From c03f908247bb8605783550f89654aa7030de3c4f Mon Sep 17 00:00:00 2001
From: Nishit Suwal <81785002+NSUWAL123@users.noreply.github.com>
Date: Wed, 17 Jan 2024 18:03:27 +0545
Subject: [PATCH] fix: editable vector layer in ol for project creation (#1102)
* fix: backend import error fix
* fix (vectorLayer): style - conditionaly apply style on onModify present
* fix (splitTasks): map - edit added to splitted taskLayer
* fix (splitTasks): onModify - edited geojson set to dividedTaskGeojson state
* feat (createNewProject): only enable generate task btn if fgb file fetch is completed
* fix (createNewProject): splitTasks - logic fix
* fix (createNewProject): splitTasks - clear dividedTaskGeojson, splitTasksSelection, and dataExtractGeojson state on previous click
* feat (createNewProject): splitTasks - show loader and message until FGB file is fetching
* fix (createNewProject): taskSplit - display error on taskSplit fail
* fix vectorLayer: on modifyEnd return area of boundary as well
* fix button: loading text added to the button
* fix NewDefineAreaMap: removed data extraction in progress message from mapComponent
* fix (createNewProject): splitTasks - clearing state on step toggle remove
* fix (createNewProject): uploadArea - clear step4 & step5 step on AOI edit
* fix (createNewProject): dataExtract - generateTaskBTN added, disable next until taskGeneration success, state logic changed to track extractWays & featureType state validation
* fix (createNewProject): dataExtract - clear file state on reset click or if generateDataExtract click
* fix (createNewProject): customLine, customPolygon file state clear on AOI edit
* fix (createNewProject): dataExtract - clear previous extractGeojson, customLine, customPolygon on generate extract, btn disable state update
---
src/frontend/src/api/CreateProjectService.ts | 8 +
.../OpenLayersComponent/Layers/VectorLayer.js | 41 ++---
src/frontend/src/components/common/Button.tsx | 19 ++-
.../createnewproject/DataExtract.tsx | 153 +++++++++++++++---
.../createnewproject/SplitTasks.tsx | 12 +-
.../createnewproject/UploadArea.tsx | 5 +-
.../src/store/slices/CreateProjectSlice.ts | 10 ++
.../src/store/types/ICreateProject.ts | 1 +
src/frontend/src/views/CreateNewProject.tsx | 10 +-
src/frontend/src/views/NewDefineAreaMap.tsx | 7 +-
10 files changed, 215 insertions(+), 51 deletions(-)
diff --git a/src/frontend/src/api/CreateProjectService.ts b/src/frontend/src/api/CreateProjectService.ts
index 6750c5bcec..ff0581e30c 100755
--- a/src/frontend/src/api/CreateProjectService.ts
+++ b/src/frontend/src/api/CreateProjectService.ts
@@ -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));
diff --git a/src/frontend/src/components/MapComponent/OpenLayersComponent/Layers/VectorLayer.js b/src/frontend/src/components/MapComponent/OpenLayersComponent/Layers/VectorLayer.js
index 546bd7fddf..e3cb4c26d7 100644
--- a/src/frontend/src/components/MapComponent/OpenLayersComponent/Layers/VectorLayer.js
+++ b/src/frontend/src/components/MapComponent/OpenLayersComponent/Layers/VectorLayer.js
@@ -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);
@@ -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(() => {
@@ -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);
diff --git a/src/frontend/src/components/common/Button.tsx b/src/frontend/src/components/common/Button.tsx
index 49168f80e7..a5f69f748d 100644
--- a/src/frontend/src/components/common/Button.tsx
+++ b/src/frontend/src/components/common/Button.tsx
@@ -12,6 +12,7 @@ interface IButton {
icon?: React.ReactNode;
isLoading?: boolean;
disabled?: boolean;
+ loadingText?: string;
}
const btnStyle = (btnType, className) => {
@@ -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) => (
diff --git a/src/frontend/src/components/createnewproject/SplitTasks.tsx b/src/frontend/src/components/createnewproject/SplitTasks.tsx
index 22234d128d..55e92b5ff6 100644
--- a/src/frontend/src/components/createnewproject/SplitTasks.tsx
+++ b/src/frontend/src/components/createnewproject/SplitTasks.tsx
@@ -61,6 +61,7 @@ const SplitTasks = ({ flag, geojsonFile, setGeojsonFile, customLineUpload, custo
(state) => state.createproject.taskSplittingGeojsonLoading,
);
const isTasksGenerated = CoreModules.useAppSelector((state) => state.createproject.isTasksGenerated);
+ const isFgbFetching = CoreModules.useAppSelector((state) => state.createproject.isFgbFetching);
const toggleStep = (step, url) => {
dispatch(CommonActions.SetCurrentStepFormStep({ flag: flag, step: step }));
@@ -130,7 +131,6 @@ const SplitTasks = ({ flag, geojsonFile, setGeojsonFile, customLineUpload, custo
} else {
projectData = { ...projectData, task_split_dimension: projectDetails.dimension };
}
- console.log(projectData, 'projectData');
dispatch(
CreateProjectService(
`${import.meta.env.VITE_API_URL}/projects/create_project`,
@@ -379,8 +379,9 @@ const SplitTasks = ({ flag, geojsonFile, setGeojsonFile, customLineUpload, custo
className=""
icon={
}
disabled={
- splitTasksSelection === task_split_type['task_splitting_algorithm'] &&
- !formValues?.average_buildings_per_task
+ (splitTasksSelection === task_split_type['task_splitting_algorithm'] &&
+ !formValues?.average_buildings_per_task) ||
+ isFgbFetching
? true
: false
}
@@ -426,6 +427,11 @@ const SplitTasks = ({ flag, geojsonFile, setGeojsonFile, customLineUpload, custo
splittedGeojson={dividedTaskGeojson}
uploadedOrDrawnGeojsonFile={drawnGeojson}
buildingExtractedGeojson={dataExtractGeojson}
+ onModify={(geojson) => {
+ handleCustomChange('drawnGeojson', geojson);
+ dispatch(CreateProjectActions.SetDividedTaskGeojson(JSON.parse(geojson)));
+ setGeojsonFile(null);
+ }}
/>
{generateProjectLog ? (
diff --git a/src/frontend/src/components/createnewproject/UploadArea.tsx b/src/frontend/src/components/createnewproject/UploadArea.tsx
index 01f3c93281..2bcba1ce65 100644
--- a/src/frontend/src/components/createnewproject/UploadArea.tsx
+++ b/src/frontend/src/components/createnewproject/UploadArea.tsx
@@ -31,7 +31,7 @@ const uploadAreaOptions = [
},
];
-const UploadArea = ({ flag, geojsonFile, setGeojsonFile }) => {
+const UploadArea = ({ flag, geojsonFile, setGeojsonFile, setCustomLineUpload, setCustomPolygonUpload }) => {
const dispatch = useDispatch();
const navigate = useNavigate();
// const [uploadAreaFile, setUploadAreaFile] = useState(null);
@@ -264,6 +264,9 @@ const UploadArea = ({ flag, geojsonFile, setGeojsonFile }) => {
handleCustomChange('drawnGeojson', geojson);
dispatch(CreateProjectActions.SetDrawnGeojson(JSON.parse(geojson)));
dispatch(CreateProjectActions.SetTotalAreaSelection(area));
+ dispatch(CreateProjectActions.ClearProjectStepState());
+ setCustomLineUpload(null);
+ setCustomPolygonUpload(null);
setGeojsonFile(null);
}}
/>
diff --git a/src/frontend/src/store/slices/CreateProjectSlice.ts b/src/frontend/src/store/slices/CreateProjectSlice.ts
index 7f9cc75856..5de2a1cea2 100755
--- a/src/frontend/src/store/slices/CreateProjectSlice.ts
+++ b/src/frontend/src/store/slices/CreateProjectSlice.ts
@@ -48,6 +48,7 @@ export const initialState: CreateProjectStateTypes = {
isUnsavedChanges: false,
canSwitchCreateProjectSteps: false,
isTasksGenerated: { divide_on_square: false, task_splitting_algorithm: false },
+ isFgbFetching: false,
};
const CreateProject = createSlice({
@@ -215,6 +216,15 @@ const CreateProject = createSlice({
[action.payload.key]: action.payload.value,
};
},
+ SetFgbFetchingStatus(state, action) {
+ state.isFgbFetching = action.payload;
+ },
+ ClearProjectStepState(state) {
+ state.dividedTaskGeojson = null;
+ state.splitTasksSelection = null;
+ state.dataExtractGeojson = null;
+ state.projectDetails = { ...state.projectDetails, customLineUpload: null, customPolygonUpload: null };
+ },
},
});
diff --git a/src/frontend/src/store/types/ICreateProject.ts b/src/frontend/src/store/types/ICreateProject.ts
index 900dff66de..bd7fd27e08 100644
--- a/src/frontend/src/store/types/ICreateProject.ts
+++ b/src/frontend/src/store/types/ICreateProject.ts
@@ -34,6 +34,7 @@ export type CreateProjectStateTypes = {
isUnsavedChanges: boolean;
canSwitchCreateProjectSteps: boolean;
isTasksGenerated: {};
+ isFgbFetching: boolean;
};
export type ValidateCustomFormResponse = {
detail: { message: string; possible_reason: string };
diff --git a/src/frontend/src/views/CreateNewProject.tsx b/src/frontend/src/views/CreateNewProject.tsx
index 14f6ac96bb..271d9b4dc1 100644
--- a/src/frontend/src/views/CreateNewProject.tsx
+++ b/src/frontend/src/views/CreateNewProject.tsx
@@ -61,7 +61,15 @@ const CreateNewProject = () => {
case '/create-project':
return ;
case '/upload-area':
- return ;
+ return (
+
+ );
case '/select-form':
return (
void;
+ onDraw?: (geojson: any, area: number) => void;
+ onModify?: (geojson: any, area?: number) => void;
};
const NewDefineAreaMap = ({
drawToggle,
@@ -51,7 +52,7 @@ const NewDefineAreaMap = ({
constrainResolution: true,
duration: 500,
}}
- zoomToLayer
+ onModify={onModify}
/>
)}
{isDrawOrGeojsonFile && !splittedGeojson && (