Skip to content

feat(bounding-box): integrate bounding boxes with metadata form#4494

Open
dlasecki-box wants to merge 4 commits intobox:masterfrom
dlasecki-box:metadata-confidence-score-read-flow
Open

feat(bounding-box): integrate bounding boxes with metadata form#4494
dlasecki-box wants to merge 4 commits intobox:masterfrom
dlasecki-box:metadata-confidence-score-read-flow

Conversation

@dlasecki-box
Copy link
Copy Markdown

@dlasecki-box dlasecki-box commented Mar 31, 2026

Summary by CodeRabbit

  • New Features

    • Metadata sidebar lets users select metadata fields and shows bounding-box highlights in the content preview; preview highlighting can be toggled via a new preview prop.
  • Chores

    • Added a utility to clamp bounding-box percentage values to the 0–100 range.
    • Introduced a lightweight hook to manage field selection and preview highlight lifecycle.
    • Exposed selection state so parent UI can control/respond to the selected metadata field.
  • Tests

    • Added tests covering selection, preview highlight show/hide, clamping, and outside-click behavior.

@dlasecki-box dlasecki-box requested review from a team as code owners March 31, 2026 21:33
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 31, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cbfe81ba-c43d-4f20-8b8b-b67274f39ed6

📥 Commits

Reviewing files that changed from the base of the PR and between 6f41420 and 2eae467.

📒 Files selected for processing (2)
  • src/elements/content-sidebar/__tests__/useMetadataFieldSelection.test.ts
  • src/elements/content-sidebar/hooks/useMetadataFieldSelection.ts
✅ Files skipped from review due to trivial changes (1)
  • src/elements/content-sidebar/tests/useMetadataFieldSelection.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/elements/content-sidebar/hooks/useMetadataFieldSelection.ts

Walkthrough

Adds bounding-box highlight support: new hook useMetadataFieldSelection, BoxAnnotationsBoundingBox type, clampPercentage util and tests, wiring selection and preview show/hide through redesigned metadata sidebar and editor, plus an enableBoundingBoxHighlights prop on ContentPreview with unit tests.

Changes

Cohort / File(s) Summary
Preview Configuration
src/elements/content-preview/ContentPreview.js, src/elements/content-preview/__tests__/ContentPreview.test.js
Added enableBoundingBoxHighlights boolean prop and default, extracted in loadPreview, and forwarded in previewOptions to global.Box.Preview.show(...); added tests asserting flag propagation.
Metadata Field Selection Hook & Tests
src/elements/content-sidebar/hooks/useMetadataFieldSelection.ts, src/elements/content-sidebar/__tests__/useMetadataFieldSelection.test.ts
New hook managing selectedMetadataFieldId, selection/deselection handlers, outside-click listener, conversion of targetLocationBoxAnnotationsBoundingBox with clamping and page adjustment, and preview show/hide calls; comprehensive tests added.
Metadata Component Prop Extensions & Wiring
src/elements/content-sidebar/MetadataInstanceEditor.tsx, src/elements/content-sidebar/MetadataSidebarRedesign.tsx, src/elements/content-sidebar/SidebarPanels.js
Added optional onSelectMetadataField and selectedMetadataFieldId props to MetadataInstanceEditorProps; introduced getPreview prop usage and wired selection state/handlers into redesigned sidebar and editor/list components.
Types & Utilities
src/elements/content-sidebar/types/BoxAISidebarTypes.ts, src/elements/content-sidebar/utils/clampPercentage.ts, src/elements/content-sidebar/__tests__/clampPercentage.test.ts
Added BoxAnnotationsBoundingBox type and reformatted existing types; added clampPercentage util (wraps lodash/clamp) and tests covering boundary and fractional values.
Sidebar Tests
src/elements/content-sidebar/__tests__/MetadataSidebarRedesign.test.tsx
Mocked useMetadataFieldSelection in tests and added assertion that the hook is invoked with the getPreview prop.
Misc Tests
src/elements/content-preview/__tests__/ContentPreview.test.js
Unit tests added to assert enableBoundingBoxHighlights is forwarded (true when provided, false by default).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant MetadataUI as Metadata Sidebar UI
    participant Hook as useMetadataFieldSelection
    participant Converter as TargetLocation Converter
    participant Preview as Preview Component

    User->>MetadataUI: Click metadata field
    MetadataUI->>Hook: handleSelectMetadataField(field)
    Hook->>Hook: set selectedMetadataFieldId

    alt field.targetLocation present
        Hook->>Converter: convert targetLocation -> bounding boxes
        Converter->>Converter: clamp x,y,width,height to [0,100]
        Converter-->>Hook: BoxAnnotationsBoundingBox[]
        Hook->>Preview: getPreview().showBoundingBoxHighlights(boxes)
    else no targetLocation
        Hook->>Preview: getPreview()?.hideBoundingBoxHighlights()
    end

    Hook->>Hook: attach document mousedown listener
    User->>MetadataUI: Click outside
    Hook->>Hook: detect outside click -> deselect
    Hook->>Preview: getPreview().hideBoundingBoxHighlights()
    Hook->>Hook: remove mousedown listener
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

