import { useEffect } from "react"; import { Controller, useForm } from "react-hook-form"; import { subject } from "@casl/ability"; import { faCheck, faClose, faCopy } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { zodResolver } from "@hookform/resolvers/zod"; import { AnimatePresence, motion } from "framer-motion"; import { twMerge } from "tailwind-merge"; import { z } from "zod"; import { createNotification } from "@app/components/notifications"; import { IconButton, Input, Spinner, Tooltip } from "@app/components/v2"; import { ProjectPermissionActions, ProjectPermissionSub, useProjectPermission, useWorkspace } from "@app/context"; import { useToggle } from "@app/hooks"; import { useGetUserWsKey, useUpdateSecretV3 } from "@app/hooks/api"; import { DecryptedSecret, SecretType } 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; }; export const formSchema = z.object({ key: z.string().trim().min(1, { message: "Secret key is required" }) }); type TFormSchema = z.infer; 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 [isSecNameCopied, setIsSecNameCopied] = useToggle(false); const { mutateAsync: updateSecretV3 } = useUpdateSecretV3(); const { handleSubmit, control, reset, trigger, getValues, formState: { isDirty, isSubmitting, errors } } = useForm({ defaultValues: { key: secretKey }, values: { key: secretKey }, resolver: zodResolver(formSchema) }); useEffect(() => { let timer: NodeJS.Timeout; if (isSecNameCopied) { timer = setTimeout(() => setIsSecNameCopied.off(), 2000); } return () => clearTimeout(timer); }, [isSecNameCopied]); const handleFormSubmit = async (data: TFormSchema) => { if (!data.key) { createNotification({ type: "error", text: "Secret name cannot be empty" }); return; } 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: SecretType.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) .then(() => { createNotification({ type: "success", text: "Successfully renamed the secret" }); }) .catch(() => { createNotification({ type: "error", text: "Error renaming the secret" }); }); }; const copyTokenToClipboard = () => { const [key] = getValues(["key"]); navigator.clipboard.writeText(key as string); setIsSecNameCopied.on(); }; return (
Key ( trigger("key")} isError={Boolean(error)} {...field} className="w-full px-2 placeholder:text-red-500 focus:text-bunker-100 focus:ring-transparent" /> )} />
{isReadOnly || isOverriden ? ( Read Only ) : (
{!isDirty ? ( ) : ( {isSubmitting ? ( ) : ( )} reset()} isDisabled={isSubmitting} > )}
)}
); } export default SecretRenameRow;