chore: replace all cn comments of fe to en version by volc api (#320)

This commit is contained in:
tecvan
2025-07-31 10:32:15 +08:00
committed by GitHub
parent 716ec0cba8
commit 71f6245a01
2960 changed files with 15545 additions and 15545 deletions

View File

@@ -49,7 +49,7 @@ export const Icon = ({ type, icon }: { type: NodeType; icon?: string }) => {
if (type === NodeType.DATABASE) {
return <IconDatabase />;
}
// 插件来自商店和资源库场景默认图标不同
// Plugin from store and repository scenes have different default icons
if (type === NodeType.PLUGIN) {
return <IconPlugin />;
}

View File

@@ -44,7 +44,7 @@ const { Text } = Typography;
export const BaseNode = ({ node }: { node: FlowNodeEntity }) => {
const nodeRender = useCustomNodeRender();
const treeService = useService<TreeService>(TreeService);
// schema 信息存储
// Schema Information Store
const extraInfo = nodeRender.getExtInfo();
const [hoverNode, setHoverNode] = useState(false);
const { renderLinkNode } = useContext(TreeContext);
@@ -86,16 +86,16 @@ export const BaseNode = ({ node }: { node: FlowNodeEntity }) => {
}, []);
const handleClick = (e: React.MouseEvent) => {
// 1. 取消其他选中的线条
// 1. Uncheck other selected lines
hoverService.backgroundClick();
// 2. 选中节点,重新计算需要选中的线条
// 2. Select the node and recalculate the lines that need to be selected.
hoverService.selectNode(node);
e.stopPropagation();
};
const handleMouseEnter = () => {
setHoverNode(true);
// 判断节点类型
// Determine the node type
if (
node.flowNodeType !== 'custom' ||
edges.some(edge => edge.from === node.id)
@@ -172,7 +172,7 @@ export const BaseNode = ({ node }: { node: FlowNodeEntity }) => {
/>
</div>
) : null}
{/* 不同版本的 tag */}
{/* Different versions of tags */}
{isOtherVersion && !activated ? (
<div className={s['diff-tag']}>
{activatedVersion === extraInfo.version

View File

@@ -50,8 +50,8 @@ export function Collapse(props: Omit<CollapseProps, 'collapsed'>): JSX.Element {
const { edges: originEdges } = treeService;
const edges = treeService.getUnCollapsedEdges();
// 如果没有子元素,就是折叠了。
// 还要判断是否有线条连线
// If there are no child elements, it is collapsed.
// Also determine whether there are lines connecting
const collapsed =
!collapseNode?.children?.length &&
!collapseNode.next &&
@@ -77,9 +77,9 @@ export function Collapse(props: Omit<CollapseProps, 'collapsed'>): JSX.Element {
}
});
}
// 节点重绘
// Node redraw
treeService.treeToFlowNodeJson();
// 线条重绘
// Line redrawing
rerenderLines();
};
@@ -95,12 +95,12 @@ export function Collapse(props: Omit<CollapseProps, 'collapsed'>): JSX.Element {
}
});
}
// 节点重绘
// Node redraw
treeService.treeToFlowNodeJson();
rerenderLines();
};
// flow-labels-layer 不更新
// flow-labels-layer is not updated
useEffect(() => {
const disposable = entityManager.onEntityChange(() => {
refresh();

View File

@@ -38,7 +38,7 @@ export const LinesRenderer = ({
isViewportVisible: (bounds: Rectangle) => boolean;
version: number;
}) => {
// 单线条选中
// Single line selection
const [activeLine, setActiveLine] = useState<string[]>([]);
const renderState = useConfigEntity<CustomRenderStateConfigEntity>(
@@ -50,7 +50,7 @@ export const LinesRenderer = ({
setActiveLine(renderState.activeLines);
}, [renderState.activeLines]);
// semi 弹窗偏移计算有误,这里线条直接全部展示
// The offset calculation of the semi pop-up window is wrong, and the lines here are directly displayed.
const visibleLines = lines.filter(line => {
const bounds = Rectangle.createRectangleWithTwoPoints(
line.fromPoint,
@@ -75,7 +75,7 @@ export const LinesRenderer = ({
overflow="visible"
viewBox={viewBox}
xmlns="http://www.w3.org/2000/svg"
// 确保线条数量变化的时候,强制刷新
// Make sure to force a refresh when the number of lines changes
key={nanoid(5)}
>
{allLines.map(line => {

View File

@@ -41,7 +41,7 @@ function getPath(params: {
const { controls } = params;
// 渲染端点位置计算
// Render endpoint position calculation
const renderToPos: IPoint = { x: toPos.x, y: toPos.y };
const getPathData = (): string => {

View File

@@ -26,9 +26,9 @@ export enum BezierControlType {
const CONTROL_MAX = 300;
/**
* 获取贝塞尔曲线垂直方向的控制节点
* @param fromPos 起始点
* @param toPos 终点
* Get the control node for the vertical direction of the Bézier curve
* @param fromPos starting point
* @param toPos destination
*/
export function getBezierVerticalControlPoints(
fromPos: IPoint,

View File

@@ -60,12 +60,12 @@ export const Interactive = () => {
function handleUpdateInteractiveType(interType: InteractiveType) {
if (interType === InteractiveType.Mouse) {
// 鼠标优先交互模式:更新状态 & 设置小手
// Mouse First Interactive Mode: Update Status & Set Small Hands
playground.editorState.changeState(
EditorState.STATE_MOUSE_FRIENDLY_SELECT.id,
);
} else if (interType === InteractiveType.Pad) {
// 触控板优先交互模式:更新状态 & 设置箭头
// Trackpad Priority Interaction Mode: Update Status & Settings Arrows
playground.editorState.changeState(EditorState.STATE_SELECT.id);
}
setInteractiveType(interType);
@@ -75,7 +75,7 @@ export const Interactive = () => {
useEffect(() => {
handleUpdateMouseScrollDelta(zoom => zoom / 20);
// 从缓存读取交互模式,应用生效
// Read interactive mode from cache, application takes effect
const preferInteractiveType = getPreferInteractiveType();
handleUpdateInteractiveType(preferInteractiveType as InteractiveType);
// eslint-disable-next-line react-hooks/exhaustive-deps -- init
@@ -92,7 +92,7 @@ export const Interactive = () => {
value={interactiveType}
onChange={value => {
setInteractiveType(value);
// 目前逻辑是,只从画布读取设置。
// The current logic is to only read settings from the canvas.
// setPreferInteractiveType(value);
handleUpdateInteractiveType(value as unknown as InteractiveType);
}}

View File

@@ -33,7 +33,7 @@ export const ZoomSelect = () => {
const zoomValue = tools.zoom * 100;
return zoomValue.toFixed(0);
}, [tools.zoom]);
// 为了覆盖 coze design 的样式,不能用 tailwind css
// In order to override the style of the cozed design, you cannot use tailwind css.
const zoomOptionStyle: CSSProperties = {
padding: '8px',
lineHeight: '16px',

View File

@@ -17,4 +17,4 @@
export const STROKE_WIDTH = 2;
export const ARROW_HEIGHT = 7;
export const LINE_CLASS_NAME = 'resource-tree-custom-line';
export const LINE_HOVER_DISTANCE = 8; // 线条 hover 的最小检测距离
export const LINE_HOVER_DISTANCE = 8; // Minimum detection distance of line hover

View File

@@ -26,7 +26,7 @@ interface NodeRenderState {
activatedNode?: FlowNodeEntity;
}
/**
* 渲染相关的全局状态管理
* Rendering-related global state management
*/
export class CustomRenderStateConfigEntity extends ConfigEntity<
NodeRenderState,

View File

@@ -20,7 +20,7 @@ interface CustomRenderState {
version: number;
}
/**
* 渲染相关的全局状态管理
* Rendering-related global state management
*/
export class CustomRenderStateEntity extends ConfigEntity<CustomRenderState> {
static type = 'CustomRenderStateEntity';

View File

@@ -43,11 +43,11 @@ export function createFixedLayoutPreset(
opts = { ...DEFAULT, ...opts };
let plugins: Plugin[] = [createOperationPlugin(opts)];
/**
* 加载默认编辑器配置
* Load default editor configuration
*/
plugins = createDefaultPreset(opts, plugins)(ctx);
/*
* 加载固定布局画布模块
* Load fixed layout canvas module
* */
plugins.push(
createPlaygroundPlugin<FixedLayoutPluginContext>({
@@ -66,15 +66,15 @@ export function createFixedLayoutPreset(
},
onInit: _ctx => {
_ctx.playground.registerLayers(
FlowNodesContentLayer, // 节点内容渲染
FlowNodesTransformLayer, // 节点位置偏移计算
FlowNodesContentLayer, // Node content rendering
FlowNodesTransformLayer, // Node position offset calculation
);
if (!opts.scroll?.disableScrollLimit) {
// 控制滚动范围
// Control scroll range
_ctx.playground.registerLayer(FlowScrollLimitLayer);
}
if (!opts.scroll?.disableScrollBar) {
// 控制条
// control bar
_ctx.playground.registerLayer(FlowScrollBarLayer);
}
if (opts.nodeRegistries) {

View File

@@ -30,7 +30,7 @@ import {
export interface FixedLayoutPluginContext extends EditorPluginContext {
document: FlowDocument;
/**
* 提供对画布节点相关操作方法, 并 支持 redo/undo
* Provide operation methods related to canvas nodes, and support redo/undo
*/
operation: FlowOperationService;
clipboard: ClipboardService;
@@ -39,14 +39,14 @@ export interface FixedLayoutPluginContext extends EditorPluginContext {
}
/**
* 固定布局配置
* fixed layout configuration
*/
export interface FixedLayoutProps
extends EditorProps<FixedLayoutPluginContext, FlowDocumentJSON> {
history?: FixedHistoryPluginOptions<FixedLayoutPluginContext> & {
disableShortcuts?: boolean;
};
defaultLayout?: FlowLayoutDefault | string; // 默认布局
defaultLayout?: FlowLayoutDefault | string; // default layout
}
export const DEFAULT: FixedLayoutProps =

View File

@@ -38,50 +38,50 @@ export class FlowRegisters
implements FlowDocumentContribution, FlowRendererContribution
{
/**
* 注册数据层
* registration data layer
* @param document
*/
registerDocument(document: FlowDocument) {
/**
* 注册节点 (ECS - Entity)
* Registered Node (ECS - Entity)
*/
document.registerFlowNodes(
// 等待简化
FixedLayoutRegistries.RootRegistry, // 根节点
FixedLayoutRegistries.StartRegistry, // 开始节点
FixedLayoutRegistries.DynamicSplitRegistry, // 动态分支(并行、排他)
FixedLayoutRegistries.BlockRegistry, // 单条 block 注册
FixedLayoutRegistries.InlineBlocksRegistry, // 多个 block 组成的 block 列表
FixedLayoutRegistries.BlockIconRegistry, // icon 节点,如条件分支的菱形图标
// FixedLayoutRegistries.EndRegistry, // 结束节点
FixedLayoutRegistries.EmptyRegistry, // 占位节点
// Wait for Simplification
FixedLayoutRegistries.RootRegistry, // root node
FixedLayoutRegistries.StartRegistry, // start node
FixedLayoutRegistries.DynamicSplitRegistry, // Dynamic branching (parallel, exclusive)
FixedLayoutRegistries.BlockRegistry, // Single block registration
FixedLayoutRegistries.InlineBlocksRegistry, // A list of multiple blocks
FixedLayoutRegistries.BlockIconRegistry, // Icon nodes, such as diamond icons for conditional branches
// FixedLayoutRegistries. EndRegistry,//End Node
FixedLayoutRegistries.EmptyRegistry, // placeholder node
);
/**
* 注册节点数据 (ECS - Component)
* Registered Node Data (ECS - Components)
*/
document.registerNodeDatas(
FlowNodeRenderData, // 渲染节点相关数据
FlowNodeTransitionData, // 线条绘制数据
FlowNodeTransformData, // 坐标计算数据
FlowNodeRenderData, // Render node related data
FlowNodeTransitionData, // line drawing data
FlowNodeTransformData, // coordinate calculation data
);
}
/**
* 注册渲染层
* Register the render layer
* @param renderer
*/
registerRenderer(renderer: FlowRendererRegistry) {
/**
* 注册 layer (ECS - System)
* Registration layer (ECS - System)
*/
renderer.registerLayers(
FlowNodesTransformLayer, // 节点位置渲染
FlowNodesContentLayer, // 节点内容渲染
FlowLinesLayer, // 线条渲染
// FlowLabelsLayer, // Label 渲染
PlaygroundLayer, // 画布基础层,提供缩放、手势等能力
FlowScrollLimitLayer, // 控制滚动范围
FlowScrollBarLayer, // 滚动条
FlowNodesTransformLayer, // Node position rendering
FlowNodesContentLayer, // Node content rendering
FlowLinesLayer, // line rendering
// FlowLabelsLayer,//Label rendering
PlaygroundLayer, // Canvas base layer, providing zoom, gesture, and more
FlowScrollLimitLayer, // Control scroll range
FlowScrollBarLayer, // scroll bar
);
}
}

View File

@@ -30,56 +30,56 @@ import { getStoreNode } from '../utils';
export interface NodeRenderReturnType {
/**
* 当前节点 (如果是 icon 则会返回它的父节点)
* The current node (if it is an icon, it will return its parent node)
*/
node: FlowNodeEntity;
/**
* 节点是否激活
* Is the node active?
*/
activated: boolean;
/**
* 节点是否展开
* Is the node expanded?
*/
expanded: boolean;
/**
* 鼠标进入, 主要用于控制 activated 状态
* Mouse entry, mainly used to control the activated state
*/
onMouseEnter: (e: React.MouseEvent) => void;
/**
* 鼠标离开, 主要用于控制 activated 状态
* The mouse leaves, mainly used to control the activated state
*/
onMouseLeave: (e: React.MouseEvent) => void;
/**
* 渲染表单,只有节点引擎开启才能使用
* Render the form, which can only be used if the node engine is turned on
*/
form: NodeFormProps<any> | undefined;
/**
* 获取节点的扩展数据
* Get the extended data of the node
*/
getExtInfo<T = any>(): T;
/**
* 更新节点的扩展数据
* Update the extended data of the node
* @param extInfo
*/
updateExtInfo<T = any>(extInfo: T): void;
/**
* 展开/收起节点
* Expand/Collapse Nodes
* @param expanded
*/
toggleExpand(): void;
/**
* 全局 readonly 状态
* Global readonly state
*/
readonly: boolean;
}
/**
* 自定义 useNodeRender
* 不区分 blockIcon inlineBlocks
* Custom useNodeRender
* Do not distinguish between blockIcon and inlineBlocks
*/
export function useCustomNodeRender(
nodeFromProps?: FlowNodeEntity,

View File

@@ -50,13 +50,13 @@ export const useEditorProps = (data?: any, json?: any) =>
[FlowRendererKey.BRANCH_ADDER]: () => null,
[FlowRendererKey.DRAG_NODE]: () => null,
},
renderDefaultNode: BaseNode, // 节点渲染
renderDefaultNode: BaseNode, // Node rendering
},
onReady(ctx) {
const treeService = ctx.get<TreeService>(TreeService);
treeService.transformSchema(json);
treeService.treeToFlowNodeJson();
// 强制 resize 生效
// Forced resizing takes effect
setTimeout(() => {
ctx.playground.resize();
}, 100);
@@ -67,12 +67,12 @@ export const useEditorProps = (data?: any, json?: any) =>
},
plugins: () => [
/**
* 自定义线条插件
* Custom Line Plugin
*/
createCustomLinesPlugin({}),
/**
* Minimap plugin
* 缩略图插件
* Thumbnail plugin
*/
createMinimapPlugin({
disableLayer: true,

View File

@@ -18,7 +18,7 @@ import { type FlowDocumentJSON } from '@flowgram-adapter/fixed-layout-editor';
// only for test
export const initialData: FlowDocumentJSON = {
nodes: [
// 开始节点
// start node
{
id: 'start_0',
type: 'split',
@@ -31,7 +31,7 @@ export const initialData: FlowDocumentJSON = {
id: 'noop',
type: 'block',
blocks: [
// 分支节点
// branch node
{
id: 'condition_0',
type: 'split',

View File

@@ -48,7 +48,7 @@ export class FlowLinesLayer extends Layer {
protected declare renderState: CustomRenderStateEntity;
/**
* 可视区域变化
* Visual area change
*/
onViewportChange = throttle(() => {
this.render();
@@ -85,7 +85,7 @@ export class FlowLinesLayer extends Layer {
render(): JSX.Element {
const isViewportVisible = this.config.isViewportVisible.bind(this.config);
// 还没初始化
// Not initialized yet
if (this.documentTransformer?.loading) {
return <></>;
}

View File

@@ -21,7 +21,7 @@ import {
type FlowNodeRegister,
} from '@flowgram-adapter/fixed-layout-editor';
/**
* BlockOrderIcon 的分支节点
* BlockOrderIcon-free branch nodes
*/
export const Split: FlowNodeRegister = {
type: 'split',
@@ -29,11 +29,11 @@ export const Split: FlowNodeRegister = {
onBlockChildCreate(
originParent: FlowNodeEntity,
blockData: FlowNodeJSON,
addedNodes: FlowNodeEntity[] = [], // 新创建的节点都要存在这里
addedNodes: FlowNodeEntity[] = [], // All newly created nodes must exist here
) {
const { document } = originParent;
const parent = document.getNode(`$inlineBlocks$${originParent.id}`);
// 块节点会生成一个空的 Block 节点用来切割 Block
// The block node will generate an empty block node to cut the block.
const proxyBlock = document.addNode({
id: `$block$${blockData.id}`,
type: FlowNodeBaseType.BLOCK,

View File

@@ -76,7 +76,7 @@ export class CustomHoverService {
}
/**
* 根据鼠标位置计算和线条的间距
* Calculate and line spacing based on mouse position
*/
getCloseInLineFromMousePos(
mousePos: IPoint,
@@ -123,7 +123,7 @@ export class CustomHoverService {
}
}
// 折叠策略:访问所有连线的元素,同时访问其父元素,执行 collapse
// Collapse strategy: access all connected elements and access their parent elements simultaneously, performing collapse.
hoverCollapse(from?: FlowNodeEntity) {
this.onHoverCollapseEmitter.fire(from);
}
@@ -143,7 +143,7 @@ export class CustomHoverService {
const selectNodes = this.getRelatedNodes(node);
this.renderStateEntity.setSelectNodes(selectNodes);
this.renderStateEntity.setActivatedNode(node);
// 高亮所有相关的线条
// Highlight all relevant lines
const activeLines: string[] = [];
this.linesManager.lines.map(line => {
const fromInclude = selectNodes.includes(line.from.id);
@@ -164,9 +164,9 @@ export class CustomHoverService {
}
this.edges.forEach(edge => {
if (edge.to === getTreeIdFromNodeId(node.id)) {
// push 额外线条
// Push extra lines
ancArr.push(edge.from);
// 遍历之前的节点信息
// Traverse the previous node information
const fromNode = this.document.getNode(getNodeIdFromTreeId(edge.from));
if (fromNode) {
const arr = this.traverseAncestors(fromNode);
@@ -195,7 +195,7 @@ export class CustomHoverService {
};
/**
* 根据当前树结构,遍历节点并且选中
* According to the current tree structure, iterate through the nodes and select
*/
getRelatedNodes = (node: FlowNodeEntity) => {
const parentRelated = this.traverseAncestors(node);

View File

@@ -36,7 +36,7 @@ export class CustomLinesManager {
@inject(EntityManager) declare entityManager: EntityManager;
// 额外的连线
// Additional connection
@inject(TreeService) declare treeService: TreeService;
get edges(): EdgeItem[] {
@@ -58,7 +58,7 @@ export class CustomLinesManager {
}
/**
* 过滤其他的非渲染节点
* Filter other non-rendering nodes
*/
filterTreeNode(nodes: FlowNodeEntity[]) {
return nodes.filter(
@@ -94,7 +94,7 @@ export class CustomLinesManager {
if (node.flowNodeType === 'root') {
queue.push(node.children[0]);
} else if (node.flowNodeType === 'split') {
// 分支逻辑特殊处理
// Branch logic special handling
const inlineBlocksChildren = node.children[1]?.children || [];
const branchChildren =
inlineBlocksChildren
@@ -138,7 +138,7 @@ export class CustomLinesManager {
}
renderLines() {
// 下一帧渲染,保证线条数据最新
// The next frame is rendered to ensure the latest line data
requestAnimationFrame(() => {
const lines = this.bfsAddLine(this.document.originTree.root);
const extraLines: CustomLine[] = (this.edges || [])

View File

@@ -53,9 +53,9 @@ export class TreeService {
edges: EdgeItem[] = [];
treeHistory: {
// 唯一标识符
// unique device identifier
id: string;
// 判断是否已经存在的两个条件
// To determine whether two conditions already exist
resourceId: string;
version?: string;
depth: number;
@@ -73,7 +73,7 @@ export class TreeService {
}
/**
* 用于检查是否有重复项
* Used to check for duplicates
*/
getNodeDuplicateFromTree = (id: string, version?: string) => {
let duplicate = false;
@@ -122,7 +122,7 @@ export class TreeService {
}
/**
* 处理 knowledgeplugintable 的逻辑
* Handling knowledge, plugins, table logic
*/
transformDuplicateInfo = (
id: string,
@@ -144,13 +144,13 @@ export class TreeService {
} else {
newSchema = transformTable(depth + 1, info);
}
// 如果重复,判断添加线还是节点
// If repeated, determine whether to add a line or a node
if (duplicate) {
for (const [i, d] of dupDepth.entries()) {
// 只要有一个匹配,就加线。
// 兜底走加节点的逻辑
// As long as there is a match, add the line.
// The logic of adding nodes at the bottom
if (depth + 1 === d) {
// 存到线条中
// Save in line
this.edges.push({
from: fromId,
to: dupId[i],
@@ -160,7 +160,7 @@ export class TreeService {
}
return newSchema;
}
// 否则,正常往 blocks 里添加数据
// Otherwise, add data to blocks normally
return newSchema;
};
@@ -202,7 +202,7 @@ export class TreeService {
}
}
const loop = node.id && isLoop(node.id, this.globalJson);
// 重复节点,停止继续往下
// Repeat node, stop, continue down
const endData = {
id: nodeId,
type: 'custom',
@@ -315,7 +315,7 @@ export class TreeService {
undefined,
nodeId,
);
// 检测 workflow 的重复
// Detect duplication of workflow
if (subWorkflowSchema) {
this.treeHistory.push({
id: subWorkflowSchema.id,
@@ -353,7 +353,7 @@ export class TreeService {
};
};
// 展开所有的子元素
// Expand all child elements
dfsCloneCollapsedOpen(node: TreeNode): TreeNode {
const children = node.children?.map(c => this.dfsCloneCollapsedOpen(c));
return {
@@ -366,14 +366,14 @@ export class TreeService {
};
}
// 根据 edges移动节点到另一个 TreeNode 的 children 下。
// 需要将内部的 collapsed 全部变成 open
// According to edges, move the node to the children of another TreeNode.
// It needs to be collapsed and opened
cloneNode(node: TreeNode) {
return this.dfsCloneCollapsedOpen(node);
}
/**
* 绑定父元素 parent
* Bind parent element parent
*/
bindTreeParent(node: TreeNode, parent?: TreeNode) {
if (parent) {
@@ -393,7 +393,7 @@ export class TreeService {
}
/**
* 初始化数据,将数据从后端数据 json 变成 tree 结构
* Initialize the data and turn the data from the back-end data json into a tree structure
*/
transformSchema(json: DependencyTree) {
this.globalJson = json;
@@ -465,7 +465,7 @@ export class TreeService {
this.addNode(block, addItem);
});
}
// 可能因此原本设置为结束的节点现在有 child 了
// Perhaps because of this, the node that was originally set to end now has children
if (json.blocks?.length) {
if (json.type === 'custom') {
json.type = 'split';

View File

@@ -28,23 +28,23 @@ export interface CustomLine {
}
/**
* 资源 icon 类型
* Resource icon type
*/
export enum NodeType {
WORKFLOW, // 工作流
CHAT_FLOW, // 对话流
KNOWLEDGE, // 知识库
PLUGIN, // 插件
DATABASE, // 数据库
WORKFLOW, // Workflow
CHAT_FLOW, // conversation flow
KNOWLEDGE, // Knowledge Base
PLUGIN, // plugin
DATABASE, // database
}
/**
* 资源来源
* source of resources
*/
export enum DependencyOrigin {
LIBRARY, // 资源库
LIBRARY, // resource library
APP, // App / Project
SHOP, // 商店
SHOP, // store
}
export interface EdgeItem {

View File

@@ -20,7 +20,7 @@ export interface TreeNode {
id: string;
type: string;
meta?: FlowNodeMeta;
// collapseddepth 放在 data
// Collapsed, depth in data
data: Record<string, any>;
parent: TreeNode[];
children?: TreeNode[];

View File

@@ -125,18 +125,18 @@ const findNode = (
};
/**
* 判断是否循环
* Determine whether to cycle
*/
export const isLoop = (id: string, json: DependencyTree) => {
const node = findNode(json, id);
// 只有 workflow 会存在循环,因此只需要关注 workflow_version
// Only workflow has loops, so just focus on workflow_version
if (node?.dependency?.workflow_version?.length) {
return hasSameId(id, node.dependency.workflow_version, json);
}
return false;
};
// 判断循环
// judgment loop
const hasSameId = (
id: string,
arr: WorkflowVersionInfo[],