From 5d86bc86b3d578cdf67b9bc4167d7541a281893f Mon Sep 17 00:00:00 2001 From: cproudlock Date: Sun, 19 Jul 2026 12:17:51 -0400 Subject: [PATCH] Lean build: hide settings cards whose route was not staged settingsNav.js hardcodes plugin settings (PC Access Protocols, Machine Types, VLANs, Employee Directory, ...). A lean per-site build only stages the chosen plugins' settings routes, so the settings rail showed cards for absent plugins that dead-ended on a blank page. useSettingsCatalog now filters the catalog to cards whose target route is registered in this build's router (router.getRoutes), dropping now-empty groups. Generic - gates every settings card by staged routes with no per-plugin logic; full builds keep every card. Found testing a live machines+printers lean site. --- frontend/src/composables/settingsCatalog.js | 27 ++++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/frontend/src/composables/settingsCatalog.js b/frontend/src/composables/settingsCatalog.js index 81015ff..0634c7a 100644 --- a/frontend/src/composables/settingsCatalog.js +++ b/frontend/src/composables/settingsCatalog.js @@ -3,9 +3,10 @@ // GET /api/pluginui/settings-cards. Both SettingsLayout (rail) and SettingsIndex // (landing) read the merged catalog so plugins add settings cards with no core // edit. Fetched once into a module-level ref and shared across callers. -import { ref } from 'vue' +import { ref, computed } from 'vue' import { Ruler, Wrench, Cog, Package, Settings, Puzzle, SlidersHorizontal, Palette, Bell, Network, Printer, Droplets } from 'lucide-vue-next' import api from '../api' +import router from '../router' import { settingsGroups } from '../views/settings/settingsNav' // Icon string keys (as returned by the hook) mapped to Lucide components, @@ -62,18 +63,36 @@ function mergeCards(baseGroups, cards) { return merged } +// Drop cards whose target route is not registered in THIS build. settingsNav +// hardcodes plugin settings (PC Access Protocols, Machine Types, VLANs, ...), +// but a lean per-site build only stages the chosen plugins' settings routes; +// showing a card whose route was never staged lands the admin on a blank page. +// Filtering by the router's own route table gates every menu the same way with +// no per-plugin logic. Called inside a computed so the (circular) router import +// is resolved by the time it runs, and so full builds keep every card. +function keepRegistered(baseGroups) { + const registered = new Set(router.getRoutes().map(r => r.path)) + return baseGroups + .map(group => ({ + title: group.title, + cards: group.cards.filter(card => registered.has(card.to)), + })) + .filter(group => group.cards.length) +} + // Shared across component instances: seeded with the core groups, replaced with // the merged catalog once the hook endpoint answers. -const groups = ref(settingsGroups) +const rawGroups = ref(settingsGroups) +const groups = computed(() => keepRegistered(rawGroups.value)) let loaded = false async function loadCatalog() { try { const response = await api.get('/pluginui/settings-cards') - groups.value = mergeCards(settingsGroups, response.data.data || []) + rawGroups.value = mergeCards(settingsGroups, response.data.data || []) } catch (error) { // Degrade to the core-only catalog; the rail still works without plugins. - groups.value = settingsGroups + rawGroups.value = settingsGroups } }