Skip to content

Add zoom and pan support in session detail view#1339

Open
annavik wants to merge 5 commits into
mainfrom
feat/interactive-capture-view
Open

Add zoom and pan support in session detail view#1339
annavik wants to merge 5 commits into
mainfrom
feat/interactive-capture-view

Conversation

@annavik

@annavik annavik commented Jun 17, 2026

Copy link
Copy Markdown
Member

Summary

In this PR we make it possible to zoom and pan the capture in the session detail view. This makes it possible to see more details in high res captures. Users can zoom using the mouse wheel or using button controls in UI.

The solution using the library react-zoom-pan-pinch.

Notes

We now load the original image instead of the medium thumbnail image in the session detail view. Before merge, maybe we should load both, so we can still show something quicker, but still make it possible to see all the details?

Screenshots

Screenshot 2026-06-17 at 14 43 07 Screenshot 2026-06-17 at 14 43 32

Summary by CodeRabbit

  • New Features

    • Added zoom and pan capabilities to capture image viewer, allowing users to magnify and navigate across detailed images.
    • Introduced zoom controls (zoom in, zoom out, reset) with keyboard-accessible buttons and tooltips in the session details view.
  • Style

    • Updated button styling for settings interface.

@netlify

netlify Bot commented Jun 17, 2026

Copy link
Copy Markdown

Deploy Preview for antenna-ssec ready!

Name Link
🔨 Latest commit 8cb4150
🔍 Latest deploy log https://app.netlify.com/projects/antenna-ssec/deploys/6a329aa0a62f9a0008b9e108
😎 Deploy Preview https://deploy-preview-1339--antenna-ssec.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify

netlify Bot commented Jun 17, 2026

Copy link
Copy Markdown

Deploy Preview for antenna-preview ready!

Name Link
🔨 Latest commit 8cb4150
🔍 Latest deploy log https://app.netlify.com/projects/antenna-preview/deploys/6a329aa0de1fe2000893e504
😎 Deploy Preview https://deploy-preview-1339--antenna-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 57 (🔴 down 8 from production)
Accessibility: 81 (🔴 down 8 from production)
Best Practices: 92 (🔴 down 8 from production)
SEO: 92 (no change from production)
PWA: 80 (no change from production)
View the detailed breakdown and full score reports
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@annavik annavik requested a review from mihow June 17, 2026 13:01
@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Renames the Capture model's thumbnail_small/thumbnail_medium getters to camelCase and updates all call sites. Separately, adds react-zoom-pan-pinch as a dependency and integrates zoom/pan into the session details capture viewer: a new ZoomSettings component exposes reset/zoom controls wired to a transformRef, which is threaded through Capture and SessionDetailsPage with layout and SCSS adjustments.

Changes

Thumbnail accessor rename

Layer / File(s) Summary
Capture model rename and call site updates
ui/src/data-services/models/capture.ts, ui/src/pages/captures/capture-columns.tsx, ui/src/pages/captures/capture-gallery.tsx
Renames thumbnail_small/thumbnail_medium getters to thumbnailSmall/thumbnailMedium with optional-chaining fallback and updates the captures table column and gallery image.src mapping.

Zoom/pan capture viewer

Layer / File(s) Summary
Dependency and i18n strings
ui/package.json, ui/src/utils/language.ts
Adds react-zoom-pan-pinch ^4.0.3 dependency and ZOOM_IN/ZOOM_OUT STRING enum members with English translations.
ZoomSettings component
ui/src/pages/session-details/zoom-settings.tsx
New exported component rendering reset, zoom-in, and zoom-out buttons that invoke transformRef.current methods with tooltip labels from the new string constants.
Capture component zoom/pan integration
ui/src/pages/session-details/capture/capture.tsx, ui/src/pages/session-details/capture/capture.module.scss
Adds transformRef to CaptureProps, wraps image and overlay in TransformWrapper/TransformComponent, switches layout to a Tailwind relative+aspectRatio container, and removes now-redundant SCSS rules for .image, .loadingWrapper, and .wrapper breakpoint overrides.
SessionDetails page wiring and layout
ui/src/pages/session-details/session-details.tsx, ui/src/pages/session-details/view-settings.tsx
Creates transformRef via useRef, passes it to Capture and ZoomSettings, reorganizes toolbar flex containers, updates responsive grid breakpoint classes, and changes ViewSettings trigger button variant to ghost.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 Hoppity hop, I can zoom and pan,
Pinch the capture close — yes I can!
camelCase thumbnails, neat and bright,
TransformWrapper wraps the view just right.
Reset, zoom in, zoom out with glee —
This rabbit reviews with clarity! 🔍

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description provides a summary and screenshots but lacks several required template sections: List of Changes, Related Issues, Detailed Description, How to Test, and Deployment Notes. Add missing sections: structured list of changes, related issue references, detailed explanation of implementation and potential side effects, testing instructions, and any deployment requirements.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding zoom and pan support to the session detail view, which is the primary objective of this PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/interactive-capture-view

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ui/src/pages/session-details/capture/capture.tsx (1)

