diff --git a/angular/package.json b/angular/package.json
index 8c576f9..36084b1 100644
--- a/angular/package.json
+++ b/angular/package.json
@@ -20,7 +20,7 @@
"@abp/ng.setting-management": "~9.0.2",
"@abp/ng.tenant-management": "~9.0.2",
"@abp/ng.theme.lepton-x": "~4.0.3",
- "@abp/ng.theme.shared": "~9.0.2",
+ "@abp/ng.theme.shared": "^9.0.4",
"@angular/animations": "~18.1.0",
"@angular/common": "~18.1.0",
"@angular/compiler": "~18.1.0",
@@ -30,6 +30,7 @@
"@angular/platform-browser": "~18.1.0",
"@angular/platform-browser-dynamic": "~18.1.0",
"@angular/router": "~18.1.0",
+ "@swimlane/ngx-datatable": "^20.1.0",
"bootstrap-icons": "~1.8.0",
"primeflex": "^3.3.1",
"primeicons": "^6.0.1",
diff --git a/angular/src/app/app-routing.module.ts b/angular/src/app/app-routing.module.ts
index d7050db..344da08 100644
--- a/angular/src/app/app-routing.module.ts
+++ b/angular/src/app/app-routing.module.ts
@@ -1,5 +1,7 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
+import { CustomUsersComponent } from './modules/custom-identity/custom-users/custom-users.component';
+import { CustomRolesComponent } from './modules/custom-identity/custom-roles/custom-roles.component';
const routes: Routes = [
{
@@ -11,10 +13,12 @@ const routes: Routes = [
path: 'account',
loadChildren: () => import('@abp/ng.account').then(m => m.AccountModule.forLazy()),
},
- {
- path: 'identity',
- loadChildren: () => import('@abp/ng.identity').then(m => m.IdentityModule.forLazy()),
- },
+ { path: 'identity/users', component: CustomUsersComponent },
+ { path: 'identity/roles', component: CustomRolesComponent },
+ // {
+ // path: 'identity',
+ // loadChildren: () => import('@abp/ng.identity').then(m => m.IdentityModule.forLazy()),
+ // },
{
path: 'tenant-management',
loadChildren: () =>
diff --git a/angular/src/app/modules/custom-identity/custom-identity.module.ts b/angular/src/app/modules/custom-identity/custom-identity.module.ts
new file mode 100644
index 0000000..f84eb9b
--- /dev/null
+++ b/angular/src/app/modules/custom-identity/custom-identity.module.ts
@@ -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 { }
diff --git a/angular/src/app/modules/custom-identity/custom-roles/custom-roles.component.html b/angular/src/app/modules/custom-identity/custom-roles/custom-roles.component.html
new file mode 100644
index 0000000..acf212d
--- /dev/null
+++ b/angular/src/app/modules/custom-identity/custom-roles/custom-roles.component.html
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+ name |
+
+ Actions |
+
+
+
+
+
+ {{ role.name }} |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ {{ (selected?.id ? 'AbpIdentity::Edit' : 'AbpIdentity::NewRole') | abpLocalization }}
+
+
+
+
+
+
+
+
+ {{
+ 'AbpIdentity::Save' | abpLocalization
+ }}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/angular/src/app/modules/custom-identity/custom-roles/custom-roles.component.scss b/angular/src/app/modules/custom-identity/custom-roles/custom-roles.component.scss
new file mode 100644
index 0000000..e69de29
diff --git a/angular/src/app/modules/custom-identity/custom-roles/custom-roles.component.spec.ts b/angular/src/app/modules/custom-identity/custom-roles/custom-roles.component.spec.ts
new file mode 100644
index 0000000..dcb56ce
--- /dev/null
+++ b/angular/src/app/modules/custom-identity/custom-roles/custom-roles.component.spec.ts
@@ -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;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [CustomRolesComponent]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(CustomRolesComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/angular/src/app/modules/custom-identity/custom-roles/custom-roles.component.ts b/angular/src/app/modules/custom-identity/custom-roles/custom-roles.component.ts
new file mode 100644
index 0000000..693138f
--- /dev/null
+++ b/angular/src/app/modules/custom-identity/custom-roles/custom-roles.component.ts
@@ -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);
+ protected readonly confirmationService = inject(ConfirmationService);
+ protected readonly toasterService = inject(ToasterService);
+ private readonly injector = inject(Injector);
+ protected readonly service = inject(IdentityRoleService);
+
+ data: PagedResultDto = { 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;
+ }
+}
diff --git a/angular/src/app/modules/custom-identity/custom-users/custom-users.component.html b/angular/src/app/modules/custom-identity/custom-users/custom-users.component.html
new file mode 100644
index 0000000..f37936d
--- /dev/null
+++ b/angular/src/app/modules/custom-identity/custom-users/custom-users.component.html
@@ -0,0 +1,147 @@
+
+
+
+
+
+
+
+
+
+
+
+ Username |
+ First Name |
+ Last Name |
+ Email |
+ Status |
+ Actions |
+
+
+
+
+
+ {{ user.userName }} |
+ {{ user.name }} |
+ {{ user.surname }} |
+ {{ user.email }} |
+
+
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+ {{ (selected?.id ? 'AbpIdentity::Edit' : 'AbpIdentity::NewUser') | abpLocalization }}
+
+
+
+ @if (form) {
+
+ } @else {
+
+ }
+
+
+
+
+ {{
+ 'AbpIdentity::Save' | abpLocalization
+ }}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/angular/src/app/modules/custom-identity/custom-users/custom-users.component.scss b/angular/src/app/modules/custom-identity/custom-users/custom-users.component.scss
new file mode 100644
index 0000000..e69de29
diff --git a/angular/src/app/modules/custom-identity/custom-users/custom-users.component.spec.ts b/angular/src/app/modules/custom-identity/custom-users/custom-users.component.spec.ts
new file mode 100644
index 0000000..5bb528b
--- /dev/null
+++ b/angular/src/app/modules/custom-identity/custom-users/custom-users.component.spec.ts
@@ -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;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [CustomUsersComponent]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(CustomUsersComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/angular/src/app/modules/custom-identity/custom-users/custom-users.component.ts b/angular/src/app/modules/custom-identity/custom-users/custom-users.component.ts
new file mode 100644
index 0000000..b42e136
--- /dev/null
+++ b/angular/src/app/modules/custom-identity/custom-users/custom-users.component.ts
@@ -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);
+ 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 = { items: [], totalCount: 0 };
+
+ @ViewChild('modalContent', { static: false })
+ modalContent!: TemplateRef;
+
+ 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 = (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);
+ }
+}
diff --git a/angular/src/app/route.provider.ts b/angular/src/app/route.provider.ts
index 7a54ae8..dae1844 100644
--- a/angular/src/app/route.provider.ts
+++ b/angular/src/app/route.provider.ts
@@ -7,6 +7,7 @@ export const APP_ROUTE_PROVIDER = [
function configureRoutes(routesService: RoutesService) {
return () => {
+
routesService.add([
{
path: '/',
@@ -15,6 +16,7 @@ function configureRoutes(routesService: RoutesService) {
order: 1,
layout: eLayoutType.application,
},
+
{
path: '/appointment',
name: 'Appointments',