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>2021-03-16 21:18:33 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-03-16 21:18:33 +0300
commitf64a639bcfa1fc2bc89ca7db268f594306edfd7c (patch)
treea2c3c2ebcc3b45e596949db485d6ed18ffaacfa1 /app/assets/javascripts/ref
parentbfbc3e0d6583ea1a91f627528bedc3d65ba4b10f (diff)
Add latest changes from gitlab-org/gitlab@13-10-stable-eev13.10.0-rc40
Diffstat (limited to 'app/assets/javascripts/ref')
-rw-r--r--app/assets/javascripts/ref/components/ref_results_section.vue8
-rw-r--r--app/assets/javascripts/ref/components/ref_selector.vue239
-rw-r--r--app/assets/javascripts/ref/constants.js5
-rw-r--r--app/assets/javascripts/ref/stores/actions.js17
-rw-r--r--app/assets/javascripts/ref/stores/mutation_types.js2
-rw-r--r--app/assets/javascripts/ref/stores/mutations.js3
-rw-r--r--app/assets/javascripts/ref/stores/state.js25
7 files changed, 193 insertions, 106 deletions
diff --git a/app/assets/javascripts/ref/components/ref_results_section.vue b/app/assets/javascripts/ref/components/ref_results_section.vue
index 87ce4f1a49c..4fa2a92ff03 100644
--- a/app/assets/javascripts/ref/components/ref_results_section.vue
+++ b/app/assets/javascripts/ref/components/ref_results_section.vue
@@ -11,6 +11,12 @@ export default {
GlIcon,
},
props: {
+ showHeader: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+
sectionTitle: {
type: String,
required: true,
@@ -84,7 +90,7 @@ export default {
<template>
<div>
- <gl-dropdown-section-header>
+ <gl-dropdown-section-header v-if="showHeader">
<div class="gl-display-flex align-items-center" data-testid="section-header">
<span class="gl-mr-2 gl-mb-1">{{ sectionTitle }}</span>
<gl-badge variant="neutral">{{ totalCountText }}</gl-badge>
diff --git a/app/assets/javascripts/ref/components/ref_selector.vue b/app/assets/javascripts/ref/components/ref_selector.vue
index 8f2805b36f6..82963fe98fd 100644
--- a/app/assets/javascripts/ref/components/ref_selector.vue
+++ b/app/assets/javascripts/ref/components/ref_selector.vue
@@ -2,32 +2,48 @@
import {
GlDropdown,
GlDropdownDivider,
- GlDropdownSectionHeader,
GlSearchBoxByType,
GlSprintf,
- GlIcon,
GlLoadingIcon,
} from '@gitlab/ui';
-import { debounce } from 'lodash';
+import { debounce, isArray } from 'lodash';
import { mapActions, mapGetters, mapState } from 'vuex';
-import { SEARCH_DEBOUNCE_MS, DEFAULT_I18N } from '../constants';
+import {
+ ALL_REF_TYPES,
+ SEARCH_DEBOUNCE_MS,
+ DEFAULT_I18N,
+ REF_TYPE_BRANCHES,
+ REF_TYPE_TAGS,
+ REF_TYPE_COMMITS,
+} from '../constants';
import createStore from '../stores';
import RefResultsSection from './ref_results_section.vue';
export default {
name: 'RefSelector',
- store: createStore(),
components: {
GlDropdown,
GlDropdownDivider,
- GlDropdownSectionHeader,
GlSearchBoxByType,
GlSprintf,
- GlIcon,
GlLoadingIcon,
RefResultsSection,
},
props: {
+ enabledRefTypes: {
+ type: Array,
+ required: false,
+ default: () => ALL_REF_TYPES,
+ validator: (val) =>
+ // It has to be an arrray
+ isArray(val) &&
+ // with at least one item
+ val.length > 0 &&
+ // and only "REF_TYPE_BRANCHES", "REF_TYPE_TAGS", and "REF_TYPE_COMMITS" are allowed
+ val.every((item) => ALL_REF_TYPES.includes(item)) &&
+ // and no duplicates are allowed
+ val.length === new Set(val).size,
+ },
value: {
type: String,
required: false,
@@ -42,6 +58,13 @@ export default {
required: false,
default: () => ({}),
},
+
+ /** The validation state of this component. */
+ state: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
},
data() {
return {
@@ -62,17 +85,45 @@ export default {
};
},
showBranchesSection() {
- return Boolean(this.matches.branches.totalCount > 0 || this.matches.branches.error);
+ return (
+ this.enabledRefTypes.includes(REF_TYPE_BRANCHES) &&
+ Boolean(this.matches.branches.totalCount > 0 || this.matches.branches.error)
+ );
},
showTagsSection() {
- return Boolean(this.matches.tags.totalCount > 0 || this.matches.tags.error);
+ return (
+ this.enabledRefTypes.includes(REF_TYPE_TAGS) &&
+ Boolean(this.matches.tags.totalCount > 0 || this.matches.tags.error)
+ );
},
showCommitsSection() {
- return Boolean(this.matches.commits.totalCount > 0 || this.matches.commits.error);
+ return (
+ this.enabledRefTypes.includes(REF_TYPE_COMMITS) &&
+ Boolean(this.matches.commits.totalCount > 0 || this.matches.commits.error)
+ );
},
showNoResults() {
return !this.showBranchesSection && !this.showTagsSection && !this.showCommitsSection;
},
+ showSectionHeaders() {
+ return this.enabledRefTypes.length > 1;
+ },
+ toggleButtonClass() {
+ return {
+ 'gl-inset-border-1-red-500!': !this.state,
+ 'gl-font-monospace': Boolean(this.selectedRef),
+ };
+ },
+ footerSlotProps() {
+ return {
+ isLoading: this.isLoading,
+ matches: this.matches,
+ query: this.lastQuery,
+ };
+ },
+ buttonText() {
+ return this.selectedRef || this.i18n.noRefSelected;
+ },
},
watch: {
// Keep the Vuex store synchronized if the parent
@@ -86,6 +137,14 @@ export default {
},
},
},
+ beforeCreate() {
+ // Setting the store here instead of using
+ // the built in `store` component option because
+ // we need each new `RefSelector` instance to
+ // create a new Vuex store instance.
+ // See https://github.com/vuejs/vuex/issues/414#issue-184491718.
+ this.$store = createStore();
+ },
created() {
// This method is defined here instead of in `methods`
// because we need to access the .cancel() method
@@ -93,20 +152,29 @@ export default {
// made inaccessible by Vue. More info:
// https://stackoverflow.com/a/52988020/1063392
this.debouncedSearch = debounce(function search() {
- this.search(this.query);
+ this.search();
}, SEARCH_DEBOUNCE_MS);
this.setProjectId(this.projectId);
- this.search(this.query);
+
+ this.$watch(
+ 'enabledRefTypes',
+ () => {
+ this.setEnabledRefTypes(this.enabledRefTypes);
+ this.search();
+ },
+ { immediate: true },
+ );
},
methods: {
- ...mapActions(['setProjectId', 'setSelectedRef', 'search']),
+ ...mapActions(['setEnabledRefTypes', 'setProjectId', 'setSelectedRef']),
+ ...mapActions({ storeSearch: 'search' }),
focusSearchBox() {
this.$refs.searchBox.$el.querySelector('input').focus();
},
onSearchBoxEnter() {
this.debouncedSearch.cancel();
- this.search(this.query);
+ this.search();
},
onSearchBoxInput() {
this.debouncedSearch();
@@ -115,97 +183,96 @@ export default {
this.setSelectedRef(ref);
this.$emit('input', this.selectedRef);
},
+ search() {
+ this.storeSearch(this.query);
+ },
},
};
</script>
<template>
- <gl-dropdown v-bind="$attrs" class="ref-selector" @shown="focusSearchBox">
- <template slot="button-content">
- <span class="gl-flex-grow-1 gl-ml-2 gl-text-gray-400" data-testid="button-content">
- <span v-if="selectedRef" class="gl-font-monospace">{{ selectedRef }}</span>
- <span v-else>{{ i18n.noRefSelected }}</span>
- </span>
- <gl-icon name="chevron-down" />
- </template>
-
- <div class="gl-display-flex gl-flex-direction-column ref-selector-dropdown-content">
- <gl-dropdown-section-header>
- <span class="gl-text-center gl-display-block">{{ i18n.dropdownHeader }}</span>
- </gl-dropdown-section-header>
-
- <gl-dropdown-divider />
-
+ <gl-dropdown
+ :header-text="i18n.dropdownHeader"
+ :toggle-class="toggleButtonClass"
+ :text="buttonText"
+ class="ref-selector"
+ v-bind="$attrs"
+ v-on="$listeners"
+ @shown="focusSearchBox"
+ >
+ <template #header>
<gl-search-box-by-type
ref="searchBox"
v-model.trim="query"
:placeholder="i18n.searchPlaceholder"
+ autocomplete="off"
@input="onSearchBoxInput"
@keydown.enter.prevent="onSearchBoxEnter"
/>
+ </template>
- <div class="gl-flex-grow-1 gl-overflow-y-auto">
- <gl-loading-icon v-if="isLoading" size="lg" class="gl-my-3" />
+ <gl-loading-icon v-if="isLoading" size="lg" class="gl-my-3" />
- <div
- v-else-if="showNoResults"
- class="gl-text-center gl-mx-3 gl-py-3"
- data-testid="no-results"
- >
- <gl-sprintf v-if="lastQuery" :message="i18n.noResultsWithQuery">
- <template #query>
- <b class="gl-word-break-all">{{ lastQuery }}</b>
- </template>
- </gl-sprintf>
+ <div v-else-if="showNoResults" class="gl-text-center gl-mx-3 gl-py-3" data-testid="no-results">
+ <gl-sprintf v-if="lastQuery" :message="i18n.noResultsWithQuery">
+ <template #query>
+ <b class="gl-word-break-all">{{ lastQuery }}</b>
+ </template>
+ </gl-sprintf>
- <span v-else>{{ i18n.noResults }}</span>
- </div>
+ <span v-else>{{ i18n.noResults }}</span>
+ </div>
- <template v-else>
- <template v-if="showBranchesSection">
- <ref-results-section
- :section-title="i18n.branches"
- :total-count="matches.branches.totalCount"
- :items="matches.branches.list"
- :selected-ref="selectedRef"
- :error="matches.branches.error"
- :error-message="i18n.branchesErrorMessage"
- data-testid="branches-section"
- @selected="selectRef($event)"
- />
+ <template v-else>
+ <template v-if="showBranchesSection">
+ <ref-results-section
+ :section-title="i18n.branches"
+ :total-count="matches.branches.totalCount"
+ :items="matches.branches.list"
+ :selected-ref="selectedRef"
+ :error="matches.branches.error"
+ :error-message="i18n.branchesErrorMessage"
+ :show-header="showSectionHeaders"
+ data-testid="branches-section"
+ @selected="selectRef($event)"
+ />
- <gl-dropdown-divider v-if="showTagsSection || showCommitsSection" />
- </template>
+ <gl-dropdown-divider v-if="showTagsSection || showCommitsSection" />
+ </template>
- <template v-if="showTagsSection">
- <ref-results-section
- :section-title="i18n.tags"
- :total-count="matches.tags.totalCount"
- :items="matches.tags.list"
- :selected-ref="selectedRef"
- :error="matches.tags.error"
- :error-message="i18n.tagsErrorMessage"
- data-testid="tags-section"
- @selected="selectRef($event)"
- />
+ <template v-if="showTagsSection">
+ <ref-results-section
+ :section-title="i18n.tags"
+ :total-count="matches.tags.totalCount"
+ :items="matches.tags.list"
+ :selected-ref="selectedRef"
+ :error="matches.tags.error"
+ :error-message="i18n.tagsErrorMessage"
+ :show-header="showSectionHeaders"
+ data-testid="tags-section"
+ @selected="selectRef($event)"
+ />
- <gl-dropdown-divider v-if="showCommitsSection" />
- </template>
+ <gl-dropdown-divider v-if="showCommitsSection" />
+ </template>
- <template v-if="showCommitsSection">
- <ref-results-section
- :section-title="i18n.commits"
- :total-count="matches.commits.totalCount"
- :items="matches.commits.list"
- :selected-ref="selectedRef"
- :error="matches.commits.error"
- :error-message="i18n.commitsErrorMessage"
- data-testid="commits-section"
- @selected="selectRef($event)"
- />
- </template>
- </template>
- </div>
- </div>
+ <template v-if="showCommitsSection">
+ <ref-results-section
+ :section-title="i18n.commits"
+ :total-count="matches.commits.totalCount"
+ :items="matches.commits.list"
+ :selected-ref="selectedRef"
+ :error="matches.commits.error"
+ :error-message="i18n.commitsErrorMessage"
+ :show-header="showSectionHeaders"
+ data-testid="commits-section"
+ @selected="selectRef($event)"
+ />
+ </template>
+ </template>
+
+ <template #footer>
+ <slot name="footer" v-bind="footerSlotProps"></slot>
+ </template>
</gl-dropdown>
</template>
diff --git a/app/assets/javascripts/ref/constants.js b/app/assets/javascripts/ref/constants.js
index ca82b951377..44d0f50b832 100644
--- a/app/assets/javascripts/ref/constants.js
+++ b/app/assets/javascripts/ref/constants.js
@@ -1,5 +1,10 @@
import { __ } from '~/locale';
+export const REF_TYPE_BRANCHES = 'REF_TYPE_BRANCHES';
+export const REF_TYPE_TAGS = 'REF_TYPE_TAGS';
+export const REF_TYPE_COMMITS = 'REF_TYPE_COMMITS';
+export const ALL_REF_TYPES = Object.freeze([REF_TYPE_BRANCHES, REF_TYPE_TAGS, REF_TYPE_COMMITS]);
+
export const X_TOTAL_HEADER = 'x-total';
export const SEARCH_DEBOUNCE_MS = 250;
diff --git a/app/assets/javascripts/ref/stores/actions.js b/app/assets/javascripts/ref/stores/actions.js
index d9bdd64ace5..3832cc0c21d 100644
--- a/app/assets/javascripts/ref/stores/actions.js
+++ b/app/assets/javascripts/ref/stores/actions.js
@@ -1,17 +1,26 @@
import Api from '~/api';
+import { REF_TYPE_BRANCHES, REF_TYPE_TAGS, REF_TYPE_COMMITS } from '../constants';
import * as types from './mutation_types';
+export const setEnabledRefTypes = ({ commit }, refTypes) =>
+ commit(types.SET_ENABLED_REF_TYPES, refTypes);
+
export const setProjectId = ({ commit }, projectId) => commit(types.SET_PROJECT_ID, projectId);
export const setSelectedRef = ({ commit }, selectedRef) =>
commit(types.SET_SELECTED_REF, selectedRef);
-export const search = ({ dispatch, commit }, query) => {
+export const search = ({ state, dispatch, commit }, query) => {
commit(types.SET_QUERY, query);
- dispatch('searchBranches');
- dispatch('searchTags');
- dispatch('searchCommits');
+ const dispatchIfRefTypeEnabled = (refType, action) => {
+ if (state.enabledRefTypes.includes(refType)) {
+ dispatch(action);
+ }
+ };
+ dispatchIfRefTypeEnabled(REF_TYPE_BRANCHES, 'searchBranches');
+ dispatchIfRefTypeEnabled(REF_TYPE_TAGS, 'searchTags');
+ dispatchIfRefTypeEnabled(REF_TYPE_COMMITS, 'searchCommits');
};
export const searchBranches = ({ commit, state }) => {
diff --git a/app/assets/javascripts/ref/stores/mutation_types.js b/app/assets/javascripts/ref/stores/mutation_types.js
index 9f6195f5f3f..c26f4fa00c7 100644
--- a/app/assets/javascripts/ref/stores/mutation_types.js
+++ b/app/assets/javascripts/ref/stores/mutation_types.js
@@ -1,3 +1,5 @@
+export const SET_ENABLED_REF_TYPES = 'SET_ENABLED_REF_TYPES';
+
export const SET_PROJECT_ID = 'SET_PROJECT_ID';
export const SET_SELECTED_REF = 'SET_SELECTED_REF';
export const SET_QUERY = 'SET_QUERY';
diff --git a/app/assets/javascripts/ref/stores/mutations.js b/app/assets/javascripts/ref/stores/mutations.js
index 4dc73dabfe2..f91cbae8462 100644
--- a/app/assets/javascripts/ref/stores/mutations.js
+++ b/app/assets/javascripts/ref/stores/mutations.js
@@ -4,6 +4,9 @@ import { X_TOTAL_HEADER } from '../constants';
import * as types from './mutation_types';
export default {
+ [types.SET_ENABLED_REF_TYPES](state, refTypes) {
+ state.enabledRefTypes = refTypes;
+ },
[types.SET_PROJECT_ID](state, projectId) {
state.projectId = projectId;
},
diff --git a/app/assets/javascripts/ref/stores/state.js b/app/assets/javascripts/ref/stores/state.js
index 65b9d6449d7..3affa8f8d03 100644
--- a/app/assets/javascripts/ref/stores/state.js
+++ b/app/assets/javascripts/ref/stores/state.js
@@ -1,23 +1,18 @@
+const createRefTypeState = () => ({
+ list: [],
+ totalCount: 0,
+ error: null,
+});
+
export default () => ({
+ enabledRefTypes: [],
projectId: null,
query: '',
matches: {
- branches: {
- list: [],
- totalCount: 0,
- error: null,
- },
- tags: {
- list: [],
- totalCount: 0,
- error: null,
- },
- commits: {
- list: [],
- totalCount: 0,
- error: null,
- },
+ branches: createRefTypeState(),
+ tags: createRefTypeState(),
+ commits: createRefTypeState(),
},
selectedRef: null,
requestCount: 0,