From 83ea49ef7f5275f3a20fee830538ef98a91fdbf2 Mon Sep 17 00:00:00 2001 From: Charis Mytilinaios Date: Fri, 14 Jul 2023 15:35:49 +0300 Subject: [PATCH 1/3] Exposure Analysis Download CSV access from anywhere --- .../ExposureAnalysisActions/index.tsx | 68 +++++----------- .../MapView/LeftPanel/AnalysisPanel/index.tsx | 38 ++++++--- .../index.tsx | 75 +++++++++++++----- .../Legends/AnalysisDownloadButton.tsx | 79 +++++++++++++------ frontend/src/components/MapView/utils.ts | 52 +++++++++++- .../src/context/analysisResultStateSlice.ts | 30 +++++++ frontend/src/utils/csv-utils.ts | 11 +++ 7 files changed, 252 insertions(+), 101 deletions(-) diff --git a/frontend/src/components/MapView/LeftPanel/AnalysisPanel/ExposureAnalysisActions/index.tsx b/frontend/src/components/MapView/LeftPanel/AnalysisPanel/ExposureAnalysisActions/index.tsx index 0f8337301..e18230cb6 100644 --- a/frontend/src/components/MapView/LeftPanel/AnalysisPanel/ExposureAnalysisActions/index.tsx +++ b/frontend/src/components/MapView/LeftPanel/AnalysisPanel/ExposureAnalysisActions/index.tsx @@ -9,17 +9,21 @@ import { } from '@material-ui/core'; import { snakeCase } from 'lodash'; import { useSelector } from 'react-redux'; -import { downloadToFile } from 'components/MapView/utils'; +import { + downloadToFile, + getExposureAnalysisColumnsToRender, + getExposureAnalysisTableDataRowsToRender, +} from 'components/MapView/utils'; import { useSafeTranslation } from 'i18n'; import { exposureLayerIdSelector, getCurrentDefinition, - TableRow, TableRow as AnalysisTableRow, } from 'context/analysisResultStateSlice'; import ReportDialog from 'components/Common/ReportDialog'; -import { Column, quoteAndEscapeCell } from 'utils/analysis-utils'; +import { Column } from 'utils/analysis-utils'; import { ReportsDefinitions } from 'config/utils'; +import { getExposureAnalysisCsvData } from 'utils/csv-utils'; function ExposureAnalysisActions({ analysisButton, @@ -35,24 +39,17 @@ function ExposureAnalysisActions({ const [openReport, setOpenReport] = useState(false); - const getCellValue = useCallback((value: string | number, column: Column) => { - if (column.format && typeof value === 'number') { - return quoteAndEscapeCell(column.format(value)); - } - return quoteAndEscapeCell(value); - }, []); - - const columnsToRenderCsv = useMemo(() => { - return columns.reduce( - (acc: { [key: string]: string | number }, column: Column) => { - return { - ...acc, - [column.id]: column.label, - }; - }, - {}, - ); - }, [columns]); + const exposureAnalysisColumnsToRender = getExposureAnalysisColumnsToRender( + columns, + ); + const exposureAnalysisTableRowsToRender = getExposureAnalysisTableDataRowsToRender( + columns, + tableData, + ); + const exposureAnalysisCsvData = getExposureAnalysisCsvData( + exposureAnalysisColumnsToRender, + exposureAnalysisTableRowsToRender, + ); const reportConfig = useMemo(() => { // We use find here because exposure reports and layers have 1 - 1 sync. @@ -67,35 +64,12 @@ function ExposureAnalysisActions({ return ReportsDefinitions[foundReportKeyBasedOnLayerId as string]; }, [exposureLayerId]); - const tableDataRowsToRenderCsv = useMemo(() => { - return tableData.map((tableRowData: TableRow) => { - return columns.reduce( - (acc: { [key: string]: string | number }, column: Column) => { - const value = tableRowData[column.id]; - return { - ...acc, - [column.id]: getCellValue(value, column), - }; - }, - {}, - ); - }); - }, [columns, getCellValue, tableData]); - - const analysisCsvData = useMemo(() => { - return [columnsToRenderCsv, ...tableDataRowsToRenderCsv] - .map(analysisCsvItem => { - return Object.values(analysisCsvItem); - }) - .join('\n'); - }, [columnsToRenderCsv, tableDataRowsToRenderCsv]); - const handleOnDownloadCsv = useCallback( (event: MouseEvent) => { event.preventDefault(); downloadToFile( { - content: analysisCsvData, + content: exposureAnalysisCsvData, isUrl: false, }, `${snakeCase(analysisDefinition?.id)}_${snakeCase( @@ -104,7 +78,7 @@ function ExposureAnalysisActions({ 'text/csv', ); }, - [analysisCsvData, analysisDefinition], + [analysisDefinition, exposureAnalysisCsvData], ); const handleToggleReport = (toggle: boolean) => { @@ -118,7 +92,7 @@ function ExposureAnalysisActions({ - {analysisCsvData && ( + {exposureAnalysisCsvData && ( diff --git a/frontend/src/components/MapView/LeftPanel/AnalysisPanel/index.tsx b/frontend/src/components/MapView/LeftPanel/AnalysisPanel/index.tsx index de0ddc5c1..7faaeac45 100644 --- a/frontend/src/components/MapView/LeftPanel/AnalysisPanel/index.tsx +++ b/frontend/src/components/MapView/LeftPanel/AnalysisPanel/index.tsx @@ -57,6 +57,11 @@ import { analysisResultSortOrderSelector, setAnalysisResultSortByKey, setAnalysisResultSortOrder, + exposureAnalysisResultSortByKeySelector, + exposureAnalysisResultSortOrderSelector, + setExposureAnalysisResultSortByKey, + setExposureAnalysisResultSortOrder, + TableRow, } from 'context/analysisResultStateSlice'; import { AdminLevelType, @@ -102,6 +107,7 @@ import LoadingBlinkingDots from 'components/Common/LoadingBlinkingDots'; import AnalysisTable from './AnalysisTable'; import ExposureAnalysisTable from './AnalysisTable/ExposureAnalysisTable'; import ExposureAnalysisActions from './ExposureAnalysisActions'; +import { getExposureAnalysisTableData } from '../../utils'; const tabIndex = 2; @@ -132,6 +138,12 @@ const AnalysisPanel = memo( const analysisResultSortOrder = useSelector( analysisResultSortOrderSelector, ); + const exposureAnalysisResultSortByKey = useSelector( + exposureAnalysisResultSortByKeySelector, + ); + const exposureAnalysisResultSortOrder = useSelector( + exposureAnalysisResultSortOrderSelector, + ); const isAnalysisLoading = useSelector(isAnalysisLoadingSelector); const isExposureAnalysisLoading = useSelector( isExposureAnalysisLoadingSelector, @@ -142,12 +154,12 @@ const AnalysisPanel = memo( const [ exposureAnalysisSortColumn, setExposureAnalysisSortColumn, - ] = useState('name'); + ] = useState(exposureAnalysisResultSortByKey); // exposure analysis sort order const [ exposureAnalysisIsAscending, setExposureAnalysisIsAscending, - ] = useState(true); + ] = useState(exposureAnalysisResultSortOrder === 'asc'); // defaults the sort column of every other analysis table to 'name' const [analysisSortColumn, setAnalysisSortColumn] = useState( analysisResultSortByKey, @@ -654,22 +666,22 @@ const AnalysisPanel = memo( ); setExposureAnalysisSortColumn(newExposureAnalysisSortColumn); setExposureAnalysisIsAscending(newIsAsc); + // set the sort by key of exposure analysis data in redux + dispatch( + setExposureAnalysisResultSortByKey(newExposureAnalysisSortColumn), + ); + // set the sort order of exposure analysis result data in redux + dispatch(setExposureAnalysisResultSortOrder(newIsAsc ? 'asc' : 'desc')); }, - [exposureAnalysisIsAscending, exposureAnalysisSortColumn], + [dispatch, exposureAnalysisIsAscending, exposureAnalysisSortColumn], ); // The exposure analysis table data - const exposureAnalysisTableData = useMemo(() => { - return orderBy( - analysisResult?.tableData, - exposureAnalysisSortColumn, - exposureAnalysisIsAscending ? 'asc' : 'desc', - ); - }, [ - analysisResult, - exposureAnalysisIsAscending, + const exposureAnalysisTableData = getExposureAnalysisTableData( + analysisResult?.tableData as TableRow[], exposureAnalysisSortColumn, - ]); + exposureAnalysisIsAscending ? 'asc' : 'desc', + ); const renderedExposureAnalysisLoading = useMemo(() => { if (!isExposureAnalysisLoading) { diff --git a/frontend/src/components/MapView/LeftPanel/layersPanel/AnalysisLayerSwitchItem/AnalysisLayerSwitchItemDownloadOptions/index.tsx b/frontend/src/components/MapView/LeftPanel/layersPanel/AnalysisLayerSwitchItem/AnalysisLayerSwitchItemDownloadOptions/index.tsx index 715f3e642..83b467a57 100644 --- a/frontend/src/components/MapView/LeftPanel/layersPanel/AnalysisLayerSwitchItem/AnalysisLayerSwitchItemDownloadOptions/index.tsx +++ b/frontend/src/components/MapView/LeftPanel/layersPanel/AnalysisLayerSwitchItem/AnalysisLayerSwitchItemDownloadOptions/index.tsx @@ -2,7 +2,12 @@ import React, { memo, useMemo, useCallback, useState } from 'react'; import { IconButton, Menu, MenuItem, Tooltip } from '@material-ui/core'; import GetAppIcon from '@material-ui/icons/GetApp'; import { useSafeTranslation } from 'i18n'; -import { downloadToFile } from 'components/MapView/utils'; +import { + downloadToFile, + getExposureAnalysisColumnsToRender, + getExposureAnalysisTableData, + getExposureAnalysisTableDataRowsToRender, +} from 'components/MapView/utils'; import { BaselineLayerResult, downloadCSVFromTableData, @@ -11,6 +16,15 @@ import { PolygonAnalysisResult, useAnalysisTableColumns, } from 'utils/analysis-utils'; +import { snakeCase } from 'lodash'; +import { useSelector } from 'react-redux'; +import { + exposureAnalysisResultSortByKeySelector, + exposureAnalysisResultSortOrderSelector, + getCurrentDefinition, + TableRow, +} from 'context/analysisResultStateSlice'; +import { getExposureAnalysisCsvData } from 'utils/csv-utils'; const AnalysisLayerSwitchItemDownloadOptions = memo( ({ @@ -26,20 +40,33 @@ const AnalysisLayerSwitchItemDownloadOptions = memo( const { translatedColumns } = useAnalysisTableColumns(analysisData); + const exposureAnalysisResultSortByKey = useSelector( + exposureAnalysisResultSortByKeySelector, + ); + const exposureAnalysisResultSortOrder = useSelector( + exposureAnalysisResultSortOrderSelector, + ); + const analysisDefinition = useSelector(getCurrentDefinition); + + const exposureAnalysisTableData = getExposureAnalysisTableData( + analysisData?.tableData as TableRow[], + exposureAnalysisResultSortByKey, + exposureAnalysisResultSortOrder, + ); + const exposureAnalysisColumnsToRender = getExposureAnalysisColumnsToRender( + translatedColumns, + ); + const exposureAnalysisTableRowsToRender = getExposureAnalysisTableDataRowsToRender( + translatedColumns, + exposureAnalysisTableData, + ); + const { t } = useSafeTranslation(); const featureCollection = useMemo(() => { return analysisData?.featureCollection; }, [analysisData]); - const doesLayerAcceptCSVDownload = useMemo(() => { - return ( - analysisData && - (analysisData instanceof BaselineLayerResult || - analysisData instanceof PolygonAnalysisResult) - ); - }, [analysisData]); - const handleDownloadMenuClose = useCallback(() => { setDownloadMenuAnchorEl(null); }, []); @@ -90,11 +117,23 @@ const AnalysisLayerSwitchItemDownloadOptions = memo( }, [analysisData, analysisDate, t]); const handleDownloadCsv = useCallback((): void => { - if ( - // Explicit condition for type narrowing - !analysisData || - analysisData instanceof ExposedPopulationResult - ) { + if (!analysisData) { + return; + } + if (analysisData instanceof ExposedPopulationResult) { + downloadToFile( + { + content: getExposureAnalysisCsvData( + exposureAnalysisColumnsToRender, + exposureAnalysisTableRowsToRender, + ), + isUrl: false, + }, + `${snakeCase(analysisDefinition?.id)}_${snakeCase( + analysisDefinition?.legendText, + )}`, + 'text/csv', + ); return; } downloadCSVFromTableData( @@ -107,8 +146,11 @@ const AnalysisLayerSwitchItemDownloadOptions = memo( }, [ analysisData, analysisDate, + analysisDefinition, analysisResultSortByKey, analysisResultSortOrder, + exposureAnalysisColumnsToRender, + exposureAnalysisTableRowsToRender, translatedColumns, ]); @@ -127,15 +169,12 @@ const AnalysisLayerSwitchItemDownloadOptions = memo( }, [analysisData, featureCollection, fileName]); const renderedDownloadAsCSVMenuItem = useMemo(() => { - if (!doesLayerAcceptCSVDownload) { - return null; - } return ( {t('Download as CSV')} ); - }, [doesLayerAcceptCSVDownload, handleDownloadCsv, t]); + }, [handleDownloadCsv, t]); return ( <> diff --git a/frontend/src/components/MapView/Legends/AnalysisDownloadButton.tsx b/frontend/src/components/MapView/Legends/AnalysisDownloadButton.tsx index 4c7ea0aaf..fe428011e 100644 --- a/frontend/src/components/MapView/Legends/AnalysisDownloadButton.tsx +++ b/frontend/src/components/MapView/Legends/AnalysisDownloadButton.tsx @@ -4,6 +4,10 @@ import { analysisResultSelector, analysisResultSortByKeySelector, analysisResultSortOrderSelector, + exposureAnalysisResultSortByKeySelector, + exposureAnalysisResultSortOrderSelector, + getCurrentDefinition, + TableRow, } from 'context/analysisResultStateSlice'; import { useSafeTranslation } from 'i18n'; import { @@ -15,7 +19,14 @@ import { useAnalysisTableColumns, } from 'utils/analysis-utils'; import MultiOptionsButton from 'components/Common/MultiOptionsButton'; -import { downloadToFile } from 'components/MapView/utils'; +import { + downloadToFile, + getExposureAnalysisColumnsToRender, + getExposureAnalysisTableData, + getExposureAnalysisTableDataRowsToRender, +} from 'components/MapView/utils'; +import { snakeCase } from 'lodash'; +import { getExposureAnalysisCsvData } from 'utils/csv-utils'; function AnalysisDownloadButton() { const analysisResult = useSelector(analysisResultSelector); @@ -23,20 +34,33 @@ function AnalysisDownloadButton() { const analysisResultSortOrder = useSelector(analysisResultSortOrderSelector); const { translatedColumns } = useAnalysisTableColumns(analysisResult); + const exposureAnalysisResultSortByKey = useSelector( + exposureAnalysisResultSortByKeySelector, + ); + const exposureAnalysisResultSortOrder = useSelector( + exposureAnalysisResultSortOrderSelector, + ); + const analysisDefinition = useSelector(getCurrentDefinition); + + const exposureAnalysisTableData = getExposureAnalysisTableData( + analysisResult?.tableData as TableRow[], + exposureAnalysisResultSortByKey, + exposureAnalysisResultSortOrder, + ); + const exposureAnalysisColumnsToRender = getExposureAnalysisColumnsToRender( + translatedColumns, + ); + const exposureAnalysisTableRowsToRender = getExposureAnalysisTableDataRowsToRender( + translatedColumns, + exposureAnalysisTableData, + ); + const { t } = useSafeTranslation(); const featureCollection = useMemo(() => { return analysisResult?.featureCollection; }, [analysisResult]); - const doesLayerAcceptCSVDownload = useMemo(() => { - return ( - analysisResult && - (analysisResult instanceof BaselineLayerResult || - analysisResult instanceof PolygonAnalysisResult) - ); - }, [analysisResult]); - const analysisDate = useMemo(() => { if (analysisResult instanceof BaselineLayerResult) { return analysisResult.analysisDate; @@ -70,11 +94,23 @@ function AnalysisDownloadButton() { }, [featureCollection, fileName]); const handleAnalysisDownloadCsv = useCallback((): void => { - if ( - // Explicit condition for type narrowing - !analysisResult || - analysisResult instanceof ExposedPopulationResult - ) { + if (!analysisResult) { + return; + } + if (analysisResult instanceof ExposedPopulationResult) { + downloadToFile( + { + content: getExposureAnalysisCsvData( + exposureAnalysisColumnsToRender, + exposureAnalysisTableRowsToRender, + ), + isUrl: false, + }, + `${snakeCase(analysisDefinition?.id)}_${snakeCase( + analysisDefinition?.legendText, + )}`, + 'text/csv', + ); return; } downloadCSVFromTableData( @@ -86,9 +122,12 @@ function AnalysisDownloadButton() { ); }, [ analysisDate, + analysisDefinition, analysisResult, analysisResultSortByKey, analysisResultSortOrder, + exposureAnalysisColumnsToRender, + exposureAnalysisTableRowsToRender, translatedColumns, ]); @@ -100,14 +139,10 @@ function AnalysisDownloadButton() { label: 'GEOJSON', onClick: handleAnalysisDownloadGeoJson, }, - ...(doesLayerAcceptCSVDownload - ? [ - { - label: 'CSV', - onClick: handleAnalysisDownloadCsv, - }, - ] - : []), + { + label: 'CSV', + onClick: handleAnalysisDownloadCsv, + }, ]} /> ); diff --git a/frontend/src/components/MapView/utils.ts b/frontend/src/components/MapView/utils.ts index e4a2cc923..4e10500ed 100644 --- a/frontend/src/components/MapView/utils.ts +++ b/frontend/src/components/MapView/utils.ts @@ -1,4 +1,4 @@ -import { values } from 'lodash'; +import { orderBy, values } from 'lodash'; import { Map } from 'mapbox-gl'; import { TFunction } from 'i18next'; import { Dispatch } from 'redux'; @@ -16,6 +16,8 @@ import { TableData } from 'context/tableStateSlice'; import { getUrlKey, UrlLayerKey } from 'utils/url-utils'; import { addNotification } from 'context/notificationStateSlice'; import { LocalError } from 'utils/error-utils'; +import { Column, quoteAndEscapeCell } from 'utils/analysis-utils'; +import { TableRow } from 'context/analysisResultStateSlice'; import { getExtent } from './Layers/raster-utils'; export const getActiveFeatureInfoLayers = (map: Map): WMSLayerProps[] => { @@ -184,3 +186,51 @@ export const filterActiveLayers = ( filterActiveGroupedLayers(selectedLayer, categoryLayer) ); }; + +const getExposureAnalysisTableCellValue = ( + value: string | number, + column: Column, +) => { + if (column.format && typeof value === 'number') { + return quoteAndEscapeCell(column.format(value)); + } + return quoteAndEscapeCell(value); +}; + +export const getExposureAnalysisColumnsToRender = (columns: Column[]) => { + return columns.reduce( + (acc: { [key: string]: string | number }, column: Column) => { + return { + ...acc, + [column.id]: column.label, + }; + }, + {}, + ); +}; + +export const getExposureAnalysisTableDataRowsToRender = ( + columns: Column[], + tableData: TableRow[], +) => { + return tableData.map((tableRowData: TableRow) => { + return columns.reduce( + (acc: { [key: string]: string | number }, column: Column) => { + const value = tableRowData[column.id]; + return { + ...acc, + [column.id]: getExposureAnalysisTableCellValue(value, column), + }; + }, + {}, + ); + }); +}; + +export const getExposureAnalysisTableData = ( + tableData: TableRow[], + sortColumn: Column['id'], + sortOrder: 'asc' | 'desc', +) => { + return orderBy(tableData, sortColumn, sortOrder); +}; diff --git a/frontend/src/context/analysisResultStateSlice.ts b/frontend/src/context/analysisResultStateSlice.ts index f3f6ea8b2..bf451babf 100644 --- a/frontend/src/context/analysisResultStateSlice.ts +++ b/frontend/src/context/analysisResultStateSlice.ts @@ -84,6 +84,8 @@ type AnalysisResultState = { opacity: number; analysisResultDataSortByKey: Column['id']; analysisResultDataSortOrder: 'asc' | 'desc'; + exposureAnalysisResultDataSortByKey: Column['id']; + exposureAnalysisResultDataSortOrder: 'asc' | 'desc'; }; export type TableRow = { @@ -104,6 +106,8 @@ const initialState: AnalysisResultState = { isExposureLoading: false, analysisResultDataSortByKey: 'name', analysisResultDataSortOrder: 'asc', + exposureAnalysisResultDataSortByKey: 'name', + exposureAnalysisResultDataSortOrder: 'asc', opacity: 0.5, }; @@ -796,6 +800,20 @@ export const analysisResultSlice = createSlice({ ...state, analysisResultDataSortOrder: payload, }), + setExposureAnalysisResultSortByKey: ( + state, + { payload }: PayloadAction, + ) => ({ + ...state, + exposureAnalysisResultDataSortByKey: payload, + }), + setExposureAnalysisResultSortOrder: ( + state, + { payload }: PayloadAction<'asc' | 'desc'>, + ) => ({ + ...state, + exposureAnalysisResultDataSortOrder: payload, + }), setAnalysisLayerOpacity: (state, { payload }: PayloadAction) => ({ ...state, opacity: payload, @@ -948,6 +966,16 @@ export const analysisResultSortOrderSelector = ( state: RootState, ): 'asc' | 'desc' => state.analysisResultState.analysisResultDataSortOrder; +export const exposureAnalysisResultSortByKeySelector = ( + state: RootState, +): string | number => + state.analysisResultState.exposureAnalysisResultDataSortByKey; + +export const exposureAnalysisResultSortOrderSelector = ( + state: RootState, +): 'asc' | 'desc' => + state.analysisResultState.exposureAnalysisResultDataSortOrder; + export const exposureLayerIdSelector = (state: RootState): string => state.analysisResultState.exposureLayerId; @@ -977,6 +1005,8 @@ export const { clearAnalysisResult, setAnalysisResultSortByKey, setAnalysisResultSortOrder, + setExposureAnalysisResultSortByKey, + setExposureAnalysisResultSortOrder, } = analysisResultSlice.actions; export default analysisResultSlice.reducer; diff --git a/frontend/src/utils/csv-utils.ts b/frontend/src/utils/csv-utils.ts index 1f9d037dc..7b24e263f 100644 --- a/frontend/src/utils/csv-utils.ts +++ b/frontend/src/utils/csv-utils.ts @@ -15,3 +15,14 @@ export function castObjectsArrayToCsv( }), ].join('\n'); } + +export const getExposureAnalysisCsvData = ( + exposureAnalysisColumnsToRender: { [x: string]: string | number }, + exposureAnalysisTableRowsToRender: { [x: string]: string | number }[], +) => { + return [exposureAnalysisColumnsToRender, ...exposureAnalysisTableRowsToRender] + .map(analysisCsvItem => { + return Object.values(analysisCsvItem); + }) + .join('\n'); +}; From 0dc8c0328edd4c67d352b2ef1a3080a9acd4a4b6 Mon Sep 17 00:00:00 2001 From: Charis Mytilinaios Date: Fri, 14 Jul 2023 16:18:08 +0300 Subject: [PATCH 2/3] Updated snapshots --- .../AnalysisLayerMenuItem/__snapshots__/index.test.tsx.snap | 3 +++ .../__snapshots__/index.test.tsx.snap | 3 +++ .../AnalysisLayerSwitchItem/__snapshots__/index.test.tsx.snap | 3 +++ 3 files changed, 9 insertions(+) diff --git a/frontend/src/components/MapView/LeftPanel/layersPanel/AnalysisLayerMenuItem/__snapshots__/index.test.tsx.snap b/frontend/src/components/MapView/LeftPanel/layersPanel/AnalysisLayerMenuItem/__snapshots__/index.test.tsx.snap index b617613b9..518cded82 100644 --- a/frontend/src/components/MapView/LeftPanel/layersPanel/AnalysisLayerMenuItem/__snapshots__/index.test.tsx.snap +++ b/frontend/src/components/MapView/LeftPanel/layersPanel/AnalysisLayerMenuItem/__snapshots__/index.test.tsx.snap @@ -148,6 +148,9 @@ exports[`renders as expected 1`] = ` keepmounted="true" open="false" > + + Download as CSV + Download as GeoJSON diff --git a/frontend/src/components/MapView/LeftPanel/layersPanel/AnalysisLayerSwitchItem/AnalysisLayerSwitchItemDownloadOptions/__snapshots__/index.test.tsx.snap b/frontend/src/components/MapView/LeftPanel/layersPanel/AnalysisLayerSwitchItem/AnalysisLayerSwitchItemDownloadOptions/__snapshots__/index.test.tsx.snap index 63570b256..d7425c026 100644 --- a/frontend/src/components/MapView/LeftPanel/layersPanel/AnalysisLayerSwitchItem/AnalysisLayerSwitchItemDownloadOptions/__snapshots__/index.test.tsx.snap +++ b/frontend/src/components/MapView/LeftPanel/layersPanel/AnalysisLayerSwitchItem/AnalysisLayerSwitchItemDownloadOptions/__snapshots__/index.test.tsx.snap @@ -34,6 +34,9 @@ exports[`renders as expected 1`] = ` keepmounted="true" open="false" > + + Download as CSV + Download as GeoJSON diff --git a/frontend/src/components/MapView/LeftPanel/layersPanel/AnalysisLayerSwitchItem/__snapshots__/index.test.tsx.snap b/frontend/src/components/MapView/LeftPanel/layersPanel/AnalysisLayerSwitchItem/__snapshots__/index.test.tsx.snap index 88af92274..af66f04c9 100644 --- a/frontend/src/components/MapView/LeftPanel/layersPanel/AnalysisLayerSwitchItem/__snapshots__/index.test.tsx.snap +++ b/frontend/src/components/MapView/LeftPanel/layersPanel/AnalysisLayerSwitchItem/__snapshots__/index.test.tsx.snap @@ -79,6 +79,9 @@ exports[`renders as expected 1`] = ` keepmounted="true" open="false" > + + Download as CSV + Download as GeoJSON From d1c8623d247ee967ca4b837e255f17f99ab44ef0 Mon Sep 17 00:00:00 2001 From: Eric Boucher Date: Thu, 20 Jul 2023 14:27:38 +0200 Subject: [PATCH 3/3] fix potentially undefined array --- .../src/components/MapView/LeftPanel/AnalysisPanel/index.tsx | 2 +- .../AnalysisLayerSwitchItemDownloadOptions/index.tsx | 2 +- .../src/components/MapView/Legends/AnalysisDownloadButton.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/MapView/LeftPanel/AnalysisPanel/index.tsx b/frontend/src/components/MapView/LeftPanel/AnalysisPanel/index.tsx index 7faaeac45..388b98f6d 100644 --- a/frontend/src/components/MapView/LeftPanel/AnalysisPanel/index.tsx +++ b/frontend/src/components/MapView/LeftPanel/AnalysisPanel/index.tsx @@ -678,7 +678,7 @@ const AnalysisPanel = memo( // The exposure analysis table data const exposureAnalysisTableData = getExposureAnalysisTableData( - analysisResult?.tableData as TableRow[], + (analysisResult?.tableData || []) as TableRow[], exposureAnalysisSortColumn, exposureAnalysisIsAscending ? 'asc' : 'desc', ); diff --git a/frontend/src/components/MapView/LeftPanel/layersPanel/AnalysisLayerSwitchItem/AnalysisLayerSwitchItemDownloadOptions/index.tsx b/frontend/src/components/MapView/LeftPanel/layersPanel/AnalysisLayerSwitchItem/AnalysisLayerSwitchItemDownloadOptions/index.tsx index 83b467a57..d738728f5 100644 --- a/frontend/src/components/MapView/LeftPanel/layersPanel/AnalysisLayerSwitchItem/AnalysisLayerSwitchItemDownloadOptions/index.tsx +++ b/frontend/src/components/MapView/LeftPanel/layersPanel/AnalysisLayerSwitchItem/AnalysisLayerSwitchItemDownloadOptions/index.tsx @@ -49,7 +49,7 @@ const AnalysisLayerSwitchItemDownloadOptions = memo( const analysisDefinition = useSelector(getCurrentDefinition); const exposureAnalysisTableData = getExposureAnalysisTableData( - analysisData?.tableData as TableRow[], + (analysisData?.tableData || []) as TableRow[], exposureAnalysisResultSortByKey, exposureAnalysisResultSortOrder, ); diff --git a/frontend/src/components/MapView/Legends/AnalysisDownloadButton.tsx b/frontend/src/components/MapView/Legends/AnalysisDownloadButton.tsx index fe428011e..90b3221f3 100644 --- a/frontend/src/components/MapView/Legends/AnalysisDownloadButton.tsx +++ b/frontend/src/components/MapView/Legends/AnalysisDownloadButton.tsx @@ -43,7 +43,7 @@ function AnalysisDownloadButton() { const analysisDefinition = useSelector(getCurrentDefinition); const exposureAnalysisTableData = getExposureAnalysisTableData( - analysisResult?.tableData as TableRow[], + (analysisResult?.tableData || []) as TableRow[], exposureAnalysisResultSortByKey, exposureAnalysisResultSortOrder, );