Skip to content

Commit

Permalink
Merge pull request #290 from najeebkp/integrate-workflow-visualizer
Browse files Browse the repository at this point in the history
feat:integrate orkes-workflow-visualizer
  • Loading branch information
v1r3n authored Nov 25, 2024
2 parents c105719 + 46ac8e2 commit e9fbfaa
Show file tree
Hide file tree
Showing 8 changed files with 141 additions and 53 deletions.
27 changes: 13 additions & 14 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ name: CI
on:
push:
paths-ignore:
- 'conductor-clients/**'
- "conductor-clients/**"
pull_request:
paths-ignore:
- 'conductor-clients/**'
- "conductor-clients/**"

jobs:
build:
Expand All @@ -21,8 +21,8 @@ jobs:
- name: Set up Zulu JDK 17
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: '17'
distribution: "zulu"
java-version: "17"
- name: Cache SonarCloud packages
uses: actions/cache@v3
with:
Expand Down Expand Up @@ -53,20 +53,20 @@ jobs:
uses: mikepenz/action-junit-report@v3
if: always()
with:
report_paths: '**/build/test-results/test/TEST-*.xml'
report_paths: "**/build/test-results/test/TEST-*.xml"
- name: Upload build artifacts
uses: actions/upload-artifact@v3
with:
name: build-artifacts
path: '**/build/reports'
path: "**/build/reports"
- name: Store Buildscan URL
uses: actions/upload-artifact@v3
with:
name: build-scan
path: 'buildscan.log'
path: "buildscan.log"
build-ui:
runs-on: ubuntu-latest
container: cypress/browsers:node14.17.6-chrome100-ff98
container: cypress/browsers:node-22.11.0-chrome-130.0.6723.116-1-ff-132.0.1-edge-130.0.2849.68-1
defaults:
run:
working-directory: ui
Expand All @@ -81,15 +81,15 @@ jobs:

- name: Run E2E Tests
uses: cypress-io/github-action@v4
with:
with:
working-directory: ui
install: false
start: yarn run serve-build
wait-on: 'http://localhost:5000'
wait-on: "http://localhost:5000"

- name: Run Component Tests
uses: cypress-io/github-action@v4
with:
with:
working-directory: ui
install: false
component: true
Expand All @@ -100,11 +100,10 @@ jobs:
with:
name: cypress-screenshots
path: ui/cypress/screenshots

- name: Archive test videos
uses: actions/upload-artifact@v3
if: always()
with:
name: cypress-videos
path: ui/cypress/videos

5 changes: 3 additions & 2 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@
"moment": "^2.29.2",
"monaco-editor": "^0.44.0",
"node-forge": "^1.3.0",
"orkes-workflow-visualizer": "^1.0.0",
"parse-svg-path": "^0.1.2",
"prop-types": "^15.7.2",
"react": "^16.8.0",
"react": "^18.3.1",
"react-cron-generator": "^1.3.5",
"react-data-table-component": "^6.11.8",
"react-dom": "^16.8.0",
"react-dom": "^18.3.1",
"react-helmet": "^6.1.0",
"react-is": "^17.0.2",
"react-query": "^3.19.4",
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/diagram/WorkflowDAG.js
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,7 @@ export default class WorkflowDAG {
return this.taskResultsById.get(taskPointer.id);
} else {
const node = this.graph.node(taskPointer.ref);
return _.last(node.taskResults);
return _.last(node?.taskResults);
}
}
}
Expand Down
52 changes: 33 additions & 19 deletions ui/src/pages/definition/WorkflowDefinition.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
useWorkflowNamesAndVersions,
} from "../../data/workflow";
import WorkflowDAG from "../../components/diagram/WorkflowDAG";
import WorkflowGraph from "../../components/diagram/WorkflowGraph";
import ResetConfirmationDialog from "./ResetConfirmationDialog";
import {
configureMonaco,
Expand All @@ -23,6 +22,7 @@ import SaveWorkflowDialog from "./SaveWorkflowDialog";
import update from "immutability-helper";
import { usePushHistory } from "../../components/NavLink";
import { timestampRenderer } from "../../utils/helpers";
import { WorkflowVisualizer } from "orkes-workflow-visualizer";

import {
KeyboardArrowLeftRounded,
Expand Down Expand Up @@ -67,8 +67,8 @@ const useStyles = makeStyles({
gap: 8,
},
editorLineDecorator: {
backgroundColor: "rgb(45, 45, 45, 0.1)"
}
backgroundColor: "rgb(45, 45, 45, 0.1)",
},
});

