Skip to content

feat(media): add folder management to the media browser - #1121

Merged
stipsan merged 8 commits into
mainfrom
cursor/port-media-folder-management-c619
Aug 3, 2026
Merged

feat(media): add folder management to the media browser#1121
stipsan merged 8 commits into
mainfrom
cursor/port-media-folder-management-c619

Conversation

@stipsan

@stipsan stipsan commented Jun 17, 2026

Copy link
Copy Markdown
Member

Summary

Ports folder management from sanity-io/sanity-plugin-media#281 into the monorepo, then incorporates Pedro’s follow-up from add-folder-support-review.

Authors

Behavior

  • Reference-based media.folder documents (name + weak parent) and weak opt.media.folder on assets
  • Folders sidebar (closed by default), All assets as the default view, breadcrumbs, create/rename/move
  • Non-recursive folder delete (unset asset refs, promote children, delete the folder doc)
  • Bulk move assets; folder section in asset details; multi-select insert for array asset sources
  • Folder search facet limited to empty / not empty on opt.media.folder._ref
  • Small viewports open folders in a dialog (same pattern as tags)

Babysit follow-ups

  • Merged latest main (useMediaIndex, functional ReduxProvider)
  • Copilot: per-folder asset counts, window guard for touch, facet _ref, icons v5 subpath imports
  • Bugbot: reload assets when the current folder is deleted/disappears; mobile folders dialog

Test plan

  • pnpm lint
  • pnpm --filter sanity-plugin-media build
  • pnpm --filter sanity-plugin-media exec vitest run (157 tests)
  • Manual: open Folders panel/dialog, create/rename/move/delete, confirm asset grid refreshes after deleting the current folder
Open in Web Open in Cursor 

Port of sanity-io/sanity-plugin-media#281 by @bobbygeo.

Adds reference-based folder support: a media.folder document type
(name + weak parent ref) and a single weak opt.media.folder reference
on each asset (mirroring tags). Includes a folder sidebar with tree and
breadcrumb navigation, create/rename/move/recursive-delete flows, a bulk
"Move to folder" dialog, and multi-select insert when used as an asset
source for array fields. The default Home view lists unfiled assets.
@changeset-bot

changeset-bot Bot commented Jun 17, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 56c4ad7

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
sanity-plugin-media Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Jun 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
plugins-studio Ready Ready Preview Jul 30, 2026 1:38pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
plugins-e2e-test-studio Ignored Ignored Jul 30, 2026 1:38pm

Request Review

@stipsan stipsan added the 🤖 bot label Jun 17, 2026 — with Cursor
@stipsan
stipsan marked this pull request as ready for review June 17, 2026 15:47
@stipsan
stipsan requested a review from a team as a code owner June 17, 2026 15:47
@stipsan
stipsan requested review from Copilot and pedrobonamin and removed request for a team June 17, 2026 15:47

Copilot AI 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.

Pull request overview

Ports and integrates folder management into sanity-plugin-media, adding a reference-based folder data model (media.folder) and associated UI/Redux flows so users can create, browse, rename, move, and recursively delete folders, as well as move assets between them and support multi-select insert when used as an asset source.

Changes:

  • Add media.folder schema + opt.media.folder weak reference on assets, and update GROQ filtering to scope assets to the current folder/home.
  • Introduce full folder UI (sidebar tree, breadcrumbs, folder cards/rows, create/rename/move dialogs, bulk “Move to folder”) plus state management (Redux slice + epics + notifications).
  • Enable multi-select insertion behavior when used as an asset source for array/multiple fields.

Reviewed changes

Copilot reviewed 42 out of 42 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
plugins/sanity-plugin-media/src/utils/constructFilter.ts Adds currentFolderId-aware filtering to scope assets by folder vs home/unfiled.
plugins/sanity-plugin-media/src/utils/constructFilter.test.ts Updates snapshot expectation to include the new home/unfiled folder filter.
plugins/sanity-plugin-media/src/types/index.ts Extends types for folders, folder dialogs, folder card items, and upload folder targeting.
plugins/sanity-plugin-media/src/schemas/folder.ts Introduces media.folder document schema with weak parent reference and preview.
plugins/sanity-plugin-media/src/plugin.tsx Registers the new folder schema in the plugin’s schema types.
plugins/sanity-plugin-media/src/modules/uploads/index.ts Persists uploaded assets into the current folder via a post-upload patch; passes folder to filters.
plugins/sanity-plugin-media/src/modules/selectors.ts Includes current folder’s child folders in the combined virtualized items list.
plugins/sanity-plugin-media/src/modules/selectors.test.ts Updates selector test fixture state to include the new folders reducer slice.
plugins/sanity-plugin-media/src/modules/notifications/index.ts Adds folder create/delete/rename notifications and includes folder errors in generic error handling.
plugins/sanity-plugin-media/src/modules/index.ts Wires the new folders reducer + epics and folder-related notifications into the root module.
plugins/sanity-plugin-media/src/modules/folders/index.ts Implements folders Redux slice, selectors, and epics for fetch/create/rename/move/delete + refresh behavior.
plugins/sanity-plugin-media/src/modules/dialog/index.ts Adds folder dialog types and confirm-delete-folder flow; clears dialogs on folder/asset changes.
plugins/sanity-plugin-media/src/modules/dialog/actions.ts Adds dialog actions for folder create/move/rename dialogs.
plugins/sanity-plugin-media/src/modules/assets/index.ts Adds bulk asset “set folder” transaction flow + local state updates + refresh behavior.
plugins/sanity-plugin-media/src/formSchema/index.ts Adds folderFormSchema for folder create/rename dialogs.
plugins/sanity-plugin-media/src/contexts/AssetSourceDispatchContext.tsx Adds isMultiSelect flag to control selection behavior in asset-source mode.
plugins/sanity-plugin-media/src/constants.ts Adds folder-related constants and order options (including a folder sort option).
plugins/sanity-plugin-media/src/config/searchFacets.ts Adds a new “Folder” search facet configuration.
plugins/sanity-plugin-media/src/config/orders.ts Adds order labels for folder ordering.
plugins/sanity-plugin-media/src/components/TableRowFolder/index.tsx Adds a table row renderer for folder items in the table view.
plugins/sanity-plugin-media/src/components/TableRowAsset/index.tsx Adjusts click/context behavior for single vs multi-select asset-source mode.
plugins/sanity-plugin-media/src/components/ReduxProvider/index.tsx Extends the initial Redux state with the new folders slice defaults.
plugins/sanity-plugin-media/src/components/PickedBar/index.tsx Adds “Move to folder” action (tool mode) and “Insert selected” action (multi-select asset-source mode).
plugins/sanity-plugin-media/src/components/Items/index.tsx Auto-hides folders/tags panels on small breakpoints and includes folders panel state.
plugins/sanity-plugin-media/src/components/FormBuilderTool/index.tsx Detects multi-select asset-source usage and passes isMultiSelect through to the browser.
plugins/sanity-plugin-media/src/components/FolderView/index.tsx Implements the folders sidebar tree UI with counts and folder actions.
plugins/sanity-plugin-media/src/components/FolderPanel/index.tsx Adds the collapsible folders panel wrapper and scroll container.
plugins/sanity-plugin-media/src/components/FolderBreadcrumbs/index.tsx Adds mobile breadcrumb navigation for the current folder path.
plugins/sanity-plugin-media/src/components/Dialogs/index.tsx Registers the new folder dialogs in the dialog renderer.
plugins/sanity-plugin-media/src/components/DialogFolderRename/index.tsx Adds the folder rename dialog using zod + react-hook-form.
plugins/sanity-plugin-media/src/components/DialogFolderMove/index.tsx Adds bulk move dialog with folder tree picker.
plugins/sanity-plugin-media/src/components/DialogFolderCreate/index.tsx Adds folder creation dialog (optionally under a parent folder).
plugins/sanity-plugin-media/src/components/Controls/index.tsx Adds “New folder” controls and a folders panel toggle.
plugins/sanity-plugin-media/src/components/CardFolder/index.tsx Adds a grid card renderer for folder items in the grid view.
plugins/sanity-plugin-media/src/components/CardAsset/index.tsx Adjusts click/context behavior for single vs multi-select asset-source mode.
plugins/sanity-plugin-media/src/components/Browser/useBrowserInit.ts Fetches folders on init and listens for folder document changes to refresh.
plugins/sanity-plugin-media/src/components/Browser/index.tsx Adds folders panel + breadcrumbs, and passes multi-select info into context.
plugins/sanity-plugin-media/src/components/AssetTableVirtualized/index.tsx Supports rendering folder rows alongside assets/uploads in table view.
plugins/sanity-plugin-media/src/components/AssetGridVirtualized/index.tsx Supports rendering folder cards alongside assets/uploads in grid view.
plugins/sanity-plugin-media/src/tests/fixtures/rootState.ts Extends test root state fixture with folders slice defaults.
plugins/sanity-plugin-media/README.md Documents folder behavior and querying opt.media.folder in GROQ; updates feature list.
.changeset/media-folder-management.md Adds a minor changeset with author: credit for the original contributor.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread plugins/sanity-plugin-media/src/modules/folders/index.ts Outdated
Comment thread plugins/sanity-plugin-media/src/components/FolderView/index.tsx Outdated
Comment thread plugins/sanity-plugin-media/src/components/Controls/index.tsx
Comment thread plugins/sanity-plugin-media/src/constants.ts Outdated
Comment thread plugins/sanity-plugin-media/src/config/orders.ts Outdated
Comment thread plugins/sanity-plugin-media/src/config/searchFacets.ts
@pedrobonamin

Copy link
Copy Markdown
Contributor

We need to include the changes from this branch as well https://github.com/sanity-io/sanity-plugin-media/compare/add-folder-support-review, it fixes the comments and suggestions I added to the last changes in the PR

Resolve 4 conflicts in the media plugin (all simple - compatible intents):
- contexts/AssetSourceDispatchContext: keep main's useMemo wrapper and add
  the isMultiSelect field from this branch.
- modules/assets: keep the folder patch helper; drop the unused duplicate
  assetsRemoveTagsEpic that main removed.
- modules/uploads: keep the added 'from' rxjs import; drop the unused
  Selector import that main removed.
- types: keep the folderFormSchema import; drop the unused
  SUPPORTED_ASSET_TYPES import that main removed.

Adapt folder code to main's stricter tooling (noUncheckedIndexedAccess +
React Compiler lint): local-capture indexed lookups, bracket-notation form
data access, react/react-compiler suppressions for the dialog Footer and the
auto-expand effects, and add the missing folders effect dependency.
pedrobonamin and others added 2 commits June 19, 2026 14:17
Ports the add-folder-support-review changes by @pedrobonamin (his review
feedback on the original PR):

- Treat "All assets" as the default browser view; only filter by folder
  when one is opened (no folder filter at the root).
- Rebuild the folder sidebar and the move dialog on @sanity/ui Tree/TreeItem.
- Move the Folders toggle next to the view switcher and drop the redundant
  "New folder" button next to the filters.
- Show and edit an asset's folder (change / remove) from the asset details
  dialog.
- Make folder deletion non-recursive: clear the folder ref on contained
  assets and promote child folders one level up. Remove the unused
  folder-move epic and the moving state.
- Drop the folder sort order and restrict the folder search facet to
  empty / notEmpty.
…ent-c619' into cursor/port-media-folder-management-c619
cursoragent and others added 2 commits July 30, 2026 13:26
Resolve conflicts with mediaIndex panel hiding, functional ReduxProvider
preloaded folders state, and typed selectCombinedItems folder cards.

Also address remaining Copilot review notes: count assets per folder in
GROQ, guard ontouchstart behind window, and target folder._ref in the
empty/notEmpty facet.

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
@sanity/icons v5 types FolderIcon/AddIcon/EditIcon/TrashIcon as never
from the root entry; import from dedicated subpaths like the rest of
the plugin after the main merge.
Copilot AI review requested due to automatic review settings July 30, 2026 13:28
@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown

✅ E2E Tests

🟢 24 passedview full reportview run

Studio: https://plugins-e2e-test-studio-oxqp6kz6c.sanity.dev

Datasets: pr-1121-chromium-30547771228, pr-1121-firefox-30547771228

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d7a5a7c. Configure here.

Comment thread plugins/sanity-plugin-media/src/modules/folders/index.ts
Comment thread plugins/sanity-plugin-media/src/components/Items/index.tsx
@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 31.38% 5158 / 16432
🔵 Statements 31.09% 5433 / 17472
🔵 Functions 26.92% 1338 / 4970
🔵 Branches 22.31% 2572 / 11527
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
plugins/sanity-plugin-media/src/constants.ts 100% 100% 100% 100%
plugins/sanity-plugin-media/src/__tests__/fixtures/rootState.ts 100% 100% 100% 100%
plugins/sanity-plugin-media/src/components/AssetGridVirtualized/index.tsx 46.87% 23.07% 28.57% 45.16% 27-39, 50-51, 64-65, 81-96
plugins/sanity-plugin-media/src/components/AssetTableVirtualized/index.tsx 8.69% 0% 0% 9.09% 25-49, 54-81
plugins/sanity-plugin-media/src/components/Browser/index.tsx 100% 100% 100% 100%
plugins/sanity-plugin-media/src/components/Browser/useBrowserInit.ts 40% 22.22% 47.05% 37.73% 20-23, 28-41, 48-61, 99, 102-104, 114-132
plugins/sanity-plugin-media/src/components/CardAsset/index.tsx 90.19% 81.53% 100% 89.79% 128, 139-142, 159
plugins/sanity-plugin-media/src/components/CardFolder/index.tsx 44.44% 0% 0% 44.44% 37-61, 64-70
plugins/sanity-plugin-media/src/components/Controls/index.tsx 79.16% 70% 54.54% 73.68% 30, 34, 38, 42, 46
plugins/sanity-plugin-media/src/components/DialogAssetEdit/Details.tsx 63.15% 65.62% 42.85% 68.75% 17, 19-20, 143-196
plugins/sanity-plugin-media/src/components/DialogAssetEdit/index.tsx 53.9% 40.67% 56.75% 58.53% 34, 78-101, 105, 107-108, 147, 159-162, 169-174, 181, 189, 197, 207-211, 216-244, 251, 267-271, 284, 300-302, 309-314, 370, 420
plugins/sanity-plugin-media/src/components/DialogFolderCreate/index.tsx 4.76% 0% 0% 5.55% 26-109
plugins/sanity-plugin-media/src/components/DialogFolderMove/index.tsx 11.11% 0% 0% 12.12% 17-25, 41-61, 75-83, 89-172
plugins/sanity-plugin-media/src/components/DialogFolderRename/index.tsx 4.34% 0% 0% 5.26% 23-105
plugins/sanity-plugin-media/src/components/DialogFolders/index.tsx 16.66% 100% 0% 16.66% 19-39
plugins/sanity-plugin-media/src/components/Dialogs/index.tsx 23.33% 8.33% 100% 20.68% 23-106
plugins/sanity-plugin-media/src/components/FolderBreadcrumbs/index.tsx 63.63% 25% 40% 60% 16-36
plugins/sanity-plugin-media/src/components/FolderPanel/index.tsx 83.33% 50% 100% 80% 14-36
plugins/sanity-plugin-media/src/components/FolderView/index.tsx 10.63% 0% 0% 11.9% 31-39, 64-87, 100-149, 153-173, 180-283
plugins/sanity-plugin-media/src/components/FormBuilderTool/index.tsx 86.36% 100% 66.66% 85.71% 26-27, 72
plugins/sanity-plugin-media/src/components/Items/index.tsx 88.46% 68.42% 87.5% 85.71% 30-31, 40
plugins/sanity-plugin-media/src/components/PickedBar/index.tsx 53.84% 14.28% 25% 54.16% 25, 29, 33, 36, 39-52, 59-136
plugins/sanity-plugin-media/src/components/ReduxProvider/index.tsx 100% 100% 100% 100%
plugins/sanity-plugin-media/src/components/TableRowAsset/index.tsx 7.57% 0% 0% 8.33% 57-70, 81-85, 92-94, 98-385
plugins/sanity-plugin-media/src/components/TableRowFolder/index.tsx 30% 0% 0% 30% 17-30, 33-51, 54-60
plugins/sanity-plugin-media/src/config/searchFacets.ts 44.44% 11.11% 33.33% 44.44% 181, 269-273, 282, 290-294, 302-314
plugins/sanity-plugin-media/src/contexts/AssetSourceDispatchContext.tsx 90.9% 66.66% 100% 90.9% 38
plugins/sanity-plugin-media/src/formSchema/index.ts 63.63% 50% 100% 63.63% 8-12
plugins/sanity-plugin-media/src/modules/index.ts 100% 100% 100% 100%
plugins/sanity-plugin-media/src/modules/selectors.ts 90.9% 100% 83.33% 88.88% 16-23
plugins/sanity-plugin-media/src/modules/assets/index.ts 74.91% 34.17% 73.64% 74.62% 117-119, 135-137, 169, 176, 219-238, 375-376, 398-407, 430, 451, 496-523, 532, 541-546, 551, 558-562, 567, 570-582, 589-592, 610-613, 658, 688-697, 729-738, 750-781, 791-795, 846-854, 882
plugins/sanity-plugin-media/src/modules/dialog/actions.ts 60% 0% 50% 60% 9-11, 25-27
plugins/sanity-plugin-media/src/modules/dialog/index.ts 85.29% 75% 82.35% 87.69% 28-33, 45-50, 67-70, 263, 281
plugins/sanity-plugin-media/src/modules/folders/index.ts 45.29% 28.88% 50.63% 43.84% 64-96, 104-124, 142-143, 158-170, 182-193, 234-238, 241, 243, 286, 327-384, 439-447, 458-513, 548-564, 572-590, 619, 622-640, 647
plugins/sanity-plugin-media/src/modules/notifications/index.ts 91.93% 86.66% 89.65% 91.93% 27, 41, 204, 210, 216
plugins/sanity-plugin-media/src/modules/uploads/index.ts 65.51% 28.94% 63.88% 65.11% 52, 56-61, 72-78, 141, 156-194, 206-229, 239-243, 289-292
plugins/sanity-plugin-media/src/utils/constructFilter.ts 100% 79.16% 100% 100%
Generated in workflow #8362 for commit 56c4ad7 by the Vitest Coverage Report Action

