mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-08-26 14:19:24 +00:00
Added other tools
This commit is contained in:
parent
85caad5f5c
commit
def603a367
@ -0,0 +1,70 @@
|
||||
/**
|
||||
* AddWatermarkSingleStepSettings - Used for automation only
|
||||
*
|
||||
* This component combines all watermark settings into a single step interface
|
||||
* for use in the automation system. It includes type selection and all relevant
|
||||
* settings in one unified component.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { Stack } from "@mantine/core";
|
||||
import { AddWatermarkParameters } from "../../../hooks/tools/addWatermark/useAddWatermarkParameters";
|
||||
import WatermarkTypeSettings from "./WatermarkTypeSettings";
|
||||
import WatermarkWording from "./WatermarkWording";
|
||||
import WatermarkTextStyle from "./WatermarkTextStyle";
|
||||
import WatermarkImageFile from "./WatermarkImageFile";
|
||||
import WatermarkFormatting from "./WatermarkFormatting";
|
||||
|
||||
interface AddWatermarkSingleStepSettingsProps {
|
||||
parameters: AddWatermarkParameters;
|
||||
onParameterChange: <K extends keyof AddWatermarkParameters>(key: K, value: AddWatermarkParameters[K]) => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
const AddWatermarkSingleStepSettings = ({ parameters, onParameterChange, disabled = false }: AddWatermarkSingleStepSettingsProps) => {
|
||||
return (
|
||||
<Stack gap="lg">
|
||||
{/* Watermark Type Selection */}
|
||||
<WatermarkTypeSettings
|
||||
watermarkType={parameters.watermarkType}
|
||||
onWatermarkTypeChange={(type) => onParameterChange("watermarkType", type)}
|
||||
disabled={disabled}
|
||||
/>
|
||||
|
||||
{/* Conditional settings based on watermark type */}
|
||||
{parameters.watermarkType === "text" && (
|
||||
<>
|
||||
<WatermarkWording
|
||||
parameters={parameters}
|
||||
onParameterChange={onParameterChange}
|
||||
disabled={disabled}
|
||||
/>
|
||||
<WatermarkTextStyle
|
||||
parameters={parameters}
|
||||
onParameterChange={onParameterChange}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{parameters.watermarkType === "image" && (
|
||||
<WatermarkImageFile
|
||||
parameters={parameters}
|
||||
onParameterChange={onParameterChange}
|
||||
disabled={disabled}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Formatting settings for both text and image */}
|
||||
{parameters.watermarkType && (
|
||||
<WatermarkFormatting
|
||||
parameters={parameters}
|
||||
onParameterChange={onParameterChange}
|
||||
disabled={disabled}
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddWatermarkSingleStepSettings;
|
@ -17,9 +17,27 @@ import RemoveCertificateSign from '../tools/RemoveCertificateSign';
|
||||
import { compressOperationConfig } from '../hooks/tools/compress/useCompressOperation';
|
||||
import { splitOperationConfig } from '../hooks/tools/split/useSplitOperation';
|
||||
import { addPasswordOperationConfig } from '../hooks/tools/addPassword/useAddPasswordOperation';
|
||||
import { removePasswordOperationConfig } from '../hooks/tools/removePassword/useRemovePasswordOperation';
|
||||
import { sanitizeOperationConfig } from '../hooks/tools/sanitize/useSanitizeOperation';
|
||||
import { repairOperationConfig } from '../hooks/tools/repair/useRepairOperation';
|
||||
import { addWatermarkOperationConfig } from '../hooks/tools/addWatermark/useAddWatermarkOperation';
|
||||
import { unlockPdfFormsOperationConfig } from '../hooks/tools/unlockPdfForms/useUnlockPdfFormsOperation';
|
||||
import { singleLargePageOperationConfig } from '../hooks/tools/singleLargePage/useSingleLargePageOperation';
|
||||
import { ocrOperationConfig } from '../hooks/tools/ocr/useOCROperation';
|
||||
import { convertOperationConfig } from '../hooks/tools/convert/useConvertOperation';
|
||||
import { removeCertificateSignOperationConfig } from '../hooks/tools/removeCertificateSign/useRemoveCertificateSignOperation';
|
||||
import { changePermissionsOperationConfig } from '../hooks/tools/changePermissions/useChangePermissionsOperation';
|
||||
import CompressSettings from '../components/tools/compress/CompressSettings';
|
||||
import SplitSettings from '../components/tools/split/SplitSettings';
|
||||
import AddPasswordSettings from '../components/tools/addPassword/AddPasswordSettings';
|
||||
import RemovePasswordSettings from '../components/tools/removePassword/RemovePasswordSettings';
|
||||
import SanitizeSettings from '../components/tools/sanitize/SanitizeSettings';
|
||||
import RepairSettings from '../components/tools/repair/RepairSettings';
|
||||
import UnlockPdfFormsSettings from '../components/tools/unlockPdfForms/UnlockPdfFormsSettings';
|
||||
import AddWatermarkSingleStepSettings from '../components/tools/addWatermark/AddWatermarkSingleStepSettings';
|
||||
import OCRSettings from '../components/tools/ocr/OCRSettings';
|
||||
import ConvertSettings from '../components/tools/convert/ConvertSettings';
|
||||
import ChangePermissionsSettings from '../components/tools/changePermissions/ChangePermissionsSettings';
|
||||
|
||||
const showPlaceholderTools = false; // For development purposes. Allows seeing the full list of tools, even if they're unimplemented
|
||||
|
||||
@ -75,7 +93,9 @@ export function useFlatToolRegistry(): ToolRegistry {
|
||||
description: t("home.watermark.desc", "Add a custom watermark to your PDF document."),
|
||||
category: ToolCategory.STANDARD_TOOLS,
|
||||
subcategory: SubcategoryId.DOCUMENT_SECURITY,
|
||||
endpoints: ["add-watermark"]
|
||||
endpoints: ["add-watermark"],
|
||||
operationConfig: addWatermarkOperationConfig,
|
||||
settingsComponent: AddWatermarkSingleStepSettings
|
||||
},
|
||||
"add-stamp": {
|
||||
icon: <span className="material-symbols-rounded">approval</span>,
|
||||
@ -95,7 +115,9 @@ export function useFlatToolRegistry(): ToolRegistry {
|
||||
category: ToolCategory.STANDARD_TOOLS,
|
||||
subcategory: SubcategoryId.DOCUMENT_SECURITY,
|
||||
description: t("home.sanitize.desc", "Remove potentially harmful elements from PDF files"),
|
||||
endpoints: ["sanitize-pdf"]
|
||||
endpoints: ["sanitize-pdf"],
|
||||
operationConfig: sanitizeOperationConfig,
|
||||
settingsComponent: SanitizeSettings
|
||||
},
|
||||
"flatten": {
|
||||
icon: <span className="material-symbols-rounded">layers_clear</span>,
|
||||
@ -115,7 +137,9 @@ export function useFlatToolRegistry(): ToolRegistry {
|
||||
category: ToolCategory.STANDARD_TOOLS,
|
||||
subcategory: SubcategoryId.DOCUMENT_SECURITY,
|
||||
maxFiles: -1,
|
||||
endpoints: ["unlock-pdf-forms"]
|
||||
endpoints: ["unlock-pdf-forms"],
|
||||
operationConfig: unlockPdfFormsOperationConfig,
|
||||
settingsComponent: UnlockPdfFormsSettings
|
||||
},
|
||||
"manage-certificates": {
|
||||
icon: <span className="material-symbols-rounded">license</span>,
|
||||
@ -135,7 +159,9 @@ export function useFlatToolRegistry(): ToolRegistry {
|
||||
category: ToolCategory.STANDARD_TOOLS,
|
||||
subcategory: SubcategoryId.DOCUMENT_SECURITY,
|
||||
maxFiles: -1,
|
||||
endpoints: ["add-password"]
|
||||
endpoints: ["add-password"],
|
||||
operationConfig: changePermissionsOperationConfig,
|
||||
settingsComponent: ChangePermissionsSettings
|
||||
},
|
||||
// Verification
|
||||
|
||||
@ -255,7 +281,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
||||
category: ToolCategory.STANDARD_TOOLS,
|
||||
subcategory: SubcategoryId.PAGE_FORMATTING,
|
||||
maxFiles: -1,
|
||||
endpoints: ["pdf-to-single-page"]
|
||||
endpoints: ["pdf-to-single-page"],
|
||||
operationConfig: singleLargePageOperationConfig
|
||||
},
|
||||
"add-attachments": {
|
||||
icon: <span className="material-symbols-rounded">attachment</span>,
|
||||
@ -338,7 +365,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
||||
subcategory: SubcategoryId.REMOVAL,
|
||||
endpoints: ["remove-password"],
|
||||
maxFiles: -1,
|
||||
|
||||
operationConfig: removePasswordOperationConfig,
|
||||
settingsComponent: RemovePasswordSettings
|
||||
},
|
||||
"remove-certificate-sign": {
|
||||
icon: <span className="material-symbols-rounded">remove_moderator</span>,
|
||||
@ -349,7 +377,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
||||
category: ToolCategory.STANDARD_TOOLS,
|
||||
subcategory: SubcategoryId.REMOVAL,
|
||||
maxFiles: -1,
|
||||
endpoints: ["remove-certificate-sign"]
|
||||
endpoints: ["remove-certificate-sign"],
|
||||
operationConfig: removeCertificateSignOperationConfig
|
||||
},
|
||||
|
||||
|
||||
@ -415,7 +444,9 @@ export function useFlatToolRegistry(): ToolRegistry {
|
||||
category: ToolCategory.ADVANCED_TOOLS,
|
||||
subcategory: SubcategoryId.ADVANCED_FORMATTING,
|
||||
maxFiles: -1,
|
||||
endpoints: ["repair"]
|
||||
endpoints: ["repair"],
|
||||
operationConfig: repairOperationConfig,
|
||||
settingsComponent: RepairSettings
|
||||
},
|
||||
"detect-split-scanned-photos": {
|
||||
icon: <span className="material-symbols-rounded">scanner</span>,
|
||||
@ -590,7 +621,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
||||
"zip",
|
||||
// Other
|
||||
"dbf", "fods", "vsd", "vor", "vor3", "vor4", "uop", "pct", "ps", "pdf"
|
||||
]
|
||||
],
|
||||
operationConfig: convertOperationConfig
|
||||
},
|
||||
"mergePdfs": {
|
||||
icon: <span className="material-symbols-rounded">library_add</span>,
|
||||
@ -620,7 +652,9 @@ export function useFlatToolRegistry(): ToolRegistry {
|
||||
description: t("home.ocr.desc", "Extract text from scanned PDFs using Optical Character Recognition"),
|
||||
category: ToolCategory.RECOMMENDED_TOOLS,
|
||||
subcategory: SubcategoryId.GENERAL,
|
||||
maxFiles: -1
|
||||
maxFiles: -1,
|
||||
operationConfig: ocrOperationConfig,
|
||||
settingsComponent: OCRSettings
|
||||
},
|
||||
"redact": {
|
||||
icon: <span className="material-symbols-rounded">visibility_off</span>,
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useToolOperation } from '../shared/useToolOperation';
|
||||
import { createStandardErrorHandler } from '../../../utils/toolErrorHandler';
|
||||
import { AddWatermarkParameters } from './useAddWatermarkParameters';
|
||||
import { AddWatermarkParameters, defaultParameters } from './useAddWatermarkParameters';
|
||||
|
||||
const buildFormData = (parameters: AddWatermarkParameters, file: File): FormData => {
|
||||
// Static function that can be used by both the hook and automation executor
|
||||
export const buildAddWatermarkFormData = (parameters: AddWatermarkParameters, file: File): FormData => {
|
||||
const formData = new FormData();
|
||||
formData.append("fileInput", file);
|
||||
|
||||
@ -32,15 +33,22 @@ const buildFormData = (parameters: AddWatermarkParameters, file: File): FormData
|
||||
return formData;
|
||||
};
|
||||
|
||||
// Static configuration object
|
||||
export const addWatermarkOperationConfig = {
|
||||
operationType: 'watermark',
|
||||
endpoint: '/api/v1/security/add-watermark',
|
||||
buildFormData: buildAddWatermarkFormData,
|
||||
filePrefix: 'watermarked_', // Will be overridden in hook with translation
|
||||
multiFileEndpoint: false,
|
||||
defaultParameters,
|
||||
} as const;
|
||||
|
||||
export const useAddWatermarkOperation = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return useToolOperation<AddWatermarkParameters>({
|
||||
operationType: 'watermark',
|
||||
endpoint: '/api/v1/security/add-watermark',
|
||||
buildFormData,
|
||||
...addWatermarkOperationConfig,
|
||||
filePrefix: t('watermark.filenamePrefix', 'watermarked') + '_',
|
||||
multiFileEndpoint: false, // Individual API calls per file
|
||||
getErrorMessage: createStandardErrorHandler(t('watermark.error.failed', 'An error occurred while adding watermark to the PDF.'))
|
||||
});
|
||||
};
|
@ -1,7 +1,7 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useToolOperation } from '../shared/useToolOperation';
|
||||
import { createStandardErrorHandler } from '../../../utils/toolErrorHandler';
|
||||
import type { ChangePermissionsParameters } from './useChangePermissionsParameters';
|
||||
import { ChangePermissionsParameters, defaultParameters } from './useChangePermissionsParameters';
|
||||
|
||||
export const getFormData = ((parameters: ChangePermissionsParameters) =>
|
||||
Object.entries(parameters).map(([key, value]) =>
|
||||
@ -9,10 +9,8 @@ export const getFormData = ((parameters: ChangePermissionsParameters) =>
|
||||
) as string[][]
|
||||
);
|
||||
|
||||
export const useChangePermissionsOperation = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const buildFormData = (parameters: ChangePermissionsParameters, file: File): FormData => {
|
||||
// Static function that can be used by both the hook and automation executor
|
||||
export const buildChangePermissionsFormData = (parameters: ChangePermissionsParameters, file: File): FormData => {
|
||||
const formData = new FormData();
|
||||
formData.append("fileInput", file);
|
||||
|
||||
@ -24,12 +22,21 @@ export const useChangePermissionsOperation = () => {
|
||||
return formData;
|
||||
};
|
||||
|
||||
return useToolOperation({
|
||||
operationType: 'changePermissions',
|
||||
// Static configuration object
|
||||
export const changePermissionsOperationConfig = {
|
||||
operationType: 'change-permissions',
|
||||
endpoint: '/api/v1/security/add-password', // Change Permissions is a fake endpoint for the Add Password tool
|
||||
buildFormData,
|
||||
buildFormData: buildChangePermissionsFormData,
|
||||
filePrefix: 'permissions_',
|
||||
multiFileEndpoint: false,
|
||||
defaultParameters,
|
||||
} as const;
|
||||
|
||||
export const useChangePermissionsOperation = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return useToolOperation({
|
||||
...changePermissionsOperationConfig,
|
||||
getErrorMessage: createStandardErrorHandler(
|
||||
t('changePermissions.error.failed', 'An error occurred while changing PDF permissions.')
|
||||
)
|
||||
|
@ -1,13 +1,14 @@
|
||||
import { useCallback } from 'react';
|
||||
import axios from 'axios';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ConvertParameters } from './useConvertParameters';
|
||||
import { ConvertParameters, defaultParameters } from './useConvertParameters';
|
||||
import { detectFileExtension } from '../../../utils/fileUtils';
|
||||
import { createFileFromApiResponse } from '../../../utils/fileResponseUtils';
|
||||
import { useToolOperation, ToolOperationConfig } from '../shared/useToolOperation';
|
||||
import { getEndpointUrl, isImageFormat, isWebFormat } from '../../../utils/convertUtils';
|
||||
|
||||
const shouldProcessFilesSeparately = (
|
||||
// Static function that can be used by both the hook and automation executor
|
||||
export const shouldProcessFilesSeparately = (
|
||||
selectedFiles: File[],
|
||||
parameters: ConvertParameters
|
||||
): boolean => {
|
||||
@ -29,7 +30,8 @@ const shouldProcessFilesSeparately = (
|
||||
);
|
||||
};
|
||||
|
||||
const buildFormData = (parameters: ConvertParameters, selectedFiles: File[]): FormData => {
|
||||
// Static function that can be used by both the hook and automation executor
|
||||
export const buildConvertFormData = (parameters: ConvertParameters, selectedFiles: File[]): FormData => {
|
||||
const formData = new FormData();
|
||||
|
||||
selectedFiles.forEach(file => {
|
||||
@ -69,7 +71,8 @@ const buildFormData = (parameters: ConvertParameters, selectedFiles: File[]): Fo
|
||||
return formData;
|
||||
};
|
||||
|
||||
const createFileFromResponse = (
|
||||
// Static function that can be used by both the hook and automation executor
|
||||
export const createFileFromResponse = (
|
||||
responseData: any,
|
||||
headers: any,
|
||||
originalFileName: string,
|
||||
@ -81,19 +84,16 @@ const createFileFromResponse = (
|
||||
return createFileFromApiResponse(responseData, headers, fallbackFilename);
|
||||
};
|
||||
|
||||
export const useConvertOperation = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const customConvertProcessor = useCallback(async (
|
||||
// Static processor that can be used by both the hook and automation executor
|
||||
export const convertProcessor = async (
|
||||
parameters: ConvertParameters,
|
||||
selectedFiles: File[]
|
||||
): Promise<File[]> => {
|
||||
|
||||
const processedFiles: File[] = [];
|
||||
const endpoint = getEndpointUrl(parameters.fromExtension, parameters.toExtension);
|
||||
|
||||
if (!endpoint) {
|
||||
throw new Error(t('errorNotSupported', 'Unsupported conversion format'));
|
||||
throw new Error('Unsupported conversion format');
|
||||
}
|
||||
|
||||
// Convert-specific routing logic: decide batch vs individual processing
|
||||
@ -101,7 +101,7 @@ export const useConvertOperation = () => {
|
||||
// Individual processing for complex cases (PDF→image, smart detection, etc.)
|
||||
for (const file of selectedFiles) {
|
||||
try {
|
||||
const formData = buildFormData(parameters, [file]);
|
||||
const formData = buildConvertFormData(parameters, [file]);
|
||||
const response = await axios.post(endpoint, formData, { responseType: 'blob' });
|
||||
|
||||
const convertedFile = createFileFromResponse(response.data, response.headers, file.name, parameters.toExtension);
|
||||
@ -113,7 +113,7 @@ export const useConvertOperation = () => {
|
||||
}
|
||||
} else {
|
||||
// Batch processing for simple cases (image→PDF combine)
|
||||
const formData = buildFormData(parameters, selectedFiles);
|
||||
const formData = buildConvertFormData(parameters, selectedFiles);
|
||||
const response = await axios.post(endpoint, formData, { responseType: 'blob' });
|
||||
|
||||
const baseFilename = selectedFiles.length === 1
|
||||
@ -122,18 +122,34 @@ export const useConvertOperation = () => {
|
||||
|
||||
const convertedFile = createFileFromResponse(response.data, response.headers, baseFilename, parameters.toExtension);
|
||||
processedFiles.push(convertedFile);
|
||||
|
||||
}
|
||||
|
||||
return processedFiles;
|
||||
}, [t]);
|
||||
};
|
||||
|
||||
return useToolOperation<ConvertParameters>({
|
||||
// Static configuration object
|
||||
export const convertOperationConfig = {
|
||||
operationType: 'convert',
|
||||
endpoint: '', // Not used with customProcessor but required
|
||||
buildFormData, // Not used with customProcessor but required
|
||||
buildFormData: buildConvertFormData, // Not used with customProcessor but required
|
||||
filePrefix: 'converted_',
|
||||
customProcessor: customConvertProcessor, // Convert handles its own routing
|
||||
customProcessor: convertProcessor,
|
||||
defaultParameters,
|
||||
} as const;
|
||||
|
||||
export const useConvertOperation = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const customConvertProcessor = useCallback(async (
|
||||
parameters: ConvertParameters,
|
||||
selectedFiles: File[]
|
||||
): Promise<File[]> => {
|
||||
return convertProcessor(parameters, selectedFiles);
|
||||
}, []);
|
||||
|
||||
return useToolOperation<ConvertParameters>({
|
||||
...convertOperationConfig,
|
||||
customProcessor: customConvertProcessor, // Use instance-specific processor for translation support
|
||||
getErrorMessage: (error) => {
|
||||
if (error.response?.data && typeof error.response.data === 'string') {
|
||||
return error.response.data;
|
||||
|
@ -46,7 +46,7 @@ export interface ConvertParametersHook extends BaseParametersHook<ConvertParamet
|
||||
analyzeFileTypes: (files: Array<{name: string}>) => void;
|
||||
}
|
||||
|
||||
const defaultParameters: ConvertParameters = {
|
||||
export const defaultParameters: ConvertParameters = {
|
||||
fromExtension: '',
|
||||
toExtension: '',
|
||||
imageOptions: {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { OCRParameters } from './useOCRParameters';
|
||||
import { OCRParameters, defaultParameters } from './useOCRParameters';
|
||||
import { useToolOperation, ToolOperationConfig } from '../shared/useToolOperation';
|
||||
import { createStandardErrorHandler } from '../../../utils/toolErrorHandler';
|
||||
import { useToolResources } from '../shared/useToolResources';
|
||||
@ -37,7 +37,8 @@ function stripExt(name: string): string {
|
||||
return i > 0 ? name.slice(0, i) : name;
|
||||
}
|
||||
|
||||
const buildFormData = (parameters: OCRParameters, file: File): FormData => {
|
||||
// Static function that can be used by both the hook and automation executor
|
||||
export const buildOCRFormData = (parameters: OCRParameters, file: File): FormData => {
|
||||
const formData = new FormData();
|
||||
formData.append('fileInput', file);
|
||||
parameters.languages.forEach((lang) => formData.append('languages', lang));
|
||||
@ -51,12 +52,8 @@ const buildFormData = (parameters: OCRParameters, file: File): FormData => {
|
||||
return formData;
|
||||
};
|
||||
|
||||
export const useOCROperation = () => {
|
||||
const { t } = useTranslation();
|
||||
const { extractZipFiles } = useToolResources();
|
||||
|
||||
// OCR-specific parsing: ZIP (sidecar) vs PDF vs HTML error
|
||||
const responseHandler = useCallback(async (blob: Blob, originalFiles: File[]): Promise<File[]> => {
|
||||
// Static response handler for OCR - can be used by automation executor
|
||||
export const ocrResponseHandler = async (blob: Blob, originalFiles: File[], extractZipFiles: (blob: Blob) => Promise<{ success: boolean; extractedFiles: File[]; errors: string[] }>): Promise<File[]> => {
|
||||
const headBuf = await blob.slice(0, 8).arrayBuffer();
|
||||
const head = new TextDecoder().decode(new Uint8Array(headBuf));
|
||||
|
||||
@ -64,8 +61,8 @@ export const useOCROperation = () => {
|
||||
if (head.startsWith('PK')) {
|
||||
const base = stripExt(originalFiles[0].name);
|
||||
try {
|
||||
const extracted = await extractZipFiles(blob);
|
||||
if (extracted.length > 0) return extracted;
|
||||
const result = await extractZipFiles(blob);
|
||||
if (result.success && result.extractedFiles.length > 0) return result.extractedFiles;
|
||||
} catch { /* ignore and try local extractor */ }
|
||||
try {
|
||||
const local = await extractZipFile(blob); // local fallback
|
||||
@ -85,7 +82,7 @@ export const useOCROperation = () => {
|
||||
const title =
|
||||
text.match(/<title[^>]*>([^<]+)<\/title>/i)?.[1] ||
|
||||
text.match(/<h1[^>]*>([^<]+)<\/h1>/i)?.[1] ||
|
||||
t('ocr.error.unknown', 'Unknown error');
|
||||
'Unknown error';
|
||||
throw new Error(`OCR service error: ${title}`);
|
||||
}
|
||||
throw new Error(`Response is not a valid PDF. Header: "${head}"`);
|
||||
@ -93,15 +90,30 @@ export const useOCROperation = () => {
|
||||
|
||||
const base = stripExt(originalFiles[0].name);
|
||||
return [new File([blob], `ocr_${base}.pdf`, { type: 'application/pdf' })];
|
||||
}, [t, extractZipFiles]);
|
||||
};
|
||||
|
||||
const ocrConfig: ToolOperationConfig<OCRParameters> = {
|
||||
// Static configuration object (without t function dependencies)
|
||||
export const ocrOperationConfig = {
|
||||
operationType: 'ocr',
|
||||
endpoint: '/api/v1/misc/ocr-pdf',
|
||||
buildFormData,
|
||||
buildFormData: buildOCRFormData,
|
||||
filePrefix: 'ocr_',
|
||||
multiFileEndpoint: false, // Process files individually
|
||||
responseHandler, // use shared flow
|
||||
multiFileEndpoint: false,
|
||||
defaultParameters,
|
||||
} as const;
|
||||
|
||||
export const useOCROperation = () => {
|
||||
const { t } = useTranslation();
|
||||
const { extractZipFiles } = useToolResources();
|
||||
|
||||
// OCR-specific parsing: ZIP (sidecar) vs PDF vs HTML error
|
||||
const responseHandler = useCallback(async (blob: Blob, originalFiles: File[]): Promise<File[]> => {
|
||||
return ocrResponseHandler(blob, originalFiles, extractZipFiles);
|
||||
}, [extractZipFiles]);
|
||||
|
||||
const ocrConfig: ToolOperationConfig<OCRParameters> = {
|
||||
...ocrOperationConfig,
|
||||
responseHandler,
|
||||
getErrorMessage: (error) =>
|
||||
error.message?.includes('OCR tools') && error.message?.includes('not installed')
|
||||
? 'OCR tools (OCRmyPDF or Tesseract) are not installed on the server. Use the standard or fat Docker image instead of ultra-lite, or install OCR tools manually.'
|
||||
|
@ -10,7 +10,7 @@ export interface OCRParameters extends BaseParameters {
|
||||
|
||||
export type OCRParametersHook = BaseParametersHook<OCRParameters>;
|
||||
|
||||
const defaultParameters: OCRParameters = {
|
||||
export const defaultParameters: OCRParameters = {
|
||||
languages: [],
|
||||
ocrType: 'skip-text',
|
||||
ocrRenderType: 'hocr',
|
||||
|
@ -1,23 +1,31 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useToolOperation } from '../shared/useToolOperation';
|
||||
import { createStandardErrorHandler } from '../../../utils/toolErrorHandler';
|
||||
import { RemoveCertificateSignParameters } from './useRemoveCertificateSignParameters';
|
||||
import { RemoveCertificateSignParameters, defaultParameters } from './useRemoveCertificateSignParameters';
|
||||
|
||||
export const useRemoveCertificateSignOperation = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const buildFormData = (parameters: RemoveCertificateSignParameters, file: File): FormData => {
|
||||
// Static function that can be used by both the hook and automation executor
|
||||
export const buildRemoveCertificateSignFormData = (parameters: RemoveCertificateSignParameters, file: File): FormData => {
|
||||
const formData = new FormData();
|
||||
formData.append("fileInput", file);
|
||||
return formData;
|
||||
};
|
||||
|
||||
return useToolOperation<RemoveCertificateSignParameters>({
|
||||
operationType: 'removeCertificateSign',
|
||||
// Static configuration object
|
||||
export const removeCertificateSignOperationConfig = {
|
||||
operationType: 'remove-certificate-sign',
|
||||
endpoint: '/api/v1/security/remove-cert-sign',
|
||||
buildFormData,
|
||||
filePrefix: t('removeCertSign.filenamePrefix', 'unsigned') + '_',
|
||||
buildFormData: buildRemoveCertificateSignFormData,
|
||||
filePrefix: 'unsigned_', // Will be overridden in hook with translation
|
||||
multiFileEndpoint: false,
|
||||
defaultParameters,
|
||||
} as const;
|
||||
|
||||
export const useRemoveCertificateSignOperation = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return useToolOperation<RemoveCertificateSignParameters>({
|
||||
...removeCertificateSignOperationConfig,
|
||||
filePrefix: t('removeCertSign.filenamePrefix', 'unsigned') + '_',
|
||||
getErrorMessage: createStandardErrorHandler(t('removeCertSign.error.failed', 'An error occurred while removing certificate signatures.'))
|
||||
});
|
||||
};
|
@ -1,24 +1,32 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useToolOperation } from '../shared/useToolOperation';
|
||||
import { createStandardErrorHandler } from '../../../utils/toolErrorHandler';
|
||||
import { RemovePasswordParameters } from './useRemovePasswordParameters';
|
||||
import { RemovePasswordParameters, defaultParameters } from './useRemovePasswordParameters';
|
||||
|
||||
export const useRemovePasswordOperation = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const buildFormData = (parameters: RemovePasswordParameters, file: File): FormData => {
|
||||
// Static function that can be used by both the hook and automation executor
|
||||
export const buildRemovePasswordFormData = (parameters: RemovePasswordParameters, file: File): FormData => {
|
||||
const formData = new FormData();
|
||||
formData.append("fileInput", file);
|
||||
formData.append("password", parameters.password);
|
||||
return formData;
|
||||
};
|
||||
|
||||
return useToolOperation<RemovePasswordParameters>({
|
||||
// Static configuration object
|
||||
export const removePasswordOperationConfig = {
|
||||
operationType: 'removePassword',
|
||||
endpoint: '/api/v1/security/remove-password',
|
||||
buildFormData,
|
||||
filePrefix: t('removePassword.filenamePrefix', 'decrypted') + '_',
|
||||
buildFormData: buildRemovePasswordFormData,
|
||||
filePrefix: 'decrypted_', // Will be overridden in hook with translation
|
||||
multiFileEndpoint: false,
|
||||
defaultParameters,
|
||||
} as const;
|
||||
|
||||
export const useRemovePasswordOperation = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return useToolOperation<RemovePasswordParameters>({
|
||||
...removePasswordOperationConfig,
|
||||
filePrefix: t('removePassword.filenamePrefix', 'decrypted') + '_',
|
||||
getErrorMessage: createStandardErrorHandler(t('removePassword.error.failed', 'An error occurred while removing the password from the PDF.'))
|
||||
});
|
||||
};
|
||||
|
@ -1,23 +1,31 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useToolOperation } from '../shared/useToolOperation';
|
||||
import { createStandardErrorHandler } from '../../../utils/toolErrorHandler';
|
||||
import { RepairParameters } from './useRepairParameters';
|
||||
import { RepairParameters, defaultParameters } from './useRepairParameters';
|
||||
|
||||
export const useRepairOperation = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const buildFormData = (parameters: RepairParameters, file: File): FormData => {
|
||||
// Static function that can be used by both the hook and automation executor
|
||||
export const buildRepairFormData = (parameters: RepairParameters, file: File): FormData => {
|
||||
const formData = new FormData();
|
||||
formData.append("fileInput", file);
|
||||
return formData;
|
||||
};
|
||||
|
||||
return useToolOperation<RepairParameters>({
|
||||
// Static configuration object
|
||||
export const repairOperationConfig = {
|
||||
operationType: 'repair',
|
||||
endpoint: '/api/v1/misc/repair',
|
||||
buildFormData,
|
||||
filePrefix: t('repair.filenamePrefix', 'repaired') + '_',
|
||||
buildFormData: buildRepairFormData,
|
||||
filePrefix: 'repaired_', // Will be overridden in hook with translation
|
||||
multiFileEndpoint: false,
|
||||
defaultParameters,
|
||||
} as const;
|
||||
|
||||
export const useRepairOperation = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return useToolOperation<RepairParameters>({
|
||||
...repairOperationConfig,
|
||||
filePrefix: t('repair.filenamePrefix', 'repaired') + '_',
|
||||
getErrorMessage: createStandardErrorHandler(t('repair.error.failed', 'An error occurred while repairing the PDF.'))
|
||||
});
|
||||
};
|
@ -1,9 +1,10 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useToolOperation } from '../shared/useToolOperation';
|
||||
import { createStandardErrorHandler } from '../../../utils/toolErrorHandler';
|
||||
import { SanitizeParameters } from './useSanitizeParameters';
|
||||
import { SanitizeParameters, defaultParameters } from './useSanitizeParameters';
|
||||
|
||||
const buildFormData = (parameters: SanitizeParameters, file: File): FormData => {
|
||||
// Static function that can be used by both the hook and automation executor
|
||||
export const buildSanitizeFormData = (parameters: SanitizeParameters, file: File): FormData => {
|
||||
const formData = new FormData();
|
||||
formData.append('fileInput', file);
|
||||
|
||||
@ -18,15 +19,22 @@ const buildFormData = (parameters: SanitizeParameters, file: File): FormData =>
|
||||
return formData;
|
||||
};
|
||||
|
||||
// Static configuration object
|
||||
export const sanitizeOperationConfig = {
|
||||
operationType: 'sanitize',
|
||||
endpoint: '/api/v1/security/sanitize-pdf',
|
||||
buildFormData: buildSanitizeFormData,
|
||||
filePrefix: 'sanitized_', // Will be overridden in hook with translation
|
||||
multiFileEndpoint: false,
|
||||
defaultParameters,
|
||||
} as const;
|
||||
|
||||
export const useSanitizeOperation = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return useToolOperation<SanitizeParameters>({
|
||||
operationType: 'sanitize',
|
||||
endpoint: '/api/v1/security/sanitize-pdf',
|
||||
buildFormData,
|
||||
...sanitizeOperationConfig,
|
||||
filePrefix: t('sanitize.filenamePrefix', 'sanitized') + '_',
|
||||
multiFileEndpoint: false, // Individual API calls per file
|
||||
getErrorMessage: createStandardErrorHandler(t('sanitize.error.failed', 'An error occurred while sanitising the PDF.'))
|
||||
});
|
||||
};
|
||||
|
@ -1,23 +1,31 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useToolOperation } from '../shared/useToolOperation';
|
||||
import { createStandardErrorHandler } from '../../../utils/toolErrorHandler';
|
||||
import { SingleLargePageParameters } from './useSingleLargePageParameters';
|
||||
import { SingleLargePageParameters, defaultParameters } from './useSingleLargePageParameters';
|
||||
|
||||
export const useSingleLargePageOperation = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const buildFormData = (parameters: SingleLargePageParameters, file: File): FormData => {
|
||||
// Static function that can be used by both the hook and automation executor
|
||||
export const buildSingleLargePageFormData = (parameters: SingleLargePageParameters, file: File): FormData => {
|
||||
const formData = new FormData();
|
||||
formData.append("fileInput", file);
|
||||
return formData;
|
||||
};
|
||||
|
||||
return useToolOperation<SingleLargePageParameters>({
|
||||
operationType: 'singleLargePage',
|
||||
// Static configuration object
|
||||
export const singleLargePageOperationConfig = {
|
||||
operationType: 'single-large-page',
|
||||
endpoint: '/api/v1/general/pdf-to-single-page',
|
||||
buildFormData,
|
||||
filePrefix: t('pdfToSinglePage.filenamePrefix', 'single_page') + '_',
|
||||
buildFormData: buildSingleLargePageFormData,
|
||||
filePrefix: 'single_page_', // Will be overridden in hook with translation
|
||||
multiFileEndpoint: false,
|
||||
defaultParameters,
|
||||
} as const;
|
||||
|
||||
export const useSingleLargePageOperation = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return useToolOperation<SingleLargePageParameters>({
|
||||
...singleLargePageOperationConfig,
|
||||
filePrefix: t('pdfToSinglePage.filenamePrefix', 'single_page') + '_',
|
||||
getErrorMessage: createStandardErrorHandler(t('pdfToSinglePage.error.failed', 'An error occurred while converting to single page.'))
|
||||
});
|
||||
};
|
@ -1,23 +1,31 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useToolOperation } from '../shared/useToolOperation';
|
||||
import { createStandardErrorHandler } from '../../../utils/toolErrorHandler';
|
||||
import { UnlockPdfFormsParameters } from './useUnlockPdfFormsParameters';
|
||||
import { UnlockPdfFormsParameters, defaultParameters } from './useUnlockPdfFormsParameters';
|
||||
|
||||
export const useUnlockPdfFormsOperation = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const buildFormData = (parameters: UnlockPdfFormsParameters, file: File): FormData => {
|
||||
// Static function that can be used by both the hook and automation executor
|
||||
export const buildUnlockPdfFormsFormData = (parameters: UnlockPdfFormsParameters, file: File): FormData => {
|
||||
const formData = new FormData();
|
||||
formData.append("fileInput", file);
|
||||
return formData;
|
||||
};
|
||||
|
||||
return useToolOperation<UnlockPdfFormsParameters>({
|
||||
operationType: 'unlockPdfForms',
|
||||
// Static configuration object
|
||||
export const unlockPdfFormsOperationConfig = {
|
||||
operationType: 'unlock-pdf-forms',
|
||||
endpoint: '/api/v1/misc/unlock-pdf-forms',
|
||||
buildFormData,
|
||||
filePrefix: t('unlockPDFForms.filenamePrefix', 'unlocked_forms') + '_',
|
||||
buildFormData: buildUnlockPdfFormsFormData,
|
||||
filePrefix: 'unlocked_forms_', // Will be overridden in hook with translation
|
||||
multiFileEndpoint: false,
|
||||
defaultParameters,
|
||||
} as const;
|
||||
|
||||
export const useUnlockPdfFormsOperation = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return useToolOperation<UnlockPdfFormsParameters>({
|
||||
...unlockPdfFormsOperationConfig,
|
||||
filePrefix: t('unlockPDFForms.filenamePrefix', 'unlocked_forms') + '_',
|
||||
getErrorMessage: createStandardErrorHandler(t('unlockPDFForms.error.failed', 'An error occurred while unlocking PDF forms.'))
|
||||
});
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user