@asteby/metacore-runtime-react 7.1.4 → 8.0.0

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,45 @@
1
1
  # @asteby/metacore-runtime-react
2
2
 
3
+ ## 8.0.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [c91d778]
8
+ - Updated dependencies [64de425]
9
+ - @asteby/metacore-sdk@2.3.0
10
+ - @asteby/metacore-ui@2.0.0
11
+
12
+ ## 7.1.5
13
+
14
+ ### Patch Changes
15
+
16
+ - 922d63b: Add `<MetacoreAppShell>` — single-line provider wiring for metacore apps.
17
+
18
+ Today every app reproduces the same eight-deep wedding cake of providers (QueryClient + ApiProvider + PWAProvider + Toaster + install/update/offline prompts + metadata cache invalidation). The new shell collapses it into:
19
+
20
+ ```tsx
21
+ import { MetacoreAppShell } from "@asteby/metacore-app-providers";
22
+
23
+ <MetacoreAppShell api={api} queryClient={queryClient}>
24
+ <RouterProvider router={router} />
25
+ </MetacoreAppShell>;
26
+ ```
27
+
28
+ What it bundles:
29
+ - `QueryClientProvider` (when `queryClient` is supplied)
30
+ - `ApiProvider` from `runtime-react`
31
+ - `PWAProvider` + `PWAInstallPrompt` + `PWAUpdatePrompt` + `OfflineIndicator`
32
+ - `Toaster` from `metacore-ui`
33
+ - A `MetadataInvalidator` that clears `useMetadataCache` the moment the PWA layer reports a new service worker — so the next mount of `<DynamicTable>` fetches fresh column / filter / actions definitions instead of replaying yesterday's metadata. Resolves the stale-cache bug where adding `filterable: true` to a column on the backend was invisible until users cleared localStorage.
34
+
35
+ Apps that want a subset can pass `hidePWAInstall` / `hidePWAUpdate` / `hideOfflineIndicator` / `hideToaster` / `disableMetadataInvalidate` to opt out per layer.
36
+
37
+ `runtime-react` patch: also switches `<DynamicTable>` to stale-while-revalidate metadata fetch (paint with cache, always re-fetch in background) so the shell isn't the only path that picks up backend changes.
38
+
39
+ - 922d63b: Auto-derive `date_range` filter for `type: 'date'` columns.
40
+
41
+ The zero-config filter chip in 7.1.0 picked the right variant for text/number/boolean/select but mapped `type: 'date'` to a generic text filter. `FilterableColumnHeader` already supports `date_range` — pointing the auto-derive at it makes any column flagged `filterable: true` with `type: 'date'` light up the calendar range picker without app-side glue.
42
+
3
43
  ## 7.1.4
4
44
 
