@asteby/metacore-runtime-react 23.12.1 → 23.12.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 +13 -0
- package/dist/dynamic-table.d.ts.map +1 -1
- package/dist/dynamic-table.js +30 -10
- package/package.json +1 -1
- package/src/dynamic-table.tsx +31 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @asteby/metacore-runtime-react
|
|
2
2
|
|
|
3
|
+
## 23.12.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 5333315: fix(dynamic-table): don't rewrite a clean filtered deep-link (no URL flicker)
|
|
8
|
+
|
|
9
|
+
Normalise the `eq:` operator when fingerprinting the query string and stop
|
|
10
|
+
stamping `per_page` for the plain server default, so opening/clicking a
|
|
11
|
+
sidebar deep-link (`f_status=eq:in_progress&view=list`) is a true no-op: the
|
|
12
|
+
table adopts the filter without rewriting the URL to its own spelling
|
|
13
|
+
(`f_status=in_progress&per_page=15`). This removes the visible URL flicker and
|
|
14
|
+
keeps the sidebar active-state exact-href match working.
|
|
15
|
+
|
|
3
16
|
## 23.12.1
|
|
4
17
|
|
|
5
18
|
### Patch 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,+BAwmCnB"}
|
package/dist/dynamic-table.js
CHANGED
|
@@ -78,6 +78,13 @@ export function DynamicTable({ model, endpoint, enableUrlSync = true, hiddenColu
|
|
|
78
78
|
const [filterOptionsMap, setFilterOptionsMap] = useState(new Map());
|
|
79
79
|
const initializedFromUrl = useRef(false);
|
|
80
80
|
const urlHadPerPage = useRef(false);
|
|
81
|
+
// The model's server-declared default page size. When the current page size
|
|
82
|
+
// is just this default (the user hasn't paged/resized and the URL didn't
|
|
83
|
+
// pin one), we deliberately DON'T stamp `per_page` into the URL — otherwise
|
|
84
|
+
// the table appends `per_page=15` to the sidebar's clean deep-link on mount,
|
|
85
|
+
// which reads as a URL flicker and fights the router's spelling. Starts at 10
|
|
86
|
+
// to match the initial pagination state until metadata arrives.
|
|
87
|
+
const defaultPerPage = useRef(10);
|
|
81
88
|
useEffect(() => {
|
|
82
89
|
if (prevBranchId.current !== currentBranch?.id) {
|
|
83
90
|
prevBranchId.current = currentBranch?.id;
|
|
@@ -114,18 +121,26 @@ export function DynamicTable({ model, endpoint, enableUrlSync = true, hiddenColu
|
|
|
114
121
|
const alias = operatorToUrlAlias[prefix];
|
|
115
122
|
return alias ? `${alias}:${rest}` : value;
|
|
116
123
|
};
|
|
117
|
-
// Order- and
|
|
118
|
-
// router (TanStack)
|
|
119
|
-
// — different key order
|
|
120
|
-
// (`f_status=eq%
|
|
121
|
-
//
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
//
|
|
124
|
+
// Order-, encoding- and operator-independent fingerprint of a query string.
|
|
125
|
+
// The host router (TanStack) and the sidebar deep-link the filter in THEIR
|
|
126
|
+
// canonical form — different key order, percent-encoded operator colons, and
|
|
127
|
+
// the explicit `eq:` operator (`f_status=eq%3Ain_progress`) — while the table
|
|
128
|
+
// internally unwraps `eq:` for selects and would write the bare value
|
|
129
|
+
// (`f_status=in_progress`). Comparing raw (or even just decoded) strings then
|
|
130
|
+
// NEVER matches, so the table rewrites the URL on every navigation and the
|
|
131
|
+
// two spellings visibly ping-pong ("parpadeo", "Throttling navigation…" +
|
|
132
|
+
// React #185). Normalising each `f_` value through `urlValueToInternal`
|
|
133
|
+
// collapses `eq:X` and `X` to the same token, so a sorted `key=value` list is
|
|
134
|
+
// a true semantic fingerprint and the write effect can detect real no-ops —
|
|
135
|
+
// leaving the router's own spelling untouched (so the sidebar active-state
|
|
136
|
+
// match on the exact href keeps working too).
|
|
125
137
|
const canonicalSearch = (searchStr) => {
|
|
126
138
|
const p = new URLSearchParams(searchStr);
|
|
127
139
|
const entries = [];
|
|
128
|
-
p.forEach((value, key) =>
|
|
140
|
+
p.forEach((value, key) => {
|
|
141
|
+
const norm = key.startsWith('f_') ? urlValueToInternal(value) : value;
|
|
142
|
+
entries.push(`${key}=${norm}`);
|
|
143
|
+
});
|
|
129
144
|
entries.sort();
|
|
130
145
|
return entries.join('&');
|
|
131
146
|
};
|
|
@@ -191,7 +206,10 @@ export function DynamicTable({ model, endpoint, enableUrlSync = true, hiddenColu
|
|
|
191
206
|
}
|
|
192
207
|
if (pagination.pageIndex > 0)
|
|
193
208
|
params.set('page', String(pagination.pageIndex + 1));
|
|
194
|
-
|
|
209
|
+
// Only pin per_page when it deviates from the model's default (an explicit
|
|
210
|
+
// user page-size change) or the URL already carried one — not for the
|
|
211
|
+
// plain server default, which would needlessly mutate a clean deep-link.
|
|
212
|
+
if (pagination.pageSize !== defaultPerPage.current || urlHadPerPage.current)
|
|
195
213
|
params.set('per_page', String(pagination.pageSize));
|
|
196
214
|
if (sorting.length > 0) {
|
|
197
215
|
params.set('sortBy', sorting[0].id);
|
|
@@ -296,6 +314,7 @@ export function DynamicTable({ model, endpoint, enableUrlSync = true, hiddenColu
|
|
|
296
314
|
// localStorage.
|
|
297
315
|
if (cached) {
|
|
298
316
|
setMetadata(cached);
|
|
317
|
+
defaultPerPage.current = cached.defaultPerPage || 10;
|
|
299
318
|
if (!urlHadPerPage.current)
|
|
300
319
|
setPagination((prev) => ({ ...prev, pageSize: cached.defaultPerPage || 10 }));
|
|
301
320
|
setLoading(false);
|
|
@@ -311,6 +330,7 @@ export function DynamicTable({ model, endpoint, enableUrlSync = true, hiddenColu
|
|
|
311
330
|
meta = fresh;
|
|
312
331
|
setMetadata(fresh);
|
|
313
332
|
cacheMetadata(model, fresh);
|
|
333
|
+
defaultPerPage.current = fresh.defaultPerPage || 10;
|
|
314
334
|
if (!urlHadPerPage.current)
|
|
315
335
|
setPagination((prev) => ({ ...prev, pageSize: fresh.defaultPerPage || 10 }));
|
|
316
336
|
}
|
package/package.json
CHANGED
package/src/dynamic-table.tsx
CHANGED
|
@@ -190,6 +190,13 @@ export function DynamicTable({
|
|
|
190
190
|
|
|
191
191
|
const initializedFromUrl = useRef(false)
|
|
192
192
|
const urlHadPerPage = useRef(false)
|
|
193
|
+
// The model's server-declared default page size. When the current page size
|
|
194
|
+
// is just this default (the user hasn't paged/resized and the URL didn't
|
|
195
|
+
// pin one), we deliberately DON'T stamp `per_page` into the URL — otherwise
|
|
196
|
+
// the table appends `per_page=15` to the sidebar's clean deep-link on mount,
|
|
197
|
+
// which reads as a URL flicker and fights the router's spelling. Starts at 10
|
|
198
|
+
// to match the initial pagination state until metadata arrives.
|
|
199
|
+
const defaultPerPage = useRef(10)
|
|
193
200
|
|
|
194
201
|
useEffect(() => {
|
|
195
202
|
if (prevBranchId.current !== currentBranch?.id) {
|
|
@@ -229,18 +236,26 @@ export function DynamicTable({
|
|
|
229
236
|
return alias ? `${alias}:${rest}` : value
|
|
230
237
|
}
|
|
231
238
|
|
|
232
|
-
// Order- and
|
|
233
|
-
// router (TanStack)
|
|
234
|
-
// — different key order
|
|
235
|
-
// (`f_status=eq%
|
|
236
|
-
//
|
|
237
|
-
//
|
|
238
|
-
//
|
|
239
|
-
//
|
|
239
|
+
// Order-, encoding- and operator-independent fingerprint of a query string.
|
|
240
|
+
// The host router (TanStack) and the sidebar deep-link the filter in THEIR
|
|
241
|
+
// canonical form — different key order, percent-encoded operator colons, and
|
|
242
|
+
// the explicit `eq:` operator (`f_status=eq%3Ain_progress`) — while the table
|
|
243
|
+
// internally unwraps `eq:` for selects and would write the bare value
|
|
244
|
+
// (`f_status=in_progress`). Comparing raw (or even just decoded) strings then
|
|
245
|
+
// NEVER matches, so the table rewrites the URL on every navigation and the
|
|
246
|
+
// two spellings visibly ping-pong ("parpadeo", "Throttling navigation…" +
|
|
247
|
+
// React #185). Normalising each `f_` value through `urlValueToInternal`
|
|
248
|
+
// collapses `eq:X` and `X` to the same token, so a sorted `key=value` list is
|
|
249
|
+
// a true semantic fingerprint and the write effect can detect real no-ops —
|
|
250
|
+
// leaving the router's own spelling untouched (so the sidebar active-state
|
|
251
|
+
// match on the exact href keeps working too).
|
|
240
252
|
const canonicalSearch = (searchStr: string): string => {
|
|
241
253
|
const p = new URLSearchParams(searchStr)
|
|
242
254
|
const entries: string[] = []
|
|
243
|
-
p.forEach((value, key) =>
|
|
255
|
+
p.forEach((value, key) => {
|
|
256
|
+
const norm = key.startsWith('f_') ? urlValueToInternal(value) : value
|
|
257
|
+
entries.push(`${key}=${norm}`)
|
|
258
|
+
})
|
|
244
259
|
entries.sort()
|
|
245
260
|
return entries.join('&')
|
|
246
261
|
}
|
|
@@ -298,7 +313,11 @@ export function DynamicTable({
|
|
|
298
313
|
if (v) params.set(key, v)
|
|
299
314
|
}
|
|
300
315
|
if (pagination.pageIndex > 0) params.set('page', String(pagination.pageIndex + 1))
|
|
301
|
-
|
|
316
|
+
// Only pin per_page when it deviates from the model's default (an explicit
|
|
317
|
+
// user page-size change) or the URL already carried one — not for the
|
|
318
|
+
// plain server default, which would needlessly mutate a clean deep-link.
|
|
319
|
+
if (pagination.pageSize !== defaultPerPage.current || urlHadPerPage.current)
|
|
320
|
+
params.set('per_page', String(pagination.pageSize))
|
|
302
321
|
if (sorting.length > 0) {
|
|
303
322
|
params.set('sortBy', sorting[0].id)
|
|
304
323
|
params.set('order', sorting[0].desc ? 'desc' : 'asc')
|
|
@@ -389,6 +408,7 @@ export function DynamicTable({
|
|
|
389
408
|
// localStorage.
|
|
390
409
|
if (cached) {
|
|
391
410
|
setMetadata(cached)
|
|
411
|
+
defaultPerPage.current = cached.defaultPerPage || 10
|
|
392
412
|
if (!urlHadPerPage.current) setPagination((prev: PaginationState) => ({ ...prev, pageSize: cached.defaultPerPage || 10 }))
|
|
393
413
|
setLoading(false)
|
|
394
414
|
} else {
|
|
@@ -402,6 +422,7 @@ export function DynamicTable({
|
|
|
402
422
|
meta = fresh
|
|
403
423
|
setMetadata(fresh)
|
|
404
424
|
cacheMetadata(model, fresh)
|
|
425
|
+
defaultPerPage.current = fresh.defaultPerPage || 10
|
|
405
426
|
if (!urlHadPerPage.current) setPagination((prev: PaginationState) => ({ ...prev, pageSize: fresh.defaultPerPage || 10 }))
|
|
406
427
|
}
|
|
407
428
|
} catch (error) {
|