Browse Source

Merge pull request #4216 from abpframework/feat/ngx-datatable

Implement ngx-datatable and replace the abp-tables with the new table
pull/4316/head
Levent Arman Özak 6 years ago
committed by GitHub
parent
commit
d894439208
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json
  2. 4
      framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json
  3. 15
      npm/ng-packs/angular.json
  4. 1
      npm/ng-packs/package.json
  5. 22
      npm/ng-packs/packages/core/src/lib/services/list.service.ts
  6. 6
      npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts
  7. 123
      npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.html
  8. 42
      npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.ts
  9. 154
      npm/ng-packs/packages/identity/src/lib/components/users/users.component.html
  10. 59
      npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts
  11. 142
      npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.html
  12. 51
      npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.ts
  13. 1
      npm/ng-packs/packages/theme-shared/ng-package.json
  14. 1
      npm/ng-packs/packages/theme-shared/package.json
  15. 8
      npm/ng-packs/packages/theme-shared/src/lib/constants/styles.ts
  16. 2
      npm/ng-packs/packages/theme-shared/src/lib/directives/index.ts
  17. 23
      npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-default.directive.ts
  18. 70
      npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts
  19. 46
      npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts
  20. 10
      npm/ng-packs/scripts/prod-build.ts
  21. 12
      npm/ng-packs/scripts/yarn.lock
  22. 2
      npm/ng-packs/tslint.json
  23. 161
      npm/ng-packs/yarn.lock
  24. 15
      templates/app/angular/angular.json
  25. 60
      templates/module/angular/angular.json
  26. 19
      templates/module/angular/src/app/app.component.ts

4
framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json

@ -47,6 +47,8 @@
"PagerInfoEmpty": "Showing 0 to 0 of 0 entries", "PagerInfoEmpty": "Showing 0 to 0 of 0 entries",
"PagerInfoFiltered": "(filtered from _MAX_ total entries)", "PagerInfoFiltered": "(filtered from _MAX_ total entries)",
"NoDataAvailableInDatatable": "No data available", "NoDataAvailableInDatatable": "No data available",
"Total": "total",
"Selected": "selected",
"PagerShowMenuEntries": "Show _MENU_ entries", "PagerShowMenuEntries": "Show _MENU_ entries",
"DatatableActionDropdownDefaultText": "Actions", "DatatableActionDropdownDefaultText": "Actions",
"ChangePassword": "Change password", "ChangePassword": "Change password",
@ -59,6 +61,6 @@
"500Message": "Internal Server Error", "500Message": "Internal Server Error",
"GoHomePage": "Go to the homepage", "GoHomePage": "Go to the homepage",
"GoBack": "Go back", "GoBack": "Go back",
"Search" : "Search" "Search": "Search"
} }
} }

4
framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json

@ -47,6 +47,8 @@
"PagerInfoEmpty": "0 kayıttan 0 ile 0 arası gösteriliyor.", "PagerInfoEmpty": "0 kayıttan 0 ile 0 arası gösteriliyor.",
"PagerInfoFiltered": "(_MAX_ kayıt arasından filtrelendi)", "PagerInfoFiltered": "(_MAX_ kayıt arasından filtrelendi)",
"NoDataAvailableInDatatable": "Tabloda kayıt mevcut değil.", "NoDataAvailableInDatatable": "Tabloda kayıt mevcut değil.",
"Total": "toplam",
"Selected": "seçilen",
"PagerShowMenuEntries": "Sayfada _MENU_ kayıt göster.", "PagerShowMenuEntries": "Sayfada _MENU_ kayıt göster.",
"DatatableActionDropdownDefaultText": "İşlemler", "DatatableActionDropdownDefaultText": "İşlemler",
"ChangePassword": "Şifre değiştir", "ChangePassword": "Şifre değiştir",
@ -61,4 +63,4 @@
"GoBack": "Geri dön", "GoBack": "Geri dön",
"Search": "Arama" "Search": "Arama"
} }
} }

15
npm/ng-packs/angular.json

@ -518,6 +518,21 @@
"inject": true, "inject": true,
"bundleName": "fontawesome-v4-shims.min" "bundleName": "fontawesome-v4-shims.min"
}, },
{
"input": "node_modules/@swimlane/ngx-datatable/index.css",
"inject": true,
"bundleName": "ngx-datatable-index"
},
{
"input": "node_modules/@swimlane/ngx-datatable/assets/icons.css",
"inject": true,
"bundleName": "ngx-datatable-icons"
},
{
"input": "node_modules/@swimlane/ngx-datatable/themes/material.css",
"inject": true,
"bundleName": "ngx-datatable-material"
},
"apps/dev-app/src/styles.scss" "apps/dev-app/src/styles.scss"
], ],
"scripts": [] "scripts": []

1
npm/ng-packs/package.json

@ -61,6 +61,7 @@
"@ngxs/router-plugin": "^3.6.2", "@ngxs/router-plugin": "^3.6.2",
"@ngxs/storage-plugin": "^3.6.2", "@ngxs/storage-plugin": "^3.6.2",
"@ngxs/store": "^3.6.2", "@ngxs/store": "^3.6.2",
"@swimlane/ngx-datatable": "^16.0.0",
"@types/jest": "^25.2.3", "@types/jest": "^25.2.3",
"@types/node": "^12.11.1", "@types/node": "^12.11.1",
"angular-oauth2-oidc": "^8.0.4", "angular-oauth2-oidc": "^8.0.4",

22
npm/ng-packs/packages/core/src/lib/services/list.service.ts

