Skip to content

Commit 97c4037

Browse files
committed
Show task state and xtriggers in the info view.
Show wall_clock Trigger time in Z time. * Use v-table for xtriggers * Get rid of the trigger time column and modify the trigger_time to ISO in place * Remove unwanted css add sorting for xtriggers
1 parent 20ec8cf commit 97c4037

File tree

5 files changed

+221
-7
lines changed

5 files changed

+221
-7
lines changed

src/components/cylc/Info.vue

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,42 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
8484
</v-expansion-panel-text>
8585
</v-expansion-panel>
8686

87+
<v-expansion-panel class="run-mode-panel">
88+
<v-expansion-panel-title color="blue-grey-lighten-2">
89+
Run Mode
90+
</v-expansion-panel-title>
91+
<v-expansion-panel-text>
92+
<v-icon>{{ runModeIcon }}</v-icon> {{ runMode }}
93+
</v-expansion-panel-text>
94+
</v-expansion-panel>
95+
96+
<v-expansion-panel
97+
v-if="xtriggers.length"
98+
class="xtriggers-panel"
99+
>
100+
<v-expansion-panel-title color="blue-grey-lighten-1">
101+
Xtriggers
102+
</v-expansion-panel-title>
103+
<v-expansion-panel-text>
104+
<v-table density="compact">
105+
<thead>
106+
<tr>
107+
<th>Label</th>
108+
<th>ID</th>
109+
<th>Is satisfied</th>
110+
</tr>
111+
</thead>
112+
<tbody>
113+
<tr v-for="xt in xtriggers" :key="xt">
114+
<td>{{ xt.label }}</td>
115+
<td>{{ xt.id2 }}</td>
116+
<td><v-icon>{{ xt.satisfactionIcon }}</v-icon></td>
117+
</tr>
118+
</tbody>
119+
</v-table>
120+
</v-expansion-panel-text>
121+
</v-expansion-panel>
122+
87123
<!-- The prereqs -->
88124
<v-expansion-panel class="prerequisites-panel">
89125
<v-expansion-panel-title color="blue-grey-lighten-2">
@@ -169,6 +205,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
169205
import { useJobTheme } from '@/composables/localStorage'
170206
import GraphNode from '@/components/cylc/GraphNode.vue'
171207
import { formatCompletion } from '@/utils/outputs'
208+
import { mdiSkipForward, mdiChatQuestion, mdiGhostOutline, mdiPlay, mdiDramaMasks, mdiCheckboxOutline, mdiCheckboxBlankOutline } from '@mdi/js'
172209
173210
export default {
174211
name: 'InfoComponent',
@@ -226,6 +263,58 @@ export default {
226263
completion () {
227264
// Task output completion expression stuff.
228265
return this.task?.node?.runtime.completion
266+
},
267+
268+
runModeIcon () {
269+
// Task Run Mode:
270+
if (this.task?.node?.runtime.runMode === 'Skip') {
271+
return mdiSkipForward
272+
} else if (this.task?.node?.runtime.runMode === 'Live') {
273+
return mdiPlay
274+
} else if (this.task?.node?.runtime.runMode === 'Simulation') {
275+
return mdiGhostOutline
276+
} else if (this.task?.node?.runtime.runMode === 'Dummy') {
277+
return mdiDramaMasks
278+
}
279+
return mdiChatQuestion
280+
},
281+
282+
runMode () {
283+
// Task Run Mode:
284+
return this.task?.node?.runtime.runMode
285+
},
286+
287+
xtriggers () {
288+
const xtriggers = this.task?.node?.xtriggers
289+
xtriggers.forEach(xtrigger => {
290+
if (xtrigger.satisfied === true) {
291+
xtrigger.satisfactionIcon = mdiCheckboxOutline
292+
} else {
293+
xtrigger.satisfactionIcon = mdiCheckboxBlankOutline
294+
}
295+
296+
// Extract the trigger time from the ID
297+
const re = /trigger_time=(?<unixTime>[0-9.]+)/
298+
const result = re.exec(xtrigger.id)
299+
if (result === null) {
300+
xtrigger.id2 = xtrigger.id
301+
} else {
302+
// Since we've created this date from a Unix timestamp,
303+
// we can safely assume it is in UTC:
304+
xtrigger.id2 = xtrigger.id.replace(
305+
re,
306+
'trigger_time=' + new Date(result[1] * 1000).toISOString().slice(0, -5) + 'Z'
307+
)
308+
}
309+
})
310+
// Sort the xtriggers by label, then by ID:
311+
xtriggers.sort(function (a, b) {
312+
if (a.label === b.label) {
313+
return a.id2 > b.id2 ? 1 : -1
314+
}
315+
return a.label > b.label ? 1 : -1
316+
})
317+
return xtriggers
229318
}
230319
231320
},

src/services/mock/json/infoView.json

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,27 @@
7676
],
7777

7878
"runtime": {
79-
"completion": "succeeded"
80-
}
79+
"completion": "succeeded",
80+
"runMode": "Live"
81+
},
82+
83+
"xtriggers": [
84+
{
85+
"label": "xtrigger",
86+
"id": "myxt(foo=42)",
87+
"satisfied": true
88+
},
89+
{
90+
"label": "another xtrigger",
91+
"id": "myxt(foo=41)",
92+
"satisfied": false
93+
},
94+
{
95+
"label": "clock xtrigger",
96+
"id": "wall_clock(trigger_time=440121600)",
97+
"satisfied": true
98+
}
99+
]
81100
}
82101
]
83102
}

src/views/Info.vue

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,13 @@ fragment TaskProxyData on TaskProxy {
9797
9898
runtime {
9999
completion
100+
runMode
101+
}
102+
103+
xtriggers {
104+
label
105+
id
106+
satisfied
100107
}
101108
}
102109

