@duke333/builder-ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,644 @@
1
+ // src/admin/BuilderEditorPage.tsx
2
+ import { useEffect } from "react";
3
+ import {
4
+ FormProvider,
5
+ useFieldArray,
6
+ useForm,
7
+ useWatch
8
+ } from "react-hook-form";
9
+
10
+ // src/admin/editorState.ts
11
+ var BUILDER_EDITOR_NONE_VALUE = "__none";
12
+ function builderEditorOptionsToText(options) {
13
+ return (options ?? []).map((option) => `${option.label}:${option.value}`).join("\n");
14
+ }
15
+ function builderEditorTextToOptions(value) {
16
+ const rows = (value ?? "").split("\n").map((line) => line.trim()).filter(Boolean);
17
+ if (rows.length === 0) return void 0;
18
+ return rows.map((line) => {
19
+ const [label, ...rest] = line.split(":");
20
+ return { label: label.trim(), value: rest.join(":").trim() || label.trim() };
21
+ });
22
+ }
23
+ function builderEditorSearchFieldsToText(fields) {
24
+ return (fields ?? []).join("\n");
25
+ }
26
+ function builderEditorTextToSearchFields(value) {
27
+ const fields = (value ?? "").split("\n").map((line) => line.trim()).filter(Boolean);
28
+ return fields.length > 0 ? fields : void 0;
29
+ }
30
+ function getBuilderEditorTriggerRoute(config) {
31
+ const route = config.route ?? config.path ?? config.url;
32
+ return typeof route === "string" ? route : "";
33
+ }
34
+ function valuesFromTriggers(triggers) {
35
+ return triggers.filter((trigger) => trigger.action === "callApi" || trigger.action === "webhook").map((trigger) => ({
36
+ event: trigger.event,
37
+ route: getBuilderEditorTriggerRoute(trigger.config),
38
+ enabled: trigger.enabled,
39
+ blocking: trigger.blocking
40
+ })).filter((trigger) => trigger.route);
41
+ }
42
+ function valuesFromFieldTriggers(triggers) {
43
+ return (triggers ?? []).map((trigger) => ({
44
+ event: trigger.event,
45
+ action: trigger.action,
46
+ enabled: trigger.enabled,
47
+ debounceMs: trigger.debounceMs
48
+ }));
49
+ }
50
+ function clampLayoutSpan(span, columns) {
51
+ if (!span || Number.isNaN(span)) return columns;
52
+ return Math.max(1, Math.min(columns, Math.trunc(span)));
53
+ }
54
+ function builderFormEditorDefaultSpan(field) {
55
+ if (field.type === "textarea" || field.type === "checkbox") return 12;
56
+ return 6;
57
+ }
58
+ function builderFormEditorDefaultLayoutGroups(fields, subforms = []) {
59
+ return [
60
+ {
61
+ id: "main",
62
+ title: "\u04AE\u043D\u0434\u0441\u044D\u043D",
63
+ columns: 12,
64
+ fields: [
65
+ ...fields.map((field) => ({
66
+ key: field.key,
67
+ span: builderFormEditorDefaultSpan(field)
68
+ })),
69
+ ...subforms.map((subform) => ({ key: subform.key, span: 12 }))
70
+ ]
71
+ }
72
+ ];
73
+ }
74
+ function normalizeBuilderFormEditorLayoutGroups(groups, fields, subforms = []) {
75
+ if (fields.length === 0 && subforms.length === 0) return [];
76
+ const layoutItems = [
77
+ ...fields.map((field) => ({
78
+ key: field.key,
79
+ span: builderFormEditorDefaultSpan(field)
80
+ })),
81
+ ...subforms.map((subform) => ({ key: subform.key, span: 12 }))
82
+ ];
83
+ const itemKeys = new Set(layoutItems.map((item) => item.key));
84
+ const usedKeys = /* @__PURE__ */ new Set();
85
+ const normalized = (groups ?? []).map((group, index) => {
86
+ const columns = group.columns === 6 || group.columns === 8 ? group.columns : 12;
87
+ const groupFields = (group.fields ?? []).filter((field) => itemKeys.has(field.key) && !usedKeys.has(field.key)).map((field) => {
88
+ usedKeys.add(field.key);
89
+ return { key: field.key, span: clampLayoutSpan(field.span, columns) };
90
+ });
91
+ return {
92
+ id: group.id || `group${index + 1}`,
93
+ title: group.title || `Group ${index + 1}`,
94
+ columns,
95
+ fields: groupFields
96
+ };
97
+ }).filter((group) => group.fields.length > 0 || group.title.trim());
98
+ const missingFields = layoutItems.filter((item) => !usedKeys.has(item.key));
99
+ if (normalized.length === 0) {
100
+ return builderFormEditorDefaultLayoutGroups(fields, subforms);
101
+ }
102
+ if (missingFields.length > 0) {
103
+ normalized.push({
104
+ id: "ungrouped",
105
+ title: "\u0411\u0443\u0441\u0430\u0434",
106
+ columns: 12,
107
+ fields: missingFields
108
+ });
109
+ }
110
+ return normalized;
111
+ }
112
+ function builderFormEditorValuesFromEntity(form, emptyValues) {
113
+ if (!form) return emptyValues;
114
+ const source = form.source;
115
+ const fields = form.schema.fields.map((field) => ({
116
+ key: field.key,
117
+ label: field.label,
118
+ type: field.type,
119
+ required: field.required,
120
+ hidden: field.hidden ?? false,
121
+ disabled: field.disabled ?? false,
122
+ placeholder: field.placeholder ?? "",
123
+ optionsText: builderEditorOptionsToText(field.options),
124
+ optionsMode: field.optionsSource?.type === "dbTable" ? "table" : "static",
125
+ optionsTable: field.optionsSource?.type === "dbTable" ? field.optionsSource.tableName : BUILDER_EDITOR_NONE_VALUE,
126
+ optionsValueField: field.optionsSource?.type === "dbTable" ? field.optionsSource.valueField : BUILDER_EDITOR_NONE_VALUE,
127
+ optionsLabelField: field.optionsSource?.type === "dbTable" ? field.optionsSource.labelField : BUILDER_EDITOR_NONE_VALUE,
128
+ optionsSearchFieldsText: field.optionsSource?.type === "dbTable" ? builderEditorSearchFieldsToText(field.optionsSource.searchFields) : "",
129
+ optionsDependsOn: field.optionsSource?.type === "dbTable" ? field.optionsSource.filterBy?.valueFromField ?? "" : "",
130
+ optionsFilterField: field.optionsSource?.type === "dbTable" ? field.optionsSource.filterBy?.field ?? "" : "",
131
+ triggers: valuesFromFieldTriggers(field.triggers)
132
+ }));
133
+ const subforms = (form.schema.subforms ?? []).map((subform) => ({
134
+ key: subform.key,
135
+ label: subform.label,
136
+ viewId: subform.viewId,
137
+ parentField: subform.parentField,
138
+ childField: subform.childField,
139
+ buttonLabel: subform.buttonLabel ?? "",
140
+ icon: subform.icon ?? ""
141
+ }));
142
+ return {
143
+ title: form.title,
144
+ description: form.description ?? "",
145
+ sourceType: source?.type ?? "none",
146
+ sourceTable: source?.type === "dbTable" ? source.tableName : BUILDER_EDITOR_NONE_VALUE,
147
+ apiBasePath: source?.type === "apiEndpoint" ? source.basePath : "",
148
+ fields,
149
+ layoutGroups: normalizeBuilderFormEditorLayoutGroups(
150
+ form.schema.layout?.groups,
151
+ fields,
152
+ subforms
153
+ ),
154
+ subforms,
155
+ triggers: valuesFromTriggers(form.triggers),
156
+ version: form.version
157
+ };
158
+ }
159
+ function builderListEditorValuesFromEntity(list, emptyValues) {
160
+ if (!list) return emptyValues;
161
+ const source = list.source;
162
+ return {
163
+ title: list.title,
164
+ description: list.description ?? "",
165
+ sourceType: source?.type ?? "none",
166
+ sourceTable: source?.type === "dbTable" ? source.tableName : BUILDER_EDITOR_NONE_VALUE,
167
+ apiBasePath: source?.type === "apiEndpoint" ? source.basePath : "",
168
+ columns: list.schema.columns.map((column) => ({
169
+ key: column.key,
170
+ label: column.label,
171
+ sortable: column.sortable,
172
+ align: column.align
173
+ })),
174
+ triggers: valuesFromTriggers(list.triggers),
175
+ version: list.version
176
+ };
177
+ }
178
+ function builderViewEditorValuesFromEntity(view, emptyValues, defaultPermission) {
179
+ if (!view) return emptyValues;
180
+ return {
181
+ title: view.title,
182
+ description: view.description ?? "",
183
+ formId: view.formId ?? BUILDER_EDITOR_NONE_VALUE,
184
+ listId: view.listId ?? BUILDER_EDITOR_NONE_VALUE,
185
+ permissionRead: view.permissionRead ?? defaultPermission,
186
+ permissionWrite: view.permissionWrite ?? defaultPermission,
187
+ triggersText: JSON.stringify(view.triggers ?? [], null, 2),
188
+ version: view.version
189
+ };
190
+ }
191
+ function builderFormEditorFieldsFromTable(table) {
192
+ return table.columns.map((column) => ({
193
+ key: column.name,
194
+ label: column.label,
195
+ type: column.fieldType,
196
+ required: !column.nullable,
197
+ hidden: false,
198
+ disabled: false,
199
+ placeholder: column.label,
200
+ optionsText: "",
201
+ optionsMode: "static",
202
+ optionsTable: BUILDER_EDITOR_NONE_VALUE,
203
+ optionsValueField: BUILDER_EDITOR_NONE_VALUE,
204
+ optionsLabelField: BUILDER_EDITOR_NONE_VALUE,
205
+ optionsSearchFieldsText: "",
206
+ optionsDependsOn: "",
207
+ optionsFilterField: "",
208
+ triggers: []
209
+ }));
210
+ }
211
+ function builderListEditorColumnsFromTable(table) {
212
+ return table.columns.map((column) => ({
213
+ key: column.name,
214
+ label: column.label,
215
+ sortable: column.sortable,
216
+ align: column.fieldType === "number" || column.fieldType === "money" ? "right" : "left"
217
+ }));
218
+ }
219
+ function builderFormEditorInputFromValues(values) {
220
+ 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;
221
+ return {
222
+ title: values.title,
223
+ description: values.description || null,
224
+ source,
225
+ schema: {
226
+ fields: values.fields.map((field) => ({
227
+ key: field.key,
228
+ label: field.label,
229
+ type: field.type,
230
+ required: field.required,
231
+ hidden: field.hidden,
232
+ disabled: field.disabled,
233
+ placeholder: field.placeholder?.trim() || field.label,
234
+ options: field.type === "select" && field.optionsMode === "static" ? builderEditorTextToOptions(field.optionsText) : void 0,
235
+ 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 ? {
236
+ type: "dbTable",
237
+ tableName: field.optionsTable,
238
+ valueField: field.optionsValueField,
239
+ labelField: field.optionsLabelField,
240
+ searchFields: builderEditorTextToSearchFields(field.optionsSearchFieldsText),
241
+ filterBy: field.optionsDependsOn && field.optionsFilterField ? {
242
+ field: field.optionsFilterField,
243
+ valueFromField: field.optionsDependsOn
244
+ } : void 0
245
+ } : void 0,
246
+ triggers: field.triggers.map((trigger) => ({
247
+ event: trigger.event,
248
+ action: trigger.action,
249
+ enabled: trigger.enabled,
250
+ debounceMs: trigger.debounceMs,
251
+ config: {}
252
+ }))
253
+ })),
254
+ layout: {
255
+ groups: normalizeBuilderFormEditorLayoutGroups(
256
+ values.layoutGroups,
257
+ values.fields,
258
+ values.subforms ?? []
259
+ )
260
+ },
261
+ subforms: (values.subforms ?? []).filter(
262
+ (subform) => subform.key && subform.label && subform.viewId !== BUILDER_EDITOR_NONE_VALUE && subform.parentField && subform.childField
263
+ ).map((subform) => ({
264
+ key: subform.key,
265
+ label: subform.label,
266
+ viewId: subform.viewId,
267
+ parentField: subform.parentField,
268
+ childField: subform.childField,
269
+ buttonLabel: subform.buttonLabel?.trim() || void 0,
270
+ icon: subform.icon?.trim() || void 0
271
+ }))
272
+ },
273
+ triggers: values.triggers.map((trigger) => ({
274
+ event: trigger.event,
275
+ action: "callApi",
276
+ enabled: trigger.enabled,
277
+ blocking: trigger.blocking,
278
+ config: { route: trigger.route }
279
+ })),
280
+ version: values.version
281
+ };
282
+ }
283
+ function builderListEditorInputFromValues(values) {
284
+ 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;
285
+ return {
286
+ title: values.title,
287
+ description: values.description || null,
288
+ source,
289
+ schema: { columns: values.columns },
290
+ triggers: values.triggers.map((trigger) => ({
291
+ event: trigger.event,
292
+ action: "callApi",
293
+ enabled: trigger.enabled,
294
+ blocking: trigger.blocking,
295
+ config: { route: trigger.route }
296
+ })),
297
+ version: values.version
298
+ };
299
+ }
300
+ function builderViewEditorInputFromValues(values, parseTriggers) {
301
+ return {
302
+ title: values.title,
303
+ description: values.description || null,
304
+ formId: values.formId === BUILDER_EDITOR_NONE_VALUE ? null : values.formId,
305
+ listId: values.listId === BUILDER_EDITOR_NONE_VALUE ? null : values.listId,
306
+ permissionRead: values.permissionRead,
307
+ permissionWrite: values.permissionWrite,
308
+ triggers: values.triggersText?.trim() ? parseTriggers(values.triggersText) : [],
309
+ version: values.version
310
+ };
311
+ }
312
+
313
+ // src/admin/BuilderEditorPage.tsx
314
+ import { jsx } from "react/jsx-runtime";
315
+ function createBuilderFormEditorPageComponent(deps) {
316
+ return function BuilderFormEditorPage({ formId }) {
317
+ const Body = deps.Body;
318
+ const entityQuery = deps.hooks.useEntity(formId);
319
+ const tables = deps.hooks.useTables();
320
+ const save = deps.hooks.useSave();
321
+ const form = useForm({
322
+ resolver: deps.resolver,
323
+ defaultValues: deps.emptyValues
324
+ });
325
+ const fieldArray = useFieldArray({ control: form.control, name: "fields" });
326
+ const subformArray = useFieldArray({ control: form.control, name: "subforms" });
327
+ const triggerArray = useFieldArray({ control: form.control, name: "triggers" });
328
+ const fields = useWatch({ control: form.control, name: "fields" }) ?? [];
329
+ const subforms = useWatch({ control: form.control, name: "subforms" }) ?? [];
330
+ const sourceType = useWatch({ control: form.control, name: "sourceType" });
331
+ const sourceTable = useWatch({ control: form.control, name: "sourceTable" });
332
+ useEffect(() => {
333
+ if (formId && !entityQuery.data) return;
334
+ form.reset(builderFormEditorValuesFromEntity(entityQuery.data ?? null, deps.emptyValues));
335
+ }, [entityQuery.data, form, formId]);
336
+ const importFieldsFromTable = () => {
337
+ const table = tables.data?.find((item) => item.name === sourceTable);
338
+ if (!table) return;
339
+ const nextFields = builderFormEditorFieldsFromTable(table);
340
+ fieldArray.replace(nextFields);
341
+ form.setValue("layoutGroups", builderFormEditorDefaultLayoutGroups(nextFields), {
342
+ shouldDirty: true
343
+ });
344
+ };
345
+ const onSubmit = form.handleSubmit(async (values) => {
346
+ try {
347
+ const saved = await save.mutateAsync({ id: formId, input: deps.buildInput(values) });
348
+ deps.notifications.success(formId ? deps.labels.saved : deps.labels.created);
349
+ if (!formId) deps.navigateAfterCreate(saved);
350
+ } catch (error) {
351
+ deps.notifications.error(error);
352
+ }
353
+ });
354
+ if (formId && entityQuery.isPending) {
355
+ return /* @__PURE__ */ jsx("div", { className: "text-muted-foreground text-sm", children: deps.states.loading });
356
+ }
357
+ if (formId && entityQuery.isError) {
358
+ return /* @__PURE__ */ jsx("div", { className: "text-destructive text-sm", children: deps.states.error });
359
+ }
360
+ return /* @__PURE__ */ jsx(FormProvider, { ...form, children: /* @__PURE__ */ jsx("form", { onSubmit, noValidate: true, className: "space-y-6", children: /* @__PURE__ */ jsx(
361
+ Body,
362
+ {
363
+ formId,
364
+ form,
365
+ fieldArray,
366
+ subformArray,
367
+ triggerArray,
368
+ fields,
369
+ subforms,
370
+ sourceType,
371
+ sourceTable,
372
+ tables: tables.data ?? [],
373
+ emptyField: deps.emptyField,
374
+ emptyTrigger: deps.emptyTrigger,
375
+ isSaving: save.isPending,
376
+ importFieldsFromTable
377
+ }
378
+ ) }) });
379
+ };
380
+ }
381
+ function createBuilderListEditorPageComponent(deps) {
382
+ return function BuilderListEditorPage({ listId }) {
383
+ const Body = deps.Body;
384
+ const entityQuery = deps.hooks.useEntity(listId);
385
+ const tables = deps.hooks.useTables();
386
+ const save = deps.hooks.useSave();
387
+ const form = useForm({
388
+ resolver: deps.resolver,
389
+ defaultValues: deps.emptyValues
390
+ });
391
+ const columnArray = useFieldArray({ control: form.control, name: "columns" });
392
+ const triggerArray = useFieldArray({ control: form.control, name: "triggers" });
393
+ const sourceType = useWatch({ control: form.control, name: "sourceType" });
394
+ const sourceTable = useWatch({ control: form.control, name: "sourceTable" });
395
+ useEffect(() => {
396
+ if (listId && !entityQuery.data) return;
397
+ form.reset(builderListEditorValuesFromEntity(entityQuery.data ?? null, deps.emptyValues));
398
+ }, [entityQuery.data, form, listId]);
399
+ const importColumnsFromTable = () => {
400
+ const table = tables.data?.find((item) => item.name === sourceTable);
401
+ if (!table) return;
402
+ columnArray.replace(builderListEditorColumnsFromTable(table));
403
+ };
404
+ const onSubmit = form.handleSubmit(async (values) => {
405
+ try {
406
+ const saved = await save.mutateAsync({ id: listId, input: deps.buildInput(values) });
407
+ deps.notifications.success(listId ? deps.labels.saved : deps.labels.created);
408
+ if (!listId) deps.navigateAfterCreate(saved);
409
+ } catch (error) {
410
+ deps.notifications.error(error);
411
+ }
412
+ });
413
+ if (listId && entityQuery.isPending) {
414
+ return /* @__PURE__ */ jsx("div", { className: "text-muted-foreground text-sm", children: deps.states.loading });
415
+ }
416
+ if (listId && entityQuery.isError) {
417
+ return /* @__PURE__ */ jsx("div", { className: "text-destructive text-sm", children: deps.states.error });
418
+ }
419
+ return /* @__PURE__ */ jsx(FormProvider, { ...form, children: /* @__PURE__ */ jsx("form", { onSubmit, noValidate: true, className: "space-y-6", children: /* @__PURE__ */ jsx(
420
+ Body,
421
+ {
422
+ listId,
423
+ form,
424
+ columnArray,
425
+ triggerArray,
426
+ sourceType,
427
+ sourceTable,
428
+ tables: tables.data ?? [],
429
+ emptyColumn: deps.emptyColumn,
430
+ emptyTrigger: deps.emptyTrigger,
431
+ isSaving: save.isPending,
432
+ importColumnsFromTable
433
+ }
434
+ ) }) });
435
+ };
436
+ }
437
+
438
+ // src/admin/BuilderEntityManager.tsx
439
+ import { useCallback, useMemo, useState } from "react";
440
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
441
+ function createBuilderEntityManagerComponent(deps) {
442
+ return function BuilderEntityManager() {
443
+ const [pendingDelete, setPendingDelete] = useState(null);
444
+ const state = deps.useDataTableState({ pageSize: 20 });
445
+ const query = deps.hooks.useEntities(state.query);
446
+ const remove = deps.hooks.useDelete();
447
+ const replicate = deps.hooks.useReplicate();
448
+ const columns = useMemo(
449
+ () => deps.buildColumns({
450
+ onEdit: deps.navigateToEdit,
451
+ onReplicate: async (entity) => {
452
+ const title = await deps.requestReplicateTitle(entity);
453
+ if (!title) return;
454
+ await replicate.mutateAsync({ id: entity.id, input: { title } });
455
+ },
456
+ onDelete: setPendingDelete,
457
+ runtimeHref: deps.runtimeHref
458
+ }),
459
+ [replicate]
460
+ );
461
+ const controller = deps.useDataTable({
462
+ columns,
463
+ data: query.data?.items ?? [],
464
+ rowCount: query.data?.total ?? 0,
465
+ state,
466
+ getRowId: (row) => row.id
467
+ });
468
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
469
+ /* @__PURE__ */ jsx2(
470
+ deps.DataGrid,
471
+ {
472
+ title: deps.labels.title,
473
+ description: deps.labels.description,
474
+ controller,
475
+ isLoading: query.isPending,
476
+ searchPlaceholder: deps.labels.searchPlaceholder,
477
+ emptyTitle: deps.labels.emptyTitle,
478
+ emptyDescription: deps.labels.emptyDescription,
479
+ onRowClick: deps.navigateToEdit,
480
+ toolbarExtra: /* @__PURE__ */ jsx2(deps.AddButton, { href: deps.createHref, label: deps.labels.addLabel })
481
+ }
482
+ ),
483
+ /* @__PURE__ */ jsx2(
484
+ deps.DeleteDialog,
485
+ {
486
+ entity: pendingDelete,
487
+ title: deps.labels.deleteTitle,
488
+ description: deps.labels.deleteDescription(pendingDelete),
489
+ isDeleting: remove.isPending,
490
+ onClose: () => setPendingDelete(null),
491
+ onConfirm: async () => {
492
+ if (!pendingDelete) return;
493
+ await remove.mutateAsync(pendingDelete.id);
494
+ setPendingDelete(null);
495
+ }
496
+ }
497
+ )
498
+ ] });
499
+ };
500
+ }
501
+ function createBuilderEntityDialogManagerComponent(deps) {
502
+ return function BuilderEntityDialogManager() {
503
+ const [editing, setEditing] = useState(null);
504
+ const [isEditorOpen, setEditorOpen] = useState(false);
505
+ const [pendingDelete, setPendingDelete] = useState(null);
506
+ const state = deps.useDataTableState({ pageSize: 20 });
507
+ const query = deps.hooks.useEntities(state.query);
508
+ const remove = deps.hooks.useDelete();
509
+ const replicate = deps.hooks.useReplicate();
510
+ const openEditor = useCallback((entity) => {
511
+ setEditing(entity);
512
+ setEditorOpen(true);
513
+ }, []);
514
+ const columns = useMemo(
515
+ () => deps.buildColumns({
516
+ onEdit: (entity) => openEditor(entity),
517
+ onReplicate: async (entity) => {
518
+ const title = await deps.requestReplicateTitle(entity);
519
+ if (!title) return;
520
+ await replicate.mutateAsync({ id: entity.id, input: { title } });
521
+ },
522
+ onDelete: setPendingDelete,
523
+ runtimeHref: deps.runtimeHref
524
+ }),
525
+ [replicate, openEditor]
526
+ );
527
+ const controller = deps.useDataTable({
528
+ columns,
529
+ data: query.data?.items ?? [],
530
+ rowCount: query.data?.total ?? 0,
531
+ state,
532
+ getRowId: (row) => row.id
533
+ });
534
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
535
+ /* @__PURE__ */ jsx2(
536
+ deps.DataGrid,
537
+ {
538
+ title: deps.labels.title,
539
+ description: deps.labels.description,
540
+ controller,
541
+ isLoading: query.isPending,
542
+ searchPlaceholder: deps.labels.searchPlaceholder,
543
+ emptyTitle: deps.labels.emptyTitle,
544
+ emptyDescription: deps.labels.emptyDescription,
545
+ onRowClick: openEditor,
546
+ toolbarExtra: /* @__PURE__ */ jsx2(deps.AddButton, { label: deps.labels.addLabel, onAdd: () => openEditor(null) })
547
+ }
548
+ ),
549
+ /* @__PURE__ */ jsx2(
550
+ deps.EditorDialog,
551
+ {
552
+ open: isEditorOpen,
553
+ editing,
554
+ onClose: () => setEditorOpen(false)
555
+ }
556
+ ),
557
+ /* @__PURE__ */ jsx2(
558
+ deps.DeleteDialog,
559
+ {
560
+ entity: pendingDelete,
561
+ title: deps.labels.deleteTitle,
562
+ description: deps.labels.deleteDescription(pendingDelete),
563
+ isDeleting: remove.isPending,
564
+ onClose: () => setPendingDelete(null),
565
+ onConfirm: async () => {
566
+ if (!pendingDelete) return;
567
+ await remove.mutateAsync(pendingDelete.id);
568
+ setPendingDelete(null);
569
+ }
570
+ }
571
+ )
572
+ ] });
573
+ };
574
+ }
575
+
576
+ // src/admin/BuilderViewDialog.tsx
577
+ import { useEffect as useEffect2 } from "react";
578
+ import { FormProvider as FormProvider2, useForm as useForm2 } from "react-hook-form";
579
+ import { jsx as jsx3 } from "react/jsx-runtime";
580
+ function createBuilderViewDialogComponent(deps) {
581
+ return function BuilderViewDialog({
582
+ open,
583
+ editing,
584
+ forms,
585
+ lists,
586
+ onClose,
587
+ onSave,
588
+ isSaving
589
+ }) {
590
+ const form = useForm2({
591
+ resolver: deps.resolver,
592
+ defaultValues: deps.emptyValues
593
+ });
594
+ useEffect2(() => {
595
+ if (!open) return;
596
+ form.reset(
597
+ builderViewEditorValuesFromEntity(editing, deps.emptyValues, deps.defaultPermission)
598
+ );
599
+ }, [editing, form, open]);
600
+ const onSubmit = form.handleSubmit(async (values) => {
601
+ try {
602
+ await onSave({ id: editing?.id, input: deps.buildInput(values) });
603
+ onClose();
604
+ deps.notifications.success(editing ? deps.labels.saved : deps.labels.created);
605
+ } catch (error) {
606
+ deps.notifications.error(error);
607
+ }
608
+ });
609
+ return /* @__PURE__ */ jsx3(deps.Shell, { open, editing, onClose, children: /* @__PURE__ */ jsx3(FormProvider2, { ...form, children: /* @__PURE__ */ jsx3("form", { onSubmit, noValidate: true, children: deps.Body({
610
+ form,
611
+ editing,
612
+ forms,
613
+ lists,
614
+ permissionOptions: deps.permissionOptions,
615
+ noneValue: deps.noneValue,
616
+ isSaving,
617
+ onClose
618
+ }) }) }) });
619
+ };
620
+ }
621
+ export {
622
+ BUILDER_EDITOR_NONE_VALUE,
623
+ builderEditorOptionsToText,
624
+ builderEditorSearchFieldsToText,
625
+ builderEditorTextToOptions,
626
+ builderEditorTextToSearchFields,
627
+ builderFormEditorDefaultLayoutGroups,
628
+ builderFormEditorDefaultSpan,
629
+ builderFormEditorFieldsFromTable,
630
+ builderFormEditorInputFromValues,
631
+ builderFormEditorValuesFromEntity,
632
+ builderListEditorColumnsFromTable,
633
+ builderListEditorInputFromValues,
634
+ builderListEditorValuesFromEntity,
635
+ builderViewEditorInputFromValues,
636
+ builderViewEditorValuesFromEntity,
637
+ createBuilderEntityDialogManagerComponent,
638
+ createBuilderEntityManagerComponent,
639
+ createBuilderFormEditorPageComponent,
640
+ createBuilderListEditorPageComponent,
641
+ createBuilderViewDialogComponent,
642
+ getBuilderEditorTriggerRoute
643
+ };
644
+ //# sourceMappingURL=index.js.map