diff --git a/application_events.json b/application_events.json index 442d157..fc922a7 100644 --- a/application_events.json +++ b/application_events.json @@ -1,46 +1,5 @@ { "events": [ - { - "timestamp": "2025-07-17T17:42:25.463541", - "level": "error", - "event_type": "dataset_streaming_error", - "message": "Error in dataset 'DAR' streaming loop: dictionary changed size during iteration", - "details": { - "dataset_id": "dar", - "error": "dictionary changed size during iteration", - "consecutive_errors": 1 - } - }, - { - "timestamp": "2025-07-17T17:43:27.747295", - "level": "info", - "event_type": "dataset_created", - "message": "Dataset created: mixer (prefix: mixer)", - "details": { - "dataset_id": "mixer", - "name": "mixer", - "prefix": "mixer", - "sampling_interval": 1.0 - } - }, - { - "timestamp": "2025-07-17T17:57:48.090115", - "level": "info", - "event_type": "Application started", - "message": "Application initialization completed successfully", - "details": {} - }, - { - "timestamp": "2025-07-17T17:57:48.111503", - "level": "info", - "event_type": "plc_connection", - "message": "Successfully connected to PLC 10.1.33.11", - "details": { - "ip": "10.1.33.11", - "rack": 0, - "slot": 2 - } - }, { "timestamp": "2025-07-17T17:57:48.115971", "level": "info", @@ -10421,8 +10380,44 @@ "trigger_variable": null, "auto_started": true } + }, + { + "timestamp": "2025-08-14T11:26:02.147101", + "level": "info", + "event_type": "application_started", + "message": "Application initialization completed successfully", + "details": {} + }, + { + "timestamp": "2025-08-14T11:26:02.211520", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: DAR", + "details": { + "dataset_id": "DAR", + "variables_count": 3, + "streaming_count": 3, + "prefix": "gateway_phoenix" + } + }, + { + "timestamp": "2025-08-14T11:26:02.225519", + "level": "info", + "event_type": "csv_recording_started", + "message": "CSV recording started: 1 datasets activated", + "details": { + "activated_datasets": 1, + "total_datasets": 3 + } + }, + { + "timestamp": "2025-08-14T11:26:02.293765", + "level": "error", + "event_type": "csv_cleanup_failed", + "message": "CSV cleanup failed: 'max_hours'", + "details": {} } ], - "last_updated": "2025-08-14T11:15:09.838725", + "last_updated": "2025-08-14T11:26:02.293765", "total_entries": 1000 } \ No newline at end of file diff --git a/frontend/src/components/PlotManager.jsx b/frontend/src/components/PlotManager.jsx index b1e0dac..58a77ad 100644 --- a/frontend/src/components/PlotManager.jsx +++ b/frontend/src/components/PlotManager.jsx @@ -28,7 +28,8 @@ import { TabPanels, Tab, TabPanel, - Divider + Divider, + Select } from '@chakra-ui/react' import Form from '@rjsf/chakra-ui' import validator from '@rjsf/validator-ajv8' @@ -44,6 +45,7 @@ export default function PlotManager() { const [plotsVariablesSchemaData, setPlotsVariablesSchemaData] = useState(null) const [plotsConfig, setPlotsConfig] = useState(null) const [plotsVariablesConfig, setPlotsVariablesConfig] = useState(null) + const [selectedPlotId, setSelectedPlotId] = useState('') const [loading, setLoading] = useState(true) const [actionLoading, setActionLoading] = useState({}) @@ -77,6 +79,11 @@ export default function PlotManager() { setPlotsVariablesSchemaData(plotsVariablesSchemaResponse) setPlotsConfig(plotsConfigData) setPlotsVariablesConfig(plotsVariablesConfigData) + + // Auto-select first plot if none selected + if (!selectedPlotId && plotsConfigData?.plots?.length > 0) { + setSelectedPlotId(plotsConfigData.plots[0].id) + } } catch (error) { toast({ title: '❌ Failed to load plot data', @@ -101,6 +108,42 @@ export default function PlotManager() { return plotVarEntry?.variables || [] } + // Type 3 Pattern Helper Functions + // Get filtered variables for selected plot + const getSelectedPlotVariables = () => { + if (!plotsVariablesConfig?.variables || !selectedPlotId) { + return { variables: [] } + } + + const plotVars = plotsVariablesConfig.variables.find(v => v.plot_id === selectedPlotId) + return plotVars || { variables: [] } + } + + // Update variables for selected plot + const updateSelectedPlotVariables = (newVariableData) => { + if (!plotsVariablesConfig?.variables || !selectedPlotId) return + + const updatedVariables = plotsVariablesConfig.variables.map(v => + v.plot_id === selectedPlotId + ? { ...v, ...newVariableData } + : v + ) + + // If plot not found, add new entry + if (!plotsVariablesConfig.variables.find(v => v.plot_id === selectedPlotId)) { + updatedVariables.push({ + plot_id: selectedPlotId, + ...newVariableData + }) + } + + const updatedConfig = { ...plotsVariablesConfig, variables: updatedVariables } + setPlotsVariablesConfig(updatedConfig) + } + + // Available plots for combo selector + const availablePlots = plotsConfig?.plots || [] + // Handle plot configuration updates const handlePlotConfigUpdate = async (plotId, newConfig) => { try { @@ -310,42 +353,178 @@ export default function PlotManager() { - {plotsVariablesSchemaData?.schema && plotsVariablesConfig && ( - - - Plot Variables Configuration - - Configure which variables are displayed in each plot session - - - -
savePlotsVariablesConfig(formData)} - onChange={({ formData }) => setPlotsVariablesConfig(formData)} - > - - - - -
-
-
- )} + {/* Plot Variables Configuration with Combo Selector - Type 3 Pattern */} + + + Plot Variables Configuration + + Select a plot session, then configure which variables are displayed in that plot + + + + {/* Step 1: Plot Selector (Combo) */} + + + + 🎯 Select Plot Session + + + {availablePlots.length === 0 && ( + + ⚠️ No plot sessions available. Configure plot definitions first in the "Plot Definitions" tab. + + )} + + + {/* Variables Configuration Form */} + {selectedPlotId && ( + + + + ⚙️ Configure Variables for Plot "{selectedPlotId}" + + + {/* Simplified schema for selected plot variables */} + {(() => { + const selectedPlotVars = getSelectedPlotVariables() + + // Schema for this plot's variables + const singlePlotSchema = { + type: "object", + properties: { + variables: { + type: "array", + title: "Variables", + description: `Variables to display in plot ${selectedPlotId}`, + items: { + type: "object", + title: "Plot Variable", + properties: { + dataset_id: { + type: "string", + title: "Dataset Source", + description: "Which dataset contains this variable" + }, + variable_name: { + type: "string", + title: "Variable Name", + description: "Name of the variable to plot" + }, + label: { + type: "string", + title: "Display Label", + description: "Label shown in the plot legend" + }, + color: { + type: "string", + title: "Line Color", + default: "#3182CE" + }, + line_width: { + type: "number", + title: "Line Width", + default: 2, + minimum: 1, + maximum: 10 + }, + y_axis: { + type: "string", + title: "Y-Axis", + enum: ["left", "right"], + default: "left" + } + }, + required: ["dataset_id", "variable_name", "label"] + } + } + } + } + + const singlePlotUiSchema = { + variables: { + items: { + "ui:layout": [[ + { "name": "dataset_id", "width": 2 }, + { "name": "variable_name", "width": 3 }, + { "name": "label", "width": 2 }, + { "name": "color", "width": 2 }, + { "name": "line_width", "width": 1 }, + { "name": "y_axis", "width": 2 } + ]] + } + } + } + + return ( +
{ + updateSelectedPlotVariables(formData) + // Create updated config and save it + const updatedVariables = plotsVariablesConfig.variables?.map(v => + v.plot_id === selectedPlotId + ? { ...v, ...formData } + : v + ) || [] + + // If plot not found, add new entry + if (!plotsVariablesConfig.variables?.find(v => v.plot_id === selectedPlotId)) { + updatedVariables.push({ + plot_id: selectedPlotId, + ...formData + }) + } + + const updatedConfig = { ...plotsVariablesConfig, variables: updatedVariables } + savePlotsVariablesConfig(updatedConfig) + }} + onChange={({ formData }) => updateSelectedPlotVariables(formData)} + > + + + + +
+ ) + })()} +
+ )} + + {!selectedPlotId && availablePlots.length > 0 && ( + + + 👆 Select a plot session above to configure its variables + + + )} +
+
+
diff --git a/system_state.json b/system_state.json index 2b785b2..3e52620 100644 --- a/system_state.json +++ b/system_state.json @@ -3,11 +3,11 @@ "should_connect": true, "should_stream": false, "active_datasets": [ - "Test", "DAR", + "Test", "Fast" ] }, "auto_recovery_enabled": true, - "last_update": "2025-08-14T11:14:46.738038" + "last_update": "2025-08-14T11:26:02.237589" } \ No newline at end of file