Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-10-20 11:43:02 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-10-20 11:43:02 +0300
commitd9ab72d6080f594d0b3cae15f14b3ef2c6c638cb (patch)
tree2341ef426af70ad1e289c38036737e04b0aa5007 /app/assets/javascripts/vue_merge_request_widget
parentd6e514dd13db8947884cd58fe2a9c2a063400a9b (diff)
Add latest changes from gitlab-org/gitlab@14-4-stable-eev14.4.0-rc42
Diffstat (limited to 'app/assets/javascripts/vue_merge_request_widget')
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals_summary.vue10
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/extensions/actions.vue70
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue137
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/extensions/container.js53
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/extensions/index.js6
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/extensions/status_icon.vue61
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue14
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_how_to_merge_modal.vue22
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue5
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/commits_header.vue43
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue37
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/work_in_progress.vue6
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/constants.js97
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/extensions/issues.js29
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mixins/ready_to_merge.js2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue32
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js52
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js10
18 files changed, 547 insertions, 139 deletions
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals_summary.vue b/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals_summary.vue
index ea73ab416de..0c4a5ee35d9 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals_summary.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals_summary.vue
@@ -35,13 +35,17 @@ export default {
}
if (!this.rulesLeft.length) {
- return n__('Requires approval.', 'Requires %d more approvals.', this.approvalsLeft);
+ return n__(
+ 'Requires %d approval from eligible users.',
+ 'Requires %d approvals from eligible users.',
+ this.approvalsLeft,
+ );
}
return sprintf(
n__(
- 'Requires approval from %{names}.',
- 'Requires %{count} more approvals from %{names}.',
+ 'Requires %{count} approval from %{names}.',
+ 'Requires %{count} approvals from %{names}.',
this.approvalsLeft,
),
{
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/extensions/actions.vue b/app/assets/javascripts/vue_merge_request_widget/components/extensions/actions.vue
new file mode 100644
index 00000000000..023367a794e
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/extensions/actions.vue
@@ -0,0 +1,70 @@
+<script>
+import { GlButton, GlDropdown, GlDropdownItem } from '@gitlab/ui';
+import { sprintf, __ } from '~/locale';
+
+export default {
+ components: {
+ GlButton,
+ GlDropdown,
+ GlDropdownItem,
+ },
+ props: {
+ widget: {
+ type: String,
+ required: true,
+ },
+ tertiaryButtons: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ },
+ computed: {
+ dropdownLabel() {
+ return sprintf(__('%{widget} options'), { widget: this.widget });
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <gl-dropdown
+ v-if="tertiaryButtons"
+ :text="dropdownLabel"
+ icon="ellipsis_v"
+ no-caret
+ category="tertiary"
+ right
+ lazy
+ text-sr-only
+ size="small"
+ toggle-class="gl-p-2!"
+ class="gl-display-block gl-md-display-none!"
+ >
+ <gl-dropdown-item
+ v-for="(btn, index) in tertiaryButtons"
+ :key="index"
+ :href="btn.href"
+ :target="btn.target"
+ >
+ {{ btn.text }}
+ </gl-dropdown-item>
+ </gl-dropdown>
+ <template v-if="tertiaryButtons.length">
+ <gl-button
+ v-for="(btn, index) in tertiaryButtons"
+ :key="index"
+ :href="btn.href"
+ :target="btn.target"
+ :class="{ 'gl-mr-3': index > 1 }"
+ category="tertiary"
+ variant="confirm"
+ size="small"
+ class="gl-display-none gl-md-display-block"
+ >
+ {{ btn.text }}
+ </gl-button>
+ </template>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue b/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue
index 0ac98f6c982..298f7c7ad8c 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue
@@ -1,7 +1,18 @@
<script>
-import { GlButton, GlLoadingIcon, GlIcon, GlLink, GlBadge, GlSafeHtmlDirective } from '@gitlab/ui';
+import {
+ GlButton,
+ GlLoadingIcon,
+ GlLink,
+ GlBadge,
+ GlSafeHtmlDirective,
+ GlTooltipDirective,
+ GlIntersectionObserver,
+} from '@gitlab/ui';
+import { sprintf, s__, __ } from '~/locale';
import SmartVirtualList from '~/vue_shared/components/smart_virtual_list.vue';
-import StatusIcon from '../mr_widget_status_icon.vue';
+import { EXTENSION_ICON_CLASS } from '../../constants';
+import StatusIcon from './status_icon.vue';
+import Actions from './actions.vue';
export const LOADING_STATES = {
collapsedLoading: 'collapsedLoading',
@@ -13,14 +24,16 @@ export default {
components: {
GlButton,
GlLoadingIcon,
- GlIcon,
GlLink,
GlBadge,
+ GlIntersectionObserver,
SmartVirtualList,
StatusIcon,
+ Actions,
},
directives: {
SafeHtml: GlSafeHtmlDirective,
+ GlTooltip: GlTooltipDirective,
},
data() {
return {
@@ -28,9 +41,16 @@ export default {
collapsedData: null,
fullData: null,
isCollapsed: true,
+ showFade: false,
};
},
computed: {
+ widgetLabel() {
+ return this.$options.i18n?.label || this.$options.name;
+ },
+ widgetLoadingText() {
+ return this.$options.i18n?.loading || __('Loading...');
+ },
isLoadingSummary() {
return this.loadingState === LOADING_STATES.collapsedLoading;
},
@@ -44,17 +64,22 @@ export default {
return true;
},
+ collapseButtonLabel() {
+ return sprintf(
+ this.isCollapsed
+ ? s__('mrWidget|Show %{widget} details')
+ : s__('mrWidget|Hide %{widget} details'),
+ { widget: this.widgetLabel },
+ );
+ },
statusIconName() {
- if (this.isLoadingSummary) {
- return 'loading';
- }
-
- if (this.loadingState === LOADING_STATES.collapsedError) {
- return 'warning';
- }
+ if (this.isLoadingSummary) return null;
return this.statusIcon(this.collapsedData);
},
+ tertiaryActionsButtons() {
+ return this.tertiaryButtons ? this.tertiaryButtons() : undefined;
+ },
},
watch: {
isCollapsed(newVal) {
@@ -95,32 +120,59 @@ export default {
throw e;
});
},
+ appear(index) {
+ if (index === this.fullData.length - 1) {
+ this.showFade = false;
+ }
+ },
+ disappear(index) {
+ if (index === this.fullData.length - 1) {
+ this.showFade = true;
+ }
+ },
},
+ EXTENSION_ICON_CLASS,
};
</script>
<template>
- <section class="media-section mr-widget-border-top">
+ <section class="media-section" data-testid="widget-extension">
<div class="media gl-p-5">
- <status-icon :status="statusIconName" class="align-self-center" />
- <div class="media-body d-flex flex-align-self-center align-items-center">
- <div class="code-text">
- <template v-if="isLoadingSummary">
- {{ __('Loading...') }}
- </template>
+ <status-icon
+ :name="$options.label || $options.name"
+ :is-loading="isLoadingSummary"
+ :icon-name="statusIconName"
+ />
+ <div class="media-body gl-display-flex gl-flex-direction-row!">
+ <div class="gl-flex-grow-1">
+ <template v-if="isLoadingSummary">{{ widgetLoadingText }}</template>
<div v-else v-safe-html="summary(collapsedData)"></div>
</div>
- <gl-button
- v-if="isCollapsible"
- size="small"
- class="float-right align-self-center"
- @click="toggleCollapsed"
- >
- {{ isCollapsed ? __('Expand') : __('Collapse') }}
- </gl-button>
+ <actions
+ :widget="$options.label || $options.name"
+ :tertiary-buttons="tertiaryActionsButtons"
+ />
+ <div class="gl-border-l-1 gl-border-l-solid gl-border-gray-100 gl-ml-3 gl-pl-3 gl-h-6">
+ <gl-button
+ v-if="isCollapsible"
+ v-gl-tooltip
+ :title="collapseButtonLabel"
+ :aria-expanded="`${!isCollapsed}`"
+ :aria-label="collapseButtonLabel"
+ :icon="isCollapsed ? 'chevron-lg-down' : 'chevron-lg-up'"
+ category="tertiary"
+ data-testid="toggle-button"
+ size="small"
+ @click="toggleCollapsed"
+ />
+ </div>
</div>
</div>
- <div v-if="!isCollapsed" class="mr-widget-grouped-section">
+ <div
+ v-if="!isCollapsed"
+ class="mr-widget-grouped-section gl-relative"
+ data-testid="widget-extension-collapsed-section"
+ >
<div v-if="isLoadingExpanded" class="report-block-container">
<gl-loading-icon size="sm" inline /> {{ __('Loading...') }}
</div>
@@ -131,27 +183,38 @@ export default {
:size="32"
wtag="ul"
wclass="report-block-list"
- class="report-block-container"
+ class="report-block-container gl-px-5 gl-py-0"
>
- <li v-for="data in fullData" :key="data.id" class="d-flex align-items-center">
- <div v-if="data.icon" :class="data.icon.class" class="d-flex">
- <gl-icon :name="data.icon.name" :size="24" />
- </div>
- <div
- class="gl-mt-2 gl-mb-2 align-content-around align-items-start flex-wrap align-self-center d-flex"
+ <li
+ v-for="(data, index) in fullData"
+ :key="data.id"
+ :class="{
+ 'gl-border-b-solid gl-border-b-1 gl-border-gray-100': index !== fullData.length - 1,
+ }"
+ class="gl-display-flex gl-align-items-center gl-py-3 gl-pl-7"
+ data-testid="extension-list-item"
+ >
+ <status-icon v-if="data.icon" :icon-name="data.icon.name" :size="12" />
+ <gl-intersection-observer
+ :options="{ rootMargin: '100px', thresholds: 0.1 }"
+ class="gl-flex-wrap gl-align-self-center gl-display-flex"
+ @appear="appear(index)"
+ @disappear="disappear(index)"
>
- <div class="gl-mr-4">
- {{ data.text }}
- </div>
+ <div v-safe-html="data.text" class="gl-mr-4"></div>
<div v-if="data.link">
<gl-link :href="data.link.href">{{ data.link.text }}</gl-link>
</div>
<gl-badge v-if="data.badge" :variant="data.badge.variant || 'info'">
{{ data.badge.text }}
</gl-badge>
- </div>
+ </gl-intersection-observer>
</li>
</smart-virtual-list>
+ <div
+ :class="{ show: showFade }"
+ class="fade mr-extenson-scrim gl-absolute gl-left-0 gl-bottom-0 gl-w-full gl-h-7"
+ ></div>
</div>
</section>
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/extensions/container.js b/app/assets/javascripts/vue_merge_request_widget/components/extensions/container.js
index 529160de6a7..b9dfd3bd41e 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/extensions/container.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/extensions/container.js
@@ -1,4 +1,5 @@
-import { extensions } from './index';
+import { __ } from '~/locale';
+import { registeredExtensions } from './index';
export default {
props: {
@@ -8,20 +9,46 @@ export default {
},
},
render(h) {
+ const { extensions } = registeredExtensions;
+
+ if (extensions.length === 0) return null;
+
return h(
'div',
- {},
- extensions.map((extension) =>
- h(extension, {
- props: extensions[0].props.reduce(
- (acc, key) => ({
- ...acc,
- [key]: this.mr[key],
- }),
- {},
- ),
- }),
- ),
+ {
+ attrs: {
+ role: 'region',
+ 'aria-label': __('Merge request reports'),
+ },
+ },
+ [
+ h(
+ 'ul',
+ {
+ class: 'gl-p-0 gl-m-0 gl-list-style-none',
+ },
+ [
+ ...extensions.map((extension, index) =>
+ h('li', { attrs: { class: index > 0 && 'mr-widget-border-top' } }, [
+ h(
+ { ...extension },
+ {
+ props: {
+ ...extension.props.reduce(
+ (acc, key) => ({
+ ...acc,
+ [key]: this.mr[key],
+ }),
+ {},
+ ),
+ },
+ },
+ ),
+ ]),
+ ),
+ ],
+ ),
+ ],
);
},
};
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/extensions/index.js b/app/assets/javascripts/vue_merge_request_widget/components/extensions/index.js
index 9796bb44939..4ca0b660696 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/extensions/index.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/extensions/index.js
@@ -1,15 +1,17 @@
+import Vue from 'vue';
import ExtensionBase from './base.vue';
// Holds all the currently registered extensions
-export const extensions = [];
+export const registeredExtensions = Vue.observable({ extensions: [] });
export const registerExtension = (extension) => {
// Pushes into the extenions array a dynamically created Vue component
// that gets exteneded from `base.vue`
- extensions.push({
+ registeredExtensions.extensions.push({
extends: ExtensionBase,
name: extension.name,
props: extension.props,
+ i18n: extension.i18n,
computed: {
...Object.keys(extension.computed).reduce(
(acc, computedKey) => ({
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/extensions/status_icon.vue b/app/assets/javascripts/vue_merge_request_widget/components/extensions/status_icon.vue
new file mode 100644
index 00000000000..01d8de132e7
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/extensions/status_icon.vue
@@ -0,0 +1,61 @@
+<script>
+import { GlLoadingIcon, GlIcon } from '@gitlab/ui';
+import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
+import { EXTENSION_ICON_CLASS, EXTENSION_ICON_NAMES } from '../../constants';
+
+export default {
+ components: {
+ GlLoadingIcon,
+ GlIcon,
+ },
+ props: {
+ name: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ isLoading: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ iconName: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ size: {
+ type: Number,
+ required: false,
+ default: 16,
+ },
+ },
+ computed: {
+ iconAriaLabel() {
+ return `${capitalizeFirstCharacter(this.iconName)} ${this.name}`;
+ },
+ },
+ EXTENSION_ICON_NAMES,
+ EXTENSION_ICON_CLASS,
+};
+</script>
+
+<template>
+ <div
+ :class="[
+ $options.EXTENSION_ICON_CLASS[iconName],
+ { 'mr-widget-extension-icon': !isLoading && size === 16 },
+ { 'gl-p-2': isLoading || size === 16 },
+ ]"
+ class="gl-rounded-full gl-mr-3 gl-relative gl-p-2"
+ >
+ <gl-loading-icon v-if="isLoading" size="md" inline class="gl-display-block" />
+ <gl-icon
+ v-else
+ :name="$options.EXTENSION_ICON_NAMES[iconName]"
+ :size="size"
+ :aria-label="iconAriaLabel"
+ class="gl-display-block"
+ />
+ </div>
+</template>
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 966262944ad..5c67b9c7ab5 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
@@ -10,7 +10,7 @@ import {
GlSafeHtmlDirective as SafeHtml,
GlSprintf,
} from '@gitlab/ui';
-import { mergeUrlParams, webIDEUrl } from '~/lib/utils/url_utility';
+import { constructWebIDEPath } from '~/lib/utils/url_utility';
import { s__ } from '~/locale';
import clipboardButton from '~/vue_shared/components/clipboard_button.vue';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
@@ -58,15 +58,7 @@ export default {
});
},
webIdePath() {
- return mergeUrlParams(
- {
- target_project:
- this.mr.sourceProjectFullPath !== this.mr.targetProjectFullPath
- ? this.mr.targetProjectFullPath
- : '',
- },
- webIDEUrl(`/${this.mr.sourceProjectFullPath}/merge_requests/${this.mr.iid}`),
- );
+ return constructWebIDEPath(this.mr);
},
isFork() {
return this.mr.sourceProjectFullPath !== this.mr.targetProjectFullPath;
@@ -79,7 +71,7 @@ export default {
};
</script>
<template>
- <div class="d-flex mr-source-target gl-mb-3">
+ <div class="gl-display-flex mr-source-target">
<mr-widget-icon name="git-merge" />
<div class="git-merge-container d-flex">
<div class="normal">
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 7532eabee8a..68cff1368af 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
@@ -1,6 +1,7 @@
<script>
/* eslint-disable @gitlab/require-i18n-strings */
import { GlModal, GlLink, GlSprintf } from '@gitlab/ui';
+import { escapeShellString } from '~/lib/utils/text_utility';
import { __ } from '~/locale';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
@@ -75,20 +76,31 @@ export default {
},
computed: {
mergeInfo1() {
+ const escapedOriginBranch = escapeShellString(`origin/${this.sourceBranch}`);
+
return this.isFork
- ? `git fetch "${this.sourceProjectDefaultUrl}" ${this.sourceBranch}\ngit checkout -b "${this.sourceProjectPath}-${this.sourceBranch}" FETCH_HEAD`
- : `git fetch origin\ngit checkout -b "${this.sourceBranch}" "origin/${this.sourceBranch}"`;
+ ? `git fetch "${this.sourceProjectDefaultUrl}" ${this.escapedSourceBranch}\ngit checkout -b ${this.escapedForkBranch} FETCH_HEAD`
+ : `git fetch origin\ngit checkout -b ${this.escapedSourceBranch} ${escapedOriginBranch}`;
},
mergeInfo2() {
return this.isFork
- ? `git fetch origin\ngit checkout "${this.targetBranch}"\ngit merge --no-ff "${this.sourceProjectPath}-${this.sourceBranch}"`
- : `git fetch origin\ngit checkout "${this.targetBranch}"\ngit merge --no-ff "${this.sourceBranch}"`;
+ ? `git fetch origin\ngit checkout ${this.escapedTargetBranch}\ngit merge --no-ff ${this.escapedForkBranch}`
+ : `git fetch origin\ngit checkout ${this.escapedTargetBranch}\ngit merge --no-ff ${this.escapedSourceBranch}`;
},
mergeInfo3() {
return this.canMerge
- ? `git push origin "${this.targetBranch}"`
+ ? `git push origin ${this.escapedTargetBranch}`
: __('Note that pushing to GitLab requires write access to this repository.');
},
+ escapedForkBranch() {
+ return escapeShellString(`${this.sourceProjectPath}-${this.sourceBranch}`);
+ },
+ escapedTargetBranch() {
+ return escapeShellString(this.targetBranch);
+ },
+ escapedSourceBranch() {
+ return escapeShellString(this.sourceBranch);
+ },
},
};
</script>
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 a8272002f16..a05e8747a43 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
@@ -88,6 +88,9 @@ export default {
return this.mr.preferredAutoMergeStrategy;
},
+ ciStatus() {
+ return this.isPostMerge ? this.mr?.mergePipeline?.details?.status?.text : this.mr.ciStatus;
+ },
},
};
</script>
@@ -97,7 +100,7 @@ export default {
:pipeline="pipeline"
:pipeline-coverage-delta="mr.pipelineCoverageDelta"
:builds-with-coverage="mr.buildsWithCoverage"
- :ci-status="mr.ciStatus"
+ :ci-status="ciStatus"
:has-ci="mr.hasCI"
:pipeline-must-succeed="mr.onlyAllowMergeIfPipelineSucceeds"
:source-branch="branch"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/commits_header.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/commits_header.vue
index a55dba92e16..3ca193514f1 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/commits_header.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/commits_header.vue
@@ -1,12 +1,15 @@
<script>
-/* eslint-disable @gitlab/require-string-literal-i18n-helpers */
-import { GlButton } from '@gitlab/ui';
+import { GlButton, GlSprintf } from '@gitlab/ui';
import { escape } from 'lodash';
-import { __, n__, sprintf, s__ } from '~/locale';
+import { __, n__, s__ } from '~/locale';
+
+const mergeCommitCount = s__('mrWidgetCommitsAdded|1 merge commit');
export default {
+ mergeCommitCount,
components: {
GlButton,
+ GlSprintf,
},
props: {
isSquashEnabled: {
@@ -37,7 +40,7 @@ export default {
return this.expanded ? 'chevron-down' : 'chevron-right';
},
commitsCountMessage() {
- return n__(__('%d commit'), __('%d commits'), this.isSquashEnabled ? 1 : this.commitsCount);
+ return n__('%d commit', '%d commits', this.isSquashEnabled ? 1 : this.commitsCount);
},
modifyLinkMessage() {
if (this.isFastForwardEnabled) return __('Modify commit message');
@@ -47,22 +50,15 @@ export default {
ariaLabel() {
return this.expanded ? __('Collapse') : __('Expand');
},
+ targetBranchEscaped() {
+ return escape(this.targetBranch);
+ },
message() {
- const message = this.isFastForwardEnabled
+ return this.isFastForwardEnabled
? s__('mrWidgetCommitsAdded|%{commitCount} will be added to %{targetBranch}.')
: s__(
'mrWidgetCommitsAdded|%{commitCount} and %{mergeCommitCount} will be added to %{targetBranch}.',
);
-
- return sprintf(
- message,
- {
- commitCount: `<strong class="commits-count-message">${this.commitsCountMessage}</strong>`,
- mergeCommitCount: `<strong>${s__('mrWidgetCommitsAdded|1 merge commit')}</strong>`,
- targetBranch: `<span class="label-branch">${escape(this.targetBranch)}</span>`,
- },
- false,
- );
},
},
methods: {
@@ -89,10 +85,19 @@ export default {
/>
<span v-if="expanded">{{ __('Collapse') }}</span>
<span v-else>
- <span
- class="vertical-align-middle"
- v-html="message /* eslint-disable-line vue/no-v-html */"
- ></span>
+ <span class="vertical-align-middle">
+ <gl-sprintf :message="message">
+ <template #commitCount>
+ <strong class="commits-count-message">{{ commitsCountMessage }}</strong>
+ </template>
+ <template #mergeCommitCount>
+ <strong>{{ $options.mergeCommitCount }}</strong>
+ </template>
+ <template #targetBranch>
+ <span class="label-branch">{{ targetBranchEscaped }}</span>
+ </template>
+ </gl-sprintf>
+ </span>
<gl-button variant="link" class="modify-message-button">
{{ modifyLinkMessage }}
</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 7df65e995a5..7d4bd4cf1bf 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
@@ -29,6 +29,7 @@ import {
WARNING,
MT_MERGE_STRATEGY,
PIPELINE_FAILED_STATE,
+ STATE_MACHINE,
} from '../../constants';
import eventHub from '../../event_hub';
import mergeRequestQueryVariablesMixin from '../../mixins/merge_request_query_variables';
@@ -47,6 +48,9 @@ const MERGE_FAILED_STATUS = 'failed';
const MERGE_SUCCESS_STATUS = 'success';
const MERGE_HOOK_VALIDATION_ERROR_STATUS = 'hook_validation_error';
+const { transitions } = STATE_MACHINE;
+const { MERGE, MERGED, MERGE_FAILURE, AUTO_MERGE } = transitions;
+
export default {
name: 'ReadyToMerge',
apollo: {
@@ -99,8 +103,8 @@ export default {
GlDropdownItem,
GlFormCheckbox,
GlSkeletonLoader,
- MergeTrainHelperText: () =>
- import('ee_component/vue_merge_request_widget/components/merge_train_helper_text.vue'),
+ MergeTrainHelperIcon: () =>
+ import('ee_component/vue_merge_request_widget/components/merge_train_helper_icon.vue'),
MergeImmediatelyConfirmationDialog: () =>
import(
'ee_component/vue_merge_request_widget/components/merge_immediately_confirmation_dialog.vue'
@@ -234,7 +238,7 @@ export default {
return CONFIRM;
},
iconClass() {
- if (this.shouldRenderMergeTrainHelperText && !this.mr.preventMerge) {
+ if (this.shouldRenderMergeTrainHelperIcon && !this.mr.preventMerge) {
return PIPELINE_RUNNING_STATE;
}
@@ -361,6 +365,11 @@ export default {
}
this.isMakingRequest = true;
+
+ if (!useAutoMerge) {
+ this.mr.transitionStateMachine({ transition: MERGE });
+ }
+
this.service
.merge(options)
.then((res) => res.data)
@@ -371,10 +380,12 @@ export default {
if (AUTO_MERGE_STRATEGIES.includes(data.status)) {
eventHub.$emit('MRWidgetUpdateRequested');
+ this.mr.transitionStateMachine({ transition: AUTO_MERGE });
} else if (data.status === MERGE_SUCCESS_STATUS) {
this.initiateMergePolling();
} else if (hasError) {
eventHub.$emit('FailedToMerge', data.merge_error);
+ this.mr.transitionStateMachine({ transition: MERGE_FAILURE });
}
if (this.glFeatures.mergeRequestWidgetGraphql) {
@@ -383,6 +394,7 @@ export default {
})
.catch(() => {
this.isMakingRequest = false;
+ this.mr.transitionStateMachine({ transition: MERGE_FAILURE });
createFlash({
message: __('Something went wrong. Please try again.'),
});
@@ -417,6 +429,7 @@ export default {
eventHub.$emit('FetchActionsContent');
MergeRequest.hideCloseButton();
MergeRequest.decreaseCounter();
+ this.mr.transitionStateMachine({ transition: MERGED });
stopPolling();
refreshUserMergeRequestCounts();
@@ -428,6 +441,7 @@ export default {
}
} else if (data.merge_error) {
eventHub.$emit('FailedToMerge', data.merge_error);
+ this.mr.transitionStateMachine({ transition: MERGE_FAILURE });
stopPolling();
} else {
// MR is not merged yet, continue polling until the state becomes 'merged'
@@ -438,6 +452,7 @@ export default {
createFlash({
message: __('Something went wrong while merging this merge request. Please try again.'),
});
+ this.mr.transitionStateMachine({ transition: MERGE_FAILURE });
stopPolling();
});
},
@@ -489,7 +504,7 @@ export default {
</div>
</div>
<template v-else>
- <div class="mr-widget-body media" :class="{ 'gl-pb-3': shouldRenderMergeTrainHelperText }">
+ <div class="mr-widget-body media">
<status-icon :status="iconClass" />
<div class="media-body">
<div class="mr-widget-body-controls gl-display-flex gl-align-items-center">
@@ -560,6 +575,13 @@ export default {
:is-disabled="isSquashReadOnly"
class="gl-mx-3"
/>
+
+ <merge-train-helper-icon
+ v-if="shouldRenderMergeTrainHelperIcon"
+ :merge-train-when-pipeline-succeeds-docs-path="
+ mr.mergeTrainWhenPipelineSucceedsDocsPath
+ "
+ />
</div>
<template v-else>
<div class="bold js-resolve-mr-widget-items-message gl-ml-3">
@@ -590,13 +612,6 @@ export default {
</div>
</div>
</div>
- <merge-train-helper-text
- v-if="shouldRenderMergeTrainHelperText"
- :pipeline-id="pipelineId"
- :pipeline-link="pipeline.path"
- :merge-train-length="stateData.mergeTrainsCount"
- :merge-train-when-pipeline-succeeds-docs-path="mr.mergeTrainWhenPipelineSucceedsDocsPath"
- />
<template v-if="shouldShowMergeControls">
<div
v-if="!shouldShowMergeEdit"
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 393c599c7e8..790870ee4c6 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
@@ -3,6 +3,7 @@ import { GlButton } from '@gitlab/ui';
import { produce } from 'immer';
import $ from 'jquery';
import createFlash from '~/flash';
+import toast from '~/vue_shared/plugins/global_toast';
import { __ } from '~/locale';
import MergeRequest from '~/merge_request';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
@@ -123,10 +124,7 @@ export default {
},
},
}) => {
- createFlash({
- message: __('Marked as ready. Merging is now allowed.'),
- type: 'notice',
- });
+ toast(__('Marked as ready. Merging is now allowed.'));
$('.merge-request .detail-page-description .title').text(title);
},
)
diff --git a/app/assets/javascripts/vue_merge_request_widget/constants.js b/app/assets/javascripts/vue_merge_request_widget/constants.js
index f5710f46b7e..b88e83ccb0f 100644
--- a/app/assets/javascripts/vue_merge_request_widget/constants.js
+++ b/app/assets/javascripts/vue_merge_request_widget/constants.js
@@ -1,4 +1,5 @@
import { s__ } from '~/locale';
+import { stateToComponentMap as classStateMap, stateKey } from './stores/state_maps';
export const SUCCESS = 'success';
export const WARNING = 'warning';
@@ -52,3 +53,99 @@ export const MERGE_ACTIVE_STATUS_PHRASES = [
emoji: 'heart_eyes',
},
];
+
+const STATE_MACHINE = {
+ states: {
+ IDLE: 'IDLE',
+ MERGING: 'MERGING',
+ AUTO_MERGE: 'AUTO_MERGE',
+ },
+ transitions: {
+ MERGE: 'start-merge',
+ AUTO_MERGE: 'start-auto-merge',
+ MERGE_FAILURE: 'merge-failed',
+ MERGED: 'merge-done',
+ },
+};
+const { states, transitions } = STATE_MACHINE;
+
+STATE_MACHINE.definition = {
+ initial: states.IDLE,
+ states: {
+ [states.IDLE]: {
+ on: {
+ [transitions.MERGE]: states.MERGING,
+ [transitions.AUTO_MERGE]: states.AUTO_MERGE,
+ },
+ },
+ [states.MERGING]: {
+ on: {
+ [transitions.MERGED]: states.IDLE,
+ [transitions.MERGE_FAILURE]: states.IDLE,
+ },
+ },
+ [states.AUTO_MERGE]: {
+ on: {
+ [transitions.MERGED]: states.IDLE,
+ [transitions.MERGE_FAILURE]: states.IDLE,
+ },
+ },
+ },
+};
+
+export const stateToTransitionMap = {
+ [stateKey.merging]: transitions.MERGE,
+ [stateKey.merged]: transitions.MERGED,
+ [stateKey.autoMergeEnabled]: transitions.AUTO_MERGE,
+};
+export const stateToComponentMap = {
+ [states.MERGING]: classStateMap[stateKey.merging],
+ [states.AUTO_MERGE]: classStateMap[stateKey.autoMergeEnabled],
+};
+
+export const EXTENSION_ICONS = {
+ failed: 'failed',
+ warning: 'warning',
+ success: 'success',
+ neutral: 'neutral',
+ error: 'error',
+ notice: 'notice',
+ severityCritical: 'severityCritical',
+ severityHigh: 'severityHigh',
+ severityMedium: 'severityMedium',
+ severityLow: 'severityLow',
+ severityInfo: 'severityInfo',
+ severityUnknown: 'severityUnknown',
+};
+
+export const EXTENSION_ICON_NAMES = {
+ failed: 'status-failed',
+ warning: 'status-alert',
+ success: 'status-success',
+ neutral: 'status-neutral',
+ error: 'status-alert',
+ notice: 'status-alert',
+ severityCritical: 'severity-critical',
+ severityHigh: 'severity-high',
+ severityMedium: 'severity-medium',
+ severityLow: 'severity-low',
+ severityInfo: 'severity-info',
+ severityUnknown: 'severity-unknown',
+};
+
+export const EXTENSION_ICON_CLASS = {
+ failed: 'gl-text-red-500',
+ warning: 'gl-text-orange-500',
+ success: 'gl-text-green-500',
+ neutral: 'gl-text-gray-400',
+ error: 'gl-text-red-500',
+ notice: 'gl-text-gray-500',
+ severityCritical: 'gl-text-red-800',
+ severityHigh: 'gl-text-red-600',
+ severityMedium: 'gl-text-orange-400',
+ severityLow: 'gl-text-orange-300',
+ severityInfo: 'gl-text-blue-400',
+ severityUnknown: 'gl-text-gray-400',
+};
+
+export { STATE_MACHINE };
diff --git a/app/assets/javascripts/vue_merge_request_widget/extensions/issues.js b/app/assets/javascripts/vue_merge_request_widget/extensions/issues.js
index 6c6f5e7fc73..349e9d29355 100644
--- a/app/assets/javascripts/vue_merge_request_widget/extensions/issues.js
+++ b/app/assets/javascripts/vue_merge_request_widget/extensions/issues.js
@@ -1,4 +1,5 @@
/* eslint-disable */
+import { EXTENSION_ICONS } from '../constants';
import issuesCollapsedQuery from './issues_collapsed.query.graphql';
import issuesQuery from './issues.query.graphql';
@@ -6,20 +7,29 @@ export default {
// Give the extension a name
// Make it easier to track in Vue dev tools
name: 'WidgetIssues',
+ i18n: {
+ label: 'Issues',
+ loading: 'Loading issues...',
+ },
// Add an array of props
// These then get mapped to values stored in the MR Widget store
- props: ['targetProjectFullPath'],
+ props: ['targetProjectFullPath', 'conflictsDocsPath'],
// Add any extra computed props in here
computed: {
// Small summary text to be displayed in the collapsed state
// Receives the collapsed data as an argument
summary(count) {
- return `<strong>${count}</strong> open issue`;
+ return 'Summary text<br/>Second line';
},
// Status icon to be used next to the summary text
// Receives the collapsed data as an argument
statusIcon(count) {
- return count > 0 ? 'warning' : 'success';
+ return EXTENSION_ICONS.warning;
+ },
+ // Tertiary action buttons that will take the user elsewhere
+ // in the GitLab app
+ tertiaryButtons() {
+ return [{ text: 'Full report', href: this.conflictsDocsPath, target: '_blank' }];
},
},
methods: {
@@ -44,16 +54,13 @@ export default {
// Icon to get rendered on the side of each row
icon: {
// Required: Name maps to an icon in GitLabs SVG
- name:
- issue.state === 'closed' ? 'status_failed_borderless' : 'status_success_borderless',
- // Optional: An extra class to be added to the icon for additional styling
- class: issue.state === 'closed' ? 'text-danger' : 'text-success',
+ name: issue.state === 'closed' ? EXTENSION_ICONS.error : EXTENSION_ICONS.success,
},
// Badges get rendered next to the text on each row
- badge: issue.state === 'closed' && {
- text: 'Closed', // Required: Text to be used inside of the badge
- // variant: 'info', // Optional: The variant of the badge, maps to GitLab UI variants
- },
+ // badge: issue.state === 'closed' && {
+ // text: 'Closed', // Required: Text to be used inside of the badge
+ // // variant: 'info', // Optional: The variant of the badge, maps to GitLab UI variants
+ // },
// Each row can have its own link that will take the user elsewhere
// link: {
// href: 'https://google.com', // Required: href for the link
diff --git a/app/assets/javascripts/vue_merge_request_widget/mixins/ready_to_merge.js b/app/assets/javascripts/vue_merge_request_widget/mixins/ready_to_merge.js
index 9d8e5d12d58..cf6472f2c8c 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mixins/ready_to_merge.js
+++ b/app/assets/javascripts/vue_merge_request_widget/mixins/ready_to_merge.js
@@ -32,7 +32,7 @@ export default {
isMergeImmediatelyDangerous() {
return false;
},
- shouldRenderMergeTrainHelperText() {
+ shouldRenderMergeTrainHelperIcon() {
return false;
},
pipelineId() {
diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
index 78aa3941bfe..3ac1e881658 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
@@ -4,7 +4,7 @@ import { isEmpty } from 'lodash';
import MrWidgetApprovals from 'ee_else_ce/vue_merge_request_widget/components/approvals/approvals.vue';
import MRWidgetService from 'ee_else_ce/vue_merge_request_widget/services/mr_widget_service';
import MRWidgetStore from 'ee_else_ce/vue_merge_request_widget/stores/mr_widget_store';
-import stateMaps from 'ee_else_ce/vue_merge_request_widget/stores/state_maps';
+import { stateToComponentMap as classState } from 'ee_else_ce/vue_merge_request_widget/stores/state_maps';
import createFlash from '~/flash';
import { secondsToMilliseconds } from '~/lib/utils/datetime_utility';
import notify from '~/lib/utils/notify';
@@ -38,7 +38,8 @@ import ReadyToMergeState from './components/states/ready_to_merge.vue';
import ShaMismatch from './components/states/sha_mismatch.vue';
import UnresolvedDiscussionsState from './components/states/unresolved_discussions.vue';
import WorkInProgressState from './components/states/work_in_progress.vue';
-// import ExtensionsContainer from './components/extensions/container';
+import ExtensionsContainer from './components/extensions/container';
+import { STATE_MACHINE, stateToComponentMap } from './constants';
import eventHub from './event_hub';
import mergeRequestQueryVariablesMixin from './mixins/merge_request_query_variables';
import getStateQuery from './queries/get_state.query.graphql';
@@ -52,7 +53,7 @@ export default {
},
components: {
Loading,
- // ExtensionsContainer,
+ ExtensionsContainer,
'mr-widget-header': WidgetHeader,
'mr-widget-suggest-pipeline': WidgetSuggestPipeline,
MrWidgetPipelineContainer,
@@ -124,7 +125,9 @@ export default {
mr: store,
state: store && store.state,
service: store && this.createService(store),
+ machineState: store?.machineValue || STATE_MACHINE.definition.initial,
loading: true,
+ recomputeComponentName: 0,
};
},
computed: {
@@ -139,7 +142,7 @@ export default {
return this.mr.state !== 'nothingToMerge';
},
componentName() {
- return stateMaps.stateToComponentMap[this.mr.state];
+ return stateToComponentMap[this.machineState] || classState[this.mr.state];
},
hasPipelineMustSucceedConflict() {
return !this.mr.hasCI && this.mr.onlyAllowMergeIfPipelineSucceeds;
@@ -148,9 +151,9 @@ export default {
return this.mr.hasCI || this.hasPipelineMustSucceedConflict;
},
shouldSuggestPipelines() {
- return (
- !this.mr.hasCI && this.mr.mergeRequestAddCiConfigPath && !this.mr.isDismissedSuggestPipeline
- );
+ const { hasCI, mergeRequestAddCiConfigPath, isDismissedSuggestPipeline } = this.mr;
+
+ return !hasCI && mergeRequestAddCiConfigPath && !isDismissedSuggestPipeline;
},
shouldRenderCodeQuality() {
return this.mr?.codequalityReportsPath;
@@ -204,8 +207,19 @@ export default {
hasAlerts() {
return this.mr.mergeError || this.showMergePipelineForkWarning;
},
+ shouldShowExtension() {
+ return (
+ window.gon?.features?.refactorMrWidgetsExtensions ||
+ window.gon?.features?.refactorMrWidgetsExtensionsUser
+ );
+ },
},
watch: {
+ 'mr.machineValue': {
+ handler(newValue) {
+ this.machineState = newValue;
+ },
+ },
state(newVal, oldVal) {
if (newVal !== oldVal && this.shouldRenderMergedPipeline) {
// init polling
@@ -247,6 +261,8 @@ export default {
this.mr = new MRWidgetStore({ ...window.gl.mrWidgetData, ...data });
}
+ this.machineState = this.mr.machineValue;
+
if (!this.state) {
this.state = this.mr.state;
}
@@ -496,7 +512,7 @@ export default {
</template>
</mr-widget-alert-message>
</div>
- <!-- <extensions-container :mr="mr" /> -->
+ <extensions-container :mr="mr" />
<grouped-codequality-reports-app
v-if="shouldRenderCodeQuality"
:head-blob-path="mr.headBlobPath"
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
index 29e0c867f6b..6628225cd46 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
@@ -1,11 +1,21 @@
import getStateKey from 'ee_else_ce/vue_merge_request_widget/stores/get_state_key';
import { statusBoxState } from '~/issuable/components/status_box.vue';
import { formatDate, getTimeago } from '~/lib/utils/datetime_utility';
-import { MTWPS_MERGE_STRATEGY, MT_MERGE_STRATEGY, MWPS_MERGE_STRATEGY } from '../constants';
+import { machine } from '~/lib/utils/finite_state_machine';
+import {
+ MTWPS_MERGE_STRATEGY,
+ MT_MERGE_STRATEGY,
+ MWPS_MERGE_STRATEGY,
+ STATE_MACHINE,
+ stateToTransitionMap,
+} from '../constants';
import { stateKey } from './state_maps';
const { format } = getTimeago();
+const { states } = STATE_MACHINE;
+const { IDLE } = states;
+
export default class MergeRequestStore {
constructor(data) {
this.sha = data.diff_head_sha;
@@ -16,6 +26,9 @@ export default class MergeRequestStore {
this.apiUnapprovePath = data.api_unapprove_path;
this.hasApprovalsAvailable = data.has_approvals_available;
+ this.stateMachine = machine(STATE_MACHINE.definition);
+ this.machineValue = this.stateMachine.value;
+
this.setPaths(data);
this.setData(data);
@@ -215,10 +228,7 @@ export default class MergeRequestStore {
setState() {
if (this.mergeOngoing) {
this.state = 'merging';
- return;
- }
-
- if (this.isOpen) {
+ } else if (this.isOpen) {
this.state = getStateKey.call(this);
} else {
switch (this.mergeRequestState) {
@@ -232,6 +242,8 @@ export default class MergeRequestStore {
this.state = null;
}
}
+
+ this.translateStateToMachine();
}
setPaths(data) {
@@ -277,7 +289,7 @@ export default class MergeRequestStore {
// Security reports
this.sastComparisonPath = data.sast_comparison_path;
- this.secretScanningComparisonPath = data.secret_scanning_comparison_path;
+ this.secretDetectionComparisonPath = data.secret_detection_comparison_path;
}
get isNothingToMergeState() {
@@ -356,4 +368,32 @@ export default class MergeRequestStore {
(this.onlyAllowMergeIfPipelineSucceeds && this.isPipelineFailed)
);
}
+
+ // Because the state machine doesn't yet handle every state and transition,
+ // some use-cases will need to force a state that can't be reached by
+ // a known transition. This is undesirable long-term (as it subverts
+ // the intent of a state machine), but is necessary until the machine
+ // can handle all possible combinations. (unsafeForce)
+ transitionStateMachine({ transition, state, unsafeForce = false } = {}) {
+ if (unsafeForce && state) {
+ this.stateMachine.value = state;
+ } else {
+ this.stateMachine.send(transition);
+ }
+
+ this.machineValue = this.stateMachine.value;
+ }
+ translateStateToMachine() {
+ const transition = stateToTransitionMap[this.state];
+ let transitionOptions = {
+ state: IDLE,
+ unsafeForce: true,
+ };
+
+ if (transition) {
+ transitionOptions = { transition };
+ }
+
+ this.transitionStateMachine(transitionOptions);
+ }
}
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js b/app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js
index 04454882666..4cb23407a74 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js
@@ -1,4 +1,4 @@
-const stateToComponentMap = {
+export const stateToComponentMap = {
merged: 'mr-widget-merged',
closed: 'mr-widget-closed',
merging: 'mr-widget-merging',
@@ -21,7 +21,7 @@ const stateToComponentMap = {
mergeChecksFailed: 'mergeChecksFailed',
};
-const statesToShowHelpWidget = [
+export const statesToShowHelpWidget = [
'merging',
'conflicts',
'workInProgress',
@@ -50,11 +50,7 @@ export const stateKey = {
notAllowedToMerge: 'notAllowedToMerge',
readyToMerge: 'readyToMerge',
rebase: 'rebase',
+ merging: 'merging',
merged: 'merged',
mergeChecksFailed: 'mergeChecksFailed',
};
-
-export default {
- stateToComponentMap,
- statesToShowHelpWidget,
-};