Skip to content

feat(metadata-instance-editor): support for cascade extraction#4616

Merged
mergify[bot] merged 5 commits into
masterfrom
cascade-extract-support-metadata-instance
Jun 9, 2026
Merged

feat(metadata-instance-editor): support for cascade extraction#4616
mergify[bot] merged 5 commits into
masterfrom
cascade-extract-support-metadata-instance

Conversation

@alexkirillovtech

@alexkirillovtech alexkirillovtech commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Description

Product scope

When a metadata instance on a folder is managed by a Box AI extract agent (i.e. its cascadePolicy.cascadePolicyType === ai_extract), the values for that instance are populated and kept in sync by the agent. Editing those values inline in the metadata sidebar would put the form's local state out of sync with what the agent will produce on the next cascade run, so this PR removes the inline-edit affordance for those instances and points users to the right place to make changes — the agent itself.

Resulting UX for an extract-managed instance:

  • Collapsed / view mode — the fields are rendered read-only (no remove icons, no inputs), with a short informational notice at the top: "Metadata cascade policy is enabled for this instance".
  • Edit mode — instead of the form, we render a Blueprint ActionableInlineNotice (lock icon) titled "Managed by a Box AI extract agent" with body copy explaining that the instance can't be edited here, plus a primary "Manage agent" button. Clicking it invokes a new onManageExtractAgent(agentId) callback, where the numeric agent id is extracted from the cascade policy's agent configuration value. The host app (EUA) wires this up to navigate to the agent management surface.

For all non-extract-managed instances the existing behavior is preserved exactly — same form, same cascade-policy controls, same save/remove footer, same confirm-remove dialog.

Selected approach

Instance.js had grown into a ~700-line class component that owned both the editor state machine and the entire view tree (collapsible chrome, cascade policy, form, footer, confirm dialog). Rather than add a third rendering branch into that file, this PR splits the presentational layer into three focused components and keeps Instance as the stateful orchestrator:

New file Responsibility
InstanceCard.js Collapsible card chrome only — icon, title, error mark, header action slot. No knowledge of editing or agents.
EditableInstanceBody.js The existing editable form: CascadePolicy + TemplatedInstance/CustomInstance + Footer + confirm-remove dialog. Pure presentational — every handler and flag is passed in as a prop.
ExtractManagedInstanceBody.js New body used when cascadePolicyType === ai_extract. Renders the read-only view when collapsed and the ActionableInlineNotice + "Manage agent" button when editing.

Instance.js now:

  • keeps all the state (isEditing, isCascadingEnabled, cascadePolicyConfiguration, etc.) and all the change handlers (onSave, onFieldChange, onCascadeToggle, onAIAgentSelect, …) — unchanged behavior;
  • decides which body to render via a single check (isExtractManaged = cascadePolicy?.cascadePolicyType === CASCADE_POLICY_TYPE_AI_EXTRACT);
  • delegates the chrome to InstanceCard and the body to one of the two new components.

The new onManageExtractAgent callback is added as an optional prop and threaded MetadataInstanceEditor → Instances → Instance → ExtractManagedInstanceBody. When it's not provided (or no agentId is on the cascade policy), the "Manage agent" button is simply not rendered, so existing consumers are unaffected.

Why this split rather than inlining the new branch in Instance:

  • Instance no longer mixes "what to show when" with "how to lay out a card / form / notice"; each new file is small, props-only, and unit-testable in isolation (see the new test files).
  • The notice-vs-form choice for extract-managed instances lives in one place (ExtractManagedInstanceBody), which makes future tweaks to that UX — copy, additional CTAs, telemetry tags — a single-file change.
  • The new components are pure (no connect, no lifecycle), so they avoid the snapshot churn that touching Instance itself causes; the bulk of the snapshot diff in this PR comes from Instance.test.js re-rendering through the new component tree rather than from semantic changes.

What's included

Source

  • Instance.js — refactor: extract chrome + body, add isExtractManaged branch, accept new onManageExtractAgent prop.
  • InstanceCard.js — new presentational card.
  • EditableInstanceBody.js — new presentational editable body.
  • ExtractManagedInstanceBody.js + .scss — new presentational managed body.
  • Instances.js, MetadataInstanceEditor.js — forward the new optional onManageExtractAgent prop.
  • messages.js — 4 new i18n strings (extractManagedTitle, extractManagedDescription, extractManagedManageAgent, extractManagedNoticeIconAriaLabel).
  • i18n/en-US.properties — generated.

