diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-10-30 21:08:56 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-10-30 21:08:56 +0300 |
commit | 98d7cc758fb73239fb957c297446c811ab4150d9 (patch) | |
tree | 227a5e8efe35d2ac158e762397609a3f1754b224 /app/assets/javascripts/search | |
parent | 038366a0932c5f88019cc3db85382f26af3933e7 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/search')
-rw-r--r-- | app/assets/javascripts/search/group_filter/components/group_filter.vue | 124 | ||||
-rw-r--r-- | app/assets/javascripts/search/group_filter/constants.js | 10 | ||||
-rw-r--r-- | app/assets/javascripts/search/group_filter/index.js | 28 | ||||
-rw-r--r-- | app/assets/javascripts/search/index.js | 2 | ||||
-rw-r--r-- | app/assets/javascripts/search/store/actions.js | 16 | ||||
-rw-r--r-- | app/assets/javascripts/search/store/index.js | 4 | ||||
-rw-r--r-- | app/assets/javascripts/search/store/mutation_types.js | 3 | ||||
-rw-r--r-- | app/assets/javascripts/search/store/mutations.js | 15 | ||||
-rw-r--r-- | app/assets/javascripts/search/store/state.js | 2 |
9 files changed, 204 insertions, 0 deletions
diff --git a/app/assets/javascripts/search/group_filter/components/group_filter.vue b/app/assets/javascripts/search/group_filter/components/group_filter.vue new file mode 100644 index 00000000000..4b7963c5187 --- /dev/null +++ b/app/assets/javascripts/search/group_filter/components/group_filter.vue @@ -0,0 +1,124 @@ +<script> +import { + GlDropdown, + GlDropdownItem, + GlSearchBoxByType, + GlLoadingIcon, + GlIcon, + GlSkeletonLoader, + GlTooltipDirective, +} from '@gitlab/ui'; +import { mapState, mapActions } from 'vuex'; +import { isEmpty } from 'lodash'; +import { visitUrl, setUrlParams } from '~/lib/utils/url_utility'; +import { ANY_GROUP, GROUP_QUERY_PARAM, PROJECT_QUERY_PARAM } from '../constants'; + +export default { + name: 'GroupFilter', + components: { + GlDropdown, + GlDropdownItem, + GlSearchBoxByType, + GlLoadingIcon, + GlIcon, + GlSkeletonLoader, + }, + directives: { + GlTooltip: GlTooltipDirective, + }, + props: { + initialGroup: { + type: Object, + required: false, + default: () => ({}), + }, + }, + data() { + return { + groupSearch: '', + }; + }, + computed: { + ...mapState(['groups', 'fetchingGroups']), + selectedGroup: { + get() { + return isEmpty(this.initialGroup) ? ANY_GROUP : this.initialGroup; + }, + set(group) { + visitUrl(setUrlParams({ [GROUP_QUERY_PARAM]: group.id, [PROJECT_QUERY_PARAM]: null })); + }, + }, + }, + methods: { + ...mapActions(['fetchGroups']), + isGroupSelected(group) { + return group.id === this.selectedGroup.id; + }, + handleGroupChange(group) { + this.selectedGroup = group; + }, + }, + ANY_GROUP, +}; +</script> + +<template> + <gl-dropdown + ref="groupFilter" + class="gl-w-full" + menu-class="gl-w-full!" + toggle-class="gl-text-truncate gl-reset-line-height!" + :header-text="__('Filter results by group')" + @show="fetchGroups(groupSearch)" + > + <template #button-content> + <span class="dropdown-toggle-text gl-flex-grow-1 gl-text-truncate"> + {{ selectedGroup.name }} + </span> + <gl-loading-icon v-if="fetchingGroups" inline class="mr-2" /> + <gl-icon + v-if="!isGroupSelected($options.ANY_GROUP)" + v-gl-tooltip + name="clear" + :title="__('Clear')" + class="gl-text-gray-200! gl-hover-text-blue-800!" + @click.stop="handleGroupChange($options.ANY_GROUP)" + /> + <gl-icon name="chevron-down" /> + </template> + <div class="gl-sticky gl-top-0 gl-z-index-1 gl-bg-white"> + <gl-search-box-by-type + v-model="groupSearch" + class="m-2" + :debounce="500" + @input="fetchGroups" + /> + <gl-dropdown-item + class="gl-border-b-solid gl-border-b-gray-100 gl-border-b-1 gl-pb-2! gl-mb-2" + :is-check-item="true" + :is-checked="isGroupSelected($options.ANY_GROUP)" + @click="handleGroupChange($options.ANY_GROUP)" + > + {{ $options.ANY_GROUP.name }} + </gl-dropdown-item> + </div> + <div v-if="!fetchingGroups"> + <gl-dropdown-item + v-for="group in groups" + :key="group.id" + :is-check-item="true" + :is-checked="isGroupSelected(group)" + @click="handleGroupChange(group)" + > + {{ group.full_name }} + </gl-dropdown-item> + </div> + <div v-if="fetchingGroups" class="mx-3 mt-2"> + <gl-skeleton-loader :height="100"> + <rect y="0" width="90%" height="20" rx="4" /> + <rect y="40" width="70%" height="20" rx="4" /> + <rect y="80" width="80%" height="20" rx="4" /> + </gl-skeleton-loader> + </div> + </gl-dropdown> +</template> diff --git a/app/assets/javascripts/search/group_filter/constants.js b/app/assets/javascripts/search/group_filter/constants.js new file mode 100644 index 00000000000..9bd92eaa130 --- /dev/null +++ b/app/assets/javascripts/search/group_filter/constants.js @@ -0,0 +1,10 @@ +import { __ } from '~/locale'; + +export const ANY_GROUP = Object.freeze({ + id: null, + name: __('Any'), +}); + +export const GROUP_QUERY_PARAM = 'group_id'; + +export const PROJECT_QUERY_PARAM = 'project_id'; diff --git a/app/assets/javascripts/search/group_filter/index.js b/app/assets/javascripts/search/group_filter/index.js new file mode 100644 index 00000000000..9b009bc0305 --- /dev/null +++ b/app/assets/javascripts/search/group_filter/index.js @@ -0,0 +1,28 @@ +import Vue from 'vue'; +import Translate from '~/vue_shared/translate'; +import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; +import GroupFilter from './components/group_filter.vue'; + +Vue.use(Translate); + +export default store => { + let initialGroup; + const el = document.getElementById('js-search-group-dropdown'); + + const { initialGroupData } = el.dataset; + + initialGroup = JSON.parse(initialGroupData); + initialGroup = convertObjectPropsToCamelCase(initialGroup, { deep: true }); + + return new Vue({ + el, + store, + render(createElement) { + return createElement(GroupFilter, { + props: { + initialGroup, + }, + }); + }, + }); +}; diff --git a/app/assets/javascripts/search/index.js b/app/assets/javascripts/search/index.js index 780d3ff0d25..7d175bace4f 100644 --- a/app/assets/javascripts/search/index.js +++ b/app/assets/javascripts/search/index.js @@ -1,9 +1,11 @@ import { queryToObject } from '~/lib/utils/url_utility'; import createStore from './store'; import initDropdownFilters from './dropdown_filter'; +import initGroupFilter from './group_filter'; export default () => { const store = createStore({ query: queryToObject(window.location.search) }); initDropdownFilters(store); + initGroupFilter(store); }; diff --git a/app/assets/javascripts/search/store/actions.js b/app/assets/javascripts/search/store/actions.js new file mode 100644 index 00000000000..4bc8b2a9a5d --- /dev/null +++ b/app/assets/javascripts/search/store/actions.js @@ -0,0 +1,16 @@ +import Api from '~/api'; +import createFlash from '~/flash'; +import { __ } from '~/locale'; +import * as types from './mutation_types'; + +export const fetchGroups = ({ commit }, search) => { + commit(types.REQUEST_GROUPS); + Api.groups(search) + .then(data => { + commit(types.RECEIVE_GROUPS_SUCCESS, data); + }) + .catch(() => { + createFlash({ message: __('There was a problem fetching groups.') }); + commit(types.RECEIVE_GROUPS_ERROR); + }); +}; diff --git a/app/assets/javascripts/search/store/index.js b/app/assets/javascripts/search/store/index.js index 10cfb647a92..e0a7e488f9f 100644 --- a/app/assets/javascripts/search/store/index.js +++ b/app/assets/javascripts/search/store/index.js @@ -1,10 +1,14 @@ import Vue from 'vue'; import Vuex from 'vuex'; +import * as actions from './actions'; +import mutations from './mutations'; import createState from './state'; Vue.use(Vuex); export const getStoreConfig = ({ query }) => ({ + actions, + mutations, state: createState({ query }), }); diff --git a/app/assets/javascripts/search/store/mutation_types.js b/app/assets/javascripts/search/store/mutation_types.js new file mode 100644 index 00000000000..8469f3517c0 --- /dev/null +++ b/app/assets/javascripts/search/store/mutation_types.js @@ -0,0 +1,3 @@ +export const REQUEST_GROUPS = 'REQUEST_GROUPS'; +export const RECEIVE_GROUPS_SUCCESS = 'RECEIVE_GROUPS_SUCCESS'; +export const RECEIVE_GROUPS_ERROR = 'RECEIVE_GROUPS_ERROR'; diff --git a/app/assets/javascripts/search/store/mutations.js b/app/assets/javascripts/search/store/mutations.js new file mode 100644 index 00000000000..34fe14716f9 --- /dev/null +++ b/app/assets/javascripts/search/store/mutations.js @@ -0,0 +1,15 @@ +import * as types from './mutation_types'; + +export default { + [types.REQUEST_GROUPS](state) { + state.fetchingGroups = true; + }, + [types.RECEIVE_GROUPS_SUCCESS](state, data) { + state.fetchingGroups = false; + state.groups = data; + }, + [types.RECEIVE_GROUPS_ERROR](state) { + state.fetchingGroups = false; + state.groups = []; + }, +}; diff --git a/app/assets/javascripts/search/store/state.js b/app/assets/javascripts/search/store/state.js index 9115a613767..70a8aab9998 100644 --- a/app/assets/javascripts/search/store/state.js +++ b/app/assets/javascripts/search/store/state.js @@ -1,4 +1,6 @@ const createState = ({ query }) => ({ query, + groups: [], + fetchingGroups: false, }); export default createState; |