From dc5c315159665c2c3681e77025fbb6375fccc9be Mon Sep 17 00:00:00 2001 From: Timo Bejan Date: Thu, 22 Oct 2020 01:18:46 +0300 Subject: [PATCH 1/2] assign user / member owner / reviewer dialogs improvements --- README.md | 3 +- apps/red-ui/src/app/app.module.ts | 2 - .../assign-owner-dialog.component.html | 39 +++++--- .../assign-owner-dialog.component.ts | 96 ++++++++++++------- ...sign-project-members-dialog.component.html | 22 ----- ...sign-project-members-dialog.component.scss | 0 ...assign-project-members-dialog.component.ts | 56 ----------- .../project-overview-screen.component.html | 11 +-- .../project-overview-screen.component.ts | 75 +++++++++------ .../red-ui/src/app/state/app-state.service.ts | 6 +- apps/red-ui/src/app/user/user.service.ts | 10 +- apps/red-ui/src/assets/i18n/en.json | 32 +++++++ .../src/lib/api/projectController.service.ts | 9 -- libs/red-ui-http/src/lib/model/fileStatus.ts | 4 + 14 files changed, 192 insertions(+), 173 deletions(-) delete mode 100644 apps/red-ui/src/app/screens/project-overview-screen/project-members-dialog/assign-project-members-dialog.component.html delete mode 100644 apps/red-ui/src/app/screens/project-overview-screen/project-members-dialog/assign-project-members-dialog.component.scss delete mode 100644 apps/red-ui/src/app/screens/project-overview-screen/project-members-dialog/assign-project-members-dialog.component.ts diff --git a/README.md b/README.md index 29ba488fb..fdcb9ec47 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,8 @@ ## Swagger Generated Code To regnerate http rune swaagger ``` -URL=https://timo-redaction-dev.iqser.cloud/v2/api-docs?group=redaction-gateway-v1 +BASE=http://ingress.redaction-timo-dev-3011.178.63.47.73.xip.io/ +URL="$BASE"v2/api-docs?group=redaction-gateway-v1 mkdir -p /tmp/swagger swagger-codegen generate -i "$URL" -l typescript-angular -o /tmp/swagger ``` diff --git a/apps/red-ui/src/app/app.module.ts b/apps/red-ui/src/app/app.module.ts index faacea368..00dbd4679 100644 --- a/apps/red-ui/src/app/app.module.ts +++ b/apps/red-ui/src/app/app.module.ts @@ -55,7 +55,6 @@ import { AnnotationIconComponent } from './components/annotation-icon/annotation import { AuthGuard } from './auth/auth.guard'; import { AuthErrorComponent } from './screens/auth-error/auth-error.component'; import { RedRoleGuard } from './auth/red-role.guard'; -import { AssignProjectMembersDialogComponent } from './screens/project-overview-screen/project-members-dialog/assign-project-members-dialog.component'; import { MatListModule } from '@angular/material/list'; import { AssignOwnerDialogComponent } from './components/project-members-dialog/assign-owner-dialog.component'; @@ -75,7 +74,6 @@ export function HttpLoaderFactory(httpClient: HttpClient) { PdfViewerComponent, FileDetailsDialogComponent, ProjectDetailsDialogComponent, - AssignProjectMembersDialogComponent, AssignOwnerDialogComponent, FullPageLoadingIndicatorComponent, InitialsAvatarComponent, diff --git a/apps/red-ui/src/app/components/project-members-dialog/assign-owner-dialog.component.html b/apps/red-ui/src/app/components/project-members-dialog/assign-owner-dialog.component.html index 9423d219d..9c1f06864 100644 --- a/apps/red-ui/src/app/components/project-members-dialog/assign-owner-dialog.component.html +++ b/apps/red-ui/src/app/components/project-members-dialog/assign-owner-dialog.component.html @@ -3,17 +3,34 @@ class="dialog-header heading-l"> -
- - - - {{ userService.getNameForId(user.userId) }} - - - -
+
+
+ + + {{'assign-' + data.type + '-owner.dialog.single-user.label' | translate}} + + + {{userService.getNameForId(user.userId)}} + + + + + + {{'assign-' + data.type + '-owner.dialog.multi-user.label' | translate}} + + + {{userService.getNameForId(user.userId)}} + + + + +
+ +
+ +
+
- diff --git a/apps/red-ui/src/app/screens/project-overview-screen/project-members-dialog/assign-project-members-dialog.component.scss b/apps/red-ui/src/app/screens/project-overview-screen/project-members-dialog/assign-project-members-dialog.component.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/apps/red-ui/src/app/screens/project-overview-screen/project-members-dialog/assign-project-members-dialog.component.ts b/apps/red-ui/src/app/screens/project-overview-screen/project-members-dialog/assign-project-members-dialog.component.ts deleted file mode 100644 index 272784e9a..000000000 --- a/apps/red-ui/src/app/screens/project-overview-screen/project-members-dialog/assign-project-members-dialog.component.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { Component, Inject } from '@angular/core'; -import { Project, ProjectControllerService } from '@redaction/red-ui-http'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { AppStateService, ProjectWrapper } from '../../../state/app-state.service'; -import { UserService } from '../../../user/user.service'; -import { MatSelectionListChange } from '@angular/material/list'; -import { NotificationService, NotificationType } from '../../../notification/notification.service'; - -@Component({ - selector: 'redaction-project-details-dialog', - templateUrl: './assign-project-members-dialog.component.html', - styleUrls: ['./assign-project-members-dialog.component.scss'] -}) -export class AssignProjectMembersDialogComponent { - private _project: Project; - public memberIds: string[]; - - constructor(private readonly _projectControllerService: ProjectControllerService, - private readonly _notificationService: NotificationService, - public readonly userService: UserService, - private readonly _appStateService: AppStateService, - public dialogRef: MatDialogRef) { - this._loadProject(); - } - - private _loadProject() { - this._project = this._appStateService.activeProject.project; - this.memberIds = [...this._project.memberIds]; - } - - private _reloadProject() { - this._appStateService.addOrUpdateProject(this._project).then(() => { - this._loadProject(); - }); - } - - public selectionChange($event: MatSelectionListChange) { - const userId = $event.option.value; - const selected = $event.option.selected; - const userName = this.userService.getNameForId(userId); - - if (selected) { - this._projectControllerService.addMembersToProject({ memberIds: [userId] }, this._project.projectId).subscribe(() => { - this._notificationService.showToastNotification('Successfully assigned ' + userName + ' to project: ' + this._project.projectName); - }, error => { - this._notificationService.showToastNotification('Failed: ' + error.error.message, null, NotificationType.ERROR); - }).add(() => this._reloadProject()); - } else { - this._projectControllerService.deleteMembersToProject({ memberIds: [userId] }, this._project.projectId).subscribe(() => { - this._notificationService.showToastNotification('Successfully removed ' + userName + ' from project: ' + this._project.projectName); - }, error => { - this._notificationService.showToastNotification('Failed: ' + error.error.message, null, NotificationType.ERROR); - }).add(() => this._reloadProject()); - } - } -} diff --git a/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.html b/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.html index d2502aa14..6993925dd 100644 --- a/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.html +++ b/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.html @@ -128,7 +128,7 @@
- 1 + {{ appStateService.activeProject.project.memberIds.length }}
@@ -155,13 +155,12 @@
-
+
- - - - +
+
+{{overflowCount}}
+
+
diff --git a/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.ts b/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.ts index f152acbe2..ee6da7c66 100644 --- a/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.ts +++ b/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.ts @@ -1,5 +1,5 @@ -import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; +import {ChangeDetectorRef, Component, OnDestroy, OnInit} from '@angular/core'; +import {ActivatedRoute, Router} from '@angular/router'; import { FileStatus, FileUploadControllerService, @@ -7,22 +7,22 @@ import { ReanalysisControllerService, StatusControllerService } from '@redaction/red-ui-http'; -import { NotificationService, NotificationType } from '../../notification/notification.service'; -import { TranslateService } from '@ngx-translate/core'; -import { ConfirmationDialogComponent } from '../../common/confirmation-dialog/confirmation-dialog.component'; -import { MatDialog } from '@angular/material/dialog'; -import { AppStateService } from '../../state/app-state.service'; -import { ProjectDetailsDialogComponent } from './project-details-dialog/project-details-dialog.component'; -import { FileDropOverlayService } from '../../upload/file-drop/service/file-drop-overlay.service'; -import { FileUploadModel } from '../../upload/model/file-upload.model'; -import { FileUploadService } from '../../upload/file-upload.service'; -import { UploadStatusOverlayService } from '../../upload/upload-status-dialog/service/upload-status-overlay.service'; -import { AddEditProjectDialogComponent } from '../project-listing-screen/add-edit-project-dialog/add-edit-project-dialog.component'; -import { UserService } from '../../user/user.service'; -import { SortingOption } from '../../utils/types'; -import { DoughnutChartConfig } from '../../components/simple-doughnut-chart/simple-doughnut-chart.component'; -import { groupBy } from '../../utils/functions'; -import { AssignProjectMembersDialogComponent } from './project-members-dialog/assign-project-members-dialog.component'; +import {NotificationService, NotificationType} from '../../notification/notification.service'; +import {TranslateService} from '@ngx-translate/core'; +import {ConfirmationDialogComponent} from '../../common/confirmation-dialog/confirmation-dialog.component'; +import {MatDialog} from '@angular/material/dialog'; +import {AppStateService} from '../../state/app-state.service'; +import {ProjectDetailsDialogComponent} from './project-details-dialog/project-details-dialog.component'; +import {FileDropOverlayService} from '../../upload/file-drop/service/file-drop-overlay.service'; +import {FileUploadModel} from '../../upload/model/file-upload.model'; +import {FileUploadService} from '../../upload/file-upload.service'; +import {UploadStatusOverlayService} from '../../upload/upload-status-dialog/service/upload-status-overlay.service'; +import {AddEditProjectDialogComponent} from '../project-listing-screen/add-edit-project-dialog/add-edit-project-dialog.component'; +import {UserService} from '../../user/user.service'; +import {SortingOption} from '../../utils/types'; +import {DoughnutChartConfig} from '../../components/simple-doughnut-chart/simple-doughnut-chart.component'; +import {groupBy} from '../../utils/functions'; +import {AssignOwnerDialogComponent} from "../../components/project-members-dialog/assign-owner-dialog.component"; @Component({ @@ -34,10 +34,10 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy { private _fileStatusInterval; public sortingOptions: SortingOption[] = [ - { label: 'project-overview.sorting.recent.label', order: 'desc', column: 'lastUpdated' }, - { label: 'project-overview.sorting.alphabetically.label', order: 'asc', column: 'filename' }, - { label: 'project-overview.sorting.number-of-pages.label', order: 'asc', column: 'numberOfPages' }, - { label: 'project-overview.sorting.number-of-analyses.label', order: 'desc', column: 'numberOfAnalyses' } + {label: 'project-overview.sorting.recent.label', order: 'desc', column: 'lastUpdated'}, + {label: 'project-overview.sorting.alphabetically.label', order: 'asc', column: 'filename'}, + {label: 'project-overview.sorting.number-of-pages.label', order: 'asc', column: 'numberOfPages'}, + {label: 'project-overview.sorting.number-of-analyses.label', order: 'desc', column: 'numberOfAnalyses'} ]; public sortingOption: SortingOption = this.sortingOptions[0]; public documentsChartData: DoughnutChartConfig[] = []; @@ -90,6 +90,14 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy { return this.activeProject.memberIds.map(m => this._userService.getName(this._userService.getUserById(m))); } + public get displayMembers() { + return this.members.slice(0, 6) + } + + public get overflowCount() { + return this.members.length - 6; + } + public get ownerName() { return this._userService.getNameForId(this.activeProject.ownerId); } @@ -104,7 +112,7 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy { const groups = groupBy(this.appStateService.activeProject.files, 'status'); this.documentsChartData = []; for (const key of Object.keys(groups)) { - this.documentsChartData.push({ value: groups[key].length, color: key, label: key }); + this.documentsChartData.push({value: groups[key].length, color: key, label: key}); } } @@ -162,11 +170,14 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy { } public openAssignProjectMembersDialog() { - this._dialog.open(AssignProjectMembersDialogComponent, { + this._dialog.open(AssignOwnerDialogComponent, { width: '400px', maxWidth: '90vw', - autoFocus: false - }); + autoFocus: false, + data: {type: 'project', project: this.appStateService.activeProject.project } + }).afterClosed().subscribe( ()=>{ + this._getFileStatus(); + }) } public reanalyseFile($event: MouseEvent, fileStatus: FileStatus) { @@ -203,12 +214,16 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy { public assignPeopleToFile($event: MouseEvent, fileStatus: FileStatus) { $event.stopPropagation(); - this._statusControllerService.assignProjectOwner1(this.appStateService.activeProjectId, fileStatus.fileId, this.user.id).subscribe(() => { - this._notificationService.showToastNotification('Successfully assigned ' + this.user.name + ' to file: ' + fileStatus.filename); - }); + this._dialog.open(AssignOwnerDialogComponent, { + width: '400px', + maxWidth: '90vw', + data: {type: 'file', file: fileStatus} + }).afterClosed().subscribe( ()=>{ + this._getFileStatus(); + }) } public getFileOwnerUsername(fileStatus: FileStatus) { - return undefined; + return this._userService.getNameForId(fileStatus.currentReviewer); } } diff --git a/apps/red-ui/src/app/state/app-state.service.ts b/apps/red-ui/src/app/state/app-state.service.ts index 4727a3028..f6b1a5f3e 100644 --- a/apps/red-ui/src/app/state/app-state.service.ts +++ b/apps/red-ui/src/app/state/app-state.service.ts @@ -57,15 +57,15 @@ export class AppStateService { get isActiveProjectOwner() { - return this._appState.activeProject.project.ownerId === this._userService.userId + return this._appState.activeProject?.project?.ownerId === this._userService.userId } get isActiveProjectMember() { - return this._appState.activeProject.project.memberIds.indexOf(this._userService.userId) >= 0; + return this._appState.activeProject?.project?.memberIds?.indexOf(this._userService.userId) >= 0; } get isActiveFileDocumentReviewer() { - return false; + return this._appState.activeFile?.currentReviewer === this._userService.userId; } diff --git a/apps/red-ui/src/app/user/user.service.ts b/apps/red-ui/src/app/user/user.service.ts index d33d6626f..9cc8f1fb7 100644 --- a/apps/red-ui/src/app/user/user.service.ts +++ b/apps/red-ui/src/app/user/user.service.ts @@ -56,6 +56,10 @@ export class UserService { return this._allUsers; } + get managerUsers() { + return this._allUsers.filter(u => u.roles.indexOf('RED_MANAGER') >= 0); + } + async loadAllUsersIfNecessary() { if (!this._allUsers) { await this.loadAllUsers(); @@ -64,7 +68,7 @@ export class UserService { async loadAllUsers() { const allUsers = await this._userControllerService.getAllUsers({}, 0, 100).toPromise(); - this._allUsers = allUsers.users; + this._allUsers = allUsers.users.filter(u => this._hasAnyRedRole(u)); return allUsers; } @@ -100,4 +104,8 @@ export class UserService { isUser(user: User) { return user.roles.indexOf('RED_USER') >= 0; } + + private _hasAnyRedRole(u: User) { + return u.roles.indexOf('RED_USER') >= 0 || u.roles.indexOf('RED_MANAGER') >= 0 || u.roles.indexOf('RED_ADMIN') >= 0; + } } diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index eede097e5..f5eeaa360 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -457,6 +457,38 @@ "label": "Unassigned" } }, + + "assign-file-owner":{ + "dialog": { + "single-user": { + "label": "Reviewer" + }, + "title":{ + "label": "Manage File Reviewer" + }, + "save": { + "label": "Save" + } + } + }, + + "assign-project-owner":{ + "dialog": { + "single-user": { + "label": "Owner" + }, + "multi-user": { + "label": "Members" + }, + "title":{ + "label": "Manage Project Owner and Members" + }, + "save": { + "label": "Save" + } + } + }, + "unassigned": "Unassigned", "under-review": "Under review", "under-approval": "Under approval", diff --git a/libs/red-ui-http/src/lib/api/projectController.service.ts b/libs/red-ui-http/src/lib/api/projectController.service.ts index 2c36d650a..a9d201669 100644 --- a/libs/red-ui-http/src/lib/api/projectController.service.ts +++ b/libs/red-ui-http/src/lib/api/projectController.service.ts @@ -257,15 +257,6 @@ export class ProjectControllerService { headers = headers.set('Accept', httpHeaderAcceptSelected); } - // to determine the Content-Type header - const consumes: string[] = [ - '*/*' - ]; - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected !== undefined) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - return this.httpClient.request('delete', `${this.basePath}/project/members/${encodeURIComponent(String(projectId))}`, { body: body, diff --git a/libs/red-ui-http/src/lib/model/fileStatus.ts b/libs/red-ui-http/src/lib/model/fileStatus.ts index 2f665a661..0a5deaa26 100644 --- a/libs/red-ui-http/src/lib/model/fileStatus.ts +++ b/libs/red-ui-http/src/lib/model/fileStatus.ts @@ -18,6 +18,10 @@ export interface FileStatus { * Date and time when the file was added to the system. */ added?: string; + /** + * The current reviewer's (if any) user id. + */ + currentReviewer?: string; /** * The ID of the file. */ From 0958823d57368e30ecb64888f85797026cb38434 Mon Sep 17 00:00:00 2001 From: Bamboo Date: Thu, 22 Oct 2020 00:23:08 +0200 Subject: [PATCH 2/2] chore(release) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fa1f3e72c..ad33fe2f2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "redaction", - "version": "0.0.69", + "version": "0.0.70", "license": "MIT", "scripts": { "build-lint-all": "ng lint --project=red-ui-http --fix && ng build --project=red-ui-http && ng lint --project=red-ui --fix && ng build --project=red-ui --prod",