@fleetbase/ember-core 0.2.3 → 0.2.5
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/adapters/application.js +29 -5
- package/addon/initializers/load-socketcluster-client.js +8 -3
- package/addon/services/app-cache.js +2 -1
- package/addon/services/current-user.js +11 -0
- package/addon/services/fetch.js +26 -16
- package/addon/services/theme.js +1 -1
- package/addon/services/universe.js +87 -7
- package/index.js +2 -2
- package/package.json +3 -2
|
@@ -7,6 +7,7 @@ import { get } from '@ember/object';
|
|
|
7
7
|
import { isBlank } from '@ember/utils';
|
|
8
8
|
import { dasherize } from '@ember/string';
|
|
9
9
|
import { pluralize } from 'ember-inflector';
|
|
10
|
+
import { decompress as decompressJson } from 'compress-json';
|
|
10
11
|
import getUserOptions from '../utils/get-user-options';
|
|
11
12
|
import config from 'ember-get-config';
|
|
12
13
|
|
|
@@ -161,14 +162,37 @@ export default class ApplicationAdapter extends RESTAdapter {
|
|
|
161
162
|
* It then checks if the response is invalid based on the status code. If invalid, it constructs an `AdapterError` with the normalized errors and detailed message.
|
|
162
163
|
* For valid responses, it delegates the handling to the superclass's `handleResponse` method.
|
|
163
164
|
*/
|
|
164
|
-
handleResponse(status, headers, payload) {
|
|
165
|
+
async handleResponse(status, headers, payload, requestData) {
|
|
166
|
+
let decompressedPayload = this.decompressPayload(payload, headers);
|
|
165
167
|
let errors = this.normalizeErrorResponse(status, headers, payload);
|
|
166
|
-
let detailedMessage = this.generatedDetailedMessage(...arguments);
|
|
167
|
-
|
|
168
168
|
if (this.isInvalid(status, headers, payload)) {
|
|
169
|
-
return new AdapterError(errors
|
|
169
|
+
return new AdapterError(errors);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return super.handleResponse(status, headers, decompressedPayload, requestData);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Decompresses the response payload if it's marked as compressed in the response headers.
|
|
177
|
+
*
|
|
178
|
+
* This method checks the response headers for a specific 'x-compressed-json' flag.
|
|
179
|
+
* If this flag is set, indicating that the response payload is compressed, the method
|
|
180
|
+
* decompresses the payload. The decompressed payload is then parsed as JSON and returned.
|
|
181
|
+
* If the payload is not compressed, it is returned as is.
|
|
182
|
+
*
|
|
183
|
+
* @param {object} payload - The original payload of the response.
|
|
184
|
+
* @param {object} headers - The headers of the response, used to check if the payload is compressed.
|
|
185
|
+
* @return {object} The decompressed payload if it was compressed, or the original payload otherwise.
|
|
186
|
+
*/
|
|
187
|
+
async decompressPayload(payload, headers) {
|
|
188
|
+
// Check if the response is compressed
|
|
189
|
+
if (headers['x-compressed-json'] === '1' || headers['x-compressed-json'] === 1) {
|
|
190
|
+
// Decompress the payload
|
|
191
|
+
const decompressedPayload = decompressJson(payload);
|
|
192
|
+
// Replace payload with decompressed json payload
|
|
193
|
+
payload = JSON.parse(decompressedPayload);
|
|
170
194
|
}
|
|
171
195
|
|
|
172
|
-
return
|
|
196
|
+
return payload;
|
|
173
197
|
}
|
|
174
198
|
}
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
export function initialize() {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
document.
|
|
2
|
+
// Check if the script already exists
|
|
3
|
+
// Only insert the script tag if it doesn't already exist
|
|
4
|
+
if (!document.querySelector('script[data-socketcluster-client]')) {
|
|
5
|
+
const socketClusterClientScript = document.createElement('script');
|
|
6
|
+
socketClusterClientScript.setAttribute('data-socketcluster-client', '1');
|
|
7
|
+
socketClusterClientScript.src = '/assets/socketcluster-client.min.js';
|
|
8
|
+
document.body.appendChild(socketClusterClientScript);
|
|
9
|
+
}
|
|
5
10
|
}
|
|
6
11
|
|
|
7
12
|
export default {
|
|
@@ -12,7 +12,8 @@ export default class AppCacheService extends Service {
|
|
|
12
12
|
@storageFor('local-cache') localCache;
|
|
13
13
|
|
|
14
14
|
get cachePrefix() {
|
|
15
|
-
|
|
15
|
+
const userId = this.currentUser.id ?? 'anon';
|
|
16
|
+
return `${userId}:${this.currentUser.companyId}:`;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
@action setEmberData(key, value, except = []) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Service from '@ember/service';
|
|
2
2
|
import Evented from '@ember/object/evented';
|
|
3
3
|
import { inject as service } from '@ember/service';
|
|
4
|
+
import { tracked } from '@glimmer/tracking';
|
|
4
5
|
import { dasherize } from '@ember/string';
|
|
5
6
|
import { computed, get, action } from '@ember/object';
|
|
6
7
|
import { isBlank } from '@ember/utils';
|
|
@@ -43,6 +44,16 @@ export default class CurrentUserService extends Service.extend(Evented) {
|
|
|
43
44
|
*/
|
|
44
45
|
@service notifications;
|
|
45
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Property to hold loaded user.
|
|
49
|
+
*
|
|
50
|
+
* @var {UserModel|Object}
|
|
51
|
+
* @memberof CurrentUserService
|
|
52
|
+
*/
|
|
53
|
+
@tracked user = {
|
|
54
|
+
id: 'anon',
|
|
55
|
+
};
|
|
56
|
+
|
|
46
57
|
/**
|
|
47
58
|
* User options in localStorage
|
|
48
59
|
*
|
package/addon/services/fetch.js
CHANGED
|
@@ -9,6 +9,7 @@ import { singularize, pluralize } from 'ember-inflector';
|
|
|
9
9
|
import { task } from 'ember-concurrency';
|
|
10
10
|
import { storageFor } from 'ember-local-storage';
|
|
11
11
|
import { intervalToDuration, parseISO } from 'date-fns';
|
|
12
|
+
import { decompress as decompressJson } from 'compress-json';
|
|
12
13
|
import config from 'ember-get-config';
|
|
13
14
|
import corslite from '../utils/corslite';
|
|
14
15
|
import getMimeType from '../utils/get-mime-type';
|
|
@@ -226,22 +227,31 @@ export default class FetchService extends Service {
|
|
|
226
227
|
*
|
|
227
228
|
* @return {Promise}
|
|
228
229
|
*/
|
|
229
|
-
parseJSON(response) {
|
|
230
|
-
|
|
231
|
-
response
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
230
|
+
async parseJSON(response) {
|
|
231
|
+
try {
|
|
232
|
+
const compressedHeader = await response.headers.get('x-compressed-json');
|
|
233
|
+
let json;
|
|
234
|
+
|
|
235
|
+
if (compressedHeader === '1') {
|
|
236
|
+
// Handle compressed json
|
|
237
|
+
const text = await response.text();
|
|
238
|
+
json = JSON.parse(text);
|
|
239
|
+
json = decompressJson(json);
|
|
240
|
+
json = JSON.parse(json);
|
|
241
|
+
} else {
|
|
242
|
+
// Handle regular json
|
|
243
|
+
json = await response.json();
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return {
|
|
247
|
+
statusText: response.statusText,
|
|
248
|
+
status: response.status,
|
|
249
|
+
ok: response.ok,
|
|
250
|
+
json,
|
|
251
|
+
};
|
|
252
|
+
} catch (error) {
|
|
253
|
+
throw new Error('Error processing response: ' + error.message);
|
|
254
|
+
}
|
|
245
255
|
}
|
|
246
256
|
|
|
247
257
|
/**
|
package/addon/services/theme.js
CHANGED
|
@@ -203,7 +203,7 @@ export default class ThemeService extends Service {
|
|
|
203
203
|
setTheme(theme = 'light') {
|
|
204
204
|
document.body.classList.remove(`${this.currentTheme}-theme`);
|
|
205
205
|
document.body.classList.add(`${theme}-theme`);
|
|
206
|
-
this.currentUser.setOption(
|
|
206
|
+
this.currentUser.setOption('theme', theme);
|
|
207
207
|
this.activeTheme = theme;
|
|
208
208
|
}
|
|
209
209
|
|
|
@@ -259,6 +259,7 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
259
259
|
name: registryName,
|
|
260
260
|
menuItems: [],
|
|
261
261
|
menuPanels: [],
|
|
262
|
+
renderableComponents: [],
|
|
262
263
|
...options,
|
|
263
264
|
};
|
|
264
265
|
|
|
@@ -426,6 +427,26 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
426
427
|
return [];
|
|
427
428
|
}
|
|
428
429
|
|
|
430
|
+
/**
|
|
431
|
+
* Retrieves renderable components from a specified registry.
|
|
432
|
+
* This action checks the internal registry, identified by the given registry name,
|
|
433
|
+
* and returns the 'renderableComponents' if they are present and are an array.
|
|
434
|
+
*
|
|
435
|
+
* @action
|
|
436
|
+
* @param {string} registryName - The name of the registry to retrieve components from.
|
|
437
|
+
* @returns {Array} An array of renderable components from the specified registry, or an empty array if none found.
|
|
438
|
+
*/
|
|
439
|
+
@action getRenderableComponentsFromRegistry(registryName) {
|
|
440
|
+
const internalRegistryName = this.createInternalRegistryName(registryName);
|
|
441
|
+
const registry = this[internalRegistryName];
|
|
442
|
+
|
|
443
|
+
if (!isBlank(registry) && isArray(registry.renderableComponents)) {
|
|
444
|
+
return registry.renderableComponents;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
return [];
|
|
448
|
+
}
|
|
449
|
+
|
|
429
450
|
/**
|
|
430
451
|
* Loads a component from the specified registry based on a given slug and view.
|
|
431
452
|
*
|
|
@@ -550,6 +571,34 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
550
571
|
});
|
|
551
572
|
}
|
|
552
573
|
|
|
574
|
+
/**
|
|
575
|
+
* Registers a renderable component or an array of components into a specified registry.
|
|
576
|
+
* If a single component is provided, it is registered directly.
|
|
577
|
+
* If an array of components is provided, each component in the array is registered individually.
|
|
578
|
+
* The component is also registered into the specified engine.
|
|
579
|
+
*
|
|
580
|
+
* @param {string} engineName - The name of the engine to register the component(s) into.
|
|
581
|
+
* @param {string} registryName - The registry name where the component(s) should be registered.
|
|
582
|
+
* @param {Object|Array} component - The component or array of components to register.
|
|
583
|
+
*/
|
|
584
|
+
registerRenderableComponent(engineName, registryName, component) {
|
|
585
|
+
if (isArray(component)) {
|
|
586
|
+
component.forEach((_) => this.registerRenderableComponent(registryName, _));
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// register component to engine
|
|
591
|
+
this.registerComponentInEngine(engineName, component);
|
|
592
|
+
|
|
593
|
+
// register to registry
|
|
594
|
+
const internalRegistryName = this.createInternalRegistryName(registryName);
|
|
595
|
+
if (isArray(this[internalRegistryName].renderableComponents)) {
|
|
596
|
+
this[internalRegistryName].renderableComponents.pushObject(component);
|
|
597
|
+
} else {
|
|
598
|
+
this[internalRegistryName].renderableComponents = [component];
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
553
602
|
/**
|
|
554
603
|
* Registers a new menu panel in a registry.
|
|
555
604
|
*
|
|
@@ -769,31 +818,39 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
769
818
|
}
|
|
770
819
|
|
|
771
820
|
/**
|
|
772
|
-
* Creates a dashboard widget object
|
|
821
|
+
* Creates a dashboard widget object from the given widget configuration.
|
|
773
822
|
*
|
|
774
|
-
* @param {Object} widget
|
|
775
|
-
* @
|
|
823
|
+
* @param {Object} widget - The widget configuration object.
|
|
824
|
+
* @param {string} widget.widgetId - The unique identifier for the widget.
|
|
825
|
+
* @param {string} widget.name - The name of the widget.
|
|
826
|
+
* @param {string} widget.description - The description of the widget.
|
|
827
|
+
* @param {string} widget.icon - The icon for the widget.
|
|
828
|
+
* @param {(Function|string)} widget.component - The component class or name for the widget.
|
|
829
|
+
* @param {Object} widget.grid_options - Grid options for the widget layout.
|
|
830
|
+
* @param {Object} widget.options - Additional options for the widget.
|
|
831
|
+
* @returns {Object} A new widget object with properties derived from the input configuration.
|
|
776
832
|
* @memberof UniverseService
|
|
777
833
|
*/
|
|
778
834
|
_createDashboardWidget(widget) {
|
|
779
835
|
// Extract properties from the widget object
|
|
780
|
-
let {
|
|
836
|
+
let { widgetId, name, description, icon, component, grid_options, options } = widget;
|
|
781
837
|
|
|
782
838
|
// If component is a definition register to host application
|
|
783
839
|
if (typeof component === 'function') {
|
|
784
840
|
const owner = getOwner(this);
|
|
841
|
+
const widgetId = component.widgetId || widgetId || this._createUniqueWidgetHashFromDefinition(component);
|
|
785
842
|
|
|
786
843
|
if (owner) {
|
|
787
|
-
owner.register(`component:${
|
|
844
|
+
owner.register(`component:${widgetId}`, component);
|
|
788
845
|
|
|
789
846
|
// Update component name
|
|
790
|
-
component =
|
|
847
|
+
component = widgetId;
|
|
791
848
|
}
|
|
792
849
|
}
|
|
793
850
|
|
|
794
851
|
// Create a new widget object with the extracted properties
|
|
795
852
|
const newWidget = {
|
|
796
|
-
|
|
853
|
+
widgetId,
|
|
797
854
|
name,
|
|
798
855
|
description,
|
|
799
856
|
icon,
|
|
@@ -805,6 +862,29 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
805
862
|
return newWidget;
|
|
806
863
|
}
|
|
807
864
|
|
|
865
|
+
/**
|
|
866
|
+
* Creates a unique hash from a component's definition. This hash is used as an identifier
|
|
867
|
+
* for the component when a direct identifier (widgetId) or a name is not available.
|
|
868
|
+
*
|
|
869
|
+
* @param {Function} component - The component class or constructor function.
|
|
870
|
+
* @returns {string} A unique hash string representing the component's definition.
|
|
871
|
+
* @memberof UniverseService
|
|
872
|
+
*/
|
|
873
|
+
_createUniqueWidgetHashFromDefinition(component) {
|
|
874
|
+
if (typeof component.toString === 'function') {
|
|
875
|
+
let definition = component.toString();
|
|
876
|
+
let hash = 0;
|
|
877
|
+
for (let i = 0; i < definition.length; i++) {
|
|
878
|
+
const char = definition.charCodeAt(i);
|
|
879
|
+
hash = (hash << 5) - hash + char;
|
|
880
|
+
hash |= 0;
|
|
881
|
+
}
|
|
882
|
+
return hash.toString(16);
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
return component.name;
|
|
886
|
+
}
|
|
887
|
+
|
|
808
888
|
/**
|
|
809
889
|
* Registers a new settings menu item.
|
|
810
890
|
*
|
package/index.js
CHANGED
|
@@ -24,11 +24,11 @@ module.exports = {
|
|
|
24
24
|
|
|
25
25
|
if (app.options['ember-cli-notifications'] !== undefined) {
|
|
26
26
|
app.options['ember-cli-notifications'].autoClear = true;
|
|
27
|
-
app.options['ember-cli-notifications'].clearDuration = 1000 * 5;
|
|
27
|
+
app.options['ember-cli-notifications'].clearDuration = 1000 * 3.5;
|
|
28
28
|
} else {
|
|
29
29
|
app.options['ember-cli-notifications'] = {
|
|
30
30
|
autoClear: true,
|
|
31
|
-
clearDuration: 1000 * 5,
|
|
31
|
+
clearDuration: 1000 * 3.5,
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
34
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fleetbase/ember-core",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
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",
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@babel/core": "^7.23.2",
|
|
38
|
+
"compress-json": "^3.0.0",
|
|
38
39
|
"date-fns": "^2.30.0",
|
|
39
40
|
"ember-auto-import": "^2.6.3",
|
|
40
41
|
"ember-cli-babel": "^8.2.0",
|
|
@@ -71,13 +72,13 @@
|
|
|
71
72
|
"ember-cli-inject-live-reload": "^2.1.0",
|
|
72
73
|
"ember-cli-sri": "^2.1.1",
|
|
73
74
|
"ember-cli-terser": "^4.0.2",
|
|
75
|
+
"ember-data": "^4.12.5",
|
|
74
76
|
"ember-file-upload": "8.4.0",
|
|
75
77
|
"ember-load-initializers": "^2.1.2",
|
|
76
78
|
"ember-page-title": "^8.0.0",
|
|
77
79
|
"ember-qunit": "^8.0.1",
|
|
78
80
|
"ember-resolver": "^11.0.1",
|
|
79
81
|
"ember-source": "~5.4.0",
|
|
80
|
-
"ember-data": "^4.12.5",
|
|
81
82
|
"ember-source-channel-url": "^3.0.0",
|
|
82
83
|
"ember-template-lint": "^5.11.2",
|
|
83
84
|
"ember-try": "^3.0.0",
|