Merge pull request #1517 from rhythmbhiwani/fix-rename-bug

Stop ability to rename a secret to empty name from frontend
This commit is contained in:
Daniel Hougaard
2024-03-06 05:09:59 +01:00
committed by GitHub
4 changed files with 41 additions and 29 deletions
@@ -375,6 +375,10 @@ export const secretServiceFactory = ({
await projectDAL.checkProjectUpgradeStatus(projectId); await projectDAL.checkProjectUpgradeStatus(projectId);
if (inputSecret.newSecretName === "") {
throw new BadRequestError({ message: "New secret name cannot be empty" });
}
const folder = await folderDAL.findBySecretPath(projectId, environment, path); const folder = await folderDAL.findBySecretPath(projectId, environment, path);
if (!folder) throw new BadRequestError({ message: "Folder not found", name: "Create secret" }); if (!folder) throw new BadRequestError({ message: "Folder not found", name: "Create secret" });
const folderId = folder.id; const folderId = folder.id;
@@ -1,24 +1,4 @@
/* eslint-disable simple-import-sort/imports */ /* eslint-disable simple-import-sort/imports */
import { memo, useEffect } from "react";
import { Controller, useFieldArray, useForm } from "react-hook-form";
import { subject } from "@casl/ability";
import { faCheckCircle } from "@fortawesome/free-regular-svg-icons";
import {
faCheck,
faClock,
faClose,
faCodeBranch,
faComment,
faCopy,
faEllipsis,
faKey,
faTag,
faTags
} 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 { ProjectPermissionCan } from "@app/components/permissions"; import { ProjectPermissionCan } from "@app/components/permissions";
import { import {
Button, Button,
@@ -48,9 +28,29 @@ import {
import { useToggle } from "@app/hooks"; import { useToggle } from "@app/hooks";
import { DecryptedSecret } from "@app/hooks/api/secrets/types"; import { DecryptedSecret } from "@app/hooks/api/secrets/types";
import { WsTag } from "@app/hooks/api/types"; import { WsTag } from "@app/hooks/api/types";
import { subject } from "@casl/ability";
import { faCheckCircle } from "@fortawesome/free-regular-svg-icons";
import {
faCheck,
faClock,
faClose,
faCodeBranch,
faComment,
faCopy,
faEllipsis,
faKey,
faTag,
faTags
} 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 { memo, useEffect } from "react";
import { Controller, useFieldArray, useForm } from "react-hook-form";
import { twMerge } from "tailwind-merge";
import { formSchema, SecretActionType, TFormSchema } from "./SecretListView.utils";
import { CreateReminderForm } from "./CreateReminderForm"; import { CreateReminderForm } from "./CreateReminderForm";
import { formSchema, SecretActionType, TFormSchema } from "./SecretListView.utils";
type Props = { type Props = {
secret: DecryptedSecret; secret: DecryptedSecret;
@@ -104,7 +104,8 @@ export const SecretItem = memo(
setValue, setValue,
reset, reset,
getValues, getValues,
formState: { isDirty, isSubmitting } trigger,
formState: { isDirty, isSubmitting, errors }
} = useForm<TFormSchema>({ } = useForm<TFormSchema>({
defaultValues: secret, defaultValues: secret,
values: secret, values: secret,
@@ -235,15 +236,18 @@ export const SecretItem = memo(
<Controller <Controller
name="key" name="key"
control={control} control={control}
render={({ field }) => ( render={({ field, fieldState: { error } }) => (
<Input <Input
autoComplete="off" autoComplete="off"
isReadOnly={isReadOnly} isReadOnly={isReadOnly}
autoCapitalization={currentWorkspace?.autoCapitalization} autoCapitalization={currentWorkspace?.autoCapitalization}
variant="plain" variant="plain"
isDisabled={isOverriden} isDisabled={isOverriden}
placeholder={error?.message}
isError={Boolean(error)}
onKeyUp={() => trigger("key")}
{...field} {...field}
className="w-full px-0 focus:text-bunker-100 focus:ring-transparent" className="w-full px-0 placeholder:text-red-500 focus:text-bunker-100 focus:ring-transparent"
/> />
)} )}
/> />
@@ -497,7 +501,7 @@ export const SecretItem = memo(
animate={{ x: 0, opacity: 1 }} animate={{ x: 0, opacity: 1 }}
exit={{ x: -10, opacity: 0 }} exit={{ x: -10, opacity: 0 }}
> >
<Tooltip content="Save"> <Tooltip content={errors.key ? errors.key?.message : "Save"}>
<IconButton <IconButton
ariaLabel="more" ariaLabel="more"
variant="plain" variant="plain"
@@ -507,12 +511,16 @@ export const SecretItem = memo(
"p-0 text-primary opacity-0 group-hover:opacity-100", "p-0 text-primary opacity-0 group-hover:opacity-100",
isDirty && "opacity-100" isDirty && "opacity-100"
)} )}
isDisabled={isSubmitting} isDisabled={isSubmitting || Boolean(errors.key)}
> >
{isSubmitting ? ( {isSubmitting ? (
<Spinner className="m-0 h-4 w-4 p-0" /> <Spinner className="m-0 h-4 w-4 p-0" />
) : ( ) : (
<FontAwesomeIcon icon={faCheck} size="lg" className="text-primary" /> <FontAwesomeIcon
icon={faCheck}
size="lg"
className={twMerge("text-primary", errors.key && "text-mineshaft-300")}
/>
)} )}
</IconButton> </IconButton>
</Tooltip> </Tooltip>
@@ -206,7 +206,7 @@ export const SecretListView = ({
reminderRepeatDays, reminderRepeatDays,
reminderNote reminderNote
} = modSecret; } = modSecret;
const hasKeyChanged = oldKey !== key; const hasKeyChanged = oldKey !== key && key;
const tagIds = tags?.map(({ id }) => id); const tagIds = tags?.map(({ id }) => id);
const oldTagIds = (orgSecret?.tags || []).map(({ id }) => id); const oldTagIds = (orgSecret?.tags || []).map(({ id }) => id);
@@ -8,7 +8,7 @@ export enum SecretActionType {
} }
export const formSchema = z.object({ export const formSchema = z.object({
key: z.string().trim(), key: z.string().trim().min(1, { message: "Secret key is required" }),
value: z.string().transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim())), value: z.string().transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim())),
idOverride: z.string().trim().optional(), idOverride: z.string().trim().optional(),
valueOverride: z valueOverride: z