@asteby/metacore-runtime-react 23.12.2 → 23.12.3

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 CHANGED
@@ -1,5 +1,19 @@
1
1
  # @asteby/metacore-runtime-react
2
2
 
3
+ ## 23.12.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 5e46e61: fix(dynamic-table): don't strip a deep-linked filter on first mount (URL race)
8
+
9
+ The URL-write effect ran on the very first commit — when `initializedFromUrl`
10
+ (a ref) is already true but the init effect's `setDynamicFilters` hasn't
11
+ re-rendered yet — so it wrote a URL WITHOUT `f_status`, stripping a
12
+ deep-linked/reloaded filter and flickering the address bar until it settled
13
+ without the filter. Gate the write on a STATE flag (`urlSynced`) set once the
14
+ URL has been adopted, so the first write only happens on the render where
15
+ `dynamicFilters`/`pagination` already mirror the URL (a true no-op).
16
+
3
17
  ## 23.12.2
4
18
 
5
19
  ### 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,+BAwmCnB"}
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,+BAsnCnB"}
@@ -85,6 +85,17 @@ export function DynamicTable({ model, endpoint, enableUrlSync = true, hiddenColu
85
85
  // which reads as a URL flicker and fights the router's spelling. Starts at 10
86
86
  // to match the initial pagination state until metadata arrives.
87
87
  const defaultPerPage = useRef(10);
88
+ // Has the table finished adopting its state FROM the URL yet? The write
89
+ // effect must not run before this flips true. `initializedFromUrl` is a ref
90
+ // set synchronously at the top of the init effect, so on the very first
91
+ // commit the write effect (which runs right after, in the SAME commit) sees
92
+ // `initialized=true` but `dynamicFilters` still EMPTY — the init effect's
93
+ // setState hasn't re-rendered yet — and writes a URL WITHOUT `f_status`,
94
+ // stripping a deep-linked filter (the "recarga quita el filtro y parpadea"
95
+ // bug). A STATE flag defers the first write to the render AFTER the URL has
96
+ // been adopted, where `dynamicFilters`/`pagination` already mirror the URL,
97
+ // so the write is a no-op and the filter never gets stripped.
98
+ const [urlSynced, setUrlSynced] = useState(false);
88
99
  useEffect(() => {
89
100
  if (prevBranchId.current !== currentBranch?.id) {
90
101
  prevBranchId.current = currentBranch?.id;
@@ -181,13 +192,16 @@ export function DynamicTable({ model, endpoint, enableUrlSync = true, hiddenColu
181
192
  });
182
193
  if (Object.keys(filters).length > 0)
183
194
  setDynamicFilters(filters);
195
+ // Adopted everything the URL carries; the write effect may now run on the
196
+ // NEXT render (where the setState above has landed) without clobbering it.
197
+ setUrlSynced(true);
184
198
  }, []); // eslint-disable-line react-hooks/exhaustive-deps
185
199
  // The exact query string this table last wrote to the URL — lets the
186
200
  // resync effect below tell "our own replaceState" apart from an external
187
201
  // rewrite by the host router.
188
202
  const lastSelfSearch = useRef(null);
189
203
  useEffect(() => {
190
- if (!enableUrlSync || !initializedFromUrl.current)
204
+ if (!enableUrlSync || !urlSynced)
191
205
  return;
192
206
  const params = new URLSearchParams();
193
207
  // Preserve the route-owned view params. The table rebuilds the query
@@ -241,7 +255,7 @@ export function DynamicTable({ model, endpoint, enableUrlSync = true, hiddenColu
241
255
  const newUrl = search ? `${window.location.pathname}?${search}` : window.location.pathname;
242
256
  lastSelfSearch.current = search ? `?${search}` : '';
243
257
  window.history.replaceState(null, '', newUrl);
244
- }, [enableUrlSync, pagination, sorting, globalFilter, dynamicFilters, defaultFilters]);
258
+ }, [enableUrlSync, urlSynced, pagination, sorting, globalFilter, dynamicFilters, defaultFilters]);
245
259
  // The host router can rewrite the query string WITHOUT remounting the
246
260
  // table — e.g. sidebar sibling entries deep-link different `f_` filters
247
261
  // into the same model route. The mount-time init above never re-runs, so
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asteby/metacore-runtime-react",
3
- "version": "23.12.2",
3
+ "version": "23.12.3",
4
4
  "description": "React runtime for metacore hosts — renders addon contributions dynamically",
5
5
  "repository": {
6
6
  "type": "git",
@@ -197,6 +197,17 @@ export function DynamicTable({
197
197
  // which reads as a URL flicker and fights the router's spelling. Starts at 10
198
198
  // to match the initial pagination state until metadata arrives.
199
199
  const defaultPerPage = useRef(10)
200
+ // Has the table finished adopting its state FROM the URL yet? The write
201
+ // effect must not run before this flips true. `initializedFromUrl` is a ref
202
+ // set synchronously at the top of the init effect, so on the very first
203
+ // commit the write effect (which runs right after, in the SAME commit) sees
204
+ // `initialized=true` but `dynamicFilters` still EMPTY — the init effect's
205
+ // setState hasn't re-rendered yet — and writes a URL WITHOUT `f_status`,
206
+ // stripping a deep-linked filter (the "recarga quita el filtro y parpadea"
207
+ // bug). A STATE flag defers the first write to the render AFTER the URL has
208
+ // been adopted, where `dynamicFilters`/`pagination` already mirror the URL,
209
+ // so the write is a no-op and the filter never gets stripped.
210
+ const [urlSynced, setUrlSynced] = useState(false)
200
211
 
201
212
  useEffect(() => {
202
213
  if (prevBranchId.current !== currentBranch?.id) {
@@ -289,6 +300,9 @@ export function DynamicTable({
289
300
  }
290
301
  })
291
302
  if (Object.keys(filters).length > 0) setDynamicFilters(filters)
303
+ // Adopted everything the URL carries; the write effect may now run on the
304
+ // NEXT render (where the setState above has landed) without clobbering it.
305
+ setUrlSynced(true)
292
306
  }, []) // eslint-disable-line react-hooks/exhaustive-deps
293
307
 
294
308
  // The exact query string this table last wrote to the URL — lets the
@@ -297,7 +311,7 @@ export function DynamicTable({
297
311
  const lastSelfSearch = useRef<string | null>(null)
298
312
 
299
313
  useEffect(() => {
300
- if (!enableUrlSync || !initializedFromUrl.current) return
314
+ if (!enableUrlSync || !urlSynced) return
301
315
  const params = new URLSearchParams()
302
316
  // Preserve the route-owned view params. The table rebuilds the query
303
317
  // string from scratch (it only knows its own page/sort/filter keys), but
@@ -343,7 +357,7 @@ export function DynamicTable({
343
357
  const newUrl = search ? `${window.location.pathname}?${search}` : window.location.pathname
344
358
  lastSelfSearch.current = search ? `?${search}` : ''
345
359
  window.history.replaceState(null, '', newUrl)
346
- }, [enableUrlSync, pagination, sorting, globalFilter, dynamicFilters, defaultFilters])
360
+ }, [enableUrlSync, urlSynced, pagination, sorting, globalFilter, dynamicFilters, defaultFilters])
347
361
 
348
362
  // The host router can rewrite the query string WITHOUT remounting the
349
363
  // table — e.g. sidebar sibling entries deep-link different `f_` filters