mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-08-29 15:49:22 +00:00
V2 reduce tool boilerplate (#4313)
# Description of Changes Reduce boilerplate in tool frontends by creating a base frontend hook for the simple tools to use. I've done all the simple tools here. It'd be nice to add in some of the more complex tools as well in the future if we can figure out how.
This commit is contained in:
parent
e142af2863
commit
442b373ff4
118
frontend/src/hooks/tools/shared/useBaseTool.ts
Normal file
118
frontend/src/hooks/tools/shared/useBaseTool.ts
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
import { useEffect, useCallback } from 'react';
|
||||||
|
import { useFileSelection } from '../../../contexts/FileContext';
|
||||||
|
import { useEndpointEnabled } from '../../useEndpointConfig';
|
||||||
|
import { BaseToolProps } from '../../../types/tool';
|
||||||
|
import { ToolOperationHook } from './useToolOperation';
|
||||||
|
import { BaseParametersHook } from './useBaseParameters';
|
||||||
|
|
||||||
|
interface BaseToolReturn<TParams> {
|
||||||
|
// File management
|
||||||
|
selectedFiles: File[];
|
||||||
|
|
||||||
|
// Tool-specific hooks
|
||||||
|
params: BaseParametersHook<TParams>;
|
||||||
|
operation: ToolOperationHook<TParams>;
|
||||||
|
|
||||||
|
// Endpoint validation
|
||||||
|
endpointEnabled: boolean | null;
|
||||||
|
endpointLoading: boolean;
|
||||||
|
|
||||||
|
// Standard handlers
|
||||||
|
handleExecute: () => Promise<void>;
|
||||||
|
handleThumbnailClick: (file: File) => void;
|
||||||
|
handleSettingsReset: () => void;
|
||||||
|
|
||||||
|
// Standard computed state
|
||||||
|
hasFiles: boolean;
|
||||||
|
hasResults: boolean;
|
||||||
|
settingsCollapsed: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base tool hook for tool components. Manages standard behaviour for tools.
|
||||||
|
*/
|
||||||
|
export function useBaseTool<TParams>(
|
||||||
|
toolName: string,
|
||||||
|
useParams: () => BaseParametersHook<TParams>,
|
||||||
|
useOperation: () => ToolOperationHook<TParams>,
|
||||||
|
props: BaseToolProps,
|
||||||
|
): BaseToolReturn<TParams> {
|
||||||
|
const { onPreviewFile, onComplete, onError } = props;
|
||||||
|
|
||||||
|
// File selection
|
||||||
|
const { selectedFiles } = useFileSelection();
|
||||||
|
|
||||||
|
// Tool-specific hooks
|
||||||
|
const params = useParams();
|
||||||
|
const operation = useOperation();
|
||||||
|
|
||||||
|
// Endpoint validation using parameters hook
|
||||||
|
const { enabled: endpointEnabled, loading: endpointLoading } = useEndpointEnabled(params.getEndpointName());
|
||||||
|
|
||||||
|
// Reset results when parameters change
|
||||||
|
useEffect(() => {
|
||||||
|
operation.resetResults();
|
||||||
|
onPreviewFile?.(null);
|
||||||
|
}, [params.parameters]);
|
||||||
|
|
||||||
|
// Reset results when selected files change
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedFiles.length > 0) {
|
||||||
|
operation.resetResults();
|
||||||
|
onPreviewFile?.(null);
|
||||||
|
}
|
||||||
|
}, [selectedFiles.length]);
|
||||||
|
|
||||||
|
// Standard handlers
|
||||||
|
const handleExecute = useCallback(async () => {
|
||||||
|
try {
|
||||||
|
await operation.executeOperation(params.parameters, selectedFiles);
|
||||||
|
if (operation.files && onComplete) {
|
||||||
|
onComplete(operation.files);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (onError) {
|
||||||
|
const message = error instanceof Error ? error.message : `${toolName} operation failed`;
|
||||||
|
onError(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [operation, params.parameters, selectedFiles, onComplete, onError, toolName]);
|
||||||
|
|
||||||
|
const handleThumbnailClick = useCallback((file: File) => {
|
||||||
|
onPreviewFile?.(file);
|
||||||
|
sessionStorage.setItem('previousMode', toolName);
|
||||||
|
}, [onPreviewFile, toolName]);
|
||||||
|
|
||||||
|
const handleSettingsReset = useCallback(() => {
|
||||||
|
operation.resetResults();
|
||||||
|
onPreviewFile?.(null);
|
||||||
|
}, [operation, onPreviewFile]);
|
||||||
|
|
||||||
|
// Standard computed state
|
||||||
|
const hasFiles = selectedFiles.length > 0;
|
||||||
|
const hasResults = operation.files.length > 0 || operation.downloadUrl !== null;
|
||||||
|
const settingsCollapsed = !hasFiles || hasResults;
|
||||||
|
|
||||||
|
return {
|
||||||
|
// File management
|
||||||
|
selectedFiles,
|
||||||
|
|
||||||
|
// Tool-specific hooks
|
||||||
|
params,
|
||||||
|
operation,
|
||||||
|
|
||||||
|
// Endpoint validation
|
||||||
|
endpointEnabled,
|
||||||
|
endpointLoading,
|
||||||
|
|
||||||
|
// Handlers
|
||||||
|
handleExecute,
|
||||||
|
handleThumbnailClick,
|
||||||
|
handleSettingsReset,
|
||||||
|
|
||||||
|
// State
|
||||||
|
hasFiles,
|
||||||
|
hasResults,
|
||||||
|
settingsCollapsed
|
||||||
|
};
|
||||||
|
}
|
@ -1,96 +1,55 @@
|
|||||||
import React, { useEffect } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
|
|
||||||
import { useFileSelection } from "../contexts/FileContext";
|
|
||||||
import { useNavigationActions } from "../contexts/NavigationContext";
|
|
||||||
|
|
||||||
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
||||||
|
|
||||||
import ChangePermissionsSettings from "../components/tools/changePermissions/ChangePermissionsSettings";
|
import ChangePermissionsSettings from "../components/tools/changePermissions/ChangePermissionsSettings";
|
||||||
|
|
||||||
import { useChangePermissionsParameters } from "../hooks/tools/changePermissions/useChangePermissionsParameters";
|
import { useChangePermissionsParameters } from "../hooks/tools/changePermissions/useChangePermissionsParameters";
|
||||||
import { useChangePermissionsOperation } from "../hooks/tools/changePermissions/useChangePermissionsOperation";
|
import { useChangePermissionsOperation } from "../hooks/tools/changePermissions/useChangePermissionsOperation";
|
||||||
import { useChangePermissionsTips } from "../components/tooltips/useChangePermissionsTips";
|
import { useChangePermissionsTips } from "../components/tooltips/useChangePermissionsTips";
|
||||||
|
import { useBaseTool } from "../hooks/tools/shared/useBaseTool";
|
||||||
import { BaseToolProps, ToolComponent } from "../types/tool";
|
import { BaseToolProps, ToolComponent } from "../types/tool";
|
||||||
|
|
||||||
const ChangePermissions = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
const ChangePermissions = (props: BaseToolProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { actions } = useNavigationActions();
|
|
||||||
const { selectedFiles } = useFileSelection();
|
|
||||||
|
|
||||||
const changePermissionsParams = useChangePermissionsParameters();
|
|
||||||
const changePermissionsOperation = useChangePermissionsOperation();
|
|
||||||
const changePermissionsTips = useChangePermissionsTips();
|
const changePermissionsTips = useChangePermissionsTips();
|
||||||
|
|
||||||
// Endpoint validation
|
const base = useBaseTool(
|
||||||
const { enabled: endpointEnabled, loading: endpointLoading } = useEndpointEnabled(changePermissionsParams.getEndpointName());
|
'changePermissions',
|
||||||
|
useChangePermissionsParameters,
|
||||||
useEffect(() => {
|
useChangePermissionsOperation,
|
||||||
changePermissionsOperation.resetResults();
|
props
|
||||||
onPreviewFile?.(null);
|
);
|
||||||
}, [changePermissionsParams.parameters]);
|
|
||||||
|
|
||||||
const handleChangePermissions = async () => {
|
|
||||||
try {
|
|
||||||
await changePermissionsOperation.executeOperation(changePermissionsParams.parameters, selectedFiles);
|
|
||||||
if (changePermissionsOperation.files && onComplete) {
|
|
||||||
onComplete(changePermissionsOperation.files);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
if (onError) {
|
|
||||||
onError(
|
|
||||||
error instanceof Error ? error.message : t("changePermissions.error.failed", "Change permissions operation failed")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleThumbnailClick = (file: File) => {
|
|
||||||
onPreviewFile?.(file);
|
|
||||||
sessionStorage.setItem("previousMode", "changePermissions");
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSettingsReset = () => {
|
|
||||||
changePermissionsOperation.resetResults();
|
|
||||||
onPreviewFile?.(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const hasFiles = selectedFiles.length > 0;
|
|
||||||
const hasResults = changePermissionsOperation.files.length > 0 || changePermissionsOperation.downloadUrl !== null;
|
|
||||||
const settingsCollapsed = !hasFiles || hasResults;
|
|
||||||
|
|
||||||
return createToolFlow({
|
return createToolFlow({
|
||||||
files: {
|
files: {
|
||||||
selectedFiles,
|
selectedFiles: base.selectedFiles,
|
||||||
isCollapsed: hasResults,
|
isCollapsed: base.hasResults,
|
||||||
},
|
},
|
||||||
steps: [
|
steps: [
|
||||||
{
|
{
|
||||||
title: t("changePermissions.title", "Document Permissions"),
|
title: t("changePermissions.title", "Document Permissions"),
|
||||||
isCollapsed: settingsCollapsed,
|
isCollapsed: base.settingsCollapsed,
|
||||||
onCollapsedClick: settingsCollapsed ? handleSettingsReset : undefined,
|
onCollapsedClick: base.settingsCollapsed ? base.handleSettingsReset : undefined,
|
||||||
tooltip: changePermissionsTips,
|
tooltip: changePermissionsTips,
|
||||||
content: (
|
content: (
|
||||||
<ChangePermissionsSettings
|
<ChangePermissionsSettings
|
||||||
parameters={changePermissionsParams.parameters}
|
parameters={base.params.parameters}
|
||||||
onParameterChange={changePermissionsParams.updateParameter}
|
onParameterChange={base.params.updateParameter}
|
||||||
disabled={endpointLoading}
|
disabled={base.endpointLoading}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
executeButton: {
|
executeButton: {
|
||||||
text: t("changePermissions.submit", "Change Permissions"),
|
text: t("changePermissions.submit", "Change Permissions"),
|
||||||
isVisible: !hasResults,
|
isVisible: !base.hasResults,
|
||||||
loadingText: t("loading"),
|
loadingText: t("loading"),
|
||||||
onClick: handleChangePermissions,
|
onClick: base.handleExecute,
|
||||||
disabled: !changePermissionsParams.validateParameters() || !hasFiles || !endpointEnabled,
|
disabled: !base.params.validateParameters() || !base.hasFiles || !base.endpointEnabled,
|
||||||
},
|
},
|
||||||
review: {
|
review: {
|
||||||
isVisible: hasResults,
|
isVisible: base.hasResults,
|
||||||
operation: changePermissionsOperation,
|
operation: base.operation,
|
||||||
title: t("changePermissions.results.title", "Modified PDFs"),
|
title: t("changePermissions.results.title", "Modified PDFs"),
|
||||||
onFileClick: handleThumbnailClick,
|
onFileClick: base.handleThumbnailClick,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,95 +1,55 @@
|
|||||||
import React, { use, useEffect } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
|
|
||||||
import { useFileSelection } from "../contexts/FileContext";
|
|
||||||
import { useNavigationActions } from "../contexts/NavigationContext";
|
|
||||||
|
|
||||||
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
||||||
|
|
||||||
import CompressSettings from "../components/tools/compress/CompressSettings";
|
import CompressSettings from "../components/tools/compress/CompressSettings";
|
||||||
|
|
||||||
import { useCompressParameters } from "../hooks/tools/compress/useCompressParameters";
|
import { useCompressParameters } from "../hooks/tools/compress/useCompressParameters";
|
||||||
import { useCompressOperation } from "../hooks/tools/compress/useCompressOperation";
|
import { useCompressOperation } from "../hooks/tools/compress/useCompressOperation";
|
||||||
|
import { useBaseTool } from "../hooks/tools/shared/useBaseTool";
|
||||||
import { BaseToolProps, ToolComponent } from "../types/tool";
|
import { BaseToolProps, ToolComponent } from "../types/tool";
|
||||||
import { useCompressTips } from "../components/tooltips/useCompressTips";
|
import { useCompressTips } from "../components/tooltips/useCompressTips";
|
||||||
|
|
||||||
const Compress = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
const Compress = (props: BaseToolProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { actions } = useNavigationActions();
|
|
||||||
const { selectedFiles } = useFileSelection();
|
|
||||||
|
|
||||||
const compressParams = useCompressParameters();
|
|
||||||
const compressOperation = useCompressOperation();
|
|
||||||
const compressTips = useCompressTips();
|
const compressTips = useCompressTips();
|
||||||
|
|
||||||
// Endpoint validation
|
const base = useBaseTool(
|
||||||
const { enabled: endpointEnabled, loading: endpointLoading } = useEndpointEnabled("compress-pdf");
|
'compress',
|
||||||
|
useCompressParameters,
|
||||||
useEffect(() => {
|
useCompressOperation,
|
||||||
compressOperation.resetResults();
|
props
|
||||||
onPreviewFile?.(null);
|
);
|
||||||
}, [compressParams.parameters]);
|
|
||||||
|
|
||||||
const handleCompress = async () => {
|
|
||||||
try {
|
|
||||||
await compressOperation.executeOperation(compressParams.parameters, selectedFiles);
|
|
||||||
if (compressOperation.files && onComplete) {
|
|
||||||
onComplete(compressOperation.files);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
if (onError) {
|
|
||||||
onError(error instanceof Error ? error.message : "Compress operation failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleThumbnailClick = (file: File) => {
|
|
||||||
onPreviewFile?.(file);
|
|
||||||
sessionStorage.setItem("previousMode", "compress");
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSettingsReset = () => {
|
|
||||||
compressOperation.resetResults();
|
|
||||||
onPreviewFile?.(null); };
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const hasFiles = selectedFiles.length > 0;
|
|
||||||
const hasResults = compressOperation.files.length > 0 || compressOperation.downloadUrl !== null;
|
|
||||||
const settingsCollapsed = !hasFiles || hasResults;
|
|
||||||
|
|
||||||
return createToolFlow({
|
return createToolFlow({
|
||||||
files: {
|
files: {
|
||||||
selectedFiles,
|
selectedFiles: base.selectedFiles,
|
||||||
isCollapsed: hasResults,
|
isCollapsed: base.hasResults,
|
||||||
},
|
},
|
||||||
steps: [
|
steps: [
|
||||||
{
|
{
|
||||||
title: "Settings",
|
title: "Settings",
|
||||||
isCollapsed: settingsCollapsed,
|
isCollapsed: base.settingsCollapsed,
|
||||||
onCollapsedClick: settingsCollapsed ? handleSettingsReset : undefined,
|
onCollapsedClick: base.settingsCollapsed ? base.handleSettingsReset : undefined,
|
||||||
tooltip: compressTips,
|
tooltip: compressTips,
|
||||||
content: (
|
content: (
|
||||||
<CompressSettings
|
<CompressSettings
|
||||||
parameters={compressParams.parameters}
|
parameters={base.params.parameters}
|
||||||
onParameterChange={compressParams.updateParameter}
|
onParameterChange={base.params.updateParameter}
|
||||||
disabled={endpointLoading}
|
disabled={base.endpointLoading}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
executeButton: {
|
executeButton: {
|
||||||
text: t("compress.submit", "Compress"),
|
text: t("compress.submit", "Compress"),
|
||||||
isVisible: !hasResults,
|
isVisible: !base.hasResults,
|
||||||
loadingText: t("loading"),
|
loadingText: t("loading"),
|
||||||
onClick: handleCompress,
|
onClick: base.handleExecute,
|
||||||
disabled: !compressParams.validateParameters() || !hasFiles || !endpointEnabled,
|
disabled: !base.params.validateParameters() || !base.hasFiles || !base.endpointEnabled,
|
||||||
},
|
},
|
||||||
review: {
|
review: {
|
||||||
isVisible: hasResults,
|
isVisible: base.hasResults,
|
||||||
operation: compressOperation,
|
operation: base.operation,
|
||||||
title: t("compress.title", "Compression Results"),
|
title: t("compress.title", "Compression Results"),
|
||||||
onFileClick: handleThumbnailClick,
|
onFileClick: base.handleThumbnailClick,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,78 +1,39 @@
|
|||||||
import React, { useEffect } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
|
|
||||||
import { useFileContext } from "../contexts/FileContext";
|
|
||||||
import { useNavigationActions } from "../contexts/NavigationContext";
|
|
||||||
import { useFileSelection } from "../contexts/file/fileHooks";
|
|
||||||
|
|
||||||
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
||||||
|
|
||||||
import { useRemoveCertificateSignParameters } from "../hooks/tools/removeCertificateSign/useRemoveCertificateSignParameters";
|
import { useRemoveCertificateSignParameters } from "../hooks/tools/removeCertificateSign/useRemoveCertificateSignParameters";
|
||||||
import { useRemoveCertificateSignOperation } from "../hooks/tools/removeCertificateSign/useRemoveCertificateSignOperation";
|
import { useRemoveCertificateSignOperation } from "../hooks/tools/removeCertificateSign/useRemoveCertificateSignOperation";
|
||||||
|
import { useBaseTool } from "../hooks/tools/shared/useBaseTool";
|
||||||
import { BaseToolProps, ToolComponent } from "../types/tool";
|
import { BaseToolProps, ToolComponent } from "../types/tool";
|
||||||
|
|
||||||
const RemoveCertificateSign = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
const RemoveCertificateSign = (props: BaseToolProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { actions } = useNavigationActions();
|
|
||||||
const { selectedFiles } = useFileSelection();
|
|
||||||
|
|
||||||
const removeCertificateSignParams = useRemoveCertificateSignParameters();
|
const base = useBaseTool(
|
||||||
const removeCertificateSignOperation = useRemoveCertificateSignOperation();
|
'removeCertificateSign',
|
||||||
|
useRemoveCertificateSignParameters,
|
||||||
// Endpoint validation
|
useRemoveCertificateSignOperation,
|
||||||
const { enabled: endpointEnabled, loading: endpointLoading } = useEndpointEnabled(removeCertificateSignParams.getEndpointName());
|
props
|
||||||
|
);
|
||||||
useEffect(() => {
|
|
||||||
removeCertificateSignOperation.resetResults();
|
|
||||||
onPreviewFile?.(null);
|
|
||||||
}, [removeCertificateSignParams.parameters]);
|
|
||||||
|
|
||||||
const handleRemoveSignature = async () => {
|
|
||||||
try {
|
|
||||||
await removeCertificateSignOperation.executeOperation(removeCertificateSignParams.parameters, selectedFiles);
|
|
||||||
if (removeCertificateSignOperation.files && onComplete) {
|
|
||||||
onComplete(removeCertificateSignOperation.files);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
if (onError) {
|
|
||||||
onError(error instanceof Error ? error.message : t("removeCertSign.error.failed", "Remove certificate signature operation failed"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleThumbnailClick = (file: File) => {
|
|
||||||
onPreviewFile?.(file);
|
|
||||||
sessionStorage.setItem("previousMode", "removeCertificateSign");
|
|
||||||
actions.setMode("viewer");
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSettingsReset = () => {
|
|
||||||
removeCertificateSignOperation.resetResults();
|
|
||||||
onPreviewFile?.(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const hasFiles = selectedFiles.length > 0;
|
|
||||||
const hasResults = removeCertificateSignOperation.files.length > 0 || removeCertificateSignOperation.downloadUrl !== null;
|
|
||||||
|
|
||||||
return createToolFlow({
|
return createToolFlow({
|
||||||
files: {
|
files: {
|
||||||
selectedFiles,
|
selectedFiles: base.selectedFiles,
|
||||||
isCollapsed: hasFiles || hasResults,
|
isCollapsed: base.hasResults,
|
||||||
placeholder: t("removeCertSign.files.placeholder", "Select a PDF file in the main view to get started"),
|
placeholder: t("removeCertSign.files.placeholder", "Select a PDF file in the main view to get started"),
|
||||||
},
|
},
|
||||||
steps: [],
|
steps: [],
|
||||||
executeButton: {
|
executeButton: {
|
||||||
text: t("removeCertSign.submit", "Remove Signature"),
|
text: t("removeCertSign.submit", "Remove Signature"),
|
||||||
isVisible: !hasResults,
|
isVisible: !base.hasResults,
|
||||||
loadingText: t("loading"),
|
loadingText: t("loading"),
|
||||||
onClick: handleRemoveSignature,
|
onClick: base.handleExecute,
|
||||||
disabled: !removeCertificateSignParams.validateParameters() || !hasFiles || !endpointEnabled,
|
disabled: !base.params.validateParameters() || !base.hasFiles || !base.endpointEnabled,
|
||||||
},
|
},
|
||||||
review: {
|
review: {
|
||||||
isVisible: hasResults,
|
isVisible: base.hasResults,
|
||||||
operation: removeCertificateSignOperation,
|
operation: base.operation,
|
||||||
title: t("removeCertSign.results.title", "Certificate Removal Results"),
|
title: t("removeCertSign.results.title", "Certificate Removal Results"),
|
||||||
onFileClick: handleThumbnailClick,
|
onFileClick: base.handleThumbnailClick,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,95 +1,55 @@
|
|||||||
import { useEffect } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
|
|
||||||
import { useFileSelection } from "../contexts/FileContext";
|
|
||||||
import { useNavigationActions } from "../contexts/NavigationContext";
|
|
||||||
|
|
||||||
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
||||||
|
|
||||||
import RemovePasswordSettings from "../components/tools/removePassword/RemovePasswordSettings";
|
import RemovePasswordSettings from "../components/tools/removePassword/RemovePasswordSettings";
|
||||||
|
|
||||||
import { useRemovePasswordParameters } from "../hooks/tools/removePassword/useRemovePasswordParameters";
|
import { useRemovePasswordParameters } from "../hooks/tools/removePassword/useRemovePasswordParameters";
|
||||||
import { useRemovePasswordOperation } from "../hooks/tools/removePassword/useRemovePasswordOperation";
|
import { useRemovePasswordOperation } from "../hooks/tools/removePassword/useRemovePasswordOperation";
|
||||||
import { useRemovePasswordTips } from "../components/tooltips/useRemovePasswordTips";
|
import { useRemovePasswordTips } from "../components/tooltips/useRemovePasswordTips";
|
||||||
|
import { useBaseTool } from "../hooks/tools/shared/useBaseTool";
|
||||||
import { BaseToolProps, ToolComponent } from "../types/tool";
|
import { BaseToolProps, ToolComponent } from "../types/tool";
|
||||||
|
|
||||||
const RemovePassword = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
const RemovePassword = (props: BaseToolProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { actions } = useNavigationActions();
|
|
||||||
const { selectedFiles } = useFileSelection();
|
|
||||||
|
|
||||||
const removePasswordParams = useRemovePasswordParameters();
|
|
||||||
const removePasswordOperation = useRemovePasswordOperation();
|
|
||||||
const removePasswordTips = useRemovePasswordTips();
|
const removePasswordTips = useRemovePasswordTips();
|
||||||
|
|
||||||
// Endpoint validation
|
const base = useBaseTool(
|
||||||
const { enabled: endpointEnabled, loading: endpointLoading } = useEndpointEnabled(removePasswordParams.getEndpointName());
|
'removePassword',
|
||||||
|
useRemovePasswordParameters,
|
||||||
|
useRemovePasswordOperation,
|
||||||
useEffect(() => {
|
props
|
||||||
removePasswordOperation.resetResults();
|
);
|
||||||
onPreviewFile?.(null);
|
|
||||||
}, [removePasswordParams.parameters]);
|
|
||||||
|
|
||||||
const handleRemovePassword = async () => {
|
|
||||||
try {
|
|
||||||
await removePasswordOperation.executeOperation(removePasswordParams.parameters, selectedFiles);
|
|
||||||
if (removePasswordOperation.files && onComplete) {
|
|
||||||
onComplete(removePasswordOperation.files);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
if (onError) {
|
|
||||||
onError(error instanceof Error ? error.message : t("removePassword.error.failed", "Remove password operation failed"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleThumbnailClick = (file: File) => {
|
|
||||||
onPreviewFile?.(file);
|
|
||||||
sessionStorage.setItem("previousMode", "removePassword");
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSettingsReset = () => {
|
|
||||||
removePasswordOperation.resetResults();
|
|
||||||
onPreviewFile?.(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const hasFiles = selectedFiles.length > 0;
|
|
||||||
const hasResults = removePasswordOperation.files.length > 0 || removePasswordOperation.downloadUrl !== null;
|
|
||||||
const passwordCollapsed = !hasFiles || hasResults;
|
|
||||||
|
|
||||||
return createToolFlow({
|
return createToolFlow({
|
||||||
files: {
|
files: {
|
||||||
selectedFiles,
|
selectedFiles: base.selectedFiles,
|
||||||
isCollapsed: hasResults,
|
isCollapsed: base.hasResults,
|
||||||
},
|
},
|
||||||
steps: [
|
steps: [
|
||||||
{
|
{
|
||||||
title: t("removePassword.password.stepTitle", "Remove Password"),
|
title: t("removePassword.password.stepTitle", "Remove Password"),
|
||||||
isCollapsed: passwordCollapsed,
|
isCollapsed: base.settingsCollapsed,
|
||||||
onCollapsedClick: hasResults ? handleSettingsReset : undefined,
|
onCollapsedClick: base.hasResults ? base.handleSettingsReset : undefined,
|
||||||
tooltip: removePasswordTips,
|
tooltip: removePasswordTips,
|
||||||
content: (
|
content: (
|
||||||
<RemovePasswordSettings
|
<RemovePasswordSettings
|
||||||
parameters={removePasswordParams.parameters}
|
parameters={base.params.parameters}
|
||||||
onParameterChange={removePasswordParams.updateParameter}
|
onParameterChange={base.params.updateParameter}
|
||||||
disabled={endpointLoading}
|
disabled={base.endpointLoading}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
executeButton: {
|
executeButton: {
|
||||||
text: t("removePassword.submit", "Remove Password"),
|
text: t("removePassword.submit", "Remove Password"),
|
||||||
isVisible: !hasResults,
|
isVisible: !base.hasResults,
|
||||||
loadingText: t("loading"),
|
loadingText: t("loading"),
|
||||||
onClick: handleRemovePassword,
|
onClick: base.handleExecute,
|
||||||
disabled: !removePasswordParams.validateParameters() || !hasFiles || !endpointEnabled,
|
disabled: !base.params.validateParameters() || !base.hasFiles || !base.endpointEnabled,
|
||||||
},
|
},
|
||||||
review: {
|
review: {
|
||||||
isVisible: hasResults,
|
isVisible: base.hasResults,
|
||||||
operation: removePasswordOperation,
|
operation: base.operation,
|
||||||
title: t("removePassword.results.title", "Decrypted PDFs"),
|
title: t("removePassword.results.title", "Decrypted PDFs"),
|
||||||
onFileClick: handleThumbnailClick,
|
onFileClick: base.handleThumbnailClick,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,78 +1,39 @@
|
|||||||
import React, { useEffect } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
|
|
||||||
import { useFileContext } from "../contexts/FileContext";
|
|
||||||
import { useNavigationActions } from "../contexts/NavigationContext";
|
|
||||||
import { useFileSelection } from "../contexts/file/fileHooks";
|
|
||||||
|
|
||||||
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
||||||
|
|
||||||
import { useRepairParameters } from "../hooks/tools/repair/useRepairParameters";
|
import { useRepairParameters } from "../hooks/tools/repair/useRepairParameters";
|
||||||
import { useRepairOperation } from "../hooks/tools/repair/useRepairOperation";
|
import { useRepairOperation } from "../hooks/tools/repair/useRepairOperation";
|
||||||
|
import { useBaseTool } from "../hooks/tools/shared/useBaseTool";
|
||||||
import { BaseToolProps, ToolComponent } from "../types/tool";
|
import { BaseToolProps, ToolComponent } from "../types/tool";
|
||||||
|
|
||||||
const Repair = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
const Repair = (props: BaseToolProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { actions } = useNavigationActions();
|
|
||||||
const { selectedFiles } = useFileSelection();
|
|
||||||
|
|
||||||
const repairParams = useRepairParameters();
|
const base = useBaseTool(
|
||||||
const repairOperation = useRepairOperation();
|
'repair',
|
||||||
|
useRepairParameters,
|
||||||
// Endpoint validation
|
useRepairOperation,
|
||||||
const { enabled: endpointEnabled, loading: endpointLoading } = useEndpointEnabled(repairParams.getEndpointName());
|
props
|
||||||
|
);
|
||||||
useEffect(() => {
|
|
||||||
repairOperation.resetResults();
|
|
||||||
onPreviewFile?.(null);
|
|
||||||
}, [repairParams.parameters]);
|
|
||||||
|
|
||||||
const handleRepair = async () => {
|
|
||||||
try {
|
|
||||||
await repairOperation.executeOperation(repairParams.parameters, selectedFiles);
|
|
||||||
if (repairOperation.files && onComplete) {
|
|
||||||
onComplete(repairOperation.files);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
if (onError) {
|
|
||||||
onError(error instanceof Error ? error.message : t("repair.error.failed", "Repair operation failed"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleThumbnailClick = (file: File) => {
|
|
||||||
onPreviewFile?.(file);
|
|
||||||
sessionStorage.setItem("previousMode", "repair");
|
|
||||||
actions.setMode("viewer");
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSettingsReset = () => {
|
|
||||||
repairOperation.resetResults();
|
|
||||||
onPreviewFile?.(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const hasFiles = selectedFiles.length > 0;
|
|
||||||
const hasResults = repairOperation.files.length > 0 || repairOperation.downloadUrl !== null;
|
|
||||||
|
|
||||||
return createToolFlow({
|
return createToolFlow({
|
||||||
files: {
|
files: {
|
||||||
selectedFiles,
|
selectedFiles: base.selectedFiles,
|
||||||
isCollapsed: hasResults,
|
isCollapsed: base.hasResults,
|
||||||
placeholder: t("repair.files.placeholder", "Select a PDF file in the main view to get started"),
|
placeholder: t("repair.files.placeholder", "Select a PDF file in the main view to get started"),
|
||||||
},
|
},
|
||||||
steps: [],
|
steps: [],
|
||||||
executeButton: {
|
executeButton: {
|
||||||
text: t("repair.submit", "Repair PDF"),
|
text: t("repair.submit", "Repair PDF"),
|
||||||
isVisible: !hasResults,
|
isVisible: !base.hasResults,
|
||||||
loadingText: t("loading"),
|
loadingText: t("loading"),
|
||||||
onClick: handleRepair,
|
onClick: base.handleExecute,
|
||||||
disabled: !repairParams.validateParameters() || !hasFiles || !endpointEnabled,
|
disabled: !base.params.validateParameters() || !base.hasFiles || !base.endpointEnabled,
|
||||||
},
|
},
|
||||||
review: {
|
review: {
|
||||||
isVisible: hasResults,
|
isVisible: base.hasResults,
|
||||||
operation: repairOperation,
|
operation: base.operation,
|
||||||
title: t("repair.results.title", "Repair Results"),
|
title: t("repair.results.title", "Repair Results"),
|
||||||
onFileClick: handleThumbnailClick,
|
onFileClick: base.handleThumbnailClick,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,90 +1,53 @@
|
|||||||
import { useEffect } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
|
|
||||||
import { useFileSelection } from "../contexts/FileContext";
|
|
||||||
|
|
||||||
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
||||||
import SanitizeSettings from "../components/tools/sanitize/SanitizeSettings";
|
import SanitizeSettings from "../components/tools/sanitize/SanitizeSettings";
|
||||||
|
|
||||||
import { useSanitizeParameters } from "../hooks/tools/sanitize/useSanitizeParameters";
|
import { useSanitizeParameters } from "../hooks/tools/sanitize/useSanitizeParameters";
|
||||||
import { useSanitizeOperation } from "../hooks/tools/sanitize/useSanitizeOperation";
|
import { useSanitizeOperation } from "../hooks/tools/sanitize/useSanitizeOperation";
|
||||||
|
import { useBaseTool } from "../hooks/tools/shared/useBaseTool";
|
||||||
import { BaseToolProps, ToolComponent } from "../types/tool";
|
import { BaseToolProps, ToolComponent } from "../types/tool";
|
||||||
|
|
||||||
const Sanitize = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
const Sanitize = (props: BaseToolProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const { selectedFiles } = useFileSelection();
|
const base = useBaseTool(
|
||||||
|
'sanitize',
|
||||||
const sanitizeParams = useSanitizeParameters();
|
useSanitizeParameters,
|
||||||
const sanitizeOperation = useSanitizeOperation();
|
useSanitizeOperation,
|
||||||
|
props
|
||||||
// Endpoint validation
|
);
|
||||||
const { enabled: endpointEnabled, loading: endpointLoading } = useEndpointEnabled(sanitizeParams.getEndpointName());
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
sanitizeOperation.resetResults();
|
|
||||||
onPreviewFile?.(null);
|
|
||||||
}, [sanitizeParams.parameters]);
|
|
||||||
|
|
||||||
const handleSanitize = async () => {
|
|
||||||
try {
|
|
||||||
await sanitizeOperation.executeOperation(sanitizeParams.parameters, selectedFiles);
|
|
||||||
if (sanitizeOperation.files && onComplete) {
|
|
||||||
onComplete(sanitizeOperation.files);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
if (onError) {
|
|
||||||
onError(error instanceof Error ? error.message : t("sanitize.error.generic", "Sanitization failed"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSettingsReset = () => {
|
|
||||||
sanitizeOperation.resetResults();
|
|
||||||
onPreviewFile?.(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleThumbnailClick = (file: File) => {
|
|
||||||
onPreviewFile?.(file);
|
|
||||||
sessionStorage.setItem("previousMode", "sanitize");
|
|
||||||
};
|
|
||||||
|
|
||||||
const hasFiles = selectedFiles.length > 0;
|
|
||||||
const hasResults = sanitizeOperation.files.length > 0;
|
|
||||||
const settingsCollapsed = !hasFiles || hasResults;
|
|
||||||
|
|
||||||
return createToolFlow({
|
return createToolFlow({
|
||||||
files: {
|
files: {
|
||||||
selectedFiles,
|
selectedFiles: base.selectedFiles,
|
||||||
isCollapsed: hasResults,
|
isCollapsed: base.hasResults,
|
||||||
placeholder: t("sanitize.files.placeholder", "Select a PDF file in the main view to get started"),
|
placeholder: t("sanitize.files.placeholder", "Select a PDF file in the main view to get started"),
|
||||||
},
|
},
|
||||||
steps: [
|
steps: [
|
||||||
{
|
{
|
||||||
title: t("sanitize.steps.settings", "Settings"),
|
title: t("sanitize.steps.settings", "Settings"),
|
||||||
isCollapsed: settingsCollapsed,
|
isCollapsed: base.settingsCollapsed,
|
||||||
onCollapsedClick: settingsCollapsed ? handleSettingsReset : undefined,
|
onCollapsedClick: base.settingsCollapsed ? base.handleSettingsReset : undefined,
|
||||||
content: (
|
content: (
|
||||||
<SanitizeSettings
|
<SanitizeSettings
|
||||||
parameters={sanitizeParams.parameters}
|
parameters={base.params.parameters}
|
||||||
onParameterChange={sanitizeParams.updateParameter}
|
onParameterChange={base.params.updateParameter}
|
||||||
disabled={endpointLoading}
|
disabled={base.endpointLoading}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
executeButton: {
|
executeButton: {
|
||||||
text: t("sanitize.submit", "Sanitize PDF"),
|
text: t("sanitize.submit", "Sanitize PDF"),
|
||||||
isVisible: !hasResults,
|
isVisible: !base.hasResults,
|
||||||
loadingText: t("loading"),
|
loadingText: t("loading"),
|
||||||
onClick: handleSanitize,
|
onClick: base.handleExecute,
|
||||||
disabled: !sanitizeParams.validateParameters() || !hasFiles || !endpointEnabled,
|
disabled: !base.params.validateParameters() || !base.hasFiles || !base.endpointEnabled,
|
||||||
},
|
},
|
||||||
review: {
|
review: {
|
||||||
isVisible: hasResults,
|
isVisible: base.hasResults,
|
||||||
operation: sanitizeOperation,
|
operation: base.operation,
|
||||||
title: t("sanitize.sanitizationResults", "Sanitization Results"),
|
title: t("sanitize.sanitizationResults", "Sanitization Results"),
|
||||||
onFileClick: handleThumbnailClick,
|
onFileClick: base.handleThumbnailClick,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,78 +1,39 @@
|
|||||||
import React, { useEffect } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
|
|
||||||
import { useFileContext } from "../contexts/FileContext";
|
|
||||||
import { useNavigationActions } from "../contexts/NavigationContext";
|
|
||||||
import { useFileSelection } from "../contexts/file/fileHooks";
|
|
||||||
|
|
||||||
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
||||||
|
|
||||||
import { useSingleLargePageParameters } from "../hooks/tools/singleLargePage/useSingleLargePageParameters";
|
import { useSingleLargePageParameters } from "../hooks/tools/singleLargePage/useSingleLargePageParameters";
|
||||||
import { useSingleLargePageOperation } from "../hooks/tools/singleLargePage/useSingleLargePageOperation";
|
import { useSingleLargePageOperation } from "../hooks/tools/singleLargePage/useSingleLargePageOperation";
|
||||||
|
import { useBaseTool } from "../hooks/tools/shared/useBaseTool";
|
||||||
import { BaseToolProps, ToolComponent } from "../types/tool";
|
import { BaseToolProps, ToolComponent } from "../types/tool";
|
||||||
|
|
||||||
const SingleLargePage = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
const SingleLargePage = (props: BaseToolProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { actions } = useNavigationActions();
|
|
||||||
const { selectedFiles } = useFileSelection();
|
|
||||||
|
|
||||||
const singleLargePageParams = useSingleLargePageParameters();
|
const base = useBaseTool(
|
||||||
const singleLargePageOperation = useSingleLargePageOperation();
|
'singleLargePage',
|
||||||
|
useSingleLargePageParameters,
|
||||||
// Endpoint validation
|
useSingleLargePageOperation,
|
||||||
const { enabled: endpointEnabled, loading: endpointLoading } = useEndpointEnabled(singleLargePageParams.getEndpointName());
|
props
|
||||||
|
);
|
||||||
useEffect(() => {
|
|
||||||
singleLargePageOperation.resetResults();
|
|
||||||
onPreviewFile?.(null);
|
|
||||||
}, [singleLargePageParams.parameters]);
|
|
||||||
|
|
||||||
const handleConvert = async () => {
|
|
||||||
try {
|
|
||||||
await singleLargePageOperation.executeOperation(singleLargePageParams.parameters, selectedFiles);
|
|
||||||
if (singleLargePageOperation.files && onComplete) {
|
|
||||||
onComplete(singleLargePageOperation.files);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
if (onError) {
|
|
||||||
onError(error instanceof Error ? error.message : t("pdfToSinglePage.error.failed", "Single large page operation failed"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleThumbnailClick = (file: File) => {
|
|
||||||
onPreviewFile?.(file);
|
|
||||||
sessionStorage.setItem("previousMode", "single-large-page");
|
|
||||||
actions.setMode("viewer");
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSettingsReset = () => {
|
|
||||||
singleLargePageOperation.resetResults();
|
|
||||||
onPreviewFile?.(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const hasFiles = selectedFiles.length > 0;
|
|
||||||
const hasResults = singleLargePageOperation.files.length > 0 || singleLargePageOperation.downloadUrl !== null;
|
|
||||||
|
|
||||||
return createToolFlow({
|
return createToolFlow({
|
||||||
files: {
|
files: {
|
||||||
selectedFiles,
|
selectedFiles: base.selectedFiles,
|
||||||
isCollapsed: hasFiles || hasResults,
|
isCollapsed: base.hasResults,
|
||||||
placeholder: t("pdfToSinglePage.files.placeholder", "Select a PDF file in the main view to get started"),
|
placeholder: t("pdfToSinglePage.files.placeholder", "Select a PDF file in the main view to get started"),
|
||||||
},
|
},
|
||||||
steps: [],
|
steps: [],
|
||||||
executeButton: {
|
executeButton: {
|
||||||
text: t("pdfToSinglePage.submit", "Convert To Single Page"),
|
text: t("pdfToSinglePage.submit", "Convert To Single Page"),
|
||||||
isVisible: !hasResults,
|
isVisible: !base.hasResults,
|
||||||
loadingText: t("loading"),
|
loadingText: t("loading"),
|
||||||
onClick: handleConvert,
|
onClick: base.handleExecute,
|
||||||
disabled: !singleLargePageParams.validateParameters() || !hasFiles || !endpointEnabled,
|
disabled: !base.params.validateParameters() || !base.hasFiles || !base.endpointEnabled,
|
||||||
},
|
},
|
||||||
review: {
|
review: {
|
||||||
isVisible: hasResults,
|
isVisible: base.hasResults,
|
||||||
operation: singleLargePageOperation,
|
operation: base.operation,
|
||||||
title: t("pdfToSinglePage.results.title", "Single Page Results"),
|
title: t("pdfToSinglePage.results.title", "Single Page Results"),
|
||||||
onFileClick: handleThumbnailClick,
|
onFileClick: base.handleThumbnailClick,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,84 +1,37 @@
|
|||||||
import React, { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
|
|
||||||
import { useFileSelection } from "../contexts/FileContext";
|
|
||||||
import { useNavigationActions } from "../contexts/NavigationContext";
|
|
||||||
|
|
||||||
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
||||||
import SplitSettings from "../components/tools/split/SplitSettings";
|
import SplitSettings from "../components/tools/split/SplitSettings";
|
||||||
|
|
||||||
import { useSplitParameters } from "../hooks/tools/split/useSplitParameters";
|
import { useSplitParameters } from "../hooks/tools/split/useSplitParameters";
|
||||||
import { useSplitOperation } from "../hooks/tools/split/useSplitOperation";
|
import { useSplitOperation } from "../hooks/tools/split/useSplitOperation";
|
||||||
|
import { useBaseTool } from "../hooks/tools/shared/useBaseTool";
|
||||||
import { BaseToolProps, ToolComponent } from "../types/tool";
|
import { BaseToolProps, ToolComponent } from "../types/tool";
|
||||||
|
|
||||||
const Split = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
const Split = (props: BaseToolProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { actions } = useNavigationActions();
|
|
||||||
const { selectedFiles } = useFileSelection();
|
|
||||||
|
|
||||||
const splitParams = useSplitParameters();
|
const base = useBaseTool(
|
||||||
const splitOperation = useSplitOperation();
|
'split',
|
||||||
|
useSplitParameters,
|
||||||
// Endpoint validation
|
useSplitOperation,
|
||||||
const { enabled: endpointEnabled, loading: endpointLoading } = useEndpointEnabled(splitParams.getEndpointName());
|
props
|
||||||
|
);
|
||||||
useEffect(() => {
|
|
||||||
// Only reset results when parameters change, not when files change
|
|
||||||
splitOperation.resetResults();
|
|
||||||
onPreviewFile?.(null);
|
|
||||||
}, [splitParams.parameters]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// Reset results when selected files change (user selected different files)
|
|
||||||
if (selectedFiles.length > 0) {
|
|
||||||
splitOperation.resetResults();
|
|
||||||
onPreviewFile?.(null);
|
|
||||||
}
|
|
||||||
}, [selectedFiles]);
|
|
||||||
|
|
||||||
const handleSplit = async () => {
|
|
||||||
try {
|
|
||||||
await splitOperation.executeOperation(splitParams.parameters, selectedFiles);
|
|
||||||
if (splitOperation.files && onComplete) {
|
|
||||||
onComplete(splitOperation.files);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
if (onError) {
|
|
||||||
onError(error instanceof Error ? error.message : "Split operation failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleThumbnailClick = (file: File) => {
|
|
||||||
onPreviewFile?.(file);
|
|
||||||
sessionStorage.setItem("previousMode", "split");
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSettingsReset = () => {
|
|
||||||
splitOperation.resetResults();
|
|
||||||
onPreviewFile?.(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const hasFiles = selectedFiles.length > 0;
|
|
||||||
const hasResults = splitOperation.files.length > 0 || splitOperation.downloadUrl !== null;
|
|
||||||
const settingsCollapsed = !hasFiles || hasResults;
|
|
||||||
|
|
||||||
return createToolFlow({
|
return createToolFlow({
|
||||||
files: {
|
files: {
|
||||||
selectedFiles,
|
selectedFiles: base.selectedFiles,
|
||||||
isCollapsed: hasResults,
|
isCollapsed: base.hasResults,
|
||||||
placeholder: "Select a PDF file in the main view to get started",
|
|
||||||
},
|
},
|
||||||
steps: [
|
steps: [
|
||||||
{
|
{
|
||||||
title: "Settings",
|
title: "Settings",
|
||||||
isCollapsed: settingsCollapsed,
|
isCollapsed: base.settingsCollapsed,
|
||||||
onCollapsedClick: hasResults ? handleSettingsReset : undefined,
|
onCollapsedClick: base.hasResults ? base.handleSettingsReset : undefined,
|
||||||
content: (
|
content: (
|
||||||
<SplitSettings
|
<SplitSettings
|
||||||
parameters={splitParams.parameters}
|
parameters={base.params.parameters}
|
||||||
onParameterChange={splitParams.updateParameter}
|
onParameterChange={base.params.updateParameter}
|
||||||
disabled={endpointLoading}
|
disabled={base.endpointLoading}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -86,15 +39,15 @@ const Split = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
|||||||
executeButton: {
|
executeButton: {
|
||||||
text: t("split.submit", "Split PDF"),
|
text: t("split.submit", "Split PDF"),
|
||||||
loadingText: t("loading"),
|
loadingText: t("loading"),
|
||||||
onClick: handleSplit,
|
onClick: base.handleExecute,
|
||||||
isVisible: !hasResults,
|
isVisible: !base.hasResults,
|
||||||
disabled: !splitParams.validateParameters() || !hasFiles || !endpointEnabled,
|
disabled: !base.params.validateParameters() || !base.hasFiles || !base.endpointEnabled,
|
||||||
},
|
},
|
||||||
review: {
|
review: {
|
||||||
isVisible: hasResults,
|
isVisible: base.hasResults,
|
||||||
operation: splitOperation,
|
operation: base.operation,
|
||||||
title: "Split Results",
|
title: "Split Results",
|
||||||
onFileClick: handleThumbnailClick,
|
onFileClick: base.handleThumbnailClick,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,78 +1,39 @@
|
|||||||
import React, { useEffect } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
|
|
||||||
import { useFileContext } from "../contexts/FileContext";
|
|
||||||
import { useNavigationActions } from "../contexts/NavigationContext";
|
|
||||||
import { useFileSelection } from "../contexts/file/fileHooks";
|
|
||||||
|
|
||||||
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
||||||
|
|
||||||
import { useUnlockPdfFormsParameters } from "../hooks/tools/unlockPdfForms/useUnlockPdfFormsParameters";
|
import { useUnlockPdfFormsParameters } from "../hooks/tools/unlockPdfForms/useUnlockPdfFormsParameters";
|
||||||
import { useUnlockPdfFormsOperation } from "../hooks/tools/unlockPdfForms/useUnlockPdfFormsOperation";
|
import { useUnlockPdfFormsOperation } from "../hooks/tools/unlockPdfForms/useUnlockPdfFormsOperation";
|
||||||
|
import { useBaseTool } from "../hooks/tools/shared/useBaseTool";
|
||||||
import { BaseToolProps, ToolComponent } from "../types/tool";
|
import { BaseToolProps, ToolComponent } from "../types/tool";
|
||||||
|
|
||||||
const UnlockPdfForms = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
const UnlockPdfForms = (props: BaseToolProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { actions } = useNavigationActions();
|
|
||||||
const { selectedFiles } = useFileSelection();
|
|
||||||
|
|
||||||
const unlockPdfFormsParams = useUnlockPdfFormsParameters();
|
const base = useBaseTool(
|
||||||
const unlockPdfFormsOperation = useUnlockPdfFormsOperation();
|
'unlockPdfForms',
|
||||||
|
useUnlockPdfFormsParameters,
|
||||||
// Endpoint validation
|
useUnlockPdfFormsOperation,
|
||||||
const { enabled: endpointEnabled, loading: endpointLoading } = useEndpointEnabled(unlockPdfFormsParams.getEndpointName());
|
props
|
||||||
|
);
|
||||||
useEffect(() => {
|
|
||||||
unlockPdfFormsOperation.resetResults();
|
|
||||||
onPreviewFile?.(null);
|
|
||||||
}, [unlockPdfFormsParams.parameters]);
|
|
||||||
|
|
||||||
const handleUnlock = async () => {
|
|
||||||
try {
|
|
||||||
await unlockPdfFormsOperation.executeOperation(unlockPdfFormsParams.parameters, selectedFiles);
|
|
||||||
if (unlockPdfFormsOperation.files && onComplete) {
|
|
||||||
onComplete(unlockPdfFormsOperation.files);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
if (onError) {
|
|
||||||
onError(error instanceof Error ? error.message : t("unlockPDFForms.error.failed", "Unlock PDF forms operation failed"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleThumbnailClick = (file: File) => {
|
|
||||||
onPreviewFile?.(file);
|
|
||||||
sessionStorage.setItem("previousMode", "unlockPdfForms");
|
|
||||||
actions.setMode("viewer");
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSettingsReset = () => {
|
|
||||||
unlockPdfFormsOperation.resetResults();
|
|
||||||
onPreviewFile?.(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const hasFiles = selectedFiles.length > 0;
|
|
||||||
const hasResults = unlockPdfFormsOperation.files.length > 0 || unlockPdfFormsOperation.downloadUrl !== null;
|
|
||||||
|
|
||||||
return createToolFlow({
|
return createToolFlow({
|
||||||
files: {
|
files: {
|
||||||
selectedFiles,
|
selectedFiles: base.selectedFiles,
|
||||||
isCollapsed: hasFiles || hasResults,
|
isCollapsed: base.hasFiles || base.hasResults,
|
||||||
placeholder: t("unlockPDFForms.files.placeholder", "Select a PDF file in the main view to get started"),
|
placeholder: t("unlockPDFForms.files.placeholder", "Select a PDF file in the main view to get started"),
|
||||||
},
|
},
|
||||||
steps: [],
|
steps: [],
|
||||||
executeButton: {
|
executeButton: {
|
||||||
text: t("unlockPDFForms.submit", "Unlock Forms"),
|
text: t("unlockPDFForms.submit", "Unlock Forms"),
|
||||||
isVisible: !hasResults,
|
isVisible: !base.hasResults,
|
||||||
loadingText: t("loading"),
|
loadingText: t("loading"),
|
||||||
onClick: handleUnlock,
|
onClick: base.handleExecute,
|
||||||
disabled: !unlockPdfFormsParams.validateParameters() || !hasFiles || !endpointEnabled,
|
disabled: !base.params.validateParameters() || !base.hasFiles || !base.endpointEnabled,
|
||||||
},
|
},
|
||||||
review: {
|
review: {
|
||||||
isVisible: hasResults,
|
isVisible: base.hasResults,
|
||||||
operation: unlockPdfFormsOperation,
|
operation: base.operation,
|
||||||
title: t("unlockPDFForms.results.title", "Unlocked Forms Results"),
|
title: t("unlockPDFForms.results.title", "Unlocked Forms Results"),
|
||||||
onFileClick: handleThumbnailClick,
|
onFileClick: base.handleThumbnailClick,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user