Skip to content

Review: Dynamic thumbnail scaling based on content dimensions - #35282

Merged
ghengeveld merged 22 commits into
nextfrom
ghengeveld/review-thumbnail-content-resize
Jul 1, 2026
Merged

ghengeveld merged 22 commits into
nextfrom
ghengeveld/review-thumbnail-content-resize

Conversation

@ghengeveld

@ghengeveld ghengeveld commented Jun 25, 2026 •

Copy link
Copy Markdown
Member

Summary

  • Add setupContentResizeBroadcast in preview: when embed=true, measure story content bounds (skipping pass-through wrappers and viewport underlays) and post iframe.resize messages to the parent frame, with a final measurement after freeze via onFrozen
  • Add embed option to getStoryHrefs (preview-only; filtered from generic query params); review thumbnails request embed=true&freeze=finished
  • Extract usePreviewThumbnail and previewScheduler from CollectionGrid; a single global resize listener routes iframe.resize messages to the matching iframe
  • Size review thumbnails in fixed 3/2 frames: CSS --scale fits content width (≤300px → 100%, wider → stepped down to 50%); tall stories are cropped rather than shrunk to fit frame height
  • Centralize shared review types in review-types.ts

Test plan

  • Open review summary in Storybook UI and confirm thumbnails scale to content width (narrow stories at 100%, wide at 50%)
  • Confirm tall stories (e.g. ActionList) render at full width scale with vertical overflow cropped, not shrunk to fit
  • Confirm "Review all" iframe and grid cells share consistent frame heights

🦋 Canary release

This pull request has been released as version 0.0.0-pr-35282-sha-ac39c7d8. Try it out in a new sandbox by running npx storybook@0.0.0-pr-35282-sha-ac39c7d8 sandbox or in an existing project with npx storybook@0.0.0-pr-35282-sha-ac39c7d8 upgrade.

More information
Published version 0.0.0-pr-35282-sha-ac39c7d8
Triggered by @ghengeveld
Repository storybookjs/storybook
Branch ghengeveld/review-thumbnail-content-resize
Commit ac39c7d8
Datetime Fri Jun 26 15:00:18 UTC 2026 (1782486018)
Workflow run 28246281589

To request a new release of this pull request, mention the @storybookjs/core team.

core team members can create a new canary release here or locally with gh workflow run --repo storybookjs/storybook publish.yml --field pr=35282

Summary by CodeRabbit

  • New Features
    • Review preview links now support an embedded view option, including embedded + frozen preview variants.
  • Bug Fixes
    • Improved embedded preview iframe resizing with more accurate measurement, padding handling, and correct freeze completion behavior.
    • Review grid preview thumbnails have more consistent sizing and more stable “Review all” iframe rendering across varying content sizes.
  • Tests
    • Added coverage for embedded preview URL parameters and iframe resize/freezer behaviors.

When embed=true, measure story content and post iframe.resize messages
to the parent frame. Wire a final measurement into the story freezer
via onFrozen for stable thumbnail dimensions after freeze completes.
Review thumbnails opt into content-dimension broadcast via embed=true,
emitted before freeze=finished when both params are requested.
Listen for embed preview postMessages in CollectionGrid and derive per-cell
scale and aspect ratio from measured content via computeThumbnailLayout.
Request embed=true alongside freeze=finished when building review thumbnail
preview URLs and update story mocks to match.
@ghengeveld ghengeveld self-assigned this Jun 25, 2026
@coderabbitai

coderabbitai Bot commented Jun 25, 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

Walkthrough

This PR adds embed=true to preview URL generation, wires preview freezing to a resize-broadcast callback, and updates review-grid thumbnails to consume iframe resize messages and size cells from reported content dimensions.

Changes

Embedded preview resize flow

