Skip to content

feat(activity-feed-v2): sync sidebar timestamps with video time format#4636

Merged
mergify[bot] merged 3 commits into
box:masterfrom
kduncanhsu:kduncanhsu/sync-timestamp-to-comments
Jun 18, 2026
Merged

feat(activity-feed-v2): sync sidebar timestamps with video time format#4636
mergify[bot] merged 3 commits into
box:masterfrom
kduncanhsu:kduncanhsu/sync-timestamp-to-comments

Conversation

@kduncanhsu

@kduncanhsu kduncanhsu commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Sidebar comment timestamps (editor checkbox and posted comment badges) now respect the time format selected in the video player controls (standard, timecode, or frame numbers)
  • Adds useTimeFormat hook that observes data-time-format and data-fps attributes on .bp-media-container via MutationObserver
  • Adds convertMillisecondsToTimecode and convertMillisecondsToFrames to timestamp utils

Test plan

  • All existing tests pass (264 total across activity-feed-v2 + timestamp utils)
  • New useTimeFormat hook tests (11 tests) — initial read, reactive updates, late container, fallbacks, disable reset
  • New useVideoTimestamp format integration tests (4 tests) — timecode/frames formatting, live format switch
  • New FeedItemRow badge format tests (6 tests) — comment/annotation badges update per format
  • New timestamp utils tests (11 tests) — convertMillisecondsToTimecode and convertMillisecondsToFrames
  • Manual: open video with sidebar, change time format dropdown, verify checkbox timestamp and posted comment badges update

Summary by CodeRabbit

Release Notes

  • New Features

    • Activity feed items with video now display timestamps in the active timing mode: standard, timecode (HH:MM:SS:FF), or frames—including correct updates when timing settings change or become available after load.
  • Tests

    • Added/updated automated coverage for time-format selection, FPS fallbacks, formatting correctness for timecode/frames, and dynamic rerender behavior in the activity feed timestamp rendering.

@kduncanhsu
kduncanhsu requested review from a team as code owners June 16, 2026 23:08
@CLAassistant

CLAassistant commented Jun 16, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds video-aware timestamp formatting to the activity feed. New convertMillisecondsToTimecode and convertMillisecondsToFrames utilities are added to src/utils/timestamp.ts with a DEFAULT_VIDEO_FPS constant. A new useTimeFormat hook reads data-time-format and data-fps from .bp-media-container via MutationObserver. useVideoTimestamp and FeedItemRow consume this hook to render timecode or frame-count timestamps when video content is active.

Changes

Video Timestamp Formatting

Layer / File(s) Summary
New timestamp conversion utilities
src/constants.js, src/utils/timestamp.ts, src/utils/__tests__/timestamp.test.js
Adds DEFAULT_VIDEO_FPS constant and exports convertMillisecondsToTimecode (HH:MM:SS:FF) and convertMillisecondsToFrames utilities to the timestamp module with comprehensive edge-case test coverage.
useTimeFormat hook and formatByTimeFormat utility
src/elements/content-sidebar/activity-feed-v2/useTimeFormat.ts, src/elements/content-sidebar/activity-feed-v2/__tests__/useTimeFormat.test.tsx
New hook reads data-time-format/data-fps from .bp-media-container using MutationObservers; formatByTimeFormat dispatches to the correct converter. Full unit tests including late-container and reset scenarios.
useVideoTimestamp updated to use useTimeFormat
src/elements/content-sidebar/activity-feed-v2/useVideoTimestamp.ts, src/elements/content-sidebar/activity-feed-v2/__tests__/useVideoTimestamp.test.tsx
Replaces convertMillisecondsToTimestamp with formatByTimeFormat driven by timeFormat and fps parameters. Integration tests verify timecode, frames, dynamic format switching, and default-format paths.
FeedItemRow video timestamp formatting
src/elements/content-sidebar/activity-feed-v2/FeedItemRow.tsx, src/elements/content-sidebar/activity-feed-v2/__tests__/FeedItemRow.test.tsx
Adds fps and timeFormat props; comment and frame-annotation rendering conditionally inject formatted timestamps via formatByTimeFormat. Test suite verifies format conversion and fallback behavior.
ActivityFeedV2 video format coordination
src/elements/content-sidebar/activity-feed-v2/ActivityFeedV2.tsx
Derives isVideo flag from file.extension using FILE_EXTENSIONS.video, calls useTimeFormat(isVideo) to compute timeFormat and fps, and passes both down to useVideoTimestamp and each FeedItemRow instance.

Sequence Diagram(s)

sequenceDiagram
  participant ActivityFeedV2
  participant FeedItemRow
  participant useTimeFormat
  participant bp-media-container
  participant formatByTimeFormat

  ActivityFeedV2->>FeedItemRow: timeFormat, fps
  FeedItemRow->>formatByTimeFormat: formatByTimeFormat(annotationTimestampMs, timeFormat, fps)
  formatByTimeFormat-->>FeedItemRow: formatted timestamp string
  FeedItemRow-->>ActivityFeedV2: renders ThreadedAnnotation with formatted timestamp
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • box/box-ui-elements#4575: Both PRs update Activity Feed v2's handling/rendering of frame-based annotation timestamps—the retrieved PR adds frame target + annotationTargetToBadge timestamp generation, while the main PR changes FeedItemRow to re-format/override those frame-derived timestamps using timeFormat/fps.
  • box/box-ui-elements#4611: Both PRs update the activity-feed-v2 comment timestamp badge pipeline by wiring/deriving annotationTarget for comment items and then formatting the badge timestamp, so the main PR's FeedItemRow/time-format changes are directly related to the retrieved PR's timestamp-badge behavior.
  • box/box-ui-elements#4620: Both PRs modify the Activity Feed v2 video timestamp pipeline—useVideoTimestamp and FeedItemRow—by extending timestamp markup handling and updating how video timestamps are captured/used, including changing useVideoTimestamp's signature in the main PR to incorporate timeFormat/fps.

Suggested reviewers

  • ahorowitz123
  • jmcbgaston

Poem

🐇 Hop hop, the timestamps now sing,
In timecode and frames, a video thing!
The media container whispers its fps,
The MutationObserver does all the rest.
No more plain seconds — we're frame-perfect today,
This bunny approves of the video-aware way! 🎬

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description provides a comprehensive summary of changes, implementation details, and test coverage; however, it does not follow the repository's description template structure. Consider following the repository's PR template structure while maintaining the detailed technical summary already provided.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding video time format synchronization to sidebar timestamps in the activity-feed-v2 component.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
src/utils/__tests__/timestamp.test.js (1)

93-155: ⚡ Quick win

Add fractional-FPS coverage for timecode/frame conversions.

Current cases are integer-FPS only. Since data-fps is parsed as a number upstream, add at least one 29.97 case to lock expected behavior and prevent player/sidebar drift regressions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/__tests__/timestamp.test.js` around lines 93 - 155, The test suite
for convertMillisecondsToTimecode and convertMillisecondsToFrames lacks coverage
for fractional FPS values (such as 29.97), which can be passed as numbers from
upstream data-fps parsing. Add at least one test case within each describe block
that tests a fractional FPS value like 29.97 to ensure the conversion functions
handle non-integer frame rates correctly and prevent player/sidebar drift
regressions. Include test cases with typical fractional FPS values (29.97,
23.976) and verify that the timecode and frame calculations remain accurate.
src/elements/content-sidebar/activity-feed-v2/__tests__/FeedItemRow.test.tsx (1)

60-64: ⚡ Quick win

Reset mockTimeFormat in beforeEach to avoid cross-test state leakage.

mockTimeFormat is mutated in multiple tests but never reset. Add a deterministic reset in beforeEach so tests remain order-independent.

Suggested fix
 beforeEach(() => {
     lastThreadedAnnotationProps = {};
     lastTaskProps = {};
     lastVersionProps = {};
+    mockTimeFormat.timeFormat = 'standard';
+    mockTimeFormat.fps = 24;
     mockedSerializeEditorContent.mockReturnValue({ hasMention: false, text: 'serialized-text' });
 });

Also applies to: 213-218

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/elements/content-sidebar/activity-feed-v2/__tests__/FeedItemRow.test.tsx`
around lines 60 - 64, The mockTimeFormat object is being mutated across multiple
tests but never reset between test runs, causing state leakage and making test
execution order-dependent. Add a beforeEach block that resets mockTimeFormat
back to its initial values (timeFormat: 'standard', fps: 24) before each test
runs to ensure consistent and isolated test behavior. This ensures the mock
object starts with known values for every test regardless of what previous tests
may have modified.
src/elements/content-sidebar/activity-feed-v2/useTimeFormat.ts (1)

50-55: 💤 Low value

Consider validating the attribute value before casting.

The type assertion as TimeFormat on line 51 bypasses TypeScript's type checking. If the DOM attribute contains an invalid value like "invalid", the cast will succeed but the runtime value won't match the TimeFormat union. While formatByTimeFormat has a default case that safely handles this, explicit validation would be more type-safe:

