From 102b8659eb1cb389c4dc6577d1c195260e1d4892 Mon Sep 17 00:00:00 2001 From: "kim.tran" Date: Fri, 5 Apr 2024 08:54:58 +0200 Subject: [PATCH 1/5] fix: ocxSrc directive with external image url, ocx slots --- .../src/lib/directives/src.directive.ts | 33 ++++++++++++------- .../src/lib/services/app-config-service.ts | 5 ++- .../portal-header/header.component.html | 1 + .../portal-viewport.component.html | 8 ++--- .../portal-viewport.component.scss | 6 ---- 5 files changed, 29 insertions(+), 24 deletions(-) diff --git a/libs/angular-accelerator/src/lib/directives/src.directive.ts b/libs/angular-accelerator/src/lib/directives/src.directive.ts index 7b11454d..c1358349 100644 --- a/libs/angular-accelerator/src/lib/directives/src.directive.ts +++ b/libs/angular-accelerator/src/lib/directives/src.directive.ts @@ -11,18 +11,27 @@ export class SrcDirective { } set ocxSrc(value: string | undefined) { if (value && this._src !== value) { - this.httpClient.get(value, { responseType: 'blob' }).subscribe({ - next: (blob) => { - const url = URL.createObjectURL(blob) - this.el.nativeElement.onload = () => { - URL.revokeObjectURL(url) - } - this.el.nativeElement.src = url - }, - error: () => { - this.el.nativeElement.src = 'error' - }, - }) + try { + if (new URL(value, window.location.origin).origin === window.location.origin) { + this.httpClient.get(value, { responseType: 'blob' }).subscribe({ + next: (blob) => { + const url = URL.createObjectURL(blob) + this.el.nativeElement.onload = () => { + URL.revokeObjectURL(url) + } + this.el.nativeElement.src = url + }, + error: () => { + this.el.nativeElement.src = 'error' + }, + }) + } else { + this.el.nativeElement.src = value + } + } catch (error) { + console.log('Cannot parse URL ', value, error) + this.el.nativeElement.src = value + } this._src = value } } diff --git a/libs/angular-accelerator/src/lib/services/app-config-service.ts b/libs/angular-accelerator/src/lib/services/app-config-service.ts index 4151c533..5772fc53 100644 --- a/libs/angular-accelerator/src/lib/services/app-config-service.ts +++ b/libs/angular-accelerator/src/lib/services/app-config-service.ts @@ -1,3 +1,4 @@ +import { Location } from '@angular/common' import { HttpClient } from '@angular/common/http' import { Injectable } from '@angular/core' import { Config } from '@onecx/integration-interface' @@ -11,7 +12,9 @@ export class AppConfigService { public init(baseUrl: string): Promise { return new Promise((resolve, reject) => { - const loadConfigPromise: Promise = firstValueFrom(this.http.get(baseUrl + 'assets/env.json')) + const loadConfigPromise: Promise = firstValueFrom( + this.http.get(Location.joinWithSlash(baseUrl, 'assets/env.json')) + ) loadConfigPromise .then(async (config) => { diff --git a/libs/shell-core/src/lib/components/portal-header/header.component.html b/libs/shell-core/src/lib/components/portal-header/header.component.html index 7a1db546..90aa15d4 100644 --- a/libs/shell-core/src/lib/components/portal-header/header.component.html +++ b/libs/shell-core/src/lib/components/portal-header/header.component.html @@ -44,6 +44,7 @@
+
    diff --git a/libs/shell-core/src/lib/components/portal-viewport/portal-viewport.component.html b/libs/shell-core/src/lib/components/portal-viewport/portal-viewport.component.html index 0ff4411e..70da7800 100644 --- a/libs/shell-core/src/lib/components/portal-viewport/portal-viewport.component.html +++ b/libs/shell-core/src/lib/components/portal-viewport/portal-viewport.component.html @@ -13,9 +13,7 @@ [menuButtonTitle]="menuButtonTitle" (menuButtonClick)="onMenuButtonClick($event)" > -
    - Horizontal Menu -
    + @@ -23,13 +21,13 @@
    - Announcement Banner + diff --git a/libs/shell-core/src/lib/components/portal-viewport/portal-viewport.component.scss b/libs/shell-core/src/lib/components/portal-viewport/portal-viewport.component.scss index 793a270b..e69de29b 100644 --- a/libs/shell-core/src/lib/components/portal-viewport/portal-viewport.component.scss +++ b/libs/shell-core/src/lib/components/portal-viewport/portal-viewport.component.scss @@ -1,6 +0,0 @@ -.horizontal { - display: flex; - flex-direction: row; - justify-content: flex-end; - align-items: center; -} From fc48738f0d57a4ae2f29d94e01f37dd19796f2a6 Mon Sep 17 00:00:00 2001 From: "kim.tran" Date: Fri, 5 Apr 2024 13:30:14 +0200 Subject: [PATCH 2/5] fix: loading remote component --- .../components/loading/loading.component.ts | 1 - .../page-content/page-content.component.ts | 1 - .../portal-footer/portal-footer.component.ts | 1 - .../user-avatar/user-avatar.component.html | 15 +------- .../user-avatar/user-avatar.component.ts | 38 ++++++++++--------- .../portal-footer/portal-footer.component.ts | 1 - 6 files changed, 22 insertions(+), 35 deletions(-) diff --git a/libs/portal-integration-angular/src/lib/core/components/loading/loading.component.ts b/libs/portal-integration-angular/src/lib/core/components/loading/loading.component.ts index 9f45e6b0..b169e917 100644 --- a/libs/portal-integration-angular/src/lib/core/components/loading/loading.component.ts +++ b/libs/portal-integration-angular/src/lib/core/components/loading/loading.component.ts @@ -1,7 +1,6 @@ import { ChangeDetectionStrategy, Component } from '@angular/core' @Component({ - changeDetection: ChangeDetectionStrategy.OnPush, selector: 'ocx-loading', template: `
    diff --git a/libs/portal-integration-angular/src/lib/core/components/page-content/page-content.component.ts b/libs/portal-integration-angular/src/lib/core/components/page-content/page-content.component.ts index 1b51f42a..c2ec9920 100644 --- a/libs/portal-integration-angular/src/lib/core/components/page-content/page-content.component.ts +++ b/libs/portal-integration-angular/src/lib/core/components/page-content/page-content.component.ts @@ -4,7 +4,6 @@ import { Component, Input } from '@angular/core' selector: 'ocx-page-content', templateUrl: './page-content.component.html', styleUrls: ['./page-content.component.scss'], - // changeDetection: ChangeDetectionStrategy.OnPush, }) export class PageContentComponent { @Input() public styleClass: string | undefined diff --git a/libs/portal-integration-angular/src/lib/core/components/portal-footer/portal-footer.component.ts b/libs/portal-integration-angular/src/lib/core/components/portal-footer/portal-footer.component.ts index 45a66b25..31ca63de 100644 --- a/libs/portal-integration-angular/src/lib/core/components/portal-footer/portal-footer.component.ts +++ b/libs/portal-integration-angular/src/lib/core/components/portal-footer/portal-footer.component.ts @@ -10,7 +10,6 @@ import { ImageLogoUrlUtils } from '../../utils/image-logo-url.utils' selector: 'ocx-footer', templateUrl: './portal-footer.component.html', styleUrls: ['./portal-footer.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, }) export class PortalFooterComponent implements OnInit { copyrightMsg$: Observable | undefined diff --git a/libs/portal-integration-angular/src/lib/core/components/user-avatar/user-avatar.component.html b/libs/portal-integration-angular/src/lib/core/components/user-avatar/user-avatar.component.html index e22138e9..202e7b6a 100644 --- a/libs/portal-integration-angular/src/lib/core/components/user-avatar/user-avatar.component.html +++ b/libs/portal-integration-angular/src/lib/core/components/user-avatar/user-avatar.component.html @@ -1,14 +1,3 @@
    - - avatar - - - - avatar - -
    + avatar +
    \ No newline at end of file diff --git a/libs/portal-integration-angular/src/lib/core/components/user-avatar/user-avatar.component.ts b/libs/portal-integration-angular/src/lib/core/components/user-avatar/user-avatar.component.ts index 88fb288b..444975d2 100644 --- a/libs/portal-integration-angular/src/lib/core/components/user-avatar/user-avatar.component.ts +++ b/libs/portal-integration-angular/src/lib/core/components/user-avatar/user-avatar.component.ts @@ -1,30 +1,32 @@ -import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core' -import { Observable, of } from 'rxjs' +import { Component, Input } from '@angular/core' +import { BehaviorSubject, first, map, Observable, of } from 'rxjs' import { API_PREFIX } from '../../../api/constants' import { UserProfile } from '../../../model/user-profile.model' @Component({ - changeDetection: ChangeDetectionStrategy.OnPush, selector: 'ocx-user-avatar', templateUrl: './user-avatar.component.html', styleUrls: ['./user-avatar.component.scss'], }) -export class UserAvatarComponent implements OnInit { - @Input() user$: Observable | undefined - @Input() user: UserProfile | undefined - - public apiPrefix = API_PREFIX - public placeHolderPath = 'onecx-portal-lib/assets/images/default_avatar.png' - - ngOnInit(): void { - if (this.user) { - this.user$ = of(this.user) - } +export class UserAvatarComponent { + @Input() set user$(value: Observable | undefined) { + value?.pipe(first()).subscribe((user) => (this.user = user)) + } + @Input() set user(value: UserProfile | undefined) { + let newPath = value?.avatar?.smallImageUrl ?? this.placeHolderPath - //if the imageUrl start with a "http", then it is not from the backend. We do not add a prefix. - if (this.user?.avatar?.smallImageUrl && this.user?.avatar?.smallImageUrl.match(/^(http|https)/g)) { - this.apiPrefix = '' - } + this.imagePath$.next(newPath) } + + public placeHolderPath = 'onecx-portal-lib/assets/images/default_avatar.png' + imagePath$ = new BehaviorSubject(this.placeHolderPath) + apiPrefix$ = this.imagePath$.pipe( + map((path) => { + if (path.match(/^(http|https)/g)) { + return '' + } + return API_PREFIX + }) + ) } diff --git a/libs/shell-core/src/lib/components/portal-footer/portal-footer.component.ts b/libs/shell-core/src/lib/components/portal-footer/portal-footer.component.ts index 2d72ca7c..e927948e 100644 --- a/libs/shell-core/src/lib/components/portal-footer/portal-footer.component.ts +++ b/libs/shell-core/src/lib/components/portal-footer/portal-footer.component.ts @@ -9,7 +9,6 @@ import { SHELL_BFF_PREFIX } from '../../model/constants' selector: 'ocx-shell-footer', templateUrl: './portal-footer.component.html', styleUrls: ['./portal-footer.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, }) export class PortalFooterComponent implements OnInit { logoUrl$: Observable From 701f7c1572da4ffe32f76434a89ae50799440409 Mon Sep 17 00:00:00 2001 From: "kim.tran" Date: Fri, 5 Apr 2024 13:34:52 +0200 Subject: [PATCH 3/5] fix: lint issues --- .../src/lib/core/components/loading/loading.component.ts | 2 +- .../components/portal-footer/portal-footer.component.ts | 2 +- .../core/components/user-avatar/user-avatar.component.ts | 6 ++---- .../lib/components/portal-footer/portal-footer.component.ts | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/libs/portal-integration-angular/src/lib/core/components/loading/loading.component.ts b/libs/portal-integration-angular/src/lib/core/components/loading/loading.component.ts index b169e917..72c3b14e 100644 --- a/libs/portal-integration-angular/src/lib/core/components/loading/loading.component.ts +++ b/libs/portal-integration-angular/src/lib/core/components/loading/loading.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core' +import { Component } from '@angular/core' @Component({ selector: 'ocx-loading', diff --git a/libs/portal-integration-angular/src/lib/core/components/portal-footer/portal-footer.component.ts b/libs/portal-integration-angular/src/lib/core/components/portal-footer/portal-footer.component.ts index 31ca63de..2f0daa57 100644 --- a/libs/portal-integration-angular/src/lib/core/components/portal-footer/portal-footer.component.ts +++ b/libs/portal-integration-angular/src/lib/core/components/portal-footer/portal-footer.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core' +import { ChangeDetectorRef, Component, OnInit } from '@angular/core' import { Router } from '@angular/router' import { combineLatest, concat, map, Observable, of, withLatestFrom } from 'rxjs' import { MenuItem } from 'primeng/api' diff --git a/libs/portal-integration-angular/src/lib/core/components/user-avatar/user-avatar.component.ts b/libs/portal-integration-angular/src/lib/core/components/user-avatar/user-avatar.component.ts index 444975d2..9a95ec0e 100644 --- a/libs/portal-integration-angular/src/lib/core/components/user-avatar/user-avatar.component.ts +++ b/libs/portal-integration-angular/src/lib/core/components/user-avatar/user-avatar.component.ts @@ -1,5 +1,5 @@ import { Component, Input } from '@angular/core' -import { BehaviorSubject, first, map, Observable, of } from 'rxjs' +import { BehaviorSubject, first, map, Observable } from 'rxjs' import { API_PREFIX } from '../../../api/constants' import { UserProfile } from '../../../model/user-profile.model' @@ -14,9 +14,7 @@ export class UserAvatarComponent { value?.pipe(first()).subscribe((user) => (this.user = user)) } @Input() set user(value: UserProfile | undefined) { - let newPath = value?.avatar?.smallImageUrl ?? this.placeHolderPath - - this.imagePath$.next(newPath) + this.imagePath$.next(value?.avatar?.smallImageUrl ?? this.placeHolderPath) } public placeHolderPath = 'onecx-portal-lib/assets/images/default_avatar.png' diff --git a/libs/shell-core/src/lib/components/portal-footer/portal-footer.component.ts b/libs/shell-core/src/lib/components/portal-footer/portal-footer.component.ts index e927948e..b8631018 100644 --- a/libs/shell-core/src/lib/components/portal-footer/portal-footer.component.ts +++ b/libs/shell-core/src/lib/components/portal-footer/portal-footer.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core' +import { Component, OnInit } from '@angular/core' import { Router } from '@angular/router' import { AppStateService, ConfigurationService, CONFIG_KEY, ThemeService } from '@onecx/angular-integration-interface' import { ImageLogoUrlUtils } from '@onecx/portal-integration-angular' From 2ae09ac3846778bbbcb20bd6ee29d864d2b3c697 Mon Sep 17 00:00:00 2001 From: "kim.tran" Date: Fri, 5 Apr 2024 17:35:53 +0200 Subject: [PATCH 4/5] fix: componentType may be undefined --- .../src/lib/components/slot/slot.component.ts | 24 +++++++++++-------- .../src/lib/services/slot.service.ts | 4 +++- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/libs/angular-remote-components/src/lib/components/slot/slot.component.ts b/libs/angular-remote-components/src/lib/components/slot/slot.component.ts index a834a677..863e78d1 100644 --- a/libs/angular-remote-components/src/lib/components/slot/slot.component.ts +++ b/libs/angular-remote-components/src/lib/components/slot/slot.component.ts @@ -29,7 +29,9 @@ export class SlotComponent implements OnInit, OnDestroy { subscription: Subscription | undefined components$: - | Observable<{ componentType: Type; remoteComponent: RemoteComponentInfo; permissions: string[] }[]> + | Observable< + { componentType: Type | undefined; remoteComponent: RemoteComponentInfo; permissions: string[] }[] + > | undefined constructor(@Inject(SLOT_SERVICE) private slotService: SlotService) {} @@ -40,16 +42,18 @@ export class SlotComponent implements OnInit, OnDestroy { ([viewContainers, components]) => { if (viewContainers && viewContainers.length === components.length) { components.forEach((componentInfo, i) => { - const componentRef = viewContainers.get(i)?.createComponent(componentInfo.componentType) - if (componentRef && 'ocxInitRemoteComponent' in componentRef.instance) { - ;(componentRef.instance as ocxRemoteComponent).ocxInitRemoteComponent({ - appId: componentInfo.remoteComponent.appId, - productName: componentInfo.remoteComponent.productName, - baseUrl: componentInfo.remoteComponent.baseUrl, - permissions: componentInfo.permissions, - }) + if (componentInfo.componentType) { + const componentRef = viewContainers.get(i)?.createComponent(componentInfo.componentType) + if (componentRef && 'ocxInitRemoteComponent' in componentRef.instance) { + ;(componentRef.instance as ocxRemoteComponent).ocxInitRemoteComponent({ + appId: componentInfo.remoteComponent.appId, + productName: componentInfo.remoteComponent.productName, + baseUrl: componentInfo.remoteComponent.baseUrl, + permissions: componentInfo.permissions, + }) + } + componentRef?.changeDetectorRef.detectChanges() } - componentRef?.changeDetectorRef.detectChanges() }) } } diff --git a/libs/angular-remote-components/src/lib/services/slot.service.ts b/libs/angular-remote-components/src/lib/services/slot.service.ts index a2f56f63..5f4cd32d 100644 --- a/libs/angular-remote-components/src/lib/services/slot.service.ts +++ b/libs/angular-remote-components/src/lib/services/slot.service.ts @@ -9,5 +9,7 @@ export interface SlotService { init(): Promise getComponentsForSlot( slotName: string - ): Observable<{ componentType: Type; remoteComponent: RemoteComponentInfo; permissions: string[] }[]> + ): Observable< + { componentType: Type | undefined; remoteComponent: RemoteComponentInfo; permissions: string[] }[] + > } From 513f1d40d582bd368ded281721844f99dc6f31d1 Mon Sep 17 00:00:00 2001 From: "kim.tran" Date: Thu, 11 Apr 2024 14:05:32 +0200 Subject: [PATCH 5/5] fix: improve permission cache, use of ocxSrc, fix overflow of user avatar menu --- .../src/lib/angular-accelerator.module.ts | 22 ++++++++++--------- .../page-header/page-header.component.html | 2 +- .../user-avatar/user-avatar.component.html | 2 +- .../portal-header/header.component.scss | 4 ++++ .../lib/services/permissions-cache.service.ts | 12 +++++----- 5 files changed, 24 insertions(+), 18 deletions(-) diff --git a/libs/angular-accelerator/src/lib/angular-accelerator.module.ts b/libs/angular-accelerator/src/lib/angular-accelerator.module.ts index 8c0a9ce4..9280740b 100644 --- a/libs/angular-accelerator/src/lib/angular-accelerator.module.ts +++ b/libs/angular-accelerator/src/lib/angular-accelerator.module.ts @@ -1,8 +1,8 @@ import { CommonModule } from '@angular/common' +import { HttpClient } from '@angular/common/http' import { LOCALE_ID, NgModule } from '@angular/core' import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { RouterModule } from '@angular/router' -import { HttpClient } from '@angular/common/http' import { MissingTranslationHandler, MissingTranslationHandlerParams, @@ -20,20 +20,21 @@ import { DataListGridSortingComponent } from './components/data-list-grid-sortin import { DataListGridComponent } from './components/data-list-grid/data-list-grid.component' import { DataTableComponent } from './components/data-table/data-table.component' import { DataViewComponent } from './components/data-view/data-view.component' +import { DiagramComponent } from './components/diagram/diagram.component' +import { GroupByCountDiagramComponent } from './components/group-by-count-diagram/group-by-count-diagram.component' import { InteractiveDataViewComponent } from './components/interactive-data-view/interactive-data-view.component' -import { SearchConfigComponent } from './components/search-config/search-config.component' import { PageHeaderComponent } from './components/page-header/page-header.component' +import { SearchConfigComponent } from './components/search-config/search-config.component' import { SearchHeaderComponent } from './components/search-header/search-header.component' -import { GroupByCountDiagramComponent } from './components/group-by-count-diagram/group-by-count-diagram.component' -import { DiagramComponent } from './components/diagram/diagram.component' -import { DynamicPipe } from './pipes/dynamic.pipe' -import { IfPermissionDirective } from './directives/if-permission.directive' +import { AdvancedDirective } from './directives/advanced.directive' import { IfBreakpointDirective } from './directives/if-breakpoint.directive' +import { IfPermissionDirective } from './directives/if-permission.directive' +import { SrcDirective } from './directives/src.directive' +import { DynamicPipe } from './pipes/dynamic.pipe' import { OcxTimeAgoPipe } from './pipes/ocxtimeago.pipe' -import { createTranslateLoader } from './utils/create-translate-loader.utils' +import { AppConfigService } from './services/app-config-service' import { TranslationCacheService } from './services/translation-cache.service' -import { SrcDirective } from './directives/src.directive' -import { AdvancedDirective } from './directives/advanced.directive' +import { createTranslateLoader } from './utils/create-translate-loader.utils' export class AngularAcceleratorMissingTranslationHandler implements MissingTranslationHandler { handle(params: MissingTranslationHandlerParams) { @@ -82,7 +83,7 @@ export class AngularAcceleratorMissingTranslationHandler implements MissingTrans SrcDirective, OcxTimeAgoPipe, SrcDirective, - AdvancedDirective + AdvancedDirective, ], providers: [ { @@ -92,6 +93,7 @@ export class AngularAcceleratorMissingTranslationHandler implements MissingTrans }, deps: [UserService], }, + AppConfigService, ], exports: [ ColumnGroupSelectionComponent, diff --git a/libs/angular-accelerator/src/lib/components/page-header/page-header.component.html b/libs/angular-accelerator/src/lib/components/page-header/page-header.component.html index e6ad0158..0ccefa05 100644 --- a/libs/angular-accelerator/src/lib/components/page-header/page-header.component.html +++ b/libs/angular-accelerator/src/lib/components/page-header/page-header.component.html @@ -13,7 +13,7 @@
    - Figure image + Figure image
    diff --git a/libs/portal-integration-angular/src/lib/core/components/user-avatar/user-avatar.component.html b/libs/portal-integration-angular/src/lib/core/components/user-avatar/user-avatar.component.html index 202e7b6a..243920fb 100644 --- a/libs/portal-integration-angular/src/lib/core/components/user-avatar/user-avatar.component.html +++ b/libs/portal-integration-angular/src/lib/core/components/user-avatar/user-avatar.component.html @@ -1,3 +1,3 @@
    - avatar + avatar
    \ No newline at end of file diff --git a/libs/shell-core/src/lib/components/portal-header/header.component.scss b/libs/shell-core/src/lib/components/portal-header/header.component.scss index b5ac7c3f..a69d80d3 100644 --- a/libs/shell-core/src/lib/components/portal-header/header.component.scss +++ b/libs/shell-core/src/lib/components/portal-header/header.component.scss @@ -14,3 +14,7 @@ color: var(--logo-color, #12abdb); fill: currentColor; } + +.layout-topbar-items > * { + margin: auto; +} \ No newline at end of file diff --git a/libs/shell-core/src/lib/services/permissions-cache.service.ts b/libs/shell-core/src/lib/services/permissions-cache.service.ts index b3614126..658302b8 100644 --- a/libs/shell-core/src/lib/services/permissions-cache.service.ts +++ b/libs/shell-core/src/lib/services/permissions-cache.service.ts @@ -1,19 +1,19 @@ import { Injectable } from '@angular/core' -import { Observable, of, tap } from 'rxjs' +import { Observable, shareReplay } from 'rxjs' @Injectable({ providedIn: 'root' }) export class PermissionsCacheService { - permissions: Record = {} + permissions: Record> = {} getPermissions( appId: string, productName: string, - cachemissFkt: (appId: string, productName: string) => Observable + cacheMissFkt: (appId: string, productName: string) => Observable ): Observable { const key = appId + '|' + productName - if (this.permissions[key]) { - return of(this.permissions[key]) + if (!this.permissions[key]) { + this.permissions[key] = cacheMissFkt(appId, productName).pipe(shareReplay()) } - return cachemissFkt(appId, productName).pipe(tap((permissions) => (this.permissions[key] = permissions))) + return this.permissions[key] } }