FR-651: Remove role revision (#499)

This commit is contained in:
Rinat Arsaev 2021-06-25 17:21:28 +03:00 committed by GitHub
parent bf0ca08fac
commit 70a26701f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 46 additions and 25 deletions

View File

@ -72,7 +72,7 @@ export class OrganizationsService {
);
}
removeMemberRole(orgId: string, userId: string, memberRoleId: MemberRole['id']): Observable<any> {
removeMemberRole(orgId: string, userId: string, memberRoleId: MemberRole['id']): Observable<void> {
return this.membersService.removeMemberRole(this.idGeneratorService.shortUuid(), orgId, userId, memberRoleId);
}
@ -80,11 +80,11 @@ export class OrganizationsService {
return this.membersService.listOrgMembers(this.idGeneratorService.shortUuid(), orgId);
}
expelOrgMember(orgId: Organization['id'], userId: string): Observable<any> {
expelOrgMember(orgId: Organization['id'], userId: string): Observable<void> {
return this.membersService.expelOrgMember(this.idGeneratorService.shortUuid(), orgId, userId);
}
cancelOrgMembership(orgId: Organization['id']): Observable<any> {
cancelOrgMembership(orgId: Organization['id']): Observable<void> {
return this.orgsService.cancelOrgMembership(this.idGeneratorService.shortUuid(), orgId);
}

View File

@ -19,9 +19,10 @@
<dsh-nested-table-col *ngFor="let roleId of roleIds">
<mat-checkbox
[checked]="checkedAll(roleId) | async"
[disabled]="roleId === RoleId.Administrator || disableBatchChanges"
[disabled]="disabledAll(roleId)"
[ngClass]="{ disabled: disabledAll(roleId) }"
[indeterminate]="isIntermediate(roleId) | async"
(click)="toggleAll(roleId); $event.preventDefault()"
(click)="toggleAll(roleId, $event)"
></mat-checkbox>
</dsh-nested-table-col>
</dsh-nested-table-row>
@ -31,8 +32,9 @@
<dsh-nested-table-col *ngFor="let roleId of roleIds">
<mat-checkbox
[checked]="checked(roleId, shop.id) | async"
[disabled]="roleId === RoleId.Administrator"
(click)="toggle(roleId, shop.id); $event.preventDefault()"
[disabled]="disabled(roleId, shop.id) | async"
[ngClass]="{ disabled: (disabled(roleId, shop.id) | async) }"
(click)="toggle(roleId, shop.id, $event)"
></mat-checkbox>
</dsh-nested-table-col>
</dsh-nested-table-row>
@ -42,12 +44,7 @@
<dsh-nested-table-row *ngIf="isAllowRemoves">
<dsh-nested-table-col class="dsh-body-2"></dsh-nested-table-col>
<dsh-nested-table-col class="dsh-body-2" *ngFor="let roleId of roleIds" fxLayoutAlign="center center">
<button
*ngIf="roleId === RoleId.Administrator || !disableBatchChanges"
dsh-button
color="warn"
(click)="remove(roleId)"
>
<button *ngIf="hasRemove(roleId)" dsh-button color="warn" (click)="remove(roleId)">
{{ t('remove') }}
</button>
</dsh-nested-table-col>

View File

@ -1,3 +1,7 @@
::ng-deep .dsh-hidden {
display: none;
}
.disabled {
pointer-events: none;
}

View File

@ -35,7 +35,12 @@ export class ChangeRolesTableComponent implements OnInit {
return this.roles$.value;
}
@Input() @coerceBoolean disableBatchChanges: boolean;
/**
* Edit mode:
* - no batch changes
* - there must be at least one role
*/
@Input() @coerceBoolean editMode: boolean;
@Input() @coerceBoolean controlled: boolean;
@Output() selectedRoles = new EventEmitter<PartialReadonly<MemberRole>[]>();
@ -44,22 +49,20 @@ export class ChangeRolesTableComponent implements OnInit {
roleIds: RoleId[] = [];
shops$ = this.shopsService.shops$;
// eslint-disable-next-line @typescript-eslint/naming-convention
RoleId = RoleId;
get availableRoles(): RoleId[] {
return Object.values(RoleId).filter((r) => !this.roleIds.includes(r));
}
get isAllowRemoves(): boolean {
return !this.disableBatchChanges || this.hasAdminRole;
return !this.editMode || this.hasAdminRole;
}
get isAllowAdd(): boolean {
return !!this.availableRoles.length && !this.hasAdminRole;
}
private roles$ = new BehaviorSubject<PartialReadonly<MemberRole>[]>([]);
roles$ = new BehaviorSubject<PartialReadonly<MemberRole>[]>([]);
private get hasAdminRole() {
return !!this.roles.find((r) => r.id === RoleId.Administrator);
@ -103,7 +106,7 @@ export class ChangeRolesTableComponent implements OnInit {
this.removeRoles(this.roles.filter((r) => r.roleId === roleId));
}
toggle(roleId: RoleId, resourceId: string): void {
toggle(roleId: RoleId, resourceId: string, event: MouseEvent): void {
const role: PartialReadonly<MemberRole> = {
roleId,
scope: { id: ResourceScopeId.Shop, resourceId },
@ -114,9 +117,10 @@ export class ChangeRolesTableComponent implements OnInit {
} else {
this.addRoles([role]);
}
event.preventDefault();
}
toggleAll(roleId: RoleId): void {
toggleAll(roleId: RoleId, event: MouseEvent): void {
const roles = this.roles.filter((r) => r.roleId === roleId);
combineLatest([this.shops$, this.checkedAll(roleId)])
.pipe(first(), untilDestroyed(this))
@ -133,6 +137,18 @@ export class ChangeRolesTableComponent implements OnInit {
this.addRoles(newRoles);
}
});
event.preventDefault();
}
disabled(roleId: RoleId, resourceId: string): Observable<boolean> {
if (roleId === RoleId.Administrator) return of(true);
return combineLatest([this.roles$, this.checked(roleId, resourceId)]).pipe(
map(([roles, isChecked]) => roles.length <= 1 && isChecked)
);
}
disabledAll(roleId: RoleId): boolean {
return roleId === RoleId.Administrator || this.editMode;
}
checked(roleId: RoleId, resourceId: string): Observable<boolean> {
@ -158,6 +174,10 @@ export class ChangeRolesTableComponent implements OnInit {
);
}
hasRemove(roleId: RoleId): boolean {
return roleId === RoleId.Administrator || !this.editMode;
}
isIntermediate(roleId: RoleId): Observable<boolean> {
return combineLatest([this.shops$, this.roles$]).pipe(
map(([shops, roles]) => {

View File

@ -6,7 +6,7 @@
>
<dsh-change-roles-table
controlled
disableBatchChanges
editMode
[roles]="roles$ | async"
(addedRoles)="addRoles($event)"
(removedRoles)="removeRoles($event)"

View File

@ -1,7 +1,7 @@
import { ChangeDetectionStrategy, Component, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { UntilDestroy } from '@ngneat/until-destroy';
import { BehaviorSubject, defer, forkJoin, of } from 'rxjs';
import { BehaviorSubject, defer, forkJoin, of, Subscription } from 'rxjs';
import { catchError, pluck, shareReplay, switchMap } from 'rxjs/operators';
import { OrganizationsService } from '@dsh/api';
@ -32,11 +32,11 @@ export class EditRolesDialogComponent {
private errorService: ErrorService
) {}
cancel() {
cancel(): void {
this.dialogRef.close(BaseDialogResponseStatus.Cancelled);
}
addRoles(roles: MemberRole[]) {
addRoles(roles: MemberRole[]): Subscription {
return forkJoin(
roles.map((role) => this.organizationsService.assignMemberRole(this.data.orgId, this.data.userId, role))
)
@ -49,7 +49,7 @@ export class EditRolesDialogComponent {
.subscribe(() => this.updateRoles$.next());
}
removeRoles(roles: MemberRole[]) {
removeRoles(roles: MemberRole[]): Subscription {
return forkJoin(
roles.map((role) => this.organizationsService.removeMemberRole(this.data.orgId, this.data.userId, role.id))
)