@asteby/metacore-runtime-react 39.2.1 → 39.2.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 +12 -0
- package/dist/dynamic-crud-page.d.ts.map +1 -1
- package/dist/dynamic-crud-page.js +6 -2
- package/dist/metadata-cache.d.ts.map +1 -1
- package/dist/metadata-cache.js +19 -5
- package/dist/model-action-toolbar.d.ts.map +1 -1
- package/dist/model-action-toolbar.js +3 -1
- package/package.json +1 -1
- package/src/dynamic-crud-page.tsx +6 -2
- package/src/metadata-cache.ts +19 -5
- package/src/model-action-toolbar.tsx +5 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @asteby/metacore-runtime-react
|
|
2
2
|
|
|
3
|
+
## 39.2.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- caf2015: Always revalidate `/metadata/table` on DynamicCRUDPage cache hit and replace the catalog on `prefetchAll`, so addon toolbar actions cannot stick after HotRegister while zustand localStorage still holds the pre-upgrade snapshot.
|
|
8
|
+
|
|
9
|
+
## 39.2.2
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 4556375: Add data-aby-target model.{Model}.create on ModelActionToolbar create button for Aby UI tours.
|
|
14
|
+
|
|
3
15
|
## 39.2.1
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dynamic-crud-page.d.ts","sourceRoot":"","sources":["../src/dynamic-crud-page.tsx"],"names":[],"mappings":"AAwBA,OAAO,KAKN,MAAM,OAAO,CAAA;AAad,MAAM,WAAW,sBAAsB;IACnC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;mDAC+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAA;CACrB;AASD,MAAM,WAAW,sBAAsB;IACnC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,oBAAoB;IACjC,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAA;IACb,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,gFAAgF;IAChF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,4EAA4E;IAC5E,IAAI,CAAC,EAAE,sBAAsB,CAAA;IAC7B,+EAA+E;IAC/E,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,2EAA2E;IAC3E,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC9B,8DAA8D;IAC9D,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC/B,sDAAsD;IACtD,OAAO,CAAC,EAAE,sBAAsB,CAAA;IAChC,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACxB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,
|
|
1
|
+
{"version":3,"file":"dynamic-crud-page.d.ts","sourceRoot":"","sources":["../src/dynamic-crud-page.tsx"],"names":[],"mappings":"AAwBA,OAAO,KAKN,MAAM,OAAO,CAAA;AAad,MAAM,WAAW,sBAAsB;IACnC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;mDAC+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAA;CACrB;AASD,MAAM,WAAW,sBAAsB;IACnC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,oBAAoB;IACjC,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAA;IACb,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,gFAAgF;IAChF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,4EAA4E;IAC5E,IAAI,CAAC,EAAE,sBAAsB,CAAA;IAC7B,+EAA+E;IAC/E,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,2EAA2E;IAC3E,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC9B,8DAA8D;IAC9D,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC/B,sDAAsD;IACtD,OAAO,CAAC,EAAE,sBAAsB,CAAA;IAChC,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACxB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,qBAuM1D"}
|
|
@@ -58,9 +58,13 @@ export function DynamicCRUDPage(props) {
|
|
|
58
58
|
const [openExport, setOpenExport] = useState(false);
|
|
59
59
|
const [openImport, setOpenImport] = useState(false);
|
|
60
60
|
useEffect(() => {
|
|
61
|
+
// Stale-while-revalidate: paint from the persisted cache immediately,
|
|
62
|
+
// then ALWAYS fetch /metadata/table/:model. Returning early on a cache
|
|
63
|
+
// hit left hosts stranded on pre-upgrade actions (missing toolbar
|
|
64
|
+
// buttons after an addon HotRegister) because hard refresh does not
|
|
65
|
+
// clear zustand localStorage.
|
|
61
66
|
if (cachedMeta) {
|
|
62
67
|
setMetadata(cachedMeta);
|
|
63
|
-
return;
|
|
64
68
|
}
|
|
65
69
|
let cancelled = false;
|
|
66
70
|
api
|
|
@@ -72,7 +76,7 @@ export function DynamicCRUDPage(props) {
|
|
|
72
76
|
setMetadata(meta ?? null);
|
|
73
77
|
})
|
|
74
78
|
.catch(() => {
|
|
75
|
-
if (!cancelled)
|
|
79
|
+
if (!cancelled && !cachedMeta)
|
|
76
80
|
setMetadata(null);
|
|
77
81
|
});
|
|
78
82
|
return () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadata-cache.d.ts","sourceRoot":"","sources":["../src/metadata-cache.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"metadata-cache.d.ts","sourceRoot":"","sources":["../src/metadata-cache.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAE5C,MAAM,WAAW,iBAAiB;IAC9B,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,GAAG,CAAA;KAAE,CAAC,CAAA;CAC7D;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAA;AAE7E;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAQlF;AAED,UAAU,kBAAkB;IACxB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;IACpC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;IACzC,eAAe,EAAE,MAAM,CAAA;IACvB,UAAU,EAAE,OAAO,CAAA;IACnB,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,aAAa,GAAG,SAAS,CAAA;IACvD,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,aAAa,GAAG,SAAS,CAAA;IAC5D,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAA;IAC3D,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAA;IAChE,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAA;IACrC,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAA;IAC1C,WAAW,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACtD;;;;;;;;;;;;;OAaG;IACH,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,KAAK,MAAM,CAAA;IACxE;;;OAGG;IACH,QAAQ,EAAE,MAAM,IAAI,CAAA;CACvB;AAED,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;EA4H5B,CAAA"}
|
package/dist/metadata-cache.js
CHANGED
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
// metadata-cache store so the runtime-react package no longer depends on
|
|
4
4
|
// a host-specific alias.
|
|
5
5
|
//
|
|
6
|
+
// Contract (stale-while-revalidate):
|
|
7
|
+
// - Cache entries are a FIRST PAINT hint only.
|
|
8
|
+
// - Every consumer (DynamicTable, DynamicCRUDPage, ModelActionToolbar hosts)
|
|
9
|
+
// MUST still GET /metadata/table/:model and apply the live payload —
|
|
10
|
+
// including `actions[]`. Skipping the live fetch on a cache hit is how
|
|
11
|
+
// cross-addon toolbar actions disappear after an addon upgrade while
|
|
12
|
+
// localStorage still holds the pre-upgrade catalog.
|
|
13
|
+
// - `prefetchAll` replaces the catalog from `/metadata/all` and advances
|
|
14
|
+
// `metadataVersion`; a version change wipes the prior cache.
|
|
15
|
+
//
|
|
6
16
|
// The prefetchAll() method needs an `api` client (axios-like); we keep that
|
|
7
17
|
// as an injectable parameter so the store stays host-agnostic. If a caller
|
|
8
18
|
// never invokes prefetchAll, the `api` dep is not required.
|
|
@@ -90,9 +100,12 @@ export const useMetadataCache = create()(persist((set, get) => ({
|
|
|
90
100
|
const { tables, modals, version } = res.data.data;
|
|
91
101
|
const serverVersion = version || '';
|
|
92
102
|
const localVersion = get().metadataVersion;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
103
|
+
// Always rebuild from the server catalog. Merging into a
|
|
104
|
+
// persisted cache left hosts with pre-upgrade actions /
|
|
105
|
+
// columns after an addon HotRegister while the tab (or
|
|
106
|
+
// localStorage) stayed open.
|
|
107
|
+
const newCache = {};
|
|
108
|
+
const newModalCache = {};
|
|
96
109
|
if (tables) {
|
|
97
110
|
for (const [key, meta] of Object.entries(tables)) {
|
|
98
111
|
newCache[key] = meta;
|
|
@@ -106,7 +119,7 @@ export const useMetadataCache = create()(persist((set, get) => ({
|
|
|
106
119
|
set({
|
|
107
120
|
cache: newCache,
|
|
108
121
|
modalCache: newModalCache,
|
|
109
|
-
metadataVersion: serverVersion,
|
|
122
|
+
metadataVersion: serverVersion || localVersion || String(Date.now()),
|
|
110
123
|
prefetched: true,
|
|
111
124
|
});
|
|
112
125
|
}
|
|
@@ -118,7 +131,8 @@ export const useMetadataCache = create()(persist((set, get) => ({
|
|
|
118
131
|
}), {
|
|
119
132
|
name: 'metacore-metadata-cache',
|
|
120
133
|
// Bump when display hints (e.g. image_stack) must wipe stale cache.
|
|
121
|
-
|
|
134
|
+
// v5: always replace catalog on prefetchAll (no merge-with-stale).
|
|
135
|
+
version: 5,
|
|
122
136
|
migrate: () => ({
|
|
123
137
|
cache: {},
|
|
124
138
|
modalCache: {},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-action-toolbar.d.ts","sourceRoot":"","sources":["../src/model-action-toolbar.tsx"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,gBAAgB,EAAiC,MAAM,SAAS,CAAA;AAE9E,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAA;AAExD,MAAM,WAAW,uBAAuB;IACpC,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAA;IACb,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAA;IAC5B,qEAAqE;IACrE,UAAU,CAAC,EAAE,eAAe,EAAE,CAAA;IAC9B,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAA;CACtD;AAID;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAgBzD;AAiBD;;;GAGG;AACH,wBAAgB,eAAe,CAC3B,KAAK,EAAE,MAAM,EACb,UAAU,GAAE,eAAe,EAAuB,EAClD,QAAQ,CAAC,EAAE,gBAAgB,EAAE,GAC9B,gBAAgB,EAAE,CA2BpB;AAED,wBAAgB,kBAAkB,CAAC,EAC/B,KAAK,EACL,QAAQ,EACR,OAAO,EACP,UAA+B,EAC/B,QAAQ,EACR,SAAS,EACT,cAAc,GACjB,EAAE,uBAAuB,
|
|
1
|
+
{"version":3,"file":"model-action-toolbar.d.ts","sourceRoot":"","sources":["../src/model-action-toolbar.tsx"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,gBAAgB,EAAiC,MAAM,SAAS,CAAA;AAE9E,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAA;AAExD,MAAM,WAAW,uBAAuB;IACpC,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAA;IACb,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAA;IAC5B,qEAAqE;IACrE,UAAU,CAAC,EAAE,eAAe,EAAE,CAAA;IAC9B,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAA;CACtD;AAID;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAgBzD;AAiBD;;;GAGG;AACH,wBAAgB,eAAe,CAC3B,KAAK,EAAE,MAAM,EACb,UAAU,GAAE,eAAe,EAAuB,EAClD,QAAQ,CAAC,EAAE,gBAAgB,EAAE,GAC9B,gBAAgB,EAAE,CA2BpB;AAED,wBAAgB,kBAAkB,CAAC,EAC/B,KAAK,EACL,QAAQ,EACR,OAAO,EACP,UAA+B,EAC/B,QAAQ,EACR,SAAS,EACT,cAAc,GACjB,EAAE,uBAAuB,sCAqEzB"}
|
|
@@ -109,7 +109,9 @@ export function ModelActionToolbar({ model, endpoint, actions, placements = DEFA
|
|
|
109
109
|
return null;
|
|
110
110
|
return (_jsxs(_Fragment, { children: [_jsx("div", { className: className ?? 'flex items-center gap-2', children: surfaced.map((a) => {
|
|
111
111
|
const isCreate = (a.placement ?? 'row') === 'create';
|
|
112
|
-
return (_jsxs(Button, { variant: isCreate ? 'default' : 'outline',
|
|
112
|
+
return (_jsxs(Button, { variant: isCreate ? 'default' : 'outline', "data-aby-target": isCreate
|
|
113
|
+
? `model.${model}.create`
|
|
114
|
+
: `model.${model}.action.${a.key}`, onClick: () => {
|
|
113
115
|
onActionIntent?.(a);
|
|
114
116
|
setActive(toActionMetadata(a));
|
|
115
117
|
}, onMouseEnter: () => onActionIntent?.(a), onFocus: () => onActionIntent?.(a), style: a.color && !isCreate ? { borderColor: a.color, color: a.color } : undefined, children: [_jsx(DynamicIcon, { name: a.icon || (isCreate ? 'Plus' : 'Zap'), className: "mr-2 h-4 w-4" }), t(a.label, { defaultValue: humanizeActionLabel(a.label) })] }, a.key));
|
package/package.json
CHANGED
|
@@ -127,9 +127,13 @@ export function DynamicCRUDPage(props: DynamicCRUDPageProps) {
|
|
|
127
127
|
const [openImport, setOpenImport] = useState(false)
|
|
128
128
|
|
|
129
129
|
useEffect(() => {
|
|
130
|
+
// Stale-while-revalidate: paint from the persisted cache immediately,
|
|
131
|
+
// then ALWAYS fetch /metadata/table/:model. Returning early on a cache
|
|
132
|
+
// hit left hosts stranded on pre-upgrade actions (missing toolbar
|
|
133
|
+
// buttons after an addon HotRegister) because hard refresh does not
|
|
134
|
+
// clear zustand localStorage.
|
|
130
135
|
if (cachedMeta) {
|
|
131
136
|
setMetadata(cachedMeta)
|
|
132
|
-
return
|
|
133
137
|
}
|
|
134
138
|
let cancelled = false
|
|
135
139
|
api
|
|
@@ -140,7 +144,7 @@ export function DynamicCRUDPage(props: DynamicCRUDPageProps) {
|
|
|
140
144
|
setMetadata(meta ?? null)
|
|
141
145
|
})
|
|
142
146
|
.catch(() => {
|
|
143
|
-
if (!cancelled) setMetadata(null)
|
|
147
|
+
if (!cancelled && !cachedMeta) setMetadata(null)
|
|
144
148
|
})
|
|
145
149
|
return () => {
|
|
146
150
|
cancelled = true
|
package/src/metadata-cache.ts
CHANGED
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
// metadata-cache store so the runtime-react package no longer depends on
|
|
4
4
|
// a host-specific alias.
|
|
5
5
|
//
|
|
6
|
+
// Contract (stale-while-revalidate):
|
|
7
|
+
// - Cache entries are a FIRST PAINT hint only.
|
|
8
|
+
// - Every consumer (DynamicTable, DynamicCRUDPage, ModelActionToolbar hosts)
|
|
9
|
+
// MUST still GET /metadata/table/:model and apply the live payload —
|
|
10
|
+
// including `actions[]`. Skipping the live fetch on a cache hit is how
|
|
11
|
+
// cross-addon toolbar actions disappear after an addon upgrade while
|
|
12
|
+
// localStorage still holds the pre-upgrade catalog.
|
|
13
|
+
// - `prefetchAll` replaces the catalog from `/metadata/all` and advances
|
|
14
|
+
// `metadataVersion`; a version change wipes the prior cache.
|
|
15
|
+
//
|
|
6
16
|
// The prefetchAll() method needs an `api` client (axios-like); we keep that
|
|
7
17
|
// as an injectable parameter so the store stays host-agnostic. If a caller
|
|
8
18
|
// never invokes prefetchAll, the `api` dep is not required.
|
|
@@ -148,10 +158,13 @@ export const useMetadataCache = create<MetadataCacheState>()(
|
|
|
148
158
|
|
|
149
159
|
const serverVersion = version || ''
|
|
150
160
|
const localVersion = get().metadataVersion
|
|
151
|
-
const versionChanged = serverVersion !== localVersion && localVersion !== ''
|
|
152
161
|
|
|
153
|
-
|
|
154
|
-
|
|
162
|
+
// Always rebuild from the server catalog. Merging into a
|
|
163
|
+
// persisted cache left hosts with pre-upgrade actions /
|
|
164
|
+
// columns after an addon HotRegister while the tab (or
|
|
165
|
+
// localStorage) stayed open.
|
|
166
|
+
const newCache: Record<string, TableMetadata> = {}
|
|
167
|
+
const newModalCache: Record<string, TableMetadata> = {}
|
|
155
168
|
|
|
156
169
|
if (tables) {
|
|
157
170
|
for (const [key, meta] of Object.entries(tables)) {
|
|
@@ -167,7 +180,7 @@ export const useMetadataCache = create<MetadataCacheState>()(
|
|
|
167
180
|
set({
|
|
168
181
|
cache: newCache,
|
|
169
182
|
modalCache: newModalCache,
|
|
170
|
-
metadataVersion: serverVersion,
|
|
183
|
+
metadataVersion: serverVersion || localVersion || String(Date.now()),
|
|
171
184
|
prefetched: true,
|
|
172
185
|
})
|
|
173
186
|
} catch {
|
|
@@ -179,7 +192,8 @@ export const useMetadataCache = create<MetadataCacheState>()(
|
|
|
179
192
|
{
|
|
180
193
|
name: 'metacore-metadata-cache',
|
|
181
194
|
// Bump when display hints (e.g. image_stack) must wipe stale cache.
|
|
182
|
-
|
|
195
|
+
// v5: always replace catalog on prefetchAll (no merge-with-stale).
|
|
196
|
+
version: 5,
|
|
183
197
|
migrate: () => ({
|
|
184
198
|
cache: {},
|
|
185
199
|
modalCache: {},
|
|
@@ -166,6 +166,11 @@ export function ModelActionToolbar({
|
|
|
166
166
|
<Button
|
|
167
167
|
key={a.key}
|
|
168
168
|
variant={isCreate ? 'default' : 'outline'}
|
|
169
|
+
data-aby-target={
|
|
170
|
+
isCreate
|
|
171
|
+
? `model.${model}.create`
|
|
172
|
+
: `model.${model}.action.${a.key}`
|
|
173
|
+
}
|
|
169
174
|
onClick={() => {
|
|
170
175
|
onActionIntent?.(a)
|
|
171
176
|
setActive(toActionMetadata(a))
|