From 85a6ab8645dcc58f5a4e5d1c173e230ca0cd2c11 Mon Sep 17 00:00:00 2001 From: cproudlock Date: Mon, 13 Jul 2026 07:41:32 -0400 Subject: [PATCH] Setup wizard: plugin display names + GE-Enforce next-steps pointer Plugins list now carries a displayname (manifest display_name, else the machine name title-cased). Adds display_name to the four whose title-case was wrong: GE-Enforce, USB, Measuring Tools, Knowledge Base. The setup wizard Features step and Settings > Plugins render it, so "Geenforce"/"Usb" are gone. Finish step shows a pointer when GE-Enforce is enabled: it still needs a scoped service token (Settings > API Tokens) and a share export root (GE-Enforce page) before the fleet uses it - operational config the wizard does not collect. frontend build green; naming green. Co-Authored-By: Claude Opus 4.8 --- frontend/src/views/SetupWizard.vue | 16 ++++++++++++++-- frontend/src/views/settings/PluginsList.vue | 2 +- plugins/geenforce/manifest.json | 1 + plugins/knowledgebase/manifest.json | 1 + plugins/measuringtools/manifest.json | 1 + plugins/usb/manifest.json | 1 + shopdb/plugins/__init__.py | 5 +++++ 7 files changed, 24 insertions(+), 3 deletions(-) diff --git a/frontend/src/views/SetupWizard.vue b/frontend/src/views/SetupWizard.vue index 37e5124..8b14206 100644 --- a/frontend/src/views/SetupWizard.vue +++ b/frontend/src/views/SetupWizard.vue @@ -41,7 +41,7 @@
@@ -140,6 +140,12 @@

All set

You can change any of this later under Settings. Finish to go to the dashboard.

+
+ GE-Enforce is on. Two more steps before the fleet + uses it: create a service token with the geenforce scopes under + Settings > API Tokens, and set the on-share export root on the + GE-Enforce page. +
@@ -235,6 +241,11 @@ function modeOf(plugin) { return key ? (pluginModes.value[key] || 'selfhosted') : null } +// GE-Enforce needs post-setup operational config (service token + share root) +// the wizard does not collect; the Finish step points there when it is on. +const geenforceEnabled = computed(() => + plugins.value.some(p => p.name === 'geenforce' && p.enabled)) + // Enabled plugins whose external connection config should be collected right // now: those in external mode (or with config but no mode concept). const configurablePlugins = computed(() => @@ -420,13 +431,14 @@ async function finish() { .form-row .form-group { flex: 1; } .plugin-list { display: flex; flex-direction: column; gap: 0.6rem; } .plugin-row { display: grid; grid-template-columns: auto auto 1fr; gap: 0.6rem; align-items: baseline; padding: 0.5rem 0.6rem; background: var(--bg); border-radius: 6px; } -.plugin-name { font-weight: 600; text-transform: capitalize; } +.plugin-name { font-weight: 600; } .plugin-desc { color: var(--text-light); font-size: 0.85rem; } .plugin-mode { margin: 0.4rem 0 0.2rem 1.9rem; } .mode-opt { display: block; font-size: 0.86rem; margin-bottom: 0.3rem; cursor: pointer; } .mode-opt input { margin-right: 0.4rem; } .plugin-mode .provision-note, .plugin-mode .config-block { margin-left: 0; } .provision-note { margin: 0.3rem 0 0.2rem 1.9rem; padding: 0.6rem 0.75rem; background: var(--bg); border-left: 3px solid var(--warning); border-radius: 4px; font-size: 0.82rem; } +.finish-note { margin: 0.75rem 0 0; padding: 0.6rem 0.75rem; background: var(--bg); border-left: 3px solid var(--primary); border-radius: 4px; font-size: 0.85rem; } .provision-note p { margin: 0 0 0.35rem; } .provision-note p:last-child { margin-bottom: 0; } .provision-tables code, .provision-docs code { background: var(--bg-card); border: 1px solid var(--border); border-radius: 3px; padding: 0 0.3rem; margin-right: 0.3rem; font-size: 0.78rem; } diff --git a/frontend/src/views/settings/PluginsList.vue b/frontend/src/views/settings/PluginsList.vue index 9ea1d25..d8d4eb8 100644 --- a/frontend/src/views/settings/PluginsList.vue +++ b/frontend/src/views/settings/PluginsList.vue @@ -24,7 +24,7 @@ - {{ p.name }} + {{ p.displayname || p.name }} {{ p.version }} {{ p.description || '-' }} diff --git a/plugins/geenforce/manifest.json b/plugins/geenforce/manifest.json index 3829823..35e50bf 100644 --- a/plugins/geenforce/manifest.json +++ b/plugins/geenforce/manifest.json @@ -1,5 +1,6 @@ { "name": "geenforce", + "display_name": "GE-Enforce", "version": "0.1.0", "description": "GE-Enforce manifest store. Owns imaging PC-type scopes and their install manifests (apps, scripts, files, registry, version gates) as shopdb data, served to the GE-Enforce client as JSON. Requires GE-Enforce lib >= 2.6 on target PCs (the _CmmVersion gate).", "author": "ShopDB Team", diff --git a/plugins/knowledgebase/manifest.json b/plugins/knowledgebase/manifest.json index 3a34973..46dfb51 100644 --- a/plugins/knowledgebase/manifest.json +++ b/plugins/knowledgebase/manifest.json @@ -1,5 +1,6 @@ { "name": "knowledgebase", + "display_name": "Knowledge Base", "version": "1.0.0", "description": "Knowledge Base articles linking to external resources", "author": "ShopDB Team", diff --git a/plugins/measuringtools/manifest.json b/plugins/measuringtools/manifest.json index 8b5f200..f61c03e 100644 --- a/plugins/measuringtools/manifest.json +++ b/plugins/measuringtools/manifest.json @@ -1,5 +1,6 @@ { "name": "measuringtools", + "display_name": "Measuring Tools", "version": "1.0.0", "description": "Metrology and inspection instruments (gauges, calipers, thread gages, bore gages) with a calibration lifecycle and derived calibration status.", "author": "ShopDB Team", diff --git a/plugins/usb/manifest.json b/plugins/usb/manifest.json index 94173df..5b595c3 100644 --- a/plugins/usb/manifest.json +++ b/plugins/usb/manifest.json @@ -1,5 +1,6 @@ { "name": "usb", + "display_name": "USB", "version": "1.0.0", "description": "USB device checkout management", "author": "ShopDB Team", diff --git a/shopdb/plugins/__init__.py b/shopdb/plugins/__init__.py index 2cca4fb..1729ab2 100644 --- a/shopdb/plugins/__init__.py +++ b/shopdb/plugins/__init__.py @@ -155,6 +155,11 @@ class PluginManager: manifest = self.loader.load_manifest(name) available.append({ 'name': meta.name, + # Human label for UIs. Manifest display_name wins; else + # title-case the machine name (right for most, e.g. + # "computers" -> "Computers"). + 'displayname': (manifest.get('display_name') + or meta.name.replace('_', ' ').title()), 'version': meta.version, 'description': meta.description, 'author': meta.author,