import { faArrowDown, faArrowUp, faArrowUpRightFromSquare, faCancel, faCheck, faCheckCircle, faCopy, faEdit, faEllipsis, faFileSignature, faInfoCircle, faKey, faLock, faLockOpen, faMagnifyingGlass, faPlus, faTrash } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { motion } from "framer-motion"; import { createNotification } from "@app/components/notifications"; import { ProjectPermissionCan } from "@app/components/permissions"; import { Badge, Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, EmptyState, IconButton, Input, Pagination, Spinner, Table, TableContainer, TableSkeleton, TBody, Td, Th, THead, Tooltip, Tr } from "@app/components/v2"; import { BadgeProps } from "@app/components/v2/Badge/Badge"; import { ProjectPermissionActions, ProjectPermissionCmekActions, ProjectPermissionSub, useProject, useProjectPermission } from "@app/context"; import { kmsKeyUsageOptions } from "@app/helpers/kms"; import { getUserTablePreference, PreferenceKey, setUserTablePreference } from "@app/helpers/userTablePreferences"; import { usePagination, usePopUp, useResetPageHelper, useTimedReset } from "@app/hooks"; import { useGetCmeksByProjectId, useUpdateCmek } from "@app/hooks/api/cmeks"; import { CmekOrderBy, KmsKeyUsage, TCmek } from "@app/hooks/api/cmeks/types"; import { OrderByDirection } from "@app/hooks/api/generic/types"; import { CmekDecryptModal } from "./CmekDecryptModal"; import { CmekEncryptModal } from "./CmekEncryptModal"; import { CmekModal } from "./CmekModal"; import { CmekSignModal } from "./CmekSignModal"; import { CmekVerifyModal } from "./CmekVerifyModal"; import { DeleteCmekModal } from "./DeleteCmekModal"; const getStatusBadgeProps = ( isDisabled: boolean ): { variant: BadgeProps["variant"]; label: string } => { if (isDisabled) { return { variant: "danger", label: "Disabled" }; } return { variant: "success", label: "Active" }; }; export const CmekTable = () => { const { currentProject } = useProject(); const { permission } = useProjectPermission(); const projectId = currentProject?.id ?? ""; const { offset, limit, orderBy, orderDirection, setOrderDirection, search, debouncedSearch, setPage, setSearch, perPage, page, setPerPage } = usePagination(CmekOrderBy.Name, { initPerPage: getUserTablePreference("cmekClientTable", PreferenceKey.PerPage, 20) }); const handlePerPageChange = (newPerPage: number) => { setPerPage(newPerPage); setUserTablePreference("cmekClientTable", PreferenceKey.PerPage, newPerPage); }; const { data, isPending, isFetching } = useGetCmeksByProjectId({ projectId, offset, limit, search: debouncedSearch, orderBy, orderDirection }); const { keys = [], totalCount = 0 } = data ?? {}; useResetPageHelper({ totalCount, offset, setPage }); const [, isCopyingCiphertext, setCopyCipherText] = useTimedReset({ initialState: "", delay: 1000 }); const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp([ "upsertKey", "deleteKey", "encryptData", "decryptData", "signData", "verifyData" ] as const); const handleSort = () => { setOrderDirection((prev) => prev === OrderByDirection.ASC ? OrderByDirection.DESC : OrderByDirection.ASC ); }; const updateCmek = useUpdateCmek(); const handleDisableCmek = async ({ id: keyId, isDisabled }: TCmek) => { try { await updateCmek.mutateAsync({ keyId, projectId, isDisabled: !isDisabled }); createNotification({ text: `Key successfully ${isDisabled ? "enabled" : "disabled"}`, type: "success" }); } catch (err) { console.error(err); const error = err as any; const text = error?.response?.data?.message ?? `Failed to ${isDisabled ? "enable" : "disable"} key`; createNotification({ text, type: "error" }); } }; const cannotEditKey = permission.cannot( ProjectPermissionCmekActions.Edit, ProjectPermissionSub.Cmek ); const cannotDeleteKey = permission.cannot( ProjectPermissionCmekActions.Delete, ProjectPermissionSub.Cmek ); const cannotEncryptData = permission.cannot( ProjectPermissionCmekActions.Encrypt, ProjectPermissionSub.Cmek ); const cannotDecryptData = permission.cannot( ProjectPermissionCmekActions.Decrypt, ProjectPermissionSub.Cmek ); const cannotSignData = permission.cannot( ProjectPermissionCmekActions.Sign, ProjectPermissionSub.Cmek ); const cannotVerifyData = permission.cannot( ProjectPermissionCmekActions.Verify, ProjectPermissionSub.Cmek ); return (

Keys

Documentation{" "}
{(isAllowed) => ( )}
setSearch(e.target.value)} leftIcon={} placeholder="Search keys by name..." /> {isPending && } {!isPending && keys.length > 0 && keys.map((cmek) => { const { name, id, version, description, encryptionAlgorithm, isDisabled, keyUsage } = cmek; const { variant, label } = getStatusBadgeProps(isDisabled); return ( { setCopyCipherText(""); }} > ); })}
Name
Key ID Key Usage Algorithm Status Version {isFetching ? : null}
{name} {description && ( )}
{id} { navigator.clipboard.writeText(id); setCopyCipherText("Copied"); }} >
{kmsKeyUsageOptions[keyUsage].label}
{encryptionAlgorithm} {label} {version}
{keyUsage === KmsKeyUsage.ENCRYPT_DECRYPT && ( <>
handlePopUpOpen("encryptData", cmek)} icon={} iconPos="left" isDisabled={cannotEncryptData || isDisabled} > Encrypt Data
handlePopUpOpen("decryptData", cmek)} icon={} iconPos="left" isDisabled={cannotDecryptData || isDisabled} > Decrypt Data
)} {keyUsage === KmsKeyUsage.SIGN_VERIFY && ( <>
handlePopUpOpen("signData", cmek)} icon={} iconPos="left" isDisabled={cannotSignData || isDisabled} > Sign Data
handlePopUpOpen("verifyData", cmek)} icon={} iconPos="left" isDisabled={cannotVerifyData || isDisabled} > Verify Data
)}
handlePopUpOpen("upsertKey", cmek)} icon={} iconPos="left" isDisabled={cannotEditKey} > Edit Key
handleDisableCmek(cmek)} icon={ } iconPos="left" isDisabled={cannotEditKey} > {isDisabled ? "Enable" : "Disable"} Key
handlePopUpOpen("deleteKey", cmek)} icon={} iconPos="left" isDisabled={cannotDeleteKey} > Delete Key
{!isPending && totalCount > 0 && ( setPage(newPage)} onChangePerPage={handlePerPageChange} /> )} {!isPending && keys.length === 0 && ( 0 ? "No keys match search filter" : "No keys have been added to this project" } icon={faKey} /> )}
handlePopUpToggle("deleteKey", isOpen)} cmek={popUp.deleteKey.data as TCmek} /> handlePopUpToggle("upsertKey", isOpen)} cmek={popUp.upsertKey.data as TCmek | null} /> handlePopUpToggle("encryptData", isOpen)} cmek={popUp.encryptData.data as TCmek} /> handlePopUpToggle("decryptData", isOpen)} cmek={popUp.decryptData.data as TCmek} /> handlePopUpToggle("signData", isOpen)} cmek={popUp.signData.data as TCmek} /> handlePopUpToggle("verifyData", isOpen)} cmek={popUp.verifyData.data as TCmek} />
); };