@duke333/builder-ui 0.1.0 → 0.1.1
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 +73 -3
- package/dist/admin/index.d.ts +243 -1
- package/dist/admin/index.js +1565 -44
- 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 +3 -2
- package/dist/index.js +1654 -86
- package/dist/index.js.map +1 -1
- package/dist/integration/index.d.ts +27 -0
- package/dist/integration/index.js +435 -0
- package/dist/integration/index.js.map +1 -0
- package/package.json +5 -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) {
|
|
@@ -310,15 +301,976 @@ function builderViewEditorInputFromValues(values, parseTriggers) {
|
|
|
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 { 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: "org:manage",
|
|
1162
|
+
permissionWrite: "org:manage",
|
|
1163
|
+
triggersText: "[]",
|
|
1164
|
+
version: 0
|
|
1165
|
+
};
|
|
1166
|
+
function createBuilderDefaultViewEditorPage(options) {
|
|
1167
|
+
return function BuilderDefaultViewEditorPage({ viewId }) {
|
|
1168
|
+
const view = options.hooks.useBuilderView(viewId);
|
|
1169
|
+
const forms = options.hooks.useBuilderFormOptions();
|
|
1170
|
+
const lists = options.hooks.useBuilderListOptions();
|
|
1171
|
+
const save = options.hooks.useSaveBuilderView();
|
|
1172
|
+
const form = useForm({
|
|
1173
|
+
defaultValues: { ...defaultEmptyValues, permissionRead: options.defaultPermission, permissionWrite: options.defaultPermission }
|
|
1174
|
+
});
|
|
1175
|
+
useEffect(() => {
|
|
1176
|
+
if (viewId && !view.data) return;
|
|
1177
|
+
form.reset(
|
|
1178
|
+
builderViewEditorValuesFromEntity(
|
|
1179
|
+
view.data ?? null,
|
|
1180
|
+
{ ...defaultEmptyValues, permissionRead: options.defaultPermission, permissionWrite: options.defaultPermission },
|
|
1181
|
+
options.defaultPermission
|
|
1182
|
+
)
|
|
1183
|
+
);
|
|
1184
|
+
}, [form, view.data, viewId]);
|
|
1185
|
+
const onSubmit = form.handleSubmit(async (values) => {
|
|
1186
|
+
try {
|
|
1187
|
+
const input = builderViewEditorInputFromValues(values, options.parseTriggers);
|
|
1188
|
+
const saved = await save.mutateAsync({
|
|
1189
|
+
id: viewId,
|
|
1190
|
+
input
|
|
1191
|
+
});
|
|
1192
|
+
options.notifySuccess?.(viewId ? "View saved" : "View created");
|
|
1193
|
+
if (!viewId) {
|
|
1194
|
+
window.location.assign(options.editHref(saved.id));
|
|
1195
|
+
}
|
|
1196
|
+
} catch (error) {
|
|
1197
|
+
if (options.notifyError) options.notifyError(error);
|
|
1198
|
+
else throw error;
|
|
1199
|
+
}
|
|
1200
|
+
});
|
|
1201
|
+
if (viewId && view.isPending) {
|
|
1202
|
+
return /* @__PURE__ */ jsx3("div", { style: styles3.state, children: "Loading..." });
|
|
1203
|
+
}
|
|
1204
|
+
if (viewId && view.isError) {
|
|
1205
|
+
return /* @__PURE__ */ jsx3("div", { style: styles3.state, children: "Failed to load view." });
|
|
1206
|
+
}
|
|
1207
|
+
return /* @__PURE__ */ jsxs3("form", { onSubmit, noValidate: true, style: styles3.page, children: [
|
|
1208
|
+
/* @__PURE__ */ jsxs3("div", { style: styles3.header, children: [
|
|
1209
|
+
/* @__PURE__ */ jsxs3("div", { children: [
|
|
1210
|
+
/* @__PURE__ */ jsx3("h1", { style: styles3.title, children: viewId ? "Edit Dynamic View" : "New Dynamic View" }),
|
|
1211
|
+
/* @__PURE__ */ jsx3("p", { style: styles3.description, children: "Connect a form and list into a runtime screen." })
|
|
1212
|
+
] }),
|
|
1213
|
+
/* @__PURE__ */ jsxs3("div", { style: styles3.actions, children: [
|
|
1214
|
+
/* @__PURE__ */ jsx3("a", { href: options.backHref, style: styles3.button, children: "Cancel" }),
|
|
1215
|
+
/* @__PURE__ */ jsx3("button", { type: "submit", disabled: save.isPending, style: styles3.primaryButton, children: save.isPending ? "Saving..." : "Save" })
|
|
1216
|
+
] })
|
|
1217
|
+
] }),
|
|
1218
|
+
/* @__PURE__ */ jsx3("section", { style: styles3.section, children: /* @__PURE__ */ jsxs3("div", { style: styles3.grid, children: [
|
|
1219
|
+
/* @__PURE__ */ jsxs3("label", { style: styles3.field, children: [
|
|
1220
|
+
/* @__PURE__ */ jsx3("span", { style: styles3.label, children: "Title" }),
|
|
1221
|
+
/* @__PURE__ */ jsx3("input", { style: styles3.input, ...form.register("title", { required: true }) })
|
|
1222
|
+
] }),
|
|
1223
|
+
/* @__PURE__ */ jsxs3("label", { style: styles3.field, children: [
|
|
1224
|
+
/* @__PURE__ */ jsx3("span", { style: styles3.label, children: "Description" }),
|
|
1225
|
+
/* @__PURE__ */ jsx3("input", { style: styles3.input, ...form.register("description") })
|
|
1226
|
+
] }),
|
|
1227
|
+
/* @__PURE__ */ jsxs3("label", { style: styles3.field, children: [
|
|
1228
|
+
/* @__PURE__ */ jsx3("span", { style: styles3.label, children: "Form" }),
|
|
1229
|
+
/* @__PURE__ */ jsxs3("select", { style: styles3.input, ...form.register("formId"), children: [
|
|
1230
|
+
/* @__PURE__ */ jsx3("option", { value: BUILDER_EDITOR_NONE_VALUE, children: "No form" }),
|
|
1231
|
+
(forms.data ?? []).map((item) => /* @__PURE__ */ jsx3("option", { value: item.id, children: item.title }, item.id))
|
|
1232
|
+
] })
|
|
1233
|
+
] }),
|
|
1234
|
+
/* @__PURE__ */ jsxs3("label", { style: styles3.field, children: [
|
|
1235
|
+
/* @__PURE__ */ jsx3("span", { style: styles3.label, children: "List" }),
|
|
1236
|
+
/* @__PURE__ */ jsxs3("select", { style: styles3.input, ...form.register("listId"), children: [
|
|
1237
|
+
/* @__PURE__ */ jsx3("option", { value: BUILDER_EDITOR_NONE_VALUE, children: "No list" }),
|
|
1238
|
+
(lists.data ?? []).map((item) => /* @__PURE__ */ jsx3("option", { value: item.id, children: item.title }, item.id))
|
|
1239
|
+
] })
|
|
1240
|
+
] }),
|
|
1241
|
+
/* @__PURE__ */ jsxs3("label", { style: styles3.field, children: [
|
|
1242
|
+
/* @__PURE__ */ jsx3("span", { style: styles3.label, children: "Read permission" }),
|
|
1243
|
+
/* @__PURE__ */ jsx3("select", { style: styles3.input, ...form.register("permissionRead"), children: options.permissionOptions.map((permission) => /* @__PURE__ */ jsx3("option", { value: permission.value, children: permission.label }, permission.value)) })
|
|
1244
|
+
] }),
|
|
1245
|
+
/* @__PURE__ */ jsxs3("label", { style: styles3.field, children: [
|
|
1246
|
+
/* @__PURE__ */ jsx3("span", { style: styles3.label, children: "Write permission" }),
|
|
1247
|
+
/* @__PURE__ */ jsx3("select", { style: styles3.input, ...form.register("permissionWrite"), children: options.permissionOptions.map((permission) => /* @__PURE__ */ jsx3("option", { value: permission.value, children: permission.label }, permission.value)) })
|
|
1248
|
+
] }),
|
|
1249
|
+
/* @__PURE__ */ jsxs3("label", { style: { ...styles3.field, gridColumn: "1 / -1" }, children: [
|
|
1250
|
+
/* @__PURE__ */ jsx3("span", { style: styles3.label, children: "Triggers JSON" }),
|
|
1251
|
+
/* @__PURE__ */ jsx3("textarea", { style: styles3.textarea, ...form.register("triggersText") })
|
|
1252
|
+
] })
|
|
1253
|
+
] }) })
|
|
1254
|
+
] });
|
|
1255
|
+
};
|
|
1256
|
+
}
|
|
1257
|
+
|
|
313
1258
|
// src/admin/BuilderEditorPage.tsx
|
|
314
|
-
import {
|
|
1259
|
+
import { useEffect as useEffect2 } from "react";
|
|
1260
|
+
import {
|
|
1261
|
+
FormProvider,
|
|
1262
|
+
useFieldArray,
|
|
1263
|
+
useForm as useForm2,
|
|
1264
|
+
useWatch
|
|
1265
|
+
} from "react-hook-form";
|
|
1266
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
315
1267
|
function createBuilderFormEditorPageComponent(deps) {
|
|
316
1268
|
return function BuilderFormEditorPage({ formId }) {
|
|
317
1269
|
const Body = deps.Body;
|
|
318
1270
|
const entityQuery = deps.hooks.useEntity(formId);
|
|
319
1271
|
const tables = deps.hooks.useTables();
|
|
320
1272
|
const save = deps.hooks.useSave();
|
|
321
|
-
const form =
|
|
1273
|
+
const form = useForm2({
|
|
322
1274
|
resolver: deps.resolver,
|
|
323
1275
|
defaultValues: deps.emptyValues
|
|
324
1276
|
});
|
|
@@ -329,7 +1281,7 @@ function createBuilderFormEditorPageComponent(deps) {
|
|
|
329
1281
|
const subforms = useWatch({ control: form.control, name: "subforms" }) ?? [];
|
|
330
1282
|
const sourceType = useWatch({ control: form.control, name: "sourceType" });
|
|
331
1283
|
const sourceTable = useWatch({ control: form.control, name: "sourceTable" });
|
|
332
|
-
|
|
1284
|
+
useEffect2(() => {
|
|
333
1285
|
if (formId && !entityQuery.data) return;
|
|
334
1286
|
form.reset(builderFormEditorValuesFromEntity(entityQuery.data ?? null, deps.emptyValues));
|
|
335
1287
|
}, [entityQuery.data, form, formId]);
|
|
@@ -352,12 +1304,12 @@ function createBuilderFormEditorPageComponent(deps) {
|
|
|
352
1304
|
}
|
|
353
1305
|
});
|
|
354
1306
|
if (formId && entityQuery.isPending) {
|
|
355
|
-
return /* @__PURE__ */
|
|
1307
|
+
return /* @__PURE__ */ jsx4("div", { className: "text-muted-foreground text-sm", children: deps.states.loading });
|
|
356
1308
|
}
|
|
357
1309
|
if (formId && entityQuery.isError) {
|
|
358
|
-
return /* @__PURE__ */
|
|
1310
|
+
return /* @__PURE__ */ jsx4("div", { className: "text-destructive text-sm", children: deps.states.error });
|
|
359
1311
|
}
|
|
360
|
-
return /* @__PURE__ */
|
|
1312
|
+
return /* @__PURE__ */ jsx4(FormProvider, { ...form, children: /* @__PURE__ */ jsx4("form", { onSubmit, noValidate: true, className: "space-y-6", children: /* @__PURE__ */ jsx4(
|
|
361
1313
|
Body,
|
|
362
1314
|
{
|
|
363
1315
|
formId,
|
|
@@ -384,7 +1336,7 @@ function createBuilderListEditorPageComponent(deps) {
|
|
|
384
1336
|
const entityQuery = deps.hooks.useEntity(listId);
|
|
385
1337
|
const tables = deps.hooks.useTables();
|
|
386
1338
|
const save = deps.hooks.useSave();
|
|
387
|
-
const form =
|
|
1339
|
+
const form = useForm2({
|
|
388
1340
|
resolver: deps.resolver,
|
|
389
1341
|
defaultValues: deps.emptyValues
|
|
390
1342
|
});
|
|
@@ -392,7 +1344,7 @@ function createBuilderListEditorPageComponent(deps) {
|
|
|
392
1344
|
const triggerArray = useFieldArray({ control: form.control, name: "triggers" });
|
|
393
1345
|
const sourceType = useWatch({ control: form.control, name: "sourceType" });
|
|
394
1346
|
const sourceTable = useWatch({ control: form.control, name: "sourceTable" });
|
|
395
|
-
|
|
1347
|
+
useEffect2(() => {
|
|
396
1348
|
if (listId && !entityQuery.data) return;
|
|
397
1349
|
form.reset(builderListEditorValuesFromEntity(entityQuery.data ?? null, deps.emptyValues));
|
|
398
1350
|
}, [entityQuery.data, form, listId]);
|
|
@@ -411,12 +1363,12 @@ function createBuilderListEditorPageComponent(deps) {
|
|
|
411
1363
|
}
|
|
412
1364
|
});
|
|
413
1365
|
if (listId && entityQuery.isPending) {
|
|
414
|
-
return /* @__PURE__ */
|
|
1366
|
+
return /* @__PURE__ */ jsx4("div", { className: "text-muted-foreground text-sm", children: deps.states.loading });
|
|
415
1367
|
}
|
|
416
1368
|
if (listId && entityQuery.isError) {
|
|
417
|
-
return /* @__PURE__ */
|
|
1369
|
+
return /* @__PURE__ */ jsx4("div", { className: "text-destructive text-sm", children: deps.states.error });
|
|
418
1370
|
}
|
|
419
|
-
return /* @__PURE__ */
|
|
1371
|
+
return /* @__PURE__ */ jsx4(FormProvider, { ...form, children: /* @__PURE__ */ jsx4("form", { onSubmit, noValidate: true, className: "space-y-6", children: /* @__PURE__ */ jsx4(
|
|
420
1372
|
Body,
|
|
421
1373
|
{
|
|
422
1374
|
listId,
|
|
@@ -435,17 +1387,405 @@ function createBuilderListEditorPageComponent(deps) {
|
|
|
435
1387
|
};
|
|
436
1388
|
}
|
|
437
1389
|
|
|
1390
|
+
// src/admin/BuilderAdminPages.tsx
|
|
1391
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1392
|
+
var defaultFieldTypeOptions = [
|
|
1393
|
+
{ value: "text", label: "Text" },
|
|
1394
|
+
{ value: "textarea", label: "Textarea" },
|
|
1395
|
+
{ value: "number", label: "Number" },
|
|
1396
|
+
{ value: "money", label: "Money" },
|
|
1397
|
+
{ value: "select", label: "Select" },
|
|
1398
|
+
{ value: "checkbox", label: "Checkbox" },
|
|
1399
|
+
{ value: "date", label: "Date" }
|
|
1400
|
+
];
|
|
1401
|
+
var defaultFormTriggerEventOptions = [
|
|
1402
|
+
{ value: "beforeCreate", label: "Before create" },
|
|
1403
|
+
{ value: "afterCreate", label: "After create" },
|
|
1404
|
+
{ value: "beforeUpdate", label: "Before update" },
|
|
1405
|
+
{ value: "afterUpdate", label: "After update" }
|
|
1406
|
+
];
|
|
1407
|
+
var defaultListTriggerEventOptions = [
|
|
1408
|
+
{ value: "beforeRead", label: "Before read" },
|
|
1409
|
+
{ value: "afterRead", label: "After read" },
|
|
1410
|
+
{ value: "beforeDelete", label: "Before delete" },
|
|
1411
|
+
{ value: "afterDelete", label: "After delete" }
|
|
1412
|
+
];
|
|
1413
|
+
var defaultFieldTriggerEventOptions = [
|
|
1414
|
+
{ value: "onChange", label: "On change" },
|
|
1415
|
+
{ value: "onBlur", label: "On blur" }
|
|
1416
|
+
];
|
|
1417
|
+
var defaultPermissionOptions = [{ value: "org:manage", label: "org:manage" }];
|
|
1418
|
+
function parseJsonArray(value) {
|
|
1419
|
+
const parsed = JSON.parse(value);
|
|
1420
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
1421
|
+
}
|
|
1422
|
+
function joinPath(base, path) {
|
|
1423
|
+
return `${base.replace(/\/$/, "")}/${path.replace(/^\//, "")}`;
|
|
1424
|
+
}
|
|
1425
|
+
function defaultQuery(state) {
|
|
1426
|
+
return {
|
|
1427
|
+
page: state.page,
|
|
1428
|
+
pageSize: state.pageSize,
|
|
1429
|
+
search: state.search || void 0
|
|
1430
|
+
};
|
|
1431
|
+
}
|
|
1432
|
+
function detail(entity) {
|
|
1433
|
+
return entity.key ?? entity.id;
|
|
1434
|
+
}
|
|
1435
|
+
var homeStyles = {
|
|
1436
|
+
page: {
|
|
1437
|
+
display: "grid",
|
|
1438
|
+
gap: "1rem"
|
|
1439
|
+
},
|
|
1440
|
+
headerTitle: {
|
|
1441
|
+
margin: 0,
|
|
1442
|
+
fontSize: "1.5rem",
|
|
1443
|
+
fontWeight: 650
|
|
1444
|
+
},
|
|
1445
|
+
description: {
|
|
1446
|
+
margin: "0.25rem 0 0",
|
|
1447
|
+
color: "var(--muted-foreground, #64748b)"
|
|
1448
|
+
},
|
|
1449
|
+
grid: {
|
|
1450
|
+
display: "grid",
|
|
1451
|
+
gridTemplateColumns: "repeat(auto-fit, minmax(13rem, 1fr))",
|
|
1452
|
+
gap: "0.75rem"
|
|
1453
|
+
},
|
|
1454
|
+
card: {
|
|
1455
|
+
border: "1px solid var(--border, #d4d4d8)",
|
|
1456
|
+
borderRadius: "0.5rem",
|
|
1457
|
+
padding: "1rem",
|
|
1458
|
+
background: "var(--background, #fff)",
|
|
1459
|
+
color: "inherit",
|
|
1460
|
+
textDecoration: "none"
|
|
1461
|
+
},
|
|
1462
|
+
cardTitle: {
|
|
1463
|
+
margin: 0,
|
|
1464
|
+
fontSize: "1rem",
|
|
1465
|
+
fontWeight: 650
|
|
1466
|
+
}
|
|
1467
|
+
};
|
|
1468
|
+
function createBuilderAdminPages({
|
|
1469
|
+
hooks,
|
|
1470
|
+
routes = {},
|
|
1471
|
+
fieldTypeOptions = defaultFieldTypeOptions,
|
|
1472
|
+
formTriggerEventOptions = defaultFormTriggerEventOptions,
|
|
1473
|
+
listTriggerEventOptions = defaultListTriggerEventOptions,
|
|
1474
|
+
fieldTriggerEventOptions = defaultFieldTriggerEventOptions,
|
|
1475
|
+
permissionOptions = defaultPermissionOptions,
|
|
1476
|
+
defaultPermission = "org:manage",
|
|
1477
|
+
notifySuccess,
|
|
1478
|
+
notifyError,
|
|
1479
|
+
parseViewTriggers = parseJsonArray
|
|
1480
|
+
}) {
|
|
1481
|
+
const adminBasePath = routes.adminBasePath ?? "/admin/dev/builder";
|
|
1482
|
+
const runtimeBasePath = routes.runtimeBasePath ?? "/admin/winu";
|
|
1483
|
+
const formsPath = routes.formsPath ?? joinPath(adminBasePath, "forms");
|
|
1484
|
+
const newFormPath = routes.newFormPath ?? joinPath(formsPath, "new");
|
|
1485
|
+
const editFormPath = routes.editFormPath ?? ((id) => `${joinPath(formsPath, "edit")}?id=${encodeURIComponent(id)}`);
|
|
1486
|
+
const runtimeFormPath = routes.runtimeFormPath ?? ((id) => `${joinPath(runtimeBasePath, "form")}?id=${encodeURIComponent(id)}`);
|
|
1487
|
+
const listsPath = routes.listsPath ?? joinPath(adminBasePath, "lists");
|
|
1488
|
+
const newListPath = routes.newListPath ?? joinPath(listsPath, "new");
|
|
1489
|
+
const editListPath = routes.editListPath ?? ((id) => `${joinPath(listsPath, "edit")}?id=${encodeURIComponent(id)}`);
|
|
1490
|
+
const runtimeListPath = routes.runtimeListPath ?? ((id) => `${joinPath(runtimeBasePath, "list")}?id=${encodeURIComponent(id)}`);
|
|
1491
|
+
const viewsPath = routes.viewsPath ?? joinPath(adminBasePath, "views");
|
|
1492
|
+
const newViewPath = routes.newViewPath ?? joinPath(viewsPath, "new");
|
|
1493
|
+
const editViewPath = routes.editViewPath ?? ((id) => `${joinPath(viewsPath, "edit")}?id=${encodeURIComponent(id)}`);
|
|
1494
|
+
const runtimeViewPath = routes.runtimeViewPath ?? ((id) => `${joinPath(runtimeBasePath, "view")}?id=${encodeURIComponent(id)}`);
|
|
1495
|
+
const formFieldType = fieldTypeOptions[0]?.value ?? "text";
|
|
1496
|
+
const formTriggerEvent = formTriggerEventOptions[0]?.value ?? "beforeCreate";
|
|
1497
|
+
const listTriggerEvent = listTriggerEventOptions[0]?.value ?? "beforeRead";
|
|
1498
|
+
const emptyField = {
|
|
1499
|
+
key: "name",
|
|
1500
|
+
label: "Name",
|
|
1501
|
+
type: formFieldType,
|
|
1502
|
+
required: true,
|
|
1503
|
+
hidden: false,
|
|
1504
|
+
disabled: false,
|
|
1505
|
+
placeholder: "",
|
|
1506
|
+
optionsText: "",
|
|
1507
|
+
optionsMode: "static",
|
|
1508
|
+
optionsTable: BUILDER_EDITOR_NONE_VALUE,
|
|
1509
|
+
optionsValueField: BUILDER_EDITOR_NONE_VALUE,
|
|
1510
|
+
optionsLabelField: BUILDER_EDITOR_NONE_VALUE,
|
|
1511
|
+
optionsSearchFieldsText: "",
|
|
1512
|
+
optionsDependsOn: "",
|
|
1513
|
+
optionsFilterField: "",
|
|
1514
|
+
triggers: []
|
|
1515
|
+
};
|
|
1516
|
+
const emptyFormValues = {
|
|
1517
|
+
title: "",
|
|
1518
|
+
description: "",
|
|
1519
|
+
sourceType: "none",
|
|
1520
|
+
sourceTable: BUILDER_EDITOR_NONE_VALUE,
|
|
1521
|
+
apiBasePath: "",
|
|
1522
|
+
fields: [emptyField],
|
|
1523
|
+
layoutGroups: builderFormEditorDefaultLayoutGroups([emptyField]),
|
|
1524
|
+
subforms: [],
|
|
1525
|
+
triggers: [],
|
|
1526
|
+
version: 0
|
|
1527
|
+
};
|
|
1528
|
+
const emptyFormTrigger = {
|
|
1529
|
+
event: formTriggerEvent,
|
|
1530
|
+
route: "/api/v1/",
|
|
1531
|
+
enabled: false,
|
|
1532
|
+
blocking: true
|
|
1533
|
+
};
|
|
1534
|
+
const emptyColumn = {
|
|
1535
|
+
key: "name",
|
|
1536
|
+
label: "Name",
|
|
1537
|
+
sortable: true,
|
|
1538
|
+
align: "left"
|
|
1539
|
+
};
|
|
1540
|
+
const emptyListValues = {
|
|
1541
|
+
title: "",
|
|
1542
|
+
description: "",
|
|
1543
|
+
sourceType: "none",
|
|
1544
|
+
sourceTable: BUILDER_EDITOR_NONE_VALUE,
|
|
1545
|
+
apiBasePath: "",
|
|
1546
|
+
columns: [emptyColumn],
|
|
1547
|
+
triggers: [],
|
|
1548
|
+
version: 0
|
|
1549
|
+
};
|
|
1550
|
+
const emptyListTrigger = {
|
|
1551
|
+
event: listTriggerEvent,
|
|
1552
|
+
route: "/api/v1/",
|
|
1553
|
+
enabled: false,
|
|
1554
|
+
blocking: true
|
|
1555
|
+
};
|
|
1556
|
+
const FormEditorPage = createBuilderFormEditorPageComponent({
|
|
1557
|
+
emptyValues: emptyFormValues,
|
|
1558
|
+
emptyField,
|
|
1559
|
+
emptyTrigger: emptyFormTrigger,
|
|
1560
|
+
labels: {
|
|
1561
|
+
created: "Form created",
|
|
1562
|
+
saved: "Form saved"
|
|
1563
|
+
},
|
|
1564
|
+
states: {
|
|
1565
|
+
loading: "Loading...",
|
|
1566
|
+
error: "Failed to load form."
|
|
1567
|
+
},
|
|
1568
|
+
hooks: {
|
|
1569
|
+
useEntity: hooks.useBuilderForm,
|
|
1570
|
+
useTables: hooks.useBuilderDbTables,
|
|
1571
|
+
useSave: hooks.useSaveBuilderForm
|
|
1572
|
+
},
|
|
1573
|
+
buildInput: (values) => builderFormEditorInputFromValues(values),
|
|
1574
|
+
navigateAfterCreate: (entity) => window.location.assign(editFormPath(entity.id)),
|
|
1575
|
+
notifications: {
|
|
1576
|
+
success: (message) => notifySuccess?.(message),
|
|
1577
|
+
error: (error) => {
|
|
1578
|
+
if (notifyError) notifyError(error);
|
|
1579
|
+
else throw error;
|
|
1580
|
+
}
|
|
1581
|
+
},
|
|
1582
|
+
Body: createBuilderDefaultFormEditorBody({
|
|
1583
|
+
backHref: formsPath,
|
|
1584
|
+
fieldTypeOptions,
|
|
1585
|
+
formTriggerEventOptions,
|
|
1586
|
+
fieldTriggerEventOptions
|
|
1587
|
+
})
|
|
1588
|
+
});
|
|
1589
|
+
const ListEditorPage = createBuilderListEditorPageComponent({
|
|
1590
|
+
emptyValues: emptyListValues,
|
|
1591
|
+
emptyColumn,
|
|
1592
|
+
emptyTrigger: emptyListTrigger,
|
|
1593
|
+
labels: {
|
|
1594
|
+
created: "List created",
|
|
1595
|
+
saved: "List saved"
|
|
1596
|
+
},
|
|
1597
|
+
states: {
|
|
1598
|
+
loading: "Loading...",
|
|
1599
|
+
error: "Failed to load list."
|
|
1600
|
+
},
|
|
1601
|
+
hooks: {
|
|
1602
|
+
useEntity: hooks.useBuilderList,
|
|
1603
|
+
useTables: hooks.useBuilderDbTables,
|
|
1604
|
+
useSave: hooks.useSaveBuilderList
|
|
1605
|
+
},
|
|
1606
|
+
buildInput: (values) => builderListEditorInputFromValues(values),
|
|
1607
|
+
navigateAfterCreate: (entity) => window.location.assign(editListPath(entity.id)),
|
|
1608
|
+
notifications: {
|
|
1609
|
+
success: (message) => notifySuccess?.(message),
|
|
1610
|
+
error: (error) => {
|
|
1611
|
+
if (notifyError) notifyError(error);
|
|
1612
|
+
else throw error;
|
|
1613
|
+
}
|
|
1614
|
+
},
|
|
1615
|
+
Body: createBuilderDefaultListEditorBody({
|
|
1616
|
+
backHref: listsPath,
|
|
1617
|
+
listTriggerEventOptions
|
|
1618
|
+
})
|
|
1619
|
+
});
|
|
1620
|
+
const ViewEditorPage = createBuilderDefaultViewEditorPage({
|
|
1621
|
+
hooks,
|
|
1622
|
+
backHref: viewsPath,
|
|
1623
|
+
editHref: editViewPath,
|
|
1624
|
+
permissionOptions,
|
|
1625
|
+
defaultPermission,
|
|
1626
|
+
parseTriggers: parseViewTriggers,
|
|
1627
|
+
notifySuccess,
|
|
1628
|
+
notifyError
|
|
1629
|
+
});
|
|
1630
|
+
const AdminHomePage = function BuilderAdminHomePage() {
|
|
1631
|
+
const items = [
|
|
1632
|
+
{
|
|
1633
|
+
title: "Dynamic Forms",
|
|
1634
|
+
description: "Reusable form schemas.",
|
|
1635
|
+
href: formsPath
|
|
1636
|
+
},
|
|
1637
|
+
{
|
|
1638
|
+
title: "Dynamic Lists",
|
|
1639
|
+
description: "Reusable list and grid schemas.",
|
|
1640
|
+
href: listsPath
|
|
1641
|
+
},
|
|
1642
|
+
{
|
|
1643
|
+
title: "Dynamic Views",
|
|
1644
|
+
description: "Runtime screens composed from form and list schemas.",
|
|
1645
|
+
href: viewsPath
|
|
1646
|
+
}
|
|
1647
|
+
];
|
|
1648
|
+
return /* @__PURE__ */ jsxs4("section", { style: homeStyles.page, children: [
|
|
1649
|
+
/* @__PURE__ */ jsxs4("div", { children: [
|
|
1650
|
+
/* @__PURE__ */ jsx5("h1", { style: homeStyles.headerTitle, children: "Builder" }),
|
|
1651
|
+
/* @__PURE__ */ jsx5("p", { style: homeStyles.description, children: "Manage dynamic forms, lists, and views." })
|
|
1652
|
+
] }),
|
|
1653
|
+
/* @__PURE__ */ jsx5("div", { style: homeStyles.grid, children: items.map((item) => /* @__PURE__ */ jsxs4("a", { href: item.href, style: homeStyles.card, children: [
|
|
1654
|
+
/* @__PURE__ */ jsx5("h2", { style: homeStyles.cardTitle, children: item.title }),
|
|
1655
|
+
/* @__PURE__ */ jsx5("p", { style: homeStyles.description, children: item.description })
|
|
1656
|
+
] }, item.href)) })
|
|
1657
|
+
] });
|
|
1658
|
+
};
|
|
1659
|
+
const AdminFormsPage = createBuilderDefaultEntityManagerComponent({
|
|
1660
|
+
labels: {
|
|
1661
|
+
title: "Dynamic Forms",
|
|
1662
|
+
description: "Reusable form schemas.",
|
|
1663
|
+
searchPlaceholder: "Search forms...",
|
|
1664
|
+
emptyTitle: "No forms",
|
|
1665
|
+
emptyDescription: "Create your first dynamic form.",
|
|
1666
|
+
addLabel: "Add form",
|
|
1667
|
+
editLabel: "Edit",
|
|
1668
|
+
replicateLabel: "Replicate",
|
|
1669
|
+
deleteLabel: "Delete",
|
|
1670
|
+
runtimeLabel: "Open",
|
|
1671
|
+
deleteConfirm: (entity) => `Delete ${entity.title}?`,
|
|
1672
|
+
replicatePrompt: () => "New form title",
|
|
1673
|
+
replicateDefaultTitle: (entity) => `${entity.title} copy`
|
|
1674
|
+
},
|
|
1675
|
+
createHref: newFormPath,
|
|
1676
|
+
editHref: (entity) => editFormPath(entity.id),
|
|
1677
|
+
runtimeHref: (entity) => runtimeFormPath(entity.id),
|
|
1678
|
+
getDetail: detail,
|
|
1679
|
+
buildQuery: (state) => defaultQuery(state),
|
|
1680
|
+
hooks: {
|
|
1681
|
+
useEntities: (query) => hooks.useBuilderForms(query),
|
|
1682
|
+
useDelete: hooks.useDeleteBuilderForm,
|
|
1683
|
+
useReplicate: hooks.useReplicateBuilderForm
|
|
1684
|
+
}
|
|
1685
|
+
});
|
|
1686
|
+
const AdminListsPage = createBuilderDefaultEntityManagerComponent({
|
|
1687
|
+
labels: {
|
|
1688
|
+
title: "Dynamic Lists",
|
|
1689
|
+
description: "Reusable list and grid schemas.",
|
|
1690
|
+
searchPlaceholder: "Search lists...",
|
|
1691
|
+
emptyTitle: "No lists",
|
|
1692
|
+
emptyDescription: "Create your first dynamic list.",
|
|
1693
|
+
addLabel: "Add list",
|
|
1694
|
+
editLabel: "Edit",
|
|
1695
|
+
replicateLabel: "Replicate",
|
|
1696
|
+
deleteLabel: "Delete",
|
|
1697
|
+
runtimeLabel: "Open",
|
|
1698
|
+
deleteConfirm: (entity) => `Delete ${entity.title}?`,
|
|
1699
|
+
replicatePrompt: () => "New list title",
|
|
1700
|
+
replicateDefaultTitle: (entity) => `${entity.title} copy`
|
|
1701
|
+
},
|
|
1702
|
+
createHref: newListPath,
|
|
1703
|
+
editHref: (entity) => editListPath(entity.id),
|
|
1704
|
+
runtimeHref: (entity) => runtimeListPath(entity.id),
|
|
1705
|
+
getDetail: detail,
|
|
1706
|
+
buildQuery: (state) => defaultQuery(state),
|
|
1707
|
+
hooks: {
|
|
1708
|
+
useEntities: (query) => hooks.useBuilderLists(query),
|
|
1709
|
+
useDelete: hooks.useDeleteBuilderList,
|
|
1710
|
+
useReplicate: hooks.useReplicateBuilderList
|
|
1711
|
+
}
|
|
1712
|
+
});
|
|
1713
|
+
const AdminViewsPage = createBuilderDefaultEntityManagerComponent({
|
|
1714
|
+
labels: {
|
|
1715
|
+
title: "Dynamic Views",
|
|
1716
|
+
description: "Runtime screens composed from form and list schemas.",
|
|
1717
|
+
searchPlaceholder: "Search views...",
|
|
1718
|
+
emptyTitle: "No views",
|
|
1719
|
+
emptyDescription: "Create a dynamic view after preparing a form and list.",
|
|
1720
|
+
addLabel: "Add view",
|
|
1721
|
+
editLabel: "Edit",
|
|
1722
|
+
replicateLabel: "Replicate",
|
|
1723
|
+
deleteLabel: "Delete",
|
|
1724
|
+
runtimeLabel: "Open",
|
|
1725
|
+
deleteConfirm: (entity) => `Delete ${entity.title}?`,
|
|
1726
|
+
replicatePrompt: () => "New view title",
|
|
1727
|
+
replicateDefaultTitle: (entity) => `${entity.title} copy`
|
|
1728
|
+
},
|
|
1729
|
+
createHref: newViewPath,
|
|
1730
|
+
editHref: (entity) => editViewPath(entity.id),
|
|
1731
|
+
runtimeHref: (entity) => runtimeViewPath(entity.id),
|
|
1732
|
+
getDetail: detail,
|
|
1733
|
+
buildQuery: (state) => defaultQuery(state),
|
|
1734
|
+
hooks: {
|
|
1735
|
+
useEntities: (query) => hooks.useBuilderViews(query),
|
|
1736
|
+
useDelete: hooks.useDeleteBuilderView,
|
|
1737
|
+
useReplicate: hooks.useReplicateBuilderView
|
|
1738
|
+
}
|
|
1739
|
+
});
|
|
1740
|
+
return {
|
|
1741
|
+
AdminHomePage,
|
|
1742
|
+
AdminFormsPage,
|
|
1743
|
+
AdminNewFormPage: function BuilderAdminNewFormPage() {
|
|
1744
|
+
return /* @__PURE__ */ jsx5(FormEditorPage, {});
|
|
1745
|
+
},
|
|
1746
|
+
AdminEditFormPage: function BuilderAdminEditFormPage({ formId }) {
|
|
1747
|
+
return /* @__PURE__ */ jsx5(FormEditorPage, { formId });
|
|
1748
|
+
},
|
|
1749
|
+
AdminListsPage,
|
|
1750
|
+
AdminNewListPage: function BuilderAdminNewListPage() {
|
|
1751
|
+
return /* @__PURE__ */ jsx5(ListEditorPage, {});
|
|
1752
|
+
},
|
|
1753
|
+
AdminEditListPage: function BuilderAdminEditListPage({ listId }) {
|
|
1754
|
+
return /* @__PURE__ */ jsx5(ListEditorPage, { listId });
|
|
1755
|
+
},
|
|
1756
|
+
AdminViewsPage,
|
|
1757
|
+
AdminNewViewPage: function BuilderAdminNewViewPage() {
|
|
1758
|
+
return /* @__PURE__ */ jsx5(ViewEditorPage, {});
|
|
1759
|
+
},
|
|
1760
|
+
AdminEditViewPage: function BuilderAdminEditViewPage({ viewId }) {
|
|
1761
|
+
return /* @__PURE__ */ jsx5(ViewEditorPage, { viewId });
|
|
1762
|
+
},
|
|
1763
|
+
routes: {
|
|
1764
|
+
adminBasePath,
|
|
1765
|
+
formsPath,
|
|
1766
|
+
newFormPath,
|
|
1767
|
+
editFormPath,
|
|
1768
|
+
listsPath,
|
|
1769
|
+
newListPath,
|
|
1770
|
+
editListPath,
|
|
1771
|
+
viewsPath,
|
|
1772
|
+
newViewPath,
|
|
1773
|
+
editViewPath
|
|
1774
|
+
}
|
|
1775
|
+
};
|
|
1776
|
+
}
|
|
1777
|
+
|
|
438
1778
|
// src/admin/BuilderEntityManager.tsx
|
|
439
|
-
import { useCallback, useMemo, useState } from "react";
|
|
440
|
-
import { jsx as
|
|
1779
|
+
import { useCallback, useMemo as useMemo2, useState as useState2 } from "react";
|
|
1780
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
441
1781
|
function createBuilderEntityManagerComponent(deps) {
|
|
442
1782
|
return function BuilderEntityManager() {
|
|
443
|
-
const [pendingDelete, setPendingDelete] =
|
|
1783
|
+
const [pendingDelete, setPendingDelete] = useState2(null);
|
|
444
1784
|
const state = deps.useDataTableState({ pageSize: 20 });
|
|
445
1785
|
const query = deps.hooks.useEntities(state.query);
|
|
446
1786
|
const remove = deps.hooks.useDelete();
|
|
447
1787
|
const replicate = deps.hooks.useReplicate();
|
|
448
|
-
const columns =
|
|
1788
|
+
const columns = useMemo2(
|
|
449
1789
|
() => deps.buildColumns({
|
|
450
1790
|
onEdit: deps.navigateToEdit,
|
|
451
1791
|
onReplicate: async (entity) => {
|
|
@@ -465,8 +1805,8 @@ function createBuilderEntityManagerComponent(deps) {
|
|
|
465
1805
|
state,
|
|
466
1806
|
getRowId: (row) => row.id
|
|
467
1807
|
});
|
|
468
|
-
return /* @__PURE__ */
|
|
469
|
-
/* @__PURE__ */
|
|
1808
|
+
return /* @__PURE__ */ jsxs5("div", { className: "space-y-6", children: [
|
|
1809
|
+
/* @__PURE__ */ jsx6(
|
|
470
1810
|
deps.DataGrid,
|
|
471
1811
|
{
|
|
472
1812
|
title: deps.labels.title,
|
|
@@ -477,10 +1817,10 @@ function createBuilderEntityManagerComponent(deps) {
|
|
|
477
1817
|
emptyTitle: deps.labels.emptyTitle,
|
|
478
1818
|
emptyDescription: deps.labels.emptyDescription,
|
|
479
1819
|
onRowClick: deps.navigateToEdit,
|
|
480
|
-
toolbarExtra: /* @__PURE__ */
|
|
1820
|
+
toolbarExtra: /* @__PURE__ */ jsx6(deps.AddButton, { href: deps.createHref, label: deps.labels.addLabel })
|
|
481
1821
|
}
|
|
482
1822
|
),
|
|
483
|
-
/* @__PURE__ */
|
|
1823
|
+
/* @__PURE__ */ jsx6(
|
|
484
1824
|
deps.DeleteDialog,
|
|
485
1825
|
{
|
|
486
1826
|
entity: pendingDelete,
|
|
@@ -500,9 +1840,9 @@ function createBuilderEntityManagerComponent(deps) {
|
|
|
500
1840
|
}
|
|
501
1841
|
function createBuilderEntityDialogManagerComponent(deps) {
|
|
502
1842
|
return function BuilderEntityDialogManager() {
|
|
503
|
-
const [editing, setEditing] =
|
|
504
|
-
const [isEditorOpen, setEditorOpen] =
|
|
505
|
-
const [pendingDelete, setPendingDelete] =
|
|
1843
|
+
const [editing, setEditing] = useState2(null);
|
|
1844
|
+
const [isEditorOpen, setEditorOpen] = useState2(false);
|
|
1845
|
+
const [pendingDelete, setPendingDelete] = useState2(null);
|
|
506
1846
|
const state = deps.useDataTableState({ pageSize: 20 });
|
|
507
1847
|
const query = deps.hooks.useEntities(state.query);
|
|
508
1848
|
const remove = deps.hooks.useDelete();
|
|
@@ -511,7 +1851,7 @@ function createBuilderEntityDialogManagerComponent(deps) {
|
|
|
511
1851
|
setEditing(entity);
|
|
512
1852
|
setEditorOpen(true);
|
|
513
1853
|
}, []);
|
|
514
|
-
const columns =
|
|
1854
|
+
const columns = useMemo2(
|
|
515
1855
|
() => deps.buildColumns({
|
|
516
1856
|
onEdit: (entity) => openEditor(entity),
|
|
517
1857
|
onReplicate: async (entity) => {
|
|
@@ -531,8 +1871,8 @@ function createBuilderEntityDialogManagerComponent(deps) {
|
|
|
531
1871
|
state,
|
|
532
1872
|
getRowId: (row) => row.id
|
|
533
1873
|
});
|
|
534
|
-
return /* @__PURE__ */
|
|
535
|
-
/* @__PURE__ */
|
|
1874
|
+
return /* @__PURE__ */ jsxs5("div", { className: "space-y-6", children: [
|
|
1875
|
+
/* @__PURE__ */ jsx6(
|
|
536
1876
|
deps.DataGrid,
|
|
537
1877
|
{
|
|
538
1878
|
title: deps.labels.title,
|
|
@@ -543,10 +1883,10 @@ function createBuilderEntityDialogManagerComponent(deps) {
|
|
|
543
1883
|
emptyTitle: deps.labels.emptyTitle,
|
|
544
1884
|
emptyDescription: deps.labels.emptyDescription,
|
|
545
1885
|
onRowClick: openEditor,
|
|
546
|
-
toolbarExtra: /* @__PURE__ */
|
|
1886
|
+
toolbarExtra: /* @__PURE__ */ jsx6(deps.AddButton, { label: deps.labels.addLabel, onAdd: () => openEditor(null) })
|
|
547
1887
|
}
|
|
548
1888
|
),
|
|
549
|
-
/* @__PURE__ */
|
|
1889
|
+
/* @__PURE__ */ jsx6(
|
|
550
1890
|
deps.EditorDialog,
|
|
551
1891
|
{
|
|
552
1892
|
open: isEditorOpen,
|
|
@@ -554,7 +1894,7 @@ function createBuilderEntityDialogManagerComponent(deps) {
|
|
|
554
1894
|
onClose: () => setEditorOpen(false)
|
|
555
1895
|
}
|
|
556
1896
|
),
|
|
557
|
-
/* @__PURE__ */
|
|
1897
|
+
/* @__PURE__ */ jsx6(
|
|
558
1898
|
deps.DeleteDialog,
|
|
559
1899
|
{
|
|
560
1900
|
entity: pendingDelete,
|
|
@@ -574,9 +1914,9 @@ function createBuilderEntityDialogManagerComponent(deps) {
|
|
|
574
1914
|
}
|
|
575
1915
|
|
|
576
1916
|
// src/admin/BuilderViewDialog.tsx
|
|
577
|
-
import { useEffect as
|
|
578
|
-
import { FormProvider as FormProvider2, useForm as
|
|
579
|
-
import { jsx as
|
|
1917
|
+
import { useEffect as useEffect3 } from "react";
|
|
1918
|
+
import { FormProvider as FormProvider2, useForm as useForm3 } from "react-hook-form";
|
|
1919
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
580
1920
|
function createBuilderViewDialogComponent(deps) {
|
|
581
1921
|
return function BuilderViewDialog({
|
|
582
1922
|
open,
|
|
@@ -587,11 +1927,11 @@ function createBuilderViewDialogComponent(deps) {
|
|
|
587
1927
|
onSave,
|
|
588
1928
|
isSaving
|
|
589
1929
|
}) {
|
|
590
|
-
const form =
|
|
1930
|
+
const form = useForm3({
|
|
591
1931
|
resolver: deps.resolver,
|
|
592
1932
|
defaultValues: deps.emptyValues
|
|
593
1933
|
});
|
|
594
|
-
|
|
1934
|
+
useEffect3(() => {
|
|
595
1935
|
if (!open) return;
|
|
596
1936
|
form.reset(
|
|
597
1937
|
builderViewEditorValuesFromEntity(editing, deps.emptyValues, deps.defaultPermission)
|
|
@@ -606,7 +1946,7 @@ function createBuilderViewDialogComponent(deps) {
|
|
|
606
1946
|
deps.notifications.error(error);
|
|
607
1947
|
}
|
|
608
1948
|
});
|
|
609
|
-
return /* @__PURE__ */
|
|
1949
|
+
return /* @__PURE__ */ jsx7(deps.Shell, { open, editing, onClose, children: /* @__PURE__ */ jsx7(FormProvider2, { ...form, children: /* @__PURE__ */ jsx7("form", { onSubmit, noValidate: true, children: deps.Body({
|
|
610
1950
|
form,
|
|
611
1951
|
editing,
|
|
612
1952
|
forms,
|
|
@@ -619,6 +1959,175 @@ function createBuilderViewDialogComponent(deps) {
|
|
|
619
1959
|
};
|
|
620
1960
|
}
|
|
621
1961
|
|
|
1962
|
+
// src/admin/formLayoutEditorState.ts
|
|
1963
|
+
import { useMemo as useMemo3 } from "react";
|
|
1964
|
+
import { useWatch as useWatch2 } from "react-hook-form";
|
|
1965
|
+
var builderFormLayoutDragDataType = "application/x-winu-builder-layout-field";
|
|
1966
|
+
function clampBuilderFormLayoutSpan(span, columns) {
|
|
1967
|
+
return Math.max(1, Math.min(columns, span));
|
|
1968
|
+
}
|
|
1969
|
+
function swapBuilderFormLayoutItems(items, from, to) {
|
|
1970
|
+
if (from < 0 || from >= items.length || to < 0 || to >= items.length) return items;
|
|
1971
|
+
const next = [...items];
|
|
1972
|
+
const item = next[from];
|
|
1973
|
+
next[from] = next[to];
|
|
1974
|
+
next[to] = item;
|
|
1975
|
+
return next;
|
|
1976
|
+
}
|
|
1977
|
+
function nextBuilderFormLayoutGroupId(groups) {
|
|
1978
|
+
let index = groups.length + 1;
|
|
1979
|
+
let id = `group${index}`;
|
|
1980
|
+
const ids = new Set(groups.map((group) => group.id));
|
|
1981
|
+
while (ids.has(id)) {
|
|
1982
|
+
index += 1;
|
|
1983
|
+
id = `group${index}`;
|
|
1984
|
+
}
|
|
1985
|
+
return id;
|
|
1986
|
+
}
|
|
1987
|
+
function serializeBuilderFormLayoutDragPayload(payload) {
|
|
1988
|
+
return JSON.stringify(payload);
|
|
1989
|
+
}
|
|
1990
|
+
function parseBuilderFormLayoutDragPayload(raw) {
|
|
1991
|
+
if (!raw) return null;
|
|
1992
|
+
try {
|
|
1993
|
+
const value = JSON.parse(raw);
|
|
1994
|
+
if (value.type === "palette" && typeof value.key === "string" && value.key) {
|
|
1995
|
+
return { type: value.type, key: value.key };
|
|
1996
|
+
}
|
|
1997
|
+
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) {
|
|
1998
|
+
return {
|
|
1999
|
+
type: value.type,
|
|
2000
|
+
groupIndex: value.groupIndex,
|
|
2001
|
+
fieldIndex: value.fieldIndex,
|
|
2002
|
+
key: value.key
|
|
2003
|
+
};
|
|
2004
|
+
}
|
|
2005
|
+
return null;
|
|
2006
|
+
} catch {
|
|
2007
|
+
return null;
|
|
2008
|
+
}
|
|
2009
|
+
}
|
|
2010
|
+
function useBuilderFormLayoutEditor({ form, fields, subforms = [] }) {
|
|
2011
|
+
const layoutGroups = useWatch2({ control: form.control, name: "layoutGroups" }) ?? [];
|
|
2012
|
+
const layoutItems = useMemo3(
|
|
2013
|
+
() => [
|
|
2014
|
+
...fields.map((field) => ({
|
|
2015
|
+
key: field.key,
|
|
2016
|
+
kind: "field",
|
|
2017
|
+
meta: field.type,
|
|
2018
|
+
span: builderFormEditorDefaultSpan(field)
|
|
2019
|
+
})),
|
|
2020
|
+
...subforms.map((subform) => ({
|
|
2021
|
+
key: subform.key,
|
|
2022
|
+
kind: "subform",
|
|
2023
|
+
meta: "subform",
|
|
2024
|
+
span: 12
|
|
2025
|
+
}))
|
|
2026
|
+
],
|
|
2027
|
+
[fields, subforms]
|
|
2028
|
+
);
|
|
2029
|
+
const assignedKeys = useMemo3(
|
|
2030
|
+
() => new Set(layoutGroups.flatMap((group) => group.fields.map((field) => field.key))),
|
|
2031
|
+
[layoutGroups]
|
|
2032
|
+
);
|
|
2033
|
+
const unassignedItems = useMemo3(
|
|
2034
|
+
() => layoutItems.filter((item) => !assignedKeys.has(item.key)),
|
|
2035
|
+
[assignedKeys, layoutItems]
|
|
2036
|
+
);
|
|
2037
|
+
const setGroups = (groups) => {
|
|
2038
|
+
form.setValue("layoutGroups", groups, { shouldDirty: true, shouldValidate: true });
|
|
2039
|
+
};
|
|
2040
|
+
const updateGroup = (groupIndex, group) => {
|
|
2041
|
+
setGroups(layoutGroups.map((item, index) => index === groupIndex ? group : item));
|
|
2042
|
+
};
|
|
2043
|
+
const updateGroupFields = (groupIndex, updater) => {
|
|
2044
|
+
const group = layoutGroups[groupIndex];
|
|
2045
|
+
if (!group) return;
|
|
2046
|
+
updateGroup(groupIndex, { ...group, fields: updater(group.fields) });
|
|
2047
|
+
};
|
|
2048
|
+
const addGroup = () => {
|
|
2049
|
+
setGroups([
|
|
2050
|
+
...layoutGroups,
|
|
2051
|
+
{
|
|
2052
|
+
id: nextBuilderFormLayoutGroupId(layoutGroups),
|
|
2053
|
+
title: `Group ${layoutGroups.length + 1}`,
|
|
2054
|
+
columns: 12,
|
|
2055
|
+
fields: []
|
|
2056
|
+
}
|
|
2057
|
+
]);
|
|
2058
|
+
};
|
|
2059
|
+
const addItemToNewGroup = (itemKey) => {
|
|
2060
|
+
if (assignedKeys.has(itemKey)) return;
|
|
2061
|
+
const item = layoutItems.find((candidate) => candidate.key === itemKey);
|
|
2062
|
+
if (!item) return;
|
|
2063
|
+
setGroups([
|
|
2064
|
+
...layoutGroups,
|
|
2065
|
+
{
|
|
2066
|
+
id: nextBuilderFormLayoutGroupId(layoutGroups),
|
|
2067
|
+
title: layoutGroups.length === 0 ? "\u04AE\u043D\u0434\u0441\u044D\u043D" : `Group ${layoutGroups.length + 1}`,
|
|
2068
|
+
columns: 12,
|
|
2069
|
+
fields: [{ key: itemKey, span: item.span }]
|
|
2070
|
+
}
|
|
2071
|
+
]);
|
|
2072
|
+
};
|
|
2073
|
+
const addItemToGroup = (groupIndex, itemKey, insertAt) => {
|
|
2074
|
+
if (assignedKeys.has(itemKey)) return;
|
|
2075
|
+
const item = layoutItems.find((candidate) => candidate.key === itemKey);
|
|
2076
|
+
const group = layoutGroups[groupIndex];
|
|
2077
|
+
if (!item || !group) return;
|
|
2078
|
+
const nextField = {
|
|
2079
|
+
key: itemKey,
|
|
2080
|
+
span: clampBuilderFormLayoutSpan(item.span, group.columns)
|
|
2081
|
+
};
|
|
2082
|
+
updateGroupFields(groupIndex, (groupFields) => {
|
|
2083
|
+
const next = [...groupFields];
|
|
2084
|
+
next.splice(insertAt ?? next.length, 0, nextField);
|
|
2085
|
+
return next;
|
|
2086
|
+
});
|
|
2087
|
+
};
|
|
2088
|
+
const moveLayoutField = (payload, targetGroupIndex, targetFieldIndex) => {
|
|
2089
|
+
const sourceGroup = layoutGroups[payload.groupIndex];
|
|
2090
|
+
const targetGroup = layoutGroups[targetGroupIndex];
|
|
2091
|
+
if (!sourceGroup || !targetGroup) return;
|
|
2092
|
+
const movingField = sourceGroup.fields[payload.fieldIndex];
|
|
2093
|
+
if (!movingField) return;
|
|
2094
|
+
const nextGroups = layoutGroups.map((group) => ({ ...group, fields: [...group.fields] }));
|
|
2095
|
+
nextGroups[payload.groupIndex].fields.splice(payload.fieldIndex, 1);
|
|
2096
|
+
let insertAt = targetFieldIndex ?? nextGroups[targetGroupIndex].fields.length;
|
|
2097
|
+
if (payload.groupIndex === targetGroupIndex && payload.fieldIndex < insertAt) {
|
|
2098
|
+
insertAt -= 1;
|
|
2099
|
+
}
|
|
2100
|
+
nextGroups[targetGroupIndex].fields.splice(insertAt, 0, {
|
|
2101
|
+
...movingField,
|
|
2102
|
+
span: clampBuilderFormLayoutSpan(movingField.span, targetGroup.columns)
|
|
2103
|
+
});
|
|
2104
|
+
setGroups(nextGroups);
|
|
2105
|
+
};
|
|
2106
|
+
const applyDragPayload = (payload, targetGroupIndex, targetFieldIndex) => {
|
|
2107
|
+
if (!payload) return;
|
|
2108
|
+
if (payload.type === "palette") {
|
|
2109
|
+
addItemToGroup(targetGroupIndex, payload.key, targetFieldIndex);
|
|
2110
|
+
return;
|
|
2111
|
+
}
|
|
2112
|
+
moveLayoutField(payload, targetGroupIndex, targetFieldIndex);
|
|
2113
|
+
};
|
|
2114
|
+
const resetDefaultLayout = () => setGroups(builderFormEditorDefaultLayoutGroups(fields, subforms));
|
|
2115
|
+
return {
|
|
2116
|
+
assignedKeys,
|
|
2117
|
+
layoutGroups,
|
|
2118
|
+
layoutItems,
|
|
2119
|
+
unassignedItems,
|
|
2120
|
+
addGroup,
|
|
2121
|
+
addItemToGroup,
|
|
2122
|
+
addItemToNewGroup,
|
|
2123
|
+
applyDragPayload,
|
|
2124
|
+
resetDefaultLayout,
|
|
2125
|
+
setGroups,
|
|
2126
|
+
updateGroup,
|
|
2127
|
+
updateGroupFields
|
|
2128
|
+
};
|
|
2129
|
+
}
|
|
2130
|
+
|
|
622
2131
|
// src/api/createBuilderApiClient.ts
|
|
623
2132
|
function queryParams(query) {
|
|
624
2133
|
return { ...query };
|
|
@@ -709,8 +2218,8 @@ function createBuilderApiClient(transport) {
|
|
|
709
2218
|
}
|
|
710
2219
|
|
|
711
2220
|
// src/components/DynamicForm.tsx
|
|
712
|
-
import { useMemo as
|
|
713
|
-
import { FormProvider as FormProvider3, useForm as
|
|
2221
|
+
import { useMemo as useMemo4 } from "react";
|
|
2222
|
+
import { FormProvider as FormProvider3, useForm as useForm4 } from "react-hook-form";
|
|
714
2223
|
|
|
715
2224
|
// src/runtime/runtimeUtils.ts
|
|
716
2225
|
function emptyFieldValue(field) {
|
|
@@ -739,16 +2248,16 @@ function formatBuilderRuntimeValue(value, locale = "mn-MN") {
|
|
|
739
2248
|
}
|
|
740
2249
|
|
|
741
2250
|
// src/components/DynamicForm.tsx
|
|
742
|
-
import { jsx as
|
|
2251
|
+
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
743
2252
|
function createDynamicFormComponent(deps) {
|
|
744
2253
|
return function DynamicForm({ formId }) {
|
|
745
2254
|
const query = deps.hooks.useRuntimeBuilderForm(formId);
|
|
746
2255
|
const save = deps.hooks.useSaveRuntimeBuilderFormEntry(formId);
|
|
747
|
-
const formValues =
|
|
2256
|
+
const formValues = useMemo4(
|
|
748
2257
|
() => query.data ? createBuilderFormDefaultValues(query.data.schema) : void 0,
|
|
749
2258
|
[query.data]
|
|
750
2259
|
);
|
|
751
|
-
const form =
|
|
2260
|
+
const form = useForm4({
|
|
752
2261
|
defaultValues: createBuilderFormDefaultValues(query.data?.schema),
|
|
753
2262
|
values: formValues
|
|
754
2263
|
});
|
|
@@ -762,7 +2271,7 @@ function createDynamicFormComponent(deps) {
|
|
|
762
2271
|
}
|
|
763
2272
|
});
|
|
764
2273
|
if (query.isError) {
|
|
765
|
-
return /* @__PURE__ */
|
|
2274
|
+
return /* @__PURE__ */ jsx8(
|
|
766
2275
|
deps.ErrorState,
|
|
767
2276
|
{
|
|
768
2277
|
title: "Form \u043D\u044D\u044D\u0433\u0434\u0441\u044D\u043D\u0433\u04AF\u0439",
|
|
@@ -771,22 +2280,22 @@ function createDynamicFormComponent(deps) {
|
|
|
771
2280
|
);
|
|
772
2281
|
}
|
|
773
2282
|
if (!query.data) return null;
|
|
774
|
-
return /* @__PURE__ */
|
|
775
|
-
/* @__PURE__ */
|
|
776
|
-
/* @__PURE__ */
|
|
2283
|
+
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: [
|
|
2284
|
+
/* @__PURE__ */ jsx8(deps.FormFields, { formId, schema: query.data.schema, namePrefix: "values" }),
|
|
2285
|
+
/* @__PURE__ */ jsx8(deps.SubmitButton, { isSaving: save.isPending })
|
|
777
2286
|
] }) }) });
|
|
778
2287
|
};
|
|
779
2288
|
}
|
|
780
2289
|
|
|
781
2290
|
// src/components/DynamicList.tsx
|
|
782
|
-
import { useMemo as
|
|
783
|
-
import { jsx as
|
|
2291
|
+
import { useMemo as useMemo5 } from "react";
|
|
2292
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
784
2293
|
function createDynamicListComponent(deps) {
|
|
785
2294
|
return function DynamicList({ listId }) {
|
|
786
2295
|
const query = deps.hooks.useRuntimeBuilderList(listId);
|
|
787
2296
|
const state = deps.useDataTableState({ pageSize: 20 });
|
|
788
2297
|
const entriesQuery = deps.hooks.useRuntimeBuilderListEntries(listId, state.query);
|
|
789
|
-
const columns =
|
|
2298
|
+
const columns = useMemo5(() => query.data ? deps.buildColumns(query.data) : [], [query.data]);
|
|
790
2299
|
const entries = entriesQuery.data?.items ?? [];
|
|
791
2300
|
const controller = deps.useDataTable({
|
|
792
2301
|
columns,
|
|
@@ -796,7 +2305,7 @@ function createDynamicListComponent(deps) {
|
|
|
796
2305
|
getRowId: (row) => row.id
|
|
797
2306
|
});
|
|
798
2307
|
if (query.isError) {
|
|
799
|
-
return /* @__PURE__ */
|
|
2308
|
+
return /* @__PURE__ */ jsx9(
|
|
800
2309
|
deps.ErrorState,
|
|
801
2310
|
{
|
|
802
2311
|
title: "List \u043D\u044D\u044D\u0433\u0434\u0441\u044D\u043D\u0433\u04AF\u0439",
|
|
@@ -804,7 +2313,7 @@ function createDynamicListComponent(deps) {
|
|
|
804
2313
|
}
|
|
805
2314
|
);
|
|
806
2315
|
}
|
|
807
|
-
return /* @__PURE__ */
|
|
2316
|
+
return /* @__PURE__ */ jsx9(
|
|
808
2317
|
deps.DataGrid,
|
|
809
2318
|
{
|
|
810
2319
|
title: query.data?.title ?? "Dynamic List",
|
|
@@ -820,20 +2329,20 @@ function createDynamicListComponent(deps) {
|
|
|
820
2329
|
}
|
|
821
2330
|
|
|
822
2331
|
// src/components/DynamicView.tsx
|
|
823
|
-
import { useMemo as
|
|
824
|
-
import { jsx as
|
|
2332
|
+
import { useMemo as useMemo6, useState as useState3 } from "react";
|
|
2333
|
+
import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
825
2334
|
function createDynamicViewComponent(deps) {
|
|
826
2335
|
return function DynamicView({ viewId }) {
|
|
827
|
-
const [editing, setEditing] =
|
|
828
|
-
const [isDialogOpen, setDialogOpen] =
|
|
829
|
-
const [pendingDelete, setPendingDelete] =
|
|
2336
|
+
const [editing, setEditing] = useState3(null);
|
|
2337
|
+
const [isDialogOpen, setDialogOpen] = useState3(false);
|
|
2338
|
+
const [pendingDelete, setPendingDelete] = useState3(null);
|
|
830
2339
|
const viewQuery = deps.hooks.useRuntimeBuilderView(viewId);
|
|
831
2340
|
const state = deps.useDataTableState({ pageSize: 20 });
|
|
832
2341
|
const entriesQuery = deps.hooks.useBuilderViewEntries(viewId, state.query);
|
|
833
2342
|
const save = deps.hooks.useSaveBuilderViewEntry(viewId);
|
|
834
2343
|
const remove = deps.hooks.useDeleteBuilderViewEntry(viewId);
|
|
835
2344
|
const view = viewQuery.data;
|
|
836
|
-
const columns =
|
|
2345
|
+
const columns = useMemo6(
|
|
837
2346
|
() => view ? deps.buildColumns(view, {
|
|
838
2347
|
onEdit: (entry) => {
|
|
839
2348
|
setEditing(entry);
|
|
@@ -851,7 +2360,7 @@ function createDynamicViewComponent(deps) {
|
|
|
851
2360
|
getRowId: (row) => row.id
|
|
852
2361
|
});
|
|
853
2362
|
if (viewQuery.isError) {
|
|
854
|
-
return /* @__PURE__ */
|
|
2363
|
+
return /* @__PURE__ */ jsx10(
|
|
855
2364
|
deps.ErrorState,
|
|
856
2365
|
{
|
|
857
2366
|
title: "View \u043D\u044D\u044D\u0433\u0434\u0441\u044D\u043D\u0433\u04AF\u0439",
|
|
@@ -859,8 +2368,8 @@ function createDynamicViewComponent(deps) {
|
|
|
859
2368
|
}
|
|
860
2369
|
);
|
|
861
2370
|
}
|
|
862
|
-
return /* @__PURE__ */
|
|
863
|
-
/* @__PURE__ */
|
|
2371
|
+
return /* @__PURE__ */ jsxs7("div", { className: "space-y-6", children: [
|
|
2372
|
+
/* @__PURE__ */ jsx10(
|
|
864
2373
|
deps.DataGrid,
|
|
865
2374
|
{
|
|
866
2375
|
title: view?.title ?? "Dynamic View",
|
|
@@ -874,7 +2383,7 @@ function createDynamicViewComponent(deps) {
|
|
|
874
2383
|
setEditing(entry);
|
|
875
2384
|
setDialogOpen(true);
|
|
876
2385
|
},
|
|
877
|
-
toolbarExtra: /* @__PURE__ */
|
|
2386
|
+
toolbarExtra: /* @__PURE__ */ jsx10(
|
|
878
2387
|
deps.AddButton,
|
|
879
2388
|
{
|
|
880
2389
|
disabled: !view?.form,
|
|
@@ -886,7 +2395,7 @@ function createDynamicViewComponent(deps) {
|
|
|
886
2395
|
)
|
|
887
2396
|
}
|
|
888
2397
|
),
|
|
889
|
-
view ? /* @__PURE__ */
|
|
2398
|
+
view ? /* @__PURE__ */ jsx10(
|
|
890
2399
|
deps.EntryDialog,
|
|
891
2400
|
{
|
|
892
2401
|
open: isDialogOpen,
|
|
@@ -897,7 +2406,7 @@ function createDynamicViewComponent(deps) {
|
|
|
897
2406
|
isSaving: save.isPending
|
|
898
2407
|
}
|
|
899
2408
|
) : null,
|
|
900
|
-
/* @__PURE__ */
|
|
2409
|
+
/* @__PURE__ */ jsx10(
|
|
901
2410
|
deps.DeleteDialog,
|
|
902
2411
|
{
|
|
903
2412
|
entry: pendingDelete,
|
|
@@ -915,9 +2424,9 @@ function createDynamicViewComponent(deps) {
|
|
|
915
2424
|
}
|
|
916
2425
|
|
|
917
2426
|
// src/components/RuntimeEntryDialog.tsx
|
|
918
|
-
import { useEffect as
|
|
919
|
-
import { FormProvider as FormProvider4, useForm as
|
|
920
|
-
import { jsx as
|
|
2427
|
+
import { useEffect as useEffect4, useMemo as useMemo7, useState as useState4 } from "react";
|
|
2428
|
+
import { FormProvider as FormProvider4, useForm as useForm5 } from "react-hook-form";
|
|
2429
|
+
import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
921
2430
|
function isDbTableSource(source) {
|
|
922
2431
|
return source?.type === "dbTable" && "tableName" in source;
|
|
923
2432
|
}
|
|
@@ -950,19 +2459,19 @@ function createRuntimeEntryDialogComponent(deps) {
|
|
|
950
2459
|
onSave,
|
|
951
2460
|
isSaving
|
|
952
2461
|
}) {
|
|
953
|
-
const [draftSubforms, setDraftSubforms] =
|
|
2462
|
+
const [draftSubforms, setDraftSubforms] = useState4({});
|
|
954
2463
|
const compositeCreate = deps.useCreateCompositeEntry?.(view.id);
|
|
955
2464
|
const compositeUpdate = deps.useUpdateCompositeEntry?.(view.id);
|
|
956
|
-
const form =
|
|
2465
|
+
const form = useForm5({
|
|
957
2466
|
defaultValues: createBuilderEntryDefaultValues(view, editing),
|
|
958
2467
|
values: open ? createBuilderEntryDefaultValues(view, editing) : void 0
|
|
959
2468
|
});
|
|
960
2469
|
const mainTableName = runtimeViewTableName(view);
|
|
961
|
-
const hasDraftRows =
|
|
2470
|
+
const hasDraftRows = useMemo7(
|
|
962
2471
|
() => Object.values(draftSubforms).some((draft) => draft.rows.length > 0),
|
|
963
2472
|
[draftSubforms]
|
|
964
2473
|
);
|
|
965
|
-
|
|
2474
|
+
useEffect4(() => {
|
|
966
2475
|
if (open) setDraftSubforms({});
|
|
967
2476
|
}, [open]);
|
|
968
2477
|
const onSubmit = form.handleSubmit(async (values) => {
|
|
@@ -1014,7 +2523,7 @@ function createRuntimeEntryDialogComponent(deps) {
|
|
|
1014
2523
|
const saving = isSaving || Boolean(compositeCreate?.isPending || compositeUpdate?.isPending);
|
|
1015
2524
|
const extraItems = deps.SubformField && view.form?.schema.subforms?.length ? view.form.schema.subforms.map((subform) => ({
|
|
1016
2525
|
key: subform.key,
|
|
1017
|
-
render: () => deps.SubformField ? /* @__PURE__ */
|
|
2526
|
+
render: () => deps.SubformField ? /* @__PURE__ */ jsx11(
|
|
1018
2527
|
deps.SubformField,
|
|
1019
2528
|
{
|
|
1020
2529
|
subform,
|
|
@@ -1029,15 +2538,15 @@ function createRuntimeEntryDialogComponent(deps) {
|
|
|
1029
2538
|
}
|
|
1030
2539
|
) : null
|
|
1031
2540
|
})) : void 0;
|
|
1032
|
-
return /* @__PURE__ */
|
|
2541
|
+
return /* @__PURE__ */ jsx11(
|
|
1033
2542
|
deps.DialogShell,
|
|
1034
2543
|
{
|
|
1035
2544
|
open,
|
|
1036
2545
|
title: editing ? "\u041C\u04E9\u0440 \u0437\u0430\u0441\u0430\u0445" : "\u041C\u04E9\u0440 \u043D\u044D\u043C\u044D\u0445",
|
|
1037
2546
|
description: view.title,
|
|
1038
2547
|
onClose,
|
|
1039
|
-
children: /* @__PURE__ */
|
|
1040
|
-
view.form ? /* @__PURE__ */
|
|
2548
|
+
children: /* @__PURE__ */ jsx11(FormProvider4, { ...form, children: /* @__PURE__ */ jsxs8("form", { onSubmit, noValidate: true, className: deps.formClassName, children: [
|
|
2549
|
+
view.form ? /* @__PURE__ */ jsx11(
|
|
1041
2550
|
deps.FormFields,
|
|
1042
2551
|
{
|
|
1043
2552
|
formId: view.form.id,
|
|
@@ -1048,7 +2557,7 @@ function createRuntimeEntryDialogComponent(deps) {
|
|
|
1048
2557
|
extraItems
|
|
1049
2558
|
}
|
|
1050
2559
|
) : null,
|
|
1051
|
-
/* @__PURE__ */
|
|
2560
|
+
/* @__PURE__ */ jsx11(deps.Actions, { isSaving: saving, onClose })
|
|
1052
2561
|
] }) })
|
|
1053
2562
|
}
|
|
1054
2563
|
);
|
|
@@ -1056,9 +2565,9 @@ function createRuntimeEntryDialogComponent(deps) {
|
|
|
1056
2565
|
}
|
|
1057
2566
|
|
|
1058
2567
|
// src/components/RuntimeSubformField.tsx
|
|
1059
|
-
import { useEffect as
|
|
1060
|
-
import { FormProvider as FormProvider5, useForm as
|
|
1061
|
-
import { jsx as
|
|
2568
|
+
import { useEffect as useEffect5, useMemo as useMemo8, useRef, useState as useState5 } from "react";
|
|
2569
|
+
import { FormProvider as FormProvider5, useForm as useForm6 } from "react-hook-form";
|
|
2570
|
+
import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1062
2571
|
|
|
1063
2572
|
// src/hooks/createBuilderHooks.ts
|
|
1064
2573
|
import { keepPreviousData, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
@@ -1075,6 +2584,7 @@ function createBuilderKeys() {
|
|
|
1075
2584
|
listOptions: () => [...builderKeys.lists, "options"],
|
|
1076
2585
|
views: ["builder", "views"],
|
|
1077
2586
|
viewList: (query) => [...builderKeys.views, "list", query],
|
|
2587
|
+
view: (id) => [...builderKeys.views, "detail", id],
|
|
1078
2588
|
runtimeForm: (id) => ["builder", "runtime", "form", id],
|
|
1079
2589
|
runtimeFieldOptions: (formId, fieldKey, query) => [...builderKeys.runtimeForm(formId), "fields", fieldKey, "options", query],
|
|
1080
2590
|
runtimeFormEntries: (id) => [...builderKeys.runtimeForm(id), "entries"],
|
|
@@ -1193,6 +2703,13 @@ function createBuilderHooks(client) {
|
|
|
1193
2703
|
placeholderData: keepPreviousData
|
|
1194
2704
|
});
|
|
1195
2705
|
}
|
|
2706
|
+
function useBuilderView(id) {
|
|
2707
|
+
return useQuery({
|
|
2708
|
+
queryKey: builderKeys.view(id ?? ""),
|
|
2709
|
+
queryFn: () => client.getBuilderView(id ?? ""),
|
|
2710
|
+
enabled: Boolean(id)
|
|
2711
|
+
});
|
|
2712
|
+
}
|
|
1196
2713
|
function useSaveBuilderView() {
|
|
1197
2714
|
const queryClient = useQueryClient();
|
|
1198
2715
|
return useMutation({
|
|
@@ -1333,6 +2850,7 @@ function createBuilderHooks(client) {
|
|
|
1333
2850
|
useBuilderListOptions,
|
|
1334
2851
|
useBuilderLists,
|
|
1335
2852
|
useBuilderViewEntries,
|
|
2853
|
+
useBuilderView,
|
|
1336
2854
|
useBuilderViews,
|
|
1337
2855
|
useDeleteBuilderForm,
|
|
1338
2856
|
useDeleteBuilderList,
|
|
@@ -1357,10 +2875,47 @@ function createBuilderHooks(client) {
|
|
|
1357
2875
|
};
|
|
1358
2876
|
}
|
|
1359
2877
|
|
|
2878
|
+
// src/integration/createBuilderIntegration.ts
|
|
2879
|
+
function normalizeBasePath(path) {
|
|
2880
|
+
const trimmed = path.trim().replace(/\/+$/g, "");
|
|
2881
|
+
if (!trimmed) return "/builder";
|
|
2882
|
+
return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
2883
|
+
}
|
|
2884
|
+
function withQuery(path, query) {
|
|
2885
|
+
const params = new URLSearchParams();
|
|
2886
|
+
for (const [key, value] of Object.entries(query)) {
|
|
2887
|
+
if (value) params.set(key, value);
|
|
2888
|
+
}
|
|
2889
|
+
const queryString = params.toString();
|
|
2890
|
+
return queryString ? `${path}?${queryString}` : path;
|
|
2891
|
+
}
|
|
2892
|
+
function createBuilderIntegration(config) {
|
|
2893
|
+
const adminBasePath = normalizeBasePath(config.adminBasePath ?? "/admin/dev/builder");
|
|
2894
|
+
const api = createBuilderApiClient(config.transport);
|
|
2895
|
+
const hooks = createBuilderHooks(api);
|
|
2896
|
+
const formsPath = `${adminBasePath}/forms`;
|
|
2897
|
+
const listsPath = `${adminBasePath}/lists`;
|
|
2898
|
+
return {
|
|
2899
|
+
api,
|
|
2900
|
+
hooks,
|
|
2901
|
+
routes: {
|
|
2902
|
+
adminBasePath,
|
|
2903
|
+
adminHomePath: adminBasePath,
|
|
2904
|
+
formsPath,
|
|
2905
|
+
newFormPath: `${formsPath}/new`,
|
|
2906
|
+
editFormPath: (id) => withQuery(`${formsPath}/edit`, { id }),
|
|
2907
|
+
listsPath,
|
|
2908
|
+
newListPath: `${listsPath}/new`,
|
|
2909
|
+
editListPath: (id) => withQuery(`${listsPath}/edit`, { id }),
|
|
2910
|
+
viewsPath: `${adminBasePath}/views`
|
|
2911
|
+
}
|
|
2912
|
+
};
|
|
2913
|
+
}
|
|
2914
|
+
|
|
1360
2915
|
// src/index.ts
|
|
1361
2916
|
var builderUiPackage = {
|
|
1362
2917
|
name: "@duke333/builder-ui",
|
|
1363
|
-
version: "0.1.
|
|
2918
|
+
version: "0.1.1"
|
|
1364
2919
|
};
|
|
1365
2920
|
export {
|
|
1366
2921
|
BUILDER_EDITOR_NONE_VALUE,
|
|
@@ -1371,19 +2926,27 @@ export {
|
|
|
1371
2926
|
builderFormEditorFieldsFromTable,
|
|
1372
2927
|
builderFormEditorInputFromValues,
|
|
1373
2928
|
builderFormEditorValuesFromEntity,
|
|
2929
|
+
builderFormLayoutDragDataType,
|
|
1374
2930
|
builderListEditorColumnsFromTable,
|
|
1375
2931
|
builderListEditorInputFromValues,
|
|
1376
2932
|
builderListEditorValuesFromEntity,
|
|
1377
2933
|
builderUiPackage,
|
|
1378
2934
|
builderViewEditorInputFromValues,
|
|
1379
2935
|
builderViewEditorValuesFromEntity,
|
|
2936
|
+
clampBuilderFormLayoutSpan,
|
|
2937
|
+
createBuilderAdminPages,
|
|
1380
2938
|
createBuilderApiClient,
|
|
2939
|
+
createBuilderDefaultEntityManagerComponent,
|
|
2940
|
+
createBuilderDefaultFormEditorBody,
|
|
2941
|
+
createBuilderDefaultListEditorBody,
|
|
2942
|
+
createBuilderDefaultViewEditorPage,
|
|
1381
2943
|
createBuilderEntityDialogManagerComponent,
|
|
1382
2944
|
createBuilderEntityManagerComponent,
|
|
1383
2945
|
createBuilderEntryDefaultValues,
|
|
1384
2946
|
createBuilderFormDefaultValues,
|
|
1385
2947
|
createBuilderFormEditorPageComponent,
|
|
1386
2948
|
createBuilderHooks,
|
|
2949
|
+
createBuilderIntegration,
|
|
1387
2950
|
createBuilderKeys,
|
|
1388
2951
|
createBuilderListEditorPageComponent,
|
|
1389
2952
|
createBuilderViewDialogComponent,
|
|
@@ -1392,6 +2955,11 @@ export {
|
|
|
1392
2955
|
createDynamicViewComponent,
|
|
1393
2956
|
createRuntimeEntryDialogComponent,
|
|
1394
2957
|
formatBuilderRuntimeValue,
|
|
1395
|
-
getBuilderEditorTriggerRoute
|
|
2958
|
+
getBuilderEditorTriggerRoute,
|
|
2959
|
+
nextBuilderFormLayoutGroupId,
|
|
2960
|
+
parseBuilderFormLayoutDragPayload,
|
|
2961
|
+
serializeBuilderFormLayoutDragPayload,
|
|
2962
|
+
swapBuilderFormLayoutItems,
|
|
2963
|
+
useBuilderFormLayoutEditor
|
|
1396
2964
|
};
|
|
1397
2965
|
//# sourceMappingURL=index.js.map
|