Suggested labels

ready-to-merge

Suggested reviewers

  • tjuanitas
  • reneshen0328

Poem

🐇 I nudge a field and edges softly glow,
Little boxes leap where the page-lines flow,
Click to show, click away — they vanish from sight,
A rabbit hops proud at each bounding-box light! ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request description contains only template boilerplate about merge procedures and labels, with no actual description of the changes, objectives, or implementation details. Replace the template comments with a substantive description explaining what bounding box integration was added, why it was needed, and how it affects the metadata form.
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding bounding box functionality to the metadata form components, which is the core theme across all modified files.

✏️ 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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/elements/content-sidebar/__tests__/useMetadataFieldSelection.test.ts (1)

175-187: Consider using afterEach for DOM cleanup in click-outside tests.

The manual DOM cleanup works but could leave elements behind if a test fails. Using afterEach ensures cleanup regardless of test outcome:

♻️ Optional: Safer DOM cleanup pattern
 describe('click outside behavior', () => {
+    let testElements: HTMLElement[] = [];
+
+    afterEach(() => {
+        testElements.forEach(el => el.parentNode?.removeChild(el));
+        testElements = [];
+    });
+
     // ... existing tests ...

     test('should not deselect when clicking on a metadata field element', () => {
         // ...
         const metadataFieldElement = document.createElement('div');
         metadataFieldElement.setAttribute('data-metadata-field', 'true');
         document.body.appendChild(metadataFieldElement);
+        testElements.push(metadataFieldElement);

         // ... test logic ...
-
-        document.body.removeChild(metadataFieldElement);
     });

Also applies to: 196-208

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/elements/content-sidebar/__tests__/useMetadataFieldSelection.test.ts`
around lines 175 - 187, The tests manually append and remove
metadataFieldElement in useMetadataFieldSelection.test.ts which can leave DOM
nodes if a test fails; add a global afterEach hook that removes any appended
elements (e.g., querySelectorAll('[data-metadata-field]') and remove each) and
resets any mutated state so click-outside tests always clean up; update or
remove the per-test document.body.removeChild(...) calls in the tests
(references: variable metadataFieldElement and the assertion on
result.current.selectedMetadataFieldId) so cleanup is centralized and guaranteed
even on test failure.
src/elements/content-sidebar/__tests__/clampPercentage.test.ts (1)

4-13: Consider adding edge case tests for NaN and Infinity.

The test coverage is solid for normal numeric inputs. However, based on the actual usage in useMetadataFieldSelection.ts (where arithmetic expressions like item.boundingBox.left * 100 - 0.5 are passed), consider adding tests for edge cases that could arise from malformed data:

🧪 Optional: Add edge case tests
     test.each([
         [50, 50],
         [0, 0],
         [100, 100],
         [-0.5, 0],
         [100.5, 100],
         [99.999, 99.999],
+        [NaN, NaN],
+        [Infinity, 100],
+        [-Infinity, 0],
     ])('clampPercentage(%s) should return %s', (input, expected) => {
-        expect(clampPercentage(input)).toBe(expected);
+        if (Number.isNaN(expected)) {
+            expect(clampPercentage(input)).toBeNaN();
+        } else {
+            expect(clampPercentage(input)).toBe(expected);
+        }
     });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/elements/content-sidebar/__tests__/clampPercentage.test.ts` around lines
4 - 13, Add edge-case tests for clampPercentage to cover NaN and infinite
values: add test.each entries for [NaN, 0], [Infinity, 100], and [-Infinity, 0]
in the existing test block that references clampPercentage; if those tests fail,
update the clampPercentage implementation (the clampPercentage function) so that
NaN maps to 0, positive Infinity clamps to 100 and negative Infinity clamps to
0, keeping the current behavior for normal numeric inputs used by
useMetadataFieldSelection.ts.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/elements/content-preview/ContentPreview.js`:
- Line 293: The new prop enableBoundingBoxHighlights was added to defaultProps
and used in loadPreview but is missing from the Props Flow type, causing type
errors; add enableBoundingBoxHighlights: boolean to the Props type declaration
(near the existing enableThumbnailsSidebar entry) so the component's Props type
includes this prop and matches defaultProps and usages in loadPreview.

In `@src/elements/content-sidebar/hooks/useMetadataFieldSelection.ts`:
- Around line 15-22: The bounding-box width/height calculations in the mapping
that returns id/x/y/width/height use mixed units — `left`/`top` are treated as
normalized (0–1) while `right`/`bottom` are treated as percentages — so update
the width and height expressions in the mapping inside useMetadataFieldSelection
(the return of targetLocationEntries.map) to compute the difference in
normalized space then convert to percent; specifically compute
(item.boundingBox.right - item.boundingBox.left) * 100 and
(item.boundingBox.bottom - item.boundingBox.top) * 100 (with the existing +1
offset and clampPercentage call as needed) so all terms use the same units, or
alternatively add a normalization step that converts boundingBox.right/bottom to
0–1 before calculating width/height and ensure x/y use the same normalization.

---

Nitpick comments:
In `@src/elements/content-sidebar/__tests__/clampPercentage.test.ts`:
- Around line 4-13: Add edge-case tests for clampPercentage to cover NaN and
infinite values: add test.each entries for [NaN, 0], [Infinity, 100], and
[-Infinity, 0] in the existing test block that references clampPercentage; if
those tests fail, update the clampPercentage implementation (the clampPercentage
function) so that NaN maps to 0, positive Infinity clamps to 100 and negative
Infinity clamps to 0, keeping the current behavior for normal numeric inputs
used by useMetadataFieldSelection.ts.

In `@src/elements/content-sidebar/__tests__/useMetadataFieldSelection.test.ts`:
- Around line 175-187: The tests manually append and remove metadataFieldElement
in useMetadataFieldSelection.test.ts which can leave DOM nodes if a test fails;
add a global afterEach hook that removes any appended elements (e.g.,
querySelectorAll('[data-metadata-field]') and remove each) and resets any
mutated state so click-outside tests always clean up; update or remove the
per-test document.body.removeChild(...) calls in the tests (references: variable
metadataFieldElement and the assertion on
result.current.selectedMetadataFieldId) so cleanup is centralized and guaranteed
even on test failure.
🪄 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: 71eb007e-074e-4089-8fdf-26d81457158b

📥 Commits

Reviewing files that changed from the base of the PR and between 4f308da and 6953a8b.

📒 Files selected for processing (11)
  • src/elements/content-preview/ContentPreview.js
  • src/elements/content-preview/__tests__/ContentPreview.test.js
  • src/elements/content-sidebar/MetadataInstanceEditor.tsx
  • src/elements/content-sidebar/MetadataSidebarRedesign.tsx
  • src/elements/content-sidebar/SidebarPanels.js
  • src/elements/content-sidebar/__tests__/MetadataSidebarRedesign.test.tsx
  • src/elements/content-sidebar/__tests__/clampPercentage.test.ts
  • src/elements/content-sidebar/__tests__/useMetadataFieldSelection.test.ts
  • src/elements/content-sidebar/hooks/useMetadataFieldSelection.ts
  • src/elements/content-sidebar/types/BoxAISidebarTypes.ts
  • src/elements/content-sidebar/utils/clampPercentage.ts

return undefined;
}

// Adding extra space (-0.25 for left and top, +0.5 for width and height) to provide paddings for bounding boxes
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Image

Copy link
Copy Markdown
Contributor

@Lindar90 Lindar90 left a comment

Choose a reason for hiding this comment

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

Left 2 comments. But they are not PR blocking. Looks good!

return;
}

const boundingBoxes = convertTargetLocationToBoundingBox(field.id, field.targetLocation);
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.

Nit: maybe we could pass the whole field object? I.e:
const boundingBoxes = buildBoundingBoxesFromField(field)

function useMetadataFieldSelection(
getPreview?: () => {
showBoundingBoxHighlights?: (boundingBoxes: BoxAnnotationsBoundingBox[]) => void;
hideBoundingBoxHighlights?: () => void;
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.

Type duplication:

  • MetadataSidebarRedesign
  • and useMetadataFieldSelection

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.

2 participants