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>2022-03-14 18:09:32 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-03-14 18:09:32 +0300
commit739467f1fa4d5d4042b47ff6637a567d1ad6a4a4 (patch)
treee9b13550a7f6373c8580b7a0eda499ad2bb9e81d /app
parentfd27e4f95b3ea8668e1e67f5a88dfb061909c893 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/attention_requests/components/navigation_popover.vue120
-rw-r--r--app/assets/javascripts/attention_requests/index.js73
-rw-r--r--app/assets/javascripts/main.js6
-rw-r--r--app/assets/javascripts/sidebar/components/attention_requested_toggle.vue5
-rw-r--r--app/assets/javascripts/sidebar/sidebar_bundle.js12
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_related_links.vue24
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js4
-rw-r--r--app/assets/stylesheets/page_bundles/merge_requests.scss4
-rw-r--r--app/controllers/dashboard_controller.rb4
-rw-r--r--app/controllers/projects/merge_requests_controller.rb3
-rw-r--r--app/models/users/callout.rb4
-rw-r--r--app/presenters/merge_request_presenter.rb15
-rw-r--r--app/serializers/merge_request_widget_entity.rb6
-rw-r--r--app/views/layouts/header/_default.html.haml3
-rw-r--r--app/views/projects/merge_requests/show.html.haml3
15 files changed, 261 insertions, 25 deletions
diff --git a/app/assets/javascripts/attention_requests/components/navigation_popover.vue b/app/assets/javascripts/attention_requests/components/navigation_popover.vue
new file mode 100644
index 00000000000..1542bc9a7e9
--- /dev/null
+++ b/app/assets/javascripts/attention_requests/components/navigation_popover.vue
@@ -0,0 +1,120 @@
+<script>
+import { GlPopover, GlSprintf, GlButton, GlLink, GlIcon } from '@gitlab/ui';
+import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
+import { helpPagePath } from '~/helpers/help_page_helper';
+import UserCalloutDismisser from '~/vue_shared/components/user_callout_dismisser.vue';
+
+export default {
+ components: {
+ GlPopover,
+ GlSprintf,
+ GlButton,
+ GlLink,
+ GlIcon,
+ UserCalloutDismisser,
+ },
+ inject: {
+ message: {
+ default: '',
+ },
+ observerElSelector: {
+ default: '',
+ },
+ observerElToggledClass: {
+ default: '',
+ },
+ featureName: {
+ default: '',
+ },
+ popoverTarget: {
+ default: '',
+ },
+ showAttentionIcon: {
+ default: false,
+ },
+ delay: {
+ default: 0,
+ },
+ popoverCssClass: {
+ default: '',
+ },
+ },
+ data() {
+ return {
+ showPopover: false,
+ popoverPlacement: this.popoverPosition(),
+ };
+ },
+ mounted() {
+ this.observeEl = document.querySelector(this.observerElSelector);
+ this.observer = new MutationObserver(this.callback);
+ this.observer.observe(this.observeEl, {
+ attributes: true,
+ });
+ this.callback();
+
+ window.addEventListener('resize', () => {
+ this.popoverPlacement = this.popoverPosition();
+ });
+ },
+ beforeDestroy() {
+ this.observer.disconnect();
+ },
+ methods: {
+ callback() {
+ if (this.showPopover) {
+ this.$root.$emit('bv::hide::popover');
+ }
+
+ setTimeout(() => this.toggleShowPopover(), this.delay);
+ },
+ toggleShowPopover() {
+ this.showPopover = this.observeEl.classList.contains(this.observerElToggledClass);
+ },
+ getPopoverTarget() {
+ return document.querySelector(this.popoverTarget);
+ },
+ popoverPosition() {
+ if (bp.isDesktop()) {
+ return 'left';
+ }
+
+ return 'bottom';
+ },
+ },
+ docsPage: helpPagePath('development/code_review.html'),
+};
+</script>
+
+<template>
+ <user-callout-dismisser :feature-name="featureName">
+ <template #default="{ shouldShowCallout, dismiss }">
+ <gl-popover
+ v-if="shouldShowCallout"
+ :show-close-button="false"
+ :target="() => getPopoverTarget()"
+ :show="showPopover"
+ :delay="0"
+ triggers="manual"
+ :placement="popoverPlacement"
+ boundary="window"
+ no-fade
+ :css-classes="[popoverCssClass]"
+ >
+ <p v-for="(m, index) in message" :key="index" class="gl-mb-5">
+ <gl-sprintf :message="m">
+ <template #strong="{ content }">
+ <strong><gl-icon v-if="showAttentionIcon" name="attention" /> {{ content }}</strong>
+ </template>
+ </gl-sprintf>
+ </p>
+ <div class="gl-display-flex gl-align-items-center">
+ <gl-button size="small" variant="confirm" class="gl-mr-5" @click.prevent.stop="dismiss">
+ {{ __('Got it!') }}
+ </gl-button>
+ <gl-link :href="$options.docsPage" target="_blank">{{ __('Learn more') }}</gl-link>
+ </div>
+ </gl-popover>
+ </template>
+ </user-callout-dismisser>
+</template>
diff --git a/app/assets/javascripts/attention_requests/index.js b/app/assets/javascripts/attention_requests/index.js
new file mode 100644
index 00000000000..2a142ab46e5
--- /dev/null
+++ b/app/assets/javascripts/attention_requests/index.js
@@ -0,0 +1,73 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import { __ } from '~/locale';
+import createDefaultClient from '~/lib/graphql';
+import NavigationPopover from './components/navigation_popover.vue';
+
+Vue.use(VueApollo);
+
+const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient(),
+});
+
+export const initTopNavPopover = () => {
+ const el = document.getElementById('js-need-attention-nav-onboarding');
+
+ if (!el) return;
+
+ // eslint-disable-next-line no-new
+ new Vue({
+ el,
+ apolloProvider,
+ provide: {
+ observerElSelector: '.user-counter.dropdown',
+ observerElToggledClass: 'show',
+ message: [
+ __(
+ '%{strongStart}Need your attention%{strongEnd} are the merge requests that need your help to move forward, as an assignee or reviewer.',
+ ),
+ ],
+ featureName: 'attention_requests_top_nav',
+ popoverTarget: '#js-need-attention-nav',
+ },
+ render(h) {
+ return h(NavigationPopover);
+ },
+ });
+};
+
+export const initSideNavPopover = () => {
+ const el = document.getElementById('js-need-attention-sidebar-onboarding');
+
+ if (!el) return;
+
+ // eslint-disable-next-line no-new
+ new Vue({
+ el,
+ apolloProvider,
+ provide: {
+ observerElSelector: '.js-right-sidebar',
+ observerElToggledClass: 'right-sidebar-expanded',
+ message: [
+ __(
+ 'To ask someone to look at a merge request, select %{strongStart}Request attention%{strongEnd}. Select again to remove the request.',
+ ),
+ __(
+ 'Some actions remove attention requests, like a reviewer approving or anyone merging the merge request.',
+ ),
+ ],
+ featureName: 'attention_requests_side_nav',
+ popoverTarget: '.js-attention-request-toggle',
+ showAttentionIcon: true,
+ delay: 500,
+ popoverCssClass: 'attention-request-sidebar-popover',
+ },
+ render(h) {
+ return h(NavigationPopover);
+ },
+ });
+};
+
+export default () => {
+ initTopNavPopover();
+};
diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js
index efc425a1972..b3cb93e74f2 100644
--- a/app/assets/javascripts/main.js
+++ b/app/assets/javascripts/main.js
@@ -161,6 +161,12 @@ function deferredInitialisation() {
// Adding a helper class to activate animations only after all is rendered
setTimeout(() => $body.addClass('page-initialised'), 1000);
+
+ if (window.gon?.features?.mrAttentionRequests) {
+ import('~/attention_requests')
+ .then((module) => module.default())
+ .catch(() => {});
+ }
}
const $body = $('body');
diff --git a/app/assets/javascripts/sidebar/components/attention_requested_toggle.vue b/app/assets/javascripts/sidebar/components/attention_requested_toggle.vue
index d11bed4f058..6ba88939373 100644
--- a/app/assets/javascripts/sidebar/components/attention_requested_toggle.vue
+++ b/app/assets/javascripts/sidebar/components/attention_requested_toggle.vue
@@ -70,7 +70,10 @@ export default {
</script>
<template>
- <span v-gl-tooltip.left.viewport="tooltipTitle" class="gl-display-inline-block">
+ <span
+ v-gl-tooltip.left.viewport="tooltipTitle"
+ class="gl-display-inline-block js-attention-request-toggle"
+ >
<gl-button
:loading="loading"
:variant="user.attention_requested ? 'warning' : 'default'"
diff --git a/app/assets/javascripts/sidebar/sidebar_bundle.js b/app/assets/javascripts/sidebar/sidebar_bundle.js
index 1be670f7590..74ab65e4e04 100644
--- a/app/assets/javascripts/sidebar/sidebar_bundle.js
+++ b/app/assets/javascripts/sidebar/sidebar_bundle.js
@@ -3,7 +3,17 @@ import Mediator from './sidebar_mediator';
export default (store) => {
const mediator = new Mediator(getSidebarOptions());
- mediator.fetch();
+ mediator
+ .fetch()
+ .then(() => {
+ if (window.gon?.features?.mrAttentionRequests) {
+ return import('~/attention_requests');
+ }
+
+ return null;
+ })
+ .then((module) => module?.initSideNavPopover())
+ .catch(() => {});
mountSidebar(mediator, store);
};
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_related_links.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_related_links.vue
index 730d11b1208..319df090ff1 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_related_links.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_related_links.vue
@@ -1,5 +1,5 @@
<script>
-import { GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
+import { GlSafeHtmlDirective as SafeHtml, GlLink } from '@gitlab/ui';
import { s__, n__ } from '~/locale';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
@@ -8,6 +8,9 @@ export default {
directives: {
SafeHtml,
},
+ components: {
+ GlLink,
+ },
mixins: [glFeatureFlagMixin()],
props: {
relatedLinks: {
@@ -37,6 +40,17 @@ export default {
return n__('mrWidget|Closes issue', 'mrWidget|Closes issues', this.relatedLinks.closingCount);
},
+ assignIssueText() {
+ if (this.relatedLinks.unassignedCount > 1) {
+ return s__('mrWidget|Assign yourself to these issues');
+ }
+ return s__('mrWidget|Assign yourself to this issue');
+ },
+ shouldShowAssignToMeLink() {
+ return (
+ this.relatedLinks.unassignedCount && this.relatedLinks.assignToMe && this.showAssignToMe
+ );
+ },
},
};
</script>
@@ -57,10 +71,14 @@ export default {
<span v-safe-html="relatedLinks.mentioned"></span>
</p>
<p
- v-if="relatedLinks.assignToMe && showAssignToMe"
+ v-if="shouldShowAssignToMeLink"
:class="{ 'gl-display-line gl-m-0': glFeatures.restructuredMrWidget }"
>
- <span v-html="relatedLinks.assignToMe /* eslint-disable-line vue/no-v-html */"></span>
+ <span>
+ <gl-link rel="nofollow" data-method="post" :href="relatedLinks.assignToMe">{{
+ assignIssueText
+ }}</gl-link>
+ </span>
</p>
</section>
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
index 5378dabf638..994e0c23b44 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
@@ -82,14 +82,16 @@ export default class MergeRequestStore {
const { closing } = links;
const mentioned = links.mentioned_but_not_closing;
const assignToMe = links.assign_to_closing;
+ const unassignedCount = links.assign_to_closing_count;
- if (closing || mentioned || assignToMe) {
+ if (closing || mentioned || unassignedCount) {
this.relatedLinks = {
closing,
mentioned,
assignToMe,
closingCount: links.closing_count,
mentionedCount: links.mentioned_count,
+ unassignedCount: links.assign_to_closing_count,
};
}
}
diff --git a/app/assets/stylesheets/page_bundles/merge_requests.scss b/app/assets/stylesheets/page_bundles/merge_requests.scss
index d2649acd622..34a3d936a67 100644
--- a/app/assets/stylesheets/page_bundles/merge_requests.scss
+++ b/app/assets/stylesheets/page_bundles/merge_requests.scss
@@ -757,3 +757,7 @@ $tabs-holder-z-index: 250;
background: linear-gradient(to bottom, rgba(#333, 0), rgba(#333, 1));
}
}
+
+.attention-request-sidebar-popover {
+ z-index: 999;
+}
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index 898e7826e3a..f25cc1bbc32 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -20,10 +20,6 @@ class DashboardController < Dashboard::ApplicationController
urgency :low, [:merge_requests]
- before_action only: [:merge_requests] do
- push_frontend_feature_flag(:mr_attention_requests, default_enabled: :yaml)
- end
-
def activity
respond_to do |format|
format.html
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index a7d2fb4a127..5f39a8419c9 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -30,9 +30,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
before_action :set_issuables_index, only: [:index]
before_action :authenticate_user!, only: [:assign_related_issues]
before_action :check_user_can_push_to_source_branch!, only: [:rebase]
- before_action only: [:index, :show] do
- push_frontend_feature_flag(:mr_attention_requests, project, default_enabled: :yaml)
- end
before_action only: [:show] do
push_frontend_feature_flag(:file_identifier_hash)
diff --git a/app/models/users/callout.rb b/app/models/users/callout.rb
index 800256a613b..0922323e12b 100644
--- a/app/models/users/callout.rb
+++ b/app/models/users/callout.rb
@@ -46,7 +46,9 @@ module Users
storage_enforcement_banner_first_enforcement_threshold: 43,
storage_enforcement_banner_second_enforcement_threshold: 44,
storage_enforcement_banner_third_enforcement_threshold: 45,
- storage_enforcement_banner_fourth_enforcement_threshold: 46
+ storage_enforcement_banner_fourth_enforcement_threshold: 46,
+ attention_requests_top_nav: 47,
+ attention_requests_side_nav: 48
}
validates :feature_name,
diff --git a/app/presenters/merge_request_presenter.rb b/app/presenters/merge_request_presenter.rb
index 2dc2ecad1b4..6dd3908b21d 100644
--- a/app/presenters/merge_request_presenter.rb
+++ b/app/presenters/merge_request_presenter.rb
@@ -149,7 +149,11 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
)
end
- def assign_to_closing_issues_link
+ def assign_to_closing_issues_path
+ assign_related_issues_project_merge_request_path(project, merge_request)
+ end
+
+ def assign_to_closing_issues_count
# rubocop: disable CodeReuse/ServiceClass
issues = MergeRequests::AssignIssuesService.new(project: project,
current_user: current_user,
@@ -157,14 +161,7 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
merge_request: merge_request,
closes_issues: closing_issues
}).assignable_issues
- path = assign_related_issues_project_merge_request_path(project, merge_request)
- if issues.present?
- if issues.count > 1
- link_to _('Assign yourself to these issues'), path, method: :post
- else
- link_to _('Assign yourself to this issue'), path, method: :post
- end
- end
+ issues.count
# rubocop: enable CodeReuse/ServiceClass
end
diff --git a/app/serializers/merge_request_widget_entity.rb b/app/serializers/merge_request_widget_entity.rb
index b9c71e6d97b..21ab20747d0 100644
--- a/app/serializers/merge_request_widget_entity.rb
+++ b/app/serializers/merge_request_widget_entity.rb
@@ -104,7 +104,11 @@ class MergeRequestWidgetEntity < Grape::Entity
# include them if they are explicitly requested on first load.
expose :issues_links, if: -> (_, opts) { opts[:issues_links] } do
expose :assign_to_closing do |merge_request|
- presenter(merge_request).assign_to_closing_issues_link
+ presenter(merge_request).assign_to_closing_issues_path
+ end
+
+ expose :assign_to_closing_count do |merge_request|
+ presenter(merge_request).assign_to_closing_issues_count
end
expose :closing do |merge_request|
diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml
index 7256b9ed467..512a4185bee 100644
--- a/app/views/layouts/header/_default.html.haml
+++ b/app/views/layouts/header/_default.html.haml
@@ -79,7 +79,8 @@
%li.dropdown-header
= _('Merge requests')
- if Feature.enabled?(:mr_attention_requests, default_enabled: :yaml)
- %li
+ %li#js-need-attention-nav
+ #js-need-attention-nav-onboarding
= link_to attention_requested_mrs_dashboard_path, class: 'gl-display-flex! gl-align-items-center js-prefetch-document' do
= _('Need your attention')
= gl_badge_tag user_merge_requests_counts[:attention_requested_count], { size: :sm, variant: user_merge_requests_counts[:attention_requested_count] == 0 ? :neutral : :warning }, { class: 'merge-request-badge gl-ml-auto js-attention-count' }
diff --git a/app/views/projects/merge_requests/show.html.haml b/app/views/projects/merge_requests/show.html.haml
index 43bcb75ebbf..008f2588dbd 100644
--- a/app/views/projects/merge_requests/show.html.haml
+++ b/app/views/projects/merge_requests/show.html.haml
@@ -92,5 +92,8 @@
#js-review-bar
+- if Feature.enabled?(:mr_attention_requests, default_enabled: :yaml)
+ #js-need-attention-sidebar-onboarding
+
= render 'projects/invite_members_modal', project: @project
= render 'shared/web_ide_path'