From 4b8ab2913baa4dddc9e9ea463b9bed720b45343c Mon Sep 17 00:00:00 2001 From: Open TAK server Date: Thu, 16 Apr 2026 15:30:40 +0000 Subject: [PATCH 1/7] feat: add admin Settings page for map defaults Co-Authored-By: Claude Sonnet 4.6 --- src/pages/Settings.tsx | 134 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 src/pages/Settings.tsx diff --git a/src/pages/Settings.tsx b/src/pages/Settings.tsx new file mode 100644 index 0000000..440a892 --- /dev/null +++ b/src/pages/Settings.tsx @@ -0,0 +1,134 @@ +import React, { useEffect, useState } from 'react'; +import { + Button, + NumberInput, + Paper, + Select, + Title, +} from '@mantine/core'; +import { IconCheck, IconX } from '@tabler/icons-react'; +import { notifications } from '@mantine/notifications'; +import axios from '../axios_config'; +import { apiRoutes } from '../apiRoutes'; +import { t } from 'i18next'; + +const LAYER_OPTIONS = [ + 'OSM', + 'Google Streets', + 'Google Hybrid', + 'Google Terrain', + 'ESRI World Imagery (Clarity) Beta', + 'ESRI World Topo', +]; + +export default function Settings() { + const [lat, setLat] = useState(10); + const [lon, setLon] = useState(0); + const [zoom, setZoom] = useState(3); + const [layer, setLayer] = useState('OSM'); + const [loading, setLoading] = useState(true); + + useEffect(() => { + axios.get(apiRoutes.adminSettings) + .then(r => { + if (r.status === 200) { + setLat(r.data.OTS_MAP_DEFAULT_LAT); + setLon(r.data.OTS_MAP_DEFAULT_LON); + setZoom(r.data.OTS_MAP_DEFAULT_ZOOM); + setLayer(r.data.OTS_MAP_DEFAULT_LAYER); + } + setLoading(false); + }) + .catch(err => { + setLoading(false); + if (err.response && err.response.status === 404) { + notifications.show({ + title: t('Settings unavailable'), + message: t('This feature requires a newer version of OpenTAKServer'), + icon: , + color: 'orange', + }); + } else { + notifications.show({ + title: t('Failed to load settings'), + message: err.response?.data?.error || String(err), + icon: , + color: 'red', + }); + } + }); + }, []); + + function saveSettings() { + axios.put(apiRoutes.adminSettings, { + OTS_MAP_DEFAULT_LAT: lat, + OTS_MAP_DEFAULT_LON: lon, + OTS_MAP_DEFAULT_ZOOM: zoom, + OTS_MAP_DEFAULT_LAYER: layer, + }).then(r => { + if (r.status === 200) { + notifications.show({ + message: t('Settings saved'), + icon: , + color: 'green', + }); + } + }).catch(err => { + notifications.show({ + title: t('Failed to save settings'), + message: err.response?.data?.error || String(err), + icon: , + color: 'red', + }); + }); + } + + return ( + <> + {t('Map Defaults')} + + setLat(Number(v))} + min={-90} + max={90} + decimalScale={6} + step={0.1} + mb="md" + disabled={loading} + /> + setLon(Number(v))} + min={-180} + max={180} + decimalScale={6} + step={0.1} + mb="md" + disabled={loading} + /> + setZoom(Number(v))} + min={1} + max={20} + mb="md" + disabled={loading} + /> + setLayer(v || 'OSM')} - data={LAYER_OPTIONS} - mb="md" - disabled={loading} - allowDeselect={false} - /> - - + + + + setLat(Number(v))} + min={-90} + max={90} + decimalScale={6} + step={0.1} + mb="md" + disabled={loading} + /> + setLon(Number(v))} + min={-180} + max={180} + decimalScale={6} + step={0.1} + mb="md" + disabled={loading} + /> + setZoom(Number(v))} + min={1} + max={20} + mb="md" + disabled={loading} + /> +