From d6f612356788d34cc04c24ffec80974e4d50db72 Mon Sep 17 00:00:00 2001 From: Valentin Mihai Date: Fri, 21 Jul 2023 15:38:45 +0300 Subject: [PATCH 1/2] DM-337 - WIP on Add/Remove annotations dialog in DocuMine --- .../add-annotation-dialog.component.html | 56 +++++++++ .../add-annotation-dialog.component.scss | 0 .../add-annotation-dialog.component.ts | 116 ++++++++++++++++++ .../remove-annotation-dialog.component.html | 34 +++++ .../remove-annotation-dialog.component.scss | 0 .../remove-annotation-dialog.component.ts | 99 +++++++++++++++ .../remove-annotation-options.ts | 7 ++ .../redact-text-dialog.component.ts | 4 +- .../remove-redaction-dialog.component.ts | 3 +- .../file-preview-screen.component.ts | 46 ++++--- .../file-preview/file-preview.module.ts | 4 + .../services/pdf-proxy.service.ts | 21 ++-- .../entity-services/dictionary.service.ts | 10 +- .../remove-annotation-translations.ts | 22 ++++ apps/red-ui/src/assets/config/config.json | 6 +- apps/red-ui/src/assets/i18n/redact/de.json | 43 +++++++ apps/red-ui/src/assets/i18n/redact/en.json | 43 +++++++ apps/red-ui/src/assets/i18n/scm/de.json | 43 +++++++ apps/red-ui/src/assets/i18n/scm/en.json | 43 +++++++ 19 files changed, 564 insertions(+), 36 deletions(-) create mode 100644 apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/add-annotation-dialog/add-annotation-dialog.component.html create mode 100644 apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/add-annotation-dialog/add-annotation-dialog.component.scss create mode 100644 apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/add-annotation-dialog/add-annotation-dialog.component.ts create mode 100644 apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-dialog.component.html create mode 100644 apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-dialog.component.scss create mode 100644 apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-dialog.component.ts create mode 100644 apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-options.ts create mode 100644 apps/red-ui/src/app/translations/remove-annotation-translations.ts diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/add-annotation-dialog/add-annotation-dialog.component.html b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/add-annotation-dialog/add-annotation-dialog.component.html new file mode 100644 index 000000000..e08222606 --- /dev/null +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/add-annotation-dialog/add-annotation-dialog.component.html @@ -0,0 +1,56 @@ +
+
+
+ +
+
+ + {{ form.get('selectedText').value }} +
+ +
+ + + + + {{ displayedDictionaryLabel }} + + {{ dictionary.label }} + + + +
+ +
+ + +
+
+ +
+ + + +
+
+
+ + +
diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/add-annotation-dialog/add-annotation-dialog.component.scss b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/add-annotation-dialog/add-annotation-dialog.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/add-annotation-dialog/add-annotation-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/add-annotation-dialog/add-annotation-dialog.component.ts new file mode 100644 index 000000000..1d840f854 --- /dev/null +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/add-annotation-dialog/add-annotation-dialog.component.ts @@ -0,0 +1,116 @@ +import { Component, OnInit } from '@angular/core'; +import { IconButtonTypes, IqserPermissionsService } from '@iqser/common-ui'; +import { Dictionary, Dossier, File, IAddRedactionRequest, IManualRedactionEntry, SuperTypes } from '@red/domain'; +import { FormBuilder, UntypedFormGroup } from '@angular/forms'; +import { Roles } from '@users/roles'; +import { JustificationsService } from '@services/entity-services/justifications.service'; +import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service'; +import { DictionaryService } from '@services/entity-services/dictionary.service'; + +import { ManualRedactionEntryWrapper } from '@models/file/manual-redaction-entry.wrapper'; +import { IqserDialogComponent } from '@iqser/common-ui'; + +export interface AddAnnotationData { + manualRedactionEntryWrapper: ManualRedactionEntryWrapper; + dossierId: string; + file: File; +} + +interface DialogResult { + redaction: IManualRedactionEntry; + dictionary: Dictionary; + applyToAllDossiers: boolean | null; +} + +@Component({ + templateUrl: './add-annotation-dialog.component.html', + styleUrls: ['./add-annotation-dialog.component.scss'], +}) +export class AddAnnotationDialogComponent + extends IqserDialogComponent + implements OnInit +{ + readonly iconButtonTypes = IconButtonTypes; + dictionaries: Dictionary[] = []; + form!: UntypedFormGroup; + + #manualRedactionTypeExists = true; + readonly #dossier: Dossier; + readonly #isRss = this._iqserPermissionsService.has(Roles.getRss); + readonly hint: boolean; + + constructor( + private readonly _justificationsService: JustificationsService, + private readonly _activeDossiersService: ActiveDossiersService, + private readonly _dictionaryService: DictionaryService, + private readonly _iqserPermissionsService: IqserPermissionsService, + private readonly _formBuilder: FormBuilder, + ) { + super(); + this.#dossier = _activeDossiersService.find(this.data.dossierId); + this.#manualRedactionTypeExists = this._dictionaryService.hasManualType(this.#dossier.dossierTemplateId); + + this.form = this.#getForm(); + } + + get displayedDictionaryLabel() { + const dictType = this.form.get('dictionary').value; + if (dictType) { + return this.dictionaries.find(d => d.type === dictType)?.label ?? null; + } + return null; + } + + get disabled() { + return !this.#isRss || !this.form.get('dictionary').value; + } + + async ngOnInit(): Promise { + this.dictionaries = this._dictionaryService.getRedactionTypes(this.#dossier.dossierTemplateId); + this.#formatSelectedTextValue(); + } + + save(): void { + this.#enhanceManualRedaction(this.data.manualRedactionEntryWrapper.manualRedactionEntry); + const redaction = this.data.manualRedactionEntryWrapper.manualRedactionEntry; + this.dialogRef.close({ + redaction, + dictionary: this.dictionaries.find(d => d.type === this.form.get('dictionary').value), + }); + } + + #getForm(): UntypedFormGroup { + return this._formBuilder.group({ + selectedText: this.data?.manualRedactionEntryWrapper?.manualRedactionEntry?.value, + reason: [null], + comment: [null], + dictionary: [this.#manualRedactionTypeExists ? SuperTypes.ManualRedaction : null], + classification: ['non-readable content'], + section: [null], + }); + } + + #formatSelectedTextValue(): void { + this.data.manualRedactionEntryWrapper.manualRedactionEntry.value = + this.data.manualRedactionEntryWrapper.manualRedactionEntry.value.replace( + // eslint-disable-next-line no-control-regex,max-len + /([^\s\d-]{2,})[-\u00AD]\u000D\u000A|[\u000A\u000B\u000C\u000D\u0085\u2028\u2029]/gi, + '$1', + ); + } + + #enhanceManualRedaction(addRedactionRequest: IAddRedactionRequest) { + addRedactionRequest.type = this.form.get('dictionary').value; + + const selectedType = this.dictionaries.find(d => d.type === addRedactionRequest.type); + addRedactionRequest.addToDictionary = !!selectedType?.hasDictionary; + + if (!addRedactionRequest.reason) { + addRedactionRequest.reason = 'Dictionary Request'; + } + const commentValue = this.form.get('comment').value; + addRedactionRequest.comment = commentValue ? { text: commentValue } : null; + addRedactionRequest.section = this.form.get('section').value; + addRedactionRequest.value = this.form.get('selectedText').value; + } +} diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-dialog.component.html b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-dialog.component.html new file mode 100644 index 000000000..30b92426c --- /dev/null +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-dialog.component.html @@ -0,0 +1,34 @@ +
+
+
+ +
+ + +
+ + +
+
+ +
+ + + +
+
+
+ + +
diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-dialog.component.scss b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-dialog.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-dialog.component.ts new file mode 100644 index 000000000..70f757ecc --- /dev/null +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-dialog.component.ts @@ -0,0 +1,99 @@ +import { Component } from '@angular/core'; +import { DetailsRadioOption, IconButtonTypes } from '@iqser/common-ui'; +import { FormBuilder, UntypedFormGroup } from '@angular/forms'; +import { AnnotationWrapper } from '@models/file/annotation.wrapper'; +import { Dossier } from '@red/domain'; +import { IqserDialogComponent } from '@iqser/common-ui'; +import { PermissionsService } from '@services/permissions.service'; +import { RemoveAnnotationOption, RemoveAnnotationOptions } from './remove-annotation-options'; +import { removeAnnotationTranslations } from '@translations/remove-annotation-translations'; + +const PIN_ICON = 'red:push-pin'; +const FOLDER_ICON = 'red:folder'; +const REMOVE_FROM_DICT_ICON = 'red:remove-from-dict'; + +export interface RemoveAnnotationPermissions { + canRemoveOnlyHere: boolean; + canRemoveFromDictionary: boolean; + canMarkAsFalsePositive: boolean; +} + +export interface RemoveAnnotationData { + annotation: AnnotationWrapper; + dossier: Dossier; + falsePositiveContext: string; + permissions: RemoveAnnotationPermissions; + applyToAllDossiers: boolean; +} + +export interface RemoveAnnotationResult { + comment: string; + option: DetailsRadioOption; +} + +@Component({ + templateUrl: './remove-annotation-dialog.component.html', + styleUrls: ['./remove-annotation-dialog.component.scss'], +}) +export class RemoveAnnotationDialogComponent extends IqserDialogComponent< + RemoveAnnotationDialogComponent, + RemoveAnnotationData, + RemoveAnnotationResult +> { + readonly iconButtonTypes = IconButtonTypes; + readonly options: DetailsRadioOption[]; + + form!: UntypedFormGroup; + + readonly #annotation: AnnotationWrapper; + readonly #permissions: RemoveAnnotationPermissions; + readonly #translations = removeAnnotationTranslations; + + constructor(private readonly _formBuilder: FormBuilder, private readonly _permissionsService: PermissionsService) { + super(); + this.#annotation = this.data.annotation; + this.#permissions = this.data.permissions; + this.options = this.#options(); + this.form = this.#getForm(); + } + + save(): void { + this.dialogRef.close(this.form.getRawValue()); + } + + #getForm(): UntypedFormGroup { + return this._formBuilder.group({ + comment: [null], + option: [this.options[0]], + }); + } + + #options() { + const options: DetailsRadioOption[] = []; + if (this.#permissions.canRemoveOnlyHere) { + options.push({ + label: this.#translations.ONLY_HERE.label, + description: this.#translations.ONLY_HERE.description, + icon: PIN_ICON, + value: RemoveAnnotationOptions.ONLY_HERE, + }); + } + if (this.#permissions.canRemoveFromDictionary) { + options.push({ + label: this.#translations.IN_DOSSIER.label, + description: this.#translations.IN_DOSSIER.description, + icon: FOLDER_ICON, + value: RemoveAnnotationOptions.IN_DOSSIER, + }); + } + if (this.#permissions.canMarkAsFalsePositive) { + options.push({ + label: this.#translations.FALSE_POSITIVE.label, + description: this.#translations.FALSE_POSITIVE.description, + icon: REMOVE_FROM_DICT_ICON, + value: RemoveAnnotationOptions.FALSE_POSITIVE, + }); + } + return options; + } +} diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-options.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-options.ts new file mode 100644 index 000000000..01da1c682 --- /dev/null +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-options.ts @@ -0,0 +1,7 @@ +export const RemoveAnnotationOptions = { + ONLY_HERE: 'ONLY_HERE', + IN_DOSSIER: 'IN_DOSSIER', + FALSE_POSITIVE: 'FALSE_POSITIVE', +} as const; + +export type RemoveAnnotationOption = keyof typeof RemoveAnnotationOptions; diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/redact-text-dialog/redact-text-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/redact-text-dialog/redact-text-dialog.component.ts index fdb1e990a..e97829dc1 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/redact-text-dialog/redact-text-dialog.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/redact-text-dialog/redact-text-dialog.component.ts @@ -14,12 +14,12 @@ import { redactTextTranslations } from '@translations/redact-text-translations'; import { RedactTextOption, RedactTextOptions } from './redact-text-options'; import { tap } from 'rxjs/operators'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; -import { IqserDialogComponent } from '../../../../../../../../libs/common-ui/src/lib/dialog/iqser-dialog-component.directive'; +import { IqserDialogComponent } from '@iqser/common-ui'; const PIN_ICON = 'red:push-pin'; const FOLDER_ICON = 'red:folder'; -interface RedactTextData { +export interface RedactTextData { manualRedactionEntryWrapper: ManualRedactionEntryWrapper; dossierId: string; file: File; diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/remove-redaction-dialog/remove-redaction-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/remove-redaction-dialog/remove-redaction-dialog.component.ts index 4c133e169..7a7bbf2f2 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/remove-redaction-dialog/remove-redaction-dialog.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/remove-redaction-dialog/remove-redaction-dialog.component.ts @@ -5,11 +5,10 @@ import { FormBuilder, UntypedFormGroup } from '@angular/forms'; import { removeRedactionTranslations } from '@translations/remove-redaction-translations'; import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { Dossier } from '@red/domain'; -import { IqserDialogComponent } from '../../../../../../../../libs/common-ui/src/lib/dialog/iqser-dialog-component.directive'; +import { IqserDialogComponent } from '@iqser/common-ui'; import { PermissionsService } from '@services/permissions.service'; import { tap } from 'rxjs/operators'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; -import { RedactTextOption } from '../redact-text-dialog/redact-text-options'; const PIN_ICON = 'red:push-pin'; const FOLDER_ICON = 'red:folder'; diff --git a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts index 64844499f..28d035905 100644 --- a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts @@ -19,6 +19,7 @@ import { ConfirmOptions, CustomError, ErrorService, + getConfig, HelpModeService, IConfirmationDialogData, IqserDialog, @@ -66,11 +67,12 @@ import { ConfigService } from '@services/config.service'; import { ReadableRedactionsService } from '../pdf-viewer/services/readable-redactions.service'; import { Roles } from '@users/roles'; import { SuggestionsService } from './services/suggestions.service'; -import { RedactTextDialogComponent } from './dialogs/redact-text-dialog/redact-text-dialog.component'; +import { RedactTextData, RedactTextDialogComponent } from './dialogs/redact-text-dialog/redact-text-dialog.component'; import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { copyLocalStorageFiltersValues, FilterService, NestedFilter, processFilters } from '@iqser/common-ui/lib/filtering'; import { AutoUnsubscribe, Bind, bool, Debounce, List, OnAttach, OnDetach } from '@iqser/common-ui/lib/utils'; import { TenantsService } from '@iqser/common-ui/lib/tenants'; +import { AddAnnotationDialogComponent } from './dialogs/docu-mine/add-annotation-dialog/add-annotation-dialog.component'; const textActions = [TextPopups.REDACT_TEXT, TextPopups.ADD_HINT, TextPopups.ADD_FALSE_POSITIVE]; @@ -95,6 +97,7 @@ export class FilePreviewScreenComponent readonly fileId = this.state.fileId; readonly dossierId = this.state.dossierId; readonly lastAssignee = computed(() => this.getLastAssignee()); + readonly #isDocumine; width: number; constructor( @@ -169,6 +172,7 @@ export class FilePreviewScreenComponent this._stampService.stampPDF().then(); } }); + this.#isDocumine = getConfig().IS_DOCUMINE; } get changed() { @@ -365,20 +369,12 @@ export class FilePreviewScreenComponent async openRedactTextDialog(manualRedactionEntryWrapper: ManualRedactionEntryWrapper) { const file = this.state.file(); - const dossierTemplate = this._dossierTemplatesService.find(this.state.dossierTemplateId); - const isApprover = this.permissionsService.isApprover(this.state.dossier()); - const applyDictionaryUpdatesToAllDossiersByDefault = dossierTemplate.applyDictionaryUpdatesToAllDossiersByDefault; const hint = manualRedactionEntryWrapper.type === ManualRedactionEntryTypes.HINT; - const ref = this._iqserDialog.openDefault(RedactTextDialogComponent, { - data: { - manualRedactionEntryWrapper, - dossierId: this.dossierId, - file, - applyToAllDossiers: isApprover ? applyDictionaryUpdatesToAllDossiersByDefault : false, - isApprover, - hint, - }, - }); + + const data = this.#getRedactTextDialogData(manualRedactionEntryWrapper, file, hint); + const ref = this.#isDocumine + ? this._iqserDialog.openDefault(AddAnnotationDialogComponent, { data }) + : this._iqserDialog.openDefault(RedactTextDialogComponent, { data: data as RedactTextData }); const result = await ref.result(); if (!result) { @@ -397,6 +393,28 @@ export class FilePreviewScreenComponent return firstValueFrom(addAndReload$.pipe(catchError(() => of(undefined)))); } + #getRedactTextDialogData(manualRedactionEntryWrapper: ManualRedactionEntryWrapper, file: File, hint: boolean) { + const dossierTemplate = this._dossierTemplatesService.find(this.state.dossierTemplateId); + + const data = { + manualRedactionEntryWrapper, + dossierId: this.dossierId, + file, + }; + if (this.#isDocumine) { + return data; + } + + const isApprover = this.permissionsService.isApprover(this.state.dossier()); + const applyDictionaryUpdatesToAllDossiersByDefault = dossierTemplate.applyDictionaryUpdatesToAllDossiersByDefault; + return { + ...data, + applyToAllDossiers: isApprover ? applyDictionaryUpdatesToAllDossiersByDefault : false, + isApprover, + hint, + }; + } + toggleFullScreen() { this.fullScreen = !this.fullScreen; if (this.fullScreen) { diff --git a/apps/red-ui/src/app/modules/file-preview/file-preview.module.ts b/apps/red-ui/src/app/modules/file-preview/file-preview.module.ts index 82cbd9fb1..f00380451 100644 --- a/apps/red-ui/src/app/modules/file-preview/file-preview.module.ts +++ b/apps/red-ui/src/app/modules/file-preview/file-preview.module.ts @@ -66,6 +66,8 @@ import { IqserUsersModule } from '@iqser/common-ui/lib/users'; import { IqserFiltersModule } from '@iqser/common-ui/lib/filtering'; import { StatusBarComponent } from '@iqser/common-ui/lib/shared'; import { TenantPipe } from '@iqser/common-ui/lib/tenants'; +import { AddAnnotationDialogComponent } from './dialogs/docu-mine/add-annotation-dialog/add-annotation-dialog.component'; +import { RemoveAnnotationDialogComponent } from './dialogs/docu-mine/remove-annotation-dialog/remove-annotation-dialog.component'; const routes: IqserRoutes = [ { @@ -89,6 +91,8 @@ const dialogs = [ RssDialogComponent, RedactTextDialogComponent, RemoveRedactionDialogComponent, + AddAnnotationDialogComponent, + RemoveAnnotationDialogComponent, ]; const components = [ diff --git a/apps/red-ui/src/app/modules/file-preview/services/pdf-proxy.service.ts b/apps/red-ui/src/app/modules/file-preview/services/pdf-proxy.service.ts index 2d15c7a65..76cf1f29d 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/pdf-proxy.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/pdf-proxy.service.ts @@ -9,7 +9,7 @@ import { } from '@models/file/manual-redaction-entry.wrapper'; import { AnnotationDrawService } from '../../pdf-viewer/services/annotation-draw.service'; import { UserPreferenceService } from '@users/user-preference.service'; -import { IqserPermissionsService } from '@iqser/common-ui'; +import { getConfig, IqserPermissionsService } from '@iqser/common-ui'; import { toPosition } from '../utils/pdf-calculation.utils'; import { MultiSelectService } from './multi-select.service'; import { FilePreviewStateService } from './file-preview-state.service'; @@ -50,6 +50,7 @@ export class PdfProxyService { readonly #addRedactionIcon = this._iqserPermissionsService.has(Roles.getRss) ? this._convertPath('/assets/icons/general/pdftron-action-add-annotation.svg') : this._convertPath('/assets/icons/general/pdftron-action-add-redaction.svg'); + readonly #isDocumine; readonly #addHintIcon = this._convertPath('/assets/icons/general/pdftron-action-add-hint.svg'); readonly annotationSelected$ = this.#annotationSelected$; readonly manualAnnotationRequested$ = new Subject(); @@ -113,6 +114,7 @@ export class PdfProxyService { this._viewerHeaderService.disable([HeaderElements.TOGGLE_READABLE_REDACTIONS]); } }); + this.#isDocumine = getConfig().IS_DOCUMINE; } get #annotationSelected$() { @@ -186,13 +188,16 @@ export class PdfProxyService { title: this.#getTitle(ManualRedactionEntryTypes.REDACT), onClick: () => this._ngZone.run(() => this.#redactText(ManualRedactionEntryTypes.REDACT)), }); - popups.push({ - type: 'actionButton', - dataElement: TextPopups.ADD_HINT, - img: this.#addHintIcon, - title: this.#getTitle(ManualRedactionEntryTypes.HINT), - onClick: () => this._ngZone.run(() => this.#redactText(ManualRedactionEntryTypes.HINT)), - }); + + if (!this.#isDocumine) { + popups.push({ + type: 'actionButton', + dataElement: TextPopups.ADD_HINT, + img: this.#addHintIcon, + title: this.#getTitle(ManualRedactionEntryTypes.HINT), + onClick: () => this._ngZone.run(() => this.#redactText(ManualRedactionEntryTypes.HINT)), + }); + } } this._pdf.configureTextPopups(popups); diff --git a/apps/red-ui/src/app/services/entity-services/dictionary.service.ts b/apps/red-ui/src/app/services/entity-services/dictionary.service.ts index 6402c0485..1e5b8dcc5 100644 --- a/apps/red-ui/src/app/services/entity-services/dictionary.service.ts +++ b/apps/red-ui/src/app/services/entity-services/dictionary.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { firstValueFrom, forkJoin, Observable, of, throwError } from 'rxjs'; +import { firstValueFrom, forkJoin, Observable, throwError } from 'rxjs'; import { EntitiesService, QueryParam, Toaster } from '@iqser/common-ui'; import { Dictionary, DictionaryEntryType, DictionaryEntryTypes, IDictionary, IUpdateDictionary, SuperTypes } from '@red/domain'; import { catchError, map, switchMap, tap } from 'rxjs/operators'; @@ -177,9 +177,7 @@ export class DictionaryService extends EntitiesService } }); - possibleDictionaries.sort((a, b) => a.label.localeCompare(b.label)); - - return possibleDictionaries; + return possibleDictionaries.sort((a, b) => a.label.localeCompare(b.label)); } getRedactionTypes(dossierTemplateId: string): Dictionary[] { @@ -191,9 +189,7 @@ export class DictionaryService extends EntitiesService } } - possibleDictionaries.sort((a, b) => a.label.localeCompare(b.label)); - - return possibleDictionaries; + return possibleDictionaries.sort((a, b) => a.label.localeCompare(b.label)); } async getDictionariesOptions(dossierTemplateId: string, dossierId: string): Promise { diff --git a/apps/red-ui/src/app/translations/remove-annotation-translations.ts b/apps/red-ui/src/app/translations/remove-annotation-translations.ts new file mode 100644 index 000000000..b186ef467 --- /dev/null +++ b/apps/red-ui/src/app/translations/remove-annotation-translations.ts @@ -0,0 +1,22 @@ +import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { RemoveAnnotationOption } from '../modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-options'; + +interface Option { + label: string; + description: string; +} + +export const removeAnnotationTranslations: { [key in RemoveAnnotationOption]: Option } = { + ONLY_HERE: { + label: _('remove-annotation.dialog.content.options.only-here.label'), + description: _('remove-annotation.dialog.content.options.only-here.description'), + }, + IN_DOSSIER: { + label: _('remove-annotation.dialog.content.options.in-dossier.label'), + description: _('remove-annotation.dialog.content.options.in-dossier.description'), + }, + FALSE_POSITIVE: { + label: _('remove-annotation.dialog.content.options.false-positive.label'), + description: _('remove-annotation.dialog.content.options.false-positive.description'), + }, +}; diff --git a/apps/red-ui/src/assets/config/config.json b/apps/red-ui/src/assets/config/config.json index f96939231..772d6e339 100644 --- a/apps/red-ui/src/assets/config/config.json +++ b/apps/red-ui/src/assets/config/config.json @@ -1,9 +1,9 @@ { "ADMIN_CONTACT_NAME": null, "ADMIN_CONTACT_URL": null, - "API_URL": "https://dan.iqser.cloud", + "API_URL": "https://dev-04.iqser.cloud", "APP_NAME": "RedactManager very very very very long", - "IS_DOCUMINE": false, + "IS_DOCUMINE": true, "AUTO_READ_TIME": 3, "BACKEND_APP_VERSION": "4.4.40", "EULA_URL": "EULA_URL", @@ -12,7 +12,7 @@ "MAX_RETRIES_ON_SERVER_ERROR": 3, "OAUTH_CLIENT_ID": "redaction", "OAUTH_IDP_HINT": null, - "OAUTH_URL": "https://dan.iqser.cloud/auth", + "OAUTH_URL": "https://dev-04.iqser.cloud/auth", "RECENT_PERIOD_IN_HOURS": 24, "SELECTION_MODE": "structural", "MANUAL_BASE_URL": "https://docs.redactmanager.com/preview", diff --git a/apps/red-ui/src/assets/i18n/redact/de.json b/apps/red-ui/src/assets/i18n/redact/de.json index 7c8549c24..d52bf2b30 100644 --- a/apps/red-ui/src/assets/i18n/redact/de.json +++ b/apps/red-ui/src/assets/i18n/redact/de.json @@ -11,6 +11,22 @@ "all": "Alle", "none": "Keine" }, + "add-annotation": { + "dialog": { + "actions": { + "cancel": "", + "save": "" + }, + "content": { + "comment": "", + "comment-placeholder": "", + "selected-text": "", + "type": "", + "type-placeholder": "" + }, + "title": "" + } + }, "add-dossier-dialog": { "actions": { "save": "Speichern", @@ -1951,6 +1967,33 @@ }, "redaction-abbreviation": "R", "references": "", + "remove-annotation": { + "dialog": { + "actions": { + "cancel": "", + "save": "" + }, + "content": { + "comment": "", + "comment-placeholder": "", + "options": { + "false-positive": { + "description": "", + "label": "" + }, + "in-dossier": { + "description": "", + "label": "" + }, + "only-here": { + "description": "", + "label": "" + } + } + }, + "title": "" + } + }, "remove-redaction": { "dialog": { "actions": { diff --git a/apps/red-ui/src/assets/i18n/redact/en.json b/apps/red-ui/src/assets/i18n/redact/en.json index 5ad6ae7d5..1b22cc672 100644 --- a/apps/red-ui/src/assets/i18n/redact/en.json +++ b/apps/red-ui/src/assets/i18n/redact/en.json @@ -11,6 +11,22 @@ "all": "All", "none": "None" }, + "add-annotation": { + "dialog": { + "actions": { + "cancel": "Cancel", + "save": "Save" + }, + "content": { + "comment": "Comment", + "comment-placeholder": "Add remarks or mentions...", + "selected-text": "Selected text:", + "type": "Type", + "type-placeholder": "Select type ..." + }, + "title": "Add annotation" + } + }, "add-dossier-dialog": { "actions": { "save": "Save", @@ -1951,6 +1967,33 @@ }, "redaction-abbreviation": "R", "references": "{count} {count, plural, one{reference} other{references}}", + "remove-annotation": { + "dialog": { + "actions": { + "cancel": "", + "save": "" + }, + "content": { + "comment": "", + "comment-placeholder": "", + "options": { + "false-positive": { + "description": "", + "label": "" + }, + "in-dossier": { + "description": "", + "label": "" + }, + "only-here": { + "description": "", + "label": "" + } + } + }, + "title": "" + } + }, "remove-redaction": { "dialog": { "actions": { diff --git a/apps/red-ui/src/assets/i18n/scm/de.json b/apps/red-ui/src/assets/i18n/scm/de.json index 26c56448b..452dcf579 100644 --- a/apps/red-ui/src/assets/i18n/scm/de.json +++ b/apps/red-ui/src/assets/i18n/scm/de.json @@ -11,6 +11,22 @@ "all": "Alle", "none": "Keine" }, + "add-annotation": { + "dialog": { + "actions": { + "cancel": "", + "save": "" + }, + "content": { + "comment": "", + "comment-placeholder": "", + "selected-text": "", + "type": "", + "type-placeholder": "" + }, + "title": "" + } + }, "add-dossier-dialog": { "actions": { "save": "Speichern", @@ -1951,6 +1967,33 @@ }, "redaction-abbreviation": "C", "references": "", + "remove-annotation": { + "dialog": { + "actions": { + "cancel": "", + "save": "" + }, + "content": { + "comment": "", + "comment-placeholder": "", + "options": { + "false-positive": { + "description": "", + "label": "" + }, + "in-dossier": { + "description": "", + "label": "" + }, + "only-here": { + "description": "", + "label": "" + } + } + }, + "title": "" + } + }, "remove-redaction": { "dialog": { "actions": { diff --git a/apps/red-ui/src/assets/i18n/scm/en.json b/apps/red-ui/src/assets/i18n/scm/en.json index f382a2b4e..76cbfd99b 100644 --- a/apps/red-ui/src/assets/i18n/scm/en.json +++ b/apps/red-ui/src/assets/i18n/scm/en.json @@ -11,6 +11,22 @@ "all": "All", "none": "None" }, + "add-annotation": { + "dialog": { + "actions": { + "cancel": "Cancel", + "save": "Save" + }, + "content": { + "comment": "Comment", + "comment-placeholder": "Add remarks or mentions...", + "selected-text": "Selected text:", + "type": "Type", + "type-placeholder": "Select type ..." + }, + "title": "Add annotation" + } + }, "add-dossier-dialog": { "actions": { "save": "Save", @@ -1951,6 +1967,33 @@ }, "redaction-abbreviation": "A", "references": "{count} {count, plural, one{reference} other{references}}", + "remove-annotation": { + "dialog": { + "actions": { + "cancel": "", + "save": "" + }, + "content": { + "comment": "", + "comment-placeholder": "", + "options": { + "false-positive": { + "description": "", + "label": "" + }, + "in-dossier": { + "description": "", + "label": "" + }, + "only-here": { + "description": "", + "label": "" + } + } + }, + "title": "" + } + }, "remove-redaction": { "dialog": { "actions": { From 9806149dffa203adff11cb98243096790a88fc42 Mon Sep 17 00:00:00 2001 From: Valentin Mihai Date: Mon, 24 Jul 2023 00:46:54 +0300 Subject: [PATCH 2/2] DM-337 - Add/Remove annotations dialog in DocuMine --- .../add-hint-dialog.component.ts | 24 ++---- .../add-annotation-dialog.component.scss | 8 ++ .../add-annotation-dialog.component.ts | 42 ++--------- .../remove-annotation-dialog.component.ts | 73 +++---------------- .../remove-annotation-options.ts | 7 -- .../redact-text-dialog.component.ts | 9 +-- .../remove-redaction-dialog.component.ts | 2 +- .../file-preview-screen.component.ts | 24 ++++-- .../services/annotation-actions.service.ts | 54 ++++++++------ .../file-preview/utils/dialog-options.ts | 34 ++++++--- .../file-preview/utils/dialog-types.ts | 22 ++++-- .../app/translations/add-hint-translations.ts | 4 +- .../translations/redact-text-translations.ts | 4 +- .../remove-annotation-translations.ts | 10 +-- .../remove-redaction-translations.ts | 9 +-- apps/red-ui/src/assets/i18n/redact/en.json | 22 +++--- apps/red-ui/src/assets/i18n/scm/en.json | 22 +++--- 17 files changed, 150 insertions(+), 220 deletions(-) delete mode 100644 apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-options.ts diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/add-hint-dialog/add-hint-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/add-hint-dialog/add-hint-dialog.component.ts index a6135d5da..84fb04590 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/add-hint-dialog/add-hint-dialog.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/add-hint-dialog/add-hint-dialog.component.ts @@ -8,18 +8,15 @@ import { ActiveDossiersService } from '@services/dossiers/active-dossiers.servic import { DictionaryService } from '@services/entity-services/dictionary.service'; import { tap } from 'rxjs/operators'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; -import { IqserDialogComponent } from '@common-ui/dialog/iqser-dialog-component.directive'; -import { RedactOrHintData, RedactOrHintResult } from '../../utils/dialog-types'; +import { IqserDialogComponent } from '@iqser/common-ui'; import { getRedactOrHintOptions, RedactOrHintOption, RedactOrHintOptions } from '../../utils/dialog-options'; +import { AddHintData, AddHintResult } from '../../utils/dialog-types'; @Component({ templateUrl: './add-hint-dialog.component.html', styleUrls: ['./add-hint-dialog.component.scss'], }) -export class AddHintDialogComponent - extends IqserDialogComponent - implements OnInit -{ +export class AddHintDialogComponent extends IqserDialogComponent implements OnInit { readonly roles = Roles; readonly iconButtonTypes = IconButtonTypes; readonly options: DetailsRadioOption[]; @@ -27,7 +24,6 @@ export class AddHintDialogComponent dictionaries: Dictionary[] = []; form!: UntypedFormGroup; - #manualRedactionTypeExists = true; #applyToAllDossiers: boolean; readonly #dossier: Dossier; @@ -43,7 +39,6 @@ export class AddHintDialogComponent super(); this.#dossier = _activeDossiersService.find(this.data.dossierId); this.#applyToAllDossiers = this.data.applyToAllDossiers ?? true; - this.#manualRedactionTypeExists = this._dictionaryService.hasManualType(this.#dossier.dossierTemplateId); this.options = getRedactOrHintOptions(this.#dossier, this.#isRss, true, this.#applyToAllDossiers, this.data.isApprover); this.form = this.#getForm(); @@ -122,11 +117,8 @@ export class AddHintDialogComponent #getForm(): UntypedFormGroup { return this._formBuilder.group({ selectedText: this.data?.manualRedactionEntryWrapper?.manualRedactionEntry?.value, - reason: [null], comment: [null], - dictionary: [this.#manualRedactionTypeExists ? SuperTypes.ManualRedaction : null], - classification: ['non-readable content'], - section: [null], + dictionary: [null], option: [this.options[0]], }); } @@ -134,7 +126,7 @@ export class AddHintDialogComponent #enhanceManualRedaction(addRedactionRequest: IAddRedactionRequest) { addRedactionRequest.reason = 'Dictionary Request'; addRedactionRequest.type = this.form.get('dictionary').value; - addRedactionRequest.section = this.form.get('section').value; + addRedactionRequest.section = null; addRedactionRequest.value = this.form.get('selectedText').value; const selectedType = this.dictionaries.find(d => d.type === addRedactionRequest.type); @@ -154,10 +146,6 @@ export class AddHintDialogComponent if (!this.#isRss) { this.options[1].extraOption.checked = this.#applyToAllDossiers; } - if (this.dictionaryRequest) { - this.form.get('dictionary').setValue(null); - return; - } - this.form.get('dictionary').setValue(this.#manualRedactionTypeExists ? SuperTypes.ManualRedaction : null); + this.form.get('dictionary').setValue(null); } } diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/add-annotation-dialog/add-annotation-dialog.component.scss b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/add-annotation-dialog/add-annotation-dialog.component.scss index e69de29bb..0bc0b2eb8 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/add-annotation-dialog/add-annotation-dialog.component.scss +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/add-annotation-dialog/add-annotation-dialog.component.scss @@ -0,0 +1,8 @@ +label { + font-weight: bold; + padding-bottom: 8px; +} + +iqser-details-radio { + padding-top: 20px; +} diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/add-annotation-dialog/add-annotation-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/add-annotation-dialog/add-annotation-dialog.component.ts index 1d840f854..946b3e521 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/add-annotation-dialog/add-annotation-dialog.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/add-annotation-dialog/add-annotation-dialog.component.ts @@ -1,46 +1,29 @@ import { Component, OnInit } from '@angular/core'; import { IconButtonTypes, IqserPermissionsService } from '@iqser/common-ui'; -import { Dictionary, Dossier, File, IAddRedactionRequest, IManualRedactionEntry, SuperTypes } from '@red/domain'; +import { Dictionary, Dossier, IAddRedactionRequest, SuperTypes } from '@red/domain'; import { FormBuilder, UntypedFormGroup } from '@angular/forms'; import { Roles } from '@users/roles'; -import { JustificationsService } from '@services/entity-services/justifications.service'; import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service'; import { DictionaryService } from '@services/entity-services/dictionary.service'; - -import { ManualRedactionEntryWrapper } from '@models/file/manual-redaction-entry.wrapper'; import { IqserDialogComponent } from '@iqser/common-ui'; - -export interface AddAnnotationData { - manualRedactionEntryWrapper: ManualRedactionEntryWrapper; - dossierId: string; - file: File; -} - -interface DialogResult { - redaction: IManualRedactionEntry; - dictionary: Dictionary; - applyToAllDossiers: boolean | null; -} +import { AddAnnotationData, AddAnnotationResult } from '../../../utils/dialog-types'; @Component({ templateUrl: './add-annotation-dialog.component.html', styleUrls: ['./add-annotation-dialog.component.scss'], }) export class AddAnnotationDialogComponent - extends IqserDialogComponent + extends IqserDialogComponent implements OnInit { readonly iconButtonTypes = IconButtonTypes; dictionaries: Dictionary[] = []; form!: UntypedFormGroup; - #manualRedactionTypeExists = true; readonly #dossier: Dossier; readonly #isRss = this._iqserPermissionsService.has(Roles.getRss); - readonly hint: boolean; constructor( - private readonly _justificationsService: JustificationsService, private readonly _activeDossiersService: ActiveDossiersService, private readonly _dictionaryService: DictionaryService, private readonly _iqserPermissionsService: IqserPermissionsService, @@ -48,8 +31,6 @@ export class AddAnnotationDialogComponent ) { super(); this.#dossier = _activeDossiersService.find(this.data.dossierId); - this.#manualRedactionTypeExists = this._dictionaryService.hasManualType(this.#dossier.dossierTemplateId); - this.form = this.#getForm(); } @@ -67,7 +48,6 @@ export class AddAnnotationDialogComponent async ngOnInit(): Promise { this.dictionaries = this._dictionaryService.getRedactionTypes(this.#dossier.dossierTemplateId); - this.#formatSelectedTextValue(); } save(): void { @@ -82,23 +62,11 @@ export class AddAnnotationDialogComponent #getForm(): UntypedFormGroup { return this._formBuilder.group({ selectedText: this.data?.manualRedactionEntryWrapper?.manualRedactionEntry?.value, - reason: [null], comment: [null], - dictionary: [this.#manualRedactionTypeExists ? SuperTypes.ManualRedaction : null], - classification: ['non-readable content'], - section: [null], + dictionary: [null], }); } - #formatSelectedTextValue(): void { - this.data.manualRedactionEntryWrapper.manualRedactionEntry.value = - this.data.manualRedactionEntryWrapper.manualRedactionEntry.value.replace( - // eslint-disable-next-line no-control-regex,max-len - /([^\s\d-]{2,})[-\u00AD]\u000D\u000A|[\u000A\u000B\u000C\u000D\u0085\u2028\u2029]/gi, - '$1', - ); - } - #enhanceManualRedaction(addRedactionRequest: IAddRedactionRequest) { addRedactionRequest.type = this.form.get('dictionary').value; @@ -110,7 +78,7 @@ export class AddAnnotationDialogComponent } const commentValue = this.form.get('comment').value; addRedactionRequest.comment = commentValue ? { text: commentValue } : null; - addRedactionRequest.section = this.form.get('section').value; + addRedactionRequest.section = null; addRedactionRequest.value = this.form.get('selectedText').value; } } diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-dialog.component.ts index 70f757ecc..38360893b 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-dialog.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-dialog.component.ts @@ -1,35 +1,10 @@ import { Component } from '@angular/core'; import { DetailsRadioOption, IconButtonTypes } from '@iqser/common-ui'; import { FormBuilder, UntypedFormGroup } from '@angular/forms'; -import { AnnotationWrapper } from '@models/file/annotation.wrapper'; -import { Dossier } from '@red/domain'; import { IqserDialogComponent } from '@iqser/common-ui'; import { PermissionsService } from '@services/permissions.service'; -import { RemoveAnnotationOption, RemoveAnnotationOptions } from './remove-annotation-options'; -import { removeAnnotationTranslations } from '@translations/remove-annotation-translations'; - -const PIN_ICON = 'red:push-pin'; -const FOLDER_ICON = 'red:folder'; -const REMOVE_FROM_DICT_ICON = 'red:remove-from-dict'; - -export interface RemoveAnnotationPermissions { - canRemoveOnlyHere: boolean; - canRemoveFromDictionary: boolean; - canMarkAsFalsePositive: boolean; -} - -export interface RemoveAnnotationData { - annotation: AnnotationWrapper; - dossier: Dossier; - falsePositiveContext: string; - permissions: RemoveAnnotationPermissions; - applyToAllDossiers: boolean; -} - -export interface RemoveAnnotationResult { - comment: string; - option: DetailsRadioOption; -} +import { RemoveAnnotationData, RemoveAnnotationResult } from '../../../utils/dialog-types'; +import { getRemoveRedactionOptions, RemoveAnnotationOption, RemoveAnnotationOptions } from '../../../utils/dialog-options'; @Component({ templateUrl: './remove-annotation-dialog.component.html', @@ -45,20 +20,19 @@ export class RemoveAnnotationDialogComponent extends IqserDialogComponent< form!: UntypedFormGroup; - readonly #annotation: AnnotationWrapper; - readonly #permissions: RemoveAnnotationPermissions; - readonly #translations = removeAnnotationTranslations; - constructor(private readonly _formBuilder: FormBuilder, private readonly _permissionsService: PermissionsService) { super(); - this.#annotation = this.data.annotation; - this.#permissions = this.data.permissions; - this.options = this.#options(); + this.options = getRemoveRedactionOptions(this.data, true); this.form = this.#getForm(); } + get #applyToAllDossiers(): boolean { + const selectedOption = this.form.get('option').value.value; + return selectedOption === RemoveAnnotationOptions.IN_DOSSIER || selectedOption === RemoveAnnotationOptions.FALSE_POSITIVE; + } + save(): void { - this.dialogRef.close(this.form.getRawValue()); + this.dialogRef.close({ ...this.form.getRawValue(), applyToAllDossiers: this.#applyToAllDossiers }); } #getForm(): UntypedFormGroup { @@ -67,33 +41,4 @@ export class RemoveAnnotationDialogComponent extends IqserDialogComponent< option: [this.options[0]], }); } - - #options() { - const options: DetailsRadioOption[] = []; - if (this.#permissions.canRemoveOnlyHere) { - options.push({ - label: this.#translations.ONLY_HERE.label, - description: this.#translations.ONLY_HERE.description, - icon: PIN_ICON, - value: RemoveAnnotationOptions.ONLY_HERE, - }); - } - if (this.#permissions.canRemoveFromDictionary) { - options.push({ - label: this.#translations.IN_DOSSIER.label, - description: this.#translations.IN_DOSSIER.description, - icon: FOLDER_ICON, - value: RemoveAnnotationOptions.IN_DOSSIER, - }); - } - if (this.#permissions.canMarkAsFalsePositive) { - options.push({ - label: this.#translations.FALSE_POSITIVE.label, - description: this.#translations.FALSE_POSITIVE.description, - icon: REMOVE_FROM_DICT_ICON, - value: RemoveAnnotationOptions.FALSE_POSITIVE, - }); - } - return options; - } } diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-options.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-options.ts deleted file mode 100644 index 01da1c682..000000000 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-options.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const RemoveAnnotationOptions = { - ONLY_HERE: 'ONLY_HERE', - IN_DOSSIER: 'IN_DOSSIER', - FALSE_POSITIVE: 'FALSE_POSITIVE', -} as const; - -export type RemoveAnnotationOption = keyof typeof RemoveAnnotationOptions; diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/redact-text-dialog/redact-text-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/redact-text-dialog/redact-text-dialog.component.ts index e103a4e17..d30c5586a 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/redact-text-dialog/redact-text-dialog.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/redact-text-dialog/redact-text-dialog.component.ts @@ -10,16 +10,16 @@ import { LegalBasisOption } from '../manual-redaction-dialog/manual-annotation-d import { DictionaryService } from '@services/entity-services/dictionary.service'; import { tap } from 'rxjs/operators'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; -import { IqserDialogComponent } from '@common-ui/dialog/iqser-dialog-component.directive'; +import { IqserDialogComponent } from '@iqser/common-ui'; import { getRedactOrHintOptions, RedactOrHintOption, RedactOrHintOptions } from '../../utils/dialog-options'; -import { RedactOrHintData, RedactOrHintResult } from '../../utils/dialog-types'; +import { RedactTextData, RedactTextResult } from '../../utils/dialog-types'; @Component({ templateUrl: './redact-text-dialog.component.html', styleUrls: ['./redact-text-dialog.component.scss'], }) export class RedactTextDialogComponent - extends IqserDialogComponent + extends IqserDialogComponent implements OnInit { readonly roles = Roles; @@ -137,7 +137,6 @@ export class RedactTextDialogComponent reason: [null], comment: [null], dictionary: [this.#manualRedactionTypeExists ? SuperTypes.ManualRedaction : null], - section: [null], option: [this.options[0]], }); } @@ -150,7 +149,7 @@ export class RedactTextDialogComponent #enhanceManualRedaction(addRedactionRequest: IAddRedactionRequest) { addRedactionRequest.type = this.form.get('dictionary').value; - addRedactionRequest.section = this.form.get('section').value; + addRedactionRequest.section = null; addRedactionRequest.value = this.form.get('selectedText').value; const legalOption: LegalBasisOption = this.form.get('reason').value; diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/remove-redaction-dialog/remove-redaction-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/remove-redaction-dialog/remove-redaction-dialog.component.ts index da89aaad9..cc1c0d386 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/remove-redaction-dialog/remove-redaction-dialog.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/remove-redaction-dialog/remove-redaction-dialog.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { DetailsRadioOption, IconButtonTypes } from '@iqser/common-ui'; import { FormBuilder, UntypedFormGroup } from '@angular/forms'; -import { IqserDialogComponent } from '@common-ui/dialog/iqser-dialog-component.directive'; +import { IqserDialogComponent } from '@iqser/common-ui'; import { PermissionsService } from '@services/permissions.service'; import { tap } from 'rxjs/operators'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; diff --git a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts index 838eeaa2b..67ac0b29e 100644 --- a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts @@ -73,7 +73,8 @@ import { copyLocalStorageFiltersValues, FilterService, NestedFilter, processFilt import { AutoUnsubscribe, Bind, bool, Debounce, List, OnAttach, OnDetach } from '@iqser/common-ui/lib/utils'; import { TenantsService } from '@iqser/common-ui/lib/tenants'; import { AddHintDialogComponent } from './dialogs/add-hint-dialog/add-hint-dialog.component'; -import { RedactOrHintData } from './utils/dialog-types'; +import { AddAnnotationDialogComponent } from './dialogs/docu-mine/add-annotation-dialog/add-annotation-dialog.component'; +import { RedactTextData } from './utils/dialog-types'; const textActions = [TextPopups.REDACT_TEXT, TextPopups.ADD_HINT, TextPopups.ADD_FALSE_POSITIVE]; @@ -368,16 +369,13 @@ export class FilePreviewScreenComponent ); } - async openRedactTextDialog(manualRedactionEntryWrapper: ManualRedactionEntryWrapper) { + async #openRedactTextDialog(manualRedactionEntryWrapper: ManualRedactionEntryWrapper) { const file = this.state.file(); const hint = manualRedactionEntryWrapper.type === ManualRedactionEntryTypes.HINT; const data = this.#getRedactTextDialogData(manualRedactionEntryWrapper, file); - const ref = hint - ? this._iqserDialog.openDefault(AddHintDialogComponent, { data: data as RedactOrHintData }) - : this._iqserDialog.openDefault(RedactTextDialogComponent, { data: data as RedactOrHintData }); + const result = await this.#getRedactTextDialog(hint, data).result(); - const result = await ref.result(); if (!result) { return; } @@ -652,7 +650,7 @@ export class FilePreviewScreenComponent }); this.addActiveScreenSubscription = this.pdfProxyService.redactTextRequested$.subscribe($event => { - this.openRedactTextDialog($event).then(); + this.#openRedactTextDialog($event).then(); }); this.addActiveScreenSubscription = this.pdfProxyService.pageChanged$.subscribe(page => @@ -850,7 +848,17 @@ export class FilePreviewScreenComponent } } - #getRedactTextDialogData(manualRedactionEntryWrapper: ManualRedactionEntryWrapper, file: File) { + #getRedactTextDialog(hint: boolean, data: RedactTextData) { + if (this.#isDocumine) { + return this._iqserDialog.openDefault(AddAnnotationDialogComponent, { data }); + } + if (hint) { + return this._iqserDialog.openDefault(AddHintDialogComponent, { data }); + } + return this._iqserDialog.openDefault(RedactTextDialogComponent, { data }); + } + + #getRedactTextDialogData(manualRedactionEntryWrapper: ManualRedactionEntryWrapper, file: File): RedactTextData { const dossierTemplate = this._dossierTemplatesService.find(this.state.dossierTemplateId); const data = { diff --git a/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts b/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts index c11f728b5..e3f608ec9 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts @@ -19,7 +19,7 @@ import { AcceptRecommendationDialogComponent, AcceptRecommendationReturnType, } from '../dialogs/accept-recommendation-dialog/accept-recommendation-dialog.component'; -import { defaultDialogConfig } from '@iqser/common-ui'; +import { defaultDialogConfig, getConfig } from '@iqser/common-ui'; import { filter } from 'rxjs/operators'; import { MatDialog } from '@angular/material/dialog'; import { FilePreviewStateService } from './file-preview-state.service'; @@ -34,11 +34,19 @@ import { IqserDialog } from '@common-ui/dialog/iqser-dialog.service'; import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { isJustOne, List } from '@iqser/common-ui/lib/utils'; import { PermissionsService } from '@services/permissions.service'; -import { RemoveRedactionPermissions, RemoveRedactionResult } from '../utils/dialog-types'; +import { + RedactTextData, + RemoveAnnotationResult, + RemoveRedactionData, + RemoveRedactionPermissions, + RemoveRedactionResult, +} from '../utils/dialog-types'; import { RemoveRedactionOptions } from '../utils/dialog-options'; +import { RemoveAnnotationDialogComponent } from '../dialogs/docu-mine/remove-annotation-dialog/remove-annotation-dialog.component'; @Injectable() export class AnnotationActionsService { + readonly #isDocumine; constructor( private readonly _manualRedactionService: ManualRedactionService, private readonly _dialogService: FilePreviewDialogService, @@ -53,13 +61,8 @@ export class AnnotationActionsService { private readonly _skippedService: SkippedService, private readonly _dossierTemplatesService: DossierTemplatesService, private readonly _permissionsService: PermissionsService, - ) {} - - acceptSuggestion(annotations: AnnotationWrapper[]) { - const { dossierId, fileId } = this._state; - const ids = annotations.map(a => a.id); - const request = this._manualRedactionService.approve(ids, dossierId, fileId); - this.#processObsAndEmit(request).then(); + ) { + this.#isDocumine = getConfig().IS_DOCUMINE; } removeHighlights(highlights: AnnotationWrapper[]): void { @@ -127,18 +130,16 @@ export class AnnotationActionsService { const dossierTemplate = this._dossierTemplatesService.find(this._state.dossierTemplateId); const isApprover = this._permissionsService.isApprover(this._state.dossier()); - const result: RemoveRedactionResult = await this._iqserDialog - .openDefault(RemoveRedactionDialogComponent, { - data: { - redaction, - dossier: this._state.dossier(), - falsePositiveContext: this._getFalsePositiveText(redaction), - permissions: removePermissions, - applyToAllDossiers: isApprover ? dossierTemplate.applyDictionaryUpdatesToAllDossiersByDefault : false, - isApprover, - }, - }) - .result(); + const data = { + redaction, + dossier: this._state.dossier(), + falsePositiveContext: this._getFalsePositiveText(redaction), + permissions: removePermissions, + applyToAllDossiers: isApprover ? dossierTemplate.applyDictionaryUpdatesToAllDossiersByDefault : false, + isApprover, + }; + + const result = await this.#getRemoveRedactionDialog(data).result(); if (result) { if (result.option.value === RemoveRedactionOptions.FALSE_POSITIVE) { @@ -382,7 +383,7 @@ export class AnnotationActionsService { type: redaction.type, positions: redaction.positions, addToDictionary: true, - addToAllDossiers: !!dialogResult.option.extraOption?.checked, + addToAllDossiers: !!dialogResult.option.extraOption?.checked || !!dialogResult.applyToAllDossiers, reason: 'False Positive', dictionaryEntryType: redaction.isRecommendation ? DictionaryEntryTypes.FALSE_RECOMMENDATION @@ -400,11 +401,18 @@ export class AnnotationActionsService { annotationId: redaction.id, comment: dialogResult.comment, removeFromDictionary, - removeFromAllDossiers: !!dialogResult.option.extraOption?.checked, + removeFromAllDossiers: !!dialogResult.option.extraOption?.checked || !!dialogResult.applyToAllDossiers, }; const { dossierId, fileId } = this._state; this.#processObsAndEmit( this._manualRedactionService.removeRedaction([body], dossierId, fileId, removeFromDictionary, redaction.isHint), ).then(); } + + #getRemoveRedactionDialog(data: RemoveRedactionData) { + if (this.#isDocumine) { + return this._iqserDialog.openDefault(RemoveAnnotationDialogComponent, { data }); + } + return this._iqserDialog.openDefault(RemoveRedactionDialogComponent, { data }); + } } diff --git a/apps/red-ui/src/app/modules/file-preview/utils/dialog-options.ts b/apps/red-ui/src/app/modules/file-preview/utils/dialog-options.ts index 7b7980053..6a4774e68 100644 --- a/apps/red-ui/src/app/modules/file-preview/utils/dialog-options.ts +++ b/apps/red-ui/src/app/modules/file-preview/utils/dialog-options.ts @@ -4,6 +4,7 @@ import { redactTextTranslations } from '@translations/redact-text-translations'; import { Dossier } from '@red/domain'; import { removeRedactionTranslations } from '@translations/remove-redaction-translations'; import { RemoveRedactionData } from './dialog-types'; +import { removeAnnotationTranslations } from '@translations/remove-annotation-translations'; const PIN_ICON = 'red:push-pin'; const FOLDER_ICON = 'red:folder'; @@ -21,8 +22,10 @@ export const RemoveRedactionOptions = { IN_DOSSIER: 'IN_DOSSIER', FALSE_POSITIVE: 'FALSE_POSITIVE', } as const; +export const RemoveAnnotationOptions = RemoveRedactionOptions; export type RemoveRedactionOption = keyof typeof RemoveRedactionOptions; +export type RemoveAnnotationOption = RemoveRedactionOption; export const getRedactOrHintOptions = ( dossier: Dossier, @@ -57,8 +60,11 @@ export const getRedactOrHintOptions = ( return options; }; -export const getRemoveRedactionOptions = (data: RemoveRedactionData): DetailsRadioOption[] => { - const translations = removeRedactionTranslations; +export const getRemoveRedactionOptions = ( + data: RemoveRedactionData, + isDocumine: boolean = false, +): DetailsRadioOption[] => { + const translations = isDocumine ? removeAnnotationTranslations : removeRedactionTranslations; const { permissions, redaction, applyToAllDossiers, isApprover, falsePositiveContext } = data; const options: DetailsRadioOption[] = []; @@ -78,11 +84,13 @@ export const getRemoveRedactionOptions = (data: RemoveRedactionData): DetailsRad descriptionParams: { type: redaction.hint ? 'hint' : 'redact', value: redaction.value }, icon: FOLDER_ICON, value: RemoveRedactionOptions.IN_DOSSIER, - extraOption: { - label: translations.IN_DOSSIER.extraOptionLabel, - checked: applyToAllDossiers ?? true, - hidden: !isApprover, - }, + extraOption: !isDocumine + ? { + label: translations.IN_DOSSIER.extraOptionLabel, + checked: applyToAllDossiers ?? true, + hidden: !isApprover, + } + : null, }); } if (permissions.canMarkAsFalsePositive) { @@ -92,11 +100,13 @@ export const getRemoveRedactionOptions = (data: RemoveRedactionData): DetailsRad descriptionParams: { value: redaction.value, type: redaction.type, context: falsePositiveContext }, icon: REMOVE_FROM_DICT_ICON, value: RemoveRedactionOptions.FALSE_POSITIVE, - extraOption: { - label: translations.FALSE_POSITIVE.extraOptionLabel, - checked: applyToAllDossiers ?? true, - hidden: !isApprover, - }, + extraOption: !isDocumine + ? { + label: translations.FALSE_POSITIVE.extraOptionLabel, + checked: applyToAllDossiers ?? true, + hidden: !isApprover, + } + : null, }); } return options; diff --git a/apps/red-ui/src/app/modules/file-preview/utils/dialog-types.ts b/apps/red-ui/src/app/modules/file-preview/utils/dialog-types.ts index 7423a8716..d252100b5 100644 --- a/apps/red-ui/src/app/modules/file-preview/utils/dialog-types.ts +++ b/apps/red-ui/src/app/modules/file-preview/utils/dialog-types.ts @@ -4,19 +4,27 @@ import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { DetailsRadioOption } from '@iqser/common-ui'; import { RemoveRedactionOption } from './dialog-options'; -export interface RedactOrHintData { +export interface AddAnnotationData { manualRedactionEntryWrapper: ManualRedactionEntryWrapper; dossierId: string; file: File; - applyToAllDossiers: boolean; - isApprover: boolean; } -export interface RedactOrHintResult { +export interface RedactTextData extends AddAnnotationData { + applyToAllDossiers?: boolean; + isApprover?: boolean; +} + +export type AddHintData = RedactTextData; + +export interface RedactTextResult { redaction: IManualRedactionEntry; dictionary: Dictionary; } +export type AddHintResult = RedactTextResult; +export type AddAnnotationResult = RedactTextResult; + export interface RemoveRedactionPermissions { canRemoveOnlyHere: boolean; canRemoveFromDictionary: boolean; @@ -32,8 +40,12 @@ export interface RemoveRedactionData { isApprover: boolean; } +export type RemoveAnnotationData = RemoveRedactionData; + export interface RemoveRedactionResult { comment: string; option: DetailsRadioOption; - applyToAllDossiers: boolean | null; + applyToAllDossiers?: boolean; } + +export type RemoveAnnotationResult = RemoveRedactionResult; diff --git a/apps/red-ui/src/app/translations/add-hint-translations.ts b/apps/red-ui/src/app/translations/add-hint-translations.ts index 4ed66d469..75866f456 100644 --- a/apps/red-ui/src/app/translations/add-hint-translations.ts +++ b/apps/red-ui/src/app/translations/add-hint-translations.ts @@ -1,7 +1,7 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; -import { RedactOrHintOption } from '@translations/redact-text-translations'; +import { DialogOption } from '@translations/redact-text-translations'; -export const addHintTranslations: Record<'onlyHere' | 'inDossier', RedactOrHintOption> = { +export const addHintTranslations: Record<'onlyHere' | 'inDossier', DialogOption> = { onlyHere: { label: _('add-hint.dialog.content.options.only-here.label'), description: _('add-hint.dialog.content.options.only-here.description'), diff --git a/apps/red-ui/src/app/translations/redact-text-translations.ts b/apps/red-ui/src/app/translations/redact-text-translations.ts index cae038523..ae4b9cc61 100644 --- a/apps/red-ui/src/app/translations/redact-text-translations.ts +++ b/apps/red-ui/src/app/translations/redact-text-translations.ts @@ -1,12 +1,12 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; -export interface RedactOrHintOption { +export interface DialogOption { label: string; description: string; extraOptionLabel?: string; } -export const redactTextTranslations: Record<'onlyHere' | 'inDossier', RedactOrHintOption> = { +export const redactTextTranslations: Record<'onlyHere' | 'inDossier', DialogOption> = { onlyHere: { label: _('redact-text.dialog.content.options.only-here.label'), description: _('redact-text.dialog.content.options.only-here.description'), diff --git a/apps/red-ui/src/app/translations/remove-annotation-translations.ts b/apps/red-ui/src/app/translations/remove-annotation-translations.ts index b186ef467..0b056844c 100644 --- a/apps/red-ui/src/app/translations/remove-annotation-translations.ts +++ b/apps/red-ui/src/app/translations/remove-annotation-translations.ts @@ -1,12 +1,8 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; -import { RemoveAnnotationOption } from '../modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-options'; +import { RemoveAnnotationOption } from '../modules/file-preview/utils/dialog-options'; +import { DialogOption } from '@translations/redact-text-translations'; -interface Option { - label: string; - description: string; -} - -export const removeAnnotationTranslations: { [key in RemoveAnnotationOption]: Option } = { +export const removeAnnotationTranslations: { [key in RemoveAnnotationOption]: DialogOption } = { ONLY_HERE: { label: _('remove-annotation.dialog.content.options.only-here.label'), description: _('remove-annotation.dialog.content.options.only-here.description'), diff --git a/apps/red-ui/src/app/translations/remove-redaction-translations.ts b/apps/red-ui/src/app/translations/remove-redaction-translations.ts index 53a88f21b..05b850b66 100644 --- a/apps/red-ui/src/app/translations/remove-redaction-translations.ts +++ b/apps/red-ui/src/app/translations/remove-redaction-translations.ts @@ -1,13 +1,8 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { RemoveRedactionOption } from '../modules/file-preview/utils/dialog-options'; +import { DialogOption } from '@translations/redact-text-translations'; -interface Option { - label: string; - description: string; - extraOptionLabel?: string; -} - -export const removeRedactionTranslations: { [key in RemoveRedactionOption]: Option } = { +export const removeRedactionTranslations: { [key in RemoveRedactionOption]: DialogOption } = { ONLY_HERE: { label: _('remove-redaction.dialog.content.options.only-here.label'), description: _('remove-redaction.dialog.content.options.only-here.description'), diff --git a/apps/red-ui/src/assets/i18n/redact/en.json b/apps/red-ui/src/assets/i18n/redact/en.json index a70a34b4b..e157891c2 100644 --- a/apps/red-ui/src/assets/i18n/redact/en.json +++ b/apps/red-ui/src/assets/i18n/redact/en.json @@ -1983,28 +1983,28 @@ "remove-annotation": { "dialog": { "actions": { - "cancel": "", - "save": "" + "cancel": "Cancel", + "save": "Save" }, "content": { - "comment": "", - "comment-placeholder": "", + "comment": "Comment", + "comment-placeholder": "Add remarks or mentions ...", "options": { "false-positive": { - "description": "", - "label": "" + "description": "\"{value}\" is not a {type} in this context: \"{context}\".", + "label": "False positive" }, "in-dossier": { - "description": "", - "label": "" + "description": "Do not annotate \"{value}\" in any document of the current dossier.", + "label": "Remove from dossier" }, "only-here": { - "description": "", - "label": "" + "description": "Do not annotate \"{value}\" at this position in the current document.", + "label": "Remove here" } } }, - "title": "" + "title": "Remove annotation" } }, "remove-redaction": { diff --git a/apps/red-ui/src/assets/i18n/scm/en.json b/apps/red-ui/src/assets/i18n/scm/en.json index d358b29b7..defd5c7b3 100644 --- a/apps/red-ui/src/assets/i18n/scm/en.json +++ b/apps/red-ui/src/assets/i18n/scm/en.json @@ -1983,28 +1983,28 @@ "remove-annotation": { "dialog": { "actions": { - "cancel": "", - "save": "" + "cancel": "Cancel", + "save": "Save" }, "content": { - "comment": "", - "comment-placeholder": "", + "comment": "Comment", + "comment-placeholder": "Add remarks or mentions ...", "options": { "false-positive": { - "description": "", - "label": "" + "description": "\"{value}\" is not a {type} in this context: \"{context}\".", + "label": "False positive" }, "in-dossier": { - "description": "", - "label": "" + "description": "Do not annotate \"{value}\" in any document of the current dossier.", + "label": "Remove from dossier" }, "only-here": { - "description": "", - "label": "" + "description": "Do not annotate \"{value}\" at this position in the current document.", + "label": "Remove here" } } }, - "title": "" + "title": "Remove annotation" } }, "remove-redaction": {