Conversation
|
Important Review skippedAuto reviews are disabled on this repository. To trigger a review, include ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
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 |
|
@cursor review |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 3 potential issues.
Bugbot Autofix prepared fixes for all 3 issues found in the latest run.
- ✅ Fixed: Dialog cancel/confirm logic is inverted
- I swapped the close-confirmation branch so declining keeps the dialog/request unchanged while confirming now calls
onCancel()before closing.
- I swapped the close-confirmation branch so declining keeps the dialog/request unchanged while confirming now calls
- ✅ Fixed: Context value recomputes every render due to unstable
queries- I switched
useQueriesto use a memoizedqueriesarray pluscombineand now memoize contextvaluefrom the combined result to avoid per-render reference churn.
- I switched
- ✅ Fixed: eslint-disable comment lacks required explanation
- I kept the
react-hooks/exhaustive-depssuppression and added an inline reason explaining whyqueryClientis intentionally omitted.
- I kept the
Or push these changes by commenting:
@cursor push 3aed5894e2
Preview (3aed5894e2)
diff --git a/client/features/csv-export/components/dialog/CsvExportDialog.tsx b/client/features/csv-export/components/dialog/CsvExportDialog.tsx
--- a/client/features/csv-export/components/dialog/CsvExportDialog.tsx
+++ b/client/features/csv-export/components/dialog/CsvExportDialog.tsx
@@ -34,9 +34,9 @@
if (formState.isSubmitting && !open) {
const confirm = window.confirm('Are you sure you want to close the dialog? The export will be cancelled.');
if (!confirm) {
- onCancel();
return;
}
+ onCancel();
}
onOpenChange({ open });
}, [ onOpenChange, formState.isSubmitting, onCancel ]);
diff --git a/client/features/csv-export/components/downloads/CsvExportDownloadsItem.tsx b/client/features/csv-export/components/downloads/CsvExportDownloadsItem.tsx
--- a/client/features/csv-export/components/downloads/CsvExportDownloadsItem.tsx
+++ b/client/features/csv-export/components/downloads/CsvExportDownloadsItem.tsx
@@ -56,7 +56,7 @@
window.clearInterval(intervalId);
};
- // eslint-disable-next-line react-hooks/exhaustive-deps
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- queryClient is intentionally omitted to avoid restarting interval on client identity changes
}, [ data.expires_at, data.status ]);
const markItemAsViewed = React.useCallback(() => {
diff --git a/client/features/csv-export/utils/context.tsx b/client/features/csv-export/utils/context.tsx
--- a/client/features/csv-export/utils/context.tsx
+++ b/client/features/csv-export/utils/context.tsx
@@ -34,8 +34,8 @@
const [ items, setItems ] = React.useState<Array<StorageItem>>(isBrowser() ? storage.getItems() : []);
- const queries = useQueries<Array<UseQueryOptions<StorageItem | undefined, Error, StorageItem | undefined>>>({
- queries: items.map((item) => ({
+ const queryOptions = React.useMemo(() => (
+ items.map((item) => ({
queryKey: [ 'general:csv_exports_item', item.request_id ],
queryFn: async() => {
try {
@@ -64,7 +64,6 @@
storage.updateItems([ newItem ]);
return newItem;
}
-
} catch (error) {
const statusCode = getErrorObjStatusCode(error);
if (statusCode === 404) {
@@ -85,7 +84,14 @@
return status === 'pending' ? 10 * SECOND : false;
},
refetchOnMount: false,
- })),
+ })) satisfies Array<UseQueryOptions<StorageItem | undefined, Error, StorageItem | undefined>>
+ ), [ items, apiFetch ]);
+
+ const queriedItems = useQueries({
+ queries: queryOptions,
+ combine: React.useCallback((results) => {
+ return results.map(({ data }) => data).filter((item): item is StorageItem => Boolean(item));
+ }, [ ]),
});
const addItems = React.useCallback((items: Array<StorageItem>) => {
@@ -94,14 +100,13 @@
}, [ ]);
const value = React.useMemo(() => {
- const items = queries.map(({ data }) => data).filter(Boolean);
return {
dialogOpen: dialog.open,
onDialogOpenChange: dialog.onOpenChange,
- items,
+ items: queriedItems,
addItems,
};
- }, [ queries, dialog.open, dialog.onOpenChange, addItems ]);
+ }, [ queriedItems, dialog.open, dialog.onOpenChange, addItems ]);
return (
<CsvExportContext.Provider value={ value }>This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.
Applied via @cursor push command


Description and Related Issue(s)
Resolves #3319
This PR adds frontend support for async CSV export when the API reports
async_enabled: true(non-multichain). Exports are started from a dialog instead of the old standalone CSV export page; the app tracks pending jobs, polls status, and surfaces completed downloads (including a downloads list with status indicators). Multichain keeps synchronous export only (asyncis disabled when multichain is on). CSV endpoints can return HTTP 429 with a "too many pending requests" style message; that message is shown to the user without CAPTCHA or automatic retry.Proposed Changes
/csv-exportpage and related routes/components; export entry points on address, token, txs, advanced filter, etc. now open the dialog.Breaking or Incompatible Changes
Additional Information
package.jsonanddocs/ENVS.mdare unchanged vsmain— no dependencies or ENVs PR labels from this diff.Checklist for PR author
Note
Medium Risk
Adds new async CSV export flow with polling, localStorage persistence, and download-link generation, plus removes the old
/csv-exportpages; these changes touch user-facing data export behavior and routing but not auth or payments.Overview
Introduces a new
client/features/csv-exportmodule that replaces the standalone CSV export pages with an in-place export dialog (period picker + reCAPTCHA) and unified export button used across address, token holders, tx lists, and advanced filter.When
general:config_csv_exportreportsasync_enabled(and multichain is off), exports are now started asynchronously: the UI stores arequest_idin localStorage, pollsgeneral:csv_exports_itemfor completion/expiry, and surfaces results via a TopBar downloads popover with status indicators and one-click file download; otherwise it falls back to the existing synchronous blob download.Removes
/csv-exportand/chain/[chain_slug]/csv-exportroutes/SSR guards and cleans up related metadata/sitemap entries, updates API typings/resources for the new status endpoint, and adds aStatustoolkit component/recipe plus minor theme/button tweaks to support the new UI states.Written by Cursor Bugbot for commit 4fc87b8. This will update automatically on new commits. Configure here.