summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/vue_merge_request_widget
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/vue_merge_request_widget')
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/added_commit_message.vue43
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue17
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue22
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/extensions/child_content.vue14
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/extensions/index.js1
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/extensions/status_icon.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/extensions/utils.js22
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue77
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_how_to_merge_modal.vue8
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue5
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_related_links.vue27
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.vue4
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue7
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue8
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merging.vue4
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue57
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/extensions/code_quality/index.js13
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/extensions/test_report/constants.js30
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/extensions/test_report/index.js84
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/extensions/test_report/utils.js45
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue25
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/queries/states/ready_to_merge.fragment.graphql1
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js6
25 files changed, 378 insertions, 148 deletions
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/added_commit_message.vue b/app/assets/javascripts/vue_merge_request_widget/components/added_commit_message.vue
index 492e68b636f..437d035fbf5 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/added_commit_message.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/added_commit_message.vue
@@ -12,6 +12,11 @@ export default {
},
mixins: [glFeatureFlagMixin()],
props: {
+ state: {
+ type: String,
+ required: false,
+ default: '',
+ },
isSquashEnabled: {
type: Boolean,
required: false,
@@ -30,8 +35,16 @@ export default {
type: String,
required: true,
},
+ mergeCommitSha: {
+ type: String,
+ required: false,
+ default: '',
+ },
},
computed: {
+ isMerged() {
+ return this.state === 'merged';
+ },
targetBranchEscaped() {
return escape(this.targetBranch);
},
@@ -39,6 +52,22 @@ export default {
return n__('%d commit', '%d commits', this.isSquashEnabled ? 1 : this.commitsCount);
},
message() {
+ if (this.glFeatures.restructuredMrWidget) {
+ if (this.state === 'closed') {
+ return s__('mrWidgetCommitsAdded|The changes were not merged into %{targetBranch}.');
+ } else if (this.isMerged) {
+ return s__(
+ 'mrWidgetCommitsAdded|Changes merged into %{targetBranch} with %{mergeCommitSha}%{squashedCommits}.',
+ );
+ }
+
+ return this.isFastForwardEnabled
+ ? s__('mrWidgetCommitsAdded|%{commitCount} will be added to %{targetBranch}.')
+ : s__(
+ 'mrWidgetCommitsAdded|%{commitCount} and %{mergeCommitCount} will be added to %{targetBranch}%{squashedCommits}.',
+ );
+ }
+
return this.isFastForwardEnabled
? s__('mrWidgetCommitsAdded|Adds %{commitCount} to %{targetBranch}.')
: s__(
@@ -48,6 +77,13 @@ export default {
textDecorativeComponent() {
return this.glFeatures.restructuredMrWidget ? 'span' : 'strong';
},
+ squashCommitMessage() {
+ if (this.isMerged) {
+ return s__('mergedCommitsAdded|(commits were squashed)');
+ }
+
+ return n__('(squashes %d commit)', '(squashes %d commits)', this.commitsCount);
+ },
},
mergeCommitCount,
};
@@ -69,9 +105,14 @@ export default {
</template>
<template #squashedCommits>
<template v-if="glFeatures.restructuredMrWidget && isSquashEnabled">
- {{ n__('(squashes %d commit)', '(squashes %d commits)', commitsCount) }}</template
+ {{ squashCommitMessage }}</template
></template
>
+ <template #mergeCommitSha>
+ <template v-if="glFeatures.restructuredMrWidget"
+ ><span class="label-branch">{{ mergeCommitSha }}</span></template
+ >
+ </template>
</gl-sprintf>
</span>
</template>
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 24cefd63ce3..e7d5e4086bc 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
@@ -2,8 +2,11 @@
import { GlButton } from '@gitlab/ui';
import createFlash from '~/flash';
import { BV_SHOW_MODAL } from '~/lib/utils/constants';
-import { s__ } from '~/locale';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import { s__, __ } from '~/locale';
import sidebarEventHub from '~/sidebar/event_hub';
+import showToast from '~/vue_shared/plugins/global_toast';
+import SidebarMediator from '~/sidebar/sidebar_mediator';
import eventHub from '../../event_hub';
import approvalsMixin from '../../mixins/approvals';
import MrWidgetContainer from '../mr_widget_container.vue';
@@ -21,7 +24,7 @@ export default {
ApprovalsSummaryOptional,
GlButton,
},
- mixins: [approvalsMixin],
+ mixins: [approvalsMixin, glFeatureFlagsMixin()],
props: {
mr: {
type: Object,
@@ -171,6 +174,14 @@ export default {
return serviceFn()
.then((data) => {
this.mr.setApprovals(data);
+
+ if (
+ this.glFeatures.mrAttentionRequests &&
+ SidebarMediator.singleton?.store.currentUserHasAttention
+ ) {
+ showToast(__('Approved. Your attention request was removed.'));
+ }
+
eventHub.$emit('MRWidgetUpdateRequested');
eventHub.$emit('ApprovalUpdated');
sidebarEventHub.$emit('removeCurrentUserAttentionRequested');
@@ -217,7 +228,7 @@ export default {
<slot
:is-approving="isApproving"
:approve-with-auth="approveWithAuth"
- :hasApproval-auth-error="hasApprovalAuthError"
+ :has-approval-auth-error="hasApprovalAuthError"
></slot>
</template>
</div>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue b/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue
index f1b89c42fb5..0bc17de638b 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue
@@ -47,6 +47,8 @@ export default {
fullData: [],
isCollapsed: true,
showFade: false,
+ modalData: undefined,
+ modalName: undefined,
};
},
computed: {
@@ -116,6 +118,9 @@ export default {
return summary;
},
+ modalId() {
+ return this.modalName || `modal${this.$options.name}`;
+ },
},
watch: {
isCollapsed(newVal) {
@@ -249,7 +254,7 @@ export default {
class="media-body gl-display-flex gl-flex-direction-row! gl-align-self-center"
data-testid="widget-extension-top-level"
>
- <div class="gl-flex-grow-1">
+ <div class="gl-flex-grow-1" data-testid="widget-extension-top-level-summary">
<template v-if="isLoadingSummary">{{ widgetLoadingText }}</template>
<template v-else-if="hasFetchError">{{ widgetErrorText }}</template>
<div v-else>
@@ -306,12 +311,20 @@ export default {
data-testid="extension-list-item"
>
<gl-intersection-observer
- :options="{ rootMargin: '100px', thresholds: 0.1 }"
+ :options="/* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */ {
+ rootMargin: '100px',
+ thresholds: 0.1,
+ } /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */"
class="gl-w-full"
@appear="appear(index)"
@disappear="disappear(index)"
>
- <child-content :data="item" :widget-label="widgetLabel" :level="2" />
+ <child-content
+ :data="item"
+ :widget-label="widgetLabel"
+ :modal-id="modalId"
+ :level="2"
+ />
</gl-intersection-observer>
</div>
</dynamic-scroller-item>
@@ -322,5 +335,8 @@ export default {
class="fade mr-extenson-scrim gl-absolute gl-left-0 gl-bottom-0 gl-w-full gl-h-7 gl-pointer-events-none"
></div>
</div>
+ <div v-if="$options.modalComponent && modalData">
+ <component :is="$options.modalComponent" :modal-id="modalId" v-bind="modalData" />
+ </div>
</section>
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/extensions/child_content.vue b/app/assets/javascripts/vue_merge_request_widget/components/extensions/child_content.vue
index 5cfee21dd5e..0ca4c92a5ae 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/extensions/child_content.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/extensions/child_content.vue
@@ -1,5 +1,5 @@
<script>
-import { GlBadge, GlLink, GlSafeHtmlDirective } from '@gitlab/ui';
+import { GlBadge, GlLink, GlSafeHtmlDirective, GlModalDirective } from '@gitlab/ui';
import StatusIcon from './status_icon.vue';
import Actions from './actions.vue';
import { generateText } from './utils';
@@ -14,6 +14,7 @@ export default {
},
directives: {
SafeHtml: GlSafeHtmlDirective,
+ GlModal: GlModalDirective,
},
props: {
data: {
@@ -24,6 +25,11 @@ export default {
type: String,
required: true,
},
+ modalId: {
+ type: String,
+ required: false,
+ default: null,
+ },
level: {
type: Number,
required: true,
@@ -63,6 +69,11 @@ export default {
<div v-if="data.link">
<gl-link :href="data.link.href">{{ data.link.text }}</gl-link>
</div>
+ <div v-if="data.modal">
+ <gl-link v-gl-modal="modalId" @click="data.modal.onClick">
+ {{ data.modal.text }}
+ </gl-link>
+ </div>
<div v-if="data.supportingText">
<p v-safe-html="generateText(data.supportingText)" class="gl-m-0"></p>
</div>
@@ -87,6 +98,7 @@ export default {
:key="childData.id"
:data="childData"
:widget-label="widgetLabel"
+ :modal-id="modalId"
:level="3"
data-testid="child-content"
/>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/extensions/index.js b/app/assets/javascripts/vue_merge_request_widget/components/extensions/index.js
index 8438f3492b2..65273678fb9 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/extensions/index.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/extensions/index.js
@@ -14,6 +14,7 @@ export const registerExtension = (extension) => {
i18n: extension.i18n,
expandEvent: extension.expandEvent,
enablePolling: extension.enablePolling,
+ modalComponent: extension.modalComponent,
computed: {
...Object.keys(extension.computed).reduce(
(acc, computedKey) => ({
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/extensions/status_icon.vue b/app/assets/javascripts/vue_merge_request_widget/components/extensions/status_icon.vue
index 01d8de132e7..456a1f17aae 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/extensions/status_icon.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/extensions/status_icon.vue
@@ -49,7 +49,7 @@ export default {
]"
class="gl-rounded-full gl-mr-3 gl-relative gl-p-2"
>
- <gl-loading-icon v-if="isLoading" size="md" inline class="gl-display-block" />
+ <gl-loading-icon v-if="isLoading" size="lg" inline class="gl-display-block" />
<gl-icon
v-else
:name="$options.EXTENSION_ICON_NAMES[iconName]"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/extensions/utils.js b/app/assets/javascripts/vue_merge_request_widget/components/extensions/utils.js
index 5fba070f79c..cba12507eba 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/extensions/utils.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/extensions/utils.js
@@ -35,9 +35,7 @@ const textStyleTags = {
[getStartTag('small')]: '<span class="gl-font-sm gl-text-gray-700">',
};
-export const generateText = (text) => {
- if (typeof text !== 'string') return null;
-
+const createText = (text) => {
return text
.replace(
new RegExp(
@@ -60,3 +58,21 @@ export const generateText = (text) => {
)
.replace(/%{([a-z]|_)+}/g, ''); // Filter out any tags we don't know about
};
+
+export const generateText = (text) => {
+ if (typeof text === 'string') {
+ return createText(text);
+ } else if (
+ typeof text === 'object' &&
+ typeof text.text === 'string' &&
+ typeof text.href === 'string'
+ ) {
+ return createText(
+ `${
+ text.prependText ? `${text.prependText} ` : ''
+ }<a class="gl-text-decoration-underline" href="${text.href}">${text.text}</a>`,
+ );
+ }
+
+ return null;
+};
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue
index 8cdaa3316ee..e1d88099580 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue
@@ -1,9 +1,5 @@
<script>
import {
- GlButton,
- GlDropdown,
- GlDropdownSectionHeader,
- GlDropdownItem,
GlLink,
GlTooltipDirective,
GlModalDirective,
@@ -14,8 +10,6 @@ import { constructWebIDEPath } from '~/lib/utils/url_utility';
import { s__ } from '~/locale';
import clipboardButton from '~/vue_shared/components/clipboard_button.vue';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
-import WebIdeLink from '~/vue_shared/components/web_ide_link.vue';
-import MrWidgetHowToMergeModal from './mr_widget_how_to_merge_modal.vue';
import MrWidgetIcon from './mr_widget_icon.vue';
export default {
@@ -24,14 +18,8 @@ export default {
clipboardButton,
TooltipOnTruncate,
MrWidgetIcon,
- MrWidgetHowToMergeModal,
- GlButton,
- GlDropdown,
- GlDropdownSectionHeader,
- GlDropdownItem,
GlLink,
GlSprintf,
- WebIdeLink,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -107,71 +95,6 @@ export default {
</gl-sprintf>
</div>
</div>
-
- <div class="branch-actions d-flex">
- <template v-if="mr.isOpen">
- <web-ide-link
- v-if="!mr.sourceBranchRemoved"
- :show-edit-button="false"
- :show-web-ide-button="true"
- :web-ide-url="webIdePath"
- :web-ide-text="$options.i18n.webIdeText"
- :show-gitpod-button="mr.showGitpodButton"
- :gitpod-url="mr.gitpodUrl"
- :gitpod-enabled="mr.gitpodEnabled"
- :user-preferences-gitpod-path="mr.userPreferencesGitpodPath"
- :user-profile-enable-gitpod-path="mr.userProfileEnableGitpodPath"
- :gitpod-text="$options.i18n.gitpodText"
- class="gl-display-none gl-md-display-inline-block gl-mr-3"
- data-placement="bottom"
- tabindex="0"
- data-qa-selector="open_in_web_ide_button"
- />
- <gl-button
- v-gl-modal-directive="'modal-merge-info'"
- :disabled="mr.sourceBranchRemoved"
- class="js-check-out-branch gl-mr-3"
- >
- {{ s__('mrWidget|Check out branch') }}
- </gl-button>
- <mr-widget-how-to-merge-modal
- :is-fork="isFork"
- :can-merge="mr.canMerge"
- :source-branch="mr.sourceBranch"
- :source-project="mr.sourceProject"
- :source-project-path="mr.sourceProjectFullPath"
- :target-branch="mr.targetBranch"
- :source-project-default-url="mr.sourceProjectDefaultUrl"
- :reviewing-docs-path="mr.reviewingDocsPath"
- />
- </template>
- <gl-dropdown
- v-gl-tooltip
- :title="__('Download as')"
- :aria-label="__('Download as')"
- icon="download"
- right
- data-qa-selector="download_dropdown"
- >
- <gl-dropdown-section-header>{{ __('Download as') }}</gl-dropdown-section-header>
- <gl-dropdown-item
- :href="mr.emailPatchesPath"
- class="js-download-email-patches"
- download
- data-qa-selector="download_email_patches_menu_item"
- >
- {{ s__('mrWidget|Email patches') }}
- </gl-dropdown-item>
- <gl-dropdown-item
- :href="mr.plainDiffPath"
- class="js-download-plain-diff"
- download
- data-qa-selector="download_plain_diff_menu_item"
- >
- {{ s__('mrWidget|Plain diff') }}
- </gl-dropdown-item>
- </gl-dropdown>
- </div>
</div>
</div>
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_how_to_merge_modal.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_how_to_merge_modal.vue
index e906b8c3b59..c2a3ae361ca 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_how_to_merge_modal.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_how_to_merge_modal.vue
@@ -112,11 +112,19 @@ export default {
return escapeShellString(this.sourceBranch);
},
},
+ mounted() {
+ document.addEventListener('click', (e) => {
+ if (e.target.closest('.js-check-out-modal-trigger')) {
+ this.$refs.modal.show();
+ }
+ });
+ },
};
</script>
<template>
<gl-modal
+ ref="modal"
modal-id="modal-merge-info"
:no-enforce-focus="true"
:title="$options.i18n.title"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
index c0b80eef082..3b3b46e9772 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
@@ -276,12 +276,11 @@ export default {
</div>
</div>
<div>
- <span class="mr-widget-pipeline-graph">
- <span class="stage-cell">
+ <span class="gl-align-items-center gl-display-inline-flex mr-widget-pipeline-graph">
+ <span class="gl-align-items-center gl-display-inline-flex gl-flex-wrap stage-cell">
<linked-pipelines-mini-list v-if="triggeredBy.length" :triggered-by="triggeredBy" />
<pipeline-mini-graph
v-if="hasStages"
- class="gl-display-inline-block"
stages-class="mr-widget-pipeline-stages"
:stages="pipeline.details.stages"
:is-merge-train="isMergeTrain"
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 2cef37d5c2e..b8a1f89d232 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, GlLink } from '@gitlab/ui';
+import { GlSafeHtmlDirective as SafeHtml, GlLink, GlSprintf } from '@gitlab/ui';
import { s__, n__ } from '~/locale';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
@@ -10,6 +10,7 @@ export default {
},
components: {
GlLink,
+ GlSprintf,
},
mixins: [glFeatureFlagMixin()],
props: {
@@ -28,6 +29,16 @@ export default {
required: false,
default: true,
},
+ divergedCommitsCount: {
+ type: Number,
+ required: false,
+ default: 0,
+ },
+ targetBranchPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
},
computed: {
closesText() {
@@ -81,5 +92,19 @@ export default {
}}</gl-link>
</span>
</p>
+ <div
+ v-if="
+ divergedCommitsCount > 0 && glFeatures.updatedMrHeader && !glFeatures.restructuredMrWidget
+ "
+ class="diverged-commits-count"
+ >
+ <gl-sprintf :message="s__('mrWidget|The source branch is %{link} the target branch')">
+ <template #link>
+ <gl-link :href="targetBranchPath">{{
+ n__('%d commit behind', '%d commits behind', divergedCommitsCount)
+ }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </div>
</section>
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue
index 9499603163b..7ff1eb6e73a 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue
@@ -46,7 +46,7 @@ export default {
<gl-button
v-if="!glFeatures.restructuredMrWidget && showDisabledButton"
category="primary"
- variant="success"
+ variant="confirm"
data-testid="disabled-merge-button"
:disabled="true"
>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue
index a44caf886a4..aabbeac564a 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue
@@ -175,7 +175,7 @@ export default {
{{ cancelButtonText }}
</gl-button>
</h4>
- <section class="mr-info-list">
+ <section v-if="!glFeatures.restructuredMrWidget" class="mr-info-list">
<p v-if="shouldRemoveSourceBranch">
{{ s__('mrWidget|Deletes the source branch') }}
</p>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.vue
index 6d5ca58aa20..d50e52f5ac1 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.vue
@@ -1,4 +1,5 @@
<script>
+import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import MrWidgetAuthorTime from '../mr_widget_author_time.vue';
import statusIcon from '../mr_widget_status_icon.vue';
@@ -8,6 +9,7 @@ export default {
MrWidgetAuthorTime,
statusIcon,
},
+ mixins: [glFeatureFlagMixin()],
props: {
/* TODO: This is providing all store and service down when it
only needs metrics and targetBranch */
@@ -29,7 +31,7 @@ export default {
:date-readable="mr.metrics.readableClosedAt"
/>
- <section class="mr-info-list">
+ <section v-if="!glFeatures.restructuredMrWidget" class="mr-info-list">
<p>
{{ s__('mrWidget|The changes were not merged into') }}
<a :href="mr.targetBranchPath" class="label-branch"> {{ mr.targetBranch }} </a>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue
index 7435f578852..def30dacf8a 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue
@@ -1,5 +1,5 @@
<script>
-import { GlButton, GlModalDirective, GlSkeletonLoader } from '@gitlab/ui';
+import { GlButton, GlSkeletonLoader } from '@gitlab/ui';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import mergeRequestQueryVariablesMixin from '../../mixins/merge_request_query_variables';
import userPermissionsQuery from '../../queries/permissions.query.graphql';
@@ -13,9 +13,6 @@ export default {
StatusIcon,
GlButton,
},
- directives: {
- GlModalDirective,
- },
mixins: [glFeatureFlagMixin(), mergeRequestQueryVariablesMixin],
apollo: {
userPermissions: {
@@ -131,9 +128,9 @@ export default {
</gl-button>
<gl-button
v-if="canMerge"
- v-gl-modal-directive="'modal-merge-info'"
:size="glFeatures.restructuredMrWidget ? 'small' : 'medium'"
data-testid="merge-locally-button"
+ class="js-check-out-modal-trigger"
>
{{ s__('mrWidget|Resolve locally') }}
</gl-button>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue
index 84dac95ce74..bf036f562ed 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue
@@ -1,6 +1,7 @@
<script>
/* eslint-disable @gitlab/vue-require-i18n-strings */
import { GlLoadingIcon, GlButton, GlTooltipDirective, GlIcon } from '@gitlab/ui';
+import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import api from '~/api';
import createFlash from '~/flash';
import { s__, __ } from '~/locale';
@@ -22,6 +23,7 @@ export default {
GlLoadingIcon,
GlButton,
},
+ mixins: [glFeatureFlagMixin()],
props: {
mr: {
type: Object,
@@ -181,7 +183,11 @@ export default {
{{ s__('mrWidget|Delete source branch') }}
</gl-button>
</div>
- <section class="mr-info-list" data-qa-selector="merged_status_content">
+ <section
+ v-if="!glFeatures.restructuredMrWidget"
+ class="mr-info-list"
+ data-qa-selector="merged_status_content"
+ >
<p>
{{ s__('mrWidget|The changes were merged into') }}
<span class="label-branch">
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merging.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merging.vue
index 887d1aab524..b86ab69af3f 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merging.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merging.vue
@@ -1,5 +1,6 @@
<script>
import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests';
+import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import simplePoll from '~/lib/utils/simple_poll';
import MergeRequest from '~/merge_request';
import eventHub from '../../event_hub';
@@ -14,6 +15,7 @@ export default {
components: {
statusIcon,
},
+ mixins: [glFeatureFlagMixin()],
props: {
mr: {
type: Object,
@@ -88,7 +90,7 @@ export default {
{{ mergeStatus.message }}
<gl-emoji :data-name="mergeStatus.emoji" />
</h4>
- <section class="mr-info-list">
+ <section v-if="!glFeatures.restructuredMrWidget" class="mr-info-list">
<p>
{{ s__('mrWidget|Merges changes into') }}
<span class="label-branch">
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
index 4f8faeb877f..4fb95fe635c 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
@@ -322,11 +322,33 @@ export default {
},
restructuredWidgetShowMergeButtons() {
if (this.glFeatures.restructuredMrWidget) {
- return this.isMergeAllowed && this.state.userPermissions.canMerge;
+ return (
+ (this.isMergeAllowed || this.isAutoMergeAvailable) &&
+ this.state.userPermissions.canMerge &&
+ !this.mr.mergeOngoing &&
+ !this.mr.autoMergeEnabled
+ );
}
return true;
},
+ sourceBranchDeletedText() {
+ if (this.glFeatures.restructuredMrWidget) {
+ if (this.removeSourceBranch) {
+ return this.mr.state === 'merged'
+ ? __('Deleted the source branch.')
+ : __('Source branch will be deleted.');
+ }
+
+ return this.mr.state === 'merged'
+ ? __('Did not delete the source branch.')
+ : __('Source branch will not be deleted.');
+ }
+
+ return this.removeSourceBranch
+ ? __('Deletes the source branch.')
+ : __('Does not delete the source branch.');
+ },
},
mounted() {
if (this.glFeatures.mergeRequestWidgetGraphql) {
@@ -421,6 +443,8 @@ export default {
if (this.glFeatures.mergeRequestWidgetGraphql) {
this.updateGraphqlState();
}
+
+ this.isMakingRequest = false;
})
.catch(() => {
this.isMakingRequest = false;
@@ -499,6 +523,7 @@ export default {
<template>
<div
+ data-testid="ready_to_merge_state"
:class="{
'gl-border-t-1 gl-border-t-solid gl-border-gray-100 gl-bg-gray-10 gl-pl-7 gl-rounded-bottom-left-base gl-rounded-bottom-right-base':
glFeatures.restructuredMrWidget,
@@ -611,6 +636,7 @@ export default {
glFeatures.restructuredMrWidget && (shouldShowSquashEdit || shouldShowMergeEdit)
"
v-model="editCommitMessage"
+ data-testid="widget_edit_commit_message"
class="gl-display-flex gl-align-items-center"
>
{{ __('Edit commit message') }}
@@ -686,25 +712,36 @@ export default {
v-if="!restructuredWidgetShowMergeButtons"
class="gl-w-full gl-order-n1 gl-text-gray-500"
>
- <strong>
+ <strong v-if="mr.state !== 'closed'">
{{ __('Merge details') }}
</strong>
<ul class="gl-pl-4 gl-m-0">
+ <li
+ v-if="mr.divergedCommitsCount > 0 && glFeatures.updatedMrHeader"
+ class="gl-line-height-normal"
+ >
+ <gl-sprintf
+ :message="s__('mrWidget|The source branch is %{link} the target branch')"
+ >
+ <template #link>
+ <gl-link :href="mr.targetBranchPath">{{
+ n__('%d commit behind', '%d commits behind', mr.divergedCommitsCount)
+ }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </li>
<li class="gl-line-height-normal">
<added-commit-message
+ :state="mr.state"
+ :merge-commit-sha="mr.shortMergeCommitSha"
:is-squash-enabled="squashBeforeMerge"
:is-fast-forward-enabled="!shouldShowMergeEdit"
:commits-count="commitsCount"
:target-branch="stateData.targetBranch"
/>
</li>
- <li class="gl-line-height-normal">
- <template v-if="removeSourceBranch">
- {{ __('Deletes the source branch.') }}
- </template>
- <template v-else>
- {{ __('Does not delete the source branch.') }}
- </template>
+ <li v-if="mr.state !== 'closed'" class="gl-line-height-normal">
+ {{ sourceBranchDeletedText }}
</li>
<li v-if="mr.relatedLinks" class="gl-line-height-normal">
<related-links
@@ -733,6 +770,8 @@ export default {
:state="mr.state"
:related-links="mr.relatedLinks"
:show-assign-to-me="false"
+ :diverged-commits-count="mr.divergedCommitsCount"
+ :target-branch-path="mr.targetBranchPath"
class="mr-ready-merge-related-links gl-display-inline"
/>
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/extensions/code_quality/index.js b/app/assets/javascripts/vue_merge_request_widget/extensions/code_quality/index.js
index d32db50874c..cea8df2484b 100644
--- a/app/assets/javascripts/vue_merge_request_widget/extensions/code_quality/index.js
+++ b/app/assets/javascripts/vue_merge_request_widget/extensions/code_quality/index.js
@@ -83,14 +83,11 @@ export default {
this.collapsedData.newErrors.map((e) => {
return fullData.push({
text: `${capitalizeFirstCharacter(e.severity)} - ${e.description}`,
- subtext: sprintf(
- s__(`ciReport|in %{open_link}${e.file_path}:${e.line}%{close_link}`),
- {
- open_link: `<a class="gl-text-decoration-underline" href="${e.urlPath}">`,
- close_link: '</a>',
- },
- false,
- ),
+ subtext: {
+ prependText: s__(`ciReport|in`),
+ text: `${e.file_path}:${e.line}`,
+ href: e.urlPath,
+ },
icon: {
name: SEVERITY_ICONS_EXTENSION[e.severity],
},
diff --git a/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/constants.js b/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/constants.js
index cd5cfb6837c..23f14bea4e1 100644
--- a/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/constants.js
+++ b/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/constants.js
@@ -10,6 +10,8 @@ export const i18n = {
label: s__('Reports|Test summary'),
loading: s__('Reports|Test summary results are loading'),
error: s__('Reports|Test summary failed to load results'),
+ newHeader: s__('Reports|New'),
+ fixedHeader: s__('Reports|Fixed'),
fullReport: s__('Reports|Full report'),
noChanges: (bold) => s__(`Reports|${noText(bold)} changed test results`),
@@ -36,4 +38,32 @@ export const i18n = {
sprintf(s__('Reports|An error occurred while loading %{name} results'), { name }),
headReportParsingError: s__('Reports|Head report parsing error:'),
baseReportParsingError: s__('Reports|Base report parsing error:'),
+
+ recentFailureSummary: (recentlyFailed, failed) => {
+ if (failed < 2) {
+ return sprintf(
+ s__(
+ 'Reports|%{recentlyFailed} out of %{failed} failed test has failed more than once in the last 14 days',
+ ),
+ { recentlyFailed, failed },
+ );
+ }
+ return sprintf(
+ n__(
+ 'Reports|%{recentlyFailed} out of %{failed} failed tests has failed more than once in the last 14 days',
+ 'Reports|%{recentlyFailed} out of %{failed} failed tests have failed more than once in the last 14 days',
+ recentlyFailed,
+ ),
+ { recentlyFailed, failed },
+ );
+ },
+ recentFailureCount: (recentFailures) =>
+ sprintf(
+ n__(
+ 'Reports|Failed %{count} time in %{base_branch} in the last 14 days',
+ 'Reports|Failed %{count} times in %{base_branch} in the last 14 days',
+ recentFailures.count,
+ ),
+ recentFailures,
+ ),
};
diff --git a/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/index.js b/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/index.js
index 65d9257903f..577b2cbfc5c 100644
--- a/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/index.js
+++ b/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/index.js
@@ -1,7 +1,13 @@
import { uniqueId } from 'lodash';
import axios from '~/lib/utils/axios_utils';
import { EXTENSION_ICONS } from '../../constants';
-import { summaryTextBuilder, reportTextBuilder, reportSubTextBuilder } from './utils';
+import {
+ summaryTextBuilder,
+ reportTextBuilder,
+ reportSubTextBuilder,
+ countRecentlyFailedTests,
+ recentFailuresTextBuilder,
+} from './utils';
import { i18n, TESTS_FAILED_STATUS, ERROR_STATUS } from './constants';
export default {
@@ -18,7 +24,10 @@ export default {
if (data.hasSuiteError) {
return this.$options.i18n.error;
}
- return summaryTextBuilder(this.$options.i18n.label, data.summary);
+ return {
+ subject: summaryTextBuilder(this.$options.i18n.label, data.summary),
+ meta: recentFailuresTextBuilder(data.summary),
+ };
},
statusIcon(data) {
if (data.parsingInProgress) {
@@ -50,6 +59,10 @@ export default {
hasSuiteError: data.suites?.some((suite) => suite.status === ERROR_STATUS),
parsingInProgress: status === 204,
...data,
+ summary: {
+ recentlyFailed: countRecentlyFailedTests(data.suites),
+ ...data.summary,
+ },
},
};
});
@@ -66,17 +79,66 @@ export default {
}
return EXTENSION_ICONS.success;
},
- prepareReports() {
- return this.collapsedData.suites.map((suite) => {
+ testHeader(test, sectionHeader, index) {
+ const headers = [];
+ if (index === 0) {
+ headers.push(sectionHeader);
+ }
+ if (test.recent_failures?.count && test.recent_failures?.base_branch) {
+ headers.push(i18n.recentFailureCount(test.recent_failures));
+ }
+ return headers;
+ },
+ mapTestAsChild({ iconName, sectionHeader }) {
+ return (test, index) => {
return {
- id: uniqueId('suite-'),
- text: reportTextBuilder(suite),
- subtext: reportSubTextBuilder(suite),
- icon: {
- name: this.suiteIcon(suite),
- },
+ id: uniqueId('test-'),
+ header: this.testHeader(test, sectionHeader, index),
+ icon: { name: iconName },
+ text: test.name,
};
- });
+ };
+ },
+ prepareReports() {
+ return this.collapsedData.suites
+ .map((suite) => {
+ return {
+ ...suite,
+ summary: {
+ recentlyFailed: countRecentlyFailedTests(suite),
+ ...suite.summary,
+ },
+ };
+ })
+ .map((suite) => {
+ return {
+ id: uniqueId('suite-'),
+ text: reportTextBuilder(suite),
+ subtext: reportSubTextBuilder(suite),
+ icon: {
+ name: this.suiteIcon(suite),
+ },
+ children: [
+ ...[...suite.new_failures, ...suite.new_errors].map(
+ this.mapTestAsChild({
+ sectionHeader: i18n.newHeader,
+ iconName: EXTENSION_ICONS.failed,
+ }),
+ ),
+ ...[...suite.existing_failures, ...suite.existing_errors].map(
+ this.mapTestAsChild({
+ iconName: EXTENSION_ICONS.failed,
+ }),
+ ),
+ ...[...suite.resolved_failures, ...suite.resolved_errors].map(
+ this.mapTestAsChild({
+ sectionHeader: i18n.fixedHeader,
+ iconName: EXTENSION_ICONS.success,
+ }),
+ ),
+ ],
+ };
+ });
},
},
};
diff --git a/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/utils.js b/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/utils.js
index a74ed20362f..9e4b0ac581c 100644
--- a/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/utils.js
+++ b/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/utils.js
@@ -43,13 +43,42 @@ export const reportTextBuilder = ({ name = '', summary = {}, status }) => {
return i18n.summaryText(name, resultsString);
};
-export const reportSubTextBuilder = ({ suite_errors }) => {
- const errors = [];
- if (suite_errors?.head) {
- errors.push(`${i18n.headReportParsingError} ${suite_errors.head}`);
- }
- if (suite_errors?.base) {
- errors.push(`${i18n.baseReportParsingError} ${suite_errors.base}`);
+export const recentFailuresTextBuilder = (summary = {}) => {
+ const { failed, recentlyFailed } = summary;
+ if (!failed || !recentlyFailed) return '';
+
+ return i18n.recentFailureSummary(recentlyFailed, failed);
+};
+
+export const reportSubTextBuilder = ({ suite_errors, summary }) => {
+ if (suite_errors?.head || suite_errors?.base) {
+ const errors = [];
+ if (suite_errors?.head) {
+ errors.push(`${i18n.headReportParsingError} ${suite_errors.head}`);
+ }
+ if (suite_errors?.base) {
+ errors.push(`${i18n.baseReportParsingError} ${suite_errors.base}`);
+ }
+ return errors.join('<br />');
}
- return errors.join('<br />');
+ return recentFailuresTextBuilder(summary);
+};
+
+export const countRecentlyFailedTests = (subject) => {
+ // handle either a single report or an array of reports
+ const reports = !subject.length ? [subject] : subject;
+
+ return reports
+ .map((report) => {
+ return (
+ [report.new_failures, report.existing_failures, report.resolved_failures]
+ // only count tests which have failed more than once
+ .map(
+ (failureArray) =>
+ failureArray.filter((failure) => failure.recent_failures?.count > 1).length,
+ )
+ .reduce((total, count) => total + count, 0)
+ );
+ })
+ .reduce((total, count) => total + count, 0);
};
diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
index 4b3ad288768..8ebb7f6f159 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
@@ -165,7 +165,10 @@ export default {
return this.mr?.codequalityReportsPath;
},
shouldRenderRelatedLinks() {
- return Boolean(this.mr.relatedLinks) && !this.mr.isNothingToMergeState;
+ return (
+ (Boolean(this.mr.relatedLinks) || this.mr.divergedCommitsCount > 0) &&
+ !this.mr.isNothingToMergeState
+ );
},
shouldRenderSourceBranchRemovalStatus() {
return (
@@ -195,6 +198,9 @@ export default {
shouldRenderTestReport() {
return Boolean(this.mr?.testResultsPath);
},
+ shouldRenderRefactoredTestReport() {
+ return window.gon?.features?.refactorMrWidgetTestSummary;
+ },
mergeError() {
let { mergeError } = this.mr;
@@ -228,6 +234,9 @@ export default {
isRestructuredMrWidgetEnabled() {
return window.gon?.features?.restructuredMrWidget;
},
+ isUpdatedHeaderEnabled() {
+ return window.gon?.features?.updatedMrHeader;
+ },
},
watch: {
'mr.machineValue': {
@@ -512,7 +521,7 @@ export default {
}
},
registerTestReportExtension() {
- if (this.shouldRenderTestReport && this.shouldShowExtension) {
+ if (this.shouldRenderTestReport && this.shouldRenderRefactoredTestReport) {
registerExtension(testReportExtension);
}
},
@@ -521,11 +530,15 @@ export default {
</script>
<template>
<div v-if="isLoaded" class="mr-state-widget gl-mt-3">
- <header class="gl-rounded-base gl-border-solid gl-border-1 gl-border-gray-100">
+ <header
+ v-if="shouldRenderCollaborationStatus || !isUpdatedHeaderEnabled"
+ :class="{ 'mr-widget-workflow gl-mt-0!': isUpdatedHeaderEnabled }"
+ class="gl-rounded-base gl-border-solid gl-border-1 gl-border-gray-100 gl-overflow-hidden"
+ >
<mr-widget-alert-message v-if="shouldRenderCollaborationStatus" type="info">
{{ s__('mrWidget|Members who can merge are allowed to add commits.') }}
</mr-widget-alert-message>
- <mr-widget-header :mr="mr" />
+ <mr-widget-header v-if="!isUpdatedHeaderEnabled" :mr="mr" />
</header>
<mr-widget-suggest-pipeline
v-if="shouldSuggestPipelines"
@@ -588,7 +601,7 @@ export default {
/>
<grouped-test-reports-app
- v-if="mr.testResultsPath && !shouldShowExtension"
+ v-if="shouldRenderTestReport && !shouldRenderRefactoredTestReport"
class="js-reports-container"
:endpoint="mr.testResultsPath"
:head-blob-path="mr.headBlobPath"
@@ -617,6 +630,8 @@ export default {
v-if="shouldRenderRelatedLinks"
:state="mr.state"
:related-links="mr.relatedLinks"
+ :diverged-commits-count="mr.divergedCommitsCount"
+ :target-branch-path="mr.targetBranchPath"
class="mr-info-list gl-ml-7 gl-pb-5"
/>
diff --git a/app/assets/javascripts/vue_merge_request_widget/queries/states/ready_to_merge.fragment.graphql b/app/assets/javascripts/vue_merge_request_widget/queries/states/ready_to_merge.fragment.graphql
index 99e6f4e9beb..efc0673bc26 100644
--- a/app/assets/javascripts/vue_merge_request_widget/queries/states/ready_to_merge.fragment.graphql
+++ b/app/assets/javascripts/vue_merge_request_widget/queries/states/ready_to_merge.fragment.graphql
@@ -11,7 +11,6 @@ fragment ReadyToMerge on Project {
shouldRemoveSourceBranch
forceRemoveSourceBranch
defaultMergeCommitMessage
- defaultMergeCommitMessageWithDescription
defaultSquashCommitMessage
squash
squashOnMerge
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 eb07609d5d6..146cf7e11a7 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
@@ -1,5 +1,5 @@
import getStateKey from 'ee_else_ce/vue_merge_request_widget/stores/get_state_key';
-import { statusBoxState } from '~/issuable/components/status_box.vue';
+import { badgeState } from '~/issuable/components/status_box.vue';
import { formatDate, getTimeago } from '~/lib/utils/datetime_utility';
import { machine } from '~/lib/utils/finite_state_machine';
import {
@@ -221,8 +221,8 @@ export default class MergeRequestStore {
}
updateStatusState(state) {
- if (this.mergeRequestState !== state && statusBoxState.updateStatus) {
- statusBoxState.updateStatus();
+ if (this.mergeRequestState !== state && badgeState.updateStatus) {
+ badgeState.updateStatus();
}
}