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 eb2a0d30b6..69cf23e8a4 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,6 +1,6 @@ import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { map, tap } from 'rxjs/operators'; +import { Observable, Subject } from 'rxjs'; +import { map, take, switchMap } from 'rxjs/operators'; import { ApplicationConfigurationDto } from '../proxy/volo/abp/asp-net-core/mvc/application-configurations/models'; import { InternalStore } from '../utils/internal-store-utils'; import { AbpApplicationConfigurationService } from '../proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-configuration.service'; @@ -15,14 +15,29 @@ export class ConfigStateService { return this.store.sliceUpdate; } - constructor(private abpConfigService: AbpApplicationConfigurationService) {} + private updateSubject = new Subject(); + constructor(private abpConfigService: AbpApplicationConfigurationService) { + this.initUpdateStream(); + } + + private initUpdateStream() { + this.updateSubject + .pipe(switchMap(() => this.abpConfigService.get())) + .subscribe(res => this.setState(res)); + } + + /** + * @deprecated do not use this method directly, instead call refreshAppState + * This method will be private in v5.0 + */ setState(state: ApplicationConfigurationDto) { this.store.set(state); } refreshAppState() { - return this.abpConfigService.get().pipe(tap(res => this.setState(res))); + this.updateSubject.next(); + return this.createOnUpdateStream(state => state).pipe(take(1)); } getOne$(key: string) { 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 dc229a4c22..fe6e410f24 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 @@ -1,10 +1,9 @@ import { registerLocaleData } from '@angular/common'; import { Injectable, Injector, isDevMode, Optional, SkipSelf } from '@angular/core'; import { from, Observable, Subject } from 'rxjs'; -import { filter, map, mapTo, switchMap, tap } from 'rxjs/operators'; +import { filter, map, mapTo, switchMap } from 'rxjs/operators'; import { ABP } from '../models/common'; import { Config } from '../models/config'; -import { AbpApplicationConfigurationService } from '../proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-configuration.service'; import { ApplicationConfigurationDto } from '../proxy/volo/abp/asp-net-core/mvc/application-configurations/models'; import { CORE_OPTIONS } from '../tokens/options.token'; import { createLocalizer, createLocalizerWithFallback } from '../utils/localization-utils'; @@ -35,7 +34,6 @@ export class LocalizationService { @SkipSelf() otherInstance: LocalizationService, private configState: ConfigStateService, - private appConfigService: AbpApplicationConfigurationService, ) { if (otherInstance) throw new Error('LocalizationService should have only one instance.'); @@ -49,12 +47,7 @@ export class LocalizationService { filter( lang => this.configState.getDeep('localization.currentCulture.cultureName') !== lang, ), - switchMap(lang => - this.appConfigService - .get() - .pipe(tap(res => this.configState.setState(res))) - .pipe(mapTo(lang)), - ), + switchMap(lang => this.configState.refreshAppState().pipe(mapTo(lang))), switchMap(lang => from(this.registerLocale(lang).then(() => lang))), ) .subscribe(lang => this._languageChange$.next(lang)); diff --git a/npm/ng-packs/packages/core/src/lib/states/config.state.ts b/npm/ng-packs/packages/core/src/lib/states/config.state.ts index 4cc2dc741d..455014e895 100644 --- a/npm/ng-packs/packages/core/src/lib/states/config.state.ts +++ b/npm/ng-packs/packages/core/src/lib/states/config.state.ts @@ -1,19 +1,17 @@ import { HttpClient, HttpErrorResponse } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Action, createSelector, Selector, State, StateContext, Store } from '@ngxs/store'; -import { of, throwError } from 'rxjs'; -import { catchError, distinctUntilChanged, switchMap, tap } from 'rxjs/operators'; +import { throwError } from 'rxjs'; +import { catchError, distinctUntilChanged } from 'rxjs/operators'; import snq from 'snq'; import { GetAppConfiguration, PatchConfigState, SetEnvironment } from '../actions/config.actions'; import { RestOccurError } from '../actions/rest.actions'; -import { ApplicationConfiguration } from '../models/application-configuration'; import { Config } from '../models/config'; import { ConfigStateService } from '../services/config-state.service'; import { EnvironmentService } from '../services/environment.service'; import { SessionStateService } from '../services/session-state.service'; import { interpolate } from '../utils/string-utils'; import compare from 'just-compare'; -import { ApplicationConfigurationDto } from '../proxy/volo/abp/asp-net-core/mvc/application-configurations/models'; /** * @deprecated Use ConfigStateService instead. To be deleted in v5.0. @@ -143,11 +141,16 @@ export class ConfigState { } static getLocalizationResource(resourceName: string) { - const selector = createSelector([ConfigState], (state: Config.State): { - [key: string]: string; - } => { - return state.localization.values[resourceName]; - }); + const selector = createSelector( + [ConfigState], + ( + state: Config.State, + ): { + [key: string]: string; + } => { + return state.localization.values[resourceName]; + }, + ); return selector; } @@ -217,9 +220,7 @@ export class ConfigState { } constructor( - private http: HttpClient, private store: Store, - private sessionState: SessionStateService, private environmentService: EnvironmentService, private configState: ConfigStateService, ) { @@ -245,15 +246,12 @@ export class ConfigState { addData({ patchState, dispatch }: StateContext) { const apiName = 'default'; const api = this.store.selectSnapshot(ConfigState.getApiUrl(apiName)); - return this.http - .get(`${api}/api/abp/application-configuration`) - .pipe( - tap(configuration => this.configState.setState(configuration)), - catchError((err: HttpErrorResponse) => { - dispatch(new RestOccurError(err)); - return throwError(err); - }), - ); + return this.configState.refreshAppState().pipe( + catchError((err: HttpErrorResponse) => { + dispatch(new RestOccurError(err)); + return throwError(err); + }), + ); } @Action(SetEnvironment) diff --git a/npm/ng-packs/packages/core/src/lib/strategies/auth-flow.strategy.ts b/npm/ng-packs/packages/core/src/lib/strategies/auth-flow.strategy.ts index 4cb959ac45..001d0e8842 100644 --- a/npm/ng-packs/packages/core/src/lib/strategies/auth-flow.strategy.ts +++ b/npm/ng-packs/packages/core/src/lib/strategies/auth-flow.strategy.ts @@ -13,7 +13,6 @@ import { from, Observable, of, pipe } from 'rxjs'; import { filter, switchMap, tap } from 'rxjs/operators'; import { RestOccurError } from '../actions/rest.actions'; import { LoginParams } from '../models/auth'; -import { AbpApplicationConfigurationService } from '../proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-configuration.service'; import { ConfigStateService } from '../services/config-state.service'; import { EnvironmentService } from '../services/environment.service'; import { SessionStateService } from '../services/session-state.service'; @@ -32,7 +31,6 @@ export abstract class AuthFlowStrategy { protected oAuthService: OAuthService; protected oAuthConfig: AuthConfig; protected sessionState: SessionStateService; - protected appConfigService: AbpApplicationConfigurationService; protected tenantKey: string; abstract checkIfInternalAuth(queryParams?: Params): boolean; @@ -47,7 +45,6 @@ export abstract class AuthFlowStrategy { this.environment = injector.get(EnvironmentService); this.configState = injector.get(ConfigStateService); this.oAuthService = injector.get(OAuthService); - this.appConfigService = injector.get(AbpApplicationConfigurationService); this.sessionState = injector.get(SessionStateService); this.oAuthConfig = this.environment.getEnvironment().oAuthConfig; this.tenantKey = injector.get(TENANT_KEY); @@ -84,11 +81,9 @@ export abstract class AuthFlowStrategy { .pipe( filter(event => event instanceof OAuthErrorEvent), tap(() => clearOAuthStorage()), - switchMap(() => this.appConfigService.get()), + switchMap(() => this.configState.refreshAppState()), ) - .subscribe(res => { - this.configState.setState(res); - }); + .subscribe(); } } @@ -148,9 +143,7 @@ export class AuthPasswordFlowStrategy extends AuthFlowStrategy { } else { this.oAuthService.logOut(); removeRememberMe(); - this.appConfigService.get().subscribe(res => { - this.configState.setState(res); - }); + this.configState.refreshAppState().subscribe(); } }); } @@ -188,9 +181,8 @@ export class AuthPasswordFlowStrategy extends AuthFlowStrategy { const router = this.injector.get(Router); return pipe( - switchMap(() => this.appConfigService.get()), - tap(res => { - this.configState.setState(res); + switchMap(() => this.configState.refreshAppState()), + tap(() => { setRememberMe(params.rememberMe); if (params.redirectUrl) router.navigate([params.redirectUrl]); }), @@ -201,9 +193,8 @@ export class AuthPasswordFlowStrategy extends AuthFlowStrategy { const router = this.injector.get(Router); return from(this.oAuthService.revokeTokenAndLogout(queryParams)).pipe( - switchMap(() => this.appConfigService.get()), - tap(res => { - this.configState.setState(res); + switchMap(() => this.configState.refreshAppState()), + tap(() => { router.navigateByUrl('/'); removeRememberMe(); }), diff --git a/npm/ng-packs/packages/core/src/lib/utils/auth-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/auth-utils.ts index 44da3f7c4a..10fe1e1177 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/auth-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/auth-utils.ts @@ -4,7 +4,6 @@ import { OAuthStorage, TokenResponse } from 'angular-oauth2-oidc'; import { pipe } from 'rxjs'; import { switchMap, tap } from 'rxjs/operators'; import { LoginParams } from '../models/auth'; -import { AbpApplicationConfigurationService } from '../proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-configuration.service'; import { ConfigStateService } from '../services/config-state.service'; const cookieKey = 'rememberMe'; @@ -15,13 +14,11 @@ export function pipeToLogin( injector: Injector, ) { const configState = injector.get(ConfigStateService); - const appConfigService = injector.get(AbpApplicationConfigurationService); const router = injector.get(Router); return pipe( - switchMap(() => appConfigService.get()), - tap(res => { - configState.setState(res); + switchMap(() => configState.refreshAppState()), + tap(() => { setRememberMe(params.rememberMe); if (params.redirectUrl) router.navigate([params.redirectUrl]); }), diff --git a/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts index 87982d8bd0..9c14d14b6d 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts @@ -5,7 +5,6 @@ import { tap, catchError } from 'rxjs/operators'; import { throwError } from 'rxjs'; import { ABP } from '../models/common'; import { Environment } from '../models/environment'; -import { AbpApplicationConfigurationService } from '../proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-configuration.service'; import { CurrentTenantDto } from '../proxy/volo/abp/asp-net-core/mvc/multi-tenancy/models'; import { AuthService } from '../services/auth.service'; import { ConfigStateService } from '../services/config-state.service'; @@ -21,7 +20,6 @@ export function getInitialData(injector: Injector) { const fn = async () => { const environmentService = injector.get(EnvironmentService); const configState = injector.get(ConfigStateService); - const appConfigService = injector.get(AbpApplicationConfigurationService); const options = injector.get(CORE_OPTIONS) as ABP.Root; environmentService.setState(options.environment as Environment); @@ -31,10 +29,9 @@ export function getInitialData(injector: Injector) { if (options.skipGetAppConfiguration) return; - return appConfigService - .get() + return configState + .refreshAppState() .pipe( - tap(res => configState.setState(res)), tap(() => checkAccessToken(injector)), tap(() => { const currentTenant = configState.getOne('currentTenant') as CurrentTenantDto; diff --git a/npm/ng-packs/packages/feature-management/src/lib/components/feature-management/feature-management.component.ts b/npm/ng-packs/packages/feature-management/src/lib/components/feature-management/feature-management.component.ts index 4bda77b4fb..e40779eba4 100644 --- a/npm/ng-packs/packages/feature-management/src/lib/components/feature-management/feature-management.component.ts +++ b/npm/ng-packs/packages/feature-management/src/lib/components/feature-management/feature-management.component.ts @@ -1,12 +1,8 @@ -import { - AbpApplicationConfigurationService, - ConfigStateService, - TrackByService, -} from '@abp/ng.core'; +import { ConfigStateService, TrackByService } from '@abp/ng.core'; import { LocaleDirection } from '@abp/ng.theme.shared'; import { Component, EventEmitter, Input, Output } from '@angular/core'; import { Store } from '@ngxs/store'; -import { finalize, tap } from 'rxjs/operators'; +import { finalize } from 'rxjs/operators'; import { FeatureManagement } from '../../models/feature-management'; import { FeaturesService } from '../../proxy/feature-management/features.service'; import { @@ -29,7 +25,8 @@ enum ValueTypes { export class FeatureManagementComponent implements FeatureManagement.FeatureManagementComponentInputs, - FeatureManagement.FeatureManagementComponentOutputs { + FeatureManagement.FeatureManagementComponentOutputs +{ @Input() providerKey: string; @@ -70,7 +67,6 @@ export class FeatureManagementComponent protected service: FeaturesService, protected store: Store, protected configState: ConfigStateService, - protected appConfigService: AbpApplicationConfigurationService, ) {} openModal() { @@ -122,10 +118,7 @@ export class FeatureManagementComponent if (!this.providerKey) { // to refresh host's features - this.appConfigService - .get() - .pipe(tap(res => this.configState.setState(res))) - .subscribe(); + this.configState.refreshAppState().subscribe(); } }); } 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 67a48cb507..2fe9a1f294 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 @@ -1,8 +1,4 @@ -import { - AbpApplicationConfigurationService, - ConfigStateService, - CurrentUserDto, -} from '@abp/ng.core'; +import { ConfigStateService, CurrentUserDto } from '@abp/ng.core'; import { LocaleDirection } from '@abp/ng.theme.shared'; import { Component, EventEmitter, Input, Output, TrackByFunction } from '@angular/core'; import { Select, Store } from '@ngxs/store'; @@ -39,7 +35,8 @@ type PermissionWithStyle = PermissionGrantInfoDto & { export class PermissionManagementComponent implements PermissionManagement.PermissionManagementComponentInputs, - PermissionManagement.PermissionManagementComponentOutputs { + PermissionManagement.PermissionManagementComponentOutputs +{ @Input() readonly providerName: string; @@ -105,21 +102,17 @@ export class PermissionManagementComponent map(permissions => permissions.map( permission => - (({ + ({ ...permission, style: { [margin]: findMargin(permissions, permission) }, isGranted: this.permissions.find(per => per.name === permission.name).isGranted, - } as any) as PermissionWithStyle), + } as any as PermissionWithStyle), ), ), ); } - constructor( - protected store: Store, - protected configState: ConfigStateService, - protected appConfigService: AbpApplicationConfigurationService, - ) {} + constructor(protected store: Store, protected configState: ConfigStateService) {} getChecked(name: string) { return (this.permissions.find(per => per.name === name) || { isGranted: false }).isGranted; @@ -253,9 +246,7 @@ export class PermissionManagementComponent ) .pipe( switchMap(() => - this.shouldFetchAppConfig() - ? this.appConfigService.get().pipe(tap(res => this.configState.setState(res))) - : of(null), + this.shouldFetchAppConfig() ? this.configState.refreshAppState() : of(null), ), finalize(() => (this.modalBusy = false)), )