From c561a0095438ad964aeb584f1471a567f7870460 Mon Sep 17 00:00:00 2001 From: Romein van Buren Date: Mon, 11 Jul 2022 11:20:44 +0200 Subject: [PATCH] Basic dashboard Signed-off-by: Romein van Buren --- builddashboard.js => dashboard/build.js | 16 +++++- dashboard/socket.js | 72 +++++++++++++++++++++++++ gui/dashboard/app.svelte | 63 +++++++++++++++++++++- gui/dashboard/tile-rawvalue.svelte | 29 ++++++++++ gui/dashboard/tile.svelte | 29 ++++++---- index.js | 51 +++++++++++------- package.json | 1 + 7 files changed, 230 insertions(+), 31 deletions(-) rename builddashboard.js => dashboard/build.js (73%) create mode 100644 dashboard/socket.js create mode 100644 gui/dashboard/tile-rawvalue.svelte diff --git a/builddashboard.js b/dashboard/build.js similarity index 73% rename from builddashboard.js rename to dashboard/build.js index 15ef7a7..04608ad 100644 --- a/builddashboard.js +++ b/dashboard/build.js @@ -4,16 +4,20 @@ const { minify: minifyCSS } = require('csso'); const { rollup } = require('rollup'); const commonjs = require('@rollup/plugin-commonjs'); const css = require('rollup-plugin-css-only'); +const replace = require('@rollup/plugin-replace'); const { default: resolve } = require('@rollup/plugin-node-resolve'); const svelte = require('rollup-plugin-svelte'); const { terser } = require('rollup-plugin-terser'); -async function build() { +async function build(server) { + const serverDomain = server.settings.domain || 'localhost'; + const serverPort = server.settings.port || 80; + const serverBase = `${serverDomain}:${serverPort}`; let cssOutput = ''; try { const bundle = await rollup({ - input: __dirname + '/gui/dashboard/index.js', + input: __dirname + '/../gui/dashboard/index.js', plugins: [ // Svelte svelte({ @@ -39,6 +43,14 @@ async function build() { // Minify terser(), + + // Replace env vars + replace({ + preventAssignment: false, + values: { + '__SERVER__': serverBase, + }, + }), ], }); diff --git a/dashboard/socket.js b/dashboard/socket.js new file mode 100644 index 0000000..88ed900 --- /dev/null +++ b/dashboard/socket.js @@ -0,0 +1,72 @@ +'use strict'; + +const { makeId } = require('core/makeid'); + +const decoder = new TextDecoder('utf-8'); +let uws; + +async function createDashboardSocket(server) { + uws = server.ws({ + route: '/statusdashboard/socket', + onOpen: async ws => { + function sendTime() { + ws.send(JSON.stringify({ + cmd: 'time', + time: new Date().getTime(), + })); + } + + sendTime(); + setInterval(sendTime, 5000); + + async function sendStatuses() { + const services = await server.storage + .store('smartyellow/webservice') + .find() + .toArray(); + const heartbeats = await server.storage + .store('smartyellow/webserviceheartbeat') + .find({ webservice: { $in: services.map(s => s.id) } }) + .sort({ date: -1 }) + .toArray(); + const mappedServices = {}; + + for (const s of services) { + const lastBeat = heartbeats.find(h => h.webservice === s.id); + mappedServices[s.id] = { + name: s.name, + lastBeat: lastBeat, + }; + } + + ws.send(JSON.stringify({ + cmd: 'data', + data: mappedServices, + })); + } + + sendStatuses(); + setInterval(sendStatuses, 5000); + }, + onUpgrade: async () => ({ id: makeId(10) }), + onMessage: async (ws, msg) => { + msg = JSON.parse(decoder.decode(msg)); + console.log('msg', msg); + + if (!msg || !msg.command) { + return; + } + + switch (msg.command) { + case 'data': + ws.send('data'); + return; + + default: + return; + } + }, + }); +} + +module.exports = createDashboardSocket; diff --git a/gui/dashboard/app.svelte b/gui/dashboard/app.svelte index 8a1636f..c92e58b 100644 --- a/gui/dashboard/app.svelte +++ b/gui/dashboard/app.svelte @@ -1,19 +1,69 @@
+
+ + {#if !loading} + {#each Object.entries(services) as [ id, service ] (id)} + {@const isDown = service.lastBeat.down} + + {/each} + {:else} + loading + {/if} +
diff --git a/gui/dashboard/tile-rawvalue.svelte b/gui/dashboard/tile-rawvalue.svelte new file mode 100644 index 0000000..0df918c --- /dev/null +++ b/gui/dashboard/tile-rawvalue.svelte @@ -0,0 +1,29 @@ + + + +
+ {value} +
+
+ + diff --git a/gui/dashboard/tile.svelte b/gui/dashboard/tile.svelte index 36d1306..3b81204 100644 --- a/gui/dashboard/tile.svelte +++ b/gui/dashboard/tile.svelte @@ -4,27 +4,38 @@
- {#if title} -
{title}
+ {#if title || subtitle} +
+ {#if title} +
{title}
+ {/if} + + {#if subtitle} +
{subtitle}
+ {/if} +
{/if} - {#if subtitle} -
{subtitle}
- {/if} +
diff --git a/index.js b/index.js index d04fc59..50b71b6 100644 --- a/index.js +++ b/index.js @@ -2,7 +2,8 @@ const { fork } = require('child_process'); const { processOutage } = require('./lib/processoutage'); -const buildDashboard = require('./builddashboard'); +const buildDashboard = require('./dashboard/build'); +const createDashboardSocket = require('./dashboard/socket'); const { minifyHtml } = require('core/strings'); const guiCluster = 'web service status'; @@ -210,6 +211,15 @@ module.exports = { ], hooks: ({ server, settings }) => [ + { id: 'startDashboardSocket', + event: 'boot', + order: 100, + purpose: 'Start the websocket for the dashboard after server has booted', + handler: async ({ server }) => { + createDashboardSocket(server); + }, + }, + { id: 'autotestOnSave', order: 500, event: 'saveEntity', @@ -535,24 +545,29 @@ module.exports = { { route: '/statusdashboard', method: 'get', handler: async (req, res) => { - if (!renderedDashboard) { - renderedDashboard = await buildDashboard(); + try { + if (!renderedDashboard) { + renderedDashboard = await buildDashboard(server); + } + const dashboardHtml = minifyHtml(` + + + + + + + Web service status dashboard + + + + + + `); + res.send(dashboardHtml); + } + catch (error) { + server.error('could not compile web service status dashboard', error); } - const dashboardHtml = minifyHtml(` - - - - - - - Web service status dashboard - - - - - - `); - res.send(dashboardHtml); }, }, diff --git a/package.json b/package.json index 6af96d3..4f7c72d 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ }, "homepage": "https://github.com/smartyellow/status#readme", "dependencies": { + "@rollup/plugin-replace": "^4.0.0", "csso": "^5.0.3", "rollup-plugin-css-only": "^3.1.0" }