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
529831ec
Commit
529831ec
authored
Nov 16, 2020
by
Eulyeon Ko
Committed by
Simon Knox
Nov 16, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add notifications toggle to swimlanes sidebar
parent
a5032437
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
405 additions
and
30 deletions
+405
-30
app/assets/javascripts/boards/components/sidebar/board_sidebar_due_date.vue
...ipts/boards/components/sidebar/board_sidebar_due_date.vue
+2
-6
app/assets/javascripts/boards/components/sidebar/board_sidebar_labels_select.vue
...boards/components/sidebar/board_sidebar_labels_select.vue
+5
-9
app/assets/javascripts/boards/components/sidebar/board_sidebar_subscription.vue
.../boards/components/sidebar/board_sidebar_subscription.vue
+71
-0
app/assets/javascripts/boards/graphql/mutations/issue_set_subscription.mutation.graphql
...graphql/mutations/issue_set_subscription.mutation.graphql
+8
-0
app/assets/javascripts/boards/stores/actions.js
app/assets/javascripts/boards/stores/actions.js
+24
-0
app/assets/javascripts/boards/stores/getters.js
app/assets/javascripts/boards/stores/getters.js
+5
-0
app/helpers/notifications_helper.rb
app/helpers/notifications_helper.rb
+1
-0
ee/app/assets/javascripts/boards/components/board_content_sidebar.vue
...s/javascripts/boards/components/board_content_sidebar.vue
+3
-0
ee/app/assets/javascripts/boards/components/sidebar/board_sidebar_epic_select.vue
...s/boards/components/sidebar/board_sidebar_epic_select.vue
+4
-8
ee/app/assets/javascripts/boards/components/sidebar/board_sidebar_weight_input.vue
.../boards/components/sidebar/board_sidebar_weight_input.vue
+2
-6
ee/app/assets/javascripts/boards/queries/issue.fragment.graphql
.../assets/javascripts/boards/queries/issue.fragment.graphql
+1
-0
ee/spec/features/boards/swimlanes/epics_swimlanes_sidebar_spec.rb
...features/boards/swimlanes/epics_swimlanes_sidebar_spec.rb
+42
-1
ee/spec/frontend/boards/components/board_content_sidebar_spec.js
.../frontend/boards/components/board_content_sidebar_spec.js
+1
-0
locale/gitlab.pot
locale/gitlab.pot
+3
-0
spec/frontend/boards/components/sidebar/board_sidebar_subscription_spec.js
...rds/components/sidebar/board_sidebar_subscription_spec.js
+157
-0
spec/frontend/boards/mock_data.js
spec/frontend/boards/mock_data.js
+8
-0
spec/frontend/boards/stores/actions_spec.js
spec/frontend/boards/stores/actions_spec.js
+52
-0
spec/frontend/boards/stores/getters_spec.js
spec/frontend/boards/stores/getters_spec.js
+16
-0
No files found.
app/assets/javascripts/boards/components/sidebar/board_sidebar_due_date.vue
View file @
529831ec
...
...
@@ -18,7 +18,7 @@ export default {
};
},
computed
:
{
...
mapGetters
({
issue
:
'
activeIssue
'
}),
...
mapGetters
({
issue
:
'
activeIssue
'
,
projectPathForActiveIssue
:
'
projectPathForActiveIssue
'
}),
hasDueDate
()
{
return
this
.
issue
.
dueDate
!=
null
;
},
...
...
@@ -36,10 +36,6 @@ export default {
return
dateInWords
(
this
.
parsedDueDate
,
true
);
},
projectPath
()
{
const
referencePath
=
this
.
issue
.
referencePath
||
''
;
return
referencePath
.
slice
(
0
,
referencePath
.
indexOf
(
'
#
'
));
},
},
methods
:
{
...
mapActions
([
'
setActiveIssueDueDate
'
]),
...
...
@@ -53,7 +49,7 @@ export default {
try
{
const
dueDate
=
date
?
formatDate
(
date
,
'
yyyy-mm-dd
'
)
:
null
;
await
this
.
setActiveIssueDueDate
({
dueDate
,
projectPath
:
this
.
projectPath
});
await
this
.
setActiveIssueDueDate
({
dueDate
,
projectPath
:
this
.
projectPath
ForActiveIssue
});
}
catch
(
e
)
{
createFlash
({
message
:
this
.
$options
.
i18n
.
updateDueDateError
});
}
finally
{
...
...
app/assets/javascripts/boards/components/sidebar/board_sidebar_labels_select.vue
View file @
529831ec
...
...
@@ -21,9 +21,9 @@ export default {
},
inject
:
[
'
labelsFetchPath
'
,
'
labelsManagePath
'
,
'
labelsFilterBasePath
'
],
computed
:
{
...
mapGetters
(
{
issue
:
'
activeIssue
'
}
),
...
mapGetters
(
[
'
activeIssue
'
,
'
projectPathForActiveIssue
'
]
),
selectedLabels
()
{
const
{
labels
=
[]
}
=
this
.
i
ssue
;
const
{
labels
=
[]
}
=
this
.
activeI
ssue
;
return
labels
.
map
(
label
=>
({
...
label
,
...
...
@@ -31,17 +31,13 @@ export default {
}));
},
issueLabels
()
{
const
{
labels
=
[]
}
=
this
.
i
ssue
;
const
{
labels
=
[]
}
=
this
.
activeI
ssue
;
return
labels
.
map
(
label
=>
({
...
label
,
scoped
:
isScopedLabel
(
label
),
}));
},
projectPath
()
{
const
{
referencePath
=
''
}
=
this
.
issue
;
return
referencePath
.
slice
(
0
,
referencePath
.
indexOf
(
'
#
'
));
},
},
methods
:
{
...
mapActions
([
'
setActiveIssueLabels
'
]),
...
...
@@ -55,7 +51,7 @@ export default {
.
filter
(
label
=>
!
payload
.
find
(
selected
=>
selected
.
id
===
label
.
id
))
.
map
(
label
=>
label
.
id
);
const
input
=
{
addLabelIds
,
removeLabelIds
,
projectPath
:
this
.
projectPath
};
const
input
=
{
addLabelIds
,
removeLabelIds
,
projectPath
:
this
.
projectPath
ForActiveIssue
};
await
this
.
setActiveIssueLabels
(
input
);
}
catch
(
e
)
{
createFlash
({
message
:
__
(
'
An error occurred while updating labels.
'
)
});
...
...
@@ -68,7 +64,7 @@ export default {
try
{
const
removeLabelIds
=
[
getIdFromGraphQLId
(
id
)];
const
input
=
{
removeLabelIds
,
projectPath
:
this
.
projectPath
};
const
input
=
{
removeLabelIds
,
projectPath
:
this
.
projectPath
ForActiveIssue
};
await
this
.
setActiveIssueLabels
(
input
);
}
catch
(
e
)
{
createFlash
({
message
:
__
(
'
An error occurred when removing the label.
'
)
});
...
...
app/assets/javascripts/boards/components/sidebar/board_sidebar_subscription.vue
0 → 100644
View file @
529831ec
<
script
>
import
{
mapGetters
,
mapActions
}
from
'
vuex
'
;
import
{
GlToggle
}
from
'
@gitlab/ui
'
;
import
createFlash
from
'
~/flash
'
;
import
{
__
,
s__
}
from
'
~/locale
'
;
export
default
{
i18n
:
{
header
:
{
title
:
__
(
'
Notifications
'
),
/* Any change to subscribeDisabledDescription
must be reflected in app/helpers/notifications_helper.rb */
subscribeDisabledDescription
:
__
(
'
Notifications have been disabled by the project or group owner
'
,
),
},
updateSubscribedErrorMessage
:
s__
(
'
IssueBoards|An error occurred while setting notifications status.
'
,
),
},
components
:
{
GlToggle
,
},
data
()
{
return
{
loading
:
false
,
};
},
computed
:
{
...
mapGetters
([
'
activeIssue
'
,
'
projectPathForActiveIssue
'
]),
notificationText
()
{
return
this
.
activeIssue
.
emailsDisabled
?
this
.
$options
.
i18n
.
header
.
subscribeDisabledDescription
:
this
.
$options
.
i18n
.
header
.
title
;
},
},
methods
:
{
...
mapActions
([
'
setActiveIssueSubscribed
'
]),
async
handleToggleSubscription
()
{
this
.
loading
=
true
;
try
{
await
this
.
setActiveIssueSubscribed
({
subscribed
:
!
this
.
activeIssue
.
subscribed
,
projectPath
:
this
.
projectPathForActiveIssue
,
});
}
catch
(
error
)
{
createFlash
({
message
:
this
.
$options
.
i18n
.
updateSubscribedErrorMessage
});
}
finally
{
this
.
loading
=
false
;
}
},
},
};
</
script
>
<
template
>
<div
class=
"gl-display-flex gl-align-items-center gl-justify-content-space-between"
data-testid=
"sidebar-notifications"
>
<span
data-testid=
"notification-header-text"
>
{{
notificationText
}}
</span>
<gl-toggle
v-if=
"!activeIssue.emailsDisabled"
:value=
"activeIssue.subscribed"
:is-loading=
"loading"
data-testid=
"notification-subscribe-toggle"
@
change=
"handleToggleSubscription"
/>
</div>
</
template
>
app/assets/javascripts/boards/graphql/mutations/issue_set_subscription.mutation.graphql
0 → 100644
View file @
529831ec
mutation
issueSetSubscription
(
$input
:
IssueSetSubscriptionInput
!)
{
issueSetSubscription
(
input
:
$input
)
{
issue
{
subscribed
}
errors
}
}
app/assets/javascripts/boards/stores/actions.js
View file @
529831ec
...
...
@@ -24,6 +24,7 @@ import destroyBoardListMutation from '../queries/board_list_destroy.mutation.gra
import
issueCreateMutation
from
'
../queries/issue_create.mutation.graphql
'
;
import
issueSetLabels
from
'
../queries/issue_set_labels.mutation.graphql
'
;
import
issueSetDueDate
from
'
../queries/issue_set_due_date.mutation.graphql
'
;
import
issueSetSubscriptionMutation
from
'
../graphql/mutations/issue_set_subscription.mutation.graphql
'
;
const
notImplemented
=
()
=>
{
/* eslint-disable-next-line @gitlab/require-i18n-strings */
...
...
@@ -420,6 +421,29 @@ export default {
});
},
setActiveIssueSubscribed
:
async
({
commit
,
getters
},
input
)
=>
{
const
{
data
}
=
await
gqlClient
.
mutate
({
mutation
:
issueSetSubscriptionMutation
,
variables
:
{
input
:
{
iid
:
String
(
getters
.
activeIssue
.
iid
),
projectPath
:
input
.
projectPath
,
subscribedState
:
input
.
subscribed
,
},
},
});
if
(
data
.
issueSetSubscription
?.
errors
?.
length
>
0
)
{
throw
new
Error
(
data
.
issueSetSubscription
.
errors
);
}
commit
(
types
.
UPDATE_ISSUE_BY_ID
,
{
issueId
:
getters
.
activeIssue
.
id
,
prop
:
'
subscribed
'
,
value
:
data
.
issueSetSubscription
.
issue
.
subscribed
,
});
},
fetchBacklog
:
()
=>
{
notImplemented
();
},
...
...
app/assets/javascripts/boards/stores/getters.js
View file @
529831ec
...
...
@@ -24,6 +24,11 @@ export default {
return
state
.
issues
[
state
.
activeId
]
||
{};
},
projectPathForActiveIssue
:
(
_
,
getters
)
=>
{
const
referencePath
=
getters
.
activeIssue
.
referencePath
||
''
;
return
referencePath
.
slice
(
0
,
referencePath
.
indexOf
(
'
#
'
));
},
getListByLabelId
:
state
=>
labelId
=>
{
return
find
(
state
.
boardLists
,
l
=>
l
.
label
?.
id
===
labelId
);
},
...
...
app/helpers/notifications_helper.rb
View file @
529831ec
...
...
@@ -67,6 +67,7 @@ module NotificationsHelper
when
:custom
_
(
'You will only receive notifications for the events you choose'
)
when
:owner_disabled
# Any change must be reflected in board_sidebar_subscription.vue
_
(
'Notifications have been disabled by the project or group owner'
)
end
end
...
...
ee/app/assets/javascripts/boards/components/board_content_sidebar.vue
View file @
529831ec
...
...
@@ -11,6 +11,7 @@ import BoardSidebarTimeTracker from './sidebar/board_sidebar_time_tracker.vue';
import
BoardSidebarWeightInput
from
'
./sidebar/board_sidebar_weight_input.vue
'
;
import
BoardSidebarLabelsSelect
from
'
~/boards/components/sidebar/board_sidebar_labels_select.vue
'
;
import
BoardSidebarDueDate
from
'
~/boards/components/sidebar/board_sidebar_due_date.vue
'
;
import
BoardSidebarSubscription
from
'
~/boards/components/sidebar/board_sidebar_subscription.vue
'
;
export
default
{
headerHeight
:
`
${
contentTop
()}
px`
,
...
...
@@ -23,6 +24,7 @@ export default {
BoardSidebarWeightInput
,
BoardSidebarLabelsSelect
,
BoardSidebarDueDate
,
BoardSidebarSubscription
,
},
mixins
:
[
glFeatureFlagsMixin
()],
computed
:
{
...
...
@@ -56,6 +58,7 @@ export default {
<board-sidebar-weight-input
v-if=
"glFeatures.issueWeights"
/>
<board-sidebar-labels-select
/>
<board-sidebar-due-date
/>
<board-sidebar-subscription
/>
</
template
>
</gl-drawer>
</template>
ee/app/assets/javascripts/boards/components/sidebar/board_sidebar_epic_select.vue
View file @
529831ec
...
...
@@ -20,9 +20,9 @@ export default {
inject
:
[
'
groupId
'
],
computed
:
{
...
mapState
([
'
epics
'
]),
...
mapGetters
(
{
getEpicById
:
'
getEpicById
'
,
issue
:
'
activeIssue
'
}
),
...
mapGetters
(
[
'
activeIssue
'
,
'
getEpicById
'
,
'
projectPathForActiveIssue
'
]
),
storedEpic
()
{
const
storedEpic
=
this
.
getEpicById
(
this
.
i
ssue
.
epic
?.
id
);
const
storedEpic
=
this
.
getEpicById
(
this
.
activeI
ssue
.
epic
?.
id
);
const
epicId
=
getIdFromGraphQLId
(
storedEpic
?.
id
);
return
{
...
...
@@ -30,10 +30,6 @@ export default {
id
:
Number
(
epicId
),
};
},
projectPath
()
{
const
{
referencePath
=
''
}
=
this
.
issue
;
return
referencePath
.
slice
(
0
,
referencePath
.
indexOf
(
'
#
'
));
},
},
methods
:
{
...
mapMutations
({
...
...
@@ -51,7 +47,7 @@ export default {
const
epicId
=
selectedEpic
?.
id
?
`gid://gitlab/Epic/
${
selectedEpic
.
id
}
`
:
null
;
const
input
=
{
epicId
,
projectPath
:
this
.
projectPath
,
projectPath
:
this
.
projectPath
ForActiveIssue
,
};
try
{
...
...
@@ -62,7 +58,7 @@ export default {
}
debounceByAnimationFrame
(()
=>
{
this
.
updateIssueById
({
issueId
:
this
.
i
ssue
.
id
,
prop
:
'
epic
'
,
value
:
epic
});
this
.
updateIssueById
({
issueId
:
this
.
activeI
ssue
.
id
,
prop
:
'
epic
'
,
value
:
epic
});
this
.
loading
=
false
;
})();
}
catch
(
e
)
{
...
...
ee/app/assets/javascripts/boards/components/sidebar/board_sidebar_weight_input.vue
View file @
529831ec
...
...
@@ -23,14 +23,10 @@ export default {
};
},
computed
:
{
...
mapGetters
({
issue
:
'
activeIssue
'
}),
...
mapGetters
({
issue
:
'
activeIssue
'
,
projectPathForActiveIssue
:
'
projectPathForActiveIssue
'
}),
hasWeight
()
{
return
this
.
issue
.
weight
>
0
;
},
projectPath
()
{
const
{
referencePath
=
''
}
=
this
.
issue
;
return
referencePath
.
slice
(
0
,
referencePath
.
indexOf
(
'
#
'
));
},
},
watch
:
{
issue
:
{
...
...
@@ -56,7 +52,7 @@ export default {
this
.
loading
=
true
;
try
{
await
this
.
setActiveIssueWeight
({
weight
,
projectPath
:
this
.
projectPath
});
await
this
.
setActiveIssueWeight
({
weight
,
projectPath
:
this
.
projectPath
ForActiveIssue
});
this
.
weight
=
weight
;
}
catch
(
e
)
{
this
.
weight
=
this
.
issue
.
weight
;
...
...
ee/app/assets/javascripts/boards/queries/issue.fragment.graphql
View file @
529831ec
...
...
@@ -10,6 +10,7 @@ fragment IssueNode on Issue {
totalTimeSpent
humanTimeEstimate
humanTotalTimeSpent
emailsDisabled
weight
confidential
webUrl
...
...
ee/spec/features/boards/swimlanes/epics_swimlanes_sidebar_spec.rb
View file @
529831ec
...
...
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec
.
describe
'epics swimlanes sidebar'
,
:js
do
let_it_be
(
:user
)
{
create
(
:user
)
}
let_it_be
(
:group
)
{
create
(
:group
,
:public
)
}
let_it_be
(
:project
)
{
create
(
:project
,
:public
,
group:
group
)
}
let_it_be
(
:project
,
reload:
true
)
{
create
(
:project
,
:public
,
group:
group
)
}
let_it_be
(
:board
)
{
create
(
:board
,
project:
project
)
}
let_it_be
(
:list
)
{
create
(
:list
,
board:
board
,
position:
0
)
}
...
...
@@ -31,6 +31,47 @@ RSpec.describe 'epics swimlanes sidebar', :js do
wait_for_all_requests
end
context
'notifications subscription'
do
it
'displays notifications toggle'
do
click_first_issue_card
page
.
within
(
'[data-testid="sidebar-notifications"]'
)
do
expect
(
page
).
to
have_selector
(
'[data-testid="notification-subscribe-toggle"]'
)
expect
(
page
).
to
have_content
(
'Notifications'
)
expect
(
page
).
not_to
have_content
(
'Notifications have been disabled by the project or group owner'
)
end
end
it
'shows toggle as on then as off as user toggles to subscribe and unsubscribe'
do
click_first_issue_card
toggle
=
find
(
'[data-testid="notification-subscribe-toggle"]'
)
toggle
.
click
expect
(
toggle
).
to
have_css
(
"button.is-checked"
)
toggle
.
click
expect
(
toggle
).
not_to
have_css
(
"button.is-checked"
)
end
context
'when notifications have been disabled'
do
before
do
project
.
update_attribute
(
:emails_disabled
,
true
)
end
it
'displays a message that notifications have been disabled'
do
click_first_issue_card
page
.
within
(
'[data-testid="sidebar-notifications"]'
)
do
expect
(
page
).
not_to
have_selector
(
'[data-testid="notification-subscribe-toggle"]'
)
expect
(
page
).
to
have_content
(
'Notifications have been disabled by the project or group owner'
)
end
end
end
end
context
'time tracking'
do
it
'displays time tracking feature with default message'
do
click_first_issue_card
...
...
ee/spec/frontend/boards/components/board_content_sidebar_spec.js
View file @
529831ec
...
...
@@ -24,6 +24,7 @@ describe('ee/BoardContentSidebar', () => {
'
board-sidebar-weight-input
'
:
'
<div></div>
'
,
'
board-sidebar-labels-select
'
:
'
<div></div>
'
,
'
board-sidebar-due-date
'
:
'
<div></div>
'
,
'
board-sidebar-subscription
'
:
'
<div></div>
'
,
},
});
};
...
...
locale/gitlab.pot
View file @
529831ec
...
...
@@ -15089,6 +15089,9 @@ msgstr ""
msgid "IssueAnalytics|Weight"
msgstr ""
msgid "IssueBoards|An error occurred while setting notifications status."
msgstr ""
msgid "IssueBoards|Board"
msgstr ""
...
...
spec/frontend/boards/components/sidebar/board_sidebar_subscription_spec.js
0 → 100644
View file @
529831ec
import
Vuex
from
'
vuex
'
;
import
{
mount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
{
GlToggle
,
GlLoadingIcon
}
from
'
@gitlab/ui
'
;
import
BoardSidebarSubscription
from
'
~/boards/components/sidebar/board_sidebar_subscription.vue
'
;
import
*
as
types
from
'
~/boards/stores/mutation_types
'
;
import
{
createStore
}
from
'
~/boards/stores
'
;
import
{
mockActiveIssue
}
from
'
../../mock_data
'
;
import
createFlash
from
'
~/flash
'
;
jest
.
mock
(
'
~/flash.js
'
);
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
describe
(
'
~/boards/components/sidebar/board_sidebar_subscription_spec.vue
'
,
()
=>
{
let
wrapper
;
let
store
;
const
findNotificationHeader
=
()
=>
wrapper
.
find
(
"
[data-testid='notification-header-text']
"
);
const
findToggle
=
()
=>
wrapper
.
find
(
GlToggle
);
const
findGlLoadingIcon
=
()
=>
wrapper
.
find
(
GlLoadingIcon
);
const
createComponent
=
(
activeIssue
=
{
...
mockActiveIssue
})
=>
{
store
=
createStore
();
store
.
state
.
issues
=
{
[
activeIssue
.
id
]:
activeIssue
};
store
.
state
.
activeId
=
activeIssue
.
id
;
wrapper
=
mount
(
BoardSidebarSubscription
,
{
localVue
,
store
,
});
};
afterEach
(()
=>
{
wrapper
.
destroy
();
wrapper
=
null
;
store
=
null
;
jest
.
clearAllMocks
();
});
describe
(
'
Board sidebar subscription component template
'
,
()
=>
{
it
(
'
displays "notifications" heading
'
,
()
=>
{
createComponent
();
expect
(
findNotificationHeader
().
text
()).
toBe
(
'
Notifications
'
);
});
it
(
'
renders toggle as "off" when currently not subscribed
'
,
()
=>
{
createComponent
();
expect
(
findToggle
().
exists
()).
toBe
(
true
);
expect
(
findToggle
().
props
(
'
value
'
)).
toBe
(
false
);
});
it
(
'
renders toggle as "on" when currently subscribed
'
,
()
=>
{
createComponent
({
...
mockActiveIssue
,
subscribed
:
true
,
});
expect
(
findToggle
().
exists
()).
toBe
(
true
);
expect
(
findToggle
().
props
(
'
value
'
)).
toBe
(
true
);
});
describe
(
'
when notification emails have been disabled
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
...
mockActiveIssue
,
emailsDisabled
:
true
,
});
});
it
(
'
displays a message that notification have been disabled
'
,
()
=>
{
expect
(
findNotificationHeader
().
text
()).
toBe
(
'
Notifications have been disabled by the project or group owner
'
,
);
});
it
(
'
does not render the toggle button
'
,
()
=>
{
expect
(
findToggle
().
exists
()).
toBe
(
false
);
});
});
});
describe
(
'
Board sidebar subscription component `behavior`
'
,
()
=>
{
const
mockSetActiveIssueSubscribed
=
subscribedState
=>
{
jest
.
spyOn
(
wrapper
.
vm
,
'
setActiveIssueSubscribed
'
).
mockImplementation
(
async
()
=>
{
store
.
commit
(
types
.
UPDATE_ISSUE_BY_ID
,
{
issueId
:
mockActiveIssue
.
id
,
prop
:
'
subscribed
'
,
value
:
subscribedState
,
});
});
};
it
(
'
subscribing to notification
'
,
async
()
=>
{
createComponent
();
mockSetActiveIssueSubscribed
(
true
);
expect
(
findGlLoadingIcon
().
exists
()).
toBe
(
false
);
findToggle
().
trigger
(
'
click
'
);
await
wrapper
.
vm
.
$nextTick
();
expect
(
findGlLoadingIcon
().
exists
()).
toBe
(
true
);
expect
(
wrapper
.
vm
.
setActiveIssueSubscribed
).
toHaveBeenCalledWith
({
subscribed
:
true
,
projectPath
:
'
gitlab-org/test-subgroup/gitlab-test
'
,
});
await
wrapper
.
vm
.
$nextTick
();
expect
(
findGlLoadingIcon
().
exists
()).
toBe
(
false
);
expect
(
findToggle
().
props
(
'
value
'
)).
toBe
(
true
);
});
it
(
'
unsubscribing from notification
'
,
async
()
=>
{
createComponent
({
...
mockActiveIssue
,
subscribed
:
true
,
});
mockSetActiveIssueSubscribed
(
false
);
expect
(
findGlLoadingIcon
().
exists
()).
toBe
(
false
);
findToggle
().
trigger
(
'
click
'
);
await
wrapper
.
vm
.
$nextTick
();
expect
(
wrapper
.
vm
.
setActiveIssueSubscribed
).
toHaveBeenCalledWith
({
subscribed
:
false
,
projectPath
:
'
gitlab-org/test-subgroup/gitlab-test
'
,
});
expect
(
findGlLoadingIcon
().
exists
()).
toBe
(
true
);
await
wrapper
.
vm
.
$nextTick
();
expect
(
findGlLoadingIcon
().
exists
()).
toBe
(
false
);
expect
(
findToggle
().
props
(
'
value
'
)).
toBe
(
false
);
});
it
(
'
flashes an error message when setting the subscribed state fails
'
,
async
()
=>
{
createComponent
();
jest
.
spyOn
(
wrapper
.
vm
,
'
setActiveIssueSubscribed
'
).
mockImplementation
(
async
()
=>
{
throw
new
Error
();
});
findToggle
().
trigger
(
'
click
'
);
await
wrapper
.
vm
.
$nextTick
();
expect
(
createFlash
).
toHaveBeenNthCalledWith
(
1
,
{
message
:
wrapper
.
vm
.
$options
.
i18n
.
updateSubscribedErrorMessage
,
});
});
});
});
spec/frontend/boards/mock_data.js
View file @
529831ec
...
...
@@ -176,6 +176,14 @@ export const mockIssue = {
},
};
export
const
mockActiveIssue
=
{
...
mockIssue
,
id
:
436
,
iid
:
'
27
'
,
subscribed
:
false
,
emailsDisabled
:
false
,
};
export
const
mockIssueWithModel
=
new
ListIssue
(
mockIssue
);
export
const
mockIssue2
=
{
...
...
spec/frontend/boards/stores/actions_spec.js
View file @
529831ec
...
...
@@ -9,6 +9,7 @@ import {
rawIssue
,
mockIssues
,
labels
,
mockActiveIssue
,
}
from
'
../mock_data
'
;
import
actions
,
{
gqlClient
}
from
'
~/boards/stores/actions
'
;
import
*
as
types
from
'
~/boards/stores/mutation_types
'
;
...
...
@@ -833,6 +834,57 @@ describe('setActiveIssueDueDate', () => {
});
});
describe
(
'
setActiveIssueSubscribed
'
,
()
=>
{
const
state
=
{
issues
:
{
[
mockActiveIssue
.
id
]:
mockActiveIssue
}
};
const
getters
=
{
activeIssue
:
mockActiveIssue
};
const
subscribedState
=
true
;
const
input
=
{
subscribedState
,
projectPath
:
'
gitlab-org/gitlab-test
'
,
};
it
(
'
should commit subscribed status
'
,
done
=>
{
jest
.
spyOn
(
gqlClient
,
'
mutate
'
).
mockResolvedValue
({
data
:
{
issueSetSubscription
:
{
issue
:
{
subscribed
:
subscribedState
,
},
errors
:
[],
},
},
});
const
payload
=
{
issueId
:
getters
.
activeIssue
.
id
,
prop
:
'
subscribed
'
,
value
:
subscribedState
,
};
testAction
(
actions
.
setActiveIssueSubscribed
,
input
,
{
...
state
,
...
getters
},
[
{
type
:
types
.
UPDATE_ISSUE_BY_ID
,
payload
,
},
],
[],
done
,
);
});
it
(
'
throws error if fails
'
,
async
()
=>
{
jest
.
spyOn
(
gqlClient
,
'
mutate
'
)
.
mockResolvedValue
({
data
:
{
issueSetSubscription
:
{
errors
:
[
'
failed mutation
'
]
}
}
});
await
expect
(
actions
.
setActiveIssueSubscribed
({
getters
},
input
)).
rejects
.
toThrow
(
Error
);
});
});
describe
(
'
fetchBacklog
'
,
()
=>
{
expectNotImplemented
(
actions
.
fetchBacklog
);
});
...
...
spec/frontend/boards/stores/getters_spec.js
View file @
529831ec
...
...
@@ -124,6 +124,22 @@ describe('Boards - Getters', () => {
});
});
describe('projectPathByIssueId', () => {
it('returns project path for the active issue', () => {
const mockActiveIssue = {
referencePath: 'gitlab-org/gitlab-test#1',
};
expect(getters.projectPathForActiveIssue({}, { activeIssue: mockActiveIssue })).toEqual(
'gitlab-org/gitlab-test',
);
});
it('returns empty string as project when active issue is an empty object', () => {
const mockActiveIssue = {};
expect(getters.projectPathForActiveIssue({}, { activeIssue: mockActiveIssue })).toEqual('');
});
});
describe('getIssuesByList', () => {
const boardsState = {
issuesByListId: mockIssuesByListId,
...
...
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