-
Notifications
You must be signed in to change notification settings - Fork 2
Feat/events multiselect bulk actions #640
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 17 commits
ec4350a
42287da
40ca14d
0593ed3
dd309a5
9a0fc08
7ed3481
d497afd
dd84f03
ace53d0
530adaa
c212292
049bace
f250de5
ccd4a7e
6535527
93fd728
94d4e84
f2ab338
81a682f
c271563
57582bd
1e13972
2e9fba0
0ee4684
c4963c4
bf64ade
ae8d3dc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,11 @@ | ||
| const getEventsFactory = require('./helpers/eventsFactory').default; | ||
| const sendPersonalNotification = require('../utils/personalNotifications').default; | ||
| const { | ||
| fireAndForgetAssigneeNotifications, | ||
| parseBulkEventIds, | ||
| mergeFailedEventIds, | ||
| } = require('./helpers/bulkEvents'); | ||
| const { aiService } = require('../services/ai'); | ||
| const { UserInputError } = require('apollo-server-express'); | ||
|
|
||
| /** | ||
| * See all types and fields here {@see ../typeDefs/event.graphql} | ||
|
|
@@ -135,6 +140,34 @@ module.exports = { | |
|
|
||
| return !!result.acknowledged; | ||
| }, | ||
| /** | ||
| * Mark many original events as visited for current user | ||
| * | ||
| * @param {ResolverObj} _obj - resolver context | ||
| * @param {string} projectId - project id | ||
| * @param {string[]} eventIds - original event ids | ||
| * @param {UserInContext} user - user context | ||
| * @returns {Promise<{ updatedCount: number, updatedEventIds: string[], failedEventIds: string[] }>} | ||
| */ | ||
| async bulkVisitEvents(_obj, { projectId, eventIds }, { user, ...context }) { | ||
| const { validEventIds, invalidEventIds } = parseBulkEventIds(eventIds); | ||
|
|
||
| if (validEventIds.length === 0) { | ||
| return { | ||
| updatedCount: 0, | ||
| updatedEventIds: [], | ||
| failedEventIds: invalidEventIds, | ||
| }; | ||
| } | ||
|
|
||
| const factory = getEventsFactory(context, projectId); | ||
| const result = await factory.bulkVisitEvent(validEventIds, user.id); | ||
|
|
||
| return { | ||
| ...result, | ||
| failedEventIds: mergeFailedEventIds(result, invalidEventIds), | ||
| }; | ||
| }, | ||
|
|
||
| /** | ||
| * Mark event with one of the event marks | ||
|
|
@@ -153,6 +186,37 @@ module.exports = { | |
| return !!result.acknowledged; | ||
| }, | ||
|
|
||
| /** | ||
| * Bulk set resolved/ignored: always set mark on events that lack it, unless all selected | ||
| * already have the mark — then remove from all. | ||
| * | ||
| * @param {ResolverObj} _obj - resolver context | ||
| * @param {string} projectId - project id | ||
| * @param {string[]} eventIds - original event ids | ||
| * @param {string} mark - EventMark enum value | ||
| * @param {object} context - gql context | ||
| * @return {Promise<{ updatedCount: number, updatedEventIds: string[], failedEventIds: string[] }>} | ||
| */ | ||
| async bulkToggleEventMarks(_obj, { projectId, eventIds, mark }, context) { | ||
| const { validEventIds, invalidEventIds } = parseBulkEventIds(eventIds); | ||
|
|
||
| if (validEventIds.length === 0) { | ||
| return { | ||
| updatedCount: 0, | ||
| updatedEventIds: [], | ||
| failedEventIds: invalidEventIds, | ||
| }; | ||
| } | ||
|
|
||
| const factory = getEventsFactory(context, projectId); | ||
| const result = await factory.bulkToggleEventMark(validEventIds, mark); | ||
|
|
||
| return { | ||
| ...result, | ||
| failedEventIds: mergeFailedEventIds(result, invalidEventIds), | ||
| }; | ||
| }, | ||
|
|
||
| /** | ||
| * Mutations namespace | ||
| * | ||
|
|
@@ -196,14 +260,12 @@ module.exports = { | |
|
|
||
| const assigneeData = await factories.usersFactory.dataLoaders.userById.load(assignee); | ||
|
|
||
| await sendPersonalNotification(assigneeData, { | ||
| type: 'assignee', | ||
| payload: { | ||
| assigneeId: assignee, | ||
| projectId, | ||
| whoAssignedId: user.id, | ||
| eventId, | ||
| }, | ||
| fireAndForgetAssigneeNotifications({ | ||
| assigneeData, | ||
| eventIds: [ eventId ], | ||
| projectId, | ||
| assigneeId: assignee, | ||
| whoAssignedId: user.id, | ||
| }); | ||
|
|
||
| return { | ||
|
|
@@ -230,5 +292,65 @@ module.exports = { | |
| success: !!result.acknowledged, | ||
| }; | ||
| }, | ||
|
|
||
| /** | ||
| * Bulk set/clear assignee for selected original events | ||
| * | ||
| * @param {ResolverObj} _obj - resolver context | ||
| * @param {BulkUpdateAssigneeInput} input - object of arguments | ||
| * @param factories - factories for working with models | ||
| * @return {Promise<{ updatedCount: number, updatedEventIds: string[], failedEventIds: string[] }>} | ||
| */ | ||
| async bulkUpdateAssignee(_obj, { input }, { factories, user, ...context }) { | ||
| const { projectId, eventIds, assignee } = input; | ||
| const { validEventIds, invalidEventIds } = parseBulkEventIds(eventIds); | ||
| let assigneeData = null; | ||
|
|
||
| if (validEventIds.length === 0) { | ||
| return { | ||
| updatedCount: 0, | ||
| updatedEventIds: [], | ||
| failedEventIds: invalidEventIds, | ||
| }; | ||
| } | ||
|
|
||
| const factory = getEventsFactory(context, projectId); | ||
|
|
||
| if (assignee) { | ||
| const userExists = await factories.usersFactory.findById(assignee); | ||
|
|
||
| if (!userExists) { | ||
| throw new UserInputError('assignee not found'); | ||
| } | ||
|
Comment on lines
+295
to
+304
|
||
|
|
||
| assigneeData = userExists; | ||
|
|
||
| const project = await factories.projectsFactory.findById(projectId); | ||
| const workspace = await factories.workspacesFactory.findById(project.workspaceId); | ||
| const assigneeExistsInWorkspace = await workspace.getMemberInfo(assignee); | ||
|
|
||
| if (!assigneeExistsInWorkspace) { | ||
| throw new UserInputError('assignee is not a workspace member'); | ||
| } | ||
| } | ||
|
|
||
| const result = await factory.bulkUpdateAssignee(validEventIds, assignee); | ||
| const resultWithInvalid = { | ||
| ...result, | ||
| failedEventIds: mergeFailedEventIds(result, invalidEventIds), | ||
| }; | ||
|
|
||
| if (assignee && resultWithInvalid.updatedEventIds.length > 0) { | ||
| fireAndForgetAssigneeNotifications({ | ||
| assigneeData, | ||
| eventIds: resultWithInvalid.updatedEventIds, | ||
| projectId, | ||
| assigneeId: assignee, | ||
| whoAssignedId: user.id, | ||
| }); | ||
| } | ||
|
|
||
| return resultWithInvalid; | ||
| }, | ||
| }, | ||
| }; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.