diff --git a/frontend/src/components/WorkflowValidationTimeline.jsx b/frontend/src/components/WorkflowValidationTimeline.jsx new file mode 100644 index 00000000..cbbb7bd6 --- /dev/null +++ b/frontend/src/components/WorkflowValidationTimeline.jsx @@ -0,0 +1,443 @@ +import React, { useState, } from "react"; +import { makeStyles, createStyles } from "@mui/styles"; +import { toast } from "react-toastify" + +import { + Tooltip, + Typography, + + Avatar, + AvatarGroup, +} from "@mui/material" + +import { + green, + yellow, + red, +} from "../views/AngularWorkflow.jsx" + +import { validateJson, GetIconInfo } from "../views/Workflows.jsx"; +import theme from "../theme.jsx"; +const itemHeight = 40 + +export const getParentNodes = (workflow, action) => { + if (action === undefined || action === null) { + return [] + } + + if (workflow.actions === undefined || workflow.actions === null) { + workflow.actions = [] + } + + if (workflow.triggers === undefined || workflow.triggers === null) { + workflow.triggers = [] + } + + if (workflow.branches === undefined || workflow.branches === null) { + workflow.branches = [] + } + + var allkeys = [action.id]; + var handled = []; + var results = []; + + // maxiter = max amount of parent nodes to loop + // also handles breaks if there are issues + var iterations = 0; + var maxiter = 10; + while (true) { + for (let parentkey in allkeys) { + if (allkeys[parentkey] === undefined) { + continue + } + + var currentnode = workflow.actions.find((element) => element.id === allkeys[parentkey]) + if (currentnode === undefined) { + currentnode = workflow.triggers.find((element) => element.id === allkeys[parentkey]) + + if (currentnode === undefined) { + console.log("Could not find parent node for: ", allkeys[parentkey]) + continue + } + } + + if (handled.includes(currentnode.id)) { + continue + } else { + handled.push(currentnode.id); + results.push(currentnode); + } + + // Get the name / label here too? + if (currentnode.length === 0) { + continue; + } + + // FIXME: This part is only handling first level, + // but needs to recurse + var incomingEdges = [] + for (var branchkey in workflow.branches) { + const branch = workflow.branches[branchkey] + if (branch.destination_id !== currentnode.id) { + continue + } + + // Go up in the levels + const parents = getParentNodes(workflow, { + id: branch.source_id, + }) + if (parents.length > 0) { + incomingEdges = incomingEdges.concat(parents) + } + + incomingEdges.push(branch) + } + + for (let i = 0; i < incomingEdges.length; i++) { + var tmp = incomingEdges[i]; + if (tmp.decorator === true) { + continue + } + + if (!allkeys.includes(tmp.source_id)) { + allkeys.push(tmp.source_id) + } + } + } + + if (results.length === allkeys.length || iterations === maxiter) { + break + } + + iterations += 1 + } + + // Remove on the end as we don't want to remove everything + results = results.filter((data) => data.id !== action.id) + results = results.filter((data) => data.type === "ACTION" || data.app_name === "Shuffle Workflow" || data.app_name === "User Input" || data.app_name === "shuffle-subflow") + results.push({ label: "Execution Argument", type: "INTERNAL" }) + + return results +} + +const WorkflowValidationTimeline = (props) => { + const { workflow, originalWorkflow, apps, getParents, execution} = props + + + if (workflow === undefined || workflow === null) { + return null + } + + if (workflow.validation === undefined || workflow.validation === null) { + return null + } + + if (workflow.actions === undefined || workflow.actions === null) { + workflow.actions = [] + } + + if (workflow.triggers === undefined || workflow.triggers === null) { + workflow.triggers = [] + + } + + if (workflow.branches === undefined || workflow.branches === null) { + workflow.branches = [] + + } + + var results = [] + if (execution !== undefined) { + results = execution.results + } + + // 1. Find startnode + // 2. Map childnodes from it + const startnodeId = workflow.start + + // Find parent of startnodeId and if it's a webhook + var relevantactions = [] + for (var key in workflow.branches) { + const branch = workflow.branches[key] + if (branch.destination_id !== startnodeId) { + continue + } + + for (var triggerkey in workflow.triggers) { + const trigger = workflow.triggers[triggerkey] + if (trigger.trigger_type !== "WEBHOOK") { + continue + } + + if (trigger.id === branch.source_id) { + trigger.order = -1 + relevantactions.push(trigger) + break + } + } + } + + + if (getParents !== undefined) { + for (var key in workflow.actions) { + const action = workflow.actions[key] + if (action.id === startnodeId) { + action.order = 0 + relevantactions.push(action) + continue + } + + const parents = getParents(action) + //const parents = getParentNodes(workflow, action) + //console.log("PARENTS", key, parents) + if (parents !== undefined && parents !== null) { + const parentfound = parents.find((element) => element.id === startnodeId) + if (parentfound !== undefined) { + + // FIXME: add order here based on how many steps away from the startnode + // This just has the parent count + action.order = parents.length + + relevantactions.push(action) + } + } + } + } else { + for (var key in workflow.triggers) { + const trigger = workflow.triggers[key] + if (trigger.trigger_type !== "SUBFLOW" && trigger.trigger_type !== "USERINPUT") { + continue + } + + if (workflow.actions.find((element) => element.id === trigger.id) === undefined) { + workflow.actions.push(trigger) + } + } + + relevantactions = workflow.actions + } + + // Sort according to how many parents a node has. MAY be wrong~ + relevantactions.sort((a, b) => { + if (a.order === undefined) { + return 1 + } + + if (b.order === undefined) { + return -1 + } + + return a.order - b.order + }) + + // FIXME: Add other relevant items as well from subflows (?) + var nodecolor = "grey" + var branchcolor = "grey" + var skipped = false + + var previousTools = false + + return ( +