Upgrade to Angular 18
This commit is contained in:
İsmail ÇAĞDAŞ 2024-07-26 11:42:06 +03:00 коммит произвёл GitHub
Родитель 250105a491 1e3b9221af
Коммит 1e732c4853
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
39 изменённых файлов: 1537 добавлений и 1548 удалений

Просмотреть файл

@ -183,5 +183,8 @@
"@schematics/angular:directive": {
"prefix": "app"
}
},
"cli": {
"analytics": false
}
}

Просмотреть файл

@ -13,14 +13,14 @@
"test": "ng test"
},
"dependencies": {
"@angular/animations": "^18.1.1",
"@angular/common": "^18.1.1",
"@angular/compiler": "^18.1.1",
"@angular/core": "^18.1.1",
"@angular/forms": "^18.1.1",
"@angular/platform-browser": "^18.1.1",
"@angular/platform-browser-dynamic": "^18.1.1",
"@angular/router": "^18.1.1",
"@angular/animations": "^18.1.2",
"@angular/common": "^18.1.2",
"@angular/compiler": "^18.1.2",
"@angular/core": "^18.1.2",
"@angular/forms": "^18.1.2",
"@angular/platform-browser": "^18.1.2",
"@angular/platform-browser-dynamic": "^18.1.2",
"@angular/router": "^18.1.2",
"@microsoft/signalr": "^8.0.7",
"@fortawesome/fontawesome-free": "^6.6.0",
"abp-ng2-module": "10.0.0",
@ -37,19 +37,17 @@
"rxjs": "^7.8.1",
"sweetalert2": "^11.12.2",
"ts-helpers": "^1.1.2",
"tslib": "^2.6.3",
"zone.js": "~0.14.8"
"tslib": "^2.6.3"
},
"devDependencies": {
"@angular-devkit/build-angular": "^18.1.1",
"@angular/cli": "^18.1.1",
"@angular/compiler-cli": "^18.1.1",
"@angular-devkit/build-angular": "^18.1.2",
"@angular/cli": "^18.1.2",
"@angular/compiler-cli": "^18.1.2",
"@angularclass/hmr": "^3.0.0",
"@types/jasmine": "~5.1.4",
"@types/lodash-es": "^4.17.12",
"@types/moment-timezone": "^0.5.30",
"@types/node": "^20.11.1",
"codelyzer": "^6.0.2",
"jasmine-core": "~5.1.2",
"jasmine-spec-reporter": "~7.0.0",
"karma": "~6.4.3",

Просмотреть файл

@ -1,9 +1,11 @@
<div class="login-box">
<account-header></account-header>
<div class="card">
<div *ngIf="showTenantChange()" class="card-header">
<tenant-change></tenant-change>
</div>
@if (showTenantChange()) {
<div class="card-header">
<tenant-change></tenant-change>
</div>
}
<div class="card-body login-card-body">
<router-outlet></router-outlet>
</div>

Просмотреть файл

@ -1,18 +1,19 @@
<div class="text-center">
<ng-container *ngFor="let language of languages">
<a
*ngIf="language.name != currentLanguage.name"
href="javascript:void(0);"
(click)="changeLanguage(language.name)"
>
<span
title="{{ language.displayName }}"
<div class="text-center">
@for (language of languages; track language) {
@if (language.name != currentLanguage.name) {
<a
href="javascript:void(0);"
(click)="changeLanguage(language.name)"
>
<span
title="{{ language.displayName }}"
[attr.class.current-language-icon]="
language.name != currentLanguage.name
"
>
<i class="d-inline-block mx-1 {{ language.icon }}"></i>
</span>
</a>
</ng-container>
>
<i class="d-inline-block mx-1 {{ language.icon }}"></i>
</span>
</a>
}
}
</div>

Просмотреть файл

@ -13,71 +13,73 @@
maxlength="256"
#userNameOrEmailAddressModel="ngModel"
#userNameOrEmailAddressEl
/>
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-user"></span>
</div>
</div>
</div>
<abp-validation-summary
[control]="userNameOrEmailAddressModel"
[controlEl]="userNameOrEmailAddressEl"
></abp-validation-summary>
</div>
<div class="form-group">
<div class="input-group">
<input
type="password"
class="form-control"
name="password"
[(ngModel)]="authService.authenticateModel.password"
[placeholder]="'Password' | localize"
required
maxlength="32"
#passwordModel="ngModel"
#passwordEl
/>
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-lock"></span>
</div>
</div>
</div>
<abp-validation-summary
[control]="passwordModel"
[controlEl]="passwordEl"
></abp-validation-summary>
</div>
<div class="form-group row">
<div class="col-md-8">
<div class="custom-control custom-checkbox">
<input
type="checkbox"
class="custom-control-input"
id="rememberMe"
name="rememberMe"
[(ngModel)]="authService.rememberMe"
/>
<label for="rememberMe" class="custom-control-label">
{{ "RememberMe" | localize }}
</label>
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-user"></span>
</div>
</div>
</div>
<abp-validation-summary
[control]="userNameOrEmailAddressModel"
[controlEl]="userNameOrEmailAddressEl"
></abp-validation-summary>
</div>
<div class="col-md-4">
<button
type="submit"
class="btn btn-primary btn-block"
[disabled]="!loginForm.form.valid || submitting"
>
{{ "LogIn" | localize }}
</button>
<div class="form-group">
<div class="input-group">
<input
type="password"
class="form-control"
name="password"
[(ngModel)]="authService.authenticateModel.password"
[placeholder]="'Password' | localize"
required
maxlength="32"
#passwordModel="ngModel"
#passwordEl
/>
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-lock"></span>
</div>
</div>
</div>
<abp-validation-summary
[control]="passwordModel"
[controlEl]="passwordEl"
></abp-validation-summary>
</div>
<div class="form-group row">
<div class="col-md-8">
<div class="custom-control custom-checkbox">
<input
type="checkbox"
class="custom-control-input"
id="rememberMe"
name="rememberMe"
[(ngModel)]="authService.rememberMe"
/>
<label for="rememberMe" class="custom-control-label">
{{ "RememberMe" | localize }}
</label>
</div>
</div>
<div class="col-md-4">
<button
type="submit"
class="btn btn-primary btn-block"
[disabled]="!loginForm.form.valid || submitting"
>
{{ "LogIn" | localize }}
</button>
</div>
</div>
</form>
@if (isSelfRegistrationAllowed) {
<p class="mb-1">
<a [routerLink]="['../register']">
<i class="fa fa-plus-circle"></i> {{ "Register" | localize }}
</a>
</p>
}
</div>
</div>
</form>
<p *ngIf="isSelfRegistrationAllowed" class="mb-1">
<a [routerLink]="['../register']">
<i class="fa fa-plus-circle"></i> {{ "Register" | localize }}
</a>
</p>
</div>

Просмотреть файл

@ -1,4 +1,4 @@
import { Component, Injector } from '@angular/core';
import { Component, Injector, Input } from '@angular/core';
import { Router } from '@angular/router';
import { finalize } from 'rxjs/operators';
import { AppComponentBase } from '@shared/app-component-base';

Просмотреть файл

@ -1,12 +1,18 @@
<div *ngIf="isMultiTenancyEnabled" class="text-center tenant-change-component">
<span>
{{ "CurrentTenant" | localize }}:
<span *ngIf="tenancyName" title="{{ name }}">
<strong>{{ tenancyName }}</strong>
</span>
<span *ngIf="!tenancyName">{{ "NotSelected" | localize }}</span>
(<a href="javascript:;" (click)="showChangeModal()">
@if (isMultiTenancyEnabled) {
<div class="text-center tenant-change-component">
<span>
{{ "CurrentTenant" | localize }}:
@if (tenancyName) {
<span title="{{ name }}">
<strong>{{ tenancyName }}</strong>
</span>
}
@if (!tenancyName) {
<span>{{ "NotSelected" | localize }}</span>
}
(<a href="javascript:;" (click)="showChangeModal()">
{{ "Change" | localize }} </a
>)
</span>
</div>
>)
</span>
</div>
}

Просмотреть файл

@ -6,16 +6,17 @@
</span>
</a>
<div class="dropdown-menu dropdown-menu-right p-0" *dropdownMenu>
<ng-container *ngFor="let language of languages">
<a
*ngIf="language.name != currentLanguage.name"
class="dropdown-item"
href="javascript:;"
(click)="changeLanguage(language.name)"
>
<i class="d-inline-block {{ language.icon }} mr-1"></i>
{{ language.displayName }}
</a>
</ng-container>
@for (language of languages; track language) {
@if (language.name != currentLanguage.name) {
<a
class="dropdown-item"
href="javascript:;"
(click)="changeLanguage(language.name)"
>
<i class="d-inline-block {{ language.icon }} mr-1"></i>
{{ language.displayName }}
</a>
}
}
</div>
</li>

Просмотреть файл

@ -4,68 +4,73 @@
data-widget="treeview"
role="menu"
data-accordion="false"
>
<ng-container *ngFor="let item of menuItems">
>
@for (item of menuItems; track item) {
<ng-container
*ngTemplateOutlet="sidebarInner; context: { item: item }"
></ng-container>
</ng-container>
}
</ul>
</nav>
<ng-template #sidebarInner let-item="item">
<li
*ngIf="isMenuItemVisible(item)"
class="nav-item"
[class.menu-open]="!item.isCollapsed"
[class.has-treeview]="item.children"
>
<a
*ngIf="item.route && item.route.indexOf('http') != 0"
class="nav-link"
[routerLink]="item.route"
[class.active]="item.isActive"
>
<i class="nav-icon {{ item.icon }}"></i>
<p>
{{ item.label }}
</p>
</a>
<a
*ngIf="item.route && item.route.indexOf('http') == 0 && !item.children"
class="nav-link"
target="_blank"
[href]="item.route"
>
<i class="nav-icon {{ item.icon }}"></i>
<p>
{{ item.label }}
</p>
</a>
<a
*ngIf="!item.route && item.children"
class="nav-link"
href="javascript:;"
[class.active]="item.isActive"
(click)="item.isCollapsed = !item.isCollapsed"
>
<i class="nav-icon {{ item.icon }}"></i>
<p>
{{ item.label }}
<i class="right fas fa-angle-left"></i>
</p>
</a>
<ul
*ngIf="item.children"
class="nav nav-treeview"
[collapse]="item.isCollapsed"
[isAnimated]="true"
>
<ng-container *ngFor="let item of item.children">
<ng-container
*ngTemplateOutlet="sidebarInner; context: { item: item }"
></ng-container>
</ng-container>
</ul>
</li>
@if (isMenuItemVisible(item)) {
<li
class="nav-item"
[class.menu-open]="!item.isCollapsed"
[class.has-treeview]="item.children"
>
@if (item.route && item.route.indexOf('http') != 0) {
<a
class="nav-link"
[routerLink]="item.route"
[class.active]="item.isActive"
>
<i class="nav-icon {{ item.icon }}"></i>
<p>
{{ item.label }}
</p>
</a>
}
@if (item.route && item.route.indexOf('http') == 0 && !item.children) {
<a
class="nav-link"
target="_blank"
[href]="item.route"
>
<i class="nav-icon {{ item.icon }}"></i>
<p>
{{ item.label }}
</p>
</a>
}
@if (!item.route && item.children) {
<a
class="nav-link"
href="javascript:;"
[class.active]="item.isActive"
(click)="item.isCollapsed = !item.isCollapsed"
>
<i class="nav-icon {{ item.icon }}"></i>
<p>
{{ item.label }}
<i class="right fas fa-angle-left"></i>
</p>
</a>
}
@if (item.children) {
<ul
class="nav nav-treeview"
[collapse]="item.isCollapsed"
[isAnimated]="true"
>
@for (item of item.children; track item) {
<ng-container
*ngTemplateOutlet="sidebarInner; context: { item: item }"
></ng-container>
}
</ul>
}
</li>
}
</ng-template>

Просмотреть файл

@ -3,7 +3,7 @@
autocomplete="off"
#createRoleForm="ngForm"
(ngSubmit)="save()"
>
>
<abp-modal-header
[title]="'CreateNewRole' | localize"
(onCloseClick)="bsModalRef.hide()"
@ -27,77 +27,77 @@
[(ngModel)]="role.name"
#nameModel="ngModel"
#nameEl
/>
<abp-validation-summary
[control]="nameModel"
[controlEl]="nameEl"
></abp-validation-summary>
/>
<abp-validation-summary
[control]="nameModel"
[controlEl]="nameEl"
></abp-validation-summary>
</div>
</div>
</div>
<div class="form-group row required">
<label class="col-md-3 col-form-label" for="displayName">
{{ "DisplayName" | localize }}
</label>
<div class="col-md-9">
<input
type="text"
class="form-control"
name="displayName"
id="displayName"
required
minlength="2"
maxlength="32"
[(ngModel)]="role.displayName"
#displayNameModel="ngModel"
#displayNameEl
/>
<abp-validation-summary
[control]="displayNameModel"
[controlEl]="displayNameEl"
></abp-validation-summary>
</div>
</div>
<div class="form-group row mb-0">
<label class="col-md-3 col-form-label" for="description">
{{ "RoleDescription" | localize }}
</label>
<div class="col-md-9">
<textarea
type="text"
class="form-control"
name="description"
id="description"
[(ngModel)]="role.description"
>
</textarea>
</div>
</div>
</tab>
<tab [heading]="'Permissions' | localize" class="pt-3 px-2">
<div class="form-group row mb-0">
<ng-container *ngFor="let permission of permissions; let i = index">
<div class="col-md-6">
<div class="custom-control custom-checkbox">
<input
type="checkbox"
class="custom-control-input"
[id]="'permission_' + i"
[checked]="isPermissionChecked(permission.name)"
(change)="onPermissionChange(permission, $event)"
<div class="form-group row required">
<label class="col-md-3 col-form-label" for="displayName">
{{ "DisplayName" | localize }}
</label>
<div class="col-md-9">
<input
type="text"
class="form-control"
name="displayName"
id="displayName"
required
minlength="2"
maxlength="32"
[(ngModel)]="role.displayName"
#displayNameModel="ngModel"
#displayNameEl
/>
<label class="custom-control-label" [for]="'permission_' + i">
{{ permission.displayName }}
</label>
<abp-validation-summary
[control]="displayNameModel"
[controlEl]="displayNameEl"
></abp-validation-summary>
</div>
</div>
</ng-container>
<div class="form-group row mb-0">
<label class="col-md-3 col-form-label" for="description">
{{ "RoleDescription" | localize }}
</label>
<div class="col-md-9">
<textarea
type="text"
class="form-control"
name="description"
id="description"
[(ngModel)]="role.description"
>
</textarea>
</div>
</div>
</tab>
<tab [heading]="'Permissions' | localize" class="pt-3 px-2">
<div class="form-group row mb-0">
@for (permission of permissions; track permission; let i = $index) {
<div class="col-md-6">
<div class="custom-control custom-checkbox">
<input
type="checkbox"
class="custom-control-input"
[id]="'permission_' + i"
[checked]="isPermissionChecked(permission.name)"
(change)="onPermissionChange(permission, $event)"
/>
<label class="custom-control-label" [for]="'permission_' + i">
{{ permission.displayName }}
</label>
</div>
</div>
}
</div>
</tab>
</tabset>
</div>
</tab>
</tabset>
</div>
<abp-modal-footer
[cancelDisabled]="saving"
[saveDisabled]="!createRoleForm.form.valid || saving"
(onCancelClick)="bsModalRef.hide()"
></abp-modal-footer>
</form>
<abp-modal-footer
[cancelDisabled]="saving"
[saveDisabled]="!createRoleForm.form.valid || saving"
(onCancelClick)="bsModalRef.hide()"
></abp-modal-footer>
</form>

Просмотреть файл

@ -3,7 +3,8 @@ import {
Injector,
OnInit,
EventEmitter,
Output,
output,
ChangeDetectorRef,
} from '@angular/core';
import { BsModalRef } from 'ngx-bootstrap/modal';
import { AppComponentBase } from '@shared/app-component-base';
@ -27,12 +28,13 @@ export class CreateRoleDialogComponent extends AppComponentBase
checkedPermissionsMap: { [key: string]: boolean } = {};
defaultPermissionCheckedStatus = true;
@Output() onSave = new EventEmitter<any>();
onSave = output<EventEmitter<any>>()
constructor(
injector: Injector,
private _roleService: RoleServiceProxy,
public bsModalRef: BsModalRef
public bsModalRef: BsModalRef,
private cd: ChangeDetectorRef
) {
super(injector);
}
@ -43,6 +45,7 @@ export class CreateRoleDialogComponent extends AppComponentBase
.subscribe((result: PermissionDtoListResultDto) => {
this.permissions = result.items;
this.setInitialPermissionsStatus();
this.cd.detectChanges();
});
}
@ -87,10 +90,11 @@ export class CreateRoleDialogComponent extends AppComponentBase
() => {
this.notify.info(this.l('SavedSuccessfully'));
this.bsModalRef.hide();
this.onSave.emit();
this.onSave.emit(null);
},
() => {
this.saving = false;
this.cd.detectChanges();
}
);
}

