feat: Add confirmation dialog for deletion operations, enhance logging in symbol processor, and update button color schemes
This commit is contained in:
parent
0f2b9b8fb4
commit
a4f74b70ed
|
@ -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
|
||||
}
|
|
@ -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..."
|
||||
>
|
||||
|
|
|
@ -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}>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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")
|
||||
|
|
Loading…
Reference in New Issue