Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into feat/active-projec…
Browse files Browse the repository at this point in the history
…ts-api-for-export-tool
  • Loading branch information
kshitijrajsharma committed Jan 8, 2024
2 parents 4d59f9c + ae66919 commit c3f5aca
Show file tree
Hide file tree
Showing 24 changed files with 1,956 additions and 480 deletions.
13 changes: 13 additions & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# These are supported funding model platforms

github: hotosm
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
5 changes: 5 additions & 0 deletions example.env
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,8 @@ TM_DEFAULT_LOCALE=en
# Sentry.io DSN Config (optional)
# TM_SENTRY_BACKEND_DSN=https://foo.ingest.sentry.io/1234567
# TM_SENTRY_FRONTEND_DSN=https://bar.ingest.sentry.io/8901234


#EXPORT TOOL Integration with 0(Disable) and 1(Enable) and S3 URL for Export Tool
#EXPORT_TOOL_S3_URL=https://foorawdataapi.s3.amazonaws.com
#ENABLE_EXPORT_TOOL=0
2 changes: 2 additions & 0 deletions frontend/.env.expand
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,5 @@ REACT_APP_SENTRY_FRONTEND_DSN=$TM_SENTRY_FRONTEND_DSN
REACT_APP_ENVIRONMENT=$TM_ENVIRONMENT
REACT_APP_TM_DEFAULT_CHANGESET_COMMENT=$TM_DEFAULT_CHANGESET_COMMENT
REACT_APP_RAPID_EDITOR_URL=$RAPID_EDITOR_URL
REACT_APP_EXPORT_TOOL_S3_URL=$EXPORT_TOOL_S3_URL
REACT_APP_ENABLE_EXPORT_TOOL=$ENABLE_EXPORT_TOOL
17 changes: 10 additions & 7 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"@mapbox/mapbox-gl-geocoder": "^5.0.1",
"@mapbox/mapbox-gl-language": "^0.10.1",
"@placemarkio/geo-viewport": "^1.0.1",
"@rapideditor/rapid": "^2.1.1",
"@sentry/react": "^7.60.1",
"@tmcw/togeojson": "^4.7.0",
"@tanstack/react-query": "^4.29.7",
Expand All @@ -27,7 +28,6 @@
"@turf/transform-scale": "^6.5.0",
"@turf/truncate": "^6.5.0",
"@uiw/react-md-editor": "^3.22.0",
"RapiD": "facebookincubator/rapid#rapid-v1.1.9-tm.1",
"axios": "^1.4.0",
"chart.js": "^3.7.1",
"chartjs-adapter-date-fns": "^3.0.0",
Expand Down Expand Up @@ -81,8 +81,8 @@
},
"scripts": {
"build-locales": "combine-messages -i './src/**/messages.js' -o './src/locales/en.json'",
"copy-static": "bash -c \"mkdir -p public/static/id; mkdir -p public/static/rapid; if ! (test -a public/static/id/index.js); then cp -R node_modules/@hotosm/id/dist/* public/static/id; fi; if ! (test -a public/static/rapid/index.js); then if ! (test -a node_modules/RapiD/dist/RapiD.css) then mv node_modules/RapiD/dist/iD.css node_modules/RapiD/dist/RapiD.css; fi; cp -R node_modules/RapiD/dist/* public/static/rapid; fi\"",
"update-static": "bash -c \"mkdir -p public/static/id; mkdir -p public/static/rapid; cp -R node_modules/@hotosm/id/dist/* public/static/id; if ! (test -a node_modules/RapiD/dist/RapiD.css) then mv node_modules/RapiD/dist/iD.css node_modules/RapiD/dist/RapiD.css; fi; cp -R node_modules/RapiD/dist/* public/static/rapid;\"",
"copy-static": "bash -c \"mkdir -p public/static/id; mkdir -p public/static/rapid; if ! (test -a public/static/id/index.js); then cp -R node_modules/@hotosm/id/dist/* public/static/id; fi; if ! (test -a public/static/rapid/rapid.js); then cp -R node_modules/@rapideditor/rapid/dist/* public/static/rapid; fi\"",
"update-static": "bash -c \"mkdir -p public/static/id; mkdir -p public/static/rapid; cp -R node_modules/@hotosm/id/dist/* public/static/id; cp -R node_modules/@rapideditor/rapid/dist/* public/static/rapid;\"",
"patch-id": "bash -c \"cp patch/imagery.min.json public/static/id/data\"",
"patch-rapid": "bash -c \"cp patch/rapid-imagery.min.json public/static/rapid/data/imagery.min.json\"",
"preparation": "bash -c \"if (test -a ../tasking-manager.env); then grep -hs ^ ../tasking-manager.env .env.expand > .env; else cp .env.expand .env; fi\"",
Expand All @@ -93,7 +93,7 @@
"test": "npm run lint && react-scripts test --env=jsdom",
"coverage": "npm run test -- --coverage --watchAll=false",
"analyze": "source-map-explorer 'build/static/js/*.js'",
"sentry:sourcemaps": "sentry-cli sourcemaps inject --org humanitarian-openstreetmap-tea --project taskingmanager-frontend ./build && sentry-cli sourcemaps upload --org humanitarian-openstreetmap-tea --project taskingmanager-frontend ./build"
"sentry:sourcemaps": "if sentry-cli info; then sentry-cli sourcemaps inject --org humanitarian-openstreetmap-tea --project taskingmanager-frontend ./build && sentry-cli sourcemaps upload --org humanitarian-openstreetmap-tea --project taskingmanager-frontend ./build; fi"
},
"eslintConfig": {
"extends": "react-app"
Expand All @@ -112,6 +112,7 @@
},
"devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@sentry/cli": "^2.20.5",
"@tanstack/eslint-plugin-query": "^4.29.8",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^12.1.5",
Expand All @@ -123,8 +124,7 @@
"prettier": "^2.8.8",
"react-select-event": "^5.5.1",
"react-test-renderer": "^17.0.2",
"source-map-explorer": "^2.5.3",
"@sentry/cli": "^2.20.5"
"source-map-explorer": "^2.5.3"
},
"jest": {
"coverageReporters": [
Expand All @@ -133,5 +133,8 @@
"transformIgnorePatterns": [
"node_modules/@uiw/react-md-editor/"
]
},
"volta": {
"node": "16.20.0"
}
}
}
2 changes: 1 addition & 1 deletion frontend/patch/rapid-imagery.min.json

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions frontend/src/assets/styles/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,17 @@
@import 'learn';
@import 'notifications';
@import 'contributions';

.fade-in {
opacity: 0;
transition: opacity 0.5s ease-in;
}

.fade-in.active {
opacity: 1;
}

.categorycard:hover > svg *,
.categorycard:hover {
fill: #d73f3f;
}
231 changes: 231 additions & 0 deletions frontend/src/components/projectDetail/downloadOsmData.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { RoadIcon, HomeIcon, WavesIcon, TaskIcon, DownloadIcon } from '../svgIcons';
import FileFormatCard from './fileFormatCard';
import Popup from 'reactjs-popup';
import { EXPORT_TOOL_S3_URL } from '../../config';
import messages from './messages';
import { FormattedMessage } from 'react-intl';

export const TITLED_ICONS = [
{
Icon: RoadIcon,
title: 'roads',
value: 'ROADS',
featuretype: ['lines'],
formats: ['geojson', 'shp', 'kml'],
},
{
Icon: HomeIcon,
title: 'buildings',
value: 'BUILDINGS',
featuretype: ['polygons'],
formats: ['geojson', 'shp', 'kml'],
},
{
Icon: WavesIcon,
title: 'waterways',
value: 'WATERWAYS',
featuretype: ['lines', 'polygons'],
formats: ['geojson', 'shp', 'kml'],
},
{
Icon: TaskIcon,
title: 'landuse',
value: 'LAND_USE',
featuretype: ['points', 'polygons'],
formats: ['geojson', 'shp', 'kml'],
},
];

/**
* Renders a list of download options for OSM data based on the project mapping types.
*
* @param {Array<string>} projectMappingTypes - The mapping types of the project.
* @return {JSX.Element} - The JSX element containing the download options.
*/

