Edit project approvers
This commit is contained in:
parent
103c23a194
commit
534c5ea3dc
@ -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)"
|
||||
>
|
||||
<redaction-initials-avatar [userId]="userId" size="large" color="gray"></redaction-initials-avatar>
|
||||
<div class="remove">
|
||||
<div class="remove" *ngIf="canRemoveMember(userId)">
|
||||
<mat-icon svgIcon="red:close"></mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -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<string>();
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,17 +14,39 @@
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<ng-container *ngIf="data.type === 'project'">
|
||||
<div class="all-caps-label mt-10" [translate]="'assign-' + data.type + '-owner.dialog.members'"></div>
|
||||
<div class="all-caps-label mt-16" [translate]="'assign-' + data.type + '-owner.dialog.approvers'"></div>
|
||||
<redaction-team-members
|
||||
[memberIds]="selectedUserList"
|
||||
[memberIds]="selectedApproversList"
|
||||
[canAdd]="false"
|
||||
[largeSpacing]="true"
|
||||
[canRemove]="true"
|
||||
[unremovableMembers]="[selectedSingleUser]"
|
||||
(remove)="toggleSelected($event)"
|
||||
[perLine]="13"
|
||||
></redaction-team-members>
|
||||
|
||||
<pre *ngIf="selectedUserList.length === 0" class="info" [innerHTML]="'assign-' + data.type + '-owner.dialog.no-members' | translate"></pre>
|
||||
<pre
|
||||
*ngIf="selectedApproversList.length === 0"
|
||||
class="info"
|
||||
[innerHTML]="'assign-' + data.type + '-owner.dialog.no-approvers' | translate"
|
||||
></pre>
|
||||
|
||||
<div class="all-caps-label mt-16" [translate]="'assign-' + data.type + '-owner.dialog.reviewers'"></div>
|
||||
<redaction-team-members
|
||||
[memberIds]="selectedReviewersList"
|
||||
[canAdd]="false"
|
||||
[largeSpacing]="true"
|
||||
[canRemove]="true"
|
||||
[unremovableMembers]="[selectedSingleUser]"
|
||||
(remove)="toggleSelected($event)"
|
||||
[perLine]="13"
|
||||
></redaction-team-members>
|
||||
|
||||
<pre
|
||||
*ngIf="selectedReviewersList.length === 0"
|
||||
class="info"
|
||||
[innerHTML]="'assign-' + data.type + '-owner.dialog.no-reviewers' | translate"
|
||||
></pre>
|
||||
|
||||
<redaction-search-input
|
||||
[width]="560"
|
||||
@ -36,8 +58,13 @@
|
||||
<div class="members-list">
|
||||
<div *ngFor="let userId of multiUsersSelectOptions" [class.selected]="isMemberSelected(userId)" (click)="toggleSelected(userId)">
|
||||
<redaction-initials-avatar [userId]="userId" [withName]="true" size="large"></redaction-initials-avatar>
|
||||
<mat-icon svgIcon="red:check" class="add"></mat-icon>
|
||||
<mat-icon svgIcon="red:close" class="remove"></mat-icon>
|
||||
<div class="actions">
|
||||
<div class="make-approver" (click)="toggleApprover(userId, $event)">
|
||||
<redaction-round-checkbox class="mr-8" [active]="isApprover(userId)"></redaction-round-checkbox>
|
||||
<span [translate]="'assign-' + data.type + '-owner.dialog.make-approver'"></span>
|
||||
</div>
|
||||
<mat-icon *ngIf="!isOwner(userId)" [svgIcon]="'red:' + (isMemberSelected(userId) ? 'close' : 'check')"></mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -49,6 +49,10 @@ export class ProjectWrapper {
|
||||
return this.project.memberIds;
|
||||
}
|
||||
|
||||
get approverIds() {
|
||||
return this.project.approverIds;
|
||||
}
|
||||
|
||||
get files() {
|
||||
return this._files;
|
||||
}
|
||||
|
||||
@ -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": {
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
*/
|
||||
|
||||
export interface Project {
|
||||
approverIds?: Array<string>;
|
||||
date?: string;
|
||||
description?: string;
|
||||
downloadFileTypes?: Array<Project.DownloadFileTypesEnum>;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user