diff --git a/backend/src/services/secret-sync/aws-parameter-store/aws-parameter-store-sync-fns.ts b/backend/src/services/secret-sync/aws-parameter-store/aws-parameter-store-sync-fns.ts index 7e77bd256..abc4dcf82 100644 --- a/backend/src/services/secret-sync/aws-parameter-store/aws-parameter-store-sync-fns.ts +++ b/backend/src/services/secret-sync/aws-parameter-store/aws-parameter-store-sync-fns.ts @@ -169,7 +169,7 @@ const getParameterStoreTagsRecord = async ( throw new SecretSyncError({ message: - "IAM role has inadequate permissions to manage resource tags. Ensure the following polices are present: ssm:ListTagsForResource, ssm:AddTagsToResource, and ssm:RemoveTagsFromResource", + "IAM role has inadequate permissions to manage resource tags. Ensure the following policies are present: ssm:ListTagsForResource, ssm:AddTagsToResource, and ssm:RemoveTagsFromResource", shouldRetry: false }); } diff --git a/docs/documentation/platform/access-controls/abac/managing-user-metadata.mdx b/docs/documentation/platform/access-controls/abac/managing-user-metadata.mdx index 3f62a3b61..b6d1d691f 100644 --- a/docs/documentation/platform/access-controls/abac/managing-user-metadata.mdx +++ b/docs/documentation/platform/access-controls/abac/managing-user-metadata.mdx @@ -27,7 +27,7 @@ User identities can have metadata attributes assigned directly. These attributes #### Applying ABAC Policies with User Metadata -Attribute-based access controls are currently only available for polices defined on Secrets Manager projects. +Attribute-based access controls are currently only available for policies defined on Secrets Manager projects. You can set ABAC permissions to dynamically set access to environments, folders, secrets, and secret tags. diff --git a/docs/integrations/platforms/kubernetes/infisical-dynamic-secret-crd.mdx b/docs/integrations/platforms/kubernetes/infisical-dynamic-secret-crd.mdx index 21f54994a..5962e4c10 100644 --- a/docs/integrations/platforms/kubernetes/infisical-dynamic-secret-crd.mdx +++ b/docs/integrations/platforms/kubernetes/infisical-dynamic-secret-crd.mdx @@ -165,7 +165,7 @@ spec: - Creation polices allow you to control whether or not owner references should be added to the managed Kubernetes secret that is generated by the Infisical operator. + Creation policies allow you to control whether or not owner references should be added to the managed Kubernetes secret that is generated by the Infisical operator. This is useful for tools such as ArgoCD, where every resource requires an owner reference; otherwise, it will be pruned automatically. #### Available options diff --git a/docs/integrations/platforms/kubernetes/infisical-secret-crd.mdx b/docs/integrations/platforms/kubernetes/infisical-secret-crd.mdx index a79a8d0a5..5ff5d468f 100644 --- a/docs/integrations/platforms/kubernetes/infisical-secret-crd.mdx +++ b/docs/integrations/platforms/kubernetes/infisical-secret-crd.mdx @@ -832,7 +832,7 @@ The namespace of the managed Kubernetes secret to be created. Override the default Opaque type for managed secrets with this field. Useful for creating kubernetes.io/dockerconfigjson secrets. -Creation polices allow you to control whether or not owner references should be added to the managed Kubernetes secret that is generated by the Infisical operator. +Creation policies allow you to control whether or not owner references should be added to the managed Kubernetes secret that is generated by the Infisical operator. This is useful for tools such as ArgoCD, where every resource requires an owner reference; otherwise, it will be pruned automatically. #### Available options @@ -940,7 +940,7 @@ The Infisical operator will automatically create the Kubernetes config map in th The namespace of the managed Kubernetes config map that your Infisical data will be stored in. - Creation polices allow you to control whether or not owner references should be added to the managed Kubernetes config map that is generated by the Infisical operator. + Creation policies allow you to control whether or not owner references should be added to the managed Kubernetes config map that is generated by the Infisical operator. This is useful for tools such as ArgoCD, where every resource requires an owner reference; otherwise, it will be pruned automatically. #### Available options diff --git a/frontend/src/components/projects/ProjectSettings/components/ProjectTemplatesTab/components/EditProjectTemplateSection/components/ProjectTemplateEditRoleForm.tsx b/frontend/src/components/projects/ProjectSettings/components/ProjectTemplatesTab/components/EditProjectTemplateSection/components/ProjectTemplateEditRoleForm.tsx index b1a639e89..7431b41fa 100644 --- a/frontend/src/components/projects/ProjectSettings/components/ProjectTemplatesTab/components/EditProjectTemplateSection/components/ProjectTemplateEditRoleForm.tsx +++ b/frontend/src/components/projects/ProjectSettings/components/ProjectTemplatesTab/components/EditProjectTemplateSection/components/ProjectTemplateEditRoleForm.tsx @@ -6,15 +6,15 @@ import { twMerge } from "tailwind-merge"; import { z } from "zod"; import { createNotification } from "@app/components/notifications"; -import { Button, FormControl, Input, Modal, ModalContent, ModalTrigger } from "@app/components/v2"; +import { Button, FormControl, Input } from "@app/components/v2"; import { ProjectPermissionSub } from "@app/context"; import { isCustomProjectRole } from "@app/helpers/roles"; import { usePopUp } from "@app/hooks"; import { TProjectTemplate, useUpdateProjectTemplate } from "@app/hooks/api/projectTemplates"; import { slugSchema } from "@app/lib/schemas"; import { GeneralPermissionPolicies } from "@app/pages/project/RoleDetailsBySlugPage/components/GeneralPermissionPolicies"; -import { NewPermissionRule } from "@app/pages/project/RoleDetailsBySlugPage/components/NewPermissionRule"; import { PermissionEmptyState } from "@app/pages/project/RoleDetailsBySlugPage/components/PermissionEmptyState"; +import { PolicySelectionModal } from "@app/pages/project/RoleDetailsBySlugPage/components/PolicySelectionModal"; import { formRolePermission2API, PROJECT_PERMISSION_OBJECT, @@ -44,7 +44,7 @@ export const ProjectTemplateEditRoleForm = ({ role, isDisabled }: Props) => { - const { popUp, handlePopUpToggle } = usePopUp(["createPolicy"] as const); + const { popUp, handlePopUpToggle } = usePopUp(["addPolicy"] as const); const formMethods = useForm({ values: role ? { ...role, permissions: rolePermission2Form(role.permissions) } : undefined, @@ -119,34 +119,29 @@ export const ProjectTemplateEditRoleForm = ({ - handlePopUpToggle("createPolicy", isOpen)} + - - - handlePopUpToggle("createPolicy")} /> - - + Add Policies + + handlePopUpToggle("addPolicy", isOpen)} + /> )} diff --git a/frontend/src/hooks/useGetProjectTypeFromRoute.tsx b/frontend/src/hooks/useGetProjectTypeFromRoute.tsx index 95215eff5..b3b8f3d5e 100644 --- a/frontend/src/hooks/useGetProjectTypeFromRoute.tsx +++ b/frontend/src/hooks/useGetProjectTypeFromRoute.tsx @@ -1,3 +1,4 @@ +import { useMemo } from "react"; import { useRouterState } from "@tanstack/react-router"; import { ProjectType } from "@app/hooks/api/workspace/types"; @@ -5,9 +6,17 @@ import { ProjectType } from "@app/hooks/api/workspace/types"; export const useGetProjectTypeFromRoute = () => { const { location } = useRouterState(); - const segment = location.pathname.split("/")[2]; + return useMemo(() => { + const segments = location.pathname.split("/"); - if (!Object.values(ProjectType).includes(segment as ProjectType)) return undefined; + let type: ProjectType | undefined; - return segment as ProjectType; + // location of project type can vary in router path, so we need to check all possible values + segments.forEach((segment) => { + if (Object.values(ProjectType).includes(segment as ProjectType)) + type = segment as ProjectType; + }); + + return type; + }, [location]); }; diff --git a/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityProjectAdditionalPrivilegeSection/IdentityProjectAdditionalPrivilegeModifySection.tsx b/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityProjectAdditionalPrivilegeSection/IdentityProjectAdditionalPrivilegeModifySection.tsx index ac761e129..50d392748 100644 --- a/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityProjectAdditionalPrivilegeSection/IdentityProjectAdditionalPrivilegeModifySection.tsx +++ b/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityProjectAdditionalPrivilegeSection/IdentityProjectAdditionalPrivilegeModifySection.tsx @@ -18,10 +18,6 @@ import { TtlFormLabel } from "@app/components/features"; import { createNotification } from "@app/components/notifications"; import { Button, - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, FormControl, FormLabel, Input, @@ -37,6 +33,7 @@ import { useProjectPermission, useWorkspace } from "@app/context"; +import { usePopUp } from "@app/hooks"; import { useCreateIdentityProjectAdditionalPrivilege, useGetIdentityProjectPrivilegeDetails, @@ -45,12 +42,11 @@ import { import { IdentityProjectAdditionalPrivilegeTemporaryMode } from "@app/hooks/api/identityProjectAdditionalPrivilege/types"; import { GeneralPermissionPolicies } from "@app/pages/project/RoleDetailsBySlugPage/components/GeneralPermissionPolicies"; import { PermissionEmptyState } from "@app/pages/project/RoleDetailsBySlugPage/components/PermissionEmptyState"; +import { PolicySelectionModal } from "@app/pages/project/RoleDetailsBySlugPage/components/PolicySelectionModal"; import { formRolePermission2API, - isConditionalSubjects, PROJECT_PERMISSION_OBJECT, projectRoleFormSchema, - ProjectTypePermissionSubjects, rolePermission2Form } from "@app/pages/project/RoleDetailsBySlugPage/components/ProjectRoleModifySection.utils"; import { renderConditionalComponents } from "@app/pages/project/RoleDetailsBySlugPage/components/RolePermissionsSection"; @@ -101,6 +97,7 @@ export const IdentityProjectAdditionalPrivilegeModifySection = ({ ProjectPermissionIdentityActions.Edit, subject(ProjectPermissionSub.Identity, { identityId }) ); + const { popUp, handlePopUpToggle } = usePopUp(["addPolicy"] as const); const form = useForm({ values: privilegeDetails @@ -195,30 +192,6 @@ export const IdentityProjectAdditionalPrivilegeModifySection = ({ } } - const onNewPolicy = (selectedSubject: ProjectPermissionSub) => { - const rootPolicyValue = form.getValues(`permissions.${selectedSubject}`); - if (rootPolicyValue && isConditionalSubjects(selectedSubject)) { - form.setValue( - `permissions.${selectedSubject}`, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore-error akhilmhdh: this is because of ts collision with both - [...rootPolicyValue, {}], - { shouldDirty: true, shouldTouch: true } - ); - } else { - form.setValue( - `permissions.${selectedSubject}`, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore-error akhilmhdh: this is because of ts collision with both - [{}], - { - shouldDirty: true, - shouldTouch: true - } - ); - } - }; - return (
} > Save - - - - - - {Object.keys(PROJECT_PERMISSION_OBJECT) - .filter( - (sub) => - ProjectTypePermissionSubjects[currentWorkspace.type][ - sub as ProjectPermissionSub - ] - ) - .sort((a, b) => - PROJECT_PERMISSION_OBJECT[a as keyof typeof PROJECT_PERMISSION_OBJECT].title - .toLowerCase() - .localeCompare( - PROJECT_PERMISSION_OBJECT[ - b as keyof typeof PROJECT_PERMISSION_OBJECT - ].title.toLowerCase() - ) - ) - .map((permissionSubject) => ( - onNewPolicy(permissionSubject as ProjectPermissionSub)} - > - {PROJECT_PERMISSION_OBJECT[permissionSubject as ProjectPermissionSub].title} - - ))} - - + @@ -436,6 +382,10 @@ export const IdentityProjectAdditionalPrivilegeModifySection = ({ ) )} + handlePopUpToggle("addPolicy", isOpen)} + /> ); diff --git a/frontend/src/pages/project/MemberDetailsByIDPage/components/MemberProjectAdditionalPrivilegeSection/MembershipProjectAdditionalPrivilegeModifySection.tsx b/frontend/src/pages/project/MemberDetailsByIDPage/components/MemberProjectAdditionalPrivilegeSection/MembershipProjectAdditionalPrivilegeModifySection.tsx index 6b345250c..5fee21f9c 100644 --- a/frontend/src/pages/project/MemberDetailsByIDPage/components/MemberProjectAdditionalPrivilegeSection/MembershipProjectAdditionalPrivilegeModifySection.tsx +++ b/frontend/src/pages/project/MemberDetailsByIDPage/components/MemberProjectAdditionalPrivilegeSection/MembershipProjectAdditionalPrivilegeModifySection.tsx @@ -17,10 +17,6 @@ import { TtlFormLabel } from "@app/components/features"; import { createNotification } from "@app/components/notifications"; import { Button, - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, FormControl, FormLabel, Input, @@ -36,6 +32,7 @@ import { useProjectPermission, useWorkspace } from "@app/context"; +import { usePopUp } from "@app/hooks"; import { useCreateProjectUserAdditionalPrivilege, useGetProjectUserPrivilegeDetails, @@ -44,12 +41,11 @@ import { import { ProjectUserAdditionalPrivilegeTemporaryMode } from "@app/hooks/api/projectUserAdditionalPrivilege/types"; import { GeneralPermissionPolicies } from "@app/pages/project/RoleDetailsBySlugPage/components/GeneralPermissionPolicies"; import { PermissionEmptyState } from "@app/pages/project/RoleDetailsBySlugPage/components/PermissionEmptyState"; +import { PolicySelectionModal } from "@app/pages/project/RoleDetailsBySlugPage/components/PolicySelectionModal"; import { formRolePermission2API, - isConditionalSubjects, PROJECT_PERMISSION_OBJECT, projectRoleFormSchema, - ProjectTypePermissionSubjects, rolePermission2Form } from "@app/pages/project/RoleDetailsBySlugPage/components/ProjectRoleModifySection.utils"; import { renderConditionalComponents } from "@app/pages/project/RoleDetailsBySlugPage/components/RolePermissionsSection"; @@ -87,6 +83,8 @@ export const MembershipProjectAdditionalPrivilegeModifySection = ({ projectMembershipId, isDisabled }: Props) => { + const { popUp, handlePopUpToggle } = usePopUp(["addPolicy"] as const); + const isCreate = !privilegeId; const { currentWorkspace } = useWorkspace(); const projectId = currentWorkspace?.id || ""; @@ -167,30 +165,6 @@ export const MembershipProjectAdditionalPrivilegeModifySection = ({ } }; - const onNewPolicy = (selectedSubject: ProjectPermissionSub) => { - const rootPolicyValue = form.getValues(`permissions.${selectedSubject}`); - if (rootPolicyValue && isConditionalSubjects(selectedSubject)) { - form.setValue( - `permissions.${selectedSubject}`, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore-error akhilmhdh: this is because of ts collision with both - [...rootPolicyValue, {}], - { shouldDirty: true, shouldTouch: true } - ); - } else { - form.setValue( - `permissions.${selectedSubject}`, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore-error akhilmhdh: this is because of ts collision with both - [{}], - { - shouldDirty: true, - shouldTouch: true - } - ); - } - }; - const privilegeTemporaryAccess = form.watch("temporaryAccess"); const isTemporary = privilegeTemporaryAccess?.isTemporary; const isExpired = @@ -246,52 +220,25 @@ export const MembershipProjectAdditionalPrivilegeModifySection = ({ - - - - - - {Object.keys(PROJECT_PERMISSION_OBJECT) - .filter( - (subject) => - ProjectTypePermissionSubjects[currentWorkspace.type][ - subject as ProjectPermissionSub - ] - ) - .sort((a, b) => - PROJECT_PERMISSION_OBJECT[a as keyof typeof PROJECT_PERMISSION_OBJECT].title - .toLowerCase() - .localeCompare( - PROJECT_PERMISSION_OBJECT[ - b as keyof typeof PROJECT_PERMISSION_OBJECT - ].title.toLowerCase() - ) - ) - .map((subject) => ( - onNewPolicy(subject as ProjectPermissionSub)} - > - {PROJECT_PERMISSION_OBJECT[subject as ProjectPermissionSub].title} - - ))} - - + @@ -430,6 +377,10 @@ export const MembershipProjectAdditionalPrivilegeModifySection = ({ ))} + handlePopUpToggle("addPolicy", isOpen)} + /> ); diff --git a/frontend/src/pages/project/RoleDetailsBySlugPage/components/NewPermissionRule.tsx b/frontend/src/pages/project/RoleDetailsBySlugPage/components/NewPermissionRule.tsx deleted file mode 100644 index cb3ac2f85..000000000 --- a/frontend/src/pages/project/RoleDetailsBySlugPage/components/NewPermissionRule.tsx +++ /dev/null @@ -1,136 +0,0 @@ -import { Controller, useForm, useFormContext } from "react-hook-form"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { z } from "zod"; - -import { - Button, - Checkbox, - FormControl, - FormLabel, - ModalClose, - Select, - SelectItem -} from "@app/components/v2"; -import { ProjectPermissionSub } from "@app/context"; -import { useGetProjectTypeFromRoute } from "@app/hooks"; -import { ProjectType } from "@app/hooks/api/workspace/types"; - -import { - isConditionalSubjects, - PROJECT_PERMISSION_OBJECT, - projectRoleFormSchema, - ProjectTypePermissionSubjects, - TFormSchema -} from "./ProjectRoleModifySection.utils"; - -type Props = { - onClose: () => void; -}; - -export const NewPermissionRule = ({ onClose }: Props) => { - const rootForm = useFormContext(); - - const form = useForm<{ - type: ProjectPermissionSub; - permissions: NonNullable; - }>({ - resolver: zodResolver( - projectRoleFormSchema - .pick({ permissions: true }) - .extend({ type: z.nativeEnum(ProjectPermissionSub) }) - ), - defaultValues: { - type: ProjectPermissionSub.Project - } - }); - - const selectedSubject = form.watch("type"); - - const projectType = useGetProjectTypeFromRoute(); - - return ( -
- ( - - - - )} - /> - -
- {PROJECT_PERMISSION_OBJECT?.[selectedSubject]?.actions?.map(({ label, value }) => ( - ( -
- - {label} - -
- )} - /> - ))} -
-
- - - - -
-
- ); -}; diff --git a/frontend/src/pages/project/RoleDetailsBySlugPage/components/PolicySelectionModal.tsx b/frontend/src/pages/project/RoleDetailsBySlugPage/components/PolicySelectionModal.tsx new file mode 100644 index 000000000..e636bdfe4 --- /dev/null +++ b/frontend/src/pages/project/RoleDetailsBySlugPage/components/PolicySelectionModal.tsx @@ -0,0 +1,214 @@ +import { useState } from "react"; +import { Controller, useForm, useFormContext } from "react-hook-form"; +import { faCheck, faSearch, faXmark, faXmarkCircle } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; + +import { + Button, + EmptyState, + IconButton, + Input, + Modal, + ModalClose, + ModalContent, + Table, + TableContainer, + TBody, + Td, + Tooltip, + Tr +} from "@app/components/v2"; +import { ProjectPermissionSub } from "@app/context"; +import { useGetProjectTypeFromRoute } from "@app/hooks"; +import { ProjectType } from "@app/hooks/api/workspace/types"; + +import { + isConditionalSubjects, + PROJECT_PERMISSION_OBJECT, + ProjectTypePermissionSubjects, + TFormSchema +} from "./ProjectRoleModifySection.utils"; + +type Props = { + isOpen: boolean; + onOpenChange: (isOpen: boolean) => void; +}; + +type ContentProps = { + onClose: () => void; +}; + +type TForm = { permissions: Record }; + +const Content = ({ onClose }: ContentProps) => { + const rootForm = useFormContext(); + const [search, setSearch] = useState(""); + const { + control, + handleSubmit, + formState: { isDirty }, + setValue, + reset + } = useForm({ + defaultValues: { + permissions: Object.fromEntries( + Object.values(ProjectPermissionSub).map((subject) => [subject, false]) + ) + } + }); + + const projectType = useGetProjectTypeFromRoute(); + + const filteredPolicies = Object.entries(PROJECT_PERMISSION_OBJECT) + .filter( + ([subject, { title }]) => + ProjectTypePermissionSubjects[projectType ?? ProjectType.SecretManager][ + subject as ProjectPermissionSub + ] && (search ? title.toLowerCase().includes(search.toLowerCase()) : true) + ) + .sort((a, b) => a[1].title.localeCompare(b[1].title)) + .map(([subject]) => subject); + + const onSubmit = () => + handleSubmit((form) => { + Object.entries(form.permissions).forEach(([subject, add]) => { + if (!add) return; + + const type = subject as ProjectPermissionSub; + + const rootPolicyValue = rootForm.getValues("permissions")?.[type]; + + if (rootPolicyValue && isConditionalSubjects(subject as ProjectPermissionSub)) { + rootForm.setValue( + `permissions.${type}`, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore-error akhilmhdh: this is because of ts collision with both + [...rootPolicyValue, {}], + { shouldDirty: true, shouldTouch: true } + ); + } else if (!rootPolicyValue?.length) { + rootForm.setValue( + `permissions.${type}`, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore-error akhilmhdh: this is because of ts collision with both + [{}], + { + shouldDirty: true, + shouldTouch: true + } + ); + } + }); + onClose(); + })(); + + return ( + <> + setSearch(e.target.value)} + leftIcon={} + rightIcon={ + search ? ( + setSearch("")}> + + + ) : null + } + /> + +
+ Resource +
+ + + reset()} + variant="plain" + size="xs" + className={`text-mineshaft-400 ${!isDirty ? "pointer-events-none opacity-50" : ""} hover:text-red`} + isDisabled={!isDirty} + > + + + +
+
+ + + {filteredPolicies.map((subject) => ( + ( + onChange(!value)} + > + + + + )} + name={`permissions.${subject as ProjectPermissionSub}`} + /> + ))} + +
+ {PROJECT_PERMISSION_OBJECT[subject as ProjectPermissionSub].title} + + {value ? : null} +
+ {!filteredPolicies.length && ( + + )} +
+
+ + + + +
+ + ); +}; + +export const PolicySelectionModal = ({ isOpen, onOpenChange }: Props) => { + return ( + + + onOpenChange(false)} /> + + + ); +}; diff --git a/frontend/src/pages/project/RoleDetailsBySlugPage/components/ProjectRoleModifySection.utils.tsx b/frontend/src/pages/project/RoleDetailsBySlugPage/components/ProjectRoleModifySection.utils.tsx index a43674d5d..bd5cdaa4e 100644 --- a/frontend/src/pages/project/RoleDetailsBySlugPage/components/ProjectRoleModifySection.utils.tsx +++ b/frontend/src/pages/project/RoleDetailsBySlugPage/components/ProjectRoleModifySection.utils.tsx @@ -913,7 +913,7 @@ export const PROJECT_PERMISSION_OBJECT: TProjectPermissionObject = { actions: [{ label: "Modify", value: "edit" }] }, [ProjectPermissionSub.Integrations]: { - title: "Integrations", + title: "Native Integrations", actions: [ { label: "Read", value: "read" }, { label: "Create", value: "create" }, diff --git a/frontend/src/pages/project/RoleDetailsBySlugPage/components/RolePermissionsSection.tsx b/frontend/src/pages/project/RoleDetailsBySlugPage/components/RolePermissionsSection.tsx index 0331b87c3..8dc9a2fa1 100644 --- a/frontend/src/pages/project/RoleDetailsBySlugPage/components/RolePermissionsSection.tsx +++ b/frontend/src/pages/project/RoleDetailsBySlugPage/components/RolePermissionsSection.tsx @@ -8,19 +8,15 @@ import { twMerge } from "tailwind-merge"; import { createNotification } from "@app/components/notifications"; import { AccessTree } from "@app/components/permissions"; -import { - Button, - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger -} from "@app/components/v2"; +import { Button } from "@app/components/v2"; import { ProjectPermissionSub, useWorkspace } from "@app/context"; import { ProjectPermissionSet } from "@app/context/ProjectPermissionContext"; import { evaluatePermissionsAbility } from "@app/helpers/permissions"; +import { usePopUp } from "@app/hooks"; import { useGetProjectRoleBySlug, useUpdateProjectRole } from "@app/hooks/api"; import { ProjectMembershipRole } from "@app/hooks/api/roles/types"; import { ProjectType } from "@app/hooks/api/workspace/types"; +import { PolicySelectionModal } from "@app/pages/project/RoleDetailsBySlugPage/components/PolicySelectionModal"; import { DynamicSecretPermissionConditions } from "./DynamicSecretPermissionConditions"; import { GeneralPermissionConditions } from "./GeneralPermissionConditions"; @@ -90,6 +86,8 @@ export const RolePermissionsSection = ({ roleSlug, isDisabled }: Props) => { const { mutateAsync: updateRole } = useUpdateProjectRole(); + const { popUp, handlePopUpToggle } = usePopUp(["addPolicy"] as const); + const onSubmit = async (el: TFormSchema) => { try { if (!projectId || !role?.id) return; @@ -110,30 +108,6 @@ export const RolePermissionsSection = ({ roleSlug, isDisabled }: Props) => { (role?.slug ?? "") as ProjectMembershipRole ); - const onNewPolicy = (selectedSubject: ProjectPermissionSub) => { - const rootPolicyValue = form.getValues(`permissions.${selectedSubject}`); - if (rootPolicyValue && isConditionalSubjects(selectedSubject)) { - form.setValue( - `permissions.${selectedSubject}`, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore-error akhilmhdh: this is because of ts collision with both - [...rootPolicyValue, {}], - { shouldDirty: true, shouldTouch: true } - ); - } else { - form.setValue( - `permissions.${selectedSubject}`, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore-error akhilmhdh: this is because of ts collision with both - [{}], - { - shouldDirty: true, - shouldTouch: true - } - ); - } - }; - const permissions = form.watch("permissions"); const formattedPermissions = useMemo( @@ -176,54 +150,25 @@ export const RolePermissionsSection = ({ roleSlug, isDisabled }: Props) => { - - - - - - {Object.keys(PROJECT_PERMISSION_OBJECT) - .filter( - (subject) => - ProjectTypePermissionSubjects[currentWorkspace.type][ - subject as ProjectPermissionSub - ] - ) - .sort((a, b) => - PROJECT_PERMISSION_OBJECT[ - a as keyof typeof PROJECT_PERMISSION_OBJECT - ].title - .toLowerCase() - .localeCompare( - PROJECT_PERMISSION_OBJECT[ - b as keyof typeof PROJECT_PERMISSION_OBJECT - ].title.toLowerCase() - ) - ) - .map((subject) => ( - onNewPolicy(subject as ProjectPermissionSub)} - > - {PROJECT_PERMISSION_OBJECT[subject as ProjectPermissionSub].title} - - ))} - - + )} @@ -245,6 +190,10 @@ export const RolePermissionsSection = ({ roleSlug, isDisabled }: Props) => { ))} + handlePopUpToggle("addPolicy", isOpen)} + /> diff --git a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/components/AccessPolicyModal.tsx b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/components/AccessPolicyModal.tsx index 269d77543..a9304e7ed 100644 --- a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/components/AccessPolicyModal.tsx +++ b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/components/AccessPolicyModal.tsx @@ -251,7 +251,7 @@ export const AccessPolicyForm = ({ label="Policy Type" isRequired isError={Boolean(error)} - tooltipText="Change polices govern secret changes within a given environment and secret path. Access polices allow underprivileged user to request access to environment/secret path." + tooltipText="Change policies govern secret changes within a given environment and secret path. Access policies allow underprivileged user to request access to environment/secret path." errorText={error?.message} > )}