1- import { useEffect , useState } from "react" ;
1+ import { useEffect , useMemo , useState } from "react" ;
22import { useLazyLoadQuery } from "react-relay" ;
33import { TaskInfo } from "workflows-lib/lib/components/workflow/TaskInfo" ;
4- import { Artifact , Task , TaskStatus } from "workflows-lib/lib/types" ;
4+ import { Artifact , Task , TaskNode , TaskStatus } from "workflows-lib/lib/types" ;
55import WorkflowRelay , { workflowRelayQuery } from "./WorkflowRelay" ;
66import { isWorkflowWithTasks } from "../utils" ;
77import { Visit } from "@diamondlightsource/sci-react-ui" ;
88import { WorkflowRelayQuery as WorkflowRelayQueryType } from "./__generated__/WorkflowRelayQuery.graphql" ;
9+ import { Box , ToggleButton } from "@mui/material" ;
10+ import { buildTaskTree } from "workflows-lib/lib/utils/tasksFlowUtils" ;
911
1012interface SingleWorkflowViewProps {
1113 visit : Visit ;
@@ -22,49 +24,124 @@ export default function SingleWorkflowView({
2224 visit : visit ,
2325 name : workflowName ,
2426 } ) ;
25- const workflow = data . workflow ;
2627
2728 const [ artifactList , setArtifactList ] = useState < Artifact [ ] > ( [ ] ) ;
29+ const [ outputSelected , setOutputSelected ] = useState < boolean > ( false ) ;
30+ const [ outputTasks , setOutputTasks ] = useState < string [ ] > ( [ ] ) ;
31+ const [ selectedTasks , setSelectedTasks ] = useState < string [ ] > ( [ ] ) ;
32+ const [ fetchedTasks , setFetchedTasks ] = useState < Task [ ] > ( [ ] ) ;
33+
34+ const taskTree = useMemo ( ( ) => buildTaskTree ( fetchedTasks ) , [ fetchedTasks ] ) ;
35+
36+ const handleSelectOutput = ( ) => {
37+ setOutputSelected ( ! outputSelected ) ;
38+ } ;
2839
2940 useEffect ( ( ) => {
30- let fetchedTasks : Task [ ] = [ ] ;
3141 if ( data . workflow . status && isWorkflowWithTasks ( data . workflow . status ) ) {
32- fetchedTasks = data . workflow . status . tasks . map ( ( task ) => ( {
33- id : task . id ,
34- name : task . name ,
35- status : task . status as TaskStatus ,
36- artifacts : task . artifacts . map ( ( artifact ) => ( {
37- ...artifact ,
38- parentTask : task . name ,
39- key : `${ task . name } -${ artifact . name } ` ,
40- } ) ) ,
41- workflow : workflowName ,
42- instrumentSession : visit ,
43- stepType : task . stepType ,
44- } ) ) ;
42+ setFetchedTasks (
43+ data . workflow . status . tasks . map ( ( task ) => ( {
44+ id : task . id ,
45+ name : task . name ,
46+ status : task . status as TaskStatus ,
47+ depends : [ ...task . depends ] ,
48+ artifacts : task . artifacts . map ( ( artifact ) => ( {
49+ ...artifact ,
50+ parentTask : task . name ,
51+ key : `${ task . name } -${ artifact . name } ` ,
52+ } ) ) ,
53+ workflow : workflowName ,
54+ instrumentSession : visit ,
55+ stepType : task . stepType ,
56+ } ) )
57+ ) ;
4558 }
59+ } , [ data . workflow . status ] ) ;
4660
47- const filteredTasks = tasknames ?. length
48- ? tasknames
61+ useEffect ( ( ) => {
62+ const filteredTasks = selectedTasks ?. length
63+ ? selectedTasks
4964 . map ( ( name ) => fetchedTasks . find ( ( task ) => task . name === name ) )
5065 . filter ( ( task ) : task is Task => ! ! task )
5166 : fetchedTasks ;
5267 setArtifactList ( filteredTasks . flatMap ( ( task ) => task . artifacts ) ) ;
53- } , [ workflow , tasknames , data . workflow . status ] ) ;
68+ } , [ selectedTasks , fetchedTasks ] ) ;
69+
70+ useEffect ( ( ) => {
71+ let newOutputTasks : string [ ] = [ ] ;
72+ const traverse = ( tasks : TaskNode [ ] ) => {
73+ const sortedTasks = [ ...tasks ] . sort ( ( a , b ) =>
74+ a . name . localeCompare ( b . name )
75+ ) ;
76+ sortedTasks . forEach ( ( taskNode ) => {
77+ if (
78+ taskNode . children &&
79+ taskNode . children . length == 0 &&
80+ ! newOutputTasks . includes ( taskNode . name )
81+ ) {
82+ newOutputTasks . push ( taskNode . name ) ;
83+ } else if ( taskNode . children && taskNode . children . length > 0 ) {
84+ traverse ( taskNode . children ) ;
85+ }
86+ } ) ;
87+ } ;
88+ traverse ( taskTree ) ;
89+ setOutputTasks ( newOutputTasks ) ;
90+ } , [ taskTree ] ) ;
91+
92+ useEffect ( ( ) => {
93+ if ( outputSelected ) {
94+ setSelectedTasks ( outputTasks ) ;
95+ } else {
96+ setSelectedTasks ( tasknames ? tasknames : [ ] ) ;
97+ }
98+ } , [ outputTasks , outputSelected , tasknames ] ) ;
5499
55100 return (
56101 < >
57- < WorkflowRelay
58- key = { workflowName }
59- visit = { visit }
60- workflowName = { workflowName }
61- workflowLink
62- expanded = { true }
63- highlightedTaskNames = { tasknames }
64- />
65- < div style = { { width : "100%" , marginTop : "1rem" } } >
66- < TaskInfo artifactList = { artifactList } />
67- </ div >
102+ < Box
103+ sx = { {
104+ position : "relative" ,
105+ display : "inline-flex" ,
106+ alignItems : "flex-start" ,
107+ width : "100%" ,
108+ height : "100%" ,
109+ } }
110+ >
111+ < Box
112+ sx = { {
113+ display : "flex" ,
114+ flexDirection : "row" ,
115+ width : "100%" ,
116+ height : "100%" ,
117+ gap : 2 ,
118+ } }
119+ >
120+ < ToggleButton
121+ value = "output"
122+ aria-label = "output"
123+ selected = { outputSelected }
124+ onClick = { handleSelectOutput }
125+ sx = { { position : "absolute" , left : "-100px" } }
126+ >
127+ OUTPUT
128+ </ ToggleButton >
129+ < WorkflowRelay
130+ key = { workflowName }
131+ visit = { visit }
132+ workflowName = { workflowName }
133+ fetchedTasks = { fetchedTasks }
134+ workflowLink
135+ expanded = { true }
136+ highlightedTaskNames = { selectedTasks }
137+ />
138+ </ Box >
139+ </ Box >
140+ { tasknames && (
141+ < div style = { { width : "100%" , marginTop : "1rem" } } >
142+ < TaskInfo artifactList = { artifactList } />
143+ </ div >
144+ ) }
68145 </ >
69146 ) ;
70147}
0 commit comments