Skip to content

Commit

Permalink
info: add completion expression
Browse files Browse the repository at this point in the history
  • Loading branch information
oliver-sanders committed Oct 11, 2024
1 parent 9b3bc07 commit 0dfac1a
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 7 deletions.
38 changes: 35 additions & 3 deletions cypress/component/info.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,15 @@ const TASK = {
message: 'failed',
satisfied: false,
},
]
{
label: 'x',
message: 'xxx',
satisfied: true,
}
],
runtime: {
completion: '(succeeded and x) or failed'
}
},
children: [
{
Expand Down Expand Up @@ -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],
}
})

Expand Down Expand Up @@ -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')
Expand All @@ -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')
})
})

Expand Down
54 changes: 50 additions & 4 deletions src/components/cylc/Info.vue
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,40 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</v-expansion-panel-text>
</v-expansion-panel>

<!-- The completion -->
<v-expansion-panel class="completion-panel">
<v-expansion-panel-title color="blue-grey-lighten-2">
Completion
</v-expansion-panel-title>
<v-expansion-panel-text>
<!-- TODO: We don't have an "is complete" field yet so we cannot
display an aggregate status-->
<ul>
<li
v-for="([complete, indent, line], index) in formatCompletion(completion, outputs)"
:key="index"
>
<span
class="condition"
:class="{satisfied: complete, blank: (complete === null)}"
>
<!-- Indent the line as required -->
<span :style="`margin-left: ${1 * indent}em;`"></span>
{{ line }}
</span>
</li>
</ul>
</v-expansion-panel-text>
</v-expansion-panel>

</v-expansion-panels>
</div>
</template>

<script>
import { useJobTheme } from '@/composables/localStorage'
import GraphNode from '@/components/cylc/GraphNode.vue'
import { formatCompletion } from '@/utils/outputs'
export default {
name: 'InfoComponent',
Expand Down Expand Up @@ -196,8 +223,17 @@ export default {
return this.task?.node?.outputs || {}
},
completion () {
// Task output completion expression stuff.
return this.task?.node?.runtime.completion
}
},
methods: {
formatCompletion,
}
}
</script>
Expand All @@ -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)
Expand Down Expand Up @@ -265,5 +305,11 @@ export default {
list-style: none;
}
}
.completion-panel {
li {
list-style: none;
}
}
}
</style>
71 changes: 71 additions & 0 deletions src/utils/outputs.js
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*/

/** 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
}
4 changes: 4 additions & 0 deletions src/views/Info.vue
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ fragment TaskProxyData on TaskProxy {
label
satisfied
}
runtime {
completion
}
}
fragment TaskDefinitionData on Task {
Expand Down

0 comments on commit 0dfac1a

Please sign in to comment.