Commit d77cb89d authored by Kushal Pandya's avatar Kushal Pandya

Merge branch 'ph/343782/mergeBlockedStyles' into 'master'

Fixed merge blocked states styling

See merge request gitlab-org/gitlab!77691
parents 5bc18d7e c49872e1
<script>
import { GlButton, GlLoadingIcon } from '@gitlab/ui';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import ciIcon from '../../vue_shared/components/ci_icon.vue';
export default {
......@@ -8,6 +9,7 @@ export default {
GlButton,
GlLoadingIcon,
},
mixins: [glFeatureFlagMixin()],
props: {
status: {
type: String,
......@@ -42,7 +44,7 @@ export default {
</div>
<gl-button
v-if="showDisabledButton"
v-if="!glFeatures.restructuredMrWidget && showDisabledButton"
category="primary"
variant="success"
data-testid="disabled-merge-button"
......
<script>
import { GlButton } from '@gitlab/ui';
import { s__ } from '~/locale';
import notesEventHub from '~/notes/event_hub';
import StatusIcon from '../mr_widget_status_icon.vue';
export default {
i18n: {
pipelineFailed: s__(
'mrWidget|The pipeline for this merge request did not complete. Push a new commit to fix the failure.',
),
approvalNeeded: s__('mrWidget|Merge blocked: this merge request must be approved.'),
unresolvedDiscussions: s__('mrWidget|Merge blocked: all threads must be resolved.'),
blockingMergeRequests: s__(
'mrWidget|Merge blocked: you can only merge once above items are resolved.',
),
},
components: {
StatusIcon,
GlButton,
},
props: {
mr: {
......@@ -24,22 +20,15 @@ export default {
},
computed: {
failedText() {
if (this.mr.isPipelineFailed) {
return this.$options.i18n.pipelineFailed;
} else if (this.mr.approvals && !this.mr.isApproved) {
if (this.mr.approvals && !this.mr.isApproved) {
return this.$options.i18n.approvalNeeded;
} else if (this.mr.hasMergeableDiscussionsState) {
return this.$options.i18n.unresolvedDiscussions;
} else if (this.mr.blockingMergeRequests?.total_count > 0) {
return this.$options.i18n.blockingMergeRequests;
}
return null;
},
},
methods: {
jumpToFirstUnresolvedDiscussion() {
notesEventHub.$emit('jumpToFirstUnresolvedDiscussion');
},
},
};
</script>
......@@ -48,28 +37,6 @@ export default {
<status-icon status="warning" />
<p class="media-body gl-m-0! gl-font-weight-bold gl-text-black-normal!">
{{ failedText }}
<template v-if="failedText == $options.i18n.unresolvedDiscussions">
<gl-button
class="gl-ml-3"
size="small"
variant="confirm"
data-testid="jumpToUnresolved"
@click="jumpToFirstUnresolvedDiscussion"
>
{{ s__('mrWidget|Jump to first unresolved thread') }}
</gl-button>
<gl-button
v-if="mr.createIssueToResolveDiscussionsPath"
:href="mr.createIssueToResolveDiscussionsPath"
class="gl-ml-3"
size="small"
variant="confirm"
category="secondary"
data-testid="resolveIssue"
>
{{ s__('mrWidget|Create issue to resolve all threads') }}
</gl-button>
</template>
</p>
</div>
</template>
<script>
import { GlButton } from '@gitlab/ui';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import statusIcon from '../mr_widget_status_icon.vue';
export default {
name: 'MRWidgetArchived',
components: {
GlButton,
statusIcon,
},
mixins: [glFeatureFlagMixin()],
};
</script>
<template>
<div class="mr-widget-body media">
<div class="space-children">
<status-icon status="warning" />
<gl-button category="secondary" variant="success" :disabled="true">
{{ s__('mrWidget|Merge') }}
</gl-button>
<status-icon status="warning" show-disabled-button />
</div>
<div class="media-body">
<span class="bold">
<span :class="{ 'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget }" class="bold">
{{ s__('mrWidget|Merge unavailable: merge requests are read-only on archived projects.') }}
</span>
</div>
......
......@@ -12,9 +12,11 @@ export default {
</script>
<template>
<div class="mr-widget-body media">
<status-icon :show-disabled-button="!glFeatures.restructuredMrWidget" status="loading" />
<status-icon :show-disabled-button="true" status="loading" />
<div class="media-body space-children">
<span class="bold"> {{ s__('mrWidget|Checking if merge request can be merged…') }} </span>
<span :class="{ 'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget }" class="bold">
{{ s__('mrWidget|Checking if merge request can be merged…') }}
</span>
</div>
</div>
</template>
......@@ -109,14 +109,18 @@ export default {
</gl-skeleton-loader>
</div>
<div v-else class="media-body space-children gl-display-flex gl-align-items-center">
<span v-if="shouldBeRebased" class="bold">
<span
v-if="shouldBeRebased"
:class="{ 'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget }"
class="bold"
>
{{
s__(`mrWidget|Merge blocked: fast-forward merge is not possible.
To merge this request, first rebase locally.`)
}}
</span>
<template v-else>
<span class="bold">
<span :class="{ 'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget }" class="bold">
{{ s__('mrWidget|Merge blocked: merge conflicts must be resolved.') }}
<span v-if="!canMerge">
{{
......@@ -129,6 +133,7 @@ export default {
<gl-button
v-if="showResolveButton"
:href="mr.conflictResolutionPath"
:size="glFeatures.restructuredMrWidget ? 'small' : 'medium'"
data-testid="resolve-conflicts-button"
>
{{ s__('mrWidget|Resolve conflicts') }}
......@@ -136,6 +141,7 @@ export default {
<gl-button
v-if="canMerge"
v-gl-modal-directive="'modal-merge-info'"
:size="glFeatures.restructuredMrWidget ? 'small' : 'medium'"
data-testid="merge-locally-button"
>
{{ s__('mrWidget|Merge locally') }}
......
......@@ -74,10 +74,21 @@ export default {
<status-icon :show-disabled-button="true" status="warning" />
<div class="media-body space-children">
<span class="bold js-branch-text">
<span
:class="{
'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget,
}"
class="bold js-branch-text"
>
<span class="capitalize" data-testid="missingBranchName"> {{ missingBranchName }} </span>
{{ s__('mrWidget|branch does not exist.') }} {{ missingBranchNameMessage }}
<gl-icon v-gl-tooltip :title="message" :aria-label="message" name="question-o" />
<gl-icon
v-gl-tooltip
:title="message"
:aria-label="message"
name="question-o"
class="gl-text-blue-600 gl-cursor-pointer"
/>
</span>
</div>
</div>
......
<script>
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import StatusIcon from '../mr_widget_status_icon.vue';
export default {
......@@ -6,13 +7,14 @@ export default {
components: {
StatusIcon,
},
mixins: [glFeatureFlagMixin()],
};
</script>
<template>
<div class="mr-widget-body media">
<status-icon :show-disabled-button="true" status="warning" />
<div class="media-body space-children">
<span class="bold">
<span :class="{ 'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget }" class="bold">
{{
s__(
`mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue.`,
......
......@@ -152,12 +152,14 @@ export default {
<div class="rebase-state-find-class-convention media media-body space-children">
<span
v-if="rebaseInProgress || isMakingRequest"
:class="{ 'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget }"
class="gl-font-weight-bold"
data-testid="rebase-message"
>{{ __('Rebase in progress') }}</span
>
<span
v-if="!rebaseInProgress && !canPushToSourceBranch"
:class="{ 'gl-text-body!': glFeatures.restructuredMrWidget }"
class="gl-font-weight-bold gl-ml-0!"
data-testid="rebase-message"
>{{ fastForwardMergeText }}</span
......@@ -167,6 +169,7 @@ export default {
class="accept-merge-holder clearfix js-toggle-container accept-action media space-children"
>
<gl-button
v-if="!glFeatures.restructuredMrWidget"
:loading="isMakingRequest"
variant="confirm"
data-qa-selector="mr_rebase_button"
......@@ -176,6 +179,7 @@ export default {
</gl-button>
<span
v-if="!rebasingError"
:class="{ 'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget }"
class="gl-font-weight-bold"
data-testid="rebase-message"
data-qa-selector="no_fast_forward_message_content"
......@@ -186,6 +190,17 @@ export default {
<span v-else class="gl-font-weight-bold danger" data-testid="rebase-message">{{
rebasingError
}}</span>
<gl-button
v-if="glFeatures.restructuredMrWidget"
:loading="isMakingRequest"
variant="confirm"
size="small"
data-qa-selector="mr_rebase_button"
class="gl-ml-3!"
@click="rebase"
>
{{ __('Rebase') }}
</gl-button>
</div>
</div>
</template>
......
<script>
import { GlLink, GlSprintf } from '@gitlab/ui';
import { helpPagePath } from '~/helpers/help_page_helper';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { s__ } from '~/locale';
import statusIcon from '../mr_widget_status_icon.vue';
......@@ -11,6 +12,7 @@ export default {
GlSprintf,
statusIcon,
},
mixins: [glFeatureFlagMixin()],
computed: {
troubleshootingDocsPath() {
return helpPagePath('ci/troubleshooting', { anchor: 'merge-request-status-messages' });
......@@ -28,7 +30,7 @@ export default {
<div class="mr-widget-body media">
<status-icon :show-disabled-button="true" status="warning" />
<div class="media-body space-children">
<span class="bold">
<span :class="{ 'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget }" class="bold">
<gl-sprintf :message="$options.i18n.failedMessage">
<template #link="{ content }">
<gl-link :href="troubleshootingDocsPath" target="_blank">
......
......@@ -529,7 +529,7 @@ export default {
<template>
<div
:class="{
'gl-border-t-1 gl-border-t-solid gl-border-gray-100 gl-bg-gray-10 gl-pl-7':
'gl-border-t-1 gl-border-t-solid gl-border-gray-100 gl-bg-gray-10 gl-pl-7 gl-rounded-bottom-left-base gl-rounded-bottom-right-base':
glFeatures.restructuredMrWidget,
}"
>
......
<script>
import { GlButton } from '@gitlab/ui';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { I18N_SHA_MISMATCH } from '../../i18n';
import statusIcon from '../mr_widget_status_icon.vue';
......@@ -12,6 +13,7 @@ export default {
i18n: {
I18N_SHA_MISMATCH,
},
mixins: [glFeatureFlagMixin()],
props: {
mr: {
type: Object,
......@@ -25,7 +27,11 @@ export default {
<div class="mr-widget-body media">
<status-icon :show-disabled-button="false" status="warning" />
<div class="media-body">
<span class="gl-font-weight-bold" data-qa-selector="head_mismatch_content">
<span
:class="{ 'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget }"
class="gl-font-weight-bold"
data-qa-selector="head_mismatch_content"
>
{{ $options.i18n.I18N_SHA_MISMATCH.warningMessage }}
</span>
<gl-button
......
<script>
import { GlButton } from '@gitlab/ui';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import notesEventHub from '~/notes/event_hub';
import statusIcon from '../mr_widget_status_icon.vue';
......@@ -9,6 +10,7 @@ export default {
statusIcon,
GlButton,
},
mixins: [glFeatureFlagMixin()],
props: {
mr: {
type: Object,
......@@ -25,16 +27,24 @@ export default {
<template>
<div class="mr-widget-body media gl-flex-wrap">
<status-icon :show-disabled-button="true" status="warning" />
<status-icon show-disabled-button status="warning" />
<div class="media-body">
<span class="gl-ml-3 gl-font-weight-bold gl-display-block gl-w-100">{{
s__('mrWidget|Merge blocked: all threads must be resolved.')
}}</span>
<span
:class="{
'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget,
'gl-display-block': !glFeatures.restructuredMrWidget,
}"
class="gl-ml-3 gl-font-weight-bold gl-w-100"
>
{{ s__('mrWidget|Merge blocked: all threads must be resolved.') }}
</span>
<gl-button
data-testid="jump-to-first"
class="gl-ml-3"
size="small"
icon="comment-next"
:icon="glFeatures.restructuredMrWidget ? undefined : 'comment-next'"
:variant="glFeatures.restructuredMrWidget && 'confirm'"
:category="glFeatures.restructuredMrWidget && 'secondary'"
@click="jumpToFirstUnresolvedDiscussion"
>
{{ s__('mrWidget|Jump to first unresolved thread') }}
......@@ -44,7 +54,7 @@ export default {
:href="mr.createIssueToResolveDiscussionsPath"
class="js-create-issue gl-ml-3"
size="small"
icon="issue-new"
:icon="glFeatures.restructuredMrWidget ? undefined : 'issue-new'"
>
{{ s__('mrWidget|Create issue to resolve all threads') }}
</gl-button>
......
......@@ -166,7 +166,10 @@ export default {
<status-icon :show-disabled-button="canUpdate" status="warning" />
<div class="media-body">
<div class="float-left">
<span class="gl-font-weight-bold">
<span
:class="{ 'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget }"
class="gl-font-weight-bold"
>
{{
__("Merge blocked: merge request must be marked as ready. It's still marked as draft.")
}}
......
......@@ -357,15 +357,13 @@ export default class MergeRequestStore {
setApprovals(data) {
this.approvals = data;
this.isApproved = data.approved || false;
this.setState();
}
// eslint-disable-next-line class-methods-use-this
get hasMergeChecksFailed() {
if (!window.gon?.features?.restructuredMrWidget) return false;
return (
this.hasMergeableDiscussionsState ||
(this.onlyAllowMergeIfPipelineSucceeds && this.isPipelineFailed)
);
return false;
}
// Because the state machine doesn't yet handle every state and transition,
......
<script>
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import StatusIcon from '~/vue_merge_request_widget/components/mr_widget_status_icon.vue';
export default {
......@@ -6,17 +7,23 @@ export default {
components: {
StatusIcon,
},
mixins: [glFeatureFlagMixin()],
};
</script>
<template>
<div class="mr-widget-body media">
<status-icon :show-disabled-button="true" status="warning" />
<status-icon show-disabled-button status="warning" />
<div class="media-body">
<strong class="gl-font-weight-bold gl-text-gray-700">
<span
:class="{
'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget,
}"
class="gl-font-weight-bold gl-text-gray-700"
>
{{
s__('mrWidget|To merge, a Jira issue key must be mentioned in the title or description.')
}}
</strong>
</span>
</div>
</div>
</template>
<script>
import { GlButton } from '@gitlab/ui';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import StatusIcon from '~/vue_merge_request_widget/components/mr_widget_status_icon.vue';
export default {
name: 'MRWidgetPolicyViolation',
components: {
GlButton,
StatusIcon,
},
mixins: [glFeatureFlagMixin()],
};
</script>
<template>
<div class="mr-widget-body media">
<div class="space-children gl-display-flex">
<status-icon status="warning" />
<gl-button category="primary" variant="success" disabled size="small">
{{ s__('mrWidget|Merge') }}
</gl-button>
<status-icon status="warning" show-disabled-button />
</div>
<div class="media-body">
<strong class="gl-font-weight-bold gl-text-gray-700 gl-pl-2">
<span
:class="{
'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget,
}"
class="gl-font-weight-bold gl-text-gray-700 gl-pl-2"
>
{{ s__('mrWidget|Merge blocked: denied licenses must be removed.') }}
</strong>
</span>
</div>
</div>
</template>
<script>
import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import statusIcon from '~/vue_merge_request_widget/components/mr_widget_status_icon.vue';
export default {
......@@ -10,6 +11,7 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
mixins: [glFeatureFlagMixin()],
props: {
mr: {
type: Object,
......@@ -19,12 +21,17 @@ export default {
};
</script>
<template>
<div class="media">
<div class="mr-widget-body media gl-flex-wrap">
<status-icon status="warning" show-disabled-button />
<div class="media-body">
<span class="bold">{{
__('Merge unavailable: merge requests are read-only in a secondary Geo node.')
}}</span>
<span
:class="{
'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget,
}"
class="bold"
>
{{ __('Merge unavailable: merge requests are read-only in a secondary Geo node.') }}
</span>
<a
v-gl-tooltip
:href="mr.geoSecondaryHelpPath"
......
......@@ -83,6 +83,8 @@ export default class MergeRequestStore extends CEMergeRequestStore {
this.approvals = mapApprovalsResponse(data);
this.approvalsLeft = Boolean(data.approvals_left);
this.preventMerge = !this.isApproved;
this.setState();
}
setApprovalRules(data) {
......@@ -94,6 +96,8 @@ export default class MergeRequestStore extends CEMergeRequestStore {
if (this.hasApprovalsAvailable && this.approvals && this.approvalsLeft) return !this.isApproved;
if (this.blockingMergeRequests.total_count > 0) return true;
return super.hasMergeChecksFailed;
}
......
import { GlButton } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import StatusIcon from '~/vue_merge_request_widget/components/mr_widget_status_icon.vue';
import MrWidgetPolicyViolation from 'ee/vue_merge_request_widget/components/states/mr_widget_policy_violation.vue';
describe('EE MrWidgetPolicyViolation', () => {
let wrapper;
const findButton = () => wrapper.find(GlButton);
const findStatusIcon = () => wrapper.findComponent(StatusIcon);
const createComponent = () => {
wrapper = shallowMount(MrWidgetPolicyViolation, {});
......@@ -22,7 +22,7 @@ describe('EE MrWidgetPolicyViolation', () => {
it('shows the disabled merge button', () => {
expect(wrapper.text()).toContain('Merge');
expect(findButton().props().disabled).toBe(true);
expect(findStatusIcon().props('showDisabledButton')).toBe(true);
});
it('shows the disabled reason', () => {
......
......@@ -42529,6 +42529,9 @@ msgstr ""
msgid "mrWidget|Merge blocked: this merge request must be approved."
msgstr ""
msgid "mrWidget|Merge blocked: you can only merge once above items are resolved."
msgstr ""
msgid "mrWidget|Merge failed."
msgstr ""
......@@ -42637,9 +42640,6 @@ msgstr ""
msgid "mrWidget|The pipeline for this merge request did not complete. Push a new commit to fix the failure, or check the %{linkStart}troubleshooting documentation%{linkEnd} to see other possible actions."
msgstr ""
msgid "mrWidget|The pipeline for this merge request did not complete. Push a new commit to fix the failure."
msgstr ""
msgid "mrWidget|The source branch has been deleted"
msgstr ""
......
......@@ -15,35 +15,12 @@ describe('Merge request widget merge checks failed state component', () => {
});
it.each`
mrState | displayText
${{ isPipelineFailed: true }} | ${'pipelineFailed'}
${{ approvals: true, isApproved: false }} | ${'approvalNeeded'}
${{ hasMergeableDiscussionsState: true }} | ${'unresolvedDiscussions'}
mrState | displayText
${{ approvals: true, isApproved: false }} | ${'approvalNeeded'}
${{ blockingMergeRequests: { total_count: 1 } }} | ${'blockingMergeRequests'}
`('display $displayText text for $mrState', ({ mrState, displayText }) => {
factory({ mr: mrState });
expect(wrapper.text()).toContain(MergeChecksFailed.i18n[displayText]);
});
describe('unresolved discussions', () => {
it('renders jump to button', () => {
factory({ mr: { hasMergeableDiscussionsState: true } });
expect(wrapper.find('[data-testid="jumpToUnresolved"]').exists()).toBe(true);
});
it('renders resolve thread button', () => {
factory({
mr: {
hasMergeableDiscussionsState: true,
createIssueToResolveDiscussionsPath: 'https://gitlab.com',
},
});
expect(wrapper.find('[data-testid="resolveIssue"]').exists()).toBe(true);
expect(wrapper.find('[data-testid="resolveIssue"]').attributes('href')).toBe(
'https://gitlab.com',
);
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment