@fleetbase/ember-core 0.2.17 → 0.2.19
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.
- package/addon/services/current-user.js +23 -5
- package/addon/services/fetch.js +12 -1
- package/addon/services/session.js +14 -8
- package/addon/services/theme.js +1 -1
- package/addon/services/universe.js +636 -119
- package/addon/services/url-search-params.js +189 -35
- package/addon/utils/inject-engine-service.js +7 -2
- package/addon/utils/is-empty-object.js +7 -1
- package/addon/utils/register-component.js +8 -0
- package/addon/utils/register-helper.js +8 -0
- package/addon/utils/serialize/normalize-relations-with-hash.js +0 -5
- package/app/utils/register-component.js +1 -0
- package/app/utils/register-helper.js +1 -0
- package/package.json +1 -1
|
@@ -7,8 +7,9 @@ import { isBlank } from '@ember/utils';
|
|
|
7
7
|
import { A, isArray } from '@ember/array';
|
|
8
8
|
import { later } from '@ember/runloop';
|
|
9
9
|
import { dasherize, camelize } from '@ember/string';
|
|
10
|
+
import { pluralize } from 'ember-inflector';
|
|
10
11
|
import { getOwner } from '@ember/application';
|
|
11
|
-
import { assert, debug } from '@ember/debug';
|
|
12
|
+
import { assert, debug, warn } from '@ember/debug';
|
|
12
13
|
import RSVP from 'rsvp';
|
|
13
14
|
import loadInstalledExtensions from '../utils/load-installed-extensions';
|
|
14
15
|
import loadExtensions from '../utils/load-extensions';
|
|
@@ -18,18 +19,22 @@ import config from 'ember-get-config';
|
|
|
18
19
|
export default class UniverseService extends Service.extend(Evented) {
|
|
19
20
|
@service router;
|
|
20
21
|
@service intl;
|
|
22
|
+
@service urlSearchParams;
|
|
23
|
+
@tracked applicationInstance;
|
|
24
|
+
@tracked enginesBooted = false;
|
|
25
|
+
@tracked bootedExtensions = A([]);
|
|
21
26
|
@tracked headerMenuItems = A([]);
|
|
22
27
|
@tracked organizationMenuItems = A([]);
|
|
23
28
|
@tracked userMenuItems = A([]);
|
|
24
|
-
@tracked
|
|
29
|
+
@tracked consoleAdminRegistry = {
|
|
25
30
|
menuItems: A([]),
|
|
26
31
|
menuPanels: A([]),
|
|
27
32
|
};
|
|
28
|
-
@tracked
|
|
33
|
+
@tracked consoleAccountRegistry = {
|
|
29
34
|
menuItems: A([]),
|
|
30
35
|
menuPanels: A([]),
|
|
31
36
|
};
|
|
32
|
-
@tracked
|
|
37
|
+
@tracked consoleSettingsRegistry = {
|
|
33
38
|
menuItems: A([]),
|
|
34
39
|
menuPanels: A([]),
|
|
35
40
|
};
|
|
@@ -37,6 +42,8 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
37
42
|
defaultWidgets: A([]),
|
|
38
43
|
widgets: A([]),
|
|
39
44
|
};
|
|
45
|
+
@tracked hooks = {};
|
|
46
|
+
@tracked bootCallbacks = A([]);
|
|
40
47
|
|
|
41
48
|
/**
|
|
42
49
|
* Computed property that returns all administrative menu items.
|
|
@@ -47,8 +54,8 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
47
54
|
* @memberof UniverseService
|
|
48
55
|
* @returns {Array} Array of administrative menu items
|
|
49
56
|
*/
|
|
50
|
-
@computed('
|
|
51
|
-
return this.
|
|
57
|
+
@computed('consoleAdminRegistry.menuItems.[]') get adminMenuItems() {
|
|
58
|
+
return this.consoleAdminRegistry.menuItems;
|
|
52
59
|
}
|
|
53
60
|
|
|
54
61
|
/**
|
|
@@ -60,8 +67,8 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
60
67
|
* @memberof UniverseService
|
|
61
68
|
* @returns {Array} Array of administrative menu panels
|
|
62
69
|
*/
|
|
63
|
-
@computed('
|
|
64
|
-
return this.
|
|
70
|
+
@computed('consoleAdminRegistry.menuPanels.[]') get adminMenuPanels() {
|
|
71
|
+
return this.consoleAdminRegistry.menuPanels;
|
|
65
72
|
}
|
|
66
73
|
|
|
67
74
|
/**
|
|
@@ -73,8 +80,8 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
73
80
|
* @memberof UniverseService
|
|
74
81
|
* @returns {Array} Array of administrative menu items
|
|
75
82
|
*/
|
|
76
|
-
@computed('
|
|
77
|
-
return this.
|
|
83
|
+
@computed('consoleSettingsRegistry.menuItems.[]') get settingsMenuItems() {
|
|
84
|
+
return this.consoleSettingsRegistry.menuItems;
|
|
78
85
|
}
|
|
79
86
|
|
|
80
87
|
/**
|
|
@@ -86,8 +93,8 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
86
93
|
* @memberof UniverseService
|
|
87
94
|
* @returns {Array} Array of administrative menu panels
|
|
88
95
|
*/
|
|
89
|
-
@computed('
|
|
90
|
-
return this.
|
|
96
|
+
@computed('consoleSettingsRegistry.menuPanels.[]') get settingsMenuPanels() {
|
|
97
|
+
return this.consoleSettingsRegistry.menuPanels;
|
|
91
98
|
}
|
|
92
99
|
|
|
93
100
|
/**
|
|
@@ -130,6 +137,26 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
130
137
|
return this.router.transitionTo(route, ...args);
|
|
131
138
|
}
|
|
132
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Sets the application instance.
|
|
142
|
+
*
|
|
143
|
+
* @param {ApplicationInstance} - The application instance object.
|
|
144
|
+
* @return {void}
|
|
145
|
+
*/
|
|
146
|
+
setApplicationInstance(instance) {
|
|
147
|
+
window.Fleetbase = instance;
|
|
148
|
+
this.applicationInstance = instance;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Retrieves the application instance.
|
|
153
|
+
*
|
|
154
|
+
* @returns {ApplicationInstance} - The application instance object.
|
|
155
|
+
*/
|
|
156
|
+
getApplicationInstance() {
|
|
157
|
+
return this.applicationInstance;
|
|
158
|
+
}
|
|
159
|
+
|
|
133
160
|
/**
|
|
134
161
|
* Retrieves the mount point of a specified engine by its name.
|
|
135
162
|
|
|
@@ -230,13 +257,58 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
230
257
|
* @returns {Transition} Returns a Transition object representing the transition to the route.
|
|
231
258
|
*/
|
|
232
259
|
@action transitionMenuItem(route, menuItem) {
|
|
233
|
-
const { slug, view } = menuItem;
|
|
260
|
+
const { slug, view, section } = menuItem;
|
|
234
261
|
|
|
235
|
-
if (view) {
|
|
236
|
-
return this.router.transitionTo(route, slug, view);
|
|
262
|
+
if (section && slug && view) {
|
|
263
|
+
return this.router.transitionTo(route, section, slug, { queryParams: { view } });
|
|
237
264
|
}
|
|
238
265
|
|
|
239
|
-
|
|
266
|
+
if (section && slug) {
|
|
267
|
+
return this.router.transitionTo(route, section, slug);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (slug && view) {
|
|
271
|
+
return this.router.transitionTo(route, slug, { queryParams: { view } });
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return this.router.transitionTo(route, slug);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Redirects to a virtual route if a corresponding menu item exists based on the current URL slug.
|
|
279
|
+
*
|
|
280
|
+
* This asynchronous function checks whether a virtual route exists by extracting the slug from the current
|
|
281
|
+
* window's pathname and looking up a matching menu item in a specified registry. If a matching menu item
|
|
282
|
+
* is found, it initiates a transition to the given route associated with that menu item and returns the
|
|
283
|
+
* transition promise.
|
|
284
|
+
*
|
|
285
|
+
* @async
|
|
286
|
+
*
|
|
287
|
+
* @param {Object} transition - The current transition object from the router.
|
|
288
|
+
* Used to retrieve additional information required for the menu item lookup.
|
|
289
|
+
* @param {string} registryName - The name of the registry to search for the menu item.
|
|
290
|
+
* This registry should contain menu items mapped by their slugs.
|
|
291
|
+
* @param {string} route - The name of the route to transition to if the menu item is found.
|
|
292
|
+
* This is typically the route associated with displaying the menu item's content.
|
|
293
|
+
*
|
|
294
|
+
* @returns {Promise|undefined} - Returns a promise that resolves when the route transition completes
|
|
295
|
+
* if a matching menu item is found. If no matching menu item is found, the function returns undefined.
|
|
296
|
+
*
|
|
297
|
+
*/
|
|
298
|
+
async virtualRouteRedirect(transition, registryName, route, options = {}) {
|
|
299
|
+
const view = this.getViewFromTransition(transition);
|
|
300
|
+
const slug = window.location.pathname.replace('/', '');
|
|
301
|
+
const queryParams = this.urlSearchParams.all();
|
|
302
|
+
const menuItem = await this.lookupMenuItemFromRegistry(registryName, slug, view);
|
|
303
|
+
if (menuItem && transition.from === null) {
|
|
304
|
+
return this.transitionMenuItem(route, menuItem, { queryParams }).then((transition) => {
|
|
305
|
+
if (options && options.restoreQueryParams === true) {
|
|
306
|
+
this.urlSearchParams.setParamsToCurrentUrl(queryParams);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return transition;
|
|
310
|
+
});
|
|
311
|
+
}
|
|
240
312
|
}
|
|
241
313
|
|
|
242
314
|
/**
|
|
@@ -259,13 +331,20 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
259
331
|
@action createRegistry(registryName, options = {}) {
|
|
260
332
|
const internalRegistryName = this.createInternalRegistryName(registryName);
|
|
261
333
|
|
|
262
|
-
this[internalRegistryName]
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
334
|
+
if (this[internalRegistryName] == undefined) {
|
|
335
|
+
this[internalRegistryName] = {
|
|
336
|
+
name: registryName,
|
|
337
|
+
menuItems: [],
|
|
338
|
+
menuPanels: [],
|
|
339
|
+
renderableComponents: [],
|
|
340
|
+
...options,
|
|
341
|
+
};
|
|
342
|
+
} else {
|
|
343
|
+
this[internalRegistryName] = {
|
|
344
|
+
...this[internalRegistryName],
|
|
345
|
+
...options,
|
|
346
|
+
};
|
|
347
|
+
}
|
|
269
348
|
|
|
270
349
|
// trigger registry created event
|
|
271
350
|
this.trigger('registry.created', this[internalRegistryName]);
|
|
@@ -519,10 +598,11 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
519
598
|
* @param {string} registryName - The name of the registry where the menu item is located.
|
|
520
599
|
* @param {string} slug - The slug of the menu item.
|
|
521
600
|
* @param {string} [view=null] - The view of the menu item, if applicable.
|
|
601
|
+
* @param {string} [section=null] - The section of the menu item, if applicable.
|
|
522
602
|
*
|
|
523
603
|
* @returns {Promise} Returns a Promise that resolves with the menu item if it is found, or null.
|
|
524
604
|
*/
|
|
525
|
-
lookupMenuItemFromRegistry(registryName, slug, view = null) {
|
|
605
|
+
lookupMenuItemFromRegistry(registryName, slug, view = null, section = null) {
|
|
526
606
|
const internalRegistryName = this.createInternalRegistryName(registryName);
|
|
527
607
|
const registry = this[internalRegistryName];
|
|
528
608
|
|
|
@@ -537,8 +617,7 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
537
617
|
for (let i = 0; i < registry.menuItems.length; i++) {
|
|
538
618
|
const menuItem = registry.menuItems[i];
|
|
539
619
|
|
|
540
|
-
|
|
541
|
-
if (menuItem && menuItem.slug === slug && menuItem.view === null && view === 'index') {
|
|
620
|
+
if (menuItem && menuItem.slug === slug && menuItem.section === section && menuItem.view === view) {
|
|
542
621
|
foundMenuItem = menuItem;
|
|
543
622
|
break;
|
|
544
623
|
}
|
|
@@ -557,8 +636,7 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
557
636
|
for (let j = 0; j < menuPanel.items.length; j++) {
|
|
558
637
|
const menuItem = menuPanel.items[j];
|
|
559
638
|
|
|
560
|
-
|
|
561
|
-
if (menuItem && menuItem.slug === slug && menuItem.view === null && view === 'index') {
|
|
639
|
+
if (menuItem && menuItem.slug === slug && menuItem.section === section && menuItem.view === view) {
|
|
562
640
|
foundMenuItem = menuItem;
|
|
563
641
|
break;
|
|
564
642
|
}
|
|
@@ -575,6 +653,134 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
575
653
|
});
|
|
576
654
|
}
|
|
577
655
|
|
|
656
|
+
/**
|
|
657
|
+
* Gets the view param from the transition object.
|
|
658
|
+
*
|
|
659
|
+
* @param {Transition} transition
|
|
660
|
+
* @return {String|Null}
|
|
661
|
+
* @memberof UniverseService
|
|
662
|
+
*/
|
|
663
|
+
getViewFromTransition(transition) {
|
|
664
|
+
const queryParams = transition.to.queryParams ?? { view: null };
|
|
665
|
+
return queryParams.view;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Creates an internal registry name for hooks based on a given registry name.
|
|
670
|
+
* The registry name is transformed to camel case and appended with 'Hooks'.
|
|
671
|
+
* Non-alphanumeric characters are replaced with hyphens.
|
|
672
|
+
*
|
|
673
|
+
* @param {string} registryName - The name of the registry for which to create an internal hook registry name.
|
|
674
|
+
* @returns {string} - The internal hook registry name, formatted as camel case with 'Hooks' appended.
|
|
675
|
+
*/
|
|
676
|
+
createInternalHookRegistryName(registryName) {
|
|
677
|
+
return `${camelize(registryName.replace(/[^a-zA-Z0-9]/g, '-'))}Hooks`;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* Registers a hook function under a specified registry name.
|
|
682
|
+
* The hook is stored in an internal registry, and its hash is computed for identification.
|
|
683
|
+
* If the hook is already registered, it is appended to the existing list of hooks.
|
|
684
|
+
*
|
|
685
|
+
* @param {string} registryName - The name of the registry where the hook should be registered.
|
|
686
|
+
* @param {Function} hook - The hook function to be registered.
|
|
687
|
+
*/
|
|
688
|
+
registerHook(registryName, hook) {
|
|
689
|
+
if (typeof hook !== 'function') {
|
|
690
|
+
throw new Error('The hook must be a function.');
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
// no duplicate hooks
|
|
694
|
+
if (this.didRegisterHook(registryName, hook)) {
|
|
695
|
+
return;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
const internalHookRegistryName = this.createInternalHookRegistryName(registryName);
|
|
699
|
+
const hookRegistry = this.hooks[internalHookRegistryName] || [];
|
|
700
|
+
hookRegistry.pushObject({ id: this._createHashFromFunctionDefinition(hook), hook });
|
|
701
|
+
|
|
702
|
+
this.hooks[internalHookRegistryName] = hookRegistry;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* Checks if a hook was registered already.
|
|
707
|
+
*
|
|
708
|
+
* @param {String} registryName
|
|
709
|
+
* @param {Function} hook
|
|
710
|
+
* @return {Boolean}
|
|
711
|
+
* @memberof UniverseService
|
|
712
|
+
*/
|
|
713
|
+
didRegisterHook(registryName, hook) {
|
|
714
|
+
const hooks = this.getHooks(registryName);
|
|
715
|
+
const hookId = this._createHashFromFunctionDefinition(hook);
|
|
716
|
+
return isArray(hooks) && hooks.some((h) => h.id === hookId);
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
/**
|
|
720
|
+
* Retrieves the list of hooks registered under a specified registry name.
|
|
721
|
+
* If no hooks are registered, returns an empty array.
|
|
722
|
+
*
|
|
723
|
+
* @param {string} registryName - The name of the registry for which to retrieve hooks.
|
|
724
|
+
* @returns {Array<Object>} - An array of hook objects registered under the specified registry name.
|
|
725
|
+
* Each object contains an `id` and a `hook` function.
|
|
726
|
+
*/
|
|
727
|
+
getHooks(registryName) {
|
|
728
|
+
const internalHookRegistryName = this.createInternalHookRegistryName(registryName);
|
|
729
|
+
return this.hooks[internalHookRegistryName] ?? [];
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* Executes all hooks registered under a specified registry name with the given parameters.
|
|
734
|
+
* Each hook is called with the provided parameters.
|
|
735
|
+
*
|
|
736
|
+
* @param {string} registryName - The name of the registry under which hooks should be executed.
|
|
737
|
+
* @param {...*} params - The parameters to pass to each hook function.
|
|
738
|
+
*/
|
|
739
|
+
executeHooks(registryName, ...params) {
|
|
740
|
+
const hooks = this.getHooks(registryName);
|
|
741
|
+
hooks.forEach(({ hook }) => {
|
|
742
|
+
try {
|
|
743
|
+
hook(...params);
|
|
744
|
+
} catch (error) {
|
|
745
|
+
debug(`Error executing hook: ${error}`);
|
|
746
|
+
}
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
/**
|
|
751
|
+
* Calls all hooks registered under a specified registry name with the given parameters.
|
|
752
|
+
* This is an alias for `executeHooks` for consistency in naming.
|
|
753
|
+
*
|
|
754
|
+
* @param {string} registryName - The name of the registry under which hooks should be called.
|
|
755
|
+
* @param {...*} params - The parameters to pass to each hook function.
|
|
756
|
+
*/
|
|
757
|
+
callHooks(registryName, ...params) {
|
|
758
|
+
this.executeHooks(registryName, ...params);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
/**
|
|
762
|
+
* Calls a specific hook identified by its ID under a specified registry name with the given parameters.
|
|
763
|
+
* Only the hook with the matching ID is executed.
|
|
764
|
+
*
|
|
765
|
+
* @param {string} registryName - The name of the registry where the hook is registered.
|
|
766
|
+
* @param {string} hookId - The unique identifier of the hook to be called.
|
|
767
|
+
* @param {...*} params - The parameters to pass to the hook function.
|
|
768
|
+
*/
|
|
769
|
+
callHook(registryName, hookId, ...params) {
|
|
770
|
+
const hooks = this.getHooks(registryName);
|
|
771
|
+
const hook = hooks.find((h) => h.id === hookId);
|
|
772
|
+
|
|
773
|
+
if (hook) {
|
|
774
|
+
try {
|
|
775
|
+
hook.hook(...params);
|
|
776
|
+
} catch (error) {
|
|
777
|
+
debug(`Error executing hook: ${error}`);
|
|
778
|
+
}
|
|
779
|
+
} else {
|
|
780
|
+
warn(`Hook with ID ${hookId} not found.`);
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
|
|
578
784
|
/**
|
|
579
785
|
* Registers a renderable component or an array of components into a specified registry.
|
|
580
786
|
* If a single component is provided, it is registered directly.
|
|
@@ -621,9 +827,11 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
621
827
|
*/
|
|
622
828
|
registerMenuPanel(registryName, title, items = [], options = {}) {
|
|
623
829
|
const internalRegistryName = this.createInternalRegistryName(registryName);
|
|
830
|
+
const intl = this._getOption(options, 'intl', null);
|
|
624
831
|
const open = this._getOption(options, 'open', true);
|
|
625
832
|
const slug = this._getOption(options, 'slug', dasherize(title));
|
|
626
833
|
const menuPanel = {
|
|
834
|
+
intl,
|
|
627
835
|
title,
|
|
628
836
|
open,
|
|
629
837
|
items: items.map(({ title, route, ...options }) => {
|
|
@@ -684,6 +892,26 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
684
892
|
this.trigger('menuItem.registered', menuItem, this[internalRegistryName]);
|
|
685
893
|
}
|
|
686
894
|
|
|
895
|
+
/**
|
|
896
|
+
* Register multiple menu items to a registry.
|
|
897
|
+
*
|
|
898
|
+
* @param {String} registryName
|
|
899
|
+
* @param {Array} [menuItems=[]]
|
|
900
|
+
* @memberof UniverseService
|
|
901
|
+
*/
|
|
902
|
+
registerMenuItems(registryName, menuItems = []) {
|
|
903
|
+
for (let i = 0; i < menuItems.length; i++) {
|
|
904
|
+
const menuItem = menuItems[i];
|
|
905
|
+
if (menuItem && menuItem.title) {
|
|
906
|
+
if (menuItem.options) {
|
|
907
|
+
this.registerMenuItem(registryName, menuItem.title, menuItem.options);
|
|
908
|
+
} else {
|
|
909
|
+
this.registerMenuItem(registryName, menuItem.title, menuItem);
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
|
|
687
915
|
/**
|
|
688
916
|
* Registers a menu item's component to one or multiple engines.
|
|
689
917
|
*
|
|
@@ -724,7 +952,7 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
724
952
|
*/
|
|
725
953
|
registerAdminMenuPanel(title, items = [], options = {}) {
|
|
726
954
|
options.section = this._getOption(options, 'section', 'admin');
|
|
727
|
-
this.registerMenuPanel('admin', title, items, options);
|
|
955
|
+
this.registerMenuPanel('console:admin', title, items, options);
|
|
728
956
|
}
|
|
729
957
|
|
|
730
958
|
/**
|
|
@@ -737,7 +965,7 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
737
965
|
* @param {Object} options Additional options for the item
|
|
738
966
|
*/
|
|
739
967
|
registerAdminMenuItem(title, options = {}) {
|
|
740
|
-
this.registerMenuItem('admin', title, options);
|
|
968
|
+
this.registerMenuItem('console:admin', title, options);
|
|
741
969
|
}
|
|
742
970
|
|
|
743
971
|
/**
|
|
@@ -751,94 +979,252 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
751
979
|
* @param {Object} options Additional options for the panel
|
|
752
980
|
*/
|
|
753
981
|
registerSettingsMenuPanel(title, items = [], options = {}) {
|
|
754
|
-
this.registerMenuPanel('settings', title, items, options);
|
|
982
|
+
this.registerMenuPanel('console:settings', title, items, options);
|
|
755
983
|
}
|
|
756
984
|
|
|
757
985
|
/**
|
|
758
|
-
* Registers a new
|
|
986
|
+
* Registers a new settings menu item.
|
|
759
987
|
*
|
|
760
|
-
* @method
|
|
988
|
+
* @method registerSettingsMenuItem
|
|
761
989
|
* @public
|
|
762
990
|
* @memberof UniverseService
|
|
763
|
-
* @param {
|
|
764
|
-
*
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
* @property {Object} options - Additional options for the widget.
|
|
769
|
-
*/
|
|
770
|
-
registerDashboardWidgets(widget) {
|
|
771
|
-
if (isArray(widget)) {
|
|
772
|
-
widget.forEach((w) => this.registerDashboardWidgets(w));
|
|
773
|
-
return;
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
const newWidget = this._createDashboardWidget(widget);
|
|
777
|
-
this.dashboardWidgets.widgets.pushObject(newWidget);
|
|
778
|
-
this.trigger('widget.registered', newWidget);
|
|
991
|
+
* @param {String} title The title of the item
|
|
992
|
+
* @param {Object} options Additional options for the item
|
|
993
|
+
*/
|
|
994
|
+
registerSettingsMenuItem(title, options = {}) {
|
|
995
|
+
this.registerMenuItem('console:settings', title, options);
|
|
779
996
|
}
|
|
780
997
|
|
|
781
998
|
/**
|
|
782
|
-
*
|
|
999
|
+
* Registers a new account menu panel.
|
|
783
1000
|
*
|
|
784
|
-
* @method
|
|
1001
|
+
* @method registerAccountMenuPanel
|
|
785
1002
|
* @public
|
|
786
1003
|
* @memberof UniverseService
|
|
787
|
-
* @
|
|
1004
|
+
* @param {String} title The title of the panel
|
|
1005
|
+
* @param {Array} items The items of the panel
|
|
1006
|
+
* @param {Object} options Additional options for the panel
|
|
788
1007
|
*/
|
|
789
|
-
|
|
790
|
-
|
|
1008
|
+
registerAccountMenuPanel(title, items = [], options = {}) {
|
|
1009
|
+
this.registerMenuPanel('console:account', title, items, options);
|
|
791
1010
|
}
|
|
792
1011
|
|
|
793
1012
|
/**
|
|
794
|
-
* Registers a new
|
|
1013
|
+
* Registers a new account menu item.
|
|
795
1014
|
*
|
|
796
|
-
* @method
|
|
1015
|
+
* @method registerAccountMenuItem
|
|
797
1016
|
* @public
|
|
798
1017
|
* @memberof UniverseService
|
|
799
|
-
* @param {
|
|
800
|
-
*
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
1018
|
+
* @param {String} title The title of the item
|
|
1019
|
+
* @param {Object} options Additional options for the item
|
|
1020
|
+
*/
|
|
1021
|
+
registerAccountMenuItem(title, options = {}) {
|
|
1022
|
+
this.registerMenuItem('console:account', title, options);
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
/**
|
|
1026
|
+
* Registers a new dashboard with the given name.
|
|
1027
|
+
* Initializes the dashboard with empty arrays for default widgets and widgets.
|
|
1028
|
+
*
|
|
1029
|
+
* @param {string} dashboardName - The name of the dashboard to register.
|
|
1030
|
+
* @returns {void}
|
|
1031
|
+
*/
|
|
1032
|
+
registerDashboard(dashboardName) {
|
|
1033
|
+
const internalDashboardRegistryName = this.createInternalDashboardName(dashboardName);
|
|
1034
|
+
if (this[internalDashboardRegistryName] !== undefined) {
|
|
809
1035
|
return;
|
|
810
1036
|
}
|
|
811
1037
|
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
1038
|
+
this[internalDashboardRegistryName] = {
|
|
1039
|
+
defaultWidgets: A([]),
|
|
1040
|
+
widgets: A([]),
|
|
1041
|
+
};
|
|
1042
|
+
|
|
1043
|
+
this.trigger('dashboard.registered', this[internalDashboardRegistryName]);
|
|
815
1044
|
}
|
|
816
1045
|
|
|
817
1046
|
/**
|
|
818
|
-
* Retrieves the
|
|
1047
|
+
* Retrieves the registry for a specific dashboard.
|
|
819
1048
|
*
|
|
820
|
-
* @
|
|
821
|
-
* @
|
|
1049
|
+
* @param {string} dashboardName - The name of the dashboard to get the registry for.
|
|
1050
|
+
* @returns {Object} - The registry object for the specified dashboard, including default and registered widgets.
|
|
1051
|
+
*/
|
|
1052
|
+
getDashboardRegistry(dashboardName) {
|
|
1053
|
+
const internalDashboardRegistryName = this.createInternalDashboardName(dashboardName);
|
|
1054
|
+
return this[internalDashboardRegistryName];
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
/**
|
|
1058
|
+
* Checks if a dashboard has been registered.
|
|
1059
|
+
*
|
|
1060
|
+
* @param {String} dashboardName
|
|
1061
|
+
* @return {Boolean}
|
|
822
1062
|
* @memberof UniverseService
|
|
823
|
-
|
|
1063
|
+
*/
|
|
1064
|
+
didRegisterDashboard(dashboardName) {
|
|
1065
|
+
const internalDashboardRegistryName = this.createInternalDashboardName(dashboardName);
|
|
1066
|
+
return this[internalDashboardRegistryName] !== undefined;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
/**
|
|
1070
|
+
* Retrieves the widget registry for a specific dashboard and type.
|
|
1071
|
+
*
|
|
1072
|
+
* @param {string} dashboardName - The name of the dashboard to get the widget registry for.
|
|
1073
|
+
* @param {string} [type='widgets'] - The type of widget registry to retrieve (e.g., 'widgets', 'defaultWidgets').
|
|
1074
|
+
* @returns {Array} - An array of widget objects for the specified dashboard and type.
|
|
1075
|
+
*/
|
|
1076
|
+
getWidgetRegistry(dashboardName, type = 'widgets') {
|
|
1077
|
+
const internalDashboardRegistryName = this.createInternalDashboardName(dashboardName);
|
|
1078
|
+
const typeKey = pluralize(type);
|
|
1079
|
+
return isArray(this[internalDashboardRegistryName][typeKey]) ? this[internalDashboardRegistryName][typeKey] : [];
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
/**
|
|
1083
|
+
* Registers widgets for a specific dashboard.
|
|
1084
|
+
* Supports registering multiple widgets and different types of widget collections.
|
|
1085
|
+
*
|
|
1086
|
+
* @param {string} dashboardName - The name of the dashboard to register widgets for.
|
|
1087
|
+
* @param {Array|Object} widgets - An array of widget objects or a single widget object to register.
|
|
1088
|
+
* @param {string} [type='widgets'] - The type of widgets to register (e.g., 'widgets', 'defaultWidgets').
|
|
1089
|
+
* @returns {void}
|
|
1090
|
+
*/
|
|
1091
|
+
registerWidgets(dashboardName, widgets = [], type = 'widgets') {
|
|
1092
|
+
const internalDashboardRegistryName = this.createInternalDashboardName(dashboardName);
|
|
1093
|
+
if (isArray(widgets)) {
|
|
1094
|
+
widgets.forEach((w) => this.registerWidgets(dashboardName, w, type));
|
|
1095
|
+
return;
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
const typeKey = pluralize(type);
|
|
1099
|
+
const newWidget = this._createDashboardWidget(widgets);
|
|
1100
|
+
const widgetRegistry = this.getWidgetRegistry(dashboardName, type);
|
|
1101
|
+
if (this.widgetRegistryHasWidget(widgetRegistry, newWidget)) {
|
|
1102
|
+
return;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
this[internalDashboardRegistryName][typeKey] = [...widgetRegistry, newWidget];
|
|
1106
|
+
this.trigger('widget.registered', newWidget);
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
/**
|
|
1110
|
+
* Checks if a widget with the same ID as the pending widget is already registered in the specified dashboard and type.
|
|
1111
|
+
*
|
|
1112
|
+
* @param {string} dashboardName - The name of the dashboard to check.
|
|
1113
|
+
* @param {Object} widgetPendingRegistry - The widget to check for in the registry.
|
|
1114
|
+
* @param {string} [type='widgets'] - The type of widget registry to check (e.g., 'widgets', 'defaultWidgets').
|
|
1115
|
+
* @returns {boolean} - `true` if a widget with the same ID is found in the registry; otherwise, `false`.
|
|
1116
|
+
*/
|
|
1117
|
+
didRegisterWidget(dashboardName, widgetPendingRegistry, type = 'widgets') {
|
|
1118
|
+
const widgetRegistry = this.getWidgetRegistry(dashboardName, type);
|
|
1119
|
+
return widgetRegistry.includes((widget) => widget.widgetId === widgetPendingRegistry.widgetId);
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
/**
|
|
1123
|
+
* Checks if a widget with the same ID as the pending widget exists in the provided widget registry instance.
|
|
1124
|
+
*
|
|
1125
|
+
* @param {Array} [widgetRegistryInstance=[]] - An array of widget objects to check.
|
|
1126
|
+
* @param {Object} widgetPendingRegistry - The widget to check for in the registry.
|
|
1127
|
+
* @returns {boolean} - `true` if a widget with the same ID is found in the registry; otherwise, `false`.
|
|
1128
|
+
*/
|
|
1129
|
+
widgetRegistryHasWidget(widgetRegistryInstance = [], widgetPendingRegistry) {
|
|
1130
|
+
return widgetRegistryInstance.includes((widget) => widget.widgetId === widgetPendingRegistry.widgetId);
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
/**
|
|
1134
|
+
* Registers widgets for the default 'dashboard' dashboard.
|
|
1135
|
+
*
|
|
1136
|
+
* @param {Array} [widgets=[]] - An array of widget objects to register.
|
|
1137
|
+
* @returns {void}
|
|
1138
|
+
*/
|
|
1139
|
+
registerDashboardWidgets(widgets = []) {
|
|
1140
|
+
this.registerWidgets('dashboard', widgets);
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
/**
|
|
1144
|
+
* Registers default widgets for the default 'dashboard' dashboard.
|
|
1145
|
+
*
|
|
1146
|
+
* @param {Array} [widgets=[]] - An array of default widget objects to register.
|
|
1147
|
+
* @returns {void}
|
|
1148
|
+
*/
|
|
1149
|
+
registerDefaultDashboardWidgets(widgets = []) {
|
|
1150
|
+
this.registerWidgets('dashboard', widgets, 'defaultWidgets');
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
/**
|
|
1154
|
+
* Registers default widgets for a specified dashboard.
|
|
1155
|
+
*
|
|
1156
|
+
* @param {String} dashboardName
|
|
1157
|
+
* @param {Array} [widgets=[]] - An array of default widget objects to register.
|
|
1158
|
+
* @returns {void}
|
|
1159
|
+
*/
|
|
1160
|
+
registerDefaultWidgets(dashboardName, widgets = []) {
|
|
1161
|
+
this.registerWidgets(dashboardName, widgets, 'defaultWidgets');
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
/**
|
|
1165
|
+
* Retrieves widgets for a specific dashboard.
|
|
1166
|
+
*
|
|
1167
|
+
* @param {string} dashboardName - The name of the dashboard to retrieve widgets for.
|
|
1168
|
+
* @param {string} [type='widgets'] - The type of widgets to retrieve (e.g., 'widgets', 'defaultWidgets').
|
|
1169
|
+
* @returns {Array} - An array of widgets for the specified dashboard and type.
|
|
1170
|
+
*/
|
|
1171
|
+
getWidgets(dashboardName, type = 'widgets') {
|
|
1172
|
+
const typeKey = pluralize(type);
|
|
1173
|
+
const internalDashboardRegistryName = this.createInternalDashboardName(dashboardName);
|
|
1174
|
+
return isArray(this[internalDashboardRegistryName][typeKey]) ? this[internalDashboardRegistryName][typeKey] : [];
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
/**
|
|
1178
|
+
* Retrieves default widgets for a specific dashboard.
|
|
1179
|
+
*
|
|
1180
|
+
* @param {string} dashboardName - The name of the dashboard to retrieve default widgets for.
|
|
1181
|
+
* @returns {Array} - An array of default widgets for the specified dashboard.
|
|
1182
|
+
*/
|
|
1183
|
+
getDefaultWidgets(dashboardName) {
|
|
1184
|
+
return this.getWidgets(dashboardName, 'defaultWidgets');
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
/**
|
|
1188
|
+
* Retrieves widgets for the default 'dashboard' dashboard.
|
|
1189
|
+
*
|
|
1190
|
+
* @returns {Array} - An array of widgets for the default 'dashboard' dashboard.
|
|
1191
|
+
*/
|
|
1192
|
+
getDashboardWidgets() {
|
|
1193
|
+
return this.getWidgets('dashboard');
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
/**
|
|
1197
|
+
* Retrieves default widgets for the default 'dashboard' dashboard.
|
|
1198
|
+
*
|
|
1199
|
+
* @returns {Array} - An array of default widgets for the default 'dashboard' dashboard.
|
|
824
1200
|
*/
|
|
825
1201
|
getDefaultDashboardWidgets() {
|
|
826
|
-
return this.
|
|
1202
|
+
return this.getWidgets('dashboard', 'defaultWidgets');
|
|
827
1203
|
}
|
|
828
1204
|
|
|
829
1205
|
/**
|
|
830
|
-
* Creates a dashboard
|
|
1206
|
+
* Creates an internal name for a dashboard based on its given name.
|
|
831
1207
|
*
|
|
832
|
-
* @param {
|
|
833
|
-
* @
|
|
1208
|
+
* @param {string} dashboardName - The name of the dashboard.
|
|
1209
|
+
* @returns {string} - The internal name for the dashboard, formatted as `${dashboardName}Widgets`.
|
|
1210
|
+
*/
|
|
1211
|
+
createInternalDashboardName(dashboardName) {
|
|
1212
|
+
return `${camelize(dashboardName.replace(/[^a-zA-Z0-9]/g, '-'))}Widgets`;
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
/**
|
|
1216
|
+
* Creates a new widget object from a widget definition.
|
|
1217
|
+
* If the component is a function, it is registered with the host application.
|
|
1218
|
+
*
|
|
1219
|
+
* @param {Object} widget - The widget definition.
|
|
1220
|
+
* @param {string} widget.widgetId - The unique ID of the widget.
|
|
834
1221
|
* @param {string} widget.name - The name of the widget.
|
|
835
|
-
* @param {string} widget.description -
|
|
836
|
-
* @param {string} widget.icon -
|
|
837
|
-
* @param {
|
|
838
|
-
* @param {Object} widget.grid_options - Grid options for the widget
|
|
839
|
-
* @param {Object} widget.options - Additional options for the widget.
|
|
840
|
-
* @returns {Object}
|
|
841
|
-
* @memberof UniverseService
|
|
1222
|
+
* @param {string} [widget.description] - A description of the widget.
|
|
1223
|
+
* @param {string} [widget.icon] - An icon for the widget.
|
|
1224
|
+
* @param {Function|string} [widget.component] - A component definition or name for the widget.
|
|
1225
|
+
* @param {Object} [widget.grid_options] - Grid options for the widget.
|
|
1226
|
+
* @param {Object} [widget.options] - Additional options for the widget.
|
|
1227
|
+
* @returns {Object} - The newly created widget object.
|
|
842
1228
|
*/
|
|
843
1229
|
_createDashboardWidget(widget) {
|
|
844
1230
|
// Extract properties from the widget object
|
|
@@ -872,16 +1258,31 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
872
1258
|
}
|
|
873
1259
|
|
|
874
1260
|
/**
|
|
875
|
-
*
|
|
876
|
-
*
|
|
1261
|
+
* Generates a unique hash for a widget component based on its function definition.
|
|
1262
|
+
* This method delegates the hash creation to the `_createHashFromFunctionDefinition` method.
|
|
877
1263
|
*
|
|
878
|
-
* @param {Function} component - The
|
|
879
|
-
* @returns {string}
|
|
880
|
-
* @memberof UniverseService
|
|
1264
|
+
* @param {Function} component - The function representing the widget component.
|
|
1265
|
+
* @returns {string} - The unique hash representing the widget component.
|
|
881
1266
|
*/
|
|
882
1267
|
_createUniqueWidgetHashFromDefinition(component) {
|
|
883
|
-
|
|
884
|
-
|
|
1268
|
+
return this._createHashFromFunctionDefinition(component);
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
/**
|
|
1272
|
+
* Creates a hash value from a function definition. The hash is generated based on the function's string representation.
|
|
1273
|
+
* If the function has a name, it returns that name. Otherwise, it converts the function's string representation
|
|
1274
|
+
* into a hash value. This is done by iterating over the characters of the string and performing a simple hash calculation.
|
|
1275
|
+
*
|
|
1276
|
+
* @param {Function} func - The function whose definition will be hashed.
|
|
1277
|
+
* @returns {string} - The hash value derived from the function's definition. If the function has a name, it is returned directly.
|
|
1278
|
+
*/
|
|
1279
|
+
_createHashFromFunctionDefinition(func) {
|
|
1280
|
+
if (func.name) {
|
|
1281
|
+
return func.name;
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
if (typeof func.toString === 'function') {
|
|
1285
|
+
let definition = func.toString();
|
|
885
1286
|
let hash = 0;
|
|
886
1287
|
for (let i = 0; i < definition.length; i++) {
|
|
887
1288
|
const char = definition.charCodeAt(i);
|
|
@@ -891,20 +1292,7 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
891
1292
|
return hash.toString(16);
|
|
892
1293
|
}
|
|
893
1294
|
|
|
894
|
-
return
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
/**
|
|
898
|
-
* Registers a new settings menu item.
|
|
899
|
-
*
|
|
900
|
-
* @method registerSettingsMenuItem
|
|
901
|
-
* @public
|
|
902
|
-
* @memberof UniverseService
|
|
903
|
-
* @param {String} title The title of the item
|
|
904
|
-
* @param {Object} options Additional options for the item
|
|
905
|
-
*/
|
|
906
|
-
registerSettingsMenuItem(title, options = {}) {
|
|
907
|
-
this.registerMenuItem('settings', title, options);
|
|
1295
|
+
return func.name;
|
|
908
1296
|
}
|
|
909
1297
|
|
|
910
1298
|
/**
|
|
@@ -985,6 +1373,7 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
985
1373
|
* @returns {Object} A new menu item object
|
|
986
1374
|
*/
|
|
987
1375
|
_createMenuItem(title, route, options = {}) {
|
|
1376
|
+
const intl = this._getOption(options, 'intl', null);
|
|
988
1377
|
const priority = this._getOption(options, 'priority', 9);
|
|
989
1378
|
const icon = this._getOption(options, 'icon', 'circle-dot');
|
|
990
1379
|
const items = this._getOption(options, 'items');
|
|
@@ -992,7 +1381,7 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
992
1381
|
const componentParams = this._getOption(options, 'componentParams', {});
|
|
993
1382
|
const renderComponentInPlace = this._getOption(options, 'renderComponentInPlace', false);
|
|
994
1383
|
const slug = this._getOption(options, 'slug', dasherize(title));
|
|
995
|
-
const view = this._getOption(options, 'view');
|
|
1384
|
+
const view = this._getOption(options, 'view', dasherize(title));
|
|
996
1385
|
const queryParams = this._getOption(options, 'queryParams', {});
|
|
997
1386
|
const index = this._getOption(options, 'index', 0);
|
|
998
1387
|
const onClick = this._getOption(options, 'onClick', null);
|
|
@@ -1007,6 +1396,11 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
1007
1396
|
const wrapperClass = this._getOption(options, 'wrapperClass', null);
|
|
1008
1397
|
const overwriteWrapperClass = this._getOption(options, 'overwriteWrapperClass', false);
|
|
1009
1398
|
const id = this._getOption(options, 'id', dasherize(title));
|
|
1399
|
+
const type = this._getOption(options, 'type', null);
|
|
1400
|
+
const buttonType = this._getOption(options, 'buttonType', null);
|
|
1401
|
+
const permission = this._getOption(options, 'permission', null);
|
|
1402
|
+
const disabled = this._getOption(options, 'disabled', null);
|
|
1403
|
+
const isLoading = this._getOption(options, 'isLoading', null);
|
|
1010
1404
|
|
|
1011
1405
|
// dasherize route segments
|
|
1012
1406
|
if (typeof route === 'string') {
|
|
@@ -1019,6 +1413,7 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
1019
1413
|
// @todo: create menu item class
|
|
1020
1414
|
const menuItem = {
|
|
1021
1415
|
id,
|
|
1416
|
+
intl,
|
|
1022
1417
|
title,
|
|
1023
1418
|
text: title,
|
|
1024
1419
|
route,
|
|
@@ -1043,8 +1438,21 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
1043
1438
|
inlineClass,
|
|
1044
1439
|
wrapperClass,
|
|
1045
1440
|
overwriteWrapperClass,
|
|
1441
|
+
type,
|
|
1442
|
+
buttonType,
|
|
1443
|
+
permission,
|
|
1444
|
+
disabled,
|
|
1445
|
+
isLoading,
|
|
1046
1446
|
};
|
|
1047
1447
|
|
|
1448
|
+
// make the menu item and universe object a default param of the onClick handler
|
|
1449
|
+
if (typeof onClick === 'function') {
|
|
1450
|
+
const universe = this;
|
|
1451
|
+
menuItem.onClick = function () {
|
|
1452
|
+
return onClick(menuItem, universe);
|
|
1453
|
+
};
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1048
1456
|
return menuItem;
|
|
1049
1457
|
}
|
|
1050
1458
|
|
|
@@ -1120,6 +1528,7 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
1120
1528
|
engineInstance.register(`component:${dasherize(componentClass.name.replace('Component', ''))}`, componentClass);
|
|
1121
1529
|
if (options && typeof options.registerAs === 'string') {
|
|
1122
1530
|
engineInstance.register(`component:${options.registerAs}`, componentClass);
|
|
1531
|
+
this.trigger('component.registered', componentClass, engineInstance);
|
|
1123
1532
|
}
|
|
1124
1533
|
}
|
|
1125
1534
|
}
|
|
@@ -1157,6 +1566,7 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
1157
1566
|
if (sharedService) {
|
|
1158
1567
|
// Register the service in the target engine
|
|
1159
1568
|
targetEngineInstance.register(`service:${serviceName}`, sharedService, { instantiate: false });
|
|
1569
|
+
this.trigger('service.registered', serviceName, targetEngineInstance);
|
|
1160
1570
|
}
|
|
1161
1571
|
}
|
|
1162
1572
|
}
|
|
@@ -1275,6 +1685,7 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
1275
1685
|
// store loaded instance to engineInstances for booting
|
|
1276
1686
|
engineInstances[name][instanceId] = engineInstance;
|
|
1277
1687
|
|
|
1688
|
+
this.trigger('engine.loaded', engineInstance);
|
|
1278
1689
|
return engineInstance.boot().then(() => {
|
|
1279
1690
|
return engineInstance;
|
|
1280
1691
|
});
|
|
@@ -1340,6 +1751,35 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
1340
1751
|
return null;
|
|
1341
1752
|
}
|
|
1342
1753
|
|
|
1754
|
+
/**
|
|
1755
|
+
* Returns a promise that resolves when the `enginesBooted` property is set to true.
|
|
1756
|
+
* The promise will reject with a timeout error if the property does not become true within the specified timeout.
|
|
1757
|
+
*
|
|
1758
|
+
* @function booting
|
|
1759
|
+
* @returns {Promise<void>} A promise that resolves when `enginesBooted` is true or rejects with an error after a timeout.
|
|
1760
|
+
*/
|
|
1761
|
+
booting() {
|
|
1762
|
+
return new Promise((resolve, reject) => {
|
|
1763
|
+
const check = () => {
|
|
1764
|
+
if (this.enginesBooted === true) {
|
|
1765
|
+
this.trigger('booted');
|
|
1766
|
+
clearInterval(intervalId);
|
|
1767
|
+
resolve();
|
|
1768
|
+
}
|
|
1769
|
+
};
|
|
1770
|
+
|
|
1771
|
+
const intervalId = setInterval(check, 100);
|
|
1772
|
+
later(
|
|
1773
|
+
this,
|
|
1774
|
+
() => {
|
|
1775
|
+
clearInterval(intervalId);
|
|
1776
|
+
reject(new Error('Timeout: Universe was unable to boot engines'));
|
|
1777
|
+
},
|
|
1778
|
+
5000
|
|
1779
|
+
);
|
|
1780
|
+
});
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1343
1783
|
/**
|
|
1344
1784
|
* Boot all installed engines, ensuring dependencies are resolved.
|
|
1345
1785
|
*
|
|
@@ -1352,7 +1792,7 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
1352
1792
|
* @param {ApplicationInstance|null} owner - The Ember ApplicationInstance that owns the engines.
|
|
1353
1793
|
* @return {void}
|
|
1354
1794
|
*/
|
|
1355
|
-
bootEngines(owner = null) {
|
|
1795
|
+
async bootEngines(owner = null) {
|
|
1356
1796
|
const booted = [];
|
|
1357
1797
|
const pending = [];
|
|
1358
1798
|
const additionalCoreExtensions = config.APP.extensions ?? [];
|
|
@@ -1362,10 +1802,13 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
1362
1802
|
owner = getOwner(this);
|
|
1363
1803
|
}
|
|
1364
1804
|
|
|
1805
|
+
// Set application instance
|
|
1806
|
+
this.setApplicationInstance(owner);
|
|
1807
|
+
|
|
1365
1808
|
const tryBootEngine = (extension) => {
|
|
1366
|
-
this.loadEngine(extension.name).then((engineInstance) => {
|
|
1809
|
+
return this.loadEngine(extension.name).then((engineInstance) => {
|
|
1367
1810
|
if (engineInstance.base && engineInstance.base.setupExtension) {
|
|
1368
|
-
if (
|
|
1811
|
+
if (this.bootedExtensions.includes(extension.name)) {
|
|
1369
1812
|
return;
|
|
1370
1813
|
}
|
|
1371
1814
|
|
|
@@ -1379,6 +1822,8 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
1379
1822
|
|
|
1380
1823
|
engineInstance.base.setupExtension(owner, engineInstance, this);
|
|
1381
1824
|
booted.push(extension.name);
|
|
1825
|
+
this.bootedExtensions.pushObject(extension.name);
|
|
1826
|
+
this.trigger('extension.booted', extension);
|
|
1382
1827
|
debug(`Booted : ${extension.name}`);
|
|
1383
1828
|
|
|
1384
1829
|
// Try booting pending engines again
|
|
@@ -1391,7 +1836,7 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
1391
1836
|
const stillPending = [];
|
|
1392
1837
|
|
|
1393
1838
|
pending.forEach(({ extension, engineInstance }) => {
|
|
1394
|
-
if (
|
|
1839
|
+
if (this.bootedExtensions.includes(extension.name)) {
|
|
1395
1840
|
return;
|
|
1396
1841
|
}
|
|
1397
1842
|
|
|
@@ -1401,6 +1846,8 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
1401
1846
|
if (allDependenciesBooted) {
|
|
1402
1847
|
engineInstance.base.setupExtension(owner, engineInstance, this);
|
|
1403
1848
|
booted.push(extension.name);
|
|
1849
|
+
this.bootedExtensions.pushObject(extension.name);
|
|
1850
|
+
this.trigger('extension.booted', extension);
|
|
1404
1851
|
debug(`Booted : ${extension.name}`);
|
|
1405
1852
|
} else {
|
|
1406
1853
|
stillPending.push({ extension, engineInstance });
|
|
@@ -1414,10 +1861,14 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
1414
1861
|
pending.push(...stillPending);
|
|
1415
1862
|
};
|
|
1416
1863
|
|
|
1417
|
-
loadInstalledExtensions(additionalCoreExtensions).then((extensions) => {
|
|
1418
|
-
extensions.
|
|
1419
|
-
|
|
1420
|
-
|
|
1864
|
+
return loadInstalledExtensions(additionalCoreExtensions).then(async (extensions) => {
|
|
1865
|
+
for (let i = 0; i < extensions.length; i++) {
|
|
1866
|
+
const extension = extensions[i];
|
|
1867
|
+
await tryBootEngine(extension);
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1870
|
+
this.runBootCallbacks(owner);
|
|
1871
|
+
this.enginesBooted = true;
|
|
1421
1872
|
});
|
|
1422
1873
|
}
|
|
1423
1874
|
|
|
@@ -1443,8 +1894,11 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
1443
1894
|
owner = getOwner(this);
|
|
1444
1895
|
}
|
|
1445
1896
|
|
|
1897
|
+
// Set application instance
|
|
1898
|
+
this.setApplicationInstance(owner);
|
|
1899
|
+
|
|
1446
1900
|
const tryBootEngine = (extension) => {
|
|
1447
|
-
this.loadEngine(extension.name).then((engineInstance) => {
|
|
1901
|
+
return this.loadEngine(extension.name).then((engineInstance) => {
|
|
1448
1902
|
if (engineInstance.base && engineInstance.base.setupExtension) {
|
|
1449
1903
|
const engineDependencies = getWithDefault(engineInstance.base, 'engineDependencies', []);
|
|
1450
1904
|
|
|
@@ -1458,6 +1912,8 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
1458
1912
|
|
|
1459
1913
|
engineInstance.base.setupExtension(owner, engineInstance, this);
|
|
1460
1914
|
booted.push(extension.name);
|
|
1915
|
+
this.bootedExtensions.pushObject(extension.name);
|
|
1916
|
+
this.trigger('extension.booted', extension);
|
|
1461
1917
|
debug(`Booted : ${extension.name}`);
|
|
1462
1918
|
|
|
1463
1919
|
// Try booting pending engines again
|
|
@@ -1476,6 +1932,8 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
1476
1932
|
if (allDependenciesBooted) {
|
|
1477
1933
|
engineInstance.base.setupExtension(owner, engineInstance, this);
|
|
1478
1934
|
booted.push(extension.name);
|
|
1935
|
+
this.bootedExtensions.pushObject(extension.name);
|
|
1936
|
+
this.trigger('extension.booted', extension);
|
|
1479
1937
|
debug(`Booted : ${extension.name}`);
|
|
1480
1938
|
} else {
|
|
1481
1939
|
stillPending.push({ extension, engineInstance });
|
|
@@ -1489,13 +1947,72 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
1489
1947
|
pending.push(...stillPending);
|
|
1490
1948
|
};
|
|
1491
1949
|
|
|
1492
|
-
loadExtensions().then((extensions) => {
|
|
1493
|
-
extensions.
|
|
1494
|
-
|
|
1495
|
-
|
|
1950
|
+
return loadExtensions().then(async (extensions) => {
|
|
1951
|
+
for (let i = 0; i < extensions.length; i++) {
|
|
1952
|
+
const extension = extensions[i];
|
|
1953
|
+
await tryBootEngine(extension);
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
this.runBootCallbacks(owner);
|
|
1957
|
+
this.enginesBooted = true;
|
|
1496
1958
|
});
|
|
1497
1959
|
}
|
|
1498
1960
|
|
|
1961
|
+
/**
|
|
1962
|
+
* Checks if an extension has been booted.
|
|
1963
|
+
*
|
|
1964
|
+
* @param {String} name
|
|
1965
|
+
* @return {Boolean}
|
|
1966
|
+
* @memberof UniverseService
|
|
1967
|
+
*/
|
|
1968
|
+
didBootEngine(name) {
|
|
1969
|
+
return this.bootedExtensions.includes(name);
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1972
|
+
/**
|
|
1973
|
+
* Registers a callback function to be executed after the engine boot process completes.
|
|
1974
|
+
*
|
|
1975
|
+
* This method ensures that the `bootCallbacks` array is initialized. It then adds the provided
|
|
1976
|
+
* callback to this array. The callbacks registered will be invoked in sequence after the engine
|
|
1977
|
+
* has finished booting, using the `runBootCallbacks` method.
|
|
1978
|
+
*
|
|
1979
|
+
* @param {Function} callback - The function to execute after the engine boots.
|
|
1980
|
+
* The callback should accept two arguments:
|
|
1981
|
+
* - `{Object} universe` - The universe context or environment.
|
|
1982
|
+
* - `{Object} appInstance` - The application instance.
|
|
1983
|
+
*/
|
|
1984
|
+
afterBoot(callback) {
|
|
1985
|
+
if (!isArray(this.bootCallbacks)) {
|
|
1986
|
+
this.bootCallbacks = [];
|
|
1987
|
+
}
|
|
1988
|
+
|
|
1989
|
+
this.bootCallbacks.pushObject(callback);
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
/**
|
|
1993
|
+
* Executes all registered engine boot callbacks in the order they were added.
|
|
1994
|
+
*
|
|
1995
|
+
* This method iterates over the `bootCallbacks` array and calls each callback function,
|
|
1996
|
+
* passing in the `universe` and `appInstance` parameters. After all callbacks have been
|
|
1997
|
+
* executed, it optionally calls a completion function `onComplete`.
|
|
1998
|
+
*
|
|
1999
|
+
* @param {Object} appInstance - The application instance to pass to each callback.
|
|
2000
|
+
* @param {Function} [onComplete] - Optional. A function to call after all boot callbacks have been executed.
|
|
2001
|
+
* It does not receive any arguments.
|
|
2002
|
+
*/
|
|
2003
|
+
runBootCallbacks(appInstance, onComplete = null) {
|
|
2004
|
+
for (let i = 0; i < this.bootCallbacks.length; i++) {
|
|
2005
|
+
const callback = this.bootCallbacks[i];
|
|
2006
|
+
if (typeof callback === 'function') {
|
|
2007
|
+
callback(this, appInstance);
|
|
2008
|
+
}
|
|
2009
|
+
}
|
|
2010
|
+
|
|
2011
|
+
if (typeof onComplete === 'function') {
|
|
2012
|
+
onComplete();
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
|
|
1499
2016
|
/**
|
|
1500
2017
|
* Alias for intl service `t`
|
|
1501
2018
|
*
|