@onehat/data 1.20.4 → 1.20.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onehat/data",
3
- "version": "1.20.4",
3
+ "version": "1.20.5",
4
4
  "description": "JS data modeling package with adapters for many storage mediums.",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -519,7 +519,7 @@ class AjaxRepository extends Repository {
519
519
  } = this._processServerResponse(result);
520
520
 
521
521
  if (!success) {
522
- this.throwError(message);
522
+ this.throwError(message, root);
523
523
  return;
524
524
  }
525
525
 
@@ -603,7 +603,7 @@ class AjaxRepository extends Repository {
603
603
  entity.isSaving = false;
604
604
 
605
605
  if (!success) {
606
- this.throwError(message);
606
+ this.throwError(message, root);
607
607
  return;
608
608
  }
609
609
 
@@ -661,7 +661,7 @@ class AjaxRepository extends Repository {
661
661
  });
662
662
 
663
663
  if (!success) {
664
- this.throwError(message);
664
+ this.throwError(message, root);
665
665
  return;
666
666
  }
667
667
 
@@ -714,7 +714,7 @@ class AjaxRepository extends Repository {
714
714
  entity.isSaving = false;
715
715
 
716
716
  if (!success) {
717
- this.throwError(message);
717
+ this.throwError(message, root);
718
718
  return;
719
719
  }
720
720
 
@@ -772,7 +772,7 @@ class AjaxRepository extends Repository {
772
772
  });
773
773
 
774
774
  if (!success) {
775
- this.throwError(message);
775
+ this.throwError(message, root);
776
776
  return;
777
777
  }
778
778
 
@@ -835,7 +835,7 @@ class AjaxRepository extends Repository {
835
835
  entity.isSaving = false;
836
836
 
837
837
  if (!success) {
838
- this.throwError(message);
838
+ this.throwError(message, root);
839
839
  return;
840
840
  }
841
841
 
@@ -891,7 +891,7 @@ class AjaxRepository extends Repository {
891
891
  });
892
892
 
893
893
  if (!success) {
894
- this.throwError(message);
894
+ this.throwError(message, root);
895
895
  return;
896
896
  }
897
897
 
