Skip to content

Commit

Permalink
Show flow nums in tree view & command menu
Browse files Browse the repository at this point in the history
  • Loading branch information
MetRonnie committed Dec 6, 2024
1 parent eff665f commit 9cfa0ea
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 20 deletions.
12 changes: 8 additions & 4 deletions src/components/cylc/commandMenu/Menu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ import { mapGetters, mapState } from 'vuex'
import WorkflowState from '@/model/WorkflowState.model'
import { eventBus } from '@/services/eventBus'
import CopyBtn from '@/components/core/CopyBtn.vue'
import { upperFirst } from 'lodash-es'

export default {
name: 'CommandMenu',
Expand Down Expand Up @@ -199,14 +200,14 @@ export default {
// can happen briefly when switching workflows
return
}
let ret = this.node.type
let ret = upperFirst(this.node.type)
if (this.node.type !== 'cycle') {
// NOTE: cycle point nodes don't have associated node data at present
ret += ' - '
ret += ' '
if (this.node.type === 'workflow') {
ret += this.node.node.statusMsg || this.node.node.status || 'state unknown'
ret += upperFirst(this.node.node.statusMsg || this.node.node.status || 'state unknown')
} else {
ret += this.node.node.state || 'state unknown'
ret += upperFirst(this.node.node.state || 'state unknown')
if (this.node.node.isHeld) {
ret += ' (held)'
}
Expand All @@ -216,6 +217,9 @@ export default {
if (this.node.node.isRunahead) {
ret += ' (runahead)'
}
if (this.node.node.flowNums) {
ret += ` • Flows: ${this.node.node.flowNums.replace(/\[|\]/g, '')}`
}
}
}
return ret
Expand Down
28 changes: 24 additions & 4 deletions src/components/cylc/tree/TreeItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,19 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
/>
</div>
<span class="mx-1">{{ node.name }}</span>
<v-chip
label
density="compact"
size="small"
class="ml-1 cursor-default"
:prepend-icon="$options.icons.flow"
:disabled="node.node.state === 'waiting' && !node.node.isQueued"
>
{{ formatFlowNums(node.node.flowNums) }}
<v-tooltip location="right">
Flows: {{ formatFlowNums(node.node.flowNums) }}
</v-tooltip>
</v-chip>
</template>
<template v-else-if="node.type === 'job'">
<Job
Expand Down Expand Up @@ -175,13 +188,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</template>

<script>
import { mdiChevronRight } from '@mdi/js'
import { ref } from 'vue'
import {
mdiChevronRight,
mdiLabelOutline,
} from '@mdi/js'
import Task from '@/components/cylc/Task.vue'
import Job from '@/components/cylc/Job.vue'
import JobDetails from '@/components/cylc/tree/JobDetails.vue'
import {
formatFlowNums,
jobMessageOutputs,
latestJob,
jobMessageOutputs
} from '@/utils/tasks'
import { getIndent, getNodeChildren } from '@/components/cylc/tree/util'

Expand Down Expand Up @@ -240,9 +258,10 @@ export default {
},
},

data () {
setup () {
return {
manuallyExpanded: null,
manuallyExpanded: ref(null),
formatFlowNums,
}
},

Expand Down Expand Up @@ -319,6 +338,7 @@ export default {

icons: {
mdiChevronRight,
flow: mdiLabelOutline
},
}
</script>
7 changes: 7 additions & 0 deletions src/services/mock/json/workflows/one.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@
"isQueued": false,
"isRunahead": false,
"cyclePoint": "20000102T0000Z",
"flowNums": "[1]",
"firstParent": {
"id": "~user/one//20000102T0000Z/root",
"name": "root",
Expand All @@ -133,6 +134,7 @@
"isQueued": false,
"isRunahead": false,
"cyclePoint": "20000102T0000Z",
"flowNums": "[1]",
"firstParent": {
"id": "~user/one//20000102T0000Z/SUCCEEDED",
"name": "SUCCEEDED",
Expand All @@ -152,6 +154,7 @@
"isQueued": false,
"isRunahead": false,
"cyclePoint": "20000102T0000Z",
"flowNums": "[1]",
"firstParent": {
"id": "~user/one//20000102T0000Z/BAD",
"name": "BAD",
Expand All @@ -170,6 +173,7 @@
"isQueued": false,
"isRunahead": false,
"cyclePoint": "20000102T0000Z",
"flowNums": "[1]",
"firstParent": {
"id": "~user/one//20000102T0000Z/BAD",
"name": "BAD",
Expand All @@ -188,6 +192,7 @@
"isQueued": false,
"isRunahead": false,
"cyclePoint": "20000102T0000Z",
"flowNums": "[1]",
"firstParent": {
"id": "~user/one//20000102T0000Z/root",
"name": "root",
Expand All @@ -206,6 +211,7 @@
"isQueued": false,
"isRunahead": false,
"cyclePoint": "20000102T0000Z",
"flowNums": "[1]",
"firstParent": {
"id": "~user/one//20000102T0000Z/SUCCEEDED",
"name": "SUCCEEDED",
Expand All @@ -225,6 +231,7 @@
"isQueued": false,
"isRunahead": false,
"cyclePoint": "20000102T0000Z",
"flowNums": "[1]",
"firstParent": {
"id": "~user/one//20000102T0000Z/root",
"name": "root",
Expand Down
1 change: 1 addition & 0 deletions src/styles/cylc/_tree.scss
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ $icon-width: 1.5rem;
.node-data {
display: flex;
flex-wrap: nowrap;
align-items: center;
.node-summary {
display: flex;
flex-wrap: nowrap;
Expand Down
22 changes: 11 additions & 11 deletions src/utils/tasks.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const isStoppedOrderedStates = [
* @returns {string} a valid Task State name, or empty string if not found
* @link @see https://github.com/cylc/cylc-flow/blob/d66ae5c3ce8c749c8178d1cd53cb8c81d1560346/lib/cylc/task_state_prop.py
*/
function extractGroupState (childStates, isStopped = false) {
export function extractGroupState (childStates, isStopped = false) {
const states = isStopped ? isStoppedOrderedStates : TaskState.enumValues
for (const state of states) {
if (childStates.includes(state.name)) {
Expand All @@ -50,7 +50,7 @@ function extractGroupState (childStates, isStopped = false) {
return ''
}

function latestJob (taskProxy) {
export function latestJob (taskProxy) {
return taskProxy?.children?.[0]?.node
}

Expand All @@ -67,7 +67,7 @@ function latestJob (taskProxy) {
* }
* }
*/
function jobMessageOutputs (jobNode) {
export function jobMessageOutputs (jobNode) {
const ret = []

for (const message of jobNode.node.messages || []) {
Expand Down Expand Up @@ -96,7 +96,7 @@ function jobMessageOutputs (jobNode) {
* 00:00:00, rather than undefined
* @return {string=} Formatted duration
*/
function formatDuration (dur, allowZeros = false) {
export function formatDuration (dur, allowZeros = false) {
if (dur || (dur === 0 && allowZeros === true)) {
const seconds = dur % 60
const minutes = ((dur - seconds) / 60) % 60
Expand All @@ -118,16 +118,16 @@ function formatDuration (dur, allowZeros = false) {
return undefined
}

function dtMean (taskNode) {
export function dtMean (taskNode) {
// Convert to an easily read duration format:
const dur = taskNode.node?.task?.meanElapsedTime
return formatDuration(dur)
}

export {
extractGroupState,
latestJob,
jobMessageOutputs,
formatDuration,
dtMean
/**
* @param {string} flowNums - Flow numbers in DB format
* @returns {string} - Flow numbers in pretty format
*/
export function formatFlowNums (flowNums) {
return JSON.parse(flowNums).join(', ') || 'None'

Check failure on line 132 in src/utils/tasks.js

View workflow job for this annotation

GitHub Actions / unit-test-and-build

tests/unit/components/cylc/tree/tree.vue.spec.js > Tree component > auto strips []

SyntaxError: "undefined" is not valid JSON ❯ Proxy.formatFlowNums src/utils/tasks.js:132:15 ❯ src/components/cylc/tree/TreeItem.vue:285:18 ❯ Proxy.renderFnWithContext node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:814:13 ❯ default node_modules/vuetify/src/components/VChip/VChip.tsx:319:22 ❯ normalizeChildren node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:7293:34 ❯ createBaseVNode node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:7104:5 ❯ _createVNode node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:7181:10 ❯ createVNodeWithArgsTransform node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:7058:10 ❯ Proxy.<anonymous> node_modules/vuetify/src/components/VChip/VChip.tsx:229:49

Check failure on line 132 in src/utils/tasks.js

View workflow job for this annotation

GitHub Actions / unit-test-and-build

tests/unit/components/cylc/tree/treeitem.vue.spec.js

SyntaxError: "undefined" is not valid JSON ❯ Proxy.formatFlowNums src/utils/tasks.js:132:15 ❯ src/components/cylc/tree/TreeItem.vue:285:18 ❯ Proxy.renderFnWithContext node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:814:13 ❯ default node_modules/vuetify/src/components/VChip/VChip.tsx:319:22 ❯ normalizeChildren node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:7293:34 ❯ createBaseVNode node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:7104:5 ❯ _createVNode node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:7181:10 ❯ createVNodeWithArgsTransform node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:7058:10 ❯ Proxy.<anonymous> node_modules/vuetify/src/components/VChip/VChip.tsx:229:49
}
1 change: 1 addition & 0 deletions src/views/Tree.vue
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ fragment TaskProxyData on TaskProxy {
firstParent {
id
}
flowNums
}

fragment JobData on Job {
Expand Down
19 changes: 18 additions & 1 deletion tests/unit/utils/tasks.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,14 @@
*/

import TaskState from '@/model/TaskState.model'
import { dtMean, extractGroupState, latestJob, formatDuration, jobMessageOutputs } from '@/utils/tasks'
import {
dtMean,
extractGroupState,
latestJob,
formatDuration,
jobMessageOutputs,
formatFlowNums,
} from '@/utils/tasks'

describe('tasks', () => {
describe('extractGroupState', () => {
Expand Down Expand Up @@ -207,4 +214,14 @@ describe('tasks', () => {
])
})
})

describe('formatFlowNums', () => {
it.each([
['[1]', '1'],
['[1, 4, 8]', '1, 4, 8'],
['[]', 'None'],
])('formatFlowNums(%s) -> %s', (input, expected) => {
expect(formatFlowNums(input)).toEqual(expected)
})
})
})

0 comments on commit 9cfa0ea

Please sign in to comment.