Просмотреть файл

@ -3,7 +3,7 @@
autocomplete="off"
#editRoleForm="ngForm"
(ngSubmit)="save()"
>
>
<abp-modal-header
[title]="'EditRole' | localize"
(onCloseClick)="bsModalRef.hide()"
@ -27,78 +27,78 @@
[(ngModel)]="role.name"
#nameModel="ngModel"
#nameEl
/>
<abp-validation-summary
[control]="nameModel"
[controlEl]="nameEl"
></abp-validation-summary>
/>
<abp-validation-summary
[control]="nameModel"
[controlEl]="nameEl"
></abp-validation-summary>
</div>
</div>
</div>
<div class="form-group row required">
<label class="col-md-3 col-form-label" for="displayName">
{{ "DisplayName" | localize }}
</label>
<div class="col-md-9">
<input
type="text"
class="form-control"
name="displayName"
id="displayName"
required
minlength="2"
maxlength="32"
[(ngModel)]="role.displayName"
#displayNameModel="ngModel"
#displayNameEl
/>
<abp-validation-summary
[control]="displayNameModel"
[controlEl]="displayNameEl"
></abp-validation-summary>
</div>
</div>
<div class="form-group row mb-0">
<label class="col-md-3 col-form-label" for="description">
{{ "RoleDescription" | localize }}
</label>
<div class="col-md-9">
<textarea
type="text"
class="form-control"
name="description"
id="description"
[(ngModel)]="role.description"
>
</textarea>
</div>
</div>
</tab>
<tab [heading]="'Permissions' | localize" class="pt-3 px-2">
<div class="form-group row mb-0">
<ng-container *ngFor="let permission of permissions; let i = index">
<div class="col-md-6">
<div class="custom-control custom-checkbox">
<input
type="checkbox"
class="custom-control-input"
[id]="'permission_' + i"
[checked]="isPermissionChecked(permission.name)"
[disabled]="role.isStatic"
(change)="onPermissionChange(permission, $event)"
<div class="form-group row required">
<label class="col-md-3 col-form-label" for="displayName">
{{ "DisplayName" | localize }}
</label>
<div class="col-md-9">
<input
type="text"
class="form-control"
name="displayName"
id="displayName"
required
minlength="2"
maxlength="32"
[(ngModel)]="role.displayName"
#displayNameModel="ngModel"
#displayNameEl
/>
<label class="custom-control-label" [for]="'permission_' + i">
{{ permission.displayName }}
</label>
<abp-validation-summary
[control]="displayNameModel"
[controlEl]="displayNameEl"
></abp-validation-summary>
</div>
</div>
</ng-container>
<div class="form-group row mb-0">
<label class="col-md-3 col-form-label" for="description">
{{ "RoleDescription" | localize }}
</label>
<div class="col-md-9">
<textarea
type="text"
class="form-control"
name="description"
id="description"
[(ngModel)]="role.description"
>
</textarea>
</div>
</div>
</tab>
<tab [heading]="'Permissions' | localize" class="pt-3 px-2">
<div class="form-group row mb-0">
@for (permission of permissions; track permission; let i = $index) {
<div class="col-md-6">
<div class="custom-control custom-checkbox">
<input
type="checkbox"
class="custom-control-input"
[id]="'permission_' + i"
[checked]="isPermissionChecked(permission.name)"
[disabled]="role.isStatic"
(change)="onPermissionChange(permission, $event)"
/>
<label class="custom-control-label" [for]="'permission_' + i">
{{ permission.displayName }}
</label>
</div>
</div>
}
</div>
</tab>
</tabset>
</div>
</tab>
</tabset>
</div>
<abp-modal-footer
[cancelDisabled]="saving"
[saveDisabled]="!editRoleForm.form.valid || saving"
(onCancelClick)="bsModalRef.hide()"
></abp-modal-footer>
</form>
<abp-modal-footer
[cancelDisabled]="saving"
[saveDisabled]="!editRoleForm.form.valid || saving"
(onCancelClick)="bsModalRef.hide()"
></abp-modal-footer>
</form>

