Browse Source

Merge pull request #1556 from abpframework/feature/globalize-modal

feature: generalize modal component
pull/1565/head
Yasin Aydın 7 years ago
committed by GitHub
parent
commit
f5756309f5
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      npm/ng-packs/.prettierrc
  2. 2
      npm/ng-packs/packages/core/src/lib/states/config.state.ts
  3. 40
      npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.html
  4. 16
      npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.ts
  5. 205
      npm/ng-packs/packages/identity/src/lib/components/users/users.component.html
  6. 46
      npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts
  7. 2
      npm/ng-packs/packages/identity/src/lib/identity.module.ts
  8. 29
      npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.html
  9. 56
      npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts
  10. 96
      npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.html
  11. 121
      npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.ts
  12. 10
      npm/ng-packs/packages/tenant-management/src/lib/services/tenant-management.service.ts
  13. 38
      npm/ng-packs/packages/theme-basic/src/lib/components/change-password/change-password.component.html
  14. 45
      npm/ng-packs/packages/theme-basic/src/lib/components/change-password/change-password.component.ts
  15. 19
      npm/ng-packs/packages/theme-basic/src/lib/components/layout-application/layout-application.component.html
  16. 40
      npm/ng-packs/packages/theme-basic/src/lib/components/profile/profile.component.html
  17. 65
      npm/ng-packs/packages/theme-basic/src/lib/components/profile/profile.component.ts
  18. 2
      npm/ng-packs/packages/theme-shared/src/lib/components/modal/modal.component.ts
  19. 3
      npm/ng-packs/packages/theme-shared/src/lib/contants/styles.ts

5
npm/ng-packs/.prettierrc

@ -0,0 +1,5 @@
{
"printWidth": 120,
"singleQuote": true,
"trailingComma": "all"
}

2
npm/ng-packs/packages/core/src/lib/states/config.state.ts

@ -107,6 +107,8 @@ export class ConfigState {
} }
static getCopy(key: string, ...interpolateParams: string[]) { static getCopy(key: string, ...interpolateParams: string[]) {
if (!key) key = '';
const keys = key.split('::') as string[]; const keys = key.split('::') as string[];
const selector = createSelector( const selector = createSelector(
[ConfigState], [ConfigState],

40
npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.html

@ -58,17 +58,13 @@
</div> </div>
</div> </div>
<ng-template #modalContent let-modal> <abp-modal size="md" [(visible)]="isModalVisible" *ngIf="isModalVisible" [centered]="true">
<div class="modal-header"> <ng-template #abpHeader>
<h5 class="modal-title" id="modal-basic-title"> <h3>{{ (selected?.id ? 'AbpIdentity::Edit' : 'AbpIdentity::NewRole') | abpLocalization }}</h3>
{{ (selected?.id ? 'AbpIdentity::Edit' : 'AbpIdentity::NewRole') | abpLocalization }} </ng-template>
</h5>
<button type="button" class="close" aria-label="Close" (click)="modal.dismiss()"> <ng-template #abpBody>
<span aria-hidden="true">&times;</span> <form [formGroup]="form">
</button>
</div>
<form [formGroup]="form" (ngSubmit)="save()">
<div class="modal-body">
<div class="form-group"> <div class="form-group">
<label for="role-name">{{ 'AbpIdentity::RoleName' | abpLocalization }}</label <label for="role-name">{{ 'AbpIdentity::RoleName' | abpLocalization }}</label
><span> * </span> ><span> * </span>
@ -88,18 +84,18 @@
'AbpIdentity::DisplayName:IsPublic' | abpLocalization 'AbpIdentity::DisplayName:IsPublic' | abpLocalization
}}</label> }}</label>
</div> </div>
</div> </form>
</ng-template>
<div class="modal-footer"> <ng-template #abpFooter>
<button type="button" class="btn btn-secondary" data-dismiss="modal" (click)="modal.close()"> <button type="button" class="btn btn-secondary" #abpClose>
{{ 'AbpIdentity::Cancel' | abpLocalization }} {{ 'AbpIdentity::Cancel' | abpLocalization }}
</button> </button>
<button type="submit" class="btn btn-primary"> <button type="button" class="btn btn-primary" (click)="save()">
<i class="fa fa-check mr-1"></i> <span>{{ 'AbpIdentity::Save' | abpLocalization }}</span> <i class="fa fa-check mr-1"></i> <span>{{ 'AbpIdentity::Save' | abpLocalization }}</span>
</button> </button>
</div> </ng-template>
</form> </abp-modal>
</ng-template>
<abp-permission-management <abp-permission-management
[(visible)]="visiblePermissions" [(visible)]="visiblePermissions"

16
npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.ts

@ -1,7 +1,6 @@
import { Component, TemplateRef, ViewChild } from '@angular/core'; import { Component, TemplateRef, ViewChild } from '@angular/core';
import { Select, Store } from '@ngxs/store'; import { Select, Store } from '@ngxs/store';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { IdentityState } from '../../states/identity.state'; import { IdentityState } from '../../states/identity.state';
import { Identity } from '../../models/identity'; import { Identity } from '../../models/identity';
@ -26,6 +25,8 @@ export class RolesComponent {
selected: Identity.RoleItem; selected: Identity.RoleItem;
isModalVisible: boolean;
visiblePermissions: boolean = false; visiblePermissions: boolean = false;
providerKey: string; providerKey: string;
@ -33,12 +34,7 @@ export class RolesComponent {
@ViewChild('modalContent', { static: false }) @ViewChild('modalContent', { static: false })
modalContent: TemplateRef<any>; modalContent: TemplateRef<any>;
constructor( constructor(private confirmationService: ConfirmationService, private fb: FormBuilder, private store: Store) {}
private confirmationService: ConfirmationService,
private modalService: NgbModal,
private fb: FormBuilder,
private store: Store,
) {}
createForm() { createForm() {
this.form = this.fb.group({ this.form = this.fb.group({
@ -50,7 +46,7 @@ export class RolesComponent {
openModal() { openModal() {
this.createForm(); this.createForm();
this.modalService.open(this.modalContent); this.isModalVisible = true;
} }
onAdd() { onAdd() {
@ -77,7 +73,9 @@ export class RolesComponent {
? new IdentityUpdateRole({ ...this.form.value, id: this.selected.id }) ? new IdentityUpdateRole({ ...this.form.value, id: this.selected.id })
: new IdentityAddRole(this.form.value), : new IdentityAddRole(this.form.value),
) )
.subscribe(() => this.modalService.dismissAll()); .subscribe(() => {
this.isModalVisible = false;
});
} }
delete(id: string, name: string) { delete(id: string, name: string) {

205
npm/ng-packs/packages/identity/src/lib/components/users/users.component.html

@ -77,119 +77,118 @@
</div> </div>
</div> </div>
<ng-template #modalContent let-modal> <abp-modal [(visible)]="isModalVisible" *ngIf="isModalVisible">
<div class="modal-header"> <ng-template #abpHeader>
<h5 class="modal-title" id="modal-basic-title"> <h3>{{ (selected?.id ? 'AbpIdentity::Edit' : 'AbpIdentity::NewUser') | abpLocalization }}</h3>
{{ (selected?.id ? 'AbpIdentity::Edit' : 'AbpIdentity::NewUser') | abpLocalization }} </ng-template>
</h5>
<button type="button" class="close" aria-label="Close" (click)="modal.dismiss()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form [formGroup]="form" (ngSubmit)="save()">
<div class="modal-body">
<ngb-tabset>
<ngb-tab [title]="'AbpIdentity::UserInformations' | abpLocalization">
<ng-template ngbTabContent>
<div class="mt-2">
<div class="form-group">
<label for="user-name">{{ 'AbpIdentity::UserName' | abpLocalization }}</label
><span> * </span>
<input type="text" id="user-name" class="form-control" formControlName="userName" />
</div>
<div class="form-group"> <ng-template #abpBody>
<label for="name">{{ 'AbpIdentity::Name' | abpLocalization }}</label> <perfect-scrollbar class="ps-show-always" style="max-height: 65vh;">
<input type="text" id="name" class="form-control" formControlName="name" /> <form [formGroup]="form">
</div> <ngb-tabset>
<ngb-tab [title]="'AbpIdentity::UserInformations' | abpLocalization">
<ng-template ngbTabContent>
<div class="mt-2">
<div class="form-group">
<label for="user-name">{{ 'AbpIdentity::UserName' | abpLocalization }}</label
><span> * </span>
<input type="text" id="user-name" class="form-control" formControlName="userName" />
</div>
<div class="form-group"> <div class="form-group">
<label for="surname">{{ 'AbpIdentity::DisplayName:Surname' | abpLocalization }}</label> <label for="name">{{ 'AbpIdentity::DisplayName:Name' | abpLocalization }}</label>
<input type="text" id="surname" class="form-control" formControlName="surname" /> <input type="text" id="name" class="form-control" formControlName="name" />
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="password">{{ 'AbpIdentity::Password' | abpLocalization }}</label <label for="surname">{{ 'AbpIdentity::DisplayName:Surname' | abpLocalization }}</label>
><span> * </span> <input type="text" id="surname" class="form-control" formControlName="surname" />
<input </div>
type="password"
id="password"
autocomplete="new-password"
class="form-control"
formControlName="password"
/>
</div>
<div class="form-group"> <div class="form-group">
<label for="email">{{ 'AbpIdentity::EmailAddress' | abpLocalization }}</label <label for="password">{{ 'AbpIdentity::Password' | abpLocalization }}</label
><span> * </span> ><span> * </span>
<input type="text" id="email" class="form-control" formControlName="email" /> <input
</div> type="password"
id="password"
autocomplete="new-password"
class="form-control"
formControlName="password"
/>
</div>
<div class="form-group"> <div class="form-group">
<label for="phone-number">{{ 'AbpIdentity::PhoneNumber' | abpLocalization }}</label> <label for="email">{{ 'AbpIdentity::EmailAddress' | abpLocalization }}</label
<input type="text" id="phone-number" class="form-control" formControlName="phoneNumber" /> ><span> * </span>
</div> <input type="text" id="email" class="form-control" formControlName="email" />
</div>
<div class="custom-checkbox custom-control mb-2"> <div class="form-group">
<input <label for="phone-number">{{ 'AbpIdentity::PhoneNumber' | abpLocalization }}</label>
type="checkbox" <input type="text" id="phone-number" class="form-control" formControlName="phoneNumber" />
id="lockout-checkbox" </div>
class="custom-control-input"
formControlName="lockoutEnabled"
/>
<label class="custom-control-label" for="lockout-checkbox">{{
'AbpIdentity::DisplayName:LockoutEnabled' | abpLocalization
}}</label>
</div>
<div class="custom-checkbox custom-control mb-2"> <div class="custom-checkbox custom-control mb-2">
<input <input
type="checkbox" type="checkbox"
id="two-factor-checkbox" id="lockout-checkbox"
class="custom-control-input" class="custom-control-input"
formControlName="twoFactorEnabled" formControlName="lockoutEnabled"
/> />
<label class="custom-control-label" for="two-factor-checkbox">{{ <label class="custom-control-label" for="lockout-checkbox">{{
'AbpIdentity::DisplayName:TwoFactorEnabled' | abpLocalization 'AbpIdentity::DisplayName:LockoutEnabled' | abpLocalization
}}</label> }}</label>
</div>
<div class="custom-checkbox custom-control mb-2">
<input
type="checkbox"
id="two-factor-checkbox"
class="custom-control-input"
formControlName="twoFactorEnabled"
/>
<label class="custom-control-label" for="two-factor-checkbox">{{
'AbpIdentity::DisplayName:TwoFactorEnabled' | abpLocalization
}}</label>
</div>
</div> </div>
</div> </ng-template>
</ng-template> </ngb-tab>
</ngb-tab> <ngb-tab [title]="'AbpIdentity::Roles' | abpLocalization">
<ngb-tab [title]="'AbpIdentity::Roles' | abpLocalization"> <ng-template ngbTabContent>
<ng-template ngbTabContent> <div class="mt-2">
<div class="mt-2"> <div
<div *ngFor="let roleGroup of roleGroups; let i = index; trackBy: trackByFn"
*ngFor="let roleGroup of roleGroups; let i = index; trackBy: trackByFn" class="custom-checkbox custom-control mb-2"
class="custom-checkbox custom-control mb-2" >
> <input
<input type="checkbox"
type="checkbox" name="Roles[0].IsAssigned"
name="Roles[0].IsAssigned" value="true"
value="true" class="custom-control-input"
class="custom-control-input" [attr.id]="'roles-' + i"
[attr.id]="'roles-' + i" [formControl]="roleGroup.controls[roles[i].name]"
[formControl]="roleGroup.controls[roles[i].name]" />
/> <label class="custom-control-label" [attr.for]="'roles-' + i">{{ roles[i].name }}</label>
<label class="custom-control-label" [attr.for]="'roles-' + i">{{ roles[i].name }}</label> </div>
</div> </div>
</div> </ng-template>
</ng-template> </ngb-tab>
</ngb-tab> </ngb-tabset>
</ngb-tabset> </form>
</div> </perfect-scrollbar>
</ng-template>
<ng-template #abpFooter>
<button type="button" class="btn btn-secondary" #abpClose>
{{ 'AbpIdentity::Cancel' | abpLocalization }}
</button>
<button type="button" class="btn btn-primary" (click)="save()">
<i class="fa fa-check mr-1"></i> <span>{{ 'AbpIdentity::Save' | abpLocalization }}</span>
</button>
</ng-template>
</abp-modal>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal" (click)="modal.close()">
{{ 'AbpIdentity::Cancel' | abpLocalization }}
</button>
<button type="submit" class="btn btn-primary">
<i class="fa fa-check mr-1"></i> <span>{{ 'AbpIdentity::Save' | abpLocalization }}</span>
</button>
</div>
</form>
</ng-template>
<abp-permission-management <abp-permission-management
[(visible)]="visiblePermissions" [(visible)]="visiblePermissions"
providerName="User" providerName="User"

46
npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts

@ -1,24 +1,22 @@
import { Component, TemplateRef, ViewChild, TrackByFunction, OnInit } from '@angular/core'; import { ABP } from '@abp/ng.core';
import { ConfirmationService, Toaster } from '@abp/ng.theme.shared';
import { Component, OnInit, TemplateRef, TrackByFunction, ViewChild } from '@angular/core';
import { AbstractControl, FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { validatePassword } from '@ngx-validate/core';
import { Select, Store } from '@ngxs/store'; import { Select, Store } from '@ngxs/store';
import { Observable, combineLatest, Subject } from 'rxjs'; import { combineLatest, Observable, Subject } from 'rxjs';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { debounceTime, filter, map, pluck, take } from 'rxjs/operators';
import { FormBuilder, FormGroup, Validators, FormArray, AbstractControl } from '@angular/forms'; import snq from 'snq';
import { IdentityState } from '../../states/identity.state';
import { Identity } from '../../models/identity';
import { import {
IdentityUpdateUser,
IdentityAddUser, IdentityAddUser,
IdentityDeleteUser, IdentityDeleteUser,
IdentityGetUserById, IdentityGetUserById,
IdentityGetUserRoles,
IdentityGetUsers, IdentityGetUsers,
IdentityUpdateUser,
} from '../../actions/identity.actions'; } from '../../actions/identity.actions';
import { pluck, filter, map, take, debounceTime } from 'rxjs/operators'; import { Identity } from '../../models/identity';
import { ConfirmationService, Toaster } from '@abp/ng.theme.shared'; import { IdentityState } from '../../states/identity.state';
import snq from 'snq';
import { IdentityGetUserRoles } from '../../actions/identity.actions';
import { validatePassword } from '@ngx-validate/core';
import { ABP } from '@abp/ng.core';
@Component({ @Component({
selector: 'abp-users', selector: 'abp-users',
templateUrl: './users.component.html', templateUrl: './users.component.html',
@ -49,6 +47,8 @@ export class UsersComponent implements OnInit {
sorting: 'userName', sorting: 'userName',
}; };
isModalVisible: boolean;
loading: boolean = false; loading: boolean = false;
search$ = new Subject<string>(); search$ = new Subject<string>();
@ -59,12 +59,7 @@ export class UsersComponent implements OnInit {
return snq(() => (this.form.get('roleNames') as FormArray).controls as FormGroup[], []); return snq(() => (this.form.get('roleNames') as FormArray).controls as FormGroup[], []);
} }
constructor( constructor(private confirmationService: ConfirmationService, private fb: FormBuilder, private store: Store) {}
private confirmationService: ConfirmationService,
private modalService: NgbModal,
private fb: FormBuilder,
private store: Store,
) {}
ngOnInit() { ngOnInit() {
this.search$.pipe(debounceTime(300)).subscribe(value => { this.search$.pipe(debounceTime(300)).subscribe(value => {
@ -105,7 +100,7 @@ export class UsersComponent implements OnInit {
openModal() { openModal() {
this.buildForm(); this.buildForm();
this.modalService.open(this.modalContent); this.isModalVisible = true;
} }
onAdd() { onAdd() {
@ -146,9 +141,14 @@ export class UsersComponent implements OnInit {
id: this.selected.id, id: this.selected.id,
roleNames: mappedRoleNames, roleNames: mappedRoleNames,
}) })
: new IdentityAddUser({ ...this.form.value, roleNames: mappedRoleNames }), : new IdentityAddUser({
...this.form.value,
roleNames: mappedRoleNames,
}),
) )
.subscribe(() => this.modalService.dismissAll()); .subscribe(() => {
this.isModalVisible = false;
});
} }
delete(id: string, userName: string) { delete(id: string, userName: string) {

2
npm/ng-packs/packages/identity/src/lib/identity.module.ts

@ -10,6 +10,7 @@ import { UsersComponent } from './components/users/users.component';
import { PermissionManagementModule } from '@abp/ng.permission-management'; import { PermissionManagementModule } from '@abp/ng.permission-management';
import { TableModule } from 'primeng/table'; import { TableModule } from 'primeng/table';
import { NgxValidateCoreModule } from '@ngx-validate/core'; import { NgxValidateCoreModule } from '@ngx-validate/core';
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
@NgModule({ @NgModule({
declarations: [RolesComponent, UsersComponent], declarations: [RolesComponent, UsersComponent],
@ -23,6 +24,7 @@ import { NgxValidateCoreModule } from '@ngx-validate/core';
NgbDropdownModule, NgbDropdownModule,
PermissionManagementModule, PermissionManagementModule,
NgxValidateCoreModule, NgxValidateCoreModule,
PerfectScrollbarModule,
], ],
}) })
export class IdentityModule {} export class IdentityModule {}

29
npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.html

@ -1,15 +1,9 @@
<ng-template #modalContent let-modal> <abp-modal [(visible)]="visible" *ngIf="visible" size="lg">
<ng-container *ngIf="{ entityName: entityName$ | async } as data"> <ng-container *ngIf="{ entityName: entityName$ | async } as data">
<div class="modal-header"> <ng-template #abpHeader>
<h4 class="modal-title" id="modal-basic-title"> <h4>{{ 'AbpPermissionManagement::Permissions' | abpLocalization }} - {{ data.entityName }}</h4>
{{ 'AbpPermissionManagement::Permissions' | abpLocalization }} - </ng-template>
{{ data.entityName }} <ng-template #abpBody>
</h4>
<button type="button" class="close" aria-label="Close" (click)="modal.dismiss()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="custom-checkbox custom-control mb-2"> <div class="custom-checkbox custom-control mb-2">
<input <input
type="checkbox" type="checkbox"
@ -31,7 +25,7 @@
<perfect-scrollbar class="ps-show-always" style="max-height: 70vh;"> <perfect-scrollbar class="ps-show-always" style="max-height: 70vh;">
<li *ngFor="let group of groups$ | async; trackBy: trackByFn" class="nav-item"> <li *ngFor="let group of groups$ | async; trackBy: trackByFn" class="nav-item">
<a class="nav-link" [class.active]="selectedGroup.name === group.name" (click)="onChangeGroup(group)">{{ <a class="nav-link" [class.active]="selectedGroup.name === group.name" (click)="onChangeGroup(group)">{{
group.displayName group?.displayName
}}</a> }}</a>
</li> </li>
</perfect-scrollbar> </perfect-scrollbar>
@ -80,15 +74,14 @@
</div> </div>
</div> </div>
</div> </div>
</div> </ng-template>
<ng-template #abpFooter>
<div class="modal-footer"> <button type="button" class="btn btn-secondary" #abpClose>
<button type="button" class="btn btn-secondary" data-dismiss="modal" (click)="modal.close()">
{{ 'AbpIdentity::Cancel' | abpLocalization }} {{ 'AbpIdentity::Cancel' | abpLocalization }}
</button> </button>
<button type="submit" class="btn btn-primary" (click)="onSubmit()"> <button type="submit" class="btn btn-primary" (click)="onSubmit()">
<i class="fa fa-check mr-1"></i> <span>{{ 'AbpIdentity::Save' | abpLocalization }}</span> <i class="fa fa-check mr-1"></i> <span>{{ 'AbpIdentity::Save' | abpLocalization }}</span>
</button> </button>
</div> </ng-template>
</ng-container> </ng-container>
</ng-template> </abp-modal>

56
npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts

@ -7,11 +7,8 @@ import {
Output, Output,
Renderer2, Renderer2,
SimpleChanges, SimpleChanges,
TemplateRef,
TrackByFunction, TrackByFunction,
ViewChild,
} from '@angular/core'; } from '@angular/core';
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
import { Select, Store } from '@ngxs/store'; import { Select, Store } from '@ngxs/store';
import { from, Observable } from 'rxjs'; import { from, Observable } from 'rxjs';
import { map, pluck, take } from 'rxjs/operators'; import { map, pluck, take } from 'rxjs/operators';
@ -35,23 +32,33 @@ export class PermissionManagementComponent implements OnInit, OnChanges {
@Input() @Input()
providerKey: string; providerKey: string;
protected _visible;
@Input() @Input()
visible: boolean; get visible(): boolean {
return this._visible;
}
set visible(value: boolean) {
if (!this.selectedGroup) return;
this._visible = value;
this.visibleChange.emit(value);
if (!value) {
this.selectedGroup = null;
}
}
@Output() @Output()
visibleChange = new EventEmitter<boolean>(); visibleChange = new EventEmitter<boolean>();
@ViewChild('modalContent', { static: false })
modalContent: TemplateRef<any>;
@Select(PermissionManagementState.getPermissionGroups) @Select(PermissionManagementState.getPermissionGroups)
groups$: Observable<PermissionManagement.Group[]>; groups$: Observable<PermissionManagement.Group[]>;
@Select(PermissionManagementState.getEntitiyDisplayName) @Select(PermissionManagementState.getEntitiyDisplayName)
entityName$: Observable<string>; entityName$: Observable<string>;
modalRef: NgbModalRef;
selectedGroup: PermissionManagement.Group; selectedGroup: PermissionManagement.Group;
permissions: PermissionManagement.Permission[] = []; permissions: PermissionManagement.Permission[] = [];
@ -80,7 +87,7 @@ export class PermissionManagementComponent implements OnInit, OnChanges {
); );
} }
constructor(private modalService: NgbModal, private store: Store, private renderer: Renderer2) {} constructor(private store: Store, private renderer: Renderer2) {}
ngOnInit(): void {} ngOnInit(): void {}
@ -186,9 +193,11 @@ export class PermissionManagementComponent implements OnInit, OnChanges {
permissions: changedPermissions, permissions: changedPermissions,
}), }),
) )
.subscribe(() => this.modalRef.close()); .subscribe(() => {
this.visible = false;
});
} else { } else {
this.modalRef.close(); this.visible = false;
} }
} }
@ -206,39 +215,22 @@ export class PermissionManagementComponent implements OnInit, OnChanges {
this.selectedGroup = permissionRes.groups[0]; this.selectedGroup = permissionRes.groups[0];
this.permissions = getPermissions(permissionRes.groups); this.permissions = getPermissions(permissionRes.groups);
this.modalRef = this.modalService.open(this.modalContent, { size: 'lg' }); this.visible = true;
this.visibleChange.emit(true);
setTimeout(() => { setTimeout(() => {
this.setTabCheckboxState(); this.setTabCheckboxState();
this.setGrantCheckboxState(); this.setGrantCheckboxState();
}, 0); }, 0);
from(this.modalRef.result)
.pipe(take(1))
.subscribe(
data => {
this.setVisible(false);
},
reason => {
this.setVisible(false);
},
);
}); });
} }
setVisible(value: boolean) {
this.visible = value;
this.visibleChange.emit(value);
}
ngOnChanges({ visible }: SimpleChanges): void { ngOnChanges({ visible }: SimpleChanges): void {
if (!visible) return; if (!visible) return;
if (visible.currentValue) { if (visible.currentValue) {
this.openModal(); this.openModal();
} else if (visible.currentValue === false && this.modalService.hasOpenModals()) { } else if (visible.currentValue === false && this.visible) {
this.modalRef.close(); this.visible = false;
} }
} }
} }

