mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-16 19:33:11 +02:00
V2 flatten (#4358)
# Description of Changes <!-- Please provide a summary of the changes, including: - What was changed - Why the change was made - Any challenges encountered Closes #(issue_number) --> --- ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing) for more details. --------- Co-authored-by: James Brunton <[email protected]> Co-authored-by: ConnorYoh <[email protected]>
This commit is contained in:
co-authored by
James Brunton
ConnorYoh
parent
bd13f6bf57
commit
da359d329d
@@ -1305,7 +1305,48 @@
|
||||
"title": "Flatten",
|
||||
"header": "Flatten PDF",
|
||||
"flattenOnlyForms": "Flatten only forms",
|
||||
"submit": "Flatten"
|
||||
"submit": "Flatten",
|
||||
"filenamePrefix": "flattened",
|
||||
"files": {
|
||||
"placeholder": "Select a PDF file in the main view to get started"
|
||||
},
|
||||
"steps": {
|
||||
"settings": "Settings"
|
||||
},
|
||||
"options": {
|
||||
"stepTitle": "Flatten Options",
|
||||
"title": "Flatten Options",
|
||||
"flattenOnlyForms": "Flatten only forms",
|
||||
"flattenOnlyForms.desc": "Only flatten form fields, leaving other interactive elements intact",
|
||||
"note": "Flattening removes interactive elements from the PDF, making them non-editable."
|
||||
},
|
||||
"results": {
|
||||
"title": "Flatten Results"
|
||||
},
|
||||
"error": {
|
||||
"failed": "An error occurred while flattening the PDF."
|
||||
},
|
||||
"tooltip": {
|
||||
"header": {
|
||||
"title": "About Flattening PDFs"
|
||||
},
|
||||
"description": {
|
||||
"title": "What does flattening do?",
|
||||
"text": "Flattening makes your PDF non-editable by turning fillable forms and buttons into regular text and images. The PDF will look exactly the same, but no one can change or fill in the forms anymore. Perfect for sharing completed forms, creating final documents for records, or ensuring the PDF looks the same everywhere.",
|
||||
"bullet1": "Text boxes become regular text (can't be edited)",
|
||||
"bullet2": "Checkboxes and buttons become pictures",
|
||||
"bullet3": "Great for final versions you don't want changed",
|
||||
"bullet4": "Ensures consistent appearance across all devices"
|
||||
},
|
||||
"formsOnly": {
|
||||
"title": "What does 'Flatten only forms' mean?",
|
||||
"text": "This option only removes the ability to fill in forms, but keeps other features working like clicking links, viewing bookmarks, and reading comments.",
|
||||
"bullet1": "Forms become non-editable",
|
||||
"bullet2": "Links still work when clicked",
|
||||
"bullet3": "Comments and notes remain visible",
|
||||
"bullet4": "Bookmarks still help you navigate"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repair": {
|
||||
"tags": "fix,restore,correction,recover",
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Stack, Text, Checkbox } from "@mantine/core";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { FlattenParameters } from "../../../hooks/tools/flatten/useFlattenParameters";
|
||||
|
||||
interface FlattenSettingsProps {
|
||||
parameters: FlattenParameters;
|
||||
onParameterChange: <K extends keyof FlattenParameters>(key: K, value: FlattenParameters[K]) => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
const FlattenSettings = ({ parameters, onParameterChange, disabled = false }: FlattenSettingsProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Stack gap="md">
|
||||
<Stack gap="sm">
|
||||
<Checkbox
|
||||
checked={parameters.flattenOnlyForms}
|
||||
onChange={(event) => onParameterChange('flattenOnlyForms', event.currentTarget.checked)}
|
||||
disabled={disabled}
|
||||
label={
|
||||
<div>
|
||||
<Text size="sm">{t('flatten.options.flattenOnlyForms', 'Flatten only forms')}</Text>
|
||||
<Text size="xs" c="dimmed">
|
||||
{t('flatten.options.flattenOnlyForms.desc', 'Only flatten form fields, leaving other interactive elements intact')}
|
||||
</Text>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default FlattenSettings;
|
||||
@@ -0,0 +1,34 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { TooltipContent } from '../../types/tips';
|
||||
|
||||
export const useFlattenTips = (): TooltipContent => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return {
|
||||
header: {
|
||||
title: t("flatten.tooltip.header.title", "About Flattening PDFs")
|
||||
},
|
||||
tips: [
|
||||
{
|
||||
title: t("flatten.tooltip.description.title", "What does flattening do?"),
|
||||
description: t("flatten.tooltip.description.text", "Flattening makes your PDF non-editable by turning fillable forms and buttons into regular text and images. The PDF will look exactly the same, but no one can change or fill in the forms anymore. Perfect for sharing completed forms, creating final documents for records, or ensuring the PDF looks the same everywhere."),
|
||||
bullets: [
|
||||
t("flatten.tooltip.description.bullet1", "Text boxes become regular text (can't be edited)"),
|
||||
t("flatten.tooltip.description.bullet2", "Checkboxes and buttons become pictures"),
|
||||
t("flatten.tooltip.description.bullet3", "Great for final versions you don't want changed"),
|
||||
t("flatten.tooltip.description.bullet4", "Ensures consistent appearance across all devices")
|
||||
]
|
||||
},
|
||||
{
|
||||
title: t("flatten.tooltip.formsOnly.title", "What does 'Flatten only forms' mean?"),
|
||||
description: t("flatten.tooltip.formsOnly.text", "This option only removes the ability to fill in forms, but keeps other features working like clicking links, viewing bookmarks, and reading comments."),
|
||||
bullets: [
|
||||
t("flatten.tooltip.formsOnly.bullet1", "Forms become non-editable"),
|
||||
t("flatten.tooltip.formsOnly.bullet2", "Links still work when clicked"),
|
||||
t("flatten.tooltip.formsOnly.bullet3", "Comments and notes remain visible"),
|
||||
t("flatten.tooltip.formsOnly.bullet4", "Bookmarks still help you navigate")
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
};
|
||||
@@ -15,6 +15,7 @@ import Repair from "../tools/Repair";
|
||||
import SingleLargePage from "../tools/SingleLargePage";
|
||||
import UnlockPdfForms from "../tools/UnlockPdfForms";
|
||||
import RemoveCertificateSign from "../tools/RemoveCertificateSign";
|
||||
import Flatten from "../tools/Flatten";
|
||||
import { compressOperationConfig } from "../hooks/tools/compress/useCompressOperation";
|
||||
import { splitOperationConfig } from "../hooks/tools/split/useSplitOperation";
|
||||
import { addPasswordOperationConfig } from "../hooks/tools/addPassword/useAddPasswordOperation";
|
||||
@@ -28,6 +29,7 @@ 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 { flattenOperationConfig } from "../hooks/tools/flatten/useFlattenOperation";
|
||||
import CompressSettings from "../components/tools/compress/CompressSettings";
|
||||
import SplitSettings from "../components/tools/split/SplitSettings";
|
||||
import AddPasswordSettings from "../components/tools/addPassword/AddPasswordSettings";
|
||||
@@ -39,6 +41,7 @@ import AddWatermarkSingleStepSettings from "../components/tools/addWatermark/Add
|
||||
import OCRSettings from "../components/tools/ocr/OCRSettings";
|
||||
import ConvertSettings from "../components/tools/convert/ConvertSettings";
|
||||
import ChangePermissionsSettings from "../components/tools/changePermissions/ChangePermissionsSettings";
|
||||
import FlattenSettings from "../components/tools/flatten/FlattenSettings";
|
||||
import { ToolId } from "../types/toolId";
|
||||
|
||||
const showPlaceholderTools = true; // Show all tools; grey out unavailable ones in UI
|
||||
@@ -198,10 +201,14 @@ export function useFlatToolRegistry(): ToolRegistry {
|
||||
flatten: {
|
||||
icon: <LocalIcon icon="layers-clear-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.flatten.title", "Flatten"),
|
||||
component: null,
|
||||
component: Flatten,
|
||||
description: t("home.flatten.desc", "Remove all interactive elements and forms from a PDF"),
|
||||
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||
subcategoryId: SubcategoryId.DOCUMENT_SECURITY,
|
||||
maxFiles: -1,
|
||||
endpoints: ["flatten"],
|
||||
operationConfig: flattenOperationConfig,
|
||||
settingsComponent: FlattenSettings,
|
||||
},
|
||||
"unlock-pdf-forms": {
|
||||
icon: <LocalIcon icon="preview-off-rounded" width="1.5rem" height="1.5rem" />,
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ToolType, useToolOperation } from '../shared/useToolOperation';
|
||||
import { createStandardErrorHandler } from '../../../utils/toolErrorHandler';
|
||||
import { FlattenParameters, defaultParameters } from './useFlattenParameters';
|
||||
|
||||
// Static function that can be used by both the hook and automation executor
|
||||
export const buildFlattenFormData = (parameters: FlattenParameters, file: File): FormData => {
|
||||
const formData = new FormData();
|
||||
formData.append('fileInput', file);
|
||||
formData.append('flattenOnlyForms', parameters.flattenOnlyForms.toString());
|
||||
return formData;
|
||||
};
|
||||
|
||||
// Static configuration object
|
||||
export const flattenOperationConfig = {
|
||||
toolType: ToolType.singleFile,
|
||||
buildFormData: buildFlattenFormData,
|
||||
operationType: 'flatten',
|
||||
endpoint: '/api/v1/misc/flatten',
|
||||
filePrefix: 'flattened_', // Will be overridden in hook with translation
|
||||
multiFileEndpoint: false,
|
||||
defaultParameters,
|
||||
} as const;
|
||||
|
||||
export const useFlattenOperation = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return useToolOperation<FlattenParameters>({
|
||||
...flattenOperationConfig,
|
||||
filePrefix: t('flatten.filenamePrefix', 'flattened') + '_',
|
||||
getErrorMessage: createStandardErrorHandler(t('flatten.error.failed', 'An error occurred while flattening the PDF.'))
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
import { BaseParameters } from '../../../types/parameters';
|
||||
import { useBaseParameters, BaseParametersHook } from '../shared/useBaseParameters';
|
||||
|
||||
export interface FlattenParameters extends BaseParameters {
|
||||
flattenOnlyForms: boolean;
|
||||
}
|
||||
|
||||
export const defaultParameters: FlattenParameters = {
|
||||
flattenOnlyForms: false,
|
||||
};
|
||||
|
||||
export type FlattenParametersHook = BaseParametersHook<FlattenParameters>;
|
||||
|
||||
export const useFlattenParameters = (): FlattenParametersHook => {
|
||||
return useBaseParameters({
|
||||
defaultParameters,
|
||||
endpointName: 'flatten',
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,62 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
||||
import FlattenSettings from "../components/tools/flatten/FlattenSettings";
|
||||
import { useFlattenParameters } from "../hooks/tools/flatten/useFlattenParameters";
|
||||
import { useFlattenOperation } from "../hooks/tools/flatten/useFlattenOperation";
|
||||
import { useBaseTool } from "../hooks/tools/shared/useBaseTool";
|
||||
import { useFlattenTips } from "../components/tooltips/useFlattenTips";
|
||||
import { BaseToolProps, ToolComponent } from "../types/tool";
|
||||
|
||||
const Flatten = (props: BaseToolProps) => {
|
||||
const { t } = useTranslation();
|
||||
const flattenTips = useFlattenTips();
|
||||
|
||||
const base = useBaseTool(
|
||||
'flatten',
|
||||
useFlattenParameters,
|
||||
useFlattenOperation,
|
||||
props
|
||||
);
|
||||
|
||||
return createToolFlow({
|
||||
files: {
|
||||
selectedFiles: base.selectedFiles,
|
||||
isCollapsed: base.hasResults,
|
||||
placeholder: t("flatten.files.placeholder", "Select a PDF file in the main view to get started"),
|
||||
},
|
||||
steps: [
|
||||
{
|
||||
title: t("flatten.options.stepTitle", "Flatten Options"),
|
||||
isCollapsed: base.settingsCollapsed,
|
||||
onCollapsedClick: base.settingsCollapsed ? base.handleSettingsReset : undefined,
|
||||
tooltip: flattenTips,
|
||||
content: (
|
||||
<FlattenSettings
|
||||
parameters={base.params.parameters}
|
||||
onParameterChange={base.params.updateParameter}
|
||||
disabled={base.endpointLoading}
|
||||
/>
|
||||
),
|
||||
},
|
||||
],
|
||||
executeButton: {
|
||||
text: t("flatten.submit", "Flatten PDF"),
|
||||
isVisible: !base.hasResults,
|
||||
loadingText: t("loading"),
|
||||
onClick: base.handleExecute,
|
||||
disabled: !base.params.validateParameters() || !base.hasFiles || !base.endpointEnabled,
|
||||
},
|
||||
review: {
|
||||
isVisible: base.hasResults,
|
||||
operation: base.operation,
|
||||
title: t("flatten.results.title", "Flatten Results"),
|
||||
onFileClick: base.handleThumbnailClick,
|
||||
onUndo: base.handleUndo,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// Static method to get the operation hook for automation
|
||||
Flatten.tool = () => useFlattenOperation;
|
||||
|
||||
export default Flatten as ToolComponent;
|
||||
Reference in New Issue
Block a user