wip
This commit is contained in:
parent
8e97ed44ed
commit
9ae510bf5a
@ -1,704 +0,0 @@
|
||||
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));
|
||||
}
|
||||
}
|
||||
@ -1,73 +0,0 @@
|
||||
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 {}
|
||||
@ -20,7 +20,6 @@ import {
|
||||
ManualRedactionEntryWrapper,
|
||||
} from '@models/file/manual-redaction-entry.wrapper';
|
||||
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||
import { ManualAnnotationService } from '@services/manual-annotation.service';
|
||||
import { environment } from '@environments/environment';
|
||||
import { AnnotationDrawService } from '../../services/annotation-draw.service';
|
||||
import { AnnotationActionsService } from '../../services/annotation-actions.service';
|
||||
@ -44,6 +43,7 @@ import { from, fromEvent } from 'rxjs';
|
||||
import { FileDataService } from '../../services/file-data.service';
|
||||
import { ViewerHeaderConfigService } from '../../services/viewer-header-config.service';
|
||||
import { TooltipsService } from '../../services/tooltips.service';
|
||||
import { ManualRedactionService } from '../../services/manual-redaction.service';
|
||||
import Tools = Core.Tools;
|
||||
import TextTool = Tools.TextTool;
|
||||
import Annotation = Core.Annotations.Annotation;
|
||||
@ -71,7 +71,7 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
|
||||
constructor(
|
||||
@Inject(BASE_HREF) private readonly _baseHref: string,
|
||||
private readonly _translateService: TranslateService,
|
||||
private readonly _manualAnnotationService: ManualAnnotationService,
|
||||
private readonly _manualRedactionService: ManualRedactionService,
|
||||
private readonly _dialogService: FilePreviewDialogService,
|
||||
private readonly _ngZone: NgZone,
|
||||
private readonly _activatedRoute: ActivatedRoute,
|
||||
@ -481,7 +481,7 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
|
||||
}
|
||||
|
||||
#getTitle(type: ManualRedactionEntryType) {
|
||||
return this._translateService.instant(this._manualAnnotationService.getTitle(type, this.dossier));
|
||||
return this._translateService.instant(this._manualRedactionService.getTitle(type, this.dossier));
|
||||
}
|
||||
|
||||
private _addManualRedactionOfType(type: ManualRedactionEntryType) {
|
||||
|
||||
@ -2,13 +2,13 @@ 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 { 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';
|
||||
import { DictionaryService } from '@services/entity-services/dictionary.service';
|
||||
import { BaseDialogComponent, CircleButtonTypes } from '@iqser/common-ui';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { ManualRedactionService } from '../../services/manual-redaction.service';
|
||||
|
||||
export interface LegalBasisOption {
|
||||
label?: string;
|
||||
|
||||
@ -35,6 +35,7 @@ import { HighlightActionDialogComponent } from './dialogs/highlight-action-dialo
|
||||
import { FilePreviewDialogService } from './services/file-preview-dialog.service';
|
||||
import { ColorPickerModule } from 'ngx-color-picker';
|
||||
import { DocumentInfoDialogComponent } from './dialogs/document-info-dialog/document-info-dialog.component';
|
||||
import { ManualRedactionService } from './services/manual-redaction.service';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
@ -75,10 +76,11 @@ const components = [
|
||||
AnnotationCardComponent,
|
||||
AnnotationReferencesPageIndicatorComponent,
|
||||
HighlightsSeparatorComponent,
|
||||
FilePreviewScreenComponent,
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
declarations: [FilePreviewScreenComponent, ...components, ...dialogs],
|
||||
declarations: [...components, ...dialogs],
|
||||
imports: [
|
||||
RouterModule.forChild(routes),
|
||||
CommonModule,
|
||||
@ -89,6 +91,6 @@ const components = [
|
||||
OverlayModule,
|
||||
ColorPickerModule,
|
||||
],
|
||||
providers: [FilePreviewDialogService],
|
||||
providers: [FilePreviewDialogService, ManualRedactionService],
|
||||
})
|
||||
export class FilePreviewModule {}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import type {
|
||||
AnnotationActionMode,
|
||||
DictionaryActions,
|
||||
Dossier,
|
||||
IAddRedactionRequest,
|
||||
IApproveRequest,
|
||||
@ -9,18 +10,23 @@ import type {
|
||||
IManualAddResponse,
|
||||
IRemoveRedactionRequest,
|
||||
IResizeRequest,
|
||||
ManualRedactionActions,
|
||||
} from '@red/domain';
|
||||
import { type 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 '@services/permissions.service';
|
||||
import { annotationActionsTranslations } from '../../../../../translations/annotation-actions-translations';
|
||||
import { PermissionsService } from '../../../services/permissions.service';
|
||||
import {
|
||||
annotationActionsTranslations,
|
||||
dictionaryActionsTranslations,
|
||||
manualRedactionActionsTranslations,
|
||||
} from '../../../translations/annotation-actions-translations';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http';
|
||||
import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service';
|
||||
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';
|
||||
import { DictionariesMapService } from '../../../services/entity-services/dictionaries-map.service';
|
||||
import { type ManualRedactionEntryType } from '../../../models/file/manual-redaction-entry.wrapper';
|
||||
|
||||
function getMessage(mode: AnnotationActionMode, modifyDictionary?: boolean, error = false, isConflict = false) {
|
||||
const type = modifyDictionary ? 'dictionary' : 'manual-redaction';
|
||||
@ -28,8 +34,22 @@ function getMessage(mode: AnnotationActionMode, modifyDictionary?: boolean, erro
|
||||
return annotationActionsTranslations[type][mode][resultType];
|
||||
}
|
||||
|
||||
function getResponseType(error: boolean, isConflict: boolean) {
|
||||
return error ? (isConflict ? 'conflictError' : 'error') : 'success';
|
||||
}
|
||||
|
||||
function getDictionaryMessage(action: DictionaryActions, error = false, isConflict = false) {
|
||||
return dictionaryActionsTranslations[action][getResponseType(error, isConflict)];
|
||||
}
|
||||
|
||||
function getManualRedactionMessage(action: ManualRedactionActions, error = false, isConflict = false) {
|
||||
return manualRedactionActionsTranslations[action][getResponseType(error, isConflict)];
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class ManualRedactionService extends GenericService<IManualAddResponse> {
|
||||
readonly request = `${this._defaultModelPath}/request`;
|
||||
readonly redaction = `${this._defaultModelPath}/redaction`;
|
||||
CONFIG: {
|
||||
[key in AnnotationActionMode]: string;
|
||||
};
|
||||
@ -153,6 +173,20 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
|
||||
return this._makeRequest(mode, dossierId, fileId, request);
|
||||
}
|
||||
|
||||
_force(request: ILegalBasisChangeRequest, dossierId: string, fileId: string) {
|
||||
const mode: AnnotationActionMode = this._permissionsService.isApprover(this.#dossier(dossierId))
|
||||
? 'force-redaction'
|
||||
: 'request-force-redaction';
|
||||
return this._makeRequest(mode, dossierId, fileId, request);
|
||||
}
|
||||
|
||||
_requestForce(request: ILegalBasisChangeRequest, dossierId: string, fileId: string) {
|
||||
const mode: AnnotationActionMode = this._permissionsService.isApprover(this.#dossier(dossierId))
|
||||
? 'force-redaction'
|
||||
: 'request-force-redaction';
|
||||
return this._makeRequest(mode, dossierId, fileId, request);
|
||||
}
|
||||
|
||||
approve(annotationId: string, dossierId: string, fileId: string, addToDictionary: boolean = false) {
|
||||
// for only here - approve the request
|
||||
return this._makeRequest(
|
||||
@ -236,7 +270,7 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
|
||||
|
||||
@Validate()
|
||||
addRedaction(@RequiredParam() body: IAddRedactionRequest, @RequiredParam() dossierId: string, @RequiredParam() fileId: string) {
|
||||
const url = `${this._defaultModelPath}/redaction/add/${dossierId}/${fileId}`;
|
||||
const url = `${this.redaction}/add/${dossierId}/${fileId}`;
|
||||
return this._post(body, url);
|
||||
}
|
||||
|
||||
@ -246,7 +280,7 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
|
||||
@RequiredParam() dossierId: string,
|
||||
@RequiredParam() fileId: string,
|
||||
) {
|
||||
const url = `${this._defaultModelPath}/redaction/recategorize/${dossierId}/${fileId}`;
|
||||
const url = `${this.redaction}/recategorize/${dossierId}/${fileId}`;
|
||||
return this._post(body, url);
|
||||
}
|
||||
|
||||
@ -256,13 +290,13 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
|
||||
@RequiredParam() dossierId: string,
|
||||
@RequiredParam() fileId: string,
|
||||
) {
|
||||
const url = `${this._defaultModelPath}/request/recategorize/${dossierId}/${fileId}`;
|
||||
const url = `${this.request}/recategorize/${dossierId}/${fileId}`;
|
||||
return this._post(body, url);
|
||||
}
|
||||
|
||||
@Validate()
|
||||
legalBasisChange(@RequiredParam() body: ILegalBasisChangeRequest, @RequiredParam() dossierId: string, @RequiredParam() fileId: string) {
|
||||
const url = `${this._defaultModelPath}/redaction/legalBasisChange/${dossierId}/${fileId}`;
|
||||
const url = `${this.redaction}/legalBasisChange/${dossierId}/${fileId}`;
|
||||
return this._post(body, url);
|
||||
}
|
||||
|
||||
@ -272,7 +306,7 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
|
||||
@RequiredParam() dossierId: string,
|
||||
@RequiredParam() fileId: string,
|
||||
) {
|
||||
const url = `${this._defaultModelPath}/request/legalBasis/${dossierId}/${fileId}`;
|
||||
const url = `${this.request}/legalBasis/${dossierId}/${fileId}`;
|
||||
return this._post(body, url);
|
||||
}
|
||||
|
||||
@ -282,7 +316,7 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
|
||||
@RequiredParam() dossierId: string,
|
||||
@RequiredParam() fileId: string,
|
||||
) {
|
||||
const url = `${this._defaultModelPath}/request/remove/${dossierId}/${fileId}`;
|
||||
const url = `${this.request}/remove/${dossierId}/${fileId}`;
|
||||
return this._post(body, url);
|
||||
}
|
||||
|
||||
@ -311,20 +345,17 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
|
||||
|
||||
@Validate()
|
||||
removeRedaction(@RequiredParam() body: IRemoveRedactionRequest, @RequiredParam() dossierId: string, @RequiredParam() fileId: string) {
|
||||
const url = `${this._defaultModelPath}/redaction/remove/${dossierId}/${fileId}`;
|
||||
return this._post(body, url);
|
||||
return this._post(body, `${this.redaction}/remove/${dossierId}/${fileId}`);
|
||||
}
|
||||
|
||||
@Validate()
|
||||
requestAddRedaction(@RequiredParam() body: IAddRedactionRequest, @RequiredParam() dossierId: string, @RequiredParam() fileId: string) {
|
||||
const url = `${this._defaultModelPath}/request/add/${dossierId}/${fileId}`;
|
||||
return this._post(body, url);
|
||||
return this._post(body, `${this.request}/add/${dossierId}/${fileId}`);
|
||||
}
|
||||
|
||||
@Validate()
|
||||
forceRedaction(@RequiredParam() body: ILegalBasisChangeRequest, @RequiredParam() dossierId: string, @RequiredParam() fileId: string) {
|
||||
const url = `${this._defaultModelPath}/redaction/force/${dossierId}/${fileId}`;
|
||||
return this._post(body, url);
|
||||
return this._post(body, `${this.redaction}/force/${dossierId}/${fileId}`);
|
||||
}
|
||||
|
||||
@Validate()
|
||||
@ -333,41 +364,38 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
|
||||
@RequiredParam() dossierId: string,
|
||||
@RequiredParam() fileId: string,
|
||||
) {
|
||||
const url = `${this._defaultModelPath}/request/force/${dossierId}/${fileId}`;
|
||||
return this._post(body, url);
|
||||
return this._post(body, `${this.request}/force/${dossierId}/${fileId}`);
|
||||
}
|
||||
|
||||
@Validate()
|
||||
resize(@RequiredParam() body: IResizeRequest, @RequiredParam() dossierId: string, @RequiredParam() fileId: string) {
|
||||
const url = `${this._defaultModelPath}/redaction/resize/${dossierId}/${fileId}`;
|
||||
return this._post(body, url);
|
||||
return this._post(body, `${this.redaction}/resize/${dossierId}/${fileId}`);
|
||||
}
|
||||
|
||||
@Validate()
|
||||
requestResize(@RequiredParam() body: IResizeRequest, @RequiredParam() dossierId: string, @RequiredParam() fileId: string) {
|
||||
const url = `${this._defaultModelPath}/request/resize/${dossierId}/${fileId}`;
|
||||
return this._post(body, url);
|
||||
return this._post(body, `${this.request}/resize/${dossierId}/${fileId}`);
|
||||
}
|
||||
|
||||
// #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',
|
||||
// });
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
#showToast(mode: AnnotationActionMode, body, dossierId: string, modifyDictionary = false) {
|
||||
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);
|
||||
@ -1,7 +1,13 @@
|
||||
import { AnnotationActionMode } from '@red/domain';
|
||||
import { AnnotationActionMode, DictionaryActions, ManualRedactionActions } from '@red/domain';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
|
||||
type ActionType = { [key in AnnotationActionMode]?: { error: string; success: string; conflictError?: string } };
|
||||
interface AnnotationActionResponses {
|
||||
error: string;
|
||||
success: string;
|
||||
conflictError?: string;
|
||||
}
|
||||
|
||||
type ActionType = { [key in AnnotationActionMode]?: AnnotationActionResponses };
|
||||
|
||||
export const annotationActionsTranslations: {
|
||||
dictionary: ActionType;
|
||||
@ -93,3 +99,90 @@ export const annotationActionsTranslations: {
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const dictionaryActionsTranslations: Record<DictionaryActions, AnnotationActionResponses> = {
|
||||
add: {
|
||||
error: _('annotation-actions.message.dictionary.add.error'),
|
||||
conflictError: _('annotation-actions.message.dictionary.add.conflict-error'),
|
||||
success: _('annotation-actions.message.dictionary.add.success'),
|
||||
},
|
||||
approve: {
|
||||
error: _('annotation-actions.message.dictionary.approve.error'),
|
||||
success: _('annotation-actions.message.dictionary.approve.success'),
|
||||
},
|
||||
decline: {
|
||||
error: _('annotation-actions.message.dictionary.decline.error'),
|
||||
success: _('annotation-actions.message.dictionary.decline.success'),
|
||||
},
|
||||
remove: {
|
||||
error: _('annotation-actions.message.dictionary.remove.error'),
|
||||
success: _('annotation-actions.message.dictionary.remove.success'),
|
||||
},
|
||||
'request-remove': {
|
||||
error: _('annotation-actions.message.dictionary.request-remove.error'),
|
||||
success: _('annotation-actions.message.dictionary.request-remove.success'),
|
||||
},
|
||||
suggest: {
|
||||
error: _('annotation-actions.message.dictionary.suggest.error'),
|
||||
success: _('annotation-actions.message.dictionary.suggest.success'),
|
||||
},
|
||||
undo: {
|
||||
error: _('annotation-actions.message.dictionary.undo.error'),
|
||||
success: _('annotation-actions.message.dictionary.undo.success'),
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const manualRedactionActionsTranslations: Record<ManualRedactionActions, AnnotationActionResponses> = {
|
||||
add: {
|
||||
error: _('annotation-actions.message.manual-redaction.add.error'),
|
||||
success: _('annotation-actions.message.manual-redaction.add.success'),
|
||||
},
|
||||
approve: {
|
||||
error: _('annotation-actions.message.manual-redaction.approve.error'),
|
||||
success: _('annotation-actions.message.manual-redaction.approve.success'),
|
||||
},
|
||||
'change-legal-basis': {
|
||||
error: _('annotation-actions.message.manual-redaction.change-legal-basis.error'),
|
||||
success: _('annotation-actions.message.manual-redaction.change-legal-basis.success'),
|
||||
},
|
||||
decline: {
|
||||
error: _('annotation-actions.message.manual-redaction.decline.error'),
|
||||
success: _('annotation-actions.message.manual-redaction.decline.success'),
|
||||
},
|
||||
'force-redaction': {
|
||||
error: _('annotation-actions.message.manual-redaction.force-redaction.error'),
|
||||
success: _('annotation-actions.message.manual-redaction.force-redaction.success'),
|
||||
},
|
||||
'recategorize-image': {
|
||||
error: _('annotation-actions.message.manual-redaction.recategorize-image.error'),
|
||||
success: _('annotation-actions.message.manual-redaction.recategorize-image.success'),
|
||||
},
|
||||
'request-change-legal-basis': {
|
||||
error: _('annotation-actions.message.manual-redaction.request-change-legal-basis.error'),
|
||||
success: _('annotation-actions.message.manual-redaction.request-change-legal-basis.success'),
|
||||
},
|
||||
'request-force-redaction': {
|
||||
error: _('annotation-actions.message.manual-redaction.request-force-redaction.error'),
|
||||
success: _('annotation-actions.message.manual-redaction.request-force-redaction.success'),
|
||||
},
|
||||
'request-image-recategorization': {
|
||||
error: _('annotation-actions.message.manual-redaction.request-image-recategorization.error'),
|
||||
success: _('annotation-actions.message.manual-redaction.request-image-recategorization.success'),
|
||||
},
|
||||
suggest: {
|
||||
error: _('annotation-actions.message.manual-redaction.suggest.error'),
|
||||
success: _('annotation-actions.message.manual-redaction.suggest.success'),
|
||||
},
|
||||
undo: {
|
||||
error: _('annotation-actions.message.manual-redaction.undo.error'),
|
||||
success: _('annotation-actions.message.manual-redaction.undo.success'),
|
||||
},
|
||||
remove: {
|
||||
error: _('annotation-actions.message.manual-redaction.remove.error'),
|
||||
success: _('annotation-actions.message.manual-redaction.remove.success'),
|
||||
},
|
||||
'request-remove': {
|
||||
error: _('annotation-actions.message.manual-redaction.request-remove.error'),
|
||||
success: _('annotation-actions.message.manual-redaction.request-remove.success'),
|
||||
},
|
||||
} as const;
|
||||
|
||||
@ -16,3 +16,19 @@ export type AnnotationActionMode =
|
||||
| 'request-force-redaction'
|
||||
| 'resize'
|
||||
| 'request-resize';
|
||||
|
||||
export type DictionaryActions = 'add' | 'approve' | 'remove' | 'decline' | 'request-remove' | 'suggest' | 'undo';
|
||||
export type ManualRedactionActions =
|
||||
| 'add'
|
||||
| 'approve'
|
||||
| 'remove'
|
||||
| 'change-legal-basis'
|
||||
| 'decline'
|
||||
| 'request-remove'
|
||||
| 'request-change-legal-basis'
|
||||
| 'recategorize-image'
|
||||
| 'request-image-recategorization'
|
||||
| 'suggest'
|
||||
| 'undo'
|
||||
| 'force-redaction'
|
||||
| 'request-force-redaction';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user