@asteby/metacore-runtime-react 25.1.0 → 25.1.2
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/CHANGELOG.md +25 -0
- package/dist/dynamic-table.d.ts.map +1 -1
- package/dist/dynamic-table.js +32 -11
- package/package.json +1 -1
- package/src/dynamic-table.tsx +32 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# @asteby/metacore-runtime-react
|
|
2
2
|
|
|
3
|
+
## 25.1.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 7c19de1: fix(table): stop infinite reload loop when applying a column filter
|
|
8
|
+
|
|
9
|
+
The URL-resync effect read the location's search string from a render-time
|
|
10
|
+
snapshot, which lagged one commit behind the sibling write effect's imperative
|
|
11
|
+
`history.replaceState` (that write does not re-render). Applying any column
|
|
12
|
+
filter (e.g. the "Almacén" facet on /m/stock) made the resync misread its own
|
|
13
|
+
write as an external change, reset the filters, and ping-pong `{k:[v]} <-> {}`
|
|
14
|
+
every render — spinning the infinite-scroll fetch forever. The resync now reads
|
|
15
|
+
`window.location.search` fresh inside the effect, so a self-write is recognized
|
|
16
|
+
and skipped; only genuine external rewrites (sidebar deep-links, back/forward)
|
|
17
|
+
are adopted. Also lifts the pagination reset out of the `setDynamicFilters`
|
|
18
|
+
updater.
|
|
19
|
+
|
|
20
|
+
## 25.1.1
|
|
21
|
+
|
|
22
|
+
### Patch Changes
|
|
23
|
+
|
|
24
|
+
- dea9d02: fix(table): las listas en infinite-scroll recargan al bumpear refreshTrigger
|
|
25
|
+
|
|
26
|
+
El efecto de recarga de la tabla en modo infinite-scroll omitía `refreshTrigger` de sus deps (aunque el comentario decía que lo respetaba), así que tras crear/editar/eliminar en la página la lista infinita no se recargaba ("a veces no recarga la tabla"). Se añade `refreshTrigger` a las deps para igualar el path clásico.
|
|
27
|
+
|
|
3
28
|
## 25.1.0
|
|
4
29
|
|
|
5
30
|
### Minor Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dynamic-table.d.ts","sourceRoot":"","sources":["../src/dynamic-table.tsx"],"names":[],"mappings":"AAgBA,OAAO,EAKH,KAAK,SAAS,EAajB,MAAM,uBAAuB,CAAA;AAgC9B,OAAO,KAAK,EAAsB,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAiEnF,MAAM,WAAW,iBAAiB;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IAC7C;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IAC/B,cAAc,CAAC,EAAE,GAAG,CAAA;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACpC,YAAY,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAA;IAC/B;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;CAC3B;AAED,wBAAgB,YAAY,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,aAAoB,EACpB,aAAkB,EAClB,QAAQ,EACR,UAAU,EACV,cAAc,EACd,cAAc,EACd,YAAiB,EACjB,iBAA4C,EAC5C,QAAQ,EACR,QAAQ,EACR,cAAsB,GACzB,EAAE,iBAAiB,+
|
|
1
|
+
{"version":3,"file":"dynamic-table.d.ts","sourceRoot":"","sources":["../src/dynamic-table.tsx"],"names":[],"mappings":"AAgBA,OAAO,EAKH,KAAK,SAAS,EAajB,MAAM,uBAAuB,CAAA;AAgC9B,OAAO,KAAK,EAAsB,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAiEnF,MAAM,WAAW,iBAAiB;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IAC7C;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IAC/B,cAAc,CAAC,EAAE,GAAG,CAAA;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACpC,YAAY,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAA;IAC/B;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;CAC3B;AAED,wBAAgB,YAAY,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,aAAoB,EACpB,aAAkB,EAClB,QAAQ,EACR,UAAU,EACV,cAAc,EACd,cAAc,EACd,YAAiB,EACjB,iBAA4C,EAC5C,QAAQ,EACR,QAAQ,EACR,cAAsB,GACzB,EAAE,iBAAiB,+BA6qCnB"}
|
package/dist/dynamic-table.js
CHANGED
|
@@ -314,16 +314,30 @@ export function DynamicTable({ model, endpoint, enableUrlSync = true, hiddenColu
|
|
|
314
314
|
// the table kept showing the previous filter. On every render where the
|
|
315
315
|
// location's search differs from the last URL we ourselves wrote,
|
|
316
316
|
// re-parse the `f_` params and adopt them.
|
|
317
|
-
const locationSearch = typeof window !== 'undefined' ? window.location.search : '';
|
|
318
317
|
useEffect(() => {
|
|
319
318
|
if (!enableUrlSync || !initializedFromUrl.current)
|
|
320
319
|
return;
|
|
320
|
+
// Read the URL FRESH inside the effect — NOT a value captured during
|
|
321
|
+
// render. The write effect above mutates the URL imperatively via
|
|
322
|
+
// `history.replaceState`, which does NOT trigger a re-render, so a search
|
|
323
|
+
// string snapshotted at render time lags one commit behind what we just
|
|
324
|
+
// wrote. Comparing that stale snapshot against `lastSelfSearch` (which the
|
|
325
|
+
// write effect updated in this same commit) always mismatched, so the
|
|
326
|
+
// resync "adopted" a phantom external change and reset the filters — the
|
|
327
|
+
// write effect then re-wrote them, and the two effects ping-ponged the
|
|
328
|
+
// filters `{almacen:['Test']} <-> {}` on every render, spinning the
|
|
329
|
+
// infinite-scroll fetch forever the instant any column filter was applied.
|
|
330
|
+
// Reading fresh here means that right after our own write, `now` already
|
|
331
|
+
// equals `lastSelfSearch` and we bail out early. Only a genuine external
|
|
332
|
+
// rewrite (router deep-link from a sidebar sibling, browser back/forward)
|
|
333
|
+
// makes `now` diverge, which is exactly when we want to adopt it.
|
|
334
|
+
const now = typeof window !== 'undefined' ? window.location.search : '';
|
|
321
335
|
// Semantic compare: the router's spelling of the query string we just
|
|
322
336
|
// wrote (different order/encoding) is NOT an external change.
|
|
323
|
-
if (canonicalSearch(
|
|
337
|
+
if (canonicalSearch(now) === canonicalSearch(lastSelfSearch.current ?? ''))
|
|
324
338
|
return;
|
|
325
|
-
lastSelfSearch.current =
|
|
326
|
-
const params = new URLSearchParams(
|
|
339
|
+
lastSelfSearch.current = now;
|
|
340
|
+
const params = new URLSearchParams(now);
|
|
327
341
|
const filters = {};
|
|
328
342
|
params.forEach((rawValue, key) => {
|
|
329
343
|
if (!key.startsWith('f_'))
|
|
@@ -337,14 +351,16 @@ export function DynamicTable({ model, endpoint, enableUrlSync = true, hiddenColu
|
|
|
337
351
|
else
|
|
338
352
|
filters[filterKey] = [value];
|
|
339
353
|
});
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
354
|
+
// Compare against the current filters directly (the effect re-runs every
|
|
355
|
+
// render, so this closure is always fresh) and only touch state on a real
|
|
356
|
+
// change — resetting pagination OUTSIDE any updater, never nested inside
|
|
357
|
+
// another setState's updater.
|
|
358
|
+
if (JSON.stringify(dynamicFilters) !== JSON.stringify(filters)) {
|
|
359
|
+
setDynamicFilters(filters);
|
|
343
360
|
setPagination((p) => ({ ...p, pageIndex: 0 }));
|
|
344
|
-
|
|
345
|
-
});
|
|
361
|
+
}
|
|
346
362
|
const search = params.get('search');
|
|
347
|
-
if (search !== null)
|
|
363
|
+
if (search !== null && search !== globalFilter)
|
|
348
364
|
setGlobalFilter(search);
|
|
349
365
|
});
|
|
350
366
|
const prefetchOptions = useCallback(async (endpoints) => {
|
|
@@ -669,8 +685,13 @@ export function DynamicTable({ model, endpoint, enableUrlSync = true, hiddenColu
|
|
|
669
685
|
void fetchAggregates();
|
|
670
686
|
}, 300);
|
|
671
687
|
return () => clearTimeout(timeoutId);
|
|
688
|
+
// refreshTrigger is included so an external bump (e.g. a create/edit/
|
|
689
|
+
// delete elsewhere on the page) reloads page 1 in infinite mode too —
|
|
690
|
+
// matching the classic path (fetchData carries refreshTrigger in its
|
|
691
|
+
// deps). Without it the comment above lied: infinite lists silently
|
|
692
|
+
// failed to reload after a create ("a veces no recarga la tabla").
|
|
672
693
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
673
|
-
}, [infiniteScroll, metadata, filterSignature]);
|
|
694
|
+
}, [infiniteScroll, metadata, filterSignature, refreshTrigger]);
|
|
674
695
|
const handleRefresh = useCallback(() => {
|
|
675
696
|
// Infinite mode owns its own list: refresh reloads page 1 and drops the
|
|
676
697
|
// accumulated pages (a classic fetchData would collapse it to one small
|
package/package.json
CHANGED
package/src/dynamic-table.tsx
CHANGED
|
@@ -432,14 +432,28 @@ export function DynamicTable({
|
|
|
432
432
|
// the table kept showing the previous filter. On every render where the
|
|
433
433
|
// location's search differs from the last URL we ourselves wrote,
|
|
434
434
|
// re-parse the `f_` params and adopt them.
|
|
435
|
-
const locationSearch = typeof window !== 'undefined' ? window.location.search : ''
|
|
436
435
|
useEffect(() => {
|
|
437
436
|
if (!enableUrlSync || !initializedFromUrl.current) return
|
|
437
|
+
// Read the URL FRESH inside the effect — NOT a value captured during
|
|
438
|
+
// render. The write effect above mutates the URL imperatively via
|
|
439
|
+
// `history.replaceState`, which does NOT trigger a re-render, so a search
|
|
440
|
+
// string snapshotted at render time lags one commit behind what we just
|
|
441
|
+
// wrote. Comparing that stale snapshot against `lastSelfSearch` (which the
|
|
442
|
+
// write effect updated in this same commit) always mismatched, so the
|
|
443
|
+
// resync "adopted" a phantom external change and reset the filters — the
|
|
444
|
+
// write effect then re-wrote them, and the two effects ping-ponged the
|
|
445
|
+
// filters `{almacen:['Test']} <-> {}` on every render, spinning the
|
|
446
|
+
// infinite-scroll fetch forever the instant any column filter was applied.
|
|
447
|
+
// Reading fresh here means that right after our own write, `now` already
|
|
448
|
+
// equals `lastSelfSearch` and we bail out early. Only a genuine external
|
|
449
|
+
// rewrite (router deep-link from a sidebar sibling, browser back/forward)
|
|
450
|
+
// makes `now` diverge, which is exactly when we want to adopt it.
|
|
451
|
+
const now = typeof window !== 'undefined' ? window.location.search : ''
|
|
438
452
|
// Semantic compare: the router's spelling of the query string we just
|
|
439
453
|
// wrote (different order/encoding) is NOT an external change.
|
|
440
|
-
if (canonicalSearch(
|
|
441
|
-
lastSelfSearch.current =
|
|
442
|
-
const params = new URLSearchParams(
|
|
454
|
+
if (canonicalSearch(now) === canonicalSearch(lastSelfSearch.current ?? '')) return
|
|
455
|
+
lastSelfSearch.current = now
|
|
456
|
+
const params = new URLSearchParams(now)
|
|
443
457
|
const filters: Record<string, string[]> = {}
|
|
444
458
|
params.forEach((rawValue, key) => {
|
|
445
459
|
if (!key.startsWith('f_')) return
|
|
@@ -449,13 +463,16 @@ export function DynamicTable({
|
|
|
449
463
|
if (value.startsWith('IN:')) filters[filterKey] = value.substring(3).split(',')
|
|
450
464
|
else filters[filterKey] = [value]
|
|
451
465
|
})
|
|
452
|
-
|
|
453
|
-
|
|
466
|
+
// Compare against the current filters directly (the effect re-runs every
|
|
467
|
+
// render, so this closure is always fresh) and only touch state on a real
|
|
468
|
+
// change — resetting pagination OUTSIDE any updater, never nested inside
|
|
469
|
+
// another setState's updater.
|
|
470
|
+
if (JSON.stringify(dynamicFilters) !== JSON.stringify(filters)) {
|
|
471
|
+
setDynamicFilters(filters)
|
|
454
472
|
setPagination((p: PaginationState) => ({ ...p, pageIndex: 0 }))
|
|
455
|
-
|
|
456
|
-
})
|
|
473
|
+
}
|
|
457
474
|
const search = params.get('search')
|
|
458
|
-
if (search !== null) setGlobalFilter(search)
|
|
475
|
+
if (search !== null && search !== globalFilter) setGlobalFilter(search)
|
|
459
476
|
})
|
|
460
477
|
|
|
461
478
|
const prefetchOptions = useCallback(async (endpoints: string[]) => {
|
|
@@ -777,8 +794,13 @@ export function DynamicTable({
|
|
|
777
794
|
void fetchAggregates()
|
|
778
795
|
}, 300)
|
|
779
796
|
return () => clearTimeout(timeoutId)
|
|
797
|
+
// refreshTrigger is included so an external bump (e.g. a create/edit/
|
|
798
|
+
// delete elsewhere on the page) reloads page 1 in infinite mode too —
|
|
799
|
+
// matching the classic path (fetchData carries refreshTrigger in its
|
|
800
|
+
// deps). Without it the comment above lied: infinite lists silently
|
|
801
|
+
// failed to reload after a create ("a veces no recarga la tabla").
|
|
780
802
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
781
|
-
}, [infiniteScroll, metadata, filterSignature])
|
|
803
|
+
}, [infiniteScroll, metadata, filterSignature, refreshTrigger])
|
|
782
804
|
|
|
783
805
|
const handleRefresh = useCallback(() => {
|
|
784
806
|
// Infinite mode owns its own list: refresh reloads page 1 and drops the
|