Merge branch 'RED-10363' into 'master'

RED-10363: disable analysis button when rules are locked.

See merge request redactmanager/red-ui!684
This commit is contained in:
Dan Percic 2024-11-11 12:46:40 +01:00
commit 7a78dd6547
7 changed files with 83 additions and 22 deletions

View File

@ -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<IRules> {
export class RulesService extends EntitiesService<IRules, Rules> {
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<IRules> {
}
getFor<R = IRules>(entityId: string, queryParams?: List<QueryParam>): Observable<R> {
return super.getFor(entityId, queryParams);
return super.getFor<R>(entityId, queryParams).pipe(tap(rules => this.setEntities([rules as Rules])));
}
}

View File

@ -1,5 +1,5 @@
<iqser-page-header
(closeAction)="router.navigate([dossier.dossiersListRouterLink])"
(closeAction)="router.navigate([dossier().dossiersListRouterLink])"
[actionConfigs]="actionConfigs"
[helpModeKey]="'document'"
[showCloseButton]="true"
@ -10,14 +10,14 @@
[attr.help-mode-key]="isDocumine ? 'dossier_download_dossier' : 'download_dossier_in_dossier'"
[buttonId]="'download-files-btn'"
[disabled]="downloadFilesDisabled$ | async"
[dossier]="dossier"
[dossier]="dossier()"
[files]="entitiesService.all$ | async"
dossierDownload
></redaction-file-download-btn>
<iqser-circle-button
(action)="downloadDossierAsCSV()"
*ngIf="permissionsService.canDownloadCsvReport(dossier)"
*ngIf="permissionsService.canDownloadCsvReport(dossier())"
[attr.help-mode-key]="'download_csv'"
[disabled]="listingService.areSomeSelected$ | async"
[icon]="'iqser:csv'"
@ -26,17 +26,20 @@
<iqser-circle-button
(action)="reanalyseDossier()"
*ngIf="permissionsService.displayReanalyseBtn(dossier)"
[disabled]="listingService.areSomeSelected$ | async"
*ngIf="permissionsService.displayReanalyseBtn(dossier())"
[disabled]="(listingService.areSomeSelected$ | async) || areRulesLocked()"
[icon]="'iqser:refresh'"
[tooltipClass]="'small warn'"
[tooltip]="'dossier-overview.new-rule.toast.actions.reanalyse-all' | translate"
[tooltip]="
(areRulesLocked() ? 'dossier-listing.rules.timeoutError' : 'dossier-overview.new-rule.toast.actions.reanalyse-all')
| translate
"
[type]="circleButtonTypes.warn"
></iqser-circle-button>
<iqser-circle-button
(action)="upload.emit()"
*ngIf="permissionsService.canUploadFiles(dossier)"
*ngIf="permissionsService.canUploadFiles(dossier())"
[attr.help-mode-key]="'upload_document'"
[buttonId]="'upload-document-btn'"
[icon]="'iqser:upload'"

View File

@ -1,4 +1,4 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { ChangeDetectionStrategy, Component, computed, EventEmitter, input, OnInit, Output } from '@angular/core';
import {
ActionConfig,
CircleButtonComponent,
@ -25,12 +25,12 @@ import { Router } from '@angular/router';
import { Roles } from '@users/roles';
import { SortingService } from '@iqser/common-ui/lib/sorting';
import { List, some } from '@iqser/common-ui/lib/utils';
import { ComponentLogService } from '@services/files/component-log.service';
import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu';
import { AsyncPipe, NgIf } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core';
import { FileDownloadBtnComponent } from '@shared/components/buttons/file-download-btn/file-download-btn.component';
import { ViewModeSelectionComponent } from '../view-mode-selection/view-mode-selection.component';
import { RulesService } from '../../../admin/services/rules.service';
@Component({
selector: 'redaction-dossier-overview-screen-header [dossier] [upload]',
@ -50,9 +50,10 @@ import { ViewModeSelectionComponent } from '../view-mode-selection/view-mode-sel
MatMenu,
MatMenuItem,
],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DossierOverviewScreenHeaderComponent implements OnInit {
@Input() dossier: Dossier;
readonly dossier = input<Dossier>();
@Output() readonly upload = new EventEmitter<void>();
readonly circleButtonTypes = CircleButtonTypes;
readonly roles = Roles;
@ -60,6 +61,9 @@ export class DossierOverviewScreenHeaderComponent implements OnInit {
readonly downloadFilesDisabled$: Observable<boolean>;
readonly downloadComponentLogsDisabled$: Observable<boolean>;
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'];

View File

@ -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',
},
{

View File

@ -13,3 +13,4 @@ export * from './app-config';
export * from './system-preferences';
export * from './component-rules';
export * from './editor.types';
export * from './rules.model';

View File

@ -0,0 +1,23 @@
import { IRules } from '@red/domain';
import { Entity } from '@iqser/common-ui';
export class Rules extends Entity<IRules> 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;
}
}

View File

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