@cccsaurora/howler-ui 2.14.0-dev.228 → 2.14.0-dev.245
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/commons/components/app/AppConfigs.d.ts +9 -3
- package/components/app/App.js +1 -0
- package/components/app/providers/FavouritesProvider.js +2 -2
- package/components/hooks/useMyPreferences.js +208 -193
- package/components/hooks/useMySitemap.js +3 -1
- package/components/routes/hits/search/InformationPane.js +3 -3
- package/components/routes/hits/view/HitViewer.js +1 -1
- package/package.json +102 -102
- package/plugins/HowlerPlugin.d.ts +53 -1
- package/plugins/HowlerPlugin.js +146 -14
- package/plugins/store.d.ts +51 -14
- package/plugins/store.js +36 -21
- package/utils/menuUtils.d.ts +89 -0
- package/utils/menuUtils.js +243 -0
package/plugins/store.js
CHANGED
|
@@ -6,6 +6,12 @@ export class HitEvent extends Event {
|
|
|
6
6
|
this.hit = hit;
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
|
+
export var MainMenuInsertOperation;
|
|
10
|
+
(function (MainMenuInsertOperation) {
|
|
11
|
+
MainMenuInsertOperation["Insert"] = "INSERT";
|
|
12
|
+
MainMenuInsertOperation["InsertAfter"] = "AFTER";
|
|
13
|
+
MainMenuInsertOperation["InsertBefore"] = "BEFORE";
|
|
14
|
+
})(MainMenuInsertOperation || (MainMenuInsertOperation = {}));
|
|
9
15
|
class HowlerPluginStore {
|
|
10
16
|
_pluginStore = createPluginStore();
|
|
11
17
|
plugins = [];
|
|
@@ -14,6 +20,9 @@ class HowlerPluginStore {
|
|
|
14
20
|
_operations = [];
|
|
15
21
|
_userMenuItems = [];
|
|
16
22
|
_adminMenuItems = [];
|
|
23
|
+
_mainMenuOperations = [];
|
|
24
|
+
_routes = [];
|
|
25
|
+
_sitemaps = [];
|
|
17
26
|
install(plugin) {
|
|
18
27
|
console.log(`Installing plugin ${plugin.getPluginName()} by ${plugin.author}`);
|
|
19
28
|
this.plugins.push(plugin.name);
|
|
@@ -33,6 +42,21 @@ class HowlerPluginStore {
|
|
|
33
42
|
this._pivotFormats.push(format);
|
|
34
43
|
return true;
|
|
35
44
|
}
|
|
45
|
+
addUserMenuItem(menuItem) {
|
|
46
|
+
this._userMenuItems.push(menuItem);
|
|
47
|
+
}
|
|
48
|
+
addAdminMenuItem(menuItem) {
|
|
49
|
+
this._adminMenuItems.push(menuItem);
|
|
50
|
+
}
|
|
51
|
+
addMainMenuItem(menuOperation) {
|
|
52
|
+
this._mainMenuOperations.push(menuOperation);
|
|
53
|
+
}
|
|
54
|
+
addRoute(route) {
|
|
55
|
+
this._routes.push(route);
|
|
56
|
+
}
|
|
57
|
+
addSitemap(sitemap) {
|
|
58
|
+
this._sitemaps.push(sitemap);
|
|
59
|
+
}
|
|
36
60
|
addOperation(format) {
|
|
37
61
|
if (this._operations.includes(format)) {
|
|
38
62
|
return false;
|
|
@@ -40,24 +64,6 @@ class HowlerPluginStore {
|
|
|
40
64
|
this._operations.push(format);
|
|
41
65
|
return true;
|
|
42
66
|
}
|
|
43
|
-
/**
|
|
44
|
-
* Adds a single menu item to the User Menu group under the Avatar Menu,
|
|
45
|
-
* items are added before the 'Settings' and 'Logout' menu items.
|
|
46
|
-
*
|
|
47
|
-
* @param menuItem Menu Item {i18nKey, route, icon}
|
|
48
|
-
*/
|
|
49
|
-
addUserMenuItem(menuItem) {
|
|
50
|
-
this._userMenuItems.push(menuItem);
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Adds a single menu item to the Admin Menu group under the Avatar Menu,
|
|
54
|
-
* items are added to the end of the existing Admin menu items.
|
|
55
|
-
*
|
|
56
|
-
* @param menuItem Menu Item {i18nKey, route, icon}
|
|
57
|
-
*/
|
|
58
|
-
addAdminMenuItem(menuItem) {
|
|
59
|
-
this._adminMenuItems.push(menuItem);
|
|
60
|
-
}
|
|
61
67
|
get leadFormats() {
|
|
62
68
|
return this._leadFormats;
|
|
63
69
|
}
|
|
@@ -67,15 +73,24 @@ class HowlerPluginStore {
|
|
|
67
73
|
get operations() {
|
|
68
74
|
return this._operations;
|
|
69
75
|
}
|
|
70
|
-
get pluginStore() {
|
|
71
|
-
return this._pluginStore;
|
|
72
|
-
}
|
|
73
76
|
get userMenuItems() {
|
|
74
77
|
return this._userMenuItems;
|
|
75
78
|
}
|
|
76
79
|
get adminMenuItems() {
|
|
77
80
|
return this._adminMenuItems;
|
|
78
81
|
}
|
|
82
|
+
get mainMenuOperations() {
|
|
83
|
+
return this._mainMenuOperations;
|
|
84
|
+
}
|
|
85
|
+
get routes() {
|
|
86
|
+
return this._routes;
|
|
87
|
+
}
|
|
88
|
+
get sitemaps() {
|
|
89
|
+
return this._sitemaps;
|
|
90
|
+
}
|
|
91
|
+
get pluginStore() {
|
|
92
|
+
return this._pluginStore;
|
|
93
|
+
}
|
|
79
94
|
}
|
|
80
95
|
const howlerPluginStore = new HowlerPluginStore();
|
|
81
96
|
export default howlerPluginStore;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { AppLeftNavElement, AppLeftNavItem } from '../commons/components/app/AppConfigs';
|
|
2
|
+
declare class AppMenuBuilder {
|
|
3
|
+
private items;
|
|
4
|
+
private indexMap;
|
|
5
|
+
constructor(defaultMenu: AppLeftNavElement[]);
|
|
6
|
+
/**
|
|
7
|
+
* Applies a collection of Menu Operation objects created by the plugin system
|
|
8
|
+
*
|
|
9
|
+
* @param operations Operations created by the plugin system
|
|
10
|
+
*/
|
|
11
|
+
applyOperations(operations: {
|
|
12
|
+
operation: string;
|
|
13
|
+
targetId: string;
|
|
14
|
+
item: AppLeftNavElement;
|
|
15
|
+
}[]): void;
|
|
16
|
+
/**
|
|
17
|
+
* Get the completed menu structure
|
|
18
|
+
*/
|
|
19
|
+
get menu(): AppLeftNavElement[];
|
|
20
|
+
/**
|
|
21
|
+
* Insert provided menu item at the menu object identified by targetId.
|
|
22
|
+
*
|
|
23
|
+
* If the target menu is a group then item will be placed at end of sub items
|
|
24
|
+
*
|
|
25
|
+
* If the target menu is a standard item then group will be created and new item added, warning this removes
|
|
26
|
+
* the route from the new group parent item, be sure to add it back.
|
|
27
|
+
*
|
|
28
|
+
* If the target is 'root' then item will be added to end of root menu
|
|
29
|
+
*
|
|
30
|
+
* @param targetId Identifier of menu to insert to
|
|
31
|
+
* @param item Menu Item to insert
|
|
32
|
+
*/
|
|
33
|
+
insert(targetId: string, item: AppLeftNavElement): void;
|
|
34
|
+
/**
|
|
35
|
+
* Insert provided menu item before the menu object identified by targetId.
|
|
36
|
+
*
|
|
37
|
+
* @param targetId Identifier of menu to insert to
|
|
38
|
+
* @param item Menu Item to insert
|
|
39
|
+
*/
|
|
40
|
+
insertBefore(targetId: string, item: AppLeftNavElement): void;
|
|
41
|
+
/**
|
|
42
|
+
* Insert provided menu item after the menu object identified by targetId.
|
|
43
|
+
*
|
|
44
|
+
* @param targetId Identifier of menu to insert to
|
|
45
|
+
* @param item Menu Item to insert
|
|
46
|
+
*/
|
|
47
|
+
insertAfter(targetId: string, item: AppLeftNavElement): void;
|
|
48
|
+
/**
|
|
49
|
+
* Locates menu location in menu structure by menu id.
|
|
50
|
+
*
|
|
51
|
+
* @param id Menu Id to search for
|
|
52
|
+
* @return {index: number, subIndex: number} A dictionary containing indexes needed to access Menu Item
|
|
53
|
+
*/
|
|
54
|
+
indexOfMenuId(id: string): {
|
|
55
|
+
index: number;
|
|
56
|
+
subIndex?: number;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Grabs a menu by indexes, helper function to account for an index of -1
|
|
60
|
+
* to represent the root menu
|
|
61
|
+
*
|
|
62
|
+
* @param index First level index
|
|
63
|
+
* @param subIndex Second level index
|
|
64
|
+
* @return {} Menu item
|
|
65
|
+
*/
|
|
66
|
+
menuFromIndex(index: number, subIndex?: number): AppLeftNavElement[] | AppLeftNavElement | AppLeftNavItem;
|
|
67
|
+
/**
|
|
68
|
+
* Determine if provided element is a group element
|
|
69
|
+
*
|
|
70
|
+
* @param elem Element to check
|
|
71
|
+
* @private
|
|
72
|
+
*/
|
|
73
|
+
private isGroupElement;
|
|
74
|
+
/**
|
|
75
|
+
* Determine if provided element is an item element
|
|
76
|
+
*
|
|
77
|
+
* @param elem Element to check
|
|
78
|
+
* @private
|
|
79
|
+
*/
|
|
80
|
+
private isItemElement;
|
|
81
|
+
/**
|
|
82
|
+
* Creates a flat list of menu items and subitems by menu id
|
|
83
|
+
* for quick lookup.
|
|
84
|
+
*
|
|
85
|
+
* @private
|
|
86
|
+
*/
|
|
87
|
+
private updateMenuMap;
|
|
88
|
+
}
|
|
89
|
+
export default AppMenuBuilder;
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { MainMenuInsertOperation } from '../plugins/store';
|
|
2
|
+
import { isNil } from 'lodash-es';
|
|
3
|
+
class AppMenuBuilder {
|
|
4
|
+
items;
|
|
5
|
+
indexMap;
|
|
6
|
+
constructor(defaultMenu) {
|
|
7
|
+
this.items = defaultMenu;
|
|
8
|
+
this.updateMenuMap();
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Applies a collection of Menu Operation objects created by the plugin system
|
|
12
|
+
*
|
|
13
|
+
* @param operations Operations created by the plugin system
|
|
14
|
+
*/
|
|
15
|
+
applyOperations(operations) {
|
|
16
|
+
for (const operation of operations) {
|
|
17
|
+
switch (operation.operation) {
|
|
18
|
+
case MainMenuInsertOperation.Insert:
|
|
19
|
+
// Inserts at end or adds to sub-elements
|
|
20
|
+
this.insert(operation.targetId, operation.item);
|
|
21
|
+
break;
|
|
22
|
+
case MainMenuInsertOperation.InsertBefore:
|
|
23
|
+
// Inserts before target element
|
|
24
|
+
this.insertBefore(operation.targetId, operation.item);
|
|
25
|
+
break;
|
|
26
|
+
case MainMenuInsertOperation.InsertAfter:
|
|
27
|
+
// Inserts after target element
|
|
28
|
+
this.insertAfter(operation.targetId, operation.item);
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
this.updateMenuMap();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Get the completed menu structure
|
|
36
|
+
*/
|
|
37
|
+
get menu() {
|
|
38
|
+
return this.items;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Insert provided menu item at the menu object identified by targetId.
|
|
42
|
+
*
|
|
43
|
+
* If the target menu is a group then item will be placed at end of sub items
|
|
44
|
+
*
|
|
45
|
+
* If the target menu is a standard item then group will be created and new item added, warning this removes
|
|
46
|
+
* the route from the new group parent item, be sure to add it back.
|
|
47
|
+
*
|
|
48
|
+
* If the target is 'root' then item will be added to end of root menu
|
|
49
|
+
*
|
|
50
|
+
* @param targetId Identifier of menu to insert to
|
|
51
|
+
* @param item Menu Item to insert
|
|
52
|
+
*/
|
|
53
|
+
insert(targetId, item) {
|
|
54
|
+
const menuLocation = this.indexOfMenuId(targetId);
|
|
55
|
+
const target = this.menuFromIndex(menuLocation.index, menuLocation.subIndex);
|
|
56
|
+
if (!Array.isArray(target) && this.isGroupElement(target)) {
|
|
57
|
+
if (item.type === 'divider') {
|
|
58
|
+
console.warn(`Skipping DIVIDER Operation: INSERT on Target: ${targetId}, Dividers cannot be inserted to sub-menus`);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const group = target.element;
|
|
62
|
+
const newItem = { ...item.element, nested: true };
|
|
63
|
+
group.items = [...group.items, newItem];
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (Array.isArray(target)) {
|
|
67
|
+
target.push(item);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (menuLocation.index !== -1 && isNil(menuLocation.subIndex)) {
|
|
71
|
+
if (item.type === 'divider') {
|
|
72
|
+
console.warn(`Skipping DIVIDER Operation: INSERT on Target: ${targetId}, Dividers cannot be inserted to sub-menus`);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (!this.isItemElement(target)) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const header = target.element;
|
|
79
|
+
const inserted = { ...item.element, nested: true };
|
|
80
|
+
const newGroup = {
|
|
81
|
+
type: 'group',
|
|
82
|
+
element: {
|
|
83
|
+
id: header.id,
|
|
84
|
+
open: true,
|
|
85
|
+
i18nKey: header.i18nKey,
|
|
86
|
+
title: header.text,
|
|
87
|
+
userPropValidators: header.userPropValidators,
|
|
88
|
+
icon: header.icon,
|
|
89
|
+
items: [inserted]
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
this.items[menuLocation.index] = newGroup;
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Insert provided menu item before the menu object identified by targetId.
|
|
98
|
+
*
|
|
99
|
+
* @param targetId Identifier of menu to insert to
|
|
100
|
+
* @param item Menu Item to insert
|
|
101
|
+
*/
|
|
102
|
+
insertBefore(targetId, item) {
|
|
103
|
+
const menuLocation = this.indexOfMenuId(targetId);
|
|
104
|
+
if (!isNil(menuLocation.subIndex)) {
|
|
105
|
+
if (item.type === 'divider') {
|
|
106
|
+
console.warn(`Skipping DIVIDER Operation: INSERT on Target: ${targetId}, Dividers cannot be inserted to sub-menus`);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const parentElement = this.menuFromIndex(menuLocation.index);
|
|
110
|
+
if (!Array.isArray(parentElement) && this.isGroupElement(parentElement)) {
|
|
111
|
+
const group = parentElement.element;
|
|
112
|
+
const newItem = { ...item.element, nested: true };
|
|
113
|
+
group.items = [
|
|
114
|
+
...group.items.slice(0, menuLocation.subIndex),
|
|
115
|
+
newItem,
|
|
116
|
+
...group.items.slice(menuLocation.subIndex)
|
|
117
|
+
];
|
|
118
|
+
}
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
// Root level insertion before target index
|
|
122
|
+
if (menuLocation.index < 0) {
|
|
123
|
+
menuLocation.index = 0;
|
|
124
|
+
}
|
|
125
|
+
this.items = [...this.items.slice(0, menuLocation.index), item, ...this.items.slice(menuLocation.index)];
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Insert provided menu item after the menu object identified by targetId.
|
|
129
|
+
*
|
|
130
|
+
* @param targetId Identifier of menu to insert to
|
|
131
|
+
* @param item Menu Item to insert
|
|
132
|
+
*/
|
|
133
|
+
insertAfter(targetId, item) {
|
|
134
|
+
const menuLocation = this.indexOfMenuId(targetId);
|
|
135
|
+
if (!isNil(menuLocation.subIndex)) {
|
|
136
|
+
if (item.type === 'divider') {
|
|
137
|
+
console.warn(`Skipping DIVIDER Operation: INSERT on Target: ${targetId}, Dividers cannot be inserted to sub-menus`);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const parentElement = this.menuFromIndex(menuLocation.index);
|
|
141
|
+
if (!Array.isArray(parentElement) && this.isGroupElement(parentElement)) {
|
|
142
|
+
const group = parentElement.element;
|
|
143
|
+
const newItem = { ...item.element, nested: true };
|
|
144
|
+
group.items = [
|
|
145
|
+
...group.items.slice(0, menuLocation.subIndex + 1),
|
|
146
|
+
newItem,
|
|
147
|
+
...group.items.slice(menuLocation.subIndex + 1)
|
|
148
|
+
];
|
|
149
|
+
}
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
// Root level insertion after target index
|
|
153
|
+
if (menuLocation.index < 0) {
|
|
154
|
+
menuLocation.index = this.items.length;
|
|
155
|
+
}
|
|
156
|
+
this.items = [...this.items.slice(0, menuLocation.index + 1), item, ...this.items.slice(menuLocation.index + 1)];
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Locates menu location in menu structure by menu id.
|
|
160
|
+
*
|
|
161
|
+
* @param id Menu Id to search for
|
|
162
|
+
* @return {index: number, subIndex: number} A dictionary containing indexes needed to access Menu Item
|
|
163
|
+
*/
|
|
164
|
+
indexOfMenuId(id) {
|
|
165
|
+
if (id === 'root') {
|
|
166
|
+
// Root item so return entire menu
|
|
167
|
+
return { index: -1 };
|
|
168
|
+
}
|
|
169
|
+
else if (id in this.indexMap) {
|
|
170
|
+
// Item exists, check if it's a subitem
|
|
171
|
+
if ('parent' in this.indexMap[id]) {
|
|
172
|
+
return { index: this.indexMap[id].parent, subIndex: this.indexMap[id].index };
|
|
173
|
+
}
|
|
174
|
+
return { index: this.indexMap[id].index };
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
throw new Error(`Menu element with id of '${id}' not found.`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Grabs a menu by indexes, helper function to account for an index of -1
|
|
182
|
+
* to represent the root menu
|
|
183
|
+
*
|
|
184
|
+
* @param index First level index
|
|
185
|
+
* @param subIndex Second level index
|
|
186
|
+
* @return {} Menu item
|
|
187
|
+
*/
|
|
188
|
+
menuFromIndex(index, subIndex) {
|
|
189
|
+
if (index === -1) {
|
|
190
|
+
return this.items;
|
|
191
|
+
}
|
|
192
|
+
if (isNil(subIndex)) {
|
|
193
|
+
return this.items[index];
|
|
194
|
+
}
|
|
195
|
+
const menuItem = this.items[index];
|
|
196
|
+
if (menuItem.type === 'group') {
|
|
197
|
+
return menuItem.element.items[subIndex];
|
|
198
|
+
}
|
|
199
|
+
throw new Error(`Menu item at index ${index} is not a group and does not have sub-items.`);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Determine if provided element is a group element
|
|
203
|
+
*
|
|
204
|
+
* @param elem Element to check
|
|
205
|
+
* @private
|
|
206
|
+
*/
|
|
207
|
+
isGroupElement(elem) {
|
|
208
|
+
return !!elem && typeof elem === 'object' && elem.type === 'group';
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Determine if provided element is an item element
|
|
212
|
+
*
|
|
213
|
+
* @param elem Element to check
|
|
214
|
+
* @private
|
|
215
|
+
*/
|
|
216
|
+
isItemElement(elem) {
|
|
217
|
+
return !!elem && typeof elem === 'object' && elem.type === 'item';
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Creates a flat list of menu items and subitems by menu id
|
|
221
|
+
* for quick lookup.
|
|
222
|
+
*
|
|
223
|
+
* @private
|
|
224
|
+
*/
|
|
225
|
+
updateMenuMap() {
|
|
226
|
+
const indexMap = {};
|
|
227
|
+
for (let index = 0; index < this.items.length; index++) {
|
|
228
|
+
const menuItem = this.items[index];
|
|
229
|
+
if (menuItem.type === 'divider') {
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
indexMap[menuItem.element.id] = { index };
|
|
233
|
+
if (menuItem.type === 'group') {
|
|
234
|
+
for (let subIndex = 0; subIndex < menuItem.element.items.length; subIndex++) {
|
|
235
|
+
const subMenuItem = menuItem.element.items[subIndex];
|
|
236
|
+
indexMap[subMenuItem.id] = { index: subIndex, parent: index };
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
this.indexMap = indexMap;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
export default AppMenuBuilder;
|