diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-11 03:08:58 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-11 03:08:58 +0300 |
commit | 5427433c6d79f9131f4025cabb7e3208380bce9a (patch) | |
tree | ea0a22450f467f1ef1e3449255017dbe0f178882 /app/assets/javascripts/search | |
parent | 13bcb8221306526671a61df589f7c05505c9934c (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/search')
10 files changed, 250 insertions, 57 deletions
diff --git a/app/assets/javascripts/search/dropdown_filter/components/dropdown_filter.vue b/app/assets/javascripts/search/dropdown_filter/components/dropdown_filter.vue new file mode 100644 index 00000000000..08619fa2066 --- /dev/null +++ b/app/assets/javascripts/search/dropdown_filter/components/dropdown_filter.vue @@ -0,0 +1,108 @@ +<script> +import { mapState } from 'vuex'; +import { GlDropdown, GlDropdownItem, GlDropdownDivider } from '@gitlab/ui'; +import { setUrlParams, visitUrl } from '~/lib/utils/url_utility'; +import { sprintf, s__ } from '~/locale'; + +export default { + name: 'DropdownFilter', + components: { + GlDropdown, + GlDropdownItem, + GlDropdownDivider, + }, + props: { + filterData: { + type: Object, + required: true, + }, + }, + computed: { + ...mapState(['query']), + scope() { + return this.query.scope; + }, + supportedScopes() { + return Object.values(this.filterData.scopes); + }, + initialFilter() { + return this.query[this.filterData.filterParam]; + }, + filter() { + return this.initialFilter || this.filterData.filters.ANY.value; + }, + filtersArray() { + return this.filterData.filterByScope[this.scope]; + }, + selectedFilter: { + get() { + if (this.filtersArray.some(({ value }) => value === this.filter)) { + return this.filter; + } + + return this.filterData.filters.ANY.value; + }, + set(filter) { + // we need to remove the pagination cursor to ensure the + // relevancy of the new results + + visitUrl( + setUrlParams({ + page: null, + [this.filterData.filterParam]: filter, + }), + ); + }, + }, + selectedFilterText() { + const f = this.filtersArray.find(({ value }) => value === this.selectedFilter); + if (!f || f === this.filterData.filters.ANY) { + return sprintf(s__('Any %{header}'), { header: this.filterData.header }); + } + + return f.label; + }, + showDropdown() { + return this.supportedScopes.includes(this.scope); + }, + }, + methods: { + dropDownItemClass(filter) { + return { + 'gl-border-b-solid gl-border-b-gray-100 gl-border-b-1 gl-pb-2! gl-mb-2': + filter === this.filterData.filters.ANY, + }; + }, + isFilterSelected(filter) { + return filter === this.selectedFilter; + }, + handleFilterChange(filter) { + this.selectedFilter = filter; + }, + }, +}; +</script> + +<template> + <gl-dropdown + v-if="showDropdown" + :text="selectedFilterText" + class="col-3 gl-pt-4 gl-pl-0 gl-pr-0 gl-mr-4" + menu-class="gl-w-full! gl-pl-0" + > + <header class="gl-text-center gl-font-weight-bold gl-font-lg"> + {{ filterData.header }} + </header> + <gl-dropdown-divider /> + <gl-dropdown-item + v-for="f in filtersArray" + :key="f.value" + :is-check-item="true" + :is-checked="isFilterSelected(f.value)" + :class="dropDownItemClass(f)" + @click="handleFilterChange(f.value)" + > + {{ f.label }} + </gl-dropdown-item> + </gl-dropdown> +</template> diff --git a/app/assets/javascripts/search/dropdown_filter/constants/confidential_filter_data.js b/app/assets/javascripts/search/dropdown_filter/constants/confidential_filter_data.js new file mode 100644 index 00000000000..b29daca89cb --- /dev/null +++ b/app/assets/javascripts/search/dropdown_filter/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 default { + header, + filters, + scopes, + filterByScope, + filterParam, +}; diff --git a/app/assets/javascripts/search/dropdown_filter/constants/state_filter_data.js b/app/assets/javascripts/search/dropdown_filter/constants/state_filter_data.js new file mode 100644 index 00000000000..0b93aa0be29 --- /dev/null +++ b/app/assets/javascripts/search/dropdown_filter/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 default { + header, + filters, + scopes, + filterByScope, + filterParam, +}; diff --git a/app/assets/javascripts/search/dropdown_filter/index.js b/app/assets/javascripts/search/dropdown_filter/index.js new file mode 100644 index 00000000000..e5e0745d990 --- /dev/null +++ b/app/assets/javascripts/search/dropdown_filter/index.js @@ -0,0 +1,38 @@ +import Vue from 'vue'; +import Translate from '~/vue_shared/translate'; +import DropdownFilter from './components/dropdown_filter.vue'; +import stateFilterData from './constants/state_filter_data'; +import confidentialFilterData from './constants/confidential_filter_data'; + +Vue.use(Translate); + +const mountDropdownFilter = (store, { id, filterData }) => { + const el = document.getElementById(id); + + if (!el) return false; + + return new Vue({ + el, + store, + render(createElement) { + return createElement(DropdownFilter, { + props: { + filterData, + }, + }); + }, + }); +}; + +const dropdownFilters = [ + { + id: 'js-search-filter-by-state', + filterData: stateFilterData, + }, + { + id: 'js-search-filter-by-confidential', + filterData: confidentialFilterData, + }, +]; + +export default store => [...dropdownFilters].map(filter => mountDropdownFilter(store, filter)); diff --git a/app/assets/javascripts/search/index.js b/app/assets/javascripts/search/index.js index 7508b3c9a55..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) }); - initSidebar(store); + if (gon.features.searchFacets) { + initSidebar(store); + } else { + initDropdownFilters(store); + } + initGroupFilter(store); }; diff --git a/app/assets/javascripts/search/sidebar/components/app.vue b/app/assets/javascripts/search/sidebar/components/app.vue deleted file mode 100644 index 0c50f93d381..00000000000 --- a/app/assets/javascripts/search/sidebar/components/app.vue +++ /dev/null @@ -1,41 +0,0 @@ -<script> -import { mapActions, mapState } from 'vuex'; -import { GlButton, GlLink } from '@gitlab/ui'; -import StatusFilter from './status_filter.vue'; -import ConfidentialityFilter from './confidentiality_filter.vue'; - -export default { - name: 'GlobalSearchSidebar', - components: { - GlButton, - GlLink, - StatusFilter, - ConfidentialityFilter, - }, - computed: { - ...mapState(['query']), - showReset() { - return this.query.state || this.query.confidential; - }, - }, - methods: { - ...mapActions(['applyQuery', 'resetQuery']), - }, -}; -</script> - -<template> - <form - class="gl-display-flex gl-flex-direction-column col-md-3 gl-mr-4 gl-mb-6 gl-mb gl-mt-5" - @submit.prevent="applyQuery" - > - <status-filter /> - <confidentiality-filter /> - <div class="gl-display-flex gl-align-items-center gl-mt-3"> - <gl-button variant="success" type="submit">{{ __('Apply') }}</gl-button> - <gl-link v-if="showReset" class="gl-ml-auto" @click="resetQuery">{{ - __('Reset filters') - }}</gl-link> - </div> - </form> -</template> diff --git a/app/assets/javascripts/search/sidebar/components/confidentiality_filter.vue b/app/assets/javascripts/search/sidebar/components/confidentiality_filter.vue index 38dccb9675d..f8938e799aa 100644 --- a/app/assets/javascripts/search/sidebar/components/confidentiality_filter.vue +++ b/app/assets/javascripts/search/sidebar/components/confidentiality_filter.vue @@ -21,6 +21,5 @@ export default { <template> <div v-if="showDropdown"> <radio-filter :filter-data="$options.confidentialFilterData" /> - <hr class="gl-my-5 gl-border-gray-100" /> </div> </template> diff --git a/app/assets/javascripts/search/sidebar/components/status_filter.vue b/app/assets/javascripts/search/sidebar/components/status_filter.vue index 5cec2090906..876123ccc52 100644 --- a/app/assets/javascripts/search/sidebar/components/status_filter.vue +++ b/app/assets/javascripts/search/sidebar/components/status_filter.vue @@ -21,6 +21,5 @@ export default { <template> <div v-if="showDropdown"> <radio-filter :filter-data="$options.stateFilterData" /> - <hr class="gl-my-5 gl-border-gray-100" /> </div> </template> diff --git a/app/assets/javascripts/search/sidebar/index.js b/app/assets/javascripts/search/sidebar/index.js index 6419e8ac2c6..b19016edf3d 100644 --- a/app/assets/javascripts/search/sidebar/index.js +++ b/app/assets/javascripts/search/sidebar/index.js @@ -1,11 +1,12 @@ import Vue from 'vue'; import Translate from '~/vue_shared/translate'; -import GlobalSearchSidebar from './components/app.vue'; +import StatusFilter from './components/status_filter.vue'; +import ConfidentialityFilter from './components/confidentiality_filter.vue'; Vue.use(Translate); -export const initSidebar = store => { - const el = document.getElementById('js-search-sidebar'); +const mountRadioFilters = (store, { id, component }) => { + const el = document.getElementById(id); if (!el) return false; @@ -13,7 +14,21 @@ export const initSidebar = store => { el, store, render(createElement) { - return createElement(GlobalSearchSidebar); + 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 447278aa223..722ed2eec26 100644 --- a/app/assets/javascripts/search/store/actions.js +++ b/app/assets/javascripts/search/store/actions.js @@ -1,7 +1,6 @@ import Api from '~/api'; import createFlash from '~/flash'; import { __ } from '~/locale'; -import { visitUrl, setUrlParams } from '~/lib/utils/url_utility'; import * as types from './mutation_types'; export const fetchGroups = ({ commit }, search) => { @@ -19,11 +18,3 @@ export const fetchGroups = ({ commit }, search) => { export const setQuery = ({ commit }, { key, value }) => { commit(types.SET_QUERY, { key, value }); }; - -export const applyQuery = ({ state }) => { - visitUrl(setUrlParams({ ...state.query, page: null })); -}; - -export const resetQuery = ({ state }) => { - visitUrl(setUrlParams({ ...state.query, page: null, state: null, confidential: null })); -}; |