Tests

  • New: EditableInstanceBody.test.js, ExtractManagedInstanceBody.test.js, InstanceCard.test.js, plus a shared __fixtures__/metadataInstances.js.
  • Updated: Instance.test.js, Instances.test.js, MetadataInstanceEditor.test.js to cover the new prop pass-through and the extract-managed branching (view + edit).
  • Updated: Instance.test.js.snap — large diff, but purely structural (rendering goes through InstanceCard / EditableInstanceBody wrappers now).

All 650 tests pass; coverage on the touched module is 100% statements / ~85% branches for the new files.

How to test

  • Setup: you need box-ui-elements and enduserapp
  • Run box-ui-elements with yarn start:npm and enduserapp with yarn start:local:linked / or yarn start:linked, whatever you prefer more
  • You need a test account with Extract enabled, metadata template created in Admin Console and one test folder
  • Go to Automate -> Extract -> Create custom agent -> Select template -> Click select source folder -> select a test folder
  • Now go to files -> However over test folder and the end of row click "..." button -> metadata
  • In metadata instance modal confirm that template instance exist
  • Expand it and click pencil icon
  • Confirm that there are no more fields or cascade setup, but the new banner exists and navigate to custom agent works
  • Also confirm that navigation is protected with unsaved changes banner, by adding new template to folder or editing existing instance of non agent template and click navigate -> modal should appear protecting for unsaved changes

Semantic release type

PR title: feat(metadata-instance-editor): support cascade extraction

  • feat — New feature (extract-agent-managed metadata instances)

Summary by CodeRabbit

Release Notes

  • New Features

    • Added support for managing Box AI extract agents directly from the metadata instance editor with dedicated UI controls and status indicators
    • Improved visual separation between AI extract-managed and manually-editable metadata modes
  • Refactor

    • Reorganized metadata instance editor components for improved user interface structure and usability

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This PR refactors the metadata instance editor to support custom AI extract agent management by introducing utility helpers for agent ID parsing, new component layers for agent-managed and editable instances, and routing logic that conditionally renders the appropriate UI based on cascade policy type.

Changes

Custom AI Extract Agent Management in Metadata Editor

Layer / File(s) Summary
Agent ID parsing and policy detection utilities
src/features/metadata-instance-editor/constants.js, src/features/metadata-instance-editor/messages.js, src/features/metadata-instance-editor/metadataUtil.js, src/features/metadata-instance-editor/__tests__/metadataUtil.test.js
CUSTOM_EXTRACT_AGENT_CONFIGURATION_PREFIX constant and localization messages are added; getCustomExtractAgentId() parses numeric agent IDs from configuration strings, and isCustomExtractAgentPolicy() detects custom extract policies by prefix and cascade type.
Custom extract agent instance body component
src/features/metadata-instance-editor/CustomExtractAgentInstanceBody.js, src/features/metadata-instance-editor/CustomExtractAgentInstanceBody.scss, src/features/metadata-instance-editor/__tests__/CustomExtractAgentInstanceBody.test.js
CustomExtractAgentInstanceBody renders agent-managed metadata in edit mode with a lock-icon notice and optional manage button, or in read-only mode with cascade-policy notice and appropriate template instance (custom or templated).
Editable instance body component
src/features/metadata-instance-editor/EditableInstanceBody.js, src/features/metadata-instance-editor/__tests__/EditableInstanceBody.test.js
EditableInstanceBody extracted from Instance, presents a form-based editor with conditional confirm-remove dialog, cascade policy rendering, template switching, and footer controls; wires form submission only when dirty.
Instance card presentational wrapper
src/features/metadata-instance-editor/InstanceCard.js, src/features/metadata-instance-editor/__tests__/InstanceCard.test.js
InstanceCard wraps the collapsible UI that was previously inlined, computing icon type from cascade policy, deriving animation duration from template field count, rendering title with optional error icon, and passing through header action items and children.
Instance component refactoring with routing logic
src/features/metadata-instance-editor/Instance.js, src/features/metadata-instance-editor/__tests__/Instance.test.js
Instance refactored to replace Collapsible/Form with InstanceCard containing either CustomExtractAgentInstanceBody or EditableInstanceBody based on isCustomExtractAgentPolicy(). Removes getTitle(), adds onManageExtractAgent prop, and routes extraction/cascade state to the appropriate body component.
Callback prop threading through hierarchy
src/features/metadata-instance-editor/Instances.js, src/features/metadata-instance-editor/MetadataInstanceEditor.js
onManageExtractAgent callback is destructured and forwarded through Instances and MetadataInstanceEditor to reach the Instance component, enabling agent management from the top-level editor context.
Test fixtures and integrated test coverage
src/features/metadata-instance-editor/__tests__/__fixtures__/metadataInstances.js, src/features/metadata-instance-editor/__tests__/Instances.test.js, src/features/metadata-instance-editor/__tests__/MetadataInstanceEditor.test.js
Fixture builders construct test data for templates, cascade policies, and metadata instances; integration tests verify managed notice rendering, agent button clicks, and callback invocation across the complete editor flow.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • box/box-ui-elements#4197: Refactors Instance.js and CascadePolicy.js with cascadePolicyConfiguration and enhanced agent selection logic—directly related to agent configuration handling in this PR.
  • box/box-ui-elements#4102: Modifies Instance/CascadePolicy/TemplatedInstance for ai_extract cascade-policy handling with AI-folder-extraction toggle—related component behavior changes.

