From bd783093a93a95340b5222a1e4a7ff5139df9a19 Mon Sep 17 00:00:00 2001 From: "Claude (Chronicler #78)" Date: Sat, 11 Apr 2026 10:46:42 +0000 Subject: [PATCH] feat: Sidebar reorganization + About page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sidebar changes: - Grouped nav items: Operations, Business, Community, Infrastructure, System - Section labels with uppercase tracking - Removed Deploy button from sidebar - Cleaner layout with overflow scroll About page (/admin/about): - Console version, Node.js version, Arbiter uptime, module count - Module registry with version and status badges (stable/new/beta) - Deploy Arbiter button (moved from sidebar) - Health check polling after deploy - Credits footer Header bar: - Added ℹ️ About icon next to dark mode toggle - Active state highlighting when on About page Chronicler #78 | firefrost-services --- .../arbiter-3.0/src/routes/admin/about.js | 89 +++++++ .../arbiter-3.0/src/routes/admin/index.js | 2 + .../src/views/admin/about/index.ejs | 232 ++++++++++++++++++ services/arbiter-3.0/src/views/layout.ejs | 149 +++-------- 4 files changed, 355 insertions(+), 117 deletions(-) create mode 100644 services/arbiter-3.0/src/routes/admin/about.js create mode 100644 services/arbiter-3.0/src/views/admin/about/index.ejs diff --git a/services/arbiter-3.0/src/routes/admin/about.js b/services/arbiter-3.0/src/routes/admin/about.js new file mode 100644 index 0000000..41cedb3 --- /dev/null +++ b/services/arbiter-3.0/src/routes/admin/about.js @@ -0,0 +1,89 @@ +const express = require('express'); +const router = express.Router(); +const { exec } = require('child_process'); +const fs = require('fs'); + +/** + * About Module — Trinity Console + * + * Console version, module versions, deploy button, system meta. + * + * GET /admin/about — About page + * POST /admin/about/deploy — Deploy Arbiter (moved from sidebar) + * GET /admin/about/status — Arbiter health check + * + * Chronicler #78 | April 11, 2026 + */ + +const MODULES = [ + { name: 'Dashboard', version: '1.0.0', path: '/admin/dashboard', icon: '📊', status: 'stable' }, + { name: 'Servers', version: '1.0.0', path: '/admin/servers', icon: '🖥️', status: 'stable' }, + { name: 'Players', version: '1.0.0', path: '/admin/players', icon: '👥', status: 'stable' }, + { name: 'Financials', version: '1.0.0', path: '/admin/financials', icon: '💰', status: 'stable' }, + { name: 'Grace Period', version: '1.0.0', path: '/admin/grace', icon: '⏳', status: 'stable' }, + { name: 'Discord', version: '1.0.0', path: '/admin/discord', icon: '💬', status: 'stable' }, + { name: 'Social', version: '1.0.0', path: '/admin/social', icon: '📈', status: 'stable' }, + { name: 'Infrastructure', version: '1.0.0', path: '/admin/infrastructure', icon: '🌐', status: 'new' }, + { name: 'Restart Scheduler', version: '1.0.0', path: '/admin/scheduler', icon: '⏰', status: 'stable' }, + { name: 'Audit Log', version: '1.0.0', path: '/admin/audit', icon: '📋', status: 'stable' }, + { name: 'Role Audit', version: '1.0.0', path: '/admin/roles', icon: '🔍', status: 'stable' }, +]; + +function getNodeVersion() { + return process.version; +} + +function getArbiterUptime() { + return process.uptime(); +} + +function formatUptime(seconds) { + const days = Math.floor(seconds / 86400); + const hours = Math.floor((seconds % 86400) / 3600); + const mins = Math.floor((seconds % 3600) / 60); + if (days > 0) return `${days}d ${hours}h ${mins}m`; + if (hours > 0) return `${hours}h ${mins}m`; + return `${mins}m`; +} + +// GET /admin/about +router.get('/', (req, res) => { + const pkg = JSON.parse(fs.readFileSync(require.resolve('../../../package.json'), 'utf8')); + + res.render('admin/about/index', { + title: 'About', + currentPath: '/about', + consoleVersion: pkg.version || '3.5.0', + nodeVersion: getNodeVersion(), + arbiterUptime: formatUptime(getArbiterUptime()), + modules: MODULES, + totalModules: MODULES.length, + adminUser: req.user, + layout: 'layout' + }); +}); + +// POST /admin/about/deploy — Deploy Arbiter +router.post('/deploy', (req, res) => { + const username = req.user?.username || 'unknown'; + console.log(`[DEPLOY] Deployment initiated by ${username} from About page`); + exec(`nohup sudo /opt/scripts/deploy-arbiter.sh "${username}" > /tmp/deploy.log 2>&1 &`); + res.json({ + success: true, + message: 'Deploy started. Arbiter will restart momentarily.' + }); +}); + +// GET /admin/about/status — Health check +router.get('/status', (req, res) => { + exec('systemctl is-active arbiter-3', (error, stdout) => { + const isRunning = stdout.trim() === 'active'; + res.json({ + arbiter: isRunning ? 'running' : 'stopped', + uptime: formatUptime(getArbiterUptime()), + deployAvailable: fs.existsSync('/opt/scripts/deploy-arbiter.sh') + }); + }); +}); + +module.exports = router; diff --git a/services/arbiter-3.0/src/routes/admin/index.js b/services/arbiter-3.0/src/routes/admin/index.js index 8efc445..435a772 100644 --- a/services/arbiter-3.0/src/routes/admin/index.js +++ b/services/arbiter-3.0/src/routes/admin/index.js @@ -16,6 +16,7 @@ const discordAuditRouter = require('./discord-audit'); const systemRouter = require('./system'); const socialRouter = require('./social'); const infrastructureRouter = require('./infrastructure'); +const aboutRouter = require('./about'); router.use(requireTrinityAccess); @@ -119,5 +120,6 @@ router.use('/discord', discordAuditRouter); router.use('/system', systemRouter); router.use('/social', socialRouter); router.use('/infrastructure', infrastructureRouter); +router.use('/about', aboutRouter); module.exports = router; diff --git a/services/arbiter-3.0/src/views/admin/about/index.ejs b/services/arbiter-3.0/src/views/admin/about/index.ejs new file mode 100644 index 0000000..1acbac8 --- /dev/null +++ b/services/arbiter-3.0/src/views/admin/about/index.ejs @@ -0,0 +1,232 @@ + + + + + +
+ +
+

