Workflow initial
This commit is contained in:
parent
c975fc859f
commit
b9ecec3e52
@ -14,12 +14,12 @@
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
padding: 0 8px;
|
||||
padding: 4px 8px;
|
||||
margin-left: -8px;
|
||||
|
||||
&.link-property {
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2;
|
||||
transition: background-color 0.2s;
|
||||
|
||||
&:hover {
|
||||
background-color: $grey-6;
|
||||
|
||||
@ -1,17 +1,26 @@
|
||||
<div *ngIf="screen === 'dossier-overview'" class="action-buttons">
|
||||
<div *ngIf="isDossierOverviewList" class="action-buttons">
|
||||
<ng-container *ngTemplateOutlet="actions"></ng-container>
|
||||
<iqser-status-bar *ngIf="isWorkable" [configs]="statusBarConfig"></iqser-status-bar>
|
||||
<iqser-status-bar *ngIf="showStatusBar" [configs]="statusBarConfig"></iqser-status-bar>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="screen === 'file-preview'">
|
||||
<ng-container *ngIf="isFilePreview || isDossierOverviewWorkflow">
|
||||
<ng-container *ngTemplateOutlet="actions"></ng-container>
|
||||
</ng-container>
|
||||
|
||||
<ng-template #actions>
|
||||
<div class="file-actions" *ngIf="fileStatus">
|
||||
<div *ngIf="fileStatus" class="file-actions">
|
||||
<iqser-circle-button
|
||||
(action)="openDocument()"
|
||||
*ngIf="showOpenDocument"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[tooltip]="'dossier-overview.open-document' | translate"
|
||||
[type]="buttonType"
|
||||
icon="red:collapse"
|
||||
></iqser-circle-button>
|
||||
|
||||
<iqser-circle-button
|
||||
(action)="openDeleteFileDialog($event)"
|
||||
*ngIf="canDelete"
|
||||
*ngIf="showDelete"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[tooltip]="'dossier-overview.delete.action' | translate"
|
||||
[type]="buttonType"
|
||||
@ -20,7 +29,7 @@
|
||||
|
||||
<iqser-circle-button
|
||||
(action)="assign($event)"
|
||||
*ngIf="canAssign && screen === 'dossier-overview'"
|
||||
*ngIf="showAssign"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[tooltip]="assignTooltip | translate"
|
||||
[type]="buttonType"
|
||||
@ -29,7 +38,7 @@
|
||||
|
||||
<iqser-circle-button
|
||||
(action)="assignToMe($event)"
|
||||
*ngIf="canAssignToSelf && screen === 'dossier-overview'"
|
||||
*ngIf="showAssignToSelf"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[tooltip]="'dossier-overview.assign-me' | translate"
|
||||
[type]="buttonType"
|
||||
@ -47,7 +56,7 @@
|
||||
|
||||
<iqser-circle-button
|
||||
(action)="toggleViewDocumentInfo()"
|
||||
*ngIf="screen === 'file-preview'"
|
||||
*ngIf="showDocumentInfo"
|
||||
[attr.aria-expanded]="activeDocumentInfo"
|
||||
[tooltip]="'file-preview.document-info' | translate"
|
||||
icon="red:status-info"
|
||||
@ -56,7 +65,7 @@
|
||||
|
||||
<iqser-circle-button
|
||||
(action)="toggleExcludePages()"
|
||||
*ngIf="screen === 'file-preview'"
|
||||
*ngIf="showExcludePages"
|
||||
[attr.aria-expanded]="activeExcludePages"
|
||||
[showDot]="!!fileStatus.excludedPages?.length"
|
||||
[tooltip]="'file-preview.exclude-pages' | translate"
|
||||
@ -67,7 +76,7 @@
|
||||
<!-- Ready for approval-->
|
||||
<iqser-circle-button
|
||||
(action)="setFileUnderApproval($event)"
|
||||
*ngIf="canSetToUnderApproval"
|
||||
*ngIf="showUnderApproval"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[tooltip]="'dossier-overview.under-approval' | translate"
|
||||
[type]="buttonType"
|
||||
@ -77,7 +86,7 @@
|
||||
<!-- Back to review -->
|
||||
<iqser-circle-button
|
||||
(action)="setFileUnderReview($event, true)"
|
||||
*ngIf="canSetToUnderReview"
|
||||
*ngIf="showUnderReview"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[tooltip]="'dossier-overview.under-review' | translate"
|
||||
[type]="buttonType"
|
||||
@ -87,7 +96,7 @@
|
||||
<!-- Approved-->
|
||||
<iqser-circle-button
|
||||
(action)="setFileApproved($event)"
|
||||
*ngIf="readyForApproval"
|
||||
*ngIf="showApprove"
|
||||
[disabled]="!fileStatus.canBeApproved"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[tooltip]="
|
||||
@ -100,7 +109,7 @@
|
||||
<!-- Back to approval -->
|
||||
<iqser-circle-button
|
||||
(action)="setFileUnderApproval($event)"
|
||||
*ngIf="canUndoApproval"
|
||||
*ngIf="showUndoApproval"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[tooltip]="'dossier-overview.under-approval' | translate"
|
||||
[type]="buttonType"
|
||||
@ -109,7 +118,7 @@
|
||||
|
||||
<iqser-circle-button
|
||||
(action)="ocrFile($event)"
|
||||
*ngIf="fileStatus.canBeOCRed"
|
||||
*ngIf="showOCR"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[tooltip]="'dossier-overview.ocr-file' | translate"
|
||||
[type]="buttonType"
|
||||
@ -119,22 +128,22 @@
|
||||
<!-- reanalyse file preview -->
|
||||
<iqser-circle-button
|
||||
(action)="reanalyseFile($event)"
|
||||
*ngIf="canReanalyse && screen === 'file-preview'"
|
||||
*ngIf="canReanalyse && isFilePreview"
|
||||
[tooltip]="'file-preview.reanalyse-notification' | translate"
|
||||
[type]="circleButtonTypes.warn"
|
||||
icon="iqser:refresh"
|
||||
tooltipClass="warn small"
|
||||
tooltipPosition="below"
|
||||
[type]="circleButtonTypes.warn"
|
||||
></iqser-circle-button>
|
||||
|
||||
<!-- reanalyse file listing -->
|
||||
<iqser-circle-button
|
||||
(action)="reanalyseFile($event)"
|
||||
*ngIf="canReanalyse && screen === 'dossier-overview'"
|
||||
*ngIf="canReanalyse && isDossierOverview"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[tooltip]="'dossier-overview.reanalyse.action' | translate"
|
||||
icon="iqser:refresh"
|
||||
[type]="circleButtonTypes.dark"
|
||||
icon="iqser:refresh"
|
||||
></iqser-circle-button>
|
||||
|
||||
<!-- exclude from redaction -->
|
||||
@ -143,7 +152,7 @@
|
||||
(change)="toggleAnalysis()"
|
||||
(click)="$event.stopPropagation()"
|
||||
[checked]="!fileStatus?.excluded"
|
||||
[class.mr-24]="screen === 'dossier-overview'"
|
||||
[class.mr-24]="isDossierOverviewList"
|
||||
[disabled]="!canToggleAnalysis"
|
||||
[matTooltipPosition]="tooltipPosition"
|
||||
[matTooltip]="toggleTooltip | translate"
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
@import 'libs/common-ui/src/assets/styles/mixins';
|
||||
|
||||
.file-actions {
|
||||
display: flex;
|
||||
overflow-y: auto;
|
||||
@include no-scroll-bar;
|
||||
|
||||
> *:not(:last-child) {
|
||||
margin-right: 2px;
|
||||
|
||||
@ -5,7 +5,7 @@ import { AppStateService } from '@state/app-state.service';
|
||||
import { FileActionService } from '../../services/file-action.service';
|
||||
import { DossiersDialogService } from '../../services/dossiers-dialog.service';
|
||||
import { ConfirmationDialogInput } from '@shared/dialogs/confirmation-dialog/confirmation-dialog.component';
|
||||
import { AutoUnsubscribe, CircleButtonType, CircleButtonTypes, LoadingService, StatusBarConfig, Toaster } from '@iqser/common-ui';
|
||||
import { AutoUnsubscribe, CircleButtonType, CircleButtonTypes, LoadingService, Required, StatusBarConfig, Toaster } from '@iqser/common-ui';
|
||||
import { FileManagementControllerService, FileStatus } from '@redaction/red-ui-http';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { UserService } from '@services/user.service';
|
||||
@ -23,25 +23,29 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD
|
||||
@Input() fileStatus: FileStatusWrapper;
|
||||
@Input() activeDocumentInfo: boolean;
|
||||
@Input() activeExcludePages: boolean;
|
||||
@Input() @Required() type: 'file-preview' | 'dossier-overview-list' | 'dossier-overview-workflow';
|
||||
@Output() actionPerformed = new EventEmitter<string>();
|
||||
|
||||
screen: 'file-preview' | 'dossier-overview';
|
||||
statusBarConfig?: readonly StatusBarConfig<FileStatus.StatusEnum>[];
|
||||
tooltipPosition?: 'below' | 'above';
|
||||
toggleTooltip?: string;
|
||||
assignTooltip?: string;
|
||||
buttonType?: CircleButtonType;
|
||||
isWorkable: boolean;
|
||||
|
||||
canUndoApproval: boolean;
|
||||
canAssignToSelf: boolean;
|
||||
canAssign: boolean;
|
||||
canDelete: boolean;
|
||||
showUndoApproval: boolean;
|
||||
showAssignToSelf: boolean;
|
||||
showAssign: boolean;
|
||||
showDelete: boolean;
|
||||
showOCR: boolean;
|
||||
canReanalyse: boolean;
|
||||
canSetToUnderReview: boolean;
|
||||
canSetToUnderApproval: boolean;
|
||||
readyForApproval: boolean;
|
||||
showUnderReview: boolean;
|
||||
showUnderApproval: boolean;
|
||||
showApprove: boolean;
|
||||
canToggleAnalysis: boolean;
|
||||
showExcludePages: boolean;
|
||||
showDocumentInfo: boolean;
|
||||
showStatusBar: boolean;
|
||||
showOpenDocument: boolean;
|
||||
|
||||
constructor(
|
||||
readonly permissionsService: PermissionsService,
|
||||
@ -56,6 +60,22 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD
|
||||
super();
|
||||
}
|
||||
|
||||
get isDossierOverviewList(): boolean {
|
||||
return this.type === 'dossier-overview-list';
|
||||
}
|
||||
|
||||
get isDossierOverviewWorkflow(): boolean {
|
||||
return this.type === 'dossier-overview-workflow';
|
||||
}
|
||||
|
||||
get isFilePreview(): boolean {
|
||||
return this.type === 'file-preview';
|
||||
}
|
||||
|
||||
get isDossierOverview(): boolean {
|
||||
return this.type.startsWith('dossier-overview-list');
|
||||
}
|
||||
|
||||
private get _toggleTooltip(): string {
|
||||
if (!this.currentUser.isManager) {
|
||||
return _('file-preview.toggle-analysis.only-managers');
|
||||
@ -65,13 +85,9 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
if (this.fileStatus) {
|
||||
this.screen = 'dossier-overview';
|
||||
} else {
|
||||
if (!this.fileStatus) {
|
||||
this.fileStatus = this.appStateService.activeFile;
|
||||
this.screen = 'file-preview';
|
||||
}
|
||||
|
||||
this._setup();
|
||||
this.addSubscription = this.appStateService.fileChanged$
|
||||
.pipe(filter(file => file.fileId === this.fileStatus?.fileId))
|
||||
@ -93,6 +109,10 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD
|
||||
this.actionPerformed.emit('view-exclude-pages');
|
||||
}
|
||||
|
||||
openDocument() {
|
||||
this.actionPerformed.emit('navigate');
|
||||
}
|
||||
|
||||
openDeleteFileDialog($event: MouseEvent) {
|
||||
this._dialogService.openDialog(
|
||||
'confirm',
|
||||
@ -194,22 +214,31 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD
|
||||
|
||||
private _setup() {
|
||||
this.statusBarConfig = [{ color: this.fileStatus.status, length: 1 }];
|
||||
this.tooltipPosition = this.screen === 'file-preview' ? 'below' : 'above';
|
||||
this.tooltipPosition = this.isFilePreview ? 'below' : 'above';
|
||||
this.assignTooltip = this.fileStatus.isUnderApproval
|
||||
? _('dossier-overview.assign-approver')
|
||||
: _('dossier-overview.assign-reviewer');
|
||||
this.buttonType = this.screen === 'file-preview' ? CircleButtonTypes.default : CircleButtonTypes.dark;
|
||||
this.isWorkable = this.fileStatus.isWorkable;
|
||||
this.buttonType = this.isFilePreview ? CircleButtonTypes.default : CircleButtonTypes.dark;
|
||||
this.toggleTooltip = this._toggleTooltip;
|
||||
|
||||
this.canUndoApproval = this.permissionsService.canUndoApproval(this.fileStatus);
|
||||
this.canAssignToSelf = this.permissionsService.canAssignToSelf(this.fileStatus);
|
||||
this.canAssign = this.permissionsService.canAssignUser(this.fileStatus);
|
||||
this.canDelete = this.permissionsService.canDeleteFile(this.fileStatus);
|
||||
this.canReanalyse = this.permissionsService.canReanalyseFile(this.fileStatus);
|
||||
this.canSetToUnderReview = this.permissionsService.canSetUnderReview(this.fileStatus);
|
||||
this.canSetToUnderApproval = this.permissionsService.canSetUnderApproval(this.fileStatus);
|
||||
this.readyForApproval = this.permissionsService.isReadyForApproval(this.fileStatus);
|
||||
this.showUndoApproval = this.permissionsService.canUndoApproval(this.fileStatus) && !this.isDossierOverviewWorkflow;
|
||||
this.showUnderReview = this.permissionsService.canSetUnderReview(this.fileStatus) && !this.isDossierOverviewWorkflow;
|
||||
this.showUnderApproval = this.permissionsService.canSetUnderApproval(this.fileStatus) && !this.isDossierOverviewWorkflow;
|
||||
this.showApprove = this.permissionsService.isReadyForApproval(this.fileStatus) && !this.isDossierOverviewWorkflow;
|
||||
|
||||
this.canToggleAnalysis = this.permissionsService.canToggleAnalysis(this.fileStatus);
|
||||
this.showDelete = this.permissionsService.canDeleteFile(this.fileStatus);
|
||||
this.showOCR = this.fileStatus.canBeOCRed;
|
||||
this.canReanalyse = this.permissionsService.canReanalyseFile(this.fileStatus);
|
||||
|
||||
this.showStatusBar = this.fileStatus.isWorkable && this.isDossierOverviewList;
|
||||
|
||||
this.showAssignToSelf = this.permissionsService.canAssignToSelf(this.fileStatus) && this.isDossierOverview;
|
||||
this.showAssign = this.permissionsService.canAssignUser(this.fileStatus) && this.isDossierOverview;
|
||||
|
||||
this.showOpenDocument = this.fileStatus.canBeOpened && this.isDossierOverviewWorkflow;
|
||||
|
||||
this.showExcludePages = this.isFilePreview;
|
||||
this.showDocumentInfo = this.isFilePreview;
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,10 +33,10 @@
|
||||
|
||||
<ng-template #nameTemplate let-dossier="entity">
|
||||
<div class="cell">
|
||||
<div [matTooltip]="dossier.dossierName" class="table-item-title heading" matTooltipPosition="above">
|
||||
<div [matTooltip]="dossier.dossierName" class="table-item-title heading mb-6" matTooltipPosition="above">
|
||||
{{ dossier.dossierName }}
|
||||
</div>
|
||||
<div class="small-label stats-subtitle">
|
||||
<div class="small-label stats-subtitle mb-6">
|
||||
<div>
|
||||
<mat-icon svgIcon="red:template"></mat-icon>
|
||||
{{ dossier.dossierTemplateName }}
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
[actionConfigs]="actionConfigs"
|
||||
[fileAttributeConfigs]="fileAttributeConfigs"
|
||||
[showCloseButton]="true"
|
||||
[viewModeSelection]="viewModeSelection"
|
||||
>
|
||||
<redaction-file-download-btn
|
||||
[dossier]="currentDossier"
|
||||
@ -37,6 +38,7 @@
|
||||
<div [class.extended]="collapsedDetails" class="content-container">
|
||||
<iqser-table
|
||||
(noDataAction)="fileInput.click()"
|
||||
*ngIf="(listingMode$ | async) === listingModes.table"
|
||||
[bulkActions]="bulkActions"
|
||||
[hasScrollButton]="true"
|
||||
[itemSize]="80"
|
||||
@ -49,6 +51,12 @@
|
||||
noDataButtonIcon="red:upload"
|
||||
noDataIcon="red:document"
|
||||
></iqser-table>
|
||||
|
||||
<iqser-workflow
|
||||
*ngIf="(listingMode$ | async) === listingModes.workflow"
|
||||
[config]="workflowConfig"
|
||||
[itemTemplate]="workflowItemTemplate"
|
||||
></iqser-workflow>
|
||||
</div>
|
||||
|
||||
<div [class.collapsed]="collapsedDetails" class="right-container" iqserHasScrollbar>
|
||||
@ -74,34 +82,21 @@
|
||||
|
||||
<ng-template #filenameTemplate let-fileStatus="entity">
|
||||
<div class="cell">
|
||||
<div class="filename-wrapper">
|
||||
<div [class.error]="fileStatus.isError" class="table-item-title text-overflow">
|
||||
<div>
|
||||
<div [class.error]="fileStatus.isError" class="table-item-title">
|
||||
<span [matTooltip]="fileStatus.filename" matTooltipPosition="above">
|
||||
{{ fileStatus.filename }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="fileStatus.primaryAttribute" class="small-label">
|
||||
<div class="primary-attribute text-overflow">
|
||||
<div class="primary-attribute">
|
||||
<span [matTooltip]="fileStatus.primaryAttribute" matTooltipPosition="above">
|
||||
{{ fileStatus.primaryAttribute }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="small-label stats-subtitle">
|
||||
<div>
|
||||
<mat-icon svgIcon="red:pages"></mat-icon>
|
||||
{{ fileStatus.numberOfPages }}
|
||||
</div>
|
||||
<div>
|
||||
<mat-icon svgIcon="red:exclude-pages"></mat-icon>
|
||||
{{ fileStatus.excludedPagesCount }}
|
||||
</div>
|
||||
<div *ngIf="fileStatus.lastOCRTime" [matTooltipPosition]="'above'" [matTooltip]="'dossier-overview.ocr-performed' | translate">
|
||||
<mat-icon svgIcon="red:ocr"></mat-icon>
|
||||
{{ fileStatus.lastOCRTime | date: 'mediumDate' }}
|
||||
</div>
|
||||
</div>
|
||||
<ng-container *ngTemplateOutlet="statsTemplate; context: { entity: fileStatus }"></ng-container>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
@ -167,10 +162,71 @@
|
||||
></iqser-status-bar>
|
||||
|
||||
<redaction-file-actions
|
||||
(actionPerformed)="calculateData()"
|
||||
(actionPerformed)="actionPerformed()"
|
||||
*ngIf="!fileStatus.isProcessing"
|
||||
[fileStatus]="fileStatus"
|
||||
class="mr-4"
|
||||
type="dossier-overview-list"
|
||||
></redaction-file-actions>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #viewModeSelection>
|
||||
<div class="view-mode-selection">
|
||||
<div class="all-caps-label" translate="view-mode.view-as"></div>
|
||||
<iqser-circle-button
|
||||
(action)="listingMode = listingModes.workflow"
|
||||
[attr.aria-expanded]="(listingMode$ | async) === listingModes.workflow"
|
||||
[tooltip]="'view-mode.workflow' | translate"
|
||||
icon="iqser:lanes"
|
||||
></iqser-circle-button>
|
||||
|
||||
<iqser-circle-button
|
||||
(action)="listingMode = listingModes.table"
|
||||
[attr.aria-expanded]="(listingMode$ | async) === listingModes.table"
|
||||
[tooltip]="'view-mode.list' | translate"
|
||||
icon="iqser:list"
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #workflowItemTemplate let-fileStatus="entity">
|
||||
<div class="workflow-item">
|
||||
<div>
|
||||
<div class="details">
|
||||
<div class="filename">
|
||||
<span [matTooltip]="fileStatus.filename" matTooltipPosition="above">
|
||||
{{ fileStatus.filename }}
|
||||
</span>
|
||||
</div>
|
||||
<ng-container *ngTemplateOutlet="statsTemplate; context: { entity: fileStatus }"></ng-container>
|
||||
</div>
|
||||
<div class="user">
|
||||
<redaction-initials-avatar [userId]="fileStatus.currentReviewer"></redaction-initials-avatar>
|
||||
</div>
|
||||
</div>
|
||||
<redaction-file-actions
|
||||
(actionPerformed)="actionPerformed($event, fileStatus)"
|
||||
*ngIf="!fileStatus.isProcessing"
|
||||
[fileStatus]="fileStatus"
|
||||
type="dossier-overview-workflow"
|
||||
></redaction-file-actions>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #statsTemplate let-fileStatus="entity">
|
||||
<div class="small-label stats-subtitle">
|
||||
<div>
|
||||
<mat-icon svgIcon="red:pages"></mat-icon>
|
||||
{{ fileStatus.numberOfPages }}
|
||||
</div>
|
||||
<div>
|
||||
<mat-icon svgIcon="red:exclude-pages"></mat-icon>
|
||||
{{ fileStatus.excludedPagesCount }}
|
||||
</div>
|
||||
<div *ngIf="fileStatus.lastOCRTime" [matTooltipPosition]="'above'" [matTooltip]="'dossier-overview.ocr-performed' | translate">
|
||||
<mat-icon svgIcon="red:ocr"></mat-icon>
|
||||
{{ fileStatus.lastOCRTime | date: 'mediumDate' }}
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@import 'libs/common-ui/src/assets/styles/mixins';
|
||||
|
||||
.file-upload-input {
|
||||
display: none;
|
||||
@ -27,6 +28,7 @@
|
||||
|
||||
.primary-attribute {
|
||||
padding-top: 6px;
|
||||
@include line-clamp(1);
|
||||
}
|
||||
|
||||
&.extend-cols {
|
||||
@ -63,3 +65,55 @@
|
||||
background-color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.view-mode-selection {
|
||||
border-right: 1px solid $separator;
|
||||
padding-right: 16px;
|
||||
margin-right: 16px !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> iqser-circle-button:not(:last-child) {
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
> div {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.workflow-item {
|
||||
padding: 10px;
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.details {
|
||||
max-width: calc(100% - 28px);
|
||||
|
||||
.filename {
|
||||
font-weight: 600;
|
||||
@include line-clamp(1);
|
||||
}
|
||||
}
|
||||
|
||||
.user {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
redaction-file-actions {
|
||||
margin-top: 10px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover redaction-file-actions {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.stats-subtitle {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ import {
|
||||
TemplateRef,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import { FileAttributeConfig, FileStatus } from '@redaction/red-ui-http';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { FileDropOverlayService } from '@upload-download/services/file-drop-overlay.service';
|
||||
import { FileUploadModel } from '@upload-download/model/file-upload.model';
|
||||
@ -34,11 +35,13 @@ import {
|
||||
DefaultListingServices,
|
||||
keyChecker,
|
||||
ListingComponent,
|
||||
ListingModes,
|
||||
LoadingService,
|
||||
NestedFilter,
|
||||
TableColumnConfig,
|
||||
TableComponent,
|
||||
Toaster
|
||||
Toaster,
|
||||
WorkflowConfig
|
||||
} from '@iqser/common-ui';
|
||||
import { DossierAttributesService } from '@shared/services/controller-wrappers/dossier-attributes.service';
|
||||
import { DossierAttributeWithValue } from '@models/dossier-attributes.model';
|
||||
@ -49,8 +52,10 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { annotationFilterChecker } from '@utils/filter-utils';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { RouterHistoryService } from '@services/router-history.service';
|
||||
import { FileAttributeConfig } from '@redaction/red-ui-http';
|
||||
import { DossierWrapper } from '../../../../state/model/dossier.wrapper';
|
||||
import { Router } from '@angular/router';
|
||||
import { FileActionService } from '../../services/file-action.service';
|
||||
import StatusEnum = FileStatus.StatusEnum;
|
||||
|
||||
@Component({
|
||||
templateUrl: './dossier-overview-screen.component.html',
|
||||
@ -58,6 +63,7 @@ import { DossierWrapper } from '../../../../state/model/dossier.wrapper';
|
||||
providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => DossierOverviewScreenComponent) }]
|
||||
})
|
||||
export class DossierOverviewScreenComponent extends ListingComponent<FileStatusWrapper> implements OnInit, OnDestroy, OnDetach, OnAttach {
|
||||
readonly listingModes = ListingModes;
|
||||
readonly circleButtonTypes = CircleButtonTypes;
|
||||
readonly currentUser = this._userService.currentUser;
|
||||
currentDossier = this._appStateService.activeDossier;
|
||||
@ -81,6 +87,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
@ViewChild('reviewerTemplate', { static: true }) reviewerTemplate: TemplateRef<never>;
|
||||
@ViewChild('pagesTemplate', { static: true }) pagesTemplate: TemplateRef<never>;
|
||||
@ViewChild('statusTemplate', { static: true }) statusTemplate: TemplateRef<never>;
|
||||
readonly workflowConfig: WorkflowConfig<FileStatusWrapper, StatusEnum>;
|
||||
protected readonly _primaryKey = 'filename';
|
||||
@ViewChild(DossierDetailsComponent, { static: false })
|
||||
private readonly _dossierDetailsComponent: DossierDetailsComponent;
|
||||
@ -93,6 +100,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
constructor(
|
||||
private readonly _toaster: Toaster,
|
||||
protected readonly _injector: Injector,
|
||||
private readonly _router: Router,
|
||||
private readonly _userService: UserService,
|
||||
readonly permissionsService: PermissionsService,
|
||||
private readonly _loadingService: LoadingService,
|
||||
@ -106,13 +114,49 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
private readonly _statusOverlayService: StatusOverlayService,
|
||||
private readonly _userPreferenceService: UserPreferenceService,
|
||||
private readonly _fileDropOverlayService: FileDropOverlayService,
|
||||
private readonly _dossierAttributesService: DossierAttributesService
|
||||
private readonly _dossierAttributesService: DossierAttributesService,
|
||||
private readonly _fileActionService: FileActionService
|
||||
) {
|
||||
super(_injector);
|
||||
this._loadEntitiesFromState();
|
||||
this.fileAttributeConfigs = this._appStateService.getFileAttributeConfig(
|
||||
this.currentDossier.dossierTemplateId
|
||||
).fileAttributeConfigs;
|
||||
this.listingMode = this.listingModes.workflow;
|
||||
this.workflowConfig = {
|
||||
key: 'status',
|
||||
columns: [
|
||||
{
|
||||
label: fileStatusTranslations[StatusEnum.UNASSIGNED],
|
||||
key: StatusEnum.UNASSIGNED,
|
||||
enterFn: this.unassignFn,
|
||||
enterPredicate: (entity: FileStatusWrapper) => !!entity,
|
||||
color: '#D3D5DA'
|
||||
},
|
||||
{
|
||||
label: fileStatusTranslations[StatusEnum.UNDERREVIEW],
|
||||
enterFn: this.underReviewFn,
|
||||
enterPredicate: (file: FileStatusWrapper) => this.permissionsService.canAssignUser(file),
|
||||
key: StatusEnum.UNDERREVIEW,
|
||||
color: '#FDBD00'
|
||||
},
|
||||
{
|
||||
label: fileStatusTranslations[StatusEnum.UNDERAPPROVAL],
|
||||
enterFn: this.underApprovalFn,
|
||||
enterPredicate: (file: FileStatusWrapper) =>
|
||||
this.permissionsService.canSetUnderApproval(file) || this.permissionsService.canUndoApproval(file),
|
||||
key: StatusEnum.UNDERAPPROVAL,
|
||||
color: '#374C81'
|
||||
},
|
||||
{
|
||||
label: fileStatusTranslations[StatusEnum.APPROVED],
|
||||
enterFn: this.approveFn,
|
||||
enterPredicate: (file: FileStatusWrapper) => this.permissionsService.isReadyForApproval(file),
|
||||
key: StatusEnum.APPROVED,
|
||||
color: '#48C9F7'
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
get checkedRequiredFilters() {
|
||||
@ -127,10 +171,46 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
return this.fileAttributeConfigs.filter(config => config.displayedInFileList);
|
||||
}
|
||||
|
||||
unassignFn = async (file: FileStatusWrapper) => {
|
||||
// TODO
|
||||
console.log('unassign', file);
|
||||
};
|
||||
|
||||
underReviewFn = (file: FileStatusWrapper) => {
|
||||
this._fileActionService.assignFile('reviewer', null, file, () => this._loadingService.loadWhile(this.reloadDossiers()), true);
|
||||
};
|
||||
|
||||
underApprovalFn = async (file: FileStatusWrapper) => {
|
||||
if (this._appStateService.activeDossier.approverIds.length > 1) {
|
||||
this._fileActionService.assignFile('approver', null, file, () => this._loadingService.loadWhile(this.reloadDossiers()), true);
|
||||
} else {
|
||||
this._loadingService.start();
|
||||
await this._fileActionService.setFileUnderApproval(file).toPromise();
|
||||
await this.reloadDossiers();
|
||||
this._loadingService.stop();
|
||||
}
|
||||
};
|
||||
|
||||
approveFn = async (file: FileStatusWrapper) => {
|
||||
this._loadingService.start();
|
||||
await this._fileActionService.setFileApproved(file).toPromise();
|
||||
await this.reloadDossiers();
|
||||
this._loadingService.stop();
|
||||
};
|
||||
|
||||
actionPerformed(action?: string, fileStatus?: FileStatusWrapper) {
|
||||
this._calculateData();
|
||||
|
||||
if (action === 'navigate') {
|
||||
this._router.navigate(this.routerLinkFn(fileStatus));
|
||||
}
|
||||
}
|
||||
|
||||
routerLinkFn = (fileStatus: FileStatusWrapper) =>
|
||||
fileStatus.canBeOpened ? [`/main/dossiers/${this.currentDossier.dossierId}/file/${fileStatus.fileId}`] : [];
|
||||
|
||||
disabledFn = (fileStatus: FileStatusWrapper) => fileStatus.excluded;
|
||||
|
||||
lastOpenedFn = (fileStatus: FileStatusWrapper) => fileStatus.lastOpened;
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
@ -139,7 +219,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
try {
|
||||
this._fileDropOverlayService.initFileDropHandling();
|
||||
|
||||
this.calculateData();
|
||||
this._calculateData();
|
||||
|
||||
this.addSubscription = timer(0, 7500).subscribe(async () => {
|
||||
await this._appStateService.reloadActiveDossierFilesIfNecessary();
|
||||
@ -147,7 +227,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
});
|
||||
|
||||
this.addSubscription = this._appStateService.fileChanged$.subscribe(() => {
|
||||
this.calculateData();
|
||||
this._calculateData();
|
||||
});
|
||||
|
||||
this.addSubscription = this._appStateService.dossierTemplateChanged$.subscribe(() => {
|
||||
@ -197,10 +277,10 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
|
||||
async reloadDossiers() {
|
||||
await this._appStateService.getFiles(this.currentDossier, false);
|
||||
this.calculateData();
|
||||
this._calculateData();
|
||||
}
|
||||
|
||||
calculateData(): void {
|
||||
_calculateData(): void {
|
||||
if (!this._appStateService.activeDossierId) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -91,6 +91,7 @@
|
||||
(actionPerformed)="fileActionPerformed($event)"
|
||||
[activeDocumentInfo]="viewDocumentInfo"
|
||||
[activeExcludePages]="excludePages"
|
||||
type="file-preview"
|
||||
></redaction-file-actions>
|
||||
|
||||
<iqser-circle-button
|
||||
@ -106,10 +107,10 @@
|
||||
(action)="downloadOriginalFile()"
|
||||
*ngIf="userPreferenceService.areDevFeaturesEnabled"
|
||||
[tooltip]="'file-preview.download-original-file' | translate"
|
||||
[type]="circleButtonTypes.primary"
|
||||
class="ml-8"
|
||||
icon="red:download"
|
||||
tooltipPosition="below"
|
||||
[type]="circleButtonTypes.primary"
|
||||
></iqser-circle-button>
|
||||
<!-- End Dev Mode Features-->
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@ import { isArray } from 'rxjs/internal-compatibility';
|
||||
import { DossiersDialogService } from './dossiers-dialog.service';
|
||||
import { ConfirmationDialogInput } from '../../shared/dialogs/confirmation-dialog/confirmation-dialog.component';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
@Injectable()
|
||||
export class FileActionService {
|
||||
@ -83,7 +84,7 @@ export class FileActionService {
|
||||
);
|
||||
}
|
||||
|
||||
setFileApproved(fileStatus: FileStatusWrapper | FileStatusWrapper[]) {
|
||||
setFileApproved(fileStatus: FileStatusWrapper | FileStatusWrapper[]): Observable<any> {
|
||||
if (!isArray(fileStatus)) {
|
||||
fileStatus = [fileStatus];
|
||||
}
|
||||
@ -116,11 +117,7 @@ export class FileActionService {
|
||||
assignFile(mode: 'reviewer' | 'approver', $event: MouseEvent, file?: FileStatusWrapper, callback?: Function, ignoreChanged = false) {
|
||||
const files = file ? [file] : [this._appStateService.activeFile];
|
||||
const data = { mode, files, ignoreChanged };
|
||||
this._dialogService.openDialog('assignFile', $event, data, async () => {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
this._dialogService.openDialog('assignFile', $event, data, callback);
|
||||
}
|
||||
|
||||
private async _assignReviewerToCurrentUser(fileStatus: FileStatusWrapper | FileStatusWrapper[], callback?: Function) {
|
||||
|
||||
@ -15,7 +15,9 @@
|
||||
<div (click)="resetFilters()" *ngIf="showResetFilters$ | async" class="reset-filters" translate="reset-filters"></div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="showCloseButton || actionConfigs || buttonConfigs" class="actions">
|
||||
<div *ngIf="showCloseButton || actionConfigs || buttonConfigs || viewModeSelection" class="actions">
|
||||
<ng-container [ngTemplateOutlet]="viewModeSelection"></ng-container>
|
||||
|
||||
<ng-container *ngFor="let config of buttonConfigs; trackBy: trackByLabel">
|
||||
<iqser-icon-button
|
||||
(action)="config.action($event)"
|
||||
@ -53,10 +55,10 @@
|
||||
|
||||
<ng-template #searchBar>
|
||||
<iqser-input-with-action
|
||||
[(value)]="searchService.searchValue"
|
||||
*ngIf="searchPlaceholder && searchService"
|
||||
[(value)]="searchService.searchValue"
|
||||
[class.mr-8]="searchPosition === searchPositions.beforeFilters"
|
||||
[placeholder]="searchPlaceholder"
|
||||
[width]="searchWidth"
|
||||
[class.mr-8]="searchPosition === searchPositions.beforeFilters"
|
||||
></iqser-input-with-action>
|
||||
</ng-template>
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
|
||||
.ml-6 {
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Component, EventEmitter, Input, Optional, Output } from '@angular/core';
|
||||
import { Component, EventEmitter, Input, Optional, Output, TemplateRef } from '@angular/core';
|
||||
import { ActionConfig } from '@shared/components/page-header/models/action-config.model';
|
||||
import { ButtonConfig } from '@shared/components/page-header/models/button-config.model';
|
||||
import { FilterService, SearchService } from '@iqser/common-ui';
|
||||
import { FilterService, IconButtonTypes, Listable, SearchService } from '@iqser/common-ui';
|
||||
import { distinctUntilChanged, map } from 'rxjs/operators';
|
||||
import { combineLatest, Observable, of } from 'rxjs';
|
||||
import { SearchPosition, SearchPositions } from '@shared/components/page-header/models/search-positions.type';
|
||||
@ -12,13 +12,15 @@ import { FileAttributeConfig } from '@redaction/red-ui-http';
|
||||
templateUrl: './page-header.component.html',
|
||||
styleUrls: ['./page-header.component.scss']
|
||||
})
|
||||
export class PageHeaderComponent<T> {
|
||||
export class PageHeaderComponent<T extends Listable> {
|
||||
readonly searchPositions = SearchPositions;
|
||||
readonly iconButtonTypes = IconButtonTypes;
|
||||
|
||||
@Input() pageLabel: string;
|
||||
@Input() showCloseButton: boolean;
|
||||
@Input() actionConfigs: readonly ActionConfig[];
|
||||
@Input() buttonConfigs: readonly ButtonConfig[];
|
||||
@Input() viewModeSelection: TemplateRef<unknown>;
|
||||
@Input() fileAttributeConfigs: readonly FileAttributeConfig[];
|
||||
@Input() searchPlaceholder: string;
|
||||
@Input() searchWidth: number | 'full';
|
||||
|
||||
@ -680,6 +680,7 @@
|
||||
},
|
||||
"ocr-file": "OCR Document",
|
||||
"ocr-performed": "OCR was performed for this file.",
|
||||
"open-document": "Open Document",
|
||||
"quick-filters": {
|
||||
"assigned-to-me": "Assigned to me",
|
||||
"assigned-to-others": "Assigned to others",
|
||||
@ -1491,6 +1492,11 @@
|
||||
"expand": "Show Details",
|
||||
"title": "Users"
|
||||
},
|
||||
"view-mode": {
|
||||
"list": "List",
|
||||
"view-as": "View as:",
|
||||
"workflow": "Workflow"
|
||||
},
|
||||
"watermark": "Watermark",
|
||||
"watermark-screen": {
|
||||
"action": {
|
||||
|
||||
@ -81,6 +81,8 @@
|
||||
|
||||
mat-icon {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
line-height: 13px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
|
||||
@ -241,10 +241,18 @@ section.settings {
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
.mb-6 {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.mb-8 {
|
||||
margin-bottom: 8px !important;
|
||||
}
|
||||
|
||||
.mb-12 {
|
||||
margin-bottom: 12px !important;
|
||||
}
|
||||
|
||||
.ml-8 {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit 6c0f123bd97148f8696038f63c9951c241b71990
|
||||
Subproject commit cb8393c492ec1e2795d644009266cc71eeca11a7
|
||||
Loading…
x
Reference in New Issue
Block a user