From 534c5ea3dc3b40694833ce9e9c0f8d11fb22c08c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Tue, 4 May 2021 15:53:47 +0300 Subject: [PATCH] Edit project approvers --- .../team-members/team-members.component.html | 6 +- .../team-members/team-members.component.ts | 5 ++ .../assign-owner-dialog.component.html | 37 ++++++-- .../assign-owner-dialog.component.scss | 48 +++++----- .../assign-owner-dialog.component.ts | 90 +++++++++++++++---- .../src/app/state/model/project.wrapper.ts | 4 + apps/red-ui/src/assets/i18n/en.json | 7 +- libs/red-ui-http/src/lib/model/project.ts | 1 + 8 files changed, 145 insertions(+), 53 deletions(-) diff --git a/apps/red-ui/src/app/modules/projects/components/team-members/team-members.component.html b/apps/red-ui/src/app/modules/projects/components/team-members/team-members.component.html index 817338b65..0c04aa61c 100644 --- a/apps/red-ui/src/app/modules/projects/components/team-members/team-members.component.html +++ b/apps/red-ui/src/app/modules/projects/components/team-members/team-members.component.html @@ -3,11 +3,11 @@ *ngFor="let userId of displayedMembers" class="member" [class.large-spacing]="largeSpacing" - [class.can-remove]="canRemove" - (click)="canRemove && remove.emit(userId)" + [class.can-remove]="canRemoveMember(userId)" + (click)="canRemoveMember(userId) && remove.emit(userId)" > -
+
diff --git a/apps/red-ui/src/app/modules/projects/components/team-members/team-members.component.ts b/apps/red-ui/src/app/modules/projects/components/team-members/team-members.component.ts index 34c83603f..ed1a49f2d 100644 --- a/apps/red-ui/src/app/modules/projects/components/team-members/team-members.component.ts +++ b/apps/red-ui/src/app/modules/projects/components/team-members/team-members.component.ts @@ -12,6 +12,7 @@ export class TeamMembersComponent implements OnInit { @Input() public canAdd = true; @Input() public largeSpacing = false; @Input() public canRemove = false; + @Input() public unremovableMembers: string[] = []; @Output() public openAssignProjectMembersDialog = new EventEmitter(); @Output() public remove = new EventEmitter(); @@ -38,4 +39,8 @@ export class TeamMembersComponent implements OnInit { public get overflowCount() { return this.memberIds.length > this.maxTeamMembersBeforeExpand ? this.memberIds.length - (this.maxTeamMembersBeforeExpand - 1) : 0; } + + public canRemoveMember(userId: string) { + return this.canRemove && this.unremovableMembers.indexOf(userId) === -1; + } } 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 ceaecbb0e..f91abc1cf 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 @@ -14,17 +14,39 @@ -
+
-

+                

+
+                
+ + +

 
                 
                     
- - +
+
+ + +
+ +
diff --git a/apps/red-ui/src/app/modules/projects/dialogs/assign-owner-dialog/assign-owner-dialog.component.scss b/apps/red-ui/src/app/modules/projects/dialogs/assign-owner-dialog/assign-owner-dialog.component.scss index 3c383fe6e..5ef1a840a 100644 --- a/apps/red-ui/src/app/modules/projects/dialogs/assign-owner-dialog/assign-owner-dialog.component.scss +++ b/apps/red-ui/src/app/modules/projects/dialogs/assign-owner-dialog/assign-owner-dialog.component.scss @@ -8,6 +8,11 @@ margin-top: 16px; } +redaction-team-members { + margin-top: -4px; + display: block; +} + .members-list { max-height: 220px; height: 220px; @@ -30,40 +35,35 @@ width: 560px; box-sizing: border-box; - mat-icon { + .make-approver { + display: flex; + align-items: center; + } + + .actions { display: none; position: absolute; right: 13px; - top: 12px; - width: 14px; - height: 14px; + top: 0; + height: 38px; + align-items: center; + + mat-icon { + width: 14px; + height: 14px; + margin-left: 24px; + } } &.selected { background-color: $green-2; - - mat-icon.add { - display: initial; - } } &:hover { background-color: $grey-2; - &.selected { - mat-icon.remove { - display: initial; - } - - mat-icon.add { - display: none; - } - } - - &:not(.selected) { - mat-icon.add { - display: initial; - } + .actions { + display: flex; } } } @@ -72,7 +72,3 @@ .info { margin-top: 4px; } - -.mt-10 { - margin-top: 10px; -} 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 dff977c46..a3fbff6ae 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 @@ -42,11 +42,18 @@ export class AssignOwnerDialogComponent { const project = this.data.project; this.usersForm = this._formBuilder.group({ singleUser: [project?.ownerId, Validators.required], - userList: [[...project?.memberIds]] + 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') { @@ -67,8 +74,20 @@ export class AssignOwnerDialogComponent { return this.usersForm.get('singleUser').value; } - public get selectedUserList(): string[] { - return this.usersForm.get('userList').value; + public get selectedApproversList(): string[] { + return this.usersForm.get('approvers').value; + } + + public get selectedReviewersList(): string[] { + return this.selectedUsersList.filter((m) => this.selectedApproversList.indexOf(m) === -1); + } + + public get selectedUsersList(): string[] { + return this.usersForm.get('members').value; + } + + public isOwner(userId: string): boolean { + return userId === this.selectedSingleUser; } async saveUsers() { @@ -76,9 +95,11 @@ export class AssignOwnerDialogComponent { try { if (this.data.type === 'project') { const ownerId = this.selectedSingleUser; - const memberIds = this.selectedUserList; + 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); } @@ -118,18 +139,56 @@ export class AssignOwnerDialogComponent { } public isMemberSelected(userId: string): boolean { - return this.selectedUserList.indexOf(userId) !== -1; + return this.selectedUsersList.indexOf(userId) !== -1; + } + + public isApprover(userId: string): boolean { + return this.selectedApproversList.indexOf(userId) !== -1; + } + + public toggleApprover(userId: string, $event?: MouseEvent) { + $event?.stopPropagation(); + + if (this.isOwner(userId) && this.isApprover(userId)) { + return; + } + + if (this.isApprover(userId)) { + this.selectedApproversList.splice(this.selectedApproversList.indexOf(userId), 1); + } else { + this.selectedApproversList.push(userId); + if (!this.isMemberSelected(userId)) { + this.toggleSelected(userId); + } + } } public toggleSelected(userId: string) { if (this.isMemberSelected(userId)) { - const idx = this.selectedUserList.indexOf(userId); - this.selectedUserList.splice(idx, 1); + this.selectedUsersList.splice(this.selectedUsersList.indexOf(userId), 1); + + if (this.isApprover(userId)) { + this.selectedApproversList.splice(this.selectedApproversList.indexOf(userId), 1); + } } else { - this.selectedUserList.push(userId); + this.selectedUsersList.push(userId); } } + private _compareLists(l1: string[], l2: string[]) { + if (l1.length !== l2.length) { + return true; + } + + for (let idx = 0; idx < l1.length; ++idx) { + if (l1[idx] !== l2[idx]) { + return true; + } + } + + return false; + } + public get changed(): boolean { if (this.data.ignoreChanged) { return true; @@ -140,18 +199,15 @@ export class AssignOwnerDialogComponent { return true; } - const initial = this.data.project.memberIds.sort(); - const current = this.selectedUserList.sort(); + const initialMembers = this.data.project.memberIds.sort(); + const currentMembers = this.selectedUsersList.sort(); - if (initial.length !== current.length) { + const initialApprovers = this.data.project.approverIds.sort(); + const currentApprovers = this.selectedApproversList.sort(); + + if (this._compareLists(initialMembers, currentMembers) || this._compareLists(initialApprovers, currentApprovers)) { return true; } - - for (let idx = 0; idx < initial.length; ++idx) { - if (initial[idx] !== current[idx]) { - return true; - } - } } else if (this.data.type === 'file') { const reviewerId = this.selectedSingleUser; diff --git a/apps/red-ui/src/app/state/model/project.wrapper.ts b/apps/red-ui/src/app/state/model/project.wrapper.ts index 517635fbd..de4798f62 100644 --- a/apps/red-ui/src/app/state/model/project.wrapper.ts +++ b/apps/red-ui/src/app/state/model/project.wrapper.ts @@ -49,6 +49,10 @@ export class ProjectWrapper { return this.project.memberIds; } + get approverIds() { + return this.project.approverIds; + } + get files() { return this._files; } diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index 309d67fab..06a15f6a7 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -455,11 +455,14 @@ "single-user": "Owner", "multi-user": "Review Team", "title": "Manage Dossier Team", - "members": "Members", + "approvers": "Approvers", + "reviewers": "Reviewers", "save": "Save Changes", "cancel": "Cancel", "search": "Search...", - "no-members": "No members yet.\nSelect from the list below." + "no-approvers": "No approvers yet.\nSelect from the list below.", + "no-reviewers": "No reviewers yet.\nSelect from the list below.", + "make-approver": "Make Approver" } }, "project-member-guard": { diff --git a/libs/red-ui-http/src/lib/model/project.ts b/libs/red-ui-http/src/lib/model/project.ts index dfb74d8dc..e3bbacdd3 100644 --- a/libs/red-ui-http/src/lib/model/project.ts +++ b/libs/red-ui-http/src/lib/model/project.ts @@ -11,6 +11,7 @@ */ export interface Project { + approverIds?: Array; date?: string; description?: string; downloadFileTypes?: Array;