Commit 1d3d8788 authored by Tristan Read's avatar Tristan Read Committed by Sean Arnold

Revert "Remove edit functionality"

This reverts commit 50c8bbceb62a682ce922a4eafde0ca3f9fd7dae1.
parent 02649691
...@@ -94,6 +94,7 @@ export default { ...@@ -94,6 +94,7 @@ export default {
presetType: this.$options.PRESET_TYPES.WEEKS, presetType: this.$options.PRESET_TYPES.WEEKS,
timeframeStartDate: new Date(), timeframeStartDate: new Date(),
rotations: this.schedule.rotations.nodes, rotations: this.schedule.rotations.nodes,
rotationToUpdate: {},
}; };
}, },
computed: { computed: {
...@@ -163,6 +164,9 @@ export default { ...@@ -163,6 +164,9 @@ export default {
fetchRotationShifts() { fetchRotationShifts() {
this.$apollo.queries.rotations.refetch(); this.$apollo.queries.rotations.refetch();
}, },
setRotationToUpdate(rotation) {
this.rotationToUpdate = rotation;
},
}, },
}; };
</script> </script>
...@@ -249,6 +253,7 @@ export default { ...@@ -249,6 +253,7 @@ export default {
:timeframe="timeframe" :timeframe="timeframe"
:schedule-iid="schedule.iid" :schedule-iid="schedule.iid"
:loading="loading" :loading="loading"
@set-rotation-to-update="setRotationToUpdate"
/> />
</div> </div>
</gl-card> </gl-card>
...@@ -262,12 +267,14 @@ export default { ...@@ -262,12 +267,14 @@ export default {
<add-edit-rotation-modal <add-edit-rotation-modal
:schedule="schedule" :schedule="schedule"
:modal-id="$options.addRotationModalId" :modal-id="$options.addRotationModalId"
@fetchRotationShifts="fetchRotationShifts" @fetch-rotation-shifts="fetchRotationShifts"
/> />
<add-edit-rotation-modal <add-edit-rotation-modal
:schedule="schedule" :schedule="schedule"
:modal-id="$options.editRotationModalId" :modal-id="$options.editRotationModalId"
:rotation="rotationToUpdate"
is-edit-mode is-edit-mode
@fetch-rotation-shifts="fetchRotationShifts"
/> />
</div> </div>
</template> </template>
...@@ -97,12 +97,6 @@ export default { ...@@ -97,12 +97,6 @@ export default {
default: () => ({}), default: () => ({}),
}, },
}, },
data() {
return {
participantsArr: [],
endDateEnabled: false,
};
},
methods: { methods: {
format24HourTimeStringFromInt, format24HourTimeStringFromInt,
}, },
...@@ -121,7 +115,8 @@ export default { ...@@ -121,7 +115,8 @@ export default {
> >
<gl-form-input <gl-form-input
id="rotation-name" id="rotation-name"
@blur="$emit('update-rotation-form', { type: 'name', value: $event.target.value })" :value="form.name"
@change="$emit('update-rotation-form', { type: 'name', value: $event })"
/> />
</gl-form-group> </gl-form-group>
...@@ -133,14 +128,14 @@ export default { ...@@ -133,14 +128,14 @@ export default {
:state="validationState.participants" :state="validationState.participants"
> >
<gl-token-selector <gl-token-selector
v-model="participantsArr" :selected-tokens="form.participants"
:dropdown-items="participants" :dropdown-items="participants"
:loading="isLoading" :loading="isLoading"
container-class="gl-h-13! gl-overflow-y-auto" container-class="gl-h-13! gl-overflow-y-auto"
menu-class="gl-overflow-y-auto" menu-class="gl-overflow-y-auto"
@text-input="$emit('filter-participants', $event)" @text-input="$emit('filter-participants', $event)"
@blur="$emit('update-rotation-form', { type: 'participants', value: participantsArr })" @blur="$emit('update-rotation-form', { type: 'participants', value: form.participants })"
@input="$emit('update-rotation-form', { type: 'participants', value: participantsArr })" @input="$emit('update-rotation-form', { type: 'participants', value: $event })"
> >
<template #token-content="{ token }"> <template #token-content="{ token }">
<gl-avatar v-if="token.avatarUrl" :src="token.avatarUrl" :size="16" /> <gl-avatar v-if="token.avatarUrl" :src="token.avatarUrl" :size="16" />
...@@ -169,7 +164,7 @@ export default { ...@@ -169,7 +164,7 @@ export default {
type="number" type="number"
class="gl-w-12 gl-mr-3" class="gl-w-12 gl-mr-3"
min="1" min="1"
:value="1" :value="form.rotationLength.length"
@input="$emit('update-rotation-form', { type: 'rotationLength.length', value: $event })" @input="$emit('update-rotation-form', { type: 'rotationLength.length', value: $event })"
/> />
<gl-dropdown :text="form.rotationLength.unit.toLowerCase()"> <gl-dropdown :text="form.rotationLength.unit.toLowerCase()">
...@@ -195,6 +190,7 @@ export default { ...@@ -195,6 +190,7 @@ export default {
<div class="gl-display-flex gl-align-items-center"> <div class="gl-display-flex gl-align-items-center">
<gl-datepicker <gl-datepicker
class="gl-mr-3" class="gl-mr-3"
:value="form.startsAt.date"
@input="$emit('update-rotation-form', { type: 'startsAt.date', value: $event })" @input="$emit('update-rotation-form', { type: 'startsAt.date', value: $event })"
> >
<template #default="{ formattedDate }"> <template #default="{ formattedDate }">
...@@ -233,14 +229,17 @@ export default { ...@@ -233,14 +229,17 @@ export default {
</div> </div>
<div class="gl-display-inline-block"> <div class="gl-display-inline-block">
<gl-toggle <gl-toggle
v-model="endDateEnabled" :value="form.isEndDateEnabled"
:label="$options.i18n.fields.endsAt.enableToggle" :label="$options.i18n.fields.endsAt.enableToggle"
label-position="left" label-position="left"
class="gl-mb-5" class="gl-mb-5"
@change="
$emit('update-rotation-form', { type: 'isEndDateEnabled', value: !form.isEndDateEnabled })
"
/> />
<gl-card <gl-card
v-if="endDateEnabled" v-if="form.isEndDateEnabled"
data-testid="rotation-ends-on" data-testid="rotation-ends-on"
class="gl-border-gray-400 gl-bg-gray-10" class="gl-border-gray-400 gl-bg-gray-10"
> >
...@@ -254,6 +253,7 @@ export default { ...@@ -254,6 +253,7 @@ export default {
<div class="gl-display-flex gl-align-items-center"> <div class="gl-display-flex gl-align-items-center">
<gl-datepicker <gl-datepicker
class="gl-mr-3" class="gl-mr-3"
:value="form.endsAt.date"
@input="$emit('update-rotation-form', { type: 'endsAt.date', value: $event })" @input="$emit('update-rotation-form', { type: 'endsAt.date', value: $event })"
> >
<template #default="{ formattedDate }"> <template #default="{ formattedDate }">
......
...@@ -6,7 +6,12 @@ import createOncallScheduleRotationMutation from 'ee/oncall_schedules/graphql/mu ...@@ -6,7 +6,12 @@ import createOncallScheduleRotationMutation from 'ee/oncall_schedules/graphql/mu
import updateOncallScheduleRotationMutation from 'ee/oncall_schedules/graphql/mutations/update_oncall_schedule_rotation.mutation.graphql'; import updateOncallScheduleRotationMutation from 'ee/oncall_schedules/graphql/mutations/update_oncall_schedule_rotation.mutation.graphql';
import getOncallSchedulesWithRotationsQuery from 'ee/oncall_schedules/graphql/queries/get_oncall_schedules.query.graphql'; import getOncallSchedulesWithRotationsQuery from 'ee/oncall_schedules/graphql/queries/get_oncall_schedules.query.graphql';
import { updateStoreAfterRotationEdit } from 'ee/oncall_schedules/utils/cache_updates'; import { updateStoreAfterRotationEdit } from 'ee/oncall_schedules/utils/cache_updates';
import { isNameFieldValid, getParticipantsForSave } from 'ee/oncall_schedules/utils/common_utils'; import {
isNameFieldValid,
getParticipantsForSave,
parseHour,
parseRotationDate,
} from 'ee/oncall_schedules/utils/common_utils';
import createFlash, { FLASH_TYPES } from '~/flash'; import createFlash, { FLASH_TYPES } from '~/flash';
import searchProjectMembersQuery from '~/graphql_shared/queries/project_user_members_search.query.graphql'; import searchProjectMembersQuery from '~/graphql_shared/queries/project_user_members_search.query.graphql';
import { format24HourTimeStringFromInt, formatDate } from '~/lib/utils/datetime_utility'; import { format24HourTimeStringFromInt, formatDate } from '~/lib/utils/datetime_utility';
...@@ -32,6 +37,7 @@ export const formEmptyState = { ...@@ -32,6 +37,7 @@ export const formEmptyState = {
date: null, date: null,
time: 0, time: 0,
}, },
isEndDateEnabled: false,
endsAt: { endsAt: {
date: null, date: null,
time: 0, time: 0,
...@@ -43,6 +49,13 @@ export const formEmptyState = { ...@@ -43,6 +49,13 @@ export const formEmptyState = {
}, },
}; };
const validiationInitialState = {
name: true,
participants: true,
startsAt: true,
endsAt: true,
};
export default { export default {
i18n, i18n,
components: { components: {
...@@ -61,6 +74,11 @@ export default { ...@@ -61,6 +74,11 @@ export default {
required: false, required: false,
default: false, default: false,
}, },
rotation: {
type: Object,
required: false,
default: () => ({}),
},
schedule: { schedule: {
type: Object, type: Object,
required: true, required: true,
...@@ -90,12 +108,7 @@ export default { ...@@ -90,12 +108,7 @@ export default {
ptSearchTerm: '', ptSearchTerm: '',
form: cloneDeep(formEmptyState), form: cloneDeep(formEmptyState),
error: '', error: '',
validationState: { validationState: cloneDeep(validiationInitialState),
name: true,
participants: true,
startsAt: true,
endsAt: true,
},
}; };
}, },
computed: { computed: {
...@@ -134,34 +147,35 @@ export default { ...@@ -134,34 +147,35 @@ export default {
participants, participants,
startsAt: { date: startDate, time: startTime }, startsAt: { date: startDate, time: startTime },
endsAt: { date: endDate, time: endTime }, endsAt: { date: endDate, time: endTime },
isEndDateEnabled,
isRestrictedToTime,
restrictedTo: { startTime: activeStartTime, endTime: activeEndTime },
} = this.form; } = this.form;
const variables = { const variables = {
projectPath: this.projectPath,
scheduleIid: this.schedule.iid,
name, name,
participants: getParticipantsForSave(participants),
rotationLength: {
...rotationLength,
length: parseInt(rotationLength.length, 10),
},
startsAt: { startsAt: {
date: formatDate(startDate, 'yyyy-mm-dd'), date: formatDate(startDate, 'yyyy-mm-dd'),
time: format24HourTimeStringFromInt(startTime), time: format24HourTimeStringFromInt(startTime),
}, },
endsAt: endDate endsAt: isEndDateEnabled
? { ? {
date: formatDate(endDate, 'yyyy-mm-dd'), date: formatDate(endDate, 'yyyy-mm-dd'),
time: format24HourTimeStringFromInt(endTime), time: format24HourTimeStringFromInt(endTime),
} }
: null, : null,
rotationLength: { activePeriod: isRestrictedToTime
...rotationLength, ? {
length: parseInt(rotationLength.length, 10), startTime: format24HourTimeStringFromInt(activeStartTime),
}, endTime: format24HourTimeStringFromInt(activeEndTime),
participants: getParticipantsForSave(participants), }
: null,
}; };
if (this.form.isRestrictedToTime) {
variables.activePeriod = {
startTime: format24HourTimeStringFromInt(this.form.restrictedTo.startTime),
endTime: format24HourTimeStringFromInt(this.form.restrictedTo.endTime),
};
}
return variables; return variables;
}, },
title() { title() {
...@@ -185,11 +199,15 @@ export default { ...@@ -185,11 +199,15 @@ export default {
methods: { methods: {
createRotation() { createRotation() {
this.loading = true; this.loading = true;
const input = {
...this.rotationVariables,
projectPath: this.projectPath,
scheduleIid: this.schedule.iid,
};
this.$apollo this.$apollo
.mutate({ .mutate({
mutation: createOncallScheduleRotationMutation, mutation: createOncallScheduleRotationMutation,
variables: { input: this.rotationVariables }, variables: { input },
}) })
.then( .then(
({ ({
...@@ -204,7 +222,7 @@ export default { ...@@ -204,7 +222,7 @@ export default {
} }
this.$refs.addEditScheduleRotationModal.hide(); this.$refs.addEditScheduleRotationModal.hide();
this.$emit('fetchRotationShifts'); this.$emit('fetch-rotation-shifts');
return createFlash({ return createFlash({
message: this.$options.i18n.rotationCreated, message: this.$options.i18n.rotationCreated,
type: FLASH_TYPES.SUCCESS, type: FLASH_TYPES.SUCCESS,
...@@ -221,11 +239,14 @@ export default { ...@@ -221,11 +239,14 @@ export default {
editRotation() { editRotation() {
this.loading = true; this.loading = true;
const { projectPath, schedule } = this; const { projectPath, schedule } = this;
const input = {
...this.rotationVariables,
id: this.rotation.id,
};
this.$apollo this.$apollo
.mutate({ .mutate({
mutation: updateOncallScheduleRotationMutation, mutation: updateOncallScheduleRotationMutation,
variables: { input: this.rotationVariables }, variables: { input },
update(store, { data }) { update(store, { data }) {
updateStoreAfterRotationEdit( updateStoreAfterRotationEdit(
store, store,
...@@ -250,6 +271,7 @@ export default { ...@@ -250,6 +271,7 @@ export default {
} }
this.$refs.addEditScheduleRotationModal.hide(); this.$refs.addEditScheduleRotationModal.hide();
this.$emit('fetch-rotation-shifts');
return createFlash({ return createFlash({
message: this.$options.i18n.editedRotation, message: this.$options.i18n.editedRotation,
type: FLASH_TYPES.SUCCESS, type: FLASH_TYPES.SUCCESS,
...@@ -282,8 +304,45 @@ export default { ...@@ -282,8 +304,45 @@ export default {
this.validationState.endsAt = this.isEndDateValid; this.validationState.endsAt = this.isEndDateValid;
} }
}, },
afterCloseModal() { beforeShowModal() {
if (this.isEditMode) {
this.parseRotation();
}
},
resetModal() {
this.form = cloneDeep(formEmptyState); this.form = cloneDeep(formEmptyState);
this.validationState = cloneDeep(validiationInitialState);
this.error = '';
},
parseRotation() {
const scheduleTimezone = this.schedule.timezone;
this.form.name = this.rotation.name;
const participants =
this.rotation?.participants?.nodes?.map(({ user }) => ({ ...user })) ?? [];
this.form.participants = participants;
this.form.rotationLength = {
length: this.rotation.length,
unit: this.rotation.lengthUnit,
};
if (this.rotation.startsAt) {
this.form.startsAt = parseRotationDate(this.rotation.startsAt, scheduleTimezone);
}
if (this.rotation.endsAt) {
this.form.isEndDateEnabled = true;
this.form.endsAt = parseRotationDate(this.rotation.endsAt, scheduleTimezone);
}
if (this.rotation?.activePeriod?.startTime) {
const { activePeriod } = this.rotation;
this.form.isRestrictedToTime = true;
this.form.restrictedTo.startTime = parseHour(activePeriod.startTime);
this.form.restrictedTo.endTime = parseHour(activePeriod.endTime);
}
}, },
}, },
}; };
...@@ -298,7 +357,8 @@ export default { ...@@ -298,7 +357,8 @@ export default {
:action-cancel="actionsProps.cancel" :action-cancel="actionsProps.cancel"
modal-class="rotations-modal" modal-class="rotations-modal"
@primary.prevent="isEditMode ? editRotation() : createRotation()" @primary.prevent="isEditMode ? editRotation() : createRotation()"
@hide="afterCloseModal" @show="beforeShowModal"
@hide="resetModal"
> >
<gl-alert v-if="error" variant="danger" @dismiss="error = ''"> <gl-alert v-if="error" variant="danger" @dismiss="error = ''">
{{ error || $options.i18n.errorMsg }} {{ error || $options.i18n.errorMsg }}
......
...@@ -89,6 +89,7 @@ export default { ...@@ -89,6 +89,7 @@ export default {
methods: { methods: {
setRotationToUpdate(rotation) { setRotationToUpdate(rotation) {
this.rotationToUpdate = rotation; this.rotationToUpdate = rotation;
this.$emit('set-rotation-to-update', rotation);
}, },
cellShouldHideOverflow(index) { cellShouldHideOverflow(index) {
return index + 1 === this.timeframe.length || this.presetIsDay; return index + 1 === this.timeframe.length || this.presetIsDay;
...@@ -126,11 +127,9 @@ export default { ...@@ -126,11 +127,9 @@ export default {
> >
<span class="gl-text-truncated">{{ rotation.name }}</span> <span class="gl-text-truncated">{{ rotation.name }}</span>
<gl-button-group class="gl-px-2"> <gl-button-group class="gl-px-2">
<!-- TODO: Un-hide this button when: https://gitlab.com/gitlab-org/gitlab/-/issues/262862 is completed -->
<gl-button <gl-button
v-gl-modal="$options.editRotationModalId" v-gl-modal="$options.editRotationModalId"
v-gl-tooltip v-gl-tooltip
class="gl-display-none"
category="tertiary" category="tertiary"
:title="$options.i18n.editRotationLabel" :title="$options.i18n.editRotationLabel"
icon="pencil" icon="pencil"
......
fragment OnCallParticipant on OncallParticipantType { fragment OnCallParticipant on OncallParticipantType {
user { user {
id id
name
username username
avatarUrl avatarUrl
} }
......
import { newDateAsLocaleTime } from '~/lib/utils/datetime_utility';
import { sprintf, __ } from '~/locale'; import { sprintf, __ } from '~/locale';
import { ASSIGNEE_COLORS_COMBO } from '../constants'; import { ASSIGNEE_COLORS_COMBO } from '../constants';
...@@ -52,3 +53,36 @@ export const getParticipantsForSave = (participants) => ...@@ -52,3 +53,36 @@ export const getParticipantsForSave = (participants) =>
colorPalette, colorPalette,
}; };
}); });
/**
* Parses a activePeriod string into an integer value
*
* @param {String} hourString
*/
export const parseHour = (hourString) => parseInt(hourString.slice(0, 2), 10);
/**
* Parses a rotation date for use in the add/edit rotation form
*
* @param {ISOString} dateTimeString
* @param {Timezone string - long} scheduleTimezone
*/
export const parseRotationDate = (dateTimeString, scheduleTimezone) => {
const options = {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
hour12: false, // The time picker uses 24 hour time
timeZone: scheduleTimezone,
timeZoneName: 'long',
};
const formatter = new Intl.DateTimeFormat('en-US', options);
const parts = formatter.formatToParts(Date.parse(dateTimeString));
const [month, , day, , year, , hour] = parts.map((part) => part.value);
// The datepicker uses local time
const date = newDateAsLocaleTime(`${year}-${month}-${day}`);
const time = parseInt(hour, 10);
return { date, time };
};
...@@ -2,6 +2,8 @@ import { ASSIGNEE_COLORS_COMBO } from 'ee/oncall_schedules/constants'; ...@@ -2,6 +2,8 @@ import { ASSIGNEE_COLORS_COMBO } from 'ee/oncall_schedules/constants';
import { import {
getFormattedTimezone, getFormattedTimezone,
getParticipantsForSave, getParticipantsForSave,
parseHour,
parseRotationDate,
} from 'ee/oncall_schedules/utils/common_utils'; } from 'ee/oncall_schedules/utils/common_utils';
import mockTimezones from './mocks/mock_timezones.json'; import mockTimezones from './mocks/mock_timezones.json';
...@@ -27,3 +29,24 @@ describe('getParticipantsForSave', () => { ...@@ -27,3 +29,24 @@ describe('getParticipantsForSave', () => {
}); });
}); });
}); });
describe('parseRotationDate', () => {
it('parses a rotation date according to the supplied timezone', () => {
const dateTimeString = '2021-01-12T05:04:56.333Z';
const scheduleTimezone = 'Pacific/Honolulu';
const rotationDate = parseRotationDate(dateTimeString, scheduleTimezone);
expect(rotationDate).toStrictEqual({ date: new Date('2021-01-11T00:00:00.000Z'), time: 19 });
});
});
describe('parseHour', () => {
it('parses a rotation active period hour string', () => {
const hourString = '14:00';
const hourInt = parseHour(hourString);
expect(hourInt).toBe(14);
});
});
...@@ -34,9 +34,7 @@ export const getOncallSchedulesQueryResponse = { ...@@ -34,9 +34,7 @@ export const getOncallSchedulesQueryResponse = {
iid: '37', iid: '37',
name: 'Test schedule from query', name: 'Test schedule from query',
description: 'Description 1 lives here', description: 'Description 1 lives here',
timezone: { timezone: 'Pacific/Honolulu',
identifier: 'Pacific/Honolulu',
},
rotations: { nodes: [mockRotations] }, rotations: { nodes: [mockRotations] },
}, },
], ],
...@@ -156,6 +154,7 @@ export const createRotationResponse = { ...@@ -156,6 +154,7 @@ export const createRotationResponse = {
username: 'project_1_bot3', username: 'project_1_bot3',
avatarUrl: invalidUrl, avatarUrl: invalidUrl,
avatar__typename: 'User', avatar__typename: 'User',
name: 'Bot 3',
}, },
colorWeight: '500', colorWeight: '500',
colorPalette: 'blue', colorPalette: 'blue',
...@@ -194,6 +193,7 @@ export const createRotationResponseWithErrors = { ...@@ -194,6 +193,7 @@ export const createRotationResponseWithErrors = {
username: 'project_1_bot3', username: 'project_1_bot3',
avatarUrl: invalidUrl, avatarUrl: invalidUrl,
__typename: 'User', __typename: 'User',
name: 'Bot 3',
}, },
colorWeight: '500', colorWeight: '500',
colorPalette: 'blue', colorPalette: 'blue',
......
[{ [{
"id": "gid://gitlab/IncidentManagement::OncallRotation/2", "id": "gid://gitlab/IncidentManagement::OncallRotation/2",
"name": "Rotation 242", "name": "Rotation 242",
"startsAt": "2021-01-13T10:04:56.333Z", "startsAt": "2021-01-13T11:04:56.333Z",
"endsAt": "2021-03-13T10:04:56.333Z", "endsAt": "2021-03-13T15:04:56.333Z",
"length": 1, "length": 2,
"lengthUnit": "WEEKS", "lengthUnit": "WEEKS",
"activePeriod": { "activePeriod": {
"startTime": "02:00", "startTime": "02:00",
...@@ -15,7 +15,8 @@ ...@@ -15,7 +15,8 @@
"user": { "user": {
"id": "gid://gitlab/IncidentManagement::OncallParticipant/49", "id": "gid://gitlab/IncidentManagement::OncallParticipant/49",
"username": "nora.schaden", "username": "nora.schaden",
"avatarUrl": "/url" "avatarUrl": "/url",
"name": "nora"
}, },
"colorWeight": "500", "colorWeight": "500",
"colorPalette": "blue" "colorPalette": "blue"
...@@ -32,7 +33,8 @@ ...@@ -32,7 +33,8 @@
"user": { "user": {
"id": "1", "id": "1",
"username": "nora.schaden", "username": "nora.schaden",
"avatarUrl": "/url" "avatarUrl": "/url",
"name": "nora"
} }
}, },
"startsAt": "2021-01-12T10:04:56.333Z", "startsAt": "2021-01-12T10:04:56.333Z",
...@@ -46,7 +48,8 @@ ...@@ -46,7 +48,8 @@
"user": { "user": {
"id": "2", "id": "2",
"username": "racheal.loving", "username": "racheal.loving",
"avatarUrl": "/url" "avatarUrl": "/url",
"name": "racheal"
} }
}, },
"startsAt": "2021-01-16T10:04:56.333Z", "startsAt": "2021-01-16T10:04:56.333Z",
...@@ -58,8 +61,8 @@ ...@@ -58,8 +61,8 @@
{ {
"id": "gid://gitlab/IncidentManagement::OncallRotation/55", "id": "gid://gitlab/IncidentManagement::OncallRotation/55",
"name": "Rotation 242", "name": "Rotation 242",
"startsAt": "2021-01-13T10:04:56.333Z", "startsAt": "2021-01-13T11:04:56.333Z",
"endsAt": "2021-03-13T10:04:56.333Z", "endsAt": "2021-03-13T15:04:56.333Z",
"length": 1, "length": 1,
"lengthUnit": "WEEKS", "lengthUnit": "WEEKS",
"activePeriod": { "activePeriod": {
...@@ -72,7 +75,8 @@ ...@@ -72,7 +75,8 @@
"user": { "user": {
"id": "gid://gitlab/IncidentManagement::OncallParticipant/99", "id": "gid://gitlab/IncidentManagement::OncallParticipant/99",
"username": "david.oregan", "username": "david.oregan",
"avatarUrl": "/url" "avatarUrl": "/url",
"name": "david"
}, },
"colorWeight": "500", "colorWeight": "500",
"colorPalette": "aqua" "colorPalette": "aqua"
...@@ -87,7 +91,8 @@ ...@@ -87,7 +91,8 @@
"colorWeight": "500", "colorWeight": "500",
"colorPalette": "aqua", "colorPalette": "aqua",
"user": { "user": {
"username": "david.oregan" "username": "david.oregan",
"name": "david"
} }
}, },
"startsAt": "2021-01-14T10:04:56.333Z", "startsAt": "2021-01-14T10:04:56.333Z",
...@@ -99,7 +104,8 @@ ...@@ -99,7 +104,8 @@
"colorWeight": "500", "colorWeight": "500",
"colorPalette": "green", "colorPalette": "green",
"user": { "user": {
"username": "david.keagan" "username": "david.keagan",
"name": "david k"
} }
}, },
"startsAt": "2021-01-21T10:04:56.333Z", "startsAt": "2021-01-21T10:04:56.333Z",
...@@ -125,7 +131,8 @@ ...@@ -125,7 +131,8 @@
"user": { "user": {
"id": "gid://gitlab/IncidentManagement::OncallParticipant/48", "id": "gid://gitlab/IncidentManagement::OncallParticipant/48",
"username": "root", "username": "root",
"avatarUrl": "/url" "avatarUrl": "/url",
"name": "Administrator"
}, },
"colorWeight": "500", "colorWeight": "500",
"colorPalette": "magenta" "colorPalette": "magenta"
...@@ -140,11 +147,12 @@ ...@@ -140,11 +147,12 @@
"colorWeight": "500", "colorWeight": "500",
"colorPalette": "magenta", "colorPalette": "magenta",
"user": { "user": {
"username": "root" "username": "root",
"name": "Administrator"
} }
}, },
"startsAt": "2021-01-10T10:04:56.333Z", "startsAt": "2021-01-10T10:04:56.333Z",
"endsAt": "2021-01-13T10:04:56.333Z" "endsAt": "2021-01-13T11:04:56.333Z"
}, },
{ {
"participant": { "participant": {
...@@ -152,7 +160,8 @@ ...@@ -152,7 +160,8 @@
"colorWeight": "600", "colorWeight": "600",
"colorPalette": "blue", "colorPalette": "blue",
"user": { "user": {
"username": "root2" "username": "root2",
"name": "Administrator 2"
} }
}, },
"startsAt": "2021-01-15T10:04:56.333Z", "startsAt": "2021-01-15T10:04:56.333Z",
...@@ -178,7 +187,8 @@ ...@@ -178,7 +187,8 @@
"user": { "user": {
"id": "gid://gitlab/IncidentManagement::OncallParticipant/51", "id": "gid://gitlab/IncidentManagement::OncallParticipant/51",
"username": "oregand", "username": "oregand",
"avatarUrl": "/url" "avatarUrl": "/url",
"name": "david"
}, },
"colorWeight": "600", "colorWeight": "600",
"colorPalette": "orange" "colorPalette": "orange"
...@@ -193,7 +203,8 @@ ...@@ -193,7 +203,8 @@
"colorWeight": "600", "colorWeight": "600",
"colorPalette": "orange", "colorPalette": "orange",
"user": { "user": {
"username": "oregand" "username": "oregand",
"name": "david"
} }
}, },
"startsAt": "2021-01-12T10:04:56.333Z", "startsAt": "2021-01-12T10:04:56.333Z",
...@@ -205,7 +216,8 @@ ...@@ -205,7 +216,8 @@
"colorWeight": "600", "colorWeight": "600",
"colorPalette": "aqua", "colorPalette": "aqua",
"user": { "user": {
"username": "sarah.w" "username": "sarah.w",
"name": "sarah"
} }
}, },
"startsAt": "2021-01-16T10:04:56.333Z", "startsAt": "2021-01-16T10:04:56.333Z",
......
...@@ -56,6 +56,7 @@ describe('AddEditRotationForm', () => { ...@@ -56,6 +56,7 @@ describe('AddEditRotationForm', () => {
const findStartsOnTimeOptions = () => findRotationStartTime().findAllComponents(GlDropdownItem); const findStartsOnTimeOptions = () => findRotationStartTime().findAllComponents(GlDropdownItem);
const findEndsOnTimeOptions = () => findRotationEndTime().findAllComponents(GlDropdownItem); const findEndsOnTimeOptions = () => findRotationEndTime().findAllComponents(GlDropdownItem);
const findRestrictedToToggle = () => wrapper.find('[data-testid="restricted-to-toggle"]'); const findRestrictedToToggle = () => wrapper.find('[data-testid="restricted-to-toggle"]');
const findRestrictedToContainer = () => wrapper.find('[data-testid="restricted-to-time"]');
const findRestrictedFromOptions = () => const findRestrictedFromOptions = () =>
wrapper.find('[data-testid="restricted-from"]').findAllComponents(GlDropdownItem); wrapper.find('[data-testid="restricted-from"]').findAllComponents(GlDropdownItem);
const findRestrictedToOptions = () => const findRestrictedToOptions = () =>
...@@ -126,20 +127,35 @@ describe('AddEditRotationForm', () => { ...@@ -126,20 +127,35 @@ describe('AddEditRotationForm', () => {
}); });
describe('Rotation end time', () => { describe('Rotation end time', () => {
it('toggles end time visibility', async () => { it('toggle state depends on isEndDateEnabled', async () => {
createComponent(); createComponent();
const toggle = findEndDateToggle().vm; expect(findEndDateToggle().props('value')).toBe(false);
toggle.$emit('change', false);
expect(findRotationEndsContainer().exists()).toBe(false); expect(findRotationEndsContainer().exists()).toBe(false);
toggle.$emit('change', true);
await wrapper.vm.$nextTick(); createComponent({ props: { form: { isEndDateEnabled: true } } });
expect(findRotationEndsContainer().exists()).toBe(true); expect(findRotationEndsContainer().exists()).toBe(true);
}); });
it('should emit an event with selected value on time selection', async () => { it('toggles end time visibility on', async () => {
createComponent(); createComponent();
findEndDateToggle().vm.$emit('change', true); const toggle = findEndDateToggle().vm;
await wrapper.vm.$nextTick(); toggle.$emit('change', true);
const emittedEvent = wrapper.emitted('update-rotation-form');
expect(emittedEvent).toHaveLength(1);
expect(emittedEvent[0][0]).toEqual({ type: 'isEndDateEnabled', value: true });
});
it('toggles end time visibility off', async () => {
createComponent({ props: { form: { isEndDateEnabled: true } } });
const toggle = findEndDateToggle().vm;
toggle.$emit('change', false);
const emittedEvent = wrapper.emitted('update-rotation-form');
expect(emittedEvent).toHaveLength(1);
expect(emittedEvent[0][0]).toEqual({ type: 'isEndDateEnabled', value: false });
});
it('should emit an event with selected value on time selection', async () => {
createComponent({ props: { form: { isEndDateEnabled: true } } });
const option = 3; const option = 3;
findEndsOnTimeOptions().at(option).vm.$emit('click'); findEndsOnTimeOptions().at(option).vm.$emit('click');
const emittedEvent = wrapper.emitted('update-rotation-form'); const emittedEvent = wrapper.emitted('update-rotation-form');
...@@ -152,6 +168,7 @@ describe('AddEditRotationForm', () => { ...@@ -152,6 +168,7 @@ describe('AddEditRotationForm', () => {
createComponent({ createComponent({
props: { props: {
form: { form: {
isEndDateEnabled: true,
endsAt: { endsAt: {
time, time,
}, },
...@@ -175,9 +192,11 @@ describe('AddEditRotationForm', () => { ...@@ -175,9 +192,11 @@ describe('AddEditRotationForm', () => {
it('toggle state depends on isRestrictedToTime', async () => { it('toggle state depends on isRestrictedToTime', async () => {
createComponent(); createComponent();
expect(findRestrictedToToggle().props('value')).toBe(false); expect(findRestrictedToToggle().props('value')).toBe(false);
expect(findRestrictedToContainer().exists()).toBe(false);
createComponent({ props: { form: { ...formEmptyState, isRestrictedToTime: true } } }); createComponent({ props: { form: { ...formEmptyState, isRestrictedToTime: true } } });
expect(findRestrictedToToggle().props('value')).toBe(true); expect(findRestrictedToToggle().props('value')).toBe(true);
expect(findRestrictedToContainer().exists()).toBe(true);
}); });
it('toggles end time visibility on', async () => { it('toggles end time visibility on', async () => {
......
...@@ -77,6 +77,7 @@ describe('AddEditRotationModal', () => { ...@@ -77,6 +77,7 @@ describe('AddEditRotationModal', () => {
const createComponentWithApollo = ({ const createComponentWithApollo = ({
search = '', search = '',
createHandler = jest.fn().mockResolvedValue(createRotationResponse), createHandler = jest.fn().mockResolvedValue(createRotationResponse),
props = {},
} = {}) => { } = {}) => {
createRotationHandler = createHandler; createRotationHandler = createHandler;
localVue.use(VueApollo); localVue.use(VueApollo);
...@@ -104,6 +105,7 @@ describe('AddEditRotationModal', () => { ...@@ -104,6 +105,7 @@ describe('AddEditRotationModal', () => {
modalId: addRotationModalId, modalId: addRotationModalId,
schedule, schedule,
rotation: mockRotation[0], rotation: mockRotation[0],
...props,
}, },
apolloProvider: fakeApollo, apolloProvider: fakeApollo,
data() { data() {
...@@ -323,7 +325,7 @@ describe('AddEditRotationModal', () => { ...@@ -323,7 +325,7 @@ describe('AddEditRotationModal', () => {
it('calls a mutation with correct parameters and creates a rotation', async () => { it('calls a mutation with correct parameters and creates a rotation', async () => {
createComponentWithApollo(); createComponentWithApollo();
expect(wrapper.emitted('fetchRotationShifts')).toBeUndefined(); expect(wrapper.emitted('fetch-rotation-shifts')).toBeUndefined();
await createRotation(wrapper); await createRotation(wrapper);
await awaitApolloDomMock(); await awaitApolloDomMock();
...@@ -334,7 +336,7 @@ describe('AddEditRotationModal', () => { ...@@ -334,7 +336,7 @@ describe('AddEditRotationModal', () => {
message: i18n.rotationCreated, message: i18n.rotationCreated,
type: FLASH_TYPES.SUCCESS, type: FLASH_TYPES.SUCCESS,
}); });
expect(wrapper.emitted('fetchRotationShifts')).toHaveLength(1); expect(wrapper.emitted('fetch-rotation-shifts')).toHaveLength(1);
}); });
it('displays alert if mutation had a recoverable error', async () => { it('displays alert if mutation had a recoverable error', async () => {
...@@ -350,4 +352,59 @@ describe('AddEditRotationModal', () => { ...@@ -350,4 +352,59 @@ describe('AddEditRotationModal', () => {
expect(alert.text()).toContain('Houston, we have a problem'); expect(alert.text()).toContain('Houston, we have a problem');
}); });
}); });
describe('edit mode', () => {
beforeEach(async () => {
await createComponentWithApollo({ props: { isEditMode: true } });
await awaitApolloDomMock();
findModal().vm.$emit('show');
});
it('should load name correctly', () => {
expect(findForm().props('form')).toMatchObject({
name: 'Rotation 242',
});
});
it('should load rotation length correctly', () => {
expect(findForm().props('form')).toMatchObject({
rotationLength: {
length: 2,
unit: 'WEEKS',
},
});
});
it('should load participants correctly', () => {
expect(findForm().props('form')).toMatchObject({
participants: [{ name: 'nora' }],
});
});
it('should load startTime correctly', () => {
expect(findForm().props('form')).toMatchObject({
startsAt: {
date: new Date('2021-01-13T00:00:00.000Z'),
time: 1,
},
});
});
it('should load endTime correctly', () => {
expect(findForm().props('form')).toMatchObject({
endsAt: {
date: new Date('2021-03-13T00:00:00.000Z'),
time: 5,
},
});
});
it('should load rotation restriction data successfully', async () => {
expect(findForm().props('form')).toMatchObject({
isRestrictedToTime: true,
restrictedTo: { startTime: 2, endTime: 10 },
});
});
});
}); });
...@@ -23,7 +23,7 @@ exports[`RotationsListSectionComponent when the timeframe includes today renders ...@@ -23,7 +23,7 @@ exports[`RotationsListSectionComponent when the timeframe includes today renders
> >
<button <button
aria-label="Edit rotation" aria-label="Edit rotation"
class="btn gl-display-none btn-default btn-md gl-button btn-default-tertiary btn-icon" class="btn btn-default btn-md gl-button btn-default-tertiary btn-icon"
title="Edit rotation" title="Edit rotation"
type="button" type="button"
> >
......
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