const actions = {
Expand Down Expand Up @@ -240,21 +240,26 @@ export default function Workflow() {
};

const handleWorkflowNodeClick = (node) => {
let editor = editorRef.current.getModel()
let searchResult = editor.findMatches(`"taskReferenceName": "${node.ref}"`)
if (searchResult.length){
editorRef.current.revealLineInCenter(searchResult[0]?.range?.startLineNumber, 0);
setDecorations(editorRef.current.deltaDecorations(decorations, [
{
range: searchResult[0]?.range,
options: {
isWholeLine: true,
inlineClassName: classes.editorLineDecorator
}
}
]))
let editor = editorRef.current.getModel();
let searchResult = editor.findMatches(`"taskReferenceName": "${node.ref}"`);
if (searchResult.length) {
editorRef.current.revealLineInCenter(
searchResult[0]?.range?.startLineNumber,
0
);
setDecorations(
editorRef.current.deltaDecorations(decorations, [
{
range: searchResult[0]?.range,
options: {
isWholeLine: true,
inlineClassName: classes.editorLineDecorator,
},
},
])
);
}
}
};

return (
<>
Expand Down Expand Up @@ -369,8 +374,17 @@ export default function Workflow() {
className={classes.resizer}
onMouseDown={(e) => handleMouseDown(e)}
/>
<div className={classes.workflowGraph}>
{dag && <WorkflowGraph dag={dag} onClick={handleWorkflowNodeClick} />}
<div className={classes.workflowGraph} style={{ overflow: "scroll" }}>
{dag && dag?.workflowDef && (
<WorkflowVisualizer
maxHeightOverride
pannable
zoomable
zoom={0.7}
data={dag?.workflowDef}
onClick={(e, data) => handleWorkflowNodeClick({ ref: data?.id })}
/>
)}
</div>
</div>
</>
Expand Down
11 changes: 10 additions & 1 deletion ui/src/pages/execution/Execution.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ export default function Execution() {
const [isFullWidth, setIsFullWidth] = useState(false);
const [isResizing, setIsResizing] = useState(false);
const [drawerWidth, setDrawerWidth] = useState(INIT_DRAWER_WIDTH);
const [selectedNode, setSelectedNode] = useState();

const [tabIndex, setTabIndex] = useQueryState("tabIndex", 0);
const [selectedTaskRison, setSelectedTaskRison] = useQueryState("task", "");
Expand Down Expand Up @@ -222,7 +223,12 @@ export default function Execution() {
</div>
)}
<div className={classes.frItem}>
<NavLink newTab path={`/workflowDef/${execution.workflowName}`}>Definition</NavLink>
<NavLink
newTab
path={`/workflowDef/${execution.workflowName}`}
>
Definition
</NavLink>
</div>
<SecondaryButton onClick={refresh} style={{ marginRight: 10 }}>
Refresh
Expand Down Expand Up @@ -260,6 +266,7 @@ export default function Execution() {
execution={execution}
setSelectedTask={setSelectedTask}
selectedTask={selectedTask}
setSelectedNode={setSelectedNode}
/>
)}
{tabIndex === 1 && <ExecutionSummary execution={execution} />}
Expand Down Expand Up @@ -302,6 +309,8 @@ export default function Execution() {
className={classes.rightPanel}
selectedTask={selectedTask}
dag={dag}
execution={execution}
selectedNode={selectedNode}
onTaskChange={setSelectedTask}
/>
</div>
Expand Down
21 changes: 16 additions & 5 deletions ui/src/pages/execution/RightPanel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import TaskLogs from "./TaskLogs";
import { makeStyles } from "@material-ui/styles";
import _ from "lodash";
import TaskPollData from "./TaskPollData";
import {
pendingTaskSelection,
taskWithLatestIteration,
} from "../../utils/helpers";

const useStyles = makeStyles({
banner: {
Expand All @@ -24,7 +28,13 @@ const useStyles = makeStyles({
},
});

export default function RightPanel({ selectedTask, dag, onTaskChange }) {
export default function RightPanel({
selectedTask,
dag,
execution,
onTaskChange,
selectedNode,
}) {
const [tabIndex, setTabIndex] = useState("summary");

const classes = useStyles();
Expand All @@ -33,10 +43,11 @@ export default function RightPanel({ selectedTask, dag, onTaskChange }) {
setTabIndex("summary"); // Reset to Status Tab on ref change
}, [selectedTask]);

const taskResult = useMemo(
() => dag && dag.resolveTaskResult(selectedTask),
[dag, selectedTask]
);
const taskResult =
selectedNode?.data?.task?.executionData?.status === "PENDING"
? pendingTaskSelection(selectedNode?.data?.task)
: taskWithLatestIteration(execution?.tasks, selectedTask?.ref);

const dfOptions = useMemo(
() => dag && dag.getSiblings(selectedTask),
[dag, selectedTask]
Expand Down
29 changes: 23 additions & 6 deletions ui/src/pages/execution/TaskDetails.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import React, { useState } from "react";
import { useState } from "react";
import { Tabs, Tab, Paper } from "../../components";
import Timeline from "./Timeline";
import TaskList from "./TaskList";
import WorkflowGraph from "../../components/diagram/WorkflowGraph";
import { makeStyles } from "@material-ui/styles";
import { WorkflowVisualizer } from "orkes-workflow-visualizer";
import {
pendingTaskSelection,
taskWithLatestIteration,
} from "../../utils/helpers";

const useStyles = makeStyles({
taskWrapper: {
Expand All @@ -18,6 +22,7 @@ export default function TaskDetails({
dag,
selectedTask,
setSelectedTask,
setSelectedNode,
}) {
const [tabIndex, setTabIndex] = useState(0);
const classes = useStyles();
Expand All @@ -32,11 +37,23 @@ export default function TaskDetails({
</Tabs>

{tabIndex === 0 && (
<WorkflowGraph
selectedTask={selectedTask}
<WorkflowVisualizer
maxHeightOverride
pannable
zoomable
zoom={0.7}
data={dag?.execution}
executionMode={true}
dag={dag}
onClick={setSelectedTask}
onClick={(e, data) => {
const selectedTaskRefName =
data?.data?.task?.executionData?.status === "PENDING"
? pendingTaskSelection(data?.data?.task)?.workflowTask
?.taskReferenceName
: taskWithLatestIteration(execution?.tasks, data?.id)
?.referenceTaskName;
setSelectedNode(data);
setSelectedTask({ ref: selectedTaskRefName });
}}
/>
)}
{tabIndex === 1 && (
Expand Down
47 changes: 42 additions & 5 deletions ui/src/utils/helpers.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { format, formatDuration, intervalToDuration } from "date-fns";
import _ from "lodash";
import packageJson from '../../package.json';
import packageJson from "../../package.json";
import _nth from "lodash/nth";

export function timestampRenderer(date) {
if (_.isNil(date)) return null;
Expand Down Expand Up @@ -91,9 +92,45 @@ export function isEmptyIterable(iterable) {
}

export function getBasename() {
let basename = '/';
try{
let basename = "/";
try {
basename = new URL(packageJson.homepage).pathname;
} catch(e) {}
return _.isEmpty(basename) ? '/' : basename;
} catch (e) {}
return _.isEmpty(basename) ? "/" : basename;
}

export const taskWithLatestIteration = (tasksList, taskReferenceName) => {
const filteredTasks = tasksList?.filter(
(task) =>
task?.workflowTask?.taskReferenceName === taskReferenceName ||
task?.referenceTaskName === taskReferenceName
);

if (filteredTasks && filteredTasks.length === 1) {
// task without any retry/iteration
return _nth(filteredTasks, 0);
} else if (filteredTasks && filteredTasks.length > 1) {
const result = filteredTasks.reduce(
(acc, task, idx) => {
if (task?.seq && acc?.seqNumber < Number(task.seq)) {
return { seqNumber: Number(task.seq), idx };
}
return acc;
},
{ seqNumber: 0, idx: -1 }
);

if (result?.idx > -1) {
return _nth(filteredTasks, result.idx);
}
}
return undefined;
};

export const pendingTaskSelection = (task) => {
const result = {
...task?.executionData,
workflowTask: task,
};
return result;
};

0 comments on commit e9fbfaa

Please sign in to comment.