Iterating Over a Visual Editor Compiler

The Visual Editor

When it comes to creating visual editors for workflows, React Flow stands out as an ideal choice. It offers robust performance, is highly customizable, and facilitates document export. With it, you can build everything from…


This content originally appeared on DEV Community and was authored by Ytalo

The Visual Editor

When it comes to creating visual editors for workflows, React Flow stands out as an ideal choice. It offers robust performance, is highly customizable, and facilitates document export. With it, you can build everything from chatbots to complex backends.

Compiling the Visual

Directly exporting the visual format is not efficient for execution. Therefore, we convert this structure into something more executable. A basic example of the structure would be:

[{prev: null, data: {}, id: id, next: <some id>}]

This makes it easy to navigate and filter the objects.

Data Maintenance

To reverse the "compilation" and maintain node metadata, we use:

const step: any = {
    data: node.data,
    height: node.height,
    id: node.id,
    position: node.position,
    positionAbsolute: node.positionAbsolute,
    selected: node.selected,
    type: node.type,
    width: node.width,
    prev: another step,
    next: another step
};

[Format Conversion

Below is the function that converts the React Flow format to a custom format:

function convertToCustomFormat(reactFlowObject: any) {
    const customFormatObject: any = {
        steps: [],
        viewport: reactFlowObject.flow.viewport,
    };

    reactFlowObject.flow.nodes.forEach((node: any) => {
        const step: any = {
            data: node.data,
            height: node.height,
            id: node.id,
            position: node.position,
            positionAbsolute: node.positionAbsolute,
            selected: node.selected,
            type: node.type,
            width: node.width,
        };

        if (node.data.nodeType === "conditionNode" || node.data.nodeType === "pixNode") {
            const trueEdge = reactFlowObject.flow.edges.find(
                (edge: any) => edge.source === node.id && edge.sourceHandle == "a"
            );
            const falseEdge = reactFlowObject.flow.edges.find(
                (edge: any) => edge.source === node.id && edge.sourceHandle == "b"
            );

            step.true = trueEdge ? trueEdge : null;
            step.false = falseEdge ? falseEdge : null;
            step.prev = reactFlowObject.flow.edges.find(
                (edge: any) => edge.target === node.id
            );
        } else {
            step.prev = reactFlowObject.flow.edges.find(
                (edge: any) => edge.target === node.id
            );
            step.next = reactFlowObject.flow.edges.find(
                (edge: any) => edge.source === node.id
            );
        }

        customFormatObject.steps.push(step);
    });

    return customFormatObject;
}

Reconversion to React Flow

To reconvert the custom format back to React Flow, we use the following function:

function convertToReactFlowFormat(customFormatObject: any) {
    const reactFlowObject: any = {
        flow: {
            nodes: [],
            edges: [],
            viewport: customFormatObject.viewport,
        },
    };

    customFormatObject.steps.forEach((step: any) => {
        const node = {
            data: step.data,
            height: step.height,
            id: step.id,
            position: step.position,
            positionAbsolute: step.positionAbsolute,
            selected: step.selected,
            type: step.type,
            width: step.width,
        };

        reactFlowObject.flow.nodes.push(node);

        if (step.type === "nodeContainer") {
            if (step.prev) {
                reactFlowObject.flow.edges.push({
                    ...step.prev,
                    target: step.id,
                });
            }

            if (step.next) {
                reactFlowObject.flow.edges.push({
                    ...step.next,
                    source: step.id,
                });
            }
        }
    });

    return reactFlowObject;
}

Execution

To execute from the metadata, especially when user inputs are needed, we can use variables that change continuously and can be stored in memory or in a database like Redis. We keep the step ID, the number of steps passed, and metadata for each previous step or input.

This allows us to pause and resume execution easily, maintaining the flow logic intact. In cases where there are multiple outputs, we adapt the function to handle specific actions:

const step: any = {
    data: node.data,

height: node.height,
    id: node.id,
    position: node.position,
    positionAbsolute: node.positionAbsolute,
    selected: node.selected,
    type: node.type,
    width: node.width,
    prev: step,
    outputs: {
        0: step,
        1: step
    }
};

This allows for even more detailed and specific management of the constructed flow.

Introducing the Visitor Pattern

For those looking for a more structured and scalable way to iterate over the elements of a visual editor, the Visitor Pattern can be an intriguing solution. The Visitor Pattern allows you to separate algorithms from the objects on which they operate, making it easier to add new operations without modifying the existing elements.

What is the Visitor Pattern?

The Visitor Pattern involves creating a visitor interface that declares a set of visit methods for each type of element. Each element class implements an accept method that accepts a visitor, allowing the visitor to perform the required operation.

Benefits

  • Simplified Maintenance: Adding new operations only requires creating a new visitor without needing to modify existing elements.
  • Separation of Responsibilities: Operations are clearly separated from the elements, making the code more modular.
  • Scalability: Facilitates the addition of new types of elements and operations in an orderly and hassle-free manner.

Basic Example

Here is a basic example of how the Visitor Pattern can be implemented:

class Visitor {
  visitText(element) {}
  visitImage(element) {}
  visitShape(element) {}
}

class ConcreteVisitor extends Visitor {
  visitText(element) {
    console.log('Processing text element');
  }
  visitImage(element) {
    console.log('Processing image element');
  }
  visitShape(element) {
    console.log('Processing shape element');
  }
}

class Element {
  accept(visitor) {}
}

class TextElement extends Element {
  accept(visitor) {
    visitor.visitText(this);
  }
}

class ImageElement extends Element {
  accept(visitor) {
    visitor.visitImage(this);
  }
}

class ShapeElement extends Element {
  accept(visitor) {
    visitor.visitShape(this);
  }
}

function processElements(elements, visitor) {
  for (let element of elements) {
    element.accept(visitor);
  }
}

const elements = [new TextElement(), new ImageElement(), new ShapeElement()];
const visitor = new ConcreteVisitor();
processElements(elements, visitor);

Considering the use of the Visitor Pattern can help keep your code more organized and adaptable to future changes. If you are iterating over a complex set of elements and need to apply multiple operations, this pattern can be an excellent choice.

This article was built based on the BatAnBot project and the recent technical challenge by Vom.


This content originally appeared on DEV Community and was authored by Ytalo


Print Share Comment Cite Upload Translate Updates
APA

Ytalo | Sciencx (2024-07-10T20:15:25+00:00) Iterating Over a Visual Editor Compiler. Retrieved from https://www.scien.cx/2024/07/10/iterating-over-a-visual-editor-compiler/

MLA
" » Iterating Over a Visual Editor Compiler." Ytalo | Sciencx - Wednesday July 10, 2024, https://www.scien.cx/2024/07/10/iterating-over-a-visual-editor-compiler/
HARVARD
Ytalo | Sciencx Wednesday July 10, 2024 » Iterating Over a Visual Editor Compiler., viewed ,<https://www.scien.cx/2024/07/10/iterating-over-a-visual-editor-compiler/>
VANCOUVER
Ytalo | Sciencx - » Iterating Over a Visual Editor Compiler. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2024/07/10/iterating-over-a-visual-editor-compiler/
CHICAGO
" » Iterating Over a Visual Editor Compiler." Ytalo | Sciencx - Accessed . https://www.scien.cx/2024/07/10/iterating-over-a-visual-editor-compiler/
IEEE
" » Iterating Over a Visual Editor Compiler." Ytalo | Sciencx [Online]. Available: https://www.scien.cx/2024/07/10/iterating-over-a-visual-editor-compiler/. [Accessed: ]
rf:citation
» Iterating Over a Visual Editor Compiler | Ytalo | Sciencx | https://www.scien.cx/2024/07/10/iterating-over-a-visual-editor-compiler/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.