export const DownloadOsmData = ({ projectMappingTypes, project }) => {
const [showPopup, setShowPopup] = useState(false);
const [isDownloadingState, setIsDownloadingState] = useState(null);
const [selectedCategoryFormat, setSelectedCategoryFormat] = useState(null);

const datasetConfig = {
dataset_prefix: `hotosm_project_${project.projectId}`,
dataset_folder: 'TM',
dataset_title: `Tasking Manger Project ${project.projectId}`,
};
/**
* Downloads an S3 file from the given URL and saves it as a file.
*
* @param {string} title - The title of the file.
* @param {string} fileFormat - The format of the file.
* @param {string} feature_type - The feature type of the ffile.
* @return {Promise<void>} Promise that resolves when the download is complete.
*/
const downloadS3File = async (title, fileFormat, feature_type) => {
// Create the base URL for the S3 file
const baseUrl = `${EXPORT_TOOL_S3_URL}/${datasetConfig.dataset_folder}/${
datasetConfig.dataset_prefix
}/${title}/${feature_type}/${
datasetConfig.dataset_prefix
}_${title}_${feature_type}_${fileFormat.toLowerCase()}.zip`;

// Set the state to indicate that the file download is in progress
setIsDownloadingState({ title: title, fileFormat: fileFormat, isDownloading: true });

try {
// Fetch the file from the S3 URL
const response = await fetch(baseUrl);

// Check if the request was successful
if (response.ok) {
// Get the file data as a blob
const blob = await response.blob();

// Create a download link for the file
const href = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = href;
link.setAttribute(
'download',
`hotosm_project_${
project.projectId
}_${title}_${feature_type}_${fileFormat?.toLowerCase()}.zip`,
);

// Add the link to the document body, click it, and then remove it
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
// Set the state to indicate that the file download is complete
setIsDownloadingState({ title: title, fileFormat: fileFormat, isDownloading: false });
} else {
// Show a popup and throw an error if the request was not successful
setShowPopup(true);
throw new Error(`Request failed with status: ${response.status}`);
}
} catch (error) {
// Show a popup and log the error if an error occurs during the download
setShowPopup(true);
setIsDownloadingState({ title: title, fileFormat: fileFormat, isDownloading: false });
console.error('Error:', error.message);
}
};
const filteredMappingTypes = TITLED_ICONS?.filter((icon) =>
projectMappingTypes?.includes(icon.value),
);
return (
<div className="mb5 w-100 pb5 ph4 flex flex-wrap">
<Popup modal open={showPopup} closeOnDocumentClick nested onClose={() => setShowPopup(false)}>
{(close) => (
<div className="blue-dark bg-white pv2 pv4-ns ph2 ph4-ns">
<h3 className="barlow-condensed f3 fw6 mv0">
<FormattedMessage {...messages.errorDownloadOsmData} />
</h3>
<p className="mt4">
<FormattedMessage {...messages.errorDownloadOsmDataDescription} />
</p>
<div className="w-100 pt3 flex justify-end">
<button
aria-pressed="false"
tabIndex={0}
className="mr2 bg-red white br1 f5 bn pointer"
style={{ padding: '0.75rem 1.5rem' }}
onClick={() => {
setShowPopup(false);
close();
}}
>
Close
</button>
</div>
</div>
)}
</Popup>
{filteredMappingTypes.map((type) => (
<div
className="osm-card bg-white pa3 mr4 mt4 w-auto-m flex flex-wrap items-center "
style={{
width: '560px',
gap: '16px',
}}
key={type.title}
>
<div
style={{
justifyContent: 'center',
display: 'flex',
alignItems: 'center',
}}
>
<type.Icon
title={type.title}
color="#D73F3F"
className="br1 h2 w2 pa1 ma1 ba b--white bw1 dib h-65 w-65"
style={{ height: '56px' }}
/>
</div>
<div className="flex-column">
<div
className="file-list flex barlow-condensed f3"
style={{ display: 'flex', gap: '12px' }}
>
<p className="fw5 ttc">{type.title}</p>
<FileFormatCard
title={type.title}
fileFormats={type.formats}
downloadS3Data={downloadS3File}
isDownloadingState={isDownloadingState}
selectedCategoryFormat={selectedCategoryFormat}
setSelectedCategoryFormat={setSelectedCategoryFormat}
/>
</div>
<div
className={`flex flex-row ${
selectedCategoryFormat && selectedCategoryFormat.title === type.title
? 'fade-in active'
: 'fade-in'
} `}
style={{ gap: '20px' }}
>
{selectedCategoryFormat &&
selectedCategoryFormat.title === type.title &&
type?.featuretype?.map((typ) => (
<span
key={`${typ}_${selectedCategoryFormat.title}`}
onClick={() =>
downloadS3File(
selectedCategoryFormat.title,
selectedCategoryFormat.format,
typ,
)
}
onKeyUp={() =>
downloadS3File(
selectedCategoryFormat.title,
selectedCategoryFormat.format,
typ,
)
}
className="flex flex-row items-center pointer link hover-red color-inherit categorycard"
style={{ gap: '10px' }}
>
<DownloadIcon style={{ height: '28px' }} color="#D73F3F" />
<p className="ttc">
{typ} {selectedCategoryFormat.format}
</p>
</span>
))}
</div>
</div>
</div>
))}
</div>
);
};

DownloadOsmData.propTypes = {
projectMappingTypes: PropTypes.arrayOf(PropTypes.string).isRequired,
project: PropTypes.objectOf(PropTypes.any).isRequired,
};
Loading

0 comments on commit c3f5aca

Please sign in to comment.