Skip to content

feat(cross-dataset-duplicator): add migrationFilters config option#1229

Open
stipsan wants to merge 2 commits into
mainfrom
cursor/port-cdd-migration-filters-2800
Open

feat(cross-dataset-duplicator): add migrationFilters config option#1229
stipsan wants to merge 2 commits into
mainfrom
cursor/port-cdd-migration-filters-2800

Conversation

@stipsan

@stipsan stipsan commented Jun 18, 2026

Copy link
Copy Markdown
Member

Ports sanity-io/cross-dataset-duplicator#53 by @Nathan-Heller into the monorepo.

What

Adds a new optional migrationFilters plugin config option to @sanity/cross-dataset-duplicator. It restricts which Datasets (and Projects) are allowed as Migration destinations for a given source Dataset, preventing accidental duplication to the wrong Dataset (e.g. by mistakenly selecting the wrong target).

crossDatasetDuplicator({
  migrationFilters: [
    {
      sourceDataset: 'production',
      targets: [{dataset: 'staging'}], // optionally {projectId, dataset}
    },
  ],
})
  • If no filter is configured for a source Dataset, all Workspaces remain valid targets (existing default behaviour — fully backwards compatible).
  • When a target omits projectId, only Workspaces in the same Project as the source are allowed.
  • When a target specifies projectId, that Project must match (enables cross-project allow-listing).

Walkthrough

Demo (filter allows only the test dataset): the To Destination dropdown offers the allowed Cross Dataset Duplicator Target and the Duplicate button updates accordingly.

cross_dataset_duplicator_migration_filters_demo.mp4

The three screenshots below were captured with a small temporary debug panel (not committed) that printed each Workspace's computed disabled state, so the native <select> disabled states could be verified reliably end-to-end (config → context → component):

No filter → test target enabled:
No migrationFilters: test target enabled

Filter excludes test (targets: [{dataset: 'staging'}]) → test target disabled:
Filter excludes test: test target disabled

Filter allows test (targets: [{dataset: 'test'}]) → test target enabled again:
Filter allows test: test target enabled

Changes

  • src/types/index.ts — new exported @public types MigrationTarget and MigrationFilter; added migrationFilters? to PluginConfig.
  • src/helpers/constants.ts — added migrationFilters: [] to DEFAULT_CONFIG.
  • src/helpers/migrationFilters.ts — new pure isAllowedMigrationTarget() helper holding the decision logic (extracted so it is unit-testable).
  • src/components/Duplicator.tsx — disables disallowed destinations, derives the source as currentWorkspace, and only labels the actual current Workspace as (Current).
  • README.md — documents the option and removes the now-implemented "allowed migrations" future-idea bullet.
  • src/helpers/migrationFilters.test.ts — unit tests covering all branches.

Note on the port

The monorepo's Duplicator.tsx had already diverged from upstream, so the change was adapted rather than applied verbatim. The upstream PR's same-project fallback (|| workspace.projectId === sourceProjectId) was applied only when a target omits projectId, matching the PR's own inline comment and second commit message ("when filter is configured and projectId is omitted, limit targets to those in the same project"). The behaviour is otherwise identical.

Testing

  • pnpm format
  • pnpm lint
  • pnpm build
  • pnpm test run (895 tests; 10 new migration-filter unit tests)
  • pnpm knip (only pre-existing @sanity/vision catalog warning / @types/nodemon hint)
  • ✅ Manual GUI verification in the test studio (see Walkthrough above)

Environment note: @repo/generators build failed on a fresh VM because unrun (an optional peer dep of tsdown) was missing. Installed locally to unblock the full build/test; not committed. The demo used a placeholder bearer token to pass the secret gate, which is why a small unrelated "DATA ERROR" indicator appears in the recording.

Crediting

  • Commit authored as @Nathan-Heller (git commit --author).
  • Changeset includes author: @Nathan-Heller so the release changelog credits the original author.

To show artifacts inline, enable in settings.

Open in Web Open in Cursor 

Port of sanity-io/cross-dataset-duplicator#53 by @Nathan-Heller.

Adds a `migrationFilters` plugin config option to restrict which Datasets
and Projects are allowed as Migration destinations for a given source
Dataset. When a target omits `projectId`, only Workspaces in the same
Project as the source are allowed. This helps prevent accidental
duplication to the wrong Dataset.
@vercel

vercel Bot commented Jun 18, 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, Comment Jun 19, 2026 1:39pm

Request Review

@changeset-bot

changeset-bot Bot commented Jun 18, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 48bbfdd

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

This PR includes changesets to release 1 package
Name Type
@sanity/cross-dataset-duplicator 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

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

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

Adds a new migrationFilters configuration option to @sanity/cross-dataset-duplicator to allow-list valid migration destinations per source dataset (optionally across projects), and wires this into the destination UI with unit-tested decision logic.

Changes:

  • Introduces new public types (MigrationTarget, MigrationFilter) and adds migrationFilters? to plugin config.
  • Implements isAllowedMigrationTarget() helper (with unit tests) and uses it to disable disallowed workspace destinations in the duplicator UI.
  • Documents the new option in the README and adds a changeset for a minor release.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
plugins/@sanity/cross-dataset-duplicator/src/types/index.ts Adds public types for migration filtering and exposes migrationFilters on PluginConfig.
plugins/@sanity/cross-dataset-duplicator/src/helpers/constants.ts Extends default config with migrationFilters: [].
plugins/@sanity/cross-dataset-duplicator/src/helpers/migrationFilters.ts Adds the allow/deny decision helper for migration targets.
plugins/@sanity/cross-dataset-duplicator/src/helpers/migrationFilters.test.ts Adds unit tests covering migration filter behaviors and edge cases.
plugins/@sanity/cross-dataset-duplicator/src/components/Duplicator.tsx Applies migration filtering to workspace options and adjusts “current workspace” labeling/source selection.
plugins/@sanity/cross-dataset-duplicator/README.md Documents migrationFilters and updates future ideas list.
.changeset/cross-dataset-duplicator-migration-filters.md Declares a minor version bump and credits the original author.

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

Comment on lines +457 to 460
<Select readOnly value={currentWorkspace?.name}>
{workspacesOptions
.filter((space) => space.disabled)
.map((space) => (
Comment on lines 454 to +457
<Flex gap={3}>
<Stack style={{flex: 1}} gap={3}>
<Label>Duplicate from</Label>
<Select readOnly value={workspacesOptions.find((space) => space.disabled)?.name}>
<Select readOnly value={currentWorkspace?.name}>
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.

4 participants