- Every nav page has its own address (/tracked, /status, /devices, ...); the logo and name go to the Overview; back/forward work. - List filters gain an "Only ticked" mode; software columns get a one-click "devices with only documented apps" pick and an easiest-first sort. - Overview: the device list uses the dashboard's table header (sticky, with Excel filters); what opened it is clearly highlighted; locations colored by how much is done (red to green); stages read red / amber / green. - Details: one-line title bar; presence and monitors only in Advanced View. - Presence sweep pings only completed pairs (everything else is pinged by the sweep itself), hourly and at midnight. - Custom View scrollbar smaller, in the table header blue. - Docs: no sideways scroll in the article list; no blank lines around code.
77 lines
3.0 KiB
JavaScript
77 lines
3.0 KiB
JavaScript
/*
|
|
* USMT Dash - page routes
|
|
*
|
|
* Every page in the nav has its own address, so links, bookmarks, new tabs and the
|
|
* browser's back / forward buttons land on the right page without loading the home page
|
|
* first: / (Overview) /tracked /workbench /status /devices /custom /docs /docs/<title>
|
|
* The server answers all of these with the dashboard itself.
|
|
*/
|
|
(function () {
|
|
'use strict';
|
|
|
|
const ROUTES = {
|
|
'overview': '/',
|
|
'tracked-devices': '/tracked',
|
|
'workbench': '/workbench',
|
|
'all-devices': '/status',
|
|
'software': '/devices',
|
|
'custom': '/custom',
|
|
'docs': '/docs'
|
|
};
|
|
const ALIASES = { '/overview': 'overview', '/home': 'overview' };
|
|
|
|
function pageFor(path) {
|
|
path = (path || '/').replace(/\/+$/, '') || '/';
|
|
if (path === '/docs' || path.startsWith('/docs/')) return 'docs';
|
|
if (ALIASES[path]) return ALIASES[path];
|
|
return Object.keys(ROUTES).find(id => ROUTES[id] === path) || null;
|
|
}
|
|
const docTitle = () => (typeof currentDocTitle !== 'undefined' && currentDocTitle) ? currentDocTitle : '';
|
|
function pathFor(id) {
|
|
if (id === 'docs') {
|
|
if (location.pathname.startsWith('/docs/')) return location.pathname; // docs.js already set the article
|
|
return docTitle() ? '/docs/' + encodeURIComponent(docTitle()) : '/docs';
|
|
}
|
|
return ROUTES[id] || '/';
|
|
}
|
|
|
|
let quiet = false; // true while following the address bar (no new history entries)
|
|
function go(id) {
|
|
if (!ROUTES[id]) return;
|
|
const path = pathFor(id);
|
|
if (quiet || location.pathname === path) return;
|
|
try { history.pushState({ page: id }, '', path + location.hash); } catch (e) {}
|
|
}
|
|
|
|
function follow() {
|
|
const id = pageFor(location.pathname);
|
|
if (!id) return;
|
|
quiet = true;
|
|
try {
|
|
if (id === 'docs') {
|
|
const m = location.pathname.match(/^\/docs\/(.+)$/);
|
|
let title = null;
|
|
if (m) { try { title = decodeURIComponent(m[1]); } catch (e) {} }
|
|
if (!(title && window.KB && KB.open(title))) switchPage('docs');
|
|
} else {
|
|
switchPage(id);
|
|
}
|
|
} finally { quiet = false; }
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const orig = window.switchPage;
|
|
if (typeof orig !== 'function') return;
|
|
window.switchPage = function (id) {
|
|
const r = orig.apply(this, arguments);
|
|
go(id);
|
|
return r;
|
|
};
|
|
// Open the page in the address bar right away (articles open once the list has loaded)
|
|
const id = pageFor(location.pathname);
|
|
if (id && id !== 'overview' && id !== 'docs') { quiet = true; try { orig(id); } finally { quiet = false; } }
|
|
if (id === 'docs' && location.pathname === '/docs') { quiet = true; try { orig('docs'); } finally { quiet = false; } }
|
|
window.addEventListener('popstate', follow);
|
|
});
|
|
})();
|