Suggested labels

ready-to-merge

Suggested reviewers

  • tjuanitas
  • jmcbgaston
  • jfox-box

Poem

🐰 A rabbit hops through metadata fields with care,
Extracting agents from config strings in the air,
Two bodies now dance—one managed, one free,
Cards wrap them both in collapsible glee!
The routing flows smooth, the callbacks thread through,
Custom extract agents now have their own view! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title clearly and concisely summarizes the main feature being added: support for cascade extraction in the metadata instance editor.
Description check ✅ Passed The pull request description is comprehensive and well-structured, covering product scope, approach, included changes, testing instructions, and semantic-release type, exceeding template requirements.
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 cascade-extract-support-metadata-instance

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Biome (2.4.16)
src/features/metadata-instance-editor/CustomExtractAgentInstanceBody.js

File contains syntax errors that prevent linting: Line 14: 'import type' are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.; Line 22: type alias are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.; Line 47: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

src/features/metadata-instance-editor/EditableInstanceBody.js

File contains syntax errors that prevent linting: Line 5: 'import type' are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.; Line 15: 'import type' are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.; Line 22: type alias are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.; Line 87: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

src/features/metadata-instance-editor/Instance.js

File contains syntax errors that prevent linting: Line 10: 'import type' are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.; Line 20: 'import type' are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.; Line 29: 'import type' are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.; Line 49: type alias are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.; Line 72: type alias are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.; Line 85: optional parameters are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.; Line 85: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.; Line 91: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.; Line 91: Type an

... [truncated 6347 characters] ...

ript only feature. Convert your file to a TypeScript file or remove the syntax.; Line 576: return type annotation are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.; Line 577: type annotation are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.; Line 582: type annotation are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.; Line 583: type annotation are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.; Line 619: type annotation are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.; Line 629: type annotation are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

  • 5 others

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.

@alexkirillovtech alexkirillovtech marked this pull request as ready for review June 9, 2026 09:27
@alexkirillovtech alexkirillovtech requested review from a team as code owners June 9, 2026 09:27

@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

🧹 Nitpick comments (1)
src/features/metadata-instance-editor/__tests__/CustomExtractAgentInstanceBody.test.js (1)

36-41: ⚡ Quick win

Align the test assertion with the stated “title and description” behavior.

This test currently verifies only the description. Please also assert the notice title (or rename the test) so heading regressions are caught.

🤖 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/features/metadata-instance-editor/__tests__/CustomExtractAgentInstanceBody.test.js`
around lines 36 - 41, The test "renders the custom extract agent notice with
title and description" only asserts NOTICE_DESCRIPTION; update it to also assert
the notice title is rendered (or rename the test). Locate the test function
(test(...) with renderComponent({ isEditing: true })) and add an assertion for
the title—e.g. assert presence of NOTICE_TITLE or use
screen.getByRole('heading', { name: NOTICE_TITLE })—and keep the existing
assertion that CASCADE_NOTICE is not present.
🤖 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/features/metadata-instance-editor/CustomExtractAgentInstanceBody.js`:
- Around line 55-59: The ActionableInlineNotice currently only renders the
description; update the component usage in CustomExtractAgentInstanceBody so
that in edit mode it also receives a title prop: pass
title={formatMessage(messages.customExtractAgentNoticeTitle)} (using the
existing formatMessage and messages.customExtractAgentNoticeTitle) when the
editor is in edit mode, ensuring the notice shows “Managed by a Box AI extract
agent” above the description; keep the existing icon, iconAriaLabel and text
props unchanged and only add the title prop for edit-mode rendering.

