diff --git a/frontend/public/locales/en-GB/translation.json b/frontend/public/locales/en-GB/translation.json
index a405edb7c..ad0fe8aa6 100644
--- a/frontend/public/locales/en-GB/translation.json
+++ b/frontend/public/locales/en-GB/translation.json
@@ -1597,7 +1597,7 @@
"auto": {
"header": "Auto Redact",
"settings": "Redaction Settings",
- "colorLabel": "Colour",
+ "colorLabel": "Box Colour",
"wordsToRedact": {
"title": "Words to Redact",
"placeholder": "Enter a word",
diff --git a/frontend/src/components/tools/redact/AutomaticRedactSettings.tsx b/frontend/src/components/tools/redact/AutomaticRedactSettings.tsx
index a724b0407..1cac3ff05 100644
--- a/frontend/src/components/tools/redact/AutomaticRedactSettings.tsx
+++ b/frontend/src/components/tools/redact/AutomaticRedactSettings.tsx
@@ -33,27 +33,28 @@ const AutomaticRedactSettings = ({ parameters, onParameterChange, disabled = fal
{/* Box Color */}
- {t('redact.auto.colorLabel', 'Colour')}
-
- onParameterChange('redactColor', value)}
- disabled={disabled}
- size="sm"
- style={{ width: '80px' }}
- />
- onParameterChange('customPadding', typeof value === 'number' ? value : 0.1)}
- min={0}
- max={10}
- step={0.1}
- disabled={disabled}
- size="sm"
- style={{ width: '80px' }}
- placeholder="0.1"
- />
-
+ {t('redact.auto.colorLabel', 'Box Colour')}
+ onParameterChange('redactColor', value)}
+ disabled={disabled}
+ size="sm"
+ />
+
+
+ {/* Box Padding */}
+
+ {t('redact.auto.paddingLabel', 'Box Padding')}
+ onParameterChange('customPadding', typeof value === 'number' ? value : 0.1)}
+ min={0}
+ max={10}
+ step={0.1}
+ disabled={disabled}
+ size="sm"
+ placeholder="0.1"
+ />
{/* Use Regex */}
diff --git a/frontend/src/components/tools/redact/RedactAdvancedStep.tsx b/frontend/src/components/tools/redact/RedactAdvancedStep.tsx
new file mode 100644
index 000000000..8c9ab493e
--- /dev/null
+++ b/frontend/src/components/tools/redact/RedactAdvancedStep.tsx
@@ -0,0 +1,76 @@
+import { Stack, Text, NumberInput, ColorInput } from '@mantine/core';
+import { useTranslation } from 'react-i18next';
+import { RedactParameters } from '../../../hooks/tools/redact/useRedactParameters';
+
+interface RedactAdvancedStepProps {
+ parameters: RedactParameters;
+ onParameterChange: (key: K, value: RedactParameters[K]) => void;
+ disabled?: boolean;
+}
+
+export default function RedactAdvancedStep({ parameters, onParameterChange, disabled }: RedactAdvancedStepProps) {
+ const { t } = useTranslation();
+
+ return (
+
+ {/* Box Color */}
+
+ {t('redact.advanced.colorLabel', 'Box Color')}
+ onParameterChange('redactColor', value)}
+ disabled={disabled}
+ size="sm"
+ />
+
+
+ {/* Box Padding */}
+
+ {t('redact.advanced.paddingLabel', 'Box Padding')}
+ onParameterChange('customPadding', typeof value === 'number' ? value : 0.1)}
+ min={0}
+ max={10}
+ step={0.1}
+ disabled={disabled}
+ size="sm"
+ placeholder="0.1"
+ />
+
+
+ {/* Use Regex */}
+
+
+ {/* Whole Word Search */}
+
+
+ {/* Convert PDF to PDF-Image */}
+
+
+ );
+}
diff --git a/frontend/src/components/tools/redact/RedactModeStep.tsx b/frontend/src/components/tools/redact/RedactModeStep.tsx
new file mode 100644
index 000000000..ec98b56a0
--- /dev/null
+++ b/frontend/src/components/tools/redact/RedactModeStep.tsx
@@ -0,0 +1,21 @@
+import { Stack } from '@mantine/core';
+import { RedactParameters } from '../../../hooks/tools/redact/useRedactParameters';
+import RedactModeSelector from './RedactModeSelector';
+
+interface RedactModeStepProps {
+ parameters: RedactParameters;
+ onParameterChange: (key: K, value: RedactParameters[K]) => void;
+ disabled?: boolean;
+}
+
+export default function RedactModeStep({ parameters, onParameterChange, disabled }: RedactModeStepProps) {
+ return (
+
+ onParameterChange('mode', mode)}
+ disabled={disabled}
+ />
+
+ );
+}
diff --git a/frontend/src/components/tools/redact/RedactWordsStep.tsx b/frontend/src/components/tools/redact/RedactWordsStep.tsx
new file mode 100644
index 000000000..6de3c3350
--- /dev/null
+++ b/frontend/src/components/tools/redact/RedactWordsStep.tsx
@@ -0,0 +1,21 @@
+import { Stack } from '@mantine/core';
+import { RedactParameters } from '../../../hooks/tools/redact/useRedactParameters';
+import WordsToRedactInput from './WordsToRedactInput';
+
+interface RedactWordsStepProps {
+ parameters: RedactParameters;
+ onParameterChange: (key: K, value: RedactParameters[K]) => void;
+ disabled?: boolean;
+}
+
+export default function RedactWordsStep({ parameters, onParameterChange, disabled }: RedactWordsStepProps) {
+ return (
+
+ onParameterChange('wordsToRedact', words)}
+ disabled={disabled}
+ />
+
+ );
+}
diff --git a/frontend/src/components/tools/redact/WordsToRedactInput.tsx b/frontend/src/components/tools/redact/WordsToRedactInput.tsx
index 1b2f48ef4..e574c4819 100644
--- a/frontend/src/components/tools/redact/WordsToRedactInput.tsx
+++ b/frontend/src/components/tools/redact/WordsToRedactInput.tsx
@@ -58,14 +58,13 @@ export default function WordsToRedactInput({ wordsToRedact, onWordsChange, disab
))}
{/* Add new word input */}
-
+
setCurrentWord(e.target.value)}
onKeyDown={handleKeyPress}
disabled={disabled}
- style={{ flex: 1 }}
size="sm"
/>
-
+
{/* Examples */}
{wordsToRedact.length === 0 && (
diff --git a/frontend/src/components/tooltips/useRedactTips.ts b/frontend/src/components/tooltips/useRedactTips.ts
new file mode 100644
index 000000000..af925f4fb
--- /dev/null
+++ b/frontend/src/components/tooltips/useRedactTips.ts
@@ -0,0 +1,79 @@
+import { useTranslation } from 'react-i18next';
+import { TooltipContent } from '../../types/tips';
+
+export const useRedactModeTips = (): TooltipContent => {
+ const { t } = useTranslation();
+
+ return {
+ header: {
+ title: t("redact.tooltip.mode.header.title", "Redaction Method")
+ },
+ tips: [
+ {
+ title: t("redact.tooltip.mode.automatic.title", "Automatic Redaction"),
+ description: t("redact.tooltip.mode.automatic.text", "Automatically finds and redacts specified text throughout the document. Perfect for removing consistent sensitive information like names, SSNs, or confidential markers.")
+ },
+ {
+ title: t("redact.tooltip.mode.manual.title", "Manual Redaction"),
+ description: t("redact.tooltip.mode.manual.text", "Click and drag to manually select specific areas to redact. Gives you precise control over what gets redacted. (Coming soon)")
+ }
+ ]
+ };
+};
+
+export const useRedactWordsTips = (): TooltipContent => {
+ const { t } = useTranslation();
+
+ return {
+ header: {
+ title: t("redact.tooltip.words.header.title", "Words to Redact")
+ },
+ tips: [
+ {
+ title: t("redact.tooltip.words.description.title", "Text Matching"),
+ description: t("redact.tooltip.words.description.text", "Enter words or phrases to find and redact in your document. Each word will be searched for separately."),
+ bullets: [
+ t("redact.tooltip.words.bullet1", "Add one word at a time"),
+ t("redact.tooltip.words.bullet2", "Press Enter or click 'Add Another' to add"),
+ t("redact.tooltip.words.bullet3", "Click × to remove words")
+ ]
+ },
+ {
+ title: t("redact.tooltip.words.examples.title", "Common Examples"),
+ description: t("redact.tooltip.words.examples.text", "Typical words to redact include: 'Confidential', 'SSN:', phone numbers, email addresses, or specific names.")
+ }
+ ]
+ };
+};
+
+export const useRedactAdvancedTips = (): TooltipContent => {
+ const { t } = useTranslation();
+
+ return {
+ header: {
+ title: t("redact.tooltip.advanced.header.title", "Advanced Redaction Settings")
+ },
+ tips: [
+ {
+ title: t("redact.tooltip.advanced.color.title", "Box Color & Padding"),
+ description: t("redact.tooltip.advanced.color.text", "Customize the appearance of redaction boxes. Black is standard, but you can choose any color. Padding adds extra space around the found text."),
+ },
+ {
+ title: t("redact.tooltip.advanced.regex.title", "Use Regex"),
+ description: t("redact.tooltip.advanced.regex.text", "Enable regular expressions for advanced pattern matching. Useful for finding phone numbers, emails, or complex patterns."),
+ bullets: [
+ t("redact.tooltip.advanced.regex.bullet1", "Example: \\d{3}-\\d{3}-\\d{4} for phone numbers"),
+ t("redact.tooltip.advanced.regex.bullet2", "Use with caution - test thoroughly")
+ ]
+ },
+ {
+ title: t("redact.tooltip.advanced.wholeWord.title", "Whole Word Search"),
+ description: t("redact.tooltip.advanced.wholeWord.text", "Only match complete words, not partial matches. 'John' won't match 'Johnson' when enabled.")
+ },
+ {
+ title: t("redact.tooltip.advanced.convert.title", "Convert to PDF-Image"),
+ description: t("redact.tooltip.advanced.convert.text", "Converts the PDF to an image-based PDF after redaction. This ensures text behind redaction boxes is completely removed and unrecoverable.")
+ }
+ ]
+ };
+};
diff --git a/frontend/src/tools/Redact.tsx b/frontend/src/tools/Redact.tsx
index 3a4d67d7c..c902ce30a 100644
--- a/frontend/src/tools/Redact.tsx
+++ b/frontend/src/tools/Redact.tsx
@@ -1,14 +1,23 @@
import { useTranslation } from "react-i18next";
+import { useState } from "react";
import { createToolFlow } from "../components/tools/shared/createToolFlow";
-import RedactSettings from "../components/tools/redact/RedactSettings";
+import RedactModeStep from "../components/tools/redact/RedactModeStep";
+import RedactWordsStep from "../components/tools/redact/RedactWordsStep";
+import RedactAdvancedStep from "../components/tools/redact/RedactAdvancedStep";
import { useRedactParameters } from "../hooks/tools/redact/useRedactParameters";
import { useRedactOperation } from "../hooks/tools/redact/useRedactOperation";
import { useBaseTool } from "../hooks/tools/shared/useBaseTool";
import { BaseToolProps, ToolComponent } from "../types/tool";
+import { useRedactModeTips, useRedactWordsTips, useRedactAdvancedTips } from "../components/tooltips/useRedactTips";
const Redact = (props: BaseToolProps) => {
const { t } = useTranslation();
+ // State for managing step collapse status
+ const [methodCollapsed, setMethodCollapsed] = useState(false);
+ const [wordsCollapsed, setWordsCollapsed] = useState(false);
+ const [advancedCollapsed, setAdvancedCollapsed] = useState(true);
+
const base = useBaseTool(
'redact',
useRedactParameters,
@@ -16,6 +25,11 @@ const Redact = (props: BaseToolProps) => {
props
);
+ // Tooltips for each step
+ const modeTips = useRedactModeTips();
+ const wordsTips = useRedactWordsTips();
+ const advancedTips = useRedactAdvancedTips();
+
const isExecuteDisabled = () => {
if (base.params.parameters.mode === 'manual') {
return true; // Manual mode not implemented yet
@@ -23,6 +37,11 @@ const Redact = (props: BaseToolProps) => {
return !base.params.validateParameters() || !base.hasFiles || !base.endpointEnabled;
};
+ // Compute actual collapsed state based on results and user state
+ const getActualCollapsedState = (userCollapsed: boolean) => {
+ return base.hasResults ? true : userCollapsed; // Force collapse when results are shown
+ };
+
return createToolFlow({
files: {
selectedFiles: base.selectedFiles,
@@ -30,11 +49,38 @@ const Redact = (props: BaseToolProps) => {
},
steps: [
{
- title: "Settings",
- isCollapsed: base.settingsCollapsed,
- onCollapsedClick: base.settingsCollapsed ? base.handleSettingsReset : undefined,
+ title: t("redact.steps.method", "Method"),
+ isCollapsed: getActualCollapsedState(methodCollapsed),
+ onCollapsedClick: () => base.settingsCollapsed ? base.handleSettingsReset() : setMethodCollapsed(!methodCollapsed),
+ tooltip: modeTips,
content: (
-
+ ),
+ },
+ {
+ title: t("redact.steps.words", "Words to Redact"),
+ isCollapsed: getActualCollapsedState(wordsCollapsed),
+ onCollapsedClick: () => base.settingsCollapsed ? base.handleSettingsReset() : setWordsCollapsed(!wordsCollapsed),
+ tooltip: wordsTips,
+ content: (
+
+ ),
+ },
+ {
+ title: t("redact.steps.advanced", "Advanced Settings"),
+ isCollapsed: getActualCollapsedState(advancedCollapsed),
+ onCollapsedClick: () => base.settingsCollapsed ? base.handleSettingsReset() : setAdvancedCollapsed(!advancedCollapsed),
+ tooltip: advancedTips,
+ content: (
+