datocms-plugin-project-exporter 0.9.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +42 -0
- package/README.md +364 -11
- package/build/assets/index-0m9-6ORL.css +1 -0
- package/build/assets/index-BfyEs43G.js +54 -0
- package/build/index.html +13 -1
- package/docs/preview.mp4 +0 -0
- package/index.html +12 -0
- package/package.json +25 -26
- package/src/entrypoints/ConfigScreen.tsx +99 -83
- package/src/entrypoints/LoadingOverlay.tsx +31 -0
- package/src/entrypoints/RecordDownloaderSidebar.tsx +51 -7
- package/src/entrypoints/styles.module.css +66 -30
- package/src/react-app-env.d.ts +1 -1
- package/src/utils/assetExport.test.ts +146 -0
- package/src/utils/assetExport.ts +299 -0
- package/src/utils/downloadAllAssets.ts +190 -14
- package/src/utils/downloadAllRecords.ts +72 -8
- package/src/utils/downloadRecordsFile.ts +53 -25
- package/src/utils/recordExport.test.ts +249 -0
- package/src/utils/recordExport.ts +1149 -0
- package/tsconfig.json +2 -1
- package/vite.config.ts +27 -0
- package/build/asset-manifest.json +0 -13
- package/build/static/css/main.78b0c021.css +0 -2
- package/build/static/css/main.78b0c021.css.map +0 -1
- package/build/static/js/main.c990a123.js +0 -3
- package/build/static/js/main.c990a123.js.LICENSE.txt +0 -76
- package/build/static/js/main.c990a123.js.map +0 -1
package/AGENTS.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Repository Guidelines
|
|
2
|
+
|
|
3
|
+
## Project Structure & Module Organization
|
|
4
|
+
This plugin is a React + TypeScript DatoCMS app. Keep code changes inside `src/` unless updating docs or static assets.
|
|
5
|
+
- `src/index.tsx`: plugin bootstrap and SDK wiring.
|
|
6
|
+
- `src/entrypoints/`: UI entrypoints (`ConfigScreen`, sidebar panel, loading overlay) and CSS modules.
|
|
7
|
+
- `src/utils/`: export logic for records/assets and file-format builders.
|
|
8
|
+
- `public/`: static HTML shell used by `react-scripts`.
|
|
9
|
+
- `docs/`: plugin preview media (`cover.png`, `preview.mp4`).
|
|
10
|
+
|
|
11
|
+
Generated output goes to `build/` after a production build and should not be edited manually.
|
|
12
|
+
|
|
13
|
+
## Build, Test, and Development Commands
|
|
14
|
+
- `npm install`: install dependencies.
|
|
15
|
+
- `npm start`: start local development server (`react-scripts start` with `BROWSER=none`).
|
|
16
|
+
- `npm run build`: create production bundle in `build/`.
|
|
17
|
+
- `npm test`: run Jest in watch mode through `react-scripts test`.
|
|
18
|
+
- `npm run prepublishOnly`: build check executed before publishing.
|
|
19
|
+
|
|
20
|
+
## Coding Style & Naming Conventions
|
|
21
|
+
- Use TypeScript with strict mode expectations from `tsconfig.json`.
|
|
22
|
+
- Prefer 2-space indentation, semicolons, and clear import grouping.
|
|
23
|
+
- Components and types use PascalCase (`ConfigScreen`, `AvailableFormats`).
|
|
24
|
+
- Functions, variables, and helpers use camelCase (`downloadAllRecords`, `loadingStatus`).
|
|
25
|
+
- Keep styles in CSS modules (`*.module.css`) colocated with entrypoint components.
|
|
26
|
+
- ESLint is configured via `react-app`; address lint warnings before opening a PR.
|
|
27
|
+
|
|
28
|
+
## Testing Guidelines
|
|
29
|
+
- Test stack is Jest via `react-scripts` (React Testing Library compatible).
|
|
30
|
+
- Add tests alongside source files as `*.test.ts` or `*.test.tsx` under `src/`.
|
|
31
|
+
- Focus coverage on export filtering, format conversion behavior, and utility edge cases.
|
|
32
|
+
- For one-shot runs, use `npm test -- --watchAll=false`.
|
|
33
|
+
|
|
34
|
+
## Commit & Pull Request Guidelines
|
|
35
|
+
- Follow short, imperative commit subjects. Prefixes like `fix:`, `refactor:`, and `chore:` are consistent with existing history.
|
|
36
|
+
- Keep each commit focused (example: `fix: handle empty model selection in export flow`).
|
|
37
|
+
- PRs should include what changed and why, commands/tests executed, linked issue/task (if available), and a screenshot or short video for UI changes in config/sidebar screens.
|
|
38
|
+
|
|
39
|
+
## Security & Configuration Tips
|
|
40
|
+
- Do not commit tokens, exports, or project-specific secrets.
|
|
41
|
+
- Access DatoCMS credentials only through SDK context (`ctx.currentUserAccessToken`).
|
|
42
|
+
- For very large exports, mention browser limits and prefer official DatoCMS export tooling when needed.
|
package/README.md
CHANGED
|
@@ -1,17 +1,370 @@
|
|
|
1
|
-
|
|
1
|
+
# DatoCMS Project Exporter Plugin
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
* JSON
|
|
5
|
-
* CSV
|
|
6
|
-
* XML
|
|
7
|
-
* XLSX
|
|
3
|
+
A powerful DatoCMS plugin that allows you to export your project's records and assets directly from the dashboard. Whether you need a complete backup, a specific set of data for analysis, or just a single record, Project Exporter handles it with support for multiple popular formats.
|
|
8
4
|
|
|
9
|
-

|
|
10
6
|
|
|
11
|
-
|
|
7
|
+
## Features
|
|
12
8
|
|
|
13
|
-
|
|
9
|
+
- **Multiple Export Formats**: Export your data in JSON, CSV, XML, or XLSX.
|
|
10
|
+
- **Bulk Record Export**: Download all records in your project.
|
|
11
|
+
- **Filtered Exports**:
|
|
12
|
+
- **By Model**: Select specific models to export records from.
|
|
13
|
+
- **By Text Search**: Export records matching a specific search query.
|
|
14
|
+
- **Import-Friendly JSON Envelope**: JSON exports now include `manifest`, schema ID/API-key maps, and a `referenceIndex` for records/uploads/blocks/structured-text links.
|
|
15
|
+
- **Chunked Asset Export**: Assets are split into conservative multi-ZIP chunks to reduce browser memory pressure.
|
|
16
|
+
- **Asset Mapping Manifests**: Every ZIP includes `manifest.json` and deterministic filename conventions for easier re-import.
|
|
17
|
+
- **Single Record Export**: JSON single-record exports use the same envelope shape as bulk JSON exports.
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
## Installation
|
|
16
20
|
|
|
17
|
-
|
|
21
|
+
1. Go to your DatoCMS project dashboard.
|
|
22
|
+
2. Navigate to **Settings** > **Plugins**.
|
|
23
|
+
3. Click the **Plus** icon to add a new plugin.
|
|
24
|
+
4. Search for **Project Exporter** or install it manually using the package name `datocms-plugin-project-exporter`.
|
|
25
|
+
|
|
26
|
+
## Configuration
|
|
27
|
+
|
|
28
|
+
Once installed, you can configure the default export format in the plugin settings:
|
|
29
|
+
|
|
30
|
+
1. Navigate to **Settings** > **Plugins**.
|
|
31
|
+
2. Click on **Project Exporter**.
|
|
32
|
+
3. In the configuration area (or via the plugin's main page), you can select your preferred default format:
|
|
33
|
+
- `JSON`
|
|
34
|
+
- `CSV`
|
|
35
|
+
- `XML`
|
|
36
|
+
- `XLSX`
|
|
37
|
+
|
|
38
|
+
*Note: You can also change the format on-the-fly when performing an export.*
|
|
39
|
+
|
|
40
|
+
## Usage
|
|
41
|
+
|
|
42
|
+
### Exporting Records (Bulk)
|
|
43
|
+
|
|
44
|
+
To perform bulk exports, navigate to the plugin's configuration screen (typically found under **Settings** > **Plugins** > **Project Exporter** > **Config Screen** or the dedicated plugin page if applicable).
|
|
45
|
+
|
|
46
|
+
1. **Select Format**: Choose between JSON, CSV, XML, or XLSX from the dropdown menu.
|
|
47
|
+
2. **Filter by Model**: Use the dropdown to select one or multiple models. Click "Download records from selected models" to export only those records.
|
|
48
|
+
3. **Filter by Text**: Enter a search term in the text field. Click "Download records from text query" to export matches.
|
|
49
|
+
4. **Export All**: Click "Download all records" to export everything.
|
|
50
|
+
|
|
51
|
+
### Exporting Assets
|
|
52
|
+
|
|
53
|
+
1. On the main plugin screen, click the **Download all assets** button.
|
|
54
|
+
2. The plugin scans assets and creates one or more ZIP files using conservative limits.
|
|
55
|
+
3. Every ZIP includes:
|
|
56
|
+
- Asset binaries
|
|
57
|
+
- `manifest.json` with source upload IDs and metadata
|
|
58
|
+
4. ZIP entry filenames follow:
|
|
59
|
+
- `u_<sourceUploadId>__<sanitizedOriginalFilename>`
|
|
60
|
+
|
|
61
|
+
### Exporting a Single Record
|
|
62
|
+
|
|
63
|
+
When editing a specific record:
|
|
64
|
+
|
|
65
|
+
1. Look for the **Record Downloader** panel in the right sidebar.
|
|
66
|
+
2. Click **Download this record**.
|
|
67
|
+
3. The record will be downloaded in the format currently selected in the plugin's global configuration.
|
|
68
|
+
|
|
69
|
+
## Development
|
|
70
|
+
|
|
71
|
+
This plugin is built with React and the DatoCMS Plugin SDK. To contribute or modify the plugin locally:
|
|
72
|
+
|
|
73
|
+
1. Clone the repository:
|
|
74
|
+
```bash
|
|
75
|
+
git clone https://github.com/marcelofinamorvieira/datocms-plugin-project-exporter.git
|
|
76
|
+
```
|
|
77
|
+
2. Install dependencies:
|
|
78
|
+
```bash
|
|
79
|
+
npm install
|
|
80
|
+
# or
|
|
81
|
+
pnpm install
|
|
82
|
+
```
|
|
83
|
+
3. Start the development server:
|
|
84
|
+
```bash
|
|
85
|
+
npm start
|
|
86
|
+
```
|
|
87
|
+
4. Follow the [DatoCMS Plugin SDK documentation](https://www.datocms.com/docs/plugins/sdk) to link your local server to a DatoCMS project for testing.
|
|
88
|
+
|
|
89
|
+
## Tech Stack
|
|
90
|
+
|
|
91
|
+
- **Framework**: React, TypeScript
|
|
92
|
+
- **DatoCMS**: `datocms-plugin-sdk`, `datocms-react-ui`
|
|
93
|
+
- **Utilities**:
|
|
94
|
+
- `json-2-csv` (CSV generation)
|
|
95
|
+
- `jsontoxml` (XML generation)
|
|
96
|
+
- `exceljs` (Excel generation)
|
|
97
|
+
- `jszip` (Asset zipping)
|
|
98
|
+
|
|
99
|
+
## Export Contracts (Import-Oriented)
|
|
100
|
+
|
|
101
|
+
This section documents the concrete output contract of this plugin so you can build an importer with predictable behavior.
|
|
102
|
+
|
|
103
|
+
### Record Export File Names
|
|
104
|
+
|
|
105
|
+
All record exports download with this filename pattern:
|
|
106
|
+
|
|
107
|
+
```txt
|
|
108
|
+
allDatocmsRecords<ISO_TIMESTAMP>.<extension>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Examples:
|
|
112
|
+
|
|
113
|
+
- `allDatocmsRecords2026-02-10T18:12:33.271Z.json`
|
|
114
|
+
- `allDatocmsRecords2026-02-10T18:12:33.271Z.csv`
|
|
115
|
+
|
|
116
|
+
Notes:
|
|
117
|
+
|
|
118
|
+
- `JSON` exports contain the full envelope described below (`manifest`, `schema`, `referenceIndex`, etc.).
|
|
119
|
+
- `CSV`, `XML`, and `XLSX` exports contain only the exported record data (no manifest/schema/reference index).
|
|
120
|
+
|
|
121
|
+
### Asset ZIP File Names and Entry Names
|
|
122
|
+
|
|
123
|
+
Assets are split into one or more ZIP files using this naming template:
|
|
124
|
+
|
|
125
|
+
```txt
|
|
126
|
+
allAssets.part-<PPP>-of-<TTT>.<timestamp>.zip
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
- `PPP` and `TTT` are zero-padded to 3 digits (`001`, `012`, etc.).
|
|
130
|
+
- `timestamp` is generated from `new Date().toISOString().replace(/:/g, '-')`.
|
|
131
|
+
- Example: `allAssets.part-003-of-012.2026-02-09T12-00-00.000Z.zip`.
|
|
132
|
+
|
|
133
|
+
Each binary asset inside a ZIP uses:
|
|
134
|
+
|
|
135
|
+
```txt
|
|
136
|
+
u_<sourceUploadId>__<sanitizedOriginalFilename>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Sanitization rules:
|
|
140
|
+
|
|
141
|
+
- `sourceUploadId`:
|
|
142
|
+
- trim
|
|
143
|
+
- replace spaces with `_`
|
|
144
|
+
- replace characters not matching `[A-Za-z0-9_-]` with `-`
|
|
145
|
+
- collapse repeated `-`
|
|
146
|
+
- fallback to `unknown` if empty
|
|
147
|
+
- `originalFilename`:
|
|
148
|
+
- trim
|
|
149
|
+
- replace spaces with `_`
|
|
150
|
+
- replace characters not matching `[A-Za-z0-9._-]` with `-`
|
|
151
|
+
- collapse repeated `-`
|
|
152
|
+
- remove leading dots
|
|
153
|
+
- fallback to `file` if empty
|
|
154
|
+
|
|
155
|
+
Example:
|
|
156
|
+
|
|
157
|
+
- Source: `upload:123` + `Hero Image (Final).png`
|
|
158
|
+
- ZIP entry: `u_upload-123__Hero_Image_-Final-.png`
|
|
159
|
+
|
|
160
|
+
### `manifest.json` Inside Each Asset ZIP
|
|
161
|
+
|
|
162
|
+
Every ZIP contains a `manifest.json` at the root with this structure:
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
type AssetZipManifest = {
|
|
166
|
+
manifestVersion: "2.0.0";
|
|
167
|
+
generatedAt: string; // ISO timestamp
|
|
168
|
+
chunk: {
|
|
169
|
+
index: number; // 1-based chunk index
|
|
170
|
+
totalChunks: number;
|
|
171
|
+
filename: string; // actual ZIP filename for this chunk
|
|
172
|
+
assetCount: number;
|
|
173
|
+
estimatedBytes: number; // conservative estimate used for chunking
|
|
174
|
+
};
|
|
175
|
+
conventions: {
|
|
176
|
+
zipEntryName: "u_<sourceUploadId>__<sanitizedOriginalFilename>";
|
|
177
|
+
zipFilename: "allAssets.part-{part}-of-{total}.{timestamp}.zip";
|
|
178
|
+
};
|
|
179
|
+
limits: {
|
|
180
|
+
maxZipBytes: 157286400; // 150 * 1024 * 1024
|
|
181
|
+
maxFilesPerZip: 100;
|
|
182
|
+
sizeSafetyFactor: 1.2;
|
|
183
|
+
};
|
|
184
|
+
assets: AssetManifestEntry[];
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
type AssetManifestEntry = {
|
|
188
|
+
sourceUploadId: string;
|
|
189
|
+
zipEntryName: string;
|
|
190
|
+
originalFilename: string;
|
|
191
|
+
size: number | null;
|
|
192
|
+
mimeType: string | null;
|
|
193
|
+
width: number | null;
|
|
194
|
+
height: number | null;
|
|
195
|
+
checksum: string | null; // upload md5
|
|
196
|
+
url: string | null;
|
|
197
|
+
path: string | null;
|
|
198
|
+
metadata: {
|
|
199
|
+
// only included if present on the source upload:
|
|
200
|
+
default_field_metadata?: unknown;
|
|
201
|
+
field_metadata?: unknown;
|
|
202
|
+
custom_data?: unknown;
|
|
203
|
+
tags?: unknown;
|
|
204
|
+
notes?: unknown;
|
|
205
|
+
author?: unknown;
|
|
206
|
+
copyright?: unknown;
|
|
207
|
+
focal_point?: unknown;
|
|
208
|
+
is_image?: unknown;
|
|
209
|
+
blurhash?: unknown;
|
|
210
|
+
};
|
|
211
|
+
};
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### JSON Record Envelope (`.json` record exports)
|
|
215
|
+
|
|
216
|
+
`JSON` record exports (bulk and single-record) use this envelope:
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
type RecordExportEnvelope = {
|
|
220
|
+
manifest: {
|
|
221
|
+
exportVersion: "2.0.0";
|
|
222
|
+
pluginVersion: string;
|
|
223
|
+
exportedAt: string; // ISO timestamp
|
|
224
|
+
sourceProjectId: string | null;
|
|
225
|
+
sourceEnvironment: string | null;
|
|
226
|
+
defaultLocale: string | null;
|
|
227
|
+
locales: string[];
|
|
228
|
+
scope: "bulk" | "single-record";
|
|
229
|
+
filtersUsed: {
|
|
230
|
+
modelIDs?: string[];
|
|
231
|
+
textQuery?: string;
|
|
232
|
+
};
|
|
233
|
+
};
|
|
234
|
+
schema: {
|
|
235
|
+
itemTypes: Record<string, unknown>[]; // raw itemTypes from CMA
|
|
236
|
+
fields: Record<string, unknown>[]; // raw fields from CMA
|
|
237
|
+
itemTypeIdToApiKey: Record<string, string>; // model id -> api_key
|
|
238
|
+
fieldIdToApiKey: Record<string, string>; // field id -> api_key
|
|
239
|
+
fieldsByItemType: Record<
|
|
240
|
+
string,
|
|
241
|
+
{
|
|
242
|
+
fieldId: string;
|
|
243
|
+
apiKey: string;
|
|
244
|
+
fieldType: string;
|
|
245
|
+
localized: boolean;
|
|
246
|
+
}[]
|
|
247
|
+
>;
|
|
248
|
+
};
|
|
249
|
+
records: Record<string, unknown>[]; // raw records from CMA iterator
|
|
250
|
+
referenceIndex: {
|
|
251
|
+
recordRefs: RecordReference[];
|
|
252
|
+
uploadRefs: UploadReference[];
|
|
253
|
+
structuredTextRefs: StructuredTextReference[];
|
|
254
|
+
blockRefs: BlockReference[];
|
|
255
|
+
};
|
|
256
|
+
assetPackageInfo: {
|
|
257
|
+
packageVersion: "2.0.0";
|
|
258
|
+
zipNamingConvention: "allAssets.part-{part}-of-{total}.{timestamp}.zip";
|
|
259
|
+
zipEntryNamingConvention:
|
|
260
|
+
"u_<sourceUploadId>__<sanitizedOriginalFilename>";
|
|
261
|
+
manifestFilename: "manifest.json";
|
|
262
|
+
chunkingDefaults: {
|
|
263
|
+
maxZipBytes: 157286400;
|
|
264
|
+
maxFilesPerZip: 100;
|
|
265
|
+
sizeSafetyFactor: 1.2;
|
|
266
|
+
};
|
|
267
|
+
lastAssetExportSnapshot: LastAssetExportSnapshot | null;
|
|
268
|
+
};
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
type LastAssetExportSnapshot = {
|
|
272
|
+
packageVersion: string;
|
|
273
|
+
generatedAt: string;
|
|
274
|
+
chunkFilenames: string[];
|
|
275
|
+
totalChunks: number;
|
|
276
|
+
totalAssets: number;
|
|
277
|
+
maxZipBytes: number;
|
|
278
|
+
maxFilesPerZip: number;
|
|
279
|
+
sizeSafetyFactor: number;
|
|
280
|
+
};
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Where references are:
|
|
284
|
+
|
|
285
|
+
```ts
|
|
286
|
+
type BaseRef = {
|
|
287
|
+
recordSourceId: string;
|
|
288
|
+
sourceBlockId: string | null;
|
|
289
|
+
fieldApiKey: string;
|
|
290
|
+
locale: string | null;
|
|
291
|
+
jsonPath: string;
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
type RecordReference = BaseRef & {
|
|
295
|
+
targetSourceId: string;
|
|
296
|
+
kind: string;
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
type UploadReference = BaseRef & {
|
|
300
|
+
targetSourceId: string;
|
|
301
|
+
kind: string;
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
type StructuredTextReference = BaseRef & {
|
|
305
|
+
targetSourceId: string;
|
|
306
|
+
targetType: "record" | "block";
|
|
307
|
+
kind: "link" | "block";
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
type BlockReference = BaseRef & {
|
|
311
|
+
blockSourceId: string;
|
|
312
|
+
blockModelId: string | null;
|
|
313
|
+
parentBlockSourceId: string | null;
|
|
314
|
+
kind: string;
|
|
315
|
+
synthetic: boolean;
|
|
316
|
+
};
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### `manifest` Behavior Details
|
|
320
|
+
|
|
321
|
+
- `manifest.exportVersion` is currently fixed at `2.0.0`.
|
|
322
|
+
- `manifest.pluginVersion` comes from:
|
|
323
|
+
1. `REACT_APP_PLUGIN_VERSION`, else
|
|
324
|
+
2. `npm_package_version`, else
|
|
325
|
+
3. fallback `"1.0.0"`.
|
|
326
|
+
- `manifest.scope`:
|
|
327
|
+
- `bulk` for config-screen bulk exports
|
|
328
|
+
- `single-record` for sidebar single-record export
|
|
329
|
+
- `manifest.filtersUsed`:
|
|
330
|
+
- bulk export can include `modelIDs` and/or `textQuery`
|
|
331
|
+
- single-record JSON export uses `{}`.
|
|
332
|
+
- Site fields (`sourceProjectId`, `sourceEnvironment`, `defaultLocale`, `locales`) are fetched from `GET /site`; on fetch failure they fall back to `null` / `[]`.
|
|
333
|
+
|
|
334
|
+
### Reference Index Semantics
|
|
335
|
+
|
|
336
|
+
- `jsonPath` always points to the location in `records` where the relationship was found.
|
|
337
|
+
- Path root starts at `$.records[index]`.
|
|
338
|
+
- Localized fields include locale in both:
|
|
339
|
+
- `jsonPath` (for example `$.records[0].content.en.document...`)
|
|
340
|
+
- `locale` property (`"en"`, `"pt"`, etc.).
|
|
341
|
+
- `sourceBlockId` is `null` for top-level record fields and set for relationships found inside blocks.
|
|
342
|
+
- Deduplication is applied; each unique `(context + target + kind)` is emitted once.
|
|
343
|
+
|
|
344
|
+
`kind` values currently emitted by this version:
|
|
345
|
+
|
|
346
|
+
- `recordRefs.kind`: `link`, `links`, `structured_text_itemLink`, `structured_text_inlineItem`, `structured_text_links_array`, `unknown_item`
|
|
347
|
+
- `uploadRefs.kind`: `file`, `gallery`, `unknown_upload`
|
|
348
|
+
- `blockRefs.kind`: `modular_content`, `single_block`, `nested_block`, `structured_text_block`, `structured_text_blocks_array`
|
|
349
|
+
|
|
350
|
+
When a block-like object has no `id`, the exporter creates a synthetic block ID:
|
|
351
|
+
|
|
352
|
+
```txt
|
|
353
|
+
synthetic::<recordSourceId>::<jsonPath>
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
This appears in `blockRefs.blockSourceId` with `synthetic: true`.
|
|
357
|
+
|
|
358
|
+
### Import Guidance (Recommended Order)
|
|
359
|
+
|
|
360
|
+
If you are writing an importer, this order is reliable for the current contract:
|
|
361
|
+
|
|
362
|
+
1. Read `schema` maps (`itemTypeIdToApiKey`, `fieldIdToApiKey`, `fieldsByItemType`).
|
|
363
|
+
2. Import assets from ZIPs and build `sourceUploadId -> targetUploadId` mapping from each ZIP `manifest.json`.
|
|
364
|
+
3. Create records first (without resolving all links yet), preserving a `sourceRecordId -> targetRecordId` map.
|
|
365
|
+
4. Reconcile links/uploads/blocks using `referenceIndex`.
|
|
366
|
+
5. Apply structured text links and block references in a final pass using `structuredTextRefs` and `blockRefs`.
|
|
367
|
+
|
|
368
|
+
## License
|
|
369
|
+
|
|
370
|
+
This project is licensed under the MIT License.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
._buttonItem_1yz8o_1{margin-top:var(--spacing-l)}._hidden_1yz8o_4{display:none}._buttonList_1yz8o_7{display:flex;flex-direction:column}._filteredExportOptions_1yz8o_12{width:100%}._tooltipBox_1yz8o_16{position:relative;display:inline-block;margin-top:10px;font-size:14px;color:#666;z-index:10}._modelSelectorContainer_1yz8o_25{display:flex;flex-direction:column;align-items:center;margin-top:var(--spacing-l);width:100%;gap:var(--spacing-l);text-align:center}._textQueryContainer_1yz8o_35{display:flex;flex-direction:column;align-items:center;width:100%;gap:var(--spacing-m);margin-bottom:var(--spacing-l);margin-top:var(--spacing-l);text-align:center}._modelSelector_1yz8o_25{display:block;text-align:center;font-size:var(--font-size-l);width:100%}._overlay_1yz8o_53{position:absolute;top:0;left:0;width:100%;height:100%;background-color:#fffffff2;display:flex;justify-content:center;align-items:center;z-index:100}._overlayContent_1yz8o_66{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px;background-color:#fff;border-radius:8px;box-shadow:0 4px 12px #0000001a;min-width:350px}._spinnerContainer_1yz8o_78{margin-bottom:30px;display:flex;justify-content:center;align-items:center;height:60px}._overlayText_1yz8o_86{margin-top:10px;margin-bottom:10px;font-size:16px;color:#333;font-weight:500;text-align:center;max-width:80%}._progressBarContainer_1yz8o_96{width:300px;height:8px;background-color:#e0e0e0;border-radius:4px;margin-top:20px;overflow:hidden}._progressBarFill_1yz8o_105{height:100%;background-color:var(--primary-color, #00b3b3);transition:width .3s ease}._progressText_1yz8o_111{margin-top:12px;font-size:14px;color:#666;font-weight:500}@font-face{font-display:auto;font-family:colfax-web;font-style:normal;font-weight:700;src:url(https://use.typekit.net/af/522c51/00000000000000003b9acde6/27/l?primer=f592e0a4b9356877842506ce344308576437e4f677d7c9b78ca2162e6cad991a&fvd=n5&v=3) format("woff2"),url(https://use.typekit.net/af/522c51/00000000000000003b9acde6/27/d?primer=f592e0a4b9356877842506ce344308576437e4f677d7c9b78ca2162e6cad991a&fvd=n5&v=3) format("woff"),url(https://use.typekit.net/af/522c51/00000000000000003b9acde6/27/a?primer=f592e0a4b9356877842506ce344308576437e4f677d7c9b78ca2162e6cad991a&fvd=n5&v=3) format("opentype")}@font-face{font-display:auto;font-family:colfax-web;font-style:italic;font-weight:700;src:url(https://use.typekit.net/af/4e71b3/00000000000000003b9acde7/27/l?primer=f592e0a4b9356877842506ce344308576437e4f677d7c9b78ca2162e6cad991a&fvd=i5&v=3) format("woff2"),url(https://use.typekit.net/af/4e71b3/00000000000000003b9acde7/27/d?primer=f592e0a4b9356877842506ce344308576437e4f677d7c9b78ca2162e6cad991a&fvd=i5&v=3) format("woff"),url(https://use.typekit.net/af/4e71b3/00000000000000003b9acde7/27/a?primer=f592e0a4b9356877842506ce344308576437e4f677d7c9b78ca2162e6cad991a&fvd=i5&v=3) format("opentype")}@font-face{font-display:auto;font-family:colfax-web;font-style:normal;font-weight:500;src:url(https://use.typekit.net/af/522c51/00000000000000003b9acde6/27/l?primer=f592e0a4b9356877842506ce344308576437e4f677d7c9b78ca2162e6cad991a&fvd=n5&v=3) format("woff2"),url(https://use.typekit.net/af/522c51/00000000000000003b9acde6/27/d?primer=f592e0a4b9356877842506ce344308576437e4f677d7c9b78ca2162e6cad991a&fvd=n5&v=3) format("woff"),url(https://use.typekit.net/af/522c51/00000000000000003b9acde6/27/a?primer=f592e0a4b9356877842506ce344308576437e4f677d7c9b78ca2162e6cad991a&fvd=n5&v=3) format("opentype")}@font-face{font-display:auto;font-family:colfax-web;font-style:italic;font-weight:500;src:url(https://use.typekit.net/af/4e71b3/00000000000000003b9acde7/27/l?primer=f592e0a4b9356877842506ce344308576437e4f677d7c9b78ca2162e6cad991a&fvd=i5&v=3) format("woff2"),url(https://use.typekit.net/af/4e71b3/00000000000000003b9acde7/27/d?primer=f592e0a4b9356877842506ce344308576437e4f677d7c9b78ca2162e6cad991a&fvd=i5&v=3) format("woff"),url(https://use.typekit.net/af/4e71b3/00000000000000003b9acde7/27/a?primer=f592e0a4b9356877842506ce344308576437e4f677d7c9b78ca2162e6cad991a&fvd=i5&v=3) format("opentype")}@font-face{font-display:auto;font-family:colfax-web;font-style:normal;font-weight:400;src:url(https://use.typekit.net/af/bac079/00000000000000003b9acde4/27/l?primer=f592e0a4b9356877842506ce344308576437e4f677d7c9b78ca2162e6cad991a&fvd=n4&v=3) format("woff2"),url(https://use.typekit.net/af/bac079/00000000000000003b9acde4/27/d?primer=f592e0a4b9356877842506ce344308576437e4f677d7c9b78ca2162e6cad991a&fvd=n4&v=3) format("woff"),url(https://use.typekit.net/af/bac079/00000000000000003b9acde4/27/a?primer=f592e0a4b9356877842506ce344308576437e4f677d7c9b78ca2162e6cad991a&fvd=n4&v=3) format("opentype")}@font-face{font-display:auto;font-family:colfax-web;font-style:italic;font-weight:400;src:url(https://use.typekit.net/af/c1cc04/00000000000000003b9acde5/27/l?primer=f592e0a4b9356877842506ce344308576437e4f677d7c9b78ca2162e6cad991a&fvd=i4&v=3) format("woff2"),url(https://use.typekit.net/af/c1cc04/00000000000000003b9acde5/27/d?primer=f592e0a4b9356877842506ce344308576437e4f677d7c9b78ca2162e6cad991a&fvd=i4&v=3) format("woff"),url(https://use.typekit.net/af/c1cc04/00000000000000003b9acde5/27/a?primer=f592e0a4b9356877842506ce344308576437e4f677d7c9b78ca2162e6cad991a&fvd=i4&v=3) format("opentype")}html{font-size:16px;height:auto}body,html{margin:0;padding:0}._button_474wk_1{-webkit-appearance:none;-moz-appearance:none;background-color:transparent;border:0;border-radius:4px;box-sizing:border-box;color:var(--base-body-color);cursor:pointer;display:inline-block;font-family:inherit;font-weight:var(--font-weight-bold);line-height:inherit;opacity:1;text-decoration:none;transition:all .3s var(--material-ease);vertical-align:middle;white-space:nowrap}._button_474wk_1:focus,._button_474wk_1:hover{opacity:.8}._button_474wk_1:active{opacity:.7}._disabled_474wk_30{cursor:not-allowed}._buttonType-muted_474wk_34{background-color:var(--light-color);color:var(--accent-color)}._buttonType-muted_474wk_34._disabled_474wk_30{background-color:var(--light-bg-color);color:#0003}._buttonType-muted_474wk_34._disabled_474wk_30:active,._buttonType-muted_474wk_34._disabled_474wk_30:focus,._buttonType-muted_474wk_34._disabled_474wk_30:hover{color:#0003}._buttonType-primary_474wk_50{background-color:var(--accent-color);color:#fff}._buttonType-primary_474wk_50:active,._buttonType-primary_474wk_50:focus,._buttonType-primary_474wk_50:hover{color:#fff}._buttonType-primary_474wk_50._disabled_474wk_30{background-color:var(--disabled-bg-color);color:#0003}._buttonType-primary_474wk_50._disabled_474wk_30:active,._buttonType-primary_474wk_50._disabled_474wk_30:focus,._buttonType-primary_474wk_50._disabled_474wk_30:hover{color:#0003}._buttonType-negative_474wk_71,._buttonType-negative_474wk_71:active,._buttonType-negative_474wk_71:focus,._buttonType-negative_474wk_71:hover{background-color:var(--alert-color);color:#fff}._buttonType-negative_474wk_71._disabled_474wk_30{background-color:var(--disabled-bg-color);color:#0003}._buttonSize-xxs_474wk_88{font-size:1em;padding:.5em .8em}._buttonSize-xs_474wk_93{font-size:1em;padding:.6em .8em}._buttonSize-s_474wk_98{font-size:1em;padding:.7em 1em}._buttonSize-m_474wk_103{font-size:1.1em;padding:.7em 1em}._buttonSize-l_474wk_108{font-size:1.2em;padding:.7em 1em}._buttonSize-xl_474wk_113{font-size:1.2em;padding:1em}._fullWidth_474wk_118{display:block;text-align:center;width:100%}._button__leftIcon_474wk_124,._button__rightIcon_474wk_125{display:inline-block;line-height:.6;vertical-align:middle}._button__leftIcon_474wk_124 svg,._button__rightIcon_474wk_125 svg{fill:var(--accent-color)}._button__leftIcon_474wk_124{margin-right:.5em}._button__leftIcon_474wk_124:last-child{margin-right:0}._button__rightIcon_474wk_125{margin-left:.5em}._button__rightIcon_474wk_125:first-child{margin-left:0}._Button_1h1w1_1{justify-column:center;align-items:center;-webkit-appearance:none;-moz-appearance:none;background-color:#fff;border:0;border-right:1px solid var(--border-color);border:1px solid var(--border-color);border-left-width:0;box-sizing:border-box;color:var(--base-body-color);color:rgba(var(--base-body-color-rgb-components,.6));cursor:pointer;display:flex;font-family:inherit;font-size:inherit;line-height:inherit;padding:7px 13px}._Button_1h1w1_1:hover{background-color:var(--light-bg-color)}._Button_1h1w1_1 svg{fill:var(--light-body-color)}._Button--s_1h1w1_32{padding:3px 10px}._Button--disabled_1h1w1_36{color:var(--light-body-color);cursor:not-allowed}._Button--disabled_1h1w1_36:hover{background:#fff}._Button--selected_1h1w1_45{background-color:var(--accent-color);border-color:var(--accent-color);color:#fff}._Button--selected_1h1w1_45 svg{fill:#fff}._Button--selected_1h1w1_45:hover{background-color:var(--accent-color)}._Button--selected_1h1w1_45._Button--disabled_1h1w1_36,._Button--selected_1h1w1_45:hover{background-color:rgba(var(--accent-color-rgb-components),.8);border-color:rgba(var(--accent-color-rgb-components),.8)}._Button_1h1w1_1:first-child{border-left-width:1px;border-radius:4px 0 0 4px}._Button_1h1w1_1:last-child{border-radius:0 4px 4px 0}._Group_10mj4_1{align-items:stretch;background-color:#fff;display:flex;overflow:hidden}._themeVariables_2dr1w_1{--base-body-color-rgb-components:52,54,58;--base-body-color:rgb(var(--base-body-color-rgb-components));--light-body-color-rgb-components:132,132,132;--light-body-color:rgb(var(--light-body-color-rgb-components));--placeholder-body-color-rgb-components:198,198,198;--placeholder-body-color:rgb(var(--placeholder-body-color-rgb-components));--light-bg-color-rgb-components:245,245,245;--light-bg-color:rgb(var(--light-bg-color-rgb-components));--lighter-bg-color-rgb-components:248,248,248;--lighter-bg-color:rgb(var(--lighter-bg-color-rgb-components));--disabled-bg-color-rgb-components:237,237,237;--disabled-bg-color:rgb(var(--disabled-bg-color-rgb-components));--border-color-rgb-components:240,240,240;--border-color:rgb(var(--border-color-rgb-components));--darker-border-color-rgb-components:215,215,215;--darker-border-color:rgb(var(--darker-border-color-rgb-components));--alert-color-rgb-components:255,94,73;--alert-color:rgb(var(--alert-color-rgb-components));--warning-color-rgb-components:255,215,0;--warning-color:rgb(var(--warning-color-rgb-components));--notice-color-rgb-components:70,215,0;--notice-color:rgb(var(--notice-color-rgb-components));--warning-bg-color-rgb-components:255,255,229;--warning-bg-color:rgb(var(--warning-bg-color-rgb-components));--add-color-rgb-components:76,176,109;--add-color:rgb(var(--add-color-rgb-components));--remove-color-rgb-components:235,87,106;--remove-color:rgb(var(--remove-color-rgb-components));--base-font-family:"colfax-web","Roboto","Helvetica Neue",Helvetica,Roboto,Arial,sans-serif;--monospaced-font-family:"Roboto Mono","Menlo","Bitstream Vera Sans Mono",Consolas,Courier,monospace;--font-weight-bold:500;--spacing-s:.375rem;--spacing-m:.75rem;--spacing-l:1.5rem;--spacing-xl:2.25rem;--spacing-xxl:3.75rem;--spacing-xxxl:6rem;--negative-spacing-s:-.375rem;--negative-spacing-m:-.75rem;--negative-spacing-l:-1.5rem;--negative-spacing-xl:-2.25rem;--negative-spacing-xxl:-3.75rem;--negative-spacing-xxxl:-6rem;--font-size-xxs:.6875rem;--font-size-xs:.75rem;--font-size-s:.875rem;--font-size-m:.9375rem;--font-size-l:1.0625rem;--font-size-xl:1.1875rem;--font-size-xxl:1.5625rem;--font-size-xxxl:1.875rem;--material-ease:cubic-bezier(.55,0,.1,1);--inertial-ease:cubic-bezier(.19,1,.22,1)}._canvas_2dr1w_70{-webkit-text-size-adjust:100%;text-rendering:optimizeLegibility;color:var(--base-body-color);font-family:var(--base-font-family);font-size:var(--font-size-m);line-height:1.5}._inspector_u6041_1{margin:var(--spacing-l) 0}._panel_u6041_5{border-bottom:1px solid var(--border-color)}._panelHandle_u6041_9{all:inherit;background:var(--light-bg-color);border:0;box-sizing:border-box;cursor:pointer;display:block;font-weight:var(--font-weight-bold);padding:5px 10px;width:100%}._panelHandle_u6041_9:hover{background:var(--lighter-bg-color)}._panelBody_u6041_25{border-left:1px solid var(--border-color);border-right:1px solid var(--border-color);padding:20px}._groupDescription_u6041_31{font-size:var(--font-size-s);line-height:1.2;margin-bottom:20px}._propertyGroup_u6041_37{border:1px solid var(--border-color);border-radius:5px}._propertyOrMethod_u6041_42{border-bottom:1px solid var(--border-color);line-height:1.2}._propertyOrMethod_u6041_42 p{margin:0}._propertyOrMethodBody_u6041_51{padding:15px}._propertyOrMethodExample_u6041_55{position:relative}._propertyOrMethodExample_u6041_55 pre{background:var(--light-bg-color);font-size:.8em;margin:0;max-height:240px;overflow:auto;padding:15px}._propertyOrMethodName_u6041_68{color:var(--light-body-color);display:block;font-family:var(--monospaced-font-family);font-size:.9em;font-weight:700;margin-bottom:5px;text-decoration:none}._propertyOrMethodName_u6041_68:hover{text-decoration:underline}._propertyOrMethodExampleActions_u6041_82{background:#fff;display:flex;padding:15px}._propertyOrMethodExampleActions_u6041_82>*{margin-right:10px}._fieldError_qi0xk_1{color:var(--alert-color);font-size:var(--font-size-xs);line-height:1.2;margin-top:var(--spacing-s)}._FieldGroup_uz9ju_1{display:block}._FieldGroup__item_uz9ju_5{display:block;margin-bottom:var(--spacing-l)}._FieldGroup__item_uz9ju_5:last-child{margin-bottom:0}._fieldHint_1avon_1{color:var(--light-body-color);font-size:var(--font-size-xs);line-height:1.2;margin-top:var(--spacing-s)}._fieldHint_1avon_1 a{color:inherit}._fieldHint_1avon_1 a:hover{text-decoration:none}._Form_5qspp_1,._Form__item_5qspp_5{display:block}._Form__item_5qspp_5:last-child{margin-bottom:0}._Form__item--default_5qspp_13{margin-bottom:var(--spacing-l)}._Form__item--condensed_5qspp_17{margin-bottom:var(--spacing-m)}._formLabel_tcjrv_1{align-items:center;color:var(--light-body-color);display:flex;margin-bottom:var(--spacing-s)}._formLabel_tcjrv_1:hover ._formLabel__code_tcjrv_8{opacity:1}._formLabel--error_tcjrv_14{color:var(--alert-color)}._formLabel__label_tcjrv_18{flex:1}._formLabel__code_tcjrv_8{font-family:var(--monospaced-font-family);font-size:.95em;opacity:0;position:absolute;transition:opacity .2s var(--material-ease)}._hotKey_1eko8_1{align-items:center;display:inline-flex;gap:15px}._label_1eko8_7{align-items:center;display:flex}._keys_1eko8_12{align-items:center;display:inline-flex;gap:4px}._hotKeyKey_1eko8_18{background:var(--light-color);border-radius:3px;padding:5px 8px}._Section_zh95u_1{position:relative}._Section--highlighted_zh95u_5:before{animation:_pageContentSectionHighligh_zh95u_1 4s ease-in-out .25s forwards;border-radius:4px;box-shadow:0 0 0 4px var(--accent-color);content:"";inset:-20px -30px;pointer-events:none;position:absolute;z-index:10}._Section__header_zh95u_19{margin-bottom:var(--spacing-l);margin-left:var(--negative-spacing-l);margin-right:var(--negative-spacing-l);position:relative}._Section__header_zh95u_19:before{background-color:var(--border-color);content:"";display:block;height:1px;left:0;position:absolute;right:0;top:50%;z-index:1}._Section__title_zh95u_38{align-items:center;background-color:#fff;display:inline-flex;font-size:var(--font-size-l);font-weight:var(--font-weight-bold);margin-left:var(--spacing-m);margin-right:var(--spacing-l);padding-left:var(--spacing-m);padding-right:var(--spacing-m);position:relative;z-index:2}._Section__arrow_zh95u_55{all:initial;align-self:stretch;cursor:pointer;margin-right:.3em;width:15px}._Section__arrow_zh95u_55:before{border-bottom:6px solid transparent;border-left:6px solid var(--base-body-color);border-top:6px solid transparent;content:"";height:0;left:14px;margin-top:-6px;position:absolute;top:50%;transform-origin:50% 50%;transition:transform .2s ease-out;width:0}._Section__arrow_zh95u_55:hover:before{opacity:.7}._Section__arrow--is-open_zh95u_82:before{transform:rotate(90deg)}@keyframes _pageContentSectionHighligh_zh95u_1{0%{box-shadow:0 0 0 4px var(--accent-color),0 0 0 4px rgba(var(--accent-color-rgb-components),.7)}15%{box-shadow:0 0 0 4px var(--accent-color),0 0 0 80px transparent}75%{box-shadow:0 0 0 4px var(--accent-color),0 0 0 80px transparent}to{box-shadow:0 0 0 4px transparent,0 0 0 80px transparent}}._SidebarPanel_4uwco_1{border-bottom:1px solid var(--border-color)}._SidebarPanel__header_4uwco_5{align-items:center;-webkit-appearance:none;-moz-appearance:none;background-color:#fff;background-color:var(--light-bg-color);border:0;box-sizing:border-box;color:var(--base-body-color);cursor:pointer;display:flex;font-family:inherit;font-size:inherit;line-height:inherit;padding:0;text-align:left;-webkit-user-select:none;user-select:none;width:100%}._SidebarPanel__header_4uwco_5:focus,._SidebarPanel__header_4uwco_5:hover{background-color:var(--lighter-bg-color)}._SidebarPanel__header__title_4uwco_30{flex:1;font-weight:500;padding:0 20px}._SidebarPanel__header__chevron_4uwco_36{align-items:center;display:flex;padding:13px 15px}._SidebarPanel__content_4uwco_42{background-color:#fff;padding:20px}._SidebarPanel__content--no-padding_4uwco_47{padding:0}._Spinner--inline_oumod_1{display:inline-block;position:relative;vertical-align:middle}._Spinner--centered_oumod_7{left:50%;position:absolute;top:50%}._Spinner__bar_oumod_13{animation:_Spinner__spin_oumod_1 1.2s linear infinite;background-color:var(--light-body-color);height:14%;left:-20%;position:absolute;top:0;width:40%}@keyframes _Spinner__spin_oumod_1{0%{opacity:1}to{opacity:.15}}._switchField__flex_16z4j_1{align-items:center;display:flex}._switchField__switchInput_16z4j_6{width:55px}._switchField__label_16z4j_10{color:var(--base-body-color);flex:1;line-height:1.1;line-height:20px;margin-bottom:0;pointer-events:none;-moz-user-select:text;-ms-user-select:text;-webkit-user-select:text;user-select:text}._switchField__below_16z4j_22{margin-left:55px;margin-top:var(--spacing-s)}._switchInput__inner_1knbg_1{color:#fff;font-size:12px;left:24px;position:absolute}._switchInput_1knbg_1{background-color:#ccc;border:1px solid #ccc;border-radius:20px;box-sizing:border-box;cursor:pointer;display:inline-block;height:22px;line-height:20px;position:relative;transition:all .3s cubic-bezier(.35,0,.25,1);vertical-align:middle;width:44px}._switchInput_1knbg_1:after{animation-duration:.3s;animation-name:_switchInput__off_1knbg_1;animation-timing-function:cubic-bezier(.35,0,.25,1);background-color:#fff;border-radius:50%;box-shadow:0 2px 5px #00000042;content:" ";cursor:pointer;height:18px;left:2px;position:absolute;top:1px;transform:scale(1);transition:left .3s cubic-bezier(.35,0,.25,1);width:18px}._switchInput_1knbg_1:focus:after,._switchInput_1knbg_1:hover{animation-name:_switchInput__on_1knbg_1;transform:scale(1.1)}._switchInput__checked_1knbg_47{background-color:var(--accent-color);border:1px solid var(--accent-color)}._switchInput__checked_1knbg_47 ._switchInput__inner_1knbg_1{left:6px}._switchInput__checked_1knbg_47:after{left:22px}._switchInput__disabled_1knbg_60{background:#ccc;border-color:#ccc;cursor:no-drop}._switchInput__disabled_1knbg_60:after{animation-name:_none_1knbg_1;background:#9e9e9e;cursor:no-drop}._switchInput__disabled_1knbg_60:focus:after,._switchInput__disabled_1knbg_60:hover{animation-name:_none_1knbg_1;transform:scale(1)}@keyframes _switchInput__on_1knbg_1{0%{transform:scale(1)}50%{transform:scale(1.25)}to{transform:scale(1.1)}}@keyframes _switchInput__off_1knbg_1{0%{transform:scale(1.1)}to{transform:scale(1)}}._TextInput_x2oj2_1{appearance:none;background-image:none;border:1px solid var(--border-color);border-radius:0;box-sizing:border-box;display:block;font-family:inherit;font-size:var(--font-size-m);padding:10px;resize:none;transition:border .2s var(--material-ease);width:100%}._TextInput_x2oj2_1::placeholder{color:var(--placeholder-body-color)}._TextInput_x2oj2_1:hover{border-color:var(--darker-border-color)}._TextInput_x2oj2_1:focus{border-color:var(--accent-color);box-shadow:0 0 0 3px var(--semi-transparent-accent-color);outline:0}._TextInput--monospaced_x2oj2_30{font-family:var(--monospaced-font-family);font-size:var(--font-size-s)}._TextInput--disabled_x2oj2_35{background:var(--lighter-bg-color);border-color:var(--border-color);color:var(--light-body-color)}._TextInput--error_x2oj2_41,._TextInput--error_x2oj2_41:focus,._TextInput--error_x2oj2_41:hover{border-color:var(--alert-color)}._TextInput--error_x2oj2_41:focus{box-shadow:0 0 0 3px rgba(var(--alert-color-rgb-components),.2)}._TextareaInput_1wnu9_1{appearance:none;background-image:none;border:1px solid var(--border-color);border-radius:0;box-sizing:border-box;display:block;font-family:inherit;font-size:var(--font-size-m);padding:10px;resize:none;transition:border .2s var(--material-ease);width:100%}._TextareaInput_1wnu9_1::placeholder{color:var(--placeholder-body-color)}._TextareaInput_1wnu9_1:hover{border-color:var(--darker-border-color)}._TextareaInput_1wnu9_1:focus{border-color:var(--accent-color);box-shadow:0 0 0 3px var(--semi-transparent-accent-color);outline:0}._TextareaInput--monospaced_1wnu9_30{font-family:var(--monospaced-font-family);font-size:var(--font-size-s)}._TextareaInput--disabled_1wnu9_35{background:var(--lighter-bg-color);border-color:var(--border-color);color:var(--light-body-color)}._TextareaInput--error_1wnu9_41,._TextareaInput--error_1wnu9_41:focus,._TextareaInput--error_1wnu9_41:hover{border-color:var(--alert-color)}._TextareaInput--error_1wnu9_41:focus{box-shadow:0 0 0 3px rgba(var(--alert-color-rgb-components),.2)}._Button_fy6g6_1{align-items:center;-webkit-appearance:none;-moz-appearance:none;background-color:transparent;border:0;border-left:1px solid var(--border-color);border-right:1px solid var(--border-color);box-sizing:border-box;color:var(--base-body-color);cursor:pointer;display:flex;font-family:inherit;justify-content:center;line-height:inherit;min-height:49px;padding:0;width:49px}._Button_fy6g6_1:focus,._Button_fy6g6_1:hover{background-color:var(--light-bg-color)}._Button_fy6g6_1:first-child{border-left:0}._Button_fy6g6_1:last-child{border-right:0}@media screen and (min-width:380px){._Button_fy6g6_1{min-height:59px;width:59px}._Button_fy6g6_1 svg{font-size:20px}}._Stack_1nnzo_1{align-items:center;display:flex;flex:1;flex-direction:row;justify-content:center;padding:10px 15px}._Stack--s_1nnzo_10{padding-bottom:var(--spacing-s);padding-top:var(--spacing-s)}._Stack--l_1nnzo_15{padding-left:var(--spacing-xl);padding-right:var(--spacing-xl)}._Title_1dx5n_1{font-size:var(--font-size-l);font-weight:500;line-height:1.1;margin-right:15px}@media screen and (min-width:380px){._Title_1dx5n_1{font-size:var(--font-size-xl)}}._Toolbar_1cwb8_1{align-items:stretch;border-bottom:1px solid var(--border-color);border-top:1px solid var(--border-color);display:flex;position:relative}._Toolbar_1cwb8_1:first-child{border-top-width:0}._Toolbar_1cwb8_1:last-child{border-bottom-width:0}._tooltip_3z5rn_1{word-wrap:break-word;background:#fff;border-radius:4px;box-shadow:0 1px 9px #0003;-webkit-hyphens:auto;hyphens:auto;max-width:400px;overflow-wrap:break-word;padding:10px 15px}._Dropdown_nie0g_1{position:relative}._Dropdown__spacer_nie0g_5{inset:0;pointer-events:none;position:absolute}._Dropdown__menu__search_nie0g_11{border-bottom:1px solid var(--border-color);padding:7px}._Dropdown__menu__search__input_nie0g_16{appearance:none;background-image:none;border:1px solid var(--border-color);border-radius:3px;box-sizing:border-box;display:block;font-family:inherit;font-size:.9em;padding:8px;resize:none;transition:border .2s var(--material-ease);width:100%}._Dropdown__menu__search__input_nie0g_16::placeholder{color:var(--placeholder-body-color)}._Dropdown__menu__search__input_nie0g_16:hover{border-color:var(--darker-border-color)}._Dropdown__menu__search__input_nie0g_16:focus{border-color:var(--accent-color);box-shadow:0 0 0 3px var(--semi-transparent-accent-color);outline:0}._Dropdown__menu-container_nie0g_45{position:fixed;visibility:hidden}._Dropdown__menu_nie0g_11{background-color:#fff;border-radius:4px;box-shadow:0 3px 10px #0003;margin-bottom:var(--spacing-xl);margin-top:10px;min-width:200px;padding:1px 0;text-align:initial}._Dropdown__menu__inner_nie0g_61{margin:7px 0}._Dropdown__menu__group__title_nie0g_65{background-color:var(--light-bg-color);color:var(--light-body-color);font-size:var(--font-size-xs);padding:5px 15px 3px;text-transform:uppercase}._Dropdown__menu__group__content_nie0g_73{margin:8px 0}._Dropdown__menu__text_nie0g_77{color:var(--light-body-color);display:block;line-height:1.2;padding:4px 15px;position:relative;text-align:left}._Dropdown__menu__option_nie0g_86{align-items:center;color:var(--base-body-color);display:flex;padding:4px 15px;position:relative;text-align:left;text-decoration:none;white-space:nowrap}._Dropdown__menu__option_nie0g_86:focus,._Dropdown__menu__option_nie0g_86:hover{background-color:var(--light-bg-color)}._Dropdown__menu__option_nie0g_86>a{color:inherit;display:block;text-decoration:none}._Dropdown__menu__option--is-selected_nie0g_108{background-color:var(--light-bg-color)}._Dropdown__menu__option--is-disabled_nie0g_112{opacity:.5}._Dropdown__menu__option--is-disabled_nie0g_112 ._Dropdown__menu__option__content_nie0g_115{cursor:not-allowed}._Dropdown__menu__option--is-dangerous_nie0g_120{color:var(--alert-color)}._Dropdown__menu__option--is-dangerous_nie0g_120 svg{fill:var(--alert-color)}._Dropdown__menu__option--is-dangerous_nie0g_120:focus,._Dropdown__menu__option--is-dangerous_nie0g_120:hover{background-color:var(--alert-color);color:#fff}._Dropdown__menu__option--is-dangerous_nie0g_120:focus svg,._Dropdown__menu__option--is-dangerous_nie0g_120:hover svg{fill:#fff}._Dropdown__menu__option--is-active_nie0g_138{font-weight:500}._Dropdown__menu__option--is-active_nie0g_138:focus,._Dropdown__menu__option--is-active_nie0g_138:hover{background-color:none}._Dropdown__menu__option--is-invalid_nie0g_151,._Dropdown__menu__option--is-valid_nie0g_147{padding-left:35px}._Dropdown__menu__option--is-invalid_nie0g_151:before{background-color:var(--alert-color);border-radius:4px;content:"";font-size:12px;height:8px;left:15px;position:absolute;top:50%;transform:translateY(-50%);width:8px}._Dropdown__menu__option__content_nie0g_115{-webkit-appearance:none;-moz-appearance:none;background-color:transparent;border:0;box-sizing:border-box;color:inherit;cursor:pointer;flex:1;font-family:inherit;font-size:inherit;font-weight:inherit;line-height:inherit;padding:0;text-align:left}._Dropdown__menu__option__content_nie0g_115>svg{fill:var(--light-body-color);color:var(--light-body-color);display:inline-block;font-size:13px;padding-right:8px;vertical-align:middle}._Dropdown__menu__option__icons_nie0g_194{align-items:center;display:flex;padding-left:15px}._Dropdown__menu__option__icon_nie0g_194{-webkit-appearance:none;-moz-appearance:none;background-color:transparent;border:0;box-sizing:border-box;color:var(--base-body-color);color:var(--light-body-color);cursor:pointer;display:inline-block;font-family:inherit;font-size:inherit;font-size:13px;line-height:inherit;line-height:10px;opacity:0;padding:3px;position:relative;top:-1px;transition:transform .1s ease-in-out;width:100%;width:auto}._Dropdown__menu__option_nie0g_86:focus ._Dropdown__menu__option__icon_nie0g_194,._Dropdown__menu__option_nie0g_86:hover ._Dropdown__menu__option__icon_nie0g_194{opacity:1}._Dropdown__menu__option__icon_nie0g_194:focus,._Dropdown__menu__option__icon_nie0g_194:hover{transform:scale(1.2)}._Dropdown__menu__option__icon_nie0g_194 svg{fill:var(--light-body-color)}._Dropdown__menu__option__icon--delete_nie0g_241{color:var(--alert-color)}._Dropdown__menu__option__icon--delete_nie0g_241 svg{fill:var(--alert-color)}._Dropdown__menu__separator_nie0g_248{background-color:var(--border-color);height:1px;margin:8px 0}._Dropdown__menu_nie0g_11{overflow-y:auto}._SplitViewPane_1cl1f_1{height:100%;overflow-y:auto;position:absolute;width:100%}._SplitViewSash_tds51_1{align-items:center;background-color:rgba(var(--light-color-components),0);display:flex;height:100%;justify-content:center;position:absolute;top:0;transition:background-color .2s .15s;width:100%;z-index:2}._SplitViewSash--dragging_tds51_15,._SplitViewSash_tds51_1:hover{background-color:var(--light-color)}._SplitViewSash--dragging_tds51_15:has(._SplitViewSash__content_tds51_19:hover),._SplitViewSash_tds51_1:hover:has(._SplitViewSash__content_tds51_19:hover){background-color:transparent}._SplitViewSash--no-resize_tds51_24{pointer-events:none}._SplitViewSash--vertical_tds51_28{cursor:col-resize}._SplitViewSash--horizontal_tds51_32{cursor:row-resize}._SplitViewSash__content_tds51_19{cursor:pointer;left:50%;padding:15px 0;pointer-events:auto;position:absolute;top:50%;transform:translate(-50%,-50%)}._SplitViewSash__content__button_tds51_46{align-items:center;background:#fff;border:1px solid var(--border-color);border-radius:6px;color:var(--light-body-color);display:flex;font-size:10px;height:20px;justify-content:center;width:20px;z-index:2}._SplitViewSash__content__button_tds51_46 svg{fill:currentColor;display:block}._SplitViewSash__content_tds51_19:hover ._SplitViewSash__content__button_tds51_46{background:var(--light-bg-color);color:var(--base-body-color)}._SplitView_1oi17_1{flex:1;height:100%;position:relative;width:100%}._SplitView--dragging_1oi17_8._SplitView--vertical_1oi17_8{cursor:col-resize}._SplitView--dragging_1oi17_8._SplitView--horizontal_1oi17_12{cursor:row-resize}._SplitView--disable-select_1oi17_16{-webkit-user-select:none;user-select:none}._SplitView--disable-select_1oi17_16 ._SplitViewPane_1oi17_20{pointer-events:none}._VerticalSplitPane__expand_80tii_1{background:#fff;cursor:pointer;inset:0;position:absolute;transition:all .3s cubic-bezier(.55,0,.1,1)}._VerticalSplitPane__expand_80tii_1:hover{animation:_VerticalSplitPane__expand_80tii_1 .6s cubic-bezier(.55,0,.1,1);background:var(--light-bg-color)}._VerticalSplitPane__expand_80tii_1._VerticalSplitPane__expand_80tii_1{border-right:1px solid var(--border-color);transform-origin:left}._VerticalSplitPane__expand_80tii_1._VerticalSplitPane__expand--right_80tii_25{border-left:1px solid var(--border-color);transform-origin:right}@keyframes _VerticalSplitPane__expand_80tii_1{0%{transform:scaleX(1)}50%{transform:scaleX(2)}to{transform:scaleX(1)}}._VerticalSplitPaneOverlay_80tii_42{background:linear-gradient(180deg,#30302f80,#30302f4d);height:100%;inset:0;overflow:hidden;position:absolute;z-index:12}._VerticalSplitPaneOverlay__primary_80tii_58{inset:0;position:absolute;z-index:1}._VerticalSplitPaneOverlay__primary--left_80tii_67{margin-right:20px}._VerticalSplitPaneOverlay__primary--right_80tii_71{margin-left:20px}._VerticalSplitPaneOverlay__secondary_80tii_75{background:#fff;bottom:0;box-shadow:0 0 15px #0006;position:absolute;top:0}._VerticalSplitPaneOverlay__secondary--left_80tii_83{left:0}._VerticalSplitPaneOverlay__secondary--right_80tii_87{right:0}._VerticalSplitPaneOverlay__sash_80tii_91{height:100%;position:absolute;top:0}._VerticalSplitPaneOverlay__secondary--left_80tii_83 ._VerticalSplitPaneOverlay__sash_80tii_91{right:0}._VerticalSplitPaneOverlay__secondary--right_80tii_87 ._VerticalSplitPaneOverlay__sash_80tii_91{left:0}
|