Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add support for making maps from GPX files #1330

Merged
merged 9 commits into from
Nov 29, 2023
3 changes: 2 additions & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export const MAX_DESCRIPTION_LENGTH = 600;

export const MAP_DATA_ACCEPTED_TYPES_NAMES = [
'GeoJSON',
'GPX',
'JSON',
'KML',
'KMZ',
Expand All @@ -85,6 +86,7 @@ const getTypesExtensions = (types: Record<string, string[]>) =>

export const MAP_DATA_ACCEPTED_TYPES = {
'application/json': ['.json', '.geojson'],
'application/gpx': ['.gpx'],
'application/xml': ['.kml'],
'application/zip': ['.kmz', '.zip'],
};
Expand All @@ -111,7 +113,6 @@ export const DOCUMENT_ACCEPTED_TYPES = {
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': [
'.docx',
],
'application/xml': ['.gpx'],
};

export const MEDIA_ACCEPTED_TYPES = {
Expand Down
9 changes: 7 additions & 2 deletions src/gis/gisService.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ import _ from 'lodash/fp';
import logger from 'terraso-client-shared/monitoring/logger';
import * as terrasoApi from 'terraso-client-shared/terrasoApi/api';

import { isKmlFile, isShapefile, openGeoJsonFile } from 'gis/gisUtils';
import {
isGpxFile,
isKmlFile,
isShapefile,
openGeoJsonFile,
} from 'gis/gisUtils';

const generateUrl = name =>
`https://nominatim.openstreetmap.org/search.php?q=${name}&format=jsonv2`;
Expand Down Expand Up @@ -52,7 +57,7 @@ const sendFileToTerrasoApi = async file => {
};

export const parseFileToGeoJSON = async file => {
return isKmlFile(file) || isShapefile(file)
return isKmlFile(file) || isShapefile(file) || isGpxFile(file)
? sendFileToTerrasoApi(file)
: openGeoJsonFile(file);
};
2 changes: 2 additions & 0 deletions src/gis/gisUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import { isValidLatitude, isValidLongitude } from 'terraso-client-shared/utils';
// From: https://gis.stackexchange.com/a/303362
export const normalizeLongitude = lng => (((lng % 360) + 540) % 360) - 180;

export const isGpxFile = file => file.name.endsWith('.gpx');

export const isKmlFile = file =>
file.name.endsWith('.kml') || file.name.endsWith('.kmz');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,13 +189,13 @@ test('LandscapeNew: Save from GeoJSON', async () => {
await act(async () =>
fireEvent.click(
screen.getByRole('button', {
name: 'Upload a map file. Accepted file formats: GeoJSON, JSON, KML, KMZ, ESRI Shapefile',
name: 'Upload a map file. Accepted file formats: GeoJSON, GPX, JSON, KML, KMZ, ESRI Shapefile',
})
)
);

const dropzone = screen.getByRole('button', {
name: 'Select File Accepted file formats: *.geojson, *.json, *.kml, *.kmz, *.zip Maximum file size: 10 MB',
name: 'Select File Accepted file formats: *.geojson, *.gpx, *.json, *.kml, *.kmz, *.zip Maximum file size: 10 MB',
});

const file = new File([GEOJSON_STRING], 'test.json', {
Expand All @@ -219,7 +219,7 @@ test('LandscapeNew: Save from GeoJSON', async () => {
await waitFor(async () => {
expect(
await screen.findByRole('button', {
name: 'Select File Accepted file formats: *.geojson, *.json, *.kml, *.kmz, *.zip Maximum file size: 10 MB test.json 804 B',
name: 'Select File Accepted file formats: *.geojson, *.gpx, *.json, *.kml, *.kmz, *.zip Maximum file size: 10 MB test.json 804 B',
})
).toBeInTheDocument();
});
Expand Down
24 changes: 12 additions & 12 deletions src/landscape/components/LandscapeForm/BoundaryStepUpdate.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,13 @@ const testGeoJsonParsing = (file, errorMessage) => async () => {
await act(async () =>
fireEvent.click(
screen.getByRole('button', {
name: 'Upload a map file. Accepted file formats: GeoJSON, JSON, KML, KMZ, ESRI Shapefile',
name: 'Upload a map file. Accepted file formats: GeoJSON, GPX, JSON, KML, KMZ, ESRI Shapefile',
})
)
);

const dropzone = screen.getByRole('button', {
name: 'Select File Accepted file formats: *.geojson, *.json, *.kml, *.kmz, *.zip Maximum file size: 10 MB',
name: 'Select File Accepted file formats: *.geojson, *.gpx, *.json, *.kml, *.kmz, *.zip Maximum file size: 10 MB',
});

const data = {
Expand Down Expand Up @@ -246,13 +246,13 @@ test('LandscapeBoundaries: Select file', async () => {
await act(async () =>
fireEvent.click(
screen.getByRole('button', {
name: 'Upload a map file. Accepted file formats: GeoJSON, JSON, KML, KMZ, ESRI Shapefile',
name: 'Upload a map file. Accepted file formats: GeoJSON, GPX, JSON, KML, KMZ, ESRI Shapefile',
})
)
);

const dropzone = screen.getByRole('button', {
name: 'Select File Accepted file formats: *.geojson, *.json, *.kml, *.kmz, *.zip Maximum file size: 10 MB',
name: 'Select File Accepted file formats: *.geojson, *.gpx, *.json, *.kml, *.kmz, *.zip Maximum file size: 10 MB',
});

const file = new File([GEOJSON], 'test.json', { type: 'application/json' });
Expand All @@ -272,7 +272,7 @@ test('LandscapeBoundaries: Select file', async () => {
await act(async () => fireEvent.drop(dropzone, data));
expect(
await screen.findByRole('button', {
name: 'Select File Accepted file formats: *.geojson, *.json, *.kml, *.kmz, *.zip Maximum file size: 10 MB test.json 804 B',
name: 'Select File Accepted file formats: *.geojson, *.gpx, *.json, *.kml, *.kmz, *.zip Maximum file size: 10 MB test.json 804 B',
})
).toBeInTheDocument();
});
Expand All @@ -299,7 +299,7 @@ test('LandscapeBoundaries: Show back', async () => {
await act(async () =>
fireEvent.click(
screen.getByRole('button', {
name: 'Upload a map file. Accepted file formats: GeoJSON, JSON, KML, KMZ, ESRI Shapefile',
name: 'Upload a map file. Accepted file formats: GeoJSON, GPX, JSON, KML, KMZ, ESRI Shapefile',
})
)
);
Expand Down Expand Up @@ -355,13 +355,13 @@ test('LandscapeBoundaries: Save GeoJSON', async () => {
await act(async () =>
fireEvent.click(
screen.getByRole('button', {
name: 'Upload a map file. Accepted file formats: GeoJSON, JSON, KML, KMZ, ESRI Shapefile',
name: 'Upload a map file. Accepted file formats: GeoJSON, GPX, JSON, KML, KMZ, ESRI Shapefile',
})
)
);

const dropzone = screen.getByRole('button', {
name: 'Select File Accepted file formats: *.geojson, *.json, *.kml, *.kmz, *.zip Maximum file size: 10 MB',
name: 'Select File Accepted file formats: *.geojson, *.gpx, *.json, *.kml, *.kmz, *.zip Maximum file size: 10 MB',
});

const file = new File([GEOJSON], 'test.json', { type: 'application/json' });
Expand All @@ -381,7 +381,7 @@ test('LandscapeBoundaries: Save GeoJSON', async () => {
await act(async () => fireEvent.drop(dropzone, data));
expect(
await screen.findByRole('button', {
name: 'Select File Accepted file formats: *.geojson, *.json, *.kml, *.kmz, *.zip Maximum file size: 10 MB test.json 804 B',
name: 'Select File Accepted file formats: *.geojson, *.gpx, *.json, *.kml, *.kmz, *.zip Maximum file size: 10 MB test.json 804 B',
})
).toBeInTheDocument();

Expand Down Expand Up @@ -471,13 +471,13 @@ test('LandscapeBoundaries: Save KML', async () => {
await act(async () =>
fireEvent.click(
screen.getByRole('button', {
name: 'Upload a map file. Accepted file formats: GeoJSON, JSON, KML, KMZ, ESRI Shapefile',
name: 'Upload a map file. Accepted file formats: GeoJSON, GPX, JSON, KML, KMZ, ESRI Shapefile',
})
)
);

const dropzone = screen.getByRole('button', {
name: 'Select File Accepted file formats: *.geojson, *.json, *.kml, *.kmz, *.zip Maximum file size: 10 MB',
name: 'Select File Accepted file formats: *.geojson, *.gpx, *.json, *.kml, *.kmz, *.zip Maximum file size: 10 MB',
});

const dataTransfer = {
Expand All @@ -497,7 +497,7 @@ test('LandscapeBoundaries: Save KML', async () => {
await waitFor(async () => {
expect(
screen.getByRole('button', {
name: 'Select File Accepted file formats: *.geojson, *.json, *.kml, *.kmz, *.zip Maximum file size: 10 MB valid.kml 406 B',
name: 'Select File Accepted file formats: *.geojson, *.gpx, *.json, *.kml, *.kmz, *.zip Maximum file size: 10 MB valid.kml 406 B',
})
).toBeInTheDocument();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const TEST_KML = `
<kml xmlns="http://www.opengis.net/kml/2.2">
<Placemark>
<name>Simple placemark</name>
<description>Attached to the ground. Intelligently places itself
<description>Attached to the ground. Intelligently places itself
at the height of the underlying terrain.</description>
<Point>
<coordinates>-122.0822035425683,37.42228990140251,0</coordinates>
Expand All @@ -61,23 +61,23 @@ const TEST_KML = `
<outerBoundaryIs>
<LinearRing>
<coordinates>
-77.05788457660967,38.87253259892824,100
-77.05465973756702,38.87291016281703,100
-77.05315536854791,38.87053267794386,100
-77.05552622493516,38.868757801256,100
-77.05844056290393,38.86996206506943,100
-77.05788457660967,38.87253259892824,100
-77.05465973756702,38.87291016281703,100
-77.05315536854791,38.87053267794386,100
-77.05552622493516,38.868757801256,100
-77.05844056290393,38.86996206506943,100
-77.05788457660967,38.87253259892824,100
</coordinates>
</LinearRing>
</outerBoundaryIs>
<innerBoundaryIs>
<LinearRing>
<coordinates>
-77.05668055019126,38.87154239798456,100
-77.05542625960818,38.87167890344077,100
-77.05485125901024,38.87076535397792,100
-77.05577677433152,38.87008686581446,100
-77.05691162017543,38.87054446963351,100
-77.05668055019126,38.87154239798456,100
-77.05542625960818,38.87167890344077,100
-77.05485125901024,38.87076535397792,100
-77.05577677433152,38.87008686581446,100
-77.05691162017543,38.87054446963351,100
-77.05668055019126,38.87154239798456,100
</coordinates>
</LinearRing>
Expand Down Expand Up @@ -579,6 +579,7 @@ test.each([
expectedDataEntriesFetchInput: {
resourceTypes: [
'geojson',
'gpx',
'json',
'kml',
'kmz',
Expand Down Expand Up @@ -651,6 +652,7 @@ test.each([
expectedDataEntriesFetchInput: {
resourceTypes: [
'geojson',
'gpx',
'json',
'kml',
'kmz',
Expand Down
Loading