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-11-08 18:09:34 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-11-08 18:09:34 +0300
commitb5bdf6e5219b3b57107aee49ba7c103affb65dd9 (patch)
tree54c1ea8b3140d60af9a6c64867edc0a484ef7735 /app/assets/javascripts/search
parent81f062b841f6062601662061850934a51e77ceea (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/search')
-rw-r--r--app/assets/javascripts/search/sidebar/components/app.vue47
-rw-r--r--app/assets/javascripts/search/sidebar/components/results_filters.vue49
-rw-r--r--app/assets/javascripts/search/sidebar/components/scope_navigation.vue66
-rw-r--r--app/assets/javascripts/search/sidebar/constants/index.js11
-rw-r--r--app/assets/javascripts/search/store/actions.js18
-rw-r--r--app/assets/javascripts/search/store/index.js4
-rw-r--r--app/assets/javascripts/search/store/mutation_types.js1
-rw-r--r--app/assets/javascripts/search/store/mutations.js4
-rw-r--r--app/assets/javascripts/search/store/state.js3
9 files changed, 166 insertions, 37 deletions
diff --git a/app/assets/javascripts/search/sidebar/components/app.vue b/app/assets/javascripts/search/sidebar/components/app.vue
index 789efc8f09d..927ae6f6b81 100644
--- a/app/assets/javascripts/search/sidebar/components/app.vue
+++ b/app/assets/javascripts/search/sidebar/components/app.vue
@@ -1,48 +1,27 @@
<script>
-import { GlButton, GlLink } from '@gitlab/ui';
-import { mapActions, mapState } from 'vuex';
-import ConfidentialityFilter from './confidentiality_filter.vue';
-import StatusFilter from './status_filter.vue';
+import { mapState } from 'vuex';
+import ScopeNavigation from '~/search/sidebar/components/scope_navigation.vue';
+import { SCOPE_ISSUES, SCOPE_MERGE_REQUESTS } from '../constants';
+import ResultsFilters from './results_filters.vue';
export default {
name: 'GlobalSearchSidebar',
components: {
- GlButton,
- GlLink,
- StatusFilter,
- ConfidentialityFilter,
+ ResultsFilters,
+ ScopeNavigation,
},
computed: {
- ...mapState(['urlQuery', 'sidebarDirty']),
- showReset() {
- return this.urlQuery.state || this.urlQuery.confidential;
+ ...mapState(['urlQuery']),
+ showFilters() {
+ return this.urlQuery.scope === SCOPE_ISSUES || this.urlQuery.scope === SCOPE_MERGE_REQUESTS;
},
- showSidebar() {
- return this.urlQuery.scope === 'issues' || this.urlQuery.scope === 'merge_requests';
- },
- },
- methods: {
- ...mapActions(['applyQuery', 'resetQuery']),
},
};
</script>
<template>
- <form
- class="search-sidebar gl-display-flex gl-flex-direction-column gl-mr-4 gl-mb-6 gl-mt-5"
- @submit.prevent="applyQuery"
- >
- <template v-if="showSidebar">
- <status-filter />
- <confidentiality-filter />
- <div class="gl-display-flex gl-align-items-center gl-mt-3">
- <gl-button category="primary" variant="confirm" type="submit" :disabled="!sidebarDirty">
- {{ __('Apply') }}
- </gl-button>
- <gl-link v-if="showReset" class="gl-ml-auto" @click="resetQuery">{{
- __('Reset filters')
- }}</gl-link>
- </div>
- </template>
- </form>
+ <section class="search-sidebar gl-display-flex gl-flex-direction-column gl-mr-4 gl-mb-6 gl-mt-5">
+ <scope-navigation />
+ <results-filters v-if="showFilters" />
+ </section>
</template>
diff --git a/app/assets/javascripts/search/sidebar/components/results_filters.vue b/app/assets/javascripts/search/sidebar/components/results_filters.vue
new file mode 100644
index 00000000000..5b53f94bb53
--- /dev/null
+++ b/app/assets/javascripts/search/sidebar/components/results_filters.vue
@@ -0,0 +1,49 @@
+<script>
+import { GlButton, GlLink } from '@gitlab/ui';
+import { mapActions, mapState } from 'vuex';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import ConfidentialityFilter from './confidentiality_filter.vue';
+import StatusFilter from './status_filter.vue';
+
+export default {
+ name: 'ResultsFilters',
+ components: {
+ GlButton,
+ GlLink,
+ StatusFilter,
+ ConfidentialityFilter,
+ },
+ mixins: [glFeatureFlagsMixin()],
+ computed: {
+ ...mapState(['urlQuery', 'sidebarDirty']),
+ showReset() {
+ return this.urlQuery.state || this.urlQuery.confidential;
+ },
+ searchPageVerticalNavFeatureFlag() {
+ return this.glFeatures.searchPageVerticalNav;
+ },
+ },
+ methods: {
+ ...mapActions(['applyQuery', 'resetQuery']),
+ },
+};
+</script>
+
+<template>
+ <form
+ :class="searchPageVerticalNavFeatureFlag ? 'gl-px-5' : 'gl-px-0'"
+ @submit.prevent="applyQuery"
+ >
+ <hr v-if="searchPageVerticalNavFeatureFlag" class="gl-my-5 gl-border-gray-100" />
+ <status-filter />
+ <confidentiality-filter />
+ <div class="gl-display-flex gl-align-items-center gl-mt-4">
+ <gl-button category="primary" variant="confirm" type="submit" :disabled="!sidebarDirty">
+ {{ __('Apply') }}
+ </gl-button>
+ <gl-link v-if="showReset" class="gl-ml-auto" @click="resetQuery">{{
+ __('Reset filters')
+ }}</gl-link>
+ </div>
+ </form>
+</template>
diff --git a/app/assets/javascripts/search/sidebar/components/scope_navigation.vue b/app/assets/javascripts/search/sidebar/components/scope_navigation.vue
new file mode 100644
index 00000000000..37138955415
--- /dev/null
+++ b/app/assets/javascripts/search/sidebar/components/scope_navigation.vue
@@ -0,0 +1,66 @@
+<script>
+import { GlNav, GlNavItem } from '@gitlab/ui';
+import { mapActions, mapState } from 'vuex';
+import { formatNumber } from '~/locale';
+import Tracking from '~/tracking';
+import { NAV_LINK_DEFAULT_CLASSES, NUMBER_FORMATING_OPTIONS } from '../constants';
+
+export default {
+ name: 'ScopeNavigation',
+ components: {
+ GlNav,
+ GlNavItem,
+ },
+ mixins: [Tracking.mixin()],
+ computed: {
+ ...mapState(['navigation', 'urlQuery']),
+ },
+ created() {
+ this.fetchSidebarCount();
+ },
+ methods: {
+ ...mapActions(['fetchSidebarCount']),
+ activeClasses(currentScope) {
+ return currentScope === this.urlQuery.scope ? 'gl-font-weight-bold' : '';
+ },
+ showFormatedCount(count) {
+ if (!count) {
+ return '0';
+ }
+ const countNumber = parseInt(count.replace(/,/g, ''), 10);
+ return formatNumber(countNumber, NUMBER_FORMATING_OPTIONS);
+ },
+ handleClick(scope) {
+ this.track('click_menu_item', { label: `vertical_navigation_${scope}` });
+ },
+ linkClasses(scope) {
+ return [
+ { 'gl-font-weight-bold': scope === this.urlQuery.scope },
+ ...this.$options.NAV_LINK_DEFAULT_CLASSES,
+ ];
+ },
+ },
+ NAV_LINK_DEFAULT_CLASSES,
+};
+</script>
+
+<template>
+ <nav>
+ <gl-nav vertical pills>
+ <gl-nav-item
+ v-for="(item, scope, index) in navigation"
+ :key="scope"
+ :link-classes="linkClasses(scope)"
+ class="gl-mb-1"
+ :href="item.link"
+ :active="urlQuery.scope ? urlQuery.scope === scope : index === 0"
+ @click="handleClick(scope)"
+ ><span>{{ item.label }}</span
+ ><span v-if="item.count" class="gl-font-sm gl-font-weight-normal">
+ {{ showFormatedCount(item.count) }}
+ </span>
+ </gl-nav-item>
+ </gl-nav>
+ <hr class="gl-mt-5 gl-mb-0 gl-border-gray-100 gl-md-display-none" />
+ </nav>
+</template>
diff --git a/app/assets/javascripts/search/sidebar/constants/index.js b/app/assets/javascripts/search/sidebar/constants/index.js
new file mode 100644
index 00000000000..3621138afe4
--- /dev/null
+++ b/app/assets/javascripts/search/sidebar/constants/index.js
@@ -0,0 +1,11 @@
+export const SCOPE_ISSUES = 'issues';
+export const SCOPE_MERGE_REQUESTS = 'merge_requests';
+
+export const NUMBER_FORMATING_OPTIONS = { notation: 'compact', compactDisplay: 'short' };
+export const NAV_LINK_DEFAULT_CLASSES = [
+ 'gl-display-flex',
+ 'gl-flex-direction-row',
+ 'gl-flex-wrap-nowrap',
+ 'gl-justify-content-space-between',
+ 'gl-text-gray-900',
+];
diff --git a/app/assets/javascripts/search/store/actions.js b/app/assets/javascripts/search/store/actions.js
index be5742e5949..2a1b744561d 100644
--- a/app/assets/javascripts/search/store/actions.js
+++ b/app/assets/javascripts/search/store/actions.js
@@ -1,6 +1,8 @@
import Api from '~/api';
import { createAlert } from '~/flash';
+import axios from '~/lib/utils/axios_utils';
import { visitUrl, setUrlParams } from '~/lib/utils/url_utility';
+import { logError } from '~/lib/logger';
import { __ } from '~/locale';
import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY, SIDEBAR_PARAMS } from './constants';
import * as types from './mutation_types';
@@ -99,3 +101,19 @@ export const applyQuery = ({ state }) => {
export const resetQuery = ({ state }) => {
visitUrl(setUrlParams({ ...state.query, page: null, state: null, confidential: null }));
};
+
+export const fetchSidebarCount = ({ commit, state }) => {
+ const promises = Object.keys(state.navigation).map((scope) => {
+ // active nav item has count already so we skip it
+ if (scope !== state.urlQuery.scope) {
+ return axios
+ .get(state.navigation[scope].count_link)
+ .then(({ data: { count } }) => {
+ commit(types.RECEIVE_NAVIGATION_COUNT, { key: scope, count });
+ })
+ .catch((e) => logError(e));
+ }
+ return Promise.resolve();
+ });
+ return Promise.all(promises);
+};
diff --git a/app/assets/javascripts/search/store/index.js b/app/assets/javascripts/search/store/index.js
index 4fa88822722..e20a43808cf 100644
--- a/app/assets/javascripts/search/store/index.js
+++ b/app/assets/javascripts/search/store/index.js
@@ -7,11 +7,11 @@ import createState from './state';
Vue.use(Vuex);
-export const getStoreConfig = ({ query }) => ({
+export const getStoreConfig = ({ query, navigation }) => ({
actions,
getters,
mutations,
- state: createState({ query }),
+ state: createState({ query, navigation }),
});
const createStore = (config) => new Vuex.Store(getStoreConfig(config));
diff --git a/app/assets/javascripts/search/store/mutation_types.js b/app/assets/javascripts/search/store/mutation_types.js
index bf1e3e79cba..511b93cad2b 100644
--- a/app/assets/javascripts/search/store/mutation_types.js
+++ b/app/assets/javascripts/search/store/mutation_types.js
@@ -10,3 +10,4 @@ export const SET_QUERY = 'SET_QUERY';
export const SET_SIDEBAR_DIRTY = 'SET_SIDEBAR_DIRTY';
export const LOAD_FREQUENT_ITEMS = 'LOAD_FREQUENT_ITEMS';
+export const RECEIVE_NAVIGATION_COUNT = 'RECEIVE_NAVIGATION_COUNT';
diff --git a/app/assets/javascripts/search/store/mutations.js b/app/assets/javascripts/search/store/mutations.js
index 5d154fe3aa0..c1339845272 100644
--- a/app/assets/javascripts/search/store/mutations.js
+++ b/app/assets/javascripts/search/store/mutations.js
@@ -32,4 +32,8 @@ export default {
[types.LOAD_FREQUENT_ITEMS](state, { key, data }) {
state.frequentItems[key] = data;
},
+ [types.RECEIVE_NAVIGATION_COUNT](state, { key, count }) {
+ const item = { ...state.navigation[key], count };
+ state.navigation = { ...state.navigation, [key]: item };
+ },
};
diff --git a/app/assets/javascripts/search/store/state.js b/app/assets/javascripts/search/store/state.js
index d4005697f35..b64231a8688 100644
--- a/app/assets/javascripts/search/store/state.js
+++ b/app/assets/javascripts/search/store/state.js
@@ -1,7 +1,7 @@
import { cloneDeep } from 'lodash';
import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY } from './constants';
-const createState = ({ query }) => ({
+const createState = ({ query, navigation }) => ({
urlQuery: cloneDeep(query),
query,
groups: [],
@@ -13,5 +13,6 @@ const createState = ({ query }) => ({
[PROJECTS_LOCAL_STORAGE_KEY]: [],
},
sidebarDirty: false,
+ navigation,
});
export default createState;