Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-04-20 13:00:54 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-04-20 13:00:54 +0300
commit3cccd102ba543e02725d247893729e5c73b38295 (patch)
treef36a04ec38517f5deaaacb5acc7d949688d1e187 /app/assets/javascripts/header_search
parent205943281328046ef7b4528031b90fbda70c75ac (diff)
Add latest changes from gitlab-org/gitlab@14-10-stable-eev14.10.0-rc42
Diffstat (limited to 'app/assets/javascripts/header_search')
-rw-r--r--app/assets/javascripts/header_search/components/app.vue25
-rw-r--r--app/assets/javascripts/header_search/components/header_search_autocomplete_items.vue74
-rw-r--r--app/assets/javascripts/header_search/components/header_search_scoped_items.vue6
-rw-r--r--app/assets/javascripts/header_search/constants.js8
-rw-r--r--app/assets/javascripts/header_search/store/actions.js4
-rw-r--r--app/assets/javascripts/header_search/store/getters.js1
6 files changed, 101 insertions, 17 deletions
diff --git a/app/assets/javascripts/header_search/components/app.vue b/app/assets/javascripts/header_search/components/app.vue
index 36fc48a2ba8..4406cacdf3f 100644
--- a/app/assets/javascripts/header_search/components/app.vue
+++ b/app/assets/javascripts/header_search/components/app.vue
@@ -11,6 +11,7 @@ import {
SEARCH_BOX_INDEX,
SEARCH_INPUT_DESCRIPTION,
SEARCH_RESULTS_DESCRIPTION,
+ SEARCH_SHORTCUTS_MIN_CHARACTERS,
} from '../constants';
import HeaderSearchAutocompleteItems from './header_search_autocomplete_items.vue';
import HeaderSearchDefaultItems from './header_search_default_items.vue';
@@ -50,7 +51,7 @@ export default {
},
computed: {
...mapState(['search', 'loading']),
- ...mapGetters(['searchQuery', 'searchOptions']),
+ ...mapGetters(['searchQuery', 'searchOptions', 'autocompleteGroupedSearchOptions']),
searchText: {
get() {
return this.search;
@@ -66,14 +67,20 @@ export default {
return this.currentFocusedOption?.html_id;
},
isLoggedIn() {
- return gon?.current_username;
+ return Boolean(gon?.current_username);
},
showSearchDropdown() {
- return this.showDropdown && this.isLoggedIn;
+ const hasResultsUnderMinCharacters =
+ this.searchText?.length === 1 ? this?.autocompleteGroupedSearchOptions?.length > 0 : true;
+
+ return this.showDropdown && this.isLoggedIn && hasResultsUnderMinCharacters;
},
showDefaultItems() {
return !this.searchText;
},
+ showShortcuts() {
+ return this.searchText && this.searchText?.length >= SEARCH_SHORTCUTS_MIN_CHARACTERS;
+ },
defaultIndex() {
if (this.showDefaultItems) {
return SEARCH_BOX_INDEX;
@@ -105,6 +112,9 @@ export default {
count: this.searchOptions.length,
});
},
+ headerSearchActivityDescriptor() {
+ return this.showDropdown ? 'is-active' : 'is-not-active';
+ },
},
methods: {
...mapActions(['setSearch', 'fetchAutocompleteOptions', 'clearAutocomplete']),
@@ -136,13 +146,15 @@ export default {
v-outside="closeDropdown"
role="search"
:aria-label="$options.i18n.searchGitlab"
- class="header-search gl-relative"
+ class="header-search gl-relative gl-rounded-base"
+ :class="headerSearchActivityDescriptor"
>
<gl-search-box-by-type
id="search"
v-model="searchText"
role="searchbox"
class="gl-z-index-1"
+ data-qa-selector="search_term_field"
autocomplete="off"
:placeholder="$options.i18n.searchGitlab"
:aria-activedescendant="currentFocusedId"
@@ -182,7 +194,10 @@ export default {
:current-focused-option="currentFocusedOption"
/>
<template v-else>
- <header-search-scoped-items :current-focused-option="currentFocusedOption" />
+ <header-search-scoped-items
+ v-if="showShortcuts"
+ :current-focused-option="currentFocusedOption"
+ />
<header-search-autocomplete-items :current-focused-option="currentFocusedOption" />
</template>
</div>
diff --git a/app/assets/javascripts/header_search/components/header_search_autocomplete_items.vue b/app/assets/javascripts/header_search/components/header_search_autocomplete_items.vue
index c0e2c18bece..025c48f355d 100644
--- a/app/assets/javascripts/header_search/components/header_search_autocomplete_items.vue
+++ b/app/assets/javascripts/header_search/components/header_search_autocomplete_items.vue
@@ -11,7 +11,18 @@ import {
import { mapState, mapGetters } from 'vuex';
import { s__ } from '~/locale';
import highlight from '~/lib/utils/highlight';
-import { GROUPS_CATEGORY, PROJECTS_CATEGORY, LARGE_AVATAR_PX, SMALL_AVATAR_PX } from '../constants';
+import { AVATAR_SHAPE_OPTION_RECT } from '~/vue_shared/constants';
+import { truncateNamespace } from '~/lib/utils/text_utility';
+
+import {
+ GROUPS_CATEGORY,
+ PROJECTS_CATEGORY,
+ MERGE_REQUEST_CATEGORY,
+ ISSUES_CATEGORY,
+ RECENT_EPICS_CATEGORY,
+ LARGE_AVATAR_PX,
+ SMALL_AVATAR_PX,
+} from '../constants';
export default {
name: 'HeaderSearchAutocompleteItems',
@@ -39,7 +50,7 @@ export default {
},
},
computed: {
- ...mapState(['search', 'loading', 'autocompleteError']),
+ ...mapState(['search', 'loading', 'autocompleteError', 'searchContext']),
...mapGetters(['autocompleteGroupedSearchOptions']),
},
watch: {
@@ -52,6 +63,13 @@ export default {
},
},
methods: {
+ truncateNamespace(string) {
+ if (string.split(' / ').length > 2) {
+ return truncateNamespace(string);
+ }
+
+ return string;
+ },
highlightedName(val) {
return highlight(val, this.search);
},
@@ -65,15 +83,45 @@ export default {
isOptionFocused(data) {
return this.currentFocusedOption?.html_id === data.html_id;
},
+ isProjectsCategory(data) {
+ return data.category === PROJECTS_CATEGORY;
+ },
+ getEntityId(data) {
+ switch (data.category) {
+ case GROUPS_CATEGORY:
+ case RECENT_EPICS_CATEGORY:
+ return data.group_id || data.id || this.searchContext?.group?.id;
+ case PROJECTS_CATEGORY:
+ case ISSUES_CATEGORY:
+ case MERGE_REQUEST_CATEGORY:
+ return data.project_id || data.id || this.searchContext?.project?.id;
+ default:
+ return data.id;
+ }
+ },
+ getEntitytName(data) {
+ switch (data.category) {
+ case GROUPS_CATEGORY:
+ case RECENT_EPICS_CATEGORY:
+ return data.group_name || data.value || data.label || this.searchContext?.group?.name;
+ case PROJECTS_CATEGORY:
+ case ISSUES_CATEGORY:
+ case MERGE_REQUEST_CATEGORY:
+ return data.project_name || data.value || data.label || this.searchContext?.project?.name;
+ default:
+ return data.label;
+ }
+ },
},
+ AVATAR_SHAPE_OPTION_RECT,
};
</script>
<template>
<div>
<template v-if="!loading">
- <div v-for="option in autocompleteGroupedSearchOptions" :key="option.category">
- <gl-dropdown-divider />
+ <div v-for="(option, index) in autocompleteGroupedSearchOptions" :key="option.category">
+ <gl-dropdown-divider v-if="index > 0" />
<gl-dropdown-section-header>{{ option.category }}</gl-dropdown-section-header>
<gl-dropdown-item
v-for="data in option.data"
@@ -90,12 +138,22 @@ export default {
<gl-avatar
v-if="data.avatar_url !== undefined"
:src="data.avatar_url"
- :entity-id="data.id"
- :entity-name="data.label"
+ :entity-id="getEntityId(data)"
+ :entity-name="getEntitytName(data)"
:size="avatarSize(data)"
- shape="square"
+ :shape="$options.AVATAR_SHAPE_OPTION_RECT"
/>
- <span v-safe-html="highlightedName(data.label)"></span>
+ <span class="gl-display-flex gl-flex-direction-column">
+ <span
+ v-safe-html="highlightedName(data.value || data.label)"
+ class="gl-text-gray-900"
+ ></span>
+ <span
+ v-if="data.value"
+ v-safe-html="truncateNamespace(data.label)"
+ class="gl-font-sm gl-text-gray-500"
+ ></span>
+ </span>
</div>
</gl-dropdown-item>
</div>
diff --git a/app/assets/javascripts/header_search/components/header_search_scoped_items.vue b/app/assets/javascripts/header_search/components/header_search_scoped_items.vue
index 3aebee71509..34d1bd71399 100644
--- a/app/assets/javascripts/header_search/components/header_search_scoped_items.vue
+++ b/app/assets/javascripts/header_search/components/header_search_scoped_items.vue
@@ -1,5 +1,5 @@
<script>
-import { GlDropdownItem } from '@gitlab/ui';
+import { GlDropdownItem, GlDropdownDivider } from '@gitlab/ui';
import { mapState, mapGetters } from 'vuex';
import { __, sprintf } from '~/locale';
@@ -7,6 +7,7 @@ export default {
name: 'HeaderSearchScopedItems',
components: {
GlDropdownItem,
+ GlDropdownDivider,
},
props: {
currentFocusedOption: {
@@ -17,7 +18,7 @@ export default {
},
computed: {
...mapState(['search']),
- ...mapGetters(['scopedSearchOptions']),
+ ...mapGetters(['scopedSearchOptions', 'autocompleteGroupedSearchOptions']),
},
methods: {
isOptionFocused(option) {
@@ -53,5 +54,6 @@ export default {
<span v-if="option.scope" class="gl-font-style-italic">{{ option.scope }}</span>
</span>
</gl-dropdown-item>
+ <gl-dropdown-divider v-if="autocompleteGroupedSearchOptions.length > 0" />
</div>
</template>
diff --git a/app/assets/javascripts/header_search/constants.js b/app/assets/javascripts/header_search/constants.js
index b2e45fcd648..045a552efb0 100644
--- a/app/assets/javascripts/header_search/constants.js
+++ b/app/assets/javascripts/header_search/constants.js
@@ -20,6 +20,12 @@ export const GROUPS_CATEGORY = 'Groups';
export const PROJECTS_CATEGORY = 'Projects';
+export const ISSUES_CATEGORY = 'Recent issues';
+
+export const MERGE_REQUEST_CATEGORY = 'Recent merge requests';
+
+export const RECENT_EPICS_CATEGORY = 'Recent epics';
+
export const LARGE_AVATAR_PX = 32;
export const SMALL_AVATAR_PX = 16;
@@ -28,6 +34,8 @@ export const FIRST_DROPDOWN_INDEX = 0;
export const SEARCH_BOX_INDEX = -1;
+export const SEARCH_SHORTCUTS_MIN_CHARACTERS = 2;
+
export const SEARCH_INPUT_DESCRIPTION = 'search-input-description';
export const SEARCH_RESULTS_DESCRIPTION = 'search-results-description';
diff --git a/app/assets/javascripts/header_search/store/actions.js b/app/assets/javascripts/header_search/store/actions.js
index ee4c312fed0..3a86dcca409 100644
--- a/app/assets/javascripts/header_search/store/actions.js
+++ b/app/assets/javascripts/header_search/store/actions.js
@@ -5,7 +5,9 @@ export const fetchAutocompleteOptions = ({ commit, getters }) => {
commit(types.REQUEST_AUTOCOMPLETE);
return axios
.get(getters.autocompleteQuery)
- .then(({ data }) => commit(types.RECEIVE_AUTOCOMPLETE_SUCCESS, data))
+ .then(({ data }) => {
+ commit(types.RECEIVE_AUTOCOMPLETE_SUCCESS, data);
+ })
.catch(() => {
commit(types.RECEIVE_AUTOCOMPLETE_ERROR);
});
diff --git a/app/assets/javascripts/header_search/store/getters.js b/app/assets/javascripts/header_search/store/getters.js
index 87dec95153f..7d08aa859fb 100644
--- a/app/assets/javascripts/header_search/store/getters.js
+++ b/app/assets/javascripts/header_search/store/getters.js
@@ -190,7 +190,6 @@ export const autocompleteGroupedSearchOptions = (state) => {
results.push(groupedOptions[option.category]);
}
});
-
return results;
};