96
npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.html

@ -12,7 +12,7 @@
id="create-tenants" id="create-tenants"
class="btn btn-primary" class="btn btn-primary"
type="button" type="button"
(click)="onAdd()" (click)="onAddTenant()"
> >
<i class="fa fa-plus mr-1"></i> <i class="fa fa-plus mr-1"></i>
<span>{{ 'AbpTenantManagement::NewTenant' | abpLocalization }}</span> <span>{{ 'AbpTenantManagement::NewTenant' | abpLocalization }}</span>
@ -53,14 +53,14 @@
<button <button
[abpPermission]="'AbpTenantManagement.Tenants.Update'" [abpPermission]="'AbpTenantManagement.Tenants.Update'"
ngbDropdownItem ngbDropdownItem
(click)="onEdit(data.id)" (click)="onEditTenant(data.id)"
> >
{{ 'AbpTenantManagement::Edit' | abpLocalization }} {{ 'AbpTenantManagement::Edit' | abpLocalization }}
</button> </button>
<button <button
[abpPermission]="'AbpTenantManagement.Tenants.ManageConnectionStrings'" [abpPermission]="'AbpTenantManagement.Tenants.ManageConnectionStrings'"
ngbDropdownItem ngbDropdownItem
(click)="onEditConnStr(data.id)" (click)="onEditConnectionString(data.id)"
> >
{{ 'AbpTenantManagement::ConnectionStrings' | abpLocalization }} {{ 'AbpTenantManagement::ConnectionStrings' | abpLocalization }}
</button> </button>
@ -88,60 +88,62 @@
</div> </div>
</div> </div>
<ng-template #modalWrapper let-modal> <abp-modal [(visible)]="isModalVisible" *ngIf="isModalVisible">
<div class="modal-header"> <ng-template #abpHeader>
<h5 class="modal-title" id="modal-basic-title"> <h3>{{ selectedModalContent.title | abpLocalization }}</h3>
{{ selectedModalContent.title | abpLocalization }} </ng-template>
</h5>
<button type="button" class="close" aria-label="Close" (click)="modal.dismiss()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form [formGroup]="tenantForm" (ngSubmit)="selectedModalContent.onSave()"> <ng-template #abpBody>
<div class="modal-body"> <ng-container *ngTemplateOutlet="selectedModalContent?.template"></ng-container>
<ng-container *ngTemplateOutlet="selectedModalContent.template; context: { $implicit: modal }"></ng-container> </ng-template>
</div>
<div class="modal-footer"> <ng-template #abpFooter>
<button type="button" class="btn btn-secondary" data-dismiss="modal" (click)="modal.close()"> <button #abpClose type="button" class="btn btn-secondary">
{{ 'AbpTenantManagement::Cancel' | abpLocalization }} {{ 'AbpTenantManagement::Cancel' | abpLocalization }}
</button> </button>
<button type="submit" class="btn btn-primary"> <button class="btn btn-primary" type="button" (click)="save()">
<i class="fa fa-check mr-1"></i> <span>{{ 'AbpTenantManagement::Save' | abpLocalization }}</span> {{ 'AbpTenantManagement::Save' | abpLocalization }}
</button> </button>
</div> </ng-template>
</form> </abp-modal>
</ng-template>
<ng-template #mTemplateTenant let-modal> <ng-template #tenantModalTemplate>
<div class="mt-2"> <form [formGroup]="tenantForm">
<div class="form-group"> <div class="mt-2">
<label for="name">{{ 'AbpTenantManagement::TenantName' | abpLocalization }}</label> <div class="form-group">
<input type="text" id="name" class="form-control" formControlName="name" /> <label for="name">{{ 'AbpTenantManagement::TenantName' | abpLocalization }}</label>
<input type="text" id="name" class="form-control" formControlName="name" />
</div>
</div> </div>
</div> </form>
</ng-template> </ng-template>
<ng-template #mTemplateConnStr let-modal> <ng-template #connectionStringModalTemplate>
<div class="mt-2"> <form [formGroup]="defaultConnectionStringForm">
<div class="form-group"> <div class="mt-2">
<div class="form-check"> <div class="form-group">
<input id="useSharedDatabase" type="checkbox" class="form-check-input" formControlName="useSharedDatabase" /> <div class="form-check">
<label for="useSharedDatabase" class="font-check-label">{{ <input id="useSharedDatabase" type="checkbox" class="form-check-input" formControlName="useSharedDatabase" />
'AbpTenantManagement::DisplayName:UseSharedDatabase' | abpLocalization <label for="useSharedDatabase" class="font-check-label">{{
'AbpTenantManagement::DisplayName:UseSharedDatabase' | abpLocalization
}}</label>
</div>
</div>
<div class="form-group" *ngIf="!useSharedDatabase">
<label for="defaultConnectionString">{{
'AbpTenantManagement::DisplayName:DefaultConnectionString' | abpLocalization
}}</label> }}</label>
<input
type="text"
id="defaultConnectionString"
class="form-control"
formControlName="defaultConnectionString"
/>
</div> </div>
</div> </div>
<div class="form-group" *ngIf="showInput"> </form>
<label for="defaultConnectionString">{{
'AbpTenantManagement::DisplayName:DefaultConnectionString' | abpLocalization
}}</label>
<input type="text" id="defaultConnectionString" class="form-control" formControlName="defaultConnectionString" />
</div>
</div>
</ng-template> </ng-template>
<ng-template #mTemplateFeatures let-modal> <ng-template #featuresModalTemplate>
Manage Features Manage Features
</ng-template> </ng-template>

