Browse Source

Merge pull request #15750 from abpframework/fix/strict-mode-errors

Fix/strict mode errors
pull/15753/head
Mahmut Gundogdu 3 years ago
committed by GitHub
parent
commit
89b4e65927
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      npm/ng-packs/package.json
  2. 14
      npm/ng-packs/packages/account-core/src/lib/tenant-box.service.ts
  3. 19
      npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.ts
  4. 4
      npm/ng-packs/packages/account/src/lib/components/forgot-password/forgot-password.component.ts
  5. 6
      npm/ng-packs/packages/account/src/lib/components/login/login.component.ts
  6. 2
      npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.ts
  7. 4
      npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings-half-row.component.ts
  8. 6
      npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings.component.ts
  9. 14
      npm/ng-packs/packages/account/src/lib/components/register/register.component.ts
  10. 10
      npm/ng-packs/packages/account/src/lib/components/reset-password/reset-password.component.ts
  11. 10
      npm/ng-packs/packages/components/chart.js/src/chart.component.ts
  12. 2
      npm/ng-packs/packages/components/chart.js/src/widget-utils.ts
  13. 4
      npm/ng-packs/packages/components/page/src/page-part.directive.ts
  14. 2
      npm/ng-packs/packages/components/page/src/page.component.html
  15. 14
      npm/ng-packs/packages/components/page/src/page.component.ts
  16. 6
      npm/ng-packs/packages/core/locale/src/utils/register-locale.ts
  17. 2
      npm/ng-packs/packages/core/package.json
  18. 10
      npm/ng-packs/packages/core/src/lib/abstracts/ng-model.component.ts
  19. 2
      npm/ng-packs/packages/core/src/lib/clients/http.client.ts
  20. 22
      npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts
  21. 6
      npm/ng-packs/packages/core/src/lib/components/replaceable-route-container.component.ts
  22. 4
      npm/ng-packs/packages/core/src/lib/directives/debounce.directive.ts
  23. 58
      npm/ng-packs/packages/core/src/lib/directives/for.directive.ts
  24. 12
      npm/ng-packs/packages/core/src/lib/directives/form-submit.directive.ts
  25. 15
      npm/ng-packs/packages/core/src/lib/directives/replaceable-template.directive.ts
  26. 2
      npm/ng-packs/packages/core/src/lib/directives/stop-propagation.directive.ts
  27. 20
      npm/ng-packs/packages/core/src/lib/handlers/routes.handler.ts
  28. 2
      npm/ng-packs/packages/core/src/lib/interceptors/api.interceptor.ts
  29. 38
      npm/ng-packs/packages/core/src/lib/models/dtos.ts
  30. 5
      npm/ng-packs/packages/core/src/lib/models/environment.ts
  31. 2
      npm/ng-packs/packages/core/src/lib/models/session.ts
  32. 6
      npm/ng-packs/packages/core/src/lib/providers/locale.provider.ts
  33. 15
      npm/ng-packs/packages/core/src/lib/services/config-state.service.ts
  34. 11
      npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts
  35. 17
      npm/ng-packs/packages/core/src/lib/services/environment.service.ts
  36. 5
      npm/ng-packs/packages/core/src/lib/services/http-wait.service.ts
  37. 10
      npm/ng-packs/packages/core/src/lib/services/lazy-load.service.ts
  38. 22
      npm/ng-packs/packages/core/src/lib/services/localization.service.ts
  39. 2
      npm/ng-packs/packages/core/src/lib/services/multi-tenancy.service.ts
  40. 4
      npm/ng-packs/packages/core/src/lib/services/permission.service.ts
  41. 6
      npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts
  42. 2
      npm/ng-packs/packages/core/src/lib/services/resource-wait.service.ts
  43. 7
      npm/ng-packs/packages/core/src/lib/services/rest.service.ts
  44. 5
      npm/ng-packs/packages/core/src/lib/services/router-events.service.ts
  45. 12
      npm/ng-packs/packages/core/src/lib/services/routes.service.ts
  46. 2
      npm/ng-packs/packages/core/src/lib/services/session-state.service.ts
  47. 8
      npm/ng-packs/packages/core/src/lib/services/subscription.service.ts
  48. 4
      npm/ng-packs/packages/core/src/lib/strategies/content-security.strategy.ts
  49. 10
      npm/ng-packs/packages/core/src/lib/strategies/content.strategy.ts
  50. 2
      npm/ng-packs/packages/core/src/lib/strategies/context.strategy.ts
  51. 9
      npm/ng-packs/packages/core/src/lib/strategies/cross-origin.strategy.ts
  52. 6
      npm/ng-packs/packages/core/src/lib/strategies/loading.strategy.ts
  53. 4
      npm/ng-packs/packages/core/src/lib/tokens/localization.token.ts
  54. 20
      npm/ng-packs/packages/core/src/lib/utils/common-utils.ts
  55. 5
      npm/ng-packs/packages/core/src/lib/utils/date-utils.ts
  56. 10
      npm/ng-packs/packages/core/src/lib/utils/environment-utils.ts
  57. 4
      npm/ng-packs/packages/core/src/lib/utils/factory-utils.ts
  58. 3
      npm/ng-packs/packages/core/src/lib/utils/internal-store-utils.ts
  59. 12
      npm/ng-packs/packages/core/src/lib/utils/lazy-load-utils.ts
  60. 2
      npm/ng-packs/packages/core/src/lib/utils/localization-utils.ts
  61. 9
      npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts
  62. 28
      npm/ng-packs/packages/core/src/lib/utils/object-utils.ts
  63. 6
      npm/ng-packs/packages/core/src/lib/utils/route-utils.ts
  64. 6
      npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts
  65. 4
      npm/ng-packs/packages/core/src/lib/validators/range.validator.ts
  66. 2
      npm/ng-packs/packages/core/src/lib/validators/required.validator.ts
  67. 4
      npm/ng-packs/packages/core/src/lib/validators/string-length.validator.ts
  68. 2
      npm/ng-packs/packages/core/src/lib/validators/username.validator.ts
  69. 2
      npm/ng-packs/packages/core/testing/src/lib/services/mock-permission.service.ts
  70. 10
      npm/ng-packs/packages/core/testing/src/lib/services/mock-rest.service.ts
  71. 14
      npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.ts
  72. 92
      npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts
  73. 8
      npm/ng-packs/packages/identity/src/lib/defaults/default-roles-entity-actions.ts
  74. 4
      npm/ng-packs/packages/identity/src/lib/defaults/default-roles-form-props.ts
  75. 23
      npm/ng-packs/packages/identity/src/lib/defaults/default-users-entity-actions.ts
  76. 2
      npm/ng-packs/packages/identity/src/lib/defaults/default-users-form-props.ts
  77. 6
      npm/ng-packs/packages/oauth/src/lib/handlers/oauth-configuration.handler.ts
  78. 4
      npm/ng-packs/packages/oauth/src/lib/interceptors/api.interceptor.ts
  79. 4
      npm/ng-packs/packages/oauth/src/lib/oauth.module.ts
  80. 6
      npm/ng-packs/packages/oauth/src/lib/services/oauth.service.ts
  81. 18
      npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts
  82. 2
      npm/ng-packs/packages/oauth/src/lib/utils/auth-utils.ts
  83. 38
      npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts
  84. 14
      npm/ng-packs/packages/theme-shared/extensions/src/lib/adapters/date-time.adapter.ts
  85. 8
      npm/ng-packs/packages/theme-shared/extensions/src/lib/components/abstract-actions/abstract-actions.component.ts
  86. 6
      npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form-prop.component.ts
  87. 2
      npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form.component.ts
  88. 24
      npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-table/extensible-table.component.ts
  89. 2
      npm/ng-packs/packages/theme-shared/extensions/src/lib/components/grid-actions/grid-actions.component.ts
  90. 20
      npm/ng-packs/packages/theme-shared/extensions/src/lib/components/page-toolbar/page-toolbar.component.html
  91. 8
      npm/ng-packs/packages/theme-shared/extensions/src/lib/components/page-toolbar/page-toolbar.component.ts
  92. 17
      npm/ng-packs/packages/theme-shared/extensions/src/lib/models/actions.ts
  93. 2
      npm/ng-packs/packages/theme-shared/extensions/src/lib/models/entity-actions.ts
  94. 26
      npm/ng-packs/packages/theme-shared/extensions/src/lib/models/entity-props.ts
  95. 12
      npm/ng-packs/packages/theme-shared/extensions/src/lib/models/form-props.ts
  96. 2
      npm/ng-packs/packages/theme-shared/extensions/src/lib/models/internal/object-extensions.ts
  97. 9
      npm/ng-packs/packages/theme-shared/extensions/src/lib/models/props.ts
  98. 7
      npm/ng-packs/packages/theme-shared/extensions/src/lib/models/toolbar-actions.ts
  99. 2
      npm/ng-packs/packages/theme-shared/extensions/src/lib/pipes/create-injector.pipe.ts
  100. 4
      npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/actions.util.ts

2
npm/ng-packs/package.json

@ -106,7 +106,7 @@
"jest-preset-angular": "^12.2.2", "jest-preset-angular": "^12.2.2",
"jsonc-parser": "^2.3.0", "jsonc-parser": "^2.3.0",
"just-clone": "^6.1.1", "just-clone": "^6.1.1",
"just-compare": "^1.4.0", "just-compare": "^2.3.0",
"lerna": "^4.0.0", "lerna": "^4.0.0",
"lint-staged": "^13.0.3", "lint-staged": "^13.0.3",
"ng-packagr": "15.0.1", "ng-packagr": "15.0.1",

14
npm/ng-packs/packages/account-core/src/lib/tenant-box.service.ts

@ -12,22 +12,22 @@ import { finalize } from 'rxjs/operators';
export class TenantBoxService { export class TenantBoxService {
currentTenant$ = this.sessionState.getTenant$(); currentTenant$ = this.sessionState.getTenant$();
name: string; name?: string;
isModalVisible: boolean; isModalVisible!: boolean;
modalBusy: boolean; modalBusy!: boolean;
constructor( constructor(
private toasterService: ToasterService, private toasterService: ToasterService,
private tenantService: AbpTenantService, private tenantService: AbpTenantService,
private sessionState: SessionStateService, private sessionState: SessionStateService,
private configState: ConfigStateService, private configState: ConfigStateService,
) { } ) {}
onSwitch() { onSwitch() {
const tenant = this.sessionState.getTenant(); const tenant = this.sessionState.getTenant();
this.name = tenant?.name; this.name = tenant?.name || '';
this.isModalVisible = true; this.isModalVisible = true;
} }
@ -53,14 +53,14 @@ export class TenantBoxService {
}); });
} }
private setTenant(tenant: CurrentTenantDto) { private setTenant(tenant: CurrentTenantDto | null) {
this.sessionState.setTenant(tenant); this.sessionState.setTenant(tenant);
this.configState.refreshAppState(); this.configState.refreshAppState();
} }
private showError() { private showError() {
this.toasterService.error('AbpUiMultiTenancy::GivenTenantIsNotAvailable', 'AbpUi::Error', { this.toasterService.error('AbpUiMultiTenancy::GivenTenantIsNotAvailable', 'AbpUi::Error', {
messageLocalizationParams: [this.name], messageLocalizationParams: [this.name || ''],
}); });
} }
} }

19
npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.ts

