diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-06 09:08:51 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-06 09:08:51 +0300 |
commit | eefbee4451565989727256d36176dc2950e3a0b7 (patch) | |
tree | 29d630cac89ec88ab5c2a22f9b2ca40b4e0fd613 /app/assets/javascripts/search | |
parent | 74d35955aa0e12ff6ed99b39adb38e0f13fb96aa (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/search')
10 files changed, 246 insertions, 1 deletions
diff --git a/app/assets/javascripts/search/index.js b/app/assets/javascripts/search/index.js index 7d175bace4f..275d6351adc 100644 --- a/app/assets/javascripts/search/index.js +++ b/app/assets/javascripts/search/index.js @@ -1,11 +1,17 @@ import { queryToObject } from '~/lib/utils/url_utility'; import createStore from './store'; import initDropdownFilters from './dropdown_filter'; +import { initSidebar } from './sidebar'; import initGroupFilter from './group_filter'; export default () => { const store = createStore({ query: queryToObject(window.location.search) }); - initDropdownFilters(store); + if (gon.features.searchFacets) { + initSidebar(store); + } else { + initDropdownFilters(store); + } + initGroupFilter(store); }; diff --git a/app/assets/javascripts/search/sidebar/components/confidentiality_filter.vue b/app/assets/javascripts/search/sidebar/components/confidentiality_filter.vue new file mode 100644 index 00000000000..f8938e799aa --- /dev/null +++ b/app/assets/javascripts/search/sidebar/components/confidentiality_filter.vue @@ -0,0 +1,25 @@ +<script> +import { mapState } from 'vuex'; +import { confidentialFilterData } from '../constants/confidential_filter_data'; +import RadioFilter from './radio_filter.vue'; + +export default { + name: 'ConfidentialityFilter', + components: { + RadioFilter, + }, + computed: { + ...mapState(['query']), + showDropdown() { + return Object.values(confidentialFilterData.scopes).includes(this.query.scope); + }, + }, + confidentialFilterData, +}; +</script> + +<template> + <div v-if="showDropdown"> + <radio-filter :filter-data="$options.confidentialFilterData" /> + </div> +</template> diff --git a/app/assets/javascripts/search/sidebar/components/radio_filter.vue b/app/assets/javascripts/search/sidebar/components/radio_filter.vue new file mode 100644 index 00000000000..b27c4e26fb5 --- /dev/null +++ b/app/assets/javascripts/search/sidebar/components/radio_filter.vue @@ -0,0 +1,68 @@ +<script> +import { mapState, mapActions } from 'vuex'; +import { GlFormRadioGroup, GlFormRadio } from '@gitlab/ui'; +import { sprintf, s__ } from '~/locale'; + +export default { + name: 'RadioFilter', + components: { + GlFormRadioGroup, + GlFormRadio, + }, + props: { + filterData: { + type: Object, + required: true, + }, + }, + computed: { + ...mapState(['query']), + ANY() { + return this.filterData.filters.ANY; + }, + scope() { + return this.query.scope; + }, + initialFilter() { + return this.query[this.filterData.filterParam]; + }, + filter() { + return this.initialFilter || this.ANY.value; + }, + filtersArray() { + return this.filterData.filterByScope[this.scope]; + }, + selectedFilter: { + get() { + if (this.filtersArray.some(({ value }) => value === this.filter)) { + return this.filter; + } + + return this.ANY.value; + }, + set(value) { + this.setQuery({ key: this.filterData.filterParam, value }); + }, + }, + }, + methods: { + ...mapActions(['setQuery']), + radioLabel(filter) { + return filter.value === this.ANY.value + ? sprintf(s__('Any %{header}'), { header: this.filterData.header.toLowerCase() }) + : filter.label; + }, + }, +}; +</script> + +<template> + <div> + <h5 class="gl-mt-0">{{ filterData.header }}</h5> + <gl-form-radio-group v-model="selectedFilter"> + <gl-form-radio v-for="f in filtersArray" :key="f.value" :value="f.value"> + {{ radioLabel(f) }} + </gl-form-radio> + </gl-form-radio-group> + </div> +</template> diff --git a/app/assets/javascripts/search/sidebar/components/status_filter.vue b/app/assets/javascripts/search/sidebar/components/status_filter.vue new file mode 100644 index 00000000000..876123ccc52 --- /dev/null +++ b/app/assets/javascripts/search/sidebar/components/status_filter.vue @@ -0,0 +1,25 @@ +<script> +import { mapState } from 'vuex'; +import { stateFilterData } from '../constants/state_filter_data'; +import RadioFilter from './radio_filter.vue'; + +export default { + name: 'StatusFilter', + components: { + RadioFilter, + }, + computed: { + ...mapState(['query']), + showDropdown() { + return Object.values(stateFilterData.scopes).includes(this.query.scope); + }, + }, + stateFilterData, +}; +</script> + +<template> + <div v-if="showDropdown"> + <radio-filter :filter-data="$options.stateFilterData" /> + </div> +</template> diff --git a/app/assets/javascripts/search/sidebar/constants/confidential_filter_data.js b/app/assets/javascripts/search/sidebar/constants/confidential_filter_data.js new file mode 100644 index 00000000000..ecb63ed9eea --- /dev/null +++ b/app/assets/javascripts/search/sidebar/constants/confidential_filter_data.js @@ -0,0 +1,36 @@ +import { __ } from '~/locale'; + +const header = __('Confidentiality'); + +const filters = { + ANY: { + label: __('Any'), + value: null, + }, + CONFIDENTIAL: { + label: __('Confidential'), + value: 'yes', + }, + NOT_CONFIDENTIAL: { + label: __('Not confidential'), + value: 'no', + }, +}; + +const scopes = { + ISSUES: 'issues', +}; + +const filterByScope = { + [scopes.ISSUES]: [filters.ANY, filters.CONFIDENTIAL, filters.NOT_CONFIDENTIAL], +}; + +const filterParam = 'confidential'; + +export const confidentialFilterData = { + header, + filters, + scopes, + filterByScope, + filterParam, +}; diff --git a/app/assets/javascripts/search/sidebar/constants/state_filter_data.js b/app/assets/javascripts/search/sidebar/constants/state_filter_data.js new file mode 100644 index 00000000000..7c9a029ffe4 --- /dev/null +++ b/app/assets/javascripts/search/sidebar/constants/state_filter_data.js @@ -0,0 +1,42 @@ +import { __ } from '~/locale'; + +const header = __('Status'); + +const filters = { + ANY: { + label: __('Any'), + value: 'all', + }, + OPEN: { + label: __('Open'), + value: 'opened', + }, + CLOSED: { + label: __('Closed'), + value: 'closed', + }, + MERGED: { + label: __('Merged'), + value: 'merged', + }, +}; + +const scopes = { + ISSUES: 'issues', + MERGE_REQUESTS: 'merge_requests', +}; + +const filterByScope = { + [scopes.ISSUES]: [filters.ANY, filters.OPEN, filters.CLOSED], + [scopes.MERGE_REQUESTS]: [filters.ANY, filters.OPEN, filters.MERGED, filters.CLOSED], +}; + +const filterParam = 'state'; + +export const stateFilterData = { + header, + filters, + scopes, + filterByScope, + filterParam, +}; diff --git a/app/assets/javascripts/search/sidebar/index.js b/app/assets/javascripts/search/sidebar/index.js new file mode 100644 index 00000000000..b19016edf3d --- /dev/null +++ b/app/assets/javascripts/search/sidebar/index.js @@ -0,0 +1,34 @@ +import Vue from 'vue'; +import Translate from '~/vue_shared/translate'; +import StatusFilter from './components/status_filter.vue'; +import ConfidentialityFilter from './components/confidentiality_filter.vue'; + +Vue.use(Translate); + +const mountRadioFilters = (store, { id, component }) => { + const el = document.getElementById(id); + + if (!el) return false; + + return new Vue({ + el, + store, + render(createElement) { + return createElement(component); + }, + }); +}; + +const radioFilters = [ + { + id: 'js-search-filter-by-state', + component: StatusFilter, + }, + { + id: 'js-search-filter-by-confidential', + component: ConfidentialityFilter, + }, +]; + +export const initSidebar = store => + [...radioFilters].map(filter => mountRadioFilters(store, filter)); diff --git a/app/assets/javascripts/search/store/actions.js b/app/assets/javascripts/search/store/actions.js index 4bc8b2a9a5d..722ed2eec26 100644 --- a/app/assets/javascripts/search/store/actions.js +++ b/app/assets/javascripts/search/store/actions.js @@ -14,3 +14,7 @@ export const fetchGroups = ({ commit }, search) => { commit(types.RECEIVE_GROUPS_ERROR); }); }; + +export const setQuery = ({ commit }, { key, value }) => { + commit(types.SET_QUERY, { key, value }); +}; diff --git a/app/assets/javascripts/search/store/mutation_types.js b/app/assets/javascripts/search/store/mutation_types.js index 8469f3517c0..2482621d4d7 100644 --- a/app/assets/javascripts/search/store/mutation_types.js +++ b/app/assets/javascripts/search/store/mutation_types.js @@ -1,3 +1,5 @@ export const REQUEST_GROUPS = 'REQUEST_GROUPS'; export const RECEIVE_GROUPS_SUCCESS = 'RECEIVE_GROUPS_SUCCESS'; export const RECEIVE_GROUPS_ERROR = 'RECEIVE_GROUPS_ERROR'; + +export const SET_QUERY = 'SET_QUERY'; diff --git a/app/assets/javascripts/search/store/mutations.js b/app/assets/javascripts/search/store/mutations.js index 34fe14716f9..e57850b870e 100644 --- a/app/assets/javascripts/search/store/mutations.js +++ b/app/assets/javascripts/search/store/mutations.js @@ -12,4 +12,7 @@ export default { state.fetchingGroups = false; state.groups = []; }, + [types.SET_QUERY](state, { key, value }) { + state.query[key] = value; + }, }; |