diff --git a/django_project/frontend/src/pages/Admin/Dashboard/Form/Filters/index.jsx b/django_project/frontend/src/pages/Admin/Dashboard/Form/Filters/index.jsx
index 455492b86..77dc3374f 100644
--- a/django_project/frontend/src/pages/Admin/Dashboard/Form/Filters/index.jsx
+++ b/django_project/frontend/src/pages/Admin/Dashboard/Form/Filters/index.jsx
@@ -16,6 +16,7 @@
import React from 'react';
import { useDispatch, useSelector } from "react-redux";
import Checkbox from "@mui/material/Checkbox";
+import { FormControlLabel } from "@mui/material";
import FiltersAccordion from "../../../../Dashboard/LeftPanel/Filters";
import { Actions } from "../../../../../store/dashboard/index";
@@ -27,13 +28,26 @@ import './style.scss';
export default function FiltersForm() {
const dispatch = useDispatch();
const {
- filtersAllowModify
+ filtersAllowModify,
+ auto_zoom_to_filter
} = useSelector(state => state.dashboard.data);
return
- {
- dispatch(Actions.Dashboard.updateFiltersAllowModify())
- }}/> Allow users to modify filters in dashboard
+ }
+ onChange={evt => {
+ dispatch(Actions.Dashboard.updateFiltersAllowModify())
+ }}
+ label={'Allow users to modify filters in dashboard'}/>
+
+ }
+ onChange={evt => {
+ dispatch(Actions.Dashboard.updateAutoZoomToFilter())
+ }}
+ label={'Zoom in automatically to filtered area'}/>
}
\ No newline at end of file
diff --git a/django_project/frontend/src/pages/Admin/Dashboard/Form/index.jsx b/django_project/frontend/src/pages/Admin/Dashboard/Form/index.jsx
index eed6b4895..c9ab07832 100644
--- a/django_project/frontend/src/pages/Admin/Dashboard/Form/index.jsx
+++ b/django_project/frontend/src/pages/Admin/Dashboard/Form/index.jsx
@@ -180,6 +180,7 @@ export function DashboardSaveForm(
extent,
filters,
filtersAllowModify,
+ auto_zoom_to_filter,
permission,
geoField,
levelConfig
@@ -298,6 +299,7 @@ export function DashboardSaveForm(
'widgets_structure': widgetsStructure,
'filters': filtersData ? filtersData : filters,
'filters_allow_modify': filtersAllowModify,
+ 'auto_zoom_to_filter': auto_zoom_to_filter,
'permission': permission,
'show_splash_first_open': splashScreen,
'truncate_indicator_layer_name': truncateIndicatorName,
diff --git a/django_project/frontend/src/pages/Dashboard/MapLibre/index.jsx b/django_project/frontend/src/pages/Dashboard/MapLibre/index.jsx
index e432101f6..fde631da4 100644
--- a/django_project/frontend/src/pages/Dashboard/MapLibre/index.jsx
+++ b/django_project/frontend/src/pages/Dashboard/MapLibre/index.jsx
@@ -44,6 +44,7 @@ import {
SearchGeometryInput,
TiltControl,
ToggleSidePanel,
+ ZoomToFilteredGeometries
} from '../Toolbars'
import { EmbedConfig } from "../../../utils/embed";
import { Actions } from "../../../store/dashboard";
@@ -247,6 +248,7 @@ export default function MapLibre(
{/* Embed */}
+
diff --git a/django_project/frontend/src/pages/Dashboard/Toolbars/ZoomToFilteredGeometries/index.jsx b/django_project/frontend/src/pages/Dashboard/Toolbars/ZoomToFilteredGeometries/index.jsx
new file mode 100644
index 000000000..7565a1a2b
--- /dev/null
+++ b/django_project/frontend/src/pages/Dashboard/Toolbars/ZoomToFilteredGeometries/index.jsx
@@ -0,0 +1,90 @@
+/**
+ * GeoSight is UNICEF's geospatial web-based business intelligence platform.
+ *
+ * Contact : geosight-no-reply@unicef.org
+ *
+ * .. note:: This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * __author__ = 'irwan@kartoza.com'
+ * __date__ = '07/09/2023'
+ * __copyright__ = ('Copyright 2023, Unicef')
+ */
+
+/* ==========================================================================
+ Zoom To Geometries by Filters
+ This is called and triggered when we do filters
+ And "Zoom in automatically in filtered areas" is true
+ ========================================================================== */
+
+import React, { useEffect } from 'react';
+
+import { useSelector } from "react-redux";
+import { returnWhere } from "../../../../utils/queryExtraction";
+import { fetchJson } from "../../../../utils/georepo";
+import { Session } from "../../../../utils/Sessions";
+import { GeometriesBBOX } from "../../../../utils/geometry";
+import { dictDeepCopy } from "../../../../utils/main";
+
+import './style.scss';
+
+/**
+ * Zoom To Geometries by Filters.
+ */
+export default function ZoomToFilteredGeometries({ map }) {
+ const {
+ referenceLayer,
+ auto_zoom_to_filter
+ } = useSelector(state => state.dashboard.data);
+ const filteredGeometries = useSelector(state => state.filteredGeometries);
+ const geometries = useSelector(state => state.geometries);
+ const filtersData = useSelector(state => state.filtersData);
+ const selectedAdminLevel = useSelector(state => state.selectedAdminLevel);
+
+ useEffect(() => {
+ (
+ async () => {
+ if (!map || !auto_zoom_to_filter) {
+ return
+ }
+ const session = new Session('ZoomToGeometriesByFilters', 1000)
+
+ const where = returnWhere(filtersData ? filtersData : [])
+ const level = selectedAdminLevel?.level
+ if (!filteredGeometries || !geometries[level] || !where) {
+ return
+ }
+ const geoms = dictDeepCopy(geometries[level]);
+ const usedGeometries = []
+ for (let i = 0; i < filteredGeometries.length; i++) {
+ const geom = filteredGeometries[i]
+ const found = geoms[geom]
+ if (found) {
+ try {
+ const response = await fetchJson(`/operation/view/${referenceLayer.identifier}/bbox/concept_uuid/${found.concept_uuid}/`)
+ found.bbox = response
+ usedGeometries.push(found)
+ } catch (err) {
+
+ }
+ }
+ }
+ if (session.isValid) {
+ const extent = GeometriesBBOX(usedGeometries)
+ if (extent) {
+ map.fitBounds([
+ [extent[0], extent[1]],
+ [extent[2], extent[3]]
+ ],
+ { padding: 20 }
+ )
+ }
+ }
+ }
+ )()
+ }, [filteredGeometries, filtersData]);
+
+ return null
+}
\ No newline at end of file
diff --git a/django_project/frontend/src/pages/Dashboard/Toolbars/ZoomToFilteredGeometries/style.scss b/django_project/frontend/src/pages/Dashboard/Toolbars/ZoomToFilteredGeometries/style.scss
new file mode 100644
index 000000000..e0d2ae695
--- /dev/null
+++ b/django_project/frontend/src/pages/Dashboard/Toolbars/ZoomToFilteredGeometries/style.scss
@@ -0,0 +1,14 @@
+/**
+* GeoSight is UNICEF's geospatial web-based business intelligence platform.
+*
+* Contact : geosight-no-reply@unicef.org
+*
+* .. note:: This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License as published by
+* the Free Software Foundation; either version 3 of the License, or
+* (at your option) any later version.
+*
+* __author__ = 'irwan@kartoza.com'
+* __date__ = '07/09/2023'
+* __copyright__ = ('Copyright 2023, Unicef')
+*/
\ No newline at end of file
diff --git a/django_project/frontend/src/pages/Dashboard/Toolbars/index.jsx b/django_project/frontend/src/pages/Dashboard/Toolbars/index.jsx
index 7ce0d13f3..841714d87 100644
--- a/django_project/frontend/src/pages/Dashboard/Toolbars/index.jsx
+++ b/django_project/frontend/src/pages/Dashboard/Toolbars/index.jsx
@@ -25,4 +25,5 @@ export { default as EmbedControl } from "./Embed";
export { default as LabelToggler } from "./LabelToggler";
export { default as ProjectOverview } from "./ProjectOverview";
export { default as SearchGeometryInput } from "./SearchGeometryInput";
-export { default as ToggleSidePanel } from "./ToggleSidePanel";
\ No newline at end of file
+export { default as ToggleSidePanel } from "./ToggleSidePanel";
+export { default as ZoomToFilteredGeometries } from "./ZoomToFilteredGeometries";
\ No newline at end of file
diff --git a/django_project/frontend/src/store/dashboard/reducers/dashboard/actions.jsx b/django_project/frontend/src/store/dashboard/reducers/dashboard/actions.jsx
index cb8b885b7..e5cd66490 100644
--- a/django_project/frontend/src/store/dashboard/reducers/dashboard/actions.jsx
+++ b/django_project/frontend/src/store/dashboard/reducers/dashboard/actions.jsx
@@ -17,6 +17,7 @@ import { fetchingData } from "../../../../Requests";
import {
DASHBOARD_ACTION_NAME,
+ DASHBOARD_ACTION_TYPE_AUTO_ZOOM_TO_FILTER,
DASHBOARD_ACTION_TYPE_FILTERS_ALLOW_MODIFY,
DASHBOARD_ACTION_TYPE_UPDATE,
DASHBOARD_ACTION_TYPE_UPDATE_GEOFIELD,
@@ -192,6 +193,16 @@ export function updateFiltersAllowModify() {
};
}
+/**
+ * Update auto zoom to filter.
+ */
+export function updateAutoZoomToFilter() {
+ return {
+ name: DASHBOARD_ACTION_NAME,
+ type: DASHBOARD_ACTION_TYPE_AUTO_ZOOM_TO_FILTER
+ };
+}
+
/**
* Change geofield
*/
@@ -224,6 +235,7 @@ export default {
update,
updateProps,
updateFiltersAllowModify,
+ updateAutoZoomToFilter,
updatePermission,
changeGeoField,
updateStructure
diff --git a/django_project/frontend/src/store/dashboard/reducers/dashboard/index.js b/django_project/frontend/src/store/dashboard/reducers/dashboard/index.js
index a0d746779..8f9ef744f 100644
--- a/django_project/frontend/src/store/dashboard/reducers/dashboard/index.js
+++ b/django_project/frontend/src/store/dashboard/reducers/dashboard/index.js
@@ -39,6 +39,7 @@ export const DASHBOARD_ACTION_NAME = 'DASHBOARD';
export const DASHBOARD_ACTION_TYPE_UPDATE = 'DASHBOARD/UPDATE';
export const DASHBOARD_ACTION_TYPE_UPDATE_PROPS = 'DASHBOARD/UPDATE_PROPS';
export const DASHBOARD_ACTION_TYPE_FILTERS_ALLOW_MODIFY = 'DASHBOARD/FILTERS_ALLOW_MODIFY';
+export const DASHBOARD_ACTION_TYPE_AUTO_ZOOM_TO_FILTER = 'DASHBOARD/AUTO_ZOOM_TO_FILTER';
export const DASHBOARD_ACTION_TYPE_UPDATE_SHARE = 'DASHBOARD/UPDATE_SHARE';
export const DASHBOARD_ACTION_TYPE_UPDATE_GEOFIELD = 'DASHBOARD/UPDATE_GEOFIELD';
export const DASHBOARD_ACTION_TYPE_UPDATE_STRUCTURE = 'DASHBOARD/UPDATE_STRUCTURE';
@@ -80,6 +81,15 @@ export default function dashboardReducer(
}
}
}
+ case DASHBOARD_ACTION_TYPE_AUTO_ZOOM_TO_FILTER: {
+ return {
+ ...state,
+ data: {
+ ...state.data,
+ auto_zoom_to_filter: !state.data.auto_zoom_to_filter
+ }
+ }
+ }
case DASHBOARD_ACTION_TYPE_UPDATE_SHARE: {
return {
...state,
diff --git a/django_project/geosight/data/forms/dashboard.py b/django_project/geosight/data/forms/dashboard.py
index 848e6a518..b85115275 100644
--- a/django_project/geosight/data/forms/dashboard.py
+++ b/django_project/geosight/data/forms/dashboard.py
@@ -117,5 +117,7 @@ def update_data(data):
data['filters'] = json.dumps(other_data['filters'])
data['filters_allow_modify'] = other_data.get(
'filters_allow_modify', False)
+ data['auto_zoom_to_filter'] = other_data.get(
+ 'auto_zoom_to_filter', False)
data['permission'] = other_data['permission']
return data
diff --git a/django_project/geosight/data/migrations/0086_dashboard_auto_zoom_to_filter.py b/django_project/geosight/data/migrations/0086_dashboard_auto_zoom_to_filter.py
new file mode 100644
index 000000000..105777ed8
--- /dev/null
+++ b/django_project/geosight/data/migrations/0086_dashboard_auto_zoom_to_filter.py
@@ -0,0 +1,18 @@
+# Generated by Django 3.2.16 on 2023-09-07 05:35
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('geosight_data', '0085_dashboard_enable_geometry_search'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='dashboard',
+ name='auto_zoom_to_filter',
+ field=models.BooleanField(default=False),
+ ),
+ ]
diff --git a/django_project/geosight/data/models/dashboard/dashboard.py b/django_project/geosight/data/models/dashboard/dashboard.py
index 60e8801af..762e149cc 100644
--- a/django_project/geosight/data/models/dashboard/dashboard.py
+++ b/django_project/geosight/data/models/dashboard/dashboard.py
@@ -70,6 +70,9 @@ class Dashboard(SlugTerm, IconTerm, AbstractEditData):
filters_allow_modify = models.BooleanField(
default=False
)
+ auto_zoom_to_filter = models.BooleanField(
+ default=False
+ )
geo_field = models.CharField(
max_length=64,
default='concept_uuid'
diff --git a/django_project/geosight/data/serializer/dashboard.py b/django_project/geosight/data/serializer/dashboard.py
index 744d9b23f..d9a507307 100644
--- a/django_project/geosight/data/serializer/dashboard.py
+++ b/django_project/geosight/data/serializer/dashboard.py
@@ -237,7 +237,7 @@ class Meta: # noqa: D106
fields = (
'id', 'slug', 'icon', 'name', 'description',
'category', 'group',
- 'extent', 'filters', 'filters_allow_modify',
+ 'extent', 'filters', 'filters_allow_modify', 'auto_zoom_to_filter',
'reference_layer', 'level_config',
'indicators', 'indicator_layers', 'indicator_layers_structure',
'context_layers', 'context_layers_structure',