RED-7619 update annotation wrapper
This commit is contained in:
parent
ffa9a5830f
commit
7d141c5b23
@ -32,7 +32,7 @@ export const canChangeLegalBasis = (annotation: AnnotationWrapper, canAddRedacti
|
||||
canAddRedaction && annotation.isRedacted && !annotation.pending;
|
||||
|
||||
export const canRecategorizeAnnotation = (annotation: AnnotationWrapper, canRecategorize: boolean) =>
|
||||
canRecategorize && (annotation.isImage || annotation.HINT) && !annotation.pending;
|
||||
canRecategorize && (annotation.isImage || annotation.isDictBasedHint) && !annotation.pending;
|
||||
|
||||
export const canResizeAnnotation = (annotation: AnnotationWrapper, canAddRedaction: boolean) =>
|
||||
canAddRedaction &&
|
||||
|
||||
@ -186,10 +186,6 @@ export class AnnotationWrapper implements IListable {
|
||||
return Math.floor(this.positions[0].height);
|
||||
}
|
||||
|
||||
get previewAnnotation() {
|
||||
return this.isRedacted;
|
||||
}
|
||||
|
||||
static fromEarmark(earmark: Earmark) {
|
||||
const annotationWrapper = new AnnotationWrapper();
|
||||
|
||||
@ -244,27 +240,30 @@ export class AnnotationWrapper implements IListable {
|
||||
annotationWrapper.engines = logEntry.engines ?? [];
|
||||
annotationWrapper.section = logEntry.section;
|
||||
annotationWrapper.reference = logEntry.reference || [];
|
||||
annotationWrapper.hasBeenResized = !!logEntry.manualChanges?.find(
|
||||
c => c.manualRedactionType === ManualRedactionTypes.RESIZE && c.processed,
|
||||
);
|
||||
annotationWrapper.hasBeenResized = !!logEntry.manualChanges?.find(c => c.manualRedactionType === ManualRedactionTypes.RESIZE);
|
||||
annotationWrapper.hasBeenRecategorized = !!logEntry.manualChanges?.find(
|
||||
c => c.manualRedactionType === ManualRedactionTypes.RECATEGORIZE && c.processed,
|
||||
c => c.manualRedactionType === ManualRedactionTypes.RECATEGORIZE,
|
||||
);
|
||||
annotationWrapper.hasLegalBasisChanged = !!logEntry.manualChanges?.find(
|
||||
c => c.manualRedactionType === ManualRedactionTypes.LEGAL_BASIS_CHANGE && c.processed,
|
||||
c => c.manualRedactionType === ManualRedactionTypes.LEGAL_BASIS_CHANGE,
|
||||
);
|
||||
annotationWrapper.hasBeenForcedHint = !!logEntry.manualChanges?.find(
|
||||
c => c.manualRedactionType === ManualRedactionTypes.FORCE_HINT && c.processed,
|
||||
c => c.manualRedactionType === ManualRedactionTypes.FORCE_HINT,
|
||||
);
|
||||
annotationWrapper.hasBeenForcedRedaction = !!logEntry.manualChanges?.find(
|
||||
c => c.manualRedactionType === ManualRedactionTypes.FORCE_REDACT && c.processed,
|
||||
c => c.manualRedactionType === ManualRedactionTypes.FORCE_REDACT,
|
||||
);
|
||||
annotationWrapper.hasBeenRemovedByManualOverride = !!logEntry.manualChanges?.find(
|
||||
c => c.manualRedactionType === ManualRedactionTypes.REMOVE_LOCALLY && c.processed,
|
||||
c => c.manualRedactionType === ManualRedactionTypes.REMOVE_LOCALLY,
|
||||
);
|
||||
|
||||
this.#createContent(annotationWrapper, logEntry, isDocumine, legalBasisList);
|
||||
this.#setSuperType(annotationWrapper, logEntry);
|
||||
const content = this.#createContent(annotationWrapper, logEntry, isDocumine);
|
||||
annotationWrapper.shortContent = this.#getShortContent(annotationWrapper, legalBasisList) || content;
|
||||
annotationWrapper.content = content;
|
||||
|
||||
const lastRelevantManualChange = logEntry.manualChanges?.at(-1);
|
||||
annotationWrapper.pending = lastRelevantManualChange && !lastRelevantManualChange.processed;
|
||||
annotationWrapper.superType = SuperTypeMapper[logEntry.entryType][logEntry.state](logEntry);
|
||||
annotationWrapper.superTypeLabel = annotationTypesTranslations[annotationWrapper.superType];
|
||||
|
||||
annotationWrapper.typeLabel = dictionary.virtual ? undefined : dictionary.label;
|
||||
@ -276,18 +275,7 @@ export class AnnotationWrapper implements IListable {
|
||||
return annotationWrapper;
|
||||
}
|
||||
|
||||
static #setSuperType(annotationWrapper: AnnotationWrapper, logEntry: IEntityLogEntry) {
|
||||
const lastRelevantManualChange = logEntry.manualChanges?.at(-1);
|
||||
annotationWrapper.pending = lastRelevantManualChange && !lastRelevantManualChange.processed;
|
||||
annotationWrapper.superType = SuperTypeMapper[logEntry.entryType][logEntry.state](logEntry);
|
||||
}
|
||||
|
||||
static #createContent(
|
||||
annotationWrapper: AnnotationWrapper,
|
||||
logEntry: IEntityLogEntry,
|
||||
isDocumine: boolean,
|
||||
legalBasisList: ILegalBasis[],
|
||||
) {
|
||||
static #createContent(annotationWrapper: AnnotationWrapper, logEntry: IEntityLogEntry, isDocumine: boolean) {
|
||||
let content = '';
|
||||
if (logEntry.matchedRule) {
|
||||
content += `Rule ${logEntry.matchedRule} matched${isDocumine ? ':' : ''} \n\n`;
|
||||
@ -320,8 +308,7 @@ export class AnnotationWrapper implements IListable {
|
||||
content += `${prefix} "${logEntry.section}"`;
|
||||
}
|
||||
|
||||
annotationWrapper.shortContent = this.#getShortContent(annotationWrapper, legalBasisList) || content;
|
||||
annotationWrapper.content = content;
|
||||
return content;
|
||||
}
|
||||
|
||||
static #getShortContent(annotationWrapper: AnnotationWrapper, legalBasisList: ILegalBasis[]) {
|
||||
|
||||
@ -1,9 +1,20 @@
|
||||
import { effect, Injectable, Signal, signal } from '@angular/core';
|
||||
import { effect, inject, Injectable, Signal, signal } from '@angular/core';
|
||||
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, ViewedPage, ViewMode, ViewModes } from '@red/domain';
|
||||
import {
|
||||
ChangeType,
|
||||
ChangeTypes,
|
||||
EntryStates,
|
||||
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 { FilesService } from '@services/files/files.service';
|
||||
@ -35,6 +46,8 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
|
||||
readonly #earmarks = signal<Map<number, AnnotationWrapper[]>>(new Map());
|
||||
#originalViewedPages: ViewedPage[] = [];
|
||||
readonly #isDocumine = getConfig().IS_DOCUMINE;
|
||||
readonly #logger = inject(NGXLogger);
|
||||
readonly #toaster = inject(Toaster);
|
||||
protected readonly _entityClass = AnnotationWrapper;
|
||||
missingTypes = new Set<string>();
|
||||
readonly earmarks: Signal<Map<number, AnnotationWrapper[]>>;
|
||||
@ -53,8 +66,6 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
|
||||
private readonly _earmarksService: EarmarksService,
|
||||
private readonly _multiSelectService: MultiSelectService,
|
||||
private readonly _filesService: FilesService,
|
||||
private readonly _toaster: Toaster,
|
||||
private readonly _logger: NGXLogger,
|
||||
) {
|
||||
super();
|
||||
this.annotations$ = toObservable(this.#annotations);
|
||||
@ -89,16 +100,16 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
|
||||
|
||||
async loadAnnotations(file: File) {
|
||||
if (!file || file.isUnprocessed) {
|
||||
this._logger.info('[ANNOTATIONS] File is null or unprocessed, skipping annotations loading');
|
||||
this.#logger.info('[ANNOTATIONS] File is null or unprocessed, skipping annotations loading');
|
||||
return;
|
||||
}
|
||||
|
||||
this._logger.info('[ANNOTATIONS] Loading annotations...');
|
||||
this.#logger.info('[ANNOTATIONS] Loading annotations...');
|
||||
|
||||
await this.#loadViewedPages(file);
|
||||
await this.loadRedactionLog();
|
||||
|
||||
this._logger.info('[ANNOTATIONS] Annotations loaded');
|
||||
this.#logger.info('[ANNOTATIONS] Annotations loaded');
|
||||
}
|
||||
|
||||
async annotationsChanged() {
|
||||
@ -119,10 +130,10 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
|
||||
}
|
||||
|
||||
async loadRedactionLog() {
|
||||
this._logger.info('[REDACTION_LOG] Loading redaction log...');
|
||||
this.#logger.info('[REDACTION_LOG] Loading redaction log...');
|
||||
const redactionLog = await this._redactionLogService.getEntityLog(this._state.dossierId, this._state.fileId);
|
||||
|
||||
this._logger.info('[REDACTION_LOG] Redaction log loaded', redactionLog);
|
||||
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);
|
||||
@ -131,7 +142,7 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
|
||||
|
||||
#checkMissingTypes() {
|
||||
if (this.missingTypes.size > 0) {
|
||||
this._toaster.error(_('error.missing-types'), {
|
||||
this.#toaster.error(_('error.missing-types'), {
|
||||
disableTimeOut: true,
|
||||
params: { missingTypes: Array.from(this.missingTypes).join(', ') },
|
||||
});
|
||||
@ -142,12 +153,12 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
|
||||
async #loadViewedPages(file: File) {
|
||||
if (!this._permissionsService.canMarkPagesAsViewed(file)) {
|
||||
this._viewedPagesMapService.set(file.fileId, []);
|
||||
this._logger.info('[VIEWED_PAGES] Cannot mark pages as viewed, skip loading viewed pages');
|
||||
this.#logger.info('[VIEWED_PAGES] Cannot mark pages as viewed, skip loading viewed pages');
|
||||
return;
|
||||
}
|
||||
|
||||
this.#originalViewedPages = await this._viewedPagesService.load(file.dossierId, file.fileId);
|
||||
this._logger.info('[VIEWED_PAGES] Loaded viewed pages', this.#originalViewedPages);
|
||||
this.#logger.info('[VIEWED_PAGES] Loaded viewed pages', this.#originalViewedPages);
|
||||
this._viewedPagesMapService.set(file.fileId, this.#originalViewedPages);
|
||||
}
|
||||
|
||||
@ -161,7 +172,7 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
|
||||
return annotation.isChangeLogEntry;
|
||||
}
|
||||
|
||||
return annotation.previewAnnotation;
|
||||
return annotation.isRedacted;
|
||||
});
|
||||
}
|
||||
|
||||
@ -186,6 +197,24 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
|
||||
continue;
|
||||
}
|
||||
|
||||
const canBeMappedToASuperType = !!SuperTypeMapper[entry.entryType][entry.state](entry);
|
||||
if (!canBeMappedToASuperType && this._userPreferenceService.isIqserDevMode) {
|
||||
this.#logger.error(
|
||||
`[ENTITY_LOG] Entity ${entry.value} (${entry.entryType}, ${entry.state}) cannot be mapped to a super type!`,
|
||||
entry,
|
||||
);
|
||||
this.#toaster.rawError(
|
||||
`Skipping entity ${entry.value} (${entry.entryType}, ${entry.state}). It has unexpected state.
|
||||
Check console for details.`,
|
||||
{
|
||||
timeOut: 15000,
|
||||
easing: 'ease-in-out',
|
||||
easeTime: 500,
|
||||
},
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
let dictionary = dictionaries.find(dict => dict.type === entry.type);
|
||||
if (!dictionary && checkDictionary) {
|
||||
const dictionaryRequest = this._dictionaryService.loadDictionaryDataForDossierTemplate(this._state.dossierTemplateId);
|
||||
|
||||
@ -163,7 +163,7 @@ export class AnnotationDrawService {
|
||||
(hideSkipped && annotationWrapper.isSkipped) ||
|
||||
this._annotationManager.isHidden(annotationWrapper.id);
|
||||
annotation.setCustomData('redact-manager', 'true');
|
||||
annotation.setCustomData('redaction', String(annotationWrapper.previewAnnotation));
|
||||
annotation.setCustomData('redaction', String(annotationWrapper.isRedacted));
|
||||
annotation.setCustomData('skipped', String(annotationWrapper.isSkipped));
|
||||
annotation.setCustomData('changeLog', String(annotationWrapper.isChangeLogEntry));
|
||||
annotation.setCustomData('changeLogRemoved', String(annotationWrapper.isIgnored));
|
||||
|
||||
@ -14,62 +14,61 @@ export const SuperTypes = {
|
||||
|
||||
export type SuperType = ValuesOf<typeof SuperTypes>;
|
||||
|
||||
function throwWrongSuperType(entry: IEntityLogEntry): never {
|
||||
console.log('throwWrongSuperType', entry);
|
||||
throw new Error(`A ${entry.state} ${entry.entryType} should never be mapped to a super type`);
|
||||
function wrongSuperTypeHandler(): never | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* https://knecon.atlassian.net/wiki/spaces/RED/pages/102072322/EntityLog+-+Enum+combinations
|
||||
*/
|
||||
export const SuperTypeMapper: Record<EntityType, Record<EntryState, (entry: IEntityLogEntry) => SuperType>> = {
|
||||
export const SuperTypeMapper: Record<EntityType, Record<EntryState, (entry: IEntityLogEntry) => SuperType | undefined>> = {
|
||||
[EntityTypes.ENTITY]: {
|
||||
[EntryStates.APPLIED]: entry => (entry.manualChanges.length ? SuperTypes.ManualRedaction : SuperTypes.Redaction),
|
||||
[EntryStates.SKIPPED]: () => SuperTypes.Skipped,
|
||||
[EntryStates.IGNORED]: () => SuperTypes.Redaction,
|
||||
[EntryStates.REMOVED]: throwWrongSuperType,
|
||||
[EntryStates.REMOVED]: wrongSuperTypeHandler,
|
||||
},
|
||||
[EntityTypes.HINT]: {
|
||||
[EntryStates.APPLIED]: entry => (entry.manualChanges.length ? SuperTypes.ManualHint : SuperTypes.Hint),
|
||||
[EntryStates.APPLIED]: wrongSuperTypeHandler,
|
||||
[EntryStates.SKIPPED]: entry => (entry.manualChanges.length ? SuperTypes.ManualHint : SuperTypes.Hint),
|
||||
[EntryStates.IGNORED]: () => SuperTypes.IgnoredHint,
|
||||
[EntryStates.REMOVED]: throwWrongSuperType,
|
||||
[EntryStates.REMOVED]: wrongSuperTypeHandler,
|
||||
},
|
||||
[EntityTypes.FALSE_POSITIVE]: {
|
||||
[EntryStates.APPLIED]: throwWrongSuperType,
|
||||
[EntryStates.SKIPPED]: throwWrongSuperType,
|
||||
[EntryStates.IGNORED]: throwWrongSuperType,
|
||||
[EntryStates.REMOVED]: throwWrongSuperType,
|
||||
[EntryStates.APPLIED]: wrongSuperTypeHandler,
|
||||
[EntryStates.SKIPPED]: wrongSuperTypeHandler,
|
||||
[EntryStates.IGNORED]: wrongSuperTypeHandler,
|
||||
[EntryStates.REMOVED]: wrongSuperTypeHandler,
|
||||
},
|
||||
[EntityTypes.RECOMMENDATION]: {
|
||||
[EntryStates.APPLIED]: throwWrongSuperType,
|
||||
[EntryStates.APPLIED]: wrongSuperTypeHandler,
|
||||
[EntryStates.SKIPPED]: () => SuperTypes.Recommendation,
|
||||
[EntryStates.IGNORED]: throwWrongSuperType,
|
||||
[EntryStates.REMOVED]: throwWrongSuperType,
|
||||
[EntryStates.IGNORED]: wrongSuperTypeHandler,
|
||||
[EntryStates.REMOVED]: wrongSuperTypeHandler,
|
||||
},
|
||||
[EntityTypes.FALSE_RECOMMENDATION]: {
|
||||
[EntryStates.APPLIED]: throwWrongSuperType,
|
||||
[EntryStates.SKIPPED]: throwWrongSuperType,
|
||||
[EntryStates.IGNORED]: throwWrongSuperType,
|
||||
[EntryStates.REMOVED]: throwWrongSuperType,
|
||||
[EntryStates.APPLIED]: wrongSuperTypeHandler,
|
||||
[EntryStates.SKIPPED]: wrongSuperTypeHandler,
|
||||
[EntryStates.IGNORED]: wrongSuperTypeHandler,
|
||||
[EntryStates.REMOVED]: wrongSuperTypeHandler,
|
||||
},
|
||||
[EntityTypes.AREA]: {
|
||||
[EntryStates.APPLIED]: () => SuperTypes.Redaction,
|
||||
[EntryStates.SKIPPED]: throwWrongSuperType,
|
||||
[EntryStates.IGNORED]: throwWrongSuperType,
|
||||
[EntryStates.REMOVED]: throwWrongSuperType,
|
||||
[EntryStates.SKIPPED]: wrongSuperTypeHandler,
|
||||
[EntryStates.IGNORED]: wrongSuperTypeHandler,
|
||||
[EntryStates.REMOVED]: wrongSuperTypeHandler,
|
||||
},
|
||||
[EntityTypes.IMAGE]: {
|
||||
[EntryStates.APPLIED]: () => SuperTypes.Redaction,
|
||||
[EntryStates.SKIPPED]: () => SuperTypes.Skipped,
|
||||
[EntryStates.IGNORED]: throwWrongSuperType,
|
||||
[EntryStates.REMOVED]: throwWrongSuperType,
|
||||
[EntryStates.IGNORED]: wrongSuperTypeHandler,
|
||||
[EntryStates.REMOVED]: wrongSuperTypeHandler,
|
||||
},
|
||||
[EntityTypes.IMAGE_HINT]: {
|
||||
[EntryStates.APPLIED]: throwWrongSuperType,
|
||||
[EntryStates.APPLIED]: wrongSuperTypeHandler,
|
||||
[EntryStates.SKIPPED]: () => SuperTypes.Hint,
|
||||
[EntryStates.IGNORED]: throwWrongSuperType,
|
||||
[EntryStates.REMOVED]: throwWrongSuperType,
|
||||
[EntryStates.IGNORED]: wrongSuperTypeHandler,
|
||||
[EntryStates.REMOVED]: wrongSuperTypeHandler,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import { LogEntryStatus, ManualRedactionType } from './types';
|
||||
import { ManualRedactionType } from './types';
|
||||
|
||||
export interface IManualChange {
|
||||
userId: string;
|
||||
processedDate: string;
|
||||
requestedDate: string;
|
||||
annotationStatus: LogEntryStatus;
|
||||
manualRedactionType: ManualRedactionType;
|
||||
propertyChanges: { [key: string]: any };
|
||||
processed: boolean;
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { IRectangle } from '../geometry';
|
||||
import { LogEntryStatus } from './types';
|
||||
|
||||
export interface IManualRedactionEntry {
|
||||
addToDictionary?: boolean;
|
||||
@ -11,7 +10,6 @@ export interface IManualRedactionEntry {
|
||||
reason?: string;
|
||||
requestDate?: string;
|
||||
softDeletedTime?: string;
|
||||
status?: LogEntryStatus;
|
||||
type?: string;
|
||||
user?: string;
|
||||
value?: string;
|
||||
|
||||
@ -21,10 +21,3 @@ export const ManualRedactionTypes = {
|
||||
} as const;
|
||||
|
||||
export type ManualRedactionType = ValuesOf<typeof ManualRedactionTypes>;
|
||||
|
||||
export const LogEntryStatuses = {
|
||||
APPROVED: 'APPROVED',
|
||||
DECLINED: 'DECLINED',
|
||||
} as const;
|
||||
|
||||
export type LogEntryStatus = ValuesOf<typeof LogEntryStatuses>;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user