@questpie/admin 3.5.1 → 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 (94) hide show
  1. package/dist/client/builder/types/collection-types.d.mts +9 -0
  2. package/dist/client/components/actions/action-dialog.mjs +5 -0
  3. package/dist/client/components/fields/rich-text-editor/bubble-menu.mjs +7 -0
  4. package/dist/client/components/fields/rich-text-editor/extensions.mjs +17 -1
  5. package/dist/client/components/fields/rich-text-editor/index.d.mts +2 -1
  6. package/dist/client/components/fields/rich-text-editor/index.mjs +35 -74
  7. package/dist/client/components/fields/rich-text-editor/slash-commands.mjs +30 -7
  8. package/dist/client/components/fields/rich-text-editor/toolbar.mjs +1 -312
  9. package/dist/client/components/fields/rich-text-editor/types.d.mts +4 -0
  10. package/dist/client/components/fields/rich-text-editor/types.mjs +1 -1
  11. package/dist/client/components/fields/rich-text-editor/utils.mjs +6 -12
  12. package/dist/client/components/filter-builder/filter-builder-sheet.mjs +75 -22
  13. package/dist/client/components/ui/dropdown-menu.mjs +1 -34
  14. package/dist/client/hooks/query-access.d.mts +9 -0
  15. package/dist/client/hooks/query-access.mjs +20 -0
  16. package/dist/client/hooks/typed-hooks.d.mts +4 -2
  17. package/dist/client/hooks/typed-hooks.mjs +30 -29
  18. package/dist/client/hooks/use-reactive-fields.d.mts +1 -0
  19. package/dist/client/hooks/use-reactive-fields.mjs +16 -1
  20. package/dist/client/hooks/use-server-actions.mjs +12 -1
  21. package/dist/client/hooks/use-view-state.mjs +15 -7
  22. package/dist/client/lib/view-filter-utils.mjs +30 -0
  23. package/dist/client/preview/block-scope-context.d.mts +2 -2
  24. package/dist/client/preview/preview-banner.d.mts +2 -2
  25. package/dist/client/preview/preview-field.d.mts +4 -4
  26. package/dist/client/scope/picker.d.mts +2 -2
  27. package/dist/client/scope/provider.d.mts +2 -2
  28. package/dist/client/styles/base.css +69 -77
  29. package/dist/client/utils/build-field-definitions-from-schema.mjs +1 -0
  30. package/dist/client/views/collection/auto-form-fields.mjs +3 -2
  31. package/dist/client/views/collection/cells/primitive-cells.mjs +9 -6
  32. package/dist/client/views/collection/columns/build-columns.mjs +3 -1
  33. package/dist/client/views/collection/field-renderer.mjs +11 -3
  34. package/dist/client/views/collection/form-view.mjs +207 -202
  35. package/dist/client/views/collection/list-view.mjs +581 -183
  36. package/dist/client/views/collection/outline.mjs +44 -19
  37. package/dist/client/views/collection/quick-filter-bar.mjs +45 -0
  38. package/dist/client/views/collection/table-view.mjs +60 -16
  39. package/dist/client/views/globals/global-form-view.mjs +12 -9
  40. package/dist/client/views/layout/admin-layout.mjs +1 -1
  41. package/dist/client/views/layout/admin-sidebar.mjs +20 -14
  42. package/dist/client/views/layout/admin-theme.mjs +5 -4
  43. package/dist/client.mjs +1 -1
  44. package/dist/components/rich-text/rich-text-renderer.d.mts +5 -5
  45. package/dist/components/rich-text/rich-text-renderer.mjs +5 -2
  46. package/dist/index.mjs +1 -1
  47. package/dist/modules/admin.d.mts +1 -1
  48. package/dist/server/augmentation/actions.d.mts +4 -3
  49. package/dist/server/augmentation/dashboard.d.mts +11 -11
  50. package/dist/server/augmentation/form-layout.d.mts +11 -6
  51. package/dist/server/augmentation/index.d.mts +7 -0
  52. package/dist/server/augmentation/sidebar.d.mts +8 -8
  53. package/dist/server/codegen/admin-client-template.mjs +55 -38
  54. package/dist/server/fields/index.d.mts +1 -1
  55. package/dist/server/fields/rich-text.d.mts +16 -17
  56. package/dist/server/fields/rich-text.mjs +18 -7
  57. package/dist/server/i18n/messages/cs.mjs +2 -0
  58. package/dist/server/i18n/messages/de.mjs +2 -0
  59. package/dist/server/i18n/messages/en.mjs +4 -0
  60. package/dist/server/i18n/messages/es.mjs +2 -0
  61. package/dist/server/i18n/messages/fr.mjs +2 -0
  62. package/dist/server/i18n/messages/pl.mjs +2 -0
  63. package/dist/server/i18n/messages/pt.mjs +2 -0
  64. package/dist/server/i18n/messages/sk.mjs +2 -0
  65. package/dist/server/modules/admin/block/block-builder.d.mts +0 -8
  66. package/dist/server/modules/admin/block/introspection.d.mts +2 -2
  67. package/dist/server/modules/admin/collections/account.d.mts +53 -52
  68. package/dist/server/modules/admin/collections/admin-locks.d.mts +57 -56
  69. package/dist/server/modules/admin/collections/admin-preferences.d.mts +3 -2
  70. package/dist/server/modules/admin/collections/admin-saved-views.d.mts +50 -49
  71. package/dist/server/modules/admin/collections/apikey.d.mts +72 -71
  72. package/dist/server/modules/admin/collections/assets.d.mts +42 -41
  73. package/dist/server/modules/admin/collections/session.d.mts +46 -45
  74. package/dist/server/modules/admin/collections/user.d.mts +67 -66
  75. package/dist/server/modules/admin/collections/verification.d.mts +39 -38
  76. package/dist/server/modules/admin/index.d.mts +3 -3
  77. package/dist/server/modules/admin/routes/admin-config.d.mts +2 -2
  78. package/dist/server/modules/admin/routes/admin-config.mjs +39 -23
  79. package/dist/server/modules/admin/routes/execute-action.d.mts +9 -9
  80. package/dist/server/modules/admin/routes/execute-action.mjs +28 -8
  81. package/dist/server/modules/admin/routes/locales.d.mts +2 -2
  82. package/dist/server/modules/admin/routes/reactive.mjs +2 -2
  83. package/dist/server/modules/admin/routes/route-helpers.d.mts +11 -7
  84. package/dist/server/modules/admin/routes/translations.d.mts +4 -4
  85. package/dist/server/modules/admin/routes/widget-data.mjs +12 -4
  86. package/dist/server/modules/admin-preferences/collections/saved-views.d.mts +27 -27
  87. package/dist/server/modules/audit/.generated/module.d.mts +6 -6
  88. package/dist/server/modules/audit/collections/audit-log.d.mts +40 -39
  89. package/dist/server/plugin.mjs +3 -3
  90. package/dist/server.d.mts +1 -1
  91. package/dist/shared/types/index.d.mts +1 -0
  92. package/dist/shared/types/saved-views.types.d.mts +14 -7
  93. package/dist/shared.d.mts +3 -2
  94. package/package.json +4 -3
