From 944b3c6638577536a13bc26b0400b96f87397e5e Mon Sep 17 00:00:00 2001 From: Jackie Jou Date: Mon, 18 May 2026 10:56:36 -0700 Subject: [PATCH] fix(activity-feed-v2): Read resolvedBy and resolvedAt from resolution The transformer was reading modified_by/modified_at to populate the resolvedBy and resolvedAt fields on the V2 row, which is wrong whenever the item was edited after being resolved. Both UAA and the legacy update endpoint return a resolution object with resolved_at and resolved_by, so read those instead. --- src/common/types/annotations.js | 6 ++ src/common/types/feed.js | 4 +- .../__tests__/transformers.test.ts | 57 ++++++++++++++++++- .../activity-feed-v2/transformers.ts | 10 ++-- 4 files changed, 69 insertions(+), 8 deletions(-) diff --git a/src/common/types/annotations.js b/src/common/types/annotations.js index 815277a699..0bd39eac32 100644 --- a/src/common/types/annotations.js +++ b/src/common/types/annotations.js @@ -56,6 +56,11 @@ export type AnnotationPermission = { can_resolve?: boolean, }; +export type Resolution = { + resolved_at?: string | null, + resolved_by?: User | null, +}; + export type Annotation = { created_at: string, created_by: User, @@ -69,6 +74,7 @@ export type Annotation = { modified_by: User, permissions: AnnotationPermission, replies?: Array, + resolution?: Resolution | null, status?: FeedItemStatus, target: Target, total_reply_count?: number, diff --git a/src/common/types/feed.js b/src/common/types/feed.js index 9c9901b76d..d9985d238a 100644 --- a/src/common/types/feed.js +++ b/src/common/types/feed.js @@ -19,7 +19,7 @@ import { FILE_ACTIVITY_TYPE_VERSION, } from '../../constants'; import type { BoxItemPermission, BoxItemVersion, Reply, User } from './core'; -import type { Annotation, AnnotationPermission, Annotations } from './annotations'; +import type { Annotation, AnnotationPermission, Annotations, Resolution } from './annotations'; import type { TaskNew } from './tasks'; type FeedItemType = @@ -84,6 +84,7 @@ type Comment = { }, permissions: BoxCommentPermission, replies?: Array, + resolution?: Resolution | null, status?: FeedItemStatus, tagged_message: string, total_reply_count?: number, @@ -230,6 +231,7 @@ export type { FocusableFeedItem, FocusableFeedItemType, Reply, + Resolution, Task, Tasks, ThreadedComments, diff --git a/src/elements/content-sidebar/activity-feed-v2/__tests__/transformers.test.ts b/src/elements/content-sidebar/activity-feed-v2/__tests__/transformers.test.ts index 10e5f394b2..f173dbdfbd 100644 --- a/src/elements/content-sidebar/activity-feed-v2/__tests__/transformers.test.ts +++ b/src/elements/content-sidebar/activity-feed-v2/__tests__/transformers.test.ts @@ -507,7 +507,33 @@ describe('elements/content-sidebar/activity-feed-v2/transformers', () => { expect(result!.type).toBe('app_activity'); }); - test('should set isResolved true for resolved comments', () => { + test('should set isResolved, resolvedBy, and resolvedAt for resolved comments from the resolution field', () => { + const comment = { + created_at: '2024-01-01T00:00:00Z', + created_by: { id: '1', name: 'Author', type: 'user' }, + id: 'c1', + message: '', + modified_at: '2024-01-02T00:00:00Z', + modified_by: { id: '2', name: 'Editor', type: 'user' }, + permissions: {}, + resolution: { + resolved_at: '2024-01-03T00:00:00Z', + resolved_by: { id: '3', name: 'Resolver', type: 'user' }, + }, + status: 'resolved', + tagged_message: 'Resolved comment', + type: 'comment', + }; + const result = transformFeedItem(comment as unknown as FeedItem); + expect(result!.type).toBe('comment'); + if (result!.type === 'comment') { + expect(result!.isResolved).toBe(true); + expect(result!.resolvedBy).toBe('Resolver'); + expect(result!.resolvedAt).toBe(new Date('2024-01-03T00:00:00Z').getTime()); + } + }); + + test('should leave resolvedBy and resolvedAt undefined when a resolved comment has no resolution field', () => { const comment = { created_at: '2024-01-01T00:00:00Z', created_by: { id: '1', name: 'User', type: 'user' }, @@ -523,6 +549,35 @@ describe('elements/content-sidebar/activity-feed-v2/transformers', () => { expect(result!.type).toBe('comment'); if (result!.type === 'comment') { expect(result!.isResolved).toBe(true); + expect(result!.resolvedBy).toBeUndefined(); + expect(result!.resolvedAt).toBeUndefined(); + } + }); + + test('should set resolvedBy and resolvedAt for resolved annotations from the resolution field', () => { + const annotation = { + created_at: '2024-01-01T00:00:00Z', + created_by: { id: '1', name: 'Author', type: 'user' }, + description: { message: 'Annotation' }, + file_version: { id: 'fv1', type: 'version', version_number: '1' }, + id: 'a1', + modified_at: '2024-01-02T00:00:00Z', + modified_by: { id: '2', name: 'Editor', type: 'user' }, + permissions: {}, + resolution: { + resolved_at: '2024-01-03T00:00:00Z', + resolved_by: { id: '3', name: 'Resolver', type: 'user' }, + }, + status: 'resolved', + target: { location: { type: 'page', value: 1 }, type: 'point', x: 0, y: 0 }, + type: 'annotation', + }; + const result = transformFeedItem(annotation as unknown as FeedItem); + expect(result!.type).toBe('annotation'); + if (result!.type === 'annotation') { + expect(result!.isResolved).toBe(true); + expect(result!.resolvedBy).toBe('Resolver'); + expect(result!.resolvedAt).toBe(new Date('2024-01-03T00:00:00Z').getTime()); } }); }); diff --git a/src/elements/content-sidebar/activity-feed-v2/transformers.ts b/src/elements/content-sidebar/activity-feed-v2/transformers.ts index ef64ec5785..19c4c61a03 100644 --- a/src/elements/content-sidebar/activity-feed-v2/transformers.ts +++ b/src/elements/content-sidebar/activity-feed-v2/transformers.ts @@ -253,10 +253,8 @@ export const transformFeedItem = (item: FeedItem, currentUserId?: string): Trans messages: transformCommentToMessages(comment), originalText: comment.tagged_message || comment.message || '', permissions: comment.permissions ?? {}, - resolvedAt: commentIsResolved ? toUnixMs(comment.modified_at) : undefined, - resolvedBy: commentIsResolved - ? (comment as unknown as { modified_by?: { name?: string } }).modified_by?.name - : undefined, + resolvedAt: commentIsResolved ? toUnixMs(comment.resolution?.resolved_at) : undefined, + resolvedBy: commentIsResolved ? comment.resolution?.resolved_by?.name : undefined, status: comment.status, type: 'comment', }; @@ -270,8 +268,8 @@ export const transformFeedItem = (item: FeedItem, currentUserId?: string): Trans isResolved: annotationIsResolved, messages: transformAnnotationToMessages(annotation), permissions: annotation.permissions ?? {}, - resolvedAt: annotationIsResolved ? toUnixMs(annotation.modified_at) : undefined, - resolvedBy: annotationIsResolved ? annotation.modified_by?.name : undefined, + resolvedAt: annotationIsResolved ? toUnixMs(annotation.resolution?.resolved_at) : undefined, + resolvedBy: annotationIsResolved ? annotation.resolution?.resolved_by?.name : undefined, status: annotation.status, type: 'annotation', };