@nocobase/client-v2 2.1.0-alpha.40 → 2.1.0-alpha.45
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/es/Application.d.ts +7 -0
- package/es/BaseApplication.d.ts +13 -0
- package/es/RouterManager.d.ts +1 -0
- package/es/collection-field-interface/CollectionFieldInterface.d.ts +51 -15
- package/es/collection-field-interface/CollectionFieldInterfaceManager.d.ts +82 -3
- package/es/collection-manager/field-configure.d.ts +80 -0
- package/es/collection-manager/field-validation.d.ts +43 -0
- package/es/collection-manager/filter-operators/index.d.ts +46 -0
- package/es/collection-manager/filter-operators/operators.d.ts +30 -0
- package/es/collection-manager/interfaces/checkbox.d.ts +1 -41
- package/es/collection-manager/interfaces/checkboxGroup.d.ts +12 -44
- package/es/collection-manager/interfaces/collection.d.ts +12 -51
- package/es/collection-manager/interfaces/color.d.ts +1 -16
- package/es/collection-manager/interfaces/createdAt.d.ts +1 -44
- package/es/collection-manager/interfaces/createdBy.d.ts +0 -4
- package/es/collection-manager/interfaces/dateOnly.d.ts +7 -44
- package/es/collection-manager/interfaces/datetime.d.ts +1 -44
- package/es/collection-manager/interfaces/datetimeNoTz.d.ts +1 -44
- package/es/collection-manager/interfaces/email.d.ts +1 -29
- package/es/collection-manager/interfaces/id.d.ts +1 -16
- package/es/collection-manager/interfaces/index.d.ts +2 -3
- package/es/collection-manager/interfaces/input.d.ts +1 -102
- package/es/collection-manager/interfaces/integer.d.ts +1 -95
- package/es/collection-manager/interfaces/json.d.ts +16 -7
- package/es/collection-manager/interfaces/m2m.d.ts +11 -19
- package/es/collection-manager/interfaces/m2o.d.ts +11 -19
- package/es/collection-manager/interfaces/markdown.d.ts +1 -63
- package/es/collection-manager/interfaces/multipleSelect.d.ts +12 -44
- package/es/collection-manager/interfaces/nanoid.d.ts +1 -34
- package/es/collection-manager/interfaces/number.d.ts +1 -87
- package/es/collection-manager/interfaces/o2m.d.ts +12 -24
- package/es/collection-manager/interfaces/obo.d.ts +207 -0
- package/es/collection-manager/interfaces/oho.d.ts +207 -0
- package/es/collection-manager/interfaces/password.d.ts +1 -56
- package/es/collection-manager/interfaces/percent.d.ts +1 -84
- package/es/collection-manager/interfaces/phone.d.ts +1 -25
- package/es/collection-manager/interfaces/properties/index.d.ts +0 -28
- package/es/collection-manager/interfaces/radioGroup.d.ts +1 -29
- package/es/collection-manager/interfaces/richText.d.ts +1 -63
- package/es/collection-manager/interfaces/select.d.ts +12 -44
- package/es/collection-manager/interfaces/snowflake-id.d.ts +1 -34
- package/es/collection-manager/interfaces/tableoid.d.ts +1 -10
- package/es/collection-manager/interfaces/textarea.d.ts +1 -51
- package/es/collection-manager/interfaces/time.d.ts +1 -16
- package/es/collection-manager/interfaces/types.d.ts +3 -12
- package/es/collection-manager/interfaces/unixTimestamp.d.ts +1 -44
- package/es/collection-manager/interfaces/updatedAt.d.ts +1 -44
- package/es/collection-manager/interfaces/updatedBy.d.ts +0 -4
- package/es/collection-manager/interfaces/url.d.ts +1 -20
- package/es/collection-manager/interfaces/uuid.d.ts +1 -34
- package/es/collection-manager/template-fields.d.ts +53 -0
- package/es/components/KeepAlive.d.ts +22 -0
- package/es/components/RouterBridge.d.ts +9 -0
- package/es/components/form/DialogFormLayout.d.ts +5 -29
- package/es/components/form/VariableInput.d.ts +53 -2
- package/es/components/form/filter/CollectionFilter.d.ts +49 -0
- package/es/components/form/filter/CollectionFilterItem.d.ts +49 -0
- package/es/components/form/filter/DateFilterDynamicComponent.d.ts +57 -0
- package/es/components/form/filter/FilterValueInput.d.ts +29 -0
- package/es/components/form/filter/index.d.ts +11 -0
- package/es/components/form/filter/useFilterActionProps.d.ts +96 -0
- package/es/components/form/index.d.ts +1 -0
- package/es/data-source/ExtendCollectionsProvider.d.ts +50 -0
- package/es/data-source/index.d.ts +9 -0
- package/es/flow/FlowPage.d.ts +2 -1
- package/es/flow/admin-shell/AdminLayoutRouteCoordinator.d.ts +8 -40
- package/es/flow/admin-shell/BaseLayoutModel.d.ts +89 -0
- package/es/flow/admin-shell/BaseLayoutRouteCoordinator.d.ts +74 -0
- package/es/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.d.ts +12 -0
- package/es/flow/admin-shell/admin-layout/AdminLayoutModel.d.ts +7 -92
- package/es/flow/admin-shell/admin-layout/AppListRender.d.ts +11 -0
- package/es/flow/admin-shell/admin-layout/index.d.ts +3 -0
- package/es/flow/admin-shell/admin-layout/useApplications.d.ts +3 -2
- package/es/flow/admin-shell/useAdminLayoutRoutePage.d.ts +2 -2
- package/es/flow/admin-shell/useLayoutRoutePage.d.ts +23 -0
- package/es/flow/components/FlowRoute.d.ts +10 -1
- package/es/flow/components/filter/index.d.ts +2 -0
- package/es/flow/components/filter/useFilterOptions.d.ts +66 -0
- package/es/flow/index.d.ts +4 -0
- package/es/flow/models/base/PageModel/PageModel.d.ts +3 -1
- package/es/flow/models/blocks/assign-form/assignFieldValuesFlow.d.ts +84 -0
- package/es/flow/models/blocks/assign-form/index.d.ts +1 -0
- package/es/flow/models/blocks/form/FormActionGroupModel.d.ts +1 -0
- package/es/flow/models/blocks/form/FormActionModel.d.ts +9 -2
- package/es/flow/models/blocks/table/TableBlockModel.d.ts +10 -0
- package/es/flow/models/fields/AssociationFieldModel/SubTableFieldModel/index.d.ts +1 -1
- package/es/flow-compat/passwordUtils.d.ts +1 -1
- package/es/index.d.ts +6 -0
- package/es/index.mjs +552 -459
- package/es/layout-manager/LayoutContentRoute.d.ts +14 -0
- package/es/layout-manager/LayoutManager.d.ts +22 -0
- package/es/layout-manager/LayoutRoute.d.ts +14 -0
- package/es/layout-manager/index.d.ts +13 -0
- package/es/layout-manager/types.d.ts +20 -0
- package/es/layout-manager/utils.d.ts +14 -0
- package/es/nocobase-buildin-plugin/index.d.ts +3 -10
- package/es/settings-center/index.d.ts +1 -1
- package/es/settings-center/plugin-manager/BulkEnableButton.d.ts +15 -0
- package/es/settings-center/plugin-manager/PluginCard.d.ts +15 -0
- package/es/settings-center/plugin-manager/PluginDetail.d.ts +16 -0
- package/es/settings-center/{PluginManagerPage.d.ts → plugin-manager/index.d.ts} +1 -7
- package/es/settings-center/plugin-manager/types.d.ts +34 -0
- package/lib/index.js +552 -459
- package/package.json +8 -7
- package/src/Application.tsx +51 -12
- package/src/BaseApplication.tsx +32 -0
- package/src/PluginSettingsManager.ts +1 -1
- package/src/RouterManager.tsx +17 -1
- package/src/__tests__/PluginSettingsManager.test.ts +41 -2
- package/src/__tests__/app.test.tsx +17 -1
- package/src/__tests__/globalDeps.test.ts +1 -0
- package/src/__tests__/nocobase-buildin-plugin-auth.test.tsx +45 -2
- package/src/__tests__/plugin-manager.test.tsx +177 -0
- package/src/__tests__/settings-center.test.tsx +24 -2
- package/src/collection-field-interface/CollectionFieldInterface.ts +71 -77
- package/src/collection-field-interface/CollectionFieldInterfaceManager.ts +201 -4
- package/src/collection-manager/field-configure.ts +548 -0
- package/src/collection-manager/field-validation.ts +195 -0
- package/src/collection-manager/filter-operators/index.ts +176 -0
- package/src/collection-manager/{interfaces/properties → filter-operators}/operators.ts +24 -13
- package/src/collection-manager/interfaces/checkbox.ts +2 -9
- package/src/collection-manager/interfaces/checkboxGroup.ts +2 -10
- package/src/collection-manager/interfaces/collection.ts +2 -15
- package/src/collection-manager/interfaces/color.ts +2 -2
- package/src/collection-manager/interfaces/createdAt.ts +2 -2
- package/src/collection-manager/interfaces/createdBy.ts +1 -12
- package/src/collection-manager/interfaces/dateOnly.ts +8 -2
- package/src/collection-manager/interfaces/datetime.ts +2 -2
- package/src/collection-manager/interfaces/datetimeNoTz.ts +2 -2
- package/src/collection-manager/interfaces/email.ts +2 -9
- package/src/collection-manager/interfaces/id.ts +1 -2
- package/src/collection-manager/interfaces/index.ts +2 -3
- package/src/collection-manager/interfaces/input.ts +2 -133
- package/src/collection-manager/interfaces/integer.ts +2 -71
- package/src/collection-manager/interfaces/json.tsx +17 -11
- package/src/collection-manager/interfaces/m2m.tsx +0 -21
- package/src/collection-manager/interfaces/m2o.tsx +0 -22
- package/src/collection-manager/interfaces/markdown.ts +2 -51
- package/src/collection-manager/interfaces/multipleSelect.ts +2 -14
- package/src/collection-manager/interfaces/nanoid.ts +2 -2
- package/src/collection-manager/interfaces/number.ts +2 -85
- package/src/collection-manager/interfaces/o2m.tsx +1 -22
- package/src/collection-manager/interfaces/obo.tsx +145 -0
- package/src/collection-manager/interfaces/oho.tsx +145 -0
- package/src/collection-manager/interfaces/password.ts +2 -44
- package/src/collection-manager/interfaces/percent.ts +2 -74
- package/src/collection-manager/interfaces/phone.ts +2 -2
- package/src/collection-manager/interfaces/properties/index.ts +0 -133
- package/src/collection-manager/interfaces/radioGroup.ts +2 -2
- package/src/collection-manager/interfaces/richText.ts +2 -51
- package/src/collection-manager/interfaces/select.ts +2 -14
- package/src/collection-manager/interfaces/snowflake-id.ts +2 -2
- package/src/collection-manager/interfaces/tableoid.ts +1 -2
- package/src/collection-manager/interfaces/textarea.ts +2 -51
- package/src/collection-manager/interfaces/time.ts +2 -2
- package/src/collection-manager/interfaces/types.ts +4 -12
- package/src/collection-manager/interfaces/unixTimestamp.tsx +2 -2
- package/src/collection-manager/interfaces/updatedAt.ts +2 -2
- package/src/collection-manager/interfaces/updatedBy.ts +1 -12
- package/src/collection-manager/interfaces/url.ts +2 -4
- package/src/collection-manager/interfaces/uuid.ts +2 -2
- package/src/collection-manager/template-fields.ts +109 -0
- package/src/components/KeepAlive.tsx +131 -0
- package/src/components/README.md +90 -6
- package/src/components/README.zh-CN.md +90 -7
- package/src/components/RouterBridge.tsx +28 -4
- package/src/components/__tests__/KeepAlive.test.tsx +63 -0
- package/src/components/__tests__/RouterBridge.test.tsx +27 -0
- package/src/components/form/DialogFormLayout.tsx +5 -29
- package/src/components/form/VariableInput.tsx +101 -28
- package/src/components/form/__tests__/VariableInput.test.ts +85 -0
- package/src/components/form/filter/CollectionFilter.tsx +111 -0
- package/src/components/form/filter/CollectionFilterItem.tsx +184 -0
- package/src/components/form/filter/DateFilterDynamicComponent.tsx +283 -0
- package/src/components/form/filter/FilterValueInput.tsx +198 -0
- package/src/components/form/filter/__tests__/CollectionFilterItem.test.tsx +247 -0
- package/src/components/form/filter/__tests__/DateFilterDynamicComponent.test.tsx +148 -0
- package/src/components/form/filter/__tests__/FilterValueInput.test.tsx +243 -0
- package/src/components/form/filter/__tests__/compileFilterGroup.test.ts +146 -0
- package/src/components/form/filter/index.ts +13 -0
- package/src/components/form/filter/useFilterActionProps.ts +203 -0
- package/src/components/form/index.tsx +1 -0
- package/src/data-source/ExtendCollectionsProvider.tsx +144 -0
- package/src/data-source/__tests__/ExtendCollectionsProvider.test.tsx +264 -0
- package/src/data-source/index.ts +10 -0
- package/src/flow/FlowPage.tsx +35 -7
- package/src/flow/__tests__/FlowPage.test.tsx +79 -0
- package/src/flow/__tests__/FlowRoute.test.tsx +529 -2
- package/src/flow/actions/__tests__/linkageRules.subFormSetFieldProps.test.ts +191 -0
- package/src/flow/actions/__tests__/openView.subModelKey.test.tsx +33 -0
- package/src/flow/actions/aclCheck.tsx +4 -0
- package/src/flow/actions/aclCheckRefresh.tsx +4 -0
- package/src/flow/actions/dateTimeFormat.tsx +12 -8
- package/src/flow/actions/linkageRules.tsx +122 -0
- package/src/flow/actions/openView.tsx +28 -4
- package/src/flow/admin-shell/AdminLayoutRouteCoordinator.ts +11 -329
- package/src/flow/admin-shell/BaseLayoutModel.tsx +455 -0
- package/src/flow/admin-shell/BaseLayoutRouteCoordinator.ts +502 -0
- package/src/flow/admin-shell/__tests__/AdminLayoutRouteCoordinator.test.ts +547 -3
- package/src/flow/admin-shell/admin-layout/AdminLayoutComponent.tsx +35 -7
- package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.tsx +160 -0
- package/src/flow/admin-shell/admin-layout/AdminLayoutMenuModels.tsx +0 -12
- package/src/flow/admin-shell/admin-layout/AdminLayoutModel.tsx +28 -201
- package/src/flow/admin-shell/admin-layout/AdminLayoutSlotModels.tsx +11 -2
- package/src/flow/admin-shell/admin-layout/AppListRender.tsx +139 -0
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutMenuModels.test.ts +1 -26
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutModel.test.tsx +149 -27
- package/src/flow/admin-shell/admin-layout/index.ts +3 -0
- package/src/flow/admin-shell/admin-layout/useApplications.tsx +34 -1
- package/src/flow/admin-shell/useAdminLayoutRoutePage.ts +10 -26
- package/src/flow/admin-shell/useLayoutRoutePage.ts +61 -0
- package/src/flow/components/AdminLayout.tsx +4 -154
- package/src/flow/components/FlowRoute.tsx +105 -15
- package/src/flow/components/filter/index.ts +3 -0
- package/src/flow/components/filter/useFilterOptions.ts +102 -0
- package/src/flow/index.ts +4 -0
- package/src/flow/models/actions/UpdateRecordActionModel.tsx +14 -95
- package/src/flow/models/actions/UpdateRecordActionUtils.ts +4 -7
- package/src/flow/models/actions/__tests__/AssignFormRefill.test.ts +26 -1
- package/src/flow/models/base/ActionModel.tsx +8 -1
- package/src/flow/models/base/PageModel/PageModel.tsx +51 -18
- package/src/flow/models/base/PageModel/RootPageModel.tsx +6 -13
- package/src/flow/models/base/PageModel/__tests__/PageModel.test.ts +102 -1
- package/src/flow/models/base/RouteModel.tsx +1 -1
- package/src/flow/models/blocks/assign-form/AssignFormItemModel.tsx +63 -2
- package/src/flow/models/blocks/assign-form/assignFieldValuesFlow.tsx +206 -0
- package/src/flow/models/blocks/assign-form/index.ts +1 -0
- package/src/flow/models/blocks/form/FormActionGroupModel.tsx +14 -0
- package/src/flow/models/blocks/form/FormActionModel.tsx +30 -3
- package/src/flow/models/blocks/form/FormItemModel.tsx +8 -1
- package/src/flow/models/blocks/form/__tests__/FormActionGroupModel.test.ts +46 -0
- package/src/flow/models/blocks/form/__tests__/submitHandler.test.ts +71 -0
- package/src/flow/models/blocks/form/submitHandler.ts +8 -1
- package/src/flow/models/blocks/form/submitValues.ts +4 -1
- package/src/flow/models/blocks/table/TableBlockModel.tsx +118 -16
- package/src/flow/models/blocks/table/__tests__/TableBlockModel.rowSelection.test.tsx +114 -0
- package/src/flow/models/fields/AssociationFieldModel/SubFormFieldModel.tsx +7 -1
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableField.tsx +1 -1
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/index.tsx +6 -5
- package/src/flow/models/fields/ClickableFieldModel.tsx +9 -1
- package/src/flow/models/fields/CollectionSelectorFieldModel.tsx +8 -2
- package/src/flow/models/fields/DisplayEnumFieldModel.tsx +8 -2
- package/src/flow/models/fields/DisplayTimeFieldModel.tsx +1 -1
- package/src/flow/models/fields/TimeFieldModel.tsx +1 -1
- package/src/flow/models/fields/__tests__/TimeFieldModel.test.tsx +61 -0
- package/src/flow/models/fields/mobile-components/MobileDatePicker.tsx +19 -3
- package/src/flow/models/fields/mobile-components/__tests__/MobileDatePicker.test.tsx +94 -0
- package/src/flow/models/topbar/TopbarActionModel.tsx +1 -1
- package/src/flow/utils/__tests__/dateTimeFormat.test.ts +91 -0
- package/src/index.ts +6 -0
- package/src/layout-manager/LayoutContentRoute.tsx +90 -0
- package/src/layout-manager/LayoutManager.tsx +185 -0
- package/src/layout-manager/LayoutRoute.tsx +138 -0
- package/src/layout-manager/__tests__/LayoutManager.test.tsx +335 -0
- package/src/layout-manager/__tests__/LayoutRoute.test.tsx +473 -0
- package/src/layout-manager/index.ts +14 -0
- package/src/layout-manager/types.ts +22 -0
- package/src/layout-manager/utils.ts +37 -0
- package/src/nocobase-buildin-plugin/index.tsx +69 -67
- package/src/nocobase-buildin-plugin/plugins/LocalePlugin.ts +1 -0
- package/src/settings-center/index.ts +1 -1
- package/src/settings-center/plugin-manager/BulkEnableButton.tsx +111 -0
- package/src/settings-center/plugin-manager/PluginCard.tsx +270 -0
- package/src/settings-center/plugin-manager/PluginDetail.tsx +195 -0
- package/src/settings-center/plugin-manager/index.tsx +254 -0
- package/src/settings-center/plugin-manager/types.ts +35 -0
- package/src/settings-center/utils.tsx +8 -1
- package/src/theme/__tests__/globalStyles.test.ts +24 -0
- package/src/theme/globalStyles.ts +10 -0
- package/src/utils/globalDeps.ts +2 -0
- package/es/collection-manager/interfaces/linkTo.d.ts +0 -90
- package/es/collection-manager/interfaces/o2o.d.ts +0 -621
- package/es/collection-manager/interfaces/properties/operators.d.ts +0 -294
- package/es/collection-manager/interfaces/subTable.d.ts +0 -172
- package/src/collection-manager/interfaces/linkTo.ts +0 -120
- package/src/collection-manager/interfaces/o2o.tsx +0 -561
- package/src/collection-manager/interfaces/subTable.ts +0 -218
- package/src/settings-center/PluginManagerPage.tsx +0 -162
|
@@ -68,22 +68,15 @@ export class RootPageModel extends PageModel {
|
|
|
68
68
|
reaction(
|
|
69
69
|
() => this.context.pageActive.value,
|
|
70
70
|
() => {
|
|
71
|
+
if (this.context.view?.inputArgs?.activationControlledByLayout) {
|
|
72
|
+
this.mounted = true;
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
71
75
|
if (this.context.pageActive.value && this.mounted) {
|
|
72
|
-
|
|
73
|
-
if (firstTab) {
|
|
74
|
-
this.setProps('tabActiveKey', firstTab.uid);
|
|
75
|
-
this.invokeTabModelLifecycleMethod(firstTab.uid, 'onActive', true);
|
|
76
|
-
}
|
|
76
|
+
this.activateCurrentTab(true);
|
|
77
77
|
}
|
|
78
78
|
if (this.context.pageActive.value === false) {
|
|
79
|
-
|
|
80
|
-
this.invokeTabModelLifecycleMethod(this.props.tabActiveKey, 'onInactive');
|
|
81
|
-
} else {
|
|
82
|
-
const firstTab = this.subModels.tabs?.[0];
|
|
83
|
-
if (firstTab) {
|
|
84
|
-
this.invokeTabModelLifecycleMethod(firstTab.uid, 'onInactive');
|
|
85
|
-
}
|
|
86
|
-
}
|
|
79
|
+
this.deactivateCurrentTab();
|
|
87
80
|
}
|
|
88
81
|
this.mounted = true;
|
|
89
82
|
},
|
|
@@ -47,6 +47,13 @@ vi.mock('@nocobase/flow-engine', () => {
|
|
|
47
47
|
return [];
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
findSubModel(key: string, callback: any) {
|
|
51
|
+
if (this.subModels[key]) {
|
|
52
|
+
return this.subModels[key].find(callback) || null;
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
50
57
|
addSubModel() {}
|
|
51
58
|
setSubModel() {}
|
|
52
59
|
|
|
@@ -260,6 +267,44 @@ describe('PageModel', () => {
|
|
|
260
267
|
});
|
|
261
268
|
});
|
|
262
269
|
|
|
270
|
+
describe('tab lifecycle', () => {
|
|
271
|
+
it('should invoke tab lifecycle on PageModel subModels before engine lookup', () => {
|
|
272
|
+
const blockOnActive = vi.fn();
|
|
273
|
+
const blockOnInactive = vi.fn();
|
|
274
|
+
const tabModel = {
|
|
275
|
+
uid: 'tab1',
|
|
276
|
+
context: {
|
|
277
|
+
tabActive: { value: false },
|
|
278
|
+
},
|
|
279
|
+
subModels: {
|
|
280
|
+
grid: {
|
|
281
|
+
mapSubModels: vi.fn((_key, callback) => {
|
|
282
|
+
callback({ onActive: blockOnActive, onInactive: blockOnInactive });
|
|
283
|
+
}),
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
};
|
|
287
|
+
(pageModel as any).subModels = { tabs: [tabModel] };
|
|
288
|
+
(pageModel as any).flowEngine = {
|
|
289
|
+
getModel: vi.fn(() => undefined),
|
|
290
|
+
};
|
|
291
|
+
(pageModel as any).context = {
|
|
292
|
+
pageInfo: {},
|
|
293
|
+
view: {
|
|
294
|
+
inputArgs: { pageActive: true },
|
|
295
|
+
},
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
pageModel.invokeTabModelLifecycleMethod('tab1', 'onActive', true);
|
|
299
|
+
pageModel.invokeTabModelLifecycleMethod('tab1', 'onInactive');
|
|
300
|
+
|
|
301
|
+
expect((pageModel as any).flowEngine.getModel).not.toHaveBeenCalled();
|
|
302
|
+
expect(tabModel.context.tabActive.value).toBe(false);
|
|
303
|
+
expect(blockOnActive).toHaveBeenCalledWith(true);
|
|
304
|
+
expect(blockOnInactive).toHaveBeenCalledWith(false);
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
|
|
263
308
|
describe('renderTabs activeKey logic', () => {
|
|
264
309
|
beforeEach(() => {
|
|
265
310
|
// Mock mapTabs to avoid complex rendering logic inside it
|
|
@@ -455,6 +500,7 @@ describe('PageModel', () => {
|
|
|
455
500
|
} as any;
|
|
456
501
|
(pageModel as any).context = {
|
|
457
502
|
currentRoute: {
|
|
503
|
+
id: 'route-1',
|
|
458
504
|
enableTabs: false,
|
|
459
505
|
},
|
|
460
506
|
};
|
|
@@ -479,6 +525,7 @@ describe('PageModel', () => {
|
|
|
479
525
|
} as any;
|
|
480
526
|
(pageModel as any).context = {
|
|
481
527
|
currentRoute: {
|
|
528
|
+
id: 'route-1',
|
|
482
529
|
enableTabs: true,
|
|
483
530
|
},
|
|
484
531
|
};
|
|
@@ -495,6 +542,59 @@ describe('PageModel', () => {
|
|
|
495
542
|
paddingBottom: 0,
|
|
496
543
|
});
|
|
497
544
|
});
|
|
545
|
+
|
|
546
|
+
it('should ignore stale desktop route enableTabs=false from another route', () => {
|
|
547
|
+
pageModel.props = {
|
|
548
|
+
routeId: 'route-1',
|
|
549
|
+
displayTitle: true,
|
|
550
|
+
enableTabs: true,
|
|
551
|
+
title: 'Title',
|
|
552
|
+
headerStyle: { backgroundColor: 'var(--colorBgLayout)' },
|
|
553
|
+
} as any;
|
|
554
|
+
(pageModel as any).context = {
|
|
555
|
+
currentRoute: {
|
|
556
|
+
id: 'route-2',
|
|
557
|
+
enableTabs: false,
|
|
558
|
+
},
|
|
559
|
+
};
|
|
560
|
+
pageModel.renderTabs = vi.fn(() => null);
|
|
561
|
+
pageModel.renderFirstTab = vi.fn(() => null);
|
|
562
|
+
|
|
563
|
+
const result = pageModel.render() as any;
|
|
564
|
+
const header = result.props.children[0];
|
|
565
|
+
|
|
566
|
+
expect(pageModel.renderTabs).toHaveBeenCalled();
|
|
567
|
+
expect(pageModel.renderFirstTab).not.toHaveBeenCalled();
|
|
568
|
+
expect(header.props.style).toMatchObject({
|
|
569
|
+
backgroundColor: 'var(--colorBgLayout)',
|
|
570
|
+
paddingBottom: 0,
|
|
571
|
+
});
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
it('should ignore stale desktop route enableTabs=true from another route', () => {
|
|
575
|
+
pageModel.props = {
|
|
576
|
+
routeId: 'route-1',
|
|
577
|
+
displayTitle: true,
|
|
578
|
+
enableTabs: false,
|
|
579
|
+
title: 'Title',
|
|
580
|
+
headerStyle: { backgroundColor: 'var(--colorBgLayout)' },
|
|
581
|
+
} as any;
|
|
582
|
+
(pageModel as any).context = {
|
|
583
|
+
currentRoute: {
|
|
584
|
+
id: 'route-2',
|
|
585
|
+
enableTabs: true,
|
|
586
|
+
},
|
|
587
|
+
};
|
|
588
|
+
pageModel.renderTabs = vi.fn(() => null);
|
|
589
|
+
pageModel.renderFirstTab = vi.fn(() => null);
|
|
590
|
+
|
|
591
|
+
const result = pageModel.render() as any;
|
|
592
|
+
const header = result.props.children[0];
|
|
593
|
+
|
|
594
|
+
expect(pageModel.renderTabs).not.toHaveBeenCalled();
|
|
595
|
+
expect(pageModel.renderFirstTab).toHaveBeenCalled();
|
|
596
|
+
expect(header.props.style).toEqual({ backgroundColor: 'var(--colorBgLayout)' });
|
|
597
|
+
});
|
|
498
598
|
});
|
|
499
599
|
|
|
500
600
|
describe('dirty refresh signal', () => {
|
|
@@ -554,7 +654,7 @@ describe('PageModel', () => {
|
|
|
554
654
|
pageModel.onMount();
|
|
555
655
|
|
|
556
656
|
expect(typeof listeners['view:activated']).toBe('function');
|
|
557
|
-
expect(invokeSpy).toHaveBeenCalledWith('tab1', 'onActive');
|
|
657
|
+
expect(invokeSpy).toHaveBeenCalledWith('tab1', 'onActive', false);
|
|
558
658
|
});
|
|
559
659
|
});
|
|
560
660
|
|
|
@@ -630,6 +730,7 @@ describe('PageModel', () => {
|
|
|
630
730
|
it('should use page documentTitle when desktop route disables tabs even if flow model enables tabs', async () => {
|
|
631
731
|
pageModel.props = { routeId: 'route-1', enableTabs: true, title: 'Route page title' } as any;
|
|
632
732
|
(pageModel as any).context.currentRoute = {
|
|
733
|
+
id: 'route-1',
|
|
633
734
|
enableTabs: false,
|
|
634
735
|
};
|
|
635
736
|
(pageModel as any).stepParams = {
|
|
@@ -28,6 +28,64 @@ import { customAlphabet as Alphabet } from 'nanoid';
|
|
|
28
28
|
import { ensureOptionsFromUiSchemaEnumIfAbsent } from '../../../internal/utils/enumOptionsUtils';
|
|
29
29
|
import { RunJSValueEditor } from '../../../components/RunJSValueEditor';
|
|
30
30
|
|
|
31
|
+
type AssignFormTempOriginField = {
|
|
32
|
+
uid?: string;
|
|
33
|
+
props?: {
|
|
34
|
+
fieldNames?: unknown;
|
|
35
|
+
titleField?: unknown;
|
|
36
|
+
};
|
|
37
|
+
getStepParams?: (flowKey: string, stepKey: string) => unknown;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
function getAssignFormTempFieldOptions(
|
|
41
|
+
originField: AssignFormTempOriginField | undefined,
|
|
42
|
+
init: Record<string, unknown>,
|
|
43
|
+
) {
|
|
44
|
+
const inheritedFieldNames = originField?.props?.fieldNames;
|
|
45
|
+
const inheritedTitleField = originField?.props?.titleField;
|
|
46
|
+
const inheritedSelectFieldNamesStep = originField?.getStepParams?.('selectSettings', 'fieldNames');
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
stepParams: {
|
|
50
|
+
fieldSettings: {
|
|
51
|
+
init,
|
|
52
|
+
},
|
|
53
|
+
...(inheritedSelectFieldNamesStep
|
|
54
|
+
? {
|
|
55
|
+
selectSettings: {
|
|
56
|
+
fieldNames: inheritedSelectFieldNamesStep,
|
|
57
|
+
},
|
|
58
|
+
}
|
|
59
|
+
: {}),
|
|
60
|
+
},
|
|
61
|
+
props: {
|
|
62
|
+
...(typeof inheritedFieldNames !== 'undefined' ? { fieldNames: inheritedFieldNames } : {}),
|
|
63
|
+
...(typeof inheritedTitleField !== 'undefined' ? { titleField: inheritedTitleField } : {}),
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function stringifyAssignFormTempFieldOption(value: unknown) {
|
|
69
|
+
try {
|
|
70
|
+
return JSON.stringify(value) ?? '';
|
|
71
|
+
} catch {
|
|
72
|
+
return String(value);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function getAssignFormTempFieldRefreshKey(originField: AssignFormTempOriginField | undefined) {
|
|
77
|
+
const inheritedFieldNames = originField?.props?.fieldNames;
|
|
78
|
+
const inheritedTitleField = originField?.props?.titleField;
|
|
79
|
+
const inheritedSelectFieldNamesStep = originField?.getStepParams?.('selectSettings', 'fieldNames');
|
|
80
|
+
|
|
81
|
+
return [
|
|
82
|
+
originField?.uid || '',
|
|
83
|
+
stringifyAssignFormTempFieldOption(inheritedFieldNames),
|
|
84
|
+
stringifyAssignFormTempFieldOption(inheritedTitleField),
|
|
85
|
+
stringifyAssignFormTempFieldOption(inheritedSelectFieldNamesStep),
|
|
86
|
+
].join('|');
|
|
87
|
+
}
|
|
88
|
+
|
|
31
89
|
/**
|
|
32
90
|
* 使用 FormItemModel 的“表单项”包装,内部渲染 VariableInput,并将“常量”映射到临时字段模型。
|
|
33
91
|
*/
|
|
@@ -108,6 +166,8 @@ export class AssignFormItemModel extends FormItemModel {
|
|
|
108
166
|
const init = this.fieldInit;
|
|
109
167
|
const namePath = this.props?.name || (this.fieldPath ? [this.fieldPath] : undefined);
|
|
110
168
|
const fieldPath = this.fieldPath;
|
|
169
|
+
const originField = this.subModels?.field as AssignFormTempOriginField | undefined;
|
|
170
|
+
const tempFieldRefreshKey = getAssignFormTempFieldRefreshKey(originField);
|
|
111
171
|
|
|
112
172
|
const FieldRow: React.FC = () => {
|
|
113
173
|
const [tempRoot, setTempRoot] = React.useState<any>(null);
|
|
@@ -121,13 +181,14 @@ export class AssignFormItemModel extends FormItemModel {
|
|
|
121
181
|
return;
|
|
122
182
|
}
|
|
123
183
|
const fieldModel = binding.modelName;
|
|
184
|
+
const tempFieldOptions = getAssignFormTempFieldOptions(originField, init);
|
|
124
185
|
const created = ctx?.engine?.createModel?.({
|
|
125
186
|
use: 'VariableFieldFormModel',
|
|
126
187
|
subModels: {
|
|
127
188
|
fields: [
|
|
128
189
|
{
|
|
129
190
|
use: fieldModel,
|
|
130
|
-
|
|
191
|
+
...tempFieldOptions,
|
|
131
192
|
},
|
|
132
193
|
],
|
|
133
194
|
},
|
|
@@ -302,7 +363,7 @@ export class AssignFormItemModel extends FormItemModel {
|
|
|
302
363
|
);
|
|
303
364
|
};
|
|
304
365
|
|
|
305
|
-
return <FieldRow />;
|
|
366
|
+
return <FieldRow key={tempFieldRefreshKey} />;
|
|
306
367
|
}
|
|
307
368
|
}
|
|
308
369
|
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
FlowModelRenderer,
|
|
12
|
+
resolveRunJSObjectValues,
|
|
13
|
+
tExpr,
|
|
14
|
+
type FlowModelContext,
|
|
15
|
+
useFlowEngine,
|
|
16
|
+
useFlowSettingsContext,
|
|
17
|
+
} from '@nocobase/flow-engine';
|
|
18
|
+
import React, { useEffect, useRef } from 'react';
|
|
19
|
+
import { CollectionActionModel } from '../../base/CollectionActionModel';
|
|
20
|
+
import { RecordActionModel } from '../../base/RecordActionModel';
|
|
21
|
+
import { AssignFormModel } from './AssignFormModel';
|
|
22
|
+
|
|
23
|
+
export const ASSIGN_FIELD_VALUES_STEP_KEY = 'assignFieldValues';
|
|
24
|
+
|
|
25
|
+
type AssignedValues = Record<string, unknown>;
|
|
26
|
+
|
|
27
|
+
type AssignFieldValuesCollection = {
|
|
28
|
+
dataSourceKey?: string;
|
|
29
|
+
name?: string;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
type AssignFieldValuesContext = FlowModelContext & {
|
|
33
|
+
collection?: AssignFieldValuesCollection;
|
|
34
|
+
flowSettingsEnabled?: boolean;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
type AssignFieldValuesModel = {
|
|
38
|
+
uid: string;
|
|
39
|
+
assignFormUid?: string;
|
|
40
|
+
context?: AssignFieldValuesContext;
|
|
41
|
+
getStepParams?: (flowKey: string, stepKey: string) => { assignedValues?: AssignedValues } | undefined;
|
|
42
|
+
setStepParams?: (flowKey: string, stepKey: string, params: { assignedValues: AssignedValues }) => void;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
type AssignFieldValuesStepOptions = {
|
|
46
|
+
settingsFlowKey: string;
|
|
47
|
+
title?: string;
|
|
48
|
+
tipComponent?: React.ComponentType;
|
|
49
|
+
validateBeforeSave?: boolean;
|
|
50
|
+
clearRecordContext?: boolean;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
function getContextCollection(ctx: AssignFieldValuesContext | undefined): AssignFieldValuesCollection | undefined {
|
|
54
|
+
const collection = ctx?.collection;
|
|
55
|
+
return collection && typeof collection === 'object' ? collection : undefined;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function getResourceInit(ctx: AssignFieldValuesContext): { dataSourceKey: string; collectionName: string } | undefined {
|
|
59
|
+
const collection = getContextCollection(ctx);
|
|
60
|
+
const dsKey = collection?.dataSourceKey;
|
|
61
|
+
const collName = collection?.name;
|
|
62
|
+
return dsKey && collName ? { dataSourceKey: dsKey, collectionName: collName } : undefined;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function createAssignFormSubModelOptions(ctx: AssignFieldValuesContext) {
|
|
66
|
+
return {
|
|
67
|
+
async: true,
|
|
68
|
+
use: 'AssignFormModel',
|
|
69
|
+
stepParams: { resourceSettings: { init: getResourceInit(ctx) } },
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function getAssignFieldValuesDefaultParams(
|
|
74
|
+
ctx: {
|
|
75
|
+
model: Pick<AssignFieldValuesModel, 'getStepParams'>;
|
|
76
|
+
},
|
|
77
|
+
settingsFlowKey: string,
|
|
78
|
+
): { assignedValues: AssignedValues } {
|
|
79
|
+
const step = ctx.model.getStepParams?.(settingsFlowKey, ASSIGN_FIELD_VALUES_STEP_KEY) || {};
|
|
80
|
+
return { assignedValues: step?.assignedValues || {} };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export async function resolveAssignFieldValues(
|
|
84
|
+
ctx: {
|
|
85
|
+
message?: { error?: (message: string) => void };
|
|
86
|
+
t?: (message: string) => string;
|
|
87
|
+
},
|
|
88
|
+
rawAssignedValues: unknown,
|
|
89
|
+
logName = 'AssignFieldValues',
|
|
90
|
+
): Promise<AssignedValues | null> {
|
|
91
|
+
try {
|
|
92
|
+
return await resolveRunJSObjectValues(ctx, rawAssignedValues);
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error(`[${logName}] RunJS execution failed`, error);
|
|
95
|
+
ctx.message?.error?.(ctx.t?.('RunJS execution failed') || 'RunJS execution failed');
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function mergeAssignFieldValues<T extends Record<string, unknown>>(
|
|
101
|
+
values: T,
|
|
102
|
+
assignedValues?: AssignedValues | null,
|
|
103
|
+
): T {
|
|
104
|
+
if (!assignedValues || typeof assignedValues !== 'object' || !Object.keys(assignedValues).length) {
|
|
105
|
+
return values;
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
...values,
|
|
109
|
+
...assignedValues,
|
|
110
|
+
} as T;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function AssignFieldsEditor(props: { settingsFlowKey: string; clearRecordContext?: boolean }) {
|
|
114
|
+
const { model, blockModel } = useFlowSettingsContext();
|
|
115
|
+
const action = model as AssignFieldValuesModel;
|
|
116
|
+
const engine = useFlowEngine();
|
|
117
|
+
const initializedRef = useRef(false);
|
|
118
|
+
const [formModel, setFormModel] = React.useState<AssignFormModel | null>(null);
|
|
119
|
+
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
let cancelled = false;
|
|
122
|
+
const loadAssignForm = async () => {
|
|
123
|
+
const loaded = (await engine.loadOrCreateModel(
|
|
124
|
+
{
|
|
125
|
+
parentId: action.uid,
|
|
126
|
+
subKey: 'assignForm',
|
|
127
|
+
use: 'AssignFormModel',
|
|
128
|
+
},
|
|
129
|
+
{ skipSave: !model.context.flowSettingsEnabled },
|
|
130
|
+
)) as AssignFormModel;
|
|
131
|
+
if (cancelled) return;
|
|
132
|
+
setFormModel(loaded);
|
|
133
|
+
action.assignFormUid = loaded?.uid || action.assignFormUid;
|
|
134
|
+
};
|
|
135
|
+
loadAssignForm();
|
|
136
|
+
return () => {
|
|
137
|
+
cancelled = true;
|
|
138
|
+
};
|
|
139
|
+
}, [action, engine, model.context.flowSettingsEnabled]);
|
|
140
|
+
|
|
141
|
+
useEffect(() => {
|
|
142
|
+
if (initializedRef.current) return;
|
|
143
|
+
if (!formModel) return;
|
|
144
|
+
|
|
145
|
+
const prev = action.getStepParams?.(props.settingsFlowKey, ASSIGN_FIELD_VALUES_STEP_KEY) || {};
|
|
146
|
+
const coll = blockModel?.collection || getContextCollection(action?.context);
|
|
147
|
+
const dsKey = coll?.dataSourceKey;
|
|
148
|
+
const collName = coll?.name;
|
|
149
|
+
if (dsKey && collName) {
|
|
150
|
+
formModel.setStepParams('resourceSettings', 'init', {
|
|
151
|
+
dataSourceKey: dsKey,
|
|
152
|
+
collectionName: collName,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
formModel.setInitialAssignedValues(prev?.assignedValues || {});
|
|
156
|
+
|
|
157
|
+
const isBulk =
|
|
158
|
+
props.clearRecordContext || (action instanceof CollectionActionModel && !(action instanceof RecordActionModel));
|
|
159
|
+
if (isBulk && formModel.context?.defineProperty) {
|
|
160
|
+
formModel.context.defineProperty('record', { get: () => undefined, cache: false });
|
|
161
|
+
}
|
|
162
|
+
initializedRef.current = true;
|
|
163
|
+
}, [action, blockModel?.collection, formModel, props.clearRecordContext, props.settingsFlowKey]);
|
|
164
|
+
|
|
165
|
+
return formModel ? <FlowModelRenderer model={formModel} showFlowSettings={false} /> : null;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function createAssignFieldValuesStep(options: AssignFieldValuesStepOptions) {
|
|
169
|
+
return {
|
|
170
|
+
title: options.title || tExpr('Assign field values'),
|
|
171
|
+
uiSchema() {
|
|
172
|
+
return {
|
|
173
|
+
tip: options.tipComponent
|
|
174
|
+
? {
|
|
175
|
+
'x-decorator': 'FormItem',
|
|
176
|
+
'x-component': options.tipComponent,
|
|
177
|
+
}
|
|
178
|
+
: undefined,
|
|
179
|
+
editor: {
|
|
180
|
+
'x-decorator': 'FormItem',
|
|
181
|
+
'x-component': () => (
|
|
182
|
+
<AssignFieldsEditor
|
|
183
|
+
settingsFlowKey={options.settingsFlowKey}
|
|
184
|
+
clearRecordContext={options.clearRecordContext}
|
|
185
|
+
/>
|
|
186
|
+
),
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
},
|
|
190
|
+
async beforeParamsSave(ctx: {
|
|
191
|
+
model: AssignFieldValuesModel;
|
|
192
|
+
engine: {
|
|
193
|
+
getModel?: (uid: string, fromRoot?: boolean) => AssignFormModel | undefined;
|
|
194
|
+
};
|
|
195
|
+
}) {
|
|
196
|
+
const form = ctx.model.assignFormUid ? ctx.engine.getModel?.(ctx.model.assignFormUid, true) : undefined;
|
|
197
|
+
if (!form) return;
|
|
198
|
+
if (options.validateBeforeSave) {
|
|
199
|
+
await form.form?.validateFields?.();
|
|
200
|
+
}
|
|
201
|
+
const assignedValues = form.getAssignedValues?.() || {};
|
|
202
|
+
ctx.model.setStepParams?.(options.settingsFlowKey, ASSIGN_FIELD_VALUES_STEP_KEY, { assignedValues });
|
|
203
|
+
},
|
|
204
|
+
handler() {},
|
|
205
|
+
};
|
|
206
|
+
}
|
|
@@ -12,4 +12,18 @@ import { FormActionModel } from './FormActionModel';
|
|
|
12
12
|
|
|
13
13
|
export class FormActionGroupModel extends ActionGroupModel {
|
|
14
14
|
static baseClass = FormActionModel;
|
|
15
|
+
|
|
16
|
+
static async defineChildren(ctx) {
|
|
17
|
+
const allowedModelNames = ctx.allowedFormActionModelNames;
|
|
18
|
+
|
|
19
|
+
if (!Array.isArray(allowedModelNames) || allowedModelNames.length === 0) {
|
|
20
|
+
return super.defineChildren(ctx);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
await Promise.all(allowedModelNames.map((name) => ctx.engine?.getModelClassAsync?.(name)));
|
|
24
|
+
|
|
25
|
+
const items = await super.defineChildren(ctx);
|
|
26
|
+
const allowedSet = new Set(allowedModelNames);
|
|
27
|
+
return items.filter((item) => allowedSet.has(item.useModel || item.key));
|
|
28
|
+
}
|
|
15
29
|
}
|
|
@@ -7,15 +7,27 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { tExpr } from '@nocobase/flow-engine';
|
|
10
|
+
import { DefaultStructure, FlowExitAllException, tExpr } from '@nocobase/flow-engine';
|
|
11
11
|
import { ButtonProps } from 'antd';
|
|
12
12
|
import { AxiosRequestConfig } from 'axios';
|
|
13
13
|
import { ActionModel } from '../../base/ActionModelCore';
|
|
14
|
+
import { AssignFormModel } from '../assign-form/AssignFormModel';
|
|
15
|
+
import {
|
|
16
|
+
createAssignFieldValuesStep,
|
|
17
|
+
createAssignFormSubModelOptions,
|
|
18
|
+
getAssignFieldValuesDefaultParams,
|
|
19
|
+
} from '../assign-form/assignFieldValuesFlow';
|
|
14
20
|
import { shouldSkipSubmitValidation, validateSubmitForm } from './submitValues';
|
|
15
21
|
|
|
16
|
-
export class FormActionModel extends ActionModel {}
|
|
22
|
+
export class FormActionModel<T extends DefaultStructure = DefaultStructure> extends ActionModel<T> {}
|
|
23
|
+
|
|
24
|
+
export class FormSubmitActionModel extends FormActionModel<{
|
|
25
|
+
subModels: {
|
|
26
|
+
assignForm: AssignFormModel;
|
|
27
|
+
};
|
|
28
|
+
}> {
|
|
29
|
+
assignFormUid?: string;
|
|
17
30
|
|
|
18
|
-
export class FormSubmitActionModel extends FormActionModel {
|
|
19
31
|
defaultProps: ButtonProps = {
|
|
20
32
|
title: tExpr('Submit'),
|
|
21
33
|
type: 'primary',
|
|
@@ -35,6 +47,11 @@ export class FormSubmitActionModel extends FormActionModel {
|
|
|
35
47
|
|
|
36
48
|
FormSubmitActionModel.define({
|
|
37
49
|
label: tExpr('Submit'),
|
|
50
|
+
createModelOptions: (ctx) => ({
|
|
51
|
+
subModels: {
|
|
52
|
+
assignForm: createAssignFormSubModelOptions(ctx),
|
|
53
|
+
},
|
|
54
|
+
}),
|
|
38
55
|
});
|
|
39
56
|
|
|
40
57
|
FormSubmitActionModel.registerFlow({
|
|
@@ -82,7 +99,14 @@ FormSubmitActionModel.registerFlow({
|
|
|
82
99
|
},
|
|
83
100
|
handler() {},
|
|
84
101
|
},
|
|
102
|
+
assignFieldValues: createAssignFieldValuesStep({
|
|
103
|
+
settingsFlowKey: 'submitSettings',
|
|
104
|
+
title: tExpr('Assign field values'),
|
|
105
|
+
}),
|
|
85
106
|
saveResource: {
|
|
107
|
+
async defaultParams(ctx) {
|
|
108
|
+
return getAssignFieldValuesDefaultParams(ctx, 'submitSettings');
|
|
109
|
+
},
|
|
86
110
|
async handler(ctx, params) {
|
|
87
111
|
if (!ctx?.resource) {
|
|
88
112
|
throw new Error('Resource is not initialized');
|
|
@@ -96,6 +120,9 @@ FormSubmitActionModel.registerFlow({
|
|
|
96
120
|
await submitHandler(ctx, params);
|
|
97
121
|
} catch (error) {
|
|
98
122
|
ctx.model.setProps('loading', false);
|
|
123
|
+
if (error instanceof FlowExitAllException) {
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
99
126
|
// 显示保存失败提示
|
|
100
127
|
ctx.message.error(ctx.t('Save failed'));
|
|
101
128
|
console.error('Form submission error:', error);
|
|
@@ -138,6 +138,10 @@ export class FormItemModel<T extends DefaultStructure = DefaultStructure> extend
|
|
|
138
138
|
});
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
|
+
fork.context.defineProperty('fieldPathArray', {
|
|
142
|
+
get: () => this.context.fieldPathArray,
|
|
143
|
+
cache: false,
|
|
144
|
+
});
|
|
141
145
|
if (isHiddenReservedValuePreview) {
|
|
142
146
|
fork.setProps({ hidden: false });
|
|
143
147
|
}
|
|
@@ -151,7 +155,10 @@ export class FormItemModel<T extends DefaultStructure = DefaultStructure> extend
|
|
|
151
155
|
: { hidden, ...mergedPropsWithoutInitial };
|
|
152
156
|
const fieldPath = buildDynamicNamePath(this.props.name, idx);
|
|
153
157
|
this.context.defineProperty('fieldPathArray', {
|
|
154
|
-
|
|
158
|
+
get: () => {
|
|
159
|
+
return [...parentFieldPathArray, ..._.castArray(fieldPath)];
|
|
160
|
+
},
|
|
161
|
+
cache: false,
|
|
155
162
|
});
|
|
156
163
|
const record = this.context.item?.value || this.context.record;
|
|
157
164
|
const content = (
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { FlowEngine } from '@nocobase/flow-engine';
|
|
11
|
+
import { describe, expect, it } from 'vitest';
|
|
12
|
+
import { FormActionGroupModel, FormActionModel } from '../../../..';
|
|
13
|
+
|
|
14
|
+
describe('FormActionGroupModel', () => {
|
|
15
|
+
it('filters addable form actions by allowedFormActionModelNames', async () => {
|
|
16
|
+
class AllowedFormActionModel extends FormActionModel {}
|
|
17
|
+
class HiddenFormActionModel extends FormActionModel {}
|
|
18
|
+
|
|
19
|
+
AllowedFormActionModel.define({
|
|
20
|
+
label: 'Allowed action',
|
|
21
|
+
sort: 10,
|
|
22
|
+
});
|
|
23
|
+
HiddenFormActionModel.define({
|
|
24
|
+
label: 'Hidden action',
|
|
25
|
+
sort: 20,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const engine = new FlowEngine();
|
|
29
|
+
engine.registerModels({
|
|
30
|
+
FormActionModel,
|
|
31
|
+
HiddenFormActionModel,
|
|
32
|
+
});
|
|
33
|
+
engine.registerModelLoaders({
|
|
34
|
+
AllowedFormActionModel: {
|
|
35
|
+
loader: async () => ({ AllowedFormActionModel }),
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const items = await FormActionGroupModel.defineChildren({
|
|
40
|
+
engine,
|
|
41
|
+
allowedFormActionModelNames: ['AllowedFormActionModel'],
|
|
42
|
+
} as any);
|
|
43
|
+
|
|
44
|
+
expect(items.map((item: any) => item.useModel)).toEqual(['AllowedFormActionModel']);
|
|
45
|
+
});
|
|
46
|
+
});
|