From f00a92a5eabfe9bf993faf996c0fb2a04a973c86 Mon Sep 17 00:00:00 2001 From: Nicoleta Panaghiu Date: Wed, 16 Oct 2024 13:46:19 +0300 Subject: [PATCH] RED-10139: rid file-preview module of anything resembling getters. --- .../user-profile-screen.component.ts | 5 +- .../file-workload.component.html | 14 +-- .../file-workload/file-workload.component.ts | 35 ++++---- .../annotation-actions.component.ts | 2 +- .../annotation-card.component.html | 34 ++++---- .../annotation-card.component.ts | 15 +++- .../annotation-wrapper.component.html | 2 +- .../annotation-wrapper.component.ts | 2 + .../document-info.component.html | 16 ++-- .../document-info/document-info.component.ts | 5 +- ...-structured-component-value.component.html | 2 +- ...le-structured-component-value.component.ts | 24 +++--- .../file-workload.component.html | 2 +- .../page-indicator.component.html | 16 ++-- .../page-indicator.component.ts | 60 +++++++------ .../components/pages/pages.component.html | 17 ++-- .../components/pages/pages.component.ts | 25 +----- .../selected-annotations-list.component.html | 4 +- .../selected-annotations-list.component.ts | 11 ++- ...ctured-component-management.component.html | 2 +- ...ructured-component-management.component.ts | 29 +++---- .../add-hint-dialog.component.html | 4 +- .../add-hint-dialog.component.ts | 49 +++++------ .../change-legal-basis-dialog.component.html | 2 +- .../change-legal-basis-dialog.component.ts | 5 +- .../add-annotation-dialog.component.html | 2 +- .../add-annotation-dialog.component.ts | 20 +++-- .../edit-annotation-dialog.component.html | 2 +- .../edit-annotation-dialog.component.ts | 31 +++---- .../remove-annotation-dialog.component.html | 2 +- .../remove-annotation-dialog.component.ts | 9 +- .../revert-value-dialog.component.ts | 3 +- .../edit-redaction-dialog.component.html | 8 +- .../edit-redaction-dialog.component.ts | 80 +++++++++-------- .../force-annotation-dialog.component.html | 2 +- .../force-annotation-dialog.component.ts | 17 ++-- .../highlight-action-dialog.component.html | 7 +- .../highlight-action-dialog.component.ts | 3 + ...rectangle-annotation-dialog.component.html | 2 +- .../rectangle-annotation-dialog.component.ts | 7 +- ...edact-recommendation-dialog.component.html | 2 +- .../redact-recommendation-dialog.component.ts | 45 +++++----- .../redact-text-dialog.component.html | 4 +- .../redact-text-dialog.component.ts | 85 ++++++++++--------- .../remove-redaction-dialog.component.ts | 39 +++------ .../resize-redaction-dialog.component.html | 4 +- .../resize-redaction-dialog.component.ts | 38 ++++----- .../file-preview-screen.component.html | 11 +-- .../services/annotation-processing.service.ts | 5 +- .../services/file-data.service.ts | 4 +- .../services/file-preview-state.service.ts | 25 +++--- .../pdf-annotation-actions.service.ts | 4 +- apps/red-ui/src/app/utils/functions.ts | 6 -- libs/common-ui | 2 +- 54 files changed, 402 insertions(+), 449 deletions(-) diff --git a/apps/red-ui/src/app/modules/account/screens/user-profile/user-profile-screen/user-profile-screen.component.ts b/apps/red-ui/src/app/modules/account/screens/user-profile/user-profile-screen/user-profile-screen.component.ts index 63666e80a..5594d16dc 100644 --- a/apps/red-ui/src/app/modules/account/screens/user-profile/user-profile-screen/user-profile-screen.component.ts +++ b/apps/red-ui/src/app/modules/account/screens/user-profile/user-profile-screen/user-profile-screen.component.ts @@ -22,8 +22,7 @@ import { MatFormField } from '@angular/material/form-field'; import { MatOption, MatSelect, MatSelectTrigger } from '@angular/material/select'; import { MatSlideToggle } from '@angular/material/slide-toggle'; import { PdfViewer } from '../../../../pdf-viewer/services/pdf-viewer.service'; -import { formControlToSignal } from '@utils/functions'; -import { AsControl } from '@common-ui/utils'; +import { AsControl, formValueToSignal } from '@common-ui/utils'; interface UserProfileForm { email: string; @@ -59,7 +58,7 @@ export class UserProfileScreenComponent extends BaseFormComponent { readonly profileKeys = ['email', 'firstName', 'lastName']; readonly languages = this._translateService.langs; - readonly language = formControlToSignal(this.form.controls.language); + readonly language = formValueToSignal(this.form.controls.language); readonly languageSelectLabel = computed(() => this.translations[this.language()]); constructor( diff --git a/apps/red-ui/src/app/modules/dossier-overview/components/table-item/file-workload/file-workload.component.html b/apps/red-ui/src/app/modules/dossier-overview/components/table-item/file-workload/file-workload.component.html index 18a3391fa..2d9cfd923 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/components/table-item/file-workload/file-workload.component.html +++ b/apps/red-ui/src/app/modules/dossier-overview/components/table-item/file-workload/file-workload.component.html @@ -1,19 +1,19 @@
- + - - - - - + + + + -
diff --git a/apps/red-ui/src/app/modules/dossier-overview/components/table-item/file-workload/file-workload.component.ts b/apps/red-ui/src/app/modules/dossier-overview/components/table-item/file-workload/file-workload.component.ts index e28112268..d5351a840 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/components/table-item/file-workload/file-workload.component.ts +++ b/apps/red-ui/src/app/modules/dossier-overview/components/table-item/file-workload/file-workload.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; +import { ChangeDetectionStrategy, Component, computed, input, Input, OnInit } from '@angular/core'; import { annotationDefaultColorConfig, DefaultBasedColorType, File } from '@red/domain'; import { DossiersService } from '@services/dossiers/dossiers.service'; import { DefaultColorsService } from '@services/entity-services/default-colors.service'; @@ -21,13 +21,27 @@ import { MatIcon } from '@angular/material/icon'; }) export class FileWorkloadComponent implements OnInit { #dossierTemplateId: string; - @Input() file: File; + file = input(); imageColor$: Observable; updatedColor$: Observable; analysisColor$: Observable; hintColor$: Observable; redactionColor$: Observable; + readonly updated = computed( + () => this.file().hasUpdates && this.file().assignee === this._userService.currentUser.id && !this.file().isApproved, + ); + + readonly noWorkloadItems = computed( + () => + !this.updated() && + !this.file().analysisRequired && + !this.file().hasRedactions && + !this.file().hasImages && + !this.file().hintsOnly && + !this.file().hasAnnotationComments, + ); + constructor( private readonly _userService: UserService, private readonly _defaultColorsService: DefaultColorsService, @@ -35,23 +49,8 @@ export class FileWorkloadComponent implements OnInit { private readonly _dictionariesMapService: DictionariesMapService, ) {} - get updated(): boolean { - return this.file.hasUpdates && this.file.assignee === this._userService.currentUser.id && !this.file.isApproved; - } - - get noWorkloadItems(): boolean { - return ( - !this.updated && - !this.file.analysisRequired && - !this.file.hasRedactions && - !this.file.hasImages && - !this.file.hintsOnly && - !this.file.hasAnnotationComments - ); - } - ngOnInit() { - this.#dossierTemplateId = this._dossiersService.find(this.file.dossierId).dossierTemplateId; + this.#dossierTemplateId = this._dossiersService.find(this.file().dossierId).dossierTemplateId; this.updatedColor$ = this.#getDefaultColor$('updated'); this.analysisColor$ = this.#getDefaultColor$('analysis'); this.hintColor$ = this.#getDefaultColor$('hint'); diff --git a/apps/red-ui/src/app/modules/file-preview/components/annotation-actions/annotation-actions.component.ts b/apps/red-ui/src/app/modules/file-preview/components/annotation-actions/annotation-actions.component.ts index ae64768f4..11746d155 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/annotation-actions/annotation-actions.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/annotation-actions/annotation-actions.component.ts @@ -60,7 +60,7 @@ export class AnnotationActionsComponent { AnnotationPermissions.forUser( this._permissionsService.isApprover(this._state.dossier()), this.annotations(), - this._state.dictionaries, + untracked(this._state.dictionaries), this._iqserPermissionsService, this._state.file().excludedFromAutomaticAnalysis, ), diff --git a/apps/red-ui/src/app/modules/file-preview/components/annotation-card/annotation-card.component.html b/apps/red-ui/src/app/modules/file-preview/components/annotation-card/annotation-card.component.html index 507ffe447..698c9a26f 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/annotation-card/annotation-card.component.html +++ b/apps/red-ui/src/app/modules/file-preview/components/annotation-card/annotation-card.component.html @@ -1,44 +1,42 @@
- {{ annotation.superTypeLabel | translate }} + {{ annotation().superTypeLabel | translate }}   - - {{ 'annotation.pending' | translate }} + + {{ 'annotation().pending' | translate }}
-
+
- {{ annotation.descriptor | translate }}{{ descriptor() | translate }}: - {{ annotation.typeLabel }} + {{ annotation().typeLabel }}
-
- : {{ annotation.shortContent }} +
+ : {{ annotation().shortContent }}
-
- : {{ annotation.color }} +
+ : {{ annotation().color }}
-
- : {{ annotation.width }}x{{ annotation.height }} px +
+ : {{ width() }}x{{ height() }} px
- +
diff --git a/apps/red-ui/src/app/modules/file-preview/components/annotation-card/annotation-card.component.ts b/apps/red-ui/src/app/modules/file-preview/components/annotation-card/annotation-card.component.ts index 60d8a9d39..3d3d18392 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/annotation-card/annotation-card.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/annotation-card/annotation-card.component.ts @@ -1,5 +1,5 @@ import { NgIf, UpperCasePipe } from '@angular/common'; -import { Component, Input } from '@angular/core'; +import { Component, computed, input } from '@angular/core'; import { RoundCheckboxComponent } from '@common-ui/inputs/round-checkbox/round-checkbox.component'; import { getConfig, IqserDenyDirective } from '@iqser/common-ui'; import { AnnotationWrapper } from '@models/file/annotation.wrapper'; @@ -20,8 +20,17 @@ export class AnnotationCardComponent { protected readonly roles = Roles; protected readonly annotationTypesTranslations = annotationTypesTranslations; protected readonly isDocumine = getConfig().IS_DOCUMINE; - @Input() annotation: AnnotationWrapper; - @Input() isSelected = false; + annotation = input(); + isSelected = input(false); + + readonly isEarmark = computed(() => this.annotation().isEarmark); + readonly iconShape = computed(() => this.annotation().iconShape); + readonly width = computed(() => this.annotation().width); + readonly height = computed(() => this.annotation().height); + readonly isHint = computed(() => this.annotation().isHint); + readonly isSkipped = computed(() => this.annotation().isSkipped); + readonly isIgnoredHint = computed(() => this.annotation().isIgnoredHint); + readonly descriptor = computed(() => this.annotation().descriptor); constructor(readonly multiSelectService: MultiSelectService) {} } diff --git a/apps/red-ui/src/app/modules/file-preview/components/annotation-wrapper/annotation-wrapper.component.html b/apps/red-ui/src/app/modules/file-preview/components/annotation-wrapper/annotation-wrapper.component.html index 8c22e3273..32b0dd320 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/annotation-wrapper/annotation-wrapper.component.html +++ b/apps/red-ui/src/app/modules/file-preview/components/annotation-wrapper/annotation-wrapper.component.html @@ -8,7 +8,7 @@ matTooltipPosition="above" > - @if (!annotation().item.isEarmark) { + @if (!isEarmark()) {
@if (!annotation().item.pending) {
this.annotation().item.isEarmark); + constructor() { effect(() => { this.active = this.annotation().isSelected; diff --git a/apps/red-ui/src/app/modules/file-preview/components/document-info/document-info.component.html b/apps/red-ui/src/app/modules/file-preview/components/document-info/document-info.component.html index 8aff704ff..62e9e3797 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/document-info/document-info.component.html +++ b/apps/red-ui/src/app/modules/file-preview/components/document-info/document-info.component.html @@ -23,7 +23,9 @@
{{ attr.label }}:
-
{{ attr.value ? (isDate(attr) ? (attr.value | date : 'd MMM yyyy') : attr.value) : '-' }}
+
+ {{ attr.value ? (attr.type === FileAttributeConfigTypes.DATE ? (attr.value | date: 'd MMM yyyy') : attr.value) : '-' }} +
@@ -31,23 +33,23 @@
- {{ 'file-preview.tabs.document-info.details.pages' | translate : { pages: _state.file().numberOfPages } }} + {{ 'file-preview.tabs.document-info.details.pages' | translate: { pages: _state.file().numberOfPages } }}
-
+
- +
-
+
- +
diff --git a/apps/red-ui/src/app/modules/file-preview/components/document-info/document-info.component.ts b/apps/red-ui/src/app/modules/file-preview/components/document-info/document-info.component.ts index fe3d55f0c..4e1d16066 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/document-info/document-info.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/document-info/document-info.component.ts @@ -43,6 +43,7 @@ export class DocumentInfoComponent extends ContextComponent { this._fileAttributesConfig(); return this._attributes(); }); + protected readonly FileAttributeConfigTypes = FileAttributeConfigTypes; constructor( readonly permissionsService: PermissionsService, @@ -56,10 +57,6 @@ export class DocumentInfoComponent extends ContextComponent { this._dialogService.openDialog('documentInfo', this._state.file()); } - isDate(attribute: FileAttribute) { - return attribute.type === FileAttributeConfigTypes.DATE; - } - closeView() { this._documentInfoService.hide(); setLocalStorageDataByFileId(this._state.fileId, 'show-document-info', false); diff --git a/apps/red-ui/src/app/modules/file-preview/components/editable-structured-component-value/editable-structured-component-value.component.html b/apps/red-ui/src/app/modules/file-preview/components/editable-structured-component-value/editable-structured-component-value.component.html index 725693fd3..ba7b1109d 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/editable-structured-component-value/editable-structured-component-value.component.html +++ b/apps/red-ui/src/app/modules/file-preview/components/editable-structured-component-value/editable-structured-component-value.component.html @@ -54,7 +54,7 @@
diff --git a/apps/red-ui/src/app/modules/file-preview/components/editable-structured-component-value/editable-structured-component-value.component.ts b/apps/red-ui/src/app/modules/file-preview/components/editable-structured-component-value/editable-structured-component-value.component.ts index 128482377..3a42118b1 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/editable-structured-component-value/editable-structured-component-value.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/editable-structured-component-value/editable-structured-component-value.component.ts @@ -48,7 +48,16 @@ export class EditableStructuredComponentValueComponent implements OnInit { protected entryLabel: string; protected editing = false; protected initialEntry: IComponentLogEntry; + readonly disabled = computed(() => { + for (let i = 0; i < this.currentEntry().componentValues.length; i++) { + if (this.currentEntry().componentValues[i].value !== this.initialEntry.componentValues[i]?.value) { + return false; + } + } + return this.currentEntry().componentValues.length === this.initialEntry.componentValues.length; + }); protected readonly iconButtonTypes = IconButtonTypes; + readonly #initialEntry = computed(() => JSON.parse(JSON.stringify(this.entry()))); constructor( readonly helpModeService: HelpModeService, @@ -56,26 +65,13 @@ export class EditableStructuredComponentValueComponent implements OnInit { private readonly _state: FilePreviewStateService, ) {} - get disabled() { - for (let i = 0; i < this.currentEntry().componentValues.length; i++) { - if (this.currentEntry().componentValues[i].value !== this.initialEntry.componentValues[i]?.value) { - return false; - } - } - return this.currentEntry().componentValues.length === this.initialEntry.componentValues.length; - } - - get #initialEntry() { - return JSON.parse(JSON.stringify(this.entry())); - } - ngOnInit() { this.currentEntry = signal(this.entry()); this.reset(); } reset() { - this.initialEntry = this.#initialEntry; + this.initialEntry = this.#initialEntry(); this.entryLabel = this.parseName(this.currentEntry().name); this.deselect(); } diff --git a/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.html b/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.html index 47d3dc13b..5bab0e988 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.html +++ b/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.html @@ -172,7 +172,7 @@ translate="file-preview.tabs.annotations.reset" > {{ 'file-preview.tabs.annotations.the-filters' | translate }} - } @else if (state.componentReferenceIds?.length === 0) { + } @else if (state.componentReferenceIdsSignal()?.length === 0) { {{ 'file-preview.tabs.annotations.no-annotations' | translate }} } } diff --git a/apps/red-ui/src/app/modules/file-preview/components/page-indicator/page-indicator.component.html b/apps/red-ui/src/app/modules/file-preview/components/page-indicator/page-indicator.component.html index 79da8fcd1..f55d40c01 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/page-indicator/page-indicator.component.html +++ b/apps/red-ui/src/app/modules/file-preview/components/page-indicator/page-indicator.component.html @@ -1,19 +1,19 @@
- + -
{{ number }}
+
{{ pageNumber() }}
-
+
-
+
diff --git a/apps/red-ui/src/app/modules/file-preview/components/page-indicator/page-indicator.component.ts b/apps/red-ui/src/app/modules/file-preview/components/page-indicator/page-indicator.component.ts index 47002e55c..318eec24e 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/page-indicator/page-indicator.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/page-indicator/page-indicator.component.ts @@ -1,4 +1,4 @@ -import { Component, effect, EventEmitter, inject, Input, OnChanges, Output } from '@angular/core'; +import { Component, computed, effect, inject, input, output, untracked } from '@angular/core'; import { PermissionsService } from '@services/permissions.service'; import { ViewedPagesService } from '@services/files/viewed-pages.service'; import { FilePreviewStateService } from '../../services/file-preview-state.service'; @@ -12,6 +12,9 @@ import { PdfViewer } from '../../../pdf-viewer/services/pdf-viewer.service'; import { NGXLogger } from 'ngx-logger'; import { AsyncPipe, NgIf } from '@angular/common'; import { MatIcon } from '@angular/material/icon'; +import { MultiSelectService } from '../../services/multi-select.service'; +import { AnnotationsListingService } from '../../services/annotations-listing.service'; +import { toSignal } from '@angular/core/rxjs-interop'; @Component({ selector: 'redaction-page-indicator', @@ -20,16 +23,26 @@ import { MatIcon } from '@angular/material/icon'; standalone: true, imports: [NgIf, AsyncPipe, MatIcon], }) -export class PageIndicatorComponent implements OnChanges { +export class PageIndicatorComponent { + readonly #multiSelectService = inject(MultiSelectService); + readonly #listingService = inject(AnnotationsListingService); readonly #config = getConfig(); readonly #logger = inject(NGXLogger); - @Input({ required: true }) number: number; - @Input() showDottedIcon = false; - @Input() activeSelection = false; - @Input() read = false; - @Output() readonly pageSelected = new EventEmitter(); + readonly pageNumber = input.required(); + readonly viewedPages = input.required(); + readonly showDottedIcon = computed(() => this._state.file().excludedPages.includes(this.pageNumber())); + readonly selectedLength = toSignal(this.#listingService.selectedLength$); + readonly activeSelection = computed( + () => + this.#multiSelectService.active() && + this.selectedLength() && + this.#listingService.selected.find(p => p.pageNumber === this.pageNumber()), + ); + readonly read = computed(() => this.viewedPages().find(p => p.page === this.pageNumber())); + readonly pageSelected = output(); pageReadTimeout: number = null; readonly assigneeChanged$: Observable; + isActive = computed(() => untracked(this.pageNumber) === this._pdf.currentPage()); constructor( private readonly _viewedPagesService: ViewedPagesService, @@ -48,27 +61,19 @@ export class PageIndicatorComponent implements OnChanges { ); effect(() => { - if (this.isActive) { + if (this.isActive()) { this.handlePageRead(); } }); } - get isActive() { - return this.number === this._pdf.currentPage(); - } - - ngOnChanges() { - this.handlePageRead(); - } - async toggleReadState() { if (!this._permissionService.canMarkPagesAsViewed(this._state.file())) { this.#logger.info('[PAGES] Cannot toggle read state'); return; } - - if (this.read) { + const read = untracked(this.read); + if (read) { await this.#markPageUnread(); } else { await this.#markPageRead(); @@ -85,9 +90,10 @@ export class PageIndicatorComponent implements OnChanges { clearTimeout(this.pageReadTimeout); } - if (this.isActive && !this.read) { + const read = untracked(this.read); + if (this.isActive() && !read) { this.pageReadTimeout = window.setTimeout(async () => { - if (this.isActive && !this.read) { + if (this.isActive() && !read) { await this.#markPageRead(); } }, this.#config.AUTO_READ_TIME * 1000); @@ -95,19 +101,21 @@ export class PageIndicatorComponent implements OnChanges { } async #markPageRead() { - this.#logger.info('[PAGES] Mark page read', this.number); + const number = untracked(this.pageNumber); + this.#logger.info('[PAGES] Mark page read', number); const fileId = this._state.fileId; - await this._viewedPagesService.add({ page: this.number }, this._state.dossierId, fileId); - const viewedPage = new ViewedPage({ page: this.number, fileId }); + await this._viewedPagesService.add({ page: number }, this._state.dossierId, fileId); + const viewedPage = new ViewedPage({ page: number, fileId }); this._viewedPagesMapService.add(fileId, viewedPage); } async #markPageUnread() { - this.#logger.info('[PAGES] Mark page unread', this.number); + const number = untracked(this.pageNumber); + this.#logger.info('[PAGES] Mark page unread', number); const fileId = this._state.fileId; - await this._viewedPagesService.remove(this._state.dossierId, fileId, this.number); - this._viewedPagesMapService.delete(fileId, this.number); + await this._viewedPagesService.remove(this._state.dossierId, fileId, number); + this._viewedPagesMapService.delete(fileId, number); } } diff --git a/apps/red-ui/src/app/modules/file-preview/components/pages/pages.component.html b/apps/red-ui/src/app/modules/file-preview/components/pages/pages.component.html index c7515da50..feb18cc9a 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/pages/pages.component.html +++ b/apps/red-ui/src/app/modules/file-preview/components/pages/pages.component.html @@ -1,10 +1,9 @@ -
- +
+ @for (pageNumber of pages(); track pageNumber) { + + }
diff --git a/apps/red-ui/src/app/modules/file-preview/components/pages/pages.component.ts b/apps/red-ui/src/app/modules/file-preview/components/pages/pages.component.ts index 9c8725e46..4c9285154 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/pages/pages.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/pages/pages.component.ts @@ -1,14 +1,12 @@ import { AsyncPipe, NgForOf, NgIf } from '@angular/common'; -import { AfterViewInit, Component, inject, Input } from '@angular/core'; +import { AfterViewInit, Component, inject, input } from '@angular/core'; import { List } from '@iqser/common-ui/lib/utils'; -import { ViewedPage } from '@red/domain'; import { ViewedPagesMapService } from '@services/files/viewed-pages-map.service'; import scrollIntoView from 'scroll-into-view-if-needed'; import { PdfViewer } from '../../../pdf-viewer/services/pdf-viewer.service'; -import { AnnotationsListingService } from '../../services/annotations-listing.service'; import { FilePreviewStateService } from '../../services/file-preview-state.service'; -import { MultiSelectService } from '../../services/multi-select.service'; import { PageIndicatorComponent } from '../page-indicator/page-indicator.component'; +import { toSignal } from '@angular/core/rxjs-interop'; @Component({ selector: 'redaction-pages', @@ -19,11 +17,10 @@ import { PageIndicatorComponent } from '../page-indicator/page-indicator.compone }) export class PagesComponent implements AfterViewInit { readonly #state = inject(FilePreviewStateService); - readonly #multiSelectService = inject(MultiSelectService); - readonly #listingService = inject(AnnotationsListingService); protected readonly _pdf = inject(PdfViewer); - @Input({ required: true }) pages: List; + readonly pages = input.required>(); readonly viewedPages$ = inject(ViewedPagesMapService).get$(this.#state.fileId); + readonly viewedPages = toSignal(this.viewedPages$); ngAfterViewInit() { setTimeout(() => { @@ -45,18 +42,4 @@ export class PagesComponent implements AfterViewInit { pageSelectedByClick($event: number): void { this._pdf.navigateTo($event); } - - readonly trackBy = (_index: number, item: number) => item; - - pageHasSelection(page: number) { - return this.#multiSelectService.active() && !!this.#listingService.selected.find(a => a.pageNumber === page); - } - - isPageExcluded(pageNumber: number): boolean { - return this.#state.file().excludedPages.includes(pageNumber); - } - - getViewedPage(viewedPages: ViewedPage[], pageNumber: number) { - return viewedPages.find(p => p.page === pageNumber); - } } diff --git a/apps/red-ui/src/app/modules/file-preview/components/selected-annotations-list/selected-annotations-list.component.html b/apps/red-ui/src/app/modules/file-preview/components/selected-annotations-list/selected-annotations-list.component.html index 63961a98f..9781e0e71 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/selected-annotations-list/selected-annotations-list.component.html +++ b/apps/red-ui/src/app/modules/file-preview/components/selected-annotations-list/selected-annotations-list.component.html @@ -1,5 +1,5 @@ - +
    -
  • {{ value }}
  • +
  • {{ value }}
diff --git a/apps/red-ui/src/app/modules/file-preview/components/selected-annotations-list/selected-annotations-list.component.ts b/apps/red-ui/src/app/modules/file-preview/components/selected-annotations-list/selected-annotations-list.component.ts index b3663cc17..81528a101 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/selected-annotations-list/selected-annotations-list.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/selected-annotations-list/selected-annotations-list.component.ts @@ -1,4 +1,4 @@ -import { Component, Input } from '@angular/core'; +import { Component, computed, input } from '@angular/core'; import { CdkFixedSizeVirtualScroll, CdkVirtualForOf, CdkVirtualScrollViewport } from '@angular/cdk/scrolling'; import { NgStyle } from '@angular/common'; @@ -13,10 +13,9 @@ const MAX_ITEMS_DISPLAY = 5; styleUrl: './selected-annotations-list.component.scss', }) export class SelectedAnnotationsListComponent { - @Input({ required: true }) values: string[]; + values = input.required(); + readonly redactedTextsAreaHeight = computed(() => + this.values.length <= MAX_ITEMS_DISPLAY ? LIST_ITEM_SIZE * this.values.length : LIST_ITEM_SIZE * MAX_ITEMS_DISPLAY, + ); protected readonly LIST_ITEM_SIZE = LIST_ITEM_SIZE; - - get redactedTextsAreaHeight() { - return this.values.length <= MAX_ITEMS_DISPLAY ? LIST_ITEM_SIZE * this.values.length : LIST_ITEM_SIZE * MAX_ITEMS_DISPLAY; - } } diff --git a/apps/red-ui/src/app/modules/file-preview/components/structured-component-management/structured-component-management.component.html b/apps/red-ui/src/app/modules/file-preview/components/structured-component-management/structured-component-management.component.html index faa6c3677..d94d18d3c 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/structured-component-management/structured-component-management.component.html +++ b/apps/red-ui/src/app/modules/file-preview/components/structured-component-management/structured-component-management.component.html @@ -16,7 +16,7 @@ (); + dictionaries = input(); + editableComponents = viewChild>('editableComponent'); + canEdit = computed(() => this.file().workflowStatus !== WorkflowFileStatuses.APPROVED); protected readonly componentLogData = signal(undefined); protected readonly componentLogData$ = toObservable(this.componentLogData); protected readonly iconButtonTypes = IconButtonTypes; protected displayedComponents$: Observable; - @Input() file: File; - @Input() dictionaries: Dictionary[]; - @ViewChildren('editableComponent') editableComponents: List; constructor( private readonly _componentLogService: ComponentLogService, @@ -42,17 +43,13 @@ export class StructuredComponentManagementComponent implements OnInit { }); } - get canEdit() { - return this.file.workflowStatus !== WorkflowFileStatuses.APPROVED; - } - async ngOnInit(): Promise { await this.#loadData(); this.displayedComponents$ = this.#displayedComponents$(); } deselectLast() { - const lastSelected = this.editableComponents.find(c => c.selected); + const lastSelected = this.editableComponents().find(c => c.selected); if (lastSelected) { lastSelected.deselect(); } @@ -61,7 +58,9 @@ export class StructuredComponentManagementComponent implements OnInit { async revertOverride(originalKey: string) { this._loadingService.start(); await firstValueFrom( - this._componentLogService.revertOverride(this.file.dossierTemplateId, this.file.dossierId, this.file.fileId, [originalKey]), + this._componentLogService.revertOverride(this.file().dossierTemplateId, this.file().dossierId, this.file().fileId, [ + originalKey, + ]), ); await this.#loadData(); } @@ -69,7 +68,7 @@ export class StructuredComponentManagementComponent implements OnInit { async overrideValue(componentLogEntry: IComponentLogEntry) { this._loadingService.start(); await firstValueFrom( - this._componentLogService.override(this.file.dossierTemplateId, this.file.dossierId, this.file.fileId, componentLogEntry), + this._componentLogService.override(this.file().dossierTemplateId, this.file().dossierId, this.file().fileId, componentLogEntry), ); await this.#loadData(); } @@ -84,10 +83,10 @@ export class StructuredComponentManagementComponent implements OnInit { async #loadData(): Promise { const componentLogData = await firstValueFrom( this._componentLogService.getComponentLogData( - this.file.dossierTemplateId, - this.file.dossierId, - this.file.fileId, - this.dictionaries, + this.file().dossierTemplateId, + this.file().dossierId, + this.file().fileId, + this.dictionaries(), ), ); this.#computeFilters(componentLogData); diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/add-hint-dialog/add-hint-dialog.component.html b/apps/red-ui/src/app/modules/file-preview/dialogs/add-hint-dialog/add-hint-dialog.component.html index 1b8ba9d00..62c6eefad 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/add-hint-dialog/add-hint-dialog.component.html +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/add-hint-dialog/add-hint-dialog.component.html @@ -67,7 +67,7 @@ - {{ displayedDictionaryLabel }} + {{ displayedDictionaryLabel() }} 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 2826b01a4..dbaee8fc6 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 @@ -1,6 +1,5 @@ import { NgClass, NgForOf, NgIf, NgStyle } from '@angular/common'; -import { Component, OnInit } from '@angular/core'; -import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { Component, computed, effect, OnInit } from '@angular/core'; import { FormBuilder, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms'; import { MatDialogClose } from '@angular/material/dialog'; import { MatFormField } from '@angular/material/form-field'; @@ -24,10 +23,10 @@ import { DictionaryService } from '@services/entity-services/dictionary.service' import { Roles } from '@users/roles'; import { UserPreferenceService } from '@users/user-preference.service'; import { calcTextWidthInPixels, stringToBoolean } from '@utils/functions'; -import { tap } from 'rxjs/operators'; import { SystemDefaultOption, SystemDefaults } from '../../../account/utils/dialog-defaults'; import { getRedactOrHintOptions } from '../../utils/dialog-options'; import { AddHintData, AddHintResult, RedactOrHintOption, RedactOrHintOptions } from '../../utils/dialog-types'; +import { formValueToSignal } from '@common-ui/utils'; const MAXIMUM_TEXT_AREA_WIDTH = 421; @@ -67,11 +66,22 @@ export class AddHintDialogComponent extends IqserDialogComponent { + if (this.dictionary()) { + return this.dictionaries.find(d => d.type === this.dictionary())?.label ?? null; + } + return null; + }); + + _disabled = computed(() => this.#isRss || !this.dictionary()); + readonly optionValue = formValueToSignal>(this.form.get('option')); + constructor( private readonly _activeDossiersService: ActiveDossiersService, private readonly _dictionaryService: DictionaryService, @@ -80,7 +90,7 @@ export class AddHintDialogComponent extends IqserDialogComponent) => { - this.dictionaryRequest = option.value === RedactOrHintOptions.IN_DOSSIER; - this.#setDictionaries(); - this.#resetValues(); - }), - takeUntilDestroyed(), - ) - .subscribe(); + effect(() => { + this.dictionaryRequest = this.optionValue().value === RedactOrHintOptions.IN_DOSSIER; + this.#setDictionaries(); + this.#resetValues(); + }); } toggleEditingSelectedText() { @@ -120,14 +123,6 @@ export class AddHintDialogComponent extends IqserDialogComponent d.type === dictType)?.label ?? null; - } - return null; - } - get applyToAll() { return this.isSystemDefault || this._userPreferences.getAddHintDefaultExtraOption() === 'undefined' ? this.data.applyToAllDossiers ?? true @@ -150,10 +145,6 @@ export class AddHintDialogComponent extends IqserDialogComponent { this.#setDictionaries(); this.#resetValues(); diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/change-legal-basis-dialog/change-legal-basis-dialog.component.html b/apps/red-ui/src/app/modules/file-preview/dialogs/change-legal-basis-dialog/change-legal-basis-dialog.component.html index 50005eae3..645d7d725 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/change-legal-basis-dialog/change-legal-basis-dialog.component.html +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/change-legal-basis-dialog/change-legal-basis-dialog.component.html @@ -28,7 +28,7 @@
-
+
diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/change-legal-basis-dialog/change-legal-basis-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/change-legal-basis-dialog/change-legal-basis-dialog.component.ts index 457bd752c..2da3d8bfe 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/change-legal-basis-dialog/change-legal-basis-dialog.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/change-legal-basis-dialog/change-legal-basis-dialog.component.ts @@ -34,6 +34,7 @@ import { LegalBasisOption } from '../../utils/dialog-types'; }) export class ChangeLegalBasisDialogComponent extends BaseDialogComponent implements OnInit { legalOptions: LegalBasisOption[] = []; + allRectangles = this._data.annotations.reduce((acc, a) => acc && a.AREA, true); constructor( private readonly _justificationsService: JustificationsService, @@ -44,10 +45,6 @@ export class ChangeLegalBasisDialogComponent extends BaseDialogComponent impleme this.form = this._getForm(); } - get allRectangles(): boolean { - return this._data.annotations.reduce((acc, a) => acc && a.AREA, true); - } - async ngOnInit() { const data = await firstValueFrom(this._justificationsService.getForDossierTemplate(this._data.dossier.dossierTemplateId)); 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 index b00923b5d..144024ade 100644 --- 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 @@ -13,7 +13,7 @@ - {{ displayedDictionaryLabel }} + {{ displayedDictionaryLabel() }} { + const dictType = this.dictionaryType(); + if (dictType) { + return this.dictionaries.find(d => d.type === dictType)?.label ?? null; + } + return null; + }); constructor( private readonly _dictionaryService: DictionaryService, @@ -46,14 +56,6 @@ export class AddAnnotationDialogComponent super(); } - get displayedDictionaryLabel() { - const dictType = this.form.controls.dictionary.value; - if (dictType) { - return this.dictionaries.find(d => d.type === dictType)?.label ?? null; - } - return null; - } - get disabled() { return !this.form.controls.dictionary.value; } diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/edit-annotation-dialog/edit-annotation-dialog.component.html b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/edit-annotation-dialog/edit-annotation-dialog.component.html index 5f142c981..195b9b756 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/edit-annotation-dialog/edit-annotation-dialog.component.html +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/edit-annotation-dialog/edit-annotation-dialog.component.html @@ -12,7 +12,7 @@ - {{ displayedDictionaryLabel }} + {{ displayedDictionaryLabel() }} annotation.isSkipped || annotation.isRedacted); + selectedDictionaryType = formValueToSignal(this.form.get('type')); + + displayedDictionaryLabel = computed(() => { + const selectedDictionaryType = this.selectedDictionaryType(); + if (selectedDictionaryType) { + return this.dictionaries.find(d => d.type === selectedDictionaryType)?.label ?? null; + } + return null; + }); constructor( private readonly _activeDossiersService: ActiveDossiersService, @@ -60,25 +71,11 @@ export class EditAnnotationDialogComponent private readonly _formBuilder: FormBuilder, ) { super(); - this.#dossier = this._activeDossiersService.find(this.data.dossierId); const annotations = this.data.annotations; this.redactedTexts = annotations.map(annotation => annotation.value); - this.form = this.#getForm(); this.initialFormValue = JSON.parse(JSON.stringify(this.form.getRawValue())); } - get displayedDictionaryLabel() { - const selectedDictionaryType = this.form.get('type').value; - if (selectedDictionaryType) { - return this.dictionaries.find(d => d.type === selectedDictionaryType)?.label ?? null; - } - return null; - } - - get showList() { - return this.data.annotations.every(annotation => annotation.isSkipped || annotation.isRedacted); - } - async ngOnInit(): Promise { this.#setTypes(); } 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 index 42b4689a4..b81d9f6ee 100644 --- 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 @@ -20,7 +20,7 @@
  • {{ - (isFalsePositive + (isFalsePositive() ? 'remove-annotation.dialog.content.list-item-false-positive' : 'remove-annotation.dialog.content.list-item' ) 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 6571d4ecc..43438271c 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,6 +1,6 @@ import { CdkFixedSizeVirtualScroll, CdkVirtualForOf } from '@angular/cdk/scrolling'; import { NgIf, NgStyle } from '@angular/common'; -import { Component } from '@angular/core'; +import { Component, computed } from '@angular/core'; import { FormBuilder, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms'; import { MatDialogClose } from '@angular/material/dialog'; import { DetailsRadioOption } from '@common-ui/inputs/details-radio/details-radio-option'; @@ -17,6 +17,7 @@ import { import { TranslateModule } from '@ngx-translate/core'; import { getRemoveRedactionOptions } from '../../../utils/dialog-options'; import { RemoveAnnotationData, RemoveAnnotationOption, RemoveAnnotationOptions, RemoveAnnotationResult } from '../../../utils/dialog-types'; +import { formValueToSignal } from '@common-ui/utils'; @Component({ templateUrl: 'remove-annotation-dialog.component.html', @@ -46,6 +47,8 @@ export class RemoveAnnotationDialogComponent extends IqserDialogComponent< readonly iconButtonTypes = IconButtonTypes; readonly options: DetailsRadioOption[]; readonly redactedTexts: string[]; + readonly option = formValueToSignal>(this.form.get('option')); + readonly isFalsePositive = computed(() => this.option().value === RemoveAnnotationOptions.FALSE_POSITIVE); form!: UntypedFormGroup; @@ -56,10 +59,6 @@ export class RemoveAnnotationDialogComponent extends IqserDialogComponent< this.form = this.#getForm(); } - get isFalsePositive(): boolean { - return this.form.get('option').value.value === RemoveAnnotationOptions.FALSE_POSITIVE; - } - get #applyToAllDossiers(): boolean { const selectedOption = this.form.get('option').value.value; return selectedOption === RemoveAnnotationOptions.IN_DOSSIER || selectedOption === RemoveAnnotationOptions.FALSE_POSITIVE; diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/revert-value-dialog/revert-value-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/revert-value-dialog/revert-value-dialog.component.ts index 14fcf2201..6eb01a4a3 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/revert-value-dialog/revert-value-dialog.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/docu-mine/revert-value-dialog/revert-value-dialog.component.ts @@ -18,6 +18,7 @@ interface RevertValueResult {} }) export class RevertValueDialogComponent extends IqserDialogComponent { protected readonly entry = this.data.entry; + readonly valueDescription = this.#valueDescription; constructor(private readonly _translateService: TranslateService) { super(); @@ -26,7 +27,7 @@ export class RevertValueDialogComponent extends IqserDialogComponent${componentRuleString} ${valueDescription}`; diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/edit-redaction-dialog/edit-redaction-dialog.component.html b/apps/red-ui/src/app/modules/file-preview/dialogs/edit-redaction-dialog/edit-redaction-dialog.component.html index 55bfda05b..a9c43365b 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/edit-redaction-dialog/edit-redaction-dialog.component.html +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/edit-redaction-dialog/edit-redaction-dialog.component.html @@ -30,7 +30,7 @@ [placeholder]="isBulkEdit ? ('edit-redaction.dialog.content.unchanged' | translate) : ''" formControlName="type" > - {{ displayedDictionaryLabel }} + {{ displayedDictionaryLabel() }}
- -
+ +
this.formStatus() === 'INVALID'); + readonly dictionaryType = formValueToSignal(this.form.controls.type); + readonly reasonStatus = formStatusToSignal(this.form.controls.reason); + readonly reasonValue = formValueToSignal(this.form.controls.reason); + readonly sectionValue = formValueToSignal(this.form.controls.section); + + readonly displayedDictionaryLabel = computed(() => { + const selectedDictionaryType = this.dictionaryType(); + if (selectedDictionaryType) { + return this.typeSelectOptions.find(option => option.type === selectedDictionaryType)?.label ?? null; + } + return null; + }); + readonly reasonDisabled = computed(() => this.reasonStatus() === 'DISABLED'); + readonly hiddenReason = computed(() => this.isImage && this.reasonDisabled()); + readonly hideParagraphPlaceholder = computed( + () => this.sectionValue() !== this.initialFormValue['section'] || this.#isFieldEmpty('section'), + ); + readonly hideReasonPlaceholder = this.#hideReasonPlaceholder; + + readonly isBulkEdit = !isJustOne(this.annotations); + readonly showExtras = (this.isImage && this.isRedacted) || !(this.isImage || this.isHint); + constructor( private readonly _justificationsService: JustificationsService, private readonly _dictionaryService: DictionaryService, @@ -105,54 +130,27 @@ export class EditRedactionDialogComponent super(); } - get displayedDictionaryLabel() { - const selectedDictionaryType = this.form.controls.type.value; - if (selectedDictionaryType) { - return this.typeSelectOptions.find(option => option.type === selectedDictionaryType)?.label ?? null; - } - return null; - } - - get showExtras() { - return (this.isImage && this.isRedacted) || !(this.isImage || this.isHint); - } - get disabled() { - return ( - this.form.invalid || - (!this.isImage && this.showExtras && !this.form.controls.reason.disabled ? !this.form.controls.reason.value : false) - ); + return this.formInvalid() || (!this.isImage && this.showExtras && !this.reasonDisabled() ? !this.reasonValue() : false); } - get someSkipped() { + get #someSkipped() { return this.annotations.some(annotation => annotation.isSkipped); } - get redactBasedTypes() { + get #redactBasedTypes() { return this._dictionaryService.getRedactionTypes(this.#dossier.dossierTemplateId).map(dictionary => dictionary.type); } - get isRedactBasedType() { - return this.redactBasedTypes.includes(this.form.controls.type.value); + get #isRedactBasedType() { + return this.#redactBasedTypes.includes(this.form.controls.type.value); } - get hideReasonPlaceholder() { - return (this.hasTypeChanged && this.isRedactBasedType) || this.#isFieldEmpty('legalBasisValue'); + get #hideReasonPlaceholder() { + return (this.hasTypeChanged && this.#isRedactBasedType) || this.#isFieldEmpty('legalBasisValue'); } - get hideParagraphPlaceholder() { - return this.form.controls.section.value !== this.initialFormValue['section'] || this.#isFieldEmpty('section'); - } - - get hiddenReason() { - return this.isImage && this.form.controls.reason.disabled; - } - - get isBulkEdit() { - return this.annotations.length > 1; - } - - get sameType() { + get #sameType() { return this.annotations.every(annotation => annotation.type === this.annotations[0].type); } @@ -187,7 +185,7 @@ export class EditRedactionDialogComponent const selectedDictionaryType = this.form.controls.type.value; const initialReason = this.form.get('type').value === this.initialFormValue.type && !this.initialReasonDisabled; - if (this.redactBasedTypes.includes(selectedDictionaryType) || initialReason) { + if (this.#redactBasedTypes.includes(selectedDictionaryType) || initialReason) { this.form.controls.reason.enable(); this.hasTypeChanged = true; if (initialReason) { @@ -230,7 +228,7 @@ export class EditRedactionDialogComponent this.isImage, this.isHint, this.annotations.every(annotation => annotation.isOCR), - this.sameType ? this.annotations[0].type : null, + this.#sameType ? this.annotations[0].type : null, ); this.typeSelectOptions = this.dictionaries.map(dictionary => ({ @@ -248,10 +246,10 @@ export class EditRedactionDialogComponent #getForm() { const sameSection = this.annotations.every(annotation => annotation.section === this.annotations[0].section); return new FormGroup({ - reason: new FormControl({ value: null, disabled: this.someSkipped }), + reason: new FormControl({ value: null, disabled: this.#someSkipped }), comment: new FormControl(null), type: new FormControl({ - value: this.sameType ? this.annotations[0].type : null, + value: this.#sameType ? this.annotations[0].type : null, disabled: this.isImported, }), section: new FormControl({ value: sameSection ? this.annotations[0].section : null, disabled: this.isImported }), diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/force-redaction-dialog/force-annotation-dialog.component.html b/apps/red-ui/src/app/modules/file-preview/dialogs/force-redaction-dialog/force-annotation-dialog.component.html index cdf6b9936..34c3cff4b 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/force-redaction-dialog/force-annotation-dialog.component.html +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/force-redaction-dialog/force-annotation-dialog.component.html @@ -33,7 +33,7 @@
- +
} diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/force-redaction-dialog/force-annotation-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/force-redaction-dialog/force-annotation-dialog.component.ts index 243f88bef..5b87a6cc0 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/force-redaction-dialog/force-annotation-dialog.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/force-redaction-dialog/force-annotation-dialog.component.ts @@ -30,6 +30,7 @@ import { ForceAnnotationOption, LegalBasisOption } from '../../utils/dialog-type import { getForceAnnotationOptions } from '../../utils/dialog-options'; import { DetailsRadioComponent } from '@common-ui/inputs/details-radio/details-radio.component'; import { SystemDefaults } from '../../../account/utils/dialog-defaults'; +import { formValueToSignal } from '@common-ui/utils'; const DOCUMINE_LEGAL_BASIS = 'n-a.'; @@ -68,6 +69,12 @@ export class ForceAnnotationDialogComponent extends BaseDialogComponent implemen ]); legalOptions: LegalBasisOption[] = []; + readonly isImageHint = this._data.annotations.every(annotation => annotation.IMAGE_HINT); + readonly isHintDialog = this._data.hint; + readonly dialogTitle = this.#dialogTitle; + + readonly reasonValue = formValueToSignal(this.form.get('reason')); + protected readonly roles = Roles; constructor( @@ -81,19 +88,11 @@ export class ForceAnnotationDialogComponent extends BaseDialogComponent implemen this.form = this.#getForm(); } - get isImageHint() { - return this._data.annotations.every(annotation => annotation.IMAGE_HINT); - } - - get isHintDialog() { - return this._data.hint; - } - get disabled(): boolean { return !this.valid; } - get dialogTitle(): string { + get #dialogTitle(): string { return this.isImageHint ? _('manual-annotation.dialog.header.force-redaction-image-hint') : this.isHintDialog diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/highlight-action-dialog/highlight-action-dialog.component.html b/apps/red-ui/src/app/modules/file-preview/dialogs/highlight-action-dialog/highlight-action-dialog.component.html index 90d8d8ae5..5b643b662 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/highlight-action-dialog/highlight-action-dialog.component.html +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/highlight-action-dialog/highlight-action-dialog.component.html @@ -9,12 +9,7 @@
-
+
diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/highlight-action-dialog/highlight-action-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/highlight-action-dialog/highlight-action-dialog.component.ts index b6c1324a6..9b44af08e 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/highlight-action-dialog/highlight-action-dialog.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/highlight-action-dialog/highlight-action-dialog.component.ts @@ -14,6 +14,7 @@ import { highlightsTranslations } from '@translations/highlights-translations'; import { Roles } from '@users/roles'; import { ColorPickerModule } from 'ngx-color-picker'; import { firstValueFrom } from 'rxjs'; +import { formValueToSignal } from '@common-ui/utils'; export interface HighlightActionData { readonly operation: EarmarkOperation; @@ -59,6 +60,8 @@ export class HighlightActionDialogComponent extends BaseDialogComponent { }, ]; + readonly colorValue = formValueToSignal(this.form.get('color')); + constructor( protected readonly _dialogRef: MatDialogRef, private readonly _textHighlightService: EarmarksService, diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/rectangle-annotation-dialog/rectangle-annotation-dialog.component.html b/apps/red-ui/src/app/modules/file-preview/dialogs/rectangle-annotation-dialog/rectangle-annotation-dialog.component.html index deeeb9113..a65fc831b 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/rectangle-annotation-dialog/rectangle-annotation-dialog.component.html +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/rectangle-annotation-dialog/rectangle-annotation-dialog.component.html @@ -28,7 +28,7 @@
- +
diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/rectangle-annotation-dialog/rectangle-annotation-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/rectangle-annotation-dialog/rectangle-annotation-dialog.component.ts index 0fd48e9db..bb74e118c 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/rectangle-annotation-dialog/rectangle-annotation-dialog.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/rectangle-annotation-dialog/rectangle-annotation-dialog.component.ts @@ -9,7 +9,7 @@ import { IqserDialogComponent, Toaster, } from '@iqser/common-ui'; -import { Dossier, IAddRedactionRequest, SuperTypes } from '@red/domain'; +import { Dossier, IAddRedactionRequest, ILegalBasisChangeRequest, SuperTypes } from '@red/domain'; import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service'; import { JustificationsService } from '@services/entity-services/justifications.service'; import { Roles } from '@users/roles'; @@ -33,6 +33,7 @@ import { getRectangleRedactOptions } from '../../utils/dialog-options'; import { DetailsRadioComponent } from '@common-ui/inputs/details-radio/details-radio.component'; import { SystemDefaults } from '../../../account/utils/dialog-defaults'; import { validatePageRange } from '../../utils/form-validators'; +import { formValueToSignal } from '@common-ui/utils'; export const NON_READABLE_CONTENT = 'non-readable content'; @@ -68,7 +69,8 @@ export class RectangleAnnotationDialog protected readonly options: DetailsRadioOption[]; protected legalOptions: LegalBasisOption[] = []; - readonly form: UntypedFormGroup; + readonly form: UntypedFormGroup = this.#getForm(); + readonly reasonValue = formValueToSignal(this.form.get('reason')); constructor( private readonly activeDossiersService: ActiveDossiersService, @@ -81,7 +83,6 @@ export class RectangleAnnotationDialog this.options = getRectangleRedactOptions(); - this.form = this.#getForm(); this.initialFormValue = this.form.getRawValue(); } diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/redact-recommendation-dialog/redact-recommendation-dialog.component.html b/apps/red-ui/src/app/modules/file-preview/dialogs/redact-recommendation-dialog/redact-recommendation-dialog.component.html index 5c7d34dd2..457cc3e77 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/redact-recommendation-dialog/redact-recommendation-dialog.component.html +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/redact-recommendation-dialog/redact-recommendation-dialog.component.html @@ -22,7 +22,7 @@ - {{ displayedDictionaryLabel }} + {{ displayedDictionaryLabel() }} >(this.form.controls.option); + + readonly displayedDictionaryLabel = computed(() => { + const dictType = this.dictionaryType(); + if (dictType) { + return this.dictionaries.find(d => d.type === dictType)?.label ?? null; + } + return null; + }); + constructor( private readonly _justificationsService: JustificationsService, private readonly _dictionaryService: DictionaryService, @@ -88,32 +98,19 @@ export class RedactRecommendationDialogComponent super(); this.options = getRedactOrHintOptions(this.#dossier, this.#applyToAllDossiers, this.data.isApprover, false, true); - this.form.controls.option.valueChanges - .pipe( - tap((option: DetailsRadioOption) => { - this.dictionaryRequest = option.value === RedactOrHintOptions.IN_DOSSIER; - this.#setDictionaries(); - this.#resetValues(); - }), - takeUntilDestroyed(), - ) - .subscribe(); + effect(() => { + this.dictionaryRequest = this.optionValue().value === RedactOrHintOptions.IN_DOSSIER; + this.#setDictionaries(); + this.#resetValues(); + }); this.form.controls.option.setValue(this.options[0]); } - get isBulkLocal(): boolean { + get #isBulkLocal(): boolean { return this.form.controls.option.value.value === ResizeOptions.IN_DOCUMENT; } - get displayedDictionaryLabel() { - const dictType = this.form.controls.dictionary.value; - if (dictType) { - return this.dictionaries.find(d => d.type === dictType)?.label ?? null; - } - return null; - } - get disabled() { return !this.form.controls.dictionary.value; } @@ -157,7 +154,7 @@ export class RedactRecommendationDialogComponent this.close({ redaction, isMulti: this.isMulti, - bulkLocal: this.isBulkLocal, + bulkLocal: this.#isBulkLocal, }); } @@ -185,7 +182,7 @@ export class RedactRecommendationDialogComponent } const commentValue = this.form.controls.comment.value; - addRedactionRequest.comment = commentValue ? (this.isBulkLocal ? commentValue : { text: commentValue }) : null; + addRedactionRequest.comment = commentValue ? (this.#isBulkLocal ? commentValue : { text: commentValue }) : null; addRedactionRequest.addToAllDossiers = this.data.isApprover && this.dictionaryRequest && this.#applyToAllDossiers; return addRedactionRequest; } diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/redact-text-dialog/redact-text-dialog.component.html b/apps/red-ui/src/app/modules/file-preview/dialogs/redact-text-dialog/redact-text-dialog.component.html index 698b338c8..e69f79be4 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/redact-text-dialog/redact-text-dialog.component.html +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/redact-text-dialog/redact-text-dialog.component.html @@ -91,7 +91,7 @@ - {{ displayedDictionaryLabel$ | async }} + {{ displayedDictionaryLabel() }} [] = getRedactOrHintOptions( + this.#dossier, + this.#applyToAllDossiers, + this.data.isApprover, + this.data.isPageExcluded, + ); + readonly form: FormGroup = this.#getForm(); + readonly formStatus = formStatusToSignal(this.form); + readonly isFormValid = computed(() => this.formStatus() === 'VALID'); + + readonly dictionaryType = formValueToSignal(this.form.controls.dictionary); + readonly displayedDictionaryLabel = computed(() => { + return this.dictionaries.find(d => d.type === this.dictionaryType())?.label ?? null; + }); + + readonly optionValue = formValueToSignal>(this.form.controls.option); + dictionaryRequest = false; legalOptions: LegalBasisOption[] = []; dictionaries: Dictionary[] = []; isEditingSelectedText = false; modifiedText = this.initialText; selectedTextRows = 1; - readonly options: DetailsRadioOption[]; - readonly displayedDictionaryLabel$: Observable; readonly maximumTextAreaWidth = MAXIMUM_TEXT_AREA_WIDTH; readonly maximumSelectedTextWidth = 567; @@ -88,44 +101,34 @@ export class RedactTextDialogComponent private readonly _userPreferences: UserPreferenceService, ) { super(); - this.options = getRedactOrHintOptions(this.#dossier, this.#applyToAllDossiers, this.data.isApprover, this.data.isPageExcluded); - this.form = this.#getForm(); this.#setupValidators(this.dictionaryRequest ? RedactOrHintOptions.IN_DOSSIER : RedactOrHintOptions.ONLY_HERE); this.textWidth = calcTextWidthInPixels(this.form.controls.selectedText.value); - this.form.controls.option.valueChanges - .pipe( - tap((option: DetailsRadioOption) => { - this.dictionaryRequest = option.value === RedactOrHintOptions.IN_DOSSIER; - if (this.dictionaryRequest) { - this.#setDictionaries(); - this.form.patchValue({ selectedText: this.modifiedText }); - } else { - this.isEditingSelectedText = false; - this.modifiedText = this.form.controls.selectedText.value; - this.form.patchValue({ selectedText: this.initialText }, { emitEvent: true }); - } - this.#setupValidators(option.value); - this.#resetValues(); - }), - takeUntilDestroyed(), - ) - .subscribe(); - this.displayedDictionaryLabel$ = this.form.controls.dictionary.valueChanges.pipe( - map(dictionary => this.dictionaries.find(d => d.type === dictionary)?.label ?? null), - ); + effect(() => { + this.dictionaryRequest = this.optionValue().value === RedactOrHintOptions.IN_DOSSIER; + if (this.dictionaryRequest) { + this.#setDictionaries(); + this.form.patchValue({ selectedText: this.modifiedText }); + } else { + this.isEditingSelectedText = false; + this.modifiedText = this.form.controls.selectedText.value; + this.form.patchValue({ selectedText: this.initialText }, { emitEvent: true }); + } + this.#setupValidators(this.optionValue().value); + this.#resetValues(); + }); } - get isBulkLocal() { + get #isBulkLocal() { return this.form.controls.option.value.value === ResizeOptions.IN_DOCUMENT; } - get isSystemDefault(): boolean { + get #isSystemDefault(): boolean { return this._userPreferences.getAddRedactionDefaultOption() === SystemDefaultOption.SYSTEM_DEFAULT; } - get defaultOption() { - const defaultOption = this.isSystemDefault + get #defaultOption() { + const defaultOption = this.#isSystemDefault ? this.#getOption(SystemDefaults.ADD_REDACTION_DEFAULT) : this.#getOption(this._userPreferences.getAddRedactionDefaultOption() as RedactOrHintOption); this.dictionaryRequest = defaultOption.value === RedactOrHintOptions.IN_DOSSIER; @@ -136,8 +139,8 @@ export class RedactTextDialogComponent return defaultOption ?? this.options[0]; } - get applyToAll() { - return this.isSystemDefault || this._userPreferences.getAddRedactionDefaultExtraOption() === 'undefined' + get #applyToAll() { + return this.#isSystemDefault || this._userPreferences.getAddRedactionDefaultExtraOption() === 'undefined' ? this.data.applyToAllDossiers ?? true : stringToBoolean(this._userPreferences.getAddRedactionDefaultExtraOption()); } @@ -186,7 +189,7 @@ export class RedactTextDialogComponent this.close({ redaction, dictionary: this.dictionaries.find(d => d.type === this.form.controls.dictionary.value), - bulkLocal: this.isBulkLocal, + bulkLocal: this.#isBulkLocal, }); } @@ -228,7 +231,7 @@ export class RedactTextDialogComponent reason: [null as LegalBasisOption], comment: [null], dictionary: [this.#manualRedactionTypeExists ? SuperTypes.ManualRedaction : null], - option: this.defaultOption, + option: this.#defaultOption, }); } @@ -239,7 +242,7 @@ export class RedactTextDialogComponent } #resetValues() { - this.#applyToAllDossiers = this.applyToAll; + this.#applyToAllDossiers = this.#applyToAll; this.options[2].additionalCheck.checked = this.#applyToAllDossiers; if (this.dictionaryRequest) { this.form.controls.reason.setValue(null); @@ -263,7 +266,7 @@ export class RedactTextDialogComponent comment: this.form.controls.comment.value, isApprover: this.data.isApprover, applyToAllDossiers: this.#applyToAllDossiers, - bulkLocal: this.isBulkLocal, + bulkLocal: this.#isBulkLocal, }; } } 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 b7c80d8ed..01620c0be 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,6 +1,5 @@ import { NgStyle } from '@angular/common'; import { Component, computed } from '@angular/core'; -import { toSignal } from '@angular/core/rxjs-interop'; import { FormBuilder, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms'; import { MatDialogClose } from '@angular/material/dialog'; import { DetailsRadioOption } from '@common-ui/inputs/details-radio/details-radio-option'; @@ -18,7 +17,6 @@ import { TranslateModule } from '@ngx-translate/core'; import { Roles } from '@users/roles'; import { UserPreferenceService } from '@users/user-preference.service'; import { stringToBoolean } from '@utils/functions'; -import { map } from 'rxjs/operators'; import { SystemDefaultOption, SystemDefaults } from '../../../account/utils/dialog-defaults'; import { SelectedAnnotationsTableComponent, @@ -34,7 +32,7 @@ import { RemoveRedactionResult, ResizeOptions, } from '../../utils/dialog-types'; -import { isJustOne } from '@common-ui/utils'; +import { formValueToSignal, isJustOne } from '@common-ui/utils'; import { validatePageRange } from '../../utils/form-validators'; import { parseRectanglePosition, parseSelectedPageNumbers } from '../../utils/enhance-manual-redaction-request.utils'; @@ -112,11 +110,13 @@ export class RemoveRedactionDialogComponent extends IqserDialogComponent< readonly redactedTexts = this.data.redactions.map(annotation => annotation.value); form: UntypedFormGroup = this._formBuilder.group({ comment: [null], - option: [this.defaultOption, validatePageRange(true)], + option: [this.#defaultOption, validatePageRange(true)], }); - readonly selectedOption = toSignal(this.form.get('option').valueChanges.pipe(map(value => value.value))); - readonly isFalsePositive = computed(() => this.selectedOption() === RemoveRedactionOptions.FALSE_POSITIVE); + readonly optionValue = formValueToSignal>(this.form.controls.option); + readonly isFalsePositive = computed(() => this.optionValue().value === RemoveRedactionOptions.FALSE_POSITIVE); + readonly hasFalsePositiveOption = !!this.options.find(option => option.value === RemoveRedactionOptions.FALSE_POSITIVE); + readonly tableColumns = computed(() => [ { label: 'Value', width: '25%' }, { label: 'Type', width: '25%' }, @@ -135,6 +135,11 @@ export class RemoveRedactionDialogComponent extends IqserDialogComponent< ]), ); + readonly isBulk = !isJustOne(this.data.redactions); + readonly redactedTextsAreaHeight = this.redactedTexts.length <= 10 ? 18 * this.redactedTexts.length : 180; + readonly dialogContentHeight = this.options.length * 75 + 230; + readonly typeTranslationArg = { type: this.annotationsType }; + constructor( private readonly _formBuilder: FormBuilder, private readonly _userPreferences: UserPreferenceService, @@ -142,32 +147,12 @@ export class RemoveRedactionDialogComponent extends IqserDialogComponent< super(); } - get hasFalsePositiveOption() { - return !!this.options.find(option => option.value === RemoveRedactionOptions.FALSE_POSITIVE); - } - - get defaultOption() { + get #defaultOption() { const removeDefaultOption = this.#getOption(this.defaultOptionPreference as RemoveRedactionOption); if (!!removeDefaultOption && !removeDefaultOption.disabled) return removeDefaultOption; return this.options[0]; } - get typeTranslationArg() { - return { type: this.annotationsType }; - } - - get isBulk() { - return !isJustOne(this.data.redactions); - } - - get redactedTextsAreaHeight() { - return this.redactedTexts.length <= 10 ? 18 * this.redactedTexts.length : 180; - } - - get dialogContentHeight() { - return this.options.length * 75 + 230; - } - extraOptionChanged(option: DetailsRadioOption): void { if (option.value === RectangleRedactOptions.MULTIPLE_PAGES) { setTimeout(() => { 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 5f33edd9e..dc64e53b6 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 @@ -3,7 +3,7 @@
- +
- {{ displayedDictionaryLabel }} + {{ displayedDictionaryLabel() }} {{ redaction.typeLabel }} diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/resize-redaction-dialog/resize-redaction-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/resize-redaction-dialog/resize-redaction-dialog.component.ts index a5b174c13..9384522c9 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/resize-redaction-dialog/resize-redaction-dialog.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/resize-redaction-dialog/resize-redaction-dialog.component.ts @@ -1,5 +1,5 @@ import { NgIf } from '@angular/common'; -import { Component, inject } from '@angular/core'; +import { Component, computed, inject } from '@angular/core'; import { FormBuilder, FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms'; import { MatDialogClose } from '@angular/material/dialog'; import { MatFormField } from '@angular/material/form-field'; @@ -12,6 +12,13 @@ import { ActiveDossiersService } from '@services/dossiers/active-dossiers.servic import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service'; import { getResizeRedactionOptions } from '../../utils/dialog-options'; import { ResizeOptions, ResizeRedactionData, ResizeRedactionOption, ResizeRedactionResult } from '../../utils/dialog-types'; +import { AsControl, formValueToSignal } from '@common-ui/utils'; + +interface ResizeForm { + comment: string; + dictionary: string; + option: DetailsRadioOption; +} @Component({ templateUrl: './resize-redaction-dialog.component.html', @@ -44,11 +51,17 @@ export class ResizeRedactionDialogComponent extends IqserDialogComponent< readonly dictionaries = inject(DictionariesMapService).get(this.#dossier.dossierTemplateId); readonly entity = this.dictionaries.find(d => d.type === this.data.redaction.type); readonly redaction = this.data.redaction; - readonly form: FormGroup<{ - comment: FormControl; - dictionary: FormControl; - option: FormControl>; - }>; + readonly isImage = this.redaction.isImage; + readonly form: FormGroup> = this.#getForm(); + readonly dialogHeaderType = this.data.redaction.HINT ? 'hint' : this.data.redaction.isSkippedImageHint ? 'image' : 'redaction'; + readonly dictionaryType = formValueToSignal(this.form.get('dictionary')); + readonly displayedDictionaryLabel = computed(() => { + const dictType = this.dictionaryType(); + if (dictType) { + return this.dictionaries.find(d => d.type === dictType)?.label ?? null; + } + return null; + }); constructor(private readonly _formBuilder: FormBuilder) { super(); @@ -60,19 +73,6 @@ export class ResizeRedactionDialogComponent extends IqserDialogComponent< this.data.isApprover, this.data.permissions.canResizeInDictionary, ); - this.form = this.#getForm(); - } - - get dialogHeaderType() { - return this.data.redaction.HINT ? 'hint' : this.data.redaction.isSkippedImageHint ? 'image' : 'redaction'; - } - - get displayedDictionaryLabel() { - const dictType = this.form.get('dictionary').value; - if (dictType) { - return this.dictionaries.find(d => d.type === dictType)?.label ?? null; - } - return null; } save() { diff --git a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.html b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.html index 41b9e50a3..0fdcfe684 100644 --- a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.html +++ b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.html @@ -5,11 +5,12 @@
- + @if (isDocumine) { + + }
diff --git a/apps/red-ui/src/app/modules/file-preview/services/annotation-processing.service.ts b/apps/red-ui/src/app/modules/file-preview/services/annotation-processing.service.ts index e453fb37d..2865bd303 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/annotation-processing.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/annotation-processing.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@angular/core'; +import { Injectable, untracked } from '@angular/core'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { getConfig } from '@iqser/common-ui'; import { Filter, handleCheckedValue, IFilter, INestedFilter, NestedFilter } from '@iqser/common-ui/lib/filtering'; @@ -78,7 +78,8 @@ export class AnnotationProcessingService { const filters: INestedFilter[] = []; this._fileDataService.all?.forEach(a => { - const dictionary = this._state.dictionaries.find(dictionary => dictionary.type === a.type); + const dictionaries = untracked(this._state.dictionaries); + const dictionary = dictionaries.find(dictionary => dictionary.type === a.type); const doesTypeExist = !!dictionary; if ( (this.#isDocumine && !this.#devMode && a.isOCR) || diff --git a/apps/red-ui/src/app/modules/file-preview/services/file-data.service.ts b/apps/red-ui/src/app/modules/file-preview/services/file-data.service.ts index 8a255b226..226834cf1 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/file-data.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/file-data.service.ts @@ -1,4 +1,4 @@ -import { effect, inject, Injectable, Signal, signal } from '@angular/core'; +import { effect, inject, Injectable, Signal, signal, untracked } from '@angular/core'; import { toObservable } from '@angular/core/rxjs-interop'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { EntitiesService, getConfig, Toaster } from '@iqser/common-ui'; @@ -180,7 +180,7 @@ export class FileDataService extends EntitiesService; readonly componentReferenceIds$: Observable; readonly #componentReferenceIds$ = new BehaviorSubject(null); + readonly componentReferenceIdsSignal: Signal; readonly dossierId = getParam(DOSSIER_ID); readonly dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID); readonly fileId = getParam(FILE_ID); readonly excludedPages: WritableSignal; readonly updateExcludedPagesStyle = computed(() => this.excludedPages()); readonly isEditingReviewer = signal(false); + readonly dictionaries: Signal; constructor( private readonly _permissionsService: PermissionsService, @@ -76,6 +78,14 @@ export class FilePreviewStateService { this.blob$ = this.#blob$; this.dossierDictionary = toSignal(inject(DossierDictionariesMapService).watch$(this.dossierId, 'dossier_redaction')); + this.dictionaries = computed(() => { + const dictionaries = this._dictionariesMapService.get(this.dossierTemplateId); + if (this.dossierDictionary()) { + dictionaries.push(this.dossierDictionary()); + } + + return dictionaries; + }); this.#dossierFilesChange$ .pipe( switchMap(() => this._filesService.loadAll(this.dossierId)), @@ -92,21 +102,14 @@ export class FilePreviewStateService { }, { allowSignalWrites: true }, ); + + this.componentReferenceIdsSignal = toSignal(this.componentReferenceIds$); } set componentReferenceIds(ids: string[]) { this.#componentReferenceIds$.next(ids); } - get dictionaries(): Dictionary[] { - const dictionaries = this._dictionariesMapService.get(this.dossierTemplateId); - if (this.dossierDictionary()) { - dictionaries.push(this.dossierDictionary()); - } - - return dictionaries; - } - get blob(): Promise { return firstValueFrom(this.blob$); } @@ -133,10 +136,6 @@ export class FilePreviewStateService { ); } - get componentReferenceIds() { - return this.#componentReferenceIds$.getValue(); - } - reloadBlob(): void { this.#reloadBlob$.next(true); } 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 08ed74c69..554125f7a 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,4 +1,4 @@ -import { inject, Injectable, NgZone } from '@angular/core'; +import { inject, Injectable, NgZone, untracked } from '@angular/core'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { getConfig, IqserPermissionsService } from '@iqser/common-ui'; import { AnnotationPermissions } from '@models/file/annotation.permissions'; @@ -135,7 +135,7 @@ export class PdfAnnotationActionsService { #getAnnotationsPermissions(annotations: AnnotationWrapper[]): AnnotationPermissions { const dossier = this.#state.dossier(); const isApprover = this.#permissionsService.isApprover(dossier); - const dictionaries = this.#state.dictionaries; + const dictionaries = untracked(this.#state.dictionaries); const autoAnalysisDisabled = this.#state.file().excludedFromAutomaticAnalysis; const permissions = annotations.map(a => AnnotationPermissions.forUser(isApprover, a, dictionaries, this.#iqserPermissionsService, autoAnalysisDisabled), diff --git a/apps/red-ui/src/app/utils/functions.ts b/apps/red-ui/src/app/utils/functions.ts index 50492e03c..0aca86784 100644 --- a/apps/red-ui/src/app/utils/functions.ts +++ b/apps/red-ui/src/app/utils/functions.ts @@ -2,8 +2,6 @@ import { ITrackable } from '@iqser/common-ui'; import type { List } from '@iqser/common-ui/lib/utils'; import type { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { Dayjs } from 'dayjs'; -import { FormControl } from '@angular/forms'; -import { toSignal } from '@angular/core/rxjs-interop'; export function hexToRgb(hex: string) { const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); @@ -145,7 +143,3 @@ export function urlFileId() { const fileId = splitUrl[splitUrl.length - 1]; return fileId.split('?')[0]; } - -export function formControlToSignal(control: FormControl) { - return toSignal(control.valueChanges, { initialValue: control.value }); -} diff --git a/libs/common-ui b/libs/common-ui index ba85260cc..3f214d972 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit ba85260cc4a3e780a37b3f41be26b83d045a1dcb +Subproject commit 3f214d9726e17cd204acae8a4ef95749260b3c9a