@fleetbase/ember-core 0.2.15 → 0.2.17

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.
@@ -0,0 +1,55 @@
1
+ import { decoratorWithRequiredParams } from '@ember-decorators/utils/decorator';
2
+ import { assert } from '@ember/debug';
3
+ import { getOwner } from '@ember/application';
4
+ import { scheduleOnce } from '@ember/runloop';
5
+
6
+ export default function fetchFrom(endpoint, query = {}, options = {}) {
7
+ assert('The first argument of the @fetchFrom decorator must be a string', typeof endpoint === 'string');
8
+ assert('The second argument of the @fetchFrom decorator must be an object', typeof query === 'object');
9
+ assert('The third argument of the @fetchFrom decorator must be an object', typeof options === 'object');
10
+
11
+ return decoratorWithRequiredParams(function (target, key) {
12
+ const symbol = Symbol(`__${key}_fetchFrom`);
13
+
14
+ Object.defineProperty(target, symbol, {
15
+ configurable: true,
16
+ enumerable: false,
17
+ writable: true,
18
+ value: null,
19
+ });
20
+
21
+ Object.defineProperty(target, key, {
22
+ configurable: true,
23
+ enumerable: true,
24
+ get() {
25
+ return this[symbol];
26
+ },
27
+ set(value) {
28
+ this[symbol] = value;
29
+ },
30
+ });
31
+
32
+ const originalInit = target.init;
33
+
34
+ target.init = function () {
35
+ if (originalInit) {
36
+ originalInit.call(this);
37
+ }
38
+
39
+ scheduleOnce('afterRender', this, function () {
40
+ const owner = getOwner(this);
41
+ const fetch = owner.lookup('service:fetch'); // Get the Fleetbase Fetch service
42
+
43
+ // Perform the query and set the result to the property
44
+ fetch
45
+ .get(endpoint, query, options)
46
+ .then((result) => {
47
+ this.set(key, result);
48
+ })
49
+ .catch(() => {
50
+ this.set(key, []);
51
+ });
52
+ });
53
+ };
54
+ }, 'fetchFrom')(endpoint, query, options);
55
+ }
@@ -0,0 +1,52 @@
1
+ import { decoratorWithRequiredParams } from '@ember-decorators/utils/decorator';
2
+ import { getOwner } from '@ember/application';
3
+ import { assert } from '@ember/debug';
4
+
5
+ export default decoratorWithRequiredParams(function (target, key, descriptor, [modelName, query = {}, options = {}]) {
6
+ assert('The first argument of the @fetchFrom decorator must be a string', typeof modelName === 'string');
7
+ assert('The second argument of the @fetchFrom decorator must be an object', typeof query === 'object');
8
+ assert('The third argument of the @fetchFrom decorator must be an object', typeof options === 'object');
9
+
10
+ // Remove value and writable if previously set, use getter instead
11
+ delete descriptor.value;
12
+ delete descriptor.writable;
13
+ delete descriptor.initializer;
14
+
15
+ // Create symbol to track value
16
+ const symbol = Symbol(`__${key}_fromStore`);
17
+
18
+ // Setter to get symbol value
19
+ descriptor.set = function (value) {
20
+ this[symbol] = value;
21
+ };
22
+
23
+ // Get or set symbol value
24
+ descriptor.get = function () {
25
+ if (this[symbol] !== undefined) {
26
+ return this[symbol];
27
+ }
28
+
29
+ Object.defineProperty(this, symbol, {
30
+ configurable: true,
31
+ enumerable: false,
32
+ writable: true,
33
+ value: null,
34
+ });
35
+
36
+ const owner = getOwner(this);
37
+ const store = owner.lookup('service:store');
38
+ return store
39
+ .query(modelName, query, options)
40
+ .then((response) => {
41
+ this.set(key, response);
42
+ if (options && typeof options.onComplete === 'function') {
43
+ options.onComplete(response, this);
44
+ }
45
+ })
46
+ .catch(() => {
47
+ this.set(key, null);
48
+ });
49
+ };
50
+
51
+ return descriptor;
52
+ });
@@ -3,119 +3,36 @@ import Evented from '@ember/object/evented';
3
3
  import { inject as service } from '@ember/service';
