mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-15 15:41:27 +00:00
Merge pull request #2397 from Infisical/cert-template-enforcement
Certificate Template Enforcement Option + PKI UX Improvements
This commit is contained in:
@@ -8,4 +8,4 @@ export {
|
||||
useSignIntermediate,
|
||||
useUpdateCa
|
||||
} from "./mutations";
|
||||
export { useGetCaById, useGetCaCert, useGetCaCerts, useGetCaCrls, useGetCaCsr } from "./queries";
|
||||
export { useGetCaById, useGetCaCert, useGetCaCerts, useGetCaCertTemplates,useGetCaCrls, useGetCaCsr } from "./queries";
|
||||
|
||||
@@ -43,8 +43,9 @@ export const useUpdateCa = () => {
|
||||
} = await apiRequest.patch<{ ca: TCertificateAuthority }>(`/api/v1/pki/ca/${caId}`, body);
|
||||
return ca;
|
||||
},
|
||||
onSuccess: (_, { projectSlug }) => {
|
||||
onSuccess: ({ id }, { projectSlug }) => {
|
||||
queryClient.invalidateQueries(workspaceKeys.getWorkspaceCas({ projectSlug }));
|
||||
queryClient.invalidateQueries(caKeys.getCaById(id));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import { TCertificateTemplate } from "../certificateTemplates/types";
|
||||
import { TCertificateAuthority } from "./types";
|
||||
|
||||
export const caKeys = {
|
||||
@@ -11,6 +12,7 @@ export const caKeys = {
|
||||
getCaCert: (caId: string) => [{ caId }, "ca-cert"],
|
||||
getCaCsr: (caId: string) => [{ caId }, "ca-csr"],
|
||||
getCaCrl: (caId: string) => [{ caId }, "ca-crl"],
|
||||
getCaCertTemplates: (caId: string) => [{ caId }, "ca-cert-templates"],
|
||||
getCaEstConfig: (caId: string) => [{ caId }, "ca-est-config"]
|
||||
};
|
||||
|
||||
@@ -90,3 +92,16 @@ export const useGetCaCrls = (caId: string) => {
|
||||
enabled: Boolean(caId)
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetCaCertTemplates = (caId: string) => {
|
||||
return useQuery({
|
||||
queryKey: caKeys.getCaCertTemplates(caId),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<{
|
||||
certificateTemplates: TCertificateTemplate[];
|
||||
}>(`/api/v1/pki/ca/${caId}/certificate-templates`);
|
||||
return data;
|
||||
},
|
||||
enabled: Boolean(caId)
|
||||
});
|
||||
};
|
||||
@@ -19,6 +19,7 @@ export type TCertificateAuthority = {
|
||||
notAfter?: string;
|
||||
notBefore?: string;
|
||||
keyAlgorithm: CertKeyAlgorithm;
|
||||
requireTemplateForIssuance: boolean;
|
||||
activeCaCertId?: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
@@ -37,12 +38,14 @@ export type TCreateCaDTO = {
|
||||
notAfter?: string;
|
||||
maxPathLength: number;
|
||||
keyAlgorithm: CertKeyAlgorithm;
|
||||
requireTemplateForIssuance: boolean;
|
||||
};
|
||||
|
||||
export type TUpdateCaDTO = {
|
||||
projectSlug: string;
|
||||
caId: string;
|
||||
status?: CaStatus;
|
||||
requireTemplateForIssuance?: boolean;
|
||||
};
|
||||
|
||||
export type TDeleteCaDTO = {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import { caKeys } from "../ca/queries";
|
||||
import { workspaceKeys } from "../workspace/queries";
|
||||
import { certTemplateKeys } from "./queries";
|
||||
import {
|
||||
@@ -23,8 +24,9 @@ export const useCreateCertTemplate = () => {
|
||||
);
|
||||
return certificateTemplate;
|
||||
},
|
||||
onSuccess: (_, { projectId }) => {
|
||||
onSuccess: ({ caId }, { projectId }) => {
|
||||
queryClient.invalidateQueries(workspaceKeys.getWorkspaceCertificateTemplates(projectId));
|
||||
queryClient.invalidateQueries(caKeys.getCaCertTemplates(caId));
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -40,22 +42,25 @@ export const useUpdateCertTemplate = () => {
|
||||
|
||||
return certificateTemplate;
|
||||
},
|
||||
onSuccess: (_, { projectId, id }) => {
|
||||
onSuccess: ({ caId }, { projectId, id }) => {
|
||||
queryClient.invalidateQueries(workspaceKeys.getWorkspaceCertificateTemplates(projectId));
|
||||
queryClient.invalidateQueries(certTemplateKeys.getCertTemplateById(id));
|
||||
queryClient.invalidateQueries(caKeys.getCaCertTemplates(caId));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useDeleteCertTemplate = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<void, {}, TDeleteCertificateTemplateDTO>({
|
||||
return useMutation<TCertificateTemplate, {}, TDeleteCertificateTemplateDTO>({
|
||||
mutationFn: async (data) => {
|
||||
return apiRequest.delete(`/api/v1/pki/certificate-templates/${data.id}`);
|
||||
const { data: certificateTemplate } = await apiRequest.delete<TCertificateTemplate>(`/api/v1/pki/certificate-templates/${data.id}`);
|
||||
return certificateTemplate;
|
||||
},
|
||||
onSuccess: (_, { projectId, id }) => {
|
||||
onSuccess: ({ caId }, { projectId, id }) => {
|
||||
queryClient.invalidateQueries(workspaceKeys.getWorkspaceCertificateTemplates(projectId));
|
||||
queryClient.invalidateQueries(certTemplateKeys.getCertTemplateById(id));
|
||||
queryClient.invalidateQueries(caKeys.getCaCertTemplates(caId));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -22,6 +22,7 @@ import { usePopUp } from "@app/hooks/usePopUp";
|
||||
import { CaModal } from "@app/views/Project/CertificatesPage/components/CaTab/components/CaModal";
|
||||
|
||||
import { CaInstallCertModal } from "../CertificatesPage/components/CaTab/components/CaInstallCertModal";
|
||||
import { CertificateTemplatesSection } from "../CertificatesPage/components/CertificatesTab/components/CertificateTemplatesSection";
|
||||
import {
|
||||
CaCertificatesSection,
|
||||
CaCrlsSection,
|
||||
@@ -125,6 +126,7 @@ export const CaPage = withProjectPermission(
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<CaCertificatesSection caId={caId} />
|
||||
<CertificateTemplatesSection caId={caId} />
|
||||
<CaCrlsSection caId={caId} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { faCheck, faCopy } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faCheck, faCopy, faPencil } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { format } from "date-fns";
|
||||
|
||||
@@ -33,6 +33,28 @@ export const CaDetailsSection = ({ caId, handlePopUpOpen }: Props) => {
|
||||
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<div className="flex items-center justify-between border-b border-mineshaft-400 pb-4">
|
||||
<h3 className="text-lg font-semibold text-mineshaft-100">CA Details</h3>
|
||||
<ProjectPermissionCan I={ProjectPermissionActions.Edit} a={ProjectPermissionSub.Identity}>
|
||||
{(isAllowed) => {
|
||||
return (
|
||||
<Tooltip content="Edit CA">
|
||||
<IconButton
|
||||
isDisabled={!isAllowed}
|
||||
ariaLabel="copy icon"
|
||||
variant="plain"
|
||||
className="group relative"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handlePopUpOpen("ca", {
|
||||
caId: ca.id
|
||||
});
|
||||
}}
|
||||
>
|
||||
<FontAwesomeIcon icon={faPencil} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
);
|
||||
}}
|
||||
</ProjectPermissionCan>
|
||||
</div>
|
||||
<div className="pt-4">
|
||||
<div className="mb-4">
|
||||
@@ -115,6 +137,12 @@ export const CaDetailsSection = ({ caId, handlePopUpOpen }: Props) => {
|
||||
{ca.notAfter ? format(new Date(ca.notAfter), "yyyy-MM-dd") : "-"}
|
||||
</p>
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<p className="text-sm font-semibold text-mineshaft-300">Template Issuance Required</p>
|
||||
<p className="text-sm text-mineshaft-300">
|
||||
{ca.requireTemplateForIssuance ? "True" : "False"}
|
||||
</p>
|
||||
</div>
|
||||
{ca.status === CaStatus.ACTIVE && (
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Edit}
|
||||
|
||||
+80
-42
@@ -12,11 +12,12 @@ import {
|
||||
Modal,
|
||||
ModalContent,
|
||||
Select,
|
||||
SelectItem
|
||||
SelectItem,
|
||||
Switch
|
||||
// DatePicker
|
||||
} from "@app/components/v2";
|
||||
import { useWorkspace } from "@app/context";
|
||||
import { CaType, useCreateCa, useGetCaById } from "@app/hooks/api/ca";
|
||||
import { CaType, useCreateCa, useGetCaById,useUpdateCa } from "@app/hooks/api/ca";
|
||||
import { certKeyAlgorithms } from "@app/hooks/api/certificates/constants";
|
||||
import { CertKeyAlgorithm } from "@app/hooks/api/certificates/enums";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
@@ -49,7 +50,8 @@ const schema = z
|
||||
CertKeyAlgorithm.RSA_4096,
|
||||
CertKeyAlgorithm.ECDSA_P256,
|
||||
CertKeyAlgorithm.ECDSA_P384
|
||||
])
|
||||
]),
|
||||
requireTemplateForIssuance: z.boolean()
|
||||
})
|
||||
.required();
|
||||
|
||||
@@ -70,7 +72,9 @@ export const CaModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
// const [isStartDatePickerOpen, setIsStartDatePickerOpen] = useState(false);
|
||||
|
||||
const { data: ca } = useGetCaById((popUp?.ca?.data as { caId: string })?.caId || "");
|
||||
|
||||
const { mutateAsync: createMutateAsync } = useCreateCa();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateCa();
|
||||
|
||||
const {
|
||||
control,
|
||||
@@ -110,7 +114,8 @@ export const CaModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
commonName: ca.commonName,
|
||||
notAfter: ca.notAfter ? format(new Date(ca.notAfter), "yyyy-MM-dd") : "",
|
||||
maxPathLength: ca.maxPathLength ? String(ca.maxPathLength) : "",
|
||||
keyAlgorithm: ca.keyAlgorithm
|
||||
keyAlgorithm: ca.keyAlgorithm,
|
||||
requireTemplateForIssuance: ca.requireTemplateForIssuance
|
||||
});
|
||||
} else {
|
||||
reset({
|
||||
@@ -124,7 +129,8 @@ export const CaModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
commonName: "",
|
||||
notAfter: getDateTenYearsFromToday(),
|
||||
maxPathLength: "-1",
|
||||
keyAlgorithm: CertKeyAlgorithm.RSA_2048
|
||||
keyAlgorithm: CertKeyAlgorithm.RSA_2048,
|
||||
requireTemplateForIssuance: true
|
||||
});
|
||||
}
|
||||
}, [ca]);
|
||||
@@ -140,31 +146,43 @@ export const CaModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
province,
|
||||
notAfter,
|
||||
maxPathLength,
|
||||
keyAlgorithm
|
||||
keyAlgorithm,
|
||||
requireTemplateForIssuance
|
||||
}: FormData) => {
|
||||
try {
|
||||
if (!currentWorkspace?.slug) return;
|
||||
|
||||
await createMutateAsync({
|
||||
projectSlug: currentWorkspace.slug,
|
||||
type,
|
||||
friendlyName,
|
||||
commonName,
|
||||
organization,
|
||||
ou,
|
||||
country,
|
||||
province,
|
||||
locality,
|
||||
notAfter,
|
||||
maxPathLength: Number(maxPathLength),
|
||||
keyAlgorithm
|
||||
});
|
||||
|
||||
if (ca) {
|
||||
// update
|
||||
await updateMutateAsync({
|
||||
projectSlug: currentWorkspace.slug,
|
||||
caId: ca.id,
|
||||
requireTemplateForIssuance
|
||||
});
|
||||
} else {
|
||||
// create
|
||||
await createMutateAsync({
|
||||
projectSlug: currentWorkspace.slug,
|
||||
type,
|
||||
friendlyName,
|
||||
commonName,
|
||||
organization,
|
||||
ou,
|
||||
country,
|
||||
province,
|
||||
locality,
|
||||
notAfter,
|
||||
maxPathLength: Number(maxPathLength),
|
||||
keyAlgorithm,
|
||||
requireTemplateForIssuance
|
||||
});
|
||||
}
|
||||
|
||||
reset();
|
||||
handlePopUpToggle("ca", false);
|
||||
|
||||
createNotification({
|
||||
text: "Successfully created CA",
|
||||
text: `Successfully ${ca ? "updated" : "created"} CA`,
|
||||
type: "success"
|
||||
});
|
||||
} catch (err) {
|
||||
@@ -186,6 +204,11 @@ export const CaModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
>
|
||||
<ModalContent title={`${ca ? "View" : "Create"} Private CA`}>
|
||||
<form onSubmit={handleSubmit(onFormSubmit)}>
|
||||
{ca && (
|
||||
<FormControl label="CA ID">
|
||||
<Input value={ca.id} isDisabled className="bg-white/[0.07]" />
|
||||
</FormControl>
|
||||
)}
|
||||
<Controller
|
||||
control={control}
|
||||
name="type"
|
||||
@@ -406,26 +429,41 @@ export const CaModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
{!ca && (
|
||||
<div className="flex items-center">
|
||||
<Button
|
||||
className="mr-4"
|
||||
size="sm"
|
||||
type="submit"
|
||||
isLoading={isSubmitting}
|
||||
isDisabled={isSubmitting}
|
||||
>
|
||||
{popUp?.ca?.data ? "Update" : "Create"}
|
||||
</Button>
|
||||
<Button
|
||||
colorSchema="secondary"
|
||||
variant="plain"
|
||||
onClick={() => handlePopUpToggle("ca", false)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
<Controller
|
||||
control={control}
|
||||
name="requireTemplateForIssuance"
|
||||
render={({ field, fieldState: { error } }) => {
|
||||
return (
|
||||
<FormControl isError={Boolean(error)} errorText={error?.message} className="my-8">
|
||||
<Switch
|
||||
id="is-active"
|
||||
onCheckedChange={(value) => field.onChange(value)}
|
||||
isChecked={field.value}
|
||||
>
|
||||
<p className="w-full">Require Template for Certificate Issuance</p>
|
||||
</Switch>
|
||||
</FormControl>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<div className="flex items-center">
|
||||
<Button
|
||||
className="mr-4"
|
||||
size="sm"
|
||||
type="submit"
|
||||
isLoading={isSubmitting}
|
||||
isDisabled={isSubmitting}
|
||||
>
|
||||
{popUp?.ca?.data ? "Update" : "Create"}
|
||||
</Button>
|
||||
<Button
|
||||
colorSchema="secondary"
|
||||
variant="plain"
|
||||
onClick={() => handlePopUpToggle("ca", false)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
|
||||
@@ -3,7 +3,6 @@ import {
|
||||
faBan,
|
||||
faCertificate,
|
||||
faEllipsis,
|
||||
faEye,
|
||||
faTrash
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
@@ -155,28 +154,6 @@ export const CaTable = ({ handlePopUpOpen }: Props) => {
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
)}
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Read}
|
||||
a={ProjectPermissionSub.CertificateAuthorities}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<DropdownMenuItem
|
||||
className={twMerge(
|
||||
!isAllowed && "pointer-events-none cursor-not-allowed opacity-50"
|
||||
)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handlePopUpOpen("ca", {
|
||||
caId: ca.id
|
||||
});
|
||||
}}
|
||||
disabled={!isAllowed}
|
||||
icon={<FontAwesomeIcon icon={faEye} />}
|
||||
>
|
||||
View CA
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
{(ca.status === CaStatus.ACTIVE || ca.status === CaStatus.DISABLED) && (
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Edit}
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
import { PkiCollectionSection } from "../PkiAlertsTab/components";
|
||||
import { CertificateTemplatesSection } from "./components/CertificateTemplatesSection";
|
||||
// import { CertificateTemplatesSection } from "./components/CertificateTemplatesSection";
|
||||
import { CertificatesSection } from "./components";
|
||||
|
||||
export const CertificatesTab = () => {
|
||||
@@ -14,7 +14,7 @@ export const CertificatesTab = () => {
|
||||
exit={{ opacity: 0, translateX: 30 }}
|
||||
>
|
||||
<PkiCollectionSection />
|
||||
<CertificateTemplatesSection />
|
||||
{/* <CertificateTemplatesSection /> */}
|
||||
<CertificatesSection />
|
||||
</motion.div>
|
||||
);
|
||||
|
||||
-1
@@ -218,7 +218,6 @@ export const CertificateModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
}
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
className="mt-4"
|
||||
isRequired
|
||||
>
|
||||
<Select
|
||||
|
||||
+16
-7
@@ -21,11 +21,11 @@ import { useWorkspace } from "@app/context";
|
||||
import {
|
||||
CaStatus,
|
||||
useCreateCertTemplate,
|
||||
useGetCaById,
|
||||
useGetCertTemplate,
|
||||
useListWorkspaceCas,
|
||||
useListWorkspacePkiCollections,
|
||||
useUpdateCertTemplate
|
||||
} from "@app/hooks/api";
|
||||
useUpdateCertTemplate} from "@app/hooks/api";
|
||||
import { caTypeToNameMap } from "@app/hooks/api/ca/constants";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
@@ -51,6 +51,7 @@ const schema = z.object({
|
||||
export type FormData = z.infer<typeof schema>;
|
||||
|
||||
type Props = {
|
||||
caId: string;
|
||||
popUp: UsePopUpState<["certificateTemplate"]>;
|
||||
handlePopUpToggle: (
|
||||
popUpName: keyof UsePopUpState<["certificateTemplate"]>,
|
||||
@@ -58,8 +59,11 @@ type Props = {
|
||||
) => void;
|
||||
};
|
||||
|
||||
export const CertificateTemplateModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
export const CertificateTemplateModal = ({ popUp, handlePopUpToggle, caId }: Props) => {
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
|
||||
const { data: ca } = useGetCaById(caId);
|
||||
|
||||
const { data: certTemplate } = useGetCertTemplate(
|
||||
(popUp?.certificateTemplate?.data as { id: string })?.id || ""
|
||||
);
|
||||
@@ -97,16 +101,15 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle }: Props) =>
|
||||
});
|
||||
} else {
|
||||
reset({
|
||||
caId: "",
|
||||
caId,
|
||||
name: "",
|
||||
commonName: "",
|
||||
ttl: ""
|
||||
});
|
||||
}
|
||||
}, [certTemplate]);
|
||||
}, [certTemplate, ca]);
|
||||
|
||||
const onFormSubmit = async ({
|
||||
caId,
|
||||
collectionId,
|
||||
name,
|
||||
commonName,
|
||||
@@ -172,6 +175,11 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle }: Props) =>
|
||||
>
|
||||
<ModalContent title={certTemplate ? "Certificate Template" : "Create Certificate Template"}>
|
||||
<form onSubmit={handleSubmit(onFormSubmit)}>
|
||||
{certTemplate && (
|
||||
<FormControl label="Certificate Template ID">
|
||||
<Input value={certTemplate.id} isDisabled className="bg-white/[0.07]" />
|
||||
</FormControl>
|
||||
)}
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
@@ -190,7 +198,7 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle }: Props) =>
|
||||
<Controller
|
||||
control={control}
|
||||
name="caId"
|
||||
defaultValue=""
|
||||
defaultValue={caId}
|
||||
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Issuing CA"
|
||||
@@ -204,6 +212,7 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle }: Props) =>
|
||||
{...field}
|
||||
onValueChange={(e) => onChange(e)}
|
||||
className="w-full"
|
||||
isDisabled
|
||||
>
|
||||
{(cas || []).map(({ id, type, dn }) => (
|
||||
<SelectItem value={id} key={`ca-${id}`}>
|
||||
|
||||
+23
-13
@@ -1,9 +1,13 @@
|
||||
/**
|
||||
* TODO (dangtony98): Reevaluate if this component should be in main
|
||||
* CertificateTab or under CA page in the future.
|
||||
*/
|
||||
import { faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { ProjectPermissionCan } from "@app/components/permissions";
|
||||
import { Button, DeleteActionModal, UpgradePlanModal } from "@app/components/v2";
|
||||
import { DeleteActionModal, IconButton, UpgradePlanModal } from "@app/components/v2";
|
||||
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
|
||||
import { usePopUp } from "@app/hooks";
|
||||
import { useDeleteCertTemplate } from "@app/hooks/api";
|
||||
@@ -12,7 +16,11 @@ import { CertificateTemplateEnrollmentModal } from "./CertificateTemplateEnrollm
|
||||
import { CertificateTemplateModal } from "./CertificateTemplateModal";
|
||||
import { CertificateTemplatesTable } from "./CertificateTemplatesTable";
|
||||
|
||||
export const CertificateTemplatesSection = () => {
|
||||
type Props = {
|
||||
caId: string;
|
||||
}
|
||||
|
||||
export const CertificateTemplatesSection = ({ caId }: Props) => {
|
||||
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
|
||||
"certificateTemplate",
|
||||
"deleteCertificateTemplate",
|
||||
@@ -50,28 +58,30 @@ export const CertificateTemplatesSection = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<div className="mb-4 flex justify-between">
|
||||
<p className="text-xl font-semibold text-mineshaft-100">Certificate Templates</p>
|
||||
<div className="mt-4 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<div className="flex items-center justify-between border-b border-mineshaft-400 pb-4">
|
||||
<h3 className="text-lg font-semibold text-mineshaft-100">Certificate Templates</h3>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Create}
|
||||
a={ProjectPermissionSub.CertificateTemplates}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
colorSchema="primary"
|
||||
type="submit"
|
||||
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
||||
<IconButton
|
||||
ariaLabel="copy icon"
|
||||
variant="plain"
|
||||
className="group relative"
|
||||
onClick={() => handlePopUpOpen("certificateTemplate")}
|
||||
isDisabled={!isAllowed}
|
||||
>
|
||||
Create
|
||||
</Button>
|
||||
<FontAwesomeIcon icon={faPlus} />
|
||||
</IconButton>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
</div>
|
||||
<CertificateTemplatesTable handlePopUpOpen={handlePopUpOpen} />
|
||||
<CertificateTemplateModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||
<div className="py-4">
|
||||
<CertificateTemplatesTable handlePopUpOpen={handlePopUpOpen} caId={caId} />
|
||||
</div>
|
||||
<CertificateTemplateModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} caId={caId} />
|
||||
<CertificateTemplateEnrollmentModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||
<DeleteActionModal
|
||||
isOpen={popUp.deleteCertificateTemplate.isOpen}
|
||||
|
||||
+10
-11
@@ -23,12 +23,15 @@ import {
|
||||
ProjectPermissionActions,
|
||||
ProjectPermissionSub,
|
||||
useSubscription,
|
||||
useWorkspace
|
||||
} from "@app/context";
|
||||
import { useListWorkspaceCertificateTemplates } from "@app/hooks/api";
|
||||
import {
|
||||
// useListWorkspaceCertificateTemplates,
|
||||
useGetCaCertTemplates
|
||||
} from "@app/hooks/api";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
type Props = {
|
||||
caId: string;
|
||||
handlePopUpOpen: (
|
||||
popUpName: keyof UsePopUpState<
|
||||
["certificateTemplate", "deleteCertificateTemplate", "enrollmentOptions", "upgradePlan"]
|
||||
@@ -40,12 +43,10 @@ type Props = {
|
||||
) => void;
|
||||
};
|
||||
|
||||
export const CertificateTemplatesTable = ({ handlePopUpOpen }: Props) => {
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
export const CertificateTemplatesTable = ({ handlePopUpOpen, caId }: Props) => {
|
||||
const { subscription } = useSubscription();
|
||||
const { data, isLoading } = useListWorkspaceCertificateTemplates({
|
||||
workspaceId: currentWorkspace?.id ?? ""
|
||||
});
|
||||
|
||||
const { data, isLoading } = useGetCaCertTemplates(caId);
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -54,7 +55,6 @@ export const CertificateTemplatesTable = ({ handlePopUpOpen }: Props) => {
|
||||
<THead>
|
||||
<Tr>
|
||||
<Th>Name</Th>
|
||||
<Th>Certificate Authority</Th>
|
||||
<Th />
|
||||
</Tr>
|
||||
</THead>
|
||||
@@ -65,13 +65,12 @@ export const CertificateTemplatesTable = ({ handlePopUpOpen }: Props) => {
|
||||
return (
|
||||
<Tr className="h-10" key={`certificate-${certificateTemplate.id}`}>
|
||||
<Td>{certificateTemplate.name}</Td>
|
||||
<Td>{certificateTemplate.caName}</Td>
|
||||
<Td className="flex justify-end">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild className="rounded-lg">
|
||||
<div className="hover:text-primary-400 data-[state=open]:text-primary-400">
|
||||
<Tooltip content="More options">
|
||||
<FontAwesomeIcon size="lg" icon={faEllipsis} />
|
||||
<FontAwesomeIcon size="sm" icon={faEllipsis} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
</DropdownMenuTrigger>
|
||||
@@ -143,7 +142,7 @@ export const CertificateTemplatesTable = ({ handlePopUpOpen }: Props) => {
|
||||
</TBody>
|
||||
</Table>
|
||||
{!isLoading && !data?.certificateTemplates?.length && (
|
||||
<EmptyState title="No certificate templates have been created" icon={faFileAlt} />
|
||||
<EmptyState title="No certificate templates have been created for this CA" icon={faFileAlt} />
|
||||
)}
|
||||
</TableContainer>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user