diff --git a/apps/web/src/components/EnvironmentVariablesEditor.tsx b/apps/web/src/components/EnvironmentVariablesEditor.tsx index 44809a620..6d9938064 100644 --- a/apps/web/src/components/EnvironmentVariablesEditor.tsx +++ b/apps/web/src/components/EnvironmentVariablesEditor.tsx @@ -1,4 +1,4 @@ -import { EyeIcon, EyeOffIcon, PlusIcon, Trash2Icon } from "lucide-react"; +import { CheckIcon, CopyIcon, EyeIcon, EyeOffIcon, PlusIcon, Trash2Icon } from "lucide-react"; import { type CSSProperties, type ReactNode, useEffect, useState } from "react"; import { ENVIRONMENT_VARIABLE_KEY_MAX_LENGTH, @@ -11,6 +11,7 @@ import { Button } from "./ui/button"; import { Input } from "./ui/input"; import { Textarea } from "./ui/textarea"; import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip"; +import { useCopyToClipboard } from "~/hooks/useCopyToClipboard"; import { cn } from "~/lib/utils"; type DraftRow = { @@ -125,6 +126,14 @@ export function EnvironmentVariablesEditor({ const [visibleValueRowIds, setVisibleValueRowIds] = useState>(() => new Set()); const [isSaving, setIsSaving] = useState(false); const [saveError, setSaveError] = useState(null); + const [copiedRowId, setCopiedRowId] = useState(null); + const { copyToClipboard } = useCopyToClipboard({ + timeout: 2000, + onCopy: (rowId) => { + setCopiedRowId(rowId); + setTimeout(() => setCopiedRowId(null), 2000); + }, + }); useEffect(() => { setRows(rowsFromEntries(entries)); @@ -278,31 +287,57 @@ export function EnvironmentVariablesEditor({ > Value - - toggleValueVisibility(row.id)} - > - {isValueVisible ? ( - - ) : ( - - )} - - } - /> - - {isValueVisible ? "Hide value" : "Show value"} - - +
+ + toggleValueVisibility(row.id)} + > + {isValueVisible ? ( + + ) : ( + + )} + + } + /> + + {isValueVisible ? "Hide value" : "Show value"} + + + + copyToClipboard(row.value, row.id)} + > + {copiedRowId === row.id ? ( + + ) : ( + + )} + + } + /> + + {copiedRowId === row.id ? "Copied!" : "Copy value"} + + +