From 1bbf593232e80f45b80508962c6355a145602c62 Mon Sep 17 00:00:00 2001 From: William Mantly Date: Tue, 4 Aug 2026 13:26:36 -0400 Subject: [PATCH] feat: error page, admin-only DNS page, navbar active styling (v1.33.0) - Add SSO-style error page (views/error.ejs) and render it for browser navigation in the error handler (API still returns JSON). - DNS page admin-only: forceLogin(['admin']) + nav groups ['admin']. - Navbar: username not underlined; only the active nav link is bold+underlined. Co-Authored-By: Claude --- CHANGELOG.md | 5 +++++ nodejs/app.js | 15 +++++++++++++++ nodejs/public/css/styles.css | 6 ++++++ nodejs/utils/ui.js | 2 +- nodejs/views/dns.ejs | 4 ++-- nodejs/views/error.ejs | 25 +++++++++++++++++++++++++ nodejs/views/top.ejs | 2 +- 7 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 nodejs/views/error.ejs diff --git a/CHANGELOG.md b/CHANGELOG.md index 367e1ef..da6dc99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## v1.33.0 +- feat: Add SSO-style error page (404/500) for browser navigation instead of a bare JSON/text response +- feat: DNS page is now admin-only (hidden from non-admins; API already admin-gated) +- feat: navbar — username no longer underlined; only the active link is bold + underlined + ## v1.13.3 - fix: remove missing DEPLOYMENT.md and docs/ from Docker build context diff --git a/nodejs/app.js b/nodejs/app.js index 1652b01..2564865 100755 --- a/nodejs/app.js +++ b/nodejs/app.js @@ -21,6 +21,8 @@ module.exports = app; // Hold onto the auth middleware const middleware = require('./middleware/auth'); +const conf = require('@simpleworkjs/conf'); +const buildInfo = require('./utils/build_info'); // Grab the projects PubSub app.contoller = require('./controller'); @@ -115,6 +117,19 @@ app.use(async function(err, req, res, next) { res.status(status); // Only expose safe, non-internal fields to the client. const body = { name: err.name, message: err.message }; + // Browser navigation gets the HTML error page (shared with SSO); API + // clients get JSON. + if (req.accepts('html') && !req.originalUrl.startsWith('/api/')) { + res.render('error', { + title: conf.environment !== 'production' ? 'dev' : '', + titleIcon: conf.environment !== 'production' ? '' : '', + name: conf.name, + logo: conf.logo, + ...buildInfo, + error: err, + }); + return; + } res.json(body); }catch(error){ console.error('error in the catch-all error handler', error); diff --git a/nodejs/public/css/styles.css b/nodejs/public/css/styles.css index 7065eae..fd0dde2 100755 --- a/nodejs/public/css/styles.css +++ b/nodejs/public/css/styles.css @@ -3,6 +3,12 @@ nav.navbar{ padding-right: 1em; } +/* Only the active top-nav link is bold + underlined; the username is plain. */ +.top-nav a.active{ + font-weight: bold; + text-decoration: underline; +} + body { display: flex; flex-direction: column; diff --git a/nodejs/utils/ui.js b/nodejs/utils/ui.js index 8197992..5093d60 100644 --- a/nodejs/utils/ui.js +++ b/nodejs/utils/ui.js @@ -37,7 +37,7 @@ module.exports = { // in (plus the synthetic `admin` group when user/me reports isAdmin). nav: [ {href: '/hosts', icon: 'fa-solid fa-network-wired', label: 'Hosts', groups: []}, - {href: '/dns', icon: 'fa-solid fa-record-vinyl', label: 'DNS', groups: []}, + {href: '/dns', icon: 'fa-solid fa-record-vinyl', label: 'DNS', groups: ['admin']}, {href: '/permissions', icon: 'fa-solid fa-user-shield', label: 'Permissions', groups: ['admin']}, {href: '/groups', icon: 'fa-solid fa-users-gear', label: 'Groups', groups: ['admin']}, ], diff --git a/nodejs/views/dns.ejs b/nodejs/views/dns.ejs index 4cfeab1..f4b0803 100644 --- a/nodejs/views/dns.ejs +++ b/nodejs/views/dns.ejs @@ -1,7 +1,7 @@ <%- include('top') %>