mirror of
https://github.com/litruv/AudioSort.git
synced 2026-07-25 03:06:02 +10:00
fix file by id in the parent field
This commit is contained in:
@@ -225,6 +225,9 @@ export class MainApp {
|
|||||||
|
|
||||||
ipcMain.handle(IPC_CHANNELS.libraryScan, async () => this.requireLibrary().scanLibrary());
|
ipcMain.handle(IPC_CHANNELS.libraryScan, async () => this.requireLibrary().scanLibrary());
|
||||||
ipcMain.handle(IPC_CHANNELS.libraryList, async () => this.requireLibrary().listFiles());
|
ipcMain.handle(IPC_CHANNELS.libraryList, async () => this.requireLibrary().listFiles());
|
||||||
|
ipcMain.handle(IPC_CHANNELS.libraryGetById, async (_event: IpcMainInvokeEvent, fileId: number) =>
|
||||||
|
this.requireLibrary().getFileById(fileId)
|
||||||
|
);
|
||||||
ipcMain.handle(IPC_CHANNELS.libraryDuplicates, async () => this.requireLibrary().listDuplicates());
|
ipcMain.handle(IPC_CHANNELS.libraryDuplicates, async () => this.requireLibrary().listDuplicates());
|
||||||
ipcMain.handle(IPC_CHANNELS.searchQuery, async (_event: IpcMainInvokeEvent, query: string) =>
|
ipcMain.handle(IPC_CHANNELS.searchQuery, async (_event: IpcMainInvokeEvent, query: string) =>
|
||||||
this.requireSearch().search(query)
|
this.requireSearch().search(query)
|
||||||
|
|||||||
@@ -214,6 +214,20 @@ export class LibraryService {
|
|||||||
return this.database.listFiles();
|
return this.database.listFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to resolve a file summary by id. Returns null when the record no longer exists.
|
||||||
|
*/
|
||||||
|
public getFileById(fileId: number): AudioFileSummary | null {
|
||||||
|
try {
|
||||||
|
return this.database.getFileById(fileId);
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
console.warn(`Failed to resolve file by id ${fileId}:`, error.message);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns groups of files that have identical checksums (potential duplicates).
|
* Returns groups of files that have identical checksums (potential duplicates).
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ const api: RendererApi = {
|
|||||||
async listAudioFiles(): Promise<AudioFileSummary[]> {
|
async listAudioFiles(): Promise<AudioFileSummary[]> {
|
||||||
return ipcRenderer.invoke(IPC_CHANNELS.libraryList);
|
return ipcRenderer.invoke(IPC_CHANNELS.libraryList);
|
||||||
},
|
},
|
||||||
|
/** Retrieves a single audio file summary by id, returning null when the record no longer exists. */
|
||||||
|
async getAudioFileById(fileId: number): Promise<AudioFileSummary | null> {
|
||||||
|
return ipcRenderer.invoke(IPC_CHANNELS.libraryGetById, fileId);
|
||||||
|
},
|
||||||
async listDuplicates(): Promise<{ checksum: string; files: AudioFileSummary[] }[]> {
|
async listDuplicates(): Promise<{ checksum: string; files: AudioFileSummary[] }[]> {
|
||||||
return ipcRenderer.invoke(IPC_CHANNELS.libraryDuplicates);
|
return ipcRenderer.invoke(IPC_CHANNELS.libraryDuplicates);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ function App(): JSX.Element {
|
|||||||
[library.files, library.selectedFileId]
|
[library.files, library.selectedFileId]
|
||||||
);
|
);
|
||||||
|
|
||||||
const parentFile = useMemo(() => {
|
const parentFileFromStore = useMemo(() => {
|
||||||
const parentId = selectedFile?.parentFileId ?? null;
|
const parentId = selectedFile?.parentFileId ?? null;
|
||||||
if (parentId === null) {
|
if (parentId === null) {
|
||||||
return null;
|
return null;
|
||||||
@@ -77,6 +77,39 @@ function App(): JSX.Element {
|
|||||||
return library.files.find((file) => file.id === parentId) ?? null;
|
return library.files.find((file) => file.id === parentId) ?? null;
|
||||||
}, [library.files, selectedFile?.parentFileId]);
|
}, [library.files, selectedFile?.parentFileId]);
|
||||||
|
|
||||||
|
const [resolvedParentFile, setResolvedParentFile] = useState<AudioFileSummary | null>(parentFileFromStore);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const parentId = selectedFile?.parentFileId ?? null;
|
||||||
|
if (parentId === null) {
|
||||||
|
setResolvedParentFile(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (parentFileFromStore) {
|
||||||
|
setResolvedParentFile(parentFileFromStore);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cancelled = false;
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
const fetched = await window.api.getAudioFileById(parentId);
|
||||||
|
if (!cancelled) {
|
||||||
|
setResolvedParentFile(fetched ?? null);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Unable to resolve parent file details', { parentId, error });
|
||||||
|
if (!cancelled) {
|
||||||
|
setResolvedParentFile(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
};
|
||||||
|
}, [parentFileFromStore, selectedFile?.parentFileId]);
|
||||||
|
|
||||||
const selectedFiles = useMemo(
|
const selectedFiles = useMemo(
|
||||||
() => library.files.filter((file) => library.selectedFileIds.has(file.id)),
|
() => library.files.filter((file) => library.selectedFileIds.has(file.id)),
|
||||||
[library.files, library.selectedFileIds]
|
[library.files, library.selectedFileIds]
|
||||||
@@ -307,7 +340,7 @@ function App(): JSX.Element {
|
|||||||
<>
|
<>
|
||||||
<FileDetailPanel
|
<FileDetailPanel
|
||||||
file={selectedFile}
|
file={selectedFile}
|
||||||
parentFile={parentFile}
|
parentFile={resolvedParentFile}
|
||||||
categories={library.categories}
|
categories={library.categories}
|
||||||
onRename={handleRename}
|
onRename={handleRename}
|
||||||
onMove={handleMove}
|
onMove={handleMove}
|
||||||
|
|||||||
@@ -369,7 +369,7 @@ export function FileDetailPanel({ file, parentFile, categories, onRename, onMove
|
|||||||
onClick={handleOpenParent}
|
onClick={handleOpenParent}
|
||||||
title={parentFile ? `Open source file ${parentFile.displayName}` : 'Open source file'}
|
title={parentFile ? `Open source file ${parentFile.displayName}` : 'Open source file'}
|
||||||
>
|
>
|
||||||
🔗 {parentFile ? parentFile.customName || parentFile.displayName : `File #${file.parentFileId}`}
|
🔗 {parentFile ? parentFile.customName || parentFile.displayName : `Source missing (#${file.parentFileId})`}
|
||||||
</button>
|
</button>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ export const IPC_CHANNELS = {
|
|||||||
dialogSelectLibrary: 'dialog:select-library',
|
dialogSelectLibrary: 'dialog:select-library',
|
||||||
libraryScan: 'library:scan',
|
libraryScan: 'library:scan',
|
||||||
libraryList: 'library:list',
|
libraryList: 'library:list',
|
||||||
|
libraryGetById: 'library:get-by-id',
|
||||||
libraryDuplicates: 'library:duplicates',
|
libraryDuplicates: 'library:duplicates',
|
||||||
libraryRename: 'library:rename',
|
libraryRename: 'library:rename',
|
||||||
libraryMove: 'library:move',
|
libraryMove: 'library:move',
|
||||||
@@ -39,6 +40,8 @@ export interface RendererApi {
|
|||||||
rescanLibrary(): Promise<import('./models').LibraryScanSummary>;
|
rescanLibrary(): Promise<import('./models').LibraryScanSummary>;
|
||||||
/** Fetches the current list of audio files. */
|
/** Fetches the current list of audio files. */
|
||||||
listAudioFiles(): Promise<import('./models').AudioFileSummary[]>;
|
listAudioFiles(): Promise<import('./models').AudioFileSummary[]>;
|
||||||
|
/** Retrieves a single audio file summary by id, or null if it cannot be resolved. */
|
||||||
|
getAudioFileById(fileId: number): Promise<import('./models').AudioFileSummary | null>;
|
||||||
/** Fetches groups of duplicate files based on checksum. */
|
/** Fetches groups of duplicate files based on checksum. */
|
||||||
listDuplicates(): Promise<{ checksum: string; files: import('./models').AudioFileSummary[] }[]>;
|
listDuplicates(): Promise<{ checksum: string; files: import('./models').AudioFileSummary[] }[]>;
|
||||||
/** Requests a rename for the target file. */
|
/** Requests a rename for the target file. */
|
||||||
|
|||||||
Reference in New Issue
Block a user