@oondemand/oon-core-front 0.3.12 → 0.3.15
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/dist/index.d.ts +19 -2
- package/dist/index.js +141 -50
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -246,6 +246,7 @@ interface OonColumnDef {
|
|
|
246
246
|
permissions?: string[];
|
|
247
247
|
capabilities?: string[];
|
|
248
248
|
}
|
|
249
|
+
type OonFormFieldWidget = "default" | "checkbox";
|
|
249
250
|
interface OonFormFieldDef {
|
|
250
251
|
field: string;
|
|
251
252
|
label?: string;
|
|
@@ -255,6 +256,19 @@ interface OonFormFieldDef {
|
|
|
255
256
|
/** model relacionada quando kind === "ref". */
|
|
256
257
|
ref?: string;
|
|
257
258
|
renderer?: string;
|
|
259
|
+
/** Controle visual pontual sem substituir a página/formulário inteiro. */
|
|
260
|
+
widget?: OonFormFieldWidget;
|
|
261
|
+
/** Valor persistido quando um checkbox está marcado. Default: true. */
|
|
262
|
+
checkedValue?: string | number | boolean;
|
|
263
|
+
/** Valor persistido quando um checkbox está desmarcado. Default: false. */
|
|
264
|
+
uncheckedValue?: string | number | boolean;
|
|
265
|
+
/** Agrupa campos relacionados em um bloco visual comum. */
|
|
266
|
+
group?: string;
|
|
267
|
+
/** Rótulo exibido uma vez acima do grupo. Default: group. */
|
|
268
|
+
groupLabel?: string;
|
|
269
|
+
groupDescription?: string;
|
|
270
|
+
/** Exibe controles do mesmo grupo na mesma linha quando houver espaço. */
|
|
271
|
+
inline?: boolean;
|
|
258
272
|
permissions?: string[];
|
|
259
273
|
capabilities?: string[];
|
|
260
274
|
}
|
|
@@ -412,7 +426,7 @@ interface CollectionViewDef {
|
|
|
412
426
|
mode?: CollectionMode;
|
|
413
427
|
/** modo "full": colunas explícitas. */
|
|
414
428
|
columns?: OonColumnDef[];
|
|
415
|
-
/**
|
|
429
|
+
/** Campos explícitos ou overrides pontuais sobre a metadata do model. */
|
|
416
430
|
form?: OonFormFieldDef[];
|
|
417
431
|
importExport?: boolean;
|
|
418
432
|
renderer?: string;
|
|
@@ -583,6 +597,8 @@ interface CentralUiManifest {
|
|
|
583
597
|
path?: string;
|
|
584
598
|
label?: string;
|
|
585
599
|
section?: string;
|
|
600
|
+
/** Overrides pontuais de campos; os demais continuam vindo da metadata. */
|
|
601
|
+
form?: OonFormFieldDef[];
|
|
586
602
|
list?: OonCollectionListConfig;
|
|
587
603
|
relations?: Record<string, OonRelationDef>;
|
|
588
604
|
detailModal?: OonDetailModalConfig;
|
|
@@ -658,8 +674,9 @@ interface CoreCollectionProps {
|
|
|
658
674
|
list?: OonCollectionListConfig;
|
|
659
675
|
relations?: Record<string, OonRelationDef>;
|
|
660
676
|
detailModal?: OonDetailModalConfig;
|
|
677
|
+
cellRenderers?: OonComponentRegistry["cellRenderers"];
|
|
661
678
|
}
|
|
662
|
-
declare function CoreCollection({ model, label, section, mode, endpoint, columns, form, importExport, list, relations, detailModal }: CoreCollectionProps): react.JSX.Element;
|
|
679
|
+
declare function CoreCollection({ model, label, section, mode, endpoint, columns, form, importExport, list, relations, detailModal, cellRenderers }: CoreCollectionProps): react.JSX.Element;
|
|
663
680
|
|
|
664
681
|
interface CoreDocumentProps {
|
|
665
682
|
model: string;
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { StrictMode } from "react";
|
|
|
3
3
|
import { createRoot } from "react-dom/client";
|
|
4
4
|
|
|
5
5
|
// src/app/OonApp.tsx
|
|
6
|
-
import { useMemo as
|
|
6
|
+
import { useMemo as useMemo7 } from "react";
|
|
7
7
|
import { RouterProvider } from "react-router-dom";
|
|
8
8
|
|
|
9
9
|
// src/api/createRestClient.ts
|
|
@@ -787,6 +787,12 @@ function renderCell(value, kind) {
|
|
|
787
787
|
}
|
|
788
788
|
return formatted;
|
|
789
789
|
}
|
|
790
|
+
function renderColumnCell(row, column, cellRenderers) {
|
|
791
|
+
const value = row[column.field];
|
|
792
|
+
const Renderer = column.renderer ? cellRenderers?.[column.renderer] : void 0;
|
|
793
|
+
if (Renderer) return /* @__PURE__ */ jsx7(Renderer, { value, row, column });
|
|
794
|
+
return renderCell(value, column.kind);
|
|
795
|
+
}
|
|
790
796
|
function DataGrid({
|
|
791
797
|
resource,
|
|
792
798
|
resourceKey,
|
|
@@ -798,7 +804,8 @@ function DataGrid({
|
|
|
798
804
|
toolbarExtra,
|
|
799
805
|
filters = [],
|
|
800
806
|
queryExtra,
|
|
801
|
-
renderRowActions
|
|
807
|
+
renderRowActions,
|
|
808
|
+
cellRenderers
|
|
802
809
|
}) {
|
|
803
810
|
const [pageIndex, setPageIndex] = useState3(0);
|
|
804
811
|
const [pageSize, setPageSize] = useState3(20);
|
|
@@ -904,7 +911,7 @@ function DataGrid({
|
|
|
904
911
|
actionCount ? /* @__PURE__ */ jsx7(Table.ColumnHeader, { w: "84px", h: "39px", px: "10px", py: "8px", color: "#667085", borderBottomWidth: "1px", borderColor: "#D5DDE3", fontSize: "10px", fontWeight: "600", textAlign: "center", children: "A\xE7\xF5es" }) : null
|
|
905
912
|
] }) }),
|
|
906
913
|
/* @__PURE__ */ jsx7(Table.Body, { children: rows.length === 0 ? /* @__PURE__ */ jsx7(Table.Row, { children: /* @__PURE__ */ jsx7(Table.Cell, { colSpan: columns.length + actionCount, children: /* @__PURE__ */ jsx7(Text3, { minH: "140px", display: "grid", placeItems: "center", color: "#98A2B3", fontSize: "12px", children: "Nenhum registro encontrado." }) }) }) : rows.map((row, index) => /* @__PURE__ */ jsxs3(Table.Row, { bg: index % 2 ? "#FBFCFD" : "white", _hover: { bg: "#F0F7FF" }, children: [
|
|
907
|
-
columns.map((column) => /* @__PURE__ */ jsx7(Table.Cell, { maxW: "250px", h: "42px", px: "10px", py: "8px", overflow: "hidden", color: "#52606D", borderBottomWidth: "1px", borderColor: "#EEF1F3", fontSize: "11px", textOverflow: "ellipsis", whiteSpace: "nowrap", children:
|
|
914
|
+
columns.map((column) => /* @__PURE__ */ jsx7(Table.Cell, { maxW: "250px", h: "42px", px: "10px", py: "8px", overflow: "hidden", color: "#52606D", borderBottomWidth: "1px", borderColor: "#EEF1F3", fontSize: "11px", textOverflow: "ellipsis", whiteSpace: "nowrap", children: renderColumnCell(row, column, cellRenderers) }, column.field)),
|
|
908
915
|
actionCount ? /* @__PURE__ */ jsx7(Table.Cell, { h: "42px", px: "10px", py: "5px", borderBottomWidth: "1px", borderColor: "#EEF1F3", textAlign: "center", children: /* @__PURE__ */ jsxs3(Flex2, { justify: "center", gap: "5px", children: [
|
|
909
916
|
onEdit ? /* @__PURE__ */ jsx7(Button2, { type: "button", "aria-label": "Editar", w: "31px", minW: "31px", h: "31px", p: 0, color: "#667085", bg: "white", borderWidth: "1px", borderColor: "#E5E9ED", borderRadius: "6px", onClick: () => onEdit(row), _hover: { color: "#036491", bg: "#F0F7FF", borderColor: "#B8D9EB" }, children: /* @__PURE__ */ jsx7(EditIcon, {}) }) : null,
|
|
910
917
|
onDelete ? /* @__PURE__ */ jsx7(Button2, { type: "button", "aria-label": "Excluir", w: "31px", minW: "31px", h: "31px", p: 0, color: "#667085", bg: "white", borderWidth: "1px", borderColor: "#E5E9ED", borderRadius: "6px", onClick: () => onDelete(row), _hover: { color: "#B42318", bg: "#FFF5F5", borderColor: "#FECACA" }, children: /* @__PURE__ */ jsx7(TrashIcon, {}) }) : null,
|
|
@@ -953,7 +960,7 @@ function DataGrid({
|
|
|
953
960
|
}
|
|
954
961
|
|
|
955
962
|
// src/components/internal/DynamicForm.tsx
|
|
956
|
-
import { useEffect as useEffect4, useState as useState5 } from "react";
|
|
963
|
+
import { useEffect as useEffect4, useMemo as useMemo4, useState as useState5 } from "react";
|
|
957
964
|
import { Box as Box4, Button as Button4, Flex as Flex4, Heading as Heading2, Input as Input3, NativeSelect as NativeSelect2, SimpleGrid, Stack as Stack2, Text as Text5, Textarea } from "@chakra-ui/react";
|
|
958
965
|
|
|
959
966
|
// src/components/internal/ReferenceSelect.tsx
|
|
@@ -1443,10 +1450,25 @@ var controlProps = (invalid) => ({
|
|
|
1443
1450
|
boxShadow: invalid ? "0 0 0 3px rgba(220,38,38,.08)" : void 0,
|
|
1444
1451
|
fontSize: "11px"
|
|
1445
1452
|
});
|
|
1453
|
+
function buildItems(fields) {
|
|
1454
|
+
const items = [];
|
|
1455
|
+
const renderedGroups = /* @__PURE__ */ new Set();
|
|
1456
|
+
fields.forEach((field) => {
|
|
1457
|
+
if (!field.group) {
|
|
1458
|
+
items.push({ type: "field", field });
|
|
1459
|
+
return;
|
|
1460
|
+
}
|
|
1461
|
+
if (renderedGroups.has(field.group)) return;
|
|
1462
|
+
renderedGroups.add(field.group);
|
|
1463
|
+
items.push({ type: "group", id: field.group, fields: fields.filter((candidate) => candidate.group === field.group) });
|
|
1464
|
+
});
|
|
1465
|
+
return items;
|
|
1466
|
+
}
|
|
1446
1467
|
function DynamicForm({ title, eyebrow = "Cadastro", fields, initialValues, submitting, error, onSubmit, onCancel, onFieldChange }) {
|
|
1447
1468
|
const [values, setValues] = useState5(() => Object.fromEntries(fields.map((field) => [field.field, toValue(initialValues?.[field.field], field.kind)])));
|
|
1448
1469
|
const [errors, setErrors] = useState5({});
|
|
1449
1470
|
const [dismissed, setDismissed] = useState5(false);
|
|
1471
|
+
const items = useMemo4(() => buildItems(fields), [fields]);
|
|
1450
1472
|
useEffect4(() => {
|
|
1451
1473
|
const listener = (event) => {
|
|
1452
1474
|
if (event.key !== "Escape" || event.defaultPrevented || submitting) return;
|
|
@@ -1496,6 +1518,83 @@ function DynamicForm({ title, eyebrow = "Cadastro", fields, initialValues, submi
|
|
|
1496
1518
|
setErrors({});
|
|
1497
1519
|
onSubmit(payload);
|
|
1498
1520
|
};
|
|
1521
|
+
const renderField = (field, grouped = false) => {
|
|
1522
|
+
const label = fieldLabel({ name: field.field, label: field.label });
|
|
1523
|
+
const message = errors[field.field];
|
|
1524
|
+
const id = idFor(field.field);
|
|
1525
|
+
const errorId = message ? errorIdFor(field.field) : void 0;
|
|
1526
|
+
const multiline = isMultiline(field);
|
|
1527
|
+
const span = field.span === 2 || multiline;
|
|
1528
|
+
const wrap = (control, showLabel = true) => /* @__PURE__ */ jsxs5(Box4, { minW: grouped ? "150px" : void 0, flex: grouped ? "0 1 auto" : void 0, gridColumn: !grouped && span ? "1 / -1" : void 0, children: [
|
|
1529
|
+
showLabel ? /* @__PURE__ */ jsx9(Label, { id, label, required: field.required }) : null,
|
|
1530
|
+
control,
|
|
1531
|
+
/* @__PURE__ */ jsx9(ErrorText, { id: errorId, text: message })
|
|
1532
|
+
] }, field.field);
|
|
1533
|
+
if (field.widget === "checkbox") {
|
|
1534
|
+
const checkedValue = String(field.checkedValue ?? true);
|
|
1535
|
+
const uncheckedValue = String(field.uncheckedValue ?? false);
|
|
1536
|
+
const checked = (values[field.field] ?? uncheckedValue) === checkedValue;
|
|
1537
|
+
return wrap(
|
|
1538
|
+
/* @__PURE__ */ jsxs5(
|
|
1539
|
+
Box4,
|
|
1540
|
+
{
|
|
1541
|
+
as: "label",
|
|
1542
|
+
display: "flex",
|
|
1543
|
+
minH: "37px",
|
|
1544
|
+
px: "11px",
|
|
1545
|
+
alignItems: "center",
|
|
1546
|
+
gap: "8px",
|
|
1547
|
+
color: "#344054",
|
|
1548
|
+
bg: checked ? "#F0F7FF" : "white",
|
|
1549
|
+
borderWidth: "1px",
|
|
1550
|
+
borderColor: message ? "#DC2626" : checked ? "#8FC9E7" : "#D5DDE3",
|
|
1551
|
+
borderRadius: "7px",
|
|
1552
|
+
cursor: "pointer",
|
|
1553
|
+
transition: "background .15s ease, border-color .15s ease",
|
|
1554
|
+
_hover: { borderColor: "#8FC9E7", bg: "#F7FBFE" },
|
|
1555
|
+
children: [
|
|
1556
|
+
/* @__PURE__ */ jsx9(
|
|
1557
|
+
"input",
|
|
1558
|
+
{
|
|
1559
|
+
id,
|
|
1560
|
+
type: "checkbox",
|
|
1561
|
+
checked,
|
|
1562
|
+
"aria-invalid": !!message,
|
|
1563
|
+
"aria-describedby": errorId,
|
|
1564
|
+
style: { width: 16, height: 16, accentColor: "#0474AF", cursor: "pointer" },
|
|
1565
|
+
onChange: (event) => change(field.field, event.currentTarget.checked ? checkedValue : uncheckedValue)
|
|
1566
|
+
}
|
|
1567
|
+
),
|
|
1568
|
+
/* @__PURE__ */ jsxs5(Text5, { as: "span", fontSize: "11px", fontWeight: "600", children: [
|
|
1569
|
+
label,
|
|
1570
|
+
field.required ? /* @__PURE__ */ jsx9(Text5, { as: "span", color: "#DC2626", children: " *" }) : null
|
|
1571
|
+
] })
|
|
1572
|
+
]
|
|
1573
|
+
}
|
|
1574
|
+
),
|
|
1575
|
+
false
|
|
1576
|
+
);
|
|
1577
|
+
}
|
|
1578
|
+
if (field.kind === "ref" && field.ref) return wrap(/* @__PURE__ */ jsx9(ReferenceSelect, { field: field.field, inputId: id, errorId, label, refModel: field.ref, value: values[field.field] ?? "", initialValue: initialValues?.[field.field], required: field.required, invalid: !!message, error: message, onChange: (value) => change(field.field, value) }));
|
|
1579
|
+
if (field.kind === "enum" && field.options?.length) return wrap(/* @__PURE__ */ jsxs5(NativeSelect2.Root, { size: "sm", children: [
|
|
1580
|
+
/* @__PURE__ */ jsxs5(NativeSelect2.Field, { id, "aria-invalid": !!message, "aria-describedby": errorId, value: values[field.field] ?? "", ...controlProps(!!message), onChange: (event) => change(field.field, event.currentTarget.value), children: [
|
|
1581
|
+
/* @__PURE__ */ jsx9("option", { value: "", children: "\u2014 Selecione \u2014" }),
|
|
1582
|
+
field.options.map((option) => /* @__PURE__ */ jsx9("option", { value: option, children: option }, option))
|
|
1583
|
+
] }),
|
|
1584
|
+
/* @__PURE__ */ jsx9(NativeSelect2.Indicator, {})
|
|
1585
|
+
] }));
|
|
1586
|
+
if (field.kind === "boolean") return wrap(/* @__PURE__ */ jsxs5(NativeSelect2.Root, { size: "sm", children: [
|
|
1587
|
+
/* @__PURE__ */ jsxs5(NativeSelect2.Field, { id, "aria-invalid": !!message, "aria-describedby": errorId, value: values[field.field] ?? "", ...controlProps(!!message), onChange: (event) => change(field.field, event.currentTarget.value), children: [
|
|
1588
|
+
/* @__PURE__ */ jsx9("option", { value: "", children: "\u2014 Selecione \u2014" }),
|
|
1589
|
+
/* @__PURE__ */ jsx9("option", { value: "true", children: "Sim" }),
|
|
1590
|
+
/* @__PURE__ */ jsx9("option", { value: "false", children: "N\xE3o" })
|
|
1591
|
+
] }),
|
|
1592
|
+
/* @__PURE__ */ jsx9(NativeSelect2.Indicator, {})
|
|
1593
|
+
] }));
|
|
1594
|
+
if (multiline) return wrap(/* @__PURE__ */ jsx9(Textarea, { id, rows: field.rows ?? 4, resize: "vertical", "aria-invalid": !!message, "aria-describedby": errorId, value: values[field.field] ?? "", ...controlProps(!!message), lineHeight: "1.5", onChange: (event) => change(field.field, event.currentTarget.value) }));
|
|
1595
|
+
const type = field.kind === "date" ? "date" : ["number", "currency", "currencyConverted"].includes(field.kind ?? "") ? "number" : "text";
|
|
1596
|
+
return wrap(/* @__PURE__ */ jsx9(Input3, { id, type, step: type === "number" ? "any" : void 0, autoComplete: "off", "aria-invalid": !!message, "aria-describedby": errorId, value: values[field.field] ?? "", ...controlProps(!!message), onChange: (event) => change(field.field, event.currentTarget.value) }));
|
|
1597
|
+
};
|
|
1499
1598
|
const invalid = fields.filter((field) => errors[field.field]);
|
|
1500
1599
|
const generic = dismissed ? null : messageOf(error);
|
|
1501
1600
|
return /* @__PURE__ */ jsx9(Flex4, { position: "fixed", inset: 0, zIndex: 1e3, align: "center", justify: "center", p: { base: 2, md: 6 }, bg: "rgba(15,23,42,.48)", backdropFilter: "blur(2px)", onMouseDown: (event) => {
|
|
@@ -1525,38 +1624,15 @@ function DynamicForm({ title, eyebrow = "Cadastro", fields, initialValues, submi
|
|
|
1525
1624
|
/* @__PURE__ */ jsx9(AlertIcon, {}),
|
|
1526
1625
|
generic
|
|
1527
1626
|
] }) : null,
|
|
1528
|
-
/* @__PURE__ */ jsx9(SimpleGrid, { columns: { base: 1, lg: 2 }, gapX: "16px", gapY: "15px", children:
|
|
1529
|
-
|
|
1530
|
-
const
|
|
1531
|
-
const
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
/* @__PURE__ */ jsx9(Label, { id, label, required: field.required }),
|
|
1538
|
-
control,
|
|
1539
|
-
/* @__PURE__ */ jsx9(ErrorText, { id: errorId, text: message })
|
|
1540
|
-
] }, field.field);
|
|
1541
|
-
if (field.kind === "ref" && field.ref) return wrap(/* @__PURE__ */ jsx9(ReferenceSelect, { field: field.field, inputId: id, errorId, label, refModel: field.ref, value: values[field.field] ?? "", initialValue: initialValues?.[field.field], required: field.required, invalid: !!message, error: message, onChange: (value) => change(field.field, value) }));
|
|
1542
|
-
if (field.kind === "enum" && field.options?.length) return wrap(/* @__PURE__ */ jsxs5(NativeSelect2.Root, { size: "sm", children: [
|
|
1543
|
-
/* @__PURE__ */ jsxs5(NativeSelect2.Field, { id, "aria-invalid": !!message, "aria-describedby": errorId, value: values[field.field] ?? "", ...controlProps(!!message), onChange: (event) => change(field.field, event.currentTarget.value), children: [
|
|
1544
|
-
/* @__PURE__ */ jsx9("option", { value: "", children: "\u2014 Selecione \u2014" }),
|
|
1545
|
-
field.options.map((option) => /* @__PURE__ */ jsx9("option", { value: option, children: option }, option))
|
|
1546
|
-
] }),
|
|
1547
|
-
/* @__PURE__ */ jsx9(NativeSelect2.Indicator, {})
|
|
1548
|
-
] }));
|
|
1549
|
-
if (field.kind === "boolean") return wrap(/* @__PURE__ */ jsxs5(NativeSelect2.Root, { size: "sm", children: [
|
|
1550
|
-
/* @__PURE__ */ jsxs5(NativeSelect2.Field, { id, "aria-invalid": !!message, "aria-describedby": errorId, value: values[field.field] ?? "", ...controlProps(!!message), onChange: (event) => change(field.field, event.currentTarget.value), children: [
|
|
1551
|
-
/* @__PURE__ */ jsx9("option", { value: "", children: "\u2014 Selecione \u2014" }),
|
|
1552
|
-
/* @__PURE__ */ jsx9("option", { value: "true", children: "Sim" }),
|
|
1553
|
-
/* @__PURE__ */ jsx9("option", { value: "false", children: "N\xE3o" })
|
|
1554
|
-
] }),
|
|
1555
|
-
/* @__PURE__ */ jsx9(NativeSelect2.Indicator, {})
|
|
1556
|
-
] }));
|
|
1557
|
-
if (multiline) return wrap(/* @__PURE__ */ jsx9(Textarea, { id, rows: field.rows ?? 4, resize: "vertical", "aria-invalid": !!message, "aria-describedby": errorId, value: values[field.field] ?? "", ...controlProps(!!message), lineHeight: "1.5", onChange: (event) => change(field.field, event.currentTarget.value) }));
|
|
1558
|
-
const type = field.kind === "date" ? "date" : ["number", "currency", "currencyConverted"].includes(field.kind ?? "") ? "number" : "text";
|
|
1559
|
-
return wrap(/* @__PURE__ */ jsx9(Input3, { id, type, step: type === "number" ? "any" : void 0, autoComplete: "off", "aria-invalid": !!message, "aria-describedby": errorId, value: values[field.field] ?? "", ...controlProps(!!message), onChange: (event) => change(field.field, event.currentTarget.value) }));
|
|
1627
|
+
/* @__PURE__ */ jsx9(SimpleGrid, { columns: { base: 1, lg: 2 }, gapX: "16px", gapY: "15px", children: items.map((item) => {
|
|
1628
|
+
if (item.type === "field") return renderField(item.field);
|
|
1629
|
+
const first = item.fields[0];
|
|
1630
|
+
const inline = item.fields.some((field) => field.inline !== false);
|
|
1631
|
+
return /* @__PURE__ */ jsxs5(Box4, { gridColumn: "1 / -1", p: "12px", bg: "#FAFCFD", borderWidth: "1px", borderColor: "#E5E9ED", borderRadius: "9px", children: [
|
|
1632
|
+
/* @__PURE__ */ jsx9(Text5, { color: "#344054", fontSize: "11px", fontWeight: "700", children: first.groupLabel ?? item.id }),
|
|
1633
|
+
first.groupDescription ? /* @__PURE__ */ jsx9(Text5, { mt: "2px", mb: "10px", color: "#667085", fontSize: "10px", children: first.groupDescription }) : /* @__PURE__ */ jsx9(Box4, { h: "8px" }),
|
|
1634
|
+
/* @__PURE__ */ jsx9(Flex4, { direction: inline ? "row" : "column", wrap: "wrap", gap: "9px", children: item.fields.map((field) => renderField(field, true)) })
|
|
1635
|
+
] }, item.id);
|
|
1560
1636
|
}) })
|
|
1561
1637
|
] }) }),
|
|
1562
1638
|
/* @__PURE__ */ jsxs5(Flex4, { minH: "68px", px: "20px", py: "14px", justify: "flex-end", gap: "9px", borderTopWidth: "1px", borderColor: "#E5E9ED", children: [
|
|
@@ -1571,7 +1647,7 @@ function DynamicForm({ title, eyebrow = "Cadastro", fields, initialValues, submi
|
|
|
1571
1647
|
}
|
|
1572
1648
|
|
|
1573
1649
|
// src/components/internal/CoreDetailModal.tsx
|
|
1574
|
-
import { useEffect as useEffect6, useMemo as
|
|
1650
|
+
import { useEffect as useEffect6, useMemo as useMemo6, useState as useState9 } from "react";
|
|
1575
1651
|
import { Box as Box8, Button as Button8, Flex as Flex7, Heading as Heading3, Text as Text10 } from "@chakra-ui/react";
|
|
1576
1652
|
import { useQuery as useQuery6, useQueryClient as useQueryClient2 } from "@tanstack/react-query";
|
|
1577
1653
|
|
|
@@ -1632,7 +1708,7 @@ function CoreSummaryCards({ cards = [], parent, relations }) {
|
|
|
1632
1708
|
}
|
|
1633
1709
|
|
|
1634
1710
|
// src/components/internal/CoreRelatedGrid.tsx
|
|
1635
|
-
import { useMemo as
|
|
1711
|
+
import { useMemo as useMemo5, useState as useState7 } from "react";
|
|
1636
1712
|
import { Badge as Badge3, Box as Box6, Button as Button6, Flex as Flex5, Table as Table2, Text as Text8 } from "@chakra-ui/react";
|
|
1637
1713
|
import { useMutation, useQuery as useQuery5, useQueryClient } from "@tanstack/react-query";
|
|
1638
1714
|
|
|
@@ -1748,7 +1824,7 @@ function CoreRelatedGrid({ tab, parent, relations, refreshToken, onRefresh }) {
|
|
|
1748
1824
|
const parentValue = relation ? parent[relation.parentKey ?? "_id"] : void 0;
|
|
1749
1825
|
const key = ["oon", "related", relation?.model, relation?.foreignKey, parentValue, refreshToken];
|
|
1750
1826
|
const query = useQuery5({ queryKey: key, enabled: !!relation && parentValue != null, queryFn: () => resource.list({ [relation.foreignKey]: parentValue, pageSize: 1e3 }) });
|
|
1751
|
-
const columns =
|
|
1827
|
+
const columns = useMemo5(() => (tab.columns?.length ? tab.columns : schema?.fields.slice(0, 8).map((f) => f.name) ?? []).map((column) => normalizeColumn(column, schema)).filter((column) => !column.hidden), [tab.columns, schema]);
|
|
1752
1828
|
const [drafts, setDrafts] = useState7({});
|
|
1753
1829
|
const [errors, setErrors] = useState7({});
|
|
1754
1830
|
const editable = tab.type === "relatedGrid" && tab.editable && tab.editMode === "inline";
|
|
@@ -1876,7 +1952,7 @@ function CoreDetailModal({ model, title, config, recordId, initialRecord, initia
|
|
|
1876
1952
|
useEffect6(() => {
|
|
1877
1953
|
if (parentQuery.data) setParent(parentQuery.data);
|
|
1878
1954
|
}, [parentQuery.data]);
|
|
1879
|
-
const formFields =
|
|
1955
|
+
const formFields = useMemo6(() => schema ? formFieldsFromMeta(schema.fields) : [], [schema]);
|
|
1880
1956
|
const refresh = (targets) => {
|
|
1881
1957
|
const list = targets?.length ? targets : ["self"];
|
|
1882
1958
|
if (list.includes("parent") || list.includes("all")) {
|
|
@@ -1912,13 +1988,24 @@ function CoreDetailModal({ model, title, config, recordId, initialRecord, initia
|
|
|
1912
1988
|
|
|
1913
1989
|
// src/components/CoreCollection.tsx
|
|
1914
1990
|
import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1915
|
-
function
|
|
1991
|
+
function mergeFormFields(metadataFields, overrides) {
|
|
1992
|
+
if (!overrides?.length) return metadataFields;
|
|
1993
|
+
const byField = new Map(overrides.map((field) => [field.field, field]));
|
|
1994
|
+
const merged = metadataFields.map((field) => ({ ...field, ...byField.get(field.field) }));
|
|
1995
|
+
const known = new Set(metadataFields.map((field) => field.field));
|
|
1996
|
+
overrides.forEach((field) => {
|
|
1997
|
+
if (!known.has(field.field)) merged.push(field);
|
|
1998
|
+
});
|
|
1999
|
+
return merged;
|
|
2000
|
+
}
|
|
2001
|
+
function CoreCollection({ model, label, section = "Cole\xE7\xE3o", mode = "dynamic", endpoint, columns, form, importExport, list, relations, detailModal, cellRenderers }) {
|
|
1916
2002
|
const needsSchema = mode !== "full" || !columns || !form || !endpoint;
|
|
1917
2003
|
const schemaQuery = useModelSchema(needsSchema ? model : "");
|
|
1918
2004
|
const schema = schemaQuery.data;
|
|
1919
2005
|
const basePath = endpoint ?? schema?.basePath ?? `/${model.toLowerCase()}s`;
|
|
1920
2006
|
const resolvedColumns = (list?.columns?.length ? list.columns.map((column) => normalizeColumn(column, schema)) : columns) ?? (schema ? columnsFromMeta(schema.fields) : []);
|
|
1921
|
-
const
|
|
2007
|
+
const metadataForm = schema ? formFieldsFromMeta(schema.fields) : [];
|
|
2008
|
+
const resolvedForm = mode === "full" && form?.length ? form : mergeFormFields(metadataForm, form);
|
|
1922
2009
|
const resource = useOonResource(basePath);
|
|
1923
2010
|
const queryClient = useQueryClient3();
|
|
1924
2011
|
const [formState, setFormState] = useState10({ open: false });
|
|
@@ -1958,6 +2045,7 @@ function CoreCollection({ model, label, section = "Cole\xE7\xE3o", mode = "dynam
|
|
|
1958
2045
|
resourceKey: basePath,
|
|
1959
2046
|
columns: resolvedColumns,
|
|
1960
2047
|
filters: list?.filters,
|
|
2048
|
+
cellRenderers,
|
|
1961
2049
|
onCreate: () => {
|
|
1962
2050
|
setFormError(null);
|
|
1963
2051
|
if (detailModal?.enabled) setDetailState({ open: true });
|
|
@@ -2391,7 +2479,7 @@ function viewLabel(view) {
|
|
|
2391
2479
|
if (view.type === "dashboard") return "Dashboard";
|
|
2392
2480
|
return view.model;
|
|
2393
2481
|
}
|
|
2394
|
-
function renderView(view) {
|
|
2482
|
+
function renderView(view, registry) {
|
|
2395
2483
|
switch (view.type) {
|
|
2396
2484
|
case "collection": {
|
|
2397
2485
|
const v = view;
|
|
@@ -2407,7 +2495,8 @@ function renderView(view) {
|
|
|
2407
2495
|
importExport: v.importExport,
|
|
2408
2496
|
list: v.list,
|
|
2409
2497
|
relations: v.relations,
|
|
2410
|
-
detailModal: v.detailModal
|
|
2498
|
+
detailModal: v.detailModal,
|
|
2499
|
+
cellRenderers: registry?.cellRenderers
|
|
2411
2500
|
}
|
|
2412
2501
|
);
|
|
2413
2502
|
}
|
|
@@ -2435,10 +2524,10 @@ function renderView(view) {
|
|
|
2435
2524
|
return null;
|
|
2436
2525
|
}
|
|
2437
2526
|
}
|
|
2438
|
-
function viewToRoute(view) {
|
|
2527
|
+
function viewToRoute(view, registry) {
|
|
2439
2528
|
return {
|
|
2440
2529
|
path: viewPath(view),
|
|
2441
|
-
element: renderView(view),
|
|
2530
|
+
element: renderView(view, registry),
|
|
2442
2531
|
permissions: requiredAccess2(view)
|
|
2443
2532
|
};
|
|
2444
2533
|
}
|
|
@@ -2463,6 +2552,7 @@ function resolveRegistry(config) {
|
|
|
2463
2552
|
const routes = [];
|
|
2464
2553
|
const menu = [];
|
|
2465
2554
|
const seenPaths = /* @__PURE__ */ new Set();
|
|
2555
|
+
const componentRegistry = config.registry ?? config.ui?.registry;
|
|
2466
2556
|
const pushRoute = (route) => {
|
|
2467
2557
|
if (seenPaths.has(route.path)) return;
|
|
2468
2558
|
seenPaths.add(route.path);
|
|
@@ -2472,7 +2562,7 @@ function resolveRegistry(config) {
|
|
|
2472
2562
|
for (const route of mod.routes ?? []) pushRoute({ ...route, permissions: requiredAccess2(route) });
|
|
2473
2563
|
for (const item of mod.menu ?? []) menu.push({ ...item, permissions: requiredAccess2(item) });
|
|
2474
2564
|
for (const view of mod.views ?? []) {
|
|
2475
|
-
pushRoute(viewToRoute(view));
|
|
2565
|
+
pushRoute(viewToRoute(view, componentRegistry));
|
|
2476
2566
|
menu.push(viewToMenu(view));
|
|
2477
2567
|
}
|
|
2478
2568
|
}
|
|
@@ -2481,11 +2571,11 @@ function resolveRegistry(config) {
|
|
|
2481
2571
|
const includeManual = navMode === "manual" || navMode === "mixed";
|
|
2482
2572
|
if (includeAuto) {
|
|
2483
2573
|
for (const view of config.ui?.views ?? []) {
|
|
2484
|
-
pushRoute(viewToRoute(view));
|
|
2574
|
+
pushRoute(viewToRoute(view, componentRegistry));
|
|
2485
2575
|
menu.push(viewToMenu(view));
|
|
2486
2576
|
}
|
|
2487
2577
|
for (const page of config.ui?.pages ?? []) {
|
|
2488
|
-
pushRoute(pageToRoute(page,
|
|
2578
|
+
pushRoute(pageToRoute(page, componentRegistry));
|
|
2489
2579
|
const item = pageToMenu(page);
|
|
2490
2580
|
if (item) menu.push(item);
|
|
2491
2581
|
}
|
|
@@ -3438,7 +3528,7 @@ function localLoginUrl() {
|
|
|
3438
3528
|
return `/login?redirect=${encodeURIComponent(current)}`;
|
|
3439
3529
|
}
|
|
3440
3530
|
function OonApp({ config }) {
|
|
3441
|
-
const { http, storage, router } =
|
|
3531
|
+
const { http, storage, router } = useMemo7(() => {
|
|
3442
3532
|
const storage2 = createTokenStorage(config.app.id);
|
|
3443
3533
|
const externalLoginUrl = config.auth?.loginUrl ?? config.api.meusAppsUrl;
|
|
3444
3534
|
const http2 = createRestClient({
|
|
@@ -3533,6 +3623,7 @@ function manifestToConfig(manifest, runtime) {
|
|
|
3533
3623
|
path: c.path,
|
|
3534
3624
|
label: c.label,
|
|
3535
3625
|
section: c.section,
|
|
3626
|
+
form: c.form,
|
|
3536
3627
|
list: c.list,
|
|
3537
3628
|
relations: c.relations,
|
|
3538
3629
|
detailModal: c.detailModal
|