Skip to content

Commit

Permalink
Merge pull request #2859 from Infisical/daniel/copy-paste
Browse files Browse the repository at this point in the history
fix(dashboard): pasting secrets into create secret modal
  • Loading branch information
DanielHougaard authored Dec 11, 2024
2 parents ba5e6fe + 4568370 commit a8ad870
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 14 deletions.
25 changes: 21 additions & 4 deletions frontend/src/helpers/parseEnvVar.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,31 @@
/** Extracts the key and value from a passed in env string based on the provided delimiters. */
export const getKeyValue = (pastedContent: string, delimiters: string[]) => {
const foundDelimiter = delimiters.find((delimiter) => pastedContent.includes(delimiter));
if (!pastedContent) {
return { key: "", value: "" };
}

let firstDelimiterIndex = -1;
let foundDelimiter = "";

delimiters.forEach((delimiter) => {
const index = pastedContent.indexOf(delimiter);
if (index !== -1 && (firstDelimiterIndex === -1 || index < firstDelimiterIndex)) {
firstDelimiterIndex = index;
foundDelimiter = delimiter;
}
});

if (!foundDelimiter) {
const hasValueAfterDelimiter = pastedContent.length > firstDelimiterIndex + foundDelimiter.length;

if (firstDelimiterIndex === -1 || !hasValueAfterDelimiter) {
return { key: pastedContent.trim(), value: "" };
}

const [key, value] = pastedContent.split(foundDelimiter);
const key = pastedContent.substring(0, firstDelimiterIndex);
const value = pastedContent.substring(firstDelimiterIndex + foundDelimiter.length);

return {
key: key.trim(),
value: (value ?? "").trim()
value: value.trim()
};
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ClipboardEvent } from "react";
import { ClipboardEvent, useRef } from "react";
import { Controller, useForm } from "react-hook-form";
import { faTriangleExclamation } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
Expand Down Expand Up @@ -46,6 +46,7 @@ export const CreateSecretForm = ({
control,
reset,
setValue,
watch,
formState: { errors, isSubmitting }
} = useForm<TFormSchema>({ resolver: zodResolver(typeSchema) });
const { closePopUp } = usePopUpAction();
Expand All @@ -59,6 +60,11 @@ export const CreateSecretForm = ({
canReadTags ? workspaceId : ""
);

const secretKeyInputRef = useRef<HTMLInputElement>(null);
const { ref: setSecretKeyHookRef, ...secretKeyRegisterRest } = register("key");

const secretKey = watch("key");

const slugSchema = z.string().trim().toLowerCase().min(1);
const createNewTag = async (slug: string) => {
// TODO: Replace with slugSchema generic
Expand Down Expand Up @@ -108,13 +114,23 @@ export const CreateSecretForm = ({
};

const handlePaste = (e: ClipboardEvent<HTMLInputElement>) => {
e.preventDefault();
const delimitters = [":", "="];
const pastedContent = e.clipboardData.getData("text");
const { key, value } = getKeyValue(pastedContent, delimitters);

setValue("key", key);
setValue("value", value);
const isWholeKeyHighlighted =
secretKeyInputRef.current &&
secretKeyInputRef.current.selectionStart === 0 &&
secretKeyInputRef.current.selectionEnd === secretKeyInputRef.current.value.length;

if (!secretKey || isWholeKeyHighlighted) {
e.preventDefault();

setValue("key", key);
if (value) {
setValue("value", value);
}
}
};

return (
Expand All @@ -126,7 +142,12 @@ export const CreateSecretForm = ({
errorText={errors?.key?.message}
>
<Input
{...register("key")}
{...secretKeyRegisterRest}
ref={(e) => {
setSecretKeyHookRef(e);
// @ts-expect-error this is for multiple ref single component
secretKeyInputRef.current = e;
}}
placeholder="Type your secret name"
onPaste={handlePaste}
autoCapitalization={autoCapitalize}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ClipboardEvent } from "react";
import { ClipboardEvent, useRef } from "react";
import { Controller, useForm } from "react-hook-form";
import { subject } from "@casl/ability";
import { faTriangleExclamation } from "@fortawesome/free-solid-svg-icons";
Expand Down Expand Up @@ -46,6 +46,7 @@ export const CreateSecretForm = ({ secretPath = "/", onClose }: Props) => {
control,
reset,
setValue,
watch,
formState: { isSubmitting, errors }
} = useForm<TFormSchema>({ resolver: zodResolver(typeSchema) });

Expand All @@ -61,6 +62,11 @@ export const CreateSecretForm = ({ secretPath = "/", onClose }: Props) => {
canReadTags ? workspaceId : ""
);

const secretKeyInputRef = useRef<HTMLInputElement>(null);
const { ref: setSecretKeyHookRef, ...secretKeyRegisterRest } = register("key");

const secretKey = watch("key");

const handleFormSubmit = async ({ key, value, environments: selectedEnv, tags }: TFormSchema) => {
const promises = selectedEnv.map(async (env) => {
const environment = env.slug;
Expand Down Expand Up @@ -152,13 +158,23 @@ export const CreateSecretForm = ({ secretPath = "/", onClose }: Props) => {
};

const handlePaste = (e: ClipboardEvent<HTMLInputElement>) => {
e.preventDefault();
const delimitters = [":", "="];
const pastedContent = e.clipboardData.getData("text");
const { key, value } = getKeyValue(pastedContent, delimitters);

setValue("key", key);
setValue("value", value);
const isWholeKeyHighlighted =
secretKeyInputRef.current &&
secretKeyInputRef.current.selectionStart === 0 &&
secretKeyInputRef.current.selectionEnd === secretKeyInputRef.current.value.length;

if (!secretKey || isWholeKeyHighlighted) {
e.preventDefault();

setValue("key", key);
if (value) {
setValue("value", value);
}
}
};

const createWsTag = useCreateWsTag();
Expand Down Expand Up @@ -189,7 +205,12 @@ export const CreateSecretForm = ({ secretPath = "/", onClose }: Props) => {
errorText={errors?.key?.message}
>
<Input
{...register("key")}
{...secretKeyRegisterRest}
ref={(e) => {
setSecretKeyHookRef(e);
// @ts-expect-error this is for multiple ref single component
secretKeyInputRef.current = e;
}}
placeholder="Type your secret name"
onPaste={handlePaste}
autoCapitalization={currentWorkspace?.autoCapitalization}
Expand Down

0 comments on commit a8ad870

Please sign in to comment.