Skip to content

Commit

Permalink
Merge pull request #1312 from MetRonnie/table-view
Browse files Browse the repository at this point in the history
Fix incorrect latest job in table view
  • Loading branch information
oliver-sanders authored Jun 14, 2023
2 parents 9a49c59 + 706c565 commit 63bdcc2
Show file tree
Hide file tree
Showing 10 changed files with 158 additions and 86 deletions.
5 changes: 5 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ ones in. -->
[#1269](https://github.com/cylc/cylc-ui/pull/1269) -
Upgraded Vue and Vuetify frameworks to v3.

### Fixes

[#1312](https://github.com/cylc/cylc-ui/pull/1312) -
Fix incorrect latest job info in table view.

-------------------------------------------------------------------------------
## __cylc-ui-1.6.0 (<span actions:bind='release-date'>Released 2023-04-27</span>)__

Expand Down
4 changes: 2 additions & 2 deletions src/components/cylc/table/Table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<Task
v-cylc-object="item.value.task"
:task="item.value.task.node"
:startTime="((item.value.latestJob || {}).node || {}).startedTime"
:startTime="item.value.latestJob?.node?.startedTime"
/>
</div>
<div class="mr-1">
<Job
v-cylc-object="item.value.task"
:status="item.value.task.node.state"
:previous-state="((item.value.previousJob || {}).node || {}).state"
:previous-state="item.value.previousJob?.node?.state"
/>
</div>
<div>{{ item.value.task.name }}</div>
Expand Down
9 changes: 4 additions & 5 deletions src/store/workflows.module.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ const getters = {
while (stack.length) {
item = stack.pop()
if (parentNodeTypes.includes(item.type)) {
// this is above "nodeTyoe" in the tree, look through its child nodes
// this is above "nodeType" in the tree, look through its child nodes
stack.push(...item.children)
} else if (
item.type === nodeType &&
Expand All @@ -99,12 +99,11 @@ function createTree (state) {
if (state.cylcTree) {
return
}
const tree = {
state.cylcTree = {
$index: {},
id: '$root'
id: '$root',
children: [],
}
tree.children = []
state.cylcTree = tree
// console.log('@@')
}

Expand Down
13 changes: 5 additions & 8 deletions src/utils/tasks.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { TASK_OUTPUT_NAMES } from '@/model/TaskOutput.model'

/**
* States used when the parent is stopped.
* @type {Array<TaskState>}
* @type {TaskState[]}
*/
const isStoppedOrderedStates = [
TaskState.SUBMIT_FAILED,
Expand All @@ -35,9 +35,9 @@ const isStoppedOrderedStates = [

/**
* Gives a single state, based on a list of states of children nodes.
* @param childStates {Array<TaskState>} children nodes
* @param isStopped {boolean} whether the parent node is stopped or not
* @returns {string} a valid Task State name, or null if not found
* @param {TaskState[]} childStates children nodes
* @param {boolean} isStopped whether the parent node is stopped or not
* @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) {
Expand All @@ -51,10 +51,7 @@ function extractGroupState (childStates, isStopped = false) {
}

function latestJob (taskProxy) {
if (taskProxy && taskProxy.children && taskProxy.children.length > 0) {
return taskProxy.children[0].node
}
return null
return taskProxy?.children?.[0]?.node
}

/** Returns an array of task messages and custom outputs for a job node.
Expand Down
14 changes: 2 additions & 12 deletions src/views/Table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -65,23 +65,13 @@ export default {
},
tasks () {
const ret = []
let latestJob
let previousJob
for (const workflow of this.workflows) {
for (const cycle of workflow.children) {
for (const task of cycle.children) {
latestJob = null
previousJob = null
if (task.children.length) {
latestJob = task.children.slice(-1)[0]
if (task.children.length > 1) {
previousJob = task.children.slice(-2)[0]
}
}
ret.push({
task,
latestJob,
previousJob
latestJob: task.children[0],
previousJob: task.children[1],
})
}
}
Expand Down
14 changes: 3 additions & 11 deletions tests/unit/components/cylc/table/table.vue.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,18 @@

import { mount } from '@vue/test-utils'
import { createVuetify } from 'vuetify'
import sinon from 'sinon'
import { simpleTableTasks } from './table.data'
import TaskState from '@/model/TaskState.model'
import CylcObjectPlugin from '@/components/cylc/cylcObject/plugin'
import Table from '@/components/cylc/table/Table.vue'
import { VDataTable, VDataTableFooter } from 'vuetify/labs/VDataTable'
import WorkflowService from '@/services/workflow.service'

const $eventBus = {
emit () {}
}
const $workflowService = {
register () {},
unregister () {},
subscribe () {},
introspection: Promise.resolve({
mutations: [
{ args: [] }
],
types: []
})
}
const $workflowService = sinon.createStubInstance(WorkflowService)

const vuetify = createVuetify({
components: { VDataTable, VDataTableFooter }
Expand Down
14 changes: 3 additions & 11 deletions tests/unit/components/cylc/tree/tree.vue.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,17 @@
import { nextTick } from 'vue'
import { mount } from '@vue/test-utils'
import { createVuetify } from 'vuetify'
import sinon from 'sinon'
import Tree from '@/components/cylc/tree/Tree.vue'
import { simpleWorkflowTree4Nodes } from './tree.data'
import CylcObjectPlugin from '@/components/cylc/cylcObject/plugin'
import cloneDeep from 'lodash/cloneDeep'
import WorkflowService from '@/services/workflow.service'

const $eventBus = {
emit () {}
}
const $workflowService = {
register () {},
unregister () {},
subscribe () {},
introspection: Promise.resolve({
mutations: [
{ args: [] }
],
types: []
})
}
const $workflowService = sinon.createStubInstance(WorkflowService)
const vuetify = createVuetify()

describe('Tree component', () => {
Expand Down
9 changes: 3 additions & 6 deletions tests/unit/components/cylc/tree/treeitem.vue.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@
import { mount } from '@vue/test-utils'
import { Assertion } from 'chai'
import { createVuetify } from 'vuetify'
import sinon from 'sinon'
import TreeItem from '@/components/cylc/tree/TreeItem.vue'
import {
simpleWorkflowNode,
simpleCyclepointNode,
simpleTaskNode
} from './tree.data'
import CylcObjectPlugin from '@/components/cylc/cylcObject/plugin'
import WorkflowService from '@/services/workflow.service'

/**
* Helper function for expecting TreeItem to be expanded.
Expand All @@ -50,12 +52,7 @@ Assertion.addMethod('expanded', function () {
)
})

const $workflowService = {
introspection: Promise.resolve({
mutations: [],
types: []
})
}
const $workflowService = sinon.createStubInstance(WorkflowService)
const $eventBus = {
emit: () => {}
}
Expand Down
58 changes: 27 additions & 31 deletions tests/unit/utils/tasks.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,37 +56,33 @@ describe('tasks', () => {
expect(extractGroupState([])).to.equal('')
})
})
describe('latestJob', () => {
it('should return the correct value for latestJob', () => {
const tests = [
{
taskProxy: null,
expected: null
},
{
taskProxy: {},
expected: null
},
{
taskProxy: {
children: []
},
expected: null
},
{
taskProxy: {
children: [
{
node: 1
}
]
},
expected: 1
}
]
tests.forEach(test => {
expect(latestJob(test.taskProxy)).to.equal(test.expected)
})
describe.each([
{
taskProxy: null,
expected: undefined
},
{
taskProxy: {},
expected: undefined
},
{
taskProxy: {
children: []
},
expected: undefined
},
{
taskProxy: {
children: [
{ node: 'foo' },
{ node: 'bar' },
]
},
expected: 'foo'
}
])('latestJob($taskProxy)', ({ taskProxy, expected }) => {
it(`returns ${expected}`, () => {
expect(latestJob(taskProxy)).to.equal(expected)
})
})
describe('dtMean', () => {
Expand Down
104 changes: 104 additions & 0 deletions tests/unit/views/table.vue.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/**
* 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/>.
*/

import { mount } from '@vue/test-utils'
import { createStore } from 'vuex'
import sinon from 'sinon'
import storeOptions from '@/store/options'
import Table from '@/views/Table.vue'
import WorkflowService from '@/services/workflow.service'
import User from '@/model/User.model'

chai.config.truncateThreshold = 0

const workflows = [
{
id: '~user/one',
children: [
{
id: '~user/one//1',
children: [
{
id: '~user/one//1/eventually_succeeded',
children: [
{
id: '~user/one//1/eventually_succeeded/3',
children: [],
},
{
id: '~user/one//1/eventually_succeeded/2',
children: [],
},
{
id: '~user/one//1/eventually_succeeded/1',
children: [],
},
],
},
{
id: '~user/one//1/failed',
children: [
{
id: '~user/one//1/failed/1',
children: [],
},
],
},
]
}
]
},
]

describe('Table view', () => {
let store, $workflowService
beforeEach(() => {
store = createStore(storeOptions)
const user = new User('cylc', [], new Date(), true, 'localhost', 'owner')
store.commit('user/SET_USER', user)
$workflowService = sinon.createStubInstance(WorkflowService)
})

it('computes tasks', async () => {
const wrapper = mount(Table, {
shallow: true,
global: {
plugins: [store],
mocks: { $workflowService }
},
props: {
workflowName: 'one',
},
data: () => ({
// Override computed property
workflows
})
})

expect(wrapper.vm.tasks).toMatchObject([
{
task: { id: '~user/one//1/eventually_succeeded' },
latestJob: { id: '~user/one//1/eventually_succeeded/3' },
previousJob: { id: '~user/one//1/eventually_succeeded/2' }
},
{
task: { id: '~user/one//1/failed' },
latestJob: { id: '~user/one//1/failed/1' },
}
])
})
})

0 comments on commit 63bdcc2

Please sign in to comment.