diff --git a/public/locales/en/results.json b/public/locales/en/results.json index baaaa092998cf918fd7cbb01b758a76a4cc257f6..66d1b63e5be83efd6ac21c1281a9684c998cd96b 100644 --- a/public/locales/en/results.json +++ b/public/locales/en/results.json @@ -1,7 +1,17 @@ { "clickOnRowTip": "Click on a row to display metadata.", - "downloadResultsButton": { - "JSON": "Download as JSON" + "downloadResultsButtons": { + "download": "Download", + "selection": { + "all": "All results", + "selectionOnly": "Selected results only", + "label": "Row selection download options" + }, + "format": { + "label": "Download format options", + "JSON": "in JSON", + "CSV": "in CSV" + } }, "table": { "title": "Search results from query: <strong>{{searchQuery}}</strong>", diff --git a/public/locales/fr/results.json b/public/locales/fr/results.json index 1237c231591e493969bca0aa7d0b3451f9ea6db2..c8e2dd90522036090eab01276647ab2543bd3c7f 100644 --- a/public/locales/fr/results.json +++ b/public/locales/fr/results.json @@ -1,7 +1,17 @@ { "clickOnRowTip": "Clickez sur une ligne du tableau pour afficher ses métadonnées.", - "downloadResultsButton": { - "JSON": "Télécharger en JSON" + "downloadResultsButtons": { + "download": "Télécharger", + "selection": { + "all": "Tous les résultats", + "selectionOnly": "Uniquement la sélection", + "label": "Options de téléchargement de la sélection" + }, + "format": { + "label": "Format du téléchargement", + "JSON": "en JSON", + "CSV": "en CSV" + } }, "table": { "title": "Résultats de la requête : <strong>{{searchQuery}}</strong>", diff --git a/src/pages/results/Results.js b/src/pages/results/Results.js index 5d4290463b7b6abdbf45ba2b173a72f46d84451d..79eaec095dbd4c17dfb9bf7cd027d83f38797f4c 100644 --- a/src/pages/results/Results.js +++ b/src/pages/results/Results.js @@ -22,7 +22,12 @@ const Results = ({ searchResults, searchQuery, selectedRowsIds, setSelectedRowsI <EuiFlexItem> <EuiCallOut size="s" title={t('results:clickOnRowTip')} iconType="search" /> </EuiFlexItem> - <ResultsDownload searchResults={searchResults} /> + <EuiFlexItem grow={false}> + <ResultsDownload + searchResults={searchResults} + selectedRowsIds={selectedRowsIds} + /> + </EuiFlexItem> </EuiFlexGroup> <EuiSpacer size={'m'} /> <ResultsTableMUI diff --git a/src/pages/results/ResultsDownload.js b/src/pages/results/ResultsDownload.js index 7ed397818e778b6002540841f35743628c07c628..1a750b49524aa071ebdeb477a5c2669d776d1e0a 100644 --- a/src/pages/results/ResultsDownload.js +++ b/src/pages/results/ResultsDownload.js @@ -1,28 +1,146 @@ -import React from 'react'; -import { EuiButton, EuiFlexItem } from '@elastic/eui'; +import React, { useState } from 'react'; +import { EuiButton, EuiFlexGroup, EuiSelect, EuiToolTip } from '@elastic/eui'; import download from 'downloadjs'; import { useTranslation } from 'react-i18next'; -const ResultsDownload = ({ searchResults }) => { +const ResultsDownload = ({ searchResults, selectedRowsIds }) => { const { t } = useTranslation('results'); + const [resultsRowsSelection, setResultsRowsSelection] = useState('all'); + const [format, setFormat] = useState('json'); + + const downloadJSON = (content) => { + download( + `{"metadataRecords": ${JSON.stringify(content, null, '\t')}}`, + `InSylvaSearchResults.json`, + 'application/json' + ); + }; + + function JSONtoCSV(jsonData) { + let csv = ''; + let headers = Object.keys(jsonData[0]); + csv += headers.join(',') + '\n'; + jsonData.forEach((row) => { + let data = headers.map((header) => JSON.stringify(row[header])).join(','); + csv += data + '\n'; + }); + return csv; + } + + const downloadCSV = (content) => { + download(JSONtoCSV(content), `InSylvaSearchResults.csv`, 'text/csv'); + }; const downloadResults = () => { if (!searchResults) { return; } - download( - `{"metadataRecords": ${JSON.stringify(searchResults, null, '\t')}}`, - 'InSylvaSearchResults.json', - 'application/json' + let downloadResults = searchResults; + // Change content to download if user selected 'selected results only' + if (resultsRowsSelection !== 'all') { + downloadResults = searchResults.filter((result) => { + return selectedRowsIds.find((id) => result.id === id); + }); + } + // Switch will ease the need to add new formats in the future. + switch (format) { + case 'json': + downloadJSON(downloadResults); + break; + case 'csv': + downloadCSV(downloadResults); + break; + default: + downloadJSON(downloadResults); + break; + } + }; + + const ResultsRowSelectionSelectable = () => { + const resultsRowSelectionOptions = [ + { + value: 'all', + text: t('results:downloadResultsButtons.selection.all'), + }, + { + value: 'selected', + text: t('results:downloadResultsButtons.selection.selectionOnly'), + disabled: selectedRowsIds.length <= 0, + }, + ]; + + const onResultsRowSelectionChange = (e) => { + setResultsRowsSelection(e.target.value); + }; + + return ( + <EuiToolTip + position="top" + content={t('results:downloadResultsButtons.selection.label')} + > + <EuiSelect + value={resultsRowsSelection} + options={resultsRowSelectionOptions} + onChange={onResultsRowSelectionChange} + style={{ + borderRadius: '0', + }} + aria-label={t('results:downloadResultsButtons.selection.label')} + compressed + /> + </EuiToolTip> + ); + }; + + const FormatSelection = () => { + const resultsRowSelectionOptions = [ + { + value: 'json', + text: t('results:downloadResultsButtons.format.JSON'), + }, + { + value: 'csv', + text: t('results:downloadResultsButtons.format.CSV'), + }, + ]; + + const onFormatChange = (e) => { + setFormat(e.target.value); + }; + + return ( + <EuiToolTip + position="top" + content={t('results:downloadResultsButtons.format.label')} + > + <EuiSelect + value={format} + options={resultsRowSelectionOptions} + onChange={onFormatChange} + aria-label={t('results:downloadResultsButtons.format.label')} + style={{ + borderTopLeftRadius: '0', + borderBottomLeftRadius: '0', + }} + compressed + /> + </EuiToolTip> ); }; return ( - <EuiFlexItem grow={false}> - <EuiButton fill onClick={() => downloadResults()}> - {t('results:downloadResultsButton.JSON')} + <EuiFlexGroup gutterSize={'none'}> + <EuiButton + style={{ borderBottomRightRadius: '0', borderTopRightRadius: '0' }} + fill + size={'s'} + onClick={() => downloadResults()} + > + {t('results:downloadResultsButtons.download')} </EuiButton> - </EuiFlexItem> + <ResultsRowSelectionSelectable /> + <FormatSelection /> + </EuiFlexGroup> ); }; diff --git a/src/pages/search/AdvancedSearch/AdvancedSearch.js b/src/pages/search/AdvancedSearch/AdvancedSearch.js index f38cadc8e6704ee48406fa4ba916e6b7c8216d0d..154b25b6a6cfc9807856b235adc61aae66cf878e 100644 --- a/src/pages/search/AdvancedSearch/AdvancedSearch.js +++ b/src/pages/search/AdvancedSearch/AdvancedSearch.js @@ -409,13 +409,7 @@ const SearchBar = ({ placeholder={t('search:advancedSearch.textQueryPlaceholder')} fullWidth /> - {isLoading && ( - <EuiFlexGroup> - <EuiFlexItem> - <EuiProgress postion="fixed" size="l" color="accent" /> - </EuiFlexItem> - </EuiFlexGroup> - )} + {isLoading && <EuiProgress postion="fixed" size="l" color="accent" />} </EuiFlexItem> <EuiFlexItem grow={false}> <EuiButton diff --git a/src/pages/search/BasicSearch/BasicSearch.js b/src/pages/search/BasicSearch/BasicSearch.js index a4decdd8706b8b01aceb1251ae354c3a7d7bc495..4d53c63a2c53cc07919ae4fa48e59faf11e747da 100644 --- a/src/pages/search/BasicSearch/BasicSearch.js +++ b/src/pages/search/BasicSearch/BasicSearch.js @@ -63,13 +63,7 @@ const BasicSearch = ({ autoFocus={true} fullWidth /> - {isLoading && ( - <EuiFlexGroup> - <EuiFlexItem> - <EuiProgress postion="fixed" size="l" color="accent" /> - </EuiFlexItem> - </EuiFlexGroup> - )} + {isLoading && <EuiProgress postion="fixed" size="l" color="accent" />} </EuiFlexItem> <EuiFlexItem grow={false}> <EuiButton type="submit" fill isDisabled={isAdvancedSearch}>