Layer / File(s) Summary
Embed preview URLs
code/core/src/manager-api/modules/url.ts, code/core/src/manager-api/tests/url.test.js, code/core/src/manager/components/review/ReviewProvider.tsx, code/core/src/manager/components/review/ReviewPage.stories.tsx, code/core/src/manager/components/review/ReviewToolbarHeader.stories.tsx
getStoryHrefs accepts embed, and review preview builders and mocks append embed=true while preserving freeze=finished handling.
Resize broadcast core
code/core/src/preview-api/modules/preview-web/setupContentResizeBroadcast.ts, code/core/src/preview-api/modules/preview-web/setupContentResizeBroadcast.test.ts, code/core/src/shared/constants/iframe-resize.ts
setupContentResizeBroadcast measures embedded content, filters tracked elements, and posts iframe.resize; tests cover embed gating, heuristics, padding, and freeze gating.
Freeze callback wiring
code/core/src/preview-api/modules/preview-web/PreviewWithSelection.tsx, code/core/src/preview-api/modules/preview-web/setupStoryFreezer.ts, code/core/src/preview-api/modules/preview-web/setupStoryFreezer.test.ts
setupStoryFreezer accepts onFrozen, PreviewWithSelection passes the resize callback into freezing, and tests confirm the callback runs after freeze.
Thumbnail contracts and helpers
code/core/src/manager/components/review/review-types.ts, code/core/src/manager/components/review/review-store.ts, code/core/src/manager/components/review/ReviewCollectionPicker.tsx, code/core/src/manager/components/review/screens/SummaryScreen.tsx, code/core/src/manager/components/review/screens/SummaryScreen.stories.tsx, code/core/src/manager/components/review/components/iframeResizeMessage.ts, code/core/src/manager/components/review/components/iframeResizeMessage.test.ts, code/core/src/manager/components/review/components/previewScheduler.ts, code/core/src/manager/components/review/components/usePreviewThumbnail.ts
review-types centralizes story metadata types, iframeResizeMessage parses resize payloads and derives thumbnail sizing values, and preview loading is scheduled through a new hook and scheduler.
Review grid layout and stories
code/core/src/manager/components/review/components/CollectionGrid.tsx, code/core/src/manager/components/review/components/CollectionGrid.stories.tsx
CollectionGrid uses thumbnail dimensions to size preview cells, and its stories update iframe preview URLs and layout assertions for embedded previews.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • storybookjs/storybook#35255: Updates the same preview freezing path in setupStoryFreezer, adding hot-update handling alongside the new onFrozen callback wiring here.

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

@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: 4

🧹 Nitpick comments (3)
code/core/src/preview-api/modules/preview-web/setupContentResizeBroadcast.test.ts (1)

22-40: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Use Vitest global stubs instead of mutating window directly.

This test overwrites window.parent manually and installs the ResizeObserver mock inside the test body. That makes cleanup depend on custom restoration logic and is exactly the kind of global state pollution the repo rules are trying to avoid. Prefer vi.stubGlobal() in beforeEach() and vi.unstubAllGlobals() in afterEach().

As per coding guidelines, "Never assign globalThis.* directly in tests ... Use Vitest's vi.stubGlobal() ... vi.unstubAllGlobals() in afterEach()" and "Implement mock behaviors in beforeEach blocks in Vitest tests."

Also applies to: 62-86

🤖 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
`@code/core/src/preview-api/modules/preview-web/setupContentResizeBroadcast.test.ts`
around lines 22 - 40, The test is mutating window globals directly, including
window.parent and the ResizeObserver mock setup, which should be managed through
Vitest stubs instead. Update setupContentResizeBroadcast.test.ts to use
vi.stubGlobal() in beforeEach for window.parent and any global mocks, and call
vi.unstubAllGlobals() in afterEach to restore state cleanly. Keep the mock
behavior setup near the existing beforeEach/afterEach test hooks so the test
stays isolated and avoids manual Object.defineProperty cleanup.

Source: Coding guidelines

code/core/src/manager-api/tests/url.test.js (1)

641-655: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert params, not query-string ordering.

This test is locking in embed before freeze, but the behavior that matters is that both params are present on previewHref. Parsing the query here would make the test survive harmless URL-builder refactors.

