@nubitio/crud 0.5.19 → 0.5.20
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 +50 -34
- package/dist/index.mjs +50 -34
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -7466,14 +7466,15 @@ function ResourceSchemaProvider({ children, resolver }) {
|
|
|
7466
7466
|
children
|
|
7467
7467
|
});
|
|
7468
7468
|
}
|
|
7469
|
-
function resolveWithRuntimeErrors(resolver, supportedOperations = [], formLayout) {
|
|
7469
|
+
function resolveWithRuntimeErrors(resolver, supportedOperations = [], formLayout, workflow) {
|
|
7470
7470
|
try {
|
|
7471
7471
|
return {
|
|
7472
7472
|
fields: resolver(),
|
|
7473
7473
|
isLoading: false,
|
|
7474
7474
|
error: void 0,
|
|
7475
7475
|
supportedOperations,
|
|
7476
|
-
formLayout
|
|
7476
|
+
formLayout,
|
|
7477
|
+
workflow
|
|
7477
7478
|
};
|
|
7478
7479
|
} catch (runtimeError) {
|
|
7479
7480
|
return {
|
|
@@ -7481,7 +7482,8 @@ function resolveWithRuntimeErrors(resolver, supportedOperations = [], formLayout
|
|
|
7481
7482
|
isLoading: false,
|
|
7482
7483
|
error: runtimeError instanceof Error ? runtimeError : new Error(String(runtimeError)),
|
|
7483
7484
|
supportedOperations,
|
|
7484
|
-
formLayout
|
|
7485
|
+
formLayout,
|
|
7486
|
+
workflow
|
|
7485
7487
|
};
|
|
7486
7488
|
}
|
|
7487
7489
|
}
|
|
@@ -7507,7 +7509,7 @@ function useResolvedResourceFields({ apiUrl, manualFields, overrides, fieldContr
|
|
|
7507
7509
|
baselineFields: baseline.fields,
|
|
7508
7510
|
contract: fieldContract,
|
|
7509
7511
|
legacyOverrides: fieldContract ? void 0 : overrides
|
|
7510
|
-
}), baseline.supportedOperations, baseline.formLayout);
|
|
7512
|
+
}), baseline.supportedOperations, baseline.formLayout, baseline.workflow);
|
|
7511
7513
|
}, [
|
|
7512
7514
|
baseline,
|
|
7513
7515
|
fieldContract,
|
|
@@ -7515,6 +7517,28 @@ function useResolvedResourceFields({ apiUrl, manualFields, overrides, fieldContr
|
|
|
7515
7517
|
]);
|
|
7516
7518
|
}
|
|
7517
7519
|
//#endregion
|
|
7520
|
+
//#region packages/crud/workflow/buildWorkflowRowActions.ts
|
|
7521
|
+
function buildWorkflowRowActions(row, workflow, apiUrl, roles, onDone) {
|
|
7522
|
+
if (!workflow) return [];
|
|
7523
|
+
const current = String(row[workflow.field] ?? "");
|
|
7524
|
+
return workflow.transitions.filter((transition) => transition.from.includes(current)).filter((transition) => !transition.roles?.length || transition.roles.some((role) => roles.includes(role))).map((transition) => ({
|
|
7525
|
+
text: transition.label ?? transition.name,
|
|
7526
|
+
onClick: async () => {
|
|
7527
|
+
const base = apiUrl.replace(/\/$/, "");
|
|
7528
|
+
const id = row.id;
|
|
7529
|
+
const response = await fetch(`${base}/${id}/transition/${transition.name}`, {
|
|
7530
|
+
method: "POST",
|
|
7531
|
+
credentials: "include"
|
|
7532
|
+
});
|
|
7533
|
+
if (!response.ok) {
|
|
7534
|
+
const detail = await response.text().catch(() => "");
|
|
7535
|
+
throw new Error(detail || `Transition "${transition.name}" failed (${response.status})`);
|
|
7536
|
+
}
|
|
7537
|
+
onDone?.();
|
|
7538
|
+
}
|
|
7539
|
+
}));
|
|
7540
|
+
}
|
|
7541
|
+
//#endregion
|
|
7518
7542
|
//#region packages/crud/crud/SmartCrudPage.tsx
|
|
7519
7543
|
function CrudSkeleton() {
|
|
7520
7544
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -7587,7 +7611,7 @@ function SmartCrudPage({ resource, fieldOverrides, formRef, onSelectionChanged,
|
|
|
7587
7611
|
const effectiveGridRef = gridRef ?? internalGridRef;
|
|
7588
7612
|
const resolvedBaseResource = (0, react.useMemo)(() => resolveCrudResource(resource), [resource]);
|
|
7589
7613
|
const hasManualFields = !resource.fieldContract && Array.isArray(resource.fields) && resource.fields.length > 0;
|
|
7590
|
-
const { fields, isLoading, error, supportedOperations, formLayout: inferredFormLayout } = useResolvedResourceFields({
|
|
7614
|
+
const { fields, isLoading, error, supportedOperations, formLayout: inferredFormLayout, workflow } = useResolvedResourceFields({
|
|
7591
7615
|
apiUrl: resolvedBaseResource.apiUrl,
|
|
7592
7616
|
manualFields: hasManualFields ? buildFields(resource.fields) : void 0,
|
|
7593
7617
|
overrides: hasManualFields ? void 0 : fieldOverrides,
|
|
@@ -7611,21 +7635,29 @@ function SmartCrudPage({ resource, fieldOverrides, formRef, onSelectionChanged,
|
|
|
7611
7635
|
const routingState = useRouting(resource.routing);
|
|
7612
7636
|
const { activeOperation, formData, handleFormDataChange, startCreate, startEdit, resetOperation } = useSmartCrudOperation(void 0, routingState);
|
|
7613
7637
|
const roles = useSmartCrudRoles();
|
|
7614
|
-
const
|
|
7638
|
+
const stableRoles = (0, react.useMemo)(() => roles ?? [], [roles]);
|
|
7639
|
+
const { gridFields, processedFields, computedValues } = useSmartCrudFields(fields, activeOperation, formData, stableRoles);
|
|
7615
7640
|
const formFields = (0, react.useMemo)(() => applyFormDetailFormFieldOverrides(processedFields, resolvedBaseResource.formDetail), [processedFields, resolvedBaseResource.formDetail]);
|
|
7616
7641
|
(0, _nubitio_core.useMercureSubscription)(resource.apiUrl, () => {
|
|
7617
7642
|
effectiveGridRef.current?.refresh();
|
|
7618
7643
|
}, resolvedBaseResource.mercure !== false);
|
|
7619
7644
|
const normalizedApiUrl = resolvedBaseResource.apiUrl.startsWith("/") ? resolvedBaseResource.apiUrl : `/${resolvedBaseResource.apiUrl}`;
|
|
7620
|
-
const resolvedResource = (0, react.useMemo)(() =>
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
|
|
7626
|
-
|
|
7627
|
-
|
|
7628
|
-
|
|
7645
|
+
const resolvedResource = (0, react.useMemo)(() => {
|
|
7646
|
+
const rowActions = resolvedBaseResource.rowActions ?? (workflow ? (row) => buildWorkflowRowActions(row, workflow, normalizedApiUrl, stableRoles, () => {
|
|
7647
|
+
effectiveGridRef.current?.refresh();
|
|
7648
|
+
}) : void 0);
|
|
7649
|
+
return {
|
|
7650
|
+
...resolvedBaseResource,
|
|
7651
|
+
...!hasManualFields ? { fields: gridFields } : {},
|
|
7652
|
+
apiUrl: normalizedApiUrl,
|
|
7653
|
+
fields: hasManualFields ? buildFields(resource.fields) : gridFields,
|
|
7654
|
+
formFields,
|
|
7655
|
+
formLayout: resolvedBaseResource.formLayout ?? inferredFormLayout,
|
|
7656
|
+
_supportedOperations: supportedOperations,
|
|
7657
|
+
rowActions
|
|
7658
|
+
};
|
|
7659
|
+
}, [
|
|
7660
|
+
effectiveGridRef,
|
|
7629
7661
|
fields,
|
|
7630
7662
|
gridFields,
|
|
7631
7663
|
hasManualFields,
|
|
@@ -7634,7 +7666,9 @@ function SmartCrudPage({ resource, fieldOverrides, formRef, onSelectionChanged,
|
|
|
7634
7666
|
formFields,
|
|
7635
7667
|
resolvedBaseResource,
|
|
7636
7668
|
resource.fields,
|
|
7637
|
-
|
|
7669
|
+
stableRoles,
|
|
7670
|
+
supportedOperations,
|
|
7671
|
+
workflow
|
|
7638
7672
|
]);
|
|
7639
7673
|
if (!hasManualFields && isLoading) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CrudSkeleton, {});
|
|
7640
7674
|
if (!hasManualFields && error) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CrudError, {
|
|
@@ -8460,24 +8494,6 @@ function ToolbarSelect({ id, label, icon = "ph-funnel", value, options, onChange
|
|
|
8460
8494
|
});
|
|
8461
8495
|
}
|
|
8462
8496
|
//#endregion
|
|
8463
|
-
//#region packages/crud/workflow/buildWorkflowRowActions.ts
|
|
8464
|
-
function buildWorkflowRowActions(row, workflow, apiUrl, roles, onDone) {
|
|
8465
|
-
if (!workflow) return [];
|
|
8466
|
-
const current = String(row[workflow.field] ?? "");
|
|
8467
|
-
return workflow.transitions.filter((transition) => transition.from.includes(current)).filter((transition) => !transition.roles?.length || transition.roles.some((role) => roles.includes(role))).map((transition) => ({
|
|
8468
|
-
text: transition.label ?? transition.name,
|
|
8469
|
-
onClick: async () => {
|
|
8470
|
-
const base = apiUrl.replace(/\/$/, "");
|
|
8471
|
-
const id = row.id;
|
|
8472
|
-
await fetch(`${base}/${id}/transition/${transition.name}`, {
|
|
8473
|
-
method: "POST",
|
|
8474
|
-
credentials: "include"
|
|
8475
|
-
});
|
|
8476
|
-
onDone?.();
|
|
8477
|
-
}
|
|
8478
|
-
}));
|
|
8479
|
-
}
|
|
8480
|
-
//#endregion
|
|
8481
8497
|
//#region packages/crud/adapter/RestAdapter.ts
|
|
8482
8498
|
/**
|
|
8483
8499
|
* Backend adapter for plain OpenAPI / REST backends.
|
package/dist/index.mjs
CHANGED
|
@@ -7442,14 +7442,15 @@ function ResourceSchemaProvider({ children, resolver }) {
|
|
|
7442
7442
|
children
|
|
7443
7443
|
});
|
|
7444
7444
|
}
|
|
7445
|
-
function resolveWithRuntimeErrors(resolver, supportedOperations = [], formLayout) {
|
|
7445
|
+
function resolveWithRuntimeErrors(resolver, supportedOperations = [], formLayout, workflow) {
|
|
7446
7446
|
try {
|
|
7447
7447
|
return {
|
|
7448
7448
|
fields: resolver(),
|
|
7449
7449
|
isLoading: false,
|
|
7450
7450
|
error: void 0,
|
|
7451
7451
|
supportedOperations,
|
|
7452
|
-
formLayout
|
|
7452
|
+
formLayout,
|
|
7453
|
+
workflow
|
|
7453
7454
|
};
|
|
7454
7455
|
} catch (runtimeError) {
|
|
7455
7456
|
return {
|
|
@@ -7457,7 +7458,8 @@ function resolveWithRuntimeErrors(resolver, supportedOperations = [], formLayout
|
|
|
7457
7458
|
isLoading: false,
|
|
7458
7459
|
error: runtimeError instanceof Error ? runtimeError : new Error(String(runtimeError)),
|
|
7459
7460
|
supportedOperations,
|
|
7460
|
-
formLayout
|
|
7461
|
+
formLayout,
|
|
7462
|
+
workflow
|
|
7461
7463
|
};
|
|
7462
7464
|
}
|
|
7463
7465
|
}
|
|
@@ -7483,7 +7485,7 @@ function useResolvedResourceFields({ apiUrl, manualFields, overrides, fieldContr
|
|
|
7483
7485
|
baselineFields: baseline.fields,
|
|
7484
7486
|
contract: fieldContract,
|
|
7485
7487
|
legacyOverrides: fieldContract ? void 0 : overrides
|
|
7486
|
-
}), baseline.supportedOperations, baseline.formLayout);
|
|
7488
|
+
}), baseline.supportedOperations, baseline.formLayout, baseline.workflow);
|
|
7487
7489
|
}, [
|
|
7488
7490
|
baseline,
|
|
7489
7491
|
fieldContract,
|
|
@@ -7491,6 +7493,28 @@ function useResolvedResourceFields({ apiUrl, manualFields, overrides, fieldContr
|
|
|
7491
7493
|
]);
|
|
7492
7494
|
}
|
|
7493
7495
|
//#endregion
|
|
7496
|
+
//#region packages/crud/workflow/buildWorkflowRowActions.ts
|
|
7497
|
+
function buildWorkflowRowActions(row, workflow, apiUrl, roles, onDone) {
|
|
7498
|
+
if (!workflow) return [];
|
|
7499
|
+
const current = String(row[workflow.field] ?? "");
|
|
7500
|
+
return workflow.transitions.filter((transition) => transition.from.includes(current)).filter((transition) => !transition.roles?.length || transition.roles.some((role) => roles.includes(role))).map((transition) => ({
|
|
7501
|
+
text: transition.label ?? transition.name,
|
|
7502
|
+
onClick: async () => {
|
|
7503
|
+
const base = apiUrl.replace(/\/$/, "");
|
|
7504
|
+
const id = row.id;
|
|
7505
|
+
const response = await fetch(`${base}/${id}/transition/${transition.name}`, {
|
|
7506
|
+
method: "POST",
|
|
7507
|
+
credentials: "include"
|
|
7508
|
+
});
|
|
7509
|
+
if (!response.ok) {
|
|
7510
|
+
const detail = await response.text().catch(() => "");
|
|
7511
|
+
throw new Error(detail || `Transition "${transition.name}" failed (${response.status})`);
|
|
7512
|
+
}
|
|
7513
|
+
onDone?.();
|
|
7514
|
+
}
|
|
7515
|
+
}));
|
|
7516
|
+
}
|
|
7517
|
+
//#endregion
|
|
7494
7518
|
//#region packages/crud/crud/SmartCrudPage.tsx
|
|
7495
7519
|
function CrudSkeleton() {
|
|
7496
7520
|
return /* @__PURE__ */ jsxs("div", {
|
|
@@ -7563,7 +7587,7 @@ function SmartCrudPage({ resource, fieldOverrides, formRef, onSelectionChanged,
|
|
|
7563
7587
|
const effectiveGridRef = gridRef ?? internalGridRef;
|
|
7564
7588
|
const resolvedBaseResource = useMemo(() => resolveCrudResource(resource), [resource]);
|
|
7565
7589
|
const hasManualFields = !resource.fieldContract && Array.isArray(resource.fields) && resource.fields.length > 0;
|
|
7566
|
-
const { fields, isLoading, error, supportedOperations, formLayout: inferredFormLayout } = useResolvedResourceFields({
|
|
7590
|
+
const { fields, isLoading, error, supportedOperations, formLayout: inferredFormLayout, workflow } = useResolvedResourceFields({
|
|
7567
7591
|
apiUrl: resolvedBaseResource.apiUrl,
|
|
7568
7592
|
manualFields: hasManualFields ? buildFields(resource.fields) : void 0,
|
|
7569
7593
|
overrides: hasManualFields ? void 0 : fieldOverrides,
|
|
@@ -7587,21 +7611,29 @@ function SmartCrudPage({ resource, fieldOverrides, formRef, onSelectionChanged,
|
|
|
7587
7611
|
const routingState = useRouting(resource.routing);
|
|
7588
7612
|
const { activeOperation, formData, handleFormDataChange, startCreate, startEdit, resetOperation } = useSmartCrudOperation(void 0, routingState);
|
|
7589
7613
|
const roles = useSmartCrudRoles();
|
|
7590
|
-
const
|
|
7614
|
+
const stableRoles = useMemo(() => roles ?? [], [roles]);
|
|
7615
|
+
const { gridFields, processedFields, computedValues } = useSmartCrudFields(fields, activeOperation, formData, stableRoles);
|
|
7591
7616
|
const formFields = useMemo(() => applyFormDetailFormFieldOverrides(processedFields, resolvedBaseResource.formDetail), [processedFields, resolvedBaseResource.formDetail]);
|
|
7592
7617
|
useMercureSubscription(resource.apiUrl, () => {
|
|
7593
7618
|
effectiveGridRef.current?.refresh();
|
|
7594
7619
|
}, resolvedBaseResource.mercure !== false);
|
|
7595
7620
|
const normalizedApiUrl = resolvedBaseResource.apiUrl.startsWith("/") ? resolvedBaseResource.apiUrl : `/${resolvedBaseResource.apiUrl}`;
|
|
7596
|
-
const resolvedResource = useMemo(() =>
|
|
7597
|
-
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
|
|
7604
|
-
|
|
7621
|
+
const resolvedResource = useMemo(() => {
|
|
7622
|
+
const rowActions = resolvedBaseResource.rowActions ?? (workflow ? (row) => buildWorkflowRowActions(row, workflow, normalizedApiUrl, stableRoles, () => {
|
|
7623
|
+
effectiveGridRef.current?.refresh();
|
|
7624
|
+
}) : void 0);
|
|
7625
|
+
return {
|
|
7626
|
+
...resolvedBaseResource,
|
|
7627
|
+
...!hasManualFields ? { fields: gridFields } : {},
|
|
7628
|
+
apiUrl: normalizedApiUrl,
|
|
7629
|
+
fields: hasManualFields ? buildFields(resource.fields) : gridFields,
|
|
7630
|
+
formFields,
|
|
7631
|
+
formLayout: resolvedBaseResource.formLayout ?? inferredFormLayout,
|
|
7632
|
+
_supportedOperations: supportedOperations,
|
|
7633
|
+
rowActions
|
|
7634
|
+
};
|
|
7635
|
+
}, [
|
|
7636
|
+
effectiveGridRef,
|
|
7605
7637
|
fields,
|
|
7606
7638
|
gridFields,
|
|
7607
7639
|
hasManualFields,
|
|
@@ -7610,7 +7642,9 @@ function SmartCrudPage({ resource, fieldOverrides, formRef, onSelectionChanged,
|
|
|
7610
7642
|
formFields,
|
|
7611
7643
|
resolvedBaseResource,
|
|
7612
7644
|
resource.fields,
|
|
7613
|
-
|
|
7645
|
+
stableRoles,
|
|
7646
|
+
supportedOperations,
|
|
7647
|
+
workflow
|
|
7614
7648
|
]);
|
|
7615
7649
|
if (!hasManualFields && isLoading) return /* @__PURE__ */ jsx(CrudSkeleton, {});
|
|
7616
7650
|
if (!hasManualFields && error) return /* @__PURE__ */ jsx(CrudError, {
|
|
@@ -8436,24 +8470,6 @@ function ToolbarSelect({ id, label, icon = "ph-funnel", value, options, onChange
|
|
|
8436
8470
|
});
|
|
8437
8471
|
}
|
|
8438
8472
|
//#endregion
|
|
8439
|
-
//#region packages/crud/workflow/buildWorkflowRowActions.ts
|
|
8440
|
-
function buildWorkflowRowActions(row, workflow, apiUrl, roles, onDone) {
|
|
8441
|
-
if (!workflow) return [];
|
|
8442
|
-
const current = String(row[workflow.field] ?? "");
|
|
8443
|
-
return workflow.transitions.filter((transition) => transition.from.includes(current)).filter((transition) => !transition.roles?.length || transition.roles.some((role) => roles.includes(role))).map((transition) => ({
|
|
8444
|
-
text: transition.label ?? transition.name,
|
|
8445
|
-
onClick: async () => {
|
|
8446
|
-
const base = apiUrl.replace(/\/$/, "");
|
|
8447
|
-
const id = row.id;
|
|
8448
|
-
await fetch(`${base}/${id}/transition/${transition.name}`, {
|
|
8449
|
-
method: "POST",
|
|
8450
|
-
credentials: "include"
|
|
8451
|
-
});
|
|
8452
|
-
onDone?.();
|
|
8453
|
-
}
|
|
8454
|
-
}));
|
|
8455
|
-
}
|
|
8456
|
-
//#endregion
|
|
8457
8473
|
//#region packages/crud/adapter/RestAdapter.ts
|
|
8458
8474
|
/**
|
|
8459
8475
|
* Backend adapter for plain OpenAPI / REST backends.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nubitio/crud",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.20",
|
|
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,7 +56,7 @@
|
|
|
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.20",
|
|
60
|
+
"@nubitio/ui": "^0.5.20"
|
|
61
61
|
}
|
|
62
62
|
}
|