@questpie/admin 3.5.2 → 3.5.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.
Files changed (100) hide show
  1. package/dist/client/blocks/block-renderer.d.mts +2 -2
  2. package/dist/client/builder/types/collection-types.d.mts +9 -0
  3. package/dist/client/components/actions/action-dialog.mjs +5 -0
  4. package/dist/client/components/fields/rich-text-editor/bubble-menu.mjs +7 -0
  5. package/dist/client/components/fields/rich-text-editor/extensions.mjs +17 -1
  6. package/dist/client/components/fields/rich-text-editor/index.d.mts +2 -1
  7. package/dist/client/components/fields/rich-text-editor/index.mjs +35 -74
  8. package/dist/client/components/fields/rich-text-editor/slash-commands.mjs +30 -7
  9. package/dist/client/components/fields/rich-text-editor/toolbar.mjs +1 -312
  10. package/dist/client/components/fields/rich-text-editor/types.d.mts +4 -0
  11. package/dist/client/components/fields/rich-text-editor/types.mjs +1 -1
  12. package/dist/client/components/fields/rich-text-editor/utils.mjs +6 -12
  13. package/dist/client/components/filter-builder/filter-builder-sheet.mjs +75 -22
  14. package/dist/client/components/ui/dropdown-menu.mjs +1 -34
  15. package/dist/client/hooks/query-access.d.mts +9 -0
  16. package/dist/client/hooks/query-access.mjs +20 -0
  17. package/dist/client/hooks/typed-hooks.d.mts +4 -2
  18. package/dist/client/hooks/typed-hooks.mjs +30 -29
  19. package/dist/client/hooks/use-reactive-fields.d.mts +1 -0
  20. package/dist/client/hooks/use-reactive-fields.mjs +16 -1
  21. package/dist/client/hooks/use-server-actions.mjs +12 -1
  22. package/dist/client/hooks/use-view-state.mjs +15 -7
  23. package/dist/client/lib/view-filter-utils.mjs +30 -0
  24. package/dist/client/preview/block-scope-context.d.mts +2 -2
  25. package/dist/client/preview/preview-banner.d.mts +2 -2
  26. package/dist/client/preview/preview-field.d.mts +4 -4
  27. package/dist/client/styles/base.css +69 -77
  28. package/dist/client/utils/build-field-definitions-from-schema.mjs +1 -0
  29. package/dist/client/views/auth/accept-invite-form.d.mts +2 -2
  30. package/dist/client/views/auth/auth-layout.d.mts +3 -3
  31. package/dist/client/views/auth/login-form.d.mts +2 -2
  32. package/dist/client/views/auth/reset-password-form.d.mts +2 -2
  33. package/dist/client/views/collection/auto-form-fields.mjs +3 -2
  34. package/dist/client/views/collection/cells/primitive-cells.mjs +9 -6
  35. package/dist/client/views/collection/columns/build-columns.mjs +3 -1
  36. package/dist/client/views/collection/field-renderer.mjs +11 -3
  37. package/dist/client/views/collection/form-view.mjs +207 -202
  38. package/dist/client/views/collection/list-view.mjs +581 -183
  39. package/dist/client/views/collection/outline.mjs +44 -19
  40. package/dist/client/views/collection/quick-filter-bar.mjs +45 -0
  41. package/dist/client/views/collection/table-view.mjs +60 -16
  42. package/dist/client/views/globals/global-form-view.mjs +12 -9
  43. package/dist/client/views/layout/admin-layout.mjs +1 -1
  44. package/dist/client/views/layout/admin-sidebar.mjs +20 -14
  45. package/dist/client/views/layout/admin-theme.mjs +5 -4
  46. package/dist/client.mjs +1 -1
  47. package/dist/components/rich-text/rich-text-renderer.d.mts +5 -5
  48. package/dist/components/rich-text/rich-text-renderer.mjs +5 -2
  49. package/dist/index.mjs +1 -1
  50. package/dist/modules/admin.d.mts +1 -1
  51. package/dist/server/augmentation/actions.d.mts +4 -3
  52. package/dist/server/augmentation/dashboard.d.mts +11 -11
  53. package/dist/server/augmentation/form-layout.d.mts +11 -6
  54. package/dist/server/augmentation/index.d.mts +7 -0
  55. package/dist/server/augmentation/sidebar.d.mts +8 -8
  56. package/dist/server/codegen/admin-client-template.mjs +7 -6
  57. package/dist/server/fields/index.d.mts +1 -1
  58. package/dist/server/fields/rich-text.d.mts +16 -17
  59. package/dist/server/fields/rich-text.mjs +18 -7
  60. package/dist/server/i18n/messages/cs.mjs +2 -0
  61. package/dist/server/i18n/messages/de.mjs +2 -0
  62. package/dist/server/i18n/messages/en.mjs +4 -0
  63. package/dist/server/i18n/messages/es.mjs +2 -0
  64. package/dist/server/i18n/messages/fr.mjs +2 -0
  65. package/dist/server/i18n/messages/pl.mjs +2 -0
  66. package/dist/server/i18n/messages/pt.mjs +2 -0
  67. package/dist/server/i18n/messages/sk.mjs +2 -0
  68. package/dist/server/modules/admin/block/block-builder.d.mts +0 -8
  69. package/dist/server/modules/admin/block/introspection.d.mts +2 -2
  70. package/dist/server/modules/admin/collections/account.d.mts +53 -52
  71. package/dist/server/modules/admin/collections/admin-locks.d.mts +4 -3
  72. package/dist/server/modules/admin/collections/admin-preferences.d.mts +38 -37
  73. package/dist/server/modules/admin/collections/admin-saved-views.d.mts +50 -49
  74. package/dist/server/modules/admin/collections/apikey.d.mts +72 -71
  75. package/dist/server/modules/admin/collections/assets.d.mts +42 -41
  76. package/dist/server/modules/admin/collections/session.d.mts +46 -45
  77. package/dist/server/modules/admin/collections/user.d.mts +67 -66
  78. package/dist/server/modules/admin/collections/verification.d.mts +39 -38
  79. package/dist/server/modules/admin/index.d.mts +3 -3
  80. package/dist/server/modules/admin/routes/admin-config.d.mts +2 -2
  81. package/dist/server/modules/admin/routes/admin-config.mjs +39 -23
  82. package/dist/server/modules/admin/routes/execute-action.mjs +28 -8
  83. package/dist/server/modules/admin/routes/locales.d.mts +2 -2
  84. package/dist/server/modules/admin/routes/preview.d.mts +11 -11
  85. package/dist/server/modules/admin/routes/reactive.d.mts +9 -9
  86. package/dist/server/modules/admin/routes/reactive.mjs +2 -2
  87. package/dist/server/modules/admin/routes/route-helpers.d.mts +11 -7
  88. package/dist/server/modules/admin/routes/setup.d.mts +7 -7
  89. package/dist/server/modules/admin/routes/translations.d.mts +4 -4
  90. package/dist/server/modules/admin/routes/widget-data.d.mts +5 -5
  91. package/dist/server/modules/admin/routes/widget-data.mjs +12 -4
  92. package/dist/server/modules/admin-preferences/collections/saved-views.d.mts +27 -27
  93. package/dist/server/modules/audit/.generated/module.d.mts +6 -6
  94. package/dist/server/modules/audit/collections/audit-log.d.mts +40 -39
  95. package/dist/server/plugin.mjs +3 -3
  96. package/dist/server.d.mts +1 -1
  97. package/dist/shared/types/index.d.mts +1 -0
  98. package/dist/shared/types/saved-views.types.d.mts +14 -7
  99. package/dist/shared.d.mts +3 -2
  100. package/package.json +4 -3