5
45
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"dynamic-table.d.ts","sourceRoot":"","sources":["../src/dynamic-table.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAKH,KAAK,SAAS,EAajB,MAAM,uBAAuB,CAAA;AA+B9B,OAAO,KAAK,EAAsB,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AASnF,UAAU,iBAAiB;IACvB,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,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;CACxC;AAED,wBAAgB,YAAY,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,aAAoB,EACpB,aAAkB,EAClB,QAAQ,EACR,cAAc,EACd,cAAc,EACd,YAAiB,EACjB,iBAA4C,GAC/C,EAAE,iBAAiB,2CAwrBnB"}
1
+ {"version":3,"file":"dynamic-table.d.ts","sourceRoot":"","sources":["../src/dynamic-table.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAKH,KAAK,SAAS,EAajB,MAAM,uBAAuB,CAAA;AA+B9B,OAAO,KAAK,EAAsB,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AASnF,UAAU,iBAAiB;IACvB,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,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;CACxC;AAED,wBAAgB,YAAY,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,aAAoB,EACpB,aAAkB,EAClB,QAAQ,EACR,cAAc,EACd,cAAc,EACd,YAAiB,EACjB,iBAA4C,GAC/C,EAAE,iBAAiB,2CA8rBnB"}
@@ -191,35 +191,42 @@ export function DynamicTable({ model, endpoint, enableUrlSync = true, hiddenColu
191
191
  return;
192
192
  metaInitRef.current = true;
193
193
  const initMetadataAndOptions = async () => {
194
- let meta;
195
194
  const cached = getMetadata(model);
195
+ // Stale-while-revalidate: paint with the cached metadata if any so
196
+ // the table renders instantly, then always re-fetch in the
197
+ // background so a backend metadata change (new column, new
198
+ // filterable flag) propagates without users having to clear
199
+ // localStorage.
196
200
  if (cached) {
197
- meta = cached;
198
- setMetadata(meta);
201
+ setMetadata(cached);
199
202
  if (!urlHadPerPage.current)
200
- setPagination((prev) => ({ ...prev, pageSize: meta.defaultPerPage || 10 }));
203
+ setPagination((prev) => ({ ...prev, pageSize: cached.defaultPerPage || 10 }));
201
204
  setLoading(false);
202
205
  }
203
206
  else {
204
207
  setLoading(true);
205
- try {
206
- const res = await api.get(`/metadata/table/${model}`);
207
- if (!res.data.success)
208
- return;
209
- meta = res.data.data;
210
- setMetadata(meta);
211
- cacheMetadata(model, meta);
208
+ }
209
+ let meta = cached || null;
210
+ try {
211
+ const res = await api.get(`/metadata/table/${model}`);
212
+ if (res.data.success) {
213
+ const fresh = res.data.data;
214
+ meta = fresh;
215
+ setMetadata(fresh);
216
+ cacheMetadata(model, fresh);
212
217
  if (!urlHadPerPage.current)
213
- setPagination((prev) => ({ ...prev, pageSize: meta.defaultPerPage || 10 }));
218
+ setPagination((prev) => ({ ...prev, pageSize: fresh.defaultPerPage || 10 }));
214
219
  }
215
- catch (error) {
220
+ }
221
+ catch (error) {
222
+ if (!cached)
216
223
  console.error('Error al cargar la configuración de la tabla', error);
217
- return;
218
- }
219
- finally {
220
- setLoading(false);
221
- }
222
224
  }
225
+ finally {
226
+ setLoading(false);
227
+ }
228
+ if (!meta)
229
+ return;
223
230
  const columnEndpoints = meta.columns.filter(c => c.useOptions && c.searchEndpoint).map(c => c.searchEndpoint);
224
231
  const filterEndpoints = (meta.filters || []).filter(f => f.searchEndpoint && (f.type === 'select' || f.type === 'boolean')).map(f => f.searchEndpoint);
225
232
  const allEndpoints = [...columnEndpoints, ...filterEndpoints];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asteby/metacore-runtime-react",
3
- "version": "7.1.4",
3
+ "version": "8.0.0",
4
4
  "description": "React runtime for metacore hosts — renders addon contributions dynamically",
5
5
  "repository": {
6
6
  "type": "git",
@@ -29,8 +29,8 @@
29
29
  "lucide-react": ">=0.460",
30
30
  "date-fns": ">=3",
31
31
  "react-day-picker": ">=8",
32
- "@asteby/metacore-sdk": "^2.2.0",
33
- "@asteby/metacore-ui": "^0.7.0"
32
+ "@asteby/metacore-sdk": "^2.3.0",
33
+ "@asteby/metacore-ui": "^2.0.0"
34
34
  },
35
35
  "peerDependenciesMeta": {
36
36
  "@tanstack/react-router": {
@@ -47,16 +47,16 @@
47
47
  "@types/react": "^19.0.0",
48
48
  "date-fns": "^4.1.0",
49
49
  "i18next": "^26.0.0",
50
- "lucide-react": "^0.460.0",
50
+ "lucide-react": "^1.0.0",
51
51
  "react": "^19.2.4",
52
- "react-day-picker": "^8.10.1",
52
+ "react-day-picker": "^9.0.0",
53
53
  "react-dom": "^19.2.4",
54
- "react-i18next": "^15.1.0",
55
- "sonner": "^1.7.0",
54
+ "react-i18next": "^17.0.0",
55
+ "sonner": "^2.0.0",
56
56
  "typescript": "^5.6.0",
57
57
  "zustand": "^5.0.0",
58
- "@asteby/metacore-sdk": "2.2.0",
59
- "@asteby/metacore-ui": "0.7.0"
58
+ "@asteby/metacore-sdk": "2.3.0",
59
+ "@asteby/metacore-ui": "2.0.0"
60
60
  },
61
61
  "scripts": {
62
62
  "build": "tsc -p tsconfig.json",
@@ -269,29 +269,35 @@ export function DynamicTable({
269
269
  if (metaInitRef.current) return
270
270
  metaInitRef.current = true
271
271
  const initMetadataAndOptions = async () => {
272
- let meta: TableMetadata
273
272
  const cached = getMetadata(model)
273
+ // Stale-while-revalidate: paint with the cached metadata if any so
274
+ // the table renders instantly, then always re-fetch in the
275
+ // background so a backend metadata change (new column, new
276
+ // filterable flag) propagates without users having to clear
277
+ // localStorage.
274
278
  if (cached) {
275
- meta = cached
276
- setMetadata(meta)
277
- if (!urlHadPerPage.current) setPagination((prev: PaginationState) => ({ ...prev, pageSize: meta.defaultPerPage || 10 }))
279
+ setMetadata(cached)
280
+ if (!urlHadPerPage.current) setPagination((prev: PaginationState) => ({ ...prev, pageSize: cached.defaultPerPage || 10 }))
278
281
  setLoading(false)
279
282
  } else {
280
283
  setLoading(true)
281
- try {
282
- const res = await api.get(`/metadata/table/${model}`) as { data: ApiResponse<TableMetadata> }
283
- if (!res.data.success) return
284
- meta = res.data.data
285
- setMetadata(meta)
286
- cacheMetadata(model, meta)
287
- if (!urlHadPerPage.current) setPagination((prev: PaginationState) => ({ ...prev, pageSize: meta.defaultPerPage || 10 }))
288
- } catch (error) {
289
- console.error('Error al cargar la configuración de la tabla', error)
290
- return
291
- } finally {
292
- setLoading(false)
284
+ }
285
+ let meta: TableMetadata | null = cached || null
286
+ try {
287
+ const res = await api.get(`/metadata/table/${model}`) as { data: ApiResponse<TableMetadata> }
288
+ if (res.data.success) {
289
+ const fresh = res.data.data
290
+ meta = fresh
291
+ setMetadata(fresh)
292
+ cacheMetadata(model, fresh)
293
+ if (!urlHadPerPage.current) setPagination((prev: PaginationState) => ({ ...prev, pageSize: fresh.defaultPerPage || 10 }))
293
294
  }
295
+ } catch (error) {
296
+ if (!cached) console.error('Error al cargar la configuración de la tabla', error)
297
+ } finally {
298
+ setLoading(false)
294
299
  }
300
+ if (!meta) return
295
301
  const columnEndpoints = meta.columns.filter(c => c.useOptions && c.searchEndpoint).map(c => c.searchEndpoint!)
296
302
  const filterEndpoints = (meta.filters || []).filter(f => f.searchEndpoint && (f.type === 'select' || f.type === 'boolean')).map(f => f.searchEndpoint!)
297
303
  const allEndpoints = [...columnEndpoints, ...filterEndpoints]