Browse Source

Merge branch 'dev' of https://github.com/volosoft/abp into dev

pull/1584/head
Yunus Emre Kalkan 7 years ago
parent
commit
108823d2fd
  1. 2
      npm/ng-packs/package.json
  2. 4
      npm/ng-packs/packages/account/src/lib/components/login/login.component.html
  3. 22
      npm/ng-packs/packages/account/src/lib/components/register/register.component.html
  4. 33
      npm/ng-packs/packages/account/src/lib/components/register/register.component.ts
  5. 42
      npm/ng-packs/packages/account/src/lib/components/tenant-box/tenant-box.component.html
  6. 52
      npm/ng-packs/packages/account/src/lib/components/tenant-box/tenant-box.component.ts
  7. 2
      npm/ng-packs/packages/account/src/lib/models/index.ts
  8. 4
      npm/ng-packs/packages/account/src/lib/models/tenant.ts
  9. 29
      npm/ng-packs/packages/account/src/lib/models/user.ts
  10. 30
      npm/ng-packs/packages/account/src/lib/services/account.service.ts
  11. 0
      npm/ng-packs/packages/account/src/lib/services/index.ts
  12. 4
      npm/ng-packs/packages/core/src/lib/actions/session.actions.ts
  13. 10
      npm/ng-packs/packages/core/src/lib/core.module.ts
  14. 15
      npm/ng-packs/packages/core/src/lib/directives/autofocus.directive.ts
  15. 1
      npm/ng-packs/packages/core/src/lib/directives/index.ts
  16. 1
      npm/ng-packs/packages/core/src/lib/models/session.ts
  17. 10
      npm/ng-packs/packages/core/src/lib/plugins/config.plugin.ts
  18. 16
      npm/ng-packs/packages/core/src/lib/states/session.state.ts
  19. 4
      npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.html
  20. 6
      npm/ng-packs/packages/identity/src/lib/components/users/users.component.html
  21. 11
      npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.html
  22. 10
      npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts
  23. 6
      npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.html
  24. 5
      npm/ng-packs/packages/theme-basic/src/lib/components/change-password/change-password.component.html
  25. 18
      npm/ng-packs/packages/theme-basic/src/lib/components/layout-application/layout-application.component.html
  26. 8
      npm/ng-packs/packages/theme-basic/src/lib/components/layout/layout.component.html
  27. 2
      npm/ng-packs/packages/theme-basic/src/lib/components/layout/layout.component.ts
  28. 4
      npm/ng-packs/packages/theme-basic/src/lib/components/profile/profile.component.html
  29. 8
      npm/ng-packs/packages/theme-shared/src/lib/abstracts/toaster.ts
  30. 1
      npm/ng-packs/packages/theme-shared/src/lib/animations/index.ts
  31. 6
      npm/ng-packs/packages/theme-shared/src/lib/animations/slide.animation.ts
  32. 68
      npm/ng-packs/packages/theme-shared/src/lib/components/button/button.component.ts
  33. 4
      npm/ng-packs/packages/theme-shared/src/lib/components/index.ts
  34. 2
      npm/ng-packs/packages/theme-shared/src/lib/components/modal/README.md
  35. 12
      npm/ng-packs/packages/theme-shared/src/lib/components/modal/modal.component.html
  36. 54
      npm/ng-packs/packages/theme-shared/src/lib/components/modal/modal.component.ts
  37. 4
      npm/ng-packs/packages/theme-shared/src/lib/contants/styles.ts
  38. 3
      npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts
  39. 8
      npm/ng-packs/packages/theme-shared/src/lib/services/confirmation.service.ts
  40. 4
      npm/ng-packs/packages/theme-shared/src/lib/services/toaster.service.ts
  41. 12
      npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts
  42. 1
      npm/ng-packs/packages/theme-shared/src/public-api.ts
  43. 2
      npm/ng-packs/scripts/build.js
  44. 3
      npm/ng-packs/scripts/sync.js
  45. 25
      templates/app/angular/package.json
  46. 4
      templates/app/angular/src/app/app.component.ts

2
npm/ng-packs/package.json

@ -48,7 +48,7 @@
"protractor": "~5.4.0", "protractor": "~5.4.0",
"rxjs": "~6.4.0", "rxjs": "~6.4.0",
"snq": "^1.0.3", "snq": "^1.0.3",
"symlink-manager": "^1.2.2", "symlink-manager": "^1.3.0",
"ts-node": "~7.0.0", "ts-node": "~7.0.0",
"tsickle": "^0.35.0", "tsickle": "^0.35.0",
"tslib": "^1.9.0", "tslib": "^1.9.0",

4
npm/ng-packs/packages/account/src/lib/components/login/login.component.html

@ -14,6 +14,7 @@
type="text" type="text"
id="login-input-user-name-or-email-address" id="login-input-user-name-or-email-address"
formControlName="username" formControlName="username"
autofocus
/> />
</div> </div>
<div class="form-group"> <div class="form-group">
@ -27,9 +28,6 @@
</label> </label>
</div> </div>
<div class="mt-2"> <div class="mt-2">
<button type="button" name="Action" value="Cancel" class="btn btn-secondary">
{{ 'AbpAccount::Cancel' | abpLocalization }}
</button>
<button [disabled]="inProgress" type="submit" name="Action" value="Login" class="btn btn-primary ml-1"> <button [disabled]="inProgress" type="submit" name="Action" value="Login" class="btn btn-primary ml-1">
{{ 'AbpAccount::Login' | abpLocalization }} {{ 'AbpAccount::Login' | abpLocalization }}
</button> </button>

22
npm/ng-packs/packages/account/src/lib/components/register/register.component.html

@ -3,22 +3,28 @@
<abp-tenant-box></abp-tenant-box> <abp-tenant-box></abp-tenant-box>
<div class="abp-account-container"> <div class="abp-account-container">
<h2>Register</h2> <h2>{{ 'AbpAccount::Register' | abpLocalization }}</h2>
<form [formGroup]="form" (ngSubmit)="onSubmit()" novalidate> <form [formGroup]="form" (ngSubmit)="onSubmit()" novalidate>
<div class="form-group"> <div class="form-group">
<label for="input-user-name">User name</label><span> * </span <label for="input-user-name">{{ 'AbpAccount::UserName' | abpLocalization }}</label
><input autofocus type="text" id="input-user-name" class="form-control" formControlName="username" /> ><span> * </span
><input autofocus type="text" id="input-user-name" class="form-control" formControlName="username" autofocus/>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="input-email-address">Email address</label><span> * </span <label for="input-email-address">{{ 'AbpAccount::EmailAddress' | abpLocalization }}</label
><input type="email" id="input-email-address" class="form-control" formControlName="email" /> ><span> * </span><input type="email" id="input-email-address" class="form-control" formControlName="email" />
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="input-password">Password</label><span> * </span <label for="input-password">{{ 'AbpAccount::Password' | abpLocalization }}</label
><input type="password" id="input-password" class="form-control" formControlName="password" /> ><span> * </span><input type="password" id="input-password" class="form-control" formControlName="password" />
</div> </div>
<button type="submit" class="btn btn-primary">Register</button> <button [disabled]="inProgress" type="submit" name="Action" value="Register" class="btn btn-primary">
{{ 'AbpAccount::Register' | abpLocalization }}
</button>
</form> </form>
<div style="padding-top: 20px">
<a routerLink="/account/login">{{ 'AbpAccount::Login' | abpLocalization }}</a>
</div>
</div> </div>
</div> </div>
</div> </div>

