From 35efc1f31a3412e4c61bb9cd87ad9c7b907aff30 Mon Sep 17 00:00:00 2001 From: Jackie Jou Date: Thu, 9 Jul 2026 16:30:39 -0700 Subject: [PATCH] feat(activity-feed-v2): add resin fileid and task modal instrumentation Tag the feed wrapper with data-resin-fileid so descendant events carry the file id. Anchor the portaled task modal with its own feature and fileid attributes. Restore the task datepicker resin target from V1. --- .../activity-feed-v2/ActivityFeedV2.tsx | 4 +++- .../__tests__/ActivityFeedV2.test.tsx | 16 +++++++++++++++- .../task-modal-v2/TaskFormV2.tsx | 3 +++ .../task-modal-v2/TaskModalV2.tsx | 4 ++++ .../task-modal-v2/__tests__/TaskFormV2.test.tsx | 12 +++++++++++- .../task-modal-v2/__tests__/TaskModalV2.test.tsx | 10 +++++++--- .../content-sidebar/activity-feed-v2/types.ts | 1 + 7 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/elements/content-sidebar/activity-feed-v2/ActivityFeedV2.tsx b/src/elements/content-sidebar/activity-feed-v2/ActivityFeedV2.tsx index 2377385b20..0d022ade17 100644 --- a/src/elements/content-sidebar/activity-feed-v2/ActivityFeedV2.tsx +++ b/src/elements/content-sidebar/activity-feed-v2/ActivityFeedV2.tsx @@ -454,7 +454,7 @@ const ActivityFeedV2 = ({ ); return ( -
+
@@ -532,6 +532,7 @@ const ActivityFeedV2 = ({ error={taskError} fetchAvatarUrls={fetchAvatarUrls} fetchUsers={fetchApprovers} + fileId={file?.id} isOpen={isTaskFormOpen} mode="edit" onClose={handleTaskModalClose} @@ -545,6 +546,7 @@ const ActivityFeedV2 = ({ error={taskError} fetchAvatarUrls={fetchAvatarUrls} fetchUsers={fetchApprovers} + fileId={file?.id} isOpen={isTaskFormOpen} onClose={handleTaskModalClose} onSubmitError={setTaskError} diff --git a/src/elements/content-sidebar/activity-feed-v2/__tests__/ActivityFeedV2.test.tsx b/src/elements/content-sidebar/activity-feed-v2/__tests__/ActivityFeedV2.test.tsx index a313210902..396df59662 100644 --- a/src/elements/content-sidebar/activity-feed-v2/__tests__/ActivityFeedV2.test.tsx +++ b/src/elements/content-sidebar/activity-feed-v2/__tests__/ActivityFeedV2.test.tsx @@ -200,6 +200,19 @@ describe('elements/content-sidebar/activity-feed-v2/ActivityFeedV2', () => { expect(screen.getByTestId('activity-feed-editor')).toBeVisible(); }); + test('should tag the feed wrapper with resin feature and fileid', () => { + const { container } = render( + , + ); + + expect(container.firstChild).toHaveAttribute('data-resin-feature', 'activityfeedv2'); + expect(container.firstChild).toHaveAttribute('data-resin-fileid', '12345'); + }); + test('should not render the list when feedItems is undefined', () => { render(); expect(screen.queryByTestId('activity-feed-list')).not.toBeInTheDocument(); @@ -1213,9 +1226,10 @@ describe('elements/content-sidebar/activity-feed-v2/ActivityFeedV2', () => { }; test('should forward create-mode props to TaskModalV2', () => { - renderFeed({ createTask: jest.fn(), onTaskUpdate: jest.fn() }); + renderFeed({ createTask: jest.fn(), file: { id: '12345' }, onTaskUpdate: jest.fn() }); expect(lastTaskModalProps.mode).toBeUndefined(); expect(lastTaskModalProps.editingTask).toBeUndefined(); + expect(lastTaskModalProps.fileId).toBe('12345'); expect(lastTaskModalProps.taskType).toBe('APPROVAL'); expect(lastTaskModalProps.isOpen).toBe(false); }); diff --git a/src/elements/content-sidebar/activity-feed-v2/task-modal-v2/TaskFormV2.tsx b/src/elements/content-sidebar/activity-feed-v2/task-modal-v2/TaskFormV2.tsx index b373b913e1..99995c505c 100644 --- a/src/elements/content-sidebar/activity-feed-v2/task-modal-v2/TaskFormV2.tsx +++ b/src/elements/content-sidebar/activity-feed-v2/task-modal-v2/TaskFormV2.tsx @@ -11,6 +11,8 @@ import { TASK_COMPLETION_RULE_ALL, TASK_COMPLETION_RULE_ANY, TASK_EDIT_MODE_EDIT import type { TaskCompletionRule, TaskEditMode, TaskType } from '../../../../common/types/tasks'; +import { ACTIVITY_TARGETS } from '../../../common/interactionTargets'; + import { mapAssigneeToUserContact, mapUserContactToAssignee } from './utils/contactMapping'; import type { TaskAssignee, TaskFormV2SubmitPayload } from './types'; @@ -198,6 +200,7 @@ const TaskFormV2 = ({ Promise; fetchUsers: (query: string) => Promise; + fileId?: string; isOpen: boolean; onClose: () => void; onSubmitError: (error: ElementsXhrError) => void; @@ -89,6 +90,7 @@ const TaskModalV2 = ({ error, fetchAvatarUrls, fetchUsers, + fileId, isOpen, onClose, onSubmitError, @@ -174,6 +176,8 @@ const TaskModalV2 = ({ diff --git a/src/elements/content-sidebar/activity-feed-v2/task-modal-v2/__tests__/TaskFormV2.test.tsx b/src/elements/content-sidebar/activity-feed-v2/task-modal-v2/__tests__/TaskFormV2.test.tsx index 935980fd14..d7fc0b2138 100644 --- a/src/elements/content-sidebar/activity-feed-v2/task-modal-v2/__tests__/TaskFormV2.test.tsx +++ b/src/elements/content-sidebar/activity-feed-v2/task-modal-v2/__tests__/TaskFormV2.test.tsx @@ -46,7 +46,12 @@ jest.mock('@box/user-selector', () => ({ }, })); -type DatePickerMockProps = { label: React.ReactNode; value?: unknown; minValue?: unknown }; +type DatePickerMockProps = { + 'data-resin-target'?: string; + label: React.ReactNode; + minValue?: unknown; + value?: unknown; +}; let lastDatePickerProps: DatePickerMockProps = { label: null }; @@ -242,6 +247,11 @@ describe('elements/content-sidebar/activity-feed-v2/task-modal-v2/TaskFormV2', ( expect(lastDatePickerProps.minValue).toBeDefined(); }); + test('tags the DatePicker with the task datepicker resin target', () => { + renderForm(); + expect(lastDatePickerProps['data-resin-target']).toBe('activityfeed-taskdatepicker'); + }); + test('omits the DatePicker minValue when editing a task whose due date is already in the past', () => { const pastDate = new Date(); pastDate.setDate(pastDate.getDate() - 7); diff --git a/src/elements/content-sidebar/activity-feed-v2/task-modal-v2/__tests__/TaskModalV2.test.tsx b/src/elements/content-sidebar/activity-feed-v2/task-modal-v2/__tests__/TaskModalV2.test.tsx index d8dc08d5c3..3891ea6de7 100644 --- a/src/elements/content-sidebar/activity-feed-v2/task-modal-v2/__tests__/TaskModalV2.test.tsx +++ b/src/elements/content-sidebar/activity-feed-v2/task-modal-v2/__tests__/TaskModalV2.test.tsx @@ -96,6 +96,7 @@ type RenderModalOptions = { editingAssignees?: TaskAssignee[]; editingTask?: TaskNew | null; error?: ElementsXhrError; + fileId?: string; isOpen?: boolean; taskType?: TaskNew['task_type']; }; @@ -309,9 +310,12 @@ describe('elements/content-sidebar/activity-feed-v2/task-modal-v2/TaskModalV2', expect(screen.getByRole('button', { name: /cancel/i })).toBeDisabled(); }); - test('tags the modal content with data-resin-component=taskmodalv2', () => { - renderModal(); - expect(screen.getByTestId('task-modal-v2')).toHaveAttribute('data-resin-component', 'taskmodalv2'); + test('tags the modal content with resin component, feature, and fileid', () => { + renderModal({ fileId: '12345' }); + const modalContent = screen.getByTestId('task-modal-v2'); + expect(modalContent).toHaveAttribute('data-resin-component', 'taskmodalv2'); + expect(modalContent).toHaveAttribute('data-resin-feature', 'activityfeedv2'); + expect(modalContent).toHaveAttribute('data-resin-fileid', '12345'); }); test('tags the Cancel and Create buttons with data-resin-target and data-target-id', () => { diff --git a/src/elements/content-sidebar/activity-feed-v2/types.ts b/src/elements/content-sidebar/activity-feed-v2/types.ts index 8a303f7457..90e5f8f5d8 100644 --- a/src/elements/content-sidebar/activity-feed-v2/types.ts +++ b/src/elements/content-sidebar/activity-feed-v2/types.ts @@ -81,6 +81,7 @@ export type TransformedFeedItem = export type ActivityFeedV2File = { extension?: string; file_version?: { id: string }; + id?: string; }; export type ViewerHandle = {