@fleetbase/ember-core 0.3.13 → 0.3.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  import BaseContract from './base-contract';
2
2
  import ExtensionComponent from './extension-component';
3
3
  import { dasherize } from '@ember/string';
4
+ import { isArray } from '@ember/array';
4
5
  import isObject from '../utils/is-object';
5
6
 
6
7
  /**
@@ -123,6 +124,11 @@ export default class MenuItem extends BaseContract {
123
124
  // plain object with at minimum { title, route } and optionally
124
125
  // { icon, iconPrefix, id }. Optional – defaults to null.
125
126
  this.shortcuts = definition.shortcuts || null;
127
+
128
+ // An array of string tags used to improve search discoverability in
129
+ // the overflow dropdown. e.g. ['logistics', 'tracking', 'fleet'].
130
+ // Optional – defaults to null.
131
+ this.tags = isArray(definition.tags) ? definition.tags : definition.tags ? [definition.tags] : null;
126
132
  } else {
127
133
  // Handle string title with optional route (chaining pattern)
128
134
  this.title = titleOrDefinition;
@@ -178,6 +184,7 @@ export default class MenuItem extends BaseContract {
178
184
  // ── Phase 2 additions ──────────────────────────────────────────
179
185
  this.description = null;
180
186
  this.shortcuts = null;
187
+ this.tags = null;
181
188
  }
182
189
 
183
190
  // Call setup() to trigger validation after properties are set
@@ -388,14 +395,40 @@ export default class MenuItem extends BaseContract {
388
395
  }
389
396
 
390
397
  /**
391
- * Set an array of shortcut items displayed beneath the extension in the
392
- * multi-column overflow dropdown. Each shortcut is a plain object:
398
+ * Set an array of shortcut items displayed as independent sibling cards in
399
+ * the multi-column overflow dropdown (AWS Console style). Each shortcut
400
+ * supports the full MenuItem property surface:
401
+ *
402
+ * Required:
403
+ * title {String} Display label
404
+ *
405
+ * Routing:
406
+ * route {String} Ember route name
407
+ * queryParams {Object}
408
+ * routeParams {Array}
409
+ *
410
+ * Identity:
411
+ * id {String} Explicit id (auto-dasherized from title if omitted)
412
+ * slug {String} URL slug (falls back to id)
413
+ *
414
+ * Icons:
415
+ * icon {String} FontAwesome icon name
416
+ * iconPrefix {String} FA prefix (e.g. 'far', 'fab')
417
+ * iconSize {String} FA size string
418
+ * iconClass {String} Extra CSS class on the icon element
419
+ * iconComponent {String} Lazy-loaded engine component path
420
+ * iconComponentOptions {Object}
393
421
  *
394
- * { title, route, icon?, iconPrefix?, id? }
422
+ * Metadata:
423
+ * description {String} Short description shown in the card
424
+ * tags {String[]} Search tags
395
425
  *
396
- * Shortcuts are purely navigational – they do not support onClick handlers.
397
- * They are rendered as compact links inside the extension card in the
398
- * dropdown and can be individually pinned to the navigation bar.
426
+ * Behaviour:
427
+ * onClick {Function} Click handler (receives the shortcut item)
428
+ * disabled {Boolean}
429
+ *
430
+ * Shortcuts are registered as first-class header menu items at boot time
431
+ * and can be individually pinned to the navigation bar.
399
432
  *
400
433
  * @method withShortcuts
401
434
  * @param {Array<Object>} shortcuts Array of shortcut definition objects
@@ -404,16 +437,47 @@ export default class MenuItem extends BaseContract {
404
437
  * @example
405
438
  * new MenuItem('Fleet-Ops', 'console.fleet-ops')
406
439
  * .withShortcuts([
407
- * { title: 'Scheduler', route: 'console.fleet-ops.scheduler', icon: 'calendar' },
408
- * { title: 'Order Config', route: 'console.fleet-ops.order-configs', icon: 'gear' },
440
+ * {
441
+ * title: 'Scheduler',
442
+ * route: 'console.fleet-ops.scheduler',
443
+ * icon: 'calendar',
444
+ * description: 'Plan and visualise driver schedules',
445
+ * tags: ['schedule', 'calendar'],
446
+ * },
447
+ * {
448
+ * title: 'Live Map',
449
+ * route: 'console.fleet-ops',
450
+ * iconComponent: 'fleet-ops@components/live-map-icon',
451
+ * description: 'Real-time vehicle tracking',
452
+ * },
409
453
  * ])
410
454
  */
411
455
  withShortcuts(shortcuts) {
412
- this.shortcuts = Array.isArray(shortcuts) ? shortcuts : null;
456
+ this.shortcuts = isArray(shortcuts) ? shortcuts : null;
413
457
  this._options.shortcuts = this.shortcuts;
414
458
  return this;
415
459
  }
416
460
 
461
+ /**
462
+ * Set an array of string tags for this menu item.
463
+ * Tags are matched against the search query in the overflow dropdown,
464
+ * making items discoverable even when the query doesn't match the title
465
+ * or description.
466
+ *
467
+ * @method withTags
468
+ * @param {String|String[]} tags One tag string or an array of tag strings
469
+ * @returns {MenuItem} This instance for chaining
470
+ *
471
+ * @example
472
+ * new MenuItem('Fleet-Ops', 'console.fleet-ops')
473
+ * .withTags(['logistics', 'tracking', 'fleet', 'drivers'])
474
+ */
475
+ withTags(tags) {
476
+ this.tags = isArray(tags) ? tags : tags ? [tags] : null;
477
+ this._options.tags = this.tags;
478
+ return this;
479
+ }
480
+
417
481
  /**
418
482
  * Add a single shortcut to the existing shortcuts array.
419
483
  * Creates the array if it does not yet exist.
@@ -428,7 +492,7 @@ export default class MenuItem extends BaseContract {
428
492
  * .addShortcut({ title: 'Order Config', route: 'console.fleet-ops.order-configs' })
429
493
  */
