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
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-07-28 18:09:45 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-07-28 18:09:45 +0300
commitd62fd6e04c272d48dccde4033529ca97c27502f6 (patch)
treee3bbea524f4bccb92048fd8a52a42b757618b57b /app
parentaaff41e10e8c03e545af9ba157e79f67686972a0 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/issues/show/components/header_actions.vue1
-rw-r--r--app/assets/javascripts/search/sidebar/components/app.vue31
-rw-r--r--app/assets/javascripts/search/sidebar/components/blobs_filters.vue18
-rw-r--r--app/assets/javascripts/search/sidebar/components/checkbox_filter.vue96
-rw-r--r--app/assets/javascripts/search/sidebar/components/confidentiality_filter/index.vue2
-rw-r--r--app/assets/javascripts/search/sidebar/components/filters_template.vue59
-rw-r--r--app/assets/javascripts/search/sidebar/components/issues_filters.vue60
-rw-r--r--app/assets/javascripts/search/sidebar/components/label_filter/index.vue7
-rw-r--r--app/assets/javascripts/search/sidebar/components/language_filter/checkbox_filter.vue4
-rw-r--r--app/assets/javascripts/search/sidebar/components/language_filter/index.vue144
-rw-r--r--app/assets/javascripts/search/sidebar/components/language_filter/tracking.js10
-rw-r--r--app/assets/javascripts/search/sidebar/components/merge_requests_filters.vue18
-rw-r--r--app/assets/javascripts/search/sidebar/components/results_filters.vue54
-rw-r--r--app/assets/javascripts/search/sidebar/components/scope_sidebar_navigation.vue2
-rw-r--r--app/assets/javascripts/search/sidebar/components/status_filter/index.vue8
-rw-r--r--app/assets/javascripts/search/store/actions.js9
-rw-r--r--app/assets/javascripts/search/store/getters.js6
-rw-r--r--app/assets/javascripts/super_sidebar/components/context_header.vue56
-rw-r--r--app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue39
-rw-r--r--app/assets/javascripts/super_sidebar/components/global_search/store/getters.js15
-rw-r--r--app/assets/javascripts/super_sidebar/components/sidebar_menu.vue9
-rw-r--r--app/assets/javascripts/super_sidebar/components/sidebar_peek_behavior.vue11
-rw-r--r--app/assets/javascripts/super_sidebar/components/super_sidebar.vue16
-rw-r--r--app/assets/javascripts/super_sidebar/components/user_bar.vue34
-rw-r--r--app/assets/stylesheets/framework/emojis.scss8
-rw-r--r--app/helpers/application_settings_helper.rb3
-rw-r--r--app/helpers/nav_helper.rb2
-rw-r--r--app/helpers/sidebars_helper.rb33
-rw-r--r--app/helpers/users/callouts_helper.rb2
29 files changed, 335 insertions, 422 deletions
diff --git a/app/assets/javascripts/issues/show/components/header_actions.vue b/app/assets/javascripts/issues/show/components/header_actions.vue
index 719f252781d..5cf0f4ad5ab 100644
--- a/app/assets/javascripts/issues/show/components/header_actions.vue
+++ b/app/assets/javascripts/issues/show/components/header_actions.vue
@@ -464,6 +464,7 @@ export default {
</template>
<gl-dropdown-item
v-if="showToggleIssueStateButton && glFeatures.moveCloseIntoDropdown"
+ data-testid="toggle-issue-state-button"
@click="toggleIssueState"
>
{{ buttonText }}
diff --git a/app/assets/javascripts/search/sidebar/components/app.vue b/app/assets/javascripts/search/sidebar/components/app.vue
index cd289be4c05..cd0976a9fd6 100644
--- a/app/assets/javascripts/search/sidebar/components/app.vue
+++ b/app/assets/javascripts/search/sidebar/components/app.vue
@@ -5,7 +5,8 @@ import ScopeSidebarNavigation from '~/search/sidebar/components/scope_sidebar_na
import SidebarPortal from '~/super_sidebar/components/sidebar_portal.vue';
import { SCOPE_ISSUES, SCOPE_MERGE_REQUESTS, SCOPE_BLOB } from '../constants';
import IssuesFilters from './issues_filters.vue';
-import LanguageFilter from './language_filter/index.vue';
+import MergeRequestsFilters from './merge_requests_filters.vue';
+import BlobsFilters from './blobs_filters.vue';
export default {
name: 'GlobalSearchSidebar',
@@ -13,25 +14,27 @@ export default {
IssuesFilters,
ScopeLegacyNavigation,
ScopeSidebarNavigation,
- LanguageFilter,
SidebarPortal,
+ MergeRequestsFilters,
+ BlobsFilters,
},
computed: {
// useSidebarNavigation refers to whether the new left sidebar navigation is enabled
...mapState(['useSidebarNavigation']),
...mapGetters(['currentScope']),
- showIssueAndMergeFilters() {
- return this.currentScope === SCOPE_ISSUES || this.currentScope === SCOPE_MERGE_REQUESTS;
+ showIssuesFilters() {
+ return this.currentScope === SCOPE_ISSUES;
},
- showBlobFilter() {
- return this.currentScope === SCOPE_BLOB;
+ showMergeRequestFilters() {
+ return this.currentScope === SCOPE_MERGE_REQUESTS;
},
- showLabelFilter() {
- return this.currentScope === SCOPE_ISSUES;
+ showBlobFilters() {
+ return this.currentScope === SCOPE_BLOB;
},
showScopeNavigation() {
// showScopeNavigation refers to whether the scope navigation should be shown
- // while the legacy navigation is being used and there are no search results the scope navigation has to be hidden
+ // while the legacy navigation is being used and there are no search results
+ // the scope navigation has to be hidden
return Boolean(this.currentScope);
},
},
@@ -42,8 +45,9 @@ export default {
<section v-if="useSidebarNavigation">
<sidebar-portal>
<scope-sidebar-navigation />
- <issues-filters v-if="showIssueAndMergeFilters" />
- <language-filter v-if="showBlobFilter" />
+ <issues-filters v-if="showIssuesFilters" />
+ <merge-requests-filters v-if="showMergeRequestFilters" />
+ <blobs-filters v-if="showBlobFilters" />
</sidebar-portal>
</section>
<section
@@ -51,7 +55,8 @@ export default {
class="search-sidebar gl-display-flex gl-flex-direction-column gl-md-mr-5 gl-mb-6 gl-mt-5"
>
<scope-legacy-navigation />
- <issues-filters v-if="showIssueAndMergeFilters" />
- <language-filter v-if="showBlobFilter" />
+ <issues-filters v-if="showIssuesFilters" />
+ <merge-requests-filters v-if="showMergeRequestFilters" />
+ <blobs-filters v-if="showBlobFilters" />
</section>
</template>
diff --git a/app/assets/javascripts/search/sidebar/components/blobs_filters.vue b/app/assets/javascripts/search/sidebar/components/blobs_filters.vue
new file mode 100644
index 00000000000..5f4d6fbd56c
--- /dev/null
+++ b/app/assets/javascripts/search/sidebar/components/blobs_filters.vue
@@ -0,0 +1,18 @@
+<script>
+import LanguageFilter from './language_filter/index.vue';
+import FiltersTemplate from './filters_template.vue';
+
+export default {
+ name: 'BlobsFilters',
+ components: {
+ LanguageFilter,
+ FiltersTemplate,
+ },
+};
+</script>
+
+<template>
+ <filters-template>
+ <language-filter class="gl-mb-5" />
+ </filters-template>
+</template>
diff --git a/app/assets/javascripts/search/sidebar/components/checkbox_filter.vue b/app/assets/javascripts/search/sidebar/components/checkbox_filter.vue
deleted file mode 100644
index bca049e56c7..00000000000
--- a/app/assets/javascripts/search/sidebar/components/checkbox_filter.vue
+++ /dev/null
@@ -1,96 +0,0 @@
-<script>
-import Vue from 'vue';
-import { GlFormCheckboxGroup, GlFormCheckbox } from '@gitlab/ui';
-import { mapState, mapActions, mapGetters } from 'vuex';
-import { intersection } from 'lodash';
-import Tracking from '~/tracking';
-import { NAV_LINK_COUNT_DEFAULT_CLASSES, LABEL_DEFAULT_CLASSES } from '../constants';
-import { formatSearchResultCount } from '../../store/utils';
-
-export const TRACKING_LABEL_SET = 'set';
-export const TRACKING_LABEL_CHECKBOX = 'checkbox';
-
-export default {
- name: 'CheckboxFilter',
- components: {
- GlFormCheckboxGroup,
- GlFormCheckbox,
- },
- props: {
- filtersData: {
- type: Object,
- required: true,
- },
- trackingNamespace: {
- type: String,
- required: true,
- },
- },
- computed: {
- ...mapState(['query', 'useSidebarNavigation']),
- ...mapGetters(['queryLanguageFilters']),
- dataFilters() {
- return Object.values(this.filtersData?.filters || []);
- },
- flatDataFilterValues() {
- return this.dataFilters.map(({ value }) => value);
- },
- selectedFilter: {
- get() {
- return intersection(this.flatDataFilterValues, this.queryLanguageFilters);
- },
- async set(value) {
- this.setQuery({ key: this.filtersData?.filterParam, value });
-
- await Vue.nextTick();
- this.trackSelectCheckbox();
- },
- },
- labelCountClasses() {
- return [...NAV_LINK_COUNT_DEFAULT_CLASSES, 'gl-text-gray-500'];
- },
- },
- methods: {
- ...mapActions(['setQuery']),
- getFormattedCount(count) {
- return formatSearchResultCount(count);
- },
- trackSelectCheckbox() {
- Tracking.event(this.trackingNamespace, TRACKING_LABEL_CHECKBOX, {
- label: TRACKING_LABEL_SET,
- property: this.selectedFilter,
- });
- },
- },
- NAV_LINK_COUNT_DEFAULT_CLASSES,
- LABEL_DEFAULT_CLASSES,
-};
-</script>
-
-<template>
- <div class="gl-mx-5">
- <h5 class="gl-mt-0" :class="{ 'gl-font-sm': useSidebarNavigation }">
- {{ filtersData.header }}
- </h5>
- <gl-form-checkbox-group v-model="selectedFilter">
- <gl-form-checkbox
- v-for="f in dataFilters"
- :key="f.label"
- :value="f.label"
- class="gl-flex-grow-1 gl-display-inline-flex gl-justify-content-space-between gl-w-full"
- :class="$options.LABEL_DEFAULT_CLASSES"
- >
- <span
- class="gl-flex-grow-1 gl-display-inline-flex gl-justify-content-space-between gl-w-full"
- >
- <span data-testid="label">
- {{ f.label }}
- </span>
- <span v-if="f.count" :class="labelCountClasses" data-testid="labelCount">
- {{ getFormattedCount(f.count) }}
- </span>
- </span>
- </gl-form-checkbox>
- </gl-form-checkbox-group>
- </div>
-</template>
diff --git a/app/assets/javascripts/search/sidebar/components/confidentiality_filter/index.vue b/app/assets/javascripts/search/sidebar/components/confidentiality_filter/index.vue
index 312092b9904..ea3a27168c8 100644
--- a/app/assets/javascripts/search/sidebar/components/confidentiality_filter/index.vue
+++ b/app/assets/javascripts/search/sidebar/components/confidentiality_filter/index.vue
@@ -1,6 +1,5 @@
<script>
import { mapState } from 'vuex';
-import { HR_DEFAULT_CLASSES } from '../../constants';
import RadioFilter from '../radio_filter.vue';
import { confidentialFilterData } from './data';
@@ -13,7 +12,6 @@ export default {
...mapState(['useSidebarNavigation']),
},
confidentialFilterData,
- HR_DEFAULT_CLASSES,
};
</script>
diff --git a/app/assets/javascripts/search/sidebar/components/filters_template.vue b/app/assets/javascripts/search/sidebar/components/filters_template.vue
new file mode 100644
index 00000000000..29c62096dcf
--- /dev/null
+++ b/app/assets/javascripts/search/sidebar/components/filters_template.vue
@@ -0,0 +1,59 @@
+<script>
+import { GlButton, GlLink, GlForm } from '@gitlab/ui';
+import { mapActions, mapState, mapGetters } from 'vuex';
+import Tracking from '~/tracking';
+
+import {
+ HR_DEFAULT_CLASSES,
+ TRACKING_ACTION_CLICK,
+ TRACKING_LABEL_APPLY,
+ TRACKING_LABEL_RESET,
+} from '../constants/index';
+
+export default {
+ name: 'FiltersTemplate',
+ components: {
+ GlButton,
+ GlLink,
+ GlForm,
+ },
+ computed: {
+ ...mapState(['sidebarDirty', 'useSidebarNavigation']),
+ ...mapGetters(['currentScope']),
+ hrClasses() {
+ return [...HR_DEFAULT_CLASSES, 'gl-display-none', 'gl-md-display-block'];
+ },
+ },
+ methods: {
+ ...mapActions(['applyQuery', 'resetQuery']),
+ applyQueryWithTracking() {
+ Tracking.event(TRACKING_ACTION_CLICK, TRACKING_LABEL_APPLY, {
+ label: this.currentScope,
+ });
+ this.applyQuery();
+ },
+ resetQueryWithTracking() {
+ Tracking.event(TRACKING_ACTION_CLICK, TRACKING_LABEL_RESET, {
+ label: this.currentScope,
+ });
+ this.resetQuery();
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-form class="issue-filters gl-px-5 gl-pt-0" @submit.prevent="applyQueryWithTracking">
+ <hr v-if="!useSidebarNavigation" :class="hrClasses" />
+ <slot></slot>
+ <hr v-if="!useSidebarNavigation" :class="hrClasses" />
+ <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="sidebarDirty" class="gl-ml-auto" @click="resetQueryWithTracking">{{
+ __('Reset filters')
+ }}</gl-link>
+ </div>
+ </gl-form>
+</template>
diff --git a/app/assets/javascripts/search/sidebar/components/issues_filters.vue b/app/assets/javascripts/search/sidebar/components/issues_filters.vue
index 5fd8b6418d7..df3fd464a2d 100644
--- a/app/assets/javascripts/search/sidebar/components/issues_filters.vue
+++ b/app/assets/javascripts/search/sidebar/components/issues_filters.vue
@@ -1,15 +1,7 @@
<script>
-import { GlButton, GlLink } from '@gitlab/ui';
-import { mapActions, mapState, mapGetters } from 'vuex';
-import Tracking from '~/tracking';
+import { mapGetters, mapState } from 'vuex';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import {
- HR_DEFAULT_CLASSES,
- TRACKING_ACTION_CLICK,
- TRACKING_LABEL_APPLY,
- TRACKING_CATEGORY,
- TRACKING_LABEL_RESET,
-} from '../constants/index';
+import { HR_DEFAULT_CLASSES } from '../constants/index';
import { confidentialFilterData } from './confidentiality_filter/data';
import { statusFilterData } from './status_filter/data';
import ConfidentialityFilter from './confidentiality_filter/index.vue';
@@ -17,22 +9,20 @@ import { labelFilterData } from './label_filter/data';
import LabelFilter from './label_filter/index.vue';
import StatusFilter from './status_filter/index.vue';
+import FiltersTemplate from './filters_template.vue';
+
export default {
name: 'IssuesFilters',
components: {
- GlButton,
- GlLink,
StatusFilter,
ConfidentialityFilter,
LabelFilter,
+ FiltersTemplate,
},
mixins: [glFeatureFlagsMixin()],
computed: {
- ...mapState(['urlQuery', 'sidebarDirty', 'useSidebarNavigation']),
...mapGetters(['currentScope']),
- showReset() {
- return this.urlQuery.state || this.urlQuery.confidential || this.urlQuery.labels;
- },
+ ...mapState(['useSidebarNavigation']),
showConfidentialityFilter() {
return Object.values(confidentialFilterData.scopes).includes(this.currentScope);
},
@@ -45,46 +35,22 @@ export default {
this.glFeatures.searchIssueLabelAggregation
);
},
+ showDivider() {
+ return !this.useSidebarNavigation;
+ },
hrClasses() {
return [...HR_DEFAULT_CLASSES, 'gl-display-none', 'gl-md-display-block'];
},
},
- methods: {
- ...mapActions(['applyQuery', 'resetQuery']),
- applyQueryWithTracking() {
- Tracking.event(TRACKING_ACTION_CLICK, TRACKING_LABEL_APPLY, {
- label: TRACKING_CATEGORY,
- });
- this.applyQuery();
- },
- resetQueryWithTracking() {
- Tracking.event(TRACKING_ACTION_CLICK, TRACKING_LABEL_RESET, {
- label: TRACKING_CATEGORY,
- });
- this.resetQuery();
- },
- },
};
</script>
<template>
- <form class="issue-filters gl-px-5 gl-pt-0" @submit.prevent="applyQueryWithTracking">
- <hr v-if="!useSidebarNavigation" :class="hrClasses" />
+ <filters-template>
<status-filter v-if="showStatusFilter" class="gl-mb-5" />
- <hr v-if="!useSidebarNavigation" :class="hrClasses" />
+ <hr v-if="showConfidentialityFilter && showDivider" :class="hrClasses" />
<confidentiality-filter v-if="showConfidentialityFilter" class="gl-mb-5" />
- <hr
- v-if="!useSidebarNavigation && showConfidentialityFilter && showLabelFilter"
- :class="hrClasses"
- />
+ <hr v-if="showLabelFilter && showDivider" :class="hrClasses" />
<label-filter v-if="showLabelFilter" />
- <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="resetQueryWithTracking">{{
- __('Reset filters')
- }}</gl-link>
- </div>
- </form>
+ </filters-template>
</template>
diff --git a/app/assets/javascripts/search/sidebar/components/label_filter/index.vue b/app/assets/javascripts/search/sidebar/components/label_filter/index.vue
index eb3556ac2cf..f14c95b41aa 100644
--- a/app/assets/javascripts/search/sidebar/components/label_filter/index.vue
+++ b/app/assets/javascripts/search/sidebar/components/label_filter/index.vue
@@ -19,8 +19,6 @@ import { sprintf } from '~/locale';
import DropdownKeyboardNavigation from '~/vue_shared/components/dropdown_keyboard_navigation.vue';
import { I18N } from '~/vue_shared/global_search/constants';
-
-import { HR_DEFAULT_CLASSES, ONLY_SHOW_MD } from '../../constants';
import LabelDropdownItems from './label_dropdown_items.vue';
import {
@@ -62,7 +60,6 @@ export default {
'filteredUnselectedLabels',
'filteredAppliedSelectedLabels',
'appliedSelectedLabels',
- 'filteredUnappliedSelectedLabels',
]),
searchInputDescribeBy() {
if (this.isLoggedIn) {
@@ -107,9 +104,6 @@ export default {
hasUnselectedLabels() {
return this.filteredUnselectedLabels.length > 0;
},
- dividerClasses() {
- return [...HR_DEFAULT_CLASSES, ...ONLY_SHOW_MD];
- },
labelSearchBox() {
return this.$refs.searchLabelInputBox?.$el.querySelector('[role=searchbox]');
},
@@ -277,6 +271,5 @@ export default {
<gl-loading-icon v-if="aggregations.fetching" size="lg" class="my-4" />
</div>
</div>
- <hr v-if="!useSidebarNavigation" :class="dividerClasses" />
</div>
</template>
diff --git a/app/assets/javascripts/search/sidebar/components/language_filter/checkbox_filter.vue b/app/assets/javascripts/search/sidebar/components/language_filter/checkbox_filter.vue
index b42fe9185cb..404cfd9a1e5 100644
--- a/app/assets/javascripts/search/sidebar/components/language_filter/checkbox_filter.vue
+++ b/app/assets/javascripts/search/sidebar/components/language_filter/checkbox_filter.vue
@@ -1,7 +1,7 @@
<script>
import Vue from 'vue';
import { GlFormCheckboxGroup, GlFormCheckbox } from '@gitlab/ui';
-import { mapState, mapActions, mapGetters } from 'vuex';
+import { mapActions, mapGetters } from 'vuex';
import { intersection } from 'lodash';
import Tracking from '~/tracking';
import { NAV_LINK_COUNT_DEFAULT_CLASSES, LABEL_DEFAULT_CLASSES } from '../../constants';
@@ -27,7 +27,6 @@ export default {
},
},
computed: {
- ...mapState(['query', 'useSidebarNavigation']),
...mapGetters(['queryLanguageFilters']),
dataFilters() {
return Object.values(this.filtersData?.filters || []);
@@ -62,7 +61,6 @@ export default {
});
},
},
- NAV_LINK_COUNT_DEFAULT_CLASSES,
LABEL_DEFAULT_CLASSES,
};
</script>
diff --git a/app/assets/javascripts/search/sidebar/components/language_filter/index.vue b/app/assets/javascripts/search/sidebar/components/language_filter/index.vue
index e5560dd5b55..b958c4d8eeb 100644
--- a/app/assets/javascripts/search/sidebar/components/language_filter/index.vue
+++ b/app/assets/javascripts/search/sidebar/components/language_filter/index.vue
@@ -1,17 +1,10 @@
<script>
-import { GlButton, GlAlert, GlForm } from '@gitlab/ui';
+import { GlButton, GlAlert } from '@gitlab/ui';
import { mapState, mapActions, mapGetters } from 'vuex';
-import { __, s__, sprintf } from '~/locale';
-import { HR_DEFAULT_CLASSES, ONLY_SHOW_MD } from '../../constants';
+import { s__, sprintf } from '~/locale';
import { convertFiltersData } from '../../utils';
import CheckboxFilter from './checkbox_filter.vue';
-import {
- trackShowMore,
- trackShowHasOverMax,
- trackSubmitQuery,
- trackResetQuery,
- TRACKING_ACTION_SELECT,
-} from './tracking';
+import { trackShowMore, trackShowHasOverMax, TRACKING_ACTION_SELECT } from './tracking';
import { DEFAULT_ITEM_LENGTH, MAX_ITEM_LENGTH, languageFilterData } from './data';
@@ -21,7 +14,6 @@ export default {
CheckboxFilter,
GlButton,
GlAlert,
- GlForm,
},
data() {
return {
@@ -30,18 +22,12 @@ export default {
},
i18n: {
showMore: s__('GlobalSearch|Show more'),
- apply: __('Apply'),
showingMax: sprintf(s__('GlobalSearch|Showing top %{maxItems}'), { maxItems: MAX_ITEM_LENGTH }),
loadError: s__('GlobalSearch|Aggregations load error.'),
- reset: s__('GlobalSearch|Reset filters'),
},
computed: {
- ...mapState(['aggregations', 'sidebarDirty', 'useSidebarNavigation']),
- ...mapGetters([
- 'languageAggregationBuckets',
- 'currentUrlQueryHasLanguageFilters',
- 'queryLanguageFilters',
- ]),
+ ...mapState(['aggregations', 'useSidebarNavigation']),
+ ...mapGetters(['languageAggregationBuckets']),
hasBuckets() {
return this.languageAggregationBuckets.length > 0;
},
@@ -63,26 +49,12 @@ export default {
hasOverMax() {
return this.languageAggregationBuckets.length > MAX_ITEM_LENGTH;
},
- dividerClassesTop() {
- return [...HR_DEFAULT_CLASSES, ...ONLY_SHOW_MD];
- },
- dividerClassesBottom() {
- return [...HR_DEFAULT_CLASSES, 'gl-mt-5'];
- },
- hasQueryFilters() {
- return this.queryLanguageFilters.length > 0;
- },
},
async created() {
await this.fetchAllAggregation();
},
methods: {
- ...mapActions([
- 'applyQuery',
- 'resetLanguageQuery',
- 'resetLanguageQueryWithRedirect',
- 'fetchAllAggregation',
- ]),
+ ...mapActions(['fetchAllAggregation']),
onShowMore() {
this.showAll = true;
trackShowMore();
@@ -91,91 +63,47 @@ export default {
trackShowHasOverMax();
}
},
- submitQuery() {
- trackSubmitQuery();
- this.applyQuery();
- },
trimBuckets(length) {
return this.languageAggregationBuckets.slice(0, length);
},
- cleanResetFilters() {
- trackResetQuery();
- if (this.currentUrlQueryHasLanguageFilters) {
- return this.resetLanguageQueryWithRedirect();
- }
- this.showAll = false;
- return this.resetLanguageQuery();
- },
},
- HR_DEFAULT_CLASSES,
TRACKING_ACTION_SELECT,
languageFilterData,
};
</script>
<template>
- <div>
- <gl-form
- v-if="hasBuckets"
- class="gl-m-5 gl-my-0 language-filter-checkbox"
- @submit.prevent="submitQuery"
+ <div v-if="hasBuckets" class="gl-my-0 language-filter-checkbox">
+ <h5 class="gl-mt-0 gl-mb-5" :class="{ 'gl-font-sm': useSidebarNavigation }">
+ {{ $options.languageFilterData.header }}
+ </h5>
+ <div
+ v-if="!aggregations.error"
+ class="gl-overflow-x-hidden gl-overflow-y-auto"
+ :class="{ 'language-filter-max-height': showAll }"
>
- <hr v-if="!useSidebarNavigation" :class="dividerClassesTop" />
- <h5 class="gl-mt-0 gl-mb-5" :class="{ 'gl-font-sm': useSidebarNavigation }">
- {{ $options.languageFilterData.header }}
- </h5>
- <div
- v-if="!aggregations.error"
- class="gl-overflow-x-hidden gl-overflow-y-auto"
- :class="{ 'language-filter-max-height': showAll }"
+ <checkbox-filter
+ :filters-data="filtersData"
+ :tracking-namespace="$options.TRACKING_ACTION_SELECT"
+ />
+ <span v-if="showAll && hasOverMax" data-testid="has-over-max-text">{{
+ $options.i18n.showingMax
+ }}</span>
+ </div>
+ <gl-alert v-else class="gl-mx-5" variant="danger" :dismissible="false">{{
+ $options.i18n.loadError
+ }}</gl-alert>
+ <div v-if="hasShowMore && !showAll" class="language-filter-show-all">
+ <gl-button
+ data-testid="show-more-button"
+ category="tertiary"
+ variant="link"
+ size="small"
+ button-text-classes="gl-font-sm"
+ @click="onShowMore"
>
- <checkbox-filter
- :filters-data="filtersData"
- :tracking-namespace="$options.TRACKING_ACTION_SELECT"
- />
- <span v-if="showAll && hasOverMax" data-testid="has-over-max-text">{{
- $options.i18n.showingMax
- }}</span>
- </div>
- <gl-alert v-else class="gl-mx-5" variant="danger" :dismissible="false">{{
- $options.i18n.loadError
- }}</gl-alert>
- <div v-if="hasShowMore && !showAll" class="gl-px-5 language-filter-show-all">
- <gl-button
- data-testid="show-more-button"
- category="tertiary"
- variant="link"
- size="small"
- button-text-classes="gl-font-sm"
- @click="onShowMore"
- >
- {{ $options.i18n.showMore }}
- </gl-button>
- </div>
- <div v-if="!aggregations.error">
- <hr v-if="!useSidebarNavigation" :class="dividerClassesBottom" />
- <div class="gl-display-flex gl-align-items-center gl-justify-content-space-between gl-mt-4">
- <gl-button
- category="primary"
- variant="confirm"
- type="submit"
- :disabled="!sidebarDirty"
- data-testid="apply-button"
- >
- {{ $options.i18n.apply }}
- </gl-button>
- <gl-button
- v-if="hasQueryFilters && sidebarDirty"
- category="tertiary"
- variant="link"
- size="small"
- data-testid="reset-button"
- @click="cleanResetFilters"
- >
- {{ $options.i18n.reset }}
- </gl-button>
- </div>
- </div>
- </gl-form>
+ {{ $options.i18n.showMore }}
+ </gl-button>
+ </div>
</div>
</template>
diff --git a/app/assets/javascripts/search/sidebar/components/language_filter/tracking.js b/app/assets/javascripts/search/sidebar/components/language_filter/tracking.js
index db107830329..5f085c7df7e 100644
--- a/app/assets/javascripts/search/sidebar/components/language_filter/tracking.js
+++ b/app/assets/javascripts/search/sidebar/components/language_filter/tracking.js
@@ -27,13 +27,3 @@ export const trackShowHasOverMax = () =>
label: TRACKING_LABEL_MAX,
property: TRACKING_PROPERTY_MAX,
});
-
-export const trackSubmitQuery = () =>
- Tracking.event(TRACKING_ACTION_CLICK, TRACKING_LABEL_APPLY, {
- label: TRACKING_CATEGORY,
- });
-
-export const trackResetQuery = () =>
- Tracking.event(TRACKING_ACTION_CLICK, TRACKING_LABEL_RESET, {
- label: TRACKING_CATEGORY,
- });
diff --git a/app/assets/javascripts/search/sidebar/components/merge_requests_filters.vue b/app/assets/javascripts/search/sidebar/components/merge_requests_filters.vue
new file mode 100644
index 00000000000..bc5b797dd56
--- /dev/null
+++ b/app/assets/javascripts/search/sidebar/components/merge_requests_filters.vue
@@ -0,0 +1,18 @@
+<script>
+import StatusFilter from './status_filter/index.vue';
+import FiltersTemplate from './filters_template.vue';
+
+export default {
+ name: 'MergeRequestsFilters',
+ components: {
+ StatusFilter,
+ FiltersTemplate,
+ },
+};
+</script>
+
+<template>
+ <filters-template>
+ <status-filter class="gl-mb-5" />
+ </filters-template>
+</template>
diff --git a/app/assets/javascripts/search/sidebar/components/results_filters.vue b/app/assets/javascripts/search/sidebar/components/results_filters.vue
deleted file mode 100644
index 88e434cf99e..00000000000
--- a/app/assets/javascripts/search/sidebar/components/results_filters.vue
+++ /dev/null
@@ -1,54 +0,0 @@
-<script>
-import { GlButton, GlLink } from '@gitlab/ui';
-import { mapActions, mapState, mapGetters } from 'vuex';
-import { HR_DEFAULT_CLASSES } from '../constants/index';
-import { confidentialFilterData } from './confidentiality_filter/data';
-import { statusFilterData } from './status_filter/data';
-import ConfidentialityFilter from './confidentiality_filter/index.vue';
-import StatusFilter from './status_filter/index.vue';
-
-export default {
- name: 'ResultsFilters',
- components: {
- GlButton,
- GlLink,
- StatusFilter,
- ConfidentialityFilter,
- },
- computed: {
- ...mapState(['urlQuery', 'sidebarDirty', 'useSidebarNavigation']),
- ...mapGetters(['currentScope']),
- showReset() {
- return this.urlQuery.state || this.urlQuery.confidential;
- },
- showConfidentialityFilter() {
- return Object.values(confidentialFilterData.scopes).includes(this.currentScope);
- },
- showStatusFilter() {
- return Object.values(statusFilterData.scopes).includes(this.currentScope);
- },
- hrClasses() {
- return [...HR_DEFAULT_CLASSES, 'gl-display-none', 'gl-md-display-block'];
- },
- },
- methods: {
- ...mapActions(['applyQuery', 'resetQuery']),
- },
-};
-</script>
-
-<template>
- <form class="gl-pt-5 gl-md-pt-0" @submit.prevent="applyQuery">
- <hr v-if="!useSidebarNavigation" :class="hrClasses" />
- <status-filter v-if="showStatusFilter" />
- <confidentiality-filter v-if="showConfidentialityFilter" />
- <div class="gl-display-flex gl-align-items-center gl-mt-4 gl-px-5">
- <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_sidebar_navigation.vue b/app/assets/javascripts/search/sidebar/components/scope_sidebar_navigation.vue
index 3707e152e47..70fad49724c 100644
--- a/app/assets/javascripts/search/sidebar/components/scope_sidebar_navigation.vue
+++ b/app/assets/javascripts/search/sidebar/components/scope_sidebar_navigation.vue
@@ -1,7 +1,6 @@
<script>
import { mapActions, mapState, mapGetters } from 'vuex';
import { s__ } from '~/locale';
-import Tracking from '~/tracking';
import NavItem from '~/super_sidebar/components/nav_item.vue';
import { NAV_LINK_DEFAULT_CLASSES, NAV_LINK_COUNT_DEFAULT_CLASSES } from '../constants';
@@ -13,7 +12,6 @@ export default {
components: {
NavItem,
},
- mixins: [Tracking.mixin()],
computed: {
...mapState(['navigation', 'urlQuery']),
...mapGetters(['navigationItems']),
diff --git a/app/assets/javascripts/search/sidebar/components/status_filter/index.vue b/app/assets/javascripts/search/sidebar/components/status_filter/index.vue
index 010cfbad590..a5f717dcf06 100644
--- a/app/assets/javascripts/search/sidebar/components/status_filter/index.vue
+++ b/app/assets/javascripts/search/sidebar/components/status_filter/index.vue
@@ -1,5 +1,4 @@
<script>
-import { mapState } from 'vuex';
import { HR_DEFAULT_CLASSES } from '../../constants';
import RadioFilter from '../radio_filter.vue';
import { statusFilterData } from './data';
@@ -9,16 +8,11 @@ export default {
components: {
RadioFilter,
},
- computed: {
- ...mapState(['useSidebarNavigation']),
- },
statusFilterData,
HR_DEFAULT_CLASSES,
};
</script>
<template>
- <div>
- <radio-filter :filter-data="$options.statusFilterData" />
- </div>
+ <radio-filter :filter-data="$options.statusFilterData" />
</template>
diff --git a/app/assets/javascripts/search/store/actions.js b/app/assets/javascripts/search/store/actions.js
index 077c46bbe22..f4928834bf3 100644
--- a/app/assets/javascripts/search/store/actions.js
+++ b/app/assets/javascripts/search/store/actions.js
@@ -4,7 +4,6 @@ import axios from '~/lib/utils/axios_utils';
import { visitUrl, setUrlParams } from '~/lib/utils/url_utility';
import { logError } from '~/lib/logger';
import { __ } from '~/locale';
-import { languageFilterData } from '~/search/sidebar/components/language_filter/data';
import { labelFilterData } from '~/search/sidebar/components/label_filter/data';
import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY, SIDEBAR_PARAMS } from './constants';
import * as types from './mutation_types';
@@ -127,14 +126,6 @@ export const setLabelFilterSearch = ({ commit }, { value }) => {
commit(types.SET_LABEL_SEARCH_STRING, value);
};
-export const resetLanguageQueryWithRedirect = ({ state }) => {
- visitUrl(setUrlParams({ ...state.query, language: null }, undefined, true));
-};
-
-export const resetLanguageQuery = ({ commit }) => {
- commit(types.SET_QUERY, { key: languageFilterData?.filterParam, value: [] });
-};
-
export const fetchSidebarCount = ({ commit, state }) => {
const promises = Object.values(state.navigation).map((navItem) => {
// active nav item has count already so we skip it
diff --git a/app/assets/javascripts/search/store/getters.js b/app/assets/javascripts/search/store/getters.js
index c7cb595f42f..6c9834d0d6c 100644
--- a/app/assets/javascripts/search/store/getters.js
+++ b/app/assets/javascripts/search/store/getters.js
@@ -1,4 +1,4 @@
-import { findKey, has } from 'lodash';
+import { findKey } from 'lodash';
import { languageFilterData } from '~/search/sidebar/components/language_filter/data';
import { labelFilterData } from '~/search/sidebar/components/label_filter/data';
import { formatSearchResultCount, addCountOverLimit } from '~/search/store/utils';
@@ -62,10 +62,6 @@ export const currentScope = (state) => findKey(state.navigation, { active: true
export const queryLanguageFilters = (state) => state.query[languageFilterData.filterParam] || [];
-export const currentUrlQueryHasLanguageFilters = (state) =>
- has(state.urlQuery, languageFilterData.filterParam) &&
- state.urlQuery[languageFilterData.filterParam]?.length > 0;
-
export const navigationItems = (state) =>
Object.values(state.navigation).map((item) => ({
title: item.label,
diff --git a/app/assets/javascripts/super_sidebar/components/context_header.vue b/app/assets/javascripts/super_sidebar/components/context_header.vue
new file mode 100644
index 00000000000..11b9840a409
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/components/context_header.vue
@@ -0,0 +1,56 @@
+<script>
+import { GlTruncate, GlAvatar, GlIcon } from '@gitlab/ui';
+
+export default {
+ components: {
+ GlTruncate,
+ GlAvatar,
+ GlIcon,
+ },
+ props: {
+ /*
+ * Contains metadata about the current view, e.g. `id`, `title` and `avatar`
+ */
+ context: {
+ type: Object,
+ required: true,
+ },
+ tag: {
+ type: String,
+ required: false,
+ default: 'div',
+ },
+ },
+ computed: {
+ avatarShape() {
+ return this.context.avatar_shape || 'rect';
+ },
+ },
+};
+</script>
+
+<template>
+ <component
+ :is="tag"
+ class="border-top border-bottom gl-border-gray-a-08! gl-display-flex gl-align-items-center gl-gap-3 gl-font-weight-bold gl-w-full gl-h-8 gl-px-4 gl-flex-shrink-0"
+ >
+ <span
+ v-if="context.icon"
+ class="gl-avatar avatar-container gl-bg-t-gray-a-08 icon-avatar rect-avatar s24"
+ >
+ <gl-icon class="gl-text-gray-700" :name="context.icon" :size="16" />
+ </span>
+ <gl-avatar
+ v-else
+ :size="24"
+ :shape="avatarShape"
+ :entity-name="context.title"
+ :entity-id="context.id"
+ :src="context.avatar"
+ />
+ <div class="gl-flex-grow-1 gl-overflow-auto gl-text-gray-900">
+ <gl-truncate :text="context.title" />
+ </div>
+ <slot name="end"></slot>
+ </component>
+</template>
diff --git a/app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue b/app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue
index 17227a2b123..f6aa2b637eb 100644
--- a/app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue
+++ b/app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue
@@ -1,11 +1,11 @@
<script>
-import { GlTruncate, GlAvatar, GlIcon } from '@gitlab/ui';
+import { GlIcon } from '@gitlab/ui';
+import ContextHeader from './context_header.vue';
export default {
components: {
- GlTruncate,
- GlAvatar,
GlIcon,
+ ContextHeader,
},
props: {
/*
@@ -24,39 +24,20 @@ export default {
collapseIcon() {
return this.expanded ? 'chevron-up' : 'chevron-down';
},
- avatarShape() {
- return this.context.avatar_shape || 'rect';
- },
},
};
</script>
<template>
- <button
+ <context-header
+ :context="context"
+ tag="button"
type="button"
- class="context-switcher-toggle gl-p-0 gl-bg-transparent gl-hover-bg-t-gray-a-08 gl-focus-bg-t-gray-a-08 gl-border-0 border-top border-bottom gl-border-gray-a-08! gl-box-shadow-none gl-display-flex gl-align-items-center gl-font-weight-bold gl-w-full gl-h-8 gl-flex-shrink-0"
+ class="context-switcher-toggle gl-p-0 gl-bg-transparent gl-hover-bg-t-gray-a-08 gl-focus-bg-t-gray-a-08 gl-border-0 gl-box-shadow-none gl-text-left"
data-qa-selector="context_switcher"
>
- <span
- v-if="context.icon"
- class="gl-avatar avatar-container gl-bg-t-gray-a-08 icon-avatar rect-avatar s24 gl-mr-3 gl-ml-4"
- >
- <gl-icon class="gl-text-gray-700" :name="context.icon" :size="16" />
- </span>
- <gl-avatar
- v-else
- :size="24"
- :shape="avatarShape"
- :entity-name="context.title"
- :entity-id="context.id"
- :src="context.avatar"
- class="gl-mr-3 gl-ml-4"
- />
- <div class="gl-overflow-auto gl-text-gray-900">
- <gl-truncate :text="context.title" />
- </div>
- <span class="gl-flex-grow-1 gl-text-right gl-mr-4">
+ <template #end>
<gl-icon class="gl-text-gray-400" :name="collapseIcon" />
- </span>
- </button>
+ </template>
+ </context-header>
</template>
diff --git a/app/assets/javascripts/super_sidebar/components/global_search/store/getters.js b/app/assets/javascripts/super_sidebar/components/global_search/store/getters.js
index 4a42f416206..89bd41ea6c4 100644
--- a/app/assets/javascripts/super_sidebar/components/global_search/store/getters.js
+++ b/app/assets/javascripts/super_sidebar/components/global_search/store/getters.js
@@ -1,6 +1,8 @@
import { omitBy, isNil } from 'lodash';
import { objectToQuery } from '~/lib/utils/url_utility';
import {
+ ISSUES_CATEGORY,
+ MERGE_REQUEST_CATEGORY,
MSG_ISSUES_ASSIGNED_TO_ME,
MSG_ISSUES_IVE_CREATED,
MSG_MR_ASSIGNED_TO_ME,
@@ -61,6 +63,19 @@ export const scopedMRPath = (state) => {
export const defaultSearchOptions = (state, getters) => {
const userName = gon.current_username;
+ if (!userName) {
+ return [
+ {
+ text: ISSUES_CATEGORY,
+ href: getters.scopedIssuesPath,
+ },
+ {
+ text: MERGE_REQUEST_CATEGORY,
+ href: getters.scopedMRPath,
+ },
+ ];
+ }
+
const issues = [
{
text: MSG_ISSUES_ASSIGNED_TO_ME,
diff --git a/app/assets/javascripts/super_sidebar/components/sidebar_menu.vue b/app/assets/javascripts/super_sidebar/components/sidebar_menu.vue
index 86fe5c9ad5c..821b9dbcb7b 100644
--- a/app/assets/javascripts/super_sidebar/components/sidebar_menu.vue
+++ b/app/assets/javascripts/super_sidebar/components/sidebar_menu.vue
@@ -30,6 +30,10 @@ export default {
type: Array,
required: true,
},
+ isLoggedIn: {
+ type: Boolean,
+ required: true,
+ },
pinnedItemIds: {
type: Array,
required: false,
@@ -42,7 +46,8 @@ export default {
},
updatePinsUrl: {
type: String,
- required: true,
+ required: false,
+ default: '',
},
},
@@ -97,7 +102,7 @@ export default {
.filter(Boolean);
},
supportsPins() {
- return PANELS_WITH_PINS.includes(this.panelType);
+ return this.isLoggedIn && PANELS_WITH_PINS.includes(this.panelType);
},
hasStaticItems() {
return this.staticItems.length > 0;
diff --git a/app/assets/javascripts/super_sidebar/components/sidebar_peek_behavior.vue b/app/assets/javascripts/super_sidebar/components/sidebar_peek_behavior.vue
index 6058ed3a1cd..ec728b4af9e 100644
--- a/app/assets/javascripts/super_sidebar/components/sidebar_peek_behavior.vue
+++ b/app/assets/javascripts/super_sidebar/components/sidebar_peek_behavior.vue
@@ -11,6 +11,12 @@ export const STATE_WILL_CLOSE = 'will-close';
export default {
name: 'SidebarPeek',
mixins: [Tracking.mixin()],
+ props: {
+ isMouseOverSidebar: {
+ type: Boolean,
+ required: true,
+ },
+ },
created() {
// Nothing needs to observe these properties, so they are not reactive.
this.state = null;
@@ -57,6 +63,11 @@ export default {
this.close();
}
} else if (this.state === STATE_OPEN) {
+ // Do not close the sidebar if it or one of its child elements still
+ // has mouseover. This allows to move the mouse from the sidebar to
+ // one of its flyout menus.
+ if (this.isMouseOverSidebar) return;
+
if (clientX >= this.xAwayFromSidebar) {
this.close();
} else if (clientX >= this.xSidebarEdge) {
diff --git a/app/assets/javascripts/super_sidebar/components/super_sidebar.vue b/app/assets/javascripts/super_sidebar/components/super_sidebar.vue
index c194401ce95..dd07d2f21e0 100644
--- a/app/assets/javascripts/super_sidebar/components/super_sidebar.vue
+++ b/app/assets/javascripts/super_sidebar/components/super_sidebar.vue
@@ -8,6 +8,7 @@ import { sidebarState } from '../constants';
import { isCollapsed, toggleSuperSidebarCollapsed } from '../super_sidebar_collapsed_state_manager';
import UserBar from './user_bar.vue';
import SidebarPortalTarget from './sidebar_portal_target.vue';
+import ContextHeader from './context_header.vue';
import ContextSwitcher from './context_switcher.vue';
import HelpCenter from './help_center.vue';
import SidebarMenu from './sidebar_menu.vue';
@@ -17,6 +18,7 @@ export default {
components: {
GlButton,
UserBar,
+ ContextHeader,
ContextSwitcher,
HelpCenter,
SidebarMenu,
@@ -42,6 +44,7 @@ export default {
return {
sidebarState,
showPeekHint: false,
+ isMouseover: false,
};
},
computed: {
@@ -57,7 +60,7 @@ export default {
},
watch: {
'sidebarState.isCollapsed': function isCollapsedWatcher(newIsCollapsed) {
- if (newIsCollapsed) {
+ if (newIsCollapsed && this.$refs['context-switcher']) {
this.$refs['context-switcher'].close();
}
},
@@ -118,6 +121,8 @@ export default {
data-testid="super-sidebar"
data-qa-selector="navbar"
:inert="sidebarState.isCollapsed"
+ @mouseenter="isMouseover = true"
+ @mouseleave="isMouseover = false"
>
<user-bar :has-collapse-button="!sidebarState.isPeek" :sidebar-data="sidebarData" />
<div v-if="showTrialStatusWidget" class="gl-px-2 gl-py-2">
@@ -133,6 +138,7 @@ export default {
data-testid="nav-container"
>
<context-switcher
+ v-if="sidebarData.is_logged_in"
ref="context-switcher"
:persistent-links="sidebarData.context_switcher_links"
:username="sidebarData.username"
@@ -142,9 +148,11 @@ export default {
:context-header="sidebarData.current_context_header"
@toggle="onContextSwitcherToggled"
/>
+ <context-header v-else :context="sidebarData.current_context_header" />
<sidebar-menu
v-if="menuItems.length"
:items="menuItems"
+ :is-logged-in="sidebarData.is_logged_in"
:panel-type="sidebarData.panel_type"
:pinned-item-ids="sidebarData.pinned_items"
:update-pins-url="sidebarData.update_pins_url"
@@ -170,6 +178,10 @@ export default {
Only mount SidebarPeekBehavior if the sidebar is peekable, to avoid
setting up event listeners unnecessarily.
-->
- <sidebar-peek-behavior v-if="sidebarState.isPeekable" @change="onPeekChange" />
+ <sidebar-peek-behavior
+ v-if="sidebarState.isPeekable"
+ :is-mouse-over-sidebar="isMouseover"
+ @change="onPeekChange"
+ />
</div>
</template>
diff --git a/app/assets/javascripts/super_sidebar/components/user_bar.vue b/app/assets/javascripts/super_sidebar/components/user_bar.vue
index a882df057fa..0188585df40 100644
--- a/app/assets/javascripts/super_sidebar/components/user_bar.vue
+++ b/app/assets/javascripts/super_sidebar/components/user_bar.vue
@@ -105,17 +105,20 @@ export default {
<template>
<div class="user-bar">
<div class="gl-display-flex gl-align-items-center gl-px-3 gl-py-2">
- <brand-logo :logo-url="sidebarData.logo_url" />
- <gl-badge
- v-if="sidebarData.gitlab_com_and_canary"
- variant="success"
- :href="sidebarData.canary_toggle_com_url"
- size="sm"
- class="gl-ml-2"
- >
- {{ $options.NEXT_LABEL }}
- </gl-badge>
- <div class="gl-flex-grow-1"></div>
+ <template v-if="sidebarData.is_logged_in">
+ <brand-logo :logo-url="sidebarData.logo_url" />
+ <gl-badge
+ v-if="sidebarData.gitlab_com_and_canary"
+ variant="success"
+ :href="sidebarData.canary_toggle_com_url"
+ size="sm"
+ class="gl-ml-2"
+ >
+ {{ $options.NEXT_LABEL }}
+ </gl-badge>
+ <div class="gl-flex-grow-1"></div>
+ </template>
+
<super-sidebar-toggle
v-if="hasCollapseButton"
:class="$options.JS_TOGGLE_COLLAPSE_CLASS"
@@ -123,7 +126,7 @@ export default {
tooltip-container="super-sidebar"
data-testid="super-sidebar-collapse-button"
/>
- <create-menu :groups="sidebarData.create_new_menu_groups" />
+ <create-menu v-if="sidebarData.is_logged_in" :groups="sidebarData.create_new_menu_groups" />
<gl-button
id="super-sidebar-search"
@@ -136,7 +139,7 @@ export default {
/>
<search-modal @shown="hideSearchTooltip" @hidden="showSearchTooltip" />
- <user-menu :data="sidebarData" />
+ <user-menu v-if="sidebarData.is_logged_in" :data="sidebarData" />
<gl-button
v-if="isImpersonating"
@@ -151,7 +154,10 @@ export default {
data-testid="stop-impersonation-btn"
/>
</div>
- <div class="gl-display-flex gl-justify-content-space-between gl-px-3 gl-py-2 gl-gap-2">
+ <div
+ v-if="sidebarData.is_logged_in"
+ class="gl-display-flex gl-justify-content-space-between gl-px-3 gl-py-2 gl-gap-2"
+ >
<counter
v-gl-tooltip:super-sidebar.hover.bottom="$options.i18n.issues"
class="gl-flex-basis-third dashboard-shortcuts-issues"
diff --git a/app/assets/stylesheets/framework/emojis.scss b/app/assets/stylesheets/framework/emojis.scss
index 358f599e0e9..3b0cacb2350 100644
--- a/app/assets/stylesheets/framework/emojis.scss
+++ b/app/assets/stylesheets/framework/emojis.scss
@@ -45,6 +45,14 @@ gl-emoji {
.emoji-picker-category-tab {
border-bottom-color: transparent;
+
+ &:hover {
+ @include gl-text-gray-900;
+
+ &:not(.emoji-picker-category-active) {
+ @include gl-border-b-gray-200;
+ }
+ }
}
.emoji-picker-category-active {
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index fd699737b63..6af81e2fa06 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -499,7 +499,8 @@ module ApplicationSettingsHelper
:gitlab_dedicated_instance,
:ci_max_includes,
:allow_account_deletion,
- :gitlab_shell_operation_limit
+ :gitlab_shell_operation_limit,
+ :namespace_aggregation_schedule_lease_duration_in_seconds
].tap do |settings|
next if Gitlab.com?
diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb
index c7864c1d45f..4cbd5029ac9 100644
--- a/app/helpers/nav_helper.rb
+++ b/app/helpers/nav_helper.rb
@@ -90,7 +90,7 @@ module NavHelper
# The new sidebar is not enabled for anonymous use
# Once we enable the new sidebar by default, this
# should return true
- return false unless user
+ return Feature.enabled?(:super_sidebar_logged_out) unless user
# Users who got the special `super_sidebar_nav_enrolled` enabled,
# see the new nav as long as they don't explicitly opt-out via the toggle
diff --git a/app/helpers/sidebars_helper.rb b/app/helpers/sidebars_helper.rb
index 90917cb96e0..0329a3e136b 100644
--- a/app/helpers/sidebars_helper.rb
+++ b/app/helpers/sidebars_helper.rb
@@ -45,9 +45,31 @@ module SidebarsHelper
end
def super_sidebar_context(user, group:, project:, panel:, panel_type:) # rubocop:disable Metrics/AbcSize
+ return super_sidebar_logged_out_context(panel: panel, panel_type: panel_type) unless user
+
+ super_sidebar_logged_in_context(user, group: group, project: project, panel: panel, panel_type: panel_type)
+ end
+
+ def super_sidebar_logged_out_context(panel:, panel_type:) # rubocop:disable Metrics/AbcSize
{
+ is_logged_in: false,
current_menu_items: panel.super_sidebar_menu_items,
current_context_header: panel.super_sidebar_context_header,
+ support_path: support_url,
+ display_whats_new: display_whats_new?,
+ whats_new_most_recent_release_items_count: whats_new_most_recent_release_items_count,
+ whats_new_version_digest: whats_new_version_digest,
+ show_version_check: show_version_check?,
+ gitlab_version: Gitlab.version_info,
+ gitlab_version_check: gitlab_version_check,
+ search: search_data,
+ panel_type: panel_type
+ }
+ end
+
+ def super_sidebar_logged_in_context(user, group:, project:, panel:, panel_type:) # rubocop:disable Metrics/AbcSize
+ super_sidebar_logged_out_context(panel: panel, panel_type: panel_type).merge({
+ is_logged_in: true,
name: user.name,
username: user.username,
avatar_url: user.avatar_url,
@@ -75,26 +97,17 @@ module SidebarsHelper
merge_request_menu: create_merge_request_menu(user),
projects_path: dashboard_projects_path,
groups_path: dashboard_groups_path,
- support_path: support_url,
- display_whats_new: display_whats_new?,
- whats_new_most_recent_release_items_count: whats_new_most_recent_release_items_count,
- whats_new_version_digest: whats_new_version_digest,
- show_version_check: show_version_check?,
- gitlab_version: Gitlab.version_info,
- gitlab_version_check: gitlab_version_check,
gitlab_com_but_not_canary: Gitlab.com_but_not_canary?,
gitlab_com_and_canary: Gitlab.com_and_canary?,
canary_toggle_com_url: Gitlab::Saas.canary_toggle_com_url,
current_context: super_sidebar_current_context(project: project, group: group),
context_switcher_links: context_switcher_links,
- search: search_data,
pinned_items: user.pinned_nav_items[panel_type] || super_sidebar_default_pins(panel_type),
- panel_type: panel_type,
update_pins_url: pins_url,
is_impersonating: impersonating?,
stop_impersonation_path: admin_impersonation_path,
shortcut_links: shortcut_links(user, project: project)
- }
+ })
end
def super_sidebar_nav_panel(
diff --git a/app/helpers/users/callouts_helper.rb b/app/helpers/users/callouts_helper.rb
index 0f4cbd6642b..12f78d9bd16 100644
--- a/app/helpers/users/callouts_helper.rb
+++ b/app/helpers/users/callouts_helper.rb
@@ -89,6 +89,8 @@ module Users
end
def gitlab_com_user_created_after_new_nav_rollout?
+ return true unless current_user
+
Gitlab.com? && current_user.created_at >= Date.new(2023, 6, 2)
end