Skip to content

fix: support mid-migration metadata templates - #4653

Open
JakubKida wants to merge 14 commits into
masterfrom
metadata-namespace-migration-support
Open

fix: support mid-migration metadata templates#4653
JakubKida wants to merge 14 commits into
masterfrom
metadata-namespace-migration-support

Conversation

@JakubKida

@JakubKida JakubKida commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Description

This PR adds metadata namespace migration support to the redesigned Content Sidebar metadata experience.

Box metadata is moving from legacy scoped templates (enterprise / enterprise_<id>) toward namespaced templates (hierarchical FQNs under an enterprise root). Enterprises can be in one of three modes:

Mode Meaning
SCOPED Legacy behavior — no namespace APIs, no template-management browser
MIGRATION Mid-migration — both models may appear; UI must resolve templates carefully
FINAL Namespaced templates are the source of truth

Without this work, the redesigned sidebar assumes SCOPED semantics: it fetches enterprise templates with the enterprise shorthand, matches instances only by $scope, and cannot browse or manage templates in a namespace tree. That breaks (or silently mis-handles) files in MIGRATION/FINAL.

This PR wires the sidebar and Metadata API so that, when the namespaces opt-in feature is enabled, we:

  1. Resolve the viewer’s enterprise root FQN and migration mode
  2. Fetch metadata with mode-aware template URLs and matching
  3. Enable template browsing / create / edit when mode is MIGRATION or FINAL

When the opt-in flag is off, behavior stays on the legacy path.


Screenshots/Videos

N/A for API/hook wiring. For UI review, open a file in an enterprise in MIGRATION or FINAL with metadata.namespacesOptIn.enabled on and confirm:

  • Metadata instances still load
  • The add-template control uses the namespace browser (not only the flat list)
  • Create / edit template flows open the template editor modal

Related issues

N/A (public repo)


Changes made

API layer

  • Metadata.js — mode-aware getMetadata paths:
    • SCOPED: parallel fetch of instances + global + enterprise templates (unchanged intent)
    • MIGRATION/FINAL: prefer the caller’s enterprise root FQN; fall back to deriving it from instances; avoid invalid enterprise shorthand where namespaces are required
    • Stronger instance→template matching (scope and/or namespace), including externally owned templates
  • MetadataNamespaces.js — dedicated surface for namespace HTTP:
    • list child namespaces
    • list templates in a namespace
    • resolve migration mode from enterprise configurations
    • create / update template schema (editor flows)
    • Delegated from Metadata so callers keep using api.getMetadataAPI()
  • metadataNamespaceUtils.js — pure helpers for enterprise-root resolution, mode resolution, scope-vs-namespace selection, and “externally owned” checks
  • metadataNamespaceMocks.js — temporary mocks for namespace endpoints until the live API is fully available in all environments
  • Base.js / types / constants — shared header/constants/types for namespace mode fields, error codes, and box-version where needed

Sidebar hooks

  • useCurrentUserEnterpriseIdGET /users/me?fields=enterprise → numeric id + enterprise_<id> FQN
  • useMetadataNamespaceMode — enterprise configurations → SCOPED | MIGRATION | FINAL
  • useMetadataNamespaceContext — composition hook: feature flag + the two hooks above + isTemplateManagementEnabled
  • useSidebarMetadataFetcher — accepts namespace context (enterpriseFqn, metadataNamespaceMode) and forwards it into getMetadata; can refetch when authoritative mode/FQN becomes available after the initial load
  • useMetadataTemplateItemsServiceItemsService for the template browser (namespaces / templates / client-side search)
  • useMetadataTemplateEditor / useMetadataTemplateEventService — create/edit modal + dropdown event wiring

UI

  • MetadataSidebarRedesign — uses useMetadataNamespaceContext, passes context into the fetcher, and gates template-management UI on non-SCOPED mode
  • MetadataTemplateDropdown — chooses legacy flat dropdown vs browser-backed dropdown; wires create/edit into the template editor

Dependencies

  • Bumps @box/metadata-editor
  • Adds @box/metadata-template-editor (and related peer deps used by the editor/browser)

Tests

  • Unit coverage for utils, namespace mode, enterprise id, composition context, template items/editor/event services
  • Metadata API tests for mode-aware fetching
  • Sidebar tests updated for the new fetcher argument (namespace context)

Type of change

  • Bug fix (non-breaking change addressing an issue)
  • New feature (non-breaking change adding functionality)
  • Breaking change (fix or feature causing existing functionality to change)
  • Code refactor (no functional changes)
  • Documentation update
  • Performance improvement
  • Test addition or update
  • CI/CD configuration change

Testing done

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed

Notable local suites:

nvm use
yarn test \
  src/api/__tests__/Metadata.test.js \
  src/api/__tests__/metadataNamespaceUtils.test.js \
  src/elements/content-sidebar/__tests__/useMetadataNamespaceContext.test.tsx \
  src/elements/content-sidebar/__tests__/useMetadataNamespaceMode.test.ts \
  src/elements/content-sidebar/__tests__/useCurrentUserEnterpriseId.test.ts \
  src/elements/content-sidebar/__tests__/useMetadataTemplateItemsService.test.tsx \
  src/elements/content-sidebar/__tests__/useMetadataTemplateEditor.test.tsx \
  src/elements/content-sidebar/__tests__/useSidebarMetadataFetcher.test.tsx \
  src/elements/content-sidebar/__tests__/MetadataSidebarRedesign.test.tsx \
  --no-coverage

Dependencies

  • @box/metadata-editor upgraded
  • @box/metadata-template-editor added
  • Related peer deps for the template editor/browser stack (e.g. dnd-kit, yup) as required by those packages

