@arrai-innovations/reactive-helpers 11.0.0 → 11.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/README.md +3 -3
- package/package.json +1 -1
- package/tests/unit/use/listFilter.spec.js +146 -4
- package/tests/unit/use/listInstance.spec.js +14 -1
- package/tests/unit/use/listSort.spec.js +17 -0
- package/tests/unit/utils/assignReactiveObject.spec.js +43 -0
- package/use/listFilter.js +40 -20
- package/use/listInstance.js +26 -3
- package/use/listKeys.js +9 -4
- package/use/listSearch.js +4 -5
- package/use/listSort.js +16 -7
- package/use/watchesRunning.js +1 -1
- package/utils/assignReactiveObject.js +1 -1
package/README.md
CHANGED
|
@@ -523,7 +523,7 @@ const managedList = useList({
|
|
|
523
523
|
},
|
|
524
524
|
});
|
|
525
525
|
// the state expected of each are all available on the same state.
|
|
526
|
-
console.log(managedList.state.
|
|
526
|
+
console.log(managedList.state.objects);
|
|
527
527
|
// managed instances can also be accessed directly.
|
|
528
528
|
console.log(managedList.managed);
|
|
529
529
|
/*
|
|
@@ -685,7 +685,7 @@ const managedObject = useObject({
|
|
|
685
685
|
},
|
|
686
686
|
});
|
|
687
687
|
// the state expected of each are all available on the same state.
|
|
688
|
-
console.log(managedObject.state.
|
|
688
|
+
console.log(managedObject.state.objects);
|
|
689
689
|
// managed instances can also be accessed directly.
|
|
690
690
|
console.log(managedObject.managed);
|
|
691
691
|
/*
|
|
@@ -727,7 +727,7 @@ const source2 = reactive({ b: 5 });
|
|
|
727
727
|
|
|
728
728
|
const a = toRef(target, "a");
|
|
729
729
|
const b = toRef(target, "b");
|
|
730
|
-
const mySum = computed(() => (a
|
|
730
|
+
const mySum = computed(() => (unref(a) || 0) + (unref(b) || 0));
|
|
731
731
|
|
|
732
732
|
console.log(mySum.value); // 1
|
|
733
733
|
assignReactiveObject(target, source);
|
package/package.json
CHANGED
|
@@ -154,10 +154,8 @@ describe("use/listFilter", () => {
|
|
|
154
154
|
obj: filter.state,
|
|
155
155
|
prop: "running",
|
|
156
156
|
});
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
expect(unrefOrder).toEqual(expectedOrder);
|
|
160
|
-
expect(unrefObjectsInOrder).toEqual(orderedObjects);
|
|
157
|
+
expect(filter.state.order).toEqual(expectedOrder);
|
|
158
|
+
expect(filter.state.objectsInOrder).toEqual(orderedObjects);
|
|
161
159
|
});
|
|
162
160
|
});
|
|
163
161
|
describe("useListFilters accepts args and parentInstances", () => {
|
|
@@ -356,4 +354,148 @@ describe("use/listFilter", () => {
|
|
|
356
354
|
});
|
|
357
355
|
});
|
|
358
356
|
});
|
|
357
|
+
it("you can use nested useListFilters", async () => {
|
|
358
|
+
const list = useListInstance({ props: {} });
|
|
359
|
+
|
|
360
|
+
function filter1AllowedFilter(object) {
|
|
361
|
+
return object.has_things && object.has_stuff;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function filter2AllowedFilter(object) {
|
|
365
|
+
return object.has_things && object.has_other_stuff;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const filter1 = useListFilter({
|
|
369
|
+
parentState: list.state,
|
|
370
|
+
allowedFilter: filter1AllowedFilter,
|
|
371
|
+
});
|
|
372
|
+
const filter2 = useListFilter({
|
|
373
|
+
parentState: filter1.state,
|
|
374
|
+
allowedFilter: filter2AllowedFilter,
|
|
375
|
+
});
|
|
376
|
+
await doAwaitNot({
|
|
377
|
+
obj: filter1.state,
|
|
378
|
+
prop: "running",
|
|
379
|
+
});
|
|
380
|
+
await doAwaitNot({
|
|
381
|
+
obj: filter2.state,
|
|
382
|
+
prop: "running",
|
|
383
|
+
});
|
|
384
|
+
expect(filter1.state.objects).toEqual({});
|
|
385
|
+
expect(filter1.state.order).toEqual([]);
|
|
386
|
+
expect(filter2.state.objects).toEqual({});
|
|
387
|
+
expect(filter2.state.order).toEqual([]);
|
|
388
|
+
list.addListObject({ id: 1, name: "one", has_things: true, has_stuff: true, has_other_stuff: true });
|
|
389
|
+
await doAwaitNot({
|
|
390
|
+
obj: filter1.state,
|
|
391
|
+
prop: "running",
|
|
392
|
+
});
|
|
393
|
+
await doAwaitNot({
|
|
394
|
+
obj: filter2.state,
|
|
395
|
+
prop: "running",
|
|
396
|
+
});
|
|
397
|
+
expect(filter1.state.objects).toEqual({
|
|
398
|
+
1: { id: 1, name: "one", has_things: true, has_stuff: true, has_other_stuff: true },
|
|
399
|
+
});
|
|
400
|
+
expect(filter1.state.order).toEqual(["1"]);
|
|
401
|
+
expect(filter2.state.objects).toEqual({
|
|
402
|
+
1: { id: 1, name: "one", has_things: true, has_stuff: true, has_other_stuff: true },
|
|
403
|
+
});
|
|
404
|
+
expect(filter2.state.order).toEqual(["1"]);
|
|
405
|
+
list.addListObject({ id: 2, name: "two", has_things: true, has_stuff: true, has_other_stuff: false });
|
|
406
|
+
await doAwaitNot({
|
|
407
|
+
obj: filter1.state,
|
|
408
|
+
prop: "running",
|
|
409
|
+
});
|
|
410
|
+
await doAwaitNot({
|
|
411
|
+
obj: filter2.state,
|
|
412
|
+
prop: "running",
|
|
413
|
+
});
|
|
414
|
+
expect(filter1.state.objects).toEqual({
|
|
415
|
+
1: { id: 1, name: "one", has_things: true, has_stuff: true, has_other_stuff: true },
|
|
416
|
+
2: { id: 2, name: "two", has_things: true, has_stuff: true, has_other_stuff: false },
|
|
417
|
+
});
|
|
418
|
+
expect(filter1.state.order).toEqual(["1", "2"]);
|
|
419
|
+
expect(filter2.state.objects).toEqual({
|
|
420
|
+
1: { id: 1, name: "one", has_things: true, has_stuff: true, has_other_stuff: true },
|
|
421
|
+
});
|
|
422
|
+
expect(filter2.state.order).toEqual(["1"]);
|
|
423
|
+
list.addListObject({ id: 3, name: "three", has_things: true, has_stuff: false, has_other_stuff: true });
|
|
424
|
+
await doAwaitNot({
|
|
425
|
+
obj: filter1.state,
|
|
426
|
+
prop: "running",
|
|
427
|
+
});
|
|
428
|
+
await doAwaitNot({
|
|
429
|
+
obj: filter2.state,
|
|
430
|
+
prop: "running",
|
|
431
|
+
});
|
|
432
|
+
expect(filter1.state.objects).toEqual({
|
|
433
|
+
1: { id: 1, name: "one", has_things: true, has_stuff: true, has_other_stuff: true },
|
|
434
|
+
2: { id: 2, name: "two", has_things: true, has_stuff: true, has_other_stuff: false },
|
|
435
|
+
});
|
|
436
|
+
expect(filter1.state.order).toEqual(["1", "2"]);
|
|
437
|
+
expect(filter2.state.objects).toEqual({
|
|
438
|
+
1: { id: 1, name: "one", has_things: true, has_stuff: true, has_other_stuff: true },
|
|
439
|
+
});
|
|
440
|
+
expect(filter2.state.order).toEqual(["1"]);
|
|
441
|
+
list.addListObject({ id: 4, name: "four", has_things: true, has_stuff: false, has_other_stuff: false });
|
|
442
|
+
await doAwaitNot({
|
|
443
|
+
obj: filter1.state,
|
|
444
|
+
prop: "running",
|
|
445
|
+
});
|
|
446
|
+
await doAwaitNot({
|
|
447
|
+
obj: filter2.state,
|
|
448
|
+
prop: "running",
|
|
449
|
+
});
|
|
450
|
+
expect(filter1.state.objects).toEqual({
|
|
451
|
+
1: { id: 1, name: "one", has_things: true, has_stuff: true, has_other_stuff: true },
|
|
452
|
+
2: { id: 2, name: "two", has_things: true, has_stuff: true, has_other_stuff: false },
|
|
453
|
+
});
|
|
454
|
+
expect(filter1.state.order).toEqual(["1", "2"]);
|
|
455
|
+
expect(filter2.state.objects).toEqual({
|
|
456
|
+
1: { id: 1, name: "one", has_things: true, has_stuff: true, has_other_stuff: true },
|
|
457
|
+
});
|
|
458
|
+
expect(filter2.state.order).toEqual(["1"]);
|
|
459
|
+
list.state.objects[1].has_stuff = false;
|
|
460
|
+
list.state.objects[2].has_other_stuff = true;
|
|
461
|
+
await doAwaitNot({
|
|
462
|
+
obj: filter1.state,
|
|
463
|
+
prop: "running",
|
|
464
|
+
});
|
|
465
|
+
await doAwaitNot({
|
|
466
|
+
obj: filter2.state,
|
|
467
|
+
prop: "running",
|
|
468
|
+
});
|
|
469
|
+
expect(filter1.state.objects).toEqual({
|
|
470
|
+
2: { id: 2, name: "two", has_things: true, has_stuff: true, has_other_stuff: true },
|
|
471
|
+
});
|
|
472
|
+
expect(filter1.state.order).toEqual(["2"]);
|
|
473
|
+
expect(filter2.state.objects).toEqual({
|
|
474
|
+
2: { id: 2, name: "two", has_things: true, has_stuff: true, has_other_stuff: true },
|
|
475
|
+
});
|
|
476
|
+
expect(filter2.state.order).toEqual(["2"]);
|
|
477
|
+
list.addListObject({ id: 5, name: "five", has_things: true, has_stuff: false, has_other_stuff: true });
|
|
478
|
+
list.addListObject({ id: 6, name: "six", has_things: true, has_stuff: true, has_other_stuff: false });
|
|
479
|
+
list.addListObject({ id: 7, name: "seven", has_things: false, has_stuff: true, has_other_stuff: true });
|
|
480
|
+
list.addListObject({ id: 8, name: "eight", has_things: true, has_stuff: true, has_other_stuff: true });
|
|
481
|
+
await doAwaitNot({
|
|
482
|
+
obj: filter1.state,
|
|
483
|
+
prop: "running",
|
|
484
|
+
});
|
|
485
|
+
await doAwaitNot({
|
|
486
|
+
obj: filter2.state,
|
|
487
|
+
prop: "running",
|
|
488
|
+
});
|
|
489
|
+
expect(filter1.state.objects).toEqual({
|
|
490
|
+
2: { id: 2, name: "two", has_things: true, has_stuff: true, has_other_stuff: true },
|
|
491
|
+
6: { id: 6, name: "six", has_things: true, has_stuff: true, has_other_stuff: false },
|
|
492
|
+
8: { id: 8, name: "eight", has_things: true, has_stuff: true, has_other_stuff: true },
|
|
493
|
+
});
|
|
494
|
+
expect(filter1.state.order).toEqual(["2", "6", "8"]);
|
|
495
|
+
expect(filter2.state.objects).toEqual({
|
|
496
|
+
2: { id: 2, name: "two", has_things: true, has_stuff: true, has_other_stuff: true },
|
|
497
|
+
8: { id: 8, name: "eight", has_things: true, has_stuff: true, has_other_stuff: true },
|
|
498
|
+
});
|
|
499
|
+
expect(filter2.state.order).toEqual(["2", "8"]);
|
|
500
|
+
});
|
|
359
501
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { doAwaitNot } from "../../../utils/index.js";
|
|
1
2
|
import { expectErrorToBeNull } from "../expectHelpers.js";
|
|
2
3
|
import flushPromises from "flush-promises";
|
|
3
4
|
import keyBy from "lodash-es/keyBy.js";
|
|
@@ -308,6 +309,7 @@ describe("use/listInstance.spec.js", function () {
|
|
|
308
309
|
expect(listInstance.state.errored).toBe(false);
|
|
309
310
|
expect(listInstance.state.loading).toBe(false);
|
|
310
311
|
expect({ ...listInstance.state.objects }).toEqual(crudListResolvedObjects2);
|
|
312
|
+
await nextTick();
|
|
311
313
|
await flushPromises();
|
|
312
314
|
expect(listInstance.state.order).toEqual(Object.keys(crudListResolvedObjects2));
|
|
313
315
|
expect(listInstance.state.objectsInOrder).toEqual(Object.values(crudListResolvedObjects2));
|
|
@@ -429,7 +431,7 @@ describe("use/listInstance.spec.js", function () {
|
|
|
429
431
|
expect(fakeId).toBeTruthy();
|
|
430
432
|
});
|
|
431
433
|
});
|
|
432
|
-
it("computes objectsInOrder and maintains state", () => {
|
|
434
|
+
it("computes objectsInOrder and maintains state", async () => {
|
|
433
435
|
const crudListResolvedPage3 = [
|
|
434
436
|
{
|
|
435
437
|
id: 3,
|
|
@@ -447,6 +449,7 @@ describe("use/listInstance.spec.js", function () {
|
|
|
447
449
|
name: "zxcv",
|
|
448
450
|
},
|
|
449
451
|
];
|
|
452
|
+
const crudListResolvedObjects3 = keyBy(crudListResolvedPage3, "id");
|
|
450
453
|
const addObject = {
|
|
451
454
|
id: 4,
|
|
452
455
|
__str__: "yuio",
|
|
@@ -467,12 +470,22 @@ describe("use/listInstance.spec.js", function () {
|
|
|
467
470
|
|
|
468
471
|
passedPageCallback(crudListResolvedPage3);
|
|
469
472
|
crudListResolve();
|
|
473
|
+
await doAwaitNot({
|
|
474
|
+
obj: listInstance.state,
|
|
475
|
+
prop: "loading",
|
|
476
|
+
});
|
|
477
|
+
expect(listInstance.state.objects).toEqual(crudListResolvedObjects3);
|
|
478
|
+
expect(listInstance.state.order).toEqual(crudListResolvedPage3.map((e) => e.id.toString()));
|
|
470
479
|
expect(listInstance.state.objectsInOrder).toEqual(crudListResolvedPage3);
|
|
471
480
|
listInstance.addListObject(addObject);
|
|
472
481
|
crudListResolvedPage3.push(addObject);
|
|
482
|
+
await nextTick();
|
|
483
|
+
expect(listInstance.state.order).toEqual(crudListResolvedPage3.map((e) => e.id.toString()));
|
|
473
484
|
expect(listInstance.state.objectsInOrder).toEqual(crudListResolvedPage3);
|
|
474
485
|
listInstance.deleteListObject(8);
|
|
475
486
|
crudListResolvedPage3.splice(1, 1);
|
|
487
|
+
await nextTick();
|
|
488
|
+
expect(listInstance.state.order).toEqual(crudListResolvedPage3.map((e) => e.id.toString()));
|
|
476
489
|
expect(listInstance.state.objectsInOrder).toEqual(crudListResolvedPage3);
|
|
477
490
|
});
|
|
478
491
|
});
|
|
@@ -107,13 +107,16 @@ describe("use/useListSort", () => {
|
|
|
107
107
|
const listSort = useListSort({ parentState: listInstance.state, orderByRules });
|
|
108
108
|
// sorts immediately
|
|
109
109
|
expect(listSort.state.order).toEqual(testOrder1);
|
|
110
|
+
expect(listSort.state.objectsInOrder).toEqual(testOrder1.map((id) => listInstance.state.objects[id]));
|
|
110
111
|
await waitForListSort(listSort);
|
|
111
112
|
listInstance.addListObject(addObject);
|
|
112
113
|
await waitForListSort(listSort);
|
|
113
114
|
expect(listSort.state.order).toEqual(testOrder2);
|
|
115
|
+
expect(listSort.state.objectsInOrder).toEqual(testOrder2.map((id) => listInstance.state.objects[id]));
|
|
114
116
|
listInstance.deleteListObject(12);
|
|
115
117
|
await waitForListSort(listSort);
|
|
116
118
|
expect(listSort.state.order).toEqual(testOrder3);
|
|
119
|
+
expect(listSort.state.objectsInOrder).toEqual(testOrder3.map((id) => listInstance.state.objects[id]));
|
|
117
120
|
});
|
|
118
121
|
});
|
|
119
122
|
describe("sortWatch sifts various criteria", () => {
|
|
@@ -132,18 +135,22 @@ describe("use/useListSort", () => {
|
|
|
132
135
|
listSort.state.orderByRules.pop();
|
|
133
136
|
listSort.state.orderByRules.push({ key: "lexical_name", desc: false, localeCompare: true });
|
|
134
137
|
expect(listSort.state.order).toEqual(testOrder1);
|
|
138
|
+
expect(listSort.state.objectsInOrder).toEqual(testOrder1.map((id) => listInstance.state.objects[id]));
|
|
135
139
|
await waitForListSort(listSort);
|
|
136
140
|
expect(listSort.state.order).toEqual(testOrder2);
|
|
137
141
|
listSort.state.orderByRules.pop();
|
|
138
142
|
listSort.state.orderByRules.push({ key: "organization", desc: true, localeCompare: true });
|
|
139
143
|
await waitForListSort(listSort);
|
|
140
144
|
expect(listSort.state.order).toEqual(testOrder3);
|
|
145
|
+
expect(listSort.state.objectsInOrder).toEqual(testOrder3.map((id) => listInstance.state.objects[id]));
|
|
141
146
|
listSort.state.orderByRules.pop();
|
|
142
147
|
await waitForListSort(listSort);
|
|
143
148
|
expect(listSort.state.order).toEqual(testOrder4);
|
|
149
|
+
expect(listSort.state.objectsInOrder).toEqual(testOrder4.map((id) => listInstance.state.objects[id]));
|
|
144
150
|
listSort.state.orderByRules.push({ key: "organization", desc: false, localeCompare: false });
|
|
145
151
|
await waitForListSort(listSort);
|
|
146
152
|
expect(listSort.state.order).toEqual(testOrder2);
|
|
153
|
+
expect(listSort.state.objectsInOrder).toEqual(testOrder2.map((id) => listInstance.state.objects[id]));
|
|
147
154
|
});
|
|
148
155
|
});
|
|
149
156
|
it("useListSorts & useListInstances", async function () {
|
|
@@ -269,13 +276,16 @@ describe("use/useListSort", () => {
|
|
|
269
276
|
}
|
|
270
277
|
await waitForListSort(listSort);
|
|
271
278
|
expect(listSort.state.order).toEqual(["4", "3", "2", "1"]);
|
|
279
|
+
expect(listSort.state.objectsInOrder.map((obj) => obj.id)).toEqual([4, 3, 2, 1]);
|
|
272
280
|
orderByRules[0].key = "relatedItemName.name";
|
|
273
281
|
await waitForListSort(listSort);
|
|
274
282
|
expect(listSort.state.order).toEqual(["1", "2", "3", "4"]);
|
|
283
|
+
expect(listSort.state.objectsInOrder.map((obj) => obj.id)).toEqual([1, 2, 3, 4]);
|
|
275
284
|
orderByRules[0].key = "relatedItemName.sameValue";
|
|
276
285
|
orderByRules[1] = { key: "calculatedItem.calculatedItemName", desc: false, localeCompare: false };
|
|
277
286
|
await waitForListSort(listSort);
|
|
278
287
|
expect(listSort.state.order).toEqual(["4", "3", "2", "1"]);
|
|
288
|
+
expect(listSort.state.objectsInOrder.map((obj) => obj.id)).toEqual([4, 3, 2, 1]);
|
|
279
289
|
});
|
|
280
290
|
describe("useListSort/sortThrottleWait", () => {
|
|
281
291
|
it("respects throttle time prior to triggering", async () => {
|
|
@@ -301,25 +311,32 @@ describe("use/useListSort", () => {
|
|
|
301
311
|
|
|
302
312
|
const listSort = useListSort({ parentState: listInstance.state, orderByRules, sortThrottleWait });
|
|
303
313
|
expect(listSort.state.order).toEqual(testOrder1);
|
|
314
|
+
expect(listSort.state.objectsInOrder).toEqual(testOrder1.map((id) => listInstance.state.objects[id]));
|
|
304
315
|
|
|
305
316
|
// wait for the original throttle to finish
|
|
306
317
|
await doAwaitTimeout(250);
|
|
307
318
|
|
|
308
319
|
expect(listSort.state.order).toEqual(testOrder2);
|
|
320
|
+
expect(listSort.state.objectsInOrder).toEqual(testOrder2.map((id) => listInstance.state.objects[id]));
|
|
309
321
|
listInstance.addListObject(addObject);
|
|
310
322
|
expect(listSort.state.order).toEqual(testOrder2);
|
|
323
|
+
expect(listSort.state.objectsInOrder).toEqual(testOrder2.map((id) => listInstance.state.objects[id]));
|
|
311
324
|
// trigger the leading edge of the throttle
|
|
312
325
|
await doAwaitTimeout(10);
|
|
313
326
|
expect(listSort.state.order).toEqual(testOrder3);
|
|
327
|
+
expect(listSort.state.objectsInOrder).toEqual(testOrder3.map((id) => listInstance.state.objects[id]));
|
|
314
328
|
// trigger again before the 200ms throttle
|
|
315
329
|
listInstance.deleteListObject(12);
|
|
316
330
|
expect(listSort.state.order).toEqual(testOrder3);
|
|
331
|
+
expect(listSort.state.objectsInOrder).toEqual(testOrder3.map((id) => listInstance.state.objects[id]));
|
|
317
332
|
// this should trigger before the 200ms throttle
|
|
318
333
|
await doAwaitTimeout(100);
|
|
319
334
|
expect(listSort.state.order).toEqual(testOrder3);
|
|
335
|
+
expect(listSort.state.objectsInOrder).toEqual(testOrder3.map((id) => listInstance.state.objects[id]));
|
|
320
336
|
// this should trigger after the 200ms throttle
|
|
321
337
|
await doAwaitTimeout(200);
|
|
322
338
|
expect(listSort.state.order).toEqual(testOrder4);
|
|
339
|
+
expect(listSort.state.objectsInOrder).toEqual(testOrder4.map((id) => listInstance.state.objects[id]));
|
|
323
340
|
});
|
|
324
341
|
});
|
|
325
342
|
});
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
AssignReactiveObjectError,
|
|
5
5
|
} from "../../../utils/assignReactiveObject.js";
|
|
6
6
|
import { computed, EffectScope, effectScope, reactive, toRef, unref } from "vue";
|
|
7
|
+
import { deepUnref } from "vue-deepunref";
|
|
7
8
|
|
|
8
9
|
describe("utils/assignReactiveObject", function () {
|
|
9
10
|
describe("assignReactiveObject", function () {
|
|
@@ -183,4 +184,46 @@ describe("utils/assignReactiveObject", function () {
|
|
|
183
184
|
});
|
|
184
185
|
es.stop();
|
|
185
186
|
});
|
|
187
|
+
describe("should propagate changes when used to chain multiple levels of reactivity", function () {
|
|
188
|
+
it("array", function () {
|
|
189
|
+
// assign reactive object will make lists of refs for each layer, causing refs to refs to refs
|
|
190
|
+
// this isn't great but consumers should use other methods to avoid this
|
|
191
|
+
const target = reactive({
|
|
192
|
+
a: [1, 2, 3],
|
|
193
|
+
});
|
|
194
|
+
const source = reactive({
|
|
195
|
+
a: [4, 5, 6],
|
|
196
|
+
});
|
|
197
|
+
const source2 = reactive({
|
|
198
|
+
a: [7, 8, 9],
|
|
199
|
+
});
|
|
200
|
+
expect(source.a).toEqual([4, 5, 6]);
|
|
201
|
+
assignReactiveObject(target.a, source.a);
|
|
202
|
+
expect(source.a).toEqual([4, 5, 6]);
|
|
203
|
+
expect(deepUnref(target.a)).toEqual([4, 5, 6]);
|
|
204
|
+
assignReactiveObject(source.a, source2.a);
|
|
205
|
+
expect(source2.a).toEqual([7, 8, 9]);
|
|
206
|
+
expect(deepUnref(source.a)).toEqual([7, 8, 9]);
|
|
207
|
+
expect(deepUnref(deepUnref(target.a))).toEqual([7, 8, 9]);
|
|
208
|
+
});
|
|
209
|
+
it("object", function () {
|
|
210
|
+
const target = reactive({
|
|
211
|
+
a: { b: 1, c: 2, d: 3 },
|
|
212
|
+
});
|
|
213
|
+
const source = reactive({
|
|
214
|
+
a: { b: 4, c: 5, d: 6 },
|
|
215
|
+
});
|
|
216
|
+
const source2 = reactive({
|
|
217
|
+
a: { b: 7, c: 8, d: 9 },
|
|
218
|
+
});
|
|
219
|
+
expect(source.a).toEqual({ b: 4, c: 5, d: 6 });
|
|
220
|
+
assignReactiveObject(target.a, source.a);
|
|
221
|
+
expect(target.a).toEqual({ b: 4, c: 5, d: 6 });
|
|
222
|
+
expect(source.a).toEqual({ b: 4, c: 5, d: 6 });
|
|
223
|
+
assignReactiveObject(source.a, source2.a);
|
|
224
|
+
expect(source2.a).toEqual({ b: 7, c: 8, d: 9 });
|
|
225
|
+
expect(source.a).toEqual({ b: 7, c: 8, d: 9 });
|
|
226
|
+
expect(target.a).toEqual({ b: 7, c: 8, d: 9 });
|
|
227
|
+
});
|
|
228
|
+
});
|
|
186
229
|
});
|
package/use/listFilter.js
CHANGED
|
@@ -11,8 +11,6 @@ import {
|
|
|
11
11
|
} from "./listKeys.js";
|
|
12
12
|
import { effectScope, reactive, toRef, watch, unref, computed, nextTick } from "vue";
|
|
13
13
|
|
|
14
|
-
3;
|
|
15
|
-
|
|
16
14
|
const parentStateKeys = difference(
|
|
17
15
|
new Set([
|
|
18
16
|
...listInstanceStateKeys,
|
|
@@ -37,6 +35,9 @@ const inResults = (state, object, relatedObject, calculatedObject) => {
|
|
|
37
35
|
const unrefObject = unref(object);
|
|
38
36
|
const unrefRelatedObject = unref(relatedObject);
|
|
39
37
|
const unrefCalculatedObject = unref(calculatedObject);
|
|
38
|
+
if (!unrefObject) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
40
41
|
return !(
|
|
41
42
|
(state.allowedFilter && !state.allowedFilter(unrefObject, unrefRelatedObject, unrefCalculatedObject)) ||
|
|
42
43
|
(state.excludedFilter && state.excludedFilter(unrefObject, unrefRelatedObject, unrefCalculatedObject))
|
|
@@ -45,13 +46,14 @@ const inResults = (state, object, relatedObject, calculatedObject) => {
|
|
|
45
46
|
|
|
46
47
|
export function useListFilter({ parentState, allowedFilter, excludedFilter }) {
|
|
47
48
|
const state = reactive({
|
|
49
|
+
allowedFilter,
|
|
50
|
+
excludedFilter,
|
|
48
51
|
inResults: {},
|
|
49
52
|
objects: {},
|
|
50
53
|
objectsInOrder: [],
|
|
51
|
-
|
|
52
|
-
allowedFilter,
|
|
53
|
-
excludedFilter,
|
|
54
|
+
objectsInOrderRefs: [],
|
|
54
55
|
objectsWatchRunning: undefined,
|
|
56
|
+
order: [],
|
|
55
57
|
resultsWatchRunning: undefined,
|
|
56
58
|
running: undefined,
|
|
57
59
|
});
|
|
@@ -104,11 +106,7 @@ export function useListFilter({ parentState, allowedFilter, excludedFilter }) {
|
|
|
104
106
|
};
|
|
105
107
|
|
|
106
108
|
const resultsWatch = async () => {
|
|
107
|
-
if (parentState.running) {
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
109
|
state.resultsWatchRunning = true;
|
|
111
|
-
await nextTick();
|
|
112
110
|
if (state.allowedFilter || state.excludedFilter) {
|
|
113
111
|
assignReactiveObject(
|
|
114
112
|
state.objects,
|
|
@@ -119,21 +117,37 @@ export function useListFilter({ parentState, allowedFilter, excludedFilter }) {
|
|
|
119
117
|
)
|
|
120
118
|
);
|
|
121
119
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
120
|
+
await nextTick();
|
|
121
|
+
// the watches don't necessarily run in the order we expect, or at all
|
|
122
|
+
orderWatch();
|
|
123
|
+
await nextTick();
|
|
124
|
+
state.resultsWatchRunning = false;
|
|
126
125
|
};
|
|
127
126
|
|
|
128
127
|
const orderWatch = () => {
|
|
129
|
-
let desiredOrder = parentState.order.filter((id) => !!state.objects[id])
|
|
130
|
-
desiredObjectsInOrder = desiredOrder.map((id) => toRef(state.objects, id));
|
|
128
|
+
let desiredOrder = parentState.order.filter((id) => !!state.objects[id]);
|
|
131
129
|
if (!state.allowedFilter && !state.excludedFilter) {
|
|
132
130
|
desiredOrder = parentState.order;
|
|
133
|
-
desiredObjectsInOrder = parentState.objectsInOrder;
|
|
134
131
|
}
|
|
135
|
-
|
|
136
|
-
|
|
132
|
+
// order is primitives, references to the parent state order doesn't make sense
|
|
133
|
+
const entries = Object.entries(desiredOrder);
|
|
134
|
+
entries.reverse();
|
|
135
|
+
if (entries.length !== state.order.length) {
|
|
136
|
+
state.order.length = entries.length;
|
|
137
|
+
state.objectsInOrderRefs.length = entries.length;
|
|
138
|
+
}
|
|
139
|
+
for (const [index, id] of entries) {
|
|
140
|
+
if (state.order[index] !== id) {
|
|
141
|
+
state.order[index] = id;
|
|
142
|
+
}
|
|
143
|
+
if (unref(toRef(state.objectsInOrderRefs, index)) !== unref(toRef(state.objects, id))) {
|
|
144
|
+
state.objectsInOrderRefs[index] = toRef(state.objects, id);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
assignReactiveObject(
|
|
148
|
+
state.objectsInOrderRefs,
|
|
149
|
+
desiredOrder.map((id) => toRef(state.objects, id))
|
|
150
|
+
);
|
|
137
151
|
};
|
|
138
152
|
|
|
139
153
|
es.run(() => {
|
|
@@ -148,11 +162,17 @@ export function useListFilter({ parentState, allowedFilter, excludedFilter }) {
|
|
|
148
162
|
watch(toRef(state, "inResults"), resultsWatch, { deep: true });
|
|
149
163
|
|
|
150
164
|
watch(toRef(parentState, "order"), orderWatch, { deep: true, immediate: true });
|
|
165
|
+
state.objectsInOrder = computed(() => state.objectsInOrderRefs.map((e) => unref(e)));
|
|
151
166
|
|
|
152
167
|
watch(
|
|
153
|
-
[
|
|
168
|
+
[
|
|
169
|
+
toRef(parentState, "objects"),
|
|
170
|
+
toRef(state, "allowedFilter"),
|
|
171
|
+
toRef(state, "excludedFilter"),
|
|
172
|
+
toRef(parentState, "running"),
|
|
173
|
+
],
|
|
154
174
|
objectsWatch,
|
|
155
|
-
{ immediate: true }
|
|
175
|
+
{ immediate: true, deep: true }
|
|
156
176
|
);
|
|
157
177
|
});
|
|
158
178
|
return {
|
package/use/listInstance.js
CHANGED
|
@@ -2,7 +2,7 @@ import { getListCrud } from "../config/listCrud.js";
|
|
|
2
2
|
import { assignReactiveObject } from "../utils/assignReactiveObject.js";
|
|
3
3
|
import { getFakeId } from "../utils/getFakeId.js";
|
|
4
4
|
import inspect from "browser-util-inspect";
|
|
5
|
-
import {
|
|
5
|
+
import { effectScope, reactive, toRef, watch, computed, unref } from "vue";
|
|
6
6
|
|
|
7
7
|
export class ListError extends Error {
|
|
8
8
|
constructor(message, code) {
|
|
@@ -32,6 +32,7 @@ export class ListError extends Error {
|
|
|
32
32
|
* @param {Object.<string, ListInstanceOptions>} listInstanceArgs - each desired list instance options, keyed by an instance name.
|
|
33
33
|
* @returns {Object.<string, ListInstance>} - each list instance, keyed by the instance name.
|
|
34
34
|
*/
|
|
35
|
+
|
|
35
36
|
/* eslint-enable jsdoc/check-types */
|
|
36
37
|
export function useListInstances(listInstanceArgs) {
|
|
37
38
|
const instances = {};
|
|
@@ -119,6 +120,10 @@ export function useListInstance({ props, functions = {}, keepOldPages = false })
|
|
|
119
120
|
}
|
|
120
121
|
: Reflect.getOwnPropertyDescriptor(target, p); // we can't report target properties as non-existent re: proxy invariants
|
|
121
122
|
},
|
|
123
|
+
// things introspect us thing we are a map, we need to pretend to be a object
|
|
124
|
+
getPrototypeOf() {
|
|
125
|
+
return Object.prototype;
|
|
126
|
+
},
|
|
122
127
|
});
|
|
123
128
|
// ### touching the _objectsMap or _objectsProxy directly will not trigger reactivity ###
|
|
124
129
|
const state = reactive({
|
|
@@ -132,6 +137,9 @@ export function useListInstance({ props, functions = {}, keepOldPages = false })
|
|
|
132
137
|
loading: undefined,
|
|
133
138
|
errored: false,
|
|
134
139
|
error: null,
|
|
140
|
+
order: [],
|
|
141
|
+
objectsInOrder: [],
|
|
142
|
+
objectsInOrderRefs: [],
|
|
135
143
|
});
|
|
136
144
|
const es = effectScope();
|
|
137
145
|
|
|
@@ -249,8 +257,23 @@ export function useListInstance({ props, functions = {}, keepOldPages = false })
|
|
|
249
257
|
state.error = null;
|
|
250
258
|
}
|
|
251
259
|
|
|
252
|
-
|
|
253
|
-
|
|
260
|
+
es.run(() => {
|
|
261
|
+
watch(
|
|
262
|
+
toRef(state, "objects"),
|
|
263
|
+
() => {
|
|
264
|
+
assignReactiveObject(
|
|
265
|
+
state.objectsInOrderRefs,
|
|
266
|
+
Object.keys(state.objects).map((id) => toRef(state.objects, id))
|
|
267
|
+
);
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
immediate: true,
|
|
271
|
+
deep: true,
|
|
272
|
+
}
|
|
273
|
+
);
|
|
274
|
+
state.objectsInOrder = computed(() => state.objectsInOrderRefs.map((ref) => unref(ref)));
|
|
275
|
+
state.order = computed(() => Object.keys(state.objects));
|
|
276
|
+
});
|
|
254
277
|
|
|
255
278
|
const returnedObject = {
|
|
256
279
|
state,
|
package/use/listKeys.js
CHANGED
|
@@ -7,6 +7,7 @@ export const listInstanceStateKeys = [
|
|
|
7
7
|
"errored",
|
|
8
8
|
"error",
|
|
9
9
|
"objectsInOrder",
|
|
10
|
+
"objectsInOrderRefs",
|
|
10
11
|
"order",
|
|
11
12
|
// when paged
|
|
12
13
|
"totalRecords",
|
|
@@ -54,14 +55,16 @@ export const listCalculatedStateKeys = [
|
|
|
54
55
|
export const listCalculatedFunctions = [];
|
|
55
56
|
|
|
56
57
|
export const listFilterStateKeys = [
|
|
57
|
-
"objects",
|
|
58
|
-
"order",
|
|
59
|
-
"objectsInOrder",
|
|
60
58
|
"allowedFilter",
|
|
61
59
|
"excludedFilter",
|
|
62
|
-
"
|
|
60
|
+
"inResults",
|
|
61
|
+
"objects",
|
|
62
|
+
"objectsInOrder",
|
|
63
|
+
"objectsInOrderRefs",
|
|
63
64
|
"objectsWatchRunning",
|
|
65
|
+
"order",
|
|
64
66
|
"resultsWatchRunning",
|
|
67
|
+
"running",
|
|
65
68
|
];
|
|
66
69
|
export const listFilterFunctions = [];
|
|
67
70
|
|
|
@@ -70,6 +73,7 @@ export const listSearchStateKeys = [
|
|
|
70
73
|
"objects",
|
|
71
74
|
"order",
|
|
72
75
|
"objectsInOrder",
|
|
76
|
+
"objectsInOrderRefs",
|
|
73
77
|
"textSearchRules",
|
|
74
78
|
"textSearchValue",
|
|
75
79
|
"searched",
|
|
@@ -84,6 +88,7 @@ export const listSortStateKeys = [
|
|
|
84
88
|
"orderByRules",
|
|
85
89
|
"order",
|
|
86
90
|
"objectsInOrder",
|
|
91
|
+
"objectsInOrderRefs",
|
|
87
92
|
"sortCriteria",
|
|
88
93
|
"orderByDesc",
|
|
89
94
|
"sortCriteriaWatchRunning",
|
package/use/listSearch.js
CHANGED
|
@@ -81,6 +81,7 @@ export function useListSearch({ parentState, props, throttle = 500, showAllWhenE
|
|
|
81
81
|
const state = reactive({
|
|
82
82
|
objects: {},
|
|
83
83
|
objectsInOrder: [],
|
|
84
|
+
objectsInOrderRefs: [],
|
|
84
85
|
order: [],
|
|
85
86
|
textSearchRules: toRef(props, "textSearchRules"),
|
|
86
87
|
textSearchValue: toRef(props, "textSearchValue"),
|
|
@@ -270,14 +271,11 @@ export function useListSearch({ parentState, props, throttle = 500, showAllWhenE
|
|
|
270
271
|
};
|
|
271
272
|
|
|
272
273
|
const updateOrder = () => {
|
|
274
|
+
state.order = parentState.order.filter((id) => !!state.objects[id]);
|
|
273
275
|
assignReactiveObject(
|
|
274
|
-
state.
|
|
276
|
+
state.objectsInOrderRefs,
|
|
275
277
|
parentState.order.filter((id) => !!state.objects[id]).map((id) => toRef(state.objects, id))
|
|
276
278
|
);
|
|
277
|
-
assignReactiveObject(
|
|
278
|
-
state.order,
|
|
279
|
-
parentState.order.filter((id) => !!state.objects[id])
|
|
280
|
-
);
|
|
281
279
|
};
|
|
282
280
|
|
|
283
281
|
let firstIndexWasCleared = false;
|
|
@@ -309,6 +307,7 @@ export function useListSearch({ parentState, props, throttle = 500, showAllWhenE
|
|
|
309
307
|
state.running = computed(() => {
|
|
310
308
|
return loadingCombine(parentState.running, state.newSearchComputeds, textSearchIndex.state.running);
|
|
311
309
|
});
|
|
310
|
+
state.objectsInOrder = computed(() => state.objectsInOrderRefs.map((ref) => unref(ref)));
|
|
312
311
|
|
|
313
312
|
watch([() => Object.keys(parentState.objects), toRef(state.textSearchRules)], makeComputeds, {
|
|
314
313
|
immediate: true,
|
package/use/listSort.js
CHANGED
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
listSearchStateKeys,
|
|
10
10
|
} from "./listKeys.js";
|
|
11
11
|
import { useWatchesRunning } from "./watchesRunning.js";
|
|
12
|
-
import cloneDeep from "lodash-es/cloneDeep.js";
|
|
13
12
|
import get from "lodash-es/get.js";
|
|
14
13
|
import identity from "lodash-es/identity.js";
|
|
15
14
|
import isEmpty from "lodash-es/isEmpty.js";
|
|
@@ -19,6 +18,7 @@ import isUndefined from "lodash-es/isUndefined.js";
|
|
|
19
18
|
import throttle from "lodash-es/throttle.js";
|
|
20
19
|
import zip from "lodash-es/zip.js";
|
|
21
20
|
import { effectScope, reactive, toRef, unref, watch, computed } from "vue";
|
|
21
|
+
import { deepUnref } from "vue-deepunref";
|
|
22
22
|
|
|
23
23
|
const collator = new Intl.Collator(undefined, { numeric: true });
|
|
24
24
|
|
|
@@ -62,6 +62,7 @@ export function useListSort({ parentState, orderByRules, sortThrottleWait = defa
|
|
|
62
62
|
const state = reactive({
|
|
63
63
|
orderByRules,
|
|
64
64
|
order: [],
|
|
65
|
+
objectsInOrderRefs: [],
|
|
65
66
|
objectsInOrder: [],
|
|
66
67
|
sortCriteria: {},
|
|
67
68
|
orderByDesc: [],
|
|
@@ -137,8 +138,8 @@ export function useListSort({ parentState, orderByRules, sortThrottleWait = defa
|
|
|
137
138
|
removeSortCriteria(removedKey);
|
|
138
139
|
}
|
|
139
140
|
}
|
|
140
|
-
assignReactiveObject(state.order,
|
|
141
|
-
assignReactiveObject(state.objectsInOrder,
|
|
141
|
+
assignReactiveObject(state.order, deepUnref(parentState.order));
|
|
142
|
+
assignReactiveObject(state.objectsInOrder, deepUnref(parentState.objectsInOrder));
|
|
142
143
|
return;
|
|
143
144
|
}
|
|
144
145
|
const { removedKeys, addedKeys } = keyDiff(
|
|
@@ -169,8 +170,12 @@ export function useListSort({ parentState, orderByRules, sortThrottleWait = defa
|
|
|
169
170
|
function sortWatch() {
|
|
170
171
|
try {
|
|
171
172
|
if (!state.orderByRules || !state.orderByRules.length) {
|
|
172
|
-
|
|
173
|
-
assignReactiveObject(
|
|
173
|
+
state.order = [...parentState.order];
|
|
174
|
+
assignReactiveObject(
|
|
175
|
+
state.objectsInOrderRefs,
|
|
176
|
+
state.order.map((e) => toRef(parentState.objects, e))
|
|
177
|
+
);
|
|
178
|
+
3;
|
|
174
179
|
return;
|
|
175
180
|
}
|
|
176
181
|
|
|
@@ -210,8 +215,11 @@ export function useListSort({ parentState, orderByRules, sortThrottleWait = defa
|
|
|
210
215
|
}
|
|
211
216
|
return 0;
|
|
212
217
|
});
|
|
213
|
-
|
|
214
|
-
assignReactiveObject(
|
|
218
|
+
state.order = idList;
|
|
219
|
+
assignReactiveObject(
|
|
220
|
+
state.objectsInOrderRefs,
|
|
221
|
+
idList.map((e) => toRef(parentState.objects, e))
|
|
222
|
+
);
|
|
215
223
|
} finally {
|
|
216
224
|
state.sortWatchRunning = false;
|
|
217
225
|
state.outstandingEffects = false;
|
|
@@ -243,6 +251,7 @@ export function useListSort({ parentState, orderByRules, sortThrottleWait = defa
|
|
|
243
251
|
watchSentinelRefs: [toRef(state, "sortCriteriaWatchRunning"), toRef(state, "sortWatchRunning")],
|
|
244
252
|
});
|
|
245
253
|
|
|
254
|
+
state.objectsInOrder = computed(() => state.objectsInOrderRefs.map((e) => unref(e)));
|
|
246
255
|
state.sortRunning = computed(() => loadingCombine(watchesRunning.state.running, state.outstandingEffects));
|
|
247
256
|
state.running = computed(() =>
|
|
248
257
|
loadingCombine(watchesRunning.state.running, state.outstandingEffects, parentState.running)
|
package/use/watchesRunning.js
CHANGED
|
@@ -22,7 +22,7 @@ export function useWatchesRunning({ triggerRefs, watchSentinelRefs }) {
|
|
|
22
22
|
}
|
|
23
23
|
);
|
|
24
24
|
state.running = computed(() => {
|
|
25
|
-
const values = watchSentinelRefs.map((ref) => ref
|
|
25
|
+
const values = watchSentinelRefs.map((ref) => unref(ref));
|
|
26
26
|
return loadingCombine(values);
|
|
27
27
|
});
|
|
28
28
|
});
|
|
@@ -221,7 +221,7 @@ export function trimReactiveObject(target, source, exclude, removedKeys = null)
|
|
|
221
221
|
}
|
|
222
222
|
|
|
223
223
|
function checkIfReversed(target, source) {
|
|
224
|
-
if (target.length !== source.length) {
|
|
224
|
+
if (target.length !== source.length || target.length === 0) {
|
|
225
225
|
return false;
|
|
226
226
|
}
|
|
227
227
|
let t = target.length - 1,
|