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

Fix editable vector layer #1102

Merged
merged 21 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e7f60da
fix: backend import error fix
NSUWAL123 Jan 9, 2024
73c06aa
fix (vectorLayer): style - conditionaly apply style on onModify present
NSUWAL123 Jan 9, 2024
9d45249
fix (splitTasks): map - edit added to splitted taskLayer
NSUWAL123 Jan 9, 2024
0676190
Merge branch 'development' of github.com:hotosm/fmtm into fix-editabl…
NSUWAL123 Jan 9, 2024
ba154f1
fix (splitTasks): onModify - edited geojson set to dividedTaskGeojson…
NSUWAL123 Jan 9, 2024
49c7415
Merge branch 'development' of github.com:hotosm/fmtm into fix-editabl…
NSUWAL123 Jan 11, 2024
f3140d4
feat (createNewProject): only enable generate task btn if fgb file fe…
NSUWAL123 Jan 11, 2024
937ae6a
fix (createNewProject): splitTasks - logic fix
NSUWAL123 Jan 11, 2024
55ec79c
fix (createNewProject): splitTasks - clear dividedTaskGeojson, splitT…
NSUWAL123 Jan 11, 2024
df682b7
feat (createNewProject): splitTasks - show loader and message until F…
NSUWAL123 Jan 11, 2024
b7f105c
fix (createNewProject): taskSplit - display error on taskSplit fail
NSUWAL123 Jan 11, 2024
4214f92
fix vectorLayer: on modifyEnd return area of boundary as well
NSUWAL123 Jan 11, 2024
6a615bd
fix button: loading text added to the button
NSUWAL123 Jan 12, 2024
2e5b408
fix NewDefineAreaMap: removed data extraction in progress message fro…
NSUWAL123 Jan 12, 2024
d1fc838
fix (createNewProject): splitTasks - clearing state on step toggle re…
NSUWAL123 Jan 12, 2024
c189ab3
fix (createNewProject): uploadArea - clear step4 & step5 step on AOI …
NSUWAL123 Jan 12, 2024
fddb17a
fix (createNewProject): dataExtract - generateTaskBTN added, disable …
NSUWAL123 Jan 12, 2024
7ba2362
fix (createNewProject): dataExtract - clear file state on reset click…
NSUWAL123 Jan 12, 2024
d42fe8d
fix (createNewProject): customLine, customPolygon file state clear on…
NSUWAL123 Jan 12, 2024
563c588
fix (createNewProject): dataExtract - clear previous extractGeojson, …
NSUWAL123 Jan 16, 2024
f6eecf1
Merge branch 'development' of github.com:hotosm/fmtm into fix-editabl…
NSUWAL123 Jan 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/frontend/src/api/CreateProjectService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,14 @@ const TaskSplittingPreviewService: Function = (
dispatch(CreateProjectActions.SetIsTasksGenerated({ key: 'task_splitting_algorithm', value: true }));
dispatch(CreateProjectActions.GetTaskSplittingPreview(resp));
} catch (error) {
dispatch(
CommonActions.SetSnackBar({
open: true,
message: 'Task generation failed. Please try again',
variant: 'error',
duration: 2000,
}),
);
dispatch(CreateProjectActions.GetTaskSplittingPreviewLoading(false));
} finally {
dispatch(CreateProjectActions.GetTaskSplittingPreviewLoading(false));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,10 @@ const VectorLayer = ({
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857',
});
const geometry = vectorLayer.getSource().getFeatures()?.[0].getGeometry();
const area = formatArea(geometry);

onModify(geoJSONString);
onModify(geoJSONString, area);
});
map.addInteraction(modify);
map.addInteraction(select);
Expand Down Expand Up @@ -191,22 +193,26 @@ const VectorLayer = ({

useEffect(() => {
if (!vectorLayer || !style.visibleOnMap || setStyle) return;
vectorLayer.setStyle((feature, resolution) => [
new Style({
image: new CircleStyle({
radius: 5,
fill: new Fill({
color: 'orange',
}),
}),
geometry: function (feature) {
// return the coordinates of the first ring of the polygon
const coordinates = feature.getGeometry().getCoordinates()[0];
return new MultiPoint(coordinates);
},
}),
getStyles({ style, feature, resolution }),
]);
vectorLayer.setStyle((feature, resolution) => {
return onModify
? [
new Style({
image: new CircleStyle({
radius: 5,
fill: new Fill({
color: 'orange',
}),
}),
geometry: function (feature) {
// return the coordinates of the first ring of the polygon
const coordinates = feature.getGeometry().getCoordinates()[0];
return new MultiPoint(coordinates);
},
}),
getStyles({ style, feature, resolution }),
]
: [getStyles({ style, feature, resolution })];
});
}, [vectorLayer, style, setStyle]);

useEffect(() => {
Expand Down Expand Up @@ -254,7 +260,6 @@ const VectorLayer = ({
});
function pointerMovefn(event) {
vectorLayer.getFeatures(event.pixel).then((features) => {
console.log(selection, 'selection');
if (!features.length) {
selection = {};
hoverEffect(undefined, vectorLayer);
Expand Down
19 changes: 16 additions & 3 deletions src/frontend/src/components/common/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ interface IButton {
icon?: React.ReactNode;
isLoading?: boolean;
disabled?: boolean;
loadingText?: string;
}

const btnStyle = (btnType, className) => {
Expand All @@ -24,13 +25,25 @@ const btnStyle = (btnType, className) => {
case 'other':
return `fmtm-py-1 fmtm-px-5 fmtm-bg-red-500 fmtm-text-white fmtm-rounded-lg hover:fmtm-bg-red-600`;
case 'disabled':
return `fmtm-py-1 fmtm-px-4 fmtm-text-white fmtm-rounded-lg fmtm-bg-gray-400 fmtm-cursor-not-allowed`;
return `fmtm-py-1 fmtm-px-4 fmtm-text-white fmtm-rounded-lg fmtm-bg-gray-400 fmtm-cursor-not-allowed ${className}`;

default:
return 'fmtm-primary';
}
};
const Button = ({ btnText, btnType, type, onClick, disabled, className, count, dataTip, icon, isLoading }: IButton) => (
const Button = ({
btnText,
btnType,
type,
onClick,
disabled,
className,
count,
dataTip,
icon,
isLoading,
loadingText,
}: IButton) => (
<div className="fmtm-w-fit">
<button
type={type === 'submit' ? 'submit' : 'button'}
Expand All @@ -44,7 +57,7 @@ const Button = ({ btnText, btnType, type, onClick, disabled, className, count, d
>
{isLoading ? (
<>
{type === 'submit' ? 'Submitting...' : 'Loading...'}
{type === 'submit' ? 'Submitting...' : loadingText ? loadingText : 'Loading...'}
<Loader2 className="fmtm-mr-2 fmtm-h-6 fmtm-w-6 fmtm-animate-spin" />
</>
) : (
Expand Down
153 changes: 131 additions & 22 deletions src/frontend/src/components/createnewproject/DataExtract.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import axios from 'axios';
import { geojson as fgbGeojson } from 'flatgeobuf';
import React, { useEffect } from 'react';
import React, { useEffect, useState } from 'react';
import Button from '../../components/common/Button';
import { useDispatch } from 'react-redux';
import { CommonActions } from '../../store/slices/CommonSlice';
Expand All @@ -25,27 +25,66 @@ const osmFeatureTypeOptions = [
{ name: 'osm_feature_type', value: 'polygon', label: 'Polygon' },
];

enum FeatureTypeName {
point_centroid = 'Point/Centroid',
line = 'Line',
polygon = 'Polygon',
}

const DataExtract = ({ flag, customLineUpload, setCustomLineUpload, customPolygonUpload, setCustomPolygonUpload }) => {
const dispatch = useDispatch();
const navigate = useNavigate();

const [extractWays, setExtractWays] = useState('');
const [featureType, setFeatureType] = useState('');
const projectDetails: any = useAppSelector((state) => state.createproject.projectDetails);
const drawnGeojson = useAppSelector((state) => state.createproject.drawnGeojson);
const dataExtractGeojson = useAppSelector((state) => state.createproject.dataExtractGeojson);
const isFgbFetching = useAppSelector((state) => state.createproject.isFgbFetching);

const submission = () => {
if (featureType !== formValues?.dataExtractFeatureType && formValues.dataExtractWays === 'osm_data_extract') {
dispatch(
CommonActions.SetSnackBar({
open: true,
message: `Please generate data extract for ${FeatureTypeName[featureType]}`,
variant: 'warning',
duration: 2000,
}),
);
return;
}

const submission = async () => {
dispatch(CreateProjectActions.SetIndividualProjectDetailsData(formValues));
dispatch(CommonActions.SetCurrentStepFormStep({ flag: flag, step: 5 }));

// First go to next page, to not block UX
navigate('/split-tasks');
};

const resetFile = (setDataExtractToState) => {
setDataExtractToState(null);
};

const {
handleSubmit,
handleCustomChange,
values: formValues,
errors,
}: any = useForm(projectDetails, submission, DataExtractValidation);

// Generate OSM data extract
const generateDataExtract = async () => {
// Get OSM data extract if required
if (formValues.dataExtractWays === 'osm_data_extract') {
if (extractWays === 'osm_data_extract') {
// Remove current data extract
dispatch(CreateProjectActions.setDataExtractGeojson(null));

// Create a file object from the project area Blob
const projectAreaBlob = new Blob([JSON.stringify(drawnGeojson)], { type: 'application/json' });
const drawnGeojsonFile = new File([projectAreaBlob], 'outline.json', { type: 'application/json' });

dispatch(CreateProjectActions.SetFgbFetchingStatus(true));
// Create form and POST endpoint
const dataExtractRequestFormData = new FormData();
dataExtractRequestFormData.append('geojson_file', drawnGeojsonFile);
Expand All @@ -56,9 +95,16 @@ const DataExtract = ({ flag, customLineUpload, setCustomLineUpload, customPolygo
);

const fgbUrl = response.data.url;
// Append url to project data
// Append url to project data & remove custom files
dispatch(
CreateProjectActions.SetIndividualProjectDetailsData({ ...projectDetails, data_extract_type: fgbUrl }),
CreateProjectActions.SetIndividualProjectDetailsData({
...formValues,
data_extract_type: fgbUrl,
dataExtractWays: extractWays,
dataExtractFeatureType: featureType,
customLineUpload: null,
customPolygonUpload: null,
}),
);

// Extract fgb and set geojson to map
Expand All @@ -67,21 +113,43 @@ const DataExtract = ({ flag, customLineUpload, setCustomLineUpload, customPolygo
const uint8ArrayData = new Uint8Array(binaryData);
// Deserialize the binary data
const geojsonExtract = await fgbGeojson.deserialize(uint8ArrayData);
dispatch(CreateProjectActions.SetFgbFetchingStatus(false));
await dispatch(CreateProjectActions.setDataExtractGeojson(geojsonExtract));
} catch (error) {
dispatch(
CommonActions.SetSnackBar({
open: true,
message: 'Error to generate FGB file.',
variant: 'error',
duration: 2000,
}),
);
dispatch(CreateProjectActions.SetFgbFetchingStatus(false));
// TODO add error message for user
console.error('Error getting data extract:', error);
}
}
};
const {
handleSubmit,
handleCustomChange,
values: formValues,
errors,
}: any = useForm(projectDetails, submission, DataExtractValidation);

useEffect(() => {
if (formValues?.dataExtractWays) {
setExtractWays(formValues?.dataExtractWays);
}
if (formValues?.dataExtractFeatureType) {
setFeatureType(formValues?.dataExtractFeatureType);
}
}, [formValues?.dataExtractWays, formValues?.dataExtractFeatureType]);

const toggleStep = (step, url) => {
if (url === '/select-form') {
dispatch(
CreateProjectActions.SetIndividualProjectDetailsData({
...formValues,
dataExtractWays: extractWays,
dataExtractFeatureType: featureType,
}),
);
}
dispatch(CommonActions.SetCurrentStepFormStep({ flag: flag, step: step }));
navigate(url);
};
Expand Down Expand Up @@ -137,10 +205,6 @@ const DataExtract = ({ flag, customLineUpload, setCustomLineUpload, customPolygo
await dispatch(CreateProjectActions.setDataExtractGeojson(extractFeatCol));
};

const resetFile = (setDataExtractToState) => {
setDataExtractToState(null);
};

useEffect(() => {
dispatch(FormCategoryService(`${import.meta.env.VITE_API_URL}/central/list-forms`));
}, []);
Expand Down Expand Up @@ -179,31 +243,59 @@ const DataExtract = ({ flag, customLineUpload, setCustomLineUpload, customPolygo
value={formValues.dataExtractWays}
onChangeData={(value) => {
handleCustomChange('dataExtractWays', value);
setExtractWays(value);
}}
errorMsg={errors.dataExtractWays}
/>
{formValues.dataExtractWays === 'osm_data_extract' && (
{extractWays === 'osm_data_extract' && (
<div className="fmtm-mt-6">
<RadioButton
topic="Select OSM feature type"
options={osmFeatureTypeOptions}
direction="column"
value={formValues.dataExtractFeatureType}
value={featureType}
onChangeData={(value) => {
handleCustomChange('dataExtractFeatureType', value);
setFeatureType(value);
}}
errorMsg={errors.dataExtractFeatureType}
/>
</div>
)}
{formValues.dataExtractWays === 'custom_data_extract' && (
{extractWays === 'osm_data_extract' && featureType && (
<Button
btnText="Generate Data Extract"
btnType="primary"
onClick={() => {
resetFile(setCustomPolygonUpload);
resetFile(setCustomLineUpload);
generateDataExtract();
}}
className="fmtm-mt-6"
isLoading={isFgbFetching}
loadingText="Data extracting..."
disabled={
featureType === formValues?.dataExtractFeatureType &&
dataExtractGeojson &&
!customPolygonUpload &&
!customLineUpload
? true
: false
}
/>
)}
{extractWays === 'custom_data_extract' && (
<>
<FileInputComponent
onChange={(e) => {
changeFileHandler(e, setCustomPolygonUpload);
handleCustomChange('customPolygonUpload', e.target.files[0]);
handleCustomChange('dataExtractFeatureType', '');
setFeatureType('');
}}
onResetFile={() => {
resetFile(setCustomPolygonUpload);
handleCustomChange('customPolygonUpload', null);
}}
onResetFile={() => resetFile(setCustomPolygonUpload)}
customFile={customPolygonUpload}
btnText="Upload Polygons"
accept=".geojson,.json,.fgb"
Expand All @@ -214,8 +306,12 @@ const DataExtract = ({ flag, customLineUpload, setCustomLineUpload, customPolygo
onChange={(e) => {
changeFileHandler(e, setCustomLineUpload);
handleCustomChange('customLineUpload', e.target.files[0]);
handleCustomChange('dataExtractFeatureType', null);
}}
onResetFile={() => {
resetFile(setCustomLineUpload);
handleCustomChange('customLineUpload', null);
}}
onResetFile={() => resetFile(setCustomLineUpload)}
customFile={customLineUpload}
btnText="Upload Lines"
accept=".geojson,.json,.fgb"
Expand All @@ -233,7 +329,20 @@ const DataExtract = ({ flag, customLineUpload, setCustomLineUpload, customPolygo
onClick={() => toggleStep(3, '/select-form')}
className="fmtm-font-bold"
/>
<Button btnText="NEXT" btnType="primary" type="submit" className="fmtm-font-bold" />
<Button
btnText="NEXT"
btnType="primary"
type="submit"
className="fmtm-font-bold"
dataTip={`${!dataExtractGeojson ? 'Please Generate Data Extract First.' : ''}`}
disabled={
!dataExtractGeojson ||
(extractWays === 'osm_data_extract' && !formValues?.dataExtractFeatureType) ||
isFgbFetching
? true
: false
}
/>
</div>
</form>
<div className="fmtm-w-full lg:fmtm-w-[60%] fmtm-flex fmtm-flex-col fmtm-gap-6 fmtm-bg-gray-300 fmtm-h-[60vh] lg:fmtm-h-full">
Expand Down
Loading