Commit 84e01b3e authored by Jose Ivan Vargas's avatar Jose Ivan Vargas

Changed selector names, address code concerns

parent d5c00186
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
}, },
computed: { computed: {
title() { title() {
return sprintf(s__('Milestones|Promote %{title} to group milestone?'), { title: this.milestoneTitle }); return sprintf(s__('Milestones|Promote %{milestoneTitle} to group milestone?'), { milestoneTitle: this.milestoneTitle });
}, },
text() { text() {
return s__(`Milestones|Promoting this milestone will make it available for all projects inside the group. return s__(`Milestones|Promoting this milestone will make it available for all projects inside the group.
...@@ -35,11 +35,11 @@ ...@@ -35,11 +35,11 @@
eventHub.$emit('promoteMilestoneModal.requestStarted', this.url); eventHub.$emit('promoteMilestoneModal.requestStarted', this.url);
return axios.post(this.url) return axios.post(this.url)
.then((response) => { .then((response) => {
eventHub.$emit('promoteMilestoneModal.requestFinished', { labelUrl: this.url, successful: true }); eventHub.$emit('promoteMilestoneModal.requestFinished', { milestoneUrl: this.url, successful: true });
redirectTo(response.request.responseURL); redirectTo(response.request.responseURL);
}) })
.catch((error) => { .catch((error) => {
eventHub.$emit('promoteMilestoneModal.requestFinished', { labelUrl: this.url, successful: true }); eventHub.$emit('promoteMilestoneModal.requestFinished', { milestoneUrl: this.url, successful: false });
createFlash(error); createFlash(error);
}); });
}, },
...@@ -53,11 +53,11 @@ ...@@ -53,11 +53,11 @@
:footer-primary-button-text="s__('Milestones|Promote Milestone')" :footer-primary-button-text="s__('Milestones|Promote Milestone')"
@submit="onSubmit" @submit="onSubmit"
> >
<div <template
slot="title" slot="title"
> >
{{ title }} {{ title }}
</div> </template>
{{ text }} {{ text }}
</gl-modal> </gl-modal>
</template> </template>
......
...@@ -37,16 +37,14 @@ export default () => { ...@@ -37,16 +37,14 @@ export default () => {
}; };
const deleteMilestoneButtons = document.querySelectorAll('.js-delete-milestone-button'); const deleteMilestoneButtons = document.querySelectorAll('.js-delete-milestone-button');
for (let i = 0; i < deleteMilestoneButtons.length; i += 1) { deleteMilestoneButtons.forEach((button) => {
const button = deleteMilestoneButtons[i];
button.addEventListener('click', onDeleteButtonClick); button.addEventListener('click', onDeleteButtonClick);
} });
eventHub.$once('deleteMilestoneModal.mounted', () => { eventHub.$once('deleteMilestoneModal.mounted', () => {
for (let i = 0; i < deleteMilestoneButtons.length; i += 1) { deleteMilestoneButtons.forEach((button) => {
const button = deleteMilestoneButtons[i];
button.removeAttribute('disabled'); button.removeAttribute('disabled');
} });
}); });
return new Vue({ return new Vue({
......
...@@ -5,78 +5,78 @@ import eventHub from './event_hub'; ...@@ -5,78 +5,78 @@ import eventHub from './event_hub';
Vue.use(Translate); Vue.use(Translate);
const onRequestFinished = ({ milestoneUrl, successful }) => { export default () => {
const button = document.querySelector(`.js-promote-project-milestone[data-url="${milestoneUrl}"]`); const onRequestFinished = ({ milestoneUrl, successful }) => {
const button = document.querySelector(`.js-promote-project-milestone-button[data-url="${milestoneUrl}"]`);
if (!successful) {
button.removeAttribute('disabled');
}
};
const onRequestStarted = (milestoneUrl) => { if (!successful) {
const button = document.querySelector(`.js-promote-project-milestone[data-url="${milestoneUrl}"]`); button.removeAttribute('disabled');
button.setAttribute('disabled', ''); }
eventHub.$once('promoteMilestoneModal.requestFinished', onRequestFinished); };
};
const onDeleteButtonClick = (event) => { const onRequestStarted = (milestoneUrl) => {
const button = event.currentTarget; const button = document.querySelector(`.js-promote-project-milestone-button[data-url="${milestoneUrl}"]`);
const modalProps = { button.setAttribute('disabled', '');
milestoneTitle: button.dataset.milestoneTitle, eventHub.$once('promoteMilestoneModal.requestFinished', onRequestFinished);
url: button.dataset.url,
}; };
eventHub.$once('promoteMilestoneModal.requestStarted', onRequestStarted);
eventHub.$emit('promoteMilestoneModal.props', modalProps);
};
const promoteMilestoneButtons = document.querySelectorAll('.js-promote-project-milestone'); const onDeleteButtonClick = (event) => {
promoteMilestoneButtons.forEach((button) => { const button = event.currentTarget;
button.addEventListener('click', onDeleteButtonClick); const modalProps = {
}); milestoneTitle: button.dataset.milestoneTitle,
url: button.dataset.url,
};
eventHub.$once('promoteMilestoneModal.requestStarted', onRequestStarted);
eventHub.$emit('promoteMilestoneModal.props', modalProps);
};
eventHub.$once('promoteMilestoneModal.mounted', () => { const promoteMilestoneButtons = document.querySelectorAll('.js-promote-project-milestone-button');
promoteMilestoneButtons.forEach((button) => { promoteMilestoneButtons.forEach((button) => {
button.removeAttribute('disabled'); button.addEventListener('click', onDeleteButtonClick);
}); });
});
export default () => { eventHub.$once('promoteMilestoneModal.mounted', () => {
const promoteMilestoneComponent = new Vue({ promoteMilestoneButtons.forEach((button) => {
el: '#promote-milestone-modal', button.removeAttribute('disabled');
components: { });
PromoteMilestoneModal,
},
data() {
return {
modalProps: {
milestoneTitle: '',
url: '',
},
};
},
mounted() {
eventHub.$on('promoteMilestoneModal.props', this.setModalProps);
eventHub.$emit('promoteMilestoneModal.mounted');
},
beforeDestroy() {
eventHub.$off('promoteMilestoneModal.props', this.setModalProps);
},
methods: {
setModalProps(modalProps) {
this.modalProps = modalProps;
},
},
render(createElement) {
return createElement('promote-milestone-modal', {
props: this.modalProps,
});
},
}); });
const promoteMilestoneModal = document.getElementById('promote-milestone-modal'); const promoteMilestoneModal = document.getElementById('promote-milestone-modal');
let withMilestone; let promoteMilestoneComponent;
if (promoteMilestoneModal != null) {
withMilestone = promoteMilestoneComponent; if (promoteMilestoneModal) {
promoteMilestoneComponent = new Vue({
el: promoteMilestoneModal,
components: {
PromoteMilestoneModal,
},
data() {
return {
modalProps: {
milestoneTitle: '',
url: '',
},
};
},
mounted() {
eventHub.$on('promoteMilestoneModal.props', this.setModalProps);
eventHub.$emit('promoteMilestoneModal.mounted');
},
beforeDestroy() {
eventHub.$off('promoteMilestoneModal.props', this.setModalProps);
},
methods: {
setModalProps(modalProps) {
this.modalProps = modalProps;
},
},
render(createElement) {
return createElement('promote-milestone-modal', {
props: this.modalProps,
});
},
});
} }
return withMilestone;
return promoteMilestoneComponent;
}; };
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
import createFlash from '~/flash'; import createFlash from '~/flash';
import GlModal from '~/vue_shared/components/gl_modal.vue'; import GlModal from '~/vue_shared/components/gl_modal.vue';
import { redirectTo } from '~/lib/utils/url_utility'; import { redirectTo } from '~/lib/utils/url_utility';
import { s__ } from '~/locale'; import { s__, sprintf } from '~/locale';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
export default { export default {
...@@ -23,12 +23,26 @@ ...@@ -23,12 +23,26 @@
type: String, type: String,
required: true, required: true,
}, },
labelTextColor: {
type: String,
required: true,
},
}, },
computed: { computed: {
text() { text() {
return s__(`Milestones|Promoting this label will make it available for all projects inside the group. return s__(`Milestones|Promoting this label will make it available for all projects inside the group.
Existing project labels with the same name will be merged. This action cannot be reversed.`); Existing project labels with the same name will be merged. This action cannot be reversed.`);
}, },
title() {
const label = `<span
class="label color-label"
style="background-color: ${this.labelColor}; color: ${this.labelTextColor};"
>${this.labelTitle}</span>`;
return sprintf(s__('Labels|Promote label %{labelTitle} to Group Label?'), {
labelTitle: label,
}, false);
},
}, },
methods: { methods: {
onSubmit() { onSubmit() {
...@@ -55,15 +69,9 @@ ...@@ -55,15 +69,9 @@
> >
<div <div
slot="title" slot="title"
v-html="title"
> >
{{ s__('Labels|Promote label') }} {{ title }}
<span
class="label color-label"
:style="{ backgroundColor: labelColor }"
>
{{ labelTitle }}
</span>
{{ s__('Labels|to Group Label?') }}
</div> </div>
{{ text }} {{ text }}
......
...@@ -6,84 +6,86 @@ import PromoteLabelModal from '../components/promote_label_modal.vue'; ...@@ -6,84 +6,86 @@ import PromoteLabelModal from '../components/promote_label_modal.vue';
Vue.use(Translate); Vue.use(Translate);
const onRequestFinished = ({ labelUrl, successful }) => { const initLabelIndex = () => {
const button = document.querySelector(`.js-promote-project-label[data-url="${labelUrl}"]`); initLabels();
if (!successful) { const onRequestFinished = ({ labelUrl, successful }) => {
button.removeAttribute('disabled'); const button = document.querySelector(`.js-promote-project-label-button[data-url="${labelUrl}"]`);
}
};
const onRequestStarted = (labelUrl) => { if (!successful) {
const button = document.querySelector(`.js-promote-project-label[data-url="${labelUrl}"]`); button.removeAttribute('disabled');
button.setAttribute('disabled', ''); }
eventHub.$once('promoteLabelModal.requestFinished', onRequestFinished); };
};
const onDeleteButtonClick = (event) => { const onRequestStarted = (labelUrl) => {
const button = event.currentTarget; const button = document.querySelector(`.js-promote-project-label-button[data-url="${labelUrl}"]`);
const modalProps = { button.setAttribute('disabled', '');
labelTitle: button.dataset.labelTitle, eventHub.$once('promoteLabelModal.requestFinished', onRequestFinished);
labelColor: button.dataset.labelColor,
url: button.dataset.url,
}; };
eventHub.$once('promoteLabelModal.requestStarted', onRequestStarted);
eventHub.$emit('promoteLabelModal.props', modalProps);
};
const promoteLabelButtons = document.querySelectorAll('.js-promote-project-label'); const onDeleteButtonClick = (event) => {
promoteLabelButtons.forEach((button) => { const button = event.currentTarget;
button.addEventListener('click', onDeleteButtonClick); const modalProps = {
}); labelTitle: button.dataset.labelTitle,
labelColor: button.dataset.labelColor,
labelTextColor: button.dataset.labelTextColor,
url: button.dataset.url,
};
eventHub.$once('promoteLabelModal.requestStarted', onRequestStarted);
eventHub.$emit('promoteLabelModal.props', modalProps);
};
eventHub.$once('promoteLabelModal.mounted', () => { const promoteLabelButtons = document.querySelectorAll('.js-promote-project-label-button');
promoteLabelButtons.forEach((button) => { promoteLabelButtons.forEach((button) => {
button.removeAttribute('disabled'); button.addEventListener('click', onDeleteButtonClick);
}); });
});
const initLabelIndex = () => {
initLabels();
const promoteLabelModalComponent = new Vue({ eventHub.$once('promoteLabelModal.mounted', () => {
el: '#promote-label-modal', promoteLabelButtons.forEach((button) => {
components: { button.removeAttribute('disabled');
PromoteLabelModal, });
},
data() {
return {
modalProps: {
labelTitle: '',
labelColor: '',
url: '',
},
};
},
mounted() {
eventHub.$on('promoteLabelModal.props', this.setModalProps);
eventHub.$emit('promoteLabelModal.mounted');
},
beforeDestroy() {
eventHub.$off('promoteLabelModal.props', this.setModalProps);
},
methods: {
setModalProps(modalProps) {
this.modalProps = modalProps;
},
},
render(createElement) {
return createElement('promote-label-modal', {
props: this.modalProps,
});
},
}); });
const promoteLabelModal = document.getElementById('promote-label-modal'); const promoteLabelModal = document.getElementById('promote-label-modal');
let withLabel; let promoteLabelModalComponent;
if (promoteLabelModal != null) {
withLabel = promoteLabelModalComponent; if (promoteLabelModal) {
promoteLabelModalComponent = new Vue({
el: promoteLabelModal,
components: {
PromoteLabelModal,
},
data() {
return {
modalProps: {
labelTitle: '',
labelColor: '',
labelTextColor: '',
url: '',
},
};
},
mounted() {
eventHub.$on('promoteLabelModal.props', this.setModalProps);
eventHub.$emit('promoteLabelModal.mounted');
},
beforeDestroy() {
eventHub.$off('promoteLabelModal.props', this.setModalProps);
},
methods: {
setModalProps(modalProps) {
this.modalProps = modalProps;
},
},
render(createElement) {
return createElement('promote-label-modal', {
props: this.modalProps,
});
},
});
} }
return withLabel;
return promoteLabelModalComponent;
}; };
document.addEventListener('DOMContentLoaded', initLabelIndex); document.addEventListener('DOMContentLoaded', initLabelIndex);
...@@ -4,13 +4,15 @@ ...@@ -4,13 +4,15 @@
.page-title, .page-title,
.modal-title { .modal-title {
margin-top: 0;
.color-label { .color-label {
font-size: $gl-font-size; font-size: $gl-font-size;
padding: $gl-vert-padding $label-padding-modal; padding: $gl-vert-padding $label-padding-modal;
} }
} }
.page-title {
margin-top: 0;
}
} }
.modal-body { .modal-body {
......
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
- hide_class = '' - hide_class = ''
- can_admin_label = can?(current_user, :admin_label, @project) - can_admin_label = can?(current_user, :admin_label, @project)
#promote-label-modal
- if @labels.exists? || @prioritized_labels.exists? - if @labels.exists? || @prioritized_labels.exists?
#promote-label-modal
%div{ class: container_class } %div{ class: container_class }
.top-area.adjust .top-area.adjust
.nav-text .nav-text
......
...@@ -27,12 +27,12 @@ ...@@ -27,12 +27,12 @@
Edit Edit
- if @project.group - if @project.group
%button.js-promote-project-milestone.btn.btn-grouped{ data: { toggle: 'modal', %button.js-promote-project-milestone-button.btn.btn-grouped{ data: { toggle: 'modal',
target: '#promote-milestone-modal', target: '#promote-milestone-modal',
milestone_title: @milestone.title, milestone_title: @milestone.title,
url: promote_project_milestone_path(@milestone.project, @milestone), url: promote_project_milestone_path(@milestone.project, @milestone),
container: 'body', container: 'body' },
disabled: true } } disabled: true }
= _('Promote') = _('Promote')
#promote-milestone-modal #promote-milestone-modal
......
...@@ -48,10 +48,11 @@ ...@@ -48,10 +48,11 @@
.pull-right.hidden-xs.hidden-sm .pull-right.hidden-xs.hidden-sm
- if label.is_a?(ProjectLabel) && label.project.group && can?(current_user, :admin_label, label.project.group) - if label.is_a?(ProjectLabel) && label.project.group && can?(current_user, :admin_label, label.project.group)
%a.js-promote-project-label.btn.btn-transparent.btn-action.has-tooltip{ title: _('Promote to Group Label'), %a.js-promote-project-label-button.btn.btn-transparent.btn-action.has-tooltip{ title: _('Promote to Group Label'),
data: { url: promote_project_label_path(label.project, label), data: { url: promote_project_label_path(label.project, label),
label_title: label.title, label_title: label.title,
label_color: label.color, label_color: label.color,
label_text_color: label.text_color,
target: '#promote-label-modal', target: '#promote-label-modal',
container: 'body', container: 'body',
toggle: 'modal' }, toggle: 'modal' },
......
...@@ -51,14 +51,14 @@ ...@@ -51,14 +51,14 @@
\ \
- if @project.group - if @project.group
%a.js-promote-project-milestone.btn.btn-xs.btn-grouped.has-tooltip{ title: _('Promote to Group Milestone'), %a.js-promote-project-milestone-button.btn.btn-xs.btn-grouped.has-tooltip{ title: _('Promote to Group Milestone'),
data: { url: promote_project_milestone_path(milestone.project, milestone), data: { url: promote_project_milestone_path(milestone.project, milestone),
milestone_title: milestone.title, milestone_title: milestone.title,
target: '#promote-milestone-modal', target: '#promote-milestone-modal',
container: 'body', container: 'body',
toggle: 'modal' }, toggle: 'modal' },
disabled: true } disabled: true }
Promote = _('Promote')
= link_to 'Close Milestone', project_milestone_path(@project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-xs btn-close btn-grouped" = link_to 'Close Milestone', project_milestone_path(@project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-xs btn-close btn-grouped"
......
--- ---
title: Added vue based promotion modals for labels and milestones title: Added new design for promotion modals
merge_request: 17197 merge_request: 17197
author: author:
type: other type: other
...@@ -7,35 +7,28 @@ import mountComponent from '../../../helpers/vue_mount_component_helper'; ...@@ -7,35 +7,28 @@ import mountComponent from '../../../helpers/vue_mount_component_helper';
describe('Promote label modal', () => { describe('Promote label modal', () => {
let vm; let vm;
let Component; const Component = Vue.extend(promoteLabelModal);
const labelMockData = { const labelMockData = {
labelTitle: 'Documentation', labelTitle: 'Documentation',
labelColor: '#5cb85c', labelColor: '#5cb85c',
url: `${gl.TEST_HOST}/dummy/endpoint`, labelTextColor: '#ffffff',
url: `${gl.TEST_HOST}/dummy/promote/labels`,
}; };
beforeEach(() => {
Component = Vue.extend(promoteLabelModal);
});
describe('Modal title and description', () => { describe('Modal title and description', () => {
beforeEach(() => { beforeEach(() => {
vm = mountComponent(Component, { vm = mountComponent(Component, labelMockData);
...labelMockData,
});
}); });
afterEach(() => { afterEach(() => {
vm.$destroy(); vm.$destroy();
}); });
it('should contain the proper description', () => { it('contains the proper description', () => {
expect(vm.text).toContain('Promoting this label will make it available for all projects inside the group'); expect(vm.text).toContain('Promoting this label will make it available for all projects inside the group');
expect(vm.text).toContain('Existing project labels with the same name will be merged');
expect(vm.text).toContain('This action cannot be reversed.');
}); });
it('should contain a label span with the color', () => { it('contains a label span with the color', () => {
const labelFromTitle = vm.$el.querySelector('.modal-header .label.color-label'); const labelFromTitle = vm.$el.querySelector('.modal-header .label.color-label');
expect(labelFromTitle.style.backgroundColor).not.toBe(null); expect(labelFromTitle.style.backgroundColor).not.toBe(null);
...@@ -55,7 +48,7 @@ describe('Promote label modal', () => { ...@@ -55,7 +48,7 @@ describe('Promote label modal', () => {
vm.$destroy(); vm.$destroy();
}); });
it('should redirect when a label is promoted', (done) => { it('redirects when a label is promoted', (done) => {
const responseURL = `${gl.TEST_HOST}/dummy/endpoint`; const responseURL = `${gl.TEST_HOST}/dummy/endpoint`;
spyOn(axios, 'post').and.callFake((url) => { spyOn(axios, 'post').and.callFake((url) => {
expect(url).toBe(labelMockData.url); expect(url).toBe(labelMockData.url);
...@@ -71,6 +64,7 @@ describe('Promote label modal', () => { ...@@ -71,6 +64,7 @@ describe('Promote label modal', () => {
vm.onSubmit() vm.onSubmit()
.then(() => { .then(() => {
expect(redirectSpy).toHaveBeenCalledWith(responseURL); expect(redirectSpy).toHaveBeenCalledWith(responseURL);
expect(eventHub.$emit).toHaveBeenCalledWith('promoteLabelModal.requestFinished', { labelUrl: labelMockData.url, successful: true });
}) })
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
......
...@@ -7,34 +7,26 @@ import mountComponent from '../../../../helpers/vue_mount_component_helper'; ...@@ -7,34 +7,26 @@ import mountComponent from '../../../../helpers/vue_mount_component_helper';
describe('Promote milestone modal', () => { describe('Promote milestone modal', () => {
let vm; let vm;
let Component; const Component = Vue.extend(promoteMilestoneModal);
const milestoneMockData = { const milestoneMockData = {
milestoneTitle: 'v1.0', milestoneTitle: 'v1.0',
url: `${gl.TEST_HOST}/dummy/endpoint`, url: `${gl.TEST_HOST}/dummy/promote/milestones`,
}; };
beforeEach(() => {
Component = Vue.extend(promoteMilestoneModal);
});
describe('Modal title and description', () => { describe('Modal title and description', () => {
beforeEach(() => { beforeEach(() => {
vm = mountComponent(Component, { vm = mountComponent(Component, milestoneMockData);
...milestoneMockData,
});
}); });
afterEach(() => { afterEach(() => {
vm.$destroy(); vm.$destroy();
}); });
it('should contain the proper description', () => { it('contains the proper description', () => {
expect(vm.text).toContain('Promoting this milestone will make it available for all projects inside the group.'); expect(vm.text).toContain('Promoting this milestone will make it available for all projects inside the group.');
expect(vm.text).toContain('Existing project milestones with the same name will be merged.');
expect(vm.text).toContain('This action cannot be reversed.');
}); });
it('should contain the correct title', () => { it('contains the correct title', () => {
expect(vm.title).toEqual('Promote v1.0 to group milestone?'); expect(vm.title).toEqual('Promote v1.0 to group milestone?');
}); });
}); });
...@@ -51,7 +43,7 @@ describe('Promote milestone modal', () => { ...@@ -51,7 +43,7 @@ describe('Promote milestone modal', () => {
vm.$destroy(); vm.$destroy();
}); });
it('should redirect when a milestone is promoted', (done) => { it('redirects when a milestone is promoted', (done) => {
const responseURL = `${gl.TEST_HOST}/dummy/endpoint`; const responseURL = `${gl.TEST_HOST}/dummy/endpoint`;
spyOn(axios, 'post').and.callFake((url) => { spyOn(axios, 'post').and.callFake((url) => {
expect(url).toBe(milestoneMockData.url); expect(url).toBe(milestoneMockData.url);
...@@ -67,6 +59,7 @@ describe('Promote milestone modal', () => { ...@@ -67,6 +59,7 @@ describe('Promote milestone modal', () => {
vm.onSubmit() vm.onSubmit()
.then(() => { .then(() => {
expect(redirectSpy).toHaveBeenCalledWith(responseURL); expect(redirectSpy).toHaveBeenCalledWith(responseURL);
expect(eventHub.$emit).toHaveBeenCalledWith('promoteMilestoneModal.requestFinished', { milestoneUrl: milestoneMockData.url, successful: true });
}) })
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
......
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