feat(ui): inline conflict resolution with Keep This button
Replace the 'Go to Conflicts Page' link with inline conflict resolution. Each conflict source now has a 'Keep This' button that resolves the conflict directly from the book detail page. - Conflict data now keyed by source name (koreader, web) instead of new/existing, with Source and Timestamp fields - Display percentage scaled correctly (* 100) - Fix page field name from current_page to page - Add conflict resolution JavaScript in book-detail.ts - Add 10-minute cooldown after resolution to prevent re-detection
This commit is contained in:
@@ -104,6 +104,7 @@ interface MetadataEditorState {
|
||||
generateCover(): Promise<void>;
|
||||
removeCover(): void;
|
||||
saveMetadata(): Promise<void>;
|
||||
resolveConflict(conflictId: string, winner: string): Promise<void>;
|
||||
}
|
||||
|
||||
Alpine.data("bookDetail", () => {
|
||||
@@ -149,6 +150,33 @@ Alpine.data("bookDetail", () => {
|
||||
hideProgressSyncModal,
|
||||
hideNotesModal,
|
||||
|
||||
async resolveConflict(conflictId: string, winner: string) {
|
||||
try {
|
||||
const resp = await fetch(`/api/conflicts/${conflictId}/resolve`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: getAuthHeader(),
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ winner }),
|
||||
});
|
||||
|
||||
if (!resp.ok) {
|
||||
const err = await resp.json().catch(() => ({}));
|
||||
throw new Error(err.error || err.message || "Failed to resolve conflict");
|
||||
}
|
||||
|
||||
hideProgressSyncModal();
|
||||
showToast("Conflict resolved successfully", "success");
|
||||
setTimeout(() => window.location.reload(), 500);
|
||||
} catch (e) {
|
||||
showToast(
|
||||
e instanceof Error ? e.message : "Failed to resolve conflict",
|
||||
"error",
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
init() {
|
||||
const link = document.getElementById("back-link");
|
||||
if (!link) return;
|
||||
|
||||
Reference in New Issue
Block a user