feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { type FC } from 'react';
|
||||
|
||||
import {
|
||||
FlowNodeVariableData,
|
||||
ScopeProvider,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
import { type DecoratorComponentProps } from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
const PrivateScopeDecorator: FC<DecoratorComponentProps> = props => {
|
||||
const { context, children } = props;
|
||||
|
||||
const privateScope = context.node?.getData(FlowNodeVariableData)?.private;
|
||||
|
||||
if (privateScope) {
|
||||
return (
|
||||
<ScopeProvider value={{ scope: privateScope }}>{children}</ScopeProvider>
|
||||
);
|
||||
}
|
||||
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
||||
export const privateScopeDecorator = {
|
||||
key: 'PrivateScopeDecorator',
|
||||
component: PrivateScopeDecorator,
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type VariableProviderAbilityOptions } from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { provideNodeOutputVariables } from './variable-providers/provide-node-output-variables';
|
||||
import { provideNodeBatchVariables } from './variable-providers/provide-node-batch-variables';
|
||||
import { provideLoopOutputsVariables } from './variable-providers/provide-loop-output-variables';
|
||||
import { provideLoopInputsVariables } from './variable-providers/provide-loop-input-variables';
|
||||
import { consumeRefValueExpression } from './variable-consumers/consume-ref-value-expression';
|
||||
import { privateScopeDecorator } from './decorators/private-scope-decorator';
|
||||
|
||||
export { provideMergeGroupVariablesEffect } from './variable-providers/provide-merge-group-variables';
|
||||
|
||||
export const variableProviders: VariableProviderAbilityOptions[] = [
|
||||
provideNodeOutputVariables,
|
||||
provideNodeBatchVariables,
|
||||
provideLoopInputsVariables,
|
||||
provideLoopOutputsVariables,
|
||||
];
|
||||
|
||||
export const variableConsumers = [consumeRefValueExpression];
|
||||
|
||||
export const variableDecorators = [privateScopeDecorator];
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ASTFactory, type ASTNode } from '@flowgram-adapter/free-layout-editor';
|
||||
import { type VariableConsumerAbilityOptions } from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
/**
|
||||
* TODO 数组内 variable-consumer 拿不到 value 值
|
||||
*/
|
||||
export const consumeRefValueExpression: VariableConsumerAbilityOptions = {
|
||||
key: 'consume-ref-value-expression',
|
||||
parse(v, ctx) {
|
||||
console.log(
|
||||
'[ debugger test change ] > ',
|
||||
ctx.formItem?.formModel,
|
||||
ctx.formItem?.path,
|
||||
v,
|
||||
);
|
||||
|
||||
return ASTFactory.createKeyPathExpression({
|
||||
keyPath: v?.content?.keyPath,
|
||||
});
|
||||
},
|
||||
onInit(ctx) {
|
||||
const { options, scope, formItem } = ctx;
|
||||
|
||||
const astKey = options?.namespace || formItem?.path || '';
|
||||
|
||||
return scope.ast.subscribe<ASTNode>(
|
||||
_type => {
|
||||
console.log('[ debugger type ] >', _type);
|
||||
},
|
||||
{
|
||||
selector: _ast => _ast.get(astKey)?.returnType as ASTNode,
|
||||
},
|
||||
);
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { uniqBy } from 'lodash-es';
|
||||
import { type PropertyJSON } from '@flowgram-adapter/free-layout-editor';
|
||||
import { type RefExpression } from '@coze-workflow/base/types';
|
||||
|
||||
export interface InputItem {
|
||||
name: string;
|
||||
input: RefExpression;
|
||||
}
|
||||
|
||||
export const uniqInputs = (inputs?: InputItem[]): InputItem[] =>
|
||||
uniqBy(
|
||||
(inputs || []).filter(_input => _input && _input?.name),
|
||||
_child => _child?.name,
|
||||
);
|
||||
|
||||
export const uniqProperties = (properties?: PropertyJSON[]): PropertyJSON[] =>
|
||||
uniqBy(
|
||||
(properties || []).filter(_input => _input && _input?.key),
|
||||
_child => _child?.key,
|
||||
);
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ASTFactory } from '@flowgram-adapter/free-layout-editor';
|
||||
import { type VariableProviderAbilityOptions } from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { ValueExpressionType } from '../../typings';
|
||||
import { createRefExpression } from '../../core/extend-ast/custom-key-path-expression';
|
||||
import { type InputItem, uniqInputs, uniqProperties } from './common';
|
||||
interface ValueType {
|
||||
inputParameters?: InputItem[];
|
||||
variableParameters?: InputItem[];
|
||||
}
|
||||
|
||||
export const parseLoopInputsByViewVariableMeta = (
|
||||
nodeId: string,
|
||||
value: ValueType,
|
||||
) => {
|
||||
const { inputParameters, variableParameters } = value || {};
|
||||
const batchProperties = uniqInputs(inputParameters).map(_input =>
|
||||
ASTFactory.createProperty({
|
||||
key: _input?.name,
|
||||
meta: {
|
||||
label: `item (in ${_input?.name})`,
|
||||
},
|
||||
initializer: ASTFactory.createEnumerateExpression({
|
||||
enumerateFor: createRefExpression({
|
||||
keyPath: _input?.input?.content?.keyPath || [],
|
||||
rawMeta: _input?.input?.rawMeta,
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
const variableProperties = uniqInputs(variableParameters).map(_input => {
|
||||
// 没有 rawMeta 时,可能是历史数据,走下面的兜底逻辑
|
||||
if (_input?.input?.rawMeta?.type) {
|
||||
return ASTFactory.createProperty({
|
||||
key: _input?.name,
|
||||
meta: {
|
||||
mutable: true,
|
||||
},
|
||||
initializer: createRefExpression({
|
||||
keyPath: _input?.input?.content?.keyPath || [],
|
||||
rawMeta: _input?.input?.rawMeta,
|
||||
}),
|
||||
});
|
||||
}
|
||||
if (_input?.input?.type === ValueExpressionType.REF) {
|
||||
return ASTFactory.createProperty({
|
||||
key: _input?.name,
|
||||
meta: {
|
||||
mutable: true,
|
||||
},
|
||||
// 直接引用变量
|
||||
initializer: ASTFactory.createKeyPathExpression({
|
||||
keyPath: _input?.input?.content?.keyPath || [],
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
return ASTFactory.createProperty({
|
||||
key: _input?.name,
|
||||
meta: {
|
||||
mutable: true,
|
||||
},
|
||||
type: ASTFactory.createString(),
|
||||
});
|
||||
});
|
||||
|
||||
const indexProperties = [
|
||||
ASTFactory.createProperty({
|
||||
key: 'index',
|
||||
type: ASTFactory.createInteger(),
|
||||
}),
|
||||
];
|
||||
|
||||
const properties = uniqProperties([
|
||||
...batchProperties,
|
||||
...indexProperties,
|
||||
...variableProperties,
|
||||
]);
|
||||
|
||||
return [
|
||||
ASTFactory.createVariableDeclaration({
|
||||
key: `${nodeId}.locals`,
|
||||
type: ASTFactory.createObject({
|
||||
properties,
|
||||
}),
|
||||
}),
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
* 循环输入变量同步
|
||||
*/
|
||||
export const provideLoopInputsVariables: VariableProviderAbilityOptions = {
|
||||
key: 'provide-loop-input-variables',
|
||||
namespace: '/node/locals',
|
||||
private: true,
|
||||
scope: 'private',
|
||||
parse(value: ValueType, context) {
|
||||
return parseLoopInputsByViewVariableMeta(context.node.id, value);
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type VariableProviderAbilityOptions } from '@flowgram-adapter/free-layout-editor';
|
||||
import { ASTFactory } from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { createWrapArrayExpression } from '../../core/extend-ast/wrap-array-expression';
|
||||
import { type InputItem, uniqInputs } from './common';
|
||||
|
||||
export const parseLoopOutputsByViewVariableMeta = (
|
||||
nodeId: string,
|
||||
value: InputItem[],
|
||||
) => {
|
||||
const properties = uniqInputs(value || []).map(_input => {
|
||||
const keyPath = _input?.input?.content?.keyPath;
|
||||
// 如果选择的是 Loop 的 Variable 内的变量
|
||||
if (keyPath?.[0] === nodeId) {
|
||||
return ASTFactory.createProperty({
|
||||
key: _input?.name,
|
||||
// 直接引用变量
|
||||
initializer: ASTFactory.createKeyPathExpression({
|
||||
keyPath: _input?.input?.content?.keyPath || [],
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
return ASTFactory.createProperty({
|
||||
key: _input?.name,
|
||||
// 输出类型包一层 Array
|
||||
initializer: createWrapArrayExpression({
|
||||
keyPath: _input?.input?.content?.keyPath || [],
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
return [
|
||||
ASTFactory.createVariableDeclaration({
|
||||
key: `${nodeId}.outputs`,
|
||||
type: ASTFactory.createObject({
|
||||
properties,
|
||||
}),
|
||||
}),
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
* 循环输出变量同步
|
||||
*/
|
||||
export const provideLoopOutputsVariables: VariableProviderAbilityOptions = {
|
||||
key: 'provide-loop-output-variables',
|
||||
namespace: '/node/outputs',
|
||||
private: false,
|
||||
scope: 'public',
|
||||
parse(value, context) {
|
||||
return parseLoopOutputsByViewVariableMeta(context.node.id, value);
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
ASTFactory,
|
||||
ASTKind,
|
||||
type ObjectType,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
import { type VariableProviderAbilityOptions } from '@flowgram-adapter/free-layout-editor';
|
||||
import { type EffectOptions } from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { createEffectFromVariableProvider } from '../../utils/variable-provider';
|
||||
import { setValueIn } from '../../utils/form';
|
||||
import { type RefExpression } from '../../typings';
|
||||
import {
|
||||
createMergeGroupExpression,
|
||||
MergeStrategy,
|
||||
} from '../../core/extend-ast/merge-group-expression';
|
||||
import { createRefExpression } from '../../core/extend-ast/custom-key-path-expression';
|
||||
import { WorkflowVariableFacadeService } from '../../core';
|
||||
|
||||
interface MergeGroup {
|
||||
name: string;
|
||||
variables: RefExpression[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并组变量同步
|
||||
*/
|
||||
export const provideMergeGroupVariables: VariableProviderAbilityOptions = {
|
||||
key: 'provide-merge-group-variables',
|
||||
namespace: '/node/outputs',
|
||||
parse(value: MergeGroup[], context) {
|
||||
const nodeId = context.node.id;
|
||||
|
||||
return [
|
||||
ASTFactory.createVariableDeclaration({
|
||||
key: `${nodeId}.outputs`,
|
||||
type: ASTFactory.createObject({
|
||||
properties: value?.map(_item =>
|
||||
ASTFactory.createProperty({
|
||||
key: _item?.name,
|
||||
initializer: createMergeGroupExpression({
|
||||
mergeStrategy: MergeStrategy.FirstNotEmpty,
|
||||
expressions: _item.variables.map(_v =>
|
||||
createRefExpression({
|
||||
keyPath: _v?.content?.keyPath || [],
|
||||
rawMeta: _v?.rawMeta,
|
||||
}),
|
||||
),
|
||||
}),
|
||||
}),
|
||||
),
|
||||
}),
|
||||
}),
|
||||
];
|
||||
},
|
||||
onInit(ctx) {
|
||||
const facadeService = ctx.node.getService(WorkflowVariableFacadeService);
|
||||
|
||||
return ctx.scope.ast.subscribe(() => {
|
||||
// 监听输出变量变化,回填到表单的 outputs
|
||||
const outputVariable = ctx.scope.output.variables[0];
|
||||
if (outputVariable?.type?.kind === ASTKind.Object) {
|
||||
const { properties } = outputVariable.type as ObjectType;
|
||||
|
||||
const nextOutputs = properties
|
||||
.map(
|
||||
_property =>
|
||||
// OutputTree 组件中,所有树节点的 key 需要保证是唯一的
|
||||
facadeService.getVariableFacadeByField(_property)
|
||||
.viewMetaWithUniqKey,
|
||||
)
|
||||
.filter(Boolean);
|
||||
|
||||
setValueIn(ctx.node, 'outputs', nextOutputs);
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export const provideMergeGroupVariablesEffect: EffectOptions[] =
|
||||
createEffectFromVariableProvider(provideMergeGroupVariables);
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type VariableProviderAbilityOptions } from '@flowgram-adapter/free-layout-editor';
|
||||
import { FlowNodeFormData } from '@flowgram-adapter/free-layout-editor';
|
||||
import { Disposable } from '@flowgram-adapter/common';
|
||||
|
||||
import { parseNodeBatchByInputList } from '../../core';
|
||||
|
||||
export const provideNodeBatchVariables: VariableProviderAbilityOptions = {
|
||||
key: 'provide-node-batch-variables',
|
||||
namespace: '/node/locals',
|
||||
scope: 'private',
|
||||
parse(value, context) {
|
||||
const batchMode =
|
||||
context.formItem?.formModel.getFormItemValueByPath('/batchMode') ||
|
||||
context.formItem?.formModel.getFormItemValueByPath('/inputs/batchMode');
|
||||
|
||||
if (batchMode !== 'batch') {
|
||||
return [];
|
||||
}
|
||||
|
||||
return parseNodeBatchByInputList(context.node.id, value);
|
||||
},
|
||||
onInit(context) {
|
||||
const formData = context.node.getData(FlowNodeFormData);
|
||||
if (!formData) {
|
||||
return Disposable.create(() => null);
|
||||
}
|
||||
|
||||
return formData.onDetailChange(_detail => {
|
||||
if (_detail.path.includes('/batchMode')) {
|
||||
context.triggerSync();
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type VariableProviderAbilityOptions } from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { parseNodeOutputByViewVariableMeta } from '../../core';
|
||||
|
||||
export const provideNodeOutputVariables: VariableProviderAbilityOptions = {
|
||||
key: 'provide-node-output-variables',
|
||||
namespace: '/node/outputs',
|
||||
parse(value, context) {
|
||||
return parseNodeOutputByViewVariableMeta(context.node.id, value);
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user