Deployment notes

  • Gated by metadata.namespacesOptIn.enabled. With the flag off, the sidebar stays on the legacy SCOPED path (no enterprise-config / namespace list calls from this wiring).
  • Namespace list/create/update may still use local mocks in some environments until the backend namespace API is fully rolled out. Mode resolution via enterprise configurations is the live path used to decide SCOPED vs MIGRATION vs FINAL.
  • No data migration is performed by this PR; it only adapts client fetch/UI to the enterprise’s configured mode.

How to test

  1. Use an enterprise in SCOPED, MIGRATION, and FINAL (or equivalent test fixtures).
  2. Flag off: open redesigned metadata sidebar → flat template list, no namespace browser, metadata loads as today.
  3. Flag on + SCOPED: metadata loads; template management browser stays disabled.
  4. Flag on + MIGRATION/FINAL:
    • instances/templates load with correct enterprise root FQN
    • add-template UI uses the namespace browser
    • create/edit template opens the editor and refreshes metadata afterward
  5. Spot-check externally owned / collab files still behave (limited addable templates, correct template resolution).
  6. In the Network tab, confirm template requests use the expected scope/namespace for the mode (not a blind double-fetch of the same URL from unrelated bugs).

How to review

Suggested order:

  1. metadataNamespaceUtils.js — pure rules for mode / FQN / matching
  2. MetadataNamespaces.js + Metadata.js getMetadata paths — SCOPED vs namespaced fetch and instance→template resolution
  3. Hooks: useMetadataNamespaceContext → fetcher options → template items/editor services
  4. MetadataSidebarRedesign + MetadataTemplateDropdown — feature gating and UI wiring
  5. Tests — especially mode transitions and fetcher namespace-context argument

Pay attention to:

  • Not calling namespace APIs when the opt-in flag is off
  • Not using the enterprise shorthand in MIGRATION/FINAL template fetches
  • Matching instances that only have $namespace (no $scope) during migration
  • Keeping template-management UI off unless mode is known and not SCOPED

Self-review checklist

  • Code follows the project's style guidelines
  • Code is properly documented (comments, JSDoc/docstrings, etc.)
  • Changes are covered by tests
  • All tests pass locally
  • No unnecessary console logs or debugging code
  • No sensitive information is exposed
  • No new warnings or errors are introduced
  • PR title follows conventional commit format

Running package.json scripts

  1. Please use yarn instead of npm.
  2. Before executing ANY script from package.json, please execute nvm use.

Additional notes

  • The sidebar resolves enterprise id + mode from fileId only, in parallel with the file GET used for permissions — so getMetadata can receive an authoritative enterprise root in MIGRATION/FINAL without waiting on the full file payload.
  • Template search in the browser is currently client-side over already-loaded editor templates; server-side search can replace that later.
  • Classic (non-redesign) metadata sidebar is largely unchanged by this PR; the new paths target the redesigned sidebar.

@JakubKida
JakubKida requested review from a team as code owners June 25, 2026 15:58
@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

Metadata APIs and types now support namespace-aware templates and namespace-only instances across SCOPED, MIGRATION, and FINAL modes. The sidebar adds namespace browsing, template creation/editing, schema loading, and metadata refresh flows backed by live or mocked APIs.

Changes

Namespace metadata workflow

