diff --git a/app/w/components/sidebar/components/settings-modal/settings-modal.tsx b/app/w/components/sidebar/components/settings-modal/settings-modal.tsx index 65594ae92..8568e760c 100644 --- a/app/w/components/sidebar/components/settings-modal/settings-modal.tsx +++ b/app/w/components/sidebar/components/settings-modal/settings-modal.tsx @@ -9,77 +9,171 @@ import { import { Input } from '@/components/ui/input' import { Button } from '@/components/ui/button' import { Label } from '@/components/ui/label' -import { useState } from 'react' +import { useState, useRef, useEffect } from 'react' -export function SettingsModal({ - open, - onOpenChange, -}: { +interface EnvVar { + key: string + value: string +} + +interface SettingsModalProps { open: boolean onOpenChange: (open: boolean) => void -}) { - const [envVars, setEnvVars] = useState<{ key: string; value: string }[]>([ - { key: '', value: '' }, - ]) +} - const addEnvVar = () => { - setEnvVars([...envVars, { key: '', value: '' }]) +const GRID_COLS = 'grid grid-cols-[minmax(0,1fr),minmax(0,1fr),40px] gap-4' +const INITIAL_ENV_VAR: EnvVar = { key: '', value: '' } + +export function SettingsModal({ open, onOpenChange }: SettingsModalProps) { + const [envVars, setEnvVars] = useState([INITIAL_ENV_VAR]) + const [focusedValueIndex, setFocusedValueIndex] = useState(null) + const inputRefs = useRef<(HTMLInputElement | null)[]>([]) + + useEffect(() => { + inputRefs.current = inputRefs.current.slice(0, envVars.length) + }, [envVars.length]) + + const setInputRef = (el: HTMLInputElement | null, index: number) => { + inputRefs.current[index] = el } - const updateEnvVar = ( - index: number, - field: 'key' | 'value', - value: string - ) => { + const handleValueFocus = (index: number) => { + setFocusedValueIndex(index) + setTimeout(() => { + const input = inputRefs.current[index] + if (input) { + input.setSelectionRange(0, 0) + input.scrollLeft = 0 + } + }, 0) + } + + const handleValueClick = (e: React.MouseEvent, index: number) => { + e.preventDefault() + const input = inputRefs.current[index] + if (input) { + input.setSelectionRange(0, 0) + input.scrollLeft = 0 + } + } + + const handleValueKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') { + e.preventDefault() + } + } + + const handlePaste = (e: React.ClipboardEvent, index: number) => { + const text = e.clipboardData.getData('text') + const lines = text.split('\n').filter(line => line.trim()) + + if (lines.length === 0) return + e.preventDefault() + + if (lines.length === 1) { + // Single line paste + const [key, ...valueParts] = lines[0].split('=') + const value = valueParts.join('=').trim() + if (key && value) { + const newEnvVars = [...envVars] + newEnvVars[index] = { key: key.trim(), value } + setEnvVars(newEnvVars) + } + } else { + // Multi-line paste + const parsedVars = lines + .map(line => { + const [key, ...valueParts] = line.split('=') + return { + key: key.trim(), + value: valueParts.join('=').trim() + } + }) + .filter(({ key, value }) => key && value) + + if (parsedVars.length > 0) { + setEnvVars(parsedVars) + } + } + } + + const addEnvVar = () => setEnvVars([...envVars, INITIAL_ENV_VAR]) + + const updateEnvVar = (index: number, field: keyof EnvVar, value: string) => { const newEnvVars = [...envVars] newEnvVars[index][field] = value setEnvVars(newEnvVars) } + const removeEnvVar = (index: number) => { + const newEnvVars = envVars.filter((_, i) => i !== index) + setEnvVars(newEnvVars.length ? newEnvVars : [INITIAL_ENV_VAR]) + } + + const renderEnvVarRow = (envVar: EnvVar, index: number) => ( +
+ updateEnvVar(index, 'key', e.target.value)} + onPaste={(e) => handlePaste(e, index)} + placeholder="e.g. API_KEY" + /> + setInputRef(el, index)} + value={envVar.value} + onChange={(e) => updateEnvVar(index, 'value', e.target.value)} + type={focusedValueIndex === index ? "text" : "password"} + onFocus={() => handleValueFocus(index)} + onClick={(e) => handleValueClick(e, index)} + onBlur={() => setFocusedValueIndex(null)} + onKeyDown={handleValueKeyDown} + placeholder="Enter value" + /> + +
+ ) + return ( - + Environment Variables -
- {envVars.map((envVar, index) => ( -
-
- - updateEnvVar(index, 'key', e.target.value)} - placeholder="API_KEY" - /> -
-
- - updateEnvVar(index, 'value', e.target.value)} - type="password" - placeholder="Enter value" - /> -
-
- ))} + +
+
+ + +
+
+ +
+ {envVars.map(renderEnvVarRow)} +
- -
- - + +
+ + +