18
18
import { sortedIndexBy } from '@/components/cylc/common/sort'
19
19
import { sortWorkflowNamePartNodeOrWorkflowNode } from '@/components/cylc/gscan/sort'
20
20
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
+
21
25
/**
22
26
* @typedef {Object } TreeNode
23
27
* @property {String } id
@@ -60,18 +64,46 @@ function newWorkflowNode (workflow, part) {
60
64
*/
61
65
function newWorkflowPartNode ( id , part ) {
62
66
return {
63
- id : `workflow-name-part- ${ id } ` ,
67
+ id,
64
68
name : part ,
65
69
type : 'workflow-name-part' ,
66
70
node : {
67
- id : id ,
71
+ id,
68
72
name : part ,
69
73
status : ''
70
74
} ,
71
75
children : [ ]
72
76
}
73
77
}
74
78
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
+
75
107
/**
76
108
* Create a workflow node for GScan component.
77
109
*
@@ -84,38 +116,39 @@ function newWorkflowPartNode (id, part) {
84
116
*
85
117
* @param {WorkflowGraphQLData } workflow
86
118
* @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')
87
121
* @returns {TreeNode|null }
88
122
*/
89
- function createWorkflowNode ( workflow , hierarchy ) {
123
+ function createWorkflowNode ( workflow , hierarchy , partsSeparator = DEFAULT_PARTS_SEPARATOR , namesSeparator = DEFAULT_NAMES_SEPARATOR ) {
90
124
if ( ! hierarchy ) {
91
125
return newWorkflowNode ( workflow , null )
92
126
}
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.
100
130
let rootNode = null
101
131
// And a helper used when iterating the array...
102
132
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 )
112
136
if ( rootNode === null ) {
113
137
rootNode = currentNode = partNode
114
138
} else {
115
139
currentNode . children . push ( partNode )
116
140
currentNode = partNode
117
141
}
118
142
}
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
+ }
119
152
return rootNode
120
153
}
121
154
@@ -158,5 +191,6 @@ function addNodeToTree (node, nodes) {
158
191
159
192
export {
160
193
addNodeToTree ,
161
- createWorkflowNode
194
+ createWorkflowNode ,
195
+ parseWorkflowNameParts
162
196
}
0 commit comments