feat(ui): show file path and Reset to Scanned in the metadata editor
Release / build-and-push (push) Successful in 2m24s

Complete the metadata editor modal to match the backend override work:

- File Path: read-only, monospace field showing the resolved on-disk
  location (MediaDetail.FileLocation), next to Format and File Size, so
  admins can see exactly which file backs the record without leaving the
  editor. Renders empty for non-admins, who never receive the path.
- Reset to Scanned: new button beside Rescan. It confirms, then calls
  POST /api/media-items/:id/rescan?reset_overrides=true to drop all
  per-field user overrides and re-extract scanned defaults. Rescan alone
  keeps customizations; Reset discards them.
This commit is contained in:
John O'Keefe
2026-09-12 14:22:38 -04:00
parent 2df3ecbf36
commit 7a9a66fcc5
3 changed files with 92 additions and 14 deletions
+38
View File
@@ -96,6 +96,7 @@ interface MetadataEditorState {
coverAction: string;
saving: boolean;
rescanning: boolean;
resetting: boolean;
userRating: number;
ratingHover: number;
ratingSaving: boolean;
@@ -109,6 +110,7 @@ interface MetadataEditorState {
removeCover(): void;
saveMetadata(): Promise<void>;
rescanBook(): Promise<void>;
resetMetadata(): Promise<void>;
starFill(i: number): string;
ratingText(): string;
setRating(value: number): Promise<void>;
@@ -142,6 +144,7 @@ Alpine.data("bookDetail", () => {
coverAction: "keep",
saving: false,
rescanning: false,
resetting: false,
userRating: 0,
ratingHover: 0,
ratingSaving: false,
@@ -550,6 +553,41 @@ Alpine.data("bookDetail", () => {
}
},
async resetMetadata() {
if (this.resetting) return;
if (
!window.confirm(
"Reset all metadata to scanned defaults? Manual edits and custom covers will be discarded.",
)
) {
return;
}
this.resetting = true;
const mediaId = getMediaId();
try {
const resp = await fetch(
`/api/media-items/${mediaId}/rescan?reset_overrides=true`,
{
method: "POST",
headers: { Authorization: getAuthHeader() },
},
);
if (!resp.ok) {
const err = await resp.json().catch(() => ({}));
throw new Error(err.error || "Failed to reset metadata");
}
showToast("Metadata reset to scanned defaults", "success");
setTimeout(() => window.location.reload(), 500);
} catch (e) {
showToast(
e instanceof Error ? e.message : "Failed to reset metadata",
"error",
);
} finally {
this.resetting = false;
}
},
async searchEditorTags() {
const libraryId = document.body.getAttribute("data-library-id") || "";
if (!this.tagSearch || this.tagSearch.length < 2 || !libraryId) {