# DatoCMS Schema Import/Export Plugin

Powerful, safe schema migration for DatoCMS. Export models/blocks and plugins as JSON, then import them into another project with guided conflict resolution.

## What it does

- Builds dependency-aware exports: collects selected models, blocks, fieldsets, fields, and any referenced plugins while trimming validators that point to out-of-scope item types.
- Keeps exports portable: rewrites field appearances to rely only on bundled or built-in editors and downloads a prettified `export.json` when each task completes.
- Imports additively: compares the bundle against the target project, walks you through reuse/rename/skip decisions, and creates new entities without mutating existing ones unless you opt in.
- Restores editors safely: reinstalls plugin editors/addons when present, falling back to core editors so fields always remain valid in the destination project.
- Handles long tasks gracefully: surfaces cancellable overlays with stall notices, honors rate-limit throttling, and stops at the next safe checkpoint if you cancel mid-flight.
- Loads shared recipes: accepts `recipe_url` query parameters to pull an export from a URL so collaborators can hand off ready-to-import snapshots.

## Where To Find It

- Configuration > Export: start a new export, select multiple models/blocks, or export the entire current environment.
- Configuration > Import: upload an export file (or paste a recipe URL) and import safely into the current environment.
- From a model/block: in Schema, open a model/block, click the three dots beside the model/block name, and pick “Export as JSON…”—the plugin opens the Export page preloaded with that entity so you can jump straight to the graph.

## Installation

- In DatoCMS, open your project, go to Plugins, search for “Schema Import/Export”, then install.

## Export

- Start from a model/block
  - Open Schema, select a model/block.
  - Click the three dots beside the model/block name and choose “Export as JSON…”.
  - The Export page opens with that entity locked in the selection; inspect the graph/list, run “Select all dependencies” to pull in linked models/blocks/plugins, and undo it with “Unselect dependencies” if you change your mind.
  - Start the export when ready; the long-task overlay shows progress/cancel options, and the prettified `export.json` downloads automatically once the task completes.

- Start a new export (Schema > Export)
  - The landing panel lets you either pick specific starting models/blocks or go straight to “Export entire schema”.
  - Use the multi-select to seed the graph; the graph animates selections for small/medium schemas, while large schemas (>60 nodes) fall back to the list view with search, metrics (counts, components, cycles), and “Why included?” explanations.
  - “Select all dependencies” adds related models/blocks/plugins in bulk and logs a notice showing how many were added; “Unselect dependencies” removes the auto-added ones.
  - Plugin dependencies come from installed plugin lookups; if the CMA call fails you’ll see a warning so you know selections may be incomplete.

- Export the entire schema (one click)
  - Confirm the dialog to queue up every model, block, and plugin in the current environment.
  - The overlay reports progress, handles cancellable requests, and falls back gracefully if the CMA throttles; the final file downloads as `export.json`.

- After export
  - You get a success notice (or cancellation/error messaging) plus the downloaded file; the selection stays in place so you can tweak it and run another export without leaving the page.

## Import

- Start an import (Schema > Import)
  - Drag and drop an exported JSON file or use the “Select a JSON export file…” button; invalid JSON triggers an alert so you can retry.
  - To hydrate directly from a shared recipe, append `?recipe_url=https://…` (optional `recipe_title=…`)—the plugin fetches it and switches to import mode automatically.

- Resolve conflicts safely
  - The plugin builds a conflict summary in the background with progress feedback; you can refresh it if the schema changes while you wait.
  - For models/blocks: choose “Reuse existing” or “Rename” with inline validation for name/API key (preset suggestions are provided for fast renames).
  - For plugins: choose “Reuse existing” or “Skip”.
  - Use “Show only unresolved conflicts” to focus the list; entities marked “reuse” drop out of the graph/list so you stay focused on what will be created.
  - The import graph mirrors the export graph for smaller selections and switches to the list view with metrics/search once the node count crosses the same 60-node threshold.

- Run the import
  - Imports are additive: new models/blocks/fields/fieldsets/plugins are created with fresh IDs, and existing assets are touched only when you explicitly reuse them.
  - Field validators and appearances are remapped to the target project; missing plugin editors fall back to safe defaults and localized defaults expand to every locale in the target environment.
  - The progress overlay includes a cancel affordance with the required warning dialog; if you cancel, the task stops at the next safe checkpoint.

