From 02da8e5a02e7d414550900e66acecf58f1ad9692 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Wed, 8 Dec 2021 00:21:55 +0200 Subject: [PATCH] File bulk actions service, permissions for multiple files, workflow done --- ...sign-reviewer-approver-dialog.component.ts | 2 +- ...dossier-overview-bulk-actions.component.ts | 196 ++++-------------- .../dossier-overview/config.service.ts | 62 ++---- .../dossier-overview.module.ts | 3 +- .../services/bulk-actions.service.ts | 140 +++++++++++++ .../user-management.component.ts | 6 +- .../src/app/services/permissions.service.ts | 126 +++++++---- .../src/app/services/reanalysis.service.ts | 4 +- libs/common-ui | 2 +- 9 files changed, 295 insertions(+), 246 deletions(-) create mode 100644 apps/red-ui/src/app/modules/dossier/screens/dossier-overview/services/bulk-actions.service.ts diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component.ts b/apps/red-ui/src/app/modules/dossier/dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component.ts index b5863f77e..27757ca3e 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component.ts +++ b/apps/red-ui/src/app/modules/dossier/dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component.ts @@ -66,7 +66,7 @@ export class AssignReviewerApproverDialogComponent { } private get _canUnassignFiles() { - return this.data.files.reduce((prev, file) => prev && this.permissionsService.canUnassignUser(file), true); + return this.permissionsService.canUnassignUser(this.data.files); } /** Initialize the form with: 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 445aa6a8e..633791158 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 @@ -1,15 +1,11 @@ import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; import { PermissionsService } from '@services/permissions.service'; import { Action, ActionTypes, Dossier, File } from '@red/domain'; -import { FileAssignService } from '../../../../shared/services/file-assign.service'; -import { DossiersDialogService } from '../../../../services/dossiers-dialog.service'; -import { CircleButtonType, CircleButtonTypes, ConfirmationDialogInput, LoadingService, Required } from '@iqser/common-ui'; +import { CircleButtonType, CircleButtonTypes, Required } from '@iqser/common-ui'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { LongPressEvent } from '@shared/directives/long-press.directive'; import { UserPreferenceService } from '@services/user-preference.service'; -import { FileManagementService } from '@services/entity-services/file-management.service'; -import { ReanalysisService } from '@services/reanalysis.service'; -import { FilesService } from '@services/entity-services/files.service'; +import { BulkActionsService } from '../../services/bulk-actions.service'; @Component({ selector: 'redaction-dossier-overview-bulk-actions', @@ -40,49 +36,44 @@ export class DossierOverviewBulkActionsComponent implements OnChanges { private _canMoveToSameState: boolean; constructor( - private readonly _dialogService: DossiersDialogService, - private readonly _fileManagementService: FileManagementService, - private readonly _reanalysisService: ReanalysisService, private readonly _permissionsService: PermissionsService, - private readonly _fileAssignService: FileAssignService, - private readonly _loadingService: LoadingService, private readonly _userPreferenceService: UserPreferenceService, - private readonly _filesService: FilesService, + private readonly _bulkActionsService: BulkActionsService, ) {} private get _buttons(): Action[] { return [ { type: ActionTypes.circleBtn, - action: () => this._delete(), + action: () => this._bulkActionsService.delete(this.selectedFiles), tooltip: _('dossier-overview.bulk.delete'), icon: 'iqser:trash', show: this.canDelete, }, { type: ActionTypes.circleBtn, - action: () => this._assign(), + action: () => this._bulkActionsService.assign(this.selectedFiles), tooltip: this.assignTooltip, icon: 'red:assign', show: this.canAssign, }, { type: ActionTypes.circleBtn, - action: () => this._assignToMe(), + action: () => this._bulkActionsService.assignToMe(this.selectedFiles), tooltip: _('dossier-overview.assign-me'), icon: 'red:assign-me', show: this.canAssignToSelf, }, { type: ActionTypes.circleBtn, - action: () => this._setToUnderApproval(), + action: () => this._bulkActionsService.setToUnderApproval(this.selectedFiles), tooltip: _('dossier-overview.under-approval'), icon: 'red:ready-for-approval', show: this.canSetToUnderApproval, }, { type: ActionTypes.circleBtn, - action: () => this._setToUnderReview(), + action: () => this._bulkActionsService.backToUnderReview(this.selectedFiles), tooltip: _('dossier-overview.under-review'), icon: 'red:undo', show: this.canSetToUnderReview, @@ -94,7 +85,7 @@ export class DossierOverviewBulkActionsComponent implements OnChanges { }, { type: ActionTypes.circleBtn, - action: () => this._approveDocuments(), + action: () => this._bulkActionsService.approve(this.selectedFiles), disabled: !this.canApprove, tooltip: this.canApprove ? _('dossier-overview.approve') : _('dossier-overview.approve-disabled'), icon: 'red:approved', @@ -102,21 +93,21 @@ export class DossierOverviewBulkActionsComponent implements OnChanges { }, { type: ActionTypes.circleBtn, - action: () => this._setToUnderApproval(), + action: () => this._bulkActionsService.setToUnderApproval(this.selectedFiles), tooltip: _('dossier-overview.under-approval'), icon: 'red:undo', show: this.canUndoApproval, }, { type: ActionTypes.circleBtn, - action: () => this._ocr(), + action: () => this._bulkActionsService.ocr(this.selectedFiles), tooltip: _('dossier-overview.ocr-file'), icon: 'iqser:ocr', show: this.canOcr, }, { type: ActionTypes.circleBtn, - action: () => this._reanalyse(), + action: () => this._bulkActionsService.reanalyse(this.selectedFiles), tooltip: _('dossier-overview.bulk.reanalyse'), icon: 'iqser:refresh', show: this.canReanalyse && this.analysisForced, @@ -133,159 +124,42 @@ export class DossierOverviewBulkActionsComponent implements OnChanges { this._setup(); } - private _delete() { - this._dialogService.openDialog( - 'confirm', - null, - new ConfirmationDialogInput({ - title: _('confirmation-dialog.delete-file.title'), - question: _('confirmation-dialog.delete-file.question'), - }), - async () => { - this._loadingService.start(); - await this._fileManagementService - .delete( - this.selectedFiles.map(item => item.fileId), - this.dossier.dossierId, - ) - .toPromise(); - this._loadingService.stop(); - }, - ); - } - - private async _setToUnderApproval() { - // If more than 1 approver - show dialog and ask who to assign - if (this.dossier.approverIds.length > 1) { - this._assignFiles('approver', true); - } else { - this._loadingService.start(); - await this._filesService - .setUnderApprovalFor( - this.selectedFiles.map(f => f.id), - this.dossier.id, - this.dossier.approverIds[0], - ) - .toPromise(); - this._loadingService.stop(); - } - } - - private async _reanalyse() { - this._loadingService.start(); - const fileIds = this.selectedFiles.filter(file => file.analysisRequired).map(file => file.fileId); - await this._reanalysisService.reanalyzeFilesForDossier(fileIds, this.dossier.id).toPromise(); - this._loadingService.stop(); - } - - private async _ocr() { - this._loadingService.start(); - await this._reanalysisService - .ocrFiles( - this.selectedFiles.map(f => f.fileId), - this.dossier.id, - ) - .toPromise(); - this._loadingService.stop(); - } - - private async _setToUnderReview() { - this._loadingService.start(); - await this._filesService - .setUnderReviewFor( - this.selectedFiles.map(f => f.id), - this.dossier.id, - ) - .toPromise(); - this._loadingService.stop(); - } - - private async _approveDocuments(): Promise { - const foundUpdatedFile = this.selectedFiles.find(file => file.hasUpdates); - if (foundUpdatedFile) { - this._dialogService.openDialog( - 'confirm', - null, - new ConfirmationDialogInput({ - title: _('confirmation-dialog.approve-multiple-files.title'), - question: _('confirmation-dialog.approve-multiple-files.question'), - }), - async () => { - this._loadingService.start(); - await this._filesService - .setApprovedFor( - this.selectedFiles.map(f => f.id), - this.dossier.id, - ) - .toPromise(); - this._loadingService.stop(); - }, - ); - } else { - this._loadingService.start(); - await this._filesService - .setApprovedFor( - this.selectedFiles.map(f => f.id), - this.dossier.id, - ) - .toPromise(); - this._loadingService.stop(); - } - } - - private async _assignToMe() { - await this._fileAssignService.assignToMe(this.selectedFiles); - } - - private _assign() { - const mode = this.selectedFiles[0].isUnderApproval ? 'approver' : 'reviewer'; - this._assignFiles(mode); - } - private _setup() { - const allFilesAreUnderReviewOrUnassigned = this.selectedFiles.reduce( - (acc, file) => acc && (file.isUnderReview || file.isNew), - true, - ); - const allFilesAreUnderApproval = this.selectedFiles.reduce((acc, file) => acc && file.isUnderApproval, true); - this._canMoveToSameState = allFilesAreUnderReviewOrUnassigned || allFilesAreUnderApproval; - - this.canAssign = - this._canMoveToSameState && - this.selectedFiles.reduce( - (acc, file) => (acc && this._permissionsService.canAssignUser(file)) || this._permissionsService.canUnassignUser(file), + if (this.selectedFiles.length) { + const allFilesAreUnderReviewOrUnassigned = this.selectedFiles.reduce( + (acc, file) => acc && (file.isUnderReview || file.isNew), true, ); - this.canAssignToSelf = - this._canMoveToSameState && - this.selectedFiles.reduce((acc, file) => acc && this._permissionsService.canAssignToSelf(file), true); + const allFilesAreUnderApproval = this.selectedFiles.reduce((acc, file) => acc && file.isUnderApproval, true); + this._canMoveToSameState = allFilesAreUnderReviewOrUnassigned || allFilesAreUnderApproval; - this.canDelete = this.selectedFiles.reduce((acc, file) => acc && this._permissionsService.canDeleteFile(file), true); + 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.canReanalyse = this.selectedFiles.reduce((acc, file) => acc && this._permissionsService.canReanalyseFile(file), true); + this.canDelete = this._permissionsService.canDeleteFile(this.selectedFiles); - this.canOcr = this.selectedFiles.reduce((acc, file) => acc && file.canBeOCRed, true); + this.canReanalyse = this._permissionsService.canReanalyseFile(this.selectedFiles); - this.canSetToUnderReview = this.selectedFiles.reduce((acc, file) => acc && this._permissionsService.canSetUnderReview(file), true); + this.canOcr = this.selectedFiles.reduce((acc, file) => acc && file.canBeOCRed, true); - this.canSetToUnderApproval = this.selectedFiles.reduce( - (acc, file) => acc && this._permissionsService.canSetUnderApproval(file), - true, - ); + this.canSetToUnderReview = this._permissionsService.canSetUnderReview(this.selectedFiles); - this.isReadyForApproval = this.selectedFiles.reduce((acc, file) => acc && this._permissionsService.isReadyForApproval(file), true); + this.canSetToUnderApproval = this._permissionsService.canSetUnderApproval(this.selectedFiles); - this.canApprove = this.selectedFiles.reduce((acc, file) => acc && file.canBeApproved, true); + this.isReadyForApproval = this._permissionsService.isReadyForApproval(this.selectedFiles); - this.canUndoApproval = this.selectedFiles.reduce((acc, file) => acc && this._permissionsService.canUndoApproval(file), true); + this.canApprove = this._permissionsService.canBeApproved(this.selectedFiles); - this.assignTooltip = allFilesAreUnderApproval ? _('dossier-overview.assign-approver') : _('dossier-overview.assign-reviewer'); + this.canUndoApproval = this._permissionsService.canUndoApproval(this.selectedFiles); - this.buttons = this._buttons; - } + this.assignTooltip = allFilesAreUnderApproval ? _('dossier-overview.assign-approver') : _('dossier-overview.assign-reviewer'); - private _assignFiles(mode: 'reviewer' | 'approver', ignoreChanged = false) { - const data = { mode, files: this.selectedFiles, ignoreChanged }; - this._dialogService.openDialog('assignFile', null, data); + this.buttons = this._buttons; + } } } diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/config.service.ts b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/config.service.ts index 72e1ac733..77a6b107e 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/config.service.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/config.service.ts @@ -7,14 +7,12 @@ import { List, ListingMode, ListingModes, - LoadingService, NestedFilter, TableColumnConfig, WorkflowConfig, } from '@iqser/common-ui'; import { File, IFileAttributeConfig, StatusSorter, WorkflowFileStatus, WorkflowFileStatuses } from '@red/domain'; import { workflowFileStatusTranslations } from '../../translations/file-status-translations'; -import { FileAssignService } from '../../shared/services/file-assign.service'; import { PermissionsService } from '@services/permissions.service'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { TranslateService } from '@ngx-translate/core'; @@ -24,26 +22,22 @@ import { annotationFilterChecker, RedactionFilterSorter } from '@utils/index'; import { workloadTranslations } from '../../translations/workload-translations'; import * as moment from 'moment'; import { ConfigService as AppConfigService } from '@services/config.service'; -import { DossiersService } from '@services/entity-services/dossiers.service'; -import { FilesService } from '@services/entity-services/files.service'; import { BehaviorSubject, Observable } from 'rxjs'; -import { noop } from 'lodash'; +import noop from 'lodash/noop'; +import { BulkActionsService } from './services/bulk-actions.service'; @Injectable() export class ConfigService { readonly listingMode$: Observable; - private readonly _listingMode$ = new BehaviorSubject(ListingModes.workflow); + private readonly _listingMode$ = new BehaviorSubject(ListingModes.table); constructor( - private readonly _fileAssignService: FileAssignService, - private readonly _filesService: FilesService, - private readonly _loadingService: LoadingService, - private readonly _dossiersService: DossiersService, private readonly _permissionsService: PermissionsService, private readonly _translateService: TranslateService, private readonly _userService: UserService, private readonly _dialogService: DossiersDialogService, private readonly _appConfigService: AppConfigService, + private readonly _bulkActionsService: BulkActionsService, ) { this.listingMode$ = this._listingMode$.asObservable(); } @@ -71,28 +65,35 @@ export class ConfigService { }, { label: workflowFileStatusTranslations[WorkflowFileStatuses.UNDER_REVIEW], - enterFn: this._underReviewFn, - enterPredicate: (file: File) => - this._permissionsService.canSetUnderReview(file) || - this._permissionsService.canAssignToSelf(file) || - this._permissionsService.canAssignUser(file), + enterFn: async (files: File[]) => { + if (files[0].workflowStatus === WorkflowFileStatuses.UNDER_APPROVAL) { + await this._bulkActionsService.backToUnderReview(files); + } else { + await this._bulkActionsService.assignToMe(files); + } + }, + enterPredicate: (files: File[]) => + this._permissionsService.canSetUnderReview(files) || + this._permissionsService.canAssignToSelf(files) || + this._permissionsService.canAssignUser(files), key: WorkflowFileStatuses.UNDER_REVIEW, color: '#FDBD00', entities: new BehaviorSubject([]), }, { label: workflowFileStatusTranslations[WorkflowFileStatuses.UNDER_APPROVAL], - enterFn: this._underApprovalFn, - enterPredicate: (file: File) => - this._permissionsService.canSetUnderApproval(file) || this._permissionsService.canUndoApproval(file), + enterFn: (files: File[]) => this._bulkActionsService.setToUnderApproval(files), + enterPredicate: (files: File[]) => + this._permissionsService.canSetUnderApproval(files) || this._permissionsService.canUndoApproval(files), key: WorkflowFileStatuses.UNDER_APPROVAL, color: '#374C81', entities: new BehaviorSubject([]), }, { label: workflowFileStatusTranslations[WorkflowFileStatuses.APPROVED], - enterFn: this._approveFn, - enterPredicate: (file: File) => this._permissionsService.isReadyForApproval(file) && file.canBeApproved, + enterFn: (files: File[]) => this._bulkActionsService.approve(files), + enterPredicate: (files: File[]) => + this._permissionsService.isReadyForApproval(files) && this._permissionsService.canBeApproved(files), key: WorkflowFileStatuses.APPROVED, color: '#48C9F7', entities: new BehaviorSubject([]), @@ -366,25 +367,4 @@ export class ConfigService { private _openEditDossierDialog($event: MouseEvent, dossierId: string) { this._dialogService.openDialog('editDossier', $event, { dossierId }); } - - private _underReviewFn = async (file: File) => { - await this._fileAssignService.assignReviewer(null, file, true); - }; - - private _underApprovalFn = async (file: File) => { - const dossier = this._dossiersService.find(file.dossierId); - if (dossier.approverIds.length > 1) { - await this._fileAssignService.assignApprover(null, file, true); - } else { - this._loadingService.start(); - await this._filesService.setUnderApprovalFor([file.id], dossier.dossierId, dossier.approverIds[0]).toPromise(); - this._loadingService.stop(); - } - }; - - private _approveFn = async (file: File) => { - this._loadingService.start(); - await this._filesService.setApprovedFor([file.id], file.dossierId).toPromise(); - this._loadingService.stop(); - }; } diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/dossier-overview.module.ts b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/dossier-overview.module.ts index c9382a62a..57f081d3b 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/dossier-overview.module.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/dossier-overview.module.ts @@ -18,6 +18,7 @@ import { ScreenHeaderComponent } from './components/screen-header/screen-header. import { ViewModeSelectionComponent } from './components/view-mode-selection/view-mode-selection.component'; import { FileNameColumnComponent } from './components/table-item/file-name-column/file-name-column.component'; import { AddedColumnComponent } from './components/table-item/added-column/added-column.component'; +import { BulkActionsService } from './services/bulk-actions.service'; const routes: Routes = [ { @@ -45,7 +46,7 @@ const routes: Routes = [ FileNameColumnComponent, AddedColumnComponent, ], - providers: [ConfigService], + providers: [ConfigService, BulkActionsService], imports: [RouterModule.forChild(routes), CommonModule, SharedModule, SharedDossiersModule, IqserIconsModule, TranslateModule], }) export class DossierOverviewModule {} 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 new file mode 100644 index 000000000..40aed1fe3 --- /dev/null +++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/services/bulk-actions.service.ts @@ -0,0 +1,140 @@ +import { Injectable } from '@angular/core'; +import { Dossier, File } from '@red/domain'; +import { DossiersDialogService } from '../../../services/dossiers-dialog.service'; +import { ConfirmationDialogInput, LoadingService } from '@iqser/common-ui'; +import { DossiersService } from '@services/entity-services/dossiers.service'; +import { FilesService } from '@services/entity-services/files.service'; +import { FileAssignService } from '../../../shared/services/file-assign.service'; +import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { ReanalysisService } from '../../../../../services/reanalysis.service'; +import { FileManagementService } from '@services/entity-services/file-management.service'; + +@Injectable() +export class BulkActionsService { + constructor( + private readonly _dialogService: DossiersDialogService, + private readonly _loadingService: LoadingService, + private readonly _dossiersService: DossiersService, + private readonly _filesService: FilesService, + private readonly _fileAssignService: FileAssignService, + private readonly _reanalysisService: ReanalysisService, + private readonly _fileManagementService: FileManagementService, + ) {} + + async setToUnderApproval(files: File[]) { + const dossier = this._getDossier(files); + // If more than 1 approver - show dialog and ask who to assign + if (dossier.approverIds.length > 1) { + this._assignFiles(files, 'approver', true); + } else { + this._loadingService.start(); + await this._filesService + .setUnderApprovalFor( + files.map(f => f.id), + dossier.id, + dossier.approverIds[0], + ) + .toPromise(); + this._loadingService.stop(); + } + } + + async assignToMe(files: File[]) { + await this._fileAssignService.assignToMe(files); + } + + async ocr(files: File[]) { + this._loadingService.start(); + await this._reanalysisService + .ocrFiles( + files.map(f => f.fileId), + files[0].dossierId, + ) + .toPromise(); + this._loadingService.stop(); + } + + delete(files: File[]) { + this._dialogService.openDialog( + 'confirm', + null, + new ConfirmationDialogInput({ + title: _('confirmation-dialog.delete-file.title'), + question: _('confirmation-dialog.delete-file.question'), + }), + async () => { + this._loadingService.start(); + await this._fileManagementService + .delete( + files.map(item => item.fileId), + files[0].dossierId, + ) + .toPromise(); + this._loadingService.stop(); + }, + ); + } + + async reanalyse(files: File[]) { + this._loadingService.start(); + const fileIds = files.filter(file => file.analysisRequired).map(file => file.fileId); + await this._reanalysisService.reanalyzeFilesForDossier(fileIds, files[0].dossierId).toPromise(); + this._loadingService.stop(); + } + + async backToUnderReview(files: File[]): Promise { + this._loadingService.start(); + await this._filesService + .setUnderReviewFor( + files.map(f => f.id), + files[0].dossierId, + ) + .toPromise(); + this._loadingService.stop(); + } + + async approve(files: File[]): Promise { + const foundUpdatedFile = files.find(file => file.hasUpdates); + if (foundUpdatedFile) { + this._dialogService.openDialog( + 'confirm', + null, + new ConfirmationDialogInput({ + title: _('confirmation-dialog.approve-multiple-files.title'), + question: _('confirmation-dialog.approve-multiple-files.question'), + }), + async () => { + this._loadingService.start(); + await this._filesService + .setApprovedFor( + files.map(f => f.id), + files[0].dossierId, + ) + .toPromise(); + this._loadingService.stop(); + }, + ); + } else { + this._loadingService.start(); + await this._filesService + .setApprovedFor( + files.map(f => f.id), + files[0].dossierId, + ) + .toPromise(); + this._loadingService.stop(); + } + } + + assign(files: File[], mode: 'reviewer' | 'approver' = files[0].isUnderApproval ? 'approver' : 'reviewer') { + this._assignFiles(files, mode); + } + + private _getDossier(files: File[]): Dossier { + return this._dossiersService.find(files[0].dossierId); + } + + private _assignFiles(files: File[], mode: 'reviewer' | 'approver', ignoreChanged = false) { + this._dialogService.openDialog('assignFile', null, { mode, files, ignoreChanged }); + } +} diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/user-management/user-management.component.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/user-management/user-management.component.ts index 6ec0a7db8..fdbe6d8f3 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/user-management/user-management.component.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/user-management/user-management.component.ts @@ -68,9 +68,9 @@ export class UserManagementComponent implements OnChanges { } ngOnChanges() { - this.canAssignToSelf = this.permissionsService.canAssignToSelf(this.file, this.dossier); - this.canAssignUser = this.permissionsService.canAssignUser(this.file, this.dossier); - this.canUnassignUser = this.permissionsService.canUnassignUser(this.file, this.dossier); + this.canAssignToSelf = this.permissionsService.canAssignToSelf(this.file); + this.canAssignUser = this.permissionsService.canAssignUser(this.file); + this.canUnassignUser = this.permissionsService.canUnassignUser(this.file); this.canAssignOrUnassign = this.canAssignUser || this.canUnassignUser; this.canAssign = this.canAssignToSelf || this.canAssignOrUnassign; diff --git a/apps/red-ui/src/app/services/permissions.service.ts b/apps/red-ui/src/app/services/permissions.service.ts index d979b2ebf..6a7bfbbee 100644 --- a/apps/red-ui/src/app/services/permissions.service.ts +++ b/apps/red-ui/src/app/services/permissions.service.ts @@ -22,58 +22,57 @@ export class PermissionsService { return this.isReviewerOrApprover(file) && (file.isNew || file.isUnderReview || file.isUnderApproval); } - canReanalyseFile(file: File): boolean { - return this.isReviewerOrApprover(file) || file.isNew || (file.isError && file.isNew); + canReanalyseFile(file: File | File[]): boolean { + const files = file instanceof File ? [file] : file; + return files.reduce((acc, _file) => this._canReanalyseFile(_file) && acc, true); } isFileAssignee(file: File): boolean { return file.assignee === this._userService.currentUser.id; } - // https://jira.iqser.com/browse/RED-2787 - canDeleteFile(file: File): boolean { - const dossier = this._getDossier(file); - return ( - file.isNew || - (file.isUnderReview && !file.assignee && this.isDossierMember(dossier)) || - (file.isUnderApproval && !file.assignee && this.isApprover(dossier)) || - (file.assignee && !file.isApproved && (this.isFileAssignee(file) || this.isOwner(dossier))) - ); + canDeleteFile(file: File | File[]): boolean { + const files = file instanceof File ? [file] : file; + const dossier = this._getDossier(files[0]); + return files.reduce((acc, _file) => this._canDeleteFile(_file, dossier) && acc, true); } - canAssignToSelf(file: File, dossier = this._getDossier(file)): boolean { - const precondition = this.isDossierMember(dossier) && !this.isFileAssignee(file) && !file.isError && !file.isProcessing; - return precondition && (file.isNew || file.isUnderReview || (file.isUnderApproval && this.isApprover(dossier))); + canAssignToSelf(file: File | File[]): boolean { + const files = file instanceof File ? [file] : file; + const dossier = this._getDossier(files[0]); + return files.reduce((acc, _file) => this._canAssignToSelf(_file, dossier) && acc, true); } - canAssignUser(file: File, dossier = this._getDossier(file)): boolean { - const precondition = !file.isProcessing && !file.isError && !file.isApproved && this.isApprover(dossier); - - if (precondition) { - if ((file.isNew || file.isUnderReview) && dossier.hasReviewers) { - return true; - } - if (file.isUnderApproval && dossier.approverIds.length > 1) { - return true; - } - } - return false; + canAssignUser(file: File | File[]): boolean { + const files = file instanceof File ? [file] : file; + const dossier = this._getDossier(files[0]); + return files.reduce((acc, _file) => this._canAssignUser(_file, dossier) && acc, true); } - canUnassignUser(file: File, dossier = this._getDossier(file)): boolean { - return (file.isUnderReview || file.isUnderApproval) && (this.isFileAssignee(file) || this.isApprover(dossier)); + canUnassignUser(file: File | File[]): boolean { + const files = file instanceof File ? [file] : file; + const dossier = this._getDossier(files[0]); + return files.reduce((acc, _file) => this._canUnassignUser(_file, dossier) && acc, true); } - canSetUnderReview(file: File, dossier = this._getDossier(file)): boolean { - return file.isUnderApproval && this.isApprover(dossier); + canSetUnderReview(file: File | File[]): boolean { + const files = file instanceof File ? [file] : file; + const dossier = this._getDossier(files[0]); + return this.isApprover(dossier) && files.reduce((acc, _file) => this._canSetUnderReview(_file) && acc, true); } - isReadyForApproval(file: File): boolean { - return this.canSetUnderReview(file); + canBeApproved(file: File | File[]): boolean { + const files = file instanceof File ? [file] : file; + return files.reduce((acc, _file) => this._canBeApproved(_file) && acc, true); } - canSetUnderApproval(file: File): boolean { - return file.isUnderReview && this.isReviewerOrApprover(file); + isReadyForApproval(files: File | File[]): boolean { + return this.canSetUnderReview(files); + } + + canSetUnderApproval(file: File | File[]): boolean { + const files = file instanceof File ? [file] : file; + return files.reduce((acc, _file) => this._canSetUnderApproval(_file) && acc, true); } isOwner(dossier: Dossier, user = this._userService.currentUser): boolean { @@ -97,8 +96,10 @@ export class PermissionsService { return (file?.isUnderReview || file?.isUnderApproval) && this.isFileAssignee(file); } - canUndoApproval(file: File): boolean { - return file.isApproved && this.isApprover(this._getDossier(file)); + canUndoApproval(file: File | File[]): boolean { + const files = file instanceof File ? [file] : file; + const dossier = this._getDossier(files[0]); + return files.reduce((acc, _file) => this._canUndoApproval(_file, dossier) && acc, true); } canMarkPagesAsViewed(file: File): boolean { @@ -135,6 +136,59 @@ export class PermissionsService { return (comment.user === this._userService.currentUser.id || this.isApprover(dossier)) && !file.isApproved; } + // https://jira.iqser.com/browse/RED-2787 + private _canDeleteFile(file: File, dossier: Dossier): boolean { + return ( + file.isNew || + (file.isUnderReview && !file.assignee && this.isDossierMember(dossier)) || + (file.isUnderApproval && !file.assignee && this.isApprover(dossier)) || + (file.assignee && !file.isApproved && (this.isFileAssignee(file) || this.isOwner(dossier))) + ); + } + + private _canReanalyseFile(file: File): boolean { + return this.isReviewerOrApprover(file) || file.isNew || (file.isError && file.isNew); + } + + private _canAssignToSelf(file: File, dossier: Dossier): boolean { + const precondition = this.isDossierMember(dossier) && !this.isFileAssignee(file) && !file.isError && !file.isProcessing; + return precondition && (file.isNew || file.isUnderReview || (file.isUnderApproval && this.isApprover(dossier))); + } + + private _canSetUnderApproval(file: File): boolean { + return file.isUnderReview && this.isReviewerOrApprover(file); + } + + private _canUndoApproval(file: File, dossier: Dossier): boolean { + return file.isApproved && this.isApprover(dossier); + } + + private _canBeApproved(file: File): boolean { + return file.canBeApproved; + } + + private _canAssignUser(file: File, dossier: Dossier) { + const precondition = !file.isProcessing && !file.isError && !file.isApproved && this.isApprover(dossier); + + if (precondition) { + if ((file.isNew || file.isUnderReview) && dossier.hasReviewers) { + return true; + } + if (file.isUnderApproval && dossier.approverIds.length > 1) { + return true; + } + } + return false; + } + + private _canUnassignUser(file: File, dossier: Dossier) { + return (file.isUnderReview || file.isUnderApproval) && (this.isFileAssignee(file) || this.isApprover(dossier)); + } + + private _canSetUnderReview(file: File): boolean { + return file.isUnderApproval; + } + private _getDossier(file: File): Dossier { return this._dossiersService.find(file.dossierId); } diff --git a/apps/red-ui/src/app/services/reanalysis.service.ts b/apps/red-ui/src/app/services/reanalysis.service.ts index c9802f6a6..1707aca5a 100644 --- a/apps/red-ui/src/app/services/reanalysis.service.ts +++ b/apps/red-ui/src/app/services/reanalysis.service.ts @@ -45,8 +45,8 @@ export class ReanalysisService extends GenericService { } @Validate() - ocrFiles(@RequiredParam() body: List, @RequiredParam() dossierId: string) { - return this._post(body, `ocr/reanalyze/${dossierId}/bulk`).pipe(switchMap(() => this._filesService.loadAll(dossierId))); + ocrFiles(@RequiredParam() fileIds: List, @RequiredParam() dossierId: string) { + return this._post(fileIds, `ocr/reanalyze/${dossierId}/bulk`).pipe(switchMap(() => this._filesService.loadAll(dossierId))); } @Validate() diff --git a/libs/common-ui b/libs/common-ui index 567de98f3..28a6b735f 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit 567de98f30d622c6bbc9a47d87a784c7aa36055f +Subproject commit 28a6b735f700351f36c2583de4b581fe5fb8106b