@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
|
|
392
|
-
* multi-column overflow dropdown. Each shortcut
|
|
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
|
-
*
|
|
422
|
+
* Metadata:
|
|
423
|
+
* description {String} Short description shown in the card
|
|
424
|
+
* tags {String[]} Search tags
|
|
395
425
|
*
|
|
396
|
-
*
|
|
397
|
-
*
|
|
398
|
-
*
|
|
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
|
-
* {
|
|
408
|
-
*
|
|
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 =
|
|
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 (!
|
|
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