Commit bd9cfdeb authored by Phil Hughes's avatar Phil Hughes

Merge branch '7437-fix-epic-date-type-change-flip' into 'master'

Handle fixed dates seperately from selected dates in Epics

Closes #7437

See merge request gitlab-org/gitlab-ee!7227
parents ba6eeda0 456fbfff
...@@ -143,9 +143,11 @@ export default { ...@@ -143,9 +143,11 @@ export default {
const store = new Store({ const store = new Store({
startDateIsFixed: this.initialStartDateIsFixed, startDateIsFixed: this.initialStartDateIsFixed,
startDateFromMilestones: this.startDateFromMilestones, startDateFromMilestones: this.startDateFromMilestones,
startDateFixed: this.initialStartDateFixed,
startDate: this.initialStartDate, startDate: this.initialStartDate,
dueDateIsFixed: this.initialDueDateIsFixed, dueDateIsFixed: this.initialDueDateIsFixed,
dueDateFromMilestones: this.dueDateFromMilestones, dueDateFromMilestones: this.dueDateFromMilestones,
dueDateFixed: this.initialDueDateFixed,
endDate: this.initialEndDate, endDate: this.initialEndDate,
subscribed: this.initialSubscribed, subscribed: this.initialSubscribed,
todoExists: this.initialTodoExists, todoExists: this.initialTodoExists,
...@@ -275,6 +277,12 @@ export default { ...@@ -275,6 +277,12 @@ export default {
.then(() => { .then(() => {
this[savingBoolean] = false; this[savingBoolean] = false;
this.store[`${type}Date`] = newDate; this.store[`${type}Date`] = newDate;
if (isFixed) {
// Update fixed date in store
const fixedDate = dateType === DateTypes.start ? 'startDateFixed' : 'dueDateFixed';
this.store[fixedDate] = newDate;
}
}) })
.catch(() => { .catch(() => {
this[savingBoolean] = false; this[savingBoolean] = false;
...@@ -288,7 +296,7 @@ export default { ...@@ -288,7 +296,7 @@ export default {
if (!typeChangeOnEdit) { if (!typeChangeOnEdit) {
this.saveDate( this.saveDate(
DateTypes.start, DateTypes.start,
dateTypeIsFixed ? this.store.startDate : this.store.startDateFromMilestones, dateTypeIsFixed ? this.store.startDateFixed : this.store.startDateFromMilestones,
dateTypeIsFixed, dateTypeIsFixed,
); );
} }
...@@ -301,7 +309,7 @@ export default { ...@@ -301,7 +309,7 @@ export default {
if (!typeChangeOnEdit) { if (!typeChangeOnEdit) {
this.saveDate( this.saveDate(
DateTypes.end, DateTypes.end,
dateTypeIsFixed ? this.store.endDate : this.store.dueDateFromMilestones, dateTypeIsFixed ? this.store.dueDateFixed : this.store.dueDateFromMilestones,
dateTypeIsFixed, dateTypeIsFixed,
); );
} }
...@@ -437,6 +445,7 @@ export default { ...@@ -437,6 +445,7 @@ export default {
:editable="editable" :editable="editable"
:selected-date-is-fixed="store.startDateIsFixed" :selected-date-is-fixed="store.startDateIsFixed"
:selected-date="store.startDateTime" :selected-date="store.startDateTime"
:date-fixed="store.startDateTimeFixed"
:date-from-milestones="store.startDateTimeFromMilestones" :date-from-milestones="store.startDateTimeFromMilestones"
:date-from-milestones-tooltip="getDateFromMilestonesTooltip('start')" :date-from-milestones-tooltip="getDateFromMilestonesTooltip('start')"
:show-toggle-sidebar="!isUserSignedIn" :show-toggle-sidebar="!isUserSignedIn"
...@@ -456,6 +465,7 @@ export default { ...@@ -456,6 +465,7 @@ export default {
:editable="editable" :editable="editable"
:selected-date-is-fixed="store.dueDateIsFixed" :selected-date-is-fixed="store.dueDateIsFixed"
:selected-date="store.endDateTime" :selected-date="store.endDateTime"
:date-fixed="store.dueDateTimeFixed"
:date-from-milestones="store.dueDateTimeFromMilestones" :date-from-milestones="store.dueDateTimeFromMilestones"
:date-from-milestones-tooltip="getDateFromMilestonesTooltip('due')" :date-from-milestones-tooltip="getDateFromMilestonesTooltip('due')"
:date-picker-label="__('Fixed finish date')" :date-picker-label="__('Fixed finish date')"
......
...@@ -69,6 +69,11 @@ export default { ...@@ -69,6 +69,11 @@ export default {
required: false, required: false,
default: null, default: null,
}, },
dateFixed: {
type: Date,
required: false,
default: null,
},
dateFromMilestonesTooltip: { dateFromMilestonesTooltip: {
type: String, type: String,
required: false, required: false,
...@@ -98,6 +103,9 @@ export default { ...@@ -98,6 +103,9 @@ export default {
selectedDateWords() { selectedDateWords() {
return dateInWords(this.selectedDate, true); return dateInWords(this.selectedDate, true);
}, },
dateFixedWords() {
return dateInWords(this.dateFixed, true);
},
dateFromMilestonesWords() { dateFromMilestonesWords() {
return this.dateFromMilestones ? dateInWords(this.dateFromMilestones, true) : __('None'); return this.dateFromMilestones ? dateInWords(this.dateFromMilestones, true) : __('None');
}, },
...@@ -207,7 +215,7 @@ export default { ...@@ -207,7 +215,7 @@ export default {
>{{ __('Fixed:') }}</span> >{{ __('Fixed:') }}</span>
<date-picker <date-picker
v-if="editing" v-if="editing"
:selected-date="selectedDate" :selected-date="dateFixed"
:label="datePickerLabel" :label="datePickerLabel"
@newDateSelected="newDateSelected" @newDateSelected="newDateSelected"
@hidePicker="stopEditing" @hidePicker="stopEditing"
...@@ -216,8 +224,8 @@ export default { ...@@ -216,8 +224,8 @@ export default {
v-else v-else
class="d-flex value-content" class="d-flex value-content"
> >
<template v-if="selectedDate"> <template v-if="dateFixed">
<span>{{ selectedDateWords }}</span> <span>{{ dateFixedWords }}</span>
<icon <icon
v-popover="dateInvalidPopoverOptions" v-popover="dateInvalidPopoverOptions"
v-if="isDateInvalid && selectedDateIsFixed" v-if="isDateInvalid && selectedDateIsFixed"
......
...@@ -3,9 +3,11 @@ import { parsePikadayDate } from '~/lib/utils/datefix'; ...@@ -3,9 +3,11 @@ import { parsePikadayDate } from '~/lib/utils/datefix';
export default class SidebarStore { export default class SidebarStore {
constructor({ constructor({
startDateIsFixed, startDateIsFixed,
startDateFixed,
startDateFromMilestones, startDateFromMilestones,
startDate, startDate,
dueDateIsFixed, dueDateIsFixed,
dueDateFixed,
dueDateFromMilestones, dueDateFromMilestones,
endDate, endDate,
subscribed, subscribed,
...@@ -13,8 +15,10 @@ export default class SidebarStore { ...@@ -13,8 +15,10 @@ export default class SidebarStore {
todoDeletePath, todoDeletePath,
}) { }) {
this.startDateIsFixed = startDateIsFixed; this.startDateIsFixed = startDateIsFixed;
this.startDateFixed = startDateFixed;
this.startDateFromMilestones = startDateFromMilestones; this.startDateFromMilestones = startDateFromMilestones;
this.startDate = startDate; this.startDate = startDate;
this.dueDateFixed = dueDateFixed;
this.dueDateIsFixed = dueDateIsFixed; this.dueDateIsFixed = dueDateIsFixed;
this.dueDateFromMilestones = dueDateFromMilestones; this.dueDateFromMilestones = dueDateFromMilestones;
this.endDate = endDate; this.endDate = endDate;
...@@ -27,6 +31,10 @@ export default class SidebarStore { ...@@ -27,6 +31,10 @@ export default class SidebarStore {
return this.startDate ? parsePikadayDate(this.startDate) : null; return this.startDate ? parsePikadayDate(this.startDate) : null;
} }
get startDateTimeFixed() {
return this.startDateFixed ? parsePikadayDate(this.startDateFixed) : null;
}
get startDateTimeFromMilestones() { get startDateTimeFromMilestones() {
return this.startDateFromMilestones ? parsePikadayDate(this.startDateFromMilestones) : null; return this.startDateFromMilestones ? parsePikadayDate(this.startDateFromMilestones) : null;
} }
...@@ -35,6 +43,10 @@ export default class SidebarStore { ...@@ -35,6 +43,10 @@ export default class SidebarStore {
return this.endDate ? parsePikadayDate(this.endDate) : null; return this.endDate ? parsePikadayDate(this.endDate) : null;
} }
get dueDateTimeFixed() {
return this.dueDateFixed ? parsePikadayDate(this.dueDateFixed) : null;
}
get dueDateTimeFromMilestones() { get dueDateTimeFromMilestones() {
return this.dueDateFromMilestones ? parsePikadayDate(this.dueDateFromMilestones) : null; return this.dueDateFromMilestones ? parsePikadayDate(this.dueDateFromMilestones) : null;
} }
......
---
title: Handle fixed dates seperately from selected dates in Epics
merge_request: 7227
author:
type: fixed
...@@ -85,6 +85,7 @@ export const mockDatePickerProps = { ...@@ -85,6 +85,7 @@ export const mockDatePickerProps = {
selectedDate: null, selectedDate: null,
selectedDateIsFixed: true, selectedDateIsFixed: true,
dateFromMilestones: null, dateFromMilestones: null,
dateFixed: null,
dateFromMilestonesTooltip: 'Select an issue with milestone to set date', dateFromMilestonesTooltip: 'Select an issue with milestone to set date',
isDateInvalid: false, isDateInvalid: false,
dateInvalidTooltip: 'Selected date is invalid', dateInvalidTooltip: 'Selected date is invalid',
......
...@@ -81,9 +81,13 @@ describe('epicSidebar', () => { ...@@ -81,9 +81,13 @@ describe('epicSidebar', () => {
}); });
it('should render both sidebar-date-picker', () => { it('should render both sidebar-date-picker', () => {
const startDate = '2017-01-01';
const endDate = '2018-01-01';
vm = mountComponent(EpicSidebar, Object.assign({}, defaultPropsData, { vm = mountComponent(EpicSidebar, Object.assign({}, defaultPropsData, {
initialStartDate: '2017-01-01', initialStartDate: startDate,
initialEndDate: '2018-01-01', initialStartDateFixed: startDate,
initialEndDate: endDate,
initialDueDateFixed: endDate,
})); }));
const startDatePicker = vm.$el.querySelector('.block.start-date'); const startDatePicker = vm.$el.querySelector('.block.start-date');
...@@ -219,7 +223,7 @@ describe('epicSidebar', () => { ...@@ -219,7 +223,7 @@ describe('epicSidebar', () => {
.catch(done.fail); .catch(done.fail);
}); });
it('should change start date type', (done) => { it('should change start date type as from milestones', (done) => {
spyOn(component.service, 'updateStartDate').and.callThrough(); spyOn(component.service, 'updateStartDate').and.callThrough();
const dateValue = '2017-01-01'; const dateValue = '2017-01-01';
component.saveDate('start', dateValue, false); component.saveDate('start', dateValue, false);
...@@ -234,7 +238,23 @@ describe('epicSidebar', () => { ...@@ -234,7 +238,23 @@ describe('epicSidebar', () => {
.catch(done.fail); .catch(done.fail);
}); });
it('should change end date type', (done) => { it('should change start date type as fixed', (done) => {
spyOn(component.service, 'updateStartDate').and.callThrough();
const dateValue = '2017-04-01';
component.saveDate('start', dateValue, true);
// Using setTimeout instead of Vue.nextTick
// as otherwise store updates are not reflected correctly
setTimeout(() => {
expect(component.service.updateStartDate).toHaveBeenCalledWith({
dateValue,
isFixed: true,
});
expect(component.store.startDateFixed).toBe(dateValue);
done();
}, 0);
});
it('should change end date type as from milestones', (done) => {
spyOn(component.service, 'updateEndDate').and.callThrough(); spyOn(component.service, 'updateEndDate').and.callThrough();
const dateValue = '2017-01-01'; const dateValue = '2017-01-01';
component.saveDate('end', dateValue, false); component.saveDate('end', dateValue, false);
...@@ -248,6 +268,22 @@ describe('epicSidebar', () => { ...@@ -248,6 +268,22 @@ describe('epicSidebar', () => {
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
}); });
it('should change end date type as fixed', (done) => {
spyOn(component.service, 'updateEndDate').and.callThrough();
const dateValue = '2017-04-01';
component.saveDate('end', dateValue, true);
// Using setTimeout instead of Vue.nextTick
// as otherwise store updates are not reflected correctly
setTimeout(() => {
expect(component.service.updateEndDate).toHaveBeenCalledWith({
dateValue,
isFixed: true,
});
expect(component.store.dueDateFixed).toBe(dateValue);
done();
}, 0);
});
}); });
describe('handleLabelClick', () => { describe('handleLabelClick', () => {
......
...@@ -52,6 +52,18 @@ describe('SidebarParticipants', () => { ...@@ -52,6 +52,18 @@ describe('SidebarParticipants', () => {
}); });
}); });
describe('dateFixedWords', () => {
it('returns full date string in words based on `dateFixed` prop value', done => {
vm.dateFixed = new Date(2018, 0, 1);
Vue.nextTick()
.then(() => {
expect(vm.dateFixedWords).toBe('Jan 1, 2018');
})
.then(done)
.catch(done.fail);
});
});
describe('dateFromMilestonesWords', () => { describe('dateFromMilestonesWords', () => {
it('returns full date string in words when `dateFromMilestones` is defined', done => { it('returns full date string in words when `dateFromMilestones` is defined', done => {
vm.dateFromMilestones = new Date(2018, 0, 1); vm.dateFromMilestones = new Date(2018, 0, 1);
......
...@@ -37,6 +37,24 @@ describe('Sidebar Store', () => { ...@@ -37,6 +37,24 @@ describe('Sidebar Store', () => {
}); });
}); });
describe('startDateTimeFixed', () => {
it('should return null when there is no startDateFixed', () => {
const store = new SidebarStore({});
expect(store.startDateTimeFixed).toEqual(null);
});
it('should return date', () => {
const store = new SidebarStore({
startDateFixed: dateString,
});
const date = store.startDateTimeFixed;
expect(date.getDate()).toEqual(20);
expect(date.getMonth()).toEqual(0);
expect(date.getFullYear()).toEqual(2017);
});
});
describe('endDateTime', () => { describe('endDateTime', () => {
it('should return null when there is no endDate', () => { it('should return null when there is no endDate', () => {
const store = new SidebarStore({}); const store = new SidebarStore({});
...@@ -55,6 +73,24 @@ describe('Sidebar Store', () => { ...@@ -55,6 +73,24 @@ describe('Sidebar Store', () => {
}); });
}); });
describe('dueDateTimeFixed', () => {
it('should return null when there is no dueDateFixed', () => {
const store = new SidebarStore({});
expect(store.dueDateTimeFixed).toEqual(null);
});
it('should return date', () => {
const store = new SidebarStore({
dueDateFixed: dateString,
});
const date = store.dueDateTimeFixed;
expect(date.getDate()).toEqual(20);
expect(date.getMonth()).toEqual(0);
expect(date.getFullYear()).toEqual(2017);
});
});
describe('setSubscribed', () => { describe('setSubscribed', () => {
it('should set store.subscribed value', () => { it('should set store.subscribed value', () => {
const store = new SidebarStore({ subscribed: true }); const store = new SidebarStore({ subscribed: true });
......
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