1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
<script>
import { mapActions, mapState } from 'vuex';
import { __ } from '~/locale';
import {
OPERATOR_IS_ONLY,
DEFAULT_NONE_ANY,
} from '~/vue_shared/components/filtered_search_bar/constants';
import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
import {
prepareTokens,
processFilters,
filterToQueryObject,
} from '~/vue_shared/components/filtered_search_bar/filtered_search_utils';
import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue';
import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label_token.vue';
import MilestoneToken from '~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue';
import UrlSync from '~/vue_shared/components/url_sync.vue';
export default {
name: 'FilterBar',
components: {
FilteredSearchBar,
UrlSync,
},
props: {
groupPath: {
type: String,
required: true,
},
},
computed: {
...mapState('filters', {
selectedMilestone: (state) => state.milestones.selected,
selectedAuthor: (state) => state.authors.selected,
selectedLabelList: (state) => state.labels.selectedList,
selectedAssigneeList: (state) => state.assignees.selectedList,
milestonesData: (state) => state.milestones.data,
labelsData: (state) => state.labels.data,
authorsData: (state) => state.authors.data,
assigneesData: (state) => state.assignees.data,
}),
tokens() {
return [
{
icon: 'clock',
title: __('Milestone'),
type: 'milestone',
token: MilestoneToken,
initialMilestones: this.milestonesData,
unique: true,
symbol: '%',
operators: OPERATOR_IS_ONLY,
fetchMilestones: this.fetchMilestones,
},
{
icon: 'labels',
title: __('Label'),
type: 'labels',
token: LabelToken,
defaultLabels: DEFAULT_NONE_ANY,
initialLabels: this.labelsData,
unique: false,
symbol: '~',
operators: OPERATOR_IS_ONLY,
fetchLabels: this.fetchLabels,
},
{
icon: 'pencil',
title: __('Author'),
type: 'author',
token: AuthorToken,
initialAuthors: this.authorsData,
unique: true,
operators: OPERATOR_IS_ONLY,
fetchAuthors: this.fetchAuthors,
},
{
icon: 'user',
title: __('Assignees'),
type: 'assignees',
token: AuthorToken,
defaultAuthors: [],
initialAuthors: this.assigneesData,
unique: false,
operators: OPERATOR_IS_ONLY,
fetchAuthors: this.fetchAssignees,
},
];
},
query() {
return filterToQueryObject({
milestone_title: this.selectedMilestone,
author_username: this.selectedAuthor,
label_name: this.selectedLabelList,
assignee_username: this.selectedAssigneeList,
});
},
},
methods: {
...mapActions('filters', [
'setFilters',
'fetchMilestones',
'fetchLabels',
'fetchAuthors',
'fetchAssignees',
]),
initialFilterValue() {
return prepareTokens({
milestone: this.selectedMilestone,
author: this.selectedAuthor,
assignees: this.selectedAssigneeList,
labels: this.selectedLabelList,
});
},
handleFilter(filters) {
const { labels, milestone, author, assignees } = processFilters(filters);
this.setFilters({
selectedAuthor: author ? author[0] : null,
selectedMilestone: milestone ? milestone[0] : null,
selectedAssigneeList: assignees || [],
selectedLabelList: labels || [],
});
},
},
};
</script>
<template>
<div>
<filtered-search-bar
class="gl-flex-grow-1"
:namespace="groupPath"
recent-searches-storage-key="value-stream-analytics"
:search-input-placeholder="__('Filter results')"
:tokens="tokens"
:initial-filter-value="initialFilterValue()"
@onFilter="handleFilter"
/>
<url-sync :query="query" />
</div>
</template>
|