feat: Add confirmation dialog for deletion operations, enhance logging in symbol processor, and update button color schemes

This commit is contained in:
Miguel 2025-08-15 22:31:25 +02:00
parent 0f2b9b8fb4
commit a4f74b70ed
6 changed files with 215 additions and 40 deletions

View File

@ -8138,8 +8138,15 @@
"active_datasets_count": 3,
"csv_recording_active": false
}
},
{
"timestamp": "2025-08-15T21:25:51.900870",
"level": "info",
"event_type": "application_started",
"message": "Application initialization completed successfully",
"details": {}
}
],
"last_updated": "2025-08-15T21:03:44.900837",
"total_entries": 675
"last_updated": "2025-08-15T21:25:51.900870",
"total_entries": 676
}

View File

@ -49,7 +49,7 @@ import * as api from '../services/api'
// Collapsible Form Component for Plot Definitions
function CollapsiblePlotForm({ data, schema, uiSchema, onSave, title, icon, getItemLabel }) {
const [isOpen, setIsOpen] = useState(false)
const [isOpen, setIsOpen] = useState(true)
const [formData, setFormData] = useState(data)
useEffect(() => {
@ -577,7 +577,7 @@ export default function PlotManager() {
<HStack spacing={2} mt={4}>
<Button
type="submit"
colorScheme="blue"
colorScheme="red"
isLoading={actionLoading.savePlotsVariables}
loadingText="Saving..."
>

View File

@ -23,7 +23,16 @@ import {
Collapse,
useDisclosure,
Spinner,
Select
Select,
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalFooter,
ModalBody,
ModalCloseButton,
Alert,
AlertIcon
} from '@chakra-ui/react'
import { ChevronDownIcon, ChevronUpIcon } from '@chakra-ui/icons'
import Form from '@rjsf/chakra-ui'
@ -34,10 +43,57 @@ import PlotRealtimeSession from './PlotRealtimeSession'
import { useVariableContext } from '../contexts/VariableContext'
import * as api from '../services/api'
// Confirmation Dialog Component for deletion operations
function ConfirmationDialog({ isOpen, onClose, onConfirm, title, message, itemName, confirmButtonText = "Delete" }) {
return (
<Modal isOpen={isOpen} onClose={onClose} isCentered>
<ModalOverlay />
<ModalContent>
<ModalHeader>
<Flex align="center">
<Box mr={3} fontSize="2xl"></Box>
{title}
</Flex>
</ModalHeader>
<ModalCloseButton />
<ModalBody>
<VStack spacing={3} align="stretch">
<Text>
{message}
</Text>
{itemName && (
<Box p={3} bg="gray.50" borderRadius="md" borderLeft="4px solid" borderColor="red.400">
<Text fontWeight="bold" color="red.600">
Item to delete: "{itemName}"
</Text>
</Box>
)}
<Alert status="warning" borderRadius="md">
<AlertIcon />
<Text fontSize="sm">
This action cannot be undone. Make sure you want to proceed.
</Text>
</Alert>
</VStack>
</ModalBody>
<ModalFooter>
<Button variant="outline" mr={3} onClick={onClose}>
Cancel
</Button>
<Button colorScheme="red" onClick={onConfirm}>
🗑 {confirmButtonText}
</Button>
</ModalFooter>
</ModalContent>
</Modal>
)
}
// Collapsible Plot Items Form - Each item in the array is individually collapsible
function CollapsiblePlotItemsForm({ data, schema, uiSchema, onSave, title, icon, getItemLabel, isExpanded, onToggleExpansion }) {
const [formData, setFormData] = useState(data)
const [expandedItems, setExpandedItems] = useState(new Set())
const [confirmDelete, setConfirmDelete] = useState({ isOpen: false, index: null, itemName: '' })
useEffect(() => {
// Solo actualizar formData si data realmente cambió en contenido
@ -98,6 +154,28 @@ function CollapsiblePlotItemsForm({ data, schema, uiSchema, onSave, title, icon,
else if (i > index) newExpanded.add(i - 1)
})
setExpandedItems(newExpanded)
// Close confirmation dialog
setConfirmDelete({ isOpen: false, index: null, itemName: '' })
}
const handleDeleteClick = (index) => {
const item = items[index]
const itemName = getItemLabel ? getItemLabel(item) : (item.name || item.id || `Item ${index + 1}`)
setConfirmDelete({
isOpen: true,
index,
itemName
})
}
const handleConfirmDelete = () => {
if (confirmDelete.index !== null) {
removeItem(confirmDelete.index)
}
}
const handleCancelDelete = () => {
setConfirmDelete({ isOpen: false, index: null, itemName: '' })
}
const saveChanges = async () => {
@ -141,7 +219,7 @@ function CollapsiblePlotItemsForm({ data, schema, uiSchema, onSave, title, icon,
<Button size="sm" colorScheme="green" onClick={addItem}>
Add Item
</Button>
<Button size="sm" colorScheme="blue" onClick={saveChanges}>
<Button size="sm" colorScheme="red" onClick={saveChanges}>
💾 Save All
</Button>
</HStack>
@ -186,7 +264,8 @@ function CollapsiblePlotItemsForm({ data, schema, uiSchema, onSave, title, icon,
size="xs"
colorScheme="red"
variant="ghost"
onClick={() => removeItem(index)}
onClick={() => handleDeleteClick(index)}
title="Delete this item"
>
🗑
</Button>
@ -251,7 +330,8 @@ function CollapsiblePlotItemsForm({ data, schema, uiSchema, onSave, title, icon,
size="xs"
colorScheme="red"
variant="ghost"
onClick={() => removeItem(index)}
onClick={() => handleDeleteClick(index)}
title="Delete this item"
>
🗑
</Button>
@ -280,6 +360,17 @@ function CollapsiblePlotItemsForm({ data, schema, uiSchema, onSave, title, icon,
)}
</CardBody>
)}
{/* Confirmation Dialog for Deletion */}
<ConfirmationDialog
isOpen={confirmDelete.isOpen}
onClose={handleCancelDelete}
onConfirm={handleConfirmDelete}
title={`Delete ${title.replace(/📊|📋|⚙️|📈|🗂️/g, '').trim()} Item`}
message={`Are you sure you want to delete this ${title.toLowerCase().replace(/📊|📋|⚙️|📈|🗂️/g, '').trim()} item?`}
itemName={confirmDelete.itemName}
confirmButtonText="Delete Item"
/>
</Card>
)
}
@ -306,9 +397,6 @@ function CollapsiblePlotChart({ plotDefinition, plotVariables, onConfigUpdate, o
>
{isExpanded ? 'Hide' : 'Show'} Chart
</Button>
<Button size="xs" colorScheme="red" variant="outline" onClick={() => onRemove(plotDefinition.id)}>
</Button>
</HStack>
</Flex>
</CardHeader>
@ -768,7 +856,7 @@ export default function PlotManager() {
onChange={({ formData }) => updateSelectedPlotVariables(formData)}
>
<HStack spacing={2} mt={4}>
<Button type="submit" colorScheme="blue">
<Button type="submit" colorScheme="red">
💾 Save Variables for {selectedPlotId}
</Button>
<Button variant="outline" onClick={loadPlotData}>

View File

@ -550,14 +550,6 @@ export default function PlotRealtimeSession({
aria-label="Settings"
onClick={() => setShowSettings(!showSettings)}
/>
<Button
size="sm"
colorScheme="red"
variant="ghost"
onClick={() => onRemove?.(plotDefinition.id)}
>
</Button>
</HStack>
</HStack>
</CardHeader>

View File

@ -43,7 +43,14 @@ import {
AccordionButton,
AccordionPanel,
Collapse,
useDisclosure
useDisclosure,
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalFooter,
ModalBody,
ModalCloseButton
} from '@chakra-ui/react'
import { ChevronDownIcon, ChevronUpIcon } from '@chakra-ui/icons'
import Form from '@rjsf/chakra-ui'
@ -56,10 +63,57 @@ import { VariableProvider, useVariableContext } from '../contexts/VariableContex
import * as api from '../services/api'
import { useCoordinatedPolling } from '../hooks/useCoordinatedConnection'
// Confirmation Dialog Component for deletion operations
function ConfirmationDialog({ isOpen, onClose, onConfirm, title, message, itemName, confirmButtonText = "Delete" }) {
return (
<Modal isOpen={isOpen} onClose={onClose} isCentered>
<ModalOverlay />
<ModalContent>
<ModalHeader>
<Flex align="center">
<Box mr={3} fontSize="2xl"></Box>
{title}
</Flex>
</ModalHeader>
<ModalCloseButton />
<ModalBody>
<VStack spacing={3} align="stretch">
<Text>
{message}
</Text>
{itemName && (
<Box p={3} bg="gray.50" borderRadius="md" borderLeft="4px solid" borderColor="red.400">
<Text fontWeight="bold" color="red.600">
Item to delete: "{itemName}"
</Text>
</Box>
)}
<Alert status="warning" borderRadius="md">
<AlertIcon />
<Text fontSize="sm">
This action cannot be undone. Make sure you want to proceed.
</Text>
</Alert>
</VStack>
</ModalBody>
<ModalFooter>
<Button variant="outline" mr={3} onClick={onClose}>
Cancel
</Button>
<Button colorScheme="red" onClick={onConfirm}>
🗑 {confirmButtonText}
</Button>
</ModalFooter>
</ModalContent>
</Modal>
)
}
// Collapsible Array Items Form - Each item in the array is individually collapsible
function CollapsibleArrayItemsForm({ data, schema, uiSchema, onSave, title, icon, getItemLabel }) {
const [formData, setFormData] = useState(data)
const [expandedItems, setExpandedItems] = useState(new Set())
const [confirmDelete, setConfirmDelete] = useState({ isOpen: false, index: null, itemName: '' })
useEffect(() => {
setFormData(data)
@ -117,6 +171,28 @@ function CollapsibleArrayItemsForm({ data, schema, uiSchema, onSave, title, icon
else if (i > index) newExpanded.add(i - 1)
})
setExpandedItems(newExpanded)
// Close confirmation dialog
setConfirmDelete({ isOpen: false, index: null, itemName: '' })
}
const handleDeleteClick = (index) => {
const item = items[index]
const itemName = getItemLabel ? getItemLabel(item) : (item.name || item.id || `Item ${index + 1}`)
setConfirmDelete({
isOpen: true,
index,
itemName
})
}
const handleConfirmDelete = () => {
if (confirmDelete.index !== null) {
removeItem(confirmDelete.index)
}
}
const handleCancelDelete = () => {
setConfirmDelete({ isOpen: false, index: null, itemName: '' })
}
const saveChanges = () => {
@ -144,7 +220,7 @@ function CollapsibleArrayItemsForm({ data, schema, uiSchema, onSave, title, icon
<Button size="sm" colorScheme="green" onClick={addItem}>
Add Item
</Button>
<Button size="sm" colorScheme="blue" onClick={saveChanges}>
<Button size="sm" colorScheme="red" onClick={saveChanges}>
💾 Save All
</Button>
</HStack>
@ -186,7 +262,8 @@ function CollapsibleArrayItemsForm({ data, schema, uiSchema, onSave, title, icon
size="xs"
colorScheme="red"
variant="ghost"
onClick={() => removeItem(index)}
onClick={() => handleDeleteClick(index)}
title="Delete this item"
>
🗑
</Button>
@ -214,6 +291,17 @@ function CollapsibleArrayItemsForm({ data, schema, uiSchema, onSave, title, icon
</VStack>
)}
</CardBody>
{/* Confirmation Dialog for Deletion */}
<ConfirmationDialog
isOpen={confirmDelete.isOpen}
onClose={handleCancelDelete}
onConfirm={handleConfirmDelete}
title={`Delete ${title.replace(/📊|📋|⚙️|📈|🗂️/g, '').trim()} Item`}
message={`Are you sure you want to delete this ${title.toLowerCase().replace(/📊|📋|⚙️|📈|🗂️/g, '').trim()} item?`}
itemName={confirmDelete.itemName}
confirmButtonText="Delete Item"
/>
</Card>
)
}
@ -615,7 +703,7 @@ function ConfigurationPanel({ schemaData, formData, onFormChange, onSave, saving
)}
</CardHeader>
<CardBody>
<Form
<Form
schema={schemaData.schema}
uiSchema={schemaData.uiSchema}
formData={formData}
@ -627,8 +715,8 @@ function ConfigurationPanel({ schemaData, formData, onFormChange, onSave, saving
>
<HStack spacing={2} mt={4}>
<Button
type="submit"
colorScheme="blue"
type="submit"
colorScheme="red"
isLoading={saving}
loadingText="Saving..."
>
@ -1145,7 +1233,7 @@ function DatasetManager() {
}}
>
<HStack spacing={2} mt={4}>
<Button type="submit" colorScheme="blue">
<Button type="submit" colorScheme="red">
💾 Save Variables for {selectedDatasetId}
</Button>
<Button variant="outline" onClick={loadDatasetData}>
@ -1351,7 +1439,7 @@ function DashboardContent() {
<StatusBar status={status} isConnected={isConnected} isLeader={isLeader} />
<Tabs variant="enclosed" colorScheme="blue">
<Tabs variant="enclosed" colorScheme="orange" defaultIndex={2}>
<TabList>
<Tab>🔧 Configuration</Tab>
<Tab>📊 Datasets</Tab>

View File

@ -34,11 +34,11 @@ class SymbolProcessor:
if self.logger:
# Check if logger is EventLogger (has log_event method) or standard logger
if hasattr(self.logger, 'log_event'):
if hasattr(self.logger, "log_event"):
self.logger.log_event(
'info',
'symbols_loaded',
f"Loaded {len(self._symbols_cache.get('symbols', []))} symbols"
"info",
"symbols_loaded",
f"Loaded {len(self._symbols_cache.get('symbols', []))} symbols",
)
else:
self.logger.info(
@ -48,11 +48,11 @@ class SymbolProcessor:
except Exception as e:
if self.logger:
# Check if logger is EventLogger (has log_event method) or standard logger
if hasattr(self.logger, 'log_event'):
if hasattr(self.logger, "log_event"):
self.logger.log_event(
'error',
'symbols_load_error',
f"Error loading symbols: {str(e)}"
"error",
"symbols_load_error",
f"Error loading symbols: {str(e)}",
)
else:
self.logger.error(f"Error loading symbols: {str(e)}")
@ -98,11 +98,11 @@ class SymbolProcessor:
if not symbol:
if self.logger:
# Check if logger is EventLogger (has log_event method) or standard logger
if hasattr(self.logger, 'log_event'):
if hasattr(self.logger, "log_event"):
self.logger.log_event(
'warning',
'symbol_not_found',
f"Symbol '{symbol_name}' not found"
"warning",
"symbol_not_found",
f"Symbol '{symbol_name}' not found",
)
else:
self.logger.warning(f"Symbol '{symbol_name}' not found")