mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2026-03-04 02:20:19 +01:00
Bug fixing, file management changes
This commit is contained in:
@@ -27,9 +27,9 @@ interface FileItem {
|
||||
interface FileEditorProps {
|
||||
onOpenPageEditor?: (file: File) => void;
|
||||
onMergeFiles?: (files: File[]) => void;
|
||||
sharedFiles?: any[];
|
||||
setSharedFiles?: (files: any[]) => void;
|
||||
preSelectedFiles?: any[];
|
||||
sharedFiles?: { file: File; url: string }[];
|
||||
setSharedFiles?: (files: { file: File; url: string }[]) => void;
|
||||
preSelectedFiles?: { file: File; url: string }[];
|
||||
onClearPreSelection?: () => void;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ export interface PageEditorProps {
|
||||
setFile?: (file: { file: File; url: string } | null) => void;
|
||||
downloadUrl?: string | null;
|
||||
setDownloadUrl?: (url: string | null) => void;
|
||||
sharedFiles?: { file: File; url: string }[];
|
||||
|
||||
// Optional callbacks to expose internal functions
|
||||
onFunctionsReady?: (functions: {
|
||||
|
||||
@@ -69,13 +69,6 @@ const PageThumbnail = ({
|
||||
}: PageThumbnailProps) => {
|
||||
return (
|
||||
<div
|
||||
ref={(el) => {
|
||||
if (el) {
|
||||
pageRefs.current.set(page.id, el);
|
||||
} else {
|
||||
pageRefs.current.delete(page.id);
|
||||
}
|
||||
}}
|
||||
data-page-id={page.id}
|
||||
className={`
|
||||
${styles.pageContainer}
|
||||
|
||||
@@ -22,6 +22,7 @@ interface FileManagerProps {
|
||||
allowMultiple?: boolean;
|
||||
setCurrentView?: (view: string) => void;
|
||||
onOpenFileEditor?: (selectedFiles?: FileWithUrl[]) => void;
|
||||
onLoadFileToActive?: (file: File) => void;
|
||||
}
|
||||
|
||||
const FileManager = ({
|
||||
@@ -30,6 +31,7 @@ const FileManager = ({
|
||||
allowMultiple = true,
|
||||
setCurrentView,
|
||||
onOpenFileEditor,
|
||||
onLoadFileToActive,
|
||||
}: FileManagerProps) => {
|
||||
const { t } = useTranslation();
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -210,28 +212,56 @@ const FileManager = ({
|
||||
|
||||
const handleFileDoubleClick = async (file: FileWithUrl) => {
|
||||
try {
|
||||
const url = await createBlobUrlForFile(file);
|
||||
// Add file to the beginning of files array and switch to viewer
|
||||
setFiles(prev => [{ file: file, url: url }, ...prev.filter(f => f.id !== file.id)]);
|
||||
setCurrentView && setCurrentView("viewer");
|
||||
// Reconstruct File object from storage and add to active files
|
||||
if (onLoadFileToActive) {
|
||||
const reconstructedFile = await reconstructFileFromStorage(file);
|
||||
onLoadFileToActive(reconstructedFile);
|
||||
setCurrentView && setCurrentView("viewer");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to create blob URL for file:', error);
|
||||
console.error('Failed to load file to active set:', error);
|
||||
setNotification('Failed to open file. It may have been removed from storage.');
|
||||
}
|
||||
};
|
||||
|
||||
const handleFileView = async (file: FileWithUrl) => {
|
||||
try {
|
||||
const url = await createBlobUrlForFile(file);
|
||||
// Add file to the beginning of files array and switch to viewer
|
||||
setFiles(prev => [{ file: file, url: url }, ...prev.filter(f => f.id !== file.id)]);
|
||||
setCurrentView && setCurrentView("viewer");
|
||||
// Reconstruct File object from storage and add to active files
|
||||
if (onLoadFileToActive) {
|
||||
const reconstructedFile = await reconstructFileFromStorage(file);
|
||||
onLoadFileToActive(reconstructedFile);
|
||||
setCurrentView && setCurrentView("viewer");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to create blob URL for file:', error);
|
||||
console.error('Failed to load file to active set:', error);
|
||||
setNotification('Failed to open file. It may have been removed from storage.');
|
||||
}
|
||||
};
|
||||
|
||||
const reconstructFileFromStorage = async (fileWithUrl: FileWithUrl): Promise<File> => {
|
||||
// If it's already a regular file, return it
|
||||
if (fileWithUrl instanceof File) {
|
||||
return fileWithUrl;
|
||||
}
|
||||
|
||||
// Reconstruct from IndexedDB
|
||||
const arrayBuffer = await createBlobUrlForFile(fileWithUrl);
|
||||
if (typeof arrayBuffer === 'string') {
|
||||
// createBlobUrlForFile returned a blob URL, we need the actual data
|
||||
const response = await fetch(arrayBuffer);
|
||||
const data = await response.arrayBuffer();
|
||||
return new File([data], fileWithUrl.name, {
|
||||
type: fileWithUrl.type || 'application/pdf',
|
||||
lastModified: fileWithUrl.lastModified || Date.now()
|
||||
});
|
||||
} else {
|
||||
return new File([arrayBuffer], fileWithUrl.name, {
|
||||
type: fileWithUrl.type || 'application/pdf',
|
||||
lastModified: fileWithUrl.lastModified || Date.now()
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleFileEdit = (file: FileWithUrl) => {
|
||||
if (onOpenFileEditor) {
|
||||
onOpenFileEditor([file]);
|
||||
@@ -309,8 +339,11 @@ const FileManager = ({
|
||||
subtitle="Add files to your storage for easy access across tools"
|
||||
sharedFiles={[]} // FileManager is the source, so no shared files
|
||||
onFilesSelect={(uploadedFiles) => {
|
||||
// Handle multiple files
|
||||
// Handle multiple files - add to storage AND active set
|
||||
handleDrop(uploadedFiles);
|
||||
if (onLoadFileToActive && uploadedFiles.length > 0) {
|
||||
uploadedFiles.forEach(onLoadFileToActive);
|
||||
}
|
||||
}}
|
||||
allowMultiple={allowMultiple}
|
||||
accept={["application/pdf"]}
|
||||
|
||||
@@ -10,14 +10,14 @@ interface FileUploadSelectorProps {
|
||||
title?: string;
|
||||
subtitle?: string;
|
||||
showDropzone?: boolean;
|
||||
|
||||
|
||||
// File handling
|
||||
sharedFiles?: any[];
|
||||
onFileSelect: (file: File) => void;
|
||||
onFilesSelect?: (files: File[]) => void;
|
||||
allowMultiple?: boolean;
|
||||
accept?: string[];
|
||||
|
||||
|
||||
// Loading state
|
||||
loading?: boolean;
|
||||
disabled?: boolean;
|
||||
@@ -40,7 +40,7 @@ const FileUploadSelector = ({
|
||||
|
||||
const handleFileUpload = useCallback((uploadedFiles: File[]) => {
|
||||
if (uploadedFiles.length === 0) return;
|
||||
|
||||
|
||||
if (allowMultiple && onFilesSelect) {
|
||||
onFilesSelect(uploadedFiles);
|
||||
} else {
|
||||
@@ -50,7 +50,7 @@ const FileUploadSelector = ({
|
||||
|
||||
const handleStorageSelection = useCallback((selectedFiles: File[]) => {
|
||||
if (selectedFiles.length === 0) return;
|
||||
|
||||
|
||||
if (allowMultiple && onFilesSelect) {
|
||||
onFilesSelect(selectedFiles);
|
||||
} else {
|
||||
@@ -81,13 +81,13 @@ const FileUploadSelector = ({
|
||||
disabled={disabled || sharedFiles.length === 0}
|
||||
loading={loading}
|
||||
>
|
||||
Load from Storage ({sharedFiles.length} files available)
|
||||
{loading ? "Loading..." : `Load from Storage (${sharedFiles.length} files available)`}
|
||||
</Button>
|
||||
|
||||
|
||||
<Text size="md" c="dimmed">
|
||||
or
|
||||
</Text>
|
||||
|
||||
|
||||
{showDropzone ? (
|
||||
<Dropzone
|
||||
onDrop={handleFileUpload}
|
||||
@@ -115,8 +115,8 @@ const FileUploadSelector = ({
|
||||
disabled={disabled || loading}
|
||||
style={{ display: 'contents' }}
|
||||
>
|
||||
<Button
|
||||
variant="outline"
|
||||
<Button
|
||||
variant="outline"
|
||||
size="lg"
|
||||
disabled={disabled}
|
||||
loading={loading}
|
||||
@@ -139,4 +139,4 @@ const FileUploadSelector = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default FileUploadSelector;
|
||||
export default FileUploadSelector;
|
||||
|
||||
Reference in New Issue
Block a user