Copilot AI 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.

Pull request overview

Copilot reviewed 46 out of 46 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (4)

plugins/sanity-plugin-media/src/components/CardFolder/index.tsx:76

  • FolderCard defines a hover border-color in styled-components, but the inline style={{border: '1px solid transparent'}} wins in the cascade (inline styles override stylesheet rules). As a result, the hover border color change won’t apply.
        radius={2}
        style={{
          background: getSchemeColor(scheme, 'bg'),
          border: '1px solid transparent',
        }}

plugins/sanity-plugin-media/src/modules/folders/index.ts:621

  • selectCurrentFolderChildren recomputes each child folder’s totalCount by walking its entire subtree in a loop for every child. For large folder trees this becomes O(N×M) work per selector run and can cause noticeable UI jank when the asset list re-renders.
    plugins/sanity-plugin-media/src/components/TableRowFolder/index.tsx:28
  • The ContainerGrid hover background won’t take effect because the row sets style={{background: ...}} inline later. Inline background overrides the &:hover { background: ... } rule, so the hover styling is effectively dead code.
    @media (hover: hover) and (pointer: fine) {
      &:hover {
        background: ${theme.sanity.color.card.enabled.bg};
      }
    }

plugins/sanity-plugin-media/src/components/CardFolder/index.tsx:5

  • This introduces new styled-components styling (and a number of inline style objects) for newly added UI. In this monorepo, new plugin styling should prefer vanilla-extract (*.css.ts) to avoid runtime CSS-in-JS cost and to keep styling consistent with the repo’s direction.

This issue also appears on line 72 of the same file.

import {Box, Card, Flex, Stack, Text} from '@sanity/ui'
import {useDispatch} from 'react-redux'
import {useColorSchemeValue} from 'sanity'
import {css, styled} from 'styled-components'

…dialog

When deleting (or losing) the currently viewed folder, clear and reload
assets so the grid matches All assets. On small screens, open folders in
a dialog like tags instead of a panel that was immediately forced closed.

Copilot AI 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.

Pull request overview

Copilot reviewed 47 out of 47 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (2)

plugins/sanity-plugin-media/src/components/FormBuilderTool/index.tsx:17

  • selectionType is read via an as unknown as cast, which bypasses type-safety and makes it easy to accidentally depend on a non-existent prop. A runtime-safe 'selectionType' in props check avoids the unknown cast while keeping behavior the same when the prop is absent.
  const selectionType = (props as unknown as {selectionType?: string})?.selectionType
  const schemaJsonType = (props?.schemaType as {jsonType?: string} | undefined)?.jsonType
  const isMultiSelect = selectionType === 'multiple' || schemaJsonType === 'array'

plugins/sanity-plugin-media/src/modules/notifications/index.ts:170

  • Folder fetch failures won't produce an error notification because foldersActions.fetchError isn't included in the notificationsGenericErrorEpic ofType list. This makes folder-related connectivity/auth errors easy to miss.

@stipsan
stipsan enabled auto-merge (squash) July 30, 2026 20:23
@stipsan
stipsan disabled auto-merge August 3, 2026 11:43
@stipsan
stipsan merged commit 30fa7e2 into main Aug 3, 2026
26 checks passed
@stipsan
stipsan deleted the cursor/port-media-folder-management-c619 branch August 3, 2026 11:43
@squiggler-app squiggler-app Bot mentioned this pull request Aug 3, 2026
stipsan pushed a commit that referenced this pull request Aug 3, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @sanity/sanity-plugin-async-list@3.0.0

### Major Changes

