Translations and merges

This commit is contained in:
Connor Yoh 2025-08-21 12:22:45 +01:00
parent 018d1e57ff
commit bd9c6f9a03
16 changed files with 102 additions and 49 deletions

View File

@ -85,6 +85,7 @@
"warning": {
"tooltipTitle": "Warning"
},
"edit": "Edit",
"delete": "Delete",
"username": "Username",
"password": "Password",
@ -538,10 +539,6 @@
"title": "Edit Table of Contents",
"desc": "Add or edit bookmarks and table of contents in PDF documents"
},
"automate": {
"title": "Automate",
"desc": "Build multi-step workflows by chaining together PDF actions. Ideal for recurring tasks."
},
"manageCertificates": {
"title": "Manage Certificates",
"desc": "Import, export, or delete digital certificate files used for signing PDFs."
@ -601,6 +598,10 @@
"changePermissions": {
"title": "Change Permissions",
"desc": "Change document restrictions and permissions"
},
"automate": {
"title": "Automate",
"desc": "Build multi-step workflows by chaining together PDF actions. Ideal for recurring tasks."
}
},
"viewPdf": {
@ -2184,5 +2185,68 @@
"results": {
"title": "Decrypted PDFs"
}
}
},
"automate": {
"title": "Automate",
"desc": "Build multi-step workflows by chaining together PDF actions. Ideal for recurring tasks.",
"invalidStep": "Invalid step",
"files": {
"placeholder": "Select files to process with this automation"
},
"selection": {
"title": "Automation Selection",
"saved": {
"title": "Saved"
},
"createNew": {
"title": "Create New Automation"
},
"suggested": {
"title": "Suggested"
}
},
"creation": {
"createTitle": "Create Automation",
"editTitle": "Edit Automation",
"description": "Automations run tools sequentially. To get started, add tools in the order you want them to run.",
"name": {
"placeholder": "Automation name"
},
"tools": {
"selectTool": "Select a tool...",
"selected": "Selected Tools",
"remove": "Remove tool",
"configure": "Configure tool",
"notConfigured": "! Not Configured",
"addTool": "Add Tool",
"add": "Add a tool..."
},
"save": "Save Automation",
"unsavedChanges": {
"title": "Unsaved Changes",
"message": "You have unsaved changes. Are you sure you want to go back? All changes will be lost.",
"cancel": "Cancel",
"confirm": "Go Back"
}
},
"run": {
"title": "Run Automation"
},
"sequence": {
"unnamed": "Unnamed Automation",
"steps": "{{count}} steps",
"running": "Running Automation...",
"run": "Run Automation",
"finish": "Finish"
},
"reviewTitle": "Automation Results",
"config": {
"loading": "Loading tool configuration...",
"noSettings": "This tool does not have configurable settings.",
"title": "Configure {{toolName}}",
"description": "Configure the settings for this tool. These settings will be applied when the automation runs.",
"cancel": "Cancel",
"save": "Save Configuration"
}
}
}

View File

@ -6,7 +6,7 @@ import NumberInputWithUnit from "../shared/NumberInputWithUnit";
interface WatermarkFormattingProps {
parameters: AddWatermarkParameters;
onParameterChange: (key: keyof AddWatermarkParameters, value: any) => void;
onParameterChange: <K extends keyof AddWatermarkParameters>(key: K, value: AddWatermarkParameters[K]) => void;
disabled?: boolean;
}

View File

