From 1dd8c51408a8fda54be8ed7548a560ca961d50ed Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Fri, 19 Jun 2026 18:34:14 +0800 Subject: [PATCH 1/2] v0.3.23 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 296204c..d8de2ab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@fleetbase/ember-core", - "version": "0.3.22", + "version": "0.3.23", "description": "Provides all the core services, decorators and utilities for building a Fleetbase extension for the Console.", "keywords": [ "fleetbase-core", From 63cf9152bb108a459abe894a5371521058427099 Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Fri, 19 Jun 2026 18:38:04 +0800 Subject: [PATCH 2/2] Add dashboard slot registration APIs --- addon/services/universe.js | 44 ++++++++ addon/services/universe/widget-service.js | 100 ++++++++++++++++++ .../services/universe/widget-service-test.js | 62 +++++++++++ 3 files changed, 206 insertions(+) create mode 100644 tests/unit/services/universe/widget-service-test.js diff --git a/addon/services/universe.js b/addon/services/universe.js index 27709e1..eeeb240 100644 --- a/addon/services/universe.js +++ b/addon/services/universe.js @@ -492,6 +492,50 @@ export default class UniverseService extends Service.extend(Evented) { this.widgetService.registerDashboard(name, options); } + /** + * Register a dashboard render slot. + * + * @method registerDashboardSlot + * @param {String} slotId Dashboard slot identifier + * @param {Object} options Slot options + */ + registerDashboardSlot(slotId, options = {}) { + this.widgetService.registerDashboardSlot(slotId, options); + } + + /** + * Register a system dashboard for a render slot. + * + * @method registerDashboardForSlot + * @param {String} slotId Dashboard slot identifier + * @param {String} dashboardName Dashboard widget namespace + * @param {Object} options Dashboard slot options + */ + registerDashboardForSlot(slotId, dashboardName, options = {}) { + this.widgetService.registerDashboardForSlot(slotId, dashboardName, options); + } + + /** + * Set the first system dashboard for a render slot. + * + * @method setDefaultDashboardForSlot + * @param {String} slotId Dashboard slot identifier + * @param {String} dashboardName Dashboard widget namespace + */ + setDefaultDashboardForSlot(slotId, dashboardName) { + this.widgetService.setDefaultDashboardForSlot(slotId, dashboardName); + } + + /** + * Set the dashboard that should load first on the console home. + * + * @method setConsoleDashboard + * @param {String} dashboardName Dashboard widget namespace + */ + setConsoleDashboard(dashboardName) { + this.widgetService.setConsoleDashboard(dashboardName); + } + /** * Get dashboard widgets * diff --git a/addon/services/universe/widget-service.js b/addon/services/universe/widget-service.js index 5cf829a..4994089 100644 --- a/addon/services/universe/widget-service.js +++ b/addon/services/universe/widget-service.js @@ -91,6 +91,106 @@ export default class WidgetService extends Service { this.registry.register('dashboards', 'dashboard', name, dashboard); } + /** + * Register a dashboard render slot. + * + * Slots describe where dashboards render (for example `console.home`), + * while dashboard names continue to describe widget namespaces. + * + * @method registerDashboardSlot + * @param {String} slotId Slot identifier + * @param {Object} options Slot options + */ + registerDashboardSlot(slotId, options = {}) { + const slot = { + id: slotId, + ...options, + }; + + this.registry.register('dashboard:slots', 'slot', slotId, slot); + } + + /** + * Register a system dashboard that should be available in a render slot. + * + * @method registerDashboardForSlot + * @param {String} slotId Slot identifier + * @param {String} dashboardName Dashboard widget namespace + * @param {Object} options Dashboard slot options + */ + registerDashboardForSlot(slotId, dashboardName, options = {}) { + this.registerDashboardSlot(slotId); + this.registerDashboard(dashboardName, options); + + const dashboard = { + id: dashboardName, + dashboardId: dashboardName, + name: options.name ?? options.defaultDashboardName ?? dashboardName, + extension: options.extension ?? 'core', + priority: options.priority ?? 0, + ...options, + }; + + this.registry.register('dashboard:slots', 'dashboard', `${slotId}#${dashboardName}`, { + slotId, + ...dashboard, + }); + } + + /** + * Set the system dashboard that should load first for a render slot. + * + * @method setDefaultDashboardForSlot + * @param {String} slotId Slot identifier + * @param {String} dashboardName Dashboard widget namespace + */ + setDefaultDashboardForSlot(slotId, dashboardName) { + this.registerDashboardSlot(slotId); + this.registry.register('dashboard:slots', 'default', slotId, { + slotId, + dashboardId: dashboardName, + }); + } + + /** + * Convenience alias for setting the console home dashboard. + * + * @method setConsoleDashboard + * @param {String} dashboardName Dashboard widget namespace + */ + setConsoleDashboard(dashboardName) { + this.setDefaultDashboardForSlot('console.home', dashboardName); + } + + /** + * Get system dashboards registered for a slot. + * + * @method getDashboardsForSlot + * @param {String} slotId Slot identifier + * @returns {Array} Slot dashboard registrations + */ + getDashboardsForSlot(slotId) { + if (!slotId) { + return []; + } + + const prefix = `${slotId}#`; + return [...this.registry.getRegistry('dashboard:slots', 'dashboard')] + .filter((dashboard) => dashboard?._registryKey?.startsWith(prefix)) + .sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0)); + } + + /** + * Get the dashboard namespace that should load first for a slot. + * + * @method getDefaultDashboardForSlot + * @param {String} slotId Slot identifier + * @returns {String|null} Dashboard namespace + */ + getDefaultDashboardForSlot(slotId) { + return this.registry.lookup('dashboard:slots', 'default', slotId)?.dashboardId ?? null; + } + /** * Register widgets to a specific dashboard * Makes these widgets available for selection on the dashboard diff --git a/tests/unit/services/universe/widget-service-test.js b/tests/unit/services/universe/widget-service-test.js new file mode 100644 index 0000000..843911d --- /dev/null +++ b/tests/unit/services/universe/widget-service-test.js @@ -0,0 +1,62 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'dummy/tests/helpers'; +import Service from '@ember/service'; + +class RegistryStubService extends Service { + registries = new Map(); + + register(section, list, key, value) { + const registryKey = `${section}:${list}`; + const registry = this.registries.get(registryKey) ?? []; + const record = { ...value, _registryKey: key }; + const existingIndex = registry.findIndex((item) => item._registryKey === key); + + if (existingIndex === -1) { + registry.push(record); + } else { + registry[existingIndex] = record; + } + + this.registries.set(registryKey, registry); + } + + getRegistry(section, list) { + return this.registries.get(`${section}:${list}`) ?? []; + } + + lookup(section, list, key) { + return this.getRegistry(section, list).find((item) => item._registryKey === key) ?? null; + } +} + +module('Unit | Service | universe/widget-service', function (hooks) { + setupTest(hooks); + + hooks.beforeEach(function () { + this.owner.register('service:universe/registry-service', RegistryStubService); + }); + + test('it registers multiple system dashboards for a dashboard slot', function (assert) { + const service = this.owner.lookup('service:universe/widget-service'); + + service.registerDashboardForSlot('console.home', 'dashboard', { + name: 'Default Dashboard', + priority: 0, + }); + service.registerDashboardForSlot('console.home', 'alrashd', { + name: 'Al-Rashed KPI Dashboard', + priority: 10, + }); + service.setConsoleDashboard('alrashd'); + + const dashboards = service.getDashboardsForSlot('console.home'); + + assert.deepEqual( + dashboards.map((dashboard) => dashboard.id), + ['alrashd', 'dashboard'], + 'slot dashboards are returned by priority' + ); + assert.strictEqual(service.getDefaultDashboardForSlot('console.home'), 'alrashd', 'console shortcut sets the console home default'); + assert.strictEqual(service.getDashboard('alrashd').name, 'Al-Rashed KPI Dashboard', 'dashboard namespace metadata is registered'); + }); +});