diff --git a/application_events.json b/application_events.json
index 7efc965..1d8a2b4 100644
--- a/application_events.json
+++ b/application_events.json
@@ -1,165 +1,5 @@
{
"events": [
- {
- "timestamp": "2025-07-17T18:00:01.179115",
- "level": "info",
- "event_type": "dataset_activated",
- "message": "Dataset activated: DAR",
- "details": {
- "dataset_id": "dar",
- "variables_count": 4,
- "streaming_count": 4,
- "prefix": "dar"
- }
- },
- {
- "timestamp": "2025-07-17T18:01:12.766609",
- "level": "info",
- "event_type": "dataset_activated",
- "message": "Dataset activated: DAR",
- "details": {
- "dataset_id": "dar",
- "variables_count": 4,
- "streaming_count": 4,
- "prefix": "dar"
- }
- },
- {
- "timestamp": "2025-07-17T18:01:12.769824",
- "level": "info",
- "event_type": "streaming_started",
- "message": "Multi-dataset streaming started: 1 datasets activated",
- "details": {
- "activated_datasets": 1,
- "total_datasets": 2,
- "udp_host": "127.0.0.1",
- "udp_port": 9870
- }
- },
- {
- "timestamp": "2025-07-17T18:01:26.427183",
- "level": "info",
- "event_type": "Application started",
- "message": "Application initialization completed successfully",
- "details": {}
- },
- {
- "timestamp": "2025-07-17T18:01:26.451766",
- "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-17T18:01:26.456954",
- "level": "info",
- "event_type": "dataset_activated",
- "message": "Dataset activated: DAR",
- "details": {
- "dataset_id": "dar",
- "variables_count": 4,
- "streaming_count": 4,
- "prefix": "dar"
- }
- },
- {
- "timestamp": "2025-07-17T18:01:30.909879",
- "level": "info",
- "event_type": "dataset_activated",
- "message": "Dataset activated: DAR",
- "details": {
- "dataset_id": "dar",
- "variables_count": 4,
- "streaming_count": 4,
- "prefix": "dar"
- }
- },
- {
- "timestamp": "2025-07-17T18:01:30.911944",
- "level": "info",
- "event_type": "streaming_started",
- "message": "Multi-dataset streaming started: 1 datasets activated",
- "details": {
- "activated_datasets": 1,
- "total_datasets": 2,
- "udp_host": "127.0.0.1",
- "udp_port": 9870
- }
- },
- {
- "timestamp": "2025-07-17T18:20:09.887378",
- "level": "info",
- "event_type": "Application started",
- "message": "Application initialization completed successfully",
- "details": {}
- },
- {
- "timestamp": "2025-07-17T18:20:09.913286",
- "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-17T18:20:09.917270",
- "level": "info",
- "event_type": "dataset_activated",
- "message": "Dataset activated: DAR",
- "details": {
- "dataset_id": "dar",
- "variables_count": 4,
- "streaming_count": 4,
- "prefix": "dar"
- }
- },
- {
- "timestamp": "2025-07-18T09:39:20.220724",
- "level": "info",
- "event_type": "dataset_activated",
- "message": "Dataset activated: DAR",
- "details": {
- "dataset_id": "dar",
- "variables_count": 4,
- "streaming_count": 3,
- "prefix": "dar"
- }
- },
- {
- "timestamp": "2025-07-18T09:39:20.226708",
- "level": "info",
- "event_type": "streaming_started",
- "message": "Multi-dataset streaming started: 1 datasets activated",
- "details": {
- "activated_datasets": 1,
- "total_datasets": 2,
- "udp_host": "127.0.0.1",
- "udp_port": 9870
- }
- },
- {
- "timestamp": "2025-07-18T09:40:58.642342",
- "level": "info",
- "event_type": "dataset_deactivated",
- "message": "Dataset deactivated: DAR",
- "details": {
- "dataset_id": "dar"
- }
- },
- {
- "timestamp": "2025-07-18T09:40:58.644338",
- "level": "info",
- "event_type": "streaming_stopped",
- "message": "Multi-dataset streaming stopped: 1 datasets deactivated",
- "details": {}
- },
{
"timestamp": "2025-07-18T09:40:58.647328",
"level": "info",
@@ -10414,8 +10254,155 @@
"trigger_variable": null,
"auto_started": true
}
+ },
+ {
+ "timestamp": "2025-08-14T11:42:26.264053",
+ "level": "info",
+ "event_type": "application_started",
+ "message": "Application initialization completed successfully",
+ "details": {}
+ },
+ {
+ "timestamp": "2025-08-14T11:42:26.345728",
+ "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:42:26.362513",
+ "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:42:26.424426",
+ "level": "error",
+ "event_type": "csv_cleanup_failed",
+ "message": "CSV cleanup failed: 'max_hours'",
+ "details": {}
+ },
+ {
+ "timestamp": "2025-08-14T11:49:00.624419",
+ "level": "info",
+ "event_type": "application_started",
+ "message": "Application initialization completed successfully",
+ "details": {}
+ },
+ {
+ "timestamp": "2025-08-14T11:49:00.691022",
+ "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:49:00.703362",
+ "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:49:00.738130",
+ "level": "error",
+ "event_type": "csv_cleanup_failed",
+ "message": "CSV cleanup failed: 'max_hours'",
+ "details": {}
+ },
+ {
+ "timestamp": "2025-08-14T12:00:00.237052",
+ "level": "error",
+ "event_type": "csv_cleanup_failed",
+ "message": "CSV cleanup failed: 'max_hours'",
+ "details": {}
+ },
+ {
+ "timestamp": "2025-08-14T12:03:29.892080",
+ "level": "info",
+ "event_type": "plot_session_created",
+ "message": "Plot session 'UR29' created and started",
+ "details": {
+ "session_id": "plot_1",
+ "variables": [
+ "UR29_Brix",
+ "UR29_ma"
+ ],
+ "time_window": 25,
+ "trigger_variable": null,
+ "auto_started": true
+ }
+ },
+ {
+ "timestamp": "2025-08-14T12:05:58.231793",
+ "level": "info",
+ "event_type": "application_started",
+ "message": "Application initialization completed successfully",
+ "details": {}
+ },
+ {
+ "timestamp": "2025-08-14T12:05:58.282781",
+ "level": "info",
+ "event_type": "dataset_activated",
+ "message": "Dataset activated: DAR",
+ "details": {
+ "dataset_id": "DAR",
+ "variables_count": 2,
+ "streaming_count": 2,
+ "prefix": "gateway_phoenix"
+ }
+ },
+ {
+ "timestamp": "2025-08-14T12:05:58.294856",
+ "level": "info",
+ "event_type": "csv_recording_started",
+ "message": "CSV recording started: 1 datasets activated",
+ "details": {
+ "activated_datasets": 1,
+ "total_datasets": 3
+ }
+ },
+ {
+ "timestamp": "2025-08-14T12:05:58.314287",
+ "level": "error",
+ "event_type": "csv_cleanup_failed",
+ "message": "CSV cleanup failed: 'max_hours'",
+ "details": {}
+ },
+ {
+ "timestamp": "2025-08-14T12:06:22.595559",
+ "level": "info",
+ "event_type": "plot_session_created",
+ "message": "Plot session 'UR29' created and started",
+ "details": {
+ "session_id": "plot_1",
+ "variables": [
+ "UR29_Brix",
+ "UR29_ma"
+ ],
+ "time_window": 25,
+ "trigger_variable": null,
+ "auto_started": true
+ }
}
],
- "last_updated": "2025-08-14T11:34:45.734619",
+ "last_updated": "2025-08-14T12:06:22.595559",
"total_entries": 1000
}
\ No newline at end of file
diff --git a/config/data/dataset_variables.json b/config/data/dataset_variables.json
index 1106d75..cff7e7c 100644
--- a/config/data/dataset_variables.json
+++ b/config/data/dataset_variables.json
@@ -4,28 +4,20 @@
"dataset_id": "DAR",
"variables": [
{
- "area": "db",
- "db": 1011,
"name": "UR29_Brix",
- "offset": 1322,
- "streaming": true,
- "type": "real"
- },
- {
"area": "db",
"db": 1011,
+ "offset": 1322,
+ "type": "real",
+ "streaming": true
+ },
+ {
"name": "UR29_ma",
- "offset": 1296,
- "streaming": true,
- "type": "real"
- },
- {
"area": "db",
"db": 1011,
- "name": "fUR29_Brix",
- "offset": 1322,
- "streaming": true,
- "type": "real"
+ "offset": 1296,
+ "type": "real",
+ "streaming": true
}
]
},
diff --git a/config/schema/plot-variables.schema.json b/config/schema/plot-variables.schema.json
index 4419ff5..f7e47c4 100644
--- a/config/schema/plot-variables.schema.json
+++ b/config/schema/plot-variables.schema.json
@@ -28,7 +28,12 @@
"variable_name": {
"type": "string",
"title": "Variable Name",
- "description": "Name of the variable to plot (must exist in dataset variables)"
+ "description": "Name of the variable to plot (selected from dataset variables using search widget)"
+ },
+ "label": {
+ "type": "string",
+ "title": "Display Label",
+ "description": "Label shown in the plot legend"
},
"color": {
"type": "string",
@@ -37,6 +42,21 @@
"pattern": "^#[0-9A-Fa-f]{6}$",
"default": "#3498db"
},
+ "line_width": {
+ "type": "number",
+ "title": "Line Width",
+ "description": "Width of the line in the plot",
+ "default": 2,
+ "minimum": 1,
+ "maximum": 10
+ },
+ "y_axis": {
+ "type": "string",
+ "title": "Y-Axis",
+ "description": "Which Y-axis to use for this variable",
+ "enum": ["left", "right"],
+ "default": "left"
+ },
"enabled": {
"type": "boolean",
"title": "Enable Plotting",
@@ -46,7 +66,7 @@
},
"required": [
"variable_name",
- "color"
+ "label"
]
}
}
diff --git a/config/schema/ui/plot-variables.uischema.json b/config/schema/ui/plot-variables.uischema.json
index ba76382..dc7fd6e 100644
--- a/config/schema/ui/plot-variables.uischema.json
+++ b/config/schema/ui/plot-variables.uischema.json
@@ -27,29 +27,49 @@
"items": {
"ui:order": [
"variable_name",
+ "label",
"color",
+ "line_width",
+ "y_axis",
"enabled"
],
"ui:layout": [
[
{
"name": "variable_name",
- "width": 6
+ "width": 4
+ },
+ {
+ "name": "label",
+ "width": 2
},
{
"name": "color",
- "width": 3
+ "width": 2
+ },
+ {
+ "name": "line_width",
+ "width": 2
+ },
+ {
+ "name": "y_axis",
+ "width": 1
},
{
"name": "enabled",
- "width": 3
+ "width": 1
}
]
],
"variable_name": {
+ "ui:widget": "variableSelector",
+ "ui:placeholder": "Search and select variable from datasets...",
+ "ui:help": "🔍 Search and select a variable from the configured datasets (includes live values and metadata)"
+ },
+ "label": {
"ui:widget": "text",
- "ui:placeholder": "UR29_Brix",
- "ui:help": "� Name of the variable to plot (must exist in dataset variables)"
+ "ui:placeholder": "Chart legend label...",
+ "ui:help": "📊 Label shown in the plot legend for this variable"
},
"color": {
"ui:widget": "color",
@@ -72,6 +92,14 @@
]
}
},
+ "line_width": {
+ "ui:widget": "updown",
+ "ui:help": "📏 Width of the line in the plot (1-10 pixels)"
+ },
+ "y_axis": {
+ "ui:widget": "select",
+ "ui:help": "📊 Which Y-axis to use for this variable (left or right)"
+ },
"enabled": {
"ui:widget": "checkbox",
"ui:help": "📊 Enable this variable to be displayed in the real-time plot"
diff --git a/frontend/src/components/PlotManager.jsx b/frontend/src/components/PlotManager.jsx
index 58a77ad..6843c7f 100644
--- a/frontend/src/components/PlotManager.jsx
+++ b/frontend/src/components/PlotManager.jsx
@@ -36,10 +36,12 @@ import validator from '@rjsf/validator-ajv8'
import allWidgets from './widgets/AllWidgets'
import LayoutObjectFieldTemplate from './rjsf/LayoutObjectFieldTemplate'
import PlotRealtimeSession from './PlotRealtimeSession'
+import { useVariableContext } from '../contexts/VariableContext'
import * as api from '../services/api'
// Pure RJSF Plot Manager Component
export default function PlotManager() {
+ const { triggerVariableRefresh } = useVariableContext()
const [plots, setPlots] = useState({})
const [plotsSchemaData, setPlotsSchemaData] = useState(null)
const [plotsVariablesSchemaData, setPlotsVariablesSchemaData] = useState(null)
@@ -238,6 +240,8 @@ export default function PlotManager() {
duration: 2000
})
setPlotsVariablesConfig(formData)
+ // Trigger refresh of variable selectors (though they don't depend on plot vars directly)
+ triggerVariableRefresh()
} catch (error) {
toast({
title: '❌ Failed to save plot variables',
@@ -411,15 +415,10 @@ export default function PlotManager() {
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"
+ description: "Select variable from datasets with search and metadata"
},
label: {
type: "string",
@@ -445,7 +444,7 @@ export default function PlotManager() {
default: "left"
}
},
- required: ["dataset_id", "variable_name", "label"]
+ required: ["variable_name", "label"]
}
}
}
@@ -455,13 +454,26 @@ export default function PlotManager() {
variables: {
items: {
"ui:layout": [[
- { "name": "dataset_id", "width": 2 },
- { "name": "variable_name", "width": 3 },
+ { "name": "variable_name", "width": 4 },
{ "name": "label", "width": 2 },
{ "name": "color", "width": 2 },
- { "name": "line_width", "width": 1 },
+ { "name": "line_width", "width": 2 },
{ "name": "y_axis", "width": 2 }
- ]]
+ ]],
+ variable_name: {
+ "ui:widget": "variableSelector",
+ "ui:placeholder": "Search and select variable from datasets...",
+ "ui:help": "🔍 Search variables from configured datasets with live values and metadata"
+ },
+ label: {
+ "ui:placeholder": "Chart legend label..."
+ },
+ color: {
+ "ui:widget": "color"
+ },
+ line_width: {
+ "ui:widget": "updown"
+ }
}
}
}
diff --git a/frontend/src/components/rjsf/VariableSelectorWidget.jsx b/frontend/src/components/rjsf/VariableSelectorWidget.jsx
index 70894bb..cb45d81 100644
--- a/frontend/src/components/rjsf/VariableSelectorWidget.jsx
+++ b/frontend/src/components/rjsf/VariableSelectorWidget.jsx
@@ -1,14 +1,27 @@
-import React, { useState, useEffect, useMemo, useRef } from 'react'
+import React, { useState, useEffect, useMemo, useRef, useCallback } from 'react'
import {
FormControl, FormLabel, FormHelperText, Select, VStack, HStack,
- Text, Badge, Box, Icon, Input, useColorModeValue, Spinner
+ Text, Badge, Box, Icon, Input, useColorModeValue, Spinner, IconButton, Tooltip
} from '@chakra-ui/react'
-import { SearchIcon } from '@chakra-ui/icons'
+import { SearchIcon, RepeatIcon } from '@chakra-ui/icons'
import { readConfig } from '../../services/api.js'
+import { useVariableContext } from '../../contexts/VariableContext.jsx'
// Widget for selecting existing dataset variables with filtering and search
export function VariableSelectorWidget(props) {
- const { id, value, required, disabled, readonly, label, onChange, onBlur, onFocus, rawErrors = [] } = props
+ const { id, value, required, disabled, readonly, label, onChange, onBlur, onFocus, rawErrors = [], options = {} } = props
+
+ // Extract refresh trigger from options if provided
+ const refreshTrigger = options?.refreshTrigger || 0
+
+ // Use variable context if available, fallback to local state
+ let contextTrigger = 0
+ try {
+ const variableContext = useVariableContext()
+ contextTrigger = variableContext?.variableRefreshTrigger || 0
+ } catch {
+ // Context not available, use local trigger only
+ }
const [datasetVariables, setDatasetVariables] = useState({})
const [loading, setLoading] = useState(true)
@@ -16,6 +29,7 @@ export function VariableSelectorWidget(props) {
const [selectedDataset, setSelectedDataset] = useState('all')
const [liveValue, setLiveValue] = useState(undefined)
const [liveStatus, setLiveStatus] = useState('idle')
+ const [refreshing, setRefreshing] = useState(false)
const esRef = useRef(null)
const borderColor = useColorModeValue('gray.300', 'gray.600')
@@ -24,24 +38,67 @@ export function VariableSelectorWidget(props) {
const selectedVarBgColor = useColorModeValue('blue.50', 'blue.900')
const selectedVarBorderColor = useColorModeValue('blue.200', 'blue.700')
- // Load dataset variables on mount
- useEffect(() => {
- const loadDatasetVariables = async () => {
- try {
- setLoading(true)
- const response = await readConfig('dataset-variables')
- setDatasetVariables(response.data?.dataset_variables || {})
- } catch (error) {
- console.error('Error loading dataset variables:', error)
- setDatasetVariables({})
- } finally {
- setLoading(false)
- }
+ // Load dataset variables function (extracted for reuse)
+ const loadDatasetVariables = useCallback(async () => {
+ try {
+ setLoading(true)
+ const response = await readConfig('dataset-variables')
+ // Handle the array-based structure: { variables: [{dataset_id, variables: [...]}] }
+ const datasetVariablesArray = response?.variables || []
+
+ // Convert array format to object format for easier processing
+ const datasetVariablesObj = {}
+ datasetVariablesArray.forEach(item => {
+ if (item.dataset_id && item.variables) {
+ datasetVariablesObj[item.dataset_id] = {
+ variables: {}
+ }
+ // Convert variables array to object with variable name as key
+ item.variables.forEach(variable => {
+ if (variable.name) {
+ datasetVariablesObj[item.dataset_id].variables[variable.name] = variable
+ }
+ })
+ }
+ })
+
+ setDatasetVariables(datasetVariablesObj)
+ } catch (error) {
+ console.error('Error loading dataset variables:', error)
+ setDatasetVariables({})
+ } finally {
+ setLoading(false)
}
-
- loadDatasetVariables()
}, [])
+ // Manual refresh function
+ const handleRefresh = useCallback(async () => {
+ setRefreshing(true)
+ await loadDatasetVariables()
+ setRefreshing(false)
+ }, [loadDatasetVariables])
+
+ // Load dataset variables on mount and when refresh trigger changes
+ useEffect(() => {
+ loadDatasetVariables()
+ }, [loadDatasetVariables, refreshTrigger, contextTrigger])
+
+ // Auto-refresh when component gains focus (optional behavior)
+ const handleFocusWithRefresh = useCallback((event) => {
+ // Call original onFocus if provided
+ if (onFocus) {
+ onFocus(id, event.target.value)
+ }
+
+ // Auto-refresh data on focus (debounced to avoid excessive calls)
+ const now = Date.now()
+ const lastRefresh = window._lastVariableRefresh || 0
+ if (now - lastRefresh > 30000) { // Refresh at most once every 30 seconds
+ window._lastVariableRefresh = now
+ handleRefresh()
+ }
+ }, [onFocus, id, handleRefresh])
+
// Create flattened list of all variables with their metadata
const allVariables = useMemo(() => {
const variables = []
@@ -190,7 +247,7 @@ export function VariableSelectorWidget(props) {
{label && {label}}
- {/* Search and Dataset Filter */}
+ {/* Search and Dataset Filter with Refresh */}
))}
+
+ }
+ onClick={handleRefresh}
+ isLoading={refreshing}
+ loadingText="Refreshing..."
+ size="md"
+ variant="outline"
+ colorScheme="blue"
+ aria-label="Refresh variables"
+ isDisabled={loading}
+ />
+
{/* Variable Selection */}
@@ -234,10 +304,11 @@ export function VariableSelectorWidget(props) {
value={value || ''}
onChange={(e) => onChange(e.target.value === '' ? undefined : e.target.value)}
onBlur={onBlur && ((e) => onBlur(id, e.target.value))}
- onFocus={onFocus && ((e) => onFocus(id, e.target.value))}
+ onFocus={handleFocusWithRefresh}
borderColor={borderColor}
_focus={{ borderColor: focusBorderColor }}
bg={bgColor}
+ isDisabled={disabled || readonly}
>
{filteredVariables.map((variable, index) => (
diff --git a/frontend/src/components/widgets/AllWidgets.jsx b/frontend/src/components/widgets/AllWidgets.jsx
index 73d94de..5a97837 100644
--- a/frontend/src/components/widgets/AllWidgets.jsx
+++ b/frontend/src/components/widgets/AllWidgets.jsx
@@ -1,5 +1,6 @@
import { customWidgets } from './CustomWidgets'
import { widgets } from '../rjsf/widgets'
+import VariableSelectorWidget from '../rjsf/VariableSelectorWidget'
// Comprehensive widget collection that merges all available widgets
// for full UI schema support with layouts
@@ -17,9 +18,10 @@ export const allWidgets = {
select: widgets.SelectWidget,
checkbox: widgets.CheckboxWidget,
- // Variable selector aliases
- variableSelector: customWidgets.VariableSelectorWidget,
- 'variable-selector': customWidgets.VariableSelectorWidget,
+ // Variable selector aliases - use the advanced version with search and metadata
+ variableSelector: VariableSelectorWidget,
+ 'variable-selector': VariableSelectorWidget,
+ VariableSelectorWidget: VariableSelectorWidget,
// PLC-specific widget aliases (if available)
plcArea: widgets.PlcAreaWidget,
diff --git a/frontend/src/contexts/VariableContext.jsx b/frontend/src/contexts/VariableContext.jsx
new file mode 100644
index 0000000..8bac30c
--- /dev/null
+++ b/frontend/src/contexts/VariableContext.jsx
@@ -0,0 +1,34 @@
+import React, { createContext, useContext, useState, useCallback } from 'react'
+
+// Context for managing variable data updates across components
+const VariableContext = createContext()
+
+export function VariableProvider({ children }) {
+ const [variableRefreshTrigger, setVariableRefreshTrigger] = useState(0)
+
+ // Function to trigger refresh of all variable selectors
+ const triggerVariableRefresh = useCallback(() => {
+ setVariableRefreshTrigger(prev => prev + 1)
+ }, [])
+
+ const value = {
+ variableRefreshTrigger,
+ triggerVariableRefresh
+ }
+
+ return (
+
+ {children}
+
+ )
+}
+
+export function useVariableContext() {
+ const context = useContext(VariableContext)
+ if (context === undefined) {
+ throw new Error('useVariableContext must be used within a VariableProvider')
+ }
+ return context
+}
+
+export default VariableContext
diff --git a/frontend/src/pages/DashboardNew.jsx b/frontend/src/pages/DashboardNew.jsx
index 46e0d96..271849e 100644
--- a/frontend/src/pages/DashboardNew.jsx
+++ b/frontend/src/pages/DashboardNew.jsx
@@ -44,6 +44,7 @@ import validator from '@rjsf/validator-ajv8'
import PlotManager from '../components/PlotManager'
import allWidgets from '../components/widgets/AllWidgets'
import LayoutObjectFieldTemplate from '../components/rjsf/LayoutObjectFieldTemplate'
+import { VariableProvider, useVariableContext } from '../contexts/VariableContext'
import * as api from '../services/api'
// StatusBar Component - Real-time PLC status with action buttons
@@ -312,6 +313,7 @@ function ConfigurationPanel({ schemaData, formData, onFormChange, onSave, saving
// Dataset Manager - Type 3 Form Pattern implementation
function DatasetManager() {
+ const { triggerVariableRefresh } = useVariableContext()
const [datasetsConfig, setDatasetsConfig] = useState(null)
const [variablesConfig, setVariablesConfig] = useState(null)
const [datasetsSchemaData, setDatasetsSchemaData] = useState(null)
@@ -379,6 +381,8 @@ function DatasetManager() {
duration: 2000
})
setVariablesConfig(formData)
+ // Trigger refresh of all variable selector widgets
+ triggerVariableRefresh()
} catch (error) {
toast({
title: '❌ Failed to save variables',
@@ -599,7 +603,10 @@ function DatasetManager() {
templates={{ ObjectFieldTemplate: LayoutObjectFieldTemplate }}
onSubmit={({ formData }) => {
updateSelectedDatasetVariables(formData)
- saveVariables(variablesConfig)
+ saveVariables(variablesConfig).then(() => {
+ // Additional trigger after successful save
+ triggerVariableRefresh()
+ })
}}
onChange={({ formData }) => updateSelectedDatasetVariables(formData)}
>
@@ -707,8 +714,17 @@ function EventsDisplay({ events, loading, onRefresh }) {
)
}
-// Main Dashboard Component - PLC S7-31x Streamer & Logger
+// Main Dashboard Component - PLC S7-31x Streamer & Logger
export default function Dashboard() {
+ return (
+
+
+
+ )
+}
+
+// Dashboard Content Component (separated to use context)
+function DashboardContent() {
const [status, setStatus] = useState(null)
const [statusLoading, setStatusLoading] = useState(true)
const [statusError, setStatusError] = useState('')
diff --git a/system_state.json b/system_state.json
index 07b1a7c..ce76b17 100644
--- a/system_state.json
+++ b/system_state.json
@@ -3,11 +3,11 @@
"should_connect": true,
"should_stream": false,
"active_datasets": [
+ "Test",
"Fast",
- "DAR",
- "Test"
+ "DAR"
]
},
"auto_recovery_enabled": true,
- "last_update": "2025-08-14T11:34:34.761474"
+ "last_update": "2025-08-14T12:05:58.306284"
}
\ No newline at end of file