In `@src/features/metadata-instance-editor/metadataUtil.js`:
- Around line 53-57: isCustomExtractAgentPolicy currently calls
agent.startsWith(...) which can throw if
cascadePolicy.cascadePolicyConfiguration.agent exists but is not a string;
modify isCustomExtractAgentPolicy to guard that agent is a string before calling
startsWith (e.g., check typeof agent === "string" or coerce safely) and keep the
existing conditions on cascadePolicy?.cascadePolicyType ===
CASCADE_POLICY_TYPE_AI_EXTRACT and CUSTOM_EXTRACT_AGENT_CONFIGURATION_PREFIX so
malformed/non-string agent values do not cause render-time crashes.

---

Nitpick comments:
In
`@src/features/metadata-instance-editor/__tests__/CustomExtractAgentInstanceBody.test.js`:
- Around line 36-41: The test "renders the custom extract agent notice with
title and description" only asserts NOTICE_DESCRIPTION; update it to also assert
the notice title is rendered (or rename the test). Locate the test function
(test(...) with renderComponent({ isEditing: true })) and add an assertion for
the title—e.g. assert presence of NOTICE_TITLE or use
screen.getByRole('heading', { name: NOTICE_TITLE })—and keep the existing
assertion that CASCADE_NOTICE is not present.
🪄 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: b0239e2f-78a1-47be-8ed5-b08886b8ef0c

📥 Commits

Reviewing files that changed from the base of the PR and between aed0f4e and 3c3f3e1.

⛔ Files ignored due to path filters (2)
  • i18n/en-US.properties is excluded by !i18n/**
  • src/features/metadata-instance-editor/__tests__/__snapshots__/Instance.test.js.snap is excluded by !**/*.snap
📒 Files selected for processing (18)
  • src/features/metadata-instance-editor/CustomExtractAgentInstanceBody.js
  • src/features/metadata-instance-editor/CustomExtractAgentInstanceBody.scss
  • src/features/metadata-instance-editor/EditableInstanceBody.js
  • src/features/metadata-instance-editor/Instance.js
  • src/features/metadata-instance-editor/InstanceCard.js
  • src/features/metadata-instance-editor/Instances.js
  • src/features/metadata-instance-editor/MetadataInstanceEditor.js
  • src/features/metadata-instance-editor/__tests__/CustomExtractAgentInstanceBody.test.js
  • src/features/metadata-instance-editor/__tests__/EditableInstanceBody.test.js
  • src/features/metadata-instance-editor/__tests__/Instance.test.js
  • src/features/metadata-instance-editor/__tests__/InstanceCard.test.js
  • src/features/metadata-instance-editor/__tests__/Instances.test.js
  • src/features/metadata-instance-editor/__tests__/MetadataInstanceEditor.test.js
  • src/features/metadata-instance-editor/__tests__/__fixtures__/metadataInstances.js
  • src/features/metadata-instance-editor/__tests__/metadataUtil.test.js
  • src/features/metadata-instance-editor/constants.js
  • src/features/metadata-instance-editor/messages.js
  • src/features/metadata-instance-editor/metadataUtil.js

Comment thread src/features/metadata-instance-editor/metadataUtil.js
@alexkirillovtech

Copy link
Copy Markdown
Contributor Author

https://github.com/Mergifyio queue

@mergify

mergify Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

  • Entered queue2026-06-09 14:05 UTC · Rule: Automatic strict merge
  • Checks skipped · PR is already up-to-date
  • Merged2026-06-09 14:05 UTC · at 3c3f3e19aae1425b55e9a84b6be74242e5bb8406 · squash

This pull request spent 19 seconds in the queue, including 3 seconds running CI.

Required conditions to merge

@mergify mergify Bot added the queued label Jun 9, 2026
@mergify mergify Bot merged commit 73c36cf into master Jun 9, 2026
17 checks passed
@mergify mergify Bot deleted the cascade-extract-support-metadata-instance branch June 9, 2026 14:05
@mergify mergify Bot removed the queued label Jun 9, 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