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 {
const store = new Store({
startDateIsFixed: this.initialStartDateIsFixed,
startDateFromMilestones: this.startDateFromMilestones,
startDateFixed: this.initialStartDateFixed,
startDate: this.initialStartDate,
dueDateIsFixed: this.initialDueDateIsFixed,
dueDateFromMilestones: this.dueDateFromMilestones,
dueDateFixed: this.initialDueDateFixed,
endDate: this.initialEndDate,
subscribed: this.initialSubscribed,
todoExists: this.initialTodoExists,
......@@ -275,6 +277,12 @@ export default {
.then(() => {
this[savingBoolean] = false;
this.store[`${type}Date`] = newDate;
if (isFixed) {
// Update fixed date in store
const fixedDate = dateType === DateTypes.start ? 'startDateFixed' : 'dueDateFixed';
this.store[fixedDate] = newDate;
}
})
.catch(() => {
this[savingBoolean] = false;
......@@ -288,7 +296,7 @@ export default {
if (!typeChangeOnEdit) {
this.saveDate(
DateTypes.start,
dateTypeIsFixed ? this.store.startDate : this.store.startDateFromMilestones,
dateTypeIsFixed ? this.store.startDateFixed : this.store.startDateFromMilestones,
dateTypeIsFixed,
);
}
......@@ -301,7 +309,7 @@ export default {
if (!typeChangeOnEdit) {
this.saveDate(
DateTypes.end,
dateTypeIsFixed ? this.store.endDate : this.store.dueDateFromMilestones,
dateTypeIsFixed ? this.store.dueDateFixed : this.store.dueDateFromMilestones,
dateTypeIsFixed,
);
}
......@@ -437,6 +445,7 @@ export default {
:editable="editable"
:selected-date-is-fixed="store.startDateIsFixed"
:selected-date="store.startDateTime"
:date-fixed="store.startDateTimeFixed"
:date-from-milestones="store.startDateTimeFromMilestones"
:date-from-milestones-tooltip="getDateFromMilestonesTooltip('start')"
:show-toggle-sidebar="!isUserSignedIn"
......@@ -456,6 +465,7 @@ export default {
:editable="editable"
:selected-date-is-fixed="store.dueDateIsFixed"
:selected-date="store.endDateTime"
:date-fixed="store.dueDateTimeFixed"
:date-from-milestones="store.dueDateTimeFromMilestones"
:date-from-milestones-tooltip="getDateFromMilestonesTooltip('due')"
:date-picker-label="__('Fixed finish date')"
......
......@@ -69,6 +69,11 @@ export default {
required: false,
default: null,
},
dateFixed: {
type: Date,
required: false,
default: null,
},
dateFromMilestonesTooltip: {
type: String,
required: false,
......@@ -98,6 +103,9 @@ export default {
selectedDateWords() {
return dateInWords(this.selectedDate, true);
},
dateFixedWords() {
return dateInWords(this.dateFixed, true);
},
dateFromMilestonesWords() {
return this.dateFromMilestones ? dateInWords(this.dateFromMilestones, true) : __('None');
},
......@@ -207,7 +215,7 @@ export default {
>{{ __('Fixed:') }}</span>
<date-picker
v-if="editing"
:selected-date="selectedDate"
:selected-date="dateFixed"
:label="datePickerLabel"
@newDateSelected="newDateSelected"
@hidePicker="stopEditing"
......@@ -216,8 +224,8 @@ export default {
v-else
class="d-flex value-content"
>
<template v-if="selectedDate">
<span>{{ selectedDateWords }}</span>
<template v-if="dateFixed">
<span>{{ dateFixedWords }}</span>
<icon
v-popover="dateInvalidPopoverOptions"
v-if="isDateInvalid && selectedDateIsFixed"
......
......@@ -3,9 +3,11 @@ import { parsePikadayDate } from '~/lib/utils/datefix';
export default class SidebarStore {
constructor({
startDateIsFixed,
startDateFixed,
startDateFromMilestones,
startDate,
dueDateIsFixed,
dueDateFixed,
dueDateFromMilestones,
endDate,
subscribed,
......@@ -13,8 +15,10 @@ export default class SidebarStore {
todoDeletePath,
}) {
this.startDateIsFixed = startDateIsFixed;
this.startDateFixed = startDateFixed;
this.startDateFromMilestones = startDateFromMilestones;
this.startDate = startDate;
this.dueDateFixed = dueDateFixed;
this.dueDateIsFixed = dueDateIsFixed;
this.dueDateFromMilestones = dueDateFromMilestones;
this.endDate = endDate;
......@@ -27,6 +31,10 @@ export default class SidebarStore {
return this.startDate ? parsePikadayDate(this.startDate) : null;
}
get startDateTimeFixed() {
return this.startDateFixed ? parsePikadayDate(this.startDateFixed) : null;
}
get startDateTimeFromMilestones() {
return this.startDateFromMilestones ? parsePikadayDate(this.startDateFromMilestones) : null;
}
......@@ -35,6 +43,10 @@ export default class SidebarStore {
return this.endDate ? parsePikadayDate(this.endDate) : null;
}
get dueDateTimeFixed() {
return this.dueDateFixed ? parsePikadayDate(this.dueDateFixed) : null;
}
get dueDateTimeFromMilestones() {
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 = {
selectedDate: null,
selectedDateIsFixed: true,
dateFromMilestones: null,
dateFixed: null,
dateFromMilestonesTooltip: 'Select an issue with milestone to set date',
isDateInvalid: false,
dateInvalidTooltip: 'Selected date is invalid',
......
......@@ -81,9 +81,13 @@ describe('epicSidebar', () => {
});
it('should render both sidebar-date-picker', () => {
const startDate = '2017-01-01';
const endDate = '2018-01-01';
vm = mountComponent(EpicSidebar, Object.assign({}, defaultPropsData, {
initialStartDate: '2017-01-01',
initialEndDate: '2018-01-01',
initialStartDate: startDate,
initialStartDateFixed: startDate,
initialEndDate: endDate,
initialDueDateFixed: endDate,
}));
const startDatePicker = vm.$el.querySelector('.block.start-date');
......@@ -219,7 +223,7 @@ describe('epicSidebar', () => {
.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();
const dateValue = '2017-01-01';
component.saveDate('start', dateValue, false);
......@@ -234,7 +238,23 @@ describe('epicSidebar', () => {
.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();
const dateValue = '2017-01-01';
component.saveDate('end', dateValue, false);
......@@ -248,6 +268,22 @@ describe('epicSidebar', () => {
.then(done)
.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', () => {
......
......@@ -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', () => {
it('returns full date string in words when `dateFromMilestones` is defined', done => {
vm.dateFromMilestones = new Date(2018, 0, 1);
......
......@@ -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', () => {
it('should return null when there is no endDate', () => {
const store = new SidebarStore({});
......@@ -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', () => {
it('should set store.subscribed value', () => {
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