RED-4416: Annotation colors

This commit is contained in:
Adina Țeudan 2022-07-11 19:57:33 +03:00
parent d9435b8b4d
commit 29d1fc7653
24 changed files with 79 additions and 245 deletions

View File

@ -29,6 +29,7 @@ export class AnnotationWrapper implements IListable, Record<string, unknown> {
typeValue: string;
recategorizationType: string;
color: string;
dictionary: Dictionary;
comments: IComment[] = [];
firstTopLeftPoint: IPoint;
annotationId: string;
@ -102,7 +103,7 @@ export class AnnotationWrapper implements IListable, Record<string, unknown> {
}
get colorKey(): KeysOf<Dictionary> {
return this.isSkipped ? 'skippedHexColor' : this.isRecommendation ? 'recommendationHexColor' : 'hexColor';
return this.isSkipped || this.isIgnoredHint ? 'skippedHexColor' : this.isRecommendation ? 'recommendationHexColor' : 'hexColor';
}
get isSkipped() {
@ -154,7 +155,13 @@ export class AnnotationWrapper implements IListable, Record<string, unknown> {
}
get iconShape(): AnnotationIconType {
return this.isRecommendation ? 'hexagon' : this.isHint ? 'circle' : this.isSuggestion ? 'rhombus' : 'square';
return this.isRecommendation
? 'hexagon'
: this.isHint || this.isIgnoredHint
? 'circle'
: this.isSuggestion || this.isDeclinedSuggestion
? 'rhombus'
: 'square';
}
get isIgnoredHint() {
@ -262,7 +269,7 @@ export class AnnotationWrapper implements IListable, Record<string, unknown> {
return annotationWrapper;
}
static fromData(redactionLogEntry?: RedactionLogEntry) {
static fromData(redactionLogEntry: RedactionLogEntry, dictionaries: Dictionary[]) {
const annotationWrapper = new AnnotationWrapper();
annotationWrapper.annotationId = redactionLogEntry.id;
@ -312,6 +319,11 @@ export class AnnotationWrapper implements IListable, Record<string, unknown> {
this._handleRecommendations(annotationWrapper, redactionLogEntry);
annotationWrapper.typeLabel = this.#getTypeLabel(redactionLogEntry, annotationWrapper);
const type = annotationWrapper.isSuperTypeBasedColor ? annotationWrapper.superType : annotationWrapper.type;
const dictionary = dictionaries.find(d => d.type === type);
annotationWrapper.dictionary = dictionary;
annotationWrapper.color = dictionary[annotationWrapper.colorKey] as string;
return annotationWrapper;
}

View File

@ -11,13 +11,13 @@ export const SuperTypes = {
SuggestionRemoveDictionary: 'suggestion-remove-dictionary',
SuggestionAdd: 'suggestion-add',
SuggestionRemove: 'suggestion-remove',
IgnoredHint: 'ignored-hint',
IgnoredHint: 'hint-ignored',
Skipped: 'skipped',
Redaction: 'redaction',
ManualRedaction: 'manual-redaction',
Recommendation: 'recommendation',
Hint: 'hint',
DeclinedSuggestion: 'declined-suggestion',
DeclinedSuggestion: 'suggestion-declined',
} as const;
export type SuperType = ValuesOf<typeof SuperTypes>;

View File

@ -122,7 +122,7 @@ export class AnnotationActionsComponent implements OnChanges {
this._permissionsService.isApprover(dossier),
this._userService.currentUser,
this.annotations,
this._dictionariesMapService.get(dossier.dossierTemplateId),
this._state.dictionaries,
);
}
}

View File

@ -1,18 +1,25 @@
<div class="details">
<redaction-type-annotation-icon [annotation]="annotation"></redaction-type-annotation-icon>
<redaction-annotation-icon
[color]="annotation.color"
[label]="annotation.isHighlight ? '' : annotation.superType[0].toUpperCase()"
[type]="annotation.iconShape"
class="mt-6 mr-10"
></redaction-annotation-icon>
<div class="flex-1">
<div>
<strong>{{ annotation.typeLabel | translate }}</strong
>&nbsp;<strong *ngIf="annotation.pending && !annotation.isSuggestion" class="pending-analysis">{{
'annotation.pending' | translate
}}</strong>
<strong>{{ annotation.typeLabel | translate }}</strong>
&nbsp;
<strong *ngIf="annotation.pending && !annotation.isSuggestion" class="pending-analysis">
{{ 'annotation.pending' | translate }}
</strong>
</div>
<div *ngIf="annotation.type !== 'manual' && !annotation.isHighlight">
<strong>
<span>{{ annotation.descriptor | translate }}</span
>: </strong
>{{ (dictionary$ | async).label }}
>:
</strong>
{{ annotation.dictionary.label }}
</div>
<div *ngIf="annotation.shortContent && !annotation.isHint">
<strong><span translate="content"></span>: </strong>{{ annotation.shortContent }}

View File

@ -9,11 +9,6 @@
min-width: 20px;
}
redaction-type-annotation-icon {
margin-top: 6px;
margin-right: 10px;
}
.pending-analysis {
color: var(--iqser-red-1);
}

View File

@ -1,13 +1,6 @@
import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core';
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { MultiSelectService } from '../../services/multi-select.service';
import { FilePreviewStateService } from '../../services/file-preview-state.service';
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
import { Dictionary, DOSSIER_ID } from '@red/domain';
import { ActivatedRoute } from '@angular/router';
import { DossiersService } from '@services/dossiers/dossiers.service';
import { BehaviorSubject } from 'rxjs';
import { DictionaryService } from '@services/entity-services/dictionary.service';
@Component({
selector: 'redaction-annotation-card',
@ -15,34 +8,9 @@ import { DictionaryService } from '@services/entity-services/dictionary.service'
styleUrls: ['./annotation-card.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AnnotationCardComponent implements OnChanges {
export class AnnotationCardComponent {
@Input() annotation: AnnotationWrapper;
@Input() isSelected = false;
readonly dictionary$ = new BehaviorSubject<Dictionary>(undefined);
readonly #dossierId: string;
readonly #dossierTemplateId: string;
constructor(
route: ActivatedRoute,
dossiersService: DossiersService,
readonly multiSelectService: MultiSelectService,
private readonly _dictionariesMapService: DictionariesMapService,
private readonly _dictionaryService: DictionaryService,
private readonly _state: FilePreviewStateService,
) {
this.#dossierId = route.snapshot.paramMap.get(DOSSIER_ID);
this.#dossierTemplateId = dossiersService.find(this.#dossierId).dossierTemplateId;
}
ngOnChanges(changes: SimpleChanges): void {
if (changes.annotation) {
if (this.annotation.type !== 'manual' && !this.annotation.isHighlight) {
const dictionary =
this.annotation.type === 'dossier_redaction'
? this._state.dossierDictionary
: this._dictionariesMapService.getDictionary(this.annotation.type, this.#dossierTemplateId);
this.dictionary$.next(dictionary);
}
}
}
constructor(readonly multiSelectService: MultiSelectService) {}
}

View File

@ -1,5 +1,5 @@
<div>
<redaction-type-annotation-icon [annotation]="annotation" class="mr-8"></redaction-type-annotation-icon>
<redaction-annotation-icon [color]="annotation.color" [label]="''" [type]="'square'" class="mr-8"></redaction-annotation-icon>
<span [translateParams]="highlightGroup" [translate]="'highlights'" class="all-caps-label"></span>
</div>

View File

@ -1 +0,0 @@
<redaction-annotation-icon [color]="color" [label]="label" [type]="type"></redaction-annotation-icon>

View File

@ -1,53 +0,0 @@
import { Component, Input, OnChanges } from '@angular/core';
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { FilePreviewStateService } from '../../services/file-preview-state.service';
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
@Component({
selector: 'redaction-type-annotation-icon',
templateUrl: './type-annotation-icon.component.html',
styleUrls: ['./type-annotation-icon.component.scss'],
})
export class TypeAnnotationIconComponent implements OnChanges {
@Input() annotation: AnnotationWrapper;
label: string;
color: string;
type: 'square' | 'rhombus' | 'circle' | 'hexagon';
constructor(private _dictionariesMapService: DictionariesMapService, readonly screenStateService: FilePreviewStateService) {}
private get _dossierTemplateId(): string {
return this.screenStateService.dossierTemplateId;
}
ngOnChanges(): void {
if (!this.annotation) {
return;
}
const { isHighlight, isSuggestion, isRecommendation, isSkipped, isDeclinedSuggestion, isHint, isIgnoredHint } = this.annotation;
if (isHighlight) {
this.color = this.annotation.color;
} else {
const type = this.annotation.isSuperTypeBasedColor ? this.annotation.superType : this.annotation.type;
if (type === 'dossier_redaction') {
this.color = this.screenStateService.dossierDictionary[this.annotation.colorKey] as string;
} else {
// todo: use annotation.colorKey
this.color = this._dictionariesMapService.getDictionaryColor(
type,
this._dossierTemplateId,
isRecommendation,
isSkipped || isIgnoredHint,
);
}
}
this.type =
isSuggestion || isDeclinedSuggestion ? 'rhombus' : isHint || isIgnoredHint ? 'circle' : isRecommendation ? 'hexagon' : 'square';
this.label = isHighlight ? '' : isSuggestion || isDeclinedSuggestion || isSkipped ? 'S' : this.annotation.type[0].toUpperCase();
}
}

View File

@ -97,7 +97,10 @@ export class ManualAnnotationDialogComponent extends BaseDialogComponent impleme
this.isRectangle && !!this.form.get('multiplePages').value
? this.#getRectangles()
: [this.data.manualRedactionEntryWrapper];
this._dialogRef.close(annotations);
this._dialogRef.close({
annotations,
dictionary: this.possibleDictionaries.find(d => d.type === this.form.get('dictionary').value),
});
} catch (e) {
this._toaster.error(_('manual-annotation.dialog.error'));
}

View File

@ -22,7 +22,7 @@ import { ManualRedactionEntryWrapper } from '@models/file/manual-redaction-entry
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { AnnotationDrawService } from '../pdf-viewer/services/annotation-draw.service';
import { AnnotationProcessingService } from './services/annotation-processing.service';
import { File, ViewMode, ViewModes } from '@red/domain';
import { Dictionary, File, ViewMode, ViewModes } from '@red/domain';
import { PermissionsService } from '@services/permissions.service';
import { combineLatest, firstValueFrom, from, of, pairwise } from 'rxjs';
import { UserPreferenceService } from '@services/user-preference.service';
@ -194,12 +194,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
this._loadingService.start();
this._annotationManager.hide(annotations);
const highlights = await this._fileDataService.loadTextHighlights();
await this._annotationDrawService.draw(
highlights,
this.state.dossierTemplateId,
this._skippedService.hideSkipped,
this.state.dossierDictionary,
);
await this._annotationDrawService.draw(highlights, this._skippedService.hideSkipped, this.state.dictionaries);
this._loadingService.stop();
}
}
@ -256,16 +251,17 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
'manualAnnotation',
null,
{ manualRedactionEntryWrapper, dossierId: this.dossierId, file },
(wrappers: ManualRedactionEntryWrapper[]) => {
(result: { annotations: ManualRedactionEntryWrapper[]; dictionary?: Dictionary }) => {
const selectedAnnotations = this._annotationManager.selected;
if (selectedAnnotations.length > 0) {
this._annotationManager.delete([selectedAnnotations[0].Id]);
}
const manualRedactionService = this._injector.get(ManualRedactionService);
const add$ = manualRedactionService.addAnnotation(
wrappers.map(w => w.manualRedactionEntry).filter(e => e.positions[0].page <= file.numberOfPages),
result.annotations.map(w => w.manualRedactionEntry).filter(e => e.positions[0].page <= file.numberOfPages),
this.dossierId,
this.fileId,
result.dictionary?.label,
);
const filesService = this._injector.get(FilesService);
const addAndReload$ = add$.pipe(switchMap(() => filesService.reload(this.dossierId, file)));
@ -600,12 +596,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
this._handleDeltaAnnotationFilters(currentFilters);
}
await this._annotationDrawService.draw(
newAnnotations,
this.state.dossierTemplateId,
this._skippedService.hideSkipped,
this.state.dossierDictionary,
);
await this._annotationDrawService.draw(newAnnotations, this._skippedService.hideSkipped, this.state.dictionaries);
}
private _handleDeltaAnnotationFilters(currentFilters: NestedFilter[]) {

View File

@ -14,7 +14,6 @@ import { PageExclusionComponent } from './components/page-exclusion/page-exclusi
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';
@ -72,7 +71,6 @@ const components = [
AnnotationActionsComponent,
CommentsComponent,
DocumentInfoComponent,
TypeAnnotationIconComponent,
ViewSwitchComponent,
UserManagementComponent,
AnnotationReferencesListComponent,

View File

@ -235,12 +235,7 @@ export class AnnotationActionsService {
annotationWrapper.resizing = false;
this._annotationManager.delete(annotationWrapper);
await this._annotationDrawService.draw(
[annotationWrapper],
this._state.dossierTemplateId,
this._skippedService.hideSkipped,
this._state.dossierDictionary,
);
await this._annotationDrawService.draw([annotationWrapper], this._skippedService.hideSkipped, this._state.dictionaries);
this._annotationManager.deselect();
await this._fileDataService.annotationsChanged();
}
@ -276,13 +271,7 @@ export class AnnotationActionsService {
annotation.ReadOnly = false;
annotation.Hidden = false;
annotation.disableRotationControl();
const dossierTemplateId = this._state.dossierTemplateId;
annotation.FillColor = this._annotationDrawService.getAndConvertColor(
annotationWrapper.superType,
dossierTemplateId,
this._state.dossierDictionary,
annotationWrapper.type,
);
annotation.FillColor = this._annotationDrawService.convertColor(annotationWrapper.color);
annotation.StrokeColor = annotation.FillColor;
annotation.Opacity = 0.6;
annotation.StrokeThickness = 1;

View File

@ -66,18 +66,13 @@ export class AnnotationProcessingService {
// top level filter
if (topLevelFilter) {
this._createParentFilter(a.isHighlight ? a.filterKey : a.superType, filterMap, filters, a.isHighlight, {
color: a.isHighlight ? a.color : null,
color: a.color,
shortLabel: a.isHighlight ? '' : null,
shape: a.iconShape,
});
} else {
let parentFilter = filterMap.get(a.superType);
const dictionary =
a.type === 'dossier_redaction'
? this.#state.dossierDictionary
: this.#dictionariesMapService.getDictionary(a.type, this.#state.dossierTemplateId);
if (!parentFilter) {
parentFilter = this._createParentFilter(a.superType, filterMap, filters, false, {
shape: a.iconShape,
@ -85,11 +80,11 @@ export class AnnotationProcessingService {
}
const childFilter: IFilter = {
id: a.filterKey,
label: dictionary.label,
label: a.dictionary.label,
checked: false,
matches: 1,
metadata: {
color: dictionary[a.colorKey],
color: a.color,
shape: a.iconShape,
},
skipTranslation: true,

View File

@ -146,7 +146,7 @@ export class FileDataService extends EntitiesService<AnnotationWrapper> {
#buildAnnotations(redactionLog: IRedactionLog, file: File) {
const entries: RedactionLogEntry[] = this.#convertData(redactionLog, file);
const annotations = entries.map(entry => AnnotationWrapper.fromData(entry));
const annotations = entries.map(entry => AnnotationWrapper.fromData(entry, this._state.dictionaries));
return annotations.filter(ann => ann.manual || !file.excludedPages.includes(ann.pageNumber));
}
@ -154,11 +154,10 @@ export class FileDataService extends EntitiesService<AnnotationWrapper> {
#convertData(redactionLog: IRedactionLog, file: File): RedactionLogEntry[] {
let result: RedactionLogEntry[] = [];
const sourceIdAnnotationIds: { [key: string]: RedactionLogEntry[] } = {};
const dictionaries = this._dictionariesMapService.get(this._state.dossierTemplateId);
redactionLog.redactionLogEntry?.forEach(redactionLogEntry => {
const changeLogValues = this.#getChangeLogValues(redactionLogEntry, file);
const dictionary = dictionaries.find(dict => dict.type === redactionLogEntry.type);
const dictionary = this._state.dictionaries.find(dict => dict.type === redactionLogEntry.type);
if (!dictionary) {
this.missingTypes.add(redactionLogEntry.type);
return;

View File

@ -14,6 +14,7 @@ import { FilesService } from '@services/files/files.service';
import { DictionaryService } from '@services/entity-services/dictionary.service';
import { HttpEvent, HttpEventType, HttpProgressEvent, HttpResponse } from '@angular/common/http';
import { TranslateService } from '@ngx-translate/core';
import { DictionariesMapService } from '../../../services/entity-services/dictionaries-map.service';
const ONE_MEGABYTE = 1024 * 1024;
@ -55,6 +56,7 @@ export class FilePreviewStateService {
private readonly _dossiersService: DossiersService,
private readonly _fileManagementService: FileManagementService,
private readonly _dictionaryService: DictionaryService,
private readonly _dictionariesMapService: DictionariesMapService,
private readonly _translateService: TranslateService,
private readonly _loadingService: LoadingService,
) {
@ -83,6 +85,10 @@ export class FilePreviewStateService {
return this.#dossierDictionary;
}
get dictionaries(): Dictionary[] {
return this._dictionariesMapService.get(this.dossierTemplateId).concat([this.dossierDictionary]);
}
get blob(): Promise<Blob> {
return firstValueFrom(this.blob$);
}

View File

@ -18,7 +18,6 @@ import { dictionaryActionsTranslations, manualRedactionActionsTranslations } fro
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 { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
import { type ManualRedactionEntryType } from '@models/file/manual-redaction-entry.wrapper';
import { NGXLogger } from 'ngx-logger';
@ -46,7 +45,6 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
protected readonly _injector: Injector,
private readonly _permissionsService: PermissionsService,
private readonly _activeDossiersService: ActiveDossiersService,
private readonly _dictionariesMapService: DictionariesMapService,
) {
super(_injector, 'manualRedaction');
}
@ -92,8 +90,8 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
return this.requestRecategorize(body, dossierId, fileId).pipe(this.#showToast('request-image-recategorization'));
}
addAnnotation(requests: List<IAddRedactionRequest>, dossierId: string, fileId: string) {
const toast = requests[0].addToDictionary ? this.#showAddToDictionaryToast(requests, dossierId) : this.#showToast('add');
addAnnotation(requests: List<IAddRedactionRequest>, dossierId: string, fileId: string, dictionaryLabel?: string) {
const toast = requests[0].addToDictionary ? this.#showAddToDictionaryToast(requests, dictionaryLabel) : this.#showToast('add');
if (this._permissionsService.isApprover(this.#dossier(dossierId))) {
return this.add(requests, dossierId, fileId).pipe(toast);
}
@ -291,7 +289,7 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
});
}
#showAddToDictionaryToast(body: List<IAddRedactionRequest>, dossierId: string) {
#showAddToDictionaryToast(body: List<IAddRedactionRequest>, dictionaryLabel?: string) {
return tap({
next: () => this._toaster.success(getDictionaryMessage('add'), { positionClass: 'toast-file-preview' }),
error: (error: HttpErrorResponse) => {
@ -299,8 +297,7 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
this._toaster.error(getDictionaryMessage('add', true, isConflict), {
error,
params: {
dictionaryName: this._dictionariesMapService.getDictionary(body[0].type, this.#dossier(dossierId).dossierTemplateId)
.label,
dictionaryName: dictionaryLabel,
content: body[0].value,
},
positionClass: 'toast-file-preview',

View File

@ -144,9 +144,8 @@ export class PdfAnnotationActionsService {
#getAnnotationsPermissions(annotations: AnnotationWrapper[]) {
const dossier = this.#state.dossier;
const isApprover = this.#permissionsService.isApprover(dossier);
const dictionaries = this.#dictionariesMapService.get(dossier.dossierTemplateId);
const permissions = annotations.map(a => AnnotationPermissions.forUser(isApprover, this.#currentUser, a, dictionaries));
const permissions = annotations.map(a => AnnotationPermissions.forUser(isApprover, this.#currentUser, a, this.#state.dictionaries));
return {
canResize: permissions.length === 1 && permissions[0].canResizeAnnotation,
canChangeLegalBasis: permissions.reduce((acc, next) => acc && next.canChangeLegalBasis, true),

View File

@ -148,13 +148,7 @@ export class PdfProxyService {
}
private _configureElements() {
const dossierTemplateId = this._state.dossierTemplateId;
const color = this._annotationDrawService.getAndConvertColor(
dossierTemplateId,
dossierTemplateId,
this._state.dossierDictionary,
'manual',
);
const color = this._annotationDrawService.convertColor(this._state.dictionaries.find(d => d.type === 'manual').hexColor);
this._documentViewer.setRectangleToolStyles(color);
}

View File

@ -32,18 +32,14 @@ export class AnnotationDrawService {
private readonly _documentViewer: REDDocumentViewer,
) {}
async draw(annotations: List<AnnotationWrapper>, dossierTemplateId: string, hideSkipped: boolean, dossierDictionary: Dictionary) {
async draw(annotations: List<AnnotationWrapper>, hideSkipped: boolean, dictionaries: Dictionary[]) {
try {
await this._draw(annotations, dossierTemplateId, hideSkipped, dossierDictionary);
await this._draw(annotations, hideSkipped, dictionaries);
} catch (e) {
console.log(e);
}
}
getAndConvertColor(superType: string, dossierTemplateId: string, dossierDictionary: Dictionary, type?: string) {
return this.convertColor(this.#getColor(superType, dossierTemplateId, type, dossierDictionary));
}
convertColor(hexColor: string) {
return this._pdf.color(hexToRgb(hexColor));
}
@ -64,45 +60,10 @@ export class AnnotationDrawService {
return this._pdf.quad(x1, y1, x2, y2, x3, y3, x4, y4);
}
#getColor(superType: string, dossierTemplateId: string, type: string, dossierDictionary: Dictionary) {
let color: string;
let dictionary: Dictionary;
if (type === 'dossier_redaction') {
dictionary = dossierDictionary;
} else {
dictionary = this._dictionariesMapService.getDictionary(type, dossierTemplateId);
}
switch (superType) {
case SuperTypes.Hint:
case SuperTypes.Redaction:
color = dictionary.hexColor;
break;
case SuperTypes.Recommendation:
color = dictionary.recommendationHexColor;
break;
case SuperTypes.Skipped:
case SuperTypes.IgnoredHint:
color = dictionary.skippedHexColor;
break;
default:
color = dictionary.hexColor;
break;
}
return color;
}
private async _draw(
annotationWrappers: List<AnnotationWrapper>,
dossierTemplateId: string,
hideSkipped: boolean,
dossierDictionary: Dictionary,
) {
private async _draw(annotationWrappers: List<AnnotationWrapper>, hideSkipped: boolean, dictionaries: Dictionary[]) {
const totalPages = await firstValueFrom(this._pdf.totalPages$);
const annotations = annotationWrappers
.map(annotation => this._computeAnnotation(annotation, dossierTemplateId, hideSkipped, totalPages, dossierDictionary))
.map(annotation => this._computeAnnotation(annotation, hideSkipped, totalPages, dictionaries))
.filterTruthy();
const documentLoaded = await firstValueFrom(this._documentViewer.loaded$);
if (!documentLoaded) {
@ -114,27 +75,22 @@ export class AnnotationDrawService {
const { dossierId, fileId } = this._pdf;
const sectionsGrid$ = this._redactionLogService.getSectionGrid(dossierId, fileId);
const sectionsGrid = await firstValueFrom(sectionsGrid$).catch(() => ({ rectanglesPerPage: {} }));
await this._drawSections(sectionsGrid, dossierTemplateId, dossierDictionary);
await this._drawSections(sectionsGrid, dictionaries);
}
}
private async _drawSections(sectionGrid: ISectionGrid, dossierTemplateId: string, dossierDictionary: Dictionary) {
private async _drawSections(sectionGrid: ISectionGrid, dictionaries: Dictionary[]) {
const sections: Core.Annotations.RectangleAnnotation[] = [];
for (const page of Object.keys(sectionGrid.rectanglesPerPage)) {
const sectionRectangles = sectionGrid.rectanglesPerPage[page];
sectionRectangles.forEach(sectionRectangle => {
sections.push(this._computeSection(dossierTemplateId, parseInt(page, 10), sectionRectangle, dossierDictionary));
sections.push(this._computeSection(parseInt(page, 10), sectionRectangle, dictionaries));
});
}
await this._annotationManager.add(sections);
}
private _computeSection(
dossierTemplateId: string,
pageNumber: number,
sectionRectangle: ISectionRectangle,
dossierDictionary: Dictionary,
) {
private _computeSection(pageNumber: number, sectionRectangle: ISectionRectangle, dictionaries: Dictionary[]) {
const rectangleAnnot = this._pdf.rectangle();
const pageHeight = this._documentViewer.getHeight(pageNumber);
const rectangle: IRectangle = {
@ -149,19 +105,13 @@ export class AnnotationDrawService {
rectangleAnnot.Width = rectangle.width + 2;
rectangleAnnot.Height = rectangle.height + 2;
rectangleAnnot.ReadOnly = true;
rectangleAnnot.StrokeColor = this.getAndConvertColor('analysis', dossierTemplateId, dossierDictionary, 'analysis');
rectangleAnnot.StrokeColor = this.convertColor(dictionaries.find(d => d.type === 'analysis').hexColor);
rectangleAnnot.StrokeThickness = 1;
return rectangleAnnot;
}
private _computeAnnotation(
annotationWrapper: AnnotationWrapper,
dossierTemplateId: string,
hideSkipped: boolean,
totalPages: number,
dossierDictionary: Dictionary,
) {
private _computeAnnotation(annotationWrapper: AnnotationWrapper, hideSkipped: boolean, totalPages: number, dictionaries: Dictionary[]) {
const pageNumber = this._pdf.isCompare ? annotationWrapper.pageNumber * 2 - 1 : annotationWrapper.pageNumber;
if (pageNumber > totalPages) {
// skip imported annotations from files that have more pages than the current one
@ -190,12 +140,7 @@ export class AnnotationDrawService {
annotation.Opacity = annotationWrapper.isChangeLogRemoved ? DEFAULT_REMOVED_ANNOTATION_OPACITY : DEFAULT_TEXT_ANNOTATION_OPACITY;
annotation.setContents(annotationWrapper.content);
annotation.PageNumber = pageNumber;
annotation.StrokeColor = this.getAndConvertColor(
annotationWrapper.superType,
dossierTemplateId,
dossierDictionary,
annotationWrapper.type,
);
annotation.StrokeColor = this.convertColor(annotationWrapper.color);
annotation.Id = annotationWrapper.id;
annotation.ReadOnly = true;
@ -210,11 +155,8 @@ export class AnnotationDrawService {
annotation.setCustomData('changeLog', String(annotationWrapper.isChangeLogEntry));
annotation.setCustomData('changeLogRemoved', String(annotationWrapper.isChangeLogRemoved));
annotation.setCustomData('opacity', String(annotation.Opacity));
annotation.setCustomData('redactionColor', String(this.#getColor('redaction', dossierTemplateId, 'preview', dossierDictionary)));
annotation.setCustomData(
'annotationColor',
String(this.#getColor(annotationWrapper.superType, dossierTemplateId, annotationWrapper.type, dossierDictionary)),
);
annotation.setCustomData('redactionColor', String(dictionaries.find(d => d.type === 'preview').hexColor));
annotation.setCustomData('annotationColor', String(annotationWrapper.color));
return annotation;
}

View File

@ -13,7 +13,6 @@ export class DictionariesMapService extends EntitiesMapService<Dictionary, IDict
return this.get(dossierTemplateId, type) || this.get(dossierTemplateId, 'default');
}
// todo is this necessary?
getDictionaryColor(type: string, dossierTemplateId: string, isRecommendation = false, isSkipped = false) {
const defaultColor = '#CCCCCC';
if (!this.get(dossierTemplateId)) {

View File

@ -237,12 +237,6 @@ export class DictionaryService extends EntitiesService<Dictionary, IDictionary>
}),
map(colors => {
const virtualTypes = [
{
hexColor: colors.manualRedactionColor || FALLBACK_COLOR,
type: 'dossier_redaction',
hint: false,
recommendation: false,
},
{ hexColor: colors.notRedacted || FALLBACK_COLOR, type: SuperTypes.DeclinedSuggestion },
{ hexColor: colors.manualRedactionColor || FALLBACK_COLOR, type: 'manual' },
{ hexColor: colors.ignoredHintColor || FALLBACK_COLOR, type: SuperTypes.IgnoredHint },

@ -1 +1 @@
Subproject commit 738c38cf5f13de9542facd84d8c70f9929b980e6
Subproject commit f2f7283c9c97e30752fdd4cf56ca3b41999e6962