import { useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { Plus, Trash2, Save, Eye, EyeOff, Key, Loader2 } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import { variablesApi } from '@/lib/api'; interface EnvironmentVariable { id: string; service_id: string; key: string; value: string; is_secret: boolean; created_at: string; updated_at: string; } interface EnvVariablesEditorProps { serviceId: string; } function _EnvVariablesEditor({ serviceId }: EnvVariablesEditorProps) { const [variables, setVariables] = useState<{ key: string; value: string; is_secret: boolean }[]>([]); const [showSecrets, setShowSecrets] = useState>({}); const [hasChanges, setHasChanges] = useState(false); const queryClient = useQueryClient(); const { data: existingVars, isLoading } = useQuery({ queryKey: ['variables', serviceId], queryFn: async () => { const response = await variablesApi.getVariables(serviceId); return response.variables as EnvironmentVariable[]; }, }); useState(() => { if (existingVars) { setVariables( existingVars.map((v) => ({ key: v.key, value: v.is_secret ? '' : v.value, is_secret: v.is_secret, })) ); } }); const updateVariables = useMutation({ mutationFn: async (vars: { key: string; value: string; is_secret: boolean }[]) => { const response = await variablesApi.updateVariables(serviceId, vars); return response; }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['variables', serviceId] }); setHasChanges(false); }, }); const addVariable = () => { setVariables([...variables, { key: '', value: '', is_secret: false }]); setHasChanges(true); }; const removeVariable = (index: number) => { setVariables(variables.filter((_, i) => i !== index)); setHasChanges(true); }; const updateVariable = ( index: number, field: 'key' | 'value' | 'is_secret', newValue: string | boolean ) => { const updated = [...variables]; updated[index] = { ...updated[index], [field]: newValue }; setVariables(updated); setHasChanges(true); }; const handleSave = () => { const validVars = variables.filter((v) => v.key.trim() !== ''); updateVariables.mutate(validVars); }; if (isLoading) { return (
); } return (
Environment Variables
{hasChanges && ( )}
{variables.length === 0 ? (
No environment variables configured. Click "Add Variable" to add one.
) : ( variables.map((variable, index) => (
updateVariable(index, 'key', e.target.value)} className="font-mono" />
updateVariable(index, 'value', e.target.value)} className="font-mono pr-16" /> {variable.is_secret && ( )}
)) )}
{variables.length > 0 && (

Tips:

  • Secret variables are encrypted and hidden in the UI
  • Changes are applied after the next deployment
  • Use uppercase keys with underscores (e.g., DATABASE_URL)
)}
); }