430
494
  addShortcut(shortcut) {
431
- if (!Array.isArray(this.shortcuts)) {
495
+ if (!isArray(this.shortcuts)) {
432
496
  this.shortcuts = [];
433
497
  }
434
498
  this.shortcuts = [...this.shortcuts, shortcut];
@@ -502,6 +566,9 @@ export default class MenuItem extends BaseContract {
502
566
  // Optional array of shortcut sub-links shown inside the extension card
503
567
  shortcuts: this.shortcuts,
504
568
 
569
+ // Optional array of string tags for search discoverability
570
+ tags: this.tags,
571
+
505
572
  // Indicator flag
506
573
  _isMenuItem: true,
507
574
 
@@ -19,6 +19,11 @@ export const hostServices = [
19
19
  'sidebar',
20
20
  'dashboard',
21
21
  'universe',
22
+ 'universe/menu-service',
23
+ 'universe/registry-service',
24
+ 'universe/hook-service',
25
+ 'universe/widget-service',
26
+ 'universe/extension-manager',
22
27
  'events',
23
28
  'intl',
24
29
  'abilities',
@@ -21,6 +21,11 @@ export const services = [
21
21
  'sidebar',
22
22
  'dashboard',
23
23
  'universe',
24
+ 'universe/menu-service',
25
+ 'universe/registry-service',
26
+ 'universe/hook-service',
27
+ 'universe/widget-service',
28
+ 'universe/extension-manager',
24
29
  'events',
25
30
  'intl',
26
31
  'abilities',
@@ -3,7 +3,7 @@ import Evented from '@ember/object/evented';
3
3
  import { tracked } from '@glimmer/tracking';
4
4
  import { inject as service } from '@ember/service';
5
5
  import { dasherize } from '@ember/string';
6
- import { A } from '@ember/array';
6
+ import { A, isArray } from '@ember/array';
7
7
  import MenuItem from '../../contracts/menu-item';
8
8
  import MenuPanel from '../../contracts/menu-panel';
9
9
 
@@ -153,6 +153,70 @@ export default class MenuService extends Service.extend(Evented) {
153
153
  const menuItem = this.#normalizeMenuItem(itemOrTitle, route, options);
154
154
  this.registry.register('header', 'menu-item', menuItem.slug, menuItem);
155
155
 
156
+ // Auto-register each shortcut as a first-class header menu item so that
157
+ // they appear in the customiser's "All Extensions" list and can be found
158
+ // by id in allItems when pinned to the bar.
159
+ if (isArray(menuItem.shortcuts)) {
160
+ for (const sc of menuItem.shortcuts) {
161
+ const scId = sc.id ?? dasherize(menuItem.id + '-sc-' + sc.title);
162
+ const scSlug = sc.slug ?? scId;
163
+
164
+ // Build a first-class item that supports the full MenuItem
165
+ // property surface. Each property falls back to the parent's
166
+ // value so shortcuts inherit sensible defaults without the
167
+ // consumer having to repeat them.
168
+ const scItem = {
169
+ // ── Identity ──────────────────────────────────────────────
170
+ id: scId,
171
+ slug: scSlug,
172
+ title: sc.title,
173
+ text: sc.text ?? sc.title,
174
+ label: sc.label ?? sc.title,
175
+ view: sc.view ?? scId,
176
+
177
+ // ── Routing ───────────────────────────────────────────────
178
+ route: sc.route ?? menuItem.route,
179
+ section: sc.section ?? null,
180
+ queryParams: sc.queryParams ?? {},
181
+ routeParams: sc.routeParams ?? [],
182
+
183
+ // ── Icons (full surface) ──────────────────────────────────
184
+ icon: sc.icon ?? menuItem.icon,
185
+ iconPrefix: sc.iconPrefix ?? menuItem.iconPrefix,
186
+ iconSize: sc.iconSize ?? menuItem.iconSize ?? null,
187
+ iconClass: sc.iconClass ?? menuItem.iconClass ?? null,
188
+ iconComponent: sc.iconComponent ?? null,
189
+ iconComponentOptions: sc.iconComponentOptions ?? {},
190
+
191
+ // ── Metadata ──────────────────────────────────────────────
192
+ description: sc.description ?? null,
193
+ // Shortcuts inherit parent tags so they surface under the
194
+ // same search terms; shortcut-specific tags take precedence.
195
+ tags: isArray(sc.tags) ? sc.tags : isArray(menuItem.tags) ? menuItem.tags : null,
196
+
197
+ // ── Behaviour ─────────────────────────────────────────────
198
+ onClick: sc.onClick ?? null,
199
+ disabled: sc.disabled ?? false,
200
+ type: sc.type ?? 'default',
201
+ buttonType: sc.buttonType ?? null,
202
+
203
+ // ── Styling ───────────────────────────────────────────────
204
+ class: sc.class ?? null,
205
+ inlineClass: sc.inlineClass ?? null,
206
+ wrapperClass: sc.wrapperClass ?? null,
207
+
208
+ // ── Internal flags ────────────────────────────────────────
209
+ _isShortcut: true,
210
+ _parentTitle: menuItem.title,
211
+ _parentId: menuItem.id,
212
+ priority: (menuItem.priority ?? 0) + 1,
213
+ _isMenuItem: true,
214
+ };
215
+ this.registry.register('header', 'menu-item', scSlug, scItem);
216
+ this.trigger('menuItem.registered', scItem, 'header');
217
+ }
218
+ }
219
+
156
220
  // Trigger event for backward compatibility
157
221
  this.trigger('menuItem.registered', menuItem, 'header');
158
222
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fleetbase/ember-core",
3
- "version": "0.3.13",
3
+ "version": "0.3.15",
4
4
  "description": "Provides all the core services, decorators and utilities for building a Fleetbase extension for the Console.",
5
5
  "keywords": [
6
6
  "fleetbase-core",