RED-4639: Refactor annotation colors
This commit is contained in:
parent
e030b20f04
commit
5427de6f58
@ -1,26 +1,27 @@
|
||||
import { annotationTypesTranslations, SuggestionAddFalsePositive } from '@translations/annotation-types-translations';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import {
|
||||
annotationDefaultColorConfig,
|
||||
annotationEntityColorConfig,
|
||||
AnnotationIconType,
|
||||
DefaultColors,
|
||||
Dictionary,
|
||||
FalsePositiveSuperTypes,
|
||||
Highlight,
|
||||
IComment,
|
||||
IManualChange,
|
||||
IPoint,
|
||||
IRectangle,
|
||||
LogEntryStatus,
|
||||
ManualRedactionType,
|
||||
} from '@red/domain';
|
||||
import { RedactionLogEntry } from '@models/file/redaction-log.entry';
|
||||
import {
|
||||
FalsePositiveSuperTypes,
|
||||
LowLevelFilterTypes,
|
||||
ManualRedactionType,
|
||||
SuggestionAddSuperTypes,
|
||||
SuggestionsSuperTypes,
|
||||
SuperType,
|
||||
SuperTypes,
|
||||
} from '@models/file/super-types';
|
||||
import { IListable, KeysOf, List } from '@iqser/common-ui';
|
||||
} from '@red/domain';
|
||||
import { RedactionLogEntry } from '@models/file/redaction-log.entry';
|
||||
import { IListable, List } from '@iqser/common-ui';
|
||||
|
||||
export class AnnotationWrapper implements IListable, Record<string, unknown> {
|
||||
[x: string]: unknown;
|
||||
@ -29,7 +30,7 @@ export class AnnotationWrapper implements IListable, Record<string, unknown> {
|
||||
typeValue: string;
|
||||
recategorizationType: string;
|
||||
color: string;
|
||||
dictionary: Dictionary;
|
||||
entity: Dictionary;
|
||||
comments: IComment[] = [];
|
||||
firstTopLeftPoint: IPoint;
|
||||
annotationId: string;
|
||||
@ -102,18 +103,6 @@ export class AnnotationWrapper implements IListable, Record<string, unknown> {
|
||||
return this.isSuggestion || this.isDeclinedSuggestion;
|
||||
}
|
||||
|
||||
get colorKey(): KeysOf<Dictionary> {
|
||||
if (this.isSkipped || this.isIgnoredHint) {
|
||||
return 'skippedHexColor';
|
||||
}
|
||||
|
||||
if (this.isRecommendation) {
|
||||
return 'recommendationHexColor';
|
||||
}
|
||||
|
||||
return 'hexColor';
|
||||
}
|
||||
|
||||
get isSkipped() {
|
||||
return this.superType === SuperTypes.Skipped;
|
||||
}
|
||||
@ -283,7 +272,7 @@ export class AnnotationWrapper implements IListable, Record<string, unknown> {
|
||||
return annotationWrapper;
|
||||
}
|
||||
|
||||
static fromData(redactionLogEntry: RedactionLogEntry, dictionaries: Dictionary[]) {
|
||||
static fromData(redactionLogEntry: RedactionLogEntry, dictionaries: Dictionary[], defaultColors: DefaultColors) {
|
||||
const annotationWrapper = new AnnotationWrapper();
|
||||
|
||||
annotationWrapper.annotationId = redactionLogEntry.id;
|
||||
@ -333,10 +322,13 @@ 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;
|
||||
const entity = dictionaries.find(d => d.type === annotationWrapper.typeValue);
|
||||
annotationWrapper.entity = entity.virtual ? null : entity;
|
||||
|
||||
const colorKey = annotationWrapper.isSuperTypeBasedColor
|
||||
? annotationDefaultColorConfig[annotationWrapper.superType]
|
||||
: annotationEntityColorConfig[annotationWrapper.superType];
|
||||
annotationWrapper.color = annotationWrapper.isSuperTypeBasedColor ? defaultColors[colorKey] : (entity[colorKey] as string);
|
||||
|
||||
return annotationWrapper;
|
||||
}
|
||||
|
||||
@ -1,16 +1,15 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { DefaultColorType, IColors } from '@red/domain';
|
||||
import { DefaultColorType } from '@red/domain';
|
||||
import { BaseDialogComponent } from '@iqser/common-ui';
|
||||
import { UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { defaultColorsTranslations } from '@translations/default-colors-translations';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { DictionaryService } from '@services/entity-services/dictionary.service';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { DefaultColorsService } from '@services/entity-services/default-colors.service';
|
||||
|
||||
interface IEditColorData {
|
||||
colors: IColors;
|
||||
colorKey: DefaultColorType;
|
||||
dossierTemplateId: string;
|
||||
}
|
||||
@ -23,7 +22,7 @@ export class EditColorDialogComponent extends BaseDialogComponent {
|
||||
readonly translations = defaultColorsTranslations;
|
||||
|
||||
constructor(
|
||||
private readonly _dictionaryService: DictionaryService,
|
||||
private readonly _defaultColorsService: DefaultColorsService,
|
||||
private readonly _translateService: TranslateService,
|
||||
protected readonly _dialogRef: MatDialogRef<EditColorDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) readonly data: IEditColorData,
|
||||
@ -35,24 +34,29 @@ export class EditColorDialogComponent extends BaseDialogComponent {
|
||||
}
|
||||
|
||||
async save() {
|
||||
const colors = {
|
||||
...this.data.colors,
|
||||
const colors: Partial<Record<DefaultColorType, string>> = {
|
||||
[this.data.colorKey]: this.form.get('color').value,
|
||||
};
|
||||
|
||||
this._loadingService.start();
|
||||
try {
|
||||
await firstValueFrom(this._dictionaryService.setColors(colors, this.data.dossierTemplateId));
|
||||
await firstValueFrom(this._defaultColorsService.update(colors, this.data.dossierTemplateId));
|
||||
this._dialogRef.close(true);
|
||||
this._loadingService.stop();
|
||||
const color = this._translateService.instant(defaultColorsTranslations[this.data.colorKey]);
|
||||
this._toaster.info(_('edit-color-dialog.success'), { params: { color: color } });
|
||||
} catch (e) {
|
||||
this._toaster.error(_('edit-color-dialog.error'));
|
||||
}
|
||||
this._loadingService.stop();
|
||||
}
|
||||
|
||||
private _getForm(): UntypedFormGroup {
|
||||
return this._formBuilder.group({
|
||||
color: [this.data.colors[this.data.colorKey], [Validators.required, Validators.minLength(7)]],
|
||||
color: [
|
||||
this._defaultColorsService.find(this.data.dossierTemplateId)[this.data.colorKey],
|
||||
[Validators.required, Validators.minLength(7)],
|
||||
],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
<section>
|
||||
<section *ngIf="context$ | async as context">
|
||||
<div class="page-header">
|
||||
<redaction-dossier-template-breadcrumbs class="flex-1"></redaction-dossier-template-breadcrumbs>
|
||||
|
||||
@ -26,19 +26,19 @@
|
||||
</section>
|
||||
|
||||
<ng-template #tableItemTemplate let-entity="entity">
|
||||
<div *ngIf="cast(entity) as color">
|
||||
<div>
|
||||
<div class="cell">
|
||||
<div [translate]="translations[color.key]" class="table-item-title heading"></div>
|
||||
<div [translate]="translations[entity.key]" class="table-item-title heading"></div>
|
||||
</div>
|
||||
|
||||
<div class="cell color-wrapper">
|
||||
<div [ngStyle]="{ 'background-color': color.value }" class="color-square"></div>
|
||||
<div [ngStyle]="{ 'background-color': entity.value }" class="color-square"></div>
|
||||
</div>
|
||||
|
||||
<div class="cell">
|
||||
<div class="action-buttons">
|
||||
<iqser-circle-button
|
||||
(action)="openEditColorDialog($event, color)"
|
||||
(action)="openEditColorDialog($event, entity)"
|
||||
*ngIf="currentUser.isAdmin"
|
||||
[tooltip]="'default-colors-screen.action.edit' | translate"
|
||||
[type]="circleButtonTypes.dark"
|
||||
|
||||
@ -1,20 +1,13 @@
|
||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||
import { DefaultColorType, DOSSIER_TEMPLATE_ID, IColors } from '@red/domain';
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { DefaultColorTypes, DOSSIER_TEMPLATE_ID } from '@red/domain';
|
||||
import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
import {
|
||||
CircleButtonTypes,
|
||||
getParam,
|
||||
IListable,
|
||||
ListingComponent,
|
||||
listingProvidersFactory,
|
||||
LoadingService,
|
||||
TableColumnConfig,
|
||||
} from '@iqser/common-ui';
|
||||
import { CircleButtonTypes, getParam, IListable, ListingComponent, listingProvidersFactory, TableColumnConfig } from '@iqser/common-ui';
|
||||
import { defaultColorsTranslations } from '@translations/default-colors-translations';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { getCurrentUser } from '@services/user.service';
|
||||
import { DictionaryService } from '@services/entity-services/dictionary.service';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import { map, tap } from 'rxjs/operators';
|
||||
import { DefaultColorsService } from '@services/entity-services/default-colors.service';
|
||||
|
||||
interface ListItem extends IListable {
|
||||
readonly key: string;
|
||||
@ -27,7 +20,7 @@ interface ListItem extends IListable {
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: listingProvidersFactory(DefaultColorsScreenComponent),
|
||||
})
|
||||
export class DefaultColorsScreenComponent extends ListingComponent<ListItem> implements OnInit {
|
||||
export class DefaultColorsScreenComponent extends ListingComponent<ListItem> {
|
||||
readonly circleButtonTypes = CircleButtonTypes;
|
||||
readonly currentUser = getCurrentUser();
|
||||
readonly translations = defaultColorsTranslations;
|
||||
@ -36,50 +29,22 @@ export class DefaultColorsScreenComponent extends ListingComponent<ListItem> imp
|
||||
{ label: _('default-colors-screen.table-col-names.key'), sortByKey: 'searchKey', width: '2fr' },
|
||||
{ label: _('default-colors-screen.table-col-names.color'), class: 'flex-center' },
|
||||
];
|
||||
|
||||
#colorsObj: IColors;
|
||||
readonly context$;
|
||||
readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID);
|
||||
|
||||
constructor(
|
||||
private readonly _loadingService: LoadingService,
|
||||
private readonly _dialogService: AdminDialogService,
|
||||
private readonly _dictionaryService: DictionaryService,
|
||||
) {
|
||||
constructor(private readonly _dialogService: AdminDialogService, private readonly _defaultColorsService: DefaultColorsService) {
|
||||
super();
|
||||
}
|
||||
|
||||
openEditColorDialog($event: MouseEvent, color: { key: DefaultColorType | string; value: string }) {
|
||||
this._dialogService.openDialog(
|
||||
'editColor',
|
||||
$event,
|
||||
{
|
||||
colors: this.#colorsObj,
|
||||
colorKey: color.key,
|
||||
dossierTemplateId: this.#dossierTemplateId,
|
||||
},
|
||||
async () => {
|
||||
await this._loadColors();
|
||||
},
|
||||
this.context$ = combineLatest([this._defaultColorsService.all$]).pipe(
|
||||
map(([allDefaultColors]) => {
|
||||
const color = allDefaultColors.find(c => c.id === this.#dossierTemplateId);
|
||||
return DefaultColorTypes.map(key => ({ id: key, key, searchKey: key, value: color[key] }));
|
||||
}),
|
||||
tap(colors => this.entitiesService.setEntities(colors)),
|
||||
);
|
||||
}
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
await this._loadColors();
|
||||
}
|
||||
|
||||
private async _loadColors() {
|
||||
this._loadingService.start();
|
||||
const data = await firstValueFrom(this._dictionaryService.getColors(this.#dossierTemplateId));
|
||||
this.#colorsObj = data;
|
||||
const entities = Object.keys(data)
|
||||
.map(key => ({
|
||||
id: key,
|
||||
key,
|
||||
searchKey: key,
|
||||
value: data[key],
|
||||
}))
|
||||
.filter(entry => entry.id !== DOSSIER_TEMPLATE_ID);
|
||||
this.entitiesService.setEntities(entities);
|
||||
this._loadingService.stop();
|
||||
openEditColorDialog($event: MouseEvent, color: ListItem) {
|
||||
this._dialogService.openDialog('editColor', $event, { colorKey: color.key, dossierTemplateId: this.#dossierTemplateId });
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,7 +85,7 @@
|
||||
<div class="cell center">
|
||||
<redaction-annotation-icon
|
||||
[color]="dict.hexColor"
|
||||
[label]="dict.label.charAt(0)"
|
||||
[label]="dict.hint ? 'H' : 'R'"
|
||||
[type]="dict.hint ? 'circle' : 'square'"
|
||||
></redaction-annotation-icon>
|
||||
</div>
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||
import { File } from '@red/domain';
|
||||
import { annotationDefaultColorConfig, DefaultBasedColorType, File } from '@red/domain';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||
import { DossiersService } from '@services/dossiers/dossiers.service';
|
||||
import { DefaultColorsService } from '@services/entity-services/default-colors.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-file-workload',
|
||||
@ -15,36 +15,36 @@ export class FileWorkloadComponent {
|
||||
|
||||
constructor(
|
||||
readonly userService: UserService,
|
||||
private readonly _dictionariesMapService: DictionariesMapService,
|
||||
private readonly _defaultColorsService: DefaultColorsService,
|
||||
private readonly _dossiersService: DossiersService,
|
||||
) {}
|
||||
|
||||
get suggestionColor() {
|
||||
return this._getDictionaryColor('suggestion');
|
||||
return this._getDefaultColor('suggestion');
|
||||
}
|
||||
|
||||
get imageColor() {
|
||||
return this._getDictionaryColor('image');
|
||||
return this._getDefaultColor('recommendation');
|
||||
}
|
||||
|
||||
get updatedColor() {
|
||||
return this._getDictionaryColor('updated');
|
||||
return this._getDefaultColor('updated');
|
||||
}
|
||||
|
||||
get analysisColor() {
|
||||
return this._getDictionaryColor('analysis');
|
||||
return this._getDefaultColor('analysis');
|
||||
}
|
||||
|
||||
get hintColor() {
|
||||
return this._getDictionaryColor('hint');
|
||||
return this._getDefaultColor('hint');
|
||||
}
|
||||
|
||||
get redactionColor() {
|
||||
return this._getDictionaryColor('redaction');
|
||||
return this._getDefaultColor('redaction');
|
||||
}
|
||||
|
||||
private _getDictionaryColor(type: string) {
|
||||
private _getDefaultColor(type: DefaultBasedColorType) {
|
||||
const dossierTemplateId = this._dossiersService.find(this.file.dossierId).dossierTemplateId;
|
||||
return this._dictionariesMapService.getDictionaryColor(type, dossierTemplateId);
|
||||
return this._defaultColorsService.getColor(dossierTemplateId, annotationDefaultColorConfig[type]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ import {
|
||||
WorkflowConfig,
|
||||
} from '@iqser/common-ui';
|
||||
import {
|
||||
annotationDefaultColorConfig,
|
||||
AnnotationShapeMap,
|
||||
Dossier,
|
||||
File,
|
||||
@ -33,6 +34,7 @@ import { ConfigService as AppConfigService } from '@services/config.service';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { BulkActionsService } from './services/bulk-actions.service';
|
||||
import dayjs from 'dayjs';
|
||||
import { DefaultColorsService } from '@services/entity-services/default-colors.service';
|
||||
|
||||
@Injectable()
|
||||
export class ConfigService {
|
||||
@ -46,6 +48,7 @@ export class ConfigService {
|
||||
private readonly _dialogService: DossiersDialogService,
|
||||
private readonly _appConfigService: AppConfigService,
|
||||
private readonly _bulkActionsService: BulkActionsService,
|
||||
private readonly _defaultColorsService: DefaultColorsService,
|
||||
) {
|
||||
this.listingMode$ = this._listingMode$.asObservable();
|
||||
}
|
||||
@ -171,6 +174,7 @@ export class ConfigService {
|
||||
filterGroups(
|
||||
entities: File[],
|
||||
fileAttributeConfigs: IFileAttributeConfig[],
|
||||
dossierTemplateId: string,
|
||||
needsWorkFilterTemplate: TemplateRef<unknown>,
|
||||
checkedRequiredFilters: () => NestedFilter[],
|
||||
checkedNotRequiredFilters: () => NestedFilter[],
|
||||
@ -286,7 +290,10 @@ export class ConfigService {
|
||||
new NestedFilter({
|
||||
id: item,
|
||||
label: workloadTranslations[item],
|
||||
metadata: { shape: AnnotationShapeMap[item] },
|
||||
metadata: {
|
||||
color: this._defaultColorsService.getColor(dossierTemplateId, annotationDefaultColorConfig[item]),
|
||||
shape: AnnotationShapeMap[item],
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@ -211,6 +211,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<File> imple
|
||||
const filterGroups = this.configService.filterGroups(
|
||||
this.entitiesService.all,
|
||||
this._fileAttributeConfigs,
|
||||
this.dossierTemplateId,
|
||||
this._needsWorkFilterTemplate,
|
||||
() => this.checkedRequiredFilters,
|
||||
() => this.checkedNotRequiredFilters,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||
import { Dossier, DossierStats } from '@red/domain';
|
||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||
import { DefaultColorsService } from '@services/entity-services/default-colors.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-dossier-workload-column',
|
||||
@ -12,17 +12,17 @@ export class DossierWorkloadColumnComponent {
|
||||
@Input() dossier: Dossier;
|
||||
@Input() dossierStats: DossierStats;
|
||||
|
||||
constructor(private readonly _dictionariesMapService: DictionariesMapService) {}
|
||||
constructor(private readonly _colorsService: DefaultColorsService) {}
|
||||
|
||||
get suggestionColor() {
|
||||
return this._dictionariesMapService.getDictionaryColor('suggestion', this.dossier.dossierTemplateId);
|
||||
return this._colorsService.getColor(this.dossier.dossierTemplateId, 'requestAddColor');
|
||||
}
|
||||
|
||||
get hintColor() {
|
||||
return this._dictionariesMapService.getDictionaryColor('hint', this.dossier.dossierTemplateId);
|
||||
return this._colorsService.getColor(this.dossier.dossierTemplateId, 'hintColor');
|
||||
}
|
||||
|
||||
get redactionColor() {
|
||||
return this._dictionariesMapService.getDictionaryColor('redaction', this.dossier.dossierTemplateId);
|
||||
return this._colorsService.getColor(this.dossier.dossierTemplateId, 'redactionColor');
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,12 +14,12 @@
|
||||
{{ 'annotation.pending' | translate }}
|
||||
</strong>
|
||||
</div>
|
||||
<div *ngIf="annotation.type !== 'manual' && !annotation.isHighlight">
|
||||
<div *ngIf="annotation.entity">
|
||||
<strong>
|
||||
<span>{{ annotation.descriptor | translate }}</span
|
||||
>:
|
||||
</strong>
|
||||
{{ annotation.dictionary.label }}
|
||||
{{ annotation.entity.label }}
|
||||
</div>
|
||||
<div *ngIf="annotation.shortContent && !annotation.isHint">
|
||||
<strong><span translate="content"></span>: </strong>{{ annotation.shortContent }}
|
||||
|
||||
@ -181,7 +181,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._skippedService.hideSkipped, this.state.dictionaries);
|
||||
await this._annotationDrawService.draw(highlights, this._skippedService.hideSkipped, this.state.dossierTemplateId);
|
||||
this._loadingService.stop();
|
||||
}
|
||||
}
|
||||
@ -574,7 +574,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
||||
this._handleDeltaAnnotationFilters(currentFilters);
|
||||
}
|
||||
|
||||
await this._annotationDrawService.draw(newAnnotations, this._skippedService.hideSkipped, this.state.dictionaries);
|
||||
await this._annotationDrawService.draw(newAnnotations, this._skippedService.hideSkipped, this.state.dossierTemplateId);
|
||||
}
|
||||
|
||||
private _handleDeltaAnnotationFilters(currentFilters: NestedFilter[]) {
|
||||
|
||||
@ -235,7 +235,7 @@ export class AnnotationActionsService {
|
||||
annotationWrapper.resizing = false;
|
||||
|
||||
this._annotationManager.delete(annotationWrapper);
|
||||
await this._annotationDrawService.draw([annotationWrapper], this._skippedService.hideSkipped, this._state.dictionaries);
|
||||
await this._annotationDrawService.draw([annotationWrapper], this._skippedService.hideSkipped, this._state.dossierTemplateId);
|
||||
this._annotationManager.deselect();
|
||||
await this._fileDataService.annotationsChanged();
|
||||
}
|
||||
|
||||
@ -1,19 +1,21 @@
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||
import { SuperTypeSorter } from '../../../utils';
|
||||
import { Filter, handleCheckedValue, IFilter, INestedFilter, NestedFilter } from '@iqser/common-ui';
|
||||
import { annotationTypesTranslations } from '@translations/annotation-types-translations';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { IViewedPage } from '@red/domain';
|
||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||
import { annotationDefaultColorConfig, IViewedPage } from '@red/domain';
|
||||
import { FilePreviewStateService } from './file-preview-state.service';
|
||||
import { FileDataService } from './file-data.service';
|
||||
import { DefaultColorsService } from '@services/entity-services/default-colors.service';
|
||||
|
||||
@Injectable()
|
||||
export class AnnotationProcessingService {
|
||||
readonly #fileDataService = inject(FileDataService);
|
||||
readonly #state = inject(FilePreviewStateService);
|
||||
readonly #dictionariesMapService = inject(DictionariesMapService);
|
||||
constructor(
|
||||
private readonly _fileDataService: FileDataService,
|
||||
private readonly _state: FilePreviewStateService,
|
||||
private readonly _defaultColorsService: DefaultColorsService,
|
||||
) {}
|
||||
|
||||
static secondaryAnnotationFilters(viewedPages?: IViewedPage[]): INestedFilter[] {
|
||||
const _viewedPages = viewedPages ? viewedPages.map(page => page.page) : [];
|
||||
@ -57,7 +59,7 @@ export class AnnotationProcessingService {
|
||||
const filterMap = new Map<string, INestedFilter>();
|
||||
const filters: INestedFilter[] = [];
|
||||
|
||||
this.#fileDataService.all?.forEach(a => {
|
||||
this._fileDataService.all?.forEach(a => {
|
||||
const topLevelFilter = a.topLevelFilter;
|
||||
const filter = filterMap.get(a.filterKey);
|
||||
if (filter) {
|
||||
@ -76,11 +78,15 @@ export class AnnotationProcessingService {
|
||||
if (!parentFilter) {
|
||||
parentFilter = this._createParentFilter(a.superType, filterMap, filters, false, {
|
||||
shape: a.iconShape,
|
||||
color: this._defaultColorsService.getColor(
|
||||
this._state.dossierTemplateId,
|
||||
annotationDefaultColorConfig[a.superType],
|
||||
),
|
||||
});
|
||||
}
|
||||
const childFilter: IFilter = {
|
||||
id: a.filterKey,
|
||||
label: a.dictionary.label,
|
||||
label: a.entity.label,
|
||||
checked: false,
|
||||
matches: 1,
|
||||
metadata: {
|
||||
|
||||
@ -18,6 +18,7 @@ import dayjs from 'dayjs';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { MultiSelectService } from './multi-select.service';
|
||||
import { FilesService } from '@services/files/files.service';
|
||||
import { DefaultColorsService } from '@services/entity-services/default-colors.service';
|
||||
|
||||
const DELTA_VIEW_TIME = 10 * 60 * 1000; // 10 minutes;
|
||||
|
||||
@ -44,6 +45,7 @@ export class FileDataService extends EntitiesService<AnnotationWrapper> {
|
||||
private readonly _filesService: FilesService,
|
||||
private readonly _toaster: Toaster,
|
||||
private readonly _logger: NGXLogger,
|
||||
private readonly _defaultColorsService: DefaultColorsService,
|
||||
) {
|
||||
super();
|
||||
this.annotations$ = this.#annotations$;
|
||||
@ -144,7 +146,9 @@ 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, this._state.dictionaries));
|
||||
const annotations = entries.map(entry =>
|
||||
AnnotationWrapper.fromData(entry, this._state.dictionaries, this._defaultColorsService.find(this._state.dossierTemplateId)),
|
||||
);
|
||||
|
||||
return annotations.filter(ann => ann.manual || !file.excludedPages.includes(ann.pageNumber));
|
||||
}
|
||||
|
||||
@ -6,9 +6,9 @@ import {
|
||||
ManualRedactionEntryType,
|
||||
ManualRedactionEntryTypes,
|
||||
ManualRedactionEntryWrapper,
|
||||
} from '../../../models/file/manual-redaction-entry.wrapper';
|
||||
} from '@models/file/manual-redaction-entry.wrapper';
|
||||
import { AnnotationDrawService } from '../../pdf-viewer/services/annotation-draw.service';
|
||||
import { UserPreferenceService } from '../../../services/user-preference.service';
|
||||
import { UserPreferenceService } from '@services/user-preference.service';
|
||||
import { BASE_HREF_FN, BaseHrefFn } from '../../../tokens';
|
||||
import { shareDistinctLast } from '@iqser/common-ui';
|
||||
import { toPosition } from '../utils/pdf-calculation.utils';
|
||||
@ -25,9 +25,10 @@ import { ALLOWED_ACTIONS_WHEN_PAGE_EXCLUDED, HEADER_ITEMS_TO_TOGGLE, TEXT_POPUPS
|
||||
import { REDDocumentViewer } from '../../pdf-viewer/services/document-viewer.service';
|
||||
import { combineLatest, Observable, Subject } from 'rxjs';
|
||||
import { ViewModeService } from './view-mode.service';
|
||||
import { PermissionsService } from '../../../services/permissions.service';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { AnnotationsListingService } from './annotations-listing.service';
|
||||
import { PdfAnnotationActionsService } from './pdf-annotation-actions.service';
|
||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||
import Annotation = Core.Annotations.Annotation;
|
||||
import Quad = Core.Math.Quad;
|
||||
|
||||
@ -69,6 +70,7 @@ export class PdfProxyService {
|
||||
private readonly _multiSelectService: MultiSelectService,
|
||||
private readonly _listingService: AnnotationsListingService,
|
||||
private readonly _changeDetectorRef: ChangeDetectorRef,
|
||||
private readonly _dictionariesMapService: DictionariesMapService,
|
||||
) {
|
||||
this.canPerformAnnotationActions$ = this.#canPerformAnnotationActions$;
|
||||
}
|
||||
@ -148,7 +150,9 @@ export class PdfProxyService {
|
||||
}
|
||||
|
||||
private _configureElements() {
|
||||
const color = this._annotationDrawService.convertColor(this._state.dictionaries.find(d => d.type === 'manual').hexColor);
|
||||
const color = this._annotationDrawService.convertColor(
|
||||
this._dictionariesMapService.get(this._state.dossierTemplateId, 'manual').hexColor,
|
||||
);
|
||||
this._documentViewer.setRectangleToolStyles(color);
|
||||
}
|
||||
|
||||
|
||||
@ -5,15 +5,16 @@ import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||
import { UserPreferenceService } from '@services/user-preference.service';
|
||||
import { RedactionLogService } from '@services/files/redaction-log.service';
|
||||
|
||||
import { Dictionary, IRectangle, ISectionGrid, ISectionRectangle } from '@red/domain';
|
||||
import { IRectangle, ISectionGrid, ISectionRectangle } from '@red/domain';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||
import { SuperTypes } from '@models/file/super-types';
|
||||
import { SuperTypes } from '@red/domain';
|
||||
import { PdfViewer } from './pdf-viewer.service';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { REDAnnotationManager } from './annotation-manager.service';
|
||||
import { List } from '@iqser/common-ui';
|
||||
import { REDDocumentViewer } from './document-viewer.service';
|
||||
import { DefaultColorsService } from '@services/entity-services/default-colors.service';
|
||||
import Annotation = Core.Annotations.Annotation;
|
||||
import Quad = Core.Math.Quad;
|
||||
|
||||
@ -30,13 +31,14 @@ export class AnnotationDrawService {
|
||||
private readonly _annotationManager: REDAnnotationManager,
|
||||
private readonly _pdf: PdfViewer,
|
||||
private readonly _documentViewer: REDDocumentViewer,
|
||||
private readonly _defaultColorsService: DefaultColorsService,
|
||||
) {}
|
||||
|
||||
async draw(annotations: List<AnnotationWrapper>, hideSkipped: boolean, dictionaries: Dictionary[]) {
|
||||
async draw(annotations: List<AnnotationWrapper>, hideSkipped: boolean, dossierTemplateId: string) {
|
||||
try {
|
||||
await this._draw(annotations, hideSkipped, dictionaries);
|
||||
await this._draw(annotations, hideSkipped, dossierTemplateId);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,10 +62,10 @@ export class AnnotationDrawService {
|
||||
return this._pdf.quad(x1, y1, x2, y2, x3, y3, x4, y4);
|
||||
}
|
||||
|
||||
private async _draw(annotationWrappers: List<AnnotationWrapper>, hideSkipped: boolean, dictionaries: Dictionary[]) {
|
||||
private async _draw(annotationWrappers: List<AnnotationWrapper>, hideSkipped: boolean, dossierTemplateId: string) {
|
||||
const totalPages = await firstValueFrom(this._pdf.totalPages$);
|
||||
const annotations = annotationWrappers
|
||||
.map(annotation => this._computeAnnotation(annotation, hideSkipped, totalPages, dictionaries))
|
||||
.map(annotation => this._computeAnnotation(annotation, hideSkipped, totalPages, dossierTemplateId))
|
||||
.filterTruthy();
|
||||
const documentLoaded = await firstValueFrom(this._documentViewer.loaded$);
|
||||
if (!documentLoaded) {
|
||||
@ -75,22 +77,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, dictionaries);
|
||||
await this._drawSections(sectionsGrid, dossierTemplateId);
|
||||
}
|
||||
}
|
||||
|
||||
private async _drawSections(sectionGrid: ISectionGrid, dictionaries: Dictionary[]) {
|
||||
private async _drawSections(sectionGrid: ISectionGrid, dossierTemplateId: string) {
|
||||
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(parseInt(page, 10), sectionRectangle, dictionaries));
|
||||
sections.push(this._computeSection(parseInt(page, 10), sectionRectangle, dossierTemplateId));
|
||||
});
|
||||
}
|
||||
await this._annotationManager.add(sections);
|
||||
}
|
||||
|
||||
private _computeSection(pageNumber: number, sectionRectangle: ISectionRectangle, dictionaries: Dictionary[]) {
|
||||
private _computeSection(pageNumber: number, sectionRectangle: ISectionRectangle, dossierTemplateId: string) {
|
||||
const rectangleAnnot = this._pdf.rectangle();
|
||||
const pageHeight = this._documentViewer.getHeight(pageNumber);
|
||||
const rectangle: IRectangle = {
|
||||
@ -105,13 +107,13 @@ export class AnnotationDrawService {
|
||||
rectangleAnnot.Width = rectangle.width + 2;
|
||||
rectangleAnnot.Height = rectangle.height + 2;
|
||||
rectangleAnnot.ReadOnly = true;
|
||||
rectangleAnnot.StrokeColor = this.convertColor(dictionaries.find(d => d.type === 'analysis').hexColor);
|
||||
rectangleAnnot.StrokeColor = this.convertColor(this._defaultColorsService.getColor(dossierTemplateId, 'analysisColor'));
|
||||
rectangleAnnot.StrokeThickness = 1;
|
||||
|
||||
return rectangleAnnot;
|
||||
}
|
||||
|
||||
private _computeAnnotation(annotationWrapper: AnnotationWrapper, hideSkipped: boolean, totalPages: number, dictionaries: Dictionary[]) {
|
||||
private _computeAnnotation(annotationWrapper: AnnotationWrapper, hideSkipped: boolean, totalPages: number, dossierTemplateId: string) {
|
||||
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
|
||||
@ -155,7 +157,7 @@ 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(dictionaries.find(d => d.type === 'preview').hexColor));
|
||||
annotation.setCustomData('redactionColor', String(this._defaultColorsService.getColor(dossierTemplateId, 'previewColor')));
|
||||
annotation.setCustomData('annotationColor', String(annotationWrapper.color));
|
||||
|
||||
return annotation;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Component, Input, OnChanges } from '@angular/core';
|
||||
import { INestedFilter } from '@iqser/common-ui';
|
||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||
import { SuperTypes } from '@models/file/super-types';
|
||||
import { SuperTypes } from '@red/domain';
|
||||
import { DefaultColorsService } from '@services/entity-services/default-colors.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-type-filter [dossierTemplateId]',
|
||||
@ -13,7 +13,6 @@ export class TypeFilterComponent implements OnChanges {
|
||||
@Input() dossierTemplateId: string;
|
||||
@Input() dossierId: string;
|
||||
|
||||
dictionaryColor: string;
|
||||
label: string;
|
||||
color: string;
|
||||
|
||||
@ -28,10 +27,9 @@ export class TypeFilterComponent implements OnChanges {
|
||||
];
|
||||
private _needsAnalysisKeys: string[] = ['remove-only-here', 'analysis'];
|
||||
|
||||
constructor(private readonly _dictionariesMapService: DictionariesMapService) {}
|
||||
constructor(private readonly _defaultColorsService: DefaultColorsService) {}
|
||||
|
||||
ngOnChanges(): void {
|
||||
this.dictionaryColor = this._dictionariesMapService.getDictionaryColor(this.filter.id, this.dossierTemplateId);
|
||||
this.label =
|
||||
this.filter.metadata?.shortLabel === ''
|
||||
? ''
|
||||
@ -42,6 +40,7 @@ export class TypeFilterComponent implements OnChanges {
|
||||
: this._suggestionsKeys.includes(this.filter.id)
|
||||
? 'S'
|
||||
: this.filter.id.charAt(0);
|
||||
this.color = this.filter.metadata?.color || (this.filter.id === 'none' ? 'transparent' : this.dictionaryColor);
|
||||
|
||||
this.color = this.filter.metadata?.color || 'transparent';
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,11 +3,12 @@ import { DossierTemplate, IDossierTemplate } from '@red/domain';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { forkJoin, Observable, of } from 'rxjs';
|
||||
import { FileAttributesService } from '../entity-services/file-attributes.service';
|
||||
import { catchError, mapTo, switchMap, tap } from 'rxjs/operators';
|
||||
import { catchError, map, mapTo, switchMap, tap } from 'rxjs/operators';
|
||||
import { DossierTemplateStatsService } from '../entity-services/dossier-template-stats.service';
|
||||
import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { DictionaryService } from '../entity-services/dictionary.service';
|
||||
import { DefaultColorsService } from '@services/entity-services/default-colors.service';
|
||||
|
||||
const DOSSIER_TEMPLATE_CONFLICT_MSG = _('dossier-templates-listing.error.conflict');
|
||||
const GENERIC_MSG = _('dossier-templates-listing.error.generic');
|
||||
@ -24,6 +25,7 @@ export class DossierTemplatesService extends EntitiesService<IDossierTemplate, D
|
||||
private readonly _fileAttributesService: FileAttributesService,
|
||||
private readonly _dossierTemplateStatsService: DossierTemplateStatsService,
|
||||
private readonly _dictionaryService: DictionaryService,
|
||||
private readonly _defaultColorsService: DefaultColorsService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
@ -42,7 +44,8 @@ export class DossierTemplatesService extends EntitiesService<IDossierTemplate, D
|
||||
this._dossierTemplateStatsService.getFor(dossierTemplateIds(templates)),
|
||||
...getAttributes(templates),
|
||||
this._dictionaryService.loadDictionaryData(dossierTemplateIds(templates)),
|
||||
]).pipe(mapTo(templates));
|
||||
this._defaultColorsService.loadAll(dossierTemplateIds(templates)),
|
||||
]).pipe(map(() => templates));
|
||||
}
|
||||
return of(templates);
|
||||
}),
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { EntitiesService, mapEach, RequiredParam, Validate } from '@iqser/common-ui';
|
||||
import { DefaultColors, DefaultColorType, IDefaultColors } from '@red/domain';
|
||||
import { forkJoin, Observable } from 'rxjs';
|
||||
import { map, switchMap, tap } from 'rxjs/operators';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class DefaultColorsService extends EntitiesService<IDefaultColors, DefaultColors> {
|
||||
protected readonly _defaultModelPath = 'color';
|
||||
protected readonly _entityClass = DefaultColors;
|
||||
|
||||
getColor(dossierTemplateId: string, colorType: DefaultColorType): string {
|
||||
return this.find(dossierTemplateId)[colorType];
|
||||
}
|
||||
|
||||
loadAll(dossierTemplateIds: string[]): Observable<DefaultColors[]> {
|
||||
return forkJoin(dossierTemplateIds.map(id => super.getFor<IDefaultColors>(id))).pipe(
|
||||
mapEach(defaultColors => new DefaultColors(defaultColors)),
|
||||
tap(defaultColors => this.setEntities(defaultColors)),
|
||||
);
|
||||
}
|
||||
|
||||
@Validate()
|
||||
update(
|
||||
@RequiredParam() newColor: Partial<Record<DefaultColorType, string>>,
|
||||
@RequiredParam() dossierTemplateId: string,
|
||||
): Observable<DefaultColors> {
|
||||
const oldColors = this.find(dossierTemplateId);
|
||||
const body = { ...oldColors, ...newColor };
|
||||
return this._post(body, `${this._defaultModelPath}/${dossierTemplateId}`).pipe(
|
||||
switchMap(() => super.getFor<IDefaultColors>(dossierTemplateId)),
|
||||
map(defaultColors => new DefaultColors(defaultColors)),
|
||||
tap(defaultColors => this.replace(defaultColors)),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -5,24 +5,4 @@ import { EntitiesMapService } from '@iqser/common-ui';
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class DictionariesMapService extends EntitiesMapService<Dictionary, IDictionary> {
|
||||
protected readonly _primaryKey = DOSSIER_TEMPLATE_ID;
|
||||
|
||||
/** If the type is not found, it returns the 'default' type. */
|
||||
getDictionary(type: string, dossierTemplateId: string): Dictionary | undefined {
|
||||
return this.get(dossierTemplateId, type) || this.get(dossierTemplateId, 'default');
|
||||
}
|
||||
|
||||
getDictionaryColor(type: string, dossierTemplateId: string, isRecommendation = false, isSkipped = false) {
|
||||
const defaultColor = '#CCCCCC';
|
||||
if (!this.get(dossierTemplateId)) {
|
||||
return defaultColor;
|
||||
}
|
||||
|
||||
const dictionary = this.getDictionary(type, dossierTemplateId);
|
||||
const colorKey = isRecommendation ? 'recommendationHexColor' : isSkipped ? 'skippedHexColor' : 'hexColor';
|
||||
if (dictionary && dictionary[colorKey]) {
|
||||
return dictionary[colorKey];
|
||||
}
|
||||
|
||||
return defaultColor;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,15 +1,13 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { firstValueFrom, forkJoin, Observable, of, throwError } from 'rxjs';
|
||||
import { firstValueFrom, forkJoin, Observable, throwError } from 'rxjs';
|
||||
import { EntitiesService, List, QueryParam, RequiredParam, Toaster, Validate } from '@iqser/common-ui';
|
||||
import { Dictionary, DictionaryEntryType, DictionaryEntryTypes, IColors, IDictionary, IUpdateDictionary } from '@red/domain';
|
||||
import { Dictionary, DictionaryEntryType, DictionaryEntryTypes, IDictionary, IUpdateDictionary, SuperTypes } from '@red/domain';
|
||||
import { catchError, map, switchMap, tap } from 'rxjs/operators';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { DossierTemplateStatsService } from './dossier-template-stats.service';
|
||||
import { DictionariesMapService } from './dictionaries-map.service';
|
||||
import { FALLBACK_COLOR } from '@utils/constants';
|
||||
import { hexToRgb } from '@utils/functions';
|
||||
import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http';
|
||||
import { SuperTypes } from '@models/file/super-types';
|
||||
import { FALLBACK_COLOR } from '@utils/constants';
|
||||
|
||||
const MIN_WORD_LENGTH = 2;
|
||||
|
||||
@ -63,29 +61,6 @@ export class DictionaryService extends EntitiesService<IDictionary, Dictionary>
|
||||
return this._getOne<{ types: IDictionary[] }>(['type', dossierTemplateId], this._defaultModelPath, queryParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves system colors for redaction.
|
||||
*/
|
||||
@Validate()
|
||||
getColors(@RequiredParam() dossierTemplateId: string) {
|
||||
return this._getOne<IColors>([dossierTemplateId], 'color').pipe(
|
||||
catchError(() =>
|
||||
of({
|
||||
analysisColor: FALLBACK_COLOR,
|
||||
dictionaryRequestColor: FALLBACK_COLOR,
|
||||
defaultColor: FALLBACK_COLOR,
|
||||
manualRedactionColor: FALLBACK_COLOR,
|
||||
notRedacted: FALLBACK_COLOR,
|
||||
requestAdd: FALLBACK_COLOR,
|
||||
previewColor: FALLBACK_COLOR,
|
||||
requestRemove: FALLBACK_COLOR,
|
||||
updatedColor: FALLBACK_COLOR,
|
||||
dossierTemplateId: dossierTemplateId,
|
||||
} as IColors),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates colors, hint and caseInsensitive of an entry type.
|
||||
*/
|
||||
@ -105,16 +80,6 @@ export class DictionaryService extends EntitiesService<IDictionary, Dictionary>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set system colors for redaction
|
||||
*/
|
||||
@Validate()
|
||||
setColors(@RequiredParam() body: IColors, @RequiredParam() dossierTemplateId: string): Observable<Dictionary[]> {
|
||||
return this._post(body, `color/${dossierTemplateId}`).pipe(
|
||||
switchMap(() => this.loadDictionaryDataForDossierTemplate(dossierTemplateId)),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates entry type with colors, hint and caseInsensitive
|
||||
*/
|
||||
@ -217,73 +182,24 @@ export class DictionaryService extends EntitiesService<IDictionary, Dictionary>
|
||||
}
|
||||
|
||||
loadDictionaryDataForDossierTemplate(dossierTemplateId: string): Observable<Dictionary[]> {
|
||||
const types$: Observable<Dictionary[]> = this.getAllDictionaries(dossierTemplateId).pipe(
|
||||
return this.getAllDictionaries(dossierTemplateId).pipe(
|
||||
map(typesResponse => typesResponse.types.map(type => new Dictionary(type))),
|
||||
);
|
||||
|
||||
const virtualTypes$: Observable<Dictionary[]> = this.getColors(dossierTemplateId).pipe(
|
||||
tap(colors => {
|
||||
for (const key of Object.keys(colors)) {
|
||||
const color: string = colors[key];
|
||||
try {
|
||||
const rgbValue = hexToRgb(color);
|
||||
if (!rgbValue) {
|
||||
colors[key] = FALLBACK_COLOR;
|
||||
}
|
||||
} catch (e) {
|
||||
colors[key] = FALLBACK_COLOR;
|
||||
map(dictionaries => {
|
||||
let manualTypeExists = false;
|
||||
for (const dictionary of dictionaries) {
|
||||
if (dictionary.type === SuperTypes.ManualRedaction) {
|
||||
manualTypeExists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}),
|
||||
map(colors => {
|
||||
const virtualTypes = [
|
||||
{ hexColor: colors.skippedColor || FALLBACK_COLOR, type: SuperTypes.DeclinedSuggestion },
|
||||
// dictionary actions
|
||||
{ hexColor: colors.recommendationColor || FALLBACK_COLOR, type: SuperTypes.Recommendation },
|
||||
{ hexColor: colors.analysisColor || FALLBACK_COLOR, type: 'remove-only-here' },
|
||||
// generic suggestions
|
||||
{ hexColor: colors.requestAddColor || FALLBACK_COLOR, type: 'suggestion' },
|
||||
{ hexColor: colors.requestAddColor || FALLBACK_COLOR, type: SuperTypes.SuggestionAdd },
|
||||
// add suggestions
|
||||
{ hexColor: colors.requestAddColor || FALLBACK_COLOR, type: SuperTypes.SuggestionChangeLegalBasis },
|
||||
{ hexColor: colors.requestAddColor || FALLBACK_COLOR, type: SuperTypes.SuggestionRecategorizeImage },
|
||||
{ hexColor: colors.dictionaryRequestColor || FALLBACK_COLOR, type: SuperTypes.SuggestionAddDictionary },
|
||||
{ hexColor: colors.dictionaryRequestColor || FALLBACK_COLOR, type: SuperTypes.SuggestionResize },
|
||||
{ hexColor: colors.requestRemoveColor || FALLBACK_COLOR, type: SuperTypes.SuggestionRemove },
|
||||
{ hexColor: colors.dictionaryRequestColor || FALLBACK_COLOR, type: SuperTypes.SuggestionRemoveDictionary },
|
||||
{ hexColor: colors.skippedColor || FALLBACK_COLOR, type: SuperTypes.Skipped },
|
||||
{ hexColor: colors.requestAddColor || FALLBACK_COLOR, type: 'add' },
|
||||
{ hexColor: colors.analysisColor || FALLBACK_COLOR, type: 'analysis' },
|
||||
{ hexColor: colors.hintColor || FALLBACK_COLOR, type: SuperTypes.Hint, hint: true },
|
||||
{ hexColor: colors.ignoredHintColor || FALLBACK_COLOR, type: SuperTypes.IgnoredHint, hint: true },
|
||||
{ hexColor: colors.redactionColor || FALLBACK_COLOR, type: SuperTypes.Redaction },
|
||||
{ hexColor: colors.previewColor || FALLBACK_COLOR, type: 'preview' },
|
||||
{ hexColor: colors.updatedColor || FALLBACK_COLOR, type: 'updated' },
|
||||
];
|
||||
if (!manualTypeExists) {
|
||||
dictionaries.push(new Dictionary({ hexColor: FALLBACK_COLOR, type: SuperTypes.ManualRedaction }, true));
|
||||
}
|
||||
|
||||
return virtualTypes.map(config => new Dictionary(config, true));
|
||||
return dictionaries;
|
||||
}),
|
||||
tap(dictionaries => this._dictionariesMapService.set(dossierTemplateId, dictionaries)),
|
||||
);
|
||||
|
||||
return forkJoin([types$, virtualTypes$])
|
||||
.pipe(map(([types, virtualTypes]: Dictionary[][]) => [...types, ...virtualTypes]))
|
||||
.pipe(
|
||||
map(dictionaries => {
|
||||
let manualTypeExists = false;
|
||||
for (const dictionary of dictionaries) {
|
||||
if (dictionary.type === SuperTypes.ManualRedaction) {
|
||||
manualTypeExists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!manualTypeExists) {
|
||||
dictionaries.push(new Dictionary({ hexColor: FALLBACK_COLOR, type: SuperTypes.ManualRedaction }, true));
|
||||
}
|
||||
|
||||
return dictionaries;
|
||||
}),
|
||||
)
|
||||
.pipe(tap(dictionaries => this._dictionariesMapService.set(dossierTemplateId, dictionaries)));
|
||||
}
|
||||
|
||||
#addUpdateDictionaryErrorToast(error: HttpErrorResponse): Observable<never> {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { SuperType, SuperTypes } from '@models/file/super-types';
|
||||
import { SuperType, SuperTypes } from '@red/domain';
|
||||
|
||||
export const SuggestionAddFalsePositive = 'suggestion-add-false-positive' as const;
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { SuperType, SuperTypes } from '@models/file/super-types';
|
||||
import { SuperType, SuperTypes } from '@red/domain';
|
||||
|
||||
export const SuperTypeSorter: { [key in SuperType]: number } = {
|
||||
[SuperTypes.TextHighlight]: 100,
|
||||
|
||||
@ -27,3 +27,4 @@ export * from './lib/permissions';
|
||||
export * from './lib/license';
|
||||
export * from './lib/digital-signature';
|
||||
export * from './lib/watermarks';
|
||||
export * from './lib/colors';
|
||||
|
||||
48
libs/red-domain/src/lib/colors/annotation-color-config.ts
Normal file
48
libs/red-domain/src/lib/colors/annotation-color-config.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import { DefaultColorType } from './default-color-type';
|
||||
import { SuperType, SuperTypes } from '../files';
|
||||
|
||||
export type DefaultBasedColorType = SuperType | 'updated' | 'image' | 'suggestion' | 'analysis';
|
||||
|
||||
export const annotationDefaultColorConfig: Record<DefaultBasedColorType, DefaultColorType> = {
|
||||
[SuperTypes.TextHighlight]: 'redactionColor', // not actually used
|
||||
|
||||
[SuperTypes.SuggestionChangeLegalBasis]: 'requestAddColor',
|
||||
[SuperTypes.SuggestionRecategorizeImage]: 'requestAddColor',
|
||||
[SuperTypes.SuggestionAddDictionary]: 'dictionaryRequestColor',
|
||||
[SuperTypes.SuggestionForceRedaction]: 'requestAddColor',
|
||||
[SuperTypes.SuggestionForceHint]: 'requestAddColor',
|
||||
[SuperTypes.SuggestionResize]: 'dictionaryRequestColor',
|
||||
[SuperTypes.SuggestionRemoveDictionary]: 'dictionaryRequestColor',
|
||||
[SuperTypes.SuggestionAdd]: 'requestAddColor',
|
||||
[SuperTypes.SuggestionRemove]: 'requestRemoveColor',
|
||||
[SuperTypes.DeclinedSuggestion]: 'skippedColor',
|
||||
|
||||
[SuperTypes.IgnoredHint]: 'ignoredHintColor',
|
||||
[SuperTypes.Skipped]: 'skippedColor',
|
||||
[SuperTypes.Redaction]: 'redactionColor',
|
||||
[SuperTypes.ManualRedaction]: 'redactionColor',
|
||||
[SuperTypes.Recommendation]: 'recommendationColor',
|
||||
[SuperTypes.Hint]: 'hintColor',
|
||||
|
||||
updated: 'updatedColor',
|
||||
image: 'recommendationColor',
|
||||
suggestion: 'requestAddColor',
|
||||
analysis: 'analysisColor',
|
||||
} as const;
|
||||
|
||||
type EntityBasedColorType =
|
||||
| typeof SuperTypes.IgnoredHint
|
||||
| typeof SuperTypes.Skipped
|
||||
| typeof SuperTypes.Redaction
|
||||
| typeof SuperTypes.ManualRedaction
|
||||
| typeof SuperTypes.Recommendation
|
||||
| typeof SuperTypes.Hint;
|
||||
|
||||
export const annotationEntityColorConfig: Record<EntityBasedColorType, 'hexColor' | 'recommendationHexColor' | 'skippedHexColor'> = {
|
||||
[SuperTypes.IgnoredHint]: 'skippedHexColor',
|
||||
[SuperTypes.Skipped]: 'skippedHexColor',
|
||||
[SuperTypes.Redaction]: 'hexColor',
|
||||
[SuperTypes.ManualRedaction]: 'hexColor',
|
||||
[SuperTypes.Recommendation]: 'recommendationHexColor',
|
||||
[SuperTypes.Hint]: 'hexColor',
|
||||
} as const;
|
||||
15
libs/red-domain/src/lib/colors/default-color-type.ts
Normal file
15
libs/red-domain/src/lib/colors/default-color-type.ts
Normal file
@ -0,0 +1,15 @@
|
||||
export const DefaultColorTypes = [
|
||||
'requestAddColor',
|
||||
'requestRemoveColor',
|
||||
'dictionaryRequestColor',
|
||||
'previewColor',
|
||||
'analysisColor',
|
||||
'updatedColor',
|
||||
'recommendationColor',
|
||||
'hintColor',
|
||||
'redactionColor',
|
||||
'ignoredHintColor',
|
||||
'skippedColor',
|
||||
] as const;
|
||||
|
||||
export type DefaultColorType = typeof DefaultColorTypes[number];
|
||||
43
libs/red-domain/src/lib/colors/default-colors.model.ts
Normal file
43
libs/red-domain/src/lib/colors/default-colors.model.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import { Entity } from '@iqser/common-ui';
|
||||
import { IDefaultColors } from './default-colors';
|
||||
|
||||
export class DefaultColors extends Entity<IDefaultColors> implements IDefaultColors {
|
||||
readonly dossierTemplateId: string;
|
||||
readonly requestAddColor: string;
|
||||
readonly requestRemoveColor: string;
|
||||
readonly dictionaryRequestColor: string;
|
||||
readonly previewColor: string;
|
||||
readonly analysisColor: string;
|
||||
readonly updatedColor: string;
|
||||
readonly recommendationColor: string;
|
||||
readonly hintColor: string;
|
||||
readonly redactionColor: string;
|
||||
readonly ignoredHintColor: string;
|
||||
readonly skippedColor: string;
|
||||
|
||||
readonly routerLink = '';
|
||||
|
||||
constructor(entity: IDefaultColors) {
|
||||
super(entity);
|
||||
this.dossierTemplateId = entity.dossierTemplateId;
|
||||
this.requestAddColor = entity.requestAddColor;
|
||||
this.requestRemoveColor = entity.requestRemoveColor;
|
||||
this.dictionaryRequestColor = entity.dictionaryRequestColor;
|
||||
this.previewColor = entity.previewColor;
|
||||
this.analysisColor = entity.analysisColor;
|
||||
this.updatedColor = entity.updatedColor;
|
||||
this.recommendationColor = entity.recommendationColor;
|
||||
this.hintColor = entity.hintColor;
|
||||
this.redactionColor = entity.redactionColor;
|
||||
this.ignoredHintColor = entity.ignoredHintColor;
|
||||
this.skippedColor = entity.skippedColor;
|
||||
}
|
||||
|
||||
get id(): string {
|
||||
return this.dossierTemplateId;
|
||||
}
|
||||
|
||||
get searchKey(): string {
|
||||
return this.dossierTemplateId;
|
||||
}
|
||||
}
|
||||
3
libs/red-domain/src/lib/colors/default-colors.ts
Normal file
3
libs/red-domain/src/lib/colors/default-colors.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import { DefaultColorType } from './default-color-type';
|
||||
|
||||
export type IDefaultColors = Record<DefaultColorType, string> & { dossierTemplateId: string };
|
||||
4
libs/red-domain/src/lib/colors/index.ts
Normal file
4
libs/red-domain/src/lib/colors/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export * from './default-colors.model';
|
||||
export * from './default-colors';
|
||||
export * from './annotation-color-config';
|
||||
export * from './default-color-type';
|
||||
@ -1,14 +0,0 @@
|
||||
export interface IColors {
|
||||
dossierTemplateId?: string;
|
||||
requestAddColor?: string;
|
||||
requestRemoveColor?: string;
|
||||
dictionaryRequestColor?: string;
|
||||
previewColor?: string;
|
||||
analysisColor?: string;
|
||||
updatedColor?: string;
|
||||
recommendationColor?: string;
|
||||
hintColor?: string;
|
||||
redactionColor?: string;
|
||||
ignoredHintColor?: string;
|
||||
skippedColor?: string;
|
||||
}
|
||||
@ -1,4 +1,3 @@
|
||||
export * from './colors';
|
||||
export * from './dictionary';
|
||||
export * from './update-dictionary';
|
||||
export * from './dictionary.model';
|
||||
|
||||
@ -3,3 +3,4 @@ export * from './file.model';
|
||||
export * from './types';
|
||||
export * from './file-upload-result';
|
||||
export * from './overwrite-file-options';
|
||||
export * from './super-types';
|
||||
|
||||
@ -11,13 +11,13 @@ export const SuperTypes = {
|
||||
SuggestionRemoveDictionary: 'suggestion-remove-dictionary',
|
||||
SuggestionAdd: 'suggestion-add',
|
||||
SuggestionRemove: 'suggestion-remove',
|
||||
DeclinedSuggestion: 'suggestion-declined',
|
||||
IgnoredHint: 'hint-ignored',
|
||||
Skipped: 'skipped',
|
||||
Redaction: 'redaction',
|
||||
ManualRedaction: 'manual',
|
||||
Recommendation: 'recommendation',
|
||||
Hint: 'hint',
|
||||
DeclinedSuggestion: 'suggestion-declined',
|
||||
} as const;
|
||||
|
||||
export type SuperType = ValuesOf<typeof SuperTypes>;
|
||||
@ -1,3 +0,0 @@
|
||||
import { IColors } from '../dictionaries';
|
||||
|
||||
export type DefaultColorType = keyof IColors;
|
||||
@ -2,7 +2,6 @@ export * from './sorters/status-sorter';
|
||||
export * from './breadcrumb-types';
|
||||
export * from './types';
|
||||
export * from './rules';
|
||||
export * from './default-color-type';
|
||||
export * from './colors';
|
||||
export * from './view-mode';
|
||||
export * from './expandable-file-actions';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user