@@ -0,0 +1,947 @@
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
+ _.each(this.filters, (filter, ix) => {
173
+ if (_.includes(nonConditionFilters, filter.name)) {
174
+ this.setParam(filter.name, filter.value);
175
+ } else {
176
+ this.setParam('conditions[' + filter.name + ']', filter.value);
177
+ }
178
+ });
179
+
180
+ if (this.isLoaded && !this.eventsPaused) {
181
+ if (this.isTree) {
182
+ return this.getRootNodes(1);
183
+ } else {
184
+ return this.reload();
185
+ }
186
+ }
187
+ }
188
+
189
+ /**
190
+ * Sets "order" param.
191
+ * OneBuild uses a single order param, rather than separate name & direction params.
192
+ * Refreshes entities.
193
+ */
194
+ _onChangeSorters = () => {
195
+ let sorterStrings = [];
196
+ _.each(this.sorters, (sorter) => {
197
+ sorterStrings.push(sorter.name + ' ' + sorter.direction);
198
+ });
199
+
200
+ if (!_.isEmpty(sorterStrings)) {
201
+ this.setBaseParam('order', sorterStrings.join(','));
202
+ }
203
+
204
+ if (!this.eventsPaused) {
205
+ if (this.isLoaded && this.isAutoLoad) {
206
+ if (this.isTree) {
207
+ return this.getRootNodes(1).then(() => {
208
+ this.emit('changeSorters');
209
+ });
210
+ } else {
211
+ return this.reload().then(() => {
212
+ this.emit('changeSorters');
213
+ });
214
+ }
215
+ } else {
216
+ this.emit('changeSorters');
217
+ }
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Helper for _send.
223
+ * Handles server's response to _send().
224
+ * This is basically just looking for errors.
225
+ * @fires error
226
+ * @private
227
+ */
228
+ _processServerResponse = (result) => {
229
+
230
+ if (result === false) { // e.g. 401 error
231
+ return {
232
+ root: null,
233
+ success: false,
234
+ total: 0,
235
+ message: null,
236
+ };
237
+ }
238
+
239
+ const
240
+ response = _.isPlainObject(result.data) ? result.data : this.reader.read(result.data),
241
+ root = response[this.rootProperty],
242
+ success = response[this.successProperty],
243
+ total = response[this.totalProperty],
244
+ message = response[this.messageProperty];
245
+
246
+ if (!success) {
247
+ this.emit('error', message, root);
248
+ }
249
+
250
+ if (message === 'You do not have authorization to access this area.') {
251
+ this.emit('logout');
252
+ }
253
+
254
+ return {
255
+ root,
256
+ success,
257
+ total,
258
+ message
259
+ };
260
+ }
261
+
262
+
263
+ /**
264
+ * Integrates with RestTrait::reorder in OneBuild API
265
+ * @param {entity|array} dragRecordOrIds - which entity or ids were being dragged
266
+ * @param {entity} dropRecord - which entity it was dropped on to
267
+ * @param {string} dropPosition - position in which it was dropped; could be 'before' or 'after'
268
+ * @return {Promise}
269
+ */
270
+ reorder = (dragRecordOrIds, dropRecord, dropPosition) => {
271
+
272
+ if (!this.isOnline) {
273
+ this.throwError('Offline');
274
+ return;
275
+ }
276
+
277
+ let ids;
278
+ if (_.isArray(dragRecordOrIds)) {
279
+ ids = dragRecordOrIds;
280
+ } else if (dragRecordOrIds?.id) {
281
+ ids = [dragRecordOrIds.id];
282
+ } else {
283
+ throw Error('dragRecordOrIds must be an entity or array of ids')
284
+ }
285
+
286
+ const data = {
287
+ url: this.name + '/reorder',
288
+ data: qs.stringify({
289
+ ids,
290
+ dropPosition,
291
+ dropRecord_id: dropRecord.id,
292
+ }),
293
+ method: 'POST',
294
+ baseURL: this.api.baseURL,
295
+ };
296
+
297
+ if (this.debugMode) {
298
+ console.log('reorder', data);
299
+ }
300
+
301
+ return this.axios(data)
302
+ .then((result) => {
303
+ if (this.debugMode) {
304
+ console.log('reorder response', result);
305
+ }
306
+
307
+ const response = result.data;
308
+ if (!response.success) {
309
+ this.throwError(response.data);
310
+ return;
311
+ }
312
+
313
+ // Reload the repository, so updated sort_order values can be retrieved
314
+ this.reload();
315
+
316
+ });
317
+ }
318
+
319
+ remoteDuplicate = async (entity) => {
320
+
321
+ this.markLoading();
322
+
323
+ const
324
+ Model = this.getSchema().name,
325
+ id = entity.id,
326
+ result = await this._send('POST', Model + '/duplicate', { id });
327
+
328
+ if (!result) {
329
+ this.markLoading(false);
330
+ this.throwError('error duplicating on server');
331
+ return;
332
+ }
333
+
334
+ const {
335
+ root,
336
+ success,
337
+ total,
338
+ message
339
+ } = this._processServerResponse(result);
340
+
341
+ if (!success) {
342
+ this.markLoading(false);
343
+ throw Error(message);
344
+ }
345
+
346
+ // Click duplicateId. The new row appears directly above the one that was duplicated
347
+ // The new duplicate is selected
348
+ // The display field should read "{old name} (duplicate)"
349
+
350
+
351
+ const duplicateEntity = await this.createStandaloneEntity(root, true, true);
352
+ if (entity.isRemotePhantomMode) {
353
+ entity.isRemotePhantom = true;
354
+ }
355
+ this._insertBefore(duplicateEntity, entity);
356
+
357
+ this.markLoading(false);
358
+ return duplicateEntity;
359
+ }
360
+
361
+ loadOneAdditionalEntity = async (id) => {
362
+ const entity = await this.getSingleEntityFromServer(id);
363
+ if (!entity) {
364
+ this.throwError('entity not found');
365
+ return;
366
+ }
367
+
368
+ this._relayEntityEvents(entity);
369
+ this.entities.push(entity);
370
+ this.total++;
371
+ this._setPaginationVars();
372
+ this.emit('changeData', this.entities);
373
+ }
374
+
375
+ getSingleEntityFromServer = async (id) => {
376
+ if (this.isDestroyed) {
377
+ this.throwError('this.getSingleEntityFromServer is no longer valid. Repository has been destroyed.');
378
+ return;
379
+ }
380
+ if (!this.api.get) {
381
+ this.throwError('No "get" api endpoint defined.');
382
+ return;
383
+ }
384
+
385
+ if (!id) {
386
+ return null;
387
+ }
388
+
389
+ this.markLoading();
390
+
391
+ const idPropertyName = this.getSchema().model.idProperty;
392
+ const params = {};
393
+ params['conditions[' + idPropertyName + ']'] = id;
394
+
395
+ const data = _.merge(params, this._baseParams);
396
+
397
+ if (this.debugMode) {
398
+ console.log('getSingleEntityFromServer', data);
399
+ }
400
+
401
+ return this._send(this.methods.get, this.api.get, data)
402
+ .then(result => {
403
+ if (this.debugMode) {
404
+ console.log('Response for getSingleEntityFromServer for ' + this.name, result);
405
+ }
406
+
407
+ if (this.isDestroyed) {
408
+ // If this repository gets destroyed before it has a chance
409
+ // to process the Ajax request, just ignore the response.
410
+ return;
411
+ }
412
+
413
+ const {
414
+ root,
415
+ success,
416
+ total,
417
+ message
418
+ } = this._processServerResponse(result);
419
+
420
+ if (!root[0]) {
421
+ return null;
422
+ }
423
+
424
+ const entity = this.createStandaloneEntity(root[0]);
425
+ entity.isRemotePhantom = false;
426
+ return entity;
427
+ })
428
+ .finally(() => {
429
+ this.markLoading(false);
430
+ });
431
+
432
+ }
433
+
434
+ /**
435
+ * Login to OneBuild API
436
+ * @param {object} creds - object with two properties:
437
+ * - username,
438
+ * - password,
439
+ * @return {Promise}
440
+ */
441
+ login = (creds) => {
442
+
443
+ if (!this.isOnline) {
444
+ this.throwError('Offline');
445
+ return;
446
+ }
447
+
448
+ const data = {
449
+ url: 'apiLogin',
450
+ data: qs.stringify(creds),
451
+ method: 'POST',
452
+ baseURL: this.api.baseURL,
453
+ };
454
+
455
+ if (this.debugMode) {
456
+ console.log('login', data);
457
+ }
458
+
459
+ return this.axios(data)
460
+ .then((result) => {
461
+ if (this.debugMode) {
462
+ console.log('login response', result);
463
+ }
464
+
465
+ const response = result.data;
466
+ if (!response.success) {
467
+ this.throwError(response.data); // TODO: Fix back-end, so OneBuild submits the error message on response.message, not response.data
468
+ return false;
469
+ }
470
+
471
+ const userData = response.data;
472
+ return userData;
473
+ });
474
+ }
475
+
476
+ /**
477
+ * Logout from OneBuild API
478
+ * @return {Promise}
479
+ */
480
+ logout = () => {
481
+
482
+ if (!this.isOnline) {
483
+ this.throwError('Offline');
484
+ return;
485
+ }
486
+
487
+ if (this.debugMode) {
488
+ console.log('logout');
489
+ }
490
+
491
+ const headers = _.merge({
492
+ 'Content-Type': 'application/json',
493
+ Accept: 'application/json',
494
+ }, this.headers);
495
+
496
+ return this.axios({
497
+ url: 'Users/apiLogout',
498
+ method: 'POST',
499
+ baseURL: this.api.baseURL,
500
+ headers,
501
+ timeout: this.timeout,
502
+ })
503
+ .then((result) => {
504
+ if (this.debugMode) {
505
+ console.log('logout response', result);
506
+ }
507
+ const response = result.data;
508
+ if (!response.success) {
509
+ this.throwError(response.data);
510
+ return;
511
+ }
512
+ return true;
513
+ });
514
+ }
515
+
516
+ forgotPassword = (email = null, username = null) => {
517
+
518
+ if (!this.isOnline) {
519
+ this.throwError('Offline');
520
+ return;
521
+ }
522
+
523
+ const data = {
524
+ url: 'forgotPassword',
525
+ data: qs.stringify({
526
+ email,
527
+ username,
528
+ }),
529
+ method: 'POST',
530
+ baseURL: this.api.baseURL,
531
+ };
532
+
533
+ if (this.debugMode) {
534
+ console.log('forgotPassword', data);
535
+ }
536
+
537
+ return this.axios(data)
538
+ .then((result) => {
539
+ if (this.debugMode) {
540
+ console.log('forgotPassword response', result);
541
+ }
542
+
543
+ const response = result.data;
544
+ if (!response.success) {
545
+ this.throwError(response.data);
546
+ return;
547
+ }
548
+
549
+ return response;
550
+ });
551
+ }
552
+
553
+
554
+ // ______
555
+ // /_ __/_______ ___ _____
556
+ // / / / ___/ _ \/ _ \/ ___/
557
+ // / / / / / __/ __(__ )
558
+ // /_/ /_/ \___/\___/____/
559
+
560
+ /**
561
+ * Loads the root nodes of this tree.
562
+ */
563
+ loadRootNodes = (depth) => {
564
+ this.ensureTree();
565
+ if (this.isDestroyed) {
566
+ this.throwError('this.setRootNode is no longer valid. Repository has been destroyed.');
567
+ return;
568
+ }
569
+ if (!this.isOnline) {
570
+ this.throwError('Offline');
571
+ return;
572
+ }
573
+
574
+ this.emit('beforeLoad'); // TODO: canceling beforeLoad will cancel the load operation
575
+ this.markLoading();
576
+
577
+ const data = _.merge({ depth }, this._baseParams, this._params);
578
+
579
+ if (this.debugMode) {
580
+ console.log('loadRootNodes', data);
581
+ }
582
+
583
+ return this._send('POST', this.name + '/getNodes', data)
584
+ .then((result) => {
585
+ if (this.debugMode) {
586
+ console.log('Response for getRootNodes', result);
587
+ }
588
+
589
+ if (this.isDestroyed) {
590
+ // If this repository gets destroyed before it has a chance
591
+ // to process the Ajax request, just ignore the response.
592
+ return;
593
+ }
594
+
595
+ const {
596
+ root,
597
+ success,
598
+ total,
599
+ message
600
+ } = this._processServerResponse(result);
601
+
602
+ if (!success) {
603
+ this.throwError(message);
604
+ return;
605
+ }
606
+
607
+ this._destroyEntities();
608
+
609
+ // Set the current entities
610
+ this.entities = _.map(root, (data) => {
611
+ const entity = Repository._createEntity(this.schema, data, this, true);
612
+ this._relayEntityEvents(entity);
613
+ return entity;
614
+ });
615
+
616
+ this.assembleTreeNodes();
617
+
618
+ // Set the total records that pass filter
619
+ this.total = total;
620
+ this._setPaginationVars();
621
+
622
+ this.areRootNodesLoaded = true;
623
+
624
+
625
+ // Don't emit events for root nodes...
626
+ this.rehash();
627
+ this.emit('load', this);
628
+ // this.emit('changeData', this.entities);
629
+
630
+ return this.getBy((entity) => {
631
+ return entity.isRoot;
632
+ });
633
+ })
634
+ .finally(() => {
635
+ this.markLoading(false);
636
+ });
637
+ }
638
+
639
+ /**
640
+ * Loads (or reloads) the supplied treeNode
641
+ */
642
+ loadNode = (treeNode, depth = 1) => {
643
+ this.ensureTree();
644
+ if (this.isDestroyed) {
645
+ this.throwError('this.loadNode is no longer valid. Repository has been destroyed.');
646
+ return;
647
+ }
648
+ if (!this.isOnline) {
649
+ this.throwError('Offline');
650
+ return;
651
+ }
652
+
653
+ // If children already exist, remove them from the repository
654
+ // This way, we can reload just a portion of the tree
655
+ if (!_.isEmpty(treeNode.children)) {
656
+ const children = treeNode.children;
657
+ treeNode.children = [];
658
+
659
+ _.each(children, (child) => {
660
+ this.removeEntity(child);
661
+ });
662
+ }
663
+
664
+ this.markLoading();
665
+
666
+ const data = _.merge({ depth, nodeId: treeNode.id, }, this._baseParams, this._params);
667
+
668
+ if (this.debugMode) {
669
+ console.log('loadNode', data);
670
+ }
671
+
672
+ return this._send('POST', this.name + '/getNodes', data)
673
+ .then((result) => {
674
+ if (this.debugMode) {
675
+ console.log('Response for loadNode', result);
676
+ }
677
+
678
+ if (this.isDestroyed) {
679
+ // If this repository gets destroyed before it has a chance
680
+ // to process the Ajax request, just ignore the response.
681
+ return;
682
+ }
683
+
684
+ const {
685
+ root,
686
+ success,
687
+ total,
688
+ message
689
+ } = this._processServerResponse(result);
690
+
691
+ if (!success) {
692
+ this.throwError(message);
693
+ return;
694
+ }
695
+
696
+ // Set the current entities
697
+ const children = _.map(root, (data) => {
698
+ const entity = Repository._createEntity(this.schema, data, this, true);
699
+ this._relayEntityEvents(entity);
700
+ return entity;
701
+ });
702
+
703
+ this.entities = this.entities.concat(children);
704
+
705
+ this.assembleTreeNodes();
706
+
707
+ this._setPaginationVars();
708
+
709
+ this.rehash();
710
+ // this.emit('changeData', this.entities);
711
+ this.emit('load', this);
712
+
713
+ return children;
714
+ })
715
+ .finally(() => {
716
+ this.markLoading(false);
717
+ });
718
+ }
719
+
720
+ /**
721
+ * Loads (or reloads) the children of the supplied treeNode
722
+ */
723
+ loadChildNodes = (treeNode, depth = 1) => {
724
+ this.ensureTree();
725
+ if (this.isDestroyed) {
726
+ this.throwError('this.loadChildNodes is no longer valid. Repository has been destroyed.');
727
+ return;
728
+ }
729
+ if (!this.isOnline) {
730
+ this.throwError('Offline');
731
+ return;
732
+ }
733
+
734
+ // If children already exist, remove them from the repository
735
+ // This way, we can reload just a portion of the tree
736
+ if (!_.isEmpty(treeNode.children)) {
737
+ const children = treeNode.children;
738
+ treeNode.children = [];
739
+
740
+ _.each(children, (child) => {
741
+ this.removeEntity(child);
742
+ });
743
+ }
744
+
745
+ this.markLoading();
746
+
747
+ const data = _.merge({ depth, parentId: treeNode.id, }, this._baseParams, this._params);
748
+
749
+ if (this.debugMode) {
750
+ console.log('loadChildNodes', data);
751
+ }
752
+
753
+ return this._send('POST', this.name + '/getNodes', data)
754
+ .then((result) => {
755
+ if (this.debugMode) {
756
+ console.log('Response for loadChildNodes', result);
757
+ }
758
+
759
+ if (this.isDestroyed) {
760
+ // If this repository gets destroyed before it has a chance
761
+ // to process the Ajax request, just ignore the response.
762
+ return;
763
+ }
764
+
765
+ const {
766
+ root,
767
+ success,
768
+ total,
769
+ message
770
+ } = this._processServerResponse(result);
771
+
772
+ if (!success) {
773
+ this.throwError(message);
774
+ return;
775
+ }
776
+
777
+ // Set the current entities
778
+ const children = _.map(root, (data) => {
779
+ const entity = Repository._createEntity(this.schema, data, this, true);
780
+ this._relayEntityEvents(entity);
781
+ return entity;
782
+ });
783
+
784
+ this.entities = this.entities.concat(children);
785
+
786
+ this.assembleTreeNodes();
787
+
788
+ this._setPaginationVars();
789
+
790
+ this.rehash();
791
+ // this.emit('changeData', this.entities);
792
+ this.emit('load', this);
793
+
794
+ return children;
795
+ })
796
+ .finally(() => {
797
+ this.markLoading(false);
798
+ });
799
+ }
800
+
801
+ /**
802
+ * Override the AjaxRepository to we can reload a treeNode if needed
803
+ */
804
+ reloadEntity = (entity, callback = null) => {
805
+ if (!entity.isTree) {
806
+ return super.reloadEntity(entity, callback);
807
+ }
808
+
809
+ return this.loadNode(entity, 1);
810
+ }
811
+
812
+ /**
813
+ * Searches all nodes for the supplied text.
814
+ * This basically takes the search query and returns whatever the server sends
815
+ */
816
+ searchNodes = (q) => {
817
+ this.ensureTree();
818
+ if (this.isDestroyed) {
819
+ this.throwError('this.searchNodes is no longer valid. Repository has been destroyed.');
820
+ return;
821
+ }
822
+ if (!this.isOnline) {
823
+ this.throwError('Offline');
824
+ return;
825
+ }
826
+
827
+ const data = _.merge({ q, }, this._baseParams, this._params);
828
+
829
+ if (this.debugMode) {
830
+ console.log('searchNodes', data);
831
+ }
832
+
833
+ return this._send('POST', this.name + '/searchNodes', data)
834
+ .then((result) => {
835
+ if (this.debugMode) {
836
+ console.log('Response for searchNodes', result);
837
+ }
838
+
839
+ if (this.isDestroyed) {
840
+ // If this repository gets destroyed before it has a chance
841
+ // to process the Ajax request, just ignore the response.
842
+ return;
843
+ }
844
+
845
+ const {
846
+ root,
847
+ success,
848
+ total,
849
+ message
850
+ } = this._processServerResponse(result);
851
+
852
+ if (!success) {
853
+ this.throwError(message);
854
+ return;
855
+ }
856
+
857
+ return root;
858
+ })
859
+ .finally(() => {
860
+ this.markLoading(false);
861
+ });
862
+ }
863
+
864
+ /**
865
+ * Alias for loadChildren
866
+ */
867
+ reloadChildren = (treeNode, depth) => {
868
+ return this.loadChildren(treeNode, depth);
869
+ }
870
+
871
+ /**
872
+ * Moves the supplied treeNode to a new position on the tree
873
+ * @returns id of common ancestor node
874
+ */
875
+ moveTreeNode = (treeNode, newParentId) => {
876
+ // this.ensureTree();
877
+ // if (this.isDestroyed) {
878
+ // this.throwError('this.moveTreeNode is no longer valid. Repository has been destroyed.');
879
+ // return;
880
+ // }
881
+ // if (!this.isOnline) {
882
+ // this.throwError('Offline');
883
+ // return;
884
+ // }
885
+
886
+ // const oldParentId = treeNode.parent?.id;
887
+
888
+ // const data = _.merge({ nodeId: treeNode.id, parentId: newParentId, }, this._baseParams, this._params);
889
+
890
+ // if (this.debugMode) {
891
+ // console.log('moveTreeNode', data);
892
+ // }
893
+
894
+ // return this._send('POST', this.name + '/moveNode', data)
895
+ // .then((result) => {
896
+ // if (this.debugMode) {
897
+ // console.log('Response for searchNodes', result);
898
+ // }
899
+
900
+ // if (this.isDestroyed) {
901
+ // // If this repository gets destroyed before it has a chance
902
+ // // to process the Ajax request, just ignore the response.
903
+ // return;
904
+ // }
905
+
906
+ // const {
907
+ // root: {
908
+ // commonAncestorId,
909
+ // oldParent,
910
+ // newParent,
911
+ // node,
912
+ // },
913
+ // success,
914
+ // total,
915
+ // message
916
+ // } = this._processServerResponse(result);
917
+
918
+ // if (!success) {
919
+ // this.throwError(message);
920
+ // return;
921
+ // }
922
+
923
+ // // move it from oldParent.children to newParent.children
924
+ // const
925
+ // oldParentRecord = this.getById(oldParentId),
926
+ // newParentRecord = this.getById(newParentId);
927
+
928
+ // oldParentRecord?.loadOriginalData(oldParent);
929
+ // newParentRecord.loadOriginalData(newParent);
930
+ // treeNode.loadOriginalData(node);
931
+
932
+ // this.assembleTreeNodes();
933
+
934
+ // return commonAncestorId;
935
+ // })
936
+ // .finally(() => {
937
+ // this.markLoading(false);
938
+ // });
939
+ }
940
+
941
+ }
942
+
943
+
944
+ OneBuildRepository.className = 'OneBuild2';
945
+ OneBuildRepository.type = 'onebuild2';
946
+
947
+ export default OneBuild2Repository;
@@ -2218,13 +2218,14 @@ export default class Repository extends EventEmitter {
2218
2218
  /**
2219
2219
  * Either generates an exception, or handles it with the repository's errorHandler
2220
2220
  * @param {string|object|bool} error - the error message
2221
+ * @param {object} data - optional data object to describe the error
2221
2222
  */
2222
- throwError(obj) {
2223
+ throwError(obj, data = null) {
2223
2224
  if (this.errorHandler) {
2224
- this.errorHandler(obj);
2225
+ this.errorHandler(obj, data);
2225
2226
  } else {
2226
- this.emit('error', obj);
2227
- throw Error(obj);
2227
+ this.emit('error', obj, data);
2228
+ throw Error(obj, data);
2228
2229
  }
2229
2230
  }
2230
2231