mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-09-18 01:19:24 +00:00
Clean up
This commit is contained in:
parent
3b3a2df392
commit
4e5789e8f4
@ -2,275 +2,318 @@
|
||||
|
||||
## Overview
|
||||
|
||||
Stirling PDF implements a comprehensive file history tracking system that embeds metadata directly into PDF documents using the PDF keywords field. This system tracks tool operations, version progression, and file lineage through the processing pipeline.
|
||||
Stirling PDF implements a client-side file history system using IndexedDB storage. File metadata, including version history and tool chains, are stored as `StirlingFileStub` objects that travel alongside the actual file data. This enables comprehensive version tracking, tool history, and file lineage management without modifying PDF content.
|
||||
|
||||
## PDF Metadata Format
|
||||
## Storage Architecture
|
||||
|
||||
### Storage Mechanism
|
||||
File history is stored in the PDF **Keywords** field as a JSON string with the prefix `stirling-history:`.
|
||||
### IndexedDB-Based Storage
|
||||
File history is stored in the browser's IndexedDB using the `fileStorage` service, providing:
|
||||
- **Persistent storage**: Survives browser sessions and page reloads
|
||||
- **Large capacity**: Supports files up to 100GB+ with full metadata
|
||||
- **Fast queries**: Optimized for file browsing and history lookups
|
||||
- **Type safety**: Structured TypeScript interfaces
|
||||
|
||||
### Metadata Structure
|
||||
### Core Data Structures
|
||||
|
||||
```typescript
|
||||
interface PDFHistoryMetadata {
|
||||
stirlingHistory: {
|
||||
originalFileId: string; // UUID of the root file in the version chain
|
||||
parentFileId?: string; // UUID of the immediate parent file
|
||||
versionNumber: number; // Version number (1, 2, 3, etc.)
|
||||
toolChain: ToolOperation[]; // Array of applied tool operations
|
||||
formatVersion: '1.0'; // Metadata format version
|
||||
};
|
||||
interface StirlingFileStub extends BaseFileMetadata {
|
||||
id: FileId; // Unique file identifier (UUID)
|
||||
quickKey: string; // Deduplication key: name|size|lastModified
|
||||
thumbnailUrl?: string; // Generated thumbnail blob URL
|
||||
processedFile?: ProcessedFileMetadata; // PDF page data and processing results
|
||||
|
||||
// File Metadata
|
||||
name: string;
|
||||
size: number;
|
||||
type: string;
|
||||
lastModified: number;
|
||||
createdAt: number;
|
||||
|
||||
// Version Control
|
||||
isLeaf: boolean; // True if this is the latest version
|
||||
versionNumber?: number; // Version number (1, 2, 3, etc.)
|
||||
originalFileId?: string; // UUID of the root file in version chain
|
||||
parentFileId?: string; // UUID of immediate parent file
|
||||
|
||||
// Tool History
|
||||
toolHistory?: ToolOperation[]; // Complete sequence of applied tools
|
||||
}
|
||||
|
||||
interface ToolOperation {
|
||||
toolName: string; // Tool identifier (e.g., 'compress', 'sanitize')
|
||||
timestamp: number; // When the tool was applied
|
||||
parameters?: Record<string, any>; // Tool-specific parameters (optional)
|
||||
}
|
||||
|
||||
interface StoredStirlingFileRecord extends StirlingFileStub {
|
||||
data: ArrayBuffer; // Actual file content
|
||||
fileId: FileId; // Duplicate for indexing
|
||||
}
|
||||
```
|
||||
|
||||
### Standard PDF Metadata Fields Used
|
||||
The system uses industry-standard PDF document information fields:
|
||||
- **Creator**: Set to "Stirling-PDF" (identifies the application)
|
||||
- **Producer**: Set to "Stirling-PDF" (identifies the PDF library/processor)
|
||||
- **Title, Author, Subject, CreationDate**: Automatically preserved by pdf-lib during processing
|
||||
- **Keywords**: Enhanced with Stirling history data while preserving user keywords
|
||||
|
||||
**Date Handling Strategy**:
|
||||
- **PDF CreationDate**: Preserved automatically (document creation date)
|
||||
- **File.lastModified**: Source of truth for "when file was last changed" (original upload time or tool processing time)
|
||||
- **No duplication**: Single timestamp approach using File.lastModified for all UI displays
|
||||
|
||||
### Example PDF Document Information
|
||||
```
|
||||
PDF Document Info:
|
||||
Title: "User Document Title" (preserved from original)
|
||||
Author: "Document Author" (preserved from original)
|
||||
Creator: "Stirling-PDF"
|
||||
Producer: "Stirling-PDF"
|
||||
CreationDate: "2025-01-01T10:30:00Z" (preserved from original)
|
||||
Keywords: ["user-keyword", "stirling-history:{\"stirlingHistory\":{\"originalFileId\":\"abc123\",\"versionNumber\":2,\"toolChain\":[{\"toolName\":\"compress\",\"timestamp\":1756825614618},{\"toolName\":\"sanitize\",\"timestamp\":1756825631545}],\"formatVersion\":\"1.0\"}}"]
|
||||
|
||||
File System:
|
||||
lastModified: 1756825631545 (tool processing time - source of truth for "when file was last changed")
|
||||
```
|
||||
|
||||
## Version Numbering System
|
||||
## Version Management System
|
||||
|
||||
### Version Progression
|
||||
- **v0**: Original uploaded file (no Stirling PDF processing)
|
||||
- **v1**: First tool applied to original file
|
||||
- **v2**: Second tool applied (inherits from v1)
|
||||
- **v3**: Third tool applied (inherits from v2)
|
||||
- **v1**: Original uploaded file (first version)
|
||||
- **v2**: First tool applied to original
|
||||
- **v3**: Second tool applied (inherits from v2)
|
||||
- **v4**: Third tool applied (inherits from v3)
|
||||
- **etc.**
|
||||
|
||||
### Version Relationships
|
||||
### Leaf Node System
|
||||
Only the latest version of each file family is marked as `isLeaf: true`:
|
||||
- **Leaf files**: Show in default file list, available for tool processing
|
||||
- **History files**: Hidden by default, accessible via history expansion
|
||||
|
||||
### File Relationships
|
||||
```
|
||||
document.pdf (v0)
|
||||
document.pdf (v1, isLeaf: false)
|
||||
↓ compress
|
||||
document.pdf (v1: compress)
|
||||
document.pdf (v2, isLeaf: false)
|
||||
↓ sanitize
|
||||
document.pdf (v2: compress → sanitize)
|
||||
↓ ocr
|
||||
document.pdf (v3: compress → sanitize → ocr)
|
||||
document.pdf (v3, isLeaf: true) ← Current active version
|
||||
```
|
||||
|
||||
## File Lineage Tracking
|
||||
|
||||
### Original File ID
|
||||
The `originalFileId` remains constant throughout the entire version chain, enabling grouping of all versions of the same logical document.
|
||||
|
||||
### Parent-Child Relationships
|
||||
Each processed file references its immediate parent via `parentFileId`, creating a complete audit trail.
|
||||
|
||||
### Tool Chain
|
||||
The `toolChain` array maintains the complete sequence of tool operations applied to reach the current version.
|
||||
|
||||
## Implementation Architecture
|
||||
|
||||
### Frontend Components
|
||||
### 1. FileStorage Service (`fileStorage.ts`)
|
||||
|
||||
#### 1. PDF Metadata Service (`pdfMetadataService.ts`)
|
||||
- **PDF-lib Integration**: Uses pdf-lib for metadata injection/extraction
|
||||
- **Caching**: ContentCache with 10-minute TTL for performance
|
||||
- **Encryption Support**: Handles encrypted PDFs with `ignoreEncryption: true`
|
||||
|
||||
**Key Methods:**
|
||||
**Core Methods:**
|
||||
```typescript
|
||||
// Inject metadata into PDF
|
||||
injectHistoryMetadata(pdfBytes: ArrayBuffer, originalFileId: string, parentFileId?: string, toolChain: ToolOperation[], versionNumber: number): Promise<ArrayBuffer>
|
||||
// Store file with complete metadata
|
||||
async storeStirlingFile(stirlingFile: StirlingFile, stub: StirlingFileStub): Promise<void>
|
||||
|
||||
// Extract metadata from PDF
|
||||
extractHistoryMetadata(pdfBytes: ArrayBuffer): Promise<PDFHistoryMetadata | null>
|
||||
// Load file with metadata
|
||||
async getStirlingFile(id: FileId): Promise<StirlingFile | null>
|
||||
async getStirlingFileStub(id: FileId): Promise<StirlingFileStub | null>
|
||||
|
||||
// Create new version with incremented number
|
||||
createNewVersion(pdfBytes: ArrayBuffer, parentFileId: string, toolOperation: ToolOperation): Promise<ArrayBuffer>
|
||||
// Query operations
|
||||
async getLeafStirlingFileStubs(): Promise<StirlingFileStub[]>
|
||||
async getAllStirlingFileStubs(): Promise<StirlingFileStub[]>
|
||||
|
||||
// Version management
|
||||
async markFileAsProcessed(fileId: FileId): Promise<boolean> // Set isLeaf = false
|
||||
async markFileAsLeaf(fileId: FileId): Promise<boolean> // Set isLeaf = true
|
||||
```
|
||||
|
||||
#### 2. File History Utilities (`fileHistoryUtils.ts`)
|
||||
- **FileContext Integration**: Links PDF metadata with React state management
|
||||
- **Version Management**: Handles version grouping and latest version filtering
|
||||
- **Tool Integration**: Prepares files for tool processing with history injection
|
||||
### 2. File Context Integration
|
||||
|
||||
**Key Functions:**
|
||||
**FileContext** manages runtime state with `StirlingFileStub[]` in memory:
|
||||
```typescript
|
||||
// Extract history from File and update FileRecord
|
||||
extractFileHistory(file: File, record: FileRecord): Promise<FileRecord>
|
||||
|
||||
// Inject history before tool processing
|
||||
injectHistoryForTool(file: File, sourceFileRecord: FileRecord, toolName: string, parameters?): Promise<File>
|
||||
|
||||
// Group files by original ID for version management
|
||||
groupFilesByOriginal(fileRecords: FileRecord[]): Map<string, FileRecord[]>
|
||||
|
||||
// Get only latest version of each file group
|
||||
getLatestVersions(fileRecords: FileRecord[]): FileRecord[]
|
||||
interface FileContextState {
|
||||
files: {
|
||||
ids: FileId[];
|
||||
byId: Record<FileId, StirlingFileStub>;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. Tool Operation Integration (`useToolOperation.ts`)
|
||||
- **Automatic Injection**: All tool operations automatically inject history metadata
|
||||
- **Version Progression**: Reads current version from PDF and increments appropriately
|
||||
- **Universal Support**: Works with single-file, multi-file, and custom tool patterns
|
||||
**Key Operations:**
|
||||
- `addFiles()`: Stores new files with initial metadata
|
||||
- `addStirlingFileStubs()`: Loads existing files from storage with preserved metadata
|
||||
- `consumeFiles()`: Processes files through tools, creating new versions
|
||||
|
||||
### Data Flow
|
||||
### 3. Tool Operation Integration
|
||||
|
||||
```
|
||||
1. User uploads PDF → No history (v0)
|
||||
2. Tool processing begins → prepareFilesWithHistory() injects current state
|
||||
3. Backend processes PDF → Returns processed file with embedded history
|
||||
4. FileContext adds result → extractFileHistory() reads embedded metadata
|
||||
5. UI displays file → Shows version badges and tool chain
|
||||
**Tool Processing Flow:**
|
||||
1. **Input**: User selects files (marked as `isLeaf: true`)
|
||||
2. **Processing**: Backend processes files and returns results
|
||||
3. **History Creation**: New `StirlingFileStub` created with:
|
||||
- Incremented version number
|
||||
- Updated tool history
|
||||
- Parent file reference
|
||||
4. **Storage**: Both parent (marked `isLeaf: false`) and child (marked `isLeaf: true`) stored
|
||||
5. **UI Update**: FileContext updated with new file state
|
||||
|
||||
**Child Stub Creation:**
|
||||
```typescript
|
||||
export function createChildStub(
|
||||
parentStub: StirlingFileStub,
|
||||
operation: { toolName: string; timestamp: number },
|
||||
resultingFile: File,
|
||||
thumbnail?: string
|
||||
): StirlingFileStub {
|
||||
return {
|
||||
id: createFileId(),
|
||||
name: resultingFile.name,
|
||||
size: resultingFile.size,
|
||||
type: resultingFile.type,
|
||||
lastModified: resultingFile.lastModified,
|
||||
quickKey: createQuickKey(resultingFile),
|
||||
createdAt: Date.now(),
|
||||
isLeaf: true,
|
||||
|
||||
// Version Control
|
||||
versionNumber: (parentStub.versionNumber || 1) + 1,
|
||||
originalFileId: parentStub.originalFileId || parentStub.id,
|
||||
parentFileId: parentStub.id,
|
||||
|
||||
// Tool History
|
||||
toolHistory: [...(parentStub.toolHistory || []), operation],
|
||||
thumbnailUrl: thumbnail
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## UI Integration
|
||||
|
||||
### File Manager
|
||||
- **Version Toggle**: Switch between "Latest Only" and "All Versions" views
|
||||
- **Version Badges**: v0, v1, v2 indicators on file items
|
||||
- **History Dropdown**: Version timeline with restore functionality
|
||||
- **Tool Chain Display**: Complete processing history in file details panel
|
||||
### File Manager History Display
|
||||
|
||||
### Active Files Workbench
|
||||
- **Version Metadata**: Version number in file metadata line (e.g., "PDF file - 3 Pages - v2")
|
||||
- **Tool Chain Overlay**: Bottom overlay showing tool sequence (e.g., "compress → sanitize")
|
||||
- **Real-time Updates**: Immediate display after tool processing
|
||||
**FileManager** (`FileManager.tsx`) provides:
|
||||
- **Default View**: Shows only leaf files (`isLeaf: true`)
|
||||
- **History Expansion**: Click to show all versions of a file family
|
||||
- **History Groups**: Nested display using `FileHistoryGroup.tsx`
|
||||
|
||||
## Storage and Persistence
|
||||
**FileListItem** (`FileListItem.tsx`) displays:
|
||||
- **Version Badges**: v1, v2, v3 indicators
|
||||
- **Tool Chain**: Complete processing history in tooltips
|
||||
- **History Actions**: "Show/Hide History" toggle, "Restore" for history files
|
||||
|
||||
### PDF Metadata
|
||||
- **Embedded in PDF**: History travels with the document across downloads/uploads
|
||||
- **Keywords Field**: Uses standard PDF metadata field for maximum compatibility
|
||||
- **Multiple Keywords**: System handles multiple history entries and extracts latest version
|
||||
### FileManagerContext Integration
|
||||
|
||||
### IndexedDB Storage
|
||||
- **Client-side Persistence**: FileMetadata includes extracted history information
|
||||
- **Lazy Loading**: History extracted when files are accessed from storage
|
||||
- **Batch Processing**: Large collections processed in batches of 5 to prevent memory issues
|
||||
|
||||
### Memory Management
|
||||
- **ContentCache**: 10-minute TTL, 50-file capacity for metadata extraction results
|
||||
- **Cleanup**: Automatic cache eviction and expired entry removal
|
||||
- **Large File Support**: No artificial size limits (supports 100GB+ PDFs)
|
||||
|
||||
## Tool Configuration
|
||||
|
||||
### Filename Preservation
|
||||
Most tools preserve the original filename to maintain file identity:
|
||||
|
||||
**No Prefix (Filename Preserved):**
|
||||
- compress, repair, sanitize, addPassword, removePassword, changePermissions, removeCertificateSign, unlockPdfForms, ocr, addWatermark
|
||||
|
||||
**With Prefix (Different Content):**
|
||||
- split (`split_` - creates multiple files)
|
||||
- convert (`converted_` - changes file format)
|
||||
|
||||
### Configuration Pattern
|
||||
**File Selection Flow:**
|
||||
```typescript
|
||||
export const toolOperationConfig = {
|
||||
toolType: ToolType.singleFile,
|
||||
operationType: 'toolName',
|
||||
endpoint: '/api/v1/category/tool-endpoint',
|
||||
filePrefix: '', // Empty for filename preservation
|
||||
buildFormData: buildToolFormData,
|
||||
defaultParameters
|
||||
// Recent files (from storage)
|
||||
onRecentFileSelect: (stirlingFileStubs: StirlingFileStub[]) => void
|
||||
// Calls: actions.addStirlingFileStubs(stirlingFileStubs, options)
|
||||
|
||||
// New uploads
|
||||
onFileUpload: (files: File[]) => void
|
||||
// Calls: actions.addFiles(files, options)
|
||||
```
|
||||
|
||||
**History Management:**
|
||||
```typescript
|
||||
// Toggle history visibility
|
||||
const { expandedFileIds, onToggleExpansion } = useFileManagerContext();
|
||||
|
||||
// Restore history file to current
|
||||
const handleAddToRecents = (file: StirlingFileStub) => {
|
||||
fileStorage.markFileAsLeaf(file.id); // Make this version current
|
||||
};
|
||||
```
|
||||
|
||||
### Metadata Preservation Strategy
|
||||
The system uses a **minimal touch approach** for PDF metadata:
|
||||
## Data Flow
|
||||
|
||||
```typescript
|
||||
// Only modify necessary fields, let pdf-lib preserve everything else
|
||||
pdfDoc.setCreator('Stirling-PDF');
|
||||
pdfDoc.setProducer('Stirling-PDF');
|
||||
pdfDoc.setKeywords([...existingKeywords, historyKeyword]);
|
||||
|
||||
// File.lastModified = Date.now() for processed files (source of truth)
|
||||
// PDF internal dates (CreationDate, etc.) preserved automatically by pdf-lib
|
||||
### New File Upload
|
||||
```
|
||||
1. User uploads files → addFiles()
|
||||
2. Generate thumbnails and page count
|
||||
3. Create StirlingFileStub with isLeaf: true, versionNumber: 1
|
||||
4. Store both StirlingFile + StirlingFileStub in IndexedDB
|
||||
5. Dispatch to FileContext state
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- **Automatic Preservation**: pdf-lib preserves Title, Author, Subject, CreationDate without explicit re-setting
|
||||
- **No Duplication**: File.lastModified is single source of truth for "when file changed"
|
||||
- **Simpler Code**: Minimal metadata operations reduce complexity and bugs
|
||||
- **Better Performance**: Fewer PDF reads/writes during processing
|
||||
### Tool Processing
|
||||
```
|
||||
1. User selects tool + files → useToolOperation()
|
||||
2. API processes files → returns processed File objects
|
||||
3. createChildStub() for each result:
|
||||
- Parent marked isLeaf: false
|
||||
- Child created with isLeaf: true, incremented version
|
||||
4. Store all files with updated metadata
|
||||
5. Update FileContext with new state
|
||||
```
|
||||
|
||||
## Error Handling and Resilience
|
||||
### File Loading (Recent Files)
|
||||
```
|
||||
1. User selects from FileManager → onRecentFileSelect()
|
||||
2. addStirlingFileStubs() with preserved metadata
|
||||
3. Load actual StirlingFile data from storage
|
||||
4. Files appear in workbench with complete history intact
|
||||
```
|
||||
|
||||
## Performance Optimizations
|
||||
|
||||
### Metadata Regeneration
|
||||
When loading files from storage, missing `processedFile` data is regenerated:
|
||||
```typescript
|
||||
// In addStirlingFileStubs()
|
||||
const needsProcessing = !record.processedFile ||
|
||||
!record.processedFile.pages ||
|
||||
record.processedFile.pages.length === 0;
|
||||
|
||||
if (needsProcessing) {
|
||||
const result = await generateThumbnailWithMetadata(stirlingFile);
|
||||
record.processedFile = createProcessedFile(result.pageCount, result.thumbnail);
|
||||
}
|
||||
```
|
||||
|
||||
### Memory Management
|
||||
- **Blob URL Tracking**: Automatic cleanup of thumbnail URLs
|
||||
- **Lazy Loading**: Files loaded from storage only when needed
|
||||
- **LRU Caching**: File objects cached in memory with size limits
|
||||
|
||||
## File Deduplication
|
||||
|
||||
### QuickKey System
|
||||
Files are deduplicated using `quickKey` format:
|
||||
```typescript
|
||||
const quickKey = `${file.name}|${file.size}|${file.lastModified}`;
|
||||
```
|
||||
|
||||
This prevents duplicate uploads while allowing different versions of the same logical file.
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Graceful Degradation
|
||||
- **Extraction Failures**: Files display normally without history if metadata extraction fails
|
||||
- **Encrypted PDFs**: System handles encrypted documents with `ignoreEncryption` option
|
||||
- **Corrupted Metadata**: Invalid history metadata is silently ignored with fallback to basic file info
|
||||
- **Storage Failures**: Files continue to work without persistence
|
||||
- **Metadata Issues**: Missing metadata regenerated on demand
|
||||
- **Version Conflicts**: Automatic version number resolution
|
||||
|
||||
### Performance Considerations
|
||||
- **Caching**: Metadata extraction results are cached to avoid re-parsing
|
||||
- **Batch Processing**: Large file collections processed in controlled batches
|
||||
- **Async Extraction**: History extraction doesn't block file operations
|
||||
### Recovery Scenarios
|
||||
- **Corrupted Storage**: Automatic cleanup and re-initialization
|
||||
- **Missing Files**: Stubs cleaned up automatically
|
||||
- **Version Mismatches**: Automatic version chain reconstruction
|
||||
|
||||
## Developer Guidelines
|
||||
|
||||
### Adding History to New Tools
|
||||
1. **Set `filePrefix: ''`** in tool configuration to preserve filenames
|
||||
2. **Use existing patterns**: Tool operations automatically inherit history injection
|
||||
3. **Custom processors**: Must handle history injection manually if using custom response handlers
|
||||
### Adding File History to New Components
|
||||
|
||||
1. **Use FileContext Actions**:
|
||||
```typescript
|
||||
const { actions } = useFileActions();
|
||||
await actions.addFiles(files); // For new uploads
|
||||
await actions.addStirlingFileStubs(stubs); // For existing files
|
||||
```
|
||||
|
||||
2. **Preserve Metadata When Processing**:
|
||||
```typescript
|
||||
const childStub = createChildStub(parentStub, {
|
||||
toolName: 'compress',
|
||||
timestamp: Date.now()
|
||||
}, processedFile, thumbnail);
|
||||
```
|
||||
|
||||
3. **Handle Storage Operations**:
|
||||
```typescript
|
||||
await fileStorage.storeStirlingFile(stirlingFile, stirlingFileStub);
|
||||
const stub = await fileStorage.getStirlingFileStub(fileId);
|
||||
```
|
||||
|
||||
### Testing File History
|
||||
1. **Upload a PDF**: Should show no version (v0), original File.lastModified preserved
|
||||
2. **Apply any tool**: Should show v1 with tool name, File.lastModified updated to processing time
|
||||
3. **Apply another tool**: Should show v2 with tool chain sequence
|
||||
4. **Check file manager**: Version toggle, history dropdown, standard PDF metadata should all work
|
||||
5. **Check workbench**: Tool chain overlay should appear on thumbnails
|
||||
|
||||
### Backend Tool Monitoring
|
||||
The system automatically logs metadata preservation:
|
||||
- **Success**: `✅ METADATA PRESERVED: Tool 'ocr' correctly preserved all PDF metadata`
|
||||
- **Issues**: `⚠️ METADATA LOSS: Tool 'compress' did not preserve PDF metadata: CreationDate modified, Author stripped`
|
||||
|
||||
This helps identify which backend tools need to be updated to preserve standard PDF metadata fields.
|
||||
|
||||
### Debugging
|
||||
Enable development mode logging to see:
|
||||
- History injection: `📄 Injected PDF history metadata`
|
||||
- History extraction: `📄 History extraction completed`
|
||||
- Version progression: Version number increments and tool chain updates
|
||||
- Metadata issues: Warnings for tools that strip PDF metadata
|
||||
1. **Upload files**: Should show v1, marked as leaf
|
||||
2. **Apply tool**: Should create v2, mark v1 as non-leaf
|
||||
3. **Check FileManager**: History should show both versions
|
||||
4. **Restore old version**: Should mark old version as leaf
|
||||
5. **Check storage**: Both versions should persist in IndexedDB
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Possible Extensions
|
||||
- **Branching**: Support for parallel processing branches from same source
|
||||
- **Diff Tracking**: Track specific changes made by each tool
|
||||
- **User Attribution**: Add user information to tool operations
|
||||
- **Timestamp Precision**: Enhanced timestamp tracking for audit trails
|
||||
- **Export Options**: Export complete processing history as JSON/XML
|
||||
### Potential Improvements
|
||||
- **Branch History**: Support for parallel processing branches
|
||||
- **History Export**: Export complete version history as JSON
|
||||
- **Conflict Resolution**: Handle concurrent modifications
|
||||
- **Cloud Sync**: Sync history across devices
|
||||
- **Compression**: Compress historical file data
|
||||
|
||||
### Compatibility
|
||||
- **PDF Standard Compliance**: Uses standard PDF Keywords field for broad compatibility
|
||||
- **Backwards Compatibility**: PDFs without history metadata work normally
|
||||
- **Future Versions**: Format version field enables future metadata schema evolution
|
||||
### API Extensions
|
||||
- **Batch Operations**: Process multiple version chains simultaneously
|
||||
- **Search Integration**: Search within tool history and file metadata
|
||||
- **Analytics**: Track usage patterns and tool effectiveness
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: January 2025
|
||||
**Format Version**: 1.0
|
||||
**Implementation**: Stirling PDF Frontend v2
|
||||
**Implementation**: Stirling PDF Frontend v2
|
||||
**Storage Version**: IndexedDB with fileStorage service
|
@ -28,7 +28,7 @@ const FileHistoryGroup: React.FC<FileHistoryGroupProps> = ({
|
||||
// Sort history files by version number (oldest first, excluding the current leaf file)
|
||||
const sortedHistory = historyFiles
|
||||
.filter(file => file.id !== leafFile.id) // Exclude the leaf file itself
|
||||
.sort((a, b) => (a.versionNumber || 1) - (b.versionNumber || 1));
|
||||
.sort((a, b) => (b.versionNumber || 1) - (a.versionNumber || 1));
|
||||
|
||||
if (!isExpanded || sortedHistory.length === 0) {
|
||||
return null;
|
||||
|
@ -21,7 +21,6 @@ const FileListArea: React.FC<FileListAreaProps> = ({
|
||||
recentFiles,
|
||||
filteredFiles,
|
||||
selectedFilesSet,
|
||||
fileGroups,
|
||||
expandedFileIds,
|
||||
loadedHistoryFiles,
|
||||
onFileSelect,
|
||||
@ -72,7 +71,7 @@ const FileListArea: React.FC<FileListAreaProps> = ({
|
||||
isHistoryFile={false} // All files here are leaf files
|
||||
isLatestVersion={true} // All files here are the latest versions
|
||||
/>
|
||||
|
||||
|
||||
<FileHistoryGroup
|
||||
leafFile={file}
|
||||
historyFiles={historyFiles}
|
||||
|
Loading…
x
Reference in New Issue
Block a user