mirror of
https://github.com/nowcommunity/nowdatabase.git
synced 2026-10-12 19:13:52 +03:00
Add occurrence table map exports
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { useMemo } from 'react'
|
||||
import { type MRT_ColumnDef } from 'material-react-table'
|
||||
import { type MRT_ColumnDef, type MRT_RowData, type MRT_TableInstance } from 'material-react-table'
|
||||
import { CrossSearch, formatDevelopmentalCrownType } from '@/shared/types'
|
||||
import { TableView } from '../TableView/TableView'
|
||||
import type { ColumnVisibilityGroup } from '../TableView/TableToolBar'
|
||||
@@ -12,6 +12,9 @@ import { OccurrenceDwcExportMenuItem } from '@/components/Occurrence/OccurrenceD
|
||||
import { OccurrenceDwcDpExportMenuItem } from '@/components/Occurrence/OccurrenceDwcDpExportMenuItem'
|
||||
import { OccurrenceFullDarwinCoreExportMenuItem } from '@/components/Occurrence/OccurrenceFullDarwinCoreExportMenuItem'
|
||||
import { matchesCountryOrContinent } from '@/shared/validators/countryContinents'
|
||||
import { generateKml } from '@/util/kml'
|
||||
import { currentDateAsString } from '@/shared/currentDateAsString'
|
||||
import { getUniqueCrossSearchMapExportLocalities } from '@/components/Species/localitySpeciesMapExport'
|
||||
|
||||
export const CrossSearchTable = ({ selectorFn }: { selectorFn?: (newObject: CrossSearch) => void }) => {
|
||||
const { sqlLimit, sqlOffset, sqlColumnFilters, sqlOrderBy } = usePageContext()
|
||||
@@ -1072,6 +1075,32 @@ export const CrossSearchTable = ({ selectorFn }: { selectorFn?: (newObject: Cros
|
||||
return !!row.loc_status
|
||||
}
|
||||
|
||||
const getExportLocalities = <T extends MRT_RowData>(table: MRT_TableInstance<T>) => {
|
||||
const rows = table.getPrePaginationRowModel().rows.map(row => row.original as unknown as CrossSearch)
|
||||
return getUniqueCrossSearchMapExportLocalities(rows)
|
||||
}
|
||||
|
||||
const kmlExport = <T extends MRT_RowData>(table: MRT_TableInstance<T>) => {
|
||||
const dataString = generateKml(getExportLocalities(table))
|
||||
const blob = new Blob([dataString], { type: 'text/kml' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = `occurrences-${currentDateAsString()}.kml`
|
||||
a.click()
|
||||
}
|
||||
|
||||
const svgExport = async <T extends MRT_RowData>(table: MRT_TableInstance<T>) => {
|
||||
const { generateSvg } = await import('@/components/Map/generateSvg')
|
||||
const dataString = generateSvg(getExportLocalities(table))
|
||||
const blob = new Blob([dataString], { type: 'image/svg+xml' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = `occurrences-map-${currentDateAsString()}.svg`
|
||||
a.click()
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<LocalitiesMap localities={localitiesData} isFetching={localitiesFetching || isFetching} />
|
||||
@@ -1090,6 +1119,8 @@ export const CrossSearchTable = ({ selectorFn }: { selectorFn?: (newObject: Cros
|
||||
enableColumnFilterModes={true}
|
||||
serverSidePagination={true}
|
||||
isCrossSearchTable={true}
|
||||
kmlExport={kmlExport}
|
||||
svgExport={svgExport}
|
||||
isError={isError}
|
||||
error={error}
|
||||
renderExtraExportMenuItems={handleClose => (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Locality, LocalityDetailsType, LocalitySpecies, SpeciesLocality } from '@/shared/types'
|
||||
import type { CrossSearch, Locality, LocalityDetailsType, LocalitySpecies, SpeciesLocality } from '@/shared/types'
|
||||
|
||||
type SpeciesSource = {
|
||||
species_id?: number | null
|
||||
@@ -121,3 +121,38 @@ export const getUniqueOccurrenceMapExportLocalities = (
|
||||
|
||||
return [exportLocality]
|
||||
}
|
||||
|
||||
export const getUniqueCrossSearchMapExportLocalities = (rows: CrossSearch[]): MapExportLocality[] => {
|
||||
const localitiesById = new Map<number, MapExportLocality>()
|
||||
|
||||
rows.forEach(row => {
|
||||
const locality = toMapExportLocality({
|
||||
lid: row.lid_now_loc,
|
||||
loc_name: row.loc_name,
|
||||
country: row.country,
|
||||
dms_lat: row.dms_lat,
|
||||
dms_long: row.dms_long,
|
||||
dec_lat: row.dec_lat,
|
||||
dec_long: row.dec_long,
|
||||
bfa_max: row.bfa_max,
|
||||
bfa_min: row.bfa_min,
|
||||
max_age: row.max_age,
|
||||
min_age: row.min_age,
|
||||
altitude: row.altitude,
|
||||
appr_num_spm: row.appr_num_spm,
|
||||
})
|
||||
|
||||
if (!locality) return
|
||||
|
||||
const exportLocality = localitiesById.get(locality.lid) ?? locality
|
||||
addSpecies(exportLocality, {
|
||||
species_id: row.species_id_com_species,
|
||||
genus_name: row.genus_name,
|
||||
species_name: row.species_name,
|
||||
unique_identifier: row.unique_identifier,
|
||||
})
|
||||
localitiesById.set(locality.lid, exportLocality)
|
||||
})
|
||||
|
||||
return [...localitiesById.values()]
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import { describe, expect, it } from '@jest/globals'
|
||||
|
||||
import {
|
||||
getUniqueCrossSearchMapExportLocalities,
|
||||
getUniqueOccurrenceMapExportLocalities,
|
||||
getUniqueSpeciesLocalityMapExportLocalities,
|
||||
toMapExportLocality,
|
||||
} from '@/components/Species/localitySpeciesMapExport'
|
||||
import { generateKml } from '@/util/kml'
|
||||
import type { LocalityDetailsType, LocalitySpecies, SpeciesLocality } from '@/shared/types'
|
||||
import type { CrossSearch, LocalityDetailsType, LocalitySpecies, SpeciesLocality } from '@/shared/types'
|
||||
|
||||
const crossSearch = (overrides: unknown): CrossSearch => overrides as CrossSearch
|
||||
const speciesLocality = (overrides: unknown): SpeciesLocality => overrides as SpeciesLocality
|
||||
const localitySpecies = (overrides: unknown): LocalitySpecies => overrides as LocalitySpecies
|
||||
const locality = (overrides: unknown): LocalityDetailsType => overrides as LocalityDetailsType
|
||||
@@ -103,6 +105,47 @@ describe('locality species map export helpers', () => {
|
||||
expect(result[0]?.species).toEqual(['Ursus arctos', 'Vulpes vulpes'])
|
||||
})
|
||||
|
||||
it('groups cross-search occurrence rows by locality with species names', () => {
|
||||
const result = getUniqueCrossSearchMapExportLocalities([
|
||||
crossSearch({
|
||||
lid_now_loc: 1,
|
||||
loc_name: 'A',
|
||||
country: 'Finland',
|
||||
dec_lat: 1,
|
||||
dec_long: 2,
|
||||
species_id_com_species: 100,
|
||||
genus_name: 'Ursus',
|
||||
species_name: 'arctos',
|
||||
unique_identifier: '-',
|
||||
}),
|
||||
crossSearch({
|
||||
lid_now_loc: 1,
|
||||
loc_name: 'A',
|
||||
country: 'Finland',
|
||||
dec_lat: 1,
|
||||
dec_long: 2,
|
||||
species_id_com_species: 101,
|
||||
genus_name: 'Vulpes',
|
||||
species_name: 'vulpes',
|
||||
unique_identifier: null,
|
||||
}),
|
||||
crossSearch({
|
||||
lid_now_loc: 2,
|
||||
loc_name: 'B',
|
||||
country: 'Sweden',
|
||||
dec_lat: null,
|
||||
dec_long: 2,
|
||||
species_id_com_species: 102,
|
||||
genus_name: 'Alces',
|
||||
species_name: 'alces',
|
||||
}),
|
||||
])
|
||||
|
||||
expect(result).toHaveLength(1)
|
||||
expect(result[0]).toMatchObject({ lid: 1, loc_name: 'A', country: 'Finland' })
|
||||
expect(result[0]?.species).toEqual(['Ursus arctos', 'Vulpes vulpes'])
|
||||
})
|
||||
|
||||
it('writes species lists into KML descriptions when provided', () => {
|
||||
const exportLocality = toMapExportLocality({
|
||||
lid: 1,
|
||||
|
||||
Reference in New Issue
Block a user