diff --git a/ui/src/components/library/LibraryResultPanel.css b/ui/src/components/library/LibraryResultPanel.css new file mode 100644 index 0000000..2641f7b --- /dev/null +++ b/ui/src/components/library/LibraryResultPanel.css @@ -0,0 +1,67 @@ +.library-result { + background: var(--c-ink-2); + border: 1px solid var(--c-ink-5); + border-radius: var(--r-3); + padding: var(--s-4); + margin-bottom: var(--s-3); + display: flex; + flex-direction: column; + gap: var(--s-3); +} + +.library-result.error { + border-color: var(--c-danger); +} + +.library-result header { + display: flex; + justify-content: space-between; + align-items: center; +} + +.library-result dl { + margin: 0; + display: grid; + grid-template-columns: max-content 1fr; + gap: var(--s-2) var(--s-4); + font-size: var(--fs-small); +} + +.library-result dl > div { + display: contents; +} + +.library-result dt { + color: var(--c-ink-9); +} + +.library-result dd { + margin: 0; +} + +.library-result dd.mono { + font-family: var(--font-mono); + word-break: break-all; +} + +.library-result details { + font-size: var(--fs-small); +} + +.library-result details summary { + cursor: pointer; + color: var(--c-warn); +} + +.library-result details ul { + margin: var(--s-2) 0 0; + padding-left: var(--s-5); +} + +.library-result-error { + margin: 0; + font-family: var(--font-mono); + font-size: var(--fs-small); + white-space: pre-wrap; + color: var(--c-danger); +} diff --git a/ui/src/screens/LibraryScreen.tsx b/ui/src/screens/LibraryScreen.tsx index 04d3731..ae7da7d 100644 --- a/ui/src/screens/LibraryScreen.tsx +++ b/ui/src/screens/LibraryScreen.tsx @@ -1,6 +1,7 @@ import { open, save } from "@tauri-apps/plugin-dialog"; import { useCallback, useMemo, useState } from "react"; +import "@/components/library/LibraryResultPanel.css"; import { FormatPickerModal } from "@/components/library/FormatPickerModal"; import { ipc, @@ -87,10 +88,23 @@ export function LibraryScreen({ const [pickerMode, setPickerMode] = useState<"export" | "import" | null>( null, ); + const [libraryBusy, setLibraryBusy] = useState<"export" | "import" | null>( + null, + ); const [libraryResult, setLibraryResult] = useState< - | { kind: "export"; report: LibraryExportReport } - | { kind: "import"; report: LibraryImportReport } - | { kind: "error"; message: string } + | { + kind: "export"; + format: FormatInfo; + destination: string; + report: LibraryExportReport; + } + | { + kind: "import"; + format: FormatInfo; + source: string; + report: LibraryImportReport; + } + | { kind: "error"; mode: "export" | "import"; message: string } | null >(null); @@ -102,20 +116,24 @@ export function LibraryScreen({ if (mode === "export") { const destination = await pickExportDestination(f); if (!destination) return; + setLibraryBusy("export"); const report = await ipc.libraryExport({ format: f.format, destination, }); - setLibraryResult({ kind: "export", report }); + setLibraryResult({ kind: "export", format: f, destination, report }); } else { const source = await pickImportSource(f); if (!source) return; + setLibraryBusy("import"); const report = await ipc.libraryImport({ format: f.format, source }); - setLibraryResult({ kind: "import", report }); + setLibraryResult({ kind: "import", format: f, source, report }); await refresh(); } } catch (e) { - setLibraryResult({ kind: "error", message: String(e) }); + setLibraryResult({ kind: "error", mode, message: String(e) }); + } finally { + setLibraryBusy(null); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [pickerMode]); @@ -199,17 +217,18 @@ export function LibraryScreen({ {filtered.length} @@ -264,61 +283,16 @@ export function LibraryScreen({
)} + {libraryBusy && ( ++ {libraryBusy === "export" ? "Exporting library…" : "Importing library…"} +
+ )} {libraryResult && ( -{libraryResult.report.format}
- {libraryResult.report.warnings.length > 0 && (
- <>. {libraryResult.report.warnings.length} warning(s)>
- )}
- .{" "}
-
- >
- )}
- {libraryResult.kind === "import" && (
- <>
- Imported {libraryResult.report.tracks_imported} new,{" "}
- {libraryResult.report.tracks_updated} updated,{" "}
- {libraryResult.report.tracks_skipped} skipped (
- {libraryResult.report.format}).{" "}
-
- >
- )}
- {libraryResult.kind === "error" && (
- <>
- Library operation failed: {libraryResult.message}{" "}
-
- >
- )}
- {result.message}
+