@questpie/admin 3.0.9 → 3.2.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.
Files changed (46) hide show
  1. package/dist/augmentation.d.mts +39 -0
  2. package/dist/client/builder/page/page.d.mts +29 -1
  3. package/dist/client/builder/types/field-types.d.mts +10 -14
  4. package/dist/client/components/fields/relation-picker.mjs +2 -2
  5. package/dist/client/components/fields/relation-select.mjs +3 -3
  6. package/dist/client/hooks/use-audit-history.mjs +10 -17
  7. package/dist/client/hooks/use-reactive-prop.mjs +308 -0
  8. package/dist/client/hooks/use-transition-stage.mjs +34 -41
  9. package/dist/client/preview/block-scope-context.d.mts +2 -2
  10. package/dist/client/preview/preview-banner.d.mts +2 -2
  11. package/dist/client/preview/preview-field.d.mts +4 -4
  12. package/dist/client/views/auth/accept-invite-form.d.mts +2 -2
  13. package/dist/client/views/auth/auth-layout.d.mts +3 -3
  14. package/dist/client/views/auth/reset-password-form.d.mts +2 -2
  15. package/dist/client/views/auth/setup-form.d.mts +2 -2
  16. package/dist/client/views/collection/field-renderer.mjs +59 -134
  17. package/dist/client/views/pages/forgot-password-page.d.mts +2 -2
  18. package/dist/client/views/pages/invite-page.d.mts +2 -2
  19. package/dist/client/views/pages/login-page.d.mts +2 -2
  20. package/dist/client/views/pages/reset-password-page.d.mts +2 -2
  21. package/dist/client/views/pages/setup-page.d.mts +2 -2
  22. package/dist/client.d.mts +2 -1
  23. package/dist/client.mjs +2 -1
  24. package/dist/components/rich-text/rich-text-renderer.d.mts +2 -2
  25. package/dist/index.d.mts +2 -1
  26. package/dist/index.mjs +2 -1
  27. package/dist/server/augmentation/form-layout.d.mts +48 -4
  28. package/dist/server/augmentation/index.d.mts +1 -1
  29. package/dist/server/augmentation.d.mts +1 -1
  30. package/dist/server/modules/admin/collections/admin-locks.d.mts +54 -54
  31. package/dist/server/modules/admin/collections/admin-preferences.d.mts +39 -39
  32. package/dist/server/modules/admin/collections/admin-saved-views.d.mts +47 -47
  33. package/dist/server/modules/admin/collections/apikey.d.mts +68 -68
  34. package/dist/server/modules/admin/collections/assets.d.mts +20 -20
  35. package/dist/server/modules/admin/collections/session.d.mts +42 -42
  36. package/dist/server/modules/admin/collections/user.d.mts +32 -32
  37. package/dist/server/modules/admin/collections/verification.d.mts +32 -32
  38. package/dist/server/modules/admin/routes/admin-config.d.mts +2 -2
  39. package/dist/server/modules/admin/routes/execute-action.d.mts +9 -9
  40. package/dist/server/modules/admin/routes/preview.d.mts +11 -11
  41. package/dist/server/modules/admin/routes/reactive.d.mts +13 -11
  42. package/dist/server/modules/admin/routes/reactive.mjs +75 -11
  43. package/dist/server/modules/admin/routes/setup.d.mts +7 -7
  44. package/dist/server/modules/admin/routes/widget-data.d.mts +5 -5
  45. package/dist/server/modules/admin-preferences/collections/saved-views.d.mts +27 -27
  46. package/package.json +4 -4
