diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-09-10 06:10:59 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-09-10 06:10:59 +0300 |
commit | db6b854ea711b395c17827a5047f54dc29b518f9 (patch) | |
tree | 5c853b091a3a4068a3a091a33929128900c1a47b /app/assets/javascripts/header_search | |
parent | 8f8e342720899033f06747430414d2d2e3e6527a (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/header_search')
7 files changed, 168 insertions, 3 deletions
diff --git a/app/assets/javascripts/header_search/components/app.vue b/app/assets/javascripts/header_search/components/app.vue index 0c4df9cf522..cdec3d8eec3 100644 --- a/app/assets/javascripts/header_search/components/app.vue +++ b/app/assets/javascripts/header_search/components/app.vue @@ -1,20 +1,56 @@ <script> -import { GlSearchBoxByType } from '@gitlab/ui'; +import { GlSearchBoxByType, GlOutsideDirective as Outside } from '@gitlab/ui'; import { __ } from '~/locale'; +import HeaderSearchDefaultItems from './header_search_default_items.vue'; export default { name: 'HeaderSearchApp', i18n: { searchPlaceholder: __('Search or jump to...'), }, + directives: { Outside }, components: { GlSearchBoxByType, + HeaderSearchDefaultItems, + }, + data() { + return { + showDropdown: false, + }; + }, + computed: { + showSearchDropdown() { + return this.showDropdown && gon?.current_username; + }, + }, + methods: { + openDropdown() { + this.showDropdown = true; + }, + closeDropdown() { + this.showDropdown = false; + }, }, }; </script> <template> - <section class="header-search"> - <gl-search-box-by-type autocomplete="off" :placeholder="$options.i18n.searchPlaceholder" /> + <section v-outside="closeDropdown" class="header-search gl-relative"> + <gl-search-box-by-type + autocomplete="off" + :placeholder="$options.i18n.searchPlaceholder" + @focus="openDropdown" + @click="openDropdown" + @keydown.esc="closeDropdown" + /> + <div + v-if="showSearchDropdown" + data-testid="header-search-dropdown-menu" + class="header-search-dropdown-menu gl-overflow-y-auto gl-absolute gl-left-0 gl-z-index-1 gl-w-full gl-bg-white gl-border-1 gl-rounded-base gl-border-solid gl-border-gray-200 gl-shadow-x0-y2-b4-s0" + > + <div class="header-search-dropdown-content gl-overflow-y-auto gl-py-2"> + <header-search-default-items /> + </div> + </div> </section> </template> diff --git a/app/assets/javascripts/header_search/components/header_search_default_items.vue b/app/assets/javascripts/header_search/components/header_search_default_items.vue new file mode 100644 index 00000000000..2871937ed3a --- /dev/null +++ b/app/assets/javascripts/header_search/components/header_search_default_items.vue @@ -0,0 +1,42 @@ +<script> +import { GlDropdownItem, GlDropdownSectionHeader } from '@gitlab/ui'; +import { mapState, mapGetters } from 'vuex'; +import { __ } from '~/locale'; + +export default { + name: 'HeaderSearchDefaultItems', + i18n: { + allGitLab: __('All GitLab'), + }, + components: { + GlDropdownSectionHeader, + GlDropdownItem, + }, + computed: { + ...mapState(['searchContext']), + ...mapGetters(['defaultSearchOptions']), + sectionHeader() { + return ( + this.searchContext.project?.name || + this.searchContext.group?.name || + this.$options.i18n.allGitLab + ); + }, + }, +}; +</script> + +<template> + <div> + <gl-dropdown-section-header>{{ sectionHeader }}</gl-dropdown-section-header> + <gl-dropdown-item + v-for="(option, index) in defaultSearchOptions" + :id="`default-${index}`" + :key="index" + tabindex="-1" + :href="option.url" + > + {{ option.title }} + </gl-dropdown-item> + </div> +</template> diff --git a/app/assets/javascripts/header_search/constants.js b/app/assets/javascripts/header_search/constants.js new file mode 100644 index 00000000000..64e56156c2f --- /dev/null +++ b/app/assets/javascripts/header_search/constants.js @@ -0,0 +1,11 @@ +import { __ } from '~/locale'; + +export const MSG_ISSUES_ASSIGNED_TO_ME = __('Issues assigned to me'); + +export const MSG_ISSUES_IVE_CREATED = __("Issues I've created"); + +export const MSG_MR_ASSIGNED_TO_ME = __('Merge requests assigned to me'); + +export const MSG_MR_IM_REVIEWER = __("Merge requests that I'm a reviewer"); + +export const MSG_MR_IVE_CREATED = __("Merge requests I've created"); diff --git a/app/assets/javascripts/header_search/index.js b/app/assets/javascripts/header_search/index.js index fa1ac71655c..0881db16be3 100644 --- a/app/assets/javascripts/header_search/index.js +++ b/app/assets/javascripts/header_search/index.js @@ -1,6 +1,7 @@ import Vue from 'vue'; import Translate from '~/vue_shared/translate'; import HeaderSearchApp from './components/app.vue'; +import createStore from './store'; Vue.use(Translate); @@ -11,8 +12,13 @@ export const initHeaderSearchApp = () => { return false; } + const { issuesPath, mrPath } = el.dataset; + let { searchContext } = el.dataset; + searchContext = JSON.parse(searchContext); + return new Vue({ el, + store: createStore({ issuesPath, mrPath, searchContext }), render(createElement) { return createElement(HeaderSearchApp); }, diff --git a/app/assets/javascripts/header_search/store/getters.js b/app/assets/javascripts/header_search/store/getters.js new file mode 100644 index 00000000000..1feb0e519ba --- /dev/null +++ b/app/assets/javascripts/header_search/store/getters.js @@ -0,0 +1,50 @@ +import { + MSG_ISSUES_ASSIGNED_TO_ME, + MSG_ISSUES_IVE_CREATED, + MSG_MR_ASSIGNED_TO_ME, + MSG_MR_IM_REVIEWER, + MSG_MR_IVE_CREATED, +} from '../constants'; + +export const scopedIssuesPath = (state) => { + return ( + state.searchContext.project_metadata?.issues_path || + state.searchContext.group_metadata?.issues_path || + state.issuesPath + ); +}; + +export const scopedMRPath = (state) => { + return ( + state.searchContext.project_metadata?.mr_path || + state.searchContext.group_metadata?.mr_path || + state.mrPath + ); +}; + +export const defaultSearchOptions = (state, getters) => { + const userName = gon.current_username; + + return [ + { + title: MSG_ISSUES_ASSIGNED_TO_ME, + url: `${getters.scopedIssuesPath}/?assignee_username=${userName}`, + }, + { + title: MSG_ISSUES_IVE_CREATED, + url: `${getters.scopedIssuesPath}/?author_username=${userName}`, + }, + { + title: MSG_MR_ASSIGNED_TO_ME, + url: `${getters.scopedMRPath}/?assignee_username=${userName}`, + }, + { + title: MSG_MR_IM_REVIEWER, + url: `${getters.scopedMRPath}/?reviewer_username=${userName}`, + }, + { + title: MSG_MR_IVE_CREATED, + url: `${getters.scopedMRPath}/?author_username=${userName}`, + }, + ]; +}; diff --git a/app/assets/javascripts/header_search/store/index.js b/app/assets/javascripts/header_search/store/index.js new file mode 100644 index 00000000000..066e02aed9f --- /dev/null +++ b/app/assets/javascripts/header_search/store/index.js @@ -0,0 +1,14 @@ +import Vue from 'vue'; +import Vuex from 'vuex'; +import * as getters from './getters'; +import createState from './state'; + +Vue.use(Vuex); + +export const getStoreConfig = ({ issuesPath, mrPath, searchContext }) => ({ + getters, + state: createState({ issuesPath, mrPath, searchContext }), +}); + +const createStore = (config) => new Vuex.Store(getStoreConfig(config)); +export default createStore; diff --git a/app/assets/javascripts/header_search/store/state.js b/app/assets/javascripts/header_search/store/state.js new file mode 100644 index 00000000000..94a238a24ee --- /dev/null +++ b/app/assets/javascripts/header_search/store/state.js @@ -0,0 +1,6 @@ +const createState = ({ issuesPath, mrPath, searchContext }) => ({ + issuesPath, + mrPath, + searchContext, +}); +export default createState; |