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/mr_widget_author.js28
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author.vue53
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.js27
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue42
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js18
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.js113
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue145
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js8
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_merge_help.js23
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_merge_help.vue41
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.js90
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue110
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_related_links.js37
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_related_links.vue43
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.js36
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue57
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_archived.js26
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_archived.vue31
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.js47
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue55
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.js18
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.vue23
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.js35
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.vue48
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.js37
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue61
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.js78
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue105
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.js117
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue147
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.js140
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue192
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merging.js29
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merging.vue35
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.js43
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue62
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_not_allowed.js19
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_not_allowed.vue25
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.js18
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.vue24
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_failed.js4
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js97
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue138
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_sha_mismatch.js4
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_unresolved_discussions.js4
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_wip.js15
46 files changed, 1521 insertions, 1027 deletions
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author.js
deleted file mode 100644
index 982b5e8e373..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import tooltip from '../../vue_shared/directives/tooltip';
-
-export default {
- name: 'MRWidgetAuthor',
- props: {
- author: { type: Object, required: true },
- showAuthorName: { type: Boolean, required: false, default: true },
- showAuthorTooltip: { type: Boolean, required: false, default: false },
- },
- directives: {
- tooltip,
- },
- template: `
- <a
- :href="author.webUrl || author.web_url"
- class="author-link inline"
- :v-tooltip="showAuthorTooltip"
- :title="author.name">
- <img
- :src="author.avatarUrl || author.avatar_url"
- class="avatar avatar-inline s16" />
- <span
- v-if="showAuthorName"
- class="author">{{author.name}}
- </span>
- </a>
- `,
-};
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author.vue
new file mode 100644
index 00000000000..cb6e9858736
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author.vue
@@ -0,0 +1,53 @@
+<script>
+ import tooltip from '../../vue_shared/directives/tooltip';
+
+ export default {
+ name: 'MRWidgetAuthor',
+ directives: {
+ tooltip,
+ },
+ props: {
+ author: {
+ type: Object,
+ required: true,
+ },
+ showAuthorName: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ showAuthorTooltip: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ computed: {
+ authorUrl() {
+ return this.author.webUrl || this.author.web_url;
+ },
+ avatarUrl() {
+ return this.author.avatarUrl || this.author.avatar_url;
+ },
+ },
+ };
+</script>
+<template>
+ <a
+ :href="authorUrl"
+ class="author-link inline"
+ :v-tooltip="showAuthorTooltip"
+ :title="author.name"
+ >
+ <img
+ :src="avatarUrl"
+ class="avatar avatar-inline s16"
+ />
+ <span
+ class="author"
+ v-if="showAuthorName"
+ >
+ {{ author.name }}
+ </span>
+ </a>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.js
deleted file mode 100644
index 6d2ed5fda64..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import MRWidgetAuthor from './mr_widget_author';
-
-export default {
- name: 'MRWidgetAuthorTime',
- props: {
- actionText: { type: String, required: true },
- author: { type: Object, required: true },
- dateTitle: { type: String, required: true },
- dateReadable: { type: String, required: true },
- },
- components: {
- 'mr-widget-author': MRWidgetAuthor,
- },
- template: `
- <h4 class="js-mr-widget-author">
- {{actionText}}
- <mr-widget-author :author="author" />
- <time
- :title="dateTitle"
- data-toggle="tooltip"
- data-placement="top"
- data-container="body">
- {{dateReadable}}
- </time>
- </h4>
- `,
-};
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue
new file mode 100644
index 00000000000..8f1fd809a81
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue
@@ -0,0 +1,42 @@
+<script>
+ import mrWidgetAuthor from './mr_widget_author.vue';
+
+ export default {
+ name: 'MRWidgetAuthorTime',
+ components: {
+ mrWidgetAuthor,
+ },
+ props: {
+ actionText: {
+ type: String,
+ required: true,
+ },
+ author: {
+ type: Object,
+ required: true,
+ },
+ dateTitle: {
+ type: String,
+ required: true,
+ },
+ dateReadable: {
+ type: String,
+ required: true,
+ },
+ },
+ };
+</script>
+<template>
+ <h4 class="js-mr-widget-author">
+ {{ actionText }}
+ <mr-widget-author :author="author" />
+ <time
+ :title="dateTitle"
+ data-toggle="tooltip"
+ data-placement="top"
+ data-container="body"
+ >
+ {{ dateReadable }}
+ </time>
+ </h4>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js
index e98d147733c..d174a900f63 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js
@@ -1,8 +1,8 @@
-/* global Flash */
-
-import '~/lib/utils/datetime_utility';
+import { getTimeago } from '~/lib/utils/datetime_utility';
+import { visitUrl } from '../../lib/utils/url_utility';
+import Flash from '../../flash';
import MemoryUsage from './mr_widget_memory_usage';
-import StatusIcon from './mr_widget_status_icon';
+import StatusIcon from './mr_widget_status_icon.vue';
import MRWidgetService from '../services/mr_widget_service';
export default {
@@ -17,7 +17,7 @@ export default {
},
methods: {
formatDate(date) {
- return gl.utils.getTimeago().format(date);
+ return getTimeago().format(date);
},
hasExternalUrls(deployment = {}) {
return deployment.external_url && deployment.external_url_formatted;
@@ -34,10 +34,10 @@ export default {
if (isConfirmed) {
MRWidgetService.stopEnvironment(deployment.stop_url)
- .then(res => res.json())
- .then((res) => {
- if (res.redirect_url) {
- gl.utils.visitUrl(res.redirect_url);
+ .then(res => res.data)
+ .then((data) => {
+ if (data.redirect_url) {
+ visitUrl(data.redirect_url);
}
})
.catch(() => {
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.js
deleted file mode 100644
index 219ff94924e..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.js
+++ /dev/null
@@ -1,113 +0,0 @@
-import tooltip from '../../vue_shared/directives/tooltip';
-import '../../lib/utils/text_utility';
-
-export default {
- name: 'MRWidgetHeader',
- props: {
- mr: { type: Object, required: true },
- },
- directives: {
- tooltip,
- },
- computed: {
- shouldShowCommitsBehindText() {
- return this.mr.divergedCommitsCount > 0;
- },
- commitsText() {
- return gl.text.pluralize('commit', this.mr.divergedCommitsCount);
- },
- branchNameClipboardData() {
- // This supports code in app/assets/javascripts/copy_to_clipboard.js that
- // works around ClipboardJS limitations to allow the context-specific
- // copy/pasting of plain text or GFM.
- return JSON.stringify({
- text: this.mr.sourceBranch,
- gfm: `\`${this.mr.sourceBranch}\``,
- });
- },
- },
- methods: {
- isBranchTitleLong(branchTitle) {
- return branchTitle.length > 32;
- },
- },
- template: `
- <div class="mr-source-target">
- <div class="normal">
- <strong>
- Request to merge
- <span
- class="label-branch"
- :class="{'label-truncated': isBranchTitleLong(mr.sourceBranch)}"
- :title="isBranchTitleLong(mr.sourceBranch) ? mr.sourceBranch : ''"
- data-placement="bottom"
- :v-tooltip="isBranchTitleLong(mr.sourceBranch)"
- v-html="mr.sourceBranchLink"></span>
- <button
- v-tooltip
- class="btn btn-transparent btn-clipboard"
- data-title="Copy branch name to clipboard"
- :data-clipboard-text="branchNameClipboardData">
- <i
- aria-hidden="true"
- class="fa fa-clipboard"></i>
- </button>
- into
- <span
- class="label-branch"
- :v-tooltip="isBranchTitleLong(mr.sourceBranch)"
- :class="{'label-truncatedtooltip': isBranchTitleLong(mr.targetBranch)}"
- :title="isBranchTitleLong(mr.targetBranch) ? mr.targetBranch : ''"
- data-placement="bottom">
- <a :href="mr.targetBranchTreePath">{{mr.targetBranch}}</a>
- </span>
- </strong>
- <span
- v-if="shouldShowCommitsBehindText"
- class="diverged-commits-count">
- (<a :href="mr.targetBranchPath">{{mr.divergedCommitsCount}} {{commitsText}} behind</a>)
- </span>
- </div>
- <div v-if="mr.isOpen">
- <a
- href="#modal_merge_info"
- data-toggle="modal"
- class="btn btn-sm inline">
- Check out branch
- </a>
- <span class="dropdown prepend-left-10">
- <a
- class="btn btn-sm inline dropdown-toggle"
- data-toggle="dropdown"
- aria-label="Download as"
- role="button">
- <i
- class="fa fa-download"
- aria-hidden="true">
- </i>
- <i
- class="fa fa-caret-down"
- aria-hidden="true">
- </i>
- </a>
- <ul class="dropdown-menu dropdown-menu-align-right">
- <li>
- <a
- :href="mr.emailPatchesPath"
- download>
- Email patches
- </a>
- </li>
- <li>
- <a
- :href="mr.plainDiffPath"
- download>
- Plain diff
- </a>
- </li>
- </ul>
- </span>
- </div>
- </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
new file mode 100644
index 00000000000..18a3787857d
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue
@@ -0,0 +1,145 @@
+<script>
+ import tooltip from '~/vue_shared/directives/tooltip';
+ import { n__ } from '~/locale';
+ import icon from '~/vue_shared/components/icon.vue';
+ import clipboardButton from '~/vue_shared/components/clipboard_button.vue';
+
+ export default {
+ name: 'MRWidgetHeader',
+ directives: {
+ tooltip,
+ },
+ components: {
+ icon,
+ clipboardButton,
+ },
+ props: {
+ mr: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ shouldShowCommitsBehindText() {
+ return this.mr.divergedCommitsCount > 0;
+ },
+ commitsText() {
+ return n__('%d commit behind', '%d commits behind', this.mr.divergedCommitsCount);
+ },
+ branchNameClipboardData() {
+ // This supports code in app/assets/javascripts/copy_to_clipboard.js that
+ // works around ClipboardJS limitations to allow the context-specific
+ // copy/pasting of plain text or GFM.
+ return JSON.stringify({
+ text: this.mr.sourceBranch,
+ gfm: `\`${this.mr.sourceBranch}\``,
+ });
+ },
+ isSourceBranchLong() {
+ return this.isBranchTitleLong(this.mr.sourceBranch);
+ },
+ isTargetBranchLong() {
+ return this.isBranchTitleLong(this.mr.targetBranch);
+ },
+ },
+ methods: {
+ isBranchTitleLong(branchTitle) {
+ return branchTitle.length > 32;
+ },
+ },
+ };
+</script>
+<template>
+ <div class="mr-source-target">
+ <div class="normal">
+ <strong>
+ {{ s__("mrWidget|Request to merge") }}
+ <span
+ class="label-branch js-source-branch"
+ :class="{ 'label-truncated': isSourceBranchLong }"
+ :title="isSourceBranchLong ? mr.sourceBranch : ''"
+ data-placement="bottom"
+ :v-tooltip="isSourceBranchLong"
+ v-html="mr.sourceBranchLink"
+ >
+ </span>
+
+ <clipboard-button
+ :text="branchNameClipboardData"
+ :title="__('Copy branch name to clipboard')"
+ />
+
+ {{ s__("mrWidget|into") }}
+
+ <span
+ class="label-branch"
+ :v-tooltip="isTargetBranchLong"
+ :class="{ 'label-truncatedtooltip': isTargetBranchLong }"
+ :title="isTargetBranchLong ? mr.targetBranch : ''"
+ data-placement="bottom"
+ >
+ <a
+ :href="mr.targetBranchTreePath"
+ class="js-target-branch"
+ >
+ {{ mr.targetBranch }}
+ </a>
+ </span>
+ </strong>
+ <span
+ v-if="shouldShowCommitsBehindText"
+ class="diverged-commits-count"
+ >
+ (<a :href="mr.targetBranchPath">{{ commitsText }}</a>)
+ </span>
+ </div>
+
+ <div v-if="mr.isOpen">
+ <button
+ data-target="#modal_merge_info"
+ data-toggle="modal"
+ :disabled="mr.sourceBranchRemoved"
+ class="btn btn-sm btn-default inline js-check-out-branch"
+ type="button"
+ >
+ {{ s__("mrWidget|Check out branch") }}
+ </button>
+ <span class="dropdown prepend-left-10">
+ <button
+ type="button"
+ class="btn btn-sm inline dropdown-toggle"
+ data-toggle="dropdown"
+ aria-label="Download as"
+ aria-haspopup="true"
+ aria-expanded="false"
+ >
+ <icon name="download" />
+ <i
+ class="fa fa-caret-down"
+ aria-hidden="true">
+ </i>
+ </button>
+ <ul class="dropdown-menu dropdown-menu-align-right">
+ <li>
+ <a
+ class="js-download-email-patches"
+ :href="mr.emailPatchesPath"
+ download
+ >
+ {{ s__("mrWidget|Email patches") }}
+ </a>
+ </li>
+ <li>
+ <a
+ class="js-download-plain-diff"
+ :href="mr.plainDiffPath"
+ download
+ >
+ {{ s__("mrWidget|Plain diff") }}
+ </a>
+ </li>
+ </ul>
+ </span>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js
index a8c686e5065..69e70ba1dd6 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js
@@ -102,11 +102,11 @@ export default {
return res;
}
- return res.json();
+ return res.data;
})
- .then((res) => {
- this.computeGraphData(res.metrics, res.deployment_time);
- return res;
+ .then((data) => {
+ this.computeGraphData(data.metrics, data.deployment_time);
+ return data;
})
.catch(() => {
this.loadFailed = true;
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_merge_help.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_merge_help.js
deleted file mode 100644
index 1d9f9863dd9..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_merge_help.js
+++ /dev/null
@@ -1,23 +0,0 @@
-export default {
- name: 'MRWidgetMergeHelp',
- props: {
- missingBranch: { type: String, required: false, default: '' },
- },
- template: `
- <section class="mr-widget-help">
- <template
- v-if="missingBranch">
- If the {{missingBranch}} branch exists in your local repository, you
- </template>
- <template v-else>
- You
- </template>
- can merge this merge request manually using the
- <a
- data-toggle="modal"
- href="#modal_merge_info">
- command line
- </a>
- </section>
- `,
-};
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
new file mode 100644
index 00000000000..62b61e1f41f
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_merge_help.vue
@@ -0,0 +1,41 @@
+<script>
+ import { sprintf, s__ } from '~/locale';
+
+ export default {
+ name: 'MRWidgetMergeHelp',
+ 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="mr-widget-help">
+ <template v-if="missingBranch">
+ {{ missingBranchInfo }}
+ </template>
+ <template v-else>
+ {{ s__("mrWidget|You can merge this merge request manually using the") }}
+ </template>
+
+ <button
+ type="button"
+ class="btn-link btn-blank js-open-modal-help"
+ data-toggle="modal"
+ data-target="#modal_merge_info"
+ >
+ {{ s__("mrWidget|command line") }}
+ </button>
+ </section>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.js
deleted file mode 100644
index c79b5c720eb..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.js
+++ /dev/null
@@ -1,90 +0,0 @@
-import PipelineStage from '../../pipelines/components/stage.vue';
-import ciIcon from '../../vue_shared/components/ci_icon.vue';
-import { statusIconEntityMap } from '../../vue_shared/ci_status_icons';
-
-export default {
- name: 'MRWidgetPipeline',
- props: {
- mr: { type: Object, required: true },
- },
- components: {
- 'pipeline-stage': PipelineStage,
- ciIcon,
- },
- computed: {
- hasPipeline() {
- return this.mr.pipeline && Object.keys(this.mr.pipeline).length > 0;
- },
- hasCIError() {
- const { hasCI, ciStatus } = this.mr;
-
- return hasCI && !ciStatus;
- },
- svg() {
- return statusIconEntityMap.icon_status_failed;
- },
- stageText() {
- return this.mr.pipeline.details.stages.length > 1 ? 'stages' : 'stage';
- },
- status() {
- return this.mr.pipeline.details.status || {};
- },
- },
- template: `
- <div
- v-if="hasPipeline || hasCIError"
- class="mr-widget-heading">
- <div class="ci-widget media">
- <template v-if="hasCIError">
- <div class="ci-status-icon ci-status-icon-failed ci-error js-ci-error append-right-10">
- <span
- v-html="svg"
- aria-hidden="true"></span>
- </div>
- <div class="media-body">
- Could not connect to the CI server. Please check your settings and try again
- </div>
- </template>
- <template v-else-if="hasPipeline">
- <div class="ci-status-icon append-right-10">
- <a
- class="icon-link"
- :href="this.status.details_path">
- <ci-icon :status="status" />
- </a>
- </div>
- <div class="media-body">
- <span>
- Pipeline
- <a
- :href="mr.pipeline.path"
- class="pipeline-id">#{{mr.pipeline.id}}</a>
- </span>
- <span class="mr-widget-pipeline-graph">
- <span class="stage-cell">
- <div
- v-if="mr.pipeline.details.stages.length > 0"
- v-for="stage in mr.pipeline.details.stages"
- class="stage-container dropdown js-mini-pipeline-graph">
- <pipeline-stage :stage="stage" />
- </div>
- </span>
- </span>
- <span>
- {{mr.pipeline.details.status.label}} for
- <a
- :href="mr.pipeline.commit.commit_path"
- class="commit-sha js-commit-link">
- {{mr.pipeline.commit.short_id}}</a>.
- </span>
- <span
- v-if="mr.pipeline.coverage"
- class="js-mr-coverage">
- Coverage {{mr.pipeline.coverage}}%
- </span>
- </div>
- </template>
- </div>
- </div>
- `,
-};
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
new file mode 100644
index 00000000000..54a98abf860
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
@@ -0,0 +1,110 @@
+<script>
+ /* eslint-disable vue/require-default-prop */
+ import pipelineStage from '~/pipelines/components/stage.vue';
+ import ciIcon from '~/vue_shared/components/ci_icon.vue';
+ import icon from '~/vue_shared/components/icon.vue';
+
+ export default {
+ name: 'MRWidgetPipeline',
+ components: {
+ pipelineStage,
+ ciIcon,
+ icon,
+ },
+ props: {
+ pipeline: {
+ type: Object,
+ required: true,
+ },
+ // This prop needs to be camelCase, html attributes are case insensive
+ // https://vuejs.org/v2/guide/components.html#camelCase-vs-kebab-case
+ hasCi: {
+ type: Boolean,
+ required: false,
+ },
+ ciStatus: {
+ type: String,
+ required: false,
+ },
+ },
+ computed: {
+ hasPipeline() {
+ return this.pipeline && Object.keys(this.pipeline).length > 0;
+ },
+ hasCIError() {
+ return this.hasCi && !this.ciStatus;
+ },
+ status() {
+ return this.pipeline.details &&
+ this.pipeline.details.status ? this.pipeline.details.status : {};
+ },
+ hasStages() {
+ return this.pipeline.details &&
+ this.pipeline.details.stages &&
+ this.pipeline.details.stages.length;
+ },
+ },
+ };
+</script>
+
+<template>
+ <div
+ v-if="hasPipeline || hasCIError"
+ class="mr-widget-heading">
+ <div class="ci-widget media">
+ <template v-if="hasCIError">
+ <div class="ci-status-icon ci-status-icon-failed ci-error js-ci-error append-right-10">
+ <icon name="status_failed" />
+ </div>
+ <div class="media-body">
+ Could not connect to the CI server. Please check your settings and try again
+ </div>
+ </template>
+ <template v-else-if="hasPipeline">
+ <a
+ class="append-right-10"
+ :href="status.details_path"
+ >
+ <ci-icon :status="status" />
+ </a>
+
+ <div class="media-body">
+ Pipeline
+ <a
+ :href="pipeline.path"
+ class="pipeline-id"
+ >
+ #{{ pipeline.id }}
+ </a>
+
+ {{ pipeline.details.status.label }} for
+
+ <a
+ :href="pipeline.commit.commit_path"
+ class="commit-sha js-commit-link"
+ >
+ {{ pipeline.commit.short_id }}</a>.
+
+ <span class="mr-widget-pipeline-graph">
+ <span
+ class="stage-cell"
+ v-if="hasStages"
+ >
+ <div
+ v-for="(stage, i) in pipeline.details.stages"
+ :key="i"
+ class="stage-container dropdown js-mini-pipeline-graph"
+ >
+ <pipeline-stage :stage="stage" />
+ </div>
+ </span>
+ </span>
+
+ <template v-if="pipeline.coverage">
+ Coverage {{ pipeline.coverage }}%
+ </template>
+ </div>
+ </template>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_related_links.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_related_links.js
deleted file mode 100644
index 563267ad044..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_related_links.js
+++ /dev/null
@@ -1,37 +0,0 @@
-export default {
- name: 'MRWidgetRelatedLinks',
- props: {
- relatedLinks: { type: Object, required: true },
- state: { type: String, required: false },
- },
- computed: {
- hasLinks() {
- const { closing, mentioned, assignToMe } = this.relatedLinks;
- return closing || mentioned || assignToMe;
- },
- closesText() {
- if (this.state === 'merged') {
- return 'Closed';
- }
- if (this.state === 'closed') {
- return 'Did not close';
- }
- return 'Closes';
- },
- },
- template: `
- <section
- v-if="hasLinks"
- class="mr-info-list mr-links">
- <p v-if="relatedLinks.closing">
- {{closesText}} <span v-html="relatedLinks.closing"></span>
- </p>
- <p v-if="relatedLinks.mentioned">
- Mentions <span v-html="relatedLinks.mentioned"></span>
- </p>
- <p v-if="relatedLinks.assignToMe">
- <span v-html="relatedLinks.assignToMe"></span>
- </p>
- </section>
- `,
-};
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
new file mode 100644
index 00000000000..88d0fcd70f5
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_related_links.vue
@@ -0,0 +1,43 @@
+<script>
+ import { s__ } from '~/locale';
+
+ export default {
+ name: 'MRWidgetRelatedLinks',
+ props: {
+ relatedLinks: {
+ type: Object,
+ required: true,
+ default: () => ({}),
+ },
+ state: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ computed: {
+ closesText() {
+ if (this.state === 'merged') {
+ return s__('mrWidget|Closed');
+ }
+ if (this.state === 'closed') {
+ return s__('mrWidget|Did not close');
+ }
+ return s__('mrWidget|Closes');
+ },
+ },
+ };
+</script>
+<template>
+ <section class="mr-info-list mr-links">
+ <p v-if="relatedLinks.closing">
+ {{ closesText }} <span v-html="relatedLinks.closing"></span>
+ </p>
+ <p v-if="relatedLinks.mentioned">
+ {{ s__("mrWidget|Mentions") }} <span v-html="relatedLinks.mentioned"></span>
+ </p>
+ <p v-if="relatedLinks.assignToMe">
+ <span v-html="relatedLinks.assignToMe"></span>
+ </p>
+ </section>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.js
deleted file mode 100644
index 703f3a56a34..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import ciIcon from '../../vue_shared/components/ci_icon.vue';
-import loadingIcon from '../../vue_shared/components/loading_icon.vue';
-
-export default {
- props: {
- status: { type: String, required: true },
- showDisabledButton: { type: Boolean, required: false },
- },
- components: {
- ciIcon,
- loadingIcon,
- },
- computed: {
- statusObj() {
- return {
- group: this.status,
- icon: `icon_status_${this.status}`,
- };
- },
- },
- template: `
- <div class="space-children flex-container-block append-right-10">
- <div v-if="status === 'loading'" class="mr-widget-icon">
- <loading-icon />
- </div>
- <ci-icon v-else :status="statusObj" />
- <button
- v-if="showDisabledButton"
- type="button"
- class="btn btn-success btn-sm"
- disabled="true">
- Merge
- </button>
- </div>
- `,
-};
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
new file mode 100644
index 00000000000..1fdc3218671
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue
@@ -0,0 +1,57 @@
+<script>
+ import ciIcon from '../../vue_shared/components/ci_icon.vue';
+ import loadingIcon from '../../vue_shared/components/loading_icon.vue';
+
+ export default {
+ components: {
+ ciIcon,
+ loadingIcon,
+ },
+ props: {
+ status: {
+ type: String,
+ required: true,
+ },
+ showDisabledButton: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ computed: {
+ isLoading() {
+ return this.status === 'loading';
+ },
+ statusObj() {
+ return {
+ group: this.status,
+ icon: `status_${this.status}`,
+ };
+ },
+ },
+ };
+</script>
+<template>
+ <div class="space-children flex-container-block append-right-10">
+ <div
+ v-if="isLoading"
+ class="mr-widget-icon"
+ >
+ <loading-icon />
+ </div>
+
+ <ci-icon
+ v-else
+ :status="statusObj"
+ />
+
+ <button
+ v-if="showDisabledButton"
+ type="button"
+ class="js-disabled-merge-button btn btn-success btn-sm"
+ disabled="true"
+ >
+ {{ s__("mrWidget|Merge") }}
+ </button>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_archived.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_archived.js
deleted file mode 100644
index b4e4a6aa161..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_archived.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import statusIcon from '../mr_widget_status_icon';
-
-export default {
- name: 'MRWidgetArchived',
- components: {
- statusIcon,
- },
- template: `
- <div class="mr-widget-body media">
- <div class="space-children">
- <status-icon status="failed" />
- <button
- type="button"
- class="btn btn-success btn-sm"
- disabled="true">
- Merge
- </button>
- </div>
- <div class="media-body">
- <span class="bold">
- This project is archived, write access has been disabled
- </span>
- </div>
- </div>
- `,
-};
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_archived.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_archived.vue
new file mode 100644
index 00000000000..cfbd44d41b2
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_archived.vue
@@ -0,0 +1,31 @@
+<script>
+ import statusIcon from '../mr_widget_status_icon.vue';
+
+ export default {
+ name: 'MRWidgetArchived',
+ components: {
+ statusIcon,
+ },
+ };
+</script>
+<template>
+ <div class="mr-widget-body media">
+ <div class="space-children">
+ <status-icon
+ status="warning"
+ />
+ <button
+ type="button"
+ class="btn btn-success btn-sm"
+ disabled="true"
+ >
+ {{ s__("mrWidget|Merge") }}
+ </button>
+ </div>
+ <div class="media-body">
+ <span class="bold">
+ {{ s__("mrWidget|This project is archived, write access has been disabled") }}
+ </span>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.js
deleted file mode 100644
index 5648208f7b1..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import eventHub from '../../event_hub';
-import statusIcon from '../mr_widget_status_icon';
-
-export default {
- name: 'MRWidgetAutoMergeFailed',
- props: {
- mr: { type: Object, required: true },
- },
- data() {
- return {
- isRefreshing: false,
- };
- },
- components: {
- statusIcon,
- },
- methods: {
- refreshWidget() {
- this.isRefreshing = true;
- eventHub.$emit('MRWidgetUpdateRequested', () => {
- this.isRefreshing = false;
- });
- },
- },
- template: `
- <div class="mr-widget-body media">
- <status-icon status="failed" />
- <div class="media-body space-children">
- <span class="bold">
- <template v-if="mr.mergeError">{{mr.mergeError}}.</template>
- This merge request failed to be merged automatically
- </span>
- <button
- @click="refreshWidget"
- :disabled="isRefreshing"
- type="button"
- class="btn btn-xs btn-default">
- <i
- v-if="isRefreshing"
- class="fa fa-spinner fa-spin"
- aria-hidden="true" />
- Refresh
- </button>
- </div>
- </div>
- `,
-};
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue
new file mode 100644
index 00000000000..ebaf2b972eb
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue
@@ -0,0 +1,55 @@
+<script>
+ import loadingIcon from '~/vue_shared/components/loading_icon.vue';
+ import eventHub from '../../event_hub';
+ import statusIcon from '../mr_widget_status_icon.vue';
+
+ export default {
+ name: 'MRWidgetAutoMergeFailed',
+ components: {
+ statusIcon,
+ loadingIcon,
+ },
+ props: {
+ mr: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ isRefreshing: false,
+ };
+ },
+ methods: {
+ refreshWidget() {
+ this.isRefreshing = true;
+ eventHub.$emit('MRWidgetUpdateRequested', () => {
+ this.isRefreshing = false;
+ });
+ },
+ },
+ };
+</script>
+<template>
+ <div class="mr-widget-body media">
+ <status-icon status="warning" />
+ <div class="media-body space-children">
+ <span class="bold">
+ <template v-if="mr.mergeError">{{ mr.mergeError }}.</template>
+ {{ s__("mrWidget|This merge request failed to be merged automatically") }}
+ </span>
+ <button
+ @click="refreshWidget"
+ :disabled="isRefreshing"
+ type="button"
+ class="btn btn-xs btn-default"
+ >
+ <loading-icon
+ v-if="isRefreshing"
+ :inline="true"
+ />
+ {{ s__("mrWidget|Refresh") }}
+ </button>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.js
deleted file mode 100644
index aaf9d3304a4..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import statusIcon from '../mr_widget_status_icon';
-
-export default {
- name: 'MRWidgetChecking',
- components: {
- statusIcon,
- },
- template: `
- <div class="mr-widget-body media">
- <status-icon status="loading" showDisabledButton />
- <div class="media-body space-children">
- <span class="bold">
- Checking ability to merge automatically
- </span>
- </div>
- </div>
- `,
-};
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.vue
new file mode 100644
index 00000000000..caeaac75b45
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.vue
@@ -0,0 +1,23 @@
+<script>
+ import statusIcon from '../mr_widget_status_icon.vue';
+
+ export default {
+ name: 'MRWidgetChecking',
+ components: {
+ statusIcon,
+ },
+ };
+</script>
+<template>
+ <div class="mr-widget-body media">
+ <status-icon
+ status="loading"
+ :show-disabled-button="true"
+ />
+ <div class="media-body space-children">
+ <span class="bold">
+ {{ s__("mrWidget|Checking ability to merge automatically") }}
+ </span>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.js
deleted file mode 100644
index 4078aad7f83..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import mrWidgetAuthorTime from '../../components/mr_widget_author_time';
-import statusIcon from '../mr_widget_status_icon';
-
-export default {
- name: 'MRWidgetClosed',
- props: {
- mr: { type: Object, required: true },
- },
- components: {
- 'mr-widget-author-and-time': mrWidgetAuthorTime,
- statusIcon,
- },
- template: `
- <div class="mr-widget-body media">
- <status-icon status="failed" />
- <div class="media-body">
- <mr-widget-author-and-time
- actionText="Closed by"
- :author="mr.closedBy"
- :dateTitle="mr.updatedAt"
- :dateReadable="mr.closedAt"
- />
- <section class="mr-info-list">
- <p>
- The changes were not merged into
- <a
- :href="mr.targetBranchPath"
- class="label-branch">
- {{mr.targetBranch}}</a>
- </p>
- </section>
- </div>
- </div>
- `,
-};
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
new file mode 100644
index 00000000000..68b691fc914
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.vue
@@ -0,0 +1,48 @@
+<script>
+ import mrWidgetAuthorTime from '../../components/mr_widget_author_time.vue';
+ import statusIcon from '../mr_widget_status_icon.vue';
+
+ export default {
+ name: 'MRWidgetClosed',
+ components: {
+ mrWidgetAuthorTime,
+ statusIcon,
+ },
+ props: {
+ /* TODO: This is providing all store and service down when it
+ only needs metrics and targetBranch */
+ mr: {
+ type: Object,
+ required: true,
+ default: () => ({}),
+ },
+ },
+ };
+</script>
+<template>
+ <div class="mr-widget-body media">
+ <status-icon
+ status="warning"
+ />
+ <div class="media-body">
+ <mr-widget-author-time
+ :action-text="s__('mrWidget|Closed by')"
+ :author="mr.metrics.closedBy"
+ :date-title="mr.metrics.closedAt"
+ :date-readable="mr.metrics.readableClosedAt"
+ />
+
+ <section class="mr-info-list">
+ <p>
+ {{ s__("mrWidget|The changes were not merged into") }}
+ <a
+ :href="mr.targetBranchPath"
+ class="label-branch"
+ >
+ {{ mr.targetBranch }}
+ </a>
+ </p>
+ </section>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.js
deleted file mode 100644
index f9cb79a0bc1..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import statusIcon from '../mr_widget_status_icon';
-
-export default {
- name: 'MRWidgetConflicts',
- props: {
- mr: { type: Object, required: true },
- },
- components: {
- statusIcon,
- },
- template: `
- <div class="mr-widget-body media">
- <status-icon status="failed" showDisabledButton />
- <div class="media-body space-children">
- <span class="bold">
- There are merge conflicts<span v-if="!mr.canMerge">.</span>
- <span v-if="!mr.canMerge">
- Resolve these conflicts or ask someone with write access to this repository to merge it locally
- </span>
- </span>
- <a
- v-if="mr.canMerge && mr.conflictResolutionPath"
- :href="mr.conflictResolutionPath"
- class="btn btn-default btn-xs js-resolve-conflicts-button">
- Resolve conflicts
- </a>
- <a
- v-if="mr.canMerge"
- class="btn btn-default btn-xs js-merge-locally-button"
- data-toggle="modal"
- href="#modal_merge_info">
- Merge locally
- </a>
- </div>
- </div>
- `,
-};
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
new file mode 100644
index 00000000000..dad4b0fe49d
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue
@@ -0,0 +1,61 @@
+<script>
+ import statusIcon from '../mr_widget_status_icon.vue';
+
+ export default {
+ name: 'MRWidgetConflicts',
+ components: {
+ statusIcon,
+ },
+ props: {
+ /* TODO: This is providing all store and service down when it
+ only needs a few props */
+ mr: {
+ type: Object,
+ required: true,
+ default: () => ({}),
+ },
+ },
+ };
+</script>
+<template>
+ <div class="mr-widget-body media">
+ <status-icon
+ status="warning"
+ :show-disabled-button="true"
+ />
+
+ <div class="media-body space-children">
+ <span
+ v-if="mr.shouldBeRebased"
+ class="bold"
+ >
+ {{ s__(`mrWidget|Fast-forward merge is not possible.
+To merge this request, first rebase locally.`) }}
+ </span>
+ <template v-else>
+ <span class="bold">
+ {{ s__("mrWidget|There are merge conflicts") }}<span v-if="!mr.canMerge">.</span>
+ <span v-if="!mr.canMerge">
+ {{ s__(`mrWidget|Resolve these conflicts or ask someone
+ with write access to this repository to merge it locally`) }}
+ </span>
+ </span>
+ <a
+ v-if="mr.canMerge && mr.conflictResolutionPath"
+ :href="mr.conflictResolutionPath"
+ class="js-resolve-conflicts-button btn btn-default btn-xs"
+ >
+ {{ s__("mrWidget|Resolve conflicts") }}
+ </a>
+ <button
+ v-if="mr.canMerge"
+ class="js-merge-locally-button btn btn-default btn-xs"
+ data-toggle="modal"
+ data-target="#modal_merge_info"
+ >
+ {{ s__("mrWidget|Merge locally") }}
+ </button>
+ </template>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.js
deleted file mode 100644
index 1cb24549d53..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.js
+++ /dev/null
@@ -1,78 +0,0 @@
-import statusIcon from '../mr_widget_status_icon';
-import eventHub from '../../event_hub';
-
-export default {
- name: 'MRWidgetFailedToMerge',
- props: {
- mr: { type: Object, required: true },
- },
- data() {
- return {
- timer: 10,
- isRefreshing: false,
- };
- },
- mounted() {
- setInterval(() => {
- this.updateTimer();
- }, 1000);
- },
- created() {
- eventHub.$emit('DisablePolling');
- },
- computed: {
- timerText() {
- return this.timer > 1 ? `${this.timer} seconds` : 'a second';
- },
- },
- methods: {
- refresh() {
- this.isRefreshing = true;
- eventHub.$emit('MRWidgetUpdateRequested');
- eventHub.$emit('EnablePolling');
- },
- updateTimer() {
- this.timer = this.timer - 1;
-
- if (this.timer === 0) {
- this.refresh();
- }
- },
- },
- components: {
- statusIcon,
- },
- template: `
- <div class="mr-widget-body media">
- <template v-if="isRefreshing">
- <status-icon status="loading" />
- <span class="media-body bold js-refresh-label">
- Refreshing now
- </span>
- </template>
- <template v-else>
- <status-icon status="failed" showDisabledButton />
- <div class="media-body space-children">
- <span class="bold">
- <span
- class="has-error-message"
- v-if="mr.mergeError">
- {{mr.mergeError}}.
- </span>
- <span v-else>Merge failed.</span>
- <span
- :class="{ 'has-custom-error': mr.mergeError }">
- Refreshing in {{timerText}} to show the updated status...
- </span>
- </span>
- <button
- @click="refresh"
- class="btn btn-default btn-xs js-refresh-button"
- type="button">
- Refresh now
- </button>
- </div>
- </template>
- </div>
- `,
-};
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue
new file mode 100644
index 00000000000..602b68ea572
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue
@@ -0,0 +1,105 @@
+<script>
+ import { n__ } from '~/locale';
+ import statusIcon from '../mr_widget_status_icon.vue';
+ import eventHub from '../../event_hub';
+
+ export default {
+ name: 'MRWidgetFailedToMerge',
+
+ components: {
+ statusIcon,
+ },
+
+ props: {
+ mr: {
+ type: Object,
+ required: true,
+ default: () => ({}),
+ },
+ },
+
+ data() {
+ return {
+ timer: 10,
+ isRefreshing: false,
+ };
+ },
+
+ computed: {
+ timerText() {
+ return n__(
+ 'Refreshing in a second to show the updated status...',
+ 'Refreshing in %d seconds to show the updated status...',
+ this.timer,
+ );
+ },
+ },
+
+ mounted() {
+ setInterval(() => {
+ this.updateTimer();
+ }, 1000);
+ },
+
+ created() {
+ eventHub.$emit('DisablePolling');
+ },
+
+ methods: {
+ refresh() {
+ this.isRefreshing = true;
+ eventHub.$emit('MRWidgetUpdateRequested');
+ eventHub.$emit('EnablePolling');
+ },
+ updateTimer() {
+ this.timer = this.timer - 1;
+
+ if (this.timer === 0) {
+ this.refresh();
+ }
+ },
+ },
+
+ };
+</script>
+<template>
+ <div class="mr-widget-body media">
+ <template v-if="isRefreshing">
+ <status-icon status="loading" />
+ <span class="media-body bold js-refresh-label">
+ {{ s__("mrWidget|Refreshing now") }}
+ </span>
+ </template>
+ <template v-else>
+ <status-icon
+ status="warning"
+ :show-disabled-button="true"
+ />
+ <div class="media-body space-children">
+ <span class="bold">
+ <span
+ class="has-error-message"
+ v-if="mr.mergeError"
+ >
+ {{ mr.mergeError }}.
+ </span>
+ <span v-else>
+ {{ s__("mrWidget|Merge failed.") }}
+ </span>
+ <span
+ :class="{ 'has-custom-error': mr.mergeError }"
+ >
+ {{ timerText }}
+ </span>
+ </span>
+ <button
+ @click="refresh"
+ class="btn btn-default btn-xs js-refresh-button"
+ type="button"
+ >
+ {{ s__("mrWidget|Refresh now") }}
+ </button>
+ </div>
+ </template>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.js
deleted file mode 100644
index bdfd4d9667c..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.js
+++ /dev/null
@@ -1,117 +0,0 @@
-/* global Flash */
-import statusIcon from '../mr_widget_status_icon';
-import MRWidgetAuthor from '../../components/mr_widget_author';
-import eventHub from '../../event_hub';
-
-export default {
- name: 'MRWidgetMergeWhenPipelineSucceeds',
- props: {
- mr: { type: Object, required: true },
- service: { type: Object, required: true },
- },
- components: {
- 'mr-widget-author': MRWidgetAuthor,
- statusIcon,
- },
- data() {
- return {
- isCancellingAutoMerge: false,
- isRemovingSourceBranch: false,
- };
- },
- computed: {
- canRemoveSourceBranch() {
- const { shouldRemoveSourceBranch, canRemoveSourceBranch,
- mergeUserId, currentUserId } = this.mr;
-
- return !shouldRemoveSourceBranch && canRemoveSourceBranch && mergeUserId === currentUserId;
- },
- },
- methods: {
- cancelAutomaticMerge() {
- this.isCancellingAutoMerge = true;
- this.service.cancelAutomaticMerge()
- .then(res => res.json())
- .then((res) => {
- eventHub.$emit('UpdateWidgetData', res);
- })
- .catch(() => {
- this.isCancellingAutoMerge = false;
- new Flash('Something went wrong. Please try again.'); // eslint-disable-line
- });
- },
- removeSourceBranch() {
- const options = {
- sha: this.mr.sha,
- merge_when_pipeline_succeeds: true,
- should_remove_source_branch: true,
- };
-
- this.isRemovingSourceBranch = true;
- this.service.mergeResource.save(options)
- .then(res => res.json())
- .then((res) => {
- if (res.status === 'merge_when_pipeline_succeeds') {
- eventHub.$emit('MRWidgetUpdateRequested');
- }
- })
- .catch(() => {
- this.isRemovingSourceBranch = false;
- new Flash('Something went wrong. Please try again.'); // eslint-disable-line
- });
- },
- },
- template: `
- <div class="mr-widget-body media">
- <status-icon status="success" />
- <div class="media-body">
- <h4>
- Set by
- <mr-widget-author :author="mr.setToMWPSBy" />
- to be merged automatically when the pipeline succeeds
- <a
- v-if="mr.canCancelAutomaticMerge"
- @click.prevent="cancelAutomaticMerge"
- :disabled="isCancellingAutoMerge"
- role="button"
- href="#"
- class="btn btn-xs btn-default js-cancel-auto-merge">
- <i
- v-if="isCancellingAutoMerge"
- class="fa fa-spinner fa-spin"
- aria-hidden="true" />
- Cancel automatic merge
- </a>
- </h4>
- <section class="mr-info-list">
- <p>The changes will be merged into
- <a
- :href="mr.targetBranchPath"
- class="label-branch">
- {{mr.targetBranch}}
- </a>
- </p>
- <p v-if="mr.shouldRemoveSourceBranch">
- The source branch will be removed
- </p>
- <p v-else>
- The source branch will not be removed
- <a
- v-if="canRemoveSourceBranch"
- :disabled="isRemovingSourceBranch"
- @click.prevent="removeSourceBranch"
- role="button"
- class="btn btn-xs btn-default js-remove-source-branch"
- href="#">
- <i
- v-if="isRemovingSourceBranch"
- class="fa fa-spinner fa-spin"
- aria-hidden="true" />
- Remove source branch
- </a>
- </p>
- </section>
- </div>
- </div>
- `,
-};
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue
new file mode 100644
index 00000000000..de98a77be6f
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue
@@ -0,0 +1,147 @@
+<script>
+ import Flash from '../../../flash';
+ import statusIcon from '../mr_widget_status_icon.vue';
+ import mrWidgetAuthor from '../../components/mr_widget_author.vue';
+ import eventHub from '../../event_hub';
+
+ export default {
+ name: 'MRWidgetMergeWhenPipelineSucceeds',
+ components: {
+ mrWidgetAuthor,
+ statusIcon,
+ },
+ props: {
+ mr: {
+ type: Object,
+ required: true,
+ default: () => ({}),
+ },
+ service: {
+ type: Object,
+ required: true,
+ default: () => ({}),
+ },
+ },
+ data() {
+ return {
+ isCancellingAutoMerge: false,
+ isRemovingSourceBranch: false,
+ };
+ },
+ computed: {
+ canRemoveSourceBranch() {
+ const {
+ shouldRemoveSourceBranch,
+ canRemoveSourceBranch,
+ mergeUserId,
+ currentUserId,
+ } = this.mr;
+
+ return !shouldRemoveSourceBranch &&
+ canRemoveSourceBranch &&
+ mergeUserId === currentUserId;
+ },
+ },
+ methods: {
+ cancelAutomaticMerge() {
+ this.isCancellingAutoMerge = true;
+ this.service.cancelAutomaticMerge()
+ .then(res => res.data)
+ .then((data) => {
+ eventHub.$emit('UpdateWidgetData', data);
+ })
+ .catch(() => {
+ this.isCancellingAutoMerge = false;
+ Flash('Something went wrong. Please try again.');
+ });
+ },
+ removeSourceBranch() {
+ const options = {
+ sha: this.mr.sha,
+ merge_when_pipeline_succeeds: true,
+ should_remove_source_branch: true,
+ };
+
+ this.isRemovingSourceBranch = true;
+ this.service.mergeResource.save(options)
+ .then(res => res.data)
+ .then((data) => {
+ if (data.status === 'merge_when_pipeline_succeeds') {
+ eventHub.$emit('MRWidgetUpdateRequested');
+ }
+ })
+ .catch(() => {
+ this.isRemovingSourceBranch = false;
+ Flash('Something went wrong. Please try again.');
+ });
+ },
+ },
+ };
+</script>
+<template>
+ <div class="mr-widget-body media">
+ <status-icon status="success" />
+ <div class="media-body">
+ <h4 class="flex-container-block">
+ <span class="append-right-10">
+ {{ s__("mrWidget|Set by") }}
+ <mr-widget-author :author="mr.setToMWPSBy" />
+ {{ s__("mrWidget|to be merged automatically when the pipeline succeeds") }}
+ </span>
+ <a
+ v-if="mr.canCancelAutomaticMerge"
+ @click.prevent="cancelAutomaticMerge"
+ :disabled="isCancellingAutoMerge"
+ role="button"
+ href="#"
+ class="btn btn-xs btn-default js-cancel-auto-merge">
+ <i
+ v-if="isCancellingAutoMerge"
+ class="fa fa-spinner fa-spin"
+ aria-hidden="true"
+ >
+ </i>
+ {{ s__("mrWidget|Cancel automatic merge") }}
+ </a>
+ </h4>
+ <section class="mr-info-list">
+ <p>
+ {{ s__("mrWidget|The changes will be merged into") }}
+ <a
+ :href="mr.targetBranchPath"
+ class="label-branch"
+ >
+ {{ mr.targetBranch }}
+ </a>
+ </p>
+ <p v-if="mr.shouldRemoveSourceBranch">
+ {{ s__("mrWidget|The source branch will be removed") }}
+ </p>
+ <p
+ v-else
+ class="flex-container-block"
+ >
+ <span class="append-right-10">
+ {{ s__("mrWidget|The source branch will not be removed") }}
+ </span>
+ <a
+ v-if="canRemoveSourceBranch"
+ :disabled="isRemovingSourceBranch"
+ @click.prevent="removeSourceBranch"
+ role="button"
+ class="btn btn-xs btn-default js-remove-source-branch"
+ href="#"
+ >
+ <i
+ v-if="isRemovingSourceBranch"
+ class="fa fa-spinner fa-spin"
+ aria-hidden="true"
+ >
+ </i>
+ {{ s__("mrWidget|Remove source branch") }}
+ </a>
+ </p>
+ </section>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.js
deleted file mode 100644
index e452260a4d0..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.js
+++ /dev/null
@@ -1,140 +0,0 @@
-/* global Flash */
-
-import mrWidgetAuthorTime from '../../components/mr_widget_author_time';
-import tooltip from '../../../vue_shared/directives/tooltip';
-import loadingIcon from '../../../vue_shared/components/loading_icon.vue';
-import statusIcon from '../mr_widget_status_icon';
-import eventHub from '../../event_hub';
-
-export default {
- name: 'MRWidgetMerged',
- props: {
- mr: { type: Object, required: true },
- service: { type: Object, required: true },
- },
- data() {
- return {
- isMakingRequest: false,
- };
- },
- directives: {
- tooltip,
- },
- components: {
- 'mr-widget-author-and-time': mrWidgetAuthorTime,
- loadingIcon,
- statusIcon,
- },
- computed: {
- shouldShowRemoveSourceBranch() {
- const { sourceBranchRemoved, isRemovingSourceBranch, canRemoveSourceBranch } = this.mr;
-
- return !sourceBranchRemoved && canRemoveSourceBranch &&
- !this.isMakingRequest && !isRemovingSourceBranch;
- },
- shouldShowSourceBranchRemoving() {
- const { sourceBranchRemoved, isRemovingSourceBranch } = this.mr;
- return !sourceBranchRemoved && (isRemovingSourceBranch || this.isMakingRequest);
- },
- shouldShowMergedButtons() {
- const { canRevertInCurrentMR, canCherryPickInCurrentMR, revertInForkPath,
- cherryPickInForkPath } = this.mr;
-
- return canRevertInCurrentMR || canCherryPickInCurrentMR ||
- revertInForkPath || cherryPickInForkPath;
- },
- },
- methods: {
- removeSourceBranch() {
- this.isMakingRequest = true;
- this.service.removeSourceBranch()
- .then(res => res.json())
- .then((res) => {
- if (res.message === 'Branch was removed') {
- eventHub.$emit('MRWidgetUpdateRequested', () => {
- this.isMakingRequest = false;
- });
- }
- })
- .catch(() => {
- this.isMakingRequest = false;
- new Flash('Something went wrong. Please try again.'); // eslint-disable-line
- });
- },
- },
- template: `
- <div class="mr-widget-body media">
- <status-icon status="success" />
- <div class="media-body">
- <div class="space-children">
- <mr-widget-author-and-time
- actionText="Merged by"
- :author="mr.mergedBy"
- :dateTitle="mr.updatedAt"
- :dateReadable="mr.mergedAt" />
- <a
- v-if="mr.canRevertInCurrentMR"
- v-tooltip
- class="btn btn-close btn-xs"
- href="#modal-revert-commit"
- data-toggle="modal"
- data-container="body"
- title="Revert this merge request in a new merge request">
- Revert
- </a>
- <a
- v-else-if="mr.revertInForkPath"
- v-tooltip
- class="btn btn-close btn-xs"
- data-method="post"
- :href="mr.revertInForkPath"
- title="Revert this merge request in a new merge request">
- Revert
- </a>
- <a
- v-if="mr.canCherryPickInCurrentMR"
- v-tooltip
- class="btn btn-default btn-xs"
- href="#modal-cherry-pick-commit"
- data-toggle="modal"
- data-container="body"
- title="Cherry-pick this merge request in a new merge request">
- Cherry-pick
- </a>
- <a
- v-else-if="mr.cherryPickInForkPath"
- v-tooltip
- class="btn btn-default btn-xs"
- data-method="post"
- :href="mr.cherryPickInForkPath"
- title="Cherry-pick this merge request in a new merge request">
- Cherry-pick
- </a>
- </div>
- <section class="mr-info-list">
- <p>
- The changes were merged into
- <span class="label-branch">
- <a :href="mr.targetBranchPath">{{mr.targetBranch}}</a>
- </span>
- </p>
- <p v-if="mr.sourceBranchRemoved">The source branch has been removed</p>
- <p v-if="shouldShowRemoveSourceBranch" class="space-children">
- <span>You can remove source branch now</span>
- <button
- @click="removeSourceBranch"
- :disabled="isMakingRequest"
- type="button"
- class="btn btn-xs btn-default js-remove-branch-button">
- Remove Source Branch
- </button>
- </p>
- <p v-if="shouldShowSourceBranchRemoving">
- <loading-icon inline />
- <span>The source branch is being removed</span>
- </p>
- </section>
- </div>
- </div>
- `,
-};
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
new file mode 100644
index 00000000000..c1618bc6ea0
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue
@@ -0,0 +1,192 @@
+<script>
+ import Flash from '~/flash';
+ import tooltip from '~/vue_shared/directives/tooltip';
+ import loadingIcon from '~/vue_shared/components/loading_icon.vue';
+ import { s__, __ } from '~/locale';
+ import mrWidgetAuthorTime from '../../components/mr_widget_author_time.vue';
+ import statusIcon from '../mr_widget_status_icon.vue';
+ import eventHub from '../../event_hub';
+
+ export default {
+ name: 'MRWidgetMerged',
+ directives: {
+ tooltip,
+ },
+ components: {
+ mrWidgetAuthorTime,
+ loadingIcon,
+ statusIcon,
+ },
+ props: {
+ mr: {
+ type: Object,
+ required: true,
+ default: () => ({}),
+ },
+ service: {
+ type: Object,
+ required: true,
+ default: () => ({}),
+ },
+ },
+ data() {
+ return {
+ isMakingRequest: false,
+ };
+ },
+ computed: {
+ shouldShowRemoveSourceBranch() {
+ const {
+ sourceBranchRemoved,
+ isRemovingSourceBranch,
+ canRemoveSourceBranch,
+ } = this.mr;
+
+ return !sourceBranchRemoved &&
+ canRemoveSourceBranch &&
+ !this.isMakingRequest &&
+ !isRemovingSourceBranch;
+ },
+ shouldShowSourceBranchRemoving() {
+ const {
+ sourceBranchRemoved,
+ isRemovingSourceBranch,
+ } = this.mr;
+ return !sourceBranchRemoved &&
+ (isRemovingSourceBranch || this.isMakingRequest);
+ },
+ shouldShowMergedButtons() {
+ const {
+ canRevertInCurrentMR,
+ canCherryPickInCurrentMR,
+ revertInForkPath,
+ cherryPickInForkPath,
+ } = this.mr;
+
+ return canRevertInCurrentMR ||
+ canCherryPickInCurrentMR ||
+ revertInForkPath ||
+ cherryPickInForkPath;
+ },
+ revertTitle() {
+ return s__('mrWidget|Revert this merge request in a new merge request');
+ },
+ cherryPickTitle() {
+ return s__('mrWidget|Cherry-pick this merge request in a new merge request');
+ },
+ revertLabel() {
+ return s__('mrWidget|Revert');
+ },
+ cherryPickLabel() {
+ return s__('mrWidget|Cherry-pick');
+ },
+ },
+ methods: {
+ removeSourceBranch() {
+ this.isMakingRequest = true;
+
+ this.service.removeSourceBranch()
+ .then(res => res.data)
+ .then((data) => {
+ if (data.message === 'Branch was removed') {
+ eventHub.$emit('MRWidgetUpdateRequested', () => {
+ this.isMakingRequest = false;
+ });
+ }
+ })
+ .catch(() => {
+ this.isMakingRequest = false;
+ Flash(__('Something went wrong. Please try again.'));
+ });
+ },
+ },
+ };
+</script>
+<template>
+ <div class="mr-widget-body media">
+ <status-icon status="success" />
+ <div class="media-body">
+ <div class="space-children">
+ <mr-widget-author-time
+ :action-text="s__('mrWidget|Merged by')"
+ :author="mr.metrics.mergedBy"
+ :date-title="mr.metrics.mergedAt"
+ :date-readable="mr.metrics.readableMergedAt"
+ />
+ <a
+ v-if="mr.canRevertInCurrentMR"
+ v-tooltip
+ class="btn btn-close btn-xs"
+ href="#modal-revert-commit"
+ data-toggle="modal"
+ data-container="body"
+ :title="revertTitle"
+ >
+ {{ revertLabel }}
+ </a>
+ <a
+ v-else-if="mr.revertInForkPath"
+ v-tooltip
+ class="btn btn-close btn-xs"
+ data-method="post"
+ :href="mr.revertInForkPath"
+ :title="revertTitle"
+ >
+ {{ revertLabel }}
+ </a>
+ <a
+ v-if="mr.canCherryPickInCurrentMR"
+ v-tooltip
+ class="btn btn-default btn-xs"
+ href="#modal-cherry-pick-commit"
+ data-toggle="modal"
+ data-container="body"
+ :title="cherryPickTitle"
+ >
+ {{ cherryPickLabel }}
+ </a>
+ <a
+ v-else-if="mr.cherryPickInForkPath"
+ v-tooltip
+ class="btn btn-default btn-xs"
+ data-method="post"
+ :href="mr.cherryPickInForkPath"
+ :title="cherryPickTitle"
+ >
+ {{ cherryPickLabel }}
+ </a>
+ </div>
+ <section class="mr-info-list">
+ <p>
+ {{ s__("mrWidget|The changes were merged into") }}
+ <span class="label-branch">
+ <a :href="mr.targetBranchPath">{{ mr.targetBranch }}</a>
+ </span>
+ </p>
+ <p v-if="mr.sourceBranchRemoved">
+ {{ s__("mrWidget|The source branch has been removed") }}
+ </p>
+ <p
+ v-if="shouldShowRemoveSourceBranch"
+ class="space-children"
+ >
+ <span>{{ s__("mrWidget|You can remove source branch now") }}</span>
+ <button
+ @click="removeSourceBranch"
+ :disabled="isMakingRequest"
+ type="button"
+ class="btn btn-xs btn-default js-remove-branch-button"
+ >
+ {{ s__("mrWidget|Remove Source Branch") }}
+ </button>
+ </p>
+ <p v-if="shouldShowSourceBranchRemoving">
+ <loading-icon :inline="true" />
+ <span>
+ {{ s__("mrWidget|The source branch is being removed") }}
+ </span>
+ </p>
+ </section>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merging.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merging.js
deleted file mode 100644
index f6d1a4feeb2..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merging.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import statusIcon from '../mr_widget_status_icon';
-
-export default {
- name: 'MRWidgetMerging',
- props: {
- mr: { type: Object, required: true },
- },
- components: {
- statusIcon,
- },
- template: `
- <div class="mr-widget-body mr-state-locked media">
- <status-icon status="loading" />
- <div class="media-body">
- <h4>
- This merge request is in the process of being merged
- </h4>
- <section class="mr-info-list">
- <p>
- The changes will be merged into
- <span class="label-branch">
- <a :href="mr.targetBranchPath">{{mr.targetBranch}}</a>
- </span>
- </p>
- </section>
- </div>
- </div>
- `,
-};
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
new file mode 100644
index 00000000000..953ddf40a51
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merging.vue
@@ -0,0 +1,35 @@
+<script>
+ import statusIcon from '../mr_widget_status_icon.vue';
+
+ export default {
+ name: 'MRWidgetMerging',
+ components: {
+ statusIcon,
+ },
+ props: {
+ mr: {
+ type: Object,
+ required: true,
+ default: () => ({}),
+ },
+ },
+ };
+</script>
+<template>
+ <div class="mr-widget-body mr-state-locked media">
+ <status-icon status="loading" />
+ <div class="media-body">
+ <h4>
+ {{ s__("mrWidget|This merge request is in the process of being merged") }}
+ </h4>
+ <section class="mr-info-list">
+ <p>
+ {{ s__("mrWidget|The changes will be merged into") }}
+ <span class="label-branch">
+ <a :href="mr.targetBranchPath">{{ mr.targetBranch }}</a>
+ </span>
+ </p>
+ </section>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.js
deleted file mode 100644
index 9f0a359d01a..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import statusIcon from '../mr_widget_status_icon';
-import tooltip from '../../../vue_shared/directives/tooltip';
-import mrWidgetMergeHelp from '../../components/mr_widget_merge_help';
-
-export default {
- name: 'MRWidgetMissingBranch',
- props: {
- mr: { type: Object, required: true },
- },
- directives: {
- tooltip,
- },
- components: {
- 'mr-widget-merge-help': mrWidgetMergeHelp,
- statusIcon,
- },
- computed: {
- missingBranchName() {
- return this.mr.sourceBranchRemoved ? 'source' : 'target';
- },
- message() {
- return `If the ${this.missingBranchName} branch exists in your local repository, you can merge this merge request manually using the command line`;
- },
- },
- template: `
- <div class="mr-widget-body media">
- <status-icon status="failed" showDisabledButton />
- <div class="media-body space-children">
- <span class="bold js-branch-text">
- <span class="capitalize">
- {{missingBranchName}}
- </span> branch does not exist.
- Please restore it or use a different {{missingBranchName}} branch
- <i
- v-tooltip
- class="fa fa-question-circle"
- :title="message"
- :aria-label="message"></i>
- </span>
- </div>
- </div>
- `,
-};
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue
new file mode 100644
index 00000000000..718c0e4b3c6
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue
@@ -0,0 +1,62 @@
+<script>
+ import { sprintf, s__ } from '~/locale';
+ import tooltip from '~/vue_shared/directives/tooltip';
+ import statusIcon from '../mr_widget_status_icon.vue';
+ import mrWidgetMergeHelp from '../../components/mr_widget_merge_help.vue';
+
+ export default {
+ name: 'MRWidgetMissingBranch',
+ directives: {
+ tooltip,
+ },
+ components: {
+ mrWidgetMergeHelp,
+ statusIcon,
+ },
+ props: {
+ mr: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ missingBranchName() {
+ return this.mr.sourceBranchRemoved ? 'source' : 'target';
+ },
+ missingBranchNameMessage() {
+ return sprintf(s__('mrWidget| Please restore it or use a different %{missingBranchName} branch'), {
+ missingBranchName: this.missingBranchName,
+ });
+ },
+ message() {
+ return sprintf(s__('mrWidget|If the %{missingBranchName} branch exists in your local repository, you can merge this merge request manually using the command line'), {
+ missingBranchName: this.missingBranchName,
+ });
+ },
+ },
+ };
+</script>
+<template>
+ <div class="mr-widget-body media">
+ <status-icon
+ status="warning"
+ :show-disabled-button="true"
+ />
+
+ <div class="media-body space-children">
+ <span class="bold js-branch-text">
+ <span class="capitalize">
+ {{ missingBranchName }}
+ </span> {{ s__("mrWidget|branch does not exist.") }}
+ {{ missingBranchNameMessage }}
+ <i
+ v-tooltip
+ class="fa fa-question-circle"
+ :title="message"
+ :aria-label="message"
+ >
+ </i>
+ </span>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_not_allowed.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_not_allowed.js
deleted file mode 100644
index 797511d4e3a..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_not_allowed.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import statusIcon from '../mr_widget_status_icon';
-
-export default {
- name: 'MRWidgetNotAllowed',
- components: {
- statusIcon,
- },
- template: `
- <div class="mr-widget-body media">
- <status-icon status="success" showDisabledButton />
- <div class="media-body space-children">
- <span class="bold">
- Ready to be merged automatically.
- Ask someone with write access to this repository to merge this request
- </span>
- </div>
- </div>
- `,
-};
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_not_allowed.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_not_allowed.vue
new file mode 100644
index 00000000000..e4af50b09f8
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_not_allowed.vue
@@ -0,0 +1,25 @@
+<script>
+ import StatusIcon from '../mr_widget_status_icon.vue';
+
+ export default {
+ name: 'MRWidgetNotAllowed',
+ components: {
+ StatusIcon,
+ },
+ };
+</script>
+
+<template>
+ <div class="mr-widget-body media">
+ <status-icon
+ status="success"
+ :show-disabled-button="true"
+ />
+ <div class="media-body space-children">
+ <span class="bold">
+ {{ s__(`mrWidget|Ready to be merged automatically.
+Ask someone with write access to this repository to merge this request`) }}
+ </span>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.js
deleted file mode 100644
index 167a0d4613a..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import statusIcon from '../mr_widget_status_icon';
-
-export default {
- name: 'MRWidgetPipelineBlocked',
- components: {
- statusIcon,
- },
- template: `
- <div class="mr-widget-body media">
- <status-icon status="failed" showDisabledButton />
- <div class="media-body space-children">
- <span class="bold">
- Pipeline blocked. The pipeline for this merge request requires a manual action to proceed
- </span>
- </div>
- </div>
- `,
-};
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.vue
new file mode 100644
index 00000000000..6d7cc03f7ad
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.vue
@@ -0,0 +1,24 @@
+<script>
+ import StatusIcon from '../mr_widget_status_icon.vue';
+
+ export default {
+ name: 'MRWidgetPipelineBlocked',
+ components: {
+ StatusIcon,
+ },
+ };
+</script>
+<template>
+ <div class="mr-widget-body media">
+ <status-icon
+ status="warning"
+ :show-disabled-button="true"
+ />
+ <div class="media-body space-children">
+ <span class="bold">
+ {{ s__(`mrWidget|Pipeline blocked.
+The pipeline for this merge request requires a manual action to proceed`) }}
+ </span>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_failed.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_failed.js
index c5be9a0530a..4d9a2ca530f 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_failed.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_failed.js
@@ -1,4 +1,4 @@
-import statusIcon from '../mr_widget_status_icon';
+import statusIcon from '../mr_widget_status_icon.vue';
export default {
name: 'MRWidgetPipelineBlocked',
@@ -7,7 +7,7 @@ export default {
},
template: `
<div class="mr-widget-body media">
- <status-icon status="failed" showDisabledButton />
+ <status-icon status="warning" :show-disabled-button="true" />
<div class="media-body space-children">
<span class="bold">
The pipeline for this merge request failed. Please retry the job or push a new commit to fix the failure
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js
index ad709da51ee..162f048aac7 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js
@@ -1,8 +1,9 @@
-/* global Flash */
import successSvg from 'icons/_icon_status_success.svg';
import warningSvg from 'icons/_icon_status_warning.svg';
import simplePoll from '~/lib/utils/simple_poll';
-import statusIcon from '../mr_widget_status_icon';
+import MergeRequest from '../../../merge_request';
+import Flash from '../../../flash';
+import statusIcon from '../mr_widget_status_icon.vue';
import eventHub from '../../event_hub';
export default {
@@ -38,24 +39,40 @@ export default {
return this.useCommitMessageWithDescription ? withoutDesc : withDesc;
},
- mergeButtonClass() {
- const defaultClass = 'btn btn-sm btn-success accept-merge-request';
- const failedClass = `${defaultClass} btn-danger`;
- const inActionClass = `${defaultClass} btn-info`;
+ status() {
const { pipeline, isPipelineActive, isPipelineFailed, hasCI, ciStatus } = this.mr;
if (hasCI && !ciStatus) {
- return failedClass;
+ return 'failed';
} else if (!pipeline) {
- return defaultClass;
+ return 'success';
} else if (isPipelineActive) {
- return inActionClass;
+ return 'pending';
} else if (isPipelineFailed) {
+ return 'failed';
+ }
+
+ return 'success';
+ },
+ mergeButtonClass() {
+ const defaultClass = 'btn btn-sm btn-success accept-merge-request';
+ const failedClass = `${defaultClass} btn-danger`;
+ const inActionClass = `${defaultClass} btn-info`;
+
+ if (this.status === 'failed') {
return failedClass;
+ } else if (this.status === 'pending') {
+ return inActionClass;
}
return defaultClass;
},
+ iconClass() {
+ if (this.status === 'failed' || !this.commitMessage.length || !this.mr.isMergeAllowed || this.mr.preventMerge) {
+ return 'warning';
+ }
+ return 'success';
+ },
mergeButtonText() {
if (this.isMergingImmediately) {
return 'Merge in progress';
@@ -84,13 +101,8 @@ export default {
},
},
methods: {
- isMergeAllowed() {
- return !this.mr.onlyAllowMergeIfPipelineSucceeds ||
- this.mr.isPipelinePassing ||
- this.mr.isPipelineSkipped;
- },
shouldShowMergeControls() {
- return this.isMergeAllowed() || this.shouldShowMergeWhenPipelineSucceedsText;
+ return this.mr.isMergeAllowed || this.shouldShowMergeWhenPipelineSucceedsText;
},
updateCommitMessage() {
const cmwd = this.mr.commitMessageWithDescription;
@@ -124,16 +136,16 @@ export default {
this.isMakingRequest = true;
this.service.merge(options)
- .then(res => res.json())
- .then((res) => {
- const hasError = res.status === 'failed' || res.status === 'hook_validation_error';
+ .then(res => res.data)
+ .then((data) => {
+ const hasError = data.status === 'failed' || data.status === 'hook_validation_error';
- if (res.status === 'merge_when_pipeline_succeeds') {
+ if (data.status === 'merge_when_pipeline_succeeds') {
eventHub.$emit('MRWidgetUpdateRequested');
- } else if (res.status === 'success') {
+ } else if (data.status === 'success') {
this.initiateMergePolling();
} else if (hasError) {
- eventHub.$emit('FailedToMerge', res.merge_error);
+ eventHub.$emit('FailedToMerge', data.merge_error);
}
})
.catch(() => {
@@ -148,25 +160,24 @@ export default {
},
handleMergePolling(continuePolling, stopPolling) {
this.service.poll()
- .then(res => res.json())
- .then((res) => {
- if (res.state === 'merged') {
+ .then(res => res.data)
+ .then((data) => {
+ if (data.state === 'merged') {
// If state is merged we should update the widget and stop the polling
eventHub.$emit('MRWidgetUpdateRequested');
eventHub.$emit('FetchActionsContent');
- if (window.mergeRequest) {
- window.mergeRequest.updateStatusText('status-box-open', 'status-box-merged', 'Merged');
- window.mergeRequest.decreaseCounter();
- }
+ MergeRequest.setStatusBoxToMerged();
+ MergeRequest.hideCloseButton();
+ MergeRequest.decreaseCounter();
stopPolling();
// If user checked remove source branch and we didn't remove the branch yet
// we should start another polling for source branch remove process
- if (this.removeSourceBranch && res.source_branch_exists) {
+ if (this.removeSourceBranch && data.source_branch_exists) {
this.initiateRemoveSourceBranchPolling();
}
- } else if (res.merge_error) {
- eventHub.$emit('FailedToMerge', res.merge_error);
+ } else if (data.merge_error) {
+ eventHub.$emit('FailedToMerge', data.merge_error);
stopPolling();
} else {
// MR is not merged yet, continue polling until the state becomes 'merged'
@@ -187,11 +198,11 @@ export default {
},
handleRemoveBranchPolling(continuePolling, stopPolling) {
this.service.poll()
- .then(res => res.json())
- .then((res) => {
+ .then(res => res.data)
+ .then((data) => {
// If source branch exists then we should continue polling
// because removing a source branch is a background task and takes time
- if (res.source_branch_exists) {
+ if (data.source_branch_exists) {
continuePolling();
} else {
// Branch is removed. Update widget, stop polling and hide the spinner
@@ -208,7 +219,7 @@ export default {
},
template: `
<div class="mr-widget-body media">
- <status-icon status="success" />
+ <status-icon :status="iconClass" />
<div class="media-body">
<div class="mr-widget-body-controls media space-children">
<span class="btn-group append-bottom-5">
@@ -216,7 +227,8 @@ export default {
@click="handleMergeButtonClick()"
:disabled="isMergeButtonDisabled"
:class="mergeButtonClass"
- type="button">
+ type="button"
+ class="qa-merge-button">
<i
v-if="isMakingRequest"
class="fa fa-spinner fa-spin"
@@ -274,6 +286,7 @@ export default {
<input
id="remove-source-branch-input"
v-model="removeSourceBranch"
+ class="js-remove-source-branch-checkbox"
:disabled="isRemoveSourceBranchButtonDisabled"
type="checkbox"/> Remove source branch
</label>
@@ -284,17 +297,23 @@ export default {
:mr="mr"
:is-merge-button-disabled="isMergeButtonDisabled" />
+ <span
+ v-if="mr.ffOnlyEnabled"
+ class="js-fast-forward-message">
+ Fast-forward merge without a merge commit
+ </span>
<button
+ v-else
@click="toggleCommitMessageEditor"
:disabled="isMergeButtonDisabled"
- class="btn btn-default btn-xs"
+ class="js-modify-commit-message-button btn btn-default btn-xs"
type="button">
Modify commit message
</button>
</template>
<template v-else>
- <span class="bold">
- The pipeline for this merge request has not succeeded yet
+ <span class="bold js-resolve-mr-widget-items-message">
+ You can only merge once the items above are resolved
</span>
</template>
</div>
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
new file mode 100644
index 00000000000..143fd328d88
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue
@@ -0,0 +1,138 @@
+<script>
+ import simplePoll from '../../../lib/utils/simple_poll';
+ import eventHub from '../../event_hub';
+ import statusIcon from '../mr_widget_status_icon.vue';
+ import loadingIcon from '../../../vue_shared/components/loading_icon.vue';
+ import Flash from '../../../flash';
+
+ export default {
+ name: 'MRWidgetRebase',
+ components: {
+ statusIcon,
+ loadingIcon,
+ },
+ props: {
+ mr: {
+ type: Object,
+ required: true,
+ },
+ service: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ isMakingRequest: false,
+ rebasingError: null,
+ };
+ },
+ computed: {
+ status() {
+ if (this.mr.rebaseInProgress || this.isMakingRequest) {
+ return 'loading';
+ }
+ if (!this.mr.canPushToSourceBranch && !this.mr.rebaseInProgress) {
+ return 'warning';
+ }
+ return 'success';
+ },
+ showDisabledButton() {
+ return ['failed', 'loading'].includes(this.status);
+ },
+ },
+ methods: {
+ rebase() {
+ this.isMakingRequest = true;
+ this.rebasingError = null;
+
+ this.service.rebase()
+ .then(() => {
+ simplePoll(this.checkRebaseStatus);
+ })
+ .catch((error) => {
+ this.rebasingError = error.merge_error;
+ this.isMakingRequest = false;
+ Flash('Something went wrong. Please try again.');
+ });
+ },
+ checkRebaseStatus(continuePolling, stopPolling) {
+ this.service.poll()
+ .then(res => res.data)
+ .then((res) => {
+ if (res.rebase_in_progress) {
+ continuePolling();
+ } else {
+ this.isMakingRequest = false;
+
+ if (res.merge_error && res.merge_error.length) {
+ this.rebasingError = res.merge_error;
+ Flash('Something went wrong. Please try again.');
+ }
+
+ eventHub.$emit('MRWidgetUpdateRequested');
+ stopPolling();
+ }
+ })
+ .catch(() => {
+ this.isMakingRequest = false;
+ Flash('Something went wrong. Please try again.');
+ stopPolling();
+ });
+ },
+ },
+ };
+</script>
+<template>
+ <div class="mr-widget-body media">
+ <status-icon
+ :status="status"
+ :show-disabled-button="showDisabledButton"
+ />
+
+ <div class="rebase-state-find-class-convention media media-body space-children">
+ <template v-if="mr.rebaseInProgress || isMakingRequest">
+ <span class="bold">
+ Rebase in progress
+ </span>
+ </template>
+ <template v-if="!mr.rebaseInProgress && !mr.canPushToSourceBranch">
+ <span class="bold">
+ Fast-forward merge is not possible.
+ Rebase the source branch onto
+ <span class="label-branch">{{ mr.targetBranch }}</span>
+ to allow this merge request to be merged.
+ </span>
+ </template>
+ <template v-if="!mr.rebaseInProgress && mr.canPushToSourceBranch && !isMakingRequest">
+ <div
+ class="accept-merge-holder clearfix
+js-toggle-container accept-action media space-children"
+ >
+ <button
+ type="button"
+ class="btn btn-sm btn-reopen btn-success qa-mr-rebase-button"
+ :disabled="isMakingRequest"
+ @click="rebase"
+ >
+ <loading-icon v-if="isMakingRequest" />
+ Rebase
+ </button>
+ <span
+ v-if="!rebasingError"
+ class="bold"
+ >
+ Fast-forward merge is not possible.
+ Rebase the source branch onto the target branch or merge target
+ branch into source branch to allow this merge request to be merged.
+ </span>
+ <span
+ v-else
+ class="bold danger">
+ {{ rebasingError }}
+ </span>
+ </div>
+ </template>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_sha_mismatch.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_sha_mismatch.js
index 89f38e5bd2a..142ddf477f1 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_sha_mismatch.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_sha_mismatch.js
@@ -1,4 +1,4 @@
-import statusIcon from '../mr_widget_status_icon';
+import statusIcon from '../mr_widget_status_icon.vue';
export default {
name: 'MRWidgetSHAMismatch',
@@ -7,7 +7,7 @@ export default {
},
template: `
<div class="mr-widget-body media">
- <status-icon status="failed" showDisabledButton />
+ <status-icon status="warning" :show-disabled-button="true" />
<div class="media-body space-children">
<span class="bold">
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/mr_widget_unresolved_discussions.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_unresolved_discussions.js
index d762ca6e640..67b271c69ca 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_unresolved_discussions.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_unresolved_discussions.js
@@ -1,4 +1,4 @@
-import statusIcon from '../mr_widget_status_icon';
+import statusIcon from '../mr_widget_status_icon.vue';
export default {
name: 'MRWidgetUnresolvedDiscussions',
@@ -10,7 +10,7 @@ export default {
},
template: `
<div class="mr-widget-body media">
- <status-icon status="failed" showDisabledButton />
+ <status-icon status="warning" :show-disabled-button="true" />
<div class="media-body space-children">
<span class="bold">
There are unresolved discussions. Please resolve these discussions
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_wip.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_wip.js
index b11a06899cf..bbca641f65e 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_wip.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_wip.js
@@ -1,5 +1,4 @@
-/* global Flash */
-import statusIcon from '../mr_widget_status_icon';
+import statusIcon from '../mr_widget_status_icon.vue';
import tooltip from '../../../vue_shared/directives/tooltip';
import eventHub from '../../event_hub';
@@ -24,21 +23,21 @@ export default {
removeWIP() {
this.isMakingRequest = true;
this.service.removeWIP()
- .then(res => res.json())
- .then((res) => {
- eventHub.$emit('UpdateWidgetData', res);
- new Flash('The merge request can now be merged.', 'notice'); // eslint-disable-line
+ .then(res => res.data)
+ .then((data) => {
+ eventHub.$emit('UpdateWidgetData', data);
+ new window.Flash('The merge request can now be merged.', 'notice'); // eslint-disable-line
$('.merge-request .detail-page-description .title').text(this.mr.title);
})
.catch(() => {
this.isMakingRequest = false;
- new Flash('Something went wrong. Please try again.'); // eslint-disable-line
+ new window.Flash('Something went wrong. Please try again.'); // eslint-disable-line
});
},
},
template: `
<div class="mr-widget-body media">
- <status-icon status="failed" :showDisabledButton="Boolean(mr.removeWIPPath)" />
+ <status-icon status="warning" :show-disabled-button="Boolean(mr.removeWIPPath)" />
<div class="media-body space-children">
<span class="bold">
This is a Work in Progress