33
npm/ng-packs/packages/account/src/lib/components/register/register.component.ts

@ -1,8 +1,12 @@
import { ToasterService } from '@abp/ng.theme.shared';
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { validatePassword } from '@ngx-validate/core'; import { validatePassword } from '@ngx-validate/core';
import { OAuthService } from 'angular-oauth2-oidc'; import { throwError } from 'rxjs';
import { catchError, finalize, take } from 'rxjs/operators';
import snq from 'snq';
import { RegisterRequest } from '../../models';
import { AccountService } from '../../services/account.service';
const { maxLength, minLength, required, email } = Validators; const { maxLength, minLength, required, email } = Validators;
@ -13,7 +17,9 @@ const { maxLength, minLength, required, email } = Validators;
export class RegisterComponent { export class RegisterComponent {
form: FormGroup; form: FormGroup;
constructor(private fb: FormBuilder, private oauthService: OAuthService, private router: Router) { inProgress: boolean;
constructor(private fb: FormBuilder, private accountService: AccountService, private toasterService: ToasterService) {
this.form = this.fb.group({ this.form = this.fb.group({
username: ['', [required, maxLength(255)]], username: ['', [required, maxLength(255)]],
password: [ password: [
@ -26,5 +32,26 @@ export class RegisterComponent {
onSubmit() { onSubmit() {
if (this.form.invalid) return; if (this.form.invalid) return;
this.inProgress = true;
const newUser = {
userName: this.form.get('username').value,
password: this.form.get('password').value,
emailAddress: this.form.get('email').value,
appName: 'angular',
} as RegisterRequest;
this.accountService
.register(newUser)
.pipe(
take(1),
catchError(err => {
this.toasterService.error(snq(() => err.error.error_description, 'An error occured.'), 'Error');
return throwError(err);
}),
finalize(() => (this.inProgress = false)),
)
.subscribe();
} }
} }

42
npm/ng-packs/packages/account/src/lib/components/tenant-box/tenant-box.component.html

@ -12,33 +12,27 @@
>) >)
</div> </div>
<ng-template #modalContent let-modal> <abp-modal [(visible)]="isModalVisible" size="md">
<div class="modal-header"> <ng-template #abpHeader>
<h5 class="modal-title" id="modal-basic-title"> <h5>Switch Tenant</h5>
SwitchTenant </ng-template>
</h5> <ng-template #abpBody>
<button type="button" class="close" aria-label="Close" (click)="modal.dismiss()"> <form>
<span aria-hidden="true">&times;</span>
</button>
</div>
<form [formGroup]="form" (ngSubmit)="save()">
<div class="modal-body">
<div class="mt-2"> <div class="mt-2">
<div class="form-group"> <div class="form-group">
<label for="name">{{ 'AbpUiMultiTenancy::Name' | abpLocalization }}</label> <label for="name">{{ 'AbpUiMultiTenancy::Name' | abpLocalization }}</label>
<input type="text" id="name" class="form-control" formControlName="name" /> <input [(ngModel)]="selected.name" type="text" id="name" name="tenant" class="form-control" autofocus />
</div> </div>
<p>{{ 'AbpUiMultiTenancy::SwitchTenantHint' | abpLocalization }}</p> <p>{{ 'AbpUiMultiTenancy::SwitchTenantHint' | abpLocalization }}</p>
</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">
{{ 'AbpTenantManagement::Cancel' | abpLocalization }} {{ 'AbpTenantManagement::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>{{ 'AbpTenantManagement::Save' | abpLocalization }}</span> <i class="fa fa-check mr-1"></i> <span>{{ 'AbpTenantManagement::Save' | abpLocalization }}</span>
</button> </button>
</div> </ng-template>
</form> </abp-modal>
</ng-template>

52
npm/ng-packs/packages/account/src/lib/components/tenant-box/tenant-box.component.ts

@ -1,40 +1,50 @@
import { ABP, SessionSetTenantId } from '@abp/ng.core';
import { ToasterService } from '@abp/ng.theme.shared';
import { Component, TemplateRef, ViewChild } from '@angular/core'; import { Component, TemplateRef, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms'; import { Store } from '@ngxs/store';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { throwError } from 'rxjs';
import { ABP } from '@abp/ng.core'; import { catchError, take } from 'rxjs/operators';
import snq from 'snq';
import { AccountService } from '../../services/account.service';
@Component({ @Component({
selector: 'abp-tenant-box', selector: 'abp-tenant-box',
templateUrl: './tenant-box.component.html', templateUrl: './tenant-box.component.html',
}) })
export class TenantBoxComponent { export class TenantBoxComponent {
constructor(private modalService: NgbModal, private fb: FormBuilder) {} constructor(private store: Store, private toasterService: ToasterService, private accountService: AccountService) {}
form: FormGroup; selected = {} as ABP.BasicItem;
selected: ABP.BasicItem; isModalVisible: boolean;
@ViewChild('modalContent', { static: false }) @ViewChild('modalContent', { static: false })
modalContent: TemplateRef<any>; modalContent: TemplateRef<any>;
createForm() {
this.form = this.fb.group({
name: [this.selected.name],
});
}
openModal() {
this.createForm();
this.modalService.open(this.modalContent);
}
onSwitch() { onSwitch() {
this.selected = {} as ABP.BasicItem; this.isModalVisible = true;
this.openModal();
} }
save() { save() {
this.selected = this.form.value; this.selected.name = this.selected.name || '';
this.modalService.dismissAll();
this.accountService
.findTenant(this.selected.name)
.pipe(
take(1),
catchError(err => {
this.toasterService.error(snq(() => err.error.error_description, 'An error occured.'), 'Error');
return throwError(err);
}),
)
.subscribe(({ success, tenantId }) => {
if (success) {
this.isModalVisible = false;
} else {
this.toasterService.error(`Given tenant is not available: ${this.selected.name}`, 'Error');
this.selected = {} as ABP.BasicItem;
}
this.store.dispatch(new SessionSetTenantId(success ? tenantId : null));
});
} }
} }

2
npm/ng-packs/packages/account/src/lib/models/index.ts

@ -1 +1,3 @@
export * from './options'; export * from './options';
export * from './user';
export * from './tenant';

4
npm/ng-packs/packages/account/src/lib/models/tenant.ts

@ -0,0 +1,4 @@
export interface Tenant {
success: boolean;
tenantId: string;
}

29
npm/ng-packs/packages/account/src/lib/models/user.ts

@ -0,0 +1,29 @@
export interface RegisterRequest {
userName: string;
emailAddress: string;
password: string;
appName?: string;
}
export interface RegisterResponse {
tenantId: string;
userName: string;
name: string;
surname: string;
email: string;
emailConfirmed: boolean;
phoneNumber: string;
phoneNumberConfirmed: boolean;
twoFactorEnabled: boolean;
lockoutEnabled: boolean;
lockoutEnd: string;
concurrencyStamp: string;
isDeleted: boolean;
deleterId: string;
deletionTime: string;
lastModificationTime: string;
lastModifierId: string;
creationTime: string;
creatorId: string;
id: string;
}

30
npm/ng-packs/packages/account/src/lib/services/account.service.ts

@ -0,0 +1,30 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { RestService, Rest } from '@abp/ng.core';
import { RegisterResponse, RegisterRequest, Tenant } from '../models';
@Injectable({
providedIn: 'root',
})
export class AccountService {
constructor(private rest: RestService) {}
findTenant(tenantName: string): Observable<Tenant> {
const request: Rest.Request<null> = {
method: 'GET',
url: `/api/abp/multi-tenancy/find-tenant/${tenantName}`,
};
return this.rest.request<null, Tenant>(request);
}
register(body: RegisterRequest): Observable<RegisterResponse> {
const request: Rest.Request<RegisterRequest> = {
method: 'POST',
url: `/api/account/register`,
body,
};
return this.rest.request<RegisterRequest, RegisterResponse>(request, { throwErr: true });
}
}

0
npm/ng-packs/packages/account/src/lib/services/index.ts

4
npm/ng-packs/packages/core/src/lib/actions/session.actions.ts

@ -2,3 +2,7 @@ export class SessionSetLanguage {
static readonly type = '[Session] Set Language'; static readonly type = '[Session] Set Language';
constructor(public payload: string) {} constructor(public payload: string) {}
} }
export class SessionSetTenantId {
static readonly type = '[Session] Set Tenant Id';
constructor(public payload: string) {}
}

10
npm/ng-packs/packages/core/src/lib/core.module.ts

@ -19,6 +19,7 @@ import { ProfileState } from './states/profile.state';
import { SessionState } from './states/session.state'; import { SessionState } from './states/session.state';
import { getInitialData } from './utils/initial-utils'; import { getInitialData } from './utils/initial-utils';
import { EllipsisDirective } from './directives/ellipsis.directive'; import { EllipsisDirective } from './directives/ellipsis.directive';
import { AutofocusDirective } from './directives/autofocus.directive';
@NgModule({ @NgModule({
imports: [ imports: [
@ -34,10 +35,11 @@ import { EllipsisDirective } from './directives/ellipsis.directive';
declarations: [ declarations: [
RouterOutletComponent, RouterOutletComponent,
DynamicLayoutComponent, DynamicLayoutComponent,
AutofocusDirective,
EllipsisDirective,
LocalizationPipe,
PermissionDirective, PermissionDirective,
VisibilityDirective, VisibilityDirective,
LocalizationPipe,
EllipsisDirective,
], ],
exports: [ exports: [
CommonModule, CommonModule,
@ -47,9 +49,11 @@ import { EllipsisDirective } from './directives/ellipsis.directive';
RouterModule, RouterModule,
RouterOutletComponent, RouterOutletComponent,
DynamicLayoutComponent, DynamicLayoutComponent,
AutofocusDirective,
EllipsisDirective,
LocalizationPipe,
PermissionDirective, PermissionDirective,
VisibilityDirective, VisibilityDirective,
EllipsisDirective,
LocalizationPipe, LocalizationPipe,
], ],
providers: [LocalizationPipe], providers: [LocalizationPipe],

15
npm/ng-packs/packages/core/src/lib/directives/autofocus.directive.ts

@ -0,0 +1,15 @@
import { Directive, ElementRef, Input, AfterViewInit } from '@angular/core';
@Directive({
selector: '[autofocus]',
})
export class AutofocusDirective implements AfterViewInit {
@Input('autofocus')
delay: number = 0;
constructor(private elRef: ElementRef) {}
ngAfterViewInit(): void {
setTimeout(() => this.elRef.nativeElement.focus(), this.delay);
}
}

1
npm/ng-packs/packages/core/src/lib/directives/index.ts

@ -1,3 +1,4 @@
export * from './autofocus.directive';
export * from './ellipsis.directive'; export * from './ellipsis.directive';
export * from './permission.directive'; export * from './permission.directive';
export * from './visibility.directive'; export * from './visibility.directive';

1
npm/ng-packs/packages/core/src/lib/models/session.ts

@ -1,5 +1,6 @@
export namespace Session { export namespace Session {
export interface State { export interface State {
language: string; language: string;
tenantId: string;
} }
} }

10
npm/ng-packs/packages/core/src/lib/plugins/config.plugin.ts

@ -1,9 +1,9 @@
import { Injectable, Inject, InjectionToken, Type } from '@angular/core'; import { Inject, Injectable, InjectionToken } from '@angular/core';
import { NgxsPlugin, setValue, actionMatcher, InitState, UpdateState, NgxsNextPluginFn } from '@ngxs/store';
import { Router, Routes } from '@angular/router'; import { Router, Routes } from '@angular/router';
import { ABP } from '../models'; import { actionMatcher, InitState, NgxsNextPluginFn, NgxsPlugin, setValue, UpdateState } from '@ngxs/store';
import snq from 'snq'; import snq from 'snq';
import { setChildRoute, sortRoutes, organizeRoutes } from '../utils/route-utils'; import { ABP } from '../models';
import { organizeRoutes } from '../utils/route-utils';
export const NGXS_CONFIG_PLUGIN_OPTIONS = new InjectionToken('NGXS_CONFIG_PLUGIN_OPTIONS'); export const NGXS_CONFIG_PLUGIN_OPTIONS = new InjectionToken('NGXS_CONFIG_PLUGIN_OPTIONS');
@ -45,7 +45,7 @@ function transformRoutes(routes: Routes = [], wrappers: ABP.FullRoute[] = []): a
wrappers = abpRoutes.filter(ar => ar.wrapper); wrappers = abpRoutes.filter(ar => ar.wrapper);
const transformed = [] as ABP.FullRoute[]; const transformed = [] as ABP.FullRoute[];
routes routes
.filter(route => route.component || route.loadChildren) .filter(route => (route.data || {}).routes && (route.component || route.loadChildren))
.forEach(route => { .forEach(route => {
const abpPackage = abpRoutes.find(abp => abp.path.toLowerCase() === route.path.toLowerCase()); const abpPackage = abpRoutes.find(abp => abp.path.toLowerCase() === route.path.toLowerCase());
const { length } = transformed; const { length } = transformed;

16
npm/ng-packs/packages/core/src/lib/states/session.state.ts

@ -1,5 +1,5 @@
import { State, Action, StateContext, Selector } from '@ngxs/store'; import { Action, Selector, State, StateContext } from '@ngxs/store';
import { SessionSetLanguage } from '../actions/session.actions'; import { SessionSetLanguage, SessionSetTenantId } from '../actions/session.actions';
import { Session } from '../models/session'; import { Session } from '../models/session';
@State<Session.State>({ @State<Session.State>({
@ -12,6 +12,11 @@ export class SessionState {
return language; return language;
} }
@Selector()
static getSelectedTenantId({ tenantId }: Session.State): string {
return tenantId;
}
constructor() {} constructor() {}
@Action(SessionSetLanguage) @Action(SessionSetLanguage)
@ -20,4 +25,11 @@ export class SessionState {
language: payload, language: payload,
}); });
} }
@Action(SessionSetTenantId)
sessionSetTenantId({ patchState }: StateContext<Session.State>, { payload }: SessionSetTenantId) {
patchState({
tenantId: payload,
});
}
} }

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

@ -58,7 +58,7 @@
</div> </div>
</div> </div>
<abp-modal size="md" [(visible)]="isModalVisible" *ngIf="isModalVisible" [centered]="true"> <abp-modal size="md" [(visible)]="isModalVisible">
<ng-template #abpHeader> <ng-template #abpHeader>
<h3>{{ (selected?.id ? 'AbpIdentity::Edit' : 'AbpIdentity::NewRole') | abpLocalization }}</h3> <h3>{{ (selected?.id ? 'AbpIdentity::Edit' : 'AbpIdentity::NewRole') | abpLocalization }}</h3>
</ng-template> </ng-template>
@ -68,7 +68,7 @@
<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>
<input type="text" id="role-name" class="form-control" formControlName="name" /> <input type="text" id="role-name" class="form-control" formControlName="name" autofocus />
</div> </div>
<div class="custom-checkbox custom-control mb-2"> <div class="custom-checkbox custom-control mb-2">

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

@ -77,13 +77,13 @@
</div> </div>
</div> </div>
<abp-modal [(visible)]="isModalVisible" *ngIf="isModalVisible"> <abp-modal [(visible)]="isModalVisible">
<ng-template #abpHeader> <ng-template #abpHeader>
<h3>{{ (selected?.id ? 'AbpIdentity::Edit' : 'AbpIdentity::NewUser') | abpLocalization }}</h3> <h3>{{ (selected?.id ? 'AbpIdentity::Edit' : 'AbpIdentity::NewUser') | abpLocalization }}</h3>
</ng-template> </ng-template>
<ng-template #abpBody> <ng-template #abpBody>
<perfect-scrollbar class="ps-show-always" style="max-height: 65vh;"> <perfect-scrollbar class="ps-show-always" style="max-height: 70vh;">
<form [formGroup]="form"> <form [formGroup]="form">
<ngb-tabset> <ngb-tabset>
<ngb-tab [title]="'AbpIdentity::UserInformations' | abpLocalization"> <ngb-tab [title]="'AbpIdentity::UserInformations' | abpLocalization">
@ -92,7 +92,7 @@
<div class="form-group"> <div class="form-group">
<label for="user-name">{{ 'AbpIdentity::UserName' | abpLocalization }}</label <label for="user-name">{{ 'AbpIdentity::UserName' | abpLocalization }}</label
><span> * </span> ><span> * </span>
<input type="text" id="user-name" class="form-control" formControlName="userName" /> <input type="text" id="user-name" class="form-control" formControlName="userName" autofocus />
</div> </div>
<div class="form-group"> <div class="form-group">

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

@ -1,4 +1,4 @@
<abp-modal [(visible)]="visible" *ngIf="visible" size="lg"> <abp-modal [(visible)]="visible" (init)="initModal()">
<ng-container *ngIf="{ entityName: entityName$ | async } as data"> <ng-container *ngIf="{ entityName: entityName$ | async } as data">
<ng-template #abpHeader> <ng-template #abpHeader>
<h4>{{ 'AbpPermissionManagement::Permissions' | abpLocalization }} - {{ data.entityName }}</h4> <h4>{{ 'AbpPermissionManagement::Permissions' | abpLocalization }} - {{ data.entityName }}</h4>
@ -24,9 +24,12 @@
<ul class="nav nav-pills flex-column"> <ul class="nav nav-pills flex-column">
<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
group?.displayName class="nav-link pointer"
}}</a> [class.active]="selectedGroup.name === group.name"
(click)="onChangeGroup(group)"
>{{ group?.displayName }}</a
>
</li> </li>
</perfect-scrollbar> </perfect-scrollbar>
</ul> </ul>

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

@ -216,14 +216,14 @@ export class PermissionManagementComponent implements OnInit, OnChanges {
this.permissions = getPermissions(permissionRes.groups); this.permissions = getPermissions(permissionRes.groups);
this.visible = true; this.visible = true;
setTimeout(() => {
this.setTabCheckboxState();
this.setGrantCheckboxState();
}, 0);
}); });
} }
initModal() {
this.setTabCheckboxState();
this.setGrantCheckboxState();
}
ngOnChanges({ visible }: SimpleChanges): void { ngOnChanges({ visible }: SimpleChanges): void {
if (!visible) return; if (!visible) return;

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

@ -88,7 +88,7 @@
</div> </div>
</div> </div>
<abp-modal [(visible)]="isModalVisible" *ngIf="isModalVisible"> <abp-modal [(visible)]="isModalVisible">
<ng-template #abpHeader> <ng-template #abpHeader>
<h3>{{ selectedModalContent.title | abpLocalization }}</h3> <h3>{{ selectedModalContent.title | abpLocalization }}</h3>
</ng-template> </ng-template>
@ -112,7 +112,7 @@
<div class="mt-2"> <div class="mt-2">
<div class="form-group"> <div class="form-group">
<label for="name">{{ 'AbpTenantManagement::TenantName' | abpLocalization }}</label> <label for="name">{{ 'AbpTenantManagement::TenantName' | abpLocalization }}</label>
<input type="text" id="name" class="form-control" formControlName="name" /> <input type="text" id="name" class="form-control" formControlName="name" autofocus/>
</div> </div>
</div> </div>
</form> </form>
@ -123,7 +123,7 @@
<div class="mt-2"> <div class="mt-2">
<div class="form-group"> <div class="form-group">
<div class="form-check"> <div class="form-check">
<input id="useSharedDatabase" type="checkbox" class="form-check-input" formControlName="useSharedDatabase" /> <input id="useSharedDatabase" type="checkbox" class="form-check-input" formControlName="useSharedDatabase" autofocus/>
<label for="useSharedDatabase" class="font-check-label">{{ <label for="useSharedDatabase" class="font-check-label">{{
'AbpTenantManagement::DisplayName:UseSharedDatabase' | abpLocalization 'AbpTenantManagement::DisplayName:UseSharedDatabase' | abpLocalization
}}</label> }}</label>

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

@ -1,4 +1,4 @@
<abp-modal *ngIf="visible" [(visible)]="visible"> <abp-modal [(visible)]="visible">
<ng-template #abpHeader> <ng-template #abpHeader>
<h4>{{ 'AbpIdentity::ChangePassword' | abpLocalization }}</h4> <h4>{{ 'AbpIdentity::ChangePassword' | abpLocalization }}</h4>
</ng-template> </ng-template>
@ -6,7 +6,8 @@
<form [formGroup]="form" novalidate> <form [formGroup]="form" novalidate>
<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" autofocus />
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="new-password">{{ 'AbpIdentity::DisplayName:NewPassword' | abpLocalization }}</label <label for="new-password">{{ 'AbpIdentity::DisplayName:NewPassword' | abpLocalization }}</label

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

@ -16,13 +16,13 @@
<ng-template #dropdownLink let-route> <ng-template #dropdownLink let-route>
<li <li
#navbarRootDropdown #navbarRootDropdown
class="nav-item dropdown"
ngbDropdown ngbDropdown
display="static"
[abpPermission]="route.requiredPolicy" [abpPermission]="route.requiredPolicy"
[abpVisibility]="routeContainer" [abpVisibility]="routeContainer"
class="nav-item dropdown pointer"
display="static"
> >
<a ngbDropdownToggle class="nav-link dropdown-toggle" data-toggle="dropdown"> <a ngbDropdownToggle class="nav-link dropdown-toggle pointer" data-toggle="dropdown">
{{ route.name | abpLocalization }} {{ route.name | abpLocalization }}
</a> </a>
<div #routeContainer ngbDropdownMenu class="dropdown-menu dropdown-menu-right"> <div #routeContainer ngbDropdownMenu class="dropdown-menu dropdown-menu-right">
@ -53,13 +53,13 @@
<ng-template #dropdownChild let-child> <ng-template #dropdownChild let-child>
<div <div
[abpVisibility]="childrenContainer" [abpVisibility]="childrenContainer"
class="dropdown-submenu" class="dropdown-submenu pointer"
ngbDropdown ngbDropdown
[display]="isDropdownChildDynamic ? 'dynamic' : 'static'" [display]="isDropdownChildDynamic ? 'dynamic' : 'static'"
placement="right-top" placement="right-top"
[abpPermission]="child.requiredPolicy" [abpPermission]="child.requiredPolicy"
> >
<div ngbDropdownToggle [class.dropdown-toggle]="false"> <div ngbDropdownToggle [class.dropdown-toggle]="false" class="pointer">
<a <a
abpEllipsis="140px" abpEllipsis="140px"
[abpEllipsisEnabled]="isDropdownChildDynamic" [abpEllipsisEnabled]="isDropdownChildDynamic"
@ -90,8 +90,8 @@
</abp-layout> </abp-layout>
<ng-template #language> <ng-template #language>
<li class="nav-item dropdown" ngbDropdown> <li class="nav-item dropdown pointer" ngbDropdown>
<a ngbDropdownToggle class="nav-link dropdown-toggle" data-toggle="dropdown"> <a ngbDropdownToggle class="nav-link dropdown-toggle pointer" data-toggle="dropdown">
{{ defaultLanguage$ | async }} {{ defaultLanguage$ | async }}
</a> </a>
<div ngbDropdownMenu class="dropdown-menu dropdown-menu-right"> <div ngbDropdownMenu class="dropdown-menu dropdown-menu-right">
@ -106,8 +106,8 @@
</ng-template> </ng-template>
<ng-template #currentUser> <ng-template #currentUser>
<li *ngIf="(currentUser$ | async)?.isAuthenticated" class="nav-item dropdown" ngbDropdown> <li *ngIf="(currentUser$ | async)?.isAuthenticated" class="nav-item dropdown pointer" ngbDropdown>
<a ngbDropdownToggle class="nav-link dropdown-toggle" data-toggle="dropdown"> <a ngbDropdownToggle class="nav-link dropdown-toggle pointer" data-toggle="dropdown">
{{ (currentUser$ | async)?.userName }} {{ (currentUser$ | async)?.userName }}
</a> </a>
<div ngbDropdownMenu class="dropdown-menu dropdown-menu-right"> <div ngbDropdownMenu class="dropdown-menu dropdown-menu-right">

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

@ -8,8 +8,12 @@
</div> </div>
</nav> </nav>
<div style="padding-top: 5rem;" class="container"> <div
<router-outlet></router-outlet> [@routeAnimations]="outlet && outlet.activatedRoute && outlet.activatedRoute.routeConfig.path"
style="padding-top: 5rem;"
class="container"
>
<router-outlet #outlet="outlet"></router-outlet>
</div> </div>
<abp-confirmation></abp-confirmation> <abp-confirmation></abp-confirmation>

2
npm/ng-packs/packages/theme-basic/src/lib/components/layout/layout.component.ts

@ -1,8 +1,10 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { slideFromBottom } from '@abp/ng.theme.shared';
@Component({ @Component({
selector: ' abp-layout', selector: ' abp-layout',
templateUrl: './layout.component.html', templateUrl: './layout.component.html',
animations: [slideFromBottom],
}) })
export class LayoutComponent { export class LayoutComponent {
isCollapsed: boolean = false; isCollapsed: boolean = false;

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

@ -1,4 +1,4 @@
<abp-modal *ngIf="visible" [(visible)]="visible"> <abp-modal [(visible)]="visible">
<ng-template #abpHeader> <ng-template #abpHeader>
<h4>{{ 'AbpIdentity::PersonalInfo' | abpLocalization }}</h4> <h4>{{ 'AbpIdentity::PersonalInfo' | abpLocalization }}</h4>
</ng-template> </ng-template>
@ -6,7 +6,7 @@
<form *ngIf="form" [formGroup]="form" novalidate> <form *ngIf="form" [formGroup]="form" novalidate>
<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" autofocus/>
</div> </div>
<div class="row"> <div class="row">
<div class="col col-md-6"> <div class="col col-md-6">

8
npm/ng-packs/packages/theme-shared/src/lib/abstracts/toaster.ts

@ -2,12 +2,12 @@ import { MessageService } from 'primeng/components/common/messageservice';
import { Observable, Subject } from 'rxjs'; import { Observable, Subject } from 'rxjs';
import { Toaster } from '../models/toaster'; import { Toaster } from '../models/toaster';
export class AbstractToasterClass<T = Toaster.Options> { export class AbstractToaster<T = Toaster.Options> {
protected status$: Subject<Toaster.Status>; status$: Subject<Toaster.Status>;
protected key: string = 'abpToast'; key: string = 'abpToast';
protected sticky: boolean = false; sticky: boolean = false;
constructor(protected messageService: MessageService) {} constructor(protected messageService: MessageService) {}
info(message: string, title: string, options?: T): Observable<Toaster.Status> { info(message: string, title: string, options?: T): Observable<Toaster.Status> {

1
npm/ng-packs/packages/theme-shared/src/lib/animations/index.ts

@ -0,0 +1 @@
export * from './slide.animation';

6
npm/ng-packs/packages/theme-shared/src/lib/animations/slide.animation.ts

@ -0,0 +1,6 @@
import { animate, state, style, transition, trigger, query } from '@angular/animations';
export const slideFromBottom = trigger('routeAnimations', [
state('void', style({ 'margin-top': '20px', opacity: '0' })),
state('*', style({ 'margin-top': '0px', opacity: '1' })),
transition(':enter', [animate('0.2s ease-out', style({ opacity: '1', 'margin-top': '0px' }))]),
]);

68
npm/ng-packs/packages/theme-shared/src/lib/components/button/button.component.ts

@ -0,0 +1,68 @@
import { LoaderStart, LoaderStop } from '@abp/ng.core';
import { Component, Input, OnInit } from '@angular/core';
import { Actions, ofActionSuccessful } from '@ngxs/store';
import { filter } from 'rxjs/operators';
@Component({
selector: 'abp-button',
template: `
<button [attr.type]="buttonType" [ngClass]="buttonClass" [disabled]="loading">
<i [ngClass]="icon" class="mr-1"></i><ng-content></ng-content>
</button>
`,
})
export class ButtonComponent implements OnInit {
@Input()
buttonClass: string = 'btn btn-primary';
@Input()
buttonType: string = 'button';
@Input()
iconClass: string;
@Input()
loading: boolean = false;
@Input()
requestType: string | string[];
@Input()
requestURLContainSearchValue: string;
get icon(): string {
return `${this.loading ? 'fa fa-spin fa-spinner' : this.iconClass || 'd-none'}`;
}
constructor(private actions: Actions) {}
ngOnInit(): void {
if (this.requestType || this.requestURLContainSearchValue) {
this.actions
.pipe(
ofActionSuccessful(LoaderStart, LoaderStop),
filter((event: LoaderStart | LoaderStop) => {
let condition = true;
if (this.requestType) {
if (!Array.isArray(this.requestType)) this.requestType = [this.requestType];
condition =
condition &&
this.requestType.findIndex(type => type.toLowerCase() === event.payload.method.toLowerCase()) > -1;
}
if (condition && this.requestURLContainSearchValue) {
condition =
condition &&
event.payload.url.toLowerCase().indexOf(this.requestURLContainSearchValue.toLowerCase()) > -1;
}
return condition;
}),
)
.subscribe(() => {
this.loading = !this.loading;
});
}
}
}

4
npm/ng-packs/packages/theme-shared/src/lib/components/index.ts

@ -1,3 +1,5 @@
export * from './button/button.component';
export * from './confirmation/confirmation.component'; export * from './confirmation/confirmation.component';
export * from './toast/toast.component'; export * from './loader-bar/loader-bar.component';
export * from './modal/modal.component'; export * from './modal/modal.component';
export * from './toast/toast.component';

2
npm/ng-packs/packages/theme-shared/src/lib/components/modal/README.md

@ -3,7 +3,7 @@
Example Usage: Example Usage:
```html ```html
<abp-modal size="lg" [(visible)]="isModalShow" [centered]="true"> <abp-modal size="md" [(visible)]="isModalShow" [centered]="false">
<ng-template #abpHeader> <ng-template #abpHeader>
<h3>Modal Title</h3> <h3>Modal Title</h3>
</ng-template> </ng-template>

12
npm/ng-packs/packages/theme-shared/src/lib/components/modal/modal.component.html

@ -1,9 +1,8 @@
<div <div
*ngIf="showModal"
id="abp-modal" id="abp-modal"
tabindex="-1" tabindex="-1"
class="modal fade {{ modalClass }}" class="modal fade {{ modalClass }} d-block show"
[class.show]="visible"
[style.display]="visible ? 'block' : 'none'"
[style.padding-right.px]="'15'" [style.padding-right.px]="'15'"
> >
<div <div
@ -20,7 +19,12 @@
<span aria-hidden="true">&times;</span> <span aria-hidden="true">&times;</span>
</button> </button>
</div> </div>
<div id="abp-modal-body" class="modal-body"> <div
id="abp-modal-body"
class="modal-body"
[style.height]="height || undefined"
[style.minHeight]="minHeight || undefined"
>
<ng-container *ngTemplateOutlet="abpBody"></ng-container> <ng-container *ngTemplateOutlet="abpBody"></ng-container>
<div id="abp-modal-footer" class="modal-footer"> <div id="abp-modal-footer" class="modal-footer">

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

@ -17,6 +17,8 @@ import { Toaster } from '../../models/toaster';
export type ModalSize = 'sm' | 'md' | 'lg' | 'xl'; export type ModalSize = 'sm' | 'md' | 'lg' | 'xl';
const ANIMATION_TIMEOUT = 200;
@Component({ @Component({
selector: 'abp-modal', selector: 'abp-modal',
templateUrl: './modal.component.html', templateUrl: './modal.component.html',
@ -27,8 +29,15 @@ export class ModalComponent implements OnDestroy {
return this._visible; return this._visible;
} }
set visible(value: boolean) { set visible(value: boolean) {
if (typeof value !== 'boolean') return;
if (!this.modalContent) { if (!this.modalContent) {
setTimeout(() => (this.visible = value), 0); if (value) {
setTimeout(() => {
this.showModal = value;
this.visible = value;
}, 0);
}
return; return;
} }
@ -40,13 +49,13 @@ export class ModalComponent implements OnDestroy {
this.renderer.addClass(this.modalContent.nativeElement, 'fade-out-top'); this.renderer.addClass(this.modalContent.nativeElement, 'fade-out-top');
setTimeout(() => { setTimeout(() => {
this.setVisible(value); this.setVisible(value);
this.renderer.removeClass(this.modalContent.nativeElement, 'fade-out-top'); // this.renderer.removeClass(this.modalContent.nativeElement, 'fade-out-top');
this.ngOnDestroy(); this.ngOnDestroy();
}, 350); }, ANIMATION_TIMEOUT - 10);
} }
} }
@Input() centered: boolean = true; @Input() centered: boolean = false;
@Input() modalClass: string = ''; @Input() modalClass: string = '';
@ -54,6 +63,12 @@ export class ModalComponent implements OnDestroy {
@Output() visibleChange = new EventEmitter<boolean>(); @Output() visibleChange = new EventEmitter<boolean>();
@Input() height: number;
@Input() minHeight: number;
@Output() init = new EventEmitter<void>();
@ContentChild('abpHeader', { static: false }) abpHeader: TemplateRef<any>; @ContentChild('abpHeader', { static: false }) abpHeader: TemplateRef<any>;
@ContentChild('abpBody', { static: false }) abpBody: TemplateRef<any>; @ContentChild('abpBody', { static: false }) abpBody: TemplateRef<any>;
@ -66,10 +81,12 @@ export class ModalComponent implements OnDestroy {
_visible: boolean = false; _visible: boolean = false;
closable: boolean = false; showModal: boolean = false;
isOpenConfirmation: boolean = false; isOpenConfirmation: boolean = false;
closable: boolean = false;
destroy$ = new Subject<void>(); destroy$ = new Subject<void>();
constructor(private renderer: Renderer2, private confirmationService: ConfirmationService) {} constructor(private renderer: Renderer2, private confirmationService: ConfirmationService) {}
@ -81,8 +98,10 @@ export class ModalComponent implements OnDestroy {
setVisible(value: boolean) { setVisible(value: boolean) {
this._visible = value; this._visible = value;
this.visibleChange.emit(value); this.visibleChange.emit(value);
this.showModal = value;
value value
? timer(500) ? timer(ANIMATION_TIMEOUT + 100)
.pipe(take(1)) .pipe(take(1))
.subscribe(_ => (this.closable = true)) .subscribe(_ => (this.closable = true))
: (this.closable = false); : (this.closable = false);
@ -91,16 +110,18 @@ export class ModalComponent implements OnDestroy {
listen() { listen() {
fromEvent(document, 'click') fromEvent(document, 'click')
.pipe( .pipe(
debounceTime(350), debounceTime(100),
takeUntil(this.destroy$), takeUntil(this.destroy$),
filter( filter((event: MouseEvent) => {
(event: MouseEvent) => const isOpenConfirmation = this.isOpenConfirmation || document.querySelector('p-toastitem');
return (
event && event &&
this.closable && this.closable &&
this.modalContent && this.modalContent &&
!this.isOpenConfirmation && !isOpenConfirmation &&
!this.modalContent.nativeElement.contains(event.target), !this.modalContent.nativeElement.contains(event.target)
), );
}),
) )
.subscribe(_ => { .subscribe(_ => {
this.close(); this.close();
@ -109,8 +130,8 @@ export class ModalComponent implements OnDestroy {
fromEvent(document, 'keyup') fromEvent(document, 'keyup')
.pipe( .pipe(
takeUntil(this.destroy$), takeUntil(this.destroy$),
debounceTime(250),
filter((key: KeyboardEvent) => key && key.code === 'Escape' && this.closable), filter((key: KeyboardEvent) => key && key.code === 'Escape' && this.closable),
debounceTime(350),
) )
.subscribe(_ => { .subscribe(_ => {
this.close(); this.close();
@ -122,9 +143,10 @@ export class ModalComponent implements OnDestroy {
.pipe( .pipe(
takeUntil(this.destroy$), takeUntil(this.destroy$),
filter(() => !!(this.closable && this.modalContent)), filter(() => !!(this.closable && this.modalContent)),
debounceTime(350),
) )
.subscribe(() => this.close()); .subscribe(() => this.close());
this.init.emit();
} }
close() { close() {
@ -139,7 +161,7 @@ export class ModalComponent implements OnDestroy {
this.confirmationService this.confirmationService
.warn('AbpAccount::AreYouSureYouWantToCancelEditingWarningMessage', 'AbpAccount::AreYouSure') .warn('AbpAccount::AreYouSureYouWantToCancelEditingWarningMessage', 'AbpAccount::AreYouSure')
.subscribe((status: Toaster.Status) => { .subscribe((status: Toaster.Status) => {
timer(400).subscribe(() => { timer(ANIMATION_TIMEOUT).subscribe(() => {
this.isOpenConfirmation = false; this.isOpenConfirmation = false;
}); });
@ -155,7 +177,7 @@ export class ModalComponent implements OnDestroy {
function getFlatNodes(nodes: NodeList): HTMLElement[] { function getFlatNodes(nodes: NodeList): HTMLElement[] {
return Array.from(nodes).reduce( return Array.from(nodes).reduce(
(acc, val) => [...acc, ...(val.childNodes && val.childNodes.length ? Array.from(val.childNodes) : [val])], (acc, val) => [...acc, ...(val.childNodes && val.childNodes.length ? getFlatNodes(val.childNodes) : [val])],
[], [],
); );
} }

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

@ -38,11 +38,11 @@ export default `
/* <animations */ /* <animations */
.fade-in-top { .fade-in-top {
animation: fadeInTop 0.4s ease-in-out; animation: fadeInTop 0.2s ease-in-out;
} }
.fade-out-top { .fade-out-top {
animation: fadeOutTop 0.4s ease-in-out; animation: fadeOutTop 0.2s ease-in-out;
} }

3
npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts

@ -14,6 +14,7 @@ import { Observable } from 'rxjs';
import { ErrorComponent } from '../components/errors/error.component'; import { ErrorComponent } from '../components/errors/error.component';
import { Toaster } from '../models/toaster'; import { Toaster } from '../models/toaster';
import { ConfirmationService } from '../services/confirmation.service'; import { ConfirmationService } from '../services/confirmation.service';
import snq from 'snq';
const DEFAULTS = { const DEFAULTS = {
defaultError: { defaultError: {
@ -50,7 +51,7 @@ export class ErrorHandler {
) { ) {
actions.pipe(ofActionSuccessful(RestOccurError)).subscribe(res => { actions.pipe(ofActionSuccessful(RestOccurError)).subscribe(res => {
const { payload: err = {} as HttpErrorResponse | any } = res; const { payload: err = {} as HttpErrorResponse | any } = res;
const body = (err as HttpErrorResponse).error.error; const body = snq(() => (err as HttpErrorResponse).error.error, DEFAULTS.defaultError.message);
if (err.headers.get('_AbpErrorFormat')) { if (err.headers.get('_AbpErrorFormat')) {
const confirmation$ = this.showError(null, null, body); const confirmation$ = this.showError(null, null, body);

8
npm/ng-packs/packages/theme-shared/src/lib/services/confirmation.service.ts

@ -1,10 +1,10 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { AbstractToasterClass } from '../abstracts/toaster'; import { AbstractToaster } from '../abstracts/toaster';
import { Confirmation } from '../models/confirmation'; import { Confirmation } from '../models/confirmation';
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class ConfirmationService extends AbstractToasterClass<Confirmation.Options> { export class ConfirmationService extends AbstractToaster<Confirmation.Options> {
protected key: string = 'abpConfirmation'; key: string = 'abpConfirmation';
protected sticky: boolean = true; sticky: boolean = true;
} }

4
npm/ng-packs/packages/theme-shared/src/lib/services/toaster.service.ts

@ -1,9 +1,9 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { AbstractToasterClass } from '../abstracts/toaster'; import { AbstractToaster } from '../abstracts/toaster';
import { Message } from 'primeng/components/common/message'; import { Message } from 'primeng/components/common/message';
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class ToasterService extends AbstractToasterClass { export class ToasterService extends AbstractToaster {
addAll(messages: Message[]): void { addAll(messages: Message[]): void {
this.messageService.addAll(messages.map(message => ({ key: this.key, ...message }))); this.messageService.addAll(messages.map(message => ({ key: this.key, ...message })));
} }

12
npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts

@ -13,6 +13,7 @@ import { ModalComponent } from './components/modal/modal.component';
import { ToastComponent } from './components/toast/toast.component'; import { ToastComponent } from './components/toast/toast.component';
import styles from './contants/styles'; import styles from './contants/styles';
import { ErrorHandler } from './handlers/error.handler'; import { ErrorHandler } from './handlers/error.handler';
import { ButtonComponent } from './components/button/button.component';
export function appendScript(injector: Injector) { export function appendScript(injector: Injector) {
const fn = function() { const fn = function() {
@ -41,8 +42,15 @@ export function appendScript(injector: Injector) {
targetSelector: '.form-group', targetSelector: '.form-group',
}), }),
], ],
declarations: [ConfirmationComponent, ToastComponent, ModalComponent, ErrorComponent, LoaderBarComponent], declarations: [
exports: [NgbModalModule, ConfirmationComponent, ToastComponent, ModalComponent, LoaderBarComponent], ButtonComponent,
ConfirmationComponent,
ToastComponent,
ModalComponent,
ErrorComponent,
LoaderBarComponent,
],
exports: [NgbModalModule, ButtonComponent, ConfirmationComponent, ToastComponent, ModalComponent, LoaderBarComponent],
entryComponents: [ErrorComponent], entryComponents: [ErrorComponent],
}) })
export class ThemeSharedModule { export class ThemeSharedModule {

1
npm/ng-packs/packages/theme-shared/src/public-api.ts

@ -3,6 +3,7 @@
*/ */
export * from './lib/theme-shared.module'; export * from './lib/theme-shared.module';
export * from './lib/animations';
export * from './lib/components'; export * from './lib/components';
export * from './lib/models'; export * from './lib/models';
export * from './lib/services'; export * from './lib/services';

2
npm/ng-packs/scripts/build.js

@ -35,4 +35,6 @@ import fse from 'fs-extra';
cwd: '../', cwd: '../',
}); });
}); });
process.exit(0);
})(); })();

3
npm/ng-packs/scripts/sync.js

@ -1,5 +1,4 @@
// ESM syntax is supported. // ESM syntax is supported.
import execa from 'execa';
import fse from 'fs-extra'; import fse from 'fs-extra';
(async () => { (async () => {
@ -21,4 +20,6 @@ import fse from 'fs-extra';
await fse.writeJSON(srcPackagePath, { ...srcPackage, version }, { spaces: 2 }); await fse.writeJSON(srcPackagePath, { ...srcPackage, version }, { spaces: 2 });
}); });
process.exit(0);
})(); })();

25
templates/app/angular/package.json

@ -17,14 +17,14 @@
"@abp/ng.identity": "^0.8.0", "@abp/ng.identity": "^0.8.0",
"@abp/ng.tenant-management": "^0.8.0", "@abp/ng.tenant-management": "^0.8.0",
"@abp/ng.theme.basic": "^0.8.0", "@abp/ng.theme.basic": "^0.8.0",
"@angular/animations": "~8.1.2", "@angular/animations": "~8.2.0",
"@angular/common": "~8.1.2", "@angular/common": "~8.2.0",
"@angular/compiler": "~8.1.2", "@angular/compiler": "~8.2.0",
"@angular/core": "~8.1.2", "@angular/core": "~8.2.0",
"@angular/forms": "~8.1.2", "@angular/forms": "~8.2.0",
"@angular/platform-browser": "~8.1.2", "@angular/platform-browser": "~8.2.0",
"@angular/platform-browser-dynamic": "~8.1.2", "@angular/platform-browser-dynamic": "~8.2.0",
"@angular/router": "~8.1.2", "@angular/router": "~8.2.0",
"@angularclass/hmr": "^2.1.3", "@angularclass/hmr": "^2.1.3",
"@ngxs/devtools-plugin": "^3.5.0", "@ngxs/devtools-plugin": "^3.5.0",
"@ngxs/hmr-plugin": "^3.5.0", "@ngxs/hmr-plugin": "^3.5.0",
@ -33,10 +33,10 @@
"zone.js": "~0.9.1" "zone.js": "~0.9.1"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "~0.801.2", "@angular-devkit/build-angular": "~0.802.0",
"@angular/cli": "~8.1.2", "@angular/cli": "~8.2.0",
"@angular/compiler-cli": "~8.1.2", "@angular/compiler-cli": "~8.2.0",
"@angular/language-service": "~8.1.2", "@angular/language-service": "~8.2.0",
"@types/jasmine": "~3.3.8", "@types/jasmine": "~3.3.8",
"@types/jasminewd2": "~2.0.3", "@types/jasminewd2": "~2.0.3",
"@types/node": "~8.9.4", "@types/node": "~8.9.4",
@ -48,6 +48,7 @@
"karma-coverage-istanbul-reporter": "~2.0.1", "karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~2.0.1", "karma-jasmine": "~2.0.1",
"karma-jasmine-html-reporter": "^1.4.0", "karma-jasmine-html-reporter": "^1.4.0",
"ngxs-schematic": "^1.1.5",
"protractor": "~5.4.0", "protractor": "~5.4.0",
"ts-node": "~7.0.0", "ts-node": "~7.0.0",
"tslint": "~5.15.0", "tslint": "~5.15.0",

4
templates/app/angular/src/app/app.component.ts

@ -7,6 +7,4 @@ import { Component } from '@angular/core';
<router-outlet></router-outlet> <router-outlet></router-outlet>
`, `,
}) })
export class AppComponent { export class AppComponent {}
title = 'myProjectName';
}

Loading…
Cancel
Save