Add region picker for OpenSky default bounding box
Replace the free-text bounding-box field in the Web App OpenSky settings with a grouped preset picker (World / Continents / Countries) plus a Custom option that keeps the manual lamin,lomin,lamax,lomax entry. Saved values that match a preset render as the friendly region name, including in the locked/inherited display. Change the API Server default bounding box to Europe to match the new "Europe" preset. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
6a007fd25e
commit
c5e34e32be
@@ -25,8 +25,10 @@ import (
|
||||
const (
|
||||
apiBase = "https://opensky-network.org/api"
|
||||
tokenURL = "https://auth.opensky-network.org/auth/realms/opensky-network/protocol/openid-connect/token"
|
||||
// Small default bounding box (Netherlands) keeps the health probe cheap.
|
||||
defaultBBox = "50.5,3.2,53.7,7.3" // lamin,lomin,lamax,lomax
|
||||
// Default bounding box covers Europe; matches the "Europe" preset offered in
|
||||
// the Web App bounding-box picker. Users can narrow it (e.g. a single country)
|
||||
// to reduce per-query credit cost.
|
||||
defaultBBox = "34,-25,72,45" // lamin,lomin,lamax,lomax (Europe)
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
-20
File diff suppressed because one or more lines are too long
+20
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+2
-2
@@ -35,8 +35,8 @@
|
||||
})()
|
||||
</script>
|
||||
<title>PilotVault — Control Panel</title>
|
||||
<script type="module" crossorigin src="./assets/index-BdIdzNiz.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="./assets/index-CYeDXsw9.css">
|
||||
<script type="module" crossorigin src="./assets/index-CznFJTz4.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="./assets/index-D0ghlckk.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
@@ -206,6 +206,68 @@ const OS_SCOPE_OPTS = [
|
||||
{ value: 'org', label: 'Organization', icon: 'users' },
|
||||
]
|
||||
|
||||
// Predefined bounding boxes (lamin,lomin,lamax,lomax). The picker offers these
|
||||
// plus a "Custom…" option that reveals the free-text field for manual entry.
|
||||
// Europe is the default (kept in sync with the API Server's defaultBBox).
|
||||
const OS_BBOX_GROUPS = [
|
||||
{ label: 'World', options: [
|
||||
{ value: '-90,-180,90,180', label: 'World' },
|
||||
] },
|
||||
{ label: 'Continents', options: [
|
||||
{ value: '34,-25,72,45', label: 'Europe' },
|
||||
{ value: '-35,-18,38,52', label: 'Africa' },
|
||||
{ value: '5,25,82,180', label: 'Asia' },
|
||||
{ value: '7,-168,72,-52', label: 'North America' },
|
||||
{ value: '-56,-82,13,-34', label: 'South America' },
|
||||
{ value: '-48,110,-10,180', label: 'Oceania' },
|
||||
] },
|
||||
{ label: 'Countries', options: [
|
||||
{ value: '49,14.1,54.9,24.2', label: 'Poland' },
|
||||
{ value: '50.5,3.2,53.7,7.3', label: 'Netherlands' },
|
||||
{ value: '47.2,5.8,55.1,15.1', label: 'Germany' },
|
||||
{ value: '41.3,-5.2,51.1,9.6', label: 'France' },
|
||||
{ value: '49.9,-8.7,59,1.8', label: 'United Kingdom' },
|
||||
{ value: '35.9,-9.6,43.8,3.4', label: 'Spain' },
|
||||
{ value: '36.6,6.6,47.1,18.6', label: 'Italy' },
|
||||
{ value: '24,-125,49.5,-66.5', label: 'United States' },
|
||||
] },
|
||||
]
|
||||
const OS_BBOX_FLAT = OS_BBOX_GROUPS.flatMap((g) => g.options)
|
||||
|
||||
// Normalise a bbox string to "n1,n2,n3,n4" so preset matching ignores spacing
|
||||
// and trailing-zero differences; returns '' when it isn't four valid numbers.
|
||||
function osNormBbox(s) {
|
||||
const parts = String(s || '').split(',').map((x) => x.trim())
|
||||
if (parts.length !== 4) return ''
|
||||
const nums = parts.map(Number)
|
||||
if (nums.some((n) => Number.isNaN(n))) return ''
|
||||
return nums.join(',')
|
||||
}
|
||||
// Friendly label for a bbox value when it matches a preset (else '').
|
||||
function osBboxLabel(v) {
|
||||
const norm = osNormBbox(v)
|
||||
const m = norm && OS_BBOX_FLAT.find((o) => osNormBbox(o.value) === norm)
|
||||
return m ? m.label : ''
|
||||
}
|
||||
|
||||
// Manual-entry toggle: sticky once the user picks "Custom…", and implied when
|
||||
// the current value doesn't match any preset.
|
||||
const osBboxCustom = ref(false)
|
||||
const osBboxPreset = computed({
|
||||
get() {
|
||||
if (osBboxCustom.value) return '__custom__'
|
||||
const norm = osNormBbox(osForm.bbox)
|
||||
const match = norm && OS_BBOX_FLAT.find((o) => osNormBbox(o.value) === norm)
|
||||
return match ? match.value : '__custom__'
|
||||
},
|
||||
set(v) {
|
||||
if (v === '__custom__') { osBboxCustom.value = true; return }
|
||||
osBboxCustom.value = false
|
||||
osForm.bbox = v
|
||||
},
|
||||
})
|
||||
const osBboxManual = computed(() => osBboxPreset.value === '__custom__')
|
||||
|
||||
// Superadmin edits the global layer in the API panel — read-only in the Web App.
|
||||
const osReadOnly = computed(() => os.isSuperadmin)
|
||||
// The scope key currently in view (superadmin always sees the single read-only view).
|
||||
@@ -233,6 +295,8 @@ function fillOsForm() {
|
||||
osForm.clientSecret = osField('clientSecret').own || ''
|
||||
osForm.plan = osField('plan').own || ''
|
||||
osForm.bbox = osField('bbox').own || ''
|
||||
// Show the preset dropdown; the getter falls back to Custom for non-preset values.
|
||||
osBboxCustom.value = false
|
||||
}
|
||||
|
||||
function applyOpenSkyView(body) {
|
||||
@@ -1433,14 +1497,22 @@ onBeforeUnmount(() => {
|
||||
</Row>
|
||||
|
||||
<!-- bounding box -->
|
||||
<Row title="Default bounding box" desc="lamin,lomin,lamax,lomax — used for live queries and the health probe." keywords="bounding box bbox area">
|
||||
<Row title="Default bounding box" desc="Pick a region, or choose Custom to enter lamin,lomin,lamax,lomax by hand — used for live queries and the health probe." keywords="bounding box bbox area region country continent world europe custom coordinates">
|
||||
<template v-if="osLocked('bbox')">
|
||||
<span class="inline-flex items-center gap-2 font-mono text-sm text-ink">
|
||||
{{ osField('bbox').effective || '—' }}
|
||||
{{ osBboxLabel(osField('bbox').effective) || osField('bbox').effective || '—' }}
|
||||
<span v-if="osSourceLabel('bbox')" class="inline-flex items-center gap-1 rounded-full bg-surface-2 px-2 py-0.5 text-[10px] font-semibold text-ink-secondary"><Icon name="lock" :size="10" />{{ osSourceLabel('bbox') }}</span>
|
||||
</span>
|
||||
</template>
|
||||
<input v-else v-model="osForm.bbox" class="field w-64 font-mono" placeholder="50.5,3.2,53.7,7.3" />
|
||||
<div v-else class="flex flex-col items-end gap-2">
|
||||
<select v-model="osBboxPreset" class="field w-64">
|
||||
<optgroup v-for="g in OS_BBOX_GROUPS" :key="g.label" :label="g.label">
|
||||
<option v-for="o in g.options" :key="o.value" :value="o.value">{{ o.label }}</option>
|
||||
</optgroup>
|
||||
<option value="__custom__">Custom…</option>
|
||||
</select>
|
||||
<input v-if="osBboxManual" v-model="osForm.bbox" class="field w-64 font-mono" placeholder="50.5,3.2,53.7,7.3" />
|
||||
</div>
|
||||
</Row>
|
||||
|
||||
<!-- client id -->
|
||||
|
||||
Reference in New Issue
Block a user