Version 1.0 of approver assigne

This commit is contained in:
Timo 2021-05-13 17:22:56 +03:00
parent 7119ed92be
commit 35fda6e8c6
14 changed files with 438 additions and 195 deletions

View File

@ -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

View File

@ -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));
}

View File

@ -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) {

View File

@ -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>

View File

@ -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[]) {

View File

@ -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>

View File

@ -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;
}

View File

@ -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]
});
}
}

View File

@ -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 = [

View File

@ -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();

View File

@ -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(() => {

View File

@ -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",

View File

@ -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",

View File

@ -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,