Commit c49872e1 authored by Phil Hughes's avatar Phil Hughes

Fixed merge blocked states styling

Fixes the styling of all the merge blocked state components
to match the new design specs.

Closes https://gitlab.com/gitlab-org/gitlab/-/issues/343782
parent 05b048ca
<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', () => {
......
......@@ -42352,6 +42352,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 ""
......@@ -42460,9 +42463,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