diff --git a/apps/red-ui/src/app/app.module.ts b/apps/red-ui/src/app/app.module.ts index 383a62684..c255390da 100644 --- a/apps/red-ui/src/app/app.module.ts +++ b/apps/red-ui/src/app/app.module.ts @@ -131,7 +131,7 @@ export const appModuleFactory = (config: AppConfig) => { features: { ANNOTATIONS: { color: 'aqua', - enabled: false, + enabled: true, level: NgxLoggerLevel.DEBUG, }, FILTERS: { @@ -147,7 +147,7 @@ export const appModuleFactory = (config: AppConfig) => { enabled: true, }, FILE: { - enabled: true, + enabled: false, }, CHANGES: { enabled: false, diff --git a/apps/red-ui/src/app/models/file/annotation-permissions.utils.ts b/apps/red-ui/src/app/models/file/annotation-permissions.utils.ts index f9334fb7b..ef53f5c51 100644 --- a/apps/red-ui/src/app/models/file/annotation-permissions.utils.ts +++ b/apps/red-ui/src/app/models/file/annotation-permissions.utils.ts @@ -1,5 +1,5 @@ -import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { AnnotationPermissions } from '@models/file/annotation.permissions'; +import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { Dictionary } from '@red/domain'; export const canUndo = (annotation: AnnotationWrapper, isApprover: boolean) => @@ -39,7 +39,9 @@ export const canRecategorizeAnnotation = (annotation: AnnotationWrapper, canReca export const canResizeAnnotation = (annotation: AnnotationWrapper, canAddRedaction: boolean) => canAddRedaction && + !annotation.isSkipped && + !annotation.pending && (((annotation.isRedacted || annotation.isImage) && !annotation.isSuggestion) || annotation.isSuggestionResize || - annotation.isRecommendation) && - !annotation.pending; + annotation.isDictBasedHint || + annotation.isRecommendation); diff --git a/apps/red-ui/src/app/models/file/annotation.permissions.ts b/apps/red-ui/src/app/models/file/annotation.permissions.ts index 50ea54fb6..16eef7da4 100644 --- a/apps/red-ui/src/app/models/file/annotation.permissions.ts +++ b/apps/red-ui/src/app/models/file/annotation.permissions.ts @@ -1,8 +1,7 @@ -import { AnnotationWrapper } from './annotation.wrapper'; -import { Dictionary } from '@red/domain'; -import { isArray } from 'lodash-es'; import { IqserPermissionsService } from '@iqser/common-ui'; +import { Dictionary } from '@red/domain'; import { Roles } from '@users/roles'; +import { isArray } from 'lodash-es'; import { canAcceptRecommendation, canChangeLegalBasis, @@ -16,6 +15,7 @@ import { canResizeAnnotation, canUndo, } from './annotation-permissions.utils'; +import { AnnotationWrapper } from './annotation.wrapper'; export class AnnotationPermissions { canUndo = true; @@ -64,6 +64,22 @@ export class AnnotationPermissions { return summedPermissions; } + static reduce(permissions: AnnotationPermissions[]): AnnotationPermissions { + const result = new AnnotationPermissions(); + result.canResizeAnnotation = permissions.length === 1 && permissions[0].canResizeAnnotation; + result.canChangeLegalBasis = permissions.reduce((acc, next) => acc && next.canChangeLegalBasis, true); + result.canRecategorizeAnnotation = permissions.reduce((acc, next) => acc && next.canRecategorizeAnnotation, true); + result.canRemoveFromDictionary = permissions.reduce((acc, next) => acc && next.canRemoveFromDictionary, true); + result.canAcceptRecommendation = permissions.reduce((acc, next) => acc && next.canAcceptRecommendation, true); + result.canMarkAsFalsePositive = permissions.reduce((acc, next) => acc && next.canMarkAsFalsePositive, true); + result.canForceRedaction = permissions.reduce((acc, next) => acc && next.canForceRedaction, true); + result.canForceHint = permissions.reduce((acc, next) => acc && next.canForceHint, true); + result.canRemoveOnlyHere = permissions.reduce((acc, next) => acc && next.canRemoveOnlyHere, true); + result.canRemoveRedaction = permissions.reduce((acc, next) => acc && next.canRemoveRedaction, true); + result.canUndo = permissions.reduce((acc, next) => acc && next.canUndo, true); + return result; + } + private _merge(permissions: AnnotationPermissions) { for (const key of Object.keys(this)) { if (typeof this[key] === 'boolean') { diff --git a/apps/red-ui/src/app/models/file/annotation.wrapper.ts b/apps/red-ui/src/app/models/file/annotation.wrapper.ts index 4716d2b89..1dce4e86a 100644 --- a/apps/red-ui/src/app/models/file/annotation.wrapper.ts +++ b/apps/red-ui/src/app/models/file/annotation.wrapper.ts @@ -17,6 +17,7 @@ import { IRectangle, IRedactionLogEntry, LogEntryEngine, + LogEntryEngines, LogEntryStatuses, LowLevelFilterTypes, ManualRedactionTypes, @@ -180,6 +181,10 @@ export class AnnotationWrapper implements IListable { return 'square'; } + get isDictBasedHint() { + return this.isHint && this.engines.includes(LogEntryEngines.DICTIONARY); + } + get isIgnoredHint() { return this.superType === SuperTypes.IgnoredHint; } diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/edit-redaction-dialog/edit-redaction-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/edit-redaction-dialog/edit-redaction-dialog.component.ts index 5cdc94841..acc43a71f 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/edit-redaction-dialog/edit-redaction-dialog.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/edit-redaction-dialog/edit-redaction-dialog.component.ts @@ -1,16 +1,16 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, inject, OnInit } from '@angular/core'; +import { FormBuilder } from '@angular/forms'; import { DetailsRadioOption, IconButtonTypes, IqserDialogComponent } from '@iqser/common-ui'; -import { Dictionary, Dossier, SuperTypes } from '@red/domain'; -import { FormBuilder, UntypedFormGroup } from '@angular/forms'; +import { Dictionary, SuperTypes } from '@red/domain'; +import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service'; +import { DictionaryService } from '@services/entity-services/dictionary.service'; +import { JustificationsService } from '@services/entity-services/justifications.service'; import { Roles } from '@users/roles'; import { firstValueFrom } from 'rxjs'; -import { JustificationsService } from '@services/entity-services/justifications.service'; -import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service'; -import { LegalBasisOption } from '../manual-redaction-dialog/manual-annotation-dialog.component'; -import { DictionaryService } from '@services/entity-services/dictionary.service'; +import { IMAGE_CATEGORIES } from '../../utils/constants'; import { getEditRedactionOptions, RedactOrHintOption } from '../../utils/dialog-options'; import { EditRedactionData, EditRedactResult } from '../../utils/dialog-types'; -import { IMAGE_CATEGORIES } from '../../utils/constants'; +import { LegalBasisOption } from '../manual-redaction-dialog/manual-annotation-dialog.component'; @Component({ templateUrl: './edit-redaction-dialog.component.html', @@ -19,6 +19,8 @@ export class EditRedactionDialogComponent extends IqserDialogComponent implements OnInit { + readonly #dossier = inject(ActiveDossiersService).find(this.data.dossierId); + readonly #applyToAllDossiers = this.data.applyToAllDossiers; readonly roles = Roles; readonly iconButtonTypes = IconButtonTypes; readonly redactedText: string; @@ -28,24 +30,17 @@ export class EditRedactionDialogComponent readonly showLegalReason: boolean; readonly isHint: boolean; readonly showExtras: boolean; - options: DetailsRadioOption[] | undefined; legalOptions: LegalBasisOption[] = []; dictionaries: Dictionary[] = []; - form: UntypedFormGroup; - readonly #dossier: Dossier; - - #applyToAllDossiers: boolean; + readonly form; constructor( private readonly _justificationsService: JustificationsService, - private readonly _activeDossiersService: ActiveDossiersService, private readonly _dictionaryService: DictionaryService, private readonly _formBuilder: FormBuilder, ) { super(); - this.#dossier = this._activeDossiersService.find(this.data.dossierId); - this.#applyToAllDossiers = this.data.applyToAllDossiers; const annotations = this.data.annotations; const firstEntry = annotations[0]; this.isImage = [...IMAGE_CATEGORIES, 'ocr'].includes(firstEntry.type); @@ -126,7 +121,7 @@ export class EditRedactionDialogComponent ); } - #getForm(): UntypedFormGroup { + #getForm() { return this._formBuilder.group({ reason: [null], comment: [null], diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/recategorize-image-dialog/recategorize-image-dialog.component.html b/apps/red-ui/src/app/modules/file-preview/dialogs/recategorize-image-dialog/recategorize-image-dialog.component.html deleted file mode 100644 index b50d6fab3..000000000 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/recategorize-image-dialog/recategorize-image-dialog.component.html +++ /dev/null @@ -1,40 +0,0 @@ -
-
-
- -
-
- - - - - {{ translations[option] | translate }} - - - -
- -
- - -
-
- -
- - -
-
-
- - -
diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/recategorize-image-dialog/recategorize-image-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/recategorize-image-dialog/recategorize-image-dialog.component.ts deleted file mode 100644 index fc5256af6..000000000 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/recategorize-image-dialog/recategorize-image-dialog.component.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Component, Inject, OnInit } from '@angular/core'; -import { Validators } from '@angular/forms'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { AnnotationWrapper } from '@models/file/annotation.wrapper'; -import { imageCategoriesTranslations } from '@translations/image-categories-translations'; -import { Dossier, ImageCategory } from '@red/domain'; -import { BaseDialogComponent } from '@iqser/common-ui'; - -@Component({ - templateUrl: './recategorize-image-dialog.component.html', -}) -export class RecategorizeImageDialogComponent extends BaseDialogComponent implements OnInit { - readonly typeOptions: ImageCategory[] = ['signature', 'logo', 'formula', 'image']; - readonly translations = imageCategoriesTranslations; - - constructor( - protected readonly _dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) readonly data: { annotations: AnnotationWrapper[]; dossier: Dossier }, - ) { - super(_dialogRef); - } - - get changed(): boolean { - return this.form.get('type').value !== this.data.annotations[0].type; - } - - ngOnInit() { - this.form = this._formBuilder.group({ - type: [this.data.annotations[0].type, Validators.required], - comment: [null], - }); - this.initialFormValue = this.form.getRawValue(); - } - - save() { - this._dialogRef.close({ - type: this.form.get('type').value, - comment: this.form.get('comment').value, - }); - } -} diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/resize-redaction-dialog/resize-redaction-dialog.component.html b/apps/red-ui/src/app/modules/file-preview/dialogs/resize-redaction-dialog/resize-redaction-dialog.component.html index db747fce4..78c3aeab6 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/resize-redaction-dialog/resize-redaction-dialog.component.html +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/resize-redaction-dialog/resize-redaction-dialog.component.html @@ -1,19 +1,19 @@
-
+
- {{ redaction.value }} + {{ redaction.value }}
-
+
- {{ data.text }} + {{ data.text }}
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 0de813009..2dd50f057 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 @@ -1,5 +1,8 @@ -import { NgModule } from '@angular/core'; +import { OverlayModule } from '@angular/cdk/overlay'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { PendingChangesGuard } from '@guards/can-deactivate.guard'; import { CapitalizePipe, CircleButtonComponent, @@ -20,58 +23,54 @@ import { RoundCheckboxComponent, StopPropagationDirective, } from '@iqser/common-ui'; -import { TranslateModule } from '@ngx-translate/core'; -import { RouterModule } from '@angular/router'; -import { FilePreviewScreenComponent } from './file-preview-screen.component'; -import { FileWorkloadComponent } from './components/file-workload/file-workload.component'; -import { AnnotationDetailsComponent } from './components/annotation-details/annotation-details.component'; -import { AnnotationsListComponent } from './components/annotations-list/annotations-list.component'; -import { PageIndicatorComponent } from './components/page-indicator/page-indicator.component'; -import { PageExclusionComponent } from './components/page-exclusion/page-exclusion.component'; -import { AnnotationActionsComponent } from './components/annotation-actions/annotation-actions.component'; -import { CommentsComponent } from './components/comments/comments.component'; -import { DocumentInfoComponent } from './components/document-info/document-info.component'; -import { OverlayModule } from '@angular/cdk/overlay'; -import { ViewSwitchComponent } from './components/view-switch/view-switch.component'; -import { UserManagementComponent } from './components/user-management/user-management.component'; -import { AnnotationReferencesListComponent } from './components/annotation-references-list/annotation-references-list.component'; -import { AcceptRecommendationDialogComponent } from './dialogs/accept-recommendation-dialog/accept-recommendation-dialog.component'; -import { AnnotationCardComponent } from './components/annotation-card/annotation-card.component'; -import { AnnotationReferencesPageIndicatorComponent } from './components/annotation-references-page-indicator/annotation-references-page-indicator.component'; -import { HighlightsSeparatorComponent } from './components/highlights-separator/highlights-separator.component'; -import { PendingChangesGuard } from '@guards/can-deactivate.guard'; -import { ManualAnnotationDialogComponent } from './dialogs/manual-redaction-dialog/manual-annotation-dialog.component'; -import { ForceAnnotationDialogComponent } from './dialogs/force-redaction-dialog/force-annotation-dialog.component'; -import { ResizeRedactionDialogComponent } from './dialogs/resize-redaction-dialog/resize-redaction-dialog.component'; -import { ChangeLegalBasisDialogComponent } from './dialogs/change-legal-basis-dialog/change-legal-basis-dialog.component'; -import { RecategorizeImageDialogComponent } from './dialogs/recategorize-image-dialog/recategorize-image-dialog.component'; -import { HighlightActionDialogComponent } from './dialogs/highlight-action-dialog/highlight-action-dialog.component'; -import { FilePreviewDialogService } from './services/file-preview-dialog.service'; -import { DocumentInfoDialogComponent } from './dialogs/document-info-dialog/document-info-dialog.component'; -import { ManualRedactionService } from './services/manual-redaction.service'; -import { AnnotationWrapperComponent } from './components/annotation-wrapper/annotation-wrapper.component'; -import { AnnotationReferenceComponent } from './components/annotation-reference/annotation-reference.component'; -import { ImportRedactionsDialogComponent } from './dialogs/import-redactions-dialog/import-redactions-dialog'; -import { DocumentUnloadedGuard } from './services/document-unloaded.guard'; -import { FilePreviewRightContainerComponent } from './components/right-container/file-preview-right-container.component'; -import { ReadonlyBannerComponent } from './components/readonly-banner/readonly-banner.component'; -import { PagesComponent } from './components/pages/pages.component'; -import { SharedModule } from '@shared/shared.module'; -import { SharedDossiersModule } from '../shared-dossiers/shared-dossiers.module'; -import { RedactTextDialogComponent } from './dialogs/redact-text-dialog/redact-text-dialog.component'; -import { RemoveRedactionDialogComponent } from './dialogs/remove-redaction-dialog/remove-redaction-dialog.component'; -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 { IqserUsersModule } from '@iqser/common-ui/lib/users'; +import { TranslateModule } from '@ngx-translate/core'; +import { SharedModule } from '@shared/shared.module'; +import { SharedDossiersModule } from '../shared-dossiers/shared-dossiers.module'; +import { AnnotationActionsComponent } from './components/annotation-actions/annotation-actions.component'; +import { AnnotationCardComponent } from './components/annotation-card/annotation-card.component'; +import { AnnotationDetailsComponent } from './components/annotation-details/annotation-details.component'; +import { AnnotationReferenceComponent } from './components/annotation-reference/annotation-reference.component'; +import { AnnotationReferencesListComponent } from './components/annotation-references-list/annotation-references-list.component'; +import { AnnotationReferencesPageIndicatorComponent } from './components/annotation-references-page-indicator/annotation-references-page-indicator.component'; +import { AnnotationWrapperComponent } from './components/annotation-wrapper/annotation-wrapper.component'; +import { AnnotationsListComponent } from './components/annotations-list/annotations-list.component'; +import { CommentsComponent } from './components/comments/comments.component'; +import { DocumentInfoComponent } from './components/document-info/document-info.component'; +import { FileWorkloadComponent } from './components/file-workload/file-workload.component'; +import { HighlightsSeparatorComponent } from './components/highlights-separator/highlights-separator.component'; +import { PageExclusionComponent } from './components/page-exclusion/page-exclusion.component'; +import { PageIndicatorComponent } from './components/page-indicator/page-indicator.component'; +import { PagesComponent } from './components/pages/pages.component'; +import { ReadonlyBannerComponent } from './components/readonly-banner/readonly-banner.component'; +import { FilePreviewRightContainerComponent } from './components/right-container/file-preview-right-container.component'; +import { UserManagementComponent } from './components/user-management/user-management.component'; +import { ViewSwitchComponent } from './components/view-switch/view-switch.component'; +import { AcceptRecommendationDialogComponent } from './dialogs/accept-recommendation-dialog/accept-recommendation-dialog.component'; import { AddHintDialogComponent } from './dialogs/add-hint-dialog/add-hint-dialog.component'; +import { ChangeLegalBasisDialogComponent } from './dialogs/change-legal-basis-dialog/change-legal-basis-dialog.component'; import { AddAnnotationDialogComponent } from './dialogs/docu-mine/add-annotation-dialog/add-annotation-dialog.component'; +import { EditAnnotationDialogComponent } from './dialogs/docu-mine/edit-annotation-dialog/edit-annotation-dialog.component'; import { RemoveAnnotationDialogComponent } from './dialogs/docu-mine/remove-annotation-dialog/remove-annotation-dialog.component'; import { ResizeAnnotationDialogComponent } from './dialogs/docu-mine/resize-annotation-dialog/resize-annotation-dialog.component'; -import { EditAnnotationDialogComponent } from './dialogs/docu-mine/edit-annotation-dialog/edit-annotation-dialog.component'; +import { DocumentInfoDialogComponent } from './dialogs/document-info-dialog/document-info-dialog.component'; import { EditRedactionDialogComponent } from './dialogs/edit-redaction-dialog/edit-redaction-dialog.component'; -import { TablesService } from './services/tables.service'; +import { ForceAnnotationDialogComponent } from './dialogs/force-redaction-dialog/force-annotation-dialog.component'; +import { HighlightActionDialogComponent } from './dialogs/highlight-action-dialog/highlight-action-dialog.component'; +import { ImportRedactionsDialogComponent } from './dialogs/import-redactions-dialog/import-redactions-dialog'; +import { ManualAnnotationDialogComponent } from './dialogs/manual-redaction-dialog/manual-annotation-dialog.component'; import { RedactRecommendationDialogComponent } from './dialogs/redact-recommendation-dialog/redact-recommendation-dialog.component'; +import { RedactTextDialogComponent } from './dialogs/redact-text-dialog/redact-text-dialog.component'; +import { RemoveRedactionDialogComponent } from './dialogs/remove-redaction-dialog/remove-redaction-dialog.component'; +import { ResizeRedactionDialogComponent } from './dialogs/resize-redaction-dialog/resize-redaction-dialog.component'; +import { FilePreviewScreenComponent } from './file-preview-screen.component'; +import { DocumentUnloadedGuard } from './services/document-unloaded.guard'; +import { FilePreviewDialogService } from './services/file-preview-dialog.service'; +import { ManualRedactionService } from './services/manual-redaction.service'; +import { TablesService } from './services/tables.service'; const routes: IqserRoutes = [ { @@ -87,7 +86,6 @@ const dialogs = [ ForceAnnotationDialogComponent, ResizeRedactionDialogComponent, ChangeLegalBasisDialogComponent, - RecategorizeImageDialogComponent, HighlightActionDialogComponent, AcceptRecommendationDialogComponent, DocumentInfoDialogComponent, 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 3c11ebdff..7a129a0fa 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 @@ -2,6 +2,7 @@ import { Injectable } from '@angular/core'; import { IqserDialog } from '@common-ui/dialog/iqser-dialog.service'; import { getConfig } from '@iqser/common-ui'; import { List, log } from '@iqser/common-ui/lib/utils'; +import { AnnotationPermissions } from '@models/file/annotation.permissions'; import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { Core } from '@pdftron/webviewer'; import { @@ -44,7 +45,7 @@ import { SkippedService } from './skipped.service'; @Injectable() export class AnnotationActionsService { - readonly #isDocumine; + readonly #isDocumine = getConfig().IS_DOCUMINE; constructor( private readonly _manualRedactionService: ManualRedactionService, @@ -59,9 +60,7 @@ export class AnnotationActionsService { private readonly _skippedService: SkippedService, private readonly _dossierTemplatesService: DossierTemplatesService, private readonly _permissionsService: PermissionsService, - ) { - this.#isDocumine = getConfig().IS_DOCUMINE; - } + ) {} removeHighlights(highlights: AnnotationWrapper[]): void { const data = this.#getHighlightOperationData(EarmarkOperation.REMOVE, highlights); @@ -73,18 +72,6 @@ export class AnnotationActionsService { this._dialogService.openDialog('highlightAction', data); } - rejectSuggestion(annotations: AnnotationWrapper[]) { - const { dossierId, fileId } = this._state; - this.#processObsAndEmit( - this._manualRedactionService.declineOrRemove( - annotations.map(a => a.id), - dossierId, - fileId, - annotations[0].isModifyDictionary, - ), - ).then(); - } - forceAnnotation(annotations: AnnotationWrapper[], hint: boolean = false) { const { dossierId, fileId } = this._state; const data = { dossier: this._state.dossier(), annotations, hint }; @@ -147,7 +134,7 @@ export class AnnotationActionsService { await this.#processObsAndEmit(zip(requests).pipe(log())); } - async removeRedaction(redaction: AnnotationWrapper, permissions) { + async removeRedaction(redaction: AnnotationWrapper, permissions: AnnotationPermissions) { const removePermissions: RemoveRedactionPermissions = { canRemoveOnlyHere: permissions.canRemoveOnlyHere, canRemoveFromDictionary: permissions.canRemoveFromDictionary, @@ -181,19 +168,6 @@ export class AnnotationActionsService { } } - recategorizeImages(annotations: AnnotationWrapper[]) { - const data = { annotations, dossier: this._state.dossier() }; - const { dossierId, fileId } = this._state; - this._dialogService.openDialog('recategorizeImage', data, ({ comment, type }: { type: string; comment: string }) => { - const body: List = annotations.map(({ id }) => ({ - annotationId: id, - type, - comment, - })); - this.#processObsAndEmit(this._manualRedactionService.recategorizeRedactions(body, dossierId, fileId)).then(); - }); - } - undoDirectAction(annotations: AnnotationWrapper[]) { const { dossierId, fileId } = this._state; const modifyDictionary = annotations[0].isModifyDictionary; @@ -231,7 +205,6 @@ export class AnnotationActionsService { if (annotationWrapper.rectangle || annotationWrapper.imported || annotationWrapper.isImage) { this._annotationManager.delete(annotationWrapper); const rectangleAnnotation = this.#generateRectangle(annotationWrapper); - console.log(rectangleAnnotation); return this._annotationManager.add(rectangleAnnotation); } @@ -293,11 +266,9 @@ export class AnnotationActionsService { async cancelResize(annotationWrapper: AnnotationWrapper) { this._annotationManager.resizingAnnotationId = undefined; - this._annotationManager.resizingHasStarted = false; this._annotationManager.delete(annotationWrapper); await this._annotationDrawService.draw([annotationWrapper], this._skippedService.hideSkipped(), this._state.dossierTemplateId); this._annotationManager.deselect(); - await this._fileDataService.annotationsChanged(); } #generateRectangle(annotationWrapper: AnnotationWrapper) { @@ -333,9 +304,7 @@ export class AnnotationActionsService { } async #processObsAndEmit(obs: Observable) { - await firstValueFrom(obs) - .then(() => this._fileDataService.annotationsChanged()) - .catch(() => this._fileDataService.annotationsChanged()); + await firstValueFrom(obs).finally(() => this._fileDataService.annotationsChanged()); } #getFalsePositiveText(annotation: AnnotationWrapper) { @@ -389,7 +358,7 @@ export class AnnotationActionsService { rect.topLeft.x + rect.width - 2, rect.topLeft.y + rect.height - percentHeightOffset, ); - const quadWords = await this._extractTextFromRect(page, pdfNetRect); + const quadWords = await this.#extractTextFromRect(page, pdfNetRect); words.push(...quadWords); } @@ -411,7 +380,7 @@ export class AnnotationActionsService { }; } - private async _extractTextFromRect(page: Core.PDFNet.Page, rect: Core.PDFNet.Rect) { + async #extractTextFromRect(page: Core.PDFNet.Page, rect: Core.PDFNet.Rect) { const txt = await this._pdf.PDFNet.TextExtractor.create(); await txt.begin(page, rect); // Read the page. diff --git a/apps/red-ui/src/app/modules/file-preview/services/file-preview-dialog.service.ts b/apps/red-ui/src/app/modules/file-preview/services/file-preview-dialog.service.ts index 9f02fa3a8..2d2d8f13e 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/file-preview-dialog.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/file-preview-dialog.service.ts @@ -1,23 +1,14 @@ import { Injectable } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; -import { ForceAnnotationDialogComponent } from '../dialogs/force-redaction-dialog/force-annotation-dialog.component'; -import { DocumentInfoDialogComponent } from '../dialogs/document-info-dialog/document-info-dialog.component'; -import { ManualAnnotationDialogComponent } from '../dialogs/manual-redaction-dialog/manual-annotation-dialog.component'; -import { ChangeLegalBasisDialogComponent } from '../dialogs/change-legal-basis-dialog/change-legal-basis-dialog.component'; -import { RecategorizeImageDialogComponent } from '../dialogs/recategorize-image-dialog/recategorize-image-dialog.component'; import { ConfirmationDialogComponent, DialogConfig, DialogService } from '@iqser/common-ui'; +import { ChangeLegalBasisDialogComponent } from '../dialogs/change-legal-basis-dialog/change-legal-basis-dialog.component'; +import { DocumentInfoDialogComponent } from '../dialogs/document-info-dialog/document-info-dialog.component'; +import { ForceAnnotationDialogComponent } from '../dialogs/force-redaction-dialog/force-annotation-dialog.component'; import { HighlightActionDialogComponent } from '../dialogs/highlight-action-dialog/highlight-action-dialog.component'; +import { ManualAnnotationDialogComponent } from '../dialogs/manual-redaction-dialog/manual-annotation-dialog.component'; import { StructuredComponentManagementDialogComponent } from '../dialogs/structured-component-management-dialog/structured-component-management-dialog.component'; -type DialogType = - | 'confirm' - | 'documentInfo' - | 'rss' - | 'recategorizeImage' - | 'changeLegalBasis' - | 'forceAnnotation' - | 'manualAnnotation' - | 'highlightAction'; +type DialogType = 'confirm' | 'documentInfo' | 'rss' | 'changeLegalBasis' | 'forceAnnotation' | 'manualAnnotation' | 'highlightAction'; @Injectable() export class FilePreviewDialogService extends DialogService { @@ -30,9 +21,6 @@ export class FilePreviewDialogService extends DialogService { component: DocumentInfoDialogComponent, dialogConfig: { autoFocus: true }, }, - recategorizeImage: { - component: RecategorizeImageDialogComponent, - }, changeLegalBasis: { component: ChangeLegalBasisDialogComponent, }, diff --git a/apps/red-ui/src/app/modules/file-preview/services/pdf-annotation-actions.service.ts b/apps/red-ui/src/app/modules/file-preview/services/pdf-annotation-actions.service.ts index ab888107e..7a3c63ca7 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/pdf-annotation-actions.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/pdf-annotation-actions.service.ts @@ -1,15 +1,15 @@ import { inject, Injectable, NgZone } from '@angular/core'; -import { AnnotationWrapper } from '@models/file/annotation.wrapper'; -import { AnnotationPermissions } from '@models/file/annotation.permissions'; -import { PermissionsService } from '@services/permissions.service'; -import { FilePreviewStateService } from './file-preview-state.service'; -import { TranslateService } from '@ngx-translate/core'; -import { AnnotationActionsService } from './annotation-actions.service'; -import { IqserPermissionsService } from '@iqser/common-ui'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; -import { IHeaderElement } from '@red/domain'; -import { REDAnnotationManager } from '../../pdf-viewer/services/annotation-manager.service'; +import { IqserPermissionsService } from '@iqser/common-ui'; import { BASE_HREF_FN } from '@iqser/common-ui/lib/utils'; +import { AnnotationPermissions } from '@models/file/annotation.permissions'; +import { AnnotationWrapper } from '@models/file/annotation.wrapper'; +import { TranslateService } from '@ngx-translate/core'; +import { IHeaderElement } from '@red/domain'; +import { PermissionsService } from '@services/permissions.service'; +import { REDAnnotationManager } from '../../pdf-viewer/services/annotation-manager.service'; +import { AnnotationActionsService } from './annotation-actions.service'; +import { FilePreviewStateService } from './file-preview-state.service'; @Injectable() export class PdfAnnotationActionsService { @@ -27,21 +27,18 @@ export class PdfAnnotationActionsService { const permissions = this.#getAnnotationsPermissions(annotations); // you can only resize one annotation at a time - if (permissions.canResize) { + if (permissions.canResizeAnnotation) { const firstAnnotation = annotations[0]; // if we already entered resize-mode previously if (firstAnnotation.id === this.#annotationManager.resizingAnnotationId) { - if (this.#annotationManager.resizingHasStarted) { - const acceptResizeButton = this.#getButton('check', _('annotation-actions.resize-accept.label'), () => - this.#annotationActionsService.acceptResize(firstAnnotation), - ); - const cancelResizeButton = this.#getButton('close', _('annotation-actions.resize-cancel.label'), () => - this.#annotationActionsService.cancelResize(firstAnnotation), - ); + const acceptResizeButton = this.#getButton('check', _('annotation-actions.resize-accept.label'), () => + this.#annotationActionsService.acceptResize(firstAnnotation), + ); + const cancelResizeButton = this.#getButton('close', _('annotation-actions.resize-cancel.label'), () => + this.#annotationActionsService.cancelResize(firstAnnotation), + ); - return [acceptResizeButton, cancelResizeButton]; - } - return []; + return [acceptResizeButton, cancelResizeButton]; } const resizeButton = this.#getButton('resize', _('annotation-actions.resize.label'), () => @@ -103,22 +100,11 @@ export class PdfAnnotationActionsService { }; } - #getAnnotationsPermissions(annotations: AnnotationWrapper[]) { + #getAnnotationsPermissions(annotations: AnnotationWrapper[]): AnnotationPermissions { const dossier = this.#state.dossier(); const isApprover = this.#permissionsService.isApprover(dossier); const dictionaries = this.#state.dictionaries; const permissions = annotations.map(a => AnnotationPermissions.forUser(isApprover, a, dictionaries, this.#iqserPermissionsService)); - return { - canResize: permissions.length === 1 && permissions[0].canResizeAnnotation, - canChangeLegalBasis: permissions.reduce((acc, next) => acc && next.canChangeLegalBasis, true), - canRecategorizeAnnotation: permissions.reduce((acc, next) => acc && next.canRecategorizeAnnotation, true), - canRemoveFromDictionary: permissions.reduce((acc, next) => acc && next.canRemoveFromDictionary, true), - canAcceptRecommendation: permissions.reduce((acc, next) => acc && next.canAcceptRecommendation, true), - canMarkAsFalsePositive: permissions.reduce((acc, next) => acc && next.canMarkAsFalsePositive, true), - canForceRedaction: permissions.reduce((acc, next) => acc && next.canForceRedaction, true), - canForceHint: permissions.reduce((acc, next) => acc && next.canForceHint, true), - canRemoveOnlyHere: permissions.reduce((acc, next) => acc && next.canRemoveOnlyHere, true), - canRemoveRedaction: permissions.reduce((acc, next) => acc && next.canRemoveRedaction, true), - }; + return AnnotationPermissions.reduce(permissions); } } 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 8db518c70..badf12fdf 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 @@ -286,7 +286,7 @@ export class PdfProxyService { this.handleAnnotationSelected([]); } - #processSelectedAnnotations(annotations: Annotation[], action) { + #processSelectedAnnotations(annotations: Annotation[], action: string) { let nextAnnotations: Annotation[]; if (action === 'deselected') { @@ -313,7 +313,10 @@ export class PdfProxyService { nextAnnotations = this._annotationManager.selected; } - this.#configureAnnotationSpecificActions(nextAnnotations); + const annotationWasResized = this._annotationManager.resizingAnnotationId && action === 'modify'; + if (!this._annotationManager.resizingAnnotationId || annotationWasResized) { + this.#configureAnnotationSpecificActions(nextAnnotations); + } if (!(annotations.length === 1 && annotations[0].ReadOnly)) { this._pdf.enable(TextPopups.ADD_RECTANGLE); @@ -344,7 +347,6 @@ export class PdfProxyService { // which is automatically converted to redaction when resized, // so the original annotation(wrapper) is removed this._annotationManager.resizingAnnotationId = undefined; - this._annotationManager.resizingHasStarted = false; return; } @@ -359,20 +361,20 @@ export class PdfProxyService { } #configureAnnotationSpecificActions(viewerAnnotations: Annotation[]) { + this._pdf.resetAnnotationActions(); + if (!this.canPerformActions()) { - return this._pdf.resetAnnotationActions(); + return; } const annotationWrappers = viewerAnnotations.map(va => this._fileDataService.find(va.Id)).filter(va => !!va); - this._pdf.resetAnnotationActions(); - if (annotationWrappers.length === 0) { return this.#configureRectangleAnnotationPopup(viewerAnnotations[0]); } // Add hide action as last item - const allAnnotationsHaveImageAction = annotationWrappers.reduce((acc, next) => acc && next.isImage, true); - if (allAnnotationsHaveImageAction) { + const allAreImage = annotationWrappers.reduce((acc, next) => acc && next.isImage, true); + if (allAreImage && !this._annotationManager.resizingAnnotationId) { const allAreVisible = viewerAnnotations.reduce((acc, next) => next.isVisible() && acc, true); const visibilityButton = { diff --git a/apps/red-ui/src/app/modules/pdf-viewer/services/annotation-draw.service.ts b/apps/red-ui/src/app/modules/pdf-viewer/services/annotation-draw.service.ts index 5ed80f0db..80eabfe1f 100644 --- a/apps/red-ui/src/app/modules/pdf-viewer/services/annotation-draw.service.ts +++ b/apps/red-ui/src/app/modules/pdf-viewer/services/annotation-draw.service.ts @@ -4,8 +4,6 @@ import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { Core } from '@pdftron/webviewer'; import { IRectangle, ISectionRectangle, SuperTypes } from '@red/domain'; import { DefaultColorsService } from '@services/entity-services/default-colors.service'; -import { RedactionLogService } from '@services/files/redaction-log.service'; -import { UserPreferenceService } from '@users/user-preference.service'; import { hexToRgb } from '@utils/functions'; import { BoundingBox, Table } from '../../file-preview/services/tables.service'; import { REDAnnotationManager } from './annotation-manager.service'; @@ -31,8 +29,6 @@ export function getSectionRectangle(box: BoundingBox): ISectionRectangle { @Injectable() export class AnnotationDrawService { constructor( - private readonly _redactionLogService: RedactionLogService, - private readonly _userPreferenceService: UserPreferenceService, private readonly _annotationManager: REDAnnotationManager, private readonly _pdf: PdfViewer, private readonly _documentViewer: REDDocumentViewer, @@ -41,7 +37,7 @@ export class AnnotationDrawService { async draw(annotations: List, hideSkipped: boolean, dossierTemplateId: string) { try { - return this._pdf.runWithCleanup(() => this._draw(annotations, hideSkipped, dossierTemplateId)); + return this._pdf.runWithCleanup(() => this.#draw(annotations, hideSkipped, dossierTemplateId)); } catch (e) { console.error(e); } @@ -70,7 +66,7 @@ export class AnnotationDrawService { async drawTables(tables: Table[], page: number, dossierTemplateId: string) { const sections: Core.Annotations.RectangleAnnotation[] = []; tables.forEach(table => { - const section = this._computeSection(page, getSectionRectangle(table.boundingBox), dossierTemplateId); + const section = this.#computeSection(page, getSectionRectangle(table.boundingBox), dossierTemplateId); if (table.experimental) { section.StrokeColor = this.convertColor('#800080'); } else { @@ -80,7 +76,7 @@ export class AnnotationDrawService { table.cellsPerRow .flatMap(row => row) .forEach(row => { - const cellSection = this._computeSection(page, getSectionRectangle(row.boundingBox), dossierTemplateId); + const cellSection = this.#computeSection(page, getSectionRectangle(row.boundingBox), dossierTemplateId); if (table.experimental) { cellSection.StrokeColor = this.convertColor('#800080'); } else { @@ -93,10 +89,10 @@ export class AnnotationDrawService { await this._annotationManager.add(sections); } - private async _draw(annotationWrappers: List, hideSkipped: boolean, dossierTemplateId: string) { + async #draw(annotationWrappers: List, hideSkipped: boolean, dossierTemplateId: string) { const totalPages = this._pdf.totalPages(); const annotations = annotationWrappers - ?.map(annotation => this._computeAnnotation(annotation, hideSkipped, totalPages, dossierTemplateId)) + ?.map(annotation => this.#computeAnnotation(annotation, hideSkipped, totalPages, dossierTemplateId)) .filterTruthy(); if (!this._documentViewer.loaded()) { return; @@ -104,7 +100,7 @@ export class AnnotationDrawService { await this._annotationManager.add(annotations); } - private _computeSection(pageNumber: number, sectionRectangle: ISectionRectangle, dossierTemplateId: string) { + #computeSection(pageNumber: number, sectionRectangle: ISectionRectangle, dossierTemplateId: string) { const rectangleAnnot = this._pdf.rectangle(); const pageHeight = this._documentViewer.getHeight(pageNumber); const rectangle: IRectangle = { @@ -125,7 +121,7 @@ export class AnnotationDrawService { return rectangleAnnot; } - private _computeAnnotation(annotationWrapper: AnnotationWrapper, hideSkipped: boolean, totalPages: number, dossierTemplateId: string) { + #computeAnnotation(annotationWrapper: AnnotationWrapper, hideSkipped: boolean, totalPages: number, dossierTemplateId: string) { const pageNumber = this._pdf.isCompareMode() ? annotationWrapper.pageNumber * 2 - 1 : annotationWrapper.pageNumber; if (pageNumber > totalPages) { // skip imported annotations from files that have more pages than the current one @@ -150,7 +146,7 @@ export class AnnotationDrawService { } const annotation = this._pdf.textHighlight(); - annotation.Quads = this._rectanglesToQuads(annotationWrapper.positions, pageNumber); + annotation.Quads = this.#rectanglesToQuads(annotationWrapper.positions, pageNumber); annotation.Opacity = annotationWrapper.isChangeLogRemoved ? DEFAULT_REMOVED_ANNOTATION_OPACITY : DEFAULT_TEXT_ANNOTATION_OPACITY; annotation.setContents(annotationWrapper.content); annotation.PageNumber = pageNumber; @@ -190,12 +186,12 @@ export class AnnotationDrawService { return annotation; } - private _rectanglesToQuads(positions: IRectangle[], pageNumber: number): Quad[] { + #rectanglesToQuads(positions: IRectangle[], pageNumber: number): Quad[] { const pageHeight = this._documentViewer.getHeight(pageNumber); - return positions.map(p => this._rectangleToQuad(p, pageHeight)); + return positions.map(p => this.#rectangleToQuad(p, pageHeight)); } - private _rectangleToQuad(rectangle: IRectangle, pageHeight: number): Quad { + #rectangleToQuad(rectangle: IRectangle, pageHeight: number): Quad { const x1 = rectangle.topLeft.x; const y1 = pageHeight - (rectangle.topLeft.y + rectangle.height); diff --git a/apps/red-ui/src/app/modules/pdf-viewer/services/annotation-manager.service.ts b/apps/red-ui/src/app/modules/pdf-viewer/services/annotation-manager.service.ts index 1e0ae111c..79f250bbd 100644 --- a/apps/red-ui/src/app/modules/pdf-viewer/services/annotation-manager.service.ts +++ b/apps/red-ui/src/app/modules/pdf-viewer/services/annotation-manager.service.ts @@ -1,13 +1,13 @@ import { inject, Injectable, signal } from '@angular/core'; -import { Core } from '@pdftron/webviewer'; import type { List } from '@iqser/common-ui/lib/utils'; -import { AnnotationPredicate, DeleteAnnotationsOptions } from '../utils/types'; import { AnnotationWrapper } from '@models/file/annotation.wrapper'; -import { Subject } from 'rxjs'; -import { asList, getId, isStringOrWrapper } from '../utils/functions'; +import { Core } from '@pdftron/webviewer'; import { getLast } from '@utils/functions'; -import { AnnotationToolNames } from '../utils/constants'; import { NGXLogger } from 'ngx-logger'; +import { Subject } from 'rxjs'; +import { AnnotationToolNames } from '../utils/constants'; +import { asList, getId, isStringOrWrapper } from '../utils/functions'; +import { AnnotationPredicate, DeleteAnnotationsOptions } from '../utils/types'; import AnnotationManager = Core.AnnotationManager; import Annotation = Core.Annotations.Annotation; @@ -19,7 +19,6 @@ export class REDAnnotationManager { readonly #annotationSelected$ = new Subject<[Annotation[], string]>(); readonly annotationSelected$ = this.#annotationSelected$.asObservable(); resizingAnnotationId?: string = undefined; - resizingHasStarted = false; readonly hidden = this.#hidden.asReadonly(); get selected() { @@ -141,14 +140,12 @@ export class REDAnnotationManager { // when a rectangle is drawn, // it returns one annotation with tool name 'AnnotationCreateRectangle; // this will auto select rectangle after drawing - if (annotations.length === 1 && annotations[0].ToolName === AnnotationToolNames.AnnotationCreateRectangle) { - this.#manager.selectAnnotations(annotations); - annotations[0].disableRotationControl(); - } - if (action === 'modify' && options.source === 'resize' && !this.resizingHasStarted) { - this.resizingHasStarted = true; - this.#annotationSelected$.next([annotations, action]); + const annotation = annotations.length === 1 ? annotations[0] : undefined; + if (annotation && annotation.ToolName === AnnotationToolNames.AnnotationCreateRectangle) { + this.#manager.selectAnnotation(annotation); + annotation.disableRotationControl(); } + this.#annotationSelected$.next([annotations, action]); }); } diff --git a/apps/red-ui/src/app/modules/pdf-viewer/services/document-viewer.service.ts b/apps/red-ui/src/app/modules/pdf-viewer/services/document-viewer.service.ts index d39f33fb4..4e6679ea3 100644 --- a/apps/red-ui/src/app/modules/pdf-viewer/services/document-viewer.service.ts +++ b/apps/red-ui/src/app/modules/pdf-viewer/services/document-viewer.service.ts @@ -1,18 +1,18 @@ import { effect, inject, Injectable, Signal, signal } from '@angular/core'; +import { toObservable } from '@angular/core/rxjs-interop'; +import { ActivatedRoute } from '@angular/router'; +import { log } from '@iqser/common-ui/lib/utils'; import { Core } from '@pdftron/webviewer'; +import { RotationType, RotationTypes } from '@red/domain'; +import { UserPreferenceService } from '@users/user-preference.service'; import { NGXLogger } from 'ngx-logger'; import { BehaviorSubject, fromEvent, Observable } from 'rxjs'; import { filter, tap } from 'rxjs/operators'; -import { ActivatedRoute } from '@angular/router'; -import { PdfViewer } from './pdf-viewer.service'; -import { UserPreferenceService } from '@users/user-preference.service'; -import { log } from '@iqser/common-ui/lib/utils'; -import { stopAndPrevent, stopAndPreventIfNotAllowed } from '../utils/functions'; -import { RotationType, RotationTypes } from '@red/domain'; import { AnnotationToolNames } from '../utils/constants'; -import { toObservable } from '@angular/core/rxjs-interop'; -import DocumentViewer = Core.DocumentViewer; +import { stopAndPrevent, stopAndPreventIfNotAllowed } from '../utils/functions'; +import { PdfViewer } from './pdf-viewer.service'; import Color = Core.Annotations.Color; +import DocumentViewer = Core.DocumentViewer; import Quad = Core.Math.Quad; @Injectable() diff --git a/apps/red-ui/src/app/modules/pdf-viewer/services/pdf-viewer.service.ts b/apps/red-ui/src/app/modules/pdf-viewer/services/pdf-viewer.service.ts index 40944b5ba..0c4cbb236 100644 --- a/apps/red-ui/src/app/modules/pdf-viewer/services/pdf-viewer.service.ts +++ b/apps/red-ui/src/app/modules/pdf-viewer/services/pdf-viewer.service.ts @@ -1,26 +1,26 @@ import { DestroyRef, inject, Injectable, signal, Signal } from '@angular/core'; -import WebViewer, { Core, WebViewerInstance, WebViewerOptions } from '@pdftron/webviewer'; -import { ErrorService, getConfig } from '@iqser/common-ui'; -import { AppConfig, File, IHeaderElement } from '@red/domain'; +import { takeUntilDestroyed, toObservable, toSignal } from '@angular/core/rxjs-interop'; import { ActivatedRoute } from '@angular/router'; -import { map, startWith } from 'rxjs/operators'; -import { combineLatest, fromEvent, Observable } from 'rxjs'; -import { NGXLogger } from 'ngx-logger'; -import { DISABLED_HOTKEYS, DOCUMENT_LOADING_ERROR, SEARCH_OPTIONS, USELESS_ELEMENTS } from '../utils/constants'; -import { Rgb } from '../utils/types'; -import { asList } from '../utils/functions'; +import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { environment } from '@environments/environment'; +import { ErrorService, getConfig } from '@iqser/common-ui'; +import { BASE_HREF_FN, shareDistinctLast } from '@iqser/common-ui/lib/utils'; import { TranslateService } from '@ngx-translate/core'; +import WebViewer, { Core, WebViewerInstance, WebViewerOptions } from '@pdftron/webviewer'; +import { AppConfig, File, IHeaderElement } from '@red/domain'; import { LicenseService } from '@services/license.service'; import { UserPreferenceService } from '@users/user-preference.service'; -import { environment } from '@environments/environment'; -import { takeUntilDestroyed, toObservable, toSignal } from '@angular/core/rxjs-interop'; -import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; -import { BASE_HREF_FN, shareDistinctLast } from '@iqser/common-ui/lib/utils'; -import TextTool = Core.Tools.TextTool; +import { NGXLogger } from 'ngx-logger'; +import { combineLatest, fromEvent, Observable } from 'rxjs'; +import { map, startWith } from 'rxjs/operators'; +import { DISABLED_HOTKEYS, DOCUMENT_LOADING_ERROR, SEARCH_OPTIONS, USELESS_ELEMENTS } from '../utils/constants'; +import { asList } from '../utils/functions'; +import { Rgb } from '../utils/types'; import Annotation = Core.Annotations.Annotation; import TextHighlightAnnotation = Core.Annotations.TextHighlightAnnotation; import DocumentViewer = Core.DocumentViewer; import Quad = Core.Math.Quad; +import TextTool = Core.Tools.TextTool; @Injectable() export class PdfViewer { @@ -40,6 +40,7 @@ export class PdfViewer { }, }; readonly #destroyRef = inject(DestroyRef); + readonly #logger = inject(NGXLogger); readonly #totalPages = signal(0); readonly currentPage$ = inject(ActivatedRoute).queryParamMap.pipe( map(params => Number(params.get('page') ?? '1')), @@ -118,6 +119,7 @@ export class PdfViewer { resetAnnotationActions() { if (this.#instance.UI.annotationPopup.getItems().length) { + this.#logger.info('[PDF] Reset annotation actions'); this.#instance.UI.annotationPopup.update([]); } } diff --git a/apps/red-ui/src/assets/icons/general/logo.svg b/apps/red-ui/src/assets/icons/general/logo.svg index cca50edd0..981385375 100644 --- a/apps/red-ui/src/assets/icons/general/logo.svg +++ b/apps/red-ui/src/assets/icons/general/logo.svg @@ -1,5 +1,5 @@ - @@ -8,5 +8,5 @@ s-1.904-4.254-4.254-4.254H28.843H15.793H4.254C1.904,73.401,0,71.496,0,69.146c0-2.349,1.904-4.254,4.254-4.254h24.59h41.062 c2.349,0,4.255-1.904,4.255-4.254s-1.906-4.254-4.255-4.254H28.843H4.254C1.904,56.385,0,54.48,0,52.13 c0-2.349,1.904-4.254,4.254-4.254h11.539h13.051H52.6c2.349,0,4.254-1.905,4.254-4.254c0-2.35-1.904-4.254-4.254-4.254H28.843 - h-7.283c-2.349,0-4.254-1.905-4.254-4.254c0-2.349,1.904-4.254,4.254-4.254h7.283V14.712C59.063,14.712,74.16,0,74.16,0z" /> + h-7.283c-2.349,0-4.254-1.905-4.254-4.254c0-2.349,1.904-4.254,4.254-4.254h7.283V14.712C59.063,14.712,74.16,0,74.16,0z"/> diff --git a/libs/common-ui b/libs/common-ui index c9abddb30..21d387912 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit c9abddb3017082bb169ef6da2c1a63b0b3cdf837 +Subproject commit 21d387912ca7788f4dc9675edca1c0cdc40e8bac