Phase 0: format-aware export/import scaffold#10
Merged
Conversation
… serato)
A new format module declares the four library-level export/import shapes
the user can pick from the UI, along with a TargetKind classifier
(file / directory / in-place) so callers can branch on how to ask for a
destination. FormatInfo is the IPC-facing descriptor (id, label,
target_kind, available) that the UI will use to render the format
selector.
Stable kebab-case ids ("cset", "rekordbox-xml", ...) are pinned by a
test so the IPC contract stays consistent. No plugins are registered
yet — that comes in subsequent commits.
A new api module defines: - Exporter / Importer object-safe traits taking a &Library and per-direction Options struct, returning a per-direction Report. - ExportOptions / ImportOptions carry destination + dry_run + an opaque serde_json::Value for format-specific knobs (USB volume label, conflict rules, etc.), so the IPC layer doesn't need a DTO per plugin. - ConflictStrategy (skip / update / replace) controls how an importer handles existing rows. - LibraryExportReport / LibraryImportReport keep the IPC schema on the Reports (utoipa::ToSchema) while leaving Options as internal-only types to avoid pulling PathBuf and serde_json::Value into the OpenAPI schema. No plugins implement these traits yet — that lands in subsequent commits.
PluginRegistry holds Arc<dyn Exporter> / Arc<dyn Importer> keyed by Format so the Tauri command layer can resolve "user picked rekordbox-xml" to a concrete plugin. Each direction (in/out) is registered independently: some plugins (rekordbox-usb) will only ship export at first, others (serato) read and write the same shape. export_formats() / import_formats() return FormatInfo with availability flags so the UI can render every known format and grey out the ones not yet implemented in this build. default_registry() returns an empty registry for now; per-format registration lands in Phase 1+ (rekordbox XML), Phase 6+ (serato), etc.
conduction-library's Library wraps a raw rusqlite::Connection without an internal Mutex, so every method (including read-only ones) needs &mut self. Aligning the Exporter / Importer trait signature with that lets the registered importers actually call repo methods without working around the borrow checker. Doc comment explains the rationale. The stub plugins in registry tests are updated to match.
Adds an ExportRegistryHandle state holding an Arc<PluginRegistry>
populated at boot from conduction_export::default_registry(), plus four
new Tauri commands:
- list_export_formats / list_import_formats
return Vec<FormatInfo> so the UI can render every known format with
an availability flag.
- library_export / library_import
take (format, path, ...) from the UI, build the matching
ExportOptions / ImportOptions, and dispatch through the registry to
the registered plugin. Until a plugin is registered for the chosen
format, the command returns a clear "no exporter/importer
registered for {id}" error so the UI can surface "coming soon".
The legacy setlist_export / setlist_import path (for .cset of a single
setlist) is untouched.
Adds two new toolbar buttons on the Library screen that open a modal listing every Format the backend knows about (cset / rekordbox-xml / rekordbox-usb / serato). Each row reads `available` from the registry and is rendered as a disabled "coming soon" row when no plugin is registered for that direction. Once a format is picked, a save/open dialog appropriate for the format's TargetKind (file vs directory) is opened and the result is dispatched through `library_export` / `library_import`. The new IPC types (FormatInfo, LibraryFormatId, ConflictStrategy, LibraryExportReport, LibraryImportReport) mirror the Rust side. CSS lives in a sibling file (FormatPickerModal.css) instead of App.css to keep the modal's styling colocated with its component.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phase 0 of the rekordbox / Serato / .cset interoperability work. Lands the
scaffold so subsequent phases (Phase 1+ for rekordbox XML, Phase 6+ for
Serato, etc.) only need to add plugins — the trait surface, the registry,
the Tauri commands, and the UI format picker are now in place.
Formatenum (cset/rekordbox-xml/rekordbox-usb/serato) with stable kebab-case ids pinned by a test, plus aTargetKindclassifier (file / directory / in-place).Exporter/Importertraits taking&mut Library(rusqlite needsthe mutable borrow even for reads) plus
ExportOptions/ImportOptionscarrying destination + dry_run + an opaqueserde_json::Valuefor format-specific knobs.PluginRegistrykeyed byFormatwith independent in/outregistration. Empty by default — plugins register from Phase 1+.
list_export_formats,list_import_formats,library_export,library_import. When no plugin is registered forthe chosen format, the command returns a clear
"no exporter registered for {id}"error.FormatPickerModaland two new toolbar buttons on the Library screen.Every format is rendered; unavailable ones come with a "coming soon"
badge. Once picked, the appropriate save/open dialog opens based on
TargetKindand dispatches the IPC call.The legacy
setlist_export/setlist_importpath for a singlesetlist's
.csetis untouched. The existingexport_preview/export_execute(rekordbox-USB stub) is also untouched — that will beunified into the new dispatch in Phase 11.
Test plan
cargo test --workspace— 5 new tests in conduction-export pass; no regressions.npx tsc --noEmitinui/passes."Export Library…" and "Import Library…" buttons open the modal with
all four rows greyed out. (Not part of CI; merge contingent on
manual smoke test.)