@ -1,7 +1,12 @@
import { ProfileService } from '@abp/ng.account.core/proxy'; import { ProfileService } from '@abp/ng.account.core/proxy';
import { getPasswordValidators, ToasterService } from '@abp/ng.theme.shared'; import { getPasswordValidators, ToasterService } from '@abp/ng.theme.shared';
import { Component, Injector, OnInit } from '@angular/core'; import { Component, Injector, OnInit } from '@angular/core';
import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import {
UntypedFormBuilder,
UntypedFormControl,
UntypedFormGroup,
Validators,
} from '@angular/forms';
import { comparePasswords, Validation } from '@ngx-validate/core'; import { comparePasswords, Validation } from '@ngx-validate/core';
import { finalize } from 'rxjs/operators'; import { finalize } from 'rxjs/operators';
import { Account } from '../../models/account'; import { Account } from '../../models/account';
@ -19,14 +24,14 @@ const PASSWORD_FIELDS = ['newPassword', 'repeatNewPassword'];
export class ChangePasswordComponent export class ChangePasswordComponent
implements OnInit, Account.ChangePasswordComponentInputs, Account.ChangePasswordComponentOutputs implements OnInit, Account.ChangePasswordComponentInputs, Account.ChangePasswordComponentOutputs
{ {
form: UntypedFormGroup; form!: UntypedFormGroup;
inProgress: boolean; inProgress?: boolean;
hideCurrentPassword: boolean; hideCurrentPassword?: boolean;
mapErrorsFn: Validation.MapErrorsFn = (errors, groupErrors, control) => { mapErrorsFn: Validation.MapErrorsFn = (errors, groupErrors, control) => {
if (PASSWORD_FIELDS.indexOf(String(control.name)) < 0) return errors; if (PASSWORD_FIELDS.indexOf(String(control?.name)) < 0) return errors;
return errors.concat(groupErrors.filter(({ key }) => key === 'passwordMismatch')); return errors.concat(groupErrors.filter(({ key }) => key === 'passwordMismatch'));
}; };
@ -73,8 +78,8 @@ export class ChangePasswordComponent
this.inProgress = true; this.inProgress = true;
this.profileService this.profileService
.changePassword({ .changePassword({
...(!this.hideCurrentPassword && { currentPassword: this.form.get('password').value }), ...(!this.hideCurrentPassword && { currentPassword: this.form.get('password')?.value }),
newPassword: this.form.get('newPassword').value, newPassword: this.form.get('newPassword')?.value,
}) })
.pipe(finalize(() => (this.inProgress = false))) .pipe(finalize(() => (this.inProgress = false)))
.subscribe({ .subscribe({

4
npm/ng-packs/packages/account/src/lib/components/forgot-password/forgot-password.component.ts

@ -10,7 +10,7 @@ import { finalize } from 'rxjs/operators';
export class ForgotPasswordComponent { export class ForgotPasswordComponent {
form: UntypedFormGroup; form: UntypedFormGroup;
inProgress: boolean; inProgress?: boolean;
isEmailSent = false; isEmailSent = false;
@ -27,7 +27,7 @@ export class ForgotPasswordComponent {
this.accountService this.accountService
.sendPasswordResetCode({ .sendPasswordResetCode({
email: this.form.get('email').value, email: this.form.get('email')?.value,
appName: 'Angular', appName: 'Angular',
}) })
.pipe(finalize(() => (this.inProgress = false))) .pipe(finalize(() => (this.inProgress = false)))

6
npm/ng-packs/packages/account/src/lib/components/login/login.component.ts

@ -14,9 +14,9 @@ const { maxLength, required } = Validators;
templateUrl: './login.component.html', templateUrl: './login.component.html',
}) })
export class LoginComponent implements OnInit { export class LoginComponent implements OnInit {
form: UntypedFormGroup; form!: UntypedFormGroup;
inProgress: boolean; inProgress?: boolean;
isSelfRegistrationEnabled = true; isSelfRegistrationEnabled = true;
@ -67,7 +67,7 @@ export class LoginComponent implements OnInit {
err.error?.error_description || err.error?.error_description ||
err.error?.error.message || err.error?.error.message ||
'AbpAccount::DefaultErrorMessage', 'AbpAccount::DefaultErrorMessage',
null, '',
{ life: 7000 }, { life: 7000 },
); );
return throwError(err); return throwError(err);

2
npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.ts

@ -26,7 +26,7 @@ export class ManageProfileComponent implements OnInit {
profile$ = this.manageProfileState.getProfile$(); profile$ = this.manageProfileState.getProfile$();
hideChangePasswordTab: boolean; hideChangePasswordTab?: boolean;
constructor( constructor(
protected profileService: ProfileService, protected profileService: ProfileService,

4
npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings-half-row.component.ts

@ -27,11 +27,11 @@ export class PersonalSettingsHalfRowComponent {
public displayName: string; public displayName: string;
public name: string; public name: string;
public id: string; public id: string;
public formGroup: UntypedFormGroup; public formGroup!: UntypedFormGroup;
constructor(@Inject(EXTENSIONS_FORM_PROP) private propData: FormProp) { constructor(@Inject(EXTENSIONS_FORM_PROP) private propData: FormProp) {
this.displayName = propData.displayName; this.displayName = propData.displayName;
this.name = propData.name; this.name = propData.name;
this.id = propData.id; this.id = propData.id || '';
} }
} }

6
npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings.component.ts

@ -31,11 +31,11 @@ export class PersonalSettingsComponent
Account.PersonalSettingsComponentInputs, Account.PersonalSettingsComponentInputs,
Account.PersonalSettingsComponentOutputs Account.PersonalSettingsComponentOutputs
{ {
selected: ProfileDto; selected?: ProfileDto;
form: UntypedFormGroup; form!: UntypedFormGroup;
inProgress: boolean; inProgress?: boolean;
constructor( constructor(
private fb: UntypedFormBuilder, private fb: UntypedFormBuilder,

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

@ -15,9 +15,9 @@ const { maxLength, required, email } = Validators;
templateUrl: './register.component.html', templateUrl: './register.component.html',
}) })
export class RegisterComponent implements OnInit { export class RegisterComponent implements OnInit {
form: UntypedFormGroup; form!: UntypedFormGroup;
inProgress: boolean; inProgress?: boolean;
isSelfRegistrationEnabled = true; isSelfRegistrationEnabled = true;
@ -48,7 +48,7 @@ export class RegisterComponent implements OnInit {
key: 'AbpAccount::SelfRegistrationDisabledMessage', key: 'AbpAccount::SelfRegistrationDisabledMessage',
defaultValue: 'Self registration is disabled.', defaultValue: 'Self registration is disabled.',
}, },
null, '',
{ life: 10000 }, { life: 10000 },
); );
return; return;
@ -69,9 +69,9 @@ export class RegisterComponent implements OnInit {
this.inProgress = true; this.inProgress = true;
const newUser = { const newUser = {
userName: this.form.get('username').value, userName: this.form.get('username')?.value,
password: this.form.get('password').value, password: this.form.get('password')?.value,
emailAddress: this.form.get('email').value, emailAddress: this.form.get('email')?.value,
appName: 'Angular', appName: 'Angular',
} as RegisterDto; } as RegisterDto;
@ -90,7 +90,7 @@ export class RegisterComponent implements OnInit {
err.error?.error_description || err.error?.error_description ||
err.error?.error.message || err.error?.error.message ||
'AbpAccount::DefaultErrorMessage', 'AbpAccount::DefaultErrorMessage',
null, '',
{ life: 7000 }, { life: 7000 },
); );

10
npm/ng-packs/packages/account/src/lib/components/reset-password/reset-password.component.ts

@ -13,14 +13,14 @@ const PASSWORD_FIELDS = ['password', 'confirmPassword'];
templateUrl: './reset-password.component.html', templateUrl: './reset-password.component.html',
}) })
export class ResetPasswordComponent implements OnInit { export class ResetPasswordComponent implements OnInit {
form: UntypedFormGroup; form!: UntypedFormGroup;
inProgress = false; inProgress = false;
isPasswordReset = false; isPasswordReset = false;
mapErrorsFn: Validation.MapErrorsFn = (errors, groupErrors, control) => { mapErrorsFn: Validation.MapErrorsFn = (errors, groupErrors, control) => {
if (PASSWORD_FIELDS.indexOf(String(control.name)) < 0) return errors; if (PASSWORD_FIELDS.indexOf(String(control?.name)) < 0) return errors;
return errors.concat(groupErrors.filter(({ key }) => key === 'passwordMismatch')); return errors.concat(groupErrors.filter(({ key }) => key === 'passwordMismatch'));
}; };
@ -58,9 +58,9 @@ export class ResetPasswordComponent implements OnInit {
this.accountService this.accountService
.resetPassword({ .resetPassword({
userId: this.form.get('userId').value, userId: this.form.get('userId')?.value,
resetToken: this.form.get('resetToken').value, resetToken: this.form.get('resetToken')?.value,
password: this.form.get('password').value, password: this.form.get('password')?.value,
}) })
.pipe(finalize(() => (this.inProgress = false))) .pipe(finalize(() => (this.inProgress = false)))
.subscribe(() => { .subscribe(() => {

10
npm/ng-packs/packages/components/chart.js/src/chart.component.ts

@ -35,7 +35,7 @@ let Chart: any;
exportAs: 'abpChart', exportAs: 'abpChart',
}) })
export class ChartComponent implements AfterViewInit, OnDestroy, OnChanges { export class ChartComponent implements AfterViewInit, OnDestroy, OnChanges {
@Input() type: string; @Input() type!: string;
@Input() data: any = {}; @Input() data: any = {};
@ -43,9 +43,9 @@ export class ChartComponent implements AfterViewInit, OnDestroy, OnChanges {
@Input() plugins: any[] = []; @Input() plugins: any[] = [];
@Input() width: string; @Input() width?: string;
@Input() height: string; @Input() height?: string;
@Input() responsive = true; @Input() responsive = true;
@ -53,7 +53,7 @@ export class ChartComponent implements AfterViewInit, OnDestroy, OnChanges {
@Output() initialized = new EventEmitter<boolean>(); @Output() initialized = new EventEmitter<boolean>();
@ViewChild('canvas') canvas: ElementRef<HTMLCanvasElement>; @ViewChild('canvas') canvas!: ElementRef<HTMLCanvasElement>;
chart: any; chart: any;
@ -67,7 +67,7 @@ export class ChartComponent implements AfterViewInit, OnDestroy, OnChanges {
}); });
} }
onCanvasClick(event) { onCanvasClick(event: MouseEvent) {
if (this.chart) { if (this.chart) {
const element = this.chart.getElementsAtEventForMode( const element = this.chart.getElementsAtEventForMode(
event, event,

2
npm/ng-packs/packages/components/chart.js/src/widget-utils.ts

@ -1,4 +1,4 @@
export function getRandomBackgroundColor(count) { export function getRandomBackgroundColor(count: number) {
const colors = []; const colors = [];
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {

4
npm/ng-packs/packages/components/page/src/page-part.directive.ts

@ -27,8 +27,8 @@ export const PAGE_RENDER_STRATEGY = new InjectionToken<PageRenderStrategy>('PAGE
@Directive({ selector: '[abpPagePart]' }) @Directive({ selector: '[abpPagePart]' })
export class PagePartDirective implements OnInit, OnDestroy, OnChanges { export class PagePartDirective implements OnInit, OnDestroy, OnChanges {
hasRendered = false; hasRendered = false;
type: string; type!: string;
subscription: Subscription; subscription!: Subscription;
@Input('abpPagePartContext') context: any; @Input('abpPagePartContext') context: any;
@Input() set abpPagePart(type: string) { @Input() set abpPagePart(type: string) {

2
npm/ng-packs/packages/components/page/src/page.component.html

@ -25,7 +25,7 @@
</ng-template> </ng-template>
<ng-template #defaultBreadcrumbTemplate> <ng-template #defaultBreadcrumbTemplate>
<ng-container *ngIf="breadcrumbVisible"> <ng-container *ngIf="breadcrumb">
<div class="col-lg-auto ps-lg-0" *abpPagePart="pageParts.breadcrumb"> <div class="col-lg-auto ps-lg-0" *abpPagePart="pageParts.breadcrumb">
<abp-breadcrumb></abp-breadcrumb> <abp-breadcrumb></abp-breadcrumb>
</div> </div>

14
npm/ng-packs/packages/components/page/src/page.component.ts

@ -12,11 +12,11 @@ import {
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,
}) })
export class PageComponent { export class PageComponent {
@Input() title: string; @Input() title?: string;
toolbarVisible = false; toolbarVisible = false;
_toolbarData: any; _toolbarData: any;
@Input('toolbar') set toolbarData(val: any) { @Input() set toolbar(val: any) {
this._toolbarData = val; this._toolbarData = val;
this.toolbarVisible = true; this.toolbarVisible = true;
} }
@ -25,7 +25,7 @@ export class PageComponent {
return this._toolbarData; return this._toolbarData;
} }
@Input('breadcrumb') breadcrumbVisible = true; @Input() breadcrumb = true;
pageParts = { pageParts = {
title: PageParts.title, title: PageParts.title,
@ -33,16 +33,16 @@ export class PageComponent {
toolbar: PageParts.toolbar, toolbar: PageParts.toolbar,
}; };
@ContentChild(PageTitleContainerComponent) customTitle: PageTitleContainerComponent; @ContentChild(PageTitleContainerComponent) customTitle?: PageTitleContainerComponent;
@ContentChild(PageBreadcrumbContainerComponent) @ContentChild(PageBreadcrumbContainerComponent)
customBreadcrumb: PageBreadcrumbContainerComponent; customBreadcrumb?: PageBreadcrumbContainerComponent;
@ContentChild(PageToolbarContainerComponent) customToolbar: PageToolbarContainerComponent; @ContentChild(PageToolbarContainerComponent) customToolbar?: PageToolbarContainerComponent;
get shouldRenderRow() { get shouldRenderRow() {
return !!( return !!(
this.title || this.title ||
this.toolbarVisible || this.toolbarVisible ||
this.breadcrumbVisible || this.breadcrumb ||
this.customTitle || this.customTitle ||
this.customBreadcrumb || this.customBreadcrumb ||
this.customToolbar this.customToolbar

6
npm/ng-packs/packages/core/locale/src/utils/register-locale.ts

@ -8,7 +8,7 @@ export interface LocaleErrorHandlerData {
locale: string; locale: string;
} }
let localeMap = {}; let localeMap = {} as { [key: string]: string };
export interface RegisterLocaleData { export interface RegisterLocaleData {
cultureNameLocaleFileMap?: Record<string, string>; cultureNameLocaleFileMap?: Record<string, string>;
@ -51,7 +51,7 @@ export function registerLocale(
}; };
} }
const extraLocales = {}; const extraLocales = {} as { [key: string]: any };
export function storeLocaleData(data: any, localeId: string) { export function storeLocaleData(data: any, localeId: string) {
extraLocales[localeId] = data; extraLocales[localeId] = data;
} }
@ -62,7 +62,7 @@ export async function defaultLocalErrorHandlerFn({ locale, resolve }: LocaleErro
return; return;
} }
if (isDevMode) { if (isDevMode()) {
console.error( console.error(
`Cannot find the ${locale} locale file. You can check how can add new culture at https://docs.abp.io/en/abp/latest/UI/Angular/Localization#adding-a-new-culture`, `Cannot find the ${locale} locale file. You can check how can add new culture at https://docs.abp.io/en/abp/latest/UI/Angular/Localization#adding-a-new-culture`,
); );

2
npm/ng-packs/packages/core/package.json

@ -10,7 +10,7 @@
"@abp/utils": "~7.0.1", "@abp/utils": "~7.0.1",
"angular-oauth2-oidc": "^15.0.1", "angular-oauth2-oidc": "^15.0.1",
"just-clone": "^6.1.1", "just-clone": "^6.1.1",
"just-compare": "^1.4.0", "just-compare": "^2.3.0",
"ts-toolbelt": "6.15.4", "ts-toolbelt": "6.15.4",
"tslib": "^2.0.0" "tslib": "^2.0.0"
}, },

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

@ -4,16 +4,16 @@ import { ControlValueAccessor } from '@angular/forms';
// Not an abstract class on purpose. Do not change! // Not an abstract class on purpose. Do not change!
@Component({ template: '' }) @Component({ template: '' })
export class AbstractNgModelComponent<T = any, U = T> implements ControlValueAccessor { export class AbstractNgModelComponent<T = any, U = T> implements ControlValueAccessor {
protected _value: T; protected _value!: T;
protected cdRef: ChangeDetectorRef; protected cdRef: ChangeDetectorRef;
onChange: (value: T) => void; onChange?: (value: T) => void;
onTouched: () => void; onTouched?: () => void;
@Input() @Input()
disabled: boolean; disabled?: boolean;
@Input() @Input()
readonly: boolean; readonly?: boolean;
@Input() @Input()
valueFn: (value: U, previousValue?: T) => T = value => value as any as T; valueFn: (value: U, previousValue?: T) => T = value => value as any as T;

2
npm/ng-packs/packages/core/src/lib/clients/http.client.ts

@ -15,7 +15,7 @@ export class ExternalHttpClient extends HttpClient {
): Observable<any> { ): Observable<any> {
if (typeof first === 'string') { if (typeof first === 'string') {
this.#setPlaceholderContext(options); this.#setPlaceholderContext(options);
return super.request(first, url, options); return super.request(first, url || '', options);
} }
this.#setPlaceholderContext(first); this.#setPlaceholderContext(first);

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

@ -17,8 +17,8 @@ import { TreeNode } from '../utils/tree-utils';
providers: [SubscriptionService], providers: [SubscriptionService],
}) })
export class DynamicLayoutComponent { export class DynamicLayoutComponent {
layout: Type<any>; layout?: Type<any>;
layoutKey: eLayoutType; layoutKey?: eLayoutType;
// TODO: Consider a shared enum (eThemeSharedComponents) for known layouts // TODO: Consider a shared enum (eThemeSharedComponents) for known layouts
readonly layouts = new Map([ readonly layouts = new Map([
@ -29,9 +29,9 @@ export class DynamicLayoutComponent {
isLayoutVisible = true; isLayoutVisible = true;
private router: Router; private router!: Router;
private route: ActivatedRoute; private route!: ActivatedRoute;
private routes: RoutesService; private routes!: RoutesService;
constructor( constructor(
injector: Injector, injector: Injector,
@ -42,7 +42,7 @@ export class DynamicLayoutComponent {
@Optional() @SkipSelf() dynamicLayoutComponent: DynamicLayoutComponent, @Optional() @SkipSelf() dynamicLayoutComponent: DynamicLayoutComponent,
) { ) {
if (dynamicLayoutComponent) { if (dynamicLayoutComponent) {
if (isDevMode) console.warn('DynamicLayoutComponent must be used only in AppComponent.'); if (isDevMode()) console.warn('DynamicLayoutComponent must be used only in AppComponent.');
return; return;
} }
this.route = injector.get(ActivatedRoute); this.route = injector.get(ActivatedRoute);
@ -80,8 +80,10 @@ export class DynamicLayoutComponent {
if (this.layoutKey === expectedLayout) return; if (this.layoutKey === expectedLayout) return;
const key = this.layouts.get(expectedLayout); const key = this.layouts.get(expectedLayout);
this.layout = this.getComponent(key)?.component; if (key) {
this.layoutKey = expectedLayout; this.layout = this.getComponent(key)?.component;
this.layoutKey = expectedLayout;
}
if(!this.layout){ if(!this.layout){
this.showLayoutNotFoundError(expectedLayout); this.showLayoutNotFoundError(expectedLayout);
} }
@ -94,7 +96,7 @@ export class DynamicLayoutComponent {
} }
console.warn(message); console.warn(message);
} }
private listenToLanguageChange() { private listenToLanguageChange() {
this.subscription.addOne(this.localizationService.languageChange$, () => { this.subscription.addOne(this.localizationService.languageChange$, () => {
@ -103,7 +105,7 @@ export class DynamicLayoutComponent {
}); });
} }
private getComponent(key: string): ReplaceableComponents.ReplaceableComponent { private getComponent(key: string): ReplaceableComponents.ReplaceableComponent | undefined {
return this.replaceableComponents.get(key); return this.replaceableComponents.get(key);
} }
} }

6
npm/ng-packs/packages/core/src/lib/components/replaceable-route-container.component.ts

@ -13,11 +13,11 @@ import { SubscriptionService } from '../services/subscription.service';
providers: [SubscriptionService], providers: [SubscriptionService],
}) })
export class ReplaceableRouteContainerComponent implements OnInit { export class ReplaceableRouteContainerComponent implements OnInit {
defaultComponent: Type<any>; defaultComponent!: Type<any>;
componentKey: string; componentKey!: string;
externalComponent: Type<any>; externalComponent?: Type<any>;
constructor( constructor(
private route: ActivatedRoute, private route: ActivatedRoute,

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

@ -16,7 +16,9 @@ export class InputEventDebounceDirective implements OnInit {
constructor(private el: ElementRef, private subscription: SubscriptionService) {} constructor(private el: ElementRef, private subscription: SubscriptionService) {}
ngOnInit(): void { ngOnInit(): void {
const input$ = fromEvent(this.el.nativeElement, 'input').pipe(debounceTime(this.debounce)); const input$ = fromEvent<InputEvent>(this.el.nativeElement, 'input').pipe(
debounceTime(this.debounce),
);
this.subscription.addOne(input$, (event: Event) => { this.subscription.addOne(input$, (event: Event) => {
this.debounceEvent.emit(event); this.debounceEvent.emit(event);

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

@ -38,32 +38,32 @@ class RecordView {
export class ForDirective implements OnChanges { export class ForDirective implements OnChanges {
// eslint-disable-next-line @angular-eslint/no-input-rename // eslint-disable-next-line @angular-eslint/no-input-rename
@Input('abpForOf') @Input('abpForOf')
items: any[]; items!: any[];
@Input('abpForOrderBy') @Input('abpForOrderBy')
orderBy: string; orderBy?: string;
@Input('abpForOrderDir') @Input('abpForOrderDir')
orderDir: 'ASC' | 'DESC'; orderDir?: 'ASC' | 'DESC';
@Input('abpForFilterBy') @Input('abpForFilterBy')
filterBy: string; filterBy?: string;
@Input('abpForFilterVal') @Input('abpForFilterVal')
filterVal: any; filterVal: any;
@Input('abpForTrackBy') @Input('abpForTrackBy')
trackBy; trackBy?: TrackByFunction<any>;
@Input('abpForCompareBy') @Input('abpForCompareBy')
compareBy: CompareFn; compareBy?: CompareFn;
@Input('abpForEmptyRef') @Input('abpForEmptyRef')
emptyRef: TemplateRef<any>; emptyRef?: TemplateRef<any>;
private differ: IterableDiffer<any>; private differ!: IterableDiffer<any> | null;
private isShowEmptyRef: boolean; private isShowEmptyRef!: boolean;
get compareFn(): CompareFn { get compareFn(): CompareFn {
return this.compareBy || compare; return this.compareBy || compare;
@ -83,22 +83,29 @@ export class ForDirective implements OnChanges {
const rw: RecordView[] = []; const rw: RecordView[] = [];
changes.forEachOperation( changes.forEachOperation(
(record: IterableChangeRecord<any>, previousIndex: number, currentIndex: number) => { (
record: IterableChangeRecord<any>,
previousIndex: number | null,
currentIndex: number | null,
) => {
if (record.previousIndex == null) { if (record.previousIndex == null) {
const view = this.vcRef.createEmbeddedView( const view = this.vcRef.createEmbeddedView(
this.tempRef, this.tempRef,
new AbpForContext(null, -1, -1, this.items), new AbpForContext(null, -1, -1, this.items),
currentIndex, currentIndex || 0,
); );
rw.push(new RecordView(record, view)); rw.push(new RecordView(record, view));
} else if (currentIndex == null) { } else if (currentIndex == null && previousIndex !== null) {
this.vcRef.remove(previousIndex); this.vcRef.remove(previousIndex);
} else { } else {
const view = this.vcRef.get(previousIndex); if (previousIndex !== null) {
this.vcRef.move(view, currentIndex); const view = this.vcRef.get(previousIndex);
if (view && currentIndex !== null) {
rw.push(new RecordView(record, view as EmbeddedViewRef<AbpForContext>)); this.vcRef.move(view, currentIndex);
rw.push(new RecordView(record, view as EmbeddedViewRef<AbpForContext>));
}
}
} }
}, },
); );
@ -117,8 +124,10 @@ export class ForDirective implements OnChanges {
} }
changes.forEachIdentityChange((record: IterableChangeRecord<any>) => { changes.forEachIdentityChange((record: IterableChangeRecord<any>) => {
const viewRef = this.vcRef.get(record.currentIndex) as EmbeddedViewRef<AbpForContext>; if (record.currentIndex !== null) {
viewRef.context.$implicit = record.item; const viewRef = this.vcRef.get(record.currentIndex) as EmbeddedViewRef<AbpForContext>;
viewRef.context.$implicit = record.item;
}
}); });
} }
@ -152,10 +161,9 @@ export class ForDirective implements OnChanges {
} }
private sortItems(items: any[]) { private sortItems(items: any[]) {
if (this.orderBy) { const orderBy = this.orderBy;
items.sort((a, b) => if (orderBy) {
a[this.orderBy] > b[this.orderBy] ? 1 : a[this.orderBy] < b[this.orderBy] ? -1 : 0, items.sort((a, b) => (a[orderBy] > b[orderBy] ? 1 : a[orderBy] < b[orderBy] ? -1 : 0));
);
} else { } else {
items.sort(); items.sort();
} }
@ -166,13 +174,13 @@ export class ForDirective implements OnChanges {
if (!Array.isArray(items)) return; if (!Array.isArray(items)) return;
const compareFn = this.compareFn; const compareFn = this.compareFn;
const filterBy = this.filterBy;
if ( if (
typeof this.filterBy !== 'undefined' && typeof filterBy !== 'undefined' &&
typeof this.filterVal !== 'undefined' && typeof this.filterVal !== 'undefined' &&
this.filterVal !== '' this.filterVal !== ''
) { ) {
items = items.filter(item => compareFn(item[this.filterBy], this.filterVal)); items = items.filter(item => compareFn(item[filterBy], this.filterVal));
} }
switch (this.orderDir) { switch (this.orderDir) {

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

@ -8,7 +8,7 @@ import {
Output, Output,
Self, Self,
} from '@angular/core'; } from '@angular/core';
import { UntypedFormControl, UntypedFormGroup, FormGroupDirective } from '@angular/forms'; import { FormGroupDirective, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { fromEvent } from 'rxjs'; import { fromEvent } from 'rxjs';
import { debounceTime, filter } from 'rxjs/operators'; import { debounceTime, filter } from 'rxjs/operators';
import { SubscriptionService } from '../services/subscription.service'; import { SubscriptionService } from '../services/subscription.service';
@ -26,8 +26,9 @@ export class FormSubmitDirective implements OnInit {
@Input() @Input()
debounce = 200; debounce = 200;
// TODO: Remove unused input
@Input() @Input()
notValidateOnSubmit: string | boolean; notValidateOnSubmit?: string | boolean;
@Input() @Input()
markAsDirtyWhenSubmit = true; markAsDirtyWhenSubmit = true;
@ -41,11 +42,10 @@ export class FormSubmitDirective implements OnInit {
private host: ElementRef<HTMLFormElement>, private host: ElementRef<HTMLFormElement>,
private cdRef: ChangeDetectorRef, private cdRef: ChangeDetectorRef,
private subscription: SubscriptionService, private subscription: SubscriptionService,
) { } ) {}
ngOnInit() { ngOnInit() {
this.subscription.addOne(this.formGroupDirective.ngSubmit, () => { this.subscription.addOne(this.formGroupDirective.ngSubmit, () => {
if (this.markAsDirtyWhenSubmit) { if (this.markAsDirtyWhenSubmit) {
this.markAsDirty(); this.markAsDirty();
} }
@ -53,10 +53,10 @@ export class FormSubmitDirective implements OnInit {
this.executedNgSubmit = true; this.executedNgSubmit = true;
}); });
const keyup$ = fromEvent(this.host.nativeElement as HTMLElement, 'keyup').pipe( const keyup$ = fromEvent<KeyboardEvent>(this.host.nativeElement as HTMLElement, 'keyup').pipe(
debounceTime(this.debounce), debounceTime(this.debounce),
filter(event => !(event.target instanceof HTMLTextAreaElement)), filter(event => !(event.target instanceof HTMLTextAreaElement)),
filter((event: KeyboardEvent) => event && event.key === 'Enter'), filter(event => event && event.key === 'Enter'),
); );
this.subscription.addOne(keyup$, () => { this.subscription.addOne(keyup$, () => {

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

@ -1,5 +1,4 @@
import { import {
ComponentRef,
Directive, Directive,
Injector, Injector,
Input, Input,
@ -24,7 +23,7 @@ import { SubscriptionService } from '../services/subscription.service';
}) })
export class ReplaceableTemplateDirective implements OnInit, OnChanges { export class ReplaceableTemplateDirective implements OnInit, OnChanges {
@Input('abpReplaceableTemplate') @Input('abpReplaceableTemplate')
data: ReplaceableComponents.ReplaceableTemplateDirectiveInput<any, any>; data!: ReplaceableComponents.ReplaceableTemplateDirectiveInput<any, any>;
providedData = { providedData = {
inputs: {}, inputs: {},
@ -140,11 +139,15 @@ export class ReplaceableTemplateDirective implements OnInit, OnChanges {
[key]: { [key]: {
enumerable: true, enumerable: true,
configurable: true, configurable: true,
get: () => this.data.inputs[key]?.value, get: () => this.data.inputs?.[key]?.value,
...(this.data.inputs[key]?.twoWay && { ...(this.data.inputs?.[key]?.twoWay && {
set: (newValue: any) => { set: (newValue: any) => {
this.data.inputs[key].value = newValue; if (this.data.inputs?.[key]) {
this.data.outputs[`${key}Change`](newValue); this.data.inputs[key].value = newValue;
}
if (this.data.outputs?.[`${key}Change`]) {
this.data.outputs[`${key}Change`](newValue);
}
}, },
}), }),
}, },

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

@ -13,7 +13,7 @@ export class StopPropagationDirective implements OnInit {
constructor(private el: ElementRef, private subscription: SubscriptionService) {} constructor(private el: ElementRef, private subscription: SubscriptionService) {}
ngOnInit(): void { ngOnInit(): void {
this.subscription.addOne(fromEvent(this.el.nativeElement, 'click'), (event: MouseEvent) => { this.subscription.addOne(fromEvent<MouseEvent>(this.el.nativeElement, 'click'), event => {
event.stopPropagation(); event.stopPropagation();
this.stopPropEvent.emit(event); this.stopPropEvent.emit(event);
}); });

20
npm/ng-packs/packages/core/src/lib/handlers/routes.handler.ts

@ -12,16 +12,16 @@ export class RoutesHandler {
} }
addRoutes() { addRoutes() {
this.router?.config?.forEach(({ path = '', data }: RouteData) => { (this.router?.config as RouteData[])?.forEach(({ path = '', data }: RouteData) => {
if (!data?.routes) return; const routes = data?.routes;
if (!routes) return;
if (Array.isArray(data.routes)) {
this.routes.add(data.routes); if (Array.isArray(routes)) {
return; this.routes.add(routes);
} else {
const routesFlatten = flatRoutes([{ path, ...routes }], { path: '' });
this.routes.add(routesFlatten);
} }
const routes = flatRoutes([{ path, ...data.routes }], { path: '' });
this.routes.add(routes);
}); });
} }
} }
@ -39,7 +39,7 @@ function flatRoutes(routes: RouteDef[], parent: any) {
acc.push(current, ...flatRoutes(children, current)); acc.push(current, ...flatRoutes(children, current));
return acc; return acc;
}, []); }, [] as ABP.Route[]);
} }
type RouteDef = ABP.Route & { children: RouteDef[] }; type RouteDef = ABP.Route & { children: RouteDef[] };

2
npm/ng-packs/packages/core/src/lib/interceptors/api.interceptor.ts

@ -10,7 +10,7 @@ export class ApiInterceptor implements IApiInterceptor {
constructor(private httpWaitService: HttpWaitService) {} constructor(private httpWaitService: HttpWaitService) {}
getAdditionalHeaders(existingHeaders?: HttpHeaders) { getAdditionalHeaders(existingHeaders?: HttpHeaders) {
return existingHeaders; return existingHeaders || new HttpHeaders();
} }
intercept(request: HttpRequest<any>, next: HttpHandler) { intercept(request: HttpRequest<any>, next: HttpHandler) {

38
npm/ng-packs/packages/core/src/lib/models/dtos.ts

@ -1,17 +1,18 @@
import { ABP } from './common'; import { ABP } from './common';
import { checkHasProp } from '../utils/common-utils';
export class ListResultDto<T> { export class ListResultDto<T> {
items?: T[]; items?: T[];
constructor(initialValues: Partial<ListResultDto<T>> = {}) { constructor(initialValues: Partial<ListResultDto<T>> = {}) {
for (const key in initialValues) { for (const key in initialValues) {
if (Object.prototype.hasOwnProperty.call(initialValues, key)) { if (checkHasProp(initialValues, key)) {
this[key] = initialValues[key]; this[key] = initialValues[key];
} }
} }
} }
} }
type ValueOf<T> = T[keyof T];
export class PagedResultDto<T> extends ListResultDto<T> { export class PagedResultDto<T> extends ListResultDto<T> {
totalCount?: number; totalCount?: number;
@ -25,11 +26,8 @@ export class LimitedResultRequestDto {
constructor(initialValues: Partial<LimitedResultRequestDto> = {}) { constructor(initialValues: Partial<LimitedResultRequestDto> = {}) {
for (const key in initialValues) { for (const key in initialValues) {
if ( if (checkHasProp(initialValues, key) && initialValues[key] !== undefined) {
Object.prototype.hasOwnProperty.call(initialValues, key) && this[key] = initialValues[key] as ValueOf<LimitedResultRequestDto>;
initialValues[key] !== undefined
) {
this[key] = initialValues[key];
} }
} }
} }
@ -56,7 +54,7 @@ export class EntityDto<TKey = string> {
constructor(initialValues: Partial<EntityDto<TKey>> = {}) { constructor(initialValues: Partial<EntityDto<TKey>> = {}) {
for (const key in initialValues) { for (const key in initialValues) {
if (Object.prototype.hasOwnProperty.call(initialValues, key)) { if (checkHasProp(initialValues, key)) {
this[key] = initialValues[key]; this[key] = initialValues[key];
} }
} }
@ -130,11 +128,11 @@ export class FullAuditedEntityWithUserDto<
} }
export class ExtensibleObject { export class ExtensibleObject {
extraProperties: ABP.Dictionary<any>; extraProperties?: ABP.Dictionary<any>;
constructor(initialValues: Partial<ExtensibleObject> = {}) { constructor(initialValues: Partial<ExtensibleObject> = {}) {
for (const key in initialValues) { for (const key in initialValues) {
if (Object.prototype.hasOwnProperty.call(initialValues, key)) { if (checkHasProp(initialValues, key)) {
this[key] = initialValues[key]; this[key] = initialValues[key];
} }
} }
@ -142,7 +140,7 @@ export class ExtensibleObject {
} }
export class ExtensibleEntityDto<TKey = string> extends ExtensibleObject { export class ExtensibleEntityDto<TKey = string> extends ExtensibleObject {
id: TKey; id?: TKey;
constructor(initialValues: Partial<ExtensibleEntityDto<TKey>> = {}) { constructor(initialValues: Partial<ExtensibleEntityDto<TKey>> = {}) {
super(initialValues); super(initialValues);
@ -152,7 +150,7 @@ export class ExtensibleEntityDto<TKey = string> extends ExtensibleObject {
export class ExtensibleCreationAuditedEntityDto< export class ExtensibleCreationAuditedEntityDto<
TPrimaryKey = string, TPrimaryKey = string,
> extends ExtensibleEntityDto<TPrimaryKey> { > extends ExtensibleEntityDto<TPrimaryKey> {
creationTime: Date | string; creationTime?: Date | string;
creatorId?: string; creatorId?: string;
constructor(initialValues: Partial<ExtensibleCreationAuditedEntityDto<TPrimaryKey>> = {}) { constructor(initialValues: Partial<ExtensibleCreationAuditedEntityDto<TPrimaryKey>> = {}) {
@ -175,8 +173,8 @@ export class ExtensibleAuditedEntityWithUserDto<
TPrimaryKey = string, TPrimaryKey = string,
TUserDto = any, TUserDto = any,
> extends ExtensibleAuditedEntityDto<TPrimaryKey> { > extends ExtensibleAuditedEntityDto<TPrimaryKey> {
creator: TUserDto; creator?: TUserDto;
lastModifier: TUserDto; lastModifier?: TUserDto;
constructor(initialValues: Partial<ExtensibleAuditedEntityWithUserDto<TPrimaryKey>> = {}) { constructor(initialValues: Partial<ExtensibleAuditedEntityWithUserDto<TPrimaryKey>> = {}) {
super(initialValues); super(initialValues);
@ -187,7 +185,7 @@ export class ExtensibleCreationAuditedEntityWithUserDto<
TPrimaryKey = string, TPrimaryKey = string,
TUserDto = any, TUserDto = any,
> extends ExtensibleCreationAuditedEntityDto<TPrimaryKey> { > extends ExtensibleCreationAuditedEntityDto<TPrimaryKey> {
creator: TUserDto; creator?: TUserDto;
constructor( constructor(
initialValues: Partial<ExtensibleCreationAuditedEntityWithUserDto<TPrimaryKey>> = {}, initialValues: Partial<ExtensibleCreationAuditedEntityWithUserDto<TPrimaryKey>> = {},
@ -199,9 +197,9 @@ export class ExtensibleCreationAuditedEntityWithUserDto<
export class ExtensibleFullAuditedEntityDto< export class ExtensibleFullAuditedEntityDto<
TPrimaryKey = string, TPrimaryKey = string,
> extends ExtensibleAuditedEntityDto<TPrimaryKey> { > extends ExtensibleAuditedEntityDto<TPrimaryKey> {
isDeleted: boolean; isDeleted?: boolean;
deleterId?: string; deleterId?: string;
deletionTime: Date | string; deletionTime?: Date | string;
constructor(initialValues: Partial<ExtensibleFullAuditedEntityDto<TPrimaryKey>> = {}) { constructor(initialValues: Partial<ExtensibleFullAuditedEntityDto<TPrimaryKey>> = {}) {
super(initialValues); super(initialValues);
@ -212,9 +210,9 @@ export class ExtensibleFullAuditedEntityWithUserDto<
TPrimaryKey = string, TPrimaryKey = string,
TUserDto = any, TUserDto = any,
> extends ExtensibleFullAuditedEntityDto<TPrimaryKey> { > extends ExtensibleFullAuditedEntityDto<TPrimaryKey> {
creator: TUserDto; creator?: TUserDto;
lastModifier: TUserDto; lastModifier?: TUserDto;
deleter: TUserDto; deleter?: TUserDto;
constructor(initialValues: Partial<ExtensibleFullAuditedEntityWithUserDto<TPrimaryKey>> = {}) { constructor(initialValues: Partial<ExtensibleFullAuditedEntityWithUserDto<TPrimaryKey>> = {}) {
super(initialValues); super(initialValues);

5
npm/ng-packs/packages/core/src/lib/models/environment.ts

@ -17,9 +17,10 @@ export interface ApplicationInfo {
baseUrl?: string; baseUrl?: string;
logoUrl?: string; logoUrl?: string;
} }
export interface HasAdditional {
export interface ApiConfig {
[key: string]: string; [key: string]: string;
}
export interface ApiConfig extends Partial<HasAdditional>{
url: string; url: string;
rootNamespace?: string; rootNamespace?: string;
} }

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

@ -3,6 +3,6 @@ import { CurrentTenantDto } from '../proxy/volo/abp/asp-net-core/mvc/multi-tenan
export namespace Session { export namespace Session {
export interface State { export interface State {
language: string; language: string;
tenant: CurrentTenantDto; tenant: CurrentTenantDto | null;
} }
} }

6
npm/ng-packs/packages/core/src/lib/providers/locale.provider.ts

@ -1,6 +1,7 @@
import { LOCALE_ID, Provider } from '@angular/core'; import { LOCALE_ID, Provider } from '@angular/core';
import { differentLocales } from '../constants/different-locales'; import { differentLocales } from '../constants/different-locales';
import { LocalizationService } from '../services/localization.service'; import { LocalizationService } from '../services/localization.service';
import { checkHasProp } from '../utils/common-utils';
export class LocaleId extends String { export class LocaleId extends String {
constructor(private localizationService: LocalizationService) { constructor(private localizationService: LocalizationService) {
@ -9,7 +10,10 @@ export class LocaleId extends String {
toString(): string { toString(): string {
const { currentLang } = this.localizationService; const { currentLang } = this.localizationService;
return differentLocales[currentLang] || currentLang; if (checkHasProp(differentLocales, currentLang)) {
return differentLocales[currentLang];
}
return currentLang;
} }
valueOf(): string { valueOf(): string {

15
npm/ng-packs/packages/core/src/lib/services/config-state.service.ts

@ -1,5 +1,5 @@
import { Inject, Injectable } from '@angular/core'; import { Inject, Injectable } from '@angular/core';
import { Observable, Subject, of } from 'rxjs'; import { Observable, Subject } from 'rxjs';
import { map, switchMap, take, tap } from 'rxjs/operators'; import { map, switchMap, take, tap } from 'rxjs/operators';
import { AbpApplicationConfigurationService } from '../proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-configuration.service'; import { AbpApplicationConfigurationService } from '../proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-configuration.service';
import { AbpApplicationLocalizationService } from '../proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-localization.service'; import { AbpApplicationLocalizationService } from '../proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-localization.service';
@ -47,6 +47,9 @@ export class ConfigStateService {
private getLocalizationAndCombineWithAppState( private getLocalizationAndCombineWithAppState(
appState: ApplicationConfigurationDto, appState: ApplicationConfigurationDto,
): Observable<ApplicationConfigurationDto> { ): Observable<ApplicationConfigurationDto> {
if (!appState.localization.currentCulture.cultureName) {
throw new Error('culture name should defined');
}
return this.getlocalizationResource(appState.localization.currentCulture.cultureName).pipe( return this.getlocalizationResource(appState.localization.currentCulture.cultureName).pipe(
map(result => ({ ...appState, localization: { ...appState.localization, ...result } })), map(result => ({ ...appState, localization: { ...appState.localization, ...result } })),
); );
@ -77,11 +80,11 @@ export class ConfigStateService {
} }
} }
getOne$(key: string) { getOne$<K extends keyof ApplicationConfigurationDto>(key: K) {
return this.store.sliceState(state => state[key]); return this.store.sliceState(state => state[key]);
} }
getOne(key: string) { getOne<K extends keyof ApplicationConfigurationDto>(key: K) {
return this.store.state[key]; return this.store.state[key];
} }
@ -138,7 +141,7 @@ export class ConfigStateService {
return keys.reduce((acc, key) => ({ ...acc, [key]: features.values[key] }), {}); return keys.reduce((acc, key) => ({ ...acc, [key]: features.values[key] }), {});
} }
getFeatures$(keys: string[]) { getFeatures$(keys: string[]): Observable<{[key: string]: string} | undefined> {
return this.store.sliceState(({ features }) => { return this.store.sliceState(({ features }) => {
if (!features?.values) return; if (!features?.values) return;
@ -164,7 +167,7 @@ export class ConfigStateService {
return keysFound.reduce((acc, key) => { return keysFound.reduce((acc, key) => {
acc[key] = settings[key]; acc[key] = settings[key];
return acc; return acc;
}, {}); }, {} as Record<string, string>);
} }
getSettings$(keyword?: string) { getSettings$(keyword?: string) {
@ -179,7 +182,7 @@ export class ConfigStateService {
return keysFound.reduce((acc, key) => { return keysFound.reduce((acc, key) => {
acc[key] = settings[key]; acc[key] = settings[key];
return acc; return acc;
}, {}); }, {} as Record<string, string>);
}), }),
); );
} }

11
npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts

@ -8,7 +8,7 @@ export class DomInsertionService {
insertContent<T extends HTMLScriptElement | HTMLStyleElement>( insertContent<T extends HTMLScriptElement | HTMLStyleElement>(
contentStrategy: ContentStrategy<T>, contentStrategy: ContentStrategy<T>,
): T { ): T | undefined {
const hash = generateHash(contentStrategy.content); const hash = generateHash(contentStrategy.content);
if (this.inserted.has(hash)) return; if (this.inserted.has(hash)) return;
@ -20,10 +20,11 @@ export class DomInsertionService {
} }
removeContent(element: HTMLScriptElement | HTMLStyleElement) { removeContent(element: HTMLScriptElement | HTMLStyleElement) {
const hash = generateHash(element.textContent); if (element.textContent) {
this.inserted.delete(hash); const hash = generateHash(element.textContent);
this.inserted.delete(hash);
element.parentNode.removeChild(element); element.parentNode?.removeChild(element);
}
} }
has(content: string): boolean { has(content: string): boolean {

17
npm/ng-packs/packages/core/src/lib/services/environment.service.ts

@ -4,10 +4,10 @@ import { map } from 'rxjs/operators';
import { Apis, Environment } from '../models/environment'; import { Apis, Environment } from '../models/environment';
import { InternalStore } from '../utils/internal-store-utils'; import { InternalStore } from '../utils/internal-store-utils';
const mapToApiUrl = (key: string) => (apis: Apis) => const mapToApiUrl = (key: string | undefined) => (apis: Apis) =>
(apis[key] || apis.default).url || apis.default.url; ((key && apis[key]) || apis.default).url || apis.default.url;
const mapToIssuer = (issuer: string) => { const mapToIssuer = (issuer: string | undefined) => {
if (!issuer) { if (!issuer) {
return issuer; return issuer;
} }
@ -30,8 +30,8 @@ export class EnvironmentService {
return this.store.state; return this.store.state;
} }
getApiUrl(key: string) { getApiUrl(key: string | undefined) {
return mapToApiUrl(key)(this.store.state.apis); return mapToApiUrl(key)(this.store.state?.apis);
} }
getApiUrl$(key: string) { getApiUrl$(key: string) {
@ -43,11 +43,12 @@ export class EnvironmentService {
} }
getIssuer() { getIssuer() {
const issuer = this.store.state.oAuthConfig.issuer; const issuer = this.store.state?.oAuthConfig?.issuer;
return mapToIssuer(issuer); return mapToIssuer(issuer);
} }
getIssuer$() { getIssuer$() {
return this.store.sliceState(state => state.oAuthConfig.issuer).pipe(map(mapToIssuer)); return this.store.sliceState(state => state?.oAuthConfig?.issuer).pipe(map(mapToIssuer));
} }
} }

5
npm/ng-packs/packages/core/src/lib/services/http-wait.service.ts

@ -86,7 +86,10 @@ export class HttpWaitService {
this.store.patch({ filteredRequests }); this.store.patch({ filteredRequests });
} }
private applyFilter(requests: HttpRequest<any>[]) { private applyFilter(requests: HttpRequest<any>[] | undefined) {
if (!requests) {
return [];
}
const { filteredRequests } = this.store.state; const { filteredRequests } = this.store.state;
return requests.filter( return requests.filter(
({ method, url }) => ({ method, url }) =>

10
npm/ng-packs/packages/core/src/lib/services/lazy-load.service.ts

@ -1,5 +1,5 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { concat, Observable, of, throwError } from 'rxjs'; import { concat, Observable, of, pipe, throwError } from 'rxjs';
import { delay, retryWhen, shareReplay, take, tap } from 'rxjs/operators'; import { delay, retryWhen, shareReplay, take, tap } from 'rxjs/operators';
import { LoadingStrategy } from '../strategies'; import { LoadingStrategy } from '../strategies';
import { ResourceWaitService } from './resource-wait.service'; import { ResourceWaitService } from './resource-wait.service';
@ -15,11 +15,13 @@ export class LazyLoadService {
load(strategy: LoadingStrategy, retryTimes?: number, retryDelay?: number): Observable<Event> { load(strategy: LoadingStrategy, retryTimes?: number, retryDelay?: number): Observable<Event> {
if (this.loaded.has(strategy.path)) return of(new CustomEvent('load')); if (this.loaded.has(strategy.path)) return of(new CustomEvent('load'));
this.resourceWaitService.addResource(strategy.path); this.resourceWaitService.addResource(strategy.path);
const delayOperator = retryDelay ? pipe(delay(retryDelay)) : pipe();
const takeOp = retryTimes ? pipe(take(retryTimes)) : pipe();
return strategy.createStream().pipe( return strategy.createStream().pipe(
retryWhen(error$ => retryWhen(error$ =>
concat( concat(
error$.pipe(delay(retryDelay), take(retryTimes)), error$.pipe(delayOperator, takeOp),
throwError(new CustomEvent('error')), throwError(() => new CustomEvent('error')),
), ),
), ),
tap(() => { tap(() => {
@ -36,7 +38,7 @@ export class LazyLoadService {
if (!element) return false; if (!element) return false;
element.parentNode.removeChild(element); element.parentNode?.removeChild(element);
this.loaded.delete(path); this.loaded.delete(path);
return true; return true;
} }

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

@ -90,15 +90,16 @@ export class LocalizationService {
Object.entries(remote).forEach(entry => { Object.entries(remote).forEach(entry => {
const resourceName = entry[0]; const resourceName = entry[0];
const remoteTexts = entry[1]; const remoteTexts = entry[1];
let resource = local.get(resourceName) || {}; let resource = local?.get(resourceName) || {};
resource = { ...resource, ...remoteTexts }; resource = { ...resource, ...remoteTexts };
local.set(resourceName, resource); local?.set(resourceName, resource);
}); });
} }
return local; return local;
}), }),
filter(Boolean)
) )
.subscribe(val => this.localizations$.next(val)); .subscribe(val => this.localizations$.next(val));
} }
@ -134,6 +135,7 @@ export class LocalizationService {
lang => this.configState.getDeep('localization.currentCulture.cultureName') !== lang, lang => this.configState.getDeep('localization.currentCulture.cultureName') !== lang,
), ),
switchMap(lang => this.configState.refreshAppState().pipe(map(() => lang))), switchMap(lang => this.configState.refreshAppState().pipe(map(() => lang))),
filter(Boolean),
switchMap(lang => from(this.registerLocale(lang).then(() => lang))), switchMap(lang => from(this.registerLocale(lang).then(() => lang))),
) )
.subscribe(lang => this._languageChange$.next(lang)); .subscribe(lang => this._languageChange$.next(lang));
@ -176,14 +178,14 @@ export class LocalizationService {
return this.getLocalization(this.configState.getAll(), key, ...interpolateParams); return this.getLocalization(this.configState.getAll(), key, ...interpolateParams);
} }
localize(resourceName: string, key: string, defaultValue: string): Observable<string> { localize(resourceName: string, key: string, defaultValue: string): Observable<string | null> {
return this.configState.getOne$('localization').pipe( return this.configState.getOne$('localization').pipe(
map(createLocalizer), map(createLocalizer),
map(localize => localize(resourceName, key, defaultValue)), map(localize => localize(resourceName, key, defaultValue)),
); );
} }
localizeSync(resourceName: string, key: string, defaultValue: string): string { localizeSync(resourceName: string, key: string, defaultValue: string): string | null {
const localization = this.configState.getOne('localization'); const localization = this.configState.getOne('localization');
return createLocalizer(localization)(resourceName, key, defaultValue); return createLocalizer(localization)(resourceName, key, defaultValue);
} }
@ -210,7 +212,7 @@ export class LocalizationService {
...interpolateParams: string[] ...interpolateParams: string[]
) { ) {
if (!key) key = ''; if (!key) key = '';
let defaultValue: string; let defaultValue = '';
if (typeof key !== 'string') { if (typeof key !== 'string') {
defaultValue = key.defaultValue; defaultValue = key.defaultValue;
@ -219,7 +221,7 @@ export class LocalizationService {
const keys = key.split('::') as string[]; const keys = key.split('::') as string[];
const warn = (message: string) => { const warn = (message: string) => {
if (isDevMode) console.warn(message); if (isDevMode()) console.warn(message);
}; };
if (keys.length < 2) { if (keys.length < 2) {
@ -263,7 +265,7 @@ export class LocalizationService {
} }
} }
function recursivelyMergeBaseResources(baseResourceName: string, source: ResourceDto) { function recursivelyMergeBaseResources(baseResourceName: string, source: ResourceDto): ApplicationLocalizationResourceDto {
const item = source[baseResourceName]; const item = source[baseResourceName];
if (item.baseResources.length === 0) { if (item.baseResources.length === 0) {
@ -278,7 +280,7 @@ function recursivelyMergeBaseResources(baseResourceName: string, source: Resourc
} }
function mergeResourcesWithBaseResource(resource: ResourceDto): ResourceDto { function mergeResourcesWithBaseResource(resource: ResourceDto): ResourceDto {
const entities = Object.keys(resource).map(key => { const entities: Array<[string, ApplicationLocalizationResourceDto]> = Object.keys(resource).map(key => {
const newValue = recursivelyMergeBaseResources(key, resource); const newValue = recursivelyMergeBaseResources(key, resource);
return [key, newValue]; return [key, newValue];
}); });
@ -296,5 +298,5 @@ function combineLegacyandNewResources(
}, legacy); }, legacy);
} }
type LegacyLanguageDto = Record<string, Record<string, string>>; export type LegacyLanguageDto = Record<string, Record<string, string>>;
type ResourceDto = Record<string, ApplicationLocalizationResourceDto>; export type ResourceDto = Record<string, ApplicationLocalizationResourceDto>;

2
npm/ng-packs/packages/core/src/lib/services/multi-tenancy.service.ts

@ -12,7 +12,7 @@ import { SessionStateService } from './session-state.service';
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class MultiTenancyService { export class MultiTenancyService {
domainTenant: CurrentTenantDto = null; domainTenant: CurrentTenantDto | null = null;
isTenantBoxVisible = true; isTenantBoxVisible = true;

4
npm/ng-packs/packages/core/src/lib/services/permission.service.ts

@ -14,7 +14,7 @@ export class PermissionService {
); );
} }
getGrantedPolicy(key: string) { getGrantedPolicy(key: string | undefined) {
const policies = this.getSnapshot(); const policies = this.getSnapshot();
return this.isPolicyGranted(key, policies); return this.isPolicyGranted(key, policies);
} }
@ -36,7 +36,7 @@ export class PermissionService {
); );
} }
protected isPolicyGranted(key: string, grantedPolicies: Record<string, boolean>) { protected isPolicyGranted(key: string | undefined, grantedPolicies: Record<string, boolean>) {
if (!key) return true; if (!key) return true;
const orRegexp = /\|\|/g; const orRegexp = /\|\|/g;

6
npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts

@ -23,7 +23,7 @@ export class ReplaceableComponentsService {
} }
constructor(private ngZone: NgZone, private router: Router) { constructor(private ngZone: NgZone, private router: Router) {
this.store = new InternalStore([]); this.store = new InternalStore([] as ReplaceableComponents.ReplaceableComponent[]);
} }
add(replaceableComponent: ReplaceableComponents.ReplaceableComponent, reload?: boolean): void { add(replaceableComponent: ReplaceableComponents.ReplaceableComponent, reload?: boolean): void {
@ -44,11 +44,11 @@ export class ReplaceableComponentsService {
if (reload) reloadRoute(this.router, this.ngZone); if (reload) reloadRoute(this.router, this.ngZone);
} }
get(replaceableComponentKey: string): ReplaceableComponents.ReplaceableComponent { get(replaceableComponentKey: string): ReplaceableComponents.ReplaceableComponent | undefined {
return this.replaceableComponents.find(component => component.key === replaceableComponentKey); return this.replaceableComponents.find(component => component.key === replaceableComponentKey);
} }
get$(replaceableComponentKey: string): Observable<ReplaceableComponents.ReplaceableComponent> { get$(replaceableComponentKey: string): Observable<ReplaceableComponents.ReplaceableComponent | undefined> {
return this.replaceableComponents$.pipe( return this.replaceableComponents$.pipe(
map(components => components.find(component => component.key === replaceableComponentKey)), map(components => components.find(component => component.key === replaceableComponentKey)),
); );

2
npm/ng-packs/packages/core/src/lib/services/resource-wait.service.ts

@ -20,7 +20,7 @@ export class ResourceWaitService {
} }
updateLoading$() { updateLoading$() {
return this.store.sliceUpdate(({ resources }) => !!resources.size); return this.store.sliceUpdate(({ resources }) => !!resources?.size);
} }
clearLoading() { clearLoading() {

7
npm/ng-packs/packages/core/src/lib/services/rest.service.ts

@ -20,7 +20,7 @@ export class RestService {
protected httpErrorReporter: HttpErrorReporterService, protected httpErrorReporter: HttpErrorReporterService,
) {} ) {}
protected getApiFromStore(apiName: string): string { protected getApiFromStore(apiName: string | undefined): string {
return this.environment.getApiUrl(apiName); return this.environment.getApiUrl(apiName);
} }
@ -51,13 +51,12 @@ export class RestService {
} }
private getParams(params: Rest.Params, encoder?: HttpParameterCodec): HttpParams { private getParams(params: Rest.Params, encoder?: HttpParameterCodec): HttpParams {
const filteredParams = Object.keys(params).reduce((acc, key) => { const filteredParams = Object.entries(params).reduce((acc, [key, value]) => {
const value = params[key];
if (isUndefinedOrEmptyString(value)) return acc; if (isUndefinedOrEmptyString(value)) return acc;
if (value === null && !this.options.sendNullsAsQueryParam) return acc; if (value === null && !this.options.sendNullsAsQueryParam) return acc;
acc[key] = value; acc[key] = value;
return acc; return acc;
}, {}); }, {} as any);
return encoder return encoder
? new HttpParams({ encoder, fromObject: filteredParams }) ? new HttpParams({ encoder, fromObject: filteredParams })
: new HttpParams({ fromObject: filteredParams }); : new HttpParams({ fromObject: filteredParams });

5
npm/ng-packs/packages/core/src/lib/services/router-events.service.ts

@ -6,6 +6,7 @@ import {
NavigationStart, NavigationStart,
Router, Router,
RouterEvent, RouterEvent,
Event
} from '@angular/router'; } from '@angular/router';
import { filter } from 'rxjs/operators'; import { filter } from 'rxjs/operators';
@ -23,7 +24,7 @@ export class RouterEvents {
getEvents<T extends RouterEventConstructors>(...eventTypes: T) { getEvents<T extends RouterEventConstructors>(...eventTypes: T) {
type FilteredRouterEvent = T extends Type<infer Ctor>[] ? Ctor : never; type FilteredRouterEvent = T extends Type<infer Ctor>[] ? Ctor : never;
const filterRouterEvents = (event: RouterEvent): event is FilteredRouterEvent => const filterRouterEvents = (event: Event): event is FilteredRouterEvent =>
eventTypes.some(type => event instanceof type); eventTypes.some(type => event instanceof type);
return this.router.events.pipe(filter(filterRouterEvents)); return this.router.events.pipe(filter(filterRouterEvents));
@ -36,7 +37,7 @@ export class RouterEvents {
: never : never
: never; : never;
const filterNavigationEvents = (event: RouterEvent): event is FilteredNavigationEvent => const filterNavigationEvents = (event: Event): event is FilteredNavigationEvent =>
navigationEventKeys.some(key => event instanceof NavigationEvent[key]); navigationEventKeys.some(key => event instanceof NavigationEvent[key]);
return this.router.events.pipe(filter(filterNavigationEvents)); return this.router.events.pipe(filter(filterNavigationEvents));

12
npm/ng-packs/packages/core/src/lib/services/routes.service.ts

@ -7,7 +7,7 @@ import { ConfigStateService } from './config-state.service';
import { PermissionService } from './permission.service'; import { PermissionService } from './permission.service';
// eslint-disable-next-line @typescript-eslint/ban-types // eslint-disable-next-line @typescript-eslint/ban-types
export abstract class AbstractTreeService<T extends object> { export abstract class AbstractTreeService<T extends {[key: string | number | symbol]: any}> {
abstract id: string; abstract id: string;
abstract parentId: string; abstract parentId: string;
abstract hide: (item: T) => boolean; abstract hide: (item: T) => boolean;
@ -84,7 +84,7 @@ export abstract class AbstractTreeService<T extends object> {
} }
find(predicate: (item: TreeNode<T>) => boolean, tree = this.tree): TreeNode<T> | null { find(predicate: (item: TreeNode<T>) => boolean, tree = this.tree): TreeNode<T> | null {
return tree.reduce( return tree.reduce<TreeNode<T> | null>(
(acc, node) => (acc ? acc : predicate(node) ? node : this.find(predicate, node.children)), (acc, node) => (acc ? acc : predicate(node) ? node : this.find(predicate, node.children)),
null, null,
); );
@ -119,9 +119,9 @@ export abstract class AbstractTreeService<T extends object> {
} }
search(params: Partial<T>, tree = this.tree): TreeNode<T> | null { search(params: Partial<T>, tree = this.tree): TreeNode<T> | null {
const searchKeys = Object.keys(params); const searchKeys = Object.keys(params) as Array<keyof Partial<T>>;
return tree.reduce( return tree.reduce<TreeNode<T> | null>(
(acc, node) => (acc, node) =>
acc acc
? acc ? acc
@ -147,7 +147,7 @@ export abstract class AbstractNavTreeService<T extends ABP.Nav>
if (!Number.isInteger(a.order)) return 1; if (!Number.isInteger(a.order)) return 1;
if (!Number.isInteger(b.order)) return -1; if (!Number.isInteger(b.order)) return -1;
return a.order - b.order; return (a.order as number) - (b.order as number);
}; };
constructor(protected injector: Injector) { constructor(protected injector: Injector) {
@ -170,7 +170,7 @@ export abstract class AbstractNavTreeService<T extends ABP.Nav>
hasInvisibleChild(identifier: string): boolean { hasInvisibleChild(identifier: string): boolean {
const node = this.find(item => item[this.id] === identifier); const node = this.find(item => item[this.id] === identifier);
return node?.children?.some(child => child.invisible); return node?.children?.some(child => child.invisible) || false;
} }
/* istanbul ignore next */ /* istanbul ignore next */

2
npm/ng-packs/packages/core/src/lib/services/session-state.service.ts

@ -73,7 +73,7 @@ export class SessionStateService {
return this.store.sliceState(state => state.tenant); return this.store.sliceState(state => state.tenant);
} }
setTenant(tenant: CurrentTenantDto) { setTenant(tenant: CurrentTenantDto | null) {
if (compare(tenant, this.store.state.tenant)) return; if (compare(tenant, this.store.state.tenant)) return;
this.store.set({ ...this.store.state, tenant }); this.store.set({ ...this.store.state, tenant });

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

@ -1,7 +1,7 @@
import { Injectable } from '@angular/core';
import type { OnDestroy } from '@angular/core'; import type { OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs'; import { Injectable } from '@angular/core';
import type { Observable, PartialObserver } from 'rxjs'; import type { Observable, PartialObserver } from 'rxjs';
import { Subscription } from 'rxjs';
@Injectable() @Injectable()
export class SubscriptionService implements OnDestroy { export class SubscriptionService implements OnDestroy {
@ -33,7 +33,9 @@ export class SubscriptionService implements OnDestroy {
closeOne(subscription: Subscription | undefined | null) { closeOne(subscription: Subscription | undefined | null) {
this.removeOne(subscription); this.removeOne(subscription);
subscription.unsubscribe(); if (subscription) {
subscription.unsubscribe();
}
} }
ngOnDestroy(): void { ngOnDestroy(): void {

4
npm/ng-packs/packages/core/src/lib/strategies/content-security.strategy.ts

@ -10,7 +10,9 @@ export class LooseContentSecurityStrategy extends ContentSecurityStrategy {
} }
applyCSP(element: HTMLScriptElement | HTMLStyleElement) { applyCSP(element: HTMLScriptElement | HTMLStyleElement) {
element.setAttribute('nonce', this.nonce); if (this.nonce) {
element.setAttribute('nonce', this.nonce);
}
} }
} }

10
npm/ng-packs/packages/core/src/lib/strategies/content.strategy.ts

@ -1,5 +1,5 @@
import { ContentSecurityStrategy, CONTENT_SECURITY_STRATEGY } from './content-security.strategy'; import { CONTENT_SECURITY_STRATEGY, ContentSecurityStrategy } from './content-security.strategy';
import { DomStrategy, DOM_STRATEGY } from './dom.strategy'; import { DOM_STRATEGY, DomStrategy } from './dom.strategy';
export type ElementOptions<T extends HTMLScriptElement | HTMLStyleElement = any> = Partial<{ export type ElementOptions<T extends HTMLScriptElement | HTMLStyleElement = any> = Partial<{
[key in keyof T]: T[key]; [key in keyof T]: T[key];
@ -19,7 +19,11 @@ export abstract class ContentStrategy<T extends HTMLScriptElement | HTMLStyleEle
const element = this.createElement(); const element = this.createElement();
if (this.options && Object.keys(this.options).length > 0) { if (this.options && Object.keys(this.options).length > 0) {
Object.keys(this.options).forEach(key => (element[key] = this.options[key])); (Object.keys(this.options) as Array<keyof ElementOptions<T>>).forEach(key => {
if (this.options[key]) {
element[key] = (this.options as NonNullable<T>)[key];
}
});
} }
this.contentSecurityStrategy.applyCSP(element); this.contentSecurityStrategy.applyCSP(element);

2
npm/ng-packs/packages/core/src/lib/strategies/context.strategy.ts

@ -13,7 +13,7 @@ export class NoContextStrategy<
T extends Type<any> | TemplateRef<any> = any, T extends Type<any> | TemplateRef<any> = any,
> extends ContextStrategy<T> { > extends ContextStrategy<T> {
constructor() { constructor() {
super(undefined); super(undefined as unknown as Partial<ContextType<T>>);
} }
} }

9
npm/ng-packs/packages/core/src/lib/strategies/cross-origin.strategy.ts

@ -1,9 +1,14 @@
export class CrossOriginStrategy { export class CrossOriginStrategy {
constructor(public crossorigin: 'anonymous' | 'use-credentials', public integrity?: string) {} constructor(
public crossorigin: 'anonymous' | 'use-credentials' | null,
public integrity?: string,
) {}
setCrossOrigin<T extends HTMLElement>(element: T) { setCrossOrigin<T extends HTMLElement>(element: T) {
if (this.integrity) element.setAttribute('integrity', this.integrity); if (this.integrity) element.setAttribute('integrity', this.integrity);
element.setAttribute('crossorigin', this.crossorigin); if (this.crossorigin) {
element.setAttribute('crossorigin', this.crossorigin);
}
} }
} }

6
npm/ng-packs/packages/core/src/lib/strategies/loading.strategy.ts

@ -1,11 +1,11 @@
import { Observable, of } from 'rxjs'; import { Observable, of } from 'rxjs';
import { switchMap } from 'rxjs/operators'; import { switchMap } from 'rxjs/operators';
import { fromLazyLoad } from '../utils'; import { fromLazyLoad } from '../utils';
import { CrossOriginStrategy, CROSS_ORIGIN_STRATEGY } from './cross-origin.strategy'; import { CROSS_ORIGIN_STRATEGY, CrossOriginStrategy } from './cross-origin.strategy';
import { DomStrategy, DOM_STRATEGY } from './dom.strategy'; import { DOM_STRATEGY, DomStrategy } from './dom.strategy';
export abstract class LoadingStrategy<T extends HTMLScriptElement | HTMLLinkElement = any> { export abstract class LoadingStrategy<T extends HTMLScriptElement | HTMLLinkElement = any> {
element: T; element!: T;
constructor( constructor(
public path: string, public path: string,

4
npm/ng-packs/packages/core/src/lib/tokens/localization.token.ts

@ -4,10 +4,10 @@ import { ABP } from '../models/common';
export const LOCALIZATIONS = new InjectionToken('LOCALIZATIONS'); export const LOCALIZATIONS = new InjectionToken('LOCALIZATIONS');
export function localizationContributor(localizations: ABP.Localization[]) { export function localizationContributor(localizations?: ABP.Localization[]) {
if (localizations) { if (localizations) {
localizations$.next([...localizations$.value, ...localizations]); localizations$.next([...localizations$.value, ...localizations]);
} }
} }
export const localizations$ = new BehaviorSubject([]); export const localizations$ = new BehaviorSubject<ABP.Localization[]>([]);

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

@ -7,34 +7,38 @@ export function isUndefinedOrEmptyString(value: unknown): boolean {
return value === undefined || value === ''; return value === undefined || value === '';
} }
export function isNullOrUndefined(obj) { export function isNullOrUndefined<T>(obj: T) {
return obj === null || obj === undefined; return obj === null || obj === undefined;
} }
export function isNullOrEmpty(obj){ export function isNullOrEmpty<T>(obj: T): boolean {
return obj === null || obj === undefined || obj === ''; return obj === null || obj === undefined || obj === '';
} }
export function exists(obj) { export function exists<T>(obj: T): obj is T {
return !isNullOrUndefined(obj); return !isNullOrUndefined(obj);
} }
export function isObject(obj) { export function isObject<T>(obj: T): boolean {
return obj instanceof Object; return obj instanceof Object;
} }
export function isArray(obj) { export function isArray<T>(obj: T): boolean {
return Array.isArray(obj); return Array.isArray(obj);
} }
export function isObjectAndNotArray(obj) { export function isObjectAndNotArray<T>(obj: T): boolean {
return isObject(obj) && !isArray(obj); return isObject(obj) && !isArray(obj);
} }
export function isNode(obj) { export function isNode<T>(obj: T): boolean {
return obj instanceof Node; return obj instanceof Node;
} }
export function isObjectAndNotArrayNotNode(obj) { export function isObjectAndNotArrayNotNode<T>(obj: T): boolean {
return isObjectAndNotArray(obj) && !isNode(obj); return isObjectAndNotArray(obj) && !isNode(obj);
} }
export function checkHasProp<T>(object: T, key: string | keyof T): key is keyof T {
return Object.prototype.hasOwnProperty.call(object, key);
}

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

@ -13,8 +13,7 @@ export function getShortTimeFormat(configStateService: ConfigStateService) {
const dateTimeFormat = configStateService.getDeep( const dateTimeFormat = configStateService.getDeep(
'localization.currentCulture.dateTimeFormat', 'localization.currentCulture.dateTimeFormat',
) as DateTimeFormatDto; ) as DateTimeFormatDto;
return dateTimeFormat?.shortTimePattern?.replace('tt', 'a');
return dateTimeFormat.shortTimePattern.replace('tt', 'a');
} }
export function getShortDateShortTimeFormat(configStateService: ConfigStateService) { export function getShortDateShortTimeFormat(configStateService: ConfigStateService) {
@ -22,5 +21,5 @@ export function getShortDateShortTimeFormat(configStateService: ConfigStateServi
'localization.currentCulture.dateTimeFormat', 'localization.currentCulture.dateTimeFormat',
) as DateTimeFormatDto; ) as DateTimeFormatDto;
return `${dateTimeFormat.shortDatePattern} ${dateTimeFormat.shortTimePattern.replace('tt', 'a')}`; return `${dateTimeFormat.shortDatePattern} ${dateTimeFormat?.shortTimePattern?.replace('tt', 'a')}`;
} }

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

@ -24,19 +24,23 @@ export function getRemoteEnv(injector: Injector, environment: Partial<Environmen
httpErrorReporter.reportError(err); httpErrorReporter.reportError(err);
return of(null); return of(null);
}), // TODO: Consider get handle function from a provider }), // TODO: Consider get handle function from a provider
tap(env => environmentService.setState(mergeEnvironments(environment, env, remoteEnv))), tap(env =>
environmentService.setState(
mergeEnvironments(environment, env || ({} as Environment), remoteEnv as RemoteEnv),
),
),
) )
.toPromise(); .toPromise();
} }
function mergeEnvironments( function mergeEnvironments(
local: Partial<Environment>, local: Partial<Environment>,
remote: any, remote: Environment,
config: RemoteEnv, config: RemoteEnv,
): Environment { ): Environment {
switch (config.mergeStrategy) { switch (config.mergeStrategy) {
case 'deepmerge': case 'deepmerge':
return deepMerge(local, remote); return deepMerge(local, remote) as Environment;
case 'overwrite': case 'overwrite':
case null: case null:
case undefined: case undefined:

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

@ -21,7 +21,7 @@ export class LazyModuleFactory<T> extends NgModuleFactory<T> {
create(parentInjector: Injector | null): NgModuleRef<T> { create(parentInjector: Injector | null): NgModuleRef<T> {
const injector = Injector.create({ const injector = Injector.create({
parent: parentInjector, ...(parentInjector && { parent: parentInjector }),
providers: this.moduleWithProviders.providers as StaticProvider[], providers: this.moduleWithProviders.providers as StaticProvider[],
}); });
@ -35,7 +35,7 @@ export class LazyModuleFactory<T> extends NgModuleFactory<T> {
export function featuresFactory( export function featuresFactory(
configState: ConfigStateService, configState: ConfigStateService,
featureKeys: string[], featureKeys: string[],
mapFn: (features) => any = features => features, mapFn: (features: { [key: string]: string }) => any = features => features,
) { ) {
return configState.getFeatures$(featureKeys).pipe(filter(Boolean), map(mapFn)); return configState.getFeatures$(featureKeys).pipe(filter(Boolean), map(mapFn));
} }

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

@ -37,7 +37,8 @@ export class InternalStore<State> {
} }
deepPatch(state: DeepPartial<State>) { deepPatch(state: DeepPartial<State>) {
this.state$.next(deepMerge(this.state, state)); // TODO: Strict improve deepMerge
this.state$.next(deepMerge(this.state, state) as State);
this.update$.next(state); this.update$.next(state);
} }

12
npm/ng-packs/packages/core/src/lib/utils/lazy-load-utils.ts

@ -1,6 +1,6 @@
import { Observable, Observer } from 'rxjs'; import { Observable, Observer } from 'rxjs';
import { CrossOriginStrategy, CROSS_ORIGIN_STRATEGY } from '../strategies/cross-origin.strategy'; import { CROSS_ORIGIN_STRATEGY, CrossOriginStrategy } from '../strategies/cross-origin.strategy';
import { DomStrategy, DOM_STRATEGY } from '../strategies/dom.strategy'; import { DOM_STRATEGY, DomStrategy } from '../strategies/dom.strategy';
export function fromLazyLoad<T extends Event>( export function fromLazyLoad<T extends Event>(
element: HTMLScriptElement | HTMLLinkElement, element: HTMLScriptElement | HTMLLinkElement,
@ -11,9 +11,9 @@ export function fromLazyLoad<T extends Event>(
domStrategy.insertElement(element); domStrategy.insertElement(element);
return new Observable((observer: Observer<T>) => { return new Observable((observer: Observer<T>) => {
element.onload = (event: T) => { element.onload = (event: Event) => {
clearCallbacks(element); clearCallbacks(element);
observer.next(event); observer.next(event as T);
observer.complete(); observer.complete();
}; };
@ -32,10 +32,10 @@ export function fromLazyLoad<T extends Event>(
}); });
} }
function createErrorHandler(observer: Observer<Event>, element: HTMLElement) { function createErrorHandler<T extends Event = Event>(observer: Observer<T>, element: HTMLElement) {
return function (event: Event | string) { return function (event: Event | string) {
clearCallbacks(element); clearCallbacks(element);
element.parentNode.removeChild(element); element.parentNode?.removeChild(element);
observer.error(event); observer.error(event);
}; };
} }

2
npm/ng-packs/packages/core/src/lib/utils/localization-utils.ts

@ -10,7 +10,7 @@ export function getLocaleDirection(locale: string): 'ltr' | 'rtl' {
} }
export function createLocalizer(localization: ApplicationLocalizationConfigurationDto) { export function createLocalizer(localization: ApplicationLocalizationConfigurationDto) {
return (resourceName: string, key: string, defaultValue: string) => { return (resourceName: string, key: string, defaultValue: string | null) => {
if (resourceName === '_') return key; if (resourceName === '_') return key;
const resource = localization?.values?.[resourceName]; const resource = localization?.values?.[resourceName];

9
npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts

@ -90,18 +90,21 @@ function replaceTenantNameWithinEnvironment(
); );
} }
if (environment.oAuthConfig.redirectUri) { if (environment.oAuthConfig?.redirectUri) {
environment.oAuthConfig.redirectUri = environment.oAuthConfig.redirectUri.replace( environment.oAuthConfig.redirectUri = environment.oAuthConfig.redirectUri.replace(
placeholder, placeholder,
tenancyName, tenancyName,
); );
} }
environment.oAuthConfig.issuer = environment.oAuthConfig.issuer.replace(placeholder, tenancyName); if(!environment.oAuthConfig) {
environment.oAuthConfig = {};
}
environment.oAuthConfig.issuer = (environment.oAuthConfig.issuer || '').replace(placeholder, tenancyName);
Object.keys(environment.apis).forEach(api => { Object.keys(environment.apis).forEach(api => {
Object.keys(environment.apis[api]).forEach(key => { Object.keys(environment.apis[api]).forEach(key => {
environment.apis[api][key] = environment.apis[api][key].replace(placeholder, tenancyName); environment.apis[api][key] = (environment.apis[api][key] || '').replace(placeholder, tenancyName);
}); });
}); });

28
npm/ng-packs/packages/core/src/lib/utils/object-utils.ts

@ -6,18 +6,25 @@ import {
isObject, isObject,
isObjectAndNotArrayNotNode, isObjectAndNotArrayNotNode,
} from './common-utils'; } from './common-utils';
import { DeepPartial } from '../models';
export function deepMerge(target, source) { export function deepMerge<T>(
target: DeepPartial<T> | T,
source: DeepPartial<T> | T,
): DeepPartial<T> | T {
if (isObjectAndNotArrayNotNode(target) && isObjectAndNotArrayNotNode(source)) { if (isObjectAndNotArrayNotNode(target) && isObjectAndNotArrayNotNode(source)) {
return deepMergeRecursively(target, source); return deepMergeRecursively(target, source);
} else if (isNullOrUndefined(target) && isNullOrUndefined(source)) { } else if (isNullOrUndefined(target) && isNullOrUndefined(source)) {
return {}; return {} as T;
} else { } else {
return exists(source) ? source : target; return exists(source) ? (source as T) : target;
} }
} }
function deepMergeRecursively(target, source) { function deepMergeRecursively<T>(
target: DeepPartial<T> | T,
source: DeepPartial<T> | T,
): DeepPartial<T> | T {
const shouldNotRecurse = const shouldNotRecurse =
isNullOrUndefined(target) || isNullOrUndefined(target) ||
isNullOrUndefined(source) || // at least one not defined isNullOrUndefined(source) || // at least one not defined
@ -33,14 +40,17 @@ function deepMergeRecursively(target, source) {
* we will prioritize source if it is a defined value. * we will prioritize source if it is a defined value.
*/ */
if (shouldNotRecurse) { if (shouldNotRecurse) {
return exists(source) ? source : target; return exists(source) ? (source as T) : target;
} }
const keysOfTarget = Object.keys(target); const keysOfTarget = Object.keys(target as { [key: string]: any });
const keysOfSource = Object.keys(source); const keysOfSource = Object.keys(source as { [key: string]: any });
const uniqueKeys = new Set(keysOfTarget.concat(keysOfSource)); const uniqueKeys = new Set(keysOfTarget.concat(keysOfSource));
return [...uniqueKeys].reduce((retVal, key) => { return [...uniqueKeys].reduce((retVal, key) => {
retVal[key] = deepMergeRecursively(target[key], source[key]); (retVal as any)[key] = deepMergeRecursively(
(target as { [key: string]: any })[key],
(source as { [key: string]: any })[key],
);
return retVal; return retVal;
}, {}); }, {} as T);
} }

6
npm/ng-packs/packages/core/src/lib/utils/route-utils.ts

@ -1,11 +1,11 @@
import { NgZone } from '@angular/core'; import { NgZone } from '@angular/core';
import { PRIMARY_OUTLET, Router, UrlSegmentGroup } from '@angular/router'; import { PRIMARY_OUTLET, Router, UrlSegment, UrlSegmentGroup } from "@angular/router";
import { ABP } from '../models/common'; import { ABP } from '../models/common';
import { RoutesService } from '../services/routes.service'; import { RoutesService } from '../services/routes.service';
import { noop } from './common-utils'; import { noop } from './common-utils';
import { TreeNode } from './tree-utils'; import { TreeNode } from './tree-utils';
export function findRoute(routesService: RoutesService, path: string): TreeNode<ABP.Route> { export function findRoute(routesService: RoutesService, path: string): TreeNode<ABP.Route> | null {
const node = routesService.find(route => route.path === path); const node = routesService.find(route => route.path === path);
return node || path === '/' return node || path === '/'
@ -14,7 +14,7 @@ export function findRoute(routesService: RoutesService, path: string): TreeNode<
} }
export function getRoutePath(router: Router, url = router.url) { export function getRoutePath(router: Router, url = router.url) {
const emptyGroup = { segments: [] } as UrlSegmentGroup; const emptyGroup = { segments: [] as UrlSegment[] } as UrlSegmentGroup;
const primaryGroup = router.parseUrl(url).root.children[PRIMARY_OUTLET]; const primaryGroup = router.parseUrl(url).root.children[PRIMARY_OUTLET];
return '/' + (primaryGroup || emptyGroup).segments.map(({ path }) => path).join('/'); return '/' + (primaryGroup || emptyGroup).segments.map(({ path }) => path).join('/');

6
npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts

@ -62,7 +62,7 @@ export function createTreeNodeFilterCreator<T extends object>(
return (search: string) => { return (search: string) => {
const regex = new RegExp('.*' + search + '.*', 'i'); const regex = new RegExp('.*' + search + '.*', 'i');
return function collectNodes(nodes: TreeNode<T>[], matches = []) { return function collectNodes(nodes: TreeNode<T>[], matches: TreeNode<T>[] = []) {
for (const node of nodes) { for (const node of nodes) {
if (regex.test(mapperFn(node[key]))) matches.push(node); if (regex.test(mapperFn(node[key]))) matches.push(node);
@ -82,8 +82,8 @@ export type TreeNode<T extends object> = {
parent?: TreeNode<T>; parent?: TreeNode<T>;
}; };
type NodeKey = number | string | symbol | undefined | null; export type NodeKey = number | string | symbol | undefined | null;
type NodeValue<T extends object, F extends (...args: any) => any> = F extends undefined export type NodeValue<T extends object, F extends (...args: any) => any> = F extends undefined
? TreeNode<T> ? TreeNode<T>
: ReturnType<F>; : ReturnType<F>;

4
npm/ng-packs/packages/core/src/lib/validators/range.validator.ts

@ -21,10 +21,10 @@ export function validateRange({ maximum = Infinity, minimum = 0 }: RangeOptions
}; };
} }
function getMaxError(value: number, max: number, min: number): RangeError { function getMaxError(value: number, max: number, min: number): RangeError | null {
return value > max ? { range: { max, min } } : null; return value > max ? { range: { max, min } } : null;
} }
function getMinError(value: number, min: number, max: number): RangeError { function getMinError(value: number, min: number, max: number): RangeError | null {
return value < min ? { range: { min, max } } : null; return value < min ? { range: { min, max } } : null;
} }

2
npm/ng-packs/packages/core/src/lib/validators/required.validator.ts

@ -16,7 +16,7 @@ export function validateRequired({ allowEmptyStrings }: RequiredOptions = {}): V
return required; return required;
} }
function isValidRequired(value: any, allowEmptyStrings: boolean): boolean { function isValidRequired(value: any, allowEmptyStrings: boolean | undefined): boolean {
if (value || value === 0 || value === false) return true; if (value || value === 0 || value === false) return true;
if (allowEmptyStrings && value === '') return true; if (allowEmptyStrings && value === '') return true;

4
npm/ng-packs/packages/core/src/lib/validators/string-length.validator.ts

@ -27,10 +27,10 @@ export function validateStringLength({
}; };
} }
function getMaxLengthError(value: string, requiredLength: number): StringLengthError { function getMaxLengthError(value: string, requiredLength: number): StringLengthError | null {
return value.length > requiredLength ? { maxlength: { requiredLength } } : null; return value.length > requiredLength ? { maxlength: { requiredLength } } : null;
} }
function getMinLengthError(value: string, requiredLength: number): StringLengthError { function getMinLengthError(value: string, requiredLength: number): StringLengthError | null {
return value.length < requiredLength ? { minlength: { requiredLength } } : null; return value.length < requiredLength ? { minlength: { requiredLength } } : null;
} }

2
npm/ng-packs/packages/core/src/lib/validators/username.validator.ts

@ -14,7 +14,7 @@ export interface UsernameOptions {
const onlyLetterAndNumberRegex = /^[a-zA-Z0-9]+$/; const onlyLetterAndNumberRegex = /^[a-zA-Z0-9]+$/;
export function validateUsername( export function validateUsername(
{ pattern }: UsernameOptions = { pattern: onlyLetterAndNumberRegex }, { pattern = /.*/ }: UsernameOptions = { pattern: onlyLetterAndNumberRegex },
): ValidatorFn { ): ValidatorFn {
return (control: AbstractControl): UsernamePatternError | null => { return (control: AbstractControl): UsernamePatternError | null => {
const isValid = isValidUserName(control.value, pattern); const isValid = isValidUserName(control.value, pattern);

2
npm/ng-packs/packages/core/testing/src/lib/services/mock-permission.service.ts

@ -27,7 +27,7 @@ export class MockPermissionService extends PermissionService {
const grantedPolicies = keys.reduce((policies, key) => { const grantedPolicies = keys.reduce((policies, key) => {
policies[key] = true; policies[key] = true;
return policies; return policies;
}, {}); }, {} as { [key: string]: boolean });
this.configState['store'].deepPatch({ auth: { grantedPolicies } }); this.configState['store'].deepPatch({ auth: { grantedPolicies } });
} }

10
npm/ng-packs/packages/core/testing/src/lib/services/mock-rest.service.ts

@ -1,4 +1,10 @@
import { ABP, CORE_OPTIONS, EnvironmentService, RestService } from '@abp/ng.core'; import {
ABP,
CORE_OPTIONS,
EnvironmentService,
HttpErrorReporterService,
RestService,
} from '@abp/ng.core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Inject, Injectable } from '@angular/core'; import { Inject, Injectable } from '@angular/core';
import { Observable, throwError } from 'rxjs'; import { Observable, throwError } from 'rxjs';
@ -12,7 +18,7 @@ export class MockRestService extends RestService {
protected http: HttpClient, protected http: HttpClient,
protected environment: EnvironmentService, protected environment: EnvironmentService,
) { ) {
super(options, http, environment, null); super(options, http, environment, null as unknown as HttpErrorReporterService);
} }
handleError(err: any): Observable<any> { handleError(err: any): Observable<any> {

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

@ -26,21 +26,21 @@ import { eIdentityComponents } from '../../enums/components';
export class RolesComponent implements OnInit { export class RolesComponent implements OnInit {
data: PagedResultDto<IdentityRoleDto> = { items: [], totalCount: 0 }; data: PagedResultDto<IdentityRoleDto> = { items: [], totalCount: 0 };
form: UntypedFormGroup; form!: UntypedFormGroup;
selected: IdentityRoleDto; selected?: IdentityRoleDto;
isModalVisible: boolean; isModalVisible!: boolean;
visiblePermissions = false; visiblePermissions = false;
providerKey: string; providerKey?: string;
modalBusy = false; modalBusy = false;
permissionManagementKey = ePermissionManagementComponents.PermissionManagement; permissionManagementKey = ePermissionManagementComponents.PermissionManagement;
onVisiblePermissionChange = event => { onVisiblePermissionChange = (event: boolean) => {
this.visiblePermissions = event; this.visiblePermissions = event;
}; };
@ -82,7 +82,7 @@ export class RolesComponent implements OnInit {
if (!this.form.valid) return; if (!this.form.valid) return;
this.modalBusy = true; this.modalBusy = true;
const { id } = this.selected; const { id } = this.selected || {};
(id (id
? this.service.update(id, { ...this.selected, ...this.form.value }) ? this.service.update(id, { ...this.selected, ...this.form.value })
: this.service.create(this.form.value) : this.service.create(this.form.value)
@ -118,7 +118,7 @@ export class RolesComponent implements OnInit {
}, 0); }, 0);
} }
sort(data) { sort(data: any) {
const { prop, dir } = data.sorts[0]; const { prop, dir } = data.sorts[0];
this.list.sortKey = prop; this.list.sortKey = prop;
this.list.sortOrder = dir; this.list.sortOrder = dir;

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

@ -1,28 +1,12 @@
import { ListService, PagedResultDto } from '@abp/ng.core'; import { ListService, PagedResultDto } from "@abp/ng.core";
import { import { GetIdentityUsersInput, IdentityRoleDto, IdentityUserDto, IdentityUserService } from "@abp/ng.identity/proxy";
GetIdentityUsersInput, import { ePermissionManagementComponents } from "@abp/ng.permission-management";
IdentityRoleDto, import { Confirmation, ConfirmationService, ToasterService } from "@abp/ng.theme.shared";
IdentityUserDto, import { EXTENSIONS_IDENTIFIER, FormPropData, generateFormFromProps } from "@abp/ng.theme.shared/extensions";
IdentityUserService, import { Component, Injector, OnInit, TemplateRef, TrackByFunction, ViewChild } from "@angular/core";
} from '@abp/ng.identity/proxy'; import { AbstractControl, UntypedFormArray, UntypedFormBuilder, UntypedFormGroup } from "@angular/forms";
import { ePermissionManagementComponents } from '@abp/ng.permission-management'; import { finalize, switchMap, tap } from "rxjs/operators";
import {Confirmation, ConfirmationService, ToasterService} from '@abp/ng.theme.shared'; import { eIdentityComponents } from "../../enums/components";
import {
EXTENSIONS_IDENTIFIER,
FormPropData,
generateFormFromProps,
} from '@abp/ng.theme.shared/extensions';
import {
Component,
Injector,
OnInit,
TemplateRef,
TrackByFunction,
ViewChild,
} from '@angular/core';
import { AbstractControl, UntypedFormArray, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { finalize, switchMap, tap } from 'rxjs/operators';
import { eIdentityComponents } from '../../enums/components';
@Component({ @Component({
selector: 'abp-users', selector: 'abp-users',
@ -39,31 +23,31 @@ export class UsersComponent implements OnInit {
data: PagedResultDto<IdentityUserDto> = { items: [], totalCount: 0 }; data: PagedResultDto<IdentityUserDto> = { items: [], totalCount: 0 };
@ViewChild('modalContent', { static: false }) @ViewChild('modalContent', { static: false })
modalContent: TemplateRef<any>; modalContent!: TemplateRef<any>;
form: UntypedFormGroup; form!: UntypedFormGroup;
selected: IdentityUserDto; selected?: IdentityUserDto;
selectedUserRoles: IdentityRoleDto[]; selectedUserRoles?: IdentityRoleDto[];
roles: IdentityRoleDto[]; roles?: IdentityRoleDto[];
visiblePermissions = false; visiblePermissions = false;
providerKey: string; providerKey?: string;
isModalVisible: boolean; isModalVisible?: boolean;
modalBusy = false; modalBusy = false;
permissionManagementKey = ePermissionManagementComponents.PermissionManagement; permissionManagementKey = ePermissionManagementComponents.PermissionManagement;
entityDisplayName: string; entityDisplayName?: string;
trackByFn: TrackByFunction<AbstractControl> = (index, item) => Object.keys(item)[0] || index; trackByFn: TrackByFunction<AbstractControl> = (index, item) => Object.keys(item)[0] || index;
onVisiblePermissionChange = event => { onVisiblePermissionChange = (event: boolean) => {
this.visiblePermissions = event; this.visiblePermissions = event;
}; };
@ -90,20 +74,22 @@ export class UsersComponent implements OnInit {
this.service.getAssignableRoles().subscribe(({ items }) => { this.service.getAssignableRoles().subscribe(({ items }) => {
this.roles = items; this.roles = items;
this.form.addControl( if (this.roles) {
'roleNames', this.form.addControl(
this.fb.array( 'roleNames',
this.roles.map(role => this.fb.array(
this.fb.group({ this.roles.map(role =>
[role.name]: [ this.fb.group({
this.selected.id [role.name as string]: [
? !!this.selectedUserRoles?.find(userRole => userRole.id === role.id) this.selected?.id
: role.isDefault, ? !!this.selectedUserRoles?.find(userRole => userRole.id === role.id)
], : role.isDefault,
}), ],
}),
),
), ),
), );
); }
}); });
} }
@ -137,10 +123,11 @@ export class UsersComponent implements OnInit {
const { roleNames = [] } = this.form.value; const { roleNames = [] } = this.form.value;
const mappedRoleNames = const mappedRoleNames =
roleNames.filter(role => !!role[Object.keys(role)[0]]).map(role => Object.keys(role)[0]) || roleNames
[]; .filter((role: { [key: string]: any }) => !!role[Object.keys(role)[0]])
.map((role: { [key: string]: any }) => Object.keys(role)[0]) || [];
const { id } = this.selected; const { id } = this.selected || {};
(id (id
? this.service.update(id, { ? this.service.update(id, {
@ -166,12 +153,13 @@ export class UsersComponent implements OnInit {
if (status === Confirmation.Status.confirm) { if (status === Confirmation.Status.confirm) {
this.service.delete(id).subscribe(() => { this.service.delete(id).subscribe(() => {
this.toasterService.success('AbpUi::SuccessfullyDeleted'); this.toasterService.success('AbpUi::SuccessfullyDeleted');
this.list.get()}); this.list.get();
});
} }
}); });
} }
sort(data) { sort(data: any) {
const { prop, dir } = data.sorts[0]; const { prop, dir } = data.sorts[0];
this.list.sortKey = prop; this.list.sortKey = prop;
this.list.sortOrder = dir; this.list.sortOrder = dir;

8
npm/ng-packs/packages/identity/src/lib/defaults/default-roles-entity-actions.ts

@ -7,7 +7,7 @@ export const DEFAULT_ROLES_ENTITY_ACTIONS = EntityAction.createMany<IdentityRole
text: 'AbpIdentity::Edit', text: 'AbpIdentity::Edit',
action: data => { action: data => {
const component = data.getInjected(RolesComponent); const component = data.getInjected(RolesComponent);
component.edit(data.record.id); component.edit(data.record.id || '');
}, },
permission: 'AbpIdentity.Roles.Update', permission: 'AbpIdentity.Roles.Update',
}, },
@ -15,7 +15,7 @@ export const DEFAULT_ROLES_ENTITY_ACTIONS = EntityAction.createMany<IdentityRole
text: 'AbpIdentity::Permissions', text: 'AbpIdentity::Permissions',
action: data => { action: data => {
const component = data.getInjected(RolesComponent); const component = data.getInjected(RolesComponent);
component.openPermissionsModal(data.record.name); component.openPermissionsModal(data.record.name || '');
}, },
permission: 'AbpIdentity.Roles.ManagePermissions', permission: 'AbpIdentity.Roles.ManagePermissions',
}, },
@ -23,9 +23,9 @@ export const DEFAULT_ROLES_ENTITY_ACTIONS = EntityAction.createMany<IdentityRole
text: 'AbpIdentity::Delete', text: 'AbpIdentity::Delete',
action: data => { action: data => {
const component = data.getInjected(RolesComponent); const component = data.getInjected(RolesComponent);
component.delete(data.record.id, data.record.name); component.delete(data.record.id || '', data.record.name || '');
}, },
permission: 'AbpIdentity.Roles.Delete', permission: 'AbpIdentity.Roles.Delete',
visible: data => !data.record.isStatic, visible: data => !data?.record.isStatic,
}, },
]); ]);

4
npm/ng-packs/packages/identity/src/lib/defaults/default-roles-form-props.ts

@ -1,5 +1,5 @@
import { IdentityRoleDto } from '@abp/ng.identity/proxy'; import { IdentityRoleDto } from '@abp/ng.identity/proxy';
import { ePropType, FormProp, PropData } from '@abp/ng.theme.shared/extensions'; import { ePropType, FormProp, PropData, PropPredicate } from "@abp/ng.theme.shared/extensions";
import { Validators } from '@angular/forms'; import { Validators } from '@angular/forms';
export const DEFAULT_ROLES_CREATE_FORM_PROPS = FormProp.createMany<IdentityRoleDto>([ export const DEFAULT_ROLES_CREATE_FORM_PROPS = FormProp.createMany<IdentityRoleDto>([
@ -8,7 +8,7 @@ export const DEFAULT_ROLES_CREATE_FORM_PROPS = FormProp.createMany<IdentityRoleD
name: 'name', name: 'name',
displayName: 'AbpIdentity::RoleName', displayName: 'AbpIdentity::RoleName',
id: 'role-name', id: 'role-name',
disabled: (data: PropData<IdentityRoleDto>) => data.record && data.record.isStatic, disabled: ((data: PropData<IdentityRoleDto>) => data.record && data.record.isStatic) as PropPredicate<IdentityRoleDto>,
validators: () => [Validators.required], validators: () => [Validators.required],
}, },
{ {

23
npm/ng-packs/packages/identity/src/lib/defaults/default-users-entity-actions.ts

@ -1,14 +1,14 @@
import {IdentityUserDto} from '@abp/ng.identity/proxy'; import { IdentityUserDto } from '@abp/ng.identity/proxy';
import { EntityAction } from '@abp/ng.theme.shared/extensions'; import { EntityAction } from '@abp/ng.theme.shared/extensions';
import { UsersComponent } from '../components/users/users.component'; import { UsersComponent } from '../components/users/users.component';
import {ConfigStateService, CurrentUserDto} from "@abp/ng.core"; import { ConfigStateService, CurrentUserDto } from '@abp/ng.core';
export const DEFAULT_USERS_ENTITY_ACTIONS = EntityAction.createMany<IdentityUserDto>([ export const DEFAULT_USERS_ENTITY_ACTIONS = EntityAction.createMany<IdentityUserDto>([
{ {
text: 'AbpIdentity::Edit', text: 'AbpIdentity::Edit',
action: data => { action: data => {
const component = data.getInjected(UsersComponent); const component = data.getInjected(UsersComponent);
component.edit(data.record.id); component.edit(data.record.id || '');
}, },
permission: 'AbpIdentity.Users.Update', permission: 'AbpIdentity.Users.Update',
}, },
@ -16,20 +16,21 @@ export const DEFAULT_USERS_ENTITY_ACTIONS = EntityAction.createMany<IdentityUser
text: 'AbpIdentity::Permissions', text: 'AbpIdentity::Permissions',
action: data => { action: data => {
const component = data.getInjected(UsersComponent); const component = data.getInjected(UsersComponent);
component.openPermissionsModal(data.record.id, data.record.userName); component.openPermissionsModal(data.record.id || '', data.record.userName);
}, },
permission: 'AbpIdentity.Users.ManagePermissions', permission: 'AbpIdentity.Users.ManagePermissions',
}, { },
{
text: 'AbpIdentity::Delete', text: 'AbpIdentity::Delete',
action: data => { action: data => {
const component = data.getInjected(UsersComponent); const component = data.getInjected(UsersComponent);
component.delete(data.record.id, data.record.name || data.record.userName); component.delete(data.record.id || '', data.record.name || data.record.userName || '');
}, },
visible: data => { visible: data => {
const userName = data.record.userName; const userName = data?.record.userName;
const configStateService = data.getInjected(ConfigStateService) const configStateService = data?.getInjected(ConfigStateService);
const currentUser = configStateService.getOne("currentUser") as CurrentUserDto; const currentUser = configStateService?.getOne('currentUser') as CurrentUserDto;
return userName !== currentUser.userName; return userName !== currentUser.userName;
}, },
permission: 'AbpIdentity.Users.Delete', permission: 'AbpIdentity.Users.Delete',
}, },

2
npm/ng-packs/packages/identity/src/lib/defaults/default-users-form-props.ts

@ -67,7 +67,7 @@ export const DEFAULT_USERS_EDIT_FORM_PROPS = DEFAULT_USERS_CREATE_FORM_PROPS.map
if (prop.name === 'password') { if (prop.name === 'password') {
return { return {
...prop, ...prop,
validators: data => [...getPasswordValidators({ get: data.getInjected })], validators: (data: any) => [...getPasswordValidators({ get: data.getInjected })],
}; };
} }
return prop; return prop;

6
npm/ng-packs/packages/oauth/src/lib/handlers/oauth-configuration.handler.ts

@ -1,5 +1,5 @@
import { Inject, Injectable } from '@angular/core'; import { Inject, Injectable } from '@angular/core';
import { OAuthService } from 'angular-oauth2-oidc'; import { AuthConfig, OAuthService } from "angular-oauth2-oidc";
import compare from 'just-compare'; import compare from 'just-compare';
import { filter, map } from 'rxjs/operators'; import { filter, map } from 'rxjs/operators';
import { ABP, EnvironmentService, CORE_OPTIONS } from '@abp/ng.core'; import { ABP, EnvironmentService, CORE_OPTIONS } from '@abp/ng.core';
@ -20,10 +20,10 @@ export class OAuthConfigurationHandler {
this.environmentService this.environmentService
.createOnUpdateStream(state => state) .createOnUpdateStream(state => state)
.pipe( .pipe(
map(environment => environment.oAuthConfig), map(environment => environment.oAuthConfig as AuthConfig),
filter(config => !compare(config, this.options.environment.oAuthConfig)), filter(config => !compare(config, this.options.environment.oAuthConfig)),
) )
.subscribe(config => { .subscribe((config) => {
this.oAuthService.configure(config); this.oAuthService.configure(config);
}); });
} }

4
npm/ng-packs/packages/oauth/src/lib/interceptors/api.interceptor.ts

@ -3,11 +3,11 @@ import { Inject, Injectable } from '@angular/core';
import { OAuthService } from 'angular-oauth2-oidc'; import { OAuthService } from 'angular-oauth2-oidc';
import { finalize } from 'rxjs/operators'; import { finalize } from 'rxjs/operators';
import { import {
SessionStateService,
HttpWaitService, HttpWaitService,
TENANT_KEY,
IApiInterceptor, IApiInterceptor,
IS_EXTERNAL_REQUEST, IS_EXTERNAL_REQUEST,
SessionStateService,
TENANT_KEY,
} from '@abp/ng.core'; } from '@abp/ng.core';
@Injectable({ @Injectable({

4
npm/ng-packs/packages/oauth/src/lib/oauth.module.ts

@ -1,4 +1,4 @@
import { APP_INITIALIZER, ModuleWithProviders, NgModule } from '@angular/core'; import { APP_INITIALIZER, ModuleWithProviders, NgModule, Provider } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { OAuthModule, OAuthStorage } from 'angular-oauth2-oidc'; import { OAuthModule, OAuthStorage } from 'angular-oauth2-oidc';
import { import {
@ -58,7 +58,7 @@ export class AbpOAuthModule {
deps: [OAuthConfigurationHandler], deps: [OAuthConfigurationHandler],
useFactory: noop, useFactory: noop,
}, },
OAuthModule.forRoot().providers, OAuthModule.forRoot().providers as Provider[],
{ provide: OAuthStorage, useFactory: storageFactory }, { provide: OAuthStorage, useFactory: storageFactory },
], ],
}; };

6
npm/ng-packs/packages/oauth/src/lib/services/oauth.service.ts

@ -6,13 +6,13 @@ import { IAuthService, LoginParams } from '@abp/ng.core';
import { AuthFlowStrategy } from '../strategies'; import { AuthFlowStrategy } from '../strategies';
import { EnvironmentService } from '@abp/ng.core'; import { EnvironmentService } from '@abp/ng.core';
import { AUTH_FLOW_STRATEGY } from '../tokens/auth-flow-strategy'; import { AUTH_FLOW_STRATEGY } from '../tokens/auth-flow-strategy';
import { OAuthService } from 'angular-oauth2-oidc'; import { AuthConfig, OAuthService } from "angular-oauth2-oidc";
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root',
}) })
export class AbpOAuthService implements IAuthService { export class AbpOAuthService implements IAuthService {
private strategy: AuthFlowStrategy; private strategy!: AuthFlowStrategy;
get isInternalAuth() { get isInternalAuth() {
return this.strategy.isInternalAuth; return this.strategy.isInternalAuth;
@ -25,7 +25,7 @@ export class AbpOAuthService implements IAuthService {
const result$ = environmentService.getEnvironment$().pipe( const result$ = environmentService.getEnvironment$().pipe(
map(env => env?.oAuthConfig), map(env => env?.oAuthConfig),
filter(oAuthConfig => !!oAuthConfig), filter(Boolean),
tap(oAuthConfig => { tap(oAuthConfig => {
this.strategy = this.strategy =
oAuthConfig.responseType === 'code' oAuthConfig.responseType === 'code'

18
npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts

@ -9,15 +9,16 @@ import {
import { Observable, of } from 'rxjs'; import { Observable, of } from 'rxjs';
import { filter, switchMap, tap } from 'rxjs/operators'; import { filter, switchMap, tap } from 'rxjs/operators';
import { import {
LoginParams,
ConfigStateService, ConfigStateService,
EnvironmentService, EnvironmentService,
HttpErrorReporterService, HttpErrorReporterService,
LoginParams,
SessionStateService, SessionStateService,
TENANT_KEY, TENANT_KEY,
} from '@abp/ng.core'; } from '@abp/ng.core';
import { clearOAuthStorage } from '../utils/clear-o-auth-storage'; import { clearOAuthStorage } from '../utils/clear-o-auth-storage';
import { oAuthStorage } from '../utils/oauth-storage'; import { oAuthStorage } from '../utils/oauth-storage';
import { HttpErrorResponse } from '@angular/common/http';
export abstract class AuthFlowStrategy { export abstract class AuthFlowStrategy {
abstract readonly isInternalAuth: boolean; abstract readonly isInternalAuth: boolean;
@ -26,7 +27,7 @@ export abstract class AuthFlowStrategy {
protected environment: EnvironmentService; protected environment: EnvironmentService;
protected configState: ConfigStateService; protected configState: ConfigStateService;
protected oAuthService: OAuthService2; protected oAuthService: OAuthService2;
protected oAuthConfig: AuthConfig; protected oAuthConfig!: AuthConfig;
protected sessionState: SessionStateService; protected sessionState: SessionStateService;
protected tenantKey: string; protected tenantKey: string;
@ -38,7 +39,7 @@ export abstract class AuthFlowStrategy {
abstract login(params?: LoginParams | Params): Observable<any>; abstract login(params?: LoginParams | Params): Observable<any>;
private catchError = err => { private catchError = (err: HttpErrorResponse) => {
this.httpErrorReporter.reportError(err); this.httpErrorReporter.reportError(err);
return of(null); return of(null);
}; };
@ -49,18 +50,17 @@ export abstract class AuthFlowStrategy {
this.configState = injector.get(ConfigStateService); this.configState = injector.get(ConfigStateService);
this.oAuthService = injector.get(OAuthService2); this.oAuthService = injector.get(OAuthService2);
this.sessionState = injector.get(SessionStateService); this.sessionState = injector.get(SessionStateService);
this.oAuthConfig = this.environment.getEnvironment().oAuthConfig; this.oAuthConfig = this.environment.getEnvironment().oAuthConfig || {};
this.tenantKey = injector.get(TENANT_KEY); this.tenantKey = injector.get(TENANT_KEY);
this.listenToOauthErrors(); this.listenToOauthErrors();
} }
async init(): Promise<any> { async init(): Promise<any> {
const shouldClear = shouldStorageClear( if (this.oAuthConfig.clientId) {
this.environment.getEnvironment().oAuthConfig.clientId, const shouldClear = shouldStorageClear(this.oAuthConfig.clientId, oAuthStorage);
oAuthStorage, if (shouldClear) clearOAuthStorage(oAuthStorage);
); }
if (shouldClear) clearOAuthStorage(oAuthStorage);
this.oAuthService.configure(this.oAuthConfig); this.oAuthService.configure(this.oAuthConfig);

2
npm/ng-packs/packages/oauth/src/lib/utils/auth-utils.ts

@ -29,7 +29,7 @@ export const pipeToLogin: PipeToLoginFn = function (
); );
}; };
export function setRememberMe(remember: boolean) { export function setRememberMe(remember: boolean | undefined) {
removeRememberMe(); removeRememberMe();
localStorage.setItem(storageKey, 'true'); localStorage.setItem(storageKey, 'true');
document.cookie = `${cookieKey}=true; path=/${ document.cookie = `${cookieKey}=true; path=/${

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

@ -49,10 +49,10 @@ export class PermissionManagementComponent
PermissionManagement.PermissionManagementComponentOutputs PermissionManagement.PermissionManagementComponentOutputs
{ {
@Input() @Input()
readonly providerName: string; readonly providerName!: string;
@Input() @Input()
readonly providerKey: string; readonly providerKey!: string;
@Input() @Input()
readonly hideBadges = false; readonly hideBadges = false;
@ -90,13 +90,13 @@ export class PermissionManagementComponent
@Output() readonly visibleChange = new EventEmitter<boolean>(); @Output() readonly visibleChange = new EventEmitter<boolean>();
@ViewChildren('selectAllInThisTabsRef') @ViewChildren('selectAllInThisTabsRef')
selectAllInThisTabsRef: QueryList<ElementRef<HTMLInputElement>>; selectAllInThisTabsRef!: QueryList<ElementRef<HTMLInputElement>>;
@ViewChildren('selectAllInAllTabsRef') @ViewChildren('selectAllInAllTabsRef')
selectAllInAllTabsRef: QueryList<ElementRef<HTMLInputElement>>; selectAllInAllTabsRef!: QueryList<ElementRef<HTMLInputElement>>;
data: GetPermissionListResultDto = { groups: [], entityDisplayName: null }; data: GetPermissionListResultDto = { groups: [], entityDisplayName: '' };
selectedGroup: PermissionGroupDto; selectedGroup?: PermissionGroupDto | null;
permissions: PermissionWithGroupName[] = []; permissions: PermissionWithGroupName[] = [];
@ -119,16 +119,16 @@ export class PermissionManagementComponent
(document.body.dir as LocaleDirection) === 'rtl' ? 'right' : 'left' (document.body.dir as LocaleDirection) === 'rtl' ? 'right' : 'left'
}.px`; }.px`;
const permissions = this.data.groups.find( const permissions =
group => group.name === this.selectedGroup.name, (this.data.groups.find(group => group.name === this.selectedGroup?.name) || {}).permissions ||
).permissions; [];
return permissions.map( return permissions.map(
permission => permission =>
({ ({
...permission, ...permission,
style: { [margin]: findMargin(permissions, permission) }, style: { [margin]: findMargin(permissions, permission) },
isGranted: this.permissions.find(per => per.name === permission.name).isGranted, isGranted: (this.permissions.find(per => per.name === permission.name) || {}).isGranted,
} as unknown as PermissionWithStyle), } as unknown as PermissionWithStyle),
); );
} }
@ -158,7 +158,7 @@ export class PermissionManagementComponent
return false; return false;
} }
onClickCheckbox(clickedPermission: PermissionGrantInfoDto, value) { onClickCheckbox(clickedPermission: PermissionGrantInfoDto) {
if ( if (
clickedPermission.isGranted && clickedPermission.isGranted &&
this.isGrantedByOtherProviderName(clickedPermission.grantedProviders) this.isGrantedByOtherProviderName(clickedPermission.grantedProviders)
@ -257,7 +257,7 @@ export class PermissionManagementComponent
const changedPermissions: UpdatePermissionDto[] = this.permissions const changedPermissions: UpdatePermissionDto[] = this.permissions
.filter(per => .filter(per =>
unchangedPermissions.find(unchanged => unchanged.name === per.name).isGranted === (unchangedPermissions.find(unchanged => unchanged.name === per.name) || {}).isGranted ===
per.isGranted per.isGranted
? false ? false
: true, : true,
@ -305,7 +305,7 @@ export class PermissionManagementComponent
initModal() { initModal() {
// TODO: Refactor // TODO: Refactor
setTimeout(() => { setTimeout(() => {
this.setDisabled(this.selectedGroup.permissions); this.setDisabled(this.selectedGroup?.permissions || []);
this.setTabCheckboxState(); this.setTabCheckboxState();
this.setGrantCheckboxState(); this.setGrantCheckboxState();
}); });
@ -329,7 +329,10 @@ export class PermissionManagementComponent
} }
} }
function findMargin(permissions: PermissionGrantInfoDto[], permission: PermissionGrantInfoDto) { function findMargin(
permissions: PermissionGrantInfoDto[],
permission: PermissionGrantInfoDto,
): number {
const parentPermission = permissions.find(per => per.name === permission.parentName); const parentPermission = permissions.find(per => per.name === permission.parentName);
if (parentPermission && parentPermission.parentName) { if (parentPermission && parentPermission.parentName) {
@ -342,7 +345,10 @@ function findMargin(permissions: PermissionGrantInfoDto[], permission: Permissio
function getPermissions(groups: PermissionGroupDto[]): PermissionWithGroupName[] { function getPermissions(groups: PermissionGroupDto[]): PermissionWithGroupName[] {
return groups.reduce( return groups.reduce(
(acc, val) => [...acc, ...val.permissions.map(p => ({ ...p, groupName: val.name }))], (acc, val) => [
[], ...acc,
...val.permissions.map<PermissionWithGroupName>(p => ({ ...p, groupName: val.name || '' })),
],
[] as PermissionWithGroupName[],
); );
} }

14
npm/ng-packs/packages/theme-shared/extensions/src/lib/adapters/date-time.adapter.ts

@ -3,9 +3,9 @@ import { NgbDateStruct, NgbTimeStruct } from '@ng-bootstrap/ng-bootstrap';
@Injectable() @Injectable()
export class DateTimeAdapter { export class DateTimeAdapter {
value!: NgbDateTimeStruct; value!: Partial<NgbDateTimeStruct>;
fromModel(value: string | Date): NgbDateTimeStruct | null { fromModel(value: string | Date): Partial<NgbDateTimeStruct> | null {
if (!value) return null; if (!value) return null;
const date = new Date(value); const date = new Date(value);
@ -24,12 +24,12 @@ export class DateTimeAdapter {
return this.value; return this.value;
} }
toModel(value: NgbDateTimeStruct | null): string { toModel(value: Partial<NgbDateTimeStruct> | null): string {
if (!value) return ''; if (!value) return '';
const now = new Date(); const now = new Date();
value = { const newValue = {
// TODO look for strict mode errors // TODO look for strict mode errors
year: now.getUTCFullYear(), year: now.getUTCFullYear(),
month: now.getMonth() + 1, month: now.getMonth() + 1,
@ -39,11 +39,11 @@ export class DateTimeAdapter {
second: 0, second: 0,
...this.value, ...this.value,
...value, ...value,
}; } as NgbDateTimeStruct;
const date = new Date( const date = new Date(
value.year, newValue.year,
value.month - 1, newValue.month - 1,
value.day, value.day,
value.hour, value.hour,
value.minute, value.minute,

8
npm/ng-packs/packages/theme-shared/extensions/src/lib/components/abstract-actions/abstract-actions.component.ts

@ -1,5 +1,5 @@
import { Directive, Injector, Input } from '@angular/core'; import { Directive, Injector, Input } from '@angular/core';
import { ActionData, ActionList } from '../../models/actions'; import { ActionData, ActionList, InferredAction } from '../../models/actions';
import { ExtensionsService } from '../../services/extensions.service'; import { ExtensionsService } from '../../services/extensions.service';
import { EXTENSIONS_ACTION_TYPE, EXTENSIONS_IDENTIFIER } from '../../tokens/extensions.token'; import { EXTENSIONS_ACTION_TYPE, EXTENSIONS_IDENTIFIER } from '../../tokens/extensions.token';
import { InferredData, InferredRecord } from '../../models/toolbar-actions'; import { InferredData, InferredRecord } from '../../models/toolbar-actions';
@ -7,9 +7,9 @@ import { InferredData, InferredRecord } from '../../models/toolbar-actions';
// Fix for https://github.com/angular/angular/issues/23904 // Fix for https://github.com/angular/angular/issues/23904
// @dynamic // @dynamic
@Directive() @Directive()
export abstract class AbstractActionsComponent<L extends ActionList<any>> extends ActionData< export abstract class AbstractActionsComponent<
InferredRecord<L> L extends ActionList<any, InferredAction<L>>,
> { > extends ActionData<InferredRecord<L>> {
readonly actionList: L; readonly actionList: L;
readonly getInjected: InferredData<L>['getInjected']; readonly getInjected: InferredData<L>['getInjected'];

6
npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form-prop.component.ts

@ -57,7 +57,7 @@ export class ExtensibleFormPropComponent implements OnChanges, AfterViewInit {
@ViewChild('field') private fieldRef!: ElementRef<HTMLElement>; @ViewChild('field') private fieldRef!: ElementRef<HTMLElement>;
public injectorForCustomComponent: Injector; public injectorForCustomComponent?: Injector;
asterisk = ''; asterisk = '';
@ -95,7 +95,7 @@ export class ExtensibleFormPropComponent implements OnChanges, AfterViewInit {
? text$.pipe( ? text$.pipe(
debounceTime(300), debounceTime(300),
distinctUntilChanged(), distinctUntilChanged(),
switchMap(text => this.prop.options(this.data, text)), switchMap(text => this.prop?.options?.(this.data, text) || of([])),
) )
: of([]); : of([]);
@ -109,7 +109,7 @@ export class ExtensibleFormPropComponent implements OnChanges, AfterViewInit {
get isInvalid() { get isInvalid() {
const control = this.form.get(this.prop.name); const control = this.form.get(this.prop.name);
return control.touched && control.invalid; return control?.touched && control.invalid;
} }
constructor( constructor(

2
npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form.component.ts

@ -44,7 +44,7 @@ export class ExtensibleFormComponent<R = any> {
} }
extraPropertiesKey = EXTRA_PROPERTIES_KEY; extraPropertiesKey = EXTRA_PROPERTIES_KEY;
groupedPropList: GroupedFormPropList; groupedPropList!: GroupedFormPropList;
record!: R; record!: R;
createGroupedList(propList: FormPropList<R>) { createGroupedList(propList: FormPropList<R>) {

24
npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-table/extensible-table.component.ts

@ -48,7 +48,7 @@ const DEFAULT_ACTIONS_COLUMN_WIDTH = 150;
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ExtensibleTableComponent<R = any> implements OnChanges { export class ExtensibleTableComponent<R = any> implements OnChanges {
protected _actionsText: string; protected _actionsText!: string;
@Input() @Input()
set actionsText(value: string) { set actionsText(value: string) {
this._actionsText = value; this._actionsText = value;
@ -57,13 +57,13 @@ export class ExtensibleTableComponent<R = any> implements OnChanges {
return this._actionsText ?? (this.actionList.length > 1 ? 'AbpUi::Actions' : ''); return this._actionsText ?? (this.actionList.length > 1 ? 'AbpUi::Actions' : '');
} }
@Input() data: R[]; @Input() data!: R[];
@Input() list: ListService; @Input() list!: ListService;
@Input() recordsTotal: number; @Input() recordsTotal!: number;
@Input() set actionsColumnWidth(width: number) { @Input() set actionsColumnWidth(width: number) {
this.setColumnWidths(width ? Number(width) : undefined); this.setColumnWidths(width ? Number(width) : undefined);
} }
@Input() actionsTemplate: TemplateRef<any>; @Input() actionsTemplate?: TemplateRef<any>;
@Output() tableActivate = new EventEmitter(); @Output() tableActivate = new EventEmitter();
@ -73,7 +73,7 @@ export class ExtensibleTableComponent<R = any> implements OnChanges {
entityPropTypeClasses: EntityPropTypeClass; entityPropTypeClasses: EntityPropTypeClass;
readonly columnWidths: number[]; readonly columnWidths!: number[];
readonly propList: EntityPropList<R>; readonly propList: EntityPropList<R>;
@ -102,7 +102,7 @@ export class ExtensibleTableComponent<R = any> implements OnChanges {
this.setColumnWidths(DEFAULT_ACTIONS_COLUMN_WIDTH); this.setColumnWidths(DEFAULT_ACTIONS_COLUMN_WIDTH);
} }
private setColumnWidths(actionsColumn: number) { private setColumnWidths(actionsColumn: number | undefined) {
const widths = [actionsColumn]; const widths = [actionsColumn];
this.propList.forEach(({ value: prop }) => { this.propList.forEach(({ value: prop }) => {
widths.push(prop.columnWidth); widths.push(prop.columnWidth);
@ -110,8 +110,8 @@ export class ExtensibleTableComponent<R = any> implements OnChanges {
(this.columnWidths as any) = widths; (this.columnWidths as any) = widths;
} }
private getDate(value: Date, format: string) { private getDate(value: Date | undefined, format: string | undefined) {
return value ? formatDate(value, format, this.locale) : ''; return value && format ? formatDate(value, format, this.locale) : '';
} }
private getIcon(value: boolean) { private getIcon(value: boolean) {
@ -122,7 +122,7 @@ export class ExtensibleTableComponent<R = any> implements OnChanges {
private getEnum(rowValue: any, list: Array<ABP.Option<any>>) { private getEnum(rowValue: any, list: Array<ABP.Option<any>>) {
if (!list) return rowValue; if (!list) return rowValue;
const { key } = list.find(({ value }) => value === rowValue); const { key } = list.find(({ value }) => value === rowValue) || {};
return key; return key;
} }
@ -139,7 +139,7 @@ export class ExtensibleTableComponent<R = any> implements OnChanges {
case ePropType.DateTime: case ePropType.DateTime:
return this.getDate(value, getShortDateShortTimeFormat(this.config)); return this.getDate(value, getShortDateShortTimeFormat(this.config));
case ePropType.Enum: case ePropType.Enum:
return this.getEnum(value, prop.enumList); return this.getEnum(value, prop.enumList || []);
default: default:
return value; return value;
// More types can be handled in the future // More types can be handled in the future
@ -151,7 +151,7 @@ export class ExtensibleTableComponent<R = any> implements OnChanges {
ngOnChanges({ data }: SimpleChanges) { ngOnChanges({ data }: SimpleChanges) {
if (!data?.currentValue) return; if (!data?.currentValue) return;
this.data = data.currentValue.map((record, index) => { this.data = data.currentValue.map((record: any, index: number) => {
this.propList.forEach(prop => { this.propList.forEach(prop => {
const propData = { getInjected: this.getInjected, record, index } as any; const propData = { getInjected: this.getInjected, record, index } as any;
const value = this.getContent(prop.value, propData); const value = this.getContent(prop.value, propData);

2
npm/ng-packs/packages/theme-shared/extensions/src/lib/components/grid-actions/grid-actions.component.ts

@ -24,7 +24,7 @@ import { AbstractActionsComponent } from '../abstract-actions/abstract-actions.c
export class GridActionsComponent<R = any> extends AbstractActionsComponent<EntityActionList<R>> { export class GridActionsComponent<R = any> extends AbstractActionsComponent<EntityActionList<R>> {
@Input() icon = 'fa fa-cog'; @Input() icon = 'fa fa-cog';
@Input() readonly index: number; @Input() readonly index?: number;
@Input() text = ''; @Input() text = '';

20
npm/ng-packs/packages/theme-shared/extensions/src/lib/components/page-toolbar/page-toolbar.component.html

@ -13,15 +13,17 @@
</ng-container> </ng-container>
<ng-template #button> <ng-template #button>
<button <ng-container *ngIf="asToolbarAction(action).value as toolbarAction">
(click)="action.action(data)" <button
type="button" (click)="action.action(data)"
[ngClass]="action.btnClass ? action.btnClass : defaultBtnClass" type="button"
class="d-inline-flex align-items-center gap-1" [ngClass]="toolbarAction.btnClass ? toolbarAction.btnClass : defaultBtnClass"
> class="d-inline-flex align-items-center gap-1"
<i [ngClass]="action.icon" [class.me-1]="action.icon"></i> >
{{ action.text | abpLocalization }} <i [ngClass]="toolbarAction.icon" [class.me-1]="toolbarAction.icon"></i>
</button> {{ toolbarAction.text | abpLocalization }}
</button>
</ng-container>
</ng-template> </ng-template>
</ng-container> </ng-container>
</ng-container> </ng-container>

8
npm/ng-packs/packages/theme-shared/extensions/src/lib/components/page-toolbar/page-toolbar.component.ts

@ -1,6 +1,8 @@
import { ChangeDetectionStrategy, Component, Injector, TrackByFunction } from '@angular/core'; import { ChangeDetectionStrategy, Component, Injector, TrackByFunction } from '@angular/core';
import { import {
HasCreateInjectorPipe, HasCreateInjectorPipe,
ToolbarAction,
ToolbarActionDefault,
ToolbarActionList, ToolbarActionList,
ToolbarComponent, ToolbarComponent,
} from '../../models/toolbar-actions'; } from '../../models/toolbar-actions';
@ -32,4 +34,10 @@ export class PageToolbarComponent<R = any>
constructor(public readonly injector: Injector) { constructor(public readonly injector: Injector) {
super(injector); super(injector);
} }
asToolbarAction(value: ToolbarActionDefault): { value: ToolbarAction } {
return {
value: value as ToolbarAction,
};
}
} }

17
npm/ng-packs/packages/theme-shared/extensions/src/lib/models/actions.ts

@ -1,5 +1,5 @@
import { LinkedList } from '@abp/utils'; import { LinkedList } from '@abp/utils';
import { InjectFlags, InjectionToken, Type } from '@angular/core'; import { InjectFlags, InjectionToken, InjectOptions, Type } from '@angular/core';
import { O } from 'ts-toolbelt'; import { O } from 'ts-toolbelt';
export abstract class ActionList<R = any, A = Action<R>> extends LinkedList<A> {} export abstract class ActionList<R = any, A = Action<R>> extends LinkedList<A> {}
@ -8,7 +8,7 @@ export abstract class ActionData<R = any> {
abstract getInjected: <T>( abstract getInjected: <T>(
token: Type<T> | InjectionToken<T>, token: Type<T> | InjectionToken<T>,
notFoundValue?: T, notFoundValue?: T,
flags?: InjectFlags, flags?: InjectOptions | InjectFlags,
) => T; ) => T;
index?: number; index?: number;
abstract record: R; abstract record: R;
@ -27,8 +27,8 @@ export type ReadonlyActionData<R = any> = O.Readonly<Omit<ActionData<R>, 'data'>
export abstract class Action<R = any> { export abstract class Action<R = any> {
constructor( constructor(
public readonly permission: string, public readonly permission: string,
public readonly visible: ActionPredicate<R> = _ => true, public readonly visible: ActionPredicate<R> = () => true,
public readonly action: ActionCallback<R> = _ => {}, public readonly action: ActionCallback<R> = () => {},
) {} ) {}
} }
@ -46,7 +46,7 @@ export abstract class ActionsFactory<C extends Actions<any>> {
} }
} }
export abstract class Actions<L extends ActionList> { export abstract class Actions<L extends ActionList<any, InferredAction<L>>> {
protected abstract _ctor: Type<L>; protected abstract _ctor: Type<L>;
get actions(): L { get actions(): L {
@ -68,11 +68,14 @@ export abstract class Actions<L extends ActionList> {
} }
} }
export type ActionContributorCallbacks<L extends ActionList<any>> = Record< export type ActionContributorCallbacks<L extends ActionList<any, InferredAction<L>>> = Record<
string, string,
ActionContributorCallback<L>[] ActionContributorCallback<L>[]
>; >;
export type ActionContributorCallback<L extends ActionList<any>> = (actionList: L) => any; export type ActionContributorCallback<L extends ActionList<any, InferredAction<L>>> = (
actionList: L,
) => any;
type InferredActionList<C> = C extends Actions<infer L> ? L : never; type InferredActionList<C> = C extends Actions<infer L> ? L : never;
export type InferredAction<T> = T extends ActionList<any, infer U> ? U : T;

2
npm/ng-packs/packages/theme-shared/extensions/src/lib/models/entity-actions.ts

@ -24,7 +24,7 @@ export class EntityAction<R = any> extends Action<R> {
readonly icon: string; readonly icon: string;
constructor(options: EntityActionOptions<R>) { constructor(options: EntityActionOptions<R>) {
super(options.permission, options.visible, options.action); super(options.permission || '', options.visible, options.action);
this.text = options.text; this.text = options.text;
this.icon = options.icon || ''; this.icon = options.icon || '';
} }

26
npm/ng-packs/packages/theme-shared/extensions/src/lib/models/entity-props.ts

@ -27,16 +27,16 @@ export class EntityProp<R = any> extends Prop<R> {
readonly columnWidth: number | undefined; readonly columnWidth: number | undefined;
readonly sortable: boolean; readonly sortable: boolean;
readonly valueResolver: PropCallback<R, Observable<any>>; readonly valueResolver: PropCallback<R, Observable<any>>;
readonly action: ActionCallback<R>; readonly action?: ActionCallback<R>;
readonly component: Type<any>; readonly component?: Type<any>;
readonly enumList: Array<ABP.Option<any>>; readonly enumList?: Array<ABP.Option<any>>;
constructor(options: EntityPropOptions<R>) { constructor(options: EntityPropOptions<R>) {
super( super(
options.type, options.type,
options.name, options.name,
options.displayName, options.displayName || '',
options.permission, options.permission || '',
options.visible, options.visible,
options.isExtra, options.isExtra,
); );
@ -44,10 +44,17 @@ export class EntityProp<R = any> extends Prop<R> {
this.columnWidth = options.columnWidth; this.columnWidth = options.columnWidth;
this.sortable = options.sortable || false; this.sortable = options.sortable || false;
this.valueResolver = this.valueResolver =
options.valueResolver || (data => of(escapeHtmlChars(data.record[this.name]))); options.valueResolver ||
this.action = options.action; (data => of(escapeHtmlChars((data.record as PropDataObject)[this.name])));
this.component = options.component; if (options.action) {
this.enumList = options.enumList; this.action = options.action;
}
if (options.component) {
this.component = options.component;
}
if (options.enumList) {
this.enumList = options.enumList;
}
} }
static create<R = any>(options: EntityPropOptions<R>) { static create<R = any>(options: EntityPropOptions<R>) {
@ -76,3 +83,4 @@ export type EntityPropOptions<R = any> = O.Optional<
export type EntityPropDefaults<R = any> = Record<string, EntityProp<R>[]>; export type EntityPropDefaults<R = any> = Record<string, EntityProp<R>[]>;
export type EntityPropContributorCallback<R = any> = PropContributorCallback<EntityPropList<R>>; export type EntityPropContributorCallback<R = any> = PropContributorCallback<EntityPropList<R>>;
export type EntityPropContributorCallbacks<R = any> = PropContributorCallbacks<EntityPropList<R>>; export type EntityPropContributorCallbacks<R = any> = PropContributorCallbacks<EntityPropList<R>>;
type PropDataObject = { [key: string]: any };

12
npm/ng-packs/packages/theme-shared/extensions/src/lib/models/form-props.ts

@ -18,7 +18,7 @@ import {
export class FormPropList<R = any> extends PropList<R, FormProp<R>> {} export class FormPropList<R = any> extends PropList<R, FormProp<R>> {}
export class FormProps<R = any> extends Props<FormPropList<R>> { export class FormProps<R = any> extends Props<PropList<R, FormProp<R>>> {
protected _ctor: Type<FormPropList<R>> = FormPropList; protected _ctor: Type<FormPropList<R>> = FormPropList;
} }
@ -46,7 +46,7 @@ export class GroupedFormPropList<R = any> {
} }
export interface GroupedFormPropItem { export interface GroupedFormPropItem {
group: FormPropGroup; group?: FormPropGroup;
formPropList: FormPropList; formPropList: FormPropList;
} }
@ -76,8 +76,8 @@ export class FormProp<R = any> extends Prop<R> {
super( super(
options.type, options.type,
options.name, options.name,
options.displayName, options.displayName || '',
options.permission, options.permission || '',
options.visible, options.visible,
options.isExtra, options.isExtra,
options.template, options.template,
@ -94,7 +94,7 @@ export class FormProp<R = any> extends Prop<R> {
this.options = options.options; this.options = options.options;
this.id = options.id || options.name; this.id = options.id || options.name;
const defaultValue = options.defaultValue; const defaultValue = options.defaultValue;
this.defaultValue = isFalsyValue(defaultValue) ? defaultValue : defaultValue || null; this.defaultValue = isFalsyValue(defaultValue) ? (defaultValue as number) : defaultValue || '';
this.displayTextResolver = options.displayTextResolver; this.displayTextResolver = options.displayTextResolver;
} }
@ -141,6 +141,6 @@ export type EditFormPropDefaults<R = any> = Record<string, FormProp<R>[]>;
export type EditFormPropContributorCallback<R = any> = PropContributorCallback<FormPropList<R>>; export type EditFormPropContributorCallback<R = any> = PropContributorCallback<FormPropList<R>>;
export type EditFormPropContributorCallbacks<R = any> = PropContributorCallbacks<FormPropList<R>>; export type EditFormPropContributorCallbacks<R = any> = PropContributorCallbacks<FormPropList<R>>;
function isFalsyValue(defaultValue: FormProp['defaultValue']): boolean { function isFalsyValue(defaultValue?: FormProp['defaultValue']): boolean {
return [0, '', false].indexOf(defaultValue as any) > -1; return [0, '', false].indexOf(defaultValue as any) > -1;
} }

2
npm/ng-packs/packages/theme-shared/extensions/src/lib/models/internal/object-extensions.ts

@ -6,7 +6,7 @@ import { PropContributorCallbacks } from '../props';
export type DisplayNameGeneratorFn = ( export type DisplayNameGeneratorFn = (
displayName: LocalizableStringDto, displayName: LocalizableStringDto,
fallback: LocalizableStringDto, fallback: LocalizableStringDto,
) => string; ) => string | undefined;
export type EntityExtensions = Record<string, EntityExtensionDto>; export type EntityExtensions = Record<string, EntityExtensionDto>;

9
npm/ng-packs/packages/theme-shared/extensions/src/lib/models/props.ts

@ -56,7 +56,7 @@ export abstract class PropsFactory<C extends Props<any>> {
} }
} }
export abstract class Props<L extends PropList> { export abstract class Props<L extends PropList<any, InferredProp<L>>> {
protected abstract _ctor: Type<L>; protected abstract _ctor: Type<L>;
get props(): L { get props(): L {
@ -78,11 +78,14 @@ export abstract class Props<L extends PropList> {
} }
} }
export type PropContributorCallbacks<L extends PropList<any>> = Record< export type PropContributorCallbacks<L extends PropList<any, InferredProp<L>>> = Record<
string, string,
PropContributorCallback<L>[] PropContributorCallback<L>[]
>; >;
export type PropContributorCallback<L extends PropList<any>> = (propList: L) => any; export type PropContributorCallback<L extends PropList<any, InferredProp<L>>> = (
propList: L,
) => any;
type InferredPropList<C> = C extends Props<infer L> ? L : never; type InferredPropList<C> = C extends Props<infer L> ? L : never;
export type InferredProp<T> = T extends PropList<any, infer U> ? U : T;

7
npm/ng-packs/packages/theme-shared/extensions/src/lib/models/toolbar-actions.ts

@ -11,10 +11,7 @@ import {
ReadonlyActionData, ReadonlyActionData,
} from './actions'; } from './actions';
export class ToolbarActionList<R = any> extends ActionList< export class ToolbarActionList<R = any> extends ActionList<R, ToolbarActionDefault<R>> {}
R,
ToolbarAction<R> | ToolbarComponent<R>
> {}
export class ToolbarActions<R = any> extends Actions<ToolbarActionList<R>> { export class ToolbarActions<R = any> extends Actions<ToolbarActionList<R>> {
protected _ctor: Type<ToolbarActionList<R>> = ToolbarActionList; protected _ctor: Type<ToolbarActionList<R>> = ToolbarActionList;
@ -84,7 +81,7 @@ export type ToolbarActionContributorCallbacks<R = any> = ActionContributorCallba
ToolbarActionList<R> ToolbarActionList<R>
>; >;
export type InferredData<L> = ActionData<InferredRecord<L>>; export type InferredData<L> = ActionData<InferredRecord<L>>;
export type InferredRecord<L> = L extends ActionList<infer R> ? R : never; export type InferredRecord<L> = L extends ActionList<infer R> ? R : any;
export interface HasCreateInjectorPipe<R> { export interface HasCreateInjectorPipe<R> {
getData: () => ReadonlyActionData<R>; getData: () => ReadonlyActionData<R>;

2
npm/ng-packs/packages/theme-shared/extensions/src/lib/pipes/create-injector.pipe.ts

@ -25,7 +25,7 @@ export class CreateInjectorPipe<R> implements PipeTransform {
options?: InjectOptions | InjectFlags, options?: InjectOptions | InjectFlags,
) => { ) => {
const componentData = context.getData(); const componentData = context.getData();
const componentDataCallback = data => { const componentDataCallback = (data: any) => {
data = data ?? context.getData(); data = data ?? context.getData();
return action.action(data); return action.action(data);
}; };

4
npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/actions.util.ts

@ -1,4 +1,4 @@
import { ActionContributorCallback, ActionList, ActionsFactory } from '../models/actions'; import { ActionContributorCallback, ActionList, ActionsFactory, InferredAction } from "../models/actions";
import { import {
EntityActionContributorCallbacks, EntityActionContributorCallbacks,
EntityActionDefaults, EntityActionDefaults,
@ -20,7 +20,7 @@ export function mergeWithDefaultActions<F extends ActionsFactory<any>>(
Object.keys(defaultActions).forEach((name: string) => { Object.keys(defaultActions).forEach((name: string) => {
const actions: InferredActions<F> = extension.get(name); const actions: InferredActions<F> = extension.get(name);
actions.clearContributors(); actions.clearContributors();
actions.addContributor((actionList: ActionList) => actions.addContributor((actionList: ActionList<any, InferredAction<any>>) =>
actionList.addManyTail(defaultActions[name]), actionList.addManyTail(defaultActions[name]),
); );
contributors.forEach(contributor => contributors.forEach(contributor =>

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save