Commit 41ebeaa7 authored by David O'Regan's avatar David O'Regan

Merge branch '322938-weekly-start-date-grid' into 'master'

Feat: Update schedule grid to start at beginning of current week

See merge request gitlab-org/gitlab!57004
parents 386687c9 eb571eb2
...@@ -3,6 +3,7 @@ import { GlCard, GlButtonGroup, GlButton, GlModalDirective, GlTooltipDirective } ...@@ -3,6 +3,7 @@ import { GlCard, GlButtonGroup, GlButton, GlModalDirective, GlTooltipDirective }
import * as Sentry from '@sentry/browser'; import * as Sentry from '@sentry/browser';
import { capitalize } from 'lodash'; import { capitalize } from 'lodash';
import { import {
getStartOfWeek,
formatDate, formatDate,
nWeeksBefore, nWeeksBefore,
nWeeksAfter, nWeeksAfter,
...@@ -87,7 +88,7 @@ export default { ...@@ -87,7 +88,7 @@ export default {
data() { data() {
return { return {
presetType: this.$options.PRESET_TYPES.WEEKS, presetType: this.$options.PRESET_TYPES.WEEKS,
timeframeStartDate: new Date(), timeframeStartDate: getStartOfWeek(new Date()),
rotations: this.schedule.rotations.nodes, rotations: this.schedule.rotations.nodes,
rotationToUpdate: {}, rotationToUpdate: {},
}; };
...@@ -133,7 +134,8 @@ export default { ...@@ -133,7 +134,8 @@ export default {
methods: { methods: {
switchPresetType(type) { switchPresetType(type) {
this.presetType = type; this.presetType = type;
this.timeframeStartDate = new Date(); this.timeframeStartDate =
type === PRESET_TYPES.WEEKS ? getStartOfWeek(new Date()) : new Date();
}, },
formatPresetType(type) { formatPresetType(type) {
return capitalize(type); return capitalize(type);
......
...@@ -32,7 +32,7 @@ export default { ...@@ -32,7 +32,7 @@ export default {
<template> <template>
<span <span
v-if="isVisible" v-if="isVisible"
:style="getIndicatorStyles(presetType)" :style="getIndicatorStyles(presetType, timeframeItem)"
data-testid="current-day-indicator" data-testid="current-day-indicator"
class="current-day-indicator" class="current-day-indicator"
></span> ></span>
......
...@@ -48,7 +48,7 @@ export default { ...@@ -48,7 +48,7 @@ export default {
currentDateTime >= this.timeframeItem.getTime() && currentDateTime >= this.timeframeItem.getTime() &&
currentDateTime <= lastDayOfCurrentWeekTime currentDateTime <= lastDayOfCurrentWeekTime
) { ) {
return 'label-dark label-bold'; return 'label-bold';
} }
return ''; return '';
...@@ -66,7 +66,7 @@ export default { ...@@ -66,7 +66,7 @@ export default {
<span class="timeline-header-item" :style="timelineHeaderStyles"> <span class="timeline-header-item" :style="timelineHeaderStyles">
<div <div
:class="timelineHeaderClass" :class="timelineHeaderClass"
class="item-label gl-pl-6 gl-py-4" class="item-label label-dark gl-pl-5 gl-py-4"
data-testid="timeline-header-label" data-testid="timeline-header-label"
> >
{{ timelineHeaderLabel }} {{ timelineHeaderLabel }}
......
...@@ -78,7 +78,7 @@ export default { ...@@ -78,7 +78,7 @@ export default {
> >
<span <span
v-if="hasToday" v-if="hasToday"
:style="getIndicatorStyles($options.PRESET_TYPES.WEEKS)" :style="getIndicatorStyles($options.PRESET_TYPES.WEEKS, timeframeItem)"
class="current-day-indicator-header preset-weeks" class="current-day-indicator-header preset-weeks"
></span> ></span>
</div> </div>
......
...@@ -44,3 +44,7 @@ export const ASSIGNEE_SPACER_SMALL = 1; ...@@ -44,3 +44,7 @@ export const ASSIGNEE_SPACER_SMALL = 1;
export const TIMELINE_CELL_WIDTH = 180; export const TIMELINE_CELL_WIDTH = 180;
export const SHIFT_WIDTH_CALCULATION_DELAY = 250; export const SHIFT_WIDTH_CALCULATION_DELAY = 250;
export const CURRENT_DAY_INDICATOR_OFFSET = 2.25; export const CURRENT_DAY_INDICATOR_OFFSET = 2.25;
export const oneHourOffsetDayView = 100 / HOURS_IN_DAY;
export const oneDayOffsetWeekView = 100 / DAYS_IN_WEEK;
export const oneHourOffsetWeekView = oneDayOffsetWeekView / HOURS_IN_DAY;
import { isToday } from '~/lib/utils/datetime_utility'; import { getDayDifference, isToday } from '~/lib/utils/datetime_utility';
import { import {
DAYS_IN_WEEK,
HOURS_IN_DAY,
PRESET_TYPES, PRESET_TYPES,
CURRENT_DAY_INDICATOR_OFFSET, oneHourOffsetDayView,
oneDayOffsetWeekView,
oneHourOffsetWeekView,
} from '../constants'; } from '../constants';
export default { export default {
...@@ -38,23 +38,30 @@ export default { ...@@ -38,23 +38,30 @@ export default {
this.$options.currentDate = currentDate; this.$options.currentDate = currentDate;
}, },
methods: { methods: {
getIndicatorStyles(presetType = PRESET_TYPES.WEEKS) { getIndicatorStyles(presetType = PRESET_TYPES.WEEKS, timeframeStartDate = new Date()) {
const currentDate = new Date();
const base = 100 / HOURS_IN_DAY;
const hours = base * currentDate.getHours();
if (presetType === PRESET_TYPES.DAYS) { if (presetType === PRESET_TYPES.DAYS) {
const minutes = base * (currentDate.getMinutes() / 60) - CURRENT_DAY_INDICATOR_OFFSET; return this.getDayViewIndicatorStyles();
}
return this.getWeekViewIndicatorStyles(timeframeStartDate);
},
getDayViewIndicatorStyles() {
const currentDate = new Date();
const hours = oneHourOffsetDayView * currentDate.getHours();
const minutes = oneHourOffsetDayView * (currentDate.getMinutes() / 60);
return { return {
left: `${hours + minutes}%`, left: `${hours + minutes}%`,
}; };
} },
getWeekViewIndicatorStyles(timeframeStartDate) {
const currentDate = new Date();
const hourOffset = oneHourOffsetWeekView * currentDate.getHours();
const daysSinceShiftStart = getDayDifference(timeframeStartDate, currentDate);
const leftOffset = oneDayOffsetWeekView * daysSinceShiftStart + hourOffset;
const weeklyDayOffset = 100 / DAYS_IN_WEEK / 2;
const weeklyHourOffset = (weeklyDayOffset / HOURS_IN_DAY) * currentDate.getHours();
return { return {
left: `${weeklyDayOffset + weeklyHourOffset}%`, left: `${Math.round(leftOffset)}%`,
}; };
}, },
}, },
......
---
title: Update schedule grid to start at beginning of current week
merge_request: 57004
author:
type: added
...@@ -74,7 +74,7 @@ exports[`RotationsListSectionComponent when the timeframe includes today renders ...@@ -74,7 +74,7 @@ exports[`RotationsListSectionComponent when the timeframe includes today renders
<span <span
class="current-day-indicator" class="current-day-indicator"
data-testid="current-day-indicator" data-testid="current-day-indicator"
style="left: 7.142857142857143%;" style="left: 29%;"
/> />
<div> <div>
......
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import CurrentDayIndicator from 'ee/oncall_schedules/components/schedule/components/current_day_indicator.vue'; import CurrentDayIndicator from 'ee/oncall_schedules/components/schedule/components/current_day_indicator.vue';
import { PRESET_TYPES, DAYS_IN_WEEK, HOURS_IN_DAY } from 'ee/oncall_schedules/constants'; import { PRESET_TYPES, HOURS_IN_DAY } from 'ee/oncall_schedules/constants';
import { useFakeDate } from 'helpers/fake_date'; import { useFakeDate } from 'helpers/fake_date';
describe('CurrentDayIndicator', () => { describe('CurrentDayIndicator', () => {
...@@ -10,7 +10,8 @@ describe('CurrentDayIndicator', () => { ...@@ -10,7 +10,8 @@ describe('CurrentDayIndicator', () => {
// January 1st, 2018 is the first day of the week-long timeframe // January 1st, 2018 is the first day of the week-long timeframe
// so as long as current date (faked January 3rd, 2018) is within week timeframe // so as long as current date (faked January 3rd, 2018) is within week timeframe
// current indicator will be rendered // current indicator will be rendered
const mockTimeframeInitialDate = new Date(2018, 0, 1); const mockTimeframeInitialDate = new Date(2018, 0, 1); // Monday
const mockCurrentDate = new Date(2018, 0, 3); // Wednesday
function createComponent({ function createComponent({
props = { presetType: PRESET_TYPES.WEEKS, timeframeItem: mockTimeframeInitialDate }, props = { presetType: PRESET_TYPES.WEEKS, timeframeItem: mockTimeframeInitialDate },
...@@ -36,19 +37,26 @@ describe('CurrentDayIndicator', () => { ...@@ -36,19 +37,26 @@ describe('CurrentDayIndicator', () => {
expect(wrapper.classes('current-day-indicator')).toBe(true); expect(wrapper.classes('current-day-indicator')).toBe(true);
}); });
it('sets correct styles for a week', async () => { it('sets correct styles for a week that on a different day than the timeframe start date', () => {
const left = 100 / DAYS_IN_WEEK / 2; /**
expect(wrapper.attributes('style')).toBe(`left: ${left}%;`); * Our start date for the timeframe in this spec is a Monday,
* and the current day is the following Wednesday.
* This creates a gap of two days so our generated offset should represent:
* DayDiffOffset + weeklyOffset + weeklyHourOffset
* 29 + 0
*/
const leftOffset = '29';
expect(wrapper.attributes('style')).toBe(`left: ${leftOffset}%;`);
}); });
it('sets correct styles for a day', async () => { it('sets correct styles for a day', () => {
createComponent({ createComponent({
props: { presetType: PRESET_TYPES.DAYS, timeframeItem: new Date(2018, 0, 3) }, props: { presetType: PRESET_TYPES.DAYS, timeframeItem: mockCurrentDate },
}); });
const currentDate = new Date(); const currentDate = new Date();
const base = 100 / HOURS_IN_DAY; const base = 100 / HOURS_IN_DAY;
const hours = base * currentDate.getHours(); const hours = base * currentDate.getHours();
const minutes = base * (currentDate.getMinutes() / 60) - 2.25; const minutes = base * (currentDate.getMinutes() / 60);
const left = hours + minutes; const left = hours + minutes;
expect(wrapper.attributes('style')).toBe(`left: ${left}%;`); expect(wrapper.attributes('style')).toBe(`left: ${left}%;`);
}); });
......
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { DAYS_IN_WEEK, HOURS_IN_DAY, PRESET_TYPES } from 'ee/oncall_schedules/constants'; import {
PRESET_TYPES,
oneHourOffsetDayView,
oneDayOffsetWeekView,
oneHourOffsetWeekView,
} from 'ee/oncall_schedules/constants';
import CommonMixin from 'ee/oncall_schedules/mixins/common_mixin'; import CommonMixin from 'ee/oncall_schedules/mixins/common_mixin';
import { useFakeDate } from 'helpers/fake_date'; import { useFakeDate } from 'helpers/fake_date';
import * as dateTimeUtility from '~/lib/utils/datetime_utility'; import * as dateTimeUtility from '~/lib/utils/datetime_utility';
...@@ -81,20 +86,26 @@ describe('Schedule Common Mixins', () => { ...@@ -81,20 +86,26 @@ describe('Schedule Common Mixins', () => {
}); });
describe('getIndicatorStyles', () => { describe('getIndicatorStyles', () => {
it('returns object containing `left` offset', () => { it('returns object containing `left` offset for the weekly grid', () => {
const left = 100 / DAYS_IN_WEEK / 2; const mockTimeframeInitialDate = new Date(2018, 0, 1);
expect(wrapper.vm.getIndicatorStyles()).toEqual( const mockCurrentDate = new Date(2018, 0, 3);
const hourOffset = oneHourOffsetWeekView * mockCurrentDate.getHours();
const daysSinceShiftStart = dateTimeUtility.getDayDifference(
mockTimeframeInitialDate,
mockCurrentDate,
);
const leftOffset = oneDayOffsetWeekView * daysSinceShiftStart + hourOffset;
expect(wrapper.vm.getIndicatorStyles(PRESET_TYPES.WEEKS, mockTimeframeInitialDate)).toEqual(
expect.objectContaining({ expect.objectContaining({
left: `${left}%`, left: `${Math.round(leftOffset)}%`,
}), }),
); );
}); });
it('returns object containing `left` offset for a single day grid', () => { it('returns object containing `left` offset for a single day grid', () => {
const currentDate = new Date(2018, 0, 8); const currentDate = new Date(2018, 0, 8);
const base = 100 / HOURS_IN_DAY; const hours = oneHourOffsetDayView * currentDate.getHours();
const hours = base * currentDate.getHours(); const minutes = oneHourOffsetDayView * (currentDate.getMinutes() / 60);
const minutes = base * (currentDate.getMinutes() / 60) - 2.25;
expect(wrapper.vm.getIndicatorStyles(PRESET_TYPES.DAYS)).toEqual( expect(wrapper.vm.getIndicatorStyles(PRESET_TYPES.DAYS)).toEqual(
expect.objectContaining({ expect.objectContaining({
......
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