Commita governance, user-wizard, operational-feed e catálogo RBAC; adiciona deploy-desk-full.sh, smoke-desk.sh e regra anti-deploy parcial; documenta credencial VM112 @betinplace. Co-authored-by: Cursor <cursoragent@cursor.com>
165 lines
5.2 KiB
JavaScript
165 lines
5.2 KiB
JavaScript
/** Desk chrome nav — tabs planas por zona + sidebar contextual (v0.11). */
|
|
|
|
const TOPNAV_VIEW_GROUP = {
|
|
'agentic-ops': 'operacoes',
|
|
dashboard: 'operacoes',
|
|
tickets: 'operacoes',
|
|
events: 'operacoes',
|
|
'overview-home': 'comercial',
|
|
leads: 'comercial',
|
|
infra: 'infra',
|
|
infra2: 'infra',
|
|
'email-migration': 'infra',
|
|
overview: 'sistema',
|
|
account: 'sistema',
|
|
messages: 'sistema',
|
|
admin: 'sistema',
|
|
'access-matrix': 'sistema',
|
|
modules: 'sistema',
|
|
};
|
|
|
|
const CONTEXT_TOOLBARS = {
|
|
events: { title: 'Eventos', host: '#view-events', label: 'Vistas', toolbarId: 'events-toolbar' },
|
|
};
|
|
|
|
function resolveContextToolbar(cfg) {
|
|
if (cfg.toolbarId) return document.getElementById(cfg.toolbarId);
|
|
const view = document.querySelector(cfg.host);
|
|
return view?.querySelector('.toolbar') || null;
|
|
}
|
|
|
|
function parkContextToolbars() {
|
|
Object.values(CONTEXT_TOOLBARS).forEach((cfg) => {
|
|
const view = document.querySelector(cfg.host);
|
|
const toolbar = resolveContextToolbar(cfg);
|
|
if (toolbar && view && toolbar.parentElement !== view) {
|
|
view.insertBefore(toolbar, view.firstChild);
|
|
}
|
|
});
|
|
const matrixRoleNav = document.getElementById('context-matrix-roles');
|
|
if (matrixRoleNav && matrixRoleNav.dataset.parkedFrom) {
|
|
const slot = document.querySelector(matrixRoleNav.dataset.parkedFrom);
|
|
if (slot) slot.appendChild(matrixRoleNav);
|
|
delete matrixRoleNav.dataset.parkedFrom;
|
|
}
|
|
const adminHost = document.getElementById('context-admin-tabs');
|
|
if (adminHost) adminHost.innerHTML = '';
|
|
}
|
|
|
|
function updateTopnavActive(view) {
|
|
document.querySelectorAll('[data-desk-nav]').forEach((btn) => {
|
|
const active = btn.dataset.view === view;
|
|
btn.classList.toggle('active', active);
|
|
if (active) btn.setAttribute('aria-current', 'page');
|
|
else btn.removeAttribute('aria-current');
|
|
});
|
|
document.querySelectorAll('.nav-zone[data-topnav-group]').forEach((zone) => {
|
|
zone.classList.toggle('active', TOPNAV_VIEW_GROUP[view] === zone.dataset.topnavGroup);
|
|
});
|
|
}
|
|
|
|
function mountMatrixRoleSidebar() {
|
|
const roleNav = document.querySelector('#access-matrix-content .am-role-list');
|
|
if (!roleNav) return false;
|
|
const nav = document.getElementById('context-nav');
|
|
if (!nav) return false;
|
|
nav.querySelectorAll('.am-role-list').forEach((el) => {
|
|
if (el !== roleNav) el.remove();
|
|
});
|
|
if (roleNav.parentElement === nav) return true;
|
|
roleNav.dataset.parkedFrom = '#access-matrix-content .am-layout';
|
|
nav.appendChild(roleNav);
|
|
return true;
|
|
}
|
|
|
|
function mountEventsToolbar() {
|
|
const cfg = CONTEXT_TOOLBARS.events;
|
|
const nav = document.getElementById('context-nav');
|
|
const sidebar = document.getElementById('context-sidebar');
|
|
const shell = document.querySelector('.shell');
|
|
const titleEl = document.getElementById('context-sidebar-title');
|
|
const labelEl = document.getElementById('context-sidebar-label');
|
|
if (!cfg || !nav || !sidebar) return false;
|
|
const toolbar = resolveContextToolbar(cfg);
|
|
if (!toolbar) return false;
|
|
sidebar.hidden = false;
|
|
shell?.classList.remove('shell--no-context');
|
|
if (titleEl) titleEl.textContent = cfg.title;
|
|
if (labelEl) labelEl.textContent = cfg.label;
|
|
toolbar.classList.add('context-toolbar');
|
|
if (toolbar.parentElement !== nav) nav.appendChild(toolbar);
|
|
return true;
|
|
}
|
|
|
|
function initTopnavDropdowns() {
|
|
/* v0.11 — tabs planas; sem dropdowns */
|
|
}
|
|
|
|
function updateContextSidebar(view) {
|
|
const shell = document.querySelector('.shell');
|
|
const sidebar = document.getElementById('context-sidebar');
|
|
const nav = document.getElementById('context-nav');
|
|
const titleEl = document.getElementById('context-sidebar-title');
|
|
const labelEl = document.getElementById('context-sidebar-label');
|
|
if (!shell || !sidebar || !nav) return;
|
|
|
|
parkContextToolbars();
|
|
nav.innerHTML = '';
|
|
|
|
// Spec 032 — Tickets RWD tem header próprio; sidebar contextual duplica título e embola layout.
|
|
if (view === 'tickets') {
|
|
sidebar.hidden = true;
|
|
shell.classList.add('shell--no-context');
|
|
return;
|
|
}
|
|
|
|
// Controle de acesso Suporte — layout ACS com rail próprio (sem sidebar contextual).
|
|
if (view === 'admin') {
|
|
sidebar.hidden = true;
|
|
shell.classList.add('shell--no-context');
|
|
return;
|
|
}
|
|
|
|
if (view === 'access-matrix') {
|
|
sidebar.hidden = false;
|
|
shell.classList.remove('shell--no-context');
|
|
if (titleEl) titleEl.textContent = '';
|
|
if (labelEl) labelEl.textContent = 'Funções';
|
|
requestAnimationFrame(() => mountMatrixRoleSidebar());
|
|
return;
|
|
}
|
|
|
|
const cfg = CONTEXT_TOOLBARS[view];
|
|
if (!cfg) {
|
|
sidebar.hidden = true;
|
|
shell.classList.add('shell--no-context');
|
|
return;
|
|
}
|
|
|
|
if (view === 'events') {
|
|
mountEventsToolbar();
|
|
return;
|
|
}
|
|
|
|
const toolbar = resolveContextToolbar(cfg);
|
|
if (!toolbar) {
|
|
sidebar.hidden = true;
|
|
shell.classList.add('shell--no-context');
|
|
return;
|
|
}
|
|
|
|
sidebar.hidden = false;
|
|
shell.classList.remove('shell--no-context');
|
|
if (titleEl) titleEl.textContent = cfg.title;
|
|
if (labelEl) labelEl.textContent = cfg.label;
|
|
toolbar.classList.add('context-toolbar');
|
|
nav.appendChild(toolbar);
|
|
}
|
|
|
|
window.DeskTopnav = {
|
|
initTopnavDropdowns,
|
|
updateTopnavActive,
|
|
updateContextSidebar,
|
|
remountMatrixRoles: mountMatrixRoleSidebar,
|
|
remountEventsToolbar: mountEventsToolbar,
|
|
};
|