feat: add JSON export wizard with background export and progress tracking#2892
feat: add JSON export wizard with background export and progress tracking#2892Divyansh2992 wants to merge 7 commits intoappwrite:mainfrom
Conversation
Console (appwrite/console)Project ID: Sites (1)
Tip Sites support three domain rule types: Active deployment, Git branch, and Redirect |
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (3)
WalkthroughThis PR introduces a JSON export feature: a new client-side jsonExportStore that performs batched, paginated exports; a JsonExportBox Svelte component that displays per-job progress and notifications; a new export-json page implementing a column-selection and filter-aware export wizard with pretty-print option; the table page’s export control was converted to a popover offering CSV or JSON export; analytics enums were extended with JSON export events; package.json gained a pinned packageManager entry; .gitignore received a newline/whitespace adjustment. Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR adds JSON export functionality to the database table rows view, implementing a wizard-based UI with column selection, pretty-print options, and filter support. The implementation follows the existing CSV export pattern with background processing and progress tracking. Key Changes:
Issues Found:
The core implementation is solid and mirrors the CSV export flow well. The main concerns are project configuration issues (pnpm vs Bun) and the committed test output file. Confidence Score: 3/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant TablePage as Table Page
participant Wizard as Export Wizard
participant Store as jsonExportStore
participant API as Appwrite API
participant UI as JsonExportBox
User->>TablePage: Click Export dropdown
TablePage->>User: Show CSV/JSON options
User->>Wizard: Select "Export as JSON"
Wizard->>User: Show column selection & options
User->>Wizard: Select columns, filters, pretty-print
User->>Wizard: Click Export
Wizard->>Store: startExport(config)
Store->>Store: Create job with 'pending' status
Store->>UI: Update progress UI
Store->>Store: runExport() in background
Store->>API: listRows(limit: 100, offset: 0)
API-->>Store: First batch + total count
Store->>UI: Update progress (fetched/total)
loop While rows remaining
Store->>API: listRows(limit: 100, offset: N)
API-->>Store: Next batch
Store->>UI: Update progress
end
Store->>Store: Filter to selected columns
Store->>Store: Generate JSON (pretty or minified)
Store->>User: Trigger file download
Store->>UI: Mark job as 'completed'
UI->>User: Show success notification
Last reviewed commit: caa4b0c |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (5)
src/lib/components/jsonExportBox.svelte (2)
41-64: PrunenotifiedJobswhen jobs are removed/cleared.This set only grows; in long sessions it can retain stale keys indefinitely.
♻️ Suggested cleanup
$effect(() => { + const activeKeys = new Set($jsonExportStore.keys()); + for (const key of notifiedJobs) { + if (!activeKeys.has(key)) notifiedJobs.delete(key); + } + for (const [key, job] of $jsonExportStore.entries()) { if (notifiedJobs.has(key)) continue;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/components/jsonExportBox.svelte` around lines 41 - 64, notifiedJobs currently only grows and never removes keys; update the $effect that observes $jsonExportStore so it prunes notifiedJobs for entries no longer present in $jsonExportStore (e.g., iterate over notifiedJobs and remove any key that is not in $jsonExportStore, and/or clear notifiedJobs when $jsonExportStore is empty) so notifiedJobs doesn’t retain stale job IDs; refer to notifiedJobs, $effect, and $jsonExportStore.entries() when making the change.
1-1: Component filename/path should follow the repository component convention.Please rename/move this component to a PascalCase file under a feature directory (for example,
src/lib/components/export/JsonExportBox.svelte).As per coding guidelines: "
src/lib/components/**/*.svelte: Use PascalCase for component names and place them in src/lib/components/[feature]/ directory."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/components/jsonExportBox.svelte` at line 1, Rename the component file currently named jsonExportBox.svelte to PascalCase (JsonExportBox.svelte) and move it into a feature subdirectory under components (e.g., an "export" feature folder) so it follows the repo convention; update any imports that reference jsonExportBox.svelte to the new JsonExportBox.svelte path and ensure the component's exported name (if any) matches the PascalCase filename.src/lib/stores/jsonExport.ts (1)
16-17: Trim non-essential section comments in this TS file.Most of these comments restate obvious code flow and can be removed to keep signal high.
As per coding guidelines: "Use minimal comments; only comment TODOs or complex logic."
Also applies to: 67-67, 77-77, 84-84, 111-111, 138-138, 152-152
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/stores/jsonExport.ts` around lines 16 - 17, Remove the redundant/obvious section comments in src/lib/stores/jsonExport.ts (the comment above the "region: string" config and the comments at the locations referenced: lines ~67, 77, 84, 111, 138, 152) so only meaningful comments remain; keep any TODOs or comments explaining non-trivial logic, but delete short comments that merely restate the code flow around declarations and functions in this file (use symbols like the "region" config and the surrounding functions/classes in jsonExport.ts to locate the sections to trim).src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/export-json/+page.svelte (2)
97-97: Remove the non-essential inline comment.This line is self-explanatory; dropping the comment keeps the file aligned with the minimal-comment standard.
Suggested cleanup
- // Dispatch to the background store — progress box will handle the restAs per coding guidelines: "
**/*.{js,ts,svelte}: Use minimal comments; only comment TODOs or complex logic".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/table-[table]/export-json/+page.svelte at line 97, Remove the non-essential inline comment "// Dispatch to the background store — progress box will handle the rest" in the export-json page component; locate that comment in the +page.svelte where the dispatch to the background store is performed (the code that calls dispatch or updates the background store/progress box) and delete the comment to comply with the minimal-comment guideline.
10-10: Replace relative imports with path aliases.
../storeand../rows/storeshould be imported via configured aliases ($routes/$lib) for consistency with repo conventions.Suggested import update
- import { table } from '../store'; + import { table } from '$routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/store'; @@ - import { buildWildcardColumnsQuery } from '../rows/store'; + import { buildWildcardColumnsQuery } from '$routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/store';As per coding guidelines: "
**/*.{js,ts,svelte}: Use $lib, $routes, and $themes path aliases for imports".Also applies to: 17-17
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/table-[table]/export-json/+page.svelte at line 10, The import of the Svelte stores uses relative paths; replace imports like "../store" (which exports the symbol table) and "../rows/store" with the project's path aliases (e.g. $routes or $lib per repo convention) so they use the configured aliases instead of relative paths; update the import statements that bring in the table store and the rows store to import via the appropriate alias (referencing the exported symbols table and any rows store names) to match the codebase import convention.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@package.json`:
- Line 94: Remove the packageManager entry from package.json: locate the
"packageManager" field (the line containing "pnpm@10.30.3+sha512...") and delete
that property so package.json no longer advertises Corepack/pnpm; leave the rest
of package.json intact (do not alter scripts like "build", "clean", or "tests"
that use bun).
In `@src/lib/components/jsonExportBox.svelte`:
- Around line 24-33: The text() helper in jsonExportBox.svelte builds HTML (it
wraps job.tableName in <b> and the template uses {`@html`}) which bypasses
escaping; change text(JsonExportJob) to return plain text (no <b> tags or HTML)
and update the component template to render job.tableName (or the result of
text(...)) as a plain text node instead of using {`@html`}, ensuring all dynamic
content is escaped by Svelte's default text interpolation.
In `@src/lib/stores/jsonExport.ts`:
- Around line 112-127: The pagination loop in jsonExport.ts using
allRows/total/offset/PAGE_SIZE can hang if listRows returns an empty batch;
update the loop that calls sdk.forProject(...).tablesDB.listRows to break out
when batch.rows.length === 0 (or otherwise no new rows were returned) and also
advance offset by the actual number of rows returned (batch.rows.length) instead
of unconditionally adding PAGE_SIZE so offset/progress stays correct; apply this
change in the block referencing allRows, offset, PAGE_SIZE, and the listRows
call.
In
`@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/table-[table]/export-json/+page.svelte:
- Line 13: Replace the click analytics event with a submit event in the form
submission flow: locate where Click is imported and used with trackEvent in the
submit handler (the handler bound to the form's on:submit or the function named
submit/exportJsonSubmit), stop emitting Click and instead call trackEvent with
the Submit event type (or the project's submit event constant) and relevant
payload so the flow is tracked as a form submission; update the import to remove
Click if unused and ensure the same change is applied to the other occurrence
referenced (the second usage at line 95).
---
Nitpick comments:
In `@src/lib/components/jsonExportBox.svelte`:
- Around line 41-64: notifiedJobs currently only grows and never removes keys;
update the $effect that observes $jsonExportStore so it prunes notifiedJobs for
entries no longer present in $jsonExportStore (e.g., iterate over notifiedJobs
and remove any key that is not in $jsonExportStore, and/or clear notifiedJobs
when $jsonExportStore is empty) so notifiedJobs doesn’t retain stale job IDs;
refer to notifiedJobs, $effect, and $jsonExportStore.entries() when making the
change.
- Line 1: Rename the component file currently named jsonExportBox.svelte to
PascalCase (JsonExportBox.svelte) and move it into a feature subdirectory under
components (e.g., an "export" feature folder) so it follows the repo convention;
update any imports that reference jsonExportBox.svelte to the new
JsonExportBox.svelte path and ensure the component's exported name (if any)
matches the PascalCase filename.
In `@src/lib/stores/jsonExport.ts`:
- Around line 16-17: Remove the redundant/obvious section comments in
src/lib/stores/jsonExport.ts (the comment above the "region: string" config and
the comments at the locations referenced: lines ~67, 77, 84, 111, 138, 152) so
only meaningful comments remain; keep any TODOs or comments explaining
non-trivial logic, but delete short comments that merely restate the code flow
around declarations and functions in this file (use symbols like the "region"
config and the surrounding functions/classes in jsonExport.ts to locate the
sections to trim).
In
`@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/table-[table]/export-json/+page.svelte:
- Line 97: Remove the non-essential inline comment "// Dispatch to the
background store — progress box will handle the rest" in the export-json page
component; locate that comment in the +page.svelte where the dispatch to the
background store is performed (the code that calls dispatch or updates the
background store/progress box) and delete the comment to comply with the
minimal-comment guideline.
- Line 10: The import of the Svelte stores uses relative paths; replace imports
like "../store" (which exports the symbol table) and "../rows/store" with the
project's path aliases (e.g. $routes or $lib per repo convention) so they use
the configured aliases instead of relative paths; update the import statements
that bring in the table store and the rows store to import via the appropriate
alias (referencing the exported symbols table and any rows store names) to match
the codebase import convention.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (9)
.gitignorepackage.jsonsrc/lib/actions/analytics.tssrc/lib/components/index.tssrc/lib/components/jsonExportBox.sveltesrc/lib/stores/jsonExport.tssrc/routes/(console)/project-[region]-[project]/+layout.sveltesrc/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.sveltesrc/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/export-json/+page.svelte
...ject-[region]-[project]/databases/database-[database]/table-[table]/export-json/+page.svelte
Outdated
Show resolved
Hide resolved
…nd unsafe rendering)
There was a problem hiding this comment.
🧹 Nitpick comments (3)
src/lib/stores/jsonExport.ts (2)
143-155: System fields are always included regardless of column selection.Lines 151-153 unconditionally add
$id,$createdAt, and$updatedAteven if the user did not select them. If this is intentional behavior (per the PR description), consider adding a brief comment to clarify the design decision. If users should be able to exclude these fields, the logic needs adjustment.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/stores/jsonExport.ts` around lines 143 - 155, The current filtering in the json export (inside the filteredRows mapping over allRows in jsonExport.ts) always injects system fields $id, $createdAt, and $updatedAt regardless of config.columns; either add a short comment explaining this intentional behavior or change the logic to only add those keys when they are present in config.columns (e.g., check config.columns.includes('$id') etc.) so users can exclude system fields—update the block that constructs filtered (the loop using config.columns and the subsequent unconditional if checks) accordingly.
131-131: Consider usingpushfor better memory efficiency on large exports.Repeatedly spreading into a new array allocates O(n²) memory over the pagination loop. For large tables, this can cause GC pressure. Using
pushmutates in place and is O(n) overall.♻️ Suggested improvement
- allRows = [...allRows, ...batch.rows]; + allRows.push(...batch.rows);Apply the same pattern at line 98:
- allRows = [...firstBatch.rows]; + allRows.push(...firstBatch.rows);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/stores/jsonExport.ts` at line 131, Replace the repeated array spread allocation with in-place pushes to avoid O(n²) memory behavior: instead of reassigning allRows = [...allRows, ...batch.rows] inside the pagination loop, call allRows.push(...batch.rows) (ensure allRows is initialized as an array before the loop). Apply the same change to the similar spot referenced around line 98 where a spread reassignment is used so both places mutate the existing allRows array rather than creating a new one each page.src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/export-json/+page.svelte (1)
23-23: Unnecessary$statewrapper around writable store.The
$staterune wraps the store reference, butisSubmittingis never reassigned—only its internal value changes via the Form component. The$statewrapper adds confusion without benefit. Based on learnings, Form.svelte expects a writable store, which works correctly without the$statewrapper.♻️ Suggested fix
- let isSubmitting = $state(writable(false)); + let isSubmitting = writable(false);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/table-[table]/export-json/+page.svelte at line 23, The isSubmitting store is incorrectly wrapped with the $state rune; change the declaration from using $state(writable(false)) to simply writable(false) so Form.svelte receives a writable store as expected (ensure the writable import remains). Update the symbol isSubmitting accordingly wherever used (e.g., passed into the Form component) and remove the $state usage.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/lib/stores/jsonExport.ts`:
- Around line 143-155: The current filtering in the json export (inside the
filteredRows mapping over allRows in jsonExport.ts) always injects system fields
$id, $createdAt, and $updatedAt regardless of config.columns; either add a short
comment explaining this intentional behavior or change the logic to only add
those keys when they are present in config.columns (e.g., check
config.columns.includes('$id') etc.) so users can exclude system fields—update
the block that constructs filtered (the loop using config.columns and the
subsequent unconditional if checks) accordingly.
- Line 131: Replace the repeated array spread allocation with in-place pushes to
avoid O(n²) memory behavior: instead of reassigning allRows = [...allRows,
...batch.rows] inside the pagination loop, call allRows.push(...batch.rows)
(ensure allRows is initialized as an array before the loop). Apply the same
change to the similar spot referenced around line 98 where a spread reassignment
is used so both places mutate the existing allRows array rather than creating a
new one each page.
In
`@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/table-[table]/export-json/+page.svelte:
- Line 23: The isSubmitting store is incorrectly wrapped with the $state rune;
change the declaration from using $state(writable(false)) to simply
writable(false) so Form.svelte receives a writable store as expected (ensure the
writable import remains). Update the symbol isSubmitting accordingly wherever
used (e.g., passed into the Form component) and remove the $state usage.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
.gitignoresrc/lib/components/jsonExportBox.sveltesrc/lib/stores/jsonExport.tssrc/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/export-json/+page.svelte
🚧 Files skipped from review as they are similar to previous changes (2)
- src/lib/components/jsonExportBox.svelte
- .gitignore
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
src/lib/components/jsonExportBox.svelte (2)
5-5: Remove unusedtrackEventimport.The
trackEventfunction is imported but never used in this component.- import { trackEvent } from '$lib/actions/analytics';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/components/jsonExportBox.svelte` at line 5, Remove the unused import of trackEvent from jsonExportBox.svelte: locate the import statement that references trackEvent (import { trackEvent } from '$lib/actions/analytics';) in the jsonExportBox component and delete trackEvent from the import list (or remove the entire import line if nothing else is imported) to eliminate the unused symbol and silence the linter.
1-162: Component filename should use PascalCase.The file is named
jsonExportBox.svelte, but should beJsonExportBox.svelteper project conventions. As per coding guidelines: "Use PascalCase for component names and place them in src/lib/components/[feature]/ directory".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/components/jsonExportBox.svelte` around lines 1 - 162, Summary: Component filename uses camelCase; rename to PascalCase. Fix: rename the file from jsonExportBox.svelte to JsonExportBox.svelte and move it into the feature folder under src/lib/components if not already; then update all imports that reference "jsonExportBox" (e.g., any import lines like import X from '.../jsonExportBox.svelte') to use "JsonExportBox.svelte" instead so Svelte resolves the component correctly; verify any parent components or routes that reference the component tag or path are updated accordingly (no code changes inside the component required).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/lib/components/jsonExportBox.svelte`:
- Around line 39-62: notifiedJobs is never pruned, causing a growing Set when
jobs are removed from $jsonExportStore; update the reactive block around
$jsonExportStore (the $effect that iterates $jsonExportStore and uses
notifiedJobs) to remove stale keys after processing by comparing notifiedJobs
against the current $jsonExportStore keys (or clear notifiedJobs when
$jsonExportStore is cleared/empty) so that keys for jobs no longer present in
the store are removed and the Set cannot grow unbounded; reference notifiedJobs,
$jsonExportStore, the existing $effect and addNotification when making the
change.
---
Nitpick comments:
In `@src/lib/components/jsonExportBox.svelte`:
- Line 5: Remove the unused import of trackEvent from jsonExportBox.svelte:
locate the import statement that references trackEvent (import { trackEvent }
from '$lib/actions/analytics';) in the jsonExportBox component and delete
trackEvent from the import list (or remove the entire import line if nothing
else is imported) to eliminate the unused symbol and silence the linter.
- Around line 1-162: Summary: Component filename uses camelCase; rename to
PascalCase. Fix: rename the file from jsonExportBox.svelte to
JsonExportBox.svelte and move it into the feature folder under
src/lib/components if not already; then update all imports that reference
"jsonExportBox" (e.g., any import lines like import X from
'.../jsonExportBox.svelte') to use "JsonExportBox.svelte" instead so Svelte
resolves the component correctly; verify any parent components or routes that
reference the component tag or path are updated accordingly (no code changes
inside the component required).
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/export-json/+page.svelte (2)
11-18: Use path aliases instead of relative route imports.Please replace relative imports with
$routesaliases for consistency with repo conventions.♻️ Suggested import update
-import { table } from '../store'; +import { table } from '$routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/store'; @@ -import { buildWildcardColumnsQuery } from '../rows/store'; +import { buildWildcardColumnsQuery } from '$routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/store';As per coding guidelines,
**/*.{js,ts,svelte}:Use $lib, $routes, and $themes path aliases for imports.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/table-[table]/export-json/+page.svelte around lines 11 - 18, Replace the relative route imports in this file with the repo path-aliases: change imports that come from sibling route modules (e.g., the import of table from '../store' and buildWildcardColumnsQuery from '../rows/store') to use the $routes alias instead (e.g., import table from '$routes/…' and buildWildcardColumnsQuery from '$routes/…'); keep other canonical aliases ($lib, $themes) as-is and ensure named imports like queries, TagList, Submit, trackEvent, trackError, toLocalDateTimeISO, writable, and isSmallViewport remain unchanged.
99-99: Remove this non-essential inline comment.The comment explains obvious flow and can be dropped.
As per coding guidelines,
**/*.{js,ts,svelte}:Use minimal comments; only comment TODOs or complex logic.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/table-[table]/export-json/+page.svelte at line 99, Remove the non-essential inline comment "// Dispatch to the background store — progress box will handle the rest" that sits immediately above the dispatch call to the background store (the call that enqueues the export job and relies on the progress box to update UI); simply delete that comment line so only the dispatch logic remains, leaving surrounding code and any related variables/functions (the background store dispatch and progress box components) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/table-[table]/export-json/+page.svelte:
- Around line 49-61: The tableUrl builder only uses
page.url.searchParams.get('query') which loses repeated query parameters; update
the tableUrl computed value (the const tableUrl = $derived.by(...) block) to
preserve all active query params by either using
page.url.searchParams.getAll('query') and appending each encoded query param as
repeated ?query=... pairs or by appending the entire page.url.search string to
the resolved base URL when non-empty; keep the resolve(...) call for the base
path (region/project/database/table) and only attach the preserved query string
when present so back/forward navigation retains multiple filters.
- Around line 119-126: The catch block should narrow the caught value before
reading .message: in the catch for the try that calls
jsonExportStore.startExport() / goto(), check if error is an instance of Error
(or has a string message) and use error.message, otherwise use String(error) or
a default message; pass the narrowed Error or a constructed Error to
trackError(…, Submit.DatabaseExportJson) and use the fallback string when
calling addNotification({ type: 'error', message: ... }) so you never access
.message on a non-Error value.
---
Nitpick comments:
In
`@src/routes/`(console)/project-[region]-[project]/databases/database-[database]/table-[table]/export-json/+page.svelte:
- Around line 11-18: Replace the relative route imports in this file with the
repo path-aliases: change imports that come from sibling route modules (e.g.,
the import of table from '../store' and buildWildcardColumnsQuery from
'../rows/store') to use the $routes alias instead (e.g., import table from
'$routes/…' and buildWildcardColumnsQuery from '$routes/…'); keep other
canonical aliases ($lib, $themes) as-is and ensure named imports like queries,
TagList, Submit, trackEvent, trackError, toLocalDateTimeISO, writable, and
isSmallViewport remain unchanged.
- Line 99: Remove the non-essential inline comment "// Dispatch to the
background store — progress box will handle the rest" that sits immediately
above the dispatch call to the background store (the call that enqueues the
export job and relies on the progress box to update UI); simply delete that
comment line so only the dispatch logic remains, leaving surrounding code and
any related variables/functions (the background store dispatch and progress box
components) unchanged.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/lib/components/jsonExportBox.sveltesrc/lib/stores/jsonExport.tssrc/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/export-json/+page.svelte
🚧 Files skipped from review as they are similar to previous changes (2)
- src/lib/stores/jsonExport.ts
- src/lib/components/jsonExportBox.svelte
...ject-[region]-[project]/databases/database-[database]/table-[table]/export-json/+page.svelte
Show resolved
Hide resolved
...ject-[region]-[project]/databases/database-[database]/table-[table]/export-json/+page.svelte
Show resolved
Hide resolved
Additional Comments (1)
|

What does this PR do?
This PR extends the existing row export functionality in Databases → Table → Rows by introducing a JSON export option alongside the current CSV export.
Summary of Changes
Export as CSV (existing behavior, unchanged)
Export as JSON (new feature)
Column selection
Pretty-print option
Active filter support
Paginated row fetching
Progress tracking
Added a bottom-right progress component similar to the existing CSV export box
Introduced analytics events:
Click.DatabaseExportJson
Submit.DatabaseExportJson
Implementation Details
JSON export is implemented client-side.
Rows are fetched using tablesDB.listRows() with pagination (Query.limit + Query.offset).
Active filters from the URL are respected.
Data is assembled into a JSON array and downloaded using the Blob API (application/json).
File is named {tableName}.json.
This approach keeps the implementation lightweight while maintaining UX consistency with the existing CSV export flow.
Test Plan
Manual Verification
Run pnpm install
Run pnpm dev
Navigate to:
Databases → Select database → Select table → Rows
Verify export button shows dropdown:
"Export as CSV"
"Export as JSON"
CSV Verification
Click Export as CSV
Confirm it navigates to the existing CSV export wizard (no regression)
JSON Verification
Click Export as JSON
Confirm wizard loads correctly
Select columns and enable/disable pretty print
Start export
Verify:
-> Progress box appears
-> JSON file downloads successfully
-> File is named {tableName}.json
-> File contains valid JSON
Filter Verification
Apply a filter in the Rows view
Click Export as JSON
Confirm only filtered rows are included in downloaded file
Analytics
Related PRs and Issues
Closes Issue #2891
Have you read the Contributing Guidelines on issues?
Yes, I have read and followed the contributing guidelines.
Summary by CodeRabbit
New Features
Chores