mirror of https://github.com/abpframework/abp.git
9 changed files with 514 additions and 26 deletions
@ -0,0 +1,500 @@ |
|||||
|
# How to Replace PermissionManagementComponent |
||||
|
|
||||
|
 |
||||
|
|
||||
|
Run the following command in `angular` folder to create a new component called `PermissionManagementComponent`. |
||||
|
|
||||
|
```bash |
||||
|
yarn ng generate component permission-management --entryComponent --inlineStyle |
||||
|
|
||||
|
# You don't need the --entryComponent option in Angular 9 |
||||
|
``` |
||||
|
|
||||
|
Open the generated `permission-management.component.ts` in `src/app/permission-management` folder and replace the content with the following: |
||||
|
|
||||
|
```js |
||||
|
import { |
||||
|
Component, |
||||
|
EventEmitter, |
||||
|
Input, |
||||
|
Output, |
||||
|
Renderer2, |
||||
|
TrackByFunction, |
||||
|
Inject, |
||||
|
Optional, |
||||
|
} from '@angular/core'; |
||||
|
import { ReplaceableComponents } from '@abp/ng.core'; |
||||
|
import { Select, Store } from '@ngxs/store'; |
||||
|
import { Observable } from 'rxjs'; |
||||
|
import { finalize, map, pluck, take, tap } from 'rxjs/operators'; |
||||
|
import { |
||||
|
GetPermissions, |
||||
|
UpdatePermissions, |
||||
|
PermissionManagement, |
||||
|
PermissionManagementState, |
||||
|
} from '@abp/ng.permission-management'; |
||||
|
|
||||
|
type PermissionWithMargin = PermissionManagement.Permission & { |
||||
|
margin: number; |
||||
|
}; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'app-permission-management', |
||||
|
templateUrl: './permission-management.component.html', |
||||
|
styles: [ |
||||
|
` |
||||
|
.overflow-scroll { |
||||
|
max-height: 70vh; |
||||
|
overflow-y: scroll; |
||||
|
} |
||||
|
`, |
||||
|
], |
||||
|
}) |
||||
|
export class PermissionManagementComponent |
||||
|
implements |
||||
|
PermissionManagement.PermissionManagementComponentInputs, |
||||
|
PermissionManagement.PermissionManagementComponentOutputs { |
||||
|
protected _providerName: string; |
||||
|
@Input() |
||||
|
get providerName(): string { |
||||
|
if (this.replaceableData) return this.replaceableData.inputs.providerName; |
||||
|
|
||||
|
return this._providerName; |
||||
|
} |
||||
|
|
||||
|
set providerName(value: string) { |
||||
|
this._providerName = value; |
||||
|
} |
||||
|
|
||||
|
protected _providerKey: string; |
||||
|
@Input() |
||||
|
get providerKey(): string { |
||||
|
if (this.replaceableData) return this.replaceableData.inputs.providerKey; |
||||
|
|
||||
|
return this._providerKey; |
||||
|
} |
||||
|
|
||||
|
set providerKey(value: string) { |
||||
|
this._providerKey = value; |
||||
|
} |
||||
|
|
||||
|
protected _hideBadges = false; |
||||
|
@Input() |
||||
|
get hideBadges(): boolean { |
||||
|
if (this.replaceableData) return this.replaceableData.inputs.hideBadges; |
||||
|
|
||||
|
return this._hideBadges; |
||||
|
} |
||||
|
|
||||
|
set hideBadges(value: boolean) { |
||||
|
this._hideBadges = value; |
||||
|
} |
||||
|
|
||||
|
protected _visible = false; |
||||
|
@Input() |
||||
|
get visible(): boolean { |
||||
|
return this._visible; |
||||
|
} |
||||
|
|
||||
|
set visible(value: boolean) { |
||||
|
if (value === this._visible) return; |
||||
|
|
||||
|
if (value) { |
||||
|
this.openModal().subscribe(() => { |
||||
|
this._visible = true; |
||||
|
this.visibleChange.emit(true); |
||||
|
if (this.replaceableData) this.replaceableData.outputs.visibleChange(true); |
||||
|
}); |
||||
|
} else { |
||||
|
this.selectedGroup = null; |
||||
|
this._visible = false; |
||||
|
this.visibleChange.emit(false); |
||||
|
if (this.replaceableData) this.replaceableData.outputs.visibleChange(false); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Output() readonly visibleChange = new EventEmitter<boolean>(); |
||||
|
|
||||
|
@Select(PermissionManagementState.getPermissionGroups) |
||||
|
groups$: Observable<PermissionManagement.Group[]>; |
||||
|
|
||||
|
@Select(PermissionManagementState.getEntityDisplayName) |
||||
|
entityName$: Observable<string>; |
||||
|
|
||||
|
selectedGroup: PermissionManagement.Group; |
||||
|
|
||||
|
permissions: PermissionManagement.Permission[] = []; |
||||
|
|
||||
|
selectThisTab = false; |
||||
|
|
||||
|
selectAllTab = false; |
||||
|
|
||||
|
modalBusy = false; |
||||
|
|
||||
|
trackByFn: TrackByFunction<PermissionManagement.Group> = (_, item) => item.name; |
||||
|
|
||||
|
get selectedGroupPermissions$(): Observable<PermissionWithMargin[]> { |
||||
|
return this.groups$.pipe( |
||||
|
map((groups) => |
||||
|
this.selectedGroup |
||||
|
? groups.find((group) => group.name === this.selectedGroup.name).permissions |
||||
|
: [] |
||||
|
), |
||||
|
map<PermissionManagement.Permission[], PermissionWithMargin[]>((permissions) => |
||||
|
permissions.map( |
||||
|
(permission) => |
||||
|
(({ |
||||
|
...permission, |
||||
|
margin: findMargin(permissions, permission), |
||||
|
isGranted: this.permissions.find((per) => per.name === permission.name).isGranted, |
||||
|
} as any) as PermissionWithMargin) |
||||
|
) |
||||
|
) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
get isVisible(): boolean { |
||||
|
if (!this.replaceableData) return this.visible; |
||||
|
|
||||
|
return this.replaceableData.inputs.visible; |
||||
|
} |
||||
|
|
||||
|
constructor( |
||||
|
@Optional() |
||||
|
@Inject('REPLACEABLE_DATA') |
||||
|
public replaceableData: ReplaceableComponents.ReplaceableTemplateData< |
||||
|
PermissionManagement.PermissionManagementComponentInputs, |
||||
|
PermissionManagement.PermissionManagementComponentOutputs |
||||
|
>, |
||||
|
private store: Store |
||||
|
) {} |
||||
|
|
||||
|
getChecked(name: string) { |
||||
|
return (this.permissions.find((per) => per.name === name) || { isGranted: false }).isGranted; |
||||
|
} |
||||
|
|
||||
|
isGrantedByOtherProviderName(grantedProviders: PermissionManagement.GrantedProvider[]): boolean { |
||||
|
if (grantedProviders.length) { |
||||
|
return grantedProviders.findIndex((p) => p.providerName !== this.providerName) > -1; |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
onClickCheckbox(clickedPermission: PermissionManagement.Permission, value) { |
||||
|
if ( |
||||
|
clickedPermission.isGranted && |
||||
|
this.isGrantedByOtherProviderName(clickedPermission.grantedProviders) |
||||
|
) |
||||
|
return; |
||||
|
|
||||
|
setTimeout(() => { |
||||
|
this.permissions = this.permissions.map((per) => { |
||||
|
if (clickedPermission.name === per.name) { |
||||
|
return { ...per, isGranted: !per.isGranted }; |
||||
|
} else if (clickedPermission.name === per.parentName && clickedPermission.isGranted) { |
||||
|
return { ...per, isGranted: false }; |
||||
|
} else if (clickedPermission.parentName === per.name && !clickedPermission.isGranted) { |
||||
|
return { ...per, isGranted: true }; |
||||
|
} |
||||
|
|
||||
|
return per; |
||||
|
}); |
||||
|
|
||||
|
this.setTabCheckboxState(); |
||||
|
this.setGrantCheckboxState(); |
||||
|
}, 0); |
||||
|
} |
||||
|
|
||||
|
setTabCheckboxState() { |
||||
|
this.selectedGroupPermissions$.pipe(take(1)).subscribe((permissions) => { |
||||
|
const selectedPermissions = permissions.filter((per) => per.isGranted); |
||||
|
const element = document.querySelector('#select-all-in-this-tabs') as any; |
||||
|
|
||||
|
if (selectedPermissions.length === permissions.length) { |
||||
|
element.indeterminate = false; |
||||
|
this.selectThisTab = true; |
||||
|
} else if (selectedPermissions.length === 0) { |
||||
|
element.indeterminate = false; |
||||
|
this.selectThisTab = false; |
||||
|
} else { |
||||
|
element.indeterminate = true; |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
setGrantCheckboxState() { |
||||
|
const selectedAllPermissions = this.permissions.filter((per) => per.isGranted); |
||||
|
const checkboxElement = document.querySelector('#select-all-in-all-tabs') as any; |
||||
|
|
||||
|
if (selectedAllPermissions.length === this.permissions.length) { |
||||
|
checkboxElement.indeterminate = false; |
||||
|
this.selectAllTab = true; |
||||
|
} else if (selectedAllPermissions.length === 0) { |
||||
|
checkboxElement.indeterminate = false; |
||||
|
this.selectAllTab = false; |
||||
|
} else { |
||||
|
checkboxElement.indeterminate = true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
onClickSelectThisTab() { |
||||
|
this.selectedGroupPermissions$.pipe(take(1)).subscribe((permissions) => { |
||||
|
permissions.forEach((permission) => { |
||||
|
if (permission.isGranted && this.isGrantedByOtherProviderName(permission.grantedProviders)) |
||||
|
return; |
||||
|
|
||||
|
const index = this.permissions.findIndex((per) => per.name === permission.name); |
||||
|
|
||||
|
this.permissions = [ |
||||
|
...this.permissions.slice(0, index), |
||||
|
{ ...this.permissions[index], isGranted: !this.selectThisTab }, |
||||
|
...this.permissions.slice(index + 1), |
||||
|
]; |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
this.setGrantCheckboxState(); |
||||
|
} |
||||
|
|
||||
|
onClickSelectAll() { |
||||
|
this.permissions = this.permissions.map((permission) => ({ |
||||
|
...permission, |
||||
|
isGranted: |
||||
|
this.isGrantedByOtherProviderName(permission.grantedProviders) || !this.selectAllTab, |
||||
|
})); |
||||
|
|
||||
|
this.selectThisTab = !this.selectAllTab; |
||||
|
} |
||||
|
|
||||
|
onChangeGroup(group: PermissionManagement.Group) { |
||||
|
this.selectedGroup = group; |
||||
|
this.setTabCheckboxState(); |
||||
|
} |
||||
|
|
||||
|
submit() { |
||||
|
this.modalBusy = true; |
||||
|
const unchangedPermissions = getPermissions( |
||||
|
this.store.selectSnapshot(PermissionManagementState.getPermissionGroups) |
||||
|
); |
||||
|
|
||||
|
const changedPermissions: PermissionManagement.MinimumPermission[] = this.permissions |
||||
|
.filter((per) => |
||||
|
unchangedPermissions.find((unchanged) => unchanged.name === per.name).isGranted === |
||||
|
per.isGranted |
||||
|
? false |
||||
|
: true |
||||
|
) |
||||
|
.map(({ name, isGranted }) => ({ name, isGranted })); |
||||
|
|
||||
|
if (changedPermissions.length) { |
||||
|
this.store |
||||
|
.dispatch( |
||||
|
new UpdatePermissions({ |
||||
|
providerKey: this.providerKey, |
||||
|
providerName: this.providerName, |
||||
|
permissions: changedPermissions, |
||||
|
}) |
||||
|
) |
||||
|
.pipe(finalize(() => (this.modalBusy = false))) |
||||
|
.subscribe(() => { |
||||
|
this.visible = false; |
||||
|
}); |
||||
|
} else { |
||||
|
this.modalBusy = false; |
||||
|
this.visible = false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
openModal() { |
||||
|
if (!this.providerKey || !this.providerName) { |
||||
|
throw new Error('Provider Key and Provider Name are required.'); |
||||
|
} |
||||
|
|
||||
|
return this.store |
||||
|
.dispatch( |
||||
|
new GetPermissions({ |
||||
|
providerKey: this.providerKey, |
||||
|
providerName: this.providerName, |
||||
|
}) |
||||
|
) |
||||
|
.pipe( |
||||
|
pluck('PermissionManagementState', 'permissionRes'), |
||||
|
tap((permissionRes: PermissionManagement.Response) => { |
||||
|
this.selectedGroup = permissionRes.groups[0]; |
||||
|
this.permissions = getPermissions(permissionRes.groups); |
||||
|
}) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
initModal() { |
||||
|
this.setTabCheckboxState(); |
||||
|
this.setGrantCheckboxState(); |
||||
|
} |
||||
|
|
||||
|
onVisibleChange(visible: boolean) { |
||||
|
this.visible = visible; |
||||
|
|
||||
|
if (this.replaceableData) { |
||||
|
this.replaceableData.inputs.visible = visible; |
||||
|
this.replaceableData.outputs.visibleChange(visible); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function findMargin( |
||||
|
permissions: PermissionManagement.Permission[], |
||||
|
permission: PermissionManagement.Permission |
||||
|
) { |
||||
|
const parentPermission = permissions.find((per) => per.name === permission.parentName); |
||||
|
|
||||
|
if (parentPermission && parentPermission.parentName) { |
||||
|
let margin = 20; |
||||
|
return (margin += findMargin(permissions, parentPermission)); |
||||
|
} |
||||
|
|
||||
|
return parentPermission ? 20 : 0; |
||||
|
} |
||||
|
|
||||
|
function getPermissions(groups: PermissionManagement.Group[]): PermissionManagement.Permission[] { |
||||
|
return groups.reduce((acc, val) => [...acc, ...val.permissions], []); |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
Open the generated `permission-management.component.html` in `src/app/permission-management` folder and replace the content with the below: |
||||
|
|
||||
|
```html |
||||
|
<abp-modal |
||||
|
[visible]="isVisible" |
||||
|
(visibleChange)="onVisibleChange($event)" |
||||
|
(init)="initModal()" |
||||
|
[busy]="modalBusy" |
||||
|
> |
||||
|
<ng-container *ngIf="{ entityName: entityName$ | async } as data"> |
||||
|
<ng-template #abpHeader> |
||||
|
<h4> |
||||
|
{%{{{ 'AbpPermissionManagement::Permissions' | abpLocalization }}}%} - {%{{{ data.entityName }}}%} |
||||
|
</h4> |
||||
|
</ng-template> |
||||
|
<ng-template #abpBody> |
||||
|
<div class="custom-checkbox custom-control mb-2"> |
||||
|
<input |
||||
|
type="checkbox" |
||||
|
id="select-all-in-all-tabs" |
||||
|
name="select-all-in-all-tabs" |
||||
|
class="custom-control-input" |
||||
|
[(ngModel)]="selectAllTab" |
||||
|
(click)="onClickSelectAll()" |
||||
|
/> |
||||
|
<label class="custom-control-label" for="select-all-in-all-tabs">{%{{{ |
||||
|
'AbpPermissionManagement::SelectAllInAllTabs' | abpLocalization |
||||
|
}}}%}</label> |
||||
|
</div> |
||||
|
|
||||
|
<hr class="mt-2 mb-2" /> |
||||
|
<div class="row"> |
||||
|
<div class="overflow-scroll col-md-4"> |
||||
|
<ul class="nav nav-pills flex-column"> |
||||
|
<li *ngFor="let group of groups$ | async; trackBy: trackByFn" class="nav-item"> |
||||
|
<a |
||||
|
class="nav-link pointer" |
||||
|
[class.active]="selectedGroup?.name === group?.name" |
||||
|
(click)="onChangeGroup(group)" |
||||
|
>{%{{{ group?.displayName }}}%}</a |
||||
|
> |
||||
|
</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
<div class="col-md-8 overflow-scroll"> |
||||
|
<h4>{%{{{ selectedGroup?.displayName }}}%}</h4> |
||||
|
<hr class="mt-2 mb-3" /> |
||||
|
<div class="pl-1 pt-1"> |
||||
|
<div class="custom-checkbox custom-control mb-2"> |
||||
|
<input |
||||
|
type="checkbox" |
||||
|
id="select-all-in-this-tabs" |
||||
|
name="select-all-in-this-tabs" |
||||
|
class="custom-control-input" |
||||
|
[(ngModel)]="selectThisTab" |
||||
|
(click)="onClickSelectThisTab()" |
||||
|
/> |
||||
|
<label class="custom-control-label" for="select-all-in-this-tabs">{%{{{ |
||||
|
'AbpPermissionManagement::SelectAllInThisTab' | abpLocalization |
||||
|
}}}%}</label> |
||||
|
</div> |
||||
|
<hr class="mb-3" /> |
||||
|
<div |
||||
|
*ngFor=" |
||||
|
let permission of selectedGroupPermissions$ | async; |
||||
|
let i = index; |
||||
|
trackBy: trackByFn |
||||
|
" |
||||
|
[style.margin-left]="permission.margin + 'px'" |
||||
|
class="custom-checkbox custom-control mb-2" |
||||
|
> |
||||
|
<input |
||||
|
#permissionCheckbox |
||||
|
type="checkbox" |
||||
|
[checked]="getChecked(permission.name)" |
||||
|
[value]="getChecked(permission.name)" |
||||
|
[attr.id]="permission.name" |
||||
|
class="custom-control-input" |
||||
|
[disabled]="isGrantedByOtherProviderName(permission.grantedProviders)" |
||||
|
/> |
||||
|
<label |
||||
|
class="custom-control-label" |
||||
|
[attr.for]="permission.name" |
||||
|
(click)="onClickCheckbox(permission, permissionCheckbox.value)" |
||||
|
>{%{{{ permission.displayName }}}%} |
||||
|
<ng-container *ngIf="!hideBadges"> |
||||
|
<span |
||||
|
*ngFor="let provider of permission.grantedProviders" |
||||
|
class="badge badge-light" |
||||
|
>{%{{{ provider.providerName }}}%}: {%{{{ provider.providerKey }}}%}</span |
||||
|
> |
||||
|
</ng-container> |
||||
|
</label> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</ng-template> |
||||
|
<ng-template #abpFooter> |
||||
|
<button type="button" class="btn btn-secondary" #abpClose> |
||||
|
{%{{{ 'AbpIdentity::Cancel' | abpLocalization }}}%} |
||||
|
</button> |
||||
|
<abp-button iconClass="fa fa-check" (click)="submit()">{%{{{ |
||||
|
'AbpIdentity::Save' | abpLocalization |
||||
|
}}}%}</abp-button> |
||||
|
</ng-template> |
||||
|
</ng-container> |
||||
|
</abp-modal> |
||||
|
``` |
||||
|
|
||||
|
Open `app.component.ts` in `src/app` folder and modify it as shown below: |
||||
|
|
||||
|
```js |
||||
|
import { AddReplaceableComponent } from '@abp/ng.core'; |
||||
|
import { ePermissionManagementComponents } from '@abp/ng.permission-management'; |
||||
|
import { Component, OnInit } from '@angular/core'; |
||||
|
import { Store } from '@ngxs/store'; |
||||
|
import { PermissionManagementComponent } from './permission-management/permission-management.component'; |
||||
|
|
||||
|
//... |
||||
|
export class AppComponent implements OnInit { |
||||
|
constructor(private store: Store) {} // injected store |
||||
|
|
||||
|
ngOnInit() { |
||||
|
// added dispatching the AddReplaceableComponent action |
||||
|
this.store.dispatch( |
||||
|
new AddReplaceableComponent({ |
||||
|
component: PermissionManagementComponent, |
||||
|
key: ePermissionManagementComponents.PermissionManagement, |
||||
|
}) |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
## See Also |
||||
|
|
||||
|
- [Component Replacement](./Component-Replacement.md) |
||||
|
After Width: | Height: | Size: 252 KiB |
Loading…
Reference in new issue