added approval flow

This commit is contained in:
Timo Bejan 2020-11-03 10:53:23 +02:00
parent e4c3b6bcdb
commit cca5368d62
9 changed files with 126 additions and 46 deletions

View File

@ -35,7 +35,7 @@ export class FilterComponent implements OnChanges {
private _copySettings(oldFilters: FilterModel[], newFilters: FilterModel[]) {
if (oldFilters && newFilters) {
for (let oldFilter of oldFilters) {
for (const oldFilter of oldFilters) {
const newFilter = newFilters.find((f) => f.key === oldFilter.key);
if (newFilter) {
newFilter.checked = oldFilter.checked;

View File

@ -1,10 +1,14 @@
import { FilterModel } from '../model/filter.model';
export function handleCheckedValue(filter: FilterModel) {
filter.checked = filter.filters.reduce((acc, next) => acc && next.checked, true);
if (filter.checked) {
filter.indeterminate = false;
if (filter.filters) {
filter.checked = filter.filters.reduce((acc, next) => acc && next.checked, true);
if (filter.checked) {
filter.indeterminate = false;
} else {
filter.indeterminate = filter.filters.reduce((acc, next) => acc || next.checked, false);
}
} else {
filter.indeterminate = filter.filters.reduce((acc, next) => acc || next.checked, false);
filter.indeterminate = false;
}
}

View File

@ -24,50 +24,51 @@
</button>
<button
(click)="assignReviewer()"
*ngIf="appStateService.isActiveProjectMember"
*ngIf="appStateService.isActiveProjectMember && !isApprovedOrUnderApproval()"
mat-icon-button
>
<mat-icon svgIcon="red:assign"></mat-icon>
</button>
<button
(click)="reanalyseFile($event)"
*ngIf="userService.isManager(user)"
*ngIf="appStateService.isActiveProjectMember && !isApprovedOrUnderApproval()"
mat-icon-button
>
<mat-icon svgIcon="red:refresh"></mat-icon>
</button>
<button
*ngIf="canApprove() && appStateService.isActiveProjectOwnerAndManager"
(click)="requestApprovalOrApproveFile($event)"
color="accent"
mat-icon-button
[matTooltip]="
(appStateService.activeFile.status === 'UNDER_APPROVAL'
? 'project-overview.approve'
: 'project-overview.under-approval'
) | translate
"
>
<mat-icon svgIcon="red:check-alt"></mat-icon>
</button>
<button (click)="openFileDetailsDialog($event)" mat-icon-button>
<mat-icon svgIcon="red:info"></mat-icon>
</button>
</div>
<button
*ngIf="userService.isManager(user)"
[matMenuTriggerFor]="downloadMenu"
class="arrow-button"
*ngIf="appStateService.isActiveProjectOwnerAndManager && fileReadyForDownload"
(click)="downloadFile('REDACTED')"
color="primary"
mat-flat-button
>
<span translate="file-preview.download.label"></span>
<mat-icon svgIcon="red:arrow-down"></mat-icon>
<mat-icon svgIcon="red:download"></mat-icon>
</button>
<button
[routerLink]="['/ui/projects/' + appStateService.activeProjectId]"
mat-icon-button
>
<mat-icon svgIcon="red:close"></mat-icon>
</button>
<mat-menu #downloadMenu="matMenu" xPosition="before">
<div
(click)="downloadFile('ORIGINAL')"
mat-menu-item
translate="file-preview.download.dropdown.original.label"
></div>
<div
(click)="downloadFile('ANNOTATED')"
mat-menu-item
translate="file-preview.download.dropdown.annotated.label"
></div>
<div
(click)="downloadFile('REDACTED')"
mat-menu-item
translate="file-preview.download.dropdown.redacted.label"
></div>
</mat-menu>
</div>
</div>
@ -159,23 +160,19 @@
>{{ annotation.content }}
</div>
</div>
<!-- <div class="page-number">-->
<!-- {{ annotation.pageNumber }}-->
<!-- </div>-->
</div>
<redaction-comments [annotation]="annotation"></redaction-comments>
<div
*ngIf="annotation.superType === 'request'"
[class.visible]="isSuggestionVisible(annotation)"
[class.visible]="isAnnotationMenuOpen(annotation)"
class="annotation-actions"
>
<button
(click)="openAcceptSuggestionMenu($event, annotation)"
*ngIf="appStateService.isActiveProjectOwnerAndManager"
[class.active]="isSuggestionVisible(annotation)"
[class.active]="isAnnotationMenuOpen(annotation)"
[matMenuTriggerFor]="menu"
class="confirm"
mat-icon-button

View File

@ -8,7 +8,7 @@ import {
ViewChild
} from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { ReanalysisControllerService } from '@redaction/red-ui-http';
import { FileStatus, ReanalysisControllerService } from '@redaction/red-ui-http';
import { AppStateService } from '../../../state/app-state.service';
import { WebViewerInstance } from '@pdftron/webviewer';
import { PdfViewerComponent } from '../pdf-viewer/pdf-viewer.component';
@ -102,7 +102,7 @@ export class FilePreviewScreenComponent implements OnInit {
public viewReady = false;
public filters: FilterModel[];
private _activeSuggestion: AnnotationWrapper;
private _activeMenuAnnotation: AnnotationWrapper;
public ngOnInit(): void {
this._loadFileData();
@ -250,8 +250,8 @@ export class FilePreviewScreenComponent implements OnInit {
}
}
public isSuggestionVisible(annotation: AnnotationWrapper) {
return annotation.id === this._activeSuggestion?.id;
public isAnnotationMenuOpen(annotation: AnnotationWrapper) {
return annotation.id === this._activeMenuAnnotation?.id;
}
public acceptSuggestion($event: MouseEvent, annotation: AnnotationWrapper) {
@ -262,11 +262,11 @@ export class FilePreviewScreenComponent implements OnInit {
public openAcceptSuggestionMenu($event: MouseEvent, annotation: AnnotationWrapper) {
$event.preventDefault();
this._activeSuggestion = annotation;
this._activeMenuAnnotation = annotation;
}
public onSuggestionMenuClose() {
this._activeSuggestion = null;
this._activeMenuAnnotation = null;
}
public rejectSuggestion($event: MouseEvent, annotation: AnnotationWrapper) {
@ -467,4 +467,32 @@ export class FilePreviewScreenComponent implements OnInit {
this._rebuildFilters();
});
}
get fileReadyForDownload() {
return this.appStateService.activeFile.status === 'APPROVED';
}
isApprovedOrUnderApproval() {
return (
this.appStateService.activeFile.status === 'APPROVED' ||
this.appStateService.activeFile.status === 'UNDER_APPROVAL'
);
}
canApprove() {
return (
this.appStateService.activeFile.status === 'UNDER_REVIEW' ||
this.appStateService.activeFile.status === 'UNDER_APPROVAL'
);
}
requestApprovalOrApproveFile($event: MouseEvent) {
$event.stopPropagation();
if (this.appStateService.activeFile.status === 'UNDER_REVIEW') {
this._fileActionService.setUnderApproval(this.appStateService.activeFile);
} else {
this._fileActionService.setApproved(this.appStateService.activeFile);
}
}
}

View File

@ -48,9 +48,7 @@ export class AnnotationWrapper {
comments: { [p: string]: Array<Comment> },
dictionaryData: { [p: string]: TypeValue }
) {
console.log(manualRedactionEntry);
const annotationWrapper = new AnnotationWrapper();
annotationWrapper.superType = AnnotationWrapper.getManualRedactionSuperType(
manualRedactionEntry,
dictionaryData

View File

@ -41,4 +41,16 @@ export class FileActionService {
});
}
}
setUnderApproval(fileStatus: FileStatus) {
this._statusControllerService
.setStatusUnderApproval(this._appStateService.activeProjectId, fileStatus.fileId)
.subscribe(() => {});
}
setApproved(fileStatus: FileStatus) {
this._statusControllerService
.setStatusApproved(this._appStateService.activeProjectId, fileStatus.fileId)
.subscribe(() => {});
}
}

View File

@ -137,8 +137,7 @@
[class.pointer]="canOpenFile(fileStatus)"
*ngFor="
let fileStatus of displayedFiles
| sortBy: sortingOption.order:sortingOption.column;
trackBy: fileId
| sortBy: sortingOption.order:sortingOption.column
"
[routerLink]="
canOpenFile(fileStatus)
@ -263,13 +262,17 @@
<button
(click)="assignReviewer($event, fileStatus)"
color="accent"
*ngIf="appStateService.isActiveProjectMember"
*ngIf="
appStateService.isActiveProjectMember &&
!isApprovedOrUnderApproval(fileStatus)
"
mat-icon-button
[matTooltip]="'project-overview.assign.action.label' | translate"
>
<mat-icon svgIcon="red:assign"></mat-icon>
</button>
<button
*ngIf="!isApprovedOrUnderApproval(fileStatus)"
(click)="reanalyseFile($event, fileStatus)"
color="accent"
mat-icon-button
@ -277,6 +280,23 @@
>
<mat-icon svgIcon="red:refresh"></mat-icon>
</button>
<button
*ngIf="
canApprove(fileStatus) &&
appStateService.isActiveProjectOwnerAndManager
"
(click)="requestApprovalOrApproveFile($event, fileStatus)"
color="accent"
mat-icon-button
[matTooltip]="
(fileStatus.status === 'UNDER_APPROVAL'
? 'project-overview.approve'
: 'project-overview.under-approval'
) | translate
"
>
<mat-icon svgIcon="red:check-alt"></mat-icon>
</button>
</div>
</div>
</div>

View File

@ -64,6 +64,7 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy {
});
this.appStateService.fileStatusChanged.subscribe(() => {
console.log('fs changed, rebuild');
this._calculateData();
});
}
@ -345,4 +346,22 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy {
fileNotUpToDateWithDictionary(fileStatus: FileStatus) {
return fileStatus.dictionaryVersion !== this.appStateService.dictionaryVersion;
}
requestApprovalOrApproveFile($event: MouseEvent, fileStatus: FileStatus) {
$event.stopPropagation();
if (fileStatus.status === 'UNDER_REVIEW') {
this._fileActionService.setUnderApproval(fileStatus);
} else {
this._fileActionService.setApproved(fileStatus);
}
}
isApprovedOrUnderApproval(fileStatus: FileStatus) {
return fileStatus.status === 'APPROVED' || fileStatus.status === 'UNDER_APPROVAL';
}
canApprove(fileStatus: FileStatus) {
return fileStatus.status === 'UNDER_REVIEW' || fileStatus.status === 'UNDER_APPROVAL';
}
}

View File

@ -315,6 +315,8 @@
}
},
"project-overview": {
"under-approval": "Under Approval",
"approve": "Approve",
"no-files": "This Project contains no files yet. You can start your work by uploading some files!",
"new-rule": {
"label": "New Rule",