diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-10-21 07:08:36 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-10-21 07:08:36 +0000 |
commit | 48aff82709769b098321c738f3444b9bdaa694c6 (patch) | |
tree | e00c7c43e2d9b603a5a6af576b1685e400410dee /app/assets/javascripts/search | |
parent | 879f5329ee916a948223f8f43d77fba4da6cd028 (diff) | |
download | gitlab-ce-48aff82709769b098321c738f3444b9bdaa694c6.tar.gz |
Add latest changes from gitlab-org/gitlab@13-5-stable-eev13.5.0-rc42
Diffstat (limited to 'app/assets/javascripts/search')
10 files changed, 241 insertions, 167 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..b6e2dd46358 --- /dev/null +++ b/app/assets/javascripts/search/dropdown_filter/components/dropdown_filter.vue @@ -0,0 +1,100 @@ +<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) { + visitUrl(setUrlParams({ [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 new file mode 100644 index 00000000000..780d3ff0d25 --- /dev/null +++ b/app/assets/javascripts/search/index.js @@ -0,0 +1,9 @@ +import { queryToObject } from '~/lib/utils/url_utility'; +import createStore from './store'; +import initDropdownFilters from './dropdown_filter'; + +export default () => { + const store = createStore({ query: queryToObject(window.location.search) }); + + initDropdownFilters(store); +}; diff --git a/app/assets/javascripts/search/state_filter/components/state_filter.vue b/app/assets/javascripts/search/state_filter/components/state_filter.vue deleted file mode 100644 index f08adaf8c83..00000000000 --- a/app/assets/javascripts/search/state_filter/components/state_filter.vue +++ /dev/null @@ -1,94 +0,0 @@ -<script> -import { GlDropdown, GlDropdownItem, GlDropdownDivider } from '@gitlab/ui'; -import { - FILTER_STATES, - SCOPES, - FILTER_STATES_BY_SCOPE, - FILTER_HEADER, - FILTER_TEXT, -} from '../constants'; -import { setUrlParams, visitUrl } from '~/lib/utils/url_utility'; - -const FILTERS_ARRAY = Object.values(FILTER_STATES); - -export default { - name: 'StateFilter', - components: { - GlDropdown, - GlDropdownItem, - GlDropdownDivider, - }, - props: { - scope: { - type: String, - required: true, - }, - state: { - type: String, - required: false, - default: FILTER_STATES.ANY.value, - validator: v => FILTERS_ARRAY.some(({ value }) => value === v), - }, - }, - computed: { - selectedFilterText() { - const filter = FILTERS_ARRAY.find(({ value }) => value === this.selectedFilter); - if (!filter || filter === FILTER_STATES.ANY) { - return FILTER_TEXT; - } - - return filter.label; - }, - showDropdown() { - return Object.values(SCOPES).includes(this.scope); - }, - selectedFilter: { - get() { - if (FILTERS_ARRAY.some(({ value }) => value === this.state)) { - return this.state; - } - - return FILTER_STATES.ANY.value; - }, - set(state) { - visitUrl(setUrlParams({ state })); - }, - }, - }, - methods: { - dropDownItemClass(filter) { - return { - 'gl-border-b-solid gl-border-b-gray-100 gl-border-b-1 gl-pb-2! gl-mb-2': - filter === FILTER_STATES.ANY, - }; - }, - isFilterSelected(filter) { - return filter === this.selectedFilter; - }, - handleFilterChange(state) { - this.selectedFilter = state; - }, - }, - filterStates: FILTER_STATES, - filterHeader: FILTER_HEADER, - filtersByScope: FILTER_STATES_BY_SCOPE, -}; -</script> - -<template> - <gl-dropdown v-if="showDropdown" :text="selectedFilterText" class="col-sm-3 gl-pt-4 gl-pl-0"> - <header class="gl-text-center gl-font-weight-bold gl-font-lg"> - {{ $options.filterHeader }} - </header> - <gl-dropdown-divider /> - <gl-dropdown-item - v-for="filter in $options.filtersByScope[scope]" - :key="filter.value" - :is-check-item="true" - :is-checked="isFilterSelected(filter.value)" - :class="dropDownItemClass(filter)" - @click="handleFilterChange(filter.value)" - >{{ filter.label }}</gl-dropdown-item - > - </gl-dropdown> -</template> diff --git a/app/assets/javascripts/search/state_filter/constants.js b/app/assets/javascripts/search/state_filter/constants.js deleted file mode 100644 index 2f11cab9044..00000000000 --- a/app/assets/javascripts/search/state_filter/constants.js +++ /dev/null @@ -1,39 +0,0 @@ -import { __ } from '~/locale'; - -export const FILTER_HEADER = __('Status'); - -export const FILTER_TEXT = __('Any Status'); - -export const FILTER_STATES = { - ANY: { - label: __('Any'), - value: 'all', - }, - OPEN: { - label: __('Open'), - value: 'opened', - }, - CLOSED: { - label: __('Closed'), - value: 'closed', - }, - MERGED: { - label: __('Merged'), - value: 'merged', - }, -}; - -export const SCOPES = { - ISSUES: 'issues', - MERGE_REQUESTS: 'merge_requests', -}; - -export const FILTER_STATES_BY_SCOPE = { - [SCOPES.ISSUES]: [FILTER_STATES.ANY, FILTER_STATES.OPEN, FILTER_STATES.CLOSED], - [SCOPES.MERGE_REQUESTS]: [ - FILTER_STATES.ANY, - FILTER_STATES.OPEN, - FILTER_STATES.MERGED, - FILTER_STATES.CLOSED, - ], -}; diff --git a/app/assets/javascripts/search/state_filter/index.js b/app/assets/javascripts/search/state_filter/index.js deleted file mode 100644 index 13708574cfb..00000000000 --- a/app/assets/javascripts/search/state_filter/index.js +++ /dev/null @@ -1,34 +0,0 @@ -import Vue from 'vue'; -import Translate from '~/vue_shared/translate'; -import StateFilter from './components/state_filter.vue'; - -Vue.use(Translate); - -export default () => { - const el = document.getElementById('js-search-filter-by-state'); - - if (!el) return false; - - return new Vue({ - el, - components: { - StateFilter, - }, - data() { - const { dataset } = this.$options.el; - return { - scope: dataset.scope, - state: dataset.state, - }; - }, - - render(createElement) { - return createElement('state-filter', { - props: { - scope: this.scope, - state: this.state, - }, - }); - }, - }); -}; diff --git a/app/assets/javascripts/search/store/index.js b/app/assets/javascripts/search/store/index.js new file mode 100644 index 00000000000..10cfb647a92 --- /dev/null +++ b/app/assets/javascripts/search/store/index.js @@ -0,0 +1,12 @@ +import Vue from 'vue'; +import Vuex from 'vuex'; +import createState from './state'; + +Vue.use(Vuex); + +export const getStoreConfig = ({ query }) => ({ + state: createState({ query }), +}); + +const createStore = config => new Vuex.Store(getStoreConfig(config)); +export default createStore; diff --git a/app/assets/javascripts/search/store/state.js b/app/assets/javascripts/search/store/state.js new file mode 100644 index 00000000000..9115a613767 --- /dev/null +++ b/app/assets/javascripts/search/store/state.js @@ -0,0 +1,4 @@ +const createState = ({ query }) => ({ + query, +}); +export default createState; |