@nocobase/flow-engine 2.2.0-alpha.1 → 2.2.0-alpha.11
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/JSRunner.d.ts +1 -0
- package/lib/JSRunner.js +110 -20
- package/lib/acl/Acl.d.ts +2 -1
- package/lib/acl/Acl.js +28 -0
- package/lib/components/FieldModelRenderer.js +44 -31
- package/lib/components/FlowContextSelector.js +55 -12
- package/lib/components/FormItem.js +11 -7
- package/lib/components/MobilePopup.js +39 -10
- package/lib/components/MobilePopup.style.js +27 -6
- package/lib/components/dnd/index.js +9 -2
- package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.js +86 -32
- package/lib/components/settings/wrappers/contextual/useFloatToolbarVisibility.js +20 -0
- package/lib/components/subModel/LazyDropdown.js +41 -26
- package/lib/components/variables/VariableHybridInput.d.ts +9 -0
- package/lib/components/variables/VariableHybridInput.js +146 -17
- package/lib/components/variables/VariableInput.js +19 -7
- package/lib/components/variables/VariableTag.js +48 -36
- package/lib/components/variables/types.d.ts +21 -0
- package/lib/flowContext.d.ts +1 -1
- package/lib/flowContext.js +97 -42
- package/lib/flowEngine.js +6 -0
- package/lib/flowI18n.js +3 -3
- package/lib/flowSettings.d.ts +5 -1
- package/lib/flowSettings.js +70 -0
- package/lib/locale/en-US.json +3 -0
- package/lib/locale/index.d.ts +6 -0
- package/lib/locale/zh-CN.json +3 -0
- package/lib/resources/apiResource.js +2 -1
- package/lib/resources/baseRecordResource.js +6 -17
- package/lib/resources/multiRecordResource.js +13 -3
- package/lib/resources/singleRecordResource.js +7 -2
- package/lib/runjs-context/helpers.js +12 -5
- package/lib/types.d.ts +15 -1
- package/lib/types.js +1 -0
- package/lib/utils/dataSourceDirty.d.ts +20 -0
- package/lib/utils/dataSourceDirty.js +139 -0
- package/lib/utils/dirtyAwareApiClient.d.ts +11 -0
- package/lib/utils/dirtyAwareApiClient.js +632 -0
- package/lib/utils/index.d.ts +1 -1
- package/lib/utils/index.js +11 -11
- package/lib/utils/loadedPageCache.d.ts +1 -0
- package/lib/utils/loadedPageCache.js +6 -0
- package/lib/utils/openViewRouteState.d.ts +28 -0
- package/lib/utils/openViewRouteState.js +125 -0
- package/lib/utils/parsePathnameToViewParams.d.ts +3 -0
- package/lib/utils/parsePathnameToViewParams.js +18 -1
- package/lib/utils/resolveRunJSObjectValues.js +3 -2
- package/lib/utils/runjsModuleLoader.js +0 -30
- package/lib/views/ViewNavigation.js +5 -0
- package/package.json +4 -4
- package/src/JSRunner.ts +112 -25
- package/src/__tests__/JSRunner.test.ts +4 -5
- package/src/__tests__/flowContext.test.ts +154 -0
- package/src/__tests__/flowEngine.dataSourceDirty.test.ts +51 -0
- package/src/__tests__/flowI18n.test.ts +11 -0
- package/src/__tests__/flowModel.openView.navigation.test.ts +28 -0
- package/src/__tests__/flowSettings.test.ts +72 -0
- package/src/__tests__/runjsRuntimeFeatures.test.ts +15 -2
- package/src/__tests__/viewScopedFlowEngine.test.ts +72 -6
- package/src/acl/Acl.tsx +36 -1
- package/src/acl/__tests__/Acl.test.tsx +70 -0
- package/src/components/FieldModelRenderer.tsx +50 -36
- package/src/components/FlowContextSelector.tsx +66 -11
- package/src/components/FormItem.tsx +12 -7
- package/src/components/MobilePopup.style.ts +34 -7
- package/src/components/MobilePopup.tsx +42 -10
- package/src/components/__tests__/FieldModelRenderer.test.tsx +165 -0
- package/src/components/__tests__/FormItem.test.tsx +17 -2
- package/src/components/__tests__/MobilePopup.style.test.tsx +103 -0
- package/src/components/__tests__/MobilePopup.test.tsx +150 -0
- package/src/components/dnd/index.tsx +11 -2
- package/src/components/settings/wrappers/contextual/FlowsFloatContextMenu.tsx +105 -35
- package/src/components/settings/wrappers/contextual/__tests__/FlowsFloatContextMenu.test.tsx +381 -12
- package/src/components/settings/wrappers/contextual/useFloatToolbarVisibility.ts +28 -0
- package/src/components/subModel/LazyDropdown.tsx +44 -26
- package/src/components/subModel/__tests__/AddSubModelButton.test.tsx +85 -2
- package/src/components/variables/VariableHybridInput.tsx +185 -14
- package/src/components/variables/VariableInput.tsx +32 -7
- package/src/components/variables/VariableTag.tsx +51 -37
- package/src/components/variables/__tests__/FlowContextSelector.test.tsx +60 -3
- package/src/components/variables/__tests__/VariableHybridInput.test.tsx +212 -0
- package/src/components/variables/__tests__/VariableInput.test.tsx +202 -6
- package/src/components/variables/__tests__/VariableTag.test.tsx +80 -0
- package/src/components/variables/types.ts +21 -0
- package/src/flowContext.ts +104 -36
- package/src/flowEngine.ts +6 -0
- package/src/flowI18n.ts +8 -3
- package/src/flowSettings.ts +85 -1
- package/src/locale/__tests__/index.test.ts +21 -0
- package/src/locale/en-US.json +3 -0
- package/src/locale/zh-CN.json +3 -0
- package/src/resources/apiResource.ts +2 -1
- package/src/resources/baseRecordResource.ts +6 -23
- package/src/resources/multiRecordResource.ts +13 -3
- package/src/resources/singleRecordResource.ts +6 -1
- package/src/runjs-context/helpers.ts +12 -6
- package/src/types.ts +16 -0
- package/src/utils/__tests__/dirtyAwareApiClient.test.ts +713 -0
- package/src/utils/__tests__/openViewRouteState.test.ts +40 -0
- package/src/utils/__tests__/parsePathnameToViewParams.test.ts +36 -0
- package/src/utils/dataSourceDirty.ts +126 -0
- package/src/utils/dirtyAwareApiClient.ts +742 -0
- package/src/utils/index.ts +10 -9
- package/src/utils/loadedPageCache.ts +7 -0
- package/src/utils/openViewRouteState.ts +107 -0
- package/src/utils/parsePathnameToViewParams.ts +23 -1
- package/src/utils/resolveRunJSObjectValues.ts +5 -2
- package/src/utils/runjsModuleLoader.ts +0 -32
- package/src/views/ViewNavigation.ts +6 -1
- package/src/views/__tests__/ViewNavigation.test.ts +15 -0
- package/lib/utils/safeGlobals.d.ts +0 -28
- package/lib/utils/safeGlobals.js +0 -367
- package/src/utils/__tests__/runjsRequireAsyncAutoWhitelist.test.ts +0 -38
- package/src/utils/__tests__/safeGlobals.test.ts +0 -106
- package/src/utils/safeGlobals.ts +0 -406
package/src/flowI18n.ts
CHANGED
|
@@ -64,7 +64,9 @@ export class FlowI18n {
|
|
|
64
64
|
* @private
|
|
65
65
|
*/
|
|
66
66
|
private isTemplate(str: string): boolean {
|
|
67
|
-
|
|
67
|
+
// The closing quote is a backreference to the opening one (group 1) so an embedded quote of a different type — e.g.
|
|
68
|
+
// {{t('… "Post-action event" …')}} — does not terminate the key early.
|
|
69
|
+
return /\{\{\s*t\s*\(\s*(["'`])(?:\\.|(?!\1).)*?\1\s*(?:,\s*.*?)?\s*\)\s*\}\}/.test(str);
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
/**
|
|
@@ -72,9 +74,12 @@ export class FlowI18n {
|
|
|
72
74
|
* @private
|
|
73
75
|
*/
|
|
74
76
|
private compileTemplate(template: string): string {
|
|
77
|
+
// `(["'`])` captures the opening quote; the key allows escaped chars (`\\.`) and any char that is not that same
|
|
78
|
+
// quote (`(?!\1).`), and `\1` closes on the matching quote. This keeps embedded quotes of a different type inside
|
|
79
|
+
// the key instead of truncating it at the first quote of any kind.
|
|
75
80
|
return template.replace(
|
|
76
|
-
/\{\{\s*t\s*\(\s*["'`](
|
|
77
|
-
(match, key, optionsStr) => {
|
|
81
|
+
/\{\{\s*t\s*\(\s*(["'`])((?:\\.|(?!\1).)*?)\1\s*(?:,\s*((?:[^{}]|\{[^}]*\})*?))?\s*\)\s*\}\}/g,
|
|
82
|
+
(match, _quote, key, optionsStr) => {
|
|
78
83
|
try {
|
|
79
84
|
let templateOptions = {};
|
|
80
85
|
if (optionsStr) {
|
package/src/flowSettings.ts
CHANGED
|
@@ -20,7 +20,13 @@ import { FlowRuntimeContext } from './flowContext';
|
|
|
20
20
|
import { FlowEngine, untracked } from '.';
|
|
21
21
|
import { FlowSettingsContextProvider, useFlowSettingsContext } from './hooks/useFlowSettingsContext';
|
|
22
22
|
import type { FlowModel } from './models';
|
|
23
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
DynamicFlowSource,
|
|
25
|
+
DynamicFlowSourceProvider,
|
|
26
|
+
ParamObject,
|
|
27
|
+
StepSettingsDialogProps,
|
|
28
|
+
ToolbarItemConfig,
|
|
29
|
+
} from './types';
|
|
24
30
|
import {
|
|
25
31
|
compileUiSchema,
|
|
26
32
|
FlowCancelSaveException,
|
|
@@ -128,6 +134,7 @@ export class FlowSettings {
|
|
|
128
134
|
private engine: FlowEngine;
|
|
129
135
|
#forceEnabled = false; // 强制启用状态,主要用于设计模式下的强制启用
|
|
130
136
|
public toolbarItems: ToolbarItemConfig[] = [];
|
|
137
|
+
private dynamicFlowSourceProviders: DynamicFlowSourceProvider[] = [];
|
|
131
138
|
#emitter: Emitter = new Emitter();
|
|
132
139
|
|
|
133
140
|
constructor(engine: FlowEngine) {
|
|
@@ -463,6 +470,83 @@ export class FlowSettings {
|
|
|
463
470
|
return [...this.toolbarItems];
|
|
464
471
|
}
|
|
465
472
|
|
|
473
|
+
public registerDynamicFlowSourceProvider(provider: DynamicFlowSourceProvider): () => void {
|
|
474
|
+
const existingIndex = this.dynamicFlowSourceProviders.findIndex((item) => item.key === provider.key);
|
|
475
|
+
if (existingIndex !== -1) {
|
|
476
|
+
console.warn(
|
|
477
|
+
`FlowSettings: Dynamic flow source provider with key '${provider.key}' already exists and will be replaced.`,
|
|
478
|
+
);
|
|
479
|
+
this.dynamicFlowSourceProviders[existingIndex] = provider;
|
|
480
|
+
} else {
|
|
481
|
+
this.dynamicFlowSourceProviders.push(provider);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
this.dynamicFlowSourceProviders.sort((a, b) => (a.sort || 0) - (b.sort || 0));
|
|
485
|
+
|
|
486
|
+
return () => {
|
|
487
|
+
const index = this.dynamicFlowSourceProviders.indexOf(provider);
|
|
488
|
+
if (index !== -1) {
|
|
489
|
+
this.dynamicFlowSourceProviders.splice(index, 1);
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
public hasDynamicFlowSourceProvider(model: FlowModel): boolean {
|
|
495
|
+
return this.dynamicFlowSourceProviders.some((provider) => {
|
|
496
|
+
try {
|
|
497
|
+
return provider.visible ? provider.visible(model) : true;
|
|
498
|
+
} catch (error) {
|
|
499
|
+
console.warn(`FlowSettings: Dynamic flow source provider '${provider.key}' visibility check failed.`, error);
|
|
500
|
+
return false;
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
public async getDynamicFlowSources(model: FlowModel): Promise<DynamicFlowSource[]> {
|
|
506
|
+
const t = getT(model);
|
|
507
|
+
const selfSource: DynamicFlowSource = {
|
|
508
|
+
key: 'self',
|
|
509
|
+
label: t('Current block'),
|
|
510
|
+
model,
|
|
511
|
+
sort: -1000,
|
|
512
|
+
};
|
|
513
|
+
const sources: DynamicFlowSource[] = [];
|
|
514
|
+
const seenKeys = new Set<string>(['self']);
|
|
515
|
+
const seenModelUids = new Set<string>([model.uid]);
|
|
516
|
+
|
|
517
|
+
for (const provider of this.dynamicFlowSourceProviders) {
|
|
518
|
+
try {
|
|
519
|
+
if (provider.visible && !provider.visible(model)) {
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
const providerSources = await provider.getSources(model);
|
|
524
|
+
for (const source of providerSources || []) {
|
|
525
|
+
if (!source?.key || !source.model) {
|
|
526
|
+
continue;
|
|
527
|
+
}
|
|
528
|
+
const key = String(source.key);
|
|
529
|
+
const uid = source.model.uid;
|
|
530
|
+
if (seenKeys.has(key) || seenModelUids.has(uid)) {
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
533
|
+
seenKeys.add(key);
|
|
534
|
+
seenModelUids.add(uid);
|
|
535
|
+
sources.push({
|
|
536
|
+
...source,
|
|
537
|
+
key,
|
|
538
|
+
label: source.label || key,
|
|
539
|
+
sort: source.sort || 0,
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
} catch (error) {
|
|
543
|
+
console.warn(`FlowSettings: Dynamic flow source provider '${provider.key}' failed.`, error);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
return [selfSource, ...sources.sort((a, b) => (a.sort || 0) - (b.sort || 0))];
|
|
548
|
+
}
|
|
549
|
+
|
|
466
550
|
/**
|
|
467
551
|
* 清空所有工具栏项目
|
|
468
552
|
* @example
|
|
@@ -0,0 +1,21 @@
|
|
|
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
|
+
|
|
12
|
+
import { getFlowEngineTranslation } from '../index';
|
|
13
|
+
|
|
14
|
+
describe('flow engine locale', () => {
|
|
15
|
+
it('translates the default secondary confirmation text into Chinese', () => {
|
|
16
|
+
expect(getFlowEngineTranslation('Please Confirm', 'zh-CN')).toBe('请确认');
|
|
17
|
+
expect(getFlowEngineTranslation('Are you sure you want to perform the action?', 'zh-CN')).toBe(
|
|
18
|
+
'确定要执行此操作吗?',
|
|
19
|
+
);
|
|
20
|
+
});
|
|
21
|
+
});
|
package/src/locale/en-US.json
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"Add": "Add",
|
|
3
|
+
"Are you sure you want to perform the action?": "Are you sure you want to perform the action?",
|
|
3
4
|
"Are you sure you want to delete this item? This action cannot be undone.": "Are you sure you want to delete this item? This action cannot be undone.",
|
|
4
5
|
"Are you sure to convert this template block to copy mode?": "Are you sure you want to convert this template block to copy mode?",
|
|
5
6
|
"Array index out of bounds": "Array index {{index}} out of bounds for '{{subKey}}'",
|
|
@@ -53,9 +54,11 @@
|
|
|
53
54
|
"Other blocks": "Other blocks",
|
|
54
55
|
"Parent not found, cannot replace block": "Parent not found, cannot replace block",
|
|
55
56
|
"Previous step": "Previous step",
|
|
57
|
+
"Please Confirm": "Please Confirm",
|
|
56
58
|
"Replace current block with template?": "Replace current block with template?",
|
|
57
59
|
"Replaced with template block": "Replaced with template block",
|
|
58
60
|
"Render failed": "Render failed",
|
|
61
|
+
"Response record": "Response record",
|
|
59
62
|
"Step configuration": "Step configuration",
|
|
60
63
|
"Step parameter configuration": "Step parameter configuration",
|
|
61
64
|
"Step with key {{stepKey}} not found": "Step with key {{stepKey}} not found",
|
package/src/locale/zh-CN.json
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"Add": "添加",
|
|
3
|
+
"Are you sure you want to perform the action?": "确定要执行此操作吗?",
|
|
3
4
|
"Are you sure you want to delete this item? This action cannot be undone.": "确定要删除此项吗?此操作不可撤销。",
|
|
4
5
|
"Are you sure to convert this template block to copy mode?": "确定将该模板区块转换为复制模式吗?",
|
|
5
6
|
"Array index out of bounds": "数组索引 {{index}} 超出 '{{subKey}}' 的边界",
|
|
@@ -59,7 +60,9 @@
|
|
|
59
60
|
"OK": "确定",
|
|
60
61
|
"Other blocks": "其他区块",
|
|
61
62
|
"Previous step": "上一步",
|
|
63
|
+
"Please Confirm": "请确认",
|
|
62
64
|
"Render failed": "渲染失败",
|
|
65
|
+
"Response record": "响应结果记录",
|
|
63
66
|
"Step configuration": "步骤配置",
|
|
64
67
|
"Step parameter configuration": "步骤参数配置",
|
|
65
68
|
"Step with key {{stepKey}} not found": "未找到key为 {{stepKey}} 的步骤",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import { APIClient } from '@nocobase/sdk';
|
|
11
11
|
import { FlowContext } from '../flowContext';
|
|
12
|
+
import { getDirtyAwareApiClient } from '../utils/dirtyAwareApiClient';
|
|
12
13
|
import { FlowResource, ResourceError } from './flowResource';
|
|
13
14
|
|
|
14
15
|
export class APIResource<TData = any> extends FlowResource<TData> {
|
|
@@ -33,7 +34,7 @@ export class APIResource<TData = any> extends FlowResource<TData> {
|
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
setAPIClient(api: APIClient) {
|
|
36
|
-
this.api = api;
|
|
37
|
+
this.api = getDirtyAwareApiClient(api, this.context) as APIClient;
|
|
37
38
|
return this;
|
|
38
39
|
}
|
|
39
40
|
|
|
@@ -12,7 +12,7 @@ import _ from 'lodash';
|
|
|
12
12
|
import { APIResource } from './apiResource';
|
|
13
13
|
import { FilterItem } from './filterItem';
|
|
14
14
|
import { ResourceError } from './flowResource';
|
|
15
|
-
import {
|
|
15
|
+
import { markDataSourceDirty } from '../utils/dataSourceDirty';
|
|
16
16
|
|
|
17
17
|
export abstract class BaseRecordResource<TData = any> extends APIResource<TData> {
|
|
18
18
|
protected resourceName: string;
|
|
@@ -142,28 +142,11 @@ export abstract class BaseRecordResource<TData = any> extends APIResource<TData>
|
|
|
142
142
|
* Used to coordinate "refresh on active" across view stacks.
|
|
143
143
|
*/
|
|
144
144
|
protected markDataSourceDirty(resourceName?: string) {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
if (!resName) return;
|
|
151
|
-
|
|
152
|
-
const affectedResourceNames = new Set<string>([String(resName)]);
|
|
153
|
-
// Optional safety: association resources like "users.profile" may impact parent collection views.
|
|
154
|
-
if (typeof resName === 'string' && resName.includes('.')) {
|
|
155
|
-
affectedResourceNames.add(resName.split('.')[0]);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
for (const name of affectedResourceNames) {
|
|
159
|
-
engine.markDataSourceDirty(dataSourceKey, name);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Signal current view to re-evaluate dirty blocks (e.g., same-view sibling refresh).
|
|
163
|
-
// This is emitted on the *current* engine emitter (view-scoped) so it won't affect other views.
|
|
164
|
-
engine.emitter?.emit?.(DATA_SOURCE_DIRTY_EVENT, {
|
|
165
|
-
dataSourceKey,
|
|
166
|
-
resourceNames: Array.from(affectedResourceNames),
|
|
145
|
+
markDataSourceDirty({
|
|
146
|
+
engine: this.context.engine,
|
|
147
|
+
dataSourceKey: this.getDataSourceKey(),
|
|
148
|
+
resourceName: resourceName || this.getResourceName(),
|
|
149
|
+
includePreviousEngines: true,
|
|
167
150
|
});
|
|
168
151
|
}
|
|
169
152
|
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { observable } from '@formily/reactive';
|
|
11
11
|
import { AxiosRequestConfig } from 'axios';
|
|
12
12
|
import _ from 'lodash';
|
|
13
|
+
import { SKIP_DATA_SOURCE_DIRTY } from '../utils/dirtyAwareApiClient';
|
|
13
14
|
import { BaseRecordResource } from './baseRecordResource';
|
|
14
15
|
|
|
15
16
|
export class MultiRecordResource<TDataItem = any> extends BaseRecordResource<TDataItem[]> {
|
|
@@ -113,7 +114,10 @@ export class MultiRecordResource<TDataItem = any> extends BaseRecordResource<TDa
|
|
|
113
114
|
|
|
114
115
|
async create(data: TDataItem, options?: AxiosRequestConfig & { refresh?: boolean }): Promise<void> {
|
|
115
116
|
const config = this.mergeRequestConfig({ data }, this.createActionOptions, options);
|
|
116
|
-
const res = await this.runAction('create',
|
|
117
|
+
const res = await this.runAction('create', {
|
|
118
|
+
...config,
|
|
119
|
+
[SKIP_DATA_SOURCE_DIRTY]: true,
|
|
120
|
+
});
|
|
117
121
|
this.markDataSourceDirty();
|
|
118
122
|
this.emit('saved', data);
|
|
119
123
|
if (options?.refresh !== false) {
|
|
@@ -146,7 +150,10 @@ export class MultiRecordResource<TDataItem = any> extends BaseRecordResource<TDa
|
|
|
146
150
|
this.updateActionOptions,
|
|
147
151
|
options,
|
|
148
152
|
);
|
|
149
|
-
await this.runAction('update',
|
|
153
|
+
await this.runAction('update', {
|
|
154
|
+
...config,
|
|
155
|
+
[SKIP_DATA_SOURCE_DIRTY]: true,
|
|
156
|
+
});
|
|
150
157
|
this.markDataSourceDirty();
|
|
151
158
|
this.emit('saved', data);
|
|
152
159
|
await this.refresh();
|
|
@@ -172,7 +179,10 @@ export class MultiRecordResource<TDataItem = any> extends BaseRecordResource<TDa
|
|
|
172
179
|
},
|
|
173
180
|
options,
|
|
174
181
|
);
|
|
175
|
-
await this.runAction('destroy',
|
|
182
|
+
await this.runAction('destroy', {
|
|
183
|
+
...config,
|
|
184
|
+
[SKIP_DATA_SOURCE_DIRTY]: true,
|
|
185
|
+
});
|
|
176
186
|
this.markDataSourceDirty();
|
|
177
187
|
const currentPage = this.getPage();
|
|
178
188
|
const lastPage = Math.ceil((this.getCount() - _.castArray(filterByTk).length) / this.getPageSize());
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import { AxiosRequestConfig } from 'axios';
|
|
11
11
|
import _ from 'lodash';
|
|
12
|
+
import { SKIP_DATA_SOURCE_DIRTY } from '../utils/dirtyAwareApiClient';
|
|
12
13
|
import { BaseRecordResource } from './baseRecordResource';
|
|
13
14
|
|
|
14
15
|
export class SingleRecordResource<TData = any> extends BaseRecordResource<TData> {
|
|
@@ -43,6 +44,7 @@ export class SingleRecordResource<TData = any> extends BaseRecordResource<TData>
|
|
|
43
44
|
const res = await this.runAction(actionName, {
|
|
44
45
|
...config,
|
|
45
46
|
data: result,
|
|
47
|
+
[SKIP_DATA_SOURCE_DIRTY]: true,
|
|
46
48
|
});
|
|
47
49
|
// Mark as dirty before emitting/refreshing so other views can refresh when activated.
|
|
48
50
|
this.markDataSourceDirty();
|
|
@@ -62,7 +64,10 @@ export class SingleRecordResource<TData = any> extends BaseRecordResource<TData>
|
|
|
62
64
|
},
|
|
63
65
|
options,
|
|
64
66
|
);
|
|
65
|
-
await this.runAction('destroy',
|
|
67
|
+
await this.runAction('destroy', {
|
|
68
|
+
...config,
|
|
69
|
+
[SKIP_DATA_SOURCE_DIRTY]: true,
|
|
70
|
+
});
|
|
66
71
|
this.markDataSourceDirty();
|
|
67
72
|
this.setData(null);
|
|
68
73
|
}
|
|
@@ -46,12 +46,17 @@ export function createJSRunnerWithVersion(this: FlowContext, options?: JSRunnerO
|
|
|
46
46
|
doc = {};
|
|
47
47
|
}
|
|
48
48
|
const deprecatedCtx = createRunJSDeprecationProxy(runCtx, { doc });
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (typeof
|
|
53
|
-
|
|
49
|
+
const browserGlobals: Record<string, any> = {};
|
|
50
|
+
if (typeof window !== 'undefined') {
|
|
51
|
+
browserGlobals.window = window;
|
|
52
|
+
if (typeof navigator !== 'undefined') {
|
|
53
|
+
browserGlobals.navigator = navigator;
|
|
54
|
+
}
|
|
54
55
|
}
|
|
56
|
+
if (typeof document !== 'undefined') {
|
|
57
|
+
browserGlobals.document = document;
|
|
58
|
+
}
|
|
59
|
+
const globals: Record<string, any> = { ctx: deprecatedCtx, ...browserGlobals, ...(options?.globals || {}) };
|
|
55
60
|
// 透传 JSRunnerOptions 其余配置(如 timeoutMs)
|
|
56
61
|
const { timeoutMs } = options || {};
|
|
57
62
|
return new JSRunner({ globals, timeoutMs });
|
|
@@ -59,7 +64,8 @@ export function createJSRunnerWithVersion(this: FlowContext, options?: JSRunnerO
|
|
|
59
64
|
|
|
60
65
|
export function getRunJSScenesForModel(modelClass: string, version: RunJSVersion = 'v1'): string[] {
|
|
61
66
|
const meta = RunJSContextRegistry.getMeta(version, modelClass);
|
|
62
|
-
|
|
67
|
+
const scenes = meta?.scenes;
|
|
68
|
+
return Array.isArray(scenes) ? [...scenes] : [];
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
export function getRunJSScenesForContext(ctx: FlowContext, { version = 'v1' as RunJSVersion } = {}): string[] {
|
package/src/types.ts
CHANGED
|
@@ -147,6 +147,8 @@ export enum ActionScene {
|
|
|
147
147
|
DYNAMIC_EVENT_FLOW,
|
|
148
148
|
/** 菜单项联动规则可用 */
|
|
149
149
|
MENU_LINKAGE_RULES,
|
|
150
|
+
/** 标签页联动规则可用 */
|
|
151
|
+
TAB_LINKAGE_RULES,
|
|
150
152
|
}
|
|
151
153
|
|
|
152
154
|
/**
|
|
@@ -612,6 +614,20 @@ export interface ToolbarItemConfig {
|
|
|
612
614
|
sort?: number;
|
|
613
615
|
}
|
|
614
616
|
|
|
617
|
+
export interface DynamicFlowSource {
|
|
618
|
+
key: string;
|
|
619
|
+
label: React.ReactNode;
|
|
620
|
+
model: FlowModel;
|
|
621
|
+
sort?: number;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
export interface DynamicFlowSourceProvider {
|
|
625
|
+
key: string;
|
|
626
|
+
sort?: number;
|
|
627
|
+
visible?: (model: FlowModel) => boolean;
|
|
628
|
+
getSources: (model: FlowModel) => DynamicFlowSource[] | Promise<DynamicFlowSource[]>;
|
|
629
|
+
}
|
|
630
|
+
|
|
615
631
|
export interface ApplyFlowCacheEntry {
|
|
616
632
|
status: 'pending' | 'resolved' | 'rejected';
|
|
617
633
|
promise: Promise<any>;
|