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:
co-authored by
Claude Opus 4.8
parent
c5e34e32be
commit
150758b0bf
@@ -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]"
|
||||
|
||||
Reference in New Issue
Block a user