import { PLUGIN_ICON } from "/js/icons.js";
import { notifyGpxStoreChanged } from "/js/panels.js";
// A sidebar flyout listing whatever import plugins are on disk (see
// lib/maptool/plugins.rb for the contract) — each one just a "Run for
// this area" button using the current map viewport as the bbox, so there's
// no separate area-picker to build: pan/zoom to where you want, click Run.
// Only ever mounted when logged in (see map.js) — same "hide the
// write-only affordance" story as NotesControl, since the only thing this
// panel does is a login-gated write.
export class PluginsControl {
constructor(map) {
this._map = map;
}
mount(sidebar) {
this._container = document.createElement("div");
this._container.className = "sidebar-item";
this._container.innerHTML = `
`;
return;
}
this._list.innerHTML = "";
plugins.forEach((plugin) => this._list.appendChild(this._renderItem(plugin)));
}
_renderItem(plugin) {
const li = document.createElement("li");
li.className = "plugins-panel__item";
li.innerHTML = `
`;
li.querySelector(".plugins-panel__label").textContent = plugin.label;
const button = li.querySelector(".plugins-panel__run");
const status = li.querySelector(".plugins-panel__status");
button.addEventListener("click", () => this._run(plugin, button, status));
return li;
}
async _run(plugin, button, status) {
button.disabled = true;
status.textContent = "Running…";
try {
const bounds = this._map.getBounds();
const body = new URLSearchParams({
south: bounds.getSouth(),
west: bounds.getWest(),
north: bounds.getNorth(),
east: bounds.getEast(),
});
const response = await fetch(`/api/plugins/${encodeURIComponent(plugin.name)}/run`, { method: "POST", body });
// Every app.rb response on this route is JSON, success or error —
// the catch below is only for an infra-level failure in front of it
// (a proxy's own HTML error page, a dropped connection) that never
// reached app.rb at all.
const data = await response.json().catch(() => ({}));
if (!response.ok) throw new Error(data.error || `run failed: ${response.status}`);
notifyGpxStoreChanged(data.path);
status.textContent = "Done";
status.classList.remove("plugins-panel__status--error");
} catch (err) {
// Plugins::RunError's message (e.g. "plugin exited with status 1")
// reaches here as `data.error` above — nothing about a plugin run
// failure gets logged server-side (app.rb turns it into a plain 502
// JSON response, not an exception), so showing that message directly
// is the only way to see why, short of SSHing in to reproduce it.
status.textContent = err.message;
status.classList.add("plugins-panel__status--error");
} finally {
button.disabled = false;
}
}
}