@@ -38,64 +38,55 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
38
38
id =" c-gscan-search-workflows"
39
39
/>
40
40
<v-menu
41
- v-model =" showFilterTooltip "
41
+ v-model =" showFilterMenu "
42
42
:close-on-content-click =" false"
43
43
offset-x
44
44
>
45
- <!-- button to activate the filters tooltip -->
45
+ <!-- button to activate the filters menu -->
46
46
<template v-slot :activator =" { on , attrs } " >
47
- <v-btn
48
- v-bind =" attrs"
49
- v-on =" on"
50
- link
51
- icon
52
- class =" flex-grow-0 flex-column"
53
- id =" c-gscan-filter-tooltip-btn"
54
- @click =" showFilterTooltip = !showFilterTooltip"
47
+ <v-badge
48
+ :content =" numFilters"
49
+ :value =" numFilters"
50
+ overlap
55
51
>
56
- <v-icon >{{ $options.icons.mdiFilter }}</v-icon >
57
- </v-btn >
52
+ <v-btn
53
+ v-bind =" attrs"
54
+ v-on =" on"
55
+ link
56
+ icon
57
+ id =" c-gscan-filter-menu-btn"
58
+ @click =" showFilterMenu = !showFilterMenu"
59
+ >
60
+ <v-icon >{{ $options.icons.mdiFilter }}</v-icon >
61
+ </v-btn >
62
+ </v-badge >
58
63
</template >
59
- <!-- filters tooltip -->
60
- <v-card
61
- max-height =" 250px"
62
- >
63
- <v-list
64
- dense
65
- >
64
+ <!-- filters menu -->
65
+ <v-card width =" 500px" >
66
+ <v-list dense >
66
67
<div
67
- v-for =" filter in filters"
68
- :key =" filter. title"
68
+ v-for =" (items, title) in filters"
69
+ :key =" title"
69
70
>
70
- <v-list-item dense >
71
+ <v-list-item >
71
72
<v-list-item-content ma-0 >
72
- <v-list-item-title >
73
- <v-checkbox
74
- :label =" filter.title"
75
- :input-value =" allItemsSelected(filter.items)"
76
- value
77
- dense
78
- hide-details
79
- hint =" Toggle all"
80
- @click =" toggleItemsValues(filter.items)"
81
- ></v-checkbox >
82
- </v-list-item-title >
83
- </v-list-item-content >
84
- </v-list-item >
85
- <v-divider />
86
- <v-list-item
87
- v-for =" item in filter.items"
88
- :key =" `${filter.title}-${item.text}`"
89
- dense
90
- >
91
- <v-list-item-action >
92
- <v-checkbox
93
- :label =" item.text"
94
- v-model =" item.model"
73
+ <span class =" mb-2" >Filter by {{ title }}</span >
74
+ <v-autocomplete
75
+ v-model =" filters[title]"
76
+ :items =" $options.allStates[title]"
77
+ outlined
78
+ chips
79
+ deletable-chips
80
+ small-chips
81
+ clearable
82
+ multiple
95
83
dense
96
- height =" 20"
97
- ></v-checkbox >
98
- </v-list-item-action >
84
+ hide-details
85
+ :menu-props =" { closeOnClick: true }"
86
+ :clear-icon =" $options.icons.mdiClose"
87
+ :data-cy =" `filter ${title}`"
88
+ />
89
+ </v-list-item-content >
99
90
</v-list-item >
100
91
</div >
101
92
</v-list >
@@ -202,8 +193,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
202
193
203
194
<script >
204
195
import { mdiClose , mdiFilter } from ' @mdi/js'
205
- import uniq from ' lodash/uniq'
206
- import TaskState from ' @/model/TaskState.model'
196
+ import TaskState , { TaskStateUserOrder } from ' @/model/TaskState.model'
207
197
import { WorkflowState } from ' @/model/WorkflowState.model'
208
198
import Job from ' @/components/cylc/Job'
209
199
import Tree from ' @/components/cylc/tree/Tree'
@@ -246,68 +236,20 @@ export default {
246
236
*/
247
237
searchWorkflows: ' ' ,
248
238
/**
249
- * Variable to control whether the filters tooltip (a menu actually)
250
- * is displayed or not (i.e. v-model=this).
239
+ * Whether the filters menu is displayed (i.e. v-model=this).
251
240
* @type {boolean}
252
241
*/
253
- showFilterTooltip : false ,
242
+ showFilterMenu : false ,
254
243
/**
255
- * List of filters to be displayed by the template, so that the user
256
- * can filter the list of workflows.
257
- *
258
- * Each entry contains a title and a list of items. Each item contains
259
- * the text attribute, which is used as display value in the template.
260
- * The value attribute, which may be used if necessary, as it contains
261
- * the original value (e.g. an Enum, while title would be some formatted
262
- * string). Finally, the model is bound via v-model, and keeps the
263
- * value selected in the UI (i.e. if the user checks the "running"
264
- * checkbox, the model here will be true, if the user unchecks it,
265
- * then it will be false).
266
- *
267
- * @type {[
268
- * {
269
- * title: string,
270
- * items: [{
271
- * text: string,
272
- * value: object,
273
- * model: boolean
274
- * }]
275
- * }
276
- * ]}
244
+ * List of filters selected by the user.
245
+ * @type {{string: string[]}}
277
246
*/
278
- filters: [
279
- {
280
- title: ' workflow state' ,
281
- items: WorkflowState .enumValues
282
- .map (state => {
283
- return {
284
- text: state .name ,
285
- value: state,
286
- model: true
287
- }
288
- })
289
- },
290
- {
291
- title: ' task state' ,
292
- items: TaskState .enumValues .map (state => {
293
- return {
294
- text: state .name ,
295
- value: state,
296
- model: false
297
- }
298
- }).sort ((left , right ) => {
299
- return left .text .localeCompare (right .text )
300
- })
301
- }
302
- // {
303
- // title: 'workflow host',
304
- // items: [] // TODO: will it be in state totals?
305
- // },
306
- // {
307
- // title: 'cylc version',
308
- // items: [] // TODO: will it be in state totals?
309
- // }
310
- ]
247
+ filters: {
248
+ ' workflow state' : [],
249
+ ' task state' : []
250
+ // 'workflow host': [], // TODO: will it be in state totals?
251
+ // 'cylc version': [] // TODO: will it be in state totals?
252
+ }
311
253
}
312
254
},
313
255
computed: {
@@ -318,23 +260,8 @@ export default {
318
260
}
319
261
return sortedWorkflowTree (this .workflowTree )
320
262
},
321
- /**
322
- * @return {Array<String>}
323
- */
324
- workflowStates () {
325
- return this .filters [0 ]
326
- .items
327
- .filter (item => item .model )
328
- .map (item => item .value .name )
329
- },
330
- /**
331
- * @return {Array<String>}
332
- */
333
- taskStates () {
334
- return uniq (this .filters [1 ]
335
- .items
336
- .filter (item => item .model )
337
- .map (item => item .value .name ))
263
+ numFilters () {
264
+ return Object .values (this .filters ).flat ().length
338
265
}
339
266
},
340
267
watch: {
@@ -345,25 +272,19 @@ export default {
345
272
filters: {
346
273
deep: true ,
347
274
immediate: false ,
348
- handler : function (newVal ) {
349
- this .filteredWorkflows = this .filterHierarchically (this .workflows , this .searchWorkflows , this .workflowStates , this .taskStates )
350
- }
275
+ handler: ' filterWorkflows'
351
276
},
352
277
/**
353
278
* If the user changes the workflow name to search/filter,
354
279
* then we apply the filters to the list of workflows.
355
280
*/
356
281
searchWorkflows: {
357
282
immediate: false ,
358
- handler : function (newVal ) {
359
- this .filteredWorkflows = this .filterHierarchically (this .workflows , newVal, this .workflowStates , this .taskStates )
360
- }
283
+ handler: ' filterWorkflows'
361
284
},
362
285
workflows: {
363
286
immediate: true ,
364
- handler : function () {
365
- this .filteredWorkflows = this .filterHierarchically (this .workflows , this .searchWorkflows , this .workflowStates , this .taskStates )
366
- }
287
+ handler: ' filterWorkflows'
367
288
},
368
289
filteredWorkflows: {
369
290
immediate: true ,
@@ -394,7 +315,14 @@ export default {
394
315
}
395
316
},
396
317
methods: {
397
- filterHierarchically,
318
+ filterWorkflows () {
319
+ this .filteredWorkflows = filterHierarchically (
320
+ this .workflows ,
321
+ this .searchWorkflows ,
322
+ this .filters [' workflow state' ],
323
+ this .filters [' task state' ]
324
+ )
325
+ },
398
326
399
327
/**
400
328
* Return `true` iff all the items have been selected. `false` otherwise.
@@ -474,6 +402,14 @@ export default {
474
402
icons: {
475
403
mdiClose,
476
404
mdiFilter
405
+ },
406
+ /**
407
+ * Lists of all the possible workflow and task states
408
+ * @type {{string: string[]}}
409
+ */
410
+ allStates: {
411
+ ' workflow state' : WorkflowState .enumValues .map (x => x .name ),
412
+ ' task state' : TaskStateUserOrder .map (x => x .name )
477
413
}
478
414
}
479
415
< / script>
0 commit comments