@asteby/metacore-runtime-react 23.12.0 → 23.12.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/CHANGELOG.md +14 -0
- package/dist/dynamic-table.d.ts.map +1 -1
- package/dist/dynamic-table.js +28 -1
- package/package.json +1 -1
- package/src/dynamic-table.tsx +29 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @asteby/metacore-runtime-react
|
|
2
2
|
|
|
3
|
+
## 23.12.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 8788161: fix(dynamic-table): stop infinite URL replaceState loop on filtered deep-links
|
|
8
|
+
|
|
9
|
+
The host router re-serializes the query string in its own canonical form
|
|
10
|
+
(different key order, percent-encoded operator colons) than the table writes,
|
|
11
|
+
so the raw-string comparison never matched and the table's write effect fought
|
|
12
|
+
the router's re-serialize forever ("Throttling navigation…" + React #185),
|
|
13
|
+
hanging any filtered sidebar view (e.g. `f_status=eq:reception`). Both URL-sync
|
|
14
|
+
effects now compare an order/encoding-independent fingerprint and the write is
|
|
15
|
+
skipped when semantically a no-op.
|
|
16
|
+
|
|
3
17
|
## 23.12.0
|
|
4
18
|
|
|
5
19
|
### 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;AAanF,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;AAanF,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,+BAmlCnB"}
|
package/dist/dynamic-table.js
CHANGED
|
@@ -114,6 +114,21 @@ export function DynamicTable({ model, endpoint, enableUrlSync = true, hiddenColu
|
|
|
114
114
|
const alias = operatorToUrlAlias[prefix];
|
|
115
115
|
return alias ? `${alias}:${rest}` : value;
|
|
116
116
|
};
|
|
117
|
+
// Order- and encoding-independent fingerprint of a query string. The host
|
|
118
|
+
// router (TanStack) re-serializes the same params in its own canonical form
|
|
119
|
+
// — different key order and percent-encoded operator colons
|
|
120
|
+
// (`f_status=eq%3Areception`) — than the table writes (`f_status=eq:reception`).
|
|
121
|
+
// Comparing raw strings then NEVER matches, so the table's write effect and
|
|
122
|
+
// the router's re-serialize fight forever ("Throttling navigation…" +
|
|
123
|
+
// React #185). URLSearchParams decodes values, so a sorted `key=value` list
|
|
124
|
+
// is stable across both spellings and lets us detect real no-ops.
|
|
125
|
+
const canonicalSearch = (searchStr) => {
|
|
126
|
+
const p = new URLSearchParams(searchStr);
|
|
127
|
+
const entries = [];
|
|
128
|
+
p.forEach((value, key) => entries.push(`${key}=${value}`));
|
|
129
|
+
entries.sort();
|
|
130
|
+
return entries.join('&');
|
|
131
|
+
};
|
|
117
132
|
useEffect(() => {
|
|
118
133
|
if (!enableUrlSync || initializedFromUrl.current)
|
|
119
134
|
return;
|
|
@@ -195,6 +210,16 @@ export function DynamicTable({ model, endpoint, enableUrlSync = true, hiddenColu
|
|
|
195
210
|
params.set(`f_${key}`, `in:${values.join(',')}`);
|
|
196
211
|
});
|
|
197
212
|
const search = params.toString();
|
|
213
|
+
// If what we'd write is semantically identical to what's already in the
|
|
214
|
+
// bar (only key order / colon-encoding differ from the router's form),
|
|
215
|
+
// skip the write entirely. Rewriting would flip the raw string, the
|
|
216
|
+
// router would re-serialize back to its form, and the two would ping-pong
|
|
217
|
+
// forever. We still adopt the current location as "ours" so the resync
|
|
218
|
+
// effect below doesn't treat the router's spelling as an external change.
|
|
219
|
+
if (canonicalSearch(search) === canonicalSearch(window.location.search)) {
|
|
220
|
+
lastSelfSearch.current = window.location.search;
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
198
223
|
const newUrl = search ? `${window.location.pathname}?${search}` : window.location.pathname;
|
|
199
224
|
lastSelfSearch.current = search ? `?${search}` : '';
|
|
200
225
|
window.history.replaceState(null, '', newUrl);
|
|
@@ -209,7 +234,9 @@ export function DynamicTable({ model, endpoint, enableUrlSync = true, hiddenColu
|
|
|
209
234
|
useEffect(() => {
|
|
210
235
|
if (!enableUrlSync || !initializedFromUrl.current)
|
|
211
236
|
return;
|
|
212
|
-
|
|
237
|
+
// Semantic compare: the router's spelling of the query string we just
|
|
238
|
+
// wrote (different order/encoding) is NOT an external change.
|
|
239
|
+
if (canonicalSearch(locationSearch) === canonicalSearch(lastSelfSearch.current ?? ''))
|
|
213
240
|
return;
|
|
214
241
|
lastSelfSearch.current = locationSearch;
|
|
215
242
|
const params = new URLSearchParams(locationSearch);
|
package/package.json
CHANGED
package/src/dynamic-table.tsx
CHANGED
|
@@ -229,6 +229,22 @@ export function DynamicTable({
|
|
|
229
229
|
return alias ? `${alias}:${rest}` : value
|
|
230
230
|
}
|
|
231
231
|
|
|
232
|
+
// Order- and encoding-independent fingerprint of a query string. The host
|
|
233
|
+
// router (TanStack) re-serializes the same params in its own canonical form
|
|
234
|
+
// — different key order and percent-encoded operator colons
|
|
235
|
+
// (`f_status=eq%3Areception`) — than the table writes (`f_status=eq:reception`).
|
|
236
|
+
// Comparing raw strings then NEVER matches, so the table's write effect and
|
|
237
|
+
// the router's re-serialize fight forever ("Throttling navigation…" +
|
|
238
|
+
// React #185). URLSearchParams decodes values, so a sorted `key=value` list
|
|
239
|
+
// is stable across both spellings and lets us detect real no-ops.
|
|
240
|
+
const canonicalSearch = (searchStr: string): string => {
|
|
241
|
+
const p = new URLSearchParams(searchStr)
|
|
242
|
+
const entries: string[] = []
|
|
243
|
+
p.forEach((value, key) => entries.push(`${key}=${value}`))
|
|
244
|
+
entries.sort()
|
|
245
|
+
return entries.join('&')
|
|
246
|
+
}
|
|
247
|
+
|
|
232
248
|
useEffect(() => {
|
|
233
249
|
if (!enableUrlSync || initializedFromUrl.current) return
|
|
234
250
|
initializedFromUrl.current = true
|
|
@@ -295,6 +311,16 @@ export function DynamicTable({
|
|
|
295
311
|
else params.set(`f_${key}`, `in:${values.join(',')}`)
|
|
296
312
|
})
|
|
297
313
|
const search = params.toString()
|
|
314
|
+
// If what we'd write is semantically identical to what's already in the
|
|
315
|
+
// bar (only key order / colon-encoding differ from the router's form),
|
|
316
|
+
// skip the write entirely. Rewriting would flip the raw string, the
|
|
317
|
+
// router would re-serialize back to its form, and the two would ping-pong
|
|
318
|
+
// forever. We still adopt the current location as "ours" so the resync
|
|
319
|
+
// effect below doesn't treat the router's spelling as an external change.
|
|
320
|
+
if (canonicalSearch(search) === canonicalSearch(window.location.search)) {
|
|
321
|
+
lastSelfSearch.current = window.location.search
|
|
322
|
+
return
|
|
323
|
+
}
|
|
298
324
|
const newUrl = search ? `${window.location.pathname}?${search}` : window.location.pathname
|
|
299
325
|
lastSelfSearch.current = search ? `?${search}` : ''
|
|
300
326
|
window.history.replaceState(null, '', newUrl)
|
|
@@ -309,7 +335,9 @@ export function DynamicTable({
|
|
|
309
335
|
const locationSearch = typeof window !== 'undefined' ? window.location.search : ''
|
|
310
336
|
useEffect(() => {
|
|
311
337
|
if (!enableUrlSync || !initializedFromUrl.current) return
|
|
312
|
-
|
|
338
|
+
// Semantic compare: the router's spelling of the query string we just
|
|
339
|
+
// wrote (different order/encoding) is NOT an external change.
|
|
340
|
+
if (canonicalSearch(locationSearch) === canonicalSearch(lastSelfSearch.current ?? '')) return
|
|
313
341
|
lastSelfSearch.current = locationSearch
|
|
314
342
|
const params = new URLSearchParams(locationSearch)
|
|
315
343
|
const filters: Record<string, string[]> = {}
|