diff --git a/src/components/spreadsheet-view/spreadsheet/spreadsheet-toolbar/save/save-spreadsheet-button.tsx b/src/components/spreadsheet-view/spreadsheet/spreadsheet-toolbar/save/save-spreadsheet-button.tsx index 5cd3f5b7e7..0a0488b292 100644 --- a/src/components/spreadsheet-view/spreadsheet/spreadsheet-toolbar/save/save-spreadsheet-button.tsx +++ b/src/components/spreadsheet-view/spreadsheet/spreadsheet-toolbar/save/save-spreadsheet-button.tsx @@ -10,7 +10,15 @@ import { Button, Menu, MenuItem } from '@mui/material'; import { FormattedMessage } from 'react-intl'; import SaveIcon from '@mui/icons-material/Save'; import SaveSpreadsheetDialog from './save-spreadsheet-dialog'; -import { EquipmentType, FILTER_EQUIPMENTS, useCsvExport, useStateBoolean } from '@gridsuite/commons-ui'; +import { + copyToClipboard, + CsvDownloadProps, + EquipmentType, + FILTER_EQUIPMENTS, + useCsvExport, + useSnackMessage, + useStateBoolean, +} from '@gridsuite/commons-ui'; import { ROW_INDEX_COLUMN_ID } from '../../../constants'; import { type SpreadsheetTabDefinition } from '../../../types/spreadsheet.type'; import type { AgGridReact } from 'ag-grid-react'; @@ -22,6 +30,7 @@ import SaveNamingFilterDialog from './save-naming-filter-dialog'; enum SpreadsheetSaveOptionId { SAVE_MODEL = 'SAVE_MODEL', + COPY_CSV = 'COPY_CSV', EXPORT_CSV = 'EXPORT_CSV', SAVE_FILTER = 'SAVE_FILTER', } @@ -51,12 +60,47 @@ export default function SaveSpreadsheetButton({ const [anchorEl, setAnchorEl] = useState(null); const customSaveDialogOpen = useStateBoolean(false); const saveFilterDialogOpen = useStateBoolean(false); - const { downloadCSVData } = useCsvExport(); const language = useSelector((state: AppState) => state.computedLanguage); const handleClick = useCallback((event: MouseEvent) => setAnchorEl(event.currentTarget), []); const handleClose = useCallback(() => setAnchorEl(null), []); + const { snackInfo, snackError } = useSnackMessage(); + const { downloadCSVData, getCSVData } = useCsvExport(); + + const onClipboardCopy = useCallback(() => { + snackInfo({ headerId: 'spreadsheet/save/options/csv/clipboard/success' }); + }, [snackInfo]); + + const onClipboardError = useCallback(() => { + snackError({ headerId: 'spreadsheet/save/options/csv/clipboard/error' }); + }, [snackError]); + + const getCsvProps = useCallback( + (csvCase: SpreadsheetSaveOptionId.COPY_CSV | SpreadsheetSaveOptionId.EXPORT_CSV) => { + const gridCsvFunction = + csvCase === SpreadsheetSaveOptionId.COPY_CSV + ? gridRef.current?.api.getDataAsCsv + : gridRef.current?.api.exportDataAsCsv; + if (!gridCsvFunction) { + console.error('Csv API is not available.'); + return; + } + // No active calculation: 1 pinned row (default empty line); some calculations: > 1 pinned rows + const calculationRowNumber = gridRef.current?.api.getGridOption('pinnedBottomRowData')?.length ?? 0; + return { + // Filter out the rowIndex column and the hidden columns before exporting to CSV + columns: columns.filter((col) => col.colId !== ROW_INDEX_COLUMN_ID && !col.hide), + tableName: tableDefinition.name, + language: language, + getDataAsCsv: csvCase === SpreadsheetSaveOptionId.COPY_CSV ? gridCsvFunction : undefined, + exportDataAsCsv: csvCase === SpreadsheetSaveOptionId.COPY_CSV ? undefined : gridCsvFunction, + skipPinnedBottom: calculationRowNumber === 1, + } as CsvDownloadProps; + }, + [columns, gridRef, language, tableDefinition.name] + ); + const spreadsheetOptions = useMemo>( () => ({ [SpreadsheetSaveOptionId.SAVE_MODEL]: { @@ -64,26 +108,25 @@ export default function SaveSpreadsheetButton({ label: 'spreadsheet/save/options/model', action: customSaveDialogOpen.setTrue, }, + [SpreadsheetSaveOptionId.COPY_CSV]: { + id: SpreadsheetSaveOptionId.COPY_CSV, + label: 'spreadsheet/save/options/csv/clipboard', + action: () => { + const csvProps = getCsvProps(SpreadsheetSaveOptionId.COPY_CSV); + if (csvProps) { + copyToClipboard(getCSVData(csvProps) ?? '', onClipboardCopy, onClipboardError); + } + }, + disabled: dataSize === 0, + }, [SpreadsheetSaveOptionId.EXPORT_CSV]: { id: SpreadsheetSaveOptionId.EXPORT_CSV, - label: 'spreadsheet/save/options/csv', + label: 'spreadsheet/save/options/csv/export', action: () => { - const exportDataAsCsv = gridRef.current?.api.exportDataAsCsv; - if (!exportDataAsCsv) { - console.error('Export API is not available.'); - return; + const csvProps = getCsvProps(SpreadsheetSaveOptionId.EXPORT_CSV); + if (csvProps) { + downloadCSVData(csvProps); } - - // No active calculation: 1 pinned row (default empty line); some calculations: > 1 pinned rows - const calculationRowNumber = gridRef.current?.api.getGridOption('pinnedBottomRowData')?.length ?? 0; - downloadCSVData({ - // Filter out the rowIndex column and the hidden columns before exporting to CSV - columns: columns.filter((col) => col.colId !== ROW_INDEX_COLUMN_ID && !col.hide), - tableName: tableDefinition.name, - language: language, - exportDataAsCsv, - skipPinnedBottom: calculationRowNumber === 1, // skip last empty line - }); }, disabled: dataSize === 0, }, @@ -96,14 +139,14 @@ export default function SaveSpreadsheetButton({ }), [ customSaveDialogOpen.setTrue, - saveFilterDialogOpen.setTrue, dataSize, - columns, - downloadCSVData, - gridRef, - tableDefinition.name, + saveFilterDialogOpen.setTrue, tableDefinition.type, - language, + getCsvProps, + getCSVData, + onClipboardCopy, + onClipboardError, + downloadCSVData, ] ); diff --git a/src/translations/spreadsheet-en.ts b/src/translations/spreadsheet-en.ts index f782fc51e5..07d1e4e18f 100644 --- a/src/translations/spreadsheet-en.ts +++ b/src/translations/spreadsheet-en.ts @@ -43,7 +43,10 @@ const spreadsheetEn = { 'spreadsheet/save/options/model': 'As a model', 'spreadsheet/save/options/filter': 'As a filter', 'spreadsheet/save/options/collection': 'Collection', - 'spreadsheet/save/options/csv': 'Export CSV', + 'spreadsheet/save/options/csv/export': 'Export CSV', + 'spreadsheet/save/options/csv/clipboard': 'Copy CSV', + 'spreadsheet/save/options/csv/clipboard/success': 'Sheet content copied to system clipboard', + 'spreadsheet/save/options/csv/clipboard/error': 'Could not copy sheet content to system clipboard', 'spreadsheet/save/dialog_title': 'Save a spreadsheet model', 'spreadsheet/collection/save/collection_name_dialog_title': 'Save a spreadsheet collection', 'spreadsheet/collection/save/button_tooltip': 'Save collection', diff --git a/src/translations/spreadsheet-fr.ts b/src/translations/spreadsheet-fr.ts index 335c1fa99d..11ea9f8850 100644 --- a/src/translations/spreadsheet-fr.ts +++ b/src/translations/spreadsheet-fr.ts @@ -45,7 +45,12 @@ const spreadsheetFr = { 'spreadsheet/save/options/model': 'En tant que modèle', 'spreadsheet/save/options/filter': 'En tant que filtre', 'spreadsheet/save/options/collection': 'Collection', - 'spreadsheet/save/options/csv': 'Export CSV', + 'spreadsheet/save/options/csv/export': 'Export CSV', + 'spreadsheet/save/options/csv/clipboard': 'CopieX CSV', + 'spreadsheet/save/options/csv/clipboard/success': + 'Le contenu de la feuille a été copié dans le presse-papier système', + 'spreadsheet/save/options/csv/clipboard/error': + "Le contenu de la feuille n'a pas pu être copié dans le presse-papier système", 'spreadsheet/save/dialog_title': 'Enregistrer un modèle de tableur', 'spreadsheet/collection/save/collection_name_dialog_title': 'Enregistrer une collection de tableurs', 'spreadsheet/save/error_message': 'Une erreur est survenue lors de la création du modèle de tableur',