@@ -205,6 +205,45 @@ interface RelationFieldAdminMeta extends BaseAdminMeta {
205
205
  allowEdit?: boolean;
206
206
  preload?: boolean;
207
207
  maxItems?: number;
208
+ /**
209
+ * Restrict which related records can be picked. Static `Record` is used
210
+ * as-is; a function or `{ handler, deps?, debounce? }` config stays on
211
+ * the server (introspection emits a `ReactivePropPlaceholder`) and is
212
+ * resolved on demand via `/admin/reactive` against current form data.
213
+ *
214
+ * @example Static
215
+ * ```ts
216
+ * f.relation("users").admin({ filter: { role: "admin" } })
217
+ * ```
218
+ *
219
+ * @example Reactive — depends on form state
220
+ * ```ts
221
+ * f.relation("users").admin({
222
+ * filter: ({ data }) => ({ role: "admin", team: data.team }),
223
+ * })
224
+ * ```
225
+ */
226
+ filter?: Record<string, unknown> | ((ctx: {
227
+ data: Record<string, unknown>;
228
+ sibling: Record<string, unknown>;
229
+ prev: {
230
+ data: Record<string, unknown>;
231
+ sibling: Record<string, unknown>;
232
+ };
233
+ ctx: unknown;
234
+ }) => Record<string, unknown> | Promise<Record<string, unknown>>) | {
235
+ handler: (ctx: {
236
+ data: Record<string, unknown>;
237
+ sibling: Record<string, unknown>;
238
+ prev: {
239
+ data: Record<string, unknown>;
240
+ sibling: Record<string, unknown>;
241
+ };
242
+ ctx: unknown;
243
+ }) => Record<string, unknown> | Promise<Record<string, unknown>>;
244
+ deps?: string[];
245
+ debounce?: number;
246
+ };
208
247
  /**
209
248
  * List table cell rendering for relation values.
210
249
  * - "chip": default text chip
@@ -20,5 +20,33 @@ interface PageDefinition<TName extends string = string> {
20
20
  /** Sort order within the navigation group (default: 0). */
21
21
  readonly order?: number;
22
22
  }
23
+ /**
24
+ * Options accepted by the `page()` factory (everything except `name`).
25
+ */
26
+ type PageOptions = {
27
+ component: MaybeLazyComponent;
28
+ showInNav?: boolean;
29
+ path?: string;
30
+ label?: I18nText;
31
+ icon?: IconComponent;
32
+ group?: string;
33
+ order?: number;
34
+ };
35
+ /**
36
+ * Create a custom page as a plain frozen object.
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * // Generated by `questpie generate`:
41
+ * export default page("login", {
42
+ * component: async () => ({
43
+ * default: (await import("./login-page.js")).LoginPage,
44
+ * }),
45
+ * showInNav: false,
46
+ * path: "/login",
47
+ * });
48
+ * ```
49
+ */
50
+ declare function page<TName extends string>(name: TName, config: PageOptions): PageDefinition<TName>;
23
51
  //#endregion
24
- export { PageDefinition };
52
+ export { PageDefinition, page };
@@ -501,22 +501,18 @@ interface FieldReactiveConfig<TData = any> {
501
501
  compute?: FieldReactiveHandlerConfig<TData, any> | SerializedReactiveDepsConfig;
502
502
  }
503
503
  /**
504
- * Field layout item with optional reactive config
504
+ * Field layout item single-field reference variant.
505
+ *
506
+ * On the wire this matches the server's `FormFieldLayoutItem` after
507
+ * introspection has serialized any function-valued `props.<key>` to a
508
+ * `ReactivePropPlaceholder`. Kept as `Record<string, unknown>` here because
509
+ * the client only ever consumes the post-serialization shape.
505
510
  */
506
- interface FieldLayoutItemWithReactive<TData = any> extends FieldReactiveConfig<TData> {
511
+ interface FieldLayoutItemRef<TData = any> extends FieldReactiveConfig<TData> {
507
512
  field: string;
508
513
  className?: string;
509
- /**
510
- * Extra props forwarded to the field component. Use for component-specific
511
- * configuration that doesn't have a dedicated layout key (e.g. relation
512
- * field's `filter`, custom render functions).
513
- *
514
- * @example
515
- * ```ts
516
- * { field: f.counselorId, props: { filter: () => ({ role: "admin" }) } }
517
- * ```
518
- */
519
- props?: Record<string, any>;
514
+ /** Forwarded to the field component. See server `FormFieldLayoutItem.props`. */
515
+ props?: Record<string, unknown>;
520
516
  }
521
517
  /**
522
518
  * Field layout item - can be a simple field name, field with config, section, or tabs
@@ -533,7 +529,7 @@ interface FieldLayoutItemWithReactive<TData = any> extends FieldReactiveConfig<T
533
529
  * ]
534
530
  * ```
535
531
  */
536
- type FieldLayoutItem<TData = any> = string | FieldLayoutItemWithReactive<TData> | SectionLayout<TData> | TabsLayout<TData>;
532
+ type FieldLayoutItem<TData = any> = string | FieldLayoutItemRef<TData> | SectionLayout<TData> | TabsLayout<TData>;
537
533
  /**
538
534
  * Form sidebar configuration
539
535
  * Uses `fields` array (same structure as main form)
@@ -89,7 +89,7 @@ function RelationPicker({ name, value, onChange, targetCollection, label, filter
89
89
  try {
90
90
  const options = { limit: 50 };
91
91
  if (search) options.search = search;
92
- if (filter) options.where = filter({});
92
+ if (filter) options.where = filter;
93
93
  const response_0 = await client.collections[targetCollection].find(options);
94
94
  let docs;
95
95
  if (response_0) if (response_0.docs) docs = response_0.docs;
@@ -244,7 +244,7 @@ function RelationPicker({ name, value, onChange, targetCollection, label, filter
244
244
  {
245
245
  limit: 50,
246
246
  search: search_0,
247
- where: filter ? filter({}) : void 0,
247
+ where: filter ?? void 0,
248
248
  selectedIds
249
249
  }
250
250
  ]),
@@ -49,7 +49,7 @@ function RelationSelect({ name, value, onChange, targetCollection, label, filter
49
49
  locale
50
50
  };
51
51
  if (search) options.search = search;
52
- if (filter) options.where = filter({});
52
+ if (filter) options.where = filter;
53
53
  const response = await client.collections[targetCollection].find(options);
54
54
  let docs;
55
55
  if (response) if (response.docs) docs = response.docs;
@@ -168,7 +168,7 @@ function RelationSelect({ name, value, onChange, targetCollection, label, filter
168
168
  limit: 50,
169
169
  locale,
170
170
  search: search_0,
171
- where: filter ? filter({}) : void 0
171
+ where: filter ?? void 0
172
172
  }
173
173
  ]),
174
174
  prefetchOnMount: true,
@@ -222,7 +222,7 @@ function RelationSelect({ name, value, onChange, targetCollection, label, filter
222
222
  limit: 50,
223
223
  locale,
224
224
  search: search_1,
225
- where: filter ? filter({}) : void 0
225
+ where: filter ?? void 0
226
226
  }
227
227
  ]),
228
228
  prefetchOnMount: true,
@@ -1,21 +1,14 @@
1
- import { selectClient, useAdminStore } from "../runtime/provider.mjs";
1
+ import { selectBasePath, useAdminStore } from "../runtime/provider.mjs";
2
2
  import { c } from "react/compiler-runtime";
3
3
  import { useQuery } from "@tanstack/react-query";
4
4
 
5
5
  //#region src/client/hooks/use-audit-history.ts
6
6
  function useAuditFetcher(path) {
7
- const $ = c(5);
8
- const client = useAdminStore(selectClient);
7
+ const $ = c(3);
8
+ const basePath = useAdminStore(selectBasePath);
9
9
  let t0;
10
- if ($[0] !== client) {
11
- t0 = client.getBasePath?.() ?? "";
12
- $[0] = client;
13
- $[1] = t0;
14
- } else t0 = $[1];
15
- const basePath = t0;
16
- let t1;
17
- if ($[2] !== basePath || $[3] !== path) {
18
- t1 = async (signal) => {
10
+ if ($[0] !== basePath || $[1] !== path) {
11
+ t0 = async (signal) => {
19
12
  const response = await fetch(`${basePath}${path}`, {
20
13
  credentials: "include",
21
14
  headers: { Accept: "application/json" },
@@ -25,11 +18,11 @@ function useAuditFetcher(path) {
25
18
  const data = await response.json();
26
19
  return Array.isArray(data) ? data : data?.docs ?? data ?? [];
27
20
  };
28
- $[2] = basePath;
29
- $[3] = path;
30
- $[4] = t1;
31
- } else t1 = $[4];
32
- return t1;
21
+ $[0] = basePath;
22
+ $[1] = path;
23
+ $[2] = t0;
24
+ } else t0 = $[2];
25
+ return t0;
33
26
  }
34
27
  function useGlobalAuditHistory(globalName, options, queryOptions) {
35
28
  const $ = c(14);
@@ -0,0 +1,308 @@
1
+ import { useAdminStore } from "../runtime/provider.mjs";
2
+ import { c } from "react/compiler-runtime";
3
+ import * as React from "react";
4
+ import { useQuery } from "@tanstack/react-query";
5
+ import { useFormContext, useWatch } from "react-hook-form";
6
+ import { isReactivePropPlaceholder } from "questpie/client";
7
+
8
+ //#region src/client/hooks/use-reactive-prop.ts
9
+ /**
10
+ * useReactiveProps — resolve `extraProps` placeholders against the live form.
11
+ *
12
+ * Field components (relation-select, relation-picker, …) accept user-supplied
13
+ * config via the layout escape hatch:
14
+ *
15
+ * v.collectionForm({
16
+ * fields: [
17
+ * { field: f.author, props: { filter: ({ data }) => ({ team: data.team }) } },
18
+ * ],
19
+ * })
20
+ *
21
+ * Functions never cross the wire — introspection serializes them to a
22
+ * `ReactivePropPlaceholder` carrying just the dependency list. This hook is
23
+ * called by `FieldRenderer` *before* it spreads `extraProps` into the field
24
+ * component's props:
25
+ *
26
+ * - Static JSON / `undefined` → returned synchronously, **no network**.
27
+ * - Placeholder shape `{ "~reactive": "prop", watch, debounce? }` → resolved
28
+ * by calling `/admin/reactive` (`type: "prop"`) with current `formData`.
29
+ *
30
+ * All placeholders inside a single `extraProps` record share **one** TanStack
31
+ * Query — both for cache locality and to collapse N round-trips into one.
32
+ * The query refetches only when any of the union of `watch` deps changes,
33
+ * debounced by `max(placeholder.debounce)` (or the caller-supplied override,
34
+ * default 100ms).
35
+ */
36
+ /**
37
+ * Stable hash of the watched dep values. Replacer keeps `undefined` slots so
38
+ * `[1, undefined, 2]` ≠ `[1, 2]`.
39
+ */
40
+ function hashDeps(values) {
41
+ return JSON.stringify(values, (_, v) => v === void 0 ? "__undef__" : v);
42
+ }
43
+ function useDebounced(value, delay) {
44
+ const $ = c(4);
45
+ const [debounced, setDebounced] = React.useState(value);
46
+ let t0;
47
+ let t1;
48
+ if ($[0] !== delay || $[1] !== value) {
49
+ t0 = () => {
50
+ if (delay <= 0) {
51
+ setDebounced(value);
52
+ return;
53
+ }
54
+ const timer = setTimeout(() => setDebounced(value), delay);
55
+ return () => clearTimeout(timer);
56
+ };
57
+ t1 = [value, delay];
58
+ $[0] = delay;
59
+ $[1] = value;
60
+ $[2] = t0;
61
+ $[3] = t1;
62
+ } else {
63
+ t0 = $[2];
64
+ t1 = $[3];
65
+ }
66
+ React.useEffect(t0, t1);
67
+ return debounced;
68
+ }
69
+ const EMPTY_PROPS = Object.freeze({});
70
+ function useReactiveProps(t0) {
71
+ const $ = c(52);
72
+ const { entity, entityType: t1, field, props, enabled: t2, debounce: debounceOverride } = t0;
73
+ const entityType = t1 === void 0 ? "collection" : t1;
74
+ const enabled = t2 === void 0 ? true : t2;
75
+ let dbMax;
76
+ let dynamicOut;
77
+ let staticOut;
78
+ let watchSet;
79
+ if ($[0] !== props) {
80
+ staticOut = {};
81
+ dynamicOut = [];
82
+ watchSet = /* @__PURE__ */ new Set();
83
+ dbMax = 0;
84
+ if (props) for (const [key, value] of Object.entries(props)) if (isReactivePropPlaceholder(value)) {
85
+ dynamicOut.push({
86
+ key,
87
+ placeholder: value
88
+ });
89
+ for (const dep of value.watch) watchSet.add(dep);
90
+ if (typeof value.debounce === "number" && value.debounce > dbMax) dbMax = value.debounce;
91
+ } else staticOut[key] = value;
92
+ $[0] = props;
93
+ $[1] = dbMax;
94
+ $[2] = dynamicOut;
95
+ $[3] = staticOut;
96
+ $[4] = watchSet;
97
+ } else {
98
+ dbMax = $[1];
99
+ dynamicOut = $[2];
100
+ staticOut = $[3];
101
+ watchSet = $[4];
102
+ }
103
+ const t3 = dynamicOut.length === 0 ? props ?? EMPTY_PROPS : staticOut;
104
+ let t4;
105
+ if ($[5] !== watchSet) {
106
+ t4 = [...watchSet];
107
+ $[5] = watchSet;
108
+ $[6] = t4;
109
+ } else t4 = $[6];
110
+ let t5;
111
+ if ($[7] !== dbMax || $[8] !== dynamicOut || $[9] !== t3 || $[10] !== t4) {
112
+ t5 = {
113
+ staticProps: t3,
114
+ placeholders: dynamicOut,
115
+ watchUnion: t4,
116
+ debounceMax: dbMax
117
+ };
118
+ $[7] = dbMax;
119
+ $[8] = dynamicOut;
120
+ $[9] = t3;
121
+ $[10] = t4;
122
+ $[11] = t5;
123
+ } else t5 = $[11];
124
+ const { staticProps, placeholders, watchUnion, debounceMax } = t5;
125
+ const debounce = debounceOverride ?? (debounceMax > 0 ? debounceMax : 100);
126
+ const formContext = useFormContext();
127
+ const t6 = formContext?.control;
128
+ const t7 = watchUnion;
129
+ const t8 = placeholders.length === 0 || !formContext || watchUnion.length === 0;
130
+ let t9;
131
+ if ($[12] !== t6 || $[13] !== t7 || $[14] !== t8) {
132
+ t9 = {
133
+ control: t6,
134
+ name: t7,
135
+ disabled: t8
136
+ };
137
+ $[12] = t6;
138
+ $[13] = t7;
139
+ $[14] = t8;
140
+ $[15] = t9;
141
+ } else t9 = $[15];
142
+ const watchedRaw = useWatch(t9);
143
+ let t10;
144
+ bb0: {
145
+ if (placeholders.length === 0) {
146
+ let t11$2;
147
+ if ($[16] === Symbol.for("react.memo_cache_sentinel")) {
148
+ t11$2 = [];
149
+ $[16] = t11$2;
150
+ } else t11$2 = $[16];
151
+ t10 = t11$2;
152
+ break bb0;
153
+ }
154
+ if (watchUnion.length === 0) {
155
+ let t11$2;
156
+ if ($[17] === Symbol.for("react.memo_cache_sentinel")) {
157
+ t11$2 = [];
158
+ $[17] = t11$2;
159
+ } else t11$2 = $[17];
160
+ t10 = t11$2;
161
+ break bb0;
162
+ }
163
+ let t11$1;
164
+ if ($[18] !== watchedRaw) {
165
+ t11$1 = Array.isArray(watchedRaw) ? watchedRaw : [watchedRaw];
166
+ $[18] = watchedRaw;
167
+ $[19] = t11$1;
168
+ } else t11$1 = $[19];
169
+ t10 = t11$1;
170
+ }
171
+ const debouncedDeps = useDebounced(t10, debounce);
172
+ let t11;
173
+ if ($[20] !== debouncedDeps) {
174
+ t11 = hashDeps(debouncedDeps);
175
+ $[20] = debouncedDeps;
176
+ $[21] = t11;
177
+ } else t11 = $[21];
178
+ const depHash = t11;
179
+ let t12;
180
+ if ($[22] !== placeholders) {
181
+ t12 = placeholders.map(_temp).sort();
182
+ $[22] = placeholders;
183
+ $[23] = t12;
184
+ } else t12 = $[23];
185
+ const placeholderKeys = t12;
186
+ const client = useAdminStore(_temp2);
187
+ const queryEnabled = enabled && placeholders.length > 0 && !!client;
188
+ let t13;
189
+ if ($[24] !== depHash || $[25] !== entity || $[26] !== entityType || $[27] !== field || $[28] !== placeholderKeys) {
190
+ t13 = [
191
+ "questpie",
192
+ "reactive-props",
193
+ entityType,
194
+ entity,
195
+ field,
196
+ placeholderKeys,
197
+ depHash
198
+ ];
199
+ $[24] = depHash;
200
+ $[25] = entity;
201
+ $[26] = entityType;
202
+ $[27] = field;
203
+ $[28] = placeholderKeys;
204
+ $[29] = t13;
205
+ } else t13 = $[29];
206
+ let t14;
207
+ if ($[30] !== client || $[31] !== entity || $[32] !== entityType || $[33] !== field || $[34] !== formContext || $[35] !== placeholders) {
208
+ t14 = async () => {
209
+ if (!client || placeholders.length === 0) return {};
210
+ const formData = formContext?.getValues?.() ?? {};
211
+ const response = await client.routes.batchReactive({
212
+ collection: entity,
213
+ type: entityType,
214
+ formData,
215
+ requests: placeholders.map((t15$1) => {
216
+ const { key: key_0 } = t15$1;
217
+ return {
218
+ field,
219
+ type: "prop",
220
+ propPath: key_0
221
+ };
222
+ })
223
+ });
224
+ const out = {};
225
+ for (const r of response.results) {
226
+ if (r.field !== field || r.type !== "prop" || !r.propPath) continue;
227
+ if (r.error) throw new Error(`[${r.propPath}] ${r.error}`);
228
+ out[r.propPath] = r.value;
229
+ }
230
+ return out;
231
+ };
232
+ $[30] = client;
233
+ $[31] = entity;
234
+ $[32] = entityType;
235
+ $[33] = field;
236
+ $[34] = formContext;
237
+ $[35] = placeholders;
238
+ $[36] = t14;
239
+ } else t14 = $[36];
240
+ let t15;
241
+ if ($[37] !== queryEnabled || $[38] !== t13 || $[39] !== t14) {
242
+ t15 = {
243
+ queryKey: t13,
244
+ queryFn: t14,
245
+ enabled: queryEnabled,
246
+ placeholderData: _temp3,
247
+ staleTime: 3e4
248
+ };
249
+ $[37] = queryEnabled;
250
+ $[38] = t13;
251
+ $[39] = t14;
252
+ $[40] = t15;
253
+ } else t15 = $[40];
254
+ const query = useQuery(t15);
255
+ let t16;
256
+ bb1: {
257
+ if (placeholders.length === 0) {
258
+ t16 = staticProps;
259
+ break bb1;
260
+ }
261
+ let out_0;
262
+ if ($[41] !== placeholders || $[42] !== query.data || $[43] !== staticProps) {
263
+ out_0 = { ...staticProps };
264
+ let t17$1;
265
+ if ($[45] !== query.data) {
266
+ t17$1 = query.data ?? {};
267
+ $[45] = query.data;
268
+ $[46] = t17$1;
269
+ } else t17$1 = $[46];
270
+ const resolved = t17$1;
271
+ for (const { key: key_1 } of placeholders) out_0[key_1] = resolved[key_1];
272
+ $[41] = placeholders;
273
+ $[42] = query.data;
274
+ $[43] = staticProps;
275
+ $[44] = out_0;
276
+ } else out_0 = $[44];
277
+ t16 = out_0;
278
+ }
279
+ const merged = t16;
280
+ const t17 = query.error ?? null;
281
+ let t18;
282
+ if ($[47] !== merged || $[48] !== query.isFetching || $[49] !== query.isLoading || $[50] !== t17) {
283
+ t18 = {
284
+ props: merged,
285
+ isLoading: query.isLoading,
286
+ isFetching: query.isFetching,
287
+ error: t17
288
+ };
289
+ $[47] = merged;
290
+ $[48] = query.isFetching;
291
+ $[49] = query.isLoading;
292
+ $[50] = t17;
293
+ $[51] = t18;
294
+ } else t18 = $[51];
295
+ return t18;
296
+ }
297
+ function _temp3(prev) {
298
+ return prev;
299
+ }
300
+ function _temp2(s) {
301
+ return s.client;
302
+ }
303
+ function _temp(p) {
304
+ return p.key;
305
+ }
306
+
307
+ //#endregion
308
+ export { useReactiveProps };
@@ -1,4 +1,4 @@
1
- import { selectClient, useAdminStore } from "../runtime/provider.mjs";
1
+ import { selectBasePath, useAdminStore } from "../runtime/provider.mjs";
2
2
  import { c } from "react/compiler-runtime";
3
3
  import { useMutation, useQueryClient } from "@tanstack/react-query";
4
4
 
@@ -9,8 +9,8 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
9
9
  * Provides a mutation for transitioning collection/global records between
10
10
  * workflow stages. Supports optional scheduled transitions via `scheduledAt`.
11
11
  *
12
- * Uses direct fetch (same pattern as audit fetcher) because the generated
13
- * client SDK does not yet expose the `scheduledAt` parameter.
12
+ * Uses direct fetch because the hook accepts runtime collection/global names
13
+ * from admin metadata, while the generated client SDK is keyed by app types.
14
14
  *
15
15
  * @example
16
16
  * ```tsx
@@ -40,22 +40,15 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
40
40
  * @param options - Optional configuration (mode, mutationOptions)
41
41
  */
42
42
  function useTransitionStage(resourceName, options) {
43
- const $ = c(14);
43
+ const $ = c(12);
44
44
  const mode = options?.mode ?? "collection";
45
- const client = useAdminStore(selectClient);
45
+ const basePath = useAdminStore(selectBasePath);
46
46
  const queryClient = useQueryClient();
47
47
  let t0;
48
- if ($[0] !== client) {
49
- t0 = client.getBasePath?.() ?? "";
50
- $[0] = client;
51
- $[1] = t0;
52
- } else t0 = $[1];
53
- const basePath = t0;
54
- let t1;
55
- if ($[2] !== basePath || $[3] !== mode || $[4] !== resourceName) {
56
- t1 = async (params) => {
48
+ if ($[0] !== basePath || $[1] !== mode || $[2] !== resourceName) {
49
+ t0 = async (params) => {
57
50
  const body = { stage: params.stage };
58
- if (params.scheduledAt) body.scheduledAt = params.scheduledAt instanceof Date ? params.scheduledAt.toISOString() : params.scheduledAt;
51
+ if (params.scheduledAt !== void 0) body.scheduledAt = params.scheduledAt instanceof Date ? params.scheduledAt.toISOString() : params.scheduledAt;
59
52
  const url = mode === "global" ? `${basePath}/globals/${resourceName}/transition` : `${basePath}/${resourceName}/${params.id}/transition`;
60
53
  const response = await fetch(url, {
61
54
  method: "POST",
@@ -72,14 +65,14 @@ function useTransitionStage(resourceName, options) {
72
65
  }
73
66
  return response.json();
74
67
  };
75
- $[2] = basePath;
76
- $[3] = mode;
77
- $[4] = resourceName;
78
- $[5] = t1;
79
- } else t1 = $[5];
80
- let t2;
81
- if ($[6] !== mode || $[7] !== queryClient || $[8] !== resourceName) {
82
- t2 = () => {
68
+ $[0] = basePath;
69
+ $[1] = mode;
70
+ $[2] = resourceName;
71
+ $[3] = t0;
72
+ } else t0 = $[3];
73
+ let t1;
74
+ if ($[4] !== mode || $[5] !== queryClient || $[6] !== resourceName) {
75
+ t1 = () => {
83
76
  if (mode === "collection") queryClient.invalidateQueries({ queryKey: ["questpie", "collections"] });
84
77
  else queryClient.invalidateQueries({ queryKey: ["questpie", "globals"] });
85
78
  queryClient.invalidateQueries({ queryKey: [
@@ -89,25 +82,25 @@ function useTransitionStage(resourceName, options) {
89
82
  resourceName
90
83
  ] });
91
84
  };
92
- $[6] = mode;
93
- $[7] = queryClient;
94
- $[8] = resourceName;
95
- $[9] = t2;
96
- } else t2 = $[9];
97
- const t3 = options?.mutationOptions;
98
- let t4;
99
- if ($[10] !== t1 || $[11] !== t2 || $[12] !== t3) {
100
- t4 = {
101
- mutationFn: t1,
102
- onSuccess: t2,
103
- ...t3
85
+ $[4] = mode;
86
+ $[5] = queryClient;
87
+ $[6] = resourceName;
88
+ $[7] = t1;
89
+ } else t1 = $[7];
90
+ const t2 = options?.mutationOptions;
91
+ let t3;
92
+ if ($[8] !== t0 || $[9] !== t1 || $[10] !== t2) {
93
+ t3 = {
94
+ mutationFn: t0,
95
+ onSuccess: t1,
96
+ ...t2
104
97
  };
105
- $[10] = t1;
106
- $[11] = t2;
107
- $[12] = t3;
108
- $[13] = t4;
109
- } else t4 = $[13];
110
- return useMutation(t4);
98
+ $[8] = t0;
99
+ $[9] = t1;
100
+ $[10] = t2;
101
+ $[11] = t3;
102
+ } else t3 = $[11];
103
+ return useMutation(t3);
111
104
  }
112
105
  function _temp() {
113
106
  return {};
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import * as react_jsx_runtime24 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime22 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/client/preview/block-scope-context.d.ts
5
5
 
@@ -35,7 +35,7 @@ declare function BlockScopeProvider({
35
35
  blockId,
36
36
  basePath,
37
37
  children
38
- }: BlockScopeProviderProps): react_jsx_runtime24.JSX.Element;
38
+ }: BlockScopeProviderProps): react_jsx_runtime22.JSX.Element;
39
39
  /**
40
40
  * Get current block scope context.
41
41
  *
@@ -1,4 +1,4 @@
1
- import * as react_jsx_runtime20 from "react/jsx-runtime";
1
+ import * as react_jsx_runtime21 from "react/jsx-runtime";
2
2
 
3
3
  //#region src/client/preview/preview-banner.d.ts
4
4
 
@@ -40,6 +40,6 @@ declare function PreviewBanner({
40
40
  isPreviewMode,
41
41
  className,
42
42
  exitPreviewUrl
43
- }: PreviewBannerProps): react_jsx_runtime20.JSX.Element | null;
43
+ }: PreviewBannerProps): react_jsx_runtime21.JSX.Element | null;
44
44
  //#endregion
45
45
  export { PreviewBanner, PreviewBannerProps };