diff --git a/application_events.json b/application_events.json index 515df5a..d0651e4 100644 --- a/application_events.json +++ b/application_events.json @@ -9252,8 +9252,15 @@ "event_type": "application_started", "message": "Application initialization completed successfully", "details": {} + }, + { + "timestamp": "2025-08-12T09:13:36.619106", + "level": "info", + "event_type": "application_started", + "message": "Application initialization completed successfully", + "details": {} } ], - "last_updated": "2025-08-11T16:21:42.173167", - "total_entries": 861 + "last_updated": "2025-08-12T09:13:36.619106", + "total_entries": 862 } \ No newline at end of file diff --git a/config/schema/plc.schema.json b/config/schema/plc.schema.json index ab4b575..4291732 100644 --- a/config/schema/plc.schema.json +++ b/config/schema/plc.schema.json @@ -1,154 +1,154 @@ { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "plc.schema.json", - "title": "PLC & UDP Configuration", - "description": "Esquema para editar plc_config.json", - "type": "object", - "additionalProperties": false, - "properties": { - "plc_config": { - "type": "object", - "title": "PLC Configuration", - "additionalProperties": false, - "properties": { - "ip": { - "type": "string", - "title": "PLC IP", - "description": "Dirección IP del PLC (S7-31x)", - "format": "ipv4", - "pattern": "^.+$" - }, - "rack": { - "type": "integer", - "title": "Rack", - "description": "Número de rack (0-7)", - "minimum": 0, - "maximum": 7, - "default": 0 - }, - "slot": { - "type": "integer", - "title": "Slot", - "description": "Número de slot (generalmente 2)", - "minimum": 0, - "maximum": 31, - "default": 2 - } - }, - "required": [ - "ip", - "rack", - "slot" - ] + "$id": "plc.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "additionalProperties": false, + "description": "Esquema para editar plc_config.json", + "properties": { + "csv_config": { + "additionalProperties": false, + "properties": { + "cleanup_interval_hours": { + "default": 24, + "minimum": 1, + "title": "Cleanup Interval (h)", + "type": "integer" }, - "udp_config": { - "type": "object", - "title": "UDP Configuration", - "additionalProperties": false, - "properties": { - "host": { - "type": "string", - "title": "UDP Host", - "pattern": "^.+$", - "default": "127.0.0.1" - }, - "port": { - "type": "integer", - "minimum": 1, - "maximum": 65535, - "default": 9870 - } - }, - "required": [ - "host", - "port" - ] + "last_cleanup": { + "title": "Last Cleanup", + "type": [ + "string", + "null" + ] }, - "sampling_interval": { - "type": "number", - "minimum": 0.01, - "maximum": 10, - "title": "Sampling Interval (s)", - "description": "Intervalo global de muestreo en segundos", - "default": 0.1 + "max_days": { + "default": 30, + "minimum": 1, + "title": "Max Days", + "type": [ + "integer", + "null" + ] }, - "csv_config": { - "type": "object", - "title": "CSV Recording", - "additionalProperties": false, - "properties": { - "records_directory": { - "type": "string", - "title": "Records Directory", - "default": "records" - }, - "rotation_enabled": { - "type": "boolean", - "title": "Rotation", - "default": true, - "enum": [ - true, - false - ], - "options": { - "enum_titles": [ - "Activate", - "Deactivate" - ] - } - }, - "max_size_mb": { - "type": [ - "integer", - "null" - ], - "minimum": 1, - "title": "Max Size (MB)", - "default": 1000 - }, - "max_days": { - "type": [ - "integer", - "null" - ], - "minimum": 1, - "title": "Max Days", - "default": 30 - }, - "max_hours": { - "type": [ - "integer", - "null" - ], - "minimum": 1, - "title": "Max Hours", - "default": null - }, - "cleanup_interval_hours": { - "type": "integer", - "minimum": 1, - "title": "Cleanup Interval (h)", - "default": 24 - }, - "last_cleanup": { - "type": [ - "string", - "null" - ], - "title": "Last Cleanup" - } - }, - "required": [ - "records_directory", - "rotation_enabled", - "cleanup_interval_hours" + "max_hours": { + "default": null, + "minimum": 1, + "title": "Max Hours", + "type": [ + "integer", + "null" + ] + }, + "max_size_mb": { + "default": 1000, + "minimum": 1, + "title": "Max Size (MB)", + "type": [ + "integer", + "null" + ] + }, + "records_directory": { + "default": "records", + "title": "Records Directory", + "type": "string" + }, + "rotation_enabled": { + "default": true, + "enum": [ + true, + false + ], + "options": { + "enum_titles": [ + "Activate", + "Deactivate" ] + }, + "title": "Rotation", + "type": "boolean" } + }, + "required": [ + "records_directory", + "rotation_enabled", + "cleanup_interval_hours" + ], + "title": "CSV Recording", + "type": "object" }, - "required": [ - "plc_config", - "udp_config", - "sampling_interval", - "csv_config" - ] + "plc_config": { + "additionalProperties": false, + "properties": { + "ip": { + "description": "Dirección IP del PLC (S7-31x)", + "format": "ipv4", + "pattern": "^.+$", + "title": "PLC IP", + "type": "string" + }, + "rack": { + "default": 0, + "description": "Número de rack (0-7)", + "maximum": 7, + "minimum": 0, + "title": "Rack", + "type": "integer" + }, + "slot": { + "default": 2, + "description": "Número de slot (generalmente 2)", + "maximum": 31, + "minimum": 0, + "title": "Slot", + "type": "integer" + } + }, + "required": [ + "ip", + "rack", + "slot" + ], + "title": "PLC Configuration", + "type": "object" + }, + "sampling_interval": { + "default": 0.1, + "description": "Intervalo global de muestreo en segundos", + "maximum": 10, + "minimum": 0.01, + "title": "Sampling Interval (s)", + "type": "number" + }, + "udp_config": { + "additionalProperties": false, + "properties": { + "host": { + "default": "127.0.0.1", + "pattern": "^.+$", + "title": "UDP Host", + "type": "string" + }, + "port": { + "default": 9870, + "maximum": 65535, + "minimum": 1, + "type": "integer" + } + }, + "required": [ + "host", + "port" + ], + "title": "UDP Configuration", + "type": "object" + } + }, + "required": [ + "plc_config", + "udp_config", + "sampling_interval", + "csv_config" + ], + "title": "PLC & UDP Configuration", + "type": "object" } \ No newline at end of file diff --git a/config/schema/ui/plc.uischema.json b/config/schema/ui/plc.uischema.json index 5da2348..9bbf5d8 100644 --- a/config/schema/ui/plc.uischema.json +++ b/config/schema/ui/plc.uischema.json @@ -1,44 +1,60 @@ { - "plc_config": { - "ip": { - "ui:placeholder": "192.168.1.100" - }, - "rack": { - "ui:widget": "UpDownWidget" - }, - "slot": { - "ui:widget": "UpDownWidget" - } + "csv_config": { + "cleanup_interval_hours": { + "ui:widget": "UpDownWidget" }, - "udp_config": { - "host": { - "ui:placeholder": "127.0.0.1" - }, - "port": { - "ui:widget": "UpDownWidget" - } + "max_days": { + "ui:widget": "UpDownWidget" }, - "sampling_interval": { - "ui:widget": "UpDownWidget" + "max_hours": { + "ui:widget": "UpDownWidget" }, - "csv_config": { - "records_directory": { - "ui:placeholder": "records" + "max_size_mb": { + "ui:widget": "UpDownWidget" + }, + "records_directory": { + "ui:placeholder": "records" + }, + "rotation_enabled": { + "ui:widget": "CheckboxWidget" + }, + "ui:layout": [ + [ + { + "name": "cleanup_interval_hours", + "width": 3 }, - "rotation_enabled": { - "ui:widget": "CheckboxWidget" + { + "name": "last_cleanup", + "width": 3 }, - "max_size_mb": { - "ui:widget": "UpDownWidget" - }, - "max_days": { - "ui:widget": "UpDownWidget" - }, - "max_hours": { - "ui:widget": "UpDownWidget" - }, - "cleanup_interval_hours": { - "ui:widget": "UpDownWidget" + { + "name": "max_days", + "width": 3 } + ] + ] + }, + "plc_config": { + "ip": { + "ui:placeholder": "192.168.1.100" + }, + "rack": { + "ui:widget": "UpDownWidget" + }, + "slot": { + "ui:widget": "UpDownWidget" } + }, + "sampling_interval": { + "ui:widget": "UpDownWidget" + }, + "udp_config": { + "host": { + "ui:placeholder": "127.0.0.1" + }, + "port": { + "ui:widget": "UpDownWidget" + } + } } \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json index eae1515..e69e053 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,7 +10,9 @@ }, "dependencies": { "@rjsf/core": "^5.24.12", + "@rjsf/fluent-ui": "^5.24.12", "@rjsf/validator-ajv8": "^5.24.12", + "@fluentui/react": "^8.120.2", "bootstrap": "^5.3.3", "react": "^18.2.0", "react-bootstrap": "^2.10.4", diff --git a/frontend/src/pages/Config.jsx b/frontend/src/pages/Config.jsx index 741f749..48f226a 100644 --- a/frontend/src/pages/Config.jsx +++ b/frontend/src/pages/Config.jsx @@ -1,6 +1,6 @@ import React, { useEffect, useMemo, useState } from 'react' import { Container, Row, Col, Button, ButtonGroup, Dropdown, DropdownButton } from 'react-bootstrap' -import Form from '@rjsf/core' +import Form from '@rjsf/fluent-ui' import validator from '@rjsf/validator-ajv8' import { listSchemas, getSchema, readConfig, writeConfig } from '../services/api.js' import { widgets } from '../components/rjsf/widgets.jsx' @@ -154,7 +154,6 @@ export default function ConfigPage() { validator={validator} onSubmit={handleSave} onChange={({ formData }) => setFormData(formData)} - widgets={widgets} uiSchema={uiSchema} >
diff --git a/frontend/src/pages/Dashboard.jsx b/frontend/src/pages/Dashboard.jsx index 55e5de7..b5f75d8 100644 --- a/frontend/src/pages/Dashboard.jsx +++ b/frontend/src/pages/Dashboard.jsx @@ -1,7 +1,6 @@ import React, { useEffect, useMemo, useRef, useState } from 'react' -import Form from '@rjsf/core' +import Form from '@rjsf/fluent-ui' import validator from '@rjsf/validator-ajv8' -import { widgets } from '../components/rjsf/widgets.jsx' import { getStatus, getEvents, @@ -223,78 +222,19 @@ export default function DashboardPage() { {statusError &&
{statusError}
} {status && } -
- -
- - {accordionOpen && ( -
+ {['plc', 'datasets', 'plots'].map((sectionId) => ( +
-
🧩 Schema:
-
- {['plc', 'datasets', 'plots'].map(id => ( - - ))} -
+
🧩 {sectionId}
- - - +
- - {message &&
{message}
} - - {schema && ( -
{ setFormData(e.formData); saveConfig() }} - onChange={({ formData }) => setFormData(formData)} - widgets={widgets} - uiSchema={uiSchema} - > -
- - )} +
- )} + ))}

📋 Recent Events

@@ -336,4 +276,98 @@ export default function DashboardPage() { ) } +function SectionControls({ sectionId }) { + const [busy, setBusy] = useState(false) + const [localData, setLocalData] = useState(null) + useEffect(() => { + ; (async () => { + try { + const res = await readConfig(sectionId) + setLocalData(res.data) + } catch { /* ignore */ } + })() + }, [sectionId]) + return ( +
+ + + +
+ ) +} + +function SectionForm({ sectionId }) { + const [localSchema, setLocalSchema] = useState(null) + const [localUi, setLocalUi] = useState(null) + const [localData, setLocalData] = useState(null) + const [loading, setLoading] = useState(true) + const [saving, setSaving] = useState(false) + + useEffect(() => { + let mounted = true + ; (async () => { + setLoading(true) + try { + const [schemaResp, dataResp] = await Promise.all([ + getSchema(sectionId), + readConfig(sectionId), + ]) + if (!mounted) return + setLocalSchema(schemaResp.schema) + setLocalUi(schemaResp.ui_schema || buildUiSchema(schemaResp.schema)) + setLocalData(dataResp.data) + } finally { + if (mounted) setLoading(false) + } + })() + return () => { mounted = false } + }, [sectionId]) + + if (loading || !localSchema) return
Loading {sectionId}…
+ + return ( +
setLocalData(formData)} + onSubmit={async ({ formData }) => { + setSaving(true) + try { await writeConfig(sectionId, formData) } finally { setSaving(false) } + }} + uiSchema={localUi} + > +
+ + ) +} + diff --git a/plc_config.json b/plc_config.json deleted file mode 100644 index 755cc45..0000000 --- a/plc_config.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "plc_config": { - "ip": "10.1.33.11", - "rack": 0, - "slot": 2 - }, - "udp_config": { - "host": "127.0.0.1", - "port": 9870 - }, - "sampling_interval": 0.1, - "csv_config": { - "records_directory": "records", - "rotation_enabled": true, - "max_size_mb": 1000, - "max_days": 30, - "max_hours": null, - "cleanup_interval_hours": 24, - "last_cleanup": "2025-08-09T22:43:54.224975" - } -} \ No newline at end of file diff --git a/plc_datasets.json b/plc_datasets.json deleted file mode 100644 index a39f71e..0000000 --- a/plc_datasets.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "datasets": { - "DAR": { - "name": "DAR", - "prefix": "gateway_phoenix", - "variables": { - "UR29_Brix": { - "area": "db", - "offset": 1322, - "type": "real", - "streaming": true, - "db": 1011 - }, - "UR29_ma": { - "area": "db", - "offset": 1296, - "type": "real", - "streaming": true, - "db": 1011 - }, - "fUR29_Brix": { - "area": "db", - "offset": 1322, - "type": "real", - "streaming": false, - "db": 1011 - } - }, - "streaming_variables": [ - "UR29_Brix", - "UR29_ma" - ], - "sampling_interval": 1.0, - "enabled": true, - "created": "2025-08-08T15:47:18.566053" - }, - "Fast": { - "name": "Fast", - "prefix": "fast", - "variables": { - "fUR29_Brix": { - "area": "db", - "offset": 1322, - "type": "real", - "streaming": false, - "db": 1011 - }, - "fUR29_ma": { - "area": "db", - "offset": 1296, - "type": "real", - "streaming": false, - "db": 1011 - } - }, - "streaming_variables": [], - "sampling_interval": 0.1, - "enabled": true, - "created": "2025-08-09T02:06:26.840011" - } - }, - "active_datasets": [ - "Fast", - "DAR" - ], - "current_dataset_id": "Fast", - "version": "1.0", - "last_update": "2025-08-10T01:45:12.551768" -} \ No newline at end of file diff --git a/plot_sessions.json b/plot_sessions.json deleted file mode 100644 index 177c2b7..0000000 --- a/plot_sessions.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "plots": { - "plot_1": { - "name": "UR29", - "variables": [ - "UR29_Brix", - "UR29_ma", - "fUR29_Brix", - "fUR29_ma" - ], - "time_window": 75, - "y_min": null, - "y_max": null, - "trigger_variable": null, - "trigger_enabled": false, - "trigger_on_true": true, - "session_id": "plot_1" - } - }, - "session_counter": 2, - "last_saved": "2025-08-10T00:37:46.525175", - "version": "1.0" -} \ No newline at end of file