RED-4639: Refactor annotation colors

This commit is contained in:
Adina Țeudan 2022-07-14 12:43:38 +03:00
parent e030b20f04
commit 5427de6f58
35 changed files with 306 additions and 289 deletions

View File

@ -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;
}

View File

@ -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)],
],
});
}
}

View File

@ -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"

View File

@ -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 });
}
}

View File

@ -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>

View File

@ -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]);
}
}

View File

@ -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],
},
}),
);

View File

@ -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,

View File

@ -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');
}
}

View File

@ -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 }}

View File

@ -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[]) {

View File

@ -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();
}

View File

@ -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: {

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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';
}
}

View File

@ -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);
}),

View File

@ -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)),
);
}
}

View File

@ -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;
}
}

View File

@ -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> {

View File

@ -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;

View File

@ -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,

View File

@ -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';

View 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;

View 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];

View 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;
}
}

View File

@ -0,0 +1,3 @@
import { DefaultColorType } from './default-color-type';
export type IDefaultColors = Record<DefaultColorType, string> & { dossierTemplateId: string };

View File

@ -0,0 +1,4 @@
export * from './default-colors.model';
export * from './default-colors';
export * from './annotation-color-config';
export * from './default-color-type';

View File

@ -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;
}

View File

@ -1,4 +1,3 @@
export * from './colors';
export * from './dictionary';
export * from './update-dictionary';
export * from './dictionary.model';

View File

@ -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';

View File

@ -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>;

View File

@ -1,3 +0,0 @@
import { IColors } from '../dictionaries';
export type DefaultColorType = keyof IColors;

View File

@ -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';