@onehat/data 1.21.19 → 1.21.21
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/cypress/e2e/Property/Mixed.cy.js +105 -0
- package/cypress/e2e/Property/Property.cy.js +7 -1
- package/cypress/e2e/Repository/Ajax.cy.js +15 -0
- package/cypress/support/e2e.js +1 -0
- package/cypress/support/index.js +20 -0
- package/cypress.config.js +18 -16
- package/package.json +18 -19
- package/src/Entity/Entity.js +32 -21
- package/src/OneHatData.js +7 -5
- package/src/Property/Currency.js +1 -1
- package/src/Property/Json.js +1 -1
- package/src/Property/Mixed.js +458 -0
- package/src/Property/Property.js +21 -0
- package/src/Property/index.js +2 -0
- package/src/Reader/index.js +2 -2
- package/src/Repository/Ajax.js +241 -28
- package/src/Repository/OneBuild.js +73 -434
- package/src/Repository/Repository.js +41 -94
- package/src/Repository/Tree.js +452 -0
- package/src/Repository/index.js +2 -0
- package/src/Schema/Schema.js +6 -9
- package/src/Writer/index.js +2 -2
- package/src/Repository/OneBuild2.js +0 -953
|
@@ -1,953 +0,0 @@
|
|
|
1
|
-
/** @module Repository */
|
|
2
|
-
|
|
3
|
-
import Repository from './Repository.js';
|
|
4
|
-
import AjaxRepository from './Ajax.js';
|
|
5
|
-
import qs from 'qs';
|
|
6
|
-
import _ from 'lodash';
|
|
7
|
-
|
|
8
|
-
const nonConditionFilters = [
|
|
9
|
-
'q',
|
|
10
|
-
'hydrate',
|
|
11
|
-
'fields',
|
|
12
|
-
'distinct',
|
|
13
|
-
'leftJoinWith',
|
|
14
|
-
'join',
|
|
15
|
-
'where',
|
|
16
|
-
'matching',
|
|
17
|
-
'contain',
|
|
18
|
-
'order',
|
|
19
|
-
'limit',
|
|
20
|
-
'page',
|
|
21
|
-
];
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* This class contains overrides of specific functions in
|
|
25
|
-
* AjaxRepository that are unique to OneBuild2.
|
|
26
|
-
*
|
|
27
|
-
* @extends AjaxRepository
|
|
28
|
-
*/
|
|
29
|
-
class OneBuild2Repository extends AjaxRepository {
|
|
30
|
-
constructor(config = {}) {
|
|
31
|
-
super(...arguments);
|
|
32
|
-
|
|
33
|
-
const defaults = {
|
|
34
|
-
|
|
35
|
-
isAutoLoad: false,
|
|
36
|
-
isAutoSave: false,
|
|
37
|
-
|
|
38
|
-
api: {
|
|
39
|
-
get: this.name + '/index',
|
|
40
|
-
add: this.name + '/store',
|
|
41
|
-
edit: this.name + '/update',
|
|
42
|
-
delete: this.name + '/destroy',
|
|
43
|
-
// batchAdd: this.name + '/batchAdd',
|
|
44
|
-
// batchEdit: this.name + '/batchEdit',
|
|
45
|
-
// batchDelete: this.name + '/batchDelete',
|
|
46
|
-
},
|
|
47
|
-
|
|
48
|
-
methods: {
|
|
49
|
-
// get: 'POST',
|
|
50
|
-
},
|
|
51
|
-
|
|
52
|
-
rootProperty: 'data',
|
|
53
|
-
successProperty: 'success',
|
|
54
|
-
totalProperty: 'total',
|
|
55
|
-
messageProperty: 'message',
|
|
56
|
-
|
|
57
|
-
allowsMultiSort: true,
|
|
58
|
-
// batchAsSynchronous: true, // Add directly to schema for now
|
|
59
|
-
// combineBatch: true,
|
|
60
|
-
|
|
61
|
-
// writer: {
|
|
62
|
-
// type: 'json',
|
|
63
|
-
// asForm: true,
|
|
64
|
-
// writeAllFields: true,
|
|
65
|
-
// },
|
|
66
|
-
|
|
67
|
-
queryParam: 'q', // General-purpose query/searching parameter
|
|
68
|
-
allQuery: 'getAll', // For getting all results. Basically, nullifies queryParam on backend
|
|
69
|
-
|
|
70
|
-
};
|
|
71
|
-
_.merge(this, defaults, config);
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* @member {boolean} allowsMultiSort - Whether to allow >1 sorter
|
|
75
|
-
*/
|
|
76
|
-
this.allowsMultiSort = true;
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
async initialize() {
|
|
81
|
-
|
|
82
|
-
this.registerEvents([
|
|
83
|
-
'logout',
|
|
84
|
-
]);
|
|
85
|
-
|
|
86
|
-
await super.initialize();
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Override parent so we can emit 'logout' event on 401 error
|
|
91
|
-
*
|
|
92
|
-
* Helper for _do* save operations.
|
|
93
|
-
* Fires off axios request to server
|
|
94
|
-
* @private
|
|
95
|
-
*/
|
|
96
|
-
_send = (method, url, data) => {
|
|
97
|
-
|
|
98
|
-
if (!url) {
|
|
99
|
-
this.throwError('No url submitted');
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (!this.isOnline) {
|
|
104
|
-
this.throwError('Offline');
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const headers = _.merge({
|
|
109
|
-
// 'Content-Type': 'application/json', // Stops axios from using 'application/x-www-form-urlencoded'
|
|
110
|
-
Accept: 'application/json',
|
|
111
|
-
}, this.headers);
|
|
112
|
-
|
|
113
|
-
const options = {
|
|
114
|
-
url,
|
|
115
|
-
method,
|
|
116
|
-
baseURL: this.api.baseURL,
|
|
117
|
-
transformResponse: null,
|
|
118
|
-
headers,
|
|
119
|
-
params: method === 'GET' ? data : null,
|
|
120
|
-
data: method !== 'GET' ? qs.stringify(data) : null,
|
|
121
|
-
timeout: this.timeout,
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
if (this.debugMode) {
|
|
125
|
-
console.log('Sending ' + url, options);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
this.lastSendOptions = options;
|
|
129
|
-
|
|
130
|
-
return this.axios(options)
|
|
131
|
-
.catch(error => {
|
|
132
|
-
if (this.debugMode) {
|
|
133
|
-
console.log(url + ' error', error);
|
|
134
|
-
console.log('response:', error.response);
|
|
135
|
-
}
|
|
136
|
-
// BEGIN MOD
|
|
137
|
-
if (error && error.response && error.response.status === 401) {
|
|
138
|
-
this.emit('logout');
|
|
139
|
-
console.log('logout');
|
|
140
|
-
return false;
|
|
141
|
-
}
|
|
142
|
-
// END MOD
|
|
143
|
-
|
|
144
|
-
this.throwError(error);
|
|
145
|
-
return;
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Helper for reloadEntity.
|
|
151
|
-
* @private
|
|
152
|
-
*/
|
|
153
|
-
_getReloadEntityParams(entity) {
|
|
154
|
-
const params = { conditions: {}, };
|
|
155
|
-
params.conditions[entity.schema.name + '.id'] = entity.id;
|
|
156
|
-
return params;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Sets "conditions" param.
|
|
161
|
-
* OneBuild uses a single, multi-dimentional param for filtering.
|
|
162
|
-
* Refreshes entities.
|
|
163
|
-
*/
|
|
164
|
-
_onChangeFilters = () => {
|
|
165
|
-
// Clear existing "conditions" params
|
|
166
|
-
if (!_.isEmpty(this._params)) {
|
|
167
|
-
this._params = _.omitBy(this._params, (value, key) => {
|
|
168
|
-
return key.match(/^conditions/) || _.includes(nonConditionFilters, key);
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const oThis = this;
|
|
173
|
-
_.each(this.filters, (filter, ix) => {
|
|
174
|
-
if (_.includes(nonConditionFilters, filter.name)) {
|
|
175
|
-
oThis.setParam(filter.name, filter.value);
|
|
176
|
-
} else {
|
|
177
|
-
oThis.setParam('conditions[' + filter.name + ']', filter.value);
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
if (this.isLoaded && !this.eventsPaused) {
|
|
182
|
-
if (this.isTree) {
|
|
183
|
-
return this.loadRootNodes(1);
|
|
184
|
-
} else {
|
|
185
|
-
return this.reload();
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Sets "order" param.
|
|
192
|
-
* OneBuild uses a single order param, rather than separate name & direction params.
|
|
193
|
-
* Refreshes entities.
|
|
194
|
-
*/
|
|
195
|
-
_onChangeSorters = () => {
|
|
196
|
-
let sorterStrings = [];
|
|
197
|
-
_.each(this.sorters, (sorter) => {
|
|
198
|
-
sorterStrings.push(sorter.name + ' ' + sorter.direction);
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
if (!_.isEmpty(sorterStrings)) {
|
|
202
|
-
this.setBaseParam('order', sorterStrings.join(','));
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
if (!this.eventsPaused) {
|
|
206
|
-
if (this.isLoaded && this.isAutoLoad) {
|
|
207
|
-
if (this.isTree) {
|
|
208
|
-
return this.loadRootNodes(1).then(() => {
|
|
209
|
-
this.emit('changeSorters');
|
|
210
|
-
});
|
|
211
|
-
} else {
|
|
212
|
-
return this.reload().then(() => {
|
|
213
|
-
this.emit('changeSorters');
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
} else {
|
|
217
|
-
this.emit('changeSorters');
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Helper for _send.
|
|
224
|
-
* Handles server's response to _send().
|
|
225
|
-
* This is basically just looking for errors.
|
|
226
|
-
* @fires error
|
|
227
|
-
* @private
|
|
228
|
-
*/
|
|
229
|
-
_processServerResponse = (result) => {
|
|
230
|
-
|
|
231
|
-
if (result === false) { // e.g. 401 error
|
|
232
|
-
return {
|
|
233
|
-
root: null,
|
|
234
|
-
success: false,
|
|
235
|
-
total: 0,
|
|
236
|
-
message: null,
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
const
|
|
241
|
-
response = _.isPlainObject(result.data) ? result.data : this.reader.read(result.data),
|
|
242
|
-
root = response[this.rootProperty],
|
|
243
|
-
success = response[this.successProperty],
|
|
244
|
-
total = response[this.totalProperty],
|
|
245
|
-
message = response[this.messageProperty];
|
|
246
|
-
|
|
247
|
-
if (!success) {
|
|
248
|
-
this.emit('error', message, root);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
if (message === 'You do not have authorization to access this area.') {
|
|
252
|
-
this.emit('logout');
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
return {
|
|
256
|
-
root,
|
|
257
|
-
success,
|
|
258
|
-
total,
|
|
259
|
-
message
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Integrates with RestTrait::reorder in OneBuild API
|
|
266
|
-
* @param {entity|array} dragRecordOrIds - which entity or ids were being dragged
|
|
267
|
-
* @param {entity} dropRecord - which entity it was dropped on to
|
|
268
|
-
* @param {string} dropPosition - position in which it was dropped; could be 'before' or 'after'
|
|
269
|
-
* @return {Promise}
|
|
270
|
-
*/
|
|
271
|
-
reorder = (dragRecordOrIds, dropRecord, dropPosition) => {
|
|
272
|
-
|
|
273
|
-
if (!this.isOnline) {
|
|
274
|
-
this.throwError('Offline');
|
|
275
|
-
return;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
let ids;
|
|
279
|
-
if (_.isArray(dragRecordOrIds)) {
|
|
280
|
-
ids = dragRecordOrIds;
|
|
281
|
-
} else if (dragRecordOrIds?.id) {
|
|
282
|
-
ids = [dragRecordOrIds.id];
|
|
283
|
-
} else {
|
|
284
|
-
throw Error('dragRecordOrIds must be an entity or array of ids')
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
const data = {
|
|
288
|
-
url: this.name + '/reorder',
|
|
289
|
-
data: qs.stringify({
|
|
290
|
-
ids,
|
|
291
|
-
dropPosition,
|
|
292
|
-
dropRecord_id: dropRecord.id,
|
|
293
|
-
}),
|
|
294
|
-
method: 'POST',
|
|
295
|
-
baseURL: this.api.baseURL,
|
|
296
|
-
};
|
|
297
|
-
|
|
298
|
-
if (this.debugMode) {
|
|
299
|
-
console.log('reorder', data);
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
return this.axios(data)
|
|
303
|
-
.then((result) => {
|
|
304
|
-
if (this.debugMode) {
|
|
305
|
-
console.log('reorder response', result);
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
const response = result.data;
|
|
309
|
-
if (!response.success) {
|
|
310
|
-
this.throwError(response.data);
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
// Reload the repository, so updated sort_order values can be retrieved
|
|
315
|
-
this.reload();
|
|
316
|
-
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
remoteDuplicate = async (entity) => {
|
|
321
|
-
|
|
322
|
-
this.markLoading();
|
|
323
|
-
|
|
324
|
-
const
|
|
325
|
-
Model = this.getSchema().name,
|
|
326
|
-
id = entity.id,
|
|
327
|
-
result = await this._send('POST', Model + '/duplicate', { id });
|
|
328
|
-
|
|
329
|
-
if (!result) {
|
|
330
|
-
this.markLoading(false);
|
|
331
|
-
this.throwError('error duplicating on server');
|
|
332
|
-
return;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
const {
|
|
336
|
-
root,
|
|
337
|
-
success,
|
|
338
|
-
total,
|
|
339
|
-
message
|
|
340
|
-
} = this._processServerResponse(result);
|
|
341
|
-
|
|
342
|
-
if (!success) {
|
|
343
|
-
this.markLoading(false);
|
|
344
|
-
throw Error(message);
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// Click duplicateId. The new row appears directly above the one that was duplicated
|
|
348
|
-
// The new duplicate is selected
|
|
349
|
-
// The display field should read "{old name} (duplicate)"
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
const duplicateEntity = await this.createStandaloneEntity(root, true, true);
|
|
353
|
-
if (entity.isRemotePhantomMode) {
|
|
354
|
-
entity.isRemotePhantom = true;
|
|
355
|
-
}
|
|
356
|
-
this._insertBefore(duplicateEntity, entity);
|
|
357
|
-
|
|
358
|
-
this.markLoading(false);
|
|
359
|
-
return duplicateEntity;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
loadOneAdditionalEntity = async (id) => {
|
|
363
|
-
const entity = await this.getSingleEntityFromServer(id);
|
|
364
|
-
if (!entity) {
|
|
365
|
-
this.throwError('entity not found');
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
this._relayEntityEvents(entity);
|
|
370
|
-
this.entities.push(entity);
|
|
371
|
-
this.total++;
|
|
372
|
-
this._setPaginationVars();
|
|
373
|
-
this.emit('changeData', this.entities);
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
getSingleEntityFromServer = async (id) => {
|
|
377
|
-
if (this.isDestroyed) {
|
|
378
|
-
this.throwError('this.getSingleEntityFromServer is no longer valid. Repository has been destroyed.');
|
|
379
|
-
return;
|
|
380
|
-
}
|
|
381
|
-
if (!this.api.get) {
|
|
382
|
-
this.throwError('No "get" api endpoint defined.');
|
|
383
|
-
return;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
if (!id) {
|
|
387
|
-
return null;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
this.markLoading();
|
|
391
|
-
|
|
392
|
-
const idPropertyName = this.getSchema().model.idProperty;
|
|
393
|
-
const params = {};
|
|
394
|
-
params['conditions[' + idPropertyName + ']'] = id;
|
|
395
|
-
|
|
396
|
-
const data = _.merge(params, this._baseParams);
|
|
397
|
-
|
|
398
|
-
if (this.debugMode) {
|
|
399
|
-
console.log('getSingleEntityFromServer', data);
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
return this._send(this.methods.get, this.api.get, data)
|
|
403
|
-
.then(result => {
|
|
404
|
-
if (this.debugMode) {
|
|
405
|
-
console.log('Response for getSingleEntityFromServer for ' + this.name, result);
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
if (this.isDestroyed) {
|
|
409
|
-
// If this repository gets destroyed before it has a chance
|
|
410
|
-
// to process the Ajax request, just ignore the response.
|
|
411
|
-
return;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
const {
|
|
415
|
-
root,
|
|
416
|
-
success,
|
|
417
|
-
total,
|
|
418
|
-
message
|
|
419
|
-
} = this._processServerResponse(result);
|
|
420
|
-
|
|
421
|
-
if (!root[0]) {
|
|
422
|
-
return null;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
const entity = this.createStandaloneEntity(root[0]);
|
|
426
|
-
entity.isRemotePhantom = false;
|
|
427
|
-
return entity;
|
|
428
|
-
})
|
|
429
|
-
.finally(() => {
|
|
430
|
-
this.markLoading(false);
|
|
431
|
-
});
|
|
432
|
-
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
/**
|
|
436
|
-
* Login to OneBuild API
|
|
437
|
-
* @param {object} creds - object with two properties:
|
|
438
|
-
* - username,
|
|
439
|
-
* - password,
|
|
440
|
-
* @return {Promise}
|
|
441
|
-
*/
|
|
442
|
-
login = (creds) => {
|
|
443
|
-
|
|
444
|
-
if (!this.isOnline) {
|
|
445
|
-
this.throwError('Offline');
|
|
446
|
-
return;
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
const data = {
|
|
450
|
-
url: 'apiLogin',
|
|
451
|
-
data: qs.stringify(creds),
|
|
452
|
-
method: 'POST',
|
|
453
|
-
baseURL: this.api.baseURL,
|
|
454
|
-
};
|
|
455
|
-
|
|
456
|
-
if (this.debugMode) {
|
|
457
|
-
console.log('login', data);
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
return this.axios(data)
|
|
461
|
-
.then((result) => {
|
|
462
|
-
if (this.debugMode) {
|
|
463
|
-
console.log('login response', result);
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
const response = result.data;
|
|
467
|
-
if (!response.success) {
|
|
468
|
-
this.throwError(response.data); // TODO: Fix back-end, so OneBuild submits the error message on response.message, not response.data
|
|
469
|
-
return false;
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
const userData = response.data;
|
|
473
|
-
return userData;
|
|
474
|
-
});
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
/**
|
|
478
|
-
* Logout from OneBuild API
|
|
479
|
-
* @return {Promise}
|
|
480
|
-
*/
|
|
481
|
-
logout = () => {
|
|
482
|
-
|
|
483
|
-
if (!this.isOnline) {
|
|
484
|
-
this.throwError('Offline');
|
|
485
|
-
return;
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
if (this.debugMode) {
|
|
489
|
-
console.log('logout');
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
const headers = _.merge({
|
|
493
|
-
'Content-Type': 'application/json',
|
|
494
|
-
Accept: 'application/json',
|
|
495
|
-
}, this.headers);
|
|
496
|
-
|
|
497
|
-
return this.axios({
|
|
498
|
-
url: 'Users/apiLogout',
|
|
499
|
-
method: 'POST',
|
|
500
|
-
baseURL: this.api.baseURL,
|
|
501
|
-
headers,
|
|
502
|
-
timeout: this.timeout,
|
|
503
|
-
})
|
|
504
|
-
.then((result) => {
|
|
505
|
-
if (this.debugMode) {
|
|
506
|
-
console.log('logout response', result);
|
|
507
|
-
}
|
|
508
|
-
const response = result.data;
|
|
509
|
-
if (!response.success) {
|
|
510
|
-
this.throwError(response.data);
|
|
511
|
-
return;
|
|
512
|
-
}
|
|
513
|
-
return true;
|
|
514
|
-
});
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
forgotPassword = (email = null, username = null) => {
|
|
518
|
-
|
|
519
|
-
if (!this.isOnline) {
|
|
520
|
-
this.throwError('Offline');
|
|
521
|
-
return;
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
const data = {
|
|
525
|
-
url: 'forgotPassword',
|
|
526
|
-
data: qs.stringify({
|
|
527
|
-
email,
|
|
528
|
-
username,
|
|
529
|
-
}),
|
|
530
|
-
method: 'POST',
|
|
531
|
-
baseURL: this.api.baseURL,
|
|
532
|
-
};
|
|
533
|
-
|
|
534
|
-
if (this.debugMode) {
|
|
535
|
-
console.log('forgotPassword', data);
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
return this.axios(data)
|
|
539
|
-
.then((result) => {
|
|
540
|
-
if (this.debugMode) {
|
|
541
|
-
console.log('forgotPassword response', result);
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
const response = result.data;
|
|
545
|
-
if (!response.success) {
|
|
546
|
-
this.throwError(response.data);
|
|
547
|
-
return;
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
return response;
|
|
551
|
-
});
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
// ______
|
|
556
|
-
// /_ __/_______ ___ _____
|
|
557
|
-
// / / / ___/ _ \/ _ \/ ___/
|
|
558
|
-
// / / / / / __/ __(__ )
|
|
559
|
-
// /_/ /_/ \___/\___/____/
|
|
560
|
-
|
|
561
|
-
/**
|
|
562
|
-
* Loads the root nodes of this tree.
|
|
563
|
-
*/
|
|
564
|
-
loadRootNodes = (depth) => {
|
|
565
|
-
this.ensureTree();
|
|
566
|
-
if (this.isDestroyed) {
|
|
567
|
-
this.throwError('this.setRootNode is no longer valid. Repository has been destroyed.');
|
|
568
|
-
return;
|
|
569
|
-
}
|
|
570
|
-
if (!this.isOnline) {
|
|
571
|
-
this.throwError('Offline');
|
|
572
|
-
return;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
this.emit('beforeLoad'); // TODO: canceling beforeLoad will cancel the load operation
|
|
576
|
-
this.markLoading();
|
|
577
|
-
|
|
578
|
-
const data = _.merge({ depth }, this._baseParams, this._params);
|
|
579
|
-
|
|
580
|
-
if (this.debugMode) {
|
|
581
|
-
console.log('loadRootNodes', data);
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
return this._send('POST', this.name + '/getNodes', data)
|
|
585
|
-
.then((result) => {
|
|
586
|
-
if (this.debugMode) {
|
|
587
|
-
console.log('Response for loadRootNodes', result);
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
if (this.isDestroyed) {
|
|
591
|
-
// If this repository gets destroyed before it has a chance
|
|
592
|
-
// to process the Ajax request, just ignore the response.
|
|
593
|
-
return;
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
const {
|
|
597
|
-
root,
|
|
598
|
-
success,
|
|
599
|
-
total,
|
|
600
|
-
message
|
|
601
|
-
} = this._processServerResponse(result);
|
|
602
|
-
|
|
603
|
-
if (!success) {
|
|
604
|
-
this.throwError(message);
|
|
605
|
-
return;
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
this._destroyEntities();
|
|
609
|
-
|
|
610
|
-
// Set the current entities
|
|
611
|
-
const oThis = this;
|
|
612
|
-
this.entities = _.map(root, (data) => {
|
|
613
|
-
const entity = Repository._createEntity(oThis.schema, data, this, true);
|
|
614
|
-
oThis._relayEntityEvents(entity);
|
|
615
|
-
return entity;
|
|
616
|
-
});
|
|
617
|
-
|
|
618
|
-
this.assembleTreeNodes();
|
|
619
|
-
|
|
620
|
-
// Set the total records that pass filter
|
|
621
|
-
this.total = total;
|
|
622
|
-
this._setPaginationVars();
|
|
623
|
-
|
|
624
|
-
this.areRootNodesLoaded = true;
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
// Don't emit events for root nodes...
|
|
628
|
-
this.rehash();
|
|
629
|
-
this.emit('load', this);
|
|
630
|
-
// this.emit('changeData', this.entities);
|
|
631
|
-
|
|
632
|
-
return this.getBy((entity) => {
|
|
633
|
-
return entity.isRoot;
|
|
634
|
-
});
|
|
635
|
-
})
|
|
636
|
-
.finally(() => {
|
|
637
|
-
this.markLoading(false);
|
|
638
|
-
});
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
/**
|
|
642
|
-
* Loads (or reloads) the supplied treeNode
|
|
643
|
-
*/
|
|
644
|
-
loadNode = (treeNode, depth = 1) => {
|
|
645
|
-
this.ensureTree();
|
|
646
|
-
if (this.isDestroyed) {
|
|
647
|
-
this.throwError('this.loadNode is no longer valid. Repository has been destroyed.');
|
|
648
|
-
return;
|
|
649
|
-
}
|
|
650
|
-
if (!this.isOnline) {
|
|
651
|
-
this.throwError('Offline');
|
|
652
|
-
return;
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
// If children already exist, remove them from the repository
|
|
656
|
-
// This way, we can reload just a portion of the tree
|
|
657
|
-
if (!_.isEmpty(treeNode.children)) {
|
|
658
|
-
const children = treeNode.children;
|
|
659
|
-
treeNode.children = [];
|
|
660
|
-
|
|
661
|
-
const oThis = this;
|
|
662
|
-
_.each(children, (child) => {
|
|
663
|
-
oThis.removeEntity(child);
|
|
664
|
-
});
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
this.markLoading();
|
|
668
|
-
|
|
669
|
-
const data = _.merge({ depth, nodeId: treeNode.id, }, this._baseParams, this._params);
|
|
670
|
-
|
|
671
|
-
if (this.debugMode) {
|
|
672
|
-
console.log('loadNode', data);
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
return this._send('POST', this.name + '/getNodes', data)
|
|
676
|
-
.then((result) => {
|
|
677
|
-
if (this.debugMode) {
|
|
678
|
-
console.log('Response for loadNode', result);
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
if (this.isDestroyed) {
|
|
682
|
-
// If this repository gets destroyed before it has a chance
|
|
683
|
-
// to process the Ajax request, just ignore the response.
|
|
684
|
-
return;
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
const {
|
|
688
|
-
root,
|
|
689
|
-
success,
|
|
690
|
-
total,
|
|
691
|
-
message
|
|
692
|
-
} = this._processServerResponse(result);
|
|
693
|
-
|
|
694
|
-
if (!success) {
|
|
695
|
-
this.throwError(message);
|
|
696
|
-
return;
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
// Set the current entities
|
|
700
|
-
const oThis = this;
|
|
701
|
-
const children = _.map(root, (data) => {
|
|
702
|
-
const entity = Repository._createEntity(oThis.schema, data, this, true);
|
|
703
|
-
oThis._relayEntityEvents(entity);
|
|
704
|
-
return entity;
|
|
705
|
-
});
|
|
706
|
-
|
|
707
|
-
this.entities = this.entities.concat(children);
|
|
708
|
-
|
|
709
|
-
this.assembleTreeNodes();
|
|
710
|
-
|
|
711
|
-
this._setPaginationVars();
|
|
712
|
-
|
|
713
|
-
this.rehash();
|
|
714
|
-
// this.emit('changeData', this.entities);
|
|
715
|
-
this.emit('load', this);
|
|
716
|
-
|
|
717
|
-
return children;
|
|
718
|
-
})
|
|
719
|
-
.finally(() => {
|
|
720
|
-
this.markLoading(false);
|
|
721
|
-
});
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
/**
|
|
725
|
-
* Loads (or reloads) the children of the supplied treeNode
|
|
726
|
-
*/
|
|
727
|
-
loadChildNodes = (treeNode, depth = 1) => {
|
|
728
|
-
this.ensureTree();
|
|
729
|
-
if (this.isDestroyed) {
|
|
730
|
-
this.throwError('this.loadChildNodes is no longer valid. Repository has been destroyed.');
|
|
731
|
-
return;
|
|
732
|
-
}
|
|
733
|
-
if (!this.isOnline) {
|
|
734
|
-
this.throwError('Offline');
|
|
735
|
-
return;
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
// If children already exist, remove them from the repository
|
|
739
|
-
// This way, we can reload just a portion of the tree
|
|
740
|
-
if (!_.isEmpty(treeNode.children)) {
|
|
741
|
-
const children = treeNode.children;
|
|
742
|
-
treeNode.children = [];
|
|
743
|
-
|
|
744
|
-
const oThis = this;
|
|
745
|
-
_.each(children, (child) => {
|
|
746
|
-
oThis.removeEntity(child);
|
|
747
|
-
});
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
this.markLoading();
|
|
751
|
-
|
|
752
|
-
const data = _.merge({ depth, parentId: treeNode.id, }, this._baseParams, this._params);
|
|
753
|
-
|
|
754
|
-
if (this.debugMode) {
|
|
755
|
-
console.log('loadChildNodes', data);
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
return this._send('POST', this.name + '/getNodes', data)
|
|
759
|
-
.then((result) => {
|
|
760
|
-
if (this.debugMode) {
|
|
761
|
-
console.log('Response for loadChildNodes', result);
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
if (this.isDestroyed) {
|
|
765
|
-
// If this repository gets destroyed before it has a chance
|
|
766
|
-
// to process the Ajax request, just ignore the response.
|
|
767
|
-
return;
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
const {
|
|
771
|
-
root,
|
|
772
|
-
success,
|
|
773
|
-
total,
|
|
774
|
-
message
|
|
775
|
-
} = this._processServerResponse(result);
|
|
776
|
-
|
|
777
|
-
if (!success) {
|
|
778
|
-
this.throwError(message);
|
|
779
|
-
return;
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
// Set the current entities
|
|
783
|
-
const oThis = this;
|
|
784
|
-
const children = _.map(root, (data) => {
|
|
785
|
-
const entity = Repository._createEntity(oThis.schema, data, this, true);
|
|
786
|
-
oThis._relayEntityEvents(entity);
|
|
787
|
-
return entity;
|
|
788
|
-
});
|
|
789
|
-
|
|
790
|
-
this.entities = this.entities.concat(children);
|
|
791
|
-
|
|
792
|
-
this.assembleTreeNodes();
|
|
793
|
-
|
|
794
|
-
this._setPaginationVars();
|
|
795
|
-
|
|
796
|
-
this.rehash();
|
|
797
|
-
// this.emit('changeData', this.entities);
|
|
798
|
-
this.emit('load', this);
|
|
799
|
-
|
|
800
|
-
return children;
|
|
801
|
-
})
|
|
802
|
-
.finally(() => {
|
|
803
|
-
this.markLoading(false);
|
|
804
|
-
});
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
/**
|
|
808
|
-
* Override the AjaxRepository to we can reload a treeNode if needed
|
|
809
|
-
*/
|
|
810
|
-
reloadEntity = (entity, callback = null) => {
|
|
811
|
-
if (!entity.isTree) {
|
|
812
|
-
return super.reloadEntity(entity, callback);
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
return this.loadNode(entity, 1);
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
/**
|
|
819
|
-
* Searches all nodes for the supplied text.
|
|
820
|
-
* This basically takes the search query and returns whatever the server sends
|
|
821
|
-
*/
|
|
822
|
-
searchNodes = (q) => {
|
|
823
|
-
this.ensureTree();
|
|
824
|
-
if (this.isDestroyed) {
|
|
825
|
-
this.throwError('this.searchNodes is no longer valid. Repository has been destroyed.');
|
|
826
|
-
return;
|
|
827
|
-
}
|
|
828
|
-
if (!this.isOnline) {
|
|
829
|
-
this.throwError('Offline');
|
|
830
|
-
return;
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
const data = _.merge({ q, }, this._baseParams, this._params);
|
|
834
|
-
|
|
835
|
-
if (this.debugMode) {
|
|
836
|
-
console.log('searchNodes', data);
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
return this._send('POST', this.name + '/searchNodes', data)
|
|
840
|
-
.then((result) => {
|
|
841
|
-
if (this.debugMode) {
|
|
842
|
-
console.log('Response for searchNodes', result);
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
if (this.isDestroyed) {
|
|
846
|
-
// If this repository gets destroyed before it has a chance
|
|
847
|
-
// to process the Ajax request, just ignore the response.
|
|
848
|
-
return;
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
const {
|
|
852
|
-
root,
|
|
853
|
-
success,
|
|
854
|
-
total,
|
|
855
|
-
message
|
|
856
|
-
} = this._processServerResponse(result);
|
|
857
|
-
|
|
858
|
-
if (!success) {
|
|
859
|
-
this.throwError(message);
|
|
860
|
-
return;
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
return root;
|
|
864
|
-
})
|
|
865
|
-
.finally(() => {
|
|
866
|
-
this.markLoading(false);
|
|
867
|
-
});
|
|
868
|
-
}
|
|
869
|
-
|
|
870
|
-
/**
|
|
871
|
-
* Alias for loadChildren
|
|
872
|
-
*/
|
|
873
|
-
reloadChildren = (treeNode, depth) => {
|
|
874
|
-
return this.loadChildren(treeNode, depth);
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
/**
|
|
878
|
-
* Moves the supplied treeNode to a new position on the tree
|
|
879
|
-
* @returns id of common ancestor node
|
|
880
|
-
*/
|
|
881
|
-
moveTreeNode = (treeNode, newParentId) => {
|
|
882
|
-
// this.ensureTree();
|
|
883
|
-
// if (this.isDestroyed) {
|
|
884
|
-
// this.throwError('this.moveTreeNode is no longer valid. Repository has been destroyed.');
|
|
885
|
-
// return;
|
|
886
|
-
// }
|
|
887
|
-
// if (!this.isOnline) {
|
|
888
|
-
// this.throwError('Offline');
|
|
889
|
-
// return;
|
|
890
|
-
// }
|
|
891
|
-
|
|
892
|
-
// const oldParentId = treeNode.parent?.id;
|
|
893
|
-
|
|
894
|
-
// const data = _.merge({ nodeId: treeNode.id, parentId: newParentId, }, this._baseParams, this._params);
|
|
895
|
-
|
|
896
|
-
// if (this.debugMode) {
|
|
897
|
-
// console.log('moveTreeNode', data);
|
|
898
|
-
// }
|
|
899
|
-
|
|
900
|
-
// return this._send('POST', this.name + '/moveNode', data)
|
|
901
|
-
// .then((result) => {
|
|
902
|
-
// if (this.debugMode) {
|
|
903
|
-
// console.log('Response for searchNodes', result);
|
|
904
|
-
// }
|
|
905
|
-
|
|
906
|
-
// if (this.isDestroyed) {
|
|
907
|
-
// // If this repository gets destroyed before it has a chance
|
|
908
|
-
// // to process the Ajax request, just ignore the response.
|
|
909
|
-
// return;
|
|
910
|
-
// }
|
|
911
|
-
|
|
912
|
-
// const {
|
|
913
|
-
// root: {
|
|
914
|
-
// commonAncestorId,
|
|
915
|
-
// oldParent,
|
|
916
|
-
// newParent,
|
|
917
|
-
// node,
|
|
918
|
-
// },
|
|
919
|
-
// success,
|
|
920
|
-
// total,
|
|
921
|
-
// message
|
|
922
|
-
// } = this._processServerResponse(result);
|
|
923
|
-
|
|
924
|
-
// if (!success) {
|
|
925
|
-
// this.throwError(message);
|
|
926
|
-
// return;
|
|
927
|
-
// }
|
|
928
|
-
|
|
929
|
-
// // move it from oldParent.children to newParent.children
|
|
930
|
-
// const
|
|
931
|
-
// oldParentRecord = this.getById(oldParentId),
|
|
932
|
-
// newParentRecord = this.getById(newParentId);
|
|
933
|
-
|
|
934
|
-
// oldParentRecord?.loadOriginalData(oldParent);
|
|
935
|
-
// newParentRecord.loadOriginalData(newParent);
|
|
936
|
-
// treeNode.loadOriginalData(node);
|
|
937
|
-
|
|
938
|
-
// this.assembleTreeNodes();
|
|
939
|
-
|
|
940
|
-
// return commonAncestorId;
|
|
941
|
-
// })
|
|
942
|
-
// .finally(() => {
|
|
943
|
-
// this.markLoading(false);
|
|
944
|
-
// });
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
}
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
OneBuildRepository.className = 'OneBuild2';
|
|
951
|
-
OneBuildRepository.type = 'onebuild2';
|
|
952
|
-
|
|
953
|
-
export default OneBuild2Repository;
|