diff --git a/README.md b/README.md index ba6bf8bcb..34f65c01a 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/apps/red-ui/src/app/modules/projects/components/bulk-actions/project-overview-bulk-actions.component.ts b/apps/red-ui/src/app/modules/projects/components/bulk-actions/project-overview-bulk-actions.component.ts index 7b4566df9..e419281b2 100644 --- a/apps/red-ui/src/app/modules/projects/components/bulk-actions/project-overview-bulk-actions.component.ts +++ b/apps/red-ui/src/app/modules/projects/components/bulk-actions/project-overview-bulk-actions.component.ts @@ -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)); } diff --git a/apps/red-ui/src/app/modules/projects/components/file-actions/file-actions.component.ts b/apps/red-ui/src/app/modules/projects/components/file-actions/file-actions.component.ts index 948ea01c7..6adc04f70 100644 --- a/apps/red-ui/src/app/modules/projects/components/file-actions/file-actions.component.ts +++ b/apps/red-ui/src/app/modules/projects/components/file-actions/file-actions.component.ts @@ -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) { diff --git a/apps/red-ui/src/app/modules/projects/dialogs/assign-owner-dialog/assign-owner-dialog.component.html b/apps/red-ui/src/app/modules/projects/dialogs/assign-owner-dialog/assign-owner-dialog.component.html index e3a038f2a..1b335a86f 100644 --- a/apps/red-ui/src/app/modules/projects/dialogs/assign-owner-dialog/assign-owner-dialog.component.html +++ b/apps/red-ui/src/app/modules/projects/dialogs/assign-owner-dialog/assign-owner-dialog.component.html @@ -1,11 +1,11 @@
-
+
-
+
- {{ 'assign-' + data.type + '-owner.dialog.single-user' | translate }} + {{ 'assign-project-owner.dialog.single-user' | translate }} {{ userService.getNameForId(userId) }} @@ -13,73 +13,63 @@
- -
- +
+ -

+            

 
-                
- +
+ -

+            

 
-                
+            
 
-                
-
- -
-
- - -
- +
+
+ +
+
+ +
+
- +
-
+
diff --git a/apps/red-ui/src/app/modules/projects/dialogs/assign-owner-dialog/assign-owner-dialog.component.ts b/apps/red-ui/src/app/modules/projects/dialogs/assign-owner-dialog/assign-owner-dialog.component.ts index 15b36e701..1960b9914 100644 --- a/apps/red-ui/src/app/modules/projects/dialogs/assign-owner-dialog/assign-owner-dialog.component.ts +++ b/apps/red-ui/src/app/modules/projects/dialogs/assign-owner-dialog/assign-owner-dialog.component.ts @@ -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(); - 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[]) { diff --git a/apps/red-ui/src/app/modules/projects/dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component.html b/apps/red-ui/src/app/modules/projects/dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component.html new file mode 100644 index 000000000..5d822b37b --- /dev/null +++ b/apps/red-ui/src/app/modules/projects/dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component.html @@ -0,0 +1,28 @@ +
+
+ +
+
+
+ + {{ 'assign-' + data.mode + '-owner.dialog.single-user' | translate }} + + + {{ userService.getNameForId(userId) }} + + + +
+
+ +
+ + +
+
+
+ + +
diff --git a/apps/red-ui/src/app/modules/projects/dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component.scss b/apps/red-ui/src/app/modules/projects/dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component.scss new file mode 100644 index 000000000..af18d0899 --- /dev/null +++ b/apps/red-ui/src/app/modules/projects/dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component.scss @@ -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; +} diff --git a/apps/red-ui/src/app/modules/projects/dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component.ts b/apps/red-ui/src/app/modules/projects/dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component.ts new file mode 100644 index 000000000..53cd464c7 --- /dev/null +++ b/apps/red-ui/src/app/modules/projects/dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component.ts @@ -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, + @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(); + 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] + }); + } +} diff --git a/apps/red-ui/src/app/modules/projects/projects.module.ts b/apps/red-ui/src/app/modules/projects/projects.module.ts index af2361d8d..761894780 100644 --- a/apps/red-ui/src/app/modules/projects/projects.module.ts +++ b/apps/red-ui/src/app/modules/projects/projects.module.ts @@ -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 = [ diff --git a/apps/red-ui/src/app/modules/projects/services/file-action.service.ts b/apps/red-ui/src/app/modules/projects/services/file-action.service.ts index df15668e7..90a04e502 100644 --- a/apps/red-ui/src/app/modules/projects/services/file-action.service.ts +++ b/apps/red-ui/src/app/modules/projects/services/file-action.service.ts @@ -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(); diff --git a/apps/red-ui/src/app/modules/projects/services/projects-dialog.service.ts b/apps/red-ui/src/app/modules/projects/services/projects-dialog.service.ts index bc869d051..ee95f746e 100644 --- a/apps/red-ui/src/app/modules/projects/services/projects-dialog.service.ts +++ b/apps/red-ui/src/app/modules/projects/services/projects-dialog.service.ts @@ -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 { - 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 { - const projectId = this._appStateService.activeProject.project.projectId; - const ref = this._dialog.open(AssignOwnerDialogComponent, { + openAssignFileToUserDialog( + files: FileStatusWrapper[], + mode: 'reviewer' | 'approver', + cb?: Function, + ignoreDialogChanges = false + ): MatDialogRef { + 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(() => { diff --git a/apps/red-ui/src/assets/config/config.json b/apps/red-ui/src/assets/config/config.json index f7bee7030..7fbf643fb 100644 --- a/apps/red-ui/src/assets/config/config.json +++ b/apps/red-ui/src/assets/config/config.json @@ -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", diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index 3dac708dc..13e816b89 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -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", diff --git a/libs/red-ui-http/src/lib/api/statusController.service.ts b/libs/red-ui-http/src/lib/api/statusController.service.ts index e5db0f495..5d53b1592 100644 --- a/libs/red-ui-http/src/lib/api/statusController.service.ts +++ b/libs/red-ui-http/src/lib/api/statusController.service.ts @@ -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; + public setStatusUnderApproval(fileId: string, projectId: string, approverId?: string, observe?: 'body', reportProgress?: boolean): Observable; + public setStatusUnderApproval( + fileId: string, + projectId: string, + approverId?: string, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public setStatusUnderApproval( + fileId: string, + projectId: string, + approverId?: string, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public setStatusUnderApproval( + fileId: string, + projectId: string, + approverId?: string, + observe: any = 'body', + reportProgress: boolean = false + ): Observable { + 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>; - - public setStatusUnderApproval(projectId: string, fileId: string, observe?: 'events', reportProgress?: boolean): Observable>; - - public setStatusUnderApproval(projectId: string, fileId: string, observe: any = 'body', reportProgress: boolean = false): Observable { 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', 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, projectId: string, observe?: 'body', reportProgress?: boolean): Observable; - - public setStatusUnderApprovalForList(body: Array, projectId: string, observe?: 'response', reportProgress?: boolean): Observable>; - - public setStatusUnderApprovalForList(body: Array, projectId: string, observe?: 'events', reportProgress?: boolean): Observable>; - - public setStatusUnderApprovalForList(body: Array, projectId: string, observe: any = 'body', reportProgress: boolean = false): Observable { + public setStatusUnderApprovalForList( + body: Array, + projectId: string, + approverId?: string, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public setStatusUnderApprovalForList( + body: Array, + projectId: string, + approverId?: string, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public setStatusUnderApprovalForList( + body: Array, + projectId: string, + approverId?: string, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public setStatusUnderApprovalForList( + body: Array, + projectId: string, + approverId?: string, + observe: any = 'body', + reportProgress: boolean = false + ): Observable { 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', 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('post', `${this.basePath}/status/underapproval/${encodeURIComponent(String(projectId))}/bulk`, { body: body, + params: queryParameters, withCredentials: this.configuration.withCredentials, headers: headers, observe: observe,