From 323c412f5ea6a976d6073f87ab48639b5ed9c025 Mon Sep 17 00:00:00 2001 From: Rhythm Bhiwani Date: Sat, 2 Mar 2024 06:41:32 +0530 Subject: [PATCH] Added Option to Rename Secrets from overview page in all environments --- .../SecretOverviewTableRow.tsx | 8 + .../SecretRenameRow.tsx | 178 ++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 frontend/src/views/SecretOverviewPage/components/SecretOverviewTableRow/SecretRenameRow.tsx diff --git a/frontend/src/views/SecretOverviewPage/components/SecretOverviewTableRow/SecretOverviewTableRow.tsx b/frontend/src/views/SecretOverviewPage/components/SecretOverviewTableRow/SecretOverviewTableRow.tsx index 08774535b..719b17d44 100644 --- a/frontend/src/views/SecretOverviewPage/components/SecretOverviewTableRow/SecretOverviewTableRow.tsx +++ b/frontend/src/views/SecretOverviewPage/components/SecretOverviewTableRow/SecretOverviewTableRow.tsx @@ -15,6 +15,7 @@ import { useToggle } from "@app/hooks"; import { DecryptedSecret } from "@app/hooks/api/secrets/types"; import { SecretEditRow } from "./SecretEditRow"; +import SecretRenameRow from "./SecretRenameRow"; type Props = { secretKey: string; @@ -105,6 +106,13 @@ export const SecretOverviewTableRow = ({ width: `calc(${expandableColWidth}px - 1rem)` }} > + + diff --git a/frontend/src/views/SecretOverviewPage/components/SecretOverviewTableRow/SecretRenameRow.tsx b/frontend/src/views/SecretOverviewPage/components/SecretOverviewTableRow/SecretRenameRow.tsx new file mode 100644 index 000000000..57c71527c --- /dev/null +++ b/frontend/src/views/SecretOverviewPage/components/SecretOverviewTableRow/SecretRenameRow.tsx @@ -0,0 +1,178 @@ +import { Controller, useForm } from "react-hook-form"; +import { subject } from "@casl/ability"; +import { faCheck, faClose } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { AnimatePresence, motion } from "framer-motion"; +import { twMerge } from "tailwind-merge"; + +import { IconButton, Input, Spinner, Tooltip } from "@app/components/v2"; +import { + ProjectPermissionActions, + ProjectPermissionSub, + useProjectPermission, + useWorkspace +} from "@app/context"; +import { useGetUserWsKey, useUpdateSecretV3 } from "@app/hooks/api"; +import { DecryptedSecret } from "@app/hooks/api/types"; +import { SecretActionType } from "@app/views/SecretMainPage/components/SecretListView/SecretListView.utils"; + +type Props = { + secretKey: string; + secretPath: string; + environments: { name: string; slug: string }[]; + getSecretByKey: (slug: string, key: string) => DecryptedSecret | undefined; +}; + +type Form = { key: string }; + +function SecretRenameRow({ environments, getSecretByKey, secretKey, secretPath }: Props) { + const { currentWorkspace } = useWorkspace(); + const { permission } = useProjectPermission(); + + const secrets = environments.map((env) => getSecretByKey(env.slug, secretKey)); + + const isReadOnly = environments.some((env) => { + const environment = env.slug; + const isSecretInEnvReadOnly = + permission.can( + ProjectPermissionActions.Read, + subject(ProjectPermissionSub.Secrets, { environment, secretPath }) + ) && + permission.cannot( + ProjectPermissionActions.Edit, + subject(ProjectPermissionSub.Secrets, { environment, secretPath }) + ); + if (isSecretInEnvReadOnly) { + return true; + } + return false; + }); + + const isOverriden = secrets.some( + (secret) => + secret?.overrideAction === SecretActionType.Created || + secret?.overrideAction === SecretActionType.Modified + ); + const workspaceId = currentWorkspace?.id || ""; + + const { data: decryptFileKey } = useGetUserWsKey(workspaceId); + + const { mutateAsync: updateSecretV3 } = useUpdateSecretV3(); + + const { + handleSubmit, + control, + reset, + formState: { isDirty, isSubmitting } + } = useForm({ + defaultValues: { key: secretKey }, + values: { key: secretKey } + }); + + const handleFormSubmit = async (data: Form) => { + const promises = secrets + .filter((secret) => !!secret) + .map((secret) => { + if (!secret) return null; + + return updateSecretV3({ + environment: secret?.env, + workspaceId, + secretPath, + secretName: secret.key, + secretId: secret.id, + secretValue: secret.value || "", + type: "shared", + latestFileKey: decryptFileKey!, + tags: secret.tags.map((tag) => tag.id), + secretComment: secret.comment, + secretReminderRepeatDays: secret.reminderRepeatDays, + secretReminderNote: secret.reminderNote, + skipMultilineEncoding: secret.skipMultilineEncoding, + newSecretName: data.key + }); + }); + + await Promise.all(promises); + }; + + return ( + +
+ + Key + + + ( + + )} + /> +
+ {(isReadOnly || isOverriden) && ( + Read Only + )} + + {isDirty && ( + + + + {isSubmitting ? ( + + ) : ( + + )} + + + + reset()} + isDisabled={isSubmitting} + > + + + + + )} + + + ); +} + +export default SecretRenameRow;