Commit f195ac03 authored by Phil Hughes's avatar Phil Hughes

Merge branch 'fl-vue-mr-widget' into 'master'

Move mr_widget_merged into a vue file

Closes #42486

See merge request gitlab-org/gitlab-ce!16746
parents 229785d5 c62ffe27
import Flash from '../../../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.vue';
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.data)
.then((data) => {
if (data.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.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="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>
`,
};
<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';
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>
...@@ -16,7 +16,7 @@ export { default as WidgetMergeHelp } from './components/mr_widget_merge_help'; ...@@ -16,7 +16,7 @@ export { default as WidgetMergeHelp } from './components/mr_widget_merge_help';
export { default as WidgetPipeline } from './components/mr_widget_pipeline.vue'; export { default as WidgetPipeline } from './components/mr_widget_pipeline.vue';
export { default as WidgetDeployment } from './components/mr_widget_deployment'; export { default as WidgetDeployment } from './components/mr_widget_deployment';
export { default as WidgetRelatedLinks } from './components/mr_widget_related_links'; export { default as WidgetRelatedLinks } from './components/mr_widget_related_links';
export { default as MergedState } from './components/states/mr_widget_merged'; export { default as MergedState } from './components/states/mr_widget_merged.vue';
export { default as FailedToMerge } from './components/states/mr_widget_failed_to_merge.vue'; export { default as FailedToMerge } from './components/states/mr_widget_failed_to_merge.vue';
export { default as ClosedState } from './components/states/mr_widget_closed.vue'; export { default as ClosedState } from './components/states/mr_widget_closed.vue';
export { default as MergingState } from './components/states/mr_widget_merging.vue'; export { default as MergingState } from './components/states/mr_widget_merging.vue';
......
import Vue from 'vue'; import Vue from 'vue';
import mergedComponent from '~/vue_merge_request_widget/components/states/mr_widget_merged'; import mergedComponent from '~/vue_merge_request_widget/components/states/mr_widget_merged.vue';
import eventHub from '~/vue_merge_request_widget/event_hub'; import eventHub from '~/vue_merge_request_widget/event_hub';
import mountComponent from '../../../helpers/vue_mount_component_helper';
const targetBranch = 'foo';
const createComponent = () => {
const Component = Vue.extend(mergedComponent);
const mr = {
isRemovingSourceBranch: false,
cherryPickInForkPath: false,
canCherryPickInCurrentMR: true,
revertInForkPath: false,
canRevertInCurrentMR: true,
canRemoveSourceBranch: true,
sourceBranchRemoved: true,
metrics: {
mergedBy: {},
mergedAt: 'mergedUpdatedAt',
readableMergedAt: '',
closedBy: {},
closedAt: 'mergedUpdatedAt',
readableClosedAt: '',
},
updatedAt: 'mrUpdatedAt',
targetBranch,
};
const service = {
removeSourceBranch() {},
};
return new Component({
el: document.createElement('div'),
propsData: { mr, service },
});
};
describe('MRWidgetMerged', () => { describe('MRWidgetMerged', () => {
describe('props', () => { let vm;
it('should have props', () => { const targetBranch = 'foo';
const { mr, service } = mergedComponent.props;
beforeEach(() => {
expect(mr.type instanceof Object).toBeTruthy(); const Component = Vue.extend(mergedComponent);
expect(mr.required).toBeTruthy(); const mr = {
isRemovingSourceBranch: false,
expect(service.type instanceof Object).toBeTruthy(); cherryPickInForkPath: false,
expect(service.required).toBeTruthy(); canCherryPickInCurrentMR: true,
}); revertInForkPath: false,
}); canRevertInCurrentMR: true,
canRemoveSourceBranch: true,
describe('components', () => { sourceBranchRemoved: true,
it('should have components added', () => { metrics: {
expect(mergedComponent.components['mr-widget-author-and-time']).toBeDefined(); mergedBy: {
}); name: 'Administrator',
username: 'root',
webUrl: 'http://localhost:3000/root',
avatarUrl: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
},
mergedAt: 'Jan 24, 2018 1:02pm GMT+0000',
readableMergedAt: '',
closedBy: {},
closedAt: 'Jan 24, 2018 1:02pm GMT+0000',
readableClosedAt: '',
},
updatedAt: 'mergedUpdatedAt',
targetBranch,
};
const service = {
removeSourceBranch() {},
};
spyOn(eventHub, '$emit');
vm = mountComponent(Component, { mr, service });
}); });
describe('data', () => { afterEach(() => {
it('should have default data', () => { vm.$destroy();
const data = mergedComponent.data();
expect(data.isMakingRequest).toBeFalsy();
});
}); });
describe('computed', () => { describe('computed', () => {
describe('shouldShowRemoveSourceBranch', () => { describe('shouldShowRemoveSourceBranch', () => {
it('should correct value when fields changed', () => { it('returns true when sourceBranchRemoved is false', () => {
const vm = createComponent();
vm.mr.sourceBranchRemoved = false; vm.mr.sourceBranchRemoved = false;
expect(vm.shouldShowRemoveSourceBranch).toBeTruthy(); expect(vm.shouldShowRemoveSourceBranch).toEqual(true);
});
it('returns false wehn sourceBranchRemoved is true', () => {
vm.mr.sourceBranchRemoved = true; vm.mr.sourceBranchRemoved = true;
expect(vm.shouldShowRemoveSourceBranch).toBeFalsy(); expect(vm.shouldShowRemoveSourceBranch).toEqual(false);
});
it('returns false when canRemoveSourceBranch is false', () => {
vm.mr.sourceBranchRemoved = false; vm.mr.sourceBranchRemoved = false;
vm.mr.canRemoveSourceBranch = false; vm.mr.canRemoveSourceBranch = false;
expect(vm.shouldShowRemoveSourceBranch).toBeFalsy(); expect(vm.shouldShowRemoveSourceBranch).toEqual(false);
});
it('returns false when is making request', () => {
vm.mr.canRemoveSourceBranch = true; vm.mr.canRemoveSourceBranch = true;
vm.isMakingRequest = true; vm.isMakingRequest = true;
expect(vm.shouldShowRemoveSourceBranch).toBeFalsy(); expect(vm.shouldShowRemoveSourceBranch).toEqual(false);
});
it('returns true when all are true', () => {
vm.mr.isRemovingSourceBranch = true; vm.mr.isRemovingSourceBranch = true;
vm.mr.canRemoveSourceBranch = true; vm.mr.canRemoveSourceBranch = true;
vm.isMakingRequest = true; vm.isMakingRequest = true;
expect(vm.shouldShowRemoveSourceBranch).toBeFalsy(); expect(vm.shouldShowRemoveSourceBranch).toEqual(false);
}); });
}); });
describe('shouldShowSourceBranchRemoving', () => { describe('shouldShowSourceBranchRemoving', () => {
it('should correct value when fields changed', () => { it('should correct value when fields changed', () => {
const vm = createComponent();
vm.mr.sourceBranchRemoved = false; vm.mr.sourceBranchRemoved = false;
expect(vm.shouldShowSourceBranchRemoving).toBeFalsy(); expect(vm.shouldShowSourceBranchRemoving).toEqual(false);
vm.mr.sourceBranchRemoved = true; vm.mr.sourceBranchRemoved = true;
expect(vm.shouldShowRemoveSourceBranch).toBeFalsy(); expect(vm.shouldShowRemoveSourceBranch).toEqual(false);
vm.mr.sourceBranchRemoved = false; vm.mr.sourceBranchRemoved = false;
vm.isMakingRequest = true; vm.isMakingRequest = true;
expect(vm.shouldShowSourceBranchRemoving).toBeTruthy(); expect(vm.shouldShowSourceBranchRemoving).toEqual(true);
vm.isMakingRequest = false; vm.isMakingRequest = false;
vm.mr.isRemovingSourceBranch = true; vm.mr.isRemovingSourceBranch = true;
expect(vm.shouldShowSourceBranchRemoving).toBeTruthy(); expect(vm.shouldShowSourceBranchRemoving).toEqual(true);
}); });
}); });
}); });
...@@ -110,8 +101,6 @@ describe('MRWidgetMerged', () => { ...@@ -110,8 +101,6 @@ describe('MRWidgetMerged', () => {
describe('methods', () => { describe('methods', () => {
describe('removeSourceBranch', () => { describe('removeSourceBranch', () => {
it('should set flag and call service then request main component to update the widget', (done) => { it('should set flag and call service then request main component to update the widget', (done) => {
const vm = createComponent();
spyOn(eventHub, '$emit');
spyOn(vm.service, 'removeSourceBranch').and.returnValue(new Promise((resolve) => { spyOn(vm.service, 'removeSourceBranch').and.returnValue(new Promise((resolve) => {
resolve({ resolve({
data: { data: {
...@@ -123,7 +112,7 @@ describe('MRWidgetMerged', () => { ...@@ -123,7 +112,7 @@ describe('MRWidgetMerged', () => {
vm.removeSourceBranch(); vm.removeSourceBranch();
setTimeout(() => { setTimeout(() => {
const args = eventHub.$emit.calls.argsFor(0); const args = eventHub.$emit.calls.argsFor(0);
expect(vm.isMakingRequest).toBeTruthy(); expect(vm.isMakingRequest).toEqual(true);
expect(args[0]).toEqual('MRWidgetUpdateRequested'); expect(args[0]).toEqual('MRWidgetUpdateRequested');
expect(args[1]).not.toThrow(); expect(args[1]).not.toThrow();
done(); done();
...@@ -132,53 +121,50 @@ describe('MRWidgetMerged', () => { ...@@ -132,53 +121,50 @@ describe('MRWidgetMerged', () => {
}); });
}); });
describe('template', () => { it('has merged by information', () => {
let vm; expect(vm.$el.textContent).toContain('Merged by');
let el; expect(vm.$el.textContent).toContain('Administrator');
});
beforeEach(() => { it('renders branch information', () => {
vm = createComponent(); expect(vm.$el.textContent).toContain('The changes were merged into');
el = vm.$el; expect(vm.$el.textContent).toContain(targetBranch);
}); });
it('should have correct elements', () => { it('renders information about branch being removed', () => {
expect(el.classList.contains('mr-widget-body')).toBeTruthy(); expect(vm.$el.textContent).toContain('The source branch has been removed');
expect(el.querySelector('.js-mr-widget-author')).toBeDefined(); });
expect(el.innerText).toContain('The changes were merged into');
expect(el.innerText).toContain(targetBranch);
expect(el.innerText).toContain('The source branch has been removed');
expect(el.innerText).toContain('Revert');
expect(el.innerText).toContain('Cherry-pick');
expect(el.innerText).not.toContain('You can remove source branch now');
expect(el.innerText).not.toContain('The source branch is being removed');
});
it('should not show source branch removed text', (done) => { it('shows revert and cherry-pick buttons', () => {
vm.mr.sourceBranchRemoved = false; expect(vm.$el.textContent).toContain('Revert');
expect(vm.$el.textContent).toContain('Cherry-pick');
});
Vue.nextTick(() => { it('should not show source branch removed text', (done) => {
expect(el.innerText).toContain('You can remove source branch now'); vm.mr.sourceBranchRemoved = false;
expect(el.innerText).not.toContain('The source branch has been removed');
done(); Vue.nextTick(() => {
}); expect(vm.$el.innerText).toContain('You can remove source branch now');
expect(vm.$el.innerText).not.toContain('The source branch has been removed');
done();
}); });
});
it('should show source branch removing text', (done) => { it('should show source branch removing text', (done) => {
vm.mr.isRemovingSourceBranch = true; vm.mr.isRemovingSourceBranch = true;
vm.mr.sourceBranchRemoved = false; vm.mr.sourceBranchRemoved = false;
Vue.nextTick(() => { Vue.nextTick(() => {
expect(el.innerText).toContain('The source branch is being removed'); expect(vm.$el.innerText).toContain('The source branch is being removed');
expect(el.innerText).not.toContain('You can remove source branch now'); expect(vm.$el.innerText).not.toContain('You can remove source branch now');
expect(el.innerText).not.toContain('The source branch has been removed'); expect(vm.$el.innerText).not.toContain('The source branch has been removed');
done(); done();
});
}); });
});
it('should use mergedEvent updatedAt as tooltip title', () => { it('should use mergedEvent mergedAt as tooltip title', () => {
expect( expect(
el.querySelector('time').getAttribute('title'), vm.$el.querySelector('time').getAttribute('title'),
).toBe('mergedUpdatedAt'); ).toBe('Jan 24, 2018 1:02pm GMT+0000');
});
}); });
}); });
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