@nocobase/flow-engine 2.0.0-alpha.4 → 2.0.0-alpha.40
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/lib/BlockScopedFlowEngine.d.ts +23 -0
- package/lib/BlockScopedFlowEngine.js +90 -0
- package/lib/FlowContextProvider.d.ts +2 -2
- package/lib/FlowContextProvider.js +3 -3
- package/lib/FlowDefinition.d.ts +4 -2
- package/lib/JSRunner.js +3 -0
- package/lib/ViewScopedFlowEngine.d.ts +1 -1
- package/lib/ViewScopedFlowEngine.js +12 -0
- package/lib/acl/Acl.d.ts +1 -0
- package/lib/acl/Acl.js +11 -0
- package/lib/components/FieldModelRenderer.js +14 -6
- package/lib/components/FieldSkeleton.d.ts +10 -0
- package/lib/components/FieldSkeleton.js +64 -0
- package/lib/components/FlowContextSelector.js +7 -2
- package/lib/components/FlowModelRenderer.d.ts +3 -6
- package/lib/components/FlowModelRenderer.js +16 -47
- package/lib/components/FormItem.js +5 -1
- package/lib/components/MobilePopup.d.ts +20 -0
- package/lib/components/MobilePopup.js +102 -0
- package/lib/components/MobilePopup.style.d.ts +17 -0
- package/lib/components/MobilePopup.style.js +186 -0
- package/lib/components/index.d.ts +1 -0
- package/lib/components/index.js +3 -1
- package/lib/components/settings/independents/dropdown/FlowsDropdownButton.js +2 -2
- package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.js +17 -5
- package/lib/components/settings/wrappers/contextual/FlowsContextMenu.js +2 -2
- package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.d.ts +2 -2
- package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.js +35 -6
- package/lib/components/settings/wrappers/contextual/StepSettingsDialog.js +7 -1
- package/lib/components/variables/VariableInput.js +19 -5
- package/lib/components/variables/VariableTag.js +43 -2
- package/lib/components/variables/types.d.ts +2 -0
- package/lib/data-source/index.d.ts +15 -4
- package/lib/data-source/index.js +42 -13
- package/lib/data-source/sortCollectionsByInherits.d.ts +10 -0
- package/lib/data-source/sortCollectionsByInherits.js +71 -0
- package/lib/emitter.d.ts +6 -0
- package/lib/emitter.js +12 -0
- package/lib/executor/FlowExecutor.d.ts +4 -5
- package/lib/executor/FlowExecutor.js +168 -99
- package/lib/flow-registry/GlobalFlowRegistry.d.ts +1 -0
- package/lib/flow-registry/GlobalFlowRegistry.js +3 -0
- package/lib/flow-registry/InstanceFlowRegistry.d.ts +1 -0
- package/lib/flow-registry/InstanceFlowRegistry.js +3 -0
- package/lib/flowContext.d.ts +37 -5
- package/lib/flowContext.js +215 -87
- package/lib/flowEngine.d.ts +24 -1
- package/lib/flowEngine.js +56 -6
- package/lib/flowSettings.d.ts +2 -1
- package/lib/flowSettings.js +12 -8
- package/lib/hooks/useApplyAutoFlows.js +2 -1
- package/lib/index.d.ts +7 -1
- package/lib/index.js +32 -3
- package/lib/locale/en-US.json +4 -2
- package/lib/locale/index.d.ts +4 -0
- package/lib/locale/zh-CN.json +4 -2
- package/lib/models/CollectionFieldModel.d.ts +3 -0
- package/lib/models/CollectionFieldModel.js +48 -5
- package/lib/models/flowModel.d.ts +30 -29
- package/lib/models/flowModel.js +135 -98
- package/lib/models/forkFlowModel.d.ts +8 -4
- package/lib/models/forkFlowModel.js +38 -8
- package/lib/provider.d.ts +3 -1
- package/lib/provider.js +7 -5
- package/lib/resources/multiRecordResource.js +25 -1
- package/lib/resources/singleRecordResource.js +19 -1
- package/lib/resources/sqlResource.d.ts +1 -0
- package/lib/resources/sqlResource.js +20 -24
- package/lib/runjs-context/contexts/FormJSFieldItemRunJSContext.d.ts +1 -6
- package/lib/runjs-context/contexts/FormJSFieldItemRunJSContext.js +27 -20
- package/lib/runjs-context/contexts/JSBlockRunJSContext.d.ts +1 -6
- package/lib/runjs-context/contexts/JSBlockRunJSContext.js +46 -33
- package/lib/runjs-context/contexts/JSCollectionActionRunJSContext.d.ts +1 -2
- package/lib/runjs-context/contexts/JSCollectionActionRunJSContext.js +14 -15
- package/lib/runjs-context/contexts/{LinkageRunJSContext.d.ts → JSColumnRunJSContext.d.ts} +6 -3
- package/lib/runjs-context/contexts/JSColumnRunJSContext.js +78 -0
- package/lib/runjs-context/contexts/JSFieldRunJSContext.d.ts +1 -6
- package/lib/runjs-context/contexts/JSFieldRunJSContext.js +28 -24
- package/lib/runjs-context/contexts/JSItemRunJSContext.d.ts +1 -6
- package/lib/runjs-context/contexts/JSItemRunJSContext.js +24 -20
- package/lib/runjs-context/contexts/JSRecordActionRunJSContext.d.ts +1 -2
- package/lib/runjs-context/contexts/JSRecordActionRunJSContext.js +16 -17
- package/lib/runjs-context/contexts/base.d.ts +9 -0
- package/lib/runjs-context/contexts/base.js +183 -0
- package/lib/runjs-context/helpers.d.ts +5 -2
- package/lib/runjs-context/helpers.js +36 -27
- package/lib/runjs-context/registry.d.ts +7 -4
- package/lib/runjs-context/registry.js +10 -42
- package/lib/runjs-context/setup.d.ts +9 -0
- package/lib/runjs-context/setup.js +82 -0
- package/lib/runjs-context/snippets/global/{copy-record-json.snippet.js → api-request.snippet.js} +25 -10
- package/lib/runjs-context/snippets/global/clipboard-copy-text.snippet.js +61 -0
- package/lib/runjs-context/snippets/global/{view-navigation-push.snippet.js → import-esm.snippet.js} +26 -12
- package/lib/runjs-context/snippets/global/message-error.snippet.js +6 -0
- package/lib/runjs-context/snippets/global/message-success.snippet.js +6 -0
- package/lib/runjs-context/snippets/global/notification-open.snippet.d.ts +3 -8
- package/lib/runjs-context/snippets/global/notification-open.snippet.js +8 -1
- package/lib/runjs-context/snippets/global/open-view-dialog.snippet.js +10 -3
- package/lib/runjs-context/snippets/global/open-view-drawer.snippet.js +10 -3
- package/lib/runjs-context/snippets/global/query-selector.snippet.js +53 -0
- package/lib/runjs-context/snippets/global/require-amd.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/global/{requireAsync.snippet.js → require-amd.snippet.js} +16 -13
- package/lib/runjs-context/snippets/global/window-open.snippet.d.ts +3 -8
- package/lib/runjs-context/snippets/global/window-open.snippet.js +8 -1
- package/lib/runjs-context/snippets/index.d.ts +14 -3
- package/lib/runjs-context/snippets/index.js +161 -40
- package/lib/runjs-context/snippets/scene/block/add-event-listener.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/{jsblock → block}/add-event-listener.snippet.js +11 -2
- package/lib/runjs-context/snippets/scene/block/api-fetch-render-list.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/block/api-fetch-render-list.snippet.js +64 -0
- package/lib/runjs-context/snippets/scene/block/chartjs-bar.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/block/chartjs-bar.snippet.js +99 -0
- package/lib/runjs-context/snippets/{libs → scene/block}/echarts-init.snippet.js +24 -7
- package/lib/runjs-context/snippets/scene/block/render-button-handler.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/{jsblock → block}/render-button-handler.snippet.js +17 -9
- package/lib/runjs-context/snippets/scene/block/render-iframe.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/block/render-iframe.snippet.js +57 -0
- package/lib/runjs-context/snippets/scene/block/render-info-card.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/block/render-info-card.snippet.js +71 -0
- package/lib/runjs-context/snippets/scene/block/render-react-jsx.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/{jsblock/render-card.snippet.js → block/render-react-jsx.snippet.js} +26 -13
- package/lib/runjs-context/snippets/scene/block/render-react.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/{jsblock → block}/render-react.snippet.js +18 -17
- package/lib/runjs-context/snippets/scene/block/render-statistics.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/block/render-statistics.snippet.js +95 -0
- package/lib/runjs-context/snippets/scene/block/render-timeline.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/block/render-timeline.snippet.js +84 -0
- package/lib/runjs-context/snippets/scene/block/resource-example.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/block/resource-example.snippet.js +60 -0
- package/lib/runjs-context/snippets/scene/block/three-users-orbit.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/block/three-users-orbit.snippet.js +283 -0
- package/lib/runjs-context/snippets/scene/block/vue-component.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/block/vue-component.snippet.js +124 -0
- package/lib/runjs-context/snippets/scene/detail/color-by-value.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/{jsfield → detail}/color-by-value.snippet.js +13 -3
- package/lib/runjs-context/snippets/scene/detail/copy-to-clipboard.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/{global → scene/detail}/copy-to-clipboard.snippet.js +28 -6
- package/lib/runjs-context/snippets/scene/detail/format-number.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/{jsfield → detail}/format-number.snippet.js +13 -3
- package/lib/runjs-context/snippets/scene/detail/innerHTML-value.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/{jsfield → detail}/innerHTML-value.snippet.js +13 -3
- package/lib/runjs-context/snippets/scene/detail/percentage-bar.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/detail/percentage-bar.snippet.js +82 -0
- package/lib/runjs-context/snippets/scene/detail/relative-time.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/detail/relative-time.snippet.js +80 -0
- package/lib/runjs-context/snippets/scene/detail/status-tag.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/detail/status-tag.snippet.js +74 -0
- package/lib/runjs-context/snippets/scene/form/calculate-total.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/form/calculate-total.snippet.js +63 -0
- package/lib/runjs-context/snippets/scene/form/cascade-select.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/form/cascade-select.snippet.js +81 -0
- package/lib/runjs-context/snippets/scene/form/conditional-required.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/form/conditional-required.snippet.js +64 -0
- package/lib/runjs-context/snippets/scene/form/copy-field-values.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/form/copy-field-values.snippet.js +74 -0
- package/lib/runjs-context/snippets/scene/form/render-basic.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/{jsitem → form}/render-basic.snippet.js +11 -2
- package/lib/runjs-context/snippets/scene/form/set-disabled.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/{linkage → form}/set-disabled.snippet.js +12 -3
- package/lib/runjs-context/snippets/scene/form/set-field-value.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/{linkage → form}/set-field-value.snippet.js +12 -3
- package/lib/runjs-context/snippets/scene/form/set-required.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/{linkage → form}/set-required.snippet.js +12 -3
- package/lib/runjs-context/snippets/scene/form/toggle-multiple-fields.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/form/toggle-multiple-fields.snippet.js +67 -0
- package/lib/runjs-context/snippets/scene/form/toggle-visible.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/{linkage → form}/toggle-visible.snippet.js +12 -3
- package/lib/runjs-context/snippets/scene/table/cell-open-dialog.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/table/cell-open-dialog.snippet.js +64 -0
- package/lib/runjs-context/snippets/scene/table/collection-selected-count.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/{actions → table}/collection-selected-count.snippet.js +11 -2
- package/lib/runjs-context/snippets/scene/table/concat-fields.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/table/concat-fields.snippet.js +79 -0
- package/lib/runjs-context/snippets/scene/table/destroy-selected.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/{global/log-json-record.snippet.js → scene/table/destroy-selected.snippet.js} +24 -11
- package/lib/runjs-context/snippets/scene/table/export-selected-json.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/table/export-selected-json.snippet.js +64 -0
- package/lib/runjs-context/snippets/scene/table/iterate-selected-rows.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/{actions → table}/iterate-selected-rows.snippet.js +11 -2
- package/lib/runjs-context/snippets/types.d.ts +9 -1
- package/lib/scheduler/ModelOperationScheduler.d.ts +51 -0
- package/lib/scheduler/ModelOperationScheduler.js +262 -0
- package/lib/types.d.ts +28 -3
- package/lib/types.js +4 -3
- package/lib/utils/associationObjectVariable.d.ts +32 -0
- package/lib/utils/associationObjectVariable.js +157 -0
- package/lib/utils/buildSettingsViewInputArgs.d.ts +19 -0
- package/lib/utils/buildSettingsViewInputArgs.js +75 -0
- package/lib/utils/createEphemeralContext.d.ts +13 -0
- package/lib/utils/createEphemeralContext.js +140 -0
- package/lib/utils/flows.d.ts +10 -0
- package/lib/{runjs-context/snippets/global/api-request-post.snippet.js → utils/flows.js} +21 -15
- package/lib/utils/index.d.ts +7 -2
- package/lib/utils/index.js +19 -2
- package/lib/utils/jsxTransform.d.ts +15 -0
- package/lib/utils/jsxTransform.js +68 -0
- package/lib/utils/params-resolvers.js +3 -3
- package/lib/utils/parsePathnameToViewParams.d.ts +1 -1
- package/lib/utils/parsePathnameToViewParams.js +41 -5
- package/lib/utils/pruneFilter.d.ts +21 -0
- package/lib/{runjs-context/snippets/global/try-catch-async.snippet.js → utils/pruneFilter.js} +24 -16
- package/lib/utils/safeGlobals.d.ts +5 -3
- package/lib/utils/safeGlobals.js +40 -0
- package/lib/utils/schema-utils.js +2 -2
- package/lib/utils/serverContextParams.d.ts +1 -0
- package/lib/utils/translation.d.ts +4 -1
- package/lib/utils/translation.js +6 -2
- package/lib/utils/variablesParams.d.ts +9 -5
- package/lib/utils/variablesParams.js +47 -36
- package/lib/views/DrawerComponent.js +21 -2
- package/lib/views/PageComponent.js +2 -1
- package/lib/views/ViewNavigation.d.ts +3 -9
- package/lib/views/ViewNavigation.js +16 -2
- package/lib/views/createViewMeta.d.ts +29 -1
- package/lib/views/createViewMeta.js +338 -72
- package/lib/views/index.d.ts +1 -0
- package/lib/views/index.js +3 -0
- package/lib/views/useDialog.d.ts +8 -8
- package/lib/views/useDialog.js +8 -7
- package/lib/views/useDrawer.d.ts +8 -8
- package/lib/views/useDrawer.js +43 -28
- package/lib/views/usePage.d.ts +8 -8
- package/lib/views/usePage.js +8 -7
- package/package.json +6 -3
- package/src/BlockScopedFlowEngine.ts +86 -0
- package/src/FlowContextProvider.tsx +4 -2
- package/src/JSRunner.ts +3 -0
- package/src/ViewScopedFlowEngine.ts +15 -1
- package/src/__tests__/JSRunner.test.ts +62 -53
- package/src/__tests__/blockScopedFlowEngine.test.ts +154 -0
- package/src/__tests__/createViewMeta.popup.test.ts +132 -0
- package/src/__tests__/flow-engine.test.ts +3 -0
- package/src/__tests__/flowContext.test.ts +52 -0
- package/src/__tests__/flowContextCreateJSRunner.test.ts +163 -0
- package/src/__tests__/flowEngine.saveModel.test.ts +4 -0
- package/src/__tests__/flowRunJSContextDefine.test.ts +508 -0
- package/src/__tests__/flowSettings.open.test.tsx +2 -0
- package/src/__tests__/flowSettings.test.ts +2 -0
- package/src/__tests__/globalFlowRegistry.test.ts +1 -1
- package/src/__tests__/modelOperationScheduler.test.ts +346 -0
- package/src/__tests__/objectVariable.test.ts +464 -0
- package/src/__tests__/runjsContext.test.ts +216 -35
- package/src/__tests__/runjsContextImplementations.test.ts +217 -0
- package/src/__tests__/runjsContextRuntime.test.ts +269 -0
- package/src/__tests__/runjsEdgeCases.test.ts +281 -0
- package/src/__tests__/runjsLocales.test.ts +36 -0
- package/src/__tests__/runjsRuntimeFeatures.test.ts +449 -0
- package/src/__tests__/runjsSnippets.test.ts +140 -0
- package/src/__tests__/viewScopedFlowEngine.test.ts +3 -3
- package/src/acl/Acl.tsx +14 -0
- package/src/acl/__tests__/Acl.test.tsx +43 -0
- package/src/components/DynamicFlowsEditor.tsx +3 -4
- package/src/components/FieldModelRenderer.tsx +20 -7
- package/src/components/FieldSkeleton.tsx +27 -0
- package/src/components/FlowContextSelector.tsx +6 -2
- package/src/components/FlowModelRenderer.tsx +33 -81
- package/src/components/FormItem.tsx +8 -1
- package/src/components/MobilePopup.style.ts +220 -0
- package/src/components/MobilePopup.tsx +86 -0
- package/src/components/__tests__/flow-model-render-error-fallback.test.tsx +6 -6
- package/src/components/index.ts +1 -0
- package/src/components/settings/independents/dropdown/FlowsDropdownButton.tsx +1 -1
- package/src/components/settings/wrappers/contextual/DefaultSettingsIcon.tsx +17 -4
- package/src/components/settings/wrappers/contextual/FlowsContextMenu.tsx +1 -1
- package/src/components/settings/wrappers/contextual/FlowsFloatContextMenu.tsx +39 -10
- package/src/components/settings/wrappers/contextual/StepSettingsDialog.tsx +14 -1
- package/src/components/settings/wrappers/contextual/__tests__/DefaultSettingsIcon.test.tsx +425 -0
- package/src/components/subModel/__tests__/AddSubModelButton.test.tsx +5 -7
- package/src/components/variables/VariableInput.tsx +25 -5
- package/src/components/variables/VariableTag.tsx +54 -2
- package/src/components/variables/types.ts +2 -0
- package/src/data-source/__tests__/sortCollectionsByInherits.test.ts +125 -0
- package/src/data-source/index.ts +42 -11
- package/src/data-source/sortCollectionsByInherits.ts +61 -0
- package/src/emitter.ts +14 -0
- package/src/executor/FlowExecutor.ts +213 -119
- package/src/executor/__tests__/ctx-defs-injection.test.ts +197 -0
- package/src/executor/__tests__/flowExecutor.test.ts +151 -5
- package/src/flow-registry/GlobalFlowRegistry.ts +1 -0
- package/src/flow-registry/InstanceFlowRegistry.ts +1 -0
- package/src/flow-registry/__tests__/globalFlowRegistry.test.ts +54 -0
- package/src/flowContext.ts +290 -104
- package/src/flowEngine.ts +74 -6
- package/src/flowSettings.ts +9 -4
- package/src/hooks/useApplyAutoFlows.ts +3 -1
- package/src/index.ts +12 -1
- package/src/locale/en-US.json +4 -2
- package/src/locale/zh-CN.json +4 -2
- package/src/models/CollectionFieldModel.tsx +56 -7
- package/src/models/__tests__/dispatchEvent.behavior.test.ts +169 -0
- package/src/models/__tests__/flowModel.getFlows.sort.test.ts +33 -9
- package/src/models/__tests__/flowModel.scheduleModelOperation.test.tsx +129 -0
- package/src/models/__tests__/flowModel.test.ts +234 -111
- package/src/models/__tests__/forkFlowModel.test.ts +40 -7
- package/src/models/flowModel.tsx +180 -132
- package/src/models/forkFlowModel.ts +48 -8
- package/src/provider.tsx +10 -7
- package/src/resources/multiRecordResource.ts +28 -1
- package/src/resources/singleRecordResource.ts +19 -1
- package/src/resources/sqlResource.ts +20 -25
- package/src/runjs-context/contexts/FormJSFieldItemRunJSContext.ts +28 -21
- package/src/runjs-context/contexts/JSBlockRunJSContext.ts +46 -34
- package/src/runjs-context/contexts/JSCollectionActionRunJSContext.ts +15 -16
- package/src/runjs-context/contexts/JSColumnRunJSContext.ts +58 -0
- package/src/runjs-context/contexts/JSFieldRunJSContext.ts +30 -25
- package/src/runjs-context/contexts/JSItemRunJSContext.ts +25 -21
- package/src/runjs-context/contexts/JSRecordActionRunJSContext.ts +17 -18
- package/src/runjs-context/contexts/base.ts +171 -0
- package/src/runjs-context/helpers.ts +32 -30
- package/src/runjs-context/registry.ts +16 -47
- package/src/runjs-context/setup.ts +51 -0
- package/src/runjs-context/snippets/global/api-request.snippet.ts +38 -0
- package/src/runjs-context/snippets/global/clipboard-copy-text.snippet.ts +42 -0
- package/src/runjs-context/snippets/global/import-esm.snippet.ts +39 -0
- package/src/runjs-context/snippets/global/message-error.snippet.ts +6 -0
- package/src/runjs-context/snippets/global/message-success.snippet.ts +6 -0
- package/src/runjs-context/snippets/global/notification-open.snippet.ts +11 -1
- package/src/runjs-context/snippets/global/open-view-dialog.snippet.ts +10 -3
- package/src/runjs-context/snippets/global/open-view-drawer.snippet.ts +10 -3
- package/src/runjs-context/snippets/global/query-selector.snippet.ts +34 -0
- package/src/runjs-context/snippets/global/require-amd.snippet.ts +30 -0
- package/src/runjs-context/snippets/global/window-open.snippet.ts +11 -1
- package/src/runjs-context/snippets/index.ts +177 -39
- package/src/runjs-context/snippets/scene/{jsblock → block}/add-event-listener.snippet.ts +14 -2
- package/src/runjs-context/snippets/scene/block/api-fetch-render-list.snippet.ts +45 -0
- package/src/runjs-context/snippets/scene/block/chartjs-bar.snippet.ts +80 -0
- package/src/runjs-context/snippets/scene/block/echarts-init.snippet.ts +44 -0
- package/src/runjs-context/snippets/scene/block/render-button-handler.snippet.ts +35 -0
- package/src/runjs-context/snippets/scene/block/render-iframe.snippet.ts +38 -0
- package/src/runjs-context/snippets/scene/block/render-info-card.snippet.ts +52 -0
- package/src/runjs-context/snippets/scene/block/render-react-jsx.snippet.ts +39 -0
- package/src/runjs-context/snippets/scene/block/render-react.snippet.ts +38 -0
- package/src/runjs-context/snippets/scene/block/render-statistics.snippet.ts +76 -0
- package/src/runjs-context/snippets/scene/block/render-timeline.snippet.ts +65 -0
- package/src/runjs-context/snippets/scene/block/resource-example.snippet.ts +46 -0
- package/src/runjs-context/snippets/scene/block/three-users-orbit.snippet.ts +264 -0
- package/src/runjs-context/snippets/scene/block/vue-component.snippet.ts +105 -0
- package/src/runjs-context/snippets/scene/detail/color-by-value.snippet.ts +33 -0
- package/src/runjs-context/snippets/scene/detail/copy-to-clipboard.snippet.ts +45 -0
- package/src/runjs-context/snippets/scene/detail/format-number.snippet.ts +32 -0
- package/src/runjs-context/snippets/scene/detail/innerHTML-value.snippet.ts +31 -0
- package/src/runjs-context/snippets/scene/detail/percentage-bar.snippet.ts +63 -0
- package/src/runjs-context/snippets/scene/detail/relative-time.snippet.ts +61 -0
- package/src/runjs-context/snippets/scene/detail/status-tag.snippet.ts +55 -0
- package/src/runjs-context/snippets/scene/form/calculate-total.snippet.ts +44 -0
- package/src/runjs-context/snippets/scene/form/cascade-select.snippet.ts +62 -0
- package/src/runjs-context/snippets/scene/form/conditional-required.snippet.ts +45 -0
- package/src/runjs-context/snippets/scene/form/copy-field-values.snippet.ts +55 -0
- package/src/runjs-context/snippets/scene/{jsitem → form}/render-basic.snippet.ts +14 -2
- package/src/runjs-context/snippets/scene/{linkage → form}/set-disabled.snippet.ts +15 -3
- package/src/runjs-context/snippets/scene/{linkage → form}/set-field-value.snippet.ts +15 -3
- package/src/runjs-context/snippets/scene/{linkage → form}/set-required.snippet.ts +15 -3
- package/src/runjs-context/snippets/scene/form/toggle-multiple-fields.snippet.ts +48 -0
- package/src/runjs-context/snippets/scene/{linkage → form}/toggle-visible.snippet.ts +15 -3
- package/src/runjs-context/snippets/scene/table/cell-open-dialog.snippet.ts +45 -0
- package/src/runjs-context/snippets/scene/{actions → table}/collection-selected-count.snippet.ts +14 -2
- package/src/runjs-context/snippets/scene/table/concat-fields.snippet.ts +60 -0
- package/src/runjs-context/snippets/scene/table/destroy-selected.snippet.ts +36 -0
- package/src/runjs-context/snippets/scene/table/export-selected-json.snippet.ts +45 -0
- package/src/runjs-context/snippets/scene/{actions → table}/iterate-selected-rows.snippet.ts +14 -2
- package/src/runjs-context/snippets/types.ts +5 -1
- package/src/scheduler/ModelOperationScheduler.ts +304 -0
- package/src/types.ts +34 -0
- package/src/utils/__tests__/flows.test.ts +65 -0
- package/src/utils/__tests__/jsxTransform.test.ts +38 -0
- package/src/utils/__tests__/parsePathnameToViewParams.test.ts +25 -0
- package/src/utils/__tests__/pruneFilter.test.ts +38 -0
- package/src/utils/__tests__/safeGlobals.test.ts +22 -1
- package/src/utils/associationObjectVariable.ts +180 -0
- package/src/utils/buildSettingsViewInputArgs.ts +72 -0
- package/src/utils/createEphemeralContext.ts +142 -0
- package/src/utils/flows.ts +23 -0
- package/src/utils/index.ts +10 -2
- package/src/utils/jsxTransform.ts +39 -0
- package/src/utils/params-resolvers.ts +2 -2
- package/src/utils/parsePathnameToViewParams.ts +50 -6
- package/src/utils/pruneFilter.ts +41 -0
- package/src/utils/safeGlobals.ts +49 -3
- package/src/utils/schema-utils.ts +1 -1
- package/src/utils/serverContextParams.ts +1 -0
- package/src/utils/translation.ts +7 -2
- package/src/utils/variablesParams.ts +50 -38
- package/src/views/DrawerComponent.tsx +21 -2
- package/src/views/PageComponent.tsx +1 -1
- package/src/views/ViewNavigation.ts +20 -12
- package/src/views/__tests__/ViewNavigation.test.ts +10 -0
- package/src/views/createViewMeta.ts +393 -70
- package/src/views/index.tsx +1 -0
- package/src/views/useDialog.tsx +12 -10
- package/src/views/useDrawer.tsx +62 -37
- package/src/views/usePage.tsx +13 -10
- package/lib/runjs-context/contexts/FlowRunJSContext.d.ts +0 -38
- package/lib/runjs-context/contexts/FlowRunJSContext.js +0 -217
- package/lib/runjs-context/contexts/LinkageRunJSContext.js +0 -62
- package/lib/runjs-context/index.d.ts +0 -19
- package/lib/runjs-context/index.js +0 -57
- package/lib/runjs-context/snippets/global/api-request-get.snippet.d.ts +0 -16
- package/lib/runjs-context/snippets/global/api-request-get.snippet.js +0 -42
- package/lib/runjs-context/snippets/global/api-request-post.snippet.d.ts +0 -16
- package/lib/runjs-context/snippets/global/console-log-ctx.snippet.d.ts +0 -16
- package/lib/runjs-context/snippets/global/console-log-ctx.snippet.js +0 -41
- package/lib/runjs-context/snippets/global/requireAsync.snippet.d.ts +0 -16
- package/lib/runjs-context/snippets/global/sleep.snippet.d.ts +0 -16
- package/lib/runjs-context/snippets/global/sleep.snippet.js +0 -43
- package/lib/runjs-context/snippets/global/try-catch-async.snippet.d.ts +0 -16
- package/lib/runjs-context/snippets/libs/echarts-init.snippet.d.ts +0 -15
- package/lib/runjs-context/snippets/scene/actions/collection-selected-count.snippet.d.ts +0 -15
- package/lib/runjs-context/snippets/scene/actions/iterate-selected-rows.snippet.d.ts +0 -15
- package/lib/runjs-context/snippets/scene/actions/record-id-message.snippet.d.ts +0 -15
- package/lib/runjs-context/snippets/scene/actions/record-id-message.snippet.js +0 -43
- package/lib/runjs-context/snippets/scene/actions/run-action-basic.snippet.d.ts +0 -15
- package/lib/runjs-context/snippets/scene/actions/run-action-basic.snippet.js +0 -40
- package/lib/runjs-context/snippets/scene/jsblock/add-event-listener.snippet.d.ts +0 -15
- package/lib/runjs-context/snippets/scene/jsblock/append-style.snippet.d.ts +0 -15
- package/lib/runjs-context/snippets/scene/jsblock/append-style.snippet.js +0 -42
- package/lib/runjs-context/snippets/scene/jsblock/jsx-mount.snippet.d.ts +0 -15
- package/lib/runjs-context/snippets/scene/jsblock/jsx-mount.snippet.js +0 -46
- package/lib/runjs-context/snippets/scene/jsblock/jsx-unmount.snippet.d.ts +0 -15
- package/lib/runjs-context/snippets/scene/jsblock/jsx-unmount.snippet.js +0 -41
- package/lib/runjs-context/snippets/scene/jsblock/render-basic.snippet.d.ts +0 -15
- package/lib/runjs-context/snippets/scene/jsblock/render-basic.snippet.js +0 -41
- package/lib/runjs-context/snippets/scene/jsblock/render-button-handler.snippet.d.ts +0 -15
- package/lib/runjs-context/snippets/scene/jsblock/render-react.snippet.d.ts +0 -15
- package/lib/runjs-context/snippets/scene/jsfield/color-by-value.snippet.d.ts +0 -15
- package/lib/runjs-context/snippets/scene/jsfield/format-number.snippet.d.ts +0 -15
- package/lib/runjs-context/snippets/scene/jsfield/innerHTML-value.snippet.d.ts +0 -15
- package/lib/runjs-context/snippets/scene/jsitem/render-basic.snippet.d.ts +0 -15
- package/lib/runjs-context/snippets/scene/linkage/set-disabled.snippet.d.ts +0 -15
- package/lib/runjs-context/snippets/scene/linkage/set-field-value.snippet.d.ts +0 -15
- package/lib/runjs-context/snippets/scene/linkage/set-required.snippet.d.ts +0 -15
- package/lib/runjs-context/snippets/scene/linkage/toggle-visible.snippet.d.ts +0 -15
- package/src/runjs-context/contexts/FlowRunJSContext.ts +0 -190
- package/src/runjs-context/contexts/LinkageRunJSContext.ts +0 -35
- package/src/runjs-context/index.ts +0 -20
- package/src/runjs-context/snippets/global/api-request-get.snippet.ts +0 -20
- package/src/runjs-context/snippets/global/api-request-post.snippet.ts +0 -20
- package/src/runjs-context/snippets/global/console-log-ctx.snippet.ts +0 -19
- package/src/runjs-context/snippets/global/copy-record-json.snippet.ts +0 -21
- package/src/runjs-context/snippets/global/copy-to-clipboard.snippet.ts +0 -21
- package/src/runjs-context/snippets/global/log-json-record.snippet.ts +0 -21
- package/src/runjs-context/snippets/global/requireAsync.snippet.ts +0 -24
- package/src/runjs-context/snippets/global/sleep.snippet.ts +0 -21
- package/src/runjs-context/snippets/global/try-catch-async.snippet.ts +0 -22
- package/src/runjs-context/snippets/global/view-navigation-push.snippet.ts +0 -23
- package/src/runjs-context/snippets/libs/echarts-init.snippet.ts +0 -24
- package/src/runjs-context/snippets/scene/actions/record-id-message.snippet.ts +0 -21
- package/src/runjs-context/snippets/scene/actions/run-action-basic.snippet.ts +0 -18
- package/src/runjs-context/snippets/scene/jsblock/append-style.snippet.ts +0 -20
- package/src/runjs-context/snippets/scene/jsblock/jsx-mount.snippet.ts +0 -24
- package/src/runjs-context/snippets/scene/jsblock/jsx-unmount.snippet.ts +0 -19
- package/src/runjs-context/snippets/scene/jsblock/render-basic.snippet.ts +0 -24
- package/src/runjs-context/snippets/scene/jsblock/render-button-handler.snippet.ts +0 -24
- package/src/runjs-context/snippets/scene/jsblock/render-card.snippet.ts +0 -30
- package/src/runjs-context/snippets/scene/jsblock/render-react.snippet.ts +0 -34
- package/src/runjs-context/snippets/scene/jsfield/color-by-value.snippet.ts +0 -20
- package/src/runjs-context/snippets/scene/jsfield/format-number.snippet.ts +0 -19
- package/src/runjs-context/snippets/scene/jsfield/innerHTML-value.snippet.ts +0 -18
- /package/lib/runjs-context/snippets/global/{copy-record-json.snippet.d.ts → api-request.snippet.d.ts} +0 -0
- /package/lib/runjs-context/snippets/global/{copy-to-clipboard.snippet.d.ts → clipboard-copy-text.snippet.d.ts} +0 -0
- /package/lib/runjs-context/snippets/global/{log-json-record.snippet.d.ts → import-esm.snippet.d.ts} +0 -0
- /package/lib/runjs-context/snippets/global/{view-navigation-push.snippet.d.ts → query-selector.snippet.d.ts} +0 -0
- /package/lib/runjs-context/snippets/scene/{jsblock/render-card.snippet.d.ts → block/echarts-init.snippet.d.ts} +0 -0
package/src/flowEngine.ts
CHANGED
|
@@ -17,6 +17,9 @@ import { FlowSettings } from './flowSettings';
|
|
|
17
17
|
import { ErrorFlowModel, FlowModel } from './models';
|
|
18
18
|
import { ReactView } from './ReactView';
|
|
19
19
|
import { APIResource, FlowResource, MultiRecordResource, SingleRecordResource, SQLResource } from './resources';
|
|
20
|
+
import { Emitter } from './emitter';
|
|
21
|
+
import ModelOperationScheduler from './scheduler/ModelOperationScheduler';
|
|
22
|
+
import type { ScheduleOptions, ScheduledCancel } from './scheduler/ModelOperationScheduler';
|
|
20
23
|
import type {
|
|
21
24
|
ActionDefinition,
|
|
22
25
|
ApplyFlowCacheEntry,
|
|
@@ -114,6 +117,15 @@ export class FlowEngine {
|
|
|
114
117
|
|
|
115
118
|
private _resources = new Map<string, typeof FlowResource>();
|
|
116
119
|
|
|
120
|
+
/**
|
|
121
|
+
* 引擎事件总线(目前用于模型生命周期等事件)。
|
|
122
|
+
* ViewScopedFlowEngine 持有自己的实例,实现作用域隔离。
|
|
123
|
+
*/
|
|
124
|
+
public emitter: Emitter = new Emitter();
|
|
125
|
+
|
|
126
|
+
/** 调度器:仅在 View 作用域引擎本地启用;根/Block 作用域默认不持有 */
|
|
127
|
+
private _modelOperationScheduler?: ModelOperationScheduler;
|
|
128
|
+
|
|
117
129
|
logger: pino.Logger;
|
|
118
130
|
|
|
119
131
|
/**
|
|
@@ -130,7 +142,7 @@ export class FlowEngine {
|
|
|
130
142
|
*/
|
|
131
143
|
public reactView: ReactView;
|
|
132
144
|
/**
|
|
133
|
-
* Flow executor that runs
|
|
145
|
+
* Flow executor that runs event flows.
|
|
134
146
|
*/
|
|
135
147
|
public executor: FlowExecutor;
|
|
136
148
|
|
|
@@ -165,6 +177,35 @@ export class FlowEngine {
|
|
|
165
177
|
this.executor = new FlowExecutor(this);
|
|
166
178
|
}
|
|
167
179
|
|
|
180
|
+
/** 获取/创建当前引擎的调度器(仅在本地作用域) */
|
|
181
|
+
public getScheduler(): ModelOperationScheduler {
|
|
182
|
+
if (!this._modelOperationScheduler) {
|
|
183
|
+
this._modelOperationScheduler = new ModelOperationScheduler(this);
|
|
184
|
+
}
|
|
185
|
+
return this._modelOperationScheduler;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** 释放并清理当前引擎本地调度器(若存在) */
|
|
189
|
+
public disposeScheduler(): void {
|
|
190
|
+
if (this._modelOperationScheduler) {
|
|
191
|
+
try {
|
|
192
|
+
this._modelOperationScheduler.dispose();
|
|
193
|
+
} finally {
|
|
194
|
+
this._modelOperationScheduler = undefined;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** 在目标模型生命周期达成时执行操作(仅在 View 引擎本地存储计划) */
|
|
200
|
+
public scheduleModelOperation(
|
|
201
|
+
fromModelOrUid: FlowModel | string,
|
|
202
|
+
toUid: string,
|
|
203
|
+
fn: (model: FlowModel) => Promise<void> | void,
|
|
204
|
+
options?: ScheduleOptions,
|
|
205
|
+
): ScheduledCancel {
|
|
206
|
+
return this.getScheduler().schedule(fromModelOrUid, toUid, fn, options);
|
|
207
|
+
}
|
|
208
|
+
|
|
168
209
|
/** 上一个引擎(根引擎为 undefined) */
|
|
169
210
|
get previousEngine(): FlowEngine | undefined {
|
|
170
211
|
return this._previousEngine;
|
|
@@ -447,6 +488,12 @@ export class FlowEngine {
|
|
|
447
488
|
|
|
448
489
|
modelInstance.onInit(options);
|
|
449
490
|
|
|
491
|
+
// 发射 created 生命周期事件(严格模式:不吞错)
|
|
492
|
+
void this.emitter.emitAsync('model:created', {
|
|
493
|
+
uid: modelInstance.uid,
|
|
494
|
+
model: modelInstance,
|
|
495
|
+
});
|
|
496
|
+
|
|
450
497
|
// 在模型实例化阶段应用 flow 级 defaultParams(仅填充缺失的 stepParams,不覆盖)
|
|
451
498
|
// 不阻塞创建流程:允许 defaultParams 为异步函数
|
|
452
499
|
this._applyFlowDefinitionDefaultParams(modelInstance as FlowModel).catch((err) => {
|
|
@@ -565,6 +612,12 @@ export class FlowEngine {
|
|
|
565
612
|
}
|
|
566
613
|
}
|
|
567
614
|
this._modelInstances.delete(uid);
|
|
615
|
+
|
|
616
|
+
// 发射 destroyed 生命周期事件(在移除后,但携带实例便于调度器传递;严格模式:不吞错)
|
|
617
|
+
void this.emitter.emitAsync('model:destroyed', {
|
|
618
|
+
uid,
|
|
619
|
+
model: modelInstance,
|
|
620
|
+
});
|
|
568
621
|
return true;
|
|
569
622
|
}
|
|
570
623
|
|
|
@@ -734,6 +787,17 @@ export class FlowEngine {
|
|
|
734
787
|
return this.removeModel(uid);
|
|
735
788
|
}
|
|
736
789
|
|
|
790
|
+
/**
|
|
791
|
+
* Duplicate a model tree via repository API.
|
|
792
|
+
* Returns the duplicated model JSON (root with subModels) or null if not available.
|
|
793
|
+
* @param {string} uid UID of the model to duplicate
|
|
794
|
+
* @returns {Promise<any | null>} Duplicated model JSON or null
|
|
795
|
+
*/
|
|
796
|
+
async duplicateModel(uid: string) {
|
|
797
|
+
if (!this.ensureModelRepository()) return null;
|
|
798
|
+
return this._modelRepository.duplicate(uid);
|
|
799
|
+
}
|
|
800
|
+
|
|
737
801
|
/**
|
|
738
802
|
* Replace a model instance with a new instance of a class.
|
|
739
803
|
* @template T New model type
|
|
@@ -803,7 +867,7 @@ export class FlowEngine {
|
|
|
803
867
|
// 7. 触发事件以通知其他部分模型已替换
|
|
804
868
|
if (currentParent) {
|
|
805
869
|
currentParent.emitter.setPaused(false);
|
|
806
|
-
currentParent.parent.
|
|
870
|
+
currentParent.parent.invalidateFlowCache('beforeRender', true);
|
|
807
871
|
currentParent.parent?.rerender();
|
|
808
872
|
currentParent.emitter.emit('onSubModelReplaced', { oldModel, newModel });
|
|
809
873
|
}
|
|
@@ -837,7 +901,8 @@ export class FlowEngine {
|
|
|
837
901
|
return false;
|
|
838
902
|
}
|
|
839
903
|
|
|
840
|
-
const
|
|
904
|
+
const subModelsCopy = [...subModels];
|
|
905
|
+
const findIndex = (model: FlowModel) => subModelsCopy.findIndex((item) => item.uid === model.uid);
|
|
841
906
|
|
|
842
907
|
const currentIndex = findIndex(sourceModel);
|
|
843
908
|
const targetIndex = findIndex(targetModel);
|
|
@@ -853,14 +918,17 @@ export class FlowEngine {
|
|
|
853
918
|
}
|
|
854
919
|
|
|
855
920
|
// 使用splice直接移动数组元素(O(n)比排序O(n log n)更快)
|
|
856
|
-
const [movedModel] =
|
|
857
|
-
|
|
921
|
+
const [movedModel] = subModelsCopy.splice(currentIndex, 1);
|
|
922
|
+
subModelsCopy.splice(targetIndex, 0, movedModel);
|
|
858
923
|
|
|
859
924
|
// 重新分配连续的sortIndex
|
|
860
|
-
|
|
925
|
+
subModelsCopy.forEach((model, index) => {
|
|
861
926
|
model.sortIndex = index;
|
|
862
927
|
});
|
|
863
928
|
|
|
929
|
+
// 更新父模型的subModels引用
|
|
930
|
+
sourceModel.parent.subModels[sourceModel.subKey] = subModelsCopy;
|
|
931
|
+
|
|
864
932
|
return true;
|
|
865
933
|
};
|
|
866
934
|
move(sourceModel, targetModel);
|
package/src/flowSettings.ts
CHANGED
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
resolveStepUiSchema,
|
|
30
30
|
resolveUiMode,
|
|
31
31
|
setupRuntimeContextSteps,
|
|
32
|
+
buildSettingsViewInputArgs,
|
|
32
33
|
} from './utils';
|
|
33
34
|
import { FlowStepContext } from './hooks/useFlowStep';
|
|
34
35
|
|
|
@@ -205,8 +206,7 @@ export class FlowSettings {
|
|
|
205
206
|
Upload,
|
|
206
207
|
} = await import('@formily/antd-v5');
|
|
207
208
|
|
|
208
|
-
|
|
209
|
-
const { Button } = await import('antd');
|
|
209
|
+
const { Button, Alert } = await import('antd');
|
|
210
210
|
|
|
211
211
|
// 注册基础组件
|
|
212
212
|
this.components.Form = Form;
|
|
@@ -254,6 +254,7 @@ export class FlowSettings {
|
|
|
254
254
|
this.components.Space = Space;
|
|
255
255
|
this.components.Editable = Editable;
|
|
256
256
|
this.components.PreviewText = PreviewText;
|
|
257
|
+
this.components.Alert = Alert;
|
|
257
258
|
|
|
258
259
|
// 注册按钮组件
|
|
259
260
|
this.components.Button = Button;
|
|
@@ -464,12 +465,14 @@ export class FlowSettings {
|
|
|
464
465
|
flowEngine,
|
|
465
466
|
form,
|
|
466
467
|
onFormValuesChange,
|
|
468
|
+
key,
|
|
467
469
|
}: {
|
|
468
470
|
uiSchema: any;
|
|
469
471
|
initialValues: any;
|
|
470
472
|
flowEngine: any;
|
|
471
473
|
form?: any;
|
|
472
474
|
onFormValuesChange?: (form: any) => void;
|
|
475
|
+
key?: string;
|
|
473
476
|
}): React.ReactElement {
|
|
474
477
|
// 获取 scopes 和 components
|
|
475
478
|
const scopes = {
|
|
@@ -496,7 +499,7 @@ export class FlowSettings {
|
|
|
496
499
|
|
|
497
500
|
return React.createElement(
|
|
498
501
|
FormProviderWithForm,
|
|
499
|
-
{ form, initialValues, onFormValuesChange },
|
|
502
|
+
{ form, initialValues, onFormValuesChange, key },
|
|
500
503
|
React.createElement(SchemaField as any, {
|
|
501
504
|
schema: compiledSchema,
|
|
502
505
|
components: flowEngine?.flowSettings?.components || {},
|
|
@@ -601,7 +604,7 @@ export class FlowSettings {
|
|
|
601
604
|
let actionDefaultParams: Record<string, any> = {};
|
|
602
605
|
let uiMode;
|
|
603
606
|
if (step.use) {
|
|
604
|
-
const action =
|
|
607
|
+
const action = model.getAction?.(step.use);
|
|
605
608
|
if (action) {
|
|
606
609
|
actionDefaultParams = action.defaultParams || {};
|
|
607
610
|
stepTitle = stepTitle || action.title;
|
|
@@ -764,6 +767,8 @@ export class FlowSettings {
|
|
|
764
767
|
zIndex: 5000,
|
|
765
768
|
// 允许透传其它 props(如 maskClosable、footer 等),但确保 content 由我们接管
|
|
766
769
|
...modeProps,
|
|
770
|
+
// 统一构造 settings 弹窗的 inputArgs(集合/记录/父导航/关联)
|
|
771
|
+
inputArgs: buildSettingsViewInputArgs(model as any, (modeProps as any)?.inputArgs),
|
|
767
772
|
content: (currentView, viewCtx) => {
|
|
768
773
|
viewCtx?.defineMethod('getStepFormValues', (flowKey: string, stepKey: string) => {
|
|
769
774
|
return forms.get(keyOf({ flowKey, stepKey }))?.values;
|
|
@@ -35,7 +35,9 @@ export function useApplyAutoFlows(
|
|
|
35
35
|
|
|
36
36
|
const { loading, error } = useRequest(
|
|
37
37
|
async () => {
|
|
38
|
-
|
|
38
|
+
if (!model) return;
|
|
39
|
+
// beforeRender 在模型层默认顺序执行并默认使用缓存(可覆盖)
|
|
40
|
+
await model.dispatchEvent('beforeRender', inputArgs);
|
|
39
41
|
},
|
|
40
42
|
{
|
|
41
43
|
refreshDeps: [model, inputArgs],
|
package/src/index.ts
CHANGED
|
@@ -12,6 +12,7 @@ export * from './types';
|
|
|
12
12
|
|
|
13
13
|
// 工具函数
|
|
14
14
|
export * from './utils';
|
|
15
|
+
export { compileRunJs } from './utils/jsxTransform';
|
|
15
16
|
|
|
16
17
|
// 资源类
|
|
17
18
|
export * from './resources';
|
|
@@ -31,8 +32,18 @@ export * from './ElementProxy';
|
|
|
31
32
|
export * from './flowContext';
|
|
32
33
|
export * from './FlowContextProvider';
|
|
33
34
|
export * from './JSRunner';
|
|
34
|
-
export
|
|
35
|
+
export {
|
|
36
|
+
getRunJSDocFor,
|
|
37
|
+
createJSRunnerWithVersion,
|
|
38
|
+
getRunJSScenesForModel,
|
|
39
|
+
getRunJSScenesForContext,
|
|
40
|
+
} from './runjs-context/helpers';
|
|
41
|
+
export { RunJSContextRegistry, getModelClassName } from './runjs-context/registry';
|
|
42
|
+
export { setupRunJSContexts } from './runjs-context/setup';
|
|
43
|
+
export { getSnippetBody, listSnippetsForContext } from './runjs-context/snippets';
|
|
35
44
|
|
|
36
45
|
export * from './views';
|
|
37
46
|
|
|
38
47
|
export * from './FlowDefinition';
|
|
48
|
+
export { createViewScopedEngine } from './ViewScopedFlowEngine';
|
|
49
|
+
export { createBlockScopedEngine } from './BlockScopedFlowEngine';
|
package/src/locale/en-US.json
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"UID copied to clipboard": "UID copied to clipboard",
|
|
24
24
|
"Copy failed": "Copy failed",
|
|
25
25
|
"Copy failed, please copy [{{uid}}] manually.": "Copy failed, please copy [{{uid}}] manually.",
|
|
26
|
+
"Copy failed under HTTP. Clipboard API is unavailable on non-HTTPS pages. Please copy [{{uid}}] manually.": "Copy failed under HTTP. Clipboard API is unavailable on non-HTTPS pages. Please copy [{{uid}}] manually.",
|
|
26
27
|
"Confirm delete": "Confirm delete",
|
|
27
28
|
"Are you sure you want to delete this item? This action cannot be undone.": "Are you sure you want to delete this item? This action cannot be undone.",
|
|
28
29
|
"Delete operation failed": "Delete operation failed",
|
|
@@ -57,5 +58,6 @@
|
|
|
57
58
|
"Name": "Name",
|
|
58
59
|
"Model with ID {{uid}} not found": "Model with ID {{uid}} not found",
|
|
59
60
|
"Common actions": "Common actions",
|
|
60
|
-
"This variable is not available": "This variable is not available"
|
|
61
|
-
|
|
61
|
+
"This variable is not available": "This variable is not available",
|
|
62
|
+
"Copy popup UID": "Copy popup UID"
|
|
63
|
+
}
|
package/src/locale/zh-CN.json
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"UID copied to clipboard": "UID 已复制到剪贴板",
|
|
24
24
|
"Copy failed": "复制失败",
|
|
25
25
|
"Copy failed, please copy [{{uid}}] manually.": "复制失败,请手动复制 [{{uid}}]。",
|
|
26
|
+
"Copy failed under HTTP. Clipboard API is unavailable on non-HTTPS pages. Please copy [{{uid}}] manually.": "HTTP 环境下复制失败。非 HTTPS 页面不支持剪贴板 API,请手动复制 [{{uid}}]。",
|
|
26
27
|
"Confirm delete": "确认删除",
|
|
27
28
|
"Are you sure you want to delete this item? This action cannot be undone.": "确定要删除此项吗?此操作不可撤销。",
|
|
28
29
|
"Delete operation failed": "删除操作失败",
|
|
@@ -57,5 +58,6 @@
|
|
|
57
58
|
"Name": "名称",
|
|
58
59
|
"Model with ID {{uid}} not found": "未找到 ID 为 {{uid}} 的模型",
|
|
59
60
|
"Common actions": "通用操作",
|
|
60
|
-
"This variable is not available": "此变量不可用"
|
|
61
|
-
|
|
61
|
+
"This variable is not available": "此变量不可用",
|
|
62
|
+
"Copy popup UID": "复制弹窗 UID"
|
|
63
|
+
}
|
|
@@ -9,9 +9,11 @@
|
|
|
9
9
|
|
|
10
10
|
import { Card, Form } from 'antd';
|
|
11
11
|
import _ from 'lodash';
|
|
12
|
-
import React from 'react';
|
|
12
|
+
import React, { useMemo } from 'react';
|
|
13
|
+
import { useTranslation } from 'react-i18next';
|
|
13
14
|
import { CollectionField } from '../data-source';
|
|
14
15
|
import { FlowEngineContext } from '../flowContext';
|
|
16
|
+
import { useFlowModel } from '../hooks';
|
|
15
17
|
import { DefaultStructure } from '../types';
|
|
16
18
|
import { escapeT } from '../utils';
|
|
17
19
|
import { FlowModel } from './flowModel';
|
|
@@ -33,6 +35,34 @@ export function FieldPlaceholder() {
|
|
|
33
35
|
);
|
|
34
36
|
}
|
|
35
37
|
|
|
38
|
+
export function FieldDeletePlaceholder() {
|
|
39
|
+
const { t } = useTranslation();
|
|
40
|
+
const model: any = useFlowModel();
|
|
41
|
+
const blockModel = model.context.blockModel;
|
|
42
|
+
const dataSource = blockModel.collection.dataSource;
|
|
43
|
+
const collection = blockModel.collection;
|
|
44
|
+
const name = model.fieldPath;
|
|
45
|
+
const nameValue = useMemo(() => {
|
|
46
|
+
const dataSourcePrefix = `${t(dataSource.displayName || dataSource.key)} > `;
|
|
47
|
+
const collectionPrefix = collection ? `${t(collection.title) || collection.name || collection.tableName} > ` : '';
|
|
48
|
+
return `${dataSourcePrefix}${collectionPrefix}${name}`;
|
|
49
|
+
}, []);
|
|
50
|
+
return (
|
|
51
|
+
<Form.Item>
|
|
52
|
+
<div
|
|
53
|
+
style={{
|
|
54
|
+
color: 'rgba(0,0,0,0.45)',
|
|
55
|
+
}}
|
|
56
|
+
>
|
|
57
|
+
{t(`The {{type}} "{{name}}" may have been deleted. Please remove this {{blockType}}.`, {
|
|
58
|
+
type: t('Field'),
|
|
59
|
+
name: nameValue,
|
|
60
|
+
blockType: t('Field'),
|
|
61
|
+
}).replaceAll('>', '>')}
|
|
62
|
+
</div>
|
|
63
|
+
</Form.Item>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
36
66
|
export interface FieldSettingsInitParams {
|
|
37
67
|
dataSourceKey: string;
|
|
38
68
|
collectionName: string;
|
|
@@ -51,8 +81,12 @@ const defaultWhen = () => true;
|
|
|
51
81
|
|
|
52
82
|
export class CollectionFieldModel<T extends DefaultStructure = DefaultStructure> extends FlowModel<T> {
|
|
53
83
|
private static _bindings = new Map();
|
|
84
|
+
fieldDeleted = false;
|
|
54
85
|
|
|
55
86
|
renderHiddenInConfig(): React.ReactNode | undefined {
|
|
87
|
+
if (this.fieldDeleted) {
|
|
88
|
+
return <FieldDeletePlaceholder />;
|
|
89
|
+
}
|
|
56
90
|
return <FieldPlaceholder />;
|
|
57
91
|
}
|
|
58
92
|
|
|
@@ -76,12 +110,14 @@ export class CollectionFieldModel<T extends DefaultStructure = DefaultStructure>
|
|
|
76
110
|
return this.fieldPath;
|
|
77
111
|
},
|
|
78
112
|
});
|
|
79
|
-
this.context.blockModel
|
|
80
|
-
|
|
113
|
+
if (this.context.blockModel) {
|
|
114
|
+
this.context.blockModel.addAppends(this.fieldPath);
|
|
115
|
+
this.context.blockModel.addAppends(this.associationPathName);
|
|
116
|
+
}
|
|
81
117
|
}
|
|
82
118
|
|
|
83
119
|
getFieldSettingsInitParams(): FieldSettingsInitParams {
|
|
84
|
-
return this.getStepParams('fieldSettings', 'init');
|
|
120
|
+
return this.getStepParams('fieldSettings', 'init') || {};
|
|
85
121
|
}
|
|
86
122
|
|
|
87
123
|
get fieldPath(): string {
|
|
@@ -103,6 +139,9 @@ export class CollectionFieldModel<T extends DefaultStructure = DefaultStructure>
|
|
|
103
139
|
}
|
|
104
140
|
|
|
105
141
|
static getBindingsByField(ctx: FlowEngineContext, collectionField: CollectionField): BindingOptions[] {
|
|
142
|
+
if (!collectionField) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
106
145
|
const interfaceName = collectionField.interface;
|
|
107
146
|
|
|
108
147
|
// Check if the interface exists in the map
|
|
@@ -120,13 +159,23 @@ export class CollectionFieldModel<T extends DefaultStructure = DefaultStructure>
|
|
|
120
159
|
static getDefaultBindingByField(
|
|
121
160
|
ctx: FlowEngineContext,
|
|
122
161
|
collectionField: CollectionField,
|
|
123
|
-
options: {
|
|
162
|
+
options: {
|
|
163
|
+
useStrict?: boolean;
|
|
164
|
+
fallbackToTargetTitleField?: boolean;
|
|
165
|
+
targetCollectionTitleField?: CollectionField;
|
|
166
|
+
} = {},
|
|
124
167
|
): BindingOptions | null {
|
|
125
168
|
if (options.fallbackToTargetTitleField) {
|
|
126
169
|
const binding = this.getDefaultBindingByField(ctx, collectionField, { useStrict: true });
|
|
127
170
|
if (!binding) {
|
|
128
|
-
if (
|
|
129
|
-
|
|
171
|
+
if (
|
|
172
|
+
(collectionField.isAssociationField() && options?.targetCollectionTitleField) ||
|
|
173
|
+
collectionField.targetCollectionTitleField
|
|
174
|
+
) {
|
|
175
|
+
return this.getDefaultBindingByField(
|
|
176
|
+
ctx,
|
|
177
|
+
options?.targetCollectionTitleField || collectionField.targetCollectionTitleField,
|
|
178
|
+
);
|
|
130
179
|
}
|
|
131
180
|
}
|
|
132
181
|
return binding;
|
|
@@ -0,0 +1,169 @@
|
|
|
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 { describe, test, expect } from 'vitest';
|
|
11
|
+
import { FlowEngine } from '../../flowEngine';
|
|
12
|
+
import { FlowModel } from '../../models/flowModel';
|
|
13
|
+
|
|
14
|
+
describe('dispatchEvent behavior (defaults, parallel, errors)', () => {
|
|
15
|
+
test('non-beforeRender defaults to sequential execution and respects getEventFlows order', async () => {
|
|
16
|
+
const engine = new FlowEngine();
|
|
17
|
+
class M extends FlowModel {}
|
|
18
|
+
engine.registerModels({ M });
|
|
19
|
+
|
|
20
|
+
const calls: string[] = [];
|
|
21
|
+
|
|
22
|
+
// Static flow with higher sort
|
|
23
|
+
M.registerFlow({
|
|
24
|
+
key: 'S',
|
|
25
|
+
on: { eventName: 'go' },
|
|
26
|
+
sort: 10,
|
|
27
|
+
steps: { s: { handler: async () => void calls.push('static') } as any },
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const model = engine.createModel({ use: 'M' });
|
|
31
|
+
|
|
32
|
+
// Instance flows
|
|
33
|
+
model.registerFlow('I1', {
|
|
34
|
+
on: { eventName: 'go' },
|
|
35
|
+
sort: 0,
|
|
36
|
+
steps: { i1: { handler: async () => void calls.push('inst1') } as any },
|
|
37
|
+
});
|
|
38
|
+
model.registerFlow('I2', {
|
|
39
|
+
on: { eventName: 'go' },
|
|
40
|
+
sort: 5,
|
|
41
|
+
steps: { i2: { handler: async () => void calls.push('inst2') } as any },
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// No options provided -> should default to sequential execution
|
|
45
|
+
await model.dispatchEvent('go');
|
|
46
|
+
|
|
47
|
+
// Expected order should match getEventFlows('go') order
|
|
48
|
+
const expected = model.getEventFlows('go').map((f) => f.key);
|
|
49
|
+
expect(calls).toEqual(expected.map((k) => (k === 'I1' ? 'inst1' : k === 'I2' ? 'inst2' : 'static')));
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('parallel mode (sequential=false) runs all and tolerates non-beforeRender errors', async () => {
|
|
53
|
+
const engine = new FlowEngine();
|
|
54
|
+
class M extends FlowModel {}
|
|
55
|
+
engine.registerModels({ M });
|
|
56
|
+
|
|
57
|
+
const calls: string[] = [];
|
|
58
|
+
|
|
59
|
+
M.registerFlow({
|
|
60
|
+
key: 'S',
|
|
61
|
+
on: { eventName: 'go' },
|
|
62
|
+
sort: 1,
|
|
63
|
+
steps: { s: { handler: async () => 'static-ok' } as any },
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const model = engine.createModel({ use: 'M' });
|
|
67
|
+
|
|
68
|
+
model.registerFlow('I1', {
|
|
69
|
+
on: { eventName: 'go' },
|
|
70
|
+
sort: 0,
|
|
71
|
+
steps: { i1: { handler: async () => (calls.push('inst1'), 'i1-ok') } as any },
|
|
72
|
+
});
|
|
73
|
+
model.registerFlow('I2', {
|
|
74
|
+
on: { eventName: 'go' },
|
|
75
|
+
sort: 2,
|
|
76
|
+
steps: { i2: { handler: async () => (calls.push('inst2'), 'i2-ok') } as any },
|
|
77
|
+
});
|
|
78
|
+
model.registerFlow('ERR', {
|
|
79
|
+
on: { eventName: 'go' },
|
|
80
|
+
sort: 3,
|
|
81
|
+
steps: {
|
|
82
|
+
e: {
|
|
83
|
+
handler: async () => {
|
|
84
|
+
calls.push('err');
|
|
85
|
+
throw new Error('boom');
|
|
86
|
+
},
|
|
87
|
+
} as any,
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const results = await model.dispatchEvent('go', undefined, { sequential: false });
|
|
92
|
+
|
|
93
|
+
// All handlers ran; order is not guaranteed in parallel mode
|
|
94
|
+
expect(new Set(calls)).toEqual(new Set(['inst1', 'inst2', 'err']));
|
|
95
|
+
// The error flow returns undefined and is filtered out; others return stepResults objects
|
|
96
|
+
// Expect one result object per successful flow with its step key
|
|
97
|
+
expect(Array.isArray(results)).toBe(true);
|
|
98
|
+
const keys = (results as any[]).flatMap((o) => Object.keys(o));
|
|
99
|
+
expect(new Set(keys)).toEqual(new Set(['i1', 'i2', 's']));
|
|
100
|
+
const byKey = Object.assign({}, ...(results as any[]));
|
|
101
|
+
expect(byKey['i1']).toBe('i1-ok');
|
|
102
|
+
expect(byKey['i2']).toBe('i2-ok');
|
|
103
|
+
expect(byKey['s']).toBe('static-ok');
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test('sequential non-beforeRender: stops subsequent flows on error', async () => {
|
|
107
|
+
const engine = new FlowEngine();
|
|
108
|
+
class M extends FlowModel {}
|
|
109
|
+
engine.registerModels({ M });
|
|
110
|
+
|
|
111
|
+
const calls: string[] = [];
|
|
112
|
+
const model = engine.createModel({ use: 'M' });
|
|
113
|
+
|
|
114
|
+
model.registerFlow('I1', {
|
|
115
|
+
on: { eventName: 'go' },
|
|
116
|
+
sort: 0,
|
|
117
|
+
steps: { i1: { handler: async () => void calls.push('i1') } as any },
|
|
118
|
+
});
|
|
119
|
+
model.registerFlow('ERR', {
|
|
120
|
+
on: { eventName: 'go' },
|
|
121
|
+
sort: 1,
|
|
122
|
+
steps: {
|
|
123
|
+
e: {
|
|
124
|
+
handler: async () => {
|
|
125
|
+
throw new Error('X');
|
|
126
|
+
},
|
|
127
|
+
} as any,
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
model.registerFlow('I2', {
|
|
131
|
+
on: { eventName: 'go' },
|
|
132
|
+
sort: 2,
|
|
133
|
+
steps: { i2: { handler: async () => void calls.push('i2') } as any },
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
await model.dispatchEvent('go', undefined, { sequential: true }).catch(() => undefined);
|
|
137
|
+
// 只应执行第一个 flow,后续被中止
|
|
138
|
+
expect(calls).toEqual(['i1']);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test('beforeRender errors are thrown (sequential default)', async () => {
|
|
142
|
+
const engine = new FlowEngine();
|
|
143
|
+
class M extends FlowModel {}
|
|
144
|
+
engine.registerModels({ M });
|
|
145
|
+
|
|
146
|
+
const calls: string[] = [];
|
|
147
|
+
const model = engine.createModel({ use: 'M' });
|
|
148
|
+
|
|
149
|
+
model.registerFlow('F1', {
|
|
150
|
+
on: 'beforeRender',
|
|
151
|
+
sort: 0,
|
|
152
|
+
steps: {
|
|
153
|
+
a: {
|
|
154
|
+
handler: async () => {
|
|
155
|
+
throw new Error('BR');
|
|
156
|
+
},
|
|
157
|
+
} as any,
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
model.registerFlow('F2', {
|
|
161
|
+
on: 'beforeRender',
|
|
162
|
+
sort: 1,
|
|
163
|
+
steps: { b: { handler: async () => void calls.push('b') } as any },
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
await expect(model.dispatchEvent('beforeRender', undefined, { useCache: false })).rejects.toThrow('BR');
|
|
167
|
+
expect(calls).toEqual([]);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
@@ -10,19 +10,19 @@
|
|
|
10
10
|
import { describe, expect, test, beforeEach } from 'vitest';
|
|
11
11
|
import { FlowModel } from '@nocobase/flow-engine';
|
|
12
12
|
|
|
13
|
-
describe('FlowModel.getFlows sorting and
|
|
13
|
+
describe('FlowModel.getFlows sorting and getEventFlows(beforeRender) order', () => {
|
|
14
14
|
let TestFlowModel: typeof FlowModel;
|
|
15
15
|
let model: FlowModel;
|
|
16
16
|
|
|
17
17
|
beforeEach(() => {
|
|
18
18
|
// use a fresh subclass to isolate class-level registries
|
|
19
|
-
TestFlowModel = class extends FlowModel {};
|
|
19
|
+
TestFlowModel = class extends FlowModel<any> {};
|
|
20
20
|
// provide a minimal fake engine to avoid circular deps in tests
|
|
21
21
|
const fakeEngine = { getModel: () => undefined } as any;
|
|
22
22
|
model = new TestFlowModel({ flowEngine: fakeEngine } as any);
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
-
test('getFlows returns
|
|
25
|
+
test('getFlows returns dynamic(instance) flows first, each group ordered by sort ascending', () => {
|
|
26
26
|
// class-level (static) flows
|
|
27
27
|
TestFlowModel.registerFlow('flowA', { title: 'A', sort: 10, steps: {} });
|
|
28
28
|
TestFlowModel.registerFlow('flowB', { title: 'B', sort: 5, steps: {} });
|
|
@@ -34,10 +34,11 @@ describe('FlowModel.getFlows sorting and getAutoFlows order', () => {
|
|
|
34
34
|
const flows = model.getFlows();
|
|
35
35
|
const orderedKeys = Array.from(flows.keys());
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
// 动态流组:flowD(0), flowC(7);静态流组:flowB(5), flowA(10)
|
|
38
|
+
expect(orderedKeys).toEqual(['flowD', 'flowC', 'flowB', 'flowA']);
|
|
38
39
|
});
|
|
39
40
|
|
|
40
|
-
test('
|
|
41
|
+
test("getEventFlows('beforeRender') keeps getFlows order and filters out manual/on flows", () => {
|
|
41
42
|
// class-level
|
|
42
43
|
TestFlowModel.registerFlow('flowA', { title: 'A', sort: 10, steps: {} });
|
|
43
44
|
TestFlowModel.registerFlow('flowB', { title: 'B', sort: 5, steps: {} });
|
|
@@ -51,24 +52,25 @@ describe('FlowModel.getFlows sorting and getAutoFlows order', () => {
|
|
|
51
52
|
model.registerFlow('manualFlow', { title: 'Manual', manual: true, sort: -1, steps: {} });
|
|
52
53
|
|
|
53
54
|
const getFlowsOrder = Array.from(model.getFlows().keys());
|
|
54
|
-
const autoFlowKeys = model.
|
|
55
|
+
const autoFlowKeys = model.getEventFlows('beforeRender').map((f) => f.key);
|
|
55
56
|
|
|
56
57
|
// auto flows should exclude event/manual flows
|
|
57
|
-
|
|
58
|
+
// 新顺序:动态流组(flowD 0, flowC 7, flowE 8)→ 静态流组(flowB 5, flowA 10)
|
|
59
|
+
expect(autoFlowKeys).toEqual(['flowD', 'flowC', 'flowE', 'flowB', 'flowA']);
|
|
58
60
|
|
|
59
61
|
// relative order should match getFlows order (subset in same sequence)
|
|
60
62
|
const filteredGetFlowsOrder = getFlowsOrder.filter((k) => !['eventFlow', 'manualFlow'].includes(k));
|
|
61
63
|
expect(autoFlowKeys).toEqual(filteredGetFlowsOrder);
|
|
62
64
|
});
|
|
63
65
|
|
|
64
|
-
test('getFlows tie-breaker:
|
|
66
|
+
test('getFlows tie-breaker: instance before static when sort equal', () => {
|
|
65
67
|
// static flow with sort 2
|
|
66
68
|
TestFlowModel.registerFlow('static2', { title: 'S2', sort: 2, steps: {} });
|
|
67
69
|
// instance flow with same sort 2
|
|
68
70
|
model.registerFlow('instance2', { title: 'I2', sort: 2, steps: {} });
|
|
69
71
|
|
|
70
72
|
const keys = Array.from(model.getFlows().keys());
|
|
71
|
-
expect(keys.indexOf('
|
|
73
|
+
expect(keys.indexOf('instance2')).toBeLessThan(keys.indexOf('static2'));
|
|
72
74
|
});
|
|
73
75
|
|
|
74
76
|
test('getFlows tie-breaker: parent static before child static when sort equal', () => {
|
|
@@ -97,4 +99,26 @@ describe('FlowModel.getFlows sorting and getAutoFlows order', () => {
|
|
|
97
99
|
const keys = Array.from(staticFlows.keys());
|
|
98
100
|
expect(keys.indexOf('p')).toBeLessThan(keys.indexOf('c'));
|
|
99
101
|
});
|
|
102
|
+
|
|
103
|
+
test('instance flows keep registration order when sort equal', () => {
|
|
104
|
+
// same sort for all instance flows -> keep registration order
|
|
105
|
+
model.registerFlow('i1', { title: 'I1', sort: 1, steps: {} } as any);
|
|
106
|
+
model.registerFlow('i2', { title: 'I2', sort: 1, steps: {} } as any);
|
|
107
|
+
model.registerFlow('i3', { title: 'I3', sort: 1, steps: {} } as any);
|
|
108
|
+
|
|
109
|
+
// add some static flows to ensure grouping doesn't affect instance intra-order
|
|
110
|
+
(TestFlowModel as any).registerFlow('s1', { title: 'S1', sort: 1, steps: {} });
|
|
111
|
+
(TestFlowModel as any).registerFlow('s2', { title: 'S2', sort: 2, steps: {} });
|
|
112
|
+
|
|
113
|
+
const keys = Array.from(model.getFlows().keys());
|
|
114
|
+
// Instance group appears first and preserves registration order
|
|
115
|
+
const posI1 = keys.indexOf('i1');
|
|
116
|
+
const posI2 = keys.indexOf('i2');
|
|
117
|
+
const posI3 = keys.indexOf('i3');
|
|
118
|
+
expect(posI1).toBeLessThan(posI2);
|
|
119
|
+
expect(posI2).toBeLessThan(posI3);
|
|
120
|
+
|
|
121
|
+
// Static group follows
|
|
122
|
+
expect(keys.slice(posI3 + 1)).toEqual(expect.arrayContaining(['s1', 's2']));
|
|
123
|
+
});
|
|
100
124
|
});
|