@fleetbase/ember-core 0.2.22 → 0.3.0
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 +1 -1
- package/addon/services/crud.js +72 -54
- package/addon/services/current-user.js +34 -11
- package/addon/services/fetch.js +3 -3
- package/addon/services/filters.js +0 -1
- package/addon/utils/create-notification-key.js +8 -0
- package/addon/utils/is-authenticated.js +25 -0
- package/addon/utils/load-installed-extensions.js +9 -3
- package/addon/utils/timeout.js +15 -0
- package/app/utils/create-notification-key.js +1 -0
- package/app/utils/is-authenticated.js +1 -0
- package/app/utils/timeout.js +1 -0
- package/package.json +1 -1
|
@@ -13,7 +13,7 @@ import getUserOptions from '../utils/get-user-options';
|
|
|
13
13
|
import config from 'ember-get-config';
|
|
14
14
|
|
|
15
15
|
if (isBlank(config.API.host)) {
|
|
16
|
-
config.API.host = `${window.location.protocol}//${window.location.hostname}
|
|
16
|
+
config.API.host = `${window.location.protocol}//${window.location.hostname}`;
|
|
17
17
|
}
|
|
18
18
|
const DEFAULT_ERROR_MESSAGE = 'Oops! Something went wrong. Please try again or contact support if the issue persists.';
|
|
19
19
|
export default class ApplicationAdapter extends RESTAdapter {
|
package/addon/services/crud.js
CHANGED
|
@@ -54,38 +54,38 @@ export default class CrudService extends Service {
|
|
|
54
54
|
*/
|
|
55
55
|
@action delete(model, options = {}) {
|
|
56
56
|
const modelName = getModelName(model, get(options, 'modelName'), { humanize: true, capitalizeWords: true });
|
|
57
|
+
const successNotification = options.successNotification || `${model.name ? modelName + " '" + model.name + "'" : "'" + modelName + "'"} has been deleted.`;
|
|
57
58
|
|
|
58
59
|
this.modalsManager.confirm({
|
|
59
60
|
title: `Are you sure to delete this ${modelName}?`,
|
|
60
61
|
args: ['model'],
|
|
61
62
|
model,
|
|
62
|
-
confirm: (modal) => {
|
|
63
|
-
if (typeof options.
|
|
64
|
-
options.
|
|
63
|
+
confirm: async (modal) => {
|
|
64
|
+
if (typeof options.onTrigger === 'function') {
|
|
65
|
+
options.onTrigger(model);
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
modal.startLoading();
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
.destroyRecord()
|
|
71
|
-
.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
})
|
|
77
|
-
.catch((error) => {
|
|
78
|
-
this.notifications.serverError(error);
|
|
70
|
+
try {
|
|
71
|
+
const response = await model.destroyRecord();
|
|
72
|
+
this.notifications.success(successNotification);
|
|
73
|
+
if (typeof options.onSuccess === 'function') {
|
|
74
|
+
options.onSuccess(model);
|
|
75
|
+
}
|
|
79
76
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
.
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
77
|
+
return response;
|
|
78
|
+
} catch (error) {
|
|
79
|
+
this.notifications.serverError(error);
|
|
80
|
+
|
|
81
|
+
if (typeof options.onError === 'function') {
|
|
82
|
+
options.onError(error, model);
|
|
83
|
+
}
|
|
84
|
+
} finally {
|
|
85
|
+
if (typeof options.callback === 'function') {
|
|
86
|
+
options.callback(model);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
89
|
},
|
|
90
90
|
...options,
|
|
91
91
|
});
|
|
@@ -135,10 +135,21 @@ export default class CrudService extends Service {
|
|
|
135
135
|
const modelName = getModelName(firstModel, get(options, 'modelName'), { humanize: true, capitalizeWords: true });
|
|
136
136
|
const count = selected.length;
|
|
137
137
|
const actionMethod = (typeof options.actionMethod === 'string' ? options.actionMethod : `POST`).toLowerCase();
|
|
138
|
-
const
|
|
139
|
-
const
|
|
138
|
+
const modalTemplate = getWithDefault(options, 'template', 'modals/bulk-action-model');
|
|
139
|
+
const successMessage = options.successNotification ?? `${count} ${pluralize(count, modelName)} were updated successfully.`;
|
|
140
|
+
|
|
141
|
+
if (typeof options.resolveModelName === 'function') {
|
|
142
|
+
selected = selected.map((model) => {
|
|
143
|
+
const resolvedModelName = options.resolveModelName(model);
|
|
144
|
+
if (typeof resolvedModelName === 'string') {
|
|
145
|
+
model.set('list_resolved_name', resolvedModelName);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return model;
|
|
149
|
+
});
|
|
150
|
+
}
|
|
140
151
|
|
|
141
|
-
this.modalsManager.show(
|
|
152
|
+
this.modalsManager.show(modalTemplate, {
|
|
142
153
|
title: `Bulk ${verb} ${pluralize(modelName)}`,
|
|
143
154
|
acceptButtonText: humanize(verb),
|
|
144
155
|
args: ['selected'],
|
|
@@ -151,42 +162,49 @@ export default class CrudService extends Service {
|
|
|
151
162
|
selected.removeObject(model);
|
|
152
163
|
this.modalsManager.setOption('selected', selected);
|
|
153
164
|
},
|
|
154
|
-
confirm: (modal) => {
|
|
165
|
+
confirm: async (modal) => {
|
|
155
166
|
const selected = modal.getOption('selected');
|
|
167
|
+
const fetchParams = modal.getOption('fetchParams', {});
|
|
168
|
+
const fetchOptions = modal.getOption('fetchOptions', {});
|
|
169
|
+
const callback = modal.getOption('callback');
|
|
156
170
|
|
|
157
|
-
if (typeof options.
|
|
158
|
-
options.
|
|
171
|
+
if (typeof options.withSelected === 'function') {
|
|
172
|
+
options.withSelected(selected);
|
|
159
173
|
}
|
|
160
174
|
|
|
161
175
|
modal.startLoading();
|
|
162
176
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
options.onSuccess(selected);
|
|
176
|
-
}
|
|
177
|
-
})
|
|
178
|
-
.catch((error) => {
|
|
179
|
-
this.notifications.serverError(error);
|
|
177
|
+
try {
|
|
178
|
+
const response = await this.fetch.request(
|
|
179
|
+
options.actionPath,
|
|
180
|
+
actionMethod,
|
|
181
|
+
{
|
|
182
|
+
body: JSON.stringify({
|
|
183
|
+
ids: selected.map((model) => model.id),
|
|
184
|
+
...fetchParams,
|
|
185
|
+
}),
|
|
186
|
+
},
|
|
187
|
+
fetchOptions
|
|
188
|
+
);
|
|
180
189
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
+
this.notifications.success(response.message ?? successMessage);
|
|
191
|
+
if (typeof options.onSuccess === 'function') {
|
|
192
|
+
options.onSuccess(selected);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return response;
|
|
196
|
+
} catch (error) {
|
|
197
|
+
console.error(error.message, error);
|
|
198
|
+
this.notifications.serverError(error);
|
|
199
|
+
|
|
200
|
+
if (typeof options.onError === 'function') {
|
|
201
|
+
options.onError(error, selected);
|
|
202
|
+
}
|
|
203
|
+
} finally {
|
|
204
|
+
if (typeof callback === 'function') {
|
|
205
|
+
callback(selected);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
190
208
|
},
|
|
191
209
|
...options,
|
|
192
210
|
});
|
|
@@ -7,6 +7,7 @@ import { computed, get } from '@ember/object';
|
|
|
7
7
|
import { isBlank } from '@ember/utils';
|
|
8
8
|
import { alias } from '@ember/object/computed';
|
|
9
9
|
import { storageFor } from 'ember-local-storage';
|
|
10
|
+
import { debug } from '@ember/debug';
|
|
10
11
|
|
|
11
12
|
export default class CurrentUserService extends Service.extend(Evented) {
|
|
12
13
|
@service session;
|
|
@@ -17,6 +18,7 @@ export default class CurrentUserService extends Service.extend(Evented) {
|
|
|
17
18
|
@service intl;
|
|
18
19
|
|
|
19
20
|
@tracked user = { id: 'anon' };
|
|
21
|
+
@tracked userSnapshot = { id: 'anon' };
|
|
20
22
|
@tracked company = {};
|
|
21
23
|
@tracked permissions = [];
|
|
22
24
|
@tracked organizations = [];
|
|
@@ -24,16 +26,16 @@ export default class CurrentUserService extends Service.extend(Evented) {
|
|
|
24
26
|
@tracked locale = 'en-us';
|
|
25
27
|
|
|
26
28
|
@storageFor('user-options') options;
|
|
27
|
-
@alias('
|
|
28
|
-
@alias('
|
|
29
|
-
@alias('
|
|
30
|
-
@alias('
|
|
31
|
-
@alias('
|
|
32
|
-
@alias('
|
|
33
|
-
@alias('
|
|
34
|
-
@alias('
|
|
35
|
-
@alias('
|
|
36
|
-
@alias('
|
|
29
|
+
@alias('userSnapshot.id') id;
|
|
30
|
+
@alias('userSnapshot.name') name;
|
|
31
|
+
@alias('userSnapshot.phone') phone;
|
|
32
|
+
@alias('userSnapshot.email') email;
|
|
33
|
+
@alias('userSnapshot.avatar_url') avatarUrl;
|
|
34
|
+
@alias('userSnapshot.is_admin') isAdmin;
|
|
35
|
+
@alias('userSnapshot.company_uuid') companyId;
|
|
36
|
+
@alias('userSnapshot.company_name') companyName;
|
|
37
|
+
@alias('userSnapshot.role_name') roleName;
|
|
38
|
+
@alias('userSnapshot.role') role;
|
|
37
39
|
|
|
38
40
|
@computed('id') get optionsPrefix() {
|
|
39
41
|
return `${this.id}:`;
|
|
@@ -62,7 +64,10 @@ export default class CurrentUserService extends Service.extend(Evented) {
|
|
|
62
64
|
async load() {
|
|
63
65
|
if (this.session.isAuthenticated) {
|
|
64
66
|
const user = await this.store.findRecord('user', 'me');
|
|
67
|
+
const snapshot = await this.getUserSnapshot(user);
|
|
68
|
+
|
|
65
69
|
this.set('user', user);
|
|
70
|
+
this.set('userSnapshot', snapshot);
|
|
66
71
|
this.trigger('user.loaded', user);
|
|
67
72
|
|
|
68
73
|
// Set permissions
|
|
@@ -85,9 +90,11 @@ export default class CurrentUserService extends Service.extend(Evented) {
|
|
|
85
90
|
|
|
86
91
|
try {
|
|
87
92
|
const user = await this.store.queryRecord('user', { me: true });
|
|
93
|
+
const snapshot = await this.getUserSnapshot(user);
|
|
88
94
|
|
|
89
95
|
// Set current user
|
|
90
96
|
this.set('user', user);
|
|
97
|
+
this.set('userSnapshot', snapshot);
|
|
91
98
|
this.trigger('user.loaded', user);
|
|
92
99
|
|
|
93
100
|
// Set permissions
|
|
@@ -116,7 +123,7 @@ export default class CurrentUserService extends Service.extend(Evented) {
|
|
|
116
123
|
|
|
117
124
|
return user;
|
|
118
125
|
} catch (error) {
|
|
119
|
-
|
|
126
|
+
debug(`Error loading current user : ${error.message}`);
|
|
120
127
|
throw error;
|
|
121
128
|
}
|
|
122
129
|
}
|
|
@@ -257,4 +264,20 @@ export default class CurrentUserService extends Service.extend(Evented) {
|
|
|
257
264
|
filledOption(key) {
|
|
258
265
|
return !isBlank(this.getOption(key));
|
|
259
266
|
}
|
|
267
|
+
|
|
268
|
+
async getUserSnapshot(user) {
|
|
269
|
+
const role = await user.get('role');
|
|
270
|
+
const snapshot = user.serialize({ includeId: true });
|
|
271
|
+
|
|
272
|
+
return {
|
|
273
|
+
...snapshot,
|
|
274
|
+
id: snapshot.uuid,
|
|
275
|
+
company_name: user.get('company_name'),
|
|
276
|
+
role_name: user.get('role_name'),
|
|
277
|
+
role: {
|
|
278
|
+
...role.serialize({ includeId: true }),
|
|
279
|
+
id: role.get('id'),
|
|
280
|
+
},
|
|
281
|
+
};
|
|
282
|
+
}
|
|
260
283
|
}
|
package/addon/services/fetch.js
CHANGED
|
@@ -19,7 +19,7 @@ import isEmptyObject from '../utils/is-empty-object';
|
|
|
19
19
|
import fetch from 'fetch';
|
|
20
20
|
|
|
21
21
|
if (isBlank(config.API.host)) {
|
|
22
|
-
config.API.host = `${window.location.protocol}//${window.location.hostname}
|
|
22
|
+
config.API.host = `${window.location.protocol}//${window.location.hostname}`;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export default class FetchService extends Service {
|
|
@@ -612,7 +612,7 @@ export default class FetchService extends Service {
|
|
|
612
612
|
const headers = Object.assign(this.getHeaders(), options.headers ?? {});
|
|
613
613
|
const method = options.method ?? 'GET';
|
|
614
614
|
const credentials = options.credentials ?? this.credentials;
|
|
615
|
-
const baseUrl = `${options.host
|
|
615
|
+
const baseUrl = options.externalRequest === true ? '' : `${options.host ?? this.host}/${options.namespace || this.namespace}`;
|
|
616
616
|
const isReadOnlyRequest = ['GET', 'HEAD'].includes(method.toUpperCase());
|
|
617
617
|
const params = isReadOnlyRequest && !isEmptyObject(query) ? `?${new URLSearchParams(query).toString()}` : '';
|
|
618
618
|
const body = !isReadOnlyRequest ? JSON.stringify(query) : {};
|
|
@@ -628,7 +628,7 @@ export default class FetchService extends Service {
|
|
|
628
628
|
}
|
|
629
629
|
|
|
630
630
|
return new Promise((resolve, reject) => {
|
|
631
|
-
return fetch(`${baseUrl}
|
|
631
|
+
return fetch(`${baseUrl ? baseUrl + '/' : ''}${path}${params}`, fetchOptions)
|
|
632
632
|
.then((response) => {
|
|
633
633
|
options.fileName = this.getFilenameFromResponse(response, options.fileName);
|
|
634
634
|
options.mimeType = this.getMimeTypeFromResponse(response, options.mimeType);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check whether the current browser session is authenticated.
|
|
3
|
+
*
|
|
4
|
+
* Reads the session payload Ember Simple Auth stores in
|
|
5
|
+
* localStorage (`ember_simple_auth-session`) and returns `true`
|
|
6
|
+
* only if it finds a bearer token.
|
|
7
|
+
*
|
|
8
|
+
* @return {boolean} `true` when a user appears to be logged in, otherwise `false`.
|
|
9
|
+
*/
|
|
10
|
+
export default function isAuthenticated() {
|
|
11
|
+
try {
|
|
12
|
+
const rawSession = window.localStorage.getItem('ember_simple_auth-session');
|
|
13
|
+
if (!rawSession) {
|
|
14
|
+
return false; // nothing stored
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const { authenticated } = JSON.parse(rawSession);
|
|
18
|
+
|
|
19
|
+
// Basic check: token must be a non-empty string
|
|
20
|
+
return typeof authenticated?.token === 'string' && authenticated.token.trim().length > 0;
|
|
21
|
+
} catch {
|
|
22
|
+
// Malformed JSON or restricted access to localStorage
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import loadExtensions from '
|
|
2
|
-
import fleetbaseApiFetch from '
|
|
1
|
+
import loadExtensions from './load-extensions';
|
|
2
|
+
import fleetbaseApiFetch from './fleetbase-api-fetch';
|
|
3
|
+
import isAuthenticated from './is-authenticated';
|
|
3
4
|
|
|
4
5
|
export default async function loadInstalledExtensions(additionalCoreEngines = []) {
|
|
5
6
|
const CORE_ENGINES = [
|
|
@@ -11,7 +12,12 @@ export default async function loadInstalledExtensions(additionalCoreEngines = []
|
|
|
11
12
|
...additionalCoreEngines,
|
|
12
13
|
];
|
|
13
14
|
const INDEXED_ENGINES = await loadExtensions();
|
|
14
|
-
const INSTALLED_ENGINES = await fleetbaseApiFetch('get', 'engines', {}, { namespace: '~registry/v1', fallbackResponse: [] });
|
|
15
|
+
// const INSTALLED_ENGINES = await fleetbaseApiFetch('get', 'engines', {}, { namespace: '~registry/v1', fallbackResponse: [] });
|
|
16
|
+
|
|
17
|
+
let INSTALLED_ENGINES = [];
|
|
18
|
+
if (isAuthenticated()) {
|
|
19
|
+
INSTALLED_ENGINES = await fleetbaseApiFetch('GET', 'engines', {}, { namespace: '~registry/v1', fallbackResponse: [] });
|
|
20
|
+
}
|
|
15
21
|
|
|
16
22
|
const isInstalledEngine = (engineName) => {
|
|
17
23
|
return CORE_ENGINES.includes(engineName) || INSTALLED_ENGINES.find((pkg) => pkg.name === engineName);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { later } from '@ember/runloop';
|
|
2
|
+
|
|
3
|
+
export default function timeout(ms = 300, options = {}) {
|
|
4
|
+
const response = options.response ? options.response : true;
|
|
5
|
+
|
|
6
|
+
return new Promise((resolve) => {
|
|
7
|
+
later(
|
|
8
|
+
this,
|
|
9
|
+
() => {
|
|
10
|
+
resolve(response);
|
|
11
|
+
},
|
|
12
|
+
ms
|
|
13
|
+
);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/ember-core/utils/create-notification-key';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/ember-core/utils/is-authenticated';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/ember-core/utils/timeout';
|
package/package.json
CHANGED