@ -0,0 +1,23 @@ | |||
import { NgModule } from '@angular/core'; | |||
import { CommonModule } from '@angular/common'; | |||
import { IdentityModule } from '@abp/ng.identity'; | |||
import { TableModule } from 'primeng/table'; | |||
import { ButtonModule } from 'primeng/button'; | |||
import { CustomRolesComponent } from './custom-roles/custom-roles.component'; | |||
@NgModule({ | |||
declarations: [], | |||
imports: [ | |||
CommonModule, | |||
IdentityModule, | |||
TableModule, | |||
ButtonModule, | |||
CustomRolesComponent | |||
], | |||
exports:[ | |||
CustomRolesComponent | |||
] | |||
}) | |||
export class CustomIdentityModule { } |
@ -0,0 +1,78 @@ | |||
<abp-page [title]="'AbpIdentity::Roles' | abpLocalization" [toolbar]="data.items"> | |||
<div id="identity-roles-wrapper" class="card"> | |||
<div class="card-body"> | |||
<!-- <abp-extensible-table | |||
[data]="data.items" | |||
[recordsTotal]="data.totalCount" | |||
[list]="list" | |||
></abp-extensible-table> --> | |||
<div class="flex justify-content-between align-items-center mb-3"> | |||
<button pButton icon="pi pi-plus" label="Add Roles" class="p-button-success" (click)="add()"></button> | |||
</div> | |||
<p-table [value]="data.items" [paginator]="true" [rows]="5" responsiveLayout="scroll"> | |||
<ng-template pTemplate="header"> | |||
<tr> | |||
<th pSortableColumn="name">name <p-sortIcon field="name"></p-sortIcon></th> | |||
<th>Actions</th> | |||
</tr> | |||
</ng-template> | |||
<ng-template pTemplate="body" let-role> | |||
<tr> | |||
<td>{{ role.name }}</td> | |||
<td> | |||
<button pButton icon="pi pi-pencil" class="p-button-text p-button-primary" (click)="edit(role.id)"></button> | |||
<button pButton icon="pi pi-trash" class="p-button-text p-button-danger" (click)="delete(role.id,role.name)"></button> | |||
<button pButton icon="pi pi-external-link" class="p-button-text p-button-success" (click)="openPermissionsModal(role.name)"></button> | |||
</td> | |||
</tr> | |||
</ng-template> | |||
</p-table> | |||
</div> | |||
</div> | |||
<abp-modal [(visible)]="isModalVisible" [busy]="modalBusy"> | |||
<ng-template #abpHeader> | |||
<h3>{{ (selected?.id ? 'AbpIdentity::Edit' : 'AbpIdentity::NewRole') | abpLocalization }}</h3> | |||
</ng-template> | |||
<ng-template #abpBody> | |||
<form [formGroup]="form" (ngSubmit)="save()" validateOnSubmit> | |||
<abp-extensible-form [selectedRecord]="selected"></abp-extensible-form> | |||
</form> | |||
</ng-template> | |||
<ng-template #abpFooter> | |||
<button type="button" class="btn btn-outline-primary" abpClose> | |||
{{ 'AbpIdentity::Cancel' | abpLocalization }} | |||
</button> | |||
<abp-button iconClass="fa fa-check" [disabled]="form?.invalid" (click)="save()">{{ | |||
'AbpIdentity::Save' | abpLocalization | |||
}}</abp-button> | |||
</ng-template> | |||
</abp-modal> | |||
<abp-permission-management | |||
#abpPermissionManagement="abpPermissionManagement" | |||
*abpReplaceableTemplate=" | |||
{ | |||
inputs: { | |||
providerName: { value: 'R' }, | |||
providerKey: { value: providerKey }, | |||
visible: { value: visiblePermissions, twoWay: true }, | |||
hideBadges: { value: true } | |||
}, | |||
outputs: { visibleChange: onVisiblePermissionChange }, | |||
componentKey: permissionManagementKey | |||
}; | |||
let init = initTemplate | |||
" | |||
(abpInit)="init(abpPermissionManagement)" | |||
> | |||
</abp-permission-management> | |||
</abp-page> | |||
@ -0,0 +1,23 @@ | |||
import { ComponentFixture, TestBed } from '@angular/core/testing'; | |||
import { CustomRolesComponent } from './custom-roles.component'; | |||
describe('CustomRolesComponent', () => { | |||
let component: CustomRolesComponent; | |||
let fixture: ComponentFixture<CustomRolesComponent>; | |||
beforeEach(async () => { | |||
await TestBed.configureTestingModule({ | |||
imports: [CustomRolesComponent] | |||
}) | |||
.compileComponents(); | |||
fixture = TestBed.createComponent(CustomRolesComponent); | |||
component = fixture.componentInstance; | |||
fixture.detectChanges(); | |||
}); | |||
it('should create', () => { | |||
expect(component).toBeTruthy(); | |||
}); | |||
}); |
@ -0,0 +1,162 @@ | |||
import { | |||
ExtensibleModule, | |||
EXTENSIONS_IDENTIFIER, | |||
FormPropData, | |||
generateFormFromProps, | |||
} from '@abp/ng.components/extensible'; | |||
import { PageModule } from '@abp/ng.components/page'; | |||
import { | |||
CoreModule, | |||
ListResultDto, | |||
ListService, | |||
LocalizationModule, | |||
PagedAndSortedResultRequestDto, | |||
PagedResultDto, | |||
} from '@abp/ng.core'; | |||
import { IdentityRoleDto, IdentityRoleService } from '@abp/ng.identity/proxy'; | |||
import { | |||
ThemeSharedModule, | |||
ConfirmationService, | |||
ToasterService, | |||
Confirmation, | |||
} from '@abp/ng.theme.shared'; | |||
import { CommonModule } from '@angular/common'; | |||
import { Component, inject, Injector, OnInit } from '@angular/core'; | |||
import { FormsModule, UntypedFormGroup } from '@angular/forms'; | |||
import { ButtonModule } from 'primeng/button'; | |||
import { TableModule } from 'primeng/table'; | |||
import { finalize } from 'rxjs'; | |||
import { ePermissionManagementComponents } from '@abp/ng.permission-management'; | |||
import { NgxDatatableModule } from '@swimlane/ngx-datatable'; | |||
import { eIdentityComponents } from '@abp/ng.identity'; | |||
import { PermissionManagementModule } from '@abp/ng.permission-management'; | |||
import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap'; | |||
@Component({ | |||
selector: 'app-custom-roles', | |||
standalone: true, | |||
imports: [ | |||
CommonModule, | |||
FormsModule, | |||
TableModule, | |||
ButtonModule, | |||
PageModule, | |||
LocalizationModule, | |||
ThemeSharedModule, | |||
NgxDatatableModule, | |||
ExtensibleModule, | |||
PermissionManagementModule, | |||
CoreModule, | |||
NgbNavModule | |||
], | |||
templateUrl: './custom-roles.component.html', | |||
providers: [ | |||
ListService, | |||
{ | |||
provide: EXTENSIONS_IDENTIFIER, | |||
useValue: eIdentityComponents.Roles, | |||
}, | |||
], | |||
styleUrl: './custom-roles.component.scss', | |||
}) | |||
export class CustomRolesComponent implements OnInit { | |||
protected readonly list = inject(ListService<PagedAndSortedResultRequestDto>); | |||
protected readonly confirmationService = inject(ConfirmationService); | |||
protected readonly toasterService = inject(ToasterService); | |||
private readonly injector = inject(Injector); | |||
protected readonly service = inject(IdentityRoleService); | |||
data: PagedResultDto<IdentityRoleDto> = { items: [], totalCount: 0 }; | |||
form!: UntypedFormGroup; | |||
selected?: IdentityRoleDto; | |||
isModalVisible!: boolean; | |||
visiblePermissions = false; | |||
providerKey?: string; | |||
modalBusy = false; | |||
permissionManagementKey = ePermissionManagementComponents.PermissionManagement; | |||
onVisiblePermissionChange = (event: boolean) => { | |||
this.visiblePermissions = event; | |||
}; | |||
ngOnInit() { | |||
this.hookToQuery(); | |||
} | |||
buildForm() { | |||
const data = new FormPropData(this.injector, this.selected); | |||
this.form = generateFormFromProps(data); | |||
} | |||
openModal() { | |||
this.buildForm(); | |||
this.isModalVisible = true; | |||
} | |||
add() { | |||
this.selected = {} as IdentityRoleDto; | |||
this.openModal(); | |||
} | |||
edit(id: string) { | |||
debugger | |||
this.service.get(id).subscribe(res => { | |||
this.selected = res; | |||
this.openModal(); | |||
}); | |||
} | |||
save() { | |||
if (!this.form.valid) return; | |||
this.modalBusy = true; | |||
const { id } = this.selected || {}; | |||
(id | |||
? this.service.update(id, { ...this.selected, ...this.form.value }) | |||
: this.service.create(this.form.value) | |||
) | |||
.pipe(finalize(() => (this.modalBusy = false))) | |||
.subscribe(() => { | |||
this.isModalVisible = false; | |||
this.toasterService.success('AbpUi::SavedSuccessfully'); | |||
this.list.get(); | |||
}); | |||
} | |||
delete(id: string, name: string) { | |||
this.confirmationService | |||
.warn('AbpIdentity::RoleDeletionConfirmationMessage', 'AbpIdentity::AreYouSure', { | |||
messageLocalizationParams: [name], | |||
}) | |||
.subscribe((status: Confirmation.Status) => { | |||
if (status === Confirmation.Status.confirm) { | |||
this.toasterService.success('AbpUi::DeletedSuccessfully'); | |||
this.service.delete(id).subscribe(() => this.list.get()); | |||
} | |||
}); | |||
} | |||
private hookToQuery() { | |||
this.list.hookToQuery(query => this.service.getList(query)).subscribe(res => (this.data = res)); | |||
} | |||
openPermissionsModal(providerKey: string) { | |||
this.providerKey = providerKey; | |||
setTimeout(() => { | |||
this.visiblePermissions = true; | |||
}, 0); | |||
} | |||
sort(data: any) { | |||
const { prop, dir } = data.sorts[0]; | |||
this.list.sortKey = prop; | |||
this.list.sortOrder = dir; | |||
} | |||
} |
@ -0,0 +1,147 @@ | |||
<!-- <div> | |||
<h3>Total Users: {{ data.totalCount }}</h3> | |||
<ul> | |||
<li *ngFor="let user of data.items"> | |||
<strong>{{ user.userName }}</strong> ({{ user.email }}) | |||
</li> | |||
</ul> | |||
</div> --> | |||
<abp-page [title]="'AbpIdentity::Users' | abpLocalization" [toolbar]="data.items"> | |||
<div id="identity-roles-wrapper" class="card"> | |||
<div class="card-body"> | |||
<div id="data-tables-table-filter" class="data-tables-filter mb-3"> | |||
<div class="flex justify-content-between align-items-center mb-3"> | |||
<button pButton icon="pi pi-plus" label="Add User" class="p-button-success" (click)="add()"></button> | |||
</div> | |||
<div class="input-group"> | |||
<input | |||
type="search" | |||
class="form-control" | |||
[placeholder]="'AbpUi::PagerSearch' | abpLocalization" | |||
[(ngModel)]="list.filter" | |||
/> | |||
</div> | |||
</div> | |||
<!-- | |||
<abp-extensible-table | |||
[data]="data.items" | |||
[recordsTotal]="data.totalCount" | |||
[list]="list" | |||
></abp-extensible-table> --> | |||
<p-table [value]="data.items" [paginator]="true" [rows]="5" responsiveLayout="scroll"> | |||
<ng-template pTemplate="header"> | |||
<tr> | |||
<th pSortableColumn="userName">Username <p-sortIcon field="userName"></p-sortIcon></th> | |||
<th pSortableColumn="name">First Name <p-sortIcon field="name"></p-sortIcon></th> | |||
<th pSortableColumn="surname">Last Name <p-sortIcon field="surname"></p-sortIcon></th> | |||
<th pSortableColumn="email">Email <p-sortIcon field="email"></p-sortIcon></th> | |||
<th>Status</th> | |||
<th>Actions</th> | |||
</tr> | |||
</ng-template> | |||
<ng-template pTemplate="body" let-user> | |||
<tr> | |||
<td>{{ user.userName }}</td> | |||
<td>{{ user.name }}</td> | |||
<td>{{ user.surname }}</td> | |||
<td>{{ user.email }}</td> | |||
<td> | |||
<p-tag [value]="user.isActive ? 'Active' : 'Inactive'" [severity]="user.isActive ? 'success' : 'danger'"></p-tag> | |||
</td> | |||
<td> | |||
<button pButton icon="pi pi-pencil" class="p-button-text p-button-primary" (click)="edit(user.id)"></button> | |||
<button pButton icon="pi pi-trash" class="p-button-text p-button-danger" (click)="delete(user.id,user.userName)"></button> | |||
<button pButton icon="pi pi-external-link" class="p-button-text p-button-success" (click)="openPermissionsModal(user.name,user.name)"></button> | |||
</td> | |||
</tr> | |||
</ng-template> | |||
</p-table> | |||
</div> | |||
</div> | |||
<abp-modal [(visible)]="isModalVisible" [busy]="modalBusy"> | |||
<ng-template #abpHeader> | |||
<h3>{{ (selected?.id ? 'AbpIdentity::Edit' : 'AbpIdentity::NewUser') | abpLocalization }}</h3> | |||
</ng-template> | |||
<ng-template #abpBody> | |||
@if (form) { | |||
<form [formGroup]="form" (ngSubmit)="save()"> | |||
<ul ngbNav #nav="ngbNav" class="nav-tabs"> | |||
<li ngbNavItem> | |||
<a ngbNavLink>{{ 'AbpIdentity::UserInformations' | abpLocalization }}</a> | |||
<ng-template ngbNavContent> | |||
<abp-extensible-form [selectedRecord]="selected"></abp-extensible-form> | |||
</ng-template> | |||
</li> | |||
<li ngbNavItem> | |||
<a ngbNavLink>{{ 'AbpIdentity::Roles' | abpLocalization }}</a> | |||
<ng-template ngbNavContent> | |||
@for (roleGroup of roleGroups; track $index; let i = $index) { | |||
<div class="form-check mb-2"> | |||
<abp-checkbox | |||
*abpReplaceableTemplate="{ | |||
inputs: { | |||
checkboxId: 'roles-' + i, | |||
label: roles[i].name, | |||
formControl: roleGroup.controls[roles[i].name] | |||
}, | |||
componentKey: inputKey | |||
}" | |||
[checkboxId]="'roles-' + i" | |||
[formControl]="roleGroup.controls[roles[i].name]" | |||
[label]="roles[i].name" | |||
> | |||
</abp-checkbox> | |||
</div> | |||
} | |||
</ng-template> | |||
</li> | |||
</ul> | |||
<div class="mt-2 fade-in-top" [ngbNavOutlet]="nav"></div> | |||
</form> | |||
} @else { | |||
<div class="text-center"><i class="fa fa-pulse fa-spinner" aria-hidden="true"></i></div> | |||
} | |||
</ng-template> | |||
<ng-template #abpFooter> | |||
<button type="button" class="btn btn-outline-primary" abpClose> | |||
{{ 'AbpIdentity::Cancel' | abpLocalization }} | |||
</button> | |||
<abp-button iconClass="fa fa-check" [disabled]="form?.invalid" (click)="save()">{{ | |||
'AbpIdentity::Save' | abpLocalization | |||
}}</abp-button> | |||
</ng-template> | |||
</abp-modal> | |||
<abp-permission-management | |||
#abpPermissionManagement="abpPermissionManagement" | |||
*abpReplaceableTemplate=" | |||
{ | |||
inputs: { | |||
providerName: { value: 'U' }, | |||
providerKey: { value: providerKey }, | |||
visible: { value: visiblePermissions, twoWay: true } | |||
}, | |||
outputs: { visibleChange: onVisiblePermissionChange }, | |||
componentKey: permissionManagementKey | |||
}; | |||
let init = initTemplate | |||
" | |||
[entityDisplayName]="entityDisplayName" | |||
(abpInit)="init(abpPermissionManagement)" | |||
> | |||
</abp-permission-management> | |||
</abp-page> | |||
@ -0,0 +1,23 @@ | |||
import { ComponentFixture, TestBed } from '@angular/core/testing'; | |||
import { CustomUsersComponent } from './custom-users.component'; | |||
describe('CustomUsersComponent', () => { | |||
let component: CustomUsersComponent; | |||
let fixture: ComponentFixture<CustomUsersComponent>; | |||
beforeEach(async () => { | |||
await TestBed.configureTestingModule({ | |||
imports: [CustomUsersComponent] | |||
}) | |||
.compileComponents(); | |||
fixture = TestBed.createComponent(CustomUsersComponent); | |||
component = fixture.componentInstance; | |||
fixture.detectChanges(); | |||
}); | |||
it('should create', () => { | |||
expect(component).toBeTruthy(); | |||
}); | |||
}); |
@ -0,0 +1,211 @@ | |||
import { FormPropData,EXTENSIONS_IDENTIFIER ,generateFormFromProps, ExtensibleModule} from '@abp/ng.components/extensible'; | |||
import { PageModule } from '@abp/ng.components/page'; | |||
import { CoreModule, ListResultDto, ListService, LocalizationModule, PagedResultDto } from '@abp/ng.core'; | |||
import { eIdentityComponents } from '@abp/ng.identity'; | |||
import { GetIdentityUsersInput, IdentityRoleDto, IdentityUserDto, IdentityUserService } from '@abp/ng.identity/proxy'; | |||
import { CommonModule } from '@angular/common'; | |||
import { Component, inject, Injector, OnInit, TemplateRef, TrackByFunction, ViewChild } from '@angular/core'; | |||
import { AbstractControl, FormsModule, UntypedFormArray, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; | |||
import { ButtonModule } from 'primeng/button'; | |||
import { TableModule } from 'primeng/table'; | |||
import { Confirmation, eFormComponets, ThemeSharedModule,ToasterService ,ConfirmationService} from '@abp/ng.theme.shared'; | |||
import { finalize, switchMap, tap } from 'rxjs'; | |||
import { ePermissionManagementComponents, PermissionManagementModule } from '@abp/ng.permission-management'; | |||
import { NgxDatatableModule } from '@swimlane/ngx-datatable'; | |||
import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap'; | |||
import { PaginatorModule } from 'primeng/paginator'; | |||
import { TagModule } from 'primeng/tag'; // For active/inactive status | |||
@Component({ | |||
selector: 'app-custom-users', | |||
standalone: true, | |||
imports: [CommonModule,FormsModule,TableModule,ButtonModule,PageModule,LocalizationModule,ThemeSharedModule,NgxDatatableModule,ExtensibleModule, | |||
PermissionManagementModule, | |||
CoreModule, | |||
NgbNavModule, | |||
PaginatorModule,TagModule | |||
], | |||
templateUrl: './custom-users.component.html', | |||
providers: [ | |||
ListService, | |||
{ | |||
provide: EXTENSIONS_IDENTIFIER, | |||
useValue: eIdentityComponents.Users, | |||
}, | |||
], | |||
styleUrl: './custom-users.component.scss' | |||
}) | |||
export class CustomUsersComponent implements OnInit{ | |||
protected readonly list = inject(ListService<GetIdentityUsersInput>); | |||
protected readonly confirmationService = inject(ConfirmationService); | |||
protected readonly service = inject(IdentityUserService); | |||
protected readonly toasterService = inject(ToasterService); | |||
private readonly fb = inject(UntypedFormBuilder); | |||
private readonly injector = inject(Injector); | |||
data: PagedResultDto<IdentityUserDto> = { items: [], totalCount: 0 }; | |||
@ViewChild('modalContent', { static: false }) | |||
modalContent!: TemplateRef<any>; | |||
form!: UntypedFormGroup; | |||
selected?: IdentityUserDto; | |||
selectedUserRoles?: IdentityRoleDto[]; | |||
roles?: IdentityRoleDto[]; | |||
visiblePermissions = false; | |||
providerKey?: string; | |||
isModalVisible?: boolean; | |||
modalBusy = false; | |||
permissionManagementKey = ePermissionManagementComponents.PermissionManagement; | |||
entityDisplayName: string; | |||
inputKey = eFormComponets.FormCheckboxComponent; | |||
trackByFn: TrackByFunction<AbstractControl> = (index, item) => Object.keys(item)[0] || index; | |||
onVisiblePermissionChange = (event: boolean) => { | |||
this.visiblePermissions = event; | |||
}; | |||
get roleGroups(): UntypedFormGroup[] { | |||
return ((this.form.get('roleNames') as UntypedFormArray)?.controls as UntypedFormGroup[]) || []; | |||
} | |||
ngOnInit() { | |||
this.hookToQuery(); | |||
} | |||
buildForm() { | |||
debugger | |||
const data = new FormPropData(this.injector, this.selected); | |||
this.form = generateFormFromProps(data); | |||
this.service.getAssignableRoles().subscribe(({ items }) => { | |||
this.roles = items; | |||
if (this.roles) { | |||
this.form.addControl( | |||
'roleNames', | |||
this.fb.array( | |||
this.roles.map(role => | |||
this.fb.group({ | |||
[role.name as string]: [ | |||
this.selected?.id | |||
? !!this.selectedUserRoles?.find(userRole => userRole.id === role.id) | |||
: role.isDefault, | |||
], | |||
}), | |||
), | |||
), | |||
); | |||
} | |||
}); | |||
} | |||
openModal() { | |||
this.buildForm(); | |||
this.isModalVisible = true; | |||
} | |||
add() { | |||
debugger | |||
this.selected = {} as IdentityUserDto; | |||
this.selectedUserRoles = [] as IdentityRoleDto[]; | |||
this.openModal(); | |||
} | |||
edit(id: string) { | |||
debugger | |||
this.service | |||
.get(id) | |||
.pipe( | |||
tap(user => (this.selected = user)), | |||
switchMap(() => this.service.getRoles(id)), | |||
) | |||
.subscribe(userRole => { | |||
debugger | |||
this.selectedUserRoles = userRole.items || []; | |||
this.openModal(); | |||
}); | |||
} | |||
save() { | |||
if (!this.form.valid || this.modalBusy) return; | |||
this.modalBusy = true; | |||
const { roleNames = [] } = this.form.value; | |||
const mappedRoleNames = | |||
roleNames | |||
.filter((role: { [key: string]: any }) => !!role[Object.keys(role)[0]]) | |||
.map((role: { [key: string]: any }) => Object.keys(role)[0]) || []; | |||
const { id } = this.selected || {}; | |||
(id | |||
? this.service.update(id, { | |||
...this.selected, | |||
...this.form.value, | |||
roleNames: mappedRoleNames, | |||
}) | |||
: this.service.create({ ...this.form.value, roleNames: mappedRoleNames }) | |||
) | |||
.pipe(finalize(() => (this.modalBusy = false))) | |||
.subscribe(() => { | |||
this.isModalVisible = false; | |||
this.toasterService.success('AbpUi::SavedSuccessfully'); | |||
this.list.get(); | |||
}); | |||
} | |||
delete(id: string, userName: string) { | |||
this.confirmationService | |||
.warn('AbpIdentity::UserDeletionConfirmationMessage', 'AbpIdentity::AreYouSure', { | |||
messageLocalizationParams: [userName], | |||
}) | |||
.subscribe((status: Confirmation.Status) => { | |||
if (status === Confirmation.Status.confirm) { | |||
this.service.delete(id).subscribe(() => { | |||
this.toasterService.success('AbpUi::DeletedSuccessfully'); | |||
this.list.get(); | |||
}); | |||
} | |||
}); | |||
} | |||
sort(data: any) { | |||
const { prop, dir } = data.sorts[0]; | |||
this.list.sortKey = prop; | |||
this.list.sortOrder = dir; | |||
} | |||
// private hookToQuery() { | |||
// this.list.hookToQuery(query => this.service.getList(query)).subscribe(res => (this.data = res)); | |||
// } | |||
private hookToQuery() { | |||
this.list.hookToQuery(query => { | |||
console.log('Query:', query); // Log the query | |||
return this.service.getList(query); | |||
}).subscribe(res => { | |||
debugger | |||
this.data = res; | |||
}); | |||
} | |||
openPermissionsModal(providerKey: string, entityDisplayName?: string) { | |||
debugger | |||
this.providerKey = providerKey; | |||
this.entityDisplayName = entityDisplayName; | |||
setTimeout(() => { | |||
this.visiblePermissions = true; | |||
}, 0); | |||
} | |||
} |