@nubitio/crud 0.5.13 → 0.5.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.cjs +39 -6
- package/dist/index.mjs +39 -6
- package/dist/style.css +10 -3
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -3671,6 +3671,7 @@ function normalizeFormData(data, fields, adapter = HydraAdapter, prependDataByFi
|
|
|
3671
3671
|
else row[field.name] = null;
|
|
3672
3672
|
}
|
|
3673
3673
|
if (field.type === "entity") normalizeEntityField(row, field, adapter, prependDataByField);
|
|
3674
|
+
if (field.type !== "entity" && field.type !== "file" && (Array.isArray(row[field.name]) || row[field.name] !== null && typeof row[field.name] === "object")) delete row[field.name];
|
|
3674
3675
|
});
|
|
3675
3676
|
return row;
|
|
3676
3677
|
}
|
|
@@ -4304,9 +4305,20 @@ function validateField(field, value, formData, t) {
|
|
|
4304
4305
|
}
|
|
4305
4306
|
return null;
|
|
4306
4307
|
}
|
|
4308
|
+
const DETAIL_CURRENCY_COL_WIDTH = 112;
|
|
4309
|
+
const DETAIL_NUMBER_COL_WIDTH = 96;
|
|
4310
|
+
function resolveDetailColWidth(field, colWidths) {
|
|
4311
|
+
if (colWidths[field.name] !== void 0) return colWidths[field.name];
|
|
4312
|
+
if (field.width !== void 0) {
|
|
4313
|
+
const parsed = typeof field.width === "number" ? field.width : Number.parseInt(String(field.width), 10);
|
|
4314
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
4315
|
+
}
|
|
4316
|
+
if (field.type === "currency") return DETAIL_CURRENCY_COL_WIDTH;
|
|
4317
|
+
if (field.type === "number") return DETAIL_NUMBER_COL_WIDTH;
|
|
4318
|
+
}
|
|
4307
4319
|
function DetailColumnGroup({ allowDeleting, fields, colWidths }) {
|
|
4308
4320
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("colgroup", { children: [fields.map((field) => {
|
|
4309
|
-
const width =
|
|
4321
|
+
const width = resolveDetailColWidth(field, colWidths);
|
|
4310
4322
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("col", { style: width ? { width } : void 0 }, field.name);
|
|
4311
4323
|
}), allowDeleting && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("col", { className: "nb-form__col-actions-col" })] });
|
|
4312
4324
|
}
|
|
@@ -4316,7 +4328,6 @@ function DetailSummaryFooter({ allowDeleting, colWidths, fields, rows, scrollRef
|
|
|
4316
4328
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4317
4329
|
ref: scrollRef,
|
|
4318
4330
|
className: "nb-form__detail-summary-wrap",
|
|
4319
|
-
"aria-hidden": "true",
|
|
4320
4331
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("table", {
|
|
4321
4332
|
className: "nb-form__detail-table nb-form__detail-summary-table",
|
|
4322
4333
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DetailColumnGroup, {
|
|
@@ -4328,11 +4339,16 @@ function DetailSummaryFooter({ allowDeleting, colWidths, fields, rows, scrollRef
|
|
|
4328
4339
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [fields.map((field) => {
|
|
4329
4340
|
const item = itemsByColumn.get(field.name);
|
|
4330
4341
|
const align = item?.align ?? field.align;
|
|
4342
|
+
const alignItems = align === "center" ? "center" : align === "right" ? "flex-end" : "flex-start";
|
|
4343
|
+
const colWidth = item ? resolveDetailColWidth(field, colWidths) : void 0;
|
|
4331
4344
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
|
|
4332
|
-
style:
|
|
4345
|
+
style: {
|
|
4346
|
+
...align ? { textAlign: align } : void 0,
|
|
4347
|
+
...colWidth ? { minWidth: colWidth } : void 0
|
|
4348
|
+
},
|
|
4333
4349
|
children: item && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4334
4350
|
className: "nb-form__detail-summary-cell",
|
|
4335
|
-
style: {
|
|
4351
|
+
style: { alignItems },
|
|
4336
4352
|
children: [item.label && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4337
4353
|
className: "nb-form__detail-summary-label",
|
|
4338
4354
|
children: item.label
|
|
@@ -7221,6 +7237,22 @@ function useSmartCrudFields(fields, activeOperation, formData, roles) {
|
|
|
7221
7237
|
};
|
|
7222
7238
|
}
|
|
7223
7239
|
//#endregion
|
|
7240
|
+
//#region packages/crud/crud/applyFormDetailFormFieldOverrides.ts
|
|
7241
|
+
/**
|
|
7242
|
+
* Hides the header form field that mirrors `formDetail.propertyName`.
|
|
7243
|
+
* OneToMany collections serialized as object arrays must not render as a
|
|
7244
|
+
* plain text input ([object Object]) when line items are edited via formDetail.
|
|
7245
|
+
*/
|
|
7246
|
+
function applyFormDetailFormFieldOverrides(fields, formDetail) {
|
|
7247
|
+
const propertyName = formDetail?.propertyName?.trim();
|
|
7248
|
+
if (!propertyName) return fields;
|
|
7249
|
+
return fields.map((field) => field.name === propertyName ? {
|
|
7250
|
+
...field,
|
|
7251
|
+
visibleOnForm: false,
|
|
7252
|
+
hidden: true
|
|
7253
|
+
} : field);
|
|
7254
|
+
}
|
|
7255
|
+
//#endregion
|
|
7224
7256
|
//#region packages/crud/crud/fieldValidation.ts
|
|
7225
7257
|
var SmartCrudFieldContractError = class extends Error {
|
|
7226
7258
|
issues;
|
|
@@ -7663,6 +7695,7 @@ function SmartCrudPage({ resource, fieldOverrides, formRef, onSelectionChanged,
|
|
|
7663
7695
|
const { activeOperation, formData, handleFormDataChange, startCreate, startEdit, resetOperation } = useSmartCrudOperation(void 0, routingState);
|
|
7664
7696
|
const roles = useSmartCrudRoles();
|
|
7665
7697
|
const { gridFields, processedFields, computedValues } = useSmartCrudFields(fields, activeOperation, formData, (0, react.useMemo)(() => roles ?? [], [roles]));
|
|
7698
|
+
const formFields = (0, react.useMemo)(() => applyFormDetailFormFieldOverrides(processedFields, resolvedBaseResource.formDetail), [processedFields, resolvedBaseResource.formDetail]);
|
|
7666
7699
|
(0, _nubitio_core.useMercureSubscription)(resource.apiUrl, () => {
|
|
7667
7700
|
effectiveGridRef.current?.refresh();
|
|
7668
7701
|
}, resolvedBaseResource.mercure !== false);
|
|
@@ -7672,7 +7705,7 @@ function SmartCrudPage({ resource, fieldOverrides, formRef, onSelectionChanged,
|
|
|
7672
7705
|
...!hasManualFields ? { fields: gridFields } : {},
|
|
7673
7706
|
apiUrl: normalizedApiUrl,
|
|
7674
7707
|
fields: hasManualFields ? buildFields(resource.fields) : gridFields,
|
|
7675
|
-
formFields
|
|
7708
|
+
formFields,
|
|
7676
7709
|
formLayout: resolvedBaseResource.formLayout ?? inferredFormLayout,
|
|
7677
7710
|
_supportedOperations: supportedOperations
|
|
7678
7711
|
}), [
|
|
@@ -7681,7 +7714,7 @@ function SmartCrudPage({ resource, fieldOverrides, formRef, onSelectionChanged,
|
|
|
7681
7714
|
hasManualFields,
|
|
7682
7715
|
inferredFormLayout,
|
|
7683
7716
|
normalizedApiUrl,
|
|
7684
|
-
|
|
7717
|
+
formFields,
|
|
7685
7718
|
resolvedBaseResource,
|
|
7686
7719
|
resource.fields,
|
|
7687
7720
|
supportedOperations
|
package/dist/index.mjs
CHANGED
|
@@ -3647,6 +3647,7 @@ function normalizeFormData(data, fields, adapter = HydraAdapter, prependDataByFi
|
|
|
3647
3647
|
else row[field.name] = null;
|
|
3648
3648
|
}
|
|
3649
3649
|
if (field.type === "entity") normalizeEntityField(row, field, adapter, prependDataByField);
|
|
3650
|
+
if (field.type !== "entity" && field.type !== "file" && (Array.isArray(row[field.name]) || row[field.name] !== null && typeof row[field.name] === "object")) delete row[field.name];
|
|
3650
3651
|
});
|
|
3651
3652
|
return row;
|
|
3652
3653
|
}
|
|
@@ -4280,9 +4281,20 @@ function validateField(field, value, formData, t) {
|
|
|
4280
4281
|
}
|
|
4281
4282
|
return null;
|
|
4282
4283
|
}
|
|
4284
|
+
const DETAIL_CURRENCY_COL_WIDTH = 112;
|
|
4285
|
+
const DETAIL_NUMBER_COL_WIDTH = 96;
|
|
4286
|
+
function resolveDetailColWidth(field, colWidths) {
|
|
4287
|
+
if (colWidths[field.name] !== void 0) return colWidths[field.name];
|
|
4288
|
+
if (field.width !== void 0) {
|
|
4289
|
+
const parsed = typeof field.width === "number" ? field.width : Number.parseInt(String(field.width), 10);
|
|
4290
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
4291
|
+
}
|
|
4292
|
+
if (field.type === "currency") return DETAIL_CURRENCY_COL_WIDTH;
|
|
4293
|
+
if (field.type === "number") return DETAIL_NUMBER_COL_WIDTH;
|
|
4294
|
+
}
|
|
4283
4295
|
function DetailColumnGroup({ allowDeleting, fields, colWidths }) {
|
|
4284
4296
|
return /* @__PURE__ */ jsxs("colgroup", { children: [fields.map((field) => {
|
|
4285
|
-
const width =
|
|
4297
|
+
const width = resolveDetailColWidth(field, colWidths);
|
|
4286
4298
|
return /* @__PURE__ */ jsx("col", { style: width ? { width } : void 0 }, field.name);
|
|
4287
4299
|
}), allowDeleting && /* @__PURE__ */ jsx("col", { className: "nb-form__col-actions-col" })] });
|
|
4288
4300
|
}
|
|
@@ -4292,7 +4304,6 @@ function DetailSummaryFooter({ allowDeleting, colWidths, fields, rows, scrollRef
|
|
|
4292
4304
|
return /* @__PURE__ */ jsx("div", {
|
|
4293
4305
|
ref: scrollRef,
|
|
4294
4306
|
className: "nb-form__detail-summary-wrap",
|
|
4295
|
-
"aria-hidden": "true",
|
|
4296
4307
|
children: /* @__PURE__ */ jsxs("table", {
|
|
4297
4308
|
className: "nb-form__detail-table nb-form__detail-summary-table",
|
|
4298
4309
|
children: [/* @__PURE__ */ jsx(DetailColumnGroup, {
|
|
@@ -4304,11 +4315,16 @@ function DetailSummaryFooter({ allowDeleting, colWidths, fields, rows, scrollRef
|
|
|
4304
4315
|
children: /* @__PURE__ */ jsxs("tr", { children: [fields.map((field) => {
|
|
4305
4316
|
const item = itemsByColumn.get(field.name);
|
|
4306
4317
|
const align = item?.align ?? field.align;
|
|
4318
|
+
const alignItems = align === "center" ? "center" : align === "right" ? "flex-end" : "flex-start";
|
|
4319
|
+
const colWidth = item ? resolveDetailColWidth(field, colWidths) : void 0;
|
|
4307
4320
|
return /* @__PURE__ */ jsx("td", {
|
|
4308
|
-
style:
|
|
4321
|
+
style: {
|
|
4322
|
+
...align ? { textAlign: align } : void 0,
|
|
4323
|
+
...colWidth ? { minWidth: colWidth } : void 0
|
|
4324
|
+
},
|
|
4309
4325
|
children: item && /* @__PURE__ */ jsxs("div", {
|
|
4310
4326
|
className: "nb-form__detail-summary-cell",
|
|
4311
|
-
style: {
|
|
4327
|
+
style: { alignItems },
|
|
4312
4328
|
children: [item.label && /* @__PURE__ */ jsx("span", {
|
|
4313
4329
|
className: "nb-form__detail-summary-label",
|
|
4314
4330
|
children: item.label
|
|
@@ -7197,6 +7213,22 @@ function useSmartCrudFields(fields, activeOperation, formData, roles) {
|
|
|
7197
7213
|
};
|
|
7198
7214
|
}
|
|
7199
7215
|
//#endregion
|
|
7216
|
+
//#region packages/crud/crud/applyFormDetailFormFieldOverrides.ts
|
|
7217
|
+
/**
|
|
7218
|
+
* Hides the header form field that mirrors `formDetail.propertyName`.
|
|
7219
|
+
* OneToMany collections serialized as object arrays must not render as a
|
|
7220
|
+
* plain text input ([object Object]) when line items are edited via formDetail.
|
|
7221
|
+
*/
|
|
7222
|
+
function applyFormDetailFormFieldOverrides(fields, formDetail) {
|
|
7223
|
+
const propertyName = formDetail?.propertyName?.trim();
|
|
7224
|
+
if (!propertyName) return fields;
|
|
7225
|
+
return fields.map((field) => field.name === propertyName ? {
|
|
7226
|
+
...field,
|
|
7227
|
+
visibleOnForm: false,
|
|
7228
|
+
hidden: true
|
|
7229
|
+
} : field);
|
|
7230
|
+
}
|
|
7231
|
+
//#endregion
|
|
7200
7232
|
//#region packages/crud/crud/fieldValidation.ts
|
|
7201
7233
|
var SmartCrudFieldContractError = class extends Error {
|
|
7202
7234
|
issues;
|
|
@@ -7639,6 +7671,7 @@ function SmartCrudPage({ resource, fieldOverrides, formRef, onSelectionChanged,
|
|
|
7639
7671
|
const { activeOperation, formData, handleFormDataChange, startCreate, startEdit, resetOperation } = useSmartCrudOperation(void 0, routingState);
|
|
7640
7672
|
const roles = useSmartCrudRoles();
|
|
7641
7673
|
const { gridFields, processedFields, computedValues } = useSmartCrudFields(fields, activeOperation, formData, useMemo(() => roles ?? [], [roles]));
|
|
7674
|
+
const formFields = useMemo(() => applyFormDetailFormFieldOverrides(processedFields, resolvedBaseResource.formDetail), [processedFields, resolvedBaseResource.formDetail]);
|
|
7642
7675
|
useMercureSubscription(resource.apiUrl, () => {
|
|
7643
7676
|
effectiveGridRef.current?.refresh();
|
|
7644
7677
|
}, resolvedBaseResource.mercure !== false);
|
|
@@ -7648,7 +7681,7 @@ function SmartCrudPage({ resource, fieldOverrides, formRef, onSelectionChanged,
|
|
|
7648
7681
|
...!hasManualFields ? { fields: gridFields } : {},
|
|
7649
7682
|
apiUrl: normalizedApiUrl,
|
|
7650
7683
|
fields: hasManualFields ? buildFields(resource.fields) : gridFields,
|
|
7651
|
-
formFields
|
|
7684
|
+
formFields,
|
|
7652
7685
|
formLayout: resolvedBaseResource.formLayout ?? inferredFormLayout,
|
|
7653
7686
|
_supportedOperations: supportedOperations
|
|
7654
7687
|
}), [
|
|
@@ -7657,7 +7690,7 @@ function SmartCrudPage({ resource, fieldOverrides, formRef, onSelectionChanged,
|
|
|
7657
7690
|
hasManualFields,
|
|
7658
7691
|
inferredFormLayout,
|
|
7659
7692
|
normalizedApiUrl,
|
|
7660
|
-
|
|
7693
|
+
formFields,
|
|
7661
7694
|
resolvedBaseResource,
|
|
7662
7695
|
resource.fields,
|
|
7663
7696
|
supportedOperations
|
package/dist/style.css
CHANGED
|
@@ -2926,6 +2926,7 @@ html[data-density=compact] .nb-datagrid .nb-badge {
|
|
|
2926
2926
|
font-size: var(--font-size-sm);
|
|
2927
2927
|
font-weight: var(--font-weight-semibold);
|
|
2928
2928
|
min-height: 38px;
|
|
2929
|
+
overflow: visible;
|
|
2929
2930
|
padding: 8px;
|
|
2930
2931
|
vertical-align: middle;
|
|
2931
2932
|
}
|
|
@@ -2949,7 +2950,8 @@ html[data-density=compact] .nb-datagrid .nb-badge {
|
|
|
2949
2950
|
background: var(--surface-2);
|
|
2950
2951
|
border-top: 0;
|
|
2951
2952
|
flex: 0 0 auto;
|
|
2952
|
-
overflow:
|
|
2953
|
+
overflow-x: auto;
|
|
2954
|
+
overflow-y: hidden;
|
|
2953
2955
|
scrollbar-width: none;
|
|
2954
2956
|
}
|
|
2955
2957
|
.nb-form__detail-summary-wrap::-webkit-scrollbar {
|
|
@@ -2962,10 +2964,12 @@ html[data-density=compact] .nb-datagrid .nb-badge {
|
|
|
2962
2964
|
}
|
|
2963
2965
|
|
|
2964
2966
|
.nb-form__detail-summary-cell {
|
|
2965
|
-
align-items:
|
|
2967
|
+
align-items: flex-end;
|
|
2966
2968
|
display: inline-flex;
|
|
2967
|
-
|
|
2969
|
+
flex-direction: column;
|
|
2970
|
+
gap: 2px;
|
|
2968
2971
|
min-width: 100%;
|
|
2972
|
+
overflow: visible;
|
|
2969
2973
|
}
|
|
2970
2974
|
|
|
2971
2975
|
.nb-form__detail-summary-label {
|
|
@@ -2978,9 +2982,12 @@ html[data-density=compact] .nb-datagrid .nb-badge {
|
|
|
2978
2982
|
|
|
2979
2983
|
.nb-form__detail-summary-value {
|
|
2980
2984
|
color: var(--text-primary);
|
|
2985
|
+
display: block;
|
|
2981
2986
|
font-size: var(--font-size-md);
|
|
2982
2987
|
font-weight: var(--font-weight-bold);
|
|
2988
|
+
max-width: none;
|
|
2983
2989
|
white-space: nowrap;
|
|
2990
|
+
width: max-content;
|
|
2984
2991
|
}
|
|
2985
2992
|
|
|
2986
2993
|
.nb-form__detail-table td .nb-form__control,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nubitio/crud",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.15",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Declarative CRUD engine with field DSL, forms, datagrids, RBAC, conditional logic and pluggable adapters (Hydra/REST).",
|
|
6
6
|
"license": "MIT",
|
|
@@ -56,8 +56,8 @@
|
|
|
56
56
|
"react-dom": "^19.0.0",
|
|
57
57
|
"react-i18next": "^14.0.0",
|
|
58
58
|
"react-router-dom": "^6.0.0",
|
|
59
|
-
"@nubitio/core": "^0.5.
|
|
60
|
-
"@nubitio/ui": "^0.5.
|
|
59
|
+
"@nubitio/core": "^0.5.15",
|
|
60
|
+
"@nubitio/ui": "^0.5.15"
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
63
|
"react-dropzone": "^15.0.0"
|