♻️ Suggested type-safe validation
 const readAttributes = (container: Element): void => {
-    const format = (container.getAttribute('data-time-format') as TimeFormat) || 'standard';
+    const formatAttr = container.getAttribute('data-time-format');
+    const format: TimeFormat =
+        formatAttr === 'timecode' || formatAttr === 'frames' || formatAttr === 'standard'
+            ? formatAttr
+            : 'standard';
     const fpsAttr = Number(container.getAttribute('data-fps'));
     setTimeFormat(format);
     setFps(fpsAttr > 0 ? fpsAttr : DEFAULT_FPS);
 };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/elements/content-sidebar/activity-feed-v2/useTimeFormat.ts` around lines
50 - 55, In the readAttributes function, the getAttribute call for
'data-time-format' uses a direct type assertion with `as TimeFormat` which
bypasses TypeScript type checking. Replace this unsafe cast by validating that
the retrieved attribute value is actually a valid TimeFormat value before using
it. Create a type guard or validation check that confirms the attribute value
matches one of the valid TimeFormat union values, and only apply the type
assertion after validation passes. This ensures type safety at runtime rather
than relying solely on the default case handling in downstream code.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/utils/timestamp.ts`:
- Around line 73-77: The frames calculation on line 76 uses Math.round(fps)
while the hours, minutes, and seconds calculations on lines 73-75 use the raw
fps value, creating an inconsistency that produces incorrect timecode output for
fractional frame rates like 29.97. Replace Math.round(fps) with fps in the
frames calculation to ensure all time components use the same FPS basis
throughout the timecode conversion logic.

---

Nitpick comments:
In
`@src/elements/content-sidebar/activity-feed-v2/__tests__/FeedItemRow.test.tsx`:
- Around line 60-64: The mockTimeFormat object is being mutated across multiple
tests but never reset between test runs, causing state leakage and making test
execution order-dependent. Add a beforeEach block that resets mockTimeFormat
back to its initial values (timeFormat: 'standard', fps: 24) before each test
runs to ensure consistent and isolated test behavior. This ensures the mock
object starts with known values for every test regardless of what previous tests
may have modified.

In `@src/elements/content-sidebar/activity-feed-v2/useTimeFormat.ts`:
- Around line 50-55: In the readAttributes function, the getAttribute call for
'data-time-format' uses a direct type assertion with `as TimeFormat` which
bypasses TypeScript type checking. Replace this unsafe cast by validating that
the retrieved attribute value is actually a valid TimeFormat value before using
it. Create a type guard or validation check that confirms the attribute value
matches one of the valid TimeFormat union values, and only apply the type
assertion after validation passes. This ensures type safety at runtime rather
than relying solely on the default case handling in downstream code.

In `@src/utils/__tests__/timestamp.test.js`:
- Around line 93-155: The test suite for convertMillisecondsToTimecode and
convertMillisecondsToFrames lacks coverage for fractional FPS values (such as
29.97), which can be passed as numbers from upstream data-fps parsing. Add at
least one test case within each describe block that tests a fractional FPS value
like 29.97 to ensure the conversion functions handle non-integer frame rates
correctly and prevent player/sidebar drift regressions. Include test cases with
typical fractional FPS values (29.97, 23.976) and verify that the timecode and
frame calculations remain accurate.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: af5d97fb-998e-4283-8020-8511d4ce4996

📥 Commits

Reviewing files that changed from the base of the PR and between 943e820 and 23e2093.

📒 Files selected for processing (9)
  • src/elements/content-sidebar/activity-feed-v2/ActivityFeedV2.tsx
  • src/elements/content-sidebar/activity-feed-v2/FeedItemRow.tsx
  • src/elements/content-sidebar/activity-feed-v2/__tests__/FeedItemRow.test.tsx
  • src/elements/content-sidebar/activity-feed-v2/__tests__/useTimeFormat.test.tsx
  • src/elements/content-sidebar/activity-feed-v2/__tests__/useVideoTimestamp.test.tsx
  • src/elements/content-sidebar/activity-feed-v2/useTimeFormat.ts
  • src/elements/content-sidebar/activity-feed-v2/useVideoTimestamp.ts
  • src/utils/__tests__/timestamp.test.js
  • src/utils/timestamp.ts

