mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-09-18 09:29:24 +00:00
Builds
This commit is contained in:
parent
921b0a07b0
commit
5bf024be48
@ -66,7 +66,7 @@ const FileEditorThumbnail = ({
|
|||||||
const isPinned = actualFile ? isFilePinned(actualFile) : false;
|
const isPinned = actualFile ? isFilePinned(actualFile) : false;
|
||||||
|
|
||||||
// Get file record to access tool history
|
// Get file record to access tool history
|
||||||
const fileRecord = selectors.getFileRecord(file.id);
|
const fileRecord = selectors.getStirlingFileStub(file.id);
|
||||||
const toolHistory = fileRecord?.toolHistory || [];
|
const toolHistory = fileRecord?.toolHistory || [];
|
||||||
const hasToolHistory = toolHistory.length > 0;
|
const hasToolHistory = toolHistory.length > 0;
|
||||||
const versionNumber = fileRecord?.versionNumber || 0;
|
const versionNumber = fileRecord?.versionNumber || 0;
|
||||||
|
@ -129,7 +129,7 @@ export const useToolOperation = <TParams>(
|
|||||||
config: ToolOperationConfig<TParams>
|
config: ToolOperationConfig<TParams>
|
||||||
): ToolOperationHook<TParams> => {
|
): ToolOperationHook<TParams> => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { addFiles, consumeFiles, undoConsumeFiles, selectors } = useFileContext();
|
const { addFiles, consumeFiles, undoConsumeFiles, selectors, findFileId } = useFileContext();
|
||||||
|
|
||||||
// Composed hooks
|
// Composed hooks
|
||||||
const { state, actions } = useToolState();
|
const { state, actions } = useToolState();
|
||||||
@ -168,14 +168,14 @@ export const useToolOperation = <TParams>(
|
|||||||
|
|
||||||
// Prepare files with history metadata injection (for PDFs)
|
// Prepare files with history metadata injection (for PDFs)
|
||||||
actions.setStatus('Preparing files...');
|
actions.setStatus('Preparing files...');
|
||||||
const getFileRecord = (file: File) => {
|
const getFileStub = (file: File) => {
|
||||||
const fileId = findFileId(file);
|
const fileId = findFileId(file);
|
||||||
return fileId ? selectors.getFileRecord(fileId) : undefined;
|
return fileId ? selectors.getStirlingFileStub(fileId) : undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const filesWithHistory = await prepareFilesWithHistory(
|
const filesWithHistory = await prepareFilesWithHistory(
|
||||||
validFiles,
|
validFiles,
|
||||||
getFileRecord,
|
getFileStub,
|
||||||
config.operationType,
|
config.operationType,
|
||||||
params as Record<string, any>
|
params as Record<string, any>
|
||||||
);
|
);
|
||||||
@ -197,7 +197,6 @@ export const useToolOperation = <TParams>(
|
|||||||
};
|
};
|
||||||
processedFiles = await processFiles(
|
processedFiles = await processFiles(
|
||||||
params,
|
params,
|
||||||
filesWithHistory,
|
|
||||||
validRegularFiles,
|
validRegularFiles,
|
||||||
apiCallsConfig,
|
apiCallsConfig,
|
||||||
actions.setProgress,
|
actions.setProgress,
|
||||||
@ -205,7 +204,6 @@ export const useToolOperation = <TParams>(
|
|||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ToolType.multiFile: {
|
case ToolType.multiFile: {
|
||||||
// Multi-file processing - single API call with all files
|
// Multi-file processing - single API call with all files
|
||||||
actions.setStatus('Processing files...');
|
actions.setStatus('Processing files...');
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import { useState, useCallback } from 'react';
|
import { useState, useCallback } from 'react';
|
||||||
import { FileId } from '../types/file';
|
import { FileId } from '../types/file';
|
||||||
import { FileRecord } from '../types/fileContext';
|
import { StirlingFileStub } from '../types/fileContext';
|
||||||
import { loadFileHistoryOnDemand } from '../utils/fileHistoryUtils';
|
import { loadFileHistoryOnDemand } from '../utils/fileHistoryUtils';
|
||||||
|
|
||||||
interface FileHistoryState {
|
interface FileHistoryState {
|
||||||
@ -23,7 +23,7 @@ interface UseFileHistoryResult {
|
|||||||
historyData: FileHistoryState | null;
|
historyData: FileHistoryState | null;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
error: string | null;
|
error: string | null;
|
||||||
loadHistory: (file: File, fileId: FileId, updateFileRecord?: (id: FileId, updates: Partial<FileRecord>) => void) => Promise<void>;
|
loadHistory: (file: File, fileId: FileId, updateFileStub?: (id: FileId, updates: Partial<StirlingFileStub>) => void) => Promise<void>;
|
||||||
clearHistory: () => void;
|
clearHistory: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,13 +35,13 @@ export function useFileHistory(): UseFileHistoryResult {
|
|||||||
const loadHistory = useCallback(async (
|
const loadHistory = useCallback(async (
|
||||||
file: File,
|
file: File,
|
||||||
fileId: FileId,
|
fileId: FileId,
|
||||||
updateFileRecord?: (id: FileId, updates: Partial<FileRecord>) => void
|
updateFileStub?: (id: FileId, updates: Partial<StirlingFileStub>) => void
|
||||||
) => {
|
) => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const history = await loadFileHistoryOnDemand(file, fileId, updateFileRecord);
|
const history = await loadFileHistoryOnDemand(file, fileId, updateFileStub);
|
||||||
setHistoryData(history);
|
setHistoryData(history);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const errorMessage = err instanceof Error ? err.message : 'Failed to load file history';
|
const errorMessage = err instanceof Error ? err.message : 'Failed to load file history';
|
||||||
@ -78,7 +78,7 @@ export function useMultiFileHistory() {
|
|||||||
const loadFileHistory = useCallback(async (
|
const loadFileHistory = useCallback(async (
|
||||||
file: File,
|
file: File,
|
||||||
fileId: FileId,
|
fileId: FileId,
|
||||||
updateFileRecord?: (id: FileId, updates: Partial<FileRecord>) => void
|
updateFileStub?: (id: FileId, updates: Partial<StirlingFileStub>) => void
|
||||||
) => {
|
) => {
|
||||||
// Don't reload if already loaded or currently loading
|
// Don't reload if already loaded or currently loading
|
||||||
if (historyCache.has(fileId) || loadingFiles.has(fileId)) {
|
if (historyCache.has(fileId) || loadingFiles.has(fileId)) {
|
||||||
@ -93,12 +93,12 @@ export function useMultiFileHistory() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const history = await loadFileHistoryOnDemand(file, fileId, updateFileRecord);
|
const history = await loadFileHistoryOnDemand(file, fileId, updateFileStub);
|
||||||
|
|
||||||
if (history) {
|
if (history) {
|
||||||
setHistoryCache(prev => new Map(prev).set(fileId, history));
|
setHistoryCache(prev => new Map(prev).set(fileId, history));
|
||||||
}
|
}
|
||||||
|
|
||||||
return history;
|
return history;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const errorMessage = err instanceof Error ? err.message : 'Failed to load file history';
|
const errorMessage = err instanceof Error ? err.message : 'Failed to load file history';
|
||||||
@ -157,4 +157,4 @@ export function useMultiFileHistory() {
|
|||||||
clearHistory,
|
clearHistory,
|
||||||
clearAllHistory
|
clearAllHistory
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,11 @@ export class PDFMetadataService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return await pdfDoc.save();
|
const savedPdfBytes = await pdfDoc.save();
|
||||||
|
// Convert Uint8Array to ArrayBuffer
|
||||||
|
const arrayBuffer = new ArrayBuffer(savedPdfBytes.byteLength);
|
||||||
|
new Uint8Array(arrayBuffer).set(savedPdfBytes);
|
||||||
|
return arrayBuffer;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (DEBUG) console.error('📄 Failed to inject PDF metadata:', error);
|
if (DEBUG) console.error('📄 Failed to inject PDF metadata:', error);
|
||||||
// Return original bytes if metadata injection fails
|
// Return original bytes if metadata injection fails
|
||||||
|
@ -64,8 +64,7 @@ export interface StirlingFileStub {
|
|||||||
processedFile?: ProcessedFileMetadata; // PDF page data and processing results
|
processedFile?: ProcessedFileMetadata; // PDF page data and processing results
|
||||||
insertAfterPageId?: string; // Page ID after which this file should be inserted
|
insertAfterPageId?: string; // Page ID after which this file should be inserted
|
||||||
isPinned?: boolean; // Protected from tool consumption (replace/remove)
|
isPinned?: boolean; // Protected from tool consumption (replace/remove)
|
||||||
|
isLeaf?: boolean; // True if this file is a leaf node (hasn't been processed yet)
|
||||||
isLeaf?: boolean; // True if this file is a leaf node (hasn't been processed yet)
|
|
||||||
|
|
||||||
// File history tracking (from PDF metadata)
|
// File history tracking (from PDF metadata)
|
||||||
originalFileId?: string; // Root file ID for grouping versions
|
originalFileId?: string; // Root file ID for grouping versions
|
||||||
|
@ -6,19 +6,19 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { pdfMetadataService, type ToolOperation } from '../services/pdfMetadataService';
|
import { pdfMetadataService, type ToolOperation } from '../services/pdfMetadataService';
|
||||||
import { FileRecord } from '../types/fileContext';
|
import { StirlingFileStub } from '../types/fileContext';
|
||||||
import { FileId, FileMetadata } from '../types/file';
|
import { FileId, FileMetadata } from '../types/file';
|
||||||
import { createFileId } from '../types/fileContext';
|
import { createFileId } from '../types/fileContext';
|
||||||
|
|
||||||
const DEBUG = process.env.NODE_ENV === 'development';
|
const DEBUG = process.env.NODE_ENV === 'development';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract history information from a PDF file and update FileRecord
|
* Extract history information from a PDF file and update StirlingFileStub
|
||||||
*/
|
*/
|
||||||
export async function extractFileHistory(
|
export async function extractFileHistory(
|
||||||
file: File,
|
file: File,
|
||||||
record: FileRecord
|
record: StirlingFileStub
|
||||||
): Promise<FileRecord> {
|
): Promise<StirlingFileStub> {
|
||||||
// Only process PDF files
|
// Only process PDF files
|
||||||
if (!file.type.includes('pdf')) {
|
if (!file.type.includes('pdf')) {
|
||||||
return record;
|
return record;
|
||||||
@ -52,7 +52,7 @@ export async function extractFileHistory(
|
|||||||
*/
|
*/
|
||||||
export async function injectHistoryForTool(
|
export async function injectHistoryForTool(
|
||||||
file: File,
|
file: File,
|
||||||
sourceFileRecord: FileRecord,
|
sourceStirlingFileStub: StirlingFileStub,
|
||||||
toolName: string,
|
toolName: string,
|
||||||
parameters?: Record<string, any>
|
parameters?: Record<string, any>
|
||||||
): Promise<File> {
|
): Promise<File> {
|
||||||
@ -86,20 +86,20 @@ export async function injectHistoryForTool(
|
|||||||
const history = existingHistoryMetadata.stirlingHistory;
|
const history = existingHistoryMetadata.stirlingHistory;
|
||||||
newVersionNumber = history.versionNumber + 1;
|
newVersionNumber = history.versionNumber + 1;
|
||||||
originalFileId = history.originalFileId;
|
originalFileId = history.originalFileId;
|
||||||
parentFileId = sourceFileRecord.id; // This file becomes the parent
|
parentFileId = sourceStirlingFileStub.id; // This file becomes the parent
|
||||||
parentToolChain = history.toolChain || [];
|
parentToolChain = history.toolChain || [];
|
||||||
|
|
||||||
} else if (sourceFileRecord.originalFileId && sourceFileRecord.versionNumber) {
|
} else if (sourceStirlingFileStub.originalFileId && sourceStirlingFileStub.versionNumber) {
|
||||||
// File record has history but PDF doesn't (shouldn't happen, but fallback)
|
// File record has history but PDF doesn't (shouldn't happen, but fallback)
|
||||||
newVersionNumber = sourceFileRecord.versionNumber + 1;
|
newVersionNumber = sourceStirlingFileStub.versionNumber + 1;
|
||||||
originalFileId = sourceFileRecord.originalFileId;
|
originalFileId = sourceStirlingFileStub.originalFileId;
|
||||||
parentFileId = sourceFileRecord.id;
|
parentFileId = sourceStirlingFileStub.id;
|
||||||
parentToolChain = sourceFileRecord.toolHistory || [];
|
parentToolChain = sourceStirlingFileStub.toolHistory || [];
|
||||||
} else {
|
} else {
|
||||||
// File has no history - this becomes version 1
|
// File has no history - this becomes version 1
|
||||||
newVersionNumber = 1;
|
newVersionNumber = 1;
|
||||||
originalFileId = sourceFileRecord.id; // Use source file ID as original
|
originalFileId = sourceStirlingFileStub.id; // Use source file ID as original
|
||||||
parentFileId = sourceFileRecord.id; // Parent is the source file
|
parentFileId = sourceStirlingFileStub.id; // Parent is the source file
|
||||||
parentToolChain = []; // No previous tools
|
parentToolChain = []; // No previous tools
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,14 +127,14 @@ export async function injectHistoryForTool(
|
|||||||
*/
|
*/
|
||||||
export async function prepareFilesWithHistory(
|
export async function prepareFilesWithHistory(
|
||||||
files: File[],
|
files: File[],
|
||||||
getFileRecord: (file: File) => FileRecord | undefined,
|
getStirlingFileStub: (file: File) => StirlingFileStub | undefined,
|
||||||
toolName: string,
|
toolName: string,
|
||||||
parameters?: Record<string, any>
|
parameters?: Record<string, any>
|
||||||
): Promise<File[]> {
|
): Promise<File[]> {
|
||||||
const processedFiles: File[] = [];
|
const processedFiles: File[] = [];
|
||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
const record = getFileRecord(file);
|
const record = getStirlingFileStub(file);
|
||||||
if (!record) {
|
if (!record) {
|
||||||
processedFiles.push(file);
|
processedFiles.push(file);
|
||||||
continue;
|
continue;
|
||||||
@ -180,57 +180,57 @@ export async function verifyToolMetadataPreservation(
|
|||||||
* Group files by processing branches - each branch ends in a leaf file
|
* Group files by processing branches - each branch ends in a leaf file
|
||||||
* Returns Map<fileId, lineagePath[]> where fileId is the leaf and lineagePath is the path back to original
|
* Returns Map<fileId, lineagePath[]> where fileId is the leaf and lineagePath is the path back to original
|
||||||
*/
|
*/
|
||||||
export function groupFilesByOriginal(fileRecords: FileRecord[]): Map<string, FileRecord[]> {
|
export function groupFilesByOriginal(StirlingFileStubs: StirlingFileStub[]): Map<string, StirlingFileStub[]> {
|
||||||
const groups = new Map<string, FileRecord[]>();
|
const groups = new Map<string, StirlingFileStub[]>();
|
||||||
|
|
||||||
// Create a map for quick lookups
|
// Create a map for quick lookups
|
||||||
const fileMap = new Map<string, FileRecord>();
|
const fileMap = new Map<string, StirlingFileStub>();
|
||||||
for (const record of fileRecords) {
|
for (const record of StirlingFileStubs) {
|
||||||
fileMap.set(record.id, record);
|
fileMap.set(record.id, record);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find leaf files (files that are not parents of any other files AND have version history)
|
// Find leaf files (files that are not parents of any other files AND have version history)
|
||||||
// Original files (v0) should only be leaves if they have no processed versions at all
|
// Original files (v0) should only be leaves if they have no processed versions at all
|
||||||
const leafFiles = fileRecords.filter(record => {
|
const leafFiles = StirlingFileStubs.filter(stub => {
|
||||||
const isParentOfOthers = fileRecords.some(otherRecord => otherRecord.parentFileId === record.id);
|
const isParentOfOthers = StirlingFileStubs.some(otherStub => otherStub.parentFileId === stub.id);
|
||||||
const isOriginalOfOthers = fileRecords.some(otherRecord => otherRecord.originalFileId === record.id);
|
const isOriginalOfOthers = StirlingFileStubs.some(otherStub => otherStub.originalFileId === stub.id);
|
||||||
|
|
||||||
// A file is a leaf if:
|
// A file is a leaf if:
|
||||||
// 1. It's not a parent of any other files, AND
|
// 1. It's not a parent of any other files, AND
|
||||||
// 2. It has processing history (versionNumber > 0) OR it's not referenced as original by others
|
// 2. It has processing history (versionNumber > 0) OR it's not referenced as original by others
|
||||||
return !isParentOfOthers && (record.versionNumber && record.versionNumber > 0 || !isOriginalOfOthers);
|
return !isParentOfOthers && (stub.versionNumber && stub.versionNumber > 0 || !isOriginalOfOthers);
|
||||||
});
|
});
|
||||||
|
|
||||||
// For each leaf file, build its complete lineage path back to original
|
// For each leaf file, build its complete lineage path back to original
|
||||||
for (const leafFile of leafFiles) {
|
for (const leafFile of leafFiles) {
|
||||||
const lineagePath: FileRecord[] = [];
|
const lineagePath: StirlingFileStub[] = [];
|
||||||
let currentFile: FileRecord | undefined = leafFile;
|
let currentFile: StirlingFileStub | undefined = leafFile;
|
||||||
|
|
||||||
// Trace back through parentFileId chain to build this specific branch
|
// Trace back through parentFileId chain to build this specific branch
|
||||||
while (currentFile) {
|
while (currentFile) {
|
||||||
lineagePath.push(currentFile);
|
lineagePath.push(currentFile);
|
||||||
|
|
||||||
// Move to parent file in this branch
|
// Move to parent file in this branch
|
||||||
let nextFile: FileRecord | undefined = undefined;
|
let nextFile: StirlingFileStub | undefined = undefined;
|
||||||
|
|
||||||
if (currentFile.parentFileId) {
|
if (currentFile.parentFileId) {
|
||||||
nextFile = fileMap.get(currentFile.parentFileId);
|
nextFile = fileMap.get(currentFile.parentFileId);
|
||||||
} else if (currentFile.originalFileId && currentFile.originalFileId !== currentFile.id) {
|
} else if (currentFile.originalFileId && currentFile.originalFileId !== currentFile.id) {
|
||||||
// For v1 files, the original file might be referenced by originalFileId
|
// For v1 files, the original file might be referenced by originalFileId
|
||||||
nextFile = fileMap.get(currentFile.originalFileId);
|
nextFile = fileMap.get(currentFile.originalFileId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for infinite loops before moving to next
|
// Check for infinite loops before moving to next
|
||||||
if (nextFile && lineagePath.some(file => file.id === nextFile!.id)) {
|
if (nextFile && lineagePath.some(file => file.id === nextFile!.id)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
currentFile = nextFile;
|
currentFile = nextFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort lineage with latest version first (leaf at top)
|
// Sort lineage with latest version first (leaf at top)
|
||||||
lineagePath.sort((a, b) => (b.versionNumber || 0) - (a.versionNumber || 0));
|
lineagePath.sort((a, b) => (b.versionNumber || 0) - (a.versionNumber || 0));
|
||||||
|
|
||||||
// Use leaf file ID as the group key - each branch gets its own group
|
// Use leaf file ID as the group key - each branch gets its own group
|
||||||
groups.set(leafFile.id, lineagePath);
|
groups.set(leafFile.id, lineagePath);
|
||||||
}
|
}
|
||||||
@ -241,22 +241,22 @@ export function groupFilesByOriginal(fileRecords: FileRecord[]): Map<string, Fil
|
|||||||
/**
|
/**
|
||||||
* Get the latest version of each file group (optimized version using leaf flags)
|
* Get the latest version of each file group (optimized version using leaf flags)
|
||||||
*/
|
*/
|
||||||
export function getLatestVersions(fileRecords: FileRecord[]): FileRecord[] {
|
export function getLatestVersions(fileStubs: StirlingFileStub[]): StirlingFileStub[] {
|
||||||
// If we have leaf flags, use them for much faster filtering
|
// If we have leaf flags, use them for much faster filtering
|
||||||
const hasLeafFlags = fileRecords.some(record => record.isLeaf !== undefined);
|
const hasLeafFlags = fileStubs.some(fileStub => fileStub.isLeaf !== undefined);
|
||||||
|
|
||||||
if (hasLeafFlags) {
|
if (hasLeafFlags) {
|
||||||
// Fast path: just return files marked as leaf nodes
|
// Fast path: just return files marked as leaf nodes
|
||||||
return fileRecords.filter(record => record.isLeaf !== false); // Default to true if undefined
|
return fileStubs.filter(fileStub => fileStub.isLeaf !== false); // Default to true if undefined
|
||||||
} else {
|
} else {
|
||||||
// Fallback to expensive calculation for backward compatibility
|
// Fallback to expensive calculation for backward compatibility
|
||||||
const groups = groupFilesByOriginal(fileRecords);
|
const groups = groupFilesByOriginal(fileStubs);
|
||||||
const latestVersions: FileRecord[] = [];
|
const latestVersions: StirlingFileStub[] = [];
|
||||||
|
|
||||||
for (const [_, records] of groups) {
|
for (const [_, fileStubs] of groups) {
|
||||||
if (records.length > 0) {
|
if (fileStubs.length > 0) {
|
||||||
// First item is the latest version (sorted desc by version number)
|
// First item is the latest version (sorted desc by version number)
|
||||||
latestVersions.push(records[0]);
|
latestVersions.push(fileStubs[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,15 +268,15 @@ export function getLatestVersions(fileRecords: FileRecord[]): FileRecord[] {
|
|||||||
* Get version history for a file
|
* Get version history for a file
|
||||||
*/
|
*/
|
||||||
export function getVersionHistory(
|
export function getVersionHistory(
|
||||||
targetRecord: FileRecord,
|
targetFileStub: StirlingFileStub,
|
||||||
allRecords: FileRecord[]
|
allFileStubs: StirlingFileStub[]
|
||||||
): FileRecord[] {
|
): StirlingFileStub[] {
|
||||||
const originalId = targetRecord.originalFileId || targetRecord.id;
|
const originalId = targetFileStub.originalFileId || targetFileStub.id;
|
||||||
|
|
||||||
return allRecords
|
return allFileStubs
|
||||||
.filter(record => {
|
.filter(fileStub => {
|
||||||
const recordOriginalId = record.originalFileId || record.id;
|
const fileStubOriginalId = fileStub.originalFileId || fileStub.id;
|
||||||
return recordOriginalId === originalId;
|
return fileStubOriginalId === originalId;
|
||||||
})
|
})
|
||||||
.sort((a, b) => (b.versionNumber || 0) - (a.versionNumber || 0));
|
.sort((a, b) => (b.versionNumber || 0) - (a.versionNumber || 0));
|
||||||
}
|
}
|
||||||
@ -284,23 +284,23 @@ export function getVersionHistory(
|
|||||||
/**
|
/**
|
||||||
* Check if a file has version history
|
* Check if a file has version history
|
||||||
*/
|
*/
|
||||||
export function hasVersionHistory(record: FileRecord): boolean {
|
export function hasVersionHistory(fileStub: StirlingFileStub): boolean {
|
||||||
return !!(record.originalFileId && record.versionNumber && record.versionNumber > 0);
|
return !!(fileStub.originalFileId && fileStub.versionNumber && fileStub.versionNumber > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a descriptive name for a file version
|
* Generate a descriptive name for a file version
|
||||||
*/
|
*/
|
||||||
export function generateVersionName(record: FileRecord): string {
|
export function generateVersionName(fileStub: StirlingFileStub): string {
|
||||||
const baseName = record.name.replace(/\.pdf$/i, '');
|
const baseName = fileStub.name.replace(/\.pdf$/i, '');
|
||||||
|
|
||||||
if (!hasVersionHistory(record)) {
|
if (!hasVersionHistory(fileStub)) {
|
||||||
return record.name;
|
return fileStub.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
const versionInfo = record.versionNumber ? ` (v${record.versionNumber})` : '';
|
const versionInfo = fileStub.versionNumber ? ` (v${fileStub.versionNumber})` : '';
|
||||||
const toolInfo = record.toolHistory && record.toolHistory.length > 0
|
const toolInfo = fileStub.toolHistory && fileStub.toolHistory.length > 0
|
||||||
? ` - ${record.toolHistory[record.toolHistory.length - 1].toolName}`
|
? ` - ${fileStub.toolHistory[fileStub.toolHistory.length - 1].toolName}`
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
return `${baseName}${versionInfo}${toolInfo}.pdf`;
|
return `${baseName}${versionInfo}${toolInfo}.pdf`;
|
||||||
@ -340,11 +340,11 @@ export async function getRecentLeafFileMetadata(): Promise<Omit<import('../servi
|
|||||||
*/
|
*/
|
||||||
export async function extractBasicFileMetadata(
|
export async function extractBasicFileMetadata(
|
||||||
file: File,
|
file: File,
|
||||||
record: FileRecord
|
fileStub: StirlingFileStub
|
||||||
): Promise<FileRecord> {
|
): Promise<StirlingFileStub> {
|
||||||
// Only process PDF files
|
// Only process PDF files
|
||||||
if (!file.type.includes('pdf')) {
|
if (!file.type.includes('pdf')) {
|
||||||
return record;
|
return fileStub;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -354,9 +354,9 @@ export async function extractBasicFileMetadata(
|
|||||||
if (historyMetadata) {
|
if (historyMetadata) {
|
||||||
const history = historyMetadata.stirlingHistory;
|
const history = historyMetadata.stirlingHistory;
|
||||||
|
|
||||||
// Update record with essential metadata only (no parent/original relationships)
|
// Update fileStub with essential metadata only (no parent/original relationships)
|
||||||
return {
|
return {
|
||||||
...record,
|
...fileStub,
|
||||||
versionNumber: history.versionNumber,
|
versionNumber: history.versionNumber,
|
||||||
toolHistory: history.toolChain
|
toolHistory: history.toolChain
|
||||||
};
|
};
|
||||||
@ -365,7 +365,7 @@ export async function extractBasicFileMetadata(
|
|||||||
if (DEBUG) console.warn('📄 Failed to extract basic metadata:', file.name, error);
|
if (DEBUG) console.warn('📄 Failed to extract basic metadata:', file.name, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
return record;
|
return fileStub;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -375,7 +375,7 @@ export async function extractBasicFileMetadata(
|
|||||||
export async function loadFileHistoryOnDemand(
|
export async function loadFileHistoryOnDemand(
|
||||||
file: File,
|
file: File,
|
||||||
fileId: FileId,
|
fileId: FileId,
|
||||||
updateFileRecord?: (id: FileId, updates: Partial<FileRecord>) => void
|
updateFileStub?: (id: FileId, updates: Partial<StirlingFileStub>) => void
|
||||||
): Promise<{
|
): Promise<{
|
||||||
originalFileId?: string;
|
originalFileId?: string;
|
||||||
versionNumber?: number;
|
versionNumber?: number;
|
||||||
@ -392,7 +392,7 @@ export async function loadFileHistoryOnDemand(
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const baseRecord: FileRecord = {
|
const baseFileStub: StirlingFileStub = {
|
||||||
id: fileId,
|
id: fileId,
|
||||||
name: file.name,
|
name: file.name,
|
||||||
size: file.size,
|
size: file.size,
|
||||||
@ -400,19 +400,19 @@ export async function loadFileHistoryOnDemand(
|
|||||||
lastModified: file.lastModified
|
lastModified: file.lastModified
|
||||||
};
|
};
|
||||||
|
|
||||||
const updatedRecord = await extractFileHistory(file, baseRecord);
|
const updatedFileStub = await extractFileHistory(file, baseFileStub);
|
||||||
|
|
||||||
if (updatedRecord !== baseRecord && (updatedRecord.originalFileId || updatedRecord.versionNumber)) {
|
if (updatedFileStub !== baseFileStub && (updatedFileStub.originalFileId || updatedFileStub.versionNumber)) {
|
||||||
const historyData = {
|
const historyData = {
|
||||||
originalFileId: updatedRecord.originalFileId,
|
originalFileId: updatedFileStub.originalFileId,
|
||||||
versionNumber: updatedRecord.versionNumber,
|
versionNumber: updatedFileStub.versionNumber,
|
||||||
parentFileId: updatedRecord.parentFileId,
|
parentFileId: updatedFileStub.parentFileId,
|
||||||
toolHistory: updatedRecord.toolHistory
|
toolHistory: updatedFileStub.toolHistory
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update the file record if update function is provided
|
// Update the file stub if update function is provided
|
||||||
if (updateFileRecord) {
|
if (updateFileStub) {
|
||||||
updateFileRecord(fileId, historyData);
|
updateFileStub(fileId, historyData);
|
||||||
}
|
}
|
||||||
|
|
||||||
return historyData;
|
return historyData;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user