feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
2
frontend/packages/workflow/playground/src/node-registries/.gitignore
vendored
Normal file
2
frontend/packages/workflow/playground/src/node-registries/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# output 节点不应被忽略
|
||||
!output
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { BatchPort } from './loop-port';
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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 { Port } from '@/components/node-render/node-render-new/fields/port';
|
||||
|
||||
export const BatchPort = () => (
|
||||
<>
|
||||
<Port
|
||||
id={'batch-output-to-function'}
|
||||
type="output"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
width: 20,
|
||||
height: 20,
|
||||
right: 'unset',
|
||||
top: 'unset',
|
||||
bottom: 0,
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, 50%)',
|
||||
}}
|
||||
/>
|
||||
<Port
|
||||
id={'batch-output'}
|
||||
type="output"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
right: '0',
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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 {
|
||||
WorkflowNodeEntity,
|
||||
WorkflowSubCanvas,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
import {
|
||||
FlowNodeBaseType,
|
||||
FlowNodeTransformData,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
import { FlowRendererKey } from '@flowgram-adapter/free-layout-editor';
|
||||
import {
|
||||
type IPoint,
|
||||
type PaddingSchema,
|
||||
type PositionSchema,
|
||||
} from '@flowgram-adapter/common';
|
||||
import type { WorkflowNodeJSON } from '@coze-workflow/base';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
|
||||
import { BatchFunctionSize } from '../constants';
|
||||
import { getBatchID } from './relation';
|
||||
|
||||
export const createBatchFunctionJSON = (
|
||||
id: string,
|
||||
position: IPoint,
|
||||
): WorkflowNodeJSON => ({
|
||||
id,
|
||||
type: FlowNodeBaseType.SUB_CANVAS,
|
||||
data: {},
|
||||
meta: {
|
||||
isContainer: true,
|
||||
position,
|
||||
nodeDTOType: FlowNodeBaseType.SUB_CANVAS,
|
||||
useDynamicPort: true,
|
||||
renderKey: FlowRendererKey.SUB_CANVAS,
|
||||
size: {
|
||||
width: BatchFunctionSize.width,
|
||||
height: BatchFunctionSize.height,
|
||||
},
|
||||
defaultPorts: [
|
||||
{ type: 'input', portID: 'batch-function-input', disabled: true },
|
||||
{ type: 'input', portID: 'batch-function-inline-input' },
|
||||
{ type: 'output', portID: 'batch-function-inline-output' },
|
||||
],
|
||||
padding: (transform: FlowNodeTransformData): PaddingSchema => ({
|
||||
top: 100,
|
||||
bottom: 60,
|
||||
left: 100,
|
||||
right: 100,
|
||||
}),
|
||||
selectable(node: WorkflowNodeEntity, mousePos?: PositionSchema): boolean {
|
||||
if (!mousePos) {
|
||||
return true;
|
||||
}
|
||||
const transform = node.getData<FlowNodeTransformData>(
|
||||
FlowNodeTransformData,
|
||||
);
|
||||
// 鼠标开始时所在位置不包括当前节点时才可选中
|
||||
return !transform.bounds.contains(mousePos.x, mousePos.y);
|
||||
},
|
||||
renderSubCanvas: () => ({
|
||||
title: I18n.t('workflow_batch_canvas_title'),
|
||||
tooltip: I18n.t('workflow_batch_canvas_tooltips'),
|
||||
style: {
|
||||
minWidth: BatchFunctionSize.width,
|
||||
minHeight: BatchFunctionSize.height,
|
||||
},
|
||||
renderPorts: [
|
||||
{
|
||||
id: 'batch-function-input',
|
||||
type: 'input',
|
||||
style: {
|
||||
position: 'absolute',
|
||||
left: '50%',
|
||||
top: '0',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'batch-function-inline-input',
|
||||
type: 'input',
|
||||
style: {
|
||||
position: 'absolute',
|
||||
right: '0',
|
||||
top: '50%',
|
||||
transform: 'translateY(20px)',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'batch-function-inline-output',
|
||||
type: 'output',
|
||||
style: {
|
||||
position: 'absolute',
|
||||
left: '0',
|
||||
top: '50%',
|
||||
transform: 'translateY(20px)',
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
subCanvas: (node: WorkflowNodeEntity): WorkflowSubCanvas | undefined => {
|
||||
const canvasNode = node;
|
||||
const parentNodeID = getBatchID(canvasNode.id);
|
||||
const parentNode = node.document.getNode(parentNodeID);
|
||||
if (!parentNode) {
|
||||
return undefined;
|
||||
}
|
||||
const subCanvas: WorkflowSubCanvas = {
|
||||
isCanvas: true,
|
||||
parentNode,
|
||||
canvasNode,
|
||||
};
|
||||
return subCanvas;
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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 { WorkflowDocument } from '@flowgram-adapter/free-layout-editor';
|
||||
import { delay } from '@flowgram-adapter/common';
|
||||
|
||||
/** 生成连线 */
|
||||
export const createBatchFunctionLines = async (params: {
|
||||
document: WorkflowDocument;
|
||||
batchId: string;
|
||||
batchFunctionId: string;
|
||||
}) => {
|
||||
await delay(30); // 等待节点创建完毕
|
||||
const { document, batchId, batchFunctionId } = params;
|
||||
document.linesManager.createLine({
|
||||
from: batchId,
|
||||
to: batchFunctionId,
|
||||
fromPort: 'batch-output-to-function',
|
||||
toPort: 'batch-function-input',
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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 { WorkflowNodeEntity } from '@flowgram-adapter/free-layout-editor';
|
||||
import { type NodeData, WorkflowNodeData } from '@coze-workflow/nodes';
|
||||
import type { BasicStandardNodeTypes } from '@coze-workflow/base';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
|
||||
/** 同步节点模版数据 */
|
||||
export const createBatchFunctionTemplateData = (
|
||||
batchNode: WorkflowNodeEntity,
|
||||
batchFunctionNode: WorkflowNodeEntity,
|
||||
) => {
|
||||
const batchNodeDataEntity =
|
||||
batchNode.getData<WorkflowNodeData>(WorkflowNodeData);
|
||||
const batchFunctionNodeDataEntity =
|
||||
batchFunctionNode.getData<WorkflowNodeData>(WorkflowNodeData);
|
||||
const batchNodeData = batchNodeDataEntity.getNodeData<keyof NodeData>();
|
||||
if (!batchNodeData) {
|
||||
return;
|
||||
}
|
||||
batchFunctionNodeDataEntity.setNodeData<BasicStandardNodeTypes>({
|
||||
title: I18n.t('workflow_batch_canvas_title'),
|
||||
description: I18n.t('workflow_batch_canvas_tooltips'),
|
||||
icon: batchNodeData.icon,
|
||||
mainColor: batchNodeData.mainColor,
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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 {
|
||||
WorkflowDocument,
|
||||
WorkflowNodeEntity,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
import { type IPoint } from '@flowgram-adapter/common';
|
||||
import type { WorkflowNodeJSON } from '@coze-workflow/base';
|
||||
|
||||
import { BatchFunctionIDPrefix } from './relation';
|
||||
import { createBatchFunctionTemplateData } from './create-batch-function-template-data';
|
||||
import { createBatchFunctionLines } from './create-batch-function-lines';
|
||||
import { createBatchFunctionJSON } from './create-batch-function-json';
|
||||
|
||||
/** 创建 Batch 循环体节点 */
|
||||
export const createBatchFunction = async (
|
||||
batchNode: WorkflowNodeEntity,
|
||||
batchJson: WorkflowNodeJSON,
|
||||
) => {
|
||||
const document = batchNode.document as WorkflowDocument;
|
||||
const id = `${BatchFunctionIDPrefix}${batchNode.id}`;
|
||||
const batchPosition: IPoint = {
|
||||
x: batchJson.meta?.position?.x || 0,
|
||||
y: batchJson.meta?.position?.y || 0,
|
||||
};
|
||||
const offset: IPoint = {
|
||||
x: 0,
|
||||
y: 200,
|
||||
};
|
||||
const position = {
|
||||
x: batchPosition.x + offset.x,
|
||||
y: batchPosition.y + offset.y,
|
||||
};
|
||||
const batchFunctionJSON = createBatchFunctionJSON(id, position);
|
||||
const batchFunctionNode =
|
||||
await document.createWorkflowNode(batchFunctionJSON);
|
||||
createBatchFunctionTemplateData(batchNode, batchFunctionNode);
|
||||
createBatchFunctionLines({
|
||||
document,
|
||||
batchId: batchNode.id,
|
||||
batchFunctionId: batchFunctionNode.id,
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { createBatchFunctionJSON } from './create-batch-function-json';
|
||||
export { createBatchFunctionLines } from './create-batch-function-lines';
|
||||
export { createBatchFunctionTemplateData } from './create-batch-function-template-data';
|
||||
export { createBatchFunction } from './create-batch-function';
|
||||
export {
|
||||
BatchFunctionIDPrefix,
|
||||
getBatchFunctionID,
|
||||
getBatchID,
|
||||
} from './relation';
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/naming-convention*/
|
||||
export const BatchFunctionIDPrefix = 'BatchFunction_';
|
||||
export const getBatchFunctionID = (batchID: string) =>
|
||||
BatchFunctionIDPrefix + batchID;
|
||||
export const getBatchID = (batchFunctionID: string) =>
|
||||
batchFunctionID.replace(BatchFunctionIDPrefix, '');
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/naming-convention*/
|
||||
/* eslint-disable @typescript-eslint/no-shadow */
|
||||
|
||||
export const BatchSize = {
|
||||
width: 360,
|
||||
height: 139.86,
|
||||
};
|
||||
|
||||
export const BatchFunctionSize = {
|
||||
width: BatchSize.width,
|
||||
height: (BatchSize.width * 3) / 5,
|
||||
};
|
||||
|
||||
export const BatchOutputsSuffix = '_list';
|
||||
|
||||
export enum BatchPath {
|
||||
ConcurrentSize = 'inputs.concurrentSize',
|
||||
BatchSize = 'inputs.batchSize',
|
||||
Inputs = 'inputs.inputParameters',
|
||||
Outputs = 'outputs',
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { set } from 'lodash-es';
|
||||
import { variableUtils } from '@coze-workflow/variable';
|
||||
import { type NodeDataDTO } from '@coze-workflow/base';
|
||||
|
||||
/**
|
||||
* 节点后端数据 -> 前端表单数据
|
||||
*/
|
||||
export const transformOnInit = (formData: any, ctx: any) => {
|
||||
const inputParameters = formData?.inputs?.inputParameters;
|
||||
const outputValues = formData?.outputs;
|
||||
const concurrentSize = formData?.inputs?.concurrentSize;
|
||||
const batchSize = formData?.inputs?.batchSize;
|
||||
|
||||
if (!Array.isArray(inputParameters) || inputParameters?.length === 0) {
|
||||
set(formData, 'inputs.inputParameters', [{ name: 'input' }]);
|
||||
}
|
||||
|
||||
if (outputValues && Array.isArray(outputValues)) {
|
||||
outputValues.map((outputValue, index) => {
|
||||
set(
|
||||
outputValues,
|
||||
index,
|
||||
variableUtils.inputValueToVO(
|
||||
outputValue,
|
||||
ctx.playgroundContext.variableService,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
if (concurrentSize) {
|
||||
set(
|
||||
formData,
|
||||
'inputs.concurrentSize',
|
||||
variableUtils.valueExpressionToVO(
|
||||
concurrentSize,
|
||||
ctx.playgroundContext.variableService,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (batchSize) {
|
||||
set(
|
||||
formData,
|
||||
'inputs.batchSize',
|
||||
variableUtils.valueExpressionToVO(
|
||||
batchSize,
|
||||
ctx.playgroundContext.variableService,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return formData;
|
||||
};
|
||||
|
||||
/**
|
||||
* 前端表单数据 -> 节点后端数据
|
||||
* @param value
|
||||
* @returns
|
||||
*/
|
||||
export const transformOnSubmit = (formData: any, ctx: any): NodeDataDTO => {
|
||||
const outputValues = formData?.outputs;
|
||||
const concurrentSize = formData?.inputs?.concurrentSize;
|
||||
const batchSize = formData?.inputs?.batchSize;
|
||||
|
||||
if (outputValues && Array.isArray(outputValues)) {
|
||||
outputValues.map((outputValue, index) => {
|
||||
const dto = variableUtils.inputValueToDTO(
|
||||
outputValue,
|
||||
ctx.playgroundContext.variableService,
|
||||
{ node: ctx.node },
|
||||
);
|
||||
|
||||
// 定制逻辑:如果选择了循环体内的变量,则输出变量的类型套一层 list
|
||||
if (
|
||||
outputValue?.input?.content?.keyPath?.[0] !== ctx.node.id &&
|
||||
dto?.input
|
||||
) {
|
||||
set(dto, 'input.schema', {
|
||||
type: dto.input?.type,
|
||||
schema: dto.input?.schema,
|
||||
});
|
||||
set(dto, 'input.type', 'list');
|
||||
}
|
||||
|
||||
set(outputValues, index, dto);
|
||||
});
|
||||
set(formData, 'outputs', outputValues.filter(Boolean));
|
||||
}
|
||||
|
||||
if (concurrentSize) {
|
||||
set(
|
||||
formData,
|
||||
'inputs.concurrentSize',
|
||||
variableUtils.valueExpressionToDTO(
|
||||
concurrentSize,
|
||||
ctx.playgroundContext.variableService,
|
||||
{ node: ctx.node },
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (batchSize) {
|
||||
set(
|
||||
formData,
|
||||
'inputs.batchSize',
|
||||
variableUtils.valueExpressionToDTO(
|
||||
batchSize,
|
||||
ctx.playgroundContext.variableService,
|
||||
{ node: ctx.node },
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return formData;
|
||||
};
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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 {
|
||||
useNodeTestId,
|
||||
type ValueExpression,
|
||||
ValueExpressionType,
|
||||
ViewVariableType,
|
||||
} from '@coze-workflow/base';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
|
||||
import { ValueExpressionInput } from '@/form-extensions/components/value-expression-input';
|
||||
import { FormItem } from '@/form-extensions/components/form-item';
|
||||
import { useField, withField } from '@/form';
|
||||
|
||||
interface BatchConcurrentSizeFieldProps {
|
||||
title?: string;
|
||||
tooltip?: string;
|
||||
testId?: string;
|
||||
}
|
||||
|
||||
export const BatchConcurrentSizeField = withField<
|
||||
BatchConcurrentSizeFieldProps,
|
||||
ValueExpression
|
||||
>(
|
||||
({
|
||||
title = I18n.t('workflow_maximum_parallel_runs'),
|
||||
tooltip = I18n.t('workflow_maximum_parallel_runs_tips'),
|
||||
testId,
|
||||
}) => {
|
||||
const { name, value, onChange, readonly } = useField<ValueExpression>();
|
||||
const { getNodeSetterId } = useNodeTestId();
|
||||
|
||||
return (
|
||||
<FormItem
|
||||
label={title}
|
||||
tooltip={tooltip}
|
||||
layout="vertical"
|
||||
style={{
|
||||
marginTop: 12,
|
||||
}}
|
||||
labelStyle={{
|
||||
fontSize: 12,
|
||||
fontWeight: 600,
|
||||
color: 'var(--coz-fg-secondary, rgba(6, 7, 9, 0.50))',
|
||||
}}
|
||||
>
|
||||
<ValueExpressionInput
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
testId={testId ?? getNodeSetterId(name)}
|
||||
disabledTypes={ViewVariableType.getComplement([
|
||||
ViewVariableType.Integer,
|
||||
])}
|
||||
readonly={readonly}
|
||||
inputType={ViewVariableType.Integer}
|
||||
literalConfig={{
|
||||
min: 1,
|
||||
max: 10,
|
||||
}}
|
||||
literalStyle={{
|
||||
width: '100%',
|
||||
}}
|
||||
/>
|
||||
</FormItem>
|
||||
);
|
||||
},
|
||||
{
|
||||
defaultValue: { type: ValueExpressionType.LITERAL, content: 10 },
|
||||
},
|
||||
);
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/consistent-type-assertions */
|
||||
import { type FC } from 'react';
|
||||
|
||||
import { type InputValueVO, ViewVariableType } from '@coze-workflow/base';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
|
||||
import { InputsField } from '@/node-registries/common/fields';
|
||||
|
||||
import { BatchPath } from '../../constants';
|
||||
|
||||
interface BatchInputsFieldProps {
|
||||
name?: string;
|
||||
}
|
||||
|
||||
export const BatchInputsField: FC<BatchInputsFieldProps> = ({ name }) => (
|
||||
<InputsField
|
||||
name={name ?? BatchPath.Inputs}
|
||||
title={I18n.t('workflow_batch_inputs')}
|
||||
tooltip={I18n.t('workflow_batch_inputs_tooltips')}
|
||||
defaultValue={[{ name: 'input' } as InputValueVO]}
|
||||
nthCannotDeleted={1}
|
||||
inputProps={{
|
||||
hideDeleteIcon: true,
|
||||
disabledTypes: ViewVariableType.getComplement(
|
||||
ViewVariableType.getAllArrayType(),
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/consistent-type-assertions */
|
||||
import { type FC } from 'react';
|
||||
|
||||
import { type InputValueVO } from '@coze-workflow/base';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
|
||||
import { LoopOutputsField } from '@/node-registries/common/fields';
|
||||
|
||||
import { BatchOutputsSuffix, BatchPath } from '../../constants';
|
||||
|
||||
interface BatchOutputsFieldProps {
|
||||
name?: string;
|
||||
title?: string;
|
||||
tooltip?: string;
|
||||
}
|
||||
|
||||
export const BatchOutputsField: FC<BatchOutputsFieldProps> = ({
|
||||
name = BatchPath.Outputs,
|
||||
title = I18n.t('workflow_batch_outputs'),
|
||||
tooltip = I18n.t('workflow_batch_outputs_tooltips'),
|
||||
}) => (
|
||||
<LoopOutputsField
|
||||
name={name}
|
||||
title={title}
|
||||
tooltip={tooltip}
|
||||
defaultValue={[{ name: 'output' } as InputValueVO]}
|
||||
nameProps={{
|
||||
initValidate: true,
|
||||
suffix: BatchOutputsSuffix,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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 {
|
||||
useNodeTestId,
|
||||
type ValueExpression,
|
||||
ValueExpressionType,
|
||||
ViewVariableType,
|
||||
} from '@coze-workflow/base';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
|
||||
import { ValueExpressionInput } from '@/form-extensions/components/value-expression-input';
|
||||
import { FormItem } from '@/form-extensions/components/form-item';
|
||||
import { useField, withField } from '@/form';
|
||||
|
||||
interface BatchSizeFieldProps {
|
||||
title?: string;
|
||||
tooltip?: string;
|
||||
testId?: string;
|
||||
}
|
||||
|
||||
export const BatchSizeField = withField<BatchSizeFieldProps, ValueExpression>(
|
||||
({
|
||||
title = I18n.t('workflow_maximum_run_count'),
|
||||
tooltip = I18n.t('workflow_maximum_run_count_tips'),
|
||||
testId,
|
||||
}) => {
|
||||
const { name, value, onChange, readonly } = useField<ValueExpression>();
|
||||
const { getNodeSetterId } = useNodeTestId();
|
||||
|
||||
return (
|
||||
<FormItem
|
||||
label={title}
|
||||
tooltip={tooltip}
|
||||
layout="vertical"
|
||||
style={{
|
||||
marginTop: 12,
|
||||
}}
|
||||
labelStyle={{
|
||||
fontSize: 12,
|
||||
fontWeight: 600,
|
||||
color: 'var(--coz-fg-secondary, rgba(6, 7, 9, 0.50))',
|
||||
}}
|
||||
>
|
||||
<ValueExpressionInput
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
testId={testId ?? getNodeSetterId(name)}
|
||||
disabledTypes={ViewVariableType.getComplement([
|
||||
ViewVariableType.Integer,
|
||||
])}
|
||||
readonly={readonly}
|
||||
inputType={ViewVariableType.Integer}
|
||||
literalConfig={{
|
||||
min: 1,
|
||||
max: 200,
|
||||
}}
|
||||
literalStyle={{
|
||||
width: '100%',
|
||||
}}
|
||||
/>
|
||||
</FormItem>
|
||||
);
|
||||
},
|
||||
{
|
||||
defaultValue: { type: ValueExpressionType.LITERAL, content: 100 },
|
||||
},
|
||||
);
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { BatchConcurrentSizeField } from './batch-concurrent-size';
|
||||
export { BatchInputsField } from './batch-inputs';
|
||||
export { BatchOutputsField } from './batch-outputs';
|
||||
export { BatchSizeField } from './batch-size';
|
||||
export { BatchSettingsSection } from './loop-settings-section';
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 { FC, ReactNode } from 'react';
|
||||
|
||||
import { useNodeTestId } from '@coze-workflow/base';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
|
||||
import { Section } from '@/form';
|
||||
|
||||
interface BatchSettingsFieldProps {
|
||||
title?: string;
|
||||
tooltip?: string;
|
||||
testId?: string;
|
||||
children?: ReactNode | ReactNode[];
|
||||
}
|
||||
|
||||
export const BatchSettingsSection: FC<BatchSettingsFieldProps> = ({
|
||||
title = I18n.t('workflow_loop_title'),
|
||||
tooltip,
|
||||
testId,
|
||||
children,
|
||||
}) => {
|
||||
const { getNodeSetterId } = useNodeTestId();
|
||||
|
||||
return (
|
||||
<Section
|
||||
title={title}
|
||||
tooltip={tooltip}
|
||||
testId={getNodeSetterId(testId ?? '')}
|
||||
>
|
||||
{children}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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 {
|
||||
ValidateTrigger,
|
||||
type FormMetaV2,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { nodeMetaValidate } from '@/nodes-v2/materials/node-meta-validate';
|
||||
import {
|
||||
fireNodeTitleChange,
|
||||
provideLoopInputsVariablesEffect,
|
||||
provideLoopOutputsVariablesEffect,
|
||||
} from '@/node-registries/common/effects';
|
||||
|
||||
import {
|
||||
BatchInputNameValidator,
|
||||
BatchInputValueValidator,
|
||||
BatchOutputNameValidator,
|
||||
} from './validators';
|
||||
import { type FormData } from './types';
|
||||
import { BatchFormRender } from './form';
|
||||
import { transformOnInit, transformOnSubmit } from './data-transformer';
|
||||
import { BatchPath } from './constants';
|
||||
|
||||
export const BATCH_FORM_META: FormMetaV2<FormData> = {
|
||||
// 节点表单渲染
|
||||
render: () => <BatchFormRender />,
|
||||
|
||||
// 验证触发时机
|
||||
validateTrigger: ValidateTrigger.onChange,
|
||||
|
||||
// 验证规则
|
||||
validate: {
|
||||
nodeMeta: nodeMetaValidate,
|
||||
[`${BatchPath.Inputs}.*.name`]: BatchInputNameValidator,
|
||||
[`${BatchPath.Inputs}.*.input`]: BatchInputValueValidator,
|
||||
[`${BatchPath.Outputs}.*.name`]: BatchOutputNameValidator,
|
||||
[`${BatchPath.Outputs}.*.input`]: BatchInputValueValidator,
|
||||
},
|
||||
|
||||
// 副作用管理
|
||||
effect: {
|
||||
nodeMeta: fireNodeTitleChange,
|
||||
inputs: provideLoopInputsVariablesEffect,
|
||||
outputs: provideLoopOutputsVariablesEffect,
|
||||
},
|
||||
|
||||
// 节点后端数据 -> 前端表单数据
|
||||
formatOnInit: transformOnInit,
|
||||
|
||||
// 前端表单数据 -> 节点后端数据
|
||||
formatOnSubmit: transformOnSubmit,
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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 { PrivateScopeProvider } from '@coze-workflow/variable';
|
||||
|
||||
import { NodeConfigForm } from '@/node-registries/common/components';
|
||||
|
||||
import {
|
||||
BatchConcurrentSizeField,
|
||||
BatchInputsField,
|
||||
BatchOutputsField,
|
||||
BatchSettingsSection,
|
||||
BatchSizeField,
|
||||
} from './fields';
|
||||
import { BatchPath } from './constants';
|
||||
|
||||
export const BatchFormRender = () => (
|
||||
<NodeConfigForm>
|
||||
<PrivateScopeProvider>
|
||||
<BatchSettingsSection>
|
||||
<BatchConcurrentSizeField name={BatchPath.ConcurrentSize} />
|
||||
<BatchSizeField name={BatchPath.BatchSize} />
|
||||
</BatchSettingsSection>
|
||||
<BatchInputsField name={BatchPath.Inputs} />
|
||||
</PrivateScopeProvider>
|
||||
<BatchOutputsField name={BatchPath.Outputs} />
|
||||
</NodeConfigForm>
|
||||
);
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { BATCH_NODE_REGISTRY } from './node-registry';
|
||||
export { BatchContent } from './node-content';
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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 { PrivateScopeProvider } from '@coze-workflow/variable';
|
||||
|
||||
import {
|
||||
InputParameters,
|
||||
Outputs,
|
||||
} from '@/components/node-render/node-render-new/fields';
|
||||
|
||||
import { BatchPort } from './batch-content';
|
||||
|
||||
export const BatchContent = () => (
|
||||
<PrivateScopeProvider>
|
||||
<InputParameters />
|
||||
<Outputs />
|
||||
<BatchPort />
|
||||
</PrivateScopeProvider>
|
||||
);
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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 {
|
||||
WorkflowNodeEntity,
|
||||
WorkflowSubCanvas,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
import {
|
||||
DEFAULT_NODE_META_PATH,
|
||||
DEFAULT_OUTPUTS_PATH,
|
||||
} from '@coze-workflow/nodes';
|
||||
import {
|
||||
StandardNodeType,
|
||||
type WorkflowNodeJSON,
|
||||
type WorkflowNodeRegistry,
|
||||
} from '@coze-workflow/base';
|
||||
|
||||
import { type NodeTestMeta } from '@/test-run-kit';
|
||||
|
||||
import { test } from './node-test';
|
||||
import { BATCH_FORM_META } from './form-meta';
|
||||
import { BatchPath, BatchSize } from './constants';
|
||||
import { createBatchFunction, getBatchFunctionID } from './batch-function';
|
||||
|
||||
export const BATCH_NODE_REGISTRY: WorkflowNodeRegistry<NodeTestMeta> = {
|
||||
type: StandardNodeType.Batch,
|
||||
meta: {
|
||||
nodeDTOType: StandardNodeType.Batch,
|
||||
style: {
|
||||
width: BatchSize.width,
|
||||
},
|
||||
size: BatchSize,
|
||||
nodeMetaPath: DEFAULT_NODE_META_PATH,
|
||||
outputsPath: DEFAULT_OUTPUTS_PATH,
|
||||
inputParametersPath: BatchPath.Inputs, // 入参路径,试运行等功能依赖该路径提取参数
|
||||
useDynamicPort: true,
|
||||
defaultPorts: [
|
||||
{ type: 'input' },
|
||||
{ type: 'output', portID: 'batch-output' },
|
||||
{ type: 'output', portID: 'batch-output-to-function', disabled: true },
|
||||
],
|
||||
subCanvas: (node: WorkflowNodeEntity): WorkflowSubCanvas | undefined => {
|
||||
const parentNode = node;
|
||||
const canvasNodeID = getBatchFunctionID(parentNode.id);
|
||||
const canvasNode = node.document.getNode(canvasNodeID);
|
||||
if (!canvasNode) {
|
||||
return undefined;
|
||||
}
|
||||
const subCanvas: WorkflowSubCanvas = {
|
||||
isCanvas: false,
|
||||
parentNode,
|
||||
canvasNode,
|
||||
};
|
||||
return subCanvas;
|
||||
},
|
||||
test,
|
||||
helpLink: '/open/docs/guides/batch_node',
|
||||
},
|
||||
variablesMeta: {
|
||||
outputsPathList: [],
|
||||
inputsPathList: [
|
||||
BatchPath.Inputs,
|
||||
// 'outputs', // WARNING: 加上 outputs 会导致这一数据清空
|
||||
],
|
||||
},
|
||||
formMeta: BATCH_FORM_META,
|
||||
onCreate(node, json) {
|
||||
createBatchFunction(node, json as unknown as WorkflowNodeJSON);
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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 { I18n } from '@coze-arch/i18n';
|
||||
import { FlowNodeFormData } from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import {
|
||||
generateParametersToProperties,
|
||||
getRelatedInfo,
|
||||
generateEnvToRelatedContextProperties,
|
||||
} from '@/test-run-kit';
|
||||
import { type NodeTestMeta } from '@/test-run-kit';
|
||||
|
||||
export const test: NodeTestMeta = {
|
||||
async generateRelatedContext(_, context) {
|
||||
const { isInProject, workflowId, spaceId } = context;
|
||||
if (isInProject) {
|
||||
return {};
|
||||
}
|
||||
const related = await getRelatedInfo({ workflowId, spaceId });
|
||||
return generateEnvToRelatedContextProperties(related);
|
||||
},
|
||||
generateFormSettingProperties(node) {
|
||||
const { formModel } = node.getData(FlowNodeFormData);
|
||||
const data = formModel.getFormItemValueByPath('/inputs');
|
||||
return generateParametersToProperties(
|
||||
[
|
||||
{
|
||||
name: 'concurrentSize',
|
||||
title: I18n.t('workflow_maximum_parallel_runs'),
|
||||
input: data.concurrentSize,
|
||||
},
|
||||
{
|
||||
name: 'batchSize',
|
||||
title: I18n.t('workflow_maximum_run_count'),
|
||||
input: data.batchSize,
|
||||
},
|
||||
],
|
||||
{ node },
|
||||
);
|
||||
},
|
||||
generateFormInputProperties(node) {
|
||||
const formData = node
|
||||
.getData(FlowNodeFormData)
|
||||
.formModel.getFormItemValueByPath('/');
|
||||
const parameters = formData?.inputs?.inputParameters;
|
||||
return generateParametersToProperties(parameters, { node });
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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 InputValueVO } from '@coze-workflow/base';
|
||||
|
||||
export interface FormData {
|
||||
inputs: { inputParameters: InputValueVO[] };
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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 { get } from 'lodash-es';
|
||||
import { type InputValueVO } from '@coze-workflow/base';
|
||||
|
||||
import { BatchPath } from '../../constants';
|
||||
|
||||
export const getBatchInputNames = ({ value, formValues }): string[] => {
|
||||
const batchInputs: InputValueVO[] = get(formValues, BatchPath.Inputs) ?? [];
|
||||
return batchInputs.map(input => input.name).filter(Boolean) as string[];
|
||||
};
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/naming-convention*/
|
||||
import { createNodeInputNameValidate } from '@/nodes-v2/components/node-input-name/validate';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { getBatchInputNames } from './get-batch-input-names';
|
||||
|
||||
export const BatchInputNameValidator = createNodeInputNameValidate({
|
||||
getNames: getBatchInputNames,
|
||||
invalidValues: {
|
||||
index: I18n.t('workflow_loop_name_no_index_wrong'),
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/naming-convention*/
|
||||
import { createValueExpressionInputValidate } from '@/node-registries/common/validators';
|
||||
|
||||
export const BatchInputValueValidator = createValueExpressionInputValidate({
|
||||
required: true,
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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 { get } from 'lodash-es';
|
||||
import { type InputValueVO } from '@coze-workflow/base';
|
||||
|
||||
import { BatchPath } from '../../constants';
|
||||
|
||||
export const getBatchOutputNames = ({ value, formValues }): string[] => {
|
||||
const batchOutputs: InputValueVO[] = get(formValues, BatchPath.Outputs) ?? [];
|
||||
return batchOutputs.map(input => input.name).filter(Boolean) as string[];
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/naming-convention*/
|
||||
import { createNodeInputNameValidate } from '@/nodes-v2/components/node-input-name/validate';
|
||||
import { getBatchOutputNames } from './get-batch-output-names';
|
||||
|
||||
export const BatchOutputNameValidator = createNodeInputNameValidate({
|
||||
getNames: getBatchOutputNames,
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { BatchInputNameValidator } from './batch-input-name';
|
||||
export { BatchOutputNameValidator } from './batch-output-name';
|
||||
export { BatchInputValueValidator } from './batch-input-value';
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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 NodeDataDTO } from '@coze-workflow/base';
|
||||
|
||||
import { type FormData } from './types';
|
||||
|
||||
/**
|
||||
* 节点后端数据 -> 前端表单数据
|
||||
*/
|
||||
export const transformOnInit = (value: NodeDataDTO) => value;
|
||||
|
||||
/**
|
||||
* 前端表单数据 -> 节点后端数据
|
||||
* @param value
|
||||
* @returns
|
||||
*/
|
||||
export const transformOnSubmit = (value: FormData): NodeDataDTO =>
|
||||
value as unknown as NodeDataDTO;
|
||||
@@ -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 {
|
||||
ValidateTrigger,
|
||||
type FormMetaV2,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { nodeMetaValidate } from '@/nodes-v2/materials/node-meta-validate';
|
||||
import { fireNodeTitleChange } from '@/node-registries/common/effects';
|
||||
|
||||
import { type FormData } from './types';
|
||||
import { FormRender } from './form';
|
||||
import { transformOnInit, transformOnSubmit } from './data-transformer';
|
||||
|
||||
export const BREAK_FORM_META: FormMetaV2<FormData> = {
|
||||
// 节点表单渲染
|
||||
render: () => <FormRender />,
|
||||
|
||||
// 验证触发时机
|
||||
validateTrigger: ValidateTrigger.onChange,
|
||||
|
||||
// 验证规则
|
||||
validate: {
|
||||
nodeMeta: nodeMetaValidate,
|
||||
},
|
||||
|
||||
// 副作用管理
|
||||
effect: {
|
||||
nodeMeta: fireNodeTitleChange,
|
||||
},
|
||||
|
||||
// 节点后端数据 -> 前端表单数据
|
||||
formatOnInit: transformOnInit,
|
||||
|
||||
// 前端表单数据 -> 节点后端数据
|
||||
formatOnSubmit: transformOnSubmit,
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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 { NodeConfigForm } from '@/node-registries/common/components';
|
||||
|
||||
export const FormRender = () => <NodeConfigForm />;
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { BREAK_NODE_REGISTRY } from './node-registry';
|
||||
export { BreakContent } from './node-content';
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export function BreakContent() {
|
||||
return <></>;
|
||||
}
|
||||
@@ -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 { DEFAULT_NODE_META_PATH } from '@coze-workflow/nodes';
|
||||
import {
|
||||
StandardNodeType,
|
||||
type WorkflowNodeRegistry,
|
||||
} from '@coze-workflow/base';
|
||||
|
||||
import { BREAK_FORM_META } from './form-meta';
|
||||
|
||||
export const BREAK_NODE_REGISTRY: WorkflowNodeRegistry = {
|
||||
type: StandardNodeType.Break,
|
||||
meta: {
|
||||
isNodeEnd: true,
|
||||
hideTest: true,
|
||||
nodeDTOType: StandardNodeType.Break,
|
||||
defaultPorts: [{ type: 'input' }],
|
||||
size: { width: 360, height: 67.86 },
|
||||
nodeMetaPath: DEFAULT_NODE_META_PATH,
|
||||
},
|
||||
formMeta: BREAK_FORM_META,
|
||||
getOutputPoints: () => [], // Break 节点没有输出
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-empty-interface */
|
||||
export interface FormData {}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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 { useCurrentEntity } from '@flowgram-adapter/free-layout-editor';
|
||||
import { type InputValueVO, type OutputValueVO } from '@coze-workflow/base';
|
||||
import { ConfigProvider } from '@coze-arch/coze-design';
|
||||
|
||||
import { useReadonly } from '@/nodes-v2/hooks/use-readonly';
|
||||
import { type CodeEditorValue } from '@/form-extensions/setters/code/types';
|
||||
import { type InputParams } from '@/form-extensions/setters/code/hooks/use-ide-input-output-type';
|
||||
import { CodeSetterContext } from '@/form-extensions/setters/code/context';
|
||||
import { CodeEditorWithBizIDE } from '@/form-extensions/setters/code/code-with-biz-ide';
|
||||
import { useField, withField } from '@/form';
|
||||
|
||||
export const CodeField = withField(
|
||||
({
|
||||
tooltip,
|
||||
outputParams,
|
||||
inputParams,
|
||||
}: {
|
||||
tooltip?: string;
|
||||
outputParams?: OutputValueVO[];
|
||||
inputParams?: InputValueVO[];
|
||||
}) => {
|
||||
const { value, onChange, errors } = useField<CodeEditorValue>();
|
||||
const readonly = useReadonly();
|
||||
|
||||
const feedbackText = errors?.[0]?.message || '';
|
||||
const feedbackStatus = feedbackText ? 'error' : undefined;
|
||||
const flowNodeEntity = useCurrentEntity();
|
||||
|
||||
return (
|
||||
<ConfigProvider getPopupContainer={() => document.body}>
|
||||
<CodeSetterContext.Provider
|
||||
value={{
|
||||
readonly,
|
||||
flowNodeEntity,
|
||||
}}
|
||||
>
|
||||
<CodeEditorWithBizIDE
|
||||
feedbackStatus={feedbackStatus}
|
||||
feedbackText={feedbackText}
|
||||
inputParams={inputParams as InputParams}
|
||||
onChange={onChange}
|
||||
outputParams={outputParams}
|
||||
outputPath={'/outputs'}
|
||||
tooltip={tooltip}
|
||||
value={value}
|
||||
/>
|
||||
</CodeSetterContext.Provider>
|
||||
</ConfigProvider>
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { CodeField } from './code-field';
|
||||
@@ -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 { nanoid } from 'nanoid';
|
||||
import { ViewVariableType } from '@coze-workflow/variable';
|
||||
|
||||
// 路径
|
||||
export const INPUT_PATH = 'inputParameters';
|
||||
export const CODE_PATH = 'codeParams';
|
||||
export const OUTPUT_PATH = 'outputs';
|
||||
|
||||
// 默认值
|
||||
export const DEFAULT_OUTPUTS = [
|
||||
{
|
||||
key: nanoid(),
|
||||
name: 'key0',
|
||||
type: ViewVariableType.String,
|
||||
},
|
||||
{
|
||||
key: nanoid(),
|
||||
name: 'key1',
|
||||
type: ViewVariableType.ArrayString,
|
||||
},
|
||||
{
|
||||
key: nanoid(),
|
||||
name: 'key2',
|
||||
type: ViewVariableType.Object,
|
||||
children: [
|
||||
{
|
||||
key: nanoid(),
|
||||
name: 'key21',
|
||||
type: ViewVariableType.String,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export const DEFAULT_INPUTS = [{ name: 'input' }];
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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 NodeContext } from '@flowgram-adapter/free-layout-editor';
|
||||
import { type NodeDataDTO } from '@coze-workflow/base';
|
||||
|
||||
import { getDefaultValue } from '@/form-extensions/setters/code/defaults';
|
||||
|
||||
import { type FormData } from './types';
|
||||
import { DEFAULT_INPUTS, DEFAULT_OUTPUTS } from './constants';
|
||||
|
||||
/**
|
||||
* 节点后端数据 -> 前端表单数据
|
||||
*/
|
||||
export const transformOnInit = (
|
||||
value: NodeDataDTO | undefined,
|
||||
context: NodeContext,
|
||||
) => {
|
||||
const { globalState } = context.playgroundContext;
|
||||
const { isBindDouyin } = globalState;
|
||||
const defaultCodeParams = getDefaultValue({ isBindDouyin });
|
||||
// 初始值设置
|
||||
const initValue = value || {
|
||||
inputs: {
|
||||
inputParameters: DEFAULT_INPUTS,
|
||||
...defaultCodeParams,
|
||||
},
|
||||
outputs: DEFAULT_OUTPUTS,
|
||||
};
|
||||
|
||||
const { inputs = {}, ...others } = initValue;
|
||||
return {
|
||||
...others,
|
||||
inputParameters: inputs.inputParameters,
|
||||
codeParams: {
|
||||
code: inputs.code,
|
||||
language: inputs.language,
|
||||
},
|
||||
nodeMeta: value?.nodeMeta,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 前端表单数据 -> 节点后端数据
|
||||
* @param value
|
||||
* @returns
|
||||
*/
|
||||
export const transformOnSubmit = (value: FormData) => ({
|
||||
nodeMeta: value.nodeMeta,
|
||||
inputs: {
|
||||
inputParameters: value.inputParameters,
|
||||
...value.codeParams,
|
||||
},
|
||||
outputs: value.outputs,
|
||||
});
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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 {
|
||||
ValidateTrigger,
|
||||
type FormMetaV2,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { nodeMetaValidate } from '@/nodes-v2/materials/node-meta-validate';
|
||||
import {
|
||||
fireNodeTitleChange,
|
||||
provideNodeOutputVariablesEffect,
|
||||
} from '@/node-registries/common/effects';
|
||||
|
||||
import { outputTreeMetaValidator } from '../common/fields/outputs';
|
||||
import { createCodeInputsValidator } from './validators/create-code-inputs-validator';
|
||||
import { codeEmptyValidator } from './validators/code-empty-validator';
|
||||
import { type FormData } from './types';
|
||||
import { FormRender } from './form';
|
||||
import { transformOnInit, transformOnSubmit } from './data-transformer';
|
||||
import { CODE_PATH, OUTPUT_PATH } from './constants';
|
||||
|
||||
export const CODE_FORM_META: FormMetaV2<FormData> = {
|
||||
// 节点表单渲染
|
||||
render: () => <FormRender />,
|
||||
|
||||
// 验证触发时机
|
||||
validateTrigger: ValidateTrigger.onChange,
|
||||
|
||||
// 验证规则
|
||||
validate: {
|
||||
nodeMeta: nodeMetaValidate,
|
||||
...createCodeInputsValidator(),
|
||||
[CODE_PATH]: codeEmptyValidator,
|
||||
[OUTPUT_PATH]: outputTreeMetaValidator,
|
||||
},
|
||||
|
||||
// 副作用管理
|
||||
effect: {
|
||||
nodeMeta: fireNodeTitleChange,
|
||||
outputs: provideNodeOutputVariablesEffect,
|
||||
},
|
||||
|
||||
// 节点后端数据 -> 前端表单数据
|
||||
formatOnInit: transformOnInit,
|
||||
|
||||
// 前端表单数据 -> 节点后端数据
|
||||
formatOnSubmit: transformOnSubmit,
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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 { I18n } from '@coze-arch/i18n';
|
||||
import { useForm } from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { NodeConfigForm } from '@/node-registries/common/components';
|
||||
|
||||
import { OutputsField, InputsParametersField } from '../common/fields';
|
||||
import { CODE_PATH, INPUT_PATH, OUTPUT_PATH } from './constants';
|
||||
import { CodeField } from './components';
|
||||
|
||||
export const FormRender = () => {
|
||||
const form = useForm();
|
||||
return (
|
||||
<NodeConfigForm>
|
||||
<InputsParametersField
|
||||
name={INPUT_PATH}
|
||||
tooltip={I18n.t('workflow_detail_code_input_tooltip')}
|
||||
isTree={true}
|
||||
/>
|
||||
|
||||
<CodeField
|
||||
name={CODE_PATH}
|
||||
tooltip={I18n.t('workflow_detail_code_code_tooltip')}
|
||||
inputParams={form.getValueIn(INPUT_PATH)}
|
||||
outputParams={form.getValueIn(OUTPUT_PATH)}
|
||||
hasFeedback={false}
|
||||
/>
|
||||
|
||||
<OutputsField
|
||||
title={I18n.t('workflow_detail_node_output')}
|
||||
tooltip={I18n.t('workflow_detail_code_output_tooltip')}
|
||||
jsonImport={false}
|
||||
id="code-node-outputs"
|
||||
name={OUTPUT_PATH}
|
||||
hasFeedback={false}
|
||||
/>
|
||||
</NodeConfigForm>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { CODE_NODE_REGISTRY } from './node-registry';
|
||||
export { CodeContent } from './node-content';
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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 { InputParameters, Outputs } from '../common/components';
|
||||
|
||||
export function CodeContent() {
|
||||
return (
|
||||
<>
|
||||
<InputParameters />
|
||||
<Outputs />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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 {
|
||||
DEFAULT_NODE_META_PATH,
|
||||
DEFAULT_NODE_SIZE,
|
||||
DEFAULT_OUTPUTS_PATH,
|
||||
} from '@coze-workflow/nodes';
|
||||
import {
|
||||
StandardNodeType,
|
||||
type WorkflowNodeRegistry,
|
||||
} from '@coze-workflow/base';
|
||||
|
||||
import { type NodeTestMeta } from '@/test-run-kit';
|
||||
|
||||
import { test } from './node-test';
|
||||
import { CODE_FORM_META } from './form-meta';
|
||||
import { INPUT_PATH } from './constants';
|
||||
|
||||
export const CODE_NODE_REGISTRY: WorkflowNodeRegistry<NodeTestMeta> = {
|
||||
type: StandardNodeType.Code,
|
||||
meta: {
|
||||
nodeDTOType: StandardNodeType.Code,
|
||||
size: DEFAULT_NODE_SIZE,
|
||||
style: {
|
||||
width: 484,
|
||||
},
|
||||
test,
|
||||
nodeMetaPath: DEFAULT_NODE_META_PATH,
|
||||
outputsPath: DEFAULT_OUTPUTS_PATH,
|
||||
inputParametersPath: INPUT_PATH, // 入参路径,试运行等功能依赖该路径提取参数
|
||||
enableCopilotGenerateTestNodeForm: true,
|
||||
helpLink: '/open/docs/guides/code_node',
|
||||
},
|
||||
formMeta: CODE_FORM_META,
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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 { FlowNodeFormData } from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { generateParametersToProperties } from '@/test-run-kit';
|
||||
import { type NodeTestMeta } from '@/test-run-kit';
|
||||
|
||||
export const test: NodeTestMeta = {
|
||||
generateFormInputProperties(node) {
|
||||
const formData = node
|
||||
.getData(FlowNodeFormData)
|
||||
.formModel.getFormItemValueByPath('/');
|
||||
const parameters = formData?.inputParameters;
|
||||
return generateParametersToProperties(parameters, { node });
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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 OutputValueVO,
|
||||
type InputValueVO,
|
||||
type NodeDataDTO,
|
||||
} from '@coze-workflow/base';
|
||||
|
||||
import { type CodeEditorValue } from '@/form-extensions/setters/code/types';
|
||||
|
||||
export interface FormData {
|
||||
inputParameters: InputValueVO[];
|
||||
nodeMeta: NodeDataDTO['nodeMeta'];
|
||||
outputs: OutputValueVO[];
|
||||
codeParams: CodeEditorValue;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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 { I18n } from '@coze-arch/i18n';
|
||||
import { type Validate } from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
export const codeEmptyValidator: Validate = ({ value }) => {
|
||||
const code = value?.code;
|
||||
if (!code) {
|
||||
return I18n.t('workflow_running_results_error_code');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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 Validate } from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { createInputTreeValidator } from '../../common/validators/create-input-tree-validator';
|
||||
|
||||
export function createCodeInputsValidator(): { [key: string]: Validate } {
|
||||
return {
|
||||
inputParameters: createInputTreeValidator(),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/naming-convention -- todo */
|
||||
/** 备注默认尺寸 */
|
||||
export const CommentDefaultSize = {
|
||||
width: 240,
|
||||
height: 150,
|
||||
};
|
||||
|
||||
/** 备注默认值 */
|
||||
export const CommentDefaultNote = JSON.stringify([
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
]);
|
||||
|
||||
export const CommentDefaultSchemaType = 'slate';
|
||||
|
||||
export const CommentDefaultVO = {
|
||||
schemaType: CommentDefaultSchemaType,
|
||||
note: CommentDefaultNote,
|
||||
size: CommentDefaultSize,
|
||||
};
|
||||
|
||||
export const CommentDefaultDTO = {
|
||||
inputs: {
|
||||
schemaType: CommentDefaultSchemaType,
|
||||
note: CommentDefaultNote,
|
||||
},
|
||||
size: CommentDefaultSize,
|
||||
};
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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 from 'react';
|
||||
|
||||
import {
|
||||
StandardNodeType,
|
||||
type WorkflowNodeRegistry,
|
||||
} from '@coze-workflow/base';
|
||||
|
||||
import type { ICommentNodeVO, ICommentNodeDTO } from './type';
|
||||
import {
|
||||
CommentDefaultDTO,
|
||||
CommentDefaultNote,
|
||||
CommentDefaultVO,
|
||||
CommentDefaultSize,
|
||||
CommentDefaultSchemaType,
|
||||
} from './constant';
|
||||
|
||||
export const COMMENT_NODE_REGISTRY: WorkflowNodeRegistry = {
|
||||
type: StandardNodeType.Comment,
|
||||
meta: {
|
||||
disableSideSheet: true,
|
||||
nodeDTOType: StandardNodeType.Comment,
|
||||
renderKey: StandardNodeType.Comment,
|
||||
size: {
|
||||
width: 240,
|
||||
height: 150,
|
||||
},
|
||||
},
|
||||
formMeta: {
|
||||
render: () => <></>,
|
||||
formatOnInit: (
|
||||
value: ICommentNodeDTO = CommentDefaultDTO,
|
||||
): ICommentNodeVO => {
|
||||
const { inputs, ...rest } = value;
|
||||
return {
|
||||
...rest,
|
||||
schemaType: inputs?.schemaType ?? CommentDefaultSchemaType, // 默认使用 slate 格式,后续考虑支持其他格式
|
||||
note: inputs?.note ?? CommentDefaultNote,
|
||||
size: value.size ?? CommentDefaultSize,
|
||||
};
|
||||
},
|
||||
formatOnSubmit(value: ICommentNodeVO = CommentDefaultVO): ICommentNodeDTO {
|
||||
const { note, schemaType, ...rest } = value;
|
||||
return {
|
||||
...rest,
|
||||
inputs: {
|
||||
schemaType: schemaType ?? CommentDefaultSchemaType, // 默认使用 slate 格式,后续考虑支持其他格式
|
||||
note: note ?? CommentDefaultNote,
|
||||
},
|
||||
size: value.size ?? CommentDefaultSize,
|
||||
};
|
||||
},
|
||||
},
|
||||
getInputPoints: () => [], // Comment 节点没有输入
|
||||
getOutputPoints: () => [], // Comment 节点没有输出
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export interface ICommentNodeVO {
|
||||
schemaType: string;
|
||||
note: string;
|
||||
size: {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ICommentNodeDTO {
|
||||
inputs: {
|
||||
schemaType: string;
|
||||
note: string;
|
||||
};
|
||||
size: {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* 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 { useCallback, useRef, useState } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { type FlowNodeEntity } from '@flowgram-adapter/free-layout-editor';
|
||||
import {
|
||||
workflowApi,
|
||||
CopilotType,
|
||||
ValueExpression,
|
||||
ValueExpressionType,
|
||||
ViewVariableType,
|
||||
} from '@coze-workflow/base';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozStopCircle, IconCozApply } from '@coze-arch/coze-design/icons';
|
||||
import {
|
||||
AIButton,
|
||||
Button,
|
||||
IconButton,
|
||||
Input,
|
||||
Popconfirm,
|
||||
} from '@coze-arch/coze-design';
|
||||
|
||||
import { useRefInput } from '@/hooks/use-ref-input';
|
||||
import { useGlobalState } from '@/hooks';
|
||||
|
||||
import style from './index.module.less';
|
||||
|
||||
interface AICronjobSelectProps {
|
||||
value?: ValueExpression;
|
||||
onChange: (v: ValueExpression | undefined) => void;
|
||||
readonly?: boolean;
|
||||
node: FlowNodeEntity;
|
||||
needRefInput?: boolean;
|
||||
hasError?: boolean;
|
||||
}
|
||||
|
||||
const Suffix = ({ onChange }: { onChange: (v: string) => void }) => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [prompt, setPrompt] = useState('');
|
||||
const [cronjob, setCronjob] = useState('');
|
||||
const [aiGenerating, setAIGenerating] = useState(false);
|
||||
const cancelRequest = useRef<(reason?: unknown) => void>();
|
||||
|
||||
const { spaceId, projectId, workflowId } = useGlobalState();
|
||||
return (
|
||||
<>
|
||||
<Popconfirm
|
||||
className="w-[330px]"
|
||||
title={I18n.t('workflow_start_trigger_cron_ai', {}, '使用 AI 生成')}
|
||||
trigger="custom"
|
||||
stopPropagation
|
||||
onClickOutSide={() => {
|
||||
setVisible(false);
|
||||
}}
|
||||
content={
|
||||
<div className="mt-[12px] flex flex-col gap-[12px] text-[12px]">
|
||||
<div className="flex flex-col gap-[4px] p-[8px] rounded-mini coz-mg-hglt">
|
||||
{/* <div className="font-medium coz-fg-plus">Sample i18n</div> */}
|
||||
<div className="coz-fg-primary">
|
||||
{I18n.t(
|
||||
'workflow_trigger_cron_gen_sample_placeholder',
|
||||
{},
|
||||
'您可以在提示词中用自然语言如“每天18点”,将会生成对应的Cron表达式 0 18 * * * 表示每天 18 点执行。',
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-[4px]">
|
||||
<div className="flex justify-between">
|
||||
<div className="text-[14px] font-medium coz-fg-plus">
|
||||
{I18n.t('Imageflow_prompt', {}, 'Prompt')}
|
||||
</div>
|
||||
{!aiGenerating ? (
|
||||
<AIButton
|
||||
size="small"
|
||||
disabled={!prompt}
|
||||
onClick={async () => {
|
||||
try {
|
||||
setAIGenerating(true);
|
||||
|
||||
const rs = await workflowApi.CopilotGenerate({
|
||||
space_id: spaceId,
|
||||
project_id: projectId ?? '',
|
||||
copilot_type: CopilotType.CRONTAB,
|
||||
query: prompt,
|
||||
workflow_id: workflowId,
|
||||
});
|
||||
|
||||
setCronjob(rs?.data?.content ?? '');
|
||||
} finally {
|
||||
setAIGenerating(false);
|
||||
}
|
||||
}}
|
||||
color="aihglt"
|
||||
>
|
||||
{I18n.t('workflow_start_trigger_cron_gen', {}, '生成')}
|
||||
</AIButton>
|
||||
) : (
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => {
|
||||
try {
|
||||
cancelRequest.current?.('cancel');
|
||||
} finally {
|
||||
setAIGenerating(false);
|
||||
}
|
||||
}}
|
||||
icon={<IconCozStopCircle />}
|
||||
color="aihglt"
|
||||
>
|
||||
{I18n.t('workflow_start_trigger_cron_gen_stop', {}, '停止')}
|
||||
</IconButton>
|
||||
)}
|
||||
</div>
|
||||
<Input
|
||||
size="small"
|
||||
value={prompt}
|
||||
placeholder={I18n.t(
|
||||
'workflow_trigger_cron_gen_prompt_placeholder',
|
||||
{},
|
||||
'示例:每天18点',
|
||||
)}
|
||||
onChange={setPrompt}
|
||||
></Input>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-[4px]">
|
||||
<div className="text-[14px] font-medium coz-fg-plus">
|
||||
{I18n.t(
|
||||
'workflow_start_trigger_cron_generated',
|
||||
{},
|
||||
'生成的 Cron 表达式',
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-row gap-[8px]">
|
||||
<Input
|
||||
loading={aiGenerating}
|
||||
size="small"
|
||||
disabled
|
||||
value={cronjob}
|
||||
onChange={setCronjob}
|
||||
></Input>
|
||||
<Button
|
||||
size="small"
|
||||
loading={aiGenerating}
|
||||
disabled={!cronjob}
|
||||
onClick={() => {
|
||||
if (cronjob) {
|
||||
onChange(cronjob);
|
||||
setVisible(false);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{I18n.t('workflow_start_trigger_cron_fillin', {}, '填入')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
visible={visible}
|
||||
onVisibleChange={v => {
|
||||
setVisible(v);
|
||||
}}
|
||||
onCancel={() => {
|
||||
setVisible(false);
|
||||
}}
|
||||
okText={''}
|
||||
cancelText={I18n.t('workflow_start_trigger_cron_cancel', {}, '取消')}
|
||||
>
|
||||
<div>
|
||||
<AIButton
|
||||
size="mini"
|
||||
onClick={() => setVisible(true)}
|
||||
color="aihglt"
|
||||
onlyIcon
|
||||
/>
|
||||
</div>
|
||||
</Popconfirm>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const AICronjobSelect = ({
|
||||
value,
|
||||
onChange: _onChange,
|
||||
readonly,
|
||||
node,
|
||||
needRefInput = false,
|
||||
hasError,
|
||||
}: AICronjobSelectProps) => {
|
||||
const onLiteralChange = useCallback(
|
||||
(v: string) => {
|
||||
_onChange({
|
||||
type: ValueExpressionType.LITERAL,
|
||||
content: v,
|
||||
});
|
||||
},
|
||||
[_onChange],
|
||||
);
|
||||
|
||||
const isRef = value?.type && ValueExpression.isRef(value);
|
||||
|
||||
const { renderVariableSelect, renderVariableDisplay } = useRefInput({
|
||||
value,
|
||||
onChange: _onChange,
|
||||
readonly,
|
||||
node,
|
||||
style: { width: '100%' },
|
||||
disabledTypes: ViewVariableType.getComplement([ViewVariableType.String]),
|
||||
});
|
||||
return (
|
||||
<div className="w-full flex flex-row gap-[4px]">
|
||||
{isRef ? (
|
||||
renderVariableDisplay({ needWrapper: true })
|
||||
) : (
|
||||
<Input
|
||||
error={hasError}
|
||||
size="small"
|
||||
disabled={readonly}
|
||||
className={classNames(['w-full flex-1', style.input])}
|
||||
value={value?.content as string}
|
||||
placeholder={I18n.t(
|
||||
'workflow_start_trigger_cron_ai_sample',
|
||||
{},
|
||||
'示例:您可以填写 cron 表达式。例如:0 18 * * * 表示每天 18 点执行。',
|
||||
)}
|
||||
onChange={onLiteralChange}
|
||||
suffix={
|
||||
<div className="flex flex-row gap-[4px]">
|
||||
<Suffix onChange={onLiteralChange} />
|
||||
{needRefInput ? (
|
||||
<div>
|
||||
{renderVariableSelect(
|
||||
<IconButton
|
||||
size="mini"
|
||||
color="secondary"
|
||||
icon={<IconCozApply className="text-[16px]" />}
|
||||
/>,
|
||||
)}
|
||||
</div>
|
||||
) : undefined}
|
||||
</div>
|
||||
}
|
||||
></Input>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* 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, { useRef, type ReactNode, useCallback } from 'react';
|
||||
|
||||
import { isUndefined } from 'lodash-es';
|
||||
import CronGenerator from 'cron-string-generator';
|
||||
import {
|
||||
type ValueExpression,
|
||||
ValueExpressionType,
|
||||
} from '@coze-workflow/base/types';
|
||||
import { REPORT_EVENTS as ReportEventNames } from '@coze-arch/report-events';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { CustomError } from '@coze-arch/bot-error';
|
||||
import { Cascader, type CascaderData } from '@coze-arch/coze-design';
|
||||
|
||||
const hoursSize = 24;
|
||||
const padStart = 2;
|
||||
const hoursLeaf: CascaderData[] = Array.from(new Array(hoursSize).keys()).map(
|
||||
i => ({
|
||||
label: i.toString().padStart(padStart, '0').concat(':00'),
|
||||
value: i,
|
||||
isLeaf: true,
|
||||
}),
|
||||
);
|
||||
const weekDaysNode: () => CascaderData[] = () => {
|
||||
const size = 7;
|
||||
return Array.from({ length: size }).map((item, index) => ({
|
||||
label: I18n.t('bot_task_preset_day_of_week', { day: index }),
|
||||
value: index,
|
||||
children: hoursLeaf,
|
||||
}));
|
||||
};
|
||||
|
||||
const monthDaysNode: () => CascaderData[] = () => {
|
||||
const size = 31;
|
||||
return Array.from({ length: size }).map((item, index) => ({
|
||||
label: I18n.t('bot_task_preset_day_of_month', { day: index + 1 }),
|
||||
value: index + 1,
|
||||
children: hoursLeaf,
|
||||
}));
|
||||
};
|
||||
|
||||
const intervalDaysNode: () => CascaderData[] = () => {
|
||||
const size = 5;
|
||||
const offset = 2;
|
||||
return Array.from({ length: size }).map((item, index) => ({
|
||||
label: I18n.t('bot_task_preset_day_of_month', { day: index + offset }),
|
||||
value: index + offset,
|
||||
children: hoursLeaf,
|
||||
}));
|
||||
};
|
||||
|
||||
const triggeredEveryday = () => I18n.t('bot_task_preset_triggered_everyday');
|
||||
const triggeredEveryweek = () => I18n.t('bot_task_preset_triggered_everyweek');
|
||||
const triggeredMonthly = () => I18n.t('bot_task_preset_triggered_monthly');
|
||||
const triggeredInterval = () => I18n.t('bot_task_preset_triggered_interval');
|
||||
|
||||
const treeData: () => CascaderData[] = () => [
|
||||
{
|
||||
label: triggeredEveryday(),
|
||||
value: 'daily',
|
||||
children: hoursLeaf,
|
||||
},
|
||||
{
|
||||
label: triggeredEveryweek(),
|
||||
value: 'weekly',
|
||||
children: weekDaysNode(),
|
||||
},
|
||||
{
|
||||
label: triggeredMonthly(),
|
||||
value: 'monthly',
|
||||
children: monthDaysNode(),
|
||||
},
|
||||
{
|
||||
label: triggeredInterval(),
|
||||
value: 'intervalDaily',
|
||||
children: intervalDaysNode(),
|
||||
},
|
||||
];
|
||||
|
||||
type TaskSchedule = [string, number] | [string, number, number];
|
||||
|
||||
const createCron = (schedule: TaskSchedule) => {
|
||||
const head = schedule[0];
|
||||
const cronGenerator = new CronGenerator();
|
||||
|
||||
if (head === 'daily') {
|
||||
const hour = schedule[1];
|
||||
return cronGenerator.every(1).days().atHour(hour).atMinute(0).toString();
|
||||
}
|
||||
const day = schedule[1];
|
||||
const hour = schedule[2];
|
||||
if (isUndefined(hour)) {
|
||||
throw new CustomError(
|
||||
ReportEventNames.parmasValidation,
|
||||
'invalid schedule',
|
||||
);
|
||||
}
|
||||
if (head === 'weekly') {
|
||||
return cronGenerator.atHour(hour).atMinute(0).onDaysOfWeek(day).toString();
|
||||
}
|
||||
if (head === 'monthly') {
|
||||
return cronGenerator.atHour(hour).atMinute(0).onDaysOfMonth(day).toString();
|
||||
}
|
||||
return cronGenerator.every(day).days().atHour(hour).atMinute(0).toString();
|
||||
};
|
||||
export const parseCron: (cron: string) => TaskSchedule = cronExpr => {
|
||||
// 目前需求只有 5 位 分、时、day of month、月、day of week
|
||||
// bytescheduler 只支持 6 位 秒、分、时、day of month、月、day of week
|
||||
const cronUnits = cronExpr?.split?.(' ').slice?.(1);
|
||||
const hour = cronUnits?.at(1);
|
||||
const dayOfMonthIndex = 2;
|
||||
const dayOfMonth = cronUnits?.at(dayOfMonthIndex);
|
||||
const dayOfWeek = cronExpr?.at(-1);
|
||||
|
||||
const numberHour = Number(hour);
|
||||
// 通配符
|
||||
const wildcard = '*';
|
||||
if (dayOfWeek !== wildcard) {
|
||||
return ['weekly', Number(dayOfWeek), numberHour];
|
||||
}
|
||||
if (dayOfMonth !== wildcard) {
|
||||
if (dayOfMonth?.startsWith(wildcard)) {
|
||||
return ['intervalDaily', Number(dayOfMonth.split('/').at(1)), numberHour];
|
||||
}
|
||||
return ['monthly', Number(dayOfMonth), numberHour];
|
||||
}
|
||||
return ['daily', numberHour];
|
||||
};
|
||||
|
||||
// 将key转化为对应文案
|
||||
// export const getOptionNodeText = (val: TaskSchedule): string[] => {
|
||||
// let resultData = treeData();
|
||||
// const nodeList = val?.map(item => {
|
||||
// const findData = resultData.find(data => data.value === item);
|
||||
// if (findData) {
|
||||
// resultData = findData?.children || [];
|
||||
// return String(findData.label) ?? '';
|
||||
// } else {
|
||||
// return '';
|
||||
// }
|
||||
// });
|
||||
// return nodeList;
|
||||
// };
|
||||
|
||||
const renderDisplay = (nodeList: string[]) => {
|
||||
const head = nodeList.at(0);
|
||||
const formatHours = (hours?: string) => {
|
||||
const formattedHours = hours?.startsWith?.('0') ? hours.slice?.(1) : hours;
|
||||
return formattedHours;
|
||||
};
|
||||
if (head === triggeredEveryday()) {
|
||||
const hours = nodeList.at(1);
|
||||
return I18n.t('bot_task_preset_everyday_task', {
|
||||
time: formatHours(hours),
|
||||
});
|
||||
}
|
||||
|
||||
const numberRegx = /[0-9]+/;
|
||||
const dayNode = nodeList.at(1);
|
||||
const days = Number(dayNode?.match?.(numberRegx)?.[0]);
|
||||
const hoursIndex = 2;
|
||||
const hours = nodeList.at(hoursIndex);
|
||||
|
||||
const formattedHours = formatHours(hours);
|
||||
if (head === triggeredEveryweek()) {
|
||||
return I18n.t('bot_task_preset_everyweek_task', {
|
||||
day: dayNode,
|
||||
time: formattedHours,
|
||||
});
|
||||
}
|
||||
if (head === triggeredMonthly()) {
|
||||
return I18n.t('bot_task_preset_monthly_task', {
|
||||
day: days,
|
||||
time: formattedHours,
|
||||
});
|
||||
}
|
||||
if (head === triggeredInterval()) {
|
||||
return I18n.t('bot_task_preset_interval_task', {
|
||||
day: days,
|
||||
time: formattedHours,
|
||||
});
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
interface FixCronjobSelectProps {
|
||||
value?: ValueExpression;
|
||||
onChange?: (e: ValueExpression) => void;
|
||||
readonly?: boolean;
|
||||
hasError?: boolean;
|
||||
}
|
||||
|
||||
/** 选择时间和时区组件 */
|
||||
export const FixCronjobSelect: React.FC<FixCronjobSelectProps> = ({
|
||||
value: _value,
|
||||
onChange: _onChange,
|
||||
readonly,
|
||||
hasError,
|
||||
}) => {
|
||||
const displayText = useRef<ReactNode>('');
|
||||
const value = _value?.content as string;
|
||||
|
||||
const onChange = useCallback(
|
||||
(v: string) => {
|
||||
_onChange?.({
|
||||
type: ValueExpressionType.LITERAL,
|
||||
content: v,
|
||||
});
|
||||
},
|
||||
[_onChange],
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Cascader
|
||||
hasError={hasError}
|
||||
size="small"
|
||||
className="w-full"
|
||||
disabled={readonly}
|
||||
showClear={false}
|
||||
placeholder={I18n.t('task_preset_trigger_time')}
|
||||
value={value ? parseCron(value) : void 0}
|
||||
onChange={v => {
|
||||
if (Array.isArray(v) && v.length) {
|
||||
// 生成的 cron 表达式是 5 位 但需要 6 位
|
||||
const cronExpr = `0 ${createCron(v as TaskSchedule)}`;
|
||||
onChange?.(cronExpr);
|
||||
return;
|
||||
}
|
||||
onChange?.('');
|
||||
}}
|
||||
treeData={treeData()}
|
||||
displayRender={nodes => {
|
||||
if (Array.isArray(nodes)) {
|
||||
displayText.current = renderDisplay(nodes);
|
||||
return displayText.current;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
.input{
|
||||
:global{
|
||||
.semi-input-suffix{
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* 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 { useMemo, type FC } from 'react';
|
||||
|
||||
import { useWatchFormErrors } from '@flowgram-adapter/free-layout-editor';
|
||||
import { useCurrentEntity } from '@flowgram-adapter/free-layout-editor';
|
||||
import { cronJobTranslator } from '@coze-workflow/components';
|
||||
import { CronJobType, type CronJobValue } from '@coze-workflow/nodes';
|
||||
import { ValueExpressionType, ValueExpression } from '@coze-workflow/base';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Select } from '@coze-arch/coze-design';
|
||||
|
||||
import { Text } from '@/form-extensions/components/text';
|
||||
|
||||
import { type DynamicComponentProps } from '../dynamic-form';
|
||||
import { FixCronjobSelect } from './fix-cronjob';
|
||||
import { AICronjobSelect } from './ai-cronjob';
|
||||
|
||||
type CronJobSelectProps = DynamicComponentProps<CronJobValue> & {
|
||||
needRefInput?: boolean;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export const CronJobSelect: FC<CronJobSelectProps> = ({
|
||||
needRefInput,
|
||||
className = '',
|
||||
value = {
|
||||
type: CronJobType.Selecting,
|
||||
content: {
|
||||
type: ValueExpressionType.LITERAL,
|
||||
content: '',
|
||||
},
|
||||
},
|
||||
onChange: _onChange,
|
||||
readonly,
|
||||
}) => {
|
||||
const node = useCurrentEntity();
|
||||
const errors = useWatchFormErrors(node);
|
||||
const hasError = (errors ?? []).length > 0;
|
||||
|
||||
const type = value.type ?? CronJobType.Selecting;
|
||||
const onChange = (content: ValueExpression | undefined) => {
|
||||
_onChange({
|
||||
type,
|
||||
content: content ?? {
|
||||
type: ValueExpressionType.LITERAL,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const cronjobTranslateText = useMemo(() => {
|
||||
if (
|
||||
hasError ||
|
||||
type === CronJobType.Selecting ||
|
||||
(value.content && ValueExpression.isRef(value.content))
|
||||
) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return cronJobTranslator(value.content?.content as unknown as string);
|
||||
}, [hasError, value.content, type]);
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<div className="flex flex-row gap-[2px]">
|
||||
<Select
|
||||
size="small"
|
||||
value={type}
|
||||
className="w-fit mb-[4px]"
|
||||
disabled={readonly}
|
||||
onChange={v => {
|
||||
_onChange({
|
||||
type: v as CronJobType,
|
||||
content: {
|
||||
type: ValueExpressionType.LITERAL,
|
||||
},
|
||||
});
|
||||
}}
|
||||
optionList={[
|
||||
{
|
||||
label: I18n.t(
|
||||
'workflow_start_trigger_cron_option',
|
||||
{},
|
||||
'选择预设时间',
|
||||
),
|
||||
value: CronJobType.Selecting,
|
||||
},
|
||||
{
|
||||
label: I18n.t(
|
||||
'workflow_start_trigger_cron_job',
|
||||
{},
|
||||
'使用Cron表达式',
|
||||
),
|
||||
value: CronJobType.Cronjob,
|
||||
},
|
||||
]}
|
||||
></Select>
|
||||
|
||||
<div className="flex-1 overflow-hidden">
|
||||
{type === CronJobType.Selecting ? (
|
||||
<FixCronjobSelect
|
||||
hasError={hasError}
|
||||
value={value.content}
|
||||
onChange={onChange}
|
||||
readonly={readonly}
|
||||
/>
|
||||
) : (
|
||||
<AICronjobSelect
|
||||
hasError={hasError}
|
||||
value={value.content}
|
||||
onChange={onChange}
|
||||
readonly={readonly}
|
||||
node={node}
|
||||
needRefInput={needRefInput}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{cronjobTranslateText ? (
|
||||
<div className="coz-mg-primary w-full h-[24px] flex flex-row items-center justify-center rounded-[4px]">
|
||||
<Text text={cronjobTranslateText} className="text-[12px]" />
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -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 { ViewVariableType } from '@coze-workflow/base';
|
||||
import { Tag } from '@coze-arch/coze-design';
|
||||
|
||||
const ViewDataTypeMap = {
|
||||
[ViewVariableType.String]: 'String',
|
||||
[ViewVariableType.Integer]: 'Integer',
|
||||
[ViewVariableType.Boolean]: 'Boolean',
|
||||
[ViewVariableType.Number]: 'Number',
|
||||
[ViewVariableType.Time]: 'Time',
|
||||
[ViewVariableType.File]: 'File',
|
||||
[ViewVariableType.Image]: 'File/Image',
|
||||
[ViewVariableType.Doc]: 'File/Doc',
|
||||
[ViewVariableType.Excel]: 'File/Excel',
|
||||
[ViewVariableType.Code]: 'File/Code',
|
||||
[ViewVariableType.Ppt]: 'File/PPT',
|
||||
[ViewVariableType.Txt]: 'File/Text',
|
||||
[ViewVariableType.Audio]: 'File/Audio',
|
||||
[ViewVariableType.Zip]: 'File/ZIP',
|
||||
[ViewVariableType.Video]: 'File/Video',
|
||||
[ViewVariableType.Svg]: 'File/SVG',
|
||||
[ViewVariableType.Voice]: 'File/Voice',
|
||||
};
|
||||
|
||||
interface DataTypeTagProps {
|
||||
type?: ViewVariableType;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export function DataTypeTag({ type, disabled }: DataTypeTagProps) {
|
||||
return (
|
||||
<Tag color="primary" size="mini" disabled={disabled}>
|
||||
{type === undefined ? 'undefined' : ViewDataTypeMap[type]}
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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 { useMemo, type FC } from 'react';
|
||||
|
||||
import { Field } from '@/form';
|
||||
|
||||
import { type DynamicComponentProps, type FormMeta } from './types';
|
||||
|
||||
export interface DynamicFormProps {
|
||||
formMeta: FormMeta;
|
||||
name: string;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
components: Record<string, FC<DynamicComponentProps<any>>>;
|
||||
// 禁用做触发
|
||||
onChange?: () => void;
|
||||
}
|
||||
|
||||
export const DynamicForm: FC<DynamicFormProps> = ({
|
||||
formMeta,
|
||||
name,
|
||||
components,
|
||||
onChange,
|
||||
}) => {
|
||||
const fields = useMemo(
|
||||
() =>
|
||||
formMeta.map(field => {
|
||||
const Component =
|
||||
components[field.setter] ??
|
||||
(() => <div>component {field.setter} not exist</div>);
|
||||
|
||||
return (
|
||||
<Field
|
||||
{...field}
|
||||
key={field.name}
|
||||
name={`${name}.${field.name}`}
|
||||
layout={field.layout ?? 'vertical'}
|
||||
>
|
||||
{({ value, onChange: _onChange, readonly }) => (
|
||||
<Component
|
||||
{...field.setterProps}
|
||||
value={value}
|
||||
onChange={(...args) => {
|
||||
_onChange(...args);
|
||||
onChange?.();
|
||||
}}
|
||||
readonly={readonly}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
);
|
||||
}),
|
||||
[formMeta, name, components],
|
||||
);
|
||||
return <>{fields}</>;
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { DynamicForm } from './dynamic-form';
|
||||
export { FormItemMeta, FormMeta, DynamicComponentProps } from './types';
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
export interface FormItemMeta {
|
||||
name: string;
|
||||
label: string;
|
||||
required?: boolean;
|
||||
setter: string;
|
||||
setterProps?: {
|
||||
defaultValue?: unknown;
|
||||
[k: string]: unknown;
|
||||
};
|
||||
layout?: 'horizontal' | 'vertical';
|
||||
}
|
||||
|
||||
export type FormMeta = FormItemMeta[];
|
||||
|
||||
export interface DynamicComponentProps<T> {
|
||||
value?: T; // 字段值
|
||||
readonly?: boolean; // 是否只读
|
||||
disabled?: boolean; // 是否禁用
|
||||
onChange: (newValue?: T) => void;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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 {
|
||||
ExpressionEditor,
|
||||
type ExpressionEditorProps,
|
||||
} from '@/nodes-v2/components/expression-editor';
|
||||
import { withField, useField } from '@/form';
|
||||
|
||||
export const ExpressionEditorField = withField<
|
||||
Omit<ExpressionEditorProps, 'value' | 'onChange'> & {
|
||||
testIDSuffix?: string;
|
||||
}
|
||||
>(props => {
|
||||
const { name, value, onChange, errors, onFocus, onBlur } = useField<string>();
|
||||
const {
|
||||
placeholder,
|
||||
minRows,
|
||||
maxLength,
|
||||
disableSuggestion,
|
||||
disableCounter,
|
||||
// 旧版逻辑是用name作为testID后缀 新版节点name路径可能会变(如xxx -> inputs.xxx) 需要从外部指定
|
||||
testIDSuffix = name,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<ExpressionEditor
|
||||
name={testIDSuffix}
|
||||
value={value}
|
||||
onChange={newValue => onChange(newValue as string)}
|
||||
key={name}
|
||||
placeholder={placeholder}
|
||||
minRows={minRows}
|
||||
maxLength={maxLength}
|
||||
isError={errors && errors?.length > 0}
|
||||
disableSuggestion={disableSuggestion}
|
||||
disableCounter={disableCounter}
|
||||
onFocus={onFocus}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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 { useMemo } from 'react';
|
||||
|
||||
import {
|
||||
Field,
|
||||
type FieldRenderProps,
|
||||
useCurrentEntity,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
import { WorkflowNode } from '@coze-workflow/base';
|
||||
|
||||
import { useDefaultNodeMeta } from '@/nodes-v2/hooks/use-default-node-meta';
|
||||
import { type NodeHeaderValue } from '@/nodes-v2/components/node-header';
|
||||
import { NodeHeader } from '@/nodes-v2';
|
||||
import { useGlobalState } from '@/hooks';
|
||||
import { useWatch } from '@/form';
|
||||
|
||||
export function Header({
|
||||
extraOperation,
|
||||
nodeDisabled,
|
||||
readonlyAllowDeleteOperation,
|
||||
}: {
|
||||
extraOperation?: React.ReactNode;
|
||||
nodeDisabled?: boolean;
|
||||
readonlyAllowDeleteOperation?: boolean;
|
||||
}) {
|
||||
const defaultNodeMeta = useDefaultNodeMeta();
|
||||
const node = useCurrentEntity();
|
||||
const { projectId } = useGlobalState();
|
||||
const wrappedNode = useMemo(() => new WorkflowNode(node), [node]);
|
||||
const triggerIsOpen = useWatch<Boolean>('trigger.isOpen');
|
||||
|
||||
const showTrigger = useMemo(
|
||||
() => wrappedNode.registry?.meta?.showTrigger?.({ projectId }),
|
||||
[projectId],
|
||||
);
|
||||
return (
|
||||
<Field
|
||||
name={'nodeMeta'}
|
||||
deps={['outputs', 'batchMode']}
|
||||
defaultValue={defaultNodeMeta as unknown as NodeHeaderValue}
|
||||
>
|
||||
{({ field, fieldState }: FieldRenderProps<NodeHeaderValue>) => (
|
||||
<NodeHeader
|
||||
{...field}
|
||||
showErrorIgnore
|
||||
errors={fieldState?.errors || []}
|
||||
hideTest={wrappedNode.registry?.meta?.hideTest}
|
||||
readonly={wrappedNode.registry?.meta?.headerReadonly}
|
||||
showTrigger={showTrigger}
|
||||
triggerIsOpen={triggerIsOpen}
|
||||
extraOperation={extraOperation}
|
||||
nodeDisabled={nodeDisabled}
|
||||
readonlyAllowDeleteOperation={readonlyAllowDeleteOperation}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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 ComponentProps } from 'react';
|
||||
|
||||
import { EnumImageModel } from '@coze-workflow/setters';
|
||||
|
||||
import { withField, useField } from '@/form';
|
||||
|
||||
type ImageModelSelectProps = Omit<
|
||||
ComponentProps<typeof EnumImageModel>,
|
||||
'value' | 'onChange'
|
||||
>;
|
||||
|
||||
/**
|
||||
* 图像模型选择器
|
||||
*/
|
||||
export const ImageModelSelectField = withField<ImageModelSelectProps>(props => {
|
||||
const { value, readonly, onChange, errors } = useField<number>();
|
||||
|
||||
return (
|
||||
<EnumImageModel
|
||||
value={value}
|
||||
readonly={readonly}
|
||||
onChange={newValue => onChange?.(newValue as number)}
|
||||
validateStatus={errors && errors.length > 0 ? 'error' : undefined}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { NodeConfigForm } from './node-config-form';
|
||||
export { DataTypeTag } from './data-type-tag';
|
||||
export { InputParameters } from './input-parameters';
|
||||
export { Outputs } from './outputs';
|
||||
export { ImageModelSelectField } from './image-model-select-field';
|
||||
export { ExpressionEditorField } from './expression-editor-field';
|
||||
export { Notify } from './notify';
|
||||
export { Timezone } from './timezone';
|
||||
export { CronJobSelect } from './cronjob-select';
|
||||
export { DynamicForm } from './dynamic-form';
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// TODO 源码待迁移。 开发 cli ,依赖引用路径
|
||||
export { InputParameters } from '@/components/node-render/node-render-new/fields/input-parameters';
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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 PropsWithChildren } from 'react';
|
||||
|
||||
import { PublicScopeProvider } from '@coze-workflow/variable';
|
||||
import { useIsSettingOnError } from '@coze-workflow/nodes';
|
||||
|
||||
import { useGlobalState } from '@/hooks';
|
||||
import { Form } from '@/form';
|
||||
|
||||
import { SettingOnError } from '../fields';
|
||||
import { Header } from './header';
|
||||
|
||||
type NodeConfigFormProps = PropsWithChildren<{
|
||||
extraOperation?: React.ReactNode;
|
||||
batchModePath?: string;
|
||||
nodeDisabled?: boolean;
|
||||
readonlyAllowDeleteOperation?: boolean;
|
||||
}>;
|
||||
|
||||
/**
|
||||
* NodeConfigForm组件
|
||||
* 用于展示节点配置表单
|
||||
* @param children - 子组件,用于渲染表单内容
|
||||
*/
|
||||
export function NodeConfigForm({
|
||||
children,
|
||||
extraOperation,
|
||||
batchModePath,
|
||||
nodeDisabled,
|
||||
readonlyAllowDeleteOperation,
|
||||
}: NodeConfigFormProps) {
|
||||
const { readonly } = useGlobalState();
|
||||
const isSettingOnError = useIsSettingOnError();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header
|
||||
extraOperation={extraOperation}
|
||||
nodeDisabled={nodeDisabled}
|
||||
readonlyAllowDeleteOperation={readonlyAllowDeleteOperation}
|
||||
/>
|
||||
<PublicScopeProvider>
|
||||
<Form readonly={readonly}>
|
||||
{children}
|
||||
{isSettingOnError ? (
|
||||
<SettingOnError batchModePath={batchModePath} />
|
||||
) : null}
|
||||
</Form>
|
||||
</PublicScopeProvider>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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 PropsWithChildren } from 'react';
|
||||
|
||||
import { PublicScopeProvider } from '@coze-workflow/variable';
|
||||
|
||||
import { Header } from './header';
|
||||
|
||||
export function Node({ children }: PropsWithChildren) {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<PublicScopeProvider>
|
||||
<>{children}</>
|
||||
</PublicScopeProvider>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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 FC } from 'react';
|
||||
|
||||
import classnames from 'classnames';
|
||||
|
||||
import { Text } from '@/form-extensions/components/text';
|
||||
|
||||
export const Notify: FC<{
|
||||
text: string;
|
||||
align?: 'left' | 'center' | 'right';
|
||||
className?: string;
|
||||
isBreakLine?: boolean;
|
||||
}> = ({ text, align = 'center', className = '', isBreakLine = false }) => (
|
||||
<div
|
||||
className={classnames(
|
||||
'w-full !px-[8px] !py-[6px] flex flex-row items-center coz-mg-hglt-secondary text-[14px]',
|
||||
|
||||
{
|
||||
'justify-center': align === 'center',
|
||||
'justify-end': align === 'right',
|
||||
'justify-start': align === 'left',
|
||||
},
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{isBreakLine ? text : <Text text={text} />}
|
||||
</div>
|
||||
);
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// TODO 源码待迁移。 开发 cli ,依赖引用路径
|
||||
export { Outputs } from '@/components/node-render/node-render-new/fields/outputs';
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 默认时区,目前用于 task 模块
|
||||
*
|
||||
* 国内:UTC+8
|
||||
* 海外:UTC+0
|
||||
*/
|
||||
export const DEFAULT_TIME_ZONE = IS_OVERSEA ? 'Etc/GMT+0' : 'Asia/Shanghai';
|
||||
export const DEFAULT_TIME_ZONE_OFFSET = IS_OVERSEA ? 'UTC+00:00' : 'UTC+08:00';
|
||||
// 未知时区,用于兼容
|
||||
export const UNKNOWN_TIME_ZONE_OFFSET = 'Others';
|
||||
@@ -0,0 +1,15 @@
|
||||
.dropdown {
|
||||
:global {
|
||||
.semi-cascader-option-lists {
|
||||
height: 260px;
|
||||
|
||||
&.semi-cascader-option-lists-empty {
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.semi-cascader-option-empty {
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* 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 { useMemo, type FC } from 'react';
|
||||
|
||||
import { cloneDeep, find, noop } from 'lodash-es';
|
||||
import classNames from 'classnames';
|
||||
import { type LiteralExpression } from '@coze-workflow/base';
|
||||
import { ValueExpressionType } from '@coze-workflow/base';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { EVENT_NAMES, sendTeaEvent } from '@coze-arch/bot-tea';
|
||||
import {
|
||||
Cascader,
|
||||
Highlight,
|
||||
type CascaderData,
|
||||
type FilterRenderProps,
|
||||
} from '@coze-arch/coze-design';
|
||||
|
||||
import { type DynamicComponentProps } from '../dynamic-form';
|
||||
import { generatedTimezones } from './utils/timezone';
|
||||
import { UNKNOWN_TIME_ZONE_OFFSET } from './const';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
type TimezoneProps = DynamicComponentProps<string> & {
|
||||
className?: string;
|
||||
showClear?: boolean; // 是否可清空
|
||||
defaultValue?: string; // 默认值
|
||||
};
|
||||
|
||||
export const Timezone: FC<TimezoneProps> = ({
|
||||
className,
|
||||
showClear = false,
|
||||
defaultValue,
|
||||
value: _value,
|
||||
onChange = noop,
|
||||
readonly,
|
||||
}) => {
|
||||
const value = ((_value as unknown as LiteralExpression)?.content ??
|
||||
_value ??
|
||||
defaultValue) as string;
|
||||
|
||||
// 时区列表
|
||||
const { timezoneOptions: TIME_ZONE_OPTIONS, timezoneMap: TIME_ZOME_MAP } =
|
||||
useMemo(() => generatedTimezones(), []);
|
||||
|
||||
// 时区选择器选项生成逻辑
|
||||
const [timezoneOptions, timezoneMap] = useMemo(() => {
|
||||
const timezoneOptionsBase = cloneDeep(TIME_ZONE_OPTIONS);
|
||||
const timezoneMapBase = cloneDeep(TIME_ZOME_MAP);
|
||||
// 用户已选择时区,但当前环境不支持兼容对应时区时,在选项末尾插入未知时区选项兼容
|
||||
if (value && timezoneMapBase.every(e => e.value !== value)) {
|
||||
timezoneOptionsBase.push({
|
||||
value: UNKNOWN_TIME_ZONE_OFFSET,
|
||||
label: UNKNOWN_TIME_ZONE_OFFSET,
|
||||
children: [{ value, label: value }],
|
||||
});
|
||||
timezoneMapBase.push({
|
||||
value,
|
||||
offset: UNKNOWN_TIME_ZONE_OFFSET,
|
||||
});
|
||||
}
|
||||
return [timezoneOptionsBase, timezoneMapBase];
|
||||
}, []);
|
||||
|
||||
const timezoneValue = useMemo(() => {
|
||||
const item = find(timezoneMap, ['value', value]);
|
||||
if (item) {
|
||||
return [item.offset, item.value];
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}, [value, timezoneMap]);
|
||||
|
||||
// 遍历查询时区偏移量
|
||||
const findTimezoneValue = (nodes: string[], key: string) => {
|
||||
if (Array.isArray(nodes) && nodes.length > 1) {
|
||||
const [offsetValue, timezoneLabel] = nodes;
|
||||
const item = find(timezoneOptions, ['value', offsetValue]);
|
||||
if (item && Array.isArray(item.children)) {
|
||||
const option = find(item.children, [key, timezoneLabel]);
|
||||
if (option && option.value) {
|
||||
return option.value as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const filterSorter = (
|
||||
first: CascaderData,
|
||||
second: CascaderData,
|
||||
inputValue: string,
|
||||
) => {
|
||||
if (
|
||||
Array.isArray(first) &&
|
||||
first.length > 1 &&
|
||||
Array.isArray(second) &&
|
||||
second.length > 1
|
||||
) {
|
||||
const keyword: string = (inputValue || '').toLowerCase();
|
||||
const firstLabelLowerCase: string = (first[1].label || '').toLowerCase();
|
||||
const secondLabelLowerCase: string = (
|
||||
second[1].label || ''
|
||||
).toLowerCase();
|
||||
const firstLabelArray = firstLabelLowerCase.split(' ');
|
||||
const secondLabelArray = secondLabelLowerCase.split(' ');
|
||||
if (firstLabelArray.findIndex(e => e === keyword) === 0) {
|
||||
return -1;
|
||||
}
|
||||
if (secondLabelArray.findIndex(e => e === keyword) === 0) {
|
||||
return 1;
|
||||
}
|
||||
if (firstLabelLowerCase.includes(keyword)) {
|
||||
return -1;
|
||||
}
|
||||
if (secondLabelLowerCase.includes(keyword)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
// 自定义高亮逻辑
|
||||
const filterRender = (filterRenderProps: FilterRenderProps) => {
|
||||
const { className: cls, inputValue, data, onClick } = filterRenderProps;
|
||||
// 把多级选项的文案拼起来
|
||||
const labelString = data.map(e => e.label).join(' / ');
|
||||
return (
|
||||
<li
|
||||
role="menuitem"
|
||||
className={classNames('semi-cascader-option-flatten', cls)}
|
||||
onClick={onClick}
|
||||
>
|
||||
<span className="semi-cascader-option-label">
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="semi-cascader-option-icon semi-cascader-option-icon-empty"
|
||||
></span>
|
||||
<Highlight
|
||||
sourceString={labelString}
|
||||
searchWords={[inputValue]}
|
||||
highlightStyle={{
|
||||
color: 'var(--light-usage-primary-color-primary, #4d53e8)',
|
||||
backgroundColor: 'transparent',
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Cascader
|
||||
size="small"
|
||||
className={`${className} w-full`}
|
||||
dropdownClassName={styles.dropdown}
|
||||
showClear={showClear}
|
||||
filterTreeNode
|
||||
filterSorter={filterSorter}
|
||||
filterRender={filterRender}
|
||||
disabled={readonly}
|
||||
placeholder={I18n.t('task_preset_timezone')}
|
||||
treeData={timezoneOptions}
|
||||
value={timezoneValue}
|
||||
onChange={nodes => {
|
||||
const newTimezone = findTimezoneValue(nodes as string[], 'value');
|
||||
onChange({
|
||||
type: ValueExpressionType.LITERAL,
|
||||
content: newTimezone,
|
||||
});
|
||||
if (newTimezone) {
|
||||
sendTeaEvent(EVENT_NAMES.select_scheduled_tasks_timezone, {
|
||||
timezone: newTimezone,
|
||||
});
|
||||
}
|
||||
}}
|
||||
displayRender={nodes => findTimezoneValue(nodes as string[], 'label')}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { groupBy, toPairs, find, orderBy } from 'lodash-es';
|
||||
import dayjsUTC from 'dayjs/plugin/utc';
|
||||
import dayjsTimezone from 'dayjs/plugin/timezone';
|
||||
import quartersOfYear from 'dayjs/plugin/quarterOfYear';
|
||||
import isoWeek from 'dayjs/plugin/isoWeek';
|
||||
import dayjs from 'dayjs';
|
||||
import { logger } from '@coze-arch/logger';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { type CascaderData } from '@coze-arch/bot-semi/Cascader';
|
||||
|
||||
import { DEFAULT_TIME_ZONE, DEFAULT_TIME_ZONE_OFFSET } from '../const';
|
||||
|
||||
// dependent on utc plugin
|
||||
dayjs.extend(isoWeek); // 注意:这里插件的注册顺序不能随意改变,此外重复注册插件可能会有 bug。
|
||||
dayjs.extend(quartersOfYear);
|
||||
dayjs.extend(dayjsUTC);
|
||||
dayjs.extend(dayjsTimezone);
|
||||
|
||||
export const dayjsForTimezone = dayjs;
|
||||
|
||||
export interface ITimezoneItem {
|
||||
value: string;
|
||||
label?: string;
|
||||
offset: string;
|
||||
utcOffset?: number;
|
||||
}
|
||||
|
||||
// 获取时区列表
|
||||
export const generatedTimezones = () => {
|
||||
let timezoneOptions: CascaderData[] = [];
|
||||
let timezoneMap: ITimezoneItem[] = [];
|
||||
try {
|
||||
// 当前国际化环境
|
||||
const locale = I18n.language ?? 'en-US';
|
||||
/**
|
||||
* 所有时区列表
|
||||
* (Intl as any) 项目的typescript版本不含有supportedValuesOf方法,编译会报错
|
||||
*/
|
||||
const options = (Intl as any)
|
||||
.supportedValuesOf('timeZone')
|
||||
.map((item: any) => {
|
||||
const formatDateParts = new Intl.DateTimeFormat(locale, {
|
||||
timeZone: item,
|
||||
timeZoneName: 'longGeneric',
|
||||
}).formatToParts(new Date());
|
||||
const { value: timeZoneName } = find(formatDateParts, [
|
||||
'type',
|
||||
'timeZoneName',
|
||||
]) as Intl.DateTimeFormatPart;
|
||||
const targetTime = dayjs().tz(item);
|
||||
return {
|
||||
value: item,
|
||||
label: `${timeZoneName} - ${item}`,
|
||||
offset: `UTC${targetTime.format('Z')}`,
|
||||
utcOffset: targetTime.utcOffset(),
|
||||
};
|
||||
});
|
||||
timezoneOptions = orderBy(
|
||||
toPairs(groupBy(options, 'offset')),
|
||||
item => {
|
||||
const [offset] = item;
|
||||
return find(options, ['offset', offset])?.utcOffset;
|
||||
},
|
||||
['asc'],
|
||||
).map(item => {
|
||||
const [itemKey, itemValue] = item;
|
||||
return {
|
||||
value: itemKey,
|
||||
label: itemKey,
|
||||
children: orderBy(itemValue, ['label'], ['asc']),
|
||||
};
|
||||
});
|
||||
timezoneMap = options;
|
||||
} catch (error: any) {
|
||||
timezoneOptions = [
|
||||
{
|
||||
value: DEFAULT_TIME_ZONE_OFFSET,
|
||||
label: DEFAULT_TIME_ZONE_OFFSET,
|
||||
children: [{ value: DEFAULT_TIME_ZONE, label: DEFAULT_TIME_ZONE }],
|
||||
},
|
||||
];
|
||||
timezoneMap = [
|
||||
{ value: DEFAULT_TIME_ZONE, offset: DEFAULT_TIME_ZONE_OFFSET },
|
||||
];
|
||||
// 如果出现无法获取时区信息的情况上报异常到 slardar
|
||||
logger.persist.error({
|
||||
message: 'Custom Error: Unable to obtain accurate time zone list',
|
||||
error,
|
||||
});
|
||||
}
|
||||
return { timezoneOptions, timezoneMap };
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { fireNodeTitleChange } from '@/nodes-v2/materials/fire-node-title-change';
|
||||
export { provideNodeOutputVariablesEffect } from '@/nodes-v2/materials/provide-node-output-variables';
|
||||
export { provideLoopInputsVariablesEffect } from './provide-loop-inputs-variables';
|
||||
export { provideLoopOutputsVariablesEffect } from './provide-loop-outputs-variables';
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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 { createEffectFromVariableProvider } from '@coze-workflow/variable/src/utils/variable-provider';
|
||||
import { provideLoopInputsVariables } from '@coze-workflow/variable/src/form-extensions/variable-providers/provide-loop-input-variables';
|
||||
|
||||
export const provideLoopInputsVariablesEffect =
|
||||
createEffectFromVariableProvider(provideLoopInputsVariables);
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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 { createEffectFromVariableProvider } from '@coze-workflow/variable/src/utils/variable-provider';
|
||||
import { provideLoopOutputsVariables } from '@coze-workflow/variable/src/form-extensions/variable-providers/provide-loop-output-variables';
|
||||
|
||||
export const provideLoopOutputsVariablesEffect =
|
||||
createEffectFromVariableProvider(provideLoopOutputsVariables);
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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 FC } from 'react';
|
||||
|
||||
import { type InputValueVO, useNodeTestId } from '@coze-workflow/base';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
|
||||
import { Section } from '@/form';
|
||||
|
||||
import { SwitchField } from '../switch-field';
|
||||
import { ExpressionEditorField } from '../expression-editor-field';
|
||||
export interface AnswerContentFieldProps {
|
||||
enableStreamingOutput?: boolean;
|
||||
editorFieldName: string;
|
||||
switchFieldName?: string;
|
||||
title?: string;
|
||||
tooltip?: string;
|
||||
switchLabel?: string;
|
||||
switchTooltip?: string;
|
||||
switchTestId?: string;
|
||||
inputParameters?: InputValueVO[];
|
||||
testId?: string;
|
||||
}
|
||||
export const AnswerContentField: FC<AnswerContentFieldProps> = ({
|
||||
title,
|
||||
tooltip,
|
||||
switchLabel,
|
||||
switchTooltip,
|
||||
enableStreamingOutput,
|
||||
editorFieldName,
|
||||
switchFieldName,
|
||||
switchTestId,
|
||||
inputParameters,
|
||||
testId,
|
||||
}) => {
|
||||
const { concatTestId, getNodeSetterId } = useNodeTestId();
|
||||
|
||||
return (
|
||||
<Section
|
||||
title={title}
|
||||
tooltip={tooltip}
|
||||
actions={[
|
||||
enableStreamingOutput && switchFieldName ? (
|
||||
<SwitchField
|
||||
name={switchFieldName}
|
||||
customLabel={switchLabel}
|
||||
customTooltip={switchTooltip}
|
||||
testId={concatTestId(testId ?? '', switchTestId ?? '')}
|
||||
/>
|
||||
) : null,
|
||||
]}
|
||||
testId={getNodeSetterId(testId ?? '')}
|
||||
>
|
||||
<ExpressionEditorField
|
||||
name={editorFieldName}
|
||||
placeholder={I18n.t('workflow_detail_end_answer_example')}
|
||||
inputParameters={inputParameters}
|
||||
testId={testId}
|
||||
/>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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 from 'react';
|
||||
|
||||
import { BatchMode } from '@/nodes-v2/components/batch-mode';
|
||||
import { useField, withField } from '@/form';
|
||||
|
||||
export const BatchModeField = withField<{}, string>(() => {
|
||||
const { name: fieldName, value, onChange, onBlur } = useField<string>();
|
||||
return (
|
||||
<BatchMode
|
||||
name={fieldName}
|
||||
value={value}
|
||||
onChange={e => {
|
||||
onChange?.((e as React.ChangeEvent<HTMLInputElement>).target.value);
|
||||
onBlur?.();
|
||||
}}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 from 'react';
|
||||
|
||||
import { Checkbox } from '@/form-extensions/components/checkbox';
|
||||
import { useField, withField } from '@/form';
|
||||
|
||||
export const CheckboxWithTipsField = withField(
|
||||
({ text, itemTooltip }: { text: string; itemTooltip?: string }) => {
|
||||
const { name, value, onChange, readonly } = useField<boolean>();
|
||||
const context = { meta: { name } };
|
||||
const options = {
|
||||
text,
|
||||
itemTooltip,
|
||||
};
|
||||
return (
|
||||
<Checkbox
|
||||
options={options}
|
||||
context={context}
|
||||
value={!!value}
|
||||
onChange={(v: boolean) => onChange(v)}
|
||||
readonly={!!readonly}
|
||||
/>
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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 from 'react';
|
||||
|
||||
import {
|
||||
ExpressionEditor as ExpressionEditorLeagcy,
|
||||
type ExpressionEditorProps,
|
||||
} from '@/nodes-v2/components/expression-editor';
|
||||
import { useField, withField } from '@/form';
|
||||
|
||||
type ExpressionEditorFieldProps = Omit<
|
||||
ExpressionEditorProps,
|
||||
'value' | 'onChange' | 'onBlur' | 'onFocus'
|
||||
> & {
|
||||
dataTestName?: string;
|
||||
};
|
||||
|
||||
function ExpressionEditor(props: ExpressionEditorFieldProps) {
|
||||
const { name, value, onChange, errors, onBlur, readonly } =
|
||||
useField<string>();
|
||||
|
||||
return (
|
||||
<ExpressionEditorLeagcy
|
||||
{...props}
|
||||
name={props?.dataTestName ?? name}
|
||||
value={value as string}
|
||||
onChange={e => onChange(e as string)}
|
||||
isError={errors && errors?.length > 0}
|
||||
onBlur={onBlur}
|
||||
disableSuggestion={readonly}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export const ExpressionEditorField = withField(ExpressionEditor);
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { InputsParametersField } from './inputs-parameters-field';
|
||||
export { createInputsValidator } from './inputs-parameters-field/create-inputs-validator';
|
||||
export { InputsField } from './inputs-parameters-field/inputs-field';
|
||||
export { OutputsField } from './outputs';
|
||||
export { ValueExpressionInputField } from './value-expression-input';
|
||||
export { SettingOnError } from './setting-on-error';
|
||||
export { ParametersInputGroup } from './parameters-input-group';
|
||||
export { ParametersInputGroupField } from './parameters-input-group/parameters-input-group-field';
|
||||
export { ModelSelectField } from './model-select-field';
|
||||
export { RadioSetterField } from './radio-setter-field';
|
||||
export { ExpressionEditorField } from './expression-editor-field';
|
||||
export { CheckboxWithTipsField } from './checkbox-with-tips-field';
|
||||
export { OutputsDisplayField } from './outputs-display-field';
|
||||
export { AnswerContentField } from './answer-content-field';
|
||||
export { SwitchField } from './switch-field';
|
||||
export { LoopOutputsField } from './loop-outputs-field';
|
||||
export { BatchModeField } from './batch-mode-field';
|
||||
export { InputsKVField } from './inputs-kv-field';
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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 { I18n } from '@coze-arch/i18n';
|
||||
|
||||
export const COLUMNS = [
|
||||
{
|
||||
label: I18n.t('workflow_detail_node_parameter_name'),
|
||||
style: { width: 148 },
|
||||
},
|
||||
{ label: I18n.t('workflow_detail_end_output_value') },
|
||||
];
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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 PropsWithChildren } from 'react';
|
||||
|
||||
import { generateInputJsonSchema } from '@coze-workflow/variable';
|
||||
import {
|
||||
getInputType,
|
||||
getSortedInputParameters,
|
||||
type ApiNodeDetailDTO,
|
||||
} from '@coze-workflow/nodes';
|
||||
import {
|
||||
useNodeTestId,
|
||||
type InputValueVO,
|
||||
type VariableMetaDTO,
|
||||
type DTODefine,
|
||||
} from '@coze-workflow/base';
|
||||
import { reporter } from '@coze-arch/logger';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
|
||||
import { ValueExpressionInputField } from '@/node-registries/common/fields';
|
||||
import {
|
||||
Section,
|
||||
useField,
|
||||
ColumnTitles,
|
||||
withField,
|
||||
SelectField,
|
||||
SliderField,
|
||||
FieldLayout,
|
||||
} from '@/form';
|
||||
|
||||
import { getCustomSetterProps } from '../../utils';
|
||||
import { COLUMNS } from './constants';
|
||||
|
||||
interface InputsProps {
|
||||
inputsDef: ApiNodeDetailDTO['inputs'];
|
||||
}
|
||||
|
||||
const CUSTOM_SETTER_MAP = {
|
||||
Select: SelectField,
|
||||
Slider: SliderField,
|
||||
};
|
||||
|
||||
const CUSTOM_SETTER_STYLE = {
|
||||
Select: {
|
||||
width: '100%',
|
||||
},
|
||||
};
|
||||
|
||||
const renderCustomSetter = (
|
||||
fieldDef: ApiNodeDetailDTO['inputs'][number],
|
||||
customSetterProps: Record<string, unknown> & { key: string },
|
||||
fieldName: string,
|
||||
) => {
|
||||
const { title, name, required, description, label } = fieldDef;
|
||||
const { key, ...setterProps } = customSetterProps;
|
||||
const CustomSetter = CUSTOM_SETTER_MAP[key];
|
||||
|
||||
if (!CustomSetter) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<FieldLayout
|
||||
label={title || label || name}
|
||||
tooltip={description}
|
||||
required={required}
|
||||
>
|
||||
<CustomSetter
|
||||
{...setterProps}
|
||||
name={`${fieldName}.${name}`}
|
||||
style={CUSTOM_SETTER_STYLE[key]}
|
||||
/>
|
||||
</FieldLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export const InputsKVField = withField(
|
||||
({ inputsDef }: InputsProps & PropsWithChildren) => {
|
||||
const { name: fieldName } = useField<InputValueVO>();
|
||||
const { getNodeSetterId } = useNodeTestId();
|
||||
|
||||
return (
|
||||
<Section
|
||||
title={I18n.t('workflow_detail_node_input')}
|
||||
tooltip={I18n.t('workflow_detail_api_input_tooltip')}
|
||||
testId={getNodeSetterId(fieldName)}
|
||||
actions={[]}
|
||||
>
|
||||
<ColumnTitles columns={COLUMNS} />
|
||||
|
||||
<div className="flex flex-col gap-[8px]">
|
||||
{getSortedInputParameters(inputsDef)?.map(fieldDef => {
|
||||
const { title, name, required, description, label } = fieldDef;
|
||||
|
||||
const { inputType, disabledTypes } = getInputType(
|
||||
fieldDef as DTODefine.InputVariableDTO,
|
||||
);
|
||||
|
||||
let jsonSchema: ReturnType<typeof generateInputJsonSchema>;
|
||||
try {
|
||||
jsonSchema = generateInputJsonSchema(fieldDef as VariableMetaDTO);
|
||||
} catch (error) {
|
||||
jsonSchema = undefined;
|
||||
reporter.error({
|
||||
message: 'workflow_plugin_generate_input_json_schema_error',
|
||||
error,
|
||||
});
|
||||
}
|
||||
|
||||
const customSetterProps = getCustomSetterProps(fieldDef);
|
||||
if (customSetterProps?.key) {
|
||||
return renderCustomSetter(fieldDef, customSetterProps, fieldName);
|
||||
}
|
||||
|
||||
return (
|
||||
<ValueExpressionInputField
|
||||
key={`${fieldName}.${name}`}
|
||||
label={title || label || name}
|
||||
tooltip={description}
|
||||
required={required}
|
||||
inputType={inputType}
|
||||
disabledTypes={disabledTypes}
|
||||
name={`${fieldName}.${name}`}
|
||||
literalConfig={jsonSchema ? { jsonSchema } : undefined}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</Section>
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 { get } from 'lodash-es';
|
||||
import { type Validate } from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { createValueExpressionInputValidate } from '@/nodes-v2/materials/create-value-expression-input-validate';
|
||||
import { createNodeInputNameValidate } from '@/nodes-v2/components/node-input-name/validate';
|
||||
|
||||
import { createInputTreeValidator } from '../../validators/create-input-tree-validator';
|
||||
|
||||
export function createInputsValidator(isTree: boolean): {
|
||||
[key: string]: Validate;
|
||||
} {
|
||||
if (isTree) {
|
||||
return {
|
||||
'inputs.inputParameters': createInputTreeValidator(),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
'inputs.inputParameters.*.name': createNodeInputNameValidate({
|
||||
getNames: ({ formValues }) =>
|
||||
(get(formValues, 'inputs.inputParameters') || []).map(
|
||||
item => item.name,
|
||||
),
|
||||
}),
|
||||
'inputs.inputParameters.*.input': createValueExpressionInputValidate({
|
||||
required: true,
|
||||
}),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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 ViewVariableType, type InputValueVO } from '@coze-workflow/base';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
|
||||
import { type FieldProps } from '@/form';
|
||||
|
||||
import { type NodeInputNameProps } from './node-input-name/type';
|
||||
import { InputsTreeField } from './inputs-tree-field';
|
||||
import { InputsField } from './inputs-field';
|
||||
|
||||
interface InputsSectionProps extends FieldProps<InputValueVO[]> {
|
||||
title?: string;
|
||||
tooltip?: React.ReactNode;
|
||||
isTree?: boolean;
|
||||
paramsTitle?: string;
|
||||
expressionTitle?: string;
|
||||
testId?: string;
|
||||
disabledTypes?: ViewVariableType[];
|
||||
onAppend?: () => InputValueVO;
|
||||
inputPlaceholder?: string;
|
||||
literalDisabled?: boolean;
|
||||
nameProps?: Partial<NodeInputNameProps>;
|
||||
customReadonly?: boolean;
|
||||
}
|
||||
|
||||
export const InputsParametersField = ({
|
||||
name = 'inputs.inputParameters',
|
||||
title = I18n.t('workflow_detail_node_parameter_input'),
|
||||
tooltip = I18n.t('workflow_240218_07'),
|
||||
paramsTitle,
|
||||
expressionTitle,
|
||||
disabledTypes,
|
||||
defaultValue,
|
||||
onAppend,
|
||||
inputPlaceholder,
|
||||
literalDisabled,
|
||||
isTree,
|
||||
nameProps,
|
||||
customReadonly,
|
||||
testId,
|
||||
}: InputsSectionProps) =>
|
||||
isTree ? (
|
||||
<InputsTreeField
|
||||
name={name}
|
||||
defaultValue={defaultValue}
|
||||
title={title}
|
||||
tooltip={tooltip}
|
||||
customReadonly={customReadonly}
|
||||
testId={testId}
|
||||
/>
|
||||
) : (
|
||||
<InputsField
|
||||
name={name}
|
||||
defaultValue={defaultValue}
|
||||
title={title}
|
||||
tooltip={tooltip}
|
||||
paramsTitle={paramsTitle}
|
||||
expressionTitle={expressionTitle}
|
||||
disabledTypes={disabledTypes}
|
||||
onAppend={onAppend}
|
||||
inputPlaceholder={inputPlaceholder}
|
||||
literalDisabled={literalDisabled}
|
||||
nameProps={nameProps}
|
||||
customReadonly={customReadonly}
|
||||
testId={testId}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* 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 {
|
||||
FieldArray,
|
||||
type FieldArrayRenderProps,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
import type { ViewVariableType, InputValueVO } from '@coze-workflow/base';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
|
||||
import { useReadonly } from '@/nodes-v2/hooks/use-readonly';
|
||||
import { ColumnsTitleWithAction } from '@/form-extensions/components/columns-title-with-action';
|
||||
import {
|
||||
AddButton,
|
||||
FieldArrayItem,
|
||||
FieldRows,
|
||||
Section,
|
||||
type FieldProps,
|
||||
} from '@/form';
|
||||
|
||||
import {
|
||||
ValueExpressionInputField,
|
||||
type ValueExpressionInputProps,
|
||||
} from '../value-expression-input';
|
||||
import { type NodeInputNameProps } from './node-input-name/type';
|
||||
import { NodeInputNameField } from './node-input-name';
|
||||
|
||||
interface InputsFieldProps extends FieldProps<InputValueVO[]> {
|
||||
title?: string;
|
||||
paramsTitle?: string;
|
||||
expressionTitle?: string;
|
||||
disabledTypes?: ViewVariableType[];
|
||||
onAppend?: () => InputValueVO;
|
||||
inputPlaceholder?: string;
|
||||
literalDisabled?: boolean;
|
||||
showEmptyText?: boolean;
|
||||
nthCannotDeleted?: number;
|
||||
nameProps?: Partial<NodeInputNameProps>;
|
||||
inputProps?: ValueExpressionInputProps;
|
||||
customReadonly?: boolean;
|
||||
testId?: string;
|
||||
}
|
||||
|
||||
export const InputsField = ({
|
||||
name,
|
||||
defaultValue,
|
||||
title,
|
||||
tooltip,
|
||||
paramsTitle,
|
||||
expressionTitle,
|
||||
disabledTypes,
|
||||
inputPlaceholder,
|
||||
literalDisabled,
|
||||
onAppend,
|
||||
nthCannotDeleted,
|
||||
showEmptyText = true,
|
||||
nameProps = {},
|
||||
inputProps = {},
|
||||
customReadonly,
|
||||
testId,
|
||||
}: InputsFieldProps) => {
|
||||
const formReadonly = useReadonly();
|
||||
const readonly = formReadonly || customReadonly;
|
||||
return (
|
||||
<FieldArray<InputValueVO> name={name} defaultValue={defaultValue}>
|
||||
{({ field }: FieldArrayRenderProps<InputValueVO>) => {
|
||||
const { value = [], delete: remove, append } = field;
|
||||
const length = value?.length ?? 0;
|
||||
const isEmpty = !length;
|
||||
const disableRemove = nthCannotDeleted === length;
|
||||
return (
|
||||
<Section
|
||||
title={title}
|
||||
tooltip={tooltip}
|
||||
actions={
|
||||
!readonly
|
||||
? [
|
||||
<AddButton
|
||||
dataTestId={`${testId}.add-button`}
|
||||
onClick={() => {
|
||||
const newValue = (onAppend?.() ?? {
|
||||
name: '',
|
||||
}) as InputValueVO;
|
||||
append(newValue);
|
||||
}}
|
||||
/>,
|
||||
]
|
||||
: []
|
||||
}
|
||||
isEmpty={showEmptyText && isEmpty}
|
||||
emptyText={I18n.t('workflow_inputs_empty')}
|
||||
>
|
||||
<ColumnsTitleWithAction
|
||||
columns={[
|
||||
{
|
||||
title:
|
||||
paramsTitle ??
|
||||
I18n.t('workflow_detail_node_parameter_name'),
|
||||
style: { flex: 2 },
|
||||
},
|
||||
{
|
||||
title:
|
||||
expressionTitle ??
|
||||
I18n.t('workflow_detail_end_output_value'),
|
||||
style: { flex: 3 },
|
||||
},
|
||||
]}
|
||||
readonly={readonly}
|
||||
className="mb-[8px]"
|
||||
style={{
|
||||
display: isEmpty ? 'none' : 'flex',
|
||||
}}
|
||||
/>
|
||||
<FieldRows>
|
||||
{field.map((item, index) => (
|
||||
<FieldArrayItem
|
||||
key={item.key}
|
||||
disableRemove={disableRemove}
|
||||
hiddenRemove={readonly}
|
||||
onRemove={() => remove(index)}
|
||||
>
|
||||
<div style={{ flex: 2 }}>
|
||||
<NodeInputNameField
|
||||
name={`${item.name}.name`}
|
||||
placeholder={I18n.t(
|
||||
'workflow_detail_node_input_entername',
|
||||
)}
|
||||
input={item.value.input}
|
||||
inputParameters={value}
|
||||
{...nameProps}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ flex: 3 }}>
|
||||
<ValueExpressionInputField
|
||||
name={`${name}.${index}.input`}
|
||||
disabledTypes={disabledTypes}
|
||||
inputPlaceholder={inputPlaceholder}
|
||||
literalDisabled={literalDisabled}
|
||||
customReadonly={customReadonly}
|
||||
{...inputProps}
|
||||
/>
|
||||
</div>
|
||||
</FieldArrayItem>
|
||||
))}
|
||||
</FieldRows>
|
||||
</Section>
|
||||
);
|
||||
}}
|
||||
</FieldArray>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 InputValueVO } from '@coze-workflow/base';
|
||||
|
||||
import { useReadonly } from '@/nodes-v2/hooks/use-readonly';
|
||||
import { type ValidationProps } from '@/nodes-v2/components/validation/with-validation';
|
||||
import { withValidation } from '@/nodes-v2/components/validation';
|
||||
import {
|
||||
InputTree,
|
||||
type InputTreeProps,
|
||||
} from '@/form-extensions/components/input-tree';
|
||||
import { useField, withField, type FieldProps } from '@/form';
|
||||
|
||||
interface InputsTreeFieldProps extends FieldProps<InputValueVO[]> {
|
||||
title?: string;
|
||||
customReadonly?: boolean;
|
||||
testId?: string;
|
||||
}
|
||||
|
||||
const InputTreeWithValidation = withValidation(
|
||||
(props: InputTreeProps & ValidationProps) => <InputTree {...props} />,
|
||||
);
|
||||
|
||||
export const InputsTreeField = withField(
|
||||
({ title, tooltip, customReadonly, testId }: InputsTreeFieldProps) => {
|
||||
const { value, onChange, errors } = useField<InputValueVO[]>();
|
||||
const formReadonly = useReadonly();
|
||||
const readonly = formReadonly || customReadonly;
|
||||
return (
|
||||
<InputTreeWithValidation
|
||||
value={value}
|
||||
title={title}
|
||||
titleTooltip={tooltip}
|
||||
readonly={readonly}
|
||||
onChange={onChange}
|
||||
errors={errors}
|
||||
testId={testId}
|
||||
/>
|
||||
);
|
||||
},
|
||||
{
|
||||
hasFeedback: false,
|
||||
},
|
||||
);
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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 { withField } from '@/form';
|
||||
|
||||
import { NodeInputName } from './node-input-name';
|
||||
|
||||
export const NodeInputNameField = withField(NodeInputName);
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* 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 { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
useCurrentEntity,
|
||||
useService,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
import { WorkflowVariableFacadeService } from '@coze-workflow/variable';
|
||||
import { type RefExpression, useNodeTestId } from '@coze-workflow/base';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozInfoCircle } from '@coze-arch/coze-design/icons';
|
||||
import { Input, Tooltip, Typography } from '@coze-arch/coze-design';
|
||||
|
||||
import { useReadonly } from '@/nodes-v2/hooks/use-readonly';
|
||||
import {
|
||||
getUniqueName,
|
||||
getVariableName,
|
||||
} from '@/form-extensions/setters/node-input-name/utils';
|
||||
import { useField } from '@/form';
|
||||
|
||||
import type { NodeInputNameProps } from './type';
|
||||
|
||||
export const NodeInputName = ({
|
||||
style,
|
||||
input,
|
||||
inputParameters,
|
||||
initValidate = false,
|
||||
isPureText = false,
|
||||
prefix = '',
|
||||
suffix = '',
|
||||
placeholder = I18n.t('workflow_detail_node_input_entername'),
|
||||
format,
|
||||
tooltip,
|
||||
readonly: customReadonly,
|
||||
}: NodeInputNameProps) => {
|
||||
const { name, value, onChange, onBlur, errors } = useField<string>();
|
||||
|
||||
const [initialized, setInitialized] = useState<boolean>(false);
|
||||
const [userEdited, setUserEdited] = useState<boolean>(false);
|
||||
const [variableName, setVariableName] = useState<string | undefined>(value);
|
||||
const [text, setText] = useState<string | undefined>(value);
|
||||
const formReadonly = useReadonly();
|
||||
const readonly = formReadonly || customReadonly;
|
||||
|
||||
const node = useCurrentEntity();
|
||||
const variableService = useService(WorkflowVariableFacadeService);
|
||||
const { getNodeSetterId } = useNodeTestId();
|
||||
|
||||
// text 状态受控(删除节点时联动 text 的值)
|
||||
useEffect(() => {
|
||||
if (value !== text) {
|
||||
setText(value);
|
||||
}
|
||||
}, [value]);
|
||||
|
||||
const computedVariableName = getVariableName({
|
||||
input: input as RefExpression,
|
||||
prefix,
|
||||
suffix,
|
||||
format,
|
||||
node,
|
||||
variableService,
|
||||
});
|
||||
|
||||
const onInputChange = useCallback((newInputValue: string): void => {
|
||||
setUserEdited(true);
|
||||
setText(newInputValue || '');
|
||||
setVariableName(undefined);
|
||||
}, []);
|
||||
|
||||
const handleOnBlur = () => {
|
||||
onChange(text || '');
|
||||
onBlur?.();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (initValidate) {
|
||||
// 初始化写值触发校验
|
||||
onChange(value as string);
|
||||
}
|
||||
if (value) {
|
||||
setUserEdited(true);
|
||||
}
|
||||
setInitialized(true);
|
||||
}, []);
|
||||
|
||||
if (initialized && !readonly && !userEdited) {
|
||||
if (computedVariableName && computedVariableName !== variableName) {
|
||||
const computedUniqueName = getUniqueName({
|
||||
variableName: computedVariableName,
|
||||
inputParameters,
|
||||
});
|
||||
onChange(computedUniqueName);
|
||||
setVariableName(computedVariableName);
|
||||
setText(computedUniqueName);
|
||||
} else if (!computedVariableName && variableName) {
|
||||
setVariableName(undefined);
|
||||
setText(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className="flex flex-col items-start"
|
||||
style={{
|
||||
...style,
|
||||
pointerEvents: readonly ? 'none' : 'auto',
|
||||
}}
|
||||
>
|
||||
{isPureText ? (
|
||||
<>
|
||||
<Typography.Text className="h-8 leading-8 overflow-hidden whitespace-nowrap text-ellipsis">
|
||||
{value}
|
||||
</Typography.Text>
|
||||
{tooltip ? (
|
||||
<Tooltip content={tooltip}>
|
||||
<IconCozInfoCircle
|
||||
className="ml-1"
|
||||
style={{
|
||||
fontSize: 12,
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Input
|
||||
className={classNames({
|
||||
'semi-input-wrapper-error': errors?.length,
|
||||
})}
|
||||
size={'small'}
|
||||
data-testid={getNodeSetterId(name)}
|
||||
value={text}
|
||||
onChange={onInputChange}
|
||||
onBlur={handleOnBlur}
|
||||
validateStatus={errors?.length ? 'error' : undefined}
|
||||
placeholder={placeholder}
|
||||
readonly={readonly}
|
||||
/>
|
||||
{tooltip ? (
|
||||
<Tooltip content={tooltip}>
|
||||
<IconCozInfoCircle
|
||||
className="ml-1"
|
||||
style={{
|
||||
fontSize: 12,
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 { CSSProperties } from 'react';
|
||||
|
||||
import type { WorkflowNodeEntity } from '@flowgram-adapter/free-layout-editor';
|
||||
import type { InputValueVO, ValueExpression } from '@coze-workflow/base';
|
||||
|
||||
export type NodeInputNameFormat = (params: {
|
||||
name: string;
|
||||
prefix: string;
|
||||
suffix: string;
|
||||
input: ValueExpression;
|
||||
node: WorkflowNodeEntity;
|
||||
}) => string;
|
||||
|
||||
export interface NodeInputNameProps {
|
||||
readonly?: boolean;
|
||||
initValidate?: boolean;
|
||||
isPureText?: boolean;
|
||||
style?: CSSProperties;
|
||||
/** 同一层的变量表达式 */
|
||||
input: ValueExpression;
|
||||
/** 当前输入列表中所有输入项 */
|
||||
inputParameters: Array<InputValueVO>;
|
||||
/** 前缀 */
|
||||
prefix?: string;
|
||||
/** 后缀 */
|
||||
suffix?: string;
|
||||
/** 名称自定义格式化 */
|
||||
format?: NodeInputNameFormat;
|
||||
tooltip?: string;
|
||||
isError?: boolean;
|
||||
placeholder?: string;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { LoopOutputsField } from './loop-outputs-field';
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-empty-interface */
|
||||
import { type RefExpression, useNodeTestId } from '@coze-workflow/base';
|
||||
|
||||
import { LoopOutputSelect } from '@/form-extensions/components/loop-output-select';
|
||||
import { useField, withField } from '@/form';
|
||||
|
||||
interface LoopOutputSelectFieldProps {}
|
||||
|
||||
export const LoopOutputSelectField = withField<
|
||||
LoopOutputSelectFieldProps,
|
||||
RefExpression
|
||||
>(() => {
|
||||
const { name, value, onChange, readonly } = useField<RefExpression>();
|
||||
const { getNodeSetterId } = useNodeTestId();
|
||||
const testId = getNodeSetterId(name);
|
||||
|
||||
return (
|
||||
<LoopOutputSelect
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
readonly={readonly}
|
||||
testId={testId}
|
||||
/>
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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 {
|
||||
FieldArray,
|
||||
type FieldArrayRenderProps,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
import { type InputValueVO } from '@coze-workflow/base';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
|
||||
import { useReadonly } from '@/nodes-v2/hooks/use-readonly';
|
||||
import { NodeInputNameField } from '@/node-registries/common/fields/inputs-parameters-field/node-input-name';
|
||||
import { ColumnsTitleWithAction } from '@/form-extensions/components/columns-title-with-action';
|
||||
import {
|
||||
AddButton,
|
||||
FieldArrayItem,
|
||||
FieldRows,
|
||||
Section,
|
||||
type FieldProps,
|
||||
} from '@/form';
|
||||
|
||||
import { type NodeInputNameProps } from '../inputs-parameters-field/node-input-name/type';
|
||||
import { LoopOutputSelectField } from './loop-output-select-field';
|
||||
|
||||
interface LoopOutputsFieldProps extends FieldProps<InputValueVO[]> {
|
||||
title?: string;
|
||||
tooltip?: string;
|
||||
nameProps?: Partial<NodeInputNameProps>;
|
||||
}
|
||||
|
||||
export const LoopOutputsField = ({
|
||||
name,
|
||||
defaultValue,
|
||||
title,
|
||||
tooltip,
|
||||
nameProps = {},
|
||||
}: LoopOutputsFieldProps) => {
|
||||
const readonly = useReadonly();
|
||||
return (
|
||||
<FieldArray<InputValueVO> name={name} defaultValue={defaultValue}>
|
||||
{({ field }: FieldArrayRenderProps<InputValueVO>) => {
|
||||
const { value = [], delete: remove, append } = field;
|
||||
return (
|
||||
<Section
|
||||
title={title}
|
||||
tooltip={tooltip}
|
||||
actions={
|
||||
!readonly
|
||||
? [
|
||||
<AddButton
|
||||
onClick={() => {
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
append({} as InputValueVO);
|
||||
}}
|
||||
/>,
|
||||
]
|
||||
: []
|
||||
}
|
||||
isEmpty={!value || value?.length === 0}
|
||||
emptyText={I18n.t('workflow_inputs_empty')}
|
||||
>
|
||||
<ColumnsTitleWithAction
|
||||
columns={[
|
||||
{
|
||||
title: I18n.t('workflow_detail_node_parameter_name'),
|
||||
style: {
|
||||
flex: 2,
|
||||
minWidth: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: I18n.t('workflow_detail_node_parameter_value'),
|
||||
style: {
|
||||
flex: 3,
|
||||
minWidth: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: I18n.t('workflow_detail_start_variable_type'),
|
||||
style: {
|
||||
width: 90,
|
||||
},
|
||||
},
|
||||
]}
|
||||
readonly={readonly}
|
||||
className="mb-[8px]"
|
||||
/>
|
||||
<FieldRows>
|
||||
{field.map((item, index) => (
|
||||
<FieldArrayItem
|
||||
key={item.key}
|
||||
hiddenRemove={readonly}
|
||||
onRemove={() => remove(index)}
|
||||
>
|
||||
<div style={{ flex: 2 }}>
|
||||
<NodeInputNameField
|
||||
name={`${item.name}.name`}
|
||||
placeholder={I18n.t(
|
||||
'workflow_detail_node_input_entername',
|
||||
)}
|
||||
input={item.value.input}
|
||||
inputParameters={value}
|
||||
{...nameProps}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ flex: '3 1 90px', overflow: 'hidden' }}>
|
||||
<LoopOutputSelectField name={`${item.name}.input`} />
|
||||
</div>
|
||||
</FieldArrayItem>
|
||||
))}
|
||||
</FieldRows>
|
||||
</Section>
|
||||
);
|
||||
}}
|
||||
</FieldArray>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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 from 'react';
|
||||
|
||||
import type { IModelValue } from '@/typing';
|
||||
import { Section, useField, withField } from '@/form';
|
||||
import { ModelSelect } from '@/components/model-select';
|
||||
|
||||
function ModelSelectComp({
|
||||
title,
|
||||
tooltip,
|
||||
}: {
|
||||
title?: string;
|
||||
tooltip?: string;
|
||||
}) {
|
||||
const { value, onChange, readonly, name } = useField<IModelValue>();
|
||||
return (
|
||||
<Section title={title} tooltip={tooltip}>
|
||||
<ModelSelect
|
||||
name={name}
|
||||
value={value}
|
||||
onChange={e => onChange(e as IModelValue)}
|
||||
readonly={readonly}
|
||||
/>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
|
||||
export const ModelSelectField = withField(ModelSelectComp);
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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 {
|
||||
VARIABLE_TYPE_ALIAS_MAP,
|
||||
type ViewVariableType,
|
||||
} from '@coze-workflow/base';
|
||||
|
||||
import { OutputsParamDisplay } from '@/form-extensions/components/output-param-display';
|
||||
import { withField, useField } from '@/form';
|
||||
|
||||
export interface OutputsProps {
|
||||
id: string;
|
||||
name: string;
|
||||
settingOnErrorPath?: string;
|
||||
topLevelReadonly?: boolean;
|
||||
disabledTypes?: ViewVariableType[];
|
||||
title?: string;
|
||||
tooltip?: React.ReactNode;
|
||||
disabled?: boolean;
|
||||
customReadonly?: boolean;
|
||||
hiddenTypes?: ViewVariableType[];
|
||||
noCard?: boolean;
|
||||
jsonImport?: boolean;
|
||||
allowAppendRootData?: boolean;
|
||||
withDescription?: boolean;
|
||||
withRequired?: boolean;
|
||||
}
|
||||
|
||||
export const OutputsDisplayField = withField<OutputsProps>(() => {
|
||||
const { value } = useField<
|
||||
{
|
||||
name: string;
|
||||
type: string;
|
||||
required?: boolean;
|
||||
}[]
|
||||
>();
|
||||
|
||||
return (
|
||||
<OutputsParamDisplay
|
||||
options={{
|
||||
outputInfo: value?.map(item => ({
|
||||
...item,
|
||||
label: item.name ?? '',
|
||||
type: VARIABLE_TYPE_ALIAS_MAP[item.type],
|
||||
})),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { OutputsField } from './outputs';
|
||||
export { provideNodeOutputVariablesEffect } from '@/nodes-v2/materials/provide-node-output-variables';
|
||||
export { outputTreeMetaValidator } from './output-tree-meta-validator';
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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 { z } from 'zod';
|
||||
import { type ZodError } from 'zod';
|
||||
import { get } from 'lodash-es';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { type Validate } from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
/** 变量命名校验规则 */
|
||||
const outputTreeValidationRule =
|
||||
/^(?!.*\b(true|false|and|AND|or|OR|not|NOT|null|nil|If|Switch)\b)[a-zA-Z_][a-zA-Z_$0-9]*$/;
|
||||
|
||||
/** 校验逻辑 */
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
const OutputTreeMetaSchema = z.lazy(() =>
|
||||
z
|
||||
.object({
|
||||
name: z
|
||||
.string({
|
||||
required_error: I18n.t('workflow_detail_node_error_name_empty'),
|
||||
})
|
||||
.min(1, I18n.t('workflow_detail_node_error_name_empty'))
|
||||
.regex(
|
||||
outputTreeValidationRule,
|
||||
I18n.t('workflow_detail_node_error_format'),
|
||||
),
|
||||
children: z.array(OutputTreeMetaSchema).optional(),
|
||||
})
|
||||
.passthrough(),
|
||||
);
|
||||
|
||||
const omitErrorBody = (value, isBatch) => {
|
||||
// 批量,去除 children 中的 errorBody
|
||||
if (isBatch) {
|
||||
return value?.map(v => ({
|
||||
...v,
|
||||
children: v?.children?.filter(c => c?.name !== 'errorBody'),
|
||||
}));
|
||||
}
|
||||
// 单次,去除 value 中的 errorBody
|
||||
return value?.filter(v => v?.name !== 'errorBody');
|
||||
};
|
||||
|
||||
export const outputTreeMetaValidator: Validate = ({ value, formValues }) => {
|
||||
/**
|
||||
* 判断错误异常处理是否打开,如果打开需要过滤掉 errorBody 后做校验
|
||||
*/
|
||||
const { settingOnErrorIsOpen = false } = (get(formValues, 'settingOnError') ??
|
||||
{}) as { settingOnErrorIsOpen?: boolean };
|
||||
|
||||
/**
|
||||
* 根据 batch 数据判断,当前是否处于批处理状态
|
||||
*/
|
||||
const batchValue = get(formValues, 'batchMode');
|
||||
const isBatch = batchValue === 'batch';
|
||||
|
||||
const parsed = z
|
||||
.array(OutputTreeMetaSchema)
|
||||
.safeParse(settingOnErrorIsOpen ? omitErrorBody(value, isBatch) : value);
|
||||
|
||||
if (!parsed.success) {
|
||||
const errorText = JSON.stringify((parsed as { error: ZodError }).error);
|
||||
return errorText;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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 ViewVariableType } from '@coze-workflow/base';
|
||||
|
||||
import { Outputs } from '@/nodes-v2/components/outputs';
|
||||
import { withField, useField, useWatch } from '@/form';
|
||||
|
||||
export interface OutputsProps {
|
||||
id?: string;
|
||||
name: string;
|
||||
settingOnErrorPath?: string;
|
||||
topLevelReadonly?: boolean;
|
||||
disabledTypes?: ViewVariableType[];
|
||||
title?: string;
|
||||
tooltip?: React.ReactNode;
|
||||
disabled?: boolean;
|
||||
disabledTooltip?: string;
|
||||
customReadonly?: boolean;
|
||||
hiddenTypes?: ViewVariableType[];
|
||||
noCard?: boolean;
|
||||
jsonImport?: boolean;
|
||||
allowAppendRootData?: boolean;
|
||||
withDescription?: boolean;
|
||||
withRequired?: boolean;
|
||||
addItemTitle?: string;
|
||||
allowDeleteLast?: boolean;
|
||||
emptyPlaceholder?: string;
|
||||
defaultCollapse?: boolean;
|
||||
batchMode?: string;
|
||||
needAppendChildWhenNodeIsPreset?: boolean;
|
||||
/**
|
||||
* 是否可以配置默认值
|
||||
*/
|
||||
withDefaultValue?: boolean;
|
||||
/**
|
||||
* 默认展开的参数名
|
||||
*/
|
||||
defaultExpandParams?: string[];
|
||||
/**
|
||||
* 列宽比 如 6:4 代表名称占6份,类型占4份
|
||||
*/
|
||||
columnsRatio?: string;
|
||||
maxLimit?: number;
|
||||
}
|
||||
|
||||
export const OutputsField = withField<OutputsProps>(
|
||||
({
|
||||
id = 'outputs',
|
||||
topLevelReadonly = false,
|
||||
settingOnErrorPath = 'settingOnError.settingOnErrorIsOpen',
|
||||
disabledTypes = [],
|
||||
hiddenTypes,
|
||||
title,
|
||||
tooltip,
|
||||
disabled,
|
||||
customReadonly = false,
|
||||
noCard,
|
||||
jsonImport,
|
||||
allowAppendRootData,
|
||||
withDescription = true,
|
||||
withRequired,
|
||||
batchMode,
|
||||
...props
|
||||
}: OutputsProps) => {
|
||||
const { value, onChange, readonly, onBlur, errors } = useField();
|
||||
const settingOnErrorIsOpen = useWatch(settingOnErrorPath);
|
||||
|
||||
return (
|
||||
<Outputs
|
||||
id={id}
|
||||
value={value}
|
||||
onChange={v => {
|
||||
onChange?.(v);
|
||||
// 保证 blur 时触发校验, 直接传 onBlur 不生效
|
||||
onBlur?.();
|
||||
}}
|
||||
title={title}
|
||||
titleTooltip={tooltip}
|
||||
topLevelReadonly={topLevelReadonly}
|
||||
disabledTypes={disabledTypes}
|
||||
hiddenTypes={hiddenTypes}
|
||||
readonly={readonly || customReadonly}
|
||||
disabled={disabled}
|
||||
needErrorBody={settingOnErrorIsOpen}
|
||||
noCard={noCard}
|
||||
batchMode={batchMode}
|
||||
jsonImport={jsonImport}
|
||||
allowAppendRootData={allowAppendRootData}
|
||||
withDescription={withDescription}
|
||||
withRequired={withRequired}
|
||||
errors={errors}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -0,0 +1,7 @@
|
||||
.parameters-title {
|
||||
width: calc(100% - 12px);
|
||||
}
|
||||
|
||||
.parameters-title-readonly {
|
||||
width: calc(100% - 32px);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user