@@ -1,6 +1,7 @@
1
- import { ComponentReference } from "./common.mjs";
1
+ import { ComponentReference as ComponentReference$1 } from "./common.mjs";
2
2
  import { ComponentFactory } from "./views.mjs";
3
3
  import { I18nText } from "questpie/shared";
4
+ import { ZodType } from "zod";
4
5
 
5
6
  //#region src/server/augmentation/actions.d.ts
6
7
 
@@ -146,7 +147,7 @@ interface ServerActionFormFieldDefinition {
146
147
  required?: boolean;
147
148
  };
148
149
  /** Generate Zod schema for validation */
149
- toZodSchema(): unknown;
150
+ toZodSchema(): ZodType;
150
151
  }
151
152
  /**
152
153
  * Server-side action form configuration
@@ -176,7 +177,7 @@ interface ServerActionDefinition<TData = Record<string, unknown>> {
176
177
  /** Action description */
177
178
  description?: I18nText;
178
179
  /** Icon reference */
179
- icon?: ComponentReference;
180
+ icon?: ComponentReference$1;
180
181
  /** Button variant */
181
182
  variant?: "default" | "destructive" | "outline" | "secondary" | "ghost";
182
183
  /** Where the action appears */
@@ -1,4 +1,4 @@
1
- import { ComponentReference } from "./common.mjs";
1
+ import { ComponentReference as ComponentReference$1 } from "./common.mjs";
2
2
  import { ComponentFactory } from "./views.mjs";
3
3
  import { I18nText } from "questpie/shared";
4
4
  import { AppContext } from "questpie";
