diff --git a/data/manifest.json b/data/manifest.json index faa9b0b..0481efb 100755 --- a/data/manifest.json +++ b/data/manifest.json @@ -87,10 +87,10 @@ "statusTextId": "webStatus", "lastRunKey": "org_web" }, - { - "id": "emacs", - "label": "Emacs", - "badge": "Emacs", + { + "id": "emacs", + "label": "Emacs", + "badge": "Emacs", "confirmTitle": "Rerun Emacs", "confirmBody": "This will rerun Emacs. Continue?", "runLabel": "Rerun Emacs", @@ -99,11 +99,63 @@ "status": { "path": "/api/rerun-emacs/status" }, "logs": { "path": "/api/rerun-emacs/logs" }, "statusDotId": "emacsDot", - "statusTextId": "emacsStatus", - "lastRunKey": "emacs", - "successExitCodes": [0, 124] - } - ], + "statusTextId": "emacsStatus", + "lastRunKey": "emacs", + "successExitCodes": [0, 124] + }, + { + "id": "adventure_resources", + "label": "AdventureOS Resources", + "badge": "AI", + "confirmTitle": "Free AdventureOS Resources", + "confirmBody": "This will run the configured resource cleanup command. Continue?", + "runLabel": "Free resources", + "start": { "method": "POST", "path": "/api/adventure/resources/free" }, + "cancel": { "method": "DELETE", "path": "/api/adventure/resources/free" }, + "status": { "path": "/api/adventure/resources/free/status" }, + "logs": { "path": "/api/adventure/resources/free/logs" }, + "lastRunKey": "adventure_resources" + }, + { + "id": "guacamole_start", + "label": "Guacamole Start", + "badge": "RDP", + "confirmTitle": "Start Guacamole", + "confirmBody": "This will start the configured Guacamole container. Continue?", + "runLabel": "Start RDP", + "start": { "method": "POST", "path": "/api/guacamole/start" }, + "cancel": { "method": "DELETE", "path": "/api/guacamole/start" }, + "status": { "path": "/api/guacamole/start/status" }, + "logs": { "path": "/api/guacamole/start/logs" }, + "lastRunKey": "guacamole_start" + }, + { + "id": "guacamole_stop", + "label": "Guacamole Stop", + "badge": "RDP", + "confirmTitle": "Stop Guacamole", + "confirmBody": "This will stop the configured Guacamole container. Continue?", + "runLabel": "Stop RDP", + "start": { "method": "POST", "path": "/api/guacamole/stop" }, + "cancel": { "method": "DELETE", "path": "/api/guacamole/stop" }, + "status": { "path": "/api/guacamole/stop/status" }, + "logs": { "path": "/api/guacamole/stop/logs" }, + "lastRunKey": "guacamole_stop" + }, + { + "id": "nostalgia_prod", + "label": "Nostalgia Production", + "badge": "Prod", + "confirmTitle": "Run Nostalgia Production", + "confirmBody": "This will run docker compose up -d --build in the Nostalgia directory. Continue?", + "runLabel": "Run production", + "start": { "method": "POST", "path": "/api/nostalgia/production" }, + "cancel": { "method": "DELETE", "path": "/api/nostalgia/production" }, + "status": { "path": "/api/nostalgia/production/status" }, + "logs": { "path": "/api/nostalgia/production/logs" }, + "lastRunKey": "nostalgia_prod" + } + ], "status": { "health": "/api/health", "uptime": "/api/uptime", diff --git a/js/dashboard.js b/js/dashboard.js index f0e251b..8720d53 100755 --- a/js/dashboard.js +++ b/js/dashboard.js @@ -247,15 +247,48 @@ function updateWidgetCard(widget, status) { } } -function setBadge(el, text, tone) { - if (!el) return; - el.textContent = text; - el.className = `badge ${tone} widget-badge`; -} - -function renderBuilds(builds) { - const grid = document.getElementById('buildGrid'); - grid.innerHTML = ''; +function setBadge(el, text, tone) { + if (!el) return; + el.textContent = text; + el.className = `badge ${tone} widget-badge`; +} + +function safeDomId(value) { + return String(value).replace(/[^a-zA-Z0-9_-]/g, '-'); +} + +function buildDomIds(build) { + if (build.id === 'org_web') { + return { + btnId: 'buildBtn', + killId: 'killWebBtn', + resultId: 'buildResult', + logId: 'logOutput', + lastRunId: 'webLastRunMeta', + }; + } + if (build.id === 'emacs') { + return { + btnId: 'emacsBtn', + killId: 'killEmacsBtn', + resultId: 'emacsResult', + logId: 'emacsLogs', + lastRunId: 'emacsLastRunMeta', + }; + } + const id = safeDomId(build.id); + return { + btnId: `${id}Btn`, + killId: `${id}CancelBtn`, + resultId: `${id}Result`, + logId: `${id}Logs`, + lastRunId: `${id}LastRunMeta`, + }; +} + +function renderBuilds(builds) { + const grid = document.getElementById('buildGrid'); + grid.innerHTML = ''; for (const build of builds) { grid.appendChild(createBuildCard(build)); } @@ -270,15 +303,11 @@ function renderBuilds(builds) { function createBuildCard(build) { const article = document.createElement('article'); - article.className = 'panel run-card'; - article.dataset.buildId = build.id; - article.setAttribute('data-build-id', build.id); - - const btnId = build.id === 'org_web' ? 'buildBtn' : 'emacsBtn'; - const killId = build.id === 'org_web' ? 'killWebBtn' : 'killEmacsBtn'; - const resultId = build.id === 'org_web' ? 'buildResult' : 'emacsResult'; - const logId = build.id === 'org_web' ? 'logOutput' : 'emacsLogs'; - const lastRunId = build.id === 'org_web' ? 'webLastRunMeta' : 'emacsLastRunMeta'; + article.className = 'panel run-card'; + article.dataset.buildId = build.id; + article.setAttribute('data-build-id', build.id); + + const { btnId, killId, resultId, logId, lastRunId } = buildDomIds(build); article.innerHTML = `