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>2023-04-19 15:15:59 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-04-19 15:15:59 +0300
commit2017bc90a671eac669f0114b6ef508e151409c4f (patch)
tree79bbbedede417d3ce13ae2e13dd1ad3bb069c975 /app/assets/javascripts
parent9450a63064cd1572f030628dbf155f5c047f28c7 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts')
-rw-r--r--app/assets/javascripts/admin/users/components/user_actions.vue19
-rw-r--r--app/assets/javascripts/admin/users/components/users_table.vue2
-rw-r--r--app/assets/javascripts/diffs/components/diff_view.vue12
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipeline_operations.vue22
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipelines_manual_actions_legacy.vue112
-rw-r--r--app/assets/javascripts/search/sidebar/components/app.vue14
-rw-r--r--app/assets/javascripts/search/sidebar/components/scope_navigation.vue10
-rw-r--r--app/assets/javascripts/search/sidebar/components/scope_new_navigation.vue40
-rw-r--r--app/assets/javascripts/search/sidebar/constants/index.js2
-rw-r--r--app/assets/javascripts/super_sidebar/components/create_menu.vue29
-rw-r--r--app/assets/javascripts/super_sidebar/components/help_center.vue16
-rw-r--r--app/assets/javascripts/super_sidebar/components/nav_item.vue2
-rw-r--r--app/assets/javascripts/super_sidebar/components/pinned_section.vue2
-rw-r--r--app/assets/javascripts/super_sidebar/components/user_menu.vue17
-rw-r--r--app/assets/javascripts/super_sidebar/constants.js2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue53
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/header.vue7
17 files changed, 183 insertions, 178 deletions
diff --git a/app/assets/javascripts/admin/users/components/user_actions.vue b/app/assets/javascripts/admin/users/components/user_actions.vue
index e21bb58cb4e..38c7d3f9b90 100644
--- a/app/assets/javascripts/admin/users/components/user_actions.vue
+++ b/app/assets/javascripts/admin/users/components/user_actions.vue
@@ -61,6 +61,9 @@ export default {
hasEditAction() {
return this.userActions.includes('edit');
},
+ hasEditActionOnly() {
+ return this.hasEditAction === true && this.hasDeleteActions === false;
+ },
userPaths() {
return generateUserPaths(this.paths, this.user.username);
},
@@ -91,10 +94,13 @@ export default {
class="gl-display-flex gl-justify-content-end gl-my-n2 gl-mx-n2"
:data-testid="`user-actions-${user.id}`"
>
- <div v-if="hasEditAction" class="gl-p-2">
- <gl-button v-if="showButtonLabels" v-bind="editButtonAttrs" icon="pencil-square">{{
- $options.i18n.edit
- }}</gl-button>
+ <div v-if="hasEditAction" class="gl-p-2" :class="{ 'gl-mr-3': hasEditActionOnly }">
+ <gl-button
+ v-if="showButtonLabels"
+ v-bind="editButtonAttrs"
+ :class="{ 'gl-mr-7': hasEditActionOnly }"
+ >{{ $options.i18n.edit }}</gl-button
+ >
<gl-button
v-else
v-gl-tooltip="$options.i18n.edit"
@@ -106,11 +112,14 @@ export default {
<div v-if="hasDropdownActions" class="gl-p-2">
<gl-disclosure-dropdown
+ icon="ellipsis_v"
+ category="tertiary"
:toggle-text="$options.i18n.userAdministration"
+ text-sr-only
data-testid="dropdown-toggle"
data-qa-selector="user_actions_dropdown_toggle"
:data-qa-username="user.username"
- placement="left"
+ no-caret
>
<template v-for="action in dropdownSafeActions">
<component
diff --git a/app/assets/javascripts/admin/users/components/users_table.vue b/app/assets/javascripts/admin/users/components/users_table.vue
index e55622d40ba..2d2c598f953 100644
--- a/app/assets/javascripts/admin/users/components/users_table.vue
+++ b/app/assets/javascripts/admin/users/components/users_table.vue
@@ -135,7 +135,7 @@ export default {
</template>
<template #cell(settings)="{ item: user }">
- <user-actions :user="user" :paths="paths" />
+ <user-actions :user="user" :paths="paths" :show-button-labels="true" />
</template>
</gl-table>
</div>
diff --git a/app/assets/javascripts/diffs/components/diff_view.vue b/app/assets/javascripts/diffs/components/diff_view.vue
index a2e052e0f93..348d6d1d78d 100644
--- a/app/assets/javascripts/diffs/components/diff_view.vue
+++ b/app/assets/javascripts/diffs/components/diff_view.vue
@@ -1,7 +1,6 @@
<script>
import { mapGetters, mapState, mapActions } from 'vuex';
import { IdState } from 'vendor/vue-virtual-scroller';
-import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import DraftNote from '~/batch_comments/components/draft_note.vue';
import draftCommentsMixin from '~/diffs/mixins/draft_comments';
import { getCommentedLines } from '~/notes/components/multiline_comment_utils';
@@ -21,11 +20,7 @@ export default {
DiffCommentCell,
DraftNote,
},
- mixins: [
- draftCommentsMixin,
- IdState({ idProp: (vm) => vm.diffFile.file_hash }),
- glFeatureFlagsMixin(),
- ],
+ mixins: [draftCommentsMixin, IdState({ idProp: (vm) => vm.diffFile.file_hash })],
props: {
diffFile: {
type: Object,
@@ -265,10 +260,7 @@ export default {
@stopdragging="onStopDragging"
/>
<diff-line
- v-if="
- glFeatures.refactorCodeQualityInlineFindings &&
- codeQualityExpandedLines.includes(getCodeQualityLine(line))
- "
+ v-if="codeQualityExpandedLines.includes(getCodeQualityLine(line))"
:key="line.line_code"
:line="line"
@hideCodeQualityFindings="hideCodeQualityFindings"
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_operations.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_operations.vue
index ffb8c0eb88c..caeee7edefe 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_operations.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_operations.vue
@@ -1,12 +1,10 @@
<script>
import { GlButton, GlTooltipDirective, GlModalDirective } from '@gitlab/ui';
import Tracking from '~/tracking';
-import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import eventHub from '../../event_hub';
import { BUTTON_TOOLTIP_RETRY, BUTTON_TOOLTIP_CANCEL, TRACKING_CATEGORIES } from '../../constants';
import PipelineMultiActions from './pipeline_multi_actions.vue';
import PipelinesManualActions from './pipelines_manual_actions.vue';
-import PipelinesManualActionsLegacy from './pipelines_manual_actions_legacy.vue';
export default {
BUTTON_TOOLTIP_RETRY,
@@ -19,9 +17,8 @@ export default {
GlButton,
PipelineMultiActions,
PipelinesManualActions,
- PipelinesManualActionsLegacy,
},
- mixins: [Tracking.mixin(), glFeatureFlagsMixin()],
+ mixins: [Tracking.mixin()],
props: {
pipeline: {
type: Object,
@@ -39,21 +36,11 @@ export default {
};
},
computed: {
- shouldLazyLoadActions() {
- return this.glFeatures.lazyLoadPipelineDropdownActions;
- },
hasActions() {
return (
this.pipeline?.details?.has_manual_actions || this.pipeline?.details?.has_scheduled_actions
);
},
- actions() {
- if (!this.pipeline || !this.pipeline.details) {
- return [];
- }
- const { details } = this.pipeline;
- return [...(details.manual_actions || []), ...(details.scheduled_actions || [])];
- },
isCancelling() {
return this.cancelingPipeline === this.pipeline.id;
},
@@ -86,12 +73,7 @@ export default {
<template>
<div class="gl-text-right">
<div class="btn-group">
- <pipelines-manual-actions v-if="hasActions && shouldLazyLoadActions" :iid="pipeline.iid" />
-
- <pipelines-manual-actions-legacy
- v-if="actions.length > 0 && !shouldLazyLoadActions"
- :actions="actions"
- />
+ <pipelines-manual-actions v-if="hasActions" :iid="pipeline.iid" />
<gl-button
v-if="pipeline.flags.retryable"
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_manual_actions_legacy.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_manual_actions_legacy.vue
deleted file mode 100644
index b08eb4153ce..00000000000
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_manual_actions_legacy.vue
+++ /dev/null
@@ -1,112 +0,0 @@
-<script>
-import { GlDropdown, GlDropdownItem, GlIcon, GlTooltipDirective } from '@gitlab/ui';
-import { createAlert } from '~/alert';
-import axios from '~/lib/utils/axios_utils';
-import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
-import { s__, __, sprintf } from '~/locale';
-import Tracking from '~/tracking';
-import GlCountdown from '~/vue_shared/components/gl_countdown.vue';
-import eventHub from '../../event_hub';
-import { TRACKING_CATEGORIES } from '../../constants';
-
-export default {
- name: 'PipelinesManualActionsLegacy',
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- components: {
- GlCountdown,
- GlDropdown,
- GlDropdownItem,
- GlIcon,
- },
- mixins: [Tracking.mixin()],
- props: {
- actions: {
- type: Array,
- required: true,
- },
- },
- data() {
- return {
- isLoading: false,
- };
- },
- methods: {
- async onClickAction(action) {
- if (action.scheduled_at) {
- const confirmationMessage = sprintf(
- s__(
- 'DelayedJobs|Are you sure you want to run %{jobName} immediately? Otherwise this job will run automatically after its timer finishes.',
- ),
- { jobName: action.name },
- );
-
- const confirmed = await confirmAction(confirmationMessage);
-
- if (!confirmed) {
- return;
- }
- }
-
- this.isLoading = true;
-
- /**
- * Ideally, the component would not make an api call directly.
- * However, in order to use the eventhub and know when to
- * toggle back the `isLoading` property we'd need an ID
- * to track the request with a wacther - since this component
- * is rendered at least 20 times in the same page, moving the
- * api call directly here is the most performant solution
- */
- axios
- .post(`${action.path}.json`)
- .then(() => {
- this.isLoading = false;
- eventHub.$emit('updateTable');
- })
- .catch(() => {
- this.isLoading = false;
- createAlert({ message: __('An error occurred while making the request.') });
- });
- },
- isActionDisabled(action) {
- if (action.playable === undefined) {
- return false;
- }
-
- return !action.playable;
- },
- trackClick() {
- this.track('click_manual_actions', { label: TRACKING_CATEGORIES.table });
- },
- },
-};
-</script>
-<template>
- <gl-dropdown
- v-gl-tooltip
- :title="__('Run manual or delayed jobs')"
- :loading="isLoading"
- data-testid="pipelines-manual-actions-dropdown"
- right
- lazy
- icon="play"
- @shown="trackClick"
- >
- <gl-dropdown-item
- v-for="action in actions"
- :key="action.path"
- :disabled="isActionDisabled(action)"
- @click="onClickAction(action)"
- >
- <div class="gl-display-flex gl-justify-content-space-between gl-flex-wrap">
- {{ action.name }}
- <span v-if="action.scheduled_at">
- <gl-icon name="clock" />
- <gl-countdown :end-date-string="action.scheduled_at" />
- </span>
- </div>
- </gl-dropdown-item>
- </gl-dropdown>
-</template>
diff --git a/app/assets/javascripts/search/sidebar/components/app.vue b/app/assets/javascripts/search/sidebar/components/app.vue
index ca5a9b70b34..81a57e96b3c 100644
--- a/app/assets/javascripts/search/sidebar/components/app.vue
+++ b/app/assets/javascripts/search/sidebar/components/app.vue
@@ -1,6 +1,8 @@
<script>
import { mapState, mapGetters } from 'vuex';
import ScopeNavigation from '~/search/sidebar/components/scope_navigation.vue';
+import ScopeNewNavigation from '~/search/sidebar/components/scope_new_navigation.vue';
+import SidebarPortal from '~/super_sidebar/components/sidebar_portal.vue';
import { SCOPE_ISSUES, SCOPE_MERGE_REQUESTS, SCOPE_BLOB } from '../constants';
import ResultsFilters from './results_filters.vue';
import LanguageFilter from './language_filter/index.vue';
@@ -10,10 +12,12 @@ export default {
components: {
ResultsFilters,
ScopeNavigation,
+ ScopeNewNavigation,
LanguageFilter,
+ SidebarPortal,
},
computed: {
- ...mapState(['urlQuery']),
+ ...mapState(['urlQuery', 'useNewNavigation']),
...mapGetters(['currentScope']),
showIssueAndMergeFilters() {
return this.currentScope === SCOPE_ISSUES || this.currentScope === SCOPE_MERGE_REQUESTS;
@@ -26,7 +30,15 @@ export default {
</script>
<template>
+ <section v-if="useNewNavigation">
+ <sidebar-portal>
+ <scope-new-navigation />
+ <results-filters v-if="showIssueAndMergeFilters" />
+ <language-filter v-if="showBlobFilter" />
+ </sidebar-portal>
+ </section>
<section
+ v-else
class="search-sidebar gl-display-flex gl-flex-direction-column gl-md-mr-5 gl-mb-6 gl-mt-5"
>
<scope-navigation />
diff --git a/app/assets/javascripts/search/sidebar/components/scope_navigation.vue b/app/assets/javascripts/search/sidebar/components/scope_navigation.vue
index 1c81f652387..fc41baee831 100644
--- a/app/assets/javascripts/search/sidebar/components/scope_navigation.vue
+++ b/app/assets/javascripts/search/sidebar/components/scope_navigation.vue
@@ -3,8 +3,8 @@ import { GlNav, GlNavItem, GlIcon } from '@gitlab/ui';
import { mapActions, mapState } from 'vuex';
import { s__ } from '~/locale';
import Tracking from '~/tracking';
+import { formatSearchResultCount, addCountOverLimit } from '~/search/store/utils';
import { NAV_LINK_DEFAULT_CLASSES, NAV_LINK_COUNT_DEFAULT_CLASSES } from '../constants';
-import { formatSearchResultCount } from '../../store/utils';
import { slugifyWithUnderscore } from '../../../lib/utils/text_utility';
export default {
@@ -28,11 +28,11 @@ export default {
},
methods: {
...mapActions(['fetchSidebarCount']),
- showFormatedCount(count) {
- return formatSearchResultCount(count);
+ showFormatedCount(countString) {
+ return formatSearchResultCount(countString);
},
- isCountOverLimit(count) {
- return count.includes('+');
+ isCountOverLimit(countString) {
+ return Boolean(addCountOverLimit(countString));
},
handleClick(scope) {
this.track('click_menu_item', { label: `vertical_navigation_${scope}` });
diff --git a/app/assets/javascripts/search/sidebar/components/scope_new_navigation.vue b/app/assets/javascripts/search/sidebar/components/scope_new_navigation.vue
new file mode 100644
index 00000000000..86b7cc577a6
--- /dev/null
+++ b/app/assets/javascripts/search/sidebar/components/scope_new_navigation.vue
@@ -0,0 +1,40 @@
+<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';
+
+export default {
+ name: 'ScopeNewNavigation',
+ i18n: {
+ countOverLimitLabel: s__('GlobalSearch|Result count is over limit.'),
+ },
+ components: {
+ NavItem,
+ },
+ mixins: [Tracking.mixin()],
+ computed: {
+ ...mapState(['navigation', 'urlQuery']),
+ ...mapGetters(['navigationItems']),
+ },
+ created() {
+ if (this.urlQuery?.search) {
+ this.fetchSidebarCount();
+ }
+ },
+ methods: {
+ ...mapActions(['fetchSidebarCount']),
+ },
+ NAV_LINK_DEFAULT_CLASSES,
+ NAV_LINK_COUNT_DEFAULT_CLASSES,
+};
+</script>
+
+<template>
+ <nav data-testid="search-filter" class="gl-py-2 gl-relative">
+ <ul class="gl-px-2 gl-list-style-none">
+ <nav-item v-for="item in navigationItems" :key="`menu-${item.title}`" :item="item" />
+ </ul>
+ </nav>
+</template>
diff --git a/app/assets/javascripts/search/sidebar/constants/index.js b/app/assets/javascripts/search/sidebar/constants/index.js
index 9cd366a87fd..9519154a571 100644
--- a/app/assets/javascripts/search/sidebar/constants/index.js
+++ b/app/assets/javascripts/search/sidebar/constants/index.js
@@ -12,7 +12,7 @@ export const NAV_LINK_DEFAULT_CLASSES = [
'gl-justify-content-space-between',
];
export const NAV_LINK_COUNT_DEFAULT_CLASSES = ['gl-font-sm', 'gl-font-weight-normal'];
-export const HR_DEFAULT_CLASSES = ['gl-m-5', 'gl-border-gray-100'];
+export const HR_DEFAULT_CLASSES = ['gl-my-5', 'gl-mx-5', 'gl-border-gray-100'];
export const ONLY_SHOW_MD = ['gl-display-none', 'gl-md-display-block'];
export const TRACKING_LABEL_CHECKBOX = 'Checkbox';
diff --git a/app/assets/javascripts/super_sidebar/components/create_menu.vue b/app/assets/javascripts/super_sidebar/components/create_menu.vue
index d3bb31a69fa..4cff4642cf7 100644
--- a/app/assets/javascripts/super_sidebar/components/create_menu.vue
+++ b/app/assets/javascripts/super_sidebar/components/create_menu.vue
@@ -1,6 +1,10 @@
<script>
import { GlDisclosureDropdown, GlTooltip } from '@gitlab/ui';
import { __ } from '~/locale';
+import { DROPDOWN_Y_OFFSET } from '../constants';
+
+// Left offset required for the dropdown to be aligned with the super sidebar
+const DROPDOWN_X_OFFSET = -147;
export default {
components: {
@@ -16,7 +20,22 @@ export default {
required: true,
},
},
+ data() {
+ return {
+ dropdownOpen: false,
+ };
+ },
toggleId: 'create-menu-toggle',
+ popperOptions: {
+ modifiers: [
+ {
+ name: 'offset',
+ options: {
+ offset: [DROPDOWN_X_OFFSET, DROPDOWN_Y_OFFSET],
+ },
+ },
+ ],
+ },
};
</script>
@@ -30,9 +49,17 @@ export default {
text-sr-only
:toggle-text="$options.i18n.createNew"
:toggle-id="$options.toggleId"
+ :popper-options="$options.popperOptions"
data-qa-selector="new_menu_toggle"
+ @shown="dropdownOpen = true"
+ @hidden="dropdownOpen = false"
/>
- <gl-tooltip :target="`#${$options.toggleId}`" placement="bottom" container="#super-sidebar">
+ <gl-tooltip
+ v-if="!dropdownOpen"
+ :target="`#${$options.toggleId}`"
+ placement="bottom"
+ container="#super-sidebar"
+ >
{{ $options.i18n.createNew }}
</gl-tooltip>
</div>
diff --git a/app/assets/javascripts/super_sidebar/components/help_center.vue b/app/assets/javascripts/super_sidebar/components/help_center.vue
index 32836ecb4e6..01b214f4b2b 100644
--- a/app/assets/javascripts/super_sidebar/components/help_center.vue
+++ b/app/assets/javascripts/super_sidebar/components/help_center.vue
@@ -6,7 +6,10 @@ import { PROMO_URL } from 'jh_else_ce/lib/utils/url_utility';
import { __ } from '~/locale';
import { STORAGE_KEY } from '~/whats_new/utils/notification';
import Tracking from '~/tracking';
-import { HELP_MENU_TRACKING_DEFAULTS } from '../constants';
+import { DROPDOWN_Y_OFFSET, HELP_MENU_TRACKING_DEFAULTS } from '../constants';
+
+// Left offset required for the dropdown to be aligned with the super sidebar
+const DROPDOWN_X_OFFSET = -4;
export default {
components: {
@@ -185,12 +188,23 @@ export default {
});
},
},
+ popperOptions: {
+ modifiers: [
+ {
+ name: 'offset',
+ options: {
+ offset: [DROPDOWN_X_OFFSET, DROPDOWN_Y_OFFSET],
+ },
+ },
+ ],
+ },
};
</script>
<template>
<gl-disclosure-dropdown
ref="dropdown"
+ :popper-options="$options.popperOptions"
@shown="trackDropdownToggle(true)"
@hidden="trackDropdownToggle(false)"
>
diff --git a/app/assets/javascripts/super_sidebar/components/nav_item.vue b/app/assets/javascripts/super_sidebar/components/nav_item.vue
index 53698a808a7..223fbe6d078 100644
--- a/app/assets/javascripts/super_sidebar/components/nav_item.vue
+++ b/app/assets/javascripts/super_sidebar/components/nav_item.vue
@@ -160,7 +160,7 @@ export default {
></div>
<div class="gl-flex-shrink-0 gl-w-6 gl-mx-3">
<slot name="icon">
- <gl-icon v-if="item.icon" :name="item.icon" class="gl-ml-2" />
+ <gl-icon v-if="item.icon" :name="item.icon" class="gl-ml-2 item-icon" />
<gl-icon
v-else-if="draggable"
name="grip"
diff --git a/app/assets/javascripts/super_sidebar/components/pinned_section.vue b/app/assets/javascripts/super_sidebar/components/pinned_section.vue
index 3c12e193d80..9595bdfb632 100644
--- a/app/assets/javascripts/super_sidebar/components/pinned_section.vue
+++ b/app/assets/javascripts/super_sidebar/components/pinned_section.vue
@@ -71,7 +71,7 @@ export default {
@click.prevent="expanded = !expanded"
>
<div class="gl-flex-shrink-0 gl-w-6 gl-mx-3">
- <gl-icon name="thumbtack" class="gl-ml-2" />
+ <gl-icon name="thumbtack" class="gl-ml-2 item-icon" />
</div>
<span class="gl-font-weight-bold gl-font-sm gl-flex-grow-1">{{ $options.i18n.pinned }}</span>
diff --git a/app/assets/javascripts/super_sidebar/components/user_menu.vue b/app/assets/javascripts/super_sidebar/components/user_menu.vue
index d8452900e34..c90d1ad9c3e 100644
--- a/app/assets/javascripts/super_sidebar/components/user_menu.vue
+++ b/app/assets/javascripts/super_sidebar/components/user_menu.vue
@@ -11,9 +11,12 @@ import { s__, __, sprintf } from '~/locale';
import NewNavToggle from '~/nav/components/new_nav_toggle.vue';
import Tracking from '~/tracking';
import PersistentUserCallout from '~/persistent_user_callout';
-import { USER_MENU_TRACKING_DEFAULTS } from '../constants';
+import { USER_MENU_TRACKING_DEFAULTS, DROPDOWN_Y_OFFSET } from '../constants';
import UserNameGroup from './user_name_group.vue';
+// Left offset required for the dropdown to be aligned with the super sidebar
+const DROPDOWN_X_OFFSET = -211;
+
export default {
feedbackUrl: 'https://gitlab.com/gitlab-org/gitlab/-/issues/403059',
i18n: {
@@ -216,6 +219,16 @@ export default {
});
},
},
+ popperOptions: {
+ modifiers: [
+ {
+ name: 'offset',
+ options: {
+ offset: [DROPDOWN_X_OFFSET, DROPDOWN_Y_OFFSET],
+ },
+ },
+ ],
+ },
};
</script>
@@ -223,7 +236,7 @@ export default {
<div>
<gl-disclosure-dropdown
ref="userDropdown"
- placement="right"
+ :popper-options="$options.popperOptions"
data-testid="user-dropdown"
data-qa-selector="user_menu"
@shown="onShow"
diff --git a/app/assets/javascripts/super_sidebar/constants.js b/app/assets/javascripts/super_sidebar/constants.js
index 3dbd12b4ff7..5c4a6a9dfc1 100644
--- a/app/assets/javascripts/super_sidebar/constants.js
+++ b/app/assets/javascripts/super_sidebar/constants.js
@@ -33,3 +33,5 @@ export const HELP_MENU_TRACKING_DEFAULTS = {
export const SIDEBAR_PINS_EXPANDED_COOKIE = 'sidebar_pinned_section_expanded';
export const SIDEBAR_COOKIE_EXPIRATION = 365 * 10;
+
+export const DROPDOWN_Y_OFFSET = 4;
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue b/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue
index c19dfe663f4..25cf5335fb5 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue
@@ -5,7 +5,7 @@ import { STATUS_MERGED } from '~/issues/constants';
import { BV_SHOW_MODAL } from '~/lib/utils/constants';
import { HTTP_STATUS_UNAUTHORIZED } from '~/lib/utils/http_status';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import { s__, __ } from '~/locale';
+import { s__, __, sprintf } from '~/locale';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import eventHub from '../../event_hub';
import approvalsMixin from '../../mixins/approvals';
@@ -84,13 +84,22 @@ export default {
return Boolean(this.action);
},
invalidRules() {
- return this.approvals.approvalState?.invalidApproversRules || [];
+ return this.approvals.approvalState?.rules?.filter((rule) => rule.invalid) || [];
+ },
+ invalidApprovedRules() {
+ return this.invalidRules.filter((rule) => rule.allowMergeWhenInvalid);
+ },
+ invalidFailedRules() {
+ return this.invalidRules.filter((rule) => !rule.allowMergeWhenInvalid);
},
hasInvalidRules() {
return this.mr.mergeRequestApproversAvailable && this.invalidRules.length;
},
- invalidRulesText() {
- return this.invalidRules.length;
+ hasInvalidApprovedRules() {
+ return this.mr.mergeRequestApproversAvailable && this.invalidApprovedRules.length;
+ },
+ hasInvalidFailedRules() {
+ return this.mr.mergeRequestApproversAvailable && this.invalidFailedRules.length;
},
approvedBy() {
return this.approvals.approvedBy?.nodes || [];
@@ -133,11 +142,29 @@ export default {
return null;
},
- pluralizedRuleText() {
- return this.invalidRules.length > 1
+ pluralizedApprovedRuleText() {
+ return this.invalidApprovedRules.length > 1
? this.$options.i18n.invalidRulesPlural
: this.$options.i18n.invalidRuleSingular;
},
+ pluralizedFailedRuleText() {
+ return this.invalidFailedRules.length > 1
+ ? this.$options.i18n.invalidFailedRulesPlural
+ : this.$options.i18n.invalidFailedRuleSingular;
+ },
+ pluralizedRuleText() {
+ return [
+ this.hasInvalidFailedRules
+ ? sprintf(this.pluralizedFailedRuleText, { rules: this.invalidFailedRules.length })
+ : null,
+ this.hasInvalidApprovedRules
+ ? sprintf(this.pluralizedApprovedRuleText, { rules: this.invalidApprovedRules.length })
+ : null,
+ ]
+ .filter((text) => Boolean(text))
+ .join(', ')
+ .concat('.');
+ },
},
methods: {
approve() {
@@ -205,11 +232,13 @@ export default {
FETCH_LOADING,
linkToInvalidRules: INVALID_RULES_DOCS_PATH,
i18n: {
- invalidRuleSingular: s__(
- 'mrWidget|%{rules} invalid rule has been approved automatically, as no one can approve it.',
+ invalidRuleSingular: s__('mrWidget|%{rules} invalid rule has been approved automatically'),
+ invalidRulesPlural: s__('mrWidget|%{rules} invalid rules have been approved automatically'),
+ invalidFailedRuleSingular: s__(
+ "mrWidget|%{dangerStart}%{rules} rule can't be approved%{dangerEnd}",
),
- invalidRulesPlural: s__(
- 'mrWidget|%{rules} invalid rules have been approved automatically, as no one can approve them.',
+ invalidFailedRulesPlural: s__(
+ "mrWidget|%{dangerStart}%{rules} rules can't be approved%{dangerEnd}",
),
learnMore: __('Learn more.'),
},
@@ -255,7 +284,9 @@ export default {
</div>
<div v-if="hasInvalidRules" class="gl-text-gray-400 gl-mt-2" data-testid="invalid-rules">
<gl-sprintf :message="pluralizedRuleText">
- <template #rules>{{ invalidRulesText }}</template>
+ <template #danger="{ content }">
+ <span class="gl-font-weight-bold text-danger">{{ content }}</span>
+ </template>
</gl-sprintf>
</div>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/markdown/header.vue b/app/assets/javascripts/vue_shared/components/markdown/header.vue
index 4e827d71126..3486f231b39 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/header.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/header.vue
@@ -122,12 +122,7 @@ export default {
return [`<details><summary>${expandText}</summary>`, `{text}`, '</details>'].join('\n');
},
showAiActions() {
- return (
- this.resourceGlobalId &&
- this.glFeatures.openaiExperimentation &&
- this.glFeatures.summarizeNotes &&
- this.glFeatures.summarizeComments
- );
+ return this.resourceGlobalId && this.glFeatures.summarizeComments;
},
},
watch: {