Add snackbar on CSV exports (#13608)

#13516 

Add the snackbar on CSV exports



https://github.com/user-attachments/assets/d8288351-66f1-4175-814e-ecf0f5b57274

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
Biswas Rai
2025-08-05 03:18:00 +05:45
committed by GitHub
parent d3fc1cd837
commit 2a0c73d276
2 changed files with 56 additions and 4 deletions
@@ -1,9 +1,12 @@
import { Action } from '@/action-menu/actions/components/Action';
import { ActionDisplay } from '@/action-menu/actions/display/components/ActionDisplay';
import { ActionConfigContext } from '@/action-menu/contexts/ActionConfigContext';
import { useCloseActionMenu } from '@/action-menu/hooks/useCloseActionMenu';
import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow';
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
import { useRecordIndexExportRecords } from '@/object-record/record-index/export/hooks/useRecordIndexExportRecords';
import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useContext, useMemo } from 'react';
export const ExportMultipleRecordsAction = () => {
const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow();
@@ -16,7 +19,7 @@ export const ExportMultipleRecordsAction = () => {
throw new Error('Current view ID is not defined');
}
const { download } = useRecordIndexExportRecords({
const { download, progress } = useRecordIndexExportRecords({
delayMs: 100,
objectMetadataItem,
recordIndexId: getRecordIndexIdFromObjectNamePluralAndViewId(
@@ -26,5 +29,54 @@ export const ExportMultipleRecordsAction = () => {
filename: `${objectMetadataItem.nameSingular}.csv`,
});
return <Action onClick={download} />;
const { closeActionMenu } = useCloseActionMenu({});
const actionConfig = useContext(ActionConfigContext);
const dynamicActionConfig = useMemo(() => {
if (!actionConfig) return null;
const originalLabel =
typeof actionConfig.label === 'string'
? actionConfig.label
: actionConfig.label?.message || 'Export';
const originalShortLabel =
typeof actionConfig.shortLabel === 'string'
? actionConfig.shortLabel
: actionConfig.shortLabel?.message || 'Export';
const progressText =
progress?.exportedRecordCount !== undefined
? progress.displayType === 'percentage' && progress.totalRecordCount
? ` (${Math.round((progress.exportedRecordCount / progress.totalRecordCount) * 100)}%)`
: ` (${progress.exportedRecordCount})`
: '';
return {
...actionConfig,
label: `${originalLabel}${progressText}`,
shortLabel: `${originalShortLabel}${progressText}`,
};
}, [actionConfig, progress]);
if (!dynamicActionConfig) {
return null;
}
const handleClick = async () => {
try {
await download();
closeActionMenu();
} catch (error) {
closeActionMenu();
throw error;
}
};
return (
<ActionConfigContext.Provider value={dynamicActionConfig}>
<ActionDisplay onClick={handleClick} />
</ActionConfigContext.Provider>
);
};
@@ -127,7 +127,7 @@ type UseExportTableDataOptions = Omit<UseRecordDataOptions, 'callback'> & {
export const useRecordIndexExportRecords = ({
delayMs,
filename,
maximumRequests = 100,
maximumRequests = 1000,
objectMetadataItem,
pageSize = EXPORT_TABLE_DATA_DEFAULT_PAGE_SIZE,
recordIndexId,