Add bounding-box region picker to the API Server plugin panel

Give the superadmin Plugins panel the same OpenSky "Default bounding
box" experience as the Web App: a grouped preset dropdown (World /
Continents / Countries) plus a Custom option for manual
lamin,lomin,lamax,lomax entry.

Introduce a "bbox" config-field type (rendering hint only; unknown
types still degrade to a text input) and mark the OpenSky bbox field
with it. Values that match a preset render as the region name.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
tajniak81
2026-07-13 23:28:23 +02:00
co-authored by Claude Opus 4.8
parent c5e34e32be
commit 150758b0bf
5 changed files with 84 additions and 19 deletions
+65
View File
@@ -176,6 +176,54 @@ const pluginsMsg = ref("");
const editingPlugin = ref(""); // name whose config form is expanded
const editConfig = ref({}); // working copy of the expanded plugin's config
const busyPlugin = ref(""); // name of a plugin with an in-flight action
// Predefined bounding boxes for the "bbox" config field (lamin,lomin,lamax,lomax).
// Mirrors the Web App picker; a "Custom…" entry falls back to manual coordinates.
// Europe is the default (kept in sync with the OpenSky plugin's defaultBBox).
const 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 BBOX_FLAT = BBOX_GROUPS.flatMap((g) => g.options);
// Normalise to "n1,n2,n3,n4" so matching ignores spacing / trailing zeros.
function normBbox(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(",");
}
// Field keys currently in manual ("Custom…") mode, so the text input is shown.
const bboxCustom = ref({});
// The <select> value for a bbox field: a matching preset, or "__custom__".
function bboxSelectValue(key) {
if (bboxCustom.value[key]) return "__custom__";
const norm = normBbox(editConfig.value[key]);
const match = norm && BBOX_FLAT.find((o) => normBbox(o.value) === norm);
return match ? match.value : "__custom__";
}
function setBboxSelect(key, v) {
if (v === "__custom__") { bboxCustom.value = { ...bboxCustom.value, [key]: true }; return; }
bboxCustom.value = { ...bboxCustom.value, [key]: false };
editConfig.value[key] = v;
}
const newExt = ref({ name: "", baseURL: "", provider: "" });
const newExtErr = ref("");
const newExtBusy = ref(false);
@@ -278,6 +326,7 @@ function startPluginEdit(p) {
if (cfg[f.key] === undefined && f.default) cfg[f.key] = f.default;
}
editConfig.value = cfg;
bboxCustom.value = {}; // start on the preset dropdown; non-preset values imply Custom
}
async function savePluginConfig(p) {
@@ -1273,6 +1322,22 @@ const deviceApi = [
<select v-if="f.type === 'select'" v-model="editConfig[f.key]" class="pv-input">
<option v-for="o in f.options" :key="o.value" :value="o.value">{{ o.label }}</option>
</select>
<template v-else-if="f.type === 'bbox'">
<select :value="bboxSelectValue(f.key)" class="pv-input" @change="setBboxSelect(f.key, $event.target.value)">
<optgroup v-for="g in 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="bboxSelectValue(f.key) === '__custom__'"
v-model="editConfig[f.key]"
type="text"
class="pv-input font-mono"
autocomplete="off"
placeholder="50.5,3.2,53.7,7.3"
/>
</template>
<input
v-else
v-model="editConfig[f.key]"