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:
Diffstat (limited to 'app')
-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
-rw-r--r--app/assets/stylesheets/framework/super_sidebar.scss5
-rw-r--r--app/controllers/clusters/base_controller.rb2
-rw-r--r--app/controllers/google_api/authorizations_controller.rb2
-rw-r--r--app/controllers/projects/blame_controller.rb17
-rw-r--r--app/controllers/projects/cluster_agents_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests_controller.rb1
-rw-r--r--app/controllers/projects/pipelines_controller.rb7
-rw-r--r--app/experiments/security_actions_continuous_onboarding_experiment.rb9
-rw-r--r--app/models/onboarding/completion.rb23
-rw-r--r--app/services/issues/create_service.rb1
-rw-r--r--app/services/issues/update_service.rb1
-rw-r--r--app/services/merge_requests/handle_assignees_change_service.rb1
-rw-r--r--app/workers/all_queues.yml34
-rw-r--r--app/workers/concerns/cluster_agent_queue.rb2
-rw-r--r--app/workers/concerns/cluster_queue.rb2
32 files changed, 226 insertions, 244 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: {
diff --git a/app/assets/stylesheets/framework/super_sidebar.scss b/app/assets/stylesheets/framework/super_sidebar.scss
index ba98e3b54c9..045ad4a8298 100644
--- a/app/assets/stylesheets/framework/super_sidebar.scss
+++ b/app/assets/stylesheets/framework/super_sidebar.scss
@@ -78,8 +78,9 @@
}
}
- .counter .gl-icon {
- color: var(--gray-500, $gray-500);
+ .counter .gl-icon,
+ .item-icon {
+ color: var(--gray-600, $gray-500);
}
.counter:hover,
diff --git a/app/controllers/clusters/base_controller.rb b/app/controllers/clusters/base_controller.rb
index 2401d8b1044..dd5be596ad1 100644
--- a/app/controllers/clusters/base_controller.rb
+++ b/app/controllers/clusters/base_controller.rb
@@ -8,7 +8,7 @@ class Clusters::BaseController < ApplicationController
helper_method :clusterable
- feature_category :kubernetes_management
+ feature_category :deployment_management
urgency :low, [
:index, :show, :environments, :cluster_status, :prometheus_proxy,
:destroy, :new_cluster_docs, :connect, :new, :create_user
diff --git a/app/controllers/google_api/authorizations_controller.rb b/app/controllers/google_api/authorizations_controller.rb
index 536c5e347e7..8a3183ba615 100644
--- a/app/controllers/google_api/authorizations_controller.rb
+++ b/app/controllers/google_api/authorizations_controller.rb
@@ -6,7 +6,7 @@ module GoogleApi
before_action :validate_session_key!
- feature_category :kubernetes_management
+ feature_category :deployment_management
urgency :low
##
diff --git a/app/controllers/projects/blame_controller.rb b/app/controllers/projects/blame_controller.rb
index cc0d3818e33..dbc82f5b314 100644
--- a/app/controllers/projects/blame_controller.rb
+++ b/app/controllers/projects/blame_controller.rb
@@ -8,24 +8,17 @@ class Projects::BlameController < Projects::ApplicationController
before_action :require_non_empty_project
before_action :assign_ref_vars
before_action :authorize_read_code!
+ before_action :load_blob
feature_category :source_code_management
urgency :low, [:show]
def show
- @blob = @repository.blob_at(@commit.id, @path)
-
- unless @blob
- return redirect_to_tree_root_for_missing_path(@project, @ref, @path)
- end
-
load_environment
load_blame
end
def page
- @blob = @repository.blob_at(@commit.id, @path)
-
load_environment
load_blame
@@ -34,6 +27,14 @@ class Projects::BlameController < Projects::ApplicationController
private
+ def load_blob
+ @blob = @repository.blob_at(@commit.id, @path)
+
+ return if @blob
+
+ redirect_to_tree_root_for_missing_path(@project, @ref, @path)
+ end
+
def load_environment
environment_params = @repository.branch_exists?(@ref) ? { ref: @ref } : { commit: @commit }
environment_params[:find_latest] = true
diff --git a/app/controllers/projects/cluster_agents_controller.rb b/app/controllers/projects/cluster_agents_controller.rb
index 9bc03640811..bd58bd3e470 100644
--- a/app/controllers/projects/cluster_agents_controller.rb
+++ b/app/controllers/projects/cluster_agents_controller.rb
@@ -6,7 +6,7 @@ class Projects::ClusterAgentsController < Projects::ApplicationController
before_action :authorize_read_cluster_agent!
before_action :set_kas_cookie, only: [:show], if: -> { current_user }
- feature_category :kubernetes_management
+ feature_category :deployment_management
urgency :low
def show
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 73b8ca6aafb..a9e0b2d7a98 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -39,7 +39,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:issue_assignees_widget, @project)
push_frontend_feature_flag(:refactor_security_extension, @project)
push_frontend_feature_flag(:deprecate_vulnerabilities_feedback, @project)
- push_frontend_feature_flag(:refactor_code_quality_inline_findings, project)
push_frontend_feature_flag(:moved_mr_sidebar, project)
push_frontend_feature_flag(:single_file_file_by_file, project)
push_frontend_feature_flag(:mr_experience_survey, project)
diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb
index 4f3369d5bd0..ea7bb51c1e6 100644
--- a/app/controllers/projects/pipelines_controller.rb
+++ b/app/controllers/projects/pipelines_controller.rb
@@ -22,7 +22,6 @@ class Projects::PipelinesController < Projects::ApplicationController
before_action :authorize_update_pipeline!, only: [:retry, :cancel]
before_action :ensure_pipeline, only: [:show, :downloadable_artifacts]
before_action :reject_if_build_artifacts_size_refreshing!, only: [:destroy]
- before_action :push_frontend_feature_flags, only: [:index]
# Will be removed with https://gitlab.com/gitlab-org/gitlab/-/issues/225596
before_action :redirect_for_legacy_scope_filter, only: [:index], if: -> { request.format.html? }
@@ -234,7 +233,7 @@ class Projects::PipelinesController < Projects::ApplicationController
@pipelines,
disable_coverage: true,
preload: true,
- disable_manual_and_scheduled_actions: Feature.enabled?(:lazy_load_pipeline_dropdown_actions, @project)
+ disable_manual_and_scheduled_actions: true
)
end
@@ -358,10 +357,6 @@ class Projects::PipelinesController < Projects::ApplicationController
def tracking_project_source
project
end
-
- def push_frontend_feature_flags
- push_frontend_feature_flag(:lazy_load_pipeline_dropdown_actions, @project)
- end
end
Projects::PipelinesController.prepend_mod_with('Projects::PipelinesController')
diff --git a/app/experiments/security_actions_continuous_onboarding_experiment.rb b/app/experiments/security_actions_continuous_onboarding_experiment.rb
deleted file mode 100644
index 6adfbedc744..00000000000
--- a/app/experiments/security_actions_continuous_onboarding_experiment.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# frozen_string_literal: true
-
-class SecurityActionsContinuousOnboardingExperiment < ApplicationExperiment
- def control_behavior
- end
-
- def candidate_behavior
- end
-end
diff --git a/app/models/onboarding/completion.rb b/app/models/onboarding/completion.rb
index 0966a9f2912..afbd671f82e 100644
--- a/app/models/onboarding/completion.rb
+++ b/app/models/onboarding/completion.rb
@@ -13,7 +13,10 @@ module Onboarding
:issue_created,
:git_write,
:merge_request_created,
- :user_added
+ :user_added,
+ :license_scanning_run,
+ :secure_dependency_scanning_run,
+ :secure_dast_run
].freeze
def initialize(project, current_user = nil)
@@ -58,26 +61,10 @@ module Onboarding
def action_columns
[:code_added] +
- tracked_actions.map { |action_key| ::Onboarding::Progress.column_name(action_key) }
+ ACTION_PATHS.map { |action_key| ::Onboarding::Progress.column_name(action_key) }
end
strong_memoize_attr :action_columns
- def tracked_actions
- ACTION_PATHS + deploy_section_tracked_actions
- end
-
- def deploy_section_tracked_actions
- experiment(
- :security_actions_continuous_onboarding,
- namespace: namespace,
- user: current_user,
- sticky_to: current_user
- ) do |e|
- e.control { [:security_scan_enabled] }
- e.candidate { [:license_scanning_run, :secure_dependency_scanning_run, :secure_dast_run] }
- end.run
- end
-
attr_reader :project, :namespace, :current_user
end
end
diff --git a/app/services/issues/create_service.rb b/app/services/issues/create_service.rb
index 06977dec04b..2a3f0abf4cb 100644
--- a/app/services/issues/create_service.rb
+++ b/app/services/issues/create_service.rb
@@ -93,6 +93,7 @@ module Issues
return if issue.assignees == old_assignees
create_assignee_note(issue, old_assignees)
+ Gitlab::ResourceEvents::AssignmentEventRecorder.new(parent: issue, old_assignees: old_assignees).record
end
def resolve_discussions_with_issue(issue)
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index 877f0a73c82..4dd4e2978c0 100644
--- a/app/services/issues/update_service.rb
+++ b/app/services/issues/update_service.rb
@@ -75,6 +75,7 @@ module Issues
return if issue.assignees == old_assignees
create_assignee_note(issue, old_assignees)
+ Gitlab::ResourceEvents::AssignmentEventRecorder.new(parent: issue, old_assignees: old_assignees).record
notification_service.async.reassigned_issue(issue, current_user, old_assignees)
todo_service.reassigned_assignable(issue, current_user, old_assignees)
track_incident_action(current_user, issue, :incident_assigned)
diff --git a/app/services/merge_requests/handle_assignees_change_service.rb b/app/services/merge_requests/handle_assignees_change_service.rb
index 51be4690af4..835d56a7070 100644
--- a/app/services/merge_requests/handle_assignees_change_service.rb
+++ b/app/services/merge_requests/handle_assignees_change_service.rb
@@ -15,6 +15,7 @@ module MergeRequests
def execute(merge_request, old_assignees, options = {})
create_assignee_note(merge_request, old_assignees)
notification_service.async.reassigned_merge_request(merge_request, current_user, old_assignees.to_a)
+ Gitlab::ResourceEvents::AssignmentEventRecorder.new(parent: merge_request, old_assignees: old_assignees).record
todo_service.reassigned_assignable(merge_request, current_user, old_assignees)
new_assignees = merge_request.assignees - old_assignees
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index 6c3b4990023..0418bef3c1c 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -131,7 +131,7 @@
:tags: []
- :name: cluster_agent:clusters_agents_delete_expired_events
:worker_name: Clusters::Agents::DeleteExpiredEventsWorker
- :feature_category: :kubernetes_management
+ :feature_category: :deployment_management
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :unknown
@@ -950,7 +950,7 @@
:tags: []
- :name: gcp_cluster:cluster_configure_istio
:worker_name: ClusterConfigureIstioWorker
- :feature_category: :kubernetes_management
+ :feature_category: :deployment_management
:has_external_dependencies: true
:urgency: :low
:resource_boundary: :unknown
@@ -959,7 +959,7 @@
:tags: []
- :name: gcp_cluster:cluster_install_app
:worker_name: ClusterInstallAppWorker
- :feature_category: :kubernetes_management
+ :feature_category: :deployment_management
:has_external_dependencies: true
:urgency: :low
:resource_boundary: :unknown
@@ -968,7 +968,7 @@
:tags: []
- :name: gcp_cluster:cluster_patch_app
:worker_name: ClusterPatchAppWorker
- :feature_category: :kubernetes_management
+ :feature_category: :deployment_management
:has_external_dependencies: true
:urgency: :low
:resource_boundary: :unknown
@@ -977,7 +977,7 @@
:tags: []
- :name: gcp_cluster:cluster_provision
:worker_name: ClusterProvisionWorker
- :feature_category: :kubernetes_management
+ :feature_category: :deployment_management
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :unknown
@@ -986,7 +986,7 @@
:tags: []
- :name: gcp_cluster:cluster_update_app
:worker_name: ClusterUpdateAppWorker
- :feature_category: :kubernetes_management
+ :feature_category: :deployment_management
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :unknown
@@ -995,7 +995,7 @@
:tags: []
- :name: gcp_cluster:cluster_upgrade_app
:worker_name: ClusterUpgradeAppWorker
- :feature_category: :kubernetes_management
+ :feature_category: :deployment_management
:has_external_dependencies: true
:urgency: :low
:resource_boundary: :unknown
@@ -1004,7 +1004,7 @@
:tags: []
- :name: gcp_cluster:cluster_wait_for_app_installation
:worker_name: ClusterWaitForAppInstallationWorker
- :feature_category: :kubernetes_management
+ :feature_category: :deployment_management
:has_external_dependencies: true
:urgency: :low
:resource_boundary: :cpu
@@ -1013,7 +1013,7 @@
:tags: []
- :name: gcp_cluster:cluster_wait_for_app_update
:worker_name: ClusterWaitForAppUpdateWorker
- :feature_category: :kubernetes_management
+ :feature_category: :deployment_management
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :unknown
@@ -1022,7 +1022,7 @@
:tags: []
- :name: gcp_cluster:cluster_wait_for_ingress_ip_address
:worker_name: ClusterWaitForIngressIpAddressWorker
- :feature_category: :kubernetes_management
+ :feature_category: :deployment_management
:has_external_dependencies: true
:urgency: :low
:resource_boundary: :unknown
@@ -1031,7 +1031,7 @@
:tags: []
- :name: gcp_cluster:clusters_applications_activate_integration
:worker_name: Clusters::Applications::ActivateIntegrationWorker
- :feature_category: :kubernetes_management
+ :feature_category: :deployment_management
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :unknown
@@ -1040,7 +1040,7 @@
:tags: []
- :name: gcp_cluster:clusters_applications_deactivate_integration
:worker_name: Clusters::Applications::DeactivateIntegrationWorker
- :feature_category: :kubernetes_management
+ :feature_category: :deployment_management
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :unknown
@@ -1049,7 +1049,7 @@
:tags: []
- :name: gcp_cluster:clusters_applications_uninstall
:worker_name: Clusters::Applications::UninstallWorker
- :feature_category: :kubernetes_management
+ :feature_category: :deployment_management
:has_external_dependencies: true
:urgency: :low
:resource_boundary: :unknown
@@ -1058,7 +1058,7 @@
:tags: []
- :name: gcp_cluster:clusters_applications_wait_for_uninstall_app
:worker_name: Clusters::Applications::WaitForUninstallAppWorker
- :feature_category: :kubernetes_management
+ :feature_category: :deployment_management
:has_external_dependencies: true
:urgency: :low
:resource_boundary: :cpu
@@ -1067,7 +1067,7 @@
:tags: []
- :name: gcp_cluster:clusters_cleanup_project_namespace
:worker_name: Clusters::Cleanup::ProjectNamespaceWorker
- :feature_category: :kubernetes_management
+ :feature_category: :deployment_management
:has_external_dependencies: true
:urgency: :low
:resource_boundary: :unknown
@@ -1076,7 +1076,7 @@
:tags: []
- :name: gcp_cluster:clusters_cleanup_service_account
:worker_name: Clusters::Cleanup::ServiceAccountWorker
- :feature_category: :kubernetes_management
+ :feature_category: :deployment_management
:has_external_dependencies: true
:urgency: :low
:resource_boundary: :unknown
@@ -1085,7 +1085,7 @@
:tags: []
- :name: gcp_cluster:wait_for_cluster_creation
:worker_name: WaitForClusterCreationWorker
- :feature_category: :kubernetes_management
+ :feature_category: :deployment_management
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :unknown
diff --git a/app/workers/concerns/cluster_agent_queue.rb b/app/workers/concerns/cluster_agent_queue.rb
index 68de7cca135..8fdfba11111 100644
--- a/app/workers/concerns/cluster_agent_queue.rb
+++ b/app/workers/concerns/cluster_agent_queue.rb
@@ -5,6 +5,6 @@ module ClusterAgentQueue
included do
queue_namespace :cluster_agent
- feature_category :kubernetes_management
+ feature_category :deployment_management
end
end
diff --git a/app/workers/concerns/cluster_queue.rb b/app/workers/concerns/cluster_queue.rb
index 60ba8785347..5f1a90a99d0 100644
--- a/app/workers/concerns/cluster_queue.rb
+++ b/app/workers/concerns/cluster_queue.rb
@@ -8,6 +8,6 @@ module ClusterQueue
included do
queue_namespace :gcp_cluster
- feature_category :kubernetes_management
+ feature_category :deployment_management
end
end