From 7ec68ca9a1a025cecb55a55a3217fe5a1e9c6fb2 Mon Sep 17 00:00:00 2001 From: Tuan Dang Date: Sat, 17 Aug 2024 19:44:47 -0700 Subject: [PATCH] Update expiry badge display for certs --- frontend/src/hooks/api/ca/constants.tsx | 2 +- .../src/hooks/api/certificates/constants.tsx | 13 +- .../components/CaTab/components/CaTable.tsx | 7 +- .../components/CertificatesTable.tsx | 295 +++++++++--------- .../components/CertificatesTable.utils.ts | 28 ++ .../components/PkiAlertsTab/PkiAlertsTab.tsx | 3 +- .../components/PkiCollectionTable.tsx | 2 +- 7 files changed, 198 insertions(+), 152 deletions(-) create mode 100644 frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificatesTable.utils.ts diff --git a/frontend/src/hooks/api/ca/constants.tsx b/frontend/src/hooks/api/ca/constants.tsx index e77dfe2b8..9bb7b89d5 100644 --- a/frontend/src/hooks/api/ca/constants.tsx +++ b/frontend/src/hooks/api/ca/constants.tsx @@ -11,7 +11,7 @@ export const caStatusToNameMap: { [K in CaStatus]: string } = { [CaStatus.PENDING_CERTIFICATE]: "Pending Certificate" }; -export const getStatusBadgeVariant = (status: CaStatus) => { +export const getCaStatusBadgeVariant = (status: CaStatus) => { switch (status) { case CaStatus.ACTIVE: return "success"; diff --git a/frontend/src/hooks/api/certificates/constants.tsx b/frontend/src/hooks/api/certificates/constants.tsx index e5a9b7a43..2f2972bbc 100644 --- a/frontend/src/hooks/api/certificates/constants.tsx +++ b/frontend/src/hooks/api/certificates/constants.tsx @@ -1,10 +1,21 @@ -import { CertKeyAlgorithm, CertStatus,CrlReason } from "./enums"; +import { CertKeyAlgorithm, CertStatus, CrlReason } from "./enums"; export const certStatusToNameMap: { [K in CertStatus]: string } = { [CertStatus.ACTIVE]: "Active", [CertStatus.REVOKED]: "Revoked" }; +export const getCertStatusBadgeVariant = (status: CertStatus) => { + switch (status) { + case CertStatus.ACTIVE: + return "success"; + case CertStatus.REVOKED: + return "danger"; + default: + return "primary"; + } +}; + export const certKeyAlgorithmToNameMap: { [K in CertKeyAlgorithm]: string } = { [CertKeyAlgorithm.RSA_2048]: "RSA 2048", [CertKeyAlgorithm.RSA_4096]: "RSA 4096", diff --git a/frontend/src/views/Project/CertificatesPage/components/CaTab/components/CaTable.tsx b/frontend/src/views/Project/CertificatesPage/components/CaTab/components/CaTable.tsx index f719365eb..2c0bc8706 100644 --- a/frontend/src/views/Project/CertificatesPage/components/CaTab/components/CaTable.tsx +++ b/frontend/src/views/Project/CertificatesPage/components/CaTab/components/CaTable.tsx @@ -39,7 +39,7 @@ import { CaStatus, useListWorkspaceCas } from "@app/hooks/api"; import { caStatusToNameMap, caTypeToNameMap, - getStatusBadgeVariant + getCaStatusBadgeVariant } from "@app/hooks/api/ca/constants"; import { UsePopUpState } from "@app/hooks/usePopUp"; @@ -92,7 +92,7 @@ export const CaTable = ({ handlePopUpOpen }: Props) => { > {ca.friendlyName} - + {caStatusToNameMap[ca.status]} @@ -100,9 +100,6 @@ export const CaTable = ({ handlePopUpOpen }: Props) => {

{ca.notAfter ? format(new Date(ca.notAfter), "yyyy-MM-dd") : "-"}

- {/* - Expires Soon - */}
diff --git a/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificatesTable.tsx b/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificatesTable.tsx index f23299aa8..bd2086ade 100644 --- a/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificatesTable.tsx +++ b/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificatesTable.tsx @@ -13,6 +13,7 @@ import { twMerge } from "tailwind-merge"; import { ProjectPermissionCan } from "@app/components/permissions"; import { + Badge, DropdownMenu, DropdownMenuContent, DropdownMenuItem, @@ -31,9 +32,10 @@ import { } from "@app/components/v2"; import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; import { useListWorkspaceCertificates } from "@app/hooks/api"; -import { certStatusToNameMap } from "@app/hooks/api/certificates/constants"; import { UsePopUpState } from "@app/hooks/usePopUp"; +import { getCertValidUntilBadgeDetails } from "./CertificatesTable.utils"; + type Props = { handlePopUpOpen: ( popUpName: keyof UsePopUpState< @@ -60,146 +62,155 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => { }); return ( -
- - - - - - - - - - - {isLoading && } - {!isLoading && - data?.certificates.map((certificate) => { - return ( - - - - - - - ); - })} - -
Friendly NameStatusValid Until -
{certificate.friendlyName}{certStatusToNameMap[certificate.status]} - {certificate.notAfter - ? format(new Date(certificate.notAfter), "yyyy-MM-dd") - : "-"} - - - -
- - - -
-
- - - {(isAllowed) => ( - - handlePopUpOpen("certificateCert", { - serialNumber: certificate.serialNumber - }) - } - disabled={!isAllowed} - icon={} - > - Export Certificate - - )} - - - {(isAllowed) => ( - - handlePopUpOpen("certificate", { - serialNumber: certificate.serialNumber - }) - } - disabled={!isAllowed} - icon={} - > - View Details - - )} - - - {(isAllowed) => ( - - handlePopUpOpen("revokeCertificate", { - serialNumber: certificate.serialNumber - }) - } - disabled={!isAllowed} - icon={} - > - Revoke Certificate - - )} - - - {(isAllowed) => ( - - handlePopUpOpen("deleteCertificate", { - serialNumber: certificate.serialNumber, - commonName: certificate.commonName - }) - } - disabled={!isAllowed} - icon={} - > - Delete Certificate - - )} - - -
-
- {!isLoading && data?.totalCount !== undefined && data.totalCount >= PER_PAGE_INIT && ( - setPage(newPage)} - onChangePerPage={(newPerPage) => setPerPage(newPerPage)} - /> - )} - {!isLoading && !data?.certificates?.length && ( - - )} -
-
+ + + + + + + + + + + + {isLoading && } + {!isLoading && + data?.certificates.map((certificate) => { + const { variant, label } = getCertValidUntilBadgeDetails(certificate.notAfter); + return ( + + + + + + + + ); + })} + +
Friendly NameStatusNot BeforeNot After +
{certificate.friendlyName} + + {label} + + + {certificate.notBefore + ? format(new Date(certificate.notBefore), "yyyy-MM-dd") + : "-"} + + {certificate.notAfter + ? format(new Date(certificate.notAfter), "yyyy-MM-dd") + : "-"} + + + +
+ + + +
+
+ + + {(isAllowed) => ( + + handlePopUpOpen("certificateCert", { + serialNumber: certificate.serialNumber + }) + } + disabled={!isAllowed} + icon={} + > + Export Certificate + + )} + + + {(isAllowed) => ( + + handlePopUpOpen("certificate", { + serialNumber: certificate.serialNumber + }) + } + disabled={!isAllowed} + icon={} + > + View Details + + )} + + + {(isAllowed) => ( + + handlePopUpOpen("revokeCertificate", { + serialNumber: certificate.serialNumber + }) + } + disabled={!isAllowed} + icon={} + > + Revoke Certificate + + )} + + + {(isAllowed) => ( + + handlePopUpOpen("deleteCertificate", { + serialNumber: certificate.serialNumber, + commonName: certificate.commonName + }) + } + disabled={!isAllowed} + icon={} + > + Delete Certificate + + )} + + +
+
+ {!isLoading && data?.totalCount !== undefined && data.totalCount >= PER_PAGE_INIT && ( + setPage(newPage)} + onChangePerPage={(newPerPage) => setPerPage(newPerPage)} + /> + )} + {!isLoading && !data?.certificates?.length && ( + + )} +
); }; diff --git a/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificatesTable.utils.ts b/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificatesTable.utils.ts new file mode 100644 index 000000000..93b408bbe --- /dev/null +++ b/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificatesTable.utils.ts @@ -0,0 +1,28 @@ +import ms from "ms"; + +export const getCertValidUntilBadgeDetails = (notAfter: string) => { + const currentDate = new Date().getTime(); + const notAfterDate = new Date(notAfter).getTime(); + const diffInMs = notAfterDate - currentDate; + + let variant: "success" | "primary" | "danger" = "success"; + let label = "Healthy"; + + if (diffInMs > ms("60d")) { + variant = "success"; + } else if (diffInMs > ms("30d")) { + variant = "primary"; + } else { + variant = "danger"; + } + + if (diffInMs > ms("60d")) { + label = "Healthy"; + } else if (diffInMs > ms("0d")) { + label = `Expires in ${ms(diffInMs)}`; + } else { + label = "Expired"; + } + + return { variant, label }; +}; diff --git a/frontend/src/views/Project/CertificatesPage/components/PkiAlertsTab/PkiAlertsTab.tsx b/frontend/src/views/Project/CertificatesPage/components/PkiAlertsTab/PkiAlertsTab.tsx index 974c2aa1b..3a5a04345 100644 --- a/frontend/src/views/Project/CertificatesPage/components/PkiAlertsTab/PkiAlertsTab.tsx +++ b/frontend/src/views/Project/CertificatesPage/components/PkiAlertsTab/PkiAlertsTab.tsx @@ -1,6 +1,6 @@ import { motion } from "framer-motion"; -import { PkiAlertsSection, PkiCollectionSection } from "./components"; +import { PkiAlertsSection } from "./components"; export const PkiAlertsTab = () => { return ( @@ -11,7 +11,6 @@ export const PkiAlertsTab = () => { animate={{ opacity: 1, translateX: 0 }} exit={{ opacity: 0, translateX: 30 }} > - ); diff --git a/frontend/src/views/Project/CertificatesPage/components/PkiAlertsTab/components/PkiCollectionTable.tsx b/frontend/src/views/Project/CertificatesPage/components/PkiAlertsTab/components/PkiCollectionTable.tsx index 4176b907b..a27662449 100644 --- a/frontend/src/views/Project/CertificatesPage/components/PkiAlertsTab/components/PkiCollectionTable.tsx +++ b/frontend/src/views/Project/CertificatesPage/components/PkiAlertsTab/components/PkiCollectionTable.tsx @@ -63,7 +63,7 @@ export const PkiCollectionTable = ({ handlePopUpOpen }: Props) => { } > {pkiCollection.name} - {pkiCollection.description} + {pkiCollection.description ? pkiCollection.description : "-"}