- After import
  - Successful runs raise a notice and clear the loaded export; cancellations leave the file in place so you can try again, and failures keep the conflict form available for fixes.

## Notes & Limits

- Plugin detection: editor/addon plugins used by fields are included when “Select all dependencies” is used. If the installed plugin list cannot be fetched you’ll see a one-time banner (per session) so you know detection may be incomplete.
- Graph threshold: when the graph would exceed ~60 nodes the UI switches to the large-selection layout with search, metrics (counts/components/cycles), and “Why included?” reasoning instead of rendering an unreadable canvas.
- Rate limiting & throttling: long operations show a stall notice if progress pauses, and `ProjectSchema` throttles CMA calls by default (override with something like `localStorage.setItem('schemaThrottleMax', '8')`; valid values are 1–15 for local debugging).
- Appearance portability: if an editor plugin is not selected, that field falls back to a valid built‑in editor; addons are included only if selected or already installed.
- Debug logging: run `localStorage.setItem('schemaDebug', '1')` in the iframe console to enable detailed `debugLog` output.

## Development Notes

- Entry points:
  - `src/main.tsx` registers plugin pages, schema dropdown shortcuts, and preserves environment-prefixed routing when navigating between Import/Export.
  - `src/entrypoints/Config` uses `ctx.navigateTo` so config links jump directly to Schema, Import, or Export without reloading the iframe.
- Shared hooks:
  - `useProjectSchema` memoizes the CMA client, caches item types/plugins/fields, and honors the `schemaThrottleMax` localStorage override.
  - `useLongTask` tracks cancellable progress state shared by exports, imports, and conflict analysis.
  - `useExportSelection` hydrates item types once and keeps the selection stable when the import page toggles between modes.
  - `useExportGraph` assembles the React Flow graph/list data and streams progress updates for the preparation overlay.
  - `useExportAllHandler` and `useSchemaExportTask` wrap `buildExportDoc`, download handling, progress overlays, and cancellation.
  - `useConflictsBuilder` drives conflict analysis with `useLongTask`; `useRecipeLoader` watches `recipe_url` query params for shared exports.
- Shared UI:
  - `TaskOverlayStack` + `TaskProgressOverlay` render cancellable overlays with `ProgressOverlay` stall detection.
  - `GraphCanvas` and the Schema Overview components keep the export/import visualizations consistent, with large graph warnings gating heavy renders.
- Schema utilities:
  - `ProjectSchema` provides cached lookups plus concurrency-limited `getItemTypeFieldsAndFieldsets` calls.
  - `buildExportDoc` trims validators/appearances so exports stay self-contained; `buildImportDoc` + `importSchema` orchestrate plugin installs, item type creation, field migrations, and reorder passes.
- Local development:
  - `npm run dev` starts Vite, `npm run build` runs `tsc -b` followed by `vite build`, `npm run analyze` builds with bundle analysis, and `npm run format` runs Biome in `--write` mode.

## Export File Format

- Version 2 (current): `{ version: '2', rootItemTypeId, entities: […] }` — preserves the explicit root model/block used to seed the export, to re-generate the export graph deterministically.
- Version 1 (legacy): `{ version: '1', entities: […] }` — still supported for import; the root is inferred from references.
- Field validators referencing models outside the selection are trimmed, and appearances are rewritten to include only allowed plugin editors/addons so the export remains self-contained.

## Safety

- Imports are additive and non‑destructive. The plugin never overwrites existing models/blocks or plugins. When conflicts are detected, you explicitly pick “Reuse existing” or “Rename”.

## Troubleshooting

- “Why did the graph disappear?” Large selections now show a warning instead of auto-rendering; click “Render it anyway” to view the full graph.
- “Fields lost their editor?” If you don’t include a custom editor plugin in the export/import, the plugin selects a safe, built‑in editor so the field remains valid in the target project.
- “Plugin dependencies were skipped?” Check for the banner warning about incomplete plugin detection and rerun “Select all dependencies” after reopening the page once the CMA call succeeds.
- “Cancel didn’t stop immediately?” The import/export pipeline stops at the next safe checkpoint; keep the overlay open until it confirms cancellation.
