prepare manual redaction service
This commit is contained in:
parent
70b7d0738c
commit
8e97ed44ed
@ -0,0 +1,704 @@
|
||||
import {
|
||||
Component,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
Inject,
|
||||
Input,
|
||||
NgZone,
|
||||
OnChanges,
|
||||
OnInit,
|
||||
Output,
|
||||
SimpleChanges,
|
||||
ViewChild,
|
||||
} from '@angular/core';
|
||||
import { Dossier, File, IHeaderElement, IManualRedactionEntry, RotationTypes } from '@red/domain';
|
||||
import { Core, WebViewerInstance } from '@pdftron/webviewer';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import {
|
||||
ManualRedactionEntryType,
|
||||
ManualRedactionEntryTypes,
|
||||
ManualRedactionEntryWrapper,
|
||||
} from '@models/file/manual-redaction-entry.wrapper';
|
||||
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||
import { ManualRedactionService } from '../../services/manual-redaction.service';
|
||||
import { environment } from '@environments/environment';
|
||||
import { AnnotationDrawService } from '../../services/annotation-draw.service';
|
||||
import { AnnotationActionsService } from '../../services/annotation-actions.service';
|
||||
import { UserPreferenceService } from '@services/user-preference.service';
|
||||
import { BASE_HREF } from '../../../../../../tokens';
|
||||
import { ConfigService } from '@services/config.service';
|
||||
import { AutoUnsubscribe, ConfirmationDialogInput, LoadingService } from '@iqser/common-ui';
|
||||
import { DossiersDialogService } from '../../../../services/dossiers-dialog.service';
|
||||
import { loadCompareDocumentWrapper } from '../../../../utils/compare-mode.utils';
|
||||
import { PdfViewer } from '../../services/pdf-viewer.service';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { toPosition } from '../../../../utils/pdf-calculation.utils';
|
||||
import { ViewModeService } from '../../services/view-mode.service';
|
||||
import { MultiSelectService } from '../../services/multi-select.service';
|
||||
import { FilePreviewStateService } from '../../services/file-preview-state.service';
|
||||
import { tap, withLatestFrom } from 'rxjs/operators';
|
||||
import { PageRotationService } from '../../services/page-rotation.service';
|
||||
import { ALLOWED_KEYBOARD_SHORTCUTS, HeaderElements, TextPopups } from '../../shared/constants';
|
||||
import Tools = Core.Tools;
|
||||
import TextTool = Tools.TextTool;
|
||||
import Annotation = Core.Annotations.Annotation;
|
||||
|
||||
function getDivider(hiddenOn?: readonly ('desktop' | 'mobile' | 'tablet')[]) {
|
||||
return {
|
||||
type: 'divider',
|
||||
hidden: hiddenOn,
|
||||
};
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-pdf-viewer',
|
||||
templateUrl: './pdf-viewer.component.html',
|
||||
styleUrls: ['./pdf-viewer.component.scss'],
|
||||
})
|
||||
export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnChanges {
|
||||
@Input() dossier: Dossier;
|
||||
@Input() canPerformActions = false;
|
||||
@Input() annotations: AnnotationWrapper[];
|
||||
@Output() readonly fileReady = new EventEmitter();
|
||||
@Output() readonly annotationSelected = new EventEmitter<string[]>();
|
||||
@Output() readonly manualAnnotationRequested = new EventEmitter<ManualRedactionEntryWrapper>();
|
||||
@Output() readonly pageChanged = new EventEmitter<number>();
|
||||
@Output() readonly keyUp = new EventEmitter<KeyboardEvent>();
|
||||
@Output() readonly viewerReady = new EventEmitter<WebViewerInstance>();
|
||||
@Output() readonly annotationsChanged = new EventEmitter<AnnotationWrapper>();
|
||||
@ViewChild('viewer', { static: true }) viewer: ElementRef;
|
||||
@ViewChild('compareFileInput', { static: true }) compareFileInput: ElementRef;
|
||||
instance: WebViewerInstance;
|
||||
documentViewer: Core.DocumentViewer;
|
||||
annotationManager: Core.AnnotationManager;
|
||||
private _selectedText = '';
|
||||
|
||||
constructor(
|
||||
@Inject(BASE_HREF) private readonly _baseHref: string,
|
||||
private readonly _translateService: TranslateService,
|
||||
private readonly _manualRedactionService: ManualRedactionService,
|
||||
private readonly _dialogService: DossiersDialogService,
|
||||
private readonly _ngZone: NgZone,
|
||||
private readonly _activatedRoute: ActivatedRoute,
|
||||
private readonly _userPreferenceService: UserPreferenceService,
|
||||
private readonly _annotationDrawService: AnnotationDrawService,
|
||||
private readonly _annotationActionsService: AnnotationActionsService,
|
||||
private readonly _configService: ConfigService,
|
||||
private readonly _loadingService: LoadingService,
|
||||
private readonly _pageRotationService: PageRotationService,
|
||||
readonly stateService: FilePreviewStateService,
|
||||
readonly viewModeService: ViewModeService,
|
||||
readonly multiSelectService: MultiSelectService,
|
||||
readonly pdf: PdfViewer,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
private get _toggleTooltipsBtnTitle(): string {
|
||||
return this._translateService.instant(_('pdf-viewer.toggle-tooltips'), {
|
||||
active: this._userPreferenceService.getFilePreviewTooltipsPreference(),
|
||||
});
|
||||
}
|
||||
|
||||
private get _toggleTooltipsIcon(): string {
|
||||
return this._convertPath(
|
||||
this._userPreferenceService.getFilePreviewTooltipsPreference()
|
||||
? '/assets/icons/general/pdftron-action-enable-tooltips.svg'
|
||||
: '/assets/icons/general/pdftron-action-disable-tooltips.svg',
|
||||
);
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this._setReadyAndInitialState = this._setReadyAndInitialState.bind(this);
|
||||
await this._loadViewer();
|
||||
|
||||
this.addActiveScreenSubscription = this.stateService.blob$
|
||||
.pipe(
|
||||
withLatestFrom(this.stateService.file$),
|
||||
tap(() => (this.pdf.ready = false)),
|
||||
tap(([blob, file]) => this._loadDocument(blob, file)),
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
async ngOnChanges(changes: SimpleChanges): Promise<void> {
|
||||
if (!this.instance) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (changes.canPerformActions) {
|
||||
await this._handleCustomActions();
|
||||
}
|
||||
}
|
||||
|
||||
uploadFile(files: FileList) {
|
||||
const fileToCompare = files[0];
|
||||
this.compareFileInput.nativeElement.value = null;
|
||||
|
||||
if (!fileToCompare) {
|
||||
console.error('No file to compare!');
|
||||
return;
|
||||
}
|
||||
|
||||
const fileReader = new FileReader();
|
||||
fileReader.onload = async () => {
|
||||
const pdfNet = this.instance.Core.PDFNet;
|
||||
|
||||
await pdfNet.initialize(environment.licenseKey ? atob(environment.licenseKey) : null);
|
||||
|
||||
const compareDocument = await pdfNet.PDFDoc.createFromBuffer(fileReader.result as ArrayBuffer);
|
||||
const blob = await this.stateService.blob;
|
||||
const currentDocument = await pdfNet.PDFDoc.createFromBuffer(await blob.arrayBuffer());
|
||||
|
||||
const loadCompareDocument = async () => {
|
||||
this._loadingService.start();
|
||||
this.pdf.ready = false;
|
||||
const mergedDocument = await pdfNet.PDFDoc.create();
|
||||
const file = await this.stateService.file;
|
||||
await loadCompareDocumentWrapper(
|
||||
currentDocument,
|
||||
compareDocument,
|
||||
mergedDocument,
|
||||
this.instance,
|
||||
file,
|
||||
() => {
|
||||
this.viewModeService.compareMode = true;
|
||||
},
|
||||
() => {
|
||||
this.pdf.navigateToPage(1);
|
||||
},
|
||||
this.instance.Core.PDFNet,
|
||||
);
|
||||
this._loadingService.stop();
|
||||
};
|
||||
|
||||
const currentDocumentPageCount = await currentDocument.getPageCount();
|
||||
const compareDocumentPageCount = await compareDocument.getPageCount();
|
||||
|
||||
if (currentDocumentPageCount !== compareDocumentPageCount) {
|
||||
this._dialogService.openDialog(
|
||||
'confirm',
|
||||
null,
|
||||
new ConfirmationDialogInput({
|
||||
title: _('confirmation-dialog.compare-file.title'),
|
||||
question: _('confirmation-dialog.compare-file.question'),
|
||||
translateParams: {
|
||||
fileName: fileToCompare.name,
|
||||
currentDocumentPageCount,
|
||||
compareDocumentPageCount,
|
||||
},
|
||||
}),
|
||||
loadCompareDocument,
|
||||
);
|
||||
} else {
|
||||
await loadCompareDocument();
|
||||
}
|
||||
};
|
||||
|
||||
fileReader.readAsArrayBuffer(fileToCompare);
|
||||
}
|
||||
|
||||
async closeCompareMode() {
|
||||
this.viewModeService.compareMode = false;
|
||||
const pdfNet = this.instance.Core.PDFNet;
|
||||
await pdfNet.initialize(environment.licenseKey ? atob(environment.licenseKey) : null);
|
||||
const blob = await this.stateService.blob;
|
||||
const currentDocument = await pdfNet.PDFDoc.createFromBuffer(await blob.arrayBuffer());
|
||||
|
||||
const filename = (await this.stateService.file).filename ?? 'document.pdf';
|
||||
this.instance.UI.loadDocument(currentDocument, { filename });
|
||||
|
||||
this.instance.UI.disableElements([HeaderElements.CLOSE_COMPARE_BUTTON]);
|
||||
this.instance.UI.enableElements([HeaderElements.COMPARE_BUTTON]);
|
||||
this.pdf.navigateToPage(1);
|
||||
}
|
||||
|
||||
private async _loadViewer() {
|
||||
this.instance = await this.pdf.loadViewer(this.viewer.nativeElement as HTMLElement);
|
||||
this.documentViewer = this.pdf.documentViewer;
|
||||
this.annotationManager = this.pdf.annotationManager;
|
||||
|
||||
this._setSelectionMode();
|
||||
this._configureElements();
|
||||
this.pdf.disableHotkeys();
|
||||
await this._configureTextPopup();
|
||||
|
||||
this.annotationManager.addEventListener('annotationSelected', (annotations: Annotation[], action) => {
|
||||
const nextAnnotations = this.multiSelectService.isEnabled ? this.annotationManager.getSelectedAnnotations() : annotations;
|
||||
this.annotationSelected.emit(nextAnnotations.map(ann => ann.Id));
|
||||
if (action === 'deselected') {
|
||||
this._toggleRectangleAnnotationAction(true);
|
||||
} else {
|
||||
if (!this.multiSelectService.isEnabled) {
|
||||
this.pdf.deselectAnnotations(this.annotations.filter(wrapper => !nextAnnotations.find(ann => ann.Id === wrapper.id)));
|
||||
}
|
||||
this._configureAnnotationSpecificActions(annotations);
|
||||
this._toggleRectangleAnnotationAction(annotations.length === 1 && annotations[0].ReadOnly);
|
||||
}
|
||||
});
|
||||
|
||||
this.annotationManager.addEventListener('annotationChanged', (annotations: Annotation[]) => {
|
||||
// when a rectangle is drawn,
|
||||
// it returns one annotation with tool name 'AnnotationCreateRectangle;
|
||||
// this will auto select rectangle after drawing
|
||||
if (annotations.length === 1 && annotations[0].ToolName === 'AnnotationCreateRectangle') {
|
||||
this.annotationManager.selectAnnotations(annotations);
|
||||
annotations[0].disableRotationControl();
|
||||
}
|
||||
});
|
||||
|
||||
this.documentViewer.addEventListener('pageNumberUpdated', (pageNumber: number) => {
|
||||
this.pdf.deselectAllAnnotations();
|
||||
this._ngZone.run(() => this.pageChanged.emit(pageNumber));
|
||||
return this._handleCustomActions();
|
||||
});
|
||||
|
||||
this.documentViewer.addEventListener('documentLoaded', this._setReadyAndInitialState);
|
||||
|
||||
this.documentViewer.addEventListener('keyUp', ($event: KeyboardEvent) => {
|
||||
// arrows and full-screen
|
||||
if (($event.target as HTMLElement)?.tagName?.toLowerCase() !== 'input') {
|
||||
if ($event.key.startsWith('Arrow') || $event.key === 'f') {
|
||||
this._ngZone.run(() => this.keyUp.emit($event));
|
||||
$event.preventDefault();
|
||||
$event.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
if (!ALLOWED_KEYBOARD_SHORTCUTS.includes($event.key)) {
|
||||
$event.preventDefault();
|
||||
$event.stopPropagation();
|
||||
}
|
||||
});
|
||||
|
||||
this.documentViewer.addEventListener('textSelected', async (quads, selectedText, pageNumber: number) => {
|
||||
this._selectedText = selectedText;
|
||||
const textActions = [TextPopups.ADD_DICTIONARY, TextPopups.ADD_FALSE_POSITIVE];
|
||||
|
||||
const file = await this.stateService.file;
|
||||
|
||||
if (this.viewModeService.isCompare && pageNumber % 2 === 0) {
|
||||
this.instance.UI.disableElements(['textPopup']);
|
||||
} else {
|
||||
this.instance.UI.enableElements(['textPopup']);
|
||||
}
|
||||
|
||||
if (selectedText.length > 2 && this.canPerformActions && !this.pdf.isCurrentPageExcluded(file)) {
|
||||
this.instance.UI.enableElements(textActions);
|
||||
} else {
|
||||
this.instance.UI.disableElements(textActions);
|
||||
}
|
||||
});
|
||||
|
||||
this.instance.UI.iframeWindow.addEventListener('visibilityChanged', (event: any) => {
|
||||
if (event.detail.element === 'searchPanel') {
|
||||
const inputElement = this.instance.UI.iframeWindow.document.getElementById('SearchPanel__input') as HTMLInputElement;
|
||||
setTimeout(() => {
|
||||
inputElement.value = '';
|
||||
}, 0);
|
||||
if (!event.detail.isVisible) {
|
||||
this.documentViewer.clearSearchResults();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private _setInitialDisplayMode() {
|
||||
this.instance.UI.setFitMode('FitPage');
|
||||
const instanceDisplayMode = this.documentViewer.getDisplayModeManager().getDisplayMode();
|
||||
instanceDisplayMode.mode = this.viewModeService.isCompare ? 'Facing' : 'Single';
|
||||
this.documentViewer.getDisplayModeManager().setDisplayMode(instanceDisplayMode);
|
||||
}
|
||||
|
||||
private _convertPath(path: string): string {
|
||||
return this._baseHref + path;
|
||||
}
|
||||
|
||||
private _setSelectionMode(): void {
|
||||
const textTool = this.instance.Core.Tools.TextTool as unknown as TextTool;
|
||||
textTool.SELECTION_MODE = this._configService.values.SELECTION_MODE;
|
||||
}
|
||||
|
||||
private _toggleRectangleAnnotationAction(readonly = false) {
|
||||
if (!readonly) {
|
||||
this.instance.UI.enableElements([TextPopups.ADD_RECTANGLE]);
|
||||
} else {
|
||||
this.instance.UI.disableElements([TextPopups.ADD_RECTANGLE]);
|
||||
}
|
||||
}
|
||||
|
||||
private _configureElements() {
|
||||
this.instance.UI.disableElements([
|
||||
'pageNavOverlay',
|
||||
'menuButton',
|
||||
'selectToolButton',
|
||||
'textHighlightToolButton',
|
||||
'textUnderlineToolButton',
|
||||
'textSquigglyToolButton',
|
||||
'textStrikeoutToolButton',
|
||||
'viewControlsButton',
|
||||
'contextMenuPopup',
|
||||
'linkButton',
|
||||
'toggleNotesButton',
|
||||
'notesPanel',
|
||||
'thumbnailControl',
|
||||
'documentControl',
|
||||
'ribbons',
|
||||
'toolsHeader',
|
||||
'rotateClockwiseButton',
|
||||
'rotateCounterClockwiseButton',
|
||||
'annotationStyleEditButton',
|
||||
'annotationGroupButton',
|
||||
]);
|
||||
|
||||
const applyRotation: IHeaderElement = {
|
||||
type: 'customElement',
|
||||
dataElement: HeaderElements.APPLY_ROTATION,
|
||||
render: () => {
|
||||
const paragraph = document.createElement('p');
|
||||
paragraph.innerText = this._translateService.instant('page-rotation.apply');
|
||||
paragraph.style.cssText = `
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: #DD4D50;
|
||||
cursor: pointer;
|
||||
margin: 0 12px;
|
||||
`;
|
||||
paragraph.addEventListener('click', async () => {
|
||||
await this._pageRotationService.applyRotation();
|
||||
});
|
||||
return paragraph;
|
||||
},
|
||||
};
|
||||
const discardRotation: IHeaderElement = {
|
||||
type: 'customElement',
|
||||
dataElement: HeaderElements.DISCARD_ROTATION,
|
||||
render: () => {
|
||||
const paragraph = document.createElement('p');
|
||||
paragraph.innerText = this._translateService.instant('page-rotation.discard');
|
||||
paragraph.style.cssText = `
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: #283241;
|
||||
cursor: pointer;
|
||||
opacity: 0.7;
|
||||
`;
|
||||
paragraph.addEventListener('click', () => {
|
||||
this._pageRotationService.discardRotation();
|
||||
});
|
||||
return paragraph;
|
||||
},
|
||||
};
|
||||
|
||||
const divider = getDivider();
|
||||
const headerItems: IHeaderElement[] = [
|
||||
divider,
|
||||
{
|
||||
type: 'actionButton',
|
||||
element: 'compare',
|
||||
dataElement: HeaderElements.COMPARE_BUTTON,
|
||||
img: this._convertPath('/assets/icons/general/pdftron-action-compare.svg'),
|
||||
title: 'Compare',
|
||||
onClick: () => {
|
||||
this.compareFileInput.nativeElement.click();
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'actionButton',
|
||||
element: 'closeCompare',
|
||||
dataElement: HeaderElements.CLOSE_COMPARE_BUTTON,
|
||||
img: this._convertPath('/assets/icons/general/pdftron-action-close-compare.svg'),
|
||||
title: 'Leave Compare Mode',
|
||||
onClick: async () => {
|
||||
await this.closeCompareMode();
|
||||
},
|
||||
},
|
||||
divider,
|
||||
{
|
||||
type: 'actionButton',
|
||||
element: 'tooltips',
|
||||
dataElement: HeaderElements.TOGGLE_TOOLTIPS,
|
||||
img: this._toggleTooltipsIcon,
|
||||
title: this._toggleTooltipsBtnTitle,
|
||||
onClick: async () => {
|
||||
await this._userPreferenceService.toggleFilePreviewTooltipsPreference();
|
||||
this._updateTooltipsVisibility();
|
||||
this.instance.UI.updateElement(HeaderElements.TOGGLE_TOOLTIPS, {
|
||||
title: this._toggleTooltipsBtnTitle,
|
||||
img: this._toggleTooltipsIcon,
|
||||
});
|
||||
},
|
||||
},
|
||||
divider,
|
||||
{
|
||||
type: 'toolGroupButton',
|
||||
toolGroup: 'rectangleTools',
|
||||
dataElement: HeaderElements.SHAPE_TOOL_GROUP_BUTTON,
|
||||
img: this._convertPath('/assets/icons/general/rectangle.svg'),
|
||||
title: 'annotation.rectangle',
|
||||
},
|
||||
divider,
|
||||
{
|
||||
type: 'actionButton',
|
||||
element: 'tooltips',
|
||||
dataElement: HeaderElements.ROTATE_LEFT_BUTTON,
|
||||
img: this._convertPath('/assets/icons/general/rotate-left.svg'),
|
||||
onClick: () => this._pageRotationService.addRotation(RotationTypes.LEFT),
|
||||
},
|
||||
{
|
||||
type: 'actionButton',
|
||||
element: 'tooltips',
|
||||
dataElement: HeaderElements.ROTATE_RIGHT_BUTTON,
|
||||
img: this._convertPath('/assets/icons/general/rotate-right.svg'),
|
||||
onClick: () => this._pageRotationService.addRotation(RotationTypes.RIGHT),
|
||||
},
|
||||
applyRotation,
|
||||
discardRotation,
|
||||
divider,
|
||||
];
|
||||
|
||||
this.instance.UI.setHeaderItems(header => {
|
||||
header.getItems().splice(8, 0, ...headerItems);
|
||||
});
|
||||
|
||||
this.instance.UI.disableElements([
|
||||
HeaderElements.CLOSE_COMPARE_BUTTON,
|
||||
HeaderElements.APPLY_ROTATION,
|
||||
HeaderElements.DISCARD_ROTATION,
|
||||
]);
|
||||
|
||||
const dossierTemplateId = this.dossier.dossierTemplateId;
|
||||
|
||||
this.documentViewer.getTool('AnnotationCreateRectangle').setStyles({
|
||||
StrokeThickness: 2,
|
||||
StrokeColor: this._annotationDrawService.getAndConvertColor(dossierTemplateId, 'manual'),
|
||||
FillColor: this._annotationDrawService.getAndConvertColor(dossierTemplateId, 'manual'),
|
||||
Opacity: 0.6,
|
||||
});
|
||||
}
|
||||
|
||||
private _configureAnnotationSpecificActions(viewerAnnotations: Annotation[]) {
|
||||
if (!this.canPerformActions) {
|
||||
return;
|
||||
}
|
||||
|
||||
const annotationWrappers = viewerAnnotations.map(va => this.annotations.find(a => a.id === va.Id)).filter(va => !!va);
|
||||
this.instance.UI.annotationPopup.update([]);
|
||||
|
||||
if (annotationWrappers.length === 0) {
|
||||
this._configureRectangleAnnotationPopup(viewerAnnotations[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Add hide action as last item
|
||||
const allAnnotationsHaveImageAction = annotationWrappers.reduce((acc, next) => acc && next.isImage, true);
|
||||
if (allAnnotationsHaveImageAction) {
|
||||
const allAreVisible = viewerAnnotations.reduce((acc, next) => next.isVisible() && acc, true);
|
||||
|
||||
this.instance.UI.annotationPopup.add([
|
||||
{
|
||||
type: 'actionButton',
|
||||
img: allAreVisible
|
||||
? this._convertPath('/assets/icons/general/visibility-off.svg')
|
||||
: this._convertPath('/assets/icons/general/visibility.svg'),
|
||||
title: this._translateService.instant(`annotation-actions.${allAreVisible ? 'hide' : 'show'}`),
|
||||
onClick: () => {
|
||||
this._ngZone.run(() => {
|
||||
if (allAreVisible) {
|
||||
this.annotationManager.hideAnnotations(viewerAnnotations);
|
||||
} else {
|
||||
this.annotationManager.showAnnotations(viewerAnnotations);
|
||||
}
|
||||
this.annotationManager.deselectAllAnnotations();
|
||||
this._annotationActionsService.updateHiddenAnnotation(this.annotations, viewerAnnotations, allAreVisible);
|
||||
});
|
||||
},
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
const actions = this._annotationActionsService.getViewerAvailableActions(this.dossier, annotationWrappers, this.annotationsChanged);
|
||||
this.instance.UI.annotationPopup.add(actions);
|
||||
}
|
||||
|
||||
private _configureRectangleAnnotationPopup(annotation: Annotation) {
|
||||
if (!this.viewModeService.isCompare || annotation.getPageNumber() % 2 === 1) {
|
||||
this.instance.UI.annotationPopup.add([
|
||||
{
|
||||
type: 'actionButton',
|
||||
dataElement: TextPopups.ADD_RECTANGLE,
|
||||
img: this._convertPath('/assets/icons/general/pdftron-action-add-redaction.svg'),
|
||||
title: this.#getTitle(ManualRedactionEntryTypes.REDACTION),
|
||||
onClick: () => this._addRectangleManualRedaction(),
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private _addRectangleManualRedaction() {
|
||||
const activeAnnotation = this.annotationManager.getSelectedAnnotations()[0];
|
||||
const activePage = activeAnnotation.getPageNumber();
|
||||
const quads = [this._annotationDrawService.annotationToQuads(activeAnnotation)];
|
||||
const manualRedaction = this._getManualRedaction({ [activePage]: quads });
|
||||
this._cleanUpSelectionAndButtonState();
|
||||
|
||||
this.manualAnnotationRequested.emit(new ManualRedactionEntryWrapper(quads, manualRedaction, 'REDACTION', activeAnnotation.Id));
|
||||
}
|
||||
|
||||
private _cleanUpSelectionAndButtonState() {
|
||||
const rectangleElements = [HeaderElements.SHAPE_TOOL_GROUP_BUTTON];
|
||||
this.pdf.deselectAllAnnotations();
|
||||
this.instance.UI.disableElements(rectangleElements);
|
||||
this.instance.UI.enableElements(rectangleElements);
|
||||
}
|
||||
|
||||
private _configureTextPopup() {
|
||||
const searchButton = {
|
||||
type: 'actionButton',
|
||||
img: this._convertPath('/assets/icons/general/pdftron-action-search.svg'),
|
||||
title: this._translateService.instant('pdf-viewer.text-popup.actions.search'),
|
||||
onClick: () => {
|
||||
const text = this.documentViewer.getSelectedText();
|
||||
const searchOptions = {
|
||||
caseSensitive: true, // match case
|
||||
wholeWord: true, // match whole words only
|
||||
wildcard: false, // allow using '*' as a wildcard value
|
||||
regex: false, // string is treated as a regular expression
|
||||
searchUp: false, // search from the end of the document upwards
|
||||
ambientString: true, // return ambient string as part of the result
|
||||
};
|
||||
this.instance.UI.openElements(['searchPanel']);
|
||||
setTimeout(() => this.instance.UI.searchTextFull(text, searchOptions), 250);
|
||||
},
|
||||
};
|
||||
const popups: IHeaderElement[] = [searchButton];
|
||||
|
||||
// Adding directly to the false-positive dict is only available in dev-mode
|
||||
if (this._userPreferenceService.areDevFeaturesEnabled) {
|
||||
popups.push({
|
||||
type: 'actionButton',
|
||||
dataElement: TextPopups.ADD_FALSE_POSITIVE,
|
||||
img: this._convertPath('/assets/icons/general/pdftron-action-false-positive.svg'),
|
||||
title: this.#getTitle(ManualRedactionEntryTypes.FALSE_POSITIVE),
|
||||
onClick: () => this._addManualRedactionOfType(ManualRedactionEntryTypes.FALSE_POSITIVE),
|
||||
});
|
||||
}
|
||||
|
||||
popups.push({
|
||||
type: 'actionButton',
|
||||
dataElement: TextPopups.ADD_REDACTION,
|
||||
img: this._convertPath('/assets/icons/general/pdftron-action-add-redaction.svg'),
|
||||
title: this.#getTitle(ManualRedactionEntryTypes.REDACTION),
|
||||
onClick: () => this._addManualRedactionOfType(ManualRedactionEntryTypes.REDACTION),
|
||||
});
|
||||
popups.push({
|
||||
type: 'actionButton',
|
||||
dataElement: TextPopups.ADD_DICTIONARY,
|
||||
img: this._convertPath('/assets/icons/general/pdftron-action-add-dict.svg'),
|
||||
title: this.#getTitle(ManualRedactionEntryTypes.DICTIONARY),
|
||||
onClick: () => this._addManualRedactionOfType(ManualRedactionEntryTypes.DICTIONARY),
|
||||
});
|
||||
|
||||
this.instance.UI.textPopup.add(popups);
|
||||
|
||||
return this._handleCustomActions();
|
||||
}
|
||||
|
||||
#getTitle(type: ManualRedactionEntryType) {
|
||||
return this._translateService.instant(this._manualRedactionService.getTitle(type, this.dossier));
|
||||
}
|
||||
|
||||
private _addManualRedactionOfType(type: ManualRedactionEntryType) {
|
||||
const selectedQuads: Readonly<Record<string, Core.Math.Quad[]>> = this.documentViewer.getSelectedTextQuads();
|
||||
const text = this.documentViewer.getSelectedText();
|
||||
const manualRedaction = this._getManualRedaction(selectedQuads, text, true);
|
||||
this.manualAnnotationRequested.emit(new ManualRedactionEntryWrapper(selectedQuads, manualRedaction, type));
|
||||
}
|
||||
|
||||
private async _handleCustomActions() {
|
||||
this.instance.UI.setToolMode('AnnotationEdit');
|
||||
const elementsToToggle = [
|
||||
TextPopups.ADD_REDACTION,
|
||||
TextPopups.ADD_RECTANGLE,
|
||||
TextPopups.ADD_FALSE_POSITIVE,
|
||||
HeaderElements.SHAPE_TOOL_GROUP_BUTTON,
|
||||
HeaderElements.ANNOTATION_POPUP,
|
||||
];
|
||||
|
||||
const isCurrentPageExcluded = this.pdf.isCurrentPageExcluded(await this.stateService.file);
|
||||
|
||||
if (this.canPerformActions && !isCurrentPageExcluded) {
|
||||
try {
|
||||
this.instance.UI.enableTools(['AnnotationCreateRectangle']);
|
||||
} catch (e) {
|
||||
// happens
|
||||
}
|
||||
this.instance.UI.enableElements(elementsToToggle);
|
||||
|
||||
if (this._selectedText.length > 2) {
|
||||
this.instance.UI.enableElements([TextPopups.ADD_DICTIONARY, TextPopups.ADD_FALSE_POSITIVE]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let elementsToDisable = [...elementsToToggle, TextPopups.ADD_RECTANGLE];
|
||||
|
||||
if (isCurrentPageExcluded) {
|
||||
const allowedActionsWhenPageExcluded: string[] = [
|
||||
HeaderElements.ANNOTATION_POPUP,
|
||||
TextPopups.ADD_RECTANGLE,
|
||||
TextPopups.ADD_REDACTION,
|
||||
HeaderElements.SHAPE_TOOL_GROUP_BUTTON,
|
||||
];
|
||||
elementsToDisable = elementsToDisable.filter(element => !allowedActionsWhenPageExcluded.includes(element));
|
||||
} else {
|
||||
this.instance.UI.disableTools(['AnnotationCreateRectangle']);
|
||||
}
|
||||
|
||||
this.instance.UI.disableElements(elementsToDisable);
|
||||
}
|
||||
|
||||
private _getManualRedaction(
|
||||
quads: Readonly<Record<string, Core.Math.Quad[]>>,
|
||||
text?: string,
|
||||
convertQuads = false,
|
||||
): IManualRedactionEntry {
|
||||
const entry: IManualRedactionEntry = { positions: [] };
|
||||
|
||||
for (const key of Object.keys(quads)) {
|
||||
for (const quad of quads[key]) {
|
||||
const page = parseInt(key, 10);
|
||||
const pageHeight = this.documentViewer.getPageHeight(page);
|
||||
entry.positions.push(toPosition(page, pageHeight, convertQuads ? this.pdf.translateQuad(page, quad) : quad));
|
||||
}
|
||||
}
|
||||
|
||||
entry.value = text;
|
||||
entry.rectangle = !text;
|
||||
return entry;
|
||||
}
|
||||
|
||||
private async _loadDocument(blob: Blob, file: File) {
|
||||
const document = await this.instance.Core.documentViewer.getDocument()?.getPDFDoc();
|
||||
await document?.lock();
|
||||
this.instance.UI.loadDocument(blob, { filename: file?.filename ?? 'document.pdf' });
|
||||
this._pageRotationService.clearRotationsHideActions();
|
||||
}
|
||||
|
||||
private _setReadyAndInitialState(): void {
|
||||
this._ngZone.run(() => {
|
||||
this.viewerReady.emit(this.instance);
|
||||
const routePageNumber: number = this._activatedRoute.snapshot.queryParams.page;
|
||||
this.pageChanged.emit(routePageNumber || 1);
|
||||
this._setInitialDisplayMode();
|
||||
this._updateTooltipsVisibility();
|
||||
});
|
||||
}
|
||||
|
||||
private _updateTooltipsVisibility(): void {
|
||||
const current = this._userPreferenceService.getFilePreviewTooltipsPreference();
|
||||
this.instance.UI.setAnnotationContentOverlayHandler(() => (current ? undefined : false));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { IqserIconsModule } from '@iqser/common-ui';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { SharedModule } from '@shared/shared.module';
|
||||
import { SharedDossiersModule } from '../../shared/shared-dossiers.module';
|
||||
import { FilePreviewScreenComponent } from './file-preview-screen.component';
|
||||
import { FileWorkloadComponent } from './components/file-workload/file-workload.component';
|
||||
import { AnnotationDetailsComponent } from './components/annotation-details/annotation-details.component';
|
||||
import { AnnotationsListComponent } from './components/annotations-list/annotations-list.component';
|
||||
import { PageIndicatorComponent } from './components/page-indicator/page-indicator.component';
|
||||
import { PageExclusionComponent } from './components/page-exclusion/page-exclusion.component';
|
||||
import { PdfViewerComponent } from './components/pdf-viewer/pdf-viewer.component';
|
||||
import { AnnotationActionsComponent } from './components/annotation-actions/annotation-actions.component';
|
||||
import { CommentsComponent } from './components/comments/comments.component';
|
||||
import { DocumentInfoComponent } from './components/document-info/document-info.component';
|
||||
import { TypeAnnotationIconComponent } from './components/type-annotation-icon/type-annotation-icon.component';
|
||||
import { OverlayModule } from '@angular/cdk/overlay';
|
||||
import { ViewSwitchComponent } from './components/view-switch/view-switch.component';
|
||||
import { UserManagementComponent } from './components/user-management/user-management.component';
|
||||
import { AnnotationReferencesListComponent } from './components/annotation-references-list/annotation-references-list.component';
|
||||
import { AcceptRecommendationDialogComponent } from './dialogs/accept-recommendation-dialog/accept-recommendation-dialog.component';
|
||||
import { AnnotationCardComponent } from './components/annotation-card/annotation-card.component';
|
||||
import { AnnotationReferencesPageIndicatorComponent } from './components/annotation-references-page-indicator/annotation-references-page-indicator.component';
|
||||
import { HighlightsSeparatorComponent } from './components/highlights-separator/highlights-separator.component';
|
||||
import { PendingChangesGuard } from '../../../../guards/can-deactivate.guard';
|
||||
import { ManualRedactionService } from './services/manual-redaction.service';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: FilePreviewScreenComponent,
|
||||
pathMatch: 'full',
|
||||
data: { reuse: true },
|
||||
canDeactivate: [PendingChangesGuard],
|
||||
},
|
||||
];
|
||||
|
||||
const components = [
|
||||
FileWorkloadComponent,
|
||||
AnnotationDetailsComponent,
|
||||
AnnotationsListComponent,
|
||||
PageIndicatorComponent,
|
||||
PageExclusionComponent,
|
||||
PdfViewerComponent,
|
||||
AnnotationActionsComponent,
|
||||
CommentsComponent,
|
||||
DocumentInfoComponent,
|
||||
TypeAnnotationIconComponent,
|
||||
ViewSwitchComponent,
|
||||
UserManagementComponent,
|
||||
AcceptRecommendationDialogComponent,
|
||||
AnnotationReferencesListComponent,
|
||||
AnnotationCardComponent,
|
||||
AnnotationReferencesPageIndicatorComponent,
|
||||
HighlightsSeparatorComponent,
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
declarations: [FilePreviewScreenComponent, ...components],
|
||||
imports: [
|
||||
RouterModule.forChild(routes),
|
||||
CommonModule,
|
||||
SharedModule,
|
||||
SharedDossiersModule,
|
||||
IqserIconsModule,
|
||||
TranslateModule,
|
||||
OverlayModule,
|
||||
],
|
||||
providers: [ManualRedactionService],
|
||||
})
|
||||
export class FilePreviewModule {}
|
||||
@ -1,5 +1,5 @@
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import {
|
||||
import type {
|
||||
AnnotationActionMode,
|
||||
Dossier,
|
||||
IAddRedactionRequest,
|
||||
@ -10,20 +10,26 @@ import {
|
||||
IRemoveRedactionRequest,
|
||||
IResizeRequest,
|
||||
} from '@red/domain';
|
||||
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||
import { type AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||
import { GenericService, RequiredParam, Toaster, Validate } from '@iqser/common-ui';
|
||||
import { map, tap } from 'rxjs/operators';
|
||||
import { PermissionsService } from './permissions.service';
|
||||
import { annotationActionsTranslations } from '../translations/annotation-actions-translations';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { annotationActionsTranslations } from '../../../../../translations/annotation-actions-translations';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http';
|
||||
import { ActiveDossiersService } from './dossiers/active-dossiers.service';
|
||||
import { Observable } from 'rxjs';
|
||||
import { DictionariesMapService } from './entity-services/dictionaries-map.service';
|
||||
import { ManualRedactionEntryType } from '@models/file/manual-redaction-entry.wrapper';
|
||||
import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service';
|
||||
import { type Observable } from 'rxjs';
|
||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||
import { type ManualRedactionEntryType } from '@models/file/manual-redaction-entry.wrapper';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ManualAnnotationService extends GenericService<IManualAddResponse> {
|
||||
function getMessage(mode: AnnotationActionMode, modifyDictionary?: boolean, error = false, isConflict = false) {
|
||||
const type = modifyDictionary ? 'dictionary' : 'manual-redaction';
|
||||
const resultType = error ? (isConflict ? 'conflictError' : 'error') : 'success';
|
||||
return annotationActionsTranslations[type][mode][resultType];
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class ManualRedactionService extends GenericService<IManualAddResponse> {
|
||||
CONFIG: {
|
||||
[key in AnnotationActionMode]: string;
|
||||
};
|
||||
@ -69,15 +75,15 @@ export class ManualAnnotationService extends GenericService<IManualAddResponse>
|
||||
|
||||
return obs.pipe(
|
||||
tap({
|
||||
next: () => this._toaster.success(this._getMessage(mode, modifyDictionary), { positionClass: 'toast-file-preview' }),
|
||||
next: () => this._toaster.success(getMessage(mode, modifyDictionary), { positionClass: 'toast-file-preview' }),
|
||||
error: (error: HttpErrorResponse) => {
|
||||
const isConflict = error.status === HttpStatusCode.Conflict;
|
||||
this._toaster.error(this._getMessage(mode, modifyDictionary, true, isConflict), {
|
||||
this._toaster.error(getMessage(mode, modifyDictionary, true, isConflict), {
|
||||
error,
|
||||
params: {
|
||||
dictionaryName: this._dictionariesMapService.getDictionary(
|
||||
body.type as string,
|
||||
this._dossier(dossierId).dossierTemplateId,
|
||||
this.#dossier(dossierId).dossierTemplateId,
|
||||
).label,
|
||||
content: body.value,
|
||||
},
|
||||
@ -113,7 +119,6 @@ export class ManualAnnotationService extends GenericService<IManualAddResponse>
|
||||
return this.addAnnotation(manualRedactionEntry, dossierId, fileId);
|
||||
}
|
||||
|
||||
// /manualRedaction/request/legalBasis
|
||||
changeLegalBasis(
|
||||
annotationId: string,
|
||||
dossierId: string,
|
||||
@ -123,47 +128,31 @@ export class ManualAnnotationService extends GenericService<IManualAddResponse>
|
||||
legalBasis: string,
|
||||
comment?: string,
|
||||
) {
|
||||
const mode: AnnotationActionMode = this._permissionsService.isApprover(this._dossier(dossierId))
|
||||
const mode: AnnotationActionMode = this._permissionsService.isApprover(this.#dossier(dossierId))
|
||||
? 'change-legal-basis'
|
||||
: 'request-change-legal-basis';
|
||||
return this._makeRequest(mode, dossierId, fileId, { annotationId, legalBasis, comment, section, value });
|
||||
}
|
||||
|
||||
// this wraps
|
||||
// /manualRedaction/redaction/legalBasisChange
|
||||
|
||||
// /manualRedaction/request/recategorize
|
||||
recategorizeImg(annotationId: string, dossierId: string, fileId: string, type: string, comment: string) {
|
||||
const mode: AnnotationActionMode = this._permissionsService.isApprover(this._dossier(dossierId))
|
||||
const mode: AnnotationActionMode = this._permissionsService.isApprover(this.#dossier(dossierId))
|
||||
? 'recategorize-image'
|
||||
: 'request-image-recategorization';
|
||||
return this._makeRequest(mode, dossierId, fileId, { annotationId, type, comment });
|
||||
}
|
||||
|
||||
// this wraps
|
||||
// /manualRedaction/redaction/recategorize
|
||||
|
||||
// /manualRedaction/request/add
|
||||
addAnnotation(manualRedactionEntry: IAddRedactionRequest, dossierId: string, fileId: string) {
|
||||
const mode: AnnotationActionMode = this._permissionsService.isApprover(this._dossier(dossierId)) ? 'add' : 'suggest';
|
||||
const mode: AnnotationActionMode = this._permissionsService.isApprover(this.#dossier(dossierId)) ? 'add' : 'suggest';
|
||||
return this._makeRequest(mode, dossierId, fileId, manualRedactionEntry, null, manualRedactionEntry.addToDictionary);
|
||||
}
|
||||
|
||||
// this wraps
|
||||
// /manualRedaction/redaction/add
|
||||
|
||||
// /manualRedaction/request/force
|
||||
force(request: ILegalBasisChangeRequest, dossierId: string, fileId: string) {
|
||||
const mode: AnnotationActionMode = this._permissionsService.isApprover(this._dossier(dossierId))
|
||||
const mode: AnnotationActionMode = this._permissionsService.isApprover(this.#dossier(dossierId))
|
||||
? 'force-redaction'
|
||||
: 'request-force-redaction';
|
||||
return this._makeRequest(mode, dossierId, fileId, request);
|
||||
}
|
||||
|
||||
// this wraps
|
||||
// /manualRedaction/redaction/force
|
||||
|
||||
// /manualRedaction/approve
|
||||
approve(annotationId: string, dossierId: string, fileId: string, addToDictionary: boolean = false) {
|
||||
// for only here - approve the request
|
||||
return this._makeRequest(
|
||||
@ -176,29 +165,20 @@ export class ManualAnnotationService extends GenericService<IManualAddResponse>
|
||||
);
|
||||
}
|
||||
|
||||
// this wraps
|
||||
// /manualRedaction/undo
|
||||
undoRequest(annotationWrapper: AnnotationWrapper, dossierId: string, fileId: string) {
|
||||
return this._makeRequest('undo', dossierId, fileId, annotationWrapper.id, null, annotationWrapper.isModifyDictionary);
|
||||
}
|
||||
|
||||
// this wraps
|
||||
// /manualRedaction/decline/remove
|
||||
declineOrRemoveRequest(annotationWrapper: AnnotationWrapper, dossierId: string, fileId: string) {
|
||||
const mode: AnnotationActionMode = this._permissionsService.isApprover(this._dossier(dossierId)) ? 'decline' : 'undo';
|
||||
const mode: AnnotationActionMode = this._permissionsService.isApprover(this.#dossier(dossierId)) ? 'decline' : 'undo';
|
||||
return this._makeRequest(mode, dossierId, fileId, annotationWrapper.id, null, annotationWrapper.isModifyDictionary);
|
||||
}
|
||||
|
||||
// /manualRedaction/request/resize/
|
||||
resizeOrSuggestToResize(annotationWrapper: AnnotationWrapper, dossierId: string, fileId: string, resizeRequest: IResizeRequest) {
|
||||
const mode: AnnotationActionMode = this._permissionsService.isApprover(this._dossier(dossierId)) ? 'resize' : 'request-resize';
|
||||
const mode: AnnotationActionMode = this._permissionsService.isApprover(this.#dossier(dossierId)) ? 'resize' : 'request-resize';
|
||||
return this._makeRequest(mode, dossierId, fileId, resizeRequest);
|
||||
}
|
||||
|
||||
// this wraps
|
||||
// /manualRedaction/redaction/resize/
|
||||
|
||||
// /manualRedaction/request/remove/
|
||||
removeOrSuggestRemoveAnnotation(
|
||||
annotationWrapper: AnnotationWrapper,
|
||||
dossierId: string,
|
||||
@ -210,7 +190,7 @@ export class ManualAnnotationService extends GenericService<IManualAddResponse>
|
||||
body: any,
|
||||
removeDict = false;
|
||||
|
||||
if (this._permissionsService.isApprover(this._dossier(dossierId))) {
|
||||
if (this._permissionsService.isApprover(this.#dossier(dossierId))) {
|
||||
// if it was something manual simply decline the existing request
|
||||
mode = 'remove';
|
||||
body = {
|
||||
@ -232,9 +212,6 @@ export class ManualAnnotationService extends GenericService<IManualAddResponse>
|
||||
return this._makeRequest(mode, dossierId, fileId, body, null, removeDict);
|
||||
}
|
||||
|
||||
// this wraps
|
||||
// /manualRedaction/redaction/remove/
|
||||
|
||||
getTitle(type: ManualRedactionEntryType, dossier: Dossier) {
|
||||
if (this._permissionsService.isApprover(dossier)) {
|
||||
switch (type) {
|
||||
@ -372,13 +349,27 @@ export class ManualAnnotationService extends GenericService<IManualAddResponse>
|
||||
return this._post(body, url);
|
||||
}
|
||||
|
||||
private _dossier(dossierId: string): Dossier {
|
||||
// #showToast(body, dossierId: string) {
|
||||
// return tap({
|
||||
// next: () => this._toaster.success(getMessage(mode, modifyDictionary), { positionClass: 'toast-file-preview' }),
|
||||
// error: (error: HttpErrorResponse) => {
|
||||
// const isConflict = error.status === HttpStatusCode.Conflict;
|
||||
// this._toaster.error(getMessage(mode, modifyDictionary, true, isConflict), {
|
||||
// error,
|
||||
// params: {
|
||||
// dictionaryName: this._dictionariesMapService.getDictionary(
|
||||
// body.type as string,
|
||||
// this.#dossier(dossierId).dossierTemplateId,
|
||||
// ).label,
|
||||
// content: body.value,
|
||||
// },
|
||||
// positionClass: 'toast-file-preview',
|
||||
// });
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
|
||||
#dossier(dossierId: string): Dossier {
|
||||
return this._activeDossiersService.find(dossierId);
|
||||
}
|
||||
|
||||
private _getMessage(mode: AnnotationActionMode, modifyDictionary?: boolean, error = false, isConflict = false) {
|
||||
const type = modifyDictionary ? 'dictionary' : 'manual-redaction';
|
||||
const resultType = error ? (isConflict ? 'conflictError' : 'error') : 'success';
|
||||
return annotationActionsTranslations[type][mode][resultType];
|
||||
}
|
||||
}
|
||||
@ -27,7 +27,7 @@ export class CommentsComponent extends AutoUnsubscribe implements OnChanges {
|
||||
constructor(
|
||||
readonly permissionsService: PermissionsService,
|
||||
private readonly _userService: UserService,
|
||||
private readonly _manualAnnotationService: ManualAnnotationService,
|
||||
private readonly _manualRedactionService: ManualRedactionService,
|
||||
private readonly _commentingService: CommentingService,
|
||||
private readonly _loadingService: LoadingService,
|
||||
private readonly _changeRef: ChangeDetectorRef,
|
||||
@ -55,7 +55,7 @@ export class CommentsComponent extends AutoUnsubscribe implements OnChanges {
|
||||
}
|
||||
this._loadingService.start();
|
||||
const { dossierId, fileId } = this._stateService;
|
||||
const commentId = await firstValueFrom(this._manualAnnotationService.addComment(value, this.annotation.id, dossierId, fileId));
|
||||
const commentId = await firstValueFrom(this._manualRedactionService.addComment(value, this.annotation.id, dossierId, fileId));
|
||||
this.annotation.comments.push({
|
||||
text: value,
|
||||
id: commentId,
|
||||
@ -76,7 +76,7 @@ export class CommentsComponent extends AutoUnsubscribe implements OnChanges {
|
||||
$event.stopPropagation();
|
||||
this._loadingService.start();
|
||||
const { dossierId, fileId } = this._stateService;
|
||||
await firstValueFrom(this._manualAnnotationService.deleteComment(comment.id, this.annotation.id, dossierId, fileId));
|
||||
await firstValueFrom(this._manualRedactionService.deleteComment(comment.id, this.annotation.id, dossierId, fileId));
|
||||
this.annotation.comments.splice(this.annotation.comments.indexOf(comment), 1);
|
||||
this._changeRef.markForCheck();
|
||||
this._loadingService.stop();
|
||||
|
||||
@ -6,7 +6,6 @@ import { Dictionary, Dossier } from '@red/domain';
|
||||
import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service';
|
||||
import { BaseDialogComponent } from '@iqser/common-ui';
|
||||
import { DictionaryService } from '@services/entity-services/dictionary.service';
|
||||
import { ManualAnnotationService } from '@services/manual-annotation.service';
|
||||
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||
|
||||
export interface AcceptRecommendationData {
|
||||
@ -31,7 +30,6 @@ export class AcceptRecommendationDialogComponent extends BaseDialogComponent imp
|
||||
|
||||
constructor(
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
private readonly _manualAnnotationService: ManualAnnotationService,
|
||||
private readonly _permissionsService: PermissionsService,
|
||||
private readonly _activeDossiersService: ActiveDossiersService,
|
||||
private readonly _dictionaryService: DictionaryService,
|
||||
|
||||
@ -1,11 +1,7 @@
|
||||
import { Component, Inject, Injector, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { BaseDialogComponent, Toaster } from '@iqser/common-ui';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { ManualAnnotationService } from '@services/manual-annotation.service';
|
||||
import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service';
|
||||
import { BaseDialogComponent } from '@iqser/common-ui';
|
||||
import { JustificationsService } from '@services/entity-services/justifications.service';
|
||||
import { Dossier, ILegalBasisChangeRequest } from '@red/domain';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
@ -26,13 +22,8 @@ export class ForceAnnotationDialogComponent extends BaseDialogComponent implemen
|
||||
legalOptions: LegalBasisOption[] = [];
|
||||
|
||||
constructor(
|
||||
private readonly _activeDossiersService: ActiveDossiersService,
|
||||
private readonly _userService: UserService,
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
private readonly _notificationService: Toaster,
|
||||
private readonly _translateService: TranslateService,
|
||||
private readonly _justificationsService: JustificationsService,
|
||||
private readonly _manualAnnotationService: ManualAnnotationService,
|
||||
protected readonly _injector: Injector,
|
||||
protected readonly _dialogRef: MatDialogRef<ForceAnnotationDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA)
|
||||
|
||||
@ -2,8 +2,7 @@ import { Component, Inject, Injector, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { ManualRedactionEntryWrapper } from '@models/file/manual-redaction-entry.wrapper';
|
||||
import { ManualAnnotationService } from '@services/manual-annotation.service';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { ManualRedactionService } from '../../screens/file-preview-screen/services/manual-redaction.service';
|
||||
import { JustificationsService } from '@services/entity-services/justifications.service';
|
||||
import { Dictionary, Dossier, IAddRedactionRequest } from '@red/domain';
|
||||
import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service';
|
||||
@ -35,8 +34,7 @@ export class ManualAnnotationDialogComponent extends BaseDialogComponent impleme
|
||||
constructor(
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
private readonly _justificationsService: JustificationsService,
|
||||
private readonly _manualAnnotationService: ManualAnnotationService,
|
||||
private readonly _permissionsService: PermissionsService,
|
||||
private readonly _manualRedactionService: ManualRedactionService,
|
||||
private readonly _activeDossiersService: ActiveDossiersService,
|
||||
private readonly _dictionaryService: DictionaryService,
|
||||
protected readonly _injector: Injector,
|
||||
@ -54,7 +52,7 @@ export class ManualAnnotationDialogComponent extends BaseDialogComponent impleme
|
||||
}
|
||||
|
||||
get title() {
|
||||
return this._manualAnnotationService.getTitle(this.data.manualRedactionEntryWrapper.type, this._dossier);
|
||||
return this._manualRedactionService.getTitle(this.data.manualRedactionEntryWrapper.type, this._dossier);
|
||||
}
|
||||
|
||||
get displayedDictionaryLabel() {
|
||||
|
||||
@ -41,7 +41,7 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { SkippedService } from './services/skipped.service';
|
||||
import { FilePreviewStateService } from './services/file-preview-state.service';
|
||||
import { filePreviewScreenProviders } from './file-preview-providers';
|
||||
import { ManualAnnotationService } from '@services/manual-annotation.service';
|
||||
import { ManualRedactionService } from './services/manual-redaction.service';
|
||||
import { DossiersService } from '@services/dossiers/dossiers.service';
|
||||
import { PageRotationService } from './services/page-rotation.service';
|
||||
import { ComponentCanDeactivate } from '@guards/can-deactivate.guard';
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { EventEmitter, Inject, Injectable, NgZone } from '@angular/core';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { ManualAnnotationService } from '@services/manual-annotation.service';
|
||||
import { ManualRedactionService } from './manual-redaction.service';
|
||||
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||
import { Observable } from 'rxjs';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
@ -34,7 +34,7 @@ export class AnnotationActionsService {
|
||||
private readonly _ngZone: NgZone,
|
||||
private readonly _userService: UserService,
|
||||
private readonly _permissionsService: PermissionsService,
|
||||
private readonly _manualAnnotationService: ManualAnnotationService,
|
||||
private readonly _manualRedactionService: ManualRedactionService,
|
||||
private readonly _translateService: TranslateService,
|
||||
private readonly _dialogService: FilePreviewDialogService,
|
||||
private readonly _dialog: MatDialog,
|
||||
@ -54,7 +54,7 @@ export class AnnotationActionsService {
|
||||
const { dossierId, fileId } = this._screenStateService;
|
||||
annotations.forEach(annotation => {
|
||||
this._processObsAndEmit(
|
||||
this._manualAnnotationService.approve(annotation.id, dossierId, fileId, annotation.isModifyDictionary),
|
||||
this._manualRedactionService.approve(annotation.id, dossierId, fileId, annotation.isModifyDictionary),
|
||||
annotation,
|
||||
annotationsChanged,
|
||||
);
|
||||
@ -66,7 +66,7 @@ export class AnnotationActionsService {
|
||||
const { dossierId, fileId } = this._screenStateService;
|
||||
annotations.forEach(annotation => {
|
||||
this._processObsAndEmit(
|
||||
this._manualAnnotationService.declineOrRemoveRequest(annotation, dossierId, fileId),
|
||||
this._manualRedactionService.declineOrRemoveRequest(annotation, dossierId, fileId),
|
||||
annotation,
|
||||
annotationsChanged,
|
||||
);
|
||||
@ -84,7 +84,7 @@ export class AnnotationActionsService {
|
||||
this._dialogService.openDialog('forceAnnotation', $event, data, (request: ILegalBasisChangeRequest) => {
|
||||
annotations.forEach(annotation => {
|
||||
this._processObsAndEmit(
|
||||
this._manualAnnotationService.force(
|
||||
this._manualRedactionService.force(
|
||||
{
|
||||
...request,
|
||||
annotationId: annotation.id,
|
||||
@ -108,7 +108,7 @@ export class AnnotationActionsService {
|
||||
(data: { comment: string; legalBasis: string; section: string; value: string }) => {
|
||||
annotations.forEach(annotation => {
|
||||
this._processObsAndEmit(
|
||||
this._manualAnnotationService.changeLegalBasis(
|
||||
this._manualRedactionService.changeLegalBasis(
|
||||
annotation.annotationId,
|
||||
dossierId,
|
||||
fileId,
|
||||
@ -141,7 +141,7 @@ export class AnnotationActionsService {
|
||||
this._dialogService.openDialog('removeAnnotations', $event, data, (result: { comment: string }) => {
|
||||
annotations.forEach(annotation => {
|
||||
this._processObsAndEmit(
|
||||
this._manualAnnotationService.removeOrSuggestRemoveAnnotation(
|
||||
this._manualRedactionService.removeOrSuggestRemoveAnnotation(
|
||||
annotation,
|
||||
dossierId,
|
||||
fileId,
|
||||
@ -167,7 +167,7 @@ export class AnnotationActionsService {
|
||||
this._dialogService.openDialog('recategorizeImage', $event, data, (res: { type: string; comment: string }) => {
|
||||
annotations.forEach(annotation => {
|
||||
this._processObsAndEmit(
|
||||
this._manualAnnotationService.recategorizeImg(annotation.annotationId, dossierId, fileId, res.type, res.comment),
|
||||
this._manualRedactionService.recategorizeImg(annotation.annotationId, dossierId, fileId, res.type, res.comment),
|
||||
annotation,
|
||||
annotationsChanged,
|
||||
);
|
||||
@ -181,7 +181,7 @@ export class AnnotationActionsService {
|
||||
const { dossierId, fileId } = this._screenStateService;
|
||||
annotations.forEach(annotation => {
|
||||
this._processObsAndEmit(
|
||||
this._manualAnnotationService.undoRequest(annotation, dossierId, fileId),
|
||||
this._manualRedactionService.undoRequest(annotation, dossierId, fileId),
|
||||
annotation,
|
||||
annotationsChanged,
|
||||
);
|
||||
@ -205,7 +205,7 @@ export class AnnotationActionsService {
|
||||
const comment = commentText ? { text: commentText } : undefined;
|
||||
annotations.forEach(annotation => {
|
||||
this._processObsAndEmit(
|
||||
this._manualAnnotationService.addRecommendation(annotation, dossierId, fileId, comment),
|
||||
this._manualRedactionService.addRecommendation(annotation, dossierId, fileId, comment),
|
||||
annotation,
|
||||
annotationsChanged,
|
||||
);
|
||||
@ -444,7 +444,7 @@ export class AnnotationActionsService {
|
||||
};
|
||||
|
||||
this._processObsAndEmit(
|
||||
this._manualAnnotationService.resizeOrSuggestToResize(annotationWrapper, data.dossier.dossierId, fileId, resizeRequest),
|
||||
this._manualRedactionService.resizeOrSuggestToResize(annotationWrapper, data.dossier.dossierId, fileId, resizeRequest),
|
||||
annotationWrapper,
|
||||
annotationsChanged,
|
||||
);
|
||||
@ -517,7 +517,7 @@ export class AnnotationActionsService {
|
||||
const { dossierId, fileId } = this._screenStateService;
|
||||
|
||||
this._processObsAndEmit(
|
||||
this._manualAnnotationService.addAnnotation(falsePositiveRequest, dossierId, fileId),
|
||||
this._manualRedactionService.addAnnotation(falsePositiveRequest, dossierId, fileId),
|
||||
annotation,
|
||||
annotationsChanged,
|
||||
);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user