summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/vue_merge_request_widget/components
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/vue_merge_request_widget/components')
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_list.vue92
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_collapsible_extension.vue25
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue4
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_how_to_merge_modal.vue12
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_merge_help.vue49
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue37
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue48
-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_conflicts.vue82
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue18
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue36
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue96
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/sha_mismatch.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/work_in_progress.vue6
15 files changed, 288 insertions, 223 deletions
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_list.vue b/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_list.vue
new file mode 100644
index 00000000000..d23c7f016fb
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_list.vue
@@ -0,0 +1,92 @@
+<script>
+import { GlSprintf } from '@gitlab/ui';
+import { n__ } from '~/locale';
+import MrCollapsibleExtension from '../mr_collapsible_extension.vue';
+
+export default {
+ components: {
+ Deployment: () => import('./deployment.vue'),
+ GlSprintf,
+ MrCollapsibleExtension,
+ },
+ props: {
+ deployments: {
+ type: Array,
+ required: true,
+ },
+ deploymentClass: {
+ type: String,
+ required: true,
+ },
+ hasDeploymentMetrics: {
+ type: Boolean,
+ required: true,
+ },
+ visualReviewAppMeta: {
+ type: Object,
+ required: false,
+ default: () => ({
+ sourceProjectId: '',
+ sourceProjectPath: '',
+ mergeRequestId: '',
+ appUrl: '',
+ }),
+ },
+ showVisualReviewAppLink: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ computed: {
+ showCollapsedDeployments() {
+ return this.deployments.length > 3;
+ },
+ multipleDeploymentsTitle() {
+ return n__(
+ 'Deployments|%{deployments} environment impacted.',
+ 'Deployments|%{deployments} environments impacted.',
+ this.deployments.length,
+ );
+ },
+ },
+};
+</script>
+<template>
+ <mr-collapsible-extension
+ v-if="showCollapsedDeployments"
+ :title="__('View all environments.')"
+ data-testid="mr-collapsed-deployments"
+ >
+ <template #header>
+ <div class="gl-mr-3 gl-line-height-normal">
+ <gl-sprintf :message="multipleDeploymentsTitle">
+ <template #deployments>
+ <span class="gl-font-weight-bold gl-mr-2">{{ deployments.length }}</span>
+ </template>
+ </gl-sprintf>
+ </div>
+ </template>
+ <deployment
+ v-for="deployment in deployments"
+ :key="deployment.id"
+ :class="deploymentClass"
+ class="gl-bg-gray-50"
+ :deployment="deployment"
+ :show-metrics="hasDeploymentMetrics"
+ :show-visual-review-app="showVisualReviewAppLink"
+ :visual-review-app-meta="visualReviewAppMeta"
+ />
+ </mr-collapsible-extension>
+ <div v-else class="mr-widget-extension">
+ <deployment
+ v-for="deployment in deployments"
+ :key="deployment.id"
+ :class="deploymentClass"
+ :deployment="deployment"
+ :show-metrics="hasDeploymentMetrics"
+ :show-visual-review-app="showVisualReviewAppLink"
+ :visual-review-app-meta="visualReviewAppMeta"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_collapsible_extension.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_collapsible_extension.vue
index b6b5b56e5aa..a619ae9c351 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_collapsible_extension.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_collapsible_extension.vue
@@ -50,9 +50,9 @@ export default {
<div class="mr-widget-extension d-flex align-items-center pl-3">
<div v-if="hasError" class="ci-widget media">
<div class="media-body">
- <span class="gl-font-sm mr-widget-margin-left gl-line-height-24 js-error-state">{{
- title
- }}</span>
+ <span class="gl-font-sm mr-widget-margin-left gl-line-height-24 js-error-state">
+ {{ title }}
+ </span>
</div>
</div>
@@ -67,16 +67,27 @@ export default {
<gl-loading-icon v-if="isLoading" />
<gl-icon v-else :name="arrowIconName" class="js-icon" />
</button>
+ <template v-if="isCollapsed">
+ <slot name="header"></slot>
+ <gl-button
+ variant="link"
+ data-testid="mr-collapsible-title"
+ :disabled="isLoading"
+ :class="{ 'border-0': isLoading }"
+ @click="toggleCollapsed"
+ >
+ {{ title }}
+ </gl-button>
+ </template>
<gl-button
+ v-else
variant="link"
- class="js-title"
+ data-testid="mr-collapsible-title"
:disabled="isLoading"
:class="{ 'border-0': isLoading }"
@click="toggleCollapsed"
+ >{{ __('Collapse') }}</gl-button
>
- <template v-if="isCollapsed">{{ title }}</template>
- <template v-else>{{ __('Collapse') }}</template>
- </gl-button>
</template>
</div>
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 71ff0fe6fbd..f1230e2fdeb 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
@@ -175,7 +175,7 @@ export default {
:href="mr.emailPatchesPath"
class="js-download-email-patches"
download
- data-qa-selector="download_email_patches"
+ data-qa-selector="download_email_patches_menu_item"
>
{{ s__('mrWidget|Email patches') }}
</gl-dropdown-item>
@@ -183,7 +183,7 @@ export default {
:href="mr.plainDiffPath"
class="js-download-plain-diff"
download
- data-qa-selector="download_plain_diff"
+ data-qa-selector="download_plain_diff_menu_item"
>
{{ s__('mrWidget|Plain diff') }}
</gl-dropdown-item>
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 7c50df5f104..7532eabee8a 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
@@ -108,9 +108,7 @@ export default {
{{ $options.i18n.steps.step1.help }}
</p>
<div class="gl-display-flex">
- <pre class="gl-overflow-scroll gl-w-full" data-testid="how-to-merge-instructions">{{
- mergeInfo1
- }}</pre>
+ <pre class="gl-w-full" data-testid="how-to-merge-instructions">{{ mergeInfo1 }}</pre>
<clipboard-button
:text="mergeInfo1"
:title="$options.i18n.copyCommands"
@@ -131,9 +129,7 @@ export default {
{{ $options.i18n.steps.step3.help }}
</p>
<div class="gl-display-flex">
- <pre class="gl-overflow-scroll gl-w-full" data-testid="how-to-merge-instructions">{{
- mergeInfo2
- }}</pre>
+ <pre class="gl-w-full" data-testid="how-to-merge-instructions">{{ mergeInfo2 }}</pre>
<clipboard-button
:text="mergeInfo2"
:title="$options.i18n.copyCommands"
@@ -147,9 +143,7 @@ export default {
{{ $options.i18n.steps.step4.help }}
</p>
<div class="gl-display-flex">
- <pre class="gl-overflow-scroll gl-w-full" data-testid="how-to-merge-instructions">{{
- mergeInfo3
- }}</pre>
+ <pre class="gl-w-full" data-testid="how-to-merge-instructions">{{ mergeInfo3 }}</pre>
<clipboard-button
:text="mergeInfo3"
:title="$options.i18n.copyCommands"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_merge_help.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_merge_help.vue
deleted file mode 100644
index 3cd003461b3..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_merge_help.vue
+++ /dev/null
@@ -1,49 +0,0 @@
-<script>
-import { GlButton, GlModalDirective } from '@gitlab/ui';
-import { sprintf, s__ } from '~/locale';
-
-export default {
- name: 'MRWidgetMergeHelp',
- components: {
- GlButton,
- },
- directives: {
- GlModalDirective,
- },
- props: {
- missingBranch: {
- type: String,
- required: false,
- default: '',
- },
- },
- computed: {
- missingBranchInfo() {
- return sprintf(
- s__(
- 'mrWidget|If the %{branch} branch exists in your local repository, you can merge this merge request manually using the',
- ),
- { branch: this.missingBranch },
- );
- },
- },
-};
-</script>
-<template>
- <section class="gl-py-3 gl-pr-3 gl-pl-5 gl-ml-7 mr-widget-help gl-font-style-italic">
- <template v-if="missingBranch">
- {{ missingBranchInfo }}
- </template>
- <template v-else>
- {{ s__('mrWidget|You can merge this merge request manually using the') }}
- </template>
-
- <gl-button
- v-gl-modal-directive="'modal-merge-info'"
- variant="link"
- class="gl-mt-n2 js-open-modal-help"
- >
- {{ s__('mrWidget|command line') }}
- </gl-button>
- </section>
-</template>
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 d022579ef54..3419abd4738 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
@@ -11,10 +11,11 @@ import {
} from '@gitlab/ui';
import mrWidgetPipelineMixin from 'ee_else_ce/vue_merge_request_widget/mixins/mr_widget_pipeline';
import { s__, n__ } from '~/locale';
+import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
import PipelineArtifacts from '~/pipelines/components/pipelines_list/pipelines_artifacts.vue';
-import PipelineStage from '~/pipelines/components/pipelines_list/stage.vue';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
+import { MT_MERGE_STRATEGY } from '../constants';
export default {
name: 'MRWidgetPipeline',
@@ -26,7 +27,7 @@ export default {
GlSprintf,
GlTooltip,
PipelineArtifacts,
- PipelineStage,
+ PipelineMiniGraph,
TooltipOnTruncate,
LinkedPipelinesMiniList: () =>
import('ee_component/vue_shared/components/linked_pipelines_mini_list.vue'),
@@ -80,6 +81,11 @@ export default {
type: String,
required: true,
},
+ mergeStrategy: {
+ type: String,
+ required: false,
+ default: '',
+ },
},
computed: {
hasPipeline() {
@@ -94,9 +100,7 @@ export default {
: {};
},
hasStages() {
- return (
- this.pipeline.details && this.pipeline.details.stages && this.pipeline.details.stages.length
- );
+ return this.pipeline?.details?.stages?.length > 0;
},
hasCommitInfo() {
return this.pipeline.commit && Object.keys(this.pipeline.commit).length > 0;
@@ -130,6 +134,9 @@ export default {
this.buildsWithCoverage.length,
);
},
+ isMergeTrain() {
+ return this.mergeStrategy === MT_MERGE_STRATEGY;
+ },
},
errorText: s__(
'Pipeline|Could not retrieve the pipeline status. For troubleshooting steps, read the %{linkStart}documentation%{linkEnd}.',
@@ -242,19 +249,13 @@ export default {
<span class="mr-widget-pipeline-graph">
<span class="stage-cell">
<linked-pipelines-mini-list v-if="triggeredBy.length" :triggered-by="triggeredBy" />
- <template v-if="hasStages">
- <div
- v-for="(stage, i) in pipeline.details.stages"
- :key="i"
- :class="{
- 'has-downstream': hasDownstream(i),
- }"
- class="stage-container dropdown mr-widget-pipeline-stages"
- data-testid="widget-mini-pipeline-graph"
- >
- <pipeline-stage :stage="stage" />
- </div>
- </template>
+ <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"
+ />
</span>
<linked-pipelines-mini-list v-if="triggered.length" :triggered="triggered" />
<pipeline-artifacts
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue
index 2bf86c1863a..c24ae92db4f 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue
@@ -1,8 +1,11 @@
<script>
import { isNumber } from 'lodash';
import { sanitize } from '~/lib/dompurify';
+import { n__ } from '~/locale';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import MergeRequestStore from '../stores/mr_widget_store';
import ArtifactsApp from './artifacts_list_app.vue';
+import DeploymentList from './deployment/deployment_list.vue';
import MrWidgetContainer from './mr_widget_container.vue';
import MrWidgetPipeline from './mr_widget_pipeline.vue';
@@ -18,7 +21,7 @@ export default {
name: 'MrWidgetPipelineContainer',
components: {
ArtifactsApp,
- Deployment: () => import('./deployment/deployment.vue'),
+ DeploymentList,
MrWidgetContainer,
MrWidgetPipeline,
MergeTrainPositionIndicator: () =>
@@ -64,11 +67,32 @@ export default {
return this.isPostMerge ? this.mr.mergePipeline : this.mr.pipeline;
},
showVisualReviewAppLink() {
- return this.mr.visualReviewAppAvailable && this.glFeatures.anonymousVisualReviewFeedback;
+ return Boolean(
+ this.mr.visualReviewAppAvailable && this.glFeatures.anonymousVisualReviewFeedback,
+ );
},
showMergeTrainPositionIndicator() {
return isNumber(this.mr.mergeTrainIndex);
},
+ showCollapsedDeployments() {
+ return this.deployments.length > 3;
+ },
+ multipleDeploymentsTitle() {
+ return n__(
+ 'Deployments|%{deployments} environment impacted.',
+ 'Deployments|%{deployments} environments impacted.',
+ this.deployments.length,
+ );
+ },
+ preferredAutoMergeStrategy() {
+ if (this.glFeatures.mergeRequestWidgetGraphql) {
+ return MergeRequestStore.getPreferredAutoMergeStrategy(
+ this.mr.availableAutoMergeStrategies,
+ );
+ }
+
+ return this.mr.preferredAutoMergeStrategy;
+ },
},
};
</script>
@@ -85,22 +109,20 @@ export default {
:source-branch-link="branchLink"
:mr-troubleshooting-docs-path="mr.mrTroubleshootingDocsPath"
:ci-troubleshooting-docs-path="mr.ciTroubleshootingDocsPath"
+ :merge-strategy="preferredAutoMergeStrategy"
/>
<template #footer>
<div v-if="mr.exposedArtifactsPath" class="js-exposed-artifacts">
<artifacts-app :endpoint="mr.exposedArtifactsPath" />
</div>
- <div v-if="deployments.length" class="mr-widget-extension">
- <deployment
- v-for="deployment in deployments"
- :key="deployment.id"
- :class="deploymentClass"
- :deployment="deployment"
- :show-metrics="hasDeploymentMetrics"
- :show-visual-review-app="showVisualReviewAppLink"
- :visual-review-app-meta="visualReviewAppMeta"
- />
- </div>
+ <deployment-list
+ v-if="deployments.length"
+ :deployments="deployments"
+ :deployment-class="deploymentClass"
+ :has-deployment-metrics="hasDeploymentMetrics"
+ :visual-review-app-meta="visualReviewAppMeta"
+ :show-visual-review-app-link="showVisualReviewAppLink"
+ />
<merge-train-position-indicator
v-if="showMergeTrainPositionIndicator"
class="mr-widget-extension"
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 428641a1109..84a21a25552 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
@@ -154,7 +154,7 @@ export default {
<status-icon status="success" />
<div class="media-body">
<h4 class="gl-display-flex">
- <span class="gl-mr-3">
+ <span class="gl-mr-3" data-qa-selector="merge_request_status_content">
<span class="js-status-text-before-author" data-testid="beforeStatusText">{{
statusTextBeforeAuthor
}}</span>
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 2335e2984e4..23f415c3116 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,9 +1,6 @@
<script>
-import { GlButton, GlModalDirective, GlSkeletonLoader } from '@gitlab/ui';
-import $ from 'jquery';
-import { escape } from 'lodash';
-import { s__, sprintf } from '~/locale';
-import { mouseenter, debouncedMouseleave, togglePopover } from '~/shared/popover';
+import { GlButton, GlModalDirective, GlSkeletonLoader, GlPopover, GlLink } from '@gitlab/ui';
+import { s__ } from '~/locale';
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';
@@ -16,6 +13,8 @@ export default {
GlSkeletonLoader,
StatusIcon,
GlButton,
+ GlPopover,
+ GlLink,
},
directives: {
GlModalDirective,
@@ -106,48 +105,11 @@ export default {
return this.showResolveButton && this.sourceBranchProtected;
},
},
- watch: {
- showPopover: {
- handler(newVal) {
- if (newVal) {
- this.$nextTick(this.initPopover);
- }
- },
- immediate: true,
- },
- },
- methods: {
- initPopover() {
- const $el = $(this.$refs.popover);
-
- $el
- .popover({
- html: true,
- trigger: 'focus',
- container: 'body',
- placement: 'top',
- template:
- '<div class="popover" role="tooltip"><div class="arrow"></div><p class="popover-header"></p><div class="popover-body"></div></div>',
- title: s__(
- 'mrWidget|This feature merges changes from the target branch to the source branch. You cannot use this feature since the source branch is protected.',
- ),
- content: sprintf(
- s__('mrWidget|%{link_start}Learn more about resolving conflicts%{link_end}'),
- {
- link_start: `<a href="${escape(
- this.mr.conflictsDocsPath,
- )}" target="_blank" rel="noopener noreferrer">`,
- link_end: '</a>',
- },
- false,
- ),
- })
- .on('mouseenter', mouseenter)
- .on('mouseleave', debouncedMouseleave(300))
- .on('show.bs.popover', () => {
- window.addEventListener('scroll', togglePopover.bind($el, false), { once: true });
- });
- },
+ i18n: {
+ title: s__(
+ 'mrWidget|This feature merges changes from the target branch to the source branch. You cannot use this feature since the source branch is protected.',
+ ),
+ linkText: s__('mrWidget|Learn more about resolving conflicts'),
},
};
</script>
@@ -162,7 +124,7 @@ export default {
<rect x="250" y="7" width="84" height="16" rx="4" />
</gl-skeleton-loader>
</div>
- <div v-else class="media-body space-children">
+ <div v-else class="media-body space-children gl-display-flex gl-align-items-center">
<span v-if="shouldBeRebased" class="bold">
{{
s__(`mrWidget|Fast-forward merge is not possible.
@@ -181,17 +143,35 @@ export default {
</span>
<span v-if="showResolveButton" ref="popover">
<gl-button
- :href="!sourceBranchProtected && mr.conflictResolutionPath"
+ :href="mr.conflictResolutionPath"
:disabled="sourceBranchProtected"
- class="js-resolve-conflicts-button"
+ data-testid="resolve-conflicts-button"
>
{{ s__('mrWidget|Resolve conflicts') }}
</gl-button>
+ <gl-popover
+ v-if="showPopover"
+ :target="() => $refs.popover"
+ placement="top"
+ triggers="hover focus"
+ >
+ <template #title>
+ <div class="gl-font-weight-normal gl-font-base">
+ {{ $options.i18n.title }}
+ </div>
+ </template>
+
+ <div class="gl-text-center">
+ <gl-link :href="mr.conflictsDocsPath" target="_blank" rel="noopener noreferrer">
+ {{ $options.i18n.linkText }}
+ </gl-link>
+ </div>
+ </gl-popover>
</span>
<gl-button
v-if="canMerge"
v-gl-modal-directive="'modal-merge-info'"
- class="js-merge-locally-button"
+ data-testid="merge-locally-button"
>
{{ s__('mrWidget|Merge locally') }}
</gl-button>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue
index d15794c71b1..33ca582583b 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue
@@ -176,16 +176,22 @@ export default {
<gl-button
:loading="isMakingRequest"
variant="success"
- class="qa-mr-rebase-button"
+ data-qa-selector="mr_rebase_button"
@click="rebase"
>
{{ __('Rebase') }}
</gl-button>
- <span v-if="!rebasingError" class="gl-font-weight-bold" data-testid="rebase-message">{{
- __(
- 'Fast-forward merge is not possible. Rebase the source branch onto the target branch.',
- )
- }}</span>
+ <span
+ v-if="!rebasingError"
+ class="gl-font-weight-bold"
+ data-testid="rebase-message"
+ data-qa-selector="no_fast_forward_message_content"
+ >{{
+ __(
+ 'Fast-forward merge is not possible. Rebase the source branch onto the target branch.',
+ )
+ }}</span
+ >
<span v-else class="gl-font-weight-bold danger" data-testid="rebase-message">{{
rebasingError
}}</span>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue
index f0259a975db..01e0b91bd4a 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue
@@ -1,12 +1,15 @@
<script>
/* eslint-disable vue/no-v-html */
-import { GlButton } from '@gitlab/ui';
+import { GlButton, GlSprintf, GlLink } from '@gitlab/ui';
import emptyStateSVG from 'icons/_mr_widget_empty_state.svg';
+import { helpPagePath } from '~/helpers/help_page_helper';
export default {
name: 'MRWidgetNothingToMerge',
components: {
GlButton,
+ GlSprintf,
+ GlLink,
},
props: {
mr: {
@@ -17,6 +20,7 @@ export default {
data() {
return { emptyStateSVG };
},
+ ciHelpPage: helpPagePath('/ci/quick_start/index.html'),
};
</script>
@@ -30,25 +34,20 @@ export default {
</div>
<div class="text col-md-7 order-md-first col-12">
<p class="highlight">
- {{
- s__(
- 'mrWidgetNothingToMerge|Merge requests are a place to propose changes you have made to a project and discuss those changes with others.',
- )
- }}
+ {{ s__('mrWidgetNothingToMerge|This merge request contains no changes.') }}
</p>
<p>
- {{
- s__(
- 'mrWidgetNothingToMerge|Interested parties can even contribute by pushing commits if they want to.',
- )
- }}
- </p>
- <p>
- {{
- s__(
- "mrWidgetNothingToMerge|Currently there are no changes in this merge request's source branch. Please push new commits or use a different branch.",
- )
- }}
+ <gl-sprintf
+ :message="
+ s__(
+ 'mrWidgetNothingToMerge|Use merge requests to propose changes to your project and discuss them with your team. To make changes, push a commit or edit this merge request to use a different branch. With %{linkStart}CI/CD%{linkEnd}, automatically test your changes before merging.',
+ )
+ "
+ >
+ <template #link="{ content }">
+ <gl-link :href="$options.ciHelpPage" target="_blank">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
</p>
<div>
<gl-button
@@ -56,6 +55,7 @@ export default {
:href="mr.newBlobPath"
category="secondary"
variant="success"
+ data-testid="createFileButton"
>
{{ __('Create file') }}
</gl-button>
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 690b6e9c462..62c5cd90035 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
@@ -5,6 +5,7 @@ import {
GlButtonGroup,
GlDropdown,
GlDropdownItem,
+ GlFormCheckbox,
GlSprintf,
GlLink,
GlTooltipDirective,
@@ -81,6 +82,7 @@ export default {
GlButtonGroup,
GlDropdown,
GlDropdownItem,
+ GlFormCheckbox,
GlSkeletonLoader,
MergeTrainHelperText: () =>
import('ee_component/vue_merge_request_widget/components/merge_train_helper_text.vue'),
@@ -453,12 +455,13 @@ export default {
<div class="mr-widget-body media" :class="{ 'gl-pb-3': shouldRenderMergeTrainHelperText }">
<status-icon :status="iconClass" />
<div class="media-body">
- <div class="mr-widget-body-controls media space-children">
- <gl-button-group>
+ <div class="mr-widget-body-controls gl-display-flex gl-align-items-center">
+ <gl-button-group class="gl-align-self-start">
<gl-button
size="medium"
category="primary"
- class="qa-merge-button accept-merge-request"
+ class="accept-merge-request"
+ data-testid="merge-button"
:variant="mergeButtonVariant"
:disabled="isMergeButtonDisabled"
:loading="isMakingRequest"
@@ -481,7 +484,7 @@ export default {
<gl-dropdown-item
icon-name="warning"
button-class="accept-merge-request js-merge-immediately-button"
- data-qa-selector="merge_immediately_option"
+ data-qa-selector="merge_immediately_menu_item"
@click="handleMergeImmediatelyButtonClick"
>
{{ __('Merge immediately') }}
@@ -493,47 +496,48 @@ export default {
/>
</gl-dropdown>
</gl-button-group>
- <div class="media-body-wrap space-children">
- <template v-if="shouldShowMergeControls">
- <label v-if="canRemoveSourceBranch">
- <input
- id="remove-source-branch-input"
- v-model="removeSourceBranch"
- :disabled="isRemoveSourceBranchButtonDisabled"
- class="js-remove-source-branch-checkbox"
- type="checkbox"
- />
- {{ __('Delete source branch') }}
- </label>
-
- <!-- Placeholder for EE extension of this component -->
- <squash-before-merge
- v-if="shouldShowSquashBeforeMerge"
- v-model="squashBeforeMerge"
- :help-path="mr.squashBeforeMergeHelpPath"
- :is-disabled="isSquashReadOnly"
- />
- </template>
- <template v-else>
- <div class="bold js-resolve-mr-widget-items-message">
- <div
- v-if="hasPipelineMustSucceedConflict"
- class="gl-display-flex gl-align-items-center"
- data-testid="pipeline-succeed-conflict"
+ <div
+ v-if="shouldShowMergeControls"
+ class="gl-display-flex gl-align-items-center gl-flex-wrap"
+ >
+ <gl-form-checkbox
+ v-if="canRemoveSourceBranch"
+ id="remove-source-branch-input"
+ v-model="removeSourceBranch"
+ :disabled="isRemoveSourceBranchButtonDisabled"
+ class="js-remove-source-branch-checkbox gl-mx-3 gl-display-flex gl-align-items-center"
+ >
+ {{ __('Delete source branch') }}
+ </gl-form-checkbox>
+
+ <!-- Placeholder for EE extension of this component -->
+ <squash-before-merge
+ v-if="shouldShowSquashBeforeMerge"
+ v-model="squashBeforeMerge"
+ :help-path="mr.squashBeforeMergeHelpPath"
+ :is-disabled="isSquashReadOnly"
+ class="gl-mx-3"
+ />
+ </div>
+ <template v-else>
+ <div class="bold js-resolve-mr-widget-items-message gl-ml-3">
+ <div
+ v-if="hasPipelineMustSucceedConflict"
+ class="gl-display-flex gl-align-items-center"
+ data-testid="pipeline-succeed-conflict"
+ >
+ <gl-sprintf :message="pipelineMustSucceedConflictText" />
+ <gl-link
+ :href="mr.pipelineMustSucceedDocsPath"
+ target="_blank"
+ class="gl-display-flex gl-ml-2"
>
- <gl-sprintf :message="pipelineMustSucceedConflictText" />
- <gl-link
- :href="mr.pipelineMustSucceedDocsPath"
- target="_blank"
- class="gl-display-flex gl-ml-2"
- >
- <gl-icon name="question" />
- </gl-link>
- </div>
- <gl-sprintf v-else :message="mergeDisabledText" />
+ <gl-icon name="question" />
+ </gl-link>
</div>
- </template>
- </div>
+ <gl-sprintf v-else :message="mergeDisabledText" />
+ </div>
+ </template>
</div>
<div v-if="isSHAMismatch" class="d-flex align-items-center mt-2 js-sha-mismatch">
<gl-icon name="warning-solid" class="text-warning mr-1" />
@@ -559,7 +563,11 @@ export default {
:merge-train-when-pipeline-succeeds-docs-path="mr.mergeTrainWhenPipelineSucceedsDocsPath"
/>
<template v-if="shouldShowMergeControls">
- <div v-if="!shouldShowMergeEdit" class="mr-fast-forward-message">
+ <div
+ v-if="!shouldShowMergeEdit"
+ class="mr-fast-forward-message"
+ data-qa-selector="fast_forward_message_content"
+ >
{{ __('Fast-forward merge without a merge commit') }}
</div>
<commits-header
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/sha_mismatch.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/sha_mismatch.vue
index 8acca0d6481..89edf588213 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/sha_mismatch.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/sha_mismatch.vue
@@ -13,7 +13,7 @@ export default {
<div class="mr-widget-body media">
<status-icon :show-disabled-button="true" status="warning" />
<div class="media-body space-children">
- <span class="bold">
+ <span class="bold" data-qa-selector="head_mismatch_content">
{{
s__(`mrWidget|The source branch HEAD has recently changed.
Please reload the page and review the changes before merging`)
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue
index 12fdfe601a4..6388b817e46 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue
@@ -44,7 +44,7 @@ export default {
:checked="value"
:disabled="isDisabled"
name="squash"
- class="qa-squash-checkbox js-squash-checkbox gl-mb-0 gl-mr-2"
+ class="qa-squash-checkbox js-squash-checkbox gl-mr-2 gl-display-flex gl-align-items-center"
:title="tooltipTitle"
@change="(checked) => $emit('input', checked)"
>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/work_in_progress.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/work_in_progress.vue
index af305815381..f0c624c5d8d 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/work_in_progress.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/work_in_progress.vue
@@ -70,7 +70,7 @@ export default {
data: {
mergeRequestSetWip: {
errors,
- mergeRequest: { workInProgress, title },
+ mergeRequest: { mergeableDiscussionsState, workInProgress, title },
},
},
},
@@ -87,9 +87,8 @@ export default {
});
const data = produce(sourceData, (draftState) => {
- // eslint-disable-next-line no-param-reassign
+ draftState.project.mergeRequest.mergeableDiscussionsState = mergeableDiscussionsState;
draftState.project.mergeRequest.workInProgress = workInProgress;
- // eslint-disable-next-line no-param-reassign
draftState.project.mergeRequest.title = title;
});
@@ -107,6 +106,7 @@ export default {
errors: [],
mergeRequest: {
__typename: 'MergeRequest',
+ mergeableDiscussionsState: true,
title: this.mr.title,
workInProgress: false,
},