Commit 3f567281 authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch '231401-epic-board-sidebar-edit-labels' into 'master'

Epic board sidebar - Edit epic labels [RUN AS-IF-FOSS]

See merge request gitlab-org/gitlab!57973
parents 14d0e8b8 d213000c
...@@ -18,6 +18,8 @@ export default { ...@@ -18,6 +18,8 @@ export default {
? BoardColumn ? BoardColumn
: BoardColumnDeprecated, : BoardColumnDeprecated,
BoardContentSidebar: () => import('~/boards/components/board_content_sidebar.vue'), BoardContentSidebar: () => import('~/boards/components/board_content_sidebar.vue'),
EpicBoardContentSidebar: () =>
import('ee_component/boards/components/epic_board_content_sidebar.vue'),
EpicsSwimlanes: () => import('ee_component/boards/components/epics_swimlanes.vue'), EpicsSwimlanes: () => import('ee_component/boards/components/epics_swimlanes.vue'),
GlAlert, GlAlert,
}, },
...@@ -133,7 +135,14 @@ export default { ...@@ -133,7 +135,14 @@ export default {
<board-content-sidebar <board-content-sidebar
v-if="isSwimlanesOn || glFeatures.graphqlBoardLists" v-if="isSwimlanesOn || glFeatures.graphqlBoardLists"
class="issue-boards-sidebar" class="boards-sidebar"
data-testid="issue-boards-sidebar"
/>
<epic-board-content-sidebar
v-else-if="isEpicBoard"
class="boards-sidebar"
data-testid="epic-boards-sidebar"
/> />
</div> </div>
</template> </template>
...@@ -34,7 +34,7 @@ export default { ...@@ -34,7 +34,7 @@ export default {
computed: { computed: {
...mapGetters([ ...mapGetters([
'isSidebarOpen', 'isSidebarOpen',
'activeIssue', 'activeBoardItem',
'groupPathForActiveIssue', 'groupPathForActiveIssue',
'projectPathForActiveIssue', 'projectPathForActiveIssue',
]), ]),
...@@ -46,13 +46,13 @@ export default { ...@@ -46,13 +46,13 @@ export default {
return this.isIssuableSidebar && this.isSidebarOpen; return this.isIssuableSidebar && this.isSidebarOpen;
}, },
fullPath() { fullPath() {
return this.activeIssue?.referencePath?.split('#')[0] || ''; return this.activeBoardItem?.referencePath?.split('#')[0] || '';
}, },
}, },
methods: { methods: {
...mapActions(['toggleBoardItem', 'setAssignees']), ...mapActions(['toggleBoardItem', 'setAssignees']),
handleClose() { handleClose() {
this.toggleBoardItem({ boardItem: this.activeIssue, sidebarType: this.sidebarType }); this.toggleBoardItem({ boardItem: this.activeBoardItem, sidebarType: this.sidebarType });
}, },
}, },
}; };
...@@ -61,7 +61,6 @@ export default { ...@@ -61,7 +61,6 @@ export default {
<template> <template>
<gl-drawer <gl-drawer
v-if="showSidebar" v-if="showSidebar"
data-testid="sidebar-drawer"
:open="isSidebarOpen" :open="isSidebarOpen"
:header-height="$options.headerHeight" :header-height="$options.headerHeight"
@close="handleClose" @close="handleClose"
...@@ -70,9 +69,9 @@ export default { ...@@ -70,9 +69,9 @@ export default {
<template #default> <template #default>
<board-sidebar-issue-title /> <board-sidebar-issue-title />
<sidebar-assignees-widget <sidebar-assignees-widget
:iid="activeIssue.iid" :iid="activeBoardItem.iid"
:full-path="fullPath" :full-path="fullPath"
:initial-assignees="activeIssue.assignees" :initial-assignees="activeBoardItem.assignees"
class="assignee" class="assignee"
@assignees-updated="setAssignees" @assignees-updated="setAssignees"
/> />
...@@ -80,7 +79,7 @@ export default { ...@@ -80,7 +79,7 @@ export default {
<div> <div>
<board-sidebar-milestone-select /> <board-sidebar-milestone-select />
<sidebar-iteration-widget <sidebar-iteration-widget
:iid="activeIssue.iid" :iid="activeBoardItem.iid"
:workspace-path="projectPathForActiveIssue" :workspace-path="projectPathForActiveIssue"
:iterations-workspace-path="groupPathForActiveIssue" :iterations-workspace-path="groupPathForActiveIssue"
:issuable-type="issuableType" :issuable-type="issuableType"
......
...@@ -18,16 +18,16 @@ export default { ...@@ -18,16 +18,16 @@ export default {
}; };
}, },
computed: { computed: {
...mapGetters(['activeIssue', 'projectPathForActiveIssue']), ...mapGetters(['activeBoardItem', 'projectPathForActiveIssue']),
hasDueDate() { hasDueDate() {
return this.activeIssue.dueDate != null; return this.activeBoardItem.dueDate != null;
}, },
parsedDueDate() { parsedDueDate() {
if (!this.hasDueDate) { if (!this.hasDueDate) {
return null; return null;
} }
return parsePikadayDate(this.activeIssue.dueDate); return parsePikadayDate(this.activeBoardItem.dueDate);
}, },
formattedDueDate() { formattedDueDate() {
if (!this.hasDueDate) { if (!this.hasDueDate) {
......
...@@ -27,7 +27,7 @@ export default { ...@@ -27,7 +27,7 @@ export default {
}; };
}, },
computed: { computed: {
...mapGetters({ issue: 'activeIssue' }), ...mapGetters({ issue: 'activeBoardItem' }),
pendingChangesStorageKey() { pendingChangesStorageKey() {
return this.getPendingChangesKey(this.issue); return this.getPendingChangesKey(this.issue);
}, },
......
...@@ -21,9 +21,9 @@ export default { ...@@ -21,9 +21,9 @@ export default {
}; };
}, },
computed: { computed: {
...mapGetters(['activeIssue', 'projectPathForActiveIssue']), ...mapGetters(['activeBoardItem', 'projectPathForActiveIssue']),
selectedLabels() { selectedLabels() {
const { labels = [] } = this.activeIssue; const { labels = [] } = this.activeBoardItem;
return labels.map((label) => ({ return labels.map((label) => ({
...label, ...label,
...@@ -31,7 +31,7 @@ export default { ...@@ -31,7 +31,7 @@ export default {
})); }));
}, },
issueLabels() { issueLabels() {
const { labels = [] } = this.activeIssue; const { labels = [] } = this.activeBoardItem;
return labels.map((label) => ({ return labels.map((label) => ({
...label, ...label,
...@@ -40,7 +40,7 @@ export default { ...@@ -40,7 +40,7 @@ export default {
}, },
}, },
methods: { methods: {
...mapActions(['setActiveIssueLabels']), ...mapActions(['setActiveBoardItemLabels']),
async setLabels(payload) { async setLabels(payload) {
this.loading = true; this.loading = true;
this.$refs.sidebarItem.collapse(); this.$refs.sidebarItem.collapse();
...@@ -52,7 +52,7 @@ export default { ...@@ -52,7 +52,7 @@ export default {
.map((label) => label.id); .map((label) => label.id);
const input = { addLabelIds, removeLabelIds, projectPath: this.projectPathForActiveIssue }; const input = { addLabelIds, removeLabelIds, projectPath: this.projectPathForActiveIssue };
await this.setActiveIssueLabels(input); await this.setActiveBoardItemLabels(input);
} catch (e) { } catch (e) {
createFlash({ message: __('An error occurred while updating labels.') }); createFlash({ message: __('An error occurred while updating labels.') });
} finally { } finally {
...@@ -65,7 +65,7 @@ export default { ...@@ -65,7 +65,7 @@ export default {
try { try {
const removeLabelIds = [getIdFromGraphQLId(id)]; const removeLabelIds = [getIdFromGraphQLId(id)];
const input = { removeLabelIds, projectPath: this.projectPathForActiveIssue }; const input = { removeLabelIds, projectPath: this.projectPathForActiveIssue };
await this.setActiveIssueLabels(input); await this.setActiveBoardItemLabels(input);
} catch (e) { } catch (e) {
createFlash({ message: __('An error occurred when removing the label.') }); createFlash({ message: __('An error occurred when removing the label.') });
} finally { } finally {
......
...@@ -56,20 +56,20 @@ export default { ...@@ -56,20 +56,20 @@ export default {
}, },
}, },
computed: { computed: {
...mapGetters(['activeIssue']), ...mapGetters(['activeBoardItem']),
hasMilestone() { hasMilestone() {
return this.activeIssue.milestone !== null; return this.activeBoardItem.milestone !== null;
}, },
groupFullPath() { groupFullPath() {
const { referencePath = '' } = this.activeIssue; const { referencePath = '' } = this.activeBoardItem;
return referencePath.slice(0, referencePath.indexOf('/')); return referencePath.slice(0, referencePath.indexOf('/'));
}, },
projectPath() { projectPath() {
const { referencePath = '' } = this.activeIssue; const { referencePath = '' } = this.activeBoardItem;
return referencePath.slice(0, referencePath.indexOf('#')); return referencePath.slice(0, referencePath.indexOf('#'));
}, },
dropdownText() { dropdownText() {
return this.activeIssue.milestone?.title ?? this.$options.i18n.noMilestone; return this.activeBoardItem.milestone?.title ?? this.$options.i18n.noMilestone;
}, },
}, },
methods: { methods: {
...@@ -118,7 +118,7 @@ export default { ...@@ -118,7 +118,7 @@ export default {
@close="handleClose" @close="handleClose"
> >
<template v-if="hasMilestone" #collapsed> <template v-if="hasMilestone" #collapsed>
<strong class="gl-text-gray-900">{{ activeIssue.milestone.title }}</strong> <strong class="gl-text-gray-900">{{ activeBoardItem.milestone.title }}</strong>
</template> </template>
<gl-dropdown <gl-dropdown
ref="dropdown" ref="dropdown"
...@@ -131,7 +131,7 @@ export default { ...@@ -131,7 +131,7 @@ export default {
<gl-dropdown-item <gl-dropdown-item
data-testid="no-milestone-item" data-testid="no-milestone-item"
:is-check-item="true" :is-check-item="true"
:is-checked="!activeIssue.milestone" :is-checked="!activeBoardItem.milestone"
@click="setMilestone(null)" @click="setMilestone(null)"
> >
{{ $options.i18n.noMilestone }} {{ $options.i18n.noMilestone }}
...@@ -143,7 +143,7 @@ export default { ...@@ -143,7 +143,7 @@ export default {
v-for="milestone in milestones" v-for="milestone in milestones"
:key="milestone.id" :key="milestone.id"
:is-check-item="true" :is-check-item="true"
:is-checked="activeIssue.milestone && milestone.id === activeIssue.milestone.id" :is-checked="activeBoardItem.milestone && milestone.id === activeBoardItem.milestone.id"
data-testid="milestone-item" data-testid="milestone-item"
@click="setMilestone(milestone.id)" @click="setMilestone(milestone.id)"
> >
......
...@@ -27,9 +27,9 @@ export default { ...@@ -27,9 +27,9 @@ export default {
}; };
}, },
computed: { computed: {
...mapGetters(['activeIssue', 'projectPathForActiveIssue']), ...mapGetters(['activeBoardItem', 'projectPathForActiveIssue']),
notificationText() { notificationText() {
return this.activeIssue.emailsDisabled return this.activeBoardItem.emailsDisabled
? this.$options.i18n.header.subscribeDisabledDescription ? this.$options.i18n.header.subscribeDisabledDescription
: this.$options.i18n.header.title; : this.$options.i18n.header.title;
}, },
...@@ -41,7 +41,7 @@ export default { ...@@ -41,7 +41,7 @@ export default {
try { try {
await this.setActiveIssueSubscribed({ await this.setActiveIssueSubscribed({
subscribed: !this.activeIssue.subscribed, subscribed: !this.activeBoardItem.subscribed,
projectPath: this.projectPathForActiveIssue, projectPath: this.projectPathForActiveIssue,
}); });
} catch (error) { } catch (error) {
...@@ -61,8 +61,8 @@ export default { ...@@ -61,8 +61,8 @@ export default {
> >
<span data-testid="notification-header-text"> {{ notificationText }} </span> <span data-testid="notification-header-text"> {{ notificationText }} </span>
<gl-toggle <gl-toggle
v-if="!activeIssue.emailsDisabled" v-if="!activeBoardItem.emailsDisabled"
:value="activeIssue.subscribed" :value="activeBoardItem.subscribed"
:is-loading="loading" :is-loading="loading"
:label="$options.i18n.header.title" :label="$options.i18n.header.title"
label-position="hidden" label-position="hidden"
......
...@@ -8,17 +8,17 @@ export default { ...@@ -8,17 +8,17 @@ export default {
}, },
inject: ['timeTrackingLimitToHours'], inject: ['timeTrackingLimitToHours'],
computed: { computed: {
...mapGetters(['activeIssue']), ...mapGetters(['activeBoardItem']),
}, },
}; };
</script> </script>
<template> <template>
<issuable-time-tracker <issuable-time-tracker
:time-estimate="activeIssue.timeEstimate" :time-estimate="activeBoardItem.timeEstimate"
:time-spent="activeIssue.totalTimeSpent" :time-spent="activeBoardItem.totalTimeSpent"
:human-time-estimate="activeIssue.humanTimeEstimate" :human-time-estimate="activeBoardItem.humanTimeEstimate"
:human-time-spent="activeIssue.humanTotalTimeSpent" :human-time-spent="activeBoardItem.humanTotalTimeSpent"
:limit-to-hours="timeTrackingLimitToHours" :limit-to-hours="timeTrackingLimitToHours"
:show-collapsed="false" :show-collapsed="false"
/> />
......
...@@ -371,20 +371,20 @@ export default { ...@@ -371,20 +371,20 @@ export default {
}, },
setAssignees: ({ commit, getters }, assigneeUsernames) => { setAssignees: ({ commit, getters }, assigneeUsernames) => {
commit('UPDATE_ISSUE_BY_ID', { commit('UPDATE_BOARD_ITEM_BY_ID', {
issueId: getters.activeIssue.id, itemId: getters.activeBoardItem.id,
prop: 'assignees', prop: 'assignees',
value: assigneeUsernames, value: assigneeUsernames,
}); });
}, },
setActiveIssueMilestone: async ({ commit, getters }, input) => { setActiveIssueMilestone: async ({ commit, getters }, input) => {
const { activeIssue } = getters; const { activeBoardItem } = getters;
const { data } = await gqlClient.mutate({ const { data } = await gqlClient.mutate({
mutation: issueSetMilestoneMutation, mutation: issueSetMilestoneMutation,
variables: { variables: {
input: { input: {
iid: String(activeIssue.iid), iid: String(activeBoardItem.iid),
milestoneId: getIdFromGraphQLId(input.milestoneId), milestoneId: getIdFromGraphQLId(input.milestoneId),
projectPath: input.projectPath, projectPath: input.projectPath,
}, },
...@@ -395,8 +395,8 @@ export default { ...@@ -395,8 +395,8 @@ export default {
throw new Error(data.updateIssue.errors); throw new Error(data.updateIssue.errors);
} }
commit(types.UPDATE_ISSUE_BY_ID, { commit(types.UPDATE_BOARD_ITEM_BY_ID, {
issueId: activeIssue.id, itemId: activeBoardItem.id,
prop: 'milestone', prop: 'milestone',
value: data.updateIssue.issue.milestone, value: data.updateIssue.issue.milestone,
}); });
...@@ -447,13 +447,17 @@ export default { ...@@ -447,13 +447,17 @@ export default {
.catch(() => commit(types.ADD_ISSUE_TO_LIST_FAILURE, { list, issueId: issueInput.id })); .catch(() => commit(types.ADD_ISSUE_TO_LIST_FAILURE, { list, issueId: issueInput.id }));
}, },
setActiveBoardItemLabels: ({ dispatch }, params) => {
dispatch('setActiveIssueLabels', params);
},
setActiveIssueLabels: async ({ commit, getters }, input) => { setActiveIssueLabels: async ({ commit, getters }, input) => {
const { activeIssue } = getters; const { activeBoardItem } = getters;
const { data } = await gqlClient.mutate({ const { data } = await gqlClient.mutate({
mutation: issueSetLabelsMutation, mutation: issueSetLabelsMutation,
variables: { variables: {
input: { input: {
iid: String(activeIssue.iid), iid: String(activeBoardItem.iid),
addLabelIds: input.addLabelIds ?? [], addLabelIds: input.addLabelIds ?? [],
removeLabelIds: input.removeLabelIds ?? [], removeLabelIds: input.removeLabelIds ?? [],
projectPath: input.projectPath, projectPath: input.projectPath,
...@@ -465,20 +469,20 @@ export default { ...@@ -465,20 +469,20 @@ export default {
throw new Error(data.updateIssue.errors); throw new Error(data.updateIssue.errors);
} }
commit(types.UPDATE_ISSUE_BY_ID, { commit(types.UPDATE_BOARD_ITEM_BY_ID, {
issueId: activeIssue.id, itemId: activeBoardItem.id,
prop: 'labels', prop: 'labels',
value: data.updateIssue.issue.labels.nodes, value: data.updateIssue.issue.labels.nodes,
}); });
}, },
setActiveIssueDueDate: async ({ commit, getters }, input) => { setActiveIssueDueDate: async ({ commit, getters }, input) => {
const { activeIssue } = getters; const { activeBoardItem } = getters;
const { data } = await gqlClient.mutate({ const { data } = await gqlClient.mutate({
mutation: issueSetDueDateMutation, mutation: issueSetDueDateMutation,
variables: { variables: {
input: { input: {
iid: String(activeIssue.iid), iid: String(activeBoardItem.iid),
projectPath: input.projectPath, projectPath: input.projectPath,
dueDate: input.dueDate, dueDate: input.dueDate,
}, },
...@@ -489,8 +493,8 @@ export default { ...@@ -489,8 +493,8 @@ export default {
throw new Error(data.updateIssue.errors); throw new Error(data.updateIssue.errors);
} }
commit(types.UPDATE_ISSUE_BY_ID, { commit(types.UPDATE_BOARD_ITEM_BY_ID, {
issueId: activeIssue.id, itemId: activeBoardItem.id,
prop: 'dueDate', prop: 'dueDate',
value: data.updateIssue.issue.dueDate, value: data.updateIssue.issue.dueDate,
}); });
...@@ -501,7 +505,7 @@ export default { ...@@ -501,7 +505,7 @@ export default {
mutation: issueSetSubscriptionMutation, mutation: issueSetSubscriptionMutation,
variables: { variables: {
input: { input: {
iid: String(getters.activeIssue.iid), iid: String(getters.activeBoardItem.iid),
projectPath: input.projectPath, projectPath: input.projectPath,
subscribedState: input.subscribed, subscribedState: input.subscribed,
}, },
...@@ -512,20 +516,20 @@ export default { ...@@ -512,20 +516,20 @@ export default {
throw new Error(data.issueSetSubscription.errors); throw new Error(data.issueSetSubscription.errors);
} }
commit(types.UPDATE_ISSUE_BY_ID, { commit(types.UPDATE_BOARD_ITEM_BY_ID, {
issueId: getters.activeIssue.id, itemId: getters.activeBoardItem.id,
prop: 'subscribed', prop: 'subscribed',
value: data.issueSetSubscription.issue.subscribed, value: data.issueSetSubscription.issue.subscribed,
}); });
}, },
setActiveIssueTitle: async ({ commit, getters }, input) => { setActiveIssueTitle: async ({ commit, getters }, input) => {
const { activeIssue } = getters; const { activeBoardItem } = getters;
const { data } = await gqlClient.mutate({ const { data } = await gqlClient.mutate({
mutation: issueSetTitleMutation, mutation: issueSetTitleMutation,
variables: { variables: {
input: { input: {
iid: String(activeIssue.iid), iid: String(activeBoardItem.iid),
projectPath: input.projectPath, projectPath: input.projectPath,
title: input.title, title: input.title,
}, },
...@@ -536,8 +540,8 @@ export default { ...@@ -536,8 +540,8 @@ export default {
throw new Error(data.updateIssue.errors); throw new Error(data.updateIssue.errors);
} }
commit(types.UPDATE_ISSUE_BY_ID, { commit(types.UPDATE_BOARD_ITEM_BY_ID, {
issueId: activeIssue.id, itemId: activeBoardItem.id,
prop: 'title', prop: 'title',
value: data.updateIssue.issue.title, value: data.updateIssue.issue.title,
}); });
...@@ -578,10 +582,10 @@ export default { ...@@ -578,10 +582,10 @@ export default {
const { selectedBoardItems } = state; const { selectedBoardItems } = state;
const index = selectedBoardItems.indexOf(boardItem); const index = selectedBoardItems.indexOf(boardItem);
// If user already selected an item (activeIssue) without using mult-select, // If user already selected an item (activeBoardItem) without using mult-select,
// include that item in the selection and unset state.ActiveId to hide the sidebar. // include that item in the selection and unset state.ActiveId to hide the sidebar.
if (getters.activeIssue) { if (getters.activeBoardItem) {
commit(types.ADD_BOARD_ITEM_TO_SELECTION, getters.activeIssue); commit(types.ADD_BOARD_ITEM_TO_SELECTION, getters.activeBoardItem);
dispatch('unsetActiveId'); dispatch('unsetActiveId');
} }
......
...@@ -15,17 +15,17 @@ export default { ...@@ -15,17 +15,17 @@ export default {
return listItemsIds.map((id) => getters.getBoardItemById(id)); return listItemsIds.map((id) => getters.getBoardItemById(id));
}, },
activeIssue: (state) => { activeBoardItem: (state) => {
return state.boardItems[state.activeId] || {}; return state.boardItems[state.activeId] || {};
}, },
groupPathForActiveIssue: (_, getters) => { groupPathForActiveIssue: (_, getters) => {
const { referencePath = '' } = getters.activeIssue; const { referencePath = '' } = getters.activeBoardItem;
return referencePath.slice(0, referencePath.indexOf('/')); return referencePath.slice(0, referencePath.indexOf('/'));
}, },
projectPathForActiveIssue: (_, getters) => { projectPathForActiveIssue: (_, getters) => {
const { referencePath = '' } = getters.activeIssue; const { referencePath = '' } = getters.activeBoardItem;
return referencePath.slice(0, referencePath.indexOf('#')); return referencePath.slice(0, referencePath.indexOf('#'));
}, },
......
...@@ -36,7 +36,7 @@ export const REMOVE_ISSUE_FROM_LIST = 'REMOVE_ISSUE_FROM_LIST'; ...@@ -36,7 +36,7 @@ export const REMOVE_ISSUE_FROM_LIST = 'REMOVE_ISSUE_FROM_LIST';
export const SET_CURRENT_PAGE = 'SET_CURRENT_PAGE'; export const SET_CURRENT_PAGE = 'SET_CURRENT_PAGE';
export const TOGGLE_EMPTY_STATE = 'TOGGLE_EMPTY_STATE'; export const TOGGLE_EMPTY_STATE = 'TOGGLE_EMPTY_STATE';
export const SET_ACTIVE_ID = 'SET_ACTIVE_ID'; export const SET_ACTIVE_ID = 'SET_ACTIVE_ID';
export const UPDATE_ISSUE_BY_ID = 'UPDATE_ISSUE_BY_ID'; export const UPDATE_BOARD_ITEM_BY_ID = 'UPDATE_BOARD_ITEM_BY_ID';
export const SET_ASSIGNEE_LOADING = 'SET_ASSIGNEE_LOADING'; export const SET_ASSIGNEE_LOADING = 'SET_ASSIGNEE_LOADING';
export const RESET_ISSUES = 'RESET_ISSUES'; export const RESET_ISSUES = 'RESET_ISSUES';
export const REQUEST_GROUP_PROJECTS = 'REQUEST_GROUP_PROJECTS'; export const REQUEST_GROUP_PROJECTS = 'REQUEST_GROUP_PROJECTS';
......
...@@ -158,13 +158,13 @@ export default { ...@@ -158,13 +158,13 @@ export default {
}); });
}, },
[mutationTypes.UPDATE_ISSUE_BY_ID]: (state, { issueId, prop, value }) => { [mutationTypes.UPDATE_BOARD_ITEM_BY_ID]: (state, { itemId, prop, value }) => {
if (!state.boardItems[issueId]) { if (!state.boardItems[itemId]) {
/* eslint-disable-next-line @gitlab/require-i18n-strings */ /* eslint-disable-next-line @gitlab/require-i18n-strings */
throw new Error('No issue found.'); throw new Error('No issue found.');
} }
Vue.set(state.boardItems[issueId], prop, value); Vue.set(state.boardItems[itemId], prop, value);
}, },
[mutationTypes.SET_ASSIGNEE_LOADING](state, isLoading) { [mutationTypes.SET_ASSIGNEE_LOADING](state, isLoading) {
......
...@@ -365,7 +365,7 @@ ...@@ -365,7 +365,7 @@
margin: 5px; margin: 5px;
} }
.right-sidebar.issue-boards-sidebar { .right-sidebar.boards-sidebar {
.gutter-toggle { .gutter-toggle {
bottom: 15px; bottom: 15px;
width: 22px; width: 22px;
...@@ -462,7 +462,7 @@ ...@@ -462,7 +462,7 @@
overflow-x: scroll; overflow-x: scroll;
} }
.issue-boards-sidebar { .boards-sidebar {
height: 100%; height: 100%;
top: 0; top: 0;
} }
......
...@@ -287,7 +287,7 @@ ...@@ -287,7 +287,7 @@
padding-top: 10px; padding-top: 10px;
} }
&:not(.issue-boards-sidebar):not([data-signed-in]):not([data-always-show-toggle]) { &:not(.boards-sidebar):not([data-signed-in]):not([data-always-show-toggle]) {
.issuable-sidebar-header { .issuable-sidebar-header {
display: none; display: none;
} }
......
%board-sidebar{ "inline-template" => true, ":current-user" => (UserSerializer.new.represent(current_user) || {}).to_json } %board-sidebar{ "inline-template" => true, ":current-user" => (UserSerializer.new.represent(current_user) || {}).to_json }
%transition{ name: "boards-sidebar-slide" } %transition{ name: "boards-sidebar-slide" }
%aside.right-sidebar.right-sidebar-expanded.issue-boards-sidebar{ "v-show" => "showSidebar", 'aria-label': s_('Boards|Board') } %aside.right-sidebar.right-sidebar-expanded.boards-sidebar{ "v-show" => "showSidebar", 'aria-label': s_('Boards|Board'), 'data-testid': 'issue-boards-sidebar' }
.issuable-sidebar .issuable-sidebar
.block.issuable-sidebar-header.position-relative .block.issuable-sidebar-header.position-relative
%span.issuable-header-text.hide-collapsed.float-left %span.issuable-header-text.hide-collapsed.float-left
......
<script>
import { GlDrawer } from '@gitlab/ui';
import { mapState, mapActions, mapGetters } from 'vuex';
import BoardSidebarLabelsSelect from '~/boards/components/sidebar/board_sidebar_labels_select.vue';
import { ISSUABLE } from '~/boards/constants';
import { contentTop } from '~/lib/utils/common_utils';
export default {
headerHeight: `${contentTop()}px`,
components: {
GlDrawer,
BoardSidebarLabelsSelect,
},
computed: {
...mapGetters(['isSidebarOpen', 'activeBoardItem']),
...mapState(['sidebarType']),
isIssuableSidebar() {
return this.sidebarType === ISSUABLE;
},
showSidebar() {
return this.isIssuableSidebar && this.isSidebarOpen;
},
},
methods: {
...mapActions(['toggleBoardItem']),
handleClose() {
this.toggleBoardItem({ boardItem: this.activeBoardItem, sidebarType: this.sidebarType });
},
},
};
</script>
<template>
<gl-drawer
v-if="showSidebar"
:open="isSidebarOpen"
:header-height="$options.headerHeight"
@close="handleClose"
>
<template #header>{{ __('Epic details') }}</template>
<template #default>
<board-sidebar-labels-select class="labels" />
</template>
</gl-drawer>
</template>
...@@ -26,9 +26,9 @@ export default { ...@@ -26,9 +26,9 @@ export default {
inject: ['groupId'], inject: ['groupId'],
computed: { computed: {
...mapState(['epics', 'epicsCacheById', 'epicFetchInProgress']), ...mapState(['epics', 'epicsCacheById', 'epicFetchInProgress']),
...mapGetters(['activeIssue', 'projectPathForActiveIssue']), ...mapGetters(['activeBoardItem', 'projectPathForActiveIssue']),
epic() { epic() {
return this.activeIssue.epic; return this.activeBoardItem.epic;
}, },
epicData() { epicData() {
const hasEpic = this.epic !== null; const hasEpic = this.epic !== null;
......
...@@ -23,13 +23,13 @@ export default { ...@@ -23,13 +23,13 @@ export default {
}; };
}, },
computed: { computed: {
...mapGetters(['activeIssue', 'projectPathForActiveIssue']), ...mapGetters(['activeBoardItem', 'projectPathForActiveIssue']),
hasWeight() { hasWeight() {
return this.activeIssue.weight > 0; return this.activeBoardItem.weight > 0;
}, },
}, },
watch: { watch: {
activeIssue: { activeBoardItem: {
handler(updatedIssue) { handler(updatedIssue) {
this.weight = updatedIssue.weight; this.weight = updatedIssue.weight;
}, },
...@@ -45,7 +45,7 @@ export default { ...@@ -45,7 +45,7 @@ export default {
async setWeight(provided) { async setWeight(provided) {
const weight = provided ?? this.weight; const weight = provided ?? this.weight;
if (this.loading || weight === this.activeIssue.weight) { if (this.loading || weight === this.activeBoardItem.weight) {
return; return;
} }
...@@ -55,7 +55,7 @@ export default { ...@@ -55,7 +55,7 @@ export default {
await this.setActiveIssueWeight({ weight, projectPath: this.projectPathForActiveIssue }); await this.setActiveIssueWeight({ weight, projectPath: this.projectPathForActiveIssue });
this.weight = weight; this.weight = weight;
} catch (e) { } catch (e) {
this.weight = this.activeIssue.weight; this.weight = this.activeBoardItem.weight;
createFlash({ message: __('An error occurred when updating the issue weight') }); createFlash({ message: __('An error occurred when updating the issue weight') });
} finally { } finally {
this.loading = false; this.loading = false;
...@@ -77,7 +77,7 @@ export default { ...@@ -77,7 +77,7 @@ export default {
<strong <strong
class="gl-text-gray-900 js-weight-weight-label-value" class="gl-text-gray-900 js-weight-weight-label-value"
data-qa-selector="weight_label_value" data-qa-selector="weight_label_value"
>{{ activeIssue.weight }}</strong >{{ activeBoardItem.weight }}</strong
> >
<span class="gl-mx-2">-</span> <span class="gl-mx-2">-</span>
<gl-button <gl-button
......
mutation updateEpic($input: UpdateEpicInput!) {
updateEpic(input: $input) {
epic {
id
labels {
nodes {
id
title
color
description
}
}
}
errors
}
}
...@@ -46,6 +46,7 @@ import projectBoardAssigneesQuery from '../graphql/project_board_assignees.query ...@@ -46,6 +46,7 @@ import projectBoardAssigneesQuery from '../graphql/project_board_assignees.query
import projectBoardIterationsQuery from '../graphql/project_board_iterations.query.graphql'; import projectBoardIterationsQuery from '../graphql/project_board_iterations.query.graphql';
import projectBoardMilestonesQuery from '../graphql/project_board_milestones.query.graphql'; import projectBoardMilestonesQuery from '../graphql/project_board_milestones.query.graphql';
import updateBoardEpicUserPreferencesMutation from '../graphql/update_board_epic_user_preferences.mutation.graphql'; import updateBoardEpicUserPreferencesMutation from '../graphql/update_board_epic_user_preferences.mutation.graphql';
import updateEpicLabelsMutation from '../graphql/update_epic_labels.mutation.graphql';
import boardsStoreEE from './boards_store_ee'; import boardsStoreEE from './boards_store_ee';
import * as types from './mutation_types'; import * as types from './mutation_types';
...@@ -379,13 +380,13 @@ export default { ...@@ -379,13 +380,13 @@ export default {
}, },
fetchEpicForActiveIssue: async ({ state, commit, getters }) => { fetchEpicForActiveIssue: async ({ state, commit, getters }) => {
if (!getters.activeIssue.epic) { if (!getters.activeBoardItem.epic) {
return false; return false;
} }
const { const {
epic: { id, iid }, epic: { id, iid },
} = getters.activeIssue; } = getters.activeBoardItem;
if (state.epicsCacheById[id]) { if (state.epicsCacheById[id]) {
return false; return false;
...@@ -421,7 +422,7 @@ export default { ...@@ -421,7 +422,7 @@ export default {
mutation: issueSetEpicMutation, mutation: issueSetEpicMutation,
variables: { variables: {
input: { input: {
iid: String(getters.activeIssue.iid), iid: String(getters.activeBoardItem.iid),
epicId, epicId,
projectPath: getters.projectPathForActiveIssue, projectPath: getters.projectPathForActiveIssue,
}, },
...@@ -439,8 +440,8 @@ export default { ...@@ -439,8 +440,8 @@ export default {
commit(types.UPDATE_CACHED_EPICS, [epic]); commit(types.UPDATE_CACHED_EPICS, [epic]);
} }
commit(typesCE.UPDATE_ISSUE_BY_ID, { commit(typesCE.UPDATE_BOARD_ITEM_BY_ID, {
issueId: getters.activeIssue.id, itemId: getters.activeBoardItem.id,
prop: 'epic', prop: 'epic',
value: epic ? { id: epic.id, iid: epic.iid } : null, value: epic ? { id: epic.id, iid: epic.iid } : null,
}); });
...@@ -452,7 +453,7 @@ export default { ...@@ -452,7 +453,7 @@ export default {
mutation: issueSetWeightMutation, mutation: issueSetWeightMutation,
variables: { variables: {
input: { input: {
iid: String(getters.activeIssue.iid), iid: String(getters.activeBoardItem.iid),
weight: input.weight, weight: input.weight,
projectPath: input.projectPath, projectPath: input.projectPath,
}, },
...@@ -463,8 +464,8 @@ export default { ...@@ -463,8 +464,8 @@ export default {
throw new Error(data.issueSetWeight?.errors); throw new Error(data.issueSetWeight?.errors);
} }
commit(typesCE.UPDATE_ISSUE_BY_ID, { commit(typesCE.UPDATE_BOARD_ITEM_BY_ID, {
issueId: getters.activeIssue.id, itemId: getters.activeBoardItem.id,
prop: 'weight', prop: 'weight',
value: data.issueSetWeight.issue.weight, value: data.issueSetWeight.issue.weight,
}); });
...@@ -765,4 +766,37 @@ export default { ...@@ -765,4 +766,37 @@ export default {
throw e; throw e;
}); });
}, },
setActiveBoardItemLabels: ({ getters, dispatch }, params) => {
if (!getters.isEpicBoard) {
dispatch('setActiveIssueLabels', params);
} else {
dispatch('setActiveEpicLabels', params);
}
},
setActiveEpicLabels: async ({ commit, getters, state }, input) => {
const { activeBoardItem } = getters;
const { data } = await gqlClient.mutate({
mutation: updateEpicLabelsMutation,
variables: {
input: {
iid: String(activeBoardItem.iid),
addLabelIds: input.addLabelIds ?? [],
removeLabelIds: input.removeLabelIds ?? [],
groupPath: state.fullPath,
},
},
});
if (data.updateEpic?.errors?.length > 0) {
throw new Error(data.updateEpic.errors);
}
commit(typesCE.UPDATE_BOARD_ITEM_BY_ID, {
itemId: activeBoardItem.id,
prop: 'labels',
value: data.updateEpic.epic.labels.nodes,
});
},
}; };
...@@ -36,7 +36,7 @@ RSpec.describe 'Issue Boards new issue', :js do ...@@ -36,7 +36,7 @@ RSpec.describe 'Issue Boards new issue', :js do
find('.board-card').click find('.board-card').click
end end
page.within(first('.issue-boards-sidebar')) do page.within(first('[data-testid="issue-boards-sidebar"]')) do
find('.weight [data-testid="edit-button"]').click find('.weight [data-testid="edit-button"]').click
find('.weight .form-control').set("10\n") find('.weight .form-control').set("10\n")
end end
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Epic boards sidebar', :js do
include BoardHelpers
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group, :public) }
let_it_be(:bug) { create(:group_label, group: group, name: 'Bug') }
let_it_be(:epic_board) { create(:epic_board, group: group) }
let_it_be(:backlog_list) { create(:epic_list, epic_board: epic_board, list_type: :backlog) }
let_it_be(:closed_list) { create(:epic_list, epic_board: epic_board, list_type: :closed) }
let_it_be(:epic1) { create(:epic, group: group, title: 'Epic1') }
let(:card) { find('.board:nth-child(1)').first("[data-testid='board_card']") }
before do
stub_licensed_features(epics: true)
group.add_maintainer(user)
sign_in(user)
visit group_epic_boards_path(group)
wait_for_requests
end
it 'shows sidebar when clicking epic' do
click_card(card)
expect(page).to have_selector('[data-testid="epic-boards-sidebar"]')
end
it 'closes sidebar when clicking epic' do
click_card(card)
expect(page).to have_selector('[data-testid="epic-boards-sidebar"]')
click_card(card)
expect(page).not_to have_selector('[data-testid="epic-boards-sidebar"]')
end
it 'closes sidebar when clicking close button' do
click_card(card)
expect(page).to have_selector('[data-testid="epic-boards-sidebar"]')
find('[data-testid="close-icon"]').click
expect(page).not_to have_selector('[data-testid="epic-boards-sidebar"]')
end
context 'labels' do
it 'adds a single label' do
click_card(card)
page.within('.labels') do
click_button 'Edit'
wait_for_requests
click_link bug.title
find('[data-testid="close-icon"]').click
wait_for_requests
page.within('.value') do
expect(page).to have_selector('.gl-label-text', count: 1)
expect(page).to have_content(bug.title)
end
end
expect(card).to have_selector('.gl-label', count: 1)
expect(card).to have_content(bug.title)
end
end
end
...@@ -20,7 +20,7 @@ describe('ee/BoardContentSidebar', () => { ...@@ -20,7 +20,7 @@ describe('ee/BoardContentSidebar', () => {
issuableType: issuableTypes.issue, issuableType: issuableTypes.issue,
}, },
getters: { getters: {
activeIssue: () => { activeBoardItem: () => {
return { ...mockIssue, epic: null }; return { ...mockIssue, epic: null };
}, },
projectPathForActiveIssue: () => mockIssueProjectPath, projectPathForActiveIssue: () => mockIssueProjectPath,
......
import { GlDrawer } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Vuex from 'vuex';
import EpicBoardContentSidebar from 'ee_component/boards/components/epic_board_content_sidebar.vue';
import { stubComponent } from 'helpers/stub_component';
import BoardSidebarLabelsSelect from '~/boards/components/sidebar/board_sidebar_labels_select.vue';
import { ISSUABLE } from '~/boards/constants';
import { mockEpic } from '../mock_data';
describe('EpicBoardContentSidebar', () => {
let wrapper;
let store;
const createStore = ({ mockGetters = {}, mockActions = {} } = {}) => {
store = new Vuex.Store({
state: {
sidebarType: ISSUABLE,
boardItems: { [mockEpic.id]: mockEpic },
activeId: mockEpic.id,
issuableType: 'epic',
},
getters: {
activeBoardItem: () => {
return mockEpic;
},
isSidebarOpen: () => true,
...mockGetters,
},
actions: mockActions,
});
};
const createComponent = () => {
wrapper = shallowMount(EpicBoardContentSidebar, {
provide: {
canUpdate: true,
rootPath: '/',
groupId: 1,
},
store,
stubs: {
GlDrawer: stubComponent(GlDrawer, {
template: '<div><slot name="header"></slot><slot></slot></div>',
}),
},
});
};
beforeEach(() => {
createStore();
createComponent();
});
afterEach(() => {
wrapper.destroy();
});
it('confirms we render GlDrawer', () => {
expect(wrapper.find(GlDrawer).exists()).toBe(true);
});
it('does not render GlDrawer when isSidebarOpen is false', () => {
createStore({ mockGetters: { isSidebarOpen: () => false } });
createComponent();
expect(wrapper.find(GlDrawer).exists()).toBe(false);
});
it('applies an open attribute', () => {
expect(wrapper.find(GlDrawer).props('open')).toBe(true);
});
it('renders BoardSidebarLabelsSelect', () => {
expect(wrapper.find(BoardSidebarLabelsSelect).exists()).toBe(true);
});
describe('when we emit close', () => {
let toggleBoardItem;
beforeEach(() => {
toggleBoardItem = jest.fn();
createStore({ mockActions: { toggleBoardItem } });
createComponent();
});
it('calls toggleBoardItem with correct parameters', async () => {
wrapper.find(GlDrawer).vm.$emit('close');
expect(toggleBoardItem).toHaveBeenCalledTimes(1);
expect(toggleBoardItem).toHaveBeenCalledWith(expect.any(Object), {
boardItem: mockEpic,
sidebarType: ISSUABLE,
});
});
});
});
...@@ -115,7 +115,7 @@ export const mockIterations = [ ...@@ -115,7 +115,7 @@ export const mockIterations = [
}, },
]; ];
const labels = [ export const labels = [
{ {
id: 'gid://gitlab/GroupLabel/5', id: 'gid://gitlab/GroupLabel/5',
title: 'Cosync', title: 'Cosync',
......
...@@ -15,6 +15,7 @@ import * as typesCE from '~/boards/stores/mutation_types'; ...@@ -15,6 +15,7 @@ import * as typesCE from '~/boards/stores/mutation_types';
import * as commonUtils from '~/lib/utils/common_utils'; import * as commonUtils from '~/lib/utils/common_utils';
import { mergeUrlParams, removeParams } from '~/lib/utils/url_utility'; import { mergeUrlParams, removeParams } from '~/lib/utils/url_utility';
import { import {
labels,
mockLists, mockLists,
mockIssue, mockIssue,
mockIssue2, mockIssue2,
...@@ -578,7 +579,7 @@ describe('fetchEpicForActiveIssue', () => { ...@@ -578,7 +579,7 @@ describe('fetchEpicForActiveIssue', () => {
}; };
describe("when active issue doesn't have an assigned epic", () => { describe("when active issue doesn't have an assigned epic", () => {
const getters = { activeIssue: { ...mockIssue, epic: null } }; const getters = { activeBoardItem: { ...mockIssue, epic: null } };
it('should not fetch any epic', async () => { it('should not fetch any epic', async () => {
await testAction(actions.fetchEpicForActiveIssue, undefined, { ...getters }, [], []); await testAction(actions.fetchEpicForActiveIssue, undefined, { ...getters }, [], []);
...@@ -586,7 +587,7 @@ describe('fetchEpicForActiveIssue', () => { ...@@ -586,7 +587,7 @@ describe('fetchEpicForActiveIssue', () => {
}); });
describe('when the assigned epic for active issue is found in state.epicsCacheById', () => { describe('when the assigned epic for active issue is found in state.epicsCacheById', () => {
const getters = { activeIssue: { ...mockIssue, epic: assignedEpic } }; const getters = { activeBoardItem: { ...mockIssue, epic: assignedEpic } };
const state = { epicsCacheById: { [assignedEpic.id]: assignedEpic } }; const state = { epicsCacheById: { [assignedEpic.id]: assignedEpic } };
it('should not fetch any epic', async () => { it('should not fetch any epic', async () => {
...@@ -601,7 +602,7 @@ describe('fetchEpicForActiveIssue', () => { ...@@ -601,7 +602,7 @@ describe('fetchEpicForActiveIssue', () => {
}); });
describe('when fetching fails', () => { describe('when fetching fails', () => {
const getters = { activeIssue: { ...mockIssue, epic: assignedEpic } }; const getters = { activeBoardItem: { ...mockIssue, epic: assignedEpic } };
const state = { epicsCacheById: {} }; const state = { epicsCacheById: {} };
it('should not commit UPDATE_CACHED_EPICS mutation and should throw an error', () => { it('should not commit UPDATE_CACHED_EPICS mutation and should throw an error', () => {
...@@ -630,7 +631,7 @@ describe('fetchEpicForActiveIssue', () => { ...@@ -630,7 +631,7 @@ describe('fetchEpicForActiveIssue', () => {
}); });
describe("when the assigned epic for active issue isn't found in state.epicsCacheById", () => { describe("when the assigned epic for active issue isn't found in state.epicsCacheById", () => {
const getters = { activeIssue: { ...mockIssue, epic: assignedEpic } }; const getters = { activeBoardItem: { ...mockIssue, epic: assignedEpic } };
const state = { epicsCacheById: {} }; const state = { epicsCacheById: {} };
it('should commit mutation SET_EPIC_FETCH_IN_PROGRESS before and after committing mutation UPDATE_CACHED_EPICS', async () => { it('should commit mutation SET_EPIC_FETCH_IN_PROGRESS before and after committing mutation UPDATE_CACHED_EPICS', async () => {
...@@ -664,7 +665,7 @@ describe('setActiveIssueEpic', () => { ...@@ -664,7 +665,7 @@ describe('setActiveIssueEpic', () => {
const state = { const state = {
epics: [{ id: 'gid://gitlab/Epic/422', iid: 99, title: 'existing epic' }], epics: [{ id: 'gid://gitlab/Epic/422', iid: 99, title: 'existing epic' }],
}; };
const getters = { activeIssue: { ...mockIssue, projectPath: 'h/b' } }; const getters = { activeBoardItem: { ...mockIssue, projectPath: 'h/b' } };
const epicWithData = { const epicWithData = {
id: 'gid://gitlab/Epic/42', id: 'gid://gitlab/Epic/42',
iid: 1, iid: 1,
...@@ -672,7 +673,7 @@ describe('setActiveIssueEpic', () => { ...@@ -672,7 +673,7 @@ describe('setActiveIssueEpic', () => {
}; };
describe('when the updated issue has an assigned epic', () => { describe('when the updated issue has an assigned epic', () => {
it('should commit mutation RECEIVE_EPICS_SUCCESS, UPDATE_CACHED_EPICS and UPDATE_ISSUE_BY_ID on success', async () => { it('should commit mutation RECEIVE_EPICS_SUCCESS, UPDATE_CACHED_EPICS and UPDATE_BOARD_ITEM_BY_ID on success', async () => {
jest jest
.spyOn(gqlClient, 'mutate') .spyOn(gqlClient, 'mutate')
.mockResolvedValue({ data: { issueSetEpic: { issue: { epic: epicWithData } } } }); .mockResolvedValue({ data: { issueSetEpic: { issue: { epic: epicWithData } } } });
...@@ -695,9 +696,9 @@ describe('setActiveIssueEpic', () => { ...@@ -695,9 +696,9 @@ describe('setActiveIssueEpic', () => {
payload: [epicWithData], payload: [epicWithData],
}, },
{ {
type: typesCE.UPDATE_ISSUE_BY_ID, type: typesCE.UPDATE_BOARD_ITEM_BY_ID,
payload: { payload: {
issueId: mockIssue.id, itemId: mockIssue.id,
prop: 'epic', prop: 'epic',
value: { id: epicWithData.id, iid: epicWithData.iid }, value: { id: epicWithData.id, iid: epicWithData.iid },
}, },
...@@ -713,7 +714,7 @@ describe('setActiveIssueEpic', () => { ...@@ -713,7 +714,7 @@ describe('setActiveIssueEpic', () => {
}); });
describe('when the updated issue does not have an epic (unassigned)', () => { describe('when the updated issue does not have an epic (unassigned)', () => {
it('should only commit UPDATE_ISSUE_BY_ID on success', async () => { it('should only commit UPDATE_BOARD_ITEM_BY_ID on success', async () => {
jest jest
.spyOn(gqlClient, 'mutate') .spyOn(gqlClient, 'mutate')
.mockResolvedValue({ data: { issueSetEpic: { issue: { epic: null } } } }); .mockResolvedValue({ data: { issueSetEpic: { issue: { epic: null } } } });
...@@ -728,8 +729,8 @@ describe('setActiveIssueEpic', () => { ...@@ -728,8 +729,8 @@ describe('setActiveIssueEpic', () => {
payload: true, payload: true,
}, },
{ {
type: typesCE.UPDATE_ISSUE_BY_ID, type: typesCE.UPDATE_BOARD_ITEM_BY_ID,
payload: { issueId: mockIssue.id, prop: 'epic', value: null }, payload: { itemId: mockIssue.id, prop: 'epic', value: null },
}, },
{ {
type: types.SET_EPIC_FETCH_IN_PROGRESS, type: types.SET_EPIC_FETCH_IN_PROGRESS,
...@@ -752,7 +753,7 @@ describe('setActiveIssueEpic', () => { ...@@ -752,7 +753,7 @@ describe('setActiveIssueEpic', () => {
describe('setActiveIssueWeight', () => { describe('setActiveIssueWeight', () => {
const state = { boardItems: { [mockIssue.id]: mockIssue } }; const state = { boardItems: { [mockIssue.id]: mockIssue } };
const getters = { activeIssue: mockIssue }; const getters = { activeBoardItem: mockIssue };
const testWeight = mockIssue.weight + 1; const testWeight = mockIssue.weight + 1;
const input = { const input = {
weight: testWeight, weight: testWeight,
...@@ -772,7 +773,7 @@ describe('setActiveIssueWeight', () => { ...@@ -772,7 +773,7 @@ describe('setActiveIssueWeight', () => {
}); });
const payload = { const payload = {
issueId: getters.activeIssue.id, itemId: getters.activeBoardItem.id,
prop: 'weight', prop: 'weight',
value: testWeight, value: testWeight,
}; };
...@@ -783,7 +784,7 @@ describe('setActiveIssueWeight', () => { ...@@ -783,7 +784,7 @@ describe('setActiveIssueWeight', () => {
{ ...state, ...getters }, { ...state, ...getters },
[ [
{ {
type: typesCE.UPDATE_ISSUE_BY_ID, type: typesCE.UPDATE_BOARD_ITEM_BY_ID,
payload, payload,
}, },
], ],
...@@ -1367,3 +1368,48 @@ describe('fetchAssignees', () => { ...@@ -1367,3 +1368,48 @@ describe('fetchAssignees', () => {
}); });
}); });
}); });
describe('setActiveEpicLabels', () => {
const state = { boardItems: { [mockEpic.id]: mockEpic } };
const getters = { activeBoardItem: mockEpic };
const testLabelIds = labels.map((label) => label.id);
const input = {
addLabelIds: testLabelIds,
removeLabelIds: [],
groupPath: 'h/b',
};
it('should assign labels on success', (done) => {
jest
.spyOn(gqlClient, 'mutate')
.mockResolvedValue({ data: { updateEpic: { epic: { labels: { nodes: labels } } } } });
const payload = {
itemId: getters.activeBoardItem.id,
prop: 'labels',
value: labels,
};
testAction(
actions.setActiveEpicLabels,
input,
{ ...state, ...getters },
[
{
type: typesCE.UPDATE_BOARD_ITEM_BY_ID,
payload,
},
],
[],
done,
);
});
it('throws error if fails', async () => {
jest
.spyOn(gqlClient, 'mutate')
.mockResolvedValue({ data: { updateEpic: { errors: ['failed mutation'] } } });
await expect(actions.setActiveEpicLabels({ getters }, input)).rejects.toThrow(Error);
});
});
...@@ -12108,6 +12108,9 @@ msgstr "" ...@@ -12108,6 +12108,9 @@ msgstr ""
msgid "Epic cannot be found." msgid "Epic cannot be found."
msgstr "" msgstr ""
msgid "Epic details"
msgstr ""
msgid "Epic events" msgid "Epic events"
msgstr "" msgstr ""
......
...@@ -90,7 +90,7 @@ RSpec.describe 'Issue Boards new issue', :js do ...@@ -90,7 +90,7 @@ RSpec.describe 'Issue Boards new issue', :js do
wait_for_requests wait_for_requests
expect(page).to have_selector('.issue-boards-sidebar') expect(page).to have_selector('[data-testid="issue-boards-sidebar"]')
end end
it 'successfuly loads labels to be added to newly created issue' do it 'successfuly loads labels to be added to newly created issue' do
...@@ -109,7 +109,7 @@ RSpec.describe 'Issue Boards new issue', :js do ...@@ -109,7 +109,7 @@ RSpec.describe 'Issue Boards new issue', :js do
find('.board-card').click find('.board-card').click
end end
page.within(first('.issue-boards-sidebar')) do page.within(first('[data-testid="issue-boards-sidebar"]')) do
find('.labels [data-testid="edit-button"]').click find('.labels [data-testid="edit-button"]').click
wait_for_requests wait_for_requests
......
...@@ -24,7 +24,7 @@ describe('BoardContentSidebar', () => { ...@@ -24,7 +24,7 @@ describe('BoardContentSidebar', () => {
issuableType: 'issue', issuableType: 'issue',
}, },
getters: { getters: {
activeIssue: () => { activeBoardItem: () => {
return { ...mockIssue, epic: null }; return { ...mockIssue, epic: null };
}, },
groupPathForActiveIssue: () => mockIssueGroupPath, groupPathForActiveIssue: () => mockIssueGroupPath,
......
...@@ -64,7 +64,7 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => { ...@@ -64,7 +64,7 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => {
beforeEach(async () => { beforeEach(async () => {
createWrapper(); createWrapper();
jest.spyOn(wrapper.vm, 'setActiveIssueLabels').mockImplementation(() => TEST_LABELS); jest.spyOn(wrapper.vm, 'setActiveBoardItemLabels').mockImplementation(() => TEST_LABELS);
findLabelsSelect().vm.$emit('updateSelectedLabels', TEST_LABELS_PAYLOAD); findLabelsSelect().vm.$emit('updateSelectedLabels', TEST_LABELS_PAYLOAD);
store.state.boardItems[TEST_ISSUE.id].labels = TEST_LABELS; store.state.boardItems[TEST_ISSUE.id].labels = TEST_LABELS;
await wrapper.vm.$nextTick(); await wrapper.vm.$nextTick();
...@@ -76,7 +76,7 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => { ...@@ -76,7 +76,7 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => {
}); });
it('commits change to the server', () => { it('commits change to the server', () => {
expect(wrapper.vm.setActiveIssueLabels).toHaveBeenCalledWith({ expect(wrapper.vm.setActiveBoardItemLabels).toHaveBeenCalledWith({
addLabelIds: TEST_LABELS.map((label) => label.id), addLabelIds: TEST_LABELS.map((label) => label.id),
projectPath: 'gitlab-org/test-subgroup/gitlab-test', projectPath: 'gitlab-org/test-subgroup/gitlab-test',
removeLabelIds: [], removeLabelIds: [],
...@@ -94,13 +94,13 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => { ...@@ -94,13 +94,13 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => {
beforeEach(async () => { beforeEach(async () => {
createWrapper({ labels: TEST_LABELS }); createWrapper({ labels: TEST_LABELS });
jest.spyOn(wrapper.vm, 'setActiveIssueLabels').mockImplementation(() => expectedLabels); jest.spyOn(wrapper.vm, 'setActiveBoardItemLabels').mockImplementation(() => expectedLabels);
findLabelsSelect().vm.$emit('updateSelectedLabels', testLabelsPayload); findLabelsSelect().vm.$emit('updateSelectedLabels', testLabelsPayload);
await wrapper.vm.$nextTick(); await wrapper.vm.$nextTick();
}); });
it('commits change to the server', () => { it('commits change to the server', () => {
expect(wrapper.vm.setActiveIssueLabels).toHaveBeenCalledWith({ expect(wrapper.vm.setActiveBoardItemLabels).toHaveBeenCalledWith({
addLabelIds: [5, 7], addLabelIds: [5, 7],
removeLabelIds: [6], removeLabelIds: [6],
projectPath: 'gitlab-org/test-subgroup/gitlab-test', projectPath: 'gitlab-org/test-subgroup/gitlab-test',
...@@ -114,13 +114,13 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => { ...@@ -114,13 +114,13 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => {
beforeEach(async () => { beforeEach(async () => {
createWrapper({ labels: [testLabel] }); createWrapper({ labels: [testLabel] });
jest.spyOn(wrapper.vm, 'setActiveIssueLabels').mockImplementation(() => {}); jest.spyOn(wrapper.vm, 'setActiveBoardItemLabels').mockImplementation(() => {});
}); });
it('commits change to the server', () => { it('commits change to the server', () => {
wrapper.find(GlLabel).vm.$emit('close', testLabel); wrapper.find(GlLabel).vm.$emit('close', testLabel);
expect(wrapper.vm.setActiveIssueLabels).toHaveBeenCalledWith({ expect(wrapper.vm.setActiveBoardItemLabels).toHaveBeenCalledWith({
removeLabelIds: [getIdFromGraphQLId(testLabel.id)], removeLabelIds: [getIdFromGraphQLId(testLabel.id)],
projectPath: 'gitlab-org/test-subgroup/gitlab-test', projectPath: 'gitlab-org/test-subgroup/gitlab-test',
}); });
...@@ -131,7 +131,7 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => { ...@@ -131,7 +131,7 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => {
beforeEach(async () => { beforeEach(async () => {
createWrapper({ labels: TEST_LABELS }); createWrapper({ labels: TEST_LABELS });
jest.spyOn(wrapper.vm, 'setActiveIssueLabels').mockImplementation(() => { jest.spyOn(wrapper.vm, 'setActiveBoardItemLabels').mockImplementation(() => {
throw new Error(['failed mutation']); throw new Error(['failed mutation']);
}); });
findLabelsSelect().vm.$emit('updateSelectedLabels', [{ id: '?' }]); findLabelsSelect().vm.$emit('updateSelectedLabels', [{ id: '?' }]);
......
...@@ -20,10 +20,10 @@ describe('~/boards/components/sidebar/board_sidebar_subscription_spec.vue', () = ...@@ -20,10 +20,10 @@ describe('~/boards/components/sidebar/board_sidebar_subscription_spec.vue', () =
const findToggle = () => wrapper.find(GlToggle); const findToggle = () => wrapper.find(GlToggle);
const findGlLoadingIcon = () => wrapper.find(GlLoadingIcon); const findGlLoadingIcon = () => wrapper.find(GlLoadingIcon);
const createComponent = (activeIssue = { ...mockActiveIssue }) => { const createComponent = (activeBoardItem = { ...mockActiveIssue }) => {
store = createStore(); store = createStore();
store.state.boardItems = { [activeIssue.id]: activeIssue }; store.state.boardItems = { [activeBoardItem.id]: activeBoardItem };
store.state.activeId = activeIssue.id; store.state.activeId = activeBoardItem.id;
wrapper = mount(BoardSidebarSubscription, { wrapper = mount(BoardSidebarSubscription, {
localVue, localVue,
...@@ -91,8 +91,8 @@ describe('~/boards/components/sidebar/board_sidebar_subscription_spec.vue', () = ...@@ -91,8 +91,8 @@ describe('~/boards/components/sidebar/board_sidebar_subscription_spec.vue', () =
describe('Board sidebar subscription component `behavior`', () => { describe('Board sidebar subscription component `behavior`', () => {
const mockSetActiveIssueSubscribed = (subscribedState) => { const mockSetActiveIssueSubscribed = (subscribedState) => {
jest.spyOn(wrapper.vm, 'setActiveIssueSubscribed').mockImplementation(async () => { jest.spyOn(wrapper.vm, 'setActiveIssueSubscribed').mockImplementation(async () => {
store.commit(types.UPDATE_ISSUE_BY_ID, { store.commit(types.UPDATE_BOARD_ITEM_BY_ID, {
issueId: mockActiveIssue.id, itemId: mockActiveIssue.id,
prop: 'subscribed', prop: 'subscribed',
value: subscribedState, value: subscribedState,
}); });
......
...@@ -802,11 +802,11 @@ describe('setAssignees', () => { ...@@ -802,11 +802,11 @@ describe('setAssignees', () => {
testAction( testAction(
actions.setAssignees, actions.setAssignees,
[node], [node],
{ activeIssue: { iid, referencePath: refPath }, commit: () => {} }, { activeBoardItem: { iid, referencePath: refPath }, commit: () => {} },
[ [
{ {
type: 'UPDATE_ISSUE_BY_ID', type: 'UPDATE_BOARD_ITEM_BY_ID',
payload: { prop: 'assignees', issueId: undefined, value: [node] }, payload: { prop: 'assignees', itemId: undefined, value: [node] },
}, },
], ],
[], [],
...@@ -949,7 +949,7 @@ describe('addListIssue', () => { ...@@ -949,7 +949,7 @@ describe('addListIssue', () => {
describe('setActiveIssueLabels', () => { describe('setActiveIssueLabels', () => {
const state = { boardItems: { [mockIssue.id]: mockIssue } }; const state = { boardItems: { [mockIssue.id]: mockIssue } };
const getters = { activeIssue: mockIssue }; const getters = { activeBoardItem: mockIssue };
const testLabelIds = labels.map((label) => label.id); const testLabelIds = labels.map((label) => label.id);
const input = { const input = {
addLabelIds: testLabelIds, addLabelIds: testLabelIds,
...@@ -963,7 +963,7 @@ describe('setActiveIssueLabels', () => { ...@@ -963,7 +963,7 @@ describe('setActiveIssueLabels', () => {
.mockResolvedValue({ data: { updateIssue: { issue: { labels: { nodes: labels } } } } }); .mockResolvedValue({ data: { updateIssue: { issue: { labels: { nodes: labels } } } } });
const payload = { const payload = {
issueId: getters.activeIssue.id, itemId: getters.activeBoardItem.id,
prop: 'labels', prop: 'labels',
value: labels, value: labels,
}; };
...@@ -974,7 +974,7 @@ describe('setActiveIssueLabels', () => { ...@@ -974,7 +974,7 @@ describe('setActiveIssueLabels', () => {
{ ...state, ...getters }, { ...state, ...getters },
[ [
{ {
type: types.UPDATE_ISSUE_BY_ID, type: types.UPDATE_BOARD_ITEM_BY_ID,
payload, payload,
}, },
], ],
...@@ -994,7 +994,7 @@ describe('setActiveIssueLabels', () => { ...@@ -994,7 +994,7 @@ describe('setActiveIssueLabels', () => {
describe('setActiveIssueDueDate', () => { describe('setActiveIssueDueDate', () => {
const state = { boardItems: { [mockIssue.id]: mockIssue } }; const state = { boardItems: { [mockIssue.id]: mockIssue } };
const getters = { activeIssue: mockIssue }; const getters = { activeBoardItem: mockIssue };
const testDueDate = '2020-02-20'; const testDueDate = '2020-02-20';
const input = { const input = {
dueDate: testDueDate, dueDate: testDueDate,
...@@ -1014,7 +1014,7 @@ describe('setActiveIssueDueDate', () => { ...@@ -1014,7 +1014,7 @@ describe('setActiveIssueDueDate', () => {
}); });
const payload = { const payload = {
issueId: getters.activeIssue.id, itemId: getters.activeBoardItem.id,
prop: 'dueDate', prop: 'dueDate',
value: testDueDate, value: testDueDate,
}; };
...@@ -1025,7 +1025,7 @@ describe('setActiveIssueDueDate', () => { ...@@ -1025,7 +1025,7 @@ describe('setActiveIssueDueDate', () => {
{ ...state, ...getters }, { ...state, ...getters },
[ [
{ {
type: types.UPDATE_ISSUE_BY_ID, type: types.UPDATE_BOARD_ITEM_BY_ID,
payload, payload,
}, },
], ],
...@@ -1045,7 +1045,7 @@ describe('setActiveIssueDueDate', () => { ...@@ -1045,7 +1045,7 @@ describe('setActiveIssueDueDate', () => {
describe('setActiveIssueSubscribed', () => { describe('setActiveIssueSubscribed', () => {
const state = { boardItems: { [mockActiveIssue.id]: mockActiveIssue } }; const state = { boardItems: { [mockActiveIssue.id]: mockActiveIssue } };
const getters = { activeIssue: mockActiveIssue }; const getters = { activeBoardItem: mockActiveIssue };
const subscribedState = true; const subscribedState = true;
const input = { const input = {
subscribedState, subscribedState,
...@@ -1065,7 +1065,7 @@ describe('setActiveIssueSubscribed', () => { ...@@ -1065,7 +1065,7 @@ describe('setActiveIssueSubscribed', () => {
}); });
const payload = { const payload = {
issueId: getters.activeIssue.id, itemId: getters.activeBoardItem.id,
prop: 'subscribed', prop: 'subscribed',
value: subscribedState, value: subscribedState,
}; };
...@@ -1076,7 +1076,7 @@ describe('setActiveIssueSubscribed', () => { ...@@ -1076,7 +1076,7 @@ describe('setActiveIssueSubscribed', () => {
{ ...state, ...getters }, { ...state, ...getters },
[ [
{ {
type: types.UPDATE_ISSUE_BY_ID, type: types.UPDATE_BOARD_ITEM_BY_ID,
payload, payload,
}, },
], ],
...@@ -1096,7 +1096,7 @@ describe('setActiveIssueSubscribed', () => { ...@@ -1096,7 +1096,7 @@ describe('setActiveIssueSubscribed', () => {
describe('setActiveIssueMilestone', () => { describe('setActiveIssueMilestone', () => {
const state = { boardItems: { [mockIssue.id]: mockIssue } }; const state = { boardItems: { [mockIssue.id]: mockIssue } };
const getters = { activeIssue: mockIssue }; const getters = { activeBoardItem: mockIssue };
const testMilestone = { const testMilestone = {
...mockMilestone, ...mockMilestone,
id: 'gid://gitlab/Milestone/1', id: 'gid://gitlab/Milestone/1',
...@@ -1119,7 +1119,7 @@ describe('setActiveIssueMilestone', () => { ...@@ -1119,7 +1119,7 @@ describe('setActiveIssueMilestone', () => {
}); });
const payload = { const payload = {
issueId: getters.activeIssue.id, itemId: getters.activeBoardItem.id,
prop: 'milestone', prop: 'milestone',
value: testMilestone, value: testMilestone,
}; };
...@@ -1130,7 +1130,7 @@ describe('setActiveIssueMilestone', () => { ...@@ -1130,7 +1130,7 @@ describe('setActiveIssueMilestone', () => {
{ ...state, ...getters }, { ...state, ...getters },
[ [
{ {
type: types.UPDATE_ISSUE_BY_ID, type: types.UPDATE_BOARD_ITEM_BY_ID,
payload, payload,
}, },
], ],
...@@ -1150,7 +1150,7 @@ describe('setActiveIssueMilestone', () => { ...@@ -1150,7 +1150,7 @@ describe('setActiveIssueMilestone', () => {
describe('setActiveIssueTitle', () => { describe('setActiveIssueTitle', () => {
const state = { boardItems: { [mockIssue.id]: mockIssue } }; const state = { boardItems: { [mockIssue.id]: mockIssue } };
const getters = { activeIssue: mockIssue }; const getters = { activeBoardItem: mockIssue };
const testTitle = 'Test Title'; const testTitle = 'Test Title';
const input = { const input = {
title: testTitle, title: testTitle,
...@@ -1170,7 +1170,7 @@ describe('setActiveIssueTitle', () => { ...@@ -1170,7 +1170,7 @@ describe('setActiveIssueTitle', () => {
}); });
const payload = { const payload = {
issueId: getters.activeIssue.id, itemId: getters.activeBoardItem.id,
prop: 'title', prop: 'title',
value: testTitle, value: testTitle,
}; };
...@@ -1181,7 +1181,7 @@ describe('setActiveIssueTitle', () => { ...@@ -1181,7 +1181,7 @@ describe('setActiveIssueTitle', () => {
{ ...state, ...getters }, { ...state, ...getters },
[ [
{ {
type: types.UPDATE_ISSUE_BY_ID, type: types.UPDATE_BOARD_ITEM_BY_ID,
payload, payload,
}, },
], ],
...@@ -1325,7 +1325,7 @@ describe('toggleBoardItemMultiSelection', () => { ...@@ -1325,7 +1325,7 @@ describe('toggleBoardItemMultiSelection', () => {
testAction( testAction(
actions.toggleBoardItemMultiSelection, actions.toggleBoardItemMultiSelection,
boardItem2, boardItem2,
{ activeId: mockActiveIssue.id, activeIssue: mockActiveIssue, selectedBoardItems: [] }, { activeId: mockActiveIssue.id, activeBoardItem: mockActiveIssue, selectedBoardItems: [] },
[ [
{ {
type: types.ADD_BOARD_ITEM_TO_SELECTION, type: types.ADD_BOARD_ITEM_TO_SELECTION,
......
...@@ -88,7 +88,7 @@ describe('Boards - Getters', () => { ...@@ -88,7 +88,7 @@ describe('Boards - Getters', () => {
}); });
}); });
describe('activeIssue', () => { describe('activeBoardItem', () => {
it.each` it.each`
id | expected id | expected
${'1'} | ${'issue'} ${'1'} | ${'issue'}
...@@ -96,7 +96,7 @@ describe('Boards - Getters', () => { ...@@ -96,7 +96,7 @@ describe('Boards - Getters', () => {
`('returns $expected when $id is passed to state', ({ id, expected }) => { `('returns $expected when $id is passed to state', ({ id, expected }) => {
const state = { boardItems: { 1: 'issue' }, activeId: id }; const state = { boardItems: { 1: 'issue' }, activeId: id };
expect(getters.activeIssue(state)).toEqual(expected); expect(getters.activeBoardItem(state)).toEqual(expected);
}); });
}); });
...@@ -105,14 +105,14 @@ describe('Boards - Getters', () => { ...@@ -105,14 +105,14 @@ describe('Boards - Getters', () => {
const mockActiveIssue = { const mockActiveIssue = {
referencePath: 'gitlab-org/gitlab-test#1', referencePath: 'gitlab-org/gitlab-test#1',
}; };
expect(getters.groupPathForActiveIssue({}, { activeIssue: mockActiveIssue })).toEqual( expect(getters.groupPathForActiveIssue({}, { activeBoardItem: mockActiveIssue })).toEqual(
'gitlab-org', 'gitlab-org',
); );
}); });
it('returns empty string as group path when active issue is an empty object', () => { it('returns empty string as group path when active issue is an empty object', () => {
const mockActiveIssue = {}; const mockActiveIssue = {};
expect(getters.groupPathForActiveIssue({}, { activeIssue: mockActiveIssue })).toEqual(''); expect(getters.groupPathForActiveIssue({}, { activeBoardItem: mockActiveIssue })).toEqual('');
}); });
}); });
...@@ -121,14 +121,16 @@ describe('Boards - Getters', () => { ...@@ -121,14 +121,16 @@ describe('Boards - Getters', () => {
const mockActiveIssue = { const mockActiveIssue = {
referencePath: 'gitlab-org/gitlab-test#1', referencePath: 'gitlab-org/gitlab-test#1',
}; };
expect(getters.projectPathForActiveIssue({}, { activeIssue: mockActiveIssue })).toEqual( expect(getters.projectPathForActiveIssue({}, { activeBoardItem: mockActiveIssue })).toEqual(
'gitlab-org/gitlab-test', 'gitlab-org/gitlab-test',
); );
}); });
it('returns empty string as project path when active issue is an empty object', () => { it('returns empty string as project path when active issue is an empty object', () => {
const mockActiveIssue = {}; const mockActiveIssue = {};
expect(getters.projectPathForActiveIssue({}, { activeIssue: mockActiveIssue })).toEqual(''); expect(getters.projectPathForActiveIssue({}, { activeBoardItem: mockActiveIssue })).toEqual(
'',
);
}); });
}); });
......
...@@ -335,7 +335,7 @@ describe('Board Store Mutations', () => { ...@@ -335,7 +335,7 @@ describe('Board Store Mutations', () => {
expectNotImplemented(mutations.REQUEST_ADD_ISSUE); expectNotImplemented(mutations.REQUEST_ADD_ISSUE);
}); });
describe('UPDATE_ISSUE_BY_ID', () => { describe('UPDATE_BOARD_ITEM_BY_ID', () => {
const issueId = '1'; const issueId = '1';
const prop = 'id'; const prop = 'id';
const value = '2'; const value = '2';
...@@ -353,8 +353,8 @@ describe('Board Store Mutations', () => { ...@@ -353,8 +353,8 @@ describe('Board Store Mutations', () => {
describe('when the issue is in state', () => { describe('when the issue is in state', () => {
it('updates the property of the correct issue', () => { it('updates the property of the correct issue', () => {
mutations.UPDATE_ISSUE_BY_ID(state, { mutations.UPDATE_BOARD_ITEM_BY_ID(state, {
issueId, itemId: issueId,
prop, prop,
value, value,
}); });
...@@ -366,8 +366,8 @@ describe('Board Store Mutations', () => { ...@@ -366,8 +366,8 @@ describe('Board Store Mutations', () => {
describe('when the issue is not in state', () => { describe('when the issue is not in state', () => {
it('throws an error', () => { it('throws an error', () => {
expect(() => { expect(() => {
mutations.UPDATE_ISSUE_BY_ID(state, { mutations.UPDATE_BOARD_ITEM_BY_ID(state, {
issueId: '3', itemId: '3',
prop, prop,
value, value,
}); });
......
...@@ -8,19 +8,19 @@ RSpec.shared_examples 'issue boards sidebar' do ...@@ -8,19 +8,19 @@ RSpec.shared_examples 'issue boards sidebar' do
end end
it 'shows sidebar when clicking issue' do it 'shows sidebar when clicking issue' do
expect(page).to have_selector('.issue-boards-sidebar') expect(page).to have_selector('[data-testid="issue-boards-sidebar"]')
end end
it 'closes sidebar when clicking issue' do it 'closes sidebar when clicking issue' do
expect(page).to have_selector('.issue-boards-sidebar') expect(page).to have_selector('[data-testid="issue-boards-sidebar"]')
first_card.click first_card.click
expect(page).not_to have_selector('.issue-boards-sidebar') expect(page).not_to have_selector('[data-testid="issue-boards-sidebar"]')
end end
it 'shows issue details when sidebar is open', :aggregate_failures do it 'shows issue details when sidebar is open', :aggregate_failures do
page.within('.issue-boards-sidebar') do page.within('[data-testid="issue-boards-sidebar"]') do
expect(page).to have_content(issue.title) expect(page).to have_content(issue.title)
expect(page).to have_content(issue.to_reference) expect(page).to have_content(issue.to_reference)
end end
...@@ -28,7 +28,7 @@ RSpec.shared_examples 'issue boards sidebar' do ...@@ -28,7 +28,7 @@ RSpec.shared_examples 'issue boards sidebar' do
context 'when clicking close button' do context 'when clicking close button' do
before do before do
find("[data-testid='sidebar-drawer'] .gl-drawer-close-button").click find('[data-testid="issue-boards-sidebar"] .gl-drawer-close-button').click
end end
it 'unhighlights the active issue card' do it 'unhighlights the active issue card' do
...@@ -37,7 +37,7 @@ RSpec.shared_examples 'issue boards sidebar' do ...@@ -37,7 +37,7 @@ RSpec.shared_examples 'issue boards sidebar' do
end end
it 'closes sidebar when clicking close button' do it 'closes sidebar when clicking close button' do
expect(page).not_to have_selector('.issue-boards-sidebar') expect(page).not_to have_selector('[data-testid="issue-boards-sidebar"]')
end end
end end
......
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