2025-08-12 14:37:45 +01:00
|
|
|
import React, { useState, useCallback, useRef, useEffect, useMemo } from 'react';
|
2025-07-16 17:53:50 +01:00
|
|
|
import {
|
|
|
|
Button, Text, Center, Box, Notification, TextInput, LoadingOverlay, Modal, Alert, Container,
|
|
|
|
Stack, Group
|
|
|
|
} from '@mantine/core';
|
|
|
|
import { Dropzone } from '@mantine/dropzone';
|
|
|
|
import { useTranslation } from 'react-i18next';
|
|
|
|
import UploadFileIcon from '@mui/icons-material/UploadFile';
|
2025-08-12 14:37:45 +01:00
|
|
|
import { useToolFileSelection, useProcessedFiles, useFileState, useFileManagement, useFileActions } from '../../contexts/FileContext';
|
2025-08-14 21:47:02 +01:00
|
|
|
import { FileOperation } from '../../types/fileContext';
|
2025-07-16 17:53:50 +01:00
|
|
|
import { fileStorage } from '../../services/fileStorage';
|
|
|
|
import { generateThumbnailForFile } from '../../utils/thumbnailUtils';
|
|
|
|
import { zipFileService } from '../../services/zipFileService';
|
2025-08-01 16:08:04 +01:00
|
|
|
import { detectFileExtension } from '../../utils/fileUtils';
|
2025-07-16 17:53:50 +01:00
|
|
|
import styles from '../pageEditor/PageEditor.module.css';
|
|
|
|
import FileThumbnail from '../pageEditor/FileThumbnail';
|
|
|
|
import FilePickerModal from '../shared/FilePickerModal';
|
|
|
|
import SkeletonLoader from '../shared/SkeletonLoader';
|
|
|
|
|
|
|
|
|
|
|
|
interface FileEditorProps {
|
|
|
|
onOpenPageEditor?: (file: File) => void;
|
|
|
|
onMergeFiles?: (files: File[]) => void;
|
|
|
|
toolMode?: boolean;
|
|
|
|
showUpload?: boolean;
|
|
|
|
showBulkActions?: boolean;
|
2025-08-01 16:08:04 +01:00
|
|
|
supportedExtensions?: string[];
|
2025-07-16 17:53:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const FileEditor = ({
|
|
|
|
onOpenPageEditor,
|
|
|
|
onMergeFiles,
|
|
|
|
toolMode = false,
|
|
|
|
showUpload = true,
|
2025-08-01 16:08:04 +01:00
|
|
|
showBulkActions = true,
|
|
|
|
supportedExtensions = ["pdf"]
|
2025-07-16 17:53:50 +01:00
|
|
|
}: FileEditorProps) => {
|
|
|
|
const { t } = useTranslation();
|
|
|
|
|
2025-08-01 16:08:04 +01:00
|
|
|
// Utility function to check if a file extension is supported
|
|
|
|
const isFileSupported = useCallback((fileName: string): boolean => {
|
|
|
|
const extension = detectFileExtension(fileName);
|
|
|
|
return extension ? supportedExtensions.includes(extension) : false;
|
|
|
|
}, [supportedExtensions]);
|
|
|
|
|
2025-08-10 21:08:32 +01:00
|
|
|
// Use optimized FileContext hooks
|
2025-08-12 14:37:45 +01:00
|
|
|
const { state, selectors } = useFileState();
|
2025-08-20 15:59:07 +01:00
|
|
|
const { addFiles, removeFiles, reorderFiles } = useFileManagement();
|
2025-08-10 21:08:32 +01:00
|
|
|
const processedFiles = useProcessedFiles(); // Now gets real processed files
|
|
|
|
|
2025-08-12 14:37:45 +01:00
|
|
|
// Extract needed values from state (memoized to prevent infinite loops)
|
|
|
|
const activeFiles = useMemo(() => selectors.getFiles(), [selectors.getFilesSignature()]);
|
2025-08-14 18:07:18 +01:00
|
|
|
const activeFileRecords = useMemo(() => selectors.getFileRecords(), [selectors.getFilesSignature()]);
|
2025-08-10 21:08:32 +01:00
|
|
|
const selectedFileIds = state.ui.selectedFileIds;
|
|
|
|
const isProcessing = state.ui.isProcessing;
|
|
|
|
|
2025-08-12 14:37:45 +01:00
|
|
|
// Get the real context actions
|
|
|
|
const { actions } = useFileActions();
|
|
|
|
|
|
|
|
// Create a stable ref to access current selected files and actions without dependency
|
|
|
|
const selectedFileIdsRef = useRef<string[]>([]);
|
|
|
|
const actionsRef = useRef(actions);
|
|
|
|
selectedFileIdsRef.current = selectedFileIds;
|
|
|
|
actionsRef.current = actions;
|
|
|
|
|
|
|
|
// Legacy compatibility for existing code - now actually updates context (completely stable)
|
|
|
|
const setContextSelectedFiles = useCallback((fileIds: string[] | ((prev: string[]) => string[])) => {
|
|
|
|
if (typeof fileIds === 'function') {
|
|
|
|
// Handle callback pattern - get current state from ref
|
|
|
|
const result = fileIds(selectedFileIdsRef.current);
|
|
|
|
actionsRef.current.setSelectedFiles(result);
|
|
|
|
} else {
|
|
|
|
// Handle direct array pattern
|
|
|
|
actionsRef.current.setSelectedFiles(fileIds);
|
|
|
|
}
|
|
|
|
}, []); // No dependencies at all - completely stable
|
2025-08-10 21:08:32 +01:00
|
|
|
|
|
|
|
const setCurrentView = (mode: any) => {
|
|
|
|
// Will be handled by parent component actions
|
|
|
|
};
|
|
|
|
|
|
|
|
// Get tool file selection context (replaces FileSelectionContext)
|
Feature/v2/multiselect (#4024)
# Description of Changes
This pull request introduces significant updates to the file selection
logic, tool rendering, and file context management in the frontend
codebase. The changes aim to improve modularity, enhance
maintainability, and streamline the handling of file-related operations.
Key updates include the introduction of a new `FileSelectionContext`,
refactoring of file selection logic, and updates to tool management and
rendering.
### File Selection Context and Logic Refactor:
* Added a new `FileSelectionContext` to centralize file selection state
and provide utility hooks for managing selected files, selection limits,
and tool mode. (`frontend/src/contexts/FileSelectionContext.tsx`,
[frontend/src/contexts/FileSelectionContext.tsxR1-R77](diffhunk://#diff-bda35f1aaa5eafa0a0dc48e0b1270d862f6da360ba1241234e891f0ca8907327R1-R77))
* Replaced local file selection logic in `FileEditor` with context-based
logic, improving consistency and reducing duplication.
(`frontend/src/components/fileEditor/FileEditor.tsx`,
[[1]](diffhunk://#diff-481d0a2d8a1714d34d21181db63a020b08dfccfbfa80bf47ac9af382dff25310R63-R70)
[[2]](diffhunk://#diff-481d0a2d8a1714d34d21181db63a020b08dfccfbfa80bf47ac9af382dff25310R404-R438)
### Tool Management and Rendering:
* Refactored `ToolRenderer` to use a `Suspense` fallback for lazy-loaded
tools, improving user experience during tool loading.
(`frontend/src/components/tools/ToolRenderer.tsx`,
[frontend/src/components/tools/ToolRenderer.tsxL32-L64](diffhunk://#diff-2083701113aa92cd1f5ce1b4b52cc233858e31ed7bcf39c5bfb1bcc34e99b6a9L32-L64))
* Simplified `ToolPicker` by reusing the `ToolRegistry` type, reducing
redundancy. (`frontend/src/components/tools/ToolPicker.tsx`,
[frontend/src/components/tools/ToolPicker.tsxL4-R4](diffhunk://#diff-e47deca9132018344c159925f1264794acdd57f4b65e582eb9b2a4ea69ec126dL4-R4))
### File Context Enhancements:
* Introduced a utility function `getFileId` for consistent file ID
extraction, replacing repetitive inline logic.
(`frontend/src/contexts/FileContext.tsx`,
[[1]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcR25)
[[2]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL101-R102)
* Updated `FileContextProvider` to use more specific types for PDF
documents, enhancing type safety.
(`frontend/src/contexts/FileContext.tsx`,
[[1]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL350-R351)
[[2]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL384-R385)
### Compression Tool Enhancements:
* Added blob URL cleanup logic to the compression hook to prevent memory
leaks. (`frontend/src/hooks/tools/compress/useCompressOperation.ts`,
[frontend/src/hooks/tools/compress/useCompressOperation.tsR58-L66](diffhunk://#diff-d7815fea0e89989511ae1786f7031cba492b9f2db39b7ade92d9736d1bd4b673R58-L66))
* Adjusted file ID generation in the compression operation to handle
multiple files more effectively.
(`frontend/src/hooks/tools/compress/useCompressOperation.ts`,
[frontend/src/hooks/tools/compress/useCompressOperation.tsL90-R102](diffhunk://#diff-d7815fea0e89989511ae1786f7031cba492b9f2db39b7ade92d9736d1bd4b673L90-R102))
---
## Checklist
### General
- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings
### Documentation
- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)
### UI Changes (if applicable)
- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)
### Testing (if applicable)
- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-07-25 09:37:52 +01:00
|
|
|
const {
|
|
|
|
selectedFiles: toolSelectedFiles,
|
|
|
|
setSelectedFiles: setToolSelectedFiles,
|
|
|
|
maxFiles,
|
|
|
|
isToolMode
|
2025-08-10 21:08:32 +01:00
|
|
|
} = useToolFileSelection();
|
Feature/v2/multiselect (#4024)
# Description of Changes
This pull request introduces significant updates to the file selection
logic, tool rendering, and file context management in the frontend
codebase. The changes aim to improve modularity, enhance
maintainability, and streamline the handling of file-related operations.
Key updates include the introduction of a new `FileSelectionContext`,
refactoring of file selection logic, and updates to tool management and
rendering.
### File Selection Context and Logic Refactor:
* Added a new `FileSelectionContext` to centralize file selection state
and provide utility hooks for managing selected files, selection limits,
and tool mode. (`frontend/src/contexts/FileSelectionContext.tsx`,
[frontend/src/contexts/FileSelectionContext.tsxR1-R77](diffhunk://#diff-bda35f1aaa5eafa0a0dc48e0b1270d862f6da360ba1241234e891f0ca8907327R1-R77))
* Replaced local file selection logic in `FileEditor` with context-based
logic, improving consistency and reducing duplication.
(`frontend/src/components/fileEditor/FileEditor.tsx`,
[[1]](diffhunk://#diff-481d0a2d8a1714d34d21181db63a020b08dfccfbfa80bf47ac9af382dff25310R63-R70)
[[2]](diffhunk://#diff-481d0a2d8a1714d34d21181db63a020b08dfccfbfa80bf47ac9af382dff25310R404-R438)
### Tool Management and Rendering:
* Refactored `ToolRenderer` to use a `Suspense` fallback for lazy-loaded
tools, improving user experience during tool loading.
(`frontend/src/components/tools/ToolRenderer.tsx`,
[frontend/src/components/tools/ToolRenderer.tsxL32-L64](diffhunk://#diff-2083701113aa92cd1f5ce1b4b52cc233858e31ed7bcf39c5bfb1bcc34e99b6a9L32-L64))
* Simplified `ToolPicker` by reusing the `ToolRegistry` type, reducing
redundancy. (`frontend/src/components/tools/ToolPicker.tsx`,
[frontend/src/components/tools/ToolPicker.tsxL4-R4](diffhunk://#diff-e47deca9132018344c159925f1264794acdd57f4b65e582eb9b2a4ea69ec126dL4-R4))
### File Context Enhancements:
* Introduced a utility function `getFileId` for consistent file ID
extraction, replacing repetitive inline logic.
(`frontend/src/contexts/FileContext.tsx`,
[[1]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcR25)
[[2]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL101-R102)
* Updated `FileContextProvider` to use more specific types for PDF
documents, enhancing type safety.
(`frontend/src/contexts/FileContext.tsx`,
[[1]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL350-R351)
[[2]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL384-R385)
### Compression Tool Enhancements:
* Added blob URL cleanup logic to the compression hook to prevent memory
leaks. (`frontend/src/hooks/tools/compress/useCompressOperation.ts`,
[frontend/src/hooks/tools/compress/useCompressOperation.tsR58-L66](diffhunk://#diff-d7815fea0e89989511ae1786f7031cba492b9f2db39b7ade92d9736d1bd4b673R58-L66))
* Adjusted file ID generation in the compression operation to handle
multiple files more effectively.
(`frontend/src/hooks/tools/compress/useCompressOperation.ts`,
[frontend/src/hooks/tools/compress/useCompressOperation.tsL90-R102](diffhunk://#diff-d7815fea0e89989511ae1786f7031cba492b9f2db39b7ade92d9736d1bd4b673L90-R102))
---
## Checklist
### General
- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings
### Documentation
- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)
### UI Changes (if applicable)
- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)
### Testing (if applicable)
- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-07-25 09:37:52 +01:00
|
|
|
|
2025-07-16 17:53:50 +01:00
|
|
|
const [status, setStatus] = useState<string | null>(null);
|
|
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
const [selectionMode, setSelectionMode] = useState(toolMode);
|
2025-08-11 16:40:38 +01:00
|
|
|
|
2025-07-16 17:53:50 +01:00
|
|
|
// Enable selection mode automatically in tool mode
|
|
|
|
React.useEffect(() => {
|
|
|
|
if (toolMode) {
|
|
|
|
setSelectionMode(true);
|
|
|
|
}
|
|
|
|
}, [toolMode]);
|
|
|
|
const [showFilePickerModal, setShowFilePickerModal] = useState(false);
|
|
|
|
const [zipExtractionProgress, setZipExtractionProgress] = useState<{
|
|
|
|
isExtracting: boolean;
|
|
|
|
currentFile: string;
|
|
|
|
progress: number;
|
|
|
|
extractedCount: number;
|
|
|
|
totalFiles: number;
|
|
|
|
}>({
|
|
|
|
isExtracting: false,
|
|
|
|
currentFile: '',
|
|
|
|
progress: 0,
|
|
|
|
extractedCount: 0,
|
|
|
|
totalFiles: 0
|
|
|
|
});
|
Feature/v2/multiselect (#4024)
# Description of Changes
This pull request introduces significant updates to the file selection
logic, tool rendering, and file context management in the frontend
codebase. The changes aim to improve modularity, enhance
maintainability, and streamline the handling of file-related operations.
Key updates include the introduction of a new `FileSelectionContext`,
refactoring of file selection logic, and updates to tool management and
rendering.
### File Selection Context and Logic Refactor:
* Added a new `FileSelectionContext` to centralize file selection state
and provide utility hooks for managing selected files, selection limits,
and tool mode. (`frontend/src/contexts/FileSelectionContext.tsx`,
[frontend/src/contexts/FileSelectionContext.tsxR1-R77](diffhunk://#diff-bda35f1aaa5eafa0a0dc48e0b1270d862f6da360ba1241234e891f0ca8907327R1-R77))
* Replaced local file selection logic in `FileEditor` with context-based
logic, improving consistency and reducing duplication.
(`frontend/src/components/fileEditor/FileEditor.tsx`,
[[1]](diffhunk://#diff-481d0a2d8a1714d34d21181db63a020b08dfccfbfa80bf47ac9af382dff25310R63-R70)
[[2]](diffhunk://#diff-481d0a2d8a1714d34d21181db63a020b08dfccfbfa80bf47ac9af382dff25310R404-R438)
### Tool Management and Rendering:
* Refactored `ToolRenderer` to use a `Suspense` fallback for lazy-loaded
tools, improving user experience during tool loading.
(`frontend/src/components/tools/ToolRenderer.tsx`,
[frontend/src/components/tools/ToolRenderer.tsxL32-L64](diffhunk://#diff-2083701113aa92cd1f5ce1b4b52cc233858e31ed7bcf39c5bfb1bcc34e99b6a9L32-L64))
* Simplified `ToolPicker` by reusing the `ToolRegistry` type, reducing
redundancy. (`frontend/src/components/tools/ToolPicker.tsx`,
[frontend/src/components/tools/ToolPicker.tsxL4-R4](diffhunk://#diff-e47deca9132018344c159925f1264794acdd57f4b65e582eb9b2a4ea69ec126dL4-R4))
### File Context Enhancements:
* Introduced a utility function `getFileId` for consistent file ID
extraction, replacing repetitive inline logic.
(`frontend/src/contexts/FileContext.tsx`,
[[1]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcR25)
[[2]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL101-R102)
* Updated `FileContextProvider` to use more specific types for PDF
documents, enhancing type safety.
(`frontend/src/contexts/FileContext.tsx`,
[[1]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL350-R351)
[[2]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL384-R385)
### Compression Tool Enhancements:
* Added blob URL cleanup logic to the compression hook to prevent memory
leaks. (`frontend/src/hooks/tools/compress/useCompressOperation.ts`,
[frontend/src/hooks/tools/compress/useCompressOperation.tsR58-L66](diffhunk://#diff-d7815fea0e89989511ae1786f7031cba492b9f2db39b7ade92d9736d1bd4b673R58-L66))
* Adjusted file ID generation in the compression operation to handle
multiple files more effectively.
(`frontend/src/hooks/tools/compress/useCompressOperation.ts`,
[frontend/src/hooks/tools/compress/useCompressOperation.tsL90-R102](diffhunk://#diff-d7815fea0e89989511ae1786f7031cba492b9f2db39b7ade92d9736d1bd4b673L90-R102))
---
## Checklist
### General
- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings
### Documentation
- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)
### UI Changes (if applicable)
- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)
### Testing (if applicable)
- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-07-25 09:37:52 +01:00
|
|
|
// Get selected file IDs from context (defensive programming)
|
|
|
|
const contextSelectedIds = Array.isArray(selectedFileIds) ? selectedFileIds : [];
|
2025-08-12 14:37:45 +01:00
|
|
|
|
|
|
|
// Create refs for frequently changing values to stabilize callbacks
|
|
|
|
const contextSelectedIdsRef = useRef<string[]>([]);
|
|
|
|
contextSelectedIdsRef.current = contextSelectedIds;
|
2025-07-16 17:53:50 +01:00
|
|
|
|
2025-08-20 15:59:07 +01:00
|
|
|
// Use activeFileRecords directly - no conversion needed
|
|
|
|
const localSelectedIds = contextSelectedIds;
|
2025-07-16 17:53:50 +01:00
|
|
|
|
2025-08-20 15:59:07 +01:00
|
|
|
// Helper to convert FileRecord to FileThumbnail format
|
|
|
|
const recordToFileItem = useCallback((record: any) => {
|
|
|
|
const file = selectors.getFile(record.id);
|
|
|
|
if (!file) return null;
|
|
|
|
|
|
|
|
return {
|
|
|
|
id: record.id,
|
|
|
|
name: file.name,
|
|
|
|
pageCount: record.processedFile?.totalPages || 1,
|
|
|
|
thumbnail: record.thumbnailUrl || '',
|
|
|
|
size: file.size,
|
|
|
|
file: file
|
2025-07-16 17:53:50 +01:00
|
|
|
};
|
2025-08-20 15:59:07 +01:00
|
|
|
}, [selectors]);
|
2025-07-16 17:53:50 +01:00
|
|
|
|
|
|
|
|
|
|
|
// Process uploaded files using context
|
|
|
|
const handleFileUpload = useCallback(async (uploadedFiles: File[]) => {
|
|
|
|
setError(null);
|
|
|
|
|
|
|
|
try {
|
|
|
|
const allExtractedFiles: File[] = [];
|
|
|
|
const errors: string[] = [];
|
|
|
|
|
|
|
|
for (const file of uploadedFiles) {
|
|
|
|
if (file.type === 'application/pdf') {
|
|
|
|
// Handle PDF files normally
|
|
|
|
allExtractedFiles.push(file);
|
|
|
|
} else if (file.type === 'application/zip' || file.type === 'application/x-zip-compressed' || file.name.toLowerCase().endsWith('.zip')) {
|
2025-08-01 16:08:04 +01:00
|
|
|
// Handle ZIP files - only expand if they contain PDFs
|
2025-07-16 17:53:50 +01:00
|
|
|
try {
|
|
|
|
// Validate ZIP file first
|
|
|
|
const validation = await zipFileService.validateZipFile(file);
|
2025-08-11 16:40:38 +01:00
|
|
|
|
2025-08-01 16:08:04 +01:00
|
|
|
if (validation.isValid && validation.containsPDFs) {
|
|
|
|
// ZIP contains PDFs - extract them
|
2025-07-16 17:53:50 +01:00
|
|
|
setZipExtractionProgress({
|
|
|
|
isExtracting: true,
|
2025-08-01 16:08:04 +01:00
|
|
|
currentFile: file.name,
|
|
|
|
progress: 0,
|
|
|
|
extractedCount: 0,
|
|
|
|
totalFiles: validation.fileCount
|
2025-07-16 17:53:50 +01:00
|
|
|
});
|
|
|
|
|
2025-08-01 16:08:04 +01:00
|
|
|
const extractionResult = await zipFileService.extractPdfFiles(file, (progress) => {
|
|
|
|
setZipExtractionProgress({
|
|
|
|
isExtracting: true,
|
|
|
|
currentFile: progress.currentFile,
|
|
|
|
progress: progress.progress,
|
|
|
|
extractedCount: progress.extractedCount,
|
|
|
|
totalFiles: progress.totalFiles
|
|
|
|
});
|
|
|
|
});
|
2025-07-16 17:53:50 +01:00
|
|
|
|
2025-08-01 16:08:04 +01:00
|
|
|
// Reset extraction progress
|
|
|
|
setZipExtractionProgress({
|
|
|
|
isExtracting: false,
|
|
|
|
currentFile: '',
|
|
|
|
progress: 0,
|
|
|
|
extractedCount: 0,
|
|
|
|
totalFiles: 0
|
|
|
|
});
|
|
|
|
|
|
|
|
if (extractionResult.success) {
|
|
|
|
allExtractedFiles.push(...extractionResult.extractedFiles);
|
2025-08-11 16:40:38 +01:00
|
|
|
|
2025-08-01 16:08:04 +01:00
|
|
|
// Record ZIP extraction operation
|
|
|
|
const operationId = `zip-extract-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
|
|
const operation: FileOperation = {
|
2025-07-16 17:53:50 +01:00
|
|
|
id: operationId,
|
|
|
|
type: 'convert',
|
|
|
|
timestamp: Date.now(),
|
|
|
|
fileIds: extractionResult.extractedFiles.map(f => f.name),
|
|
|
|
status: 'pending',
|
|
|
|
metadata: {
|
|
|
|
originalFileName: file.name,
|
|
|
|
outputFileNames: extractionResult.extractedFiles.map(f => f.name),
|
|
|
|
fileSize: file.size,
|
|
|
|
parameters: {
|
|
|
|
extractionType: 'zip',
|
|
|
|
extractedCount: extractionResult.extractedCount,
|
|
|
|
totalFiles: extractionResult.totalFiles
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
if (extractionResult.errors.length > 0) {
|
|
|
|
errors.push(...extractionResult.errors);
|
|
|
|
}
|
2025-08-01 16:08:04 +01:00
|
|
|
} else {
|
|
|
|
errors.push(`Failed to extract ZIP file "${file.name}": ${extractionResult.errors.join(', ')}`);
|
|
|
|
}
|
2025-07-16 17:53:50 +01:00
|
|
|
} else {
|
2025-08-01 16:08:04 +01:00
|
|
|
// ZIP doesn't contain PDFs or is invalid - treat as regular file
|
|
|
|
allExtractedFiles.push(file);
|
2025-07-16 17:53:50 +01:00
|
|
|
}
|
|
|
|
} catch (zipError) {
|
|
|
|
errors.push(`Failed to process ZIP file "${file.name}": ${zipError instanceof Error ? zipError.message : 'Unknown error'}`);
|
|
|
|
setZipExtractionProgress({
|
|
|
|
isExtracting: false,
|
|
|
|
currentFile: '',
|
|
|
|
progress: 0,
|
|
|
|
extractedCount: 0,
|
|
|
|
totalFiles: 0
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} else {
|
2025-08-01 16:08:04 +01:00
|
|
|
allExtractedFiles.push(file);
|
2025-07-16 17:53:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Show any errors
|
|
|
|
if (errors.length > 0) {
|
|
|
|
setError(errors.join('\n'));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Process all extracted files
|
|
|
|
if (allExtractedFiles.length > 0) {
|
|
|
|
// Record upload operations for PDF files
|
|
|
|
for (const file of allExtractedFiles) {
|
|
|
|
const operationId = `upload-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
|
|
const operation: FileOperation = {
|
|
|
|
id: operationId,
|
|
|
|
type: 'upload',
|
|
|
|
timestamp: Date.now(),
|
|
|
|
fileIds: [file.name],
|
|
|
|
status: 'pending',
|
|
|
|
metadata: {
|
|
|
|
originalFileName: file.name,
|
|
|
|
fileSize: file.size,
|
|
|
|
parameters: {
|
|
|
|
uploadMethod: 'drag-drop'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add files to context (they will be processed automatically)
|
|
|
|
await addFiles(allExtractedFiles);
|
|
|
|
setStatus(`Added ${allExtractedFiles.length} files`);
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
const errorMessage = err instanceof Error ? err.message : 'Failed to process files';
|
|
|
|
setError(errorMessage);
|
|
|
|
console.error('File processing error:', err);
|
2025-08-15 00:52:36 +01:00
|
|
|
|
2025-07-16 17:53:50 +01:00
|
|
|
// Reset extraction progress on error
|
|
|
|
setZipExtractionProgress({
|
|
|
|
isExtracting: false,
|
|
|
|
currentFile: '',
|
|
|
|
progress: 0,
|
|
|
|
extractedCount: 0,
|
|
|
|
totalFiles: 0
|
|
|
|
});
|
|
|
|
}
|
2025-08-10 21:08:32 +01:00
|
|
|
}, [addFiles]);
|
2025-07-16 17:53:50 +01:00
|
|
|
|
|
|
|
const selectAll = useCallback(() => {
|
2025-08-20 15:59:07 +01:00
|
|
|
setContextSelectedFiles(activeFileRecords.map(r => r.id)); // Use FileRecord IDs directly
|
|
|
|
}, [activeFileRecords, setContextSelectedFiles]);
|
2025-07-16 17:53:50 +01:00
|
|
|
|
|
|
|
const deselectAll = useCallback(() => setContextSelectedFiles([]), [setContextSelectedFiles]);
|
|
|
|
|
|
|
|
const closeAllFiles = useCallback(() => {
|
2025-08-14 18:07:18 +01:00
|
|
|
if (activeFileRecords.length === 0) return;
|
2025-08-11 16:40:38 +01:00
|
|
|
|
2025-08-15 00:52:36 +01:00
|
|
|
|
2025-07-16 17:53:50 +01:00
|
|
|
// Remove all files from context but keep in storage
|
2025-08-15 00:52:36 +01:00
|
|
|
|
2025-07-16 17:53:50 +01:00
|
|
|
// Clear selections
|
|
|
|
setContextSelectedFiles([]);
|
2025-08-14 18:07:18 +01:00
|
|
|
}, [activeFileRecords, removeFiles, setContextSelectedFiles]);
|
2025-07-16 17:53:50 +01:00
|
|
|
|
|
|
|
const toggleFile = useCallback((fileId: string) => {
|
2025-08-12 14:37:45 +01:00
|
|
|
const currentSelectedIds = contextSelectedIdsRef.current;
|
|
|
|
|
2025-08-20 15:59:07 +01:00
|
|
|
const targetRecord = activeFileRecords.find(r => r.id === fileId);
|
|
|
|
if (!targetRecord) return;
|
2025-08-11 16:40:38 +01:00
|
|
|
|
2025-08-14 18:07:18 +01:00
|
|
|
const contextFileId = fileId; // No need to create a new ID
|
2025-08-12 14:37:45 +01:00
|
|
|
const isSelected = currentSelectedIds.includes(contextFileId);
|
2025-08-11 16:40:38 +01:00
|
|
|
|
Feature/v2/multiselect (#4024)
# Description of Changes
This pull request introduces significant updates to the file selection
logic, tool rendering, and file context management in the frontend
codebase. The changes aim to improve modularity, enhance
maintainability, and streamline the handling of file-related operations.
Key updates include the introduction of a new `FileSelectionContext`,
refactoring of file selection logic, and updates to tool management and
rendering.
### File Selection Context and Logic Refactor:
* Added a new `FileSelectionContext` to centralize file selection state
and provide utility hooks for managing selected files, selection limits,
and tool mode. (`frontend/src/contexts/FileSelectionContext.tsx`,
[frontend/src/contexts/FileSelectionContext.tsxR1-R77](diffhunk://#diff-bda35f1aaa5eafa0a0dc48e0b1270d862f6da360ba1241234e891f0ca8907327R1-R77))
* Replaced local file selection logic in `FileEditor` with context-based
logic, improving consistency and reducing duplication.
(`frontend/src/components/fileEditor/FileEditor.tsx`,
[[1]](diffhunk://#diff-481d0a2d8a1714d34d21181db63a020b08dfccfbfa80bf47ac9af382dff25310R63-R70)
[[2]](diffhunk://#diff-481d0a2d8a1714d34d21181db63a020b08dfccfbfa80bf47ac9af382dff25310R404-R438)
### Tool Management and Rendering:
* Refactored `ToolRenderer` to use a `Suspense` fallback for lazy-loaded
tools, improving user experience during tool loading.
(`frontend/src/components/tools/ToolRenderer.tsx`,
[frontend/src/components/tools/ToolRenderer.tsxL32-L64](diffhunk://#diff-2083701113aa92cd1f5ce1b4b52cc233858e31ed7bcf39c5bfb1bcc34e99b6a9L32-L64))
* Simplified `ToolPicker` by reusing the `ToolRegistry` type, reducing
redundancy. (`frontend/src/components/tools/ToolPicker.tsx`,
[frontend/src/components/tools/ToolPicker.tsxL4-R4](diffhunk://#diff-e47deca9132018344c159925f1264794acdd57f4b65e582eb9b2a4ea69ec126dL4-R4))
### File Context Enhancements:
* Introduced a utility function `getFileId` for consistent file ID
extraction, replacing repetitive inline logic.
(`frontend/src/contexts/FileContext.tsx`,
[[1]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcR25)
[[2]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL101-R102)
* Updated `FileContextProvider` to use more specific types for PDF
documents, enhancing type safety.
(`frontend/src/contexts/FileContext.tsx`,
[[1]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL350-R351)
[[2]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL384-R385)
### Compression Tool Enhancements:
* Added blob URL cleanup logic to the compression hook to prevent memory
leaks. (`frontend/src/hooks/tools/compress/useCompressOperation.ts`,
[frontend/src/hooks/tools/compress/useCompressOperation.tsR58-L66](diffhunk://#diff-d7815fea0e89989511ae1786f7031cba492b9f2db39b7ade92d9736d1bd4b673R58-L66))
* Adjusted file ID generation in the compression operation to handle
multiple files more effectively.
(`frontend/src/hooks/tools/compress/useCompressOperation.ts`,
[frontend/src/hooks/tools/compress/useCompressOperation.tsL90-R102](diffhunk://#diff-d7815fea0e89989511ae1786f7031cba492b9f2db39b7ade92d9736d1bd4b673L90-R102))
---
## Checklist
### General
- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings
### Documentation
- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)
### UI Changes (if applicable)
- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)
### Testing (if applicable)
- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-07-25 09:37:52 +01:00
|
|
|
let newSelection: string[];
|
2025-08-11 16:40:38 +01:00
|
|
|
|
Feature/v2/multiselect (#4024)
# Description of Changes
This pull request introduces significant updates to the file selection
logic, tool rendering, and file context management in the frontend
codebase. The changes aim to improve modularity, enhance
maintainability, and streamline the handling of file-related operations.
Key updates include the introduction of a new `FileSelectionContext`,
refactoring of file selection logic, and updates to tool management and
rendering.
### File Selection Context and Logic Refactor:
* Added a new `FileSelectionContext` to centralize file selection state
and provide utility hooks for managing selected files, selection limits,
and tool mode. (`frontend/src/contexts/FileSelectionContext.tsx`,
[frontend/src/contexts/FileSelectionContext.tsxR1-R77](diffhunk://#diff-bda35f1aaa5eafa0a0dc48e0b1270d862f6da360ba1241234e891f0ca8907327R1-R77))
* Replaced local file selection logic in `FileEditor` with context-based
logic, improving consistency and reducing duplication.
(`frontend/src/components/fileEditor/FileEditor.tsx`,
[[1]](diffhunk://#diff-481d0a2d8a1714d34d21181db63a020b08dfccfbfa80bf47ac9af382dff25310R63-R70)
[[2]](diffhunk://#diff-481d0a2d8a1714d34d21181db63a020b08dfccfbfa80bf47ac9af382dff25310R404-R438)
### Tool Management and Rendering:
* Refactored `ToolRenderer` to use a `Suspense` fallback for lazy-loaded
tools, improving user experience during tool loading.
(`frontend/src/components/tools/ToolRenderer.tsx`,
[frontend/src/components/tools/ToolRenderer.tsxL32-L64](diffhunk://#diff-2083701113aa92cd1f5ce1b4b52cc233858e31ed7bcf39c5bfb1bcc34e99b6a9L32-L64))
* Simplified `ToolPicker` by reusing the `ToolRegistry` type, reducing
redundancy. (`frontend/src/components/tools/ToolPicker.tsx`,
[frontend/src/components/tools/ToolPicker.tsxL4-R4](diffhunk://#diff-e47deca9132018344c159925f1264794acdd57f4b65e582eb9b2a4ea69ec126dL4-R4))
### File Context Enhancements:
* Introduced a utility function `getFileId` for consistent file ID
extraction, replacing repetitive inline logic.
(`frontend/src/contexts/FileContext.tsx`,
[[1]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcR25)
[[2]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL101-R102)
* Updated `FileContextProvider` to use more specific types for PDF
documents, enhancing type safety.
(`frontend/src/contexts/FileContext.tsx`,
[[1]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL350-R351)
[[2]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL384-R385)
### Compression Tool Enhancements:
* Added blob URL cleanup logic to the compression hook to prevent memory
leaks. (`frontend/src/hooks/tools/compress/useCompressOperation.ts`,
[frontend/src/hooks/tools/compress/useCompressOperation.tsR58-L66](diffhunk://#diff-d7815fea0e89989511ae1786f7031cba492b9f2db39b7ade92d9736d1bd4b673R58-L66))
* Adjusted file ID generation in the compression operation to handle
multiple files more effectively.
(`frontend/src/hooks/tools/compress/useCompressOperation.ts`,
[frontend/src/hooks/tools/compress/useCompressOperation.tsL90-R102](diffhunk://#diff-d7815fea0e89989511ae1786f7031cba492b9f2db39b7ade92d9736d1bd4b673L90-R102))
---
## Checklist
### General
- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings
### Documentation
- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)
### UI Changes (if applicable)
- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)
### Testing (if applicable)
- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-07-25 09:37:52 +01:00
|
|
|
if (isSelected) {
|
|
|
|
// Remove file from selection
|
2025-08-12 14:37:45 +01:00
|
|
|
newSelection = currentSelectedIds.filter(id => id !== contextFileId);
|
Feature/v2/multiselect (#4024)
# Description of Changes
This pull request introduces significant updates to the file selection
logic, tool rendering, and file context management in the frontend
codebase. The changes aim to improve modularity, enhance
maintainability, and streamline the handling of file-related operations.
Key updates include the introduction of a new `FileSelectionContext`,
refactoring of file selection logic, and updates to tool management and
rendering.
### File Selection Context and Logic Refactor:
* Added a new `FileSelectionContext` to centralize file selection state
and provide utility hooks for managing selected files, selection limits,
and tool mode. (`frontend/src/contexts/FileSelectionContext.tsx`,
[frontend/src/contexts/FileSelectionContext.tsxR1-R77](diffhunk://#diff-bda35f1aaa5eafa0a0dc48e0b1270d862f6da360ba1241234e891f0ca8907327R1-R77))
* Replaced local file selection logic in `FileEditor` with context-based
logic, improving consistency and reducing duplication.
(`frontend/src/components/fileEditor/FileEditor.tsx`,
[[1]](diffhunk://#diff-481d0a2d8a1714d34d21181db63a020b08dfccfbfa80bf47ac9af382dff25310R63-R70)
[[2]](diffhunk://#diff-481d0a2d8a1714d34d21181db63a020b08dfccfbfa80bf47ac9af382dff25310R404-R438)
### Tool Management and Rendering:
* Refactored `ToolRenderer` to use a `Suspense` fallback for lazy-loaded
tools, improving user experience during tool loading.
(`frontend/src/components/tools/ToolRenderer.tsx`,
[frontend/src/components/tools/ToolRenderer.tsxL32-L64](diffhunk://#diff-2083701113aa92cd1f5ce1b4b52cc233858e31ed7bcf39c5bfb1bcc34e99b6a9L32-L64))
* Simplified `ToolPicker` by reusing the `ToolRegistry` type, reducing
redundancy. (`frontend/src/components/tools/ToolPicker.tsx`,
[frontend/src/components/tools/ToolPicker.tsxL4-R4](diffhunk://#diff-e47deca9132018344c159925f1264794acdd57f4b65e582eb9b2a4ea69ec126dL4-R4))
### File Context Enhancements:
* Introduced a utility function `getFileId` for consistent file ID
extraction, replacing repetitive inline logic.
(`frontend/src/contexts/FileContext.tsx`,
[[1]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcR25)
[[2]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL101-R102)
* Updated `FileContextProvider` to use more specific types for PDF
documents, enhancing type safety.
(`frontend/src/contexts/FileContext.tsx`,
[[1]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL350-R351)
[[2]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL384-R385)
### Compression Tool Enhancements:
* Added blob URL cleanup logic to the compression hook to prevent memory
leaks. (`frontend/src/hooks/tools/compress/useCompressOperation.ts`,
[frontend/src/hooks/tools/compress/useCompressOperation.tsR58-L66](diffhunk://#diff-d7815fea0e89989511ae1786f7031cba492b9f2db39b7ade92d9736d1bd4b673R58-L66))
* Adjusted file ID generation in the compression operation to handle
multiple files more effectively.
(`frontend/src/hooks/tools/compress/useCompressOperation.ts`,
[frontend/src/hooks/tools/compress/useCompressOperation.tsL90-R102](diffhunk://#diff-d7815fea0e89989511ae1786f7031cba492b9f2db39b7ade92d9736d1bd4b673L90-R102))
---
## Checklist
### General
- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings
### Documentation
- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)
### UI Changes (if applicable)
- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)
### Testing (if applicable)
- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-07-25 09:37:52 +01:00
|
|
|
} else {
|
|
|
|
// Add file to selection
|
|
|
|
if (maxFiles === 1) {
|
|
|
|
newSelection = [contextFileId];
|
2025-07-16 17:53:50 +01:00
|
|
|
} else {
|
Feature/v2/multiselect (#4024)
# Description of Changes
This pull request introduces significant updates to the file selection
logic, tool rendering, and file context management in the frontend
codebase. The changes aim to improve modularity, enhance
maintainability, and streamline the handling of file-related operations.
Key updates include the introduction of a new `FileSelectionContext`,
refactoring of file selection logic, and updates to tool management and
rendering.
### File Selection Context and Logic Refactor:
* Added a new `FileSelectionContext` to centralize file selection state
and provide utility hooks for managing selected files, selection limits,
and tool mode. (`frontend/src/contexts/FileSelectionContext.tsx`,
[frontend/src/contexts/FileSelectionContext.tsxR1-R77](diffhunk://#diff-bda35f1aaa5eafa0a0dc48e0b1270d862f6da360ba1241234e891f0ca8907327R1-R77))
* Replaced local file selection logic in `FileEditor` with context-based
logic, improving consistency and reducing duplication.
(`frontend/src/components/fileEditor/FileEditor.tsx`,
[[1]](diffhunk://#diff-481d0a2d8a1714d34d21181db63a020b08dfccfbfa80bf47ac9af382dff25310R63-R70)
[[2]](diffhunk://#diff-481d0a2d8a1714d34d21181db63a020b08dfccfbfa80bf47ac9af382dff25310R404-R438)
### Tool Management and Rendering:
* Refactored `ToolRenderer` to use a `Suspense` fallback for lazy-loaded
tools, improving user experience during tool loading.
(`frontend/src/components/tools/ToolRenderer.tsx`,
[frontend/src/components/tools/ToolRenderer.tsxL32-L64](diffhunk://#diff-2083701113aa92cd1f5ce1b4b52cc233858e31ed7bcf39c5bfb1bcc34e99b6a9L32-L64))
* Simplified `ToolPicker` by reusing the `ToolRegistry` type, reducing
redundancy. (`frontend/src/components/tools/ToolPicker.tsx`,
[frontend/src/components/tools/ToolPicker.tsxL4-R4](diffhunk://#diff-e47deca9132018344c159925f1264794acdd57f4b65e582eb9b2a4ea69ec126dL4-R4))
### File Context Enhancements:
* Introduced a utility function `getFileId` for consistent file ID
extraction, replacing repetitive inline logic.
(`frontend/src/contexts/FileContext.tsx`,
[[1]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcR25)
[[2]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL101-R102)
* Updated `FileContextProvider` to use more specific types for PDF
documents, enhancing type safety.
(`frontend/src/contexts/FileContext.tsx`,
[[1]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL350-R351)
[[2]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL384-R385)
### Compression Tool Enhancements:
* Added blob URL cleanup logic to the compression hook to prevent memory
leaks. (`frontend/src/hooks/tools/compress/useCompressOperation.ts`,
[frontend/src/hooks/tools/compress/useCompressOperation.tsR58-L66](diffhunk://#diff-d7815fea0e89989511ae1786f7031cba492b9f2db39b7ade92d9736d1bd4b673R58-L66))
* Adjusted file ID generation in the compression operation to handle
multiple files more effectively.
(`frontend/src/hooks/tools/compress/useCompressOperation.ts`,
[frontend/src/hooks/tools/compress/useCompressOperation.tsL90-R102](diffhunk://#diff-d7815fea0e89989511ae1786f7031cba492b9f2db39b7ade92d9736d1bd4b673L90-R102))
---
## Checklist
### General
- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings
### Documentation
- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)
### UI Changes (if applicable)
- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)
### Testing (if applicable)
- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-07-25 09:37:52 +01:00
|
|
|
// Check if we've hit the selection limit
|
2025-08-12 14:37:45 +01:00
|
|
|
if (maxFiles > 1 && currentSelectedIds.length >= maxFiles) {
|
Feature/v2/multiselect (#4024)
# Description of Changes
This pull request introduces significant updates to the file selection
logic, tool rendering, and file context management in the frontend
codebase. The changes aim to improve modularity, enhance
maintainability, and streamline the handling of file-related operations.
Key updates include the introduction of a new `FileSelectionContext`,
refactoring of file selection logic, and updates to tool management and
rendering.
### File Selection Context and Logic Refactor:
* Added a new `FileSelectionContext` to centralize file selection state
and provide utility hooks for managing selected files, selection limits,
and tool mode. (`frontend/src/contexts/FileSelectionContext.tsx`,
[frontend/src/contexts/FileSelectionContext.tsxR1-R77](diffhunk://#diff-bda35f1aaa5eafa0a0dc48e0b1270d862f6da360ba1241234e891f0ca8907327R1-R77))
* Replaced local file selection logic in `FileEditor` with context-based
logic, improving consistency and reducing duplication.
(`frontend/src/components/fileEditor/FileEditor.tsx`,
[[1]](diffhunk://#diff-481d0a2d8a1714d34d21181db63a020b08dfccfbfa80bf47ac9af382dff25310R63-R70)
[[2]](diffhunk://#diff-481d0a2d8a1714d34d21181db63a020b08dfccfbfa80bf47ac9af382dff25310R404-R438)
### Tool Management and Rendering:
* Refactored `ToolRenderer` to use a `Suspense` fallback for lazy-loaded
tools, improving user experience during tool loading.
(`frontend/src/components/tools/ToolRenderer.tsx`,
[frontend/src/components/tools/ToolRenderer.tsxL32-L64](diffhunk://#diff-2083701113aa92cd1f5ce1b4b52cc233858e31ed7bcf39c5bfb1bcc34e99b6a9L32-L64))
* Simplified `ToolPicker` by reusing the `ToolRegistry` type, reducing
redundancy. (`frontend/src/components/tools/ToolPicker.tsx`,
[frontend/src/components/tools/ToolPicker.tsxL4-R4](diffhunk://#diff-e47deca9132018344c159925f1264794acdd57f4b65e582eb9b2a4ea69ec126dL4-R4))
### File Context Enhancements:
* Introduced a utility function `getFileId` for consistent file ID
extraction, replacing repetitive inline logic.
(`frontend/src/contexts/FileContext.tsx`,
[[1]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcR25)
[[2]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL101-R102)
* Updated `FileContextProvider` to use more specific types for PDF
documents, enhancing type safety.
(`frontend/src/contexts/FileContext.tsx`,
[[1]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL350-R351)
[[2]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL384-R385)
### Compression Tool Enhancements:
* Added blob URL cleanup logic to the compression hook to prevent memory
leaks. (`frontend/src/hooks/tools/compress/useCompressOperation.ts`,
[frontend/src/hooks/tools/compress/useCompressOperation.tsR58-L66](diffhunk://#diff-d7815fea0e89989511ae1786f7031cba492b9f2db39b7ade92d9736d1bd4b673R58-L66))
* Adjusted file ID generation in the compression operation to handle
multiple files more effectively.
(`frontend/src/hooks/tools/compress/useCompressOperation.ts`,
[frontend/src/hooks/tools/compress/useCompressOperation.tsL90-R102](diffhunk://#diff-d7815fea0e89989511ae1786f7031cba492b9f2db39b7ade92d9736d1bd4b673L90-R102))
---
## Checklist
### General
- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings
### Documentation
- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)
### UI Changes (if applicable)
- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)
### Testing (if applicable)
- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-07-25 09:37:52 +01:00
|
|
|
setStatus(`Maximum ${maxFiles} files can be selected`);
|
|
|
|
return;
|
2025-07-16 17:53:50 +01:00
|
|
|
}
|
2025-08-12 14:37:45 +01:00
|
|
|
newSelection = [...currentSelectedIds, contextFileId];
|
2025-07-16 17:53:50 +01:00
|
|
|
}
|
|
|
|
}
|
2025-08-11 16:40:38 +01:00
|
|
|
|
Feature/v2/multiselect (#4024)
# Description of Changes
This pull request introduces significant updates to the file selection
logic, tool rendering, and file context management in the frontend
codebase. The changes aim to improve modularity, enhance
maintainability, and streamline the handling of file-related operations.
Key updates include the introduction of a new `FileSelectionContext`,
refactoring of file selection logic, and updates to tool management and
rendering.
### File Selection Context and Logic Refactor:
* Added a new `FileSelectionContext` to centralize file selection state
and provide utility hooks for managing selected files, selection limits,
and tool mode. (`frontend/src/contexts/FileSelectionContext.tsx`,
[frontend/src/contexts/FileSelectionContext.tsxR1-R77](diffhunk://#diff-bda35f1aaa5eafa0a0dc48e0b1270d862f6da360ba1241234e891f0ca8907327R1-R77))
* Replaced local file selection logic in `FileEditor` with context-based
logic, improving consistency and reducing duplication.
(`frontend/src/components/fileEditor/FileEditor.tsx`,
[[1]](diffhunk://#diff-481d0a2d8a1714d34d21181db63a020b08dfccfbfa80bf47ac9af382dff25310R63-R70)
[[2]](diffhunk://#diff-481d0a2d8a1714d34d21181db63a020b08dfccfbfa80bf47ac9af382dff25310R404-R438)
### Tool Management and Rendering:
* Refactored `ToolRenderer` to use a `Suspense` fallback for lazy-loaded
tools, improving user experience during tool loading.
(`frontend/src/components/tools/ToolRenderer.tsx`,
[frontend/src/components/tools/ToolRenderer.tsxL32-L64](diffhunk://#diff-2083701113aa92cd1f5ce1b4b52cc233858e31ed7bcf39c5bfb1bcc34e99b6a9L32-L64))
* Simplified `ToolPicker` by reusing the `ToolRegistry` type, reducing
redundancy. (`frontend/src/components/tools/ToolPicker.tsx`,
[frontend/src/components/tools/ToolPicker.tsxL4-R4](diffhunk://#diff-e47deca9132018344c159925f1264794acdd57f4b65e582eb9b2a4ea69ec126dL4-R4))
### File Context Enhancements:
* Introduced a utility function `getFileId` for consistent file ID
extraction, replacing repetitive inline logic.
(`frontend/src/contexts/FileContext.tsx`,
[[1]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcR25)
[[2]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL101-R102)
* Updated `FileContextProvider` to use more specific types for PDF
documents, enhancing type safety.
(`frontend/src/contexts/FileContext.tsx`,
[[1]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL350-R351)
[[2]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL384-R385)
### Compression Tool Enhancements:
* Added blob URL cleanup logic to the compression hook to prevent memory
leaks. (`frontend/src/hooks/tools/compress/useCompressOperation.ts`,
[frontend/src/hooks/tools/compress/useCompressOperation.tsR58-L66](diffhunk://#diff-d7815fea0e89989511ae1786f7031cba492b9f2db39b7ade92d9736d1bd4b673R58-L66))
* Adjusted file ID generation in the compression operation to handle
multiple files more effectively.
(`frontend/src/hooks/tools/compress/useCompressOperation.ts`,
[frontend/src/hooks/tools/compress/useCompressOperation.tsL90-R102](diffhunk://#diff-d7815fea0e89989511ae1786f7031cba492b9f2db39b7ade92d9736d1bd4b673L90-R102))
---
## Checklist
### General
- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings
### Documentation
- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)
### UI Changes (if applicable)
- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)
### Testing (if applicable)
- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-07-25 09:37:52 +01:00
|
|
|
// Update context
|
|
|
|
setContextSelectedFiles(newSelection);
|
2025-08-11 16:40:38 +01:00
|
|
|
|
Feature/v2/multiselect (#4024)
# Description of Changes
This pull request introduces significant updates to the file selection
logic, tool rendering, and file context management in the frontend
codebase. The changes aim to improve modularity, enhance
maintainability, and streamline the handling of file-related operations.
Key updates include the introduction of a new `FileSelectionContext`,
refactoring of file selection logic, and updates to tool management and
rendering.
### File Selection Context and Logic Refactor:
* Added a new `FileSelectionContext` to centralize file selection state
and provide utility hooks for managing selected files, selection limits,
and tool mode. (`frontend/src/contexts/FileSelectionContext.tsx`,
[frontend/src/contexts/FileSelectionContext.tsxR1-R77](diffhunk://#diff-bda35f1aaa5eafa0a0dc48e0b1270d862f6da360ba1241234e891f0ca8907327R1-R77))
* Replaced local file selection logic in `FileEditor` with context-based
logic, improving consistency and reducing duplication.
(`frontend/src/components/fileEditor/FileEditor.tsx`,
[[1]](diffhunk://#diff-481d0a2d8a1714d34d21181db63a020b08dfccfbfa80bf47ac9af382dff25310R63-R70)
[[2]](diffhunk://#diff-481d0a2d8a1714d34d21181db63a020b08dfccfbfa80bf47ac9af382dff25310R404-R438)
### Tool Management and Rendering:
* Refactored `ToolRenderer` to use a `Suspense` fallback for lazy-loaded
tools, improving user experience during tool loading.
(`frontend/src/components/tools/ToolRenderer.tsx`,
[frontend/src/components/tools/ToolRenderer.tsxL32-L64](diffhunk://#diff-2083701113aa92cd1f5ce1b4b52cc233858e31ed7bcf39c5bfb1bcc34e99b6a9L32-L64))
* Simplified `ToolPicker` by reusing the `ToolRegistry` type, reducing
redundancy. (`frontend/src/components/tools/ToolPicker.tsx`,
[frontend/src/components/tools/ToolPicker.tsxL4-R4](diffhunk://#diff-e47deca9132018344c159925f1264794acdd57f4b65e582eb9b2a4ea69ec126dL4-R4))
### File Context Enhancements:
* Introduced a utility function `getFileId` for consistent file ID
extraction, replacing repetitive inline logic.
(`frontend/src/contexts/FileContext.tsx`,
[[1]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcR25)
[[2]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL101-R102)
* Updated `FileContextProvider` to use more specific types for PDF
documents, enhancing type safety.
(`frontend/src/contexts/FileContext.tsx`,
[[1]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL350-R351)
[[2]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL384-R385)
### Compression Tool Enhancements:
* Added blob URL cleanup logic to the compression hook to prevent memory
leaks. (`frontend/src/hooks/tools/compress/useCompressOperation.ts`,
[frontend/src/hooks/tools/compress/useCompressOperation.tsR58-L66](diffhunk://#diff-d7815fea0e89989511ae1786f7031cba492b9f2db39b7ade92d9736d1bd4b673R58-L66))
* Adjusted file ID generation in the compression operation to handle
multiple files more effectively.
(`frontend/src/hooks/tools/compress/useCompressOperation.ts`,
[frontend/src/hooks/tools/compress/useCompressOperation.tsL90-R102](diffhunk://#diff-d7815fea0e89989511ae1786f7031cba492b9f2db39b7ade92d9736d1bd4b673L90-R102))
---
## Checklist
### General
- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings
### Documentation
- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)
### UI Changes (if applicable)
- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)
### Testing (if applicable)
- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-07-25 09:37:52 +01:00
|
|
|
// Update tool selection context if in tool mode
|
|
|
|
if (isToolMode || toolMode) {
|
2025-08-12 14:37:45 +01:00
|
|
|
setToolSelectedFiles(newSelection);
|
Feature/v2/multiselect (#4024)
# Description of Changes
This pull request introduces significant updates to the file selection
logic, tool rendering, and file context management in the frontend
codebase. The changes aim to improve modularity, enhance
maintainability, and streamline the handling of file-related operations.
Key updates include the introduction of a new `FileSelectionContext`,
refactoring of file selection logic, and updates to tool management and
rendering.
### File Selection Context and Logic Refactor:
* Added a new `FileSelectionContext` to centralize file selection state
and provide utility hooks for managing selected files, selection limits,
and tool mode. (`frontend/src/contexts/FileSelectionContext.tsx`,
[frontend/src/contexts/FileSelectionContext.tsxR1-R77](diffhunk://#diff-bda35f1aaa5eafa0a0dc48e0b1270d862f6da360ba1241234e891f0ca8907327R1-R77))
* Replaced local file selection logic in `FileEditor` with context-based
logic, improving consistency and reducing duplication.
(`frontend/src/components/fileEditor/FileEditor.tsx`,
[[1]](diffhunk://#diff-481d0a2d8a1714d34d21181db63a020b08dfccfbfa80bf47ac9af382dff25310R63-R70)
[[2]](diffhunk://#diff-481d0a2d8a1714d34d21181db63a020b08dfccfbfa80bf47ac9af382dff25310R404-R438)
### Tool Management and Rendering:
* Refactored `ToolRenderer` to use a `Suspense` fallback for lazy-loaded
tools, improving user experience during tool loading.
(`frontend/src/components/tools/ToolRenderer.tsx`,
[frontend/src/components/tools/ToolRenderer.tsxL32-L64](diffhunk://#diff-2083701113aa92cd1f5ce1b4b52cc233858e31ed7bcf39c5bfb1bcc34e99b6a9L32-L64))
* Simplified `ToolPicker` by reusing the `ToolRegistry` type, reducing
redundancy. (`frontend/src/components/tools/ToolPicker.tsx`,
[frontend/src/components/tools/ToolPicker.tsxL4-R4](diffhunk://#diff-e47deca9132018344c159925f1264794acdd57f4b65e582eb9b2a4ea69ec126dL4-R4))
### File Context Enhancements:
* Introduced a utility function `getFileId` for consistent file ID
extraction, replacing repetitive inline logic.
(`frontend/src/contexts/FileContext.tsx`,
[[1]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcR25)
[[2]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL101-R102)
* Updated `FileContextProvider` to use more specific types for PDF
documents, enhancing type safety.
(`frontend/src/contexts/FileContext.tsx`,
[[1]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL350-R351)
[[2]](diffhunk://#diff-95b3d103fa434f81fdae55f2ea14eda705f0def45a0f2c5754f81de6f2fd93bcL384-R385)
### Compression Tool Enhancements:
* Added blob URL cleanup logic to the compression hook to prevent memory
leaks. (`frontend/src/hooks/tools/compress/useCompressOperation.ts`,
[frontend/src/hooks/tools/compress/useCompressOperation.tsR58-L66](diffhunk://#diff-d7815fea0e89989511ae1786f7031cba492b9f2db39b7ade92d9736d1bd4b673R58-L66))
* Adjusted file ID generation in the compression operation to handle
multiple files more effectively.
(`frontend/src/hooks/tools/compress/useCompressOperation.ts`,
[frontend/src/hooks/tools/compress/useCompressOperation.tsL90-R102](diffhunk://#diff-d7815fea0e89989511ae1786f7031cba492b9f2db39b7ade92d9736d1bd4b673L90-R102))
---
## Checklist
### General
- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings
### Documentation
- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)
### UI Changes (if applicable)
- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)
### Testing (if applicable)
- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-07-25 09:37:52 +01:00
|
|
|
}
|
2025-08-20 15:59:07 +01:00
|
|
|
}, [setContextSelectedFiles, maxFiles, setStatus, isToolMode, toolMode, setToolSelectedFiles, activeFileRecords]);
|
2025-07-16 17:53:50 +01:00
|
|
|
|
|
|
|
const toggleSelectionMode = useCallback(() => {
|
|
|
|
setSelectionMode(prev => {
|
|
|
|
const newMode = !prev;
|
|
|
|
if (!newMode) {
|
|
|
|
setContextSelectedFiles([]);
|
|
|
|
}
|
|
|
|
return newMode;
|
|
|
|
});
|
|
|
|
}, [setContextSelectedFiles]);
|
|
|
|
|
2025-08-20 12:53:02 +01:00
|
|
|
// File reordering handler for drag and drop
|
|
|
|
const handleReorderFiles = useCallback((sourceFileId: string, targetFileId: string, selectedFileIds: string[]) => {
|
2025-08-20 15:59:07 +01:00
|
|
|
const currentIds = activeFileRecords.map(r => r.id);
|
|
|
|
|
|
|
|
// Find indices
|
|
|
|
const sourceIndex = currentIds.findIndex(id => id === sourceFileId);
|
|
|
|
const targetIndex = currentIds.findIndex(id => id === targetFileId);
|
|
|
|
|
|
|
|
if (sourceIndex === -1 || targetIndex === -1) {
|
|
|
|
console.warn('Could not find source or target file for reordering');
|
|
|
|
return;
|
|
|
|
}
|
2025-07-16 17:53:50 +01:00
|
|
|
|
2025-08-20 15:59:07 +01:00
|
|
|
// Handle multi-file selection reordering
|
|
|
|
const filesToMove = selectedFileIds.length > 1
|
|
|
|
? selectedFileIds.filter(id => currentIds.includes(id))
|
|
|
|
: [sourceFileId];
|
2025-07-16 17:53:50 +01:00
|
|
|
|
2025-08-20 15:59:07 +01:00
|
|
|
// Create new order
|
|
|
|
const newOrder = [...currentIds];
|
|
|
|
|
|
|
|
// Remove files to move from their current positions (in reverse order to maintain indices)
|
|
|
|
const sourceIndices = filesToMove.map(id => newOrder.findIndex(nId => nId === id))
|
|
|
|
.sort((a, b) => b - a); // Sort descending
|
2025-08-20 12:53:02 +01:00
|
|
|
|
2025-08-20 15:59:07 +01:00
|
|
|
sourceIndices.forEach(index => {
|
|
|
|
newOrder.splice(index, 1);
|
|
|
|
});
|
2025-07-16 17:53:50 +01:00
|
|
|
|
2025-08-20 15:59:07 +01:00
|
|
|
// Calculate insertion index after removals
|
|
|
|
let insertIndex = newOrder.findIndex(id => id === targetFileId);
|
|
|
|
if (insertIndex !== -1) {
|
|
|
|
// Determine if moving forward or backward
|
|
|
|
const isMovingForward = sourceIndex < targetIndex;
|
|
|
|
if (isMovingForward) {
|
|
|
|
// Moving forward: insert after target
|
|
|
|
insertIndex += 1;
|
|
|
|
} else {
|
|
|
|
// Moving backward: insert before target (insertIndex already correct)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Target was moved, insert at end
|
|
|
|
insertIndex = newOrder.length;
|
|
|
|
}
|
2025-07-16 17:53:50 +01:00
|
|
|
|
2025-08-20 15:59:07 +01:00
|
|
|
// Insert files at the calculated position
|
|
|
|
newOrder.splice(insertIndex, 0, ...filesToMove);
|
2025-07-16 17:53:50 +01:00
|
|
|
|
2025-08-20 15:59:07 +01:00
|
|
|
// Update file order
|
|
|
|
reorderFiles(newOrder);
|
2025-07-16 17:53:50 +01:00
|
|
|
|
2025-08-20 15:59:07 +01:00
|
|
|
// Update status
|
|
|
|
const moveCount = filesToMove.length;
|
|
|
|
setStatus(`${moveCount > 1 ? `${moveCount} files` : 'File'} reordered`);
|
|
|
|
}, [activeFileRecords, reorderFiles, setStatus]);
|
2025-07-16 17:53:50 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// File operations using context
|
|
|
|
const handleDeleteFile = useCallback((fileId: string) => {
|
2025-08-20 15:59:07 +01:00
|
|
|
const record = activeFileRecords.find(r => r.id === fileId);
|
|
|
|
const file = record ? selectors.getFile(record.id) : null;
|
2025-08-11 16:40:38 +01:00
|
|
|
|
2025-08-20 15:59:07 +01:00
|
|
|
if (record && file) {
|
2025-07-16 17:53:50 +01:00
|
|
|
// Record close operation
|
2025-08-20 15:59:07 +01:00
|
|
|
const fileName = file.name;
|
|
|
|
const contextFileId = record.id;
|
2025-07-16 17:53:50 +01:00
|
|
|
const operationId = `close-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
|
|
const operation: FileOperation = {
|
|
|
|
id: operationId,
|
|
|
|
type: 'remove',
|
|
|
|
timestamp: Date.now(),
|
|
|
|
fileIds: [fileName],
|
|
|
|
status: 'pending',
|
|
|
|
metadata: {
|
|
|
|
originalFileName: fileName,
|
2025-08-20 15:59:07 +01:00
|
|
|
fileSize: record.size,
|
2025-07-16 17:53:50 +01:00
|
|
|
parameters: {
|
|
|
|
action: 'close',
|
|
|
|
reason: 'user_request'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2025-08-15 00:52:36 +01:00
|
|
|
|
2025-07-16 17:53:50 +01:00
|
|
|
// Remove file from context but keep in storage (close, don't delete)
|
2025-08-14 18:07:18 +01:00
|
|
|
removeFiles([contextFileId], false);
|
2025-08-11 16:40:38 +01:00
|
|
|
|
2025-07-16 17:53:50 +01:00
|
|
|
// Remove from context selections
|
2025-08-12 14:37:45 +01:00
|
|
|
setContextSelectedFiles((prev: string[]) => {
|
2025-07-16 17:53:50 +01:00
|
|
|
const safePrev = Array.isArray(prev) ? prev : [];
|
2025-08-14 18:07:18 +01:00
|
|
|
return safePrev.filter(id => id !== contextFileId);
|
2025-07-16 17:53:50 +01:00
|
|
|
});
|
|
|
|
}
|
2025-08-20 15:59:07 +01:00
|
|
|
}, [activeFileRecords, selectors, removeFiles, setContextSelectedFiles]);
|
2025-07-16 17:53:50 +01:00
|
|
|
|
|
|
|
const handleViewFile = useCallback((fileId: string) => {
|
2025-08-20 15:59:07 +01:00
|
|
|
const record = activeFileRecords.find(r => r.id === fileId);
|
|
|
|
if (record) {
|
2025-08-10 21:08:32 +01:00
|
|
|
// Set the file as selected in context and switch to viewer for preview
|
2025-08-20 15:59:07 +01:00
|
|
|
setContextSelectedFiles([fileId]);
|
2025-08-10 21:08:32 +01:00
|
|
|
setCurrentView('viewer');
|
2025-07-16 17:53:50 +01:00
|
|
|
}
|
2025-08-20 15:59:07 +01:00
|
|
|
}, [activeFileRecords, setContextSelectedFiles, setCurrentView]);
|
2025-07-16 17:53:50 +01:00
|
|
|
|
|
|
|
const handleMergeFromHere = useCallback((fileId: string) => {
|
2025-08-20 15:59:07 +01:00
|
|
|
const startIndex = activeFileRecords.findIndex(r => r.id === fileId);
|
2025-07-16 17:53:50 +01:00
|
|
|
if (startIndex === -1) return;
|
|
|
|
|
2025-08-20 15:59:07 +01:00
|
|
|
const recordsToMerge = activeFileRecords.slice(startIndex);
|
|
|
|
const filesToMerge = recordsToMerge.map(r => selectors.getFile(r.id)).filter(Boolean) as File[];
|
2025-07-16 17:53:50 +01:00
|
|
|
if (onMergeFiles) {
|
|
|
|
onMergeFiles(filesToMerge);
|
|
|
|
}
|
2025-08-20 15:59:07 +01:00
|
|
|
}, [activeFileRecords, selectors, onMergeFiles]);
|
2025-07-16 17:53:50 +01:00
|
|
|
|
|
|
|
const handleSplitFile = useCallback((fileId: string) => {
|
2025-08-20 15:59:07 +01:00
|
|
|
const file = selectors.getFile(fileId);
|
2025-07-16 17:53:50 +01:00
|
|
|
if (file && onOpenPageEditor) {
|
2025-08-20 15:59:07 +01:00
|
|
|
onOpenPageEditor(file);
|
2025-07-16 17:53:50 +01:00
|
|
|
}
|
2025-08-20 15:59:07 +01:00
|
|
|
}, [selectors, onOpenPageEditor]);
|
2025-07-16 17:53:50 +01:00
|
|
|
|
|
|
|
const handleLoadFromStorage = useCallback(async (selectedFiles: any[]) => {
|
|
|
|
if (selectedFiles.length === 0) return;
|
|
|
|
|
|
|
|
try {
|
2025-08-20 15:59:07 +01:00
|
|
|
// Use FileContext to handle loading stored files
|
|
|
|
// The files are already in FileContext, just need to add them to active files
|
2025-07-16 17:53:50 +01:00
|
|
|
setStatus(`Loaded ${selectedFiles.length} files from storage`);
|
|
|
|
} catch (err) {
|
|
|
|
console.error('Error loading files from storage:', err);
|
|
|
|
setError('Failed to load some files from storage');
|
|
|
|
}
|
2025-08-20 15:59:07 +01:00
|
|
|
}, []);
|
2025-07-16 17:53:50 +01:00
|
|
|
|
|
|
|
|
|
|
|
return (
|
2025-08-04 15:01:36 +01:00
|
|
|
<Dropzone
|
|
|
|
onDrop={handleFileUpload}
|
|
|
|
multiple={true}
|
|
|
|
maxSize={2 * 1024 * 1024 * 1024}
|
2025-08-11 16:40:38 +01:00
|
|
|
style={{
|
2025-08-04 15:01:36 +01:00
|
|
|
height: '100vh',
|
|
|
|
border: 'none',
|
|
|
|
borderRadius: 0,
|
|
|
|
backgroundColor: 'transparent'
|
|
|
|
}}
|
|
|
|
activateOnClick={false}
|
|
|
|
activateOnDrag={true}
|
|
|
|
>
|
|
|
|
<Box pos="relative" h="100vh" style={{ overflow: 'auto' }}>
|
|
|
|
<LoadingOverlay visible={false} />
|
|
|
|
|
|
|
|
<Box p="md" pt="xl">
|
|
|
|
<Group mb="md">
|
|
|
|
{showBulkActions && !toolMode && (
|
|
|
|
<>
|
|
|
|
<Button onClick={selectAll} variant="light">Select All</Button>
|
|
|
|
<Button onClick={deselectAll} variant="light">Deselect All</Button>
|
|
|
|
<Button onClick={closeAllFiles} variant="light" color="orange">
|
|
|
|
Close All
|
2025-07-16 17:53:50 +01:00
|
|
|
</Button>
|
2025-08-04 15:01:36 +01:00
|
|
|
</>
|
|
|
|
)}
|
|
|
|
</Group>
|
2025-07-16 17:53:50 +01:00
|
|
|
|
|
|
|
|
2025-08-20 15:59:07 +01:00
|
|
|
{activeFileRecords.length === 0 && !zipExtractionProgress.isExtracting ? (
|
2025-07-16 17:53:50 +01:00
|
|
|
<Center h="60vh">
|
|
|
|
<Stack align="center" gap="md">
|
|
|
|
<Text size="lg" c="dimmed">📁</Text>
|
|
|
|
<Text c="dimmed">No files loaded</Text>
|
|
|
|
<Text size="sm" c="dimmed">Upload PDF files, ZIP archives, or load from storage to get started</Text>
|
|
|
|
</Stack>
|
|
|
|
</Center>
|
2025-08-20 15:59:07 +01:00
|
|
|
) : activeFileRecords.length === 0 && zipExtractionProgress.isExtracting ? (
|
2025-07-16 17:53:50 +01:00
|
|
|
<Box>
|
|
|
|
<SkeletonLoader type="controls" />
|
2025-08-11 16:40:38 +01:00
|
|
|
|
2025-07-16 17:53:50 +01:00
|
|
|
{/* ZIP Extraction Progress */}
|
|
|
|
{zipExtractionProgress.isExtracting && (
|
|
|
|
<Box mb="md" p="sm" style={{ backgroundColor: 'var(--mantine-color-orange-0)', borderRadius: 8 }}>
|
|
|
|
<Group justify="space-between" mb="xs">
|
|
|
|
<Text size="sm" fw={500}>Extracting ZIP archive...</Text>
|
|
|
|
<Text size="sm" c="dimmed">{Math.round(zipExtractionProgress.progress)}%</Text>
|
|
|
|
</Group>
|
|
|
|
<Text size="xs" c="dimmed" mb="xs">
|
|
|
|
{zipExtractionProgress.currentFile || 'Processing files...'}
|
|
|
|
</Text>
|
|
|
|
<Text size="xs" c="dimmed" mb="xs">
|
|
|
|
{zipExtractionProgress.extractedCount} of {zipExtractionProgress.totalFiles} files extracted
|
|
|
|
</Text>
|
2025-08-11 16:40:38 +01:00
|
|
|
<div style={{
|
|
|
|
width: '100%',
|
|
|
|
height: '4px',
|
|
|
|
backgroundColor: 'var(--mantine-color-gray-2)',
|
2025-07-16 17:53:50 +01:00
|
|
|
borderRadius: '2px',
|
|
|
|
overflow: 'hidden'
|
|
|
|
}}>
|
|
|
|
<div style={{
|
|
|
|
width: `${Math.round(zipExtractionProgress.progress)}%`,
|
|
|
|
height: '100%',
|
|
|
|
backgroundColor: 'var(--mantine-color-orange-6)',
|
|
|
|
transition: 'width 0.3s ease'
|
|
|
|
}} />
|
|
|
|
</div>
|
|
|
|
</Box>
|
|
|
|
)}
|
2025-08-11 16:40:38 +01:00
|
|
|
|
|
|
|
|
2025-07-16 17:53:50 +01:00
|
|
|
<SkeletonLoader type="fileGrid" count={6} />
|
|
|
|
</Box>
|
|
|
|
) : (
|
2025-08-20 12:53:02 +01:00
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
display: 'grid',
|
|
|
|
gridTemplateColumns: 'repeat(auto-fill, minmax(320px, 1fr))',
|
|
|
|
gap: '1.5rem',
|
|
|
|
padding: '1rem',
|
|
|
|
pointerEvents: 'auto'
|
|
|
|
}}
|
|
|
|
>
|
2025-08-20 15:59:07 +01:00
|
|
|
{activeFileRecords.map((record, index) => {
|
|
|
|
const fileItem = recordToFileItem(record);
|
|
|
|
if (!fileItem) return null;
|
|
|
|
|
|
|
|
return (
|
|
|
|
<FileThumbnail
|
|
|
|
key={record.id}
|
|
|
|
file={fileItem}
|
|
|
|
index={index}
|
|
|
|
totalFiles={activeFileRecords.length}
|
|
|
|
selectedFiles={localSelectedIds}
|
|
|
|
selectionMode={selectionMode}
|
|
|
|
onToggleFile={toggleFile}
|
|
|
|
onDeleteFile={handleDeleteFile}
|
|
|
|
onViewFile={handleViewFile}
|
|
|
|
onSetStatus={setStatus}
|
|
|
|
onReorderFiles={handleReorderFiles}
|
|
|
|
toolMode={toolMode}
|
|
|
|
isSupported={isFileSupported(fileItem.name)}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
})}
|
2025-08-18 23:19:44 +01:00
|
|
|
</div>
|
2025-07-16 17:53:50 +01:00
|
|
|
)}
|
|
|
|
</Box>
|
|
|
|
|
|
|
|
{/* File Picker Modal */}
|
|
|
|
<FilePickerModal
|
|
|
|
opened={showFilePickerModal}
|
|
|
|
onClose={() => setShowFilePickerModal(false)}
|
|
|
|
storedFiles={[]} // FileEditor doesn't have access to stored files, needs to be passed from parent
|
|
|
|
onSelectFiles={handleLoadFromStorage}
|
|
|
|
/>
|
|
|
|
|
|
|
|
{status && (
|
|
|
|
<Notification
|
|
|
|
color="blue"
|
|
|
|
mt="md"
|
|
|
|
onClose={() => setStatus(null)}
|
|
|
|
style={{ position: 'fixed', bottom: 20, right: 20, zIndex: 1000 }}
|
|
|
|
>
|
|
|
|
{status}
|
|
|
|
</Notification>
|
|
|
|
)}
|
|
|
|
|
|
|
|
{error && (
|
|
|
|
<Notification
|
|
|
|
color="red"
|
|
|
|
mt="md"
|
|
|
|
onClose={() => setError(null)}
|
|
|
|
style={{ position: 'fixed', bottom: 80, right: 20, zIndex: 1000 }}
|
|
|
|
>
|
|
|
|
{error}
|
|
|
|
</Notification>
|
|
|
|
)}
|
2025-08-04 15:01:36 +01:00
|
|
|
</Box>
|
|
|
|
</Dropzone>
|
2025-07-16 17:53:50 +01:00
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default FileEditor;
|