editor overhaul
This commit is contained in:
+78
-16
@@ -368,6 +368,9 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
const label = document.createElement('div');
|
||||
appendText(label, 'strong', routeName(route));
|
||||
appendText(label, 'small', routeSource(route) === 'local' ? ns.I18n.t("app.draft") : ns.I18n.t("editor.published-route"));
|
||||
if (routeSource(route) === 'local' && route.submissionStatus) {
|
||||
appendText(label, 'small', ns.I18n.t(`editor.${route.submissionStatus}`));
|
||||
}
|
||||
|
||||
const actions = document.createElement('div');
|
||||
actions.className = classes.iconRow;
|
||||
@@ -458,6 +461,36 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
setStatus('');
|
||||
// Local drafts are usable even while this request is waiting for a connection.
|
||||
void refreshPublicRoutes(requestGeneration);
|
||||
void refreshSubmittedRoutes(requestGeneration);
|
||||
}
|
||||
|
||||
async function refreshSubmittedRoutes(requestGeneration) {
|
||||
const submitted = localRouteSummaries().filter(route => route.serverRouteId);
|
||||
await Promise.allSettled(submitted.map(async route => {
|
||||
const existing = await findSubmittedRoute(route.serverRouteId);
|
||||
if (requestGeneration !== routeListGeneration) return;
|
||||
const latest = ns.LocalRoutes.get(route.id);
|
||||
if (!latest || String(latest.route.serverRouteId) !== String(route.serverRouteId)) return;
|
||||
const submissionStatus = submittedStatus(existing);
|
||||
if ((latest.route.submissionStatus || null) === submissionStatus) return;
|
||||
latest.route.submissionStatus = submissionStatus;
|
||||
const saved = ns.LocalRoutes.save(latest);
|
||||
if (state.currentSource === 'local' && routeId(state.currentRoute) === route.id) {
|
||||
state.currentRoute.submissionStatus = submissionStatus;
|
||||
renderLocalSubmissionStatus(saved.route);
|
||||
}
|
||||
}));
|
||||
if (requestGeneration !== routeListGeneration) return;
|
||||
state.routes = [...localRouteSummaries(), ...state.routes.filter(route => routeSource(route) === 'server')];
|
||||
renderRouteList();
|
||||
}
|
||||
|
||||
function renderLocalSubmissionStatus(route) {
|
||||
const uploaded = Boolean(route?.serverRouteId);
|
||||
const uploadButton = byId(ids.routeUpload);
|
||||
if (uploadButton) uploadButton.textContent = ns.I18n.t(uploaded ? 'editor.submitted' : 'editor.submit');
|
||||
const hint = uploaded ? 'editor.submitted-hint' : 'editor.draft-hint';
|
||||
byId(ids.routeActivated).textContent = ns.I18n.t(route?.submissionStatus ? `editor.${route.submissionStatus}-hint` : hint);
|
||||
}
|
||||
|
||||
async function refreshPublicRoutes(requestGeneration) {
|
||||
@@ -532,13 +565,9 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
|
||||
const uploadButton = byId(ids.routeUpload);
|
||||
if (state.currentSource === 'local') {
|
||||
const uploaded = Boolean(route?.serverRouteId);
|
||||
setHidden(uploadButton, false);
|
||||
setDisabled(uploadButton, false);
|
||||
if (uploadButton) uploadButton.textContent = uploaded ? ns.I18n.t("editor.submitted") : ns.I18n.t("editor.submit");
|
||||
byId(ids.routeActivated).textContent = uploaded
|
||||
? ns.I18n.t("editor.submitted-hint")
|
||||
: ns.I18n.t("editor.draft-hint");
|
||||
renderLocalSubmissionStatus(route);
|
||||
} else {
|
||||
setHidden(uploadButton, true);
|
||||
setDisabled(uploadButton, true);
|
||||
@@ -946,23 +975,56 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
return ns.LocalRoutes.save(routePackage);
|
||||
}
|
||||
|
||||
function submittedStatus(existing) {
|
||||
if (!existing) return 'removed';
|
||||
return existing.status === 'deleted' ? 'rejected' : null;
|
||||
}
|
||||
|
||||
async function findSubmittedRoute(id) {
|
||||
try {
|
||||
const payload = await readJson(`/routes/${encodeURIComponent(id)}?includeDeleted=true`);
|
||||
return payload.route || payload;
|
||||
} catch (error) {
|
||||
if (error.status === 404) return null;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
function clearSubmittedReferences(routePackage) {
|
||||
routePackage.route.serverRouteId = null;
|
||||
routePackage.route.uploadedAt = null;
|
||||
for (const poi of routePackage.pois || []) {
|
||||
delete poi.serverPoiId;
|
||||
delete poi.serverAudio;
|
||||
for (const image of poi.images || []) delete image.serverPictureId;
|
||||
}
|
||||
checkpointLocalUpload(routePackage);
|
||||
}
|
||||
|
||||
async function prepareServerRoute(routePackage) {
|
||||
const id = routePackage.route.serverRouteId;
|
||||
const replacedSubmission = Boolean(id || routePackage.route.submissionStatus);
|
||||
if (id) {
|
||||
const payload = await readJson(`/routes/${encodeURIComponent(id)}`);
|
||||
const existing = payload.route || payload;
|
||||
if (existing.activatedAt || existing.activated_at) {
|
||||
throw new Error(ns.I18n.t("editor.read-only-hint"));
|
||||
const existing = await findSubmittedRoute(id);
|
||||
if (!existing || existing.status === 'deleted') {
|
||||
// Preserve the old trash entry; submit a new draft with fresh references.
|
||||
routePackage.route.submissionStatus = submittedStatus(existing);
|
||||
clearSubmittedReferences(routePackage);
|
||||
} else {
|
||||
if (existing.activatedAt || existing.activated_at) {
|
||||
throw new Error(ns.I18n.t("editor.read-only-hint"));
|
||||
}
|
||||
await sendForm(`/routes/${encodeURIComponent(id)}`, 'PUT', localRouteUploadForm(routePackage));
|
||||
return { id, previousPois: existing.pois || [] };
|
||||
}
|
||||
await sendForm(`/routes/${encodeURIComponent(id)}`, 'PUT', localRouteUploadForm(routePackage));
|
||||
return { id, previousPois: existing.pois || [] };
|
||||
}
|
||||
const payload = await sendForm('/routes', 'POST', localRouteUploadForm(routePackage));
|
||||
const createdId = routeId(payload.route || payload);
|
||||
if (!createdId) throw new Error(ns.I18n.t("editor.error.send-route"));
|
||||
routePackage.route.serverRouteId = createdId;
|
||||
routePackage.route.submissionStatus = null;
|
||||
checkpointLocalUpload(routePackage);
|
||||
return { id: createdId, previousPois: [] };
|
||||
return { id: createdId, previousPois: [], recreated: replacedSubmission };
|
||||
}
|
||||
|
||||
async function syncLocalPoi(base, poi, index, routePackage) {
|
||||
@@ -1011,7 +1073,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
}
|
||||
|
||||
async function createServerRouteFromLocal(routePackage) {
|
||||
const { id, previousPois } = await prepareServerRoute(routePackage);
|
||||
const { id, previousPois, recreated } = await prepareServerRoute(routePackage);
|
||||
const base = `/routes/${encodeURIComponent(id)}/pois`;
|
||||
const orderedPois = [...(routePackage.pois || [])]
|
||||
.sort((left, right) => Number(left.sequence) - Number(right.sequence));
|
||||
@@ -1023,7 +1085,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
await syncLocalPictures(mediaBase, poi, oldPoi, routePackage);
|
||||
}
|
||||
await removeMissingServerItems(previousPois, orderedPois, 'serverPoiId', base);
|
||||
return id;
|
||||
return { id, recreated };
|
||||
}
|
||||
|
||||
async function uploadLocalRoute() {
|
||||
@@ -1039,7 +1101,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
const routePackage = ns.LocalRoutes.get(localId);
|
||||
if (!routePackage) throw new Error(ns.I18n.t("editor.error.draft-missing"));
|
||||
|
||||
const serverRouteId = await createServerRouteFromLocal(routePackage);
|
||||
const { id: serverRouteId, recreated } = await createServerRouteFromLocal(routePackage);
|
||||
const uploadedAt = new Date().toISOString();
|
||||
const saved = ns.LocalRoutes.save({
|
||||
...routePackage,
|
||||
@@ -1053,7 +1115,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
state.pois = saved.pois;
|
||||
fillRouteForm(state.currentRoute);
|
||||
await loadRoutes();
|
||||
setStatus(ns.I18n.t("editor.submit-success"));
|
||||
setStatus(ns.I18n.t(recreated ? 'editor.resubmit-success' : 'editor.submit-success'));
|
||||
} finally {
|
||||
// Keep acknowledged server IDs even if a later media request failed.
|
||||
const latest = ns.LocalRoutes.get(routeId(state.currentRoute));
|
||||
|
||||
Reference in New Issue
Block a user