Browse Source

refactor: fix all lint errors and update tslint.json

pull/1826/head
mehmet-erim 7 years ago
parent
commit
373a23a66b
  1. 1
      npm/ng-packs/.prettierrc
  2. 37
      npm/ng-packs/package.json
  3. 8
      npm/ng-packs/packages/account/src/lib/services/account.service.ts
  4. 8
      npm/ng-packs/packages/core/src/lib/abstracts/ng-model.component.ts
  5. 8
      npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts
  6. 5
      npm/ng-packs/packages/core/src/lib/directives/autofocus.directive.ts
  7. 9
      npm/ng-packs/packages/core/src/lib/directives/debounce.directive.ts
  8. 9
      npm/ng-packs/packages/core/src/lib/directives/for.directive.ts
  9. 16
      npm/ng-packs/packages/core/src/lib/directives/form-submit.directive.ts
  10. 5
      npm/ng-packs/packages/core/src/lib/directives/stop-propagation.directive.ts
  11. 10
      npm/ng-packs/packages/core/src/lib/directives/visibility.directive.ts
  12. 2
      npm/ng-packs/packages/core/src/lib/pipes/index.ts
  13. 11
      npm/ng-packs/packages/core/src/lib/pipes/localization.pipe.ts
  14. 17
      npm/ng-packs/packages/core/src/lib/pipes/sort.pipe.ts
  15. 20
      npm/ng-packs/packages/core/src/lib/plugins/config/config.plugin.ts
  16. 46
      npm/ng-packs/packages/core/src/lib/states/config.state.ts
  17. 45
      npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts
  18. 1
      npm/ng-packs/packages/core/src/lib/utils/common-utils.ts
  19. 3
      npm/ng-packs/packages/core/src/lib/utils/generator-utils.ts
  20. 4
      npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts
  21. 5
      npm/ng-packs/packages/core/src/lib/utils/rxjs-utils.ts
  22. 20
      npm/ng-packs/packages/feature-management/src/lib/components/feature-management/feature-management.component.ts
  23. 2
      npm/ng-packs/packages/feature-management/src/lib/states/index.ts
  24. 20
      npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.ts
  25. 34
      npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts
  26. 49
      npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts
  27. 2
      npm/ng-packs/packages/permission-management/src/lib/states/index.ts
  28. 40
      npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.ts
  29. 20
      npm/ng-packs/packages/tenant-management/src/lib/services/tenant-management.service.ts
  30. 29
      npm/ng-packs/packages/theme-basic/src/lib/components/application-layout/application-layout.component.ts
  31. 4
      npm/ng-packs/packages/theme-basic/src/lib/components/layout/layout.component.ts
  32. 2
      npm/ng-packs/packages/theme-basic/src/lib/constants/styles.ts
  33. 2
      npm/ng-packs/packages/theme-basic/src/lib/states/index.ts
  34. 20
      npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts
  35. 4
      npm/ng-packs/packages/theme-shared/package.json
  36. 6
      npm/ng-packs/packages/theme-shared/src/lib/abstracts/toaster.ts
  37. 10
      npm/ng-packs/packages/theme-shared/src/lib/animations/collapse.animations.ts
  38. 13
      npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.html
  39. 16
      npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.ts
  40. 10
      npm/ng-packs/packages/theme-shared/src/lib/components/button/button.component.ts
  41. 27
      npm/ng-packs/packages/theme-shared/src/lib/components/change-password/change-password.component.ts
  42. 26
      npm/ng-packs/packages/theme-shared/src/lib/components/chart/chart.component.ts
  43. 3
      npm/ng-packs/packages/theme-shared/src/lib/components/confirmation/confirmation.component.ts
  44. 22
      npm/ng-packs/packages/theme-shared/src/lib/components/error/error.component.html
  45. 27
      npm/ng-packs/packages/theme-shared/src/lib/components/error/error.component.ts
  46. 43
      npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts
  47. 48
      npm/ng-packs/packages/theme-shared/src/lib/components/modal/modal.component.ts
  48. 11
      npm/ng-packs/packages/theme-shared/src/lib/components/profile/profile.component.ts
  49. 7
      npm/ng-packs/packages/theme-shared/src/lib/components/table-empty-message/table-empty-message.component.ts
  50. 3
      npm/ng-packs/packages/theme-shared/src/lib/components/toast/toast.component.ts
  51. 2
      npm/ng-packs/packages/theme-shared/src/lib/contants/scripts.ts
  52. 8
      npm/ng-packs/packages/theme-shared/src/lib/services/confirmation.service.ts
  53. 4
      npm/ng-packs/packages/theme-shared/src/lib/tests/button.component.spec.ts
  54. 14
      npm/ng-packs/packages/theme-shared/src/lib/tests/error.handler.spec.ts
  55. 18
      npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts
  56. 14
      npm/ng-packs/packages/theme-shared/tslint.json
  57. 105
      npm/ng-packs/tslint.json

1
npm/ng-packs/.prettierrc

@ -1,3 +1,4 @@
{ {
"printWidth": 120,
"singleQuote": true "singleQuote": true
} }

37
npm/ng-packs/package.json

@ -3,28 +3,28 @@
"ng": "ng", "ng": "ng",
"symlink": "symlink", "symlink": "symlink",
"abpng": "abpng", "abpng": "abpng",
"commit": "ng lint && git-cz", "commit": "git-cz",
"lint": "ng lint" "lint": "ng lint --fix"
}, },
"devDependencies": { "devDependencies": {
"@abp/ng.core": "^0.9.0", "@abp/ng.core": "^0.9.0",
"@abp/ng.feature-management": "^0.9.0", "@abp/ng.feature-management": "^0.9.0",
"@abp/ng.permission-management": "^0.9.0", "@abp/ng.permission-management": "^0.9.0",
"@abp/ng.theme.shared": "^0.9.0", "@abp/ng.theme.shared": "^0.9.0",
"@angular-devkit/build-angular": "~0.803.5", "@angular-devkit/build-angular": "~0.803.6",
"@angular-devkit/build-ng-packagr": "~0.803.5", "@angular-devkit/build-ng-packagr": "~0.803.6",
"@angular/animations": "~8.2.7", "@angular/animations": "~8.2.8",
"@angular/cdk": "^8.0.1", "@angular/cdk": "^8.2.2",
"@angular/cli": "~8.3.5", "@angular/cli": "~8.3.6",
"@angular/common": "~8.1.2", "@angular/common": "~8.2.8",
"@angular/compiler-cli": "~8.2.7", "@angular/compiler-cli": "~8.2.8",
"@angular/compiler": "~8.2.7", "@angular/compiler": "~8.2.8",
"@angular/core": "~8.1.2", "@angular/core": "~8.2.8",
"@angular/forms": "~8.1.2", "@angular/forms": "~8.2.8",
"@angular/language-service": "~8.2.7", "@angular/language-service": "~8.2.8",
"@angular/platform-browser-dynamic": "~8.2.7", "@angular/platform-browser-dynamic": "~8.2.8",
"@angular/platform-browser": "~8.2.7", "@angular/platform-browser": "~8.2.8",
"@angular/router": "~8.1.2", "@angular/router": "~8.2.8",
"@ng-bootstrap/ng-bootstrap": "^5.1.0", "@ng-bootstrap/ng-bootstrap": "^5.1.0",
"@ngneat/spectator": "^4.3.2", "@ngneat/spectator": "^4.3.2",
"@ngx-validate/core": "^0.0.5", "@ngx-validate/core": "^0.0.5",
@ -55,7 +55,7 @@
"ngx-perfect-scrollbar": "^8.0.0", "ngx-perfect-scrollbar": "^8.0.0",
"ngxs-reset-plugin": "^1.2.0", "ngxs-reset-plugin": "^1.2.0",
"prettier": "^1.18.2", "prettier": "^1.18.2",
"primeicons": "^1.0.0", "primeicons": "^2.0.0",
"primeng": "^8.0.0", "primeng": "^8.0.0",
"protractor": "~5.4.0", "protractor": "~5.4.0",
"rxjs": "~6.4.0", "rxjs": "~6.4.0",
@ -77,7 +77,7 @@
}, },
"husky": { "husky": {
"hooks": { "hooks": {
"pre-commit": "lint-staged && touch index.js" "pre-commit": "lint-staged"
} }
}, },
"lint-staged": { "lint-staged": {
@ -86,6 +86,7 @@
"git add" "git add"
], ],
"*.ts": [ "*.ts": [
"prettier --write",
"tslint --fix", "tslint --fix",
"git add" "git add"
] ]

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

