@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.
- package/README.md +47 -59
- package/dist/BuilderAdminPages-Buy2nvjs.d.ts +592 -0
- package/dist/admin/index.d.ts +89 -430
- package/dist/admin/index.js +1588 -49
- package/dist/admin/index.js.map +1 -1
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.js +9 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +1686 -93
- package/dist/index.js.map +1 -1
- package/dist/integration/index.d.ts +52 -0
- package/dist/integration/index.js +2267 -0
- package/dist/integration/index.js.map +1 -0
- package/package.json +21 -1
package/dist/index.js
CHANGED
|
@@ -1,12 +1,3 @@
|
|
|
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
1
|
// src/admin/editorState.ts
|
|
11
2
|
var BUILDER_EDITOR_NONE_VALUE = "__none";
|
|
12
3
|
function builderEditorOptionsToText(options) {
|
|
@@ -175,15 +166,15 @@ function builderListEditorValuesFromEntity(list, emptyValues) {
|
|
|
175
166
|
version: list.version
|
|
176
167
|
};
|
|
177
168
|
}
|
|
178
|
-
function builderViewEditorValuesFromEntity(view, emptyValues, defaultPermission) {
|
|
169
|
+
function builderViewEditorValuesFromEntity(view, emptyValues, defaultPermission = "") {
|
|
179
170
|
if (!view) return emptyValues;
|
|
180
171
|
return {
|
|
181
172
|
title: view.title,
|
|
182
173
|
description: view.description ?? "",
|
|
183
174
|
formId: view.formId ?? BUILDER_EDITOR_NONE_VALUE,
|
|
184
175
|
listId: view.listId ?? BUILDER_EDITOR_NONE_VALUE,
|
|
185
|
-
permissionRead: view.permissionRead
|
|
186
|
-
permissionWrite: view.permissionWrite
|
|
176
|
+
permissionRead: view.permissionRead || defaultPermission,
|
|
177
|
+
permissionWrite: view.permissionWrite || defaultPermission,
|
|
187
178
|
triggersText: JSON.stringify(view.triggers ?? [], null, 2),
|
|
188
179
|
version: view.version
|
|
189
180
|
};
|
|
@@ -303,22 +294,1001 @@ function builderViewEditorInputFromValues(values, parseTriggers) {
|
|
|
303
294
|
description: values.description || null,
|
|
304
295
|
formId: values.formId === BUILDER_EDITOR_NONE_VALUE ? null : values.formId,
|
|
305
296
|
listId: values.listId === BUILDER_EDITOR_NONE_VALUE ? null : values.listId,
|
|
306
|
-
permissionRead: values.permissionRead,
|
|
307
|
-
permissionWrite: values.permissionWrite,
|
|
297
|
+
permissionRead: values.permissionRead || null,
|
|
298
|
+
permissionWrite: values.permissionWrite || null,
|
|
308
299
|
triggers: values.triggersText?.trim() ? parseTriggers(values.triggersText) : [],
|
|
309
300
|
version: values.version
|
|
310
301
|
};
|
|
311
302
|
}
|
|
312
303
|
|
|
304
|
+
// src/admin/BuilderDefaultEditorBodies.tsx
|
|
305
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
306
|
+
var styles = {
|
|
307
|
+
page: {
|
|
308
|
+
display: "grid",
|
|
309
|
+
gap: "1rem"
|
|
310
|
+
},
|
|
311
|
+
header: {
|
|
312
|
+
display: "flex",
|
|
313
|
+
justifyContent: "space-between",
|
|
314
|
+
gap: "1rem",
|
|
315
|
+
alignItems: "flex-start",
|
|
316
|
+
flexWrap: "wrap"
|
|
317
|
+
},
|
|
318
|
+
title: {
|
|
319
|
+
margin: 0,
|
|
320
|
+
fontSize: "1.5rem",
|
|
321
|
+
fontWeight: 650
|
|
322
|
+
},
|
|
323
|
+
description: {
|
|
324
|
+
margin: "0.25rem 0 0",
|
|
325
|
+
color: "var(--muted-foreground, #64748b)"
|
|
326
|
+
},
|
|
327
|
+
actions: {
|
|
328
|
+
display: "flex",
|
|
329
|
+
gap: "0.5rem",
|
|
330
|
+
flexWrap: "wrap"
|
|
331
|
+
},
|
|
332
|
+
section: {
|
|
333
|
+
border: "1px solid var(--border, #d4d4d8)",
|
|
334
|
+
borderRadius: "0.5rem",
|
|
335
|
+
background: "var(--background, #fff)",
|
|
336
|
+
overflow: "hidden"
|
|
337
|
+
},
|
|
338
|
+
sectionHeader: {
|
|
339
|
+
display: "flex",
|
|
340
|
+
justifyContent: "space-between",
|
|
341
|
+
gap: "1rem",
|
|
342
|
+
alignItems: "center",
|
|
343
|
+
padding: "0.75rem",
|
|
344
|
+
borderBottom: "1px solid var(--border, #d4d4d8)",
|
|
345
|
+
flexWrap: "wrap"
|
|
346
|
+
},
|
|
347
|
+
sectionTitle: {
|
|
348
|
+
margin: 0,
|
|
349
|
+
fontSize: "1rem",
|
|
350
|
+
fontWeight: 650
|
|
351
|
+
},
|
|
352
|
+
grid: {
|
|
353
|
+
display: "grid",
|
|
354
|
+
gap: "0.75rem",
|
|
355
|
+
padding: "0.75rem"
|
|
356
|
+
},
|
|
357
|
+
twoColumn: {
|
|
358
|
+
display: "grid",
|
|
359
|
+
gridTemplateColumns: "repeat(auto-fit, minmax(14rem, 1fr))",
|
|
360
|
+
gap: "0.75rem"
|
|
361
|
+
},
|
|
362
|
+
row: {
|
|
363
|
+
display: "grid",
|
|
364
|
+
gridTemplateColumns: "repeat(auto-fit, minmax(10rem, 1fr))",
|
|
365
|
+
gap: "0.5rem",
|
|
366
|
+
padding: "0.75rem",
|
|
367
|
+
borderBottom: "1px solid var(--border, #d4d4d8)"
|
|
368
|
+
},
|
|
369
|
+
field: {
|
|
370
|
+
display: "grid",
|
|
371
|
+
gap: "0.25rem",
|
|
372
|
+
fontSize: "0.875rem"
|
|
373
|
+
},
|
|
374
|
+
label: {
|
|
375
|
+
color: "var(--muted-foreground, #64748b)",
|
|
376
|
+
fontSize: "0.75rem",
|
|
377
|
+
fontWeight: 600
|
|
378
|
+
},
|
|
379
|
+
input: {
|
|
380
|
+
minWidth: 0,
|
|
381
|
+
border: "1px solid var(--border, #d4d4d8)",
|
|
382
|
+
borderRadius: "0.375rem",
|
|
383
|
+
padding: "0.5rem 0.625rem",
|
|
384
|
+
background: "var(--background, #fff)",
|
|
385
|
+
color: "inherit"
|
|
386
|
+
},
|
|
387
|
+
textarea: {
|
|
388
|
+
minWidth: 0,
|
|
389
|
+
minHeight: "5rem",
|
|
390
|
+
border: "1px solid var(--border, #d4d4d8)",
|
|
391
|
+
borderRadius: "0.375rem",
|
|
392
|
+
padding: "0.5rem 0.625rem",
|
|
393
|
+
background: "var(--background, #fff)",
|
|
394
|
+
color: "inherit",
|
|
395
|
+
resize: "vertical"
|
|
396
|
+
},
|
|
397
|
+
checkboxField: {
|
|
398
|
+
display: "flex",
|
|
399
|
+
alignItems: "center",
|
|
400
|
+
gap: "0.5rem",
|
|
401
|
+
fontSize: "0.875rem",
|
|
402
|
+
minHeight: "2.25rem"
|
|
403
|
+
},
|
|
404
|
+
button: {
|
|
405
|
+
border: "1px solid var(--border, #d4d4d8)",
|
|
406
|
+
borderRadius: "0.375rem",
|
|
407
|
+
background: "var(--background, #fff)",
|
|
408
|
+
color: "inherit",
|
|
409
|
+
cursor: "pointer",
|
|
410
|
+
padding: "0.5rem 0.75rem",
|
|
411
|
+
textDecoration: "none",
|
|
412
|
+
fontSize: "0.875rem"
|
|
413
|
+
},
|
|
414
|
+
primaryButton: {
|
|
415
|
+
border: "1px solid var(--primary, #18181b)",
|
|
416
|
+
borderRadius: "0.375rem",
|
|
417
|
+
background: "var(--primary, #18181b)",
|
|
418
|
+
color: "var(--primary-foreground, #fff)",
|
|
419
|
+
cursor: "pointer",
|
|
420
|
+
padding: "0.5rem 0.75rem",
|
|
421
|
+
textDecoration: "none",
|
|
422
|
+
fontSize: "0.875rem"
|
|
423
|
+
}
|
|
424
|
+
};
|
|
425
|
+
function optionItems(options) {
|
|
426
|
+
return options.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, children: option.label }, option.value));
|
|
427
|
+
}
|
|
428
|
+
function createBuilderDefaultFormEditorBody(options) {
|
|
429
|
+
return function BuilderDefaultFormEditorBody({
|
|
430
|
+
formId,
|
|
431
|
+
form,
|
|
432
|
+
fieldArray,
|
|
433
|
+
subformArray,
|
|
434
|
+
triggerArray,
|
|
435
|
+
fields,
|
|
436
|
+
sourceType,
|
|
437
|
+
sourceTable,
|
|
438
|
+
tables,
|
|
439
|
+
emptyField,
|
|
440
|
+
emptyTrigger,
|
|
441
|
+
isSaving,
|
|
442
|
+
importFieldsFromTable
|
|
443
|
+
}) {
|
|
444
|
+
return /* @__PURE__ */ jsxs("div", { style: styles.page, children: [
|
|
445
|
+
/* @__PURE__ */ jsxs("div", { style: styles.header, children: [
|
|
446
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
447
|
+
/* @__PURE__ */ jsx("h1", { style: styles.title, children: formId ? "Edit Dynamic Form" : "New Dynamic Form" }),
|
|
448
|
+
/* @__PURE__ */ jsx("p", { style: styles.description, children: "Configure fields, source mapping, layout, and triggers." })
|
|
449
|
+
] }),
|
|
450
|
+
/* @__PURE__ */ jsxs("div", { style: styles.actions, children: [
|
|
451
|
+
/* @__PURE__ */ jsx("a", { href: options.backHref, style: styles.button, children: "Cancel" }),
|
|
452
|
+
/* @__PURE__ */ jsx("button", { type: "submit", disabled: isSaving, style: styles.primaryButton, children: isSaving ? "Saving..." : "Save" })
|
|
453
|
+
] })
|
|
454
|
+
] }),
|
|
455
|
+
/* @__PURE__ */ jsxs("section", { style: styles.section, children: [
|
|
456
|
+
/* @__PURE__ */ jsx("div", { style: styles.sectionHeader, children: /* @__PURE__ */ jsx("h2", { style: styles.sectionTitle, children: "Details" }) }),
|
|
457
|
+
/* @__PURE__ */ jsxs("div", { style: { ...styles.grid, ...styles.twoColumn }, children: [
|
|
458
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
459
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Title" }),
|
|
460
|
+
/* @__PURE__ */ jsx("input", { style: styles.input, ...form.register("title", { required: true }) })
|
|
461
|
+
] }),
|
|
462
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
463
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Description" }),
|
|
464
|
+
/* @__PURE__ */ jsx("input", { style: styles.input, ...form.register("description") })
|
|
465
|
+
] }),
|
|
466
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
467
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Datasource" }),
|
|
468
|
+
/* @__PURE__ */ jsxs("select", { style: styles.input, ...form.register("sourceType"), children: [
|
|
469
|
+
/* @__PURE__ */ jsx("option", { value: "none", children: "None" }),
|
|
470
|
+
/* @__PURE__ */ jsx("option", { value: "dbTable", children: "DB table" }),
|
|
471
|
+
/* @__PURE__ */ jsx("option", { value: "apiEndpoint", children: "API endpoint" })
|
|
472
|
+
] })
|
|
473
|
+
] }),
|
|
474
|
+
sourceType === "dbTable" ? /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
475
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Table" }),
|
|
476
|
+
/* @__PURE__ */ jsxs("select", { style: styles.input, ...form.register("sourceTable"), children: [
|
|
477
|
+
/* @__PURE__ */ jsx("option", { value: BUILDER_EDITOR_NONE_VALUE, children: "Select table" }),
|
|
478
|
+
tables.map((table) => /* @__PURE__ */ jsx("option", { value: table.name, children: table.label ?? table.name }, table.name))
|
|
479
|
+
] })
|
|
480
|
+
] }) : null,
|
|
481
|
+
sourceType === "apiEndpoint" ? /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
482
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "API base path" }),
|
|
483
|
+
/* @__PURE__ */ jsx("input", { style: styles.input, ...form.register("apiBasePath") })
|
|
484
|
+
] }) : null,
|
|
485
|
+
sourceType === "dbTable" ? /* @__PURE__ */ jsx("div", { style: { ...styles.field, justifyContent: "end" }, children: /* @__PURE__ */ jsx(
|
|
486
|
+
"button",
|
|
487
|
+
{
|
|
488
|
+
type: "button",
|
|
489
|
+
style: styles.button,
|
|
490
|
+
disabled: sourceTable === BUILDER_EDITOR_NONE_VALUE,
|
|
491
|
+
onClick: importFieldsFromTable,
|
|
492
|
+
children: "Import fields"
|
|
493
|
+
}
|
|
494
|
+
) }) : null
|
|
495
|
+
] })
|
|
496
|
+
] }),
|
|
497
|
+
/* @__PURE__ */ jsxs("section", { style: styles.section, children: [
|
|
498
|
+
/* @__PURE__ */ jsxs("div", { style: styles.sectionHeader, children: [
|
|
499
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
500
|
+
/* @__PURE__ */ jsx("h2", { style: styles.sectionTitle, children: "Fields" }),
|
|
501
|
+
/* @__PURE__ */ jsx("p", { style: styles.description, children: "Runtime form inputs." })
|
|
502
|
+
] }),
|
|
503
|
+
/* @__PURE__ */ jsx(
|
|
504
|
+
"button",
|
|
505
|
+
{
|
|
506
|
+
type: "button",
|
|
507
|
+
style: styles.button,
|
|
508
|
+
onClick: () => {
|
|
509
|
+
const key = `field${fieldArray.fields.length + 1}`;
|
|
510
|
+
fieldArray.append({
|
|
511
|
+
...emptyField,
|
|
512
|
+
key,
|
|
513
|
+
label: `Field ${fieldArray.fields.length + 1}`,
|
|
514
|
+
type: options.fieldTypeOptions[0]?.value
|
|
515
|
+
});
|
|
516
|
+
},
|
|
517
|
+
children: "Add field"
|
|
518
|
+
}
|
|
519
|
+
)
|
|
520
|
+
] }),
|
|
521
|
+
fieldArray.fields.map((field, index) => /* @__PURE__ */ jsxs("div", { style: styles.row, children: [
|
|
522
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
523
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Key" }),
|
|
524
|
+
/* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`fields.${index}.key`) })
|
|
525
|
+
] }),
|
|
526
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
527
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Label" }),
|
|
528
|
+
/* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`fields.${index}.label`) })
|
|
529
|
+
] }),
|
|
530
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
531
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Type" }),
|
|
532
|
+
/* @__PURE__ */ jsx(
|
|
533
|
+
"select",
|
|
534
|
+
{
|
|
535
|
+
style: styles.input,
|
|
536
|
+
...form.register(`fields.${index}.type`),
|
|
537
|
+
children: optionItems(options.fieldTypeOptions)
|
|
538
|
+
}
|
|
539
|
+
)
|
|
540
|
+
] }),
|
|
541
|
+
/* @__PURE__ */ jsxs("label", { style: styles.checkboxField, children: [
|
|
542
|
+
/* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`fields.${index}.required`) }),
|
|
543
|
+
"Required"
|
|
544
|
+
] }),
|
|
545
|
+
/* @__PURE__ */ jsxs("label", { style: styles.checkboxField, children: [
|
|
546
|
+
/* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`fields.${index}.hidden`) }),
|
|
547
|
+
"Hidden"
|
|
548
|
+
] }),
|
|
549
|
+
/* @__PURE__ */ jsxs("label", { style: styles.checkboxField, children: [
|
|
550
|
+
/* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`fields.${index}.disabled`) }),
|
|
551
|
+
"Disabled"
|
|
552
|
+
] }),
|
|
553
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
554
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Placeholder" }),
|
|
555
|
+
/* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`fields.${index}.placeholder`) })
|
|
556
|
+
] }),
|
|
557
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
558
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Static options" }),
|
|
559
|
+
/* @__PURE__ */ jsx("textarea", { style: styles.textarea, ...form.register(`fields.${index}.optionsText`) })
|
|
560
|
+
] }),
|
|
561
|
+
/* @__PURE__ */ jsx("div", { style: styles.actions, children: /* @__PURE__ */ jsx(
|
|
562
|
+
"button",
|
|
563
|
+
{
|
|
564
|
+
type: "button",
|
|
565
|
+
style: styles.button,
|
|
566
|
+
onClick: () => fieldArray.remove(index),
|
|
567
|
+
disabled: fieldArray.fields.length <= 1,
|
|
568
|
+
children: "Remove"
|
|
569
|
+
}
|
|
570
|
+
) })
|
|
571
|
+
] }, field.id))
|
|
572
|
+
] }),
|
|
573
|
+
/* @__PURE__ */ jsxs("section", { style: styles.section, children: [
|
|
574
|
+
/* @__PURE__ */ jsxs("div", { style: styles.sectionHeader, children: [
|
|
575
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
576
|
+
/* @__PURE__ */ jsx("h2", { style: styles.sectionTitle, children: "Layout" }),
|
|
577
|
+
/* @__PURE__ */ jsx("p", { style: styles.description, children: "Default layout can be regenerated from current fields." })
|
|
578
|
+
] }),
|
|
579
|
+
/* @__PURE__ */ jsx(
|
|
580
|
+
"button",
|
|
581
|
+
{
|
|
582
|
+
type: "button",
|
|
583
|
+
style: styles.button,
|
|
584
|
+
onClick: () => form.setValue("layoutGroups", builderFormEditorDefaultLayoutGroups(fields), {
|
|
585
|
+
shouldDirty: true
|
|
586
|
+
}),
|
|
587
|
+
children: "Reset layout"
|
|
588
|
+
}
|
|
589
|
+
)
|
|
590
|
+
] }),
|
|
591
|
+
form.watch("layoutGroups").map((group, groupIndex) => /* @__PURE__ */ jsxs("div", { style: styles.row, children: [
|
|
592
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
593
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Group title" }),
|
|
594
|
+
/* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`layoutGroups.${groupIndex}.title`) })
|
|
595
|
+
] }),
|
|
596
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
597
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Columns" }),
|
|
598
|
+
/* @__PURE__ */ jsxs(
|
|
599
|
+
"select",
|
|
600
|
+
{
|
|
601
|
+
style: styles.input,
|
|
602
|
+
value: group.columns,
|
|
603
|
+
onChange: (event) => form.setValue(
|
|
604
|
+
`layoutGroups.${groupIndex}.columns`,
|
|
605
|
+
Number(event.target.value),
|
|
606
|
+
{ shouldDirty: true }
|
|
607
|
+
),
|
|
608
|
+
children: [
|
|
609
|
+
/* @__PURE__ */ jsx("option", { value: 6, children: "6" }),
|
|
610
|
+
/* @__PURE__ */ jsx("option", { value: 8, children: "8" }),
|
|
611
|
+
/* @__PURE__ */ jsx("option", { value: 12, children: "12" })
|
|
612
|
+
]
|
|
613
|
+
}
|
|
614
|
+
)
|
|
615
|
+
] }),
|
|
616
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
617
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Fields" }),
|
|
618
|
+
/* @__PURE__ */ jsx(
|
|
619
|
+
"input",
|
|
620
|
+
{
|
|
621
|
+
style: styles.input,
|
|
622
|
+
value: group.fields.map((item) => item.key).join(", "),
|
|
623
|
+
readOnly: true
|
|
624
|
+
}
|
|
625
|
+
)
|
|
626
|
+
] })
|
|
627
|
+
] }, group.id))
|
|
628
|
+
] }),
|
|
629
|
+
/* @__PURE__ */ jsxs("section", { style: styles.section, children: [
|
|
630
|
+
/* @__PURE__ */ jsxs("div", { style: styles.sectionHeader, children: [
|
|
631
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
632
|
+
/* @__PURE__ */ jsx("h2", { style: styles.sectionTitle, children: "Subforms" }),
|
|
633
|
+
/* @__PURE__ */ jsx("p", { style: styles.description, children: "Optional nested runtime view bindings." })
|
|
634
|
+
] }),
|
|
635
|
+
/* @__PURE__ */ jsx(
|
|
636
|
+
"button",
|
|
637
|
+
{
|
|
638
|
+
type: "button",
|
|
639
|
+
style: styles.button,
|
|
640
|
+
onClick: () => subformArray.append({
|
|
641
|
+
key: `subform${subformArray.fields.length + 1}`,
|
|
642
|
+
label: `Subform ${subformArray.fields.length + 1}`,
|
|
643
|
+
viewId: BUILDER_EDITOR_NONE_VALUE,
|
|
644
|
+
parentField: "id",
|
|
645
|
+
childField: "parentId",
|
|
646
|
+
buttonLabel: "",
|
|
647
|
+
icon: ""
|
|
648
|
+
}),
|
|
649
|
+
children: "Add subform"
|
|
650
|
+
}
|
|
651
|
+
)
|
|
652
|
+
] }),
|
|
653
|
+
subformArray.fields.map((subform, index) => /* @__PURE__ */ jsxs("div", { style: styles.row, children: [
|
|
654
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
655
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Key" }),
|
|
656
|
+
/* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`subforms.${index}.key`) })
|
|
657
|
+
] }),
|
|
658
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
659
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Label" }),
|
|
660
|
+
/* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`subforms.${index}.label`) })
|
|
661
|
+
] }),
|
|
662
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
663
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "View ID" }),
|
|
664
|
+
/* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`subforms.${index}.viewId`) })
|
|
665
|
+
] }),
|
|
666
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
667
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Parent field" }),
|
|
668
|
+
/* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`subforms.${index}.parentField`) })
|
|
669
|
+
] }),
|
|
670
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
671
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Child field" }),
|
|
672
|
+
/* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`subforms.${index}.childField`) })
|
|
673
|
+
] }),
|
|
674
|
+
/* @__PURE__ */ jsx("button", { type: "button", style: styles.button, onClick: () => subformArray.remove(index), children: "Remove" })
|
|
675
|
+
] }, subform.id))
|
|
676
|
+
] }),
|
|
677
|
+
/* @__PURE__ */ jsxs("section", { style: styles.section, children: [
|
|
678
|
+
/* @__PURE__ */ jsxs("div", { style: styles.sectionHeader, children: [
|
|
679
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
680
|
+
/* @__PURE__ */ jsx("h2", { style: styles.sectionTitle, children: "Form Triggers" }),
|
|
681
|
+
/* @__PURE__ */ jsx("p", { style: styles.description, children: "Optional API callbacks for lifecycle events." })
|
|
682
|
+
] }),
|
|
683
|
+
/* @__PURE__ */ jsx("button", { type: "button", style: styles.button, onClick: () => triggerArray.append(emptyTrigger), children: "Add trigger" })
|
|
684
|
+
] }),
|
|
685
|
+
triggerArray.fields.map((trigger, index) => /* @__PURE__ */ jsxs("div", { style: styles.row, children: [
|
|
686
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
687
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Event" }),
|
|
688
|
+
/* @__PURE__ */ jsx(
|
|
689
|
+
"select",
|
|
690
|
+
{
|
|
691
|
+
style: styles.input,
|
|
692
|
+
...form.register(
|
|
693
|
+
`triggers.${index}.event`
|
|
694
|
+
),
|
|
695
|
+
children: optionItems(options.formTriggerEventOptions)
|
|
696
|
+
}
|
|
697
|
+
)
|
|
698
|
+
] }),
|
|
699
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
700
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Route" }),
|
|
701
|
+
/* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`triggers.${index}.route`) })
|
|
702
|
+
] }),
|
|
703
|
+
/* @__PURE__ */ jsxs("label", { style: styles.checkboxField, children: [
|
|
704
|
+
/* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`triggers.${index}.enabled`) }),
|
|
705
|
+
"Enabled"
|
|
706
|
+
] }),
|
|
707
|
+
/* @__PURE__ */ jsxs("label", { style: styles.checkboxField, children: [
|
|
708
|
+
/* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`triggers.${index}.blocking`) }),
|
|
709
|
+
"Blocking"
|
|
710
|
+
] }),
|
|
711
|
+
/* @__PURE__ */ jsx("button", { type: "button", style: styles.button, onClick: () => triggerArray.remove(index), children: "Remove" })
|
|
712
|
+
] }, trigger.id))
|
|
713
|
+
] })
|
|
714
|
+
] });
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
function createBuilderDefaultListEditorBody(options) {
|
|
718
|
+
return function BuilderDefaultListEditorBody({
|
|
719
|
+
listId,
|
|
720
|
+
form,
|
|
721
|
+
columnArray,
|
|
722
|
+
triggerArray,
|
|
723
|
+
sourceType,
|
|
724
|
+
sourceTable,
|
|
725
|
+
tables,
|
|
726
|
+
emptyColumn,
|
|
727
|
+
emptyTrigger,
|
|
728
|
+
isSaving,
|
|
729
|
+
importColumnsFromTable
|
|
730
|
+
}) {
|
|
731
|
+
return /* @__PURE__ */ jsxs("div", { style: styles.page, children: [
|
|
732
|
+
/* @__PURE__ */ jsxs("div", { style: styles.header, children: [
|
|
733
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
734
|
+
/* @__PURE__ */ jsx("h1", { style: styles.title, children: listId ? "Edit Dynamic List" : "New Dynamic List" }),
|
|
735
|
+
/* @__PURE__ */ jsx("p", { style: styles.description, children: "Configure list columns, source mapping, and triggers." })
|
|
736
|
+
] }),
|
|
737
|
+
/* @__PURE__ */ jsxs("div", { style: styles.actions, children: [
|
|
738
|
+
/* @__PURE__ */ jsx("a", { href: options.backHref, style: styles.button, children: "Cancel" }),
|
|
739
|
+
/* @__PURE__ */ jsx("button", { type: "submit", disabled: isSaving, style: styles.primaryButton, children: isSaving ? "Saving..." : "Save" })
|
|
740
|
+
] })
|
|
741
|
+
] }),
|
|
742
|
+
/* @__PURE__ */ jsxs("section", { style: styles.section, children: [
|
|
743
|
+
/* @__PURE__ */ jsx("div", { style: styles.sectionHeader, children: /* @__PURE__ */ jsx("h2", { style: styles.sectionTitle, children: "Details" }) }),
|
|
744
|
+
/* @__PURE__ */ jsxs("div", { style: { ...styles.grid, ...styles.twoColumn }, children: [
|
|
745
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
746
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Title" }),
|
|
747
|
+
/* @__PURE__ */ jsx("input", { style: styles.input, ...form.register("title", { required: true }) })
|
|
748
|
+
] }),
|
|
749
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
750
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Description" }),
|
|
751
|
+
/* @__PURE__ */ jsx("input", { style: styles.input, ...form.register("description") })
|
|
752
|
+
] }),
|
|
753
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
754
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Datasource" }),
|
|
755
|
+
/* @__PURE__ */ jsxs("select", { style: styles.input, ...form.register("sourceType"), children: [
|
|
756
|
+
/* @__PURE__ */ jsx("option", { value: "none", children: "None" }),
|
|
757
|
+
/* @__PURE__ */ jsx("option", { value: "dbTable", children: "DB table" }),
|
|
758
|
+
/* @__PURE__ */ jsx("option", { value: "apiEndpoint", children: "API endpoint" })
|
|
759
|
+
] })
|
|
760
|
+
] }),
|
|
761
|
+
sourceType === "dbTable" ? /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
762
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Table" }),
|
|
763
|
+
/* @__PURE__ */ jsxs("select", { style: styles.input, ...form.register("sourceTable"), children: [
|
|
764
|
+
/* @__PURE__ */ jsx("option", { value: BUILDER_EDITOR_NONE_VALUE, children: "Select table" }),
|
|
765
|
+
tables.map((table) => /* @__PURE__ */ jsx("option", { value: table.name, children: table.label ?? table.name }, table.name))
|
|
766
|
+
] })
|
|
767
|
+
] }) : null,
|
|
768
|
+
sourceType === "apiEndpoint" ? /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
769
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "API base path" }),
|
|
770
|
+
/* @__PURE__ */ jsx("input", { style: styles.input, ...form.register("apiBasePath") })
|
|
771
|
+
] }) : null,
|
|
772
|
+
sourceType === "dbTable" ? /* @__PURE__ */ jsx("div", { style: { ...styles.field, justifyContent: "end" }, children: /* @__PURE__ */ jsx(
|
|
773
|
+
"button",
|
|
774
|
+
{
|
|
775
|
+
type: "button",
|
|
776
|
+
style: styles.button,
|
|
777
|
+
disabled: sourceTable === BUILDER_EDITOR_NONE_VALUE,
|
|
778
|
+
onClick: importColumnsFromTable,
|
|
779
|
+
children: "Import columns"
|
|
780
|
+
}
|
|
781
|
+
) }) : null
|
|
782
|
+
] })
|
|
783
|
+
] }),
|
|
784
|
+
/* @__PURE__ */ jsxs("section", { style: styles.section, children: [
|
|
785
|
+
/* @__PURE__ */ jsxs("div", { style: styles.sectionHeader, children: [
|
|
786
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
787
|
+
/* @__PURE__ */ jsx("h2", { style: styles.sectionTitle, children: "Columns" }),
|
|
788
|
+
/* @__PURE__ */ jsx("p", { style: styles.description, children: "Runtime list columns." })
|
|
789
|
+
] }),
|
|
790
|
+
/* @__PURE__ */ jsx(
|
|
791
|
+
"button",
|
|
792
|
+
{
|
|
793
|
+
type: "button",
|
|
794
|
+
style: styles.button,
|
|
795
|
+
onClick: () => columnArray.append({
|
|
796
|
+
...emptyColumn,
|
|
797
|
+
key: `field${columnArray.fields.length + 1}`,
|
|
798
|
+
label: `Column ${columnArray.fields.length + 1}`
|
|
799
|
+
}),
|
|
800
|
+
children: "Add column"
|
|
801
|
+
}
|
|
802
|
+
)
|
|
803
|
+
] }),
|
|
804
|
+
columnArray.fields.map((column, index) => /* @__PURE__ */ jsxs("div", { style: styles.row, children: [
|
|
805
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
806
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Key" }),
|
|
807
|
+
/* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`columns.${index}.key`) })
|
|
808
|
+
] }),
|
|
809
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
810
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Label" }),
|
|
811
|
+
/* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`columns.${index}.label`) })
|
|
812
|
+
] }),
|
|
813
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
814
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Align" }),
|
|
815
|
+
/* @__PURE__ */ jsxs("select", { style: styles.input, ...form.register(`columns.${index}.align`), children: [
|
|
816
|
+
/* @__PURE__ */ jsx("option", { value: "left", children: "Left" }),
|
|
817
|
+
/* @__PURE__ */ jsx("option", { value: "right", children: "Right" })
|
|
818
|
+
] })
|
|
819
|
+
] }),
|
|
820
|
+
/* @__PURE__ */ jsxs("label", { style: styles.checkboxField, children: [
|
|
821
|
+
/* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`columns.${index}.sortable`) }),
|
|
822
|
+
"Sortable"
|
|
823
|
+
] }),
|
|
824
|
+
/* @__PURE__ */ jsx(
|
|
825
|
+
"button",
|
|
826
|
+
{
|
|
827
|
+
type: "button",
|
|
828
|
+
style: styles.button,
|
|
829
|
+
onClick: () => columnArray.remove(index),
|
|
830
|
+
disabled: columnArray.fields.length <= 1,
|
|
831
|
+
children: "Remove"
|
|
832
|
+
}
|
|
833
|
+
)
|
|
834
|
+
] }, column.id))
|
|
835
|
+
] }),
|
|
836
|
+
/* @__PURE__ */ jsxs("section", { style: styles.section, children: [
|
|
837
|
+
/* @__PURE__ */ jsxs("div", { style: styles.sectionHeader, children: [
|
|
838
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
839
|
+
/* @__PURE__ */ jsx("h2", { style: styles.sectionTitle, children: "List Triggers" }),
|
|
840
|
+
/* @__PURE__ */ jsx("p", { style: styles.description, children: "Optional API callbacks for list lifecycle events." })
|
|
841
|
+
] }),
|
|
842
|
+
/* @__PURE__ */ jsx("button", { type: "button", style: styles.button, onClick: () => triggerArray.append(emptyTrigger), children: "Add trigger" })
|
|
843
|
+
] }),
|
|
844
|
+
triggerArray.fields.map((trigger, index) => /* @__PURE__ */ jsxs("div", { style: styles.row, children: [
|
|
845
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
846
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Event" }),
|
|
847
|
+
/* @__PURE__ */ jsx(
|
|
848
|
+
"select",
|
|
849
|
+
{
|
|
850
|
+
style: styles.input,
|
|
851
|
+
...form.register(
|
|
852
|
+
`triggers.${index}.event`
|
|
853
|
+
),
|
|
854
|
+
children: optionItems(options.listTriggerEventOptions)
|
|
855
|
+
}
|
|
856
|
+
)
|
|
857
|
+
] }),
|
|
858
|
+
/* @__PURE__ */ jsxs("label", { style: styles.field, children: [
|
|
859
|
+
/* @__PURE__ */ jsx("span", { style: styles.label, children: "Route" }),
|
|
860
|
+
/* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`triggers.${index}.route`) })
|
|
861
|
+
] }),
|
|
862
|
+
/* @__PURE__ */ jsxs("label", { style: styles.checkboxField, children: [
|
|
863
|
+
/* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`triggers.${index}.enabled`) }),
|
|
864
|
+
"Enabled"
|
|
865
|
+
] }),
|
|
866
|
+
/* @__PURE__ */ jsxs("label", { style: styles.checkboxField, children: [
|
|
867
|
+
/* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`triggers.${index}.blocking`) }),
|
|
868
|
+
"Blocking"
|
|
869
|
+
] }),
|
|
870
|
+
/* @__PURE__ */ jsx("button", { type: "button", style: styles.button, onClick: () => triggerArray.remove(index), children: "Remove" })
|
|
871
|
+
] }, trigger.id))
|
|
872
|
+
] })
|
|
873
|
+
] });
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
// src/admin/BuilderDefaultEntityManager.tsx
|
|
878
|
+
import { useMemo, useState } from "react";
|
|
879
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
880
|
+
var styles2 = {
|
|
881
|
+
page: {
|
|
882
|
+
display: "grid",
|
|
883
|
+
gap: "1rem"
|
|
884
|
+
},
|
|
885
|
+
header: {
|
|
886
|
+
display: "flex",
|
|
887
|
+
justifyContent: "space-between",
|
|
888
|
+
gap: "1rem",
|
|
889
|
+
alignItems: "flex-start",
|
|
890
|
+
flexWrap: "wrap"
|
|
891
|
+
},
|
|
892
|
+
title: {
|
|
893
|
+
margin: 0,
|
|
894
|
+
fontSize: "1.5rem",
|
|
895
|
+
fontWeight: 650
|
|
896
|
+
},
|
|
897
|
+
description: {
|
|
898
|
+
margin: "0.25rem 0 0",
|
|
899
|
+
color: "var(--muted-foreground, #64748b)"
|
|
900
|
+
},
|
|
901
|
+
button: {
|
|
902
|
+
border: "1px solid var(--border, #d4d4d8)",
|
|
903
|
+
borderRadius: "0.375rem",
|
|
904
|
+
background: "var(--background, #fff)",
|
|
905
|
+
color: "inherit",
|
|
906
|
+
cursor: "pointer",
|
|
907
|
+
padding: "0.5rem 0.75rem",
|
|
908
|
+
textDecoration: "none",
|
|
909
|
+
fontSize: "0.875rem"
|
|
910
|
+
},
|
|
911
|
+
primaryButton: {
|
|
912
|
+
border: "1px solid var(--primary, #18181b)",
|
|
913
|
+
borderRadius: "0.375rem",
|
|
914
|
+
background: "var(--primary, #18181b)",
|
|
915
|
+
color: "var(--primary-foreground, #fff)",
|
|
916
|
+
cursor: "pointer",
|
|
917
|
+
padding: "0.5rem 0.75rem",
|
|
918
|
+
textDecoration: "none",
|
|
919
|
+
fontSize: "0.875rem"
|
|
920
|
+
},
|
|
921
|
+
card: {
|
|
922
|
+
border: "1px solid var(--border, #d4d4d8)",
|
|
923
|
+
borderRadius: "0.5rem",
|
|
924
|
+
overflow: "hidden",
|
|
925
|
+
background: "var(--background, #fff)"
|
|
926
|
+
},
|
|
927
|
+
toolbar: {
|
|
928
|
+
padding: "0.75rem",
|
|
929
|
+
borderBottom: "1px solid var(--border, #d4d4d8)"
|
|
930
|
+
},
|
|
931
|
+
input: {
|
|
932
|
+
width: "100%",
|
|
933
|
+
maxWidth: "24rem",
|
|
934
|
+
border: "1px solid var(--border, #d4d4d8)",
|
|
935
|
+
borderRadius: "0.375rem",
|
|
936
|
+
padding: "0.5rem 0.75rem",
|
|
937
|
+
background: "var(--background, #fff)",
|
|
938
|
+
color: "inherit"
|
|
939
|
+
},
|
|
940
|
+
tableWrap: {
|
|
941
|
+
overflowX: "auto"
|
|
942
|
+
},
|
|
943
|
+
table: {
|
|
944
|
+
width: "100%",
|
|
945
|
+
borderCollapse: "collapse",
|
|
946
|
+
fontSize: "0.875rem"
|
|
947
|
+
},
|
|
948
|
+
th: {
|
|
949
|
+
padding: "0.75rem",
|
|
950
|
+
borderBottom: "1px solid var(--border, #d4d4d8)",
|
|
951
|
+
textAlign: "left",
|
|
952
|
+
color: "var(--muted-foreground, #64748b)",
|
|
953
|
+
fontWeight: 600,
|
|
954
|
+
whiteSpace: "nowrap"
|
|
955
|
+
},
|
|
956
|
+
td: {
|
|
957
|
+
padding: "0.75rem",
|
|
958
|
+
borderBottom: "1px solid var(--border, #d4d4d8)",
|
|
959
|
+
verticalAlign: "top"
|
|
960
|
+
},
|
|
961
|
+
actions: {
|
|
962
|
+
display: "flex",
|
|
963
|
+
justifyContent: "flex-end",
|
|
964
|
+
gap: "0.5rem",
|
|
965
|
+
flexWrap: "wrap"
|
|
966
|
+
},
|
|
967
|
+
empty: {
|
|
968
|
+
padding: "2rem",
|
|
969
|
+
textAlign: "center",
|
|
970
|
+
color: "var(--muted-foreground, #64748b)"
|
|
971
|
+
}
|
|
972
|
+
};
|
|
973
|
+
function createBuilderDefaultEntityManagerComponent(deps) {
|
|
974
|
+
return function BuilderDefaultEntityManager() {
|
|
975
|
+
const [state, setState] = useState({
|
|
976
|
+
page: 1,
|
|
977
|
+
pageSize: 20,
|
|
978
|
+
search: ""
|
|
979
|
+
});
|
|
980
|
+
const query = deps.hooks.useEntities(useMemo(() => deps.buildQuery(state), [state]));
|
|
981
|
+
const remove = deps.hooks.useDelete();
|
|
982
|
+
const replicate = deps.hooks.useReplicate();
|
|
983
|
+
const items = query.data?.items ?? [];
|
|
984
|
+
const onReplicate = async (entity) => {
|
|
985
|
+
const title = window.prompt(
|
|
986
|
+
deps.labels.replicatePrompt(entity),
|
|
987
|
+
deps.labels.replicateDefaultTitle(entity)
|
|
988
|
+
);
|
|
989
|
+
if (!title) return;
|
|
990
|
+
await replicate.mutateAsync({ id: entity.id, input: { title } });
|
|
991
|
+
};
|
|
992
|
+
const onDelete = async (entity) => {
|
|
993
|
+
if (!window.confirm(deps.labels.deleteConfirm(entity))) return;
|
|
994
|
+
await remove.mutateAsync(entity.id);
|
|
995
|
+
};
|
|
996
|
+
return /* @__PURE__ */ jsxs2("section", { style: styles2.page, children: [
|
|
997
|
+
/* @__PURE__ */ jsxs2("div", { style: styles2.header, children: [
|
|
998
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
999
|
+
/* @__PURE__ */ jsx2("h1", { style: styles2.title, children: deps.labels.title }),
|
|
1000
|
+
/* @__PURE__ */ jsx2("p", { style: styles2.description, children: deps.labels.description })
|
|
1001
|
+
] }),
|
|
1002
|
+
deps.createHref ? /* @__PURE__ */ jsx2("a", { href: deps.createHref, style: styles2.primaryButton, children: deps.labels.addLabel }) : null
|
|
1003
|
+
] }),
|
|
1004
|
+
/* @__PURE__ */ jsxs2("div", { style: styles2.card, children: [
|
|
1005
|
+
/* @__PURE__ */ jsx2("div", { style: styles2.toolbar, children: /* @__PURE__ */ jsx2(
|
|
1006
|
+
"input",
|
|
1007
|
+
{
|
|
1008
|
+
style: styles2.input,
|
|
1009
|
+
placeholder: deps.labels.searchPlaceholder,
|
|
1010
|
+
value: state.search,
|
|
1011
|
+
onChange: (event) => setState((current) => ({ ...current, page: 1, search: event.target.value }))
|
|
1012
|
+
}
|
|
1013
|
+
) }),
|
|
1014
|
+
/* @__PURE__ */ jsx2("div", { style: styles2.tableWrap, children: /* @__PURE__ */ jsxs2("table", { style: styles2.table, children: [
|
|
1015
|
+
/* @__PURE__ */ jsx2("thead", { children: /* @__PURE__ */ jsxs2("tr", { children: [
|
|
1016
|
+
/* @__PURE__ */ jsx2("th", { style: styles2.th, children: deps.labels.title }),
|
|
1017
|
+
/* @__PURE__ */ jsx2("th", { style: styles2.th, children: "Detail" }),
|
|
1018
|
+
/* @__PURE__ */ jsx2("th", { style: styles2.th, children: "Description" }),
|
|
1019
|
+
/* @__PURE__ */ jsx2("th", { style: { ...styles2.th, textAlign: "right" }, children: "Actions" })
|
|
1020
|
+
] }) }),
|
|
1021
|
+
/* @__PURE__ */ jsx2("tbody", { children: items.map((entity) => /* @__PURE__ */ jsxs2("tr", { children: [
|
|
1022
|
+
/* @__PURE__ */ jsx2("td", { style: styles2.td, children: /* @__PURE__ */ jsx2("a", { href: deps.editHref(entity), children: entity.title }) }),
|
|
1023
|
+
/* @__PURE__ */ jsx2("td", { style: styles2.td, children: deps.getDetail?.(entity) ?? "-" }),
|
|
1024
|
+
/* @__PURE__ */ jsx2("td", { style: styles2.td, children: entity.description || "-" }),
|
|
1025
|
+
/* @__PURE__ */ jsx2("td", { style: styles2.td, children: /* @__PURE__ */ jsxs2("div", { style: styles2.actions, children: [
|
|
1026
|
+
deps.runtimeHref ? /* @__PURE__ */ jsx2("a", { href: deps.runtimeHref(entity), style: styles2.button, children: deps.labels.runtimeLabel }) : null,
|
|
1027
|
+
/* @__PURE__ */ jsx2("a", { href: deps.editHref(entity), style: styles2.button, children: deps.labels.editLabel }),
|
|
1028
|
+
/* @__PURE__ */ jsx2(
|
|
1029
|
+
"button",
|
|
1030
|
+
{
|
|
1031
|
+
type: "button",
|
|
1032
|
+
style: styles2.button,
|
|
1033
|
+
onClick: () => void onReplicate(entity),
|
|
1034
|
+
children: deps.labels.replicateLabel
|
|
1035
|
+
}
|
|
1036
|
+
),
|
|
1037
|
+
/* @__PURE__ */ jsx2(
|
|
1038
|
+
"button",
|
|
1039
|
+
{
|
|
1040
|
+
type: "button",
|
|
1041
|
+
style: styles2.button,
|
|
1042
|
+
disabled: remove.isPending,
|
|
1043
|
+
onClick: () => void onDelete(entity),
|
|
1044
|
+
children: deps.labels.deleteLabel
|
|
1045
|
+
}
|
|
1046
|
+
)
|
|
1047
|
+
] }) })
|
|
1048
|
+
] }, entity.id)) })
|
|
1049
|
+
] }) }),
|
|
1050
|
+
query.isPending ? /* @__PURE__ */ jsx2("div", { style: styles2.empty, children: "Loading..." }) : null,
|
|
1051
|
+
query.isError ? /* @__PURE__ */ jsx2("div", { style: styles2.empty, children: "Failed to load." }) : null,
|
|
1052
|
+
!query.isPending && !query.isError && items.length === 0 ? /* @__PURE__ */ jsxs2("div", { style: styles2.empty, children: [
|
|
1053
|
+
/* @__PURE__ */ jsx2("strong", { children: deps.labels.emptyTitle }),
|
|
1054
|
+
/* @__PURE__ */ jsx2("div", { children: deps.labels.emptyDescription })
|
|
1055
|
+
] }) : null
|
|
1056
|
+
] })
|
|
1057
|
+
] });
|
|
1058
|
+
};
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
// src/admin/BuilderDefaultViewEditorPage.tsx
|
|
1062
|
+
import { useEffect } from "react";
|
|
1063
|
+
import { useForm } from "react-hook-form";
|
|
1064
|
+
import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1065
|
+
var styles3 = {
|
|
1066
|
+
page: {
|
|
1067
|
+
display: "grid",
|
|
1068
|
+
gap: "1rem"
|
|
1069
|
+
},
|
|
1070
|
+
header: {
|
|
1071
|
+
display: "flex",
|
|
1072
|
+
justifyContent: "space-between",
|
|
1073
|
+
gap: "1rem",
|
|
1074
|
+
alignItems: "flex-start",
|
|
1075
|
+
flexWrap: "wrap"
|
|
1076
|
+
},
|
|
1077
|
+
title: {
|
|
1078
|
+
margin: 0,
|
|
1079
|
+
fontSize: "1.5rem",
|
|
1080
|
+
fontWeight: 650
|
|
1081
|
+
},
|
|
1082
|
+
description: {
|
|
1083
|
+
margin: "0.25rem 0 0",
|
|
1084
|
+
color: "var(--muted-foreground, #64748b)"
|
|
1085
|
+
},
|
|
1086
|
+
actions: {
|
|
1087
|
+
display: "flex",
|
|
1088
|
+
gap: "0.5rem",
|
|
1089
|
+
flexWrap: "wrap"
|
|
1090
|
+
},
|
|
1091
|
+
section: {
|
|
1092
|
+
border: "1px solid var(--border, #d4d4d8)",
|
|
1093
|
+
borderRadius: "0.5rem",
|
|
1094
|
+
background: "var(--background, #fff)",
|
|
1095
|
+
overflow: "hidden"
|
|
1096
|
+
},
|
|
1097
|
+
grid: {
|
|
1098
|
+
display: "grid",
|
|
1099
|
+
gridTemplateColumns: "repeat(auto-fit, minmax(14rem, 1fr))",
|
|
1100
|
+
gap: "0.75rem",
|
|
1101
|
+
padding: "0.75rem"
|
|
1102
|
+
},
|
|
1103
|
+
field: {
|
|
1104
|
+
display: "grid",
|
|
1105
|
+
gap: "0.25rem",
|
|
1106
|
+
fontSize: "0.875rem"
|
|
1107
|
+
},
|
|
1108
|
+
label: {
|
|
1109
|
+
color: "var(--muted-foreground, #64748b)",
|
|
1110
|
+
fontSize: "0.75rem",
|
|
1111
|
+
fontWeight: 600
|
|
1112
|
+
},
|
|
1113
|
+
input: {
|
|
1114
|
+
minWidth: 0,
|
|
1115
|
+
border: "1px solid var(--border, #d4d4d8)",
|
|
1116
|
+
borderRadius: "0.375rem",
|
|
1117
|
+
padding: "0.5rem 0.625rem",
|
|
1118
|
+
background: "var(--background, #fff)",
|
|
1119
|
+
color: "inherit"
|
|
1120
|
+
},
|
|
1121
|
+
textarea: {
|
|
1122
|
+
minWidth: 0,
|
|
1123
|
+
minHeight: "8rem",
|
|
1124
|
+
border: "1px solid var(--border, #d4d4d8)",
|
|
1125
|
+
borderRadius: "0.375rem",
|
|
1126
|
+
padding: "0.5rem 0.625rem",
|
|
1127
|
+
background: "var(--background, #fff)",
|
|
1128
|
+
color: "inherit",
|
|
1129
|
+
resize: "vertical"
|
|
1130
|
+
},
|
|
1131
|
+
button: {
|
|
1132
|
+
border: "1px solid var(--border, #d4d4d8)",
|
|
1133
|
+
borderRadius: "0.375rem",
|
|
1134
|
+
background: "var(--background, #fff)",
|
|
1135
|
+
color: "inherit",
|
|
1136
|
+
cursor: "pointer",
|
|
1137
|
+
padding: "0.5rem 0.75rem",
|
|
1138
|
+
textDecoration: "none",
|
|
1139
|
+
fontSize: "0.875rem"
|
|
1140
|
+
},
|
|
1141
|
+
primaryButton: {
|
|
1142
|
+
border: "1px solid var(--primary, #18181b)",
|
|
1143
|
+
borderRadius: "0.375rem",
|
|
1144
|
+
background: "var(--primary, #18181b)",
|
|
1145
|
+
color: "var(--primary-foreground, #fff)",
|
|
1146
|
+
cursor: "pointer",
|
|
1147
|
+
padding: "0.5rem 0.75rem",
|
|
1148
|
+
textDecoration: "none",
|
|
1149
|
+
fontSize: "0.875rem"
|
|
1150
|
+
},
|
|
1151
|
+
state: {
|
|
1152
|
+
color: "var(--muted-foreground, #64748b)",
|
|
1153
|
+
fontSize: "0.875rem"
|
|
1154
|
+
}
|
|
1155
|
+
};
|
|
1156
|
+
var defaultEmptyValues = {
|
|
1157
|
+
title: "",
|
|
1158
|
+
description: "",
|
|
1159
|
+
formId: BUILDER_EDITOR_NONE_VALUE,
|
|
1160
|
+
listId: BUILDER_EDITOR_NONE_VALUE,
|
|
1161
|
+
permissionRead: "",
|
|
1162
|
+
permissionWrite: "",
|
|
1163
|
+
triggersText: "[]",
|
|
1164
|
+
version: 0
|
|
1165
|
+
};
|
|
1166
|
+
function createBuilderDefaultViewEditorPage(options) {
|
|
1167
|
+
const defaultPermission = options.defaultPermission ?? "";
|
|
1168
|
+
const showPermissions = options.permissionOptions.length > 0;
|
|
1169
|
+
return function BuilderDefaultViewEditorPage({ viewId }) {
|
|
1170
|
+
const view = options.hooks.useBuilderView(viewId);
|
|
1171
|
+
const forms = options.hooks.useBuilderFormOptions();
|
|
1172
|
+
const lists = options.hooks.useBuilderListOptions();
|
|
1173
|
+
const save = options.hooks.useSaveBuilderView();
|
|
1174
|
+
const form = useForm({
|
|
1175
|
+
defaultValues: {
|
|
1176
|
+
...defaultEmptyValues,
|
|
1177
|
+
permissionRead: defaultPermission,
|
|
1178
|
+
permissionWrite: defaultPermission
|
|
1179
|
+
}
|
|
1180
|
+
});
|
|
1181
|
+
useEffect(() => {
|
|
1182
|
+
if (viewId && !view.data) return;
|
|
1183
|
+
form.reset(
|
|
1184
|
+
builderViewEditorValuesFromEntity(
|
|
1185
|
+
view.data ?? null,
|
|
1186
|
+
{
|
|
1187
|
+
...defaultEmptyValues,
|
|
1188
|
+
permissionRead: defaultPermission,
|
|
1189
|
+
permissionWrite: defaultPermission
|
|
1190
|
+
},
|
|
1191
|
+
defaultPermission
|
|
1192
|
+
)
|
|
1193
|
+
);
|
|
1194
|
+
}, [form, view.data, viewId]);
|
|
1195
|
+
const onSubmit = form.handleSubmit(async (values) => {
|
|
1196
|
+
try {
|
|
1197
|
+
const input = builderViewEditorInputFromValues(values, options.parseTriggers);
|
|
1198
|
+
const saved = await save.mutateAsync({
|
|
1199
|
+
id: viewId,
|
|
1200
|
+
input
|
|
1201
|
+
});
|
|
1202
|
+
options.notifySuccess?.(viewId ? "View saved" : "View created");
|
|
1203
|
+
if (!viewId) {
|
|
1204
|
+
window.location.assign(options.editHref(saved.id));
|
|
1205
|
+
}
|
|
1206
|
+
} catch (error) {
|
|
1207
|
+
if (options.notifyError) options.notifyError(error);
|
|
1208
|
+
else throw error;
|
|
1209
|
+
}
|
|
1210
|
+
});
|
|
1211
|
+
if (viewId && view.isPending) {
|
|
1212
|
+
return /* @__PURE__ */ jsx3("div", { style: styles3.state, children: "Loading..." });
|
|
1213
|
+
}
|
|
1214
|
+
if (viewId && view.isError) {
|
|
1215
|
+
return /* @__PURE__ */ jsx3("div", { style: styles3.state, children: "Failed to load view." });
|
|
1216
|
+
}
|
|
1217
|
+
return /* @__PURE__ */ jsxs3("form", { onSubmit, noValidate: true, style: styles3.page, children: [
|
|
1218
|
+
/* @__PURE__ */ jsxs3("div", { style: styles3.header, children: [
|
|
1219
|
+
/* @__PURE__ */ jsxs3("div", { children: [
|
|
1220
|
+
/* @__PURE__ */ jsx3("h1", { style: styles3.title, children: viewId ? "Edit Dynamic View" : "New Dynamic View" }),
|
|
1221
|
+
/* @__PURE__ */ jsx3("p", { style: styles3.description, children: "Connect a form and list into a runtime screen." })
|
|
1222
|
+
] }),
|
|
1223
|
+
/* @__PURE__ */ jsxs3("div", { style: styles3.actions, children: [
|
|
1224
|
+
/* @__PURE__ */ jsx3("a", { href: options.backHref, style: styles3.button, children: "Cancel" }),
|
|
1225
|
+
/* @__PURE__ */ jsx3("button", { type: "submit", disabled: save.isPending, style: styles3.primaryButton, children: save.isPending ? "Saving..." : "Save" })
|
|
1226
|
+
] })
|
|
1227
|
+
] }),
|
|
1228
|
+
/* @__PURE__ */ jsx3("section", { style: styles3.section, children: /* @__PURE__ */ jsxs3("div", { style: styles3.grid, children: [
|
|
1229
|
+
/* @__PURE__ */ jsxs3("label", { style: styles3.field, children: [
|
|
1230
|
+
/* @__PURE__ */ jsx3("span", { style: styles3.label, children: "Title" }),
|
|
1231
|
+
/* @__PURE__ */ jsx3("input", { style: styles3.input, ...form.register("title", { required: true }) })
|
|
1232
|
+
] }),
|
|
1233
|
+
/* @__PURE__ */ jsxs3("label", { style: styles3.field, children: [
|
|
1234
|
+
/* @__PURE__ */ jsx3("span", { style: styles3.label, children: "Description" }),
|
|
1235
|
+
/* @__PURE__ */ jsx3("input", { style: styles3.input, ...form.register("description") })
|
|
1236
|
+
] }),
|
|
1237
|
+
/* @__PURE__ */ jsxs3("label", { style: styles3.field, children: [
|
|
1238
|
+
/* @__PURE__ */ jsx3("span", { style: styles3.label, children: "Form" }),
|
|
1239
|
+
/* @__PURE__ */ jsxs3("select", { style: styles3.input, ...form.register("formId"), children: [
|
|
1240
|
+
/* @__PURE__ */ jsx3("option", { value: BUILDER_EDITOR_NONE_VALUE, children: "No form" }),
|
|
1241
|
+
(forms.data ?? []).map((item) => /* @__PURE__ */ jsx3("option", { value: item.id, children: item.title }, item.id))
|
|
1242
|
+
] })
|
|
1243
|
+
] }),
|
|
1244
|
+
/* @__PURE__ */ jsxs3("label", { style: styles3.field, children: [
|
|
1245
|
+
/* @__PURE__ */ jsx3("span", { style: styles3.label, children: "List" }),
|
|
1246
|
+
/* @__PURE__ */ jsxs3("select", { style: styles3.input, ...form.register("listId"), children: [
|
|
1247
|
+
/* @__PURE__ */ jsx3("option", { value: BUILDER_EDITOR_NONE_VALUE, children: "No list" }),
|
|
1248
|
+
(lists.data ?? []).map((item) => /* @__PURE__ */ jsx3("option", { value: item.id, children: item.title }, item.id))
|
|
1249
|
+
] })
|
|
1250
|
+
] }),
|
|
1251
|
+
showPermissions ? /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
1252
|
+
/* @__PURE__ */ jsxs3("label", { style: styles3.field, children: [
|
|
1253
|
+
/* @__PURE__ */ jsx3("span", { style: styles3.label, children: "Read permission" }),
|
|
1254
|
+
/* @__PURE__ */ jsxs3("select", { style: styles3.input, ...form.register("permissionRead"), children: [
|
|
1255
|
+
/* @__PURE__ */ jsx3("option", { value: "", children: "Authenticated users" }),
|
|
1256
|
+
options.permissionOptions.map((permission) => /* @__PURE__ */ jsx3("option", { value: permission.value, children: permission.label }, permission.value))
|
|
1257
|
+
] })
|
|
1258
|
+
] }),
|
|
1259
|
+
/* @__PURE__ */ jsxs3("label", { style: styles3.field, children: [
|
|
1260
|
+
/* @__PURE__ */ jsx3("span", { style: styles3.label, children: "Write permission" }),
|
|
1261
|
+
/* @__PURE__ */ jsxs3("select", { style: styles3.input, ...form.register("permissionWrite"), children: [
|
|
1262
|
+
/* @__PURE__ */ jsx3("option", { value: "", children: "Authenticated users" }),
|
|
1263
|
+
options.permissionOptions.map((permission) => /* @__PURE__ */ jsx3("option", { value: permission.value, children: permission.label }, permission.value))
|
|
1264
|
+
] })
|
|
1265
|
+
] })
|
|
1266
|
+
] }) : null,
|
|
1267
|
+
/* @__PURE__ */ jsxs3("label", { style: { ...styles3.field, gridColumn: "1 / -1" }, children: [
|
|
1268
|
+
/* @__PURE__ */ jsx3("span", { style: styles3.label, children: "Triggers JSON" }),
|
|
1269
|
+
/* @__PURE__ */ jsx3("textarea", { style: styles3.textarea, ...form.register("triggersText") })
|
|
1270
|
+
] })
|
|
1271
|
+
] }) })
|
|
1272
|
+
] });
|
|
1273
|
+
};
|
|
1274
|
+
}
|
|
1275
|
+
|
|
313
1276
|
// src/admin/BuilderEditorPage.tsx
|
|
314
|
-
import {
|
|
1277
|
+
import { useEffect as useEffect2 } from "react";
|
|
1278
|
+
import {
|
|
1279
|
+
FormProvider,
|
|
1280
|
+
useFieldArray,
|
|
1281
|
+
useForm as useForm2,
|
|
1282
|
+
useWatch
|
|
1283
|
+
} from "react-hook-form";
|
|
1284
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
315
1285
|
function createBuilderFormEditorPageComponent(deps) {
|
|
316
1286
|
return function BuilderFormEditorPage({ formId }) {
|
|
317
1287
|
const Body = deps.Body;
|
|
318
1288
|
const entityQuery = deps.hooks.useEntity(formId);
|
|
319
1289
|
const tables = deps.hooks.useTables();
|
|
320
1290
|
const save = deps.hooks.useSave();
|
|
321
|
-
const form =
|
|
1291
|
+
const form = useForm2({
|
|
322
1292
|
resolver: deps.resolver,
|
|
323
1293
|
defaultValues: deps.emptyValues
|
|
324
1294
|
});
|
|
@@ -329,7 +1299,7 @@ function createBuilderFormEditorPageComponent(deps) {
|
|
|
329
1299
|
const subforms = useWatch({ control: form.control, name: "subforms" }) ?? [];
|
|
330
1300
|
const sourceType = useWatch({ control: form.control, name: "sourceType" });
|
|
331
1301
|
const sourceTable = useWatch({ control: form.control, name: "sourceTable" });
|
|
332
|
-
|
|
1302
|
+
useEffect2(() => {
|
|
333
1303
|
if (formId && !entityQuery.data) return;
|
|
334
1304
|
form.reset(builderFormEditorValuesFromEntity(entityQuery.data ?? null, deps.emptyValues));
|
|
335
1305
|
}, [entityQuery.data, form, formId]);
|
|
@@ -352,12 +1322,12 @@ function createBuilderFormEditorPageComponent(deps) {
|
|
|
352
1322
|
}
|
|
353
1323
|
});
|
|
354
1324
|
if (formId && entityQuery.isPending) {
|
|
355
|
-
return /* @__PURE__ */
|
|
1325
|
+
return /* @__PURE__ */ jsx4("div", { className: "text-muted-foreground text-sm", children: deps.states.loading });
|
|
356
1326
|
}
|
|
357
1327
|
if (formId && entityQuery.isError) {
|
|
358
|
-
return /* @__PURE__ */
|
|
1328
|
+
return /* @__PURE__ */ jsx4("div", { className: "text-destructive text-sm", children: deps.states.error });
|
|
359
1329
|
}
|
|
360
|
-
return /* @__PURE__ */
|
|
1330
|
+
return /* @__PURE__ */ jsx4(FormProvider, { ...form, children: /* @__PURE__ */ jsx4("form", { onSubmit, noValidate: true, className: "space-y-6", children: /* @__PURE__ */ jsx4(
|
|
361
1331
|
Body,
|
|
362
1332
|
{
|
|
363
1333
|
formId,
|
|
@@ -384,7 +1354,7 @@ function createBuilderListEditorPageComponent(deps) {
|
|
|
384
1354
|
const entityQuery = deps.hooks.useEntity(listId);
|
|
385
1355
|
const tables = deps.hooks.useTables();
|
|
386
1356
|
const save = deps.hooks.useSave();
|
|
387
|
-
const form =
|
|
1357
|
+
const form = useForm2({
|
|
388
1358
|
resolver: deps.resolver,
|
|
389
1359
|
defaultValues: deps.emptyValues
|
|
390
1360
|
});
|
|
@@ -392,7 +1362,7 @@ function createBuilderListEditorPageComponent(deps) {
|
|
|
392
1362
|
const triggerArray = useFieldArray({ control: form.control, name: "triggers" });
|
|
393
1363
|
const sourceType = useWatch({ control: form.control, name: "sourceType" });
|
|
394
1364
|
const sourceTable = useWatch({ control: form.control, name: "sourceTable" });
|
|
395
|
-
|
|
1365
|
+
useEffect2(() => {
|
|
396
1366
|
if (listId && !entityQuery.data) return;
|
|
397
1367
|
form.reset(builderListEditorValuesFromEntity(entityQuery.data ?? null, deps.emptyValues));
|
|
398
1368
|
}, [entityQuery.data, form, listId]);
|
|
@@ -411,12 +1381,12 @@ function createBuilderListEditorPageComponent(deps) {
|
|
|
411
1381
|
}
|
|
412
1382
|
});
|
|
413
1383
|
if (listId && entityQuery.isPending) {
|
|
414
|
-
return /* @__PURE__ */
|
|
1384
|
+
return /* @__PURE__ */ jsx4("div", { className: "text-muted-foreground text-sm", children: deps.states.loading });
|
|
415
1385
|
}
|
|
416
1386
|
if (listId && entityQuery.isError) {
|
|
417
|
-
return /* @__PURE__ */
|
|
1387
|
+
return /* @__PURE__ */ jsx4("div", { className: "text-destructive text-sm", children: deps.states.error });
|
|
418
1388
|
}
|
|
419
|
-
return /* @__PURE__ */
|
|
1389
|
+
return /* @__PURE__ */ jsx4(FormProvider, { ...form, children: /* @__PURE__ */ jsx4("form", { onSubmit, noValidate: true, className: "space-y-6", children: /* @__PURE__ */ jsx4(
|
|
420
1390
|
Body,
|
|
421
1391
|
{
|
|
422
1392
|
listId,
|
|
@@ -435,17 +1405,405 @@ function createBuilderListEditorPageComponent(deps) {
|
|
|
435
1405
|
};
|
|
436
1406
|
}
|
|
437
1407
|
|
|
1408
|
+
// src/admin/BuilderAdminPages.tsx
|
|
1409
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1410
|
+
var defaultFieldTypeOptions = [
|
|
1411
|
+
{ value: "text", label: "Text" },
|
|
1412
|
+
{ value: "textarea", label: "Textarea" },
|
|
1413
|
+
{ value: "number", label: "Number" },
|
|
1414
|
+
{ value: "money", label: "Money" },
|
|
1415
|
+
{ value: "select", label: "Select" },
|
|
1416
|
+
{ value: "checkbox", label: "Checkbox" },
|
|
1417
|
+
{ value: "date", label: "Date" }
|
|
1418
|
+
];
|
|
1419
|
+
var defaultFormTriggerEventOptions = [
|
|
1420
|
+
{ value: "beforeCreate", label: "Before create" },
|
|
1421
|
+
{ value: "afterCreate", label: "After create" },
|
|
1422
|
+
{ value: "beforeUpdate", label: "Before update" },
|
|
1423
|
+
{ value: "afterUpdate", label: "After update" }
|
|
1424
|
+
];
|
|
1425
|
+
var defaultListTriggerEventOptions = [
|
|
1426
|
+
{ value: "beforeRead", label: "Before read" },
|
|
1427
|
+
{ value: "afterRead", label: "After read" },
|
|
1428
|
+
{ value: "beforeDelete", label: "Before delete" },
|
|
1429
|
+
{ value: "afterDelete", label: "After delete" }
|
|
1430
|
+
];
|
|
1431
|
+
var defaultFieldTriggerEventOptions = [
|
|
1432
|
+
{ value: "onChange", label: "On change" },
|
|
1433
|
+
{ value: "onBlur", label: "On blur" }
|
|
1434
|
+
];
|
|
1435
|
+
var defaultPermissionOptions = [];
|
|
1436
|
+
function parseJsonArray(value) {
|
|
1437
|
+
const parsed = JSON.parse(value);
|
|
1438
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
1439
|
+
}
|
|
1440
|
+
function joinPath(base, path) {
|
|
1441
|
+
return `${base.replace(/\/$/, "")}/${path.replace(/^\//, "")}`;
|
|
1442
|
+
}
|
|
1443
|
+
function defaultQuery(state) {
|
|
1444
|
+
return {
|
|
1445
|
+
page: state.page,
|
|
1446
|
+
pageSize: state.pageSize,
|
|
1447
|
+
search: state.search || void 0
|
|
1448
|
+
};
|
|
1449
|
+
}
|
|
1450
|
+
function detail(entity) {
|
|
1451
|
+
return entity.key ?? entity.id;
|
|
1452
|
+
}
|
|
1453
|
+
var homeStyles = {
|
|
1454
|
+
page: {
|
|
1455
|
+
display: "grid",
|
|
1456
|
+
gap: "1rem"
|
|
1457
|
+
},
|
|
1458
|
+
headerTitle: {
|
|
1459
|
+
margin: 0,
|
|
1460
|
+
fontSize: "1.5rem",
|
|
1461
|
+
fontWeight: 650
|
|
1462
|
+
},
|
|
1463
|
+
description: {
|
|
1464
|
+
margin: "0.25rem 0 0",
|
|
1465
|
+
color: "var(--muted-foreground, #64748b)"
|
|
1466
|
+
},
|
|
1467
|
+
grid: {
|
|
1468
|
+
display: "grid",
|
|
1469
|
+
gridTemplateColumns: "repeat(auto-fit, minmax(13rem, 1fr))",
|
|
1470
|
+
gap: "0.75rem"
|
|
1471
|
+
},
|
|
1472
|
+
card: {
|
|
1473
|
+
border: "1px solid var(--border, #d4d4d8)",
|
|
1474
|
+
borderRadius: "0.5rem",
|
|
1475
|
+
padding: "1rem",
|
|
1476
|
+
background: "var(--background, #fff)",
|
|
1477
|
+
color: "inherit",
|
|
1478
|
+
textDecoration: "none"
|
|
1479
|
+
},
|
|
1480
|
+
cardTitle: {
|
|
1481
|
+
margin: 0,
|
|
1482
|
+
fontSize: "1rem",
|
|
1483
|
+
fontWeight: 650
|
|
1484
|
+
}
|
|
1485
|
+
};
|
|
1486
|
+
function createBuilderAdminPages({
|
|
1487
|
+
hooks,
|
|
1488
|
+
routes = {},
|
|
1489
|
+
fieldTypeOptions = defaultFieldTypeOptions,
|
|
1490
|
+
formTriggerEventOptions = defaultFormTriggerEventOptions,
|
|
1491
|
+
listTriggerEventOptions = defaultListTriggerEventOptions,
|
|
1492
|
+
fieldTriggerEventOptions = defaultFieldTriggerEventOptions,
|
|
1493
|
+
permissionOptions = defaultPermissionOptions,
|
|
1494
|
+
defaultPermission = "",
|
|
1495
|
+
notifySuccess,
|
|
1496
|
+
notifyError,
|
|
1497
|
+
parseViewTriggers = parseJsonArray
|
|
1498
|
+
}) {
|
|
1499
|
+
const adminBasePath = routes.adminBasePath ?? "/admin/dev/builder";
|
|
1500
|
+
const runtimeBasePath = routes.runtimeBasePath ?? "/admin/winu";
|
|
1501
|
+
const formsPath = routes.formsPath ?? joinPath(adminBasePath, "forms");
|
|
1502
|
+
const newFormPath = routes.newFormPath ?? joinPath(formsPath, "new");
|
|
1503
|
+
const editFormPath = routes.editFormPath ?? ((id) => `${joinPath(formsPath, "edit")}?id=${encodeURIComponent(id)}`);
|
|
1504
|
+
const runtimeFormPath = routes.runtimeFormPath ?? ((id) => `${joinPath(runtimeBasePath, "form")}?id=${encodeURIComponent(id)}`);
|
|
1505
|
+
const listsPath = routes.listsPath ?? joinPath(adminBasePath, "lists");
|
|
1506
|
+
const newListPath = routes.newListPath ?? joinPath(listsPath, "new");
|
|
1507
|
+
const editListPath = routes.editListPath ?? ((id) => `${joinPath(listsPath, "edit")}?id=${encodeURIComponent(id)}`);
|
|
1508
|
+
const runtimeListPath = routes.runtimeListPath ?? ((id) => `${joinPath(runtimeBasePath, "list")}?id=${encodeURIComponent(id)}`);
|
|
1509
|
+
const viewsPath = routes.viewsPath ?? joinPath(adminBasePath, "views");
|
|
1510
|
+
const newViewPath = routes.newViewPath ?? joinPath(viewsPath, "new");
|
|
1511
|
+
const editViewPath = routes.editViewPath ?? ((id) => `${joinPath(viewsPath, "edit")}?id=${encodeURIComponent(id)}`);
|
|
1512
|
+
const runtimeViewPath = routes.runtimeViewPath ?? ((id) => `${joinPath(runtimeBasePath, "view")}?id=${encodeURIComponent(id)}`);
|
|
1513
|
+
const formFieldType = fieldTypeOptions[0]?.value ?? "text";
|
|
1514
|
+
const formTriggerEvent = formTriggerEventOptions[0]?.value ?? "beforeCreate";
|
|
1515
|
+
const listTriggerEvent = listTriggerEventOptions[0]?.value ?? "beforeRead";
|
|
1516
|
+
const emptyField = {
|
|
1517
|
+
key: "name",
|
|
1518
|
+
label: "Name",
|
|
1519
|
+
type: formFieldType,
|
|
1520
|
+
required: true,
|
|
1521
|
+
hidden: false,
|
|
1522
|
+
disabled: false,
|
|
1523
|
+
placeholder: "",
|
|
1524
|
+
optionsText: "",
|
|
1525
|
+
optionsMode: "static",
|
|
1526
|
+
optionsTable: BUILDER_EDITOR_NONE_VALUE,
|
|
1527
|
+
optionsValueField: BUILDER_EDITOR_NONE_VALUE,
|
|
1528
|
+
optionsLabelField: BUILDER_EDITOR_NONE_VALUE,
|
|
1529
|
+
optionsSearchFieldsText: "",
|
|
1530
|
+
optionsDependsOn: "",
|
|
1531
|
+
optionsFilterField: "",
|
|
1532
|
+
triggers: []
|
|
1533
|
+
};
|
|
1534
|
+
const emptyFormValues = {
|
|
1535
|
+
title: "",
|
|
1536
|
+
description: "",
|
|
1537
|
+
sourceType: "none",
|
|
1538
|
+
sourceTable: BUILDER_EDITOR_NONE_VALUE,
|
|
1539
|
+
apiBasePath: "",
|
|
1540
|
+
fields: [emptyField],
|
|
1541
|
+
layoutGroups: builderFormEditorDefaultLayoutGroups([emptyField]),
|
|
1542
|
+
subforms: [],
|
|
1543
|
+
triggers: [],
|
|
1544
|
+
version: 0
|
|
1545
|
+
};
|
|
1546
|
+
const emptyFormTrigger = {
|
|
1547
|
+
event: formTriggerEvent,
|
|
1548
|
+
route: "/api/v1/",
|
|
1549
|
+
enabled: false,
|
|
1550
|
+
blocking: true
|
|
1551
|
+
};
|
|
1552
|
+
const emptyColumn = {
|
|
1553
|
+
key: "name",
|
|
1554
|
+
label: "Name",
|
|
1555
|
+
sortable: true,
|
|
1556
|
+
align: "left"
|
|
1557
|
+
};
|
|
1558
|
+
const emptyListValues = {
|
|
1559
|
+
title: "",
|
|
1560
|
+
description: "",
|
|
1561
|
+
sourceType: "none",
|
|
1562
|
+
sourceTable: BUILDER_EDITOR_NONE_VALUE,
|
|
1563
|
+
apiBasePath: "",
|
|
1564
|
+
columns: [emptyColumn],
|
|
1565
|
+
triggers: [],
|
|
1566
|
+
version: 0
|
|
1567
|
+
};
|
|
1568
|
+
const emptyListTrigger = {
|
|
1569
|
+
event: listTriggerEvent,
|
|
1570
|
+
route: "/api/v1/",
|
|
1571
|
+
enabled: false,
|
|
1572
|
+
blocking: true
|
|
1573
|
+
};
|
|
1574
|
+
const FormEditorPage = createBuilderFormEditorPageComponent({
|
|
1575
|
+
emptyValues: emptyFormValues,
|
|
1576
|
+
emptyField,
|
|
1577
|
+
emptyTrigger: emptyFormTrigger,
|
|
1578
|
+
labels: {
|
|
1579
|
+
created: "Form created",
|
|
1580
|
+
saved: "Form saved"
|
|
1581
|
+
},
|
|
1582
|
+
states: {
|
|
1583
|
+
loading: "Loading...",
|
|
1584
|
+
error: "Failed to load form."
|
|
1585
|
+
},
|
|
1586
|
+
hooks: {
|
|
1587
|
+
useEntity: hooks.useBuilderForm,
|
|
1588
|
+
useTables: hooks.useBuilderDbTables,
|
|
1589
|
+
useSave: hooks.useSaveBuilderForm
|
|
1590
|
+
},
|
|
1591
|
+
buildInput: (values) => builderFormEditorInputFromValues(values),
|
|
1592
|
+
navigateAfterCreate: (entity) => window.location.assign(editFormPath(entity.id)),
|
|
1593
|
+
notifications: {
|
|
1594
|
+
success: (message) => notifySuccess?.(message),
|
|
1595
|
+
error: (error) => {
|
|
1596
|
+
if (notifyError) notifyError(error);
|
|
1597
|
+
else throw error;
|
|
1598
|
+
}
|
|
1599
|
+
},
|
|
1600
|
+
Body: createBuilderDefaultFormEditorBody({
|
|
1601
|
+
backHref: formsPath,
|
|
1602
|
+
fieldTypeOptions,
|
|
1603
|
+
formTriggerEventOptions,
|
|
1604
|
+
fieldTriggerEventOptions
|
|
1605
|
+
})
|
|
1606
|
+
});
|
|
1607
|
+
const ListEditorPage = createBuilderListEditorPageComponent({
|
|
1608
|
+
emptyValues: emptyListValues,
|
|
1609
|
+
emptyColumn,
|
|
1610
|
+
emptyTrigger: emptyListTrigger,
|
|
1611
|
+
labels: {
|
|
1612
|
+
created: "List created",
|
|
1613
|
+
saved: "List saved"
|
|
1614
|
+
},
|
|
1615
|
+
states: {
|
|
1616
|
+
loading: "Loading...",
|
|
1617
|
+
error: "Failed to load list."
|
|
1618
|
+
},
|
|
1619
|
+
hooks: {
|
|
1620
|
+
useEntity: hooks.useBuilderList,
|
|
1621
|
+
useTables: hooks.useBuilderDbTables,
|
|
1622
|
+
useSave: hooks.useSaveBuilderList
|
|
1623
|
+
},
|
|
1624
|
+
buildInput: (values) => builderListEditorInputFromValues(values),
|
|
1625
|
+
navigateAfterCreate: (entity) => window.location.assign(editListPath(entity.id)),
|
|
1626
|
+
notifications: {
|
|
1627
|
+
success: (message) => notifySuccess?.(message),
|
|
1628
|
+
error: (error) => {
|
|
1629
|
+
if (notifyError) notifyError(error);
|
|
1630
|
+
else throw error;
|
|
1631
|
+
}
|
|
1632
|
+
},
|
|
1633
|
+
Body: createBuilderDefaultListEditorBody({
|
|
1634
|
+
backHref: listsPath,
|
|
1635
|
+
listTriggerEventOptions
|
|
1636
|
+
})
|
|
1637
|
+
});
|
|
1638
|
+
const ViewEditorPage = createBuilderDefaultViewEditorPage({
|
|
1639
|
+
hooks,
|
|
1640
|
+
backHref: viewsPath,
|
|
1641
|
+
editHref: editViewPath,
|
|
1642
|
+
permissionOptions,
|
|
1643
|
+
defaultPermission,
|
|
1644
|
+
parseTriggers: parseViewTriggers,
|
|
1645
|
+
notifySuccess,
|
|
1646
|
+
notifyError
|
|
1647
|
+
});
|
|
1648
|
+
const AdminHomePage = function BuilderAdminHomePage() {
|
|
1649
|
+
const items = [
|
|
1650
|
+
{
|
|
1651
|
+
title: "Dynamic Forms",
|
|
1652
|
+
description: "Reusable form schemas.",
|
|
1653
|
+
href: formsPath
|
|
1654
|
+
},
|
|
1655
|
+
{
|
|
1656
|
+
title: "Dynamic Lists",
|
|
1657
|
+
description: "Reusable list and grid schemas.",
|
|
1658
|
+
href: listsPath
|
|
1659
|
+
},
|
|
1660
|
+
{
|
|
1661
|
+
title: "Dynamic Views",
|
|
1662
|
+
description: "Runtime screens composed from form and list schemas.",
|
|
1663
|
+
href: viewsPath
|
|
1664
|
+
}
|
|
1665
|
+
];
|
|
1666
|
+
return /* @__PURE__ */ jsxs4("section", { style: homeStyles.page, children: [
|
|
1667
|
+
/* @__PURE__ */ jsxs4("div", { children: [
|
|
1668
|
+
/* @__PURE__ */ jsx5("h1", { style: homeStyles.headerTitle, children: "Builder" }),
|
|
1669
|
+
/* @__PURE__ */ jsx5("p", { style: homeStyles.description, children: "Manage dynamic forms, lists, and views." })
|
|
1670
|
+
] }),
|
|
1671
|
+
/* @__PURE__ */ jsx5("div", { style: homeStyles.grid, children: items.map((item) => /* @__PURE__ */ jsxs4("a", { href: item.href, style: homeStyles.card, children: [
|
|
1672
|
+
/* @__PURE__ */ jsx5("h2", { style: homeStyles.cardTitle, children: item.title }),
|
|
1673
|
+
/* @__PURE__ */ jsx5("p", { style: homeStyles.description, children: item.description })
|
|
1674
|
+
] }, item.href)) })
|
|
1675
|
+
] });
|
|
1676
|
+
};
|
|
1677
|
+
const AdminFormsPage = createBuilderDefaultEntityManagerComponent({
|
|
1678
|
+
labels: {
|
|
1679
|
+
title: "Dynamic Forms",
|
|
1680
|
+
description: "Reusable form schemas.",
|
|
1681
|
+
searchPlaceholder: "Search forms...",
|
|
1682
|
+
emptyTitle: "No forms",
|
|
1683
|
+
emptyDescription: "Create your first dynamic form.",
|
|
1684
|
+
addLabel: "Add form",
|
|
1685
|
+
editLabel: "Edit",
|
|
1686
|
+
replicateLabel: "Replicate",
|
|
1687
|
+
deleteLabel: "Delete",
|
|
1688
|
+
runtimeLabel: "Open",
|
|
1689
|
+
deleteConfirm: (entity) => `Delete ${entity.title}?`,
|
|
1690
|
+
replicatePrompt: () => "New form title",
|
|
1691
|
+
replicateDefaultTitle: (entity) => `${entity.title} copy`
|
|
1692
|
+
},
|
|
1693
|
+
createHref: newFormPath,
|
|
1694
|
+
editHref: (entity) => editFormPath(entity.id),
|
|
1695
|
+
runtimeHref: (entity) => runtimeFormPath(entity.id),
|
|
1696
|
+
getDetail: detail,
|
|
1697
|
+
buildQuery: (state) => defaultQuery(state),
|
|
1698
|
+
hooks: {
|
|
1699
|
+
useEntities: (query) => hooks.useBuilderForms(query),
|
|
1700
|
+
useDelete: hooks.useDeleteBuilderForm,
|
|
1701
|
+
useReplicate: hooks.useReplicateBuilderForm
|
|
1702
|
+
}
|
|
1703
|
+
});
|
|
1704
|
+
const AdminListsPage = createBuilderDefaultEntityManagerComponent({
|
|
1705
|
+
labels: {
|
|
1706
|
+
title: "Dynamic Lists",
|
|
1707
|
+
description: "Reusable list and grid schemas.",
|
|
1708
|
+
searchPlaceholder: "Search lists...",
|
|
1709
|
+
emptyTitle: "No lists",
|
|
1710
|
+
emptyDescription: "Create your first dynamic list.",
|
|
1711
|
+
addLabel: "Add list",
|
|
1712
|
+
editLabel: "Edit",
|
|
1713
|
+
replicateLabel: "Replicate",
|
|
1714
|
+
deleteLabel: "Delete",
|
|
1715
|
+
runtimeLabel: "Open",
|
|
1716
|
+
deleteConfirm: (entity) => `Delete ${entity.title}?`,
|
|
1717
|
+
replicatePrompt: () => "New list title",
|
|
1718
|
+
replicateDefaultTitle: (entity) => `${entity.title} copy`
|
|
1719
|
+
},
|
|
1720
|
+
createHref: newListPath,
|
|
1721
|
+
editHref: (entity) => editListPath(entity.id),
|
|
1722
|
+
runtimeHref: (entity) => runtimeListPath(entity.id),
|
|
1723
|
+
getDetail: detail,
|
|
1724
|
+
buildQuery: (state) => defaultQuery(state),
|
|
1725
|
+
hooks: {
|
|
1726
|
+
useEntities: (query) => hooks.useBuilderLists(query),
|
|
1727
|
+
useDelete: hooks.useDeleteBuilderList,
|
|
1728
|
+
useReplicate: hooks.useReplicateBuilderList
|
|
1729
|
+
}
|
|
1730
|
+
});
|
|
1731
|
+
const AdminViewsPage = createBuilderDefaultEntityManagerComponent({
|
|
1732
|
+
labels: {
|
|
1733
|
+
title: "Dynamic Views",
|
|
1734
|
+
description: "Runtime screens composed from form and list schemas.",
|
|
1735
|
+
searchPlaceholder: "Search views...",
|
|
1736
|
+
emptyTitle: "No views",
|
|
1737
|
+
emptyDescription: "Create a dynamic view after preparing a form and list.",
|
|
1738
|
+
addLabel: "Add view",
|
|
1739
|
+
editLabel: "Edit",
|
|
1740
|
+
replicateLabel: "Replicate",
|
|
1741
|
+
deleteLabel: "Delete",
|
|
1742
|
+
runtimeLabel: "Open",
|
|
1743
|
+
deleteConfirm: (entity) => `Delete ${entity.title}?`,
|
|
1744
|
+
replicatePrompt: () => "New view title",
|
|
1745
|
+
replicateDefaultTitle: (entity) => `${entity.title} copy`
|
|
1746
|
+
},
|
|
1747
|
+
createHref: newViewPath,
|
|
1748
|
+
editHref: (entity) => editViewPath(entity.id),
|
|
1749
|
+
runtimeHref: (entity) => runtimeViewPath(entity.id),
|
|
1750
|
+
getDetail: detail,
|
|
1751
|
+
buildQuery: (state) => defaultQuery(state),
|
|
1752
|
+
hooks: {
|
|
1753
|
+
useEntities: (query) => hooks.useBuilderViews(query),
|
|
1754
|
+
useDelete: hooks.useDeleteBuilderView,
|
|
1755
|
+
useReplicate: hooks.useReplicateBuilderView
|
|
1756
|
+
}
|
|
1757
|
+
});
|
|
1758
|
+
return {
|
|
1759
|
+
AdminHomePage,
|
|
1760
|
+
AdminFormsPage,
|
|
1761
|
+
AdminNewFormPage: function BuilderAdminNewFormPage() {
|
|
1762
|
+
return /* @__PURE__ */ jsx5(FormEditorPage, {});
|
|
1763
|
+
},
|
|
1764
|
+
AdminEditFormPage: function BuilderAdminEditFormPage({ formId }) {
|
|
1765
|
+
return /* @__PURE__ */ jsx5(FormEditorPage, { formId });
|
|
1766
|
+
},
|
|
1767
|
+
AdminListsPage,
|
|
1768
|
+
AdminNewListPage: function BuilderAdminNewListPage() {
|
|
1769
|
+
return /* @__PURE__ */ jsx5(ListEditorPage, {});
|
|
1770
|
+
},
|
|
1771
|
+
AdminEditListPage: function BuilderAdminEditListPage({ listId }) {
|
|
1772
|
+
return /* @__PURE__ */ jsx5(ListEditorPage, { listId });
|
|
1773
|
+
},
|
|
1774
|
+
AdminViewsPage,
|
|
1775
|
+
AdminNewViewPage: function BuilderAdminNewViewPage() {
|
|
1776
|
+
return /* @__PURE__ */ jsx5(ViewEditorPage, {});
|
|
1777
|
+
},
|
|
1778
|
+
AdminEditViewPage: function BuilderAdminEditViewPage({ viewId }) {
|
|
1779
|
+
return /* @__PURE__ */ jsx5(ViewEditorPage, { viewId });
|
|
1780
|
+
},
|
|
1781
|
+
routes: {
|
|
1782
|
+
adminBasePath,
|
|
1783
|
+
formsPath,
|
|
1784
|
+
newFormPath,
|
|
1785
|
+
editFormPath,
|
|
1786
|
+
listsPath,
|
|
1787
|
+
newListPath,
|
|
1788
|
+
editListPath,
|
|
1789
|
+
viewsPath,
|
|
1790
|
+
newViewPath,
|
|
1791
|
+
editViewPath
|
|
1792
|
+
}
|
|
1793
|
+
};
|
|
1794
|
+
}
|
|
1795
|
+
|
|
438
1796
|
// src/admin/BuilderEntityManager.tsx
|
|
439
|
-
import { useCallback, useMemo, useState } from "react";
|
|
440
|
-
import { jsx as
|
|
1797
|
+
import { useCallback, useMemo as useMemo2, useState as useState2 } from "react";
|
|
1798
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
441
1799
|
function createBuilderEntityManagerComponent(deps) {
|
|
442
1800
|
return function BuilderEntityManager() {
|
|
443
|
-
const [pendingDelete, setPendingDelete] =
|
|
1801
|
+
const [pendingDelete, setPendingDelete] = useState2(null);
|
|
444
1802
|
const state = deps.useDataTableState({ pageSize: 20 });
|
|
445
1803
|
const query = deps.hooks.useEntities(state.query);
|
|
446
1804
|
const remove = deps.hooks.useDelete();
|
|
447
1805
|
const replicate = deps.hooks.useReplicate();
|
|
448
|
-
const columns =
|
|
1806
|
+
const columns = useMemo2(
|
|
449
1807
|
() => deps.buildColumns({
|
|
450
1808
|
onEdit: deps.navigateToEdit,
|
|
451
1809
|
onReplicate: async (entity) => {
|
|
@@ -465,8 +1823,8 @@ function createBuilderEntityManagerComponent(deps) {
|
|
|
465
1823
|
state,
|
|
466
1824
|
getRowId: (row) => row.id
|
|
467
1825
|
});
|
|
468
|
-
return /* @__PURE__ */
|
|
469
|
-
/* @__PURE__ */
|
|
1826
|
+
return /* @__PURE__ */ jsxs5("div", { className: "space-y-6", children: [
|
|
1827
|
+
/* @__PURE__ */ jsx6(
|
|
470
1828
|
deps.DataGrid,
|
|
471
1829
|
{
|
|
472
1830
|
title: deps.labels.title,
|
|
@@ -477,10 +1835,10 @@ function createBuilderEntityManagerComponent(deps) {
|
|
|
477
1835
|
emptyTitle: deps.labels.emptyTitle,
|
|
478
1836
|
emptyDescription: deps.labels.emptyDescription,
|
|
479
1837
|
onRowClick: deps.navigateToEdit,
|
|
480
|
-
toolbarExtra: /* @__PURE__ */
|
|
1838
|
+
toolbarExtra: /* @__PURE__ */ jsx6(deps.AddButton, { href: deps.createHref, label: deps.labels.addLabel })
|
|
481
1839
|
}
|
|
482
1840
|
),
|
|
483
|
-
/* @__PURE__ */
|
|
1841
|
+
/* @__PURE__ */ jsx6(
|
|
484
1842
|
deps.DeleteDialog,
|
|
485
1843
|
{
|
|
486
1844
|
entity: pendingDelete,
|
|
@@ -500,9 +1858,9 @@ function createBuilderEntityManagerComponent(deps) {
|
|
|
500
1858
|
}
|
|
501
1859
|
function createBuilderEntityDialogManagerComponent(deps) {
|
|
502
1860
|
return function BuilderEntityDialogManager() {
|
|
503
|
-
const [editing, setEditing] =
|
|
504
|
-
const [isEditorOpen, setEditorOpen] =
|
|
505
|
-
const [pendingDelete, setPendingDelete] =
|
|
1861
|
+
const [editing, setEditing] = useState2(null);
|
|
1862
|
+
const [isEditorOpen, setEditorOpen] = useState2(false);
|
|
1863
|
+
const [pendingDelete, setPendingDelete] = useState2(null);
|
|
506
1864
|
const state = deps.useDataTableState({ pageSize: 20 });
|
|
507
1865
|
const query = deps.hooks.useEntities(state.query);
|
|
508
1866
|
const remove = deps.hooks.useDelete();
|
|
@@ -511,7 +1869,7 @@ function createBuilderEntityDialogManagerComponent(deps) {
|
|
|
511
1869
|
setEditing(entity);
|
|
512
1870
|
setEditorOpen(true);
|
|
513
1871
|
}, []);
|
|
514
|
-
const columns =
|
|
1872
|
+
const columns = useMemo2(
|
|
515
1873
|
() => deps.buildColumns({
|
|
516
1874
|
onEdit: (entity) => openEditor(entity),
|
|
517
1875
|
onReplicate: async (entity) => {
|
|
@@ -531,8 +1889,8 @@ function createBuilderEntityDialogManagerComponent(deps) {
|
|
|
531
1889
|
state,
|
|
532
1890
|
getRowId: (row) => row.id
|
|
533
1891
|
});
|
|
534
|
-
return /* @__PURE__ */
|
|
535
|
-
/* @__PURE__ */
|
|
1892
|
+
return /* @__PURE__ */ jsxs5("div", { className: "space-y-6", children: [
|
|
1893
|
+
/* @__PURE__ */ jsx6(
|
|
536
1894
|
deps.DataGrid,
|
|
537
1895
|
{
|
|
538
1896
|
title: deps.labels.title,
|
|
@@ -543,10 +1901,10 @@ function createBuilderEntityDialogManagerComponent(deps) {
|
|
|
543
1901
|
emptyTitle: deps.labels.emptyTitle,
|
|
544
1902
|
emptyDescription: deps.labels.emptyDescription,
|
|
545
1903
|
onRowClick: openEditor,
|
|
546
|
-
toolbarExtra: /* @__PURE__ */
|
|
1904
|
+
toolbarExtra: /* @__PURE__ */ jsx6(deps.AddButton, { label: deps.labels.addLabel, onAdd: () => openEditor(null) })
|
|
547
1905
|
}
|
|
548
1906
|
),
|
|
549
|
-
/* @__PURE__ */
|
|
1907
|
+
/* @__PURE__ */ jsx6(
|
|
550
1908
|
deps.EditorDialog,
|
|
551
1909
|
{
|
|
552
1910
|
open: isEditorOpen,
|
|
@@ -554,7 +1912,7 @@ function createBuilderEntityDialogManagerComponent(deps) {
|
|
|
554
1912
|
onClose: () => setEditorOpen(false)
|
|
555
1913
|
}
|
|
556
1914
|
),
|
|
557
|
-
/* @__PURE__ */
|
|
1915
|
+
/* @__PURE__ */ jsx6(
|
|
558
1916
|
deps.DeleteDialog,
|
|
559
1917
|
{
|
|
560
1918
|
entity: pendingDelete,
|
|
@@ -574,9 +1932,9 @@ function createBuilderEntityDialogManagerComponent(deps) {
|
|
|
574
1932
|
}
|
|
575
1933
|
|
|
576
1934
|
// src/admin/BuilderViewDialog.tsx
|
|
577
|
-
import { useEffect as
|
|
578
|
-
import { FormProvider as FormProvider2, useForm as
|
|
579
|
-
import { jsx as
|
|
1935
|
+
import { useEffect as useEffect3 } from "react";
|
|
1936
|
+
import { FormProvider as FormProvider2, useForm as useForm3 } from "react-hook-form";
|
|
1937
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
580
1938
|
function createBuilderViewDialogComponent(deps) {
|
|
581
1939
|
return function BuilderViewDialog({
|
|
582
1940
|
open,
|
|
@@ -587,11 +1945,11 @@ function createBuilderViewDialogComponent(deps) {
|
|
|
587
1945
|
onSave,
|
|
588
1946
|
isSaving
|
|
589
1947
|
}) {
|
|
590
|
-
const form =
|
|
1948
|
+
const form = useForm3({
|
|
591
1949
|
resolver: deps.resolver,
|
|
592
1950
|
defaultValues: deps.emptyValues
|
|
593
1951
|
});
|
|
594
|
-
|
|
1952
|
+
useEffect3(() => {
|
|
595
1953
|
if (!open) return;
|
|
596
1954
|
form.reset(
|
|
597
1955
|
builderViewEditorValuesFromEntity(editing, deps.emptyValues, deps.defaultPermission)
|
|
@@ -606,7 +1964,7 @@ function createBuilderViewDialogComponent(deps) {
|
|
|
606
1964
|
deps.notifications.error(error);
|
|
607
1965
|
}
|
|
608
1966
|
});
|
|
609
|
-
return /* @__PURE__ */
|
|
1967
|
+
return /* @__PURE__ */ jsx7(deps.Shell, { open, editing, onClose, children: /* @__PURE__ */ jsx7(FormProvider2, { ...form, children: /* @__PURE__ */ jsx7("form", { onSubmit, noValidate: true, children: deps.Body({
|
|
610
1968
|
form,
|
|
611
1969
|
editing,
|
|
612
1970
|
forms,
|
|
@@ -619,6 +1977,175 @@ function createBuilderViewDialogComponent(deps) {
|
|
|
619
1977
|
};
|
|
620
1978
|
}
|
|
621
1979
|
|
|
1980
|
+
// src/admin/formLayoutEditorState.ts
|
|
1981
|
+
import { useMemo as useMemo3 } from "react";
|
|
1982
|
+
import { useWatch as useWatch2 } from "react-hook-form";
|
|
1983
|
+
var builderFormLayoutDragDataType = "application/x-winu-builder-layout-field";
|
|
1984
|
+
function clampBuilderFormLayoutSpan(span, columns) {
|
|
1985
|
+
return Math.max(1, Math.min(columns, span));
|
|
1986
|
+
}
|
|
1987
|
+
function swapBuilderFormLayoutItems(items, from, to) {
|
|
1988
|
+
if (from < 0 || from >= items.length || to < 0 || to >= items.length) return items;
|
|
1989
|
+
const next = [...items];
|
|
1990
|
+
const item = next[from];
|
|
1991
|
+
next[from] = next[to];
|
|
1992
|
+
next[to] = item;
|
|
1993
|
+
return next;
|
|
1994
|
+
}
|
|
1995
|
+
function nextBuilderFormLayoutGroupId(groups) {
|
|
1996
|
+
let index = groups.length + 1;
|
|
1997
|
+
let id = `group${index}`;
|
|
1998
|
+
const ids = new Set(groups.map((group) => group.id));
|
|
1999
|
+
while (ids.has(id)) {
|
|
2000
|
+
index += 1;
|
|
2001
|
+
id = `group${index}`;
|
|
2002
|
+
}
|
|
2003
|
+
return id;
|
|
2004
|
+
}
|
|
2005
|
+
function serializeBuilderFormLayoutDragPayload(payload) {
|
|
2006
|
+
return JSON.stringify(payload);
|
|
2007
|
+
}
|
|
2008
|
+
function parseBuilderFormLayoutDragPayload(raw) {
|
|
2009
|
+
if (!raw) return null;
|
|
2010
|
+
try {
|
|
2011
|
+
const value = JSON.parse(raw);
|
|
2012
|
+
if (value.type === "palette" && typeof value.key === "string" && value.key) {
|
|
2013
|
+
return { type: value.type, key: value.key };
|
|
2014
|
+
}
|
|
2015
|
+
if (value.type === "layout" && typeof value.key === "string" && value.key && Number.isInteger(value.groupIndex) && Number.isInteger(value.fieldIndex) && (value.groupIndex ?? -1) >= 0 && (value.fieldIndex ?? -1) >= 0) {
|
|
2016
|
+
return {
|
|
2017
|
+
type: value.type,
|
|
2018
|
+
groupIndex: value.groupIndex,
|
|
2019
|
+
fieldIndex: value.fieldIndex,
|
|
2020
|
+
key: value.key
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
2023
|
+
return null;
|
|
2024
|
+
} catch {
|
|
2025
|
+
return null;
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
function useBuilderFormLayoutEditor({ form, fields, subforms = [] }) {
|
|
2029
|
+
const layoutGroups = useWatch2({ control: form.control, name: "layoutGroups" }) ?? [];
|
|
2030
|
+
const layoutItems = useMemo3(
|
|
2031
|
+
() => [
|
|
2032
|
+
...fields.map((field) => ({
|
|
2033
|
+
key: field.key,
|
|
2034
|
+
kind: "field",
|
|
2035
|
+
meta: field.type,
|
|
2036
|
+
span: builderFormEditorDefaultSpan(field)
|
|
2037
|
+
})),
|
|
2038
|
+
...subforms.map((subform) => ({
|
|
2039
|
+
key: subform.key,
|
|
2040
|
+
kind: "subform",
|
|
2041
|
+
meta: "subform",
|
|
2042
|
+
span: 12
|
|
2043
|
+
}))
|
|
2044
|
+
],
|
|
2045
|
+
[fields, subforms]
|
|
2046
|
+
);
|
|
2047
|
+
const assignedKeys = useMemo3(
|
|
2048
|
+
() => new Set(layoutGroups.flatMap((group) => group.fields.map((field) => field.key))),
|
|
2049
|
+
[layoutGroups]
|
|
2050
|
+
);
|
|
2051
|
+
const unassignedItems = useMemo3(
|
|
2052
|
+
() => layoutItems.filter((item) => !assignedKeys.has(item.key)),
|
|
2053
|
+
[assignedKeys, layoutItems]
|
|
2054
|
+
);
|
|
2055
|
+
const setGroups = (groups) => {
|
|
2056
|
+
form.setValue("layoutGroups", groups, { shouldDirty: true, shouldValidate: true });
|
|
2057
|
+
};
|
|
2058
|
+
const updateGroup = (groupIndex, group) => {
|
|
2059
|
+
setGroups(layoutGroups.map((item, index) => index === groupIndex ? group : item));
|
|
2060
|
+
};
|
|
2061
|
+
const updateGroupFields = (groupIndex, updater) => {
|
|
2062
|
+
const group = layoutGroups[groupIndex];
|
|
2063
|
+
if (!group) return;
|
|
2064
|
+
updateGroup(groupIndex, { ...group, fields: updater(group.fields) });
|
|
2065
|
+
};
|
|
2066
|
+
const addGroup = () => {
|
|
2067
|
+
setGroups([
|
|
2068
|
+
...layoutGroups,
|
|
2069
|
+
{
|
|
2070
|
+
id: nextBuilderFormLayoutGroupId(layoutGroups),
|
|
2071
|
+
title: `Group ${layoutGroups.length + 1}`,
|
|
2072
|
+
columns: 12,
|
|
2073
|
+
fields: []
|
|
2074
|
+
}
|
|
2075
|
+
]);
|
|
2076
|
+
};
|
|
2077
|
+
const addItemToNewGroup = (itemKey) => {
|
|
2078
|
+
if (assignedKeys.has(itemKey)) return;
|
|
2079
|
+
const item = layoutItems.find((candidate) => candidate.key === itemKey);
|
|
2080
|
+
if (!item) return;
|
|
2081
|
+
setGroups([
|
|
2082
|
+
...layoutGroups,
|
|
2083
|
+
{
|
|
2084
|
+
id: nextBuilderFormLayoutGroupId(layoutGroups),
|
|
2085
|
+
title: layoutGroups.length === 0 ? "\u04AE\u043D\u0434\u0441\u044D\u043D" : `Group ${layoutGroups.length + 1}`,
|
|
2086
|
+
columns: 12,
|
|
2087
|
+
fields: [{ key: itemKey, span: item.span }]
|
|
2088
|
+
}
|
|
2089
|
+
]);
|
|
2090
|
+
};
|
|
2091
|
+
const addItemToGroup = (groupIndex, itemKey, insertAt) => {
|
|
2092
|
+
if (assignedKeys.has(itemKey)) return;
|
|
2093
|
+
const item = layoutItems.find((candidate) => candidate.key === itemKey);
|
|
2094
|
+
const group = layoutGroups[groupIndex];
|
|
2095
|
+
if (!item || !group) return;
|
|
2096
|
+
const nextField = {
|
|
2097
|
+
key: itemKey,
|
|
2098
|
+
span: clampBuilderFormLayoutSpan(item.span, group.columns)
|
|
2099
|
+
};
|
|
2100
|
+
updateGroupFields(groupIndex, (groupFields) => {
|
|
2101
|
+
const next = [...groupFields];
|
|
2102
|
+
next.splice(insertAt ?? next.length, 0, nextField);
|
|
2103
|
+
return next;
|
|
2104
|
+
});
|
|
2105
|
+
};
|
|
2106
|
+
const moveLayoutField = (payload, targetGroupIndex, targetFieldIndex) => {
|
|
2107
|
+
const sourceGroup = layoutGroups[payload.groupIndex];
|
|
2108
|
+
const targetGroup = layoutGroups[targetGroupIndex];
|
|
2109
|
+
if (!sourceGroup || !targetGroup) return;
|
|
2110
|
+
const movingField = sourceGroup.fields[payload.fieldIndex];
|
|
2111
|
+
if (!movingField) return;
|
|
2112
|
+
const nextGroups = layoutGroups.map((group) => ({ ...group, fields: [...group.fields] }));
|
|
2113
|
+
nextGroups[payload.groupIndex].fields.splice(payload.fieldIndex, 1);
|
|
2114
|
+
let insertAt = targetFieldIndex ?? nextGroups[targetGroupIndex].fields.length;
|
|
2115
|
+
if (payload.groupIndex === targetGroupIndex && payload.fieldIndex < insertAt) {
|
|
2116
|
+
insertAt -= 1;
|
|
2117
|
+
}
|
|
2118
|
+
nextGroups[targetGroupIndex].fields.splice(insertAt, 0, {
|
|
2119
|
+
...movingField,
|
|
2120
|
+
span: clampBuilderFormLayoutSpan(movingField.span, targetGroup.columns)
|
|
2121
|
+
});
|
|
2122
|
+
setGroups(nextGroups);
|
|
2123
|
+
};
|
|
2124
|
+
const applyDragPayload = (payload, targetGroupIndex, targetFieldIndex) => {
|
|
2125
|
+
if (!payload) return;
|
|
2126
|
+
if (payload.type === "palette") {
|
|
2127
|
+
addItemToGroup(targetGroupIndex, payload.key, targetFieldIndex);
|
|
2128
|
+
return;
|
|
2129
|
+
}
|
|
2130
|
+
moveLayoutField(payload, targetGroupIndex, targetFieldIndex);
|
|
2131
|
+
};
|
|
2132
|
+
const resetDefaultLayout = () => setGroups(builderFormEditorDefaultLayoutGroups(fields, subforms));
|
|
2133
|
+
return {
|
|
2134
|
+
assignedKeys,
|
|
2135
|
+
layoutGroups,
|
|
2136
|
+
layoutItems,
|
|
2137
|
+
unassignedItems,
|
|
2138
|
+
addGroup,
|
|
2139
|
+
addItemToGroup,
|
|
2140
|
+
addItemToNewGroup,
|
|
2141
|
+
applyDragPayload,
|
|
2142
|
+
resetDefaultLayout,
|
|
2143
|
+
setGroups,
|
|
2144
|
+
updateGroup,
|
|
2145
|
+
updateGroupFields
|
|
2146
|
+
};
|
|
2147
|
+
}
|
|
2148
|
+
|
|
622
2149
|
// src/api/createBuilderApiClient.ts
|
|
623
2150
|
function queryParams(query) {
|
|
624
2151
|
return { ...query };
|
|
@@ -709,8 +2236,8 @@ function createBuilderApiClient(transport) {
|
|
|
709
2236
|
}
|
|
710
2237
|
|
|
711
2238
|
// src/components/DynamicForm.tsx
|
|
712
|
-
import { useMemo as
|
|
713
|
-
import { FormProvider as FormProvider3, useForm as
|
|
2239
|
+
import { useMemo as useMemo4 } from "react";
|
|
2240
|
+
import { FormProvider as FormProvider3, useForm as useForm4 } from "react-hook-form";
|
|
714
2241
|
|
|
715
2242
|
// src/runtime/runtimeUtils.ts
|
|
716
2243
|
function emptyFieldValue(field) {
|
|
@@ -739,16 +2266,16 @@ function formatBuilderRuntimeValue(value, locale = "mn-MN") {
|
|
|
739
2266
|
}
|
|
740
2267
|
|
|
741
2268
|
// src/components/DynamicForm.tsx
|
|
742
|
-
import { jsx as
|
|
2269
|
+
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
743
2270
|
function createDynamicFormComponent(deps) {
|
|
744
2271
|
return function DynamicForm({ formId }) {
|
|
745
2272
|
const query = deps.hooks.useRuntimeBuilderForm(formId);
|
|
746
2273
|
const save = deps.hooks.useSaveRuntimeBuilderFormEntry(formId);
|
|
747
|
-
const formValues =
|
|
2274
|
+
const formValues = useMemo4(
|
|
748
2275
|
() => query.data ? createBuilderFormDefaultValues(query.data.schema) : void 0,
|
|
749
2276
|
[query.data]
|
|
750
2277
|
);
|
|
751
|
-
const form =
|
|
2278
|
+
const form = useForm4({
|
|
752
2279
|
defaultValues: createBuilderFormDefaultValues(query.data?.schema),
|
|
753
2280
|
values: formValues
|
|
754
2281
|
});
|
|
@@ -762,7 +2289,7 @@ function createDynamicFormComponent(deps) {
|
|
|
762
2289
|
}
|
|
763
2290
|
});
|
|
764
2291
|
if (query.isError) {
|
|
765
|
-
return /* @__PURE__ */
|
|
2292
|
+
return /* @__PURE__ */ jsx8(
|
|
766
2293
|
deps.ErrorState,
|
|
767
2294
|
{
|
|
768
2295
|
title: "Form \u043D\u044D\u044D\u0433\u0434\u0441\u044D\u043D\u0433\u04AF\u0439",
|
|
@@ -771,22 +2298,22 @@ function createDynamicFormComponent(deps) {
|
|
|
771
2298
|
);
|
|
772
2299
|
}
|
|
773
2300
|
if (!query.data) return null;
|
|
774
|
-
return /* @__PURE__ */
|
|
775
|
-
/* @__PURE__ */
|
|
776
|
-
/* @__PURE__ */
|
|
2301
|
+
return /* @__PURE__ */ jsx8(deps.FormShell, { title: query.data.title, children: /* @__PURE__ */ jsx8(FormProvider3, { ...form, children: /* @__PURE__ */ jsxs6("form", { onSubmit, noValidate: true, className: "space-y-6", children: [
|
|
2302
|
+
/* @__PURE__ */ jsx8(deps.FormFields, { formId, schema: query.data.schema, namePrefix: "values" }),
|
|
2303
|
+
/* @__PURE__ */ jsx8(deps.SubmitButton, { isSaving: save.isPending })
|
|
777
2304
|
] }) }) });
|
|
778
2305
|
};
|
|
779
2306
|
}
|
|
780
2307
|
|
|
781
2308
|
// src/components/DynamicList.tsx
|
|
782
|
-
import { useMemo as
|
|
783
|
-
import { jsx as
|
|
2309
|
+
import { useMemo as useMemo5 } from "react";
|
|
2310
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
784
2311
|
function createDynamicListComponent(deps) {
|
|
785
2312
|
return function DynamicList({ listId }) {
|
|
786
2313
|
const query = deps.hooks.useRuntimeBuilderList(listId);
|
|
787
2314
|
const state = deps.useDataTableState({ pageSize: 20 });
|
|
788
2315
|
const entriesQuery = deps.hooks.useRuntimeBuilderListEntries(listId, state.query);
|
|
789
|
-
const columns =
|
|
2316
|
+
const columns = useMemo5(() => query.data ? deps.buildColumns(query.data) : [], [query.data]);
|
|
790
2317
|
const entries = entriesQuery.data?.items ?? [];
|
|
791
2318
|
const controller = deps.useDataTable({
|
|
792
2319
|
columns,
|
|
@@ -796,7 +2323,7 @@ function createDynamicListComponent(deps) {
|
|
|
796
2323
|
getRowId: (row) => row.id
|
|
797
2324
|
});
|
|
798
2325
|
if (query.isError) {
|
|
799
|
-
return /* @__PURE__ */
|
|
2326
|
+
return /* @__PURE__ */ jsx9(
|
|
800
2327
|
deps.ErrorState,
|
|
801
2328
|
{
|
|
802
2329
|
title: "List \u043D\u044D\u044D\u0433\u0434\u0441\u044D\u043D\u0433\u04AF\u0439",
|
|
@@ -804,7 +2331,7 @@ function createDynamicListComponent(deps) {
|
|
|
804
2331
|
}
|
|
805
2332
|
);
|
|
806
2333
|
}
|
|
807
|
-
return /* @__PURE__ */
|
|
2334
|
+
return /* @__PURE__ */ jsx9(
|
|
808
2335
|
deps.DataGrid,
|
|
809
2336
|
{
|
|
810
2337
|
title: query.data?.title ?? "Dynamic List",
|
|
@@ -820,20 +2347,20 @@ function createDynamicListComponent(deps) {
|
|
|
820
2347
|
}
|
|
821
2348
|
|
|
822
2349
|
// src/components/DynamicView.tsx
|
|
823
|
-
import { useMemo as
|
|
824
|
-
import { jsx as
|
|
2350
|
+
import { useMemo as useMemo6, useState as useState3 } from "react";
|
|
2351
|
+
import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
825
2352
|
function createDynamicViewComponent(deps) {
|
|
826
2353
|
return function DynamicView({ viewId }) {
|
|
827
|
-
const [editing, setEditing] =
|
|
828
|
-
const [isDialogOpen, setDialogOpen] =
|
|
829
|
-
const [pendingDelete, setPendingDelete] =
|
|
2354
|
+
const [editing, setEditing] = useState3(null);
|
|
2355
|
+
const [isDialogOpen, setDialogOpen] = useState3(false);
|
|
2356
|
+
const [pendingDelete, setPendingDelete] = useState3(null);
|
|
830
2357
|
const viewQuery = deps.hooks.useRuntimeBuilderView(viewId);
|
|
831
2358
|
const state = deps.useDataTableState({ pageSize: 20 });
|
|
832
2359
|
const entriesQuery = deps.hooks.useBuilderViewEntries(viewId, state.query);
|
|
833
2360
|
const save = deps.hooks.useSaveBuilderViewEntry(viewId);
|
|
834
2361
|
const remove = deps.hooks.useDeleteBuilderViewEntry(viewId);
|
|
835
2362
|
const view = viewQuery.data;
|
|
836
|
-
const columns =
|
|
2363
|
+
const columns = useMemo6(
|
|
837
2364
|
() => view ? deps.buildColumns(view, {
|
|
838
2365
|
onEdit: (entry) => {
|
|
839
2366
|
setEditing(entry);
|
|
@@ -851,7 +2378,7 @@ function createDynamicViewComponent(deps) {
|
|
|
851
2378
|
getRowId: (row) => row.id
|
|
852
2379
|
});
|
|
853
2380
|
if (viewQuery.isError) {
|
|
854
|
-
return /* @__PURE__ */
|
|
2381
|
+
return /* @__PURE__ */ jsx10(
|
|
855
2382
|
deps.ErrorState,
|
|
856
2383
|
{
|
|
857
2384
|
title: "View \u043D\u044D\u044D\u0433\u0434\u0441\u044D\u043D\u0433\u04AF\u0439",
|
|
@@ -859,8 +2386,8 @@ function createDynamicViewComponent(deps) {
|
|
|
859
2386
|
}
|
|
860
2387
|
);
|
|
861
2388
|
}
|
|
862
|
-
return /* @__PURE__ */
|
|
863
|
-
/* @__PURE__ */
|
|
2389
|
+
return /* @__PURE__ */ jsxs7("div", { className: "space-y-6", children: [
|
|
2390
|
+
/* @__PURE__ */ jsx10(
|
|
864
2391
|
deps.DataGrid,
|
|
865
2392
|
{
|
|
866
2393
|
title: view?.title ?? "Dynamic View",
|
|
@@ -874,7 +2401,7 @@ function createDynamicViewComponent(deps) {
|
|
|
874
2401
|
setEditing(entry);
|
|
875
2402
|
setDialogOpen(true);
|
|
876
2403
|
},
|
|
877
|
-
toolbarExtra: /* @__PURE__ */
|
|
2404
|
+
toolbarExtra: /* @__PURE__ */ jsx10(
|
|
878
2405
|
deps.AddButton,
|
|
879
2406
|
{
|
|
880
2407
|
disabled: !view?.form,
|
|
@@ -886,7 +2413,7 @@ function createDynamicViewComponent(deps) {
|
|
|
886
2413
|
)
|
|
887
2414
|
}
|
|
888
2415
|
),
|
|
889
|
-
view ? /* @__PURE__ */
|
|
2416
|
+
view ? /* @__PURE__ */ jsx10(
|
|
890
2417
|
deps.EntryDialog,
|
|
891
2418
|
{
|
|
892
2419
|
open: isDialogOpen,
|
|
@@ -897,7 +2424,7 @@ function createDynamicViewComponent(deps) {
|
|
|
897
2424
|
isSaving: save.isPending
|
|
898
2425
|
}
|
|
899
2426
|
) : null,
|
|
900
|
-
/* @__PURE__ */
|
|
2427
|
+
/* @__PURE__ */ jsx10(
|
|
901
2428
|
deps.DeleteDialog,
|
|
902
2429
|
{
|
|
903
2430
|
entry: pendingDelete,
|
|
@@ -915,9 +2442,9 @@ function createDynamicViewComponent(deps) {
|
|
|
915
2442
|
}
|
|
916
2443
|
|
|
917
2444
|
// src/components/RuntimeEntryDialog.tsx
|
|
918
|
-
import { useEffect as
|
|
919
|
-
import { FormProvider as FormProvider4, useForm as
|
|
920
|
-
import { jsx as
|
|
2445
|
+
import { useEffect as useEffect4, useMemo as useMemo7, useState as useState4 } from "react";
|
|
2446
|
+
import { FormProvider as FormProvider4, useForm as useForm5 } from "react-hook-form";
|
|
2447
|
+
import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
921
2448
|
function isDbTableSource(source) {
|
|
922
2449
|
return source?.type === "dbTable" && "tableName" in source;
|
|
923
2450
|
}
|
|
@@ -950,19 +2477,19 @@ function createRuntimeEntryDialogComponent(deps) {
|
|
|
950
2477
|
onSave,
|
|
951
2478
|
isSaving
|
|
952
2479
|
}) {
|
|
953
|
-
const [draftSubforms, setDraftSubforms] =
|
|
2480
|
+
const [draftSubforms, setDraftSubforms] = useState4({});
|
|
954
2481
|
const compositeCreate = deps.useCreateCompositeEntry?.(view.id);
|
|
955
2482
|
const compositeUpdate = deps.useUpdateCompositeEntry?.(view.id);
|
|
956
|
-
const form =
|
|
2483
|
+
const form = useForm5({
|
|
957
2484
|
defaultValues: createBuilderEntryDefaultValues(view, editing),
|
|
958
2485
|
values: open ? createBuilderEntryDefaultValues(view, editing) : void 0
|
|
959
2486
|
});
|
|
960
2487
|
const mainTableName = runtimeViewTableName(view);
|
|
961
|
-
const hasDraftRows =
|
|
2488
|
+
const hasDraftRows = useMemo7(
|
|
962
2489
|
() => Object.values(draftSubforms).some((draft) => draft.rows.length > 0),
|
|
963
2490
|
[draftSubforms]
|
|
964
2491
|
);
|
|
965
|
-
|
|
2492
|
+
useEffect4(() => {
|
|
966
2493
|
if (open) setDraftSubforms({});
|
|
967
2494
|
}, [open]);
|
|
968
2495
|
const onSubmit = form.handleSubmit(async (values) => {
|
|
@@ -1014,7 +2541,7 @@ function createRuntimeEntryDialogComponent(deps) {
|
|
|
1014
2541
|
const saving = isSaving || Boolean(compositeCreate?.isPending || compositeUpdate?.isPending);
|
|
1015
2542
|
const extraItems = deps.SubformField && view.form?.schema.subforms?.length ? view.form.schema.subforms.map((subform) => ({
|
|
1016
2543
|
key: subform.key,
|
|
1017
|
-
render: () => deps.SubformField ? /* @__PURE__ */
|
|
2544
|
+
render: () => deps.SubformField ? /* @__PURE__ */ jsx11(
|
|
1018
2545
|
deps.SubformField,
|
|
1019
2546
|
{
|
|
1020
2547
|
subform,
|
|
@@ -1029,15 +2556,15 @@ function createRuntimeEntryDialogComponent(deps) {
|
|
|
1029
2556
|
}
|
|
1030
2557
|
) : null
|
|
1031
2558
|
})) : void 0;
|
|
1032
|
-
return /* @__PURE__ */
|
|
2559
|
+
return /* @__PURE__ */ jsx11(
|
|
1033
2560
|
deps.DialogShell,
|
|
1034
2561
|
{
|
|
1035
2562
|
open,
|
|
1036
2563
|
title: editing ? "\u041C\u04E9\u0440 \u0437\u0430\u0441\u0430\u0445" : "\u041C\u04E9\u0440 \u043D\u044D\u043C\u044D\u0445",
|
|
1037
2564
|
description: view.title,
|
|
1038
2565
|
onClose,
|
|
1039
|
-
children: /* @__PURE__ */
|
|
1040
|
-
view.form ? /* @__PURE__ */
|
|
2566
|
+
children: /* @__PURE__ */ jsx11(FormProvider4, { ...form, children: /* @__PURE__ */ jsxs8("form", { onSubmit, noValidate: true, className: deps.formClassName, children: [
|
|
2567
|
+
view.form ? /* @__PURE__ */ jsx11(
|
|
1041
2568
|
deps.FormFields,
|
|
1042
2569
|
{
|
|
1043
2570
|
formId: view.form.id,
|
|
@@ -1048,18 +2575,13 @@ function createRuntimeEntryDialogComponent(deps) {
|
|
|
1048
2575
|
extraItems
|
|
1049
2576
|
}
|
|
1050
2577
|
) : null,
|
|
1051
|
-
/* @__PURE__ */
|
|
2578
|
+
/* @__PURE__ */ jsx11(deps.Actions, { isSaving: saving, onClose })
|
|
1052
2579
|
] }) })
|
|
1053
2580
|
}
|
|
1054
2581
|
);
|
|
1055
2582
|
};
|
|
1056
2583
|
}
|
|
1057
2584
|
|
|
1058
|
-
// src/components/RuntimeSubformField.tsx
|
|
1059
|
-
import { useEffect as useEffect4, useMemo as useMemo6, useRef, useState as useState4 } from "react";
|
|
1060
|
-
import { FormProvider as FormProvider5, useForm as useForm5 } from "react-hook-form";
|
|
1061
|
-
import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1062
|
-
|
|
1063
2585
|
// src/hooks/createBuilderHooks.ts
|
|
1064
2586
|
import { keepPreviousData, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
1065
2587
|
function createBuilderKeys() {
|
|
@@ -1075,6 +2597,7 @@ function createBuilderKeys() {
|
|
|
1075
2597
|
listOptions: () => [...builderKeys.lists, "options"],
|
|
1076
2598
|
views: ["builder", "views"],
|
|
1077
2599
|
viewList: (query) => [...builderKeys.views, "list", query],
|
|
2600
|
+
view: (id) => [...builderKeys.views, "detail", id],
|
|
1078
2601
|
runtimeForm: (id) => ["builder", "runtime", "form", id],
|
|
1079
2602
|
runtimeFieldOptions: (formId, fieldKey, query) => [...builderKeys.runtimeForm(formId), "fields", fieldKey, "options", query],
|
|
1080
2603
|
runtimeFormEntries: (id) => [...builderKeys.runtimeForm(id), "entries"],
|
|
@@ -1193,6 +2716,13 @@ function createBuilderHooks(client) {
|
|
|
1193
2716
|
placeholderData: keepPreviousData
|
|
1194
2717
|
});
|
|
1195
2718
|
}
|
|
2719
|
+
function useBuilderView(id) {
|
|
2720
|
+
return useQuery({
|
|
2721
|
+
queryKey: builderKeys.view(id ?? ""),
|
|
2722
|
+
queryFn: () => client.getBuilderView(id ?? ""),
|
|
2723
|
+
enabled: Boolean(id)
|
|
2724
|
+
});
|
|
2725
|
+
}
|
|
1196
2726
|
function useSaveBuilderView() {
|
|
1197
2727
|
const queryClient = useQueryClient();
|
|
1198
2728
|
return useMutation({
|
|
@@ -1333,6 +2863,7 @@ function createBuilderHooks(client) {
|
|
|
1333
2863
|
useBuilderListOptions,
|
|
1334
2864
|
useBuilderLists,
|
|
1335
2865
|
useBuilderViewEntries,
|
|
2866
|
+
useBuilderView,
|
|
1336
2867
|
useBuilderViews,
|
|
1337
2868
|
useDeleteBuilderForm,
|
|
1338
2869
|
useDeleteBuilderList,
|
|
@@ -1357,10 +2888,59 @@ function createBuilderHooks(client) {
|
|
|
1357
2888
|
};
|
|
1358
2889
|
}
|
|
1359
2890
|
|
|
2891
|
+
// src/integration/createBuilderIntegration.ts
|
|
2892
|
+
function normalizeBasePath(path) {
|
|
2893
|
+
const trimmed = path.trim().replace(/\/+$/g, "");
|
|
2894
|
+
if (!trimmed) return "/builder";
|
|
2895
|
+
return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
2896
|
+
}
|
|
2897
|
+
function withQuery(path, query) {
|
|
2898
|
+
const params = new URLSearchParams();
|
|
2899
|
+
for (const [key, value] of Object.entries(query)) {
|
|
2900
|
+
if (value) params.set(key, value);
|
|
2901
|
+
}
|
|
2902
|
+
const queryString = params.toString();
|
|
2903
|
+
return queryString ? `${path}?${queryString}` : path;
|
|
2904
|
+
}
|
|
2905
|
+
function createBuilderIntegration(config) {
|
|
2906
|
+
const adminBasePath = normalizeBasePath(config.adminBasePath ?? "/admin/dev/builder");
|
|
2907
|
+
const runtimeBasePath = normalizeBasePath(config.runtimeBasePath ?? "/admin/winu");
|
|
2908
|
+
const api = createBuilderApiClient(config.transport);
|
|
2909
|
+
const hooks = createBuilderHooks(api);
|
|
2910
|
+
const formsPath = `${adminBasePath}/forms`;
|
|
2911
|
+
const listsPath = `${adminBasePath}/lists`;
|
|
2912
|
+
const routes = {
|
|
2913
|
+
adminBasePath,
|
|
2914
|
+
runtimeBasePath,
|
|
2915
|
+
adminHomePath: adminBasePath,
|
|
2916
|
+
formsPath,
|
|
2917
|
+
newFormPath: `${formsPath}/new`,
|
|
2918
|
+
editFormPath: (id) => withQuery(`${formsPath}/edit`, { id }),
|
|
2919
|
+
listsPath,
|
|
2920
|
+
newListPath: `${listsPath}/new`,
|
|
2921
|
+
editListPath: (id) => withQuery(`${listsPath}/edit`, { id }),
|
|
2922
|
+
viewsPath: `${adminBasePath}/views`
|
|
2923
|
+
};
|
|
2924
|
+
const adminPages = config.adminPages ? createBuilderAdminPages({
|
|
2925
|
+
...config.adminPages,
|
|
2926
|
+
hooks,
|
|
2927
|
+
routes: {
|
|
2928
|
+
adminBasePath,
|
|
2929
|
+
runtimeBasePath
|
|
2930
|
+
}
|
|
2931
|
+
}) : void 0;
|
|
2932
|
+
return {
|
|
2933
|
+
api,
|
|
2934
|
+
hooks,
|
|
2935
|
+
routes,
|
|
2936
|
+
adminPages
|
|
2937
|
+
};
|
|
2938
|
+
}
|
|
2939
|
+
|
|
1360
2940
|
// src/index.ts
|
|
1361
2941
|
var builderUiPackage = {
|
|
1362
2942
|
name: "@duke333/builder-ui",
|
|
1363
|
-
version: "0.1.
|
|
2943
|
+
version: "0.1.1"
|
|
1364
2944
|
};
|
|
1365
2945
|
export {
|
|
1366
2946
|
BUILDER_EDITOR_NONE_VALUE,
|
|
@@ -1371,19 +2951,27 @@ export {
|
|
|
1371
2951
|
builderFormEditorFieldsFromTable,
|
|
1372
2952
|
builderFormEditorInputFromValues,
|
|
1373
2953
|
builderFormEditorValuesFromEntity,
|
|
2954
|
+
builderFormLayoutDragDataType,
|
|
1374
2955
|
builderListEditorColumnsFromTable,
|
|
1375
2956
|
builderListEditorInputFromValues,
|
|
1376
2957
|
builderListEditorValuesFromEntity,
|
|
1377
2958
|
builderUiPackage,
|
|
1378
2959
|
builderViewEditorInputFromValues,
|
|
1379
2960
|
builderViewEditorValuesFromEntity,
|
|
2961
|
+
clampBuilderFormLayoutSpan,
|
|
2962
|
+
createBuilderAdminPages,
|
|
1380
2963
|
createBuilderApiClient,
|
|
2964
|
+
createBuilderDefaultEntityManagerComponent,
|
|
2965
|
+
createBuilderDefaultFormEditorBody,
|
|
2966
|
+
createBuilderDefaultListEditorBody,
|
|
2967
|
+
createBuilderDefaultViewEditorPage,
|
|
1381
2968
|
createBuilderEntityDialogManagerComponent,
|
|
1382
2969
|
createBuilderEntityManagerComponent,
|
|
1383
2970
|
createBuilderEntryDefaultValues,
|
|
1384
2971
|
createBuilderFormDefaultValues,
|
|
1385
2972
|
createBuilderFormEditorPageComponent,
|
|
1386
2973
|
createBuilderHooks,
|
|
2974
|
+
createBuilderIntegration,
|
|
1387
2975
|
createBuilderKeys,
|
|
1388
2976
|
createBuilderListEditorPageComponent,
|
|
1389
2977
|
createBuilderViewDialogComponent,
|
|
@@ -1392,6 +2980,11 @@ export {
|
|
|
1392
2980
|
createDynamicViewComponent,
|
|
1393
2981
|
createRuntimeEntryDialogComponent,
|
|
1394
2982
|
formatBuilderRuntimeValue,
|
|
1395
|
-
getBuilderEditorTriggerRoute
|
|
2983
|
+
getBuilderEditorTriggerRoute,
|
|
2984
|
+
nextBuilderFormLayoutGroupId,
|
|
2985
|
+
parseBuilderFormLayoutDragPayload,
|
|
2986
|
+
serializeBuilderFormLayoutDragPayload,
|
|
2987
|
+
swapBuilderFormLayoutItems,
|
|
2988
|
+
useBuilderFormLayoutEditor
|
|
1396
2989
|
};
|
|
1397
2990
|
//# sourceMappingURL=index.js.map
|