diff --git a/cloud/package-lock.json b/cloud/package-lock.json
index 0dc112e4..f4eaf6e8 100644
--- a/cloud/package-lock.json
+++ b/cloud/package-lock.json
@@ -4961,6 +4961,11 @@
"type": "^1.0.1"
}
},
+ "dagre-d3-react": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/dagre-d3-react/-/dagre-d3-react-0.2.4.tgz",
+ "integrity": "sha512-spYk0zaI8Mm+5E+99veMDS7CG2Prpce1CcjQINHTKmJe0XUkmFEey5yRr4Ag7htXdirw1Lf/rlBiZgORcc1Nyg=="
+ },
"damerau-levenshtein": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz",
diff --git a/cloud/package.json b/cloud/package.json
index 3ac24c56..504a4406 100644
--- a/cloud/package.json
+++ b/cloud/package.json
@@ -19,6 +19,7 @@
"@types/react-router-dom": "^5.1.5",
"@types/react-syntax-highlighter": "^11.0.4",
"@types/redux-logger": "^3.0.7",
+ "dagre-d3-react": "^0.2.4",
"eslint-webpack-plugin": "^2.4.3",
"lodash": "^4.17.19",
"polished": "^3.6.3",
diff --git a/cloud/src/components/task/TaskState.tsx b/cloud/src/components/task/TaskState.tsx
index 2ce30ded..59092f19 100644
--- a/cloud/src/components/task/TaskState.tsx
+++ b/cloud/src/components/task/TaskState.tsx
@@ -1,18 +1,41 @@
import React from 'react'
import { ContentBlock, Code } from '../ui'
+import TaskGraph from './task-ui/TaskGraph'
type Props = {
- state?: object
+ state: State
+}
+
+type State = {
+ ui?: TaskComponent[]
+ [key: string]: any
+}
+
+type TaskComponent = {
+ component: string
+ path: string
+}
+
+function renderComponent(def: TaskComponent, state: State) {
+ switch(def.component) {
+ case 'ui.cowait.io/task-graph':
+ return
+ default:
+ throw new Error(`Unknown Task Component ${def.component}`)
+ }
}
export const TaskState: React.FC = ({ state }) => {
if (!state) {
return null
}
+ const components = state.ui || []
+
return
State
- {JSON.stringify(state, null, 4)}
+ {components.map(c => renderComponent(c, state))}
+ // {JSON.stringify(state, null, 4)}
}
export default TaskState
diff --git a/cloud/src/components/task/styled/Log.tsx b/cloud/src/components/task/styled/Log.tsx
index c1b07327..598596f9 100644
--- a/cloud/src/components/task/styled/Log.tsx
+++ b/cloud/src/components/task/styled/Log.tsx
@@ -10,6 +10,7 @@ export const LogOutput = styled.pre`
font-family: ${p => p.theme.fonts.monospace};
color: ${p => p.theme.colors.text.secondary};
line-height: 1.25em;
+ max-width: 100vh;
`
export const LogContainer = styled.div`
diff --git a/cloud/src/components/task/task-ui/TaskGraph.tsx b/cloud/src/components/task/task-ui/TaskGraph.tsx
new file mode 100644
index 00000000..25dcd889
--- /dev/null
+++ b/cloud/src/components/task/task-ui/TaskGraph.tsx
@@ -0,0 +1,105 @@
+import _ from 'lodash'
+import React from 'react'
+import { useSelector } from 'react-redux'
+import { RootState } from '../../../store'
+import DagreGraph from 'dagre-d3-react'
+import styled from 'styled-components'
+
+const DagStyle = styled.div`
+ .nodes {
+ fill: darkgray;
+ cursor: pointer;
+ rx: 0.5em;
+ }
+ .nodes .work {
+ fill: #82b332;
+ }
+ .nodes .done {
+ fill: green;
+ }
+ .nodes .fail {
+ fill: red;
+ }
+ .nodes .stop {
+ fill: orange;
+ }
+ .nodes text {
+ fill: white;
+ }
+
+ path {
+ stroke: white;
+ fill: white;
+ stroke-width: 3px;
+ }
+`
+
+type Props = {
+ graph: TaskGraph
+}
+
+type TaskGraph = {
+ [id: string]: TaskNode,
+}
+
+type TaskNode = {
+ id: string
+ task: string
+ depends_on: string[]
+ task_id?: string
+}
+
+type d3Link = {
+ source: string
+ target: string
+ class?: string
+ label?: string
+ config?: object
+}
+
+export const TaskGraph: React.FC = ({ graph }) => {
+ const tasks = useSelector((state: RootState) => state.tasks.items)
+ let nodes = _.map(graph, node => {
+ if (node.task_id && tasks[node.task_id]) {
+ let task = tasks[node.task_id]
+ return {
+ id: node.id,
+ label: task.id,
+ class: task.status,
+ }
+ }
+ return {
+ id: node.id,
+ label: node.task,
+ class: 'pending',
+ }
+ })
+ let links: d3Link[] = []
+ _.each(graph, node => {
+ _.each(node.depends_on, edge => {
+ links.push({
+ source: edge,
+ target: node.id,
+ })
+ })
+ })
+ return
+ console.log(e)}
+ />
+
+}
+
+export default TaskGraph
\ No newline at end of file
diff --git a/cowait/tasks/graph/graph_task.py b/cowait/tasks/graph/graph_task.py
index bf37c6c6..d3f79265 100644
--- a/cowait/tasks/graph/graph_task.py
+++ b/cowait/tasks/graph/graph_task.py
@@ -4,6 +4,16 @@
class GraphTask(Task):
+ def init(self) -> dict:
+ return {
+ 'ui': [
+ {
+ 'component': 'ui.cowait.io/task-graph',
+ 'path': 'graph',
+ },
+ ]
+ }
+
async def define(self, graph, **inputs):
# this is where you would define your graph nodes
# to create a dag, override this function in a subclass
@@ -22,12 +32,12 @@ async def send_state():
for node in graph.nodes:
task = node_tasks.get(node, None)
state[node.id] = {
- 'id': node.id,
+ 'id': str(node.id),
'task': node.task if not issubclass(node.task, Task) else node.task.__module__,
- 'depends_on': [edge.id for edge in node.edges],
+ 'depends_on': [str(edge.id) for edge in node.edges],
'task_id': None if not task else task.id,
}
- await self.set_state(state)
+ await self.set_state({'graph': state})
await send_state()