@fleetbase/ember-core 0.0.1
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/LICENSE.md +9 -0
- package/README.md +32 -0
- package/addon/adapters/application.js +155 -0
- package/addon/adapters/user.js +19 -0
- package/addon/authenticators/fleetbase.js +72 -0
- package/addon/decorators/fetch-from.js +55 -0
- package/addon/decorators/from-store.js +56 -0
- package/addon/decorators/is-equal.js +15 -0
- package/addon/exports/host-services.js +18 -0
- package/addon/exports/services.js +18 -0
- package/addon/initializers/local-storage-adapter.js +21 -0
- package/addon/serializers/application.js +87 -0
- package/addon/services/app-cache.js +59 -0
- package/addon/services/crud.js +226 -0
- package/addon/services/current-user.js +259 -0
- package/addon/services/fetch.js +648 -0
- package/addon/services/filters.js +183 -0
- package/addon/services/loader.js +136 -0
- package/addon/services/notifications.js +32 -0
- package/addon/services/session.js +221 -0
- package/addon/services/theme.js +200 -0
- package/addon/services/url-search-params.js +92 -0
- package/addon/transforms/array.js +29 -0
- package/addon/transforms/object.js +11 -0
- package/addon/transforms/raw.js +11 -0
- package/addon/utils/api-url.js +11 -0
- package/addon/utils/apply-column-filters.js +3 -0
- package/addon/utils/auto-serialize.js +100 -0
- package/addon/utils/calculate-percentage.js +3 -0
- package/addon/utils/close-sidebar.js +7 -0
- package/addon/utils/console-url.js +56 -0
- package/addon/utils/copy-to-clipboard.js +35 -0
- package/addon/utils/corslite.js +95 -0
- package/addon/utils/download.js +157 -0
- package/addon/utils/env.js +3 -0
- package/addon/utils/extract-coordinates.js +35 -0
- package/addon/utils/extract-latitude.js +28 -0
- package/addon/utils/extract-longitude.js +28 -0
- package/addon/utils/find-closest-waypoint.js +20 -0
- package/addon/utils/first.js +10 -0
- package/addon/utils/frontend-url.js +30 -0
- package/addon/utils/generate-slug.js +11 -0
- package/addon/utils/generate-uuid.js +3 -0
- package/addon/utils/get-length-units.js +44 -0
- package/addon/utils/get-meta-field-types.js +3 -0
- package/addon/utils/get-mime-type.js +25 -0
- package/addon/utils/get-model-name.js +45 -0
- package/addon/utils/get-permission-action.js +47 -0
- package/addon/utils/get-permission-resource.js +16 -0
- package/addon/utils/get-pod-methods.js +7 -0
- package/addon/utils/get-routing-host.js +44 -0
- package/addon/utils/get-service-name.js +21 -0
- package/addon/utils/get-user-options.js +21 -0
- package/addon/utils/get-weight-units.js +32 -0
- package/addon/utils/get-with-default.js +6 -0
- package/addon/utils/group-api-events.js +20 -0
- package/addon/utils/group-by.js +26 -0
- package/addon/utils/has-extension.js +11 -0
- package/addon/utils/has-json-structure.js +10 -0
- package/addon/utils/hason-structure.js +3 -0
- package/addon/utils/haversine.js +59 -0
- package/addon/utils/humanize.js +16 -0
- package/addon/utils/is-electron.js +18 -0
- package/addon/utils/is-email.js +5 -0
- package/addon/utils/is-function.js +3 -0
- package/addon/utils/is-image-file.js +3 -0
- package/addon/utils/is-iterable.js +7 -0
- package/addon/utils/is-json.js +9 -0
- package/addon/utils/is-latitude.js +3 -0
- package/addon/utils/is-letter.js +3 -0
- package/addon/utils/is-longitude.js +3 -0
- package/addon/utils/is-model.js +6 -0
- package/addon/utils/is-not-empty.js +5 -0
- package/addon/utils/is-not-model.js +5 -0
- package/addon/utils/is-numeric.js +3 -0
- package/addon/utils/is-object.js +3 -0
- package/addon/utils/is-proxy.js +5 -0
- package/addon/utils/is-relation-missing.js +21 -0
- package/addon/utils/is-valid-coordinates.js +38 -0
- package/addon/utils/is-video-file.js +3 -0
- package/addon/utils/is-waypoint-record.js +5 -0
- package/addon/utils/ison.js +3 -0
- package/addon/utils/isset.js +10 -0
- package/addon/utils/last.js +23 -0
- package/addon/utils/lazy-load-script.js +25 -0
- package/addon/utils/leaflet-icon.js +13 -0
- package/addon/utils/leaflet-points-from-coordinates.js +3 -0
- package/addon/utils/load-engines.js +37 -0
- package/addon/utils/load-extensions.js +8 -0
- package/addon/utils/macros/group-by.js +28 -0
- package/addon/utils/make-dataset.js +57 -0
- package/addon/utils/map-engines.js +30 -0
- package/addon/utils/mock-response.js +15 -0
- package/addon/utils/numbers-only.js +11 -0
- package/addon/utils/past-tense.js +40 -0
- package/addon/utils/path-to-route.js +10 -0
- package/addon/utils/polyline.js +161 -0
- package/addon/utils/range.js +19 -0
- package/addon/utils/refresh-route.js +3 -0
- package/addon/utils/replace-table-row.js +17 -0
- package/addon/utils/reverse-point.js +3 -0
- package/addon/utils/serialize/normalize-polymorphic-type-within-hash.js +27 -0
- package/addon/utils/serialize/normalize-polymorphic-type.js +13 -0
- package/addon/utils/serialize/normalize-relations-with-hash.js +32 -0
- package/addon/utils/set-column-filter-options.js +3 -0
- package/addon/utils/strip-html.js +3 -0
- package/addon/utils/to-leaflet-bounds.js +6 -0
- package/addon/utils/to-model.js +18 -0
- package/addon/utils/waypoint-label.js +3 -0
- package/addon/utils/with-default-value.js +5 -0
- package/addon/utils/words.js +5 -0
- package/app/adapters/user.js +1 -0
- package/app/authenticators/fleetbase.js +1 -0
- package/app/decorators/fetch-from.js +1 -0
- package/app/decorators/from-store.js +1 -0
- package/app/decorators/is-equal.js +1 -0
- package/app/exports/host-services.js +1 -0
- package/app/exports/services.js +1 -0
- package/app/initializers/local-storage-adapter.js +1 -0
- package/app/serializers/application.js +1 -0
- package/app/services/app-cache.js +1 -0
- package/app/services/crud.js +1 -0
- package/app/services/current-user.js +1 -0
- package/app/services/fetch.js +1 -0
- package/app/services/filters.js +1 -0
- package/app/services/loader.js +1 -0
- package/app/services/notifications.js +1 -0
- package/app/services/session.js +1 -0
- package/app/services/theme.js +1 -0
- package/app/services/url-search-params.js +1 -0
- package/app/storages/local-cache.js +12 -0
- package/app/storages/user-options.js +12 -0
- package/app/transforms/array.js +1 -0
- package/app/transforms/object.js +1 -0
- package/app/transforms/raw.js +1 -0
- package/app/utils/api-url.js +1 -0
- package/app/utils/apply-column-filters.js +1 -0
- package/app/utils/auto-serialize.js +1 -0
- package/app/utils/calculate-percentage.js +1 -0
- package/app/utils/close-sidebar.js +1 -0
- package/app/utils/console-url.js +1 -0
- package/app/utils/copy-to-clipboard.js +1 -0
- package/app/utils/corslite.js +1 -0
- package/app/utils/download.js +1 -0
- package/app/utils/env.js +1 -0
- package/app/utils/extract-coordinates.js +1 -0
- package/app/utils/extract-latitude.js +1 -0
- package/app/utils/extract-longitude.js +1 -0
- package/app/utils/find-closest-waypoint.js +1 -0
- package/app/utils/first.js +1 -0
- package/app/utils/frontend-url.js +1 -0
- package/app/utils/generate-slug.js +1 -0
- package/app/utils/generate-uuid.js +1 -0
- package/app/utils/get-length-units.js +1 -0
- package/app/utils/get-meta-field-types.js +1 -0
- package/app/utils/get-mime-type.js +1 -0
- package/app/utils/get-model-name.js +1 -0
- package/app/utils/get-permission-action.js +1 -0
- package/app/utils/get-permission-resource.js +1 -0
- package/app/utils/get-pod-methods.js +1 -0
- package/app/utils/get-routing-host.js +1 -0
- package/app/utils/get-service-name.js +1 -0
- package/app/utils/get-user-options.js +1 -0
- package/app/utils/get-weight-units.js +1 -0
- package/app/utils/get-with-default.js +1 -0
- package/app/utils/group-api-events.js +1 -0
- package/app/utils/group-by.js +1 -0
- package/app/utils/has-extension.js +1 -0
- package/app/utils/has-json-structure.js +1 -0
- package/app/utils/hason-structure.js +1 -0
- package/app/utils/haversine.js +1 -0
- package/app/utils/humanize.js +1 -0
- package/app/utils/is-electron.js +1 -0
- package/app/utils/is-email.js +1 -0
- package/app/utils/is-function.js +1 -0
- package/app/utils/is-image-file.js +1 -0
- package/app/utils/is-iterable.js +1 -0
- package/app/utils/is-latitude.js +1 -0
- package/app/utils/is-letter.js +1 -0
- package/app/utils/is-longitude.js +1 -0
- package/app/utils/is-model.js +1 -0
- package/app/utils/is-not-empty.js +1 -0
- package/app/utils/is-not-model.js +1 -0
- package/app/utils/is-numeric.js +1 -0
- package/app/utils/is-object.js +1 -0
- package/app/utils/is-proxy.js +1 -0
- package/app/utils/is-relation-missing.js +1 -0
- package/app/utils/is-valid-coordinates.js +1 -0
- package/app/utils/is-video-file.js +1 -0
- package/app/utils/is-waypoint-record.js +1 -0
- package/app/utils/ison.js +1 -0
- package/app/utils/isset.js +1 -0
- package/app/utils/last.js +1 -0
- package/app/utils/lazy-load-script.js +1 -0
- package/app/utils/leaflet-icon.js +1 -0
- package/app/utils/leaflet-points-from-coordinates.js +1 -0
- package/app/utils/load-engines.js +1 -0
- package/app/utils/load-extensions.js +1 -0
- package/app/utils/macros/group-by.js +1 -0
- package/app/utils/make-dataset.js +1 -0
- package/app/utils/map-engines.js +1 -0
- package/app/utils/mock-response.js +1 -0
- package/app/utils/numbers-only.js +1 -0
- package/app/utils/past-tense.js +1 -0
- package/app/utils/path-to-route.js +1 -0
- package/app/utils/polyline.js +1 -0
- package/app/utils/range.js +1 -0
- package/app/utils/refresh-route.js +1 -0
- package/app/utils/replace-table-row.js +1 -0
- package/app/utils/reverse-point.js +1 -0
- package/app/utils/serialize/normalize-polymorphic-type-within-hash.js +1 -0
- package/app/utils/serialize/normalize-polymorphic-type.js +1 -0
- package/app/utils/serialize/normalize-relations-with-hash.js +1 -0
- package/app/utils/set-column-filter-options.js +1 -0
- package/app/utils/strip-html.js +1 -0
- package/app/utils/to-leaflet-bounds.js +1 -0
- package/app/utils/to-model.js +1 -0
- package/app/utils/waypoint-label.js +1 -0
- package/app/utils/with-default-value.js +1 -0
- package/app/utils/words.js +1 -0
- package/config/environment.js +5 -0
- package/index.js +26 -0
- package/package.json +117 -0
- package/pnpm-lock.yaml +12750 -0
|
@@ -0,0 +1,648 @@
|
|
|
1
|
+
import Service from '@ember/service';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
import { inject as service } from '@ember/service';
|
|
4
|
+
import { get, set, setProperties } from '@ember/object';
|
|
5
|
+
import { isBlank } from '@ember/utils';
|
|
6
|
+
import { dasherize } from '@ember/string';
|
|
7
|
+
import { isArray } from '@ember/array';
|
|
8
|
+
import { assign } from '@ember/polyfills';
|
|
9
|
+
import { singularize, pluralize } from 'ember-inflector';
|
|
10
|
+
import { task } from 'ember-concurrency';
|
|
11
|
+
import { storageFor } from 'ember-local-storage';
|
|
12
|
+
import { intervalToDuration, parseISO } from 'date-fns';
|
|
13
|
+
import config from 'ember-get-config';
|
|
14
|
+
import corslite from '../utils/corslite';
|
|
15
|
+
import getMimeType from '../utils/get-mime-type';
|
|
16
|
+
import download from '../utils/download';
|
|
17
|
+
import getUserOptions from '../utils/get-user-options';
|
|
18
|
+
import fetch from 'fetch';
|
|
19
|
+
|
|
20
|
+
export default class FetchService extends Service {
|
|
21
|
+
/**
|
|
22
|
+
* Creates an instance of FetchService.
|
|
23
|
+
* @memberof FetchService
|
|
24
|
+
*/
|
|
25
|
+
constructor() {
|
|
26
|
+
super(...arguments);
|
|
27
|
+
|
|
28
|
+
this.headers = this.getHeaders();
|
|
29
|
+
this.host = get(config, 'API.host');
|
|
30
|
+
this.namespace = get(config, 'API.namespace');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Mutable headers property.
|
|
35
|
+
*
|
|
36
|
+
* @var {Array}
|
|
37
|
+
*/
|
|
38
|
+
@tracked headers;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Mutable namespace property.
|
|
42
|
+
*
|
|
43
|
+
* @var {String}
|
|
44
|
+
*/
|
|
45
|
+
@tracked namespace;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Mutable host property.
|
|
49
|
+
*
|
|
50
|
+
* @var {String}
|
|
51
|
+
*/
|
|
52
|
+
@tracked host;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Gets headers that should be sent with request.
|
|
56
|
+
*
|
|
57
|
+
* @return {Object}
|
|
58
|
+
*/
|
|
59
|
+
getHeaders() {
|
|
60
|
+
const headers = {};
|
|
61
|
+
const isAuthenticated = this.session.isAuthenticated;
|
|
62
|
+
const userId = this.session.data.authenticated.user;
|
|
63
|
+
const userOptions = getUserOptions();
|
|
64
|
+
const isSandbox = get(userOptions, `${userId}:sandbox`) === true;
|
|
65
|
+
const testKey = get(userOptions, `${userId}:testKey`);
|
|
66
|
+
|
|
67
|
+
headers['Content-Type'] = 'application/json';
|
|
68
|
+
|
|
69
|
+
if (isAuthenticated) {
|
|
70
|
+
headers['Authorization'] = `Bearer ${this.session.data.authenticated.token}`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (isAuthenticated && isSandbox) {
|
|
74
|
+
headers['Access-Console-Sandbox'] = true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (isAuthenticated && !isBlank(testKey)) {
|
|
78
|
+
headers['Access-Console-Sandbox-Key'] = testKey;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return headers;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Updates headers property before making request.
|
|
86
|
+
*
|
|
87
|
+
* @return {FetchService}
|
|
88
|
+
* @memberof FetchService
|
|
89
|
+
*/
|
|
90
|
+
refreshHeaders() {
|
|
91
|
+
this.headers = this.getHeaders();
|
|
92
|
+
|
|
93
|
+
return this;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Allows namespace to be set before making fetch request.
|
|
98
|
+
*
|
|
99
|
+
* @param {String} namespace
|
|
100
|
+
* @return {FetchService}
|
|
101
|
+
* @memberof FetchService
|
|
102
|
+
*/
|
|
103
|
+
setNamespace(namespace) {
|
|
104
|
+
this.namespace = namespace;
|
|
105
|
+
|
|
106
|
+
return this;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Allows host to be set before making fetch request.
|
|
111
|
+
*
|
|
112
|
+
* @param {String} host
|
|
113
|
+
* @return {FetchService}
|
|
114
|
+
* @memberof FetchService
|
|
115
|
+
*/
|
|
116
|
+
setHost(host) {
|
|
117
|
+
this.host = host;
|
|
118
|
+
|
|
119
|
+
return this;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Credentials
|
|
124
|
+
*
|
|
125
|
+
* @var {String}
|
|
126
|
+
*/
|
|
127
|
+
credentials = 'include';
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Inject the `store` service
|
|
131
|
+
*
|
|
132
|
+
* @var {Service}
|
|
133
|
+
*/
|
|
134
|
+
@service store;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Inject the `session` service
|
|
138
|
+
*
|
|
139
|
+
* @var {Service}
|
|
140
|
+
*/
|
|
141
|
+
@service session;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Inject the `currentUser` service
|
|
145
|
+
*
|
|
146
|
+
* @var {Service}
|
|
147
|
+
*/
|
|
148
|
+
@service currentUser;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Inject the `notifications` service
|
|
152
|
+
*
|
|
153
|
+
* @var {Service}
|
|
154
|
+
*/
|
|
155
|
+
@service notifications;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Local cache for some static requests
|
|
159
|
+
*
|
|
160
|
+
* @var StorageObject
|
|
161
|
+
*/
|
|
162
|
+
@storageFor('local-cache') localCache;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Normalizes a model response from fetch to a ember data model
|
|
166
|
+
*
|
|
167
|
+
* @param {Object} payload A response from a network request
|
|
168
|
+
* @param {String} modelType The type of model to be normalized too
|
|
169
|
+
*
|
|
170
|
+
* @return {Model} An ember model
|
|
171
|
+
*/
|
|
172
|
+
normalizeModel(payload, modelType = null) {
|
|
173
|
+
if (modelType === null) {
|
|
174
|
+
const modelTypeKeys = Object.keys(payload);
|
|
175
|
+
modelType = modelTypeKeys.length ? modelTypeKeys.firstObject : false;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (typeof modelType !== 'string') {
|
|
179
|
+
return payload;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const type = dasherize(singularize(modelType));
|
|
183
|
+
|
|
184
|
+
if (isArray(payload)) {
|
|
185
|
+
return payload.map((instance) => this.store.push(this.store.normalize(type, instance)));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (isArray(payload[modelType])) {
|
|
189
|
+
return payload[modelType].map((instance) => this.store.push(this.store.normalize(type, instance)));
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (!isBlank(payload) && isBlank(payload[modelType])) {
|
|
193
|
+
return this.jsonToModel(payload, type);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return this.store.push(this.store.normalize(type, payload[modelType]));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Normalizes a model response from a JSON object or string
|
|
201
|
+
*
|
|
202
|
+
* @param {Object} payload A response from a network request
|
|
203
|
+
* @param {String} modelType The type of model to be normalized too
|
|
204
|
+
*
|
|
205
|
+
* @return {Model} An ember model
|
|
206
|
+
*/
|
|
207
|
+
jsonToModel(attributes = {}, modelType) {
|
|
208
|
+
if (typeof attributes === 'string') {
|
|
209
|
+
attributes = JSON.parse(attributes);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const type = dasherize(modelType);
|
|
213
|
+
const normalized = this.store.push(this.store.normalize(type, attributes));
|
|
214
|
+
|
|
215
|
+
return normalized;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Parses the JSON returned by a network request
|
|
220
|
+
*
|
|
221
|
+
* @param {Object} response A response from a network request
|
|
222
|
+
* @return {Object} The parsed JSON, status from the response
|
|
223
|
+
*
|
|
224
|
+
* @return {Promise}
|
|
225
|
+
*/
|
|
226
|
+
parseJSON(response) {
|
|
227
|
+
return new Promise((resolve, reject) =>
|
|
228
|
+
response
|
|
229
|
+
.json()
|
|
230
|
+
.then((json) =>
|
|
231
|
+
resolve({
|
|
232
|
+
statusText: response.statusText,
|
|
233
|
+
status: response.status,
|
|
234
|
+
ok: response.ok,
|
|
235
|
+
json,
|
|
236
|
+
})
|
|
237
|
+
)
|
|
238
|
+
.catch(() => {
|
|
239
|
+
reject(new Error('Oops! Something went wrong when handling your request.'));
|
|
240
|
+
})
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* The base request method
|
|
246
|
+
*
|
|
247
|
+
* @param {String} path
|
|
248
|
+
* @param {String} method
|
|
249
|
+
* @param {Object} data
|
|
250
|
+
* @param {Object} options
|
|
251
|
+
*
|
|
252
|
+
* @return {Promise}
|
|
253
|
+
*/
|
|
254
|
+
request(path, method = 'GET', data = {}, options = {}) {
|
|
255
|
+
const headers = assign(this.getHeaders(), options.headers ?? {});
|
|
256
|
+
|
|
257
|
+
return new Promise((resolve, reject) => {
|
|
258
|
+
return fetch(options.externalRequest === true ? path : `${options.host || this.host}/${options.namespace || this.namespace}/${path}`, {
|
|
259
|
+
method,
|
|
260
|
+
mode: options.mode || 'cors',
|
|
261
|
+
credentials: options.credentials || this.credentials,
|
|
262
|
+
headers,
|
|
263
|
+
...data,
|
|
264
|
+
})
|
|
265
|
+
.then(this.parseJSON)
|
|
266
|
+
.then((response) => {
|
|
267
|
+
// console.log('[fetch:response]', response);
|
|
268
|
+
if (response.ok) {
|
|
269
|
+
if (options.normalizeToEmberData) {
|
|
270
|
+
const normalized = this.normalizeModel(response.json, options.normalizeModelType);
|
|
271
|
+
|
|
272
|
+
if (typeof options.onSuccess === 'function') {
|
|
273
|
+
options.onSuccess(normalized);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return resolve(normalized);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (typeof options.onSuccess === 'function') {
|
|
280
|
+
options.onSuccess(response.json);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return resolve(response.json);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (typeof options.onError === 'function') {
|
|
287
|
+
options.onError(response.json);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (options.rawError) {
|
|
291
|
+
return reject(response.json);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (isArray(response.json.errors)) {
|
|
295
|
+
return reject(new Error(response.json.errors ? response.json.errors.firstObject : response.statusText));
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (response.json.error && typeof response.json.error) {
|
|
299
|
+
return reject(new Error(response.json.error));
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (response.json.message && typeof response.json.message) {
|
|
303
|
+
return reject(new Error(response.json.message));
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return reject(response.json);
|
|
307
|
+
})
|
|
308
|
+
.catch(reject);
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Makes a GET request with fetch
|
|
314
|
+
*
|
|
315
|
+
* @param {String} path
|
|
316
|
+
* @param {Object} query
|
|
317
|
+
* @param {Object} options
|
|
318
|
+
*
|
|
319
|
+
* @return {Promise}
|
|
320
|
+
*/
|
|
321
|
+
get(path, query = {}, options = {}) {
|
|
322
|
+
// handle if want to request from cache
|
|
323
|
+
if (options.fromCache === true) {
|
|
324
|
+
return this.cachedGet(...arguments);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const urlParams = !isBlank(query) ? new URLSearchParams(query).toString() : '';
|
|
328
|
+
|
|
329
|
+
return this.request(`${path}${urlParams ? '?' + urlParams : ''}`, 'GET', {}, options);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Makes a GET request with fetch, but if the fetch is stored in local cache,
|
|
334
|
+
* retrieve from storage to prevent unnecessary netwrok request
|
|
335
|
+
*
|
|
336
|
+
* @param {String} path
|
|
337
|
+
* @param {Object} query
|
|
338
|
+
* @param {Object} options
|
|
339
|
+
*
|
|
340
|
+
* @return {Promise}
|
|
341
|
+
*/
|
|
342
|
+
cachedGet(path, query = {}, options = {}) {
|
|
343
|
+
const pathKey = dasherize(path);
|
|
344
|
+
const pathKeyVersion = new Date().toISOString();
|
|
345
|
+
|
|
346
|
+
const request = () => {
|
|
347
|
+
return this.get(path, query, options).then((response) => {
|
|
348
|
+
// cache the response
|
|
349
|
+
this.localCache.set(pathKey, response);
|
|
350
|
+
this.localCache.set(`${pathKey}-version`, pathKeyVersion);
|
|
351
|
+
|
|
352
|
+
// return response
|
|
353
|
+
return response;
|
|
354
|
+
});
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
// check to see if in storage already
|
|
358
|
+
if (this.localCache.get(pathKey)) {
|
|
359
|
+
return new Promise((resolve) => {
|
|
360
|
+
// get cached data
|
|
361
|
+
const data = this.localCache.get(pathKey);
|
|
362
|
+
|
|
363
|
+
// get the path key version value
|
|
364
|
+
const version = this.localCache.get(`${pathKey}-version`);
|
|
365
|
+
const expirationInterval = options.expirationInterval ?? 3;
|
|
366
|
+
const expirationIntervalUnit = pluralize(options.expirationIntervalUnit ?? 'days');
|
|
367
|
+
|
|
368
|
+
// calculate duration between cache version and now
|
|
369
|
+
const duration = intervalToDuration({
|
|
370
|
+
start: parseISO(version),
|
|
371
|
+
end: new Date(),
|
|
372
|
+
});
|
|
373
|
+
// determine if we should expire cache
|
|
374
|
+
const shouldExpire = duration[expirationIntervalUnit] > expirationInterval;
|
|
375
|
+
|
|
376
|
+
// if the version is older than 3 days clear it
|
|
377
|
+
if (!version || shouldExpire || options.clearData === true) {
|
|
378
|
+
this.flushRequestCache(path);
|
|
379
|
+
return request();
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (options.normalizeToEmberData) {
|
|
383
|
+
return resolve(this.normalizeModel(data, options.normalizeModelType));
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// return cached response
|
|
387
|
+
return resolve(data);
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// if no cached data request from server
|
|
392
|
+
return request();
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
flushRequestCache(path) {
|
|
396
|
+
const pathKey = dasherize(path);
|
|
397
|
+
|
|
398
|
+
this.localCache.set(pathKey, undefined);
|
|
399
|
+
this.localCache.set(`${pathKey}-version`, undefined);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
shouldResetCache() {
|
|
403
|
+
const consoleVersion = this.localCache.get('console-version');
|
|
404
|
+
|
|
405
|
+
if (!consoleVersion || consoleVersion !== config.APP.version) {
|
|
406
|
+
this.localCache.clear();
|
|
407
|
+
this.localCache.set('console-version', config.APP.version);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Makes a POST request with fetch
|
|
413
|
+
*
|
|
414
|
+
* @param {String} path
|
|
415
|
+
* @param {Object} data
|
|
416
|
+
* @param {Object} options
|
|
417
|
+
*
|
|
418
|
+
* @return {Promise}
|
|
419
|
+
*/
|
|
420
|
+
post(path, data = {}, options = {}) {
|
|
421
|
+
return this.request(path, 'POST', { body: JSON.stringify(data) }, options);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Makes a PUT request with fetch
|
|
426
|
+
*
|
|
427
|
+
* @param {String} path
|
|
428
|
+
* @param {Object} data
|
|
429
|
+
* @param {Object} options
|
|
430
|
+
*
|
|
431
|
+
* @return {Promise}
|
|
432
|
+
*/
|
|
433
|
+
put(path, data = {}, options = {}) {
|
|
434
|
+
return this.request(path, 'PUT', { body: JSON.stringify(data) }, options);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Makes a DELETE request with fetch
|
|
439
|
+
*
|
|
440
|
+
* @param {String} path
|
|
441
|
+
* @param {Object} data
|
|
442
|
+
* @param {Object} options
|
|
443
|
+
*
|
|
444
|
+
* @return {Promise}
|
|
445
|
+
*/
|
|
446
|
+
delete(path, data = {}, options = {}) {
|
|
447
|
+
return this.request(path, 'DELETE', { body: JSON.stringify(data) }, options);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Makes a PATCH request with fetch
|
|
452
|
+
* @param {String} path
|
|
453
|
+
* @param {Object} data
|
|
454
|
+
* @param {Object} options
|
|
455
|
+
*
|
|
456
|
+
* @return {Promise}
|
|
457
|
+
*/
|
|
458
|
+
patch(path, data = {}, options = {}) {
|
|
459
|
+
return this.request(path, 'PATCH', { body: JSON.stringify(data) }, options);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Makes a upload request with fetch
|
|
464
|
+
*
|
|
465
|
+
* @param {String} path
|
|
466
|
+
* @param {Array} files
|
|
467
|
+
* @param {Object} options
|
|
468
|
+
*
|
|
469
|
+
* @return {Promise}
|
|
470
|
+
*/
|
|
471
|
+
upload(path, files = [], options = {}) {
|
|
472
|
+
const body = new FormData();
|
|
473
|
+
files.forEach((file) => {
|
|
474
|
+
body.append('file', file);
|
|
475
|
+
});
|
|
476
|
+
return this.request(path, 'POST', { body }, options);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Sends request to routing service.
|
|
481
|
+
*
|
|
482
|
+
* @param {Array} coordinates
|
|
483
|
+
* @param {Object} query
|
|
484
|
+
* @param {String} service
|
|
485
|
+
* @param {String} profile
|
|
486
|
+
* @param {String} version
|
|
487
|
+
*/
|
|
488
|
+
routing(coordinates, query = {}, options = {}) {
|
|
489
|
+
let service = options?.service ?? 'trip';
|
|
490
|
+
let profile = options?.profile ?? 'driving';
|
|
491
|
+
let version = options?.version ?? 'v1';
|
|
492
|
+
let host = options?.host ?? `https://${options?.subdomain ?? 'routing'}.fleetbase.io`;
|
|
493
|
+
let route = coordinates.map((coords) => coords.join(',')).join(';');
|
|
494
|
+
let params = !isBlank(query) ? new URLSearchParams(query).toString() : '';
|
|
495
|
+
let path = `${host}/${service}/${version}/${profile}/${route}`;
|
|
496
|
+
let url = `${path}${params ? '?' + params : ''}`;
|
|
497
|
+
|
|
498
|
+
return new Promise((resolve, reject) => {
|
|
499
|
+
corslite(url, (container, xhr) => {
|
|
500
|
+
if (!xhr || !xhr.response) {
|
|
501
|
+
reject(new Error('Request failed.'));
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
let response = xhr.response;
|
|
506
|
+
let isJson = typeof response === 'string' && response.startsWith('{');
|
|
507
|
+
|
|
508
|
+
resolve(isJson ? JSON.parse(response) : response);
|
|
509
|
+
});
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Concurrency task to handle a file upload
|
|
515
|
+
*
|
|
516
|
+
* @void
|
|
517
|
+
*/
|
|
518
|
+
@(task(function* (file, params = {}, callback, errorCallback) {
|
|
519
|
+
const { queue } = file;
|
|
520
|
+
const headers = this.getHeaders();
|
|
521
|
+
|
|
522
|
+
// remove Content-Type header
|
|
523
|
+
delete headers['Content-Type'];
|
|
524
|
+
|
|
525
|
+
try {
|
|
526
|
+
const upload = yield file
|
|
527
|
+
.upload(`${get(config, 'API.host')}/${get(config, 'API.namespace')}/files/upload`, {
|
|
528
|
+
data: {
|
|
529
|
+
...params,
|
|
530
|
+
file_size: file.size,
|
|
531
|
+
},
|
|
532
|
+
withCredentials: true,
|
|
533
|
+
headers,
|
|
534
|
+
})
|
|
535
|
+
.then((response) => response.json());
|
|
536
|
+
|
|
537
|
+
const model = this.store.push(this.store.normalize('file', upload.file));
|
|
538
|
+
set(file, 'model', model);
|
|
539
|
+
|
|
540
|
+
if (typeof callback === 'function') {
|
|
541
|
+
callback(model);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
return model;
|
|
545
|
+
} catch (error) {
|
|
546
|
+
queue.remove(file);
|
|
547
|
+
this.notifications.serverError(error, `Upload failed.`);
|
|
548
|
+
|
|
549
|
+
if (typeof errorCallback === 'function') {
|
|
550
|
+
errorCallback(error);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
})
|
|
554
|
+
.maxConcurrency(3)
|
|
555
|
+
.enqueue())
|
|
556
|
+
uploadFile;
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Downloads blob of the request path to user
|
|
560
|
+
*
|
|
561
|
+
* @param {String} path
|
|
562
|
+
* @param {Object} query
|
|
563
|
+
* @param {Object} options
|
|
564
|
+
*
|
|
565
|
+
* @return {Promise}
|
|
566
|
+
*/
|
|
567
|
+
download(path, query = {}, options = {}) {
|
|
568
|
+
const headers = assign(this.getHeaders(), options.headers ?? {});
|
|
569
|
+
|
|
570
|
+
return new Promise((resolve, reject) => {
|
|
571
|
+
return fetch(`${options.host || this.host}/${options.namespace || this.namespace}/${path}?${!isBlank(query) ? new URLSearchParams(query).toString() : ''}`, {
|
|
572
|
+
method: 'GET',
|
|
573
|
+
credentials: options.credentials || this.credentials,
|
|
574
|
+
headers,
|
|
575
|
+
})
|
|
576
|
+
.then((response) => {
|
|
577
|
+
options.fileName = this.getFilenameFromResponse(response, options.fileName);
|
|
578
|
+
options.mimeType = this.getMimeTypeFromResponse(response, options.mimeType);
|
|
579
|
+
|
|
580
|
+
if (!options.mimeType) {
|
|
581
|
+
options.mimeType = getMimeType(options.fileName);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
return response;
|
|
585
|
+
})
|
|
586
|
+
.then((response) => response.blob())
|
|
587
|
+
.then((blob) => resolve(download(blob, options.fileName, options.mimeType)))
|
|
588
|
+
.catch((error) => {
|
|
589
|
+
reject(error);
|
|
590
|
+
});
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
getFilenameFromResponse(response, defaultFilename = null) {
|
|
595
|
+
const contentDisposition = response.headers.get('content-disposition');
|
|
596
|
+
let fileName = defaultFilename;
|
|
597
|
+
|
|
598
|
+
if (contentDisposition) {
|
|
599
|
+
const results = /filename=(.*)/.exec(contentDisposition);
|
|
600
|
+
|
|
601
|
+
if (isArray(results) && results.length > 1) {
|
|
602
|
+
fileName = results[1];
|
|
603
|
+
|
|
604
|
+
// clean fileName
|
|
605
|
+
fileName = fileName.replaceAll('"', '');
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
return fileName;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
getMimeTypeFromResponse(response, defaultMimeType = null) {
|
|
613
|
+
const contentType = response.headers.get('content-type');
|
|
614
|
+
let mimeType = defaultMimeType;
|
|
615
|
+
|
|
616
|
+
if (contentType) {
|
|
617
|
+
const results = /(.*)?;/.exec(contentType);
|
|
618
|
+
|
|
619
|
+
if (isArray(results) && results.length > 1) {
|
|
620
|
+
mimeType = results[1];
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
return mimeType;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
fetchOrderConfigurations(params = {}) {
|
|
628
|
+
return new Promise((resolve, reject) => {
|
|
629
|
+
this.request('fleet-ops/order-configs/get-installed', params)
|
|
630
|
+
.then((configs) => {
|
|
631
|
+
const serialized = [];
|
|
632
|
+
|
|
633
|
+
for (let i = 0; i < configs.length; i++) {
|
|
634
|
+
const config = configs.objectAt(i);
|
|
635
|
+
const normalizedConfig = this.store.normalize('order-config', config);
|
|
636
|
+
const serializedConfig = this.store.push(normalizedConfig);
|
|
637
|
+
|
|
638
|
+
serialized.pushObject(serializedConfig);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
resolve(serialized);
|
|
642
|
+
})
|
|
643
|
+
.catch((error) => {
|
|
644
|
+
reject(error);
|
|
645
|
+
});
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
}
|