@duke333/builder-ui 0.1.0 → 0.1.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.
@@ -0,0 +1,2267 @@
1
+ // src/api/createBuilderApiClient.ts
2
+ function queryParams(query) {
3
+ return { ...query };
4
+ }
5
+ function fieldOptionsQueryParams(query) {
6
+ const flatQuery = { search: query.search };
7
+ for (const [key, value] of Object.entries(query.depends ?? {})) {
8
+ flatQuery[`depends.${key}`] = value;
9
+ }
10
+ return flatQuery;
11
+ }
12
+ function createBuilderApiClient(transport) {
13
+ return {
14
+ listBuilderForms: (query) => transport.get("/builder/forms", {
15
+ query: queryParams(query)
16
+ }),
17
+ listBuilderDbTables: () => transport.get("/builder/datasources/tables"),
18
+ listBuilderFormOptions: () => transport.get("/builder/forms/options"),
19
+ getBuilderForm: (id) => transport.get(`/builder/forms/${encodeURIComponent(id)}`),
20
+ createBuilderForm: (input) => transport.post("/builder/forms", input),
21
+ updateBuilderForm: (id, input) => transport.patch(`/builder/forms/${encodeURIComponent(id)}`, input),
22
+ replicateBuilderForm: (id, input) => transport.post(`/builder/forms/${encodeURIComponent(id)}/replicate`, input),
23
+ deleteBuilderForm: (id) => transport.delete(`/builder/forms/${encodeURIComponent(id)}`),
24
+ listBuilderLists: (query) => transport.get("/builder/lists", {
25
+ query: queryParams(query)
26
+ }),
27
+ listBuilderListOptions: () => transport.get("/builder/lists/options"),
28
+ getBuilderList: (id) => transport.get(`/builder/lists/${encodeURIComponent(id)}`),
29
+ createBuilderList: (input) => transport.post("/builder/lists", input),
30
+ updateBuilderList: (id, input) => transport.patch(`/builder/lists/${encodeURIComponent(id)}`, input),
31
+ replicateBuilderList: (id, input) => transport.post(`/builder/lists/${encodeURIComponent(id)}/replicate`, input),
32
+ deleteBuilderList: (id) => transport.delete(`/builder/lists/${encodeURIComponent(id)}`),
33
+ listBuilderViews: (query) => transport.get("/builder/views", {
34
+ query: queryParams(query)
35
+ }),
36
+ getBuilderView: (id) => transport.get(`/builder/views/${encodeURIComponent(id)}`),
37
+ createBuilderView: (input) => transport.post("/builder/views", input),
38
+ updateBuilderView: (id, input) => transport.patch(`/builder/views/${encodeURIComponent(id)}`, input),
39
+ replicateBuilderView: (id, input) => transport.post(`/builder/views/${encodeURIComponent(id)}/replicate`, input),
40
+ deleteBuilderView: (id) => transport.delete(`/builder/views/${encodeURIComponent(id)}`),
41
+ getRuntimeBuilderForm: (id) => transport.get(`/builder/runtime/forms/${encodeURIComponent(id)}`),
42
+ createRuntimeBuilderFormEntry: (formId, input) => transport.post(
43
+ `/builder/runtime/forms/${encodeURIComponent(formId)}/entries`,
44
+ input
45
+ ),
46
+ listRuntimeBuilderFormFieldOptions: (formId, fieldKey, query) => transport.get(
47
+ `/builder/runtime/forms/${encodeURIComponent(formId)}/fields/${encodeURIComponent(fieldKey)}/options`,
48
+ { query: fieldOptionsQueryParams(query) }
49
+ ),
50
+ runRuntimeBuilderFormFieldTrigger: (formId, fieldKey, event, input) => transport.post(
51
+ `/builder/runtime/forms/${encodeURIComponent(formId)}/fields/${encodeURIComponent(fieldKey)}/triggers/${encodeURIComponent(event)}`,
52
+ input
53
+ ),
54
+ getRuntimeBuilderList: (id) => transport.get(`/builder/runtime/lists/${encodeURIComponent(id)}`),
55
+ listRuntimeBuilderListEntries: (listId, query) => transport.get(
56
+ `/builder/runtime/lists/${encodeURIComponent(listId)}/entries`,
57
+ { query: queryParams(query) }
58
+ ),
59
+ getRuntimeBuilderView: (id) => transport.get(`/builder/runtime/views/${encodeURIComponent(id)}`),
60
+ runRuntimeBuilderViewFieldTrigger: (viewId, fieldKey, event, input) => transport.post(
61
+ `/builder/runtime/views/${encodeURIComponent(viewId)}/fields/${encodeURIComponent(fieldKey)}/triggers/${encodeURIComponent(event)}`,
62
+ input
63
+ ),
64
+ listBuilderViewEntries: (viewId, query) => transport.get(
65
+ `/builder/runtime/views/${encodeURIComponent(viewId)}/entries`,
66
+ { query: queryParams(query) }
67
+ ),
68
+ createBuilderViewEntry: (viewId, input) => transport.post(
69
+ `/builder/runtime/views/${encodeURIComponent(viewId)}/entries`,
70
+ input
71
+ ),
72
+ createCompositeBuilderViewEntry: (viewId, input) => transport.post(
73
+ `/builder/runtime/views/${encodeURIComponent(viewId)}/composite-entries`,
74
+ input
75
+ ),
76
+ updateCompositeBuilderViewEntry: (viewId, id, input) => transport.patch(
77
+ `/builder/runtime/views/${encodeURIComponent(viewId)}/composite-entries/${encodeURIComponent(id)}`,
78
+ input
79
+ ),
80
+ updateBuilderViewEntry: (viewId, id, input) => transport.patch(
81
+ `/builder/runtime/views/${encodeURIComponent(viewId)}/entries/${encodeURIComponent(id)}`,
82
+ input
83
+ ),
84
+ deleteBuilderViewEntry: (viewId, id) => transport.delete(
85
+ `/builder/runtime/views/${encodeURIComponent(viewId)}/entries/${encodeURIComponent(id)}`
86
+ )
87
+ };
88
+ }
89
+
90
+ // src/admin/editorState.ts
91
+ var BUILDER_EDITOR_NONE_VALUE = "__none";
92
+ function builderEditorOptionsToText(options) {
93
+ return (options ?? []).map((option) => `${option.label}:${option.value}`).join("\n");
94
+ }
95
+ function builderEditorTextToOptions(value) {
96
+ const rows = (value ?? "").split("\n").map((line) => line.trim()).filter(Boolean);
97
+ if (rows.length === 0) return void 0;
98
+ return rows.map((line) => {
99
+ const [label, ...rest] = line.split(":");
100
+ return { label: label.trim(), value: rest.join(":").trim() || label.trim() };
101
+ });
102
+ }
103
+ function builderEditorSearchFieldsToText(fields) {
104
+ return (fields ?? []).join("\n");
105
+ }
106
+ function builderEditorTextToSearchFields(value) {
107
+ const fields = (value ?? "").split("\n").map((line) => line.trim()).filter(Boolean);
108
+ return fields.length > 0 ? fields : void 0;
109
+ }
110
+ function getBuilderEditorTriggerRoute(config) {
111
+ const route = config.route ?? config.path ?? config.url;
112
+ return typeof route === "string" ? route : "";
113
+ }
114
+ function valuesFromTriggers(triggers) {
115
+ return triggers.filter((trigger) => trigger.action === "callApi" || trigger.action === "webhook").map((trigger) => ({
116
+ event: trigger.event,
117
+ route: getBuilderEditorTriggerRoute(trigger.config),
118
+ enabled: trigger.enabled,
119
+ blocking: trigger.blocking
120
+ })).filter((trigger) => trigger.route);
121
+ }
122
+ function valuesFromFieldTriggers(triggers) {
123
+ return (triggers ?? []).map((trigger) => ({
124
+ event: trigger.event,
125
+ action: trigger.action,
126
+ enabled: trigger.enabled,
127
+ debounceMs: trigger.debounceMs
128
+ }));
129
+ }
130
+ function clampLayoutSpan(span, columns) {
131
+ if (!span || Number.isNaN(span)) return columns;
132
+ return Math.max(1, Math.min(columns, Math.trunc(span)));
133
+ }
134
+ function builderFormEditorDefaultSpan(field) {
135
+ if (field.type === "textarea" || field.type === "checkbox") return 12;
136
+ return 6;
137
+ }
138
+ function builderFormEditorDefaultLayoutGroups(fields, subforms = []) {
139
+ return [
140
+ {
141
+ id: "main",
142
+ title: "\u04AE\u043D\u0434\u0441\u044D\u043D",
143
+ columns: 12,
144
+ fields: [
145
+ ...fields.map((field) => ({
146
+ key: field.key,
147
+ span: builderFormEditorDefaultSpan(field)
148
+ })),
149
+ ...subforms.map((subform) => ({ key: subform.key, span: 12 }))
150
+ ]
151
+ }
152
+ ];
153
+ }
154
+ function normalizeBuilderFormEditorLayoutGroups(groups, fields, subforms = []) {
155
+ if (fields.length === 0 && subforms.length === 0) return [];
156
+ const layoutItems = [
157
+ ...fields.map((field) => ({
158
+ key: field.key,
159
+ span: builderFormEditorDefaultSpan(field)
160
+ })),
161
+ ...subforms.map((subform) => ({ key: subform.key, span: 12 }))
162
+ ];
163
+ const itemKeys = new Set(layoutItems.map((item) => item.key));
164
+ const usedKeys = /* @__PURE__ */ new Set();
165
+ const normalized = (groups ?? []).map((group, index) => {
166
+ const columns = group.columns === 6 || group.columns === 8 ? group.columns : 12;
167
+ const groupFields = (group.fields ?? []).filter((field) => itemKeys.has(field.key) && !usedKeys.has(field.key)).map((field) => {
168
+ usedKeys.add(field.key);
169
+ return { key: field.key, span: clampLayoutSpan(field.span, columns) };
170
+ });
171
+ return {
172
+ id: group.id || `group${index + 1}`,
173
+ title: group.title || `Group ${index + 1}`,
174
+ columns,
175
+ fields: groupFields
176
+ };
177
+ }).filter((group) => group.fields.length > 0 || group.title.trim());
178
+ const missingFields = layoutItems.filter((item) => !usedKeys.has(item.key));
179
+ if (normalized.length === 0) {
180
+ return builderFormEditorDefaultLayoutGroups(fields, subforms);
181
+ }
182
+ if (missingFields.length > 0) {
183
+ normalized.push({
184
+ id: "ungrouped",
185
+ title: "\u0411\u0443\u0441\u0430\u0434",
186
+ columns: 12,
187
+ fields: missingFields
188
+ });
189
+ }
190
+ return normalized;
191
+ }
192
+ function builderFormEditorValuesFromEntity(form, emptyValues) {
193
+ if (!form) return emptyValues;
194
+ const source = form.source;
195
+ const fields = form.schema.fields.map((field) => ({
196
+ key: field.key,
197
+ label: field.label,
198
+ type: field.type,
199
+ required: field.required,
200
+ hidden: field.hidden ?? false,
201
+ disabled: field.disabled ?? false,
202
+ placeholder: field.placeholder ?? "",
203
+ optionsText: builderEditorOptionsToText(field.options),
204
+ optionsMode: field.optionsSource?.type === "dbTable" ? "table" : "static",
205
+ optionsTable: field.optionsSource?.type === "dbTable" ? field.optionsSource.tableName : BUILDER_EDITOR_NONE_VALUE,
206
+ optionsValueField: field.optionsSource?.type === "dbTable" ? field.optionsSource.valueField : BUILDER_EDITOR_NONE_VALUE,
207
+ optionsLabelField: field.optionsSource?.type === "dbTable" ? field.optionsSource.labelField : BUILDER_EDITOR_NONE_VALUE,
208
+ optionsSearchFieldsText: field.optionsSource?.type === "dbTable" ? builderEditorSearchFieldsToText(field.optionsSource.searchFields) : "",
209
+ optionsDependsOn: field.optionsSource?.type === "dbTable" ? field.optionsSource.filterBy?.valueFromField ?? "" : "",
210
+ optionsFilterField: field.optionsSource?.type === "dbTable" ? field.optionsSource.filterBy?.field ?? "" : "",
211
+ triggers: valuesFromFieldTriggers(field.triggers)
212
+ }));
213
+ const subforms = (form.schema.subforms ?? []).map((subform) => ({
214
+ key: subform.key,
215
+ label: subform.label,
216
+ viewId: subform.viewId,
217
+ parentField: subform.parentField,
218
+ childField: subform.childField,
219
+ buttonLabel: subform.buttonLabel ?? "",
220
+ icon: subform.icon ?? ""
221
+ }));
222
+ return {
223
+ title: form.title,
224
+ description: form.description ?? "",
225
+ sourceType: source?.type ?? "none",
226
+ sourceTable: source?.type === "dbTable" ? source.tableName : BUILDER_EDITOR_NONE_VALUE,
227
+ apiBasePath: source?.type === "apiEndpoint" ? source.basePath : "",
228
+ fields,
229
+ layoutGroups: normalizeBuilderFormEditorLayoutGroups(
230
+ form.schema.layout?.groups,
231
+ fields,
232
+ subforms
233
+ ),
234
+ subforms,
235
+ triggers: valuesFromTriggers(form.triggers),
236
+ version: form.version
237
+ };
238
+ }
239
+ function builderListEditorValuesFromEntity(list, emptyValues) {
240
+ if (!list) return emptyValues;
241
+ const source = list.source;
242
+ return {
243
+ title: list.title,
244
+ description: list.description ?? "",
245
+ sourceType: source?.type ?? "none",
246
+ sourceTable: source?.type === "dbTable" ? source.tableName : BUILDER_EDITOR_NONE_VALUE,
247
+ apiBasePath: source?.type === "apiEndpoint" ? source.basePath : "",
248
+ columns: list.schema.columns.map((column) => ({
249
+ key: column.key,
250
+ label: column.label,
251
+ sortable: column.sortable,
252
+ align: column.align
253
+ })),
254
+ triggers: valuesFromTriggers(list.triggers),
255
+ version: list.version
256
+ };
257
+ }
258
+ function builderViewEditorValuesFromEntity(view, emptyValues, defaultPermission = "") {
259
+ if (!view) return emptyValues;
260
+ return {
261
+ title: view.title,
262
+ description: view.description ?? "",
263
+ formId: view.formId ?? BUILDER_EDITOR_NONE_VALUE,
264
+ listId: view.listId ?? BUILDER_EDITOR_NONE_VALUE,
265
+ permissionRead: view.permissionRead || defaultPermission,
266
+ permissionWrite: view.permissionWrite || defaultPermission,
267
+ triggersText: JSON.stringify(view.triggers ?? [], null, 2),
268
+ version: view.version
269
+ };
270
+ }
271
+ function builderFormEditorFieldsFromTable(table) {
272
+ return table.columns.map((column) => ({
273
+ key: column.name,
274
+ label: column.label,
275
+ type: column.fieldType,
276
+ required: !column.nullable,
277
+ hidden: false,
278
+ disabled: false,
279
+ placeholder: column.label,
280
+ optionsText: "",
281
+ optionsMode: "static",
282
+ optionsTable: BUILDER_EDITOR_NONE_VALUE,
283
+ optionsValueField: BUILDER_EDITOR_NONE_VALUE,
284
+ optionsLabelField: BUILDER_EDITOR_NONE_VALUE,
285
+ optionsSearchFieldsText: "",
286
+ optionsDependsOn: "",
287
+ optionsFilterField: "",
288
+ triggers: []
289
+ }));
290
+ }
291
+ function builderListEditorColumnsFromTable(table) {
292
+ return table.columns.map((column) => ({
293
+ key: column.name,
294
+ label: column.label,
295
+ sortable: column.sortable,
296
+ align: column.fieldType === "number" || column.fieldType === "money" ? "right" : "left"
297
+ }));
298
+ }
299
+ function builderFormEditorInputFromValues(values) {
300
+ const source = values.sourceType === "dbTable" && values.sourceTable !== BUILDER_EDITOR_NONE_VALUE ? { type: "dbTable", tableName: values.sourceTable } : values.sourceType === "apiEndpoint" && values.apiBasePath ? { type: "apiEndpoint", basePath: values.apiBasePath } : null;
301
+ return {
302
+ title: values.title,
303
+ description: values.description || null,
304
+ source,
305
+ schema: {
306
+ fields: values.fields.map((field) => ({
307
+ key: field.key,
308
+ label: field.label,
309
+ type: field.type,
310
+ required: field.required,
311
+ hidden: field.hidden,
312
+ disabled: field.disabled,
313
+ placeholder: field.placeholder?.trim() || field.label,
314
+ options: field.type === "select" && field.optionsMode === "static" ? builderEditorTextToOptions(field.optionsText) : void 0,
315
+ optionsSource: field.type === "select" && field.optionsMode === "table" && field.optionsTable !== BUILDER_EDITOR_NONE_VALUE && field.optionsValueField !== BUILDER_EDITOR_NONE_VALUE && field.optionsLabelField !== BUILDER_EDITOR_NONE_VALUE ? {
316
+ type: "dbTable",
317
+ tableName: field.optionsTable,
318
+ valueField: field.optionsValueField,
319
+ labelField: field.optionsLabelField,
320
+ searchFields: builderEditorTextToSearchFields(field.optionsSearchFieldsText),
321
+ filterBy: field.optionsDependsOn && field.optionsFilterField ? {
322
+ field: field.optionsFilterField,
323
+ valueFromField: field.optionsDependsOn
324
+ } : void 0
325
+ } : void 0,
326
+ triggers: field.triggers.map((trigger) => ({
327
+ event: trigger.event,
328
+ action: trigger.action,
329
+ enabled: trigger.enabled,
330
+ debounceMs: trigger.debounceMs,
331
+ config: {}
332
+ }))
333
+ })),
334
+ layout: {
335
+ groups: normalizeBuilderFormEditorLayoutGroups(
336
+ values.layoutGroups,
337
+ values.fields,
338
+ values.subforms ?? []
339
+ )
340
+ },
341
+ subforms: (values.subforms ?? []).filter(
342
+ (subform) => subform.key && subform.label && subform.viewId !== BUILDER_EDITOR_NONE_VALUE && subform.parentField && subform.childField
343
+ ).map((subform) => ({
344
+ key: subform.key,
345
+ label: subform.label,
346
+ viewId: subform.viewId,
347
+ parentField: subform.parentField,
348
+ childField: subform.childField,
349
+ buttonLabel: subform.buttonLabel?.trim() || void 0,
350
+ icon: subform.icon?.trim() || void 0
351
+ }))
352
+ },
353
+ triggers: values.triggers.map((trigger) => ({
354
+ event: trigger.event,
355
+ action: "callApi",
356
+ enabled: trigger.enabled,
357
+ blocking: trigger.blocking,
358
+ config: { route: trigger.route }
359
+ })),
360
+ version: values.version
361
+ };
362
+ }
363
+ function builderListEditorInputFromValues(values) {
364
+ const source = values.sourceType === "dbTable" && values.sourceTable !== BUILDER_EDITOR_NONE_VALUE ? { type: "dbTable", tableName: values.sourceTable } : values.sourceType === "apiEndpoint" && values.apiBasePath ? { type: "apiEndpoint", basePath: values.apiBasePath } : null;
365
+ return {
366
+ title: values.title,
367
+ description: values.description || null,
368
+ source,
369
+ schema: { columns: values.columns },
370
+ triggers: values.triggers.map((trigger) => ({
371
+ event: trigger.event,
372
+ action: "callApi",
373
+ enabled: trigger.enabled,
374
+ blocking: trigger.blocking,
375
+ config: { route: trigger.route }
376
+ })),
377
+ version: values.version
378
+ };
379
+ }
380
+ function builderViewEditorInputFromValues(values, parseTriggers) {
381
+ return {
382
+ title: values.title,
383
+ description: values.description || null,
384
+ formId: values.formId === BUILDER_EDITOR_NONE_VALUE ? null : values.formId,
385
+ listId: values.listId === BUILDER_EDITOR_NONE_VALUE ? null : values.listId,
386
+ permissionRead: values.permissionRead || null,
387
+ permissionWrite: values.permissionWrite || null,
388
+ triggers: values.triggersText?.trim() ? parseTriggers(values.triggersText) : [],
389
+ version: values.version
390
+ };
391
+ }
392
+
393
+ // src/admin/BuilderDefaultEditorBodies.tsx
394
+ import { jsx, jsxs } from "react/jsx-runtime";
395
+ var styles = {
396
+ page: {
397
+ display: "grid",
398
+ gap: "1rem"
399
+ },
400
+ header: {
401
+ display: "flex",
402
+ justifyContent: "space-between",
403
+ gap: "1rem",
404
+ alignItems: "flex-start",
405
+ flexWrap: "wrap"
406
+ },
407
+ title: {
408
+ margin: 0,
409
+ fontSize: "1.5rem",
410
+ fontWeight: 650
411
+ },
412
+ description: {
413
+ margin: "0.25rem 0 0",
414
+ color: "var(--muted-foreground, #64748b)"
415
+ },
416
+ actions: {
417
+ display: "flex",
418
+ gap: "0.5rem",
419
+ flexWrap: "wrap"
420
+ },
421
+ section: {
422
+ border: "1px solid var(--border, #d4d4d8)",
423
+ borderRadius: "0.5rem",
424
+ background: "var(--background, #fff)",
425
+ overflow: "hidden"
426
+ },
427
+ sectionHeader: {
428
+ display: "flex",
429
+ justifyContent: "space-between",
430
+ gap: "1rem",
431
+ alignItems: "center",
432
+ padding: "0.75rem",
433
+ borderBottom: "1px solid var(--border, #d4d4d8)",
434
+ flexWrap: "wrap"
435
+ },
436
+ sectionTitle: {
437
+ margin: 0,
438
+ fontSize: "1rem",
439
+ fontWeight: 650
440
+ },
441
+ grid: {
442
+ display: "grid",
443
+ gap: "0.75rem",
444
+ padding: "0.75rem"
445
+ },
446
+ twoColumn: {
447
+ display: "grid",
448
+ gridTemplateColumns: "repeat(auto-fit, minmax(14rem, 1fr))",
449
+ gap: "0.75rem"
450
+ },
451
+ row: {
452
+ display: "grid",
453
+ gridTemplateColumns: "repeat(auto-fit, minmax(10rem, 1fr))",
454
+ gap: "0.5rem",
455
+ padding: "0.75rem",
456
+ borderBottom: "1px solid var(--border, #d4d4d8)"
457
+ },
458
+ field: {
459
+ display: "grid",
460
+ gap: "0.25rem",
461
+ fontSize: "0.875rem"
462
+ },
463
+ label: {
464
+ color: "var(--muted-foreground, #64748b)",
465
+ fontSize: "0.75rem",
466
+ fontWeight: 600
467
+ },
468
+ input: {
469
+ minWidth: 0,
470
+ border: "1px solid var(--border, #d4d4d8)",
471
+ borderRadius: "0.375rem",
472
+ padding: "0.5rem 0.625rem",
473
+ background: "var(--background, #fff)",
474
+ color: "inherit"
475
+ },
476
+ textarea: {
477
+ minWidth: 0,
478
+ minHeight: "5rem",
479
+ border: "1px solid var(--border, #d4d4d8)",
480
+ borderRadius: "0.375rem",
481
+ padding: "0.5rem 0.625rem",
482
+ background: "var(--background, #fff)",
483
+ color: "inherit",
484
+ resize: "vertical"
485
+ },
486
+ checkboxField: {
487
+ display: "flex",
488
+ alignItems: "center",
489
+ gap: "0.5rem",
490
+ fontSize: "0.875rem",
491
+ minHeight: "2.25rem"
492
+ },
493
+ button: {
494
+ border: "1px solid var(--border, #d4d4d8)",
495
+ borderRadius: "0.375rem",
496
+ background: "var(--background, #fff)",
497
+ color: "inherit",
498
+ cursor: "pointer",
499
+ padding: "0.5rem 0.75rem",
500
+ textDecoration: "none",
501
+ fontSize: "0.875rem"
502
+ },
503
+ primaryButton: {
504
+ border: "1px solid var(--primary, #18181b)",
505
+ borderRadius: "0.375rem",
506
+ background: "var(--primary, #18181b)",
507
+ color: "var(--primary-foreground, #fff)",
508
+ cursor: "pointer",
509
+ padding: "0.5rem 0.75rem",
510
+ textDecoration: "none",
511
+ fontSize: "0.875rem"
512
+ }
513
+ };
514
+ function optionItems(options) {
515
+ return options.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, children: option.label }, option.value));
516
+ }
517
+ function createBuilderDefaultFormEditorBody(options) {
518
+ return function BuilderDefaultFormEditorBody({
519
+ formId,
520
+ form,
521
+ fieldArray,
522
+ subformArray,
523
+ triggerArray,
524
+ fields,
525
+ sourceType,
526
+ sourceTable,
527
+ tables,
528
+ emptyField,
529
+ emptyTrigger,
530
+ isSaving,
531
+ importFieldsFromTable
532
+ }) {
533
+ return /* @__PURE__ */ jsxs("div", { style: styles.page, children: [
534
+ /* @__PURE__ */ jsxs("div", { style: styles.header, children: [
535
+ /* @__PURE__ */ jsxs("div", { children: [
536
+ /* @__PURE__ */ jsx("h1", { style: styles.title, children: formId ? "Edit Dynamic Form" : "New Dynamic Form" }),
537
+ /* @__PURE__ */ jsx("p", { style: styles.description, children: "Configure fields, source mapping, layout, and triggers." })
538
+ ] }),
539
+ /* @__PURE__ */ jsxs("div", { style: styles.actions, children: [
540
+ /* @__PURE__ */ jsx("a", { href: options.backHref, style: styles.button, children: "Cancel" }),
541
+ /* @__PURE__ */ jsx("button", { type: "submit", disabled: isSaving, style: styles.primaryButton, children: isSaving ? "Saving..." : "Save" })
542
+ ] })
543
+ ] }),
544
+ /* @__PURE__ */ jsxs("section", { style: styles.section, children: [
545
+ /* @__PURE__ */ jsx("div", { style: styles.sectionHeader, children: /* @__PURE__ */ jsx("h2", { style: styles.sectionTitle, children: "Details" }) }),
546
+ /* @__PURE__ */ jsxs("div", { style: { ...styles.grid, ...styles.twoColumn }, children: [
547
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
548
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Title" }),
549
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register("title", { required: true }) })
550
+ ] }),
551
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
552
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Description" }),
553
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register("description") })
554
+ ] }),
555
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
556
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Datasource" }),
557
+ /* @__PURE__ */ jsxs("select", { style: styles.input, ...form.register("sourceType"), children: [
558
+ /* @__PURE__ */ jsx("option", { value: "none", children: "None" }),
559
+ /* @__PURE__ */ jsx("option", { value: "dbTable", children: "DB table" }),
560
+ /* @__PURE__ */ jsx("option", { value: "apiEndpoint", children: "API endpoint" })
561
+ ] })
562
+ ] }),
563
+ sourceType === "dbTable" ? /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
564
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Table" }),
565
+ /* @__PURE__ */ jsxs("select", { style: styles.input, ...form.register("sourceTable"), children: [
566
+ /* @__PURE__ */ jsx("option", { value: BUILDER_EDITOR_NONE_VALUE, children: "Select table" }),
567
+ tables.map((table) => /* @__PURE__ */ jsx("option", { value: table.name, children: table.label ?? table.name }, table.name))
568
+ ] })
569
+ ] }) : null,
570
+ sourceType === "apiEndpoint" ? /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
571
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "API base path" }),
572
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register("apiBasePath") })
573
+ ] }) : null,
574
+ sourceType === "dbTable" ? /* @__PURE__ */ jsx("div", { style: { ...styles.field, justifyContent: "end" }, children: /* @__PURE__ */ jsx(
575
+ "button",
576
+ {
577
+ type: "button",
578
+ style: styles.button,
579
+ disabled: sourceTable === BUILDER_EDITOR_NONE_VALUE,
580
+ onClick: importFieldsFromTable,
581
+ children: "Import fields"
582
+ }
583
+ ) }) : null
584
+ ] })
585
+ ] }),
586
+ /* @__PURE__ */ jsxs("section", { style: styles.section, children: [
587
+ /* @__PURE__ */ jsxs("div", { style: styles.sectionHeader, children: [
588
+ /* @__PURE__ */ jsxs("div", { children: [
589
+ /* @__PURE__ */ jsx("h2", { style: styles.sectionTitle, children: "Fields" }),
590
+ /* @__PURE__ */ jsx("p", { style: styles.description, children: "Runtime form inputs." })
591
+ ] }),
592
+ /* @__PURE__ */ jsx(
593
+ "button",
594
+ {
595
+ type: "button",
596
+ style: styles.button,
597
+ onClick: () => {
598
+ const key = `field${fieldArray.fields.length + 1}`;
599
+ fieldArray.append({
600
+ ...emptyField,
601
+ key,
602
+ label: `Field ${fieldArray.fields.length + 1}`,
603
+ type: options.fieldTypeOptions[0]?.value
604
+ });
605
+ },
606
+ children: "Add field"
607
+ }
608
+ )
609
+ ] }),
610
+ fieldArray.fields.map((field, index) => /* @__PURE__ */ jsxs("div", { style: styles.row, children: [
611
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
612
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Key" }),
613
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`fields.${index}.key`) })
614
+ ] }),
615
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
616
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Label" }),
617
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`fields.${index}.label`) })
618
+ ] }),
619
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
620
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Type" }),
621
+ /* @__PURE__ */ jsx(
622
+ "select",
623
+ {
624
+ style: styles.input,
625
+ ...form.register(`fields.${index}.type`),
626
+ children: optionItems(options.fieldTypeOptions)
627
+ }
628
+ )
629
+ ] }),
630
+ /* @__PURE__ */ jsxs("label", { style: styles.checkboxField, children: [
631
+ /* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`fields.${index}.required`) }),
632
+ "Required"
633
+ ] }),
634
+ /* @__PURE__ */ jsxs("label", { style: styles.checkboxField, children: [
635
+ /* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`fields.${index}.hidden`) }),
636
+ "Hidden"
637
+ ] }),
638
+ /* @__PURE__ */ jsxs("label", { style: styles.checkboxField, children: [
639
+ /* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`fields.${index}.disabled`) }),
640
+ "Disabled"
641
+ ] }),
642
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
643
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Placeholder" }),
644
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`fields.${index}.placeholder`) })
645
+ ] }),
646
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
647
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Static options" }),
648
+ /* @__PURE__ */ jsx("textarea", { style: styles.textarea, ...form.register(`fields.${index}.optionsText`) })
649
+ ] }),
650
+ /* @__PURE__ */ jsx("div", { style: styles.actions, children: /* @__PURE__ */ jsx(
651
+ "button",
652
+ {
653
+ type: "button",
654
+ style: styles.button,
655
+ onClick: () => fieldArray.remove(index),
656
+ disabled: fieldArray.fields.length <= 1,
657
+ children: "Remove"
658
+ }
659
+ ) })
660
+ ] }, field.id))
661
+ ] }),
662
+ /* @__PURE__ */ jsxs("section", { style: styles.section, children: [
663
+ /* @__PURE__ */ jsxs("div", { style: styles.sectionHeader, children: [
664
+ /* @__PURE__ */ jsxs("div", { children: [
665
+ /* @__PURE__ */ jsx("h2", { style: styles.sectionTitle, children: "Layout" }),
666
+ /* @__PURE__ */ jsx("p", { style: styles.description, children: "Default layout can be regenerated from current fields." })
667
+ ] }),
668
+ /* @__PURE__ */ jsx(
669
+ "button",
670
+ {
671
+ type: "button",
672
+ style: styles.button,
673
+ onClick: () => form.setValue("layoutGroups", builderFormEditorDefaultLayoutGroups(fields), {
674
+ shouldDirty: true
675
+ }),
676
+ children: "Reset layout"
677
+ }
678
+ )
679
+ ] }),
680
+ form.watch("layoutGroups").map((group, groupIndex) => /* @__PURE__ */ jsxs("div", { style: styles.row, children: [
681
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
682
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Group title" }),
683
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`layoutGroups.${groupIndex}.title`) })
684
+ ] }),
685
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
686
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Columns" }),
687
+ /* @__PURE__ */ jsxs(
688
+ "select",
689
+ {
690
+ style: styles.input,
691
+ value: group.columns,
692
+ onChange: (event) => form.setValue(
693
+ `layoutGroups.${groupIndex}.columns`,
694
+ Number(event.target.value),
695
+ { shouldDirty: true }
696
+ ),
697
+ children: [
698
+ /* @__PURE__ */ jsx("option", { value: 6, children: "6" }),
699
+ /* @__PURE__ */ jsx("option", { value: 8, children: "8" }),
700
+ /* @__PURE__ */ jsx("option", { value: 12, children: "12" })
701
+ ]
702
+ }
703
+ )
704
+ ] }),
705
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
706
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Fields" }),
707
+ /* @__PURE__ */ jsx(
708
+ "input",
709
+ {
710
+ style: styles.input,
711
+ value: group.fields.map((item) => item.key).join(", "),
712
+ readOnly: true
713
+ }
714
+ )
715
+ ] })
716
+ ] }, group.id))
717
+ ] }),
718
+ /* @__PURE__ */ jsxs("section", { style: styles.section, children: [
719
+ /* @__PURE__ */ jsxs("div", { style: styles.sectionHeader, children: [
720
+ /* @__PURE__ */ jsxs("div", { children: [
721
+ /* @__PURE__ */ jsx("h2", { style: styles.sectionTitle, children: "Subforms" }),
722
+ /* @__PURE__ */ jsx("p", { style: styles.description, children: "Optional nested runtime view bindings." })
723
+ ] }),
724
+ /* @__PURE__ */ jsx(
725
+ "button",
726
+ {
727
+ type: "button",
728
+ style: styles.button,
729
+ onClick: () => subformArray.append({
730
+ key: `subform${subformArray.fields.length + 1}`,
731
+ label: `Subform ${subformArray.fields.length + 1}`,
732
+ viewId: BUILDER_EDITOR_NONE_VALUE,
733
+ parentField: "id",
734
+ childField: "parentId",
735
+ buttonLabel: "",
736
+ icon: ""
737
+ }),
738
+ children: "Add subform"
739
+ }
740
+ )
741
+ ] }),
742
+ subformArray.fields.map((subform, index) => /* @__PURE__ */ jsxs("div", { style: styles.row, children: [
743
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
744
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Key" }),
745
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`subforms.${index}.key`) })
746
+ ] }),
747
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
748
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Label" }),
749
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`subforms.${index}.label`) })
750
+ ] }),
751
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
752
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "View ID" }),
753
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`subforms.${index}.viewId`) })
754
+ ] }),
755
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
756
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Parent field" }),
757
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`subforms.${index}.parentField`) })
758
+ ] }),
759
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
760
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Child field" }),
761
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`subforms.${index}.childField`) })
762
+ ] }),
763
+ /* @__PURE__ */ jsx("button", { type: "button", style: styles.button, onClick: () => subformArray.remove(index), children: "Remove" })
764
+ ] }, subform.id))
765
+ ] }),
766
+ /* @__PURE__ */ jsxs("section", { style: styles.section, children: [
767
+ /* @__PURE__ */ jsxs("div", { style: styles.sectionHeader, children: [
768
+ /* @__PURE__ */ jsxs("div", { children: [
769
+ /* @__PURE__ */ jsx("h2", { style: styles.sectionTitle, children: "Form Triggers" }),
770
+ /* @__PURE__ */ jsx("p", { style: styles.description, children: "Optional API callbacks for lifecycle events." })
771
+ ] }),
772
+ /* @__PURE__ */ jsx("button", { type: "button", style: styles.button, onClick: () => triggerArray.append(emptyTrigger), children: "Add trigger" })
773
+ ] }),
774
+ triggerArray.fields.map((trigger, index) => /* @__PURE__ */ jsxs("div", { style: styles.row, children: [
775
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
776
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Event" }),
777
+ /* @__PURE__ */ jsx(
778
+ "select",
779
+ {
780
+ style: styles.input,
781
+ ...form.register(
782
+ `triggers.${index}.event`
783
+ ),
784
+ children: optionItems(options.formTriggerEventOptions)
785
+ }
786
+ )
787
+ ] }),
788
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
789
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Route" }),
790
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`triggers.${index}.route`) })
791
+ ] }),
792
+ /* @__PURE__ */ jsxs("label", { style: styles.checkboxField, children: [
793
+ /* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`triggers.${index}.enabled`) }),
794
+ "Enabled"
795
+ ] }),
796
+ /* @__PURE__ */ jsxs("label", { style: styles.checkboxField, children: [
797
+ /* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`triggers.${index}.blocking`) }),
798
+ "Blocking"
799
+ ] }),
800
+ /* @__PURE__ */ jsx("button", { type: "button", style: styles.button, onClick: () => triggerArray.remove(index), children: "Remove" })
801
+ ] }, trigger.id))
802
+ ] })
803
+ ] });
804
+ };
805
+ }
806
+ function createBuilderDefaultListEditorBody(options) {
807
+ return function BuilderDefaultListEditorBody({
808
+ listId,
809
+ form,
810
+ columnArray,
811
+ triggerArray,
812
+ sourceType,
813
+ sourceTable,
814
+ tables,
815
+ emptyColumn,
816
+ emptyTrigger,
817
+ isSaving,
818
+ importColumnsFromTable
819
+ }) {
820
+ return /* @__PURE__ */ jsxs("div", { style: styles.page, children: [
821
+ /* @__PURE__ */ jsxs("div", { style: styles.header, children: [
822
+ /* @__PURE__ */ jsxs("div", { children: [
823
+ /* @__PURE__ */ jsx("h1", { style: styles.title, children: listId ? "Edit Dynamic List" : "New Dynamic List" }),
824
+ /* @__PURE__ */ jsx("p", { style: styles.description, children: "Configure list columns, source mapping, and triggers." })
825
+ ] }),
826
+ /* @__PURE__ */ jsxs("div", { style: styles.actions, children: [
827
+ /* @__PURE__ */ jsx("a", { href: options.backHref, style: styles.button, children: "Cancel" }),
828
+ /* @__PURE__ */ jsx("button", { type: "submit", disabled: isSaving, style: styles.primaryButton, children: isSaving ? "Saving..." : "Save" })
829
+ ] })
830
+ ] }),
831
+ /* @__PURE__ */ jsxs("section", { style: styles.section, children: [
832
+ /* @__PURE__ */ jsx("div", { style: styles.sectionHeader, children: /* @__PURE__ */ jsx("h2", { style: styles.sectionTitle, children: "Details" }) }),
833
+ /* @__PURE__ */ jsxs("div", { style: { ...styles.grid, ...styles.twoColumn }, children: [
834
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
835
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Title" }),
836
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register("title", { required: true }) })
837
+ ] }),
838
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
839
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Description" }),
840
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register("description") })
841
+ ] }),
842
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
843
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Datasource" }),
844
+ /* @__PURE__ */ jsxs("select", { style: styles.input, ...form.register("sourceType"), children: [
845
+ /* @__PURE__ */ jsx("option", { value: "none", children: "None" }),
846
+ /* @__PURE__ */ jsx("option", { value: "dbTable", children: "DB table" }),
847
+ /* @__PURE__ */ jsx("option", { value: "apiEndpoint", children: "API endpoint" })
848
+ ] })
849
+ ] }),
850
+ sourceType === "dbTable" ? /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
851
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Table" }),
852
+ /* @__PURE__ */ jsxs("select", { style: styles.input, ...form.register("sourceTable"), children: [
853
+ /* @__PURE__ */ jsx("option", { value: BUILDER_EDITOR_NONE_VALUE, children: "Select table" }),
854
+ tables.map((table) => /* @__PURE__ */ jsx("option", { value: table.name, children: table.label ?? table.name }, table.name))
855
+ ] })
856
+ ] }) : null,
857
+ sourceType === "apiEndpoint" ? /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
858
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "API base path" }),
859
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register("apiBasePath") })
860
+ ] }) : null,
861
+ sourceType === "dbTable" ? /* @__PURE__ */ jsx("div", { style: { ...styles.field, justifyContent: "end" }, children: /* @__PURE__ */ jsx(
862
+ "button",
863
+ {
864
+ type: "button",
865
+ style: styles.button,
866
+ disabled: sourceTable === BUILDER_EDITOR_NONE_VALUE,
867
+ onClick: importColumnsFromTable,
868
+ children: "Import columns"
869
+ }
870
+ ) }) : null
871
+ ] })
872
+ ] }),
873
+ /* @__PURE__ */ jsxs("section", { style: styles.section, children: [
874
+ /* @__PURE__ */ jsxs("div", { style: styles.sectionHeader, children: [
875
+ /* @__PURE__ */ jsxs("div", { children: [
876
+ /* @__PURE__ */ jsx("h2", { style: styles.sectionTitle, children: "Columns" }),
877
+ /* @__PURE__ */ jsx("p", { style: styles.description, children: "Runtime list columns." })
878
+ ] }),
879
+ /* @__PURE__ */ jsx(
880
+ "button",
881
+ {
882
+ type: "button",
883
+ style: styles.button,
884
+ onClick: () => columnArray.append({
885
+ ...emptyColumn,
886
+ key: `field${columnArray.fields.length + 1}`,
887
+ label: `Column ${columnArray.fields.length + 1}`
888
+ }),
889
+ children: "Add column"
890
+ }
891
+ )
892
+ ] }),
893
+ columnArray.fields.map((column, index) => /* @__PURE__ */ jsxs("div", { style: styles.row, children: [
894
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
895
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Key" }),
896
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`columns.${index}.key`) })
897
+ ] }),
898
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
899
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Label" }),
900
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`columns.${index}.label`) })
901
+ ] }),
902
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
903
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Align" }),
904
+ /* @__PURE__ */ jsxs("select", { style: styles.input, ...form.register(`columns.${index}.align`), children: [
905
+ /* @__PURE__ */ jsx("option", { value: "left", children: "Left" }),
906
+ /* @__PURE__ */ jsx("option", { value: "right", children: "Right" })
907
+ ] })
908
+ ] }),
909
+ /* @__PURE__ */ jsxs("label", { style: styles.checkboxField, children: [
910
+ /* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`columns.${index}.sortable`) }),
911
+ "Sortable"
912
+ ] }),
913
+ /* @__PURE__ */ jsx(
914
+ "button",
915
+ {
916
+ type: "button",
917
+ style: styles.button,
918
+ onClick: () => columnArray.remove(index),
919
+ disabled: columnArray.fields.length <= 1,
920
+ children: "Remove"
921
+ }
922
+ )
923
+ ] }, column.id))
924
+ ] }),
925
+ /* @__PURE__ */ jsxs("section", { style: styles.section, children: [
926
+ /* @__PURE__ */ jsxs("div", { style: styles.sectionHeader, children: [
927
+ /* @__PURE__ */ jsxs("div", { children: [
928
+ /* @__PURE__ */ jsx("h2", { style: styles.sectionTitle, children: "List Triggers" }),
929
+ /* @__PURE__ */ jsx("p", { style: styles.description, children: "Optional API callbacks for list lifecycle events." })
930
+ ] }),
931
+ /* @__PURE__ */ jsx("button", { type: "button", style: styles.button, onClick: () => triggerArray.append(emptyTrigger), children: "Add trigger" })
932
+ ] }),
933
+ triggerArray.fields.map((trigger, index) => /* @__PURE__ */ jsxs("div", { style: styles.row, children: [
934
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
935
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Event" }),
936
+ /* @__PURE__ */ jsx(
937
+ "select",
938
+ {
939
+ style: styles.input,
940
+ ...form.register(
941
+ `triggers.${index}.event`
942
+ ),
943
+ children: optionItems(options.listTriggerEventOptions)
944
+ }
945
+ )
946
+ ] }),
947
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
948
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Route" }),
949
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`triggers.${index}.route`) })
950
+ ] }),
951
+ /* @__PURE__ */ jsxs("label", { style: styles.checkboxField, children: [
952
+ /* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`triggers.${index}.enabled`) }),
953
+ "Enabled"
954
+ ] }),
955
+ /* @__PURE__ */ jsxs("label", { style: styles.checkboxField, children: [
956
+ /* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`triggers.${index}.blocking`) }),
957
+ "Blocking"
958
+ ] }),
959
+ /* @__PURE__ */ jsx("button", { type: "button", style: styles.button, onClick: () => triggerArray.remove(index), children: "Remove" })
960
+ ] }, trigger.id))
961
+ ] })
962
+ ] });
963
+ };
964
+ }
965
+
966
+ // src/admin/BuilderDefaultEntityManager.tsx
967
+ import { useMemo, useState } from "react";
968
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
969
+ var styles2 = {
970
+ page: {
971
+ display: "grid",
972
+ gap: "1rem"
973
+ },
974
+ header: {
975
+ display: "flex",
976
+ justifyContent: "space-between",
977
+ gap: "1rem",
978
+ alignItems: "flex-start",
979
+ flexWrap: "wrap"
980
+ },
981
+ title: {
982
+ margin: 0,
983
+ fontSize: "1.5rem",
984
+ fontWeight: 650
985
+ },
986
+ description: {
987
+ margin: "0.25rem 0 0",
988
+ color: "var(--muted-foreground, #64748b)"
989
+ },
990
+ button: {
991
+ border: "1px solid var(--border, #d4d4d8)",
992
+ borderRadius: "0.375rem",
993
+ background: "var(--background, #fff)",
994
+ color: "inherit",
995
+ cursor: "pointer",
996
+ padding: "0.5rem 0.75rem",
997
+ textDecoration: "none",
998
+ fontSize: "0.875rem"
999
+ },
1000
+ primaryButton: {
1001
+ border: "1px solid var(--primary, #18181b)",
1002
+ borderRadius: "0.375rem",
1003
+ background: "var(--primary, #18181b)",
1004
+ color: "var(--primary-foreground, #fff)",
1005
+ cursor: "pointer",
1006
+ padding: "0.5rem 0.75rem",
1007
+ textDecoration: "none",
1008
+ fontSize: "0.875rem"
1009
+ },
1010
+ card: {
1011
+ border: "1px solid var(--border, #d4d4d8)",
1012
+ borderRadius: "0.5rem",
1013
+ overflow: "hidden",
1014
+ background: "var(--background, #fff)"
1015
+ },
1016
+ toolbar: {
1017
+ padding: "0.75rem",
1018
+ borderBottom: "1px solid var(--border, #d4d4d8)"
1019
+ },
1020
+ input: {
1021
+ width: "100%",
1022
+ maxWidth: "24rem",
1023
+ border: "1px solid var(--border, #d4d4d8)",
1024
+ borderRadius: "0.375rem",
1025
+ padding: "0.5rem 0.75rem",
1026
+ background: "var(--background, #fff)",
1027
+ color: "inherit"
1028
+ },
1029
+ tableWrap: {
1030
+ overflowX: "auto"
1031
+ },
1032
+ table: {
1033
+ width: "100%",
1034
+ borderCollapse: "collapse",
1035
+ fontSize: "0.875rem"
1036
+ },
1037
+ th: {
1038
+ padding: "0.75rem",
1039
+ borderBottom: "1px solid var(--border, #d4d4d8)",
1040
+ textAlign: "left",
1041
+ color: "var(--muted-foreground, #64748b)",
1042
+ fontWeight: 600,
1043
+ whiteSpace: "nowrap"
1044
+ },
1045
+ td: {
1046
+ padding: "0.75rem",
1047
+ borderBottom: "1px solid var(--border, #d4d4d8)",
1048
+ verticalAlign: "top"
1049
+ },
1050
+ actions: {
1051
+ display: "flex",
1052
+ justifyContent: "flex-end",
1053
+ gap: "0.5rem",
1054
+ flexWrap: "wrap"
1055
+ },
1056
+ empty: {
1057
+ padding: "2rem",
1058
+ textAlign: "center",
1059
+ color: "var(--muted-foreground, #64748b)"
1060
+ }
1061
+ };
1062
+ function createBuilderDefaultEntityManagerComponent(deps) {
1063
+ return function BuilderDefaultEntityManager() {
1064
+ const [state, setState] = useState({
1065
+ page: 1,
1066
+ pageSize: 20,
1067
+ search: ""
1068
+ });
1069
+ const query = deps.hooks.useEntities(useMemo(() => deps.buildQuery(state), [state]));
1070
+ const remove = deps.hooks.useDelete();
1071
+ const replicate = deps.hooks.useReplicate();
1072
+ const items = query.data?.items ?? [];
1073
+ const onReplicate = async (entity) => {
1074
+ const title = window.prompt(
1075
+ deps.labels.replicatePrompt(entity),
1076
+ deps.labels.replicateDefaultTitle(entity)
1077
+ );
1078
+ if (!title) return;
1079
+ await replicate.mutateAsync({ id: entity.id, input: { title } });
1080
+ };
1081
+ const onDelete = async (entity) => {
1082
+ if (!window.confirm(deps.labels.deleteConfirm(entity))) return;
1083
+ await remove.mutateAsync(entity.id);
1084
+ };
1085
+ return /* @__PURE__ */ jsxs2("section", { style: styles2.page, children: [
1086
+ /* @__PURE__ */ jsxs2("div", { style: styles2.header, children: [
1087
+ /* @__PURE__ */ jsxs2("div", { children: [
1088
+ /* @__PURE__ */ jsx2("h1", { style: styles2.title, children: deps.labels.title }),
1089
+ /* @__PURE__ */ jsx2("p", { style: styles2.description, children: deps.labels.description })
1090
+ ] }),
1091
+ deps.createHref ? /* @__PURE__ */ jsx2("a", { href: deps.createHref, style: styles2.primaryButton, children: deps.labels.addLabel }) : null
1092
+ ] }),
1093
+ /* @__PURE__ */ jsxs2("div", { style: styles2.card, children: [
1094
+ /* @__PURE__ */ jsx2("div", { style: styles2.toolbar, children: /* @__PURE__ */ jsx2(
1095
+ "input",
1096
+ {
1097
+ style: styles2.input,
1098
+ placeholder: deps.labels.searchPlaceholder,
1099
+ value: state.search,
1100
+ onChange: (event) => setState((current) => ({ ...current, page: 1, search: event.target.value }))
1101
+ }
1102
+ ) }),
1103
+ /* @__PURE__ */ jsx2("div", { style: styles2.tableWrap, children: /* @__PURE__ */ jsxs2("table", { style: styles2.table, children: [
1104
+ /* @__PURE__ */ jsx2("thead", { children: /* @__PURE__ */ jsxs2("tr", { children: [
1105
+ /* @__PURE__ */ jsx2("th", { style: styles2.th, children: deps.labels.title }),
1106
+ /* @__PURE__ */ jsx2("th", { style: styles2.th, children: "Detail" }),
1107
+ /* @__PURE__ */ jsx2("th", { style: styles2.th, children: "Description" }),
1108
+ /* @__PURE__ */ jsx2("th", { style: { ...styles2.th, textAlign: "right" }, children: "Actions" })
1109
+ ] }) }),
1110
+ /* @__PURE__ */ jsx2("tbody", { children: items.map((entity) => /* @__PURE__ */ jsxs2("tr", { children: [
1111
+ /* @__PURE__ */ jsx2("td", { style: styles2.td, children: /* @__PURE__ */ jsx2("a", { href: deps.editHref(entity), children: entity.title }) }),
1112
+ /* @__PURE__ */ jsx2("td", { style: styles2.td, children: deps.getDetail?.(entity) ?? "-" }),
1113
+ /* @__PURE__ */ jsx2("td", { style: styles2.td, children: entity.description || "-" }),
1114
+ /* @__PURE__ */ jsx2("td", { style: styles2.td, children: /* @__PURE__ */ jsxs2("div", { style: styles2.actions, children: [
1115
+ deps.runtimeHref ? /* @__PURE__ */ jsx2("a", { href: deps.runtimeHref(entity), style: styles2.button, children: deps.labels.runtimeLabel }) : null,
1116
+ /* @__PURE__ */ jsx2("a", { href: deps.editHref(entity), style: styles2.button, children: deps.labels.editLabel }),
1117
+ /* @__PURE__ */ jsx2(
1118
+ "button",
1119
+ {
1120
+ type: "button",
1121
+ style: styles2.button,
1122
+ onClick: () => void onReplicate(entity),
1123
+ children: deps.labels.replicateLabel
1124
+ }
1125
+ ),
1126
+ /* @__PURE__ */ jsx2(
1127
+ "button",
1128
+ {
1129
+ type: "button",
1130
+ style: styles2.button,
1131
+ disabled: remove.isPending,
1132
+ onClick: () => void onDelete(entity),
1133
+ children: deps.labels.deleteLabel
1134
+ }
1135
+ )
1136
+ ] }) })
1137
+ ] }, entity.id)) })
1138
+ ] }) }),
1139
+ query.isPending ? /* @__PURE__ */ jsx2("div", { style: styles2.empty, children: "Loading..." }) : null,
1140
+ query.isError ? /* @__PURE__ */ jsx2("div", { style: styles2.empty, children: "Failed to load." }) : null,
1141
+ !query.isPending && !query.isError && items.length === 0 ? /* @__PURE__ */ jsxs2("div", { style: styles2.empty, children: [
1142
+ /* @__PURE__ */ jsx2("strong", { children: deps.labels.emptyTitle }),
1143
+ /* @__PURE__ */ jsx2("div", { children: deps.labels.emptyDescription })
1144
+ ] }) : null
1145
+ ] })
1146
+ ] });
1147
+ };
1148
+ }
1149
+
1150
+ // src/admin/BuilderDefaultViewEditorPage.tsx
1151
+ import { useEffect } from "react";
1152
+ import { useForm } from "react-hook-form";
1153
+ import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1154
+ var styles3 = {
1155
+ page: {
1156
+ display: "grid",
1157
+ gap: "1rem"
1158
+ },
1159
+ header: {
1160
+ display: "flex",
1161
+ justifyContent: "space-between",
1162
+ gap: "1rem",
1163
+ alignItems: "flex-start",
1164
+ flexWrap: "wrap"
1165
+ },
1166
+ title: {
1167
+ margin: 0,
1168
+ fontSize: "1.5rem",
1169
+ fontWeight: 650
1170
+ },
1171
+ description: {
1172
+ margin: "0.25rem 0 0",
1173
+ color: "var(--muted-foreground, #64748b)"
1174
+ },
1175
+ actions: {
1176
+ display: "flex",
1177
+ gap: "0.5rem",
1178
+ flexWrap: "wrap"
1179
+ },
1180
+ section: {
1181
+ border: "1px solid var(--border, #d4d4d8)",
1182
+ borderRadius: "0.5rem",
1183
+ background: "var(--background, #fff)",
1184
+ overflow: "hidden"
1185
+ },
1186
+ grid: {
1187
+ display: "grid",
1188
+ gridTemplateColumns: "repeat(auto-fit, minmax(14rem, 1fr))",
1189
+ gap: "0.75rem",
1190
+ padding: "0.75rem"
1191
+ },
1192
+ field: {
1193
+ display: "grid",
1194
+ gap: "0.25rem",
1195
+ fontSize: "0.875rem"
1196
+ },
1197
+ label: {
1198
+ color: "var(--muted-foreground, #64748b)",
1199
+ fontSize: "0.75rem",
1200
+ fontWeight: 600
1201
+ },
1202
+ input: {
1203
+ minWidth: 0,
1204
+ border: "1px solid var(--border, #d4d4d8)",
1205
+ borderRadius: "0.375rem",
1206
+ padding: "0.5rem 0.625rem",
1207
+ background: "var(--background, #fff)",
1208
+ color: "inherit"
1209
+ },
1210
+ textarea: {
1211
+ minWidth: 0,
1212
+ minHeight: "8rem",
1213
+ border: "1px solid var(--border, #d4d4d8)",
1214
+ borderRadius: "0.375rem",
1215
+ padding: "0.5rem 0.625rem",
1216
+ background: "var(--background, #fff)",
1217
+ color: "inherit",
1218
+ resize: "vertical"
1219
+ },
1220
+ button: {
1221
+ border: "1px solid var(--border, #d4d4d8)",
1222
+ borderRadius: "0.375rem",
1223
+ background: "var(--background, #fff)",
1224
+ color: "inherit",
1225
+ cursor: "pointer",
1226
+ padding: "0.5rem 0.75rem",
1227
+ textDecoration: "none",
1228
+ fontSize: "0.875rem"
1229
+ },
1230
+ primaryButton: {
1231
+ border: "1px solid var(--primary, #18181b)",
1232
+ borderRadius: "0.375rem",
1233
+ background: "var(--primary, #18181b)",
1234
+ color: "var(--primary-foreground, #fff)",
1235
+ cursor: "pointer",
1236
+ padding: "0.5rem 0.75rem",
1237
+ textDecoration: "none",
1238
+ fontSize: "0.875rem"
1239
+ },
1240
+ state: {
1241
+ color: "var(--muted-foreground, #64748b)",
1242
+ fontSize: "0.875rem"
1243
+ }
1244
+ };
1245
+ var defaultEmptyValues = {
1246
+ title: "",
1247
+ description: "",
1248
+ formId: BUILDER_EDITOR_NONE_VALUE,
1249
+ listId: BUILDER_EDITOR_NONE_VALUE,
1250
+ permissionRead: "",
1251
+ permissionWrite: "",
1252
+ triggersText: "[]",
1253
+ version: 0
1254
+ };
1255
+ function createBuilderDefaultViewEditorPage(options) {
1256
+ const defaultPermission = options.defaultPermission ?? "";
1257
+ const showPermissions = options.permissionOptions.length > 0;
1258
+ return function BuilderDefaultViewEditorPage({ viewId }) {
1259
+ const view = options.hooks.useBuilderView(viewId);
1260
+ const forms = options.hooks.useBuilderFormOptions();
1261
+ const lists = options.hooks.useBuilderListOptions();
1262
+ const save = options.hooks.useSaveBuilderView();
1263
+ const form = useForm({
1264
+ defaultValues: {
1265
+ ...defaultEmptyValues,
1266
+ permissionRead: defaultPermission,
1267
+ permissionWrite: defaultPermission
1268
+ }
1269
+ });
1270
+ useEffect(() => {
1271
+ if (viewId && !view.data) return;
1272
+ form.reset(
1273
+ builderViewEditorValuesFromEntity(
1274
+ view.data ?? null,
1275
+ {
1276
+ ...defaultEmptyValues,
1277
+ permissionRead: defaultPermission,
1278
+ permissionWrite: defaultPermission
1279
+ },
1280
+ defaultPermission
1281
+ )
1282
+ );
1283
+ }, [form, view.data, viewId]);
1284
+ const onSubmit = form.handleSubmit(async (values) => {
1285
+ try {
1286
+ const input = builderViewEditorInputFromValues(values, options.parseTriggers);
1287
+ const saved = await save.mutateAsync({
1288
+ id: viewId,
1289
+ input
1290
+ });
1291
+ options.notifySuccess?.(viewId ? "View saved" : "View created");
1292
+ if (!viewId) {
1293
+ window.location.assign(options.editHref(saved.id));
1294
+ }
1295
+ } catch (error) {
1296
+ if (options.notifyError) options.notifyError(error);
1297
+ else throw error;
1298
+ }
1299
+ });
1300
+ if (viewId && view.isPending) {
1301
+ return /* @__PURE__ */ jsx3("div", { style: styles3.state, children: "Loading..." });
1302
+ }
1303
+ if (viewId && view.isError) {
1304
+ return /* @__PURE__ */ jsx3("div", { style: styles3.state, children: "Failed to load view." });
1305
+ }
1306
+ return /* @__PURE__ */ jsxs3("form", { onSubmit, noValidate: true, style: styles3.page, children: [
1307
+ /* @__PURE__ */ jsxs3("div", { style: styles3.header, children: [
1308
+ /* @__PURE__ */ jsxs3("div", { children: [
1309
+ /* @__PURE__ */ jsx3("h1", { style: styles3.title, children: viewId ? "Edit Dynamic View" : "New Dynamic View" }),
1310
+ /* @__PURE__ */ jsx3("p", { style: styles3.description, children: "Connect a form and list into a runtime screen." })
1311
+ ] }),
1312
+ /* @__PURE__ */ jsxs3("div", { style: styles3.actions, children: [
1313
+ /* @__PURE__ */ jsx3("a", { href: options.backHref, style: styles3.button, children: "Cancel" }),
1314
+ /* @__PURE__ */ jsx3("button", { type: "submit", disabled: save.isPending, style: styles3.primaryButton, children: save.isPending ? "Saving..." : "Save" })
1315
+ ] })
1316
+ ] }),
1317
+ /* @__PURE__ */ jsx3("section", { style: styles3.section, children: /* @__PURE__ */ jsxs3("div", { style: styles3.grid, children: [
1318
+ /* @__PURE__ */ jsxs3("label", { style: styles3.field, children: [
1319
+ /* @__PURE__ */ jsx3("span", { style: styles3.label, children: "Title" }),
1320
+ /* @__PURE__ */ jsx3("input", { style: styles3.input, ...form.register("title", { required: true }) })
1321
+ ] }),
1322
+ /* @__PURE__ */ jsxs3("label", { style: styles3.field, children: [
1323
+ /* @__PURE__ */ jsx3("span", { style: styles3.label, children: "Description" }),
1324
+ /* @__PURE__ */ jsx3("input", { style: styles3.input, ...form.register("description") })
1325
+ ] }),
1326
+ /* @__PURE__ */ jsxs3("label", { style: styles3.field, children: [
1327
+ /* @__PURE__ */ jsx3("span", { style: styles3.label, children: "Form" }),
1328
+ /* @__PURE__ */ jsxs3("select", { style: styles3.input, ...form.register("formId"), children: [
1329
+ /* @__PURE__ */ jsx3("option", { value: BUILDER_EDITOR_NONE_VALUE, children: "No form" }),
1330
+ (forms.data ?? []).map((item) => /* @__PURE__ */ jsx3("option", { value: item.id, children: item.title }, item.id))
1331
+ ] })
1332
+ ] }),
1333
+ /* @__PURE__ */ jsxs3("label", { style: styles3.field, children: [
1334
+ /* @__PURE__ */ jsx3("span", { style: styles3.label, children: "List" }),
1335
+ /* @__PURE__ */ jsxs3("select", { style: styles3.input, ...form.register("listId"), children: [
1336
+ /* @__PURE__ */ jsx3("option", { value: BUILDER_EDITOR_NONE_VALUE, children: "No list" }),
1337
+ (lists.data ?? []).map((item) => /* @__PURE__ */ jsx3("option", { value: item.id, children: item.title }, item.id))
1338
+ ] })
1339
+ ] }),
1340
+ showPermissions ? /* @__PURE__ */ jsxs3(Fragment, { children: [
1341
+ /* @__PURE__ */ jsxs3("label", { style: styles3.field, children: [
1342
+ /* @__PURE__ */ jsx3("span", { style: styles3.label, children: "Read permission" }),
1343
+ /* @__PURE__ */ jsxs3("select", { style: styles3.input, ...form.register("permissionRead"), children: [
1344
+ /* @__PURE__ */ jsx3("option", { value: "", children: "Authenticated users" }),
1345
+ options.permissionOptions.map((permission) => /* @__PURE__ */ jsx3("option", { value: permission.value, children: permission.label }, permission.value))
1346
+ ] })
1347
+ ] }),
1348
+ /* @__PURE__ */ jsxs3("label", { style: styles3.field, children: [
1349
+ /* @__PURE__ */ jsx3("span", { style: styles3.label, children: "Write permission" }),
1350
+ /* @__PURE__ */ jsxs3("select", { style: styles3.input, ...form.register("permissionWrite"), children: [
1351
+ /* @__PURE__ */ jsx3("option", { value: "", children: "Authenticated users" }),
1352
+ options.permissionOptions.map((permission) => /* @__PURE__ */ jsx3("option", { value: permission.value, children: permission.label }, permission.value))
1353
+ ] })
1354
+ ] })
1355
+ ] }) : null,
1356
+ /* @__PURE__ */ jsxs3("label", { style: { ...styles3.field, gridColumn: "1 / -1" }, children: [
1357
+ /* @__PURE__ */ jsx3("span", { style: styles3.label, children: "Triggers JSON" }),
1358
+ /* @__PURE__ */ jsx3("textarea", { style: styles3.textarea, ...form.register("triggersText") })
1359
+ ] })
1360
+ ] }) })
1361
+ ] });
1362
+ };
1363
+ }
1364
+
1365
+ // src/admin/BuilderEditorPage.tsx
1366
+ import { useEffect as useEffect2 } from "react";
1367
+ import {
1368
+ FormProvider,
1369
+ useFieldArray,
1370
+ useForm as useForm2,
1371
+ useWatch
1372
+ } from "react-hook-form";
1373
+ import { jsx as jsx4 } from "react/jsx-runtime";
1374
+ function createBuilderFormEditorPageComponent(deps) {
1375
+ return function BuilderFormEditorPage({ formId }) {
1376
+ const Body = deps.Body;
1377
+ const entityQuery = deps.hooks.useEntity(formId);
1378
+ const tables = deps.hooks.useTables();
1379
+ const save = deps.hooks.useSave();
1380
+ const form = useForm2({
1381
+ resolver: deps.resolver,
1382
+ defaultValues: deps.emptyValues
1383
+ });
1384
+ const fieldArray = useFieldArray({ control: form.control, name: "fields" });
1385
+ const subformArray = useFieldArray({ control: form.control, name: "subforms" });
1386
+ const triggerArray = useFieldArray({ control: form.control, name: "triggers" });
1387
+ const fields = useWatch({ control: form.control, name: "fields" }) ?? [];
1388
+ const subforms = useWatch({ control: form.control, name: "subforms" }) ?? [];
1389
+ const sourceType = useWatch({ control: form.control, name: "sourceType" });
1390
+ const sourceTable = useWatch({ control: form.control, name: "sourceTable" });
1391
+ useEffect2(() => {
1392
+ if (formId && !entityQuery.data) return;
1393
+ form.reset(builderFormEditorValuesFromEntity(entityQuery.data ?? null, deps.emptyValues));
1394
+ }, [entityQuery.data, form, formId]);
1395
+ const importFieldsFromTable = () => {
1396
+ const table = tables.data?.find((item) => item.name === sourceTable);
1397
+ if (!table) return;
1398
+ const nextFields = builderFormEditorFieldsFromTable(table);
1399
+ fieldArray.replace(nextFields);
1400
+ form.setValue("layoutGroups", builderFormEditorDefaultLayoutGroups(nextFields), {
1401
+ shouldDirty: true
1402
+ });
1403
+ };
1404
+ const onSubmit = form.handleSubmit(async (values) => {
1405
+ try {
1406
+ const saved = await save.mutateAsync({ id: formId, input: deps.buildInput(values) });
1407
+ deps.notifications.success(formId ? deps.labels.saved : deps.labels.created);
1408
+ if (!formId) deps.navigateAfterCreate(saved);
1409
+ } catch (error) {
1410
+ deps.notifications.error(error);
1411
+ }
1412
+ });
1413
+ if (formId && entityQuery.isPending) {
1414
+ return /* @__PURE__ */ jsx4("div", { className: "text-muted-foreground text-sm", children: deps.states.loading });
1415
+ }
1416
+ if (formId && entityQuery.isError) {
1417
+ return /* @__PURE__ */ jsx4("div", { className: "text-destructive text-sm", children: deps.states.error });
1418
+ }
1419
+ return /* @__PURE__ */ jsx4(FormProvider, { ...form, children: /* @__PURE__ */ jsx4("form", { onSubmit, noValidate: true, className: "space-y-6", children: /* @__PURE__ */ jsx4(
1420
+ Body,
1421
+ {
1422
+ formId,
1423
+ form,
1424
+ fieldArray,
1425
+ subformArray,
1426
+ triggerArray,
1427
+ fields,
1428
+ subforms,
1429
+ sourceType,
1430
+ sourceTable,
1431
+ tables: tables.data ?? [],
1432
+ emptyField: deps.emptyField,
1433
+ emptyTrigger: deps.emptyTrigger,
1434
+ isSaving: save.isPending,
1435
+ importFieldsFromTable
1436
+ }
1437
+ ) }) });
1438
+ };
1439
+ }
1440
+ function createBuilderListEditorPageComponent(deps) {
1441
+ return function BuilderListEditorPage({ listId }) {
1442
+ const Body = deps.Body;
1443
+ const entityQuery = deps.hooks.useEntity(listId);
1444
+ const tables = deps.hooks.useTables();
1445
+ const save = deps.hooks.useSave();
1446
+ const form = useForm2({
1447
+ resolver: deps.resolver,
1448
+ defaultValues: deps.emptyValues
1449
+ });
1450
+ const columnArray = useFieldArray({ control: form.control, name: "columns" });
1451
+ const triggerArray = useFieldArray({ control: form.control, name: "triggers" });
1452
+ const sourceType = useWatch({ control: form.control, name: "sourceType" });
1453
+ const sourceTable = useWatch({ control: form.control, name: "sourceTable" });
1454
+ useEffect2(() => {
1455
+ if (listId && !entityQuery.data) return;
1456
+ form.reset(builderListEditorValuesFromEntity(entityQuery.data ?? null, deps.emptyValues));
1457
+ }, [entityQuery.data, form, listId]);
1458
+ const importColumnsFromTable = () => {
1459
+ const table = tables.data?.find((item) => item.name === sourceTable);
1460
+ if (!table) return;
1461
+ columnArray.replace(builderListEditorColumnsFromTable(table));
1462
+ };
1463
+ const onSubmit = form.handleSubmit(async (values) => {
1464
+ try {
1465
+ const saved = await save.mutateAsync({ id: listId, input: deps.buildInput(values) });
1466
+ deps.notifications.success(listId ? deps.labels.saved : deps.labels.created);
1467
+ if (!listId) deps.navigateAfterCreate(saved);
1468
+ } catch (error) {
1469
+ deps.notifications.error(error);
1470
+ }
1471
+ });
1472
+ if (listId && entityQuery.isPending) {
1473
+ return /* @__PURE__ */ jsx4("div", { className: "text-muted-foreground text-sm", children: deps.states.loading });
1474
+ }
1475
+ if (listId && entityQuery.isError) {
1476
+ return /* @__PURE__ */ jsx4("div", { className: "text-destructive text-sm", children: deps.states.error });
1477
+ }
1478
+ return /* @__PURE__ */ jsx4(FormProvider, { ...form, children: /* @__PURE__ */ jsx4("form", { onSubmit, noValidate: true, className: "space-y-6", children: /* @__PURE__ */ jsx4(
1479
+ Body,
1480
+ {
1481
+ listId,
1482
+ form,
1483
+ columnArray,
1484
+ triggerArray,
1485
+ sourceType,
1486
+ sourceTable,
1487
+ tables: tables.data ?? [],
1488
+ emptyColumn: deps.emptyColumn,
1489
+ emptyTrigger: deps.emptyTrigger,
1490
+ isSaving: save.isPending,
1491
+ importColumnsFromTable
1492
+ }
1493
+ ) }) });
1494
+ };
1495
+ }
1496
+
1497
+ // src/admin/BuilderAdminPages.tsx
1498
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1499
+ var defaultFieldTypeOptions = [
1500
+ { value: "text", label: "Text" },
1501
+ { value: "textarea", label: "Textarea" },
1502
+ { value: "number", label: "Number" },
1503
+ { value: "money", label: "Money" },
1504
+ { value: "select", label: "Select" },
1505
+ { value: "checkbox", label: "Checkbox" },
1506
+ { value: "date", label: "Date" }
1507
+ ];
1508
+ var defaultFormTriggerEventOptions = [
1509
+ { value: "beforeCreate", label: "Before create" },
1510
+ { value: "afterCreate", label: "After create" },
1511
+ { value: "beforeUpdate", label: "Before update" },
1512
+ { value: "afterUpdate", label: "After update" }
1513
+ ];
1514
+ var defaultListTriggerEventOptions = [
1515
+ { value: "beforeRead", label: "Before read" },
1516
+ { value: "afterRead", label: "After read" },
1517
+ { value: "beforeDelete", label: "Before delete" },
1518
+ { value: "afterDelete", label: "After delete" }
1519
+ ];
1520
+ var defaultFieldTriggerEventOptions = [
1521
+ { value: "onChange", label: "On change" },
1522
+ { value: "onBlur", label: "On blur" }
1523
+ ];
1524
+ var defaultPermissionOptions = [];
1525
+ function parseJsonArray(value) {
1526
+ const parsed = JSON.parse(value);
1527
+ return Array.isArray(parsed) ? parsed : [];
1528
+ }
1529
+ function joinPath(base, path) {
1530
+ return `${base.replace(/\/$/, "")}/${path.replace(/^\//, "")}`;
1531
+ }
1532
+ function defaultQuery(state) {
1533
+ return {
1534
+ page: state.page,
1535
+ pageSize: state.pageSize,
1536
+ search: state.search || void 0
1537
+ };
1538
+ }
1539
+ function detail(entity) {
1540
+ return entity.key ?? entity.id;
1541
+ }
1542
+ var homeStyles = {
1543
+ page: {
1544
+ display: "grid",
1545
+ gap: "1rem"
1546
+ },
1547
+ headerTitle: {
1548
+ margin: 0,
1549
+ fontSize: "1.5rem",
1550
+ fontWeight: 650
1551
+ },
1552
+ description: {
1553
+ margin: "0.25rem 0 0",
1554
+ color: "var(--muted-foreground, #64748b)"
1555
+ },
1556
+ grid: {
1557
+ display: "grid",
1558
+ gridTemplateColumns: "repeat(auto-fit, minmax(13rem, 1fr))",
1559
+ gap: "0.75rem"
1560
+ },
1561
+ card: {
1562
+ border: "1px solid var(--border, #d4d4d8)",
1563
+ borderRadius: "0.5rem",
1564
+ padding: "1rem",
1565
+ background: "var(--background, #fff)",
1566
+ color: "inherit",
1567
+ textDecoration: "none"
1568
+ },
1569
+ cardTitle: {
1570
+ margin: 0,
1571
+ fontSize: "1rem",
1572
+ fontWeight: 650
1573
+ }
1574
+ };
1575
+ function createBuilderAdminPages({
1576
+ hooks,
1577
+ routes = {},
1578
+ fieldTypeOptions = defaultFieldTypeOptions,
1579
+ formTriggerEventOptions = defaultFormTriggerEventOptions,
1580
+ listTriggerEventOptions = defaultListTriggerEventOptions,
1581
+ fieldTriggerEventOptions = defaultFieldTriggerEventOptions,
1582
+ permissionOptions = defaultPermissionOptions,
1583
+ defaultPermission = "",
1584
+ notifySuccess,
1585
+ notifyError,
1586
+ parseViewTriggers = parseJsonArray
1587
+ }) {
1588
+ const adminBasePath = routes.adminBasePath ?? "/admin/dev/builder";
1589
+ const runtimeBasePath = routes.runtimeBasePath ?? "/admin/winu";
1590
+ const formsPath = routes.formsPath ?? joinPath(adminBasePath, "forms");
1591
+ const newFormPath = routes.newFormPath ?? joinPath(formsPath, "new");
1592
+ const editFormPath = routes.editFormPath ?? ((id) => `${joinPath(formsPath, "edit")}?id=${encodeURIComponent(id)}`);
1593
+ const runtimeFormPath = routes.runtimeFormPath ?? ((id) => `${joinPath(runtimeBasePath, "form")}?id=${encodeURIComponent(id)}`);
1594
+ const listsPath = routes.listsPath ?? joinPath(adminBasePath, "lists");
1595
+ const newListPath = routes.newListPath ?? joinPath(listsPath, "new");
1596
+ const editListPath = routes.editListPath ?? ((id) => `${joinPath(listsPath, "edit")}?id=${encodeURIComponent(id)}`);
1597
+ const runtimeListPath = routes.runtimeListPath ?? ((id) => `${joinPath(runtimeBasePath, "list")}?id=${encodeURIComponent(id)}`);
1598
+ const viewsPath = routes.viewsPath ?? joinPath(adminBasePath, "views");
1599
+ const newViewPath = routes.newViewPath ?? joinPath(viewsPath, "new");
1600
+ const editViewPath = routes.editViewPath ?? ((id) => `${joinPath(viewsPath, "edit")}?id=${encodeURIComponent(id)}`);
1601
+ const runtimeViewPath = routes.runtimeViewPath ?? ((id) => `${joinPath(runtimeBasePath, "view")}?id=${encodeURIComponent(id)}`);
1602
+ const formFieldType = fieldTypeOptions[0]?.value ?? "text";
1603
+ const formTriggerEvent = formTriggerEventOptions[0]?.value ?? "beforeCreate";
1604
+ const listTriggerEvent = listTriggerEventOptions[0]?.value ?? "beforeRead";
1605
+ const emptyField = {
1606
+ key: "name",
1607
+ label: "Name",
1608
+ type: formFieldType,
1609
+ required: true,
1610
+ hidden: false,
1611
+ disabled: false,
1612
+ placeholder: "",
1613
+ optionsText: "",
1614
+ optionsMode: "static",
1615
+ optionsTable: BUILDER_EDITOR_NONE_VALUE,
1616
+ optionsValueField: BUILDER_EDITOR_NONE_VALUE,
1617
+ optionsLabelField: BUILDER_EDITOR_NONE_VALUE,
1618
+ optionsSearchFieldsText: "",
1619
+ optionsDependsOn: "",
1620
+ optionsFilterField: "",
1621
+ triggers: []
1622
+ };
1623
+ const emptyFormValues = {
1624
+ title: "",
1625
+ description: "",
1626
+ sourceType: "none",
1627
+ sourceTable: BUILDER_EDITOR_NONE_VALUE,
1628
+ apiBasePath: "",
1629
+ fields: [emptyField],
1630
+ layoutGroups: builderFormEditorDefaultLayoutGroups([emptyField]),
1631
+ subforms: [],
1632
+ triggers: [],
1633
+ version: 0
1634
+ };
1635
+ const emptyFormTrigger = {
1636
+ event: formTriggerEvent,
1637
+ route: "/api/v1/",
1638
+ enabled: false,
1639
+ blocking: true
1640
+ };
1641
+ const emptyColumn = {
1642
+ key: "name",
1643
+ label: "Name",
1644
+ sortable: true,
1645
+ align: "left"
1646
+ };
1647
+ const emptyListValues = {
1648
+ title: "",
1649
+ description: "",
1650
+ sourceType: "none",
1651
+ sourceTable: BUILDER_EDITOR_NONE_VALUE,
1652
+ apiBasePath: "",
1653
+ columns: [emptyColumn],
1654
+ triggers: [],
1655
+ version: 0
1656
+ };
1657
+ const emptyListTrigger = {
1658
+ event: listTriggerEvent,
1659
+ route: "/api/v1/",
1660
+ enabled: false,
1661
+ blocking: true
1662
+ };
1663
+ const FormEditorPage = createBuilderFormEditorPageComponent({
1664
+ emptyValues: emptyFormValues,
1665
+ emptyField,
1666
+ emptyTrigger: emptyFormTrigger,
1667
+ labels: {
1668
+ created: "Form created",
1669
+ saved: "Form saved"
1670
+ },
1671
+ states: {
1672
+ loading: "Loading...",
1673
+ error: "Failed to load form."
1674
+ },
1675
+ hooks: {
1676
+ useEntity: hooks.useBuilderForm,
1677
+ useTables: hooks.useBuilderDbTables,
1678
+ useSave: hooks.useSaveBuilderForm
1679
+ },
1680
+ buildInput: (values) => builderFormEditorInputFromValues(values),
1681
+ navigateAfterCreate: (entity) => window.location.assign(editFormPath(entity.id)),
1682
+ notifications: {
1683
+ success: (message) => notifySuccess?.(message),
1684
+ error: (error) => {
1685
+ if (notifyError) notifyError(error);
1686
+ else throw error;
1687
+ }
1688
+ },
1689
+ Body: createBuilderDefaultFormEditorBody({
1690
+ backHref: formsPath,
1691
+ fieldTypeOptions,
1692
+ formTriggerEventOptions,
1693
+ fieldTriggerEventOptions
1694
+ })
1695
+ });
1696
+ const ListEditorPage = createBuilderListEditorPageComponent({
1697
+ emptyValues: emptyListValues,
1698
+ emptyColumn,
1699
+ emptyTrigger: emptyListTrigger,
1700
+ labels: {
1701
+ created: "List created",
1702
+ saved: "List saved"
1703
+ },
1704
+ states: {
1705
+ loading: "Loading...",
1706
+ error: "Failed to load list."
1707
+ },
1708
+ hooks: {
1709
+ useEntity: hooks.useBuilderList,
1710
+ useTables: hooks.useBuilderDbTables,
1711
+ useSave: hooks.useSaveBuilderList
1712
+ },
1713
+ buildInput: (values) => builderListEditorInputFromValues(values),
1714
+ navigateAfterCreate: (entity) => window.location.assign(editListPath(entity.id)),
1715
+ notifications: {
1716
+ success: (message) => notifySuccess?.(message),
1717
+ error: (error) => {
1718
+ if (notifyError) notifyError(error);
1719
+ else throw error;
1720
+ }
1721
+ },
1722
+ Body: createBuilderDefaultListEditorBody({
1723
+ backHref: listsPath,
1724
+ listTriggerEventOptions
1725
+ })
1726
+ });
1727
+ const ViewEditorPage = createBuilderDefaultViewEditorPage({
1728
+ hooks,
1729
+ backHref: viewsPath,
1730
+ editHref: editViewPath,
1731
+ permissionOptions,
1732
+ defaultPermission,
1733
+ parseTriggers: parseViewTriggers,
1734
+ notifySuccess,
1735
+ notifyError
1736
+ });
1737
+ const AdminHomePage = function BuilderAdminHomePage() {
1738
+ const items = [
1739
+ {
1740
+ title: "Dynamic Forms",
1741
+ description: "Reusable form schemas.",
1742
+ href: formsPath
1743
+ },
1744
+ {
1745
+ title: "Dynamic Lists",
1746
+ description: "Reusable list and grid schemas.",
1747
+ href: listsPath
1748
+ },
1749
+ {
1750
+ title: "Dynamic Views",
1751
+ description: "Runtime screens composed from form and list schemas.",
1752
+ href: viewsPath
1753
+ }
1754
+ ];
1755
+ return /* @__PURE__ */ jsxs4("section", { style: homeStyles.page, children: [
1756
+ /* @__PURE__ */ jsxs4("div", { children: [
1757
+ /* @__PURE__ */ jsx5("h1", { style: homeStyles.headerTitle, children: "Builder" }),
1758
+ /* @__PURE__ */ jsx5("p", { style: homeStyles.description, children: "Manage dynamic forms, lists, and views." })
1759
+ ] }),
1760
+ /* @__PURE__ */ jsx5("div", { style: homeStyles.grid, children: items.map((item) => /* @__PURE__ */ jsxs4("a", { href: item.href, style: homeStyles.card, children: [
1761
+ /* @__PURE__ */ jsx5("h2", { style: homeStyles.cardTitle, children: item.title }),
1762
+ /* @__PURE__ */ jsx5("p", { style: homeStyles.description, children: item.description })
1763
+ ] }, item.href)) })
1764
+ ] });
1765
+ };
1766
+ const AdminFormsPage = createBuilderDefaultEntityManagerComponent({
1767
+ labels: {
1768
+ title: "Dynamic Forms",
1769
+ description: "Reusable form schemas.",
1770
+ searchPlaceholder: "Search forms...",
1771
+ emptyTitle: "No forms",
1772
+ emptyDescription: "Create your first dynamic form.",
1773
+ addLabel: "Add form",
1774
+ editLabel: "Edit",
1775
+ replicateLabel: "Replicate",
1776
+ deleteLabel: "Delete",
1777
+ runtimeLabel: "Open",
1778
+ deleteConfirm: (entity) => `Delete ${entity.title}?`,
1779
+ replicatePrompt: () => "New form title",
1780
+ replicateDefaultTitle: (entity) => `${entity.title} copy`
1781
+ },
1782
+ createHref: newFormPath,
1783
+ editHref: (entity) => editFormPath(entity.id),
1784
+ runtimeHref: (entity) => runtimeFormPath(entity.id),
1785
+ getDetail: detail,
1786
+ buildQuery: (state) => defaultQuery(state),
1787
+ hooks: {
1788
+ useEntities: (query) => hooks.useBuilderForms(query),
1789
+ useDelete: hooks.useDeleteBuilderForm,
1790
+ useReplicate: hooks.useReplicateBuilderForm
1791
+ }
1792
+ });
1793
+ const AdminListsPage = createBuilderDefaultEntityManagerComponent({
1794
+ labels: {
1795
+ title: "Dynamic Lists",
1796
+ description: "Reusable list and grid schemas.",
1797
+ searchPlaceholder: "Search lists...",
1798
+ emptyTitle: "No lists",
1799
+ emptyDescription: "Create your first dynamic list.",
1800
+ addLabel: "Add list",
1801
+ editLabel: "Edit",
1802
+ replicateLabel: "Replicate",
1803
+ deleteLabel: "Delete",
1804
+ runtimeLabel: "Open",
1805
+ deleteConfirm: (entity) => `Delete ${entity.title}?`,
1806
+ replicatePrompt: () => "New list title",
1807
+ replicateDefaultTitle: (entity) => `${entity.title} copy`
1808
+ },
1809
+ createHref: newListPath,
1810
+ editHref: (entity) => editListPath(entity.id),
1811
+ runtimeHref: (entity) => runtimeListPath(entity.id),
1812
+ getDetail: detail,
1813
+ buildQuery: (state) => defaultQuery(state),
1814
+ hooks: {
1815
+ useEntities: (query) => hooks.useBuilderLists(query),
1816
+ useDelete: hooks.useDeleteBuilderList,
1817
+ useReplicate: hooks.useReplicateBuilderList
1818
+ }
1819
+ });
1820
+ const AdminViewsPage = createBuilderDefaultEntityManagerComponent({
1821
+ labels: {
1822
+ title: "Dynamic Views",
1823
+ description: "Runtime screens composed from form and list schemas.",
1824
+ searchPlaceholder: "Search views...",
1825
+ emptyTitle: "No views",
1826
+ emptyDescription: "Create a dynamic view after preparing a form and list.",
1827
+ addLabel: "Add view",
1828
+ editLabel: "Edit",
1829
+ replicateLabel: "Replicate",
1830
+ deleteLabel: "Delete",
1831
+ runtimeLabel: "Open",
1832
+ deleteConfirm: (entity) => `Delete ${entity.title}?`,
1833
+ replicatePrompt: () => "New view title",
1834
+ replicateDefaultTitle: (entity) => `${entity.title} copy`
1835
+ },
1836
+ createHref: newViewPath,
1837
+ editHref: (entity) => editViewPath(entity.id),
1838
+ runtimeHref: (entity) => runtimeViewPath(entity.id),
1839
+ getDetail: detail,
1840
+ buildQuery: (state) => defaultQuery(state),
1841
+ hooks: {
1842
+ useEntities: (query) => hooks.useBuilderViews(query),
1843
+ useDelete: hooks.useDeleteBuilderView,
1844
+ useReplicate: hooks.useReplicateBuilderView
1845
+ }
1846
+ });
1847
+ return {
1848
+ AdminHomePage,
1849
+ AdminFormsPage,
1850
+ AdminNewFormPage: function BuilderAdminNewFormPage() {
1851
+ return /* @__PURE__ */ jsx5(FormEditorPage, {});
1852
+ },
1853
+ AdminEditFormPage: function BuilderAdminEditFormPage({ formId }) {
1854
+ return /* @__PURE__ */ jsx5(FormEditorPage, { formId });
1855
+ },
1856
+ AdminListsPage,
1857
+ AdminNewListPage: function BuilderAdminNewListPage() {
1858
+ return /* @__PURE__ */ jsx5(ListEditorPage, {});
1859
+ },
1860
+ AdminEditListPage: function BuilderAdminEditListPage({ listId }) {
1861
+ return /* @__PURE__ */ jsx5(ListEditorPage, { listId });
1862
+ },
1863
+ AdminViewsPage,
1864
+ AdminNewViewPage: function BuilderAdminNewViewPage() {
1865
+ return /* @__PURE__ */ jsx5(ViewEditorPage, {});
1866
+ },
1867
+ AdminEditViewPage: function BuilderAdminEditViewPage({ viewId }) {
1868
+ return /* @__PURE__ */ jsx5(ViewEditorPage, { viewId });
1869
+ },
1870
+ routes: {
1871
+ adminBasePath,
1872
+ formsPath,
1873
+ newFormPath,
1874
+ editFormPath,
1875
+ listsPath,
1876
+ newListPath,
1877
+ editListPath,
1878
+ viewsPath,
1879
+ newViewPath,
1880
+ editViewPath
1881
+ }
1882
+ };
1883
+ }
1884
+
1885
+ // src/hooks/createBuilderHooks.ts
1886
+ import { keepPreviousData, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
1887
+ function createBuilderKeys() {
1888
+ const builderKeys = {
1889
+ forms: ["builder", "forms"],
1890
+ dbTables: () => ["builder", "datasources", "tables"],
1891
+ formList: (query) => [...builderKeys.forms, "list", query],
1892
+ form: (id) => [...builderKeys.forms, "detail", id],
1893
+ formOptions: () => [...builderKeys.forms, "options"],
1894
+ lists: ["builder", "lists"],
1895
+ listList: (query) => [...builderKeys.lists, "list", query],
1896
+ list: (id) => [...builderKeys.lists, "detail", id],
1897
+ listOptions: () => [...builderKeys.lists, "options"],
1898
+ views: ["builder", "views"],
1899
+ viewList: (query) => [...builderKeys.views, "list", query],
1900
+ view: (id) => [...builderKeys.views, "detail", id],
1901
+ runtimeForm: (id) => ["builder", "runtime", "form", id],
1902
+ runtimeFieldOptions: (formId, fieldKey, query) => [...builderKeys.runtimeForm(formId), "fields", fieldKey, "options", query],
1903
+ runtimeFormEntries: (id) => [...builderKeys.runtimeForm(id), "entries"],
1904
+ runtimeList: (id) => ["builder", "runtime", "list", id],
1905
+ runtimeListEntries: (id, query) => [...builderKeys.runtimeList(id), "entries", query],
1906
+ runtimeView: (id) => ["builder", "runtime", "view", id],
1907
+ entries: (id, query) => [...builderKeys.runtimeView(id), "entries", query]
1908
+ };
1909
+ return builderKeys;
1910
+ }
1911
+ function createBuilderHooks(client) {
1912
+ const builderKeys = createBuilderKeys();
1913
+ function invalidateRuntimeViewEntries(queryClient, viewId) {
1914
+ return Promise.all([
1915
+ queryClient.invalidateQueries({ queryKey: builderKeys.runtimeView(viewId) }),
1916
+ queryClient.invalidateQueries({ queryKey: [...builderKeys.runtimeView(viewId), "entries"] })
1917
+ ]);
1918
+ }
1919
+ function useBuilderDbTables() {
1920
+ return useQuery({ queryKey: builderKeys.dbTables(), queryFn: client.listBuilderDbTables });
1921
+ }
1922
+ function useBuilderForms(query) {
1923
+ return useQuery({
1924
+ queryKey: builderKeys.formList(query),
1925
+ queryFn: () => client.listBuilderForms(query),
1926
+ placeholderData: keepPreviousData
1927
+ });
1928
+ }
1929
+ function useBuilderFormOptions() {
1930
+ return useQuery({
1931
+ queryKey: builderKeys.formOptions(),
1932
+ queryFn: client.listBuilderFormOptions
1933
+ });
1934
+ }
1935
+ function useBuilderForm(id) {
1936
+ return useQuery({
1937
+ queryKey: builderKeys.form(id ?? ""),
1938
+ queryFn: () => client.getBuilderForm(id ?? ""),
1939
+ enabled: Boolean(id)
1940
+ });
1941
+ }
1942
+ function useSaveBuilderForm() {
1943
+ const queryClient = useQueryClient();
1944
+ return useMutation({
1945
+ mutationFn: ({ id, input }) => id ? client.updateBuilderForm(id, input) : client.createBuilderForm(input),
1946
+ onSuccess: (form) => {
1947
+ queryClient.invalidateQueries({ queryKey: builderKeys.forms });
1948
+ queryClient.invalidateQueries({ queryKey: builderKeys.form(form.id) });
1949
+ queryClient.invalidateQueries({ queryKey: builderKeys.runtimeForm(form.id) });
1950
+ }
1951
+ });
1952
+ }
1953
+ function useReplicateBuilderForm() {
1954
+ const queryClient = useQueryClient();
1955
+ return useMutation({
1956
+ mutationFn: ({ id, input }) => client.replicateBuilderForm(id, input),
1957
+ onSuccess: () => queryClient.invalidateQueries({ queryKey: builderKeys.forms })
1958
+ });
1959
+ }
1960
+ function useDeleteBuilderForm() {
1961
+ const queryClient = useQueryClient();
1962
+ return useMutation({
1963
+ mutationFn: client.deleteBuilderForm,
1964
+ onSuccess: () => queryClient.invalidateQueries({ queryKey: builderKeys.forms })
1965
+ });
1966
+ }
1967
+ function useBuilderLists(query) {
1968
+ return useQuery({
1969
+ queryKey: builderKeys.listList(query),
1970
+ queryFn: () => client.listBuilderLists(query),
1971
+ placeholderData: keepPreviousData
1972
+ });
1973
+ }
1974
+ function useBuilderListOptions() {
1975
+ return useQuery({
1976
+ queryKey: builderKeys.listOptions(),
1977
+ queryFn: client.listBuilderListOptions
1978
+ });
1979
+ }
1980
+ function useBuilderList(id) {
1981
+ return useQuery({
1982
+ queryKey: builderKeys.list(id ?? ""),
1983
+ queryFn: () => client.getBuilderList(id ?? ""),
1984
+ enabled: Boolean(id)
1985
+ });
1986
+ }
1987
+ function useSaveBuilderList() {
1988
+ const queryClient = useQueryClient();
1989
+ return useMutation({
1990
+ mutationFn: ({ id, input }) => id ? client.updateBuilderList(id, input) : client.createBuilderList(input),
1991
+ onSuccess: (list) => {
1992
+ queryClient.invalidateQueries({ queryKey: builderKeys.lists });
1993
+ queryClient.invalidateQueries({ queryKey: builderKeys.list(list.id) });
1994
+ queryClient.invalidateQueries({ queryKey: builderKeys.runtimeList(list.id) });
1995
+ }
1996
+ });
1997
+ }
1998
+ function useReplicateBuilderList() {
1999
+ const queryClient = useQueryClient();
2000
+ return useMutation({
2001
+ mutationFn: ({ id, input }) => client.replicateBuilderList(id, input),
2002
+ onSuccess: () => queryClient.invalidateQueries({ queryKey: builderKeys.lists })
2003
+ });
2004
+ }
2005
+ function useDeleteBuilderList() {
2006
+ const queryClient = useQueryClient();
2007
+ return useMutation({
2008
+ mutationFn: client.deleteBuilderList,
2009
+ onSuccess: () => queryClient.invalidateQueries({ queryKey: builderKeys.lists })
2010
+ });
2011
+ }
2012
+ function useBuilderViews(query) {
2013
+ return useQuery({
2014
+ queryKey: builderKeys.viewList(query),
2015
+ queryFn: () => client.listBuilderViews(query),
2016
+ placeholderData: keepPreviousData
2017
+ });
2018
+ }
2019
+ function useBuilderView(id) {
2020
+ return useQuery({
2021
+ queryKey: builderKeys.view(id ?? ""),
2022
+ queryFn: () => client.getBuilderView(id ?? ""),
2023
+ enabled: Boolean(id)
2024
+ });
2025
+ }
2026
+ function useSaveBuilderView() {
2027
+ const queryClient = useQueryClient();
2028
+ return useMutation({
2029
+ mutationFn: ({ id, input }) => id ? client.updateBuilderView(id, input) : client.createBuilderView(input),
2030
+ onSuccess: () => queryClient.invalidateQueries({ queryKey: builderKeys.views })
2031
+ });
2032
+ }
2033
+ function useReplicateBuilderView() {
2034
+ const queryClient = useQueryClient();
2035
+ return useMutation({
2036
+ mutationFn: ({ id, input }) => client.replicateBuilderView(id, input),
2037
+ onSuccess: () => queryClient.invalidateQueries({ queryKey: builderKeys.views })
2038
+ });
2039
+ }
2040
+ function useDeleteBuilderView() {
2041
+ const queryClient = useQueryClient();
2042
+ return useMutation({
2043
+ mutationFn: client.deleteBuilderView,
2044
+ onSuccess: () => queryClient.invalidateQueries({ queryKey: builderKeys.views })
2045
+ });
2046
+ }
2047
+ function useRuntimeBuilderForm(id) {
2048
+ return useQuery({
2049
+ queryKey: builderKeys.runtimeForm(id),
2050
+ queryFn: () => client.getRuntimeBuilderForm(id)
2051
+ });
2052
+ }
2053
+ function useRuntimeBuilderFormFieldOptions(formId, fieldKey, query, enabled = true) {
2054
+ return useQuery({
2055
+ queryKey: builderKeys.runtimeFieldOptions(formId ?? "", fieldKey, query),
2056
+ queryFn: () => client.listRuntimeBuilderFormFieldOptions(formId ?? "", fieldKey, query),
2057
+ enabled: Boolean(formId) && enabled
2058
+ });
2059
+ }
2060
+ function useRunRuntimeBuilderFieldTrigger() {
2061
+ return useMutation({
2062
+ mutationFn: (args) => {
2063
+ if (args.viewId) {
2064
+ return client.runRuntimeBuilderViewFieldTrigger(
2065
+ args.viewId,
2066
+ args.fieldKey,
2067
+ args.event,
2068
+ args.input
2069
+ );
2070
+ }
2071
+ if (args.formId) {
2072
+ return client.runRuntimeBuilderFormFieldTrigger(
2073
+ args.formId,
2074
+ args.fieldKey,
2075
+ args.event,
2076
+ args.input
2077
+ );
2078
+ }
2079
+ throw new Error("formId \u044D\u0441\u0432\u044D\u043B viewId \u0448\u0430\u0430\u0440\u0434\u043B\u0430\u0433\u0430\u0442\u0430\u0439");
2080
+ }
2081
+ });
2082
+ }
2083
+ function useRuntimeBuilderList(id) {
2084
+ return useQuery({
2085
+ queryKey: builderKeys.runtimeList(id),
2086
+ queryFn: () => client.getRuntimeBuilderList(id)
2087
+ });
2088
+ }
2089
+ function useRuntimeBuilderListEntries(id, query) {
2090
+ return useQuery({
2091
+ queryKey: builderKeys.runtimeListEntries(id, query),
2092
+ queryFn: () => client.listRuntimeBuilderListEntries(id, query),
2093
+ placeholderData: keepPreviousData
2094
+ });
2095
+ }
2096
+ function useSaveRuntimeBuilderFormEntry(formId) {
2097
+ const queryClient = useQueryClient();
2098
+ return useMutation({
2099
+ mutationFn: (input) => client.createRuntimeBuilderFormEntry(formId, input),
2100
+ onSuccess: () => {
2101
+ queryClient.invalidateQueries({ queryKey: builderKeys.runtimeFormEntries(formId) });
2102
+ queryClient.invalidateQueries({ queryKey: builderKeys.runtimeForm(formId) });
2103
+ queryClient.invalidateQueries({ queryKey: ["builder", "runtime", "list"] });
2104
+ }
2105
+ });
2106
+ }
2107
+ function useRuntimeBuilderView(id, enabled = true) {
2108
+ return useQuery({
2109
+ queryKey: builderKeys.runtimeView(id),
2110
+ queryFn: () => client.getRuntimeBuilderView(id),
2111
+ enabled: Boolean(id) && enabled
2112
+ });
2113
+ }
2114
+ function useBuilderViewEntries(id, query, enabled = true) {
2115
+ return useQuery({
2116
+ queryKey: builderKeys.entries(id, query),
2117
+ queryFn: () => client.listBuilderViewEntries(id, query),
2118
+ placeholderData: keepPreviousData,
2119
+ enabled: Boolean(id) && enabled
2120
+ });
2121
+ }
2122
+ function useSaveBuilderViewEntry(viewId) {
2123
+ const queryClient = useQueryClient();
2124
+ return useMutation({
2125
+ mutationFn: ({ id, input }) => id ? client.updateBuilderViewEntry(viewId, id, input) : client.createBuilderViewEntry(
2126
+ viewId,
2127
+ input
2128
+ ),
2129
+ onSuccess: () => invalidateRuntimeViewEntries(queryClient, viewId)
2130
+ });
2131
+ }
2132
+ function useCreateCompositeBuilderViewEntry(viewId) {
2133
+ const queryClient = useQueryClient();
2134
+ return useMutation({
2135
+ mutationFn: (input) => client.createCompositeBuilderViewEntry(viewId, input),
2136
+ onSuccess: () => invalidateRuntimeViewEntries(queryClient, viewId)
2137
+ });
2138
+ }
2139
+ function useUpdateCompositeBuilderViewEntry(viewId) {
2140
+ const queryClient = useQueryClient();
2141
+ return useMutation({
2142
+ mutationFn: ({
2143
+ id,
2144
+ input
2145
+ }) => client.updateCompositeBuilderViewEntry(viewId, id, input),
2146
+ onSuccess: () => invalidateRuntimeViewEntries(queryClient, viewId)
2147
+ });
2148
+ }
2149
+ function useDeleteBuilderViewEntry(id) {
2150
+ const queryClient = useQueryClient();
2151
+ return useMutation({
2152
+ mutationFn: (entryId) => client.deleteBuilderViewEntry(id, entryId),
2153
+ onSuccess: () => invalidateRuntimeViewEntries(queryClient, id)
2154
+ });
2155
+ }
2156
+ return {
2157
+ builderKeys,
2158
+ useBuilderDbTables,
2159
+ useBuilderForm,
2160
+ useBuilderFormOptions,
2161
+ useBuilderForms,
2162
+ useBuilderList,
2163
+ useBuilderListOptions,
2164
+ useBuilderLists,
2165
+ useBuilderViewEntries,
2166
+ useBuilderView,
2167
+ useBuilderViews,
2168
+ useDeleteBuilderForm,
2169
+ useDeleteBuilderList,
2170
+ useDeleteBuilderView,
2171
+ useDeleteBuilderViewEntry,
2172
+ useCreateCompositeBuilderViewEntry,
2173
+ useReplicateBuilderForm,
2174
+ useReplicateBuilderList,
2175
+ useReplicateBuilderView,
2176
+ useRuntimeBuilderForm,
2177
+ useRuntimeBuilderFormFieldOptions,
2178
+ useRuntimeBuilderList,
2179
+ useRuntimeBuilderListEntries,
2180
+ useRuntimeBuilderView,
2181
+ useRunRuntimeBuilderFieldTrigger,
2182
+ useSaveBuilderForm,
2183
+ useSaveBuilderList,
2184
+ useSaveBuilderView,
2185
+ useSaveBuilderViewEntry,
2186
+ useSaveRuntimeBuilderFormEntry,
2187
+ useUpdateCompositeBuilderViewEntry
2188
+ };
2189
+ }
2190
+
2191
+ // src/integration/createBuilderIntegration.ts
2192
+ function normalizeBasePath(path) {
2193
+ const trimmed = path.trim().replace(/\/+$/g, "");
2194
+ if (!trimmed) return "/builder";
2195
+ return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
2196
+ }
2197
+ function withQuery(path, query) {
2198
+ const params = new URLSearchParams();
2199
+ for (const [key, value] of Object.entries(query)) {
2200
+ if (value) params.set(key, value);
2201
+ }
2202
+ const queryString = params.toString();
2203
+ return queryString ? `${path}?${queryString}` : path;
2204
+ }
2205
+ function createBuilderIntegration(config) {
2206
+ const adminBasePath = normalizeBasePath(config.adminBasePath ?? "/admin/dev/builder");
2207
+ const runtimeBasePath = normalizeBasePath(config.runtimeBasePath ?? "/admin/winu");
2208
+ const api = createBuilderApiClient(config.transport);
2209
+ const hooks = createBuilderHooks(api);
2210
+ const formsPath = `${adminBasePath}/forms`;
2211
+ const listsPath = `${adminBasePath}/lists`;
2212
+ const routes = {
2213
+ adminBasePath,
2214
+ runtimeBasePath,
2215
+ adminHomePath: adminBasePath,
2216
+ formsPath,
2217
+ newFormPath: `${formsPath}/new`,
2218
+ editFormPath: (id) => withQuery(`${formsPath}/edit`, { id }),
2219
+ listsPath,
2220
+ newListPath: `${listsPath}/new`,
2221
+ editListPath: (id) => withQuery(`${listsPath}/edit`, { id }),
2222
+ viewsPath: `${adminBasePath}/views`
2223
+ };
2224
+ const adminPages = config.adminPages ? createBuilderAdminPages({
2225
+ ...config.adminPages,
2226
+ hooks,
2227
+ routes: {
2228
+ adminBasePath,
2229
+ runtimeBasePath
2230
+ }
2231
+ }) : void 0;
2232
+ return {
2233
+ api,
2234
+ hooks,
2235
+ routes,
2236
+ adminPages
2237
+ };
2238
+ }
2239
+ function createBuilderPortalIntegration(config) {
2240
+ return createBuilderIntegration(config);
2241
+ }
2242
+ function validateBuilderFrontendSetup(config) {
2243
+ const checks = [
2244
+ {
2245
+ name: "adminBasePath",
2246
+ ok: Boolean(config.adminBasePath && normalizeBasePath(config.adminBasePath).startsWith("/")),
2247
+ message: "adminBasePath must be an absolute route path."
2248
+ },
2249
+ {
2250
+ name: "runtimeBasePath",
2251
+ ok: Boolean(config.runtimeBasePath && normalizeBasePath(config.runtimeBasePath).startsWith("/")),
2252
+ message: "runtimeBasePath must be an absolute route path."
2253
+ },
2254
+ {
2255
+ name: "transport",
2256
+ ok: Boolean(config.transport),
2257
+ message: "API transport is required."
2258
+ }
2259
+ ].map((check) => check.ok ? { name: check.name, ok: true } : check);
2260
+ return { ok: checks.every((check) => check.ok), checks };
2261
+ }
2262
+ export {
2263
+ createBuilderIntegration,
2264
+ createBuilderPortalIntegration,
2265
+ validateBuilderFrontendSetup
2266
+ };
2267
+ //# sourceMappingURL=index.js.map