4
4
  import { tracked } from '@glimmer/tracking';
5
5
  import { dasherize } from '@ember/string';
6
- import { computed, get, action } from '@ember/object';
6
+ 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
10
 
11
11
  export default class CurrentUserService extends Service.extend(Evented) {
12
- /**
13
- * Inject the `session` service
14
- *
15
- * @var {Service}
16
- */
17
12
  @service session;
18
-
19
- /**
20
- * Inject the `store` service
21
- *
22
- * @var {Service}
23
- */
24
13
  @service store;
25
-
26
- /**
27
- * Inject the `fetch` service
28
- *
29
- * @var {Service}
30
- */
31
14
  @service fetch;
32
-
33
- /**
34
- * Inject the `theme` service
35
- *
36
- * @var {Service}
37
- */
38
15
  @service theme;
39
-
40
- /**
41
- * Inject the `notifications` service
42
- *
43
- * @var {Service}
44
- */
45
16
  @service notifications;
17
+ @service intl;
46
18
 
47
- /**
48
- * Property to hold loaded user.
49
- *
50
- * @var {UserModel|Object}
51
- * @memberof CurrentUserService
52
- */
53
- @tracked user = {
54
- id: 'anon',
55
- };
56
-
57
- /**
58
- * The current users permissions.
59
- *
60
- * @memberof CurrentUserService
61
- */
19
+ @tracked user = { id: 'anon' };
20
+ @tracked company = {};
62
21
  @tracked permissions = [];
22
+ @tracked organizations = [];
23
+ @tracked whoisData = {};
24
+ @tracked locale = 'en-us';
63
25
 
64
- /**
65
- * User options in localStorage
66
- *
67
- * @var StorageObject
68
- */
69
26
  @storageFor('user-options') options;
70
-
71
- /**
72
- * Alias for current user id
73
- *
74
- * @var {String}
75
- */
76
27
  @alias('user.id') id;
77
-
78
- /**
79
- * Alias for current user name
80
- *
81
- * @var {String}
82
- */
83
28
  @alias('user.name') name;
84
-
85
- /**
86
- * Alias for current user phone
87
- *
88
- * @var {String}
89
- */
90
29
  @alias('user.phone') phone;
91
-
92
- /**
93
- * Alias for current user phone
94
- *
95
- * @var {String}
96
- */
97
30
  @alias('user.email') email;
98
-
99
- /**
100
- * Alias for current user's company id
101
- *
102
- * @var {String}
103
- */
104
- @alias('user.company_uuid') companyId;
105
-
106
- /**
107
- * Alias for if user is admin.
108
- *
109
- * @var {Boolean}
110
- * @memberof CurrentUserService
111
- */
31
+ @alias('user.avatar_url') avatarUrl;
112
32
  @alias('user.is_admin') isAdmin;
33
+ @alias('user.company_uuid') companyId;
34
+ @alias('user.company_name') companyName;
113
35
 
114
- /**
115
- * The prefix for this user options
116
- *
117
- * @var {String}
118
- */
119
36
  @computed('id') get optionsPrefix() {
120
37
  return `${this.id}:`;
121
38
  }
@@ -140,71 +57,115 @@ export default class CurrentUserService extends Service.extend(Evented) {
140
57
  return this.whois('country_code');
141
58
  }
142
59
 
143
- /**
144
- * Loads the current authenticated user
145
- *
146
- * @return Promise<UserModel>|null
147
- */
148
60
  async load() {
149
61
  if (this.session.isAuthenticated) {
150
- let user = await this.store.findRecord('user', 'me');
62
+ const user = await this.store.findRecord('user', 'me');
151
63
  this.set('user', user);
152
64
  this.trigger('user.loaded', user);
153
65
 
154
66
  // Set permissions
155
67
  this.permissions = this.getUserPermissions(user);
156
68
 
69
+ // Load preferences
70
+ await this.loadPreferences();
71
+
157
72
  return user;
158
73
  }
159
74
 
160
75
  return null;
161
76
  }
162
77
 
163
- /**
164
- * Resolves a user model.
165
- *
166
- * @return {Promise<User>}
167
- */
168
- @action promiseUser(options = {}) {
78
+ async promiseUser(options = {}) {
169
79
  const NoUserAuthenticatedError = new Error('Failed to authenticate user.');
80
+ if (!this.session.isAuthenticated) {
81
+ throw NoUserAuthenticatedError;
82
+ }
170
83
 
171
- return new Promise((resolve, reject) => {
172
- if (this.session.isAuthenticated) {
173
- try {
174
- this.store.queryRecord('user', { me: true }).then((user) => {
175
- // set the `current user`
176
- this.set('user', user);
177
- this.trigger('user.loaded', user);
178
-
179
- // Set permissions
180
- this.permissions = this.getUserPermissions(user);
181
-
182
- // set environment from user option
183
- this.theme.setEnvironment();
184
-
185
- // @TODO Create an event dispatch for when an authenticated user is resolved from the server
186
- if (typeof options?.onUserResolved === 'function') {
187
- options.onUserResolved(user);
188
- }
189
-
190
- resolve(user);
191
- });
192
- } catch (error) {
193
- reject(NoUserAuthenticatedError);
194
- }
195
- } else {
196
- reject(NoUserAuthenticatedError);
84
+ try {
85
+ const user = await this.store.queryRecord('user', { me: true });
86
+
87
+ // Set current user
88
+ this.set('user', user);
89
+ this.trigger('user.loaded', user);
90
+
91
+ // Set permissions
92
+ this.permissions = this.getUserPermissions(user);
93
+
94
+ // Set environment from user option
95
+ this.theme.setEnvironment();
96
+
97
+ // Load user preferces
98
+ await this.loadPreferences();
99
+
100
+ // Optional callback
101
+ if (typeof options?.onUserResolved === 'function') {
102
+ options.onUserResolved(user);
197
103
  }
198
- });
104
+
105
+ return user;
106
+ } catch (error) {
107
+ console.log(error.message);
108
+ throw error;
109
+ }
110
+ }
111
+
112
+ async loadPreferences() {
113
+ await this.loadLocale();
114
+ await this.loadWhois();
115
+ await this.loadOrganizations();
116
+ }
117
+
118
+ async loadLocale() {
119
+ try {
120
+ const { locale } = await this.fetch.get('users/locale');
121
+ this.setOption('locale', locale);
122
+ this.intl.setLocale(locale);
123
+ this.locale = locale;
124
+
125
+ return locale;
126
+ } catch (error) {
127
+ this.notifications.serverError(error);
128
+ }
129
+ }
130
+
131
+ async loadOrganizations() {
132
+ try {
133
+ const organizations = await this.fetch.get('auth/organizations', {}, { normalizeToEmberData: true, normalizeModelType: 'company' });
134
+ this.setOption('organizations', organizations);
135
+ this.organizations = organizations;
136
+
137
+ return organizations;
138
+ } catch (error) {
139
+ this.notifications.serverError(error);
140
+ }
141
+ }
142
+
143
+ async loadWhois() {
144
+ this.fetch.shouldResetCache();
145
+
146
+ try {
147
+ const whois = await this.fetch.cachedGet(
148
+ 'lookup/whois',
149
+ {},
150
+ {
151
+ expirationInterval: 60,
152
+ expirationIntervalUnit: 'minutes',
153
+ }
154
+ );
155
+ this.setOption('whois', whois);
156
+ this.whoisData = whois;
157
+
158
+ return whois;
159
+ } catch (error) {
160
+ this.notifications.serverError(error);
161
+ }
162
+ }
163
+
164
+ getCompany() {
165
+ this.company = this.store.peekRecord('company', this.user.company_uuid);
166
+ return this.company;
199
167
  }
200
168
 
201
- /**
202
- * Gets all user permissions.
203
- *
204
- * @param {UserModel} user
205
- * @return {Array}
206
- * @memberof CurrentUserService
207
- */
208
169
  getUserPermissions(user) {
209
170
  const permissions = [];
210
171
 
@@ -242,25 +203,11 @@ export default class CurrentUserService extends Service.extend(Evented) {
242
203
  return permissions;
243
204
  }
244
205
 
245
- /**
246
- * Alias to get a user's whois property
247
- *
248
- * @param {String} key
249
- * @return {Mixed}
250
- * @memberof CurrentUserService
251
- */
252
- @action whois(key) {
206
+ whois(key) {
253
207
  return this.getWhoisProperty(key);
254
208
  }
255
209
 
256
- /**
257
- * Sets a user's option in local storage
258
- *
259
- * @param {String} key
260
- * @param {Mixed} value
261
- * @return {CurrentUserService}
262
- */
263
- @action setOption(key, value) {
210
+ setOption(key, value) {
264
211
  key = `${this.optionsPrefix}${dasherize(key)}`;
265
212
 
266
213
  this.options.set(key, value);
@@ -268,26 +215,14 @@ export default class CurrentUserService extends Service.extend(Evented) {
268
215
  return this;
269
216
  }
270
217
 
271
- /**
272
- * Retrieves a user option from local storage
273
- *
274
- * @param {String} key
275
- * @return {Mixed}
276
- */
277
- @action getOption(key, defaultValue = null) {
218
+ getOption(key, defaultValue = null) {
278
219
  key = `${this.optionsPrefix}${dasherize(key)}`;
279
220
 
280
221
  const value = this.options.get(key);
281
222
  return value !== undefined ? value : defaultValue;
282
223
  }
283
224
 
284
- /**
285
- * Retrieves a user option from local storage
286
- *
287
- * @param {String} key
288
- * @return {Mixed}
289
- */
290
- @action getWhoisProperty(prop) {
225
+ getWhoisProperty(prop) {
291
226
  const whois = this.getOption('whois');
292
227
 
293
228
  if (!whois || typeof whois !== 'object') {
@@ -297,23 +232,11 @@ export default class CurrentUserService extends Service.extend(Evented) {
297
232
  return get(whois, prop);
298
233
  }
299
234
 
300
- /**
301
- * Checks if an option exists in users local storage
302
- *
303
- * @param {String} key
304
- * @return {Boolean}
305
- */
306
- @action hasOption(key) {
235
+ hasOption(key) {
307
236
  return this.getOption(key) !== undefined;
308
237
  }
309
238
 
310
- /**
311
- * Checks if an option exists in users local storage
312
- *
313
- * @param {String} key
314
- * @return {Boolean}
315
- */
316
- @action filledOption(key) {
239
+ filledOption(key) {
317
240
  return !isBlank(this.getOption(key));
318
241
  }
319
242
  }
@@ -5,25 +5,8 @@ import { later } from '@ember/runloop';
5
5
  import getWithDefault from '../utils/get-with-default';
6
6
 
7
7
  export default class SessionService extends SimpleAuthSessionService {
8
- /**
9
- * Inject the router service
10
- *
11
- * @var {Service}
12
- */
13
8
  @service router;
14
-
15
- /**
16
- * Inject the current user service
17
- *
18
- * @var {Service}
19
- */
20
9
  @service currentUser;
21
-
22
- /**
23
- * Inject the current user service
24
- *
25
- * @var {Service}
26
- */
27
10
  @service fetch;
28
11
 
29
12
  /**
@@ -69,23 +52,22 @@ export default class SessionService extends SimpleAuthSessionService {
69
52
  }
70
53
 
71
54
  const loaderNode = this.showLoader('Starting session...');
72
-
73
55
  this.isLoaderNodeOpen = true;
74
56
 
75
- this.router
76
- .transitionTo(this.redirectTo)
77
- .finally(() => {
78
- later(
79
- this,
80
- () => {
81
- // remove node from body
82
- document.body.removeChild(loaderNode);
83
- this.isLoaderNodeOpen = false;
84
- },
85
- 600 * 6
86
- );
87
- })
88
- .catch((error) => console.log(error));
57
+ try {
58
+ await this.router.transitionTo(this.redirectTo);
59
+ later(
60
+ this,
61
+ () => {
62
+ // remove node from body
63
+ document.body.removeChild(loaderNode);
64
+ this.isLoaderNodeOpen = false;
65
+ },
66
+ 600 * 6
67
+ );
68
+ } catch (error) {
69
+ this.notifications.serverError(error);
70
+ }
89
71
  }
90
72
 
91
73
  /**
@@ -113,31 +95,28 @@ export default class SessionService extends SimpleAuthSessionService {
113
95
  * @param {Transition} transition
114
96
  * @void
115
97
  */
116
- promiseCurrentUser(transition = null) {
98
+ async promiseCurrentUser(transition = null) {
117
99
  const invalidateWithLoader = this.invalidateWithLoader.bind(this);
118
100
 
119
- return new Promise((resolve, reject) => {
120
- return this.currentUser
121
- .promiseUser()
122
- .then((user) => {
123
- if (!user) {
124
- if (transition !== null) {
125
- transition.abort();
126
- }
127
-
128
- reject(invalidateWithLoader('Session authentication failed...'));
129
- }
130
-
131
- resolve(user);
132
- })
133
- .catch((error) => {
134
- if (transition !== null) {
135
- transition.abort();
136
- }
137
-
138
- reject(invalidateWithLoader(error.message ?? `Session authentication failed...`));
139
- });
140
- });
101
+ try {
102
+ const user = await this.currentUser.promiseUser();
103
+ if (!user) {
104
+ if (transition) {
105
+ transition.abort();
106
+ }
107
+
108
+ await invalidateWithLoader('Session authentication failed...');
109
+ throw new Error('Session authentication failed...');
110
+ }
111
+
112
+ return user;
113
+ } catch (error) {
114
+ if (transition) {
115
+ transition.abort();
116
+ }
117
+ await invalidateWithLoader(error.message ?? 'Session authentication failed...');
118
+ throw error;
119
+ }
141
120
  }
142
121
 
143
122
  /**
@@ -213,7 +213,7 @@ export default class ThemeService extends Service {
213
213
  * @void
214
214
  */
215
215
  setEnvironment() {
216
- const isSandbox = this.currentUser.getOption('sandbox') || false;
216
+ const isSandbox = this.currentUser.getOption('sandbox', false);
217
217
 
218
218
  if (isSandbox) {
219
219
  document.body.classList.add('sandbox-console');
@@ -1006,6 +1006,7 @@ export default class UniverseService extends Service.extend(Evented) {
1006
1006
  const inlineClass = this._getOption(options, 'inlineClass', null);
1007
1007
  const wrapperClass = this._getOption(options, 'wrapperClass', null);
1008
1008
  const overwriteWrapperClass = this._getOption(options, 'overwriteWrapperClass', false);
1009
+ const id = this._getOption(options, 'id', dasherize(title));
1009
1010
 
1010
1011
  // dasherize route segments
1011
1012
  if (typeof route === 'string') {
@@ -1015,9 +1016,11 @@ export default class UniverseService extends Service.extend(Evented) {
1015
1016
  .join('.');
1016
1017
  }
1017
1018
 
1018
- // todo: create menu item class
1019
+ // @todo: create menu item class
1019
1020
  const menuItem = {
1021
+ id,
1020
1022
  title,
1023
+ text: title,
1021
1024
  route,
1022
1025
  icon,
1023
1026
  priority,
@@ -0,0 +1,7 @@
1
+ import getModelName from './get-model-name';
2
+
3
+ export default function getModelSavePermission(service, model) {
4
+ const modelName = getModelName(model);
5
+ const ability = model && model.isNew ? 'create' : 'update';
6
+ return `${service} ${ability} ${modelName}`;
7
+ }
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/ember-core/decorators/legacy-fetch-from';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/ember-core/decorators/legacy-from-store';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/ember-core/utils/get-model-save-permission';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fleetbase/ember-core",
3
- "version": "0.2.15",
3
+ "version": "0.2.17",
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",