Make it work (fix rebase issues; add translations)
This commit is contained in:
parent
c7970d9382
commit
30fb29e437
|
@ -13,7 +13,7 @@ from migrations.utils import dbtype
|
|||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "a049e5eb24dd"
|
||||
down_revision = "a9627f63fbed"
|
||||
down_revision = "99a3d2eb08f9"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
|
|
@ -408,29 +408,6 @@ class User(Base):
|
|||
|
||||
self.username = new_name
|
||||
|
||||
async def rename(self, config, new_name):
|
||||
old_name = self.username
|
||||
|
||||
renames = [
|
||||
(join(basedir, old_name), join(basedir, new_name))
|
||||
for basedir in [config.PROCESSING_OUTPUT_DIR, config.TRACKS_DIR]
|
||||
]
|
||||
|
||||
for src, dst in renames:
|
||||
if exists(dst):
|
||||
raise FileExistsError(
|
||||
f"cannot move {src!r} to {dst!r}, destination exists"
|
||||
)
|
||||
|
||||
for src, dst in renames:
|
||||
if not exists(src):
|
||||
log.debug("Rename user %s: Not moving %s, not found", self.id, src)
|
||||
else:
|
||||
log.info("Rename user %s: Moving %s to %s", self.id, src, dst)
|
||||
os.rename(src, dst)
|
||||
|
||||
self.username = new_name
|
||||
|
||||
|
||||
class Comment(Base):
|
||||
__tablename__ = "comment"
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
from gzip import decompress
|
||||
from sqlite3 import connect
|
||||
from sanic.exceptions import Forbidden
|
||||
from datetime import datetime, time, timedelta
|
||||
from typing import Optional, Tuple
|
||||
|
||||
import dateutil.parser
|
||||
from sanic.exceptions import Forbidden, InvalidUsage
|
||||
from sanic.response import raw
|
||||
|
||||
from sqlalchemy import select, text
|
||||
|
@ -89,10 +93,6 @@ async def tiles(req, zoom: int, x: int, y: str):
|
|||
else:
|
||||
user_id, start, end = get_filter_options(req)
|
||||
|
||||
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);"
|
||||
|
|
|
@ -14,6 +14,7 @@ import { useObservable } from "rxjs-hooks";
|
|||
import { of, from, concat, combineLatest } from "rxjs";
|
||||
import { map, switchMap, distinctUntilChanged } from "rxjs/operators";
|
||||
import { Duration, DateTime } from "luxon";
|
||||
import {useTranslation} from 'react-i18next'
|
||||
|
||||
import api from "api";
|
||||
|
||||
|
@ -26,6 +27,8 @@ function formatDuration(seconds) {
|
|||
}
|
||||
|
||||
export default function Stats() {
|
||||
const {t} = useTranslation()
|
||||
|
||||
const [page, setPage] = useState(1);
|
||||
const PER_PAGE = 10;
|
||||
const stats = useObservable(
|
||||
|
@ -40,7 +43,7 @@ export default function Stats() {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Header as="h2">Top Regions</Header>
|
||||
<Header as="h2">{t(`Stats.topRegions`)}</Header>
|
||||
|
||||
<div>
|
||||
<Loader active={stats == null} />
|
||||
|
@ -48,8 +51,8 @@ export default function Stats() {
|
|||
<Table celled>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell>Region name</Table.HeaderCell>
|
||||
<Table.HeaderCell>Event count</Table.HeaderCell>
|
||||
<Table.HeaderCell>{t(`Stats.regionName`)}</Table.HeaderCell>
|
||||
<Table.HeaderCell>{t(`Stats.eventCount`)}</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
|
||||
|
|
|
@ -130,7 +130,7 @@ export const getRegionLayers = (adminLevel = 6, baseColor = "#00897B", maxValue
|
|||
"source": "obs",
|
||||
"source-layer": "obs_regions",
|
||||
"minzoom": 0,
|
||||
"maxzoom": 10,
|
||||
"maxzoom": 11,
|
||||
"filter": [
|
||||
"all",
|
||||
["==", "admin_level", adminLevel],
|
||||
|
@ -162,7 +162,7 @@ export const getRegionLayers = (adminLevel = 6, baseColor = "#00897B", maxValue
|
|||
"source": "obs",
|
||||
"source-layer": "obs_regions",
|
||||
"minzoom": 0,
|
||||
"maxzoom": 10,
|
||||
"maxzoom": 11,
|
||||
"filter": [
|
||||
"all",
|
||||
["==", "admin_level", adminLevel],
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import React from 'react'
|
||||
import {Link} from 'react-router-dom'
|
||||
import {Message, Grid, Loader, Header, Item} from 'semantic-ui-react'
|
||||
import {Grid, Loader, Header, Item} from 'semantic-ui-react'
|
||||
import {useObservable} from 'rxjs-hooks'
|
||||
import {of, from} from 'rxjs'
|
||||
import {map, switchMap} from 'rxjs/operators'
|
||||
import {useTranslation} from 'react-i18next'
|
||||
|
||||
import api from 'api'
|
||||
import {Stats, Page} from 'components'
|
||||
import {RegionStats, Stats, Page} from 'components'
|
||||
import type {Track} from 'types'
|
||||
|
||||
import {TrackListItem} from './TracksPage'
|
||||
import {TrackListItem, NoPublicTracksMessage} from './TracksPage'
|
||||
|
||||
function MostRecentTrack() {
|
||||
const {t} = useTranslation()
|
||||
|
@ -26,19 +26,13 @@ function MostRecentTrack() {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Header as="h2">Most recent tracks</Header>
|
||||
<Loader active={tracks === null} />
|
||||
{tracks?.length === 0 ? (
|
||||
<Message>
|
||||
<Translate i18nKey="HomePage.noPublicTracks">
|
||||
No public tracks yet. <Link to="/upload">Upload the first!</Link>
|
||||
</Translate>
|
||||
</Message>
|
||||
) : tracks ? (
|
||||
<Header as="h2">{t('HomePage.mostRecentTrack')}</Header>
|
||||
<Loader active={track === null} />
|
||||
{track === undefined ? (
|
||||
<NoPublicTracksMessage />
|
||||
) : track ? (
|
||||
<Item.Group>
|
||||
{tracks.map((track) => (
|
||||
<TrackListItem key={track.id} track={track} />
|
||||
))}
|
||||
<TrackListItem track={track} />
|
||||
</Item.Group>
|
||||
) : null}
|
||||
</>
|
||||
|
@ -52,6 +46,7 @@ export default function HomePage() {
|
|||
<Grid.Row>
|
||||
<Grid.Column width={8}>
|
||||
<Stats />
|
||||
<RegionStats />
|
||||
</Grid.Column>
|
||||
<Grid.Column width={8}>
|
||||
<MostRecentTrack />
|
||||
|
|
|
@ -24,14 +24,6 @@ import { ColorMapLegend, DiscreteColorMapLegend } from "components";
|
|||
const BASEMAP_STYLE_OPTIONS = ["positron", "bright"];
|
||||
|
||||
const ROAD_ATTRIBUTE_OPTIONS = [
|
||||
{value: 'distance_overtaker_mean', key: 'distance_overtaker_mean', text: 'Overtaker distance mean'},
|
||||
{value: 'distance_overtaker_min', key: 'distance_overtaker_min', text: 'Overtaker distance minimum'},
|
||||
{value: 'distance_overtaker_max', key: 'distance_overtaker_max', text: 'Overtaker distance maximum'},
|
||||
{value: 'distance_overtaker_median', key: 'distance_overtaker_median', text: 'Overtaker distance median'},
|
||||
{value: 'overtaking_event_count', key: 'overtaking_event_count', text: 'Event count'},
|
||||
{value: 'usage_count', key: 'usage_count', text: 'Usage count'},
|
||||
{value: 'zone', key: 'zone', text: 'Overtaking distance zone'}
|
||||
]
|
||||
"distance_overtaker_mean",
|
||||
"distance_overtaker_min",
|
||||
"distance_overtaker_max",
|
||||
|
@ -41,11 +33,7 @@ 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" },
|
||||
];
|
||||
const DATE_FILTER_MODES = ["none", "range", "threshold"];
|
||||
|
||||
type User = Object;
|
||||
|
||||
|
@ -183,21 +171,6 @@ function LayerSidebar({
|
|||
/>
|
||||
</List.Item>
|
||||
</>
|
||||
) : (
|
||||
<List.Item>
|
||||
<ColorMapLegend
|
||||
map={_.chunk(
|
||||
colorByCount(
|
||||
"obsRoads.maxCount",
|
||||
mapConfig.obsRoads.maxCount,
|
||||
viridisSimpleHtml
|
||||
).slice(3),
|
||||
2
|
||||
)}
|
||||
twoTicks
|
||||
/>
|
||||
</List.Item>
|
||||
</>
|
||||
) : attribute.endsWith("zone") ? (
|
||||
<>
|
||||
<List.Item>
|
||||
|
|
|
@ -2,14 +2,16 @@ import React, { useState, useCallback } from "react";
|
|||
import { createPortal } from "react-dom";
|
||||
import _ from "lodash";
|
||||
import { List, Header, Icon, Button } from "semantic-ui-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import styles from "./styles.module.less";
|
||||
|
||||
export default function RegionInfo({ region, mapInfoPortal, onClose }) {
|
||||
const { t } = useTranslation();
|
||||
const content = (
|
||||
<>
|
||||
<div className={styles.closeHeader}>
|
||||
<Header as="h3">{region.properties.name || "Unnamed region"}</Header>
|
||||
<Header as="h3">{region.properties.name || t(`MapPage.regionInfo.unnamedRegion`)}</Header>
|
||||
<Button primary icon onClick={onClose}>
|
||||
<Icon name="close" />
|
||||
</Button>
|
||||
|
@ -17,7 +19,7 @@ export default function RegionInfo({ region, mapInfoPortal, onClose }) {
|
|||
|
||||
<List>
|
||||
<List.Item>
|
||||
<List.Header>Number of events</List.Header>
|
||||
<List.Header>{t(`MapPage.regionInfo.eventNumber`)}</List.Header>
|
||||
<List.Content>{region.properties.overtaking_event_count ?? 0}</List.Content>
|
||||
</List.Item>
|
||||
</List>
|
||||
|
|
|
@ -1,15 +1,26 @@
|
|||
import React, {useState, useCallback} from 'react'
|
||||
import _ from 'lodash'
|
||||
import {Segment, Menu, Header, Label, Icon, Table} from 'semantic-ui-react'
|
||||
import {Layer, Source} from 'react-map-gl'
|
||||
import {of, from, concat} from 'rxjs'
|
||||
import {useObservable} from 'rxjs-hooks'
|
||||
import {switchMap, distinctUntilChanged} from 'rxjs/operators'
|
||||
import {Chart} from 'components'
|
||||
import {pairwise} from 'utils'
|
||||
import React, { useState, useCallback } from "react";
|
||||
import _ from "lodash";
|
||||
import {
|
||||
Segment,
|
||||
Menu,
|
||||
Header,
|
||||
Label,
|
||||
Icon,
|
||||
Table,
|
||||
Message,
|
||||
Button,
|
||||
} from "semantic-ui-react";
|
||||
import { Layer, Source } from "react-map-gl";
|
||||
import { of, from, concat } from "rxjs";
|
||||
import { useObservable } from "rxjs-hooks";
|
||||
import { switchMap, distinctUntilChanged } from "rxjs/operators";
|
||||
import { Chart } from "components";
|
||||
import { pairwise } from "utils";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import api from 'api'
|
||||
import {colorByDistance, borderByZone} from 'mapstyles'
|
||||
import type { Location } from "types";
|
||||
import api from "api";
|
||||
import { colorByDistance, borderByZone } from "mapstyles";
|
||||
|
||||
import styles from "./styles.module.less";
|
||||
|
||||
|
@ -127,7 +138,15 @@ function HistogramChart({ bins, counts, zone }) {
|
|||
);
|
||||
}
|
||||
|
||||
export default function RoadInfo({ clickLocation }) {
|
||||
export default function RoadInfo({
|
||||
clickLocation,
|
||||
hasFilters,
|
||||
onClose,
|
||||
}: {
|
||||
clickLocation: Location | null;
|
||||
hasFilters: boolean;
|
||||
onClose: () => void;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const [direction, setDirection] = useState("forwards");
|
||||
|
||||
|
@ -196,42 +215,51 @@ export default function RoadInfo({ clickLocation }) {
|
|||
/>
|
||||
</Header>
|
||||
|
||||
{hasFilters && (
|
||||
<Message info icon>
|
||||
<Icon name="info circle" small />
|
||||
<Message.Content>
|
||||
{t("MapPage.roadInfo.hintFiltersNotApplied")}
|
||||
</Message.Content>
|
||||
</Message>
|
||||
)}
|
||||
|
||||
{info?.road.zone && (
|
||||
<Label size="small" color={ZONE_COLORS[info?.road.zone]}>
|
||||
{t(`general.zone.${info.road.zone}`)}
|
||||
</Label>
|
||||
)}
|
||||
|
||||
{info.road.oneway && (
|
||||
{info?.road.oneway && (
|
||||
<Label size="small" color="blue">
|
||||
<Icon name="long arrow alternate right" fitted />{" "}
|
||||
{t("MapPage.roadInfo.oneway")}
|
||||
</Label>
|
||||
)}
|
||||
|
||||
{info.road.oneway ? null : (
|
||||
<Menu size="tiny" pointing>
|
||||
{info?.road.oneway ? null : (
|
||||
<Menu size="tiny" fluid secondary>
|
||||
<Menu.Item header>{t("MapPage.roadInfo.direction")}</Menu.Item>
|
||||
<Menu.Item
|
||||
name="forwards"
|
||||
active={direction === "forwards"}
|
||||
onClick={onClickDirection}
|
||||
>
|
||||
{getCardinalDirection(t, info.forwards?.bearing)}
|
||||
{getCardinalDirection(t, info?.forwards?.bearing)}
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
name="backwards"
|
||||
active={direction === "backwards"}
|
||||
onClick={onClickDirection}
|
||||
>
|
||||
{getCardinalDirection(t, info.backwards?.bearing)}
|
||||
{getCardinalDirection(t, info?.backwards?.bearing)}
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
)}
|
||||
|
||||
{info[direction] && <RoadStatsTable data={info[direction]} />}
|
||||
{info?.[direction] && <RoadStatsTable data={info[direction]} />}
|
||||
|
||||
{info[direction]?.distanceOvertaker?.histogram && (
|
||||
{info?.[direction]?.distanceOvertaker?.histogram && (
|
||||
<>
|
||||
<Header as="h5">
|
||||
{t("MapPage.roadInfo.overtakerDistanceDistribution")}
|
||||
|
@ -246,7 +274,7 @@ export default function RoadInfo({ clickLocation }) {
|
|||
|
||||
return (
|
||||
<>
|
||||
{info.road && (
|
||||
{info?.road && (
|
||||
<Source id="highlight" type="geojson" data={info.road.geometry}>
|
||||
<Layer
|
||||
id="route"
|
||||
|
@ -279,11 +307,10 @@ export default function RoadInfo({ clickLocation }) {
|
|||
</Source>
|
||||
)}
|
||||
|
||||
{content && mapInfoPortal && (
|
||||
createPortal(
|
||||
{content && (
|
||||
<div className={styles.mapInfoBox}>
|
||||
{content}
|
||||
</div>, mapInfoPortal))}
|
||||
<Segment loading={loading}>{content}</Segment>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState, useCallback, useMemo } from "react";
|
||||
import React, { useState, useCallback, useMemo, useRef } from "react";
|
||||
import _ from "lodash";
|
||||
import { connect } from "react-redux";
|
||||
import { Button } from "semantic-ui-react";
|
||||
|
@ -6,6 +6,7 @@ import { Layer, Source } from "react-map-gl";
|
|||
import produce from "immer";
|
||||
import classNames from "classnames";
|
||||
|
||||
import api from "api";
|
||||
import type { Location } from "types";
|
||||
import { Page, Map } from "components";
|
||||
import { useConfig } from "config";
|
||||
|
@ -15,6 +16,7 @@ import {
|
|||
borderByZone,
|
||||
reds,
|
||||
isValidAttribute,
|
||||
getRegionLayers
|
||||
} from "mapstyles";
|
||||
import { useMapConfig } from "reducers/mapConfig";
|
||||
|
||||
|
@ -69,8 +71,8 @@ const getRoadsLayer = (colorAttribute, maxCount) =>
|
|||
: colorAttribute.endsWith("zone")
|
||||
? borderByZone()
|
||||
: "#DDD";
|
||||
draft.paint["line-opacity"][3] = 12;
|
||||
draft.paint["line-opacity"][5] = 13;
|
||||
draft.paint["line-opacity"][3] = 10;
|
||||
draft.paint["line-opacity"][5] = 11;
|
||||
});
|
||||
|
||||
const getEventsLayer = () => ({
|
||||
|
@ -193,10 +195,9 @@ function MapPage({ login }) {
|
|||
node = node.parentNode;
|
||||
}
|
||||
|
||||
setClickLocation({longitude: e.lngLat[0], latitude: e.lngLat[1]})
|
||||
const { zoom } = viewportRef.current;
|
||||
|
||||
if (zoom < 10) {
|
||||
if (zoom < 11) {
|
||||
const clickedRegion = e.features?.find(
|
||||
(f) => f.source === "obs" && f.sourceLayer === "obs_regions"
|
||||
);
|
||||
|
@ -204,11 +205,8 @@ function MapPage({ login }) {
|
|||
clickedRegion ? { type: "region", region: clickedRegion } : null
|
||||
);
|
||||
} else {
|
||||
const road = await api.get("/mapdetails/road", {
|
||||
query: {
|
||||
longitude: e.lngLat[0],
|
||||
latitude: e.lngLat[1],
|
||||
radius: 100,
|
||||
setClickLocation({longitude: e.lngLat[0], latitude: e.lngLat[1]})
|
||||
}
|
||||
},
|
||||
[setClickLocation]
|
||||
);
|
||||
|
@ -292,33 +290,6 @@ function MapPage({ login }) {
|
|||
}
|
||||
);
|
||||
|
||||
const tiles = obsMapSource?.tiles?.map((tileUrl: string) => {
|
||||
const query = new URLSearchParams();
|
||||
if (login) {
|
||||
if (mapConfig.filters.currentUser) {
|
||||
query.append("user", login.id);
|
||||
}
|
||||
|
||||
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;
|
||||
});
|
||||
|
||||
const hasFilters: boolean =
|
||||
login &&
|
||||
(mapConfig.filters.currentUser || mapConfig.filters.dateMode !== "none");
|
||||
|
@ -330,6 +301,7 @@ function MapPage({ login }) {
|
|||
styles.mapContainer,
|
||||
banner ? styles.hasBanner : null
|
||||
)}
|
||||
ref={mapInfoPortal}
|
||||
>
|
||||
{layerSidebar && (
|
||||
<div className={styles.mapSidebar}>
|
||||
|
@ -338,6 +310,7 @@ function MapPage({ login }) {
|
|||
)}
|
||||
<div className={styles.map}>
|
||||
<Map viewportFromUrl onClick={onClick} onViewportChange={onViewportChange} hasToolbar>
|
||||
<div className={styles.mapToolbar}>
|
||||
<Button
|
||||
style={{
|
||||
position: "absolute",
|
||||
|
@ -355,12 +328,12 @@ function MapPage({ login }) {
|
|||
<Layer key={layer.id} {...layer} />
|
||||
))}
|
||||
</Source>
|
||||
{details?.type === "road" && details?.road?.road && (
|
||||
|
||||
|
||||
<RoadInfo
|
||||
{...{ clickLocation, hasFilters, onClose: onCloseRoadInfo }}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
{details?.type === "region" && details?.region && (
|
||||
<RegionInfo
|
||||
|
@ -369,8 +342,6 @@ function MapPage({ login }) {
|
|||
onClose={onCloseDetails}
|
||||
/>
|
||||
)}
|
||||
|
||||
<RoadInfo {...{ clickLocation }} />
|
||||
</Map>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,11 +1,20 @@
|
|||
import React, {useCallback} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
import {Button, Message, Item, Header, Loader, Pagination, Icon} from 'semantic-ui-react'
|
||||
import {useObservable} from 'rxjs-hooks'
|
||||
import {Link} from 'react-router-dom'
|
||||
import {of, from, concat} from 'rxjs'
|
||||
import {map, switchMap, distinctUntilChanged} from 'rxjs/operators'
|
||||
import _ from 'lodash'
|
||||
import React, { useCallback } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import {
|
||||
Button,
|
||||
Message,
|
||||
Item,
|
||||
Header,
|
||||
Loader,
|
||||
Pagination,
|
||||
Icon,
|
||||
} from "semantic-ui-react";
|
||||
import { useObservable } from "rxjs-hooks";
|
||||
import { Link } from "react-router-dom";
|
||||
import { of, from, concat } from "rxjs";
|
||||
import { map, switchMap, distinctUntilChanged } from "rxjs/operators";
|
||||
import _ from "lodash";
|
||||
import { useTranslation, Trans as Translate } from "react-i18next";
|
||||
|
||||
import type { Track } from "types";
|
||||
import {
|
||||
|
@ -82,7 +91,7 @@ export function NoPublicTracksMessage() {
|
|||
);
|
||||
}
|
||||
|
||||
function maxLength(t: string|null, max: number): string|null {
|
||||
function maxLength(t: string | null, max: number): string | null {
|
||||
if (t && t.length > max) {
|
||||
return t.substring(0, max) + " ...";
|
||||
} else {
|
||||
|
|
|
@ -62,6 +62,9 @@ Stats:
|
|||
thisMonth: Dieser Monat
|
||||
thisYear: Dieses Jahr
|
||||
allTime: Immer
|
||||
topRegions: Regionen mit den meisten Messwerten
|
||||
eventCount: Überholevents
|
||||
regionName: Region
|
||||
|
||||
TracksPage:
|
||||
titlePublic: Öffentliche Fahrten
|
||||
|
@ -201,6 +204,9 @@ MapPage:
|
|||
southWest: südwestwärts
|
||||
west: westwärts
|
||||
northWest: nordwestwärts
|
||||
regionInfo:
|
||||
unnamedRegion: Unbenannte Region
|
||||
eventNumber: Anzahl Überholevents
|
||||
|
||||
SettingsPage:
|
||||
title: Einstellungen
|
||||
|
|
|
@ -67,6 +67,9 @@ Stats:
|
|||
thisMonth: This month
|
||||
thisYear: This year
|
||||
allTime: All time
|
||||
topRegions: Region Leaderboard
|
||||
eventCount: Overtaking events
|
||||
regionName: Region
|
||||
|
||||
TracksPage:
|
||||
titlePublic: Public tracks
|
||||
|
@ -206,6 +209,10 @@ MapPage:
|
|||
southWest: south-west bound
|
||||
west: west bound
|
||||
northWest: north-west bound
|
||||
regionInfo:
|
||||
unnamedRegion: "unnamed region"
|
||||
eventNumber: Number of Overtaking events
|
||||
|
||||
|
||||
SettingsPage:
|
||||
title: Settings
|
||||
|
|
|
@ -12,11 +12,10 @@ RETURNS TABLE(event_id bigint, geometry geometry, distance_overtaker float, dist
|
|||
CASE WHEN road.zone IS NULL THEN 'urban' else road.zone END as zone,
|
||||
overtaking_event.way_id::bigint as way_id
|
||||
FROM overtaking_event
|
||||
FULL OUTER JOIN road ON (road.way_id = overtaking_event.way_id)
|
||||
FULL OUTER JOIN road ON road.way_id = overtaking_event.way_id
|
||||
JOIN track on track.id = overtaking_event.track_id
|
||||
WHERE
|
||||
zoom_level >= 10 AND
|
||||
ST_Transform(overtaking_event.geometry, 3857) && bbox;
|
||||
WHERE ST_Transform(overtaking_event.geometry, 3857) && bbox
|
||||
AND zoom_level >= 12
|
||||
AND (user_id is NULL OR user_id = track.author_id)
|
||||
AND time BETWEEN COALESCE(min_time, '1900-01-01'::timestamp) AND COALESCE(max_time, '2100-01-01'::timestamp);
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ RETURNS TABLE(
|
|||
) e on (e.way_id = road.way_id and (road.directionality != 0 or e.direction_reversed = r.rev))
|
||||
|
||||
WHERE
|
||||
zoom_level >= 10 AND
|
||||
zoom_level >= 11 AND
|
||||
road.geometry && bbox
|
||||
GROUP BY
|
||||
road.name,
|
||||
|
|
Loading…
Reference in a new issue