diff --git a/cypress/component/info.cy.js b/cypress/component/info.cy.js
index f9cfad5f7..132cecb6d 100644
--- a/cypress/component/info.cy.js
+++ b/cypress/component/info.cy.js
@@ -98,7 +98,15 @@ const TASK = {
message: 'failed',
satisfied: false,
},
- ]
+ {
+ label: 'x',
+ message: 'xxx',
+ satisfied: true,
+ }
+ ],
+ runtime: {
+ completion: '(succeeded and x) or failed'
+ }
},
children: [
{
@@ -127,7 +135,7 @@ describe('Info component', () => {
task: TASK,
class: 'job_theme--default',
// NOTE: expand all sections by default
- panelExpansion: [0, 1, 2],
+ panelExpansion: [0, 1, 2, 3],
}
})
@@ -175,7 +183,7 @@ describe('Info component', () => {
// the outputs panel
cy.get('.outputs-panel.v-expansion-panel--active').should('be.visible')
.find('.condition')
- .should('have.length', 3)
+ .should('have.length', 4)
.then((selector) => {
expect(selector[0]).to.contain('started')
expect(selector[0].classList.toString()).to.equal('condition satisfied')
@@ -185,6 +193,30 @@ describe('Info component', () => {
expect(selector[2]).to.contain('failed')
expect(selector[2].classList.toString()).to.equal('condition')
+
+ expect(selector[3]).to.contain('x')
+ expect(selector[3].classList.toString()).to.equal('condition satisfied')
+ })
+
+ // the completion panel
+ cy.get('.completion-panel.v-expansion-panel--active').should('be.visible')
+ .find('.condition')
+ .should('have.length', 5)
+ .then((selector) => {
+ expect(selector[0]).to.contain('(')
+ expect(selector[0].classList.toString()).to.equal('condition blank')
+
+ expect(selector[1]).to.contain('succeeded')
+ expect(selector[1].classList.toString()).to.equal('condition')
+
+ expect(selector[2]).to.contain('and x')
+ expect(selector[2].classList.toString()).to.equal('condition satisfied')
+
+ expect(selector[3]).to.contain(')')
+ expect(selector[3].classList.toString()).to.equal('condition blank')
+
+ expect(selector[4]).to.contain('or failed')
+ expect(selector[4].classList.toString()).to.equal('condition')
})
})
diff --git a/src/components/cylc/Info.vue b/src/components/cylc/Info.vue
index 9d22716cd..04581ec43 100644
--- a/src/components/cylc/Info.vue
+++ b/src/components/cylc/Info.vue
@@ -135,6 +135,32 @@ along with this program. If not, see .
+
+
+
+ Completion
+
+
+
+
+ -
+
+
+
+ {{ line }}
+
+
+
+
+
+
@@ -142,6 +168,7 @@ along with this program. If not, see .
@@ -214,18 +250,22 @@ export default {
.condition {
opacity: 0.6;
}
- .condition.satisfied {
+ .condition.satisfied, .condition.blank {
opacity: 1;
}
// prefixes a tick or cross before the entry
.condition:before {
- content: '\25CB';
- padding-right: 0.5em;
+ display: inline-block;
+ content: '\25CB'; /* empty circle */
+ width: 1.5em;
color: rgb(0, 0, 0);
}
.condition.satisfied:before {
- content: '\25CF';
+ content: '\25CF'; /* filled circle */
+ }
+ .condition.blank:before {
+ content: ''; /* blank */
}
// for prerequsite task "aliases" (used in conditional expressions)
@@ -265,5 +305,11 @@ export default {
list-style: none;
}
}
+
+ .completion-panel {
+ li {
+ list-style: none;
+ }
+ }
}
diff --git a/src/utils/outputs.js b/src/utils/outputs.js
new file mode 100644
index 000000000..deb0b1173
--- /dev/null
+++ b/src/utils/outputs.js
@@ -0,0 +1,71 @@
+/**
+ * Copyright (C) NIWA & British Crown (Met Office) & Contributors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/** Functionality relating to task output formatting. **/
+
+/** Format a completion expression for display.
+ *
+ * @param {str} completion - The task's completion expression.
+ * @param {Array} outputs - The task's outputs as obtained from GraphQL as an
+ * array of objects with "label" and "satisfied" attributes.
+ *
+ * @returns {Array} - [isSatisfied, indentLevel, text]
+ **/
+
+export function formatCompletion (completion, outputs) {
+ // the array to return
+ const lines = []
+ // indent level of the expression
+ let indent = 0
+ // text yet to be added to the return result
+ let buffer = ''
+
+ // break the completion expression down into parts and iterate over them
+ for (let part of completion.split(/(and|or|\(|\))/)) {
+ part = part.trim()
+
+ if (!part) {
+ continue
+ }
+
+ if (part === '(') {
+ // open bracket
+ lines.push([null, indent, `${buffer}(`])
+ buffer = ''
+ indent = indent + 1
+ } else if (part === ')') {
+ // close bracket
+ indent = indent - 1
+ lines.push([null, indent, `${buffer})`])
+ buffer = ''
+ } else if (part === 'and' || part === 'or') {
+ // local operator
+ buffer = `${part} `
+ } else {
+ // Cylc output -> look it up in the outputs Array
+ for (const output of outputs) {
+ if (output.label === part) {
+ lines.push([output.satisfied, indent, `${buffer}${part}`])
+ break
+ }
+ }
+ buffer = ''
+ }
+ }
+
+ return lines
+}
diff --git a/src/views/Info.vue b/src/views/Info.vue
index d3bcd1568..3b60bfa5e 100644
--- a/src/views/Info.vue
+++ b/src/views/Info.vue
@@ -94,6 +94,10 @@ fragment TaskProxyData on TaskProxy {
label
satisfied
}
+
+ runtime {
+ completion
+ }
}
fragment TaskDefinitionData on Task {