@ -4,7 +4,7 @@ import { RestService, Rest } from '@abp/ng.core';
import { RegisterResponse, RegisterRequest, TenantIdResponse } from '../models'; import { RegisterResponse, RegisterRequest, TenantIdResponse } from '../models';
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root'
}) })
export class AccountService { export class AccountService {
constructor(private rest: RestService) {} constructor(private rest: RestService) {}
@ -12,7 +12,7 @@ export class AccountService {
findTenant(tenantName: string): Observable<TenantIdResponse> { findTenant(tenantName: string): Observable<TenantIdResponse> {
const request: Rest.Request<null> = { const request: Rest.Request<null> = {
method: 'GET', method: 'GET',
url: `/api/abp/multi-tenancy/tenants/by-name/${tenantName}`, url: `/api/abp/multi-tenancy/tenants/by-name/${tenantName}`
}; };
return this.rest.request<null, TenantIdResponse>(request); return this.rest.request<null, TenantIdResponse>(request);
@ -21,8 +21,8 @@ export class AccountService {
register(body: RegisterRequest): Observable<RegisterResponse> { register(body: RegisterRequest): Observable<RegisterResponse> {
const request: Rest.Request<RegisterRequest> = { const request: Rest.Request<RegisterRequest> = {
method: 'POST', method: 'POST',
url: `/api/account/register`, url: '/api/account/register',
body, body
}; };
return this.rest.request<RegisterRequest, RegisterResponse>(request, { skipHandleError: true }); return this.rest.request<RegisterRequest, RegisterResponse>(request, { skipHandleError: true });

8
npm/ng-packs/packages/core/src/lib/abstracts/ng-model.component.ts

@ -1,13 +1,11 @@
import { ControlValueAccessor } from '@angular/forms'; import { ControlValueAccessor } from '@angular/forms';
import { ChangeDetectorRef, Component, Injector, Input, Type } from '@angular/core'; import { ChangeDetectorRef, Component, Injector, Input, Type } from '@angular/core';
@Component({ template: '' }) @Component({ selector: 'abp-abstract-ng-model', template: '' })
export class AbstractNgModelComponent<T = any> implements ControlValueAccessor { export class AbstractNgModelComponent<T = any> implements ControlValueAccessor {
@Input() @Input() disabled: boolean;
disabled: boolean;
@Input() @Input() set value(value: T) {
set value(value: T) {
this._value = value; this._value = value;
this.notifyValueChange(); this.notifyValueChange();
} }

8
npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts

@ -13,21 +13,19 @@ import { takeUntilDestroy } from '../utils/rxjs-utils';
selector: 'abp-dynamic-layout', selector: 'abp-dynamic-layout',
template: ` template: `
<ng-container *ngTemplateOutlet="layout ? componentOutlet : routerOutlet"></ng-container> <ng-container *ngTemplateOutlet="layout ? componentOutlet : routerOutlet"></ng-container>
<ng-template #routerOutlet><router-outlet></router-outlet></ng-template> <ng-template #routerOutlet><router-outlet></router-outlet></ng-template>
<ng-template #componentOutlet><ng-container *ngComponentOutlet="layout"></ng-container></ng-template> <ng-template #componentOutlet><ng-container *ngComponentOutlet="layout"></ng-container></ng-template>
`, `
}) })
export class DynamicLayoutComponent implements OnDestroy { export class DynamicLayoutComponent implements OnDestroy {
@Select(ConfigState.getOne('requirements')) @Select(ConfigState.getOne('requirements')) requirements$: Observable<Config.Requirements>;
requirements$: Observable<Config.Requirements>;
layout: Type<any>; layout: Type<any>;
constructor(private router: Router, private route: ActivatedRoute, private store: Store) { constructor(private router: Router, private route: ActivatedRoute, private store: Store) {
const { const {
requirements: { layouts }, requirements: { layouts },
routes, routes
} = this.store.selectSnapshot(ConfigState.getAll); } = this.store.selectSnapshot(ConfigState.getAll);
if ((this.route.snapshot.data || {}).layout) { if ((this.route.snapshot.data || {}).layout) {

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

@ -1,11 +1,12 @@
import { Directive, ElementRef, Input, AfterViewInit } from '@angular/core'; import { Directive, ElementRef, Input, AfterViewInit } from '@angular/core';
@Directive({ @Directive({
selector: '[autofocus]', // tslint:disable-next-line: directive-selector
selector: '[autofocus]'
}) })
export class AutofocusDirective implements AfterViewInit { export class AutofocusDirective implements AfterViewInit {
@Input('autofocus') @Input('autofocus')
delay: number = 0; delay = 0;
constructor(private elRef: ElementRef) {} constructor(private elRef: ElementRef) {}

9
npm/ng-packs/packages/core/src/lib/directives/debounce.directive.ts

@ -4,12 +4,13 @@ import { debounceTime } from 'rxjs/operators';
import { takeUntilDestroy } from '@ngx-validate/core'; import { takeUntilDestroy } from '@ngx-validate/core';
@Directive({ @Directive({
selector: '[input.debounce]', // tslint:disable-next-line: directive-selector
selector: '[input.debounce]'
}) })
export class InputEventDebounceDirective implements OnInit { export class InputEventDebounceDirective implements OnInit {
@Input() debounce: number = 300; @Input() debounce = 300;
@Output('input.debounce') debounceEvent = new EventEmitter<Event>(); @Output('input.debounce') readonly debounceEvent = new EventEmitter<Event>();
constructor(private renderer: Renderer2, private el: ElementRef) {} constructor(private renderer: Renderer2, private el: ElementRef) {}
@ -17,7 +18,7 @@ export class InputEventDebounceDirective implements OnInit {
fromEvent(this.el.nativeElement, 'input') fromEvent(this.el.nativeElement, 'input')
.pipe( .pipe(
debounceTime(this.debounce), debounceTime(this.debounce),
takeUntilDestroy(this), takeUntilDestroy(this)
) )
.subscribe((event: Event) => { .subscribe((event: Event) => {
this.debounceEvent.emit(event); this.debounceEvent.emit(event);

9
npm/ng-packs/packages/core/src/lib/directives/for.directive.ts

@ -9,7 +9,7 @@ import {
OnChanges, OnChanges,
TemplateRef, TemplateRef,
TrackByFunction, TrackByFunction,
ViewContainerRef, ViewContainerRef
} from '@angular/core'; } from '@angular/core';
import compare from 'just-compare'; import compare from 'just-compare';
import clone from 'just-clone'; import clone from 'just-clone';
@ -25,7 +25,7 @@ class RecordView {
} }
@Directive({ @Directive({
selector: '[abpFor]', selector: '[abpFor]'
}) })
export class ForDirective implements OnChanges { export class ForDirective implements OnChanges {
@Input('abpForOf') @Input('abpForOf')
@ -67,7 +67,7 @@ export class ForDirective implements OnChanges {
constructor( constructor(
private tempRef: TemplateRef<AbpForContext>, private tempRef: TemplateRef<AbpForContext>,
private vcRef: ViewContainerRef, private vcRef: ViewContainerRef,
private differs: IterableDiffers, private differs: IterableDiffers
) {} ) {}
private iterateOverAppliedOperations(changes: IterableChanges<any>) { private iterateOverAppliedOperations(changes: IterableChanges<any>) {
@ -78,7 +78,7 @@ export class ForDirective implements OnChanges {
const view = this.vcRef.createEmbeddedView( const view = this.vcRef.createEmbeddedView(
this.tempRef, this.tempRef,
new AbpForContext(null, -1, -1, this.items), new AbpForContext(null, -1, -1, this.items),
currentIndex, currentIndex
); );
rw.push(new RecordView(record, view)); rw.push(new RecordView(record, view));
@ -114,6 +114,7 @@ export class ForDirective implements OnChanges {
private projectItems(items: any[]): void { private projectItems(items: any[]): void {
if (!items.length && this.emptyRef) { if (!items.length && this.emptyRef) {
this.vcRef.clear(); this.vcRef.clear();
// tslint:disable-next-line: no-unused-expression
this.vcRef.createEmbeddedView(this.emptyRef).rootNodes; this.vcRef.createEmbeddedView(this.emptyRef).rootNodes;
this.isShowEmptyRef = true; this.isShowEmptyRef = true;
this.differ = null; this.differ = null;

16
npm/ng-packs/packages/core/src/lib/directives/form-submit.directive.ts

@ -7,7 +7,7 @@ import {
OnDestroy, OnDestroy,
OnInit, OnInit,
Output, Output,
Self, Self
} from '@angular/core'; } from '@angular/core';
import { FormControl, FormGroup, FormGroupDirective } from '@angular/forms'; import { FormControl, FormGroup, FormGroupDirective } from '@angular/forms';
import { fromEvent } from 'rxjs'; import { fromEvent } from 'rxjs';
@ -17,21 +17,21 @@ import { takeUntilDestroy } from '../utils';
type Controls = { [key: string]: FormControl } | FormGroup[]; type Controls = { [key: string]: FormControl } | FormGroup[];
@Directive({ @Directive({
selector: 'form[ngSubmit][formGroup]', // tslint:disable-next-line: directive-selector
selector: 'form[ngSubmit][formGroup]'
}) })
export class FormSubmitDirective implements OnInit, OnDestroy { export class FormSubmitDirective implements OnInit, OnDestroy {
@Input() @Input()
notValidateOnSubmit: string | boolean; notValidateOnSubmit: string | boolean;
@Output() @Output() readonly ngSubmit = new EventEmitter();
ngSubmit = new EventEmitter();
executedNgSubmit: boolean = false; executedNgSubmit = false;
constructor( constructor(
@Self() private formGroupDirective: FormGroupDirective, @Self() private formGroupDirective: FormGroupDirective,
private host: ElementRef<HTMLFormElement>, private host: ElementRef<HTMLFormElement>,
private cdRef: ChangeDetectorRef, private cdRef: ChangeDetectorRef
) {} ) {}
ngOnInit() { ngOnInit() {
@ -44,7 +44,7 @@ export class FormSubmitDirective implements OnInit, OnDestroy {
.pipe( .pipe(
debounceTime(200), debounceTime(200),
filter((key: KeyboardEvent) => key && key.key === 'Enter'), filter((key: KeyboardEvent) => key && key.key === 'Enter'),
takeUntilDestroy(this), takeUntilDestroy(this)
) )
.subscribe(() => { .subscribe(() => {
if (!this.executedNgSubmit) { if (!this.executedNgSubmit) {
@ -57,7 +57,7 @@ export class FormSubmitDirective implements OnInit, OnDestroy {
fromEvent(this.host.nativeElement, 'submit') fromEvent(this.host.nativeElement, 'submit')
.pipe( .pipe(
takeUntilDestroy(this), takeUntilDestroy(this),
filter(() => !this.notValidateOnSubmit && typeof this.notValidateOnSubmit !== 'string'), filter(() => !this.notValidateOnSubmit && typeof this.notValidateOnSubmit !== 'string')
) )
.subscribe(() => { .subscribe(() => {
if (!this.executedNgSubmit) { if (!this.executedNgSubmit) {

5
npm/ng-packs/packages/core/src/lib/directives/stop-propagation.directive.ts

@ -3,10 +3,11 @@ import { fromEvent } from 'rxjs';
import { takeUntilDestroy } from '@ngx-validate/core'; import { takeUntilDestroy } from '@ngx-validate/core';
@Directive({ @Directive({
selector: '[click.stop]', // tslint:disable-next-line: directive-selector
selector: '[click.stop]'
}) })
export class ClickEventStopPropagationDirective implements OnInit { export class ClickEventStopPropagationDirective implements OnInit {
@Output('click.stop') stopPropEvent = new EventEmitter<MouseEvent>(); @Output('click.stop') readonly stopPropEvent = new EventEmitter<MouseEvent>();
constructor(private renderer: Renderer2, private el: ElementRef) {} constructor(private renderer: Renderer2, private el: ElementRef) {}

10
npm/ng-packs/packages/core/src/lib/directives/visibility.directive.ts

@ -3,14 +3,14 @@ import { Subject } from 'rxjs';
import snq from 'snq'; import snq from 'snq';
@Directive({ @Directive({
selector: '[abpVisibility]', selector: '[abpVisibility]'
}) })
export class VisibilityDirective implements AfterViewInit { export class VisibilityDirective implements AfterViewInit {
@Input('abpVisibility') @Input('abpVisibility')
focusedElement: HTMLElement; focusedElement: HTMLElement;
@Input() @Input()
mutationObserverEnabled: boolean = true; mutationObserverEnabled = true;
completed$ = new Subject<boolean>(); completed$ = new Subject<boolean>();
@ -25,7 +25,7 @@ export class VisibilityDirective implements AfterViewInit {
const htmlNodes = snq( const htmlNodes = snq(
() => Array.from(mutation.target.childNodes).filter(node => node instanceof HTMLElement), () => Array.from(mutation.target.childNodes).filter(node => node instanceof HTMLElement),
[], []
); );
if (!htmlNodes.length) { if (!htmlNodes.length) {
@ -40,13 +40,13 @@ export class VisibilityDirective implements AfterViewInit {
}); });
observer.observe(this.focusedElement, { observer.observe(this.focusedElement, {
childList: true, childList: true
}); });
} else { } else {
setTimeout(() => { setTimeout(() => {
const htmlNodes = snq( const htmlNodes = snq(
() => Array.from(this.focusedElement.childNodes).filter(node => node instanceof HTMLElement), () => Array.from(this.focusedElement.childNodes).filter(node => node instanceof HTMLElement),
[], []
); );
if (!htmlNodes.length) this.removeFromDOM(); if (!htmlNodes.length) this.removeFromDOM();

2
npm/ng-packs/packages/core/src/lib/pipes/index.ts

@ -1,2 +1,2 @@
export * from './localization.pipe'; export * from './localization.pipe';
export * from "./sort.pipe"; export * from './sort.pipe';

11
npm/ng-packs/packages/core/src/lib/pipes/localization.pipe.ts

@ -7,10 +7,11 @@ import { Subject } from 'rxjs';
@Pipe({ @Pipe({
name: 'abpLocalization', name: 'abpLocalization',
pure: false, // required to update the value // tslint:disable-next-line: no-pipe-impure
pure: false // required to update the value
}) })
export class LocalizationPipe implements PipeTransform, OnDestroy { export class LocalizationPipe implements PipeTransform, OnDestroy {
initialValue: string = ''; initialValue = '';
value: string; value: string;
@ -27,13 +28,13 @@ export class LocalizationPipe implements PipeTransform, OnDestroy {
.select( .select(
ConfigState.getCopy( ConfigState.getCopy(
value, value,
...interpolateParams.reduce((acc, val) => (Array.isArray(val) ? [...acc, ...val] : [...acc, val]), []), ...interpolateParams.reduce((acc, val) => (Array.isArray(val) ? [...acc, ...val] : [...acc, val]), [])
), )
) )
.pipe( .pipe(
takeUntil(this.destroy$), takeUntil(this.destroy$),
takeUntilDestroy(this), takeUntilDestroy(this),
distinctUntilChanged(), distinctUntilChanged()
) )
.subscribe(copy => (this.value = copy)); .subscribe(copy => (this.value = copy));
} }

17
npm/ng-packs/packages/core/src/lib/pipes/sort.pipe.ts

@ -1,13 +1,14 @@
import { Pipe, PipeTransform } from '@angular/core'; import { Pipe, PipeTransform } from '@angular/core';
@Pipe({ @Pipe({
name: 'abpSort', name: 'abpSort',
pure: false // tslint:disable-next-line: no-pipe-impure
pure: false
}) })
export class SortPipe implements PipeTransform { export class SortPipe implements PipeTransform {
transform(value: any[], sortOrder: string): any { transform(value: any[], sortOrder: string): any {
sortOrder = sortOrder.toLowerCase(); sortOrder = sortOrder.toLowerCase();
if(sortOrder === "desc") return value.reverse(); if (sortOrder === 'desc') return value.reverse();
else return value; else return value;
} }
} }

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

@ -12,7 +12,7 @@ export let ABP_ROUTES = [] as ABP.FullRoute[];
@Injectable() @Injectable()
export class ConfigPlugin implements NgxsPlugin { export class ConfigPlugin implements NgxsPlugin {
private initialized: boolean = false; private initialized = false;
constructor(@Inject(NGXS_CONFIG_PLUGIN_OPTIONS) private options: ABP.Root, private router: Router) {} constructor(@Inject(NGXS_CONFIG_PLUGIN_OPTIONS) private options: ABP.Root, private router: Router) {}
@ -22,14 +22,17 @@ export class ConfigPlugin implements NgxsPlugin {
// const layouts = snq(() => this.options.requirements.layouts.filter(layout => layout instanceof Type), []); // const layouts = snq(() => this.options.requirements.layouts.filter(layout => layout instanceof Type), []);
if (isInitAction && !this.initialized) { if (isInitAction && !this.initialized) {
let { routes, wrappers } = transformRoutes(this.router.config); const transformedRoutes = transformRoutes(this.router.config);
let { routes } = transformedRoutes;
const { wrappers } = transformedRoutes;
routes = organizeRoutes(routes, wrappers); routes = organizeRoutes(routes, wrappers);
const flattedRoutes = flatRoutes(clone(routes)); const flattedRoutes = flatRoutes(clone(routes));
state = setValue(state, 'ConfigState', { state = setValue(state, 'ConfigState', {
...(state.ConfigState && { ...state.ConfigState }), ...(state.ConfigState && { ...state.ConfigState }),
...this.options, ...this.options,
routes, routes,
flattedRoutes, flattedRoutes
}); });
this.initialized = true; this.initialized = true;
@ -49,6 +52,7 @@ function transformRoutes(routes: Routes = [], wrappers: ABP.FullRoute[] = []): a
return snq(() => route.data.routes.routes.find(r => r.path === route.path), false); return snq(() => route.data.routes.routes.find(r => r.path === route.path), false);
}) })
.reduce((acc, val) => [...acc, ...val.data.routes.routes], []); .reduce((acc, val) => [...acc, ...val.data.routes.routes], []);
// tslint:disable-next-line: deprecation
ABP_ROUTES = [...ABP_ROUTES, ...abpRoutes]; ABP_ROUTES = [...ABP_ROUTES, ...abpRoutes];
wrappers = ABP_ROUTES.filter(ar => ar.wrapper); wrappers = ABP_ROUTES.filter(ar => ar.wrapper);
@ -69,7 +73,7 @@ function transformRoutes(routes: Routes = [], wrappers: ABP.FullRoute[] = []): a
...route.data.routes, ...route.data.routes,
path: route.path, path: route.path,
name: snq(() => route.data.routes.name, route.path), name: snq(() => route.data.routes.name, route.path),
children: route.data.routes.children || [], children: route.data.routes.children || []
} as ABP.FullRoute); } as ABP.FullRoute);
} }
}); });
@ -86,8 +90,8 @@ function setUrls(routes: ABP.FullRoute[], parentUrl?: string): ABP.FullRoute[] {
url: `${parentUrl}/${route.path}`, url: `${parentUrl}/${route.path}`,
...(route.children && ...(route.children &&
route.children.length && { route.children.length && {
children: setUrls(route.children, `${parentUrl}/${route.path}`), children: setUrls(route.children, `${parentUrl}/${route.path}`)
}), })
})); }));
} }
@ -96,8 +100,8 @@ function setUrls(routes: ABP.FullRoute[], parentUrl?: string): ABP.FullRoute[] {
url: `/${route.path}`, url: `/${route.path}`,
...(route.children && ...(route.children &&
route.children.length && { route.children.length && {
children: setUrls(route.children, `/${route.path}`), children: setUrls(route.children, `/${route.path}`)
}), })
})); }));
} }

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

@ -11,7 +11,7 @@ import { setChildRoute, sortRoutes, organizeRoutes } from '../utils/route-utils'
@State<Config.State>({ @State<Config.State>({
name: 'ConfigState', name: 'ConfigState',
defaults: {} as Config.State, defaults: {} as Config.State
}) })
export class ConfigState { export class ConfigState {
@Selector() @Selector()
@ -27,9 +27,9 @@ export class ConfigState {
static getOne(key: string) { static getOne(key: string) {
const selector = createSelector( const selector = createSelector(
[ConfigState], [ConfigState],
function(state: Config.State) { (state: Config.State) => {
return state[key]; return state[key];
}, }
); );
return selector; return selector;
@ -46,7 +46,7 @@ export class ConfigState {
const selector = createSelector( const selector = createSelector(
[ConfigState], [ConfigState],
function(state: Config.State) { (state: Config.State) => {
return (keys as string[]).reduce((acc, val) => { return (keys as string[]).reduce((acc, val) => {
if (acc) { if (acc) {
return acc[val]; return acc[val];
@ -54,7 +54,7 @@ export class ConfigState {
return undefined; return undefined;
}, state); }, state);
}, }
); );
return selector; return selector;
@ -63,7 +63,7 @@ export class ConfigState {
static getRoute(path?: string, name?: string) { static getRoute(path?: string, name?: string) {
const selector = createSelector( const selector = createSelector(
[ConfigState], [ConfigState],
function(state: Config.State) { (state: Config.State) => {
const { flattedRoutes } = state; const { flattedRoutes } = state;
return (flattedRoutes as ABP.FullRoute[]).find(route => { return (flattedRoutes as ABP.FullRoute[]).find(route => {
if (path && route.path === path) { if (path && route.path === path) {
@ -72,7 +72,7 @@ export class ConfigState {
return route; return route;
} }
}); });
}, }
); );
return selector; return selector;
@ -81,9 +81,9 @@ export class ConfigState {
static getApiUrl(key?: string) { static getApiUrl(key?: string) {
const selector = createSelector( const selector = createSelector(
[ConfigState], [ConfigState],
function(state: Config.State): string { (state: Config.State): string => {
return state.environment.apis[key || 'default'].url; return state.environment.apis[key || 'default'].url;
}, }
); );
return selector; return selector;
@ -92,9 +92,9 @@ export class ConfigState {
static getSetting(key: string) { static getSetting(key: string) {
const selector = createSelector( const selector = createSelector(
[ConfigState], [ConfigState],
function(state: Config.State) { (state: Config.State) => {
return snq(() => state.setting.values[key]); return snq(() => state.setting.values[key]);
}, }
); );
return selector; return selector;
@ -103,10 +103,10 @@ export class ConfigState {
static getGrantedPolicy(key: string) { static getGrantedPolicy(key: string) {
const selector = createSelector( const selector = createSelector(
[ConfigState], [ConfigState],
function(state: Config.State): boolean { (state: Config.State): boolean => {
if (!key) return true; if (!key) return true;
return snq(() => state.auth.grantedPolicies[key], false); return snq(() => state.auth.grantedPolicies[key], false);
}, }
); );
return selector; return selector;
@ -118,20 +118,20 @@ export class ConfigState {
const keys = key.split('::') as string[]; const keys = key.split('::') as string[];
const selector = createSelector( const selector = createSelector(
[ConfigState], [ConfigState],
function(state: Config.State) { (state: Config.State) => {
if (!state.localization) return key; if (!state.localization) return key;
const { defaultResourceName } = state.environment.localization; const { defaultResourceName } = state.environment.localization;
if (keys[0] === '') { if (keys[0] === '') {
if (!defaultResourceName) { if (!defaultResourceName) {
throw new Error( throw new Error(
`Please check your environment. May you forget set defaultResourceName? `Please check your environment. May you forget set defaultResourceName?
Here is the example: Here is the example:
{ production: false, { production: false,
localization: { localization: {
defaultResourceName: 'MyProjectName' defaultResourceName: 'MyProjectName'
} }
}`, }`
); );
} }
@ -154,7 +154,7 @@ export class ConfigState {
} }
return copy || key; return copy || key;
}, }
); );
return selector; return selector;
@ -167,8 +167,8 @@ export class ConfigState {
return this.appConfigurationService.getConfiguration().pipe( return this.appConfigurationService.getConfiguration().pipe(
tap(configuration => tap(configuration =>
patchState({ patchState({
...configuration, ...configuration
}), })
), ),
switchMap(configuration => { switchMap(configuration => {
let defaultLang: string = configuration.setting.values['Abp.Localization.DefaultLanguage']; let defaultLang: string = configuration.setting.values['Abp.Localization.DefaultLanguage'];
@ -178,7 +178,7 @@ export class ConfigState {
} }
return this.store.selectSnapshot(SessionState.getLanguage) ? of(null) : dispatch(new SetLanguage(defaultLang)); return this.store.selectSnapshot(SessionState.getLanguage) ? of(null) : dispatch(new SetLanguage(defaultLang));
}), })
); );
} }
@ -191,7 +191,7 @@ export class ConfigState {
routes = patchRouteDeep(routes, name, newValue); routes = patchRouteDeep(routes, name, newValue);
return patchState({ return patchState({
routes, routes
}); });
} }
} }
@ -200,7 +200,7 @@ function patchRouteDeep(
routes: ABP.FullRoute[], routes: ABP.FullRoute[],
name: string, name: string,
newValue: Partial<ABP.FullRoute>, newValue: Partial<ABP.FullRoute>,
parentUrl: string = null, parentUrl: string = null
): ABP.FullRoute[] { ): ABP.FullRoute[] {
routes = routes.map(route => { routes = routes.map(route => {
if (route.name === name) { if (route.name === name) {
@ -211,7 +211,7 @@ function patchRouteDeep(
if (newValue.children && newValue.children.length) { if (newValue.children && newValue.children.length) {
newValue.children = newValue.children.map(child => ({ newValue.children = newValue.children.map(child => ({
...child, ...child,
url: `${parentUrl}/${route.path}/${child.path}`, url: `${parentUrl}/${route.path}/${child.path}`
})); }));
} }

45
npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts

@ -9,7 +9,10 @@ import { NgxsResetPluginModule, StateOverwrite } from 'ngxs-reset-plugin';
import { ThemeSharedModule } from '../../../../theme-shared/src/public-api'; import { ThemeSharedModule } from '../../../../theme-shared/src/public-api';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
@Component({ selector: 'dummy', template: '{{route.snapshot.data?.name}} works!' }) @Component({
selector: 'abp-dummy',
template: '{{route.snapshot.data?.name}} works!'
})
class DummyComponent { class DummyComponent {
constructor(public route: ActivatedRoute) {} constructor(public route: ActivatedRoute) {}
} }
@ -23,7 +26,7 @@ describe('DynamicLayoutComponent', () => {
NgxsModule.forRoot([ConfigState]), NgxsModule.forRoot([ConfigState]),
NgxsResetPluginModule.forRoot(), NgxsResetPluginModule.forRoot(),
ThemeSharedModule.forRoot(), ThemeSharedModule.forRoot(),
ThemeBasicModule, ThemeBasicModule
], ],
declarations: [DummyComponent], declarations: [DummyComponent],
stubsEnabled: false, stubsEnabled: false,
@ -37,14 +40,14 @@ describe('DynamicLayoutComponent', () => {
{ {
path: 'childWithoutLayout', path: 'childWithoutLayout',
component: DummyComponent, component: DummyComponent,
data: { name: 'childWithoutLayout' }, data: { name: 'childWithoutLayout' }
}, },
{ {
path: 'childWithLayout', path: 'childWithLayout',
component: DummyComponent, component: DummyComponent,
data: { name: 'childWithLayout' }, data: { name: 'childWithLayout' }
}, }
], ]
}, },
{ {
path: 'withData', path: 'withData',
@ -53,10 +56,10 @@ describe('DynamicLayoutComponent', () => {
{ {
path: '', path: '',
component: DummyComponent, component: DummyComponent,
data: { name: 'withData' }, data: { name: 'withData' }
}, }
], ],
data: { layout: eLayoutType.empty }, data: { layout: eLayoutType.empty }
}, },
{ {
path: 'withoutLayout', path: 'withoutLayout',
@ -65,12 +68,12 @@ describe('DynamicLayoutComponent', () => {
{ {
path: '', path: '',
component: DummyComponent, component: DummyComponent,
data: { name: 'withoutLayout' }, data: { name: 'withoutLayout' }
}, }
], ],
data: { layout: null }, data: { layout: null }
}, }
], ]
}); });
let spectator: SpectatorRouting<RouterOutletComponent>; let spectator: SpectatorRouting<RouterOutletComponent>;
@ -92,16 +95,16 @@ describe('DynamicLayoutComponent', () => {
{ {
path: 'parentWithLayout', path: 'parentWithLayout',
layout: eLayoutType.application, layout: eLayoutType.application,
children: [{ path: 'childWithoutLayout' }, { path: 'childWithLayout', layout: eLayoutType.account }], children: [{ path: 'childWithoutLayout' }, { path: 'childWithLayout', layout: eLayoutType.account }]
}, }
], ]
}, },
{ path: 'withData', layout: eLayoutType.application }, { path: 'withData', layout: eLayoutType.application },
, ,
] as ABP.FullRoute[], ] as ABP.FullRoute[],
environment: { application: {} }, environment: { application: {} }
}, }
]), ])
); );
}); });
@ -136,7 +139,7 @@ describe('DynamicLayoutComponent', () => {
it('should not display any layout when layouts are empty', async () => { it('should not display any layout when layouts are empty', async () => {
store.dispatch( store.dispatch(
new StateOverwrite([ConfigState, { ...store.selectSnapshot(ConfigState), requirements: { layouts: [] } }]), new StateOverwrite([ConfigState, { ...store.selectSnapshot(ConfigState), requirements: { layouts: [] } }])
); );
spectator.detectChanges(); spectator.detectChanges();

1
npm/ng-packs/packages/core/src/lib/utils/common-utils.ts

@ -1,4 +1,5 @@
export function noop() { export function noop() {
// tslint:disable-next-line: only-arrow-functions
const fn = function() {}; const fn = function() {};
return fn; return fn;
} }

3
npm/ng-packs/packages/core/src/lib/utils/generator-utils.ts

@ -1,5 +1,6 @@
export function uuid(a?: any): string { export function uuid(a?: any): string {
return a return a
? (a ^ ((Math.random() * 16) >> (a / 4))).toString(16) ? // tslint:disable-next-line: no-bitwise
(a ^ ((Math.random() * 16) >> (a / 4))).toString(16)
: ('' + 1e7 + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, uuid); : ('' + 1e7 + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, uuid);
} }

4
npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts

@ -6,7 +6,7 @@ import differentLocales from '../constants/different-locales';
import { SessionState } from '../states/session.state'; import { SessionState } from '../states/session.state';
export function getInitialData(injector: Injector) { export function getInitialData(injector: Injector) {
const fn = function() { const fn = () => {
const store: Store = injector.get(Store); const store: Store = injector.get(Store);
return store.dispatch(new GetAppConfiguration()).toPromise(); return store.dispatch(new GetAppConfiguration()).toPromise();
@ -16,7 +16,7 @@ export function getInitialData(injector: Injector) {
} }
export function localeInitializer(injector: Injector) { export function localeInitializer(injector: Injector) {
const fn = function() { const fn = () => {
const store: Store = injector.get(Store); const store: Store = injector.get(Store);
const lang = store.selectSnapshot(SessionState.getLanguage) || 'en'; const lang = store.selectSnapshot(SessionState.getLanguage) || 'en';

5
npm/ng-packs/packages/core/src/lib/utils/rxjs-utils.ts

@ -6,18 +6,19 @@ function isFunction(value) {
} }
export const takeUntilDestroy = (componentInstance, destroyMethodName = 'ngOnDestroy') => <T>( export const takeUntilDestroy = (componentInstance, destroyMethodName = 'ngOnDestroy') => <T>(
source: Observable<T>, source: Observable<T>
) => { ) => {
const originalDestroy = componentInstance[destroyMethodName]; const originalDestroy = componentInstance[destroyMethodName];
if (isFunction(originalDestroy) === false) { if (isFunction(originalDestroy) === false) {
throw new Error( throw new Error(
`${componentInstance.constructor.name} is using untilDestroyed but doesn't implement ${destroyMethodName}`, `${componentInstance.constructor.name} is using untilDestroyed but doesn't implement ${destroyMethodName}`
); );
} }
if (!componentInstance['__takeUntilDestroy']) { if (!componentInstance['__takeUntilDestroy']) {
componentInstance['__takeUntilDestroy'] = new Subject(); componentInstance['__takeUntilDestroy'] = new Subject();
componentInstance[destroyMethodName] = function() { componentInstance[destroyMethodName] = function() {
// tslint:disable-next-line: no-unused-expression
isFunction(originalDestroy) && originalDestroy.apply(this, arguments); isFunction(originalDestroy) && originalDestroy.apply(this, arguments);
componentInstance['__takeUntilDestroy'].next(true); componentInstance['__takeUntilDestroy'].next(true);
componentInstance['__takeUntilDestroy'].complete(); componentInstance['__takeUntilDestroy'].complete();

20
npm/ng-packs/packages/feature-management/src/lib/components/feature-management/feature-management.component.ts

@ -9,7 +9,7 @@ import { pluck, tap } from 'rxjs/operators';
@Component({ @Component({
selector: 'abp-feature-management', selector: 'abp-feature-management',
templateUrl: './feature-management.component.html', templateUrl: './feature-management.component.html'
}) })
export class FeatureManagementComponent { export class FeatureManagementComponent {
@Input() @Input()
@ -32,13 +32,12 @@ export class FeatureManagementComponent {
if (value) this.openModal(); if (value) this.openModal();
} }
@Output() @Output() readonly visibleChange = new EventEmitter<boolean>();
visibleChange = new EventEmitter<boolean>();
@Select(FeatureManagementState.getFeatures) @Select(FeatureManagementState.getFeatures)
features$: Observable<FeatureManagement.Feature[]>; features$: Observable<FeatureManagement.Feature[]>;
modalBusy: boolean = false; modalBusy = false;
form: FormGroup; form: FormGroup;
@ -54,7 +53,12 @@ export class FeatureManagementComponent {
getFeatures() { getFeatures() {
this.store this.store
.dispatch(new GetFeatures({ providerKey: this.providerKey, providerName: this.providerName })) .dispatch(
new GetFeatures({
providerKey: this.providerKey,
providerName: this.providerName
})
)
.pipe(pluck('FeatureManagementState', 'features')) .pipe(pluck('FeatureManagementState', 'features'))
.subscribe(features => { .subscribe(features => {
this.buildForm(features); this.buildForm(features);
@ -78,7 +82,7 @@ export class FeatureManagementComponent {
features = features.map((feature, i) => ({ features = features.map((feature, i) => ({
name: feature.name, name: feature.name,
value: !this.form.value[i] || this.form.value[i] === 'false' ? null : this.form.value[i], value: !this.form.value[i] || this.form.value[i] === 'false' ? null : this.form.value[i]
})); }));
this.store this.store
@ -86,8 +90,8 @@ export class FeatureManagementComponent {
new UpdateFeatures({ new UpdateFeatures({
providerKey: this.providerKey, providerKey: this.providerKey,
providerName: this.providerName, providerName: this.providerName,
features, features
}), })
) )
.subscribe(() => { .subscribe(() => {
this.modalBusy = false; this.modalBusy = false;

2
npm/ng-packs/packages/feature-management/src/lib/states/index.ts

@ -1 +1 @@
export * from "./feature-management.state"; export * from './feature-management.state';

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

@ -11,7 +11,7 @@ import { IdentityState } from '../../states/identity.state';
@Component({ @Component({
selector: 'abp-roles', selector: 'abp-roles',
templateUrl: './roles.component.html', templateUrl: './roles.component.html'
}) })
export class RolesComponent { export class RolesComponent {
@Select(IdentityState.getRoles) @Select(IdentityState.getRoles)
@ -26,19 +26,19 @@ export class RolesComponent {
isModalVisible: boolean; isModalVisible: boolean;
visiblePermissions: boolean = false; visiblePermissions = false;
providerKey: string; providerKey: string;
pageQuery: ABP.PageQueryParams = { pageQuery: ABP.PageQueryParams = {
sorting: 'name', sorting: 'name'
}; };
loading: boolean = false; loading = false;
modalBusy: boolean = false; modalBusy = false;
sortOrder: string = 'asc'; sortOrder = 'asc';
@ViewChild('modalContent', { static: false }) @ViewChild('modalContent', { static: false })
modalContent: TemplateRef<any>; modalContent: TemplateRef<any>;
@ -54,10 +54,10 @@ export class RolesComponent {
this.form = this.fb.group({ this.form = this.fb.group({
name: new FormControl({ value: this.selected.name || '', disabled: this.selected.isStatic }, [ name: new FormControl({ value: this.selected.name || '', disabled: this.selected.isStatic }, [
Validators.required, Validators.required,
Validators.maxLength(256), Validators.maxLength(256)
]), ]),
isDefault: [this.selected.isDefault || false], isDefault: [this.selected.isDefault || false],
isPublic: [this.selected.isPublic || false], isPublic: [this.selected.isPublic || false]
}); });
} }
@ -89,7 +89,7 @@ export class RolesComponent {
.dispatch( .dispatch(
this.selected.id this.selected.id
? new UpdateRole({ ...this.form.value, id: this.selected.id }) ? new UpdateRole({ ...this.form.value, id: this.selected.id })
: new CreateRole(this.form.value), : new CreateRole(this.form.value)
) )
.subscribe(() => { .subscribe(() => {
this.modalBusy = false; this.modalBusy = false;
@ -100,7 +100,7 @@ export class RolesComponent {
delete(id: string, name: string) { delete(id: string, name: string) {
this.confirmationService this.confirmationService
.warn('AbpIdentity::RoleDeletionConfirmationMessage', 'AbpIdentity::AreYouSure', { .warn('AbpIdentity::RoleDeletionConfirmationMessage', 'AbpIdentity::AreYouSure', {
messageLocalizationParams: [name], messageLocalizationParams: [name]
}) })
.subscribe((status: Toaster.Status) => { .subscribe((status: Toaster.Status) => {
if (status === Toaster.Status.confirm) { if (status === Toaster.Status.confirm) {

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

@ -12,13 +12,13 @@ import {
GetUserById, GetUserById,
GetUserRoles, GetUserRoles,
GetUsers, GetUsers,
UpdateUser, UpdateUser
} from '../../actions/identity.actions'; } from '../../actions/identity.actions';
import { Identity } from '../../models/identity'; import { Identity } from '../../models/identity';
import { IdentityState } from '../../states/identity.state'; import { IdentityState } from '../../states/identity.state';
@Component({ @Component({
selector: 'abp-users', selector: 'abp-users',
templateUrl: './users.component.html', templateUrl: './users.component.html'
}) })
export class UsersComponent { export class UsersComponent {
@Select(IdentityState.getUsers) @Select(IdentityState.getUsers)
@ -38,21 +38,21 @@ export class UsersComponent {
roles: Identity.RoleItem[]; roles: Identity.RoleItem[];
visiblePermissions: boolean = false; visiblePermissions = false;
providerKey: string; providerKey: string;
pageQuery: ABP.PageQueryParams = { pageQuery: ABP.PageQueryParams = {
sorting: 'userName', sorting: 'userName'
}; };
isModalVisible: boolean; isModalVisible: boolean;
loading: boolean = false; loading = false;
modalBusy: boolean = false; modalBusy = false;
sortOrder: string = 'asc'; sortOrder = 'asc';
trackByFn: TrackByFunction<AbstractControl> = (index, item) => Object.keys(item)[0] || index; trackByFn: TrackByFunction<AbstractControl> = (index, item) => Object.keys(item)[0] || index;
@ -80,10 +80,10 @@ export class UsersComponent {
roleNames: this.fb.array( roleNames: this.fb.array(
this.roles.map(role => this.roles.map(role =>
this.fb.group({ this.fb.group({
[role.name]: [!!snq(() => this.selectedUserRoles.find(userRole => userRole.id === role.id))], [role.name]: [!!snq(() => this.selectedUserRoles.find(userRole => userRole.id === role.id))]
}), })
), )
), )
}); });
if (!this.selected.userName) { if (!this.selected.userName) {
this.form.addControl('password', new FormControl('', [Validators.required, Validators.maxLength(32)])); this.form.addControl('password', new FormControl('', [Validators.required, Validators.maxLength(32)]));
@ -107,7 +107,7 @@ export class UsersComponent {
.pipe( .pipe(
switchMap(() => this.store.dispatch(new GetUserRoles(id))), switchMap(() => this.store.dispatch(new GetUserRoles(id))),
pluck('IdentityState'), pluck('IdentityState'),
take(1), take(1)
) )
.subscribe((state: Identity.State) => { .subscribe((state: Identity.State) => {
this.selected = state.selectedUser; this.selected = state.selectedUser;
@ -123,7 +123,7 @@ export class UsersComponent {
const { roleNames } = this.form.value; const { roleNames } = this.form.value;
const mappedRoleNames = snq( const mappedRoleNames = snq(
() => roleNames.filter(role => !!role[Object.keys(role)[0]]).map(role => Object.keys(role)[0]), () => roleNames.filter(role => !!role[Object.keys(role)[0]]).map(role => Object.keys(role)[0]),
[], []
); );
this.store this.store
@ -132,12 +132,12 @@ export class UsersComponent {
? new UpdateUser({ ? new UpdateUser({
...this.form.value, ...this.form.value,
id: this.selected.id, id: this.selected.id,
roleNames: mappedRoleNames, roleNames: mappedRoleNames
}) })
: new CreateUser({ : new CreateUser({
...this.form.value, ...this.form.value,
roleNames: mappedRoleNames, roleNames: mappedRoleNames
}), })
) )
.subscribe(() => { .subscribe(() => {
this.modalBusy = false; this.modalBusy = false;
@ -148,7 +148,7 @@ export class UsersComponent {
delete(id: string, userName: string) { delete(id: string, userName: string) {
this.confirmationService this.confirmationService
.warn('AbpIdentity::UserDeletionConfirmationMessage', 'AbpIdentity::AreYouSure', { .warn('AbpIdentity::UserDeletionConfirmationMessage', 'AbpIdentity::AreYouSure', {
messageLocalizationParams: [userName], messageLocalizationParams: [userName]
}) })
.subscribe((status: Toaster.Status) => { .subscribe((status: Toaster.Status) => {
if (status === Toaster.Status.confirm) { if (status === Toaster.Status.confirm) {

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

@ -7,7 +7,7 @@ import {
Output, Output,
Renderer2, Renderer2,
SimpleChanges, SimpleChanges,
TrackByFunction, TrackByFunction
} from '@angular/core'; } from '@angular/core';
import { Select, Store } from '@ngxs/store'; import { Select, Store } from '@ngxs/store';
import { from, Observable } from 'rxjs'; import { from, Observable } from 'rxjs';
@ -16,11 +16,13 @@ import { GetPermissions, UpdatePermissions } from '../actions/permission-managem
import { PermissionManagement } from '../models/permission-management'; import { PermissionManagement } from '../models/permission-management';
import { PermissionManagementState } from '../states/permission-management.state'; import { PermissionManagementState } from '../states/permission-management.state';
type PermissionWithMargin = PermissionManagement.Permission & { margin: number }; type PermissionWithMargin = PermissionManagement.Permission & {
margin: number;
};
@Component({ @Component({
selector: 'abp-permission-management', selector: 'abp-permission-management',
templateUrl: './permission-management.component.html', templateUrl: './permission-management.component.html'
}) })
export class PermissionManagementComponent implements OnInit, OnChanges { export class PermissionManagementComponent implements OnInit, OnChanges {
@Input() @Input()
@ -47,8 +49,7 @@ export class PermissionManagementComponent implements OnInit, OnChanges {
} }
} }
@Output() @Output() readonly visibleChange = new EventEmitter<boolean>();
visibleChange = new EventEmitter<boolean>();
@Select(PermissionManagementState.getPermissionGroups) @Select(PermissionManagementState.getPermissionGroups)
groups$: Observable<PermissionManagement.Group[]>; groups$: Observable<PermissionManagement.Group[]>;
@ -60,18 +61,18 @@ export class PermissionManagementComponent implements OnInit, OnChanges {
permissions: PermissionManagement.Permission[] = []; permissions: PermissionManagement.Permission[] = [];
selectThisTab: boolean = false; selectThisTab = false;
selectAllTab: boolean = false; selectAllTab = false;
modalBusy: boolean = false; modalBusy = false;
trackByFn: TrackByFunction<PermissionManagement.Group> = (_, item) => item.name; trackByFn: TrackByFunction<PermissionManagement.Group> = (_, item) => item.name;
get selectedGroupPermissions$(): Observable<PermissionWithMargin[]> { get selectedGroupPermissions$(): Observable<PermissionWithMargin[]> {
return this.groups$.pipe( return this.groups$.pipe(
map(groups => map(groups =>
this.selectedGroup ? groups.find(group => group.name === this.selectedGroup.name).permissions : [], this.selectedGroup ? groups.find(group => group.name === this.selectedGroup.name).permissions : []
), ),
map<PermissionManagement.Permission[], PermissionWithMargin[]>(permissions => map<PermissionManagement.Permission[], PermissionWithMargin[]>(permissions =>
permissions.map( permissions.map(
@ -79,10 +80,10 @@ export class PermissionManagementComponent implements OnInit, OnChanges {
(({ (({
...permission, ...permission,
margin: findMargin(permissions, permission), margin: findMargin(permissions, permission),
isGranted: this.permissions.find(per => per.name === permission.name).isGranted, isGranted: this.permissions.find(per => per.name === permission.name).isGranted
} as any) as PermissionWithMargin), } as any) as PermissionWithMargin)
), )
), )
); );
} }
@ -164,7 +165,7 @@ export class PermissionManagementComponent implements OnInit, OnChanges {
this.permissions = [ this.permissions = [
...this.permissions.slice(0, index), ...this.permissions.slice(0, index),
{ ...this.permissions[index], isGranted: !this.selectThisTab }, { ...this.permissions[index], isGranted: !this.selectThisTab },
...this.permissions.slice(index + 1), ...this.permissions.slice(index + 1)
]; ];
}); });
}); });
@ -173,7 +174,10 @@ export class PermissionManagementComponent implements OnInit, OnChanges {
} }
onClickSelectAll() { onClickSelectAll() {
this.permissions = this.permissions.map(permission => ({ ...permission, isGranted: !this.selectAllTab })); this.permissions = this.permissions.map(permission => ({
...permission,
isGranted: !this.selectAllTab
}));
this.selectThisTab = !this.selectAllTab; this.selectThisTab = !this.selectAllTab;
} }
@ -186,12 +190,12 @@ export class PermissionManagementComponent implements OnInit, OnChanges {
submit() { submit() {
this.modalBusy = true; this.modalBusy = true;
const unchangedPermissions = getPermissions( const unchangedPermissions = getPermissions(
this.store.selectSnapshot(PermissionManagementState.getPermissionGroups), this.store.selectSnapshot(PermissionManagementState.getPermissionGroups)
); );
const changedPermissions: PermissionManagement.MinimumPermission[] = this.permissions const changedPermissions: PermissionManagement.MinimumPermission[] = this.permissions
.filter(per => .filter(per =>
unchangedPermissions.find(unchanged => unchanged.name === per.name).isGranted === per.isGranted ? false : true, unchangedPermissions.find(unchanged => unchanged.name === per.name).isGranted === per.isGranted ? false : true
) )
.map(({ name, isGranted }) => ({ name, isGranted })); .map(({ name, isGranted }) => ({ name, isGranted }));
@ -201,8 +205,8 @@ export class PermissionManagementComponent implements OnInit, OnChanges {
new UpdatePermissions({ new UpdatePermissions({
providerKey: this.providerKey, providerKey: this.providerKey,
providerName: this.providerName, providerName: this.providerName,
permissions: changedPermissions, permissions: changedPermissions
}), })
) )
.subscribe(() => { .subscribe(() => {
this.modalBusy = false; this.modalBusy = false;
@ -220,7 +224,12 @@ export class PermissionManagementComponent implements OnInit, OnChanges {
} }
this.store this.store
.dispatch(new GetPermissions({ providerKey: this.providerKey, providerName: this.providerName })) .dispatch(
new GetPermissions({
providerKey: this.providerKey,
providerName: this.providerName
})
)
.pipe(pluck('PermissionManagementState', 'permissionRes')) .pipe(pluck('PermissionManagementState', 'permissionRes'))
.subscribe((permissionRes: PermissionManagement.Response) => { .subscribe((permissionRes: PermissionManagement.Response) => {
this.selectedGroup = permissionRes.groups[0]; this.selectedGroup = permissionRes.groups[0];

2
npm/ng-packs/packages/permission-management/src/lib/states/index.ts

@ -1 +1 @@
export * from "./permission-management.state"; export * from './permission-management.state';

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

@ -10,20 +10,20 @@ import {
DeleteTenant, DeleteTenant,
GetTenants, GetTenants,
GetTenantById, GetTenantById,
UpdateTenant, UpdateTenant
} from '../../actions/tenant-management.actions'; } from '../../actions/tenant-management.actions';
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 = { interface SelectedModalContent {
type: string; type: string;
title: string; title: string;
template: TemplateRef<any>; template: TemplateRef<any>;
}; }
@Component({ @Component({
selector: 'abp-tenants', selector: 'abp-tenants',
templateUrl: './tenants.component.html', templateUrl: './tenants.component.html'
}) })
export class TenantsComponent { export class TenantsComponent {
@Select(TenantManagementState.get) @Select(TenantManagementState.get)
@ -44,21 +44,21 @@ export class TenantsComponent {
selectedModalContent = {} as SelectedModalContent; selectedModalContent = {} as SelectedModalContent;
visibleFeatures: boolean = false; visibleFeatures = false;
providerKey: string; providerKey: string;
_useSharedDatabase: boolean; _useSharedDatabase: boolean;
pageQuery: ABP.PageQueryParams = { pageQuery: ABP.PageQueryParams = {
sorting: 'name', sorting: 'name'
}; };
loading: boolean = false; loading = false;
modalBusy: boolean = false; modalBusy = false;
sortOrder: string = 'asc'; sortOrder = 'asc';
get useSharedDatabase(): boolean { get useSharedDatabase(): boolean {
return this.defaultConnectionStringForm.get('useSharedDatabase').value; return this.defaultConnectionStringForm.get('useSharedDatabase').value;
@ -78,7 +78,7 @@ export class TenantsComponent {
private confirmationService: ConfirmationService, private confirmationService: ConfirmationService,
private tenantService: TenantManagementService, private tenantService: TenantManagementService,
private fb: FormBuilder, private fb: FormBuilder,
private store: Store, private store: Store
) {} ) {}
onSearch(value) { onSearch(value) {
@ -88,14 +88,14 @@ export class TenantsComponent {
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)]]
}); });
} }
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 || '']
}); });
} }
@ -103,7 +103,7 @@ export class TenantsComponent {
this.selectedModalContent = { this.selectedModalContent = {
title, title,
template, template,
type, type
}; };
this.isModalVisible = true; this.isModalVisible = true;
@ -117,7 +117,7 @@ export class TenantsComponent {
switchMap(selected => { switchMap(selected => {
this.selected = selected; this.selected = selected;
return this.tenantService.getDefaultConnectionString(id); return this.tenantService.getDefaultConnectionString(id);
}), })
) )
.subscribe(fetchedConnectionString => { .subscribe(fetchedConnectionString => {
this._useSharedDatabase = fetchedConnectionString ? false : true; this._useSharedDatabase = fetchedConnectionString ? false : true;
@ -158,7 +158,7 @@ export class TenantsComponent {
.deleteDefaultConnectionString(this.selected.id) .deleteDefaultConnectionString(this.selected.id)
.pipe( .pipe(
take(1), take(1),
finalize(() => (this.modalBusy = false)), finalize(() => (this.modalBusy = false))
) )
.subscribe(() => { .subscribe(() => {
this.isModalVisible = false; this.isModalVisible = false;
@ -168,7 +168,7 @@ export class TenantsComponent {
.updateDefaultConnectionString({ id: this.selected.id, defaultConnectionString: this.connectionString }) .updateDefaultConnectionString({ id: this.selected.id, defaultConnectionString: this.connectionString })
.pipe( .pipe(
take(1), take(1),
finalize(() => (this.modalBusy = false)), finalize(() => (this.modalBusy = false))
) )
.subscribe(() => { .subscribe(() => {
this.isModalVisible = false; this.isModalVisible = false;
@ -184,9 +184,9 @@ export class TenantsComponent {
.dispatch( .dispatch(
this.selected.id this.selected.id
? new UpdateTenant({ ...this.tenantForm.value, id: this.selected.id }) ? new UpdateTenant({ ...this.tenantForm.value, id: this.selected.id })
: new CreateTenant(this.tenantForm.value), : new CreateTenant(this.tenantForm.value)
) )
.pipe(finalize(()=> (this.modalBusy = false))) .pipe(finalize(() => (this.modalBusy = false)))
.subscribe(() => { .subscribe(() => {
this.isModalVisible = false; this.isModalVisible = false;
}); });
@ -195,7 +195,7 @@ export class TenantsComponent {
delete(id: string, name: string) { delete(id: string, name: string) {
this.confirmationService this.confirmationService
.warn('AbpTenantManagement::TenantDeletionConfirmationMessage', 'AbpTenantManagement::AreYouSure', { .warn('AbpTenantManagement::TenantDeletionConfirmationMessage', 'AbpTenantManagement::AreYouSure', {
messageLocalizationParams: [name], messageLocalizationParams: [name]
}) })
.subscribe((status: Toaster.Status) => { .subscribe((status: Toaster.Status) => {
if (status === Toaster.Status.confirm) { if (status === Toaster.Status.confirm) {
@ -220,6 +220,6 @@ export class TenantsComponent {
} }
changeSortOrder() { changeSortOrder() {
this.sortOrder = this.sortOrder.toLowerCase() === "asc" ? "desc" : "asc"; this.sortOrder = this.sortOrder.toLowerCase() === 'asc' ? 'desc' : 'asc';
} }
} }

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

@ -4,7 +4,7 @@ import { RestService, Rest, ABP } from '@abp/ng.core';
import { TenantManagement } from '../models/tenant-management'; import { TenantManagement } from '../models/tenant-management';
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root'
}) })
export class TenantManagementService { export class TenantManagementService {
constructor(private rest: RestService) {} constructor(private rest: RestService) {}
@ -13,7 +13,7 @@ export class TenantManagementService {
const request: Rest.Request<null> = { const request: Rest.Request<null> = {
method: 'GET', method: 'GET',
url: '/api/multi-tenancy/tenants', url: '/api/multi-tenancy/tenants',
params, params
}; };
return this.rest.request<null, TenantManagement.Response>(request); return this.rest.request<null, TenantManagement.Response>(request);
@ -22,7 +22,7 @@ export class TenantManagementService {
getTenantById(id: string): Observable<ABP.BasicItem> { getTenantById(id: string): Observable<ABP.BasicItem> {
const request: Rest.Request<null> = { const request: Rest.Request<null> = {
method: 'GET', method: 'GET',
url: `/api/multi-tenancy/tenants/${id}`, url: `/api/multi-tenancy/tenants/${id}`
}; };
return this.rest.request<null, ABP.BasicItem>(request); return this.rest.request<null, ABP.BasicItem>(request);
@ -31,7 +31,7 @@ export class TenantManagementService {
deleteTenant(id: string): Observable<null> { deleteTenant(id: string): Observable<null> {
const request: Rest.Request<null> = { const request: Rest.Request<null> = {
method: 'DELETE', method: 'DELETE',
url: `/api/multi-tenancy/tenants/${id}`, url: `/api/multi-tenancy/tenants/${id}`
}; };
return this.rest.request<null, null>(request); return this.rest.request<null, null>(request);
@ -40,8 +40,8 @@ export class TenantManagementService {
createTenant(body: TenantManagement.AddRequest): Observable<ABP.BasicItem> { createTenant(body: TenantManagement.AddRequest): Observable<ABP.BasicItem> {
const request: Rest.Request<TenantManagement.AddRequest> = { const request: Rest.Request<TenantManagement.AddRequest> = {
method: 'POST', method: 'POST',
url: `/api/multi-tenancy/tenants`, url: '/api/multi-tenancy/tenants',
body, body
}; };
return this.rest.request<TenantManagement.AddRequest, ABP.BasicItem>(request); return this.rest.request<TenantManagement.AddRequest, ABP.BasicItem>(request);
@ -54,7 +54,7 @@ export class TenantManagementService {
const request: Rest.Request<TenantManagement.UpdateRequest> = { const request: Rest.Request<TenantManagement.UpdateRequest> = {
method: 'PUT', method: 'PUT',
url, url,
body, body
}; };
return this.rest.request<TenantManagement.AddRequest, ABP.BasicItem>(request); return this.rest.request<TenantManagement.AddRequest, ABP.BasicItem>(request);
@ -66,7 +66,7 @@ export class TenantManagementService {
const request: Rest.Request<TenantManagement.DefaultConnectionStringRequest> = { const request: Rest.Request<TenantManagement.DefaultConnectionStringRequest> = {
method: 'GET', method: 'GET',
responseType: Rest.ResponseType.Text, responseType: Rest.ResponseType.Text,
url, url
}; };
return this.rest.request<TenantManagement.DefaultConnectionStringRequest, string>(request); return this.rest.request<TenantManagement.DefaultConnectionStringRequest, string>(request);
} }
@ -77,7 +77,7 @@ export class TenantManagementService {
const request: Rest.Request<TenantManagement.DefaultConnectionStringRequest> = { const request: Rest.Request<TenantManagement.DefaultConnectionStringRequest> = {
method: 'PUT', method: 'PUT',
url, url,
params: { defaultConnectionString: payload.defaultConnectionString }, params: { defaultConnectionString: payload.defaultConnectionString }
}; };
return this.rest.request<TenantManagement.DefaultConnectionStringRequest, any>(request); return this.rest.request<TenantManagement.DefaultConnectionStringRequest, any>(request);
} }
@ -87,7 +87,7 @@ export class TenantManagementService {
const request: Rest.Request<TenantManagement.DefaultConnectionStringRequest> = { const request: Rest.Request<TenantManagement.DefaultConnectionStringRequest> = {
method: 'DELETE', method: 'DELETE',
url, url
}; };
return this.rest.request<TenantManagement.DefaultConnectionStringRequest, any>(request); return this.rest.request<TenantManagement.DefaultConnectionStringRequest, any>(request);
} }

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

@ -6,7 +6,7 @@ import {
eLayoutType, eLayoutType,
SetLanguage, SetLanguage,
SessionState, SessionState,
takeUntilDestroy, takeUntilDestroy
} from '@abp/ng.core'; } from '@abp/ng.core';
import { import {
AfterViewInit, AfterViewInit,
@ -16,7 +16,7 @@ import {
TemplateRef, TemplateRef,
TrackByFunction, TrackByFunction,
ViewChild, ViewChild,
ViewChildren, ViewChildren
} from '@angular/core'; } from '@angular/core';
import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap'; import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap';
import { Navigate, RouterState } from '@ngxs/router-plugin'; import { Navigate, RouterState } from '@ngxs/router-plugin';
@ -32,7 +32,7 @@ import { LayoutState } from '../../states';
@Component({ @Component({
selector: 'abp-layout-application', selector: 'abp-layout-application',
templateUrl: './application-layout.component.html', templateUrl: './application-layout.component.html'
}) })
export class ApplicationLayoutComponent implements AfterViewInit, OnDestroy { export class ApplicationLayoutComponent implements AfterViewInit, OnDestroy {
// required for dynamic component // required for dynamic component
@ -59,9 +59,9 @@ export class ApplicationLayoutComponent implements AfterViewInit, OnDestroy {
@ViewChildren('navbarRootDropdown', { read: NgbDropdown }) @ViewChildren('navbarRootDropdown', { read: NgbDropdown })
navbarRootDropdowns: QueryList<NgbDropdown>; navbarRootDropdowns: QueryList<NgbDropdown>;
isOpenChangePassword: boolean = false; isOpenChangePassword = false;
isOpenProfile: boolean = false; isOpenProfile = false;
isDropdownChildDynamic: boolean; isDropdownChildDynamic: boolean;
@ -71,16 +71,13 @@ export class ApplicationLayoutComponent implements AfterViewInit, OnDestroy {
get defaultLanguage$(): Observable<string> { get defaultLanguage$(): Observable<string> {
return this.languages$.pipe( return this.languages$.pipe(
map( map(languages => snq(() => languages.find(lang => lang.cultureName === this.selectedLangCulture).displayName), '')
languages => snq(() => languages.find(lang => lang.cultureName === this.selectedLangCulture).displayName),
'',
),
); );
} }
get dropdownLanguages$(): Observable<ApplicationConfiguration.Language[]> { get dropdownLanguages$(): Observable<ApplicationConfiguration.Language[]> {
return this.languages$.pipe( return this.languages$.pipe(
map(languages => snq(() => languages.filter(lang => lang.cultureName !== this.selectedLangCulture)), []), map(languages => snq(() => languages.filter(lang => lang.cultureName !== this.selectedLangCulture)), [])
); );
} }
@ -116,8 +113,8 @@ export class ApplicationLayoutComponent implements AfterViewInit, OnDestroy {
this.store.dispatch( this.store.dispatch(
new AddNavigationElement([ new AddNavigationElement([
{ element: this.languageRef, order: 4, name: 'LanguageRef' }, { element: this.languageRef, order: 4, name: 'LanguageRef' },
{ element: this.currentUserRef, order: 5, name: 'CurrentUserRef' }, { element: this.currentUserRef, order: 5, name: 'CurrentUserRef' }
]), ])
); );
} }
@ -125,7 +122,7 @@ export class ApplicationLayoutComponent implements AfterViewInit, OnDestroy {
.pipe( .pipe(
map(elements => elements.map(({ element }) => element)), map(elements => elements.map(({ element }) => element)),
filter(elements => !compare(elements, this.rightPartElements)), filter(elements => !compare(elements, this.rightPartElements)),
takeUntilDestroy(this), takeUntilDestroy(this)
) )
.subscribe(elements => { .subscribe(elements => {
setTimeout(() => (this.rightPartElements = elements), 0); setTimeout(() => (this.rightPartElements = elements), 0);
@ -136,7 +133,7 @@ export class ApplicationLayoutComponent implements AfterViewInit, OnDestroy {
fromEvent(window, 'resize') fromEvent(window, 'resize')
.pipe( .pipe(
takeUntilDestroy(this), takeUntilDestroy(this),
debounceTime(250), debounceTime(250)
) )
.subscribe(() => { .subscribe(() => {
this.checkWindowWidth(); this.checkWindowWidth();
@ -153,8 +150,8 @@ export class ApplicationLayoutComponent implements AfterViewInit, OnDestroy {
this.oauthService.logOut(); this.oauthService.logOut();
this.store.dispatch( this.store.dispatch(
new Navigate(['/'], null, { new Navigate(['/'], null, {
state: { redirectUrl: this.store.selectSnapshot(RouterState).state.url }, state: { redirectUrl: this.store.selectSnapshot(RouterState).state.url }
}), })
); );
this.store.dispatch(new GetAppConfiguration()); this.store.dispatch(new GetAppConfiguration());
} }

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

@ -6,10 +6,10 @@ import { Store } from '@ngxs/store';
@Component({ @Component({
selector: ' abp-layout', selector: ' abp-layout',
templateUrl: './layout.component.html', templateUrl: './layout.component.html',
animations: [slideFromBottom], animations: [slideFromBottom]
}) })
export class LayoutComponent { export class LayoutComponent {
isCollapsed: boolean = true; isCollapsed = true;
get appInfo(): Config.Application { get appInfo(): Config.Application {
return this.store.selectSnapshot(ConfigState.getApplicationInfo); return this.store.selectSnapshot(ConfigState.getApplicationInfo);

2
npm/ng-packs/packages/theme-basic/src/lib/constants/styles.ts

@ -6,4 +6,4 @@ export default `
.entry-row { .entry-row {
margin-bottom: 15px; margin-bottom: 15px;
} }
`; `;

2
npm/ng-packs/packages/theme-basic/src/lib/states/index.ts

@ -1 +1 @@
export * from "./layout.state"; export * from './layout.state';

20
npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts

@ -28,19 +28,19 @@ export const LAYOUTS = [ApplicationLayoutComponent, AccountLayoutComponent, Empt
NgxValidateCoreModule.forRoot({ NgxValidateCoreModule.forRoot({
targetSelector: '.form-group', targetSelector: '.form-group',
blueprints: { blueprints: {
email: `AbpAccount::ThisFieldIsNotAValidEmailAddress.`, email: 'AbpAccount::ThisFieldIsNotAValidEmailAddress.',
max: `AbpAccount::ThisFieldMustBeBetween{0}And{1}[{{ min }},{{ max }}]`, max: 'AbpAccount::ThisFieldMustBeBetween{0}And{1}[{{ min }},{{ max }}]',
maxlength: `AbpAccount::ThisFieldMustBeAStringWithAMaximumLengthOf{1}[{{ requiredLength }}]`, maxlength: 'AbpAccount::ThisFieldMustBeAStringWithAMaximumLengthOf{1}[{{ requiredLength }}]',
min: `AbpAccount::ThisFieldMustBeBetween{0}And{1}[{{ min }},{{ max }}]`, min: 'AbpAccount::ThisFieldMustBeBetween{0}And{1}[{{ min }},{{ max }}]',
minlength: `AbpAccount::ThisFieldMustBeAStringOrArrayTypeWithAMinimumLengthOf[{{ min }},{{ max }}]`, minlength: 'AbpAccount::ThisFieldMustBeAStringOrArrayTypeWithAMinimumLengthOf[{{ min }},{{ max }}]',
required: `AbpAccount::ThisFieldIsRequired.`, required: 'AbpAccount::ThisFieldIsRequired.',
passwordMismatch: `AbpIdentity::Identity.PasswordConfirmationFailed`, passwordMismatch: 'AbpIdentity::Identity.PasswordConfirmationFailed'
}, },
errorTemplate: ValidationErrorComponent, errorTemplate: ValidationErrorComponent
}), })
], ],
exports: [...LAYOUTS], exports: [...LAYOUTS],
entryComponents: [...LAYOUTS, ValidationErrorComponent], entryComponents: [...LAYOUTS, ValidationErrorComponent]
}) })
export class ThemeBasicModule { export class ThemeBasicModule {
constructor(private initialService: InitialService) {} constructor(private initialService: InitialService) {}

4
npm/ng-packs/packages/theme-shared/package.json

@ -10,8 +10,8 @@
"chart.js": "^2.8.0", "chart.js": "^2.8.0",
"font-awesome": "^4.7.0", "font-awesome": "^4.7.0",
"ngx-perfect-scrollbar": "^8.0.0", "ngx-perfect-scrollbar": "^8.0.0",
"primeicons": "^1.0.0", "primeicons": "^2.0.0",
"primeng": "^8.0.0" "primeng": "^8.0.3"
}, },
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"

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

@ -5,9 +5,9 @@ import { Toaster } from '../models/toaster';
export abstract class AbstractToaster<T = Toaster.Options> { export abstract class AbstractToaster<T = Toaster.Options> {
status$: Subject<Toaster.Status>; status$: Subject<Toaster.Status>;
key: string = 'abpToast'; key = 'abpToast';
sticky: boolean = false; sticky = false;
constructor(protected messageService: MessageService) {} constructor(protected messageService: MessageService) {}
@ -36,7 +36,7 @@ export abstract class AbstractToaster<T = Toaster.Options> {
summary: title || '', summary: title || '',
...options, ...options,
key: this.key, key: this.key,
...(typeof (options || ({} as any)).sticky === 'undefined' && { sticky: this.sticky }), ...(typeof (options || ({} as any)).sticky === 'undefined' && { sticky: this.sticky })
}); });
this.status$ = new Subject<Toaster.Status>(); this.status$ = new Subject<Toaster.Status>();
return this.status$; return this.status$;

10
npm/ng-packs/packages/theme-shared/src/lib/animations/collapse.animations.ts

@ -5,15 +5,15 @@ export const collapse = trigger('collapse', [
'open', 'open',
style({ style({
height: '*', height: '*',
overflow: 'hidden', overflow: 'hidden'
}), })
), ),
state( state(
'close', 'close',
style({ style({
height: '0px', height: '0px',
overflow: 'hidden', overflow: 'hidden'
}), })
), ),
transition(`open <=> close`, animate('{{duration}}ms'), { params: { duration: '350' } }), transition('open <=> close', animate('{{duration}}ms'), { params: { duration: '350' } })
]); ]);

13
npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.html

@ -0,0 +1,13 @@
<ol *ngIf="show" class="breadcrumb">
<li class="breadcrumb-item">
<a routerLink="/"><i class="fa fa-home"></i> </a>
</li>
<li
*ngFor="let segment of segments; let last = last"
class="breadcrumb-item"
[class.active]="last"
aria-current="page"
>
{{ segment | abpLocalization }}
</li>
</ol>

16
npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.ts

@ -5,21 +5,7 @@ import { ConfigState, ABP } from '@abp/ng.core';
@Component({ @Component({
selector: 'abp-breadcrumb', selector: 'abp-breadcrumb',
template: ` templateUrl: './breadcrumb.component.html'
<ol *ngIf="show" class="breadcrumb">
<li class="breadcrumb-item">
<a routerLink="/"><i class="fa fa-home"></i> </a>
</li>
<li
*ngFor="let segment of segments; let last = last"
class="breadcrumb-item"
[class.active]="last"
aria-current="page"
>
{{ segment | abpLocalization }}
</li>
</ol>
`,
}) })
export class BreadcrumbComponent implements OnInit { export class BreadcrumbComponent implements OnInit {
show: boolean; show: boolean;

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

@ -6,23 +6,23 @@ import { Component, Input } from '@angular/core';
<button [attr.type]="type" [ngClass]="buttonClass" [disabled]="loading || disabled"> <button [attr.type]="type" [ngClass]="buttonClass" [disabled]="loading || disabled">
<i [ngClass]="icon" class="mr-1"></i><ng-content></ng-content> <i [ngClass]="icon" class="mr-1"></i><ng-content></ng-content>
</button> </button>
`, `
}) })
export class ButtonComponent { export class ButtonComponent {
@Input() @Input()
buttonClass: string = 'btn btn-primary'; buttonClass = 'btn btn-primary';
@Input() @Input()
type: string = 'button'; type = 'button';
@Input() @Input()
iconClass: string; iconClass: string;
@Input() @Input()
loading: boolean = false; loading = false;
@Input() @Input()
disabled: boolean = false; disabled = false;
get icon(): string { get icon(): string {
return `${this.loading ? 'fa fa-pulse fa-spinner' : this.iconClass || 'd-none'}`; return `${this.loading ? 'fa fa-pulse fa-spinner' : this.iconClass || 'd-none'}`;

27
npm/ng-packs/packages/theme-shared/src/lib/components/change-password/change-password.component.ts

@ -8,7 +8,7 @@ import {
Output, Output,
SimpleChanges, SimpleChanges,
TemplateRef, TemplateRef,
ViewChild, ViewChild
} from '@angular/core'; } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { comparePasswords, Validation } from '@ngx-validate/core'; import { comparePasswords, Validation } from '@ngx-validate/core';
@ -23,7 +23,7 @@ const PASSWORD_FIELDS = ['newPassword', 'repeatNewPassword'];
@Component({ @Component({
selector: 'abp-change-password', selector: 'abp-change-password',
templateUrl: './change-password.component.html', templateUrl: './change-password.component.html'
}) })
export class ChangePasswordComponent implements OnInit, OnChanges { export class ChangePasswordComponent implements OnInit, OnChanges {
protected _visible; protected _visible;
@ -38,17 +38,16 @@ export class ChangePasswordComponent implements OnInit, OnChanges {
this.visibleChange.emit(value); this.visibleChange.emit(value);
} }
@Output() @Output() readonly visibleChange = new EventEmitter<boolean>();
visibleChange = new EventEmitter<boolean>();
@ViewChild('modalContent', { static: false }) @ViewChild('modalContent', { static: false })
modalContent: TemplateRef<any>; modalContent: TemplateRef<any>;
form: FormGroup; form: FormGroup;
modalBusy: boolean = false; modalBusy = false;
mapErrorsFn: Validation.MapErrorsFn = function(errors, groupErrors, control) { mapErrorsFn: Validation.MapErrorsFn = (errors, groupErrors, control) => {
if (PASSWORD_FIELDS.indexOf(control.name) < 0) return errors; if (PASSWORD_FIELDS.indexOf(control.name) < 0) return errors;
return errors.concat(groupErrors.filter(({ key }) => key === 'passwordMismatch')); return errors.concat(groupErrors.filter(({ key }) => key === 'passwordMismatch'));
@ -61,11 +60,11 @@ export class ChangePasswordComponent implements OnInit, OnChanges {
{ {
password: ['', required], password: ['', required],
newPassword: ['', required], newPassword: ['', required],
repeatNewPassword: ['', required], repeatNewPassword: ['', required]
}, },
{ {
validators: [comparePasswords(PASSWORD_FIELDS)], validators: [comparePasswords(PASSWORD_FIELDS)]
}, }
); );
} }
@ -77,13 +76,13 @@ export class ChangePasswordComponent implements OnInit, OnChanges {
.dispatch( .dispatch(
new ChangePassword({ new ChangePassword({
currentPassword: this.form.get('password').value, currentPassword: this.form.get('password').value,
newPassword: this.form.get('newPassword').value, newPassword: this.form.get('newPassword').value
}), })
) )
.pipe( .pipe(
finalize(() => { finalize(() => {
this.modalBusy = false; this.modalBusy = false;
}), })
) )
.subscribe({ .subscribe({
next: () => { next: () => {
@ -92,9 +91,9 @@ export class ChangePasswordComponent implements OnInit, OnChanges {
}, },
error: err => { error: err => {
this.toasterService.error(snq(() => err.error.error.message, 'AbpAccount::DefaultErrorMessage'), 'Error', { this.toasterService.error(snq(() => err.error.error.message, 'AbpAccount::DefaultErrorMessage'), 'Error', {
life: 7000, life: 7000
}); });
}, }
}); });
} }

26
npm/ng-packs/packages/theme-shared/src/lib/components/chart/chart.component.ts

@ -6,7 +6,7 @@ import {
Input, Input,
OnDestroy, OnDestroy,
Output, Output,
ChangeDetectorRef, ChangeDetectorRef
} from '@angular/core'; } from '@angular/core';
import { BehaviorSubject } from 'rxjs'; import { BehaviorSubject } from 'rxjs';
import { chartJsLoaded$ } from '../../utils/widget-utils'; import { chartJsLoaded$ } from '../../utils/widget-utils';
@ -14,7 +14,7 @@ declare const Chart: any;
@Component({ @Component({
selector: 'abp-chart', selector: 'abp-chart',
templateUrl: './chart.component.html', templateUrl: './chart.component.html'
}) })
export class ChartComponent implements AfterViewInit, OnDestroy { export class ChartComponent implements AfterViewInit, OnDestroy {
@Input() type: string; @Input() type: string;
@ -27,11 +27,12 @@ export class ChartComponent implements AfterViewInit, OnDestroy {
@Input() height: string; @Input() height: string;
@Input() responsive: boolean = true; @Input() responsive = true;
@Output() onDataSelect: EventEmitter<any> = new EventEmitter(); // tslint:disable-next-line: no-output-on-prefix
@Output() readonly onDataSelect: EventEmitter<any> = new EventEmitter();
@Output() initialized = new BehaviorSubject(this); @Output() readonly initialized = new BehaviorSubject(this);
private _initialized: boolean; private _initialized: boolean;
@ -61,6 +62,7 @@ export class ChartComponent implements AfterViewInit, OnDestroy {
ngAfterViewInit() { ngAfterViewInit() {
chartJsLoaded$.subscribe(() => { chartJsLoaded$.subscribe(() => {
try { try {
// tslint:disable-next-line: no-unused-expression
Chart; Chart;
} catch (error) { } catch (error) {
console.error(`Chart is not found. Import the Chart from app.module like shown below: console.error(`Chart is not found. Import the Chart from app.module like shown below:
@ -76,16 +78,20 @@ export class ChartComponent implements AfterViewInit, OnDestroy {
onCanvasClick = event => { onCanvasClick = event => {
if (this.chart) { if (this.chart) {
let element = this.chart.getElementAtEvent(event); const element = this.chart.getElementAtEvent(event);
let dataset = this.chart.getDatasetAtEvent(event); const dataset = this.chart.getDatasetAtEvent(event);
if (element && element[0] && dataset) { if (element && element[0] && dataset) {
this.onDataSelect.emit({ originalEvent: event, element: element[0], dataset: dataset }); this.onDataSelect.emit({
originalEvent: event,
element: element[0],
dataset
});
} }
} }
}; };
initChart = () => { initChart = () => {
let opts = this.options || {}; const opts = this.options || {};
opts.responsive = this.responsive; opts.responsive = this.responsive;
// allows chart to resize in responsive mode // allows chart to resize in responsive mode
@ -97,7 +103,7 @@ export class ChartComponent implements AfterViewInit, OnDestroy {
type: this.type, type: this.type,
data: this.data, data: this.data,
options: this.options, options: this.options,
plugins: this.plugins, plugins: this.plugins
}); });
this.cdRef.detectChanges(); this.cdRef.detectChanges();

3
npm/ng-packs/packages/theme-shared/src/lib/components/confirmation/confirmation.component.ts

@ -4,6 +4,7 @@ import { Toaster } from '../../models/toaster';
@Component({ @Component({
selector: 'abp-confirmation', selector: 'abp-confirmation',
// tslint:disable-next-line: component-max-inline-declarations
template: ` template: `
<p-toast <p-toast
position="center" position="center"
@ -45,7 +46,7 @@ import { Toaster } from '../../models/toaster';
</div> </div>
</ng-template> </ng-template>
</p-toast> </p-toast>
`, `
}) })
export class ConfirmationComponent { export class ConfirmationComponent {
confirm = Toaster.Status.confirm; confirm = Toaster.Status.confirm;

22
npm/ng-packs/packages/theme-shared/src/lib/components/error/error.component.html

@ -0,0 +1,22 @@
<div class="error">
<button id="abp-close-button mr-4" type="button" class="close" (click)="destroy()">
<span aria-hidden="true">&times;</span>
</button>
<div class="row centered">
<div class="col-md-12">
<div class="error-template">
<h1>
{{ title | abpLocalization }}
</h1>
<div class="error-details">
{{ details | abpLocalization }}
</div>
<div class="error-actions">
<a (click)="destroy()" routerLink="/" class="btn btn-primary btn-md mt-2"
><span class="glyphicon glyphicon-home"></span> {{ '::Menu:Home' | abpLocalization }}
</a>
</div>
</div>
</div>
</div>
</div>

27
npm/ng-packs/packages/theme-shared/src/lib/components/error/error.component.ts

@ -2,31 +2,8 @@ import { Component, Renderer2, ElementRef } from '@angular/core';
@Component({ @Component({
selector: 'abp-error', selector: 'abp-error',
template: ` templateUrl: './error.component.html',
<div class="error"> styleUrls: ['error.component.scss']
<button id="abp-close-button mr-4" type="button" class="close" (click)="destroy()">
<span aria-hidden="true">&times;</span>
</button>
<div class="row centered">
<div class="col-md-12">
<div class="error-template">
<h1>
{{ title | abpLocalization }}
</h1>
<div class="error-details">
{{ details | abpLocalization }}
</div>
<div class="error-actions">
<a (click)="destroy()" routerLink="/" class="btn btn-primary btn-md mt-2"
><span class="glyphicon glyphicon-home"></span> {{ '::Menu:Home' | abpLocalization }}
</a>
</div>
</div>
</div>
</div>
</div>
`,
styleUrls: ['error.component.scss'],
}) })
export class ErrorComponent { export class ErrorComponent {
title = 'Oops!'; title = 'Oops!';

43
npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts

@ -20,27 +20,9 @@ import { filter } from 'rxjs/operators';
></div> ></div>
</div> </div>
`, `,
styleUrls: ['./loader-bar.component.scss'], styleUrls: ['./loader-bar.component.scss']
}) })
export class LoaderBarComponent implements OnDestroy { export class LoaderBarComponent implements OnDestroy {
@Input()
containerClass: string = 'abp-loader-bar';
@Input()
color: string = '#77b6ff';
@Input()
isLoading: boolean = false;
@Input()
filter = (action: StartLoader | StopLoader) => action.payload.url.indexOf('openid-configuration') < 0;
progressLevel: number = 0;
interval: Subscription;
timer: Subscription;
get boxShadow(): string { get boxShadow(): string {
return `0 0 10px rgba(${this.color}, 0.5)`; return `0 0 10px rgba(${this.color}, 0.5)`;
} }
@ -50,7 +32,7 @@ export class LoaderBarComponent implements OnDestroy {
.pipe( .pipe(
ofActionSuccessful(StartLoader, StopLoader), ofActionSuccessful(StartLoader, StopLoader),
filter(this.filter), filter(this.filter),
takeUntilDestroy(this), takeUntilDestroy(this)
) )
.subscribe(action => { .subscribe(action => {
if (action instanceof StartLoader) this.startLoading(); if (action instanceof StartLoader) this.startLoading();
@ -61,15 +43,32 @@ export class LoaderBarComponent implements OnDestroy {
.pipe( .pipe(
filter( filter(
event => event =>
event instanceof NavigationStart || event instanceof NavigationEnd || event instanceof NavigationError, event instanceof NavigationStart || event instanceof NavigationEnd || event instanceof NavigationError
), ),
takeUntilDestroy(this), takeUntilDestroy(this)
) )
.subscribe(event => { .subscribe(event => {
if (event instanceof NavigationStart) this.startLoading(); if (event instanceof NavigationStart) this.startLoading();
else this.stopLoading(); else this.stopLoading();
}); });
} }
@Input()
containerClass = 'abp-loader-bar';
@Input()
color = '#77b6ff';
@Input()
isLoading = false;
progressLevel = 0;
interval: Subscription;
timer: Subscription;
@Input()
filter = (action: StartLoader | StopLoader) => action.payload.url.indexOf('openid-configuration') < 0;
ngOnDestroy() { ngOnDestroy() {
this.interval.unsubscribe(); this.interval.unsubscribe();

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

@ -9,7 +9,7 @@ import {
Renderer2, Renderer2,
TemplateRef, TemplateRef,
ViewChild, ViewChild,
ViewChildren, ViewChildren
} from '@angular/core'; } from '@angular/core';
import { fromEvent, Subject, timer } from 'rxjs'; import { fromEvent, Subject, timer } from 'rxjs';
import { filter, take, takeUntil, debounceTime } from 'rxjs/operators'; import { filter, take, takeUntil, debounceTime } from 'rxjs/operators';
@ -23,7 +23,7 @@ const ANIMATION_TIMEOUT = 200;
@Component({ @Component({
selector: 'abp-modal', selector: 'abp-modal',
templateUrl: './modal.component.html', templateUrl: './modal.component.html'
}) })
export class ModalComponent implements OnDestroy { export class ModalComponent implements OnDestroy {
@Input() @Input()
@ -51,7 +51,7 @@ 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.ngOnDestroy(); this.destroy$.next();
}, ANIMATION_TIMEOUT - 10); }, ANIMATION_TIMEOUT - 10);
} }
} }
@ -68,9 +68,9 @@ export class ModalComponent implements OnDestroy {
this._busy = value; this._busy = value;
} }
@Input() centered: boolean = false; @Input() centered = false;
@Input() modalClass: string = ''; @Input() modalClass = '';
@Input() size: ModalSize = 'lg'; @Input() size: ModalSize = 'lg';
@ -78,9 +78,9 @@ export class ModalComponent implements OnDestroy {
@Input() minHeight: number; @Input() minHeight: number;
@Output() visibleChange = new EventEmitter<boolean>(); @Output() readonly visibleChange = new EventEmitter<boolean>();
@Output() init = new EventEmitter<void>(); @Output() readonly init = new EventEmitter<void>();
@ContentChild('abpHeader', { static: false }) abpHeader: TemplateRef<any>; @ContentChild('abpHeader', { static: false }) abpHeader: TemplateRef<any>;
@ -88,29 +88,29 @@ export class ModalComponent implements OnDestroy {
@ContentChild('abpFooter', { static: false }) abpFooter: TemplateRef<any>; @ContentChild('abpFooter', { static: false }) abpFooter: TemplateRef<any>;
@ContentChild('abpClose', { static: false, read: ElementRef }) abpClose: ElementRef<any>; @ContentChild('abpClose', { static: false, read: ElementRef })
abpClose: ElementRef<any>;
@ContentChild(ButtonComponent, { static: false, read: ButtonComponent }) abpSubmit: ButtonComponent; @ContentChild(ButtonComponent, { static: false, read: ButtonComponent })
abpSubmit: ButtonComponent;
@ViewChild('abpModalContent', { static: false }) modalContent: ElementRef; @ViewChild('abpModalContent', { static: false }) modalContent: ElementRef;
@ViewChildren('abp-button') abpButtons; @ViewChildren('abp-button') abpButtons;
@Output() @Output() readonly appear = new EventEmitter();
show = new EventEmitter();
@Output() @Output() readonly disappear = new EventEmitter();
hide = new EventEmitter();
_visible: boolean = false; _visible = false;
_busy: boolean = false; _busy = false;
showModal: boolean = false; showModal = false;
isOpenConfirmation: boolean = false; isOpenConfirmation = false;
closable: boolean = false; closable = false;
destroy$ = new Subject<void>(); destroy$ = new Subject<void>();
@ -131,11 +131,11 @@ export class ModalComponent implements OnDestroy {
.subscribe(_ => (this.closable = true)); .subscribe(_ => (this.closable = true));
this.renderer.addClass(document.body, 'modal-open'); this.renderer.addClass(document.body, 'modal-open');
this.show.emit(); this.appear.emit();
} else { } else {
this.closable = false; this.closable = false;
this.renderer.removeClass(document.body, 'modal-open'); this.renderer.removeClass(document.body, 'modal-open');
this.hide.emit(); this.disappear.emit();
} }
} }
@ -144,7 +144,7 @@ export class ModalComponent implements OnDestroy {
.pipe( .pipe(
takeUntil(this.destroy$), takeUntil(this.destroy$),
debounceTime(150), debounceTime(150),
filter((key: KeyboardEvent) => key && key.code === 'Escape' && this.closable), filter((key: KeyboardEvent) => key && key.code === 'Escape' && this.closable)
) )
.subscribe(_ => { .subscribe(_ => {
this.close(); this.close();
@ -155,7 +155,7 @@ export class ModalComponent implements OnDestroy {
fromEvent(this.abpClose.nativeElement, 'click') fromEvent(this.abpClose.nativeElement, 'click')
.pipe( .pipe(
takeUntil(this.destroy$), takeUntil(this.destroy$),
filter(() => !!(this.closable && this.modalContent)), filter(() => !!(this.closable && this.modalContent))
) )
.subscribe(() => this.close()); .subscribe(() => this.close());
}, 0); }, 0);
@ -167,7 +167,7 @@ export class ModalComponent implements OnDestroy {
if (!this.closable || this.busy) return; if (!this.closable || this.busy) return;
const nodes = getFlatNodes( const nodes = getFlatNodes(
(this.modalContent.nativeElement.querySelector('#abp-modal-body') as HTMLElement).childNodes, (this.modalContent.nativeElement.querySelector('#abp-modal-body') as HTMLElement).childNodes
); );
if (hasNgDirty(nodes)) { if (hasNgDirty(nodes)) {
@ -194,7 +194,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 ? getFlatNodes(val.childNodes) : [val])], (acc, val) => [...acc, ...(val.childNodes && val.childNodes.length ? getFlatNodes(val.childNodes) : [val])],
[], []
); );
} }

11
npm/ng-packs/packages/theme-shared/src/lib/components/profile/profile.component.ts

@ -9,7 +9,7 @@ const { maxLength, required, email } = Validators;
@Component({ @Component({
selector: 'abp-profile', selector: 'abp-profile',
templateUrl: './profile.component.html', templateUrl: './profile.component.html'
}) })
export class ProfileComponent implements OnChanges { export class ProfileComponent implements OnChanges {
protected _visible; protected _visible;
@ -24,15 +24,14 @@ export class ProfileComponent implements OnChanges {
this.visibleChange.emit(value); this.visibleChange.emit(value);
} }
@Output() @Output() readonly visibleChange = new EventEmitter<boolean>();
visibleChange = new EventEmitter<boolean>();
@Select(ProfileState.getProfile) @Select(ProfileState.getProfile)
profile$: Observable<Profile.Response>; profile$: Observable<Profile.Response>;
form: FormGroup; form: FormGroup;
modalBusy: boolean = false; modalBusy = false;
constructor(private fb: FormBuilder, private store: Store) {} constructor(private fb: FormBuilder, private store: Store) {}
@ -41,7 +40,7 @@ export class ProfileComponent implements OnChanges {
.dispatch(new GetProfile()) .dispatch(new GetProfile())
.pipe( .pipe(
withLatestFrom(this.profile$), withLatestFrom(this.profile$),
take(1), take(1)
) )
.subscribe(([, profile]) => { .subscribe(([, profile]) => {
this.form = this.fb.group({ this.form = this.fb.group({
@ -49,7 +48,7 @@ export class ProfileComponent implements OnChanges {
email: [profile.email, [required, email, maxLength(256)]], email: [profile.email, [required, email, maxLength(256)]],
name: [profile.name || '', [maxLength(64)]], name: [profile.name || '', [maxLength(64)]],
surname: [profile.surname || '', [maxLength(64)]], surname: [profile.surname || '', [maxLength(64)]],
phoneNumber: [profile.phoneNumber || '', [maxLength(16)]], phoneNumber: [profile.phoneNumber || '', [maxLength(16)]]
}); });
}); });
} }

7
npm/ng-packs/packages/theme-shared/src/lib/components/table-empty-message/table-empty-message.component.ts

@ -1,12 +1,13 @@
import { Component, OnInit, Input } from '@angular/core'; import { Component, OnInit, Input } from '@angular/core';
@Component({ @Component({
// tslint:disable-next-line: component-selector
selector: '[abp-table-empty-message]', selector: '[abp-table-empty-message]',
template: ` template: `
<td class="text-center" [attr.colspan]="colspan"> <td class="text-center" [attr.colspan]="colspan">
{{ emptyMessage | abpLocalization }} {{ emptyMessage | abpLocalization }}
</td> </td>
`, `
}) })
export class TableEmptyMessageComponent { export class TableEmptyMessageComponent {
@Input() @Input()
@ -16,10 +17,10 @@ export class TableEmptyMessageComponent {
message: string; message: string;
@Input() @Input()
localizationResource: string = 'AbpAccount'; localizationResource = 'AbpAccount';
@Input() @Input()
localizationProp: string = 'NoDataAvailableInDatatable'; localizationProp = 'NoDataAvailableInDatatable';
get emptyMessage(): string { get emptyMessage(): string {
return this.message || `${this.localizationResource}::${this.localizationProp}`; return this.message || `${this.localizationResource}::${this.localizationProp}`;

3
npm/ng-packs/packages/theme-shared/src/lib/components/toast/toast.component.ts

@ -2,6 +2,7 @@ import { Component } from '@angular/core';
@Component({ @Component({
selector: 'abp-toast', selector: 'abp-toast',
// tslint:disable-next-line: component-max-inline-declarations
template: ` template: `
<p-toast position="bottom-right" key="abpToast" styleClass="abp-toast" [baseZIndex]="1000"> <p-toast position="bottom-right" key="abpToast" styleClass="abp-toast" [baseZIndex]="1000">
<ng-template let-message pTemplate="message"> <ng-template let-message pTemplate="message">
@ -20,6 +21,6 @@ import { Component } from '@angular/core';
</div> </div>
</ng-template> </ng-template>
</p-toast> </p-toast>
`, `
}) })
export class ToastComponent {} export class ToastComponent {}

2
npm/ng-packs/packages/theme-shared/src/lib/contants/scripts.ts

@ -1 +1 @@
export default ``; export default '';

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

@ -8,9 +8,9 @@ import { Toaster } from '../models/toaster';
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class ConfirmationService extends AbstractToaster<Confirmation.Options> { export class ConfirmationService extends AbstractToaster<Confirmation.Options> {
key: string = 'abpConfirmation'; key = 'abpConfirmation';
sticky: boolean = true; sticky = true;
destroy$ = new Subject(); destroy$ = new Subject();
@ -22,7 +22,7 @@ export class ConfirmationService extends AbstractToaster<Confirmation.Options> {
message: string, message: string,
title: string, title: string,
severity: Toaster.Severity, severity: Toaster.Severity,
options?: Confirmation.Options, options?: Confirmation.Options
): Observable<Toaster.Status> { ): Observable<Toaster.Status> {
this.listenToEscape(); this.listenToEscape();
@ -40,7 +40,7 @@ export class ConfirmationService extends AbstractToaster<Confirmation.Options> {
.pipe( .pipe(
takeUntil(this.destroy$), takeUntil(this.destroy$),
debounceTime(150), debounceTime(150),
filter((key: KeyboardEvent) => key && key.code === 'Escape'), filter((key: KeyboardEvent) => key && key.code === 'Escape')
) )
.subscribe(_ => { .subscribe(_ => {
this.clear(); this.clear();

4
npm/ng-packs/packages/theme-shared/src/lib/tests/button.component.spec.ts

@ -4,7 +4,7 @@ import {
createHostFactory, createHostFactory,
Spectator, Spectator,
SpectatorHost, SpectatorHost,
createTestComponentFactory, createTestComponentFactory
} from '@ngneat/spectator'; } from '@ngneat/spectator';
import { ButtonComponent } from '../components'; import { ButtonComponent } from '../components';
@ -13,7 +13,7 @@ describe('ButtonComponent', () => {
const createHost = createHostFactory(ButtonComponent); const createHost = createHostFactory(ButtonComponent);
beforeEach(() => (host = createHost(`<abp-button iconClass="fa fa-check">Button</abp-button>`))); beforeEach(() => (host = createHost('<abp-button iconClass="fa fa-check">Button</abp-button>')));
it('should display the button', () => { it('should display the button', () => {
expect(host.query('button')).toBeTruthy(); expect(host.query('button')).toBeTruthy();

14
npm/ng-packs/packages/theme-shared/src/lib/tests/error.handler.spec.ts

@ -9,18 +9,18 @@ import { NgxsResetPluginModule, StateOverwrite } from 'ngxs-reset-plugin';
import { DEFAULT_ERROR_MESSAGES, ErrorHandler } from '../handlers'; import { DEFAULT_ERROR_MESSAGES, ErrorHandler } from '../handlers';
import { ThemeSharedModule } from '../theme-shared.module'; import { ThemeSharedModule } from '../theme-shared.module';
@Component({ selector: 'dummy', template: 'dummy works! <abp-confirmation></abp-confirmation>' }) @Component({ selector: 'abp-dummy', template: 'dummy works! <abp-confirmation></abp-confirmation>' })
class DummyComponent { class DummyComponent {
constructor(public errorHandler: ErrorHandler, public store: Store) {} constructor(public errorHandler: ErrorHandler, public store: Store) {}
} }
describe('With Custom Host Component', function() { describe('With Custom Host Component', () => {
let component: SpectatorRouting<DummyComponent>; let component: SpectatorRouting<DummyComponent>;
const createComponent = createRoutingFactory({ const createComponent = createRoutingFactory({
component: DummyComponent, component: DummyComponent,
imports: [CoreModule, ThemeSharedModule.forRoot(), NgxsModule.forRoot([]), NgxsResetPluginModule.forRoot()], imports: [CoreModule, ThemeSharedModule.forRoot(), NgxsModule.forRoot([]), NgxsResetPluginModule.forRoot()],
stubsEnabled: false, stubsEnabled: false,
routes: [{ path: '', component: DummyComponent }, { path: 'account/login', component: RouterOutletComponent }], routes: [{ path: '', component: DummyComponent }, { path: 'account/login', component: RouterOutletComponent }]
}); });
beforeEach(() => { beforeEach(() => {
@ -45,7 +45,7 @@ describe('With Custom Host Component', function() {
it('should display the error component when unknown error occurs', () => { it('should display the error component when unknown error occurs', () => {
component.component.store.dispatch( component.component.store.dispatch(
new RestOccurError(new HttpErrorResponse({ status: 0, statusText: 'Unknown Error' })), new RestOccurError(new HttpErrorResponse({ status: 0, statusText: 'Unknown Error' }))
); );
component.detectChanges(); component.detectChanges();
expect(document.querySelector('.error-template')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultErrorUnknown.title); expect(document.querySelector('.error-template')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultErrorUnknown.title);
@ -97,9 +97,9 @@ describe('With Custom Host Component', function() {
new HttpErrorResponse({ new HttpErrorResponse({
error: { error: { message: 'test message', details: 'test detail' } }, error: { error: { message: 'test message', details: 'test detail' } },
status: 412, status: 412,
headers, headers
}), })
), )
); );
component.detectChanges(); component.detectChanges();

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

@ -21,7 +21,7 @@ import { TableEmptyMessageComponent } from './components/table-empty-message/tab
import { NgxValidateCoreModule } from '@ngx-validate/core'; import { NgxValidateCoreModule } from '@ngx-validate/core';
export function appendScript(injector: Injector) { export function appendScript(injector: Injector) {
const fn = function() { const fn = () => {
import('chart.js').then(() => chartJsLoaded$.next(true)); import('chart.js').then(() => chartJsLoaded$.next(true));
const lazyLoadService: LazyLoadService = injector.get(LazyLoadService); const lazyLoadService: LazyLoadService = injector.get(LazyLoadService);
@ -32,8 +32,8 @@ export function appendScript(injector: Injector) {
'style', 'style',
styles, styles,
'head', 'head',
'afterbegin', 'afterbegin'
) /* lazyLoadService.load(null, 'script', scripts) */, ) /* lazyLoadService.load(null, 'script', scripts) */
).pipe(take(1)); ).pipe(take(1));
}; };
@ -53,7 +53,7 @@ export function appendScript(injector: Injector) {
ModalComponent, ModalComponent,
ProfileComponent, ProfileComponent,
TableEmptyMessageComponent, TableEmptyMessageComponent,
ToastComponent, ToastComponent
], ],
exports: [ exports: [
BreadcrumbComponent, BreadcrumbComponent,
@ -65,9 +65,9 @@ export function appendScript(injector: Injector) {
ModalComponent, ModalComponent,
ProfileComponent, ProfileComponent,
TableEmptyMessageComponent, TableEmptyMessageComponent,
ToastComponent, ToastComponent
], ],
entryComponents: [ErrorComponent], entryComponents: [ErrorComponent]
}) })
export class ThemeSharedModule { export class ThemeSharedModule {
static forRoot(): ModuleWithProviders { static forRoot(): ModuleWithProviders {
@ -78,10 +78,10 @@ export class ThemeSharedModule {
provide: APP_INITIALIZER, provide: APP_INITIALIZER,
multi: true, multi: true,
deps: [Injector, ErrorHandler], deps: [Injector, ErrorHandler],
useFactory: appendScript, useFactory: appendScript
}, },
{ provide: MessageService, useClass: MessageService }, { provide: MessageService, useClass: MessageService }
], ]
}; };
} }
} }

14
npm/ng-packs/packages/theme-shared/tslint.json

@ -1,17 +1,7 @@
{ {
"extends": "../../tslint.json", "extends": "../../tslint.json",
"rules": { "rules": {
"directive-selector": [ "directive-selector": [true, "attribute", "abp", "camelCase"],
true, "component-selector": [true, "element", "abp", "kebab-case"]
"attribute",
"lib",
"camelCase"
],
"component-selector": [
true,
"element",
"lib",
"kebab-case"
]
} }
} }

105
npm/ng-packs/tslint.json

@ -1,55 +1,100 @@
{ {
"extends": "tslint:recommended", "extends": "tslint:recommended",
"rulesDirectory": ["node_modules/codelyzer"],
"rules": { "rules": {
"array-type": false, "array-type": false,
"contextual-lifecycle": true,
"component-class-suffix": [true, "Component"],
"directive-class-suffix": [true, "Directive"],
"max-line-length": [true, 140],
"no-consecutive-blank-lines": false,
"no-redundant-jsdoc": true,
"no-var-requires": false,
"object-literal-key-quotes": [true, "as-needed"],
"ordered-imports": false,
"trailing-comma": false,
"component-max-inline-declarations": [true, { "animations": 20, "styles": 10, "template": 10 }],
"no-forward-ref": true,
"no-lifecycle-call": true,
"no-pipe-impure": true,
"no-queries-metadata-property": true,
"no-unused-css": true,
"prefer-output-readonly": true,
"template-conditional-complexity": [true, 4],
"use-component-selector": true,
"max-classes-per-file": false,
"arrow-parens": false, "arrow-parens": false,
"arrow-return-shorthand": true,
"callable-types": true,
"class-name": true,
"component-selector": [true, "element", "abp", "kebab-case"],
"curly": false,
"deprecation": { "deprecation": {
"severity": "warn" "severity": "warn"
}, },
"component-class-suffix": true,
"contextual-lifecycle": true,
"directive-class-suffix": true,
"directive-selector": [true, "attribute", "abp", "camelCase"], "directive-selector": [true, "attribute", "abp", "camelCase"],
"component-selector": [true, "element", "abp", "kebab-case"], "forin": true,
"import-blacklist": [true, "rxjs/Rx"], "import-blacklist": [true, "rxjs/Rx"],
"interface-name": false, "interface-over-type-literal": true,
"max-classes-per-file": false, "interface-name": [true, "never-prefix"],
"max-line-length": [true, 140], "member-access": [true, "no-public"],
"member-access": false,
"member-ordering": [ "member-ordering": [
true, true,
{ {
"order": ["static-field", "instance-field", "static-method", "instance-method"] "order": ["static-field", "instance-field", "static-method", "instance-method"]
} }
], ],
"no-consecutive-blank-lines": false, "no-arg": true,
"no-bitwise": true,
"no-conflicting-lifecycle": true,
"no-console": [true, "debug", "info", "time", "timeEnd", "trace"], "no-console": [true, "debug", "info", "time", "timeEnd", "trace"],
"no-construct": true,
"no-debugger": true,
"no-duplicate-super": true,
"no-empty-interface": true,
"no-empty": false, "no-empty": false,
"no-inferrable-types": [false, "ignore-params"], "no-eval": true,
"no-non-null-assertion": true,
"no-redundant-jsdoc": true,
"no-switch-case-fall-through": true,
"no-use-before-declare": true,
"no-var-requires": false,
"curly": false,
"object-literal-key-quotes": [true, "as-needed"],
"object-literal-sort-keys": false,
"ordered-imports": false,
"quotemark": [true, "single"],
"trailing-comma": false,
"no-conflicting-lifecycle": true,
"no-host-metadata-property": true, "no-host-metadata-property": true,
"no-input-rename": true, "no-inferrable-types": [true, "ignore-params"],
"no-input-rename": false,
"no-inputs-metadata-property": true, "no-inputs-metadata-property": true,
"no-misused-new": true,
"no-namespace": false,
"no-non-null-assertion": true,
"no-output-native": true, "no-output-native": true,
"no-output-on-prefix": true, "no-output-on-prefix": true,
"no-output-rename": true, "no-output-rename": false,
"no-outputs-metadata-property": true, "no-outputs-metadata-property": true,
"no-namespace": false, "no-shadowed-variable": true,
"template-banana-in-box": true, "no-string-literal": false,
"template-no-negated-async": true, "no-string-throw": true,
"no-switch-case-fall-through": true,
"no-unnecessary-initializer": true,
"no-unnecessary-semicolons": false,
"no-unused-expression": true,
"no-var-keyword": true,
"object-literal-sort-keys": false,
"prefer-const": true,
"quotemark": [true, "single", "avoid-escape", "avoid-template"],
"radix": true,
"semicolon": [true, "always", "ignore-bound-class-methods"],
// "template-accessibility-alt-text": true,
// "template-accessibility-elements-content": true,
// "template-accessibility-label-for": true,
// "template-accessibility-tabindex-no-positive": true,
// "template-accessibility-table-scope": true,
// "template-accessibility-valid-aria": true,
// "template-banana-in-box": true,
// "template-click-events-have-key-events": true,
// "template-mouse-events-have-key-events": true,
// "template-no-autofocus": true,
// "template-no-distracting-elements": true,
// "template-no-negated-async": true,
"triple-equals": [true, "allow-null-check"],
"unified-signatures": true,
"use-lifecycle-interface": true, "use-lifecycle-interface": true,
"use-pipe-transform-interface": true "use-pipe-transform-interface": true,
}, "variable-name": false,
"rulesDirectory": ["codelyzer"] "prefer-for-of": false
}
} }

Loading…
Cancel
Save