From 20febc999057d77d0a2d2f270c6f5ac707e6fb95 Mon Sep 17 00:00:00 2001 From: "kim.tran" Date: Mon, 11 Dec 2023 08:35:06 +0100 Subject: [PATCH 01/13] feat: delte mfe info --- libs/portal-integration-angular/src/index.ts | 1 + .../src/lib/api/injection-tokens.ts | 6 --- .../data-list-grid.component.html | 4 +- .../data-list-grid.component.ts | 16 ++++---- .../data-view/data-view.component.spec.ts | 12 ------ .../diagram/diagram.component.spec.ts | 12 ------ .../group-by-count-diagram.component.spec.ts | 12 ------ .../interactive-data-view.component.spec.ts | 10 ----- .../src/lib/core/portal-core.module.ts | 41 ++----------------- .../utils/create-translate-loader.utils.ts | 31 ++++++++++++++ 10 files changed, 46 insertions(+), 99 deletions(-) create mode 100644 libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts diff --git a/libs/portal-integration-angular/src/index.ts b/libs/portal-integration-angular/src/index.ts index 6804d294..25132093 100644 --- a/libs/portal-integration-angular/src/index.ts +++ b/libs/portal-integration-angular/src/index.ts @@ -108,3 +108,4 @@ export * from './lib/core/utils/colorutils' export * from './lib/core/utils/translate.combined.loader' export * from './lib/core/utils/image-logo-url.utils' export * from './lib/core/utils/async-translate-loader.utils' +export * from './lib/core/utils/create-translate-loader.utils' diff --git a/libs/portal-integration-angular/src/lib/api/injection-tokens.ts b/libs/portal-integration-angular/src/lib/api/injection-tokens.ts index 6dc490fe..7900b240 100644 --- a/libs/portal-integration-angular/src/lib/api/injection-tokens.ts +++ b/libs/portal-integration-angular/src/lib/api/injection-tokens.ts @@ -18,12 +18,6 @@ export const APP_CONFIG = new InjectionToken('APP_CONFIG') export const AUTH_SERVICE = new InjectionToken('AUTH_SERVICE') -// export const MFE_NAME = new InjectionToken('OCX_MFE_NAME') - -export const MFE_INFO_FN = new InjectionToken('OCX_MFE_INFO_FN') - -export const MFE_INFO = new InjectionToken('OCX_MFE_INFO') - export type mfeInfoProducer = () => MfeInfo export const SANITY_CHECK = new InjectionToken('OCXSANITY_CHECK') diff --git a/libs/portal-integration-angular/src/lib/core/components/data-list-grid/data-list-grid.component.html b/libs/portal-integration-angular/src/lib/core/components/data-list-grid/data-list-grid.component.html index d28ae61e..368fd848 100644 --- a/libs/portal-integration-angular/src/lib/core/components/data-list-grid/data-list-grid.component.html +++ b/libs/portal-integration-angular/src/lib/core/components/data-list-grid/data-list-grid.component.html @@ -30,8 +30,8 @@
{{resolveFieldData(item, titleLineId)|| ''}}
diff --git a/libs/portal-integration-angular/src/lib/core/components/data-list-grid/data-list-grid.component.ts b/libs/portal-integration-angular/src/lib/core/components/data-list-grid/data-list-grid.component.ts index 9f03b79b..fccff57b 100644 --- a/libs/portal-integration-angular/src/lib/core/components/data-list-grid/data-list-grid.component.ts +++ b/libs/portal-integration-angular/src/lib/core/components/data-list-grid/data-list-grid.component.ts @@ -13,7 +13,6 @@ import { } from '@angular/core' import { DataSortDirection } from '../../../model/data-sort-direction' import { MenuItem } from 'primeng/api' -import { MFE_INFO } from '../../../api/injection-tokens' import { MfeInfo } from '../../../model/mfe-info.model' import { DataAction } from '../../../model/data-action' import { TranslateService } from '@ngx-translate/core' @@ -24,6 +23,7 @@ import { BehaviorSubject, combineLatest, map, mergeMap, Observable } from 'rxjs' import { DataSortBase } from '../data-sort-base/data-sort-base' import { Router } from '@angular/router' import { UserService } from '../../../services/user.service' +import { AppStateService } from '../../../services/app-state.service' export type ListGridData = { id: string | number @@ -164,17 +164,21 @@ export class DataListGridComponent extends DataSortBase implements OnInit, DoChe observedOutputs = 0 displayedItems$: Observable | undefined + fallbackImagePath$!: Observable constructor( @Inject(LOCALE_ID) locale: string, - @Inject(MFE_INFO) private mfeInfo: MfeInfo, translateService: TranslateService, private userService: UserService, private router: Router, - private injector: Injector + private injector: Injector, + private appStateService: AppStateService ) { super(locale, translateService) this.name = this.name || this.router.url.replace(/[^A-Za-z0-9]/, '_') + this.fallbackImagePath$ = this.appStateService.currentMfe$.pipe( + map((currentMfe) => this.getFallbackImagePath(currentMfe)) + ) } ngDoCheck(): void { @@ -213,10 +217,8 @@ export class DataListGridComponent extends DataSortBase implements OnInit, DoChe this.editItem.emit(element) } - imgError(event: Event) { - if (!!this.fallbackImage && (event?.target)?.src != this.fallbackImage) { - ;(event.target).src = this.getFallbackImagePath(this.mfeInfo) - } + imgError(item: ListGridData) { + item.imagePath = '' } getFallbackImagePath(mfeInfo: MfeInfo) { diff --git a/libs/portal-integration-angular/src/lib/core/components/data-view/data-view.component.spec.ts b/libs/portal-integration-angular/src/lib/core/components/data-view/data-view.component.spec.ts index f9abed05..fc726c73 100644 --- a/libs/portal-integration-angular/src/lib/core/components/data-view/data-view.component.spec.ts +++ b/libs/portal-integration-angular/src/lib/core/components/data-view/data-view.component.spec.ts @@ -4,7 +4,6 @@ import { DataViewComponent } from './data-view.component' import { MockAuthModule } from '../../../mock-auth/mock-auth.module' import { DataListGridComponent } from '../data-list-grid/data-list-grid.component' import { DataViewModule } from 'primeng/dataview' -import { MFE_INFO } from '../../../api/injection-tokens' import { TranslateTestingModule } from 'ngx-translate-testing' import { HttpClientTestingModule } from '@angular/common/http/testing' import { DataTableComponent } from '../data-table/data-table.component' @@ -17,17 +16,6 @@ describe('DataViewComponent', () => { await TestBed.configureTestingModule({ declarations: [DataViewComponent, DataListGridComponent, DataTableComponent], imports: [DataViewModule, MockAuthModule, TranslateTestingModule.withTranslations({}), HttpClientTestingModule], - providers: [ - { - provide: MFE_INFO, - useValue: { - baseHref: '/base/path', - mountPath: '/base/path', - remoteBaseUrl: 'http://localhost:4200', - shellName: 'shell', - }, - }, - ], }).compileComponents() fixture = TestBed.createComponent(DataViewComponent) diff --git a/libs/portal-integration-angular/src/lib/core/components/diagram/diagram.component.spec.ts b/libs/portal-integration-angular/src/lib/core/components/diagram/diagram.component.spec.ts index 8cc077dd..774564d6 100644 --- a/libs/portal-integration-angular/src/lib/core/components/diagram/diagram.component.spec.ts +++ b/libs/portal-integration-angular/src/lib/core/components/diagram/diagram.component.spec.ts @@ -6,7 +6,6 @@ import { HttpClientTestingModule } from '@angular/common/http/testing' import { ChartModule } from 'primeng/chart' import { MessageModule } from 'primeng/message' import { MockAuthModule } from '../../../mock-auth/mock-auth.module' -import { MFE_INFO } from '../../../api/injection-tokens' import { DiagramHarness, TestbedHarnessEnvironment } from '../../../../../testing' import { TranslateService } from '@ngx-translate/core' @@ -43,17 +42,6 @@ describe('DiagramComponent', () => { }), HttpClientTestingModule, ], - providers: [ - { - provide: MFE_INFO, - useValue: { - baseHref: '/base/path', - mountPath: '/base/path', - remoteBaseUrl: 'http://localhost:4200', - shellName: 'shell', - }, - }, - ], }).compileComponents() fixture = TestBed.createComponent(DiagramComponent) diff --git a/libs/portal-integration-angular/src/lib/core/components/group-by-count-diagram/group-by-count-diagram.component.spec.ts b/libs/portal-integration-angular/src/lib/core/components/group-by-count-diagram/group-by-count-diagram.component.spec.ts index 4b605877..31b537d0 100644 --- a/libs/portal-integration-angular/src/lib/core/components/group-by-count-diagram/group-by-count-diagram.component.spec.ts +++ b/libs/portal-integration-angular/src/lib/core/components/group-by-count-diagram/group-by-count-diagram.component.spec.ts @@ -2,7 +2,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing' import { GroupByCountDiagramComponent } from './group-by-count-diagram.component' import { HttpClientTestingModule } from '@angular/common/http/testing' import { TranslateTestingModule } from 'ngx-translate-testing' -import { MFE_INFO } from '../../../api/injection-tokens' import { MockAuthModule } from '../../../mock-auth/mock-auth.module' import { ColumnType } from '../../../model/column-type.model' import { MessageModule } from 'primeng/message' @@ -158,17 +157,6 @@ describe('GroupByCountDiagramComponent', () => { }), HttpClientTestingModule, ], - providers: [ - { - provide: MFE_INFO, - useValue: { - baseHref: '/base/path', - mountPath: '/base/path', - remoteBaseUrl: 'http://localhost:4200', - shellName: 'shell', - }, - }, - ], }).compileComponents() fixture = TestBed.createComponent(GroupByCountDiagramComponent) diff --git a/libs/portal-integration-angular/src/lib/core/components/interactive-data-view/interactive-data-view.component.spec.ts b/libs/portal-integration-angular/src/lib/core/components/interactive-data-view/interactive-data-view.component.spec.ts index c4d6047c..917511e6 100644 --- a/libs/portal-integration-angular/src/lib/core/components/interactive-data-view/interactive-data-view.component.spec.ts +++ b/libs/portal-integration-angular/src/lib/core/components/interactive-data-view/interactive-data-view.component.spec.ts @@ -14,7 +14,6 @@ import { HarnessLoader, parallel, TestElement } from '@angular/cdk/testing' import { PortalCoreModule } from '../../portal-core.module' import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed' import { ColumnType } from '../../../model/column-type.model' -import { MFE_INFO } from '../../../api/injection-tokens' import { DataViewHarness, ColumnGroupSelectionHarness, @@ -234,15 +233,6 @@ describe('InteractiveDataViewComponent', () => { HttpClientModule, ], providers: [ - { - provide: MFE_INFO, - useValue: { - baseHref: '/base/path', - mountPath: '/base/path', - remoteBaseUrl: 'http://localhost:4200', - shellName: 'shell', - }, - }, { provide: UserService, useClass: MockUserService }, ], }).compileComponents() diff --git a/libs/portal-integration-angular/src/lib/core/portal-core.module.ts b/libs/portal-integration-angular/src/lib/core/portal-core.module.ts index db49cc3a..46f109d8 100644 --- a/libs/portal-integration-angular/src/lib/core/portal-core.module.ts +++ b/libs/portal-integration-angular/src/lib/core/portal-core.module.ts @@ -19,9 +19,7 @@ import { TranslateModule, TranslateService, } from '@ngx-translate/core' -import { TranslateHttpLoader } from '@ngx-translate/http-loader' -import { APPLICATION_NAME, AUTH_SERVICE, MFE_INFO, MFE_INFO_FN, SANITY_CHECK } from '../api/injection-tokens' -import { MfeInfo } from '../model/mfe-info.model' +import { APPLICATION_NAME, AUTH_SERVICE, SANITY_CHECK } from '../api/injection-tokens' import { AutofocusDirective } from './directives/autofocus.directive' import { IfBreakpointDirective } from './directives/if-breakpoint.directive' import { IfPermissionDirective } from './directives/if-permission.directive' @@ -60,7 +58,6 @@ import { DataListGridComponent } from './components/data-list-grid/data-list-gri import { PrimeNgModule } from './primeng.module' import { MockAuthService } from '../mock-auth/mock-auth.service' import { ConfirmDialogModule } from 'primeng/confirmdialog' -import { TranslateCombinedLoader } from './utils/translate.combined.loader' import { DataTableComponent } from './components/data-table/data-table.component' import de from '@angular/common/locales/de' import { DataViewComponent } from './components/data-view/data-view.component' @@ -80,30 +77,7 @@ import { DiagramComponent } from './components/diagram/diagram.component' import { GroupByCountDiagramComponent } from './components/group-by-count-diagram/group-by-count-diagram.component' import { UserService } from '../services/user.service' import { UserProfileAPIService } from '../services/userprofile-api.service' -import { AsyncTranslateLoader } from './utils/async-translate-loader.utils' -import { combineLatest, filter, map } from 'rxjs' - -export function createTranslateLoader(http: HttpClient, appStateService: AppStateService): TranslateLoader { - return new AsyncTranslateLoader( - combineLatest([appStateService.currentMfe$.asObservable(), appStateService.globalLoading$.asObservable()]).pipe( - filter(([, isLoading]) => !isLoading), - map(([currentMfe]) => { - if (currentMfe.remoteBaseUrl) { - return new TranslateCombinedLoader( - new TranslateHttpLoader(http, `${currentMfe.remoteBaseUrl}/assets/i18n/`, '.json'), - new TranslateHttpLoader(http, `./assets/i18n/`, '.json'), - new TranslateHttpLoader(http, `./onecx-portal-lib/assets/i18n/`, '.json') - ) - } else { - return new TranslateCombinedLoader( - new TranslateHttpLoader(http, `./assets/i18n/`, '.json'), - new TranslateHttpLoader(http, `./onecx-portal-lib/assets/i18n/`, '.json') - ) - } - }) - ) - ) -} +import { CreateTranslateLoader } from './utils/create-translate-loader.utils' export class MyMissingTranslationHandler implements MissingTranslationHandler { handle(params: MissingTranslationHandlerParams) { @@ -121,7 +95,7 @@ export class MyMissingTranslationHandler implements MissingTranslationHandler { PrimeNgModule, TranslateModule.forRoot({ isolate: true, - loader: { provide: TranslateLoader, useFactory: createTranslateLoader, deps: [HttpClient, AppStateService] }, + loader: { provide: TranslateLoader, useClass: CreateTranslateLoader, deps: [HttpClient, AppStateService] }, missingTranslationHandler: { provide: MissingTranslationHandler, useClass: MyMissingTranslationHandler }, }), ConfirmDialogModule, @@ -242,14 +216,6 @@ export class PortalCoreModule { ngModule: PortalCoreModule, providers: [ { provide: SANITY_CHECK, useValue: 'mfe' }, - { - provide: MFE_INFO, - useFactory: (mfInfoFn: () => MfeInfo): MfeInfo => { - console.log(`MFE_INFO Factory called now `) - return mfInfoFn() - }, - deps: [MFE_INFO_FN], - }, ], } } @@ -259,7 +225,6 @@ export class PortalCoreModule { ngModule: PortalCoreModule, providers: [ { provide: SANITY_CHECK, useValue: 'root' }, - { provide: MFE_INFO_FN, useValue: () => undefined }, { provide: APPLICATION_NAME, useValue: appName }, { provide: MessageService, diff --git a/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts b/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts new file mode 100644 index 00000000..e9f70b36 --- /dev/null +++ b/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts @@ -0,0 +1,31 @@ +import { HttpClient } from "@angular/common/http" +import { TranslateLoader } from "@ngx-translate/core" +import { TranslateHttpLoader } from "@ngx-translate/http-loader" +import { combineLatest, filter, map } from "rxjs" +import { AppStateService } from "../../services/app-state.service" +import { AsyncTranslateLoader } from "./async-translate-loader.utils" +import { TranslateCombinedLoader } from "./translate.combined.loader" + +export class CreateTranslateLoader { + createTranslateLoader(http: HttpClient, appStateService: AppStateService): TranslateLoader { + return new AsyncTranslateLoader( + combineLatest([appStateService.currentMfe$.asObservable(), appStateService.globalLoading$.asObservable()]).pipe( + filter(([, isLoading]) => !isLoading), + map(([currentMfe]) => { + if (currentMfe.remoteBaseUrl) { + return new TranslateCombinedLoader( + new TranslateHttpLoader(http, `${currentMfe.remoteBaseUrl}/assets/i18n/`, '.json'), + new TranslateHttpLoader(http, `./assets/i18n/`, '.json'), + new TranslateHttpLoader(http, `./onecx-portal-lib/assets/i18n/`, '.json') + ) + } else { + return new TranslateCombinedLoader( + new TranslateHttpLoader(http, `./assets/i18n/`, '.json'), + new TranslateHttpLoader(http, `./onecx-portal-lib/assets/i18n/`, '.json') + ) + } + }) + ) + ) + } +} \ No newline at end of file From 52fae53918fe30e07c4051bdce9146cca70d7063 Mon Sep 17 00:00:00 2001 From: "kim.tran" Date: Tue, 12 Dec 2023 11:41:57 +0100 Subject: [PATCH 02/13] feat: public static createTranslateLoader --- .../src/lib/core/utils/create-translate-loader.utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts b/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts index e9f70b36..61912969 100644 --- a/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts +++ b/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts @@ -7,7 +7,7 @@ import { AsyncTranslateLoader } from "./async-translate-loader.utils" import { TranslateCombinedLoader } from "./translate.combined.loader" export class CreateTranslateLoader { - createTranslateLoader(http: HttpClient, appStateService: AppStateService): TranslateLoader { + public static createTranslateLoader(http: HttpClient, appStateService: AppStateService): TranslateLoader { return new AsyncTranslateLoader( combineLatest([appStateService.currentMfe$.asObservable(), appStateService.globalLoading$.asObservable()]).pipe( filter(([, isLoading]) => !isLoading), From 7d8f78238f58483d2f5596cf6db119f4ecef9273 Mon Sep 17 00:00:00 2001 From: "kim.tran" Date: Thu, 14 Dec 2023 12:58:48 +0100 Subject: [PATCH 03/13] feat: topic changes, isInitialized not necessary after publish --- .../src/lib/topic/syncable-topic.spec.ts | 3 +- libs/accelerator/src/lib/topic/topic.spec.ts | 12 ++++ libs/accelerator/src/lib/topic/topic.ts | 12 +++- .../src/lib/keycloak-auth.service.ts | 5 +- .../announcement-banner.component.spec.ts | 3 +- .../announcement-banner.component.stories.ts | 3 +- .../page-header/page-header.component.spec.ts | 3 +- .../page-header.component.stories.ts | 3 +- .../portal-footer.component.spec.ts | 3 +- .../portal-footer.component.stories.ts | 3 +- .../portal-viewport.component.spec.ts | 3 +- .../search-criteria.component.spec.ts | 3 +- .../search-criteria.component.stories.ts | 3 +- .../search-header.component.spec.ts | 3 +- .../initializer/standalone.initializer.ts | 8 +-- .../src/lib/core/portal-core.module.ts | 11 +++- .../utils/create-translate-loader.utils.ts | 58 +++++++++---------- .../src/lib/services/configuration.service.ts | 10 ++-- .../src/lib/services/theme.service.ts | 8 +-- package-lock.json | 22 ++++++- package.json | 1 + 21 files changed, 107 insertions(+), 73 deletions(-) diff --git a/libs/accelerator/src/lib/topic/syncable-topic.spec.ts b/libs/accelerator/src/lib/topic/syncable-topic.spec.ts index 5da99fad..c982f4ff 100644 --- a/libs/accelerator/src/lib/topic/syncable-topic.spec.ts +++ b/libs/accelerator/src/lib/topic/syncable-topic.spec.ts @@ -45,8 +45,7 @@ describe('Syncable Topic', () => { it('should get correct value', async () => { expect(testSyncableTopic1.getValue()).toEqual(undefined) - testSyncableTopic1.publish('value1') - await testSyncableTopic1.isInitialized + await testSyncableTopic1.publish('value1') expect(testSyncableTopic1.getValue()).toEqual('value1') expect(testSyncableTopic2.getValue()).toEqual('value1') diff --git a/libs/accelerator/src/lib/topic/topic.spec.ts b/libs/accelerator/src/lib/topic/topic.spec.ts index 7f55bec4..825f0eeb 100644 --- a/libs/accelerator/src/lib/topic/topic.spec.ts +++ b/libs/accelerator/src/lib/topic/topic.spec.ts @@ -142,4 +142,16 @@ describe('Topic', () => { expect(v).toEqual(6) expect(values1).toEqual(['value1']) }) + + it('should check isInitialized', (done) => { + let initialized = false + testTopic1.isInitialized.then(() => (initialized = true)) + + expect(initialized).toBe(false) + + testTopic1.publish('test') + setTimeout(() => { + expect(initialized).toBe(true) + }, done()) + }) }) diff --git a/libs/accelerator/src/lib/topic/topic.ts b/libs/accelerator/src/lib/topic/topic.ts index 14fc78e7..75dfb3d2 100644 --- a/libs/accelerator/src/lib/topic/topic.ts +++ b/libs/accelerator/src/lib/topic/topic.ts @@ -19,6 +19,7 @@ export class Topic implements Subscribable { protected isInit = false private resolveInitPromise!: (value: void | PromiseLike) => void private eventListener = (m: MessageEvent) => this.onMessage(m) + private publishPromiseResolver: Record void> = {} constructor(private name: string, private version: number) { this.isInitializedPromise = new Promise((resolve) => { @@ -132,9 +133,13 @@ export class Topic implements Subscribable { return (this.asObservable()).pipe(...operations) } - publish(value: T) { + publish(value: T): Promise { const message = new TopicDataMessage(TopicMessageType.TopicNext, this.name, this.version, value) + const promise = new Promise((resolve) => { + this.publishPromiseResolver[message.timestamp] = resolve + }) window.postMessage(message, '*') + return promise } destroy() { @@ -152,6 +157,11 @@ export class Topic implements Subscribable { this.isInit = true this.data.next(>m.data) this.resolveInitPromise() + const publishPromiseResolver = this.publishPromiseResolver[m.data.timestamp] + if (publishPromiseResolver) { + publishPromiseResolver() + delete this.publishPromiseResolver[m.data.timestamp] + } } break case TopicMessageType.TopicGet: diff --git a/libs/keycloak-auth/src/lib/keycloak-auth.service.ts b/libs/keycloak-auth/src/lib/keycloak-auth.service.ts index cfc6ef46..148defeb 100644 --- a/libs/keycloak-auth/src/lib/keycloak-auth.service.ts +++ b/libs/keycloak-auth/src/lib/keycloak-auth.service.ts @@ -72,9 +72,8 @@ export class KeycloakAuthService implements IAuthService { return this.keycloakService.login().then(() => 'login') } }) - .then(() => { - this.appStateService.isAuthenticated$.publish() - return this.appStateService.isAuthenticated$.isInitialized + .then(async () => { + await this.appStateService.isAuthenticated$.publish() }) .then(() => true) .catch((err) => { diff --git a/libs/portal-integration-angular/src/lib/core/components/announcement-banner/announcement-banner.component.spec.ts b/libs/portal-integration-angular/src/lib/core/components/announcement-banner/announcement-banner.component.spec.ts index 5c4e1afa..8b21ec00 100644 --- a/libs/portal-integration-angular/src/lib/core/components/announcement-banner/announcement-banner.component.spec.ts +++ b/libs/portal-integration-angular/src/lib/core/components/announcement-banner/announcement-banner.component.spec.ts @@ -46,13 +46,12 @@ describe('AnnouncementBannerComponent', () => { }).compileComponents() const appStateService = getTestBed().inject(AppStateService) - appStateService.currentPortal$.publish({ + await appStateService.currentPortal$.publish({ id: 'i-am-test-portal', portalName: 'test', baseUrl: '', microfrontendRegistrations: [], }) - await appStateService.currentPortal$.isInitialized announcementsApiService = getTestBed().inject(AnnouncementsApiService) jest.spyOn(announcementsApiService, 'getAnnouncementById').mockReturnValue(getAnnouncementByIdMock) diff --git a/libs/portal-integration-angular/src/lib/core/components/announcement-banner/announcement-banner.component.stories.ts b/libs/portal-integration-angular/src/lib/core/components/announcement-banner/announcement-banner.component.stories.ts index 67aaa1c8..49bc9773 100644 --- a/libs/portal-integration-angular/src/lib/core/components/announcement-banner/announcement-banner.component.stories.ts +++ b/libs/portal-integration-angular/src/lib/core/components/announcement-banner/announcement-banner.component.stories.ts @@ -10,13 +10,12 @@ import { HttpClientModule } from '@angular/common/http' import { AppStateService } from '../../../services/app-state.service' async function initFactory(appStateService: AppStateService) { - appStateService.currentPortal$.publish({ + await appStateService.currentPortal$.publish({ baseUrl: '/demo', portalName: 'Demo', id: 'Demo', microfrontendRegistrations: [], }) - await appStateService.currentPortal$.isInitialized return () => { appStateService diff --git a/libs/portal-integration-angular/src/lib/core/components/page-header/page-header.component.spec.ts b/libs/portal-integration-angular/src/lib/core/components/page-header/page-header.component.spec.ts index 6b12b2e2..2ad77414 100644 --- a/libs/portal-integration-angular/src/lib/core/components/page-header/page-header.component.spec.ts +++ b/libs/portal-integration-angular/src/lib/core/components/page-header/page-header.component.spec.ts @@ -85,13 +85,12 @@ describe('PageHeaderComponent', () => { }).compileComponents() const appStateService = getTestBed().inject(AppStateService) - appStateService.currentPortal$.publish({ + await appStateService.currentPortal$.publish({ id: 'i-am-test-portal', portalName: 'test', baseUrl: '', microfrontendRegistrations: [], }) - await appStateService.currentPortal$.isInitialized }) beforeEach(() => { diff --git a/libs/portal-integration-angular/src/lib/core/components/page-header/page-header.component.stories.ts b/libs/portal-integration-angular/src/lib/core/components/page-header/page-header.component.stories.ts index d5a5969f..d082f453 100644 --- a/libs/portal-integration-angular/src/lib/core/components/page-header/page-header.component.stories.ts +++ b/libs/portal-integration-angular/src/lib/core/components/page-header/page-header.component.stories.ts @@ -25,13 +25,12 @@ function initFactory(breadcrumbService: BreadcrumbService, appStateService: AppS { label: 'Level 1', routerLink: 'something' }, { label: 'Level 2', url: '/' }, ]) - appStateService.currentPortal$.publish({ + await appStateService.currentPortal$.publish({ baseUrl: '/demo', portalName: 'Demo', id: 'Demo', microfrontendRegistrations: [], }) - await appStateService.currentPortal$.isInitialized } } diff --git a/libs/portal-integration-angular/src/lib/core/components/portal-footer/portal-footer.component.spec.ts b/libs/portal-integration-angular/src/lib/core/components/portal-footer/portal-footer.component.spec.ts index af90cb34..6381e041 100644 --- a/libs/portal-integration-angular/src/lib/core/components/portal-footer/portal-footer.component.spec.ts +++ b/libs/portal-integration-angular/src/lib/core/components/portal-footer/portal-footer.component.spec.ts @@ -38,13 +38,12 @@ describe('PortalFooterComponent', () => { }).compileComponents() const appStateService = getTestBed().inject(AppStateService) - appStateService.currentPortal$.publish({ + await appStateService.currentPortal$.publish({ id: 'i-am-test-portal', portalName: 'test', baseUrl: '', microfrontendRegistrations: [], }) - await appStateService.currentPortal$.isInitialized })) beforeEach(() => { diff --git a/libs/portal-integration-angular/src/lib/core/components/portal-footer/portal-footer.component.stories.ts b/libs/portal-integration-angular/src/lib/core/components/portal-footer/portal-footer.component.stories.ts index 29a5bb09..4485a2ce 100644 --- a/libs/portal-integration-angular/src/lib/core/components/portal-footer/portal-footer.component.stories.ts +++ b/libs/portal-integration-angular/src/lib/core/components/portal-footer/portal-footer.component.stories.ts @@ -17,13 +17,12 @@ import { mockedGetMenu } from '../../../../../mocks/menuMapper' import { AppStateService } from '../../../services/app-state.service' async function initFactory(appStateService: AppStateService) { - appStateService.currentPortal$.publish({ + await appStateService.currentPortal$.publish({ baseUrl: '/demo', portalName: 'Demo', id: 'Demo', microfrontendRegistrations: [], }) - await appStateService.currentPortal$.isInitialized return () => { appStateService diff --git a/libs/portal-integration-angular/src/lib/core/components/portal-viewport/portal-viewport.component.spec.ts b/libs/portal-integration-angular/src/lib/core/components/portal-viewport/portal-viewport.component.spec.ts index b7e237cd..281f2eec 100644 --- a/libs/portal-integration-angular/src/lib/core/components/portal-viewport/portal-viewport.component.spec.ts +++ b/libs/portal-integration-angular/src/lib/core/components/portal-viewport/portal-viewport.component.spec.ts @@ -95,13 +95,12 @@ describe('PortalViewportComponent', () => { beforeEach(async () => { const appStateService = getTestBed().inject(AppStateService) - appStateService.currentPortal$.publish({ + await appStateService.currentPortal$.publish({ id: 'i-am-test-portal', portalName: 'test', baseUrl: '', microfrontendRegistrations: [], }) - await appStateService.currentPortal$.isInitialized fixture = TestBed.createComponent(PortalViewportComponent) component = fixture.componentInstance diff --git a/libs/portal-integration-angular/src/lib/core/components/search-criteria/search-criteria.component.spec.ts b/libs/portal-integration-angular/src/lib/core/components/search-criteria/search-criteria.component.spec.ts index 2bd49be5..eafa2cd8 100644 --- a/libs/portal-integration-angular/src/lib/core/components/search-criteria/search-criteria.component.spec.ts +++ b/libs/portal-integration-angular/src/lib/core/components/search-criteria/search-criteria.component.spec.ts @@ -53,13 +53,12 @@ describe('SearchCriteriaComponent', () => { component = fixture.componentInstance const appStateService = getTestBed().inject(AppStateService) - appStateService.currentPortal$.publish({ + await appStateService.currentPortal$.publish({ id: 'i-am-test-portal', portalName: 'test', baseUrl: '', microfrontendRegistrations: [], }) - await appStateService.currentPortal$.isInitialized fixture.detectChanges() }) diff --git a/libs/portal-integration-angular/src/lib/core/components/search-criteria/search-criteria.component.stories.ts b/libs/portal-integration-angular/src/lib/core/components/search-criteria/search-criteria.component.stories.ts index 36644bde..da936b46 100644 --- a/libs/portal-integration-angular/src/lib/core/components/search-criteria/search-criteria.component.stories.ts +++ b/libs/portal-integration-angular/src/lib/core/components/search-criteria/search-criteria.component.stories.ts @@ -22,13 +22,12 @@ import { InputTextModule } from 'primeng/inputtext' import { AppStateService } from '../../../services/app-state.service' async function initFactory(appStateService: AppStateService) { - appStateService.currentPortal$.publish({ + await appStateService.currentPortal$.publish({ baseUrl: '/demo', portalName: 'Demo', id: 'Demo', microfrontendRegistrations: [], }) - await appStateService.currentPortal$.isInitialized return () => { appStateService diff --git a/libs/portal-integration-angular/src/lib/core/components/search-header/search-header.component.spec.ts b/libs/portal-integration-angular/src/lib/core/components/search-header/search-header.component.spec.ts index 6b4e1f44..5039c557 100644 --- a/libs/portal-integration-angular/src/lib/core/components/search-header/search-header.component.spec.ts +++ b/libs/portal-integration-angular/src/lib/core/components/search-header/search-header.component.spec.ts @@ -52,13 +52,12 @@ describe('SearchHeaderComponent', () => { }).compileComponents() const appStateService = getTestBed().inject(AppStateService) - appStateService.currentPortal$.publish({ + await appStateService.currentPortal$.publish({ id: 'i-am-test-portal', portalName: 'test', baseUrl: '', microfrontendRegistrations: [], }) - await appStateService.currentPortal$.isInitialized fixture = TestBed.createComponent(SearchHeaderComponent) component = fixture.componentInstance diff --git a/libs/portal-integration-angular/src/lib/core/initializer/standalone.initializer.ts b/libs/portal-integration-angular/src/lib/core/initializer/standalone.initializer.ts index 63f384b1..f0d84920 100644 --- a/libs/portal-integration-angular/src/lib/core/initializer/standalone.initializer.ts +++ b/libs/portal-integration-angular/src/lib/core/initializer/standalone.initializer.ts @@ -53,8 +53,7 @@ export function standaloneInitializer( console.log(`📑 auth OK? ${authOk}`) try { const profile = await firstValueFrom(userProfileAPIService.getCurrentUser()) - userService.profile$.publish(profile) - await userService.profile$.isInitialized + await userService.profile$.publish(profile) } catch (e) { errCause = USER_INIT_ERR throw e @@ -68,8 +67,7 @@ export function standaloneInitializer( throw e } console.log(`📃 portal OK? ${portal}`) - appStateService.currentPortal$.publish(portal) - await appStateService.currentPortal$.isInitialized + await appStateService.currentPortal$.publish(portal) let theme = undefined if (!portal) { @@ -89,7 +87,7 @@ export function standaloneInitializer( console.log('Standalone Initializer') console.log(`🛑 Error during initialization: ${errCause} ${e} `) console.dir(e) - appStateService.globalError$.publish(errCause || 'INITIALIZATION_ERROR') + await appStateService.globalError$.publish(errCause || 'INITIALIZATION_ERROR') return undefined } finally { // eslint-disable-next-line no-restricted-syntax diff --git a/libs/portal-integration-angular/src/lib/core/portal-core.module.ts b/libs/portal-integration-angular/src/lib/core/portal-core.module.ts index 46f109d8..0946fe38 100644 --- a/libs/portal-integration-angular/src/lib/core/portal-core.module.ts +++ b/libs/portal-integration-angular/src/lib/core/portal-core.module.ts @@ -95,7 +95,7 @@ export class MyMissingTranslationHandler implements MissingTranslationHandler { PrimeNgModule, TranslateModule.forRoot({ isolate: true, - loader: { provide: TranslateLoader, useClass: CreateTranslateLoader, deps: [HttpClient, AppStateService] }, + loader: { provide: TranslateLoader, useFactory: CreateTranslateLoader.createTranslateLoader, deps: [HttpClient, AppStateService] }, missingTranslationHandler: { provide: MissingTranslationHandler, useClass: MyMissingTranslationHandler }, }), ConfirmDialogModule, @@ -216,6 +216,14 @@ export class PortalCoreModule { ngModule: PortalCoreModule, providers: [ { provide: SANITY_CHECK, useValue: 'mfe' }, + // { + // provide: MFE_INFO, + // useFactory: (mfInfoFn: () => MfeInfo): MfeInfo => { + // console.log(`MFE_INFO Factory called now `) + // return mfInfoFn() + // }, + // deps: [MFE_INFO_FN], + // }, ], } } @@ -225,6 +233,7 @@ export class PortalCoreModule { ngModule: PortalCoreModule, providers: [ { provide: SANITY_CHECK, useValue: 'root' }, + // { provide: MFE_INFO_FN, useValue: () => undefined }, { provide: APPLICATION_NAME, useValue: appName }, { provide: MessageService, diff --git a/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts b/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts index 61912969..79ad9a6c 100644 --- a/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts +++ b/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts @@ -1,31 +1,31 @@ -import { HttpClient } from "@angular/common/http" -import { TranslateLoader } from "@ngx-translate/core" -import { TranslateHttpLoader } from "@ngx-translate/http-loader" -import { combineLatest, filter, map } from "rxjs" -import { AppStateService } from "../../services/app-state.service" -import { AsyncTranslateLoader } from "./async-translate-loader.utils" -import { TranslateCombinedLoader } from "./translate.combined.loader" +import { HttpClient } from '@angular/common/http' +import { TranslateLoader } from '@ngx-translate/core' +import { TranslateHttpLoader } from '@ngx-translate/http-loader' +import { combineLatest, filter, map } from 'rxjs' +import { AppStateService } from '../../services/app-state.service' +import { AsyncTranslateLoader } from './async-translate-loader.utils' +import { TranslateCombinedLoader } from './translate.combined.loader' export class CreateTranslateLoader { - public static createTranslateLoader(http: HttpClient, appStateService: AppStateService): TranslateLoader { - return new AsyncTranslateLoader( - combineLatest([appStateService.currentMfe$.asObservable(), appStateService.globalLoading$.asObservable()]).pipe( - filter(([, isLoading]) => !isLoading), - map(([currentMfe]) => { - if (currentMfe.remoteBaseUrl) { - return new TranslateCombinedLoader( - new TranslateHttpLoader(http, `${currentMfe.remoteBaseUrl}/assets/i18n/`, '.json'), - new TranslateHttpLoader(http, `./assets/i18n/`, '.json'), - new TranslateHttpLoader(http, `./onecx-portal-lib/assets/i18n/`, '.json') - ) - } else { - return new TranslateCombinedLoader( - new TranslateHttpLoader(http, `./assets/i18n/`, '.json'), - new TranslateHttpLoader(http, `./onecx-portal-lib/assets/i18n/`, '.json') - ) - } - }) - ) - ) - } -} \ No newline at end of file + public static createTranslateLoader(http: HttpClient, appStateService: AppStateService): TranslateLoader { + return new AsyncTranslateLoader( + combineLatest([appStateService.currentMfe$.asObservable(), appStateService.globalLoading$.asObservable()]).pipe( + filter(([, isLoading]) => !isLoading), + map(([currentMfe]) => { + if (currentMfe.remoteBaseUrl) { + return new TranslateCombinedLoader( + new TranslateHttpLoader(http, `${currentMfe.remoteBaseUrl}/assets/i18n/`, '.json'), + new TranslateHttpLoader(http, `./assets/i18n/`, '.json'), + new TranslateHttpLoader(http, `./onecx-portal-lib/assets/i18n/`, '.json') + ) + } else { + return new TranslateCombinedLoader( + new TranslateHttpLoader(http, `./assets/i18n/`, '.json'), + new TranslateHttpLoader(http, `./onecx-portal-lib/assets/i18n/`, '.json') + ) + } + }) + ) + ) + } +} diff --git a/libs/portal-integration-angular/src/lib/services/configuration.service.ts b/libs/portal-integration-angular/src/lib/services/configuration.service.ts index 52940ece..e3527c89 100644 --- a/libs/portal-integration-angular/src/lib/services/configuration.service.ts +++ b/libs/portal-integration-angular/src/lib/services/configuration.service.ts @@ -41,15 +41,13 @@ export class ConfigurationService implements OnDestroy { } loadConfigPromise - .then((config) => { + .then(async (config) => { if (config) { - this.config$.publish({ ...this.defaultConfig }) - this.config$.isInitialized.then(() => { + await this.config$.publish({ ...this.defaultConfig }).then(() => { resolve(true) }) } }) - .catch((e) => { console.log(`Failed to load env configuration`) reject(e) @@ -65,8 +63,8 @@ export class ConfigurationService implements OnDestroy { return this.config$.getValue()?.[key] } - public setProperty(key: string, val: string) { - this.config$.publish({ key, val }) + public async setProperty(key: string, val: string) { + await this.config$.publish({ key, val }) } public getConfig(): Config | undefined { diff --git a/libs/portal-integration-angular/src/lib/services/theme.service.ts b/libs/portal-integration-angular/src/lib/services/theme.service.ts index c5f8780d..05c4e236 100644 --- a/libs/portal-integration-angular/src/lib/services/theme.service.ts +++ b/libs/portal-integration-angular/src/lib/services/theme.service.ts @@ -25,15 +25,15 @@ export class ThemeService implements OnDestroy { public loadAndApplyTheme(themeName: string) { return this.http.get(`${this.baseUrlV1}/internal/themes/${encodeURI(themeName)}`).pipe( - tap((theme) => { - this.apply(theme) + tap(async (theme) => { + await this.apply(theme) }) ) } - public apply(theme: Theme) { + public async apply(theme: Theme): Promise { console.log(`🎨 Applying theme: ${theme.name}`) - this.currentTheme$.publish(theme) + await this.currentTheme$.publish(theme) if (theme.properties) { Object.values(theme.properties).forEach((group) => { for (const [key, value] of Object.entries(group)) { diff --git a/package-lock.json b/package-lock.json index 62fcf8c1..6b2d64ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@onecx/onecx-portal-ui-libs", - "version": "3.5.0", + "version": "3.5.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@onecx/onecx-portal-ui-libs", - "version": "3.5.0", + "version": "3.5.2", "license": "Apache-2.0", "dependencies": { "@angular-architects/module-federation": "15.0.0", @@ -31,6 +31,7 @@ "chart.js": "^4.4.0", "d3-scale-chromatic": "^3.0.0", "fast-deep-equal": "^3.1.3", + "jest-marbles": "^3.0.5", "keycloak-angular": "^13.0.0", "keycloak-js": "^18.0.0", "ngx-color": "^8.0.3", @@ -17672,6 +17673,17 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-marbles": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/jest-marbles/-/jest-marbles-3.0.5.tgz", + "integrity": "sha512-ZZjMyo//+y/8w8m5qfjkj2/r3LPx0TzdnDwdwYEiVGcNb65YYtIYcJ/wlovBXsjHyXDqI4a3w5xgE9LM7brJVg==", + "engines": { + "node": ">=6.11.5" + }, + "peerDependencies": { + "rxjs": "^7.0.0" + } + }, "node_modules/jest-matcher-utils": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", @@ -45495,6 +45507,12 @@ "pretty-format": "^29.7.0" } }, + "jest-marbles": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/jest-marbles/-/jest-marbles-3.0.5.tgz", + "integrity": "sha512-ZZjMyo//+y/8w8m5qfjkj2/r3LPx0TzdnDwdwYEiVGcNb65YYtIYcJ/wlovBXsjHyXDqI4a3w5xgE9LM7brJVg==", + "requires": {} + }, "jest-matcher-utils": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", diff --git a/package.json b/package.json index 2f83421b..454e82d8 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "chart.js": "^4.4.0", "d3-scale-chromatic": "^3.0.0", "fast-deep-equal": "^3.1.3", + "jest-marbles": "^3.0.5", "keycloak-angular": "^13.0.0", "keycloak-js": "^18.0.0", "ngx-color": "^8.0.3", From 01bf10ca63e8d43f53f26365eee90c492965020b Mon Sep 17 00:00:00 2001 From: "kim.tran" Date: Fri, 15 Dec 2023 15:35:48 +0100 Subject: [PATCH 04/13] feat: add tests --- .../src/lib/api/injection-tokens.ts | 3 -- .../src/lib/core/portal-core.module.ts | 13 +---- .../core/utils/async-translate-loader.spec.ts | 30 +++++++++++ .../utils/create-translate-loader.spec.ts | 54 +++++++++++++++++++ .../utils/create-translate-loader.utils.ts | 40 +++++++------- 5 files changed, 105 insertions(+), 35 deletions(-) create mode 100644 libs/portal-integration-angular/src/lib/core/utils/async-translate-loader.spec.ts create mode 100644 libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.spec.ts diff --git a/libs/portal-integration-angular/src/lib/api/injection-tokens.ts b/libs/portal-integration-angular/src/lib/api/injection-tokens.ts index 7900b240..cc285230 100644 --- a/libs/portal-integration-angular/src/lib/api/injection-tokens.ts +++ b/libs/portal-integration-angular/src/lib/api/injection-tokens.ts @@ -1,5 +1,4 @@ import { InjectionToken } from '@angular/core' -import { MfeInfo } from '../model/mfe-info.model' import { IAuthService } from './iauth.service' export interface LibConfig { @@ -18,8 +17,6 @@ export const APP_CONFIG = new InjectionToken('APP_CONFIG') export const AUTH_SERVICE = new InjectionToken('AUTH_SERVICE') -export type mfeInfoProducer = () => MfeInfo - export const SANITY_CHECK = new InjectionToken('OCXSANITY_CHECK') export const APPLICATION_NAME = new InjectionToken('APPLICATION_NAME') \ No newline at end of file diff --git a/libs/portal-integration-angular/src/lib/core/portal-core.module.ts b/libs/portal-integration-angular/src/lib/core/portal-core.module.ts index 0946fe38..3021daa6 100644 --- a/libs/portal-integration-angular/src/lib/core/portal-core.module.ts +++ b/libs/portal-integration-angular/src/lib/core/portal-core.module.ts @@ -77,7 +77,7 @@ import { DiagramComponent } from './components/diagram/diagram.component' import { GroupByCountDiagramComponent } from './components/group-by-count-diagram/group-by-count-diagram.component' import { UserService } from '../services/user.service' import { UserProfileAPIService } from '../services/userprofile-api.service' -import { CreateTranslateLoader } from './utils/create-translate-loader.utils' +import { createTranslateLoader } from './utils/create-translate-loader.utils' export class MyMissingTranslationHandler implements MissingTranslationHandler { handle(params: MissingTranslationHandlerParams) { @@ -95,7 +95,7 @@ export class MyMissingTranslationHandler implements MissingTranslationHandler { PrimeNgModule, TranslateModule.forRoot({ isolate: true, - loader: { provide: TranslateLoader, useFactory: CreateTranslateLoader.createTranslateLoader, deps: [HttpClient, AppStateService] }, + loader: { provide: TranslateLoader, useFactory: createTranslateLoader, deps: [HttpClient, AppStateService] }, missingTranslationHandler: { provide: MissingTranslationHandler, useClass: MyMissingTranslationHandler }, }), ConfirmDialogModule, @@ -216,14 +216,6 @@ export class PortalCoreModule { ngModule: PortalCoreModule, providers: [ { provide: SANITY_CHECK, useValue: 'mfe' }, - // { - // provide: MFE_INFO, - // useFactory: (mfInfoFn: () => MfeInfo): MfeInfo => { - // console.log(`MFE_INFO Factory called now `) - // return mfInfoFn() - // }, - // deps: [MFE_INFO_FN], - // }, ], } } @@ -233,7 +225,6 @@ export class PortalCoreModule { ngModule: PortalCoreModule, providers: [ { provide: SANITY_CHECK, useValue: 'root' }, - // { provide: MFE_INFO_FN, useValue: () => undefined }, { provide: APPLICATION_NAME, useValue: appName }, { provide: MessageService, diff --git a/libs/portal-integration-angular/src/lib/core/utils/async-translate-loader.spec.ts b/libs/portal-integration-angular/src/lib/core/utils/async-translate-loader.spec.ts new file mode 100644 index 00000000..9c668fa1 --- /dev/null +++ b/libs/portal-integration-angular/src/lib/core/utils/async-translate-loader.spec.ts @@ -0,0 +1,30 @@ +import { TranslateLoader } from '@ngx-translate/core' +import { Observable, of } from 'rxjs' +import { AsyncTranslateLoader } from './async-translate-loader.utils' + +describe('AsyncTranslateLoader', () => { + class FakeTranslateLoader implements TranslateLoader { + public lastLanguage: string | undefined + constructor(private result: any) {} + + getTranslation(lang: string): Observable { + this.lastLanguage = lang + return of(this.result) + } + } + + it('should get translations', (done) => { + const translations = 'my translations' + const translateLoader = new FakeTranslateLoader(translations) + const translateLoader$ = of(translateLoader) + + expect(translateLoader.lastLanguage).toBeUndefined() + + const asyncTranslateLoader = new AsyncTranslateLoader(translateLoader$) + asyncTranslateLoader.getTranslation('en').subscribe((t) => { + expect(t).toEqual(translations) + expect(translateLoader.lastLanguage).toEqual('en') + done() + }) + }) +}) diff --git a/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.spec.ts b/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.spec.ts new file mode 100644 index 00000000..6d2a9767 --- /dev/null +++ b/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.spec.ts @@ -0,0 +1,54 @@ +import { HttpClient } from '@angular/common/http' +import { AppStateService } from '../../services/app-state.service' +import { createTranslateLoader } from './create-translate-loader.utils' +import { MockService } from 'ng-mocks' +import { Observable, of } from 'rxjs' +import { MfeInfo } from '@onecx/integration-interface' + +describe('CreateTranslateLoader', () => { + const httpClientMock = MockService(HttpClient) + httpClientMock.get = jest.fn(() => of({})) as any + let currentMfe$: Observable> + let globalLoading$: Observable + + const appStateServiceMock = { + currentMfe$: { asObservable: () => currentMfe$ }, + globalLoading$: { asObservable: () => globalLoading$ }, + } + + beforeEach(() => { + jest.clearAllMocks() + }) + + describe('', () => { + it('should call httpClient get 3 times if a remoteBaseUrl is set and if global loading is finished', () => { + currentMfe$ = of({ remoteBaseUrl: 'remoteUrl' }) + globalLoading$ = of(false) + const translateLoader = createTranslateLoader(httpClientMock, (appStateServiceMock)) + + translateLoader.getTranslation('en').subscribe() + + expect(httpClientMock.get).toHaveBeenCalledTimes(3) + }) + + it('should call httpClient get 2 times if no remoteBaseUrl is set and if global loading is finished', () => { + currentMfe$ = of({}) + globalLoading$ = of(false) + const translateLoader = createTranslateLoader(httpClientMock, (appStateServiceMock)) + + translateLoader.getTranslation('en').subscribe() + + expect(httpClientMock.get).toHaveBeenCalledTimes(2) + }) + + it('should not call httpClient get if global loading is not finished', () => { + currentMfe$ = of({}) + globalLoading$ = of(true) + const translateLoader = createTranslateLoader(httpClientMock, (appStateServiceMock)) + + translateLoader.getTranslation('en').subscribe() + + expect(httpClientMock.get).toHaveBeenCalledTimes(0) + }) + }) +}) diff --git a/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts b/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts index 79ad9a6c..86e07b6e 100644 --- a/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts +++ b/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts @@ -6,26 +6,24 @@ import { AppStateService } from '../../services/app-state.service' import { AsyncTranslateLoader } from './async-translate-loader.utils' import { TranslateCombinedLoader } from './translate.combined.loader' -export class CreateTranslateLoader { - public static createTranslateLoader(http: HttpClient, appStateService: AppStateService): TranslateLoader { - return new AsyncTranslateLoader( - combineLatest([appStateService.currentMfe$.asObservable(), appStateService.globalLoading$.asObservable()]).pipe( - filter(([, isLoading]) => !isLoading), - map(([currentMfe]) => { - if (currentMfe.remoteBaseUrl) { - return new TranslateCombinedLoader( - new TranslateHttpLoader(http, `${currentMfe.remoteBaseUrl}/assets/i18n/`, '.json'), - new TranslateHttpLoader(http, `./assets/i18n/`, '.json'), - new TranslateHttpLoader(http, `./onecx-portal-lib/assets/i18n/`, '.json') - ) - } else { - return new TranslateCombinedLoader( - new TranslateHttpLoader(http, `./assets/i18n/`, '.json'), - new TranslateHttpLoader(http, `./onecx-portal-lib/assets/i18n/`, '.json') - ) - } - }) - ) +export function createTranslateLoader(http: HttpClient, appStateService: AppStateService): TranslateLoader { + return new AsyncTranslateLoader( + combineLatest([appStateService.currentMfe$.asObservable(), appStateService.globalLoading$.asObservable()]).pipe( + filter(([, isLoading]) => !isLoading), + map(([currentMfe]) => { + if (currentMfe.remoteBaseUrl) { + return new TranslateCombinedLoader( + new TranslateHttpLoader(http, `${currentMfe.remoteBaseUrl}/assets/i18n/`, '.json'), + new TranslateHttpLoader(http, `./assets/i18n/`, '.json'), + new TranslateHttpLoader(http, `./onecx-portal-lib/assets/i18n/`, '.json') + ) + } else { + return new TranslateCombinedLoader( + new TranslateHttpLoader(http, `./assets/i18n/`, '.json'), + new TranslateHttpLoader(http, `./onecx-portal-lib/assets/i18n/`, '.json') + ) + } + }) ) - } + ) } From fd147a0bcbcbcdb55b678cfd7fb5958b3fa9ecbc Mon Sep 17 00:00:00 2001 From: "kim.tran" Date: Fri, 15 Dec 2023 15:42:23 +0100 Subject: [PATCH 05/13] fix: install ng-mocks --- package-lock.json | 23 +++++++++++++++++++++++ package.json | 1 + 2 files changed, 24 insertions(+) diff --git a/package-lock.json b/package-lock.json index 6b2d64ba..0a1469fa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -82,6 +82,7 @@ "jest-preset-angular": "13.0.1", "jsonc-eslint-parser": "^2.2.0", "msw": "^1.3.2", + "ng-mocks": "^14.12.1", "ng-packagr": "15.2.2", "ngx-translate-testing": "^6.1.0", "nx": "16.10.0", @@ -20561,6 +20562,21 @@ "dev": true, "peer": true }, + "node_modules/ng-mocks": { + "version": "14.12.1", + "resolved": "https://registry.npmjs.org/ng-mocks/-/ng-mocks-14.12.1.tgz", + "integrity": "sha512-5OdTYYOva7IkCCi6kTtgnII1hSfw+qYOM1ScrKhyo7iaI/ViV8xI4MGa89Ts7XnH6XqISSez2Un3zFSomkFpmg==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/satanTime" + }, + "peerDependencies": { + "@angular/common": "5.0.0-alpha - 5 || 6.0.0-alpha - 6 || 7.0.0-alpha - 7 || 8.0.0-alpha - 8 || 9.0.0-alpha - 9 || 10.0.0-alpha - 10 || 11.0.0-alpha - 11 || 12.0.0-alpha - 12 || 13.0.0-alpha - 13 || 14.0.0-alpha - 14 || 15.0.0-alpha - 15 || 16.0.0-alpha - 16 || 17.0.0-alpha - 17", + "@angular/core": "5.0.0-alpha - 5 || 6.0.0-alpha - 6 || 7.0.0-alpha - 7 || 8.0.0-alpha - 8 || 9.0.0-alpha - 9 || 10.0.0-alpha - 10 || 11.0.0-alpha - 11 || 12.0.0-alpha - 12 || 13.0.0-alpha - 13 || 14.0.0-alpha - 14 || 15.0.0-alpha - 15 || 16.0.0-alpha - 16 || 17.0.0-alpha - 17", + "@angular/forms": "5.0.0-alpha - 5 || 6.0.0-alpha - 6 || 7.0.0-alpha - 7 || 8.0.0-alpha - 8 || 9.0.0-alpha - 9 || 10.0.0-alpha - 10 || 11.0.0-alpha - 11 || 12.0.0-alpha - 12 || 13.0.0-alpha - 13 || 14.0.0-alpha - 14 || 15.0.0-alpha - 15 || 16.0.0-alpha - 16 || 17.0.0-alpha - 17", + "@angular/platform-browser": "5.0.0-alpha - 5 || 6.0.0-alpha - 6 || 7.0.0-alpha - 7 || 8.0.0-alpha - 8 || 9.0.0-alpha - 9 || 10.0.0-alpha - 10 || 11.0.0-alpha - 11 || 12.0.0-alpha - 12 || 13.0.0-alpha - 13 || 14.0.0-alpha - 14 || 15.0.0-alpha - 15 || 16.0.0-alpha - 16 || 17.0.0-alpha - 17" + } + }, "node_modules/ng-packagr": { "version": "15.2.2", "resolved": "https://registry.npmjs.org/ng-packagr/-/ng-packagr-15.2.2.tgz", @@ -47720,6 +47736,13 @@ "dev": true, "peer": true }, + "ng-mocks": { + "version": "14.12.1", + "resolved": "https://registry.npmjs.org/ng-mocks/-/ng-mocks-14.12.1.tgz", + "integrity": "sha512-5OdTYYOva7IkCCi6kTtgnII1hSfw+qYOM1ScrKhyo7iaI/ViV8xI4MGa89Ts7XnH6XqISSez2Un3zFSomkFpmg==", + "dev": true, + "requires": {} + }, "ng-packagr": { "version": "15.2.2", "resolved": "https://registry.npmjs.org/ng-packagr/-/ng-packagr-15.2.2.tgz", diff --git a/package.json b/package.json index 454e82d8..135eeebe 100644 --- a/package.json +++ b/package.json @@ -78,6 +78,7 @@ "jest-preset-angular": "13.0.1", "jsonc-eslint-parser": "^2.2.0", "msw": "^1.3.2", + "ng-mocks": "^14.12.1", "ng-packagr": "15.2.2", "ngx-translate-testing": "^6.1.0", "nx": "16.10.0", From 54a51068f14a6ee8bf9e748b09f227b3f1b06df6 Mon Sep 17 00:00:00 2001 From: "kim.tran" Date: Mon, 18 Dec 2023 13:17:03 +0100 Subject: [PATCH 06/13] feat: remove jest-marbles --- package-lock.json | 18 ------------------ package.json | 1 - 2 files changed, 19 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0a1469fa..1f2b0df8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,7 +31,6 @@ "chart.js": "^4.4.0", "d3-scale-chromatic": "^3.0.0", "fast-deep-equal": "^3.1.3", - "jest-marbles": "^3.0.5", "keycloak-angular": "^13.0.0", "keycloak-js": "^18.0.0", "ngx-color": "^8.0.3", @@ -17674,17 +17673,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-marbles": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/jest-marbles/-/jest-marbles-3.0.5.tgz", - "integrity": "sha512-ZZjMyo//+y/8w8m5qfjkj2/r3LPx0TzdnDwdwYEiVGcNb65YYtIYcJ/wlovBXsjHyXDqI4a3w5xgE9LM7brJVg==", - "engines": { - "node": ">=6.11.5" - }, - "peerDependencies": { - "rxjs": "^7.0.0" - } - }, "node_modules/jest-matcher-utils": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", @@ -45523,12 +45511,6 @@ "pretty-format": "^29.7.0" } }, - "jest-marbles": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/jest-marbles/-/jest-marbles-3.0.5.tgz", - "integrity": "sha512-ZZjMyo//+y/8w8m5qfjkj2/r3LPx0TzdnDwdwYEiVGcNb65YYtIYcJ/wlovBXsjHyXDqI4a3w5xgE9LM7brJVg==", - "requires": {} - }, "jest-matcher-utils": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", diff --git a/package.json b/package.json index 135eeebe..d55f193d 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,6 @@ "chart.js": "^4.4.0", "d3-scale-chromatic": "^3.0.0", "fast-deep-equal": "^3.1.3", - "jest-marbles": "^3.0.5", "keycloak-angular": "^13.0.0", "keycloak-js": "^18.0.0", "ngx-color": "^8.0.3", From 1d5a4f28d4663870e2c3ad1e980f07cfd2fef656 Mon Sep 17 00:00:00 2001 From: "kim.tran" Date: Tue, 19 Dec 2023 16:09:19 +0100 Subject: [PATCH 07/13] fix: minor fix in test --- .../utils/create-translate-loader.spec.ts | 58 +++++++++---------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.spec.ts b/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.spec.ts index 6d2a9767..123503fd 100644 --- a/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.spec.ts +++ b/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.spec.ts @@ -20,35 +20,33 @@ describe('CreateTranslateLoader', () => { jest.clearAllMocks() }) - describe('', () => { - it('should call httpClient get 3 times if a remoteBaseUrl is set and if global loading is finished', () => { - currentMfe$ = of({ remoteBaseUrl: 'remoteUrl' }) - globalLoading$ = of(false) - const translateLoader = createTranslateLoader(httpClientMock, (appStateServiceMock)) - - translateLoader.getTranslation('en').subscribe() - - expect(httpClientMock.get).toHaveBeenCalledTimes(3) - }) - - it('should call httpClient get 2 times if no remoteBaseUrl is set and if global loading is finished', () => { - currentMfe$ = of({}) - globalLoading$ = of(false) - const translateLoader = createTranslateLoader(httpClientMock, (appStateServiceMock)) - - translateLoader.getTranslation('en').subscribe() - - expect(httpClientMock.get).toHaveBeenCalledTimes(2) - }) - - it('should not call httpClient get if global loading is not finished', () => { - currentMfe$ = of({}) - globalLoading$ = of(true) - const translateLoader = createTranslateLoader(httpClientMock, (appStateServiceMock)) - - translateLoader.getTranslation('en').subscribe() - - expect(httpClientMock.get).toHaveBeenCalledTimes(0) - }) + it('should call httpClient get 3 times if a remoteBaseUrl is set and if global loading is finished', () => { + currentMfe$ = of({ remoteBaseUrl: 'remoteUrl' }) + globalLoading$ = of(false) + const translateLoader = createTranslateLoader(httpClientMock, (appStateServiceMock)) + + translateLoader.getTranslation('en').subscribe() + + expect(httpClientMock.get).toHaveBeenCalledTimes(3) + }) + + it('should call httpClient get 2 times if no remoteBaseUrl is set and if global loading is finished', () => { + currentMfe$ = of({}) + globalLoading$ = of(false) + const translateLoader = createTranslateLoader(httpClientMock, (appStateServiceMock)) + + translateLoader.getTranslation('en').subscribe() + + expect(httpClientMock.get).toHaveBeenCalledTimes(2) + }) + + it('should not call httpClient get if global loading is not finished', () => { + currentMfe$ = of({}) + globalLoading$ = of(true) + const translateLoader = createTranslateLoader(httpClientMock, (appStateServiceMock)) + + translateLoader.getTranslation('en').subscribe() + + expect(httpClientMock.get).toHaveBeenCalledTimes(0) }) }) From f46ee8fa4b84a68d25d9f9de7175425ebe56b04e Mon Sep 17 00:00:00 2001 From: "kim.tran" Date: Tue, 9 Jan 2024 09:16:55 +0100 Subject: [PATCH 08/13] fix: minor fixes --- libs/accelerator/src/lib/topic/topic.spec.ts | 5 +++-- ...-loader.spec.ts => async-translate-loader.utils.spec.ts} | 0 ...loader.spec.ts => create-translate-loader.utils.spec.ts} | 0 .../src/lib/services/theme.service.ts | 6 +++--- 4 files changed, 6 insertions(+), 5 deletions(-) rename libs/portal-integration-angular/src/lib/core/utils/{async-translate-loader.spec.ts => async-translate-loader.utils.spec.ts} (100%) rename libs/portal-integration-angular/src/lib/core/utils/{create-translate-loader.spec.ts => create-translate-loader.utils.spec.ts} (100%) diff --git a/libs/accelerator/src/lib/topic/topic.spec.ts b/libs/accelerator/src/lib/topic/topic.spec.ts index 825f0eeb..4c89a887 100644 --- a/libs/accelerator/src/lib/topic/topic.spec.ts +++ b/libs/accelerator/src/lib/topic/topic.spec.ts @@ -146,12 +146,13 @@ describe('Topic', () => { it('should check isInitialized', (done) => { let initialized = false testTopic1.isInitialized.then(() => (initialized = true)) - + expect(initialized).toBe(false) testTopic1.publish('test') setTimeout(() => { expect(initialized).toBe(true) - }, done()) + done() + }) }) }) diff --git a/libs/portal-integration-angular/src/lib/core/utils/async-translate-loader.spec.ts b/libs/portal-integration-angular/src/lib/core/utils/async-translate-loader.utils.spec.ts similarity index 100% rename from libs/portal-integration-angular/src/lib/core/utils/async-translate-loader.spec.ts rename to libs/portal-integration-angular/src/lib/core/utils/async-translate-loader.utils.spec.ts diff --git a/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.spec.ts b/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.spec.ts similarity index 100% rename from libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.spec.ts rename to libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.spec.ts diff --git a/libs/portal-integration-angular/src/lib/services/theme.service.ts b/libs/portal-integration-angular/src/lib/services/theme.service.ts index 05c4e236..9cb63616 100644 --- a/libs/portal-integration-angular/src/lib/services/theme.service.ts +++ b/libs/portal-integration-angular/src/lib/services/theme.service.ts @@ -1,7 +1,7 @@ import { HttpClient } from '@angular/common/http' import { Injectable, OnDestroy } from '@angular/core' import { CurrentThemeTopic } from '@onecx/integration-interface' -import { tap } from 'rxjs' +import { from, map, mergeMap } from 'rxjs' import { CONFIG_KEY } from '../model/config-key.model' import { Theme } from '../model/theme' import { ConfigurationService } from './configuration.service' @@ -25,8 +25,8 @@ export class ThemeService implements OnDestroy { public loadAndApplyTheme(themeName: string) { return this.http.get(`${this.baseUrlV1}/internal/themes/${encodeURI(themeName)}`).pipe( - tap(async (theme) => { - await this.apply(theme) + mergeMap((theme) => { + return from(this.apply(theme)).pipe(map(() => theme)) }) ) } From cae979f663ccf1357b29325fbddb0efa4bbbf2c0 Mon Sep 17 00:00:00 2001 From: "kim.tran" Date: Tue, 16 Jan 2024 17:42:52 +0100 Subject: [PATCH 09/13] feat: changes for enabling starting apps in standalone mode --- libs/portal-integration-angular/src/index.ts | 3 + .../initializer/standalone.initializer.ts | 2 +- .../src/lib/core/portal-core.module.ts | 15 ++-- .../add-initialize-module-guard.utils.ts | 21 ++++++ .../lib/core/utils/app-initializer.utils.ts | 16 +++++ .../create-translate-loader.utils.spec.ts | 29 ++++++-- .../utils/create-translate-loader.utils.ts | 42 +++++++---- .../src/lib/model/config-key.model.ts | 3 +- .../src/lib/services/app-state.service.ts | 6 ++ .../src/lib/services/configuration.service.ts | 5 +- .../initialize-module-guard.service.ts | 32 +++++++-- .../portal-api-configuration.service.ts | 69 +++++++++++++++++++ .../src/lib/services/theme.service.ts | 9 ++- 13 files changed, 216 insertions(+), 36 deletions(-) create mode 100644 libs/portal-integration-angular/src/lib/core/utils/add-initialize-module-guard.utils.ts create mode 100644 libs/portal-integration-angular/src/lib/core/utils/app-initializer.utils.ts create mode 100644 libs/portal-integration-angular/src/lib/services/portal-api-configuration.service.ts diff --git a/libs/portal-integration-angular/src/index.ts b/libs/portal-integration-angular/src/index.ts index 1665f292..53216d93 100644 --- a/libs/portal-integration-angular/src/index.ts +++ b/libs/portal-integration-angular/src/index.ts @@ -61,6 +61,7 @@ export * from './lib/services/initialize-module-guard.service' export * from './lib/services/userprofile-api.service' export * from './lib/services/portal-dialog.service' export * from './lib/services/user.service' +export * from './lib/services/portal-api-configuration.service' // pipes export * from './lib/core/pipes/dynamic.pipe' @@ -109,3 +110,5 @@ export * from './lib/core/utils/translate.combined.loader' export * from './lib/core/utils/image-logo-url.utils' export * from './lib/core/utils/async-translate-loader.utils' export * from './lib/core/utils/create-translate-loader.utils' +export * from './lib/core/utils/add-initialize-module-guard.utils' +export * from './lib/core/utils/app-initializer.utils' diff --git a/libs/portal-integration-angular/src/lib/core/initializer/standalone.initializer.ts b/libs/portal-integration-angular/src/lib/core/initializer/standalone.initializer.ts index f0d84920..0a409aea 100644 --- a/libs/portal-integration-angular/src/lib/core/initializer/standalone.initializer.ts +++ b/libs/portal-integration-angular/src/lib/core/initializer/standalone.initializer.ts @@ -66,7 +66,7 @@ export function standaloneInitializer( errCause = PORTAL_LOAD_INIT_ERR throw e } - console.log(`📃 portal OK? ${portal}`) + console.log(`📃 portal OK? `, portal) await appStateService.currentPortal$.publish(portal) let theme = undefined diff --git a/libs/portal-integration-angular/src/lib/core/portal-core.module.ts b/libs/portal-integration-angular/src/lib/core/portal-core.module.ts index 0cd7f5c7..669d6ac0 100644 --- a/libs/portal-integration-angular/src/lib/core/portal-core.module.ts +++ b/libs/portal-integration-angular/src/lib/core/portal-core.module.ts @@ -77,6 +77,7 @@ import { GroupByCountDiagramComponent } from './components/group-by-count-diagra import { UserService } from '../services/user.service' import { UserProfileAPIService } from '../services/userprofile-api.service' import { createTranslateLoader } from './utils/create-translate-loader.utils' +import { MessageService } from 'primeng/api' export class MyMissingTranslationHandler implements MissingTranslationHandler { handle(params: MissingTranslationHandlerParams) { @@ -94,7 +95,11 @@ export class MyMissingTranslationHandler implements MissingTranslationHandler { PrimeNgModule, TranslateModule.forRoot({ isolate: true, - loader: { provide: TranslateLoader, useFactory: createTranslateLoader, deps: [HttpClient, AppStateService] }, + loader: { + provide: TranslateLoader, + useFactory: createTranslateLoader, + deps: [HttpClient, AppStateService, ConfigurationService], + }, missingTranslationHandler: { provide: MissingTranslationHandler, useClass: MyMissingTranslationHandler }, }), ConfirmDialogModule, @@ -213,9 +218,7 @@ export class PortalCoreModule { public static forMicroFrontend(): ModuleWithProviders { return { ngModule: PortalCoreModule, - providers: [ - { provide: SANITY_CHECK, useValue: 'mfe' }, - ], + providers: [{ provide: SANITY_CHECK, useValue: 'mfe' }], } } @@ -225,6 +228,10 @@ export class PortalCoreModule { providers: [ { provide: SANITY_CHECK, useValue: 'root' }, { provide: APPLICATION_NAME, useValue: appName }, + { + provide: MessageService, + useClass: MessageService, + }, ], } if (!disableInitializer) { diff --git a/libs/portal-integration-angular/src/lib/core/utils/add-initialize-module-guard.utils.ts b/libs/portal-integration-angular/src/lib/core/utils/add-initialize-module-guard.utils.ts new file mode 100644 index 00000000..0bb601e9 --- /dev/null +++ b/libs/portal-integration-angular/src/lib/core/utils/add-initialize-module-guard.utils.ts @@ -0,0 +1,21 @@ +import { CanActivateFn, Route } from '@angular/router' +import { InitializeModuleGuard } from '../../services/initialize-module-guard.service' + +export function addInitializeModuleGuard( + routes: Route[], + initializeModuleGuard: typeof InitializeModuleGuard | CanActivateFn = InitializeModuleGuard +): Route[] { + return routes.map((r) => { + if (r.redirectTo) { + return r + } + const route = { + canActivate: [], + ...r, + } + if (!route.canActivate.includes(initializeModuleGuard)) { + route.canActivate.push(initializeModuleGuard) + } + return route + }) +} \ No newline at end of file diff --git a/libs/portal-integration-angular/src/lib/core/utils/app-initializer.utils.ts b/libs/portal-integration-angular/src/lib/core/utils/app-initializer.utils.ts new file mode 100644 index 00000000..837a1e87 --- /dev/null +++ b/libs/portal-integration-angular/src/lib/core/utils/app-initializer.utils.ts @@ -0,0 +1,16 @@ +import { TranslateService } from '@ngx-translate/core' +import { firstValueFrom, mergeMap, tap } from 'rxjs' +import { UserService } from '../../services/user.service' + +export function appInitializer(userService: UserService, translateService: TranslateService): () => Promise { + return () => { + translateService.setDefaultLang('en') + return firstValueFrom( + userService.lang$.pipe( + mergeMap((l) => { + return translateService.use(l).pipe(tap((t) => console.log('RETURN TAP USE ', t))) + }) + ) + ) + } +} diff --git a/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.spec.ts b/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.spec.ts index 123503fd..9188221e 100644 --- a/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.spec.ts +++ b/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.spec.ts @@ -3,19 +3,25 @@ import { AppStateService } from '../../services/app-state.service' import { createTranslateLoader } from './create-translate-loader.utils' import { MockService } from 'ng-mocks' import { Observable, of } from 'rxjs' -import { MfeInfo } from '@onecx/integration-interface' +import { Config, MfeInfo } from '@onecx/integration-interface' +import { ConfigurationService } from '../../services/configuration.service' describe('CreateTranslateLoader', () => { const httpClientMock = MockService(HttpClient) httpClientMock.get = jest.fn(() => of({})) as any let currentMfe$: Observable> let globalLoading$: Observable + let config$: Observable> const appStateServiceMock = { currentMfe$: { asObservable: () => currentMfe$ }, globalLoading$: { asObservable: () => globalLoading$ }, } + const configurationServiceMock = { + config$: { asObservable: () => config$ }, + } + beforeEach(() => { jest.clearAllMocks() }) @@ -23,7 +29,12 @@ describe('CreateTranslateLoader', () => { it('should call httpClient get 3 times if a remoteBaseUrl is set and if global loading is finished', () => { currentMfe$ = of({ remoteBaseUrl: 'remoteUrl' }) globalLoading$ = of(false) - const translateLoader = createTranslateLoader(httpClientMock, (appStateServiceMock)) + config$ = of({}) + const translateLoader = createTranslateLoader( + httpClientMock, + (appStateServiceMock), + configurationServiceMock + ) translateLoader.getTranslation('en').subscribe() @@ -33,7 +44,12 @@ describe('CreateTranslateLoader', () => { it('should call httpClient get 2 times if no remoteBaseUrl is set and if global loading is finished', () => { currentMfe$ = of({}) globalLoading$ = of(false) - const translateLoader = createTranslateLoader(httpClientMock, (appStateServiceMock)) + config$ = of() + const translateLoader = createTranslateLoader( + httpClientMock, + (appStateServiceMock), + configurationServiceMock + ) translateLoader.getTranslation('en').subscribe() @@ -43,7 +59,12 @@ describe('CreateTranslateLoader', () => { it('should not call httpClient get if global loading is not finished', () => { currentMfe$ = of({}) globalLoading$ = of(true) - const translateLoader = createTranslateLoader(httpClientMock, (appStateServiceMock)) + config$ = of({}) + const translateLoader = createTranslateLoader( + httpClientMock, + (appStateServiceMock), + configurationServiceMock + ) translateLoader.getTranslation('en').subscribe() diff --git a/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts b/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts index 86e07b6e..b5bd8df7 100644 --- a/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts +++ b/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts @@ -1,26 +1,42 @@ import { HttpClient } from '@angular/common/http' import { TranslateLoader } from '@ngx-translate/core' import { TranslateHttpLoader } from '@ngx-translate/http-loader' -import { combineLatest, filter, map } from 'rxjs' +import { combineLatest, filter, first, map, mergeMap, of } from 'rxjs' +import { CONFIG_KEY } from '../../model/config-key.model' import { AppStateService } from '../../services/app-state.service' +import { ConfigurationService } from '../../services/configuration.service' import { AsyncTranslateLoader } from './async-translate-loader.utils' import { TranslateCombinedLoader } from './translate.combined.loader' -export function createTranslateLoader(http: HttpClient, appStateService: AppStateService): TranslateLoader { +export function createTranslateLoader( + http: HttpClient, + appStateService: AppStateService, + configService: ConfigurationService +): TranslateLoader { return new AsyncTranslateLoader( - combineLatest([appStateService.currentMfe$.asObservable(), appStateService.globalLoading$.asObservable()]).pipe( - filter(([, isLoading]) => !isLoading), - map(([currentMfe]) => { - if (currentMfe.remoteBaseUrl) { - return new TranslateCombinedLoader( - new TranslateHttpLoader(http, `${currentMfe.remoteBaseUrl}/assets/i18n/`, '.json'), - new TranslateHttpLoader(http, `./assets/i18n/`, '.json'), - new TranslateHttpLoader(http, `./onecx-portal-lib/assets/i18n/`, '.json') + configService.config$.pipe( + first(), + mergeMap(() => { + if (configService.getProperty(CONFIG_KEY.IS_SHELL)) { + return combineLatest([ + appStateService.currentMfe$.asObservable(), + appStateService.globalLoading$.asObservable(), + ]).pipe( + filter(([, isLoading]) => !isLoading), + map(([currentMfe]) => { + return new TranslateCombinedLoader( + new TranslateHttpLoader(http, `${currentMfe.remoteBaseUrl}/assets/i18n/`, '.json'), + new TranslateHttpLoader(http, `./assets/i18n/`, '.json'), + new TranslateHttpLoader(http, `./onecx-portal-lib/assets/i18n/`, '.json') + ) + }) ) } else { - return new TranslateCombinedLoader( - new TranslateHttpLoader(http, `./assets/i18n/`, '.json'), - new TranslateHttpLoader(http, `./onecx-portal-lib/assets/i18n/`, '.json') + return of( + new TranslateCombinedLoader( + new TranslateHttpLoader(http, `./assets/i18n/`, '.json'), + new TranslateHttpLoader(http, `./onecx-portal-lib/assets/i18n/`, '.json') + ) ) } }) diff --git a/libs/portal-integration-angular/src/lib/model/config-key.model.ts b/libs/portal-integration-angular/src/lib/model/config-key.model.ts index 6d0f29f3..beef9d41 100644 --- a/libs/portal-integration-angular/src/lib/model/config-key.model.ts +++ b/libs/portal-integration-angular/src/lib/model/config-key.model.ts @@ -1,4 +1,4 @@ -export const enum CONFIG_KEY { +export enum CONFIG_KEY { TKIT_PORTAL_DEFAULT_THEME = 'TKIT_PORTAL_DEFAULT_THEME', TKIT_PORTAL_DISABLE_THEME_MANAGEMENT = 'TKIT_PORTAL_DISABLE_THEME_MANAGEMENT', TKIT_PORTAL_THEME_SERVER_URL = 'TKIT_PORTAL_THEME_SERVER_URL', @@ -21,4 +21,5 @@ export const enum CONFIG_KEY { ONECX_PORTAL_MY_ROLES_PERMISSIONS_DISABLED = 'ONECX_PORTAL_MY_ROLES_PERMISSIONS_DISABLED', ONECX_PORTAL_HELP_DISABLED = 'ONECX_PORTAL_HELP_DISABLED', APP_VERSION = 'APP_VERSION', + IS_SHELL = 'IS_SHELL', } diff --git a/libs/portal-integration-angular/src/lib/services/app-state.service.ts b/libs/portal-integration-angular/src/lib/services/app-state.service.ts index d107dd00..80fdac7c 100644 --- a/libs/portal-integration-angular/src/lib/services/app-state.service.ts +++ b/libs/portal-integration-angular/src/lib/services/app-state.service.ts @@ -12,6 +12,12 @@ import { export class AppStateService implements OnDestroy { globalError$ = new GlobalErrorTopic() globalLoading$ = new GlobalLoadingTopic() + + /** + * Values will only be set in shell mode, but you should not rely on this behavior, + * because it could change in the future. + * To check if you are in shell mode, please use the ConfigurationService + */ currentMfe$ = new CurrentMfeTopic() /** diff --git a/libs/portal-integration-angular/src/lib/services/configuration.service.ts b/libs/portal-integration-angular/src/lib/services/configuration.service.ts index e3527c89..9de13ca1 100644 --- a/libs/portal-integration-angular/src/lib/services/configuration.service.ts +++ b/libs/portal-integration-angular/src/lib/services/configuration.service.ts @@ -43,7 +43,7 @@ export class ConfigurationService implements OnDestroy { loadConfigPromise .then(async (config) => { if (config) { - await this.config$.publish({ ...this.defaultConfig }).then(() => { + await this.config$.publish({ ...this.defaultConfig, ...config }).then(() => { resolve(true) }) } @@ -60,6 +60,9 @@ export class ConfigurationService implements OnDestroy { } public getProperty(key: CONFIG_KEY): string | undefined { + if (!Object.values(CONFIG_KEY).includes(key)) { + console.error('Invalid config key ', key) + } return this.config$.getValue()?.[key] } diff --git a/libs/portal-integration-angular/src/lib/services/initialize-module-guard.service.ts b/libs/portal-integration-angular/src/lib/services/initialize-module-guard.service.ts index b598cddf..47cb3f36 100644 --- a/libs/portal-integration-angular/src/lib/services/initialize-module-guard.service.ts +++ b/libs/portal-integration-angular/src/lib/services/initialize-module-guard.service.ts @@ -1,7 +1,8 @@ import { Injectable } from '@angular/core' import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, UrlTree } from '@angular/router' import { TranslateService } from '@ngx-translate/core' -import { filter, from, map, mergeMap, Observable, of } from 'rxjs' +import { filter, from, isObservable, map, mergeMap, Observable, of } from 'rxjs' +import { CONFIG_KEY } from '../model/config-key.model' import { AppStateService } from './app-state.service' import { ConfigurationService } from './configuration.service' import { UserService } from './user.service' @@ -11,10 +12,10 @@ export class InitializeModuleGuard implements CanActivate { private SUPPORTED_LANGS = ['en', 'de'] private DEFAULT_LANG = 'en' constructor( - private txService: TranslateService, - private config: ConfigurationService, - private appStateService: AppStateService, - private userService: UserService + protected translateService: TranslateService, + protected configService: ConfigurationService, + protected appStateService: AppStateService, + protected userService: UserService ) {} canActivate( @@ -22,8 +23,16 @@ export class InitializeModuleGuard implements CanActivate { _state: RouterStateSnapshot ): Observable | Promise | boolean | UrlTree { return this.loadTranslations().pipe( - mergeMap(() => from(this.config.isInitialized)), + mergeMap(() => from(this.configService.isInitialized)), mergeMap(() => from(this.appStateService.currentPortal$.isInitialized)), + mergeMap(() => { + return this.configService.getProperty(CONFIG_KEY.IS_SHELL) + ? this.appStateService.globalLoading$.pipe( + filter((g) => !g), + map(() => true) + ) + : of(true) + }), map(() => true) ) } @@ -40,8 +49,17 @@ export class InitializeModuleGuard implements CanActivate { loadTranslations(): Observable { return this.userService.lang$.pipe( filter((v) => v !== undefined), - mergeMap((lang) => this.txService.use(this.getBestMatchLanguage(lang as string))), + mergeMap((lang) => this.translateService.use(this.getBestMatchLanguage(lang as string))), mergeMap(() => of(true)) ) } + + protected toObservable( + canActivateResult: Observable | Promise | boolean | UrlTree + ): Observable { + if (isObservable(canActivateResult)) { + return canActivateResult + } + return from(Promise.resolve(canActivateResult)) + } } diff --git a/libs/portal-integration-angular/src/lib/services/portal-api-configuration.service.ts b/libs/portal-integration-angular/src/lib/services/portal-api-configuration.service.ts new file mode 100644 index 00000000..40eed9a9 --- /dev/null +++ b/libs/portal-integration-angular/src/lib/services/portal-api-configuration.service.ts @@ -0,0 +1,69 @@ +import { BehaviorSubject, first, map } from 'rxjs' +import { API_PREFIX } from '../api/constants' +import { CONFIG_KEY } from '../model/config-key.model' +import { AppStateService } from './app-state.service' +import { ConfigurationService } from './configuration.service' + +type Config = { + credentials: { [key: string]: string | (() => string | undefined) } + selectHeaderContentType(contentTypes: string[]): string | undefined + selectHeaderAccept(accepts: string[]): string | undefined + isJsonMime(mime: string): boolean + lookupCredential(key: string): string | undefined +} + +export class PortalApiConfiguration { + private configuration = this.activator(this.configurationClassOfGenerator) + + protected basePath$ = new BehaviorSubject('./' + API_PREFIX) + get basePath() { + return this.basePath$.value + } + set basePath(_: string) { + throw new Error('Do not set basePath') + } + + get credentials(): { [key: string]: string | (() => string | undefined) } { + return this.configuration.credentials + } + set credentials(value: { [key: string]: string | (() => string | undefined) }) { + this.configuration.credentials = value + } + + constructor( + private configurationClassOfGenerator: unknown, + configService: ConfigurationService, + appStateService: AppStateService + ) { + if (configService.getProperty(CONFIG_KEY.IS_SHELL)) { + appStateService.currentMfe$ + .pipe( + first(), + map((currentMfe) => { + return currentMfe.remoteBaseUrl + API_PREFIX + }) + ) + .subscribe(this.basePath$) + } + } + + public selectHeaderContentType(contentTypes: string[]): string | undefined { + return this.configuration.selectHeaderContentType(contentTypes) + } + + public selectHeaderAccept(accepts: string[]): string | undefined { + return this.configuration.selectHeaderAccept(accepts) + } + + public isJsonMime(mime: string): boolean { + return this.configuration.isJsonMime(mime) + } + + public lookupCredential(key: string): string | undefined { + return this.configuration.lookupCredential(key) + } + + private activator(type: unknown): Config { + return new (<{ new (): Config }>(type))() + } +} diff --git a/libs/portal-integration-angular/src/lib/services/theme.service.ts b/libs/portal-integration-angular/src/lib/services/theme.service.ts index 9cb63616..78d85dcc 100644 --- a/libs/portal-integration-angular/src/lib/services/theme.service.ts +++ b/libs/portal-integration-angular/src/lib/services/theme.service.ts @@ -10,17 +10,16 @@ const defaultThemeServerUrl = 'http://portal-theme-management:8080' @Injectable({ providedIn: 'root' }) export class ThemeService implements OnDestroy { - themeServerUrl: string baseUrlV1 = './portal-api' currentTheme$ = new CurrentThemeTopic() - constructor(private configservice: ConfigurationService, private http: HttpClient) { - this.themeServerUrl = - this.configservice.getProperty(CONFIG_KEY.TKIT_PORTAL_THEME_SERVER_URL) || defaultThemeServerUrl + constructor(private configService: ConfigurationService, private http: HttpClient) { } getThemeHref(themeId: string): string { - return `${this.themeServerUrl}/themes/${themeId}/${themeId}.min.css` + const themeServerUrl = + this.configService.getProperty(CONFIG_KEY.TKIT_PORTAL_THEME_SERVER_URL) || defaultThemeServerUrl + return `${themeServerUrl}/themes/${themeId}/${themeId}.min.css` } public loadAndApplyTheme(themeName: string) { From 1d792adb5c9660dd3393c339a78c874dbce2f9a8 Mon Sep 17 00:00:00 2001 From: "kim.tran" Date: Wed, 17 Jan 2024 14:08:18 +0100 Subject: [PATCH 10/13] fix: init currentMfe with values in standalone, set basePath correctly with apiPrefix --- libs/portal-integration-angular/src/index.ts | 4 +-- .../initializer/standalone.initializer.ts | 8 ++++- .../utils/create-translate-loader.utils.ts | 30 +++++++------------ .../utils/portal-api-configuration.utils.ts} | 28 ++++++++--------- ...=> translate-service-initializer.utils.ts} | 2 +- .../initialize-module-guard.service.ts | 10 +++---- 6 files changed, 37 insertions(+), 45 deletions(-) rename libs/portal-integration-angular/src/lib/{services/portal-api-configuration.service.ts => core/utils/portal-api-configuration.utils.ts} (74%) rename libs/portal-integration-angular/src/lib/core/utils/{app-initializer.utils.ts => translate-service-initializer.utils.ts} (76%) diff --git a/libs/portal-integration-angular/src/index.ts b/libs/portal-integration-angular/src/index.ts index 53216d93..0ee24364 100644 --- a/libs/portal-integration-angular/src/index.ts +++ b/libs/portal-integration-angular/src/index.ts @@ -61,7 +61,7 @@ export * from './lib/services/initialize-module-guard.service' export * from './lib/services/userprofile-api.service' export * from './lib/services/portal-dialog.service' export * from './lib/services/user.service' -export * from './lib/services/portal-api-configuration.service' +export * from './lib/core/utils/portal-api-configuration.utils' // pipes export * from './lib/core/pipes/dynamic.pipe' @@ -111,4 +111,4 @@ export * from './lib/core/utils/image-logo-url.utils' export * from './lib/core/utils/async-translate-loader.utils' export * from './lib/core/utils/create-translate-loader.utils' export * from './lib/core/utils/add-initialize-module-guard.utils' -export * from './lib/core/utils/app-initializer.utils' +export * from './lib/core/utils/translate-service-initializer.utils' diff --git a/libs/portal-integration-angular/src/lib/core/initializer/standalone.initializer.ts b/libs/portal-integration-angular/src/lib/core/initializer/standalone.initializer.ts index 0a409aea..dd7a50d0 100644 --- a/libs/portal-integration-angular/src/lib/core/initializer/standalone.initializer.ts +++ b/libs/portal-integration-angular/src/lib/core/initializer/standalone.initializer.ts @@ -7,6 +7,7 @@ import { AppStateService } from '../../services/app-state.service' import { CONFIG_KEY } from '../../model/config-key.model' import { UserService } from '../../services/user.service' import { UserProfileAPIService } from '../../services/userprofile-api.service' +import { MfeInfo } from '@onecx/integration-interface' const CONFIG_INIT_ERR = 'CONFIG_INIT_ERR' const AUTH_INIT_ERR = 'AUTH_INIT_ERR' @@ -68,8 +69,13 @@ export function standaloneInitializer( } console.log(`📃 portal OK? `, portal) await appStateService.currentPortal$.publish(portal) - let theme = undefined + const standaloneMfeInfo: MfeInfo = { mountPath: '/', remoteBaseUrl:'.', baseHref: '/', shellName: 'standalone' } + await appStateService.globalLoading$.publish(true) + await appStateService.currentMfe$.publish(standaloneMfeInfo) + await appStateService.globalLoading$.publish(false) + + let theme = undefined if (!portal) { throw new Error('No portal data found') } else { diff --git a/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts b/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts index b5bd8df7..9ba6784d 100644 --- a/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts +++ b/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts @@ -2,7 +2,6 @@ import { HttpClient } from '@angular/common/http' import { TranslateLoader } from '@ngx-translate/core' import { TranslateHttpLoader } from '@ngx-translate/http-loader' import { combineLatest, filter, first, map, mergeMap, of } from 'rxjs' -import { CONFIG_KEY } from '../../model/config-key.model' import { AppStateService } from '../../services/app-state.service' import { ConfigurationService } from '../../services/configuration.service' import { AsyncTranslateLoader } from './async-translate-loader.utils' @@ -17,28 +16,19 @@ export function createTranslateLoader( configService.config$.pipe( first(), mergeMap(() => { - if (configService.getProperty(CONFIG_KEY.IS_SHELL)) { - return combineLatest([ - appStateService.currentMfe$.asObservable(), - appStateService.globalLoading$.asObservable(), - ]).pipe( - filter(([, isLoading]) => !isLoading), - map(([currentMfe]) => { - return new TranslateCombinedLoader( - new TranslateHttpLoader(http, `${currentMfe.remoteBaseUrl}/assets/i18n/`, '.json'), - new TranslateHttpLoader(http, `./assets/i18n/`, '.json'), - new TranslateHttpLoader(http, `./onecx-portal-lib/assets/i18n/`, '.json') - ) - }) - ) - } else { - return of( - new TranslateCombinedLoader( + return combineLatest([ + appStateService.currentMfe$.asObservable(), + appStateService.globalLoading$.asObservable(), + ]).pipe( + filter(([, isLoading]) => !isLoading), + map(([currentMfe]) => { + return new TranslateCombinedLoader( + new TranslateHttpLoader(http, `${currentMfe.remoteBaseUrl}/assets/i18n/`, '.json'), new TranslateHttpLoader(http, `./assets/i18n/`, '.json'), new TranslateHttpLoader(http, `./onecx-portal-lib/assets/i18n/`, '.json') ) - ) - } + }) + ) }) ) ) diff --git a/libs/portal-integration-angular/src/lib/services/portal-api-configuration.service.ts b/libs/portal-integration-angular/src/lib/core/utils/portal-api-configuration.utils.ts similarity index 74% rename from libs/portal-integration-angular/src/lib/services/portal-api-configuration.service.ts rename to libs/portal-integration-angular/src/lib/core/utils/portal-api-configuration.utils.ts index 40eed9a9..463bf790 100644 --- a/libs/portal-integration-angular/src/lib/services/portal-api-configuration.service.ts +++ b/libs/portal-integration-angular/src/lib/core/utils/portal-api-configuration.utils.ts @@ -1,8 +1,7 @@ +import { Location } from '@angular/common' import { BehaviorSubject, first, map } from 'rxjs' -import { API_PREFIX } from '../api/constants' -import { CONFIG_KEY } from '../model/config-key.model' -import { AppStateService } from './app-state.service' -import { ConfigurationService } from './configuration.service' +import { AppStateService } from '../../services/app-state.service' +import { ConfigurationService } from '../../services/configuration.service' type Config = { credentials: { [key: string]: string | (() => string | undefined) } @@ -15,7 +14,7 @@ type Config = { export class PortalApiConfiguration { private configuration = this.activator(this.configurationClassOfGenerator) - protected basePath$ = new BehaviorSubject('./' + API_PREFIX) + protected basePath$ = new BehaviorSubject(Location.joinWithSlash('.', this.apiPrefix)) get basePath() { return this.basePath$.value } @@ -32,19 +31,18 @@ export class PortalApiConfiguration { constructor( private configurationClassOfGenerator: unknown, + private apiPrefix: string, configService: ConfigurationService, appStateService: AppStateService ) { - if (configService.getProperty(CONFIG_KEY.IS_SHELL)) { - appStateService.currentMfe$ - .pipe( - first(), - map((currentMfe) => { - return currentMfe.remoteBaseUrl + API_PREFIX - }) - ) - .subscribe(this.basePath$) - } + appStateService.currentMfe$ + .pipe( + first(), + map((currentMfe) => { + return Location.joinWithSlash(currentMfe.remoteBaseUrl, apiPrefix) + }) + ) + .subscribe(this.basePath$) } public selectHeaderContentType(contentTypes: string[]): string | undefined { diff --git a/libs/portal-integration-angular/src/lib/core/utils/app-initializer.utils.ts b/libs/portal-integration-angular/src/lib/core/utils/translate-service-initializer.utils.ts similarity index 76% rename from libs/portal-integration-angular/src/lib/core/utils/app-initializer.utils.ts rename to libs/portal-integration-angular/src/lib/core/utils/translate-service-initializer.utils.ts index 837a1e87..30f6756f 100644 --- a/libs/portal-integration-angular/src/lib/core/utils/app-initializer.utils.ts +++ b/libs/portal-integration-angular/src/lib/core/utils/translate-service-initializer.utils.ts @@ -2,7 +2,7 @@ import { TranslateService } from '@ngx-translate/core' import { firstValueFrom, mergeMap, tap } from 'rxjs' import { UserService } from '../../services/user.service' -export function appInitializer(userService: UserService, translateService: TranslateService): () => Promise { +export function translateServiceInitializer(userService: UserService, translateService: TranslateService): () => Promise { return () => { translateService.setDefaultLang('en') return firstValueFrom( diff --git a/libs/portal-integration-angular/src/lib/services/initialize-module-guard.service.ts b/libs/portal-integration-angular/src/lib/services/initialize-module-guard.service.ts index 47cb3f36..3af1f087 100644 --- a/libs/portal-integration-angular/src/lib/services/initialize-module-guard.service.ts +++ b/libs/portal-integration-angular/src/lib/services/initialize-module-guard.service.ts @@ -26,12 +26,10 @@ export class InitializeModuleGuard implements CanActivate { mergeMap(() => from(this.configService.isInitialized)), mergeMap(() => from(this.appStateService.currentPortal$.isInitialized)), mergeMap(() => { - return this.configService.getProperty(CONFIG_KEY.IS_SHELL) - ? this.appStateService.globalLoading$.pipe( - filter((g) => !g), - map(() => true) - ) - : of(true) + return this.appStateService.globalLoading$.pipe( + filter((g) => !g), + map(() => true) + ) }), map(() => true) ) From ed0e1aa8953382e13aeb80a54fba225998cef110 Mon Sep 17 00:00:00 2001 From: "kim.tran" Date: Wed, 17 Jan 2024 17:02:45 +0100 Subject: [PATCH 11/13] fix: some minor fixes --- .../components/data-view/data-view.component.ts | 5 +---- .../interactive-data-view.component.ts | 16 +--------------- .../portal-page/portal-page.component.spec.ts | 3 --- .../portal-viewport.component.spec.ts | 3 --- .../search-header.component.spec.ts | 5 +---- .../core/utils/create-translate-loader.utils.ts | 2 +- .../services/initialize-module-guard.service.ts | 1 - 7 files changed, 4 insertions(+), 31 deletions(-) diff --git a/libs/portal-integration-angular/src/lib/core/components/data-view/data-view.component.ts b/libs/portal-integration-angular/src/lib/core/components/data-view/data-view.component.ts index 9b970e1f..3e1aaf40 100644 --- a/libs/portal-integration-angular/src/lib/core/components/data-view/data-view.component.ts +++ b/libs/portal-integration-angular/src/lib/core/components/data-view/data-view.component.ts @@ -3,7 +3,6 @@ import { ContentChild, DoCheck, EventEmitter, - Inject, Injector, Input, OnInit, @@ -15,8 +14,6 @@ import { DataListGridComponent, ListGridData } from '../data-list-grid/data-list import { Row, Filter, Sort, DataTableComponent } from '../data-table/data-table.component' import { DataTableColumn } from '../../../model/data-table-column.model' import { DataSortDirection } from '../../../model/data-sort-direction' -import { IAuthService } from '../../../api/iauth.service' -import { AUTH_SERVICE } from '../../../api/injection-tokens' import { DataAction } from '../../../model/data-action' export type RowListGridData = ListGridData & Row @@ -156,7 +153,7 @@ export class DataViewComponent implements DoCheck, OnInit { return this.injector.get('InteractiveDataViewComponent', null)?.deleteItem.observed || this.deleteItem.observed } - constructor(@Inject(AUTH_SERVICE) private authService: IAuthService, private injector: Injector) {} + constructor(private injector: Injector) {} ngOnInit(): void { this.firstColumnId = this.columns[0]?.id } diff --git a/libs/portal-integration-angular/src/lib/core/components/interactive-data-view/interactive-data-view.component.ts b/libs/portal-integration-angular/src/lib/core/components/interactive-data-view/interactive-data-view.component.ts index 0a310012..d33fb25a 100644 --- a/libs/portal-integration-angular/src/lib/core/components/interactive-data-view/interactive-data-view.component.ts +++ b/libs/portal-integration-angular/src/lib/core/components/interactive-data-view/interactive-data-view.component.ts @@ -1,20 +1,8 @@ -import { - Component, - ContentChild, - EventEmitter, - Inject, - Input, - OnInit, - Output, - TemplateRef, - ViewChild, -} from '@angular/core' +import { Component, ContentChild, EventEmitter, Input, OnInit, Output, TemplateRef, ViewChild } from '@angular/core' import { DataTableColumn } from '../../../model/data-table-column.model' import { DataSortDirection } from '../../../model/data-sort-direction' import { Filter, Sort } from '../data-table/data-table.component' import { DataViewComponent, RowListGridData } from '../data-view/data-view.component' -import { AUTH_SERVICE } from '../../../api/injection-tokens' -import { IAuthService } from '../../../api/iauth.service' import { GroupSelectionChangedEvent } from '../column-group-selection/column-group-selection.component' import { ColumnSelectionChangedEvent } from '../custom-group-column-selector/custom-group-column-selector.component' import { DataAction } from '../../../model/data-action' @@ -136,8 +124,6 @@ export class InteractiveDataViewComponent implements OnInit { this._data = value } - constructor(@Inject(AUTH_SERVICE) private authService: IAuthService) {} - ngOnInit(): void { this.selectedGroupKey = this.defaultGroupKey this.displayedColumns = this.columns diff --git a/libs/portal-integration-angular/src/lib/core/components/portal-page/portal-page.component.spec.ts b/libs/portal-integration-angular/src/lib/core/components/portal-page/portal-page.component.spec.ts index 3c21c983..ee67db19 100644 --- a/libs/portal-integration-angular/src/lib/core/components/portal-page/portal-page.component.spec.ts +++ b/libs/portal-integration-angular/src/lib/core/components/portal-page/portal-page.component.spec.ts @@ -1,7 +1,5 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing' import { PortalPageComponent } from './portal-page.component' -import { AUTH_SERVICE } from '../../../api/injection-tokens' -import { MockAuthService } from '../../../mock-auth/mock-auth.service' import { HttpClientModule } from '@angular/common/http' describe('PortalPageComponent', () => { @@ -12,7 +10,6 @@ describe('PortalPageComponent', () => { TestBed.configureTestingModule({ declarations: [PortalPageComponent], imports: [HttpClientModule], - providers: [{ provide: AUTH_SERVICE, useClass: MockAuthService }], }).compileComponents() })) diff --git a/libs/portal-integration-angular/src/lib/core/components/portal-viewport/portal-viewport.component.spec.ts b/libs/portal-integration-angular/src/lib/core/components/portal-viewport/portal-viewport.component.spec.ts index 281f2eec..0cb3903a 100644 --- a/libs/portal-integration-angular/src/lib/core/components/portal-viewport/portal-viewport.component.spec.ts +++ b/libs/portal-integration-angular/src/lib/core/components/portal-viewport/portal-viewport.component.spec.ts @@ -4,8 +4,6 @@ import { PortalViewportComponent } from './portal-viewport.component' import { HttpClientTestingModule } from '@angular/common/http/testing' import { ConfigurationService } from '../../../services/configuration.service' import { MessageService } from 'primeng/api' -import { AUTH_SERVICE } from '../../../api/injection-tokens' -import { MockAuthService } from '../../../mock-auth/mock-auth.service' import { SupportTicketComponent } from '../support-ticket/support-ticket.component' import { HelpItemEditorComponent } from '../help-item-editor/help-item-editor.component' import { HeaderComponent } from '../portal-header/header.component' @@ -78,7 +76,6 @@ describe('PortalViewportComponent', () => { providers: [ ConfigurationService, MessageService, - { provide: AUTH_SERVICE, useClass: MockAuthService }, { provide: ActivatedRoute, useValue: { diff --git a/libs/portal-integration-angular/src/lib/core/components/search-header/search-header.component.spec.ts b/libs/portal-integration-angular/src/lib/core/components/search-header/search-header.component.spec.ts index 5039c557..d43f99f3 100644 --- a/libs/portal-integration-angular/src/lib/core/components/search-header/search-header.component.spec.ts +++ b/libs/portal-integration-angular/src/lib/core/components/search-header/search-header.component.spec.ts @@ -4,8 +4,6 @@ import { TranslateTestingModule } from 'ngx-translate-testing' import { PageHeaderComponent } from '../page-header/page-header.component' import { RouterTestingModule } from '@angular/router/testing' import { ConfigurationService } from '../../../services/configuration.service' -import { AUTH_SERVICE } from '../../../api/injection-tokens' -import { MockAuthService } from '../../../mock-auth/mock-auth.service' import { HttpClientTestingModule } from '@angular/common/http/testing' import { ButtonModule } from 'primeng/button' import { BreadcrumbModule } from 'primeng/breadcrumb' @@ -36,7 +34,6 @@ describe('SearchHeaderComponent', () => { let component: SearchHeaderComponent let fixture: ComponentFixture - const mockService = new MockAuthService() beforeEach(async () => { await TestBed.configureTestingModule({ @@ -48,7 +45,7 @@ describe('SearchHeaderComponent', () => { ButtonModule, BreadcrumbModule, ], - providers: [ConfigurationService, AppStateService, { provide: AUTH_SERVICE, useValue: mockService }], + providers: [ConfigurationService, AppStateService], }).compileComponents() const appStateService = getTestBed().inject(AppStateService) diff --git a/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts b/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts index 9ba6784d..15aa9b26 100644 --- a/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts +++ b/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts @@ -1,7 +1,7 @@ import { HttpClient } from '@angular/common/http' import { TranslateLoader } from '@ngx-translate/core' import { TranslateHttpLoader } from '@ngx-translate/http-loader' -import { combineLatest, filter, first, map, mergeMap, of } from 'rxjs' +import { combineLatest, filter, first, map, mergeMap } from 'rxjs' import { AppStateService } from '../../services/app-state.service' import { ConfigurationService } from '../../services/configuration.service' import { AsyncTranslateLoader } from './async-translate-loader.utils' diff --git a/libs/portal-integration-angular/src/lib/services/initialize-module-guard.service.ts b/libs/portal-integration-angular/src/lib/services/initialize-module-guard.service.ts index 3af1f087..151e975d 100644 --- a/libs/portal-integration-angular/src/lib/services/initialize-module-guard.service.ts +++ b/libs/portal-integration-angular/src/lib/services/initialize-module-guard.service.ts @@ -2,7 +2,6 @@ import { Injectable } from '@angular/core' import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, UrlTree } from '@angular/router' import { TranslateService } from '@ngx-translate/core' import { filter, from, isObservable, map, mergeMap, Observable, of } from 'rxjs' -import { CONFIG_KEY } from '../model/config-key.model' import { AppStateService } from './app-state.service' import { ConfigurationService } from './configuration.service' import { UserService } from './user.service' From ad95c82a042935f46e6dad8962408d05eba9c0b8 Mon Sep 17 00:00:00 2001 From: "kim.tran" Date: Wed, 17 Jan 2024 17:25:20 +0100 Subject: [PATCH 12/13] fix: minor fix in one test --- .../portal-viewport/portal-viewport.component.spec.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/portal-integration-angular/src/lib/core/components/portal-viewport/portal-viewport.component.spec.ts b/libs/portal-integration-angular/src/lib/core/components/portal-viewport/portal-viewport.component.spec.ts index 0cb3903a..619fbe54 100644 --- a/libs/portal-integration-angular/src/lib/core/components/portal-viewport/portal-viewport.component.spec.ts +++ b/libs/portal-integration-angular/src/lib/core/components/portal-viewport/portal-viewport.component.spec.ts @@ -21,6 +21,8 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { TooltipModule } from 'primeng/tooltip' import { TranslateTestingModule } from 'ngx-translate-testing' import { AppStateService } from '../../../services/app-state.service' +import { AUTH_SERVICE } from '../../../api/injection-tokens' +import { MockAuthService } from '../../../mock-auth/mock-auth.service' describe('PortalViewportComponent', () => { const origAddEventListener = window.addEventListener @@ -76,6 +78,7 @@ describe('PortalViewportComponent', () => { providers: [ ConfigurationService, MessageService, + { provide: AUTH_SERVICE, useClass: MockAuthService }, { provide: ActivatedRoute, useValue: { From 02cbb80a75c7f2f11441fef9a0517c34111c87ed Mon Sep 17 00:00:00 2001 From: "kim.tran" Date: Thu, 18 Jan 2024 10:24:10 +0100 Subject: [PATCH 13/13] fix: fix tests and minor fixes --- libs/portal-integration-angular/src/index.ts | 2 +- .../create-translate-loader.utils.spec.ts | 27 +--------------- .../utils/create-translate-loader.utils.ts | 31 ++++++------------- .../translate-service-initializer.utils.ts | 9 ++++-- .../src/lib/services/app-state.service.ts | 6 ---- 5 files changed, 17 insertions(+), 58 deletions(-) diff --git a/libs/portal-integration-angular/src/index.ts b/libs/portal-integration-angular/src/index.ts index 0ee24364..269d0814 100644 --- a/libs/portal-integration-angular/src/index.ts +++ b/libs/portal-integration-angular/src/index.ts @@ -61,7 +61,6 @@ export * from './lib/services/initialize-module-guard.service' export * from './lib/services/userprofile-api.service' export * from './lib/services/portal-dialog.service' export * from './lib/services/user.service' -export * from './lib/core/utils/portal-api-configuration.utils' // pipes export * from './lib/core/pipes/dynamic.pipe' @@ -112,3 +111,4 @@ export * from './lib/core/utils/async-translate-loader.utils' export * from './lib/core/utils/create-translate-loader.utils' export * from './lib/core/utils/add-initialize-module-guard.utils' export * from './lib/core/utils/translate-service-initializer.utils' +export * from './lib/core/utils/portal-api-configuration.utils' diff --git a/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.spec.ts b/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.spec.ts index 9188221e..6f97550b 100644 --- a/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.spec.ts +++ b/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.spec.ts @@ -3,25 +3,19 @@ import { AppStateService } from '../../services/app-state.service' import { createTranslateLoader } from './create-translate-loader.utils' import { MockService } from 'ng-mocks' import { Observable, of } from 'rxjs' -import { Config, MfeInfo } from '@onecx/integration-interface' -import { ConfigurationService } from '../../services/configuration.service' +import { MfeInfo } from '@onecx/integration-interface' describe('CreateTranslateLoader', () => { const httpClientMock = MockService(HttpClient) httpClientMock.get = jest.fn(() => of({})) as any let currentMfe$: Observable> let globalLoading$: Observable - let config$: Observable> const appStateServiceMock = { currentMfe$: { asObservable: () => currentMfe$ }, globalLoading$: { asObservable: () => globalLoading$ }, } - const configurationServiceMock = { - config$: { asObservable: () => config$ }, - } - beforeEach(() => { jest.clearAllMocks() }) @@ -29,11 +23,9 @@ describe('CreateTranslateLoader', () => { it('should call httpClient get 3 times if a remoteBaseUrl is set and if global loading is finished', () => { currentMfe$ = of({ remoteBaseUrl: 'remoteUrl' }) globalLoading$ = of(false) - config$ = of({}) const translateLoader = createTranslateLoader( httpClientMock, (appStateServiceMock), - configurationServiceMock ) translateLoader.getTranslation('en').subscribe() @@ -41,29 +33,12 @@ describe('CreateTranslateLoader', () => { expect(httpClientMock.get).toHaveBeenCalledTimes(3) }) - it('should call httpClient get 2 times if no remoteBaseUrl is set and if global loading is finished', () => { - currentMfe$ = of({}) - globalLoading$ = of(false) - config$ = of() - const translateLoader = createTranslateLoader( - httpClientMock, - (appStateServiceMock), - configurationServiceMock - ) - - translateLoader.getTranslation('en').subscribe() - - expect(httpClientMock.get).toHaveBeenCalledTimes(2) - }) - it('should not call httpClient get if global loading is not finished', () => { currentMfe$ = of({}) globalLoading$ = of(true) - config$ = of({}) const translateLoader = createTranslateLoader( httpClientMock, (appStateServiceMock), - configurationServiceMock ) translateLoader.getTranslation('en').subscribe() diff --git a/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts b/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts index 15aa9b26..7a09e908 100644 --- a/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts +++ b/libs/portal-integration-angular/src/lib/core/utils/create-translate-loader.utils.ts @@ -1,33 +1,20 @@ import { HttpClient } from '@angular/common/http' import { TranslateLoader } from '@ngx-translate/core' import { TranslateHttpLoader } from '@ngx-translate/http-loader' -import { combineLatest, filter, first, map, mergeMap } from 'rxjs' +import { combineLatest, filter, map } from 'rxjs' import { AppStateService } from '../../services/app-state.service' -import { ConfigurationService } from '../../services/configuration.service' import { AsyncTranslateLoader } from './async-translate-loader.utils' import { TranslateCombinedLoader } from './translate.combined.loader' -export function createTranslateLoader( - http: HttpClient, - appStateService: AppStateService, - configService: ConfigurationService -): TranslateLoader { +export function createTranslateLoader(http: HttpClient, appStateService: AppStateService): TranslateLoader { return new AsyncTranslateLoader( - configService.config$.pipe( - first(), - mergeMap(() => { - return combineLatest([ - appStateService.currentMfe$.asObservable(), - appStateService.globalLoading$.asObservable(), - ]).pipe( - filter(([, isLoading]) => !isLoading), - map(([currentMfe]) => { - return new TranslateCombinedLoader( - new TranslateHttpLoader(http, `${currentMfe.remoteBaseUrl}/assets/i18n/`, '.json'), - new TranslateHttpLoader(http, `./assets/i18n/`, '.json'), - new TranslateHttpLoader(http, `./onecx-portal-lib/assets/i18n/`, '.json') - ) - }) + combineLatest([appStateService.currentMfe$.asObservable(), appStateService.globalLoading$.asObservable()]).pipe( + filter(([, isLoading]) => !isLoading), + map(([currentMfe]) => { + return new TranslateCombinedLoader( + new TranslateHttpLoader(http, `${currentMfe.remoteBaseUrl}/assets/i18n/`, '.json'), + new TranslateHttpLoader(http, `./assets/i18n/`, '.json'), + new TranslateHttpLoader(http, `./onecx-portal-lib/assets/i18n/`, '.json') ) }) ) diff --git a/libs/portal-integration-angular/src/lib/core/utils/translate-service-initializer.utils.ts b/libs/portal-integration-angular/src/lib/core/utils/translate-service-initializer.utils.ts index 30f6756f..9dc7419b 100644 --- a/libs/portal-integration-angular/src/lib/core/utils/translate-service-initializer.utils.ts +++ b/libs/portal-integration-angular/src/lib/core/utils/translate-service-initializer.utils.ts @@ -1,14 +1,17 @@ import { TranslateService } from '@ngx-translate/core' -import { firstValueFrom, mergeMap, tap } from 'rxjs' +import { firstValueFrom, mergeMap } from 'rxjs' import { UserService } from '../../services/user.service' -export function translateServiceInitializer(userService: UserService, translateService: TranslateService): () => Promise { +export function translateServiceInitializer( + userService: UserService, + translateService: TranslateService +): () => Promise { return () => { translateService.setDefaultLang('en') return firstValueFrom( userService.lang$.pipe( mergeMap((l) => { - return translateService.use(l).pipe(tap((t) => console.log('RETURN TAP USE ', t))) + return translateService.use(l) }) ) ) diff --git a/libs/portal-integration-angular/src/lib/services/app-state.service.ts b/libs/portal-integration-angular/src/lib/services/app-state.service.ts index 80fdac7c..d107dd00 100644 --- a/libs/portal-integration-angular/src/lib/services/app-state.service.ts +++ b/libs/portal-integration-angular/src/lib/services/app-state.service.ts @@ -12,12 +12,6 @@ import { export class AppStateService implements OnDestroy { globalError$ = new GlobalErrorTopic() globalLoading$ = new GlobalLoadingTopic() - - /** - * Values will only be set in shell mode, but you should not rely on this behavior, - * because it could change in the future. - * To check if you are in shell mode, please use the ConfigurationService - */ currentMfe$ = new CurrentMfeTopic() /**