121
npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.ts

@ -2,7 +2,6 @@ import { ABP } from '@abp/ng.core';
import { ConfirmationService, Toaster } from '@abp/ng.theme.shared'; import { ConfirmationService, Toaster } from '@abp/ng.theme.shared';
import { Component, TemplateRef, ViewChild } from '@angular/core'; import { Component, TemplateRef, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { Select, Store } from '@ngxs/store'; import { Select, Store } from '@ngxs/store';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { pluck, switchMap, take } from 'rxjs/operators'; import { pluck, switchMap, take } from 'rxjs/operators';
@ -15,6 +14,12 @@ import {
import { TenantManagementService } from '../../services/tenant-management.service'; import { TenantManagementService } from '../../services/tenant-management.service';
import { TenantManagementState } from '../../states/tenant-management.state'; import { TenantManagementState } from '../../states/tenant-management.state';
type SelectedModalContent = {
type: string;
title: string;
template: TemplateRef<any>;
};
@Component({ @Component({
selector: 'abp-tenants', selector: 'abp-tenants',
templateUrl: './tenants.component.html', templateUrl: './tenants.component.html',
@ -31,46 +36,36 @@ export class TenantsComponent {
defaultConnectionString: string; defaultConnectionString: string;
useSharedDatabase: boolean; isModalVisible: boolean;
selectedModalContent = {} as SelectedModalContent;
selectedModalContent: { _useSharedDatabase: boolean;
title: string;
template: TemplateRef<any>;
onSave: () => void;
};
get showInput(): boolean { get useSharedDatabase(): boolean {
return !this.defaultConnectionStringForm.get('useSharedDatabase').value; return this.defaultConnectionStringForm.get('useSharedDatabase').value;
} }
get connectionString(): string { get connectionString(): string {
return this.defaultConnectionStringForm.get('defaultConnectionString').value; return this.defaultConnectionStringForm.get('defaultConnectionString').value;
} }
@ViewChild('modalWrapper', { static: false }) @ViewChild('tenantModalTemplate', { static: false })
modalWrapper: TemplateRef<any>; tenantModalTemplate: TemplateRef<any>;
@ViewChild('mTemplateConnStr', { static: false })
mTemplateConnStr: TemplateRef<any>;
@ViewChild('mTemplateFeatures', { static: false }) @ViewChild('connectionStringModalTemplate', { static: false })
mTemplateFeatures: TemplateRef<any>; connectionStringModalTemplate: TemplateRef<any>;
@ViewChild('mTemplateTenant', { static: false }) @ViewChild('featuresModalTemplate', { static: false })
mTemplateTenant: TemplateRef<any>; featuresModalTemplate: TemplateRef<any>;
constructor( constructor(
private confirmationService: ConfirmationService, private confirmationService: ConfirmationService,
private tenantService: TenantManagementService, private tenantService: TenantManagementService,
private modalService: NgbModal,
private fb: FormBuilder, private fb: FormBuilder,
private store: Store, private store: Store,
) {} ) {}
openModal() {
this.modalService.open(this.modalWrapper);
}
private createTenantForm() { private createTenantForm() {
this.tenantForm = this.fb.group({ this.tenantForm = this.fb.group({
name: [this.selected.name || '', [Validators.required, Validators.maxLength(256)]], name: [this.selected.name || '', [Validators.required, Validators.maxLength(256)]],
@ -79,17 +74,22 @@ export class TenantsComponent {
private createDefaultConnectionStringForm() { private createDefaultConnectionStringForm() {
this.defaultConnectionStringForm = this.fb.group({ this.defaultConnectionStringForm = this.fb.group({
useSharedDatabase: this.useSharedDatabase, useSharedDatabase: this._useSharedDatabase,
defaultConnectionString: this.defaultConnectionString || '', defaultConnectionString: this.defaultConnectionString || '',
}); });
} }
onEditConnStr(id: string) { openModal(title: string, template: TemplateRef<any>, type: string) {
this.selectedModalContent = { this.selectedModalContent = {
title: this.selected && this.selected.id ? 'AbpTenantManagement::Edit' : 'AbpTenantManagement::NewTenant', title,
template: this.mTemplateConnStr, template,
onSave: () => this.saveConnStr, type,
}; };
this.isModalVisible = true;
}
onEditConnectionString(id: string) {
this.store this.store
.dispatch(new TenantManagementGetById(id)) .dispatch(new TenantManagementGetById(id))
.pipe( .pipe(
@ -100,56 +100,59 @@ export class TenantsComponent {
}), }),
) )
.subscribe(fetchedConnectionString => { .subscribe(fetchedConnectionString => {
this.useSharedDatabase = fetchedConnectionString ? false : true; this._useSharedDatabase = fetchedConnectionString ? false : true;
this.defaultConnectionString = fetchedConnectionString ? fetchedConnectionString : ''; this.defaultConnectionString = fetchedConnectionString ? fetchedConnectionString : '';
this.createDefaultConnectionStringForm(); this.createDefaultConnectionStringForm();
this.openModal(); this.openModal('AbpTenantManagement::ConnectionStrings', this.connectionStringModalTemplate, 'saveConnStr');
}); });
} }
saveConnStr() {
this.tenantService
.updateDefaultConnectionString({ id: this.selected.id, defaultConnectionString: this.connectionString })
.pipe(take(1))
.subscribe(() => this.modalService.dismissAll());
}
onManageFeatures(id: string) { onManageFeatures(id: string) {
this.selectedModalContent = { this.openModal('AbpTenantManagement::Features', this.featuresModalTemplate, 'saveFeatures');
title: this.selected && this.selected.id ? 'AbpTenantManagement::Edit' : 'AbpTenantManagement::NewTenant',
template: this.mTemplateFeatures,
onSave: () => {},
};
this.openModal();
} }
onAdd() { onAddTenant() {
this.selected = {} as ABP.BasicItem; this.selected = {} as ABP.BasicItem;
this.createTenantForm(); this.createTenantForm();
this.openModal(); this.openModal('AbpTenantManagement::NewTenant', this.tenantModalTemplate, 'saveTenant');
this.selectedModalContent = {
title: 'AbpTenantManagement::NewTenant',
template: this.mTemplateTenant,
onSave: () => this.saveTenant,
};
} }
onEdit(id: string) { onEditTenant(id: string) {
this.store this.store
.dispatch(new TenantManagementGetById(id)) .dispatch(new TenantManagementGetById(id))
.pipe(pluck('TenantManagementState', 'selectedItem')) .pipe(pluck('TenantManagementState', 'selectedItem'))
.subscribe(selected => { .subscribe(selected => {
this.selected = selected; this.selected = selected;
this.selectedModalContent = {
title: 'AbpTenantManagement::Edit',
template: this.mTemplateTenant,
onSave: () => this.saveTenant,
};
this.createTenantForm(); this.createTenantForm();
this.openModal(); this.openModal('AbpTenantManagement::Edit', this.tenantModalTemplate, 'saveTenant');
}); });
} }
save() {
const { type } = this.selectedModalContent;
if (!type) return;
if (type === 'saveTenant') this.saveTenant();
else if (type === 'saveConnStr') this.saveConnectionString();
}
saveConnectionString() {
if (this.useSharedDatabase) {
this.tenantService
.deleteDefaultConnectionString(this.selected.id)
.pipe(take(1))
.subscribe(() => {
this.isModalVisible = false;
});
} else {
this.tenantService
.updateDefaultConnectionString({ id: this.selected.id, defaultConnectionString: this.connectionString })
.pipe(take(1))
.subscribe(() => {
this.isModalVisible = false;
});
}
}
saveTenant() { saveTenant() {
if (!this.tenantForm.valid) return; if (!this.tenantForm.valid) return;
@ -159,7 +162,9 @@ export class TenantsComponent {
? new TenantManagementUpdate({ ...this.tenantForm.value, id: this.selected.id }) ? new TenantManagementUpdate({ ...this.tenantForm.value, id: this.selected.id })
: new TenantManagementAdd(this.tenantForm.value), : new TenantManagementAdd(this.tenantForm.value),
) )
.subscribe(() => this.modalService.dismissAll()); .subscribe(() => {
this.isModalVisible = false;
});
} }
delete(id: string, name: string) { delete(id: string, name: string) {

10
npm/ng-packs/packages/tenant-management/src/lib/services/tenant-management.service.ts

@ -80,4 +80,14 @@ export class TenantManagementService {
}; };
return this.rest.request<TenantManagement.DefaultConnectionStringRequest, any>(request); return this.rest.request<TenantManagement.DefaultConnectionStringRequest, any>(request);
} }
deleteDefaultConnectionString(id: string): Observable<string> {
const url = `/api/multi-tenancy/tenant/${id}/defaultConnectionString`;
const request: Rest.Request<TenantManagement.DefaultConnectionStringRequest> = {
method: 'DELETE',
url,
};
return this.rest.request<TenantManagement.DefaultConnectionStringRequest, any>(request);
}
} }

38
npm/ng-packs/packages/theme-basic/src/lib/components/change-password/change-password.component.html

@ -1,12 +1,9 @@
<ng-template #modalContent let-modal> <abp-modal *ngIf="visible" [(visible)]="visible">
<div class="modal-header"> <ng-template #abpHeader>
<h4 class="modal-title" id="modal-basic-title">{{ 'AbpIdentity::ChangePassword' | abpLocalization }}</h4> <h4>{{ 'AbpIdentity::ChangePassword' | abpLocalization }}</h4>
<button type="button" class="close" aria-label="Close" (click)="modal.dismiss()"> </ng-template>
<span aria-hidden="true">&times;</span> <ng-template #abpBody>
</button> <form [formGroup]="form" novalidate>
</div>
<form [formGroup]="form" (ngSubmit)="onSubmit()" novalidate>
<div class="modal-body">
<div class="form-group"> <div class="form-group">
<label for="current-password">{{ 'AbpIdentity::DisplayName:CurrentPassword' | abpLocalization }}</label <label for="current-password">{{ 'AbpIdentity::DisplayName:CurrentPassword' | abpLocalization }}</label
><span> * </span><input type="password" id="current-password" class="form-control" formControlName="password" /> ><span> * </span><input type="password" id="current-password" class="form-control" formControlName="password" />
@ -23,15 +20,14 @@
{{ 'AbpIdentity::Identity.PasswordConfirmationFailed' | abpLocalization }} {{ 'AbpIdentity::Identity.PasswordConfirmationFailed' | abpLocalization }}
</div> </div>
</div> </div>
</div> </form>
</ng-template>
<div class="modal-footer"> <ng-template #abpFooter>
<button type="button" class="btn btn-secondary" data-dismiss="modal" (click)="modal.close()"> <button type="button" class="btn btn-secondary" #abpClose>
{{ 'AbpIdentity::Cancel' | abpLocalization }} {{ 'AbpIdentity::Cancel' | abpLocalization }}
</button> </button>
<button type="submit" class="btn btn-primary"> <button type="button" class="btn btn-primary" (click)="onSubmit()">
<i class="fa fa-check mr-1"></i> <span>{{ 'AbpIdentity::Save' | abpLocalization }}</span> <i class="fa fa-check mr-1"></i> <span>{{ 'AbpIdentity::Save' | abpLocalization }}</span>
</button> </button>
</div> </ng-template>
</form> </abp-modal>
</ng-template>

45
npm/ng-packs/packages/theme-basic/src/lib/components/change-password/change-password.component.ts

@ -11,11 +11,8 @@ import {
ViewChild, ViewChild,
} from '@angular/core'; } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { NgbActiveModal, NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
import { comparePasswords, validatePassword } from '@ngx-validate/core'; import { comparePasswords, validatePassword } from '@ngx-validate/core';
import { Store } from '@ngxs/store'; import { Store } from '@ngxs/store';
import { from } from 'rxjs';
import { take } from 'rxjs/operators';
const { minLength, required } = Validators; const { minLength, required } = Validators;
@ -24,8 +21,17 @@ const { minLength, required } = Validators;
templateUrl: './change-password.component.html', templateUrl: './change-password.component.html',
}) })
export class ChangePasswordComponent implements OnInit, OnChanges { export class ChangePasswordComponent implements OnInit, OnChanges {
protected _visible;
@Input() @Input()
visible: boolean; get visible(): boolean {
return this._visible;
}
set visible(value: boolean) {
this._visible = value;
this.visibleChange.emit(value);
}
@Output() @Output()
visibleChange = new EventEmitter<boolean>(); visibleChange = new EventEmitter<boolean>();
@ -35,9 +41,7 @@ export class ChangePasswordComponent implements OnInit, OnChanges {
form: FormGroup; form: FormGroup;
modalRef: NgbModalRef; constructor(private fb: FormBuilder, private store: Store) {}
constructor(private fb: FormBuilder, private modalService: NgbModal, private store: Store) {}
ngOnInit(): void { ngOnInit(): void {
this.form = this.fb.group( this.form = this.fb.group(
@ -62,28 +66,13 @@ export class ChangePasswordComponent implements OnInit, OnChanges {
newPassword: this.form.get('newPassword').value, newPassword: this.form.get('newPassword').value,
}), }),
) )
.subscribe(() => this.modalRef.close()); .subscribe(() => {
this.visible = false;
});
} }
openModal() { openModal() {
this.modalRef = this.modalService.open(this.modalContent); this.visible = true;
this.visibleChange.emit(true);
from(this.modalRef.result)
.pipe(take(1))
.subscribe(
data => {
this.setVisible(false);
},
reason => {
this.setVisible(false);
},
);
}
setVisible(value: boolean) {
this.visible = value;
this.visibleChange.emit(value);
} }
ngOnChanges({ visible }: SimpleChanges): void { ngOnChanges({ visible }: SimpleChanges): void {
@ -91,8 +80,8 @@ export class ChangePasswordComponent implements OnInit, OnChanges {
if (visible.currentValue) { if (visible.currentValue) {
this.openModal(); this.openModal();
} else if (visible.currentValue === false && this.modalService.hasOpenModals()) { } else if (visible.currentValue === false && this.visible) {
this.modalRef.close(); this.visible = false;
} }
} }
} }

19
npm/ng-packs/packages/theme-basic/src/lib/components/layout-application/layout-application.component.html

@ -9,14 +9,20 @@
<ng-template #defaultLink let-route> <ng-template #defaultLink let-route>
<li class="nav-item" [abpPermission]="route.requiredPolicy"> <li class="nav-item" [abpPermission]="route.requiredPolicy">
<a class="nav-link" [routerLink]="[route.url]">{{ route.name }}</a> <a class="nav-link" [routerLink]="[route.url]">{{ route.name | abpLocalization }}</a>
</li> </li>
</ng-template> </ng-template>
<ng-template #dropdownLink let-route> <ng-template #dropdownLink let-route>
<li class="nav-item dropdown" ngbDropdown [abpPermission]="route.requiredPolicy" [abpVisibility]="routeContainer"> <li
class="nav-item dropdown"
ngbDropdown
display="static"
[abpPermission]="route.requiredPolicy"
[abpVisibility]="routeContainer"
>
<a ngbDropdownToggle class="nav-link dropdown-toggle" data-toggle="dropdown"> <a ngbDropdownToggle class="nav-link dropdown-toggle" data-toggle="dropdown">
{{ route.name }} {{ route.name | abpLocalization }}
</a> </a>
<div #routeContainer ngbDropdownMenu class="dropdown-menu dropdown-menu-right"> <div #routeContainer ngbDropdownMenu class="dropdown-menu dropdown-menu-right">
<ng-template <ng-template
@ -39,7 +45,7 @@
<ng-template #defaultChild let-child> <ng-template #defaultChild let-child>
<div class="dropdown-submenu" [abpPermission]="child.requiredPolicy"> <div class="dropdown-submenu" [abpPermission]="child.requiredPolicy">
<a class="dropdown-item py-2 px-2" [routerLink]="[child.url]">{{ child.name }}</a> <a class="dropdown-item py-2 px-2" [routerLink]="[child.url]">{{ child.name | abpLocalization }}</a>
</div> </div>
</ng-template> </ng-template>
@ -48,10 +54,13 @@
[abpVisibility]="childrenContainer" [abpVisibility]="childrenContainer"
class="dropdown-submenu" class="dropdown-submenu"
ngbDropdown ngbDropdown
display="static"
placement="right-top" placement="right-top"
[abpPermission]="child.requiredPolicy" [abpPermission]="child.requiredPolicy"
> >
<a role="button" class="btn d-block text-left py-2 px-2" ngbDropdownToggle> {{ child.name }} </a> <a role="button" class="btn d-block text-left py-2 px-2" ngbDropdownToggle>
{{ child.name | abpLocalization }}
</a>
<div #childrenContainer ngbDropdownMenu class="dropdown-menu dropdown-menu-right"> <div #childrenContainer ngbDropdownMenu class="dropdown-menu dropdown-menu-right">
<ng-template <ng-template
ngFor ngFor

40
npm/ng-packs/packages/theme-basic/src/lib/components/profile/profile.component.html

@ -1,12 +1,9 @@
<ng-template #modalContent let-modal> <abp-modal *ngIf="visible" [(visible)]="visible">
<div class="modal-header"> <ng-template #abpHeader>
<h4 class="modal-title" id="modal-basic-title">{{ 'AbpIdentity::PersonalInfo' | abpLocalization }}</h4> <h4>{{ 'AbpIdentity::PersonalInfo' | abpLocalization }}</h4>
<button type="button" class="close" aria-label="Close" (click)="modal.dismiss()"> </ng-template>
<span aria-hidden="true">&times;</span> <ng-template #abpBody>
</button> <form *ngIf="form" [formGroup]="form" novalidate>
</div>
<form *ngIf="form" [formGroup]="form" (ngSubmit)="onSubmit()" novalidate>
<div class="modal-body">
<div class="form-group"> <div class="form-group">
<label for="username">{{ 'AbpIdentity::DisplayName:UserName' | abpLocalization }}</label <label for="username">{{ 'AbpIdentity::DisplayName:UserName' | abpLocalization }}</label
><span> * </span><input type="text" id="username" class="form-control" formControlName="userName" /> ><span> * </span><input type="text" id="username" class="form-control" formControlName="userName" />
@ -26,22 +23,21 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="email-address">{{ 'AbpIdentity::DisplayName:EmailAddress' | abpLocalization }}</label <label for="email-address">{{ 'AbpIdentity::DisplayName:Email' | abpLocalization }}</label
><span> * </span><input type="text" id="email-address" class="form-control" formControlName="email" /> ><span> * </span><input type="text" id="email-address" class="form-control" formControlName="email" />
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="phone-number">{{ 'AbpIdentity::DisplayName:PhoneNumber' | abpLocalization }}</label <label for="phone-number">{{ 'AbpIdentity::DisplayName:PhoneNumber' | abpLocalization }}</label
><input type="text" id="phone-number" class="form-control" formControlName="phoneNumber" /> ><input type="text" id="phone-number" class="form-control" formControlName="phoneNumber" />
</div> </div>
</div> </form>
</ng-template>
<div class="modal-footer"> <ng-template #abpFooter>
<button type="button" class="btn btn-secondary" data-dismiss="modal" (click)="modal.close()"> <button #abpClose type="button" class="btn btn-secondary">
{{ 'AbpIdentity::Cancel' | abpLocalization }} {{ 'AbpIdentity::Cancel' | abpLocalization }}
</button> </button>
<button type="submit" class="btn btn-primary"> <button type="button" class="btn btn-primary" (click)="onSubmit()">
<i class="fa fa-check mr-1"></i> <span>{{ 'AbpIdentity::Save' | abpLocalization }}</span> <i class="fa fa-check mr-1"></i> <span>{{ 'AbpIdentity::Save' | abpLocalization }}</span>
</button> </button>
</div> </ng-template>
</form> </abp-modal>
</ng-template>

65
npm/ng-packs/packages/theme-basic/src/lib/components/profile/profile.component.ts

@ -1,20 +1,9 @@
import { import { Profile, ProfileGet, ProfileState, ProfileUpdate } from '@abp/ng.core';
Component, import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
EventEmitter,
Input,
OnChanges,
OnInit,
Output,
SimpleChanges,
TemplateRef,
ViewChild,
} from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; import { Select, Store } from '@ngxs/store';
import { Store, Select } from '@ngxs/store'; import { Observable } from 'rxjs';
import { from, Observable } from 'rxjs';
import { take, withLatestFrom } from 'rxjs/operators'; import { take, withLatestFrom } from 'rxjs/operators';
import { ProfileGet, ProfileState, Profile, ProfileUpdate } from '@abp/ng.core';
const { maxLength, required, email } = Validators; const { maxLength, required, email } = Validators;
@ -23,23 +12,27 @@ const { maxLength, required, email } = Validators;
templateUrl: './profile.component.html', templateUrl: './profile.component.html',
}) })
export class ProfileComponent implements OnChanges { export class ProfileComponent implements OnChanges {
protected _visible;
@Input() @Input()
visible: boolean; get visible(): boolean {
return this._visible;
}
set visible(value: boolean) {
this._visible = value;
this.visibleChange.emit(value);
}
@Output() @Output()
visibleChange = new EventEmitter<boolean>(); visibleChange = new EventEmitter<boolean>();
@ViewChild('modalContent', { static: false })
modalContent: TemplateRef<any>;
@Select(ProfileState.getProfile) @Select(ProfileState.getProfile)
profile$: Observable<Profile.Response>; profile$: Observable<Profile.Response>;
form: FormGroup; form: FormGroup;
modalRef: NgbModalRef; constructor(private fb: FormBuilder, private store: Store) {}
constructor(private fb: FormBuilder, private modalService: NgbModal, private store: Store) {}
buildForm() { buildForm() {
this.store this.store
@ -62,30 +55,14 @@ export class ProfileComponent implements OnChanges {
onSubmit() { onSubmit() {
if (this.form.invalid) return; if (this.form.invalid) return;
this.store.dispatch(new ProfileUpdate(this.form.value)).subscribe(() => this.modalRef.close()); this.store.dispatch(new ProfileUpdate(this.form.value)).subscribe(() => {
this.visible = false;
});
} }
openModal() { openModal() {
this.buildForm(); this.buildForm();
this.visible = true;
this.modalRef = this.modalService.open(this.modalContent);
this.visibleChange.emit(true);
from(this.modalRef.result)
.pipe(take(1))
.subscribe(
data => {
this.setVisible(false);
},
reason => {
this.setVisible(false);
},
);
}
setVisible(value: boolean) {
this.visible = value;
this.visibleChange.emit(value);
} }
ngOnChanges({ visible }: SimpleChanges): void { ngOnChanges({ visible }: SimpleChanges): void {
@ -93,8 +70,8 @@ export class ProfileComponent implements OnChanges {
if (visible.currentValue) { if (visible.currentValue) {
this.openModal(); this.openModal();
} else if (visible.currentValue === false && this.modalService.hasOpenModals()) { } else if (visible.currentValue === false && this.visible) {
this.modalRef.close(); this.visible = false;
} }
} }
} }

2
npm/ng-packs/packages/theme-shared/src/lib/components/modal/modal.component.ts

@ -116,6 +116,8 @@ export class ModalComponent implements OnDestroy {
this.close(); this.close();
}); });
if (!this.abpClose) return;
fromEvent(this.abpClose.nativeElement, 'click') fromEvent(this.abpClose.nativeElement, 'click')
.pipe( .pipe(
takeUntil(this.destroy$), takeUntil(this.destroy$),

3
npm/ng-packs/packages/theme-shared/src/lib/contants/styles.ts

@ -24,6 +24,9 @@ export default `
top: 18px; top: 18px;
} }
.modal {
background-color: rgba(0, 0, 0, .6);
}
/* <animations */ /* <animations */

Loading…
Cancel
Save