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 c9730e14b..e46967dab 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 @@ -25,6 +25,8 @@ export class DossierOverviewBulkActionsComponent implements OnChanges { canAssign: boolean; canDelete: boolean; canReanalyse: boolean; + canDisableAutoAnalysis: boolean; + canEnableAutoAnalysis: boolean; canOcr: boolean; canSetToUnderReview: boolean; canSetToUnderApproval: boolean; @@ -114,6 +116,20 @@ export class DossierOverviewBulkActionsComponent implements OnChanges { icon: 'iqser:refresh', show: this.canReanalyse && this.analysisForced, }, + { + type: ActionTypes.circleBtn, + action: $event => this._bulkActionsService.toggleAutomaticAnalysis(this.selectedFiles, true), + tooltip: _('dossier-overview.disable-auto-analysis'), + icon: 'red:stop', + show: this.canDisableAutoAnalysis, + }, + { + type: ActionTypes.circleBtn, + action: $event => this._bulkActionsService.toggleAutomaticAnalysis(this.selectedFiles), + tooltip: _('dossier-overview.enable-auto-analysis'), + icon: 'red:play', + show: this.canEnableAutoAnalysis, + }, ].filter(btn => btn.show); } @@ -149,6 +165,10 @@ export class DossierOverviewBulkActionsComponent implements OnChanges { this.canReanalyse = this._permissionsService.canReanalyseFile(this.selectedFiles); + this.canDisableAutoAnalysis = this._permissionsService.canDisableAutoAnalysis(this.selectedFiles); + + this.canEnableAutoAnalysis = this._permissionsService.canEnableAutoAnalysis(this.selectedFiles); + this.canOcr = this.selectedFiles.reduce((acc, file) => acc && file.canBeOCRed, true); this.canSetToUnderReview = this._permissionsService.canSetUnderReview(this.selectedFiles) && !isWorkflow; 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 a0b27b673..8ca255a02 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 @@ -83,6 +83,13 @@ export class BulkActionsService { this._loadingService.stop(); } + async toggleAutomaticAnalysis(files: File[], excluded?: boolean) { + this._loadingService.start(); + const fileIds = files.map(file => file.fileId); + await firstValueFrom(this._reanalysisService.toggleAutomaticAnalysis(files[0].dossierId, fileIds, excluded)); + this._loadingService.stop(); + } + async backToUnderReview(files: File[]): Promise { this._loadingService.start(); await firstValueFrom( diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.html b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.html index 71c41366d..050024486 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.html +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.html @@ -31,12 +31,18 @@
-
+ +
diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.scss b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.scss index 78609b428..8407e6b6c 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.scss +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.scss @@ -1,13 +1,13 @@ @use 'apps/red-ui/src/assets/styles/variables'; @use 'libs/common-ui/src/assets/styles/common-mixins'; -.read-only { +.banner { padding: 13px 16px; - background-color: variables.$primary; color: variables.$white; justify-content: space-between; - .read-only-text { + .read-only-text, + .disabled-auto-analysis-text { font-size: 11px; font-weight: 600; line-height: 14px; @@ -33,8 +33,17 @@ } } +.read-only { + background-color: variables.$primary; +} + +.disabled-auto-analysis { + background-color: variables.$yellow-2; +} + .right-content { flex-direction: column; + overflow: hidden; .no-annotations-buttons-container { display: flex; 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 ae697a33e..03a3494b1 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 @@ -62,6 +62,8 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnDestroy, showDelete = false; showOCR = false; canReanalyse = false; + canDisableAutoAnalysis = false; + canEnableAutoAnalysis = false; showUnderReview = false; showUnderApproval = false; showApprove = false; @@ -182,6 +184,20 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnDestroy, disabled: !this.file.canBeApproved, show: this.showApprove, }, + { + type: ActionTypes.circleBtn, + action: $event => this.toggleAutomaticAnalysis($event), + tooltip: _('dossier-overview.disable-auto-analysis'), + icon: 'red:stop', + show: this.canDisableAutoAnalysis, + }, + { + type: ActionTypes.circleBtn, + action: $event => this.toggleAutomaticAnalysis($event), + tooltip: _('dossier-overview.enable-auto-analysis'), + icon: 'red:play', + show: this.canEnableAutoAnalysis, + }, { type: ActionTypes.circleBtn, action: $event => this._setFileUnderApproval($event), @@ -296,12 +312,23 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnDestroy, } private async _reanalyseFile($event?: MouseEvent) { - if ($event) { - $event.stopPropagation(); - } + $event?.stopPropagation(); await firstValueFrom(this._reanalysisService.reanalyzeFilesForDossier([this.file.fileId], this.file.dossierId, true)); } + private async toggleAutomaticAnalysis($event: MouseEvent) { + $event.stopPropagation(); + this._loadingService.start(); + await firstValueFrom( + this._reanalysisService.toggleAutomaticAnalysis( + this.file.dossierId, + [this.file.fileId], + !this.file.excludedFromAutomaticAnalysis, + ), + ); + this._loadingService.stop(); + } + private async _setFileUnderApproval($event: MouseEvent) { $event.stopPropagation(); await this._fileAssignService.assignApprover($event, this.file, true); @@ -345,6 +372,8 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnDestroy, this.showDelete = this._permissionsService.canDeleteFile(this.file); this.showOCR = this.file.canBeOCRed; this.canReanalyse = this._permissionsService.canReanalyseFile(this.file); + this.canDisableAutoAnalysis = this._permissionsService.canDisableAutoAnalysis(this.file); + this.canEnableAutoAnalysis = this._permissionsService.canEnableAutoAnalysis(this.file); this.showStatusBar = !this.file.isError && !this.file.isPending && this.isDossierOverviewList; diff --git a/apps/red-ui/src/app/modules/icons/icons.module.ts b/apps/red-ui/src/app/modules/icons/icons.module.ts index cf4598843..7d808ccd7 100644 --- a/apps/red-ui/src/app/modules/icons/icons.module.ts +++ b/apps/red-ui/src/app/modules/icons/icons.module.ts @@ -24,6 +24,7 @@ export class IconsModule { 'comment-fill', 'csv', 'dictionary', + 'denied', 'double-chevron-right', 'enter', 'entries', @@ -44,6 +45,7 @@ export class IconsModule { 'new-tab', 'notification', 'page', + 'play', 'preview', 'put-back', 'read-only', @@ -59,6 +61,7 @@ export class IconsModule { 'secret', 'status', 'status-info', + 'stop', 'template', 'thumb-down', 'thumb-up', diff --git a/apps/red-ui/src/app/services/permissions.service.ts b/apps/red-ui/src/app/services/permissions.service.ts index a69c5e6a7..0d82eb7c0 100644 --- a/apps/red-ui/src/app/services/permissions.service.ts +++ b/apps/red-ui/src/app/services/permissions.service.ts @@ -32,6 +32,16 @@ export class PermissionsService { return files.reduce((acc, _file) => this._canReanalyseFile(_file) && acc, true); } + canDisableAutoAnalysis(file: File | File[]): boolean { + const files = file instanceof File ? [file] : file; + return files.reduce((acc, _file) => this._canDisableAutoAnalysis(_file) && acc, true); + } + + canEnableAutoAnalysis(file: File | File[]): boolean { + const files = file instanceof File ? [file] : file; + return files.reduce((acc, _file) => this._canEnableAutoAnalysis(_file) && acc, true); + } + isFileAssignee(file: File): boolean { return file.assignee === this._userService.currentUser.id; } @@ -158,6 +168,14 @@ export class PermissionsService { return this.isReviewerOrApprover(file) || file.isNew || (file.isError && file.isNew); } + private _canDisableAutoAnalysis(file: File): boolean { + return !file.excludedFromAutomaticAnalysis && file.assignee === this._userService.currentUser.id; + } + + private _canEnableAutoAnalysis(file: File): boolean { + return file.excludedFromAutomaticAnalysis && file.assignee === this._userService.currentUser.id; + } + 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))); diff --git a/apps/red-ui/src/app/services/reanalysis.service.ts b/apps/red-ui/src/app/services/reanalysis.service.ts index 1707aca5a..3a3bded63 100644 --- a/apps/red-ui/src/app/services/reanalysis.service.ts +++ b/apps/red-ui/src/app/services/reanalysis.service.ts @@ -44,6 +44,16 @@ export class ReanalysisService extends GenericService { ); } + @Validate() + toggleAutomaticAnalysis(@RequiredParam() dossierId: string, @RequiredParam() fileIds: string[], excluded?: boolean) { + const queryParams: QueryParam[] = [{ key: 'excluded', value: !!excluded }]; + return this._post( + fileIds.length > 1 ? fileIds : {}, + `toggle-automatic-analysis/${dossierId}/${fileIds.length > 1 ? 'bulk' : fileIds[0]}`, + queryParams, + ).pipe(switchMap(() => this._filesService.loadAll(dossierId))); + } + @Validate() ocrFiles(@RequiredParam() fileIds: List, @RequiredParam() dossierId: string) { return this._post(fileIds, `ocr/reanalyze/${dossierId}/bulk`).pipe(switchMap(() => this._filesService.loadAll(dossierId))); diff --git a/apps/red-ui/src/assets/i18n/de.json b/apps/red-ui/src/assets/i18n/de.json index 33bd2c739..e1926fb1b 100644 --- a/apps/red-ui/src/assets/i18n/de.json +++ b/apps/red-ui/src/assets/i18n/de.json @@ -608,6 +608,7 @@ "placeholder": "Begründung" } }, + "disabled-auto-analysis": "", "document-info": { "save": "Dokumenteninformation speichern", "title": "Datei-Attribute anlegen" @@ -719,6 +720,7 @@ "delete": { "action": "Datei löschen" }, + "disable-auto-analysis": "", "dossier-details": { "attributes": { "expand": "{count} {count, plural, one{benutzerdefiniertes Attribut} other{benutzerdefinierte Attribute}}", @@ -742,6 +744,7 @@ }, "download-file": "Herunterladen", "download-file-disabled": "Nur genehmigte Dateien können heruntergeladen werden", + "enable-auto-analysis": "", "file-listing": { "file-entry": { "file-error": "Reanalyse erforderlich", diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index 5f60b49ec..7f6941b71 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -608,6 +608,7 @@ "placeholder": "Reason" } }, + "disabled-auto-analysis": "Automatic analysys is disabled", "document-info": { "save": "Save Document Info", "title": "Introduce File Attributes" @@ -719,6 +720,7 @@ "delete": { "action": "Delete File" }, + "disable-auto-analysis": "Disable auto-analysis", "dossier-details": { "attributes": { "expand": "{count} custom {count, plural, one{attribute} other{attributes}}", @@ -742,6 +744,7 @@ }, "download-file": "Download", "download-file-disabled": "You need to be approver in the dossier and the {count, plural, one{file needs} other{files need}} to be approved in order to download.", + "enable-auto-analysis": "Enable auto-analysis", "file-listing": { "file-entry": { "file-error": "Re-processing required", diff --git a/apps/red-ui/src/assets/icons/general/denied.svg b/apps/red-ui/src/assets/icons/general/denied.svg new file mode 100644 index 000000000..6530d96ff --- /dev/null +++ b/apps/red-ui/src/assets/icons/general/denied.svg @@ -0,0 +1,7 @@ + + + + + Svg Vector Icons : http://www.onlinewebfonts.com/icon + + \ No newline at end of file diff --git a/apps/red-ui/src/assets/icons/general/play.svg b/apps/red-ui/src/assets/icons/general/play.svg new file mode 100644 index 000000000..1b37e3874 --- /dev/null +++ b/apps/red-ui/src/assets/icons/general/play.svg @@ -0,0 +1,7 @@ + + + + + Svg Vector Icons : http://www.onlinewebfonts.com/icon + + \ No newline at end of file diff --git a/apps/red-ui/src/assets/icons/general/stop.svg b/apps/red-ui/src/assets/icons/general/stop.svg new file mode 100644 index 000000000..db10a7bb9 --- /dev/null +++ b/apps/red-ui/src/assets/icons/general/stop.svg @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/libs/red-domain/src/lib/files/file.model.ts b/libs/red-domain/src/lib/files/file.model.ts index ad1c1e501..735b5cdc1 100644 --- a/libs/red-domain/src/lib/files/file.model.ts +++ b/libs/red-domain/src/lib/files/file.model.ts @@ -16,6 +16,7 @@ export class File extends Entity implements IFile { readonly dossierDictionaryVersion?: number; readonly dossierId: string; readonly excluded: boolean; + readonly excludedFromAutomaticAnalysis: boolean; readonly fileAttributes?: FileAttributes; readonly fileId: string; readonly filename: string; @@ -68,6 +69,7 @@ export class File extends Entity implements IFile { this.dossierDictionaryVersion = file.dossierDictionaryVersion; this.dossierId = file.dossierId; this.excluded = !!file.excluded; + this.excludedFromAutomaticAnalysis = Math.random() < 0.5; //!!file.excludedFromAutomaticAnalysis; this.fileAttributes = file.fileAttributes; this.fileId = file.fileId; this.filename = file.filename; diff --git a/libs/red-domain/src/lib/files/file.ts b/libs/red-domain/src/lib/files/file.ts index a93082aa8..6208d4fab 100644 --- a/libs/red-domain/src/lib/files/file.ts +++ b/libs/red-domain/src/lib/files/file.ts @@ -46,6 +46,10 @@ export interface IFile { * Shows if the file was excluded from analysis. */ readonly excluded?: boolean; + /** + * Shows if the file was excluded from automatic analysis. + */ + readonly excludedFromAutomaticAnalysis?: boolean; /** * Set of excluded pages for this file. */