@ -7,7 +7,7 @@ import { LIST_QUERY_DEBOUNCE_TIME } from '../tokens/list.token';
import { takeUntilDestroy } from '../utils/rxjs-utils'; import { takeUntilDestroy } from '../utils/rxjs-utils';
@Injectable() @Injectable()
export class ListService implements OnDestroy { export class ListService<QueryParamsType = ABP.PageQueryParams> implements OnDestroy {
private _filter = ''; private _filter = '';
set filter(value: string) { set filter(value: string) {
this._filter = value; this._filter = value;
@ -26,8 +26,10 @@ export class ListService implements OnDestroy {
return this._maxResultCount; return this._maxResultCount;
} }
private _page = 1; private _page = 0;
set page(value: number) { set page(value: number) {
if (value === this._page) return;
this._page = value; this._page = value;
this.get(); this.get();
} }
@ -53,9 +55,9 @@ export class ListService implements OnDestroy {
return this._sortOrder; return this._sortOrder;
} }
private _query$ = new ReplaySubject<ABP.PageQueryParams>(1); private _query$ = new ReplaySubject<QueryParamsType>(1);
get query$(): Observable<ABP.PageQueryParams> { get query$(): Observable<QueryParamsType> {
return this._query$ return this._query$
.asObservable() .asObservable()
.pipe(debounceTime(this.delay || 300), shareReplay({ bufferSize: 1, refCount: true })); .pipe(debounceTime(this.delay || 300), shareReplay({ bufferSize: 1, refCount: true }));
@ -68,12 +70,12 @@ export class ListService implements OnDestroy {
} }
get = () => { get = () => {
this._query$.next({ this._query$.next(({
filter: this._filter || undefined, filter: this._filter || undefined,
maxResultCount: this._maxResultCount, maxResultCount: this._maxResultCount,
skipCount: (this._page - 1) * this._maxResultCount, skipCount: this._page * this._maxResultCount,
sorting: this._sortOrder ? `${this._sortKey} ${this._sortOrder}` : undefined, sorting: this._sortOrder ? `${this._sortKey} ${this._sortOrder}` : undefined,
}); } as any) as QueryParamsType);
}; };
constructor(@Optional() @Inject(LIST_QUERY_DEBOUNCE_TIME) private delay: number) { constructor(@Optional() @Inject(LIST_QUERY_DEBOUNCE_TIME) private delay: number) {
@ -81,7 +83,7 @@ export class ListService implements OnDestroy {
} }
hookToQuery<T extends any>( hookToQuery<T extends any>(
streamCreatorCallback: QueryStreamCreatorCallback<T>, streamCreatorCallback: QueryStreamCreatorCallback<T, QueryParamsType>,
): Observable<PagedResultDto<T>> { ): Observable<PagedResultDto<T>> {
this._isLoading$.next(true); this._isLoading$.next(true);
@ -96,6 +98,6 @@ export class ListService implements OnDestroy {
ngOnDestroy() {} ngOnDestroy() {}
} }
export type QueryStreamCreatorCallback<T> = ( export type QueryStreamCreatorCallback<T, QueryParamsType = ABP.PageQueryParams> = (
query: ABP.PageQueryParams, query: QueryParamsType,
) => Observable<PagedResultDto<T>>; ) => Observable<PagedResultDto<T>>;

6
npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts

@ -49,8 +49,8 @@ describe('ListService', () => {
}); });
describe('#page', () => { describe('#page', () => {
it('should initially be 1', () => { it('should initially be 0', () => {
expect(service.page).toBe(1); expect(service.page).toBe(0);
}); });
it('should be changed', () => { it('should be changed', () => {
@ -110,7 +110,7 @@ describe('ListService', () => {
filter: 'foo', filter: 'foo',
sorting: 'bar baz', sorting: 'bar baz',
maxResultCount: 20, maxResultCount: 20,
skipCount: 160, skipCount: 180,
}); });
done(); done();

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

@ -20,89 +20,54 @@
</div> </div>
<div class="card-body"> <div class="card-body">
<abp-table <ngx-datatable [rows]="data$ | async" [count]="totalCount$ | async" [list]="list" default>
*ngIf="[150, 0] as columnWidths" <ngx-datatable-column
[abpLoading]="loading" [name]="'AbpIdentity::Actions' | abpLocalization"
[abpLoadingDelay]="500" [maxWidth]="150"
[abpTableSort]="{ key: sortKey, order: sortOrder }" [sortable]="false"
[colgroupTemplate]="tableColGroup" >
[headerTemplate]="tableHeader" <ng-template let-row="row" ngx-datatable-cell-template>
[bodyTemplate]="tableBody" <div ngbDropdown container="body" class="d-inline-block">
[value]="data$ | async" <button
[rows]="pageQuery.maxResultCount" class="btn btn-primary btn-sm dropdown-toggle"
[totalRecords]="totalCount$ | async" data-toggle="dropdown"
[scrollable]="true" aria-haspopup="true"
(pageChange)="onPageChange($event)" ngbDropdownToggle
> >
<ng-template #tableColGroup> <i class="fa fa-cog mr-1"></i>{{ 'AbpIdentity::Actions' | abpLocalization }}
<colgroup> </button>
<col *ngFor="let width of columnWidths" [ngStyle]="{ 'width.px': width || undefined }" /> <div ngbDropdownMenu>
</colgroup>
</ng-template>
<ng-template #tableHeader>
<tr>
<th>{{ 'AbpIdentity::Actions' | abpLocalization }}</th>
<th (click)="sortOrderIcon.sort('name')">
{{ 'AbpIdentity::RoleName' | abpLocalization }}
<abp-sort-order-icon
#sortOrderIcon
sortKey="name"
[(selectedSortKey)]="sortKey"
[(order)]="sortOrder"
></abp-sort-order-icon>
</th>
</tr>
</ng-template>
<ng-template #tableBody let-data>
<tr>
<td class="text-center">
<div ngbDropdown container="body" class="d-inline-block">
<button <button
class="btn btn-primary btn-sm dropdown-toggle" *abpPermission="'AbpIdentity.Roles.Update'"
data-toggle="dropdown" ngbDropdownItem
aria-haspopup="true" (click)="edit(row.id)"
ngbDropdownToggle
> >
<i class="fa fa-cog mr-1"></i>{{ 'AbpIdentity::Actions' | abpLocalization }} {{ 'AbpIdentity::Edit' | abpLocalization }}
</button>
<button
*abpPermission="'AbpIdentity.Roles.ManagePermissions'"
ngbDropdownItem
(click)="openPermissionsModal(row.name)"
>
{{ 'AbpIdentity::Permissions' | abpLocalization }}
</button>
<button
*ngIf="!row.isStatic"
[abpPermission]="'AbpIdentity.Roles.Delete'"
ngbDropdownItem
(click)="delete(row.id, row.name)"
>
{{ 'AbpIdentity::Delete' | abpLocalization }}
</button> </button>
<div ngbDropdownMenu>
<button
*abpPermission="'AbpIdentity.Roles.Update'"
ngbDropdownItem
(click)="edit(data.id)"
>
{{ 'AbpIdentity::Edit' | abpLocalization }}
</button>
<button
*abpPermission="'AbpIdentity.Roles.ManagePermissions'"
ngbDropdownItem
(click)="openPermissionsModal(data.name)"
>
{{ 'AbpIdentity::Permissions' | abpLocalization }}
</button>
<button
*ngIf="!data.isStatic"
[abpPermission]="'AbpIdentity.Roles.Delete'"
ngbDropdownItem
(click)="delete(data.id, data.name)"
>
{{ 'AbpIdentity::Delete' | abpLocalization }}
</button>
</div>
</div> </div>
</td> </div>
<td> </ng-template>
{{ data.name </ngx-datatable-column>
}}<span *ngIf="data.isDefault" class="badge badge-pill badge-success ml-1">{{ <ngx-datatable-column
'AbpIdentity::DisplayName:IsDefault' | abpLocalization [name]="'AbpIdentity::RoleName' | abpLocalization"
}}</span> prop="name"
<span *ngIf="data.isPublic" class="badge badge-pill badge-info ml-1">{{ ></ngx-datatable-column>
'AbpIdentity::DisplayName:IsPublic' | abpLocalization </ngx-datatable>
}}</span>
</td>
</tr>
</ng-template>
</abp-table>
</div> </div>
</div> </div>

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

@ -1,5 +1,6 @@
import { ABP } from '@abp/ng.core'; import { ListService } from '@abp/ng.core';
import { ConfirmationService, Confirmation } from '@abp/ng.theme.shared'; import { ePermissionManagementComponents } from '@abp/ng.permission-management';
import { Confirmation, ConfirmationService } from '@abp/ng.theme.shared';
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { Select, Store } from '@ngxs/store'; import { Select, Store } from '@ngxs/store';
@ -14,11 +15,11 @@ import {
} 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';
import { ePermissionManagementComponents } from '@abp/ng.permission-management';
@Component({ @Component({
selector: 'abp-roles', selector: 'abp-roles',
templateUrl: './roles.component.html', templateUrl: './roles.component.html',
providers: [ListService],
}) })
export class RolesComponent implements OnInit { export class RolesComponent implements OnInit {
@Select(IdentityState.getRoles) @Select(IdentityState.getRoles)
@ -37,16 +38,8 @@ export class RolesComponent implements OnInit {
providerKey: string; providerKey: string;
pageQuery: ABP.PageQueryParams = { maxResultCount: 10 };
loading = false;
modalBusy = false; modalBusy = false;
sortOrder = '';
sortKey = '';
permissionManagementKey = ePermissionManagementComponents.PermissionManagement; permissionManagementKey = ePermissionManagementComponents.PermissionManagement;
@ViewChild('formRef', { static: false, read: ElementRef }) @ViewChild('formRef', { static: false, read: ElementRef })
@ -57,13 +50,14 @@ export class RolesComponent implements OnInit {
}; };
constructor( constructor(
public readonly list: ListService,
private confirmationService: ConfirmationService, private confirmationService: ConfirmationService,
private fb: FormBuilder, private fb: FormBuilder,
private store: Store, private store: Store,
) {} ) {}
ngOnInit() { ngOnInit() {
this.get(); this.hookToQuery();
} }
buildForm() { buildForm() {
@ -110,7 +104,7 @@ export class RolesComponent implements OnInit {
.pipe(finalize(() => (this.modalBusy = false))) .pipe(finalize(() => (this.modalBusy = false)))
.subscribe(() => { .subscribe(() => {
this.isModalVisible = false; this.isModalVisible = false;
this.get(); this.list.get();
}); });
} }
@ -121,23 +115,13 @@ export class RolesComponent implements OnInit {
}) })
.subscribe((status: Confirmation.Status) => { .subscribe((status: Confirmation.Status) => {
if (status === Confirmation.Status.confirm) { if (status === Confirmation.Status.confirm) {
this.store.dispatch(new DeleteRole(id)).subscribe(() => this.get()); this.store.dispatch(new DeleteRole(id)).subscribe(() => this.list.get());
} }
}); });
} }
onPageChange(page: number) { private hookToQuery() {
this.pageQuery.skipCount = (page - 1) * this.pageQuery.maxResultCount; this.list.hookToQuery(query => this.store.dispatch(new GetRoles(query))).subscribe();
this.get();
}
get() {
this.loading = true;
this.store
.dispatch(new GetRoles(this.pageQuery))
.pipe(finalize(() => (this.loading = false)))
.subscribe();
} }
onClickSaveButton() { onClickSaveButton() {
@ -152,4 +136,10 @@ export class RolesComponent implements OnInit {
this.visiblePermissions = true; this.visiblePermissions = true;
}, 0); }, 0);
} }
sort(data) {
const { prop, dir } = data.sorts[0];
this.list.sortKey = prop;
this.list.sortOrder = dir;
}
} }

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

@ -20,108 +20,74 @@
</div> </div>
<div class="card-body"> <div class="card-body">
<div id="data-tables-table-filter" class="data-tables-filter"> <div id="data-tables-table-filter" class="data-tables-filter">
<label <div class="input-group">
><input <input
type="search" type="search"
class="form-control form-control-sm" class="form-control"
[placeholder]="'AbpUi::PagerSearch' | abpLocalization" [placeholder]="'AbpUi::PagerSearch' | abpLocalization"
(input.debounce)="onSearch($event.target.value)" [(ngModel)]="list.filter"
/></label> />
</div>
</div> </div>
<abp-table
*ngIf="[150, 250, 250, 250] as columnWidths" <ngx-datatable [rows]="data$ | async" [count]="totalCount$ | async" [list]="list" default>
[abpLoading]="loading" <ngx-datatable-column
[abpLoadingDelay]="500" [name]="'AbpIdentity::Actions' | abpLocalization"
[abpTableSort]="{ key: sortKey, order: sortOrder }" [maxWidth]="150"
[colgroupTemplate]="tableColGroup" [sortable]="false"
[headerTemplate]="tableHeader" >
[bodyTemplate]="tableBody" <ng-template let-row="row" ngx-datatable-cell-template>
[value]="data$ | async" <div ngbDropdown container="body" class="d-inline-block">
[rows]="pageQuery.maxResultCount" <button
[totalRecords]="totalCount$ | async" class="btn btn-primary btn-sm dropdown-toggle"
[scrollable]="true" data-toggle="dropdown"
(pageChange)="onPageChange($event)" aria-haspopup="true"
> ngbDropdownToggle
<ng-template #tableColGroup>
<colgroup>
<col *ngFor="let width of columnWidths" [ngStyle]="{ 'width.px': width || undefined }" />
</colgroup>
</ng-template>
<ng-template #tableHeader>
<tr>
<th>{{ 'AbpIdentity::Actions' | abpLocalization }}</th>
<th (click)="sortOrderIcon.sort('userName')">
{{ 'AbpIdentity::UserName' | abpLocalization }}
<abp-sort-order-icon
#sortOrderIcon
sortKey="userName"
[(selectedSortKey)]="sortKey"
[(order)]="sortOrder"
>
</abp-sort-order-icon>
</th>
<th (click)="sortOrderIcon.sort('email')">
{{ 'AbpIdentity::EmailAddress' | abpLocalization }}
<abp-sort-order-icon
sortKey="email"
[(selectedSortKey)]="sortKey"
[(order)]="sortOrder"
></abp-sort-order-icon>
</th>
<th (click)="sortOrderIcon.sort('phoneNumber')">
{{ 'AbpIdentity::PhoneNumber' | abpLocalization }}
<abp-sort-order-icon
sortKey="phoneNumber"
[(selectedSortKey)]="sortKey"
[(order)]="sortOrder"
> >
</abp-sort-order-icon> <i class="fa fa-cog mr-1"></i>{{ 'AbpIdentity::Actions' | abpLocalization }}
</th> </button>
</tr> <div ngbDropdownMenu>
</ng-template>
<ng-template #tableBody let-data>
<tr>
<td class="text-center">
<div ngbDropdown container="body" class="d-inline-block">
<button <button
class="btn btn-primary btn-sm dropdown-toggle" *abpPermission="'AbpIdentity.Users.Update'"
data-toggle="dropdown" ngbDropdownItem
aria-haspopup="true" (click)="edit(row.id)"
ngbDropdownToggle
> >
<i class="fa fa-cog mr-1"></i>{{ 'AbpIdentity::Actions' | abpLocalization }} {{ 'AbpIdentity::Edit' | abpLocalization }}
</button>
<button
*abpPermission="'AbpIdentity.Users.ManagePermissions'"
ngbDropdownItem
(click)="openPermissionsModal(row.id)"
>
{{ 'AbpIdentity::Permissions' | abpLocalization }}
</button>
<button
*abpPermission="'AbpIdentity.Users.Delete'"
ngbDropdownItem
(click)="delete(row.id, row.userName)"
>
{{ 'AbpIdentity::Delete' | abpLocalization }}
</button> </button>
<div ngbDropdownMenu>
<button
*abpPermission="'AbpIdentity.Users.Update'"
ngbDropdownItem
(click)="edit(data.id)"
>
{{ 'AbpIdentity::Edit' | abpLocalization }}
</button>
<button
*abpPermission="'AbpIdentity.Users.ManagePermissions'"
ngbDropdownItem
(click)="openPermissionsModal(data.id)"
>
{{ 'AbpIdentity::Permissions' | abpLocalization }}
</button>
<button
*abpPermission="'AbpIdentity.Users.Delete'"
ngbDropdownItem
(click)="delete(data.id, data.userName)"
>
{{ 'AbpIdentity::Delete' | abpLocalization }}
</button>
</div>
</div> </div>
</td> </div>
<td>{{ data.userName }}</td> </ng-template>
<td>{{ data.email }}</td> </ngx-datatable-column>
<td>{{ data.phoneNumber }}</td> <ngx-datatable-column
</tr> [width]="200"
</ng-template> [name]="'AbpIdentity::UserName' | abpLocalization"
</abp-table> prop="userName"
></ngx-datatable-column>
<ngx-datatable-column
[width]="200"
[name]="'AbpIdentity::EmailAddress' | abpLocalization"
prop="email"
></ngx-datatable-column>
<ngx-datatable-column
[width]="200"
[name]="'AbpIdentity::PhoneNumber' | abpLocalization"
prop="phoneNumber"
></ngx-datatable-column>
</ngx-datatable>
</div> </div>
</div> </div>

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

@ -1,13 +1,27 @@
import { ABP } from '@abp/ng.core'; import { ListService } from '@abp/ng.core';
import { ePermissionManagementComponents } from '@abp/ng.permission-management'; import { ePermissionManagementComponents } from '@abp/ng.permission-management';
import { Confirmation, ConfirmationService, getPasswordValidators } from '@abp/ng.theme.shared'; import { Confirmation, ConfirmationService, getPasswordValidators } from '@abp/ng.theme.shared';
import { Component, OnInit, TemplateRef, TrackByFunction, ViewChild } from '@angular/core'; import { Component, OnInit, TemplateRef, TrackByFunction, ViewChild } from '@angular/core';
import { AbstractControl, FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import {
AbstractControl,
FormArray,
FormBuilder,
FormControl,
FormGroup,
Validators,
} from '@angular/forms';
import { Select, Store } from '@ngxs/store'; import { Select, Store } from '@ngxs/store';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { finalize, pluck, switchMap, take } from 'rxjs/operators'; import { finalize, pluck, switchMap, take } from 'rxjs/operators';
import snq from 'snq'; import snq from 'snq';
import { CreateUser, DeleteUser, GetUserById, GetUserRoles, GetUsers, UpdateUser } from '../../actions/identity.actions'; import {
CreateUser,
DeleteUser,
GetUserById,
GetUserRoles,
GetUsers,
UpdateUser,
} from '../../actions/identity.actions';
import { Identity } from '../../models/identity'; import { Identity } from '../../models/identity';
import { IdentityService } from '../../services/identity.service'; import { IdentityService } from '../../services/identity.service';
import { IdentityState } from '../../states/identity.state'; import { IdentityState } from '../../states/identity.state';
@ -15,6 +29,7 @@ import { IdentityState } from '../../states/identity.state';
@Component({ @Component({
selector: 'abp-users', selector: 'abp-users',
templateUrl: './users.component.html', templateUrl: './users.component.html',
providers: [ListService],
}) })
export class UsersComponent implements OnInit { export class UsersComponent implements OnInit {
@Select(IdentityState.getUsers) @Select(IdentityState.getUsers)
@ -23,7 +38,7 @@ export class UsersComponent implements OnInit {
@Select(IdentityState.getUsersTotalCount) @Select(IdentityState.getUsersTotalCount)
totalCount$: Observable<number>; totalCount$: Observable<number>;
@ViewChild('modalContent', {static: false}) @ViewChild('modalContent', { static: false })
modalContent: TemplateRef<any>; modalContent: TemplateRef<any>;
form: FormGroup; form: FormGroup;
@ -38,18 +53,10 @@ export class UsersComponent implements OnInit {
providerKey: string; providerKey: string;
pageQuery: ABP.PageQueryParams = { maxResultCount: 10 };
isModalVisible: boolean; isModalVisible: boolean;
loading = false;
modalBusy = false; modalBusy = false;
sortOrder = '';
sortKey = '';
permissionManagementKey = ePermissionManagementComponents.PermissionManagement; permissionManagementKey = ePermissionManagementComponents.PermissionManagement;
trackByFn: TrackByFunction<AbstractControl> = (index, item) => Object.keys(item)[0] || index; trackByFn: TrackByFunction<AbstractControl> = (index, item) => Object.keys(item)[0] || index;
@ -63,6 +70,7 @@ export class UsersComponent implements OnInit {
} }
constructor( constructor(
public readonly list: ListService,
private confirmationService: ConfirmationService, private confirmationService: ConfirmationService,
private fb: FormBuilder, private fb: FormBuilder,
private store: Store, private store: Store,
@ -70,12 +78,7 @@ export class UsersComponent implements OnInit {
) {} ) {}
ngOnInit() { ngOnInit() {
this.get(); this.hookToQuery();
}
onSearch(value: string) {
this.pageQuery.filter = value;
this.get();
} }
buildForm() { buildForm() {
@ -170,7 +173,7 @@ export class UsersComponent implements OnInit {
.pipe(finalize(() => (this.modalBusy = false))) .pipe(finalize(() => (this.modalBusy = false)))
.subscribe(() => { .subscribe(() => {
this.isModalVisible = false; this.isModalVisible = false;
this.get(); this.list.get();
}); });
} }
@ -181,23 +184,19 @@ export class UsersComponent implements OnInit {
}) })
.subscribe((status: Confirmation.Status) => { .subscribe((status: Confirmation.Status) => {
if (status === Confirmation.Status.confirm) { if (status === Confirmation.Status.confirm) {
this.store.dispatch(new DeleteUser(id)).subscribe(() => this.get()); this.store.dispatch(new DeleteUser(id)).subscribe(() => this.list.get());
} }
}); });
} }
onPageChange(page: number) { sort(data) {
this.pageQuery.skipCount = (page - 1) * this.pageQuery.maxResultCount; const { prop, dir } = data.sorts[0];
this.list.sortKey = prop;
this.get(); this.list.sortOrder = dir;
} }
get() { private hookToQuery() {
this.loading = true; this.list.hookToQuery(query => this.store.dispatch(new GetUsers(query))).subscribe();
this.store
.dispatch(new GetUsers(this.pageQuery))
.pipe(finalize(() => (this.loading = false)))
.subscribe();
} }
openPermissionsModal(providerKey: string) { openPermissionsModal(providerKey: string) {

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

@ -18,99 +18,73 @@
</div> </div>
</div> </div>
</div> </div>
<div class="card-body"> <div class="card-body">
<div id="data-tables-table-filter" class="data-tables-filter"> <div id="data-tables-table-filter" class="data-tables-filter">
<label <div class="input-group">
><input <input
type="search" type="search"
class="form-control form-control-sm" class="form-control"
[placeholder]="'AbpUi::PagerSearch' | abpLocalization" [placeholder]="'AbpUi::PagerSearch' | abpLocalization"
(input.debounce)="onSearch($event.target.value)" [(ngModel)]="list.filter"
/></label> />
</div>
</div> </div>
<abp-table
*ngIf="[150, 0] as columnWidths" <ngx-datatable [rows]="data$ | async" [count]="totalCount$ | async" [list]="list" default>
[abpLoading]="loading" <ngx-datatable-column
[abpLoadingDelay]="500" [name]="'AbpTenantManagement::Actions' | abpLocalization"
[abpTableSort]="{ key: sortKey, order: sortOrder }" [maxWidth]="150"
[colgroupTemplate]="tableColGroup" [sortable]="false"
[headerTemplate]="tableHeader" >
[bodyTemplate]="tableBody" <ng-template let-row="row" ngx-datatable-cell-template>
[value]="data$ | async" <div ngbDropdown container="body" class="d-inline-block">
[abpTableSort]="{ key: sortKey, order: sortOrder }" <button
[rows]="pageQuery.maxResultCount" class="btn btn-primary btn-sm dropdown-toggle"
[totalRecords]="totalCount$ | async" data-toggle="dropdown"
[scrollable]="true" aria-haspopup="true"
(pageChange)="onPageChange($event)" ngbDropdownToggle
>
<ng-template #tableColGroup>
<colgroup>
<col *ngFor="let width of columnWidths" [ngStyle]="{ 'width.px': width || undefined }" />
</colgroup>
</ng-template>
<ng-template #tableHeader let-columns>
<tr>
<th>{{ 'AbpTenantManagement::Actions' | abpLocalization }}</th>
<th (click)="sortOrderIcon.sort('name')">
{{ 'AbpTenantManagement::TenantName' | abpLocalization }}
<abp-sort-order-icon
#sortOrderIcon
sortKey="name"
[(selectedSortKey)]="sortKey"
[(order)]="sortOrder"
> >
</abp-sort-order-icon> <i class="fa fa-cog mr-1"></i>{{ 'AbpTenantManagement::Actions' | abpLocalization }}
</th> </button>
</tr> <div ngbDropdownMenu>
</ng-template> <button
<ng-template #tableBody let-data> *abpPermission="'AbpTenantManagement.Tenants.Update'"
<tr> ngbDropdownItem
<td class="text-center"> (click)="editTenant(row.id)"
<div ngbDropdown container="body" class="d-inline-block"> >
{{ 'AbpTenantManagement::Edit' | abpLocalization }}
</button>
<button
*abpPermission="'AbpTenantManagement.Tenants.ManageConnectionStrings'"
ngbDropdownItem
(click)="onEditConnectionString(row.id)"
>
{{ 'AbpTenantManagement::Permission:ManageConnectionStrings' | abpLocalization }}
</button>
<button
*abpPermission="'AbpTenantManagement.Tenants.ManageFeatures'"
ngbDropdownItem
(click)="openFeaturesModal(row.id)"
>
{{ 'AbpTenantManagement::Permission:ManageFeatures' | abpLocalization }}
</button>
<button <button
class="btn btn-primary btn-sm dropdown-toggle" *abpPermission="'AbpTenantManagement.Tenants.Delete'"
data-toggle="dropdown" ngbDropdownItem
aria-haspopup="true" (click)="delete(row.id, row.name)"
ngbDropdownToggle
> >
<i class="fa fa-cog mr-1"></i>{{ 'AbpTenantManagement::Actions' | abpLocalization }} {{ 'AbpTenantManagement::Delete' | abpLocalization }}
</button> </button>
<div ngbDropdownMenu>
<button
*abpPermission="'AbpTenantManagement.Tenants.Update'"
ngbDropdownItem
(click)="editTenant(data.id)"
>
{{ 'AbpTenantManagement::Edit' | abpLocalization }}
</button>
<button
*abpPermission="'AbpTenantManagement.Tenants.ManageConnectionStrings'"
ngbDropdownItem
(click)="onEditConnectionString(data.id)"
>
{{ 'AbpTenantManagement::Permission:ManageConnectionStrings' | abpLocalization }}
</button>
<button
*abpPermission="'AbpTenantManagement.Tenants.ManageFeatures'"
ngbDropdownItem
(click)="openFeaturesModal(data.id)"
>
{{ 'AbpTenantManagement::Permission:ManageFeatures' | abpLocalization }}
</button>
<button
*abpPermission="'AbpTenantManagement.Tenants.Delete'"
ngbDropdownItem
(click)="delete(data.id, data.name)"
>
{{ 'AbpTenantManagement::Delete' | abpLocalization }}
</button>
</div>
</div> </div>
</td> </div>
<td>{{ data.name }}</td> </ng-template>
</tr> </ngx-datatable-column>
</ng-template> <ngx-datatable-column
</abp-table> [name]="'AbpTenantManagement::TenantName' | abpLocalization"
prop="name"
></ngx-datatable-column>
</ngx-datatable>
</div> </div>
</div> </div>
@ -128,7 +102,7 @@
{{ 'AbpTenantManagement::Cancel' | abpLocalization }} {{ 'AbpTenantManagement::Cancel' | abpLocalization }}
</button> </button>
<abp-button iconClass="fa fa-check" (click)="save()" [disabled]="isDisabledSaveButton">{{ <abp-button iconClass="fa fa-check" (click)="save()" [disabled]="isDisabledSaveButton">{{
'AbpIdentity::Save' | abpLocalization 'AbpTenantManagement::Save' | abpLocalization
}}</abp-button> }}</abp-button>
</ng-template> </ng-template>
</abp-modal> </abp-modal>

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

@ -1,4 +1,4 @@
import { ABP } from '@abp/ng.core'; import { ABP, ListService } from '@abp/ng.core';
import { eFeatureManagementComponents } from '@abp/ng.feature-management'; import { eFeatureManagementComponents } from '@abp/ng.feature-management';
import { Confirmation, ConfirmationService, getPasswordValidators } from '@abp/ng.theme.shared'; import { Confirmation, ConfirmationService, getPasswordValidators } from '@abp/ng.theme.shared';
import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
@ -6,7 +6,13 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Select, Store } from '@ngxs/store'; import { Select, Store } from '@ngxs/store';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { finalize, pluck, switchMap, take } from 'rxjs/operators'; import { finalize, pluck, switchMap, take } from 'rxjs/operators';
import { CreateTenant, DeleteTenant, GetTenantById, GetTenants, UpdateTenant } from '../../actions/tenant-management.actions'; import {
CreateTenant,
DeleteTenant,
GetTenantById,
GetTenants,
UpdateTenant,
} 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';
@ -19,6 +25,7 @@ interface SelectedModalContent {
@Component({ @Component({
selector: 'abp-tenants', selector: 'abp-tenants',
templateUrl: './tenants.component.html', templateUrl: './tenants.component.html',
providers: [ListService],
}) })
export class TenantsComponent implements OnInit { export class TenantsComponent implements OnInit {
@Select(TenantManagementState.get) @Select(TenantManagementState.get)
@ -45,16 +52,8 @@ export class TenantsComponent implements OnInit {
_useSharedDatabase: boolean; _useSharedDatabase: boolean;
pageQuery: ABP.PageQueryParams = { maxResultCount: 10 };
loading = false;
modalBusy = false; modalBusy = false;
sortOrder = '';
sortKey = '';
featureManagementKey = eFeatureManagementComponents.FeatureManagement; featureManagementKey = eFeatureManagementComponents.FeatureManagement;
get hasSelectedTenant(): boolean { get hasSelectedTenant(): boolean {
@ -100,6 +99,7 @@ export class TenantsComponent implements OnInit {
}; };
constructor( constructor(
public readonly list: ListService,
private confirmationService: ConfirmationService, private confirmationService: ConfirmationService,
private tenantService: TenantManagementService, private tenantService: TenantManagementService,
private fb: FormBuilder, private fb: FormBuilder,
@ -107,12 +107,7 @@ export class TenantsComponent implements OnInit {
) {} ) {}
ngOnInit() { ngOnInit() {
this.get(); this.hookToQuery();
}
onSearch(value: string) {
this.pageQuery.filter = value;
this.get();
} }
private createTenantForm() { private createTenantForm() {
@ -236,7 +231,7 @@ export class TenantsComponent implements OnInit {
.pipe(finalize(() => (this.modalBusy = false))) .pipe(finalize(() => (this.modalBusy = false)))
.subscribe(() => { .subscribe(() => {
this.isModalVisible = false; this.isModalVisible = false;
this.get(); this.list.get();
}); });
} }
@ -251,23 +246,13 @@ export class TenantsComponent implements OnInit {
) )
.subscribe((status: Confirmation.Status) => { .subscribe((status: Confirmation.Status) => {
if (status === Confirmation.Status.confirm) { if (status === Confirmation.Status.confirm) {
this.store.dispatch(new DeleteTenant(id)).subscribe(() => this.get()); this.store.dispatch(new DeleteTenant(id)).subscribe(() => this.list.get());
} }
}); });
} }
onPageChange(page: number) { hookToQuery() {
this.pageQuery.skipCount = (page - 1) * this.pageQuery.maxResultCount; this.list.hookToQuery(query => this.store.dispatch(new GetTenants(query))).subscribe();
this.get();
}
get() {
this.loading = true;
this.store
.dispatch(new GetTenants(this.pageQuery))
.pipe(finalize(() => (this.loading = false)))
.subscribe();
} }
onSharedDatabaseChange(value: boolean) { onSharedDatabaseChange(value: boolean) {
@ -289,4 +274,10 @@ export class TenantsComponent implements OnInit {
this.visibleFeatures = true; this.visibleFeatures = true;
}, 0); }, 0);
} }
sort(data) {
const { prop, dir } = data.sorts[0];
this.list.sortKey = prop;
this.list.sortOrder = dir;
}
} }

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

@ -10,6 +10,7 @@
"@fortawesome/fontawesome-free", "@fortawesome/fontawesome-free",
"@ng-bootstrap/ng-bootstrap", "@ng-bootstrap/ng-bootstrap",
"@ngx-validate/core", "@ngx-validate/core",
"@swimlane/ngx-datatable",
"bootstrap", "bootstrap",
"font-awesome", "font-awesome",
"chart.js" "chart.js"

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

@ -11,6 +11,7 @@
"@fortawesome/fontawesome-free": "^5.13.0", "@fortawesome/fontawesome-free": "^5.13.0",
"@ng-bootstrap/ng-bootstrap": "^6.1.0", "@ng-bootstrap/ng-bootstrap": "^6.1.0",
"@ngx-validate/core": "^0.0.8", "@ngx-validate/core": "^0.0.8",
"@swimlane/ngx-datatable": "^16.0.0",
"bootstrap": "^4.5.0", "bootstrap": "^4.5.0",
"chart.js": "^2.9.3" "chart.js": "^2.9.3"
}, },

8
npm/ng-packs/packages/theme-shared/src/lib/constants/styles.ts

@ -45,6 +45,11 @@ export default `
background: #8a8686; background: #8a8686;
} }
.bordered .datatable-body-row {
border-top: 1px solid #eee;
margin-top: -1px;
}
.abp-ellipsis-inline { .abp-ellipsis-inline {
display: inline-block; display: inline-block;
overflow: hidden; overflow: hidden;
@ -136,6 +141,9 @@ export default `
.sorting_asc:after { .sorting_asc:after {
opacity: .3; opacity: .3;
} }
.ngx-datatable.material {
box-shadow: none;
}
@keyframes fadeInTop { @keyframes fadeInTop {
from { from {

2
npm/ng-packs/packages/theme-shared/src/lib/directives/index.ts

@ -1,2 +1,4 @@
export * from './loading.directive'; export * from './loading.directive';
export * from './ngx-datatable-default.directive';
export * from './ngx-datatable-list.directive';
export * from './table-sort.directive'; export * from './table-sort.directive';

23
npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-default.directive.ts

@ -0,0 +1,23 @@
import { Directive, HostBinding, Input } from '@angular/core';
import { ColumnMode, DatatableComponent } from '@swimlane/ngx-datatable';
@Directive({
// tslint:disable-next-line
selector: 'ngx-datatable[default]',
exportAs: 'ngxDatatableDefault',
})
export class NgxDatatableDefaultDirective {
@Input() class = 'material bordered';
@HostBinding('class')
get classes(): string {
return `ngx-datatable ${this.class}`;
}
constructor(private table: DatatableComponent) {
this.table.columnMode = ColumnMode.force;
this.table.footerHeight = 50;
this.table.headerHeight = 50;
this.table.rowHeight = 'auto';
}
}

70
npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts

@ -0,0 +1,70 @@
import { ListService } from '@abp/ng.core';
import {
ChangeDetectorRef,
Directive,
Input,
OnChanges,
OnDestroy,
OnInit,
SimpleChanges,
} from '@angular/core';
import { DatatableComponent } from '@swimlane/ngx-datatable';
import { Subscription } from 'rxjs';
@Directive({
// tslint:disable-next-line
selector: 'ngx-datatable[list]',
exportAs: 'ngxDatatableList',
})
export class NgxDatatableListDirective implements OnChanges, OnDestroy, OnInit {
private subscription = new Subscription();
@Input() list: ListService;
constructor(private table: DatatableComponent, private cdRef: ChangeDetectorRef) {
this.table.externalPaging = true;
this.table.externalSorting = true;
}
private subscribeToPage() {
const sub = this.table.page.subscribe(({ offset }) => {
this.list.page = offset;
this.table.offset = offset;
});
this.subscription.add(sub);
}
private subscribeToSort() {
const sub = this.table.sort.subscribe(({ sorts: [{ prop, dir }] }) => {
this.list.sortKey = prop;
this.list.sortOrder = dir;
});
this.subscription.add(sub);
}
private subscribeToIsLoading() {
const sub = this.list.isLoading$.subscribe(loading => {
this.table.loadingIndicator = loading;
this.cdRef.markForCheck();
});
this.subscription.add(sub);
}
ngOnChanges({ list }: SimpleChanges) {
if (!list.firstChange) return;
const { maxResultCount, page } = list.currentValue;
this.table.limit = maxResultCount;
this.table.offset = page;
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
ngOnInit() {
this.subscribeToPage();
this.subscribeToSort();
this.subscribeToIsLoading();
}
}

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

@ -1,8 +1,10 @@
import { CoreModule, LazyLoadService, noop } from '@abp/ng.core'; import { ConfigState, CoreModule, noop } from '@abp/ng.core';
import { DatePipe } from '@angular/common'; import { DatePipe } from '@angular/common';
import { APP_INITIALIZER, Injector, ModuleWithProviders, NgModule } from '@angular/core'; import { APP_INITIALIZER, Injector, ModuleWithProviders, NgModule } from '@angular/core';
import { NgbDateParserFormatter, NgbPaginationModule } from '@ng-bootstrap/ng-bootstrap'; import { NgbDateParserFormatter, NgbPaginationModule } from '@ng-bootstrap/ng-bootstrap';
import { NgxValidateCoreModule } from '@ngx-validate/core'; import { NgxValidateCoreModule } from '@ngx-validate/core';
import { Store } from '@ngxs/store';
import { INgxDatatableConfig, NgxDatatableModule } from '@swimlane/ngx-datatable';
import { BreadcrumbComponent } from './components/breadcrumb/breadcrumb.component'; import { BreadcrumbComponent } from './components/breadcrumb/breadcrumb.component';
import { ButtonComponent } from './components/button/button.component'; import { ButtonComponent } from './components/button/button.component';
import { ChartComponent } from './components/chart/chart.component'; import { ChartComponent } from './components/chart/chart.component';
@ -18,8 +20,9 @@ import { TableEmptyMessageComponent } from './components/table-empty-message/tab
import { TableComponent } from './components/table/table.component'; import { TableComponent } from './components/table/table.component';
import { ToastContainerComponent } from './components/toast-container/toast-container.component'; import { ToastContainerComponent } from './components/toast-container/toast-container.component';
import { ToastComponent } from './components/toast/toast.component'; import { ToastComponent } from './components/toast/toast.component';
import styles from './constants/styles';
import { LoadingDirective } from './directives/loading.directive'; import { LoadingDirective } from './directives/loading.directive';
import { NgxDatatableDefaultDirective } from './directives/ngx-datatable-default.directive';
import { NgxDatatableListDirective } from './directives/ngx-datatable-list.directive';
import { TableSortDirective } from './directives/table-sort.directive'; import { TableSortDirective } from './directives/table-sort.directive';
import { ErrorHandler } from './handlers/error.handler'; import { ErrorHandler } from './handlers/error.handler';
import { initLazyStyleHandler } from './handlers/lazy-style.handler'; import { initLazyStyleHandler } from './handlers/lazy-style.handler';
@ -27,26 +30,25 @@ import { RootParams } from './models/common';
import { THEME_SHARED_APPEND_CONTENT } from './tokens/append-content.token'; import { THEME_SHARED_APPEND_CONTENT } from './tokens/append-content.token';
import { httpErrorConfigFactory, HTTP_ERROR_CONFIG } from './tokens/http-error.token'; import { httpErrorConfigFactory, HTTP_ERROR_CONFIG } from './tokens/http-error.token';
import { DateParserFormatter } from './utils/date-parser-formatter'; import { DateParserFormatter } from './utils/date-parser-formatter';
import { chartJsLoaded$ } from './utils/widget-utils';
/** export function ngxDatatableMessageFactory(store: Store) {
* const emptyMessage = store.selectSnapshot(
* @deprecated To be deleted in v2.6 ConfigState.getLocalization('AbpUi::NoDataAvailableInDatatable'),
* );
*/ const totalMessage = store.selectSnapshot(ConfigState.getLocalization('AbpUi::Total'));
export function appendScript(injector: Injector) { const selectedMessage = store.selectSnapshot(ConfigState.getLocalization('AbpUi::Selected'));
const fn = () => {
import('chart.js').then(() => chartJsLoaded$.next(true));
const lazyLoadService: LazyLoadService = injector.get(LazyLoadService); return {
return lazyLoadService.load(null, 'style', styles, 'head', 'beforeend').toPromise(); messages: {
}; emptyMessage,
totalMessage,
return fn; selectedMessage,
},
} as INgxDatatableConfig;
} }
@NgModule({ @NgModule({
imports: [CoreModule, NgxValidateCoreModule, NgbPaginationModule], imports: [CoreModule, NgxDatatableModule, NgxValidateCoreModule, NgbPaginationModule],
declarations: [ declarations: [
BreadcrumbComponent, BreadcrumbComponent,
ButtonComponent, ButtonComponent,
@ -63,11 +65,14 @@ export function appendScript(injector: Injector) {
ToastComponent, ToastComponent,
ToastContainerComponent, ToastContainerComponent,
SortOrderIconComponent, SortOrderIconComponent,
NgxDatatableDefaultDirective,
NgxDatatableListDirective,
LoadingDirective, LoadingDirective,
TableSortDirective, TableSortDirective,
ToastContainerComponent, ToastContainerComponent,
], ],
exports: [ exports: [
NgxDatatableModule,
BreadcrumbComponent, BreadcrumbComponent,
ButtonComponent, ButtonComponent,
ChartComponent, ChartComponent,
@ -81,6 +86,8 @@ export function appendScript(injector: Injector) {
ToastComponent, ToastComponent,
ToastContainerComponent, ToastContainerComponent,
SortOrderIconComponent, SortOrderIconComponent,
NgxDatatableDefaultDirective,
NgxDatatableListDirective,
LoadingDirective, LoadingDirective,
TableSortDirective, TableSortDirective,
ToastContainerComponent, ToastContainerComponent,
@ -120,6 +127,11 @@ export class ThemeSharedModule {
deps: [HTTP_ERROR_CONFIG], deps: [HTTP_ERROR_CONFIG],
}, },
{ provide: NgbDateParserFormatter, useClass: DateParserFormatter }, { provide: NgbDateParserFormatter, useClass: DateParserFormatter },
{
provide: 'configuration',
useFactory: ngxDatatableMessageFactory,
deps: [Store],
},
], ],
}; };
} }

10
npm/ng-packs/scripts/prod-build.ts

@ -13,11 +13,19 @@ import fse from 'fs-extra';
}); });
await fse.remove('../../../templates/app/angular/node_modules/@abp'); await fse.remove('../../../templates/app/angular/node_modules/@abp');
await fse.copy('../node_modules/@abp', '../../../templates/app/angular/node_modules/@abp', { await fse.copy('../node_modules/@abp', '../../../templates/app/angular/node_modules/@abp', {
overwrite: true, overwrite: true,
}); });
// TODO: Will be removed in v3.1, it is added to fix the prod build error
await fse.copy(
'../node_modules/@swimlane',
'../../../templates/app/angular/node_modules/@swimlane',
{
overwrite: true,
},
);
await execa('yarn', ['ng', 'build', '--prod'], { await execa('yarn', ['ng', 'build', '--prod'], {
stdout: 'inherit', stdout: 'inherit',
cwd: '../../../templates/app/angular', cwd: '../../../templates/app/angular',

12
npm/ng-packs/scripts/yarn.lock

@ -15,14 +15,14 @@
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
"@types/node@*": "@types/node@*":
version "14.0.11" version "14.0.13"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.11.tgz#61d4886e2424da73b7b25547f59fdcb534c165a3" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.13.tgz#ee1128e881b874c371374c1f72201893616417c9"
integrity sha512-lCvvI24L21ZVeIiyIUHZ5Oflv1hhHQ5E1S25IRlKIXaRkVgmXpJMI3wUJkmym2bTbCe+WoIibQnMVAU3FguaOg== integrity sha512-rouEWBImiRaSJsVA+ITTFM6ZxibuAlTuNOCyxVbwreu6k6+ujs7DfnU9o+PShFhET78pMBl3eH+AGSI5eOTkPA==
"@types/node@^13.1.2": "@types/node@^13.1.2":
version "13.13.10" version "13.13.12"
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.10.tgz#34a9be3cbc409fd235984bd18a130006f5234396" resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.12.tgz#9c72e865380a7dc99999ea0ef20fc9635b503d20"
integrity sha512-J+FbkhLTcFstD7E5mVZDjYxa1VppwT2HALE6H3n2AnBSP8uiCQk0Pyr6BkJcP38dFV9WecoVJRJmFnl9ikIW7Q== integrity sha512-zWz/8NEPxoXNT9YyF2osqyA9WjssZukYpgI4UYZpOjcyqwIUqWGkcCionaEb9Ki+FULyPyvNFpg/329Kd2/pbw==
ansi-bgblack@^0.1.1: ansi-bgblack@^0.1.1:
version "0.1.1" version "0.1.1"

2
npm/ng-packs/tslint.json

@ -37,7 +37,7 @@
"import-blacklist": [true, "rxjs/Rx"], "import-blacklist": [true, "rxjs/Rx"],
"interface-over-type-literal": true, "interface-over-type-literal": true,
"interface-name": [true, "never-prefix"], "interface-name": [true, "never-prefix"],
"member-access": [true, "no-public"], "member-access": [false],
"member-ordering": [ "member-ordering": [
true, true,
{ {

161
npm/ng-packs/yarn.lock

@ -110,9 +110,9 @@
tslib "^1.9.0" tslib "^1.9.0"
"@abp/ng.theme.shared@~2.9.0": "@abp/ng.theme.shared@~2.9.0":
version "2.9.0" version "2.9.1"
resolved "https://registry.yarnpkg.com/@abp/ng.theme.shared/-/ng.theme.shared-2.9.0.tgz#aaf97cf94ff798b3695cbb1b0dec33d20996fbda" resolved "https://registry.yarnpkg.com/@abp/ng.theme.shared/-/ng.theme.shared-2.9.1.tgz#c44064057505a5a2cdb4ca269daa6bd423a99ba6"
integrity sha512-04xlt3aKiDVyE+6NpxA0KGHGuupJWhXTjPWwlzVtfNiPqYjx0rG2FbTGgNWMW4K1qTlRRVjPA5a/MDhZtZHZIw== integrity sha512-iSlhRcjmNXYclAkSJ0vN20GBF7ART3340Mpn4V+hMRachkJSewwMNYG73G6ukVwZrF+0Sjdn2r9jJrJHhhKm3w==
dependencies: dependencies:
"@abp/ng.core" "~2.9.0" "@abp/ng.core" "~2.9.0"
"@fortawesome/fontawesome-free" "^5.12.1" "@fortawesome/fontawesome-free" "^5.12.1"
@ -301,9 +301,9 @@
rxjs "6.4.0" rxjs "6.4.0"
"@angular/animations@~9.1.9": "@angular/animations@~9.1.9":
version "9.1.9" version "9.1.10"
resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-9.1.9.tgz#de54334ea195189402487855c9a98f5618605da4" resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-9.1.10.tgz#c0f0b7e30dbe95ef8edd62e5d6c2ea3224d76966"
integrity sha512-qWVi0TxmU6HeXAgEsfpQvFFygh+a0kH2kGe6bWij4XvG6dWfV3xZjlaFwSIYGk+yK4yL0+9+PAXH+ENfxNw+Cw== integrity sha512-xuiL2iE8vka3IZpvwnOYDhfKKn9xKB+qyn7mcWzr6xnFP3UPfxN/1HuDJYgtwd+KXtTZmzlsm8orh+DZ3MGxbA==
"@angular/cli@~9.1.7": "@angular/cli@~9.1.7":
version "9.1.7" version "9.1.7"
@ -332,14 +332,14 @@
uuid "7.0.2" uuid "7.0.2"
"@angular/common@~9.1.9": "@angular/common@~9.1.9":
version "9.1.9" version "9.1.10"
resolved "https://registry.yarnpkg.com/@angular/common/-/common-9.1.9.tgz#16e77b2db675b80e32f1788a20c538150fd09294" resolved "https://registry.yarnpkg.com/@angular/common/-/common-9.1.10.tgz#34c36f9b889ec009c5a4aa1628acb4e002a4e280"
integrity sha512-y/tJtkuOJhV2kcaXZyrLZH84i4uQ1r+vaaEHvXj+JZYfYfcMMd/TDqMiPcIkUb3RxqghtZ+q0ZNW5D1Nlru3Pw== integrity sha512-qX7ZUIwRkQi/kO6aKmpa8iGdkLXfe+80D+svC02x5PvafdQAcuBlUQQkrr1XapBqYE/Nu2GK0yYmvpa2CzxjPQ==
"@angular/compiler-cli@~9.1.9": "@angular/compiler-cli@~9.1.9":
version "9.1.9" version "9.1.10"
resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-9.1.9.tgz#e3c234d888074002fa5f6b7eab4f63f4ddbdb7bd" resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-9.1.10.tgz#4ad54e9df3f0b00bc53493a2247ca4d22d67fdb0"
integrity sha512-aLr2eaDlREN8XybgTbelvjtSZ8eAkxBPilnkddc700BgiC6ImyUSKaItOwa8bnjQwq4Wlz5eVG0ibsrX+5MXwg== integrity sha512-D2JYI9GHzybG/NJ03aCd+95mSz+f4UhgDZ1c0GbYlsNLvk1B0UrDrmgGv0gOdP9yW1XxQjW3ldZAqpVurYru3Q==
dependencies: dependencies:
canonical-path "1.0.0" canonical-path "1.0.0"
chokidar "^3.0.0" chokidar "^3.0.0"
@ -355,48 +355,48 @@
yargs "15.3.0" yargs "15.3.0"
"@angular/compiler@~9.1.9": "@angular/compiler@~9.1.9":
version "9.1.9" version "9.1.10"
resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-9.1.9.tgz#cbf678ee28a0811a8ef3ee7be565d4911ff28ec7" resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-9.1.10.tgz#2e43cb51203e18faf3673244a78946d7a7194041"
integrity sha512-kjFgaTB2ckr9lgmkS1dOGRT7kmzpQueydxsxXSHWgICNVE6F/u1PHyeSOyJRpxW0GnrkLq3QM2EUFnQGGga5bg== integrity sha512-VlyTVK9elvtKGXxrkW9BWfKYRfeqXVLR3erukv03vy9u/pZppkG1xJ32SgAPKzYckGRV3kKHP6B7ZOXWMb9cog==
"@angular/core@~9.1.9": "@angular/core@~9.1.9":
version "9.1.9" version "9.1.10"
resolved "https://registry.yarnpkg.com/@angular/core/-/core-9.1.9.tgz#db4241f867d6e14b81ed6e7c50334813c6ebfc10" resolved "https://registry.yarnpkg.com/@angular/core/-/core-9.1.10.tgz#cb9c99cd99a61cc55337220cafac005332ff9fdf"
integrity sha512-q/DERgVU6vK2LtTcdVCGGBcoO424WsEfImh3Vcuy+P/ZVmthlDUC/+q+tSKt8MMf4hLpxFDQJE8vUSkktj7QEw== integrity sha512-pp8g0razdSi3HzSBHRzBdn5WmnVJZ5IF+sWuApvplnl4edBO0CFdZAKALmRgjctRD9y9aVPXhkEi17Spiip9aA==
"@angular/forms@~9.1.9": "@angular/forms@~9.1.9":
version "9.1.9" version "9.1.10"
resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-9.1.9.tgz#20c9a79d1dcb2cace45df9e2f304b658e02c1687" resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-9.1.10.tgz#74da1653581bb5021015cf76fa04316a627376e6"
integrity sha512-r675yImnb/0pY7K5W3V2ITa7YETu1I2AS+bRfII6UQ6gthyeFFOHb5noa7YneC2yqQiM6E4DQmF5ig3daPuFNg== integrity sha512-Qp/tO3bayvP3lkpuMe2oWGBhATd39Vd9z9z/LIWtM+PkEZCZ0xCh0d6AiKrO9sc1vDATCi4SKxEnNCkmPBWOuQ==
"@angular/language-service@~9.1.9": "@angular/language-service@~9.1.9":
version "9.1.9" version "9.1.10"
resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-9.1.9.tgz#332a7e54d5e553b92342b10703dc13aba474a28f" resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-9.1.10.tgz#515abfaf79ae9c1ab2649c48201dcd4aae4b7c74"
integrity sha512-yT6HPpdAe2mD9HRoTCiWFog1MRJt+0j+CLbI/Ql7C6pH6vbjmfsJ55xMmQ7eS6trsnebpMWTUv1f2GRykv3ygw== integrity sha512-rj+otf/uPRhEH4L3kDX13RouKg5YT0uc/CbBlgwTbEX9kOOBGxvHxoUxPT8rysBjHuLubBd2mQozZofj/IYa8Q==
"@angular/localize@~9.1.0", "@angular/localize@~9.1.9": "@angular/localize@~9.1.0", "@angular/localize@~9.1.9":
version "9.1.9" version "9.1.10"
resolved "https://registry.yarnpkg.com/@angular/localize/-/localize-9.1.9.tgz#0867a82abcdeb6b88cbd4d61e1410f3c63a66ddb" resolved "https://registry.yarnpkg.com/@angular/localize/-/localize-9.1.10.tgz#230ab75155c16d84d61eb34ccff2e3283c85b995"
integrity sha512-U/4axUr99GO3+dRuMIEyJ1FqXauT82x/w7GulWu05qk8ML8MaIQ58RcB/LTJJY1s1qfwdcsyzX2wZrZcwBLKlA== integrity sha512-gAc2Xuz4clPp8+YDK+M21q+DKnLNx+J/i8L9b9Z7rj8a/gHqOQWaTun4grLgd86AbpNxp/urkr+tEFHiHaNz6Q==
dependencies: dependencies:
"@babel/core" "7.8.3" "@babel/core" "7.8.3"
glob "7.1.2" glob "7.1.2"
yargs "15.3.0" yargs "15.3.0"
"@angular/platform-browser-dynamic@~9.1.9": "@angular/platform-browser-dynamic@~9.1.9":
version "9.1.9" version "9.1.10"
resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-9.1.9.tgz#12f8b05d3c9ef0844df88f3833e29ea1e49ec5e0" resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-9.1.10.tgz#a885b7903c1dcce36c327e9ca9b5f6e7ec1aa716"
integrity sha512-b9MG5MWne+IuL3uLm8jwPhlJzqYaGBGk/qibOqb17T24j1iyrlO7T5bZ8zO6pUy5iT/TahVfHPnPJC1qTK5OmA== integrity sha512-z8urbP03LYxiCci076SYXz+9elCukePP0ykq5RVJYe5300V6JhamGftTQgsaKszas0KlGYUz/jTULhWQ+OEv/A==
"@angular/platform-browser@~9.1.9": "@angular/platform-browser@~9.1.9":
version "9.1.9" version "9.1.10"
resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-9.1.9.tgz#c2fcc50aebfdc268521b407e32dc0d967cb40411" resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-9.1.10.tgz#d014e59a2ec4722d0bb428910116c41176868d77"
integrity sha512-V861X3MxJp1AlMTnkUPldpBLIJbApXF3ka0A5Dq2nVJCyOFeteGkaRWSBgqe2jxmq+LVpJbzcNvtDFXw6mQ0jA== integrity sha512-u8PHq92+OV0vrRKwc5bqS0SCR/VkzhuaUUXKYbjYeLsmXG+HUtg/pUCDo95ze4zPO1WFSeUvwsnRb2x1hurYAw==
"@angular/router@~9.1.9": "@angular/router@~9.1.9":
version "9.1.9" version "9.1.10"
resolved "https://registry.yarnpkg.com/@angular/router/-/router-9.1.9.tgz#5d79d72cb62ea1c04ea70238846653ecf9c4a73c" resolved "https://registry.yarnpkg.com/@angular/router/-/router-9.1.10.tgz#e0e9c5b1c35c9ab9b843c478c3cec038a0d15e19"
integrity sha512-4u+CWMPB4hCkAsFCEzC94YEWT0wVozqGkc/Dortt2hFaqvZpIegg6iJVZlDxuyDjzFYBPnnbTDdgiTTA8ckfuA== integrity sha512-nvMSzgmsjyj+vzw0meHpN1lea7kf106ml+g97RgxiOgHAtBUnuuedXpBKrajK2kA2m9QbwQvIaKrxkdBzyLuSw==
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.1", "@babel/code-frame@^7.8.3": "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.1", "@babel/code-frame@^7.8.3":
version "7.10.1" version "7.10.1"
@ -2052,10 +2052,10 @@
inquirer "^6.2.0" inquirer "^6.2.0"
npmlog "^4.1.2" npmlog "^4.1.2"
"@lerna/publish@3.22.0": "@lerna/publish@3.22.1":
version "3.22.0" version "3.22.1"
resolved "https://registry.yarnpkg.com/@lerna/publish/-/publish-3.22.0.tgz#7a3fb61026d3b7425f3b9a1849421f67d795c55d" resolved "https://registry.yarnpkg.com/@lerna/publish/-/publish-3.22.1.tgz#b4f7ce3fba1e9afb28be4a1f3d88222269ba9519"
integrity sha512-8LBeTLBN8NIrCrLGykRu+PKrfrCC16sGCVY0/bzq9TDioR7g6+cY0ZAw653Qt/0Kr7rg3J7XxVNdzj3fvevlwA== integrity sha512-PG9CM9HUYDreb1FbJwFg90TCBQooGjj+n/pb3gw/eH5mEDq0p8wKdLFe0qkiqUkm/Ub5C8DbVFertIo0Vd0zcw==
dependencies: dependencies:
"@evocateur/libnpmaccess" "^3.1.2" "@evocateur/libnpmaccess" "^3.1.2"
"@evocateur/npm-registry-fetch" "^4.0.0" "@evocateur/npm-registry-fetch" "^4.0.0"
@ -2078,7 +2078,7 @@
"@lerna/run-lifecycle" "3.16.2" "@lerna/run-lifecycle" "3.16.2"
"@lerna/run-topologically" "3.18.5" "@lerna/run-topologically" "3.18.5"
"@lerna/validation-error" "3.13.0" "@lerna/validation-error" "3.13.0"
"@lerna/version" "3.22.0" "@lerna/version" "3.22.1"
figgy-pudding "^3.5.1" figgy-pudding "^3.5.1"
fs-extra "^8.1.0" fs-extra "^8.1.0"
npm-package-arg "^6.1.0" npm-package-arg "^6.1.0"
@ -2191,10 +2191,10 @@
dependencies: dependencies:
npmlog "^4.1.2" npmlog "^4.1.2"
"@lerna/version@3.22.0": "@lerna/version@3.22.1":
version "3.22.0" version "3.22.1"
resolved "https://registry.yarnpkg.com/@lerna/version/-/version-3.22.0.tgz#67e1340c1904e9b339becd66429f32dd8ad65a55" resolved "https://registry.yarnpkg.com/@lerna/version/-/version-3.22.1.tgz#9805a9247a47ee62d6b81bd9fa5fb728b24b59e2"
integrity sha512-6uhL6RL7/FeW6u1INEgyKjd5dwO8+IsbLfkfC682QuoVLS7VG6OOB+JmTpCvnuyYWI6fqGh1bRk9ww8kPsj+EA== integrity sha512-PSGt/K1hVqreAFoi3zjD0VEDupQ2WZVlVIwesrE5GbrL2BjXowjCsTDPqblahDUPy0hp6h7E2kG855yLTp62+g==
dependencies: dependencies:
"@lerna/check-working-tree" "3.16.5" "@lerna/check-working-tree" "3.16.5"
"@lerna/child-process" "3.16.5" "@lerna/child-process" "3.16.5"
@ -2422,9 +2422,9 @@
"@types/node" ">= 8" "@types/node" ">= 8"
"@octokit/types@^4.0.1": "@octokit/types@^4.0.1":
version "4.1.9" version "4.1.10"
resolved "https://registry.yarnpkg.com/@octokit/types/-/types-4.1.9.tgz#a3e1ff1a15637ab830fbab0268c2d7ca824bc969" resolved "https://registry.yarnpkg.com/@octokit/types/-/types-4.1.10.tgz#e4029c11e2cc1335051775bc1600e7e740e4aca4"
integrity sha512-hinM/BA2c1vebN2HSR3JtVdYtrSbmvn/doUBZXXuQuh/9o60hYwitQQAGTpJu+k6pjtjURskDHQxUFvqLvYCeA== integrity sha512-/wbFy1cUIE5eICcg0wTKGXMlKSbaAxEr00qaBXzscLXpqhcwgXeS6P8O0pkysBhRfyjkKjJaYrvR1ExMO5eOXQ==
dependencies: dependencies:
"@types/node" ">= 8" "@types/node" ">= 8"
@ -2508,6 +2508,13 @@
dependencies: dependencies:
type-detect "4.0.8" type-detect "4.0.8"
"@swimlane/ngx-datatable@^16.0.0":
version "16.1.1"
resolved "https://registry.yarnpkg.com/@swimlane/ngx-datatable/-/ngx-datatable-16.1.1.tgz#1215e81f51400314ba6899f66acdbd4e3bde2915"
integrity sha512-h2A9xC/jo314eC/CzA19aoY/YadhdTupolCwpgB9Cbw3sDRi3x/LeGsdLSV0bj3XBKQUB3DA/gPuASKYuhm8iA==
dependencies:
tslib "^1.9.0"
"@szmarczak/http-timer@^1.1.2": "@szmarczak/http-timer@^1.1.2":
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421"
@ -2591,9 +2598,9 @@
"@types/node" "*" "@types/node" "*"
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
version "2.0.2" version "2.0.3"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.2.tgz#79d7a78bad4219f4c03d6557a1c72d9ca6ba62d5" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762"
integrity sha512-rsZg7eL+Xcxsxk2XlBt9KcG8nOp9iYdKCOikY9x2RFJCyOdNj4MKPQty0e8oZr29vVAzKXr1BmR+kZauti3o1w== integrity sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==
"@types/istanbul-lib-report@*": "@types/istanbul-lib-report@*":
version "3.0.0" version "3.0.0"
@ -2624,9 +2631,9 @@
pretty-format "^25.2.1" pretty-format "^25.2.1"
"@types/json-schema@^7.0.4": "@types/json-schema@^7.0.4":
version "7.0.4" version "7.0.5"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.5.tgz#dcce4430e64b443ba8945f0290fb564ad5bac6dd"
integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA== integrity sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==
"@types/minimatch@*": "@types/minimatch@*":
version "3.0.3" version "3.0.3"
@ -2639,14 +2646,14 @@
integrity sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY= integrity sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=
"@types/node@*", "@types/node@>= 8": "@types/node@*", "@types/node@>= 8":
version "14.0.11" version "14.0.13"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.11.tgz#61d4886e2424da73b7b25547f59fdcb534c165a3" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.13.tgz#ee1128e881b874c371374c1f72201893616417c9"
integrity sha512-lCvvI24L21ZVeIiyIUHZ5Oflv1hhHQ5E1S25IRlKIXaRkVgmXpJMI3wUJkmym2bTbCe+WoIibQnMVAU3FguaOg== integrity sha512-rouEWBImiRaSJsVA+ITTFM6ZxibuAlTuNOCyxVbwreu6k6+ujs7DfnU9o+PShFhET78pMBl3eH+AGSI5eOTkPA==
"@types/node@^12.11.1": "@types/node@^12.11.1":
version "12.12.44" version "12.12.47"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.44.tgz#0d400a1453adcb359b133acceae4dd8bb0e0a159" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.47.tgz#5007b8866a2f9150de82335ca7e24dd1d59bdfb5"
integrity sha512-jM6QVv0Sm5d3nW+nUD5jSzPcO6oPqboitSNcwgBay9hifVq/Rauq1PYnROnsmuw45JMBiTnsPAno0bKu2e2xrg== integrity sha512-yzBInQFhdY8kaZmqoL2+3U5dSTMrKaYcb561VU+lDzAYvqt+2lojvBEy+hmpSNuXnPTx7m9+04CzWYOUqWME2A==
"@types/node@^8.0.31": "@types/node@^8.0.31":
version "8.10.61" version "8.10.61"
@ -4005,9 +4012,9 @@ caniuse-api@^3.0.0:
lodash.uniq "^4.5.0" lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001020, caniuse-lite@^1.0.30001032, caniuse-lite@^1.0.30001043, caniuse-lite@^1.0.30001061: caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001020, caniuse-lite@^1.0.30001032, caniuse-lite@^1.0.30001043, caniuse-lite@^1.0.30001061:
version "1.0.30001079" version "1.0.30001081"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001079.tgz#ed3e5225cd9a6850984fdd88bf24ce45d69b9c22" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001081.tgz#40615a3c416a047c5a4d45673e5257bf128eb3b5"
integrity sha512-2KaYheg0iOY+CMmDuAB3DHehrXhhb4OZU4KBVGDr/YKyYAcpudaiUQ9PJ9rxrPlKEoJ3ATasQ5AN48MqpwS43Q== integrity sha512-iZdh3lu09jsUtLE6Bp8NAbJskco4Y3UDtkR3GTCJGsbMowBU5IWDFF79sV2ws7lSqTzWyKazxam2thasHymENQ==
canonical-path@1.0.0: canonical-path@1.0.0:
version "1.0.0" version "1.0.0"
@ -4055,9 +4062,9 @@ chalk@^3.0.0:
supports-color "^7.1.0" supports-color "^7.1.0"
chalk@^4.0.0: chalk@^4.0.0:
version "4.0.0" version "4.1.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.0.0.tgz#6e98081ed2d17faab615eb52ac66ec1fe6209e72" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a"
integrity sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A== integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==
dependencies: dependencies:
ansi-styles "^4.1.0" ansi-styles "^4.1.0"
supports-color "^7.1.0" supports-color "^7.1.0"
@ -5566,9 +5573,9 @@ ee-first@1.1.1:
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
electron-to-chromium@^1.3.413: electron-to-chromium@^1.3.413:
version "1.3.464" version "1.3.466"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.464.tgz#fe13feaa08f6f865d3c89d5d72e54c194f463aa5" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.466.tgz#89f716db3afc4bb482ea2aaaa16c4808f89f762a"
integrity sha512-Oo+0+CN9d2z6FToQW6Hwvi9ez09Y/usKwr0tsDsyg43a871zVJCi1nR0v03djLbRNcaCKjtrnVf2XJhTxEpPCg== integrity sha512-eieqkoM2hCkZZRhETKyCouMziDV3l4XEKHRLuzcHG+HV+P7PeODU/z9HAmBgMQkzvHg2DoyQhfIDmmeguLZT/Q==
elliptic@^6.0.0, elliptic@^6.5.2: elliptic@^6.0.0, elliptic@^6.5.2:
version "6.5.2" version "6.5.2"
@ -8338,9 +8345,9 @@ lcid@^2.0.0:
invert-kv "^2.0.0" invert-kv "^2.0.0"
lerna@^3.19.0: lerna@^3.19.0:
version "3.22.0" version "3.22.1"
resolved "https://registry.yarnpkg.com/lerna/-/lerna-3.22.0.tgz#da14d08f183ffe6eec566a4ef3f0e11afa621183" resolved "https://registry.yarnpkg.com/lerna/-/lerna-3.22.1.tgz#82027ac3da9c627fd8bf02ccfeff806a98e65b62"
integrity sha512-xWlHdAStcqK/IjKvjsSMHPZjPkBV1lS60PmsIeObU8rLljTepc4Sg/hncw4HWfQxPIewHAUTqhrxPIsqf9L2Eg== integrity sha512-vk1lfVRFm+UuEFA7wkLKeSF7Iz13W+N/vFd48aW2yuS7Kv0RbNm2/qcDPV863056LMfkRlsEe+QYOw3palj5Lg==
dependencies: dependencies:
"@lerna/add" "3.21.0" "@lerna/add" "3.21.0"
"@lerna/bootstrap" "3.21.0" "@lerna/bootstrap" "3.21.0"
@ -8355,9 +8362,9 @@ lerna@^3.19.0:
"@lerna/init" "3.21.0" "@lerna/init" "3.21.0"
"@lerna/link" "3.21.0" "@lerna/link" "3.21.0"
"@lerna/list" "3.21.0" "@lerna/list" "3.21.0"
"@lerna/publish" "3.22.0" "@lerna/publish" "3.22.1"
"@lerna/run" "3.21.0" "@lerna/run" "3.21.0"
"@lerna/version" "3.22.0" "@lerna/version" "3.22.1"
import-local "^2.0.0" import-local "^2.0.0"
npmlog "^4.1.2" npmlog "^4.1.2"
@ -13598,9 +13605,9 @@ widest-line@^3.1.0:
string-width "^4.0.0" string-width "^4.0.0"
windows-release@^3.1.0: windows-release@^3.1.0:
version "3.3.0" version "3.3.1"
resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.3.0.tgz#dce167e9f8be733f21c849ebd4d03fe66b29b9f0" resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.3.1.tgz#cb4e80385f8550f709727287bf71035e209c4ace"
integrity sha512-2HetyTg1Y+R+rUgrKeUEhAG/ZuOmTrI1NBb3ZyAGQMYmOJjBBPe4MTodghRkmLJZHwkuPi02anbeGP+Zf401LQ== integrity sha512-Pngk/RDCaI/DkuHPlGTdIkDiTAnAkyMjoQMZqRsxydNl1qGXNIoZrB7RK8g53F2tEgQBMqQJHQdYZuQEEAu54A==
dependencies: dependencies:
execa "^1.0.0" execa "^1.0.0"

15
templates/app/angular/angular.json

@ -46,6 +46,21 @@
"inject": true, "inject": true,
"bundleName": "fontawesome-v4-shims.min" "bundleName": "fontawesome-v4-shims.min"
}, },
{
"input": "node_modules/@swimlane/ngx-datatable/index.css",
"inject": true,
"bundleName": "ngx-datatable-index"
},
{
"input": "node_modules/@swimlane/ngx-datatable/assets/icons.css",
"inject": true,
"bundleName": "ngx-datatable-icons"
},
{
"input": "node_modules/@swimlane/ngx-datatable/themes/material.css",
"inject": true,
"bundleName": "ngx-datatable-material"
},
"src/styles.scss" "src/styles.scss"
], ],
"scripts": [] "scripts": []

60
templates/module/angular/angular.json

@ -24,27 +24,44 @@
"tsConfig": "tsconfig.app.json", "tsConfig": "tsconfig.app.json",
"aot": true, "aot": true,
"extractCss": true, "extractCss": true,
"assets": [ "assets": ["src/favicon.ico", "src/assets"],
"src/favicon.ico",
"src/assets"
],
"styles": [ "styles": [
{
"input": "node_modules/@abp/ng.theme.shared/styles/bootstrap-rtl.min.css",
"inject": false,
"bundleName": "bootstrap-rtl.min"
},
{ {
"input": "node_modules/bootstrap/dist/css/bootstrap.min.css", "input": "node_modules/bootstrap/dist/css/bootstrap.min.css",
"inject": true, "inject": true,
"bundleName": "bootstrap.min" "bundleName": "bootstrap-ltr.min"
}, },
"src/styles.scss",
{ {
"input": "node_modules/@fortawesome/fontawesome-free/css/all.min.css", "input": "node_modules/@fortawesome/fontawesome-free/css/all.min.css",
"inject": false, "inject": true,
"bundleName": "fontawesome-all.min" "bundleName": "fontawesome-all.min"
}, },
{ {
"input": "node_modules/@fortawesome/fontawesome-free/css/v4-shims.min.css", "input": "node_modules/@fortawesome/fontawesome-free/css/v4-shims.min.css",
"inject": false, "inject": true,
"bundleName": "fontawesome-v4-shims.min" "bundleName": "fontawesome-v4-shims.min"
} },
{
"input": "node_modules/@swimlane/ngx-datatable/index.css",
"inject": true,
"bundleName": "ngx-datatable-index"
},
{
"input": "node_modules/@swimlane/ngx-datatable/assets/icons.css",
"inject": true,
"bundleName": "ngx-datatable-icons"
},
{
"input": "node_modules/@swimlane/ngx-datatable/themes/material.css",
"inject": true,
"bundleName": "ngx-datatable-material"
},
"src/styles.scss"
], ],
"scripts": [] "scripts": []
}, },
@ -102,10 +119,7 @@
"polyfills": "src/polyfills.ts", "polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json", "tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js", "karmaConfig": "karma.conf.js",
"assets": [ "assets": ["src/favicon.ico", "src/assets"],
"src/favicon.ico",
"src/assets"
],
"styles": [ "styles": [
{ {
"input": "node_modules/bootstrap/dist/css/bootstrap.min.css", "input": "node_modules/bootstrap/dist/css/bootstrap.min.css",
@ -130,14 +144,8 @@
"lint": { "lint": {
"builder": "@angular-devkit/build-angular:tslint", "builder": "@angular-devkit/build-angular:tslint",
"options": { "options": {
"tsConfig": [ "tsConfig": ["tsconfig.app.json", "tsconfig.spec.json", "e2e/tsconfig.json"],
"tsconfig.app.json", "exclude": ["**/node_modules/**"]
"tsconfig.spec.json",
"e2e/tsconfig.json"
],
"exclude": [
"**/node_modules/**"
]
} }
}, },
"e2e": { "e2e": {
@ -187,9 +195,7 @@
"projects/my-project-name/tsconfig.lib.json", "projects/my-project-name/tsconfig.lib.json",
"projects/my-project-name/tsconfig.spec.json" "projects/my-project-name/tsconfig.spec.json"
], ],
"exclude": [ "exclude": ["**/node_modules/**"]
"**/node_modules/**"
]
} }
} }
} }
@ -227,9 +233,7 @@
"projects/my-project-name-config/tsconfig.lib.json", "projects/my-project-name-config/tsconfig.lib.json",
"projects/my-project-name-config/tsconfig.spec.json" "projects/my-project-name-config/tsconfig.spec.json"
], ],
"exclude": [ "exclude": ["**/node_modules/**"]
"**/node_modules/**"
]
} }
} }
} }
@ -239,4 +243,4 @@
"cli": { "cli": {
"analytics": false "analytics": false
} }
} }

19
templates/module/angular/src/app/app.component.ts

@ -1,6 +1,4 @@
import { LazyLoadService, LOADING_STRATEGY } from '@abp/ng.core'; import { Component } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import { forkJoin } from 'rxjs';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
@ -9,17 +7,4 @@ import { forkJoin } from 'rxjs';
<router-outlet></router-outlet> <router-outlet></router-outlet>
`, `,
}) })
export class AppComponent implements OnInit { export class AppComponent {}
constructor(private lazyLoadService: LazyLoadService) {}
ngOnInit() {
forkJoin([
this.lazyLoadService.load(
LOADING_STRATEGY.PrependAnonymousStyleToHead('fontawesome-v4-shims.min.css'),
),
this.lazyLoadService.load(
LOADING_STRATEGY.PrependAnonymousStyleToHead('fontawesome-all.min.css'),
),
]).subscribe();
}
}

Loading…
Cancel
Save