@@ -1,4 +1,6 @@
1
+ import { CollectionQueryKey } from "./query-access.mjs";
1
2
  import { UseMutationOptions, UseQueryOptions } from "@tanstack/react-query";
3
+ import { QuestpieQueryOptionsProxy } from "@questpie/tanstack-query";
2
4
  import { QuestpieApp } from "questpie/client";
3
5
 
4
6
  //#region src/client/hooks/typed-hooks.d.ts
@@ -6,11 +8,11 @@ import { QuestpieApp } from "questpie/client";
6
8
  /**
7
9
  * Extract collection names from a QuestpieApp config
8
10
  */
9
- type CollectionNames<TApp extends QuestpieApp> = keyof TApp["collections"] & string;
11
+ type CollectionNames<TApp extends QuestpieApp> = CollectionQueryKey<TApp>;
10
12
  /**
11
13
  * Extract global names from a QuestpieApp config
12
14
  */
13
- type GlobalNames<TApp extends QuestpieApp> = keyof NonNullable<TApp["globals"]> & string;
15
+ type GlobalNames<TApp extends QuestpieApp> = keyof QuestpieQueryOptionsProxy<TApp>["globals"] & string;
14
16
  interface TypedHooks<TApp extends QuestpieApp> {
15
17
  /**
16
18
  * Hook to fetch collection list with filters, sorting, pagination
@@ -1,5 +1,6 @@
1
- import { selectClient, selectContentLocale, useAdminStore } from "../runtime/provider.mjs";
1
+ import { selectContentLocale, useAdminStore } from "../runtime/provider.mjs";
2
2
  import { useScopedLocale } from "../runtime/locale-scope.mjs";
3
+ import { getCollectionQueryApi, getGlobalQueryApi, useAppClient } from "./query-access.mjs";
3
4
  import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
4
5
  import { createQuestpieQueryOptions } from "@questpie/tanstack-query";
5
6
 
@@ -57,14 +58,14 @@ import { createQuestpieQueryOptions } from "@questpie/tanstack-query";
57
58
  */
58
59
  function createTypedHooks() {
59
60
  function useCollectionList(collection, options, queryOptions) {
60
- const client = useAdminStore(selectClient);
61
+ const client = useAppClient();
61
62
  const { locale: contentLocale } = useScopedLocale();
62
63
  const queryOpts = createQuestpieQueryOptions(client, {
63
64
  keyPrefix: ["questpie", "collections"],
64
65
  locale: contentLocale
65
66
  });
66
67
  return useQuery({
67
- ...collection ? queryOpts.collections[collection].find({
68
+ ...collection ? getCollectionQueryApi(queryOpts, collection).find({
68
69
  ...options,
69
70
  locale: contentLocale
70
71
  }) : {
@@ -84,14 +85,14 @@ function createTypedHooks() {
84
85
  });
85
86
  }
86
87
  function useCollectionCount(collection, options, queryOptions) {
87
- const client = useAdminStore(selectClient);
88
+ const client = useAppClient();
88
89
  const { locale: contentLocale } = useScopedLocale();
89
90
  const queryOpts = createQuestpieQueryOptions(client, {
90
91
  keyPrefix: ["questpie", "collections"],
91
92
  locale: contentLocale
92
93
  });
93
94
  return useQuery({
94
- ...collection ? queryOpts.collections[collection].count({
95
+ ...collection ? getCollectionQueryApi(queryOpts, collection).count({
95
96
  ...options,
96
97
  locale: contentLocale
97
98
  }) : {
@@ -108,14 +109,14 @@ function createTypedHooks() {
108
109
  });
109
110
  }
110
111
  function useCollectionItem(collection, id, options, queryOptions) {
111
- const client = useAdminStore(selectClient);
112
+ const client = useAppClient();
112
113
  const { locale: contentLocale } = useScopedLocale();
113
114
  const queryOpts = createQuestpieQueryOptions(client, {
114
115
  keyPrefix: ["questpie", "collections"],
115
116
  locale: contentLocale
116
117
  });
117
118
  return useQuery({
118
- ...collection ? queryOpts.collections[collection].findOne({
119
+ ...collection ? getCollectionQueryApi(queryOpts, collection).findOne({
119
120
  where: { id },
120
121
  locale: contentLocale,
121
122
  ...options
@@ -133,14 +134,14 @@ function createTypedHooks() {
133
134
  });
134
135
  }
135
136
  function useCollectionCreate(collection, mutationOptions) {
136
- const client = useAdminStore(selectClient);
137
+ const client = useAppClient();
137
138
  const { locale: contentLocale } = useScopedLocale();
138
139
  const queryClient = useQueryClient();
139
140
  const queryOpts = createQuestpieQueryOptions(client, {
140
141
  keyPrefix: ["questpie", "collections"],
141
142
  locale: contentLocale
142
143
  });
143
- const baseOptions = queryOpts.collections[collection].create();
144
+ const baseOptions = getCollectionQueryApi(queryOpts, collection).create();
144
145
  const listQueryKey = queryOpts.key([
145
146
  "collections",
146
147
  collection,
@@ -167,14 +168,14 @@ function createTypedHooks() {
167
168
  });
168
169
  }
169
170
  function useCollectionUpdate(collection, mutationOptions) {
170
- const client = useAdminStore(selectClient);
171
+ const client = useAppClient();
171
172
  const { locale: contentLocale } = useScopedLocale();
172
173
  const queryClient = useQueryClient();
173
174
  const queryOpts = createQuestpieQueryOptions(client, {
174
175
  keyPrefix: ["questpie", "collections"],
175
176
  locale: contentLocale
176
177
  });
177
- const baseOptions = queryOpts.collections[collection].update();
178
+ const baseOptions = getCollectionQueryApi(queryOpts, collection).update();
178
179
  const listQueryKey = queryOpts.key([
179
180
  "collections",
180
181
  collection,
@@ -208,14 +209,14 @@ function createTypedHooks() {
208
209
  });
209
210
  }
210
211
  function useCollectionDelete(collection, mutationOptions) {
211
- const client = useAdminStore(selectClient);
212
+ const client = useAppClient();
212
213
  const { locale: contentLocale } = useScopedLocale();
213
214
  const queryClient = useQueryClient();
214
215
  const queryOpts = createQuestpieQueryOptions(client, {
215
216
  keyPrefix: ["questpie", "collections"],
216
217
  locale: contentLocale
217
218
  });
218
- const baseOptions = queryOpts.collections[collection].delete();
219
+ const baseOptions = getCollectionQueryApi(queryOpts, collection).delete();
219
220
  const listQueryKey = queryOpts.key([
220
221
  "collections",
221
222
  collection,
@@ -249,14 +250,14 @@ function createTypedHooks() {
249
250
  });
250
251
  }
251
252
  function useCollectionRestore(collection, mutationOptions) {
252
- const client = useAdminStore(selectClient);
253
+ const client = useAppClient();
253
254
  const { locale: contentLocale } = useScopedLocale();
254
255
  const queryClient = useQueryClient();
255
256
  const queryOpts = createQuestpieQueryOptions(client, {
256
257
  keyPrefix: ["questpie", "collections"],
257
258
  locale: contentLocale
258
259
  });
259
- const baseOptions = queryOpts.collections[collection].restore();
260
+ const baseOptions = getCollectionQueryApi(queryOpts, collection).restore();
260
261
  const listQueryKey = queryOpts.key([
261
262
  "collections",
262
263
  collection,
@@ -290,14 +291,14 @@ function createTypedHooks() {
290
291
  });
291
292
  }
292
293
  function useCollectionVersions(collection, id, options, queryOptions) {
293
- const client = useAdminStore(selectClient);
294
+ const client = useAppClient();
294
295
  const { locale: contentLocale } = useScopedLocale();
295
296
  const queryOpts = createQuestpieQueryOptions(client, {
296
297
  keyPrefix: ["questpie", "collections"],
297
298
  locale: contentLocale
298
299
  });
299
300
  return useQuery({
300
- ...collection ? queryOpts.collections[collection].findVersions({
301
+ ...collection ? getCollectionQueryApi(queryOpts, collection).findVersions({
301
302
  id,
302
303
  ...options?.limit !== void 0 ? { limit: options.limit } : {},
303
304
  ...options?.offset !== void 0 ? { offset: options.offset } : {}
@@ -318,14 +319,14 @@ function createTypedHooks() {
318
319
  });
319
320
  }
320
321
  function useCollectionRevertVersion(collection, mutationOptions) {
321
- const client = useAdminStore(selectClient);
322
+ const client = useAppClient();
322
323
  const { locale: contentLocale } = useScopedLocale();
323
324
  const queryClient = useQueryClient();
324
325
  const queryOpts = createQuestpieQueryOptions(client, {
325
326
  keyPrefix: ["questpie", "collections"],
326
327
  locale: contentLocale
327
328
  });
328
- const baseOptions = queryOpts.collections[collection].revertToVersion();
329
+ const baseOptions = getCollectionQueryApi(queryOpts, collection).revertToVersion();
329
330
  const listQueryKey = queryOpts.key([
330
331
  "collections",
331
332
  collection,
@@ -366,13 +367,13 @@ function createTypedHooks() {
366
367
  });
367
368
  }
368
369
  function useGlobal(globalName, options, queryOptions) {
369
- const client = useAdminStore(selectClient);
370
+ const client = useAppClient();
370
371
  const contentLocale = useAdminStore(selectContentLocale);
371
372
  return useQuery({
372
- ...createQuestpieQueryOptions(client, {
373
+ ...getGlobalQueryApi(createQuestpieQueryOptions(client, {
373
374
  keyPrefix: ["questpie", "globals"],
374
375
  locale: contentLocale
375
- }).globals[globalName].get({
376
+ }), globalName).get({
376
377
  ...options,
377
378
  locale: contentLocale
378
379
  }),
@@ -380,7 +381,7 @@ function createTypedHooks() {
380
381
  });
381
382
  }
382
383
  function useGlobalUpdate(globalName, mutationOptions) {
383
- const client = useAdminStore(selectClient);
384
+ const client = useAppClient();
384
385
  const contentLocale = useAdminStore(selectContentLocale);
385
386
  const queryClient = useQueryClient();
386
387
  const queryOpts = createQuestpieQueryOptions(client, {
@@ -394,7 +395,7 @@ function createTypedHooks() {
394
395
  contentLocale
395
396
  ]);
396
397
  return useMutation({
397
- ...queryOpts.globals[globalName].update(),
398
+ ...getGlobalQueryApi(queryOpts, globalName).update(),
398
399
  onSuccess: (data, variables, context) => {
399
400
  (mutationOptions?.onSuccess)?.(data, variables, context);
400
401
  },
@@ -406,13 +407,13 @@ function createTypedHooks() {
406
407
  });
407
408
  }
408
409
  function useGlobalVersions(globalName, options, queryOptions) {
409
- const client = useAdminStore(selectClient);
410
+ const client = useAppClient();
410
411
  const contentLocale = useAdminStore(selectContentLocale);
411
412
  return useQuery({
412
- ...createQuestpieQueryOptions(client, {
413
+ ...getGlobalQueryApi(createQuestpieQueryOptions(client, {
413
414
  keyPrefix: ["questpie", "globals"],
414
415
  locale: contentLocale
415
- }).globals[globalName].findVersions({
416
+ }), globalName).findVersions({
416
417
  ...options,
417
418
  locale: contentLocale
418
419
  }),
@@ -420,7 +421,7 @@ function createTypedHooks() {
420
421
  });
421
422
  }
422
423
  function useGlobalRevertVersion(globalName, mutationOptions) {
423
- const client = useAdminStore(selectClient);
424
+ const client = useAppClient();
424
425
  const contentLocale = useAdminStore(selectContentLocale);
425
426
  const queryClient = useQueryClient();
426
427
  const queryOpts = createQuestpieQueryOptions(client, {
@@ -440,7 +441,7 @@ function createTypedHooks() {
440
441
  contentLocale
441
442
  ]);
442
443
  return useMutation({
443
- ...queryOpts.globals[globalName].revertToVersion(),
444
+ ...getGlobalQueryApi(queryOpts, globalName).revertToVersion(),
444
445
  onSuccess: (data, variables, context) => {
445
446
  (mutationOptions?.onSuccess)?.(data, variables, context);
446
447
  },
@@ -1,3 +1,4 @@
1
+ import "react";
1
2
  import { UseFormReturn } from "react-hook-form";
2
3
  import { FieldReactiveSchema } from "questpie/client";
3
4
 
@@ -10,6 +10,8 @@ import { useFormContext, useWatch } from "react-hook-form";
10
10
  * Watches form changes and triggers server-side reactive handlers.
11
11
  * Supports batched RPC calls with debouncing.
12
12
  */
13
+ const EMPTY_REACTIVE_FIELD_STATE = {};
14
+ const ReactiveFieldStatesContext = React.createContext({});
13
15
  /**
14
16
  * Get sibling data for a field path (for fields inside arrays)
15
17
  */
@@ -66,6 +68,19 @@ function getChangedDeps(prevDeps, nextDeps) {
66
68
  for (const [dep, value] of Object.entries(nextDeps)) if (prevDeps[dep] !== value) changed.push(dep);
67
69
  return changed;
68
70
  }
71
+ function mergeReactiveFieldState(base, reactive) {
72
+ return {
73
+ hidden: base.hidden === true || reactive?.hidden === true,
74
+ readOnly: base.readOnly === true || reactive?.readOnly === true,
75
+ disabled: base.disabled === true || reactive?.disabled === true
76
+ };
77
+ }
78
+ function ReactiveFieldStatesProvider({ fieldStates, children }) {
79
+ return React.createElement(ReactiveFieldStatesContext.Provider, { value: fieldStates }, children);
80
+ }
81
+ function useReactiveFieldState(fieldPath) {
82
+ return React.useContext(ReactiveFieldStatesContext)[fieldPath] ?? EMPTY_REACTIVE_FIELD_STATE;
83
+ }
69
84
  /**
70
85
  * Hook to manage reactive field states.
71
86
  * Watches form changes and triggers server-side handlers when dependencies change.
@@ -198,4 +213,4 @@ function useReactiveFields({ collection, mode = "collection", reactiveConfigs, d
198
213
  }
199
214
 
200
215
  //#endregion
201
- export { useReactiveFields };
216
+ export { ReactiveFieldStatesProvider, mergeReactiveFieldState, useReactiveFieldState, useReactiveFields };
@@ -14,6 +14,13 @@ import * as React from "react";
14
14
  * Server actions have their handlers stripped during serialization; this hook
15
15
  * creates client-side wrappers that execute actions via the server API.
16
16
  */
17
+ var ServerActionValidationError = class extends Error {
18
+ constructor(message, fieldErrors) {
19
+ super(message);
20
+ this.fieldErrors = fieldErrors;
21
+ this.name = "ServerActionValidationError";
22
+ }
23
+ };
17
24
  function getActionErrorMessage(response, t) {
18
25
  if (response.error) return response.error;
19
26
  if (response.result?.toast?.message) return response.result.toast.message;
@@ -106,7 +113,11 @@ function mapServerAction(serverAction, collection, fieldRegistry, client, locale
106
113
  data,
107
114
  locale
108
115
  });
109
- if (!response.success || response.result?.type === "error") throw new Error(getActionErrorMessage(response, t));
116
+ if (!response.success || response.result?.type === "error") {
117
+ const message = getActionErrorMessage(response, t);
118
+ if (response.result?.errors) throw new ServerActionValidationError(message, response.result.errors);
119
+ throw new Error(message);
120
+ }
110
121
  await applyServerActionEffects(response.result, ctx);
111
122
  return response.result?.toast?.message;
112
123
  }
@@ -1,5 +1,6 @@
1
1
  import { useAdminStore } from "../runtime/provider.mjs";
2
2
  import { getAdminPreferenceQueryKey, useSetAdminPreference } from "./use-admin-preferences.mjs";
3
+ import { cloneFilters, filtersEqual, sortConfigEqual } from "../lib/view-filter-utils.mjs";
3
4
  import { useCallback, useEffect, useMemo, useRef } from "react";
4
5
  import { useQueryClient, useSuspenseQuery } from "@tanstack/react-query";
5
6
 
@@ -102,7 +103,7 @@ function useViewState(defaultColumns, initialConfig, collectionName, userId) {
102
103
  }
103
104
  };
104
105
  return {
105
- filters: initialConfig?.filters ?? [],
106
+ filters: cloneFilters(initialConfig?.filters ?? []),
106
107
  sortConfig: initialConfig?.sortConfig ?? null,
107
108
  visibleColumns: defaultColumns,
108
109
  groupBy: initialConfig?.groupBy ?? null,
@@ -273,17 +274,24 @@ function useViewState(defaultColumns, initialConfig, collectionName, userId) {
273
274
  resetConfig: useCallback(() => {
274
275
  setConfig({
275
276
  ...EMPTY_CONFIG,
276
- visibleColumns: defaultColumns
277
+ filters: cloneFilters(initialConfig?.filters ?? []),
278
+ sortConfig: initialConfig?.sortConfig ?? null,
279
+ visibleColumns: defaultColumns,
280
+ groupBy: initialConfig?.groupBy ?? null,
281
+ realtime: initialConfig?.realtime,
282
+ includeDeleted: initialConfig?.includeDeleted ?? false
277
283
  });
278
- }, [setConfig, defaultColumns]),
284
+ }, [
285
+ setConfig,
286
+ defaultColumns,
287
+ initialConfig
288
+ ]),
279
289
  hasChanges: useMemo(() => {
280
- return config.filters.length > 0 || config.sortConfig !== null || (config.groupBy ?? null) !== (initialConfig?.groupBy ?? null) || (config.collapsedGroups?.length ?? 0) > 0 || config.realtime !== initialConfig?.realtime || (config.includeDeleted ?? false) !== (initialConfig?.includeDeleted ?? false) || config.pagination?.page !== 1 || config.pagination?.pageSize !== 25 || JSON.stringify([...config.visibleColumns].sort()) !== JSON.stringify([...defaultColumns].sort());
290
+ return !filtersEqual(config.filters, initialConfig?.filters ?? []) || !sortConfigEqual(config.sortConfig ?? null, initialConfig?.sortConfig ?? null) || (config.groupBy ?? null) !== (initialConfig?.groupBy ?? null) || (config.collapsedGroups?.length ?? 0) > 0 || config.realtime !== initialConfig?.realtime || (config.includeDeleted ?? false) !== (initialConfig?.includeDeleted ?? false) || config.pagination?.page !== 1 || config.pagination?.pageSize !== 25 || JSON.stringify([...config.visibleColumns].sort()) !== JSON.stringify([...defaultColumns].sort());
281
291
  }, [
282
292
  config,
283
293
  defaultColumns,
284
- initialConfig?.includeDeleted,
285
- initialConfig?.groupBy,
286
- initialConfig?.realtime
294
+ initialConfig
287
295
  ]),
288
296
  isLoading: false
289
297
  };
@@ -0,0 +1,30 @@
1
+ //#region src/client/lib/view-filter-utils.ts
2
+ function filterValueEqual(a, b) {
3
+ if (Array.isArray(a) || Array.isArray(b)) {
4
+ if (!Array.isArray(a) || !Array.isArray(b)) return false;
5
+ if (a.length !== b.length) return false;
6
+ return a.every((value, index) => value === b[index]);
7
+ }
8
+ return a === b;
9
+ }
10
+ function filtersEqual(a = [], b = []) {
11
+ if (a.length !== b.length) return false;
12
+ return a.every((filter, index) => {
13
+ const other = b[index];
14
+ return filter.id === other.id && filter.field === other.field && filter.operator === other.operator && filterValueEqual(filter.value, other.value);
15
+ });
16
+ }
17
+ function cloneFilters(filters) {
18
+ return filters.map((filter) => ({
19
+ ...filter,
20
+ value: Array.isArray(filter.value) ? [...filter.value] : filter.value
21
+ }));
22
+ }
23
+ function sortConfigEqual(a, b) {
24
+ if (a === b) return true;
25
+ if (!a || !b) return false;
26
+ return a.field === b.field && a.direction === b.direction;
27
+ }
28
+
29
+ //#endregion
30
+ export { cloneFilters, filtersEqual, sortConfigEqual };
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import * as react_jsx_runtime20 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime21 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_runtime20.JSX.Element;
38
+ }: BlockScopeProviderProps): react_jsx_runtime21.JSX.Element;
39
39
  /**
40
40
  * Get current block scope context.
41
41
  *
@@ -1,4 +1,4 @@
1
- import * as react_jsx_runtime21 from "react/jsx-runtime";
1
+ import * as react_jsx_runtime22 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_runtime21.JSX.Element | null;
43
+ }: PreviewBannerProps): react_jsx_runtime22.JSX.Element | null;
44
44
  //#endregion
45
45
  export { PreviewBanner, PreviewBannerProps };
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import * as react_jsx_runtime22 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime23 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/client/preview/preview-field.d.ts
5
5
 
@@ -68,7 +68,7 @@ declare function PreviewProvider({
68
68
  }) => void;
69
69
  onFieldValueEdited?: (payload: PreviewFieldValueEditedPayload) => void;
70
70
  children: React.ReactNode;
71
- }): react_jsx_runtime22.JSX.Element;
71
+ }): react_jsx_runtime23.JSX.Element;
72
72
  /**
73
73
  * Hook to access preview context.
74
74
  */
@@ -107,7 +107,7 @@ declare function PreviewField({
107
107
  style,
108
108
  onClick,
109
109
  onValueCommit
110
- }: PreviewFieldProps): react_jsx_runtime22.JSX.Element;
110
+ }: PreviewFieldProps): react_jsx_runtime23.JSX.Element;
111
111
  /**
112
112
  * Standalone PreviewField that works without context.
113
113
  * Useful when you can't use PreviewProvider.
@@ -131,6 +131,6 @@ declare function StandalonePreviewField({
131
131
  blockId?: string;
132
132
  fieldType?: "regular" | "block" | "relation";
133
133
  }) => void;
134
- }): react_jsx_runtime22.JSX.Element;
134
+ }): react_jsx_runtime23.JSX.Element;
135
135
  //#endregion
136
136
  export { PreviewField, PreviewFieldProps, PreviewProvider, StandalonePreviewField, usePreviewContext };