mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-16 19:33:11 +02:00
feat(redaction): update to embedPDF v2.4.0 with unified redaction mode support (#5652)
# Description of Changes Bump to EmbedPDF v2.4.0 plus update to the redaction methods <!-- Please provide a summary of the changes, including: - What was changed - Why the change was made - Any challenges encountered Closes #(issue_number) --> --- ## Checklist ### General - [X] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [X] 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) - [X] I have performed a self-review of my own code - [X] 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) ### Translations (if applicable) - [ ] I ran [`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md) ### 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) - [X] 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. --------- Signed-off-by: Balázs Szücs <[email protected]>
This commit is contained in:
@@ -14,51 +14,45 @@ interface ManualRedactionControlsProps {
|
||||
/**
|
||||
* ManualRedactionControls provides UI for manual PDF redaction in the tool panel.
|
||||
* Displays controls for marking text/areas for redaction and applying them.
|
||||
* Uses our RedactionContext which bridges to the EmbedPDF API.
|
||||
*/
|
||||
export default function ManualRedactionControls({ disabled = false }: ManualRedactionControlsProps) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
// Use our RedactionContext which bridges to EmbedPDF
|
||||
const { activateTextSelection, activateMarquee, redactionsApplied, setActiveType } = useRedaction();
|
||||
const { pendingCount, activeType, isRedacting, isBridgeReady } = useRedactionMode();
|
||||
|
||||
const { pendingCount, activeType, isBridgeReady } = useRedactionMode();
|
||||
|
||||
// Get viewer context to manage annotation mode and save changes
|
||||
const { isAnnotationMode, setAnnotationMode, applyChanges, activeFileIndex } = useViewer();
|
||||
|
||||
|
||||
// Get signature context to deactivate annotation tools when switching to redaction
|
||||
const { signatureApiRef } = useSignature();
|
||||
|
||||
|
||||
// Check which tool is active based on activeType
|
||||
const isSelectionActive = activeType === 'redactSelection';
|
||||
const isMarqueeActive = activeType === 'marqueeRedact';
|
||||
|
||||
// Track if we've auto-activated
|
||||
|
||||
// Track if we've auto-activated for the current bridge session
|
||||
const hasAutoActivated = useRef(false);
|
||||
|
||||
|
||||
// Track the previous file index to detect file switches
|
||||
const prevFileIndexRef = useRef<number>(activeFileIndex);
|
||||
|
||||
// Track previous pending count to detect when all redactions are applied
|
||||
const prevPendingCountRef = useRef<number>(pendingCount);
|
||||
|
||||
// Track if we're currently auto-saving to prevent re-entry
|
||||
const isAutoSavingRef = useRef(false);
|
||||
|
||||
// Auto-activate selection mode when the API bridge becomes ready
|
||||
// This ensures at least one tool is selected when entering manual redaction mode
|
||||
// This ensures Mark Text is pre-selected when entering manual redaction mode
|
||||
useEffect(() => {
|
||||
if (isBridgeReady && !disabled && !isRedacting && !hasAutoActivated.current) {
|
||||
if (isBridgeReady && !disabled && !hasAutoActivated.current) {
|
||||
hasAutoActivated.current = true;
|
||||
// Small delay to ensure EmbedPDF is fully ready
|
||||
const timer = setTimeout(() => {
|
||||
// Deactivate annotation mode to show redaction layer
|
||||
setAnnotationMode(false);
|
||||
// Pre-select the Mark Text tool
|
||||
activateTextSelection();
|
||||
}, 100);
|
||||
}, 150);
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, [isBridgeReady, disabled, isRedacting, activateTextSelection, setAnnotationMode]);
|
||||
}, [isBridgeReady, disabled, activateTextSelection, setAnnotationMode]);
|
||||
|
||||
// Reset auto-activation flag when disabled changes or bridge becomes not ready
|
||||
useEffect(() => {
|
||||
@@ -72,50 +66,19 @@ export default function ManualRedactionControls({ disabled = false }: ManualReda
|
||||
useEffect(() => {
|
||||
if (prevFileIndexRef.current !== activeFileIndex) {
|
||||
prevFileIndexRef.current = activeFileIndex;
|
||||
|
||||
|
||||
// Reset active type to null when switching files
|
||||
// This makes both buttons appear unselected, requiring the user to re-click
|
||||
// which ensures proper activation on the new PDF
|
||||
if (isSelectionActive || isMarqueeActive) {
|
||||
setActiveType(null);
|
||||
}
|
||||
|
||||
// Reset auto-activation flag so new file can auto-activate
|
||||
hasAutoActivated.current = false;
|
||||
}
|
||||
}, [activeFileIndex, isSelectionActive, isMarqueeActive, setActiveType]);
|
||||
|
||||
// Auto-save when all pending redactions have been applied
|
||||
// This triggers when the user clicks "Apply (permanent)" on the last pending redaction
|
||||
useEffect(() => {
|
||||
const hadPendingBefore = prevPendingCountRef.current > 0;
|
||||
const hasNoPendingNow = pendingCount === 0;
|
||||
const wasJustCleared = hadPendingBefore && hasNoPendingNow;
|
||||
|
||||
// Update the ref for next comparison
|
||||
prevPendingCountRef.current = pendingCount;
|
||||
|
||||
// Auto-save when:
|
||||
// - pendingCount just went from > 0 to 0 (user applied the last pending redaction)
|
||||
// - redactionsApplied is true (at least one redaction was committed)
|
||||
// - not already auto-saving
|
||||
// - applyChanges is available
|
||||
if (wasJustCleared && redactionsApplied && !isAutoSavingRef.current && applyChanges) {
|
||||
isAutoSavingRef.current = true;
|
||||
|
||||
// Small delay to ensure UI updates before save
|
||||
const timer = setTimeout(async () => {
|
||||
try {
|
||||
await applyChanges();
|
||||
} finally {
|
||||
isAutoSavingRef.current = false;
|
||||
}
|
||||
}, 100);
|
||||
|
||||
return () => {
|
||||
clearTimeout(timer);
|
||||
isAutoSavingRef.current = false;
|
||||
};
|
||||
}
|
||||
}, [pendingCount, redactionsApplied, applyChanges]);
|
||||
|
||||
const handleSelectionClick = () => {
|
||||
// Deactivate annotation mode and tools to switch to redaction layer
|
||||
if (isAnnotationMode) {
|
||||
@@ -129,7 +92,7 @@ export default function ManualRedactionControls({ disabled = false }: ManualReda
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (isSelectionActive && !isAnnotationMode) {
|
||||
// If already active and not coming from annotation mode, switch to marquee
|
||||
activateMarquee();
|
||||
@@ -151,7 +114,7 @@ export default function ManualRedactionControls({ disabled = false }: ManualReda
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (isMarqueeActive && !isAnnotationMode) {
|
||||
// If already active and not coming from annotation mode, switch to selection
|
||||
activateTextSelection();
|
||||
@@ -170,7 +133,7 @@ export default function ManualRedactionControls({ disabled = false }: ManualReda
|
||||
// Check if there are unsaved changes to save (pending redactions OR applied redactions)
|
||||
// Save Changes button will apply pending redactions and then save everything
|
||||
const hasUnsavedChanges = pendingCount > 0 || redactionsApplied;
|
||||
|
||||
|
||||
// Check if API is available - use isBridgeReady state instead of ref (refs don't trigger re-renders)
|
||||
const isApiReady = isBridgeReady;
|
||||
|
||||
@@ -181,7 +144,7 @@ export default function ManualRedactionControls({ disabled = false }: ManualReda
|
||||
<Text size="sm" fw={500}>
|
||||
{t('redact.manual.title', 'Redaction Tools')}
|
||||
</Text>
|
||||
|
||||
|
||||
<Text size="xs" c="dimmed">
|
||||
{t('redact.manual.instructions', 'Select text or draw areas on the PDF to mark content for redaction.')}
|
||||
</Text>
|
||||
@@ -196,7 +159,7 @@ export default function ManualRedactionControls({ disabled = false }: ManualReda
|
||||
disabled={disabled || !isApiReady}
|
||||
size="sm"
|
||||
styles={{
|
||||
root: {
|
||||
root: {
|
||||
minWidth: 0,
|
||||
},
|
||||
label: { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' },
|
||||
@@ -214,7 +177,7 @@ export default function ManualRedactionControls({ disabled = false }: ManualReda
|
||||
disabled={disabled || !isApiReady}
|
||||
size="sm"
|
||||
styles={{
|
||||
root: {
|
||||
root: {
|
||||
minWidth: 0,
|
||||
},
|
||||
label: { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' },
|
||||
|
||||
Reference in New Issue
Block a user