mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
feat: completed frontend changes for new pki templates
This commit is contained in:
@@ -10,6 +10,7 @@ export {
|
||||
ProjectPermissionKmipActions,
|
||||
ProjectPermissionMemberActions,
|
||||
ProjectPermissionPkiSubscriberActions,
|
||||
ProjectPermissionPkiTemplateActions,
|
||||
ProjectPermissionSshHostActions,
|
||||
ProjectPermissionSub
|
||||
} from "./types";
|
||||
|
||||
@@ -104,6 +104,15 @@ export enum ProjectPermissionPkiSubscriberActions {
|
||||
ListCerts = "list-certs"
|
||||
}
|
||||
|
||||
export enum ProjectPermissionPkiTemplateActions {
|
||||
Read = "read",
|
||||
Create = "create",
|
||||
Edit = "edit",
|
||||
Delete = "delete",
|
||||
IssueCert = "issue-cert",
|
||||
ListCerts = "list-certs"
|
||||
}
|
||||
|
||||
export enum ProjectPermissionSecretRotationActions {
|
||||
Read = "read",
|
||||
ReadGeneratedCredentials = "read-generated-credentials",
|
||||
@@ -238,6 +247,11 @@ export type PkiSubscriberSubjectFields = {
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type PkiTemplateSubjectFields = {
|
||||
name: string;
|
||||
// (dangtony98): consider adding [commonName] as a subject field in the future
|
||||
};
|
||||
|
||||
export type ProjectPermissionSet =
|
||||
| [
|
||||
ProjectPermissionSecretActions,
|
||||
@@ -295,7 +309,13 @@ export type ProjectPermissionSet =
|
||||
]
|
||||
| [ProjectPermissionActions, ProjectPermissionSub.CertificateAuthorities]
|
||||
| [ProjectPermissionCertificateActions, ProjectPermissionSub.Certificates]
|
||||
| [ProjectPermissionActions, ProjectPermissionSub.CertificateTemplates]
|
||||
| [
|
||||
ProjectPermissionPkiTemplateActions,
|
||||
(
|
||||
| ProjectPermissionSub.CertificateTemplates
|
||||
| (ForcedSubject<ProjectPermissionSub.CertificateTemplates> & PkiTemplateSubjectFields)
|
||||
)
|
||||
]
|
||||
| [ProjectPermissionActions, ProjectPermissionSub.SshCertificateAuthorities]
|
||||
| [ProjectPermissionActions, ProjectPermissionSub.SshCertificateTemplates]
|
||||
| [ProjectPermissionActions, ProjectPermissionSub.SshCertificates]
|
||||
|
||||
@@ -19,6 +19,7 @@ export {
|
||||
ProjectPermissionKmipActions,
|
||||
ProjectPermissionMemberActions,
|
||||
ProjectPermissionPkiSubscriberActions,
|
||||
ProjectPermissionPkiTemplateActions,
|
||||
ProjectPermissionSshHostActions,
|
||||
ProjectPermissionSub,
|
||||
useProjectPermission
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
export {
|
||||
useCreateCertTemplate,
|
||||
useCreateCertTemplateV2,
|
||||
useCreateEstConfig,
|
||||
useDeleteCertTemplate,
|
||||
useDeleteCertTemplateV2,
|
||||
useUpdateCertTemplate,
|
||||
useUpdateCertTemplateV2,
|
||||
useUpdateEstConfig
|
||||
} from "./mutations";
|
||||
export { useGetCertTemplate, useGetEstConfig } from "./queries";
|
||||
export { useGetCertTemplate, useGetEstConfig, useListCertificateTemplates } from "./queries";
|
||||
|
||||
@@ -8,9 +8,12 @@ import { certTemplateKeys } from "./queries";
|
||||
import {
|
||||
TCertificateTemplate,
|
||||
TCreateCertificateTemplateDTO,
|
||||
TCreateCertificateTemplateV2DTO,
|
||||
TCreateEstConfigDTO,
|
||||
TDeleteCertificateTemplateDTO,
|
||||
TDeleteCertificateTemplateV2DTO,
|
||||
TUpdateCertificateTemplateDTO,
|
||||
TUpdateCertificateTemplateV2DTO,
|
||||
TUpdateEstConfigDTO
|
||||
} from "./types";
|
||||
|
||||
@@ -73,6 +76,58 @@ export const useDeleteCertTemplate = () => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useCreateCertTemplateV2 = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<TCertificateTemplate, object, TCreateCertificateTemplateV2DTO>({
|
||||
mutationFn: async (dto) => {
|
||||
const { data } = await apiRequest.post<{
|
||||
certificateTemplate: TCertificateTemplate;
|
||||
}>("/api/v2/pki/certificate-templates", dto);
|
||||
return data.certificateTemplate;
|
||||
},
|
||||
onSuccess: (_, { projectId }) => {
|
||||
queryClient.invalidateQueries({ queryKey: certTemplateKeys.listTemplates({ projectId }) });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateCertTemplateV2 = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<TCertificateTemplate, object, TUpdateCertificateTemplateV2DTO>({
|
||||
mutationFn: async (dto) => {
|
||||
const { data } = await apiRequest.patch<{ certificateTemplate: TCertificateTemplate }>(
|
||||
`/api/v2/pki/certificate-templates/${dto.templateName}`,
|
||||
dto
|
||||
);
|
||||
|
||||
return data.certificateTemplate;
|
||||
},
|
||||
onSuccess: (_, { projectId }) => {
|
||||
queryClient.invalidateQueries({ queryKey: certTemplateKeys.listTemplates({ projectId }) });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useDeleteCertTemplateV2 = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<TCertificateTemplate, object, TDeleteCertificateTemplateV2DTO>({
|
||||
mutationFn: async (dto) => {
|
||||
const { data } = await apiRequest.delete<{ certificateTemplate: TCertificateTemplate }>(
|
||||
`/api/v2/pki/certificate-templates/${dto.templateName}`,
|
||||
{
|
||||
data: {
|
||||
projectId: dto.projectId
|
||||
}
|
||||
}
|
||||
);
|
||||
return data.certificateTemplate;
|
||||
},
|
||||
onSuccess: (_, { projectId }) => {
|
||||
queryClient.invalidateQueries({ queryKey: certTemplateKeys.listTemplates({ projectId }) });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useCreateEstConfig = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<object, object, TCreateEstConfigDTO>({
|
||||
|
||||
@@ -2,10 +2,20 @@ import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import { TCertificateTemplate, TEstConfig } from "./types";
|
||||
import {
|
||||
TCertificateTemplate,
|
||||
TCertificateTemplateV2,
|
||||
TEstConfig,
|
||||
TListCertificateTemplatesDTO
|
||||
} from "./types";
|
||||
|
||||
export const certTemplateKeys = {
|
||||
getCertTemplateById: (id: string) => [{ id }, "cert-template"],
|
||||
listTemplates: ({ projectId, ...el }: { limit?: number; offset?: number; projectId: string }) => [
|
||||
"list-template",
|
||||
projectId,
|
||||
el
|
||||
],
|
||||
getEstConfig: (id: string) => [{ id }, "cert-template-est-config"]
|
||||
};
|
||||
|
||||
@@ -22,6 +32,29 @@ export const useGetCertTemplate = (id: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useListCertificateTemplates = ({
|
||||
limit = 100,
|
||||
offset = 0,
|
||||
projectId
|
||||
}: TListCertificateTemplatesDTO) => {
|
||||
return useQuery({
|
||||
queryKey: certTemplateKeys.listTemplates({ limit, offset, projectId }),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<{
|
||||
certificateTemplates: TCertificateTemplateV2[];
|
||||
totalCount?: number;
|
||||
}>("/api/v2/pki/certificate-templates", {
|
||||
params: {
|
||||
limit,
|
||||
offset,
|
||||
projectId
|
||||
}
|
||||
});
|
||||
return data;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetEstConfig = (certificateTemplateId: string) => {
|
||||
return useQuery({
|
||||
queryKey: certTemplateKeys.getEstConfig(certificateTemplateId),
|
||||
|
||||
@@ -14,6 +14,26 @@ export type TCertificateTemplate = {
|
||||
extendedKeyUsages: CertExtendedKeyUsage[];
|
||||
};
|
||||
|
||||
export type TCertificateTemplateV2 = {
|
||||
id: string;
|
||||
caId: string;
|
||||
caName: string;
|
||||
projectId: string;
|
||||
pkiCollectionId?: string;
|
||||
name: string;
|
||||
commonName: string;
|
||||
subjectAlternativeName: string;
|
||||
ttl: string;
|
||||
keyUsages: CertKeyUsage[];
|
||||
extendedKeyUsages: CertExtendedKeyUsage[];
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
ca: {
|
||||
name: string;
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type TCreateCertificateTemplateDTO = {
|
||||
caId: string;
|
||||
pkiCollectionId?: string;
|
||||
@@ -44,6 +64,34 @@ export type TDeleteCertificateTemplateDTO = {
|
||||
projectId: string;
|
||||
};
|
||||
|
||||
export type TCreateCertificateTemplateV2DTO = {
|
||||
caId: string;
|
||||
name: string;
|
||||
commonName: string;
|
||||
subjectAlternativeName: string;
|
||||
ttl: string;
|
||||
projectId: string;
|
||||
keyUsages: CertKeyUsage[];
|
||||
extendedKeyUsages: CertExtendedKeyUsage[];
|
||||
};
|
||||
|
||||
export type TUpdateCertificateTemplateV2DTO = {
|
||||
templateName: string;
|
||||
caId?: string;
|
||||
name?: string;
|
||||
commonName?: string;
|
||||
subjectAlternativeName?: string;
|
||||
ttl?: string;
|
||||
projectId: string;
|
||||
keyUsages?: CertKeyUsage[];
|
||||
extendedKeyUsages?: CertExtendedKeyUsage[];
|
||||
};
|
||||
|
||||
export type TDeleteCertificateTemplateV2DTO = {
|
||||
templateName: string;
|
||||
projectId: string;
|
||||
};
|
||||
|
||||
export type TCreateEstConfigDTO = {
|
||||
certificateTemplateId: string;
|
||||
caChain?: string;
|
||||
@@ -67,3 +115,9 @@ export type TEstConfig = {
|
||||
isEnabled: boolean;
|
||||
disableBootstrapCertValidation: boolean;
|
||||
};
|
||||
|
||||
export type TListCertificateTemplatesDTO = {
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
projectId: string;
|
||||
};
|
||||
|
||||
@@ -117,6 +117,20 @@ export const ProjectLayout = () => {
|
||||
</MenuItem>
|
||||
)}
|
||||
</Link>
|
||||
<Link
|
||||
to={
|
||||
`/${ProjectType.CertificateManager}/$projectId/certificate-templates` as const
|
||||
}
|
||||
params={{
|
||||
projectId: currentWorkspace.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => (
|
||||
<MenuItem isSelected={isActive} icon="pki-subscriber">
|
||||
Certificate Templates
|
||||
</MenuItem>
|
||||
)}
|
||||
</Link>
|
||||
<Link
|
||||
to={
|
||||
`/${ProjectType.CertificateManager}/$projectId/certificates` as const
|
||||
|
||||
@@ -9,7 +9,11 @@ import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { ProjectPermissionCan } from "@app/components/permissions";
|
||||
import { DeleteActionModal, IconButton } from "@app/components/v2";
|
||||
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
|
||||
import {
|
||||
ProjectPermissionPkiTemplateActions,
|
||||
ProjectPermissionSub,
|
||||
useWorkspace
|
||||
} from "@app/context";
|
||||
import { usePopUp } from "@app/hooks";
|
||||
import { useDeleteCertTemplate } from "@app/hooks/api";
|
||||
|
||||
@@ -63,7 +67,7 @@ export const CertificateTemplatesSection = ({ caId }: Props) => {
|
||||
<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}
|
||||
I={ProjectPermissionPkiTemplateActions.Create}
|
||||
a={ProjectPermissionSub.CertificateTemplates}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
|
||||
@@ -19,7 +19,11 @@ import {
|
||||
Tooltip,
|
||||
Tr
|
||||
} from "@app/components/v2";
|
||||
import { ProjectPermissionActions, ProjectPermissionSub, useSubscription } from "@app/context";
|
||||
import {
|
||||
ProjectPermissionPkiTemplateActions,
|
||||
ProjectPermissionSub,
|
||||
useSubscription
|
||||
} from "@app/context";
|
||||
import { useGetCaCertTemplates } from "@app/hooks/api";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
@@ -79,7 +83,7 @@ export const CertificateTemplatesTable = ({ handlePopUpOpen, caId }: Props) => {
|
||||
Manage Policies
|
||||
</DropdownMenuItem>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Edit}
|
||||
I={ProjectPermissionPkiTemplateActions.Edit}
|
||||
a={ProjectPermissionSub.CertificateTemplates}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
@@ -105,7 +109,7 @@ export const CertificateTemplatesTable = ({ handlePopUpOpen, caId }: Props) => {
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Delete}
|
||||
I={ProjectPermissionPkiTemplateActions.Delete}
|
||||
a={ProjectPermissionSub.CertificateTemplates}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
import { useState } from "react";
|
||||
import { Helmet } from "react-helmet";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
faArrowUpRightFromSquare,
|
||||
faCertificate,
|
||||
faEllipsis,
|
||||
faPencil,
|
||||
faPlus,
|
||||
faTrash
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { format } from "date-fns";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { ProjectPermissionCan } from "@app/components/permissions";
|
||||
import {
|
||||
Button,
|
||||
DeleteActionModal,
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
EmptyState,
|
||||
Modal,
|
||||
ModalContent,
|
||||
PageHeader,
|
||||
Pagination,
|
||||
Table,
|
||||
TableContainer,
|
||||
TableSkeleton,
|
||||
Tag,
|
||||
TBody,
|
||||
Td,
|
||||
Th,
|
||||
THead,
|
||||
Tooltip,
|
||||
Tr
|
||||
} from "@app/components/v2";
|
||||
import {
|
||||
ProjectPermissionPkiTemplateActions,
|
||||
ProjectPermissionSub,
|
||||
useWorkspace
|
||||
} from "@app/context";
|
||||
import { usePopUp } from "@app/hooks";
|
||||
import { useDeleteCertTemplateV2 } from "@app/hooks/api";
|
||||
import { useListCertificateTemplates } from "@app/hooks/api/certificateTemplates/queries";
|
||||
|
||||
import { PkiTemplateForm } from "./components/PkiTemplateForm";
|
||||
|
||||
const PER_PAGE_INIT = 25;
|
||||
export const PkiTemplateListPage = () => {
|
||||
const { t } = useTranslation();
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
const [page, setPage] = useState(1);
|
||||
const [perPage, setPerPage] = useState(PER_PAGE_INIT);
|
||||
const { handlePopUpToggle, popUp, handlePopUpOpen, handlePopUpClose } = usePopUp([
|
||||
"certificateTemplate",
|
||||
"deleteTemplate"
|
||||
] as const);
|
||||
|
||||
const { data, isPending } = useListCertificateTemplates({
|
||||
projectId: currentWorkspace.id,
|
||||
offset: (page - 1) * perPage,
|
||||
limit: perPage
|
||||
});
|
||||
|
||||
const deleteCertTemplate = useDeleteCertTemplateV2();
|
||||
|
||||
const onRemovePkiSubscriberSubmit = async () => {
|
||||
try {
|
||||
const pkiTemplate = await deleteCertTemplate.mutateAsync({
|
||||
projectId: currentWorkspace.id,
|
||||
templateName: popUp?.deleteTemplate?.data?.name
|
||||
});
|
||||
|
||||
createNotification({
|
||||
text: `Successfully deleted PKI template: ${pkiTemplate.name}`,
|
||||
type: "success"
|
||||
});
|
||||
|
||||
handlePopUpClose("deleteTemplate");
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
createNotification({
|
||||
text: "Failed to delete PKI subscriber",
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<title>{t("common.head-title", { title: "PKI Subscribers" })}</title>
|
||||
</Helmet>
|
||||
<div className="h-full bg-bunker-800">
|
||||
<div className="container mx-auto flex flex-col justify-between text-white">
|
||||
<div className="mx-auto mb-6 w-full max-w-7xl">
|
||||
<PageHeader
|
||||
title="Certificate Templates"
|
||||
description="Manage certificate template to request and issue dynamic certificates following a strict format."
|
||||
/>
|
||||
</div>
|
||||
<div className="container mx-auto mb-6 max-w-7xl 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">Templates</p>
|
||||
<div className="flex w-full justify-end">
|
||||
<a target="_blank" rel="noopener noreferrer">
|
||||
<span className="flex w-max cursor-pointer items-center rounded-md border border-mineshaft-500 bg-mineshaft-600 px-4 py-2 text-mineshaft-200 duration-200 hover:border-primary/40 hover:bg-primary/10 hover:text-white">
|
||||
Documentation{" "}
|
||||
<FontAwesomeIcon
|
||||
icon={faArrowUpRightFromSquare}
|
||||
className="mb-[0.06rem] ml-1 text-xs"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionPkiTemplateActions.Create}
|
||||
a={ProjectPermissionSub.CertificateTemplates}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
colorSchema="primary"
|
||||
type="submit"
|
||||
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
||||
onClick={() => handlePopUpOpen("certificateTemplate")}
|
||||
isDisabled={!isAllowed}
|
||||
className="ml-4"
|
||||
>
|
||||
Add Template
|
||||
</Button>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
</div>
|
||||
</div>
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<THead>
|
||||
<Tr>
|
||||
<Th>Name</Th>
|
||||
<Th>CA</Th>
|
||||
<Th className="w-64">Last Updated At</Th>
|
||||
<Th />
|
||||
</Tr>
|
||||
</THead>
|
||||
<TBody>
|
||||
{isPending && <TableSkeleton columns={4} innerKey="project-cert-templates" />}
|
||||
{!isPending &&
|
||||
data?.certificateTemplates?.map((template) => {
|
||||
return (
|
||||
<Tr className="h-10" key={`certificate-template-${template.id}`}>
|
||||
<Td>{template.name}</Td>
|
||||
<Td>
|
||||
<Tag size="xs">{template.ca.name}</Tag>
|
||||
</Td>
|
||||
<Td>{format(new Date(template.updatedAt), "yyyy-MM-dd | HH:mm:ss")}</Td>
|
||||
<Td className="text-right align-middle">
|
||||
<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} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start" className="p-1">
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionPkiTemplateActions.Edit}
|
||||
a={ProjectPermissionSub.CertificateTemplates}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<DropdownMenuItem
|
||||
className={twMerge(
|
||||
!isAllowed &&
|
||||
"pointer-events-none cursor-not-allowed opacity-50"
|
||||
)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handlePopUpOpen("certificateTemplate", template);
|
||||
}}
|
||||
disabled={!isAllowed}
|
||||
icon={<FontAwesomeIcon icon={faPencil} />}
|
||||
>
|
||||
Edit Template
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionPkiTemplateActions.Delete}
|
||||
a={ProjectPermissionSub.CertificateTemplates}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<DropdownMenuItem
|
||||
className={twMerge(
|
||||
!isAllowed &&
|
||||
"pointer-events-none cursor-not-allowed opacity-50"
|
||||
)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handlePopUpOpen("deleteTemplate", template);
|
||||
}}
|
||||
disabled={!isAllowed}
|
||||
icon={<FontAwesomeIcon icon={faTrash} />}
|
||||
>
|
||||
Delete Template
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</Td>
|
||||
</Tr>
|
||||
);
|
||||
})}
|
||||
{!isPending && !data?.certificateTemplates?.length && (
|
||||
<Tr>
|
||||
<Td colSpan={4}>
|
||||
<EmptyState title="No certificate templates found" icon={faCertificate} />
|
||||
</Td>
|
||||
</Tr>
|
||||
)}
|
||||
</TBody>
|
||||
</Table>
|
||||
{!isPending && data?.totalCount !== undefined && data.totalCount >= PER_PAGE_INIT && (
|
||||
<Pagination
|
||||
count={data.totalCount}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
onChangePage={(newPage) => setPage(newPage)}
|
||||
onChangePerPage={(newPerPage) => setPerPage(newPerPage)}
|
||||
/>
|
||||
)}
|
||||
</TableContainer>
|
||||
<DeleteActionModal
|
||||
isOpen={popUp.deleteTemplate.isOpen}
|
||||
title="Are you sure you want to remove the PKI Template?"
|
||||
onChange={(isOpen) => handlePopUpToggle("deleteTemplate", isOpen)}
|
||||
deleteKey="confirm"
|
||||
onDeleteApproved={() => onRemovePkiSubscriberSubmit()}
|
||||
/>
|
||||
</div>
|
||||
<div className="container mx-auto max-w-7xl" />
|
||||
</div>
|
||||
<Modal
|
||||
isOpen={popUp?.certificateTemplate?.isOpen}
|
||||
onOpenChange={(isOpen) => handlePopUpToggle("certificateTemplate", isOpen)}
|
||||
>
|
||||
<ModalContent
|
||||
title={
|
||||
popUp.certificateTemplate?.data
|
||||
? "Certificate Template"
|
||||
: "Create Certificate Template"
|
||||
}
|
||||
>
|
||||
<PkiTemplateForm
|
||||
certTemplate={popUp?.certificateTemplate?.data}
|
||||
handlePopUpToggle={(isOpen) => handlePopUpToggle("certificateTemplate", isOpen)}
|
||||
/>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,407 @@
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { faQuestionCircle } from "@fortawesome/free-regular-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
Button,
|
||||
Checkbox,
|
||||
FilterableSelect,
|
||||
FormControl,
|
||||
FormLabel,
|
||||
Input,
|
||||
Tooltip
|
||||
} from "@app/components/v2";
|
||||
import { useWorkspace } from "@app/context";
|
||||
import {
|
||||
useCreateCertTemplateV2,
|
||||
useListCasByProjectId,
|
||||
useUpdateCertTemplateV2
|
||||
} from "@app/hooks/api";
|
||||
import {
|
||||
EXTENDED_KEY_USAGES_OPTIONS,
|
||||
KEY_USAGES_OPTIONS
|
||||
} from "@app/hooks/api/certificates/constants";
|
||||
import { CertExtendedKeyUsage, CertKeyUsage } from "@app/hooks/api/certificates/enums";
|
||||
import { TCertificateTemplateV2 } from "@app/hooks/api/certificateTemplates/types";
|
||||
import { slugSchema } from "@app/lib/schemas";
|
||||
|
||||
const validateTemplateRegexField = z.string().trim().min(1).max(100);
|
||||
|
||||
const schema = z.object({
|
||||
ca: z.object({
|
||||
name: z.string(),
|
||||
id: z.string()
|
||||
}),
|
||||
name: slugSchema(),
|
||||
commonName: validateTemplateRegexField,
|
||||
subjectAlternativeName: validateTemplateRegexField,
|
||||
ttl: z.string().trim().min(1),
|
||||
keyUsages: z.object({
|
||||
[CertKeyUsage.DIGITAL_SIGNATURE]: z.boolean().optional(),
|
||||
[CertKeyUsage.KEY_ENCIPHERMENT]: z.boolean().optional(),
|
||||
[CertKeyUsage.NON_REPUDIATION]: z.boolean().optional(),
|
||||
[CertKeyUsage.DATA_ENCIPHERMENT]: z.boolean().optional(),
|
||||
[CertKeyUsage.KEY_AGREEMENT]: z.boolean().optional(),
|
||||
[CertKeyUsage.KEY_CERT_SIGN]: z.boolean().optional(),
|
||||
[CertKeyUsage.CRL_SIGN]: z.boolean().optional(),
|
||||
[CertKeyUsage.ENCIPHER_ONLY]: z.boolean().optional(),
|
||||
[CertKeyUsage.DECIPHER_ONLY]: z.boolean().optional()
|
||||
}),
|
||||
extendedKeyUsages: z.object({
|
||||
[CertExtendedKeyUsage.CLIENT_AUTH]: z.boolean().optional(),
|
||||
[CertExtendedKeyUsage.CODE_SIGNING]: z.boolean().optional(),
|
||||
[CertExtendedKeyUsage.EMAIL_PROTECTION]: z.boolean().optional(),
|
||||
[CertExtendedKeyUsage.OCSP_SIGNING]: z.boolean().optional(),
|
||||
[CertExtendedKeyUsage.SERVER_AUTH]: z.boolean().optional(),
|
||||
[CertExtendedKeyUsage.TIMESTAMPING]: z.boolean().optional()
|
||||
})
|
||||
});
|
||||
|
||||
export type FormData = z.infer<typeof schema>;
|
||||
|
||||
type Props = {
|
||||
certTemplate?: TCertificateTemplateV2;
|
||||
handlePopUpToggle: (state?: boolean) => void;
|
||||
};
|
||||
|
||||
export const PkiTemplateForm = ({ certTemplate, handlePopUpToggle }: Props) => {
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
|
||||
const { data: cas, isPending: isCaLoading } = useListCasByProjectId(currentWorkspace.id);
|
||||
|
||||
const { mutateAsync: createCertTemplate } = useCreateCertTemplateV2();
|
||||
const { mutateAsync: updateCertTemplate } = useUpdateCertTemplateV2();
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
reset,
|
||||
formState: { isSubmitting }
|
||||
} = useForm<FormData>({
|
||||
resolver: zodResolver(schema),
|
||||
defaultValues: async () => {
|
||||
if (certTemplate) {
|
||||
return {
|
||||
ca: certTemplate.ca,
|
||||
name: certTemplate.name,
|
||||
commonName: certTemplate.commonName,
|
||||
subjectAlternativeName: certTemplate.subjectAlternativeName,
|
||||
ttl: certTemplate.ttl,
|
||||
keyUsages: Object.fromEntries(certTemplate.keyUsages.map((name) => [name, true]) ?? []),
|
||||
extendedKeyUsages: Object.fromEntries(
|
||||
certTemplate.extendedKeyUsages.map((name) => [name, true]) ?? []
|
||||
)
|
||||
};
|
||||
}
|
||||
return {
|
||||
ca: { name: "", id: "" },
|
||||
name: "",
|
||||
subjectAlternativeName: "",
|
||||
commonName: "",
|
||||
ttl: "",
|
||||
keyUsages: {
|
||||
[CertKeyUsage.DIGITAL_SIGNATURE]: true,
|
||||
[CertKeyUsage.KEY_ENCIPHERMENT]: true
|
||||
},
|
||||
extendedKeyUsages: {}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
const onFormSubmit = async ({
|
||||
name,
|
||||
commonName,
|
||||
subjectAlternativeName,
|
||||
ttl,
|
||||
keyUsages,
|
||||
extendedKeyUsages,
|
||||
ca
|
||||
}: FormData) => {
|
||||
if (!currentWorkspace?.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (certTemplate) {
|
||||
await updateCertTemplate({
|
||||
templateName: certTemplate.name,
|
||||
projectId: currentWorkspace.id,
|
||||
caId: ca.id,
|
||||
name,
|
||||
commonName,
|
||||
subjectAlternativeName,
|
||||
ttl,
|
||||
keyUsages: Object.entries(keyUsages)
|
||||
.filter(([, value]) => value)
|
||||
.map(([key]) => key as CertKeyUsage),
|
||||
extendedKeyUsages: Object.entries(extendedKeyUsages)
|
||||
.filter(([, value]) => value)
|
||||
.map(([key]) => key as CertExtendedKeyUsage)
|
||||
});
|
||||
|
||||
createNotification({
|
||||
text: "Successfully updated certificate template",
|
||||
type: "success"
|
||||
});
|
||||
} else {
|
||||
await createCertTemplate({
|
||||
projectId: currentWorkspace.id,
|
||||
caId: ca.id,
|
||||
name,
|
||||
commonName,
|
||||
subjectAlternativeName,
|
||||
ttl,
|
||||
keyUsages: Object.entries(keyUsages)
|
||||
.filter(([, value]) => value)
|
||||
.map(([key]) => key as CertKeyUsage),
|
||||
extendedKeyUsages: Object.entries(extendedKeyUsages)
|
||||
.filter(([, value]) => value)
|
||||
.map(([key]) => key as CertExtendedKeyUsage)
|
||||
});
|
||||
|
||||
createNotification({
|
||||
text: "Successfully created certificate template",
|
||||
type: "success"
|
||||
});
|
||||
}
|
||||
|
||||
reset();
|
||||
handlePopUpToggle(false);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
createNotification({
|
||||
text: "Failed to save changes",
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<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=""
|
||||
name="name"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Template Name"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
isRequired
|
||||
>
|
||||
<Input {...field} placeholder="my-template" />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Issuing CA"
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
isRequired
|
||||
>
|
||||
<FilterableSelect
|
||||
options={cas || []}
|
||||
isLoading={isCaLoading}
|
||||
placeholder="Select CA..."
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
getOptionValue={(option) => option.id}
|
||||
getOptionLabel={(option) => option.name}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
control={control}
|
||||
name="ca"
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="commonName"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label={
|
||||
<div>
|
||||
<FormLabel
|
||||
isRequired
|
||||
label="Common Name (CN)"
|
||||
icon={
|
||||
<Tooltip
|
||||
className="text-center"
|
||||
content={
|
||||
<span>
|
||||
This field accepts limited regular expressions: spaces, *, ., @, -, \ (for
|
||||
escaping), and alphanumeric characters only
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<FontAwesomeIcon icon={faQuestionCircle} size="sm" />
|
||||
</Tooltip>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
isRequired
|
||||
>
|
||||
<Input {...field} placeholder=".*\.acme.com" />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="subjectAlternativeName"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label={
|
||||
<div>
|
||||
<FormLabel
|
||||
isRequired
|
||||
label="Alternative Names (SAN)"
|
||||
icon={
|
||||
<Tooltip
|
||||
className="text-center"
|
||||
content={
|
||||
<span>
|
||||
This field accepts limited regular expressions: spaces, *, ., @, -, \ (for
|
||||
escaping), and alphanumeric characters only
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<FontAwesomeIcon icon={faQuestionCircle} size="sm" />
|
||||
</Tooltip>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
isRequired
|
||||
>
|
||||
<Input {...field} placeholder="service\.acme.\..*" />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
name="ttl"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Max TTL"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
isRequired
|
||||
>
|
||||
<Input {...field} placeholder="2 days, 1d, 2h, 1y, ..." />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Accordion type="single" collapsible className="w-full">
|
||||
<AccordionItem value="key-usages" className="data-[state=open]:border-none">
|
||||
<AccordionTrigger className="h-fit flex-none pl-1 text-sm">
|
||||
<div className="order-1 ml-3">Key Usage</div>
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<Controller
|
||||
control={control}
|
||||
name="keyUsages"
|
||||
render={({ field: { onChange, value }, fieldState: { error } }) => {
|
||||
return (
|
||||
<FormControl
|
||||
label="Key Usage"
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
>
|
||||
<div className="mb-7 mt-2 grid grid-cols-2 gap-2">
|
||||
{KEY_USAGES_OPTIONS.map(({ label, value: optionValue }) => {
|
||||
return (
|
||||
<Checkbox
|
||||
id={optionValue}
|
||||
key={optionValue}
|
||||
className="data-[state=checked]:bg-primary"
|
||||
isChecked={value[optionValue]}
|
||||
onCheckedChange={(state) => {
|
||||
onChange({
|
||||
...value,
|
||||
[optionValue]: state
|
||||
});
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</Checkbox>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</FormControl>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
name="extendedKeyUsages"
|
||||
render={({ field: { onChange, value }, fieldState: { error } }) => {
|
||||
return (
|
||||
<FormControl
|
||||
label="Extended Key Usage"
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
>
|
||||
<div className="mb-7 mt-2 grid grid-cols-2 gap-2">
|
||||
{EXTENDED_KEY_USAGES_OPTIONS.map(({ label, value: optionValue }) => {
|
||||
return (
|
||||
<Checkbox
|
||||
id={optionValue}
|
||||
key={optionValue}
|
||||
className="data-[state=checked]:bg-primary"
|
||||
isChecked={value[optionValue]}
|
||||
onCheckedChange={(state) => {
|
||||
onChange({
|
||||
...value,
|
||||
[optionValue]: state
|
||||
});
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</Checkbox>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</FormControl>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
<div className="mt-4 flex items-center">
|
||||
<Button
|
||||
className="mr-4"
|
||||
size="sm"
|
||||
type="submit"
|
||||
isLoading={isSubmitting}
|
||||
isDisabled={isSubmitting}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
<Button colorSchema="secondary" variant="plain" onClick={() => handlePopUpToggle(false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
|
||||
import { PkiTemplateListPage } from "./PkiTemplateListPage";
|
||||
|
||||
export const Route = createFileRoute(
|
||||
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/certificate-templates/"
|
||||
)({
|
||||
component: PkiTemplateListPage
|
||||
});
|
||||
@@ -0,0 +1,173 @@
|
||||
import { Controller, useFieldArray, useFormContext } from "react-hook-form";
|
||||
import { faInfoCircle, faPlus, faTrash, faWarning } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import {
|
||||
Button,
|
||||
FormControl,
|
||||
IconButton,
|
||||
Input,
|
||||
Select,
|
||||
SelectItem,
|
||||
Tooltip
|
||||
} from "@app/components/v2";
|
||||
import {
|
||||
PermissionConditionOperators,
|
||||
ProjectPermissionSub
|
||||
} from "@app/context/ProjectPermissionContext/types";
|
||||
|
||||
import { getConditionOperatorHelperInfo } from "./PermissionConditionHelpers";
|
||||
import { TFormSchema } from "./ProjectRoleModifySection.utils";
|
||||
|
||||
type Props = {
|
||||
position?: number;
|
||||
isDisabled?: boolean;
|
||||
};
|
||||
|
||||
export const PkiTemplatePermissionConditions = ({ position = 0, isDisabled }: Props) => {
|
||||
const {
|
||||
control,
|
||||
watch,
|
||||
formState: { errors }
|
||||
} = useFormContext<TFormSchema>();
|
||||
|
||||
const permissionSubject = ProjectPermissionSub.CertificateTemplates;
|
||||
const items = useFieldArray({
|
||||
control,
|
||||
name: `permissions.${permissionSubject}.${position}.conditions`
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="mt-6 border-t border-t-mineshaft-600 bg-mineshaft-800 pt-2">
|
||||
<p className="mt-2 text-gray-300">Conditions</p>
|
||||
<p className="text-sm text-mineshaft-400">
|
||||
Conditions determine when a policy will be applied (always if no conditions are present).
|
||||
</p>
|
||||
<p className="mb-3 text-sm leading-4 text-mineshaft-400">
|
||||
All conditions must evaluate to true for the policy to take effect.
|
||||
</p>
|
||||
<div className="mt-2 flex flex-col space-y-2">
|
||||
{items.fields.map((el, index) => {
|
||||
const condition =
|
||||
(watch(`permissions.${permissionSubject}.${position}.conditions.${index}`) as {
|
||||
lhs: string;
|
||||
rhs: string;
|
||||
operator: string;
|
||||
}) || {};
|
||||
|
||||
return (
|
||||
<div
|
||||
key={el.id}
|
||||
className="flex gap-2 bg-mineshaft-800 first:rounded-t-md last:rounded-b-md"
|
||||
>
|
||||
<div className="w-1/4">
|
||||
<Controller
|
||||
control={control}
|
||||
name={`permissions.${permissionSubject}.${position}.conditions.${index}.lhs`}
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
isError={Boolean(error?.message)}
|
||||
errorText={error?.message}
|
||||
className="mb-0"
|
||||
>
|
||||
<Select
|
||||
defaultValue={field.value}
|
||||
{...field}
|
||||
onValueChange={(e) => field.onChange(e)}
|
||||
className="w-full"
|
||||
>
|
||||
<SelectItem value="name">Name</SelectItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex w-36 items-center space-x-2">
|
||||
<Controller
|
||||
control={control}
|
||||
name={`permissions.${permissionSubject}.${position}.conditions.${index}.operator`}
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
isError={Boolean(error?.message)}
|
||||
errorText={error?.message}
|
||||
className="mb-0 flex-grow"
|
||||
>
|
||||
<Select
|
||||
defaultValue={field.value}
|
||||
{...field}
|
||||
onValueChange={(e) => field.onChange(e)}
|
||||
className="w-full"
|
||||
>
|
||||
<SelectItem value={PermissionConditionOperators.$EQ}>Equals</SelectItem>
|
||||
<SelectItem value={PermissionConditionOperators.$GLOB}>Glob</SelectItem>
|
||||
<SelectItem value={PermissionConditionOperators.$IN}>In</SelectItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Tooltip
|
||||
asChild
|
||||
content={getConditionOperatorHelperInfo(
|
||||
condition?.operator as PermissionConditionOperators
|
||||
)}
|
||||
className="max-w-xs"
|
||||
>
|
||||
<FontAwesomeIcon icon={faInfoCircle} size="xs" className="text-gray-400" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className="flex-grow">
|
||||
<Controller
|
||||
control={control}
|
||||
name={`permissions.${permissionSubject}.${position}.conditions.${index}.rhs`}
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
isError={Boolean(error?.message)}
|
||||
errorText={error?.message}
|
||||
className="mb-0 flex-grow"
|
||||
>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<IconButton
|
||||
ariaLabel="plus"
|
||||
variant="outline_bg"
|
||||
className="p-2.5"
|
||||
onClick={() => items.remove(index)}
|
||||
>
|
||||
<FontAwesomeIcon icon={faTrash} />
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{errors?.permissions?.[permissionSubject]?.[position]?.conditions?.message && (
|
||||
<div className="flex items-center space-x-2 py-2 text-sm text-gray-400">
|
||||
<FontAwesomeIcon icon={faWarning} className="text-red" />
|
||||
<span>{errors?.permissions?.[permissionSubject]?.[position]?.conditions?.message}</span>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<Button
|
||||
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
||||
variant="star"
|
||||
size="xs"
|
||||
className="mt-3"
|
||||
isDisabled={isDisabled}
|
||||
onClick={() =>
|
||||
items.append({
|
||||
lhs: "name",
|
||||
operator: PermissionConditionOperators.$EQ,
|
||||
rhs: ""
|
||||
})
|
||||
}
|
||||
>
|
||||
Add Condition
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
ProjectPermissionKmipActions,
|
||||
ProjectPermissionMemberActions,
|
||||
ProjectPermissionPkiSubscriberActions,
|
||||
ProjectPermissionPkiTemplateActions,
|
||||
ProjectPermissionSecretActions,
|
||||
ProjectPermissionSecretRotationActions,
|
||||
ProjectPermissionSecretSyncActions,
|
||||
@@ -148,6 +149,15 @@ const PkiSubscriberPolicyActionSchema = z.object({
|
||||
[ProjectPermissionPkiSubscriberActions.ListCerts]: z.boolean().optional()
|
||||
});
|
||||
|
||||
const PkiTemplatePolicyActionSchema = z.object({
|
||||
[ProjectPermissionPkiTemplateActions.Read]: z.boolean().optional(),
|
||||
[ProjectPermissionPkiTemplateActions.Create]: z.boolean().optional(),
|
||||
[ProjectPermissionPkiTemplateActions.Edit]: z.boolean().optional(),
|
||||
[ProjectPermissionPkiTemplateActions.Delete]: z.boolean().optional(),
|
||||
[ProjectPermissionPkiTemplateActions.IssueCert]: z.boolean().optional(),
|
||||
[ProjectPermissionPkiTemplateActions.ListCerts]: z.boolean().optional()
|
||||
});
|
||||
|
||||
const SecretRollbackPolicyActionSchema = z.object({
|
||||
read: z.boolean().optional(),
|
||||
create: z.boolean().optional()
|
||||
@@ -255,7 +265,12 @@ export const projectRoleFormSchema = z.object({
|
||||
.default([]),
|
||||
[ProjectPermissionSub.PkiAlerts]: GeneralPolicyActionSchema.array().default([]),
|
||||
[ProjectPermissionSub.PkiCollections]: GeneralPolicyActionSchema.array().default([]),
|
||||
[ProjectPermissionSub.CertificateTemplates]: GeneralPolicyActionSchema.array().default([]),
|
||||
[ProjectPermissionSub.CertificateTemplates]: PkiTemplatePolicyActionSchema.extend({
|
||||
inverted: z.boolean().optional(),
|
||||
conditions: ConditionSchema
|
||||
})
|
||||
.array()
|
||||
.default([]),
|
||||
[ProjectPermissionSub.SshCertificateAuthorities]: GeneralPolicyActionSchema.array().default(
|
||||
[]
|
||||
),
|
||||
@@ -295,6 +310,7 @@ type TConditionalFields =
|
||||
| ProjectPermissionSub.SecretImports
|
||||
| ProjectPermissionSub.DynamicSecrets
|
||||
| ProjectPermissionSub.PkiSubscribers
|
||||
| ProjectPermissionSub.CertificateTemplates
|
||||
| ProjectPermissionSub.SshHosts
|
||||
| ProjectPermissionSub.SecretRotation
|
||||
| ProjectPermissionSub.Identity;
|
||||
@@ -309,7 +325,8 @@ export const isConditionalSubjects = (
|
||||
subject === ProjectPermissionSub.Identity ||
|
||||
subject === ProjectPermissionSub.SshHosts ||
|
||||
subject === ProjectPermissionSub.SecretRotation ||
|
||||
subject === ProjectPermissionSub.PkiSubscribers;
|
||||
subject === ProjectPermissionSub.PkiSubscribers ||
|
||||
subject === ProjectPermissionSub.CertificateTemplates;
|
||||
|
||||
const convertCaslConditionToFormOperator = (caslConditions: TPermissionCondition) => {
|
||||
const formConditions: z.infer<typeof ConditionSchema> = [];
|
||||
@@ -408,7 +425,6 @@ export const rolePermission2Form = (permissions: TProjectPermission[] = []) => {
|
||||
ProjectPermissionSub.CertificateAuthorities,
|
||||
ProjectPermissionSub.PkiAlerts,
|
||||
ProjectPermissionSub.PkiCollections,
|
||||
ProjectPermissionSub.CertificateTemplates,
|
||||
ProjectPermissionSub.Tags,
|
||||
ProjectPermissionSub.SecretRotation,
|
||||
ProjectPermissionSub.Kms,
|
||||
@@ -781,6 +797,34 @@ export const rolePermission2Form = (permissions: TProjectPermission[] = []) => {
|
||||
conditions: conditions ? convertCaslConditionToFormOperator(conditions) : [],
|
||||
inverted
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (subject === ProjectPermissionSub.CertificateTemplates) {
|
||||
if (!formVal[subject]) formVal[subject] = [];
|
||||
|
||||
formVal[subject]!.push({
|
||||
[ProjectPermissionPkiTemplateActions.Edit]: action.includes(
|
||||
ProjectPermissionPkiTemplateActions.Edit
|
||||
),
|
||||
[ProjectPermissionPkiTemplateActions.Delete]: action.includes(
|
||||
ProjectPermissionPkiTemplateActions.Delete
|
||||
),
|
||||
[ProjectPermissionPkiTemplateActions.Create]: action.includes(
|
||||
ProjectPermissionPkiTemplateActions.Create
|
||||
),
|
||||
[ProjectPermissionPkiTemplateActions.Read]: action.includes(
|
||||
ProjectPermissionPkiTemplateActions.Read
|
||||
),
|
||||
[ProjectPermissionPkiTemplateActions.IssueCert]: action.includes(
|
||||
ProjectPermissionPkiTemplateActions.IssueCert
|
||||
),
|
||||
[ProjectPermissionPkiTemplateActions.ListCerts]: action.includes(
|
||||
ProjectPermissionPkiTemplateActions.ListCerts
|
||||
),
|
||||
conditions: conditions ? convertCaslConditionToFormOperator(conditions) : [],
|
||||
inverted
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1119,10 +1163,12 @@ export const PROJECT_PERMISSION_OBJECT: TProjectPermissionObject = {
|
||||
[ProjectPermissionSub.CertificateTemplates]: {
|
||||
title: "Certificate Templates",
|
||||
actions: [
|
||||
{ label: "Read", value: "read" },
|
||||
{ label: "Create", value: "create" },
|
||||
{ label: "Modify", value: "edit" },
|
||||
{ label: "Remove", value: "delete" }
|
||||
{ label: "Read", value: ProjectPermissionPkiTemplateActions.Read },
|
||||
{ label: "Create", value: ProjectPermissionPkiTemplateActions.Create },
|
||||
{ label: "Modify", value: ProjectPermissionPkiTemplateActions.Edit },
|
||||
{ label: "Remove", value: ProjectPermissionPkiTemplateActions.Delete },
|
||||
{ label: "Issue Certificates", value: ProjectPermissionPkiTemplateActions.IssueCert },
|
||||
{ label: "List Certificates", value: ProjectPermissionPkiTemplateActions.ListCerts }
|
||||
]
|
||||
},
|
||||
[ProjectPermissionSub.SshCertificateAuthorities]: {
|
||||
|
||||
@@ -23,6 +23,7 @@ import { GeneralPermissionPolicies } from "./GeneralPermissionPolicies";
|
||||
import { IdentityManagementPermissionConditions } from "./IdentityManagementPermissionConditions";
|
||||
import { PermissionEmptyState } from "./PermissionEmptyState";
|
||||
import { PkiSubscriberPermissionConditions } from "./PkiSubscriberPermissionConditions";
|
||||
import { PkiTemplatePermissionConditions } from "./PkiTemplatePermissionConditions";
|
||||
import {
|
||||
formRolePermission2API,
|
||||
isConditionalSubjects,
|
||||
@@ -63,6 +64,10 @@ export const renderConditionalComponents = (
|
||||
return <PkiSubscriberPermissionConditions isDisabled={isDisabled} />;
|
||||
}
|
||||
|
||||
if (subject === ProjectPermissionSub.CertificateTemplates) {
|
||||
return <PkiTemplatePermissionConditions isDisabled={isDisabled} />;
|
||||
}
|
||||
|
||||
return <GeneralPermissionConditions isDisabled={isDisabled} type={subject} />;
|
||||
}
|
||||
|
||||
|
||||
@@ -123,6 +123,7 @@ import { Route as certManagerPkiSubscriberDetailsByIDPageRouteImport } from './p
|
||||
import { Route as certManagerCertAuthDetailsByIDPageRouteImport } from './pages/cert-manager/CertAuthDetailsByIDPage/route'
|
||||
import { Route as secretManagerIntegrationsListPageRouteImport } from './pages/secret-manager/IntegrationsListPage/route'
|
||||
import { Route as certManagerPkiSubscribersPageRouteImport } from './pages/cert-manager/PkiSubscribersPage/route'
|
||||
import { Route as certManagerPkiTemplateListPageRouteImport } from './pages/cert-manager/PkiTemplateListPage/route'
|
||||
import { Route as secretManagerIntegrationsWindmillConfigurePageRouteImport } from './pages/secret-manager/integrations/WindmillConfigurePage/route'
|
||||
import { Route as secretManagerIntegrationsWindmillAuthorizePageRouteImport } from './pages/secret-manager/integrations/WindmillAuthorizePage/route'
|
||||
import { Route as secretManagerIntegrationsVercelConfigurePageRouteImport } from './pages/secret-manager/integrations/VercelConfigurePage/route'
|
||||
@@ -257,6 +258,10 @@ const AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayout
|
||||
createFileRoute(
|
||||
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/subscribers',
|
||||
)()
|
||||
const AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutCertificateTemplatesImport =
|
||||
createFileRoute(
|
||||
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/certificate-templates',
|
||||
)()
|
||||
|
||||
// Create/Update Routes
|
||||
|
||||
@@ -870,6 +875,15 @@ const AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayout
|
||||
} as any,
|
||||
)
|
||||
|
||||
const AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutCertificateTemplatesRoute =
|
||||
AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutCertificateTemplatesImport.update(
|
||||
{
|
||||
id: '/certificate-templates',
|
||||
path: '/certificate-templates',
|
||||
getParentRoute: () => certManagerLayoutRoute,
|
||||
} as any,
|
||||
)
|
||||
|
||||
const projectAccessControlPageRouteCertManagerRoute =
|
||||
projectAccessControlPageRouteCertManagerImport.update({
|
||||
id: '/access-management',
|
||||
@@ -1156,6 +1170,14 @@ const certManagerPkiSubscribersPageRouteRoute =
|
||||
AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutSubscribersRoute,
|
||||
} as any)
|
||||
|
||||
const certManagerPkiTemplateListPageRouteRoute =
|
||||
certManagerPkiTemplateListPageRouteImport.update({
|
||||
id: '/',
|
||||
path: '/',
|
||||
getParentRoute: () =>
|
||||
AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutCertificateTemplatesRoute,
|
||||
} as any)
|
||||
|
||||
const secretManagerIntegrationsWindmillConfigurePageRouteRoute =
|
||||
secretManagerIntegrationsWindmillConfigurePageRouteImport.update({
|
||||
id: '/windmill/create',
|
||||
@@ -2391,6 +2413,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof projectAccessControlPageRouteCertManagerImport
|
||||
parentRoute: typeof certManagerLayoutImport
|
||||
}
|
||||
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/certificate-templates': {
|
||||
id: '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/certificate-templates'
|
||||
path: '/certificate-templates'
|
||||
fullPath: '/cert-manager/$projectId/certificate-templates'
|
||||
preLoaderRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutCertificateTemplatesImport
|
||||
parentRoute: typeof certManagerLayoutImport
|
||||
}
|
||||
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/subscribers': {
|
||||
id: '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/subscribers'
|
||||
path: '/subscribers'
|
||||
@@ -2489,6 +2518,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof projectAccessControlPageRouteSshImport
|
||||
parentRoute: typeof sshLayoutImport
|
||||
}
|
||||
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/certificate-templates/': {
|
||||
id: '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/certificate-templates/'
|
||||
path: '/'
|
||||
fullPath: '/cert-manager/$projectId/certificate-templates/'
|
||||
preLoaderRoute: typeof certManagerPkiTemplateListPageRouteImport
|
||||
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutCertificateTemplatesImport
|
||||
}
|
||||
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/subscribers/': {
|
||||
id: '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/subscribers/'
|
||||
path: '/'
|
||||
@@ -3360,6 +3396,21 @@ const AuthenticateInjectOrgDetailsOrgLayoutOrganizationRouteWithChildren =
|
||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationRouteChildren,
|
||||
)
|
||||
|
||||
interface AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutCertificateTemplatesRouteChildren {
|
||||
certManagerPkiTemplateListPageRouteRoute: typeof certManagerPkiTemplateListPageRouteRoute
|
||||
}
|
||||
|
||||
const AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutCertificateTemplatesRouteChildren: AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutCertificateTemplatesRouteChildren =
|
||||
{
|
||||
certManagerPkiTemplateListPageRouteRoute:
|
||||
certManagerPkiTemplateListPageRouteRoute,
|
||||
}
|
||||
|
||||
const AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutCertificateTemplatesRouteWithChildren =
|
||||
AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutCertificateTemplatesRoute._addFileChildren(
|
||||
AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutCertificateTemplatesRouteChildren,
|
||||
)
|
||||
|
||||
interface AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutSubscribersRouteChildren {
|
||||
certManagerPkiSubscribersPageRouteRoute: typeof certManagerPkiSubscribersPageRouteRoute
|
||||
certManagerPkiSubscriberDetailsByIDPageRouteRoute: typeof certManagerPkiSubscriberDetailsByIDPageRouteRoute
|
||||
@@ -3384,6 +3435,7 @@ interface certManagerLayoutRouteChildren {
|
||||
certManagerCertificatesPageRouteRoute: typeof certManagerCertificatesPageRouteRoute
|
||||
certManagerSettingsPageRouteRoute: typeof certManagerSettingsPageRouteRoute
|
||||
projectAccessControlPageRouteCertManagerRoute: typeof projectAccessControlPageRouteCertManagerRoute
|
||||
AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutCertificateTemplatesRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutCertificateTemplatesRouteWithChildren
|
||||
AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutSubscribersRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutSubscribersRouteWithChildren
|
||||
certManagerCertAuthDetailsByIDPageRouteRoute: typeof certManagerCertAuthDetailsByIDPageRouteRoute
|
||||
projectIdentityDetailsByIDPageRouteCertManagerRoute: typeof projectIdentityDetailsByIDPageRouteCertManagerRoute
|
||||
@@ -3400,6 +3452,8 @@ const certManagerLayoutRouteChildren: certManagerLayoutRouteChildren = {
|
||||
certManagerSettingsPageRouteRoute: certManagerSettingsPageRouteRoute,
|
||||
projectAccessControlPageRouteCertManagerRoute:
|
||||
projectAccessControlPageRouteCertManagerRoute,
|
||||
AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutCertificateTemplatesRoute:
|
||||
AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutCertificateTemplatesRouteWithChildren,
|
||||
AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutSubscribersRoute:
|
||||
AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutSubscribersRouteWithChildren,
|
||||
certManagerCertAuthDetailsByIDPageRouteRoute:
|
||||
@@ -4089,6 +4143,7 @@ export interface FileRoutesByFullPath {
|
||||
'/ssh/$projectId/overview': typeof sshSshHostsPageRouteRoute
|
||||
'/ssh/$projectId/settings': typeof sshSettingsPageRouteRoute
|
||||
'/cert-manager/$projectId/access-management': typeof projectAccessControlPageRouteCertManagerRoute
|
||||
'/cert-manager/$projectId/certificate-templates': typeof AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutCertificateTemplatesRouteWithChildren
|
||||
'/cert-manager/$projectId/subscribers': typeof AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutSubscribersRouteWithChildren
|
||||
'/integrations/azure-app-configuration/oauth2/callback': typeof secretManagerIntegrationsRouteAzureAppConfigurationsOauthRedirectRoute
|
||||
'/integrations/azure-key-vault/oauth2/callback': typeof secretManagerIntegrationsRouteAzureKeyVaultOauthRedirectRoute
|
||||
@@ -4103,6 +4158,7 @@ export interface FileRoutesByFullPath {
|
||||
'/secret-manager/$projectId/access-management': typeof projectAccessControlPageRouteSecretManagerRoute
|
||||
'/secret-manager/$projectId/integrations': typeof AuthenticateInjectOrgDetailsOrgLayoutSecretManagerProjectIdSecretManagerLayoutIntegrationsRouteWithChildren
|
||||
'/ssh/$projectId/access-management': typeof projectAccessControlPageRouteSshRoute
|
||||
'/cert-manager/$projectId/certificate-templates/': typeof certManagerPkiTemplateListPageRouteRoute
|
||||
'/cert-manager/$projectId/subscribers/': typeof certManagerPkiSubscribersPageRouteRoute
|
||||
'/secret-manager/$projectId/integrations/': typeof secretManagerIntegrationsListPageRouteRoute
|
||||
'/cert-manager/$projectId/ca/$caName': typeof certManagerCertAuthDetailsByIDPageRouteRoute
|
||||
@@ -4288,6 +4344,7 @@ export interface FileRoutesByTo {
|
||||
'/kms/$projectId/access-management': typeof projectAccessControlPageRouteKmsRoute
|
||||
'/secret-manager/$projectId/access-management': typeof projectAccessControlPageRouteSecretManagerRoute
|
||||
'/ssh/$projectId/access-management': typeof projectAccessControlPageRouteSshRoute
|
||||
'/cert-manager/$projectId/certificate-templates': typeof certManagerPkiTemplateListPageRouteRoute
|
||||
'/cert-manager/$projectId/subscribers': typeof certManagerPkiSubscribersPageRouteRoute
|
||||
'/secret-manager/$projectId/integrations': typeof secretManagerIntegrationsListPageRouteRoute
|
||||
'/cert-manager/$projectId/ca/$caName': typeof certManagerCertAuthDetailsByIDPageRouteRoute
|
||||
@@ -4479,6 +4536,7 @@ export interface FileRoutesById {
|
||||
'/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/overview': typeof sshSshHostsPageRouteRoute
|
||||
'/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/settings': typeof sshSettingsPageRouteRoute
|
||||
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/access-management': typeof projectAccessControlPageRouteCertManagerRoute
|
||||
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/certificate-templates': typeof AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutCertificateTemplatesRouteWithChildren
|
||||
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/subscribers': typeof AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdCertManagerLayoutSubscribersRouteWithChildren
|
||||
'/_authenticate/_inject-org-details/_org-layout/integrations/azure-app-configuration/oauth2/callback': typeof secretManagerIntegrationsRouteAzureAppConfigurationsOauthRedirectRoute
|
||||
'/_authenticate/_inject-org-details/_org-layout/integrations/azure-key-vault/oauth2/callback': typeof secretManagerIntegrationsRouteAzureKeyVaultOauthRedirectRoute
|
||||
@@ -4493,6 +4551,7 @@ export interface FileRoutesById {
|
||||
'/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/access-management': typeof projectAccessControlPageRouteSecretManagerRoute
|
||||
'/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/integrations': typeof AuthenticateInjectOrgDetailsOrgLayoutSecretManagerProjectIdSecretManagerLayoutIntegrationsRouteWithChildren
|
||||
'/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/access-management': typeof projectAccessControlPageRouteSshRoute
|
||||
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/certificate-templates/': typeof certManagerPkiTemplateListPageRouteRoute
|
||||
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/subscribers/': typeof certManagerPkiSubscribersPageRouteRoute
|
||||
'/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/integrations/': typeof secretManagerIntegrationsListPageRouteRoute
|
||||
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/ca/$caName': typeof certManagerCertAuthDetailsByIDPageRouteRoute
|
||||
@@ -4676,6 +4735,7 @@ export interface FileRouteTypes {
|
||||
| '/ssh/$projectId/overview'
|
||||
| '/ssh/$projectId/settings'
|
||||
| '/cert-manager/$projectId/access-management'
|
||||
| '/cert-manager/$projectId/certificate-templates'
|
||||
| '/cert-manager/$projectId/subscribers'
|
||||
| '/integrations/azure-app-configuration/oauth2/callback'
|
||||
| '/integrations/azure-key-vault/oauth2/callback'
|
||||
@@ -4690,6 +4750,7 @@ export interface FileRouteTypes {
|
||||
| '/secret-manager/$projectId/access-management'
|
||||
| '/secret-manager/$projectId/integrations'
|
||||
| '/ssh/$projectId/access-management'
|
||||
| '/cert-manager/$projectId/certificate-templates/'
|
||||
| '/cert-manager/$projectId/subscribers/'
|
||||
| '/secret-manager/$projectId/integrations/'
|
||||
| '/cert-manager/$projectId/ca/$caName'
|
||||
@@ -4874,6 +4935,7 @@ export interface FileRouteTypes {
|
||||
| '/kms/$projectId/access-management'
|
||||
| '/secret-manager/$projectId/access-management'
|
||||
| '/ssh/$projectId/access-management'
|
||||
| '/cert-manager/$projectId/certificate-templates'
|
||||
| '/cert-manager/$projectId/subscribers'
|
||||
| '/secret-manager/$projectId/integrations'
|
||||
| '/cert-manager/$projectId/ca/$caName'
|
||||
@@ -5063,6 +5125,7 @@ export interface FileRouteTypes {
|
||||
| '/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/overview'
|
||||
| '/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/settings'
|
||||
| '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/access-management'
|
||||
| '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/certificate-templates'
|
||||
| '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/subscribers'
|
||||
| '/_authenticate/_inject-org-details/_org-layout/integrations/azure-app-configuration/oauth2/callback'
|
||||
| '/_authenticate/_inject-org-details/_org-layout/integrations/azure-key-vault/oauth2/callback'
|
||||
@@ -5077,6 +5140,7 @@ export interface FileRouteTypes {
|
||||
| '/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/access-management'
|
||||
| '/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/integrations'
|
||||
| '/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/access-management'
|
||||
| '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/certificate-templates/'
|
||||
| '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/subscribers/'
|
||||
| '/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout/integrations/'
|
||||
| '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/ca/$caName'
|
||||
@@ -5605,6 +5669,7 @@ export const routeTree = rootRoute
|
||||
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/certificates",
|
||||
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/settings",
|
||||
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/access-management",
|
||||
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/certificate-templates",
|
||||
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/subscribers",
|
||||
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/ca/$caName",
|
||||
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/identities/$identityId",
|
||||
@@ -5731,6 +5796,13 @@ export const routeTree = rootRoute
|
||||
"filePath": "project/AccessControlPage/route-cert-manager.tsx",
|
||||
"parent": "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout"
|
||||
},
|
||||
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/certificate-templates": {
|
||||
"filePath": "",
|
||||
"parent": "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout",
|
||||
"children": [
|
||||
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/certificate-templates/"
|
||||
]
|
||||
},
|
||||
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/subscribers": {
|
||||
"filePath": "",
|
||||
"parent": "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout",
|
||||
@@ -5871,6 +5943,10 @@ export const routeTree = rootRoute
|
||||
"filePath": "project/AccessControlPage/route-ssh.tsx",
|
||||
"parent": "/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout"
|
||||
},
|
||||
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/certificate-templates/": {
|
||||
"filePath": "cert-manager/PkiTemplateListPage/route.tsx",
|
||||
"parent": "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/certificate-templates"
|
||||
},
|
||||
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/subscribers/": {
|
||||
"filePath": "cert-manager/PkiSubscribersPage/route.tsx",
|
||||
"parent": "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/subscribers"
|
||||
|
||||
@@ -293,6 +293,7 @@ const certManagerRoutes = route("/cert-manager/$projectId", [
|
||||
index("cert-manager/PkiSubscribersPage/route.tsx"),
|
||||
route("/$subscriberName", "cert-manager/PkiSubscriberDetailsByIDPage/route.tsx")
|
||||
]),
|
||||
route("/certificate-templates", [index("cert-manager/PkiTemplateListPage/route.tsx")]),
|
||||
route("/certificates", "cert-manager/CertificatesPage/route.tsx"),
|
||||
route("/certificate-authorities", "cert-manager/CertificateAuthoritiesPage/route.tsx"),
|
||||
route("/alerting", "cert-manager/AlertingPage/route.tsx"),
|
||||
|
||||
Reference in New Issue
Block a user