Просмотреть файл

@ -4,6 +4,7 @@ import {
OnInit,
EventEmitter,
Output,
ChangeDetectorRef,
} from '@angular/core';
import { BsModalRef } from 'ngx-bootstrap/modal';
import { forEach as _forEach, includes as _includes, map as _map } from 'lodash-es';
@ -34,7 +35,8 @@ export class EditRoleDialogComponent extends AppComponentBase
constructor(
injector: Injector,
private _roleService: RoleServiceProxy,
public bsModalRef: BsModalRef
public bsModalRef: BsModalRef,
private cd: ChangeDetectorRef
) {
super(injector);
}
@ -47,6 +49,7 @@ export class EditRoleDialogComponent extends AppComponentBase
this.permissions = result.permissions;
this.grantedPermissionNames = result.grantedPermissionNames;
this.setInitialPermissionsStatus();
this.cd.detectChanges();
});
}
@ -62,7 +65,7 @@ export class EditRoleDialogComponent extends AppComponentBase
return _includes(this.grantedPermissionNames, permissionName);
}
onPermissionChange(permission: PermissionDto, $event) {
onPermissionChange(permission: FlatPermissionDto, $event) {
this.checkedPermissionsMap[permission.name] = $event.target.checked;
}

Просмотреть файл

@ -37,49 +37,52 @@
[placeholder]="'SearchWithThreeDot' | localize"
[(ngModel)]="keyword"
(keyup.enter)="getDataPage(1)" />
</div>
</div>
</div>
</div>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-striped table-bordered"
[busy]="isTableLoading">
<thead class="bg-light">
<tr>
<th>{{ "RoleName" | localize }}</th>
<th>{{ "DisplayName" | localize }}</th>
<th style="width: 200px;">{{ "Actions" | localize }}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="
let role of roles
<div class="card-body">
<div class="table-responsive">
<table class="table table-striped table-bordered"
[busy]="isTableLoading">
<thead class="bg-light">
<tr>
<th>{{ "RoleName" | localize }}</th>
<th>{{ "DisplayName" | localize }}</th>
<th style="width: 200px;">{{ "Actions" | localize }}</th>
</tr>
</thead>
<tbody>
@for (
role of roles
| paginate
: {
id: 'server',
itemsPerPage: pageSize,
currentPage: pageNumber,
totalItems: totalItems
}
">
<td>{{ role.name }}</td>
<td>{{ role.displayName }}</td>
<td>
<button type="button"
class="btn btn-sm bg-secondary"
(click)="editRole(role)">
<i class="fas fa-pencil-alt"></i>
{{ "Edit" | localize }}
</button>
<button type="button"
class="btn btn-sm bg-danger mx-2"
(click)="delete(role)">
<i class="fas fa-trash"></i>
{{ "Delete" | localize }}
</button>
</td>
</tr>
: {
id: 'server',
itemsPerPage: pageSize,
currentPage: pageNumber,
totalItems: totalItems
}
; track
role.id) {
<tr>
<td>{{ role.name }}</td>
<td>{{ role.displayName }}</td>
<td>
<button type="button"
class="btn btn-sm bg-secondary"
(click)="editRole(role)">
<i class="fas fa-pencil-alt"></i>
{{ "Edit" | localize }}
</button>
<button type="button"
class="btn btn-sm bg-danger mx-2"
(click)="delete(role)">
<i class="fas fa-trash"></i>
{{ "Delete" | localize }}
</button>
</td>
</tr>
}
</tbody>
</table>
</div>

Просмотреть файл

@ -1,4 +1,4 @@
import { Component, Injector } from '@angular/core';
import { Component, Injector, ChangeDetectorRef } from '@angular/core';
import { finalize } from 'rxjs/operators';
import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
import { appModuleAnimation } from '@shared/animations/routerTransition';
@ -29,9 +29,10 @@ export class RolesComponent extends PagedListingComponentBase<RoleDto> {
constructor(
injector: Injector,
private _rolesService: RoleServiceProxy,
private _modalService: BsModalService
private _modalService: BsModalService,
cd: ChangeDetectorRef
) {
super(injector);
super(injector, cd);
}
list(
@ -51,6 +52,7 @@ export class RolesComponent extends PagedListingComponentBase<RoleDto> {
.subscribe((result: RoleDtoPagedResultDto) => {
this.roles = result.items;
this.showPaging(result, pageNumber);
this.cd.detectChanges();
});
}

Просмотреть файл

@ -3,7 +3,8 @@ import {
Injector,
OnInit,
Output,
EventEmitter
EventEmitter,
ChangeDetectorRef
} from '@angular/core';
import { BsModalRef } from 'ngx-bootstrap/modal';
import { AppComponentBase } from '@shared/app-component-base';
@ -25,13 +26,15 @@ export class CreateTenantDialogComponent extends AppComponentBase
constructor(
injector: Injector,
public _tenantService: TenantServiceProxy,
public bsModalRef: BsModalRef
public bsModalRef: BsModalRef,
private cd: ChangeDetectorRef
) {
super(injector);
}
ngOnInit(): void {
this.tenant.isActive = true;
this.cd.detectChanges();
}
save(): void {

Просмотреть файл

@ -3,7 +3,8 @@ import {
Injector,
OnInit,
Output,
EventEmitter
EventEmitter,
ChangeDetectorRef
} from '@angular/core';
import { BsModalRef } from 'ngx-bootstrap/modal';
import { AppComponentBase } from '@shared/app-component-base';
@ -26,7 +27,8 @@ export class EditTenantDialogComponent extends AppComponentBase
constructor(
injector: Injector,
public _tenantService: TenantServiceProxy,
public bsModalRef: BsModalRef
public bsModalRef: BsModalRef,
private cd: ChangeDetectorRef
) {
super(injector);
}
@ -34,6 +36,7 @@ export class EditTenantDialogComponent extends AppComponentBase
ngOnInit(): void {
this._tenantService.get(this.id).subscribe((result: TenantDto) => {
this.tenant = result;
this.cd.detectChanges();
});
}

Просмотреть файл

@ -1,224 +1,228 @@
<div [@routerTransition]>
<section class="content-header">
<div class="container-fluid">
<div class="row">
<div class="col-6">
<h1>{{ "Tenants" | localize }}</h1>
</div>
<div class="col-6 text-right">
<a href="javascript:;" class="btn bg-blue" (click)="createTenant()">
<i class="fa fa-plus-square"></i>
{{ "Create" | localize }}
</a>
</div>
</div>
<section class="content-header">
<div class="container-fluid">
<div class="row">
<div class="col-6">
<h1>{{ "Tenants" | localize }}</h1>
</div>
</section>
<section class="content px-2">
<div class="container-fluid">
<div class="card">
<div class="card-header">
<div class="col-6 text-right">
<a href="javascript:;" class="btn bg-blue" (click)="createTenant()">
<i class="fa fa-plus-square"></i>
{{ "Create" | localize }}
</a>
</div>
</div>
</div>
</section>
<section class="content px-2">
<div class="container-fluid">
<div class="card">
<div class="card-header">
<div class="row">
<div class="col-md-6">&emsp;</div>
<div class="col-md-6">
<div class="input-group">
<div class="input-group-prepend">
<button
type="button"
class="btn bg-blue"
(click)="getDataPage(1)"
>
<i class="fas fa-search"></i>
</button>
</div>
<input
type="text"
class="form-control"
name="keyword"
[placeholder]="'SearchWithThreeDot' | localize"
[(ngModel)]="keyword"
(keyup.enter)="getDataPage(1)"
/>
<div class="input-group-append">
<button
type="button"
class="btn btn-default"
(click)="advancedFiltersVisible = !advancedFiltersVisible"
>
<i
class="fas"
[class.fa-angle-up]="advancedFiltersVisible"
[class.fa-angle-down]="!advancedFiltersVisible"
></i>
</button>
</div>
</div>
</div>
</div>
@if (advancedFiltersVisible) {
<div class="card mb-0 mt-1">
<div class="card-body">
<form class="form-horizontal">
<div class="row">
<div class="col-md-6">&emsp;</div>
<div class="col-md-6">
<div class="input-group">
<div class="input-group-prepend">
<button
type="button"
class="btn bg-blue"
(click)="getDataPage(1)"
>
<i class="fas fa-search"></i>
</button>
</div>
<input
type="text"
class="form-control"
name="keyword"
[placeholder]="'SearchWithThreeDot' | localize"
[(ngModel)]="keyword"
(keyup.enter)="getDataPage(1)"
<div class="col-md-6">
<div class="form-group row mb-0">
<label class="col-md-3 col-form-label">
{{ "IsActive" | localize }}
</label>
<div class="col-md-9 pt-2">
<div class="custom-control custom-radio d-inline">
<input
type="radio"
class="custom-control-input"
id="isActiveAll"
name="isActive"
[(ngModel)]="isActive"
[value]="undefined"
checked
/>
<div class="input-group-append">
<button
type="button"
class="btn btn-default"
(click)="advancedFiltersVisible = !advancedFiltersVisible"
<label class="custom-control-label" for="isActiveAll">
{{ "All" | localize }}
</label>
</div>
<div class="custom-control custom-radio d-inline mx-3">
<input
type="radio"
class="custom-control-input"
id="isActiveActive"
name="isActive"
[(ngModel)]="isActive"
[value]="true"
/>
<label
class="custom-control-label"
for="isActiveActive"
>
<i
class="fas"
[class.fa-angle-up]="advancedFiltersVisible"
[class.fa-angle-down]="!advancedFiltersVisible"
></i>
</button>
{{ "Yes" | localize }}
</label>
</div>
<div class="custom-control custom-radio d-inline">
<input
type="radio"
class="custom-control-input"
id="isActivePassive"
name="isActive"
[(ngModel)]="isActive"
[value]="false"
/>
<label
class="custom-control-label"
for="isActivePassive"
>
{{ "No" | localize }}
</label>
</div>
</div>
</div>
</div>
</div>
</div>
<div *ngIf="advancedFiltersVisible" class="card mb-0 mt-1">
<div class="card-body">
<form class="form-horizontal">
<div class="row">
<div class="col-md-6">
<div class="form-group row mb-0">
<label class="col-md-3 col-form-label">
{{ "IsActive" | localize }}
</label>
<div class="col-md-9 pt-2">
<div class="custom-control custom-radio d-inline">
<input
type="radio"
class="custom-control-input"
id="isActiveAll"
name="isActive"
[(ngModel)]="isActive"
[value]="undefined"
checked
/>
<label class="custom-control-label" for="isActiveAll">
{{ "All" | localize }}
</label>
</div>
<div class="custom-control custom-radio d-inline mx-3">
<input
type="radio"
class="custom-control-input"
id="isActiveActive"
name="isActive"
[(ngModel)]="isActive"
[value]="true"
/>
<label
class="custom-control-label"
for="isActiveActive"
>
{{ "Yes" | localize }}
</label>
</div>
<div class="custom-control custom-radio d-inline">
<input
type="radio"
class="custom-control-input"
id="isActivePassive"
name="isActive"
[(ngModel)]="isActive"
[value]="false"
/>
<label
class="custom-control-label"
for="isActivePassive"
>
{{ "No" | localize }}
</label>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
<div class="card-footer">
<button
type="button"
class="btn bg-blue"
(click)="getDataPage(1)"
>
{{ "Search" | localize }}
</button>
<button
type="button"
class="btn btn-default float-right"
(click)="clearFilters()"
>
{{ "Clear" | localize }}
</button>
</div>
</div>
</form>
</div>
<div class="card-footer">
<button
type="button"
class="btn bg-blue"
(click)="getDataPage(1)"
>
{{ "Search" | localize }}
</button>
<button
type="button"
class="btn btn-default float-right"
(click)="clearFilters()"
>
{{ "Clear" | localize }}
</button>
</div>
</div>
}
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-striped table-bordered" [busy]="isTableLoading">
<thead class="bg-light">
<tr>
<th>{{ "TenancyName" | localize }}</th>
<th>{{ "Name" | localize }}</th>
<th>{{ "IsActive" | localize }}</th>
<th style="width: 200px;">{{ "Actions" | localize }}</th>
</tr>
</thead>
<tbody>
<tr
*ngFor="
let tenant of tenants
| paginate
: {
<div class="table-responsive">
<table class="table table-striped table-bordered" [busy]="isTableLoading">
<thead class="bg-light">
<tr>
<th>{{ "TenancyName" | localize }}</th>
<th>{{ "Name" | localize }}</th>
<th>{{ "IsActive" | localize }}</th>
<th style="width: 200px;">{{ "Actions" | localize }}</th>
</tr>
</thead>
<tbody>
@for (
tenant of tenants
| paginate
: {
id: 'server',
itemsPerPage: pageSize,
currentPage: pageNumber,
totalItems: totalItems
}
"
>
<td>{{ tenant.tenancyName }}</td>
<td>{{ tenant.name }}</td>
<td>
<div class="custom-control custom-checkbox">
<input
type="checkbox"
class="custom-control-input"
disabled
[checked]="tenant.isActive"
/>
<label class="custom-control-label"></label>
</div>
</td>
<td>
<button
type="button"
class="btn btn-sm bg-secondary"
(click)="editTenant(tenant)"
>
<i class="fas fa-pencil-alt"></i>
{{ "Edit" | localize }}
</button>
<button
type="button"
class="btn btn-sm bg-danger mx-2"
(click)="delete(tenant)"
>
<i class="fas fa-trash"></i>
{{ "Delete" | localize }}
</button>
</td>
</tr>
</tbody>
</table>
</div>
; track
tenant.id) {
<tr
>
<td>{{ tenant.tenancyName }}</td>
<td>{{ tenant.name }}</td>
<td>
<div class="custom-control custom-checkbox">
<input
type="checkbox"
class="custom-control-input"
disabled
[checked]="tenant.isActive"
/>
<label class="custom-control-label"></label>
</div>
</td>
<td>
<button
type="button"
class="btn btn-sm bg-secondary"
(click)="editTenant(tenant)"
>
<i class="fas fa-pencil-alt"></i>
{{ "Edit" | localize }}
</button>
<button
type="button"
class="btn btn-sm bg-danger mx-2"
(click)="delete(tenant)"
>
<i class="fas fa-trash"></i>
{{ "Delete" | localize }}
</button>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
<div class="card-footer table-card-footer bg-light border-top">
<div class="row">
<div class="col-sm-4 col-12 text-sm-left text-center">
<button class="btn btn-secondary" (click)="refresh()">
<i class="fas fa-redo-alt"></i>
</button>
</div>
<div class="col-sm-4 col-12 text-center">
<p class="mb-0 my-2">
{{ "TotalRecordsCount" | localize: totalItems }}
</p>
</div>
<div class="col-sm-4 col-12">
<div class="float-sm-right m-auto">
<abp-pagination-controls
id="server"
(pageChange)="getDataPage($event)"
>
</abp-pagination-controls>
</div>
</div>
<div class="row">
<div class="col-sm-4 col-12 text-sm-left text-center">
<button class="btn btn-secondary" (click)="refresh()">
<i class="fas fa-redo-alt"></i>
</button>
</div>
<div class="col-sm-4 col-12 text-center">
<p class="mb-0 my-2">
{{ "TotalRecordsCount" | localize: totalItems }}
</p>
</div>
<div class="col-sm-4 col-12">
<div class="float-sm-right m-auto">
<abp-pagination-controls
id="server"
(pageChange)="getDataPage($event)"
>
</abp-pagination-controls>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
</section>
</div>

Просмотреть файл

@ -1,4 +1,4 @@
import { Component, Injector } from '@angular/core';
import { ChangeDetectorRef, Component, Injector } from '@angular/core';
import { finalize } from 'rxjs/operators';
import { BsModalService, BsModalRef } from 'ngx-bootstrap/modal';
import { appModuleAnimation } from '@shared/animations/routerTransition';
@ -32,9 +32,10 @@ export class TenantsComponent extends PagedListingComponentBase<TenantDto> {
constructor(
injector: Injector,
private _tenantService: TenantServiceProxy,
private _modalService: BsModalService
private _modalService: BsModalService,
cd: ChangeDetectorRef
) {
super(injector);
super(injector, cd);
}
list(

Просмотреть файл

@ -3,7 +3,7 @@
autocomplete="off"
#createUserModal="ngForm"
(ngSubmit)="save()"
>
>
<abp-modal-header
[title]="'CreateNewUser' | localize"
(onCloseClick)="bsModalRef.hide()"
@ -26,175 +26,175 @@
[(ngModel)]="user.name"
#nameModel="ngModel"
#nameEl
/>
<abp-validation-summary
[control]="nameModel"
[controlEl]="nameEl"
></abp-validation-summary>
</div>
</div>
<div class="form-group row required">
<label class="col-md-3 col-form-label" for="surname">
{{ "Surname" | localize }}
</label>
<div class="col-md-9">
<input
type="text"
class="form-control"
name="surname"
id="surname"
required
maxlength="32"
[(ngModel)]="user.surname"
#surnameModel="ngModel"
#surnameEl
/>
<abp-validation-summary
[control]="surnameModel"
[controlEl]="surnameEl"
></abp-validation-summary>
</div>
</div>
<div class="form-group row required">
<label class="col-md-3 col-form-label" for="userName">
{{ "UserName" | localize }}
</label>
<div class="col-md-9">
<input
type="text"
class="form-control"
name="userName"
id="userName"
required
minlength="2"
maxlength="32"
[(ngModel)]="user.userName"
#userNameModel="ngModel"
#userNameEl
/>
<abp-validation-summary
[control]="userNameModel"
[controlEl]="userNameEl"
></abp-validation-summary>
</div>
</div>
<div class="form-group row required">
<label class="col-md-3 col-form-label" for="password">
{{ "Password" | localize }}
</label>
<div class="col-md-9">
<input
type="password"
class="form-control"
name="password"
id="password"
required
maxlength="32"
validateEqual="confirmPassword"
reverse="true"
pattern="(?=^.{8,}$)(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s)[0-9a-zA-Z!@#$%^&*()]*$"
[(ngModel)]="user.password"
#passwordModel="ngModel"
#passwordEl
/>
<abp-validation-summary
[control]="passwordModel"
[controlEl]="passwordEl"
[customValidationErrors]="passwordValidationErrors"
></abp-validation-summary>
</div>
</div>
<div class="form-group row required">
<label class="col-md-3 col-form-label" for="confirmPassword">
{{ "ConfirmPassword" | localize }}
</label>
<div class="col-md-9">
<input
type="password"
class="form-control"
name="confirmPassword"
id="confirmPassword"
required
maxlength="32"
validateEqual="password"
reverse="false"
ngModel
#confirmPasswordModel="ngModel"
#confirmPasswordEl
/>
<abp-validation-summary
[control]="confirmPasswordModel"
[controlEl]="confirmPasswordEl"
[customValidationErrors]="confirmPasswordValidationErrors"
></abp-validation-summary>
</div>
</div>
<div class="form-group row required">
<label class="col-md-3 col-form-label" for="emailAddress">
{{ "EmailAddress" | localize }}
</label>
<div class="col-md-9">
<input
type="email"
class="form-control"
name="emailAddress"
id="emailAddress"
required
maxlength="256"
pattern="^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{1,})+$"
[(ngModel)]="user.emailAddress"
#emailAddressModel="ngModel"
#emailAddressEl
/>
<abp-validation-summary
[control]="emailAddressModel"
[controlEl]="emailAddressEl"
></abp-validation-summary>
</div>
</div>
<div class="form-group row mb-0">
<label class="col-md-3 col-form-label">
{{ "IsActive" | localize }}
</label>
<div class="col-md-9">
<div class="custom-control custom-checkbox">
<input
type="checkbox"
class="custom-control-input"
name="isActive"
id="isActive"
[(ngModel)]="user.isActive"
/>
<label class="custom-control-label mt-2" for="isActive"></label>
<abp-validation-summary
[control]="nameModel"
[controlEl]="nameEl"
></abp-validation-summary>
</div>
</div>
</div>
</tab>
<tab [heading]="'UserRoles' | localize" class="pt-3 px-2">
<div class="form-group row mb-0">
<ng-container *ngFor="let role of roles; let i = index">
<div class="col-md-6">
<div class="custom-control custom-checkbox">
<input
type="checkbox"
class="custom-control-input"
[id]="'role_' + i"
[checked]="isRoleChecked(role.normalizedName)"
(change)="onRoleChange(role, $event)"
<div class="form-group row required">
<label class="col-md-3 col-form-label" for="surname">
{{ "Surname" | localize }}
</label>
<div class="col-md-9">
<input
type="text"
class="form-control"
name="surname"
id="surname"
required
maxlength="32"
[(ngModel)]="user.surname"
#surnameModel="ngModel"
#surnameEl
/>
<label class="custom-control-label" [for]="'role_' + i">
{{ role.name }}
</label>
<abp-validation-summary
[control]="surnameModel"
[controlEl]="surnameEl"
></abp-validation-summary>
</div>
</div>
</ng-container>
</div>
</tab>
</tabset>
</div>
<abp-modal-footer
[cancelDisabled]="saving"
[saveDisabled]="!createUserModal.form.valid || saving"
(onCancelClick)="bsModalRef.hide()"
></abp-modal-footer>
</form>
<div class="form-group row required">
<label class="col-md-3 col-form-label" for="userName">
{{ "UserName" | localize }}
</label>
<div class="col-md-9">
<input
type="text"
class="form-control"
name="userName"
id="userName"
required
minlength="2"
maxlength="32"
[(ngModel)]="user.userName"
#userNameModel="ngModel"
#userNameEl
/>
<abp-validation-summary
[control]="userNameModel"
[controlEl]="userNameEl"
></abp-validation-summary>
</div>
</div>
<div class="form-group row required">
<label class="col-md-3 col-form-label" for="password">
{{ "Password" | localize }}
</label>
<div class="col-md-9">
<input
type="password"
class="form-control"
name="password"
id="password"
required
maxlength="32"
validateEqual="confirmPassword"
reverse="true"
pattern="(?=^.{8,}$)(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s)[0-9a-zA-Z!@#$%^&*()]*$"
[(ngModel)]="user.password"
#passwordModel="ngModel"
#passwordEl
/>
<abp-validation-summary
[control]="passwordModel"
[controlEl]="passwordEl"
[customValidationErrors]="passwordValidationErrors"
></abp-validation-summary>
</div>
</div>
<div class="form-group row required">
<label class="col-md-3 col-form-label" for="confirmPassword">
{{ "ConfirmPassword" | localize }}
</label>
<div class="col-md-9">
<input
type="password"
class="form-control"
name="confirmPassword"
id="confirmPassword"
required
maxlength="32"
validateEqual="password"
reverse="false"
ngModel
#confirmPasswordModel="ngModel"
#confirmPasswordEl
/>
<abp-validation-summary
[control]="confirmPasswordModel"
[controlEl]="confirmPasswordEl"
[customValidationErrors]="confirmPasswordValidationErrors"
></abp-validation-summary>
</div>
</div>
<div class="form-group row required">
<label class="col-md-3 col-form-label" for="emailAddress">
{{ "EmailAddress" | localize }}
</label>
<div class="col-md-9">
<input
type="email"
class="form-control"
name="emailAddress"
id="emailAddress"
required
maxlength="256"
pattern="^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{1,})+$"
[(ngModel)]="user.emailAddress"
#emailAddressModel="ngModel"
#emailAddressEl
/>
<abp-validation-summary
[control]="emailAddressModel"
[controlEl]="emailAddressEl"
></abp-validation-summary>
</div>
</div>
<div class="form-group row mb-0">
<label class="col-md-3 col-form-label">
{{ "IsActive" | localize }}
</label>
<div class="col-md-9">
<div class="custom-control custom-checkbox">
<input
type="checkbox"
class="custom-control-input"
name="isActive"
id="isActive"
[(ngModel)]="user.isActive"
/>
<label class="custom-control-label mt-2" for="isActive"></label>
</div>
</div>
</div>
</tab>
<tab [heading]="'UserRoles' | localize" class="pt-3 px-2">
<div class="form-group row mb-0">
@for (role of roles; track role; let i = $index) {
<div class="col-md-6">
<div class="custom-control custom-checkbox">
<input
type="checkbox"
class="custom-control-input"
[id]="'role_' + i"
[checked]="isRoleChecked(role.normalizedName)"
(change)="onRoleChange(role, $event)"
/>
<label class="custom-control-label" [for]="'role_' + i">
{{ role.name }}
</label>
</div>
</div>
}
</div>
</tab>
</tabset>
</div>
<abp-modal-footer
[cancelDisabled]="saving"
[saveDisabled]="!createUserModal.form.valid || saving"
(onCancelClick)="bsModalRef.hide()"
></abp-modal-footer>
</form>

Просмотреть файл

@ -3,7 +3,8 @@ import {
Injector,
OnInit,
EventEmitter,
Output
Output,
ChangeDetectorRef
} from '@angular/core';
import { BsModalRef } from 'ngx-bootstrap/modal';
import { forEach as _forEach, map as _map } from 'lodash-es';
@ -44,7 +45,8 @@ export class CreateUserDialogComponent extends AppComponentBase
constructor(
injector: Injector,
public _userService: UserServiceProxy,
public bsModalRef: BsModalRef
public bsModalRef: BsModalRef,
private cd: ChangeDetectorRef
) {
super(injector);
}
@ -55,6 +57,7 @@ export class CreateUserDialogComponent extends AppComponentBase
this._userService.getRoles().subscribe((result) => {
this.roles = result.items;
this.setInitialRolesStatus();
this.cd.detectChanges();
});
}

Просмотреть файл

@ -3,7 +3,7 @@
autocomplete="off"
#editUserModal="ngForm"
(ngSubmit)="save()"
>
>
<abp-modal-header
[title]="'EditUser' | localize"
(onCloseClick)="bsModalRef.hide()"
@ -26,124 +26,124 @@
[(ngModel)]="user.name"
#nameModel="ngModel"
#nameEl
/>
<abp-validation-summary
[control]="nameModel"
[controlEl]="nameEl"
></abp-validation-summary>
</div>
</div>
<div class="form-group row required">
<label class="col-md-3 col-form-label" for="surname">
{{ "Surname" | localize }}
</label>
<div class="col-md-9">
<input
type="text"
class="form-control"
name="surname"
id="surname"
required
maxlength="32"
[(ngModel)]="user.surname"
#surnameModel="ngModel"
#surnameEl
/>
<abp-validation-summary
[control]="surnameModel"
[controlEl]="surnameEl"
></abp-validation-summary>
</div>
</div>
<div class="form-group row required">
<label class="col-md-3 col-form-label" for="userName">
{{ "UserName" | localize }}
</label>
<div class="col-md-9">
<input
type="text"
class="form-control"
name="userName"
id="userName"
required
minlength="2"
maxlength="32"
[(ngModel)]="user.userName"
#userNameModel="ngModel"
#userNameEl
/>
<abp-validation-summary
[control]="userNameModel"
[controlEl]="userNameEl"
></abp-validation-summary>
</div>
</div>
<div class="form-group row required">
<label class="col-md-3 col-form-label" for="emailAddress">
{{ "EmailAddress" | localize }}
</label>
<div class="col-md-9">
<input
type="email"
class="form-control"
name="emailAddress"
id="emailAddress"
required
maxlength="256"
pattern="^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{1,})+$"
[(ngModel)]="user.emailAddress"
#emailAddressModel="ngModel"
#emailAddressEl
/>
<abp-validation-summary
[control]="emailAddressModel"
[controlEl]="emailAddressEl"
></abp-validation-summary>
</div>
</div>
<div class="form-group row mb-0">
<label class="col-md-3 col-form-label">
{{ "IsActive" | localize }}
</label>
<div class="col-md-9">
<div class="custom-control custom-checkbox">
<input
type="checkbox"
class="custom-control-input"
name="isActive"
id="isActive"
[(ngModel)]="user.isActive"
/>
<label class="custom-control-label mt-2" for="isActive"></label>
<abp-validation-summary
[control]="nameModel"
[controlEl]="nameEl"
></abp-validation-summary>
</div>
</div>
</div>
</tab>
<tab [heading]="'UserRoles' | localize" class="pt-3 px-2">
<div class="form-group row mb-0">
<ng-container *ngFor="let role of roles; let i = index">
<div class="col-md-6">
<div class="custom-control custom-checkbox">
<input
type="checkbox"
class="custom-control-input"
[id]="'role_' + i"
[checked]="isRoleChecked(role.normalizedName)"
(change)="onRoleChange(role, $event)"
<div class="form-group row required">
<label class="col-md-3 col-form-label" for="surname">
{{ "Surname" | localize }}
</label>
<div class="col-md-9">
<input
type="text"
class="form-control"
name="surname"
id="surname"
required
maxlength="32"
[(ngModel)]="user.surname"
#surnameModel="ngModel"
#surnameEl
/>
<label class="custom-control-label" [for]="'role_' + i">
{{ role.name }}
</label>
<abp-validation-summary
[control]="surnameModel"
[controlEl]="surnameEl"
></abp-validation-summary>
</div>
</div>
</ng-container>
</div>
</tab>
</tabset>
</div>
<abp-modal-footer
[cancelDisabled]="saving"
[saveDisabled]="!editUserModal.form.valid || saving"
(onCancelClick)="bsModalRef.hide()"
></abp-modal-footer>
</form>
<div class="form-group row required">
<label class="col-md-3 col-form-label" for="userName">
{{ "UserName" | localize }}
</label>
<div class="col-md-9">
<input
type="text"
class="form-control"
name="userName"
id="userName"
required
minlength="2"
maxlength="32"
[(ngModel)]="user.userName"
#userNameModel="ngModel"
#userNameEl
/>
<abp-validation-summary
[control]="userNameModel"
[controlEl]="userNameEl"
></abp-validation-summary>
</div>
</div>
<div class="form-group row required">
<label class="col-md-3 col-form-label" for="emailAddress">
{{ "EmailAddress" | localize }}
</label>
<div class="col-md-9">
<input
type="email"
class="form-control"
name="emailAddress"
id="emailAddress"
required
maxlength="256"
pattern="^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{1,})+$"
[(ngModel)]="user.emailAddress"
#emailAddressModel="ngModel"
#emailAddressEl
/>
<abp-validation-summary
[control]="emailAddressModel"
[controlEl]="emailAddressEl"
></abp-validation-summary>
</div>
</div>
<div class="form-group row mb-0">
<label class="col-md-3 col-form-label">
{{ "IsActive" | localize }}
</label>
<div class="col-md-9">
<div class="custom-control custom-checkbox">
<input
type="checkbox"
class="custom-control-input"
name="isActive"
id="isActive"
[(ngModel)]="user.isActive"
/>
<label class="custom-control-label mt-2" for="isActive"></label>
</div>
</div>
</div>
</tab>
<tab [heading]="'UserRoles' | localize" class="pt-3 px-2">
<div class="form-group row mb-0">
@for (role of roles; track role; let i = $index) {
<div class="col-md-6">
<div class="custom-control custom-checkbox">
<input
type="checkbox"
class="custom-control-input"
[id]="'role_' + i"
[checked]="isRoleChecked(role.normalizedName)"
(change)="onRoleChange(role, $event)"
/>
<label class="custom-control-label" [for]="'role_' + i">
{{ role.name }}
</label>
</div>
</div>
}
</div>
</tab>
</tabset>
</div>
<abp-modal-footer
[cancelDisabled]="saving"
[saveDisabled]="!editUserModal.form.valid || saving"
(onCancelClick)="bsModalRef.hide()"
></abp-modal-footer>
</form>

Просмотреть файл

@ -3,7 +3,8 @@ import {
Injector,
OnInit,
EventEmitter,
Output
Output,
ChangeDetectorRef
} from '@angular/core';
import { BsModalRef } from 'ngx-bootstrap/modal';
import { forEach as _forEach, includes as _includes, map as _map } from 'lodash-es';
@ -30,7 +31,8 @@ export class EditUserDialogComponent extends AppComponentBase
constructor(
injector: Injector,
public _userService: UserServiceProxy,
public bsModalRef: BsModalRef
public bsModalRef: BsModalRef,
private cd: ChangeDetectorRef
) {
super(injector);
}
@ -42,6 +44,7 @@ export class EditUserDialogComponent extends AppComponentBase
this._userService.getRoles().subscribe((result2) => {
this.roles = result2.items;
this.setInitialRolesStatus();
this.cd.detectChanges();
});
});
}

Просмотреть файл

@ -1,234 +1,238 @@
<div [@routerTransition]>
<section class="content-header">
<div class="container-fluid">
<div class="row">
<div class="col-6">
<h1>{{ "Users" | localize }}</h1>
</div>
<div class="col-6 text-right">
<a href="javascript:;" class="btn bg-blue" (click)="createUser()">
<i class="fa fa-plus-square"></i>
{{ "Create" | localize }}
</a>
</div>
</div>
<section class="content-header">
<div class="container-fluid">
<div class="row">
<div class="col-6">
<h1>{{ "Users" | localize }}</h1>
</div>
</section>
<section class="content px-2">
<div class="container-fluid">
<div class="card">
<div class="card-header">
<div class="col-6 text-right">
<a href="javascript:;" class="btn bg-blue" (click)="createUser()">
<i class="fa fa-plus-square"></i>
{{ "Create" | localize }}
</a>
</div>
</div>
</div>
</section>
<section class="content px-2">
<div class="container-fluid">
<div class="card">
<div class="card-header">
<div class="row">
<div class="col-md-6">&emsp;</div>
<div class="col-md-6">
<div class="input-group">
<div class="input-group-prepend">
<button
type="button"
class="btn bg-blue"
(click)="getDataPage(1)"
>
<i class="fas fa-search"></i>
</button>
</div>
<input
type="text"
class="form-control"
name="keyword"
[placeholder]="'SearchWithThreeDot' | localize"
[(ngModel)]="keyword"
(keyup.enter)="getDataPage(1)"
/>
<div class="input-group-append">
<button
type="button"
class="btn btn-default"
(click)="advancedFiltersVisible = !advancedFiltersVisible"
>
<i
class="fas"
[class.fa-angle-up]="advancedFiltersVisible"
[class.fa-angle-down]="!advancedFiltersVisible"
></i>
</button>
</div>
</div>
</div>
</div>
@if (advancedFiltersVisible) {
<div class="card mb-0 mt-1">
<div class="card-body">
<form class="form-horizontal">
<div class="row">
<div class="col-md-6">&emsp;</div>
<div class="col-md-6">
<div class="input-group">
<div class="input-group-prepend">
<button
type="button"
class="btn bg-blue"
(click)="getDataPage(1)"
>
<i class="fas fa-search"></i>
</button>
</div>
<input
type="text"
class="form-control"
name="keyword"
[placeholder]="'SearchWithThreeDot' | localize"
[(ngModel)]="keyword"
(keyup.enter)="getDataPage(1)"
<div class="col-md-6">
<div class="form-group row mb-0">
<label class="col-md-3 col-form-label">
{{ "IsActive" | localize }}
</label>
<div class="col-md-9 pt-2">
<div class="custom-control custom-radio d-inline">
<input
type="radio"
class="custom-control-input"
id="isActiveAll"
name="isActive"
[(ngModel)]="isActive"
[value]="undefined"
checked
/>
<div class="input-group-append">
<button
type="button"
class="btn btn-default"
(click)="advancedFiltersVisible = !advancedFiltersVisible"
<label class="custom-control-label" for="isActiveAll">
{{ "All" | localize }}
</label>
</div>
<div class="custom-control custom-radio d-inline mx-3">
<input
type="radio"
class="custom-control-input"
id="isActiveActive"
name="isActive"
[(ngModel)]="isActive"
[value]="true"
/>
<label
class="custom-control-label"
for="isActiveActive"
>
<i
class="fas"
[class.fa-angle-up]="advancedFiltersVisible"
[class.fa-angle-down]="!advancedFiltersVisible"
></i>
</button>
{{ "Yes" | localize }}
</label>
</div>
<div class="custom-control custom-radio d-inline">
<input
type="radio"
class="custom-control-input"
id="isActivePassive"
name="isActive"
[(ngModel)]="isActive"
[value]="false"
/>
<label
class="custom-control-label"
for="isActivePassive"
>
{{ "No" | localize }}
</label>
</div>
</div>
</div>
</div>
</div>
</div>
<div *ngIf="advancedFiltersVisible" class="card mb-0 mt-1">
<div class="card-body">
<form class="form-horizontal">
<div class="row">
<div class="col-md-6">
<div class="form-group row mb-0">
<label class="col-md-3 col-form-label">
{{ "IsActive" | localize }}
</label>
<div class="col-md-9 pt-2">
<div class="custom-control custom-radio d-inline">
<input
type="radio"
class="custom-control-input"
id="isActiveAll"
name="isActive"
[(ngModel)]="isActive"
[value]="undefined"
checked
/>
<label class="custom-control-label" for="isActiveAll">
{{ "All" | localize }}
</label>
</div>
<div class="custom-control custom-radio d-inline mx-3">
<input
type="radio"
class="custom-control-input"
id="isActiveActive"
name="isActive"
[(ngModel)]="isActive"
[value]="true"
/>
<label
class="custom-control-label"
for="isActiveActive"
>
{{ "Yes" | localize }}
</label>
</div>
<div class="custom-control custom-radio d-inline">
<input
type="radio"
class="custom-control-input"
id="isActivePassive"
name="isActive"
[(ngModel)]="isActive"
[value]="false"
/>
<label
class="custom-control-label"
for="isActivePassive"
>
{{ "No" | localize }}
</label>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
<div class="card-footer">
<button
type="button"
class="btn bg-blue"
(click)="getDataPage(1)"
>
{{ "Search" | localize }}
</button>
<button
type="button"
class="btn btn-default float-right"
(click)="clearFilters()"
>
{{ "Clear" | localize }}
</button>
</div>
</div>
</form>
</div>
<div class="card-footer">
<button
type="button"
class="btn bg-blue"
(click)="getDataPage(1)"
>
{{ "Search" | localize }}
</button>
<button
type="button"
class="btn btn-default float-right"
(click)="clearFilters()"
>
{{ "Clear" | localize }}
</button>
</div>
</div>
}
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-striped table-bordered" [busy]="isTableLoading">
<thead class="bg-light">
<tr>
<th>{{ "UserName" | localize }}</th>
<th>{{ "FullName" | localize }}</th>
<th>{{ "EmailAddress" | localize }}</th>
<th>{{ "IsActive" | localize }}</th>
<th style="width: 310px;">{{ "Actions" | localize }}</th>
</tr>
</thead>
<tbody>
<tr
*ngFor="
let user of users
| paginate
: {
<div class="table-responsive">
<table class="table table-striped table-bordered" [busy]="isTableLoading">
<thead class="bg-light">
<tr>
<th>{{ "UserName" | localize }}</th>
<th>{{ "FullName" | localize }}</th>
<th>{{ "EmailAddress" | localize }}</th>
<th>{{ "IsActive" | localize }}</th>
<th style="width: 310px;">{{ "Actions" | localize }}</th>
</tr>
</thead>
<tbody>
@for (
user of users
| paginate
: {
id: 'server',
itemsPerPage: pageSize,
currentPage: pageNumber,
totalItems: totalItems
}
"
>
<td>{{ user.userName }}</td>
<td>{{ user.fullName }}</td>
<td>{{ user.emailAddress }}</td>
<td>
<div class="custom-control custom-checkbox">
<input
type="checkbox"
class="custom-control-input"
disabled
[checked]="user.isActive"
/>
<label class="custom-control-label"></label>
</div>
</td>
<td>
<button
type="button"
class="btn btn-sm bg-secondary"
(click)="editUser(user)"
>
<i class="fas fa-pencil-alt"></i>
{{ "Edit" | localize }}
</button>
<button
type="button"
class="btn btn-sm bg-danger mx-2"
(click)="delete(user)"
>
<i class="fas fa-trash"></i>
{{ "Delete" | localize }}
</button>
<button
type="button"
class="btn btn-sm bg-secondary"
(click)="resetPassword(user)"
>
<i class="fas fa-lock"></i>
{{ "ResetPassword" | localize }}
</button>
</td>
</tr>
</tbody>
</table>
</div>
; track
user.id) {
<tr
>
<td>{{ user.userName }}</td>
<td>{{ user.fullName }}</td>
<td>{{ user.emailAddress }}</td>
<td>
<div class="custom-control custom-checkbox">
<input
type="checkbox"
class="custom-control-input"
disabled
[checked]="user.isActive"
/>
<label class="custom-control-label"></label>
</div>
</td>
<td>
<button
type="button"
class="btn btn-sm bg-secondary"
(click)="editUser(user)"
>
<i class="fas fa-pencil-alt"></i>
{{ "Edit" | localize }}
</button>
<button
type="button"
class="btn btn-sm bg-danger mx-2"
(click)="delete(user)"
>
<i class="fas fa-trash"></i>
{{ "Delete" | localize }}
</button>
<button
type="button"
class="btn btn-sm bg-secondary"
(click)="resetPassword(user)"
>
<i class="fas fa-lock"></i>
{{ "ResetPassword" | localize }}
</button>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
<div class="card-footer table-card-footer bg-light border-top">
<div class="row">
<div class="col-sm-4 col-12 text-sm-left text-center">
<button class="btn btn-secondary" (click)="refresh()">
<i class="fas fa-redo-alt"></i>
</button>
</div>
<div class="col-sm-4 col-12 text-center">
<p class="mb-0 my-2">
{{ "TotalRecordsCount" | localize: totalItems }}
</p>
</div>
<div class="col-sm-4 col-12">
<div class="float-sm-right m-auto">
<abp-pagination-controls
id="server"
(pageChange)="getDataPage($event)"
>
</abp-pagination-controls>
</div>
</div>
<div class="row">
<div class="col-sm-4 col-12 text-sm-left text-center">
<button class="btn btn-secondary" (click)="refresh()">
<i class="fas fa-redo-alt"></i>
</button>
</div>
<div class="col-sm-4 col-12 text-center">
<p class="mb-0 my-2">
{{ "TotalRecordsCount" | localize: totalItems }}
</p>
</div>
<div class="col-sm-4 col-12">
<div class="float-sm-right m-auto">
<abp-pagination-controls
id="server"
(pageChange)="getDataPage($event)"
>
</abp-pagination-controls>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
</section>
</div>

Просмотреть файл

@ -1,4 +1,4 @@
import { Component, Injector } from '@angular/core';
import { ChangeDetectorRef, Component, Injector } from '@angular/core';
import { finalize } from 'rxjs/operators';
import { BsModalService, BsModalRef } from 'ngx-bootstrap/modal';
import { appModuleAnimation } from '@shared/animations/routerTransition';
@ -33,9 +33,10 @@ export class UsersComponent extends PagedListingComponentBase<UserDto> {
constructor(
injector: Injector,
private _userService: UserServiceProxy,
private _modalService: BsModalService
private _modalService: BsModalService,
cd: ChangeDetectorRef
) {
super(injector);
super(injector, cd);
}
createUser(): void {

Просмотреть файл

@ -12,7 +12,7 @@ if (environment.production) {
}
const bootstrap = () => {
return platformBrowserDynamic().bootstrapModule(RootModule);
return platformBrowserDynamic().bootstrapModule(RootModule, {ngZone: 'noop'});
};
/* "Hot Module Replacement" is enabled as described on

Просмотреть файл

@ -16,4 +16,3 @@ import 'core-js/es/string';
import 'core-js/es/symbol';
import 'core-js/es/reflect';
import { finalize } from 'rxjs/operators';
import 'zone.js';

Просмотреть файл

@ -1,5 +1,5 @@
import { NgModule, APP_INITIALIZER, LOCALE_ID } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, APP_INITIALIZER, LOCALE_ID,provideExperimentalZonelessChangeDetection} from '@angular/core';
import { BrowserModule, provideClientHydration } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
@ -43,6 +43,8 @@ export function getCurrentLanguage(): string {
],
declarations: [RootComponent],
providers: [
provideExperimentalZonelessChangeDetection(),
provideClientHydration(),
{ provide: HTTP_INTERCEPTORS, useClass: AbpHttpInterceptor, multi: true },
{
provide: APP_INITIALIZER,

Просмотреть файл

@ -2,12 +2,12 @@
<button
type="button"
class="btn btn-default"
[disabled]="cancelDisabled"
(click)="onCancelClick.emit()"
[disabled]="cancelDisabled()"
(click)="onCancelClick.emit($event)"
>
{{ cancelLabel }}
{{ cancelLabel() }}
</button>
<button type="submit" class="btn btn-primary" [disabled]="saveDisabled">
{{ saveLabel }}
<button type="submit" class="btn btn-primary" [disabled]="saveDisabled()">
{{ saveLabel() }}
</button>
</div>

Просмотреть файл

@ -1,7 +1,7 @@
import {
Component,
Input,
Output,
input,
output,
EventEmitter,
ChangeDetectionStrategy,
Injector
@ -14,12 +14,12 @@ import { AppComponentBase } from '@shared/app-component-base';
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AbpModalFooterComponent extends AppComponentBase {
@Input() cancelLabel = this.l('Cancel');
@Input() cancelDisabled: boolean;
@Input() saveLabel = this.l('Save');
@Input() saveDisabled: boolean;
cancelLabel = input(this.l('Cancel'));
cancelDisabled= input<boolean>();
saveLabel = input(this.l('Save'));
saveDisabled = input<boolean>();
@Output() onCancelClick = new EventEmitter<number>();
onCancelClick = output<EventEmitter<number>>();
constructor(injector: Injector) {
super(injector);

Просмотреть файл

@ -1,10 +1,10 @@
<div class="modal-header">
<h4 class="modal-title">{{ title }}</h4>
<h4 class="modal-title">{{ title() }}</h4>
<button
type="button"
class="close"
aria-label="Close"
(click)="onCloseClick.emit()"
(click)="onCloseClick.emit($event)"
>
<span aria-hidden="true">&times;</span>
</button>

Просмотреть файл

@ -1,7 +1,7 @@
import {
Component,
Input,
Output,
input,
output,
EventEmitter,
ChangeDetectionStrategy,
Injector
@ -14,9 +14,9 @@ import { AppComponentBase } from '@shared/app-component-base';
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AbpModalHeaderComponent extends AppComponentBase {
@Input() title: string;
title = input<string>();
@Output() onCloseClick = new EventEmitter<number>();
onCloseClick = output<EventEmitter<number>>();
constructor(injector: Injector) {
super(injector);

Просмотреть файл

@ -3,57 +3,68 @@
[id]="id"
[maxSize]="maxSize"
(pageChange)="pageChange.emit($event)"
>
>
<nav>
<ul *ngIf="!(autoHide && p.pages.length <= 1)" class="pagination m-0">
<li
*ngIf="directionLinks"
class="page-item"
[class.disabled]="p.isFirstPage()"
>
<a
*ngIf="!p.isFirstPage()"
class="page-link"
href="javascript:;"
(click)="p.previous()"
>
<i class="fas fa-chevron-left"></i>
</a>
<a *ngIf="p.isFirstPage()" class="page-link" href="javascript:;">
<i class="fas fa-chevron-left"></i>
</a>
</li>
<li
*ngFor="let page of p.pages"
class="page-item"
[class.active]="p.getCurrent() === page.value"
[style.z-index]="p.getCurrent() === page.value ? '0' : ''"
>
<a
class="page-link"
href="javascript:;"
(click)="p.setCurrent(page.value)"
>
{{ page.label }}
</a>
</li>
<li
*ngIf="directionLinks"
class="page-item"
[class.disabled]="p.isLastPage()"
>
<a
*ngIf="!p.isLastPage()"
class="page-link"
href="javascript:;"
(click)="p.next()"
>
<i class="fas fa-chevron-right"></i>
</a>
<a *ngIf="p.isLastPage()" class="page-link" href="javascript:;">
<i class="fas fa-chevron-right"></i>
</a>
</li>
</ul>
@if (!(autoHide && p.pages.length <= 1)) {
<ul class="pagination m-0">
@if (directionLinks) {
<li
class="page-item"
[class.disabled]="p.isFirstPage()"
>
@if (!p.isFirstPage()) {
<a
class="page-link"
href="javascript:;"
(click)="p.previous()"
>
<i class="fas fa-chevron-left"></i>
</a>
}
@if (p.isFirstPage()) {
<a class="page-link" href="javascript:;">
<i class="fas fa-chevron-left"></i>
</a>
}
</li>
}
@for (page of p.pages; track page.label) {
<li
class="page-item"
[class.active]="p.getCurrent() === page.value"
[style.z-index]="p.getCurrent() === page.value ? '0' : ''"
>
<a
class="page-link"
href="javascript:;"
(click)="p.setCurrent(page.value)"
>
{{ page.label }}
</a>
</li>
}
@if (directionLinks) {
<li
class="page-item"
[class.disabled]="p.isLastPage()"
>
@if (!p.isLastPage()) {
<a
class="page-link"
href="javascript:;"
(click)="p.next()"
>
<i class="fas fa-chevron-right"></i>
</a>
}
@if (p.isLastPage()) {
<a class="page-link" href="javascript:;">
<i class="fas fa-chevron-right"></i>
</a>
}
</li>
}
</ul>
}
</nav>
</pagination-template>

Просмотреть файл

@ -5,7 +5,6 @@ import { Component, Input, Output, EventEmitter } from '@angular/core';
templateUrl: './abp-pagination-controls.component.html'
})
export class AbpPaginationControlsComponent {
@Input() id: string;
@Input() maxSize = 7;
@Input() previousLabel = 'Previous';
@ -13,7 +12,7 @@ export class AbpPaginationControlsComponent {
@Input() screenReaderPaginationLabel = 'Pagination';
@Input() screenReaderPageLabel = 'page';
@Input() screenReaderCurrentLabel = `You're on page`;
@Output() pageChange: EventEmitter<number> = new EventEmitter<number>();
@Output() pageChange = new EventEmitter<number>();
private _directionLinks = true;
private _autoHide = false;
@ -25,6 +24,7 @@ export class AbpPaginationControlsComponent {
set directionLinks(value: boolean) {
this._directionLinks = !!value && <any>value !== 'false';
}
@Input()
get autoHide(): boolean {
return this._autoHide;

Просмотреть файл

@ -1,11 +1,12 @@
<ng-container *ngIf="control.invalid && (control.dirty || control.touched)">
<ng-container *ngFor="let validationError of validationErrors">
<span
*ngIf="!!this.control.errors[validationError.name]"
class="error invalid-feedback"
[class.d-block]="!!this.control.errors[validationError.name]"
>
{{ getValidationErrorMessage(validationError) }}
</span>
</ng-container>
</ng-container>
@if (control.invalid && (control.dirty || control.touched)) {
@for (validationError of validationErrors; track validationError) {
@if (!!this.control.errors[validationError.name]) {
<span
class="error invalid-feedback"
[class.d-block]="!!this.control.errors[validationError.name]"
>
{{ getValidationErrorMessage(validationError) }}
</span>
}
}
}

Просмотреть файл

@ -4,8 +4,6 @@ export class QueryStringTenantResolver {
resolve(appBaseUrl): string {
let queryParams = UrlHelper.getQueryParameters();
console.log('queryParams');
console.log(queryParams);
return queryParams['abp_tenancy_name'];
}

Просмотреть файл

@ -1,5 +1,5 @@
import { AppComponentBase } from 'shared/app-component-base';
import { Component, Injector, OnInit } from '@angular/core';
import { Component, Injector, OnInit, ChangeDetectorRef } from '@angular/core';
export class PagedResultDto {
items: any[];
@ -25,9 +25,14 @@ export abstract class PagedListingComponentBase<TEntityDto> extends AppComponent
public totalPages = 1;
public totalItems: number;
public isTableLoading = false;
protected cd: ChangeDetectorRef;
constructor(injector: Injector) {
constructor(
injector: Injector,
cd: ChangeDetectorRef
) {
super(injector);
this.cd = cd;
}
ngOnInit(): void {
@ -53,6 +58,7 @@ export abstract class PagedListingComponentBase<TEntityDto> extends AppComponent
this.isTableLoading = true;
this.list(req, page, () => {
this.isTableLoading = false;
this.cd.detectChanges();
});
}

Просмотреть файл

@ -1,11 +1,5 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/long-stack-trace-zone';
import 'zone.js/dist/proxy.js';
import 'zone.js/dist/sync-test';
import 'zone.js/dist/jasmine-patch';
import 'zone.js/dist/async-test';
import 'zone.js/dist/fake-async-test';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,

Разница между файлами не показана из-за своего большого размера Загрузить разницу