Skip to content

Commit

Permalink
Workflow wrapper class (#4441)
Browse files Browse the repository at this point in the history
  • Loading branch information
mwdchang authored Aug 13, 2024
1 parent 4793cf1 commit 08feee7
Show file tree
Hide file tree
Showing 4 changed files with 554 additions and 626 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<Button icon="pi pi-check" rounded text @click="updateWorkflowName" />
</div>
</div>
<h4 v-else>{{ wf.name }}</h4>
<h4 v-else>{{ wf.getName() }}</h4>
<Button
v-if="!isRenamingWorkflow"
icon="pi pi-ellipsis-v"
Expand All @@ -56,7 +56,7 @@
<template #data>
<ContextMenu ref="contextMenu" :model="contextMenuItems" style="white-space: nowrap; width: auto" />
<tera-canvas-item
v-for="node in wf.nodes.filter((n) => n.isDeleted !== true)"
v-for="node in wf.getNodes()"
:key="node.id"
:style="{
width: `${node.width}px`,
Expand Down Expand Up @@ -135,7 +135,7 @@
fill="none"
/>
<path
v-for="edge of wf.edges.filter((e) => e.isDeleted !== true)"
v-for="edge of wf.getEdges()"
:key="edge.id"
:d="drawPath(interpolatePointsForCurve(edge.points[0], edge.points[1]))"
stroke="#667085"
Expand Down Expand Up @@ -167,7 +167,7 @@ import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
import TeraInfiniteCanvas from '@/components/widgets/tera-infinite-canvas.vue';
import TeraCanvasItem from '@/components/widgets/tera-canvas-item.vue';
import type { Position } from '@/types/common';
import type { Operation, Workflow, WorkflowEdge, WorkflowNode, WorkflowOutput, WorkflowPort } from '@/types/workflow';
import type { Operation, WorkflowEdge, WorkflowNode, WorkflowOutput, WorkflowPort } from '@/types/workflow';
import { WorkflowDirection, WorkflowPortStatus, OperatorStatus } from '@/types/workflow';
// Operation imports
import TeraOperator from '@/components/operator/tera-operator.vue';
Expand Down Expand Up @@ -258,7 +258,7 @@ const currentActiveNode = ref<WorkflowNode<any> | null>(null);
const newEdge = ref<WorkflowEdge | undefined>();
const dialogIsOpened = ref(false);
const wf = ref<Workflow>(workflowService.emptyWorkflow());
const wf = ref<workflowService.WorkflowWrapper>(new workflowService.WorkflowWrapper());
const contextMenu = ref();
const isRenamingWorkflow = ref(false);
Expand All @@ -271,7 +271,7 @@ const optionsMenuItems = ref([
label: 'Rename',
command() {
isRenamingWorkflow.value = true;
newWorkflowName.value = wf.value?.name ?? '';
newWorkflowName.value = wf.value?.getName() ?? '';
}
}
]);
Expand All @@ -282,7 +282,7 @@ const toggleOptionsMenu = (event) => {
const teraOperatorRefs = ref();
async function updateWorkflowName() {
const workflowClone = cloneDeep(wf.value);
const workflowClone = cloneDeep(wf.value.dump());
workflowClone.name = newWorkflowName.value;
await workflowService.updateWorkflow(workflowClone);
await useProjects().refresh();
Expand Down Expand Up @@ -347,19 +347,19 @@ function appendOutput(
function updateWorkflowNodeState(node: WorkflowNode<any> | null, state: any) {
if (!node) return;
workflowService.updateNodeState(wf.value, node.id, state);
wf.value.updateNodeState(node.id, state);
workflowDirty = true;
}
function updateWorkflowNodeStatus(node: WorkflowNode<any> | null, status: OperatorStatus) {
if (!node) return;
workflowService.updateNodeStatus(wf.value, node.id, status);
wf.value.updateNodeStatus(node.id, status);
workflowDirty = true;
}
function selectOutput(node: WorkflowNode<any> | null, selectedOutputId: string) {
if (!node) return;
workflowService.selectOutput(wf.value, node, selectedOutputId);
wf.value.selectOutput(node, selectedOutputId);
workflowDirty = true;
}
Expand Down Expand Up @@ -397,13 +397,13 @@ const closeDrilldown = async () => {
);
};
const removeNode = (event) => {
workflowService.removeNode(wf.value, event);
const removeNode = (nodeId: string) => {
wf.value.removeNode(nodeId);
workflowDirty = true;
};
const duplicateBranch = (id: string) => {
workflowService.branchWorkflow(wf.value, id);
const duplicateBranch = (nodeId: string) => {
wf.value.branchWorkflow(nodeId);
cloneNoteBookSessions();
workflowDirty = true;
Expand All @@ -416,8 +416,8 @@ const cloneNoteBookSessions = async () => {
const operationList = [DatasetTransformerOp.operation.name, RegriddingOp.operation.name];
for (let i = 0; i < wf.value.nodes.length; i++) {
const node = wf.value.nodes[i];
for (let i = 0; i < wf.value.getNodes().length; i++) {
const node = wf.value.getNodes()[i];
if (operationList.includes(node.operationType)) {
const state = node.state;
const sessionId = state.notebookSessionId as string;
Expand All @@ -437,7 +437,7 @@ const cloneNoteBookSessions = async () => {
const addOperatorToWorkflow: Function =
(operator: OperatorImport, nodeSize: OperatorNodeSize = OperatorNodeSize.medium) =>
() => {
workflowService.addNode(wf.value, operator.operation, newNodePosition, {
wf.value.addNode(operator.operation, newNodePosition, {
size: nodeSize
});
workflowDirty = true;
Expand Down Expand Up @@ -608,7 +608,7 @@ function onDrop(event) {
default:
return;
}
workflowService.addNode(wf.value, operation, newNodePosition, { state });
wf.value.addNode(operation, newNodePosition, { state });
}
}
Expand All @@ -625,7 +625,7 @@ function updateNewNodePosition(event) {
function saveTransform(newTransform: { k: number; x: number; y: number }) {
canvasTransform = newTransform;
const t = wf.value.transform;
const t = wf.value.getTransform();
t.x = newTransform.x;
t.y = newTransform.y;
t.k = newTransform.k;
Expand All @@ -649,8 +649,7 @@ function createNewEdge(node: WorkflowNode<any>, port: WorkflowPort, direction: W
direction
};
} else {
workflowService.addEdge(
wf.value,
wf.value.addEdge(
newEdge.value!.source ?? node.id,
newEdge.value!.sourcePortId ?? port.id,
newEdge.value!.target ?? node.id,
Expand All @@ -662,15 +661,16 @@ function createNewEdge(node: WorkflowNode<any>, port: WorkflowPort, direction: W
}
function removeEdges(portId: string) {
const edges = wf.value.edges.filter(
({ targetPortId, sourcePortId }) => targetPortId === portId || sourcePortId === portId
);
const edges = wf.value
.getEdges()
.filter(({ targetPortId, sourcePortId }) => targetPortId === portId || sourcePortId === portId);
// Build a traversal map before we do actual removal
const nodeMap = new Map<WorkflowNode<any>['id'], WorkflowNode<any>>(wf.value.nodes.map((node) => [node.id, node]));
const nodeMap = new Map<WorkflowNode<any>['id'], WorkflowNode<any>>(
wf.value.getNodes().map((node) => [node.id, node])
);
const nodeCache = new Map<WorkflowOutput<any>['id'], WorkflowNode<any>[]>();
wf.value.edges.forEach((edge) => {
if (edge.isDeleted === true) return;
wf.value.getEdges().forEach((edge) => {
if (!edge.source || !edge.target) return;
if (!nodeCache.has(edge.source)) nodeCache.set(edge.source, []);
nodeCache.get(edge.source)?.push(nodeMap.get(edge.target) as WorkflowNode<any>);
Expand All @@ -680,7 +680,7 @@ function removeEdges(portId: string) {
// Remove edge
if (!isEmpty(edges)) {
edges.forEach((edge) => {
workflowService.removeEdge(wf.value, edge.id);
wf.value.removeEdge(edge.id);
});
workflowDirty = true;
} else {
Expand Down Expand Up @@ -729,8 +729,8 @@ const threshold2 = 5.0 * 5.0;
* FIXME: not efficient, need cache/map for larger workflows
*/
function relinkEdges(node: WorkflowNode<any> | null) {
const nodes = node ? [node] : wf.value.nodes;
const allEdges = wf.value.edges;
const nodes = node ? [node] : wf.value.getNodes();
const allEdges = wf.value.getEdges();
// Note id can start with numerals, so we need [id=...]
const getPortElement = (id: string) => d3.select(`[id='${id}']`).select('.port').node() as HTMLElement;
Expand Down Expand Up @@ -805,7 +805,7 @@ function mouseUpdate(event: MouseEvent) {
}
function updateEdgePositions(node: WorkflowNode<any>, { x, y }) {
wf.value.edges.forEach((edge) => {
wf.value.getEdges().forEach((edge) => {
if (edge.source === node.id) {
edge.points[0].x += x / canvasTransform.k;
edge.points[0].y += y / canvasTransform.k;
Expand Down Expand Up @@ -844,14 +844,14 @@ const drawPath = (v: any) => pathFn(v) as string;
const unloadCheck = () => {
if (workflowDirty) {
workflowService.updateWorkflow(wf.value);
workflowService.updateWorkflow(wf.value.dump());
}
};
const handleDrilldown = () => {
const operatorId = route.query?.operator?.toString();
if (operatorId) {
const operator = wf.value.nodes.find((n) => n.id === operatorId);
const operator = wf.value.getNodes().find((n) => n.id === operatorId);
if (operator) openDrilldown(operator);
} else {
closeDrilldown();
Expand All @@ -863,7 +863,7 @@ watch(
async () => {
isRenamingWorkflow.value = false; // Closes rename input if opened in previous workflow
if (wf.value && workflowDirty) {
workflowService.updateWorkflow(wf.value);
workflowService.updateWorkflow(wf.value.dump());
}
const workflowId = props.assetId;
if (!workflowId) return;
Expand All @@ -873,7 +873,7 @@ watch(
if (transform) {
canvasTransform = transform;
}
wf.value = await workflowService.getWorkflow(workflowId);
wf.value.load(await workflowService.getWorkflow(workflowId));
isWorkflowLoading.value = false;
handleDrilldown();
Expand All @@ -895,21 +895,21 @@ onMounted(() => {
window.addEventListener('beforeunload', unloadCheck);
saveTimer = setInterval(() => {
if (workflowDirty && useProjects().hasEditPermission()) {
workflowService.updateWorkflow(wf.value);
workflowService.updateWorkflow(wf.value.dump());
workflowDirty = false;
}
}, WORKFLOW_SAVE_INTERVAL);
});
onUnmounted(() => {
if (workflowDirty) {
workflowService.updateWorkflow(wf.value);
workflowService.updateWorkflow(wf.value.dump());
}
if (saveTimer) {
clearInterval(saveTimer);
}
if (canvasTransform) {
setLocalStorageTransform(wf.value.id, canvasTransform);
setLocalStorageTransform(wf.value.getId(), canvasTransform);
}
document.removeEventListener('mousemove', mouseUpdate);
window.removeEventListener('beforeunload', unloadCheck);
Expand Down
Loading

0 comments on commit 08feee7

Please sign in to comment.