mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-14 11:29:42 +00:00
Preliminary scaffolding for CA structures
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
import { CertificateAuthorityType } from "./enums";
|
||||
|
||||
export const caTypeToNameMap: { [K in CertificateAuthorityType]: string } = {
|
||||
[CertificateAuthorityType.ROOT]: "Root",
|
||||
[CertificateAuthorityType.INTERMEDIATE]: "Intermediate"
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
export enum CertificateAuthorityType {
|
||||
ROOT = "root",
|
||||
INTERMEDIATE = "intermediate"
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export { CertificateAuthorityType } from "./enums";
|
||||
export { useCreateCa } from "./mutations";
|
||||
@@ -0,0 +1,23 @@
|
||||
import {
|
||||
useMutation
|
||||
// useQueryClient
|
||||
} from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import { TCertificateAuthority, TCreateCaDTO } from "./types";
|
||||
|
||||
export const useCreateCa = () => {
|
||||
// const queryClient = useQueryClient();
|
||||
return useMutation<TCertificateAuthority, {}, TCreateCaDTO>({
|
||||
mutationFn: async (body) => {
|
||||
const {
|
||||
data: { identity }
|
||||
} = await apiRequest.post("/api/v1/ca/", body);
|
||||
return identity;
|
||||
},
|
||||
onSuccess: () => {
|
||||
// queryClient.invalidateQueries(organizationKeys.getOrgIdentityMemberships(organizationId));
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
import { CertificateAuthorityType } from "./enums";
|
||||
|
||||
export type TCertificateAuthority = {
|
||||
id: string;
|
||||
parentCaId?: string;
|
||||
projectId: string;
|
||||
type: CertificateAuthorityType;
|
||||
dn: string;
|
||||
commonName: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export type TCreateCaDTO = {
|
||||
projectSlug: string;
|
||||
type: string;
|
||||
organization: string;
|
||||
ou: string;
|
||||
country: string;
|
||||
province: string;
|
||||
locality: string;
|
||||
commonName: string;
|
||||
};
|
||||
@@ -5,6 +5,7 @@ export * from "./auditLogs";
|
||||
export * from "./auditLogStreams";
|
||||
export * from "./auth";
|
||||
export * from "./bots";
|
||||
export * from "./ca";
|
||||
export * from "./dynamicSecret";
|
||||
export * from "./dynamicSecretLease";
|
||||
export * from "./groups";
|
||||
|
||||
@@ -21,6 +21,7 @@ export {
|
||||
useGetWorkspaceIntegrations,
|
||||
useGetWorkspaceSecrets,
|
||||
useGetWorkspaceUsers,
|
||||
useListWorkspaceCas,
|
||||
useListWorkspaceGroups,
|
||||
useNameWorkspaceSecrets,
|
||||
useRenameWorkspace,
|
||||
@@ -28,5 +29,4 @@ export {
|
||||
useUpdateIdentityWorkspaceRole,
|
||||
useUpdateUserWorkspaceRole,
|
||||
useUpdateWsEnvironment,
|
||||
useUpgradeProject
|
||||
} from "./queries";
|
||||
useUpgradeProject} from "./queries";
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import { TCertificateAuthority } from "../ca/types";
|
||||
import { TGroupMembership } from "../groups/types";
|
||||
import { IdentityMembership } from "../identities/types";
|
||||
import { IntegrationAuth } from "../integrationAuth/types";
|
||||
@@ -39,7 +40,8 @@ export const workspaceKeys = {
|
||||
getWorkspaceIdentityMemberships: (workspaceId: string) =>
|
||||
[{ workspaceId }, "workspace-identity-memberships"] as const,
|
||||
getWorkspaceGroupMemberships: (workspaceId: string) =>
|
||||
[{ workspaceId }, "workspace-groups"] as const
|
||||
[{ workspaceId }, "workspace-groups"] as const,
|
||||
getWorkspaceCas: (workspaceId: string) => [{ workspaceId }, "workspace-cas"] as const
|
||||
};
|
||||
|
||||
const fetchWorkspaceById = async (workspaceId: string) => {
|
||||
@@ -469,3 +471,18 @@ export const useListWorkspaceGroups = (projectSlug: string) => {
|
||||
enabled: true
|
||||
});
|
||||
};
|
||||
|
||||
export const useListWorkspaceCas = (projectSlug: string) => {
|
||||
return useQuery({
|
||||
queryKey: workspaceKeys.getWorkspaceCas(projectSlug),
|
||||
queryFn: async () => {
|
||||
const {
|
||||
data: { cas }
|
||||
} = await apiRequest.get<{ cas: TCertificateAuthority[] }>(
|
||||
`/api/v2/workspace/${projectSlug}/cas`
|
||||
);
|
||||
return cas;
|
||||
},
|
||||
enabled: Boolean(projectSlug)
|
||||
});
|
||||
};
|
||||
|
||||
@@ -519,6 +519,18 @@ export const AppLayout = ({ children }: LayoutProps) => {
|
||||
</MenuItem>
|
||||
</a>
|
||||
</Link>
|
||||
<Link href={`/project/${currentWorkspace?.id}/certificates`} passHref>
|
||||
<a>
|
||||
<MenuItem
|
||||
isSelected={
|
||||
router.asPath === `/project/${currentWorkspace?.id}/certificates`
|
||||
}
|
||||
icon="system-outline-90-lock-closed"
|
||||
>
|
||||
Certificates
|
||||
</MenuItem>
|
||||
</a>
|
||||
</Link>
|
||||
<Link href={`/project/${currentWorkspace?.id}/members`} passHref>
|
||||
<a>
|
||||
<MenuItem
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Head from "next/head";
|
||||
|
||||
import { CertificatesPage } from "@app/views/Project/CertificatesPage";
|
||||
|
||||
const Certificates = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="h-full bg-bunker-800">
|
||||
<Head>
|
||||
<title>{t("common.head-title", { title: t("settings.project.title") })}</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
<meta property="og:image" content="/images/message.png" />
|
||||
</Head>
|
||||
<div>Test CA page</div>
|
||||
<CertificatesPage />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Certificates;
|
||||
|
||||
Certificates.requireAuth = true;
|
||||
@@ -0,0 +1,44 @@
|
||||
import { Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
|
||||
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context";
|
||||
import { withProjectPermission } from "@app/hoc";
|
||||
|
||||
import { CaTab } from "./components";
|
||||
// import { CaTable } from "./components";
|
||||
|
||||
// TODO: fix permission
|
||||
|
||||
/**
|
||||
* TODO 1: CA section
|
||||
* TODO 2: Certificates section
|
||||
*/
|
||||
|
||||
enum TabSections {
|
||||
Ca = "certificate-authorities",
|
||||
Certificates = "certificates"
|
||||
}
|
||||
|
||||
export const CertificatesPage = withProjectPermission(
|
||||
() => {
|
||||
return (
|
||||
<div className="container mx-auto flex flex-col justify-between bg-bunker-800 text-white">
|
||||
<div className="mx-auto mb-6 w-full max-w-7xl py-6 px-6">
|
||||
<p className="mr-4 mb-4 text-3xl font-semibold text-white">Certificates</p>
|
||||
<Tabs defaultValue={TabSections.Ca}>
|
||||
<TabList>
|
||||
<Tab value={TabSections.Ca}>Certificate Authorities</Tab>
|
||||
<Tab value={TabSections.Certificates}>Certificates</Tab>
|
||||
</TabList>
|
||||
<TabPanel value={TabSections.Ca}>
|
||||
<CaTab />
|
||||
</TabPanel>
|
||||
<TabPanel value={TabSections.Certificates}>
|
||||
<div>Certs</div>
|
||||
{/* <OrgGroupsTab /> */}
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
{ action: ProjectPermissionActions.Read, subject: ProjectPermissionSub.AuditLogs }
|
||||
);
|
||||
@@ -0,0 +1,17 @@
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
import { CaSection } from "./components";
|
||||
|
||||
export const CaTab = () => {
|
||||
return (
|
||||
<motion.div
|
||||
key="panel-certificate-authorities"
|
||||
transition={{ duration: 0.15 }}
|
||||
initial={{ opacity: 0, translateX: 30 }}
|
||||
animate={{ opacity: 1, translateX: 0 }}
|
||||
exit={{ opacity: 0, translateX: 30 }}
|
||||
>
|
||||
<CaSection />
|
||||
</motion.div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,346 @@
|
||||
// import { useEffect } from "react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
// import { yupResolver } from "@hookform/resolvers/yup";
|
||||
// import * as yup from "yup";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import {
|
||||
Button,
|
||||
FormControl,
|
||||
Input,
|
||||
Modal,
|
||||
ModalContent,
|
||||
Select,
|
||||
SelectItem
|
||||
} from "@app/components/v2";
|
||||
import { useWorkspace } from "@app/context";
|
||||
import { CertificateAuthorityType, useCreateCa } from "@app/hooks/api/ca";
|
||||
// import { useCreateIdentity, useGetOrgRoles, useUpdateIdentity } from "@app/hooks/api";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
const schema = z
|
||||
.object({
|
||||
type: z.enum(["root", "intermediate"]), // move to ref enum of hooks/api
|
||||
organization: z.string(),
|
||||
ou: z.string(),
|
||||
country: z.string(),
|
||||
province: z.string(),
|
||||
locality: z.string(),
|
||||
commonName: z.string()
|
||||
})
|
||||
.required();
|
||||
|
||||
export type FormData = z.infer<typeof schema>;
|
||||
|
||||
type Props = {
|
||||
popUp: UsePopUpState<["ca"]>;
|
||||
// handlePopUpOpen: (
|
||||
// popUpName: keyof UsePopUpState<["identityAuthMethod"]>,
|
||||
// data: {
|
||||
// identityId: string;
|
||||
// name: string;
|
||||
// authMethod?: IdentityAuthMethod;
|
||||
// }
|
||||
// ) => void;
|
||||
handlePopUpToggle: (popUpName: keyof UsePopUpState<["ca"]>, state?: boolean) => void;
|
||||
};
|
||||
|
||||
const caTypes = [
|
||||
{ label: "Root", value: CertificateAuthorityType.ROOT },
|
||||
{ label: "intermediate", value: CertificateAuthorityType.INTERMEDIATE }
|
||||
];
|
||||
|
||||
export const CaModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
console.log("CaModal currentWorkspace: ", currentWorkspace);
|
||||
|
||||
const { mutateAsync: createMutateAsync } = useCreateCa();
|
||||
// const { data: roles } = useGetOrgRoles(orgId);
|
||||
// const { mutateAsync: createMutateAsync } = useCreateIdentity();
|
||||
// const { mutateAsync: updateMutateAsync } = useUpdateIdentity();
|
||||
// const { mutateAsync: addMutateAsync } = useAddIdentityUniversalAuth();
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
reset,
|
||||
formState: { isSubmitting }
|
||||
} = useForm<FormData>({
|
||||
resolver: zodResolver(schema),
|
||||
defaultValues: {
|
||||
type: CertificateAuthorityType.ROOT,
|
||||
organization: "",
|
||||
ou: "",
|
||||
country: "",
|
||||
province: "",
|
||||
locality: "",
|
||||
commonName: ""
|
||||
}
|
||||
});
|
||||
|
||||
// useEffect(() => {
|
||||
// const identity = popUp?.identity?.data as {
|
||||
// identityId: string;
|
||||
// name: string;
|
||||
// role: string;
|
||||
// customRole: {
|
||||
// name: string;
|
||||
// slug: string;
|
||||
// };
|
||||
// };
|
||||
|
||||
// if (!roles?.length) return;
|
||||
|
||||
// if (identity) {
|
||||
// reset({
|
||||
// name: identity.name,
|
||||
// role: identity?.customRole?.slug ?? identity.role
|
||||
// });
|
||||
// } else {
|
||||
// reset({
|
||||
// name: "",
|
||||
// role: roles[0].slug
|
||||
// });
|
||||
// }
|
||||
// }, [popUp?.identity?.data, roles]);
|
||||
|
||||
const onFormSubmit = async ({
|
||||
type,
|
||||
commonName,
|
||||
organization,
|
||||
ou,
|
||||
country,
|
||||
locality,
|
||||
province
|
||||
}: FormData) => {
|
||||
try {
|
||||
console.log("onFormSubmit args: ", {
|
||||
commonName,
|
||||
organization,
|
||||
ou,
|
||||
country,
|
||||
locality,
|
||||
province
|
||||
});
|
||||
|
||||
if (!currentWorkspace?.slug) return;
|
||||
|
||||
await createMutateAsync({
|
||||
projectSlug: currentWorkspace.slug,
|
||||
type,
|
||||
commonName,
|
||||
organization,
|
||||
ou,
|
||||
country,
|
||||
province,
|
||||
locality
|
||||
});
|
||||
|
||||
// const identity = popUp?.identity?.data as {
|
||||
// identityId: string;
|
||||
// name: string;
|
||||
// role: string;
|
||||
// };
|
||||
|
||||
// if (identity) {
|
||||
// // update
|
||||
|
||||
// await updateMutateAsync({
|
||||
// identityId: identity.identityId,
|
||||
// name,
|
||||
// role: role || undefined,
|
||||
// organizationId: orgId
|
||||
// });
|
||||
|
||||
// handlePopUpToggle("identity", false);
|
||||
// } else {
|
||||
// // create
|
||||
|
||||
// const {
|
||||
// id: createdId,
|
||||
// name: createdName,
|
||||
// authMethod
|
||||
// } = await createMutateAsync({
|
||||
// name,
|
||||
// role: role || undefined,
|
||||
// organizationId: orgId
|
||||
// });
|
||||
|
||||
// await addMutateAsync({
|
||||
// organizationId: orgId,
|
||||
// identityId: createdId,
|
||||
// clientSecretTrustedIps: [{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }],
|
||||
// accessTokenTrustedIps: [{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }],
|
||||
// accessTokenTTL: 2592000,
|
||||
// accessTokenMaxTTL: 2592000,
|
||||
// accessTokenNumUsesLimit: 0
|
||||
// });
|
||||
|
||||
// handlePopUpToggle("identity", false);
|
||||
// handlePopUpOpen("identityAuthMethod", {
|
||||
// identityId: createdId,
|
||||
// name: createdName,
|
||||
// authMethod
|
||||
// });
|
||||
// }
|
||||
|
||||
createNotification({
|
||||
text: `Successfully ${popUp?.ca?.data ? "updated" : "created"} CA`,
|
||||
type: "success"
|
||||
});
|
||||
|
||||
reset();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
const error = err as any;
|
||||
const text =
|
||||
error?.response?.data?.message ?? `Failed to ${popUp?.ca?.data ? "update" : "create"} CA`;
|
||||
|
||||
createNotification({
|
||||
text,
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={popUp?.ca?.isOpen}
|
||||
onOpenChange={(isOpen) => {
|
||||
handlePopUpToggle("ca", isOpen);
|
||||
reset();
|
||||
}}
|
||||
>
|
||||
<ModalContent title={`${popUp?.ca?.data ? "Update" : "Create"} CA`}>
|
||||
<form onSubmit={handleSubmit(onFormSubmit)}>
|
||||
<Controller
|
||||
control={control}
|
||||
name="type"
|
||||
defaultValue={CertificateAuthorityType.ROOT}
|
||||
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
|
||||
<FormControl label="CA Type" errorText={error?.message} isError={Boolean(error)}>
|
||||
<Select
|
||||
defaultValue={field.value}
|
||||
{...field}
|
||||
onValueChange={(e) => onChange(e)}
|
||||
className="w-full"
|
||||
// isDisabled={!!identityAuthMethodData?.authMethod}
|
||||
>
|
||||
{caTypes.map(({ label, value }) => (
|
||||
<SelectItem value={String(value || "")} key={label}>
|
||||
{label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="organization"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Organization (O)"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
>
|
||||
<Input {...field} placeholder="Acme Corp" />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="ou"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Organization Unit (OU)"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
>
|
||||
<Input {...field} placeholder="Engineering" />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="country"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Country Name (C)"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
>
|
||||
<Input {...field} placeholder="United States (US)" />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="province"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="State or Province Name"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
>
|
||||
<Input {...field} placeholder="California" />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="locality"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Locality Name"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
>
|
||||
<Input {...field} placeholder="San Francisco" />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="commonName"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Common Name (CN)"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
>
|
||||
<Input {...field} placeholder="Example CA" />
|
||||
</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>
|
||||
);
|
||||
};
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
// import { useState } from "react";
|
||||
import { faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
// import { createNotification } from "@app/components/notifications";
|
||||
// import { OrgPermissionCan } from "@app/components/permissions";
|
||||
import {
|
||||
Button
|
||||
// DeleteActionModal,
|
||||
// EmailServiceSetupModal,
|
||||
// UpgradePlanModal
|
||||
} from "@app/components/v2";
|
||||
// import {
|
||||
// OrgPermissionActions,
|
||||
// OrgPermissionSubjects,
|
||||
// useOrganization,
|
||||
// useSubscription
|
||||
// } from "@app/context";
|
||||
// import { useDeleteOrgMembership } from "@app/hooks/api";
|
||||
import { usePopUp } from "@app/hooks/usePopUp";
|
||||
|
||||
import { CaModal } from "./CaModal";
|
||||
import { CaTable } from "./CaTable";
|
||||
// import { AddOrgMemberModal } from "./AddOrgMemberModal";
|
||||
// import { OrgMembersTable } from "./OrgMembersTable";
|
||||
|
||||
export const CaSection = () => {
|
||||
// const { subscription } = useSubscription();
|
||||
// const { currentOrg } = useOrganization();
|
||||
// const orgId = currentOrg?.id ?? "";
|
||||
|
||||
// const [completeInviteLink, setCompleteInviteLink] = useState<string>("");
|
||||
|
||||
const {
|
||||
popUp,
|
||||
handlePopUpOpen,
|
||||
// handlePopUpClose,
|
||||
handlePopUpToggle
|
||||
} = usePopUp(["ca"] as const);
|
||||
|
||||
// const { mutateAsync: deleteMutateAsync } = useDeleteOrgMembership();
|
||||
|
||||
// const isMoreUsersNotAllowed = subscription?.memberLimit
|
||||
// ? subscription.membersUsed >= subscription.memberLimit
|
||||
// : false;
|
||||
|
||||
// const handleAddMemberModal = () => {
|
||||
// if (currentOrg?.authEnforced) {
|
||||
// createNotification({
|
||||
// text: "You cannot manage users from Infisical when org-level auth is enforced for your organization",
|
||||
// type: "error"
|
||||
// });
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (isMoreUsersNotAllowed) {
|
||||
// handlePopUpOpen("upgradePlan", {
|
||||
// description: "You can add more members if you upgrade your Infisical plan."
|
||||
// });
|
||||
// } else {
|
||||
// handlePopUpOpen("addMember");
|
||||
// }
|
||||
// };
|
||||
|
||||
// const onRemoveMemberSubmit = async (orgMembershipId: string) => {
|
||||
// try {
|
||||
// await deleteMutateAsync({
|
||||
// orgId,
|
||||
// membershipId: orgMembershipId
|
||||
// });
|
||||
|
||||
// createNotification({
|
||||
// text: "Successfully removed user from org",
|
||||
// type: "success"
|
||||
// });
|
||||
// } catch (err) {
|
||||
// console.error(err);
|
||||
// createNotification({
|
||||
// text: "Failed to remove user from the organization",
|
||||
// type: "error"
|
||||
// });
|
||||
// }
|
||||
|
||||
// handlePopUpClose("removeMember");
|
||||
// };
|
||||
|
||||
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 Authorities</p>
|
||||
{/* <OrgPermissionCan I={OrgPermissionActions.Create} a={OrgPermissionSubjects.Member}>
|
||||
{(isAllowed) => ( */}
|
||||
<Button
|
||||
colorSchema="primary"
|
||||
type="submit"
|
||||
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
||||
onClick={() => handlePopUpOpen("ca")}
|
||||
// isDisabled={!isAllowed}
|
||||
>
|
||||
Create CA
|
||||
</Button>
|
||||
{/* )} */}
|
||||
{/* </OrgPermissionCan> */}
|
||||
</div>
|
||||
<CaModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||
<CaTable />
|
||||
{/* <OrgMembersTable
|
||||
handlePopUpOpen={handlePopUpOpen}
|
||||
setCompleteInviteLink={setCompleteInviteLink}
|
||||
/>
|
||||
<AddOrgMemberModal
|
||||
popUp={popUp}
|
||||
handlePopUpToggle={handlePopUpToggle}
|
||||
completeInviteLink={completeInviteLink}
|
||||
setCompleteInviteLink={setCompleteInviteLink}
|
||||
/>
|
||||
<DeleteActionModal
|
||||
isOpen={popUp.removeMember.isOpen}
|
||||
title={`Are you sure want to remove member with username ${
|
||||
(popUp?.removeMember?.data as { username: string })?.username || ""
|
||||
}?`}
|
||||
onChange={(isOpen) => handlePopUpToggle("removeMember", isOpen)}
|
||||
deleteKey="confirm"
|
||||
onDeleteApproved={() =>
|
||||
onRemoveMemberSubmit(
|
||||
(popUp?.removeMember?.data as { orgMembershipId: string })?.orgMembershipId
|
||||
)
|
||||
}
|
||||
/>
|
||||
<UpgradePlanModal
|
||||
isOpen={popUp.upgradePlan.isOpen}
|
||||
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
|
||||
text={(popUp.upgradePlan?.data as { description: string })?.description}
|
||||
/>
|
||||
<EmailServiceSetupModal
|
||||
isOpen={popUp.setUpEmail?.isOpen}
|
||||
onOpenChange={(isOpen) => handlePopUpToggle("setUpEmail", isOpen)}
|
||||
/> */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
import { faCertificate } from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
import {
|
||||
EmptyState,
|
||||
Table,
|
||||
TableContainer,
|
||||
TableSkeleton,
|
||||
TBody,
|
||||
Td,
|
||||
Th,
|
||||
THead,
|
||||
Tr
|
||||
} from "@app/components/v2";
|
||||
import { useWorkspace } from "@app/context";
|
||||
import { useListWorkspaceCas } from "@app/hooks/api";
|
||||
import { caTypeToNameMap } from "@app/hooks/api/ca/constants";
|
||||
|
||||
export const CaTable = () => {
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
const { data, isLoading } = useListWorkspaceCas(currentWorkspace?.slug ?? "");
|
||||
return (
|
||||
<div>
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<THead>
|
||||
<Tr>
|
||||
<Th>Subject</Th>
|
||||
<Th>Status</Th>
|
||||
<Th>Type</Th>
|
||||
</Tr>
|
||||
</THead>
|
||||
<TBody>
|
||||
{isLoading && <TableSkeleton columns={3} innerKey="project-cas" />}
|
||||
{!isLoading &&
|
||||
data &&
|
||||
data.length > 0 &&
|
||||
data.map((ca) => {
|
||||
return (
|
||||
<Tr className="h-10" key={`ca-${ca.id}`}>
|
||||
<Td>{ca.dn}</Td>
|
||||
<Td>Pending</Td>
|
||||
<Td>{caTypeToNameMap[ca.type]}</Td>
|
||||
</Tr>
|
||||
);
|
||||
})}
|
||||
</TBody>
|
||||
</Table>
|
||||
{!isLoading && data?.length === 0 && (
|
||||
<EmptyState title="No groups have been added to this project" icon={faCertificate} />
|
||||
)}
|
||||
</TableContainer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export { CaSection } from "./CaSection";
|
||||
@@ -0,0 +1 @@
|
||||
export { CaTab } from "./CaTab";
|
||||
@@ -0,0 +1 @@
|
||||
export { CaTab } from "./CaTab";
|
||||
@@ -0,0 +1 @@
|
||||
export { CertificatesPage } from "./CertificatesPage";
|
||||
Reference in New Issue
Block a user