Add adjustable probe area for OpenSky test connection
Let the OpenSky health probe run over a chosen bounding box without touching the saved default, so its credit cost (which scales with area) can be checked cheaply. - Backend: the plugin health endpoint (panel Check) and the OpenSky health endpoint (Web App Test connection) accept an optional ?bbox=, validated with validBBox and applied to a transient probe instance; both BFF and API forward it. Saved config is untouched. - API panel: a "Probe area" picker beside each bbox-capable plugin's Check button — saved default, all countries (grouped by continent), or Custom. Adds a compact pv-input-sm style. - Web App: a "Test area" picker beside Test connection, using the full country list (new countryGroups() helper) plus Custom. This is where the probe is authenticated and the credit cost is shown. Builds pass across both Go modules and both frontends. Panel picker verified live (186 options, defaults to saved default). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
763cc67081
commit
15bff7f517
17 files changed
+233
-53
No files matched your search
@@ -217,6 +217,41 @@ function setBboxSelect(key, v) {
|
||||
bboxCustom.value = { ...bboxCustom.value, [key]: false };
|
||||
editConfig.value[key] = v;
|
||||
}
|
||||
|
||||
// ---- Probe bounding box (Check-only override) ----------------------------
|
||||
// A plugin can be test-probed over a specific area without touching its saved
|
||||
// config, so OpenSky's credit cost (which scales with box size) can be checked
|
||||
// cheaply. State is per plugin name; empty value = "saved default" (no override).
|
||||
const probeBbox = ref({}); // name -> bbox string ("" = saved default)
|
||||
const probeBboxCustom = ref({}); // name -> in "Custom…" mode
|
||||
function pluginHasBbox(p) {
|
||||
return !!(p.configFields && p.configFields.some((f) => f.type === "bbox"));
|
||||
}
|
||||
function probeBboxSelectValue(name) {
|
||||
if (probeBboxCustom.value[name]) return "__custom__";
|
||||
const v = probeBbox.value[name];
|
||||
if (!v) return "__default__";
|
||||
const norm = normBbox(v);
|
||||
const match = norm && BBOX_FLAT.find((o) => normBbox(o.value) === norm);
|
||||
return match ? match.value : "__custom__";
|
||||
}
|
||||
function setProbeBbox(name, v) {
|
||||
if (v === "__default__") {
|
||||
probeBboxCustom.value = { ...probeBboxCustom.value, [name]: false };
|
||||
probeBbox.value = { ...probeBbox.value, [name]: "" };
|
||||
return;
|
||||
}
|
||||
if (v === "__custom__") {
|
||||
probeBboxCustom.value = { ...probeBboxCustom.value, [name]: true };
|
||||
return;
|
||||
}
|
||||
probeBboxCustom.value = { ...probeBboxCustom.value, [name]: false };
|
||||
probeBbox.value = { ...probeBbox.value, [name]: v };
|
||||
}
|
||||
function setProbeBboxCustom(name, v) {
|
||||
probeBbox.value = { ...probeBbox.value, [name]: v };
|
||||
}
|
||||
|
||||
const newExt = ref({ name: "", baseURL: "", provider: "" });
|
||||
const newExtErr = ref("");
|
||||
const newExtBusy = ref(false);
|
||||
@@ -348,7 +383,10 @@ async function checkPlugin(p) {
|
||||
busyPlugin.value = p.name;
|
||||
pluginsMsg.value = "";
|
||||
try {
|
||||
const r = await fetch(`/api/admin/plugins/${encodeURIComponent(p.name)}/health`, {
|
||||
// A probe area (if chosen) overrides the saved bbox for this check only.
|
||||
const area = (probeBbox.value[p.name] || "").trim();
|
||||
const qs = area ? `?bbox=${encodeURIComponent(area)}` : "";
|
||||
const r = await fetch(`/api/admin/plugins/${encodeURIComponent(p.name)}/health${qs}`, {
|
||||
method: "POST",
|
||||
headers: authHeaders(),
|
||||
});
|
||||
@@ -1303,6 +1341,27 @@ const deviceApi = [
|
||||
{{ p.enabled ? "Enabled" : "Disabled" }}
|
||||
</button>
|
||||
<button v-if="p.configFields && p.configFields.length" class="pv-btn-sec pv-btn-sm" @click="startPluginEdit(p)">Configure</button>
|
||||
<template v-if="pluginHasBbox(p)">
|
||||
<select
|
||||
:value="probeBboxSelectValue(p.name)"
|
||||
class="pv-input pv-input-sm max-w-[11rem]"
|
||||
title="Bounding box used for this Check — smaller areas cost fewer OpenSky credits"
|
||||
@change="setProbeBbox(p.name, $event.target.value)"
|
||||
>
|
||||
<option value="__default__">Probe: saved default</option>
|
||||
<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="probeBboxSelectValue(p.name) === '__custom__'"
|
||||
:value="probeBbox[p.name] || ''"
|
||||
class="pv-input pv-input-sm w-40 font-mono"
|
||||
placeholder="lamin,lomin,lamax,lomax"
|
||||
@input="setProbeBboxCustom(p.name, $event.target.value)"
|
||||
/>
|
||||
</template>
|
||||
<button class="pv-btn-sec pv-btn-sm" :disabled="busyPlugin === p.name" @click="checkPlugin(p)">Check</button>
|
||||
<button v-if="p.kind === 'external'" class="pv-btn-sec pv-btn-sm !text-danger" :disabled="busyPlugin === p.name" @click="removePlugin(p)">Remove</button>
|
||||
</div>
|
||||
|
||||
@@ -210,6 +210,15 @@ h1, h2, h3 {
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
|
||||
/* Compact input to sit inline with pv-btn-sm (auto width, not full-width) */
|
||||
@utility pv-input-sm {
|
||||
width: auto;
|
||||
height: 32px;
|
||||
padding: 0 8px;
|
||||
font-size: 0.75rem;
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
|
||||
/* Primary button */
|
||||
@utility pv-btn {
|
||||
display: inline-flex;
|
||||
|
||||
Reference in new issue
Block a user