From bceea2568b8551eb65a15bc82a93ce6c3a0b702e Mon Sep 17 00:00:00 2001 From: Nicoleta Panaghiu Date: Thu, 21 Nov 2024 11:34:00 +0200 Subject: [PATCH] RED-10363: backport for all the locked rules changes. --- apps/red-ui/src/app/app.module.ts | 1 + .../guards/dossier-template-exists.guard.ts | 9 +- ...ssier-overview-bulk-actions.component.html | 8 +- ...dossier-overview-bulk-actions.component.ts | 210 ++++++------ .../dossier-details.component.ts | 11 +- ...sier-overview-screen-header.component.html | 17 +- ...ossier-overview-screen-header.component.ts | 36 +- .../file-actions/file-actions.component.html | 20 +- .../file-actions/file-actions.component.ts | 307 +++++++++--------- apps/red-ui/src/assets/i18n/redact/de.json | 3 + apps/red-ui/src/assets/i18n/redact/en.json | 3 + apps/red-ui/src/assets/i18n/scm/de.json | 3 + apps/red-ui/src/assets/i18n/scm/en.json | 3 + 13 files changed, 322 insertions(+), 309 deletions(-) diff --git a/apps/red-ui/src/app/app.module.ts b/apps/red-ui/src/app/app.module.ts index 52a8534ed..82d09377f 100644 --- a/apps/red-ui/src/app/app.module.ts +++ b/apps/red-ui/src/app/app.module.ts @@ -258,6 +258,7 @@ export const appModuleFactory = (config: AppConfig) => { provide: MAT_TOOLTIP_DEFAULT_OPTIONS, useValue: { disableTooltipInteractivity: true, + showDelay: 1, }, }, BaseDatePipe, diff --git a/apps/red-ui/src/app/guards/dossier-template-exists.guard.ts b/apps/red-ui/src/app/guards/dossier-template-exists.guard.ts index 6e751efa1..8c3184cc1 100644 --- a/apps/red-ui/src/app/guards/dossier-template-exists.guard.ts +++ b/apps/red-ui/src/app/guards/dossier-template-exists.guard.ts @@ -11,8 +11,9 @@ import { DictionaryService } from '@services/entity-services/dictionary.service' import { DefaultColorsService } from '@services/entity-services/default-colors.service'; import { WatermarkService } from '@services/entity-services/watermark.service'; import { FileAttributesService } from '@services/entity-services/file-attributes.service'; -import { getConfig } from '@iqser/common-ui'; +import { getConfig, Toaster } from '@iqser/common-ui'; import { RulesService } from '../modules/admin/services/rules.service'; +import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; export function templateExistsWhenEnteringAdmin(): CanActivateFn { return async function (route: ActivatedRouteSnapshot): Promise { @@ -53,6 +54,8 @@ export function templateExistsWhenEnteringDossierList(): CanActivateFn { const dictionaryService = inject(DictionaryService); const defaultColorsService = inject(DefaultColorsService); const watermarksService = inject(WatermarkService); + const rulesService = inject(RulesService); + const toaster = inject(Toaster); const isDocumine = getConfig().IS_DOCUMINE; await firstValueFrom(dashboardStatsService.loadForTemplate(dossierTemplateId)); @@ -67,6 +70,10 @@ export function templateExistsWhenEnteringDossierList(): CanActivateFn { await firstValueFrom(fileAttributesService.loadFileAttributesConfig(dossierTemplateId)); await firstValueFrom(dictionaryService.loadDictionaryDataForDossierTemplate(dossierTemplateId)); await firstValueFrom(defaultColorsService.loadForDossierTemplate(dossierTemplateId)); + const rules = await firstValueFrom(rulesService.getFor(dossierTemplateId)); + if (rules.timeoutDetected) { + toaster.error(_('dossier-listing.rules.timeoutError')); + } if (!isDocumine) { await firstValueFrom(watermarksService.loadForDossierTemplate(dossierTemplateId)); } diff --git a/apps/red-ui/src/app/modules/dossier-overview/components/bulk-actions/dossier-overview-bulk-actions.component.html b/apps/red-ui/src/app/modules/dossier-overview/components/bulk-actions/dossier-overview-bulk-actions.component.html index 3f4b3facf..9ff365dc7 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/components/bulk-actions/dossier-overview-bulk-actions.component.html +++ b/apps/red-ui/src/app/modules/dossier-overview/components/bulk-actions/dossier-overview-bulk-actions.component.html @@ -1,8 +1,8 @@ - + diff --git a/apps/red-ui/src/app/modules/dossier-overview/components/bulk-actions/dossier-overview-bulk-actions.component.ts b/apps/red-ui/src/app/modules/dossier-overview/components/bulk-actions/dossier-overview-bulk-actions.component.ts index 52fcb2097..a8faf210e 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/components/bulk-actions/dossier-overview-bulk-actions.component.ts +++ b/apps/red-ui/src/app/modules/dossier-overview/components/bulk-actions/dossier-overview-bulk-actions.component.ts @@ -1,6 +1,6 @@ -import { Component, Input, OnChanges } from '@angular/core'; +import { Component, computed, input, signal } from '@angular/core'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; -import { CircleButtonType, CircleButtonTypes } from '@iqser/common-ui'; +import { CircleButtonType, CircleButtonTypes, Toaster } from '@iqser/common-ui'; import { Action, ActionTypes, Dossier, File, ProcessingFileStatuses } from '@red/domain'; import { PermissionsService } from '@services/permissions.service'; import { LongPressDirective, LongPressEvent } from '@shared/directives/long-press.directive'; @@ -9,6 +9,8 @@ import { BulkActionsService } from '../../services/bulk-actions.service'; import { ExpandableFileActionsComponent } from '@shared/components/expandable-file-actions/expandable-file-actions.component'; import { IqserTooltipPositions } from '@common-ui/utils'; import { NgIf } from '@angular/common'; +import { RulesService } from '../../../admin/services/rules.service'; +import { firstValueFrom } from 'rxjs'; @Component({ selector: 'redaction-dossier-overview-bulk-actions [dossier] [selectedFiles]', @@ -17,218 +19,194 @@ import { NgIf } from '@angular/common'; standalone: true, imports: [LongPressDirective, ExpandableFileActionsComponent, NgIf], }) -export class DossierOverviewBulkActionsComponent implements OnChanges { - #analysisForced: boolean; - #canAssignToSelf: boolean; - #canAssign: boolean; - #canDelete: boolean; - #canReanalyse: boolean; - #canDisableAutoAnalysis: boolean; - #canEnableAutoAnalysis: boolean; - #canOcr: boolean; - #canSetToNew: boolean; - #canSetToUnderReview: boolean; - #canSetToUnderApproval: boolean; - #isReadyForApproval: boolean; - #canApprove: boolean; - #canUndoApproval: boolean; - #canToggleAnalysis: boolean; - #assignTooltip: string; - #toggleAnalysisTooltip: string; - #allFilesAreExcluded: boolean; - #canMoveToSameState: boolean; - @Input() dossier: Dossier; - @Input() selectedFiles: File[]; - @Input() buttonType: CircleButtonType = CircleButtonTypes.default; - @Input() maxWidth: number; - buttons: Action[]; +export class DossierOverviewBulkActionsComponent { + readonly dossier = input(); + readonly selectedFiles = input(); + readonly buttonType = input(CircleButtonTypes.default); + readonly maxWidth = input(); + readonly buttons = computed(() => this.#buttons); readonly IqserTooltipPositions = IqserTooltipPositions; + readonly #areRulesLocked = computed(() => this._rulesService.currentTemplateRules().timeoutDetected); + readonly #allFilesAreUnderReviewOrUnassigned = computed(() => + this.selectedFiles().reduce((acc, file) => acc && (file.isUnderReview || file.isNew), true), + ); + readonly #allFilesAreUnderApproval = computed(() => this.selectedFiles().reduce((acc, file) => acc && file.isUnderApproval, true)); + readonly #allFilesAreExcluded = computed(() => this.selectedFiles().reduce((acc, file) => acc && file.excluded, true)); + readonly #allFilesAreApproved = computed(() => this.selectedFiles().reduce((acc, file) => acc && file.isApproved, true)); + readonly #canMoveToSameState = computed( + () => this.#allFilesAreUnderReviewOrUnassigned() || this.#allFilesAreUnderApproval() || this.#allFilesAreApproved(), + ); + readonly #canAssign = computed( + () => + this.#canMoveToSameState() && + (this._permissionsService.canAssignUser(this.selectedFiles(), this.dossier()) || + this._permissionsService.canUnassignUser(this.selectedFiles(), this.dossier())), + ); + readonly #canAssignToSelf = computed( + () => this.#canMoveToSameState() && this._permissionsService.canAssignToSelf(this.selectedFiles(), this.dossier()), + ); + readonly #canDelete = computed(() => this._permissionsService.canSoftDeleteFile(this.selectedFiles(), this.dossier())); + readonly #canReanalyse = computed(() => this._permissionsService.canReanalyseFile(this.selectedFiles(), this.dossier())); + readonly #canDisableAutoAnalysis = computed(() => + this._permissionsService.canDisableAutoAnalysis(this.selectedFiles(), this.dossier()), + ); + readonly #canEnableAutoAnalysis = computed(() => this._permissionsService.canEnableAutoAnalysis(this.selectedFiles(), this.dossier())); + readonly #canToggleAnalysis = computed(() => this._permissionsService.canToggleAnalysis(this.selectedFiles(), this.dossier())); + readonly #canOcr = computed(() => this._permissionsService.canOcrFile(this.selectedFiles(), this.dossier())); + readonly #canSetToNew = computed(() => this._permissionsService.canSetToNew(this.selectedFiles(), this.dossier())); + readonly #canSetToUnderReview = computed(() => this._permissionsService.canSetUnderReview(this.selectedFiles(), this.dossier())); + readonly #canSetToUnderApproval = computed(() => this._permissionsService.canSetUnderApproval(this.selectedFiles(), this.dossier())); + readonly #isReadyForApproval = computed(() => this._permissionsService.isReadyForApproval(this.selectedFiles(), this.dossier())); + readonly #canApprove = computed(() => this._permissionsService.canBeApproved(this.selectedFiles(), this.dossier())); + readonly #canUndoApproval = computed(() => this._permissionsService.canUndoApproval(this.selectedFiles(), this.dossier())); + readonly #assignTooltip = computed(() => + this.#allFilesAreUnderApproval() ? _('dossier-overview.assign-approver') : _('dossier-overview.assign-reviewer'), + ); + readonly #toggleAnalysisTooltip = computed(() => + this.#allFilesAreExcluded() ? _('file-preview.toggle-analysis.enable') : _('file-preview.toggle-analysis.disable'), + ); + readonly #analysisForced = signal(false); constructor( private readonly _permissionsService: PermissionsService, private readonly _userPreferenceService: UserPreferenceService, private readonly _bulkActionsService: BulkActionsService, + private readonly _rulesService: RulesService, + private readonly _toaster: Toaster, ) {} - private get _buttons(): Action[] { + get #buttons(): Action[] { const actions: Action[] = [ { id: 'delete-files-btn', type: ActionTypes.circleBtn, - action: () => this._bulkActionsService.delete(this.selectedFiles), + action: () => this._bulkActionsService.delete(this.selectedFiles()), tooltip: _('dossier-overview.bulk.delete'), icon: 'iqser:trash', - show: this.#canDelete, + show: this.#canDelete(), }, { id: 'assign-files-btn', type: ActionTypes.circleBtn, - action: () => this._bulkActionsService.assign(this.selectedFiles), - tooltip: this.#assignTooltip, + action: () => this._bulkActionsService.assign(this.selectedFiles()), + tooltip: this.#assignTooltip(), icon: 'red:assign', - show: this.#canAssign, + show: this.#canAssign(), }, { id: 'assign-files-to-me-btn', type: ActionTypes.circleBtn, - action: () => this._bulkActionsService.assignToMe(this.selectedFiles), + action: () => this._bulkActionsService.assignToMe(this.selectedFiles()), tooltip: _('dossier-overview.assign-me'), icon: 'red:assign-me', - show: this.#canAssignToSelf, + show: this.#canAssignToSelf(), }, { id: 'to-new-btn', type: ActionTypes.circleBtn, - action: () => this._bulkActionsService.setToNew(this.selectedFiles), + action: () => this._bulkActionsService.setToNew(this.selectedFiles()), tooltip: _('dossier-overview.back-to-new'), icon: 'red:undo', - show: this.#canSetToNew, + show: this.#canSetToNew(), }, { id: 'to-under-approval-btn', type: ActionTypes.circleBtn, - action: () => this._bulkActionsService.setToUnderApproval(this.selectedFiles), + action: () => this._bulkActionsService.setToUnderApproval(this.selectedFiles()), tooltip: _('dossier-overview.under-approval'), icon: 'red:ready-for-approval', - show: this.#canSetToUnderApproval, + show: this.#canSetToUnderApproval(), }, { id: 'to-under-review-btn', type: ActionTypes.circleBtn, - action: () => this._bulkActionsService.backToUnderReview(this.selectedFiles), + action: () => this._bulkActionsService.backToUnderReview(this.selectedFiles()), tooltip: _('dossier-overview.under-review'), icon: 'red:undo', - show: this.#canSetToUnderReview, + show: this.#canSetToUnderReview(), }, { id: 'download-files-btn', type: ActionTypes.downloadBtn, - show: !this.selectedFiles.some(file => file.processingStatus === ProcessingFileStatuses.ERROR || !file.lastProcessed), - files: this.selectedFiles, - dossier: this.dossier, + show: !this.selectedFiles().some(file => file.processingStatus === ProcessingFileStatuses.ERROR || !file.lastProcessed), + files: this.selectedFiles(), + dossier: this.dossier(), }, { id: 'approve-files-btn', type: ActionTypes.circleBtn, - action: () => this._bulkActionsService.approve(this.selectedFiles), + action: () => this._bulkActionsService.approve(this.selectedFiles()), disabled: !this.#canApprove, tooltip: this.#canApprove ? _('dossier-overview.approve') : _('dossier-overview.approve-disabled'), icon: 'red:approved', - show: this.#isReadyForApproval, + show: this.#isReadyForApproval(), }, { id: 'set-under-approval-btn', type: ActionTypes.circleBtn, - action: () => this._bulkActionsService.setToUnderApproval(this.selectedFiles), + action: () => this._bulkActionsService.setToUnderApproval(this.selectedFiles()), tooltip: _('dossier-overview.under-approval'), icon: 'red:undo', - show: this.#canUndoApproval, + show: this.#canUndoApproval(), }, { id: 'ocr-files-btn', type: ActionTypes.circleBtn, - action: () => this._bulkActionsService.ocr(this.selectedFiles), + action: () => this._bulkActionsService.ocr(this.selectedFiles()), tooltip: _('dossier-overview.ocr-file'), icon: 'iqser:ocr', - show: this.#canOcr, + show: this.#canOcr(), }, { id: 'reanalyse-files-btn', type: ActionTypes.circleBtn, - action: () => this._bulkActionsService.reanalyse(this.selectedFiles), - tooltip: _('dossier-overview.bulk.reanalyse'), + action: () => this.#reanalyseBulk(this.selectedFiles()), + tooltip: this.#areRulesLocked() ? _('dossier-listing.rules.timeoutError') : _('dossier-overview.bulk.reanalyse'), icon: 'iqser:refresh', + disabled: this.#areRulesLocked(), show: - this.#canReanalyse && - (this.#analysisForced || this.#canEnableAutoAnalysis || this.selectedFiles.every(file => file.isError)), + this.#canReanalyse() && + (this.#analysisForced() || this.#canEnableAutoAnalysis() || this.selectedFiles().every(file => file.isError)), }, { id: 'stop-automatic-analysis-btn', type: ActionTypes.circleBtn, - action: () => this._bulkActionsService.toggleAutomaticAnalysis(this.selectedFiles), + action: () => this._bulkActionsService.toggleAutomaticAnalysis(this.selectedFiles()), tooltip: _('dossier-overview.stop-auto-analysis'), icon: 'red:disable-analysis', - show: this.#canDisableAutoAnalysis, + show: this.#canDisableAutoAnalysis(), }, { id: 'start-automatic-analysis-btn', type: ActionTypes.circleBtn, - action: () => this._bulkActionsService.toggleAutomaticAnalysis(this.selectedFiles), + action: () => this._bulkActionsService.toggleAutomaticAnalysis(this.selectedFiles()), tooltip: _('dossier-overview.start-auto-analysis'), icon: 'red:enable-analysis', - show: this.#canEnableAutoAnalysis, + show: this.#canEnableAutoAnalysis(), }, { id: 'toggle-analysis-btn', type: ActionTypes.toggle, - action: () => this._bulkActionsService.toggleAnalysis(this.selectedFiles, !this.#allFilesAreExcluded), - tooltip: this.#toggleAnalysisTooltip, - checked: !this.#allFilesAreExcluded, - show: this.#canToggleAnalysis, + action: () => this._bulkActionsService.toggleAnalysis(this.selectedFiles(), !this.#allFilesAreExcluded()), + tooltip: this.#toggleAnalysisTooltip(), + checked: !this.#allFilesAreExcluded(), + show: this.#canToggleAnalysis(), }, ]; return actions.filter(btn => btn.show); } - ngOnChanges() { - this._setup(); - } - forceReanalysisAction($event: LongPressEvent) { - this.#analysisForced = !$event.touchEnd && this._userPreferenceService.isIqserDevMode; - this._setup(); + this.#analysisForced.set(!$event.touchEnd && this._userPreferenceService.isIqserDevMode); } - private _setup() { - if (!this.selectedFiles.length) { + async #reanalyseBulk(selectedFiles: File[]) { + const rules = await firstValueFrom(this._rulesService.getFor(this.dossier().dossierTemplateId)); + if (rules.timeoutDetected) { + this._toaster.error(_('dossier-listing.rules.timeoutError')); return; } - const allFilesAreUnderReviewOrUnassigned = this.selectedFiles.reduce( - (acc, file) => acc && (file.isUnderReview || file.isNew), - true, - ); - const allFilesAreUnderApproval = this.selectedFiles.reduce((acc, file) => acc && file.isUnderApproval, true); - const allFilesAreApproved = this.selectedFiles.reduce((acc, file) => acc && file.isApproved, true); - this.#allFilesAreExcluded = this.selectedFiles.reduce((acc, file) => acc && file.excluded, true); - this.#canMoveToSameState = allFilesAreUnderReviewOrUnassigned || allFilesAreUnderApproval || allFilesAreApproved; - - this.#canAssign = - this.#canMoveToSameState && - (this._permissionsService.canAssignUser(this.selectedFiles, this.dossier) || - this._permissionsService.canUnassignUser(this.selectedFiles, this.dossier)); - this.#canAssignToSelf = this.#canMoveToSameState && this._permissionsService.canAssignToSelf(this.selectedFiles, this.dossier); - - this.#canDelete = this._permissionsService.canSoftDeleteFile(this.selectedFiles, this.dossier); - - this.#canReanalyse = this._permissionsService.canReanalyseFile(this.selectedFiles, this.dossier); - - this.#canDisableAutoAnalysis = this._permissionsService.canDisableAutoAnalysis(this.selectedFiles, this.dossier); - - this.#canEnableAutoAnalysis = this._permissionsService.canEnableAutoAnalysis(this.selectedFiles, this.dossier); - - this.#canToggleAnalysis = this._permissionsService.canToggleAnalysis(this.selectedFiles, this.dossier); - - this.#canOcr = this._permissionsService.canOcrFile(this.selectedFiles, this.dossier); - - this.#canSetToNew = this._permissionsService.canSetToNew(this.selectedFiles, this.dossier); - - this.#canSetToUnderReview = this._permissionsService.canSetUnderReview(this.selectedFiles, this.dossier); - - this.#canSetToUnderApproval = this._permissionsService.canSetUnderApproval(this.selectedFiles, this.dossier); - - this.#isReadyForApproval = this._permissionsService.isReadyForApproval(this.selectedFiles, this.dossier); - - this.#canApprove = this._permissionsService.canBeApproved(this.selectedFiles, this.dossier); - - this.#canUndoApproval = this._permissionsService.canUndoApproval(this.selectedFiles, this.dossier); - - this.#assignTooltip = allFilesAreUnderApproval ? _('dossier-overview.assign-approver') : _('dossier-overview.assign-reviewer'); - - this.#toggleAnalysisTooltip = this.#allFilesAreExcluded - ? _('file-preview.toggle-analysis.enable') - : _('file-preview.toggle-analysis.disable'); - - this.buttons = this._buttons; + await this._bulkActionsService.reanalyse(selectedFiles); } } diff --git a/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details/dossier-details.component.ts b/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details/dossier-details.component.ts index 28b16bab9..44df12fcd 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details/dossier-details.component.ts +++ b/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details/dossier-details.component.ts @@ -1,7 +1,15 @@ import { AsyncPipe, NgForOf, NgIf, NgTemplateOutlet } from '@angular/common'; import { Component, EventEmitter, Input, Output } from '@angular/core'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; -import { CircleButtonComponent, CircleButtonTypes, getConfig, IqserLoadingModule, ProgressBarConfigModel, Toaster } from '@iqser/common-ui'; +import { + CircleButtonComponent, + CircleButtonTypes, + getConfig, + IqserAllowDirective, + IqserLoadingModule, + ProgressBarConfigModel, + Toaster, +} from '@iqser/common-ui'; import { FilterService, INestedFilter } from '@iqser/common-ui/lib/filtering'; import { getCurrentUser, InitialsAvatarComponent } from '@iqser/common-ui/lib/users'; import { ContextComponent, getParam, IqserTooltipPositions, shareLast } from '@iqser/common-ui/lib/utils'; @@ -61,6 +69,7 @@ interface DossierDetailsContext { AssignUserDropdownComponent, InitialsAvatarComponent, TeamMembersComponent, + IqserAllowDirective, ], }) export class DossierDetailsComponent extends ContextComponent { 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 876db0eb1..e3d361530 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 +62,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, @@ -74,6 +79,7 @@ export class DossierOverviewScreenHeaderComponent implements OnInit { private readonly _loadingService: LoadingService, private readonly _primaryFileAttributeService: PrimaryFileAttributeService, private readonly _componentLogService: ComponentLogService, + private readonly _rulesService: RulesService, ) { const someNotProcessed$ = this.entitiesService.all$.pipe(some(file => !file.lastProcessed)); this.downloadFilesDisabled$ = combineLatest([this.listingService.areSomeSelected$, someNotProcessed$]).pipe( @@ -85,13 +91,19 @@ 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(); + const rules = await firstValueFrom(this._rulesService.getFor(this.dossier().dossierTemplateId)); + if (rules.timeoutDetected) { + this._toaster.error(_('dossier-listing.rules.timeoutError')); + this._loadingService.stop(); + return; + } 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')); @@ -102,12 +114,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']; @@ -130,10 +142,10 @@ export class DossierOverviewScreenHeaderComponent implements OnInit { } downloadComponentAsJSON() { - return firstValueFrom(this._componentLogService.exportJSON(this.dossier.dossierTemplateId, this.dossier.dossierId)); + return firstValueFrom(this._componentLogService.exportJSON(this.dossier().dossierTemplateId, this.dossier().dossierId)); } async downloadComponentAsXML() { - return firstValueFrom(this._componentLogService.exportXML(this.dossier.dossierTemplateId, this.dossier.dossierId)); + return firstValueFrom(this._componentLogService.exportXML(this.dossier().dossierTemplateId, this.dossier().dossierId)); } } diff --git a/apps/red-ui/src/app/modules/shared-dossiers/components/file-actions/file-actions.component.html b/apps/red-ui/src/app/modules/shared-dossiers/components/file-actions/file-actions.component.html index 1f9e0bfc3..eb95e24d4 100644 --- a/apps/red-ui/src/app/modules/shared-dossiers/components/file-actions/file-actions.component.html +++ b/apps/red-ui/src/app/modules/shared-dossiers/components/file-actions/file-actions.component.html @@ -1,25 +1,25 @@ -
+
- + - +
- +
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 8cda2b996..234ddd09a 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,4 @@ -import { ChangeDetectorRef, Component, HostBinding, Injector, Input, OnChanges, Optional, ViewChild } from '@angular/core'; +import { Component, computed, HostBinding, Injector, input, 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'; @@ -36,6 +36,7 @@ import { FileAssignService } from '../../services/file-assign.service'; import { ProcessingIndicatorComponent } from '@shared/components/processing-indicator/processing-indicator.component'; import { StatusBarComponent } from '@common-ui/shared'; import { NgIf, NgTemplateOutlet } from '@angular/common'; +import { RulesService } from '../../../admin/services/rules.service'; @Component({ selector: 'redaction-file-actions', @@ -44,51 +45,92 @@ import { NgIf, NgTemplateOutlet } from '@angular/common'; standalone: true, imports: [ProcessingIndicatorComponent, StatusBarComponent, LongPressDirective, ExpandableFileActionsComponent, NgTemplateOutlet, NgIf], }) -export class FileActionsComponent implements OnChanges { - @Input({ required: true }) file: File; - @Input({ required: true }) dossier: Dossier; - @Input({ required: true }) type: 'file-preview' | 'dossier-overview-list' | 'dossier-overview-workflow'; - @Input() maxWidth: number; - @Input() minWidth: number; - @Input() helpModeKeyPrefix: 'dossier' | 'editor' = 'dossier'; - readonly currentUser = getCurrentUser(); - toggleTooltip?: string; - assignTooltip?: string; - showDownload = false; - showSetToNew = false; - showUndoApproval = false; - showAssignToSelf = false; - showImportRedactions = false; - showAssign = false; - showDelete = false; - showOCR = false; - canReanalyse = false; - canDisableAutoAnalysis = false; - canEnableAutoAnalysis = false; - showUnderReview = false; - showUnderApproval = false; - showApprove = false; - canToggleAnalysis = false; - showToggleAnalysis = false; - showStatusBar = false; - showReanalyseFilePreview = false; - showReanalyseDossierOverview = false; - analysisForced = false; - isDossierOverview = false; - isDossierOverviewList = false; - isDossierOverviewWorkflow = false; - isFilePreview = false; - isDossierMember = false; - tooltipPosition = IqserTooltipPositions.above; - buttons: Action[]; +export class FileActionsComponent { @ViewChild(ExpandableFileActionsComponent) private readonly _expandableActionsComponent: ExpandableFileActionsComponent; + readonly file = input.required(); + readonly dossier = input.required(); + readonly type = input.required<'file-preview' | 'dossier-overview-list' | 'dossier-overview-workflow'>(); + readonly maxWidth = input(); + readonly minWidth = input(); + readonly helpModeKeyPrefix = input<'dossier' | 'editor'>('dossier'); + readonly singleEntityAction = input(false); + readonly currentUser = getCurrentUser(); + readonly tooltipPosition = IqserTooltipPositions.above; + + readonly isDossierOverview = computed(() => this.type().startsWith('dossier-overview')); + readonly isDossierOverviewList = computed(() => this.type() === 'dossier-overview-list'); + readonly isDossierOverviewWorkflow = computed(() => this.type() === 'dossier-overview-workflow'); + readonly isFilePreview = computed(() => this.type() === 'file-preview'); + readonly buttons = computed(() => this.#buttons); + readonly showStatusBar = computed(() => !this.file().isError && !this.file().isUnprocessed && this.isDossierOverviewList()); + readonly #assignTooltip? = computed(() => + this.file().isUnderApproval ? _('dossier-overview.assign-approver') : _('dossier-overview.assign-reviewer'), + ); + readonly #showSetToNew = computed( + () => this._permissionsService.canSetToNew(this.file(), this.dossier()) && !this.isDossierOverviewWorkflow(), + ); + readonly #showUndoApproval = computed( + () => this._permissionsService.canUndoApproval(this.file(), this.dossier()) && !this.isDossierOverviewWorkflow(), + ); + readonly #showAssignToSelf = computed( + () => this._permissionsService.canAssignToSelf(this.file(), this.dossier()) && this.isDossierOverview(), + ); + readonly #showImportRedactions = computed(() => this._permissionsService.canImportRedactions(this.file(), this.dossier())); + readonly #showAssign = computed( + () => + (this._permissionsService.canAssignUser(this.file(), this.dossier()) || + this._permissionsService.canUnassignUser(this.file(), this.dossier())) && + this.isDossierOverview(), + ); + readonly #showDelete = computed(() => this._permissionsService.canSoftDeleteFile(this.file(), this.dossier())); + readonly #showOCR = computed(() => this._permissionsService.canOcrFile(this.file(), this.dossier())); + readonly #canReanalyse = computed(() => this._permissionsService.canReanalyseFile(this.file(), this.dossier())); + readonly #canEnableAutoAnalysis = computed(() => this._permissionsService.canEnableAutoAnalysis([this.file()], this.dossier())); + readonly #showUnderReview = computed( + () => this._permissionsService.canSetUnderReview(this.file(), this.dossier()) && !this.isDossierOverviewWorkflow(), + ); + readonly #showUnderApproval = computed( + () => this._permissionsService.canSetUnderApproval(this.file(), this.dossier()) && !this.isDossierOverviewWorkflow(), + ); + readonly #showApprove = computed( + () => this._permissionsService.isReadyForApproval(this.file(), this.dossier()) && !this.isDossierOverviewWorkflow(), + ); + readonly #canToggleAnalysis = computed(() => this._permissionsService.canToggleAnalysis(this.file(), this.dossier())); + readonly #toggleTooltip? = computed(() => { + if (!this.#canToggleAnalysis()) { + return _('file-preview.toggle-analysis.only-managers'); + } + return this.file()?.excluded ? _('file-preview.toggle-analysis.enable') : _('file-preview.toggle-analysis.disable'); + }); + readonly #showToggleAnalysis = computed( + () => !!this.file().lastProcessed && this._permissionsService.showToggleAnalysis(this.dossier()), + ); + readonly #analysisForced = signal(false); + readonly #showReanalyse = computed( + () => (this.#canReanalyse() || this.file().excludedFromAutomaticAnalysis || this.#analysisForced()) && !this.file().dossierArchived, + ); + readonly #isDossierMember = computed(() => this._permissionsService.isDossierMember(this.dossier())); + readonly #showDownload = computed( + () => this._permissionsService.canDownloadRedactedFile() && !!this.file().lastProcessed && this.#isDossierMember(), + ); + readonly #showReanalyseFilePreview = computed( + () => this.#showReanalyse() && this.isFilePreview() && !this.file().isApproved && this.#isDossierMember(), + ); + readonly #showReanalyseDossierOverview = computed( + () => this.#showReanalyse() && this.isDossierOverview() && !this.file().isApproved && this.#isDossierMember(), + ); + readonly #ariaExpanded$ = toObservable(this._documentInfoService?.shown); + readonly #areRulesLocked = computed(() => this._rulesService.currentTemplateRules().timeoutDetected); + readonly #isDocumine = getConfig().IS_DOCUMINE; + readonly #canDisableAutoAnalysis = computed( + () => !this.#isDocumine && this._permissionsService.canDisableAutoAnalysis([this.file()], this.dossier()), + ); constructor( private readonly _injector: Injector, private readonly _filesService: FilesService, - private readonly _changeRef: ChangeDetectorRef, private readonly _loadingService: LoadingService, private readonly _dialogService: DossiersDialogService, private readonly _iqserDialog: IqserDialog, @@ -99,6 +141,8 @@ export class FileActionsComponent implements OnChanges { private readonly _activeDossiersService: ActiveDossiersService, private readonly _fileManagementService: FileManagementService, private readonly _userPreferenceService: UserPreferenceService, + private readonly _rulesService: RulesService, + private readonly _toasterService: Toaster, readonly fileAttributesService: FileAttributesService, @Optional() private readonly _documentInfoService: DocumentInfoService, @Optional() private readonly _excludedPagesService: ExcludedPagesService, @@ -109,15 +153,7 @@ export class FileActionsComponent implements OnChanges { return !!this._expandableActionsComponent?.expanded; } - private get _toggleTooltip(): string { - if (!this.canToggleAnalysis) { - return _('file-preview.toggle-analysis.only-managers'); - } - - return this.file?.excluded ? _('file-preview.toggle-analysis.enable') : _('file-preview.toggle-analysis.disable'); - } - - private get _buttons(): Action[] { + get #buttons() { const actions: Action[] = [ { id: 'btn-delete_file', @@ -125,16 +161,16 @@ export class FileActionsComponent implements OnChanges { action: () => this.#openDeleteFileDialog(), tooltip: _('dossier-overview.delete.action'), icon: 'iqser:trash', - show: this.showDelete, + show: this.#showDelete(), helpModeKey: 'delete_file', }, { id: 'btn-assign', type: ActionTypes.circleBtn, action: () => this.#assign(), - tooltip: this.assignTooltip, + tooltip: this.#assignTooltip(), icon: 'red:assign', - show: this.showAssign, + show: this.#showAssign(), helpModeKey: 'assign_user', }, { @@ -143,7 +179,7 @@ export class FileActionsComponent implements OnChanges { action: () => this.#assignToMe(), tooltip: _('dossier-overview.assign-me'), icon: 'red:assign-me', - show: this.showAssignToSelf, + show: this.#showAssignToSelf(), helpModeKey: 'assign_user', }, { @@ -152,17 +188,17 @@ export class FileActionsComponent implements OnChanges { action: () => this.#openImportRedactionsDialog(), tooltip: _('dossier-overview.import-redactions'), icon: 'red:import_redactions', - show: this.showImportRedactions && !this._iqserPermissionsService.has(Roles.getRss), + show: this.#showImportRedactions() && !this._iqserPermissionsService.has(Roles.getRss), helpModeKey: 'import_redactions', }, { id: 'btn-download_file', type: ActionTypes.downloadBtn, - files: [this.file], - dossier: this.dossier, + files: [this.file()], + dossier: this.dossier(), tooltipClass: 'small', - show: this.showDownload, - disabled: this.file.processingStatus === ProcessingFileStatuses.ERROR, + show: this.#showDownload(), + disabled: this.file().processingStatus === ProcessingFileStatuses.ERROR, helpModeKey: 'download', }, { @@ -170,7 +206,7 @@ export class FileActionsComponent implements OnChanges { type: ActionTypes.circleBtn, action: () => this.#toggleDocumentInfo(), tooltip: _('file-preview.document-info'), - ariaExpanded: toObservable(this._documentInfoService?.shown, { injector: this._injector }), + ariaExpanded: this.#ariaExpanded$, icon: 'red:status-info', show: !!this._documentInfoService, helpModeKey: 'document_info', @@ -180,10 +216,10 @@ export class FileActionsComponent implements OnChanges { type: ActionTypes.circleBtn, action: () => this.#toggleExcludePages(), tooltip: _('file-preview.exclude-pages'), - ariaExpanded: toObservable(this._excludedPagesService?.shown, { injector: this._injector }), - showDot: !!this.file.excludedPages?.length, + ariaExpanded: this.#ariaExpanded$, + showDot: !!this.file().excludedPages?.length, icon: 'red:exclude-pages', - show: !!this._excludedPagesService && this._permissionsService.canExcludePages(this.file, this.dossier), + show: !!this._excludedPagesService && this._permissionsService.canExcludePages(this.file(), this.dossier()), helpModeKey: 'exclude_pages', }, { @@ -192,7 +228,7 @@ export class FileActionsComponent implements OnChanges { action: () => this.#setToNew(), tooltip: _('dossier-overview.back-to-new'), icon: 'red:undo', - show: this.showSetToNew, + show: this.#showSetToNew(), helpModeKey: 'change_status', }, { @@ -201,7 +237,7 @@ export class FileActionsComponent implements OnChanges { action: () => this.#setFileUnderApproval(), tooltip: _('dossier-overview.under-approval'), icon: 'red:ready-for-approval', - show: this.showUnderApproval, + show: this.#showUnderApproval(), helpModeKey: 'change_status', }, { @@ -210,17 +246,17 @@ export class FileActionsComponent implements OnChanges { action: () => this.#setFileUnderReview(), tooltip: _('dossier-overview.under-review'), icon: 'red:undo', - show: this.showUnderReview, + show: this.#showUnderReview(), helpModeKey: 'change_status', }, { id: 'btn-set_file_approved', type: ActionTypes.circleBtn, action: () => this.setFileApproved(), - tooltip: this.file.canBeApproved ? _('dossier-overview.approve') : _('dossier-overview.approve-disabled'), + tooltip: this.file().canBeApproved ? _('dossier-overview.approve') : _('dossier-overview.approve-disabled'), icon: 'red:approved', - disabled: !this.file.canBeApproved, - show: this.showApprove, + disabled: !this.file().canBeApproved, + show: this.#showApprove(), helpModeKey: 'change_status', }, { @@ -229,18 +265,17 @@ export class FileActionsComponent implements OnChanges { action: () => this.#toggleAutomaticAnalysis(), tooltip: _('dossier-overview.stop-auto-analysis'), icon: 'red:disable-analysis', - show: this.canDisableAutoAnalysis, + show: this.#canDisableAutoAnalysis(), helpModeKey: 'stop_analysis', }, { id: 'btn-reanalyse_file_preview', type: ActionTypes.circleBtn, action: () => this.#reanalyseFile(), - tooltip: _('file-preview.reanalyse-notification'), - tooltipClass: 'small', + tooltip: this.#areRulesLocked() ? _('dossier-listing.rules.timeoutError') : _('file-preview.reanalyse-notification'), icon: 'iqser:refresh', - show: this.showReanalyseFilePreview, - disabled: this.file.isProcessing, + show: this.#showReanalyseFilePreview(), + disabled: this.file().isProcessing || this.#areRulesLocked(), helpModeKey: 'stop_analysis', }, { @@ -248,9 +283,9 @@ export class FileActionsComponent implements OnChanges { type: ActionTypes.circleBtn, action: () => this.#toggleAutomaticAnalysis(), tooltip: _('dossier-overview.start-auto-analysis'), - buttonType: this.isFilePreview ? CircleButtonTypes.warn : CircleButtonTypes.default, + buttonType: this.isFilePreview() ? CircleButtonTypes.warn : CircleButtonTypes.default, icon: 'red:enable-analysis', - show: this.canEnableAutoAnalysis, + show: this.#canEnableAutoAnalysis(), helpModeKey: 'stop_analysis', }, { @@ -259,7 +294,7 @@ export class FileActionsComponent implements OnChanges { action: () => this.#setFileUnderApproval(), tooltip: _('dossier-overview.under-approval'), icon: 'red:undo', - show: this.showUndoApproval, + show: this.#showUndoApproval(), helpModeKey: 'change_status', }, { @@ -268,27 +303,28 @@ export class FileActionsComponent implements OnChanges { action: () => this.#ocrFile(), tooltip: _('dossier-overview.ocr-file'), icon: 'iqser:ocr', - show: this.showOCR, + show: this.#showOCR(), helpModeKey: 'automatic_text_recognition', }, { 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, + show: this.#showReanalyseDossierOverview(), + disabled: this.#areRulesLocked(), helpModeKey: 'stop_analysis', }, { id: 'btn-toggle_analysis', type: ActionTypes.toggle, action: () => this.#toggleAnalysis(), - disabled: !this.canToggleAnalysis, - tooltip: this.toggleTooltip, - class: { 'mr-24': this.isDossierOverviewList }, - checked: !this.file.excluded, - show: this.showToggleAnalysis && this.isDossierMember, + disabled: !this.#canToggleAnalysis, + tooltip: this.#toggleTooltip(), + class: { 'mr-24': this.isDossierOverviewList() }, + checked: !this.file().excluded, + show: this.#showToggleAnalysis() && this.#isDossierMember(), helpModeKey: 'disable_extraction', }, ]; @@ -296,33 +332,28 @@ export class FileActionsComponent implements OnChanges { return actions.filter(btn => btn.show); } - ngOnChanges() { - this.#setup(); - } - async setFileApproved() { - if (!this.file.analysisRequired && !this.file.hasUpdates) { + if (!this.file().analysisRequired && !this.file().hasUpdates) { await this.#setFileApproved(); return; } const data: IConfirmationDialogData = { - title: this.file.analysisRequired + title: this.file().analysisRequired ? _('confirmation-dialog.approve-file-without-analysis.title') : _('confirmation-dialog.approve-file.title'), - question: this.file.analysisRequired + question: this.file().analysisRequired ? _('confirmation-dialog.approve-file-without-analysis.question') : _('confirmation-dialog.approve-file.question'), - confirmationText: this.file.analysisRequired ? _('confirmation-dialog.approve-file-without-analysis.confirmationText') : null, - denyText: this.file.analysisRequired ? _('confirmation-dialog.approve-file-without-analysis.denyText') : null, + confirmationText: this.file().analysisRequired ? _('confirmation-dialog.approve-file-without-analysis.confirmationText') : null, + denyText: this.file().analysisRequired ? _('confirmation-dialog.approve-file-without-analysis.denyText') : null, }; this._dialogService.openDialog('confirm', data, () => this.#setFileApproved()); } forceReanalysisAction($event: LongPressEvent) { - this.analysisForced = !$event.touchEnd && this._userPreferenceService.isIqserDevMode; - this.#setup(); + this.#analysisForced.set(!$event.touchEnd && this._userPreferenceService.isIqserDevMode); } #showOCRConfirmationDialog(): Observable { @@ -337,7 +368,7 @@ export class FileActionsComponent implements OnChanges { } #openImportRedactionsDialog() { - this._dialogService.openDialog('importRedactions', { dossierId: this.file.dossierId, fileId: this.file.fileId }); + this._dialogService.openDialog('importRedactions', { dossierId: this.file().dossierId, fileId: this.file().fileId }); } #openDeleteFileDialog() { @@ -350,8 +381,8 @@ export class FileActionsComponent implements OnChanges { async () => { this._loadingService.start(); try { - const dossier = this._activeDossiersService.find(this.file.dossierId); - await firstValueFrom(this._fileManagementService.delete([this.file], this.file.dossierId)); + const dossier = this._activeDossiersService.find(this.file().dossierId); + await firstValueFrom(this._fileManagementService.delete([this.file()], this.file().dossierId)); await this._injector.get(Router).navigate([dossier.routerLink]); } catch (error) { this._injector.get(Toaster).error(_('error.http.generic'), { params: error }); @@ -362,8 +393,8 @@ export class FileActionsComponent implements OnChanges { } #assign() { - const files = [this.file]; - const targetStatus = this.file.workflowStatus; + const files = [this.file()]; + const targetStatus = this.file().workflowStatus; const withCurrentUserAsDefault = true; const withUnassignedOption = true; this._iqserDialog.openDefault(AssignReviewerApproverDialogComponent, { @@ -377,29 +408,34 @@ export class FileActionsComponent implements OnChanges { } async #assignToMe() { - await this._fileAssignService.assignToMe([this.file]); + await this._fileAssignService.assignToMe([this.file()]); } async #reanalyseFile() { + const rules = await firstValueFrom(this._rulesService.getFor(this.dossier().dossierTemplateId)); + if (rules.timeoutDetected) { + this._toasterService.error(_('dossier-listing.rules.timeoutError')); + return; + } const params: ReanalyzeQueryParams = { force: true, triggeredByUser: true, }; - await this._reanalysisService.reanalyzeFilesForDossier([this.file], this.file.dossierId, params); + await this._reanalysisService.reanalyzeFilesForDossier([this.file()], this.file().dossierId, params); } async #toggleAutomaticAnalysis() { this._loadingService.start(); - await firstValueFrom(this._reanalysisService.toggleAutomaticAnalysis(this.file.dossierId, [this.file])); + await firstValueFrom(this._reanalysisService.toggleAutomaticAnalysis(this.file().dossierId, [this.file()])); this._loadingService.stop(); } async #setFileUnderApproval() { - await this._fileAssignService.assignApprover(this.file, true); + await this._fileAssignService.assignApprover(this.file(), true); } async #ocrFile() { - if (this.file.lastManualChangeDate) { + if (this.file().lastManualChangeDate) { const confirm = await firstValueFrom(this.#showOCRConfirmationDialog()); if (!confirm) { return; @@ -412,92 +448,47 @@ export class FileActionsComponent implements OnChanges { viewerHeaderService.disableRotationButtons(); this._loadingService.start(); - await this._reanalysisService.ocrFiles([this.file], this.file.dossierId); + await this._reanalysisService.ocrFiles([this.file()], this.file().dossierId); this._loadingService.stop(); } async #setFileUnderReview() { - await this._fileAssignService.assignReviewer(this.file, true); + await this._fileAssignService.assignReviewer(this.file(), true); } async #toggleAnalysis() { this._loadingService.start(); - await this._reanalysisService.toggleAnalysis(this.file.dossierId, [this.file], !this.file.excluded); + await this._reanalysisService.toggleAnalysis(this.file().dossierId, [this.file()], !this.file().excluded); this._loadingService.stop(); } - #setup() { - this.isDossierOverviewList = this.type === 'dossier-overview-list'; - this.isDossierOverviewWorkflow = this.type === 'dossier-overview-workflow'; - this.isDossierOverview = this.type.startsWith('dossier-overview'); - this.isFilePreview = this.type === 'file-preview'; - - this.assignTooltip = this.file.isUnderApproval ? _('dossier-overview.assign-approver') : _('dossier-overview.assign-reviewer'); - this.showAssign = - (this._permissionsService.canAssignUser(this.file, this.dossier) || - this._permissionsService.canUnassignUser(this.file, this.dossier)) && - this.isDossierOverview; - - this.showAssignToSelf = this._permissionsService.canAssignToSelf(this.file, this.dossier) && this.isDossierOverview; - this.showImportRedactions = this._permissionsService.canImportRedactions(this.file, this.dossier); - - this.showSetToNew = this._permissionsService.canSetToNew(this.file, this.dossier) && !this.isDossierOverviewWorkflow; - this.showUndoApproval = this._permissionsService.canUndoApproval(this.file, this.dossier) && !this.isDossierOverviewWorkflow; - this.showUnderReview = this._permissionsService.canSetUnderReview(this.file, this.dossier) && !this.isDossierOverviewWorkflow; - this.showUnderApproval = this._permissionsService.canSetUnderApproval(this.file, this.dossier) && !this.isDossierOverviewWorkflow; - this.showApprove = this._permissionsService.isReadyForApproval(this.file, this.dossier) && !this.isDossierOverviewWorkflow; - - this.canToggleAnalysis = this._permissionsService.canToggleAnalysis(this.file, this.dossier); - this.showToggleAnalysis = !!this.file.lastProcessed && this._permissionsService.showToggleAnalysis(this.dossier); - this.toggleTooltip = this._toggleTooltip; - this.isDossierMember = this._permissionsService.isDossierMember(this.dossier); - - this.showDelete = this._permissionsService.canSoftDeleteFile(this.file, this.dossier); - this.showOCR = this._permissionsService.canOcrFile(this.file, this.dossier); - this.canReanalyse = this._permissionsService.canReanalyseFile(this.file, this.dossier); - this.canDisableAutoAnalysis = !this.#isDocumine && this._permissionsService.canDisableAutoAnalysis([this.file], this.dossier); - this.canEnableAutoAnalysis = this._permissionsService.canEnableAutoAnalysis([this.file], this.dossier); - - this.showStatusBar = !this.file.isError && !this.file.isUnprocessed && this.isDossierOverviewList; - - const showReanalyse = this.canReanalyse || this.file.excludedFromAutomaticAnalysis || this.analysisForced; - - this.showReanalyseFilePreview = showReanalyse && this.isFilePreview && !this.file.isApproved && this.isDossierMember; - this.showReanalyseDossierOverview = showReanalyse && this.isDossierOverview && !this.file.isApproved && this.isDossierMember; - - this.showDownload = this._permissionsService.canDownloadRedactedFile() && !!this.file.lastProcessed && this.isDossierMember; - this.buttons = this._buttons; - - this._changeRef.markForCheck(); - } - async #setFileApproved() { this._loadingService.start(); - await this._filesService.setApproved(this.file); + await this._filesService.setApproved(this.file()); this._loadingService.stop(); } async #setToNew() { this._loadingService.start(); - await this._filesService.setToNew(this.file); + await this._filesService.setToNew(this.file()); this._loadingService.stop(); } #toggleExcludePages() { this._excludedPagesService.toggle(); const shown = this._excludedPagesService.shown(); - setLocalStorageDataByFileId(this.file.id, 'show-exclude-pages', shown); + setLocalStorageDataByFileId(this.file().id, 'show-exclude-pages', shown); if (shown) { - setLocalStorageDataByFileId(this.file.id, 'show-document-info', false); + setLocalStorageDataByFileId(this.file().id, 'show-document-info', false); } } #toggleDocumentInfo() { this._documentInfoService.toggle(); const shown = this._documentInfoService.shown(); - setLocalStorageDataByFileId(this.file.id, 'show-document-info', shown); + setLocalStorageDataByFileId(this.file().id, 'show-document-info', shown); if (shown) { - setLocalStorageDataByFileId(this.file.id, 'show-exclude-pages', false); + setLocalStorageDataByFileId(this.file().id, 'show-exclude-pages', false); } } } diff --git a/apps/red-ui/src/assets/i18n/redact/de.json b/apps/red-ui/src/assets/i18n/redact/de.json index 2f884a217..d8c770fe2 100644 --- a/apps/red-ui/src/assets/i18n/redact/de.json +++ b/apps/red-ui/src/assets/i18n/redact/de.json @@ -913,6 +913,9 @@ "reanalyse": { "action": "Ganzes Dossier analysieren" }, + "rules": { + "timeoutError": "Regeln für Dossier-Vorlagen gesperrt!" + }, "stats": { "analyzed-pages": "{count, plural, one{Seite} other{Seiten}}", "total-people": "Benutzer" diff --git a/apps/red-ui/src/assets/i18n/redact/en.json b/apps/red-ui/src/assets/i18n/redact/en.json index 33c00275e..b1aa07cd8 100644 --- a/apps/red-ui/src/assets/i18n/redact/en.json +++ b/apps/red-ui/src/assets/i18n/redact/en.json @@ -913,6 +913,9 @@ "reanalyse": { "action": "Analyze entire dossier" }, + "rules": { + "timeoutError": "Dossier template rules locked!" + }, "stats": { "analyzed-pages": "{count, plural, one{Page} other{Pages}}", "total-people": "Total users" diff --git a/apps/red-ui/src/assets/i18n/scm/de.json b/apps/red-ui/src/assets/i18n/scm/de.json index 208af7127..d5dd72767 100644 --- a/apps/red-ui/src/assets/i18n/scm/de.json +++ b/apps/red-ui/src/assets/i18n/scm/de.json @@ -913,6 +913,9 @@ "reanalyse": { "action": "Gesamtes Dossier analysieren" }, + "rules": { + "timeoutError": "Regeln für Dossier-Vorlagen gesperrt!" + }, "stats": { "analyzed-pages": "{count, plural, one{Page} other{Pages}}", "total-people": "Anzahl der Benutzer" diff --git a/apps/red-ui/src/assets/i18n/scm/en.json b/apps/red-ui/src/assets/i18n/scm/en.json index 3d38b1eee..c303c34f7 100644 --- a/apps/red-ui/src/assets/i18n/scm/en.json +++ b/apps/red-ui/src/assets/i18n/scm/en.json @@ -913,6 +913,9 @@ "reanalyse": { "action": "Analyze entire dossier" }, + "rules": { + "timeoutError": "Dossier template rules locked!" + }, "stats": { "analyzed-pages": "{count, plural, one{Page} other{Pages}}", "total-people": "Total users"