Add conflict resolution diff UI and app branding
This commit is contained in:
96
apps/server/internal/httpserver/static/sync.js
Normal file
96
apps/server/internal/httpserver/static/sync.js
Normal file
@@ -0,0 +1,96 @@
|
||||
(function () {
|
||||
if (!window.MDHubCache) {
|
||||
return;
|
||||
}
|
||||
|
||||
function normalizeDocPath(path) {
|
||||
if (!path) return "";
|
||||
return path.replace(/^\/+/, "");
|
||||
}
|
||||
|
||||
async function postDocument(path, content, baseHash) {
|
||||
const response = await fetch("/api/documents/" + normalizeDocPath(path), {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ content: content, baseHash: baseHash || "" }),
|
||||
});
|
||||
|
||||
const payload = await response.json().catch(function () {
|
||||
return {};
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 409) {
|
||||
const conflict = new Error("document conflict");
|
||||
conflict.name = "DocumentConflictError";
|
||||
conflict.details = payload;
|
||||
throw conflict;
|
||||
}
|
||||
throw new Error("save failed");
|
||||
}
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
async function saveDocument(path, content, baseHash) {
|
||||
const normalizedPath = window.MDHubCache.normalizePath("/docs/" + normalizeDocPath(path));
|
||||
|
||||
try {
|
||||
const result = await postDocument(path, content, baseHash);
|
||||
await window.MDHubCache.deletePendingEdit(normalizedPath);
|
||||
return {
|
||||
status: "saved",
|
||||
result: result,
|
||||
};
|
||||
} catch (error) {
|
||||
if (error.name === "DocumentConflictError") {
|
||||
await window.MDHubCache.putPendingEdit(normalizedPath, content, baseHash);
|
||||
await window.MDHubCache.markPendingEditConflict(normalizedPath, error.details);
|
||||
return {
|
||||
status: "conflict",
|
||||
conflict: error.details,
|
||||
};
|
||||
}
|
||||
await window.MDHubCache.putPendingEdit(normalizedPath, content, baseHash);
|
||||
return {
|
||||
status: "queued",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async function syncPending() {
|
||||
if (!navigator.onLine) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pending = await window.MDHubCache.getPendingEdits();
|
||||
pending.sort(function (a, b) {
|
||||
return (a.updatedAt || 0) - (b.updatedAt || 0);
|
||||
});
|
||||
|
||||
for (const edit of pending) {
|
||||
try {
|
||||
await postDocument(edit.path.replace(/^\/docs\//, ""), edit.content, edit.baseHash);
|
||||
await window.MDHubCache.deletePendingEdit(edit.path);
|
||||
} catch (error) {
|
||||
if (error.name === "DocumentConflictError") {
|
||||
await window.MDHubCache.markPendingEditConflict(edit.path, error.details);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("online", function () {
|
||||
syncPending().catch(function () {});
|
||||
});
|
||||
|
||||
syncPending().catch(function () {});
|
||||
|
||||
window.MDHubSync = {
|
||||
saveDocument: saveDocument,
|
||||
syncPending: syncPending,
|
||||
};
|
||||
})();
|
||||
Reference in New Issue
Block a user