Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
1d3d8788
Commit
1d3d8788
authored
Mar 15, 2021
by
Tristan Read
Committed by
Sean Arnold
Mar 16, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Revert "Remove edit functionality"
This reverts commit 50c8bbceb62a682ce922a4eafde0ca3f9fd7dae1.
parent
02649691
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
288 additions
and
76 deletions
+288
-76
ee/app/assets/javascripts/oncall_schedules/components/oncall_schedule.vue
...vascripts/oncall_schedules/components/oncall_schedule.vue
+8
-1
ee/app/assets/javascripts/oncall_schedules/components/rotations/components/add_edit_rotation_form.vue
...omponents/rotations/components/add_edit_rotation_form.vue
+13
-13
ee/app/assets/javascripts/oncall_schedules/components/rotations/components/add_edit_rotation_modal.vue
...mponents/rotations/components/add_edit_rotation_modal.vue
+88
-28
ee/app/assets/javascripts/oncall_schedules/components/schedule/components/rotations_list_section.vue
...components/schedule/components/rotations_list_section.vue
+1
-2
ee/app/assets/javascripts/oncall_schedules/graphql/fragments/oncall_schedule_participant.fragment.graphql
...ql/fragments/oncall_schedule_participant.fragment.graphql
+1
-0
ee/app/assets/javascripts/oncall_schedules/utils/common_utils.js
...assets/javascripts/oncall_schedules/utils/common_utils.js
+34
-0
ee/spec/frontend/oncall_schedule/common_utils_spec.js
ee/spec/frontend/oncall_schedule/common_utils_spec.js
+23
-0
ee/spec/frontend/oncall_schedule/mocks/apollo_mock.js
ee/spec/frontend/oncall_schedule/mocks/apollo_mock.js
+3
-3
ee/spec/frontend/oncall_schedule/mocks/mock_rotation.json
ee/spec/frontend/oncall_schedule/mocks/mock_rotation.json
+30
-18
ee/spec/frontend/oncall_schedule/rotations/components/add_edit_rotation_form_spec.js
...edule/rotations/components/add_edit_rotation_form_spec.js
+27
-8
ee/spec/frontend/oncall_schedule/rotations/components/add_edit_rotation_modal_spec.js
...dule/rotations/components/add_edit_rotation_modal_spec.js
+59
-2
ee/spec/frontend/oncall_schedule/schedule/components/__snapshots__/rotations_list_section_spec.js.snap
...ponents/__snapshots__/rotations_list_section_spec.js.snap
+1
-1
No files found.
ee/app/assets/javascripts/oncall_schedules/components/oncall_schedule.vue
View file @
1d3d8788
...
...
@@ -94,6 +94,7 @@ export default {
presetType
:
this
.
$options
.
PRESET_TYPES
.
WEEKS
,
timeframeStartDate
:
new
Date
(),
rotations
:
this
.
schedule
.
rotations
.
nodes
,
rotationToUpdate
:
{},
};
},
computed
:
{
...
...
@@ -163,6 +164,9 @@ export default {
fetchRotationShifts
()
{
this
.
$apollo
.
queries
.
rotations
.
refetch
();
},
setRotationToUpdate
(
rotation
)
{
this
.
rotationToUpdate
=
rotation
;
},
},
};
</
script
>
...
...
@@ -249,6 +253,7 @@ export default {
:timeframe=
"timeframe"
:schedule-iid=
"schedule.iid"
:loading=
"loading"
@
set-rotation-to-update=
"setRotationToUpdate"
/>
</div>
</gl-card>
...
...
@@ -262,12 +267,14 @@ export default {
<add-edit-rotation-modal
:schedule=
"schedule"
:modal-id=
"$options.addRotationModalId"
@
fetch
RotationS
hifts=
"fetchRotationShifts"
@
fetch
-rotation-s
hifts=
"fetchRotationShifts"
/>
<add-edit-rotation-modal
:schedule=
"schedule"
:modal-id=
"$options.editRotationModalId"
:rotation=
"rotationToUpdate"
is-edit-mode
@
fetch-rotation-shifts=
"fetchRotationShifts"
/>
</div>
</template>
ee/app/assets/javascripts/oncall_schedules/components/rotations/components/add_edit_rotation_form.vue
View file @
1d3d8788
...
...
@@ -97,12 +97,6 @@ export default {
default
:
()
=>
({}),
},
},
data
()
{
return
{
participantsArr
:
[],
endDateEnabled
:
false
,
};
},
methods
:
{
format24HourTimeStringFromInt
,
},
...
...
@@ -121,7 +115,8 @@ export default {
>
<gl-form-input
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>
...
...
@@ -133,14 +128,14 @@ export default {
:state=
"validationState.participants"
>
<gl-token-selector
v-model=
"participantsArr
"
:selected-tokens=
"form.participants
"
:dropdown-items=
"participants"
:loading=
"isLoading"
container-class=
"gl-h-13! gl-overflow-y-auto"
menu-class=
"gl-overflow-y-auto"
@
text-input=
"$emit('filter-participants', $event)"
@
blur=
"$emit('update-rotation-form',
{ type: 'participants', value:
participantsArr
})"
@input="$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:
$event
})"
>
<template
#token-content
="
{ token }">
<gl-avatar
v-if=
"token.avatarUrl"
:src=
"token.avatarUrl"
:size=
"16"
/>
...
...
@@ -169,7 +164,7 @@ export default {
type=
"number"
class=
"gl-w-12 gl-mr-3"
min=
"1"
:value=
"
1
"
:value=
"
form.rotationLength.length
"
@
input=
"$emit('update-rotation-form', { type: 'rotationLength.length', value: $event })"
/>
<gl-dropdown
:text=
"form.rotationLength.unit.toLowerCase()"
>
...
...
@@ -195,6 +190,7 @@ export default {
<div
class=
"gl-display-flex gl-align-items-center"
>
<gl-datepicker
class=
"gl-mr-3"
:value=
"form.startsAt.date"
@
input=
"$emit('update-rotation-form', { type: 'startsAt.date', value: $event })"
>
<
template
#default=
"{ formattedDate }"
>
...
...
@@ -233,14 +229,17 @@ export default {
</div>
<div
class=
"gl-display-inline-block"
>
<gl-toggle
v-model=
"e
ndDateEnabled"
:value=
"form.isE
ndDateEnabled"
:label=
"$options.i18n.fields.endsAt.enableToggle"
label-position=
"left"
class=
"gl-mb-5"
@
change=
"
$emit('update-rotation-form', { type: 'isEndDateEnabled', value: !form.isEndDateEnabled })
"
/>
<gl-card
v-if=
"
e
ndDateEnabled"
v-if=
"
form.isE
ndDateEnabled"
data-testid=
"rotation-ends-on"
class=
"gl-border-gray-400 gl-bg-gray-10"
>
...
...
@@ -254,6 +253,7 @@ export default {
<div
class=
"gl-display-flex gl-align-items-center"
>
<gl-datepicker
class=
"gl-mr-3"
:value=
"form.endsAt.date"
@
input=
"$emit('update-rotation-form', { type: 'endsAt.date', value: $event })"
>
<
template
#default=
"{ formattedDate }"
>
...
...
ee/app/assets/javascripts/oncall_schedules/components/rotations/components/add_edit_rotation_modal.vue
View file @
1d3d8788
...
...
@@ -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
getOncallSchedulesWithRotationsQuery
from
'
ee/oncall_schedules/graphql/queries/get_oncall_schedules.query.graphql
'
;
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
searchProjectMembersQuery
from
'
~/graphql_shared/queries/project_user_members_search.query.graphql
'
;
import
{
format24HourTimeStringFromInt
,
formatDate
}
from
'
~/lib/utils/datetime_utility
'
;
...
...
@@ -32,6 +37,7 @@ export const formEmptyState = {
date
:
null
,
time
:
0
,
},
isEndDateEnabled
:
false
,
endsAt
:
{
date
:
null
,
time
:
0
,
...
...
@@ -43,6 +49,13 @@ export const formEmptyState = {
},
};
const
validiationInitialState
=
{
name
:
true
,
participants
:
true
,
startsAt
:
true
,
endsAt
:
true
,
};
export
default
{
i18n
,
components
:
{
...
...
@@ -61,6 +74,11 @@ export default {
required
:
false
,
default
:
false
,
},
rotation
:
{
type
:
Object
,
required
:
false
,
default
:
()
=>
({}),
},
schedule
:
{
type
:
Object
,
required
:
true
,
...
...
@@ -90,12 +108,7 @@ export default {
ptSearchTerm
:
''
,
form
:
cloneDeep
(
formEmptyState
),
error
:
''
,
validationState
:
{
name
:
true
,
participants
:
true
,
startsAt
:
true
,
endsAt
:
true
,
},
validationState
:
cloneDeep
(
validiationInitialState
),
};
},
computed
:
{
...
...
@@ -134,34 +147,35 @@ export default {
participants
,
startsAt
:
{
date
:
startDate
,
time
:
startTime
},
endsAt
:
{
date
:
endDate
,
time
:
endTime
},
isEndDateEnabled
,
isRestrictedToTime
,
restrictedTo
:
{
startTime
:
activeStartTime
,
endTime
:
activeEndTime
},
}
=
this
.
form
;
const
variables
=
{
projectPath
:
this
.
projectPath
,
scheduleIid
:
this
.
schedule
.
iid
,
name
,
participants
:
getParticipantsForSave
(
participants
),
rotationLength
:
{
...
rotationLength
,
length
:
parseInt
(
rotationLength
.
length
,
10
),
},
startsAt
:
{
date
:
formatDate
(
startDate
,
'
yyyy-mm-dd
'
),
time
:
format24HourTimeStringFromInt
(
startTime
),
},
endsAt
:
endDate
endsAt
:
isEndDateEnabled
?
{
date
:
formatDate
(
endDate
,
'
yyyy-mm-dd
'
),
time
:
format24HourTimeStringFromInt
(
endTime
),
}
:
null
,
rotationLength
:
{
...
rotationLength
,
length
:
parseInt
(
rotationLength
.
length
,
10
),
},
participants
:
getParticipantsForSave
(
participants
),
activePeriod
:
isRestrictedToTime
?
{
startTime
:
format24HourTimeStringFromInt
(
activeStartTime
),
endTime
:
format24HourTimeStringFromInt
(
activeEndTime
),
}
:
null
,
};
if
(
this
.
form
.
isRestrictedToTime
)
{
variables
.
activePeriod
=
{
startTime
:
format24HourTimeStringFromInt
(
this
.
form
.
restrictedTo
.
startTime
),
endTime
:
format24HourTimeStringFromInt
(
this
.
form
.
restrictedTo
.
endTime
),
};
}
return
variables
;
},
title
()
{
...
...
@@ -185,11 +199,15 @@ export default {
methods
:
{
createRotation
()
{
this
.
loading
=
true
;
const
input
=
{
...
this
.
rotationVariables
,
projectPath
:
this
.
projectPath
,
scheduleIid
:
this
.
schedule
.
iid
,
};
this
.
$apollo
.
mutate
({
mutation
:
createOncallScheduleRotationMutation
,
variables
:
{
input
:
this
.
rotationVariables
},
variables
:
{
input
},
})
.
then
(
({
...
...
@@ -204,7 +222,7 @@ export default {
}
this
.
$refs
.
addEditScheduleRotationModal
.
hide
();
this
.
$emit
(
'
fetch
RotationS
hifts
'
);
this
.
$emit
(
'
fetch
-rotation-s
hifts
'
);
return
createFlash
({
message
:
this
.
$options
.
i18n
.
rotationCreated
,
type
:
FLASH_TYPES
.
SUCCESS
,
...
...
@@ -221,11 +239,14 @@ export default {
editRotation
()
{
this
.
loading
=
true
;
const
{
projectPath
,
schedule
}
=
this
;
const
input
=
{
...
this
.
rotationVariables
,
id
:
this
.
rotation
.
id
,
};
this
.
$apollo
.
mutate
({
mutation
:
updateOncallScheduleRotationMutation
,
variables
:
{
input
:
this
.
rotationVariables
},
variables
:
{
input
},
update
(
store
,
{
data
})
{
updateStoreAfterRotationEdit
(
store
,
...
...
@@ -250,6 +271,7 @@ export default {
}
this
.
$refs
.
addEditScheduleRotationModal
.
hide
();
this
.
$emit
(
'
fetch-rotation-shifts
'
);
return
createFlash
({
message
:
this
.
$options
.
i18n
.
editedRotation
,
type
:
FLASH_TYPES
.
SUCCESS
,
...
...
@@ -282,8 +304,45 @@ export default {
this
.
validationState
.
endsAt
=
this
.
isEndDateValid
;
}
},
afterCloseModal
()
{
beforeShowModal
()
{
if
(
this
.
isEditMode
)
{
this
.
parseRotation
();
}
},
resetModal
()
{
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 {
:action-cancel=
"actionsProps.cancel"
modal-class=
"rotations-modal"
@
primary.prevent=
"isEditMode ? editRotation() : createRotation()"
@
hide=
"afterCloseModal"
@
show=
"beforeShowModal"
@
hide=
"resetModal"
>
<gl-alert
v-if=
"error"
variant=
"danger"
@
dismiss=
"error = ''"
>
{{
error
||
$options
.
i18n
.
errorMsg
}}
...
...
ee/app/assets/javascripts/oncall_schedules/components/schedule/components/rotations_list_section.vue
View file @
1d3d8788
...
...
@@ -89,6 +89,7 @@ export default {
methods
:
{
setRotationToUpdate
(
rotation
)
{
this
.
rotationToUpdate
=
rotation
;
this
.
$emit
(
'
set-rotation-to-update
'
,
rotation
);
},
cellShouldHideOverflow
(
index
)
{
return
index
+
1
===
this
.
timeframe
.
length
||
this
.
presetIsDay
;
...
...
@@ -126,11 +127,9 @@ export default {
>
<span
class=
"gl-text-truncated"
>
{{
rotation
.
name
}}
</span>
<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
v-gl-modal=
"$options.editRotationModalId"
v-gl-tooltip
class=
"gl-display-none"
category=
"tertiary"
:title=
"$options.i18n.editRotationLabel"
icon=
"pencil"
...
...
ee/app/assets/javascripts/oncall_schedules/graphql/fragments/oncall_schedule_participant.fragment.graphql
View file @
1d3d8788
fragment
OnCallParticipant
on
OncallParticipantType
{
user
{
id
name
username
avatarUrl
}
...
...
ee/app/assets/javascripts/oncall_schedules/utils/common_utils.js
View file @
1d3d8788
import
{
newDateAsLocaleTime
}
from
'
~/lib/utils/datetime_utility
'
;
import
{
sprintf
,
__
}
from
'
~/locale
'
;
import
{
ASSIGNEE_COLORS_COMBO
}
from
'
../constants
'
;
...
...
@@ -52,3 +53,36 @@ export const getParticipantsForSave = (participants) =>
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
};
};
ee/spec/frontend/oncall_schedule/common_utils_spec.js
View file @
1d3d8788
...
...
@@ -2,6 +2,8 @@ import { ASSIGNEE_COLORS_COMBO } from 'ee/oncall_schedules/constants';
import
{
getFormattedTimezone
,
getParticipantsForSave
,
parseHour
,
parseRotationDate
,
}
from
'
ee/oncall_schedules/utils/common_utils
'
;
import
mockTimezones
from
'
./mocks/mock_timezones.json
'
;
...
...
@@ -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
);
});
});
ee/spec/frontend/oncall_schedule/mocks/apollo_mock.js
View file @
1d3d8788
...
...
@@ -34,9 +34,7 @@ export const getOncallSchedulesQueryResponse = {
iid
:
'
37
'
,
name
:
'
Test schedule from query
'
,
description
:
'
Description 1 lives here
'
,
timezone
:
{
identifier
:
'
Pacific/Honolulu
'
,
},
timezone
:
'
Pacific/Honolulu
'
,
rotations
:
{
nodes
:
[
mockRotations
]
},
},
],
...
...
@@ -156,6 +154,7 @@ export const createRotationResponse = {
username
:
'
project_1_bot3
'
,
avatarUrl
:
invalidUrl
,
avatar__typename
:
'
User
'
,
name
:
'
Bot 3
'
,
},
colorWeight
:
'
500
'
,
colorPalette
:
'
blue
'
,
...
...
@@ -194,6 +193,7 @@ export const createRotationResponseWithErrors = {
username
:
'
project_1_bot3
'
,
avatarUrl
:
invalidUrl
,
__typename
:
'
User
'
,
name
:
'
Bot 3
'
,
},
colorWeight
:
'
500
'
,
colorPalette
:
'
blue
'
,
...
...
ee/spec/frontend/oncall_schedule/mocks/mock_rotation.json
View file @
1d3d8788
[{
"id"
:
"gid://gitlab/IncidentManagement::OncallRotation/2"
,
"name"
:
"Rotation 242"
,
"startsAt"
:
"2021-01-13T1
0
:04:56.333Z"
,
"endsAt"
:
"2021-03-13T1
0
:04:56.333Z"
,
"length"
:
1
,
"startsAt"
:
"2021-01-13T1
1
:04:56.333Z"
,
"endsAt"
:
"2021-03-13T1
5
:04:56.333Z"
,
"length"
:
2
,
"lengthUnit"
:
"WEEKS"
,
"activePeriod"
:
{
"startTime"
:
"02:00"
,
...
...
@@ -15,7 +15,8 @@
"user"
:
{
"id"
:
"gid://gitlab/IncidentManagement::OncallParticipant/49"
,
"username"
:
"nora.schaden"
,
"avatarUrl"
:
"/url"
"avatarUrl"
:
"/url"
,
"name"
:
"nora"
},
"colorWeight"
:
"500"
,
"colorPalette"
:
"blue"
...
...
@@ -32,7 +33,8 @@
"user"
:
{
"id"
:
"1"
,
"username"
:
"nora.schaden"
,
"avatarUrl"
:
"/url"
"avatarUrl"
:
"/url"
,
"name"
:
"nora"
}
},
"startsAt"
:
"2021-01-12T10:04:56.333Z"
,
...
...
@@ -46,7 +48,8 @@
"user"
:
{
"id"
:
"2"
,
"username"
:
"racheal.loving"
,
"avatarUrl"
:
"/url"
"avatarUrl"
:
"/url"
,
"name"
:
"racheal"
}
},
"startsAt"
:
"2021-01-16T10:04:56.333Z"
,
...
...
@@ -58,8 +61,8 @@
{
"id"
:
"gid://gitlab/IncidentManagement::OncallRotation/55"
,
"name"
:
"Rotation 242"
,
"startsAt"
:
"2021-01-13T1
0
:04:56.333Z"
,
"endsAt"
:
"2021-03-13T1
0
:04:56.333Z"
,
"startsAt"
:
"2021-01-13T1
1
:04:56.333Z"
,
"endsAt"
:
"2021-03-13T1
5
:04:56.333Z"
,
"length"
:
1
,
"lengthUnit"
:
"WEEKS"
,
"activePeriod"
:
{
...
...
@@ -72,7 +75,8 @@
"user"
:
{
"id"
:
"gid://gitlab/IncidentManagement::OncallParticipant/99"
,
"username"
:
"david.oregan"
,
"avatarUrl"
:
"/url"
"avatarUrl"
:
"/url"
,
"name"
:
"david"
},
"colorWeight"
:
"500"
,
"colorPalette"
:
"aqua"
...
...
@@ -87,7 +91,8 @@
"colorWeight"
:
"500"
,
"colorPalette"
:
"aqua"
,
"user"
:
{
"username"
:
"david.oregan"
"username"
:
"david.oregan"
,
"name"
:
"david"
}
},
"startsAt"
:
"2021-01-14T10:04:56.333Z"
,
...
...
@@ -99,7 +104,8 @@
"colorWeight"
:
"500"
,
"colorPalette"
:
"green"
,
"user"
:
{
"username"
:
"david.keagan"
"username"
:
"david.keagan"
,
"name"
:
"david k"
}
},
"startsAt"
:
"2021-01-21T10:04:56.333Z"
,
...
...
@@ -125,7 +131,8 @@
"user"
:
{
"id"
:
"gid://gitlab/IncidentManagement::OncallParticipant/48"
,
"username"
:
"root"
,
"avatarUrl"
:
"/url"
"avatarUrl"
:
"/url"
,
"name"
:
"Administrator"
},
"colorWeight"
:
"500"
,
"colorPalette"
:
"magenta"
...
...
@@ -140,11 +147,12 @@
"colorWeight"
:
"500"
,
"colorPalette"
:
"magenta"
,
"user"
:
{
"username"
:
"root"
"username"
:
"root"
,
"name"
:
"Administrator"
}
},
"startsAt"
:
"2021-01-10T10:04:56.333Z"
,
"endsAt"
:
"2021-01-13T1
0
:04:56.333Z"
"endsAt"
:
"2021-01-13T1
1
:04:56.333Z"
},
{
"participant"
:
{
...
...
@@ -152,7 +160,8 @@
"colorWeight"
:
"600"
,
"colorPalette"
:
"blue"
,
"user"
:
{
"username"
:
"root2"
"username"
:
"root2"
,
"name"
:
"Administrator 2"
}
},
"startsAt"
:
"2021-01-15T10:04:56.333Z"
,
...
...
@@ -178,7 +187,8 @@
"user"
:
{
"id"
:
"gid://gitlab/IncidentManagement::OncallParticipant/51"
,
"username"
:
"oregand"
,
"avatarUrl"
:
"/url"
"avatarUrl"
:
"/url"
,
"name"
:
"david"
},
"colorWeight"
:
"600"
,
"colorPalette"
:
"orange"
...
...
@@ -193,7 +203,8 @@
"colorWeight"
:
"600"
,
"colorPalette"
:
"orange"
,
"user"
:
{
"username"
:
"oregand"
"username"
:
"oregand"
,
"name"
:
"david"
}
},
"startsAt"
:
"2021-01-12T10:04:56.333Z"
,
...
...
@@ -205,7 +216,8 @@
"colorWeight"
:
"600"
,
"colorPalette"
:
"aqua"
,
"user"
:
{
"username"
:
"sarah.w"
"username"
:
"sarah.w"
,
"name"
:
"sarah"
}
},
"startsAt"
:
"2021-01-16T10:04:56.333Z"
,
...
...
ee/spec/frontend/oncall_schedule/rotations/components/add_edit_rotation_form_spec.js
View file @
1d3d8788
...
...
@@ -56,6 +56,7 @@ describe('AddEditRotationForm', () => {
const
findStartsOnTimeOptions
=
()
=>
findRotationStartTime
().
findAllComponents
(
GlDropdownItem
);
const
findEndsOnTimeOptions
=
()
=>
findRotationEndTime
().
findAllComponents
(
GlDropdownItem
);
const
findRestrictedToToggle
=
()
=>
wrapper
.
find
(
'
[data-testid="restricted-to-toggle"]
'
);
const
findRestrictedToContainer
=
()
=>
wrapper
.
find
(
'
[data-testid="restricted-to-time"]
'
);
const
findRestrictedFromOptions
=
()
=>
wrapper
.
find
(
'
[data-testid="restricted-from"]
'
).
findAllComponents
(
GlDropdownItem
);
const
findRestrictedToOptions
=
()
=>
...
...
@@ -126,20 +127,35 @@ describe('AddEditRotationForm', () => {
});
describe
(
'
Rotation end time
'
,
()
=>
{
it
(
'
toggle
s end time visibility
'
,
async
()
=>
{
it
(
'
toggle
state depends on isEndDateEnabled
'
,
async
()
=>
{
createComponent
();
const
toggle
=
findEndDateToggle
().
vm
;
toggle
.
$emit
(
'
change
'
,
false
);
expect
(
findEndDateToggle
().
props
(
'
value
'
)).
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
);
});
it
(
'
should emit an event with selected value on time selecti
on
'
,
async
()
=>
{
it
(
'
toggles end time visibility
on
'
,
async
()
=>
{
createComponent
();
findEndDateToggle
().
vm
.
$emit
(
'
change
'
,
true
);
await
wrapper
.
vm
.
$nextTick
();
const
toggle
=
findEndDateToggle
().
vm
;
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
;
findEndsOnTimeOptions
().
at
(
option
).
vm
.
$emit
(
'
click
'
);
const
emittedEvent
=
wrapper
.
emitted
(
'
update-rotation-form
'
);
...
...
@@ -152,6 +168,7 @@ describe('AddEditRotationForm', () => {
createComponent
({
props
:
{
form
:
{
isEndDateEnabled
:
true
,
endsAt
:
{
time
,
},
...
...
@@ -175,9 +192,11 @@ describe('AddEditRotationForm', () => {
it
(
'
toggle state depends on isRestrictedToTime
'
,
async
()
=>
{
createComponent
();
expect
(
findRestrictedToToggle
().
props
(
'
value
'
)).
toBe
(
false
);
expect
(
findRestrictedToContainer
().
exists
()).
toBe
(
false
);
createComponent
({
props
:
{
form
:
{
...
formEmptyState
,
isRestrictedToTime
:
true
}
}
});
expect
(
findRestrictedToToggle
().
props
(
'
value
'
)).
toBe
(
true
);
expect
(
findRestrictedToContainer
().
exists
()).
toBe
(
true
);
});
it
(
'
toggles end time visibility on
'
,
async
()
=>
{
...
...
ee/spec/frontend/oncall_schedule/rotations/components/add_edit_rotation_modal_spec.js
View file @
1d3d8788
...
...
@@ -77,6 +77,7 @@ describe('AddEditRotationModal', () => {
const
createComponentWithApollo
=
({
search
=
''
,
createHandler
=
jest
.
fn
().
mockResolvedValue
(
createRotationResponse
),
props
=
{},
}
=
{})
=>
{
createRotationHandler
=
createHandler
;
localVue
.
use
(
VueApollo
);
...
...
@@ -104,6 +105,7 @@ describe('AddEditRotationModal', () => {
modalId
:
addRotationModalId
,
schedule
,
rotation
:
mockRotation
[
0
],
...
props
,
},
apolloProvider
:
fakeApollo
,
data
()
{
...
...
@@ -323,7 +325,7 @@ describe('AddEditRotationModal', () => {
it
(
'
calls a mutation with correct parameters and creates a rotation
'
,
async
()
=>
{
createComponentWithApollo
();
expect
(
wrapper
.
emitted
(
'
fetch
RotationS
hifts
'
)).
toBeUndefined
();
expect
(
wrapper
.
emitted
(
'
fetch
-rotation-s
hifts
'
)).
toBeUndefined
();
await
createRotation
(
wrapper
);
await
awaitApolloDomMock
();
...
...
@@ -334,7 +336,7 @@ describe('AddEditRotationModal', () => {
message
:
i18n
.
rotationCreated
,
type
:
FLASH_TYPES
.
SUCCESS
,
});
expect
(
wrapper
.
emitted
(
'
fetch
RotationS
hifts
'
)).
toHaveLength
(
1
);
expect
(
wrapper
.
emitted
(
'
fetch
-rotation-s
hifts
'
)).
toHaveLength
(
1
);
});
it
(
'
displays alert if mutation had a recoverable error
'
,
async
()
=>
{
...
...
@@ -350,4 +352,59 @@ describe('AddEditRotationModal', () => {
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
},
});
});
});
});
ee/spec/frontend/oncall_schedule/schedule/components/__snapshots__/rotations_list_section_spec.js.snap
View file @
1d3d8788
...
...
@@ -23,7 +23,7 @@ exports[`RotationsListSectionComponent when the timeframe includes today renders
>
<button
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"
type="button"
>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment