@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
@@ -34,12 +34,11 @@ function stableGroupKey(value) {
34
34
  if (typeof value === "object") return getId(value) ?? JSON.stringify(value);
35
35
  return String(value);
36
36
  }
37
- function shouldExpand(key, depth, outline, collapsedKeys) {
38
- if (collapsedKeys.has(key)) return false;
37
+ function shouldExpand(key, depth, outline, toggledKeys) {
39
38
  const defaultExpanded = outline?.defaultExpanded ?? true;
40
- if (defaultExpanded === true) return true;
41
- if (defaultExpanded === false) return false;
42
- return depth === 0;
39
+ const defaultValue = defaultExpanded === true ? true : defaultExpanded === false ? false : depth === 0;
40
+ if (toggledKeys.has(key)) return !defaultValue;
41
+ return defaultValue;
43
42
  }
44
43
  function compareByOrder(a, b, order) {
45
44
  if (Array.isArray(order)) {
@@ -86,7 +85,8 @@ function buildFieldRows(level, docs, depth, levelIndex, ctx, scopeKey) {
86
85
  }
87
86
  return Array.from(groups.values()).sort((a, b) => compareByOrder(a, b, level.order)).flatMap((group) => {
88
87
  const rowKey = `${scopeKey}/field:${level.field}:${group.key}`;
89
- const expanded = shouldExpand(rowKey, depth, ctx.outline, ctx.collapsedKeys);
88
+ const expanded = shouldExpand(rowKey, depth, ctx.outline, ctx.toggledKeys);
89
+ const meta = ctx.metaForValue(group.value, level.field);
90
90
  return [{
91
91
  kind: "group",
92
92
  key: rowKey,
@@ -94,7 +94,9 @@ function buildFieldRows(level, docs, depth, levelIndex, ctx, scopeKey) {
94
94
  depth,
95
95
  count: group.docs.length,
96
96
  expandable: true,
97
- collapsed: !expanded
97
+ collapsed: !expanded,
98
+ ...meta?.icon != null && { icon: meta.icon },
99
+ ...meta?.className && { className: meta.className }
98
100
  }, ...expanded ? buildLevelRows(group.docs, depth + 1, levelIndex + 1, ctx, rowKey) : []];
99
101
  });
100
102
  }
@@ -118,7 +120,7 @@ function buildRelationFieldRows(level, docs, depth, levelIndex, ctx, scopeKey) {
118
120
  }
119
121
  return Array.from(groups.values()).sort((a, b) => compareByOrder(a, b, level.order)).flatMap((group) => {
120
122
  const rowKey = `${scopeKey}/relation-field:${fieldPath}:${group.key}`;
121
- const expanded = shouldExpand(rowKey, depth, ctx.outline, ctx.collapsedKeys);
123
+ const expanded = shouldExpand(rowKey, depth, ctx.outline, ctx.toggledKeys);
122
124
  return [{
123
125
  kind: "group",
124
126
  key: rowKey,
@@ -151,7 +153,22 @@ function buildEdgeRows(level, docs, depth, levelIndex, ctx, scopeKey) {
151
153
  const childId = getId(childValue);
152
154
  if (!parentId || !childId || !docsById.has(childId)) continue;
153
155
  if (docsById.has(parentId) || !isRecord(parentValue)) continue;
154
- docsById.set(parentId, parentValue);
156
+ docsById.set(parentId, ctx.allDocsById?.get(parentId) ?? parentValue);
157
+ changed = true;
158
+ }
159
+ if (!changed) break;
160
+ }
161
+ if (ctx.allDocsById) for (let pass = 0; pass < ctx.maxDepth; pass++) {
162
+ let changed = false;
163
+ for (const edge of edgeDocs) {
164
+ const parentId = getId(getPathValue(edge, level.parentField));
165
+ const childId = getId(getPathValue(edge, level.childField));
166
+ if (!parentId || !childId) continue;
167
+ if (!docsById.has(parentId)) continue;
168
+ if (docsById.has(childId)) continue;
169
+ const childDoc = ctx.allDocsById.get(childId);
170
+ if (!childDoc) continue;
171
+ docsById.set(childId, childDoc);
155
172
  changed = true;
156
173
  }
157
174
  if (!changed) break;
@@ -201,7 +218,7 @@ function buildEdgeRows(level, docs, depth, levelIndex, ctx, scopeKey) {
201
218
  }
202
219
  for (const [key, group] of groups) {
203
220
  const rowKey = `${scopeKey}/edge-group:${level.collection}:${parentId}:${key}`;
204
- const expanded = shouldExpand(rowKey, nextDepth, ctx.outline, ctx.collapsedKeys);
221
+ const expanded = shouldExpand(rowKey, nextDepth, ctx.outline, ctx.toggledKeys);
205
222
  rows.push({
206
223
  kind: "group",
207
224
  key: rowKey,
@@ -223,18 +240,15 @@ function buildEdgeRows(level, docs, depth, levelIndex, ctx, scopeKey) {
223
240
  if (!doc || ancestorIds.has(id)) return;
224
241
  const rowKey = `${scopeKey}/record:${id}`;
225
242
  const hasChildren = (childrenByParent.get(id) ?? []).some((child) => docsById.has(child.childId));
226
- const expanded = hasChildren && shouldExpand(rowKey, rowDepth, ctx.outline, ctx.collapsedKeys);
227
243
  rows.push({
228
244
  kind: "record",
229
245
  key: rowKey,
230
246
  id,
231
247
  doc,
232
- depth: rowDepth,
233
- expandable: hasChildren,
234
- collapsed: hasChildren ? !expanded : void 0
248
+ depth: rowDepth
235
249
  });
236
250
  visited.add(id);
237
- if (hasChildren && expanded) {
251
+ if (hasChildren) {
238
252
  const nextAncestors = new Set(ancestorIds);
239
253
  nextAncestors.add(id);
240
254
  pushChildRows(id, rowDepth + 1, branchDepth, nextAncestors);
@@ -297,7 +311,7 @@ function buildPathRows(level, docs, depth, levelIndex, ctx, scopeKey) {
297
311
  function walk(node, rowDepth) {
298
312
  const rows = [];
299
313
  for (const child of Array.from(node.children.values()).sort((a, b) => a.label.localeCompare(b.label))) {
300
- const expanded = shouldExpand(child.key, rowDepth, ctx.outline, ctx.collapsedKeys);
314
+ const expanded = shouldExpand(child.key, rowDepth, ctx.outline, ctx.toggledKeys);
301
315
  rows.push({
302
316
  kind: "synthetic",
303
317
  key: child.key,
@@ -342,15 +356,26 @@ function buildLevelRows(docs, depth, levelIndex, ctx, scopeKey = "root") {
342
356
  if (level.kind === "edge") return buildEdgeRows(level, docs, depth, levelIndex, ctx, scopeKey);
343
357
  return buildPathRows(level, docs, depth, levelIndex, ctx, scopeKey);
344
358
  }
345
- function buildOutlineRows({ docs, outline, edgesByCollection = {}, collapsedKeys, labelForValue = defaultLabelForValue, maxDepth }) {
359
+ const noMeta = () => void 0;
360
+ function buildOutlineRows({ docs, outline, edgesByCollection = {}, toggledKeys, collapsedKeys, labelForValue = defaultLabelForValue, metaForValue = noMeta, maxDepth, allDocs }) {
346
361
  const levels = outline?.levels?.filter(Boolean) ?? [];
362
+ let allDocsById;
363
+ if (allDocs && allDocs.length > 0) {
364
+ allDocsById = /* @__PURE__ */ new Map();
365
+ for (const doc of allDocs) {
366
+ const id = getId(doc);
367
+ if (id) allDocsById.set(id, doc);
368
+ }
369
+ }
347
370
  const ctx = {
348
371
  levels,
349
372
  outline,
350
373
  edgesByCollection,
351
- collapsedKeys: new Set(collapsedKeys ?? []),
374
+ toggledKeys: new Set(toggledKeys ?? collapsedKeys ?? []),
352
375
  labelForValue,
353
- maxDepth: maxDepth ?? outline?.maxDepth ?? DEFAULT_MAX_DEPTH
376
+ metaForValue,
377
+ maxDepth: maxDepth ?? outline?.maxDepth ?? DEFAULT_MAX_DEPTH,
378
+ allDocsById
354
379
  };
355
380
  if (levels.length === 0) return buildLevelRows(docs, 0, 0, {
356
381
  ...ctx,
@@ -0,0 +1,45 @@
1
+ "use client";
2
+
3
+ import { useResolveText } from "../../i18n/hooks.mjs";
4
+ import { cn } from "../../lib/utils.mjs";
5
+ import { ComponentRenderer } from "../../components/component-renderer.mjs";
6
+ import { Button } from "../../components/ui/button.mjs";
7
+ import { Tooltip, TooltipContent, TooltipTrigger } from "../../components/ui/tooltip.mjs";
8
+ import { cloneFilters, filtersEqual } from "../../lib/view-filter-utils.mjs";
9
+ import "react";
10
+ import { jsx, jsxs } from "react/jsx-runtime";
11
+
12
+ //#region src/client/views/collection/quick-filter-bar.tsx
13
+ function QuickFilterBar({ quickFilters, currentFilters, onApply }) {
14
+ const resolveText = useResolveText();
15
+ const visibleFilters = quickFilters?.filter((filter) => filter.filters) ?? [];
16
+ if (visibleFilters.length === 0) return null;
17
+ return /* @__PURE__ */ jsx("div", {
18
+ className: "flex min-w-0 flex-wrap items-center gap-2",
19
+ children: visibleFilters.map((filter) => {
20
+ const active = filtersEqual(currentFilters, filter.filters);
21
+ const label = resolveText(filter.label, filter.id);
22
+ const description = resolveText(filter.description);
23
+ const button = /* @__PURE__ */ jsxs(Button, {
24
+ variant: active ? "secondary" : "outline",
25
+ size: "sm",
26
+ className: cn("gap-1.5 text-xs", active && "border-border-strong bg-muted text-foreground"),
27
+ "aria-pressed": active,
28
+ onClick: () => onApply(cloneFilters(filter.filters)),
29
+ children: [/* @__PURE__ */ jsx(ComponentRenderer, {
30
+ reference: filter.icon,
31
+ additionalProps: { className: "size-4 shrink-0" }
32
+ }), /* @__PURE__ */ jsx("span", { children: label })]
33
+ }, filter.id);
34
+ if (!description) return button;
35
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, { render: button }), /* @__PURE__ */ jsx(TooltipContent, {
36
+ side: "bottom",
37
+ align: "start",
38
+ children: description
39
+ })] }, filter.id);
40
+ })
41
+ });
42
+ }
43
+
44
+ //#endregion
45
+ export { QuickFilterBar };
@@ -3,6 +3,7 @@ import { cn } from "../../lib/utils.mjs";
3
3
  import { selectRealtime, useAdminStore } from "../../runtime/provider.mjs";
4
4
  import { useSafeContentLocales } from "../../runtime/content-locales-provider.mjs";
5
5
  import { useScopedLocale } from "../../runtime/locale-scope.mjs";
6
+ import { resolveIconElement } from "../../components/component-renderer.mjs";
6
7
  import { flattenOptions } from "../../components/primitives/types.mjs";
7
8
  import { resolveOptionLabelForValue } from "../../components/primitives/option-label.mjs";
8
9
  import { Button } from "../../components/ui/button.mjs";
@@ -14,6 +15,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "../../components/ui/too
14
15
  import { Checkbox } from "../../components/ui/checkbox.mjs";
15
16
  import { createActionRegistryProxy } from "../../builder/types/action-registry.mjs";
16
17
  import { ActionButton } from "../../components/actions/action-button.mjs";
18
+ import { adminCollectionKey } from "../../hooks/query-access.mjs";
17
19
  import { useCollectionFields } from "../../hooks/use-collection-fields.mjs";
18
20
  import { useSuspenseCollectionMeta } from "../../hooks/use-collection-meta.mjs";
19
21
  import { ActionDialog } from "../../components/actions/action-dialog.mjs";
@@ -44,6 +46,7 @@ import { useRealtimeHighlight } from "../../hooks/use-realtime-highlight.mjs";
44
46
  import { useDeleteSavedView, useSaveView, useSavedViews } from "../../hooks/use-saved-views.mjs";
45
47
  import { useViewState } from "../../hooks/use-view-state.mjs";
46
48
  import { BulkActionToolbar } from "./bulk-action-toolbar.mjs";
49
+ import { QuickFilterBar } from "./quick-filter-bar.mjs";
47
50
  import { Icon } from "@iconify/react";
48
51
  import * as React from "react";
49
52
  import { Suspense, useMemo, useState } from "react";
@@ -258,6 +261,8 @@ function mapListSchemaToConfig(list) {
258
261
  const config = {};
259
262
  if (list.columns?.length) config.columns = list.columns;
260
263
  if (list.defaultSort) config.defaultSort = list.defaultSort;
264
+ if (list.defaultFilters?.length) config.defaultFilters = list.defaultFilters;
265
+ if (list.quickFilters?.length) config.quickFilters = list.quickFilters;
261
266
  if (list.orderable) config.orderable = list.orderable;
262
267
  if (Array.isArray(list.searchable) && list.searchable.length) {
263
268
  config.searchFields = list.searchable;
@@ -398,6 +403,7 @@ function TableView(props) {
398
403
  */
399
404
  function TableViewInner({ collection, config, viewConfig, navigate, basePath = "/admin", showSearch = true, showFilters = true, showToolbar = true, realtime, headerActions, emptyState, actionsConfig }) {
400
405
  "use no memo";
406
+ const collectionKey = adminCollectionKey(collection);
401
407
  const globalRealtimeConfig = useAdminStore(selectRealtime);
402
408
  const { fields: resolvedFields, schema } = useCollectionFields(collection, { fallbackFields: config?.fields });
403
409
  const { collections: uploadCollections } = useUploadCollection();
@@ -475,10 +481,16 @@ function TableViewInner({ collection, config, viewConfig, navigate, basePath = "
475
481
  const orderField = "order";
476
482
  const orderDirection = typeof orderableConfig === "object" ? orderableConfig.direction ?? "asc" : "asc";
477
483
  const orderStep = typeof orderableConfig === "object" ? orderableConfig.step ?? 10 : 10;
478
- const viewState = useViewState(defaultColumns, {
484
+ const defaultFilters = useMemo(() => resolvedListConfig?.defaultFilters ?? [], [resolvedListConfig?.defaultFilters]);
485
+ const viewState = useViewState(defaultColumns, useMemo(() => ({
479
486
  realtime: resolvedRealtime,
480
- groupBy: defaultGroupBy
481
- }, collection, user?.id);
487
+ groupBy: defaultGroupBy,
488
+ filters: defaultFilters
489
+ }), [
490
+ resolvedRealtime,
491
+ defaultGroupBy,
492
+ defaultFilters
493
+ ]), collection, user?.id);
482
494
  const effectiveRealtime = viewState.config.realtime ?? resolvedRealtime;
483
495
  const visibleColumnsForExpansion = viewState.config.visibleColumns.length > 0 ? viewState.config.visibleColumns : defaultColumns;
484
496
  const expandedFields = useMemo(() => autoExpandFields({
@@ -492,7 +504,7 @@ function TableViewInner({ collection, config, viewConfig, navigate, basePath = "
492
504
  visibleColumnsForExpansion,
493
505
  collectionMeta?.relations
494
506
  ]);
495
- const isKnownSortField = React.useCallback((field) => !!field && (field === "_title" || !!resolvedFields?.[field]), [resolvedFields]);
507
+ const isKnownSortField = React.useCallback((field) => !!field && (field === "_title" || field === "createdAt" || field === "updatedAt" || !!resolvedFields?.[field]), [resolvedFields]);
496
508
  const hasOrderField = isKnownSortField(orderField);
497
509
  const canUseOrderableSort = isOrderableEnabled && hasOrderField;
498
510
  const effectiveSort = useMemo(() => {
@@ -666,15 +678,15 @@ function TableViewInner({ collection, config, viewConfig, navigate, basePath = "
666
678
  limit: 100,
667
679
  highlights: true
668
680
  }, { enabled: isSearching });
669
- const { data: listData, isLoading: listLoading, error: listError } = useCollectionList(collection, queryOptions, { enabled: !isSearching }, { realtime: effectiveRealtime });
681
+ const { data: listData, isLoading: listLoading, error: listError } = useCollectionList(collectionKey, queryOptions, { enabled: !isSearching }, { realtime: effectiveRealtime });
670
682
  const isLoading = isSearching ? searchLoading : listLoading;
671
683
  const isSearchActive = isSearching && searchFetching;
672
684
  const { data: savedViewsData, isLoading: savedViewsLoading } = useSavedViews(collection, user?.id);
673
685
  const saveViewMutation = useSaveView(collection, user?.id);
674
686
  const deleteViewMutation = useDeleteSavedView(collection, user?.id);
675
- const deleteMutation = useCollectionDelete(collection);
676
- const restoreMutation = useCollectionRestore(collection);
677
- const updateBatchMutation = useCollectionUpdateBatch(collection);
687
+ const deleteMutation = useCollectionDelete(collectionKey);
688
+ const restoreMutation = useCollectionRestore(collectionKey);
689
+ const updateBatchMutation = useCollectionUpdateBatch(collectionKey);
678
690
  const availableFields = useMemo(() => {
679
691
  return getAllAvailableFields(resolvedFields, { meta: collectionMeta });
680
692
  }, [resolvedFields, collectionMeta]);
@@ -875,13 +887,23 @@ function TableViewInner({ collection, config, viewConfig, navigate, basePath = "
875
887
  orderDirection,
876
888
  viewState
877
889
  ]);
878
- const hasViewOptionsState = hasActiveFilters || !!viewState.config.groupBy || viewState.config.visibleColumns.length !== defaultColumns.length || !!viewState.config.includeDeleted;
890
+ const hasViewOptionsState = hasActiveFilters || !!viewState.config.sortConfig || !!viewState.config.groupBy || viewState.config.visibleColumns.length !== defaultColumns.length || !!viewState.config.includeDeleted;
879
891
  const clearFilters = () => {
880
892
  viewState.setConfig({
881
893
  ...viewState.config,
882
894
  filters: []
883
895
  });
884
896
  };
897
+ const applyQuickFilters = React.useCallback((filters) => {
898
+ viewState.setConfig((current) => ({
899
+ ...current,
900
+ filters,
901
+ pagination: {
902
+ ...current.pagination ?? { pageSize: 25 },
903
+ page: 1
904
+ }
905
+ }));
906
+ }, [viewState]);
885
907
  const exitReorderMode = React.useCallback(() => {
886
908
  setOptimisticOrderIds(null);
887
909
  setIsReorderMode(false);
@@ -992,6 +1014,14 @@ function TableViewInner({ collection, config, viewConfig, navigate, basePath = "
992
1014
  const groupField = groupableFields.find((field) => field.name === groupBy);
993
1015
  const collapsedGroups = new Set(viewState.config.collapsedGroups ?? []);
994
1016
  const serverGroups = !isSearching ? listData?.groups : void 0;
1017
+ const iconForValue = (value) => {
1018
+ if (groupField?.type !== "select") return null;
1019
+ const options = groupField.options?.options;
1020
+ if (!Array.isArray(options)) return null;
1021
+ const option = flattenOptions(options).find((opt) => String(opt.value) === String(value));
1022
+ if (!option?.icon) return null;
1023
+ return resolveIconElement(option.icon);
1024
+ };
995
1025
  if (serverGroups?.length) {
996
1026
  const rowsById = new Map(rows.map((row) => [row.id, row]));
997
1027
  return serverGroups.flatMap((group) => {
@@ -1003,6 +1033,7 @@ function TableViewInner({ collection, config, viewConfig, navigate, basePath = "
1003
1033
  type: "group",
1004
1034
  key: groupKey,
1005
1035
  label,
1036
+ icon: iconForValue(group.value),
1006
1037
  count: group.count,
1007
1038
  collapsed
1008
1039
  }, ...collapsed ? [] : groupRows.map((row) => ({
@@ -1013,7 +1044,8 @@ function TableViewInner({ collection, config, viewConfig, navigate, basePath = "
1013
1044
  }
1014
1045
  const groups = /* @__PURE__ */ new Map();
1015
1046
  for (const row of rows) {
1016
- const valueLabel = stringifyGroupValue(row.original?.[groupBy], groupField, resolveText, t, uiLocale, t("common.noValue"));
1047
+ const rawValue = row.original?.[groupBy];
1048
+ const valueLabel = stringifyGroupValue(rawValue, groupField, resolveText, t, uiLocale, t("common.noValue"));
1017
1049
  const groupKey = `${groupBy}:${valueLabel}`;
1018
1050
  const group = groups.get(groupKey);
1019
1051
  if (group) {
@@ -1022,8 +1054,9 @@ function TableViewInner({ collection, config, viewConfig, navigate, basePath = "
1022
1054
  }
1023
1055
  groups.set(groupKey, {
1024
1056
  label: valueLabel,
1057
+ value: rawValue,
1025
1058
  rows: [row],
1026
- sortIndex: getGroupSortIndex(row.original?.[groupBy], groupField)
1059
+ sortIndex: getGroupSortIndex(rawValue, groupField)
1027
1060
  });
1028
1061
  }
1029
1062
  return Array.from(groups.entries()).sort(([, a], [, b]) => a.sortIndex - b.sortIndex).flatMap(([key, group]) => {
@@ -1032,6 +1065,7 @@ function TableViewInner({ collection, config, viewConfig, navigate, basePath = "
1032
1065
  type: "group",
1033
1066
  key,
1034
1067
  label: group.label,
1068
+ icon: iconForValue(group.value),
1035
1069
  count: group.rows.length,
1036
1070
  collapsed
1037
1071
  }, ...collapsed ? [] : group.rows.map((row) => ({
@@ -1212,6 +1246,11 @@ function TableViewInner({ collection, config, viewConfig, navigate, basePath = "
1212
1246
  containerClassName: "h-10"
1213
1247
  })
1214
1248
  }),
1249
+ /* @__PURE__ */ jsx(QuickFilterBar, {
1250
+ quickFilters: resolvedListConfig?.quickFilters,
1251
+ currentFilters: viewState.config.filters,
1252
+ onApply: applyQuickFilters
1253
+ }),
1215
1254
  isReorderMode && canUseOrderableSort && /* @__PURE__ */ jsxs("div", {
1216
1255
  className: "border-border/70 bg-muted/30 text-muted-foreground flex min-h-10 items-center justify-between gap-3 border-y px-3 py-2 font-mono text-xs",
1217
1256
  children: [/* @__PURE__ */ jsxs("div", {
@@ -1320,16 +1359,20 @@ function TableViewInner({ collection, config, viewConfig, navigate, basePath = "
1320
1359
  children: /* @__PURE__ */ jsxs("button", {
1321
1360
  type: "button",
1322
1361
  "aria-expanded": !entry.collapsed,
1323
- className: "text-muted-foreground hover:text-foreground focus-visible:ring-ring/40 -ml-1 inline-flex min-h-8 items-center gap-2 rounded-md px-1 font-mono text-[11px] font-semibold tracking-[0.12em] uppercase transition-colors focus-visible:ring-2 focus-visible:outline-none",
1362
+ className: "text-muted-foreground hover:text-foreground focus-visible:ring-ring/40 -ml-1 inline-flex min-h-8 items-center gap-2 rounded-md px-1 text-xs font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none",
1324
1363
  onClick: () => viewState.toggleCollapsedGroup(entry.key),
1325
1364
  children: [
1326
1365
  /* @__PURE__ */ jsx(Icon, {
1327
- icon: entry.collapsed ? "ph:caret-right" : "ph:caret-down",
1328
- className: "size-3.5 shrink-0"
1366
+ icon: "ph:caret-right-bold",
1367
+ className: cn("size-3 shrink-0 transition-transform", !entry.collapsed && "rotate-90")
1368
+ }),
1369
+ entry.icon && /* @__PURE__ */ jsx("span", {
1370
+ className: "size-4 shrink-0",
1371
+ children: entry.icon
1329
1372
  }),
1330
1373
  /* @__PURE__ */ jsx("span", { children: entry.label }),
1331
1374
  groupingConfig?.showCounts !== false && /* @__PURE__ */ jsx("span", {
1332
- className: "bg-muted text-muted-foreground inline-flex h-5 min-w-5 items-center justify-center rounded-full px-1.5 text-[10px] tracking-normal tabular-nums",
1375
+ className: "text-muted-foreground/60 tabular-nums",
1333
1376
  children: entry.count
1334
1377
  })
1335
1378
  ]
@@ -1543,7 +1586,8 @@ function TableViewInner({ collection, config, viewConfig, navigate, basePath = "
1543
1586
  savedViewsLoading,
1544
1587
  onSaveView: handleSaveView,
1545
1588
  onDeleteView: handleDeleteView,
1546
- supportsSoftDelete: collectionMeta?.softDelete ?? false
1589
+ supportsSoftDelete: collectionMeta?.softDelete ?? false,
1590
+ defaultFilters
1547
1591
  }),
1548
1592
  dialogAction && /* @__PURE__ */ jsx(ActionDialog, {
1549
1593
  open: !!dialogAction,
@@ -12,13 +12,13 @@ import { Checkbox } from "../../components/ui/checkbox.mjs";
12
12
  import { DateTimeInput } from "../../components/primitives/date-input.mjs";
13
13
  import { ConfirmationDialog } from "../../components/actions/confirmation-dialog.mjs";
14
14
  import { useGlobalFields } from "../../hooks/use-global-fields.mjs";
15
+ import { ReactiveFieldStatesProvider, useReactiveFields } from "../../hooks/use-reactive-fields.mjs";
15
16
  import { AutoFormFields } from "../collection/auto-form-fields.mjs";
16
17
  import { EmptyState } from "../../components/ui/empty-state.mjs";
17
18
  import { HistorySidebar } from "../../components/history-sidebar.mjs";
18
19
  import { useGlobal, useGlobalRevertVersion, useGlobalUpdate, useGlobalVersions } from "../../hooks/use-global.mjs";
19
20
  import { useGlobalServerValidation } from "../../hooks/use-server-validation.mjs";
20
21
  import { useSidebarSearchParam } from "../../hooks/use-sidebar-search-param.mjs";
21
- import { useReactiveFields } from "../../hooks/use-reactive-fields.mjs";
22
22
  import { useTransitionStage } from "../../hooks/use-transition-stage.mjs";
23
23
  import { detectManyToManyRelations, hasManyToManyRelations } from "../../utils/detect-relations.mjs";
24
24
  import { shouldHandleAdminShortcut } from "../../utils/keyboard-shortcuts.mjs";
@@ -293,7 +293,7 @@ function GlobalFormView({ global: globalName, config, viewConfig, registry, show
293
293
  if (globalData) form.reset(globalData);
294
294
  }, [form, globalData]);
295
295
  const reactiveConfigs = React.useMemo(() => extractReactiveConfigs(globalSchema), [globalSchema]);
296
- useReactiveFields({
296
+ const { fieldStates: reactiveFieldStates } = useReactiveFields({
297
297
  collection: globalName,
298
298
  mode: "global",
299
299
  reactiveConfigs,
@@ -463,13 +463,16 @@ function GlobalFormView({ global: globalName, config, viewConfig, registry, show
463
463
  t
464
464
  })
465
465
  ] })
466
- }), /* @__PURE__ */ jsx(AutoFormFields, {
467
- collection: globalName,
468
- mode: "global",
469
- config: resolvedConfig,
470
- registry,
471
- resolvedFields: schemaFields,
472
- schema: globalSchema
466
+ }), /* @__PURE__ */ jsx(ReactiveFieldStatesProvider, {
467
+ fieldStates: reactiveFieldStates,
468
+ children: /* @__PURE__ */ jsx(AutoFormFields, {
469
+ collection: globalName,
470
+ mode: "global",
471
+ config: resolvedConfig,
472
+ registry,
473
+ resolvedFields: schemaFields,
474
+ schema: globalSchema
475
+ })
473
476
  })]
474
477
  }),
475
478
  isHistoryOpen && /* @__PURE__ */ jsx(HistorySidebar, {
@@ -163,7 +163,7 @@ function AdminLayout({ LinkComponent, activeRoute, basePath = "/admin", brandNam
163
163
  }),
164
164
  secondaryRailConfig?.placement !== "right" && secondaryRail,
165
165
  /* @__PURE__ */ jsxs(SidebarInset, {
166
- className: "qa-admin-layout__content bg-background flex h-svh flex-col overflow-hidden md:rounded-tl-2xl",
166
+ className: "qa-admin-layout__content bg-background flex h-svh scrollbar-none flex-col overflow-hidden md:rounded-t-2xl",
167
167
  children: [
168
168
  shouldShowHeader && header && /* @__PURE__ */ jsx("header", {
169
169
  className: "qa-admin-layout__header border-border-subtle border-b",
@@ -5,7 +5,7 @@ import { useSafeContentLocales } from "../../runtime/content-locales-provider.mj
5
5
  import { ComponentRenderer } from "../../components/component-renderer.mjs";
6
6
  import { Button } from "../../components/ui/button.mjs";
7
7
  import { getFlagUrl } from "../../utils/locale-to-flag.mjs";
8
- import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from "../../components/ui/dropdown-menu.mjs";
8
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from "../../components/ui/dropdown-menu.mjs";
9
9
  import { Tooltip, TooltipContent, TooltipTrigger } from "../../components/ui/tooltip.mjs";
10
10
  import { useAdminConfig } from "../../hooks/use-admin-config.mjs";
11
11
  import { useLazyComponent } from "../../utils/use-lazy-component.mjs";
@@ -440,6 +440,7 @@ function UserFooter({ theme = "system", setTheme, showThemeToggle }) {
440
440
  icon: "ph:monitor"
441
441
  }
442
442
  ], [t]);
443
+ const currentThemeOption = themeOptions.find((option) => option.value === theme) ?? themeOptions[2];
443
444
  const handleThemeChange = React.useCallback((value) => {
444
445
  setTheme?.(value);
445
446
  }, [setTheme]);
@@ -530,21 +531,26 @@ function UserFooter({ theme = "system", setTheme, showThemeToggle }) {
530
531
  className: "size-4"
531
532
  }), t("auth.myAccount")]
532
533
  }),
533
- shouldShowThemeToggle && /* @__PURE__ */ jsxs(Fragment, { children: [
534
- /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
535
- /* @__PURE__ */ jsx(DropdownMenuLabel, { children: t("ui.toggleTheme") }),
536
- /* @__PURE__ */ jsx(DropdownMenuRadioGroup, {
537
- value: theme,
538
- onValueChange: handleThemeChange,
539
- children: themeOptions.map((option) => /* @__PURE__ */ jsxs(DropdownMenuRadioItem, {
540
- value: option.value,
541
- children: [/* @__PURE__ */ jsx(Icon, {
534
+ shouldShowThemeToggle && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(DropdownMenuSeparator, {}), /* @__PURE__ */ jsxs(DropdownMenuSub, { children: [/* @__PURE__ */ jsxs(DropdownMenuSubTrigger, { children: [/* @__PURE__ */ jsx(Icon, { icon: currentThemeOption.icon }), t("ui.toggleTheme")] }), /* @__PURE__ */ jsx(DropdownMenuSubContent, {
535
+ className: "min-w-40",
536
+ children: themeOptions.map((option) => /* @__PURE__ */ jsxs(DropdownMenuItem, {
537
+ onClick: () => handleThemeChange(option.value),
538
+ children: [
539
+ /* @__PURE__ */ jsx(Icon, {
542
540
  icon: option.icon,
543
541
  className: "size-4"
544
- }), /* @__PURE__ */ jsx("span", { children: option.label })]
545
- }, option.value))
546
- })
547
- ] }),
542
+ }),
543
+ /* @__PURE__ */ jsx("span", {
544
+ className: "flex-1",
545
+ children: option.label
546
+ }),
547
+ option.value === theme && /* @__PURE__ */ jsx(Icon, {
548
+ icon: "ph:check",
549
+ className: "text-foreground size-4"
550
+ })
551
+ ]
552
+ }, option.value))
553
+ })] })] }),
548
554
  hasMultipleUiLocales && /* @__PURE__ */ jsxs(DropdownMenuSub, { children: [/* @__PURE__ */ jsxs(DropdownMenuSubTrigger, { children: [/* @__PURE__ */ jsx(Icon, { icon: "ph:globe" }), t("locale.uiLanguage")] }), /* @__PURE__ */ jsx(DropdownMenuSubContent, { children: uiLocaleOptions.map((locale) => /* @__PURE__ */ jsxs(DropdownMenuItem, {
549
555
  onClick: () => setUiLocale(locale.code),
550
556
  children: [
@@ -10,10 +10,11 @@ function getStoredAdminTheme() {
10
10
  }
11
11
  function useManagedAdminTheme(controlledTheme, controlledSetTheme, options = {}) {
12
12
  const enabled = options.enabled ?? true;
13
- const [uncontrolledTheme, setUncontrolledTheme] = React.useState(getStoredAdminTheme);
14
- const theme = controlledTheme ?? uncontrolledTheme;
13
+ const isControlled = controlledTheme !== void 0 && controlledSetTheme !== void 0;
14
+ const [uncontrolledTheme, setUncontrolledTheme] = React.useState(() => controlledTheme ?? getStoredAdminTheme());
15
+ const theme = isControlled ? controlledTheme : uncontrolledTheme;
15
16
  const setTheme = React.useCallback((next) => {
16
- if (controlledSetTheme) {
17
+ if (isControlled) {
17
18
  controlledSetTheme(next);
18
19
  return;
19
20
  }
@@ -21,7 +22,7 @@ function useManagedAdminTheme(controlledTheme, controlledSetTheme, options = {})
21
22
  try {
22
23
  window.localStorage.setItem(ADMIN_THEME_STORAGE_KEY, next);
23
24
  } catch {}
24
- }, [controlledSetTheme]);
25
+ }, [controlledSetTheme, isControlled]);
25
26
  React.useEffect(() => {
26
27
  if (!enabled) return;
27
28
  const root = document.documentElement;
package/dist/client.mjs CHANGED
@@ -9,6 +9,7 @@ import { EMPTY_BLOCK_CONTENT, isBlockContent } from "./client/blocks/types.mjs";
9
9
  import { FocusProvider, parsePreviewFieldPath, scrollFieldIntoView, useFocus, useFocusOptional, useIsBlockFocused, useIsFieldFocused } from "./client/contexts/focus-context.mjs";
10
10
  import { useIsDesktop, useIsMobile, useMediaQuery } from "./client/hooks/use-media-query.mjs";
11
11
  import { buildValidationSchema, buildZodFromIntrospection, createFormSchema } from "./client/builder/validation.mjs";
12
+ import { useReactiveFields } from "./client/hooks/use-reactive-fields.mjs";
12
13
  import { isAdminToPreviewMessage, isPreviewToAdminMessage } from "./client/preview/types.mjs";
13
14
  import { useGlobal, useGlobalRevertVersion, useGlobalUpdate, useGlobalVersions } from "./client/hooks/use-global.mjs";
14
15
  import { useSearchParamToggle } from "./client/hooks/use-search-param-toggle.mjs";
@@ -16,7 +17,6 @@ import { useSidebarSearchParam } from "./client/hooks/use-sidebar-search-param.m
16
17
  import { useCollectionCreate, useCollectionDelete, useCollectionItem, useCollectionList, useCollectionRestore, useCollectionRevertVersion, useCollectionUpdate, useCollectionVersions } from "./client/hooks/use-collection.mjs";
17
18
  import { createAdminAuthClient, useAuthClient } from "./client/hooks/use-auth.mjs";
18
19
  import { useCurrentUser } from "./client/hooks/use-current-user.mjs";
19
- import { useReactiveFields } from "./client/hooks/use-reactive-fields.mjs";
20
20
  import { AdminLink } from "./client/components/admin-link.mjs";
21
21
  import { page } from "./client/builder/page/page.mjs";
22
22
  import { widget } from "./client/builder/widget/widget.mjs";
@@ -1,4 +1,4 @@
1
- import * as react_jsx_runtime19 from "react/jsx-runtime";
1
+ import * as react_jsx_runtime20 from "react/jsx-runtime";
2
2
 
3
3
  //#region src/components/rich-text/rich-text-renderer.d.ts
4
4
  /**
@@ -10,9 +10,9 @@ type TipTapNode = {
10
10
  text?: string;
11
11
  marks?: Array<{
12
12
  type: string;
13
- attrs?: Record<string, any>;
13
+ attrs?: Record<string, unknown>;
14
14
  }>;
15
- attrs?: Record<string, any>;
15
+ attrs?: Record<string, unknown>;
16
16
  };
17
17
  type TipTapDoc = {
18
18
  type: "doc";
@@ -53,7 +53,7 @@ interface RichTextRendererProps {
53
53
  /**
54
54
  * TipTap JSON content to render
55
55
  */
56
- content: TipTapDoc | null | undefined;
56
+ content: unknown;
57
57
  /**
58
58
  * Custom styles for elements
59
59
  */
@@ -98,6 +98,6 @@ declare function RichTextRenderer({
98
98
  content,
99
99
  styles: customStyles,
100
100
  className
101
- }: RichTextRendererProps): react_jsx_runtime19.JSX.Element | null;
101
+ }: RichTextRendererProps): react_jsx_runtime20.JSX.Element | null;
102
102
  //#endregion
103
103
  export { RichTextRenderer, RichTextStyles, TipTapDoc, TipTapNode };
@@ -30,6 +30,9 @@ const defaultStyles = {
30
30
  strike: "line-through",
31
31
  underline: "underline"
32
32
  };
33
+ function isRenderableTipTapDoc(content) {
34
+ return !!content && typeof content === "object" && content.type === "doc" && Array.isArray(content.content);
35
+ }
33
36
  /**
34
37
  * Renders a single TipTap node
35
38
  */
@@ -85,7 +88,7 @@ function renderNode(node, index, styles) {
85
88
  }
86
89
  return textNode;
87
90
  }
88
- const nodeKey = `${node.type}-${node.text?.slice(0, 20) ?? ""}-${index}`;
91
+ const nodeKey = `${node.type}-${index}`;
89
92
  const children = node.content?.map((child, i) => renderNode(child, i, styles));
90
93
  switch (node.type) {
91
94
  case "doc": return /* @__PURE__ */ jsx("div", { children }, nodeKey);
@@ -198,7 +201,7 @@ function renderNode(node, index, styles) {
198
201
  * ```
199
202
  */
200
203
  function RichTextRenderer({ content, styles: customStyles, className }) {
201
- if (!content || !content.content || content.content.length === 0) return null;
204
+ if (!isRenderableTipTapDoc(content) || content.content.length === 0) return null;
202
205
  const styles = {
203
206
  ...defaultStyles,
204
207
  ...customStyles
package/dist/index.mjs CHANGED
@@ -9,6 +9,7 @@ import { EMPTY_BLOCK_CONTENT, isBlockContent } from "./client/blocks/types.mjs";
9
9
  import { FocusProvider, parsePreviewFieldPath, scrollFieldIntoView, useFocus, useFocusOptional, useIsBlockFocused, useIsFieldFocused } from "./client/contexts/focus-context.mjs";
10
10
  import { useIsDesktop, useIsMobile, useMediaQuery } from "./client/hooks/use-media-query.mjs";
11
11
  import { buildValidationSchema, buildZodFromIntrospection, createFormSchema } from "./client/builder/validation.mjs";
12
+ import { useReactiveFields } from "./client/hooks/use-reactive-fields.mjs";
12
13
  import { isAdminToPreviewMessage, isPreviewToAdminMessage } from "./client/preview/types.mjs";
13
14
  import { useGlobal, useGlobalRevertVersion, useGlobalUpdate, useGlobalVersions } from "./client/hooks/use-global.mjs";
14
15
  import { useSearchParamToggle } from "./client/hooks/use-search-param-toggle.mjs";
@@ -16,7 +17,6 @@ import { useSidebarSearchParam } from "./client/hooks/use-sidebar-search-param.m
16
17
  import { useCollectionCreate, useCollectionDelete, useCollectionItem, useCollectionList, useCollectionRestore, useCollectionRevertVersion, useCollectionUpdate, useCollectionVersions } from "./client/hooks/use-collection.mjs";
17
18
  import { createAdminAuthClient, useAuthClient } from "./client/hooks/use-auth.mjs";
18
19
  import { useCurrentUser } from "./client/hooks/use-current-user.mjs";
19
- import { useReactiveFields } from "./client/hooks/use-reactive-fields.mjs";
20
20
  import { AdminLink } from "./client/components/admin-link.mjs";
21
21
  import { page } from "./client/builder/page/page.mjs";
22
22
  import { widget } from "./client/builder/widget/widget.mjs";
@@ -1,10 +1,10 @@
1
+ import { FilterOperator, FilterRule, SortConfig, ViewConfiguration } from "../shared/types/saved-views.types.mjs";
1
2
  import { ExecuteActionRequest, ExecuteActionResponse, actionFunctions, executeAction, executeActionFn, getActionsConfig, getActionsConfigFn } from "../server/modules/admin/routes/execute-action.mjs";
2
3
  import { PreviewTokenPayload, createPreviewFunctions, createPreviewTokenVerifier, verifyPreviewTokenDirect } from "../server/modules/admin/routes/preview.mjs";
3
4
  import { batchReactive, fieldOptions, reactiveFunctions } from "../server/modules/admin/routes/reactive.mjs";
4
5
  import { createFirstAdmin, isSetupRequired, setupFunctions } from "../server/modules/admin/routes/setup.mjs";
5
6
  import { fetchWidgetData, widgetDataFunctions } from "../server/modules/admin/routes/widget-data.mjs";
6
7
  import { AdminCollections } from "../server/modules/admin/.generated/module.mjs";
7
- import { FilterOperator, FilterRule, SortConfig, ViewConfiguration } from "../shared/types/saved-views.types.mjs";
8
8
  import { savedViewsCollection } from "../server/modules/admin-preferences/collections/saved-views.mjs";
9
9
  import { AdminModule, adminModule, adminRoutes } from "../server/modules/admin/index.mjs";
10
10
  export { type AdminCollections, type AdminModule, type ExecuteActionRequest, type ExecuteActionResponse, type FilterOperator, type FilterRule, type PreviewTokenPayload, type SortConfig, type ViewConfiguration, actionFunctions, adminModule, adminRoutes, batchReactive, createFirstAdmin, createPreviewFunctions, createPreviewTokenVerifier, executeAction, executeActionFn, fetchWidgetData, fieldOptions, getActionsConfig, getActionsConfigFn, isSetupRequired, reactiveFunctions, savedViewsCollection, setupFunctions, verifyPreviewTokenDirect, widgetDataFunctions };