Comment thread src/utils/timestamp.ts Outdated
@kduncanhsu
kduncanhsu force-pushed the kduncanhsu/sync-timestamp-to-comments branch from 23e2093 to c4307d0 Compare June 16, 2026 23:38

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/utils/timestamp.ts`:
- Around line 86-91: The convertMillisecondsToFrames function currently
validates the timestampInMilliseconds parameter but does not validate the fps
parameter. Add validation to check if fps is a valid positive number (not zero,
negative, NaN, or Infinity) and return 0 if the fps value is invalid. This will
prevent the calculation on line 90 from producing NaN, Infinity, or other
incorrect frame counts when fps is provided with invalid values.
- Around line 68-84: The convertMillisecondsToTimecode function does not
validate the fps parameter, which can lead to incorrect timecode calculations if
fps is zero, negative, NaN, or Infinity. Add validation at the beginning of the
function to ensure fps is a valid positive finite number, and return a default
timecode (such as "00:00:00:00") if it is not. This validation will also resolve
the Math.round inconsistency where fps is rounded only in the frames calculation
but not in the hours, minutes, and seconds calculations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c675e84b-5bad-45cd-8a15-a43d28d20e37

📥 Commits

Reviewing files that changed from the base of the PR and between 23e2093 and c4307d0.

📒 Files selected for processing (9)
  • src/elements/content-sidebar/activity-feed-v2/ActivityFeedV2.tsx
  • src/elements/content-sidebar/activity-feed-v2/FeedItemRow.tsx
  • src/elements/content-sidebar/activity-feed-v2/__tests__/FeedItemRow.test.tsx
  • src/elements/content-sidebar/activity-feed-v2/__tests__/useTimeFormat.test.tsx
  • src/elements/content-sidebar/activity-feed-v2/__tests__/useVideoTimestamp.test.tsx
  • src/elements/content-sidebar/activity-feed-v2/useTimeFormat.ts
  • src/elements/content-sidebar/activity-feed-v2/useVideoTimestamp.ts
  • src/utils/__tests__/timestamp.test.js
  • src/utils/timestamp.ts
🚧 Files skipped from review as they are similar to previous changes (7)
  • src/elements/content-sidebar/activity-feed-v2/ActivityFeedV2.tsx
  • src/elements/content-sidebar/activity-feed-v2/useVideoTimestamp.ts
  • src/utils/tests/timestamp.test.js
  • src/elements/content-sidebar/activity-feed-v2/useTimeFormat.ts
  • src/elements/content-sidebar/activity-feed-v2/tests/useVideoTimestamp.test.tsx
  • src/elements/content-sidebar/activity-feed-v2/tests/FeedItemRow.test.tsx
  • src/elements/content-sidebar/activity-feed-v2/FeedItemRow.tsx

Comment thread src/utils/timestamp.ts
Comment thread src/utils/timestamp.ts
jackiejou
jackiejou previously approved these changes Jun 17, 2026
Comment thread src/elements/content-sidebar/activity-feed-v2/useVideoTimestamp.ts Outdated
Comment thread src/elements/content-sidebar/activity-feed-v2/useTimeFormat.ts Outdated
Comment thread src/elements/content-sidebar/activity-feed-v2/useTimeFormat.ts Outdated
jfox-box
jfox-box previously approved these changes Jun 17, 2026

@jfox-box jfox-box left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Overall LGTM, approved with some comments.

There are issues with CLA, you likely have to recommit with a different email or take off Claude as an author.

@kduncanhsu
kduncanhsu dismissed stale reviews from jfox-box and jackiejou via 1ba5ccc June 17, 2026 23:54
@kduncanhsu
kduncanhsu force-pushed the kduncanhsu/sync-timestamp-to-comments branch from 1ba5ccc to a42a9e5 Compare June 17, 2026 23:56

@jfox-box jfox-box left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks, LGTM!

@kduncanhsu
kduncanhsu force-pushed the kduncanhsu/sync-timestamp-to-comments branch from a42a9e5 to 813f456 Compare June 18, 2026 00:08
@kduncanhsu
kduncanhsu force-pushed the kduncanhsu/sync-timestamp-to-comments branch from 813f456 to bfc56c0 Compare June 18, 2026 00:22
@kduncanhsu
kduncanhsu requested a review from a team as a code owner June 18, 2026 00:22
@kduncanhsu
kduncanhsu force-pushed the kduncanhsu/sync-timestamp-to-comments branch from bfc56c0 to ffd7ec5 Compare June 18, 2026 00:24
Sidebar comment timestamps (both the editor checkbox and posted comment
badges) now respect the time format selected in the video player controls
(standard, timecode, or frame numbers). Communication uses data attributes
on .bp-media-container observed via MutationObserver.
@kduncanhsu
kduncanhsu force-pushed the kduncanhsu/sync-timestamp-to-comments branch from ffd7ec5 to 84e2f4c Compare June 18, 2026 00:43
@mergify mergify Bot added the queued label Jun 18, 2026
@mergify

mergify Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

  • Entered queue2026-06-18 00:53 UTC · Rule: Automatic strict merge
  • Checks skipped · PR is already up-to-date
  • Merged2026-06-18 00:53 UTC · at 84e2f4c93392d7482b613e26c834e3c8307d911c · squash

This pull request spent 11 seconds in the queue, including 1 second running CI.

Required conditions to merge

@mergify
mergify Bot merged commit 963422d into box:master Jun 18, 2026
9 of 10 checks passed
@mergify mergify Bot removed the queued label Jun 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants