diff --git a/frontend/src/components/v2/FilterableSelect/FilterableSelect.tsx b/frontend/src/components/v2/FilterableSelect/FilterableSelect.tsx index ad51f565d..d60df5b30 100644 --- a/frontend/src/components/v2/FilterableSelect/FilterableSelect.tsx +++ b/frontend/src/components/v2/FilterableSelect/FilterableSelect.tsx @@ -58,6 +58,7 @@ export const FilterableSelect = ({ clearIndicator: () => "p-1 hover:text-red text-bunker-400", indicatorSeparator: () => "bg-bunker-400", dropdownIndicator: () => "text-bunker-200 p-1", + menuList: () => "flex flex-col gap-1", menu: () => "mt-2 p-2 border text-sm text-mineshaft-200 thin-scrollbar bg-mineshaft-900 border-mineshaft-600 rounded-md", groupHeading: () => "ml-3 mt-2 mb-1 text-mineshaft-400 text-sm", @@ -65,7 +66,7 @@ export const FilterableSelect = ({ twMerge( isFocused && "bg-mineshaft-700 active:bg-mineshaft-600", isSelected && "text-mineshaft-200", - "hover:cursor-pointer mb-1 rounded text-xs px-3 py-2" + "hover:cursor-pointer rounded text-xs px-3 py-2" ), noOptionsMessage: () => "text-mineshaft-400 p-2 rounded-md" }} diff --git a/frontend/src/components/v2/Pagination/Pagination.tsx b/frontend/src/components/v2/Pagination/Pagination.tsx index 51eed6396..2d0e8b1a9 100644 --- a/frontend/src/components/v2/Pagination/Pagination.tsx +++ b/frontend/src/components/v2/Pagination/Pagination.tsx @@ -54,7 +54,7 @@ export const Pagination = ({ )} > {startAdornment} -
+
{(page - 1) * perPage + 1} - {Math.min((page - 1) * perPage + perPage, count)} of {count}
diff --git a/frontend/src/pages/org/[id]/overview/index.tsx b/frontend/src/pages/org/[id]/overview/index.tsx index 45fc7f3d2..9e39fd389 100644 --- a/frontend/src/pages/org/[id]/overview/index.tsx +++ b/frontend/src/pages/org/[id]/overview/index.tsx @@ -876,7 +876,7 @@ const OrganizationPage = () => { @@ -118,21 +121,16 @@ export const CreateSecretImportForm = ({ ( + render={({ field: { onChange, value }, fieldState: { error } }) => ( - + option.name} + getOptionValue={(option) => option.slug} + placeholder="Select environment..." + value={value} + onChange={onChange} + /> )} /> @@ -142,7 +140,7 @@ export const CreateSecretImportForm = ({ defaultValue="/" render={({ field, fieldState: { error } }) => ( - + )} /> diff --git a/frontend/src/views/SecretMainPage/components/SecretDropzone/CopySecretsFromBoard.tsx b/frontend/src/views/SecretMainPage/components/SecretDropzone/CopySecretsFromBoard.tsx index fb5355298..ac6efe5cd 100644 --- a/frontend/src/views/SecretMainPage/components/SecretDropzone/CopySecretsFromBoard.tsx +++ b/frontend/src/views/SecretMainPage/components/SecretDropzone/CopySecretsFromBoard.tsx @@ -1,14 +1,7 @@ import { useEffect, useState } from "react"; import { Controller, useForm } from "react-hook-form"; import { subject } from "@casl/ability"; -import { - faClone, - faFileImport, - faKey, - faSearch, - faSquareCheck, - faSquareXmark -} from "@fortawesome/free-solid-svg-icons"; +import { faClone, faFileImport, faSquareCheck } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; @@ -16,17 +9,13 @@ import { z } from "zod"; import { ProjectPermissionCan } from "@app/components/permissions"; import { Button, - Checkbox, - EmptyState, + FilterableSelect, FormControl, IconButton, - Input, Modal, ModalContent, ModalTrigger, - Select, - SelectItem, - Skeleton, + Switch, Tooltip } from "@app/components/v2"; import { SecretPathInput } from "@app/components/v2/SecretPathInput"; @@ -35,14 +24,17 @@ import { useDebounce } from "@app/hooks"; import { useGetProjectSecrets } from "@app/hooks/api"; const formSchema = z.object({ - environment: z.string().trim(), + environment: z.object({ name: z.string(), slug: z.string() }), secretPath: z .string() .trim() .transform((val) => typeof val === "string" && val.at(-1) === "/" && val.length > 1 ? val.slice(0, -1) : val ), - secrets: z.record(z.string().optional().nullable()) + secrets: z + .object({ key: z.string(), value: z.string().optional() }) + .array() + .min(1, "Select one or more secrets to copy") }); type TFormSchema = z.infer; @@ -68,7 +60,6 @@ export const CopySecretsFromBoard = ({ onToggle, onParsedEnv }: Props) => { - const [searchFilter, setSearchFilter] = useState(""); const [shouldIncludeValues, setShouldIncludeValues] = useState(true); const { @@ -80,7 +71,7 @@ export const CopySecretsFromBoard = ({ formState: { isDirty } } = useForm({ resolver: zodResolver(formSchema), - defaultValues: { secretPath: "/", environment: environments?.[0]?.slug } + defaultValues: { secretPath: "/", environment: environments?.[0] } }); const envCopySecPath = watch("secretPath"); @@ -89,7 +80,7 @@ export const CopySecretsFromBoard = ({ const { data: secrets, isLoading: isSecretsLoading } = useGetProjectSecrets({ workspaceId, - environment: selectedEnvSlug, + environment: selectedEnvSlug.slug, secretPath: debouncedEnvCopySecretPath, options: { enabled: @@ -101,29 +92,22 @@ export const CopySecretsFromBoard = ({ }); useEffect(() => { - setValue("secrets", {}); - setSearchFilter(""); - }, [debouncedEnvCopySecretPath]); + setValue("secrets", []); + }, [debouncedEnvCopySecretPath, selectedEnvSlug]); const handleSecSelectAll = () => { if (secrets) { - setValue( - "secrets", - secrets?.reduce((prev, curr) => ({ ...prev, [curr.key]: curr.value }), {}), - { shouldDirty: true } - ); + setValue("secrets", secrets, { shouldDirty: true }); } }; const handleFormSubmit = async (data: TFormSchema) => { const secretsToBePulled: Record = {}; - Object.keys(data.secrets || {}).forEach((key) => { - if (data.secrets[key]) { - secretsToBePulled[key] = { - value: (shouldIncludeValues && data.secrets[key]) || "", - comments: [""] - }; - } + data.secrets.forEach(({ key, value }) => { + secretsToBePulled[key] = { + value: (shouldIncludeValues && value) || "", + comments: [""] + }; }); onParsedEnv(secretsToBePulled); onToggle(false); @@ -136,7 +120,6 @@ export const CopySecretsFromBoard = ({ onOpenChange={(state) => { onToggle(state); reset(); - setSearchFilter(""); }} > @@ -165,6 +148,7 @@ export const CopySecretsFromBoard = ({
( - + onChange={onChange} + options={environments} + placeholder="Select environment..." + getOptionLabel={(option) => option.name} + getOptionValue={(option) => option.slug} + /> )} /> @@ -203,7 +179,7 @@ export const CopySecretsFromBoard = ({ )} @@ -212,72 +188,57 @@ export const CopySecretsFromBoard = ({
Secrets
-
- +
+ ( + + option.key} + getOptionLabel={(option) => option.key} + /> + + )} + /> + + } - onChange={(evt) => setSearchFilter(evt.target.value)} - /> - - - - - - - reset()} - > - - - -
+ onClick={handleSecSelectAll} + > + + +
- {!isSecretsLoading && !secrets?.length && ( - - )} -
- {isSecretsLoading && - Array.apply(0, Array(2)).map((_x, i) => ( - - ))} - - {secrets - ?.filter(({ key }) => key.toLowerCase().includes(searchFilter.toLowerCase())) - ?.map(({ id, key, value: secVal }) => ( - ( - onChange(isChecked ? secVal : "")} - > - {key} - - )} - /> - ))} -
-
- + setShouldIncludeValues(isChecked as boolean)} > Include secret values - +