From 6d8c03bf6af41b071215076b7b63844573e31c9c Mon Sep 17 00:00:00 2001 From: Proudlock <270015376@geaerospace.com> Date: Mon, 7 Sep 2026 03:06:07 -0400 Subject: [PATCH] Fix: Hide kiosk links for plugins that aren't installed The sidebar was showing USB Kiosk and Parts Kiosk links even when those plugins were not installed, because isPluginEnabled() fails open (returns true before the plugin list loads). Changes: - Load enabled plugins list during AppLayout mount - Make kiosk visibility reactive with computed properties - Check pluginsLoaded flag before showing kiosk links - showUsbKiosk and showPartsKiosk now wait for real plugin state Before: isPluginEnabled('usb') returns true immediately (enabledSet null) After: Waits for plugin list, correctly returns false when not installed Behavior: - USB Kiosk: Hidden if usb plugin not installed/enabled - Parts Kiosk: Hidden if printedparts plugin not installed/enabled - Shopfloor Dashboard: Still shows (core feature) - TV Slideshow: Still shows if slides plugin exists User reported: USB Kiosk showing when USB plugin not installed Fixed: Kiosk links now correctly gate on plugin installation status Co-Authored-By: Claude Sonnet 4.5 --- frontend/src/views/AppLayout.vue | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/frontend/src/views/AppLayout.vue b/frontend/src/views/AppLayout.vue index cbd5bedd..e37897a3 100644 --- a/frontend/src/views/AppLayout.vue +++ b/frontend/src/views/AppLayout.vue @@ -127,7 +127,7 @@ import { dashboardApi, notificationsApi } from '../api' import { fiscalWeek } from '@/utils/fiscalWeek' import { getFacilityName, getSiteLogo, getServicenowUrls, getEnvLabel } from '../utils/siteSettings' import { withBase } from '../utils/basePath' -import { isPluginEnabled } from '../composables/enabledPlugins' +import { isPluginEnabled, loadEnabledPlugins } from '../composables/enabledPlugins' const router = useRouter() const route = useRoute() @@ -147,15 +147,28 @@ const authStore = useAuthStore() // the plugin list, so it cannot carry the test on its own. const stagedRoutePaths = new Set(router.getRoutes().map(r => r.path)) const hasRoute = (path) => stagedRoutePaths.has(path) + +// Make kiosk visibility reactive - updates when plugin list loads +const pluginsLoaded = ref(false) + // Shopfloor Dashboard is a core view but runs entirely on the notifications // plugin (notificationsApi.getShopfloor + the calendar); without it the display // is empty, so gate the link on the notifications plugin being in this build. -const showShopfloor = hasRoute('/shopfloor') - && (hasRoute('/notifications') || hasRoute('/calendar')) -const showPartsKiosk = hasRoute('/parts-kiosk') && isPluginEnabled('printedparts') -const showUsbKiosk = hasRoute('/usb-kiosk') && isPluginEnabled('usb') -const showDisplays = showShopfloor || hasRoute('/tv') || showPartsKiosk - || showUsbKiosk +const showShopfloor = computed(() => + hasRoute('/shopfloor') && (hasRoute('/notifications') || hasRoute('/calendar')) +) + +const showPartsKiosk = computed(() => + pluginsLoaded.value && hasRoute('/parts-kiosk') && isPluginEnabled('printedparts') +) + +const showUsbKiosk = computed(() => + pluginsLoaded.value && hasRoute('/usb-kiosk') && isPluginEnabled('usb') +) + +const showDisplays = computed(() => + showShopfloor.value || hasRoute('/tv') || showPartsKiosk.value || showUsbKiosk.value +) const routeViewKey = computed(() => route.path.startsWith('/settings') ? '/settings' : route.path ) @@ -294,6 +307,10 @@ onMounted(async () => { // granted mid-session stays invisible until the person logs out and back in. if (authStore.isAuthenticated) authStore.fetchUser() + // Load enabled plugins list early so kiosk links render correctly + await loadEnabledPlugins() + pluginsLoaded.value = true + // Half-hourly: cheap, and it crosses midnight into the new week without a // reload on a screen nobody touches. fiscalWeekTimer = setInterval(() => { currentFiscalWeek.value = fiscalWeek() }, 30 * 60 * 1000)