@@ -39,7 +39,7 @@ interface ServerStatsWidget {
39
39
  /** Widget label */
40
40
  label?: I18nText;
41
41
  /** Icon reference */
42
- icon?: ComponentReference;
42
+ icon?: ComponentReference$1;
43
43
  /** Collection to count */
44
44
  collection: string;
45
45
  /** Filter to apply */
@@ -141,7 +141,7 @@ interface ServerQuickAction {
141
141
  /** Action label */
142
142
  label: I18nText;
143
143
  /** Action icon */
144
- icon?: ComponentReference;
144
+ icon?: ComponentReference$1;
145
145
  /** Visual variant */
146
146
  variant?: "default" | "primary" | "secondary" | "outline";
147
147
  /** Action to perform */
@@ -189,7 +189,7 @@ interface ServerValueWidget {
189
189
  /** Widget label */
190
190
  label?: I18nText;
191
191
  /** Icon reference */
192
- icon?: ComponentReference;
192
+ icon?: ComponentReference$1;
193
193
  /** Card visual variant */
194
194
  cardVariant?: "default" | "compact" | "featured";
195
195
  /** Grid span (1-4) */
@@ -205,10 +205,10 @@ interface ServerValueWidget {
205
205
  label?: I18nText | string;
206
206
  subtitle?: I18nText | string;
207
207
  footer?: I18nText | string;
208
- icon?: ComponentReference;
208
+ icon?: ComponentReference$1;
209
209
  trend?: {
210
210
  value: string;
211
- icon?: ComponentReference;
211
+ icon?: ComponentReference$1;
212
212
  };
213
213
  classNames?: Record<string, string>;
214
214
  }>;
@@ -275,7 +275,7 @@ interface ServerTimelineWidget {
275
275
  title: string;
276
276
  description?: string;
277
277
  timestamp: Date | string;
278
- icon?: ComponentReference;
278
+ icon?: ComponentReference$1;
279
279
  variant?: "default" | "success" | "warning" | "error" | "info";
280
280
  href?: string;
281
281
  }>>;
@@ -321,7 +321,7 @@ interface ServerDashboardSection {
321
321
  /** Section description */
322
322
  description?: I18nText;
323
323
  /** Section icon */
324
- icon?: ComponentReference;
324
+ icon?: ComponentReference$1;
325
325
  /** Layout mode */
326
326
  layout?: "grid" | "stack";
327
327
  /** Grid columns */
@@ -362,7 +362,7 @@ interface ServerDashboardTab {
362
362
  /** Tab label */
363
363
  label: I18nText;
364
364
  /** Tab icon */
365
- icon?: ComponentReference;
365
+ icon?: ComponentReference$1;
366
366
  /** Tab items */
367
367
  items: ServerDashboardItem[];
368
368
  /** Grid columns for this tab */
@@ -387,7 +387,7 @@ interface ServerDashboardAction {
387
387
  /** Action label */
388
388
  label: I18nText;
389
389
  /** Action icon */
390
- icon?: ComponentReference;
390
+ icon?: ComponentReference$1;
391
391
  /** Action URL */
392
392
  href: string;
393
393
  /** Visual variant */
@@ -427,7 +427,7 @@ type BrandLogo = string | {
427
427
  alt?: string;
428
428
  width?: number;
429
429
  height?: number;
430
- } | ComponentReference;
430
+ } | ComponentReference$1;
431
431
  /**
432
432
  * Branding configuration for the admin panel. Covers content only — name,
433
433
  * logo, tagline, favicon. Visual tokens (colors, fonts, radius, shadows)
@@ -1,4 +1,5 @@
1
- import { ActionReference, ComponentReference } from "./common.mjs";
1
+ import { ActionReference, ComponentReference as ComponentReference$1 } from "./common.mjs";
2
+ import { FilterRule, QuickFilterConfig } from "../../shared/types/saved-views.types.mjs";
2
3
  import { I18nText } from "questpie/shared";
3
4
 
4
5
  //#region src/server/augmentation/form-layout.d.ts
@@ -13,7 +14,7 @@ interface AdminCollectionConfig {
13
14
  /** Description shown in tooltips/help text */
14
15
  description?: I18nText;
15
16
  /** Icon reference (resolved by client's icon component) */
16
- icon?: ComponentReference;
17
+ icon?: ComponentReference$1;
17
18
  /** Hide from admin sidebar */
18
19
  hidden?: boolean;
19
20
  /** Group in sidebar */
@@ -37,7 +38,7 @@ interface BlockCategoryConfig {
37
38
  /** Display label for the category */
38
39
  label: I18nText;
39
40
  /** Icon for the category */
40
- icon?: ComponentReference;
41
+ icon?: ComponentReference$1;
41
42
  /** Order in block picker (lower = first) */
42
43
  order?: number;
43
44
  }
@@ -64,7 +65,7 @@ interface AdminBlockConfig {
64
65
  /** Description shown in tooltips/help text */
65
66
  description?: I18nText;
66
67
  /** Icon reference (resolved by client's icon component) */
67
- icon?: ComponentReference;
68
+ icon?: ComponentReference$1;
68
69
  /** Category for grouping in block picker */
69
70
  category?: BlockCategoryConfig;
70
71
  /** Order within category in block picker (lower = first) */
@@ -137,6 +138,10 @@ interface ListViewConfig {
137
138
  field: string;
138
139
  direction: "asc" | "desc";
139
140
  };
141
+ /** Initial filters used when the user has no saved view state */
142
+ defaultFilters?: FilterRule[];
143
+ /** Header-level quick filter presets */
144
+ quickFilters?: QuickFilterConfig[];
140
145
  /**
141
146
  * Enables reorder mode for this list.
142
147
  * Requires a numeric field named `order` on the collection.
@@ -250,7 +255,7 @@ interface FormTabConfig {
250
255
  /** Tab label */
251
256
  label: I18nText;
252
257
  /** Tab icon */
253
- icon?: ComponentReference;
258
+ icon?: ComponentReference$1;
254
259
  /** Fields in this tab */
255
260
  fields: FieldLayoutItem[];
256
261
  /** Conditional visibility */
@@ -416,7 +421,7 @@ interface AdminGlobalConfig {
416
421
  /** Description */
417
422
  description?: I18nText;
418
423
  /** Icon reference */
419
- icon?: ComponentReference;
424
+ icon?: ComponentReference$1;
420
425
  /** Hide from admin */
421
426
  hidden?: boolean;
422
427
  /** Group in sidebar */
@@ -5,6 +5,7 @@ import { BrandLogo, DashboardActionFactory, DashboardActionProxy, DashboardCallb
5
5
  import { ServerSidebarCollectionItem, ServerSidebarConfig, ServerSidebarDividerItem, ServerSidebarGlobalItem, ServerSidebarItem, ServerSidebarLinkItem, ServerSidebarPageItem, ServerSidebarSection, SidebarCallback, SidebarCallbackContext, SidebarConfigContext, SidebarContribution, SidebarItemDef, SidebarProxy, SidebarSectionDef } from "./sidebar.mjs";
6
6
  import { AdminShellRailPlacement, AdminShellRouteRules, ServerAdminShellConfig, ServerAdminShellRailConfig } from "./shell.mjs";
7
7
  import { ActionsConfigContext, BuiltinActionType, ServerActionContext, ServerActionDefinition, ServerActionDownload, ServerActionEffects, ServerActionError, ServerActionForm, ServerActionFormField, ServerActionFormFieldConfig, ServerActionFormFieldDefinition, ServerActionHandler, ServerActionRedirect, ServerActionResult, ServerActionSuccess, ServerActionsConfig } from "./actions.mjs";
8
+ import { AdminSidebarMode } from "questpie";
8
9
 
9
10
  //#region src/server/augmentation/index.d.ts
10
11
 
@@ -27,6 +28,12 @@ import { ActionsConfigContext, BuiltinActionType, ServerActionContext, ServerAct
27
28
  * ```
28
29
  */
29
30
  interface AdminConfigInput {
31
+ /**
32
+ * How module `sidebar` contributions combine with the app config.
33
+ * `append` (default): merge module items into the app sidebar.
34
+ * `replace`: keep only this file's `sidebar` (no module nav injection).
35
+ */
36
+ sidebarMode?: AdminSidebarMode;
30
37
  sidebar?: SidebarContribution;
31
38
  dashboard?: DashboardContribution | ServerDashboardConfig;
32
39
  shell?: ServerAdminShellConfig;
@@ -1,4 +1,4 @@
1
- import { ComponentReference } from "./common.mjs";
1
+ import { ComponentReference as ComponentReference$1 } from "./common.mjs";
2
2
  import { ComponentFactory } from "./views.mjs";
3
3
  import { I18nText } from "questpie/shared";
4
4
 
@@ -18,7 +18,7 @@ interface ServerSidebarCollectionItem {
18
18
  /** Override display label */
19
19
  label?: I18nText;
20
20
  /** Override icon */
21
- icon?: ComponentReference;
21
+ icon?: ComponentReference$1;
22
22
  }
23
23
  /**
24
24
  * Global item in sidebar
@@ -30,7 +30,7 @@ interface ServerSidebarGlobalItem {
30
30
  /** Override display label */
31
31
  label?: I18nText;
32
32
  /** Override icon */
33
- icon?: ComponentReference;
33
+ icon?: ComponentReference$1;
34
34
  }
35
35
  /**
36
36
  * Custom page item in sidebar
@@ -42,7 +42,7 @@ interface ServerSidebarPageItem {
42
42
  /** Display label */
43
43
  label?: I18nText;
44
44
  /** Icon */
45
- icon?: ComponentReference;
45
+ icon?: ComponentReference$1;
46
46
  }
47
47
  /**
48
48
  * External link item in sidebar
@@ -54,7 +54,7 @@ interface ServerSidebarLinkItem {
54
54
  /** Link URL */
55
55
  href: string;
56
56
  /** Icon */
57
- icon?: ComponentReference;
57
+ icon?: ComponentReference$1;
58
58
  /** Open in new tab */
59
59
  external?: boolean;
60
60
  }
@@ -73,7 +73,7 @@ interface ServerSidebarSection {
73
73
  /** Section title */
74
74
  title?: I18nText;
75
75
  /** Section icon */
76
- icon?: ComponentReference;
76
+ icon?: ComponentReference$1;
77
77
  /** Whether this section can be collapsed/expanded by the user */
78
78
  collapsible?: boolean;
79
79
  /** Section items */
@@ -108,7 +108,7 @@ interface SidebarSectionDef {
108
108
  /** Section title. */
109
109
  title?: I18nText;
110
110
  /** Section icon. */
111
- icon?: ComponentReference;
111
+ icon?: ComponentReference$1;
112
112
  /** Whether section is collapsible. */
113
113
  collapsible?: boolean;
114
114
  }
@@ -134,7 +134,7 @@ interface SidebarItemDef extends Omit<ServerSidebarItem, "type"> {
134
134
  /** URL (for links). */
135
135
  href?: string;
136
136
  /** Icon reference. */
137
- icon?: ComponentReference;
137
+ icon?: ComponentReference$1;
138
138
  /** Open in new tab (for links). */
139
139
  external?: boolean;
140
140
  }
@@ -1,5 +1,47 @@
1
+ import { categoryRecordEntry, importStatement, sortedValues } from "questpie/codegen";
2
+
1
3
  //#region src/server/codegen/admin-client-template.ts
2
4
  /**
5
+ * Admin Client Template Generator
6
+ *
7
+ * Custom generator for the `admin-client` codegen target.
8
+ * Produces `questpie/admin/.generated/client.ts` — a plain admin config
9
+ * object that merges module defaults with user-discovered files.
10
+ *
11
+ * ## Architecture
12
+ *
13
+ * The admin-client target works identically to the server target:
14
+ *
15
+ * 1. **Package mode** (`generatePackageModules`): discovers files from
16
+ * `modules/admin/client/` → generates `modules/admin/client/.generated/module.ts`
17
+ * using the standard `generateModuleTemplate()` primitive.
18
+ *
19
+ * 2. **Root app mode** (`runAllTargets`): user has `admin/modules.ts` that imports
20
+ * module packages → this template imports `_mod` and merges generically with
21
+ * user-discovered files from `admin/{blocks,views,fields,...}/`.
22
+ *
23
+ * ## How to create an admin-client module (for third-party packages)
24
+ *
25
+ * 1. Create wrapper files in `modules/<name>/client/{fields,views,...}/`
26
+ * 2. Run `questpie generate` — generates `client/.generated/module.ts`
27
+ * 3. Create `client/index.ts` that re-exports the generated module
28
+ * 4. Add `"./client/module"` to `package.json` exports
29
+ *
30
+ * ## How users extend admin
31
+ *
32
+ * Add files in `questpie/admin/{views,fields,pages,widgets,blocks,components}/`.
33
+ * They are discovered automatically and merged over module defaults.
34
+ *
35
+ * ## Category key strategies
36
+ *
37
+ * - Default: use file key — `"bookingCta": _block_bookingCta`
38
+ * - `keyFromProperty: "name"`: use runtime key — `[_view_kanban.name]: _view_kanban`
39
+ *
40
+ * The strategy is declared per-category in `CategoryDeclaration.keyFromProperty`.
41
+ *
42
+ * @see PLAN-PLUGIN-CONSISTENCY.md §6.2 (admin-client target)
43
+ */
44
+ /**
3
45
  * Generate the admin client config file.
4
46
  *
5
47
  * Called by `runAllTargets()` for the `admin-client` target.
@@ -18,24 +60,25 @@ function generateAdminClientTemplate(ctx) {
18
60
  lines.push(" */");
19
61
  lines.push("");
20
62
  if (modulesFile) {
21
- lines.push(generateImportLine(modulesFile));
22
- lines.push(`const _mergedModules = Array.isArray(${modulesFile.varName})`);
23
- lines.push(`\t? ${modulesFile.varName}.reduce((acc: any, m: any) => {`);
24
- lines.push(" for (const [k, v] of Object.entries(m)) acc[k] = typeof v === \"object\" && v !== null && !Array.isArray(v) ? { ...acc[k], ...v } : v;");
63
+ lines.push(importStatement(modulesFile));
64
+ lines.push("type _AdminModuleMergeAcc = Record<string, unknown>;");
65
+ lines.push(`const _mergedModules = (Array.isArray(${modulesFile.varName})`);
66
+ lines.push(`\t? ${modulesFile.varName}.reduce<_AdminModuleMergeAcc>((acc, mod) => {`);
67
+ lines.push(" for (const [k, v] of Object.entries(mod)) acc[k] = typeof v === \"object\" && v !== null && !Array.isArray(v) ? { ...(typeof acc[k] === \"object\" && acc[k] !== null && !Array.isArray(acc[k]) ? acc[k] as Record<string, unknown> : {}), ...(v as Record<string, unknown>) } : v;");
25
68
  lines.push(" return acc;");
26
- lines.push(`\t}, {} as any) : ${modulesFile.varName};`);
69
+ lines.push(`\t}, {}) : ${modulesFile.varName}) as _AdminModuleMergeAcc;`);
27
70
  }
28
71
  const categoryFiles = /* @__PURE__ */ new Map();
29
72
  for (const [cat, fileMap] of ctx.discovered.categories) if (fileMap.size > 0) {
30
- const sorted = [...fileMap.values()].sort((a, b) => a.key.localeCompare(b.key));
73
+ const sorted = sortedValues(fileMap);
31
74
  categoryFiles.set(cat, sorted);
32
- for (const file of sorted) lines.push(generateImportLine(file));
75
+ for (const file of sorted) lines.push(importStatement(file));
33
76
  }
34
77
  const singleFiles = /* @__PURE__ */ new Map();
35
78
  for (const [key, file] of ctx.discovered.singles) {
36
79
  if (key === "modules") continue;
37
80
  singleFiles.set(key, file);
38
- lines.push(generateImportLine(file));
81
+ lines.push(importStatement(file));
39
82
  }
40
83
  for (const imp of ctx.extraImports) lines.push(`import ${imp.name} from "${imp.path}";`);
41
84
  lines.push("");
@@ -52,11 +95,11 @@ function generateAdminClientTemplate(ctx) {
52
95
  const files = categoryFiles.get(cat);
53
96
  const catDecl = ctx.target.categories?.[cat];
54
97
  if (modulesFile && files && files.length > 0) {
55
- const entries = generateCategoryEntries(files, catDecl);
56
- lines.push(`\t${cat}: { ..._mergedModules.${cat}, ${entries} },`);
57
- } else if (modulesFile && (!files || files.length === 0)) lines.push(`\t${cat}: { ..._mergedModules.${cat} },`);
98
+ const entries = files.map((f) => categoryRecordEntry(f, catDecl)).join(", ");
99
+ lines.push(`\t${cat}: { ...(_mergedModules[${JSON.stringify(cat)}] as Record<string, unknown>), ${entries} },`);
100
+ } else if (modulesFile && (!files || files.length === 0)) lines.push(`\t${cat}: { ...(_mergedModules[${JSON.stringify(cat)}] as Record<string, unknown>) },`);
58
101
  else if (files && files.length > 0) {
59
- const entries = generateCategoryEntries(files, catDecl);
102
+ const entries = files.map((f) => categoryRecordEntry(f, catDecl)).join(", ");
60
103
  lines.push(`\t${cat}: { ${entries} },`);
61
104
  }
62
105
  }
@@ -73,32 +116,6 @@ function generateAdminClientTemplate(ctx) {
73
116
  lines.push("");
74
117
  return { code: lines.join("\n") };
75
118
  }
76
- /**
77
- * Generate category entries string based on the category's key strategy.
78
- *
79
- * When `keyFromProperty` is set (e.g., views with `keyFromProperty: "name"`),
80
- * uses runtime property as key: `[_view_kanban.name]: _view_kanban`.
81
- *
82
- * Otherwise uses the file-derived key: `"bookingCta": _block_bookingCta`.
83
- */
84
- function generateCategoryEntries(files, catDecl) {
85
- const keyProp = catDecl?.keyFromProperty;
86
- return files.map((f) => {
87
- if (keyProp) return `[${f.varName}.${keyProp}]: ${f.varName}`;
88
- if (catDecl?.keyFromSource === "basename") return `${JSON.stringify(getSourceBasename(f))}: ${f.varName}`;
89
- return `${JSON.stringify(f.key)}: ${f.varName}`;
90
- }).join(", ");
91
- }
92
- function getSourceBasename(file) {
93
- return (file.source.replaceAll("\\", "/").split("/").pop() ?? file.key).replace(/\.[^.]+$/, "");
94
- }
95
- /**
96
- * Generate an import line for a discovered file.
97
- */
98
- function generateImportLine(file) {
99
- if (file.exportType === "named" && file.namedExportName) return `import { ${file.namedExportName} as ${file.varName} } from "${file.importPath}";`;
100
- return `import ${file.varName} from "${file.importPath}";`;
101
- }
102
119
 
103
120
  //#endregion
104
121
  export { generateAdminClientTemplate };
@@ -1,5 +1,5 @@
1
1
  import { BlockNode, BlockValues, BlocksDocument, BlocksFieldMeta, BlocksFieldState, blocks, blocksFieldType } from "./blocks.mjs";
2
- import { RichTextFeature, RichTextFieldMeta, RichTextFieldState, TipTapDocument, TipTapNode, richText, richTextFieldType } from "./rich-text.mjs";
2
+ import { RichTextFeature, RichTextFieldMeta, RichTextFieldState, RichTextMode, RichTextOptions, TipTapDocument, TipTapNode, richText, richTextFieldType } from "./rich-text.mjs";
3
3
 
4
4
  //#region src/server/fields/index.d.ts
5
5
 
@@ -1,5 +1,5 @@
1
1
  import { DefaultFieldState, Field, FieldTypeDefinition } from "questpie";
2
- import { PgJsonbBuilder } from "questpie/drizzle-pg-core";
2
+ import { PgJsonbBuilder, PgTextBuilder } from "questpie/drizzle-pg-core";
3
3
 
4
4
  //#region src/server/fields/rich-text.d.ts
5
5
 
@@ -48,28 +48,27 @@ interface RichTextFieldMeta {
48
48
  * Available rich text editor features.
49
49
  */
50
50
  type RichTextFeature = "bold" | "italic" | "underline" | "strike" | "code" | "subscript" | "superscript" | "heading" | "bulletList" | "orderedList" | "taskList" | "blockquote" | "codeBlock" | "horizontalRule" | "link" | "image" | "table" | "textAlign" | "textColor" | "highlight" | "mention";
51
- /**
52
- * Rich text field factory.
53
- * Creates a TipTap-based rich text editor field.
54
- *
55
- * @example
56
- * ```ts
57
- * // In collection fields callback:
58
- * content: f.richText().required().localized()
59
- * ```
60
- */
61
- type RichTextFieldState = DefaultFieldState & {
51
+ type RichTextMode = "json" | "markdown";
52
+ type RichTextOptions = {
53
+ mode?: RichTextMode;
54
+ };
55
+ type RichTextData<TMode extends RichTextMode> = TMode extends "markdown" ? string : TipTapDocument;
56
+ type RichTextColumn<TMode extends RichTextMode> = TMode extends "markdown" ? PgTextBuilder : PgJsonbBuilder;
57
+ type RichTextFieldState<TMode extends RichTextMode = "json"> = DefaultFieldState & {
62
58
  type: "richText";
63
- data: TipTapDocument;
64
- column: PgJsonbBuilder;
59
+ data: RichTextData<TMode>;
60
+ column: RichTextColumn<TMode>;
65
61
  };
66
- declare function richText(): Field<RichTextFieldState>;
62
+ declare function richText(): Field<RichTextFieldState<"json">>;
63
+ declare function richText<const TMode extends RichTextMode>(options: {
64
+ mode: TMode;
65
+ }): Field<RichTextFieldState<TMode>>;
67
66
  /**
68
67
  * Rich text field type definition (v3 API).
69
68
  *
70
69
  * Use this with the `fieldType()` discovery system instead of the
71
70
  * legacy `richText()` factory function.
72
71
  */
73
- declare const richTextFieldType: FieldTypeDefinition<"richText", []>;
72
+ declare const richTextFieldType: FieldTypeDefinition<"richText", [RichTextOptions?]>;
74
73
  //#endregion
75
- export { RichTextFeature, RichTextFieldMeta, RichTextFieldState, TipTapDocument, TipTapNode, richText, richTextFieldType };
74
+ export { RichTextFeature, RichTextFieldMeta, RichTextFieldState, RichTextMode, RichTextOptions, TipTapDocument, TipTapNode, richText, richTextFieldType };
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { field, fieldType, isNotNull, isNull, jsonb, sql } from "questpie";
3
+ import { text } from "questpie/drizzle-pg-core";
3
4
 
4
5
  //#region src/server/fields/rich-text.ts
5
6
  /**
@@ -85,6 +86,13 @@ function getRichTextOperators() {
85
86
  }
86
87
  };
87
88
  }
89
+ const markdownOperators = {
90
+ contains: (col, value) => sql`${col} ILIKE ${"%" + value + "%"}`,
91
+ isEmpty: (col) => sql`(${col} IS NULL OR length(trim(${col})) = 0)`,
92
+ isNotEmpty: (col) => sql`(${col} IS NOT NULL AND length(trim(${col})) > 0)`,
93
+ isNull: (col) => isNull(col),
94
+ isNotNull: (col) => isNotNull(col)
95
+ };
88
96
  /**
89
97
  * Create a rich text field.
90
98
  *
@@ -97,11 +105,13 @@ function getRichTextOperators() {
97
105
  * Rich text field runtime state factory.
98
106
  * Shared between the legacy `richText()` function and the new `richTextFieldType`.
99
107
  */
100
- function createRichTextState() {
108
+ function createRichTextState(options) {
109
+ const mode = options?.mode ?? "json";
110
+ const isMarkdown = mode === "markdown";
101
111
  return {
102
112
  type: "richText",
103
- columnFactory: (name) => jsonb(name),
104
- schemaFactory: () => {
113
+ columnFactory: isMarkdown ? (name) => text(name) : (name) => jsonb(name),
114
+ schemaFactory: isMarkdown ? () => z.string() : () => {
105
115
  const nodeSchema = z.lazy(() => z.object({
106
116
  type: z.string(),
107
117
  attrs: z.record(z.string(), z.any()).optional(),
@@ -117,7 +127,7 @@ function createRichTextState() {
117
127
  content: z.array(nodeSchema).optional()
118
128
  });
119
129
  },
120
- operatorSet: {
130
+ operatorSet: isMarkdown ? markdownOperators : {
121
131
  jsonbCast: null,
122
132
  column: getRichTextOperators().column
123
133
  },
@@ -129,7 +139,8 @@ function createRichTextState() {
129
139
  localized: state.localized ?? false,
130
140
  readOnly: state.input === false ? true : void 0,
131
141
  writeOnly: state.output === false ? true : void 0,
132
- meta: state.extensions?.admin
142
+ meta: state.extensions?.admin,
143
+ outputMode: mode
133
144
  }),
134
145
  notNull: false,
135
146
  hasDefault: false,
@@ -140,8 +151,8 @@ function createRichTextState() {
140
151
  isArray: false
141
152
  };
142
153
  }
143
- function richText() {
144
- return field(createRichTextState());
154
+ function richText(options) {
155
+ return field(createRichTextState(options));
145
156
  }
146
157
  /**
147
158
  * Rich text field type definition (v3 API).
@@ -719,6 +719,8 @@ var cs_default = {
719
719
  "viewOptions.groupByDescription": "Seskupit aktuální stránku podle nakonfigurovaného pole.",
720
720
  "viewOptions.noGrouping": "Bez seskupení",
721
721
  "viewOptions.sort": "Řazení",
722
+ "viewOptions.noSort": "Bez řazení",
723
+ "viewOptions.sortDescription": "Vyberte pole a směr řazení pro tento pohled.",
722
724
  "version.history": "Historie verzí",
723
725
  "version.historyDescription": "Procházejte předchozí verze a v případě potřeby některou obnovte.",
724
726
  "version.globalHistoryDescription": "Procházejte předchozí verze globálních nastavení a v případě potřeby některou obnovte.",
@@ -717,6 +717,8 @@ var de_default = {
717
717
  "viewOptions.groupByDescription": "Die aktuelle Seite nach einem konfigurierten Feld gruppieren.",
718
718
  "viewOptions.noGrouping": "Keine Gruppierung",
719
719
  "viewOptions.sort": "Sortierung",
720
+ "viewOptions.noSort": "Keine Sortierung",
721
+ "viewOptions.sortDescription": "Wählen Sie Feld und Richtung für diese Ansicht.",
720
722
  "version.history": "Versionsverlauf",
721
723
  "version.historyDescription": "Durchsuchen Sie frühere Versionen und stellen Sie bei Bedarf eine wieder her.",
722
724
  "version.globalHistoryDescription": "Durchsuchen Sie frühere globale Versionen und stellen Sie bei Bedarf eine wieder her.",
@@ -370,6 +370,8 @@ var en_default = {
370
370
  "table.noItemsInCollection": "No items found in this collection",
371
371
  "table.emptyDescription": "Records will appear here once they are created.",
372
372
  "table.pagination": "Pagination",
373
+ "table.items": "items",
374
+ "table.loadMore": "Load more",
373
375
  "table.editing": "Editing",
374
376
  "upload.dropzone": "Drop files here or click to upload",
375
377
  "upload.browse": "Browse files",
@@ -636,6 +638,8 @@ var en_default = {
636
638
  "viewOptions.groupByDescription": "Group the current page by a configured field.",
637
639
  "viewOptions.noGrouping": "No grouping",
638
640
  "viewOptions.sort": "Sort",
641
+ "viewOptions.noSort": "No sorting",
642
+ "viewOptions.sortDescription": "Choose the field and direction used by this view.",
639
643
  "version.history": "Version history",
640
644
  "version.historyDescription": "Browse previous versions and restore one if needed.",
641
645
  "version.globalHistoryDescription": "Browse previous global versions and restore one if needed.",
@@ -862,6 +862,8 @@ var es_default = {
862
862
  "viewOptions.showDeleted": "Mostrar eliminados",
863
863
  "viewOptions.showDeletedDescription": "Incluir registros eliminados de forma reversible en esta vista.",
864
864
  "viewOptions.sort": "Ordenar",
865
+ "viewOptions.noSort": "Sin ordenación",
866
+ "viewOptions.sortDescription": "Elige el campo y la dirección para esta vista.",
865
867
  "widget.chart.emptyDescription": "Configure una fuente de datos para mostrar un gráfico.",
866
868
  "widget.chart.emptyTitle": "No hay datos de gráfico",
867
869
  "widget.progress.emptyDescription": "Configure datos de progreso para mostrar este widget.",
@@ -862,6 +862,8 @@ var fr_default = {
862
862
  "viewOptions.showDeleted": "Afficher les supprimés",
863
863
  "viewOptions.showDeletedDescription": "Inclure les enregistrements supprimés de façon réversible dans cette vue.",
864
864
  "viewOptions.sort": "Trier",
865
+ "viewOptions.noSort": "Aucun tri",
866
+ "viewOptions.sortDescription": "Choisissez le champ et le sens utilisés par cette vue.",
865
867
  "widget.chart.emptyDescription": "Configurez une source de données pour afficher un graphique.",
866
868
  "widget.chart.emptyTitle": "Aucune donnée de graphique",
867
869
  "widget.progress.emptyDescription": "Configurez des données de progression pour afficher ce widget.",
@@ -866,6 +866,8 @@ var pl_default = {
866
866
  "viewOptions.showDeleted": "Pokaż usunięte",
867
867
  "viewOptions.showDeletedDescription": "Uwzględnij w tym widoku rekordy usunięte miękko.",
868
868
  "viewOptions.sort": "Sortuj",
869
+ "viewOptions.noSort": "Bez sortowania",
870
+ "viewOptions.sortDescription": "Wybierz pole i kierunek używane w tym widoku.",
869
871
  "widget.chart.emptyDescription": "Skonfiguruj źródło danych, aby wyświetlić wykres.",
870
872
  "widget.chart.emptyTitle": "Brak danych wykresu",
871
873
  "widget.progress.emptyDescription": "Skonfiguruj dane postępu, aby wyświetlić ten widget.",
@@ -862,6 +862,8 @@ var pt_default = {
862
862
  "viewOptions.showDeleted": "Mostrar excluídos",
863
863
  "viewOptions.showDeletedDescription": "Incluir registros excluídos de forma reversível nesta visualização.",
864
864
  "viewOptions.sort": "Ordenar",
865
+ "viewOptions.noSort": "Sem ordenação",
866
+ "viewOptions.sortDescription": "Escolha o campo e a direção usados nesta visualização.",
865
867
  "widget.chart.emptyDescription": "Configure uma fonte de dados para exibir um gráfico.",
866
868
  "widget.chart.emptyTitle": "Nenhum dado de gráfico",
867
869
  "widget.progress.emptyDescription": "Configure dados de progresso para exibir este widget.",
@@ -602,6 +602,8 @@ var sk_default = {
602
602
  "viewOptions.groupByDescription": "Zoskupí aktuálnu stránku podľa nakonfigurovaného poľa.",
603
603
  "viewOptions.noGrouping": "Bez zoskupenia",
604
604
  "viewOptions.sort": "Zoradenie",
605
+ "viewOptions.noSort": "Bez zoradenia",
606
+ "viewOptions.sortDescription": "Vyberte pole a smer zoradenia pre tento pohľad.",
605
607
  "viewOptions.saveCurrentConfig": "Uložiť aktuálnu konfiguráciu",
606
608
  "viewOptions.viewNamePlaceholder": "Názov zobrazenia...",
607
609
  "viewOptions.saveDescription": "Uloží aktuálne stĺpce, filtre, zoskupenie a zoradenie.",
@@ -27,14 +27,6 @@ type AdminBlockFields = BuiltinFields & typeof adminFields;
27
27
  * ```
28
28
  */
29
29
  type BlockPrefetchContext = AppContext & {
30
- /** App instance — populated at runtime by extractAppServices */
31
- app: unknown;
32
- /** Database handle — populated at runtime by extractAppServices */
33
- db: unknown;
34
- /** Collection APIs — populated at runtime by extractAppServices */
35
- collections: Record<string, any>;
36
- /** Global APIs — populated at runtime by extractAppServices */
37
- globals: Record<string, any>;
38
30
  /** Block instance ID */
39
31
  blockId: string;
40
32
  /** Block type name */
@@ -1,4 +1,4 @@
1
- import { ComponentReference } from "../../../augmentation/common.mjs";
1
+ import { ComponentReference as ComponentReference$1 } from "../../../augmentation/common.mjs";
2
2
  import { BlockCategoryConfig, FieldLayoutItem } from "../../../augmentation/form-layout.mjs";
3
3
  import "../../../augmentation.mjs";
4
4
  import { AnyBlockDefinition } from "./block-builder.mjs";
@@ -21,7 +21,7 @@ interface BlockSchema {
21
21
  /** Description */
22
22
  description?: I18nText;
23
23
  /** Icon reference */
24
- icon?: ComponentReference;
24
+ icon?: ComponentReference$1;
25
25
  /** Category for grouping in block picker */
26
26
  category?: BlockCategoryConfig;
27
27
  /** Order within category in block picker */