@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
|
@@ -847,6 +847,7 @@ describe('AddSubModelButton toggleable behavior', () => {
|
|
|
847
847
|
save = vi.fn().mockResolvedValue({});
|
|
848
848
|
destroy = vi.fn().mockResolvedValue(true);
|
|
849
849
|
move = vi.fn().mockResolvedValue(undefined);
|
|
850
|
+
duplicate = vi.fn().mockResolvedValue(null);
|
|
850
851
|
}
|
|
851
852
|
|
|
852
853
|
function setup() {
|
|
@@ -942,13 +943,10 @@ describe('AddSubModelButton toggleable behavior', () => {
|
|
|
942
943
|
expect(screen.getByText('Child A')).toBeInTheDocument();
|
|
943
944
|
expect(screen.getByText('Child B')).toBeInTheDocument();
|
|
944
945
|
|
|
945
|
-
// ensure destroy
|
|
946
|
-
await waitFor(
|
|
947
|
-
()
|
|
948
|
-
|
|
949
|
-
},
|
|
950
|
-
{ timeout: 5000 },
|
|
951
|
-
);
|
|
946
|
+
// ensure destroy has been called (avoid flakiness on exact call counts)
|
|
947
|
+
await waitFor(() => {
|
|
948
|
+
expect(repo.destroy).toHaveBeenCalled();
|
|
949
|
+
});
|
|
952
950
|
});
|
|
953
951
|
|
|
954
952
|
test('toggle state updates without menu closing', async () => {
|
|
@@ -85,6 +85,7 @@ const VariableInputComponent: React.FC<VariableInputProps> = ({
|
|
|
85
85
|
showValueComponent = true,
|
|
86
86
|
onlyLeafSelectable = false,
|
|
87
87
|
clearValue,
|
|
88
|
+
ignoreFieldNames,
|
|
88
89
|
...restProps
|
|
89
90
|
}) => {
|
|
90
91
|
const [currentMetaTreeNode, setCurrentMetaTreeNode] = useState<MetaTreeNode | null>(null);
|
|
@@ -138,7 +139,7 @@ const VariableInputComponent: React.FC<VariableInputProps> = ({
|
|
|
138
139
|
// 当 value 存在但 currentMetaTreeNode 还未恢复,尝试按路径逐级加载(支持 children 为函数的场景)
|
|
139
140
|
useEffect(() => {
|
|
140
141
|
const restoreFromValue = async () => {
|
|
141
|
-
if (!Array.isArray(resolvedMetaTree) ||
|
|
142
|
+
if (!Array.isArray(resolvedMetaTree) || value == null) return;
|
|
142
143
|
|
|
143
144
|
// 若已存在且路径匹配,跳过
|
|
144
145
|
if (currentMetaTreeNode) {
|
|
@@ -202,7 +203,7 @@ const VariableInputComponent: React.FC<VariableInputProps> = ({
|
|
|
202
203
|
|
|
203
204
|
useEffect(() => {
|
|
204
205
|
if (!resolvedMetaTreeNode) return;
|
|
205
|
-
if (!Array.isArray(resolvedMetaTree) ||
|
|
206
|
+
if (!Array.isArray(resolvedMetaTree) || innerValue == null) return;
|
|
206
207
|
const finalValue = resolveValueFromPath?.(resolvedMetaTreeNode) || innerValue;
|
|
207
208
|
emitChange(finalValue, resolvedMetaTreeNode);
|
|
208
209
|
setCurrentMetaTreeNode(resolvedMetaTreeNode);
|
|
@@ -254,11 +255,29 @@ const VariableInputComponent: React.FC<VariableInputProps> = ({
|
|
|
254
255
|
if (disabled) {
|
|
255
256
|
return;
|
|
256
257
|
}
|
|
257
|
-
setCurrentMetaTreeNode(null);
|
|
258
258
|
const cleared = clearValue !== undefined ? clearValue : null;
|
|
259
259
|
setInnerValue(cleared);
|
|
260
|
+
|
|
261
|
+
// 若 clearValue 能解析到某个路径(例如 ['constant']),
|
|
262
|
+
// 则尝试立即定位到对应的 MetaTreeNode,以便渲染正确的常量组件。
|
|
263
|
+
try {
|
|
264
|
+
const path = resolvePathFromValue?.(cleared);
|
|
265
|
+
if (Array.isArray(resolvedMetaTree) && path && path.length > 0) {
|
|
266
|
+
const node = findMetaTreeNodeByPath(resolvedMetaTree as MetaTreeNode[], path as string[]);
|
|
267
|
+
if (node) {
|
|
268
|
+
setCurrentMetaTreeNode(node);
|
|
269
|
+
emitChange(cleared as any, node);
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
} catch (_) {
|
|
274
|
+
// 忽略解析异常,走默认回退
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// 默认回退(无法定位具体 MetaTreeNode 时)
|
|
278
|
+
setCurrentMetaTreeNode(null);
|
|
260
279
|
emitChange(cleared as any);
|
|
261
|
-
}, [emitChange, disabled, clearValue]);
|
|
280
|
+
}, [emitChange, disabled, clearValue, resolvedMetaTree, resolvePathFromValue]);
|
|
262
281
|
|
|
263
282
|
const stableProps = useMemo(() => {
|
|
264
283
|
const { style, onFocus, onBlur, disabled, ...otherProps } = restProps;
|
|
@@ -267,7 +286,7 @@ const VariableInputComponent: React.FC<VariableInputProps> = ({
|
|
|
267
286
|
|
|
268
287
|
const inputProps = useMemo(() => {
|
|
269
288
|
const baseProps = {
|
|
270
|
-
value: innerValue
|
|
289
|
+
value: innerValue ?? '',
|
|
271
290
|
onChange: handleInputChange,
|
|
272
291
|
disabled,
|
|
273
292
|
};
|
|
@@ -333,6 +352,7 @@ const VariableInputComponent: React.FC<VariableInputProps> = ({
|
|
|
333
352
|
parseValueToPath={resolvePathFromValue}
|
|
334
353
|
formatPathToValue={resolveValueFromPath}
|
|
335
354
|
onlyLeafSelectable={onlyLeafSelectable}
|
|
355
|
+
ignoreFieldNames={ignoreFieldNames}
|
|
336
356
|
{...(!showValueComponent && { children: null, placeholder: restProps?.placeholder })}
|
|
337
357
|
/>
|
|
338
358
|
</Space.Compact>
|
|
@@ -15,6 +15,7 @@ import { parseValueToPath } from './utils';
|
|
|
15
15
|
import { useResolvedMetaTree } from './useResolvedMetaTree';
|
|
16
16
|
import { useRequest } from 'ahooks';
|
|
17
17
|
import { useFlowContext } from '../../FlowContextProvider';
|
|
18
|
+
import type { MetaTreeNode } from '../../flowContext';
|
|
18
19
|
|
|
19
20
|
const VariableTagComponent: React.FC<VariableTagProps> = ({
|
|
20
21
|
value,
|
|
@@ -29,14 +30,65 @@ const VariableTagComponent: React.FC<VariableTagProps> = ({
|
|
|
29
30
|
|
|
30
31
|
const { data: displayedValue } = useRequest(
|
|
31
32
|
async () => {
|
|
33
|
+
// 1) 优先使用已解析到的节点(包含完整父标题链)
|
|
32
34
|
if (metaTreeNode) {
|
|
33
35
|
return metaTreeNode.parentTitles
|
|
34
36
|
? [...metaTreeNode.parentTitles, metaTreeNode.title].map(ctx.t).join('/')
|
|
35
37
|
: ctx.t(metaTreeNode.title) || '';
|
|
36
38
|
}
|
|
39
|
+
|
|
40
|
+
// 2) 无 metaTreeNode 时,尝试从值还原路径,并在 metaTree 中寻找“最深前缀节点”,
|
|
41
|
+
// 即便最后一段无效,也能显示前缀的翻译标题。
|
|
37
42
|
if (!value) return String(value);
|
|
38
|
-
const
|
|
39
|
-
|
|
43
|
+
const rawPath = parseValueToPath(value);
|
|
44
|
+
if (!rawPath || !Array.isArray(resolvedMetaTree)) {
|
|
45
|
+
return Array.isArray(rawPath) ? rawPath.join('/') : String(value);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 兼容 metaTree 为子树:顶层不含首段时,裁剪首段
|
|
49
|
+
const topNames = new Set((resolvedMetaTree || []).map((n: any) => String(n?.name)));
|
|
50
|
+
const path = !topNames.has(String(rawPath[0])) ? rawPath.slice(1) : rawPath;
|
|
51
|
+
if (!path.length) return '';
|
|
52
|
+
|
|
53
|
+
let nodes: MetaTreeNode[] | undefined = resolvedMetaTree as MetaTreeNode[];
|
|
54
|
+
let deepest: MetaTreeNode | null = null;
|
|
55
|
+
let matchedCount = 0;
|
|
56
|
+
for (let i = 0; i < path.length; i++) {
|
|
57
|
+
if (!nodes) break;
|
|
58
|
+
const seg = String(path[i]);
|
|
59
|
+
const node = nodes.find((n) => String(n?.name) === seg) as MetaTreeNode | undefined;
|
|
60
|
+
if (!node) break; // 停在第一个无效段之前
|
|
61
|
+
deepest = node;
|
|
62
|
+
matchedCount = i + 1;
|
|
63
|
+
if (i < path.length - 1) {
|
|
64
|
+
if (Array.isArray(node.children)) {
|
|
65
|
+
nodes = node.children as any;
|
|
66
|
+
} else if (typeof node.children === 'function') {
|
|
67
|
+
try {
|
|
68
|
+
const childNodes = await (node.children as any)();
|
|
69
|
+
(node as any).children = childNodes;
|
|
70
|
+
nodes = childNodes as any;
|
|
71
|
+
} catch {
|
|
72
|
+
nodes = undefined;
|
|
73
|
+
}
|
|
74
|
+
} else {
|
|
75
|
+
nodes = undefined;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (deepest) {
|
|
81
|
+
const titles = deepest.parentTitles ? [...deepest.parentTitles, deepest.title] : [deepest.title];
|
|
82
|
+
let label = titles.map(ctx.t).join('/');
|
|
83
|
+
if (matchedCount < path.length) {
|
|
84
|
+
const tail = path.slice(matchedCount).join('/');
|
|
85
|
+
label = tail ? `${label}/${tail}` : label;
|
|
86
|
+
}
|
|
87
|
+
return label;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// 3) 完全找不到任何前缀时,退回原始路径字符串
|
|
91
|
+
return path.join('/');
|
|
40
92
|
},
|
|
41
93
|
{ refreshDeps: [resolvedMetaTree, value, metaTreeNode] },
|
|
42
94
|
);
|
|
@@ -21,6 +21,7 @@ export interface FlowContextSelectorProps
|
|
|
21
21
|
formatPathToValue?: (item: MetaTreeNode) => string;
|
|
22
22
|
open?: boolean;
|
|
23
23
|
onlyLeafSelectable?: boolean;
|
|
24
|
+
ignoreFieldNames?: string[];
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
export interface ContextSelectorItem {
|
|
@@ -69,6 +70,7 @@ export interface VariableInputProps {
|
|
|
69
70
|
* 默认行为为 null;可设置为 '' 等,以便清空后默认切换为“常量-空字符串”。
|
|
70
71
|
*/
|
|
71
72
|
clearValue?: any;
|
|
73
|
+
ignoreFieldNames?: string[];
|
|
72
74
|
[key: string]: any;
|
|
73
75
|
}
|
|
74
76
|
|
|
@@ -0,0 +1,125 @@
|
|
|
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, expect, it } from 'vitest';
|
|
11
|
+
import { sortCollectionsByInherits } from '../sortCollectionsByInherits';
|
|
12
|
+
|
|
13
|
+
describe('sortCollectionsByInherits', () => {
|
|
14
|
+
it('should sort collections by their inherits in correct order', () => {
|
|
15
|
+
const collections = [
|
|
16
|
+
{ name: 'posts', inherits: [] },
|
|
17
|
+
{ name: 'comments', inherits: ['posts'] },
|
|
18
|
+
{ name: 'users', inherits: ['comments'] },
|
|
19
|
+
];
|
|
20
|
+
const sorted = sortCollectionsByInherits(collections);
|
|
21
|
+
expect(sorted.map((c) => c.name)).toEqual(['posts', 'comments', 'users']);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should handle collections with no inherits', () => {
|
|
25
|
+
const collections = [
|
|
26
|
+
{ name: 'users', inherits: [] },
|
|
27
|
+
{ name: 'posts', inherits: [] },
|
|
28
|
+
];
|
|
29
|
+
const sorted = sortCollectionsByInherits(collections);
|
|
30
|
+
expect(sorted.map((c) => c.name)).toEqual(['users', 'posts']);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should handle collections with undefined inherits', () => {
|
|
34
|
+
const collections = [{ name: 'users' }, { name: 'posts' }];
|
|
35
|
+
const sorted = sortCollectionsByInherits(collections);
|
|
36
|
+
expect(sorted.map((c) => c.name)).toEqual(['users', 'posts']);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should handle complex inheritance chains', () => {
|
|
40
|
+
const collections = [
|
|
41
|
+
{ name: 'base', inherits: [] },
|
|
42
|
+
{ name: 'middle', inherits: ['base'] },
|
|
43
|
+
{ name: 'top', inherits: ['middle'] },
|
|
44
|
+
{ name: 'independent', inherits: [] },
|
|
45
|
+
];
|
|
46
|
+
const sorted = sortCollectionsByInherits(collections);
|
|
47
|
+
expect(sorted.map((c) => c.name)).toEqual(['base', 'middle', 'top', 'independent']);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should handle multiple inheritance', () => {
|
|
51
|
+
const collections = [
|
|
52
|
+
{ name: 'user', inherits: [] },
|
|
53
|
+
{ name: 'post', inherits: [] },
|
|
54
|
+
{ name: 'comment', inherits: ['user', 'post'] },
|
|
55
|
+
];
|
|
56
|
+
const sorted = sortCollectionsByInherits(collections);
|
|
57
|
+
expect(sorted.map((c) => c.name)).toEqual(['user', 'post', 'comment']);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should throw error for circular dependencies', () => {
|
|
61
|
+
const collections = [
|
|
62
|
+
{ name: 'a', inherits: ['b'] },
|
|
63
|
+
{ name: 'b', inherits: ['a'] },
|
|
64
|
+
];
|
|
65
|
+
expect(() => sortCollectionsByInherits(collections)).toThrow('Circular dependency detected');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should gracefully handle missing inherit collections', () => {
|
|
69
|
+
const collections = [
|
|
70
|
+
{ name: 'posts', inherits: ['nonexistent'] },
|
|
71
|
+
{ name: 'users', inherits: [] },
|
|
72
|
+
];
|
|
73
|
+
const sorted = sortCollectionsByInherits(collections);
|
|
74
|
+
expect(sorted.map((c) => c.name)).toEqual(['posts', 'users']);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should handle self-inheritance circular dependency', () => {
|
|
78
|
+
const collections = [{ name: 'posts', inherits: ['posts'] }];
|
|
79
|
+
expect(() => sortCollectionsByInherits(collections)).toThrow('Circular dependency detected');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('should maintain order for collections without dependencies', () => {
|
|
83
|
+
const collections = [
|
|
84
|
+
{ name: 'z', inherits: [] },
|
|
85
|
+
{ name: 'a', inherits: [] },
|
|
86
|
+
{ name: 'm', inherits: [] },
|
|
87
|
+
];
|
|
88
|
+
const sorted = sortCollectionsByInherits(collections);
|
|
89
|
+
expect(sorted.map((c) => c.name)).toEqual(['z', 'a', 'm']);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should handle empty collections array', () => {
|
|
93
|
+
const sorted = sortCollectionsByInherits([]);
|
|
94
|
+
expect(sorted).toEqual([]);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should handle collections with multiple missing inherits', () => {
|
|
98
|
+
const collections = [
|
|
99
|
+
{ name: 'posts', inherits: ['missing1', 'missing2'] },
|
|
100
|
+
{ name: 'users', inherits: ['missing3'] },
|
|
101
|
+
{ name: 'comments', inherits: ['posts', 'missing4'] },
|
|
102
|
+
];
|
|
103
|
+
const sorted = sortCollectionsByInherits(collections);
|
|
104
|
+
expect(sorted.map((c) => c.name)).toEqual(['posts', 'users', 'comments']);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should handle mixed existing and missing inherits', () => {
|
|
108
|
+
const collections = [
|
|
109
|
+
{ name: 'base', inherits: [] },
|
|
110
|
+
{ name: 'middle', inherits: ['base', 'missing'] },
|
|
111
|
+
{ name: 'top', inherits: ['middle'] },
|
|
112
|
+
];
|
|
113
|
+
const sorted = sortCollectionsByInherits(collections);
|
|
114
|
+
expect(sorted.map((c) => c.name)).toEqual(['base', 'middle', 'top']);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should handle all inherits missing', () => {
|
|
118
|
+
const collections = [
|
|
119
|
+
{ name: 'posts', inherits: ['missing1', 'missing2'] },
|
|
120
|
+
{ name: 'users', inherits: ['missing3'] },
|
|
121
|
+
];
|
|
122
|
+
const sorted = sortCollectionsByInherits(collections);
|
|
123
|
+
expect(sorted.map((c) => c.name)).toEqual(['posts', 'users']);
|
|
124
|
+
});
|
|
125
|
+
});
|
package/src/data-source/index.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { observable } from '@formily/reactive';
|
|
|
11
11
|
import _ from 'lodash';
|
|
12
12
|
import { FlowEngine } from '../flowEngine';
|
|
13
13
|
import { jioToJoiSchema } from './jioToJoiSchema';
|
|
14
|
+
import { sortCollectionsByInherits } from './sortCollectionsByInherits';
|
|
14
15
|
export interface DataSourceOptions extends Record<string, any> {
|
|
15
16
|
key: string;
|
|
16
17
|
displayName?: string;
|
|
@@ -143,8 +144,8 @@ export class DataSource {
|
|
|
143
144
|
return this.collectionManager.upsertCollection(options);
|
|
144
145
|
}
|
|
145
146
|
|
|
146
|
-
upsertCollections(collections: CollectionOptions[]) {
|
|
147
|
-
return this.collectionManager.upsertCollections(collections);
|
|
147
|
+
upsertCollections(collections: CollectionOptions[], options: { clearFields?: boolean } = {}) {
|
|
148
|
+
return this.collectionManager.upsertCollections(collections, options);
|
|
148
149
|
}
|
|
149
150
|
|
|
150
151
|
removeCollection(name: string) {
|
|
@@ -209,12 +210,12 @@ export class CollectionManager {
|
|
|
209
210
|
this.collections.delete(name);
|
|
210
211
|
}
|
|
211
212
|
|
|
212
|
-
updateCollection(newOptions: CollectionOptions) {
|
|
213
|
+
updateCollection(newOptions: CollectionOptions, options: { clearFields?: boolean } = {}) {
|
|
213
214
|
const collection = this.getCollection(newOptions.name);
|
|
214
215
|
if (!collection) {
|
|
215
216
|
throw new Error(`Collection ${newOptions.name} not found`);
|
|
216
217
|
}
|
|
217
|
-
collection.setOptions(newOptions);
|
|
218
|
+
collection.setOptions(newOptions, options);
|
|
218
219
|
}
|
|
219
220
|
|
|
220
221
|
upsertCollection(options: CollectionOptions) {
|
|
@@ -226,10 +227,10 @@ export class CollectionManager {
|
|
|
226
227
|
return this.getCollection(options.name);
|
|
227
228
|
}
|
|
228
229
|
|
|
229
|
-
upsertCollections(collections: CollectionOptions[]) {
|
|
230
|
-
for (const collection of
|
|
230
|
+
upsertCollections(collections: CollectionOptions[], options: { clearFields?: boolean } = {}) {
|
|
231
|
+
for (const collection of sortCollectionsByInherits(collections)) {
|
|
231
232
|
if (this.collections.has(collection.name)) {
|
|
232
|
-
this.updateCollection(collection);
|
|
233
|
+
this.updateCollection(collection, options);
|
|
233
234
|
} else {
|
|
234
235
|
this.addCollection(collection);
|
|
235
236
|
}
|
|
@@ -320,6 +321,23 @@ export class CollectionManager {
|
|
|
320
321
|
}
|
|
321
322
|
return collection.getField(fieldName);
|
|
322
323
|
}
|
|
324
|
+
|
|
325
|
+
getChildrenCollections(name) {
|
|
326
|
+
const childrens = [];
|
|
327
|
+
const collections = Array.from(this.collections.values());
|
|
328
|
+
const getChildrens = (name) => {
|
|
329
|
+
const inheritCollections = collections.filter((v: any) => {
|
|
330
|
+
return v.options.inherits?.includes(name);
|
|
331
|
+
});
|
|
332
|
+
inheritCollections.forEach((v) => {
|
|
333
|
+
const collectionKey = v.name;
|
|
334
|
+
childrens.push(v);
|
|
335
|
+
return getChildrens(collectionKey);
|
|
336
|
+
});
|
|
337
|
+
return childrens;
|
|
338
|
+
};
|
|
339
|
+
return getChildrens(name);
|
|
340
|
+
}
|
|
323
341
|
}
|
|
324
342
|
|
|
325
343
|
// Collection 负责管理自己的 Field
|
|
@@ -352,6 +370,10 @@ export class Collection {
|
|
|
352
370
|
return _.pick(record, this.filterTargetKey);
|
|
353
371
|
}
|
|
354
372
|
|
|
373
|
+
get titleableFields() {
|
|
374
|
+
return this.getFields().filter((field) => field.titleable);
|
|
375
|
+
}
|
|
376
|
+
|
|
355
377
|
get hidden() {
|
|
356
378
|
return this.options.hidden || false;
|
|
357
379
|
}
|
|
@@ -400,7 +422,8 @@ export class Collection {
|
|
|
400
422
|
for (const inherit of this.options.inherits || []) {
|
|
401
423
|
const collection = this.collectionManager.getCollection(inherit);
|
|
402
424
|
if (!collection) {
|
|
403
|
-
|
|
425
|
+
console.warn(`Warning: Collection ${inherit} not found for collection ${this.name}`);
|
|
426
|
+
continue;
|
|
404
427
|
}
|
|
405
428
|
this.inherits.set(inherit, collection);
|
|
406
429
|
}
|
|
@@ -410,10 +433,13 @@ export class Collection {
|
|
|
410
433
|
this.dataSource = dataSource;
|
|
411
434
|
}
|
|
412
435
|
|
|
413
|
-
setOptions(newOptions: any = {}) {
|
|
436
|
+
setOptions(newOptions: any = {}, options: { clearFields?: boolean } = {}) {
|
|
414
437
|
Object.keys(this.options).forEach((key) => delete this.options[key]);
|
|
415
438
|
Object.assign(this.options, newOptions);
|
|
416
439
|
this.initInherits();
|
|
440
|
+
if (options.clearFields) {
|
|
441
|
+
this.clearFields();
|
|
442
|
+
}
|
|
417
443
|
this.upsertFields(this.options.fields || []);
|
|
418
444
|
}
|
|
419
445
|
|
|
@@ -481,7 +507,7 @@ export class Collection {
|
|
|
481
507
|
if (otherKeys.length === 0) {
|
|
482
508
|
return field;
|
|
483
509
|
}
|
|
484
|
-
if (!field
|
|
510
|
+
if (!field?.targetCollection) {
|
|
485
511
|
return null;
|
|
486
512
|
}
|
|
487
513
|
return field.targetCollection.getFieldByPath(otherKeys.join('.'));
|
|
@@ -618,6 +644,10 @@ export class CollectionField {
|
|
|
618
644
|
return this.options.readonly || this.options.uiSchema?.['x-read-pretty'] || false;
|
|
619
645
|
}
|
|
620
646
|
|
|
647
|
+
get titleable() {
|
|
648
|
+
return !!(this.options.titleable ?? this.options.titleUsable);
|
|
649
|
+
}
|
|
650
|
+
|
|
621
651
|
get fullpath() {
|
|
622
652
|
return this.collection.dataSource.key + '.' + this.collection.name + '.' + this.name;
|
|
623
653
|
}
|
|
@@ -651,7 +681,7 @@ export class CollectionField {
|
|
|
651
681
|
}
|
|
652
682
|
|
|
653
683
|
get title() {
|
|
654
|
-
const titleValue = this.options?.title || this.options?.
|
|
684
|
+
const titleValue = this.options?.uiSchema?.title || this.options?.title || this.options.name;
|
|
655
685
|
return this.flowEngine.translate(titleValue);
|
|
656
686
|
}
|
|
657
687
|
|
|
@@ -700,6 +730,7 @@ export class CollectionField {
|
|
|
700
730
|
multiple: target ? ['belongsToMany', 'hasMany', 'belongsToArray'].includes(type) : undefined,
|
|
701
731
|
maxCount: target && !['belongsToMany', 'hasMany', 'belongsToArray'].includes(type) ? 1 : undefined,
|
|
702
732
|
target: target,
|
|
733
|
+
template: this.targetCollection?.template,
|
|
703
734
|
},
|
|
704
735
|
_.isUndefined,
|
|
705
736
|
);
|
|
@@ -0,0 +1,61 @@
|
|
|
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 { CollectionOptions } from '.';
|
|
11
|
+
|
|
12
|
+
export function sortCollectionsByInherits(collections: CollectionOptions[]): CollectionOptions[] {
|
|
13
|
+
const sorted: CollectionOptions[] = [];
|
|
14
|
+
const visited = new Set<string>();
|
|
15
|
+
const visiting = new Set<string>();
|
|
16
|
+
const map = new Map<string, CollectionOptions>();
|
|
17
|
+
|
|
18
|
+
// Create a map for O(1) lookup
|
|
19
|
+
collections.forEach((col) => {
|
|
20
|
+
map.set(col.name, col);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const addToSorted = (col: CollectionOptions): void => {
|
|
24
|
+
// Check for circular dependency
|
|
25
|
+
if (visiting.has(col.name)) {
|
|
26
|
+
throw new Error(`Circular dependency detected: ${col.name} inherits from itself through a chain`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Skip if already processed
|
|
30
|
+
if (visited.has(col.name)) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Mark as currently being processed
|
|
35
|
+
visiting.add(col.name);
|
|
36
|
+
|
|
37
|
+
// Process inherits first (dependencies)
|
|
38
|
+
const inherits = col.inherits || [];
|
|
39
|
+
for (const inheritName of inherits) {
|
|
40
|
+
const inheritCol = map.get(inheritName);
|
|
41
|
+
if (!inheritCol) {
|
|
42
|
+
console.warn(`Warning: Collection ${inheritName}, inherited by ${col.name}, not found.`);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
addToSorted(inheritCol);
|
|
46
|
+
// Silently skip missing inherit collections
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Mark as processed and add to sorted array
|
|
50
|
+
visiting.delete(col.name);
|
|
51
|
+
visited.add(col.name);
|
|
52
|
+
sorted.push(col);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Process all collections
|
|
56
|
+
for (const col of collections) {
|
|
57
|
+
addToSorted(col);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return sorted;
|
|
61
|
+
}
|
package/src/emitter.ts
CHANGED
|
@@ -30,4 +30,18 @@ export class Emitter {
|
|
|
30
30
|
}
|
|
31
31
|
(this.events[event] || []).forEach((fn) => fn(...args));
|
|
32
32
|
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 异步触发事件:按监听器注册顺序依次(串行)等待执行完成。
|
|
36
|
+
* - 若某个监听器抛错/Promise reject,将中断后续执行并将异常向上传递(便于调用方统一处理)。
|
|
37
|
+
* - 当前不提供并行触发能力;如需并发处理,请在监听器内部自行管理(例如在回调内使用 Promise.all)。
|
|
38
|
+
*/
|
|
39
|
+
async emitAsync(event: string, ...args: any[]): Promise<void> {
|
|
40
|
+
if (this.paused) return;
|
|
41
|
+
const listeners = (this.events[event] || []).slice(); // 防止触发过程中被修改
|
|
42
|
+
for (const fn of listeners) {
|
|
43
|
+
// 兼容同步/异步监听器
|
|
44
|
+
await fn(...args);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
33
47
|
}
|