diff --git a/npm/ng-packs/package.json b/npm/ng-packs/package.json index e45e1d255c..edbdbe9fc1 100644 --- a/npm/ng-packs/package.json +++ b/npm/ng-packs/package.json @@ -106,7 +106,7 @@ "jest-preset-angular": "^12.2.2", "jsonc-parser": "^2.3.0", "just-clone": "^6.1.1", - "just-compare": "^1.4.0", + "just-compare": "^2.3.0", "lerna": "^4.0.0", "lint-staged": "^13.0.3", "ng-packagr": "15.0.1", diff --git a/npm/ng-packs/packages/account-core/src/lib/tenant-box.service.ts b/npm/ng-packs/packages/account-core/src/lib/tenant-box.service.ts index b59191f3d1..bcb37c3d48 100644 --- a/npm/ng-packs/packages/account-core/src/lib/tenant-box.service.ts +++ b/npm/ng-packs/packages/account-core/src/lib/tenant-box.service.ts @@ -12,22 +12,22 @@ import { finalize } from 'rxjs/operators'; export class TenantBoxService { currentTenant$ = this.sessionState.getTenant$(); - name: string; + name?: string; - isModalVisible: boolean; + isModalVisible!: boolean; - modalBusy: boolean; + modalBusy!: boolean; constructor( private toasterService: ToasterService, private tenantService: AbpTenantService, private sessionState: SessionStateService, private configState: ConfigStateService, - ) { } + ) {} onSwitch() { const tenant = this.sessionState.getTenant(); - this.name = tenant?.name; + this.name = tenant?.name || ''; this.isModalVisible = true; } @@ -53,14 +53,14 @@ export class TenantBoxService { }); } - private setTenant(tenant: CurrentTenantDto) { + private setTenant(tenant: CurrentTenantDto | null) { this.sessionState.setTenant(tenant); this.configState.refreshAppState(); } private showError() { this.toasterService.error('AbpUiMultiTenancy::GivenTenantIsNotAvailable', 'AbpUi::Error', { - messageLocalizationParams: [this.name], + messageLocalizationParams: [this.name || ''], }); } } diff --git a/npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.ts b/npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.ts index 13fcfb6b7b..1656694781 100644 --- a/npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.ts +++ b/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 { getPasswordValidators, ToasterService } from '@abp/ng.theme.shared'; 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 { finalize } from 'rxjs/operators'; import { Account } from '../../models/account'; @@ -19,14 +24,14 @@ const PASSWORD_FIELDS = ['newPassword', 'repeatNewPassword']; export class ChangePasswordComponent implements OnInit, Account.ChangePasswordComponentInputs, Account.ChangePasswordComponentOutputs { - form: UntypedFormGroup; + form!: UntypedFormGroup; - inProgress: boolean; + inProgress?: boolean; - hideCurrentPassword: boolean; + hideCurrentPassword?: boolean; 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')); }; @@ -73,8 +78,8 @@ export class ChangePasswordComponent this.inProgress = true; this.profileService .changePassword({ - ...(!this.hideCurrentPassword && { currentPassword: this.form.get('password').value }), - newPassword: this.form.get('newPassword').value, + ...(!this.hideCurrentPassword && { currentPassword: this.form.get('password')?.value }), + newPassword: this.form.get('newPassword')?.value, }) .pipe(finalize(() => (this.inProgress = false))) .subscribe({ diff --git a/npm/ng-packs/packages/account/src/lib/components/forgot-password/forgot-password.component.ts b/npm/ng-packs/packages/account/src/lib/components/forgot-password/forgot-password.component.ts index c69fa0082c..e1f460df5a 100644 --- a/npm/ng-packs/packages/account/src/lib/components/forgot-password/forgot-password.component.ts +++ b/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 { form: UntypedFormGroup; - inProgress: boolean; + inProgress?: boolean; isEmailSent = false; @@ -27,7 +27,7 @@ export class ForgotPasswordComponent { this.accountService .sendPasswordResetCode({ - email: this.form.get('email').value, + email: this.form.get('email')?.value, appName: 'Angular', }) .pipe(finalize(() => (this.inProgress = false))) diff --git a/npm/ng-packs/packages/account/src/lib/components/login/login.component.ts b/npm/ng-packs/packages/account/src/lib/components/login/login.component.ts index 65d759861b..4ea5401092 100644 --- a/npm/ng-packs/packages/account/src/lib/components/login/login.component.ts +++ b/npm/ng-packs/packages/account/src/lib/components/login/login.component.ts @@ -14,9 +14,9 @@ const { maxLength, required } = Validators; templateUrl: './login.component.html', }) export class LoginComponent implements OnInit { - form: UntypedFormGroup; + form!: UntypedFormGroup; - inProgress: boolean; + inProgress?: boolean; isSelfRegistrationEnabled = true; @@ -67,7 +67,7 @@ export class LoginComponent implements OnInit { err.error?.error_description || err.error?.error.message || 'AbpAccount::DefaultErrorMessage', - null, + '', { life: 7000 }, ); return throwError(err); diff --git a/npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.ts b/npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.ts index a10174b2ac..2e31176245 100644 --- a/npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.ts +++ b/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$(); - hideChangePasswordTab: boolean; + hideChangePasswordTab?: boolean; constructor( protected profileService: ProfileService, diff --git a/npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings-half-row.component.ts b/npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings-half-row.component.ts index 6ee50eb33b..1a58950a85 100644 --- a/npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings-half-row.component.ts +++ b/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 name: string; public id: string; - public formGroup: UntypedFormGroup; + public formGroup!: UntypedFormGroup; constructor(@Inject(EXTENSIONS_FORM_PROP) private propData: FormProp) { this.displayName = propData.displayName; this.name = propData.name; - this.id = propData.id; + this.id = propData.id || ''; } } diff --git a/npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings.component.ts b/npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings.component.ts index 32e5b1e7ab..f41058d06c 100644 --- a/npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings.component.ts +++ b/npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings.component.ts @@ -31,11 +31,11 @@ export class PersonalSettingsComponent Account.PersonalSettingsComponentInputs, Account.PersonalSettingsComponentOutputs { - selected: ProfileDto; + selected?: ProfileDto; - form: UntypedFormGroup; + form!: UntypedFormGroup; - inProgress: boolean; + inProgress?: boolean; constructor( private fb: UntypedFormBuilder, diff --git a/npm/ng-packs/packages/account/src/lib/components/register/register.component.ts b/npm/ng-packs/packages/account/src/lib/components/register/register.component.ts index 9855f9a283..b535f51fcb 100644 --- a/npm/ng-packs/packages/account/src/lib/components/register/register.component.ts +++ b/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', }) export class RegisterComponent implements OnInit { - form: UntypedFormGroup; + form!: UntypedFormGroup; - inProgress: boolean; + inProgress?: boolean; isSelfRegistrationEnabled = true; @@ -48,7 +48,7 @@ export class RegisterComponent implements OnInit { key: 'AbpAccount::SelfRegistrationDisabledMessage', defaultValue: 'Self registration is disabled.', }, - null, + '', { life: 10000 }, ); return; @@ -69,9 +69,9 @@ export class RegisterComponent implements OnInit { this.inProgress = true; const newUser = { - userName: this.form.get('username').value, - password: this.form.get('password').value, - emailAddress: this.form.get('email').value, + userName: this.form.get('username')?.value, + password: this.form.get('password')?.value, + emailAddress: this.form.get('email')?.value, appName: 'Angular', } as RegisterDto; @@ -90,7 +90,7 @@ export class RegisterComponent implements OnInit { err.error?.error_description || err.error?.error.message || 'AbpAccount::DefaultErrorMessage', - null, + '', { life: 7000 }, ); diff --git a/npm/ng-packs/packages/account/src/lib/components/reset-password/reset-password.component.ts b/npm/ng-packs/packages/account/src/lib/components/reset-password/reset-password.component.ts index 0bcb8a0d8a..8e93b75c06 100644 --- a/npm/ng-packs/packages/account/src/lib/components/reset-password/reset-password.component.ts +++ b/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', }) export class ResetPasswordComponent implements OnInit { - form: UntypedFormGroup; + form!: UntypedFormGroup; inProgress = false; isPasswordReset = false; 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')); }; @@ -58,9 +58,9 @@ export class ResetPasswordComponent implements OnInit { this.accountService .resetPassword({ - userId: this.form.get('userId').value, - resetToken: this.form.get('resetToken').value, - password: this.form.get('password').value, + userId: this.form.get('userId')?.value, + resetToken: this.form.get('resetToken')?.value, + password: this.form.get('password')?.value, }) .pipe(finalize(() => (this.inProgress = false))) .subscribe(() => { diff --git a/npm/ng-packs/packages/components/chart.js/src/chart.component.ts b/npm/ng-packs/packages/components/chart.js/src/chart.component.ts index 2ac9e1d057..ac839d86c4 100644 --- a/npm/ng-packs/packages/components/chart.js/src/chart.component.ts +++ b/npm/ng-packs/packages/components/chart.js/src/chart.component.ts @@ -35,7 +35,7 @@ let Chart: any; exportAs: 'abpChart', }) export class ChartComponent implements AfterViewInit, OnDestroy, OnChanges { - @Input() type: string; + @Input() type!: string; @Input() data: any = {}; @@ -43,9 +43,9 @@ export class ChartComponent implements AfterViewInit, OnDestroy, OnChanges { @Input() plugins: any[] = []; - @Input() width: string; + @Input() width?: string; - @Input() height: string; + @Input() height?: string; @Input() responsive = true; @@ -53,7 +53,7 @@ export class ChartComponent implements AfterViewInit, OnDestroy, OnChanges { @Output() initialized = new EventEmitter(); - @ViewChild('canvas') canvas: ElementRef; + @ViewChild('canvas') canvas!: ElementRef; chart: any; @@ -67,7 +67,7 @@ export class ChartComponent implements AfterViewInit, OnDestroy, OnChanges { }); } - onCanvasClick(event) { + onCanvasClick(event: MouseEvent) { if (this.chart) { const element = this.chart.getElementsAtEventForMode( event, diff --git a/npm/ng-packs/packages/components/chart.js/src/widget-utils.ts b/npm/ng-packs/packages/components/chart.js/src/widget-utils.ts index 6e70e2cac5..e9511d6a75 100644 --- a/npm/ng-packs/packages/components/chart.js/src/widget-utils.ts +++ b/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 = []; for (let i = 0; i < count; i++) { diff --git a/npm/ng-packs/packages/components/page/src/page-part.directive.ts b/npm/ng-packs/packages/components/page/src/page-part.directive.ts index c228189e0f..e212cac63c 100644 --- a/npm/ng-packs/packages/components/page/src/page-part.directive.ts +++ b/npm/ng-packs/packages/components/page/src/page-part.directive.ts @@ -27,8 +27,8 @@ export const PAGE_RENDER_STRATEGY = new InjectionToken('PAGE @Directive({ selector: '[abpPagePart]' }) export class PagePartDirective implements OnInit, OnDestroy, OnChanges { hasRendered = false; - type: string; - subscription: Subscription; + type!: string; + subscription!: Subscription; @Input('abpPagePartContext') context: any; @Input() set abpPagePart(type: string) { diff --git a/npm/ng-packs/packages/components/page/src/page.component.html b/npm/ng-packs/packages/components/page/src/page.component.html index 543da2d6ff..5a4a5cc66c 100644 --- a/npm/ng-packs/packages/components/page/src/page.component.html +++ b/npm/ng-packs/packages/components/page/src/page.component.html @@ -25,7 +25,7 @@ - +
diff --git a/npm/ng-packs/packages/components/page/src/page.component.ts b/npm/ng-packs/packages/components/page/src/page.component.ts index 24b6d18ccf..d0a48b145c 100644 --- a/npm/ng-packs/packages/components/page/src/page.component.ts +++ b/npm/ng-packs/packages/components/page/src/page.component.ts @@ -12,11 +12,11 @@ import { encapsulation: ViewEncapsulation.None, }) export class PageComponent { - @Input() title: string; + @Input() title?: string; toolbarVisible = false; _toolbarData: any; - @Input('toolbar') set toolbarData(val: any) { + @Input() set toolbar(val: any) { this._toolbarData = val; this.toolbarVisible = true; } @@ -25,7 +25,7 @@ export class PageComponent { return this._toolbarData; } - @Input('breadcrumb') breadcrumbVisible = true; + @Input() breadcrumb = true; pageParts = { title: PageParts.title, @@ -33,16 +33,16 @@ export class PageComponent { toolbar: PageParts.toolbar, }; - @ContentChild(PageTitleContainerComponent) customTitle: PageTitleContainerComponent; + @ContentChild(PageTitleContainerComponent) customTitle?: PageTitleContainerComponent; @ContentChild(PageBreadcrumbContainerComponent) - customBreadcrumb: PageBreadcrumbContainerComponent; - @ContentChild(PageToolbarContainerComponent) customToolbar: PageToolbarContainerComponent; + customBreadcrumb?: PageBreadcrumbContainerComponent; + @ContentChild(PageToolbarContainerComponent) customToolbar?: PageToolbarContainerComponent; get shouldRenderRow() { return !!( this.title || this.toolbarVisible || - this.breadcrumbVisible || + this.breadcrumb || this.customTitle || this.customBreadcrumb || this.customToolbar diff --git a/npm/ng-packs/packages/core/locale/src/utils/register-locale.ts b/npm/ng-packs/packages/core/locale/src/utils/register-locale.ts index db5d5c6452..97a49066ec 100644 --- a/npm/ng-packs/packages/core/locale/src/utils/register-locale.ts +++ b/npm/ng-packs/packages/core/locale/src/utils/register-locale.ts @@ -8,7 +8,7 @@ export interface LocaleErrorHandlerData { locale: string; } -let localeMap = {}; +let localeMap = {} as { [key: string]: string }; export interface RegisterLocaleData { cultureNameLocaleFileMap?: Record; @@ -51,7 +51,7 @@ export function registerLocale( }; } -const extraLocales = {}; +const extraLocales = {} as { [key: string]: any }; export function storeLocaleData(data: any, localeId: string) { extraLocales[localeId] = data; } @@ -62,7 +62,7 @@ export async function defaultLocalErrorHandlerFn({ locale, resolve }: LocaleErro return; } - if (isDevMode) { + if (isDevMode()) { 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`, ); diff --git a/npm/ng-packs/packages/core/package.json b/npm/ng-packs/packages/core/package.json index 87ad0201f2..d670e09ca0 100644 --- a/npm/ng-packs/packages/core/package.json +++ b/npm/ng-packs/packages/core/package.json @@ -10,7 +10,7 @@ "@abp/utils": "~7.0.1", "angular-oauth2-oidc": "^15.0.1", "just-clone": "^6.1.1", - "just-compare": "^1.4.0", + "just-compare": "^2.3.0", "ts-toolbelt": "6.15.4", "tslib": "^2.0.0" }, diff --git a/npm/ng-packs/packages/core/src/lib/abstracts/ng-model.component.ts b/npm/ng-packs/packages/core/src/lib/abstracts/ng-model.component.ts index cb3fe34f98..0f0eaa3722 100644 --- a/npm/ng-packs/packages/core/src/lib/abstracts/ng-model.component.ts +++ b/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! @Component({ template: '' }) export class AbstractNgModelComponent implements ControlValueAccessor { - protected _value: T; + protected _value!: T; protected cdRef: ChangeDetectorRef; - onChange: (value: T) => void; - onTouched: () => void; + onChange?: (value: T) => void; + onTouched?: () => void; @Input() - disabled: boolean; + disabled?: boolean; @Input() - readonly: boolean; + readonly?: boolean; @Input() valueFn: (value: U, previousValue?: T) => T = value => value as any as T; diff --git a/npm/ng-packs/packages/core/src/lib/clients/http.client.ts b/npm/ng-packs/packages/core/src/lib/clients/http.client.ts index c6e9017be7..299593a970 100644 --- a/npm/ng-packs/packages/core/src/lib/clients/http.client.ts +++ b/npm/ng-packs/packages/core/src/lib/clients/http.client.ts @@ -15,7 +15,7 @@ export class ExternalHttpClient extends HttpClient { ): Observable { if (typeof first === 'string') { this.#setPlaceholderContext(options); - return super.request(first, url, options); + return super.request(first, url || '', options); } this.#setPlaceholderContext(first); diff --git a/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts b/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts index 5f39e5c865..5adaa0d768 100644 --- a/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts +++ b/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts @@ -17,8 +17,8 @@ import { TreeNode } from '../utils/tree-utils'; providers: [SubscriptionService], }) export class DynamicLayoutComponent { - layout: Type; - layoutKey: eLayoutType; + layout?: Type; + layoutKey?: eLayoutType; // TODO: Consider a shared enum (eThemeSharedComponents) for known layouts readonly layouts = new Map([ @@ -29,9 +29,9 @@ export class DynamicLayoutComponent { isLayoutVisible = true; - private router: Router; - private route: ActivatedRoute; - private routes: RoutesService; + private router!: Router; + private route!: ActivatedRoute; + private routes!: RoutesService; constructor( injector: Injector, @@ -42,7 +42,7 @@ export class DynamicLayoutComponent { @Optional() @SkipSelf() dynamicLayoutComponent: 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; } this.route = injector.get(ActivatedRoute); @@ -80,8 +80,10 @@ export class DynamicLayoutComponent { if (this.layoutKey === expectedLayout) return; const key = this.layouts.get(expectedLayout); - this.layout = this.getComponent(key)?.component; - this.layoutKey = expectedLayout; + if (key) { + this.layout = this.getComponent(key)?.component; + this.layoutKey = expectedLayout; + } if(!this.layout){ this.showLayoutNotFoundError(expectedLayout); } @@ -94,7 +96,7 @@ export class DynamicLayoutComponent { } console.warn(message); } - + private listenToLanguageChange() { 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); } } diff --git a/npm/ng-packs/packages/core/src/lib/components/replaceable-route-container.component.ts b/npm/ng-packs/packages/core/src/lib/components/replaceable-route-container.component.ts index 9d60fcda84..92d30fdff9 100644 --- a/npm/ng-packs/packages/core/src/lib/components/replaceable-route-container.component.ts +++ b/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], }) export class ReplaceableRouteContainerComponent implements OnInit { - defaultComponent: Type; + defaultComponent!: Type; - componentKey: string; + componentKey!: string; - externalComponent: Type; + externalComponent?: Type; constructor( private route: ActivatedRoute, diff --git a/npm/ng-packs/packages/core/src/lib/directives/debounce.directive.ts b/npm/ng-packs/packages/core/src/lib/directives/debounce.directive.ts index 431305738a..69a96f95f1 100644 --- a/npm/ng-packs/packages/core/src/lib/directives/debounce.directive.ts +++ b/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) {} ngOnInit(): void { - const input$ = fromEvent(this.el.nativeElement, 'input').pipe(debounceTime(this.debounce)); + const input$ = fromEvent(this.el.nativeElement, 'input').pipe( + debounceTime(this.debounce), + ); this.subscription.addOne(input$, (event: Event) => { this.debounceEvent.emit(event); diff --git a/npm/ng-packs/packages/core/src/lib/directives/for.directive.ts b/npm/ng-packs/packages/core/src/lib/directives/for.directive.ts index 3e17d0ac3c..1e37e1c908 100644 --- a/npm/ng-packs/packages/core/src/lib/directives/for.directive.ts +++ b/npm/ng-packs/packages/core/src/lib/directives/for.directive.ts @@ -38,32 +38,32 @@ class RecordView { export class ForDirective implements OnChanges { // eslint-disable-next-line @angular-eslint/no-input-rename @Input('abpForOf') - items: any[]; + items!: any[]; @Input('abpForOrderBy') - orderBy: string; + orderBy?: string; @Input('abpForOrderDir') - orderDir: 'ASC' | 'DESC'; + orderDir?: 'ASC' | 'DESC'; @Input('abpForFilterBy') - filterBy: string; + filterBy?: string; @Input('abpForFilterVal') filterVal: any; @Input('abpForTrackBy') - trackBy; + trackBy?: TrackByFunction; @Input('abpForCompareBy') - compareBy: CompareFn; + compareBy?: CompareFn; @Input('abpForEmptyRef') - emptyRef: TemplateRef; + emptyRef?: TemplateRef; - private differ: IterableDiffer; + private differ!: IterableDiffer | null; - private isShowEmptyRef: boolean; + private isShowEmptyRef!: boolean; get compareFn(): CompareFn { return this.compareBy || compare; @@ -83,22 +83,29 @@ export class ForDirective implements OnChanges { const rw: RecordView[] = []; changes.forEachOperation( - (record: IterableChangeRecord, previousIndex: number, currentIndex: number) => { + ( + record: IterableChangeRecord, + previousIndex: number | null, + currentIndex: number | null, + ) => { if (record.previousIndex == null) { const view = this.vcRef.createEmbeddedView( this.tempRef, new AbpForContext(null, -1, -1, this.items), - currentIndex, + currentIndex || 0, ); rw.push(new RecordView(record, view)); - } else if (currentIndex == null) { + } else if (currentIndex == null && previousIndex !== null) { this.vcRef.remove(previousIndex); } else { - const view = this.vcRef.get(previousIndex); - this.vcRef.move(view, currentIndex); - - rw.push(new RecordView(record, view as EmbeddedViewRef)); + if (previousIndex !== null) { + const view = this.vcRef.get(previousIndex); + if (view && currentIndex !== null) { + this.vcRef.move(view, currentIndex); + rw.push(new RecordView(record, view as EmbeddedViewRef)); + } + } } }, ); @@ -117,8 +124,10 @@ export class ForDirective implements OnChanges { } changes.forEachIdentityChange((record: IterableChangeRecord) => { - const viewRef = this.vcRef.get(record.currentIndex) as EmbeddedViewRef; - viewRef.context.$implicit = record.item; + if (record.currentIndex !== null) { + const viewRef = this.vcRef.get(record.currentIndex) as EmbeddedViewRef; + viewRef.context.$implicit = record.item; + } }); } @@ -152,10 +161,9 @@ export class ForDirective implements OnChanges { } private sortItems(items: any[]) { - if (this.orderBy) { - items.sort((a, b) => - a[this.orderBy] > b[this.orderBy] ? 1 : a[this.orderBy] < b[this.orderBy] ? -1 : 0, - ); + const orderBy = this.orderBy; + if (orderBy) { + items.sort((a, b) => (a[orderBy] > b[orderBy] ? 1 : a[orderBy] < b[orderBy] ? -1 : 0)); } else { items.sort(); } @@ -166,13 +174,13 @@ export class ForDirective implements OnChanges { if (!Array.isArray(items)) return; const compareFn = this.compareFn; - + const filterBy = this.filterBy; if ( - typeof this.filterBy !== 'undefined' && + typeof filterBy !== 'undefined' && typeof this.filterVal !== 'undefined' && this.filterVal !== '' ) { - items = items.filter(item => compareFn(item[this.filterBy], this.filterVal)); + items = items.filter(item => compareFn(item[filterBy], this.filterVal)); } switch (this.orderDir) { diff --git a/npm/ng-packs/packages/core/src/lib/directives/form-submit.directive.ts b/npm/ng-packs/packages/core/src/lib/directives/form-submit.directive.ts index ed8b036b67..7562a1b7b7 100644 --- a/npm/ng-packs/packages/core/src/lib/directives/form-submit.directive.ts +++ b/npm/ng-packs/packages/core/src/lib/directives/form-submit.directive.ts @@ -8,7 +8,7 @@ import { Output, Self, } from '@angular/core'; -import { UntypedFormControl, UntypedFormGroup, FormGroupDirective } from '@angular/forms'; +import { FormGroupDirective, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; import { fromEvent } from 'rxjs'; import { debounceTime, filter } from 'rxjs/operators'; import { SubscriptionService } from '../services/subscription.service'; @@ -26,8 +26,9 @@ export class FormSubmitDirective implements OnInit { @Input() debounce = 200; + // TODO: Remove unused input @Input() - notValidateOnSubmit: string | boolean; + notValidateOnSubmit?: string | boolean; @Input() markAsDirtyWhenSubmit = true; @@ -41,11 +42,10 @@ export class FormSubmitDirective implements OnInit { private host: ElementRef, private cdRef: ChangeDetectorRef, private subscription: SubscriptionService, - ) { } + ) {} ngOnInit() { this.subscription.addOne(this.formGroupDirective.ngSubmit, () => { - if (this.markAsDirtyWhenSubmit) { this.markAsDirty(); } @@ -53,10 +53,10 @@ export class FormSubmitDirective implements OnInit { this.executedNgSubmit = true; }); - const keyup$ = fromEvent(this.host.nativeElement as HTMLElement, 'keyup').pipe( + const keyup$ = fromEvent(this.host.nativeElement as HTMLElement, 'keyup').pipe( debounceTime(this.debounce), filter(event => !(event.target instanceof HTMLTextAreaElement)), - filter((event: KeyboardEvent) => event && event.key === 'Enter'), + filter(event => event && event.key === 'Enter'), ); this.subscription.addOne(keyup$, () => { diff --git a/npm/ng-packs/packages/core/src/lib/directives/replaceable-template.directive.ts b/npm/ng-packs/packages/core/src/lib/directives/replaceable-template.directive.ts index 59f047093c..9a1bedcd71 100644 --- a/npm/ng-packs/packages/core/src/lib/directives/replaceable-template.directive.ts +++ b/npm/ng-packs/packages/core/src/lib/directives/replaceable-template.directive.ts @@ -1,5 +1,4 @@ import { - ComponentRef, Directive, Injector, Input, @@ -24,7 +23,7 @@ import { SubscriptionService } from '../services/subscription.service'; }) export class ReplaceableTemplateDirective implements OnInit, OnChanges { @Input('abpReplaceableTemplate') - data: ReplaceableComponents.ReplaceableTemplateDirectiveInput; + data!: ReplaceableComponents.ReplaceableTemplateDirectiveInput; providedData = { inputs: {}, @@ -140,11 +139,15 @@ export class ReplaceableTemplateDirective implements OnInit, OnChanges { [key]: { enumerable: true, configurable: true, - get: () => this.data.inputs[key]?.value, - ...(this.data.inputs[key]?.twoWay && { + get: () => this.data.inputs?.[key]?.value, + ...(this.data.inputs?.[key]?.twoWay && { set: (newValue: any) => { - this.data.inputs[key].value = newValue; - this.data.outputs[`${key}Change`](newValue); + if (this.data.inputs?.[key]) { + this.data.inputs[key].value = newValue; + } + if (this.data.outputs?.[`${key}Change`]) { + this.data.outputs[`${key}Change`](newValue); + } }, }), }, diff --git a/npm/ng-packs/packages/core/src/lib/directives/stop-propagation.directive.ts b/npm/ng-packs/packages/core/src/lib/directives/stop-propagation.directive.ts index 52722e95a9..0863d45e88 100644 --- a/npm/ng-packs/packages/core/src/lib/directives/stop-propagation.directive.ts +++ b/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) {} ngOnInit(): void { - this.subscription.addOne(fromEvent(this.el.nativeElement, 'click'), (event: MouseEvent) => { + this.subscription.addOne(fromEvent(this.el.nativeElement, 'click'), event => { event.stopPropagation(); this.stopPropEvent.emit(event); }); diff --git a/npm/ng-packs/packages/core/src/lib/handlers/routes.handler.ts b/npm/ng-packs/packages/core/src/lib/handlers/routes.handler.ts index 49bdc745c3..a46f6d9d77 100644 --- a/npm/ng-packs/packages/core/src/lib/handlers/routes.handler.ts +++ b/npm/ng-packs/packages/core/src/lib/handlers/routes.handler.ts @@ -12,16 +12,16 @@ export class RoutesHandler { } addRoutes() { - this.router?.config?.forEach(({ path = '', data }: RouteData) => { - if (!data?.routes) return; - - if (Array.isArray(data.routes)) { - this.routes.add(data.routes); - return; + (this.router?.config as RouteData[])?.forEach(({ path = '', data }: RouteData) => { + const routes = data?.routes; + if (!routes) return; + + if (Array.isArray(routes)) { + 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)); return acc; - }, []); + }, [] as ABP.Route[]); } type RouteDef = ABP.Route & { children: RouteDef[] }; diff --git a/npm/ng-packs/packages/core/src/lib/interceptors/api.interceptor.ts b/npm/ng-packs/packages/core/src/lib/interceptors/api.interceptor.ts index 1e85cc4716..9321521159 100644 --- a/npm/ng-packs/packages/core/src/lib/interceptors/api.interceptor.ts +++ b/npm/ng-packs/packages/core/src/lib/interceptors/api.interceptor.ts @@ -10,7 +10,7 @@ export class ApiInterceptor implements IApiInterceptor { constructor(private httpWaitService: HttpWaitService) {} getAdditionalHeaders(existingHeaders?: HttpHeaders) { - return existingHeaders; + return existingHeaders || new HttpHeaders(); } intercept(request: HttpRequest, next: HttpHandler) { diff --git a/npm/ng-packs/packages/core/src/lib/models/dtos.ts b/npm/ng-packs/packages/core/src/lib/models/dtos.ts index b9b349f513..70aad747b0 100644 --- a/npm/ng-packs/packages/core/src/lib/models/dtos.ts +++ b/npm/ng-packs/packages/core/src/lib/models/dtos.ts @@ -1,17 +1,18 @@ import { ABP } from './common'; +import { checkHasProp } from '../utils/common-utils'; export class ListResultDto { items?: T[]; constructor(initialValues: Partial> = {}) { for (const key in initialValues) { - if (Object.prototype.hasOwnProperty.call(initialValues, key)) { + if (checkHasProp(initialValues, key)) { this[key] = initialValues[key]; } } } } - +type ValueOf = T[keyof T]; export class PagedResultDto extends ListResultDto { totalCount?: number; @@ -25,11 +26,8 @@ export class LimitedResultRequestDto { constructor(initialValues: Partial = {}) { for (const key in initialValues) { - if ( - Object.prototype.hasOwnProperty.call(initialValues, key) && - initialValues[key] !== undefined - ) { - this[key] = initialValues[key]; + if (checkHasProp(initialValues, key) && initialValues[key] !== undefined) { + this[key] = initialValues[key] as ValueOf; } } } @@ -56,7 +54,7 @@ export class EntityDto { constructor(initialValues: Partial> = {}) { for (const key in initialValues) { - if (Object.prototype.hasOwnProperty.call(initialValues, key)) { + if (checkHasProp(initialValues, key)) { this[key] = initialValues[key]; } } @@ -130,11 +128,11 @@ export class FullAuditedEntityWithUserDto< } export class ExtensibleObject { - extraProperties: ABP.Dictionary; + extraProperties?: ABP.Dictionary; constructor(initialValues: Partial = {}) { for (const key in initialValues) { - if (Object.prototype.hasOwnProperty.call(initialValues, key)) { + if (checkHasProp(initialValues, key)) { this[key] = initialValues[key]; } } @@ -142,7 +140,7 @@ export class ExtensibleObject { } export class ExtensibleEntityDto extends ExtensibleObject { - id: TKey; + id?: TKey; constructor(initialValues: Partial> = {}) { super(initialValues); @@ -152,7 +150,7 @@ export class ExtensibleEntityDto extends ExtensibleObject { export class ExtensibleCreationAuditedEntityDto< TPrimaryKey = string, > extends ExtensibleEntityDto { - creationTime: Date | string; + creationTime?: Date | string; creatorId?: string; constructor(initialValues: Partial> = {}) { @@ -175,8 +173,8 @@ export class ExtensibleAuditedEntityWithUserDto< TPrimaryKey = string, TUserDto = any, > extends ExtensibleAuditedEntityDto { - creator: TUserDto; - lastModifier: TUserDto; + creator?: TUserDto; + lastModifier?: TUserDto; constructor(initialValues: Partial> = {}) { super(initialValues); @@ -187,7 +185,7 @@ export class ExtensibleCreationAuditedEntityWithUserDto< TPrimaryKey = string, TUserDto = any, > extends ExtensibleCreationAuditedEntityDto { - creator: TUserDto; + creator?: TUserDto; constructor( initialValues: Partial> = {}, @@ -199,9 +197,9 @@ export class ExtensibleCreationAuditedEntityWithUserDto< export class ExtensibleFullAuditedEntityDto< TPrimaryKey = string, > extends ExtensibleAuditedEntityDto { - isDeleted: boolean; + isDeleted?: boolean; deleterId?: string; - deletionTime: Date | string; + deletionTime?: Date | string; constructor(initialValues: Partial> = {}) { super(initialValues); @@ -212,9 +210,9 @@ export class ExtensibleFullAuditedEntityWithUserDto< TPrimaryKey = string, TUserDto = any, > extends ExtensibleFullAuditedEntityDto { - creator: TUserDto; - lastModifier: TUserDto; - deleter: TUserDto; + creator?: TUserDto; + lastModifier?: TUserDto; + deleter?: TUserDto; constructor(initialValues: Partial> = {}) { super(initialValues); diff --git a/npm/ng-packs/packages/core/src/lib/models/environment.ts b/npm/ng-packs/packages/core/src/lib/models/environment.ts index 252afe1291..78a9294525 100644 --- a/npm/ng-packs/packages/core/src/lib/models/environment.ts +++ b/npm/ng-packs/packages/core/src/lib/models/environment.ts @@ -17,9 +17,10 @@ export interface ApplicationInfo { baseUrl?: string; logoUrl?: string; } - -export interface ApiConfig { +export interface HasAdditional { [key: string]: string; +} +export interface ApiConfig extends Partial{ url: string; rootNamespace?: string; } diff --git a/npm/ng-packs/packages/core/src/lib/models/session.ts b/npm/ng-packs/packages/core/src/lib/models/session.ts index e86e0a2616..fe5d94b6a4 100644 --- a/npm/ng-packs/packages/core/src/lib/models/session.ts +++ b/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 interface State { language: string; - tenant: CurrentTenantDto; + tenant: CurrentTenantDto | null; } } diff --git a/npm/ng-packs/packages/core/src/lib/providers/locale.provider.ts b/npm/ng-packs/packages/core/src/lib/providers/locale.provider.ts index b96069e75d..ca90c4bc33 100644 --- a/npm/ng-packs/packages/core/src/lib/providers/locale.provider.ts +++ b/npm/ng-packs/packages/core/src/lib/providers/locale.provider.ts @@ -1,6 +1,7 @@ import { LOCALE_ID, Provider } from '@angular/core'; import { differentLocales } from '../constants/different-locales'; import { LocalizationService } from '../services/localization.service'; +import { checkHasProp } from '../utils/common-utils'; export class LocaleId extends String { constructor(private localizationService: LocalizationService) { @@ -9,7 +10,10 @@ export class LocaleId extends String { toString(): string { const { currentLang } = this.localizationService; - return differentLocales[currentLang] || currentLang; + if (checkHasProp(differentLocales, currentLang)) { + return differentLocales[currentLang]; + } + return currentLang; } valueOf(): string { diff --git a/npm/ng-packs/packages/core/src/lib/services/config-state.service.ts b/npm/ng-packs/packages/core/src/lib/services/config-state.service.ts index 62905c271b..2927b47e5d 100644 --- a/npm/ng-packs/packages/core/src/lib/services/config-state.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/config-state.service.ts @@ -1,5 +1,5 @@ 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 { 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'; @@ -47,6 +47,9 @@ export class ConfigStateService { private getLocalizationAndCombineWithAppState( appState: ApplicationConfigurationDto, ): Observable { + if (!appState.localization.currentCulture.cultureName) { + throw new Error('culture name should defined'); + } return this.getlocalizationResource(appState.localization.currentCulture.cultureName).pipe( map(result => ({ ...appState, localization: { ...appState.localization, ...result } })), ); @@ -77,11 +80,11 @@ export class ConfigStateService { } } - getOne$(key: string) { + getOne$(key: K) { return this.store.sliceState(state => state[key]); } - getOne(key: string) { + getOne(key: K) { return this.store.state[key]; } @@ -138,7 +141,7 @@ export class ConfigStateService { 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 }) => { if (!features?.values) return; @@ -164,7 +167,7 @@ export class ConfigStateService { return keysFound.reduce((acc, key) => { acc[key] = settings[key]; return acc; - }, {}); + }, {} as Record); } getSettings$(keyword?: string) { @@ -179,7 +182,7 @@ export class ConfigStateService { return keysFound.reduce((acc, key) => { acc[key] = settings[key]; return acc; - }, {}); + }, {} as Record); }), ); } diff --git a/npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts b/npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts index 0754205f33..4329a5cb74 100644 --- a/npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts @@ -8,7 +8,7 @@ export class DomInsertionService { insertContent( contentStrategy: ContentStrategy, - ): T { + ): T | undefined { const hash = generateHash(contentStrategy.content); if (this.inserted.has(hash)) return; @@ -20,10 +20,11 @@ export class DomInsertionService { } removeContent(element: HTMLScriptElement | HTMLStyleElement) { - const hash = generateHash(element.textContent); - this.inserted.delete(hash); - - element.parentNode.removeChild(element); + if (element.textContent) { + const hash = generateHash(element.textContent); + this.inserted.delete(hash); + element.parentNode?.removeChild(element); + } } has(content: string): boolean { diff --git a/npm/ng-packs/packages/core/src/lib/services/environment.service.ts b/npm/ng-packs/packages/core/src/lib/services/environment.service.ts index a4e74cf16a..ca5d4d79ff 100644 --- a/npm/ng-packs/packages/core/src/lib/services/environment.service.ts +++ b/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 { InternalStore } from '../utils/internal-store-utils'; -const mapToApiUrl = (key: string) => (apis: Apis) => - (apis[key] || apis.default).url || apis.default.url; +const mapToApiUrl = (key: string | undefined) => (apis: Apis) => + ((key && apis[key]) || apis.default).url || apis.default.url; -const mapToIssuer = (issuer: string) => { +const mapToIssuer = (issuer: string | undefined) => { if (!issuer) { return issuer; } @@ -30,8 +30,8 @@ export class EnvironmentService { return this.store.state; } - getApiUrl(key: string) { - return mapToApiUrl(key)(this.store.state.apis); + getApiUrl(key: string | undefined) { + return mapToApiUrl(key)(this.store.state?.apis); } getApiUrl$(key: string) { @@ -43,11 +43,12 @@ export class EnvironmentService { } getIssuer() { - const issuer = this.store.state.oAuthConfig.issuer; + const issuer = this.store.state?.oAuthConfig?.issuer; + return mapToIssuer(issuer); } - + getIssuer$() { - return this.store.sliceState(state => state.oAuthConfig.issuer).pipe(map(mapToIssuer)); + return this.store.sliceState(state => state?.oAuthConfig?.issuer).pipe(map(mapToIssuer)); } } diff --git a/npm/ng-packs/packages/core/src/lib/services/http-wait.service.ts b/npm/ng-packs/packages/core/src/lib/services/http-wait.service.ts index 792c67ed70..d80599fc25 100644 --- a/npm/ng-packs/packages/core/src/lib/services/http-wait.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/http-wait.service.ts @@ -86,7 +86,10 @@ export class HttpWaitService { this.store.patch({ filteredRequests }); } - private applyFilter(requests: HttpRequest[]) { + private applyFilter(requests: HttpRequest[] | undefined) { + if (!requests) { + return []; + } const { filteredRequests } = this.store.state; return requests.filter( ({ method, url }) => diff --git a/npm/ng-packs/packages/core/src/lib/services/lazy-load.service.ts b/npm/ng-packs/packages/core/src/lib/services/lazy-load.service.ts index 3254396b82..f50102e15a 100644 --- a/npm/ng-packs/packages/core/src/lib/services/lazy-load.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/lazy-load.service.ts @@ -1,5 +1,5 @@ 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 { LoadingStrategy } from '../strategies'; import { ResourceWaitService } from './resource-wait.service'; @@ -15,11 +15,13 @@ export class LazyLoadService { load(strategy: LoadingStrategy, retryTimes?: number, retryDelay?: number): Observable { if (this.loaded.has(strategy.path)) return of(new CustomEvent('load')); this.resourceWaitService.addResource(strategy.path); + const delayOperator = retryDelay ? pipe(delay(retryDelay)) : pipe(); + const takeOp = retryTimes ? pipe(take(retryTimes)) : pipe(); return strategy.createStream().pipe( retryWhen(error$ => concat( - error$.pipe(delay(retryDelay), take(retryTimes)), - throwError(new CustomEvent('error')), + error$.pipe(delayOperator, takeOp), + throwError(() => new CustomEvent('error')), ), ), tap(() => { @@ -36,7 +38,7 @@ export class LazyLoadService { if (!element) return false; - element.parentNode.removeChild(element); + element.parentNode?.removeChild(element); this.loaded.delete(path); return true; } diff --git a/npm/ng-packs/packages/core/src/lib/services/localization.service.ts b/npm/ng-packs/packages/core/src/lib/services/localization.service.ts index 20425460e8..8305c35c9c 100644 --- a/npm/ng-packs/packages/core/src/lib/services/localization.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/localization.service.ts @@ -90,15 +90,16 @@ export class LocalizationService { Object.entries(remote).forEach(entry => { const resourceName = entry[0]; const remoteTexts = entry[1]; - let resource = local.get(resourceName) || {}; + let resource = local?.get(resourceName) || {}; resource = { ...resource, ...remoteTexts }; - local.set(resourceName, resource); + local?.set(resourceName, resource); }); } return local; }), + filter(Boolean) ) .subscribe(val => this.localizations$.next(val)); } @@ -134,6 +135,7 @@ export class LocalizationService { lang => this.configState.getDeep('localization.currentCulture.cultureName') !== lang, ), switchMap(lang => this.configState.refreshAppState().pipe(map(() => lang))), + filter(Boolean), switchMap(lang => from(this.registerLocale(lang).then(() => lang))), ) .subscribe(lang => this._languageChange$.next(lang)); @@ -176,14 +178,14 @@ export class LocalizationService { return this.getLocalization(this.configState.getAll(), key, ...interpolateParams); } - localize(resourceName: string, key: string, defaultValue: string): Observable { + localize(resourceName: string, key: string, defaultValue: string): Observable { return this.configState.getOne$('localization').pipe( map(createLocalizer), 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'); return createLocalizer(localization)(resourceName, key, defaultValue); } @@ -210,7 +212,7 @@ export class LocalizationService { ...interpolateParams: string[] ) { if (!key) key = ''; - let defaultValue: string; + let defaultValue = ''; if (typeof key !== 'string') { defaultValue = key.defaultValue; @@ -219,7 +221,7 @@ export class LocalizationService { const keys = key.split('::') as string[]; const warn = (message: string) => { - if (isDevMode) console.warn(message); + if (isDevMode()) console.warn(message); }; 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]; if (item.baseResources.length === 0) { @@ -278,7 +280,7 @@ function recursivelyMergeBaseResources(baseResourceName: string, source: Resourc } 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); return [key, newValue]; }); @@ -296,5 +298,5 @@ function combineLegacyandNewResources( }, legacy); } -type LegacyLanguageDto = Record>; -type ResourceDto = Record; +export type LegacyLanguageDto = Record>; +export type ResourceDto = Record; diff --git a/npm/ng-packs/packages/core/src/lib/services/multi-tenancy.service.ts b/npm/ng-packs/packages/core/src/lib/services/multi-tenancy.service.ts index 979ef3bc43..8fbde5cc8e 100644 --- a/npm/ng-packs/packages/core/src/lib/services/multi-tenancy.service.ts +++ b/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' }) export class MultiTenancyService { - domainTenant: CurrentTenantDto = null; + domainTenant: CurrentTenantDto | null = null; isTenantBoxVisible = true; diff --git a/npm/ng-packs/packages/core/src/lib/services/permission.service.ts b/npm/ng-packs/packages/core/src/lib/services/permission.service.ts index a1979bbe1e..70724ac814 100644 --- a/npm/ng-packs/packages/core/src/lib/services/permission.service.ts +++ b/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(); return this.isPolicyGranted(key, policies); } @@ -36,7 +36,7 @@ export class PermissionService { ); } - protected isPolicyGranted(key: string, grantedPolicies: Record) { + protected isPolicyGranted(key: string | undefined, grantedPolicies: Record) { if (!key) return true; const orRegexp = /\|\|/g; diff --git a/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts b/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts index e929d489f7..1f02daa389 100644 --- a/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts +++ b/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) { - this.store = new InternalStore([]); + this.store = new InternalStore([] as ReplaceableComponents.ReplaceableComponent[]); } add(replaceableComponent: ReplaceableComponents.ReplaceableComponent, reload?: boolean): void { @@ -44,11 +44,11 @@ export class ReplaceableComponentsService { 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); } - get$(replaceableComponentKey: string): Observable { + get$(replaceableComponentKey: string): Observable { return this.replaceableComponents$.pipe( map(components => components.find(component => component.key === replaceableComponentKey)), ); diff --git a/npm/ng-packs/packages/core/src/lib/services/resource-wait.service.ts b/npm/ng-packs/packages/core/src/lib/services/resource-wait.service.ts index 16351837a2..28f63d7d87 100644 --- a/npm/ng-packs/packages/core/src/lib/services/resource-wait.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/resource-wait.service.ts @@ -20,7 +20,7 @@ export class ResourceWaitService { } updateLoading$() { - return this.store.sliceUpdate(({ resources }) => !!resources.size); + return this.store.sliceUpdate(({ resources }) => !!resources?.size); } clearLoading() { diff --git a/npm/ng-packs/packages/core/src/lib/services/rest.service.ts b/npm/ng-packs/packages/core/src/lib/services/rest.service.ts index 82e2c12707..e9a6e89851 100644 --- a/npm/ng-packs/packages/core/src/lib/services/rest.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/rest.service.ts @@ -20,7 +20,7 @@ export class RestService { protected httpErrorReporter: HttpErrorReporterService, ) {} - protected getApiFromStore(apiName: string): string { + protected getApiFromStore(apiName: string | undefined): string { return this.environment.getApiUrl(apiName); } @@ -51,13 +51,12 @@ export class RestService { } private getParams(params: Rest.Params, encoder?: HttpParameterCodec): HttpParams { - const filteredParams = Object.keys(params).reduce((acc, key) => { - const value = params[key]; + const filteredParams = Object.entries(params).reduce((acc, [key, value]) => { if (isUndefinedOrEmptyString(value)) return acc; if (value === null && !this.options.sendNullsAsQueryParam) return acc; acc[key] = value; return acc; - }, {}); + }, {} as any); return encoder ? new HttpParams({ encoder, fromObject: filteredParams }) : new HttpParams({ fromObject: filteredParams }); diff --git a/npm/ng-packs/packages/core/src/lib/services/router-events.service.ts b/npm/ng-packs/packages/core/src/lib/services/router-events.service.ts index 9acee09aa7..6203bad3bb 100644 --- a/npm/ng-packs/packages/core/src/lib/services/router-events.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/router-events.service.ts @@ -6,6 +6,7 @@ import { NavigationStart, Router, RouterEvent, + Event } from '@angular/router'; import { filter } from 'rxjs/operators'; @@ -23,7 +24,7 @@ export class RouterEvents { getEvents(...eventTypes: T) { type FilteredRouterEvent = T extends Type[] ? Ctor : never; - const filterRouterEvents = (event: RouterEvent): event is FilteredRouterEvent => + const filterRouterEvents = (event: Event): event is FilteredRouterEvent => eventTypes.some(type => event instanceof type); return this.router.events.pipe(filter(filterRouterEvents)); @@ -36,7 +37,7 @@ export class RouterEvents { : never : never; - const filterNavigationEvents = (event: RouterEvent): event is FilteredNavigationEvent => + const filterNavigationEvents = (event: Event): event is FilteredNavigationEvent => navigationEventKeys.some(key => event instanceof NavigationEvent[key]); return this.router.events.pipe(filter(filterNavigationEvents)); diff --git a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts index d2aba62c09..32f8b473d0 100644 --- a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts +++ b/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'; // eslint-disable-next-line @typescript-eslint/ban-types -export abstract class AbstractTreeService { +export abstract class AbstractTreeService { abstract id: string; abstract parentId: string; abstract hide: (item: T) => boolean; @@ -84,7 +84,7 @@ export abstract class AbstractTreeService { } find(predicate: (item: TreeNode) => boolean, tree = this.tree): TreeNode | null { - return tree.reduce( + return tree.reduce | null>( (acc, node) => (acc ? acc : predicate(node) ? node : this.find(predicate, node.children)), null, ); @@ -119,9 +119,9 @@ export abstract class AbstractTreeService { } search(params: Partial, tree = this.tree): TreeNode | null { - const searchKeys = Object.keys(params); + const searchKeys = Object.keys(params) as Array>; - return tree.reduce( + return tree.reduce | null>( (acc, node) => acc ? acc @@ -147,7 +147,7 @@ export abstract class AbstractNavTreeService if (!Number.isInteger(a.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) { @@ -170,7 +170,7 @@ export abstract class AbstractNavTreeService hasInvisibleChild(identifier: string): boolean { 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 */ diff --git a/npm/ng-packs/packages/core/src/lib/services/session-state.service.ts b/npm/ng-packs/packages/core/src/lib/services/session-state.service.ts index d0902f40e3..d3bac9a338 100644 --- a/npm/ng-packs/packages/core/src/lib/services/session-state.service.ts +++ b/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); } - setTenant(tenant: CurrentTenantDto) { + setTenant(tenant: CurrentTenantDto | null) { if (compare(tenant, this.store.state.tenant)) return; this.store.set({ ...this.store.state, tenant }); diff --git a/npm/ng-packs/packages/core/src/lib/services/subscription.service.ts b/npm/ng-packs/packages/core/src/lib/services/subscription.service.ts index 129391d40f..c8e31fdbf7 100644 --- a/npm/ng-packs/packages/core/src/lib/services/subscription.service.ts +++ b/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 { Subscription } from 'rxjs'; +import { Injectable } from '@angular/core'; import type { Observable, PartialObserver } from 'rxjs'; +import { Subscription } from 'rxjs'; @Injectable() export class SubscriptionService implements OnDestroy { @@ -33,7 +33,9 @@ export class SubscriptionService implements OnDestroy { closeOne(subscription: Subscription | undefined | null) { this.removeOne(subscription); - subscription.unsubscribe(); + if (subscription) { + subscription.unsubscribe(); + } } ngOnDestroy(): void { diff --git a/npm/ng-packs/packages/core/src/lib/strategies/content-security.strategy.ts b/npm/ng-packs/packages/core/src/lib/strategies/content-security.strategy.ts index a848feabe3..0e15955fb8 100644 --- a/npm/ng-packs/packages/core/src/lib/strategies/content-security.strategy.ts +++ b/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) { - element.setAttribute('nonce', this.nonce); + if (this.nonce) { + element.setAttribute('nonce', this.nonce); + } } } diff --git a/npm/ng-packs/packages/core/src/lib/strategies/content.strategy.ts b/npm/ng-packs/packages/core/src/lib/strategies/content.strategy.ts index 839e867f41..34d8fcbac8 100644 --- a/npm/ng-packs/packages/core/src/lib/strategies/content.strategy.ts +++ b/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 { DomStrategy, DOM_STRATEGY } from './dom.strategy'; +import { CONTENT_SECURITY_STRATEGY, ContentSecurityStrategy } from './content-security.strategy'; +import { DOM_STRATEGY, DomStrategy } from './dom.strategy'; export type ElementOptions = Partial<{ [key in keyof T]: T[key]; @@ -19,7 +19,11 @@ export abstract class ContentStrategy 0) { - Object.keys(this.options).forEach(key => (element[key] = this.options[key])); + (Object.keys(this.options) as Array>).forEach(key => { + if (this.options[key]) { + element[key] = (this.options as NonNullable)[key]; + } + }); } this.contentSecurityStrategy.applyCSP(element); diff --git a/npm/ng-packs/packages/core/src/lib/strategies/context.strategy.ts b/npm/ng-packs/packages/core/src/lib/strategies/context.strategy.ts index 36676c58a6..35e5f48022 100644 --- a/npm/ng-packs/packages/core/src/lib/strategies/context.strategy.ts +++ b/npm/ng-packs/packages/core/src/lib/strategies/context.strategy.ts @@ -13,7 +13,7 @@ export class NoContextStrategy< T extends Type | TemplateRef = any, > extends ContextStrategy { constructor() { - super(undefined); + super(undefined as unknown as Partial>); } } diff --git a/npm/ng-packs/packages/core/src/lib/strategies/cross-origin.strategy.ts b/npm/ng-packs/packages/core/src/lib/strategies/cross-origin.strategy.ts index d01188ac2e..c57f94be71 100644 --- a/npm/ng-packs/packages/core/src/lib/strategies/cross-origin.strategy.ts +++ b/npm/ng-packs/packages/core/src/lib/strategies/cross-origin.strategy.ts @@ -1,9 +1,14 @@ export class CrossOriginStrategy { - constructor(public crossorigin: 'anonymous' | 'use-credentials', public integrity?: string) {} + constructor( + public crossorigin: 'anonymous' | 'use-credentials' | null, + public integrity?: string, + ) {} setCrossOrigin(element: T) { if (this.integrity) element.setAttribute('integrity', this.integrity); - element.setAttribute('crossorigin', this.crossorigin); + if (this.crossorigin) { + element.setAttribute('crossorigin', this.crossorigin); + } } } diff --git a/npm/ng-packs/packages/core/src/lib/strategies/loading.strategy.ts b/npm/ng-packs/packages/core/src/lib/strategies/loading.strategy.ts index 46961e94ba..069c269d58 100644 --- a/npm/ng-packs/packages/core/src/lib/strategies/loading.strategy.ts +++ b/npm/ng-packs/packages/core/src/lib/strategies/loading.strategy.ts @@ -1,11 +1,11 @@ import { Observable, of } from 'rxjs'; import { switchMap } from 'rxjs/operators'; import { fromLazyLoad } from '../utils'; -import { CrossOriginStrategy, CROSS_ORIGIN_STRATEGY } from './cross-origin.strategy'; -import { DomStrategy, DOM_STRATEGY } from './dom.strategy'; +import { CROSS_ORIGIN_STRATEGY, CrossOriginStrategy } from './cross-origin.strategy'; +import { DOM_STRATEGY, DomStrategy } from './dom.strategy'; export abstract class LoadingStrategy { - element: T; + element!: T; constructor( public path: string, diff --git a/npm/ng-packs/packages/core/src/lib/tokens/localization.token.ts b/npm/ng-packs/packages/core/src/lib/tokens/localization.token.ts index e4fd2eeb3f..6472e7d5f3 100644 --- a/npm/ng-packs/packages/core/src/lib/tokens/localization.token.ts +++ b/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 function localizationContributor(localizations: ABP.Localization[]) { +export function localizationContributor(localizations?: ABP.Localization[]) { if (localizations) { localizations$.next([...localizations$.value, ...localizations]); } } -export const localizations$ = new BehaviorSubject([]); +export const localizations$ = new BehaviorSubject([]); diff --git a/npm/ng-packs/packages/core/src/lib/utils/common-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/common-utils.ts index b373b6c04a..44569c3cfe 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/common-utils.ts +++ b/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 === ''; } -export function isNullOrUndefined(obj) { +export function isNullOrUndefined(obj: T) { return obj === null || obj === undefined; } -export function isNullOrEmpty(obj){ +export function isNullOrEmpty(obj: T): boolean { return obj === null || obj === undefined || obj === ''; } -export function exists(obj) { +export function exists(obj: T): obj is T { return !isNullOrUndefined(obj); } -export function isObject(obj) { +export function isObject(obj: T): boolean { return obj instanceof Object; } -export function isArray(obj) { +export function isArray(obj: T): boolean { return Array.isArray(obj); } -export function isObjectAndNotArray(obj) { +export function isObjectAndNotArray(obj: T): boolean { return isObject(obj) && !isArray(obj); } -export function isNode(obj) { +export function isNode(obj: T): boolean { return obj instanceof Node; } -export function isObjectAndNotArrayNotNode(obj) { +export function isObjectAndNotArrayNotNode(obj: T): boolean { return isObjectAndNotArray(obj) && !isNode(obj); } + +export function checkHasProp(object: T, key: string | keyof T): key is keyof T { + return Object.prototype.hasOwnProperty.call(object, key); +} diff --git a/npm/ng-packs/packages/core/src/lib/utils/date-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/date-utils.ts index 2144bf69a1..4201eb92fc 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/date-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/date-utils.ts @@ -13,8 +13,7 @@ export function getShortTimeFormat(configStateService: ConfigStateService) { const dateTimeFormat = configStateService.getDeep( 'localization.currentCulture.dateTimeFormat', ) as DateTimeFormatDto; - - return dateTimeFormat.shortTimePattern.replace('tt', 'a'); + return dateTimeFormat?.shortTimePattern?.replace('tt', 'a'); } export function getShortDateShortTimeFormat(configStateService: ConfigStateService) { @@ -22,5 +21,5 @@ export function getShortDateShortTimeFormat(configStateService: ConfigStateServi 'localization.currentCulture.dateTimeFormat', ) as DateTimeFormatDto; - return `${dateTimeFormat.shortDatePattern} ${dateTimeFormat.shortTimePattern.replace('tt', 'a')}`; + return `${dateTimeFormat.shortDatePattern} ${dateTimeFormat?.shortTimePattern?.replace('tt', 'a')}`; } diff --git a/npm/ng-packs/packages/core/src/lib/utils/environment-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/environment-utils.ts index 9958c97165..8db9b5e02f 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/environment-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/environment-utils.ts @@ -24,19 +24,23 @@ export function getRemoteEnv(injector: Injector, environment: Partial environmentService.setState(mergeEnvironments(environment, env, remoteEnv))), + tap(env => + environmentService.setState( + mergeEnvironments(environment, env || ({} as Environment), remoteEnv as RemoteEnv), + ), + ), ) .toPromise(); } function mergeEnvironments( local: Partial, - remote: any, + remote: Environment, config: RemoteEnv, ): Environment { switch (config.mergeStrategy) { case 'deepmerge': - return deepMerge(local, remote); + return deepMerge(local, remote) as Environment; case 'overwrite': case null: case undefined: diff --git a/npm/ng-packs/packages/core/src/lib/utils/factory-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/factory-utils.ts index c9542f3dba..eb4759bdad 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/factory-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/factory-utils.ts @@ -21,7 +21,7 @@ export class LazyModuleFactory extends NgModuleFactory { create(parentInjector: Injector | null): NgModuleRef { const injector = Injector.create({ - parent: parentInjector, + ...(parentInjector && { parent: parentInjector }), providers: this.moduleWithProviders.providers as StaticProvider[], }); @@ -35,7 +35,7 @@ export class LazyModuleFactory extends NgModuleFactory { export function featuresFactory( configState: ConfigStateService, featureKeys: string[], - mapFn: (features) => any = features => features, + mapFn: (features: { [key: string]: string }) => any = features => features, ) { return configState.getFeatures$(featureKeys).pipe(filter(Boolean), map(mapFn)); } diff --git a/npm/ng-packs/packages/core/src/lib/utils/internal-store-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/internal-store-utils.ts index 27a8e9cbcf..f19ec89f04 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/internal-store-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/internal-store-utils.ts @@ -37,7 +37,8 @@ export class InternalStore { } deepPatch(state: DeepPartial) { - this.state$.next(deepMerge(this.state, state)); + // TODO: Strict improve deepMerge + this.state$.next(deepMerge(this.state, state) as State); this.update$.next(state); } diff --git a/npm/ng-packs/packages/core/src/lib/utils/lazy-load-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/lazy-load-utils.ts index 6bf80143ea..c0ea64f09d 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/lazy-load-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/lazy-load-utils.ts @@ -1,6 +1,6 @@ import { Observable, Observer } from 'rxjs'; -import { CrossOriginStrategy, CROSS_ORIGIN_STRATEGY } from '../strategies/cross-origin.strategy'; -import { DomStrategy, DOM_STRATEGY } from '../strategies/dom.strategy'; +import { CROSS_ORIGIN_STRATEGY, CrossOriginStrategy } from '../strategies/cross-origin.strategy'; +import { DOM_STRATEGY, DomStrategy } from '../strategies/dom.strategy'; export function fromLazyLoad( element: HTMLScriptElement | HTMLLinkElement, @@ -11,9 +11,9 @@ export function fromLazyLoad( domStrategy.insertElement(element); return new Observable((observer: Observer) => { - element.onload = (event: T) => { + element.onload = (event: Event) => { clearCallbacks(element); - observer.next(event); + observer.next(event as T); observer.complete(); }; @@ -32,10 +32,10 @@ export function fromLazyLoad( }); } -function createErrorHandler(observer: Observer, element: HTMLElement) { +function createErrorHandler(observer: Observer, element: HTMLElement) { return function (event: Event | string) { clearCallbacks(element); - element.parentNode.removeChild(element); + element.parentNode?.removeChild(element); observer.error(event); }; } diff --git a/npm/ng-packs/packages/core/src/lib/utils/localization-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/localization-utils.ts index 59a0e99051..890a83c2e4 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/localization-utils.ts +++ b/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) { - return (resourceName: string, key: string, defaultValue: string) => { + return (resourceName: string, key: string, defaultValue: string | null) => { if (resourceName === '_') return key; const resource = localization?.values?.[resourceName]; diff --git a/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts index 0b755cf9b4..a0b5aa89c6 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts +++ b/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( placeholder, 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[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); }); }); diff --git a/npm/ng-packs/packages/core/src/lib/utils/object-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/object-utils.ts index 29382ee738..fe5992777d 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/object-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/object-utils.ts @@ -6,18 +6,25 @@ import { isObject, isObjectAndNotArrayNotNode, } from './common-utils'; +import { DeepPartial } from '../models'; -export function deepMerge(target, source) { +export function deepMerge( + target: DeepPartial | T, + source: DeepPartial | T, +): DeepPartial | T { if (isObjectAndNotArrayNotNode(target) && isObjectAndNotArrayNotNode(source)) { return deepMergeRecursively(target, source); } else if (isNullOrUndefined(target) && isNullOrUndefined(source)) { - return {}; + return {} as T; } else { - return exists(source) ? source : target; + return exists(source) ? (source as T) : target; } } -function deepMergeRecursively(target, source) { +function deepMergeRecursively( + target: DeepPartial | T, + source: DeepPartial | T, +): DeepPartial | T { const shouldNotRecurse = isNullOrUndefined(target) || 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. */ if (shouldNotRecurse) { - return exists(source) ? source : target; + return exists(source) ? (source as T) : target; } - const keysOfTarget = Object.keys(target); - const keysOfSource = Object.keys(source); + const keysOfTarget = Object.keys(target as { [key: string]: any }); + const keysOfSource = Object.keys(source as { [key: string]: any }); const uniqueKeys = new Set(keysOfTarget.concat(keysOfSource)); 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; - }, {}); + }, {} as T); } diff --git a/npm/ng-packs/packages/core/src/lib/utils/route-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/route-utils.ts index 07fad6a1fe..bfd6c7a2b5 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/route-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/route-utils.ts @@ -1,11 +1,11 @@ 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 { RoutesService } from '../services/routes.service'; import { noop } from './common-utils'; import { TreeNode } from './tree-utils'; -export function findRoute(routesService: RoutesService, path: string): TreeNode { +export function findRoute(routesService: RoutesService, path: string): TreeNode | null { const node = routesService.find(route => route.path === path); return node || path === '/' @@ -14,7 +14,7 @@ export function findRoute(routesService: RoutesService, path: string): TreeNode< } 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]; return '/' + (primaryGroup || emptyGroup).segments.map(({ path }) => path).join('/'); diff --git a/npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts index da470c9c3e..bfc938c158 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts @@ -62,7 +62,7 @@ export function createTreeNodeFilterCreator( return (search: string) => { const regex = new RegExp('.*' + search + '.*', 'i'); - return function collectNodes(nodes: TreeNode[], matches = []) { + return function collectNodes(nodes: TreeNode[], matches: TreeNode[] = []) { for (const node of nodes) { if (regex.test(mapperFn(node[key]))) matches.push(node); @@ -82,8 +82,8 @@ export type TreeNode = { parent?: TreeNode; }; -type NodeKey = number | string | symbol | undefined | null; +export type NodeKey = number | string | symbol | undefined | null; -type NodeValue any> = F extends undefined +export type NodeValue any> = F extends undefined ? TreeNode : ReturnType; diff --git a/npm/ng-packs/packages/core/src/lib/validators/range.validator.ts b/npm/ng-packs/packages/core/src/lib/validators/range.validator.ts index 9497ed0407..16b9432a6e 100644 --- a/npm/ng-packs/packages/core/src/lib/validators/range.validator.ts +++ b/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; } -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; } diff --git a/npm/ng-packs/packages/core/src/lib/validators/required.validator.ts b/npm/ng-packs/packages/core/src/lib/validators/required.validator.ts index 4e2b1931db..5e10ff515e 100644 --- a/npm/ng-packs/packages/core/src/lib/validators/required.validator.ts +++ b/npm/ng-packs/packages/core/src/lib/validators/required.validator.ts @@ -16,7 +16,7 @@ export function validateRequired({ allowEmptyStrings }: RequiredOptions = {}): V 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 (allowEmptyStrings && value === '') return true; diff --git a/npm/ng-packs/packages/core/src/lib/validators/string-length.validator.ts b/npm/ng-packs/packages/core/src/lib/validators/string-length.validator.ts index 934188a4fb..068bdb65bb 100644 --- a/npm/ng-packs/packages/core/src/lib/validators/string-length.validator.ts +++ b/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; } -function getMinLengthError(value: string, requiredLength: number): StringLengthError { +function getMinLengthError(value: string, requiredLength: number): StringLengthError | null { return value.length < requiredLength ? { minlength: { requiredLength } } : null; } diff --git a/npm/ng-packs/packages/core/src/lib/validators/username.validator.ts b/npm/ng-packs/packages/core/src/lib/validators/username.validator.ts index 4e943769d2..c238c71119 100644 --- a/npm/ng-packs/packages/core/src/lib/validators/username.validator.ts +++ b/npm/ng-packs/packages/core/src/lib/validators/username.validator.ts @@ -14,7 +14,7 @@ export interface UsernameOptions { const onlyLetterAndNumberRegex = /^[a-zA-Z0-9]+$/; export function validateUsername( - { pattern }: UsernameOptions = { pattern: onlyLetterAndNumberRegex }, + { pattern = /.*/ }: UsernameOptions = { pattern: onlyLetterAndNumberRegex }, ): ValidatorFn { return (control: AbstractControl): UsernamePatternError | null => { const isValid = isValidUserName(control.value, pattern); diff --git a/npm/ng-packs/packages/core/testing/src/lib/services/mock-permission.service.ts b/npm/ng-packs/packages/core/testing/src/lib/services/mock-permission.service.ts index 81bbdcc625..b4d180b17a 100644 --- a/npm/ng-packs/packages/core/testing/src/lib/services/mock-permission.service.ts +++ b/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) => { policies[key] = true; return policies; - }, {}); + }, {} as { [key: string]: boolean }); this.configState['store'].deepPatch({ auth: { grantedPolicies } }); } diff --git a/npm/ng-packs/packages/core/testing/src/lib/services/mock-rest.service.ts b/npm/ng-packs/packages/core/testing/src/lib/services/mock-rest.service.ts index b7b4066a4c..65e1763817 100644 --- a/npm/ng-packs/packages/core/testing/src/lib/services/mock-rest.service.ts +++ b/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 { Inject, Injectable } from '@angular/core'; import { Observable, throwError } from 'rxjs'; @@ -12,7 +18,7 @@ export class MockRestService extends RestService { protected http: HttpClient, protected environment: EnvironmentService, ) { - super(options, http, environment, null); + super(options, http, environment, null as unknown as HttpErrorReporterService); } handleError(err: any): Observable { diff --git a/npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.ts b/npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.ts index 3bc940e353..5e2a0e866a 100644 --- a/npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.ts +++ b/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 { data: PagedResultDto = { items: [], totalCount: 0 }; - form: UntypedFormGroup; + form!: UntypedFormGroup; - selected: IdentityRoleDto; + selected?: IdentityRoleDto; - isModalVisible: boolean; + isModalVisible!: boolean; visiblePermissions = false; - providerKey: string; + providerKey?: string; modalBusy = false; permissionManagementKey = ePermissionManagementComponents.PermissionManagement; - onVisiblePermissionChange = event => { + onVisiblePermissionChange = (event: boolean) => { this.visiblePermissions = event; }; @@ -82,7 +82,7 @@ export class RolesComponent implements OnInit { if (!this.form.valid) return; this.modalBusy = true; - const { id } = this.selected; + const { id } = this.selected || {}; (id ? this.service.update(id, { ...this.selected, ...this.form.value }) : this.service.create(this.form.value) @@ -118,7 +118,7 @@ export class RolesComponent implements OnInit { }, 0); } - sort(data) { + sort(data: any) { const { prop, dir } = data.sorts[0]; this.list.sortKey = prop; this.list.sortOrder = dir; diff --git a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts index 0734f04d1f..cb0cdd9755 100644 --- a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts +++ b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts @@ -1,28 +1,12 @@ -import { ListService, PagedResultDto } from '@abp/ng.core'; -import { - GetIdentityUsersInput, - IdentityRoleDto, - IdentityUserDto, - IdentityUserService, -} from '@abp/ng.identity/proxy'; -import { ePermissionManagementComponents } from '@abp/ng.permission-management'; -import {Confirmation, ConfirmationService, ToasterService} from '@abp/ng.theme.shared'; -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'; +import { ListService, PagedResultDto } from "@abp/ng.core"; +import { GetIdentityUsersInput, IdentityRoleDto, IdentityUserDto, IdentityUserService } from "@abp/ng.identity/proxy"; +import { ePermissionManagementComponents } from "@abp/ng.permission-management"; +import { Confirmation, ConfirmationService, ToasterService } from "@abp/ng.theme.shared"; +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({ selector: 'abp-users', @@ -39,31 +23,31 @@ export class UsersComponent implements OnInit { data: PagedResultDto = { items: [], totalCount: 0 }; @ViewChild('modalContent', { static: false }) - modalContent: TemplateRef; + modalContent!: TemplateRef; - form: UntypedFormGroup; + form!: UntypedFormGroup; - selected: IdentityUserDto; + selected?: IdentityUserDto; - selectedUserRoles: IdentityRoleDto[]; + selectedUserRoles?: IdentityRoleDto[]; - roles: IdentityRoleDto[]; + roles?: IdentityRoleDto[]; visiblePermissions = false; - providerKey: string; + providerKey?: string; - isModalVisible: boolean; + isModalVisible?: boolean; modalBusy = false; permissionManagementKey = ePermissionManagementComponents.PermissionManagement; - entityDisplayName: string; + entityDisplayName?: string; trackByFn: TrackByFunction = (index, item) => Object.keys(item)[0] || index; - onVisiblePermissionChange = event => { + onVisiblePermissionChange = (event: boolean) => { this.visiblePermissions = event; }; @@ -90,20 +74,22 @@ export class UsersComponent implements OnInit { this.service.getAssignableRoles().subscribe(({ items }) => { this.roles = items; - this.form.addControl( - 'roleNames', - this.fb.array( - this.roles.map(role => - this.fb.group({ - [role.name]: [ - this.selected.id - ? !!this.selectedUserRoles?.find(userRole => userRole.id === role.id) - : role.isDefault, - ], - }), + if (this.roles) { + this.form.addControl( + 'roleNames', + this.fb.array( + this.roles.map(role => + this.fb.group({ + [role.name as string]: [ + this.selected?.id + ? !!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 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 ? this.service.update(id, { @@ -166,12 +153,13 @@ export class UsersComponent implements OnInit { if (status === Confirmation.Status.confirm) { this.service.delete(id).subscribe(() => { this.toasterService.success('AbpUi::SuccessfullyDeleted'); - this.list.get()}); + this.list.get(); + }); } }); } - sort(data) { + sort(data: any) { const { prop, dir } = data.sorts[0]; this.list.sortKey = prop; this.list.sortOrder = dir; diff --git a/npm/ng-packs/packages/identity/src/lib/defaults/default-roles-entity-actions.ts b/npm/ng-packs/packages/identity/src/lib/defaults/default-roles-entity-actions.ts index ac48cce799..fe6e0661d5 100644 --- a/npm/ng-packs/packages/identity/src/lib/defaults/default-roles-entity-actions.ts +++ b/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 { const component = data.getInjected(RolesComponent); - component.edit(data.record.id); + component.edit(data.record.id || ''); }, permission: 'AbpIdentity.Roles.Update', }, @@ -15,7 +15,7 @@ export const DEFAULT_ROLES_ENTITY_ACTIONS = EntityAction.createMany { const component = data.getInjected(RolesComponent); - component.openPermissionsModal(data.record.name); + component.openPermissionsModal(data.record.name || ''); }, permission: 'AbpIdentity.Roles.ManagePermissions', }, @@ -23,9 +23,9 @@ export const DEFAULT_ROLES_ENTITY_ACTIONS = EntityAction.createMany { 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', - visible: data => !data.record.isStatic, + visible: data => !data?.record.isStatic, }, ]); diff --git a/npm/ng-packs/packages/identity/src/lib/defaults/default-roles-form-props.ts b/npm/ng-packs/packages/identity/src/lib/defaults/default-roles-form-props.ts index 52fc33d218..129a095a02 100644 --- a/npm/ng-packs/packages/identity/src/lib/defaults/default-roles-form-props.ts +++ b/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 { 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'; export const DEFAULT_ROLES_CREATE_FORM_PROPS = FormProp.createMany([ @@ -8,7 +8,7 @@ export const DEFAULT_ROLES_CREATE_FORM_PROPS = FormProp.createMany) => data.record && data.record.isStatic, + disabled: ((data: PropData) => data.record && data.record.isStatic) as PropPredicate, validators: () => [Validators.required], }, { diff --git a/npm/ng-packs/packages/identity/src/lib/defaults/default-users-entity-actions.ts b/npm/ng-packs/packages/identity/src/lib/defaults/default-users-entity-actions.ts index 8f6e3ebcc7..ca0a2edcad 100644 --- a/npm/ng-packs/packages/identity/src/lib/defaults/default-users-entity-actions.ts +++ b/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 { 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([ { text: 'AbpIdentity::Edit', action: data => { const component = data.getInjected(UsersComponent); - component.edit(data.record.id); + component.edit(data.record.id || ''); }, permission: 'AbpIdentity.Users.Update', }, @@ -16,20 +16,21 @@ export const DEFAULT_USERS_ENTITY_ACTIONS = EntityAction.createMany { 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', - }, { + }, + { text: 'AbpIdentity::Delete', action: data => { 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 => { - const userName = data.record.userName; - const configStateService = data.getInjected(ConfigStateService) - const currentUser = configStateService.getOne("currentUser") as CurrentUserDto; - return userName !== currentUser.userName; + visible: data => { + const userName = data?.record.userName; + const configStateService = data?.getInjected(ConfigStateService); + const currentUser = configStateService?.getOne('currentUser') as CurrentUserDto; + return userName !== currentUser.userName; }, permission: 'AbpIdentity.Users.Delete', }, diff --git a/npm/ng-packs/packages/identity/src/lib/defaults/default-users-form-props.ts b/npm/ng-packs/packages/identity/src/lib/defaults/default-users-form-props.ts index ce0bb03636..ccdf06df24 100644 --- a/npm/ng-packs/packages/identity/src/lib/defaults/default-users-form-props.ts +++ b/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') { return { ...prop, - validators: data => [...getPasswordValidators({ get: data.getInjected })], + validators: (data: any) => [...getPasswordValidators({ get: data.getInjected })], }; } return prop; diff --git a/npm/ng-packs/packages/oauth/src/lib/handlers/oauth-configuration.handler.ts b/npm/ng-packs/packages/oauth/src/lib/handlers/oauth-configuration.handler.ts index 7e4cce28e4..a2a9228b78 100644 --- a/npm/ng-packs/packages/oauth/src/lib/handlers/oauth-configuration.handler.ts +++ b/npm/ng-packs/packages/oauth/src/lib/handlers/oauth-configuration.handler.ts @@ -1,5 +1,5 @@ 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 { filter, map } from 'rxjs/operators'; import { ABP, EnvironmentService, CORE_OPTIONS } from '@abp/ng.core'; @@ -20,10 +20,10 @@ export class OAuthConfigurationHandler { this.environmentService .createOnUpdateStream(state => state) .pipe( - map(environment => environment.oAuthConfig), + map(environment => environment.oAuthConfig as AuthConfig), filter(config => !compare(config, this.options.environment.oAuthConfig)), ) - .subscribe(config => { + .subscribe((config) => { this.oAuthService.configure(config); }); } diff --git a/npm/ng-packs/packages/oauth/src/lib/interceptors/api.interceptor.ts b/npm/ng-packs/packages/oauth/src/lib/interceptors/api.interceptor.ts index f36f966559..e7ee208c47 100644 --- a/npm/ng-packs/packages/oauth/src/lib/interceptors/api.interceptor.ts +++ b/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 { finalize } from 'rxjs/operators'; import { - SessionStateService, HttpWaitService, - TENANT_KEY, IApiInterceptor, IS_EXTERNAL_REQUEST, + SessionStateService, + TENANT_KEY, } from '@abp/ng.core'; @Injectable({ diff --git a/npm/ng-packs/packages/oauth/src/lib/oauth.module.ts b/npm/ng-packs/packages/oauth/src/lib/oauth.module.ts index 7c8c2af99c..5680b9582d 100644 --- a/npm/ng-packs/packages/oauth/src/lib/oauth.module.ts +++ b/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 { OAuthModule, OAuthStorage } from 'angular-oauth2-oidc'; import { @@ -58,7 +58,7 @@ export class AbpOAuthModule { deps: [OAuthConfigurationHandler], useFactory: noop, }, - OAuthModule.forRoot().providers, + OAuthModule.forRoot().providers as Provider[], { provide: OAuthStorage, useFactory: storageFactory }, ], }; diff --git a/npm/ng-packs/packages/oauth/src/lib/services/oauth.service.ts b/npm/ng-packs/packages/oauth/src/lib/services/oauth.service.ts index e28eebacc4..a8f937e8ca 100644 --- a/npm/ng-packs/packages/oauth/src/lib/services/oauth.service.ts +++ b/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 { EnvironmentService } from '@abp/ng.core'; import { AUTH_FLOW_STRATEGY } from '../tokens/auth-flow-strategy'; -import { OAuthService } from 'angular-oauth2-oidc'; +import { AuthConfig, OAuthService } from "angular-oauth2-oidc"; @Injectable({ providedIn: 'root', }) export class AbpOAuthService implements IAuthService { - private strategy: AuthFlowStrategy; + private strategy!: AuthFlowStrategy; get isInternalAuth() { return this.strategy.isInternalAuth; @@ -25,7 +25,7 @@ export class AbpOAuthService implements IAuthService { const result$ = environmentService.getEnvironment$().pipe( map(env => env?.oAuthConfig), - filter(oAuthConfig => !!oAuthConfig), + filter(Boolean), tap(oAuthConfig => { this.strategy = oAuthConfig.responseType === 'code' diff --git a/npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts b/npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts index 3b5c89d4ac..7a07cb8985 100644 --- a/npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts +++ b/npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts @@ -9,15 +9,16 @@ import { import { Observable, of } from 'rxjs'; import { filter, switchMap, tap } from 'rxjs/operators'; import { - LoginParams, ConfigStateService, EnvironmentService, HttpErrorReporterService, + LoginParams, SessionStateService, TENANT_KEY, } from '@abp/ng.core'; import { clearOAuthStorage } from '../utils/clear-o-auth-storage'; import { oAuthStorage } from '../utils/oauth-storage'; +import { HttpErrorResponse } from '@angular/common/http'; export abstract class AuthFlowStrategy { abstract readonly isInternalAuth: boolean; @@ -26,7 +27,7 @@ export abstract class AuthFlowStrategy { protected environment: EnvironmentService; protected configState: ConfigStateService; protected oAuthService: OAuthService2; - protected oAuthConfig: AuthConfig; + protected oAuthConfig!: AuthConfig; protected sessionState: SessionStateService; protected tenantKey: string; @@ -38,7 +39,7 @@ export abstract class AuthFlowStrategy { abstract login(params?: LoginParams | Params): Observable; - private catchError = err => { + private catchError = (err: HttpErrorResponse) => { this.httpErrorReporter.reportError(err); return of(null); }; @@ -49,18 +50,17 @@ export abstract class AuthFlowStrategy { this.configState = injector.get(ConfigStateService); this.oAuthService = injector.get(OAuthService2); this.sessionState = injector.get(SessionStateService); - this.oAuthConfig = this.environment.getEnvironment().oAuthConfig; + this.oAuthConfig = this.environment.getEnvironment().oAuthConfig || {}; this.tenantKey = injector.get(TENANT_KEY); this.listenToOauthErrors(); } async init(): Promise { - const shouldClear = shouldStorageClear( - this.environment.getEnvironment().oAuthConfig.clientId, - oAuthStorage, - ); - if (shouldClear) clearOAuthStorage(oAuthStorage); + if (this.oAuthConfig.clientId) { + const shouldClear = shouldStorageClear(this.oAuthConfig.clientId, oAuthStorage); + if (shouldClear) clearOAuthStorage(oAuthStorage); + } this.oAuthService.configure(this.oAuthConfig); diff --git a/npm/ng-packs/packages/oauth/src/lib/utils/auth-utils.ts b/npm/ng-packs/packages/oauth/src/lib/utils/auth-utils.ts index 64dcd76576..24f94fe129 100644 --- a/npm/ng-packs/packages/oauth/src/lib/utils/auth-utils.ts +++ b/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(); localStorage.setItem(storageKey, 'true'); document.cookie = `${cookieKey}=true; path=/${ diff --git a/npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts b/npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts index 44cc372f32..6193a5bc20 100644 --- a/npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts +++ b/npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts @@ -49,10 +49,10 @@ export class PermissionManagementComponent PermissionManagement.PermissionManagementComponentOutputs { @Input() - readonly providerName: string; + readonly providerName!: string; @Input() - readonly providerKey: string; + readonly providerKey!: string; @Input() readonly hideBadges = false; @@ -90,13 +90,13 @@ export class PermissionManagementComponent @Output() readonly visibleChange = new EventEmitter(); @ViewChildren('selectAllInThisTabsRef') - selectAllInThisTabsRef: QueryList>; + selectAllInThisTabsRef!: QueryList>; @ViewChildren('selectAllInAllTabsRef') - selectAllInAllTabsRef: QueryList>; + selectAllInAllTabsRef!: QueryList>; - data: GetPermissionListResultDto = { groups: [], entityDisplayName: null }; + data: GetPermissionListResultDto = { groups: [], entityDisplayName: '' }; - selectedGroup: PermissionGroupDto; + selectedGroup?: PermissionGroupDto | null; permissions: PermissionWithGroupName[] = []; @@ -119,16 +119,16 @@ export class PermissionManagementComponent (document.body.dir as LocaleDirection) === 'rtl' ? 'right' : 'left' }.px`; - const permissions = this.data.groups.find( - group => group.name === this.selectedGroup.name, - ).permissions; + const permissions = + (this.data.groups.find(group => group.name === this.selectedGroup?.name) || {}).permissions || + []; return permissions.map( permission => ({ ...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), ); } @@ -158,7 +158,7 @@ export class PermissionManagementComponent return false; } - onClickCheckbox(clickedPermission: PermissionGrantInfoDto, value) { + onClickCheckbox(clickedPermission: PermissionGrantInfoDto) { if ( clickedPermission.isGranted && this.isGrantedByOtherProviderName(clickedPermission.grantedProviders) @@ -257,7 +257,7 @@ export class PermissionManagementComponent const changedPermissions: UpdatePermissionDto[] = this.permissions .filter(per => - unchangedPermissions.find(unchanged => unchanged.name === per.name).isGranted === + (unchangedPermissions.find(unchanged => unchanged.name === per.name) || {}).isGranted === per.isGranted ? false : true, @@ -305,7 +305,7 @@ export class PermissionManagementComponent initModal() { // TODO: Refactor setTimeout(() => { - this.setDisabled(this.selectedGroup.permissions); + this.setDisabled(this.selectedGroup?.permissions || []); this.setTabCheckboxState(); 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); if (parentPermission && parentPermission.parentName) { @@ -342,7 +345,10 @@ function findMargin(permissions: PermissionGrantInfoDto[], permission: Permissio function getPermissions(groups: PermissionGroupDto[]): PermissionWithGroupName[] { return groups.reduce( - (acc, val) => [...acc, ...val.permissions.map(p => ({ ...p, groupName: val.name }))], - [], + (acc, val) => [ + ...acc, + ...val.permissions.map(p => ({ ...p, groupName: val.name || '' })), + ], + [] as PermissionWithGroupName[], ); } diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/adapters/date-time.adapter.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/adapters/date-time.adapter.ts index cff2d41597..9e33b01de9 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/adapters/date-time.adapter.ts +++ b/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() export class DateTimeAdapter { - value!: NgbDateTimeStruct; + value!: Partial; - fromModel(value: string | Date): NgbDateTimeStruct | null { + fromModel(value: string | Date): Partial | null { if (!value) return null; const date = new Date(value); @@ -24,12 +24,12 @@ export class DateTimeAdapter { return this.value; } - toModel(value: NgbDateTimeStruct | null): string { + toModel(value: Partial | null): string { if (!value) return ''; const now = new Date(); - value = { + const newValue = { // TODO look for strict mode errors year: now.getUTCFullYear(), month: now.getMonth() + 1, @@ -39,11 +39,11 @@ export class DateTimeAdapter { second: 0, ...this.value, ...value, - }; + } as NgbDateTimeStruct; const date = new Date( - value.year, - value.month - 1, + newValue.year, + newValue.month - 1, value.day, value.hour, value.minute, diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/abstract-actions/abstract-actions.component.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/abstract-actions/abstract-actions.component.ts index 285e3fd00a..a7710d16a0 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/abstract-actions/abstract-actions.component.ts +++ b/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 { ActionData, ActionList } from '../../models/actions'; +import { ActionData, ActionList, InferredAction } from '../../models/actions'; import { ExtensionsService } from '../../services/extensions.service'; import { EXTENSIONS_ACTION_TYPE, EXTENSIONS_IDENTIFIER } from '../../tokens/extensions.token'; 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 // @dynamic @Directive() -export abstract class AbstractActionsComponent> extends ActionData< - InferredRecord -> { +export abstract class AbstractActionsComponent< + L extends ActionList>, +> extends ActionData> { readonly actionList: L; readonly getInjected: InferredData['getInjected']; diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form-prop.component.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form-prop.component.ts index 815a466c8f..1774289e7a 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form-prop.component.ts +++ b/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; - public injectorForCustomComponent: Injector; + public injectorForCustomComponent?: Injector; asterisk = ''; @@ -95,7 +95,7 @@ export class ExtensibleFormPropComponent implements OnChanges, AfterViewInit { ? text$.pipe( debounceTime(300), distinctUntilChanged(), - switchMap(text => this.prop.options(this.data, text)), + switchMap(text => this.prop?.options?.(this.data, text) || of([])), ) : of([]); @@ -109,7 +109,7 @@ export class ExtensibleFormPropComponent implements OnChanges, AfterViewInit { get isInvalid() { const control = this.form.get(this.prop.name); - return control.touched && control.invalid; + return control?.touched && control.invalid; } constructor( diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form.component.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form.component.ts index abb90c9cc6..bd6f23591f 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form.component.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form.component.ts @@ -44,7 +44,7 @@ export class ExtensibleFormComponent { } extraPropertiesKey = EXTRA_PROPERTIES_KEY; - groupedPropList: GroupedFormPropList; + groupedPropList!: GroupedFormPropList; record!: R; createGroupedList(propList: FormPropList) { diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-table/extensible-table.component.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-table/extensible-table.component.ts index b7685cc10a..6028e7e3ac 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-table/extensible-table.component.ts +++ b/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, }) export class ExtensibleTableComponent implements OnChanges { - protected _actionsText: string; + protected _actionsText!: string; @Input() set actionsText(value: string) { this._actionsText = value; @@ -57,13 +57,13 @@ export class ExtensibleTableComponent implements OnChanges { return this._actionsText ?? (this.actionList.length > 1 ? 'AbpUi::Actions' : ''); } - @Input() data: R[]; - @Input() list: ListService; - @Input() recordsTotal: number; + @Input() data!: R[]; + @Input() list!: ListService; + @Input() recordsTotal!: number; @Input() set actionsColumnWidth(width: number) { this.setColumnWidths(width ? Number(width) : undefined); } - @Input() actionsTemplate: TemplateRef; + @Input() actionsTemplate?: TemplateRef; @Output() tableActivate = new EventEmitter(); @@ -73,7 +73,7 @@ export class ExtensibleTableComponent implements OnChanges { entityPropTypeClasses: EntityPropTypeClass; - readonly columnWidths: number[]; + readonly columnWidths!: number[]; readonly propList: EntityPropList; @@ -102,7 +102,7 @@ export class ExtensibleTableComponent implements OnChanges { this.setColumnWidths(DEFAULT_ACTIONS_COLUMN_WIDTH); } - private setColumnWidths(actionsColumn: number) { + private setColumnWidths(actionsColumn: number | undefined) { const widths = [actionsColumn]; this.propList.forEach(({ value: prop }) => { widths.push(prop.columnWidth); @@ -110,8 +110,8 @@ export class ExtensibleTableComponent implements OnChanges { (this.columnWidths as any) = widths; } - private getDate(value: Date, format: string) { - return value ? formatDate(value, format, this.locale) : ''; + private getDate(value: Date | undefined, format: string | undefined) { + return value && format ? formatDate(value, format, this.locale) : ''; } private getIcon(value: boolean) { @@ -122,7 +122,7 @@ export class ExtensibleTableComponent implements OnChanges { private getEnum(rowValue: any, list: Array>) { if (!list) return rowValue; - const { key } = list.find(({ value }) => value === rowValue); + const { key } = list.find(({ value }) => value === rowValue) || {}; return key; } @@ -139,7 +139,7 @@ export class ExtensibleTableComponent implements OnChanges { case ePropType.DateTime: return this.getDate(value, getShortDateShortTimeFormat(this.config)); case ePropType.Enum: - return this.getEnum(value, prop.enumList); + return this.getEnum(value, prop.enumList || []); default: return value; // More types can be handled in the future @@ -151,7 +151,7 @@ export class ExtensibleTableComponent implements OnChanges { ngOnChanges({ data }: SimpleChanges) { if (!data?.currentValue) return; - this.data = data.currentValue.map((record, index) => { + this.data = data.currentValue.map((record: any, index: number) => { this.propList.forEach(prop => { const propData = { getInjected: this.getInjected, record, index } as any; const value = this.getContent(prop.value, propData); diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/grid-actions/grid-actions.component.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/grid-actions/grid-actions.component.ts index 30d36699b6..22b5419b55 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/grid-actions/grid-actions.component.ts +++ b/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 extends AbstractActionsComponent> { @Input() icon = 'fa fa-cog'; - @Input() readonly index: number; + @Input() readonly index?: number; @Input() text = ''; diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/page-toolbar/page-toolbar.component.html b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/page-toolbar/page-toolbar.component.html index dc481700d4..649fb625ff 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/page-toolbar/page-toolbar.component.html +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/page-toolbar/page-toolbar.component.html @@ -13,15 +13,17 @@
- + + +
diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/page-toolbar/page-toolbar.component.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/page-toolbar/page-toolbar.component.ts index 8015aaa84f..afe421554b 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/page-toolbar/page-toolbar.component.ts +++ b/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 { HasCreateInjectorPipe, + ToolbarAction, + ToolbarActionDefault, ToolbarActionList, ToolbarComponent, } from '../../models/toolbar-actions'; @@ -32,4 +34,10 @@ export class PageToolbarComponent constructor(public readonly injector: Injector) { super(injector); } + + asToolbarAction(value: ToolbarActionDefault): { value: ToolbarAction } { + return { + value: value as ToolbarAction, + }; + } } diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/actions.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/actions.ts index 890899e515..d50d48678f 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/actions.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/actions.ts @@ -1,5 +1,5 @@ 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'; export abstract class ActionList> extends LinkedList {} @@ -8,7 +8,7 @@ export abstract class ActionData { abstract getInjected: ( token: Type | InjectionToken, notFoundValue?: T, - flags?: InjectFlags, + flags?: InjectOptions | InjectFlags, ) => T; index?: number; abstract record: R; @@ -27,8 +27,8 @@ export type ReadonlyActionData = O.Readonly, 'data'> export abstract class Action { constructor( public readonly permission: string, - public readonly visible: ActionPredicate = _ => true, - public readonly action: ActionCallback = _ => {}, + public readonly visible: ActionPredicate = () => true, + public readonly action: ActionCallback = () => {}, ) {} } @@ -46,7 +46,7 @@ export abstract class ActionsFactory> { } } -export abstract class Actions { +export abstract class Actions>> { protected abstract _ctor: Type; get actions(): L { @@ -68,11 +68,14 @@ export abstract class Actions { } } -export type ActionContributorCallbacks> = Record< +export type ActionContributorCallbacks>> = Record< string, ActionContributorCallback[] >; -export type ActionContributorCallback> = (actionList: L) => any; +export type ActionContributorCallback>> = ( + actionList: L, +) => any; type InferredActionList = C extends Actions ? L : never; +export type InferredAction = T extends ActionList ? U : T; diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/entity-actions.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/entity-actions.ts index 09dda5127e..99253c0da8 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/entity-actions.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/entity-actions.ts @@ -24,7 +24,7 @@ export class EntityAction extends Action { readonly icon: string; constructor(options: EntityActionOptions) { - super(options.permission, options.visible, options.action); + super(options.permission || '', options.visible, options.action); this.text = options.text; this.icon = options.icon || ''; } diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/entity-props.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/entity-props.ts index dcbd56c07f..3bf4142e75 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/entity-props.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/entity-props.ts @@ -27,16 +27,16 @@ export class EntityProp extends Prop { readonly columnWidth: number | undefined; readonly sortable: boolean; readonly valueResolver: PropCallback>; - readonly action: ActionCallback; - readonly component: Type; - readonly enumList: Array>; + readonly action?: ActionCallback; + readonly component?: Type; + readonly enumList?: Array>; constructor(options: EntityPropOptions) { super( options.type, options.name, - options.displayName, - options.permission, + options.displayName || '', + options.permission || '', options.visible, options.isExtra, ); @@ -44,10 +44,17 @@ export class EntityProp extends Prop { this.columnWidth = options.columnWidth; this.sortable = options.sortable || false; this.valueResolver = - options.valueResolver || (data => of(escapeHtmlChars(data.record[this.name]))); - this.action = options.action; - this.component = options.component; - this.enumList = options.enumList; + options.valueResolver || + (data => of(escapeHtmlChars((data.record as PropDataObject)[this.name]))); + if (options.action) { + this.action = options.action; + } + if (options.component) { + this.component = options.component; + } + if (options.enumList) { + this.enumList = options.enumList; + } } static create(options: EntityPropOptions) { @@ -76,3 +83,4 @@ export type EntityPropOptions = O.Optional< export type EntityPropDefaults = Record[]>; export type EntityPropContributorCallback = PropContributorCallback>; export type EntityPropContributorCallbacks = PropContributorCallbacks>; +type PropDataObject = { [key: string]: any }; diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/form-props.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/form-props.ts index af0ae767d7..47a64142e6 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/form-props.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/form-props.ts @@ -18,7 +18,7 @@ import { export class FormPropList extends PropList> {} -export class FormProps extends Props> { +export class FormProps extends Props>> { protected _ctor: Type> = FormPropList; } @@ -46,7 +46,7 @@ export class GroupedFormPropList { } export interface GroupedFormPropItem { - group: FormPropGroup; + group?: FormPropGroup; formPropList: FormPropList; } @@ -76,8 +76,8 @@ export class FormProp extends Prop { super( options.type, options.name, - options.displayName, - options.permission, + options.displayName || '', + options.permission || '', options.visible, options.isExtra, options.template, @@ -94,7 +94,7 @@ export class FormProp extends Prop { this.options = options.options; this.id = options.id || options.name; const defaultValue = options.defaultValue; - this.defaultValue = isFalsyValue(defaultValue) ? defaultValue : defaultValue || null; + this.defaultValue = isFalsyValue(defaultValue) ? (defaultValue as number) : defaultValue || ''; this.displayTextResolver = options.displayTextResolver; } @@ -141,6 +141,6 @@ export type EditFormPropDefaults = Record[]>; export type EditFormPropContributorCallback = PropContributorCallback>; export type EditFormPropContributorCallbacks = PropContributorCallbacks>; -function isFalsyValue(defaultValue: FormProp['defaultValue']): boolean { +function isFalsyValue(defaultValue?: FormProp['defaultValue']): boolean { return [0, '', false].indexOf(defaultValue as any) > -1; } diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/internal/object-extensions.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/internal/object-extensions.ts index 776785ed4c..811b0a04f3 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/internal/object-extensions.ts +++ b/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 = ( displayName: LocalizableStringDto, fallback: LocalizableStringDto, -) => string; +) => string | undefined; export type EntityExtensions = Record; diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/props.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/props.ts index a393e7587c..867380e9d8 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/props.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/props.ts @@ -56,7 +56,7 @@ export abstract class PropsFactory> { } } -export abstract class Props { +export abstract class Props>> { protected abstract _ctor: Type; get props(): L { @@ -78,11 +78,14 @@ export abstract class Props { } } -export type PropContributorCallbacks> = Record< +export type PropContributorCallbacks>> = Record< string, PropContributorCallback[] >; -export type PropContributorCallback> = (propList: L) => any; +export type PropContributorCallback>> = ( + propList: L, +) => any; type InferredPropList = C extends Props ? L : never; +export type InferredProp = T extends PropList ? U : T; diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/toolbar-actions.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/toolbar-actions.ts index 048ce486c8..02b26a8173 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/toolbar-actions.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/toolbar-actions.ts @@ -11,10 +11,7 @@ import { ReadonlyActionData, } from './actions'; -export class ToolbarActionList extends ActionList< - R, - ToolbarAction | ToolbarComponent -> {} +export class ToolbarActionList extends ActionList> {} export class ToolbarActions extends Actions> { protected _ctor: Type> = ToolbarActionList; @@ -84,7 +81,7 @@ export type ToolbarActionContributorCallbacks = ActionContributorCallba ToolbarActionList >; export type InferredData = ActionData>; -export type InferredRecord = L extends ActionList ? R : never; +export type InferredRecord = L extends ActionList ? R : any; export interface HasCreateInjectorPipe { getData: () => ReadonlyActionData; diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/pipes/create-injector.pipe.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/pipes/create-injector.pipe.ts index dff92e2c2d..3536fa4dad 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/pipes/create-injector.pipe.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/pipes/create-injector.pipe.ts @@ -25,7 +25,7 @@ export class CreateInjectorPipe implements PipeTransform { options?: InjectOptions | InjectFlags, ) => { const componentData = context.getData(); - const componentDataCallback = data => { + const componentDataCallback = (data: any) => { data = data ?? context.getData(); return action.action(data); }; diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/actions.util.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/actions.util.ts index f4501317df..8017afbb31 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/actions.util.ts +++ b/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 { EntityActionContributorCallbacks, EntityActionDefaults, @@ -20,7 +20,7 @@ export function mergeWithDefaultActions>( Object.keys(defaultActions).forEach((name: string) => { const actions: InferredActions = extension.get(name); actions.clearContributors(); - actions.addContributor((actionList: ActionList) => + actions.addContributor((actionList: ActionList>) => actionList.addManyTail(defaultActions[name]), ); contributors.forEach(contributor => diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/enum.util.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/enum.util.ts index 5b4181a0fa..57925956d6 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/enum.util.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/enum.util.ts @@ -1,11 +1,11 @@ -import { ABP, LocalizationService } from '@abp/ng.core'; +import { ABP, ExtensionEnumFieldDto, LocalizationService } from '@abp/ng.core'; import { merge, Observable, of } from 'rxjs'; import { map } from 'rxjs/operators'; import { EXTRA_PROPERTIES_KEY } from '../constants/extra-properties'; import { ObjectExtensions } from '../models/object-extensions'; import { PropCallback } from '../models/props'; -export function createEnum(members: ObjectExtensions.ExtensionEnumFieldDto[]) { +export function createEnum(members: ExtensionEnumFieldDto[]) { const enumObject: any = {}; members.forEach(({ name = '', value }) => { diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/form-props.util.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/form-props.util.ts index 7bdad1f7b2..617770f081 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/form-props.util.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/form-props.util.ts @@ -4,20 +4,20 @@ import { DateAdapter } from '../adapters/date.adapter'; import { TimeAdapter } from '../adapters/time.adapter'; import { EXTRA_PROPERTIES_KEY } from '../constants/extra-properties'; import { ePropType } from '../enums/props.enum'; -import { FormPropList } from '../models/form-props'; -import { PropData } from '../models/props'; +import { FormProp, FormPropList } from "../models/form-props"; +import { InferredProp, PropData } from "../models/props"; import { ExtensionsService } from '../services/extensions.service'; import { EXTENSIONS_IDENTIFIER } from '../tokens/extensions.token'; -export function generateFormFromProps(data: PropData) { - const extensions = data.getInjected(ExtensionsService); +export function generateFormFromProps(data: PropData) { + const extensions = data.getInjected(ExtensionsService); const identifier = data.getInjected(EXTENSIONS_IDENTIFIER); const form = new UntypedFormGroup({}); const extraForm = new UntypedFormGroup({}); form.addControl(EXTRA_PROPERTIES_KEY, extraForm); - const record = data.record || {}; + const record = data.record || {} as {[key:string]: any}; const type = JSON.stringify(record) === '{}' ? 'create' : 'edit'; const props: FormPropList = extensions[`${type}FormProps`].get(identifier).props; const extraProperties = record[EXTRA_PROPERTIES_KEY] || {}; diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/props.util.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/props.util.ts index b750131065..24360dccc1 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/props.util.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/props.util.ts @@ -1,4 +1,4 @@ -import { of } from 'rxjs'; +import { Observable, of } from 'rxjs'; import { EXTRA_PROPERTIES_KEY } from '../constants/extra-properties'; import { EntityPropContributorCallbacks, @@ -15,10 +15,18 @@ import { EditFormPropsFactory, FormProps, } from '../models/form-props'; -import { PropContributorCallback, PropData, PropList, PropsFactory } from '../models/props'; +import { + InferredProp, + PropCallback, + PropContributorCallback, + PropList, + PropsFactory, +} from '../models/props'; -export function createExtraPropertyValueResolver(name: string) { - return (data?: PropData) => of(data.record[EXTRA_PROPERTIES_KEY][name]); +export function createExtraPropertyValueResolver( + name: string, +): PropCallback> { + return (data?) => of((data.record as { [key: string]: any })[EXTRA_PROPERTIES_KEY][name]); } export function mergeWithDefaultProps>( @@ -29,7 +37,9 @@ export function mergeWithDefaultProps>( Object.keys(defaultProps).forEach((name: string) => { const props: InferredProps = extension.get(name); props.clearContributors(); - props.addContributor((propList: PropList) => propList.addManyTail(defaultProps[name])); + props.addContributor((propList: PropList>) => + propList.addManyTail(defaultProps[name]), + ); contributors.forEach(contributor => (contributor[name] || []).forEach((callback: PropContributorCallback) => props.addContributor(callback), diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/state.util.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/state.util.ts index c8e2b03e36..ef5fef48c3 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/state.util.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/state.util.ts @@ -2,29 +2,29 @@ import { ABP, ApplicationLocalizationConfigurationDto, ConfigStateService, + ExtensionEnumDto, ExtensionPropertyUiLookupDto, -} from '@abp/ng.core'; -import { Observable, pipe, zip } from 'rxjs'; -import { filter, map, switchMap, take } from 'rxjs/operators'; -import { ePropType } from '../enums/props.enum'; -import { EntityProp, EntityPropList } from '../models/entity-props'; -import { FormProp, FormPropList } from '../models/form-props'; -import { ObjectExtensions } from '../models/object-extensions'; -import { PropCallback } from '../models/props'; -import { createEnum, createEnumOptions, createEnumValueResolver } from './enum.util'; -import { createDisplayNameLocalizationPipeKeyGenerator } from './localization.util'; -import { createExtraPropertyValueResolver } from './props.util'; + ObjectExtensionsDto +} from "@abp/ng.core"; +import { Observable, pipe, zip } from "rxjs"; +import { filter, map, switchMap, take } from "rxjs/operators"; +import { ePropType } from "../enums/props.enum"; +import { EntityProp, EntityPropList } from "../models/entity-props"; +import { FormProp, FormPropList } from "../models/form-props"; +import { ObjectExtensions } from "../models/object-extensions"; +import { PropCallback } from "../models/props"; +import { createEnum, createEnumOptions, createEnumValueResolver } from "./enum.util"; +import { createDisplayNameLocalizationPipeKeyGenerator } from "./localization.util"; +import { createExtraPropertyValueResolver } from "./props.util"; import { createTypeaheadDisplayNameGenerator, createTypeaheadOptions, getTypeaheadType, - hasTypeaheadTextSuffix, -} from './typeahead.util'; -import { getValidatorsFromProperty } from './validation.util'; + hasTypeaheadTextSuffix +} from "./typeahead.util"; +import { getValidatorsFromProperty } from "./validation.util"; -function selectObjectExtensions( - configState: ConfigStateService, -): Observable { +function selectObjectExtensions(configState: ConfigStateService): Observable { return configState.getOne$('objectExtensions'); } @@ -36,9 +36,9 @@ function selectLocalization( function selectEnums( configState: ConfigStateService, -): Observable> { +): Observable> { return selectObjectExtensions(configState).pipe( - map((extensions: ObjectExtensions.ObjectExtensionsDto) => + map((extensions: ObjectExtensionsDto) => Object.keys(extensions.enums).reduce((acc, key) => { const { fields, localizationResource } = extensions.enums[key]; acc[key] = { @@ -63,7 +63,7 @@ export function getObjectExtensionEntitiesFromStore( return (extensions.modules[moduleKey] || ({} as ObjectExtensions.ModuleExtensionDto)) .entities; }), - map(entities => (isUndefined(entities) ? {} : entities)), + map(entities => (isUndefined(entities) ? ({} as any) : entities)), filter(Boolean), take(1), ); @@ -141,8 +141,8 @@ function createPropertiesToContributorsMapper( if (property.ui.onTable.isVisible) { const sortable = Boolean(property.ui.onTable.isSortable); const columnWidth = type === ePropType.Boolean ? 150 : 250; - const valueResolver = - type === ePropType.Enum + const valueResolver: PropCallback> = + type === ePropType.Enum && property.type ? createEnumValueResolver(property.type, enums[property.type], propName) : createExtraPropertyValueResolver(propName); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.ts index 68ac0212ff..00c01f630e 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.ts @@ -1,4 +1,11 @@ -import { ABP, getRoutePath, RouterEvents, RoutesService, SubscriptionService, TreeNode } from '@abp/ng.core'; +import { + ABP, + getRoutePath, + RouterEvents, + RoutesService, + SubscriptionService, + TreeNode, +} from '@abp/ng.core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { map, startWith } from 'rxjs/operators'; diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/confirmation/confirmation.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/confirmation/confirmation.component.ts index 53e09d9788..13c857901c 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/confirmation/confirmation.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/confirmation/confirmation.component.ts @@ -15,7 +15,7 @@ export class ConfirmationComponent { reject = Confirmation.Status.reject; dismiss = Confirmation.Status.dismiss; - confirmation$!: ReplaySubject; + confirmation$!: ReplaySubject; clear!: (status: Confirmation.Status) => void; @@ -30,7 +30,10 @@ export class ConfirmationComponent { if (!this.icons) { return ''; } - return this.icons[severity] || this.icons.default; + if (severity) { + return this.icons[severity]; + } + return this.icons.default; } isCustomIconExists({ options }: Confirmation.DialogData): boolean { diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/password/password.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/password/password.component.ts index 74020240a1..22fcd6e4f5 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/password/password.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/password/password.component.ts @@ -4,7 +4,7 @@ import { NG_VALUE_ACCESSOR } from '@angular/forms'; @Component({ selector: 'abp-password', - templateUrl: `password.component.html`, + templateUrl: `./password.component.html`, providers: [ { provide: NG_VALUE_ACCESSOR, @@ -16,7 +16,7 @@ import { NG_VALUE_ACCESSOR } from '@angular/forms'; export class PasswordComponent extends AbstractNgModelComponent { @Input() inputId!: string; @Input() formControlName!: string; - fieldTextType: boolean; + fieldTextType?: boolean; constructor(injector: Injector) { super(injector); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/services/abstract-menu.service.ts b/npm/ng-packs/packages/theme-shared/src/lib/services/abstract-menu.service.ts index 2c3d904a1b..e1048f907e 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/services/abstract-menu.service.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/services/abstract-menu.service.ts @@ -1,8 +1,9 @@ import { BehaviorSubject, Observable } from 'rxjs'; import { NavItem } from '../models/nav-item'; +import { Type } from '@angular/core'; export abstract class AbstractMenuService { - protected abstract baseClass; + protected abstract baseClass: Type; protected _items$ = new BehaviorSubject([]); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/services/confirmation.service.ts b/npm/ng-packs/packages/theme-shared/src/lib/services/confirmation.service.ts index f93e850aaf..5eeadb0ab6 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/services/confirmation.service.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/services/confirmation.service.ts @@ -8,7 +8,7 @@ import { Confirmation } from '../models/confirmation'; @Injectable({ providedIn: 'root' }) export class ConfirmationService { status$!: Subject; - confirmation$ = new ReplaySubject(1); + confirmation$ = new ReplaySubject(1); private containerComponentRef!: ComponentRef; diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tokens/confirmation-icons.token.ts b/npm/ng-packs/packages/theme-shared/src/lib/tokens/confirmation-icons.token.ts index 0c001cd9d6..6c1ed5b0b5 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/tokens/confirmation-icons.token.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/tokens/confirmation-icons.token.ts @@ -6,6 +6,7 @@ export interface ConfirmationIcons { warning: string; error: string; default: string; + neutral: string; } export const CONFIRMATION_ICONS = new InjectionToken>( @@ -18,4 +19,5 @@ export const DEFAULT_CONFIRMATION_ICONS: ConfirmationIcons = { warning: 'fa fa-exclamation-triangle', error: 'fa fa-times-circle', default: 'fa fa-question-circle', + neutral: '', };