From e0cb36565aa295ff1b874dea4057d050f4266ab9 Mon Sep 17 00:00:00 2001 From: Paul Bienkowski Date: Fri, 22 Jul 2022 13:29:51 +0200 Subject: [PATCH] Add date-range filters to map --- api/obs/api/routes/tiles.py | 10 +- frontend/src/pages/MapPage/LayerSidebar.tsx | 135 +++++++++++++++++--- frontend/src/pages/MapPage/index.tsx | 26 +++- frontend/src/reducers/mapConfig.ts | 8 ++ 4 files changed, 157 insertions(+), 22 deletions(-) diff --git a/api/obs/api/routes/tiles.py b/api/obs/api/routes/tiles.py index 7d843b2..e90d4ee 100644 --- a/api/obs/api/routes/tiles.py +++ b/api/obs/api/routes/tiles.py @@ -1,5 +1,7 @@ from gzip import decompress from sqlite3 import connect + +import dateutil.parser from sanic.exceptions import Forbidden from sanic.response import raw @@ -46,6 +48,10 @@ async def tiles(req, zoom: int, x: int, y: str): raise Forbidden() user_id = req.ctx.user.id + parse_date = lambda s: dateutil.parser.parse(s) + start = req.ctx.get_single_arg("start", default=None, convert=parse_date) + end = req.ctx.get_single_arg("end", default=None, convert=parse_date) + tile = await req.ctx.db.scalar( text( f"select data from getmvt(:zoom, :x, :y, :user_id, :min_time, :max_time) as b(data, key);" @@ -54,8 +60,8 @@ async def tiles(req, zoom: int, x: int, y: str): x=int(x), y=int(y), user_id=user_id, - min_time=None, - max_time=None, + min_time=start, + max_time=end, ) ) diff --git a/frontend/src/pages/MapPage/LayerSidebar.tsx b/frontend/src/pages/MapPage/LayerSidebar.tsx index 718bfd7..25739e0 100644 --- a/frontend/src/pages/MapPage/LayerSidebar.tsx +++ b/frontend/src/pages/MapPage/LayerSidebar.tsx @@ -32,6 +32,12 @@ const ROAD_ATTRIBUTE_OPTIONS = [ "zone", ]; +const DATE_FILTER_MODES = [ + { value: "none", key: "none", text: "All time" }, + { value: "range", key: "range", text: "Start and end range" }, + { value: "threshold", key: "threshold", text: "Before/after comparison" }, +]; + type User = Object; function LayerSidebar({ @@ -48,7 +54,13 @@ function LayerSidebar({ baseMap: { style }, obsRoads: { show: showRoads, showUntagged, attribute, maxCount }, obsEvents: { show: showEvents }, - filters: { currentUser: filtersCurrentUser }, + filters: { + currentUser: filtersCurrentUser, + dateMode, + startDate, + endDate, + thresholdAfter, + }, } = mapConfig; return ( @@ -209,24 +221,113 @@ function LayerSidebar({ )} + -
- Filter -
- {login && ( - - setMapConfigFlag("filters.currentUser", !filtersCurrentUser) - } - label="Show only my own data" - /> - )} - {!login &&
No filters available without login.
} +
Filters
+ + {login && ( + <> + +
User data
+
+ + + + setMapConfigFlag("filters.currentUser", !filtersCurrentUser) + } + label="Show only my own data" + /> + + + +
Date range
+
+ + + + setMapConfigFlag("filters.startDate", value) + } + value={startDate ?? null} + label="Start" + /> + + )} + + {dateMode == "range" && ( + + + setMapConfigFlag("filters.endDate", value) + } + value={endDate ?? null} + label="End" + /> + + )} + + {dateMode == "threshold" && ( + + + setMapConfigFlag("filters.startDate", value) + } + label="Threshold" + /> + + )} + + {dateMode == "threshold" && ( + + + Before{" "} + + setMapConfigFlag( + "filters.thresholdAfter", + !thresholdAfter + ) + } + id="filters.thresholdAfter" + />{" "} + After + + + )} + + )} + {!login && No filters available without login.} ); diff --git a/frontend/src/pages/MapPage/index.tsx b/frontend/src/pages/MapPage/index.tsx index 7298a46..c61b6dc 100644 --- a/frontend/src/pages/MapPage/index.tsx +++ b/frontend/src/pages/MapPage/index.tsx @@ -160,9 +160,29 @@ function MapPage({ login }) { } const tiles = obsMapSource?.tiles?.map( - (tileUrl: string) => - tileUrl + - (login && mapConfig.filters.currentUser ? `?user=${login.username}` : "") + (tileUrl: string) => { + const query = new URLSearchParams() + if (login) { + if (mapConfig.filters.currentUser) { + query.append('user', login.username) + } + + if (mapConfig.filters.dateMode === "range") { + if (mapConfig.filters.startDate) { + query.append('start', mapConfig.filters.startDate) + } + if (mapConfig.filters.endDate) { + query.append('end', mapConfig.filters.endDate) + } + } else if (mapConfig.filters.dateMode === "threshold") { + if (mapConfig.filters.startDate) { + query.append(mapConfig.filters.thresholdAfter ? 'start' : 'end', mapConfig.filters.startDate) + } + } + } + const queryString = String(query) + return tileUrl + (queryString ? '?' : '') + queryString + } ); return ( diff --git a/frontend/src/reducers/mapConfig.ts b/frontend/src/reducers/mapConfig.ts index 4d8d8dc..2ec5398 100644 --- a/frontend/src/reducers/mapConfig.ts +++ b/frontend/src/reducers/mapConfig.ts @@ -29,6 +29,10 @@ export type MapConfig = { }; filters: { currentUser: boolean; + dateMode: "none" | "range" | "threshold"; + startDate?: null | string; + endDate?: null | string; + thresholdAfter?: null | boolean; }; }; @@ -47,6 +51,10 @@ export const initialState: MapConfig = { }, filters: { currentUser: false, + dateMode: "none", + startDate: null, + endDate: null, + thresholdAfter: true, }, };