- [#1087](#1087)
[`f4e7fcc`](f4e7fcc)
Thanks [@stipsan](https://github.com/stipsan)! - Refactor the input into
a real React component and fix the `async-list-undefined` namespace/id

- **Breaking:** `AsyncList` is now a regular React component that takes
a single `props` argument (the standard Sanity input props plus an
`options` field), instead of being called as `AsyncList(props,
options)`. For the `components.input` slot, use the new
`createAsyncListInput(options)` factory: `input:
createAsyncListInput({loader})`. This makes the input safe under the
Rules of Hooks and lets the React Compiler optimize it.
- **Breaking:** the secrets namespace and DOM `id` are no longer derived
as `async-list-${schemaType}` (which became the literal
`async-list-undefined` for component usage). The DOM `id` now uses
Sanity's stable per-field id, and the secrets namespace falls back to
`async-list` (instead of `async-list-undefined`) when no
`schemaType`/`secrets.namespace` is available. When using the component
with `secrets`, set an explicit `secrets.namespace`; a dev warning is
logged if it is missing.
- Fix: the debounced search handler is stable and is cancelled on
unmount, so it no longer drops queued calls or updates state on an
unmounted tree.
- Fix: the value-change handler no longer depends on the whole `props`
object, avoiding unnecessary `Autocomplete` re-renders.
- Fix: loader results are validated to ensure each option's `value` is a
string.

### Patch Changes

- Updated dependencies
[[`c61bb44`](c61bb44)]:
  - @sanity/studio-secrets@4.0.15
## @sanity/personalization-plugin@3.1.0

### Minor Changes

- [#1226](#1226)
[`1143bd6`](1143bd6)
Thanks [@jjburbridge](https://github.com/jjburbridge)! - Add
`fieldLevelPersonalization` export for segment-based field
personalization. Segments can be defined statically, fetched from an
external API, or stored in your Sanity dataset. `FieldPluginConfig` is
renamed to `ExperimentFieldPluginConfig` (a deprecated type alias is
kept for compatibility).

### Patch Changes

- [#1208](#1208)
[`51317b2`](51317b2)
Thanks [@stipsan](https://github.com/stipsan)! - Address review feedback
from the migration into the monorepo:

- Fix LaunchDarkly experiment pagination so `offset` advances between
pages, preventing duplicate results and a possible infinite loop
- Correct misspelled plugin names (`personalistaion` →
`personalization`) and stop the LaunchDarkly entry point from
identifying itself as the GrowthBook plugin
- Fix an operator-precedence bug in the experiment field preview that
could set the title to the entire field object
- Walk reference preview paths with optional chaining to avoid throwing
on missing intermediate fields
- Move the experiment item activation patch out of render and into an
effect
  - Remove unused `Select` props
- Fix the GrowthBook (`project` config key) and LaunchDarkly
(`fieldLevelExperiments` usage) docs and drop the stale standalone-repo
Studio version / tooling references

- Updated dependencies
[[`c61bb44`](c61bb44)]:
  - @sanity/studio-secrets@4.0.15
## sanity-plugin-cloudinary@2.1.0

### Minor Changes

- [#1233](#1233)
[`36f3fe2`](36f3fe2)
Thanks [@ChrisLaRocque](https://github.com/ChrisLaRocque)! - Add
performant preview images

Asset previews and diffs now build an optimized, scaled-down preview URL
with `@cloudinary/url-gen` (a 400px-wide transformation) when a cloud
name is configured, instead of loading the full-size original. This
keeps the Studio fast when previewing large Cloudinary assets, and falls
back to the stored asset URL when no cloud name is available.

- [#1227](#1227)
[`3b02635`](3b02635)
Thanks [@pgurley](https://github.com/pgurley),
[@atlvis](https://github.com/atlvis)! - Add `cloudinaryReferencePlugin`
for storing Cloudinary assets as reusable document references

- New `cloudinaryReferencePlugin` registers the schema types needed to
reference Cloudinary assets as documents
- New `cloudinaryAssetDocument` type stores a Cloudinary asset as a
standalone document
- New `cloudinaryAssetReference` type references those asset documents,
with a custom input for selecting and managing assets through the
Cloudinary Media Library
- `openMediaSelector` now supports a `showHandler` callback and a
`folder` option, so the select button can show a loading state and scope
the library to a folder
- Fixed the internal name of `cloudinaryAssetSourcePlugin`
(`cloudinart-asset-source` → `cloudinary-asset-source`)

### Patch Changes

- [#1236](#1236)
[`7ec89b6`](7ec89b6)
Thanks [@stipsan](https://github.com/stipsan)! - - Fix the
`cloudinaryAssetSourcePlugin` name, which was mistakenly registered as
`cloudinart-asset-source`
- Wait for the Cloudinary Media Library script to finish loading before
opening it, avoiding runtime errors when several inputs mount at once
- Fix a user-facing typo in the asset source loading message ("Media
Libary" → "Media Library")
- Remove an invalid `src`-less `<track>` element from the video preview
- Correct the README usage examples (`defineConfg` → `defineConfig`) and
drop stale standalone-repo "Develop & test" / "Release new version"
instructions
- Updated dependencies
[[`c61bb44`](c61bb44)]:
  - @sanity/studio-secrets@4.0.15
## sanity-plugin-media@6.1.0

### Minor Changes

- [#1119](#1119)
[`ab39674`](ab39674)
Thanks [@lud-hu](https://github.com/lud-hu)! - Add an "Edit Media" asset
source so media details (alt text, title, tags, etc.) can be edited
directly from an image or file field on a document, without opening the
full Media tool.

- [#1117](#1117)
[`6f4316d`](6f4316d)
Thanks [@nickeforsberg](https://github.com/nickeforsberg)! - Add an
`excludeTags` option that hides assets referencing the listed
`media.tag` slugs (`name.current` values). Excluded assets are omitted
from the Media browser grid and asset-picker queries, and the matching
tags are hidden from the tag sidebar and tag search facet. The asset
edit dialog still lists all tags so you can assign or remove them on an
open asset.

- [#1121](#1121)
[`30fa7e2`](30fa7e2)
Thanks [@bobbygeo](https://github.com/bobbygeo),
[@pedrobonamin](https://github.com/pedrobonamin)! - Add folder
management to the media browser

- Organise assets into nested folders, backed by a new `media.folder`
document type (a `name` plus a weak `parent` reference) and a single
weak `opt.media.folder` reference on each asset (mirroring how tags
work). Renaming a folder is a one-field document write regardless of how
many assets it contains.
- Browse folders in a dedicated sidebar tree, with breadcrumb
navigation, create / rename / delete flows, a bulk "Move to folder"
dialog, and per-asset folder controls in the asset details dialog. The
default "All assets" view lists every asset; opening a folder filters
the list to that folder.
- Deleting a folder removes only the folder document — its assets stay
in the library with their folder assignment cleared, and nested folders
move up one level.
- Support multi-select insert when the media plugin is used as an asset
source for array (multiple) fields.

- [#1115](#1115)
[`e7ec6e6`](e7ec6e6)
Thanks [@am0wa](https://github.com/am0wa)! - Extract `image`
(`sanity.imageExifTags`) metadata on asset upload and include it in
asset queries. The asset edit dialog now pre-fills the Description field
from the image's `ImageDescription` EXIF tag as a fallback for image
assets.

- [#1118](#1118)
[`186e29c`](186e29c)
Thanks [@Polleke007](https://github.com/Polleke007),
[@joepvandepol](https://github.com/joepvandepol)! - Add the ability to
replace a selected asset with another one and update all of its
references across documents

When a single asset is selected, a new **Replace** action opens an
overview where you can pick a replacement asset. Every document that
references the original asset (including deeply nested image fields) is
re-pointed to the chosen asset. Ported from
sanity-io/sanity-plugin-media#236.

### Patch Changes

- [#1108](#1108)
[`1dc3a7b`](1dc3a7b)
Thanks [@oxygensmith](https://github.com/oxygensmith)! - Add
`crossOrigin="anonymous"` to the image thumbnail component so thumbnails
load in Firefox. Firefox's Opaque Response Blocking would otherwise
block Sanity CDN asset responses (which send `Vary: Origin`) when
requested without an `Origin` header.
## @sanity/plugin-kit@10.0.3

### Patch Changes

- [#1698](#1698)
[`d3dedd3`](d3dedd3)
Thanks [@squiggler-app](https://github.com/apps/squiggler-app)! -
fix(deps): update dependency oxlint to ^1.76.0

- [#1779](#1779)
[`5555795`](5555795)
Thanks [@squiggler-app](https://github.com/apps/squiggler-app)! -
fix(deps): update dependency oxfmt to ^0.61.0

- [#1799](#1799)
[`93858fc`](93858fc)
Thanks [@stipsan](https://github.com/stipsan)! - Prefer function
components via `react/prefer-function-component` (with
`allowErrorBoundary`) instead of banning `Component`/`PureComponent`
imports
## @sanity/cross-dataset-duplicator@2.0.13

### Patch Changes

- [#1228](#1228)
[`71d77d5`](71d77d5)
Thanks [@rohanvachheta](https://github.com/rohanvachheta)! - Handle
reference errors during duplication by fetching missing referenced
documents (including transitive refs, respecting `filter`), re-uploading
any recovered assets, and retrying the transaction, with a one-by-one
commit fallback

- Updated dependencies
[[`c61bb44`](c61bb44)]:
  - @sanity/studio-secrets@4.0.15
## @sanity/embeddings-index-ui@4.0.13

### Patch Changes

- [#1792](#1792)
[`c61bb44`](c61bb44)
Thanks [@squiggler-app](https://github.com/apps/squiggler-app)! -
fix(deps): update dependency react-rx to ^4.2.5
## @sanity/form-toolkit@3.0.13

### Patch Changes

- [#1234](#1234)
[`1dd36c8`](1dd36c8)
Thanks [@stipsan](https://github.com/stipsan)! - Address post-migration
review feedback:

- `FormRenderer` now renders interactive (uncontrolled) inputs when no
`getFieldState` is provided, so the documented native HTML form usage
works out of the box
- Uncontrolled text and textarea fields honor `options.defaultValue`
(controlled fields keep form-library state only, so UI and submit values
stay in sync)
- `FormRenderer` falls back to `field.name` for the React key when a
field has no `_key`
- The shared HubSpot/Mailchimp request handler defaults to the
Next.js-compatible handler instead of throwing when no framework
environment variable is detected, and short-circuits CORS preflight
(`OPTIONS`) requests
- Corrected the `formSchema`, `formiumInput`, and `mailchimpInput` usage
examples (import paths and required options), README typos, and
example/dev-workflow references

- Updated dependencies
[[`f4e7fcc`](f4e7fcc)]:
  - @sanity/sanity-plugin-async-list@3.0.0
## @sanity/language-filter@5.0.14

### Patch Changes

- [#1792](#1792)
[`c61bb44`](c61bb44)
Thanks [@squiggler-app](https://github.com/apps/squiggler-app)! -
fix(deps): update dependency react-rx to ^4.2.5
## @sanity/studio-secrets@4.0.15

### Patch Changes

- [#1792](#1792)
[`c61bb44`](c61bb44)
Thanks [@squiggler-app](https://github.com/apps/squiggler-app)! -
fix(deps): update dependency react-rx to ^4.2.5
## sanity-plugin-hotspot-array@5.0.12

### Patch Changes

- [#1789](#1789)
[`9628df4`](9628df4)
Thanks [@squiggler-app](https://github.com/apps/squiggler-app)! -
fix(deps): update dependency motion to ^12.43.0
## sanity-plugin-iframe-pane@5.0.30

### Patch Changes

- [#1789](#1789)
[`9628df4`](9628df4)
Thanks [@squiggler-app](https://github.com/apps/squiggler-app)! -
fix(deps): update dependency motion to ^12.43.0
## sanity-plugin-internationalized-array@5.1.25

### Patch Changes

- [#1765](#1765)
[`97937c4`](97937c4)
Thanks [@pedrobonamin](https://github.com/pedrobonamin)! - Add a stable
`data-testid` on the document-level add-translations panel for e2e
coverage
## sanity-plugin-mux-input@5.0.8

### Patch Changes

- [#1792](#1792)
[`c61bb44`](c61bb44)
Thanks [@squiggler-app](https://github.com/apps/squiggler-app)! -
fix(deps): update dependency react-rx to ^4.2.5
## sanity-plugin-studio-smartling@5.0.14

### Patch Changes

- [#1216](#1216)
[`d4dd45b`](d4dd45b)
Thanks [@stipsan](https://github.com/stipsan)! - Harden the Smartling
adapter and fix docs:

- Send the secret credentials JSON verbatim during authentication
instead of double-encoding it, which could break auth with proxies that
forward the request body as-is
- Throw a clear error (surfacing Smartling's message) when
authentication does not return an access token, instead of a cryptic
`TypeError`
- Avoid throwing when no existing job is found or when a
translation/progress response is missing its expected payload
- Guard the progress calculation against a zero total word count so
empty documents no longer report `NaN`/`Infinity`
- Fix the `additionalDeserializers` option name in the advanced
configuration docs (was `additonalDeserializers`) and update the README
development/release instructions for the monorepo
## sanity-plugin-workflow@3.0.39

### Patch Changes

- [#1789](#1789)
[`9628df4`](9628df4)
Thanks [@squiggler-app](https://github.com/apps/squiggler-app)! -
fix(deps): update dependency motion to ^12.43.0
## @sanity/document-internationalization@6.2.28


## @sanity/sfcc@1.0.25

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> <sup>[Cursor Bugbot](https://cursor.com/bugbot) is generating a
summary for commit 9246b02. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants