utils.ts
Overview
The utils.ts file is a utility module designed to support the construction, manipulation, and management of graph nodes and edges within a flow-based application, likely involving a Directed Acyclic Graph (DAG) or workflow system. The utilities in this file mainly handle the conversion between DSL (Domain-Specific Language) components and graph representations, manage node and edge relationships, clean and prepare operator parameters, and assist in UI-related operations such as positioning and naming nodes.
This file is heavily oriented towards operators and nodes in a flow graph, particularly for a system involving RAG (Retrieval-Augmented Generation) flows, categorization, and iteration operators. It integrates with React flow components (@xyflow/react), uses Ant Design forms (antd), and leverages several utility libraries such as Lodash and UUID for common tasks.
Detailed Explanations
Imports and Dependencies
Imports various types and interfaces related to DSL components, categorization, nodes, edges, and operators.
Uses utility functions like
removeUselessFieldsFromValuesfrom another utility module for form processing.Uses React Flow's
Node,Edge, and positioning types.Leverages Ant Design form types for form manipulation.
Uses humanId to generate human-readable unique IDs.
Uses Lodash utilities (
curry,get,intersectionWith,isEqual,sample) andpipefrom lodash/fp.Uses UUID for generating unique edge IDs.
Imports constants for operators and positions.
Functions
1. buildEdges
const buildEdges = (
operatorIds: string[],
currentId: string,
allEdges: Edge[],
isUpstream = false,
componentName: string,
nodeParams: Record<string, unknown>,
)
Purpose: Constructs and adds edges to the flow graph based on upstream or downstream operator IDs.
Parameters:
operatorIds: Array of operator IDs to connect with.currentId: The ID of the current node.allEdges: The existing list of edges to append new edges.isUpstream: Boolean indicating if building edges upstream or downstream.componentName: Name of the component/operator.nodeParams: Parameters associated with the node.
Behavior: Prevents duplicate edges; handles special case for
Categorizeoperator to assignsourceHandlebased on category descriptions.Usage example:
buildEdges(['node1', 'node2'], 'currentNode', edgesArray, false, 'Categorize', nodeParams);
2. buildNodesAndEdgesFromDSLComponents
export const buildNodesAndEdgesFromDSLComponents = (data: DSLComponents) => { ... }
Purpose: Converts a DSL representation of components into graph nodes and edges usable by the React Flow graph.
Parameters:
data: The DSL components object mapping node IDs to component information.
Returns: An object containing arrays of
nodesandedges.Details:
Iterates over DSL components.
For each, creates a
Nodewith default position (0,0), type mapped fromNodeMap.Builds edges both upstream and downstream using
buildEdges.
Usage example:
const { nodes, edges } = buildNodesAndEdgesFromDSLComponents(dslComponents);
3. buildComponentDownstreamOrUpstream
const buildComponentDownstreamOrUpstream = (
edges: Edge[],
nodeId: string,
isBuildDownstream = true,
) => { ... }
Purpose: Extracts either downstream or upstream connected node IDs from edges for a given node.
Parameters:
edges: Array of edges.nodeId: The node from which to find connected nodes.isBuildDownstream: If true, returns downstream nodes; else upstream.
Returns: Array of connected node IDs.
4. removeUselessDataInTheOperator (curried function)
const removeUselessDataInTheOperator = curry(
(operatorName: string, params: Record<string, unknown>) => { ... }
);
Purpose: Cleans operator parameters by removing unnecessary fields for specific operators (
GenerateandCategorize).Parameters:
operatorName: The name of the operator.params: The parameters object to clean.
Returns: Cleaned parameters object.
Note: Uses
removeUselessFieldsFromValuesimported from form utilities.
5. buildOperatorParams
const buildOperatorParams = (operatorName: string) =>
pipe(removeUselessDataInTheOperator(operatorName));
Purpose: A pipeline for preparing operator parameters, currently only cleans parameters.
Parameters:
operatorNamestring.Returns: A function that takes parameters and returns cleaned parameters.
6. buildDslComponentsByGraph
export const buildDslComponentsByGraph = (
nodes: RAGFlowNodeType[],
edges: Edge[],
oldDslComponents: DSLComponents,
): DSLComponents => { ... }
Purpose: Constructs a DSL components object based on the current graph nodes and edges, updating parameters and connectivity.
Parameters:
nodes: Array of current nodes in the graph.edges: Array of current edges.oldDslComponents: Previous DSL components to retain some existing data.
Returns: Updated DSL components object.
Details: Filters out nodes labeled as
Note, processes each node's form data withbuildOperatorParams, and recreates upstream and downstream relationships.
7. receiveMessageError
export const receiveMessageError = (res: any) => boolean;
Purpose: Checks if a response indicates an error based on HTTP status and response code.
Parameters:
res- the response object.Returns:
trueif response status is not 200 or code is not 0, elsefalse.
8. replaceIdWithText
export const replaceIdWithText = (
obj: Record<string, unknown> | unknown[] | unknown,
getNameById: (id?: string) => string | undefined,
) => { ... }
Purpose: Recursively traverses an object or array and replaces string IDs with corresponding text labels.
Parameters:
obj: Object or array to process.getNameById: Callback function to get text by ID.
Returns: New object/array with IDs replaced by text.
Use case: Helpful for displaying user-friendly names instead of IDs.
9. isEdgeEqual
export const isEdgeEqual = (previous: Edge, current: Edge) => boolean;
Purpose: Compares two edges to determine if they are equal, considering source, target, and sourceHandle.
Returns: Boolean.
10. buildNewPositionMap
export const buildNewPositionMap = (
currentKeys: string[],
previousPositionMap: Record<string, IPosition>,
) => { ... }
Purpose: Generates a new position map for nodes, assigning new positions for newly added keys while preserving positions of existing keys.
Parameters:
currentKeys: List of current node keys.previousPositionMap: Map of previous node positions.
Returns: An object containing:
intersectionKeys: Keys common to old and new.newPositionMap: Positions for new keys.
Details: Uses predefined anchor point positions and samples unused indexes for new positions.
11. isKeysEqual
export const isKeysEqual = (currentKeys: string[], previousKeys: string[]) => boolean;
Purpose: Checks if two arrays of keys are equal regardless of order.
Returns: Boolean.
12. getOperatorIndex
export const getOperatorIndex = (handleTitle: string) => string | undefined;
Purpose: Extracts the index (last space-separated segment) from a handle title string.
Example:
"Case 3"returns"3".
13. getOtherFieldValues
export const getOtherFieldValues = (
form: FormInstance,
formListName: string = 'items',
field: FormListFieldData,
latestField: string,
) => string[];
Purpose: Retrieves values of a specific field from all form list items except the current item.
Parameters:
form: Ant Design form instance.formListName: Name of the form list field.field: Current form list field.latestField: Field name to retrieve values from.
Returns: Array of values excluding the current field's value.
14. generateSwitchHandleText
export const generateSwitchHandleText = (idx: number) => string;
Purpose: Produces a string label for switch handles in the format
"Case n".Example:
generateSwitchHandleText(0)returns"Case 1".
15. getNodeDragHandle
export const getNodeDragHandle = (nodeType?: string) => string | undefined;
Purpose: Returns a CSS selector for the drag handle of a node type.
Details: Returns
.note-drag-handleforNotenodes; otherwise, undefined.
16. generateNodeNamesWithIncreasingIndex
export const generateNodeNamesWithIncreasingIndex = (
name: string,
nodes: RAGFlowNodeType[],
) => string;
Purpose: Generates a new node name with an incremented index suffix based on existing node names.
Parameters:
name: Base name string.nodes: Array of existing nodes.
Returns: String in format
name_indexwhereindexis the smallest unused integer.Details: Parses existing node names that match pattern
name_index, finds gaps in indexes, and returns the next available index.
17. duplicateNodeForm
export const duplicateNodeForm = (nodeData?: RAGFlowNodeType['data']) => RAGFlowNodeType['data'];
Purpose: Creates a copy of a node's form data, clearing downstream references for certain operators (
CategorizeandRelevant).Parameters:
nodeData- node data object.Returns: Cloned node data with sanitized form.
18. getDrawerWidth
export const getDrawerWidth = () => string | number;
Purpose: Determines the width of a UI drawer component based on window width.
Returns:
'40%'if window width > 1278px; otherwise a fixed pixel width470.
19. needsSingleStepDebugging
export const needsSingleStepDebugging = (label: string) => boolean;
Purpose: Checks if a node/operator requires single-step debugging.
Returns:
trueif operator is not inNoDebugOperatorsList.
20. getRelativePositionToIterationNode
export function getRelativePositionToIterationNode(
nodes: RAGFlowNodeType[],
position?: XYPosition,
)
Purpose: Calculates the position of a given point relative to an "Iteration" node if the point lies within its bounding box.
Parameters:
nodes: Array of nodes.position: Absolute position.
Returns: Object with
parentIdof the Iteration node and relativeposition, or undefined if none matches.
21. generateDuplicateNode
export const generateDuplicateNode = (
position?: XYPosition,
label?: string,
)
Purpose: Generates a new node object positioned offset from an existing position, with a unique ID.
Parameters:
position: Original node position.label: Node label/operator name.
Returns: Object containing new node properties (id, position, drag handle).
22. buildCategorizeListFromObject
export const buildCategorizeListFromObject = (
categorizeItem: ICategorizeItemResult,
) => ICategorizeItem[];
Purpose: Converts a categorization object into a sorted list of categorize items.
Parameters:
categorizeItem: Object with categorization keys mapping to descriptions and metadata.
Returns: Array of categorize items sorted by their
indexfield.Use case: Synchronizes category edges and form data for
Categorizeoperators.
Important Implementation Details and Algorithms
Edge Construction: Avoids duplicates by checking existing edges before adding new ones.
Parameter Cleaning: Uses curried functions and functional pipelines to clean operator parameters consistently.
Position Mapping: Assigns new positions to nodes using predefined anchor points and ensures no overlap by tracking used indexes.
Name Generation: Efficiently generates unique incremented names by parsing existing node names and identifying the first gap in sequence.
Recursive ID Replacement: Uses recursion to replace all ID strings in nested objects or arrays with human-readable text.
Relative Position Calculation: Uses bounding box checks to determine if a point lies within iteration nodes and calculates relative coordinates accordingly.
Interaction with Other Parts of the System
Imports from
@/interfaces/database/flow: Uses interfaces describing DSL components and categorization, indicating tight coupling with the data model of the system.Uses
@xyflow/reactComponents: The nodes and edges are structured for use with React Flow or a similar graph visualization library.Form Utilities: Relies on form utilities for cleaning and managing operator parameters.
Constants and Interfaces: Imports constants like operator names and anchor positions from related modules, aligning with the system's domain model.
UI Interaction: Functions like
getDrawerWidthandgetNodeDragHandleindicate integration with the UI layer for responsive design and interaction.Debug Support: The
needsSingleStepDebuggingfunction integrates with debugging features elsewhere in the application.Node Duplication & Naming: Supports node creation and duplication workflows, likely invoked by UI actions for editing graph flows.
Usage Examples
import { buildNodesAndEdgesFromDSLComponents, buildDslComponentsByGraph } from './utils';
// Convert DSL components to graph
const { nodes, edges } = buildNodesAndEdgesFromDSLComponents(dslComponents);
// Update DSL from graph interactions
const updatedDSL = buildDslComponentsByGraph(nodes, edges, dslComponents);
// Generate a unique node name
const newName = generateNodeNamesWithIncreasingIndex('generate', nodes);
// Duplicate a node form
const duplicatedForm = duplicateNodeForm(nodes[0]?.data);
Mermaid Flowchart Diagram
flowchart TD
A[buildNodesAndEdgesFromDSLComponents] --> B[buildEdges]
B --> C[Edge Creation & Deduplication]
A --> D[Node Creation]
E[buildDslComponentsByGraph] --> F[buildComponentDownstreamOrUpstream]
F --> G[Edge Filtering for Upstream/Downstream]
E --> H[buildOperatorParams]
H --> I[removeUselessDataInTheOperator]
J[replaceIdWithText] --> K[Recursive ID Replacement]
L[generateNodeNamesWithIncreasingIndex] --> M[Parse existing names]
L --> N[Find next index]
O[buildNewPositionMap] --> P[Calculate intersectionKeys]
O --> Q[Assign new positions from anchor points]
R[duplicateNodeForm] --> S[Clear downstream references for specific operators]
T[getRelativePositionToIterationNode] --> U[Check bounding box]
V[generateDuplicateNode] --> W[Generate new node with offset position]
style A fill:#f9f,stroke:#333,stroke-width:2px
style E fill:#bbf,stroke:#333,stroke-width:2px
style J fill:#fbf,stroke:#333,stroke-width:2px
Summary
The utils.ts file provides foundational utility functions to build and maintain a graph-based workflow system, including:
Conversion between DSL and graph representations.
Edge and node management with deduplication and parameter cleaning.
Naming and positioning support for nodes.
Recursive data transformations and UI-related helpers.
These utilities are essential to enable graph construction, editing, and serialization, supporting the broader system’s flow-based execution and visualization capabilities.