Fix Planetiler tmp-file format detection, add build progress and delete
Root cause of "planetiler exited with status 1: ... Unsupported format
tmp" (and likely the earlier unexplained "pmtiles exited with status
1"): Planetiler/go-pmtiles pick their output archive format from the
file extension, and the atomic-rename tmp files were named
"offline.pmtiles.tmp"/"terrain.pmtiles.tmp" — ".tmp" as the extension,
not ".pmtiles". Renamed to "offline.tmp.pmtiles"/"terrain.tmp.pmtiles".
Also, since build-status only ever said "running since X" with no way
to tell what it was actually doing:
- GET .../build-status now includes a `step` string ("fetching PL
(3/4) — done: SK, CZ — pending: HU", "tiling with planetiler", ...)
while a build is in progress.
- DELETE /api/offline-tiles / /api/terrain-tiles clear a built file,
its sidecar meta, and (for offline) the whole per-country download
cache — a manual "reclaim space" / "start over" action the region
picker's Apply never did on its own. DELETE
/api/offline-tiles/cache/:code clears just one country's cached
extract. All three are 409 while that kind's build is running, and
surfaced as a small "Delete" button on each row in the Offline data
panel.
This commit is contained in:
1 parent
2878270187
commit
b54020e23b
7 files changed
+327
-23
No files matched your search
@@ -17,12 +17,14 @@ function formatElapsed(ms) {
|
||||
return minutes > 0 ? `${minutes}m ${seconds}s` : `${seconds}s`;
|
||||
}
|
||||
|
||||
// "Building…" alone gave no way to tell a slow build from a stuck one —
|
||||
// elapsed time answers "is it alive" regardless of how long a given
|
||||
// selection takes.
|
||||
// "Building…" alone gave no way to tell a slow build from a stuck one, or
|
||||
// which of the current selection's sources it's actually working on right
|
||||
// now — elapsed time answers "is it alive", status.step (see
|
||||
// PmtilesBuilder.run_job) answers "doing what, and what's left".
|
||||
function formatRunning(status) {
|
||||
const elapsed = status.started_at ? ` (${formatElapsed(Date.now() - new Date(status.started_at).getTime())})` : "";
|
||||
return `Building…${elapsed}`;
|
||||
const step = status.step ? `: ${status.step}` : "";
|
||||
return `Building…${elapsed}${step}`;
|
||||
}
|
||||
|
||||
// Vendored square-cropped SVGs (public/vendor/flag-icons/, MIT, see
|
||||
@@ -131,9 +133,10 @@ class RegionPicker {
|
||||
// one class covers both rather than writing the same fetch/poll logic
|
||||
// twice.
|
||||
class DataFileRow {
|
||||
constructor({ label, statusUrl, buildUrl, buildStatusUrl, checkUpdateUrl, formatMeta }) {
|
||||
constructor({ label, statusUrl, deleteUrl, buildUrl, buildStatusUrl, checkUpdateUrl, formatMeta }) {
|
||||
this._label = label;
|
||||
this._statusUrl = statusUrl;
|
||||
this._deleteUrl = deleteUrl;
|
||||
this._buildUrl = buildUrl;
|
||||
this._buildStatusUrl = buildStatusUrl;
|
||||
this._checkUpdateUrl = checkUpdateUrl;
|
||||
@@ -144,10 +147,15 @@ class DataFileRow {
|
||||
const row = document.createElement("div");
|
||||
row.className = "offline-data-panel__row";
|
||||
row.innerHTML = `
|
||||
<strong>${this._label}</strong>
|
||||
<div class="offline-data-panel__row-head">
|
||||
<strong>${this._label}</strong>
|
||||
<button type="button" class="offline-data-panel__delete" hidden>Delete</button>
|
||||
</div>
|
||||
<p class="offline-data-panel__status">Checking…</p>
|
||||
`;
|
||||
this._statusEl = row.querySelector(".offline-data-panel__status");
|
||||
this._deleteButton = row.querySelector(".offline-data-panel__delete");
|
||||
this._deleteButton.addEventListener("click", () => this._delete());
|
||||
container.appendChild(row);
|
||||
this._refreshStatus();
|
||||
}
|
||||
@@ -163,14 +171,39 @@ class DataFileRow {
|
||||
|
||||
if (!data.available) {
|
||||
this._statusEl.textContent = "Not generated yet.";
|
||||
this._deleteButton.hidden = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const updated = new Date(data.mtime).toLocaleString([], { dateStyle: "short", timeStyle: "short" });
|
||||
this._statusEl.textContent = `${formatBytes(data.size)} · updated ${updated}${this._formatMeta(data.meta)}`;
|
||||
this._deleteButton.hidden = !isLoggedIn();
|
||||
this._checkUpdate();
|
||||
}
|
||||
|
||||
// Deletes the built file (and, for offline.pmtiles, its whole per-country
|
||||
// download cache — see PmtilesBuilder.delete_offline_data) so the row
|
||||
// goes back to "Not generated yet." — a manual way to reclaim space or
|
||||
// force a completely fresh rebuild, since Apply alone never removes
|
||||
// anything already on disk.
|
||||
async _delete() {
|
||||
if (!window.confirm(`Delete ${this._label.toLowerCase()}? This can't be undone.`)) return;
|
||||
|
||||
this._deleteButton.disabled = true;
|
||||
try {
|
||||
const response = await fetch(this._deleteUrl, { method: "DELETE" });
|
||||
const data = await response.json().catch(() => ({}));
|
||||
if (!response.ok) throw new Error(data.error || `could not delete: ${response.status}`);
|
||||
} catch (err) {
|
||||
window.alert(err.message);
|
||||
return;
|
||||
} finally {
|
||||
this._deleteButton.disabled = false;
|
||||
}
|
||||
|
||||
this._refreshStatus();
|
||||
}
|
||||
|
||||
// Separate from _refreshStatus's own fetch (and only called once, right
|
||||
// after — not polled): this one reaches an external service (Geofabrik
|
||||
// or Mapterhorn's manifest, see lib/maptool/pmtiles_builder.rb), so it's
|
||||
@@ -249,6 +282,7 @@ export class OfflineDataControl {
|
||||
new DataFileRow({
|
||||
label: "Offline map data",
|
||||
statusUrl: "/api/offline-tiles",
|
||||
deleteUrl: "/api/offline-tiles",
|
||||
buildUrl: "/api/offline-tiles/build",
|
||||
buildStatusUrl: "/api/offline-tiles/build-status",
|
||||
checkUpdateUrl: "/api/offline-tiles/check-update",
|
||||
@@ -257,6 +291,7 @@ export class OfflineDataControl {
|
||||
new DataFileRow({
|
||||
label: "Offline terrain data",
|
||||
statusUrl: "/api/terrain-tiles",
|
||||
deleteUrl: "/api/terrain-tiles",
|
||||
buildUrl: "/api/terrain-tiles/build",
|
||||
buildStatusUrl: "/api/terrain-tiles/build-status",
|
||||
checkUpdateUrl: "/api/terrain-tiles/check-update",
|
||||
|
||||
Reference in new issue
Block a user