tests/component/specs/info.cy.js

Lines changed: 74 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,21 @@ const TASK = {
105105
}
106106
],
107107
runtime: {
108-
completion: '(succeeded and x) or failed'
109-
}
108+
completion: '(succeeded and x) or failed',
109+
runMode: 'Live',
110+
},
111+
xtriggers: [
112+
{
113+
label: 'xtrigger',
114+
id: 'my-xtrigger(foo=42)',
115+
satisfied: false
116+
},
117+
{
118+
label: 'wallclock-xtrigger',
119+
id: 'wall_clock(trigger_time=634737600)',
120+
satisfied: true
121+
}
122+
]
110123
},
111124
children: [
112125
{
@@ -135,7 +148,7 @@ describe('Info component', () => {
135148
task: TASK,
136149
class: 'job_theme--default',
137150
// NOTE: expand all sections by default
138-
panelExpansion: [0, 1, 2, 3],
151+
panelExpansion: [0, 1, 2, 3, 4, 5],
139152
}
140153
})
141154

@@ -156,6 +169,23 @@ describe('Info component', () => {
156169
.should('have.attr', 'href', 'https://cylc.org')
157170
.contains(/^https:\/\/cylc.org$/)
158171

172+
// the run mode panel:
173+
cy.get('.run-mode-panel.v-expansion-panel--active').should('be.visible')
174+
.contains('Live')
175+
176+
// the xtriggers panel
177+
cy.get('.xtriggers-panel.v-expansion-panel--active').should('be.visible')
178+
.get('table')
179+
.get('tbody tr')
180+
.children()
181+
.then((selector) => {
182+
expect(selector[0].innerText).to.equal('xtrigger')
183+
expect(selector[1].innerText).to.equal('my-xtrigger(foo=42)')
184+
expect(selector[2].innerText).to.be.equal('')
185+
expect(selector[3].innerText).to.equal('wallclock-xtrigger')
186+
expect(selector[4].innerText).to.equal('wall_clock(trigger_time=1990-02-11T12:00:00Z)')
187+
})
188+
159189
// the prerequisites panel
160190
cy.get('.prerequisites-panel.v-expansion-panel--active').should('be.visible')
161191
.find('.prerequisite-alias.condition')
@@ -246,7 +276,7 @@ describe('Info component', () => {
246276
.get('@wrapper').then(({ wrapper }) => {
247277
expect(
248278
wrapper.emitted('update:panelExpansion')[0][0]
249-
).to.deep.equal([0, 1])
279+
).to.deep.equal([0, 3])
250280
})
251281
})
252282

@@ -266,6 +296,8 @@ describe('Info component', () => {
266296
},
267297
prerequisites: [],
268298
outputs: [],
299+
runtime: {},
300+
xtriggers: []
269301
},
270302
children: [],
271303
}
@@ -275,8 +307,45 @@ describe('Info component', () => {
275307
task,
276308
class: 'job_theme--default',
277309
// NOTE: expand all sections by default
278-
panelExpansion: [0, 1, 2],
310+
panelExpansion: [0, 1, 2, 3],
279311
}
280312
})
281313
})
314+
315+
for (const mode of ['Skip', 'Simulation', 'Dummy']) {
316+
it('should display ' + mode + ' mode', () => {
317+
// ensure the component can be mounted without errors for empty states
318+
// i.e. no metadata, prerequisites, outputs or jobs
319+
const tokens = new Tokens('~user/workflow//1234/foo')
320+
const task = {
321+
id: tokens.id,
322+
name: tokens.task,
323+
tokens,
324+
node: {
325+
task: {
326+
meta: {
327+
customMeta: {}
328+
}
329+
},
330+
prerequisites: [],
331+
outputs: [],
332+
runtime: { runMode: mode },
333+
xtriggers: []
334+
},
335+
children: [],
336+
}
337+
338+
cy.vmount(InfoComponent, {
339+
props: {
340+
task,
341+
class: 'job_theme--default',
342+
// Expand just the run mode panel
343+
panelExpansion: [1],
344+
}
345+
})
346+
347+
cy.get('.run-mode-panel.v-expansion-panel--active').should('be.visible')
348+
.contains(mode)
349+
})
350+
}
282351
})

tests/e2e/specs/info.cy.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,35 @@ describe('Info View', () => {
4242
.click({ force: true })
4343
.get('.v-expansion-panel--active')
4444
.should('have.length', 2)
45+
.and('contain', 'Live')
46+
47+
.get('.c-info .v-expansion-panel:nth-child(3)')
48+
.find('button')
49+
.click({ force: true })
50+
.get('.v-expansion-panel--active')
51+
.get('.c-info .v-expansion-panel:nth-child(3)')
52+
.get('table')
53+
.should('contain', 'xtrigger')
54+
.and('contain', 'myxt(foo=42)')
55+
.should('contain', 'another xtrigger')
56+
.and('contain', 'myxt(foo=41)')
57+
58+
.get('.c-info .v-expansion-panel:nth-child(4)')
59+
.find('button')
60+
.click({ force: true })
61+
.get('.v-expansion-panel--active')
62+
.should('have.length', 4)
63+
64+
.get('.c-info .v-expansion-panel:nth-child(5)')
65+
.find('button')
66+
.click({ force: true })
67+
.get('.v-expansion-panel--active')
68+
.should('have.length', 5)
69+
70+
.get('.c-info .v-expansion-panel:nth-child(6)')
71+
.find('button')
72+
.click({ force: true })
73+
.get('.v-expansion-panel--active')
74+
.should('have.length', 6)
4575
})
4676
})

0 commit comments

Comments
 (0)