Layer / File(s) Summary
Namespace mode and metadata contracts
src/constants.js, src/api/Base.js, src/common/types/api.js, src/common/types/metadata.js, package.json
Adds migration-mode constants, configuration support, namespace-aware Flow types, and template-editor dependencies.
Namespace-aware metadata API flow
src/api/Metadata.js, src/api/__tests__/Metadata.test.js
Adds namespace URL resolution, namespace/template listing and CRUD helpers, mode-specific fetching, fallback matching, schema normalization, and namespace-aware metadata writes.
Namespace API mock workflow
src/api/metadataNamespaceMocks.js
Adds seeded in-memory namespace and template mocks supporting listing, creation, patch updates, and editor schema retrieval.
Sidebar namespace template management
src/elements/content-sidebar/MetadataSidebarRedesign.tsx, src/elements/content-sidebar/MetadataTemplateDropdown.tsx, src/elements/content-sidebar/hooks/*, src/elements/content-sidebar/__tests__/*, src/elements/content-sidebar/MetadataInstanceEditor.tsx
Adds namespace-mode gating, template browsing, create/edit modal flows, selection translation, metadata refetching, supporting test updates, and prop reordering without value changes.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Suggested labels: ready-to-merge

Suggested reviewers: tjuanitas, dlasecki-box

Poem

A rabbit found namespaces bright,
And templates to sort just right.
Scope hopped away; names filled the queue,
Create and edit came bounding through.
The sidebar refreshed—what a view! 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title clearly identifies the main change: support for metadata templates during migration.
Description check ✅ Passed The description is detailed and covers implementation, testing, deployment, review guidance, and checklist items.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch metadata-namespace-migration-support

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.

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/box/box-ui-elements/issues/comments/4801502026","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- review_stack_entry_start -->\n\n[![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/box/box-ui-elements/pull/4653?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)\n\n<!-- review_stack_entry_end -->\n<!-- This is an auto-generated comment: review in progress by coderabbit.ai -->\n\n> [!NOTE]\n> Currently processing new changes in this PR. This may take a few minutes, please wait...\n> \n> <details>\n> <summary>⚙️ Run configuration</summary>\n> \n> **Configuration used**: Organization UI\n> \n> **Review profile**: CHILL\n> \n> **Plan**: Pro\n> \n> **Run ID**: `663bdb7e-179d-4256-a724-ff283df5d5fa`\n> \n> </details>\n> \n> <details>\n> <summary>📥 Commits</summary>\n> \n> Reviewing files that changed from the base of the PR and between 57396d82c48726c8674ca86940696070a42d3daa and 74d0d8366ffc0f85aab4d16287649b72b2f98b32.\n> \n> </details>\n> \n> <details>\n> <summary>📒 Files selected for processing (2)</summary>\n> \n> * `src/api/Metadata.js`\n> * `src/common/types/metadata.js`\n> \n> </details>\n> \n> ```ascii\n>  ________________________________________________________________________________________________________________________________________\n> < Use assertions to prevent the impossible. Assertions validate your assumptions. Use them to protect your code from an uncertain world. >\n>  ----------------------------------------------------------------------------------------------------------------------------------------\n>   \\\n>    \\   (\\__/)\n>        (•ㅅ•)\n>        /   づ\n> ```\n\n<!-- end of auto-generated comment: review in progress by coderabbit.ai -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing Touches</summary>\n\n<details>\n<summary>📝 Generate docstrings</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> Create stacked PR\n- [ ] <!-- {\"checkboxId\": \"3e1879ae-f29b-4d0d-8e06-d12b7ba33d98\"} --> Commit on current branch\n\n</details>\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `metadata-namespace-migration-support`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=box/box-ui-elements&utm_content=4653)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n\n<sub>Comment `@coderabbitai help` to get the list of available commands.</sub>\n\n<!-- tips_end -->"},"request":{"retryCount":3,"signal":{},"retries":3,"retryAfter":16}}}

@JakubKida
JakubKida force-pushed the metadata-namespace-migration-support branch from 74d0d83 to c73a5f2 Compare June 26, 2026 09: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: 10

🤖 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 `@s.md`:
- Around line 2280-2286: The LIST Cascade Policy FINAL description is using the
wrong operation wording; update the text in the metadata cascade policies
documentation so it says listing/retrieval instead of creation. Locate the
endpoint description around the GET metadata_cascade_policies entry and replace
the misleading phrase in the final section while keeping the rest of the spec
reference intact.
- Around line 2068-2072: The GET Cascade Policy (SCOPED) description is using
the wrong action wording, referring to “creation” in a retrieval endpoint.
Update the endpoint description text in the relevant GET metadata cascade policy
entry so it clearly says retrieval/fetching instead of creation, keeping the
rest of the spec reference unchanged.
- Around line 1832-1843: The LIST Instance FINAL description includes an
irrelevant scope restriction that belongs to other operations. Update the text
in the metadata listing section so it only describes the LIST Instance behavior,
and remove the “If global is passed instead of box.metadata, returns 400”
sentence from the listing entry. Use the surrounding metadata endpoint section
and its LIST Instance heading to locate the affected copy-pasted wording.
- Around line 2229-2235: The LIST Cascade Policy migration text uses the wrong
operation wording in the endpoint description; update the copy in the metadata
cascade policies section so it says “listing” or “retrieval” instead of
“creation.” Locate the affected wording in the migration docs around the GET
metadata_cascade_policies entry and replace the misleading phrase while keeping
the rest of the spec reference unchanged.
- Around line 2185-2191: The operation description for the LIST Cascade Policy
SCOPED endpoint is incorrect because it says “creation” instead of describing a
list/retrieval action. Update the text in the metadata cascade policy section so
the wording matches the GET metadata_cascade_policies endpoint and the
surrounding “LIST Cascade Policy” context, using the relevant SCOPED entry to
locate it.
- Around line 2147-2152: The GET Cascade Policy FINAL description uses the wrong
action term, since this endpoint is for retrieval rather than creation. Update
the wording in the metadata cascade policy GET section so the sentence about
scoped and namespaced cascade policy behavior refers to retrieval or fetching,
and keep the rest of the endpoint description aligned with the GET operation
name and path.
- Around line 2103-2108: The GET Metadata Cascade Policy migration description
is using the wrong operation wording, referring to “creation” for a retrieval
endpoint. Update the text in the GET Cascade Policy section so it describes
fetching/retrieving the policy rather than creating it, keeping the rest of the
endpoint details and spec reference unchanged.
- Line 1: The PR title contains a typo: update “temolates” to “templates” in the
title text so it matches the intended wording.

In `@src/api/Metadata.js`:
- Around line 565-575: The template lookup in Metadata.js can incorrectly match
a namespace-only template when $scope is undefined because the primary
templates.find in the scope-based path matches on undefined scope and blocks the
namespace fallback. Update the template selection logic around the namespace and
scope checks so the first lookup only runs when scope is actually defined, and
let the namespace-based fallback handle namespace-only instances in
MIGRATION/FINAL mode using templateKey plus namespace.
- Around line 423-431: The schema cache in getSchemaByTemplateKey currently uses
only templateKey, which can return the wrong result when scope changes between
calls. Update the cache key generation and lookup in
Metadata.getSchemaByTemplateKey/getMetadataTemplateSchemaCacheKey so it
incorporates scope alongside templateKey, and ensure the same scope-aware key is
used for both cache.has and cache.get before calling
getMetadataTemplateSchemaUrl.
🪄 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: 9cbcb786-2c6b-4362-ad31-a1b633615294

📥 Commits

Reviewing files that changed from the base of the PR and between 51720a1 and c73a5f2.

📒 Files selected for processing (3)
  • s.md
  • src/api/Metadata.js
  • src/common/types/metadata.js

Comment thread s.md Outdated
@@ -0,0 +1,2390 @@
Namespaces API Specification

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix typo in PR title: "temolates" → "templates"

The PR title contains a typo: "temolates" should be "templates".

🤖 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 `@s.md` at line 1, The PR title contains a typo: update “temolates” to
“templates” in the title text so it matches the intended wording.

Comment thread s.md Outdated
Comment on lines +1832 to +1843
2.5.3 FINAL
Full URL:
GET https://api.box.com/2.0/files/{file_id}/metadata

GET https://api.box.com/2.0/folders/{folder_id}/metadata

Both scoped and namespaced instance retrieval is allowed.
If global is passed instead of box.metadata, returns 400.
See the full specs:
https://developer.box.com/reference/get-files-id-metadata
https://developer.box.com/reference/get-folders-id-metadata

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Remove irrelevant restriction from LIST Instance (FINAL)

Line 1839 states "If global is passed instead of box.metadata, returns 400" but the LIST Instance endpoint path (/files/{file_id}/metadata) does not include a scope/namespace path parameter. This appears to be a copy-paste error from GET/CREATE/UPDATE/DELETE sections.

🤖 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 `@s.md` around lines 1832 - 1843, The LIST Instance FINAL description includes
an irrelevant scope restriction that belongs to other operations. Update the
text in the metadata listing section so it only describes the LIST Instance
behavior, and remove the “If global is passed instead of box.metadata, returns
400” sentence from the listing entry. Use the surrounding metadata endpoint
section and its LIST Instance heading to locate the affected copy-pasted
wording.

Comment thread s.md Outdated
Comment on lines +2068 to +2072
GET https://api.box.com/2.0/metadata_cascade_policies/{metadata_cascade_policy_id}

Only scoped cascade policy creation is allowed.
See the full spec https://developer.box.com/reference/get-metadata-cascade-policies-id

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fix incorrect operation description in GET Cascade Policy (SCOPED)

Line 2070 says "Only scoped cascade policy creation is allowed" but this is the GET endpoint (3.3 GET Cascade Policy). Should be "retrieval" or similar.

🤖 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 `@s.md` around lines 2068 - 2072, The GET Cascade Policy (SCOPED) description
is using the wrong action wording, referring to “creation” in a retrieval
endpoint. Update the endpoint description text in the relevant GET metadata
cascade policy entry so it clearly says retrieval/fetching instead of creation,
keeping the rest of the spec reference unchanged.

Comment thread s.md Outdated
Comment on lines +2103 to +2108
3.3.2 MIGRATION
Full URL:
GET https://api.box.com/2.0/metadata_cascade_policies/{metadata_cascade_policy_id}

Both scoped and namespaced cascade policy creation is allowed.
See the full spec https://developer.box.com/reference/get-metadata-cascade-policies-id

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fix incorrect operation description in GET Cascade Policy (MIGRATION)

Line 2107 says "Both scoped and namespaced cascade policy creation is allowed" but this is the GET endpoint. Should be "retrieval" or similar.

🤖 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 `@s.md` around lines 2103 - 2108, The GET Metadata Cascade Policy migration
description is using the wrong operation wording, referring to “creation” for a
retrieval endpoint. Update the text in the GET Cascade Policy section so it
describes fetching/retrieving the policy rather than creating it, keeping the
rest of the endpoint details and spec reference unchanged.

Comment thread s.md Outdated
Comment on lines +2147 to +2152
3.3.3 FINAL
Full URL:
GET https://api.box.com/2.0/metadata_cascade_policies/{metadata_cascade_policy_id}

Both scoped and namespaced cascade policy creation is allowed.
See the full spec https://developer.box.com/reference/get-metadata-cascade-policies-id

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fix incorrect operation description in GET Cascade Policy (FINAL)

Line 2151 says "Both scoped and namespaced cascade policy creation is allowed" but this is the GET endpoint. Should be "retrieval" or similar.

🤖 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 `@s.md` around lines 2147 - 2152, The GET Cascade Policy FINAL description uses
the wrong action term, since this endpoint is for retrieval rather than
creation. Update the wording in the metadata cascade policy GET section so the
sentence about scoped and namespaced cascade policy behavior refers to retrieval
or fetching, and keep the rest of the endpoint description aligned with the GET
operation name and path.

Comment thread s.md Outdated
Comment on lines +2185 to +2191
3.4.1 SCOPED
Full URL:
GET https://api.box.com/2.0/metadata_cascade_policies

Only scoped cascade policy creation is allowed.
See the full spec https://developer.box.com/reference/get-metadata-cascade-policies

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fix incorrect operation description in LIST Cascade Policy (SCOPED)

Line 2189 says "Only scoped cascade policy creation is allowed" but this is the LIST endpoint (3.4 LIST Cascade Policy). Should be "listing" or "retrieval".

🤖 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 `@s.md` around lines 2185 - 2191, The operation description for the LIST
Cascade Policy SCOPED endpoint is incorrect because it says “creation” instead
of describing a list/retrieval action. Update the text in the metadata cascade
policy section so the wording matches the GET metadata_cascade_policies endpoint
and the surrounding “LIST Cascade Policy” context, using the relevant SCOPED
entry to locate it.

Comment thread s.md Outdated
Comment on lines +2229 to +2235
3.4.2 MIGRATION
Full URL:
GET https://api.box.com/2.0/metadata_cascade_policies

Both scoped and namespaced cascade policy creation is allowed.
See the full spec https://developer.box.com/reference/get-metadata-cascade-policies

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fix incorrect operation description in LIST Cascade Policy (MIGRATION)

Line 2233 says "Both scoped and namespaced cascade policy creation is allowed" but this is the LIST endpoint. Should be "listing" or "retrieval".

🤖 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 `@s.md` around lines 2229 - 2235, The LIST Cascade Policy migration text uses
the wrong operation wording in the endpoint description; update the copy in the
metadata cascade policies section so it says “listing” or “retrieval” instead of
“creation.” Locate the affected wording in the migration docs around the GET
metadata_cascade_policies entry and replace the misleading phrase while keeping
the rest of the spec reference unchanged.

Comment thread s.md Outdated
Comment on lines +2280 to +2286
3.4.3 FINAL
Full URL:
GET https://api.box.com/2.0/metadata_cascade_policies

Both scoped and namespaced cascade policy creation is allowed.
See the full spec https://developer.box.com/reference/get-metadata-cascade-policies

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fix incorrect operation description in LIST Cascade Policy (FINAL)

Line 2284 says "Both scoped and namespaced cascade policy creation is allowed" but this is the LIST endpoint. Should be "listing" or "retrieval".

🤖 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 `@s.md` around lines 2280 - 2286, The LIST Cascade Policy FINAL description is
using the wrong operation wording; update the text in the metadata cascade
policies documentation so it says listing/retrieval instead of creation. Locate
the endpoint description around the GET metadata_cascade_policies entry and
replace the misleading phrase in the final section while keeping the rest of the
spec reference intact.

Comment thread src/api/Metadata.js Outdated
Comment thread src/api/Metadata.js
@JakubKida
JakubKida force-pushed the metadata-namespace-migration-support branch from c73a5f2 to c4696a8 Compare June 26, 2026 09:48
@CLAassistant

CLAassistant commented Jun 26, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@JakubKida JakubKida changed the title fix: support mid-migration metadata temolates fix: support mid-migration metadata templates Jun 26, 2026
@JakubKida
JakubKida force-pushed the metadata-namespace-migration-support branch from c4696a8 to 62f27b5 Compare July 14, 2026 07:15
@JakubKida
JakubKida requested a review from a team as a code owner July 14, 2026 07:15

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

Caution

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

⚠️ Outside diff range comments (1)
src/api/Metadata.js (1)

126-128: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Schema cache key still ignores scope/namespace — cross-scope collisions unresolved.

getMetadataTemplateSchemaCacheKey keys solely on templateKey, but getMetadataTemplateSchemaUrl (Line 706) now varies the URL by scope/namespace. A templateKey shared across an enterprise scope and a namespace FQN (exactly the MIGRATION-mode scenario this PR targets) will read/write the wrong cached schema after the first fetch.

🐛 Proposed fix
-    getMetadataTemplateSchemaCacheKey(templateKey: string): string {
-        return `${CACHE_PREFIX_METADATA}template_schema_${templateKey}`;
+    getMetadataTemplateSchemaCacheKey(templateKey: string, scope?: string = METADATA_SCOPE_ENTERPRISE): string {
+        return `${CACHE_PREFIX_METADATA}template_schema_${scope}_${templateKey}`;
     }
-        const key = this.getMetadataTemplateSchemaCacheKey(templateKey);
+        const key = this.getMetadataTemplateSchemaCacheKey(templateKey, scope);

Also applies to: 694-710

🤖 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/api/Metadata.js` around lines 126 - 128, Update
getMetadataTemplateSchemaCacheKey to include the same scope/namespace
discriminator used by getMetadataTemplateSchemaUrl, so identical templateKey
values in different scopes produce distinct cache keys. Propagate the scope or
namespace parameter through all callers, including the schema fetch flow around
getMetadataTemplateSchemaUrl, while preserving existing key formatting for the
default scope.
♻️ Duplicate comments (1)
src/api/Metadata.js (1)

843-857: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Primary scope match still short-circuits the namespace fallback when $scope is absent.

For namespace-only instances, scope is undefined. The primary match t.scope === scope succeeds for any namespace-only template with matching templateKey (since t.scope is also undefined), regardless of namespace, so the fallback on Line 851-853 never runs when multiple namespace-only templates share a templateKey. Note deleteMetadata (Line 1735-1738) in this same diff already uses the correct gated pattern (scope ? ... : ...).

🐛 Proposed fix
-        let template = templates.find(t => t.templateKey === templateKey && t.scope === scope);
+        let template = scope
+            ? templates.find(t => t.templateKey === templateKey && t.scope === scope)
+            : undefined;
🤖 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/api/Metadata.js` around lines 843 - 857, Update the primary template
lookup in the metadata resolution flow to match by scope only when scope is
defined, using the gated pattern established by deleteMetadata. For
namespace-only instances, skip the scope lookup so the namespace-based fallback
selects the template matching namespace, while preserving scoped-instance
behavior.
🧹 Nitpick comments (1)
src/elements/content-sidebar/MetadataTemplateDropdown.tsx (1)

72-82: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Production code parses a mock-specific ID encoding format.

This fallback decodes ids using the "fqn||templateKey" delimiter format that, per the comment, only the mock API produces. Coupling production dropdown logic to a mock implementation detail is fragile — if a real API id ever coincidentally contains ||, this would silently mis-parse namespaceFqn/templateKey. Consider passing the browser-shape template object itself (or its resolved namespace/templateKey) through the event instead of re-deriving it from an encoded id string.

🤖 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/MetadataTemplateDropdown.tsx` around lines 72 -
82, Remove the mock-specific "fqn||templateKey" parsing from the fallback in
MetadataTemplateDropdown and pass the resolved browser-shape template data,
including namespaceFqn and templateKey, through the edit event instead. Update
the surrounding lookup/event flow so real API IDs are never interpreted as
encoded mock IDs, while preserving editing for resolved and newly created
templates.
🤖 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/api/Metadata.js`:
- Around line 428-458: Update updateMetadataTemplate to evict the metadata
template schema cache after a successful update, using
getMetadataTemplateSchemaCacheKey(templateKey). Include the relevant scope in
the cache key generation so namespace and enterprise schemas for the same
templateKey cannot share cached entries.
- Around line 1032-1055: The getEnterpriseScopeFromInstances method must extract
the enterprise scope from dot-delimited namespace values as well as path-like
values. Update the $namespace parsing so names such as enterprise_123456.legal
return enterprise_123456, while preserving the existing $scope precedence and
null behavior.
- Around line 1111-1133: Update the non-SCOPED branch around
getEnterpriseScopeFromInstances so enterpriseScope is resolved from an
authoritative bootstrap source before template fetching, rather than relying
only on instances. Preserve the instances-derived value as a fallback if
appropriate, and use the resolved enterprise FQN when gating and calling
getTemplates for enterprise templates so files without metadata can still reach
template management.

In `@src/api/metadataNamespaceMocks.js`:
- Line 200: Update mockUpdateMetadataTemplate so its successCallback receives
the fully updated metadata template, including existing properties such as id,
displayName, fields, and the updated templateKey, instead of the current stub
object; preserve the existing success flow.

In `@src/elements/content-sidebar/hooks/useMetadataTemplateEditor.tsx`:
- Around line 2-8: Add the missing `@box/metadata-template-editor` package to
package.json dependencies so imports in
src/elements/content-sidebar/hooks/useMetadataTemplateEditor.tsx (lines 2-8) and
src/elements/content-sidebar/MetadataSidebarRedesign.tsx (lines 20-24) resolve
successfully; no direct source changes are needed at either import site.

In `@src/elements/content-sidebar/hooks/useSidebarMetadataFetcher.ts`:
- Around line 291-293: Update the template lookup in extractSuggestions to
compare the candidate template’s scope or namespace directly against the
function’s scope parameter, while retaining the templateKey match. Remove the
truthiness-only condition so templates from different scopes cannot be selected.

In `@src/elements/content-sidebar/MetadataSidebarRedesign.tsx`:
- Around line 176-179: Guard the template lookup in the enterprise ID
initialization so it safely handles an undefined templates value, matching the
existing checks in isViewMode and metadataDropdown. Update the expression using
templates.find(...) to fall back to an empty collection while preserving the
existing enterprise scope filtering and numeric ID extraction.

---

Outside diff comments:
In `@src/api/Metadata.js`:
- Around line 126-128: Update getMetadataTemplateSchemaCacheKey to include the
same scope/namespace discriminator used by getMetadataTemplateSchemaUrl, so
identical templateKey values in different scopes produce distinct cache keys.
Propagate the scope or namespace parameter through all callers, including the
schema fetch flow around getMetadataTemplateSchemaUrl, while preserving existing
key formatting for the default scope.

---

Duplicate comments:
In `@src/api/Metadata.js`:
- Around line 843-857: Update the primary template lookup in the metadata
resolution flow to match by scope only when scope is defined, using the gated
pattern established by deleteMetadata. For namespace-only instances, skip the
scope lookup so the namespace-based fallback selects the template matching
namespace, while preserving scoped-instance behavior.

---

Nitpick comments:
In `@src/elements/content-sidebar/MetadataTemplateDropdown.tsx`:
- Around line 72-82: Remove the mock-specific "fqn||templateKey" parsing from
the fallback in MetadataTemplateDropdown and pass the resolved browser-shape
template data, including namespaceFqn and templateKey, through the edit event
instead. Update the surrounding lookup/event flow so real API IDs are never
interpreted as encoded mock IDs, while preserving editing for resolved and newly
created templates.
🪄 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: 8a483e3e-d013-45db-97e8-22bd0b44e780

📥 Commits

Reviewing files that changed from the base of the PR and between c4696a8 and 62f27b5.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (16)
  • package.json
  • src/api/Base.js
  • src/api/Metadata.js
  • src/api/metadataNamespaceMocks.js
  • src/common/types/api.js
  • src/common/types/metadata.js
  • src/constants.js
  • src/elements/content-sidebar/MetadataInstanceEditor.tsx
  • src/elements/content-sidebar/MetadataSidebarRedesign.tsx
  • src/elements/content-sidebar/MetadataTemplateDropdown.tsx
  • src/elements/content-sidebar/__tests__/MetadataSidebarRedesign.test.tsx
  • src/elements/content-sidebar/hooks/useMetadataNamespaceMode.ts
  • src/elements/content-sidebar/hooks/useMetadataTemplateEditor.tsx
  • src/elements/content-sidebar/hooks/useMetadataTemplateEventService.ts
  • src/elements/content-sidebar/hooks/useMetadataTemplateItemsService.ts
  • src/elements/content-sidebar/hooks/useSidebarMetadataFetcher.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/common/types/metadata.js

Comment thread src/api/Metadata.js Outdated
Comment on lines +428 to +458
async updateMetadataTemplate(
file: BoxItem,
namespaceFqn: string,
templateKey: string,
patchItems: Array<Object>,
successCallback: Function,
errorCallback: ElementsErrorCallback,
): Promise<void> {
// TODO(MDX-2136): remove next two lines when namespace API is deployed
if (IS_NAMESPACE_API_MOCKED) {
mockUpdateMetadataTemplate(file, namespaceFqn, templateKey, patchItems, successCallback);
return;
}

const { id }: BoxItem = file;
this.errorCode = ERROR_CODE_UPDATE_METADATA_TEMPLATE;
const url = this.getMetadataTemplateSchemaUrl(templateKey, namespaceFqn);
try {
const response = await this.xhr.put({
url,
id: getTypedFileId(id),
headers: { [HEADER_CONTENT_TYPE]: 'application/json-patch+json' },
data: patchItems,
});
if (!this.isDestroyed()) {
successCallback(getProp(response, 'data'));
}
} catch (e) {
errorCallback(e, this.errorCode);
}
}

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map Metadata.js structure and locate cache-related symbols
ast-grep outline src/api/Metadata.js --view expanded || true

printf '\n--- Search for cache key and invalidation symbols ---\n'
rg -n "getMetadataTemplateSchemaCacheKey|getSchemaByTemplateKey|cache\.unset|cache\.unsetAll|updateMetadataTemplate|metadata template schema" src/api/Metadata.js

printf '\n--- Relevant surrounding lines ---\n'
nl -ba src/api/Metadata.js | sed -n '360,760p'

Repository: box/box-ui-elements

Length of output: 814


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for all references to schema cache key generation and invalidation across the repo
rg -n "getMetadataTemplateSchemaCacheKey|getSchemaByTemplateKey|unsetAll\(|unset\(" src

Repository: box/box-ui-elements

Length of output: 3850


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1080,1225p' src/api/Metadata.js
printf '\n--- schema fetch ---\n'
sed -n '684,725p' src/api/Metadata.js
printf '\n--- updateMetadataTemplate ---\n'
sed -n '428,470p' src/api/Metadata.js

Repository: box/box-ui-elements

Length of output: 8860


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the exact methods around the cache.unset calls and the schema cache helpers
python3 - <<'PY'
from pathlib import Path
p = Path('src/api/Metadata.js')
lines = p.read_text().splitlines()
for start, end in [(1080, 1225), (684, 725), (1100, 1225), (100, 140)]:
    print(f"\n--- lines {start}-{end} ---")
    for i in range(start-1, min(end, len(lines))):
        print(f"{i+1}: {lines[i]}")
PY

Repository: box/box-ui-elements

Length of output: 15194


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
p = Path('src/api/Metadata.js')
lines = p.read_text().splitlines()
for start, end in [(220, 280), (720, 820), (820, 920)]:
    print(f"\n--- lines {start}-{end} ---")
    for i in range(start-1, min(end, len(lines))):
        print(f"{i+1}: {lines[i]}")
PY

printf '\n--- callers of getSchemaByTemplateKey ---\n'
rg -n "getSchemaByTemplateKey\(" src

Repository: box/box-ui-elements

Length of output: 12725


Clear the metadata template schema cache after updates
updateMetadataTemplate never evicts getMetadataTemplateSchemaCacheKey(templateKey), so a cached schema can stay stale for the rest of the session. The cache key also ignores scope, which can mix schemas for the same templateKey across namespace/enterprise variants.

🧰 Tools
🪛 Biome (2.5.3)

[error] 429-429: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

(parse)


[error] 430-430: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

(parse)


[error] 431-431: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

(parse)


[error] 432-432: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

(parse)


[error] 433-433: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

(parse)


[error] 434-434: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

(parse)


[error] 435-435: return type annotation are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

(parse)


[error] 442-442: type annotation are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

(parse)

🤖 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/api/Metadata.js` around lines 428 - 458, Update updateMetadataTemplate to
evict the metadata template schema cache after a successful update, using
getMetadataTemplateSchemaCacheKey(templateKey). Include the relevant scope in
the cache key generation so namespace and enterprise schemas for the same
templateKey cannot share cached entries.

Comment thread src/api/Metadata.js
Comment thread src/api/Metadata.js
Comment thread src/api/metadataNamespaceMocks.js
Comment thread src/elements/content-sidebar/hooks/useMetadataTemplateEditor.tsx
Comment thread src/elements/content-sidebar/hooks/useSidebarMetadataFetcher.ts Outdated
Comment thread src/elements/content-sidebar/MetadataSidebarRedesign.tsx Outdated
@JakubKida
JakubKida force-pushed the metadata-namespace-migration-support branch from 62f27b5 to 064bd17 Compare July 15, 2026 09:40
@socket-security

socket-security Bot commented Jul 15, 2026

Copy link
Copy Markdown

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

🤖 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/api/Metadata.js`:
- Around line 1755-1766: Guard the findIndex results in both metadata cache
removal branches before calling splice: only remove an entry when the returned
index is non-negative. Apply this to the instance lookup and the editor lookup
in the surrounding metadata update logic, preserving the existing matching
predicates and preventing splice(-1, 1) from removing an unrelated last entry.

In `@src/api/metadataNamespaceMocks.js`:
- Line 16: Update IS_NAMESPACE_API_MOCKED in metadataNamespaceMocks.js to
default to the live backend instead of being hardcoded true. Gate the in-memory
namespace mocks behind the existing development or test configuration so list,
create, and update flows use mocks only in those environments.

In `@src/elements/content-sidebar/hooks/useMetadataNamespaceMode.ts`:
- Around line 47-70: Update the useEffect in useMetadataNamespaceMode to use a
local cancellation flag scoped to each effect invocation instead of the shared
cancelledRef, setting it in the cleanup and checking it before applying results.
Cast the Promise result from getMetadataNamespaceMode to MetadataScopeMode |
null before passing it to setMode.
🪄 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: 881464c5-9db4-4df6-be32-68bcde47a46d

📥 Commits

Reviewing files that changed from the base of the PR and between 62f27b5 and 064bd17.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (16)
  • package.json
  • src/api/Base.js
  • src/api/Metadata.js
  • src/api/metadataNamespaceMocks.js
  • src/common/types/api.js
  • src/common/types/metadata.js
  • src/constants.js
  • src/elements/content-sidebar/MetadataInstanceEditor.tsx
  • src/elements/content-sidebar/MetadataSidebarRedesign.tsx
  • src/elements/content-sidebar/MetadataTemplateDropdown.tsx
  • src/elements/content-sidebar/__tests__/MetadataSidebarRedesign.test.tsx
  • src/elements/content-sidebar/hooks/useMetadataNamespaceMode.ts
  • src/elements/content-sidebar/hooks/useMetadataTemplateEditor.tsx
  • src/elements/content-sidebar/hooks/useMetadataTemplateEventService.ts
  • src/elements/content-sidebar/hooks/useMetadataTemplateItemsService.ts
  • src/elements/content-sidebar/hooks/useSidebarMetadataFetcher.ts
🚧 Files skipped from review as they are similar to previous changes (12)
  • src/common/types/api.js
  • src/common/types/metadata.js
  • src/elements/content-sidebar/MetadataInstanceEditor.tsx
  • package.json
  • src/elements/content-sidebar/hooks/useMetadataTemplateEventService.ts
  • src/elements/content-sidebar/hooks/useSidebarMetadataFetcher.ts
  • src/elements/content-sidebar/hooks/useMetadataTemplateEditor.tsx
  • src/elements/content-sidebar/hooks/useMetadataTemplateItemsService.ts
  • src/elements/content-sidebar/MetadataTemplateDropdown.tsx
  • src/elements/content-sidebar/tests/MetadataSidebarRedesign.test.tsx
  • src/constants.js
  • src/elements/content-sidebar/MetadataSidebarRedesign.tsx

Comment thread src/api/Metadata.js
Comment on lines +1755 to +1766
instance =>
instance.templateKey === templateKey &&
(scope ? instance.scope === scope : instance.namespace === namespace),
),
1,
);
} else {
metadata.editors.splice(
metadata.editors.findIndex(
editor => editor.template.scope === scope && editor.template.templateKey === templateKey,
editor =>
editor.template.templateKey === templateKey &&
(scope ? editor.template.scope === scope : editor.template.namespace === namespace),

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Guard findIndex results before splicing the cache.

When no matching instance or editor exists, findIndex returns -1, causing splice(-1, 1) to remove the last unrelated entry.

Proposed fix
- metadata.instances.splice(metadata.instances.findIndex(instance => /* match */), 1);
+ const instanceIndex = metadata.instances.findIndex(instance => /* match */);
+ if (instanceIndex >= 0) {
+     metadata.instances.splice(instanceIndex, 1);
+ }

