Skip to content

Feat/events multiselect bulk actions#640

Open
Dobrunia wants to merge 28 commits intomasterfrom
feat/events-multiselect-bulk-actions
Open

Feat/events multiselect bulk actions#640
Dobrunia wants to merge 28 commits intomasterfrom
feat/events-multiselect-bulk-actions

Conversation

@Dobrunia
Copy link
Copy Markdown
Member

Summary

Introduces multi-select on the project daily events list with a bulk action bar

Comment thread src/constants/demoWorkspace.ts Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unexpected change

Comment thread src/models/eventsFactory.js Outdated
Comment on lines +921 to +926
/**
* Max original event ids per bulkToggleEventMark request
*/
static get BULK_TOGGLE_EVENT_MARK_MAX() {
return 100;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

specify exact problem

Comment thread src/models/eventsFactory.js Outdated
Comment on lines +940 to +942
if (mark !== 'resolved' && mark !== 'ignored' && mark !== 'starred') {
throw new Error(`bulkToggleEventMark: mark must be resolved, ignored or starred, got ${mark}`);
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

validation should be on resolver level (or via graphql schema)

Comment thread src/models/eventsFactory.js
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds backend support and test coverage for multi-select bulk actions on events, including bulk visit, bulk mark toggle, and bulk assignee updates.

Changes:

  • Introduces new GraphQL mutations/types for bulk visiting events, bulk toggling marks, and bulk updating assignees.
  • Adds resolver/helper logic to validate/dedupe bulk IDs, merge invalid IDs into failedEventIds, and enqueue assignee notifications asynchronously.
  • Implements EventsFactory bulk operations and adds Jest tests for resolvers/helpers/factory methods.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
test/resolvers/event-bulk-visit.test.ts Adds resolver tests for bulkVisitEvents validation + failed ID merging
test/resolvers/event-bulk-update-assignee.test.ts Adds resolver tests for EventsMutations.bulkUpdateAssignee and notification enqueueing
test/resolvers/event-bulk-toggle-marks.test.ts Adds resolver tests for bulkToggleEventMarks semantics + validation
test/resolvers/bulk-events-helper.test.ts Adds helper tests for fire-and-forget notification enqueueing
test/models/eventsFactory-bulk-visit.test.ts Adds model tests for EventsFactory.bulkVisitEvent
test/models/eventsFactory-bulk-update-assignee.test.ts Adds model tests for EventsFactory.bulkUpdateAssignee
test/models/eventsFactory-bulk-toggle.test.ts Adds model tests for EventsFactory.bulkToggleEventMark
src/typeDefs/event.ts Adds new GraphQL inputs/types/mutations for bulk operations
src/resolvers/helpers/bulkEvents.js Adds bulk ID parsing/merging helpers + async notification enqueue helper
src/resolvers/event.js Wires new bulk mutations and switches assignee notification sending to fire-and-forget
src/models/eventsFactory.js Implements bulk visit, bulk mark toggle, bulk assignee update, and shared resolver for bulk IDs
package.json Bumps package version

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/typeDefs/event.ts Outdated

"""
Toggle the same mark on many original events at once (resolved, ignored or starred).
Same toggle semantics as toggleEventMark per event.
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mutation comment says “Same toggle semantics as toggleEventMark per event”, but this bulk operation has different semantics (it only clears when all selected already have the mark). Please adjust the docstring so clients don’t assume per-event toggling behavior.

Suggested change
Same toggle semantics as toggleEventMark per event.
Uses bulk semantics: if every selected event already has the mark, clear it for all;
otherwise set it on each selected event that does not have it yet.

Copilot uses AI. Check for mistakes.
Comment thread src/typeDefs/event.ts Outdated
Comment on lines +492 to +513
type BulkToggleEventMarksResult {
"""
Number of events updated in the database
"""
updatedCount: Int!

"""
Original event ids actually toggled in this operation
"""
updatedEventIds: [ID!]!

"""
Event ids that were not updated (invalid id or not found)
"""
failedEventIds: [ID!]!
}

"""
Result of bulk marking events as viewed
"""
type BulkVisitEventsResult {
"""
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type naming is inconsistent: the file predominantly uses *Response (e.g., UpdateAssigneeResponse, BulkUpdateAssigneeResponse), but these new types use *Result. Consider renaming them to BulkToggleEventMarksResponse / BulkVisitEventsResponse (or switching all bulk types to *Result) to keep the public GraphQL schema consistent.

Copilot uses AI. Check for mistakes.
Comment thread src/resolvers/helpers/bulkEvents.js Outdated
Comment on lines +29 to +37
Promise.allSettled(eventIds.map(eventId => sendPersonalNotification(assigneeData, {
type: 'assignee',
payload: {
assigneeId,
projectId,
whoAssignedId,
eventId,
},
})))
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Promise.allSettled(eventIds.map(...)) will fire all notification enqueues at once. With large bulk selections this can create an unbounded burst of RabbitMQ enqueue calls and memory pressure. Consider batching/chunking or applying a concurrency limit (e.g., a small pool) while still keeping the resolver non-blocking.

Copilot uses AI. Check for mistakes.
Comment thread src/resolvers/helpers/bulkEvents.js Outdated
Comment on lines +38 to +47
.then((results) => {
const failedResults = results.filter(result => result.status === 'rejected');

if (failedResults.length > 0) {
console.error('Failed to enqueue assignee notifications', failedResults);
}
})
.catch((error) => {
console.error('Failed to enqueue assignee notifications', error);
});
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

failedResults may contain raw rejection reasons from enqueue (potentially including endpoints or other sensitive details). Logging the full array could leak data into logs; consider logging only counts + sanitized error messages, or at least logging reason.message without payload details.

Copilot uses AI. Check for mistakes.
Comment thread src/resolvers/event.js
Comment on lines +319 to +324
if (assignee) {
const userExists = await factories.usersFactory.findById(assignee);

if (!userExists) {
throw new UserInputError('assignee not found');
}
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assignee is only checked for truthiness. If the client passes an invalid ID (or an empty string), usersFactory.findById() will throw from new ObjectId(id) inside the dataloader instead of returning a controlled UserInputError. Validate assignee explicitly (e.g., ObjectId.isValid) and treat empty string as invalid since the API contract says “pass null to clear”.

Copilot uses AI. Check for mistakes.
Comment thread src/typeDefs/event.ts Outdated
Comment thread src/models/eventsFactory.js Outdated
* @param {string|ObjectId} userId - id of the user who is visiting events
* @returns {Promise<{ updatedCount: number, updatedEventIds: string[], failedEventIds: string[] }>}
*/
async bulkVisitEvent(eventIds, userId) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
async bulkVisitEvent(eventIds, userId) {
async bulkVisitEvents(eventIds, userId) {

@codecov-commenter
Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.04478% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 44.27%. Comparing base (0f8dad9) to head (81a682f).
⚠️ Report is 42 commits behind head on master.

Files with missing lines Patch % Lines
src/resolvers/helpers/bulkEvents.js 79.48% 5 Missing and 3 partials ⚠️
src/resolvers/event.js 92.85% 3 Missing ⚠️
src/models/eventsFactory.js 98.11% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           master     #640       +/-   ##
===========================================
- Coverage   58.30%   44.27%   -14.04%     
===========================================
  Files          19       52       +33     
  Lines         518     2487     +1969     
  Branches       95      527      +432     
===========================================
+ Hits          302     1101      +799     
- Misses        216     1311     +1095     
- Partials        0       75       +75     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@Dobrunia Dobrunia requested review from FeironoX5 and slaveeks April 24, 2026 09:09
…ount from responses and enhancing error handling
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants