From 9845267cc507ecdb79a92ba532c3c6e49b939c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Wed, 1 Dec 2021 21:30:31 +0200 Subject: [PATCH] Update workflow UI --- .../file-workload.component.html} | 0 .../file-workload.component.scss} | 0 .../file-workload.component.ts} | 8 +- .../table-item/table-item.component.html | 2 +- .../workflow-item.component.html | 15 +- .../workflow-item.component.scss | 25 +- .../workflow-item/workflow-item.component.ts | 7 +- .../dossier-overview/config.service.ts | 11 +- .../dossier-overview.module.ts | 4 +- .../dossier-overview-screen.component.html | 7 +- .../file-preview-screen.component.ts | 6 +- .../file-actions/file-actions.component.html | 153 +--------- .../file-actions/file-actions.component.scss | 10 - .../file-actions/file-actions.component.ts | 272 ++++++++++++++---- .../file-download-btn.component.ts | 6 +- .../expandable-file-actions.component.html | 64 +++++ .../expandable-file-actions.component.scss | 27 ++ .../expandable-file-actions.component.ts | 38 +++ .../expandable-file-actions/types.ts | 27 ++ .../src/app/modules/shared/shared.module.ts | 2 + .../src/app/services/permissions.service.ts | 9 +- libs/common-ui | 2 +- libs/red-domain/src/lib/files/file.model.ts | 1 - 23 files changed, 438 insertions(+), 258 deletions(-) rename apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/{file-workload-column/file-workload-column.component.html => file-workload/file-workload.component.html} (100%) rename apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/{file-workload-column/file-workload-column.component.scss => file-workload/file-workload.component.scss} (100%) rename apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/{file-workload-column/file-workload-column.component.ts => file-workload/file-workload.component.ts} (84%) create mode 100644 apps/red-ui/src/app/modules/shared/components/expandable-file-actions/expandable-file-actions.component.html create mode 100644 apps/red-ui/src/app/modules/shared/components/expandable-file-actions/expandable-file-actions.component.scss create mode 100644 apps/red-ui/src/app/modules/shared/components/expandable-file-actions/expandable-file-actions.component.ts create mode 100644 apps/red-ui/src/app/modules/shared/components/expandable-file-actions/types.ts diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/file-workload-column/file-workload-column.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/file-workload/file-workload.component.html similarity index 100% rename from apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/file-workload-column/file-workload-column.component.html rename to apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/file-workload/file-workload.component.html diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/file-workload-column/file-workload-column.component.scss b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/file-workload/file-workload.component.scss similarity index 100% rename from apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/file-workload-column/file-workload-column.component.scss rename to apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/file-workload/file-workload.component.scss diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/file-workload-column/file-workload-column.component.ts b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/file-workload/file-workload.component.ts similarity index 84% rename from apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/file-workload-column/file-workload-column.component.ts rename to apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/file-workload/file-workload.component.ts index 5894045a9..0b69ee12a 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/file-workload-column/file-workload-column.component.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/file-workload/file-workload.component.ts @@ -4,12 +4,12 @@ import { File } from '@red/domain'; import { DossiersService } from '@services/entity-services/dossiers.service'; @Component({ - selector: 'redaction-file-workload-column', - templateUrl: './file-workload-column.component.html', - styleUrls: ['./file-workload-column.component.scss'], + selector: 'redaction-file-workload', + templateUrl: './file-workload.component.html', + styleUrls: ['./file-workload.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class FileWorkloadColumnComponent { +export class FileWorkloadComponent { @Input() file: File; constructor(private readonly _appStateService: AppStateService, private readonly _dossiersService: DossiersService) {} diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/table-item.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/table-item.component.html index aad72d891..501c43b8c 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/table-item.component.html +++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/table-item.component.html @@ -17,7 +17,7 @@
- +
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/workflow-item/workflow-item.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/workflow-item/workflow-item.component.html index 0cc78470c..3b0eaa732 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/workflow-item/workflow-item.component.html +++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/workflow-item/workflow-item.component.html @@ -13,5 +13,18 @@
- +
+ {{ file.fileAttributes.attributeIdToValue[config.id] || '-' }} +
+ + + +
+ +
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/workflow-item/workflow-item.component.scss b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/workflow-item/workflow-item.component.scss index 75bdb518a..74a119427 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/workflow-item/workflow-item.component.scss +++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/workflow-item/workflow-item.component.scss @@ -1,7 +1,7 @@ @use 'common-mixins'; .workflow-item { - padding: 10px; + padding: 10px 10px 8px 10px; > div { display: flex; @@ -23,12 +23,31 @@ } } - redaction-file-actions { + redaction-file-workload { margin-top: 10px; + display: block; + min-height: 16px; + } + + .file-actions { + margin-top: 8px; + min-height: 34px; + overflow: hidden; + } + + redaction-file-actions:not(.keep-visible) { display: none; } + &:hover .filename { + text-decoration: underline; + } + &:hover redaction-file-actions { - display: block; + display: initial; } } + +.mt-4 { + margin-top: 4px; +} diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/workflow-item/workflow-item.component.ts b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/workflow-item/workflow-item.component.ts index fffcf980d..b7b4c79d2 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/workflow-item/workflow-item.component.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/workflow-item/workflow-item.component.ts @@ -1,5 +1,6 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; -import { File } from '@red/domain'; +import { File, IFileAttributeConfig } from '@red/domain'; +import { Required } from '@iqser/common-ui'; @Component({ selector: 'redaction-workflow-item', @@ -8,5 +9,7 @@ import { File } from '@red/domain'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class WorkflowItemComponent { - @Input() file: File; + @Input() @Required() file!: File; + @Input() @Required() displayedAttributes!: IFileAttributeConfig[]; + @Input() width: number; } 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 135fa3130..36cdc8972 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 @@ -27,6 +27,7 @@ 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'; @Injectable() export class ConfigService { @@ -63,8 +64,8 @@ export class ConfigService { { label: workflowFileStatusTranslations[WorkflowFileStatuses.NEW], key: WorkflowFileStatuses.NEW, - enterFn: this._unassignFn, - enterPredicate: (file: File) => this._permissionsService.canUnassignUser(file), + enterFn: noop, + enterPredicate: () => false, color: '#D3D5DA', }, { @@ -362,12 +363,6 @@ export class ConfigService { this._dialogService.openDialog('editDossier', $event, { dossierId }); } - private _unassignFn = async (file: File) => { - this._loadingService.start(); - await this._filesService.setUnassigned([file.fileId], file.dossierId).toPromise(); - this._loadingService.stop(); - }; - private _underReviewFn = async (file: File) => { await this._fileAssignService.assignReviewer(null, file, true); }; 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 3d7b9fb5c..c9382a62a 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 @@ -11,7 +11,7 @@ import { DossierDetailsStatsComponent } from './components/dossier-details-stats import { TableItemComponent } from './components/table-item/table-item.component'; import { ConfigService } from './config.service'; import { SharedDossiersModule } from '../../shared/shared-dossiers.module'; -import { FileWorkloadColumnComponent } from './components/table-item/file-workload-column/file-workload-column.component'; +import { FileWorkloadComponent } from './components/table-item/file-workload/file-workload.component'; import { FileStatsComponent } from './components/file-stats/file-stats.component'; import { WorkflowItemComponent } from './components/workflow-item/workflow-item.component'; import { ScreenHeaderComponent } from './components/screen-header/screen-header.component'; @@ -36,7 +36,7 @@ const routes: Routes = [ DossierOverviewBulkActionsComponent, DossierDetailsComponent, DossierDetailsStatsComponent, - FileWorkloadColumnComponent, + FileWorkloadComponent, TableItemComponent, FileStatsComponent, WorkflowItemComponent, diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/screen/dossier-overview-screen.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/screen/dossier-overview-screen.component.html index 39fdceef3..042e26b51 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/screen/dossier-overview-screen.component.html +++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/screen/dossier-overview-screen.component.html @@ -34,14 +34,13 @@ [addElementIcon]="'iqser:upload'" [config]="workflowConfig" [itemClasses]="{ disabled: disabledFn }" - [itemHeight]="'56px'" [itemTemplate]="workflowItemTemplate" [noDataButtonIcon]="'iqser:upload'" [noDataButtonLabel]="'dossier-overview.no-data.action' | translate" [noDataIcon]="'iqser:document'" [noDataText]="'dossier-overview.no-data.title' | translate" [showNoDataButton]="true" - addElementColumn="UNASSIGNED" + addElementColumn="NEW" > @@ -76,6 +75,6 @@ - - + + diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts index b2ebd6476..8a34666eb 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts @@ -44,7 +44,6 @@ import { DossiersDialogService } from '../../services/dossiers-dialog.service'; import { clearStamps, stampPDFPage } from '@utils/page-stamper'; import { TranslateService } from '@ngx-translate/core'; import { handleFilterDelta } from '@utils/filter-utils'; -import { FileActionsComponent } from '../../shared/components/file-actions/file-actions.component'; import { FilesService } from '@services/entity-services/files.service'; import { DossiersService } from '@services/entity-services/dossiers.service'; import { FileManagementService } from '@services/entity-services/file-management.service'; @@ -55,6 +54,7 @@ import { ExcludedPagesService } from './services/excluded-pages.service'; import { ViewModeService } from './services/view-mode.service'; import { MultiSelectService } from './services/multi-select.service'; import { DocumentInfoService } from './services/document-info.service'; +import { ReanalysisService } from '../../../../services/reanalysis.service'; import Annotation = Core.Annotations.Annotation; import PDFNet = Core.PDFNet; @@ -78,7 +78,6 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni hideSkipped = false; displayPDFViewer = false; @ViewChild(PdfViewerComponent) readonly viewerComponent: PdfViewerComponent; - @ViewChild('fileActions') fileActions: FileActionsComponent; readonly dossierId: string; readonly canPerformAnnotationActions$: Observable; readonly dossier$: Observable; @@ -117,6 +116,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni private readonly _translateService: TranslateService, private readonly _filesMapService: FilesMapService, private readonly _dossiersService: DossiersService, + private readonly _reanalysisService: ReanalysisService, readonly excludedPagesService: ExcludedPagesService, readonly viewModeService: ViewModeService, readonly multiSelectService: MultiSelectService, @@ -239,7 +239,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni const file = this._filesMapService.get(this.dossierId, this.fileId); if (file?.analysisRequired) { - await this.fileActions.reanalyseFile(); + await this._reanalysisService.reanalyzeFilesForDossier([this.fileId], this.dossierId, true).toPromise(); } this.displayPDFViewer = true; diff --git a/apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.html b/apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.html index 646de42ff..15dca9eca 100644 --- a/apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.html +++ b/apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.html @@ -16,153 +16,12 @@
-
- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
+ >
diff --git a/apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.scss b/apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.scss index 4aabc4879..ba5702729 100644 --- a/apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.scss +++ b/apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.scss @@ -3,9 +3,7 @@ .file-actions { display: flex; - overflow-y: auto; color: variables.$grey-1; - @include common-mixins.no-scroll-bar; > *:not(:last-child) { margin-right: 2px; @@ -27,14 +25,6 @@ iqser-status-bar { margin-left: 2px; } -mat-slide-toggle { - height: 34px; - width: 34px; - line-height: 33px; - margin-left: 8px; - margin-right: 5px; -} - .spinning-icon { margin: 0 12px 0 11px; } 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 ec6523584..e429341a8 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 @@ -1,4 +1,16 @@ -import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Optional, Output } from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + HostBinding, + Input, + OnChanges, + OnDestroy, + OnInit, + Optional, + Output, + ViewChild, +} from '@angular/core'; import { PermissionsService } from '@services/permissions.service'; import { File } from '@red/domain'; import { DossiersDialogService } from '../../../services/dossiers-dialog.service'; @@ -25,6 +37,8 @@ import { Router } from '@angular/router'; import { ExcludedPagesService } from '../../../screens/file-preview-screen/services/excluded-pages.service'; import { tap } from 'rxjs/operators'; import { DocumentInfoService } from '../../../screens/file-preview-screen/services/document-info.service'; +import { Action, ActionTypes } from '@shared/components/expandable-file-actions/types'; +import { ExpandableFileActionsComponent } from '@shared/components/expandable-file-actions/expandable-file-actions.component'; @Component({ selector: 'redaction-file-actions', @@ -36,8 +50,9 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnDestroy, readonly circleButtonTypes = CircleButtonTypes; readonly currentUser = this._userService.currentUser; - @Input() file: File; + @Input() @Required() file: File; @Input() @Required() type: 'file-preview' | 'dossier-overview-list' | 'dossier-overview-workflow'; + @Input() maxWidth: number; @Output() readonly ocredFile = new EventEmitter(); toggleTooltip?: string; @@ -56,16 +71,20 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnDestroy, canToggleAnalysis: boolean; showStatusBar: boolean; showOpenDocument: boolean; + showReanalyseFilePreview: boolean; + showReanalyseDossierOverview: boolean; analysisForced: boolean; isDossierOverview = false; isDossierOverviewList = false; isDossierOverviewWorkflow = false; isFilePreview = false; tooltipPosition: IqserTooltipPosition; + buttons: Action[]; + @ViewChild(ExpandableFileActionsComponent) _expandableActionsComponent: ExpandableFileActionsComponent; constructor( - @Optional() readonly excludedPagesService: ExcludedPagesService, - @Optional() readonly documentInfoService: DocumentInfoService, + @Optional() private readonly _excludedPagesService: ExcludedPagesService, + @Optional() private readonly _documentInfoService: DocumentInfoService, private readonly _permissionsService: PermissionsService, private readonly _dossiersService: DossiersService, private readonly _dialogService: DossiersDialogService, @@ -82,6 +101,10 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnDestroy, super(); } + @HostBinding('class.keep-visible') get expanded() { + return this._expandableActionsComponent?.expanded; + } + private get _toggleTooltip(): string { if (!this.currentUser.isManager) { return _('file-preview.toggle-analysis.only-managers'); @@ -90,6 +113,124 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnDestroy, return this.file?.excluded ? _('file-preview.toggle-analysis.enable') : _('file-preview.toggle-analysis.disable'); } + private get _buttons(): Action[] { + return [ + { + type: ActionTypes.circleBtn, + action: () => this._openDocument(), + tooltip: _('dossier-overview.open-document'), + icon: 'iqser:collapse', + show: this.showOpenDocument, + }, + { + type: ActionTypes.circleBtn, + action: $event => this._openDeleteFileDialog($event), + tooltip: _('dossier-overview.delete.action'), + icon: 'iqser:trash', + show: this.showDelete, + }, + { + type: ActionTypes.circleBtn, + action: $event => this._assign($event), + tooltip: this.assignTooltip, + icon: 'red:assign', + show: this.showAssign, + }, + { + type: ActionTypes.circleBtn, + action: $event => this._assignToMe($event), + tooltip: _('dossier-overview.assign-me'), + icon: 'red:assign-me', + show: this.showAssignToSelf, + }, + { + type: ActionTypes.downloadBtn, + show: true, + files: [this.file], + tooltipClass: 'small', + disabled: !this._permissionsService.canDownloadFiles([this.file]), + }, + { + type: ActionTypes.circleBtn, + action: () => this._documentInfoService.toggle(), + tooltip: _('file-preview.document-info'), + ariaExpanded: this._documentInfoService?.shown$, + icon: 'red:status-info', + show: !!this._documentInfoService, + }, + { + type: ActionTypes.circleBtn, + action: () => this._excludedPagesService.toggle(), + tooltip: _('file-preview.exclude-pages'), + ariaExpanded: this._excludedPagesService?.shown$, + showDot: !!this.file.excludedPages?.length, + icon: 'red:exclude-pages', + show: !!this._excludedPagesService, + }, + { + type: ActionTypes.circleBtn, + action: $event => this._setFileUnderApproval($event), + tooltip: _('dossier-overview.under-approval'), + icon: 'red:ready-for-approval', + show: this.showUnderApproval, + }, + { + type: ActionTypes.circleBtn, + action: $event => this._setFileUnderReview($event), + tooltip: _('dossier-overview.under-review'), + icon: 'red:undo', + show: this.showUnderReview, + }, + { + type: ActionTypes.circleBtn, + action: $event => this.setFileApproved($event), + tooltip: this.file.canBeApproved ? _('dossier-overview.approve') : _('dossier-overview.approve-disabled'), + icon: 'red:approved', + disabled: !this.file.canBeApproved, + show: this.showApprove, + }, + { + type: ActionTypes.circleBtn, + action: $event => this._setFileUnderApproval($event), + tooltip: _('dossier-overview.under-approval'), + icon: 'red:undo', + show: this.showUndoApproval, + }, + { + type: ActionTypes.circleBtn, + action: $event => this._ocrFile($event), + tooltip: _('dossier-overview.ocr-file'), + icon: 'iqser:ocr', + show: this.showOCR, + }, + { + type: ActionTypes.circleBtn, + action: $event => this._reanalyseFile($event), + tooltip: _('file-preview.reanalyse-notification'), + buttonType: CircleButtonTypes.warn, + tooltipClass: 'warn small', + icon: 'iqser:refresh', + show: this.showReanalyseFilePreview, + }, + { + type: ActionTypes.circleBtn, + action: $event => this._reanalyseFile($event), + tooltip: _('dossier-overview.reanalyse.action'), + icon: 'iqser:refresh', + show: this.showReanalyseDossierOverview, + }, + { + type: ActionTypes.toggle, + action: () => this._toggleAnalysis(), + disabled: !this.canToggleAnalysis, + tooltip: this.toggleTooltip, + class: { 'mr-24': this.isDossierOverviewList }, + checked: !this.file.excluded, + show: true, + }, + ].filter(btn => btn.show); + } + ngOnInit() { this._dossiersService.getEntityChanged$(this.file.dossierId).pipe(tap(() => this._setup())); } @@ -98,57 +239,6 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnDestroy, this._setup(); } - openDocument() { - this._router.navigate([this.file.routerLink]).then(); - } - - openDeleteFileDialog($event: MouseEvent) { - this._dialogService.openDialog( - 'confirm', - $event, - new ConfirmationDialogInput({ - title: _('confirmation-dialog.delete-file.title'), - question: _('confirmation-dialog.delete-file.question'), - }), - async () => { - this._loadingService.start(); - try { - const dossier = this._dossiersService.find(this.file.dossierId); - await this._fileManagementService.delete([this.file.fileId], this.file.dossierId).toPromise(); - await this._router.navigate([dossier.routerLink]); - } catch (error) { - this._toaster.error(_('error.http.generic'), { params: error }); - } - this._loadingService.stop(); - }, - ); - } - - assign($event: MouseEvent) { - const mode = this.file.isUnderApproval ? 'approver' : 'reviewer'; - const files = [this.file]; - const withCurrentUserAsDefault = true; - const withUnassignedOption = true; - this._dialogService.openDialog('assignFile', $event, { mode, files, withCurrentUserAsDefault, withUnassignedOption }); - } - - async assignToMe($event: MouseEvent) { - $event.stopPropagation(); - await this._fileAssignService.assignToMe([this.file]); - } - - async reanalyseFile($event?: MouseEvent) { - if ($event) { - $event.stopPropagation(); - } - await this._reanalysisService.reanalyzeFilesForDossier([this.file.fileId], this.file.dossierId, true).toPromise(); - } - - async setFileUnderApproval($event: MouseEvent) { - $event.stopPropagation(); - await this._fileAssignService.assignApprover($event, this.file, true); - } - async setFileApproved($event: MouseEvent) { $event.stopPropagation(); if (!this.file.hasUpdates) { @@ -169,7 +259,62 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnDestroy, ); } - async ocrFile($event: MouseEvent) { + forceReanalysisAction($event: LongPressEvent) { + this.analysisForced = !$event.touchEnd && this._userPreferenceService.areDevFeaturesEnabled; + } + + private _openDocument() { + this._router.navigate([this.file.routerLink]).then(); + } + + private _openDeleteFileDialog($event: MouseEvent) { + this._dialogService.openDialog( + 'confirm', + $event, + new ConfirmationDialogInput({ + title: _('confirmation-dialog.delete-file.title'), + question: _('confirmation-dialog.delete-file.question'), + }), + async () => { + this._loadingService.start(); + try { + const dossier = this._dossiersService.find(this.file.dossierId); + await this._fileManagementService.delete([this.file.fileId], this.file.dossierId).toPromise(); + await this._router.navigate([dossier.routerLink]); + } catch (error) { + this._toaster.error(_('error.http.generic'), { params: error }); + } + this._loadingService.stop(); + }, + ); + } + + private _assign($event: MouseEvent) { + const mode = this.file.isUnderApproval ? 'approver' : 'reviewer'; + const files = [this.file]; + const withCurrentUserAsDefault = true; + const withUnassignedOption = true; + this._dialogService.openDialog('assignFile', $event, { mode, files, withCurrentUserAsDefault, withUnassignedOption }); + } + + private async _assignToMe($event: MouseEvent) { + $event.stopPropagation(); + await this._fileAssignService.assignToMe([this.file]); + } + + private async _reanalyseFile($event?: MouseEvent) { + if ($event) { + $event.stopPropagation(); + } + await this._reanalysisService.reanalyzeFilesForDossier([this.file.fileId], this.file.dossierId, true).toPromise(); + } + + private async _setFileUnderApproval($event: MouseEvent) { + $event.stopPropagation(); + await this._fileAssignService.assignApprover($event, this.file, true); + } + + private async _ocrFile($event: MouseEvent) { $event.stopPropagation(); this._loadingService.start(); await this._reanalysisService.ocrFiles([this.file.fileId], this.file.dossierId).toPromise(); @@ -177,20 +322,16 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnDestroy, this._loadingService.stop(); } - async setFileUnderReview($event: MouseEvent, ignoreDialogChanges = false) { - await this._fileAssignService.assignReviewer($event, this.file, ignoreDialogChanges); + private async _setFileUnderReview($event: MouseEvent) { + await this._fileAssignService.assignReviewer($event, this.file, true); } - async toggleAnalysis() { + private async _toggleAnalysis() { this._loadingService.start(); await this._reanalysisService.toggleAnalysis(this.file.dossierId, this.file.fileId, !this.file.excluded).toPromise(); this._loadingService.stop(); } - forceReanalysisAction($event: LongPressEvent) { - this.analysisForced = !$event.touchEnd && this._userPreferenceService.areDevFeaturesEnabled; - } - private _setup() { this.isDossierOverviewList = this.type === 'dossier-overview-list'; this.isDossierOverviewWorkflow = this.type === 'dossier-overview-workflow'; @@ -221,6 +362,11 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnDestroy, this.isDossierOverview; this.showOpenDocument = this.file.canBeOpened && this.isDossierOverviewWorkflow; + + this.showReanalyseFilePreview = this.canReanalyse && this.isFilePreview && this.analysisForced; + this.showReanalyseDossierOverview = this.canReanalyse && this.isDossierOverview && this.analysisForced; + + this.buttons = this._buttons; } private async _setFileApproved() { diff --git a/apps/red-ui/src/app/modules/shared/components/buttons/file-download-btn/file-download-btn.component.ts b/apps/red-ui/src/app/modules/shared/components/buttons/file-download-btn/file-download-btn.component.ts index d80079779..97645d398 100644 --- a/apps/red-ui/src/app/modules/shared/components/buttons/file-download-btn/file-download-btn.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/buttons/file-download-btn/file-download-btn.component.ts @@ -2,7 +2,7 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; import { PermissionsService } from '@services/permissions.service'; import { File } from '@red/domain'; import { FileDownloadService } from '@upload-download/services/file-download.service'; -import { CircleButtonType, CircleButtonTypes, List, Toaster } from '@iqser/common-ui'; +import { CircleButtonType, CircleButtonTypes, Toaster } from '@iqser/common-ui'; import { TranslateService } from '@ngx-translate/core'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; @@ -15,7 +15,7 @@ export type MenuState = 'OPEN' | 'CLOSED'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class FileDownloadBtnComponent { - @Input() files: List; + @Input() files: File[]; @Input() tooltipPosition: 'above' | 'below' | 'before' | 'after' = 'above'; @Input() type: CircleButtonType = CircleButtonTypes.default; @Input() tooltipClass: string; @@ -29,7 +29,7 @@ export class FileDownloadBtnComponent { ) {} get canDownloadFiles() { - return this.files.length > 0 && this.files.reduce((acc, file) => acc && this._permissionsService.canDownloadFiles(file), true); + return this._permissionsService.canDownloadFiles(this.files); } get tooltip() { diff --git a/apps/red-ui/src/app/modules/shared/components/expandable-file-actions/expandable-file-actions.component.html b/apps/red-ui/src/app/modules/shared/components/expandable-file-actions/expandable-file-actions.component.html new file mode 100644 index 000000000..330b08556 --- /dev/null +++ b/apps/red-ui/src/app/modules/shared/components/expandable-file-actions/expandable-file-actions.component.html @@ -0,0 +1,64 @@ + + + + + + + +
+ +
+
+ + + + + + diff --git a/apps/red-ui/src/app/modules/shared/components/expandable-file-actions/expandable-file-actions.component.scss b/apps/red-ui/src/app/modules/shared/components/expandable-file-actions/expandable-file-actions.component.scss new file mode 100644 index 000000000..0bc36396d --- /dev/null +++ b/apps/red-ui/src/app/modules/shared/components/expandable-file-actions/expandable-file-actions.component.scss @@ -0,0 +1,27 @@ +:host { + display: contents; +} + +mat-slide-toggle { + height: 34px; + width: 34px; + line-height: 33px; + margin-left: 8px; + margin-right: 5px; +} + +.mat-menu-item { + mat-icon { + color: inherit; + width: 14px; + height: 14px; + } + + &[disabled] { + color: rgba(var(--iqser-accent-rgb), 0.3); + } +} + +.ml-0 { + margin-left: 0; +} diff --git a/apps/red-ui/src/app/modules/shared/components/expandable-file-actions/expandable-file-actions.component.ts b/apps/red-ui/src/app/modules/shared/components/expandable-file-actions/expandable-file-actions.component.ts new file mode 100644 index 000000000..318ecab8d --- /dev/null +++ b/apps/red-ui/src/app/modules/shared/components/expandable-file-actions/expandable-file-actions.component.ts @@ -0,0 +1,38 @@ +import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core'; +import { Action } from './types'; +import { CircleButtonType, IqserTooltipPosition } from '@iqser/common-ui'; + +@Component({ + selector: 'redaction-expandable-file-actions', + templateUrl: './expandable-file-actions.component.html', + styleUrls: ['./expandable-file-actions.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ExpandableFileActionsComponent implements OnChanges { + @Input() maxWidth: number; + @Input() actions: Action[]; + @Input() buttonType: CircleButtonType; + @Input() tooltipPosition: IqserTooltipPosition; + + displayedButtons: Action[]; + hiddenButtons: Action[]; + expanded = false; + + ngOnChanges(changes: SimpleChanges) { + if (changes.actions || changes.maxWidth) { + if (this.maxWidth) { + const count = Math.floor(this.maxWidth / 36); + if (count >= this.actions.length) { + this.displayedButtons = [...this.actions]; + this.hiddenButtons = []; + } else { + this.displayedButtons = this.actions.slice(0, count - 1); + this.hiddenButtons = this.actions.slice(count - 1); + } + } else { + this.displayedButtons = [...this.actions]; + this.hiddenButtons = []; + } + } + } +} diff --git a/apps/red-ui/src/app/modules/shared/components/expandable-file-actions/types.ts b/apps/red-ui/src/app/modules/shared/components/expandable-file-actions/types.ts new file mode 100644 index 000000000..fe73bfd0b --- /dev/null +++ b/apps/red-ui/src/app/modules/shared/components/expandable-file-actions/types.ts @@ -0,0 +1,27 @@ +import { Observable } from 'rxjs'; +import { CircleButtonType } from '@iqser/common-ui'; +import { File } from '@red/domain'; + +export type ActionType = 'circleBtn' | 'downloadBtn' | 'toggle'; + +export const ActionTypes = { + circleBtn: 'circleBtn' as ActionType, + downloadBtn: 'downloadBtn' as ActionType, + toggle: 'toggle' as ActionType, +}; + +export interface Action { + action?: Function; + tooltip?: string; + icon?: string; + show?: boolean; + ariaExpanded?: Observable; + showDot?: boolean; + disabled?: boolean; + buttonType?: CircleButtonType; + tooltipClass?: string; + checked?: boolean; + class?: { [key: string]: boolean }; + files?: File[]; + type: ActionType; +} diff --git a/apps/red-ui/src/app/modules/shared/shared.module.ts b/apps/red-ui/src/app/modules/shared/shared.module.ts index 15067cdb9..4f606ceb9 100644 --- a/apps/red-ui/src/app/modules/shared/shared.module.ts +++ b/apps/red-ui/src/app/modules/shared/shared.module.ts @@ -25,6 +25,7 @@ import { NamePipe } from './pipes/name.pipe'; import { TypeFilterComponent } from './components/type-filter/type-filter.component'; import { TeamMembersComponent } from './components/team-members/team-members.component'; import { EditorComponent } from './components/editor/editor.component'; +import { ExpandableFileActionsComponent } from './components/expandable-file-actions/expandable-file-actions.component'; const buttons = [FileDownloadBtnComponent, UserButtonComponent]; @@ -39,6 +40,7 @@ const components = [ AssignUserDropdownComponent, TypeFilterComponent, TeamMembersComponent, + ExpandableFileActionsComponent, ...buttons, ]; diff --git a/apps/red-ui/src/app/services/permissions.service.ts b/apps/red-ui/src/app/services/permissions.service.ts index 65f8c7b24..f1ab0c5bb 100644 --- a/apps/red-ui/src/app/services/permissions.service.ts +++ b/apps/red-ui/src/app/services/permissions.service.ts @@ -99,13 +99,12 @@ export class PermissionsService { return (file.isUnderReview || file.isUnderApproval) && this.isFileAssignee(file); } - canDownloadFiles(file: File): boolean { - const dossier = this._getDossier(file); - if (!dossier) { + canDownloadFiles(files: File[]): boolean { + if (files.length === 0) { return false; } - - return file.isApproved && this.isApprover(dossier); + const dossier = this._getDossier(files[0]); + return this.isApprover(dossier) && files.reduce((prev, file) => prev && file.isApproved, true); } canDeleteDossier(dossier: Dossier): boolean { diff --git a/libs/common-ui b/libs/common-ui index 0a861bf60..4a27531b8 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit 0a861bf60d47504a0c8cba019671da05dcdb3a28 +Subproject commit 4a27531b8e52cea707909f5d93f68b303e587945 diff --git a/libs/red-domain/src/lib/files/file.model.ts b/libs/red-domain/src/lib/files/file.model.ts index 2b38c7920..4e839dace 100644 --- a/libs/red-domain/src/lib/files/file.model.ts +++ b/libs/red-domain/src/lib/files/file.model.ts @@ -45,7 +45,6 @@ export class File extends Entity implements IFile { readonly hintsOnly: boolean; readonly hasNone: boolean; readonly isNew: boolean; - // readonly isUnassigned: boolean; readonly isError: boolean; readonly isProcessing: boolean; readonly isApproved: boolean;