@nocobase/flow-engine 2.0.0-alpha.4 → 2.0.0-alpha.41
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 +224 -87
- package/lib/flowEngine.d.ts +24 -1
- package/lib/flowEngine.js +81 -8
- package/lib/flowSettings.d.ts +2 -1
- package/lib/flowSettings.js +16 -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 +52 -6
- package/lib/models/flowModel.d.ts +30 -29
- package/lib/models/flowModel.js +153 -100
- 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 +205 -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 +162 -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-antd-icons.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/block/render-antd-icons.snippet.js +65 -0
- 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 +21 -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 +22 -5
- package/lib/utils/variablesParams.js +132 -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 +9 -8
- package/lib/views/useDialog.js +19 -14
- package/lib/views/useDrawer.d.ts +9 -8
- package/lib/views/useDrawer.js +54 -35
- package/lib/views/usePage.d.ts +9 -8
- package/lib/views/usePage.js +20 -14
- 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 +461 -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 +303 -104
- package/src/flowEngine.ts +96 -6
- package/src/flowSettings.ts +12 -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 +60 -8
- 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 +197 -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 +196 -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 +178 -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-antd-icons.snippet.ts +46 -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/__tests__/variablesParams.test.ts +63 -0
- 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 +11 -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 +156 -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 +24 -18
- package/src/views/useDrawer.tsx +74 -45
- package/src/views/usePage.tsx +26 -17
- 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
|
@@ -11,6 +11,7 @@ import { describe, expect, it } from 'vitest';
|
|
|
11
11
|
import {
|
|
12
12
|
collectContextParamsForTemplate,
|
|
13
13
|
createRecordMetaFactory,
|
|
14
|
+
createRecordResolveOnServerWithLocal,
|
|
14
15
|
inferParentRecordRef,
|
|
15
16
|
inferRecordRef,
|
|
16
17
|
} from '../variablesParams';
|
|
@@ -49,4 +50,66 @@ describe('variablesParams helpers', () => {
|
|
|
49
50
|
expect(res).toHaveProperty('record');
|
|
50
51
|
expect(res).not.toHaveProperty('user');
|
|
51
52
|
});
|
|
53
|
+
|
|
54
|
+
it('createRecordResolveOnServerWithLocal: no local record => always use server', () => {
|
|
55
|
+
const resolver = createRecordResolveOnServerWithLocal(
|
|
56
|
+
() => ({ name: 'posts', dataSourceKey: 'main' }) as any,
|
|
57
|
+
() => undefined,
|
|
58
|
+
);
|
|
59
|
+
expect(resolver('')).toBe(true);
|
|
60
|
+
expect(resolver('title')).toBe(true);
|
|
61
|
+
expect(resolver('author.name')).toBe(true);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('createRecordResolveOnServerWithLocal: local record + non-association subpaths => use local', () => {
|
|
65
|
+
const collection: any = {
|
|
66
|
+
getField: (name: string) => {
|
|
67
|
+
if (name === 'id') return { name: 'id', isAssociationField: () => false };
|
|
68
|
+
if (name === 'title') return { name: 'title', isAssociationField: () => false };
|
|
69
|
+
return undefined;
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
const record = { id: 1, title: 'Hello' };
|
|
73
|
+
const resolver = createRecordResolveOnServerWithLocal(
|
|
74
|
+
() => collection,
|
|
75
|
+
() => record,
|
|
76
|
+
);
|
|
77
|
+
expect(resolver('')).toBe(false);
|
|
78
|
+
expect(resolver('id')).toBe(false);
|
|
79
|
+
expect(resolver('title')).toBe(false);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('createRecordResolveOnServerWithLocal: association with local value => still use local', () => {
|
|
83
|
+
const collection: any = {
|
|
84
|
+
getField: (name: string) => {
|
|
85
|
+
if (name === 'author') return { name: 'author', isAssociationField: () => true };
|
|
86
|
+
if (name === 'title') return { name: 'title', isAssociationField: () => false };
|
|
87
|
+
return undefined;
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
const record = { title: 'Hello', author: { id: 1, name: 'Alice' } };
|
|
91
|
+
const resolver = createRecordResolveOnServerWithLocal(
|
|
92
|
+
() => collection,
|
|
93
|
+
() => record,
|
|
94
|
+
);
|
|
95
|
+
expect(resolver('author')).toBe(false);
|
|
96
|
+
expect(resolver('author.name')).toBe(false);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('createRecordResolveOnServerWithLocal: association without local value => use server', () => {
|
|
100
|
+
const collection: any = {
|
|
101
|
+
getField: (name: string) => {
|
|
102
|
+
if (name === 'author') return { name: 'author', isAssociationField: () => true };
|
|
103
|
+
if (name === 'title') return { name: 'title', isAssociationField: () => false };
|
|
104
|
+
return undefined;
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
const record = { title: 'Hello', author: null };
|
|
108
|
+
const resolver = createRecordResolveOnServerWithLocal(
|
|
109
|
+
() => collection,
|
|
110
|
+
() => record,
|
|
111
|
+
);
|
|
112
|
+
expect(resolver('author')).toBe(true);
|
|
113
|
+
expect(resolver('author.name')).toBe(true);
|
|
114
|
+
});
|
|
52
115
|
});
|
|
@@ -0,0 +1,180 @@
|
|
|
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 type { Collection, CollectionField } from '../data-source';
|
|
11
|
+
import _ from 'lodash';
|
|
12
|
+
import type { FlowContext, PropertyMeta, PropertyMetaFactory } from '../flowContext';
|
|
13
|
+
import { createCollectionContextMeta } from './createCollectionContextMeta';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 提取变量子路径的顶层字段名。
|
|
17
|
+
* 例如:
|
|
18
|
+
* - 'author.name' => 'author'
|
|
19
|
+
* - 'tags[0].name' => 'tags'
|
|
20
|
+
*
|
|
21
|
+
* @param subPath 变量在对象中的子路径字符串
|
|
22
|
+
* @returns 顶层字段名,找不到时返回 undefined
|
|
23
|
+
*/
|
|
24
|
+
function baseFieldNameOf(subPath: string): string | undefined {
|
|
25
|
+
if (!subPath) return undefined;
|
|
26
|
+
const m = subPath.match(/^([^.[]+)/);
|
|
27
|
+
return m?.[1];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 在集合中根据字段名查找字段定义,兼容 getField/getFields 两种方式。
|
|
32
|
+
*
|
|
33
|
+
* @param collection 集合对象
|
|
34
|
+
* @param name 字段名
|
|
35
|
+
* @returns 匹配的字段定义,找不到时返回 undefined
|
|
36
|
+
*/
|
|
37
|
+
function findFieldByName(collection: Collection | null | undefined, name?: string): CollectionField | undefined {
|
|
38
|
+
if (!collection || !name) return undefined;
|
|
39
|
+
const direct = collection.getField(name);
|
|
40
|
+
if (direct) return direct;
|
|
41
|
+
const fields = collection.getFields?.() || [];
|
|
42
|
+
return fields.find((f) => f.name === name);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 从值中提取主键:
|
|
47
|
+
* - 支持主键原始值(string/number)
|
|
48
|
+
* - 支持对象(按主键名取值)
|
|
49
|
+
*
|
|
50
|
+
* @param value 字段当前值
|
|
51
|
+
* @param primaryKey 主键字段名
|
|
52
|
+
* @returns 解析出的主键值,无法解析时返回 undefined
|
|
53
|
+
*/
|
|
54
|
+
function toFilterByTk(value: unknown, primaryKey: string | string[]) {
|
|
55
|
+
if (value == null) return undefined;
|
|
56
|
+
if (Array.isArray(primaryKey)) {
|
|
57
|
+
if (typeof value !== 'object' || !value) return undefined;
|
|
58
|
+
const out: Record<string, any> = {};
|
|
59
|
+
for (const k of primaryKey) {
|
|
60
|
+
const v = (value as any)[k];
|
|
61
|
+
if (typeof v === 'undefined' || v === null) return undefined;
|
|
62
|
+
out[k] = v;
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
if (typeof value === 'string' || typeof value === 'number') return value;
|
|
67
|
+
if (typeof value === 'object') {
|
|
68
|
+
return (value as any)[primaryKey];
|
|
69
|
+
}
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 创建一个用于“对象类变量”(如 formValues / currentObject)的 `resolveOnServer` 判定函数。
|
|
75
|
+
* 仅当访问路径以“关联字段名”开头(且继续访问其子属性)时,返回 true 交由服务端解析;
|
|
76
|
+
* 否则在前端解析即可。
|
|
77
|
+
*
|
|
78
|
+
* @param collectionAccessor 返回当前对象所在 collection
|
|
79
|
+
* @param valueAccessor 可选,本地值访问器。若本地已存在目标子路径的值,则认为无需走后端,优先使用本地值。
|
|
80
|
+
* @returns `(subPath) => boolean` 判断是否需要服务端解析
|
|
81
|
+
*/
|
|
82
|
+
export function createAssociationSubpathResolver(
|
|
83
|
+
collectionAccessor: () => Collection | null,
|
|
84
|
+
valueAccessor?: () => unknown,
|
|
85
|
+
): (subPath: string) => boolean {
|
|
86
|
+
return (p: string) => {
|
|
87
|
+
// 仅在访问子属性时才考虑后端
|
|
88
|
+
if (!p || !p.includes('.')) return false;
|
|
89
|
+
const base = baseFieldNameOf(p);
|
|
90
|
+
if (!base) return false;
|
|
91
|
+
const collection = collectionAccessor();
|
|
92
|
+
const field = findFieldByName(collection, base);
|
|
93
|
+
const isAssoc = !!field?.isAssociationField();
|
|
94
|
+
if (!isAssoc) return false;
|
|
95
|
+
|
|
96
|
+
// 可选:本地优先。当提供 valueAccessor 时,若本地已有该子路径值,则不走后端
|
|
97
|
+
if (typeof valueAccessor === 'function') {
|
|
98
|
+
const local = valueAccessor();
|
|
99
|
+
if (local && typeof local === 'object') {
|
|
100
|
+
const v = _.get(local as Record<string, unknown>, p);
|
|
101
|
+
if (typeof v !== 'undefined') return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return true;
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 构建“对象类变量”的 PropertyMetaFactory:
|
|
111
|
+
* - 暴露集合字段结构(通过 createCollectionContextMeta)用于变量选择器;
|
|
112
|
+
* - 提供 buildVariablesParams:基于对象当前值,收集所有“已选择的关联字段”
|
|
113
|
+
* 以便服务端在 variables:resolve 时按需补全关联数据。
|
|
114
|
+
*
|
|
115
|
+
* @param collectionAccessor 获取集合对象,用于字段/元信息来源
|
|
116
|
+
* @param title 变量组标题(用于 UI 展示)
|
|
117
|
+
* @param valueAccessor 获取当前对象值(如 ctx.form.getFieldsValue() / ctx.currentObject)
|
|
118
|
+
* @returns PropertyMetaFactory
|
|
119
|
+
*/
|
|
120
|
+
export function createAssociationAwareObjectMetaFactory(
|
|
121
|
+
collectionAccessor: () => Collection | null,
|
|
122
|
+
title: string,
|
|
123
|
+
valueAccessor: (ctx: FlowContext) => any,
|
|
124
|
+
): PropertyMetaFactory {
|
|
125
|
+
const baseFactory = createCollectionContextMeta(collectionAccessor, title);
|
|
126
|
+
const factory: PropertyMetaFactory = async () => {
|
|
127
|
+
const base = (await baseFactory()) as PropertyMeta | null;
|
|
128
|
+
if (!base) return null;
|
|
129
|
+
|
|
130
|
+
const meta: PropertyMeta = {
|
|
131
|
+
...base,
|
|
132
|
+
buildVariablesParams: (ctx: FlowContext) => {
|
|
133
|
+
const collection = collectionAccessor();
|
|
134
|
+
const obj = valueAccessor(ctx);
|
|
135
|
+
if (!collection || !obj || typeof obj !== 'object') return {};
|
|
136
|
+
const params: Record<string, any> = {};
|
|
137
|
+
|
|
138
|
+
const fields: CollectionField[] = collection.getFields?.() || [];
|
|
139
|
+
for (const field of fields) {
|
|
140
|
+
const name = field.name as string | undefined;
|
|
141
|
+
if (!name) continue;
|
|
142
|
+
if (!field.isAssociationField()) continue;
|
|
143
|
+
const target = field.target as string | undefined;
|
|
144
|
+
const targetCollection = field.targetCollection;
|
|
145
|
+
if (!target || !targetCollection) continue;
|
|
146
|
+
const primaryKey = targetCollection.filterTargetKey as string | string[];
|
|
147
|
+
|
|
148
|
+
const associationValue = (obj as any)[name];
|
|
149
|
+
if (associationValue == null) continue;
|
|
150
|
+
|
|
151
|
+
if (Array.isArray(associationValue)) {
|
|
152
|
+
const ids = associationValue.map((item) => toFilterByTk(item, primaryKey)).filter((v) => v != null);
|
|
153
|
+
if (ids.length) {
|
|
154
|
+
params[name] = {
|
|
155
|
+
collection: target,
|
|
156
|
+
dataSourceKey: targetCollection.dataSourceKey,
|
|
157
|
+
filterByTk: ids,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
} else {
|
|
161
|
+
const id = toFilterByTk(associationValue, primaryKey);
|
|
162
|
+
if (id != null) {
|
|
163
|
+
params[name] = {
|
|
164
|
+
collection: target,
|
|
165
|
+
dataSourceKey: targetCollection.dataSourceKey,
|
|
166
|
+
filterByTk: id,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return params;
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
return meta;
|
|
177
|
+
};
|
|
178
|
+
factory.title = title;
|
|
179
|
+
return factory;
|
|
180
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
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 type { FlowModel } from '../models';
|
|
11
|
+
import { inferRecordRef } from './variablesParams';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 统一构造设置弹窗 openView 的 inputArgs:
|
|
15
|
+
* - collectionName/dataSourceKey/filterByTk:优先从 model.context 推断;否则回退父视图 inputArgs
|
|
16
|
+
* - sourceId:优先从 resource.getSourceId();否则回退父视图 inputArgs
|
|
17
|
+
* - associationName:来自 association.resourceName 或 resource.getResourceName()
|
|
18
|
+
* - navigation:父视图 navigation 或传入的 navigationOverride
|
|
19
|
+
*/
|
|
20
|
+
export function buildSettingsViewInputArgs(
|
|
21
|
+
model: FlowModel,
|
|
22
|
+
extra?: Record<string, any>,
|
|
23
|
+
options?: { navigationOverride?: any },
|
|
24
|
+
): Record<string, any> {
|
|
25
|
+
const defaults: Record<string, any> = {};
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
// 1) 当前记录/集合
|
|
29
|
+
const ref = inferRecordRef((model as any).context);
|
|
30
|
+
if (ref?.collection) {
|
|
31
|
+
defaults.collectionName = ref.collection;
|
|
32
|
+
defaults.dataSourceKey = ref.dataSourceKey || 'main';
|
|
33
|
+
defaults.filterByTk = ref.filterByTk;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// 2) 回退父视图 inputArgs(如在抽屉/页面中)
|
|
37
|
+
const parentArgs = (model as any)?.context?.view?.inputArgs || {};
|
|
38
|
+
if (!defaults.collectionName && parentArgs?.collectionName) {
|
|
39
|
+
defaults.collectionName = parentArgs.collectionName;
|
|
40
|
+
defaults.dataSourceKey = parentArgs.dataSourceKey || defaults.dataSourceKey || 'main';
|
|
41
|
+
}
|
|
42
|
+
if (defaults.filterByTk == null && parentArgs?.filterByTk != null) {
|
|
43
|
+
defaults.filterByTk = parentArgs.filterByTk;
|
|
44
|
+
}
|
|
45
|
+
if (defaults.sourceId == null && parentArgs?.sourceId != null) {
|
|
46
|
+
defaults.sourceId = parentArgs.sourceId;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// 3) 导航(用于推断“上级弹窗”)
|
|
50
|
+
const nav = options?.navigationOverride ?? (model as any)?.context?.view?.navigation;
|
|
51
|
+
if (nav) {
|
|
52
|
+
defaults.navigation = nav;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 4) 直接从资源读取 sourceId(优先级高于父视图)
|
|
56
|
+
const sid = (model as any)?.context?.resource?.getSourceId?.();
|
|
57
|
+
if (sid !== undefined && sid !== null && String(sid) !== '') {
|
|
58
|
+
defaults.sourceId = sid;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// 5) 关联名(用于“上级记录”)
|
|
62
|
+
const assocName =
|
|
63
|
+
(model as any)?.context?.association?.resourceName || (model as any)?.context?.resource?.getResourceName?.();
|
|
64
|
+
if (typeof assocName === 'string' && assocName) {
|
|
65
|
+
defaults.associationName = assocName;
|
|
66
|
+
}
|
|
67
|
+
} catch (_) {
|
|
68
|
+
// 忽略推断异常
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return { ...defaults, ...(extra || {}) };
|
|
72
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
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 { FlowContext } from '../flowContext';
|
|
11
|
+
import type { ActionDefinition } from '../types';
|
|
12
|
+
import type { PropertyOptions } from '../flowContext';
|
|
13
|
+
|
|
14
|
+
// 临时上下文:
|
|
15
|
+
// - 读:优先从 scoped(临时定义)读取,兜底 parent;
|
|
16
|
+
// - 写:统一写入 parent(不污染 scoped);
|
|
17
|
+
// - 注入:create 阶段 define* 写入 scoped;运行阶段 define* 写入 parent。
|
|
18
|
+
type ContextDefsLike<TCtx extends FlowContext> =
|
|
19
|
+
| Partial<Pick<ActionDefinition<any, TCtx>, 'defineProperties' | 'defineMethods'>>
|
|
20
|
+
| null
|
|
21
|
+
| undefined;
|
|
22
|
+
|
|
23
|
+
export async function createEphemeralContext<TCtx extends FlowContext>(
|
|
24
|
+
parent: TCtx,
|
|
25
|
+
contextDefs?: ContextDefsLike<TCtx>,
|
|
26
|
+
): Promise<TCtx> {
|
|
27
|
+
// 若未提供任何上下文定义,直接复用父级上下文,避免不必要的代理包装
|
|
28
|
+
if (contextDefs == null || (!contextDefs.defineProperties && !contextDefs.defineMethods)) {
|
|
29
|
+
return parent;
|
|
30
|
+
}
|
|
31
|
+
// 1) 创建一个新的 FlowContext,专门承载“临时定义”(defineProperty/defineMethod)
|
|
32
|
+
const scoped = new FlowContext();
|
|
33
|
+
// 2) 读取优先:先从 scoped 自身取(_props/_methods),否则委托到 parent(仅 _props/_methods)
|
|
34
|
+
scoped.addDelegate(parent);
|
|
35
|
+
|
|
36
|
+
// 3) 先创建 scoped 的代理,用于注入阶段(define* 直达 scoped;读写行为与最终代理一致)
|
|
37
|
+
const scopedProxy = scoped.createProxy();
|
|
38
|
+
const scopedObj = scopedProxy as unknown as object;
|
|
39
|
+
const parentObj = parent as unknown as object;
|
|
40
|
+
const getFromParent = (key: PropertyKey) => {
|
|
41
|
+
const val = Reflect.get(parentObj, key, parentObj);
|
|
42
|
+
return typeof val === 'function' ? (val as Function).bind(parent) : val;
|
|
43
|
+
};
|
|
44
|
+
const hasInScopedOrParent = (key: PropertyKey) =>
|
|
45
|
+
key === 'defineProperty' || key === 'defineMethod' || Reflect.has(scopedObj, key) || Reflect.has(parentObj, key);
|
|
46
|
+
const injectionProxy = new Proxy(scopedProxy as TCtx, {
|
|
47
|
+
get(_t, key: PropertyKey, receiver) {
|
|
48
|
+
if (typeof key === 'string') {
|
|
49
|
+
// 注入阶段:允许在 defLike 的函数体中调用 ctx.defineProperty/defineMethod 写入 scoped
|
|
50
|
+
if (key === 'defineProperty') {
|
|
51
|
+
return (propKey: string, options: any) => (scoped as FlowContext).defineProperty(propKey, options);
|
|
52
|
+
}
|
|
53
|
+
if (key === 'defineMethod') {
|
|
54
|
+
return (name: string, fn: any, des?: string) => (scoped as FlowContext).defineMethod(name, fn, des);
|
|
55
|
+
}
|
|
56
|
+
if (Reflect.has(scopedObj, key)) {
|
|
57
|
+
return Reflect.get(scopedObj, key, receiver);
|
|
58
|
+
}
|
|
59
|
+
return getFromParent(key);
|
|
60
|
+
}
|
|
61
|
+
return Reflect.get(scopedObj, key, receiver);
|
|
62
|
+
},
|
|
63
|
+
set(_t, key: PropertyKey, value: unknown) {
|
|
64
|
+
return Reflect.set(parentObj, key, value);
|
|
65
|
+
},
|
|
66
|
+
has(_t, key: PropertyKey) {
|
|
67
|
+
return hasInScopedOrParent(key);
|
|
68
|
+
},
|
|
69
|
+
getOwnPropertyDescriptor(_t, key: PropertyKey) {
|
|
70
|
+
return Object.getOwnPropertyDescriptor(scopedObj, key) || Object.getOwnPropertyDescriptor(parentObj, key);
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// 如果提供了 contextDefs,则在创建时即注入定义,便于外部更简洁地使用
|
|
75
|
+
if (contextDefs) {
|
|
76
|
+
const defs = Array.isArray(contextDefs) ? contextDefs : [contextDefs];
|
|
77
|
+
for (const defLike of defs) {
|
|
78
|
+
if (!defLike) continue;
|
|
79
|
+
// 1) defineProperties -> 写入到 scoped(避免污染父级)
|
|
80
|
+
const dp = (defLike as any).defineProperties;
|
|
81
|
+
if (dp) {
|
|
82
|
+
const raw = typeof dp === 'function' ? await dp(injectionProxy as TCtx) : dp;
|
|
83
|
+
if (!raw || typeof raw !== 'object') {
|
|
84
|
+
throw new TypeError('defineProperties must return an object of PropertyOptions');
|
|
85
|
+
}
|
|
86
|
+
const propsDef = raw as Record<string, PropertyOptions>;
|
|
87
|
+
for (const [key, options] of Object.entries(propsDef)) {
|
|
88
|
+
if (!options || typeof options !== 'object') {
|
|
89
|
+
throw new TypeError(`defineProperties['${key}'] must be a PropertyOptions object`);
|
|
90
|
+
}
|
|
91
|
+
// 直接在 scoped 上定义,确保仅限本次临时作用域
|
|
92
|
+
(scoped as FlowContext).defineProperty(key, options);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// 2) defineMethods -> 写入到 scoped(避免污染父级)
|
|
96
|
+
const dm = (defLike as any).defineMethods;
|
|
97
|
+
if (dm) {
|
|
98
|
+
const raw = typeof dm === 'function' ? await dm(injectionProxy as TCtx) : dm;
|
|
99
|
+
if (!raw || typeof raw !== 'object') {
|
|
100
|
+
throw new TypeError('defineMethods must return an object of functions');
|
|
101
|
+
}
|
|
102
|
+
const methodsDef = raw as Record<string, (this: TCtx, ...args: any[]) => any>;
|
|
103
|
+
for (const [key, fn] of Object.entries(methodsDef)) {
|
|
104
|
+
if (typeof fn !== 'function') {
|
|
105
|
+
throw new TypeError(`defineMethods['${key}'] must be a function`);
|
|
106
|
+
}
|
|
107
|
+
(scoped as FlowContext).defineMethod(key, fn as any);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// 4) 创建最终对外代理:读取优先 scoped,兜底父级,且后续 define* 写入父级
|
|
114
|
+
const outerProxy = new Proxy(scopedProxy as TCtx, {
|
|
115
|
+
get(_t, key: PropertyKey, receiver) {
|
|
116
|
+
if (typeof key === 'string') {
|
|
117
|
+
if (key === 'defineProperty') {
|
|
118
|
+
return (propKey: string, options: any) => (parent as FlowContext).defineProperty(propKey, options);
|
|
119
|
+
}
|
|
120
|
+
if (key === 'defineMethod') {
|
|
121
|
+
return (name: string, fn: any, des?: string) => (parent as FlowContext).defineMethod(name, fn, des);
|
|
122
|
+
}
|
|
123
|
+
if (Reflect.has(scopedObj, key)) {
|
|
124
|
+
return Reflect.get(scopedObj, key, receiver);
|
|
125
|
+
}
|
|
126
|
+
return getFromParent(key);
|
|
127
|
+
}
|
|
128
|
+
return Reflect.get(scopedObj, key, receiver);
|
|
129
|
+
},
|
|
130
|
+
set(_t, key: PropertyKey, value: unknown) {
|
|
131
|
+
return Reflect.set(parentObj, key, value);
|
|
132
|
+
},
|
|
133
|
+
has(_t, key: PropertyKey) {
|
|
134
|
+
return hasInScopedOrParent(key);
|
|
135
|
+
},
|
|
136
|
+
getOwnPropertyDescriptor(_t, key: PropertyKey) {
|
|
137
|
+
return Object.getOwnPropertyDescriptor(scopedObj, key) || Object.getOwnPropertyDescriptor(parentObj, key);
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
return outerProxy as TCtx;
|
|
142
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
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 { FlowDefinition } from '../FlowDefinition';
|
|
11
|
+
|
|
12
|
+
export const isBeforeRenderFlow = (flow: FlowDefinition): boolean => {
|
|
13
|
+
if (typeof flow.on === 'string') {
|
|
14
|
+
return flow.on === 'beforeRender';
|
|
15
|
+
}
|
|
16
|
+
if (typeof flow.on === 'object') {
|
|
17
|
+
return flow.on.eventName === 'beforeRender';
|
|
18
|
+
}
|
|
19
|
+
if (!flow.on && flow.manual !== true) {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
};
|
package/src/utils/index.ts
CHANGED
|
@@ -41,14 +41,15 @@ export { setupRuntimeContextSteps } from './setupRuntimeContextSteps';
|
|
|
41
41
|
|
|
42
42
|
// Record Proxy 工具
|
|
43
43
|
export { createCollectionContextMeta } from './createCollectionContextMeta';
|
|
44
|
+
export { createAssociationAwareObjectMetaFactory, createAssociationSubpathResolver } from './associationObjectVariable';
|
|
44
45
|
export {
|
|
45
46
|
buildRecordMeta,
|
|
46
47
|
collectContextParamsForTemplate,
|
|
47
48
|
createCurrentRecordMetaFactory,
|
|
49
|
+
createRecordResolveOnServerWithLocal,
|
|
48
50
|
createRecordMetaFactory,
|
|
49
51
|
extractUsedVariableNames,
|
|
50
52
|
extractUsedVariablePaths,
|
|
51
|
-
inferParentRecordRef,
|
|
52
53
|
inferRecordRef,
|
|
53
54
|
type RecordParamsBuilder,
|
|
54
55
|
} from './variablesParams';
|
|
@@ -58,6 +59,14 @@ export { extractPropertyPath, formatPathToVariable, isVariableExpression } from
|
|
|
58
59
|
|
|
59
60
|
export { clearAutoFlowError, getAutoFlowError, setAutoFlowError, type AutoFlowError } from './autoFlowError';
|
|
60
61
|
export { parsePathnameToViewParams, type ViewParam } from './parsePathnameToViewParams';
|
|
62
|
+
export { buildSettingsViewInputArgs } from './buildSettingsViewInputArgs';
|
|
61
63
|
|
|
62
64
|
// 安全全局对象(window/document)
|
|
63
|
-
export { createSafeDocument, createSafeWindow } from './safeGlobals';
|
|
65
|
+
export { createSafeDocument, createSafeWindow, createSafeNavigator } from './safeGlobals';
|
|
66
|
+
|
|
67
|
+
// Ephemeral context helper(用于临时注入属性/方法,避免污染父级 ctx)
|
|
68
|
+
export { createEphemeralContext } from './createEphemeralContext';
|
|
69
|
+
|
|
70
|
+
// Filter helpers
|
|
71
|
+
export { pruneFilter } from './pruneFilter';
|
|
72
|
+
export { isBeforeRenderFlow } from './flows';
|
|
@@ -0,0 +1,39 @@
|
|
|
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
|
+
/**
|
|
11
|
+
* Lightweight JSX -> JS compiler for RunJS user code.
|
|
12
|
+
* - Uses sucrase via dynamic import (lazy; avoids static cycles and cost when not needed)
|
|
13
|
+
* - Maps JSX to ctx.React.createElement / ctx.React.Fragment so no global React is required
|
|
14
|
+
* - If sucrase is unavailable or transform throws, returns original code as graceful fallback
|
|
15
|
+
*/
|
|
16
|
+
export async function compileRunJs(code: string): Promise<string> {
|
|
17
|
+
// Fast path: cheap heuristic to skip import if no JSX likely present
|
|
18
|
+
// (not strict; still safe because we fall back to transform if dynamic import is cheap)
|
|
19
|
+
const maybeJSX = /<[A-Za-z]|<\//.test(code);
|
|
20
|
+
if (!maybeJSX) return code;
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const mod: any = await import('sucrase');
|
|
24
|
+
const transform = mod?.transform || mod?.default?.transform;
|
|
25
|
+
if (typeof transform !== 'function') return code;
|
|
26
|
+
const res = transform(code, {
|
|
27
|
+
transforms: ['jsx'],
|
|
28
|
+
jsxPragma: 'ctx.React.createElement',
|
|
29
|
+
jsxFragmentPragma: 'ctx.React.Fragment',
|
|
30
|
+
// Keep ES syntax as-is; JSRunner runs in modern engines
|
|
31
|
+
disableESTransforms: true,
|
|
32
|
+
production: true,
|
|
33
|
+
});
|
|
34
|
+
return (res && (res.code || res?.output)) ?? code;
|
|
35
|
+
} catch (_e) {
|
|
36
|
+
// Fallback: return original code if transform fails
|
|
37
|
+
return code;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import { getValuesByPath } from '@nocobase/shared';
|
|
10
11
|
import _ from 'lodash';
|
|
11
12
|
import { FlowContext, FlowModelContext, FlowRuntimeContext } from '../flowContext';
|
|
12
|
-
import { getValuesByPath } from '@nocobase/utils/client';
|
|
13
13
|
import type { FlowModel } from '../models';
|
|
14
14
|
import type { ServerContextParams } from './serverContextParams';
|
|
15
15
|
|
|
@@ -440,7 +440,7 @@ async function compileExpression<TModel extends FlowModel = FlowModel>(expressio
|
|
|
440
440
|
* ✅ "{{ctx.user}}" -> 捕获: "ctx.user"
|
|
441
441
|
* ❌ "Hello {{ ctx.user }}" -> 不匹配(不是纯表达式)
|
|
442
442
|
*/
|
|
443
|
-
const singleMatch = expression.match(/^\{\{\s*(
|
|
443
|
+
const singleMatch = expression.match(/^\s*\{\{\s*([^{}]+?)\s*\}\}\s*$/);
|
|
444
444
|
if (singleMatch) {
|
|
445
445
|
const inner = singleMatch[1];
|
|
446
446
|
const dotPath = matchDotOnly(inner);
|
|
@@ -13,7 +13,7 @@ export interface ViewParam {
|
|
|
13
13
|
/** 标签页唯一标识符 */
|
|
14
14
|
tabUid?: string;
|
|
15
15
|
/** 弹窗记录的 id */
|
|
16
|
-
filterByTk?: string
|
|
16
|
+
filterByTk?: string | Record<string, string | number>;
|
|
17
17
|
/** source Id */
|
|
18
18
|
sourceId?: string;
|
|
19
19
|
}
|
|
@@ -70,17 +70,61 @@ export const parsePathnameToViewParams = (pathname: string): ViewParam[] => {
|
|
|
70
70
|
}
|
|
71
71
|
// 处理参数
|
|
72
72
|
else if (currentView && i + 1 < segments.length) {
|
|
73
|
-
const
|
|
73
|
+
const rawValue = segments[i + 1];
|
|
74
|
+
// 尝试对路径段进行解码
|
|
75
|
+
let decoded: string = rawValue;
|
|
76
|
+
try {
|
|
77
|
+
decoded = decodeURIComponent(rawValue);
|
|
78
|
+
} catch (_) {
|
|
79
|
+
// ignore
|
|
80
|
+
}
|
|
74
81
|
|
|
75
82
|
switch (segment) {
|
|
76
83
|
case 'tab':
|
|
77
|
-
|
|
84
|
+
// tab/sourceId 仅作为字符串处理
|
|
85
|
+
currentView.tabUid = decoded;
|
|
78
86
|
break;
|
|
79
|
-
case 'filterbytk':
|
|
80
|
-
|
|
87
|
+
case 'filterbytk': {
|
|
88
|
+
// 仅在 filterByTk 分支支持对象/JSON/键值对解析
|
|
89
|
+
const parseKeyValuePairs = (s: string): Record<string, string | number> => {
|
|
90
|
+
const obj: Record<string, string | number> = {};
|
|
91
|
+
s.split('&').forEach((pair) => {
|
|
92
|
+
const [k, v = ''] = pair.split('=');
|
|
93
|
+
if (!k) return;
|
|
94
|
+
try {
|
|
95
|
+
const key = decodeURIComponent(k);
|
|
96
|
+
const val = decodeURIComponent(v);
|
|
97
|
+
obj[key] = val;
|
|
98
|
+
} catch (_) {
|
|
99
|
+
obj[k] = v;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
return obj;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
let parsed: string | Record<string, string | number> = decoded;
|
|
106
|
+
if (decoded && (decoded.startsWith('{') || decoded.startsWith('['))) {
|
|
107
|
+
try {
|
|
108
|
+
const maybe = JSON.parse(decoded);
|
|
109
|
+
if (maybe && typeof maybe === 'object' && !Array.isArray(maybe)) {
|
|
110
|
+
parsed = maybe as Record<string, string | number>;
|
|
111
|
+
} else {
|
|
112
|
+
// 非对象 JSON(如数组/数字)按字符串保留
|
|
113
|
+
parsed = decoded;
|
|
114
|
+
}
|
|
115
|
+
} catch (_) {
|
|
116
|
+
// 解析失败,按字符串保留
|
|
117
|
+
parsed = decoded;
|
|
118
|
+
}
|
|
119
|
+
} else if (decoded && decoded.includes('=') && decoded.includes('&')) {
|
|
120
|
+
// 形如 a=b&c=d 的整体段
|
|
121
|
+
parsed = parseKeyValuePairs(decoded);
|
|
122
|
+
}
|
|
123
|
+
currentView.filterByTk = parsed;
|
|
81
124
|
break;
|
|
125
|
+
}
|
|
82
126
|
case 'sourceid':
|
|
83
|
-
currentView.sourceId =
|
|
127
|
+
currentView.sourceId = decoded;
|
|
84
128
|
break;
|
|
85
129
|
default:
|
|
86
130
|
// 未知参数,跳过
|