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"), + } + }}