1818import { sortedIndexBy } from '@/components/cylc/common/sort'
1919import { sortWorkflowNamePartNodeOrWorkflowNode } from '@/components/cylc/gscan/sort'
2020
21+ // TODO: move to the `options` parameter that is passed to deltas; ideally it would be stored in DB or localstorage.
22+ const DEFAULT_PARTS_SEPARATOR = '|'
23+ const DEFAULT_NAMES_SEPARATOR = '/'
24+
2125/**
2226 * @typedef {Object } TreeNode
2327 * @property {String } id
@@ -60,18 +64,46 @@ function newWorkflowNode (workflow, part) {
6064 */
6165function newWorkflowPartNode ( id , part ) {
6266 return {
63- id : `workflow-name-part- ${ id } ` ,
67+ id,
6468 name : part ,
6569 type : 'workflow-name-part' ,
6670 node : {
67- id : id ,
71+ id,
6872 name : part ,
6973 status : ''
7074 } ,
7175 children : [ ]
7276 }
7377}
7478
79+ /**
80+ * @param {String } workflowId - Workflow ID
81+ * @param {String } partsSeparator - separator for workflow name parts (e.g. '|' as in 'user|research/workflow/run1')
82+ * @param {String } namesSeparator - separator used for workflow and run names (e.g. '/' as in 'research/workflow/run1')
83+ */
84+ function parseWorkflowNameParts ( workflowId , partsSeparator = DEFAULT_PARTS_SEPARATOR , namesSeparator = DEFAULT_NAMES_SEPARATOR ) {
85+ if ( ! workflowId || workflowId . trim ( ) === '' ) {
86+ throw new Error ( 'Missing ID for workflow name parts' )
87+ }
88+ const idParts = workflowId . split ( partsSeparator )
89+ if ( idParts . length !== 2 ) {
90+ throw new Error ( `Invalid parts found, expected at least 2 parts in ${ workflowId } ` )
91+ }
92+ const user = idParts [ 0 ]
93+ const workflowName = idParts [ 1 ]
94+ const parts = workflowName . split ( namesSeparator )
95+ // The name, used for display in the tree. Can be a workflow name like 'd', or a runN like 'run1'.
96+ const name = parts . pop ( )
97+ return {
98+ partsSeparator,
99+ namesSeparator,
100+ user, // user
101+ workflowName, // a/b/c/d/run1
102+ parts, // [a, b, c, d]
103+ name // run1
104+ }
105+ }
106+
75107/**
76108 * Create a workflow node for GScan component.
77109 *
@@ -84,38 +116,39 @@ function newWorkflowPartNode (id, part) {
84116 *
85117 * @param {WorkflowGraphQLData } workflow
86118 * @param {boolean } hierarchy - whether to parse the Workflow name and create a hierarchy or not
119+ * @param {String } partsSeparator - separator for workflow name parts (e.g. '|' as in 'part1|part2|...')
120+ * @param {String } namesSeparator - separator used for workflow and run names (e.g. '/' as in 'workflow/run1')
87121 * @returns {TreeNode|null }
88122 */
89- function createWorkflowNode ( workflow , hierarchy ) {
123+ function createWorkflowNode ( workflow , hierarchy , partsSeparator = DEFAULT_PARTS_SEPARATOR , namesSeparator = DEFAULT_NAMES_SEPARATOR ) {
90124 if ( ! hierarchy ) {
91125 return newWorkflowNode ( workflow , null )
92126 }
93- const workflowIdParts = workflow . id . split ( '|' )
94- // The prefix contains all the ID parts, except for the workflow name.
95- let prefix = workflowIdParts . slice ( 0 , workflowIdParts . length - 1 )
96- // The name is here.
97- const workflowName = workflow . name
98- const parts = workflowName . split ( '/' )
99- // Returned node...
127+ const workflowNameParts = parseWorkflowNameParts ( workflow . id , partsSeparator , namesSeparator )
128+ let prefix = workflowNameParts . user
129+ // The root node, returned in this function.
100130 let rootNode = null
101131 // And a helper used when iterating the array...
102132 let currentNode = null
103- while ( parts . length > 0 ) {
104- const part = parts . shift ( )
105- // For the first part, we need to add an ID separator `|`, but for the other parts
106- // we actually want to use the name parts separator `/`.
107- prefix = prefix . includes ( '/' ) ? `${ prefix } /${ part } ` : `${ prefix } |${ part } `
108- const partNode = parts . length !== 0
109- ? newWorkflowPartNode ( prefix , part )
110- : newWorkflowNode ( workflow , part )
111-
133+ for ( const part of workflowNameParts . parts ) {
134+ prefix = prefix === null ? part : `${ prefix } ${ partsSeparator } ${ part } `
135+ const partNode = newWorkflowPartNode ( prefix , part )
112136 if ( rootNode === null ) {
113137 rootNode = currentNode = partNode
114138 } else {
115139 currentNode . children . push ( partNode )
116140 currentNode = partNode
117141 }
118142 }
143+ const workflowNode = newWorkflowNode ( workflow , workflowNameParts . name )
144+
145+ if ( currentNode === null ) {
146+ // We will return the workflow node only. It will be appended directly to the tree as a new leaf.
147+ rootNode = workflowNode
148+ } else {
149+ // Add the workflow node to the end of the branch as a leaf. Note that the top of the branch is returned in this case.
150+ currentNode . children . push ( workflowNode )
151+ }
119152 return rootNode
120153}
121154
@@ -158,5 +191,6 @@ function addNodeToTree (node, nodes) {
158191
159192export {
160193 addNodeToTree ,
161- createWorkflowNode
194+ createWorkflowNode ,
195+ parseWorkflowNameParts
162196}
0 commit comments