Merge branch 'dan' into 'master'

Update entity log migration

See merge request redactmanager/red-ui!177
This commit is contained in:
Dan Percic 2023-11-08 09:45:21 +01:00
commit aa8e59aefa
10 changed files with 61 additions and 68 deletions

View File

@ -59,7 +59,7 @@ export class AnnotationWrapper implements IListable {
hasBeenForcedHint: boolean;
hasBeenForcedRedaction: boolean;
hasBeenRemovedByManualOverride: boolean;
isIgnored = false;
isRemoved = false;
get searchKey(): string {
return this.id;
@ -212,7 +212,7 @@ export class AnnotationWrapper implements IListable {
const annotationWrapper = new AnnotationWrapper();
annotationWrapper.id = logEntry.id;
annotationWrapper.isChangeLogEntry = !!changeLogType;
annotationWrapper.isChangeLogEntry = logEntry.state === EntryStates.REMOVED || !!changeLogType;
annotationWrapper.type = logEntry.type;
annotationWrapper.value = logEntry.value;
annotationWrapper.firstTopLeftPoint = { x: logEntry.positions[0].rectangle[0], y: logEntry.positions[0].rectangle[1] };
@ -232,7 +232,7 @@ export class AnnotationWrapper implements IListable {
annotationWrapper.AREA = logEntry.entryType === EntityTypes.AREA;
annotationWrapper.IMAGE_HINT = logEntry.entryType === EntityTypes.IMAGE_HINT;
annotationWrapper.isIgnored = logEntry.state === EntryStates.IGNORED;
annotationWrapper.isRemoved = logEntry.state === EntryStates.REMOVED;
annotationWrapper.numberOfComments = logEntry.numberOfComments;
annotationWrapper.imported = logEntry.imported;

View File

@ -1,6 +1,6 @@
<div class="active-bar-marker"></div>
<div [class.removed]="annotation.item.isIgnored" class="annotation">
<div [class.removed]="annotation.item.isRemoved" class="annotation">
<redaction-annotation-card
[annotation]="annotation.item"
[isSelected]="annotation.isSelected"

View File

@ -3,7 +3,7 @@ import { MatDialog } from '@angular/material/dialog';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { CircleButtonTypes, getConfig, IconButtonTypes } from '@iqser/common-ui';
import { FilterService, INestedFilter } from '@iqser/common-ui/lib/filtering';
import { AutoUnsubscribe, bool, Debounce, IqserEventTarget } from '@iqser/common-ui/lib/utils';
import { AutoUnsubscribe, Debounce, IqserEventTarget } from '@iqser/common-ui/lib/utils';
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { ListItem } from '@models/file/list-item';
import { UserPreferenceService } from '@users/user-preference.service';
@ -356,7 +356,7 @@ export class FileWorkloadComponent extends AutoUnsubscribe implements OnInit, On
}
if (this.viewModeService.isRedacted()) {
annotations = annotations.filter(a => !bool(a.isIgnored));
annotations = annotations.filter(a => !a.isRemoved);
}
if (this.#isDocumine && !this.#isIqserDevMode) {

View File

@ -3,22 +3,11 @@ import { toObservable } from '@angular/core/rxjs-interop';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { EntitiesService, getConfig, Toaster } from '@iqser/common-ui';
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import {
ChangeType,
ChangeTypes,
EntryStates,
File,
IEntityLog,
IEntityLogEntry,
SuperTypeMapper,
ViewedPage,
ViewMode,
ViewModes,
} from '@red/domain';
import { ChangeType, ChangeTypes, File, IEntityLog, IEntityLogEntry, SuperTypeMapper, ViewedPage, ViewMode, ViewModes } from '@red/domain';
import { DictionaryService } from '@services/entity-services/dictionary.service';
import { EarmarksService } from '@services/files/earmarks.service';
import { EntityLogService } from '@services/files/entity-log.service';
import { FilesService } from '@services/files/files.service';
import { RedactionLogService } from '@services/files/redaction-log.service';
import { ViewedPagesMapService } from '@services/files/viewed-pages-map.service';
import { ViewedPagesService } from '@services/files/viewed-pages.service';
import { PermissionsService } from '@services/permissions.service';
@ -48,6 +37,7 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
readonly #isDocumine = getConfig().IS_DOCUMINE;
readonly #logger = inject(NGXLogger);
readonly #toaster = inject(Toaster);
readonly #isIqserDevMode = inject(UserPreferenceService).isIqserDevMode;
protected readonly _entityClass = AnnotationWrapper;
missingTypes = new Set<string>();
readonly earmarks: Signal<Map<number, AnnotationWrapper[]>>;
@ -59,10 +49,9 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
private readonly _viewedPagesService: ViewedPagesService,
private readonly _viewedPagesMapService: ViewedPagesMapService,
private readonly _viewModeService: ViewModeService,
private readonly _userPreferenceService: UserPreferenceService,
private readonly _dictionaryService: DictionaryService,
private readonly _permissionsService: PermissionsService,
private readonly _redactionLogService: RedactionLogService,
private readonly _entityLogService: EntityLogService,
private readonly _earmarksService: EarmarksService,
private readonly _multiSelectService: MultiSelectService,
private readonly _filesService: FilesService,
@ -107,7 +96,7 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
this.#logger.info('[ANNOTATIONS] Loading annotations...');
await this.#loadViewedPages(file);
await this.loadRedactionLog();
await this.loadEntityLog();
this.#logger.info('[ANNOTATIONS] Annotations loaded');
}
@ -129,14 +118,14 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
return earmarks;
}
async loadRedactionLog() {
async loadEntityLog() {
this.#logger.info('[REDACTION_LOG] Loading redaction log...');
const redactionLog = await this._redactionLogService.getEntityLog(this._state.dossierId, this._state.fileId);
const redactionLog = await this._entityLogService.getEntityLog(this._state.dossierId, this._state.fileId);
this.#logger.info('[REDACTION_LOG] Redaction log loaded', redactionLog);
let annotations = await this.#convertData(redactionLog);
this.#checkMissingTypes();
annotations = this._userPreferenceService.isIqserDevMode ? annotations : annotations.filter(a => !a.isFalsePositive);
annotations = this.#isIqserDevMode ? annotations : annotations.filter(a => !a.isFalsePositive);
this.#annotations.set(annotations);
}
@ -163,24 +152,18 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
}
#getVisibleAnnotations(annotations: AnnotationWrapper[], viewMode: ViewMode) {
return annotations.filter(annotation => {
if (viewMode === 'STANDARD') {
return !annotation.isIgnored;
}
if (viewMode === ViewModes.STANDARD) {
return annotations.filter(annotation => !annotation.isRemoved);
}
if (viewMode === 'DELTA') {
return annotation.isChangeLogEntry;
}
if (viewMode === ViewModes.DELTA) {
return annotations.filter(annotation => annotation.isChangeLogEntry);
}
return annotation.isRedacted;
});
return annotations.filter(annotation => annotation.isRedacted);
}
async #convertData(entityLog: IEntityLog) {
if (!entityLog.entityLogEntry) {
return [] as AnnotationWrapper[];
}
const file = this._state.file();
const annotations: AnnotationWrapper[] = [];
const dictionaries = this._state.dictionaries;
@ -193,12 +176,8 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
continue;
}
if (entry.state === EntryStates.REMOVED) {
continue;
}
const canBeMappedToASuperType = !!SuperTypeMapper[entry.entryType][entry.state](entry);
if (!canBeMappedToASuperType && this._userPreferenceService.isIqserDevMode) {
if (!canBeMappedToASuperType && this.#isIqserDevMode) {
this.#logger.error(
`[ENTITY_LOG] Entity ${entry.value} (${entry.entryType}, ${entry.state}) cannot be mapped to a super type!`,
entry,
@ -207,7 +186,7 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
`Skipping entity ${entry.value} (${entry.entryType}, ${entry.state}). It has unexpected state.
Check console for details.`,
{
timeOut: 15000,
timeOut: 10000,
easing: 'ease-in-out',
easeTime: 500,
},

View File

@ -1,14 +1,14 @@
import { Injectable } from '@angular/core';
import { clearStamps, stampPDFPage } from '../../../utils';
import { FilePreviewStateService } from './file-preview-state.service';
import { ViewModeService } from './view-mode.service';
import { TranslateService } from '@ngx-translate/core';
import { Core } from '@pdftron/webviewer';
import { PdfViewer } from '../../pdf-viewer/services/pdf-viewer.service';
import { REDDocumentViewer } from '../../pdf-viewer/services/document-viewer.service';
import { LicenseService } from '@services/license.service';
import { WatermarksMapService } from '@services/entity-services/watermarks-map.service';
import { WATERMARK_HORIZONTAL_ALIGNMENTS, WATERMARK_VERTICAL_ALIGNMENTS } from '@red/domain';
import { WatermarksMapService } from '@services/entity-services/watermarks-map.service';
import { LicenseService } from '@services/license.service';
import { clearStamps, stampPDFPage } from '../../../utils';
import { REDDocumentViewer } from '../../pdf-viewer/services/document-viewer.service';
import { PdfViewer } from '../../pdf-viewer/services/pdf-viewer.service';
import { FilePreviewStateService } from './file-preview-state.service';
import { ViewModeService } from './view-mode.service';
import PDFNet = Core.PDFNet;
@Injectable()
@ -61,7 +61,7 @@ export class StampService {
this._translateService.instant('file-preview.excluded-from-redaction') as string,
17,
'courier',
'TOP_LEFT',
'DIAGONAL',
WATERMARK_HORIZONTAL_ALIGNMENTS.CENTER,
WATERMARK_VERTICAL_ALIGNMENTS.CENTER,
50,

View File

@ -147,7 +147,7 @@ export class AnnotationDrawService {
const annotation = this._pdf.textHighlight();
annotation.Quads = this.#rectanglesToQuads(annotationWrapper.positions, pageNumber);
annotation.Opacity = annotationWrapper.isIgnored ? DEFAULT_REMOVED_ANNOTATION_OPACITY : DEFAULT_TEXT_ANNOTATION_OPACITY;
annotation.Opacity = annotationWrapper.isRemoved ? DEFAULT_REMOVED_ANNOTATION_OPACITY : DEFAULT_TEXT_ANNOTATION_OPACITY;
annotation.setContents(annotationWrapper.content);
annotation.PageNumber = pageNumber;
annotation.StrokeColor = this.convertColor(annotationWrapper.color);
@ -159,14 +159,14 @@ export class AnnotationDrawService {
this._annotationManager.addToHidden(annotationWrapper.id);
}
annotation.Hidden =
annotationWrapper.isIgnored ||
annotationWrapper.isRemoved ||
(hideSkipped && annotationWrapper.isSkipped) ||
this._annotationManager.isHidden(annotationWrapper.id);
annotation.setCustomData('redact-manager', 'true');
annotation.setCustomData('redaction', String(annotationWrapper.isRedacted));
annotation.setCustomData('skipped', String(annotationWrapper.isSkipped));
annotation.setCustomData('changeLog', String(annotationWrapper.isChangeLogEntry));
annotation.setCustomData('changeLogRemoved', String(annotationWrapper.isIgnored));
annotation.setCustomData('changeLogRemoved', String(annotationWrapper.isRemoved));
annotation.setCustomData('opacity', String(annotation.Opacity));
const redactionColor = this._defaultColorsService.getColor(dossierTemplateId, 'previewColor');

View File

@ -77,7 +77,7 @@ export class ReadableRedactionsService {
setAnnotationsOpacity(annotations: Annotation[], restoreToOriginal = false) {
annotations.forEach(annotation => {
annotation['Opacity'] = restoreToOriginal ? parseFloat(annotation.getCustomData('opacity')) : 0.5;
annotation['Opacity'] = restoreToOriginal ? parseFloat(annotation.getCustomData('opacity')) : 1;
});
}

View File

@ -7,7 +7,7 @@ import { catchError } from 'rxjs/operators';
@Injectable({
providedIn: 'root',
})
export class RedactionLogService extends GenericService<unknown> {
export class EntityLogService extends GenericService<unknown> {
protected readonly _defaultModelPath = '';
async getEntityLog(dossierId: string, fileId: string) {

View File

@ -1,12 +1,12 @@
import { hexToRgb } from './functions';
import { Core } from '@pdftron/webviewer';
import PDFDoc = Core.PDFNet.PDFDoc;
import {
WATERMARK_HORIZONTAL_ALIGNMENTS,
WATERMARK_VERTICAL_ALIGNMENTS,
WatermarkHorizontalAlignment,
WatermarkVerticalAlignment,
} from '@red/domain';
import { hexToRgb } from './functions';
import PDFDoc = Core.PDFNet.PDFDoc;
const HORIZONTAL_TEXT_ALIGNMENT_MATRIX = [
[-1, 0, 1],
@ -62,7 +62,7 @@ export async function stampPDFPage(
text: string,
fontSize: number,
fontType: string,
orientation: 'DIAGONAL' | 'HORIZONTAL' | 'VERTICAL' | 'TOP_LEFT',
orientation: 'DIAGONAL' | 'HORIZONTAL' | 'VERTICAL',
horizontalTextAlignment: WatermarkHorizontalAlignment,
verticalTextAlignment: WatermarkVerticalAlignment,
opacity: number,
@ -117,17 +117,17 @@ export async function stampPDFPage(
case 'VERTICAL':
await stamper.setRotation(-90);
await stamper.setTextAlignment(VERTICAL_TEXT_ALIGNMENT_MATRIX[verticalAlignment + 1][horizontalAlignment + 1]);
await stamper.setPosition(10, 20);
await stamper.setPosition(10, 15);
break;
case 'HORIZONTAL':
await stamper.setTextAlignment(HORIZONTAL_TEXT_ALIGNMENT_MATRIX[verticalAlignment + 1][horizontalAlignment + 1]);
await stamper.setPosition(20, 10);
await stamper.setPosition(15, 10);
break;
case 'DIAGONAL':
default:
await stamper.setRotation(-45);
await stamper.setTextAlignment(DIAGONAL_TEXT_ALIGNMENT_MATRIX[verticalAlignment + 1][horizontalAlignment + 1]);
await stamper.setPosition(20, 10);
await stamper.setPosition(15, 10);
}
const initialFont = await pdfNet.Font.create(document, convertFont(pdfNet, fontType));

View File

@ -23,14 +23,28 @@ function wrongSuperTypeHandler(): never | undefined {
*/
export const SuperTypeMapper: Record<EntityType, Record<EntryState, (entry: IEntityLogEntry) => SuperType | undefined>> = {
[EntityTypes.ENTITY]: {
[EntryStates.APPLIED]: entry => (entry.manualChanges.length ? SuperTypes.ManualRedaction : SuperTypes.Redaction),
[EntryStates.APPLIED]: entry => {
const hasManualChanges = entry.manualChanges.length;
const hasEngines = entry.engines.length;
if (hasManualChanges && !hasEngines) {
return SuperTypes.ManualRedaction;
}
return SuperTypes.Redaction;
},
[EntryStates.SKIPPED]: () => SuperTypes.Skipped,
[EntryStates.IGNORED]: () => SuperTypes.Redaction,
[EntryStates.IGNORED]: () => SuperTypes.Skipped,
[EntryStates.REMOVED]: wrongSuperTypeHandler,
},
[EntityTypes.HINT]: {
[EntryStates.APPLIED]: wrongSuperTypeHandler,
[EntryStates.SKIPPED]: entry => (entry.manualChanges.length ? SuperTypes.ManualHint : SuperTypes.Hint),
[EntryStates.SKIPPED]: entry => {
const hasManualChanges = entry.manualChanges.length;
const hasEngines = entry.engines.length;
if (hasManualChanges && !hasEngines) {
return SuperTypes.ManualHint;
}
return SuperTypes.Hint;
},
[EntryStates.IGNORED]: () => SuperTypes.IgnoredHint,
[EntryStates.REMOVED]: wrongSuperTypeHandler,
},
@ -61,13 +75,13 @@ export const SuperTypeMapper: Record<EntityType, Record<EntryState, (entry: IEnt
[EntityTypes.IMAGE]: {
[EntryStates.APPLIED]: () => SuperTypes.Redaction,
[EntryStates.SKIPPED]: () => SuperTypes.Skipped,
[EntryStates.IGNORED]: wrongSuperTypeHandler,
[EntryStates.IGNORED]: () => SuperTypes.Skipped,
[EntryStates.REMOVED]: wrongSuperTypeHandler,
},
[EntityTypes.IMAGE_HINT]: {
[EntryStates.APPLIED]: wrongSuperTypeHandler,
[EntryStates.SKIPPED]: () => SuperTypes.Hint,
[EntryStates.IGNORED]: wrongSuperTypeHandler,
[EntryStates.IGNORED]: () => SuperTypes.IgnoredHint,
[EntryStates.REMOVED]: wrongSuperTypeHandler,
},
};