diff --git a/frontend/src/hooks/api/secrets/mutations.tsx b/frontend/src/hooks/api/secrets/mutations.tsx index 54aa97b435..7bc3849be4 100644 --- a/frontend/src/hooks/api/secrets/mutations.tsx +++ b/frontend/src/hooks/api/secrets/mutations.tsx @@ -31,7 +31,8 @@ export const useCreateSecretV3 = ({ secretKey, secretValue, secretComment, - skipMultilineEncoding + skipMultilineEncoding, + tagIds }) => { const { data } = await apiRequest.post(`/api/v3/secrets/raw/${secretKey}`, { secretPath, @@ -40,7 +41,8 @@ export const useCreateSecretV3 = ({ workspaceId, secretValue, secretComment, - skipMultilineEncoding + skipMultilineEncoding, + tagIds }); return data; }, diff --git a/frontend/src/hooks/api/secrets/types.ts b/frontend/src/hooks/api/secrets/types.ts index 7e26914ab0..f4dfb07d14 100644 --- a/frontend/src/hooks/api/secrets/types.ts +++ b/frontend/src/hooks/api/secrets/types.ts @@ -132,6 +132,7 @@ export type TCreateSecretsV3DTO = { workspaceId: string; environment: string; type: SecretType; + tagIds?: string[]; }; export type TUpdateSecretsV3DTO = { diff --git a/frontend/src/views/SecretMainPage/SecretMainPage.tsx b/frontend/src/views/SecretMainPage/SecretMainPage.tsx index 4e21a8d86b..31427d67ce 100644 --- a/frontend/src/views/SecretMainPage/SecretMainPage.tsx +++ b/frontend/src/views/SecretMainPage/SecretMainPage.tsx @@ -9,7 +9,14 @@ import { twMerge } from "tailwind-merge"; import NavHeader from "@app/components/navigation/NavHeader"; import { createNotification } from "@app/components/notifications"; import { PermissionDeniedBanner } from "@app/components/permissions"; -import { Checkbox, ContentLoader, Pagination, Tooltip } from "@app/components/v2"; +import { + Checkbox, + ContentLoader, + Modal, + ModalContent, + Pagination, + Tooltip +} from "@app/components/v2"; import { ProjectPermissionActions, ProjectPermissionDynamicSecretActions, @@ -41,7 +48,10 @@ import { SecretDropzone } from "./components/SecretDropzone"; import { SecretListView, SecretNoAccessListView } from "./components/SecretListView"; import { SnapshotView } from "./components/SnapshotView"; import { + PopUpNames, StoreProvider, + usePopUpAction, + usePopUpState, useSelectedSecretActions, useSelectedSecrets } from "./SecretMainPage.store"; @@ -123,6 +133,9 @@ const SecretMainPageContent = () => { const [debouncedSearchFilter, setDebouncedSearchFilter] = useDebounce(filter.searchFilter); const [filterHistory, setFilterHistory] = useState>(new Map()); + const createSecretPopUp = usePopUpState(PopUpNames.CreateSecretForm); + const { togglePopUp } = usePopUpAction(); + useEffect(() => { if ( !isWorkspaceLoading && @@ -520,13 +533,23 @@ const SecretMainPageContent = () => { onChangePerPage={(newPerPage) => setPerPage(newPerPage)} /> )} - + togglePopUp(PopUpNames.CreateSecretForm, state)} + > + + + + ; @@ -43,12 +45,16 @@ export const CreateSecretForm = ({ setValue, formState: { errors, isSubmitting } } = useForm({ resolver: zodResolver(typeSchema) }); - const { isOpen } = usePopUpState(PopUpNames.CreateSecretForm); - const { closePopUp, togglePopUp } = usePopUpAction(); + const { closePopUp } = usePopUpAction(); const { mutateAsync: createSecretV3 } = useCreateSecretV3(); + const { permission } = useProjectPermission(); + const canReadTags = permission.can(ProjectPermissionActions.Read, ProjectPermissionSub.Tags); + const { data: projectTags, isLoading: isTagsLoading } = useGetWsTags( + canReadTags ? workspaceId : "" + ); - const handleFormSubmit = async ({ key, value }: TFormSchema) => { + const handleFormSubmit = async ({ key, value, tags }: TFormSchema) => { try { await createSecretV3({ environment, @@ -57,7 +63,8 @@ export const CreateSecretForm = ({ secretKey: key, secretValue: value || "", secretComment: "", - type: SecretType.Shared + type: SecretType.Shared, + tagIds: tags.map((el) => el.value) }); closePopUp(PopUpNames.CreateSecretForm); reset(); @@ -88,67 +95,80 @@ export const CreateSecretForm = ({ }; return ( - togglePopUp(PopUpNames.CreateSecretForm, state)} - > - + -
+ + + ( - - ( - - - - )} - /> -
- - -
- -
-
+ )} + /> + ( + + ({ label: el.slug, value: el.id }))} + value={field.value} + onChange={field.onChange} + /> + + )} + /> +
+ + +
+ ); }; diff --git a/frontend/src/views/SecretOverviewPage/SecretOverviewPage.tsx b/frontend/src/views/SecretOverviewPage/SecretOverviewPage.tsx index 7287a37eda..0571f63c4c 100644 --- a/frontend/src/views/SecretOverviewPage/SecretOverviewPage.tsx +++ b/frontend/src/views/SecretOverviewPage/SecretOverviewPage.tsx @@ -1116,13 +1116,22 @@ export const SecretOverviewPage = () => { )} - handlePopUpToggle("addSecretsInAllEnvs", isOpen)} - onClose={() => handlePopUpClose("addSecretsInAllEnvs")} - /> + onOpenChange={(isOpen) => handlePopUpToggle("addSecretsInAllEnvs", isOpen)} + > + + handlePopUpClose("addSecretsInAllEnvs")} + /> + + handlePopUpToggle("addFolder", isOpen)} diff --git a/frontend/src/views/SecretOverviewPage/components/CreateSecretForm/CreateSecretForm.tsx b/frontend/src/views/SecretOverviewPage/components/CreateSecretForm/CreateSecretForm.tsx index 392c4440da..fa0149456f 100644 --- a/frontend/src/views/SecretOverviewPage/components/CreateSecretForm/CreateSecretForm.tsx +++ b/frontend/src/views/SecretOverviewPage/components/CreateSecretForm/CreateSecretForm.tsx @@ -13,8 +13,7 @@ import { FormControl, FormLabel, Input, - Modal, - ModalContent, + MultiSelect, Tooltip } from "@app/components/v2"; import { InfisicalSecretInput } from "@app/components/v2/InfisicalSecretInput"; @@ -25,14 +24,20 @@ import { useWorkspace } from "@app/context"; import { getKeyValue } from "@app/helpers/parseEnvVar"; -import { useCreateFolder, useCreateSecretV3, useUpdateSecretV3 } from "@app/hooks/api"; +import { + useCreateFolder, + useCreateSecretV3, + useGetWsTags, + useUpdateSecretV3 +} from "@app/hooks/api"; import { SecretType, SecretV3RawSanitized } from "@app/hooks/api/types"; const typeSchema = z .object({ key: z.string().trim().min(1, "Key is required"), value: z.string().optional(), - environments: z.record(z.boolean().optional()) + environments: z.record(z.boolean().optional()), + tags: z.array(z.object({ label: z.string().trim(), value: z.string().trim() })).min(1) }) .refine((data) => data.key !== undefined, { message: "Please enter secret name" @@ -44,18 +49,10 @@ type Props = { secretPath?: string; getSecretByKey: (slug: string, key: string) => SecretV3RawSanitized | undefined; // modal props - isOpen?: boolean; onClose: () => void; - onTogglePopUp: (isOpen: boolean) => void; }; -export const CreateSecretForm = ({ - secretPath = "/", - isOpen, - getSecretByKey, - onClose, - onTogglePopUp -}: Props) => { +export const CreateSecretForm = ({ secretPath = "/", getSecretByKey, onClose }: Props) => { const { register, handleSubmit, @@ -69,14 +66,18 @@ export const CreateSecretForm = ({ const { currentWorkspace } = useWorkspace(); const { permission } = useProjectPermission(); + const canReadTags = permission.can(ProjectPermissionActions.Read, ProjectPermissionSub.Tags); const workspaceId = currentWorkspace?.id || ""; const environments = currentWorkspace?.environments || []; const { mutateAsync: createSecretV3 } = useCreateSecretV3(); const { mutateAsync: updateSecretV3 } = useUpdateSecretV3(); const { mutateAsync: createFolder } = useCreateFolder(); + const { data: projectTags, isLoading: isTagsLoading } = useGetWsTags( + canReadTags ? workspaceId : "" + ); - const handleFormSubmit = async ({ key, value, environments: selectedEnv }: TFormSchema) => { + const handleFormSubmit = async ({ key, value, environments: selectedEnv, tags }: TFormSchema) => { const environmentsSelected = environments.filter(({ slug }) => selectedEnv[slug]); const isEnvironmentsSelected = environmentsSelected.length; @@ -120,7 +121,8 @@ export const CreateSecretForm = ({ secretPath, secretKey: key, secretValue: value || "", - type: SecretType.Shared + type: SecretType.Shared, + tagIds: tags.map((el) => el.value) })), environment }; @@ -134,7 +136,8 @@ export const CreateSecretForm = ({ secretKey: key, secretValue: value || "", secretComment: "", - type: SecretType.Shared + type: SecretType.Shared, + tagIds: tags.map((el) => el.value) })), environment }; @@ -197,114 +200,126 @@ export const CreateSecretForm = ({ }; return ( - - + -
+ + + ( - - ( - - - - )} - /> - -
- {environments - .filter((environmentSlug) => - permission.can( - ProjectPermissionActions.Create, - subject(ProjectPermissionSub.Secrets, { - environment: environmentSlug.slug, - secretPath, - secretName: "*", - secretTags: ["*"] - }) - ) - ) - .map((env) => { - return ( - ( - - - - {env.name} - - - {getSecretByKey(env.slug, newSecretKey) && ( - - - - )} - - - - )} - /> - ); - })} -
-
- - -
- -
-
+ )} + /> + ( + + ({ label: el.slug, value: el.id }))} + value={field.value} + onChange={field.onChange} + /> + + )} + /> + +
+ {environments + .filter((environmentSlug) => + permission.can( + ProjectPermissionActions.Create, + subject(ProjectPermissionSub.Secrets, { + environment: environmentSlug.slug, + secretPath, + secretName: "*", + secretTags: ["*"] + }) + ) + ) + .map((env) => { + return ( + ( + + + + {env.name} + + + {getSecretByKey(env.slug, newSecretKey) && ( + + + + )} + + + + )} + /> + ); + })} +
+
+ + +
+ ); };