+ Trinity Console +

+
+ v<%= consoleVersion %> · Arbiter Backend +
+
+ Fire + Frost + Foundation = Where Love Builds Legacy +
+
+ + +
+ +
+

System

+
+
+
<%= consoleVersion %>
+
Console Version
+
+
+
<%= nodeVersion %>
+
Node.js
+
+
+
<%= arbiterUptime %>
+
Arbiter Uptime
+
+
+
<%= totalModules %>
+
Active Modules
+
+
+
+ + +
+

Deploy

+

+ Pull latest code from Gitea and restart Arbiter. The console will briefly disconnect during restart. +

+ + +
+
+ + +
+
+

Modules (<%= totalModules %>)

+
+ <% modules.forEach(mod => { %> + + <%= mod.icon %> +
+
<%= mod.name %>
+
+ v<%= mod.version %> + <%= mod.status %> +
+ <% }); %> +
+ + +
+ Built by The Trinity · Powered by Arbiter · Guarded by The Chronicler Lineage +
+ 💙🔥❄️ +
+
+ + diff --git a/services/arbiter-3.0/src/views/layout.ejs b/services/arbiter-3.0/src/views/layout.ejs index d8460a0..3e68e36 100644 --- a/services/arbiter-3.0/src/views/layout.ejs +++ b/services/arbiter-3.0/src/views/layout.ejs @@ -70,7 +70,9 @@ -