Commit 5b15305a authored by David O'Regan's avatar David O'Regan Committed by Natalia Tepluhina

Update rotation assignee timestamp

parent 72c5f09a
<script>
import {
GlSprintf,
GlCard,
GlButtonGroup,
GlButton,
GlModalDirective,
GlTooltipDirective,
} from '@gitlab/ui';
import { GlCard, GlButtonGroup, GlButton, GlModalDirective, GlTooltipDirective } from '@gitlab/ui';
import * as Sentry from '@sentry/browser';
import { capitalize } from 'lodash';
import {
......@@ -16,7 +9,7 @@ import {
nDaysBefore,
nDaysAfter,
} from '~/lib/utils/datetime_utility';
import { s__, __ } from '~/locale';
import { s__ } from '~/locale';
import { addRotationModalId, editRotationModalId, PRESET_TYPES } from '../constants';
import getShiftsForRotations from '../graphql/queries/get_oncall_schedules_with_rotations_shifts.query.graphql';
import EditScheduleModal from './add_edit_schedule_modal.vue';
......@@ -24,10 +17,9 @@ import DeleteScheduleModal from './delete_schedule_modal.vue';
import AddEditRotationModal from './rotations/components/add_edit_rotation_modal.vue';
import RotationsListSection from './schedule/components/rotations_list_section.vue';
import ScheduleTimelineSection from './schedule/components/schedule_timeline_section.vue';
import { getTimeframeForWeeksView } from './schedule/utils';
import { getTimeframeForWeeksView, selectedTimezoneFormattedOffset } from './schedule/utils';
export const i18n = {
scheduleForTz: s__('OnCallSchedules|On-call schedule for the %{timezone}'),
editScheduleLabel: s__('OnCallSchedules|Edit schedule'),
deleteScheduleLabel: s__('OnCallSchedules|Delete schedule'),
rotationTitle: s__('OnCallSchedules|Rotations'),
......@@ -51,7 +43,6 @@ export default {
GlButton,
GlButtonGroup,
GlCard,
GlSprintf,
AddEditRotationModal,
DeleteScheduleModal,
EditScheduleModal,
......@@ -63,6 +54,11 @@ export default {
GlTooltip: GlTooltipDirective,
},
inject: ['projectPath', 'timezones'],
provide() {
return {
selectedTimezone: this.selectedTimezone,
};
},
props: {
schedule: {
type: Object,
......@@ -73,7 +69,7 @@ export default {
rotations: {
query: getShiftsForRotations,
variables() {
this.timeframeStartDate.setHours(1, 0, 0, 0);
this.timeframeStartDate.setHours(0, 0, 0, 0);
const startsAt = this.timeframeStartDate;
const endsAt = nWeeksAfter(startsAt, 2);
......@@ -101,9 +97,11 @@ export default {
};
},
computed: {
selectedTimezone() {
return this.timezones.find((tz) => tz.identifier === this.schedule.timezone);
},
offset() {
const selectedTz = this.timezones.find((tz) => tz.identifier === this.schedule.timezone);
return __(`(UTC ${selectedTz.formatted_offset})`);
return selectedTimezoneFormattedOffset(this.selectedTimezone.formatted_offset);
},
timeframe() {
return getTimeframeForWeeksView(this.timeframeStartDate);
......@@ -197,10 +195,7 @@ export default {
</div>
</template>
<p class="gl-text-gray-500 gl-mb-3" data-testid="scheduleBody">
<gl-sprintf :message="$options.i18n.scheduleForTz">
<template #timezone>{{ schedule.timezone }}</template>
</gl-sprintf>
| {{ offset }}
{{ schedule.timezone }} | {{ offset }}
</p>
<div class="gl-display-flex gl-justify-content-space-between gl-mb-3">
<div class="gl-display-flex gl-align-items-center">
......
......@@ -4,6 +4,7 @@ import { uniqueId } from 'lodash';
import { formatDate } from '~/lib/utils/datetime_utility';
import { truncate } from '~/lib/utils/text_utility';
import { __, sprintf } from '~/locale';
import { selectedTimezoneFormattedOffset } from '../../schedule/utils';
export const SHIFT_WIDTHS = {
md: 140,
......@@ -12,6 +13,7 @@ export const SHIFT_WIDTHS = {
};
const ROTATION_CENTER_CLASS = 'gl-display-flex gl-justify-content-center gl-align-items-center';
export const TIME_DATE_FORMAT = 'mmmm d, yyyy, HH:MM';
export default {
ROTATION_CENTER_CLASS,
......@@ -19,6 +21,7 @@ export default {
GlAvatar,
GlPopover,
},
inject: ['selectedTimezone'],
props: {
assignee: {
type: Object,
......@@ -54,7 +57,9 @@ export default {
},
endsAt() {
return sprintf(__('Ends: %{endsAt}'), {
endsAt: formatDate(this.rotationAssigneeEndsAt, 'mmmm d, yyyy, h:MMtt Z'),
endsAt: `${formatDate(this.rotationAssigneeEndsAt, TIME_DATE_FORMAT)} ${
this.timezoneOffset
}`,
});
},
rotationAssigneeUniqueID() {
......@@ -65,9 +70,14 @@ export default {
},
startsAt() {
return sprintf(__('Starts: %{startsAt}'), {
startsAt: formatDate(this.rotationAssigneeStartsAt, 'mmmm d, yyyy, h:MMtt Z'),
startsAt: `${formatDate(this.rotationAssigneeStartsAt, TIME_DATE_FORMAT)} ${
this.timezoneOffset
}`,
});
},
timezoneOffset() {
return selectedTimezoneFormattedOffset(this.selectedTimezone.formatted_offset);
},
},
};
</script>
......@@ -93,8 +103,12 @@ export default {
triggers="hover"
placement="top"
>
<p class="gl-m-0" data-testid="rotation-assignee-starts-at">{{ startsAt }}</p>
<p class="gl-m-0" data-testid="rotation-assignee-ends-at">{{ endsAt }}</p>
<p class="gl-m-0" data-testid="rotation-assignee-starts-at">
{{ startsAt }}
</p>
<p class="gl-m-0" data-testid="rotation-assignee-ends-at">
{{ endsAt }}
</p>
</gl-popover>
</div>
</template>
......@@ -45,7 +45,7 @@ export default {
ref="dailyHourCell"
class="sublabel-value"
data-testid="sublabel-value"
>{{ hour }}</span
>{{ hour - 1 }}</span
>
<span
v-if="isToday"
......
......@@ -40,6 +40,11 @@ export default {
GlTooltip: GlTooltipDirective,
},
props: {
loading: {
type: Boolean,
required: false,
default: false,
},
presetType: {
type: String,
required: true,
......@@ -48,18 +53,13 @@ export default {
type: Array,
required: true,
},
timeframe: {
type: Array,
required: true,
},
scheduleIid: {
type: String,
required: true,
},
loading: {
type: Boolean,
required: false,
default: false,
timeframe: {
type: Array,
required: true,
},
},
data() {
......
......@@ -11,14 +11,6 @@ export default {
WeeksScheduleShift,
},
props: {
timeframeItem: {
type: [Date, Object],
required: true,
},
timeframe: {
type: Array,
required: true,
},
presetType: {
type: String,
required: true,
......@@ -27,6 +19,14 @@ export default {
type: Object,
required: true,
},
timeframeItem: {
type: [Date, Object],
required: true,
},
timeframe: {
type: Array,
required: true,
},
},
data() {
return {
......
import { newDate } from '~/lib/utils/datetime_utility';
import { __ } from '~/locale';
import { PRESET_DEFAULTS, DAYS_IN_WEEK } from '../../constants';
/**
......@@ -32,3 +33,18 @@ export const getTimeframeForWeeksView = (initialDate = new Date()) => {
return timeframe;
};
/**
* This method returns the formatted offset for a
* given timezone against UTC
*
*
* @param {String} offset - the selected timezone offset.
* @returns {String}
*
* @example
* selectedTimezoneFormattedOffset(offset:"-10:00")
* => (UTC -10:00)
*
*/
export const selectedTimezoneFormattedOffset = (offset) => __(`(UTC ${offset})`);
......@@ -4,7 +4,7 @@ import AddEditScheduleForm, {
i18n,
} from 'ee/oncall_schedules/components/add_edit_schedule_form.vue';
import { getOncallSchedulesQueryResponse } from './mocks/apollo_mock';
import mockTimezones from './mocks/mockTimezones.json';
import mockTimezones from './mocks/mock_timezones.json';
describe('AddEditScheduleForm', () => {
let wrapper;
......
......@@ -15,7 +15,7 @@ import {
updateScheduleResponse,
updateScheduleResponseWithErrors,
} from './mocks/apollo_mock';
import mockTimezones from './mocks/mockTimezones.json';
import mockTimezones from './mocks/mock_timezones.json';
describe('AddScheduleModal', () => {
let wrapper;
......
......@@ -3,7 +3,7 @@ import {
getFormattedTimezone,
getParticipantsForSave,
} from 'ee/oncall_schedules/utils/common_utils';
import mockTimezones from './mocks/mockTimezones.json';
import mockTimezones from './mocks/mock_timezones.json';
describe('getFormattedTimezone', () => {
it('formats the timezone', () => {
......
import { GlCard, GlSprintf, GlButton } from '@gitlab/ui';
import { GlCard, GlButton } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import OnCallSchedule, { i18n } from 'ee/oncall_schedules/components/oncall_schedule.vue';
import RotationsListSection from 'ee/oncall_schedules/components/schedule/components/rotations_list_section.vue';
......@@ -8,7 +8,7 @@ import { PRESET_TYPES } from 'ee/oncall_schedules/constants';
import * as commonUtils from 'ee/oncall_schedules/utils/common_utils';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import * as dateTimeUtility from '~/lib/utils/datetime_utility';
import mockTimezones from './mocks/mockTimezones.json';
import mockTimezones from './mocks/mock_timezones.json';
describe('On-call schedule', () => {
let wrapper;
......@@ -56,7 +56,6 @@ describe('On-call schedule', () => {
},
stubs: {
GlCard,
GlSprintf,
},
mocks: { $apollo },
}),
......@@ -90,7 +89,7 @@ describe('On-call schedule', () => {
});
it('shows timezone info', () => {
const timezone = i18n.scheduleForTz.replace('%{timezone}', lastTz.identifier);
const timezone = lastTz.identifier;
const offset = `(UTC ${lastTz.formatted_offset})`;
const description = findSchedule().text();
expect(description).toContain(timezone);
......
......@@ -2,11 +2,14 @@ import { GlAvatar, GlPopover } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import RotationAssignee, {
SHIFT_WIDTHS,
TIME_DATE_FORMAT,
} from 'ee/oncall_schedules/components/rotations/components/rotation_assignee.vue';
import { selectedTimezoneFormattedOffset } from 'ee/oncall_schedules/components/schedule/utils';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import { formatDate } from '~/lib/utils/datetime_utility';
import { truncate } from '~/lib/utils/text_utility';
import mockRotations from '../../mocks/mock_rotation.json';
import mockTimezones from '../../mocks/mock_timezones.json';
jest.mock('lodash/uniqueId', () => (prefix) => `${prefix}fakeUniqueId`);
......@@ -23,12 +26,17 @@ describe('RotationAssignee', () => {
const findName = () => wrapper.findByTestId('rotation-assignee-name');
const formattedDate = (date) => {
return formatDate(date, 'mmmm d, yyyy, h:MMtt Z');
return formatDate(date, TIME_DATE_FORMAT);
};
const selectedTimezone = mockTimezones[0];
function createComponent({ props = {} } = {}) {
wrapper = extendedWrapper(
shallowMount(RotationAssignee, {
provide: {
selectedTimezone,
},
propsData: {
assignee: { ...assignee.participant },
rotationAssigneeStartsAt: assignee.startsAt,
......@@ -73,9 +81,10 @@ describe('RotationAssignee', () => {
});
it('should render an assignee schedule and rotation information in a popover', () => {
const timezone = selectedTimezoneFormattedOffset(selectedTimezone.formatted_offset);
expect(findPopOver().attributes('target')).toBe('rotation-assignee-fakeUniqueId');
expect(findStartsAt().text()).toContain(formattedDate(assignee.startsAt));
expect(findEndsAt().text()).toContain(formattedDate(assignee.endsAt));
expect(findStartsAt().text()).toContain(`${formattedDate(assignee.startsAt)} ${timezone}`);
expect(findEndsAt().text()).toContain(`${formattedDate(assignee.endsAt)} ${timezone}`);
});
});
});
......@@ -105,14 +105,18 @@ exports[`RotationsListSectionComponent when the timeframe includes today renders
class="gl-m-0"
data-testid="rotation-assignee-starts-at"
>
Starts: January 12, 2021, 10:04am GMT+0000
Starts: January 12, 2021, 10:04 (UTC -12:00)
</p>
<p
class="gl-m-0"
data-testid="rotation-assignee-ends-at"
>
Ends: January 15, 2021, 10:04am GMT+0000
Ends: January 15, 2021, 10:04 (UTC -12:00)
</p>
</div>
</div>
......@@ -145,14 +149,18 @@ exports[`RotationsListSectionComponent when the timeframe includes today renders
class="gl-m-0"
data-testid="rotation-assignee-starts-at"
>
Starts: January 16, 2021, 10:04am GMT+0000
Starts: January 16, 2021, 10:04 (UTC -12:00)
</p>
<p
class="gl-m-0"
data-testid="rotation-assignee-ends-at"
>
Ends: January 18, 2021, 10:04am GMT+0000
Ends: January 18, 2021, 10:04 (UTC -12:00)
</p>
</div>
</div>
......
......@@ -8,6 +8,7 @@ import { PRESET_TYPES } from 'ee/oncall_schedules/constants';
import { useFakeDate } from 'helpers/fake_date';
import { scheduleIid } from '../../mocks/apollo_mock';
import mockRotations from '../../mocks/mock_rotation.json';
import mockTimezones from '../../mocks/mock_timezones.json';
describe('RotationsListSectionComponent', () => {
let wrapper;
......@@ -28,6 +29,7 @@ describe('RotationsListSectionComponent', () => {
},
provide: {
projectPath,
selectedTimezone: mockTimezones[0],
},
stubs: {
GlCard,
......
......@@ -3,6 +3,7 @@ import RotationsAssignee from 'ee/oncall_schedules/components/rotations/componen
import DaysScheduleShift from 'ee/oncall_schedules/components/schedule/components/shifts/components/days_schedule_shift.vue';
import { PRESET_TYPES, DAYS_IN_WEEK } from 'ee/oncall_schedules/constants';
import { nDaysAfter } from '~/lib/utils/datetime_utility';
import mockTimezones from '../../../../mocks/mock_timezones.json';
const shift = {
participant: {
......@@ -31,6 +32,7 @@ describe('ee/oncall_schedules/components/schedule/components/shifts/components/d
timeframe,
presetType: PRESET_TYPES.WEEKS,
shiftTimeUnitWidth: CELL_WIDTH,
selectedTimezone: mockTimezones[0],
...props,
},
});
......
......@@ -21069,9 +21069,6 @@ msgstr ""
msgid "OnCallSchedules|On-call schedule"
msgstr ""
msgid "OnCallSchedules|On-call schedule for the %{timezone}"
msgstr ""
msgid "OnCallSchedules|Please note, rotations with shifts that are less than four hours are currently not supported in the weekly view."
msgstr ""
......
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