Created
March 26, 2025 10:01
-
-
Save bitmorse/836b895d04aa44996f29bf9ec3e9c1f1 to your computer and use it in GitHub Desktop.
Revisions
-
bitmorse created this gist
Mar 26, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,169 @@ <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>OpenWRT Load Monitor</title> <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script> <script crossorigin src="https://unpkg.com/@influxdata/giraffe"></script> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <style> body { font-family: Arial, sans-serif; margin: 20px; } h1 { color: #333; } .loading { margin: 40px; font-size: 18px; color: #666; } .error { margin: 40px; font-size: 18px; color: #d32f2f; } </style> </head> <body> <h1>OpenWRT Load Monitor</h1> <main id="root"></main> <script type="text/javascript"> class PlotRenderer extends React.Component { constructor(props) { super(props); this.state = { loading: true, error: null, fluxResponse: null }; } componentDidMount() { this.fetchData(); this.refreshInterval = setInterval(() => this.fetchData(), 60000); } componentWillUnmount() { if (this.refreshInterval) { clearInterval(this.refreshInterval); } } fetchData() { const url = 'YOUR INFLUX URL'; const org = 'YOUR INFLUX ORG'; const token = 'YOUR INFLUX RO TOKEN'; //READ ONLY!!!!!! const query = ` from(bucket: "AVI") |> range(start: -24h) |> filter(fn: (r) => r._measurement == "openwrt_7628") |> filter(fn: (r) => r._field == "load") |> yield(name: "load") `; axios({ method: 'POST', url: url, headers: { 'Authorization': `Token ${token}`, 'Content-Type': 'application/json', 'Accept': 'application/csv' }, params: { org }, data: { query } }) .then(response => { console.log("Data received:", response.data); // Add the missing headers that Giraffe expects const headers = [ "#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string,string,string,string", "#group,false,false,true,true,false,false,true,true,true,true", "#default,_result,,,,,,,,," ].join("\n"); // Combine headers with the data const completeData = headers + "\n" + response.data; console.log("Complete data with headers:", completeData); this.setState({ loading: false, fluxResponse: completeData }); }) .catch(error => { console.error("Error fetching data:", error); this.setState({ loading: false, error: `Error fetching data: ${error.message}` }); }); } render() { const { loading, error, fluxResponse } = this.state; if (loading) { return React.createElement('div', { className: 'loading' }, 'Loading data...'); } if (error) { return React.createElement('div', { className: 'error' }, error); } const style = { width: "calc(70vw - 20px)", height: "calc(70vh - 20px)", margin: "40px", }; // If we have data, create a plot with it if (fluxResponse) { try { // Create a simple line layer const lineLayer = { type: "line", x: "_time", y: "_value", colors: ["#31C0F6"], lineWidth: 2 }; // Create the config using the fluxResponse with added headers const config = { fluxResponse, layers: [lineLayer] }; // Create the Plot component const Plot = React.createElement(Giraffe.Plot, {config}, null); return React.createElement('div', {style}, Plot); } catch (e) { console.error("Error creating plot:", e); return React.createElement('div', { className: 'error' }, `Error creating plot: ${e.message}. Check console for details.`); } } return React.createElement('div', null, 'No data available'); } } // Render the component ReactDOM.render( React.createElement(PlotRenderer), document.getElementById('root') ); </script> </body> </html>