Skip to content

Commit 21b773b

Browse files
authored
Merge pull request #1182 from MetRonnie/filtering
Allow filtering by ID instead of only task name
2 parents 1a4823b + 68e0a62 commit 21b773b

File tree

10 files changed

+120
-83
lines changed

10 files changed

+120
-83
lines changed

CHANGES.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,23 @@ creating a new release entry be sure to copy & paste the span tag with the
1010
`actions:bind` attribute, which is used by a regex to find the text to be
1111
updated. Only the first match gets replaced, so it's fine to leave the old
1212
ones in. -->
13-
14-
## __cylc-ui-1.5.0 (<span actions:bind='release-date'>Released 2023-01-16</span>)__
13+
-------------------------------------------------------------------------------
14+
## __cylc-ui-1.5.0 (<span actions:bind='release-date'>Upcoming</span>)__
1515

1616
### Enhancements
1717

1818
[#1184](https://github.com/cylc/cylc-ui/pull/1184) - Mean times for tasks
1919
in table changed to human readable ISO duration format.
2020

21+
[#1182](https://github.com/cylc/cylc-ui/pull/1182) - Allow filtering by
22+
cycle point and family in tree & table views.
23+
24+
### Fixes
25+
26+
[#1182](https://github.com/cylc/cylc-ui/pull/1182) - Fixes bug in filtering
27+
by task name.
28+
29+
-------------------------------------------------------------------------------
2130
## __cylc-ui-1.4.0 (<span actions:bind='release-date'>Released 2023-01-16</span>)__
2231

2332
### Enhancements

src/components/cylc/TaskFilter.vue

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
2525
class="pr-md-2 mb-2 mb-md-0"
2626
>
2727
<v-text-field
28-
data-cy="filter-task-name"
28+
data-cy="filter-id"
2929
clearable
30+
:clear-icon="$options.icons.mdiClose"
3031
dense
3132
flat
3233
hide-details
3334
outlined
34-
placeholder="Filter by task name"
35-
v-model="localValue.name"
36-
ref="filterNameInput"
37-
></v-text-field>
35+
placeholder="Filter by ID"
36+
v-model="localValue.id"
37+
ref="filterIDInput"
38+
/>
3839
</v-col>
3940
<v-col
4041
cols="12"
@@ -45,6 +46,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
4546
data-cy="filter-task-states"
4647
:items="allStates"
4748
clearable
49+
:clear-icon="$options.icons.mdiClose"
4850
dense
4951
flat
5052
hide-details
@@ -76,14 +78,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
7678
<script>
7779
import Task from '@/components/cylc/Task'
7880
import { TaskStateUserOrder } from '@/model/TaskState.model'
81+
import { mdiClose } from '@mdi/js'
7982
8083
export default {
8184
name: 'TaskFilter',
8285
components: {
8386
Task
8487
},
8588
props: {
86-
value: Object // { name, states }
89+
value: Object // { id, states }
8790
},
8891
data () {
8992
return {
@@ -101,6 +104,10 @@ export default {
101104
this.$emit('input', value)
102105
}
103106
}
107+
},
108+
// Misc options
109+
icons: {
110+
mdiClose
104111
}
105112
}
106113
</script>

src/components/cylc/common/filter.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,21 @@
1818
/* Logic for filtering tasks. */
1919

2020
/**
21-
* Return true if a node has matches the specified name/state filter.
21+
* Return true if a node matches the specified id/state filter.
2222
*
2323
* @export
24-
* @param {{ name: string, state: string }} node
25-
* @param {?string} name
24+
* @param {Object} node
25+
* @param {?string} id
2626
* @param {?string[]} states
2727
* @return {boolean}
2828
*/
29-
export function matchNode (node, name, states) {
29+
export function matchNode (node, id, states) {
3030
let ret = true
31-
if (name?.trim()) {
32-
ret &&= node.name.includes(name)
31+
if (id?.trim()) {
32+
ret &&= node.tokens.relative_id.includes(id)
3333
}
3434
if (states?.length) {
35-
ret &&= states.includes(node.state)
35+
ret &&= states.includes(node.node.state)
3636
}
3737
return ret
3838
}

src/components/cylc/gscan/GScan.vue

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
2828
<v-text-field
2929
v-model="searchWorkflows"
3030
clearable
31+
:clear-icon="$options.icons.mdiClose"
3132
flat
3233
dense
3334
hide-details
@@ -52,7 +53,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
5253
id="c-gscan-filter-tooltip-btn"
5354
@click="showFilterTooltip = !showFilterTooltip"
5455
>
55-
<v-icon>{{ svgPaths.filter }}</v-icon>
56+
<v-icon>{{ $options.icons.mdiFilter }}</v-icon>
5657
</v-btn>
5758
</template>
5859
<!-- filters tooltip -->
@@ -200,7 +201,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
200201
</template>
201202

202203
<script>
203-
import { mdiFilter } from '@mdi/js'
204+
import { mdiClose, mdiFilter } from '@mdi/js'
204205
import uniq from 'lodash/uniq'
205206
import TaskState from '@/model/TaskState.model'
206207
import { WorkflowState } from '@/model/WorkflowState.model'
@@ -233,9 +234,6 @@ export default {
233234
data () {
234235
return {
235236
maximumTasksDisplayed: 5,
236-
svgPaths: {
237-
filter: mdiFilter
238-
},
239237
/**
240238
* The filtered workflows. This is the result of applying the filters
241239
* on the workflows prop.
@@ -470,6 +468,12 @@ export default {
470468
return validValues.includes(entry[0])
471469
})
472470
}
471+
},
472+
473+
// Misc options
474+
icons: {
475+
mdiClose,
476+
mdiFilter
473477
}
474478
}
475479
</script>

src/components/cylc/table/Table.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ export default {
254254
},
255255
computed: {
256256
filteredTasks () {
257-
return this.tasks.filter(({ task }) => matchNode(task.node, this.tasksFilter.name, this.tasksFilter.states))
257+
return this.tasks.filter(({ task }) => matchNode(task, this.tasksFilter.id, this.tasksFilter.states))
258258
}
259259
},
260260
methods: {

src/components/cylc/tree/Tree.vue

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ export default {
202202
}
203203
},
204204
filterByTaskName () {
205-
return Boolean(this.tasksFilter.name?.trim())
205+
return Boolean(this.tasksFilter.id?.trim())
206206
},
207207
filterByTaskState () {
208208
return Boolean(this.tasksFilter.states?.length)
@@ -237,20 +237,31 @@ export default {
237237
this.filterNode(node)
238238
}
239239
},
240-
filterNode (node) {
241-
let filtered = false
240+
/**
241+
* Update tree cache entry for this node (and its children if applicable)
242+
* with whether the node matches the filters.
243+
*
244+
* @param {Object} node
245+
* @param {boolean} parentFiltered - whether the parent of this node
246+
* matches the filter.
247+
* @return {boolean} - whether this node matches the filter.
248+
*/
249+
filterNode (node, parentFiltered = false) {
250+
const isMatch = (
251+
matchNode(node, this.tasksFilter.id, this.tasksFilter.states) ||
252+
parentFiltered
253+
)
254+
let filtered = isMatch
242255
if (node.type === 'cycle') {
243256
// follow the family tree from cycle point nodes
244257
for (const child of node.familyTree[0]?.children || []) {
245-
filtered = this.filterNode(child) || filtered
258+
filtered = this.filterNode(child, isMatch) || filtered
246259
}
247260
} else if (['workflow', 'family'].includes(node.type)) {
248261
// follow children for workflow or family nodes
249262
for (const child of node.children) {
250-
filtered = this.filterNode(child) || filtered
263+
filtered = this.filterNode(child, isMatch) || filtered
251264
}
252-
} else if (node.type === 'task') {
253-
filtered = matchNode(node.node, this.tasksFilter.name, this.tasksFilter.states)
254265
}
255266
if (this.treeItemCache[node.id]) {
256267
this.treeItemCache[node.id].filtered = filtered

tests/e2e/specs/table.cy.js

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ describe('Table view', () => {
3333
.should('have.length', 7)
3434
.should('be.visible')
3535
cy
36-
.get('[data-cy=filter-task-name]')
36+
.get('[data-cy=filter-id]')
3737
.should('be.empty')
3838
cy
3939
.get('[data-cy=filter-task-states]')
@@ -42,7 +42,7 @@ describe('Table view', () => {
4242
.find('input[type="hidden"]')
4343
.should('have.value', '')
4444
})
45-
it('Should filter by task name', () => {
45+
it('Should filter by ID', () => {
4646
cy.visit('/#/table/one')
4747
cy
4848
.get('.c-table table > tbody > tr')
@@ -52,18 +52,17 @@ describe('Table view', () => {
5252
.get('td > div.d-flex > div')
5353
.contains('sleepy')
5454
.should('be.visible')
55-
// eep should filter sleepy
56-
cy
57-
.get('[data-cy=filter-task-name]')
58-
.type('eep')
59-
cy
60-
.get('td > div.d-flex > div')
61-
.contains('sleepy')
62-
.should('be.visible')
63-
cy
64-
.get('.c-table table > tbody > tr')
65-
.should('have.length', 1)
66-
.should('be.visible')
55+
for (const id of ['eep', '/sle']) {
56+
cy.get('[data-cy=filter-id]')
57+
.clear()
58+
.type(id)
59+
cy.get('td > div.d-flex > div')
60+
.contains('sleepy')
61+
.should('be.visible')
62+
cy.get('.c-table table > tbody > tr')
63+
.should('have.length', 1)
64+
.should('be.visible')
65+
}
6766
})
6867
it('Should filter by task state', () => {
6968
cy.visit('/#/table/one')
@@ -91,7 +90,7 @@ describe('Table view', () => {
9190
.should('have.length', 1)
9291
.should('be.visible')
9392
})
94-
it('Should filter by task name and states', () => {
93+
it('Should filter by ID and states', () => {
9594
cy.visit('/#/table/one')
9695
cy
9796
.get('.c-table table > tbody > tr')
@@ -109,7 +108,7 @@ describe('Table view', () => {
109108
.should('have.length', 2)
110109
.should('be.visible')
111110
cy
112-
.get('[data-cy=filter-task-name]')
111+
.get('[data-cy=filter-id]')
113112
.type('eventually')
114113
cy
115114
.get('td > div.d-flex > div')

tests/e2e/specs/tree.cy.js

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -185,30 +185,33 @@ describe('Tree view', () => {
185185

186186
describe('filters', () => {
187187
const initialNumTasks = 7
188-
it('Should filter by task name', () => {
188+
it('Should filter by ID', () => {
189189
cy.visit('/#/tree/one')
190190
// Should not filter by default
191-
cy
192-
.get('.node-data-task:visible')
191+
cy.get('.node-data-task:visible')
193192
.should('have.length', initialNumTasks)
194193
.contains('waiting')
195-
// eep should filter sleepy
196-
cy
197-
.get('[data-cy=filter-task-name]')
198-
.type('eep')
199-
cy
200-
.get('.node-data-task:visible')
201-
.should('have.length.lessThan', initialNumTasks)
202-
.contains('sleepy')
203-
cy
204-
.get('.node-data-task')
205-
.contains('waiting')
206-
.should('not.be.visible')
194+
for (const id of ['eed', '/suc', 'GOOD', 'SUC']) {
195+
cy.get('[data-cy=filter-id]')
196+
.clear()
197+
.type(id)
198+
cy.get('.node-data-task:visible')
199+
.should('have.length.lessThan', initialNumTasks)
200+
.contains('succeeded')
201+
cy.get('.node-data-task')
202+
.contains('waiting')
203+
.should('not.be.visible')
204+
}
207205
// It should stop filtering when input is cleared
208-
cy.get('[data-cy=filter-task-name]')
206+
cy.get('[data-cy=filter-id]')
209207
.clear()
210208
.get('.node-data-task:visible')
211209
.should('have.length', initialNumTasks)
210+
// It should filter by cycle point
211+
cy.get('[data-cy=filter-id]')
212+
.type('2000') // (matches all tasks)
213+
.get('.node-data-task:visible')
214+
.should('have.length', initialNumTasks)
212215
})
213216
it('Should filter by task states', () => {
214217
cy.visit('/#/tree/one')
@@ -231,14 +234,14 @@ describe('Tree view', () => {
231234
.get('.node-data-task:visible')
232235
.should('have.length', 1)
233236
})
234-
it('Should filter by task name and states', () => {
237+
it('Should filter by ID and states', () => {
235238
cy.visit('/#/tree/one')
236239
cy
237240
.get('.node-data-task')
238241
.contains('failed')
239242
.should('be.visible')
240243
cy
241-
.get('[data-cy=filter-task-name]')
244+
.get('[data-cy=filter-id]')
242245
.type('i')
243246
cy
244247
.get('[data-cy=filter-task-states]')
@@ -275,7 +278,7 @@ describe('Tree view', () => {
275278
.contains('sleepy')
276279
.as('sleepyTask')
277280
.should('be.visible')
278-
cy.get('[data-cy=filter-task-name]')
281+
cy.get('[data-cy=filter-id]')
279282
.type('sleep')
280283
cy.get('[data-cy=collapse-all]')
281284
.click()

0 commit comments

Comments
 (0)