diff --git a/portal-ui/src/common/SecureComponent/permissions.ts b/portal-ui/src/common/SecureComponent/permissions.ts
index c070ae859..b3e114881 100644
--- a/portal-ui/src/common/SecureComponent/permissions.ts
+++ b/portal-ui/src/common/SecureComponent/permissions.ts
@@ -210,6 +210,8 @@ export const IAM_PAGES = {
"/namespaces/:tenantNamespace/tenants/:tenantName/logging",
NAMESPACE_TENANT_EVENTS:
"/namespaces/:tenantNamespace/tenants/:tenantName/events",
+ NAMESPACE_TENANT_CSR:
+ "/namespaces/:tenantNamespace/tenants/:tenantName/csr",
};
// roles
diff --git a/portal-ui/src/screens/Console/Console.tsx b/portal-ui/src/screens/Console/Console.tsx
index 5e6302c60..00a664fcb 100644
--- a/portal-ui/src/screens/Console/Console.tsx
+++ b/portal-ui/src/screens/Console/Console.tsx
@@ -556,6 +556,11 @@ const Console = ({ classes }: IConsoleProps) => {
path: IAM_PAGES.NAMESPACE_TENANT_EVENTS,
forceDisplay: true,
},
+ {
+ component: TenantDetails,
+ path: IAM_PAGES.NAMESPACE_TENANT_CSR,
+ forceDisplay: true,
+ },
{
component: License,
path: IAM_PAGES.LICENSE,
diff --git a/portal-ui/src/screens/Console/Tenants/TenantDetails/TenantCSR.tsx b/portal-ui/src/screens/Console/Tenants/TenantDetails/TenantCSR.tsx
new file mode 100644
index 000000000..3d29c3536
--- /dev/null
+++ b/portal-ui/src/screens/Console/Tenants/TenantDetails/TenantCSR.tsx
@@ -0,0 +1,131 @@
+// This file is part of MinIO Console Server
+// Copyright (c) 2022 MinIO, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+import React, { useEffect, useState, Fragment } from "react";
+import {useDispatch} from "react-redux";
+import { Theme } from "@mui/material/styles";
+import createStyles from "@mui/styles/createStyles";
+import withStyles from "@mui/styles/withStyles";
+import {
+ setErrorSnackMessage,
+} from "../../../../systemSlice";
+import {
+ actionsTray,
+ containerForHeader,
+ searchField, tableStyles,
+} from "../../Common/FormComponents/common/styleLibrary";
+import { ErrorResponseHandler } from "../../../../common/types";
+import api from "../../../../common/api";
+import TableContainer from "@mui/material/TableContainer";
+import Paper from "@mui/material/Paper";
+import Table from "@mui/material/Table";
+import TableHead from "@mui/material/TableHead";
+import TableRow from "@mui/material/TableRow";
+import TableCell from "@mui/material/TableCell";
+import TableBody from "@mui/material/TableBody";
+
+interface ITenantCSRProps {
+ classes: any;
+ match: any;
+ loadingTenant: boolean;
+ setErrorSnackMessage: typeof setErrorSnackMessage;
+}
+
+const styles = (theme: Theme) =>
+ createStyles({
+ tableWrapper: {
+ height: "450px",
+ },
+ ...actionsTray,
+ ...searchField,
+ ...tableStyles,
+ ...containerForHeader(theme.spacing(4)),
+ });
+
+const TenantCSR = ({
+ classes,
+ match,
+ loadingTenant,
+ setErrorSnackMessage,
+ }: ITenantCSRProps) => {
+ const [loading, setLoading] = useState(true);
+ const tenantName = match.params["tenantName"];
+ const tenantNamespace = match.params["tenantNamespace"];
+ const [csrStatus] = useState([""]);
+ const [csrName] = useState([""]);
+ const [csrAnnotations] = useState([""]);
+ const dispatch = useDispatch();
+ useEffect(() => {
+ if (loadingTenant) {
+ setLoading(true);
+ }
+ }, [loadingTenant]);
+
+ useEffect(() => {
+ if (loading) {
+ api
+ .invoke(
+ "GET",
+ `/api/v1/namespaces/${tenantNamespace}/tenants/${tenantName}/csr`
+ )
+ .then((res) => {
+ for (var _i = 0; _i < res.csrElement.length; _i++) {
+ var entry = res.csrElement[_i];
+ csrStatus.push(entry.status)
+ csrName.push(entry.name)
+ csrAnnotations.push(entry.annotations)
+ }
+ setLoading(false);
+ })
+ .catch((err: ErrorResponseHandler) => {
+ dispatch(setErrorSnackMessage(err));
+ });
+ }
+ }, [loading, tenantNamespace, tenantName, setErrorSnackMessage, csrAnnotations, csrName, csrStatus, dispatch]);
+
+ return (
+
+ Certificate Signing Requests
+
+
+
+
+ Name
+ Status
+ Annotation
+
+
+
+
+
+
+ {csrName.map((csrName)=>{csrName}
)}
+
+
+ {csrStatus.map((csrStatus)=>{csrStatus}
)}
+
+
+ {csrAnnotations.map((csrAnnotations)=>{csrAnnotations}
)}
+
+
+
+
+
+
+ );
+};
+
+export default withStyles(styles)(TenantCSR);
diff --git a/portal-ui/src/screens/Console/Tenants/TenantDetails/TenantDetails.tsx b/portal-ui/src/screens/Console/Tenants/TenantDetails/TenantDetails.tsx
index 85ad279ee..2a9821eee 100644
--- a/portal-ui/src/screens/Console/Tenants/TenantDetails/TenantDetails.tsx
+++ b/portal-ui/src/screens/Console/Tenants/TenantDetails/TenantDetails.tsx
@@ -63,6 +63,7 @@ const PoolsSummary = withSuspense(React.lazy(() => import("./PoolsSummary")));
const PodsSummary = withSuspense(React.lazy(() => import("./PodsSummary")));
const TenantLogging = withSuspense(React.lazy(() => import("./TenantLogging")));
const TenantEvents = withSuspense(React.lazy(() => import("./TenantEvents")));
+const TenantCSR = withSuspense(React.lazy(() => import("./TenantCSR")));
const VolumesSummary = withSuspense(
React.lazy(() => import("./VolumesSummary"))
);
@@ -493,6 +494,10 @@ const TenantDetails = ({ classes, match, history }: ITenantDetailsProps) => {
path={IAM_PAGES.NAMESPACE_TENANT_EVENTS}
component={TenantEvents}
/>
+
(
@@ -604,6 +609,14 @@ const TenantDetails = ({ classes, match, history }: ITenantDetailsProps) => {
to: getRoutePath("license"),
},
}}
+ {{
+ tabConfig: {
+ label: "Certificate Signing Request",
+ value: "csr",
+ component: Link,
+ to: getRoutePath("csr"),
+ }
+ }}