From a4b98e10dba76ed2cbb95989b88b474c134e46d3 Mon Sep 17 00:00:00 2001 From: cproudlock Date: Fri, 26 Jun 2026 22:09:38 -0400 Subject: [PATCH] Add dashboard defaults (visitor-IP -> business-unit) for kiosk displays Classic feature gap: a shopfloor/lobby kiosk auto-selects which business unit to show based on the display PC's IP (classic dashboarddefaults table + apivisitorlocation.asp). For the main admin dashboard this does nothing - it is kiosk/visitor-display infra. - Model: DashboardDefault (dashboarddefaults: ipaddress unique, businessunitid FK, description). Migration 7d01_dashboarddefaults (head). - API (core, /api/dashboarddefaults): CRUD + GET /visitor-location that resolves the calling display's business unit from its IP (X-Forwarded-For/remote_addr, or explicit ?ipaddress=); unmapped IP returns a null businessunitid, not an error. Unauthenticated resolve (kiosks); writes are admin. - Frontend: ShopfloorDashboard auto-selects its business unit via visitor-location on load when none is chosen; Settings > Dashboard Defaults CRUD page + dashboardDefaultsApi client. Tests: create + resolve by IP -> BU; unmapped IP -> null; duplicate IP 409. 191 tests pass, naming green, app boots, endpoint + admin page verified live. Co-Authored-By: Claude Opus 4.8 --- frontend/src/api/index.js | 20 ++ frontend/src/router/routes/core.js | 6 + frontend/src/views/ShopfloorDashboard.vue | 15 +- .../views/settings/DashboardDefaultsList.vue | 187 ++++++++++++++++++ frontend/src/views/settings/SettingsIndex.vue | 8 +- migrations/versions/7d01_dashboarddefaults.py | 37 ++++ shopdb/__init__.py | 1 + shopdb/core/api/__init__.py | 2 + shopdb/core/api/dashboarddefaults.py | 127 ++++++++++++ shopdb/core/models/__init__.py | 2 + shopdb/core/models/dashboarddefault.py | 28 +++ tests/test_core/test_dashboarddefaults.py | 44 +++++ 12 files changed, 475 insertions(+), 2 deletions(-) create mode 100644 frontend/src/views/settings/DashboardDefaultsList.vue create mode 100644 migrations/versions/7d01_dashboarddefaults.py create mode 100644 shopdb/core/api/dashboarddefaults.py create mode 100644 shopdb/core/models/dashboarddefault.py create mode 100644 tests/test_core/test_dashboarddefaults.py diff --git a/frontend/src/api/index.js b/frontend/src/api/index.js index f590a92..2c2bd43 100644 --- a/frontend/src/api/index.js +++ b/frontend/src/api/index.js @@ -673,6 +673,26 @@ export const employeesApi = { // Alias for different casing export const businessUnitsApi = businessunitsApi +// Dashboard defaults: visitor-IP -> business-unit mapping for kiosks +export const dashboardDefaultsApi = { + list() { + return api.get('/dashboarddefaults') + }, + create(data) { + return api.post('/dashboarddefaults', data) + }, + update(id, data) { + return api.put(`/dashboarddefaults/${id}`, data) + }, + delete(id) { + return api.delete(`/dashboarddefaults/${id}`) + }, + // Resolve the calling display's business unit by its IP + visitorLocation() { + return api.get('/dashboarddefaults/visitor-location') + } +} + // System Settings API export const pluginsApi = { list() { diff --git a/frontend/src/router/routes/core.js b/frontend/src/router/routes/core.js index 2fef2dd..fd818aa 100644 --- a/frontend/src/router/routes/core.js +++ b/frontend/src/router/routes/core.js @@ -86,6 +86,12 @@ export default [ component: () => import('../../views/settings/BusinessUnitsList.vue'), meta: { requiresAuth: true, requiresAdmin: true } }, + { + path: 'settings/dashboarddefaults', + name: 'dashboarddefaults', + component: () => import('../../views/settings/DashboardDefaultsList.vue'), + meta: { requiresAuth: true, requiresAdmin: true } + }, { path: 'settings/system', name: 'system-settings', diff --git a/frontend/src/views/ShopfloorDashboard.vue b/frontend/src/views/ShopfloorDashboard.vue index 027a562..5db7d1d 100644 --- a/frontend/src/views/ShopfloorDashboard.vue +++ b/frontend/src/views/ShopfloorDashboard.vue @@ -129,7 +129,7 @@ diff --git a/frontend/src/views/settings/SettingsIndex.vue b/frontend/src/views/settings/SettingsIndex.vue index 1068928..729ddc4 100644 --- a/frontend/src/views/settings/SettingsIndex.vue +++ b/frontend/src/views/settings/SettingsIndex.vue @@ -57,6 +57,12 @@

Manage organizational units

+ +
+

Dashboard Defaults

+

Map kiosk IPs to a default business unit

+
+

VLANs

@@ -97,7 +103,7 @@