Version 1.0 of approver assigne
This commit is contained in:
parent
7119ed92be
commit
35fda6e8c6
@ -7,8 +7,9 @@ To re-generate http rune swagger
|
||||
YOu need swagger-codegen installed `brew install swagger-codegen`
|
||||
|
||||
```
|
||||
BASE=https://adi-dev.iqser.cloud/
|
||||
BASE=https://dev-06.iqser.cloud/
|
||||
URL="$BASE"redaction-gateway-v1/v2/api-docs?group=redaction-gateway-v1
|
||||
rm -Rf /tmp/swagger
|
||||
mkdir -p /tmp/swagger
|
||||
swagger-codegen generate -i "$URL" -l typescript-angular -o /tmp/swagger
|
||||
cd /tmp/swagger
|
||||
|
||||
@ -96,7 +96,7 @@ export class ProjectOverviewBulkActionsComponent {
|
||||
|
||||
delete() {
|
||||
this.loading = true;
|
||||
this._dialogService.openDeleteFilesDialog(null, this._appStateService.activeProject.project.projectId, this.selectedFileIds, () => {
|
||||
this._dialogService.openDeleteFilesDialog(null, this._appStateService.activeProjectId, this.selectedFileIds, () => {
|
||||
this.reload.emit();
|
||||
this.loading = false;
|
||||
this.selectedFileIds.splice(0, this.selectedFileIds.length);
|
||||
@ -105,12 +105,29 @@ export class ProjectOverviewBulkActionsComponent {
|
||||
|
||||
assign() {
|
||||
this.loading = true;
|
||||
this._dialogService.openBulkAssignFileReviewerDialog(this.selectedFileIds, () => {
|
||||
const files = this.selectedFileIds.map((fileId) => this._appStateService.getFileById(this._appStateService.activeProjectId, fileId));
|
||||
|
||||
this._dialogService.openAssignFileToUserDialog(files, 'reviewer', () => {
|
||||
this.reload.emit();
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
setToUnderApproval() {
|
||||
// If more than 1 approver - show dialog and ask who to assign
|
||||
if (this._appStateService.activeProject.approverIds.length > 1) {
|
||||
this.loading = true;
|
||||
const files = this.selectedFileIds.map((fileId) => this._appStateService.getFileById(this._appStateService.activeProjectId, fileId));
|
||||
|
||||
this._dialogService.openAssignFileToUserDialog(files, 'approver', () => {
|
||||
this.reload.emit();
|
||||
this.loading = false;
|
||||
});
|
||||
} else {
|
||||
this._performBulkAction(this._fileActionService.setFileUnderApproval(this.selectedFiles, this._appStateService.activeProject.approverIds[0]));
|
||||
}
|
||||
}
|
||||
|
||||
async reanalyse() {
|
||||
const fileIds = this.selectedFiles.filter((file) => this._permissionsService.fileRequiresReanalysis(file)).map((file) => file.fileId);
|
||||
this._performBulkAction(this._reanalysisControllerService.reanalyzeFilesForProject(fileIds, this._appStateService.activeProject.projectId));
|
||||
@ -124,10 +141,6 @@ export class ProjectOverviewBulkActionsComponent {
|
||||
this._performBulkAction(this._fileActionService.setFileUnderReview(this.selectedFiles));
|
||||
}
|
||||
|
||||
setToUnderApproval() {
|
||||
this._performBulkAction(this._fileActionService.setFileUnderApproval(this.selectedFiles));
|
||||
}
|
||||
|
||||
approveDocuments() {
|
||||
this._performBulkAction(this._fileActionService.setFileApproved(this.selectedFiles));
|
||||
}
|
||||
|
||||
@ -79,9 +79,13 @@ export class FileActionsComponent implements OnInit {
|
||||
|
||||
setFileUnderApproval($event: MouseEvent, fileStatus: FileStatusWrapper) {
|
||||
$event.stopPropagation();
|
||||
this._fileActionService.setFileUnderApproval(fileStatus).subscribe(() => {
|
||||
this.reloadProjects('set-under-approval');
|
||||
});
|
||||
if (this.appStateService.activeProject.approverIds.length > 1) {
|
||||
this._fileActionService.assignProjectApprover(fileStatus, () => this.actionPerformed.emit('assign-reviewer'));
|
||||
} else {
|
||||
this._fileActionService.setFileUnderApproval(fileStatus).subscribe(() => {
|
||||
this.reloadProjects('set-under-approval');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
setFileApproved($event: MouseEvent, fileStatus: FileStatusWrapper) {
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
<section class="dialog">
|
||||
<div [translate]="'assign-' + data.type + '-owner.dialog.title'" class="dialog-header heading-l"></div>
|
||||
<div [translate]="'assign-project-owner.dialog.title'" class="dialog-header heading-l"></div>
|
||||
|
||||
<form (submit)="saveUsers()" [formGroup]="usersForm">
|
||||
<div [class.no-padding-bottom]="data.type === 'project'" class="dialog-content">
|
||||
<div class="dialog-content no-padding-bottom">
|
||||
<div class="red-input-group w-300">
|
||||
<mat-form-field floatLabel="always">
|
||||
<mat-label>{{ 'assign-' + data.type + '-owner.dialog.single-user' | translate }}</mat-label>
|
||||
<mat-label>{{ 'assign-project-owner.dialog.single-user' | translate }}</mat-label>
|
||||
<mat-select formControlName="singleUser">
|
||||
<mat-option *ngFor="let userId of singleUsersSelectOptions" [value]="userId">
|
||||
{{ userService.getNameForId(userId) }}
|
||||
@ -13,73 +13,63 @@
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<ng-container *ngIf="data.type === 'project'">
|
||||
<div [translate]="'assign-' + data.type + '-owner.dialog.approvers'" class="all-caps-label mt-16"></div>
|
||||
<redaction-team-members
|
||||
(remove)="toggleSelected($event)"
|
||||
[canAdd]="false"
|
||||
[canRemove]="true"
|
||||
[largeSpacing]="true"
|
||||
[memberIds]="selectedApproversList"
|
||||
[perLine]="13"
|
||||
[unremovableMembers]="[selectedSingleUser]"
|
||||
></redaction-team-members>
|
||||
<div [translate]="'assign-project-owner.dialog.approvers'" class="all-caps-label mt-16"></div>
|
||||
<redaction-team-members
|
||||
(remove)="toggleSelected($event)"
|
||||
[canAdd]="false"
|
||||
[canRemove]="true"
|
||||
[largeSpacing]="true"
|
||||
[memberIds]="selectedApproversList"
|
||||
[perLine]="13"
|
||||
[unremovableMembers]="[selectedSingleUser]"
|
||||
></redaction-team-members>
|
||||
|
||||
<pre
|
||||
*ngIf="selectedApproversList.length === 0"
|
||||
[innerHTML]="'assign-' + data.type + '-owner.dialog.no-approvers' | translate"
|
||||
class="info"
|
||||
></pre>
|
||||
<pre *ngIf="selectedApproversList.length === 0" [innerHTML]="'assign-project-owner.dialog.no-approvers' | translate" class="info"></pre>
|
||||
|
||||
<div [translate]="'assign-' + data.type + '-owner.dialog.reviewers'" class="all-caps-label mt-16"></div>
|
||||
<redaction-team-members
|
||||
(remove)="toggleSelected($event)"
|
||||
[canAdd]="false"
|
||||
[canRemove]="true"
|
||||
[largeSpacing]="true"
|
||||
[memberIds]="selectedReviewersList"
|
||||
[perLine]="13"
|
||||
[unremovableMembers]="[selectedSingleUser]"
|
||||
></redaction-team-members>
|
||||
<div [translate]="'assign-project-owner.dialog.reviewers'" class="all-caps-label mt-16"></div>
|
||||
<redaction-team-members
|
||||
(remove)="toggleSelected($event)"
|
||||
[canAdd]="false"
|
||||
[canRemove]="true"
|
||||
[largeSpacing]="true"
|
||||
[memberIds]="selectedReviewersList"
|
||||
[perLine]="13"
|
||||
[unremovableMembers]="[selectedSingleUser]"
|
||||
></redaction-team-members>
|
||||
|
||||
<pre
|
||||
*ngIf="selectedReviewersList.length === 0"
|
||||
[innerHTML]="'assign-' + data.type + '-owner.dialog.no-reviewers' | translate"
|
||||
class="info"
|
||||
></pre>
|
||||
<pre *ngIf="selectedReviewersList.length === 0" [innerHTML]="'assign-project-owner.dialog.no-reviewers' | translate" class="info"></pre>
|
||||
|
||||
<redaction-search-input
|
||||
[form]="searchForm"
|
||||
[placeholder]="'assign-' + data.type + '-owner.dialog.search' | translate"
|
||||
[width]="560"
|
||||
class="search-container"
|
||||
></redaction-search-input>
|
||||
<redaction-search-input
|
||||
[form]="searchForm"
|
||||
[placeholder]="'assign-project-owner.dialog.search' | translate"
|
||||
[width]="560"
|
||||
class="search-container"
|
||||
></redaction-search-input>
|
||||
|
||||
<div class="members-list">
|
||||
<div
|
||||
(click)="!isOwner(userId) && toggleSelected(userId)"
|
||||
*ngFor="let userId of multiUsersSelectOptions"
|
||||
[class.selected]="isMemberSelected(userId)"
|
||||
>
|
||||
<redaction-initials-avatar [userId]="userId" [withName]="true" size="large"></redaction-initials-avatar>
|
||||
<div class="actions">
|
||||
<div *ngIf="!isOwner(userId)" (click)="toggleApprover(userId, $event)" class="make-approver">
|
||||
<redaction-round-checkbox [active]="isApprover(userId)" class="mr-8"></redaction-round-checkbox>
|
||||
<span [translate]="'assign-' + data.type + '-owner.dialog.make-approver'"></span>
|
||||
</div>
|
||||
<mat-icon *ngIf="!isOwner(userId)" svgIcon="red:check"></mat-icon>
|
||||
<div class="members-list">
|
||||
<div
|
||||
(click)="!isOwner(userId) && toggleSelected(userId)"
|
||||
*ngFor="let userId of multiUsersSelectOptions"
|
||||
[class.selected]="isMemberSelected(userId)"
|
||||
>
|
||||
<redaction-initials-avatar [userId]="userId" [withName]="true" size="large"></redaction-initials-avatar>
|
||||
<div class="actions">
|
||||
<div *ngIf="!isOwner(userId)" (click)="toggleApprover(userId, $event)" class="make-approver">
|
||||
<redaction-round-checkbox [active]="isApprover(userId)" class="mr-8"></redaction-round-checkbox>
|
||||
<span [translate]="'assign-project-owner.dialog.make-approver'"></span>
|
||||
</div>
|
||||
<mat-icon *ngIf="!isOwner(userId)" svgIcon="red:check"></mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dialog-actions">
|
||||
<button [disabled]="!usersForm.valid || !changed" color="primary" mat-flat-button type="submit">
|
||||
{{ 'assign-' + data.type + '-owner.dialog.save' | translate }}
|
||||
{{ 'assign-project-owner.dialog.save' | translate }}
|
||||
</button>
|
||||
|
||||
<div [translate]="'assign-' + data.type + '-owner.dialog.cancel'" class="all-caps-label pointer cancel" mat-dialog-close></div>
|
||||
<div [translate]="'assign-project-owner.dialog.cancel'" class="all-caps-label pointer cancel" mat-dialog-close></div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
@ -9,7 +9,6 @@ import { FileStatusWrapper } from '@models/file/file-status.wrapper';
|
||||
import { ProjectWrapper } from '@state/model/project.wrapper';
|
||||
|
||||
class DialogData {
|
||||
type: 'file' | 'project';
|
||||
project?: ProjectWrapper;
|
||||
files?: FileStatusWrapper[];
|
||||
ignoreChanged?: boolean;
|
||||
@ -54,7 +53,7 @@ export class AssignOwnerDialogComponent {
|
||||
}
|
||||
|
||||
get singleUsersSelectOptions() {
|
||||
return this.data.type === 'file' ? this._appStateService.activeProject.memberIds : this.userService.managerUsers.map((m) => m.userId);
|
||||
return this.userService.managerUsers.map((m) => m.userId);
|
||||
}
|
||||
|
||||
get multiUsersSelectOptions() {
|
||||
@ -70,28 +69,18 @@ export class AssignOwnerDialogComponent {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.data.type === 'project') {
|
||||
if (this.data.project.ownerId !== this.selectedSingleUser) {
|
||||
return true;
|
||||
}
|
||||
if (this.data.project.ownerId !== this.selectedSingleUser) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const initialMembers = this.data.project.memberIds.sort();
|
||||
const currentMembers = this.selectedUsersList.sort();
|
||||
const initialMembers = this.data.project.memberIds.sort();
|
||||
const currentMembers = this.selectedUsersList.sort();
|
||||
|
||||
const initialApprovers = this.data.project.approverIds.sort();
|
||||
const currentApprovers = this.selectedApproversList.sort();
|
||||
const initialApprovers = this.data.project.approverIds.sort();
|
||||
const currentApprovers = this.selectedApproversList.sort();
|
||||
|
||||
if (this._compareLists(initialMembers, currentMembers) || this._compareLists(initialApprovers, currentApprovers)) {
|
||||
return true;
|
||||
}
|
||||
} else if (this.data.type === 'file') {
|
||||
const reviewerId = this.selectedSingleUser;
|
||||
|
||||
for (const file of this.data.files) {
|
||||
if (file.currentReviewer !== reviewerId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (this._compareLists(initialMembers, currentMembers) || this._compareLists(initialApprovers, currentApprovers)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -104,33 +93,14 @@ export class AssignOwnerDialogComponent {
|
||||
async saveUsers() {
|
||||
let result;
|
||||
try {
|
||||
if (this.data.type === 'project') {
|
||||
const ownerId = this.selectedSingleUser;
|
||||
const memberIds = this.selectedUsersList;
|
||||
const approverIds = this.selectedApproversList;
|
||||
const pw = Object.assign({}, this.data.project);
|
||||
pw.project.memberIds = memberIds;
|
||||
pw.project.approverIds = approverIds;
|
||||
pw.project.ownerId = ownerId;
|
||||
result = await this._appStateService.addOrUpdateProject(pw.project);
|
||||
}
|
||||
|
||||
if (this.data.type === 'file') {
|
||||
const reviewerId = this.selectedSingleUser;
|
||||
|
||||
await this._statusControllerService
|
||||
.setFileReviewerForList(
|
||||
this.data.files.map((f) => f.fileId),
|
||||
this._appStateService.activeProjectId,
|
||||
reviewerId
|
||||
)
|
||||
.toPromise();
|
||||
|
||||
for (const file of this.data.files) {
|
||||
file.currentReviewer = reviewerId;
|
||||
file.reviewerName = this.userService.getNameForId(reviewerId);
|
||||
}
|
||||
}
|
||||
const ownerId = this.selectedSingleUser;
|
||||
const memberIds = this.selectedUsersList;
|
||||
const approverIds = this.selectedApproversList;
|
||||
const pw = Object.assign({}, this.data.project);
|
||||
pw.project.memberIds = memberIds;
|
||||
pw.project.approverIds = approverIds;
|
||||
pw.project.ownerId = ownerId;
|
||||
result = await this._appStateService.addOrUpdateProject(pw.project);
|
||||
} catch (error) {
|
||||
this._notificationService.showToastNotification('Failed: ' + error.error ? error.error.message : error, null, NotificationType.ERROR);
|
||||
}
|
||||
@ -176,36 +146,21 @@ export class AssignOwnerDialogComponent {
|
||||
}
|
||||
|
||||
private _loadData() {
|
||||
if (this.data.type === 'project') {
|
||||
const project = this.data.project;
|
||||
this.usersForm = this._formBuilder.group({
|
||||
singleUser: [project?.ownerId, Validators.required],
|
||||
approvers: [[...project?.approverIds]],
|
||||
members: [[...project?.memberIds]]
|
||||
});
|
||||
this.searchForm = this._formBuilder.group({
|
||||
query: ['']
|
||||
});
|
||||
this.usersForm.get('singleUser').valueChanges.subscribe((singleUser) => {
|
||||
if (!this.isApprover(singleUser)) {
|
||||
this.toggleApprover(singleUser);
|
||||
}
|
||||
// If it is an approver, it is already a member, no need to check
|
||||
});
|
||||
}
|
||||
|
||||
if (this.data.type === 'file') {
|
||||
const uniqueReviewers = new Set<string>();
|
||||
for (const file of this.data.files) {
|
||||
if (file.currentReviewer) {
|
||||
uniqueReviewers.add(file.currentReviewer);
|
||||
}
|
||||
const project = this.data.project;
|
||||
this.usersForm = this._formBuilder.group({
|
||||
singleUser: [project?.ownerId, Validators.required],
|
||||
approvers: [[...project?.approverIds]],
|
||||
members: [[...project?.memberIds]]
|
||||
});
|
||||
this.searchForm = this._formBuilder.group({
|
||||
query: ['']
|
||||
});
|
||||
this.usersForm.get('singleUser').valueChanges.subscribe((singleUser) => {
|
||||
if (!this.isApprover(singleUser)) {
|
||||
this.toggleApprover(singleUser);
|
||||
}
|
||||
const singleUser = uniqueReviewers.size === 1 ? uniqueReviewers.values().next().value : this.userService.userId;
|
||||
this.usersForm = this._formBuilder.group({
|
||||
singleUser: [singleUser]
|
||||
});
|
||||
}
|
||||
// If it is an approver, it is already a member, no need to check
|
||||
});
|
||||
}
|
||||
|
||||
private _compareLists(l1: string[], l2: string[]) {
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
<section class="dialog">
|
||||
<div [translate]="'assign-' + data.mode + '-owner.dialog.title'" class="dialog-header heading-l"></div>
|
||||
|
||||
<form (submit)="saveUsers()" [formGroup]="usersForm">
|
||||
<div class="dialog-content">
|
||||
<div class="red-input-group w-300">
|
||||
<mat-form-field floatLabel="always">
|
||||
<mat-label>{{ 'assign-' + data.mode + '-owner.dialog.single-user' | translate }}</mat-label>
|
||||
<mat-select formControlName="singleUser">
|
||||
<mat-option *ngFor="let userId of singleUsersSelectOptions" [value]="userId">
|
||||
{{ userService.getNameForId(userId) }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dialog-actions">
|
||||
<button [disabled]="!usersForm.valid || !changed" color="primary" mat-flat-button type="submit">
|
||||
{{ 'assign-' + data.mode + '-owner.dialog.save' | translate }}
|
||||
</button>
|
||||
|
||||
<div [translate]="'assign-' + data.mode + '-owner.dialog.cancel'" class="all-caps-label pointer cancel" mat-dialog-close></div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<redaction-circle-button class="dialog-close" icon="red:close" mat-dialog-close></redaction-circle-button>
|
||||
</section>
|
||||
@ -0,0 +1,70 @@
|
||||
@import '../../../../../assets/styles/red-mixins';
|
||||
|
||||
.no-padding-bottom {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.search-container {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
redaction-team-members {
|
||||
margin-top: -4px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.members-list {
|
||||
max-height: 220px;
|
||||
height: 220px;
|
||||
margin-top: 16px;
|
||||
overflow-y: hidden;
|
||||
width: 587px;
|
||||
|
||||
&:hover {
|
||||
overflow-y: auto;
|
||||
@include scroll-bar;
|
||||
}
|
||||
|
||||
> div {
|
||||
margin-bottom: 2px;
|
||||
padding: 3px 5px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
transition: background-color ease-in-out 0.1s;
|
||||
width: 560px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.make-approver {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: none;
|
||||
position: absolute;
|
||||
right: 13px;
|
||||
top: 0;
|
||||
height: 38px;
|
||||
align-items: center;
|
||||
|
||||
mat-icon {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
margin-left: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
&.selected,
|
||||
&:hover {
|
||||
background-color: $grey-2;
|
||||
.actions {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.info {
|
||||
margin-top: 4px;
|
||||
}
|
||||
@ -0,0 +1,113 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { ProjectControllerService, StatusControllerService } from '@redaction/red-ui-http';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { NotificationService, NotificationType } from '@services/notification.service';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { FileStatusWrapper } from '@models/file/file-status.wrapper';
|
||||
import { ProjectWrapper } from '@state/model/project.wrapper';
|
||||
|
||||
class DialogData {
|
||||
mode: 'approver' | 'reviewer';
|
||||
project?: ProjectWrapper;
|
||||
files?: FileStatusWrapper[];
|
||||
ignoreChanged?: boolean;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-project-details-dialog',
|
||||
templateUrl: './assign-reviewer-approver-dialog.component.html',
|
||||
styleUrls: ['./assign-reviewer-approver-dialog.component.scss']
|
||||
})
|
||||
export class AssignReviewerApproverDialogComponent {
|
||||
usersForm: FormGroup;
|
||||
searchForm: FormGroup;
|
||||
|
||||
constructor(
|
||||
readonly userService: UserService,
|
||||
private readonly _projectControllerService: ProjectControllerService,
|
||||
private readonly _notificationService: NotificationService,
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
private readonly _statusControllerService: StatusControllerService,
|
||||
private readonly _appStateService: AppStateService,
|
||||
public dialogRef: MatDialogRef<AssignReviewerApproverDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: DialogData
|
||||
) {
|
||||
this._loadData();
|
||||
}
|
||||
|
||||
get selectedSingleUser(): string {
|
||||
return this.usersForm.get('singleUser').value;
|
||||
}
|
||||
|
||||
get singleUsersSelectOptions() {
|
||||
return this.data.mode === 'approver' ? this._appStateService.activeProject.approverIds : this._appStateService.activeProject.memberIds;
|
||||
}
|
||||
|
||||
get changed(): boolean {
|
||||
if (this.data.ignoreChanged) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const reviewerId = this.selectedSingleUser;
|
||||
|
||||
for (const file of this.data.files) {
|
||||
if (file.currentReviewer !== reviewerId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
isOwner(userId: string): boolean {
|
||||
return userId === this.selectedSingleUser;
|
||||
}
|
||||
|
||||
async saveUsers() {
|
||||
try {
|
||||
const selectedUser = this.selectedSingleUser;
|
||||
|
||||
if (this.data.mode === 'reviewer') {
|
||||
await this._statusControllerService
|
||||
.setFileReviewerForList(
|
||||
this.data.files.map((f) => f.fileId),
|
||||
this._appStateService.activeProjectId,
|
||||
selectedUser
|
||||
)
|
||||
.toPromise();
|
||||
} else {
|
||||
await this._statusControllerService
|
||||
.setStatusUnderApprovalForList(
|
||||
this.data.files.map((f) => f.fileId),
|
||||
this._appStateService.activeProjectId,
|
||||
selectedUser
|
||||
)
|
||||
.toPromise();
|
||||
}
|
||||
|
||||
for (const file of this.data.files) {
|
||||
file.currentReviewer = selectedUser;
|
||||
file.reviewerName = this.userService.getNameForId(selectedUser);
|
||||
}
|
||||
} catch (error) {
|
||||
this._notificationService.showToastNotification('Failed: ' + error.error ? error.error.message : error, null, NotificationType.ERROR);
|
||||
}
|
||||
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
private _loadData() {
|
||||
const uniqueReviewers = new Set<string>();
|
||||
for (const file of this.data.files) {
|
||||
if (file.currentReviewer) {
|
||||
uniqueReviewers.add(file.currentReviewer);
|
||||
}
|
||||
}
|
||||
const singleUser = uniqueReviewers.size === 1 ? uniqueReviewers.values().next().value : this.userService.userId;
|
||||
this.usersForm = this._formBuilder.group({
|
||||
singleUser: [singleUser]
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,7 @@ import { ProjectOverviewScreenComponent } from './screens/project-overview-scree
|
||||
import { FilePreviewScreenComponent } from './screens/file-preview-screen/file-preview-screen.component';
|
||||
import { AddEditProjectDialogComponent } from './dialogs/add-edit-project-dialog/add-edit-project-dialog.component';
|
||||
import { AssignOwnerDialogComponent } from './dialogs/assign-owner-dialog/assign-owner-dialog.component';
|
||||
import { AssignReviewerApproverDialogComponent } from './dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component';
|
||||
import { ManualAnnotationDialogComponent } from './dialogs/manual-redaction-dialog/manual-annotation-dialog.component';
|
||||
import { ForceRedactionDialogComponent } from './dialogs/force-redaction-dialog/force-redaction-dialog.component';
|
||||
import { RemoveAnnotationsDialogComponent } from './dialogs/remove-annotations-dialog/remove-annotations-dialog.component';
|
||||
@ -45,7 +46,8 @@ const dialogs = [
|
||||
ManualAnnotationDialogComponent,
|
||||
ForceRedactionDialogComponent,
|
||||
RemoveAnnotationsDialogComponent,
|
||||
DocumentInfoDialogComponent
|
||||
DocumentInfoDialogComponent,
|
||||
AssignReviewerApproverDialogComponent
|
||||
];
|
||||
|
||||
const components = [
|
||||
|
||||
@ -40,9 +40,10 @@ export class FileActionService {
|
||||
}
|
||||
}
|
||||
|
||||
assignProjectReviewer(file?: FileStatus, callback?: Function, ignoreDialogChanges = false) {
|
||||
this._dialogService.openAssignFileReviewerDialog(
|
||||
file ? file : this._appStateService.activeFile,
|
||||
assignProjectApprover(file?: FileStatusWrapper, callback?: Function, ignoreDialogChanges = false) {
|
||||
this._dialogService.openAssignFileToUserDialog(
|
||||
file ? [file] : [this._appStateService.activeFile],
|
||||
'approver',
|
||||
async () => {
|
||||
await this._appStateService.reloadActiveProjectFiles();
|
||||
if (callback) {
|
||||
@ -53,7 +54,21 @@ export class FileActionService {
|
||||
);
|
||||
}
|
||||
|
||||
async assignToMe(file?: FileStatus, callback?: Function) {
|
||||
assignProjectReviewer(file?: FileStatusWrapper, callback?: Function, ignoreDialogChanges = false) {
|
||||
this._dialogService.openAssignFileToUserDialog(
|
||||
file ? [file] : [this._appStateService.activeFile],
|
||||
'reviewer',
|
||||
async () => {
|
||||
await this._appStateService.reloadActiveProjectFiles();
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
ignoreDialogChanges
|
||||
);
|
||||
}
|
||||
|
||||
async assignToMe(file?: FileStatusWrapper, callback?: Function) {
|
||||
if (!file.currentReviewer) {
|
||||
await this._assignReviewerToCurrentUser(file, callback);
|
||||
} else {
|
||||
@ -63,13 +78,14 @@ export class FileActionService {
|
||||
}
|
||||
}
|
||||
|
||||
setFileUnderApproval(fileStatus: FileStatusWrapper | FileStatusWrapper[]) {
|
||||
setFileUnderApproval(fileStatus: FileStatusWrapper | FileStatusWrapper[], approverId?: string) {
|
||||
if (!isArray(fileStatus)) {
|
||||
fileStatus = [fileStatus];
|
||||
}
|
||||
return this._statusControllerService.setStatusUnderApprovalForList(
|
||||
fileStatus.map((f) => f.fileId),
|
||||
this._appStateService.activeProjectId
|
||||
this._appStateService.activeProjectId,
|
||||
approverId
|
||||
);
|
||||
}
|
||||
|
||||
@ -104,7 +120,7 @@ export class FileActionService {
|
||||
}
|
||||
|
||||
private _openAssignReviewerDialog(file?: FileStatusWrapper, callback?: Function) {
|
||||
this._dialogService.openAssignFileReviewerDialog(file ? file : this._appStateService.activeFile, async () => {
|
||||
this._dialogService.openAssignFileToUserDialog(file ? [file] : [this._appStateService.activeFile], 'reviewer', async () => {
|
||||
await this._appStateService.reloadActiveProjectFiles();
|
||||
if (callback) {
|
||||
callback();
|
||||
|
||||
@ -22,6 +22,8 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
import { ManualAnnotationDialogComponent } from '../dialogs/manual-redaction-dialog/manual-annotation-dialog.component';
|
||||
import { AssignOwnerDialogComponent } from '../dialogs/assign-owner-dialog/assign-owner-dialog.component';
|
||||
import { DossierDictionaryDialogComponent } from '../dialogs/dossier-dictionary-dialog/dossier-dictionary-dialog.component';
|
||||
import { FileStatusWrapper } from '../../../models/file/file-status.wrapper';
|
||||
import { AssignReviewerApproverDialogComponent } from '../dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component';
|
||||
|
||||
const dialogConfig = {
|
||||
width: '662px',
|
||||
@ -192,7 +194,7 @@ export class ProjectsDialogService {
|
||||
$event?.stopPropagation();
|
||||
const ref = this._dialog.open(AssignOwnerDialogComponent, {
|
||||
...dialogConfig,
|
||||
data: { type: 'project', project: project }
|
||||
data: { project: project }
|
||||
});
|
||||
ref.afterClosed().subscribe((result) => {
|
||||
if (cb) {
|
||||
@ -219,19 +221,6 @@ export class ProjectsDialogService {
|
||||
return ref;
|
||||
}
|
||||
|
||||
openAssignFileReviewerDialog(file: FileStatus, cb?: Function, ignoreDialogChanges = false): MatDialogRef<AssignOwnerDialogComponent> {
|
||||
const ref = this._dialog.open(AssignOwnerDialogComponent, {
|
||||
...dialogConfig,
|
||||
data: { type: 'file', files: [file], ignoreChanged: ignoreDialogChanges }
|
||||
});
|
||||
|
||||
ref.afterClosed().subscribe(() => {
|
||||
if (cb) cb();
|
||||
});
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
openAssignFileToMeDialog(file: FileStatus, cb?: Function) {
|
||||
const ref = this._dialog.open(ConfirmationDialogComponent, {
|
||||
...dialogConfig,
|
||||
@ -245,14 +234,15 @@ export class ProjectsDialogService {
|
||||
});
|
||||
}
|
||||
|
||||
openBulkAssignFileReviewerDialog(fileIds: string[], cb?: Function): MatDialogRef<AssignOwnerDialogComponent> {
|
||||
const projectId = this._appStateService.activeProject.project.projectId;
|
||||
const ref = this._dialog.open(AssignOwnerDialogComponent, {
|
||||
openAssignFileToUserDialog(
|
||||
files: FileStatusWrapper[],
|
||||
mode: 'reviewer' | 'approver',
|
||||
cb?: Function,
|
||||
ignoreDialogChanges = false
|
||||
): MatDialogRef<AssignReviewerApproverDialogComponent> {
|
||||
const ref = this._dialog.open(AssignReviewerApproverDialogComponent, {
|
||||
...dialogConfig,
|
||||
data: {
|
||||
type: 'file',
|
||||
files: fileIds.map((fileId) => this._appStateService.getFileById(projectId, fileId))
|
||||
}
|
||||
data: { mode: mode, files: files, ignoreChanged: ignoreDialogChanges }
|
||||
});
|
||||
|
||||
ref.afterClosed().subscribe(() => {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"OAUTH_URL": "https://red-staging.iqser.cloud/auth/realms/redaction",
|
||||
"API_URL": "https://red-staging.iqser.cloud/redaction-gateway-v1",
|
||||
"OAUTH_URL": "https://dev-06.iqser.cloud/auth/realms/redaction",
|
||||
"API_URL": "https://dev-06.iqser.cloud/redaction-gateway-v1",
|
||||
"OAUTH_CLIENT_ID": "redaction",
|
||||
"BACKEND_APP_VERSION": "4.4.40",
|
||||
"FRONTEND_APP_VERSION": "1.1",
|
||||
|
||||
@ -448,7 +448,7 @@
|
||||
"unassigned": "Unassigned",
|
||||
"you": "You"
|
||||
},
|
||||
"assign-file-owner": {
|
||||
"assign-reviewer-owner": {
|
||||
"dialog": {
|
||||
"single-user": "Reviewer",
|
||||
"title": "Manage File Reviewer",
|
||||
@ -456,6 +456,14 @@
|
||||
"cancel": "Cancel"
|
||||
}
|
||||
},
|
||||
"assign-approver-owner": {
|
||||
"dialog": {
|
||||
"single-user": "Approver",
|
||||
"title": "Manage File Approver",
|
||||
"save": "Save",
|
||||
"cancel": "Cancel"
|
||||
}
|
||||
},
|
||||
"assign-project-owner": {
|
||||
"dialog": {
|
||||
"single-user": "Owner",
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
*/ /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/member-ordering */
|
||||
|
||||
import { Inject, Injectable, Optional } from '@angular/core';
|
||||
import { HttpClient, HttpEvent, HttpHeaders, HttpResponse } from '@angular/common/http';
|
||||
import { HttpClient, HttpEvent, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http';
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
@ -19,6 +19,7 @@ import { FileStatus } from '../model/fileStatus';
|
||||
|
||||
import { BASE_PATH } from '../variables';
|
||||
import { Configuration } from '../configuration';
|
||||
import { CustomHttpUrlEncodingCodec } from '../encoder';
|
||||
|
||||
@Injectable()
|
||||
export class StatusControllerService {
|
||||
@ -445,24 +446,45 @@ export class StatusControllerService {
|
||||
/**
|
||||
* Sets the status UNDER_APPROVAL for a file.
|
||||
* None
|
||||
* @param projectId projectId
|
||||
* @param fileId fileId
|
||||
* @param projectId projectId
|
||||
* @param approverId approverId
|
||||
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
|
||||
* @param reportProgress flag to report request and response progress.
|
||||
*/
|
||||
public setStatusUnderApproval(projectId: string, fileId: string, observe?: 'body', reportProgress?: boolean): Observable<any>;
|
||||
public setStatusUnderApproval(fileId: string, projectId: string, approverId?: string, observe?: 'body', reportProgress?: boolean): Observable<any>;
|
||||
public setStatusUnderApproval(
|
||||
fileId: string,
|
||||
projectId: string,
|
||||
approverId?: string,
|
||||
observe?: 'response',
|
||||
reportProgress?: boolean
|
||||
): Observable<HttpResponse<any>>;
|
||||
public setStatusUnderApproval(
|
||||
fileId: string,
|
||||
projectId: string,
|
||||
approverId?: string,
|
||||
observe?: 'events',
|
||||
reportProgress?: boolean
|
||||
): Observable<HttpEvent<any>>;
|
||||
public setStatusUnderApproval(
|
||||
fileId: string,
|
||||
projectId: string,
|
||||
approverId?: string,
|
||||
observe: any = 'body',
|
||||
reportProgress: boolean = false
|
||||
): Observable<any> {
|
||||
if (fileId === null || fileId === undefined) {
|
||||
throw new Error('Required parameter fileId was null or undefined when calling setStatusUnderApproval.');
|
||||
}
|
||||
|
||||
public setStatusUnderApproval(projectId: string, fileId: string, observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<any>>;
|
||||
|
||||
public setStatusUnderApproval(projectId: string, fileId: string, observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<any>>;
|
||||
|
||||
public setStatusUnderApproval(projectId: string, fileId: string, observe: any = 'body', reportProgress: boolean = false): Observable<any> {
|
||||
if (projectId === null || projectId === undefined) {
|
||||
throw new Error('Required parameter projectId was null or undefined when calling setStatusUnderApproval.');
|
||||
}
|
||||
|
||||
if (fileId === null || fileId === undefined) {
|
||||
throw new Error('Required parameter fileId was null or undefined when calling setStatusUnderApproval.');
|
||||
let queryParameters = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() });
|
||||
if (approverId !== undefined && approverId !== null) {
|
||||
queryParameters = queryParameters.set('approverId', <any>approverId);
|
||||
}
|
||||
|
||||
let headers = this.defaultHeaders;
|
||||
@ -476,7 +498,7 @@ export class StatusControllerService {
|
||||
// to determine the Accept header
|
||||
const httpHeaderAccepts: string[] = [];
|
||||
const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts);
|
||||
if (httpHeaderAcceptSelected !== undefined) {
|
||||
if (httpHeaderAcceptSelected != undefined) {
|
||||
headers = headers.set('Accept', httpHeaderAcceptSelected);
|
||||
}
|
||||
|
||||
@ -487,6 +509,7 @@ export class StatusControllerService {
|
||||
'post',
|
||||
`${this.basePath}/status/underapproval/${encodeURIComponent(String(projectId))}/${encodeURIComponent(String(fileId))}`,
|
||||
{
|
||||
params: queryParameters,
|
||||
withCredentials: this.configuration.withCredentials,
|
||||
headers: headers,
|
||||
observe: observe,
|
||||
@ -499,25 +522,54 @@ export class StatusControllerService {
|
||||
* Sets the status UNDER_APPROVAL for a list of files.
|
||||
* None
|
||||
* @param body fileIds
|
||||
* @param approverId approverId
|
||||
* @param projectId projectId
|
||||
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
|
||||
* @param reportProgress flag to report request and response progress.
|
||||
*/
|
||||
public setStatusUnderApprovalForList(body: Array<string>, projectId: string, observe?: 'body', reportProgress?: boolean): Observable<any>;
|
||||
|
||||
public setStatusUnderApprovalForList(body: Array<string>, projectId: string, observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<any>>;
|
||||
|
||||
public setStatusUnderApprovalForList(body: Array<string>, projectId: string, observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<any>>;
|
||||
|
||||
public setStatusUnderApprovalForList(body: Array<string>, projectId: string, observe: any = 'body', reportProgress: boolean = false): Observable<any> {
|
||||
public setStatusUnderApprovalForList(
|
||||
body: Array<string>,
|
||||
projectId: string,
|
||||
approverId?: string,
|
||||
observe?: 'body',
|
||||
reportProgress?: boolean
|
||||
): Observable<any>;
|
||||
public setStatusUnderApprovalForList(
|
||||
body: Array<string>,
|
||||
projectId: string,
|
||||
approverId?: string,
|
||||
observe?: 'response',
|
||||
reportProgress?: boolean
|
||||
): Observable<HttpResponse<any>>;
|
||||
public setStatusUnderApprovalForList(
|
||||
body: Array<string>,
|
||||
projectId: string,
|
||||
approverId?: string,
|
||||
observe?: 'events',
|
||||
reportProgress?: boolean
|
||||
): Observable<HttpEvent<any>>;
|
||||
public setStatusUnderApprovalForList(
|
||||
body: Array<string>,
|
||||
projectId: string,
|
||||
approverId?: string,
|
||||
observe: any = 'body',
|
||||
reportProgress: boolean = false
|
||||
): Observable<any> {
|
||||
if (body === null || body === undefined) {
|
||||
throw new Error('Required parameter body was null or undefined when calling setStatusUnderApprovalForList.');
|
||||
}
|
||||
|
||||
if (approverId === null || approverId === undefined) {
|
||||
throw new Error('Required parameter approverId was null or undefined when calling setStatusUnderApprovalForList.');
|
||||
}
|
||||
|
||||
if (projectId === null || projectId === undefined) {
|
||||
throw new Error('Required parameter projectId was null or undefined when calling setStatusUnderApprovalForList.');
|
||||
}
|
||||
|
||||
let queryParameters = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() });
|
||||
queryParameters = queryParameters.set('approverId', <any>approverId);
|
||||
|
||||
let headers = this.defaultHeaders;
|
||||
|
||||
// authentication (RED-OAUTH) required
|
||||
@ -529,19 +581,20 @@ export class StatusControllerService {
|
||||
// to determine the Accept header
|
||||
const httpHeaderAccepts: string[] = [];
|
||||
const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts);
|
||||
if (httpHeaderAcceptSelected !== undefined) {
|
||||
if (httpHeaderAcceptSelected != undefined) {
|
||||
headers = headers.set('Accept', httpHeaderAcceptSelected);
|
||||
}
|
||||
|
||||
// to determine the Content-Type header
|
||||
const consumes: string[] = ['application/json'];
|
||||
const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes);
|
||||
if (httpContentTypeSelected !== undefined) {
|
||||
if (httpContentTypeSelected != undefined) {
|
||||
headers = headers.set('Content-Type', httpContentTypeSelected);
|
||||
}
|
||||
|
||||
return this.httpClient.request<any>('post', `${this.basePath}/status/underapproval/${encodeURIComponent(String(projectId))}/bulk`, {
|
||||
body: body,
|
||||
params: queryParameters,
|
||||
withCredentials: this.configuration.withCredentials,
|
||||
headers: headers,
|
||||
observe: observe,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user