mirror of
https://github.com/lrnselfreliance/wrolpi.git
synced 2026-10-26 19:01:39 -04:00
Adding map default view option to the map context menu.
This commit is contained in:
parent
b8a532c8d9
commit
bbc23dbf90
5 changed files with 79 additions and 6 deletions
|
|
@ -317,6 +317,7 @@ export async function getSettings() {
|
|||
ignore_outdated_zims: content.ignore_outdated_zims,
|
||||
ignored_directories: content.ignored_directories,
|
||||
log_level: content.log_level,
|
||||
map_default_location: content.map_default_location,
|
||||
map_destination: content.map_destination,
|
||||
nav_color: content.nav_color,
|
||||
media_directory: content.media_directory,
|
||||
|
|
@ -1568,6 +1569,17 @@ export async function updateMapPin(pinId, label, color) {
|
|||
}
|
||||
}
|
||||
|
||||
export async function setMapDefaultLocation(lat, lon, zoom) {
|
||||
try {
|
||||
await updateConfig('wrolpi.yaml', {map_default_location: {lat, lon, zoom}});
|
||||
toast({type: 'success', title: 'Default Location', description: 'Default map location saved', time: 3000});
|
||||
return true;
|
||||
} catch (e) {
|
||||
toast({type: 'error', title: 'Map Error', description: 'Could not set default location', time: 5000});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function clearCompletedDownloads() {
|
||||
const response = await apiPost(`${API_URI}/download/clear_completed`);
|
||||
if (!response.ok) {
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ import "maplibre-gl/dist/maplibre-gl.css";
|
|||
import {Protocol} from "pmtiles";
|
||||
import layers from "protomaps-themes-base";
|
||||
import mlcontour from "@acalcutt/maplibre-contour-pmtiles";
|
||||
import {addMapPin, deleteMapPin, getMapFiles, getMapPins} from "../api";
|
||||
import {addMapPin, deleteMapPin, getMapFiles, getMapPins, setMapDefaultLocation} from "../api";
|
||||
import {MAP_VIEWER_URI} from "./Vars";
|
||||
import {Checkbox, Icon, Segment} from "semantic-ui-react";
|
||||
import {Header} from "./Theme";
|
||||
import {ThemeContext} from "../contexts/contexts";
|
||||
import {SettingsContext, ThemeContext} from "../contexts/contexts";
|
||||
|
||||
// Terrain DEM file prefix for hillshade and contours.
|
||||
const TERRAIN_PREFIX = "terrain-";
|
||||
|
|
@ -354,11 +354,20 @@ export default function MapViewer() {
|
|||
});
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const {theme} = useContext(ThemeContext);
|
||||
const {settings, fetchSettings} = useContext(SettingsContext);
|
||||
|
||||
// Parse initial coordinates from URL.
|
||||
const initialLat = parseFloat(searchParams.get("lat")) || 0;
|
||||
const initialLon = parseFloat(searchParams.get("lon")) || 0;
|
||||
const initialZoom = parseFloat(searchParams.get("z")) || 2;
|
||||
// Use URL params if provided, otherwise fall back to saved default location, then 0,0,z2.
|
||||
const hasUrlParams = searchParams.has("lat") || searchParams.has("lon") || searchParams.has("z");
|
||||
const defaultLoc = settings?.map_default_location;
|
||||
const initialLat = hasUrlParams
|
||||
? (parseFloat(searchParams.get("lat")) || 0)
|
||||
: (parseFloat(defaultLoc?.lat) || 0);
|
||||
const initialLon = hasUrlParams
|
||||
? (parseFloat(searchParams.get("lon")) || 0)
|
||||
: (parseFloat(defaultLoc?.lon) || 0);
|
||||
const initialZoom = hasUrlParams
|
||||
? (parseFloat(searchParams.get("z")) || 2)
|
||||
: (parseFloat(defaultLoc?.zoom) || 2);
|
||||
|
||||
useEffect(() => {
|
||||
if (!mapContainer.current) return;
|
||||
|
|
@ -705,6 +714,16 @@ export default function MapViewer() {
|
|||
setContextMenu(null);
|
||||
}, [contextMenu]);
|
||||
|
||||
const handleSetDefaultLocation = useCallback(async () => {
|
||||
const map = mapRef.current;
|
||||
if (!map) return;
|
||||
const center = map.getCenter();
|
||||
const zoom = map.getZoom();
|
||||
await setMapDefaultLocation(center.lat, center.lng, zoom);
|
||||
await fetchSettings();
|
||||
setContextMenu(null);
|
||||
}, [fetchSettings]);
|
||||
|
||||
const handleSubmitPin = useCallback(async (label, color) => {
|
||||
if (!addingPin) return;
|
||||
const {lat, lon} = addingPin;
|
||||
|
|
@ -770,6 +789,14 @@ export default function MapViewer() {
|
|||
>
|
||||
Add Pin Here
|
||||
</div>
|
||||
<div
|
||||
style={{padding: "8px 12px", cursor: "pointer", userSelect: "none"}}
|
||||
onMouseEnter={e => e.target.style.background = "#f0f0f0"}
|
||||
onMouseLeave={e => e.target.style.background = "transparent"}
|
||||
onClick={handleSetDefaultLocation}
|
||||
>
|
||||
Set as Default View
|
||||
</div>
|
||||
</div>}
|
||||
{addingPin && <AddPinDialog
|
||||
lat={addingPin.lat}
|
||||
|
|
|
|||
|
|
@ -128,3 +128,26 @@ async def test_subscribe_invalid_region(async_client, test_session, test_directo
|
|||
body = json.dumps({'name': 'Atlantis', 'region': 'atlantis'})
|
||||
request, response = await async_client.post('/api/map/subscribe', content=body)
|
||||
assert response.status_code == HTTPStatus.BAD_REQUEST
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_map_default_location_empty(async_client, test_directory):
|
||||
"""Default location is null when not set."""
|
||||
request, response = await async_client.get('/api/settings')
|
||||
assert response.status_code == HTTPStatus.OK
|
||||
assert response.json['map_default_location'] is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_set_and_get_map_default_location(async_client, test_directory):
|
||||
"""Setting a default map location persists and is returned in settings."""
|
||||
body = json.dumps({'config': {'map_default_location': {'lat': 40.7, 'lon': -111.9, 'zoom': 10.5}}})
|
||||
request, response = await async_client.post('/api/config?file_name=wrolpi.yaml', content=body)
|
||||
assert response.status_code == HTTPStatus.NO_CONTENT
|
||||
|
||||
request, response = await async_client.get('/api/settings')
|
||||
assert response.status_code == HTTPStatus.OK
|
||||
loc = response.json['map_default_location']
|
||||
assert loc['lat'] == 40.7
|
||||
assert loc['lon'] == -111.9
|
||||
assert loc['zoom'] == 10.5
|
||||
|
|
|
|||
|
|
@ -801,6 +801,7 @@ class WROLPiConfigValidator:
|
|||
hotspot_ssid: str = None
|
||||
ignore_outdated_zims: bool = None
|
||||
log_level: str = None
|
||||
map_default_location: dict = None
|
||||
map_destination: str = None
|
||||
nav_color: str = None
|
||||
require_cookies_unlocked: bool = None
|
||||
|
|
@ -979,6 +980,7 @@ class WROLPiConfig(ConfigFile):
|
|||
ignore_outdated_zims=False,
|
||||
ignored_directories=['config', 'tags'],
|
||||
log_level='info',
|
||||
map_default_location=None,
|
||||
map_destination='map',
|
||||
nav_color='violet',
|
||||
require_cookies_unlocked=True,
|
||||
|
|
@ -1197,6 +1199,14 @@ class WROLPiConfig(ConfigFile):
|
|||
def archive_destination(self, value: str):
|
||||
self.update({'archive_destination': value})
|
||||
|
||||
@property
|
||||
def map_default_location(self) -> dict:
|
||||
return self._config.get('map_default_location')
|
||||
|
||||
@map_default_location.setter
|
||||
def map_default_location(self, value: dict):
|
||||
self.update({'map_default_location': value})
|
||||
|
||||
@property
|
||||
def map_destination(self) -> str:
|
||||
return self._config['map_destination']
|
||||
|
|
|
|||
|
|
@ -171,6 +171,7 @@ def get_settings(_: Request):
|
|||
'ignore_outdated_zims': wrolpi_config.ignore_outdated_zims,
|
||||
'ignored_directories': ignored_directories,
|
||||
'log_level': api_app.shared_ctx.log_level.value,
|
||||
'map_default_location': wrolpi_config.map_default_location,
|
||||
'map_destination': wrolpi_config.map_destination,
|
||||
'nav_color': wrolpi_config.nav_color,
|
||||
'media_directory': str(get_media_directory()), # Convert to string to avoid conversion to relative.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue