@oondemand/oon-core-front 0.3.26 → 0.3.28
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 +12 -2
- package/dist/index.js +263 -56
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -571,6 +571,16 @@ declare const oonCoreFront: {
|
|
|
571
571
|
start: typeof start;
|
|
572
572
|
};
|
|
573
573
|
|
|
574
|
+
interface CentralFormFieldDef extends OonFormFieldDef {
|
|
575
|
+
/** Filtros fixos enviados como query params ao CRUD da model referenciada. */
|
|
576
|
+
referenceFilters?: Record<string, string | number | boolean | null>;
|
|
577
|
+
/** Mapeia query param da referência para outro campo do mesmo formulário. */
|
|
578
|
+
referenceFilterFrom?: Record<string, string>;
|
|
579
|
+
/** Mensagem exibida enquanto algum campo de referenceFilterFrom estiver vazio. */
|
|
580
|
+
referenceDisabledMessage?: string;
|
|
581
|
+
/** Mantém somente opções em que estes campos estejam vazios/nulos. */
|
|
582
|
+
referenceEmptyFields?: string[];
|
|
583
|
+
}
|
|
574
584
|
/**
|
|
575
585
|
* Schema do `central.ui.json` (Seção 9 do escopo). É o que o frontend
|
|
576
586
|
* consumidor gerado pelo `create-central-oon` carrega — declaração pura, sem
|
|
@@ -598,7 +608,7 @@ interface CentralUiManifest {
|
|
|
598
608
|
label?: string;
|
|
599
609
|
section?: string;
|
|
600
610
|
/** Overrides pontuais de campos; os demais continuam vindo da metadata. */
|
|
601
|
-
form?:
|
|
611
|
+
form?: CentralFormFieldDef[];
|
|
602
612
|
list?: OonCollectionListConfig;
|
|
603
613
|
relations?: Record<string, OonRelationDef>;
|
|
604
614
|
detailModal?: OonDetailModalConfig;
|
|
@@ -892,4 +902,4 @@ declare function useCoreMetadata(): _tanstack_react_query.UseQueryResult<NoInfer
|
|
|
892
902
|
/** Descrição de uma model específica — base do modo "dynamic". */
|
|
893
903
|
declare function useModelSchema(name: string): _tanstack_react_query.UseQueryResult<NoInfer<ModelSummary>, Error>;
|
|
894
904
|
|
|
895
|
-
export { type CentralUiManifest, type CollectionMode, type CollectionViewDef, CoreActions, CoreAssistant, CoreCards, CoreCollection, CoreCurrency, CoreDashboard, CoreDataGrid, CoreDocument, CoreEmptyState, CoreField, CoreForm, CoreIntegration, CoreLoadingState, type CoreMetadata, CorePage, CorePageHeader, CorePipeline, CoreRelationField, CoreToolbar, type DashboardViewDef, type DashboardWidgetDef, type DocumentViewDef, type FieldKind, type FieldMeta, type ListParams, type ManifestRuntime, type ModelSummary, type OonActionDef, type OonApiConfig, type OonAppConfig, type OonAppKind, type OonAuthConfig, type OonAuthMode, type OonBlockDef, type OonColumnDef, type OonComponentRegistry, type OonCoreFrontConfig, type OonError, type OonFormFieldDef, type OonLayoutConfig, type OonMenuItem, type OonModule, type OonNavigationConfig, type OonNavigationMode, type OonPageDef, type OonRoute, type OonSchemaVersion, type OonSecurityConfig, type OonUiManifest, type OonUser, type OonViewDefinition, type PaginatedResult, type Pagination, PermissionGate, type PipelineViewDef, defineCollectionView, defineDashboard, defineDocumentView, defineOonModule, definePipelineView, manifestToConfig, oonCoreFront, start, startFromManifest, useCoreMetadata, useModelSchema, useOonApi, useOonAuth, useOonResource };
|
|
905
|
+
export { type CentralFormFieldDef, type CentralUiManifest, type CollectionMode, type CollectionViewDef, CoreActions, CoreAssistant, CoreCards, CoreCollection, CoreCurrency, CoreDashboard, CoreDataGrid, CoreDocument, CoreEmptyState, CoreField, CoreForm, CoreIntegration, CoreLoadingState, type CoreMetadata, CorePage, CorePageHeader, CorePipeline, CoreRelationField, CoreToolbar, type DashboardViewDef, type DashboardWidgetDef, type DocumentViewDef, type FieldKind, type FieldMeta, type ListParams, type ManifestRuntime, type ModelSummary, type OonActionDef, type OonApiConfig, type OonAppConfig, type OonAppKind, type OonAuthConfig, type OonAuthMode, type OonBlockDef, type OonColumnDef, type OonComponentRegistry, type OonCoreFrontConfig, type OonError, type OonFormFieldDef, type OonLayoutConfig, type OonMenuItem, type OonModule, type OonNavigationConfig, type OonNavigationMode, type OonPageDef, type OonRoute, type OonSchemaVersion, type OonSecurityConfig, type OonUiManifest, type OonUser, type OonViewDefinition, type PaginatedResult, type Pagination, PermissionGate, type PipelineViewDef, defineCollectionView, defineDashboard, defineDocumentView, defineOonModule, definePipelineView, manifestToConfig, oonCoreFront, start, startFromManifest, useCoreMetadata, useModelSchema, useOonApi, useOonAuth, useOonResource };
|
package/dist/index.js
CHANGED
|
@@ -28,11 +28,12 @@ function normalizeError(err) {
|
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
30
|
const envelope = data?.error;
|
|
31
|
+
const legacyDetails = envelope && envelope.details === void 0 && envelope.field ? envelope : void 0;
|
|
31
32
|
return {
|
|
32
33
|
code: envelope?.code || codeFromStatus(status),
|
|
33
34
|
message: envelope?.message || data?.message || err.message || "Erro inesperado.",
|
|
34
35
|
status,
|
|
35
|
-
details: envelope?.details,
|
|
36
|
+
details: envelope?.details ?? legacyDetails,
|
|
36
37
|
requestId: envelope?.requestId || err.response?.headers?.["x-request-id"]
|
|
37
38
|
};
|
|
38
39
|
}
|
|
@@ -1035,6 +1036,11 @@ function ChevronIcon2({ open }) {
|
|
|
1035
1036
|
function ClearIcon() {
|
|
1036
1037
|
return /* @__PURE__ */ jsx8("svg", { viewBox: "0 0 20 20", width: "14", height: "14", "aria-hidden": "true", children: /* @__PURE__ */ jsx8("path", { d: "m6 6 8 8M14 6l-8 8", fill: "none", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round" }) });
|
|
1037
1038
|
}
|
|
1039
|
+
function cleanFilters(filters) {
|
|
1040
|
+
return Object.fromEntries(
|
|
1041
|
+
Object.entries(filters ?? {}).filter(([, value]) => value !== void 0 && value !== null && value !== "")
|
|
1042
|
+
);
|
|
1043
|
+
}
|
|
1038
1044
|
function ReferenceSelect({
|
|
1039
1045
|
field,
|
|
1040
1046
|
inputId,
|
|
@@ -1046,9 +1052,16 @@ function ReferenceSelect({
|
|
|
1046
1052
|
required,
|
|
1047
1053
|
invalid,
|
|
1048
1054
|
error,
|
|
1055
|
+
filters,
|
|
1056
|
+
emptyFields = [],
|
|
1057
|
+
disabled = false,
|
|
1058
|
+
disabledMessage,
|
|
1049
1059
|
onChange
|
|
1050
1060
|
}) {
|
|
1051
1061
|
const initialLabel = useMemo3(() => initialReferenceLabel(initialValue), [initialValue]);
|
|
1062
|
+
const resolvedFilters = useMemo3(() => cleanFilters(filters), [filters]);
|
|
1063
|
+
const filtersKey = useMemo3(() => JSON.stringify(resolvedFilters), [resolvedFilters]);
|
|
1064
|
+
const emptyFieldsKey = useMemo3(() => JSON.stringify(emptyFields), [emptyFields]);
|
|
1052
1065
|
const [selectedLabel, setSelectedLabel] = useState4(initialLabel);
|
|
1053
1066
|
const [search, setSearch] = useState4("");
|
|
1054
1067
|
const [debouncedSearch, setDebouncedSearch] = useState4("");
|
|
@@ -1069,6 +1082,11 @@ function ReferenceSelect({
|
|
|
1069
1082
|
if (!value) setSelectedLabel("");
|
|
1070
1083
|
else if (initialLabel) setSelectedLabel(initialLabel);
|
|
1071
1084
|
}, [initialLabel, value]);
|
|
1085
|
+
useEffect3(() => {
|
|
1086
|
+
if (!disabled) return;
|
|
1087
|
+
setOpen(false);
|
|
1088
|
+
setActiveIndex(-1);
|
|
1089
|
+
}, [disabled]);
|
|
1072
1090
|
useEffect3(() => {
|
|
1073
1091
|
if (!open) return;
|
|
1074
1092
|
const onPointerDown = (event) => {
|
|
@@ -1085,9 +1103,14 @@ function ReferenceSelect({
|
|
|
1085
1103
|
window.setTimeout(() => searchRef.current?.focus(), 0);
|
|
1086
1104
|
}, [open]);
|
|
1087
1105
|
const listQuery = useQuery3({
|
|
1088
|
-
queryKey: ["oon", "reference-options", refModel, basePath, debouncedSearch],
|
|
1089
|
-
queryFn: () => resource.list({
|
|
1090
|
-
|
|
1106
|
+
queryKey: ["oon", "reference-options", refModel, basePath, debouncedSearch, filtersKey, emptyFieldsKey],
|
|
1107
|
+
queryFn: () => resource.list({
|
|
1108
|
+
pageIndex: 0,
|
|
1109
|
+
pageSize: emptyFields.length ? 200 : 30,
|
|
1110
|
+
searchTerm: debouncedSearch || void 0,
|
|
1111
|
+
...resolvedFilters
|
|
1112
|
+
}),
|
|
1113
|
+
enabled: !!schema && open && !disabled,
|
|
1091
1114
|
staleTime: 3e4
|
|
1092
1115
|
});
|
|
1093
1116
|
const currentQuery = useQuery3({
|
|
@@ -1100,11 +1123,17 @@ function ReferenceSelect({
|
|
|
1100
1123
|
if (!currentQuery.data) return;
|
|
1101
1124
|
setSelectedLabel(referenceOptionLabel(currentQuery.data, schema?.searchable));
|
|
1102
1125
|
}, [currentQuery.data, schema?.searchable]);
|
|
1103
|
-
const items = listQuery.data?.results ?? []
|
|
1126
|
+
const items = (listQuery.data?.results ?? []).filter(
|
|
1127
|
+
(record) => emptyFields.every((fieldName) => {
|
|
1128
|
+
const candidate = record[fieldName];
|
|
1129
|
+
return candidate === void 0 || candidate === null || candidate === "";
|
|
1130
|
+
})
|
|
1131
|
+
);
|
|
1104
1132
|
const listId = `oon-reference-${field}`;
|
|
1105
1133
|
const resolvedInputId = inputId ?? `oon-reference-input-${field}`;
|
|
1106
1134
|
const activeOptionId = activeIndex >= 0 ? `${listId}-option-${activeIndex}` : void 0;
|
|
1107
1135
|
const openList = (seed = "") => {
|
|
1136
|
+
if (disabled) return;
|
|
1108
1137
|
if (seed) setSearch(seed);
|
|
1109
1138
|
setOpen(true);
|
|
1110
1139
|
setActiveIndex((current) => current >= 0 ? current : 0);
|
|
@@ -1139,6 +1168,7 @@ function ReferenceSelect({
|
|
|
1139
1168
|
return next;
|
|
1140
1169
|
});
|
|
1141
1170
|
};
|
|
1171
|
+
const placeholder = disabled ? disabledMessage ?? "Selecione primeiro o campo relacionado." : "Selecione ou digite para pesquisar...";
|
|
1142
1172
|
return /* @__PURE__ */ jsxs4(Box3, { ref: rootRef, position: "relative", children: [
|
|
1143
1173
|
/* @__PURE__ */ jsxs4(
|
|
1144
1174
|
Button3,
|
|
@@ -1161,6 +1191,7 @@ function ReferenceSelect({
|
|
|
1161
1191
|
fontSize: "11px",
|
|
1162
1192
|
fontWeight: "400",
|
|
1163
1193
|
textAlign: "left",
|
|
1194
|
+
disabled,
|
|
1164
1195
|
"aria-haspopup": "listbox",
|
|
1165
1196
|
"aria-expanded": open,
|
|
1166
1197
|
"aria-controls": listId,
|
|
@@ -1170,6 +1201,7 @@ function ReferenceSelect({
|
|
|
1170
1201
|
"aria-describedby": error ? errorId : void 0,
|
|
1171
1202
|
onClick: () => open ? closeList() : openList(),
|
|
1172
1203
|
onKeyDown: (event) => {
|
|
1204
|
+
if (disabled) return;
|
|
1173
1205
|
if (event.key === "ArrowDown") {
|
|
1174
1206
|
event.preventDefault();
|
|
1175
1207
|
if (!open) openList();
|
|
@@ -1200,10 +1232,11 @@ function ReferenceSelect({
|
|
|
1200
1232
|
},
|
|
1201
1233
|
_hover: { bg: "white", borderColor: "#B9C7D1" },
|
|
1202
1234
|
_focusVisible: { borderColor: invalid ? "#DC2626" : "#0F8DD0", boxShadow: invalid ? "0 0 0 3px rgba(220,38,38,.08)" : "0 0 0 3px rgba(15,141,208,.10)" },
|
|
1235
|
+
_disabled: { cursor: "not-allowed", color: "#98A2B3", bg: "#F8FAFC", opacity: 1 },
|
|
1203
1236
|
children: [
|
|
1204
|
-
/* @__PURE__ */ jsx8(Text4, { as: "span", minW: 0, flex: "1", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", color: selectedLabel || value ? "#475467" : "#98A2B3", children: selectedLabel || (value ? String(value) :
|
|
1237
|
+
/* @__PURE__ */ jsx8(Text4, { as: "span", minW: 0, flex: "1", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", color: selectedLabel || value ? "#475467" : "#98A2B3", children: selectedLabel || (value ? String(value) : placeholder) }),
|
|
1205
1238
|
/* @__PURE__ */ jsxs4(Flex3, { as: "span", align: "center", gap: 1, flex: "0 0 auto", color: "#98A2B3", children: [
|
|
1206
|
-
value ? /* @__PURE__ */ jsx8(
|
|
1239
|
+
value && !disabled ? /* @__PURE__ */ jsx8(
|
|
1207
1240
|
Box3,
|
|
1208
1241
|
{
|
|
1209
1242
|
as: "span",
|
|
@@ -1331,7 +1364,8 @@ function ReferenceSelect({
|
|
|
1331
1364
|
}) })
|
|
1332
1365
|
]
|
|
1333
1366
|
}
|
|
1334
|
-
) : null
|
|
1367
|
+
) : null,
|
|
1368
|
+
error ? /* @__PURE__ */ jsx8(Text4, { id: errorId, role: "alert", mt: "5px", color: "#DC2626", fontSize: "10px", fontWeight: "500", children: error }) : null
|
|
1335
1369
|
] });
|
|
1336
1370
|
}
|
|
1337
1371
|
|
|
@@ -1464,6 +1498,16 @@ function buildItems(fields) {
|
|
|
1464
1498
|
});
|
|
1465
1499
|
return items;
|
|
1466
1500
|
}
|
|
1501
|
+
function resolveReference(field, values) {
|
|
1502
|
+
const filters = { ...field.referenceFilters ?? {} };
|
|
1503
|
+
const missing = [];
|
|
1504
|
+
Object.entries(field.referenceFilterFrom ?? {}).forEach(([queryField, formField]) => {
|
|
1505
|
+
const value = values[formField];
|
|
1506
|
+
if (value) filters[queryField] = value;
|
|
1507
|
+
else missing.push(formField);
|
|
1508
|
+
});
|
|
1509
|
+
return { filters, disabled: missing.length > 0 };
|
|
1510
|
+
}
|
|
1467
1511
|
function DynamicForm({ title, eyebrow = "Cadastro", fields, initialValues, submitting, error, onSubmit, onCancel, onFieldChange }) {
|
|
1468
1512
|
const [values, setValues] = useState5(() => Object.fromEntries(fields.map((field) => [field.field, toValue(initialValues?.[field.field], field.kind)])));
|
|
1469
1513
|
const [errors, setErrors] = useState5({});
|
|
@@ -1489,12 +1533,23 @@ function DynamicForm({ title, eyebrow = "Cadastro", fields, initialValues, submi
|
|
|
1489
1533
|
const first = fields.find((field) => next[field.field]);
|
|
1490
1534
|
if (first) focusField(first.field);
|
|
1491
1535
|
}, [error]);
|
|
1492
|
-
const change = (
|
|
1493
|
-
|
|
1536
|
+
const change = (fieldName, value) => {
|
|
1537
|
+
const extendedFields = fields;
|
|
1538
|
+
const dependentFields = extendedFields.filter(
|
|
1539
|
+
(candidate) => Object.values(candidate.referenceFilterFrom ?? {}).includes(fieldName)
|
|
1540
|
+
);
|
|
1541
|
+
setValues((current) => {
|
|
1542
|
+
const changed = current[fieldName] !== value;
|
|
1543
|
+
const next = { ...current, [fieldName]: value };
|
|
1544
|
+
if (changed) dependentFields.forEach((candidate) => {
|
|
1545
|
+
next[candidate.field] = "";
|
|
1546
|
+
});
|
|
1547
|
+
return next;
|
|
1548
|
+
});
|
|
1494
1549
|
setErrors((current) => {
|
|
1495
|
-
if (!current[field]) return current;
|
|
1496
1550
|
const next = { ...current };
|
|
1497
|
-
delete next[
|
|
1551
|
+
delete next[fieldName];
|
|
1552
|
+
dependentFields.forEach((candidate) => delete next[candidate.field]);
|
|
1498
1553
|
return next;
|
|
1499
1554
|
});
|
|
1500
1555
|
setDismissed(true);
|
|
@@ -1575,7 +1630,10 @@ function DynamicForm({ title, eyebrow = "Cadastro", fields, initialValues, submi
|
|
|
1575
1630
|
false
|
|
1576
1631
|
);
|
|
1577
1632
|
}
|
|
1578
|
-
if (field.kind === "ref" && field.ref)
|
|
1633
|
+
if (field.kind === "ref" && field.ref) {
|
|
1634
|
+
const reference = resolveReference(field, values);
|
|
1635
|
+
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, filters: reference.filters, emptyFields: field.referenceEmptyFields, disabled: reference.disabled, disabledMessage: field.referenceDisabledMessage, onChange: (value) => change(field.field, value) }));
|
|
1636
|
+
}
|
|
1579
1637
|
if (field.kind === "enum" && field.options?.length) return wrap(/* @__PURE__ */ jsxs5(NativeSelect2.Root, { size: "sm", children: [
|
|
1580
1638
|
/* @__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
1639
|
/* @__PURE__ */ jsx9("option", { value: "", children: "\u2014 Selecione \u2014" }),
|
|
@@ -1905,80 +1963,192 @@ function toValue2(value, kind) {
|
|
|
1905
1963
|
function isMultiline2(field) {
|
|
1906
1964
|
return /observa|descricao|mensagem|detalhe|necessidade/i.test(field.field);
|
|
1907
1965
|
}
|
|
1966
|
+
function messageOf3(error) {
|
|
1967
|
+
if (!error) return null;
|
|
1968
|
+
if (typeof error === "string") return error;
|
|
1969
|
+
if (error instanceof Error) return error.message;
|
|
1970
|
+
if (typeof error === "object") {
|
|
1971
|
+
const record = error;
|
|
1972
|
+
if (typeof record.message === "string") return record.message;
|
|
1973
|
+
if (record.error && typeof record.error === "object") {
|
|
1974
|
+
const nested = record.error;
|
|
1975
|
+
if (typeof nested.message === "string") return nested.message;
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
return "N\xE3o foi poss\xEDvel salvar o registro.";
|
|
1979
|
+
}
|
|
1980
|
+
function fieldErrorsOf(error) {
|
|
1981
|
+
if (!error || typeof error !== "object") return {};
|
|
1982
|
+
const record = error;
|
|
1983
|
+
const envelope = record.error && typeof record.error === "object" ? record.error : void 0;
|
|
1984
|
+
const details = record.details ?? envelope?.details ?? envelope;
|
|
1985
|
+
const result = {};
|
|
1986
|
+
const visit = (value) => {
|
|
1987
|
+
if (!value) return;
|
|
1988
|
+
if (Array.isArray(value)) {
|
|
1989
|
+
value.forEach(visit);
|
|
1990
|
+
return;
|
|
1991
|
+
}
|
|
1992
|
+
if (typeof value !== "object") return;
|
|
1993
|
+
const item = value;
|
|
1994
|
+
if (typeof item.field === "string" && typeof item.message === "string") {
|
|
1995
|
+
result[item.field] = item.message;
|
|
1996
|
+
}
|
|
1997
|
+
Object.values(item).forEach((nested) => {
|
|
1998
|
+
if (nested !== item.field && nested !== item.message) visit(nested);
|
|
1999
|
+
});
|
|
2000
|
+
};
|
|
2001
|
+
visit(details);
|
|
2002
|
+
return result;
|
|
2003
|
+
}
|
|
2004
|
+
function requiredErrors(fields, values) {
|
|
2005
|
+
const errors = {};
|
|
2006
|
+
fields.forEach((field) => {
|
|
2007
|
+
if (field.required && !(values[field.field] ?? "").trim()) {
|
|
2008
|
+
errors[field.field] = `${fieldLabel({ name: field.field, label: field.label })} \xE9 obrigat\xF3rio.`;
|
|
2009
|
+
}
|
|
2010
|
+
});
|
|
2011
|
+
return errors;
|
|
2012
|
+
}
|
|
2013
|
+
function resolveReference2(field, values) {
|
|
2014
|
+
const filters = { ...field.referenceFilters ?? {} };
|
|
2015
|
+
const missing = [];
|
|
2016
|
+
Object.entries(field.referenceFilterFrom ?? {}).forEach(([queryField, formField]) => {
|
|
2017
|
+
const value = values[formField];
|
|
2018
|
+
if (value) filters[queryField] = value;
|
|
2019
|
+
else missing.push(formField);
|
|
2020
|
+
});
|
|
2021
|
+
return { filters, disabled: missing.length > 0 };
|
|
2022
|
+
}
|
|
2023
|
+
function FieldLabel({ field, htmlFor }) {
|
|
2024
|
+
const label = fieldLabel({ name: field.field, label: field.label });
|
|
2025
|
+
return /* @__PURE__ */ jsx14("label", { htmlFor, children: /* @__PURE__ */ jsxs10(Text9, { as: "span", display: "block", mb: "5px", color: "#475467", fontSize: "11px", fontWeight: "600", children: [
|
|
2026
|
+
label,
|
|
2027
|
+
field.required ? /* @__PURE__ */ jsx14(Text9, { as: "span", color: "#DC2626", children: " *" }) : null
|
|
2028
|
+
] }) });
|
|
2029
|
+
}
|
|
2030
|
+
function ErrorText2({ id, message }) {
|
|
2031
|
+
return message ? /* @__PURE__ */ jsx14(Text9, { id, role: "alert", mt: "5px", color: "#DC2626", fontSize: "10px", fontWeight: "500", children: message }) : null;
|
|
2032
|
+
}
|
|
1908
2033
|
function FieldControl({
|
|
1909
2034
|
field,
|
|
1910
2035
|
value,
|
|
2036
|
+
values,
|
|
2037
|
+
initialValue,
|
|
2038
|
+
error,
|
|
1911
2039
|
onChange
|
|
1912
2040
|
}) {
|
|
1913
2041
|
const label = fieldLabel({ name: field.field, label: field.label });
|
|
2042
|
+
const inputId = `oon-detail-field-${field.field.replace(/[^a-zA-Z0-9_-]/g, "-")}`;
|
|
2043
|
+
const errorId = `${inputId}-error`;
|
|
2044
|
+
const invalidProps = {
|
|
2045
|
+
"aria-invalid": error ? true : void 0,
|
|
2046
|
+
"aria-describedby": error ? errorId : void 0,
|
|
2047
|
+
borderColor: error ? "#DC2626" : void 0,
|
|
2048
|
+
boxShadow: error ? "0 0 0 3px rgba(220,38,38,.08)" : void 0
|
|
2049
|
+
};
|
|
1914
2050
|
if (field.widget === "checkbox") {
|
|
1915
2051
|
const checkedValue = String(field.checkedValue ?? true);
|
|
1916
2052
|
const uncheckedValue = String(field.uncheckedValue ?? false);
|
|
1917
2053
|
const checked = (value || uncheckedValue) === checkedValue;
|
|
1918
|
-
return /* @__PURE__ */ jsxs10(
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
2054
|
+
return /* @__PURE__ */ jsxs10(Box7, { children: [
|
|
2055
|
+
/* @__PURE__ */ jsxs10(
|
|
2056
|
+
Box7,
|
|
2057
|
+
{
|
|
2058
|
+
as: "label",
|
|
2059
|
+
display: "flex",
|
|
2060
|
+
minH: "38px",
|
|
2061
|
+
px: "11px",
|
|
2062
|
+
alignItems: "center",
|
|
2063
|
+
gap: "8px",
|
|
2064
|
+
color: "#344054",
|
|
2065
|
+
bg: checked ? "#F0F7FF" : "white",
|
|
2066
|
+
borderWidth: "1px",
|
|
2067
|
+
borderColor: error ? "#DC2626" : checked ? "#8FC9E7" : "#D5DDE3",
|
|
2068
|
+
borderRadius: "7px",
|
|
2069
|
+
cursor: "pointer",
|
|
2070
|
+
children: [
|
|
2071
|
+
/* @__PURE__ */ jsx14(
|
|
2072
|
+
"input",
|
|
2073
|
+
{
|
|
2074
|
+
id: inputId,
|
|
2075
|
+
type: "checkbox",
|
|
2076
|
+
checked,
|
|
2077
|
+
"aria-invalid": error ? true : void 0,
|
|
2078
|
+
"aria-describedby": error ? errorId : void 0,
|
|
2079
|
+
style: { width: 16, height: 16, accentColor: "#0474AF", cursor: "pointer" },
|
|
2080
|
+
onChange: (event) => onChange(event.currentTarget.checked ? checkedValue : uncheckedValue)
|
|
2081
|
+
}
|
|
2082
|
+
),
|
|
2083
|
+
/* @__PURE__ */ jsx14(Text9, { as: "span", fontSize: "11px", fontWeight: "600", children: label })
|
|
2084
|
+
]
|
|
2085
|
+
}
|
|
2086
|
+
),
|
|
2087
|
+
/* @__PURE__ */ jsx14(ErrorText2, { id: errorId, message: error })
|
|
2088
|
+
] });
|
|
2089
|
+
}
|
|
2090
|
+
if (field.kind === "ref" && field.ref) {
|
|
2091
|
+
const reference = resolveReference2(field, values);
|
|
2092
|
+
return /* @__PURE__ */ jsxs10(Box7, { children: [
|
|
2093
|
+
/* @__PURE__ */ jsx14(FieldLabel, { field, htmlFor: inputId }),
|
|
2094
|
+
/* @__PURE__ */ jsx14(
|
|
2095
|
+
ReferenceSelect,
|
|
2096
|
+
{
|
|
2097
|
+
field: field.field,
|
|
2098
|
+
inputId,
|
|
2099
|
+
errorId,
|
|
2100
|
+
label,
|
|
2101
|
+
refModel: field.ref,
|
|
2102
|
+
value,
|
|
2103
|
+
initialValue,
|
|
2104
|
+
required: field.required,
|
|
2105
|
+
invalid: !!error,
|
|
2106
|
+
error,
|
|
2107
|
+
filters: reference.filters,
|
|
2108
|
+
emptyFields: field.referenceEmptyFields,
|
|
2109
|
+
disabled: reference.disabled,
|
|
2110
|
+
disabledMessage: field.referenceDisabledMessage,
|
|
2111
|
+
onChange
|
|
2112
|
+
}
|
|
2113
|
+
)
|
|
2114
|
+
] });
|
|
1947
2115
|
}
|
|
1948
2116
|
const control = field.kind === "enum" && field.options?.length ? /* @__PURE__ */ jsxs10(NativeSelect4.Root, { size: "sm", children: [
|
|
1949
|
-
/* @__PURE__ */ jsxs10(NativeSelect4.Field, { value, onChange: (event) => onChange(event.currentTarget.value), children: [
|
|
2117
|
+
/* @__PURE__ */ jsxs10(NativeSelect4.Field, { id: inputId, value, ...invalidProps, onChange: (event) => onChange(event.currentTarget.value), children: [
|
|
1950
2118
|
/* @__PURE__ */ jsx14("option", { value: "", children: "\u2014 Selecione \u2014" }),
|
|
1951
2119
|
field.options.map((option) => /* @__PURE__ */ jsx14("option", { value: option, children: option }, option))
|
|
1952
2120
|
] }),
|
|
1953
2121
|
/* @__PURE__ */ jsx14(NativeSelect4.Indicator, {})
|
|
1954
2122
|
] }) : field.kind === "boolean" ? /* @__PURE__ */ jsxs10(NativeSelect4.Root, { size: "sm", children: [
|
|
1955
|
-
/* @__PURE__ */ jsxs10(NativeSelect4.Field, { value, onChange: (event) => onChange(event.currentTarget.value), children: [
|
|
2123
|
+
/* @__PURE__ */ jsxs10(NativeSelect4.Field, { id: inputId, value, ...invalidProps, onChange: (event) => onChange(event.currentTarget.value), children: [
|
|
1956
2124
|
/* @__PURE__ */ jsx14("option", { value: "", children: "\u2014 Selecione \u2014" }),
|
|
1957
2125
|
/* @__PURE__ */ jsx14("option", { value: "true", children: "Sim" }),
|
|
1958
2126
|
/* @__PURE__ */ jsx14("option", { value: "false", children: "N\xE3o" })
|
|
1959
2127
|
] }),
|
|
1960
2128
|
/* @__PURE__ */ jsx14(NativeSelect4.Indicator, {})
|
|
1961
|
-
] }) : isMultiline2(field) ? /* @__PURE__ */ jsx14(Textarea3, { rows: 4, resize: "vertical", value, onChange: (event) => onChange(event.currentTarget.value) }) : /* @__PURE__ */ jsx14(
|
|
2129
|
+
] }) : isMultiline2(field) ? /* @__PURE__ */ jsx14(Textarea3, { id: inputId, rows: 4, resize: "vertical", value, ...invalidProps, onChange: (event) => onChange(event.currentTarget.value) }) : /* @__PURE__ */ jsx14(
|
|
1962
2130
|
Input5,
|
|
1963
2131
|
{
|
|
2132
|
+
id: inputId,
|
|
1964
2133
|
size: "sm",
|
|
1965
2134
|
type: field.kind === "date" ? "date" : ["number", "currency", "currencyConverted"].includes(field.kind ?? "") ? "number" : "text",
|
|
1966
2135
|
value,
|
|
2136
|
+
...invalidProps,
|
|
1967
2137
|
onChange: (event) => onChange(event.currentTarget.value)
|
|
1968
2138
|
}
|
|
1969
2139
|
);
|
|
1970
2140
|
return /* @__PURE__ */ jsxs10(Box7, { children: [
|
|
1971
|
-
/* @__PURE__ */
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
] }),
|
|
1975
|
-
control
|
|
2141
|
+
/* @__PURE__ */ jsx14(FieldLabel, { field, htmlFor: inputId }),
|
|
2142
|
+
control,
|
|
2143
|
+
/* @__PURE__ */ jsx14(ErrorText2, { id: errorId, message: error })
|
|
1976
2144
|
] });
|
|
1977
2145
|
}
|
|
1978
2146
|
function GroupSection({
|
|
1979
2147
|
group,
|
|
1980
2148
|
fields,
|
|
1981
2149
|
values,
|
|
2150
|
+
initialValues,
|
|
2151
|
+
errors,
|
|
1982
2152
|
onChange
|
|
1983
2153
|
}) {
|
|
1984
2154
|
if (!fields.length) return null;
|
|
@@ -1991,6 +2161,9 @@ function GroupSection({
|
|
|
1991
2161
|
{
|
|
1992
2162
|
field,
|
|
1993
2163
|
value: values[field.field] ?? "",
|
|
2164
|
+
values,
|
|
2165
|
+
initialValue: initialValues[field.field],
|
|
2166
|
+
error: errors[field.field],
|
|
1994
2167
|
onChange: (value) => onChange(field.field, value)
|
|
1995
2168
|
},
|
|
1996
2169
|
field.field
|
|
@@ -1998,21 +2171,41 @@ function GroupSection({
|
|
|
1998
2171
|
] });
|
|
1999
2172
|
}
|
|
2000
2173
|
function InlineParentForm({
|
|
2001
|
-
fields,
|
|
2174
|
+
fields: rawFields,
|
|
2002
2175
|
groups,
|
|
2003
2176
|
parent,
|
|
2004
2177
|
resource,
|
|
2005
2178
|
onSaved
|
|
2006
2179
|
}) {
|
|
2180
|
+
const fields = rawFields;
|
|
2007
2181
|
const [values, setValues] = useState8({});
|
|
2008
2182
|
const [saving, setSaving] = useState8(false);
|
|
2009
2183
|
const [error, setError] = useState8(null);
|
|
2184
|
+
const [fieldErrors, setFieldErrors] = useState8({});
|
|
2010
2185
|
useEffect5(() => {
|
|
2011
2186
|
setValues(Object.fromEntries(fields.map((field) => [field.field, toValue2(parent[field.field], field.kind)])));
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2187
|
+
setError(null);
|
|
2188
|
+
setFieldErrors({});
|
|
2189
|
+
}, [parent, rawFields]);
|
|
2190
|
+
const fieldsByName = useMemo6(() => new Map(fields.map((field) => [field.field, field])), [rawFields]);
|
|
2191
|
+
const change = (fieldName, value) => {
|
|
2192
|
+
const dependentFields = fields.filter(
|
|
2193
|
+
(candidate) => Object.values(candidate.referenceFilterFrom ?? {}).includes(fieldName)
|
|
2194
|
+
);
|
|
2195
|
+
setValues((current) => {
|
|
2196
|
+
const changed = current[fieldName] !== value;
|
|
2197
|
+
const next = { ...current, [fieldName]: value };
|
|
2198
|
+
if (changed) dependentFields.forEach((candidate) => {
|
|
2199
|
+
next[candidate.field] = "";
|
|
2200
|
+
});
|
|
2201
|
+
return next;
|
|
2202
|
+
});
|
|
2203
|
+
setFieldErrors((current) => {
|
|
2204
|
+
const next = { ...current };
|
|
2205
|
+
delete next[fieldName];
|
|
2206
|
+
dependentFields.forEach((candidate) => delete next[candidate.field]);
|
|
2207
|
+
return next;
|
|
2208
|
+
});
|
|
2016
2209
|
setError(null);
|
|
2017
2210
|
};
|
|
2018
2211
|
const renderFields = () => {
|
|
@@ -2023,6 +2216,8 @@ function InlineParentForm({
|
|
|
2023
2216
|
group,
|
|
2024
2217
|
fields: group.fields.map((field) => fieldsByName.get(field)).filter(Boolean),
|
|
2025
2218
|
values,
|
|
2219
|
+
initialValues: parent,
|
|
2220
|
+
errors: fieldErrors,
|
|
2026
2221
|
onChange: change
|
|
2027
2222
|
},
|
|
2028
2223
|
`${group.label}-${group.fields.join("-")}`
|
|
@@ -2033,6 +2228,9 @@ function InlineParentForm({
|
|
|
2033
2228
|
{
|
|
2034
2229
|
field,
|
|
2035
2230
|
value: values[field.field] ?? "",
|
|
2231
|
+
values,
|
|
2232
|
+
initialValue: parent[field.field],
|
|
2233
|
+
error: fieldErrors[field.field],
|
|
2036
2234
|
onChange: (value) => change(field.field, value)
|
|
2037
2235
|
},
|
|
2038
2236
|
field.field
|
|
@@ -2041,10 +2239,18 @@ function InlineParentForm({
|
|
|
2041
2239
|
return /* @__PURE__ */ jsx14(
|
|
2042
2240
|
"form",
|
|
2043
2241
|
{
|
|
2242
|
+
noValidate: true,
|
|
2044
2243
|
onSubmit: async (event) => {
|
|
2045
2244
|
event.preventDefault();
|
|
2245
|
+
const validation = requiredErrors(fields, values);
|
|
2246
|
+
if (Object.keys(validation).length) {
|
|
2247
|
+
setFieldErrors(validation);
|
|
2248
|
+
setError({ message: "Preencha os campos obrigat\xF3rios destacados." });
|
|
2249
|
+
return;
|
|
2250
|
+
}
|
|
2046
2251
|
setSaving(true);
|
|
2047
2252
|
setError(null);
|
|
2253
|
+
setFieldErrors({});
|
|
2048
2254
|
try {
|
|
2049
2255
|
const payload = Object.fromEntries(
|
|
2050
2256
|
fields.map((field) => [field.field, coerce2(values[field.field] ?? "", field.kind)]).filter(([, value]) => value !== void 0)
|
|
@@ -2053,12 +2259,13 @@ function InlineParentForm({
|
|
|
2053
2259
|
onSaved(saved);
|
|
2054
2260
|
} catch (requestError) {
|
|
2055
2261
|
setError(requestError);
|
|
2262
|
+
setFieldErrors(fieldErrorsOf(requestError));
|
|
2056
2263
|
} finally {
|
|
2057
2264
|
setSaving(false);
|
|
2058
2265
|
}
|
|
2059
2266
|
},
|
|
2060
2267
|
children: /* @__PURE__ */ jsxs10(Stack3, { gap: "16px", children: [
|
|
2061
|
-
error ? /* @__PURE__ */ jsx14(
|
|
2268
|
+
error ? /* @__PURE__ */ jsx14(Box7, { role: "alert", p: "10px 12px", color: "#B42318", bg: "#FEF3F2", borderWidth: "1px", borderColor: "#FECDCA", borderRadius: "7px", fontSize: "11px", children: messageOf3(error) }) : null,
|
|
2062
2269
|
renderFields(),
|
|
2063
2270
|
/* @__PURE__ */ jsx14(Flex6, { justify: "flex-end", children: /* @__PURE__ */ jsx14(Button7, { type: "submit", colorPalette: "brand", loading: saving, children: "Salvar dados principais" }) })
|
|
2064
2271
|
] })
|