- metadata.editors.splice(metadata.editors.findIndex(editor => /* match */), 1);
+ const editorIndex = metadata.editors.findIndex(editor => /* match */);
+ if (editorIndex >= 0) {
+     metadata.editors.splice(editorIndex, 1);
+ }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
instance =>
instance.templateKey === templateKey &&
(scope ? instance.scope === scope : instance.namespace === namespace),
),
1,
);
} else {
metadata.editors.splice(
metadata.editors.findIndex(
editor => editor.template.scope === scope && editor.template.templateKey === templateKey,
editor =>
editor.template.templateKey === templateKey &&
(scope ? editor.template.scope === scope : editor.template.namespace === namespace),
const instanceIndex = metadata.instances.findIndex(
instance =>
instance.templateKey === templateKey &&
(scope ? instance.scope === scope : instance.namespace === namespace),
);
if (instanceIndex >= 0) {
metadata.instances.splice(instanceIndex, 1);
}
} else {
const editorIndex = metadata.editors.findIndex(
editor =>
editor.template.templateKey === templateKey &&
(scope ? editor.template.scope === scope : editor.template.namespace === namespace),
);
if (editorIndex >= 0) {
metadata.editors.splice(editorIndex, 1);
}
🤖 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/api/Metadata.js` around lines 1755 - 1766, Guard the findIndex results in
both metadata cache removal branches before calling splice: only remove an entry
when the returned index is non-negative. Apply this to the instance lookup and
the editor lookup in the surrounding metadata update logic, preserving the
existing matching predicates and preventing splice(-1, 1) from removing an
unrelated last entry.

Comment thread src/api/metadataNamespaceMocks.js
Comment thread src/elements/content-sidebar/hooks/useMetadataNamespaceMode.ts Outdated
@JakubKida JakubKida closed this Jul 15, 2026
@JakubKida JakubKida reopened this Jul 15, 2026
@JakubKida
JakubKida force-pushed the metadata-namespace-migration-support branch from 4145a1c to 7b3fcd8 Compare July 16, 2026 12:33
@JakubKida
JakubKida force-pushed the metadata-namespace-migration-support branch 3 times, most recently from d42825c to f9ee5bb Compare July 24, 2026 14:08
@JakubKida
JakubKida force-pushed the metadata-namespace-migration-support branch from d435ca2 to fd99409 Compare August 3, 2026 13:09
Comment thread package.json Outdated
Comment thread src/elements/content-sidebar/hooks/useMetadataTemplateEventService.ts Outdated
Comment thread src/elements/content-sidebar/MetadataSidebarRedesign.tsx Outdated
@JakubKida
JakubKida force-pushed the metadata-namespace-migration-support branch from 9a47365 to 47c2478 Compare August 4, 2026 09:45
* The modal JSX to render somewhere stable in the tree (e.g. beside
* `SidebarContent`). `null` when the editor is closed.
*/
modal: React.ReactNode;

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.

hmmm i guess there is nothing technically wrong with having a hook return JSX, i'm just not used to seeing it. i would more expect there to be a standalone component to contain the JSX, and then that component uses this hook to manage the data.

i'm fine with doing things your way unless this piques anyone else's interest!

Comment thread src/constants.js
@@ -342,6 +351,7 @@ export const ERROR_CODE_UPDATE_TASK_COLLABORATOR = 'update_task_collaborator_err
export const ERROR_CODE_UPDATE_COMMENT = 'update_comment_error';
export const ERROR_CODE_UPDATE_SKILLS = 'update_skills_error';
export const ERROR_CODE_UPDATE_METADATA = 'update_metadata_error';

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.

just curious since this could be confusing - is update_metadata_error for updating metadata instances? or some other metadata issue other than template?

Comment thread package.json
"@box/content-field": "^1.40.23",
"@box/copy-input": "^1.42.16",
"@box/item-icon": "^3.2.0",
"@box/metadata-editor": "^2.2.11",

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.

Comment thread package.json
"@chromatic-com/storybook": "^5.2.1",
"@commitlint/cli": "^19.8.0",
"@commitlint/config-conventional": "^19.8.0",
"@dnd-kit/core": "^6.1.0",

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.

just calling out, other box-internal parent apps may need to add these as new deps which they may not be happy about. just something to look out for when developing shared features -> buie. i assume you're working on this same task though so it may be you doing that work

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.

4 participants