diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/bulk-actions/dossier-overview-bulk-actions.component.ts b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/bulk-actions/dossier-overview-bulk-actions.component.ts index 90d3354dd..72d1e1ae3 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/bulk-actions/dossier-overview-bulk-actions.component.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/bulk-actions/dossier-overview-bulk-actions.component.ts @@ -19,24 +19,26 @@ export class DossierOverviewBulkActionsComponent implements OnChanges { @Input() @Required() selectedFiles: File[]; @Input() buttonType: CircleButtonType = CircleButtonTypes.dark; @Input() maxWidth: number; - - analysisForced: boolean; - canAssignToSelf: boolean; - canAssign: boolean; - canDelete: boolean; - canReanalyse: boolean; - canDisableAutoAnalysis: boolean; - canEnableAutoAnalysis: boolean; - canOcr: boolean; - canSetToUnderReview: boolean; - canSetToUnderApproval: boolean; - isReadyForApproval: boolean; - canApprove: boolean; - canUndoApproval: boolean; - assignTooltip: string; buttons: Action[]; - private _canMoveToSameState: boolean; + #analysisForced: boolean; + #canAssignToSelf: boolean; + #canAssign: boolean; + #canDelete: boolean; + #canReanalyse: boolean; + #canDisableAutoAnalysis: boolean; + #canEnableAutoAnalysis: boolean; + #canOcr: boolean; + #canSetToUnderReview: boolean; + #canSetToUnderApproval: boolean; + #isReadyForApproval: boolean; + #canApprove: boolean; + #canUndoApproval: boolean; + #canToggleAnalysis: boolean; + #assignTooltip: string; + #toggleAnalysisTooltip: string; + #allFilesAreExcluded: boolean; + #canMoveToSameState: boolean; constructor( private readonly _permissionsService: PermissionsService, @@ -52,35 +54,35 @@ export class DossierOverviewBulkActionsComponent implements OnChanges { action: () => this._bulkActionsService.delete(this.selectedFiles), tooltip: _('dossier-overview.bulk.delete'), icon: 'iqser:trash', - show: this.canDelete, + show: this.#canDelete, }, { type: ActionTypes.circleBtn, action: () => this._bulkActionsService.assign(this.selectedFiles), - tooltip: this.assignTooltip, + tooltip: this.#assignTooltip, icon: 'red:assign', - show: this.canAssign, + show: this.#canAssign, }, { type: ActionTypes.circleBtn, action: () => this._bulkActionsService.assignToMe(this.selectedFiles), tooltip: _('dossier-overview.assign-me'), icon: 'red:assign-me', - show: this.canAssignToSelf, + show: this.#canAssignToSelf, }, { type: ActionTypes.circleBtn, action: () => this._bulkActionsService.setToUnderApproval(this.selectedFiles), tooltip: _('dossier-overview.under-approval'), icon: 'red:ready-for-approval', - show: this.canSetToUnderApproval, + show: this.#canSetToUnderApproval, }, { type: ActionTypes.circleBtn, action: () => this._bulkActionsService.backToUnderReview(this.selectedFiles), tooltip: _('dossier-overview.under-review'), icon: 'red:undo', - show: this.canSetToUnderReview, + show: this.#canSetToUnderReview, }, { type: ActionTypes.downloadBtn, @@ -90,45 +92,53 @@ export class DossierOverviewBulkActionsComponent implements OnChanges { { type: ActionTypes.circleBtn, action: () => this._bulkActionsService.approve(this.selectedFiles), - disabled: !this.canApprove, - tooltip: this.canApprove ? _('dossier-overview.approve') : _('dossier-overview.approve-disabled'), + disabled: !this.#canApprove, + tooltip: this.#canApprove ? _('dossier-overview.approve') : _('dossier-overview.approve-disabled'), icon: 'red:approved', - show: this.isReadyForApproval, + show: this.#isReadyForApproval, }, { type: ActionTypes.circleBtn, action: () => this._bulkActionsService.setToUnderApproval(this.selectedFiles), tooltip: _('dossier-overview.under-approval'), icon: 'red:undo', - show: this.canUndoApproval, + show: this.#canUndoApproval, }, { type: ActionTypes.circleBtn, action: () => this._bulkActionsService.ocr(this.selectedFiles), tooltip: _('dossier-overview.ocr-file'), icon: 'iqser:ocr', - show: this.canOcr, + show: this.#canOcr, }, { type: ActionTypes.circleBtn, action: () => this._bulkActionsService.reanalyse(this.selectedFiles), tooltip: _('dossier-overview.bulk.reanalyse'), icon: 'iqser:refresh', - show: this.canReanalyse && (this.analysisForced || this.canEnableAutoAnalysis), + show: this.#canReanalyse && (this.#analysisForced || this.#canEnableAutoAnalysis), }, { type: ActionTypes.circleBtn, - action: $event => this._bulkActionsService.toggleAutomaticAnalysis(this.selectedFiles), + action: () => this._bulkActionsService.toggleAutomaticAnalysis(this.selectedFiles), tooltip: _('dossier-overview.disable-auto-analysis'), icon: 'red:stop', - show: this.canDisableAutoAnalysis, + show: this.#canDisableAutoAnalysis, }, { type: ActionTypes.circleBtn, - action: $event => this._bulkActionsService.toggleAutomaticAnalysis(this.selectedFiles), + action: () => this._bulkActionsService.toggleAutomaticAnalysis(this.selectedFiles), tooltip: _('dossier-overview.enable-auto-analysis'), icon: 'red:play', - show: this.canEnableAutoAnalysis, + show: this.#canEnableAutoAnalysis, + }, + + { + type: ActionTypes.toggle, + action: () => this._bulkActionsService.toggleAnalysis(this.selectedFiles, !this.#allFilesAreExcluded), + tooltip: this.#toggleAnalysisTooltip, + checked: !this.#allFilesAreExcluded, + show: this.#canToggleAnalysis, }, ].filter(btn => btn.show); } @@ -138,7 +148,7 @@ export class DossierOverviewBulkActionsComponent implements OnChanges { } forceReanalysisAction($event: LongPressEvent) { - this.analysisForced = !$event.touchEnd && this._userPreferenceService.areDevFeaturesEnabled; + this.#analysisForced = !$event.touchEnd && this._userPreferenceService.areDevFeaturesEnabled; this._setup(); } @@ -151,37 +161,44 @@ export class DossierOverviewBulkActionsComponent implements OnChanges { true, ); const allFilesAreUnderApproval = this.selectedFiles.reduce((acc, file) => acc && file.isUnderApproval, true); - this._canMoveToSameState = allFilesAreUnderReviewOrUnassigned || allFilesAreUnderApproval; + this.#allFilesAreExcluded = this.selectedFiles.reduce((acc, file) => acc && file.excluded, true); + this.#canMoveToSameState = allFilesAreUnderReviewOrUnassigned || allFilesAreUnderApproval; - this.canAssign = - this._canMoveToSameState && + this.#canAssign = + this.#canMoveToSameState && this.selectedFiles.reduce( (acc, file) => (acc && this._permissionsService.canAssignUser(file)) || this._permissionsService.canUnassignUser(file), true, ); - this.canAssignToSelf = this._canMoveToSameState && this._permissionsService.canAssignToSelf(this.selectedFiles); + this.#canAssignToSelf = this.#canMoveToSameState && this._permissionsService.canAssignToSelf(this.selectedFiles); - this.canDelete = this._permissionsService.canDeleteFile(this.selectedFiles); + this.#canDelete = this._permissionsService.canDeleteFile(this.selectedFiles); - this.canReanalyse = this._permissionsService.canReanalyseFile(this.selectedFiles); + this.#canReanalyse = this._permissionsService.canReanalyseFile(this.selectedFiles); - this.canDisableAutoAnalysis = this._permissionsService.canDisableAutoAnalysis(this.selectedFiles); + this.#canDisableAutoAnalysis = this._permissionsService.canDisableAutoAnalysis(this.selectedFiles); - this.canEnableAutoAnalysis = this._permissionsService.canEnableAutoAnalysis(this.selectedFiles); + this.#canEnableAutoAnalysis = this._permissionsService.canEnableAutoAnalysis(this.selectedFiles); - this.canOcr = this.selectedFiles.reduce((acc, file) => acc && file.canBeOCRed, true); + this.#canToggleAnalysis = this._permissionsService.canToggleAnalysis(this.selectedFiles); - this.canSetToUnderReview = this._permissionsService.canSetUnderReview(this.selectedFiles) && !isWorkflow; + this.#canOcr = this.selectedFiles.reduce((acc, file) => acc && file.canBeOCRed, true); - this.canSetToUnderApproval = this._permissionsService.canSetUnderApproval(this.selectedFiles) && !isWorkflow; + this.#canSetToUnderReview = this._permissionsService.canSetUnderReview(this.selectedFiles) && !isWorkflow; - this.isReadyForApproval = this._permissionsService.isReadyForApproval(this.selectedFiles) && !isWorkflow; + this.#canSetToUnderApproval = this._permissionsService.canSetUnderApproval(this.selectedFiles) && !isWorkflow; - this.canApprove = this._permissionsService.canBeApproved(this.selectedFiles) && !isWorkflow; + this.#isReadyForApproval = this._permissionsService.isReadyForApproval(this.selectedFiles) && !isWorkflow; - this.canUndoApproval = this._permissionsService.canUndoApproval(this.selectedFiles) && !isWorkflow; + this.#canApprove = this._permissionsService.canBeApproved(this.selectedFiles) && !isWorkflow; - this.assignTooltip = allFilesAreUnderApproval ? _('dossier-overview.assign-approver') : _('dossier-overview.assign-reviewer'); + this.#canUndoApproval = this._permissionsService.canUndoApproval(this.selectedFiles) && !isWorkflow; + + 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; } diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/services/bulk-actions.service.ts b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/services/bulk-actions.service.ts index b72dbe887..d7bbdd4a5 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/services/bulk-actions.service.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/services/bulk-actions.service.ts @@ -91,6 +91,18 @@ export class BulkActionsService { this._loadingService.stop(); } + async toggleAnalysis(files: File[], excluded: boolean) { + this._loadingService.start(); + await firstValueFrom( + this._reanalysisService.toggleAnalysis( + files[0].dossierId, + files.map(f => f.id), + excluded, + ), + ); + this._loadingService.stop(); + } + async backToUnderReview(files: File[]): Promise { this._loadingService.start(); await firstValueFrom( diff --git a/apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.ts b/apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.ts index e084f178c..8b4d73884 100644 --- a/apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.ts +++ b/apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.ts @@ -345,7 +345,7 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnDestroy, private async _toggleAnalysis() { this._loadingService.start(); - await firstValueFrom(this._reanalysisService.toggleAnalysis(this.file.dossierId, this.file.fileId, !this.file.excluded)); + await firstValueFrom(this._reanalysisService.toggleAnalysis(this.file.dossierId, [this.file.fileId], !this.file.excluded)); this._loadingService.stop(); } diff --git a/apps/red-ui/src/app/services/permissions.service.ts b/apps/red-ui/src/app/services/permissions.service.ts index c1242d5c4..21404c135 100644 --- a/apps/red-ui/src/app/services/permissions.service.ts +++ b/apps/red-ui/src/app/services/permissions.service.ts @@ -23,8 +23,10 @@ export class PermissionsService { return ((file.isUnderReview || file.isNew) && this.isDossierMember(dossier)) || (file.isUnderApproval && this.isApprover(dossier)); } - canToggleAnalysis(file: File): boolean { - return this.isFileAssignee(file) && (file.isNew || file.isUnderReview || file.isUnderApproval); + canToggleAnalysis(file: File | File[]): boolean { + const files = file instanceof File ? [file] : file; + const sameState = new Set(files.map(f => f.excluded)).size === 1; + return sameState && files.reduce((acc, _file) => this._canToggleAnalysis(_file) && acc, true); } canReanalyseFile(file: File | File[]): boolean { @@ -152,6 +154,10 @@ export class PermissionsService { return (comment.user === this._userService.currentUser.id || this.isApprover(dossier)) && !file.isApproved; } + private _canToggleAnalysis(file: File): boolean { + return this.isFileAssignee(file) && (file.isNew || file.isUnderReview || file.isUnderApproval); + } + // https://jira.iqser.com/browse/RED-2787 private _canDeleteFile(file: File, dossier: Dossier): boolean { return ( diff --git a/apps/red-ui/src/app/services/reanalysis.service.ts b/apps/red-ui/src/app/services/reanalysis.service.ts index a636a7b60..03d002626 100644 --- a/apps/red-ui/src/app/services/reanalysis.service.ts +++ b/apps/red-ui/src/app/services/reanalysis.service.ts @@ -49,13 +49,13 @@ export class ReanalysisService extends GenericService { } @Validate() - toggleAnalysis(@RequiredParam() dossierId: string, @RequiredParam() fileId: string, excluded?: boolean) { + toggleAnalysis(@RequiredParam() dossierId: string, @RequiredParam() fileIds: string[], excluded?: boolean) { const queryParams: QueryParam[] = []; if (excluded) { queryParams.push({ key: 'excluded', value: excluded }); } - return this._post({}, `toggle-analysis/${dossierId}/${fileId}`, queryParams).pipe( + return this._post(fileIds, `toggle-analysis/${dossierId}/bulk`, queryParams).pipe( switchMap(() => this._filesService.loadAll(dossierId)), ); }