Guard unavailable appliance service links
This commit is contained in:
parent
2b03df0e3a
commit
0a2dc49314
@ -48,6 +48,14 @@
|
||||
max: 'Max',
|
||||
};
|
||||
|
||||
var SERVICE_PORTS = {
|
||||
'3001': { name: 'open-webui', label: 'Open WebUI' },
|
||||
'11434': { name: 'ollama', label: 'Ollama' },
|
||||
'8000': { name: 'chromadb', label: 'ChromaDB' },
|
||||
'8888': { name: 'jupyter', label: 'Jupyter' },
|
||||
'8080': { name: 'cezen-api', label: 'Nexus API' },
|
||||
};
|
||||
|
||||
// ── Upgrade modal (injected once into the DOM) ──────────────────────────────
|
||||
function ensureModal() {
|
||||
if (document.getElementById('cezen-upgrade-modal')) return;
|
||||
@ -80,9 +88,84 @@
|
||||
document.getElementById('cezen-upgrade-modal').classList.add('cezen-modal-open');
|
||||
}
|
||||
|
||||
function openServiceModal(label) {
|
||||
ensureModal();
|
||||
document.getElementById('cezen-upgrade-title').textContent = label + ' is not running';
|
||||
document.getElementById('cezen-upgrade-body').textContent =
|
||||
'This service is not currently available on this appliance. Check the home page service status, or ask the administrator to enable and start the service for this tier.';
|
||||
document.getElementById('cezen-upgrade-cta').style.display = 'none';
|
||||
document.getElementById('cezen-upgrade-modal').classList.add('cezen-modal-open');
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
var m = document.getElementById('cezen-upgrade-modal');
|
||||
if (m) m.classList.remove('cezen-modal-open');
|
||||
var cta = document.getElementById('cezen-upgrade-cta');
|
||||
if (cta) cta.style.display = '';
|
||||
}
|
||||
|
||||
function currentBaseForPort(port) {
|
||||
var protocol = location.protocol === 'https:' ? 'https:' : 'http:';
|
||||
var host = location.hostname || 'ai.local';
|
||||
return protocol + '//' + host + ':' + port;
|
||||
}
|
||||
|
||||
function rewriteAiLocalText(value) {
|
||||
if (!value || value.indexOf('ai.local') === -1) return value;
|
||||
return value
|
||||
.replace(/https?:\/\/ai\.local:3001/g, currentBaseForPort('3001'))
|
||||
.replace(/https?:\/\/ai\.local:11434/g, currentBaseForPort('11434'))
|
||||
.replace(/https?:\/\/ai\.local:8000/g, currentBaseForPort('8000'))
|
||||
.replace(/https?:\/\/ai\.local:8888/g, currentBaseForPort('8888'))
|
||||
.replace(/https?:\/\/ai\.local:8080/g, currentBaseForPort('8080'));
|
||||
}
|
||||
|
||||
function normalizeApplianceLinks() {
|
||||
document.querySelectorAll('a[href]').forEach(function (link) {
|
||||
var href = link.getAttribute('href') || '';
|
||||
if (href.indexOf('ai.local') !== -1) link.setAttribute('href', rewriteAiLocalText(href));
|
||||
});
|
||||
|
||||
var walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, {
|
||||
acceptNode: function (node) {
|
||||
var tag = node.parentNode && node.parentNode.tagName;
|
||||
if (tag === 'SCRIPT' || tag === 'STYLE') return NodeFilter.FILTER_REJECT;
|
||||
return node.nodeValue.indexOf('ai.local') !== -1 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
|
||||
}
|
||||
});
|
||||
var textNodes = [];
|
||||
while (walker.nextNode()) textNodes.push(walker.currentNode);
|
||||
textNodes.forEach(function (node) { node.nodeValue = rewriteAiLocalText(node.nodeValue); });
|
||||
}
|
||||
|
||||
function serviceForHref(href) {
|
||||
try {
|
||||
var u = new URL(href, location.href);
|
||||
return SERVICE_PORTS[u.port || (u.protocol === 'https:' ? '443' : '80')];
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function applyServiceAvailability() {
|
||||
fetch('/api/services', { credentials: 'include' })
|
||||
.then(function (r) { return r.ok ? r.json() : []; })
|
||||
.then(function (services) {
|
||||
var online = {};
|
||||
services.forEach(function (svc) { online[svc.name] = !!svc.ok; });
|
||||
document.querySelectorAll('a[href]').forEach(function (link) {
|
||||
var svc = serviceForHref(link.getAttribute('href') || '');
|
||||
if (!svc || online[svc.name]) return;
|
||||
if (link.classList.contains('cezen-service-unavailable')) return;
|
||||
link.classList.add('cezen-service-unavailable');
|
||||
link.setAttribute('title', svc.label + ' is not running on this appliance');
|
||||
link.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
openServiceModal(svc.label);
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(function () { /* Public pages or offline backend: leave links unchanged. */ });
|
||||
}
|
||||
|
||||
// ── Apply tier locks to all nav links ──────────────────────────────────────
|
||||
@ -129,6 +212,8 @@
|
||||
var tierSlug = b.tier_slug || 'basic';
|
||||
|
||||
ensureApplianceNavLink();
|
||||
normalizeApplianceLinks();
|
||||
applyServiceAvailability();
|
||||
|
||||
// ── Accent color CSS variable ───────────────────────────────────────────
|
||||
document.documentElement.style.setProperty('--accent', accent);
|
||||
@ -229,6 +314,19 @@
|
||||
'}',
|
||||
'a.cezen-locked:hover { opacity: 0.7; }',
|
||||
|
||||
'a.cezen-service-unavailable {',
|
||||
' opacity: 0.58;',
|
||||
' cursor: not-allowed !important;',
|
||||
'}',
|
||||
'a.cezen-service-unavailable::after {',
|
||||
' content: " offline";',
|
||||
' display: inline-block;',
|
||||
' margin-left: 6px;',
|
||||
' color: #dc2626;',
|
||||
' font-size: 0.75em;',
|
||||
' font-weight: 700;',
|
||||
'}',
|
||||
|
||||
/* Lock badge */
|
||||
'.cezen-lock-badge {',
|
||||
' font-size: 0.65em;',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user