@ -6,7 +6,7 @@ import FileUploadButton from "../../shared/FileUploadButton";
interface WatermarkImageFileProps {
parameters: AddWatermarkParameters;
onParameterChange: (key: keyof AddWatermarkParameters, value: any) => void;
onParameterChange: <K extends keyof AddWatermarkParameters>(key: K, value: AddWatermarkParameters[K]) => void;
disabled?: boolean;
}
@ -17,7 +17,7 @@ const WatermarkImageFile = ({ parameters, onParameterChange, disabled = false }:
<Stack gap="sm">
<FileUploadButton
file={parameters.watermarkImage}
onChange={(file) => onParameterChange('watermarkImage', file)}
onChange={(file) => onParameterChange('watermarkImage', file || undefined)}
accept="image/*"
disabled={disabled}
placeholder={t('watermark.settings.image.choose', 'Choose Image')}

View File

@ -5,7 +5,7 @@ import { AddWatermarkParameters } from "../../../hooks/tools/addWatermark/useAdd
interface WatermarkStyleSettingsProps {
parameters: AddWatermarkParameters;
onParameterChange: (key: keyof AddWatermarkParameters, value: any) => void;
onParameterChange: <K extends keyof AddWatermarkParameters>(key: K, value: AddWatermarkParameters[K]) => void;
disabled?: boolean;
}
@ -19,7 +19,7 @@ const WatermarkStyleSettings = ({ parameters, onParameterChange, disabled = fals
<Text size="sm" fw={500}>{t('watermark.settings.rotation', 'Rotation (degrees)')}</Text>
<NumberInput
value={parameters.rotation}
onChange={(value) => onParameterChange('rotation', value || 0)}
onChange={(value) => onParameterChange('rotation', typeof value === 'number' ? value : (parseInt(value as string, 10) || 0))}
min={-360}
max={360}
disabled={disabled}
@ -28,7 +28,7 @@ const WatermarkStyleSettings = ({ parameters, onParameterChange, disabled = fals
<Text size="sm" fw={500}>{t('watermark.settings.opacity', 'Opacity (%)')}</Text>
<NumberInput
value={parameters.opacity}
onChange={(value) => onParameterChange('opacity', value || 50)}
onChange={(value) => onParameterChange('opacity', typeof value === 'number' ? value : (parseInt(value as string, 10) || 50))}
min={0}
max={100}
disabled={disabled}
@ -40,7 +40,7 @@ const WatermarkStyleSettings = ({ parameters, onParameterChange, disabled = fals
<Text size="sm" fw={500}>{t('watermark.settings.spacing.width', 'Width Spacing')}</Text>
<NumberInput
value={parameters.widthSpacer}
onChange={(value) => onParameterChange('widthSpacer', value || 50)}
onChange={(value) => onParameterChange('widthSpacer', typeof value === 'number' ? value : (parseInt(value as string, 10) || 50))}
min={0}
max={200}
disabled={disabled}
@ -49,7 +49,7 @@ const WatermarkStyleSettings = ({ parameters, onParameterChange, disabled = fals
<Text size="sm" fw={500}>{t('watermark.settings.spacing.height', 'Height Spacing')}</Text>
<NumberInput
value={parameters.heightSpacer}
onChange={(value) => onParameterChange('heightSpacer', value || 50)}
onChange={(value) => onParameterChange('heightSpacer', typeof value === 'number' ? value : (parseInt(value as string, 10) || 50))}
min={0}
max={200}
disabled={disabled}

View File

@ -6,7 +6,7 @@ import { alphabetOptions } from "../../../constants/addWatermarkConstants";
interface WatermarkTextStyleProps {
parameters: AddWatermarkParameters;
onParameterChange: (key: keyof AddWatermarkParameters, value: any) => void;
onParameterChange: <K extends keyof AddWatermarkParameters>(key: K, value: AddWatermarkParameters[K]) => void;
disabled?: boolean;
}

View File

@ -6,7 +6,7 @@ import { removeEmojis } from "../../../utils/textUtils";
interface WatermarkWordingProps {
parameters: AddWatermarkParameters;
onParameterChange: (key: keyof AddWatermarkParameters, value: any) => void;
onParameterChange: <K extends keyof AddWatermarkParameters>(key: K, value: AddWatermarkParameters[K]) => void;
disabled?: boolean;
}

View File

@ -140,7 +140,7 @@ export default function AutomationEntry({
onEdit();
}}
>
{t('common.edit', 'Edit')}
{t('edit', 'Edit')}
</Menu.Item>
)}
{onDelete && (
@ -151,7 +151,7 @@ export default function AutomationEntry({
onDelete();
}}
>
{t('common.delete', 'Delete')}
{t('delete', 'Delete')}
</Menu.Item>
)}
</Menu.Dropdown>

View File

@ -39,7 +39,7 @@ export const AutomationExecutor: React.FC<AutomationExecutorProps> = ({
const tool = toolRegistry[op.operation];
if (tool?.component) {
const toolComponent = tool.component as ToolComponent;
if (toolComponent.tool) {
if ('tool' in toolComponent) {
// We still can't call the hook here dynamically
// This approach also won't work
}
@ -79,7 +79,7 @@ export const AutomationExecutor: React.FC<AutomationExecutorProps> = ({
}
const toolComponent = tool.component as ToolComponent;
if (!toolComponent.tool) {
if (!('tool' in toolComponent)) {
throw new Error(`Tool ${operation.operation} does not support automation`);
}

View File

@ -44,7 +44,7 @@ export default function AutomationSelection({
key={automation.id}
title={automation.name}
badgeIcon={SettingsIcon}
operations={automation.operations.map(op => typeof op === 'string' ? op : op.operation)}
operations={automation.operations.map((op: any) => typeof op === 'string' ? op : op.operation)}
onClick={() => onRun(automation)}
showMenu={true}
onEdit={() => onEdit(automation)}

View File

@ -229,14 +229,12 @@ export function useToolWorkflow(): ToolWorkflowContextValue {
// Return minimal safe fallback to prevent crashes
return {
state: {
sidebarsVisible: true,
leftPanelView: 'toolPicker',
readerMode: false,
previewFile: null,
pageEditorFunctions: null,
searchQuery: ''
},
sidebarsVisible: true,
leftPanelView: 'toolPicker',
readerMode: false,
previewFile: null,
pageEditorFunctions: null,
searchQuery: '',
selectedToolKey: null,
selectedTool: null,
toolRegistry: {},

View File

@ -46,3 +46,4 @@ export const useAddWatermarkParameters = (): AddWatermarkParametersHook => {
},
});
};

View File

@ -49,7 +49,7 @@ export const useAutomationExecution = () => {
// Initialize operation hooks for all tools in the automation
const hooks: Record<string, any> = {};
steps.forEach((step) => {
steps.forEach((step: ExecutionStep) => {
const tool = toolRegistry[step.operation];
if (tool?.component) {
const toolComponent = tool.component as ToolComponent;

View File

@ -4,8 +4,6 @@ import StarIcon from '@mui/icons-material/Star';
export interface SuggestedAutomation {
id: string;
name: string;
description: string;
operations: string[];
icon: React.ComponentType<any>;
}
@ -16,22 +14,16 @@ export function useSuggestedAutomations(): SuggestedAutomation[] {
const suggestedAutomations = useMemo<SuggestedAutomation[]>(() => [
{
id: "compress-and-merge",
name: t("automate.suggested.compressAndMerge.name", "Compress & Merge"),
description: t("automate.suggested.compressAndMerge.description", "Compress multiple PDFs then merge them into one"),
operations: ["compress", "merge"],
icon: StarIcon,
},
{
id: "ocr-and-convert",
name: t("automate.suggested.ocrAndConvert.name", "OCR & Convert"),
description: t("automate.suggested.ocrAndConvert.description", "Apply OCR to PDFs then convert to different format"),
operations: ["ocr", "convert"],
icon: StarIcon,
},
{
id: "secure-workflow",
name: t("automate.suggested.secureWorkflow.name", "Secure Workflow"),
description: t("automate.suggested.secureWorkflow.description", "Sanitize, add password, and set permissions"),
operations: ["sanitize", "addPassword", "changePermissions"],
icon: StarIcon,
},

View File

@ -4,7 +4,7 @@ import { useFileContext } from "../contexts/FileContext";
import { useToolFileSelection } from "../contexts/FileSelectionContext";
import { createToolFlow } from "../components/tools/shared/createToolFlow";
import { createFilesToolStep } from "../components/tools/shared/filesToolStep";
import { createFilesToolStep } from "../components/tools/shared/FilesToolStep";
import AutomationSelection from "../components/tools/automate/AutomationSelection";
import AutomationCreation, { AutomationMode } from "../components/tools/automate/AutomationCreation";
import AutomationRun from "../components/tools/automate/AutomationRun";
@ -133,7 +133,7 @@ const Automate = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
},
steps: automationSteps,
review: {
isVisible: true,
isVisible: hasResults,
operation: automateOperation,
title: t('automate.reviewTitle', 'Automation Results')
}

View File

@ -1,4 +1,4 @@
import React, { useEffect } from "react";
import React, { use, useEffect } from "react";
import { useTranslation } from "react-i18next";
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
import { useFileContext } from "../contexts/FileContext";
@ -8,7 +8,7 @@ import { createToolFlow } from "../components/tools/shared/createToolFlow";
import CompressSettings from "../components/tools/compress/CompressSettings";
import { useCompressParameters, initialParameters } from "../hooks/tools/compress/useCompressParameters";
import { useCompressParameters } from "../hooks/tools/compress/useCompressParameters";
import { useCompressOperation } from "../hooks/tools/compress/useCompressOperation";
import { BaseToolProps, ToolComponent } from "../types/tool";
import { useCompressTips } from "../components/tooltips/useCompressTips";
@ -99,8 +99,6 @@ const Compress = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
Compress.tool = () => useCompressOperation;
// Static method to get default parameters for automation
Compress.getDefaultParameters = () => {
return initialParameters;
};
Compress.getDefaultParameters = () => useCompressParameters();
export default Compress as ToolComponent;