mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-08-26 14:19:24 +00:00
Workflow
This commit is contained in:
parent
9d2ca3c8c8
commit
3e4afd166e
106
frontend/src/components/tools/shared/createToolFlow.tsx
Normal file
106
frontend/src/components/tools/shared/createToolFlow.tsx
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Stack } from '@mantine/core';
|
||||||
|
import { createToolSteps, ToolStepProvider } from './ToolStep';
|
||||||
|
import OperationButton from './OperationButton';
|
||||||
|
import { ToolOperationHook } from '../../../hooks/tools/shared/useToolOperation';
|
||||||
|
|
||||||
|
export interface FilesStepConfig {
|
||||||
|
selectedFiles: File[];
|
||||||
|
isCollapsed?: boolean;
|
||||||
|
placeholder?: string;
|
||||||
|
onCollapsedClick?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MiddleStepConfig {
|
||||||
|
title: string;
|
||||||
|
isVisible?: boolean;
|
||||||
|
isCollapsed?: boolean;
|
||||||
|
isCompleted?: boolean;
|
||||||
|
onCollapsedClick?: () => void;
|
||||||
|
completedMessage?: string;
|
||||||
|
content: React.ReactNode;
|
||||||
|
tooltip?: {
|
||||||
|
content?: React.ReactNode;
|
||||||
|
tips?: any[];
|
||||||
|
header?: {
|
||||||
|
title: string;
|
||||||
|
logo?: React.ReactNode;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExecuteButtonConfig {
|
||||||
|
text: string;
|
||||||
|
loadingText: string;
|
||||||
|
onClick: () => Promise<void>;
|
||||||
|
isVisible?: boolean;
|
||||||
|
disabled?: boolean;
|
||||||
|
testId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResultsStepConfig {
|
||||||
|
isVisible: boolean;
|
||||||
|
operation: ToolOperationHook<any>;
|
||||||
|
title: string;
|
||||||
|
onFileClick?: (file: File) => void;
|
||||||
|
testId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ToolFlowConfig {
|
||||||
|
files: FilesStepConfig;
|
||||||
|
steps: MiddleStepConfig[];
|
||||||
|
executeButton?: ExecuteButtonConfig;
|
||||||
|
results: ResultsStepConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a flexible tool flow with configurable steps and state management left to the tool.
|
||||||
|
* Reduces boilerplate while allowing tools to manage their own collapse/expansion logic.
|
||||||
|
*/
|
||||||
|
export function createToolFlow(config: ToolFlowConfig) {
|
||||||
|
const steps = createToolSteps();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ToolStepProvider>
|
||||||
|
{/* Files Step */}
|
||||||
|
{steps.createFilesStep({
|
||||||
|
selectedFiles: config.files.selectedFiles,
|
||||||
|
isCollapsed: config.files.isCollapsed,
|
||||||
|
placeholder: config.files.placeholder,
|
||||||
|
onCollapsedClick: config.files.onCollapsedClick
|
||||||
|
})}
|
||||||
|
|
||||||
|
{/* Middle Steps */}
|
||||||
|
{config.steps.map((stepConfig, index) =>
|
||||||
|
steps.create(stepConfig.title, {
|
||||||
|
isVisible: stepConfig.isVisible,
|
||||||
|
isCollapsed: stepConfig.isCollapsed,
|
||||||
|
isCompleted: stepConfig.isCompleted,
|
||||||
|
onCollapsedClick: stepConfig.onCollapsedClick,
|
||||||
|
completedMessage: stepConfig.completedMessage,
|
||||||
|
tooltip: stepConfig.tooltip
|
||||||
|
}, stepConfig.content)
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Execute Button */}
|
||||||
|
{config.executeButton && config.executeButton.isVisible !== false && (
|
||||||
|
<OperationButton
|
||||||
|
onClick={config.executeButton.onClick}
|
||||||
|
isLoading={config.results.operation.isLoading}
|
||||||
|
disabled={config.executeButton.disabled}
|
||||||
|
loadingText={config.executeButton.loadingText}
|
||||||
|
submitText={config.executeButton.text}
|
||||||
|
data-testid={config.executeButton.testId}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Results Step */}
|
||||||
|
{steps.createResultsStep({
|
||||||
|
isVisible: config.results.isVisible,
|
||||||
|
operation: config.results.operation,
|
||||||
|
title: config.results.title,
|
||||||
|
onFileClick: config.results.onFileClick
|
||||||
|
})}
|
||||||
|
</ToolStepProvider>
|
||||||
|
);
|
||||||
|
}
|
@ -1,12 +1,11 @@
|
|||||||
import React, { useEffect, useMemo } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Stack } from "@mantine/core";
|
import { Stack } from "@mantine/core";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
|
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
|
||||||
import { useFileContext } from "../contexts/FileContext";
|
import { useFileContext } from "../contexts/FileContext";
|
||||||
import { useToolFileSelection } from "../contexts/FileSelectionContext";
|
import { useToolFileSelection } from "../contexts/FileSelectionContext";
|
||||||
|
|
||||||
import { createToolSteps, ToolStepProvider } from "../components/tools/shared/ToolStep";
|
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
||||||
import OperationButton from "../components/tools/shared/OperationButton";
|
|
||||||
|
|
||||||
import CompressSettings from "../components/tools/compress/CompressSettings";
|
import CompressSettings from "../components/tools/compress/CompressSettings";
|
||||||
|
|
||||||
@ -65,49 +64,41 @@ const Compress = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
|||||||
const filesCollapsed = hasFiles;
|
const filesCollapsed = hasFiles;
|
||||||
const settingsCollapsed = !hasFiles || hasResults;
|
const settingsCollapsed = !hasFiles || hasResults;
|
||||||
|
|
||||||
|
|
||||||
const steps = createToolSteps();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack gap="md" h="100%" p="sm" style={{ overflow: 'auto' }}>
|
<Stack gap="md" h="100%" p="sm" style={{ overflow: 'auto' }}>
|
||||||
<ToolStepProvider>
|
{createToolFlow({
|
||||||
{/* Files Step */}
|
files: {
|
||||||
{steps.createFilesStep({
|
|
||||||
selectedFiles,
|
selectedFiles,
|
||||||
isCollapsed: filesCollapsed
|
isCollapsed: filesCollapsed
|
||||||
})}
|
},
|
||||||
|
steps: [{
|
||||||
{/* Settings Step */}
|
title: "Settings",
|
||||||
{steps.create("Settings", {
|
|
||||||
isCollapsed: settingsCollapsed,
|
isCollapsed: settingsCollapsed,
|
||||||
isCompleted: hasResults,
|
isCompleted: hasResults,
|
||||||
onCollapsedClick: settingsCollapsed ? handleSettingsReset : undefined,
|
onCollapsedClick: settingsCollapsed ? handleSettingsReset : undefined,
|
||||||
completedMessage: t("compress.header", "Compression completed"),
|
completedMessage: t("compress.header", "Compression completed"),
|
||||||
tooltip: compressTips
|
tooltip: compressTips,
|
||||||
}, (
|
content: (
|
||||||
<Stack gap="md">
|
|
||||||
<CompressSettings
|
<CompressSettings
|
||||||
parameters={compressParams.parameters}
|
parameters={compressParams.parameters}
|
||||||
onParameterChange={compressParams.updateParameter}
|
onParameterChange={compressParams.updateParameter}
|
||||||
disabled={endpointLoading}
|
disabled={endpointLoading}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
)
|
||||||
))}
|
}],
|
||||||
<OperationButton
|
executeButton: {
|
||||||
onClick={handleCompress}
|
text: t("compress.submit", "Compress"),
|
||||||
isLoading={compressOperation.isLoading}
|
loadingText: t("loading"),
|
||||||
disabled={!compressParams.validateParameters() || !hasFiles || !endpointEnabled}
|
onClick: handleCompress,
|
||||||
loadingText={t("loading")}
|
disabled: !compressParams.validateParameters() || !hasFiles || !endpointEnabled
|
||||||
submitText={t("compress.submit", "Compress")}
|
},
|
||||||
/>
|
results: {
|
||||||
{/* Results Step */}
|
|
||||||
{steps.createResultsStep({
|
|
||||||
isVisible: hasResults,
|
isVisible: hasResults,
|
||||||
operation: compressOperation,
|
operation: compressOperation,
|
||||||
title: t("compress.title", "Compression Results"),
|
title: t("compress.title", "Compression Results"),
|
||||||
onFileClick: handleThumbnailClick
|
onFileClick: handleThumbnailClick
|
||||||
})}
|
}
|
||||||
</ToolStepProvider>
|
})}
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,7 @@ import { useEndpointEnabled } from "../hooks/useEndpointConfig";
|
|||||||
import { useFileContext } from "../contexts/FileContext";
|
import { useFileContext } from "../contexts/FileContext";
|
||||||
import { useToolFileSelection } from "../contexts/FileSelectionContext";
|
import { useToolFileSelection } from "../contexts/FileSelectionContext";
|
||||||
|
|
||||||
import { createToolSteps, ToolStepProvider } from "../components/tools/shared/ToolStep";
|
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
||||||
import OperationButton from "../components/tools/shared/OperationButton";
|
|
||||||
|
|
||||||
import ConvertSettings from "../components/tools/convert/ConvertSettings";
|
import ConvertSettings from "../components/tools/convert/ConvertSettings";
|
||||||
|
|
||||||
@ -101,26 +100,21 @@ const Convert = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
|||||||
setCurrentMode('convert');
|
setCurrentMode('convert');
|
||||||
};
|
};
|
||||||
|
|
||||||
const steps = createToolSteps();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full max-h-screen overflow-y-auto" ref={scrollContainerRef}>
|
<div className="h-full max-h-screen overflow-y-auto" ref={scrollContainerRef}>
|
||||||
<Stack gap="sm" p="sm">
|
<Stack gap="sm" p="sm">
|
||||||
<ToolStepProvider>
|
{createToolFlow({
|
||||||
{/* Files Step */}
|
files: {
|
||||||
{steps.createFilesStep({
|
|
||||||
selectedFiles,
|
selectedFiles,
|
||||||
isCollapsed: filesCollapsed,
|
isCollapsed: filesCollapsed,
|
||||||
placeholder: t("convert.selectFilesPlaceholder", "Select files in the main view to get started")
|
placeholder: t("convert.selectFilesPlaceholder", "Select files in the main view to get started")
|
||||||
})}
|
},
|
||||||
|
steps: [{
|
||||||
{/* Settings Step */}
|
title: t("convert.settings", "Settings"),
|
||||||
{steps.create(t("convert.settings", "Settings"), {
|
|
||||||
isCollapsed: settingsCollapsed,
|
isCollapsed: settingsCollapsed,
|
||||||
isCompleted: settingsCollapsed,
|
isCompleted: settingsCollapsed,
|
||||||
onCollapsedClick: settingsCollapsed ? handleSettingsReset : undefined,
|
onCollapsedClick: settingsCollapsed ? handleSettingsReset : undefined,
|
||||||
}, (
|
content: (
|
||||||
<Stack gap="sm">
|
|
||||||
<ConvertSettings
|
<ConvertSettings
|
||||||
parameters={convertParams.parameters}
|
parameters={convertParams.parameters}
|
||||||
onParameterChange={convertParams.updateParameter}
|
onParameterChange={convertParams.updateParameter}
|
||||||
@ -128,27 +122,24 @@ const Convert = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
|||||||
selectedFiles={selectedFiles}
|
selectedFiles={selectedFiles}
|
||||||
disabled={endpointLoading}
|
disabled={endpointLoading}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
)
|
||||||
))}
|
}],
|
||||||
{!hasResults && (
|
executeButton: {
|
||||||
<OperationButton
|
text: t("convert.convertFiles", "Convert Files"),
|
||||||
onClick={handleConvert}
|
loadingText: t("convert.converting", "Converting..."),
|
||||||
isLoading={convertOperation.isLoading}
|
onClick: handleConvert,
|
||||||
disabled={!convertParams.validateParameters() || !hasFiles || !endpointEnabled}
|
isVisible: !hasResults,
|
||||||
loadingText={t("convert.converting", "Converting...")}
|
disabled: !convertParams.validateParameters() || !hasFiles || !endpointEnabled,
|
||||||
submitText={t("convert.convertFiles", "Convert Files")}
|
testId: "convert-button"
|
||||||
data-testid="convert-button"
|
},
|
||||||
/>
|
results: {
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Results Step */}
|
|
||||||
{steps.createResultsStep({
|
|
||||||
isVisible: hasResults,
|
isVisible: hasResults,
|
||||||
operation: convertOperation,
|
operation: convertOperation,
|
||||||
title: t("convert.conversionResults", "Conversion Results"),
|
title: t("convert.conversionResults", "Conversion Results"),
|
||||||
onFileClick: handleThumbnailClick
|
onFileClick: handleThumbnailClick,
|
||||||
})}
|
testId: "conversion-results"
|
||||||
</ToolStepProvider>
|
}
|
||||||
|
})}
|
||||||
</Stack>
|
</Stack>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
import React, { useEffect, useMemo, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { Stack, Box } from "@mantine/core";
|
import { Stack } from "@mantine/core";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
|
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
|
||||||
import { useFileContext } from "../contexts/FileContext";
|
import { useFileContext } from "../contexts/FileContext";
|
||||||
import { useToolFileSelection } from "../contexts/FileSelectionContext";
|
import { useToolFileSelection } from "../contexts/FileSelectionContext";
|
||||||
|
|
||||||
import { createToolSteps, ToolStepProvider } from "../components/tools/shared/ToolStep";
|
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
||||||
import OperationButton from "../components/tools/shared/OperationButton";
|
|
||||||
|
|
||||||
import OCRSettings from "../components/tools/ocr/OCRSettings";
|
import OCRSettings from "../components/tools/ocr/OCRSettings";
|
||||||
import AdvancedOCRSettings from "../components/tools/ocr/AdvancedOCRSettings";
|
import AdvancedOCRSettings from "../components/tools/ocr/AdvancedOCRSettings";
|
||||||
@ -75,78 +74,66 @@ const OCR = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const resultsVisible = hasResults;
|
|
||||||
|
|
||||||
const filesCollapsed = expandedStep !== 'files';
|
const filesCollapsed = expandedStep !== 'files';
|
||||||
const settingsCollapsed = expandedStep !== 'settings';
|
const settingsCollapsed = expandedStep !== 'settings';
|
||||||
|
|
||||||
|
|
||||||
const steps = createToolSteps();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack gap="sm" h="100%" p="sm" style={{ overflow: 'auto' }}>
|
<Stack gap="sm" h="100%" p="sm" style={{ overflow: 'auto' }}>
|
||||||
<ToolStepProvider>
|
{createToolFlow({
|
||||||
{/* Files Step */}
|
files: {
|
||||||
{steps.createFilesStep({
|
|
||||||
selectedFiles,
|
selectedFiles,
|
||||||
isCollapsed: hasFiles && filesCollapsed,
|
isCollapsed: hasFiles && filesCollapsed,
|
||||||
})}
|
},
|
||||||
|
steps: [
|
||||||
{/* Settings Step */}
|
{
|
||||||
{steps.create("Settings", {
|
title: "Settings",
|
||||||
isCollapsed: !hasFiles || settingsCollapsed,
|
isCollapsed: !hasFiles || settingsCollapsed,
|
||||||
isCompleted: hasFiles && hasValidSettings,
|
isCompleted: hasFiles && hasValidSettings,
|
||||||
onCollapsedClick: () => {
|
onCollapsedClick: () => {
|
||||||
if (!hasFiles) return; // Only allow if files are selected
|
if (!hasFiles) return; // Only allow if files are selected
|
||||||
setExpandedStep(expandedStep === 'settings' ? null : 'settings');
|
setExpandedStep(expandedStep === 'settings' ? null : 'settings');
|
||||||
|
},
|
||||||
|
tooltip: ocrTips,
|
||||||
|
content: (
|
||||||
|
<OCRSettings
|
||||||
|
parameters={ocrParams.parameters}
|
||||||
|
onParameterChange={ocrParams.updateParameter}
|
||||||
|
disabled={endpointLoading}
|
||||||
|
/>
|
||||||
|
)
|
||||||
},
|
},
|
||||||
tooltip: ocrTips
|
{
|
||||||
}, (
|
title: "Advanced",
|
||||||
<Stack gap="sm">
|
isCollapsed: expandedStep !== 'advanced',
|
||||||
<OCRSettings
|
isCompleted: hasFiles && hasResults,
|
||||||
parameters={ocrParams.parameters}
|
onCollapsedClick: () => {
|
||||||
onParameterChange={ocrParams.updateParameter}
|
if (!hasFiles) return; // Only allow if files are selected
|
||||||
disabled={endpointLoading}
|
setExpandedStep(expandedStep === 'advanced' ? null : 'advanced');
|
||||||
/>
|
},
|
||||||
</Stack>
|
content: (
|
||||||
))}
|
<AdvancedOCRSettings
|
||||||
|
advancedOptions={ocrParams.parameters.additionalOptions}
|
||||||
{/* Advanced Step */}
|
ocrRenderType={ocrParams.parameters.ocrRenderType}
|
||||||
{steps.create("Advanced", {
|
onParameterChange={ocrParams.updateParameter}
|
||||||
isCollapsed: expandedStep !== 'advanced',
|
disabled={endpointLoading}
|
||||||
isCompleted: hasFiles && hasResults,
|
/>
|
||||||
onCollapsedClick: () => {
|
)
|
||||||
if (!hasFiles) return; // Only allow if files are selected
|
}
|
||||||
setExpandedStep(expandedStep === 'advanced' ? null : 'advanced');
|
],
|
||||||
},
|
executeButton: {
|
||||||
}, (
|
text: t("ocr.operation.submit", "Process OCR and Review"),
|
||||||
<AdvancedOCRSettings
|
loadingText: t("loading"),
|
||||||
advancedOptions={ocrParams.parameters.additionalOptions}
|
onClick: handleOCR,
|
||||||
ocrRenderType={ocrParams.parameters.ocrRenderType}
|
isVisible: hasValidSettings && !hasResults,
|
||||||
onParameterChange={ocrParams.updateParameter}
|
disabled: !ocrParams.validateParameters() || !hasFiles || !endpointEnabled
|
||||||
disabled={endpointLoading}
|
},
|
||||||
/>
|
results: {
|
||||||
))}
|
isVisible: hasResults,
|
||||||
|
|
||||||
{/* Process Button - Available after all configuration */}
|
|
||||||
{hasValidSettings && !hasResults && (
|
|
||||||
<OperationButton
|
|
||||||
onClick={handleOCR}
|
|
||||||
isLoading={ocrOperation.isLoading}
|
|
||||||
disabled={!ocrParams.validateParameters() || !hasFiles || !endpointEnabled}
|
|
||||||
loadingText={t("loading")}
|
|
||||||
submitText={t("ocr.operation.submit", "Process OCR and Review")}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Results Step */}
|
|
||||||
{steps.createResultsStep({
|
|
||||||
isVisible: resultsVisible,
|
|
||||||
operation: ocrOperation,
|
operation: ocrOperation,
|
||||||
title: t("ocr.results.title", "OCR Results"),
|
title: t("ocr.results.title", "OCR Results"),
|
||||||
onFileClick: handleThumbnailClick
|
onFileClick: handleThumbnailClick
|
||||||
})}
|
}
|
||||||
</ToolStepProvider>
|
})}
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
import React, { useEffect, useMemo } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Stack } from "@mantine/core";
|
import { Stack } from "@mantine/core";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
|
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
|
||||||
import { useFileContext } from "../contexts/FileContext";
|
import { useFileContext } from "../contexts/FileContext";
|
||||||
import { useToolFileSelection } from "../contexts/FileSelectionContext";
|
import { useToolFileSelection } from "../contexts/FileSelectionContext";
|
||||||
|
|
||||||
import { createToolSteps, ToolStepProvider } from "../components/tools/shared/ToolStep";
|
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
||||||
import OperationButton from "../components/tools/shared/OperationButton";
|
|
||||||
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";
|
||||||
@ -64,52 +63,41 @@ const Split = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
|||||||
const filesCollapsed = hasFiles;
|
const filesCollapsed = hasFiles;
|
||||||
const settingsCollapsed = !hasFiles || hasResults;
|
const settingsCollapsed = !hasFiles || hasResults;
|
||||||
|
|
||||||
const steps = createToolSteps();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack gap="sm" h="100%" p="sm" style={{ overflow: 'auto' }}>
|
<Stack gap="sm" h="100%" p="sm" style={{ overflow: 'auto' }}>
|
||||||
<ToolStepProvider>
|
{createToolFlow({
|
||||||
{/* Files Step */}
|
files: {
|
||||||
{steps.createFilesStep({
|
|
||||||
selectedFiles,
|
selectedFiles,
|
||||||
isCollapsed: filesCollapsed,
|
isCollapsed: filesCollapsed,
|
||||||
placeholder: "Select a PDF file in the main view to get started"
|
placeholder: "Select a PDF file in the main view to get started"
|
||||||
})}
|
},
|
||||||
|
steps: [{
|
||||||
{/* Settings Step */}
|
title: "Settings",
|
||||||
{steps.create("Settings", {
|
|
||||||
isCollapsed: settingsCollapsed,
|
isCollapsed: settingsCollapsed,
|
||||||
isCompleted: hasResults,
|
isCompleted: hasResults,
|
||||||
onCollapsedClick: hasResults ? handleSettingsReset : undefined,
|
onCollapsedClick: hasResults ? handleSettingsReset : undefined,
|
||||||
}, (
|
content: (
|
||||||
<Stack gap="sm">
|
|
||||||
<SplitSettings
|
<SplitSettings
|
||||||
parameters={splitParams.parameters}
|
parameters={splitParams.parameters}
|
||||||
onParameterChange={splitParams.updateParameter}
|
onParameterChange={splitParams.updateParameter}
|
||||||
disabled={endpointLoading}
|
disabled={endpointLoading}
|
||||||
/>
|
/>
|
||||||
|
)
|
||||||
</Stack>
|
}],
|
||||||
))}
|
executeButton: {
|
||||||
|
text: t("split.submit", "Split PDF"),
|
||||||
{!hasResults && (
|
loadingText: t("loading"),
|
||||||
<OperationButton
|
onClick: handleSplit,
|
||||||
onClick={handleSplit}
|
isVisible: !hasResults,
|
||||||
isLoading={splitOperation.isLoading}
|
disabled: !splitParams.validateParameters() || !hasFiles || !endpointEnabled
|
||||||
disabled={!splitParams.validateParameters() || !hasFiles || !endpointEnabled}
|
},
|
||||||
loadingText={t("loading")}
|
results: {
|
||||||
submitText={t("split.submit", "Split PDF")}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Results Step */}
|
|
||||||
{steps.createResultsStep({
|
|
||||||
isVisible: hasResults,
|
isVisible: hasResults,
|
||||||
operation: splitOperation,
|
operation: splitOperation,
|
||||||
title: "Split Results",
|
title: "Split Results",
|
||||||
onFileClick: handleThumbnailClick
|
onFileClick: handleThumbnailClick
|
||||||
})}
|
}
|
||||||
</ToolStepProvider>
|
})}
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user