57-82: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle missing src explicitly to prevent a stuck loading state.

setIsLoading(true) runs before checking src. When src is null/undefined, the component can remain indefinitely in loading UI with no explicit empty-state handling.

💡 Suggested fix
  useLayoutEffect(() => {
    if (!imageRef.current) {
      return
    }

-   setIsLoading(true)
-   setNaturalSize(undefined)
-
-   if (src) {
-     imageRef.current.src = src
-     imageRef.current.onload = () => {
-       if (imageRef.current?.width && imageRef.current.height) {
-         setNaturalSize({
-           width: imageRef.current.naturalWidth,
-           height: imageRef.current.naturalHeight,
-         })
-       }
-       setIsLoading(false)
-     }
-
-     imageRef.current.onerror = () => {
-       setNaturalSize(undefined)
-       setIsLoading(false)
-     }
-   }
+   if (!src) {
+     setNaturalSize(undefined)
+     setIsLoading(false)
+     return
+   }
+
+   setIsLoading(true)
+   setNaturalSize(undefined)
+   imageRef.current.src = src
+   imageRef.current.onload = () => {
+     if (imageRef.current?.width && imageRef.current.height) {
+       setNaturalSize({
+         width: imageRef.current.naturalWidth,
+         height: imageRef.current.naturalHeight,
+       })
+     }
+     setIsLoading(false)
+   }
+
+   imageRef.current.onerror = () => {
+     setNaturalSize(undefined)
+     setIsLoading(false)
+   }
  }, [src])

As per coding guidelines: "Handle empty and null states explicitly — API fields can be null even when the surrounding payload is present".

🤖 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 `@ui/src/pages/session-details/capture/capture.tsx` around lines 57 - 82, The
useLayoutEffect hook sets isLoading to true at the beginning but does not
explicitly handle the case when src is null or undefined, causing the loading
state to remain true indefinitely. After setting setIsLoading(true) and
setNaturalSize(undefined), add an else clause to the if (src) condition that
explicitly calls setIsLoading(false) and optionally setNaturalSize(undefined) to
handle the empty-state case when src is missing or falsy.

Source: Coding guidelines

🤖 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.

Outside diff comments:
In `@ui/src/pages/session-details/capture/capture.tsx`:
- Around line 57-82: The useLayoutEffect hook sets isLoading to true at the
beginning but does not explicitly handle the case when src is null or undefined,
causing the loading state to remain true indefinitely. After setting
setIsLoading(true) and setNaturalSize(undefined), add an else clause to the if
(src) condition that explicitly calls setIsLoading(false) and optionally
setNaturalSize(undefined) to handle the empty-state case when src is missing or
falsy.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c87d497b-6ee1-47a0-8dfc-554cf87acf80

📥 Commits

Reviewing files that changed from the base of the PR and between 040eae0 and 8cb4150.

⛔ Files ignored due to path filters (1)
  • ui/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (10)
  • ui/package.json
  • ui/src/data-services/models/capture.ts
  • ui/src/pages/captures/capture-columns.tsx
  • ui/src/pages/captures/capture-gallery.tsx
  • ui/src/pages/session-details/capture/capture.module.scss
  • ui/src/pages/session-details/capture/capture.tsx
  • ui/src/pages/session-details/session-details.tsx
  • ui/src/pages/session-details/view-settings.tsx
  • ui/src/pages/session-details/zoom-settings.tsx
  • ui/src/utils/language.ts

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.

1 participant