add more plugin options + don't inject in HVNC if DXGI is set to off.
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
||||
import { mountNav } from "./nav/template.js";
|
||||
import { createAdaptiveNavController } from "./nav/layout.js";
|
||||
import { applyUserRoleUI } from "./nav/role-ui.js";
|
||||
import { loadPluginNavItems } from "./nav/plugins-loader.js";
|
||||
|
||||
const host = document.getElementById("top-nav");
|
||||
if (host) {
|
||||
@@ -38,23 +39,27 @@ if (host) {
|
||||
"/file-share": "file-share-link",
|
||||
"/purgatory": "enrollment-link",
|
||||
};
|
||||
const activeId = activeMap[path];
|
||||
if (activeId) {
|
||||
const el = document.getElementById(activeId);
|
||||
if (el) {
|
||||
el.classList.add("nav-active");
|
||||
// Also expand the parent sidebar group if applicable
|
||||
const group = el.closest(".sb-group");
|
||||
if (group) {
|
||||
const btn = group.querySelector(".sb-group-btn");
|
||||
const children = group.querySelector(".sb-group-children");
|
||||
const chevron = btn?.querySelector(".sb-chevron");
|
||||
if (btn) btn.setAttribute("aria-expanded", "true");
|
||||
if (children) children.classList.add("sb-group-open");
|
||||
if (chevron) chevron.classList.add("sb-chevron-open");
|
||||
|
||||
loadPluginNavItems(activeMap).then(() => {
|
||||
const activeId = activeMap[path];
|
||||
if (activeId) {
|
||||
const el = document.getElementById(activeId);
|
||||
if (el) {
|
||||
el.classList.add("nav-active");
|
||||
// Also expand the parent sidebar group if applicable
|
||||
const group = el.closest(".sb-group");
|
||||
if (group) {
|
||||
const btn = group.querySelector(".sb-group-btn");
|
||||
const children = group.querySelector(".sb-group-children");
|
||||
const chevron = btn?.querySelector(".sb-chevron");
|
||||
if (btn) btn.setAttribute("aria-expanded", "true");
|
||||
if (children) children.classList.add("sb-group-open");
|
||||
if (chevron) chevron.classList.add("sb-chevron-open");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (refs.logoutBtn && !refs.logoutBtn.dataset.boundLogout) {
|
||||
refs.logoutBtn.dataset.boundLogout = "true";
|
||||
refs.logoutBtn.addEventListener("click", async () => {
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import { dropdownItem, sidebarChild } from "./template.js";
|
||||
|
||||
export async function loadPluginNavItems(activeMap) {
|
||||
try {
|
||||
const res = await fetch("/api/plugins");
|
||||
if (!res.ok) return;
|
||||
|
||||
const data = await res.json();
|
||||
const plugins = data.plugins;
|
||||
if (!plugins || !Array.isArray(plugins)) return;
|
||||
|
||||
const navPlugins = plugins.filter(
|
||||
(p) => p.navbar && p.enabled
|
||||
);
|
||||
|
||||
if (navPlugins.length === 0) return;
|
||||
|
||||
const isSidebar = document.querySelector(".sb-group[data-group='plugin_apps']");
|
||||
const wg = document.querySelector(".nav-dd-wrapper[data-group='plugin_apps']");
|
||||
const container = isSidebar ? document.querySelector(".sb-group[data-group='plugin_apps']") : wg;
|
||||
|
||||
if (!container) return;
|
||||
|
||||
const childContainer = isSidebar
|
||||
? container.querySelector(".sb-group-children")
|
||||
: container.querySelector(".nav-dd-menu");
|
||||
|
||||
if (!childContainer) return;
|
||||
|
||||
const itemsHtml = navPlugins.map((p) => {
|
||||
const linkId = `plugin-nav-${p.id}`;
|
||||
activeMap[`/plugins/${p.id}`] = linkId;
|
||||
|
||||
const childObj = {
|
||||
href: `/plugins/${p.id}`,
|
||||
label: p.navbar.label || p.name,
|
||||
icon: p.navbar.icon || "fa-cube",
|
||||
iconColor: "text-slate-300",
|
||||
linkId: linkId,
|
||||
};
|
||||
|
||||
return isSidebar ? sidebarChild(childObj) : dropdownItem(childObj);
|
||||
}).join("");
|
||||
|
||||
childContainer.innerHTML = itemsHtml;
|
||||
container.classList.remove("hidden");
|
||||
|
||||
} catch (err) {
|
||||
console.error("Failed to load plugin nav items", err);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ export const NAV_MODE_KEY = "sb_mode";
|
||||
NAVIGATION DATA — single source of truth
|
||||
────────────────────────────────────────────── */
|
||||
|
||||
const NAV_GROUPS = [
|
||||
export const NAV_GROUPS = [
|
||||
{
|
||||
id: "clients",
|
||||
label: "Clients",
|
||||
@@ -65,13 +65,21 @@ const NAV_GROUPS = [
|
||||
{ href: "/metrics", label: "Metrics", icon: "fa-chart-line", iconColor: "text-emerald-400", linkId: "metrics-link" },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "plugin_apps",
|
||||
label: "Plugin Apps",
|
||||
icon: "fa-plug",
|
||||
iconColor: "text-fuchsia-400",
|
||||
hidden: true,
|
||||
children: [],
|
||||
}
|
||||
];
|
||||
|
||||
/* ──────────────────────────────────────────────
|
||||
TOPBAR — dropdown menus
|
||||
────────────────────────────────────────────── */
|
||||
|
||||
function dropdownItem(child) {
|
||||
export function dropdownItem(child) {
|
||||
const hiddenCls = child.hidden ? " hidden" : "";
|
||||
const badgeHtml = child.hasBadge
|
||||
? `<span id="enrollment-badge" class="nav-dd-badge hidden"></span>`
|
||||
@@ -100,8 +108,9 @@ function dropdownGroup(group) {
|
||||
}
|
||||
// Dropdown group — wrapper always visible, children control visibility
|
||||
const items = group.children.map(dropdownItem).join("");
|
||||
const groupHidden = group.hidden ? " hidden" : "";
|
||||
return `
|
||||
<div class="nav-dd-wrapper" data-group="${group.id}">
|
||||
<div class="nav-dd-wrapper${groupHidden}" data-group="${group.id}">
|
||||
<button class="nav-dd-group-btn" data-group="${group.id}" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="fa-solid ${group.icon} ${group.iconColor}"></i>
|
||||
<span>${group.label}</span>
|
||||
@@ -217,7 +226,7 @@ function mountTopbar(host) {
|
||||
SIDEBAR — tree-style expandable
|
||||
────────────────────────────────────────────── */
|
||||
|
||||
function sidebarChild(child) {
|
||||
export function sidebarChild(child) {
|
||||
const hiddenCls = child.hidden ? " hidden" : "";
|
||||
const badgeHtml = child.hasBadge
|
||||
? `<span id="enrollment-badge" class="sb-badge hidden"></span>`
|
||||
@@ -246,8 +255,9 @@ function sidebarGroup(group) {
|
||||
}
|
||||
// Expandable group — wrapper always visible, children control visibility
|
||||
const childrenHtml = group.children.map(sidebarChild).join("");
|
||||
const groupHidden = group.hidden ? " hidden" : "";
|
||||
return `
|
||||
<div class="sb-group" data-group="${group.id}">
|
||||
<div class="sb-group${groupHidden}" data-group="${group.id}">
|
||||
<button class="sb-group-btn" data-group="${group.id}" aria-expanded="false">
|
||||
<i class="fa-solid ${group.icon} ${group.iconColor} sb-icon"></i>
|
||||
<span class="sb-text">${group.label}</span>
|
||||
|
||||
Reference in New Issue
Block a user