Skip to content

Commit a04d093

Browse files
committed
UserManagement Feature: Issue Number 54 [Angular]
* Tenants * Users * Roles Listings have Edit/Delete/ToggleActive on an action menu, refresh at top right. * Added IsActive and Description to Role * Angular paged-listing-component-base to implement for paging * jquery.validate to show errors before submission if possible (unique ie, username etc require callbacks to be coded) * ngx-paginate for paging * Implements the AsyncCrudAppService but uses the Management classes for Create/Update/Delete Uses base service for Get and GetAll. Feels like there should be an AsyncReadOnlyAppService that implements Get and GetAll in the base. Then more complex situations that use management classes and additional methods could be layered over the top without feeling like your going against the intent of the original classes. TODO: Add: Separate Modal required to edit a users password. Fix: Messy Mappings in ApplicationModule, Add a class for the map Check: Service Interfaces and inheritance Check: Sorting issue in AsyncCrudServiceBaseClass
1 parent e157927 commit a04d093

File tree

53 files changed

+5725
-575
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+5725
-575
lines changed

angular/.angular-cli.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@
7272
"../node_modules/abp-web-resources/Abp/Framework/scripts/libs/abp.sweet-alert.js",
7373
"../node_modules/abp-web-resources/Abp/Framework/scripts/libs/abp.moment.js",
7474
"../src/bsb-theme/js/admin.js",
75-
"../src/bsb-theme/js/demo.js"
75+
"../src/bsb-theme/js/demo.js",
76+
"../src/bsb-theme/js/jquery.validate.js"
7677
],
7778
"environmentSource": "environments/environment.ts",
7879
"environments": {

angular/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"@types/bootstrap": "^3.3.33",
2626
"@types/jquery": "^2.0.41",
2727
"@types/jquery.blockui": "0.0.27",
28+
"@types/jquery.validation": "^1.16.3",
2829
"@types/lodash": "^4.14.62",
2930
"@types/moment": "^2.13.0",
3031
"@types/moment-timezone": "^0.2.34",
@@ -53,6 +54,7 @@
5354
"moment-timezone": "^0.5.13",
5455
"morris.js": "^0.5.0",
5556
"ngx-bootstrap": "^1.6.6",
57+
"ngx-pagination": "^3.0.0",
5658
"node-waves": "^0.7.5",
5759
"push.js": "0.0.12",
5860
"raphael": "^2.2.7",

angular/src/app/app-routing.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { HomeComponent } from './home/home.component';
66
import { AboutComponent } from './about/about.component';
77
import { UsersComponent } from './users/users.component';
88
import { TenantsComponent } from './tenants/tenants.component';
9+
import { RolesComponent } from "app/roles/roles.component";
910

1011
@NgModule({
1112
imports: [
@@ -16,6 +17,7 @@ import { TenantsComponent } from './tenants/tenants.component';
1617
children: [
1718
{ path: 'home', component: HomeComponent, canActivate: [AppRouteGuard] },
1819
{ path: 'users', component: UsersComponent, data: { permission: 'Pages.Users' }, canActivate: [AppRouteGuard] },
20+
{ path: 'roles', component: RolesComponent, data: { permission: 'Pages.Roles' }, canActivate: [AppRouteGuard] },
1921
{ path: 'tenants', component: TenantsComponent, data: { permission: 'Pages.Tenants' }, canActivate: [AppRouteGuard] },
2022
{ path: 'about', component: AboutComponent }
2123
]

angular/src/app/app.module.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { FormsModule } from '@angular/forms';
44
import { HttpModule, JsonpModule } from '@angular/http';
55

66
import { ModalModule } from 'ngx-bootstrap';
7+
import { NgxPaginationModule } from 'ngx-pagination';
78

89
import { AppRoutingModule } from './app-routing.module';
910
import { AppComponent } from './app.component';
@@ -16,9 +17,14 @@ import { SharedModule } from '@shared/shared.module';
1617
import { HomeComponent } from '@app/home/home.component';
1718
import { AboutComponent } from '@app/about/about.component';
1819
import { UsersComponent } from '@app/users/users.component';
19-
import { CreateUserModalComponent } from '@app/users/create-user-modal.component';
20+
import { CreateUserComponent } from '@app/users/create-user/create-user.component';
21+
import { EditUserComponent } from './users/edit-user/edit-user.component';
22+
import { RolesComponent } from '@app/roles/roles.component';
23+
import { CreateRoleComponent } from '@app/roles/create-role/create-role.component';
24+
import { EditRoleComponent } from './roles/edit-role/edit-role.component';
2025
import { TenantsComponent } from '@app/tenants/tenants.component';
21-
import { CreateTenantModalComponent } from '@app/tenants/create-tenant-modal.component';
26+
import { CreateTenantComponent } from './tenants/create-tenant/create-tenant.component';
27+
import { EditTenantComponent } from './tenants/edit-tenant/edit-tenant.component';
2228
import { TopBarComponent } from '@app/layout/topbar.component';
2329
import { TopBarLanguageSwitchComponent } from '@app/layout/topbar-languageswitch.component';
2430
import { SideBarUserAreaComponent } from '@app/layout/sidebar-user-area.component';
@@ -31,16 +37,22 @@ import { RightSideBarComponent } from '@app/layout/right-sidebar.component';
3137
AppComponent,
3238
HomeComponent,
3339
AboutComponent,
34-
UsersComponent,
35-
CreateUserModalComponent,
3640
TenantsComponent,
37-
CreateTenantModalComponent,
41+
CreateTenantComponent,
42+
EditTenantComponent,
43+
UsersComponent,
44+
CreateUserComponent,
45+
EditUserComponent,
46+
RolesComponent,
47+
CreateRoleComponent,
48+
EditRoleComponent,
3849
TopBarComponent,
3950
TopBarLanguageSwitchComponent,
4051
SideBarUserAreaComponent,
4152
SideBarNavComponent,
4253
SideBarFooterComponent,
4354
RightSideBarComponent
55+
4456
],
4557
imports: [
4658
CommonModule,
@@ -51,7 +63,8 @@ import { RightSideBarComponent } from '@app/layout/right-sidebar.component';
5163
AbpModule,
5264
AppRoutingModule,
5365
ServiceProxyModule,
54-
SharedModule
66+
SharedModule,
67+
NgxPaginationModule
5568
],
5669
providers: [
5770

angular/src/app/layout/sidebar-nav.component.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@ export class SideBarNavComponent extends AppComponentBase {
1111

1212
menuItems: MenuItem[] = [
1313
new MenuItem(this.l("HomePage"), "", "home", "/app/home"),
14+
1415
new MenuItem(this.l("Tenants"), "Pages.Tenants", "business", "/app/tenants"),
1516
new MenuItem(this.l("Users"), "Pages.Users", "people", "/app/users"),
17+
new MenuItem(this.l("Roles"), "Pages.Roles", "local_offer", "/app/roles"),
1618
new MenuItem(this.l("About"), "", "info", "/app/about"),
19+
1720
new MenuItem(this.l("MultiLevelMenu"), "", "menu", "", [
1821
new MenuItem("ASP.NET Boilerplate", "", "", "", [
1922
new MenuItem("Home", "", "", "https://aspnetboilerplate.com"),
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<div bsModal #createRoleModal="bs-modal" class="modal fade" (onShown)="onShown()" tabindex="-1" role="dialog" aria-labelledby="createRoleModal" aria-hidden="true" [config]="{backdrop: 'static'}">
2+
<div class="modal-dialog">
3+
4+
<div #modalContent class="modal-content">
5+
6+
<form *ngIf="active" #createRoleForm="ngForm" id="frm_create_role" novalidate (ngSubmit)="save()">
7+
8+
<div class="modal-header">
9+
<button type="button" class="close" (click)="close()" aria-label="Close">
10+
<span aria-hidden="true">&times;</span>
11+
</button>
12+
<h4 class="modal-title">
13+
<span>{{l("CreateNewRole")}}</span>
14+
</h4>
15+
</div>
16+
<div class="modal-body">
17+
<ul class="nav nav-tabs tab-nav-right" role="tablist">
18+
<li role="presentation" class="active"><a href="#role-details" data-toggle="tab">Role Details</a></li>
19+
<li role="presentation"><a href="#role-description" data-toggle="tab">Role Description</a></li>
20+
</ul>
21+
<div class="tab-content">
22+
<div role="tabpanel" class="tab-pane animated fadeIn active" id="role-details">
23+
24+
<div class="row clearfix" style="margin-top:20px;">
25+
<div class="col-sm-6">
26+
<div class="form-group form-float">
27+
<div class="form-line">
28+
<input id="rolename" type="text" name="RoleName" [(ngModel)]="role.name" required maxlength="32" minlength="2" class="validate form-control">
29+
<label for="username" class="form-label">{{l("RoleName")}}</label>
30+
</div>
31+
</div>
32+
</div>
33+
<div class="col-sm-6">
34+
<div class="form-group form-float">
35+
<div class="">
36+
<input id="isactive" type="checkbox" name="IsActive" [(ngModel)]="role.isActive" checked class="form-control"/>
37+
<label for="isactive" class="form-label">{{l("IsActive")}}</label>
38+
</div>
39+
</div>
40+
</div>
41+
</div>
42+
43+
<div class="row clearfix" style="margin-top:20px;">
44+
<div class="col-sm-12">
45+
<div class="form-group form-float">
46+
<div class="form-line">
47+
<input id="displayname" type="text" name="DisplayName" [(ngModel)]="role.displayName" required maxlength="32" minlength="2" class="validate form-control">
48+
<label for="displayname" class="form-label">{{l("DisplayName")}}</label>
49+
</div>
50+
</div>
51+
</div>
52+
</div>
53+
54+
<div class="row clearfix">
55+
<div class="col-sm-12">
56+
<fieldset class="show-fieldset col s12">
57+
<legend class="show-legend">Permissions</legend>
58+
59+
<ng-template ngFor let-permission [ngForOf]="permissions.items" let-permissionIndex="index">
60+
<div class="col-sm-6">
61+
<input type="checkbox" name="permission" value="{{permission.name}}" class="filled-in" id="permission-{{permissionIndex}}" checked="checked" />
62+
<label for="permission-{{permissionIndex}}">{{permission.displayName}}</label>
63+
</div>
64+
</ng-template>
65+
</fieldset>
66+
</div>
67+
</div>
68+
</div>
69+
<div role="tabpanel" class="tab-pane animated fadeIn" id="role-description">
70+
71+
<div class="row" style="margin-top:20px;">
72+
<div class="col-sm-12">
73+
<div class="form-group form-float">
74+
<div class="form-line">
75+
<textarea id="role-description" name="Description" [(ngModel)]="role.description" required class="validate form-control"></textarea>
76+
<label for="role-description" class="form-label">Role Description</label>
77+
</div>
78+
</div>
79+
</div>
80+
</div>
81+
82+
</div>
83+
</div>
84+
</div>
85+
<div class="modal-footer">
86+
<button [disabled]="saving" type="button" class="btn btn-default waves-effect" (click)="close()">
87+
<i class="material-icons">clear</i>{{l("Cancel")}}
88+
</button>
89+
<button [disabled]="!createRoleForm.form.valid || saving" type="submit" class="btn btn-primary waves-effect">
90+
<i class="material-icons">check</i>{{l("Save")}}
91+
</button>
92+
</div>
93+
94+
</form>
95+
</div>
96+
</div>
97+
</div>
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { Component, ViewChild, Injector, Output, EventEmitter, ElementRef, OnInit } from '@angular/core';
2+
import { ModalDirective } from 'ngx-bootstrap';
3+
import { RoleServiceProxy, CreateRoleDto, RoleDto, ListResultDtoOfPermissionDto } from '@shared/service-proxies/service-proxies';
4+
import { AppComponentBase } from '@shared/app-component-base';
5+
6+
@Component({
7+
selector: 'create-role-modal',
8+
templateUrl: './create-role.component.html'
9+
})
10+
export class CreateRoleComponent extends AppComponentBase implements OnInit {
11+
@ViewChild('createRoleModal') modal: ModalDirective;
12+
@ViewChild('modalContent') modalContent: ElementRef;
13+
14+
active: boolean = false;
15+
saving: boolean = false;
16+
17+
permissions: ListResultDtoOfPermissionDto = null;
18+
role: CreateRoleDto = null;
19+
20+
@Output() modalSave: EventEmitter<any> = new EventEmitter<any>();
21+
constructor(
22+
injector: Injector,
23+
private _roleService: RoleServiceProxy
24+
) {
25+
super(injector);
26+
}
27+
28+
ngOnInit(): void {
29+
this._roleService.getAllPermissions()
30+
.subscribe((permissions:ListResultDtoOfPermissionDto) =>
31+
{
32+
this.permissions = permissions;
33+
console.log(permissions);
34+
});
35+
}
36+
37+
show(): void {
38+
this.active = true;
39+
this.modal.show();
40+
this.role = new CreateRoleDto({isStatic:false,
41+
description:'',
42+
isActive:false,
43+
name:''});
44+
45+
// // shouldn't have to do this!
46+
// this.role.description = "";
47+
// this.role.isActive = false;
48+
// this.role.name = "";
49+
}
50+
51+
onShown(): void {
52+
($ as any).AdminBSB.input.activate($(this.modalContent.nativeElement));
53+
54+
$('#frm_create_role').validate({
55+
highlight: function (input) {
56+
$(input).parents('.form-line').addClass('error');
57+
},
58+
unhighlight: function (input) {
59+
$(input).parents('.form-line').removeClass('error');
60+
},
61+
errorPlacement: function (error, element) {
62+
$(element).parents('.form-group').append(error);
63+
}
64+
});
65+
}
66+
67+
save(): void {
68+
var permissions = [];
69+
$(this.modalContent.nativeElement).find("[name=permission]").each(
70+
function( index:number, elem: Element){
71+
if($(elem).is(":checked") == true){
72+
permissions.push(elem.getAttribute("value").valueOf());
73+
}
74+
}
75+
)
76+
77+
this.role.permissions = permissions;
78+
this.saving = true;
79+
this._roleService.create(this.role)
80+
.finally(() => { this.saving = false; })
81+
.subscribe(() => {
82+
this.notify.info(this.l('SavedSuccessfully'));
83+
this.close();
84+
this.modalSave.emit(null);
85+
});
86+
}
87+
88+
close(): void {
89+
this.active = false;
90+
this.modal.hide();
91+
}
92+
}

0 commit comments

Comments
 (0)