Automatically select added files (#4325)

# Description of Changes
When adding files, the user probably wants to use them straight away in
the next tool that they use, so automatically select any added files (in
addition to whatever they previously had selected).
This commit is contained in:
James Brunton 2025-08-29 16:39:19 +01:00 committed by GitHub
parent eecc410b77
commit 3b28b398d9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 34 additions and 10 deletions

View File

@ -25,7 +25,7 @@ import {
// Import modular components
import { fileContextReducer, initialFileContextState } from './file/FileReducer';
import { createFileSelectors } from './file/fileSelectors';
import { addFiles, consumeFiles, createFileActions } from './file/fileActions';
import { AddedFile, addFiles, consumeFiles, createFileActions } from './file/fileActions';
import { FileLifecycleManager } from './file/lifecycle';
import { FileStateContext, FileActionsContext } from './file/contexts';
import { IndexedDBProvider, useIndexedDB } from './IndexedDBContext';
@ -72,9 +72,21 @@ function FileContextInner({
dispatch({ type: 'SET_UNSAVED_CHANGES', payload: { hasChanges } });
}, []);
const selectFiles = (addedFilesWithIds: AddedFile[]) => {
const currentSelection = stateRef.current.ui.selectedFileIds;
const newFileIds = addedFilesWithIds.map(({ id }) => id);
dispatch({ type: 'SET_SELECTED_FILES', payload: { fileIds: [...currentSelection, ...newFileIds] } });
}
// File operations using unified addFiles helper with persistence
const addRawFiles = useCallback(async (files: File[], options?: { insertAfterPageId?: string }): Promise<File[]> => {
const addRawFiles = useCallback(async (files: File[], options?: { insertAfterPageId?: string; selectFiles?: boolean }): Promise<File[]> => {
const addedFilesWithIds = await addFiles('raw', { files, ...options }, stateRef, filesRef, dispatch, lifecycleManager);
// Auto-select the newly added files if requested
if (options?.selectFiles && addedFilesWithIds.length > 0) {
selectFiles(addedFilesWithIds);
}
// Persist to IndexedDB if enabled
if (indexedDB && enablePersistence && addedFilesWithIds.length > 0) {
await Promise.all(addedFilesWithIds.map(async ({ file, id, thumbnail }) => {
@ -94,8 +106,14 @@ function FileContextInner({
return result.map(({ file }) => file);
}, []);
const addStoredFiles = useCallback(async (filesWithMetadata: Array<{ file: File; originalId: FileId; metadata: any }>): Promise<File[]> => {
const addStoredFiles = useCallback(async (filesWithMetadata: Array<{ file: File; originalId: FileId; metadata: any }>, options?: { selectFiles?: boolean }): Promise<File[]> => {
const result = await addFiles('stored', { filesWithMetadata }, stateRef, filesRef, dispatch, lifecycleManager);
// Auto-select the newly added files if requested
if (options?.selectFiles && result.length > 0) {
selectFiles(result);
}
return result.map(({ file }) => file);
}, []);

View File

@ -88,6 +88,12 @@ interface AddFileOptions {
insertAfterPageId?: string;
}
export interface AddedFile {
file: File;
id: FileId;
thumbnail?: string;
}
/**
* Unified file addition helper - replaces addFiles/addProcessedFiles/addStoredFiles
*/
@ -98,13 +104,13 @@ export async function addFiles(
filesRef: React.MutableRefObject<Map<FileId, File>>,
dispatch: React.Dispatch<FileContextAction>,
lifecycleManager: FileLifecycleManager
): Promise<Array<{ file: File; id: FileId; thumbnail?: string }>> {
): Promise<AddedFile[]> {
// Acquire mutex to prevent race conditions
await addFilesMutex.lock();
try {
const fileRecords: FileRecord[] = [];
const addedFiles: Array<{ file: File; id: FileId; thumbnail?: string }> = [];
const addedFiles: AddedFile[] = [];
// Build quickKey lookup from existing files for deduplication
const existingQuickKeys = buildQuickKeySet(stateRef.current.files.byId);

View File

@ -9,12 +9,12 @@ export const useFileHandler = () => {
const addToActiveFiles = useCallback(async (file: File) => {
// Let FileContext handle deduplication with quickKey logic
await actions.addFiles([file]);
await actions.addFiles([file], { selectFiles: true });
}, [actions.addFiles]);
const addMultipleFiles = useCallback(async (files: File[]) => {
// Let FileContext handle deduplication with quickKey logic
await actions.addFiles(files);
await actions.addFiles(files, { selectFiles: true });
}, [actions.addFiles]);
// Add stored files preserving their original IDs to prevent session duplicates
@ -25,7 +25,7 @@ export const useFileHandler = () => {
});
if (newFiles.length > 0) {
await actions.addStoredFiles(newFiles);
await actions.addStoredFiles(newFiles, { selectFiles: true });
}
console.log(`📁 Added ${newFiles.length} stored files (${filesWithMetadata.length - newFiles.length} skipped as duplicates)`);

View File

@ -214,9 +214,9 @@ export type FileContextAction =
export interface FileContextActions {
// File management - lightweight actions only
addFiles: (files: File[], options?: { insertAfterPageId?: string }) => Promise<File[]>;
addFiles: (files: File[], options?: { insertAfterPageId?: string; selectFiles?: boolean }) => Promise<File[]>;
addProcessedFiles: (filesWithThumbnails: Array<{ file: File; thumbnail?: string; pageCount?: number }>) => Promise<File[]>;
addStoredFiles: (filesWithMetadata: Array<{ file: File; originalId: FileId; metadata: FileMetadata }>) => Promise<File[]>;
addStoredFiles: (filesWithMetadata: Array<{ file: File; originalId: FileId; metadata: FileMetadata }>, options?: { selectFiles?: boolean }) => Promise<File[]>;
removeFiles: (fileIds: FileId[], deleteFromStorage?: boolean) => Promise<void>;
updateFileRecord: (id: FileId, updates: Partial<FileRecord>) => void;
reorderFiles: (orderedFileIds: FileId[]) => void;