From 510e1c38eb6a86443ae079295ce200ca533e1e00 Mon Sep 17 00:00:00 2001 From: ConnorYoh <40631091+ConnorYoh@users.noreply.github.com> Date: Wed, 1 Oct 2025 23:13:54 +0100 Subject: [PATCH] Fix/v2/automate_settings_gap_fill (#4574) All implemented tools now support automation bar Sign. Sign will need custom automation UI support --------- Co-authored-by: Connor Yoh Co-authored-by: Reece Browne <74901996+reecebrowne@users.noreply.github.com> --- .../public/locales/en-GB/translation.json | 1 + .../addAttachments/AddAttachmentsSettings.tsx | 119 ++++++++ .../AddPageNumbersAppearanceSettings.tsx | 77 ++++++ .../AddPageNumbersAutomationSettings.tsx | 55 ++++ .../AddPageNumbersPositionSettings.tsx | 70 +++++ .../addStamp/AddStampAutomationSettings.tsx | 43 +++ .../StampPositionFormattingSettings.tsx | 201 ++++++++++++++ .../tools/addStamp/StampSetupSettings.tsx | 112 ++++++++ .../tools/automate/ToolConfigurationModal.tsx | 4 +- .../components/tools/automate/ToolList.tsx | 5 +- .../tools/automate/ToolSelector.tsx | 8 +- .../certSign/CertSignAutomationSettings.tsx | 60 ++++ .../tools/crop/CropAutomationSettings.tsx | 41 +++ .../tools/crop/CropCoordinateInputs.tsx | 101 +++++++ .../components/tools/crop/CropSettings.tsx | 82 ++---- .../tools/removePages/RemovePagesSettings.tsx | 7 +- .../tools/rotate/RotateAutomationSettings.tsx | 43 +++ .../tools/split/SplitAutomationSettings.tsx | 62 +++++ frontend/src/data/toolsTaxonomy.ts | 17 +- .../src/data/useTranslatedToolRegistry.tsx | 130 ++++++--- .../hooks/tools/automate/useAutomationForm.ts | 14 +- .../tools/automate/useSuggestedAutomations.ts | 7 +- frontend/src/hooks/useToolNavigation.ts | 2 +- frontend/src/tools/AddAttachments.tsx | 102 +------ frontend/src/tools/AddPageNumbers.tsx | 105 +------ frontend/src/tools/AddStamp.tsx | 257 ++---------------- frontend/src/utils/automationExecutor.ts | 233 +++++++++------- frontend/src/utils/urlRouting.ts | 20 +- 28 files changed, 1300 insertions(+), 678 deletions(-) create mode 100644 frontend/src/components/tools/addAttachments/AddAttachmentsSettings.tsx create mode 100644 frontend/src/components/tools/addPageNumbers/AddPageNumbersAppearanceSettings.tsx create mode 100644 frontend/src/components/tools/addPageNumbers/AddPageNumbersAutomationSettings.tsx create mode 100644 frontend/src/components/tools/addPageNumbers/AddPageNumbersPositionSettings.tsx create mode 100644 frontend/src/components/tools/addStamp/AddStampAutomationSettings.tsx create mode 100644 frontend/src/components/tools/addStamp/StampPositionFormattingSettings.tsx create mode 100644 frontend/src/components/tools/addStamp/StampSetupSettings.tsx create mode 100644 frontend/src/components/tools/certSign/CertSignAutomationSettings.tsx create mode 100644 frontend/src/components/tools/crop/CropAutomationSettings.tsx create mode 100644 frontend/src/components/tools/crop/CropCoordinateInputs.tsx create mode 100644 frontend/src/components/tools/rotate/RotateAutomationSettings.tsx create mode 100644 frontend/src/components/tools/split/SplitAutomationSettings.tsx diff --git a/frontend/public/locales/en-GB/translation.json b/frontend/public/locales/en-GB/translation.json index c6e7a95a6..45d36a371 100644 --- a/frontend/public/locales/en-GB/translation.json +++ b/frontend/public/locales/en-GB/translation.json @@ -884,6 +884,7 @@ "rotate": { "title": "Rotate PDF", "submit": "Apply Rotation", + "selectRotation": "Select Rotation Angle (Clockwise)", "error": { "failed": "An error occurred while rotating the PDF." }, diff --git a/frontend/src/components/tools/addAttachments/AddAttachmentsSettings.tsx b/frontend/src/components/tools/addAttachments/AddAttachmentsSettings.tsx new file mode 100644 index 000000000..632ed71f1 --- /dev/null +++ b/frontend/src/components/tools/addAttachments/AddAttachmentsSettings.tsx @@ -0,0 +1,119 @@ +/** + * AddAttachmentsSettings - Shared settings component for both tool UI and automation + * + * Allows selecting files to attach to PDFs. + */ + +import { Stack, Text, Group, ActionIcon, Alert, ScrollArea, Button } from "@mantine/core"; +import { useTranslation } from "react-i18next"; +import { AddAttachmentsParameters } from "../../../hooks/tools/addAttachments/useAddAttachmentsParameters"; +import LocalIcon from "../../shared/LocalIcon"; + +interface AddAttachmentsSettingsProps { + parameters: AddAttachmentsParameters; + onParameterChange: (key: K, value: AddAttachmentsParameters[K]) => void; + disabled?: boolean; +} + +const AddAttachmentsSettings = ({ parameters, onParameterChange, disabled = false }: AddAttachmentsSettingsProps) => { + const { t } = useTranslation(); + + return ( + + + + {t("AddAttachmentsRequest.info", "Select files to attach to your PDF. These files will be embedded and accessible through the PDF's attachment panel.")} + + + + + + {t("AddAttachmentsRequest.selectFiles", "Select Files to Attach")} + + { + const files = Array.from(e.target.files || []); + // Append to existing attachments instead of replacing + const newAttachments = [...(parameters.attachments || []), ...files]; + onParameterChange('attachments', newAttachments); + // Reset the input so the same file can be selected again + e.target.value = ''; + }} + disabled={disabled} + style={{ display: 'none' }} + id="attachments-input" + /> + + + + {parameters.attachments?.length > 0 && ( + + + {t("AddAttachmentsRequest.selectedFiles", "Selected Files")} ({parameters.attachments.length}) + + + + {parameters.attachments.map((file, index) => ( + + + {/* Filename (two-line clamp, wraps, no icon on the left) */} +
+
+ {file.name} +
+
+ + ({(file.size / 1024).toFixed(1)} KB) + +
+ { + const newAttachments = (parameters.attachments || []).filter((_, i) => i !== index); + onParameterChange('attachments', newAttachments); + }} + disabled={disabled} + > + + +
+ ))} +
+
+
+ )} +
+ ); +}; + +export default AddAttachmentsSettings; diff --git a/frontend/src/components/tools/addPageNumbers/AddPageNumbersAppearanceSettings.tsx b/frontend/src/components/tools/addPageNumbers/AddPageNumbersAppearanceSettings.tsx new file mode 100644 index 000000000..0b7ecb02e --- /dev/null +++ b/frontend/src/components/tools/addPageNumbers/AddPageNumbersAppearanceSettings.tsx @@ -0,0 +1,77 @@ +/** + * AddPageNumbersAppearanceSettings - Customize Appearance step + */ + +import { Stack, Select, TextInput, NumberInput } from "@mantine/core"; +import { useTranslation } from "react-i18next"; +import { AddPageNumbersParameters } from "./useAddPageNumbersParameters"; +import { Tooltip } from "../../shared/Tooltip"; + +interface AddPageNumbersAppearanceSettingsProps { + parameters: AddPageNumbersParameters; + onParameterChange: (key: K, value: AddPageNumbersParameters[K]) => void; + disabled?: boolean; +} + +const AddPageNumbersAppearanceSettings = ({ + parameters, + onParameterChange, + disabled = false +}: AddPageNumbersAppearanceSettingsProps) => { + const { t } = useTranslation(); + + return ( + + + onParameterChange('fontType', (v as any) || 'Times')} + data={[ + { value: 'Times', label: 'Times Roman' }, + { value: 'Helvetica', label: 'Helvetica' }, + { value: 'Courier', label: 'Courier New' }, + ]} + disabled={disabled} + /> + + + + onParameterChange('customText', e.currentTarget.value)} + placeholder={t('addPageNumbers.customNumberDesc', 'e.g., "Page {n}" or leave blank for just numbers')} + disabled={disabled} + /> + + + ); +}; + +export default AddPageNumbersAppearanceSettings; diff --git a/frontend/src/components/tools/addPageNumbers/AddPageNumbersAutomationSettings.tsx b/frontend/src/components/tools/addPageNumbers/AddPageNumbersAutomationSettings.tsx new file mode 100644 index 000000000..86888d0e4 --- /dev/null +++ b/frontend/src/components/tools/addPageNumbers/AddPageNumbersAutomationSettings.tsx @@ -0,0 +1,55 @@ +/** + * AddPageNumbersAutomationSettings - Used for automation only + * + * Combines both position and appearance settings into a single view + */ + +import { Stack, Divider, Text } from "@mantine/core"; +import { useTranslation } from "react-i18next"; +import { AddPageNumbersParameters } from "./useAddPageNumbersParameters"; +import AddPageNumbersPositionSettings from "./AddPageNumbersPositionSettings"; +import AddPageNumbersAppearanceSettings from "./AddPageNumbersAppearanceSettings"; + +interface AddPageNumbersAutomationSettingsProps { + parameters: AddPageNumbersParameters; + onParameterChange: (key: K, value: AddPageNumbersParameters[K]) => void; + disabled?: boolean; +} + +const AddPageNumbersAutomationSettings = ({ + parameters, + onParameterChange, + disabled = false +}: AddPageNumbersAutomationSettingsProps) => { + const { t } = useTranslation(); + + return ( + + {/* Position & Pages Section */} + + {t("addPageNumbers.positionAndPages", "Position & Pages")} + + + + + + {/* Appearance Section */} + + {t("addPageNumbers.customize", "Customize Appearance")} + + + + ); +}; + +export default AddPageNumbersAutomationSettings; diff --git a/frontend/src/components/tools/addPageNumbers/AddPageNumbersPositionSettings.tsx b/frontend/src/components/tools/addPageNumbers/AddPageNumbersPositionSettings.tsx new file mode 100644 index 000000000..be79f4e46 --- /dev/null +++ b/frontend/src/components/tools/addPageNumbers/AddPageNumbersPositionSettings.tsx @@ -0,0 +1,70 @@ +/** + * AddPageNumbersPositionSettings - Position & Pages step + */ + +import { Stack, TextInput, NumberInput, Divider, Text } from "@mantine/core"; +import { useTranslation } from "react-i18next"; +import { AddPageNumbersParameters } from "./useAddPageNumbersParameters"; +import { Tooltip } from "../../shared/Tooltip"; +import PageNumberPreview from "./PageNumberPreview"; + +interface AddPageNumbersPositionSettingsProps { + parameters: AddPageNumbersParameters; + onParameterChange: (key: K, value: AddPageNumbersParameters[K]) => void; + disabled?: boolean; + file?: File | null; + showQuickGrid?: boolean; +} + +const AddPageNumbersPositionSettings = ({ + parameters, + onParameterChange, + disabled = false, + file = null, + showQuickGrid = true +}: AddPageNumbersPositionSettingsProps) => { + const { t } = useTranslation(); + + return ( + + {/* Position Selection */} + + + + + + + {/* Pages & Starting Number Section */} + + {t('addPageNumbers.pagesAndStarting', 'Pages & Starting Number')} + + + onParameterChange('pagesToNumber', e.currentTarget.value)} + placeholder={t('addPageNumbers.numberPagesDesc', 'e.g., 1,3,5-8 or leave blank for all pages')} + disabled={disabled} + /> + + + + onParameterChange('startingNumber', typeof v === 'number' ? v : 1)} + min={1} + disabled={disabled} + /> + + + + ); +}; + +export default AddPageNumbersPositionSettings; diff --git a/frontend/src/components/tools/addStamp/AddStampAutomationSettings.tsx b/frontend/src/components/tools/addStamp/AddStampAutomationSettings.tsx new file mode 100644 index 000000000..25091d854 --- /dev/null +++ b/frontend/src/components/tools/addStamp/AddStampAutomationSettings.tsx @@ -0,0 +1,43 @@ +/** + * AddStampAutomationSettings - Used for automation only + * + * This component combines all stamp settings into a single step interface + * for use in the automation system. It includes setup and formatting + * settings in one unified component. + */ + +import { Stack } from "@mantine/core"; +import { AddStampParameters } from "./useAddStampParameters"; +import StampSetupSettings from "./StampSetupSettings"; +import StampPositionFormattingSettings from "./StampPositionFormattingSettings"; + +interface AddStampAutomationSettingsProps { + parameters: AddStampParameters; + onParameterChange: (key: K, value: AddStampParameters[K]) => void; + disabled?: boolean; +} + +const AddStampAutomationSettings = ({ parameters, onParameterChange, disabled = false }: AddStampAutomationSettingsProps) => { + return ( + + {/* Stamp Setup (Type, Text/Image, Page Selection) */} + + + {/* Position and Formatting Settings */} + {parameters.stampType && ( + + )} + + ); +}; + +export default AddStampAutomationSettings; diff --git a/frontend/src/components/tools/addStamp/StampPositionFormattingSettings.tsx b/frontend/src/components/tools/addStamp/StampPositionFormattingSettings.tsx new file mode 100644 index 000000000..d1c0d0c9f --- /dev/null +++ b/frontend/src/components/tools/addStamp/StampPositionFormattingSettings.tsx @@ -0,0 +1,201 @@ +import { useTranslation } from "react-i18next"; +import { Group, Select, Stack, ColorInput, Button, Slider, Text, NumberInput } from "@mantine/core"; +import { AddStampParameters } from "./useAddStampParameters"; +import LocalIcon from "../../shared/LocalIcon"; +import styles from "./StampPreview.module.css"; +import { Tooltip } from "../../shared/Tooltip"; + +interface StampPositionFormattingSettingsProps { + parameters: AddStampParameters; + onParameterChange: (key: K, value: AddStampParameters[K]) => void; + disabled?: boolean; + showPositionGrid?: boolean; // When true, show the 9-position grid for automation +} + +const StampPositionFormattingSettings = ({ parameters, onParameterChange, disabled = false, showPositionGrid = false }: StampPositionFormattingSettingsProps) => { + const { t } = useTranslation(); + + return ( + + {/* Position Grid - shown in automation settings */} + {showPositionGrid && ( + + {t('AddStampRequest.position', 'Stamp Position')} +
+ {Array.from({ length: 9 }).map((_, i) => { + const idx = (i + 1) as 1|2|3|4|5|6|7|8|9; + const selected = parameters.position === idx; + return ( + + ); + })} +
+
+ )} + {/* Icon pill buttons row */} +
+ + + + + + + + + +
+ + {/* Single slider bound to selected pill */} + {parameters._activePill === 'fontSize' && ( + + + {parameters.stampType === 'image' + ? t('AddStampRequest.imageSize', 'Image Size') + : t('AddStampRequest.fontSize', 'Font Size') + } + + + onParameterChange('fontSize', typeof v === 'number' ? v : 1)} + min={1} + max={400} + step={1} + size="sm" + className={styles.numberInput} + disabled={disabled} + /> + onParameterChange('fontSize', v as number)} + min={1} + max={400} + step={1} + className={styles.slider} + /> + + + )} + {parameters._activePill === 'rotation' && ( + + {t('AddStampRequest.rotation', 'Rotation')} + + onParameterChange('rotation', typeof v === 'number' ? v : 0)} + min={-180} + max={180} + step={1} + size="sm" + className={styles.numberInput} + hideControls + disabled={disabled} + /> + onParameterChange('rotation', v as number)} + min={-180} + max={180} + step={1} + className={styles.sliderWide} + /> + + + )} + {parameters._activePill === 'opacity' && ( + + {t('AddStampRequest.opacity', 'Opacity')} + + onParameterChange('opacity', typeof v === 'number' ? v : 0)} + min={0} + max={100} + step={1} + size="sm" + className={styles.numberInput} + disabled={disabled} + /> + onParameterChange('opacity', v as number)} + min={0} + max={100} + step={1} + className={styles.slider} + /> + + + )} + + {parameters.stampType !== 'image' && ( + onParameterChange('customColor', value)} + format="hex" + disabled={disabled} + /> + )} + + {/* Margin selection for text stamps */} + {parameters.stampType === 'text' && ( +