diff --git a/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/TFVarTable.tsx b/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/TFVarTable.tsx index 9e5727fa..0a163fc1 100644 --- a/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/TFVarTable.tsx +++ b/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/TFVarTable.tsx @@ -1,303 +1,186 @@ +'use client' + import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; +import { Switch } from "@/components/ui/switch"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; -import { useSAToastMutation } from '@/hooks/useSAToastMutation'; -import { AnimatePresence, motion } from "framer-motion"; -import { Copy, Edit, Eye, EyeOff, Plus, Trash } from 'lucide-react'; +import { Textarea } from "@/components/ui/textarea"; +import { EnvVar } from "@/types/userTypes"; +import { Copy, Edit, Trash } from 'lucide-react'; import moment from 'moment'; -import React, { useCallback, useState } from 'react'; -import { toast } from 'sonner'; -import EmptyState from "./EmptyTFVarState"; - -type TFVar = { - name: string; - value: string; - updated_at: string; -} +import { useRouter } from 'next/navigation'; +import { useState } from 'react'; type TFVarTableProps = { - initialVariables: string; - onUpdate: (variables: string) => Promise; -} + envVars: EnvVar[]; + onUpdate: (name: string, value: string, isSecret: boolean) => Promise; + onDelete: (name: string) => Promise; + onBulkUpdate: (vars: EnvVar[]) => Promise; +}; -const TFVarTable: React.FC = ({ initialVariables, onUpdate }) => { - const [tfvars, setTfvars] = useState(() => { - try { - return JSON.parse(initialVariables); - } catch (error) { - console.error("Failed to parse initial variables:", error); - return []; - } - }); - const [editingState, setEditingState] = useState<{ - index: number | null; - var: TFVar | null; - }>({ - index: null, - var: null, - }); - const [showSecrets, setShowSecrets] = useState<{ [key: string]: boolean }>({}); +export default function TFVarTable({ envVars, onUpdate, onDelete, onBulkUpdate }: TFVarTableProps) { + const [editingVar, setEditingVar] = useState(null); + const [newVar, setNewVar] = useState>({ name: '', value: '', is_secret: false }); const [bulkEditMode, setBulkEditMode] = useState(false); - const [bulkEditValue, setBulkEditValue] = useState(initialVariables); + const [bulkEditValue, setBulkEditValue] = useState(''); + const [isLoading, setIsLoading] = useState(false); + const router = useRouter(); - const { mutate: updateTFVar } = useSAToastMutation( - async (updatedVars) => { - const jsonString = JSON.stringify(updatedVars); - await onUpdate(jsonString); - return { status: 'success', data: jsonString }; - }, - { - loadingMessage: 'Updating TF variables...', - successMessage: 'Variables updated successfully', - errorMessage: 'Failed to update TF variables', - onSuccess: (response) => { - const updatedVars = JSON.parse(response.data) as TFVar[]; - setTfvars(updatedVars); - }, + const handleEdit = (envVar: EnvVar) => { + if (!envVar.is_secret) { + setEditingVar(envVar); } - ); - - const handleEdit = (index: number) => { - setEditingState({ - index, - var: { ...tfvars[index] }, - }); }; - const handleSave = () => { - if (editingState.index === null || editingState.var === null) return; - - const updatedVar = { - ...editingState.var, - updated_at: new Date().toISOString(), - }; - - const isDuplicate = tfvars.some((v, i) => - i !== editingState.index && v.name === updatedVar.name - ); - - if (isDuplicate) { - toast.error('Variable with this name already exists'); - return; + const handleSave = async () => { + if (editingVar) { + setIsLoading(true); + await onUpdate(editingVar.name, editingVar.value, editingVar.is_secret); + setIsLoading(false); + setEditingVar(null); + router.refresh(); } - - const newTFVars = [...tfvars]; - newTFVars[editingState.index] = updatedVar; - updateTFVar(newTFVars); - setEditingState({ index: null, var: null }); }; - const handleDelete = (index: number) => { - const updatedTFVars = tfvars.filter((_, i) => i !== index); - updateTFVar(updatedTFVars); - toast.success(`Variable ${tfvars[index].name} deleted`); + const handleAddNew = async () => { + if (newVar.name && newVar.value) { + setIsLoading(true); + await onUpdate(newVar.name, newVar.value, newVar.is_secret); + setIsLoading(false); + setNewVar({ name: '', value: '', is_secret: false }); + router.refresh(); + } }; - const handleAddVariable = () => { - const now = new Date().toISOString(); - const newVar: TFVar = { - name: `NEW_VARIABLE_${tfvars.length + 1}`, - value: 'ENV_VALUE', - updated_at: now, - }; - const newIndex = tfvars.length; - setTfvars([...tfvars, newVar]); - setEditingState({ - index: newIndex, - var: newVar, - }); + const handleDeleteVar = async (name: string) => { + setIsLoading(true); + await onDelete(name); + setIsLoading(false); + router.refresh(); }; - const handleBulkEdit = () => { + + const handleBulkEdit = async () => { try { const parsedVars = JSON.parse(bulkEditValue); - const validatedVars = parsedVars.map(({ name, value }) => { - if (!name || typeof value === 'undefined') { - throw new Error(`Invalid variable: ${JSON.stringify({ name, value })}`); - } - const existingVar = tfvars.find(v => v.name === name); - return { - name, - value, - updated_at: existingVar ? existingVar.updated_at : new Date().toISOString() - }; - }); - - const names = new Set(); - validatedVars.forEach(v => { - if (names.has(v.name)) { - throw new Error(`Duplicate variable name: ${v.name}`); - } - names.add(v.name); - }); - - updateTFVar(validatedVars); - setBulkEditMode(false); - toast.success('Bulk edit successful'); + if (Array.isArray(parsedVars)) { + setIsLoading(true); + await onBulkUpdate(parsedVars.filter(v => !v.is_secret)); + setIsLoading(false); + setBulkEditMode(false); + router.refresh(); + } } catch (error) { - toast.error(`Invalid JSON format: ${error.message}`); + console.error('Error parsing JSON:', error); } }; const toggleBulkEdit = () => { if (!bulkEditMode) { - const filteredVars = tfvars.map(({ name, value }) => ({ name, value })); - setBulkEditValue(JSON.stringify(filteredVars, null, 2)); + setBulkEditValue(JSON.stringify(envVars.filter(v => !v.is_secret), null, 2)); } setBulkEditMode(!bulkEditMode); }; - const copyToClipboard = useCallback((tfvar: TFVar) => { - navigator.clipboard.writeText(JSON.stringify(tfvar, null, 2)); - toast.success('Copied to clipboard'); - }, []); - - const handleInputChange = (field: 'name' | 'value', value: string) => { - if (editingState.var) { - setEditingState(prev => ({ - ...prev, - var: { - ...prev.var!, - [field]: field === 'name' ? value.toUpperCase() : value - } - })); - } + const handleCopy = (value: string) => { + navigator.clipboard.writeText(value); }; - return ( - - {!bulkEditMode ? ( - <> - - - - Name - Value - Secret - Last Updated - Copy - Edit - Delete - - - {tfvars.length > 0 ? ( - - - {tfvars.map((tfvar, index) => ( - - - {editingState.index === index ? ( - handleInputChange('name', e.target.value)} - onBlur={(e) => handleInputChange('name', e.target.value.toUpperCase())} - /> - ) : tfvar.name} - - - {editingState.index === index ? ( - handleInputChange('value', e.target.value)} - /> - ) : ( - - {tfvar.value} - - )} - - - - - {moment(tfvar.updated_at).fromNow()} - - - - - {editingState.index === index ? ( - - ) : ( - - )} - - - - - - ))} - - - ) : ( - - - - - - )} -
- {tfvars.length > 0 && ( -
- -
- )} - - ) : ( -
-