Commit eb571eb2 authored by David O'Regan's avatar David O'Regan

Feat: Update schedule grid for current day in week

Update the schedule grid to allow
the grid to begin at the first day
of the current week but still track
the current day via the current
day indecator
parent a138ca53
......@@ -3,6 +3,7 @@ import { GlCard, GlButtonGroup, GlButton, GlModalDirective, GlTooltipDirective }
import * as Sentry from '@sentry/browser';
import { capitalize } from 'lodash';
import {
getStartOfWeek,
formatDate,
nWeeksBefore,
nWeeksAfter,
......@@ -87,7 +88,7 @@ export default {
data() {
return {
presetType: this.$options.PRESET_TYPES.WEEKS,
timeframeStartDate: new Date(),
timeframeStartDate: getStartOfWeek(new Date()),
rotations: this.schedule.rotations.nodes,
rotationToUpdate: {},
};
......@@ -127,7 +128,8 @@ export default {
methods: {
switchPresetType(type) {
this.presetType = type;
this.timeframeStartDate = new Date();
this.timeframeStartDate =
type === PRESET_TYPES.WEEKS ? getStartOfWeek(new Date()) : new Date();
},
formatPresetType(type) {
return capitalize(type);
......
......@@ -32,7 +32,7 @@ export default {
<template>
<span
v-if="isVisible"
:style="getIndicatorStyles(presetType)"
:style="getIndicatorStyles(presetType, timeframeItem)"
data-testid="current-day-indicator"
class="current-day-indicator"
></span>
......
......@@ -48,7 +48,7 @@ export default {
currentDateTime >= this.timeframeItem.getTime() &&
currentDateTime <= lastDayOfCurrentWeekTime
) {
return 'label-dark label-bold';
return 'label-bold';
}
return '';
......@@ -66,7 +66,7 @@ export default {
<span class="timeline-header-item" :style="timelineHeaderStyles">
<div
: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"
>
{{ timelineHeaderLabel }}
......
......@@ -78,7 +78,7 @@ export default {
>
<span
v-if="hasToday"
:style="getIndicatorStyles($options.PRESET_TYPES.WEEKS)"
:style="getIndicatorStyles($options.PRESET_TYPES.WEEKS, timeframeItem)"
class="current-day-indicator-header preset-weeks"
></span>
</div>
......
......@@ -44,3 +44,7 @@ export const ASSIGNEE_SPACER_SMALL = 1;
export const TIMELINE_CELL_WIDTH = 180;
export const SHIFT_WIDTH_CALCULATION_DELAY = 250;
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 {
DAYS_IN_WEEK,
HOURS_IN_DAY,
PRESET_TYPES,
CURRENT_DAY_INDICATOR_OFFSET,
oneHourOffsetDayView,
oneDayOffsetWeekView,
oneHourOffsetWeekView,
} from '../constants';
export default {
......@@ -38,23 +38,30 @@ export default {
this.$options.currentDate = currentDate;
},
methods: {
getIndicatorStyles(presetType = PRESET_TYPES.WEEKS) {
const currentDate = new Date();
const base = 100 / HOURS_IN_DAY;
const hours = base * currentDate.getHours();
getIndicatorStyles(presetType = PRESET_TYPES.WEEKS, timeframeStartDate = new Date()) {
if (presetType === PRESET_TYPES.DAYS) {
const minutes = base * (currentDate.getMinutes() / 60) - CURRENT_DAY_INDICATOR_OFFSET;
return {
left: `${hours + minutes}%`,
};
return this.getDayViewIndicatorStyles();
}
const weeklyDayOffset = 100 / DAYS_IN_WEEK / 2;
const weeklyHourOffset = (weeklyDayOffset / HOURS_IN_DAY) * currentDate.getHours();
return this.getWeekViewIndicatorStyles(timeframeStartDate);
},
getDayViewIndicatorStyles() {
const currentDate = new Date();
const hours = oneHourOffsetDayView * currentDate.getHours();
const minutes = oneHourOffsetDayView * (currentDate.getMinutes() / 60);
return {
left: `${hours + minutes}%`,
};
},
getWeekViewIndicatorStyles(timeframeStartDate) {
const currentDate = new Date();
const hourOffset = oneHourOffsetWeekView * currentDate.getHours();
const daysSinceShiftStart = getDayDifference(timeframeStartDate, currentDate);
const leftOffset = oneDayOffsetWeekView * daysSinceShiftStart + hourOffset;
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
<span
class="current-day-indicator"
data-testid="current-day-indicator"
style="left: 7.142857142857143%;"
style="left: 29%;"
/>
<div>
......
import { shallowMount } from '@vue/test-utils';
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';
describe('CurrentDayIndicator', () => {
......@@ -10,7 +10,8 @@ describe('CurrentDayIndicator', () => {
// 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
// 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({
props = { presetType: PRESET_TYPES.WEEKS, timeframeItem: mockTimeframeInitialDate },
......@@ -36,19 +37,26 @@ describe('CurrentDayIndicator', () => {
expect(wrapper.classes('current-day-indicator')).toBe(true);
});
it('sets correct styles for a week', async () => {
const left = 100 / DAYS_IN_WEEK / 2;
expect(wrapper.attributes('style')).toBe(`left: ${left}%;`);
it('sets correct styles for a week that on a different day than the timeframe start date', () => {
/**
* 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({
props: { presetType: PRESET_TYPES.DAYS, timeframeItem: new Date(2018, 0, 3) },
props: { presetType: PRESET_TYPES.DAYS, timeframeItem: mockCurrentDate },
});
const currentDate = new Date();
const base = 100 / HOURS_IN_DAY;
const hours = base * currentDate.getHours();
const minutes = base * (currentDate.getMinutes() / 60) - 2.25;
const minutes = base * (currentDate.getMinutes() / 60);
const left = hours + minutes;
expect(wrapper.attributes('style')).toBe(`left: ${left}%;`);
});
......
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 { useFakeDate } from 'helpers/fake_date';
import * as dateTimeUtility from '~/lib/utils/datetime_utility';
......@@ -81,20 +86,26 @@ describe('Schedule Common Mixins', () => {
});
describe('getIndicatorStyles', () => {
it('returns object containing `left` offset', () => {
const left = 100 / DAYS_IN_WEEK / 2;
expect(wrapper.vm.getIndicatorStyles()).toEqual(
it('returns object containing `left` offset for the weekly grid', () => {
const mockTimeframeInitialDate = new Date(2018, 0, 1);
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({
left: `${left}%`,
left: `${Math.round(leftOffset)}%`,
}),
);
});
it('returns object containing `left` offset for a single day grid', () => {
const currentDate = new Date(2018, 0, 8);
const base = 100 / HOURS_IN_DAY;
const hours = base * currentDate.getHours();
const minutes = base * (currentDate.getMinutes() / 60) - 2.25;
const hours = oneHourOffsetDayView * currentDate.getHours();
const minutes = oneHourOffsetDayView * (currentDate.getMinutes() / 60);
expect(wrapper.vm.getIndicatorStyles(PRESET_TYPES.DAYS)).toEqual(
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