From bd0e16975706dd1bc1a3e5f33ccabcb13658e2ff Mon Sep 17 00:00:00 2001 From: Miguel Date: Thu, 14 Aug 2025 21:39:27 +0200 Subject: [PATCH] feat: Migrate Chart.js libraries to npm for offline usage and update application setup --- OFFLINE_USAGE.md | 107 +++++++++++++++++++ application_events.json | 177 ++++++++++++++++++++++++++++++- frontend/index.html | 7 +- frontend/package.json | 5 + frontend/src/main.jsx | 3 + frontend/src/utils/chartSetup.js | 58 ++++++++++ system_state.json | 6 +- 7 files changed, 352 insertions(+), 11 deletions(-) create mode 100644 OFFLINE_USAGE.md create mode 100644 frontend/src/utils/chartSetup.js diff --git a/OFFLINE_USAGE.md b/OFFLINE_USAGE.md new file mode 100644 index 0000000..2fcac56 --- /dev/null +++ b/OFFLINE_USAGE.md @@ -0,0 +1,107 @@ +# Offline Usage Configuration + +## Overview +The application has been configured to work completely offline without any CDN dependencies. + +## Changes Made + +### 1. Chart.js Libraries Migration +**Before (CDN Dependencies):** +- Chart.js loaded from `https://cdn.jsdelivr.net/npm/chart.js@3.9.1` +- Luxon from `https://cdn.jsdelivr.net/npm/luxon@2` +- Chart.js adapter from `https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon@1.3.1` +- Zoom plugin from `https://unpkg.com/chartjs-plugin-zoom@1.2.1` +- Streaming plugin from `https://cdn.jsdelivr.net/npm/chartjs-plugin-streaming@2.0.0` + +**After (NPM Dependencies):** +All Chart.js libraries are now installed as npm packages and bundled with the application: +```json +"chart.js": "^3.9.1", +"chartjs-adapter-luxon": "^1.3.1", +"chartjs-plugin-streaming": "^2.0.0", +"chartjs-plugin-zoom": "^1.2.1", +"luxon": "^2.5.2" +``` + +### 2. Chart.js Setup Module +Created `frontend/src/utils/chartSetup.js` that: +- Imports all Chart.js components as ES modules +- Registers all required plugins (zoom, streaming, time scales) +- Makes Chart.js available globally for existing components +- Provides console confirmation of successful setup + +### 3. Application Entry Point +Modified `frontend/src/main.jsx` to import the Chart.js setup before rendering the application. + +### 4. Updated HTML Template +Removed all CDN script tags from `frontend/index.html`. + +## Verification + +### Build Verification +The application builds successfully without any external dependencies: +```bash +cd frontend +npm run build +``` + +### Development Server +The development server runs without internet connection: +```bash +cd frontend +npm run dev +``` + +### Runtime Verification +- No network requests to external CDNs +- All Chart.js functionality preserved (zooming, streaming, real-time plots) +- Completely self-contained in bundled JavaScript + +## Backend Offline Compliance + +The Python backend already uses only local dependencies: +- Flask for web server +- python-snap7 for PLC communication +- Local file-based configuration +- No external API calls or services + +## Deployment for Offline Use + +### Frontend Production Build +```bash +cd frontend +npm run build +``` +The `dist/` folder contains all necessary files with no external dependencies. + +### Complete Offline Package +The entire application (backend + frontend) can be deployed on systems without internet access: + +1. **Python Requirements**: Install from `requirements.txt` +2. **Frontend**: Use built files from `dist/` folder +3. **PLC Communication**: Requires `snap7.dll` in system PATH +4. **Configuration**: All JSON-based, stored locally + +## Chart.js Feature Compatibility + +All existing Chart.js features remain functional: +- ✅ Real-time streaming plots +- ✅ Zoom and pan functionality +- ✅ Time-based X-axis with Luxon adapter +- ✅ Multiple dataset support +- ✅ Dynamic color assignment +- ✅ Plot session management +- ✅ CSV data export integration + +## Technical Notes + +### Global vs ES Module Access +The setup maintains backward compatibility by making Chart.js available both ways: +- **Global**: `window.Chart` (for existing components) +- **ES Module**: `import ChartJS from './utils/chartSetup.js'` (for new components) + +### Bundle Size Impact +The Chart.js libraries add approximately ~400KB to the bundle (gzipped), which is acceptable for offline industrial applications. + +### Browser Compatibility +All dependencies support modern browsers without requiring polyfills for the target deployment environment. diff --git a/application_events.json b/application_events.json index 299ba0b..d783e96 100644 --- a/application_events.json +++ b/application_events.json @@ -1309,8 +1309,181 @@ "udp_port": 9870, "datasets_available": 3 } + }, + { + "timestamp": "2025-08-14T18:43:38.226776", + "level": "info", + "event_type": "application_started", + "message": "Application initialization completed successfully", + "details": {} + }, + { + "timestamp": "2025-08-14T18:43:38.387187", + "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-14T18:43:38.390197", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: Fast", + "details": { + "dataset_id": "Fast", + "variables_count": 1, + "streaming_count": 1, + "prefix": "fast" + } + }, + { + "timestamp": "2025-08-14T18:43:38.393188", + "level": "info", + "event_type": "csv_recording_started", + "message": "CSV recording started: 2 datasets activated", + "details": { + "activated_datasets": 2, + "total_datasets": 3 + } + }, + { + "timestamp": "2025-08-14T18:43:38.396188", + "level": "info", + "event_type": "udp_streaming_started", + "message": "UDP streaming to PlotJuggler started", + "details": { + "udp_host": "127.0.0.1", + "udp_port": 9870, + "datasets_available": 3 + } + }, + { + "timestamp": "2025-08-14T18:45:55.386410", + "level": "info", + "event_type": "application_started", + "message": "Application initialization completed successfully", + "details": {} + }, + { + "timestamp": "2025-08-14T18:45:55.480823", + "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-14T18:45:55.484826", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: Fast", + "details": { + "dataset_id": "Fast", + "variables_count": 1, + "streaming_count": 1, + "prefix": "fast" + } + }, + { + "timestamp": "2025-08-14T18:45:55.486826", + "level": "info", + "event_type": "csv_recording_started", + "message": "CSV recording started: 2 datasets activated", + "details": { + "activated_datasets": 2, + "total_datasets": 3 + } + }, + { + "timestamp": "2025-08-14T18:45:55.488826", + "level": "info", + "event_type": "udp_streaming_started", + "message": "UDP streaming to PlotJuggler started", + "details": { + "udp_host": "127.0.0.1", + "udp_port": 9870, + "datasets_available": 3 + } + }, + { + "timestamp": "2025-08-14T18:46:16.497318", + "level": "info", + "event_type": "application_started", + "message": "Application initialization completed successfully", + "details": {} + }, + { + "timestamp": "2025-08-14T18:46:16.610938", + "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-14T18:46:16.613936", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: Fast", + "details": { + "dataset_id": "Fast", + "variables_count": 1, + "streaming_count": 1, + "prefix": "fast" + } + }, + { + "timestamp": "2025-08-14T18:46:16.616946", + "level": "info", + "event_type": "csv_recording_started", + "message": "CSV recording started: 2 datasets activated", + "details": { + "activated_datasets": 2, + "total_datasets": 3 + } + }, + { + "timestamp": "2025-08-14T18:46:16.620459", + "level": "info", + "event_type": "udp_streaming_started", + "message": "UDP streaming to PlotJuggler started", + "details": { + "udp_host": "127.0.0.1", + "udp_port": 9870, + "datasets_available": 3 + } + }, + { + "timestamp": "2025-08-14T18:46:27.723966", + "level": "info", + "event_type": "plot_session_created", + "message": "Plot session 'UR29' created and started", + "details": { + "session_id": "plot_1", + "variables": [ + "UR29_Brix", + "UR29_ma", + "AUX Blink_1.0S" + ], + "time_window": 20, + "trigger_variable": null, + "auto_started": true + } } ], - "last_updated": "2025-08-14T18:32:34.863727", - "total_entries": 138 + "last_updated": "2025-08-14T18:46:27.723966", + "total_entries": 154 } \ No newline at end of file diff --git a/frontend/index.html b/frontend/index.html index c2c9d9e..9849388 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -12,12 +12,7 @@
- - - - - - + diff --git a/frontend/package.json b/frontend/package.json index 34ec330..1b3c722 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -15,7 +15,12 @@ "@rjsf/chakra-ui": "^5.24.12", "@rjsf/core": "^5.24.12", "@rjsf/validator-ajv8": "^5.24.12", + "chart.js": "^3.9.1", + "chartjs-adapter-luxon": "^1.3.1", + "chartjs-plugin-streaming": "^2.0.0", + "chartjs-plugin-zoom": "^1.2.1", "framer-motion": "^11.2.12", + "luxon": "^2.5.2", "react": "^18.2.0", "react-dom": "^18.2.0", "react-icons": "^5.5.0", diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx index 02e5907..1af595c 100644 --- a/frontend/src/main.jsx +++ b/frontend/src/main.jsx @@ -5,6 +5,9 @@ import { BrowserRouter } from 'react-router-dom' import { ChakraProvider, ColorModeScript } from '@chakra-ui/react' import theme from './theme.js' +// Initialize Chart.js for offline usage +import './utils/chartSetup.js' + createRoot(document.getElementById('root')).render( diff --git a/frontend/src/utils/chartSetup.js b/frontend/src/utils/chartSetup.js new file mode 100644 index 0000000..4fe7393 --- /dev/null +++ b/frontend/src/utils/chartSetup.js @@ -0,0 +1,58 @@ +/** + * Chart.js Setup for Offline Usage + * Replaces CDN dependencies with npm modules + */ + +// Import Chart.js and all required plugins +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + PointElement, + LineElement, + LineController, + BarController, + BarElement, + Title, + Tooltip, + Legend, + TimeScale, + TimeSeriesScale, + Filler +} from 'chart.js'; + +// Import time adapter +import 'chartjs-adapter-luxon'; + +// Import plugins +import zoomPlugin from 'chartjs-plugin-zoom'; +import streamingPlugin from 'chartjs-plugin-streaming'; + +// Register all Chart.js components +ChartJS.register( + CategoryScale, + LinearScale, + PointElement, + LineElement, + LineController, + BarController, + BarElement, + Title, + Tooltip, + Legend, + TimeScale, + TimeSeriesScale, + Filler, + zoomPlugin, + streamingPlugin +); + +// Make Chart.js available globally for existing components +window.Chart = ChartJS; + +// Export for ES module usage +export default ChartJS; +export { ChartJS }; + +// Initialize Chart.js setup +console.log('📊 Chart.js setup complete - all plugins registered'); diff --git a/system_state.json b/system_state.json index c072574..68d7f21 100644 --- a/system_state.json +++ b/system_state.json @@ -4,10 +4,10 @@ "should_stream": true, "active_datasets": [ "Test", - "DAR", - "Fast" + "Fast", + "DAR" ] }, "auto_recovery_enabled": true, - "last_update": "2025-08-14T18:32:34.865706" + "last_update": "2025-08-14T18:46:16.622461" } \ No newline at end of file