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>2021-12-02 12:10:59 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-12-02 12:10:59 +0300
commit78bc39880c4b06b2fbe682e0201722a11237a425 (patch)
tree00500cb71d9e86a404ec42264cc3b4992e5610ce /app
parent377b57afa8292caa96921fac7daf6279e12304de (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/environments/components/new_environments_app.vue12
-rw-r--r--app/assets/javascripts/environments/graphql/client.js2
-rw-r--r--app/assets/javascripts/environments/graphql/queries/environment_app.query.graphql (renamed from app/assets/javascripts/environments/graphql/queries/environmentApp.query.graphql)0
-rw-r--r--app/assets/javascripts/environments/graphql/queries/poll_interval.query.graphql3
-rw-r--r--app/assets/javascripts/environments/graphql/resolvers.js83
-rw-r--r--app/assets/javascripts/environments/graphql/typedefs.graphql17
-rw-r--r--app/assets/javascripts/jira_connect/branches/index.js2
-rw-r--r--app/assets/javascripts/jira_connect/subscriptions/components/app.vue4
-rw-r--r--app/assets/javascripts/jira_connect/subscriptions/components/user_link.vue67
-rw-r--r--app/assets/javascripts/jira_connect/subscriptions/index.js21
-rw-r--r--app/controllers/projects/merge_requests_controller.rb2
-rw-r--r--app/helpers/jira_connect_helper.rb3
-rw-r--r--app/helpers/system_note_helper.rb4
-rw-r--r--app/models/concerns/merge_request_reviewer_state.rb6
-rw-r--r--app/models/merge_request_assignee.rb6
-rw-r--r--app/models/merge_request_reviewer.rb6
-rw-r--r--app/models/system_note_metadata.rb1
-rw-r--r--app/services/merge_requests/toggle_attention_requested_service.rb11
-rw-r--r--app/services/system_note_service.rb8
-rw-r--r--app/services/system_notes/issuables_service.rb48
-rw-r--r--app/views/jira_connect/subscriptions/index.html.haml7
21 files changed, 251 insertions, 62 deletions
diff --git a/app/assets/javascripts/environments/components/new_environments_app.vue b/app/assets/javascripts/environments/components/new_environments_app.vue
index a5526f9cd71..bfb5689d623 100644
--- a/app/assets/javascripts/environments/components/new_environments_app.vue
+++ b/app/assets/javascripts/environments/components/new_environments_app.vue
@@ -1,6 +1,7 @@
<script>
import { GlBadge, GlTab, GlTabs } from '@gitlab/ui';
-import environmentAppQuery from '../graphql/queries/environmentApp.query.graphql';
+import environmentAppQuery from '../graphql/queries/environment_app.query.graphql';
+import pollIntervalQuery from '../graphql/queries/poll_interval.query.graphql';
import EnvironmentFolder from './new_environment_folder.vue';
export default {
@@ -13,7 +14,16 @@ export default {
apollo: {
environmentApp: {
query: environmentAppQuery,
+ pollInterval() {
+ return this.interval;
+ },
},
+ interval: {
+ query: pollIntervalQuery,
+ },
+ },
+ data() {
+ return { interval: undefined };
},
computed: {
folders() {
diff --git a/app/assets/javascripts/environments/graphql/client.js b/app/assets/javascripts/environments/graphql/client.js
index c734c2fba0c..c019b4d16f3 100644
--- a/app/assets/javascripts/environments/graphql/client.js
+++ b/app/assets/javascripts/environments/graphql/client.js
@@ -1,6 +1,6 @@
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
-import environmentApp from './queries/environmentApp.query.graphql';
+import environmentApp from './queries/environment_app.query.graphql';
import { resolvers } from './resolvers';
import typeDefs from './typedefs.graphql';
diff --git a/app/assets/javascripts/environments/graphql/queries/environmentApp.query.graphql b/app/assets/javascripts/environments/graphql/queries/environment_app.query.graphql
index faa76c0a42c..faa76c0a42c 100644
--- a/app/assets/javascripts/environments/graphql/queries/environmentApp.query.graphql
+++ b/app/assets/javascripts/environments/graphql/queries/environment_app.query.graphql
diff --git a/app/assets/javascripts/environments/graphql/queries/poll_interval.query.graphql b/app/assets/javascripts/environments/graphql/queries/poll_interval.query.graphql
new file mode 100644
index 00000000000..28afc30a0dd
--- /dev/null
+++ b/app/assets/javascripts/environments/graphql/queries/poll_interval.query.graphql
@@ -0,0 +1,3 @@
+query pollInterval {
+ interval @client
+}
diff --git a/app/assets/javascripts/environments/graphql/resolvers.js b/app/assets/javascripts/environments/graphql/resolvers.js
index 8322b806370..9bb00f92ac4 100644
--- a/app/assets/javascripts/environments/graphql/resolvers.js
+++ b/app/assets/javascripts/environments/graphql/resolvers.js
@@ -1,5 +1,12 @@
import axios from '~/lib/utils/axios_utils';
+import { s__ } from '~/locale';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+import pollIntervalQuery from './queries/poll_interval.query.graphql';
+
+const buildErrors = (errors = []) => ({
+ errors,
+ __typename: 'LocalEnvironmentErrors',
+});
const mapNestedEnvironment = (env) => ({
...convertObjectPropsToCamelCase(env, { deep: true }),
@@ -12,17 +19,27 @@ const mapEnvironment = (env) => ({
export const resolvers = (endpoint) => ({
Query: {
- environmentApp() {
- return axios.get(endpoint, { params: { nested: true } }).then((res) => ({
- availableCount: res.data.available_count,
- environments: res.data.environments.map(mapNestedEnvironment),
- reviewApp: {
- ...convertObjectPropsToCamelCase(res.data.review_app),
- __typename: 'ReviewApp',
- },
- stoppedCount: res.data.stopped_count,
- __typename: 'LocalEnvironmentApp',
- }));
+ environmentApp(_context, _variables, { cache }) {
+ return axios.get(endpoint, { params: { nested: true } }).then((res) => {
+ const interval = res.headers['poll-interval'];
+
+ if (interval) {
+ cache.writeQuery({ query: pollIntervalQuery, data: { interval } });
+ } else {
+ cache.writeQuery({ query: pollIntervalQuery, data: { interval: undefined } });
+ }
+
+ return {
+ availableCount: res.data.available_count,
+ environments: res.data.environments.map(mapNestedEnvironment),
+ reviewApp: {
+ ...convertObjectPropsToCamelCase(res.data.review_app),
+ __typename: 'ReviewApp',
+ },
+ stoppedCount: res.data.stopped_count,
+ __typename: 'LocalEnvironmentApp',
+ };
+ });
},
folder(_, { environment: { folderPath } }) {
return axios.get(folderPath, { params: { per_page: 3 } }).then((res) => ({
@@ -32,19 +49,51 @@ export const resolvers = (endpoint) => ({
__typename: 'LocalEnvironmentFolder',
}));
},
+ isLastDeployment(_, { environment }) {
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ return environment?.lastDeployment?.['last?'];
+ },
},
- Mutations: {
- stopEnvironment(_, { environment: { stopPath } }) {
- return axios.post(stopPath);
+ Mutation: {
+ stopEnvironment(_, { environment }) {
+ return axios
+ .post(environment.stopPath)
+ .then(() => buildErrors())
+ .catch(() => {
+ return buildErrors([
+ s__('Environments|An error occurred while stopping the environment, please try again'),
+ ]);
+ });
},
deleteEnvironment(_, { environment: { deletePath } }) {
return axios.delete(deletePath);
},
- rollbackEnvironment(_, { environment: { retryUrl } }) {
- return axios.post(retryUrl);
+ rollbackEnvironment(_, { environment, isLastDeployment }) {
+ return axios
+ .post(environment?.retryUrl)
+ .then(() => buildErrors())
+ .catch(() => {
+ buildErrors([
+ isLastDeployment
+ ? s__(
+ 'Environments|An error occurred while re-deploying the environment, please try again',
+ )
+ : s__(
+ 'Environments|An error occurred while rolling back the environment, please try again',
+ ),
+ ]);
+ });
},
cancelAutoStop(_, { environment: { autoStopPath } }) {
- return axios.post(autoStopPath);
+ return axios
+ .post(autoStopPath)
+ .then(() => buildErrors())
+ .catch((err) =>
+ buildErrors([
+ err?.response?.data?.message ||
+ s__('Environments|An error occurred while canceling the auto stop, please try again'),
+ ]),
+ );
},
},
});
diff --git a/app/assets/javascripts/environments/graphql/typedefs.graphql b/app/assets/javascripts/environments/graphql/typedefs.graphql
index 49ea719449e..f0172765ebe 100644
--- a/app/assets/javascripts/environments/graphql/typedefs.graphql
+++ b/app/assets/javascripts/environments/graphql/typedefs.graphql
@@ -33,3 +33,20 @@ type LocalEnvironmentApp {
environments: [NestedLocalEnvironment!]!
reviewApp: ReviewApp!
}
+
+type LocalErrors {
+ errors: [String!]!
+}
+
+extend type Query {
+ environmentApp: LocalEnvironmentApp
+ folder(environment: NestedLocalEnvironment): LocalEnvironmentFolder
+ isLastDeployment: Boolean
+}
+
+extend type Mutation {
+ stopEnvironment(environment: LocalEnvironment): LocalErrors
+ deleteEnvironment(environment: LocalEnvironment): LocalErrors
+ rollbackEnvironment(environment: LocalEnvironment): LocalErrors
+ cancelAutoStop(environment: LocalEnvironment): LocalErrors
+}
diff --git a/app/assets/javascripts/jira_connect/branches/index.js b/app/assets/javascripts/jira_connect/branches/index.js
index 04510fcff4b..a9a56a6362e 100644
--- a/app/assets/javascripts/jira_connect/branches/index.js
+++ b/app/assets/javascripts/jira_connect/branches/index.js
@@ -5,7 +5,7 @@ import createDefaultClient from '~/lib/graphql';
Vue.use(VueApollo);
-export default async function initJiraConnectBranches() {
+export default function initJiraConnectBranches() {
const el = document.querySelector('.js-jira-connect-create-branch');
if (!el) {
return null;
diff --git a/app/assets/javascripts/jira_connect/subscriptions/components/app.vue b/app/assets/javascripts/jira_connect/subscriptions/components/app.vue
index c0504cbb645..7fd4cc38f11 100644
--- a/app/assets/javascripts/jira_connect/subscriptions/components/app.vue
+++ b/app/assets/javascripts/jira_connect/subscriptions/components/app.vue
@@ -7,6 +7,7 @@ import { SET_ALERT } from '../store/mutation_types';
import SubscriptionsList from './subscriptions_list.vue';
import AddNamespaceButton from './add_namespace_button.vue';
import SignInButton from './sign_in_button.vue';
+import UserLink from './user_link.vue';
export default {
name: 'JiraConnectApp',
@@ -18,6 +19,7 @@ export default {
SubscriptionsList,
AddNamespaceButton,
SignInButton,
+ UserLink,
},
inject: {
usersPath: {
@@ -74,6 +76,8 @@ export default {
</template>
</gl-alert>
+ <user-link :user-signed-in="userSignedIn" :has-subscriptions="hasSubscriptions" />
+
<h2 class="gl-text-center gl-mb-7">{{ s__('JiraService|GitLab for Jira Configuration') }}</h2>
<div class="jira-connect-app-body gl-mx-auto gl-px-5 gl-mb-7">
<template v-if="hasSubscriptions">
diff --git a/app/assets/javascripts/jira_connect/subscriptions/components/user_link.vue b/app/assets/javascripts/jira_connect/subscriptions/components/user_link.vue
new file mode 100644
index 00000000000..fad3d2616d8
--- /dev/null
+++ b/app/assets/javascripts/jira_connect/subscriptions/components/user_link.vue
@@ -0,0 +1,67 @@
+<script>
+import { GlLink, GlSprintf } from '@gitlab/ui';
+import { __ } from '~/locale';
+import { getGitlabSignInURL } from '~/jira_connect/subscriptions/utils';
+
+export default {
+ components: {
+ GlLink,
+ GlSprintf,
+ },
+ inject: {
+ usersPath: {
+ default: '',
+ },
+ gitlabUserPath: {
+ default: '',
+ },
+ },
+ props: {
+ userSignedIn: {
+ type: Boolean,
+ required: true,
+ },
+ hasSubscriptions: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ signInURL: '',
+ };
+ },
+ computed: {
+ gitlabUserHandle() {
+ return `@${gon.current_username}`;
+ },
+ },
+ async created() {
+ this.signInURL = await getGitlabSignInURL(this.usersPath);
+ },
+ i18n: {
+ signInText: __('Sign in to GitLab'),
+ signedInAsUserText: __('Signed in to GitLab as %{user_link}'),
+ },
+};
+</script>
+<template>
+ <div class="jira-connect-user gl-font-base">
+ <gl-sprintf v-if="userSignedIn" :message="$options.i18n.signedInAsUserText">
+ <template #user_link>
+ <gl-link data-testid="gitlab-user-link" :href="gitlabUserPath" target="_blank">
+ {{ gitlabUserHandle }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+
+ <gl-link
+ v-else-if="hasSubscriptions"
+ data-testid="sign-in-link"
+ :href="signInURL"
+ target="_blank"
+ >
+ {{ $options.i18n.signInText }}
+ </gl-link>
+ </div>
+</template>
diff --git a/app/assets/javascripts/jira_connect/subscriptions/index.js b/app/assets/javascripts/jira_connect/subscriptions/index.js
index 8a7a80d885d..cd1fc1d4455 100644
--- a/app/assets/javascripts/jira_connect/subscriptions/index.js
+++ b/app/assets/javascripts/jira_connect/subscriptions/index.js
@@ -7,25 +7,11 @@ import Translate from '~/vue_shared/translate';
import JiraConnectApp from './components/app.vue';
import createStore from './store';
-import { getGitlabSignInURL, sizeToParent } from './utils';
+import { sizeToParent } from './utils';
const store = createStore();
-/**
- * Add `return_to` query param to all HAML-defined GitLab sign in links.
- */
-const updateSignInLinks = async () => {
- await Promise.all(
- Array.from(document.querySelectorAll('.js-jira-connect-sign-in')).map(async (el) => {
- const updatedLink = await getGitlabSignInURL(el.getAttribute('href'));
- el.setAttribute('href', updatedLink);
- }),
- );
-};
-
-export async function initJiraConnect() {
- await updateSignInLinks();
-
+export function initJiraConnect() {
const el = document.querySelector('.js-jira-connect-app');
if (!el) {
return null;
@@ -35,7 +21,7 @@ export async function initJiraConnect() {
Vue.use(Translate);
Vue.use(GlFeatureFlagsPlugin);
- const { groupsPath, subscriptions, subscriptionsPath, usersPath } = el.dataset;
+ const { groupsPath, subscriptions, subscriptionsPath, usersPath, gitlabUserPath } = el.dataset;
sizeToParent();
return new Vue({
@@ -46,6 +32,7 @@ export async function initJiraConnect() {
subscriptions: JSON.parse(subscriptions),
subscriptionsPath,
usersPath,
+ gitlabUserPath,
},
render(createElement) {
return createElement(JiraConnectApp);
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 3bec7928058..89949b82ae5 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -282,7 +282,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
if merge_request.errors.present?
render json: @merge_request.errors, status: :bad_request
else
- render json: serializer.represent(@merge_request, serializer: 'basic')
+ render json: serializer.represent(@merge_request, serializer: params[:serializer] || 'basic')
end
end
end
diff --git a/app/helpers/jira_connect_helper.rb b/app/helpers/jira_connect_helper.rb
index 475469a6df9..9a0f0944fd1 100644
--- a/app/helpers/jira_connect_helper.rb
+++ b/app/helpers/jira_connect_helper.rb
@@ -8,7 +8,8 @@ module JiraConnectHelper
groups_path: api_v4_groups_path(params: { min_access_level: Gitlab::Access::MAINTAINER, skip_groups: skip_groups }),
subscriptions: subscriptions.map { |s| serialize_subscription(s) }.to_json,
subscriptions_path: jira_connect_subscriptions_path,
- users_path: current_user ? nil : jira_connect_users_path
+ users_path: current_user ? nil : jira_connect_users_path, # users_path is used to determine if user is signed in
+ gitlab_user_path: current_user ? user_path(current_user) : nil
}
end
diff --git a/app/helpers/system_note_helper.rb b/app/helpers/system_note_helper.rb
index 1d8b657025c..f2e1d158c2d 100644
--- a/app/helpers/system_note_helper.rb
+++ b/app/helpers/system_note_helper.rb
@@ -40,7 +40,9 @@ module SystemNoteHelper
'new_alert_added' => 'warning',
'severity' => 'information-o',
'cloned' => 'documents',
- 'issue_type' => 'pencil-square'
+ 'issue_type' => 'pencil-square',
+ 'attention_requested' => 'user',
+ 'attention_request_removed' => 'user'
}.freeze
def system_note_icon_name(note)
diff --git a/app/models/concerns/merge_request_reviewer_state.rb b/app/models/concerns/merge_request_reviewer_state.rb
index 216a3a0bd64..5859f43a70c 100644
--- a/app/models/concerns/merge_request_reviewer_state.rb
+++ b/app/models/concerns/merge_request_reviewer_state.rb
@@ -15,11 +15,5 @@ module MergeRequestReviewerState
inclusion: { in: self.states.keys }
after_initialize :set_state, unless: :persisted?
-
- def set_state
- if Feature.enabled?(:mr_attention_requests, self.merge_request&.project, default_enabled: :yaml)
- self.state = :attention_requested
- end
- end
end
end
diff --git a/app/models/merge_request_assignee.rb b/app/models/merge_request_assignee.rb
index fd8e5860040..77b46fa50f4 100644
--- a/app/models/merge_request_assignee.rb
+++ b/app/models/merge_request_assignee.rb
@@ -10,6 +10,12 @@ class MergeRequestAssignee < ApplicationRecord
scope :in_projects, ->(project_ids) { joins(:merge_request).where(merge_requests: { target_project_id: project_ids }) }
+ def set_state
+ if Feature.enabled?(:mr_attention_requests, self.merge_request&.project, default_enabled: :yaml)
+ self.state = MergeRequestReviewer.find_by(user_id: self.user_id, merge_request_id: self.merge_request_id)&.state || :attention_requested
+ end
+ end
+
def cache_key
[model_name.cache_key, id, state, assignee.cache_key]
end
diff --git a/app/models/merge_request_reviewer.rb b/app/models/merge_request_reviewer.rb
index 4abf0fa09f0..8c75fb2e4e6 100644
--- a/app/models/merge_request_reviewer.rb
+++ b/app/models/merge_request_reviewer.rb
@@ -6,6 +6,12 @@ class MergeRequestReviewer < ApplicationRecord
belongs_to :merge_request
belongs_to :reviewer, class_name: 'User', foreign_key: :user_id, inverse_of: :merge_request_reviewers
+ def set_state
+ if Feature.enabled?(:mr_attention_requests, self.merge_request&.project, default_enabled: :yaml)
+ self.state = MergeRequestAssignee.find_by(user_id: self.user_id, merge_request_id: self.merge_request_id)&.state || :attention_requested
+ end
+ end
+
def cache_key
[model_name.cache_key, id, state, reviewer.cache_key]
end
diff --git a/app/models/system_note_metadata.rb b/app/models/system_note_metadata.rb
index 749b9dce97c..7b13109dbc4 100644
--- a/app/models/system_note_metadata.rb
+++ b/app/models/system_note_metadata.rb
@@ -24,6 +24,7 @@ class SystemNoteMetadata < ApplicationRecord
opened closed merged duplicate locked unlocked outdated reviewer
tag due_date pinned_embed cherry_pick health_status approved unapproved
status alert_issue_added relate unrelate new_alert_added severity
+ attention_requested attention_request_removed
].freeze
validates :note, presence: true, unless: :importing?
diff --git a/app/services/merge_requests/toggle_attention_requested_service.rb b/app/services/merge_requests/toggle_attention_requested_service.rb
index 4e36ae065bb..fd24e87454c 100644
--- a/app/services/merge_requests/toggle_attention_requested_service.rb
+++ b/app/services/merge_requests/toggle_attention_requested_service.rb
@@ -19,7 +19,10 @@ module MergeRequests
update_state(assignee)
if reviewer&.attention_requested? || assignee&.attention_requested?
+ create_attention_request_note
notity_user
+ else
+ create_remove_attention_request_note
end
success
@@ -35,6 +38,14 @@ module MergeRequests
todo_service.create_attention_requested_todo(merge_request, current_user, user)
end
+ def create_attention_request_note
+ SystemNoteService.request_attention(merge_request, merge_request.project, current_user, user)
+ end
+
+ def create_remove_attention_request_note
+ SystemNoteService.remove_attention_request(merge_request, merge_request.project, current_user, user)
+ end
+
def assignee
merge_request.find_assignee(user)
end
diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb
index e98dfb872fe..0d13c73d49d 100644
--- a/app/services/system_note_service.rb
+++ b/app/services/system_note_service.rb
@@ -115,6 +115,14 @@ module SystemNoteService
::SystemNotes::IssuablesService.new(noteable: noteable, project: project, author: author).change_status(status, source)
end
+ def request_attention(noteable, project, author, user)
+ ::SystemNotes::IssuablesService.new(noteable: noteable, project: project, author: author).request_attention(user)
+ end
+
+ def remove_attention_request(noteable, project, author, user)
+ ::SystemNotes::IssuablesService.new(noteable: noteable, project: project, author: author).remove_attention_request(user)
+ end
+
# Called when 'merge when pipeline succeeds' is executed
def merge_when_pipeline_succeeds(noteable, project, author, sha)
::SystemNotes::MergeRequestsService.new(noteable: noteable, project: project, author: author).merge_when_pipeline_succeeds(sha)
diff --git a/app/services/system_notes/issuables_service.rb b/app/services/system_notes/issuables_service.rb
index 92540f957c8..d33dcd65589 100644
--- a/app/services/system_notes/issuables_service.rb
+++ b/app/services/system_notes/issuables_service.rb
@@ -323,23 +323,34 @@ module SystemNotes
existing_mentions_for(mentioned_in, noteable, notes).exists?
end
- # Called when a Noteable has been marked as a duplicate of another Issue
+ # Called when a user's attention has been requested for a Notable
#
- # canonical_issue - Issue that this is a duplicate of
+ # user - User's whos attention has been requested
#
# Example Note text:
#
- # "marked this issue as a duplicate of #1234"
- #
- # "marked this issue as a duplicate of other_project#5678"
+ # "requested attention from @eli.wisoky"
#
# Returns the created Note object
- def mark_duplicate_issue(canonical_issue)
- body = "marked this issue as a duplicate of #{canonical_issue.to_reference(project)}"
+ def request_attention(user)
+ body = "requested attention from #{user.to_reference}"
- issue_activity_counter.track_issue_marked_as_duplicate_action(author: author) if noteable.is_a?(Issue)
+ create_note(NoteSummary.new(noteable, project, author, body, action: 'attention_requested'))
+ end
- create_note(NoteSummary.new(noteable, project, author, body, action: 'duplicate'))
+ # Called when a user's attention request has been removed for a Notable
+ #
+ # user - User's whos attention request has been removed
+ #
+ # Example Note text:
+ #
+ # "removed attention request from @eli.wisoky"
+ #
+ # Returns the created Note object
+ def remove_attention_request(user)
+ body = "removed attention request from #{user.to_reference}"
+
+ create_note(NoteSummary.new(noteable, project, author, body, action: 'attention_request_removed'))
end
# Called when a Noteable has been marked as the canonical Issue of a duplicate
@@ -358,6 +369,25 @@ module SystemNotes
create_note(NoteSummary.new(noteable, project, author, body, action: 'duplicate'))
end
+ # Called when a Noteable has been marked as a duplicate of another Issue
+ #
+ # canonical_issue - Issue that this is a duplicate of
+ #
+ # Example Note text:
+ #
+ # "marked this issue as a duplicate of #1234"
+ #
+ # "marked this issue as a duplicate of other_project#5678"
+ #
+ # Returns the created Note object
+ def mark_duplicate_issue(canonical_issue)
+ body = "marked this issue as a duplicate of #{canonical_issue.to_reference(project)}"
+
+ issue_activity_counter.track_issue_marked_as_duplicate_action(author: author) if noteable.is_a?(Issue)
+
+ create_note(NoteSummary.new(noteable, project, author, body, action: 'duplicate'))
+ end
+
def add_email_participants(body)
create_note(NoteSummary.new(noteable, project, author, body))
end
diff --git a/app/views/jira_connect/subscriptions/index.html.haml b/app/views/jira_connect/subscriptions/index.html.haml
index be2be7288f8..d92c30c8840 100644
--- a/app/views/jira_connect/subscriptions/index.html.haml
+++ b/app/views/jira_connect/subscriptions/index.html.haml
@@ -1,13 +1,6 @@
%header.jira-connect-header.gl-display-flex.gl-align-items-center.gl-justify-content-center.gl-px-5.gl-border-b-solid.gl-border-b-gray-100.gl-border-b-1.gl-bg-white
= link_to brand_header_logo, Gitlab.config.gitlab.url, target: '_blank', rel: 'noopener noreferrer'
-.jira-connect-user.gl-font-base
- - if current_user
- - user_link = link_to(current_user.to_reference, jira_connect_users_path, target: '_blank', rel: 'noopener noreferrer', class: 'js-jira-connect-sign-in')
- = _('Signed in to GitLab as %{user_link}').html_safe % { user_link: user_link }
- - elsif @subscriptions.present?
- = link_to _('Sign in to GitLab'), jira_connect_users_path, target: '_blank', rel: 'noopener noreferrer', class: 'js-jira-connect-sign-in'
-
%main.jira-connect-app.gl-px-5.gl-pt-7.gl-mx-auto
.js-jira-connect-app{ data: jira_connect_app_data(@subscriptions) }