Suggested test shape
-  it('appends embed before freeze when both are set', () => {
+  it('includes both embed and freeze when both are set', () => {
     const { api, state } = initURL({
       store,
       provider: { channel: new EventEmitter() },
       state: { location: { pathname: '/', search: '' } },
       navigate: vi.fn(),
       fullAPI: { getCurrentStoryData: () => ({ id: 'test--story' }) },
     });
     store.setState(state);
 
     const { previewHref } = api.getStoryHrefs('test--story', { embed: true, freeze: true });
-    expect(previewHref).toEqual(
-      '/iframe.html?id=test--story&viewMode=story&embed=true&freeze=finished'
-    );
+    const url = new URL(previewHref, 'http://localhost');
+    expect(url.pathname).toBe('/iframe.html');
+    expect(url.searchParams.get('id')).toBe('test--story');
+    expect(url.searchParams.get('viewMode')).toBe('story');
+    expect(url.searchParams.get('embed')).toBe('true');
+    expect(url.searchParams.get('freeze')).toBe('finished');
   });
🤖 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 `@code/core/src/manager-api/tests/url.test.js` around lines 641 - 655, This
test is asserting a specific query-string order in getStoryHrefs, but it should
only verify that previewHref contains both embed and freeze parameters. Update
the test around initURL/getStoryHrefs so it parses previewHref and asserts the
presence and values of the params instead of comparing the full URL string,
keeping the coverage focused on the API behavior rather than ordering.
code/core/src/manager/components/review/components/computeThumbnailLayout.test.ts (1)

1-48: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add direct coverage for parseIframeResizeMessage.

The new listener path depends on malformed-message rejection, but this suite only locks down the layout buckets. Add a few cases for string/object payloads, wrong context, bad JSON, and invalid dimensions so the resize message contract is tested directly. As per coding guidelines, **/*.test.ts?(x): "For unit tests of utilities, hooks, and non-React modules, export functions that need testing, test real behavior (not syntax patterns)."

Minimal expansion
-import { computeThumbnailLayout } from './computeThumbnailLayout.ts';
+import {
+  computeThumbnailLayout,
+  IFRAME_RESIZE_CONTEXT,
+  parseIframeResizeMessage,
+} from './computeThumbnailLayout.ts';
+
+describe('parseIframeResizeMessage', () => {
+  it('accepts valid resize payloads', () => {
+    expect(
+      parseIframeResizeMessage(
+        JSON.stringify({ context: IFRAME_RESIZE_CONTEXT, width: 320, height: 240 })
+      )
+    ).toEqual({ width: 320, height: 240 });
+  });
+
+  it('rejects malformed payloads', () => {
+    expect(parseIframeResizeMessage('{')).toBeNull();
+    expect(parseIframeResizeMessage({ context: 'other', width: 320, height: 240 })).toBeNull();
+    expect(parseIframeResizeMessage({ context: IFRAME_RESIZE_CONTEXT, width: -1, height: 240 })).toBeNull();
+  });
+});
🤖 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
`@code/core/src/manager/components/review/components/computeThumbnailLayout.test.ts`
around lines 1 - 48, The current test suite only covers computeThumbnailLayout,
but the new listener behavior relies on parseIframeResizeMessage rejecting
malformed resize payloads. Add direct unit coverage for parseIframeResizeMessage
with valid string/object inputs and invalid cases like wrong context, bad JSON,
and non-positive or missing dimensions, so the message contract is tested
explicitly. Use the existing computeThumbnailLayout and parseIframeResizeMessage
symbols to locate the related utility and keep the tests focused on real
behavior.

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.

Inline comments:
In `@code/core/src/manager-api/modules/url.ts`:
- Around line 297-302: The URL builder in manager-api/modules/url.ts is mixing
preview-only flags into the generic query string, which can duplicate
embed/freeze and leak them into managerHref. Update the logic around the URL
assembly in the return object so that queryParams are filtered to exclude embed
and freeze, and only the explicit embedParam/freezeParam pieces are appended to
previewHref. Use the existing symbols managerHref, previewHref, embedParam,
freezeParam, and queryParams handling to keep the fix localized.

In
`@code/core/src/manager/components/review/components/computeThumbnailLayout.ts`:
- Around line 38-45: Reject invalid resize payload dimensions in
computeThumbnailLayout by tightening the parsed width/height checks: after
JSON.parse and the IFRAME_RESIZE_CONTEXT guard, ensure both parsed.width and
parsed.height are finite and greater than zero before returning the layout
object. Update the validation in computeThumbnailLayout so malformed
iframe.resize messages with NaN, Infinity, zero, or negative values are treated
as null instead of being passed through to thumbnail sizing.

In `@code/core/src/preview-api/modules/preview-web/setupStoryFreezer.test.ts`:
- Around line 266-269: The test for setupStoryFreezer only waits for a
microtask, so it passes only when the queueMicrotask path is used. Update the
assertion flow after channel.emit(STORY_RENDER_PHASE_CHANGED, ...) to wait in a
way that covers both scheduling branches, so the expectation on onFrozen in
setupStoryFreezer.test remains valid whether setupStoryFreezer uses
queueMicrotask or setTimeout(..., 0).

In `@code/core/src/preview-api/modules/preview-web/setupStoryFreezer.ts`:
- Around line 300-309: The STORY_RENDER_PHASE_CHANGED handler in
setupStoryFreezer currently calls options.onFrozen every time newPhase becomes
finished, even after freezer.freeze() has already no-op’d. Update the runFreeze
flow so onFrozen is only invoked on the first successful freeze, and keep the
guard close to the existing freezer.freeze() logic so repeated finished events
do not trigger duplicate callbacks or resize notifications.

---

Nitpick comments:
In `@code/core/src/manager-api/tests/url.test.js`:
- Around line 641-655: This test is asserting a specific query-string order in
getStoryHrefs, but it should only verify that previewHref contains both embed
and freeze parameters. Update the test around initURL/getStoryHrefs so it parses
previewHref and asserts the presence and values of the params instead of
comparing the full URL string, keeping the coverage focused on the API behavior
rather than ordering.

In
`@code/core/src/manager/components/review/components/computeThumbnailLayout.test.ts`:
- Around line 1-48: The current test suite only covers computeThumbnailLayout,
but the new listener behavior relies on parseIframeResizeMessage rejecting
malformed resize payloads. Add direct unit coverage for parseIframeResizeMessage
with valid string/object inputs and invalid cases like wrong context, bad JSON,
and non-positive or missing dimensions, so the message contract is tested
explicitly. Use the existing computeThumbnailLayout and parseIframeResizeMessage
symbols to locate the related utility and keep the tests focused on real
behavior.

In
`@code/core/src/preview-api/modules/preview-web/setupContentResizeBroadcast.test.ts`:
- Around line 22-40: The test is mutating window globals directly, including
window.parent and the ResizeObserver mock setup, which should be managed through
Vitest stubs instead. Update setupContentResizeBroadcast.test.ts to use
vi.stubGlobal() in beforeEach for window.parent and any global mocks, and call
vi.unstubAllGlobals() in afterEach to restore state cleanly. Keep the mock
behavior setup near the existing beforeEach/afterEach test hooks so the test
stays isolated and avoids manual Object.defineProperty cleanup.
🪄 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: cd7bd0dd-30df-473e-b141-5e9a778c6659

📥 Commits

Reviewing files that changed from the base of the PR and between 03c461b and 36c0691.

📒 Files selected for processing (15)
  • code/core/src/manager-api/modules/url.ts
  • code/core/src/manager-api/tests/url.test.js
  • code/core/src/manager/components/review/ReviewPage.stories.tsx
  • code/core/src/manager/components/review/ReviewProvider.tsx
  • code/core/src/manager/components/review/ReviewToolbarHeader.stories.tsx
  • code/core/src/manager/components/review/components/CollectionGrid.stories.tsx
  • code/core/src/manager/components/review/components/CollectionGrid.tsx
  • code/core/src/manager/components/review/components/computeThumbnailLayout.test.ts
  • code/core/src/manager/components/review/components/computeThumbnailLayout.ts
  • code/core/src/manager/components/review/screens/SummaryScreen.stories.tsx
  • code/core/src/preview-api/modules/preview-web/PreviewWithSelection.tsx
  • code/core/src/preview-api/modules/preview-web/setupContentResizeBroadcast.test.ts
  • code/core/src/preview-api/modules/preview-web/setupContentResizeBroadcast.ts
  • code/core/src/preview-api/modules/preview-web/setupStoryFreezer.test.ts
  • code/core/src/preview-api/modules/preview-web/setupStoryFreezer.ts

Comment thread code/core/src/manager-api/modules/url.ts
Comment thread code/core/src/manager/components/review/components/computeThumbnailLayout.ts Outdated
Comment thread code/core/src/preview-api/modules/preview-web/setupStoryFreezer.test.ts Outdated
Comment thread code/core/src/preview-api/modules/preview-web/setupStoryFreezer.ts
@ghengeveld ghengeveld changed the title Size review thumbnails from embedded preview content dimensions Review: Dynamic thumbnails sizing based on content dimensions Jun 25, 2026
@ghengeveld ghengeveld changed the title Review: Dynamic thumbnails sizing based on content dimensions Review: Dynamic thumbnail sizing based on content dimensions Jun 25, 2026
@ghengeveld ghengeveld added feature request ci:normal Run our default set of CI jobs (choose this for most PRs). qa:needed Pull Requests that will need manual QA prior to release. labels Jun 25, 2026
@storybook-app-bot

storybook-app-bot Bot commented Jun 25, 2026 •

Copy link
Copy Markdown
Contributor

Package Benchmarks

Commit: 52f2e4e, ran on 30 June 2026 at 12:44:49 UTC

The following packages have significant changes to their size or dependencies:

storybook

Before After Difference
Dependency count 72 72 0
Self size 21.90 MB 21.91 MB 🚨 +12 KB 🚨
Dependency size 36.44 MB 36.44 MB 0 B
Bundle Size Analyzer Link Link

@storybook/cli

Before After Difference
Dependency count 204 204 0
Self size 821 KB 821 KB 🚨 +84 B 🚨
Dependency size 91.68 MB 91.70 MB 🚨 +12 KB 🚨
Bundle Size Analyzer Link Link

@storybook/codemod

Before After Difference
Dependency count 197 197 0
Self size 32 KB 32 KB 🚨 +36 B 🚨
Dependency size 90.17 MB 90.18 MB 🚨 +12 KB 🚨
Bundle Size Analyzer Link Link

create-storybook

Before After Difference
Dependency count 73 73 0
Self size 1.09 MB 1.09 MB 🚨 +66 B 🚨
Dependency size 58.34 MB 58.35 MB 🚨 +12 KB 🚨
Bundle Size Analyzer node node

Measure content bounds with symmetric runtime body padding, skip pass-through wrappers and viewport underlays, and size CollectionGrid frames from iframe.resize via CSS variables and subgrid alignment.

@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
`@code/core/src/manager/components/review/components/CollectionGrid.stories.tsx`:
- Around line 170-177: The CollectionGrid story test is capturing neighbor
heights too early, so the waitFor loop keeps checking a stale snapshot instead
of fresh layout values. Update the logic around rowNeighborHeights to read the
cell heights inside the waitFor callback, then compute or re-read the final
heights after layout settles before asserting they match reviewAllHeight.

In
`@code/core/src/preview-api/modules/preview-web/setupContentResizeBroadcast.test.ts`:
- Around line 83-86: The tests in setupContentResizeBroadcast.test.ts are
directly mutating global window properties instead of using Vitest’s global
stubbing helpers. Update the affected setup blocks and cases that touch
innerWidth, innerHeight, parent, and ResizeObserver to use vi.stubGlobal(...) so
the test environment is isolated, and add vi.unstubAllGlobals() in afterEach()
to restore globals consistently between cases.
🪄 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: e3cfaef2-77d1-4359-9813-98117f0cfad0

📥 Commits

Reviewing files that changed from the base of the PR and between 36c0691 and c1d1d18.

📒 Files selected for processing (9)
  • code/core/src/manager/components/review/ReviewProvider.tsx
  • code/core/src/manager/components/review/ReviewToolbarHeader.stories.tsx
  • code/core/src/manager/components/review/components/CollectionGrid.stories.tsx
  • code/core/src/manager/components/review/components/CollectionGrid.tsx
  • code/core/src/manager/components/review/components/computeThumbnailLayout.ts
  • code/core/src/manager/components/review/components/iframeResizeMessage.ts
  • code/core/src/manager/components/review/screens/SummaryScreen.stories.tsx
  • code/core/src/preview-api/modules/preview-web/setupContentResizeBroadcast.test.ts
  • code/core/src/preview-api/modules/preview-web/setupContentResizeBroadcast.ts
✅ Files skipped from review due to trivial changes (1)
  • code/core/src/manager/components/review/components/iframeResizeMessage.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • code/core/src/manager/components/review/ReviewProvider.tsx
  • code/core/src/manager/components/review/ReviewToolbarHeader.stories.tsx

Comment thread code/core/src/manager/components/review/components/CollectionGrid.stories.tsx Outdated
Comment thread code/core/src/preview-api/modules/preview-web/setupContentResizeBroadcast.test.ts Outdated
Base automatically changed from yann/agentic-review-mcp-integration to next June 26, 2026 08:58
Compute a pixel min-height from reported iframe dimensions so subgrid rows
expand to the correct 3/n aspect bucket instead of clipping tall stories.

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

🧹 Nitpick comments (2)
code/core/src/manager/components/review/components/CollectionGrid.tsx (1)

490-499: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Skip no-op resize updates.

The preview now emits a final resize after freeze, so identical iframe.resize payloads will still allocate a new object and rerender this cell. Guarding the setter by width/height avoids unnecessary grid churn when many embeds settle at once.

Proposed change
-      setRememberedDimensions(dimensions);
+      setRememberedDimensions((current) =>
+        current?.width === dimensions.width && current?.height === dimensions.height
+          ? current
+          : dimensions
+      );
🤖 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 `@code/core/src/manager/components/review/components/CollectionGrid.tsx` around
lines 490 - 499, Skip no-op resize updates in the CollectionGrid message handler
by comparing the parsed iframe dimensions before calling
setRememberedDimensions. In the handleMessage logic that uses
parseIframeResizeMessage and setRememberedDimensions, add a width/height
equality guard so identical iframe.resize payloads do not create a new object
and trigger unnecessary rerenders.
code/core/src/manager/components/review/components/iframeResizeMessage.test.ts (1)

3-27: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add parser contract coverage here too.

These cases lock down the sizing math, but not parseIframeResizeMessage, which is the gate CollectionGrid depends on before any layout update happens. A few valid/invalid payload cases here would catch silent breakage in the manager/preview message format.

🤖 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
`@code/core/src/manager/components/review/components/iframeResizeMessage.test.ts`
around lines 3 - 27, The current test file covers the sizing helpers but misses
parser contract coverage for parseIframeResizeMessage, which is the entry point
CollectionGrid relies on before applying layout updates. Add tests in
iframeResizeMessage.test.ts for parseIframeResizeMessage that exercise a few
valid and invalid payload shapes, including the expected manager/preview message
format, so regressions in message parsing are caught alongside the existing
computeThumbnailScale, computeThumbnailThirds, and computeThumbnailMinHeight
cases.
🤖 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.

Nitpick comments:
In `@code/core/src/manager/components/review/components/CollectionGrid.tsx`:
- Around line 490-499: Skip no-op resize updates in the CollectionGrid message
handler by comparing the parsed iframe dimensions before calling
setRememberedDimensions. In the handleMessage logic that uses
parseIframeResizeMessage and setRememberedDimensions, add a width/height
equality guard so identical iframe.resize payloads do not create a new object
and trigger unnecessary rerenders.

In
`@code/core/src/manager/components/review/components/iframeResizeMessage.test.ts`:
- Around line 3-27: The current test file covers the sizing helpers but misses
parser contract coverage for parseIframeResizeMessage, which is the entry point
CollectionGrid relies on before applying layout updates. Add tests in
iframeResizeMessage.test.ts for parseIframeResizeMessage that exercise a few
valid and invalid payload shapes, including the expected manager/preview message
format, so regressions in message parsing are caught alongside the existing
computeThumbnailScale, computeThumbnailThirds, and computeThumbnailMinHeight
cases.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 75f33aea-bc01-4df5-98fd-835297384ec1

📥 Commits

Reviewing files that changed from the base of the PR and between c1d1d18 and bb9bcac.

📒 Files selected for processing (3)
  • code/core/src/manager/components/review/components/CollectionGrid.tsx
  • code/core/src/manager/components/review/components/iframeResizeMessage.test.ts
  • code/core/src/manager/components/review/components/iframeResizeMessage.ts

Extract preview scheduler, thumbnail hook, and shared types; use a single resize message listener and JS-only minHeight for subgrid row growth while CSS handles visual scaling.

@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

🤖 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 `@code/core/src/manager/components/review/components/usePreviewThumbnail.ts`:
- Around line 211-215: The thumbnail URL is being cached in usePreviewThumbnail,
so changes to getPreviewHref() do not refresh the iframe once src is already
set. Update the start handler in the PreviewTask so it can replace the existing
src when the computed previewHref changes, rather than only setting it when
current is null. Use the usePreviewThumbnail and PreviewTask.start symbols to
locate the logic and make the iframe reload on href changes.
🪄 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: c2a6f96b-7951-4cb6-b05e-cdb2d30f3345

📥 Commits

Reviewing files that changed from the base of the PR and between bb9bcac and ac39c7d.

📒 Files selected for processing (14)
  • code/core/src/manager/components/review/ReviewCollectionPicker.tsx
  • code/core/src/manager/components/review/ReviewProvider.tsx
  • code/core/src/manager/components/review/components/CollectionGrid.stories.tsx
  • code/core/src/manager/components/review/components/CollectionGrid.tsx
  • code/core/src/manager/components/review/components/iframeResizeMessage.ts
  • code/core/src/manager/components/review/components/previewScheduler.ts
  • code/core/src/manager/components/review/components/usePreviewThumbnail.ts
  • code/core/src/manager/components/review/review-store.ts
  • code/core/src/manager/components/review/review-types.ts
  • code/core/src/manager/components/review/screens/SummaryScreen.stories.tsx
  • code/core/src/manager/components/review/screens/SummaryScreen.tsx
  • code/core/src/preview-api/modules/preview-web/setupContentResizeBroadcast.test.ts
  • code/core/src/preview-api/modules/preview-web/setupContentResizeBroadcast.ts
  • code/core/src/shared/constants/iframe-resize.ts
✅ Files skipped from review due to trivial changes (4)
  • code/core/src/manager/components/review/review-types.ts
  • code/core/src/manager/components/review/review-store.ts
  • code/core/src/shared/constants/iframe-resize.ts
  • code/core/src/manager/components/review/screens/SummaryScreen.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
  • code/core/src/manager/components/review/screens/SummaryScreen.stories.tsx
  • code/core/src/manager/components/review/ReviewProvider.tsx
  • code/core/src/preview-api/modules/preview-web/setupContentResizeBroadcast.test.ts
  • code/core/src/manager/components/review/components/CollectionGrid.stories.tsx

Drop dynamic aspect-ratio buckets and subgrid minHeight resizing; preview
frames stay 3/2 while scale fits measured content width and height.
Re-read cell heights inside waitFor so layout assertions track live DOM values instead of a pre-layout snapshot.
Always set iframe src from the latest preview URL and skip no-op resize dimension updates to avoid stale thumbnails and unnecessary rerenders.
Guard repeated finished-phase events and wait with vi.waitFor so the freezer callback test covers both microtask and timeout scheduling paths.
Filter preview-only flags from manager and preview query strings and assert param presence in tests instead of URL ordering.
Require finite positive width and height before applying thumbnail sizing and add parser contract tests.
Replace direct window mutations with vi.stubGlobal and vi.unstubAllGlobals for consistent test isolation.
This was referenced Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:normal Run our default set of CI jobs (choose this for most PRs). feature request qa:success Pull Requests that were successfully QA'ed by the release team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants