From 8cdb869a103729fb10c2ba6e87e45b18538164be Mon Sep 17 00:00:00 2001 From: Nicoleta Panaghiu Date: Mon, 11 Nov 2024 12:23:47 +0200 Subject: [PATCH] RED-10363: disable analysis button when rules are locked. --- .../modules/admin/services/rules.service.ts | 24 +++++++++++++++---- ...sier-overview-screen-header.component.html | 17 +++++++------ ...ossier-overview-screen-header.component.ts | 19 +++++++++------ .../file-actions/file-actions.component.ts | 19 +++++++++++++-- libs/red-domain/src/lib/shared/index.ts | 1 + libs/red-domain/src/lib/shared/rules.model.ts | 23 ++++++++++++++++++ libs/red-domain/src/lib/shared/rules.ts | 2 +- 7 files changed, 83 insertions(+), 22 deletions(-) create mode 100644 libs/red-domain/src/lib/shared/rules.model.ts diff --git a/apps/red-ui/src/app/modules/admin/services/rules.service.ts b/apps/red-ui/src/app/modules/admin/services/rules.service.ts index bb89c2ad8..11efa8c81 100644 --- a/apps/red-ui/src/app/modules/admin/services/rules.service.ts +++ b/apps/red-ui/src/app/modules/admin/services/rules.service.ts @@ -1,11 +1,25 @@ import { Injectable } from '@angular/core'; -import { GenericService, QueryParam } from '@iqser/common-ui'; -import { IRules } from '@red/domain'; -import { Observable } from 'rxjs'; +import { EntitiesService, QueryParam } from '@iqser/common-ui'; +import { IRules, Rules } from '@red/domain'; +import { map, Observable, tap } from 'rxjs'; import { List } from '@common-ui/utils'; +import { toSignal } from '@angular/core/rxjs-interop'; +import { distinctUntilChanged, filter } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) -export class RulesService extends GenericService { +export class RulesService extends EntitiesService { + readonly currentTemplateRules = toSignal( + this.all$.pipe( + filter(all => !!all.length), + map(rules => rules[0]), + distinctUntilChanged( + (prev, curr) => + prev.rules !== curr.rules || + prev.timeoutDetected !== curr.timeoutDetected || + prev.dossierTemplateId !== curr.dossierTemplateId, + ), + ), + ); protected readonly _defaultModelPath = 'rules'; download(dossierTemplateId: string, ruleFileType: IRules['ruleFileType'] = 'ENTITY') { @@ -17,6 +31,6 @@ export class RulesService extends GenericService { } getFor(entityId: string, queryParams?: List): Observable { - return super.getFor(entityId, queryParams); + return super.getFor(entityId, queryParams).pipe(tap(rules => this.setEntities([rules as Rules]))); } } diff --git a/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.html b/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.html index 5e45b10fa..9ffab710e 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.html +++ b/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.html @@ -1,5 +1,5 @@ (); @Output() readonly upload = new EventEmitter(); readonly circleButtonTypes = CircleButtonTypes; readonly roles = Roles; @@ -60,6 +61,9 @@ export class DossierOverviewScreenHeaderComponent implements OnInit { readonly downloadFilesDisabled$: Observable; readonly downloadComponentLogsDisabled$: Observable; readonly isDocumine = getConfig().IS_DOCUMINE; + readonly areRulesLocked = computed(() => { + return this._rulesService.currentTemplateRules().timeoutDetected; + }); constructor( private readonly _toaster: Toaster, @@ -73,6 +77,7 @@ export class DossierOverviewScreenHeaderComponent implements OnInit { private readonly _reanalysisService: ReanalysisService, private readonly _loadingService: LoadingService, private readonly _primaryFileAttributeService: PrimaryFileAttributeService, + private readonly _rulesService: RulesService, ) { const someNotProcessed$ = this.entitiesService.all$.pipe(some(file => !file.lastProcessed)); this.downloadFilesDisabled$ = combineLatest([this.listingService.areSomeSelected$, someNotProcessed$]).pipe( @@ -84,13 +89,13 @@ export class DossierOverviewScreenHeaderComponent implements OnInit { } ngOnInit() { - this.actionConfigs = this.configService.actionConfig(this.dossier.id, this.listingService.areSomeSelected$); + this.actionConfigs = this.configService.actionConfig(this.dossier().id, this.listingService.areSomeSelected$); } async reanalyseDossier() { this._loadingService.start(); try { - await this._reanalysisService.reanalyzeDossier(this.dossier, true); + await this._reanalysisService.reanalyzeDossier(this.dossier(), true); this._toaster.success(_('dossier-overview.reanalyse-dossier.success')); } catch (e) { this._toaster.error(_('dossier-overview.reanalyse-dossier.error')); @@ -101,12 +106,12 @@ export class DossierOverviewScreenHeaderComponent implements OnInit { async downloadDossierAsCSV() { const displayedEntities = await firstValueFrom(this.listingService.displayed$); const entities = this.sortingService.defaultSort(displayedEntities); - const fileName = this.dossier.dossierName + '.export.csv'; + const fileName = this.dossier().dossierName + '.export.csv'; const mapper = (file?: File) => ({ ...file, hasAnnotations: file.hasRedactions, assignee: this._userService.getName(file.assignee) || '-', - primaryAttribute: this._primaryFileAttributeService.getPrimaryFileAttributeValue(file, this.dossier.dossierTemplateId), + primaryAttribute: this._primaryFileAttributeService.getPrimaryFileAttributeValue(file, this.dossier().dossierTemplateId), }); const documineOnlyFields = ['hasAnnotations']; const redactionOnlyFields = ['hasHints', 'hasImages', 'hasUpdates', 'hasRedactions']; diff --git a/apps/red-ui/src/app/modules/shared-dossiers/components/file-actions/file-actions.component.ts b/apps/red-ui/src/app/modules/shared-dossiers/components/file-actions/file-actions.component.ts index 760c59c66..04375e949 100644 --- a/apps/red-ui/src/app/modules/shared-dossiers/components/file-actions/file-actions.component.ts +++ b/apps/red-ui/src/app/modules/shared-dossiers/components/file-actions/file-actions.component.ts @@ -1,4 +1,15 @@ -import { ChangeDetectorRef, Component, HostBinding, Injector, Input, OnChanges, Optional, signal, ViewChild } from '@angular/core'; +import { + ChangeDetectorRef, + Component, + computed, + HostBinding, + Injector, + Input, + OnChanges, + Optional, + signal, + ViewChild, +} from '@angular/core'; import { toObservable } from '@angular/core/rxjs-interop'; import { Router } from '@angular/router'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; @@ -37,6 +48,7 @@ import { ProcessingIndicatorComponent } from '@shared/components/processing-indi import { StatusBarComponent } from '@common-ui/shared'; import { NgIf, NgTemplateOutlet } from '@angular/common'; import { ApproveWarningDetailsComponent } from '@shared/components/approve-warning-details/approve-warning-details.component'; +import { RulesService } from '../../../admin/services/rules.service'; @Component({ selector: 'redaction-file-actions', @@ -86,6 +98,7 @@ export class FileActionsComponent implements OnChanges { @ViewChild(ExpandableFileActionsComponent) private readonly _expandableActionsComponent: ExpandableFileActionsComponent; readonly #isDocumine = getConfig().IS_DOCUMINE; + readonly areRulesLocked = computed(() => this._rulesService.currentTemplateRules().timeoutDetected); constructor( private readonly _injector: Injector, @@ -101,6 +114,7 @@ export class FileActionsComponent implements OnChanges { private readonly _activeDossiersService: ActiveDossiersService, private readonly _fileManagementService: FileManagementService, private readonly _userPreferenceService: UserPreferenceService, + private readonly _rulesService: RulesService, readonly fileAttributesService: FileAttributesService, @Optional() private readonly _documentInfoService: DocumentInfoService, @Optional() private readonly _excludedPagesService: ExcludedPagesService, @@ -277,9 +291,10 @@ export class FileActionsComponent implements OnChanges { id: 'btn-reanalyse_file', type: ActionTypes.circleBtn, action: () => this.#reanalyseFile(), - tooltip: _('dossier-overview.reanalyse.action'), + tooltip: this.areRulesLocked() ? _('dossier-listing.rules.timeoutError') : _('dossier-overview.reanalyse.action'), icon: 'iqser:refresh', show: this.showReanalyseDossierOverview, + disabled: this.areRulesLocked(), helpModeKey: 'stop_analysis', }, { diff --git a/libs/red-domain/src/lib/shared/index.ts b/libs/red-domain/src/lib/shared/index.ts index 8406e4be7..7c5c49665 100644 --- a/libs/red-domain/src/lib/shared/index.ts +++ b/libs/red-domain/src/lib/shared/index.ts @@ -13,3 +13,4 @@ export * from './app-config'; export * from './system-preferences'; export * from './component-rules'; export * from './editor.types'; +export * from './rules.model'; diff --git a/libs/red-domain/src/lib/shared/rules.model.ts b/libs/red-domain/src/lib/shared/rules.model.ts new file mode 100644 index 000000000..85b7c2d05 --- /dev/null +++ b/libs/red-domain/src/lib/shared/rules.model.ts @@ -0,0 +1,23 @@ +import { IRules } from '@red/domain'; +import { Entity } from '@iqser/common-ui'; + +export class Rules extends Entity implements IRules { + readonly id: string; + readonly routerLink: string; + readonly searchKey: string; + readonly dossierTemplateId: string; + readonly ruleFileType?: 'ENTITY' | 'COMPONENT'; + readonly rules?: string; + readonly dryRun?: boolean; + readonly timeoutDetected?: boolean; + + constructor(rules: IRules) { + super(rules); + this.id = rules.dossierTemplateId; + this.dossierTemplateId = rules.dossierTemplateId; + this.ruleFileType = rules.ruleFileType; + this.rules = rules.rules; + this.dryRun = rules.dryRun; + this.timeoutDetected = rules.timeoutDetected; + } +} diff --git a/libs/red-domain/src/lib/shared/rules.ts b/libs/red-domain/src/lib/shared/rules.ts index 5a8316b1b..431bb3427 100644 --- a/libs/red-domain/src/lib/shared/rules.ts +++ b/libs/red-domain/src/lib/shared/rules.ts @@ -5,7 +5,7 @@ export interface IRules { /** * The DossierTemplate ID for these rules */ - dossierTemplateId?: string; + dossierTemplateId: string; /** * The file type to be retrieved/saved under, defaults to ENTITY */