Skip to content

Commit 0593ed3

Browse files
committed
feat(events): extend bulk toggle functionality to support starred marks
1 parent 40ca14d commit 0593ed3

5 files changed

Lines changed: 69 additions & 16 deletions

File tree

src/models/eventsFactory.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -926,19 +926,19 @@ class EventsFactory extends Factory {
926926
}
927927

928928
/**
929-
* Bulk mark for resolved / ignored (not the same as per-event toggleEventMark).
929+
* Bulk mark for resolved / ignored / starred (not the same as per-event toggleEventMark).
930930
* - If every found event already has the mark: remove it from all (bulk "undo").
931931
* - Otherwise: set the mark on every found event that does not have it yet (never remove
932932
* from a subset when the selection is mixed).
933-
* Only 'resolved' and 'ignored' are allowed for bulk.
933+
* Only 'resolved', 'ignored' and 'starred' are allowed for bulk.
934934
*
935935
* @param {string[]} eventIds - original event ids
936-
* @param {string} mark - 'resolved' | 'ignored'
936+
* @param {string} mark - 'resolved' | 'ignored' | 'starred'
937937
* @returns {Promise<{ updatedCount: number, failedEventIds: string[] }>}
938938
*/
939939
async bulkToggleEventMark(eventIds, mark) {
940-
if (mark !== 'resolved' && mark !== 'ignored') {
941-
throw new Error(`bulkToggleEventMark: mark must be resolved or ignored, got ${mark}`);
940+
if (mark !== 'resolved' && mark !== 'ignored' && mark !== 'starred') {
941+
throw new Error(`bulkToggleEventMark: mark must be resolved, ignored or starred, got ${mark}`);
942942
}
943943

944944
const max = EventsFactory.BULK_TOGGLE_EVENT_MARK_MAX;

src/resolvers/event.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,8 @@ module.exports = {
167167
* @return {Promise<{ updatedCount: number, failedEventIds: string[] }>}
168168
*/
169169
async bulkToggleEventMarks(_obj, { projectId, eventIds, mark }, context) {
170-
if (mark !== 'resolved' && mark !== 'ignored') {
171-
throw new UserInputError('bulkToggleEventMarks supports only resolved and ignored marks');
170+
if (mark !== 'resolved' && mark !== 'ignored' && mark !== 'starred') {
171+
throw new UserInputError('bulkToggleEventMarks supports only resolved, ignored and starred marks');
172172
}
173173

174174
if (!eventIds || !eventIds.length) {

src/typeDefs/event.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,7 @@ extend type Mutation {
520520
): Boolean!
521521
522522
"""
523-
Toggle the same mark on many original events at once (only resolved or ignored).
523+
Toggle the same mark on many original events at once (resolved, ignored or starred).
524524
Same toggle semantics as toggleEventMark per event.
525525
"""
526526
bulkToggleEventMarks(
@@ -535,7 +535,7 @@ extend type Mutation {
535535
eventIds: [ID!]!
536536
537537
"""
538-
Mark (resolved or ignored only): if every selected event already has it, clear it for all;
538+
Mark (resolved, ignored or starred): if every selected event already has it, clear it for all;
539539
otherwise set it on every selected event that does not have it yet.
540540
"""
541541
mark: EventMark!

test/models/eventsFactory-bulk-toggle.test.ts

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,42 @@ describe('EventsFactory.bulkToggleEventMark', () => {
4949
});
5050
});
5151

52-
it('should throw when mark is not resolved or ignored', async () => {
52+
it('should throw when mark is unsupported', async () => {
5353
const factory = new EventsFactory(projectId);
5454

55-
await expect(factory.bulkToggleEventMark([], 'starred' as any)).rejects.toThrow(
56-
'bulkToggleEventMark: mark must be resolved or ignored'
55+
await expect(factory.bulkToggleEventMark([], 'some-unknown-mark' as any)).rejects.toThrow(
56+
'bulkToggleEventMark: mark must be resolved, ignored or starred'
57+
);
58+
});
59+
60+
it('should support starred mark', async () => {
61+
const factory = new EventsFactory(projectId);
62+
const id = new ObjectId();
63+
64+
collectionMock.find.mockReturnValue({
65+
toArray: () =>
66+
Promise.resolve([
67+
{
68+
_id: id,
69+
marks: {},
70+
},
71+
]),
72+
});
73+
collectionMock.bulkWrite.mockResolvedValue({
74+
modifiedCount: 1,
75+
upsertedCount: 0,
76+
});
77+
78+
const result = await factory.bulkToggleEventMark([ id.toString() ], 'starred');
79+
80+
expect(result.updatedCount).toBe(1);
81+
const ops = collectionMock.bulkWrite.mock.calls[0][0];
82+
83+
expect(ops).toHaveLength(1);
84+
expect(ops[0].updateOne.update).toEqual(
85+
expect.objectContaining({
86+
$set: { 'marks.starred': expect.any(Number) },
87+
})
5788
);
5889
});
5990

test/resolvers/event-bulk-toggle-marks.test.ts

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,22 +29,22 @@ describe('Mutation.bulkToggleEventMarks', () => {
2929
(getEventsFactory as unknown as jest.Mock).mockReturnValue({ bulkToggleEventMark });
3030
});
3131

32-
it('should throw when mark is not resolved or ignored', async () => {
32+
it('should throw when mark is not supported', async () => {
3333
await expect(
3434
eventResolvers.Mutation.bulkToggleEventMarks(
3535
{},
36-
{ projectId: 'p1', eventIds: [ '507f1f77bcf86cd799439012' ], mark: 'starred' },
36+
{ projectId: 'p1', eventIds: [ '507f1f77bcf86cd799439012' ], mark: 'some-unknown-mark' },
3737
ctx
3838
)
3939
).rejects.toThrow(UserInputError);
4040

4141
await expect(
4242
eventResolvers.Mutation.bulkToggleEventMarks(
4343
{},
44-
{ projectId: 'p1', eventIds: [ '507f1f77bcf86cd799439012' ], mark: 'starred' },
44+
{ projectId: 'p1', eventIds: [ '507f1f77bcf86cd799439012' ], mark: 'some-unknown-mark' },
4545
ctx
4646
)
47-
).rejects.toThrow('bulkToggleEventMarks supports only resolved and ignored marks');
47+
).rejects.toThrow('bulkToggleEventMarks supports only resolved, ignored and starred marks');
4848

4949
expect(bulkToggleEventMark).not.toHaveBeenCalled();
5050
});
@@ -84,6 +84,28 @@ describe('Mutation.bulkToggleEventMarks', () => {
8484
expect(result).toEqual(payload);
8585
});
8686

87+
it('should allow starred mark for bulk toggle', async () => {
88+
const payload = { updatedCount: 1, failedEventIds: [] };
89+
90+
bulkToggleEventMark.mockResolvedValue(payload);
91+
92+
const result = await eventResolvers.Mutation.bulkToggleEventMarks(
93+
{},
94+
{
95+
projectId: 'p1',
96+
eventIds: [ '507f1f77bcf86cd799439011' ],
97+
mark: 'starred',
98+
},
99+
ctx
100+
);
101+
102+
expect(bulkToggleEventMark).toHaveBeenCalledWith(
103+
[ '507f1f77bcf86cd799439011' ],
104+
'starred'
105+
);
106+
expect(result).toEqual(payload);
107+
});
108+
87109
it('should map factory max-length error to UserInputError', async () => {
88110
bulkToggleEventMark.mockRejectedValue(
89111
new Error('bulkToggleEventMark: at most 100 event ids allowed')

0 commit comments

Comments
 (0)