Skip to content

Commit

Permalink
fix: loading of favicon and logo url (#612)
Browse files Browse the repository at this point in the history
* fix: loading of favicon and logo url

* fix: add missing parentheses

* fix: add missing filter if blob undefined, format if statements with curly brackets

* fix: lint issue

---------

Co-authored-by: kim.tran <[email protected]>
  • Loading branch information
KimFFVII and kim.tran authored Nov 19, 2024
1 parent 6d9d8e6 commit 477ab49
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 45 deletions.
4 changes: 2 additions & 2 deletions libs/angular-accelerator/src/lib/directives/src.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ export class SrcDirective {
// ok with content
if (response?.status === 200) {
const url = URL.createObjectURL(response.body as Blob)
this.el.nativeElement.onload = () => {
this.el.nativeElement.addEventListener('load', () => {
URL.revokeObjectURL(url)
}
})
this.el.nativeElement.src = url
}
// no content
Expand Down
3 changes: 3 additions & 0 deletions libs/shell-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ export * from './lib/components/portal-viewport/portal-viewport.component'
export * from './lib/components/error-component/global-error.component'
export * from './lib/services/permissions-cache.service'
export * from './lib/model/constants'

export * from './lib/shell-interface/show-content-provider'
export * from './lib/shell-interface/workspace-config-bff-service-provider'
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
<div class="ml-3 py-2 lg:ml-5 flex flex-wrap align-items-center justify-content-between row-gap-1">
<div class="flex flex-wrap align-items-center justify-content-start gap-3 row-gap-1">
<img
*ngIf="logoUrl$ | async"
*ngIf="logoUrl$ | async as logoUrl"
alt="logo"
class="max-h-1rem"
[ocxSrc]="(logoUrl$ | async) ?? ''"
(error)="onErrorHandleSrc()"
(load)="onLoad(logoUrl)"
/>
<div class="flex-none text-sm">&copy; {{copyrightMsg$ | async}}</div>
<ocx-slot name="onecx-shell-footer"></ocx-slot>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { Component, OnInit } from '@angular/core'
import { Component, Inject, OnInit, Optional } 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'
import { combineLatest, concat, map, Observable, of, withLatestFrom } from 'rxjs'
import { SHELL_BFF_PREFIX } from '../../model/constants'
import { AppStateService, CONFIG_KEY, ConfigurationService, ThemeService } from '@onecx/angular-integration-interface'
import { Observable, combineLatest, concat, filter, map, mergeMap, of, withLatestFrom } from 'rxjs'
import {
WORKSPACE_CONFIG_BFF_SERVICE_PROVIDER,
WorkspaceConfigBffService,
} from '../../shell-interface/workspace-config-bff-service-provider'

@Component({
selector: 'ocx-shell-footer',
Expand All @@ -19,7 +21,10 @@ export class PortalFooterComponent implements OnInit {
private configurationService: ConfigurationService,
public router: Router,
private appState: AppStateService,
private themeService: ThemeService
private themeService: ThemeService,
@Optional()
@Inject(WORKSPACE_CONFIG_BFF_SERVICE_PROVIDER)
public workspaceConfigBffService: WorkspaceConfigBffService | undefined
) {
this.versionInfo$ = this.appState.currentMfe$.pipe(
withLatestFrom(this.appState.currentPortal$.asObservable()),
Expand All @@ -35,7 +40,15 @@ export class PortalFooterComponent implements OnInit {
this.themeService.currentTheme$.asObservable(),
this.appState.currentWorkspace$.asObservable(),
]).pipe(
map(([theme, portalData]) => ImageLogoUrlUtils.createLogoUrl(SHELL_BFF_PREFIX, theme.logoUrl || portalData.logoUrl))
mergeMap(([theme, portalData]) => {
if (!theme.logoUrl && !portalData.logoUrl) {
return (this.workspaceConfigBffService?.getThemeLogoByName(theme.name ?? '') ?? of()).pipe(
filter((blob) => !!blob),
map((blob) => URL.createObjectURL(blob))
)
}
return of(theme.logoUrl || portalData.logoUrl)
})
)
}

Expand All @@ -62,4 +75,10 @@ export class PortalFooterComponent implements OnInit {
public onErrorHandleSrc(): void {
this.logoUrl$ = of(undefined)
}

onLoad(logoUrl: string) {
if (logoUrl.startsWith('blob: ')) {
URL.revokeObjectURL(logoUrl)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
<div class="layout-topbar shadow-4" id="header" role="banner">
<div class="layout-topbar-left">
<a class="layout-topbar-logo">
<img
id="app-logo"
[ocxSrc]="(logoUrl$ | async) ?? ''"
alt="Logo"
style="max-height: 100%; max-width: 100%"
*ngIf="(logoUrl$ | async) && !fallbackImg"
(error)="fallbackImg=true"
/>
<ng-container *ngIf="logoUrl$ | async as logoUrl">
<img
*ngIf="logoUrl && !fallbackImg"
id="app-logo"
[ocxSrc]="logoUrl"
alt="Logo"
style="max-height: 100%; max-width: 100%"
(error)="fallbackImg=true"
(load)="onLoad(logoUrl)"
/>
</ng-container>
<svg *ngIf="((logoUrl$ | async) === null) || fallbackImg" width="160" viewBox="0 0 283 72" class="default-logo">
<defs id="SvgjsDefs4962"></defs>
<g
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { animate, style, transition, trigger } from '@angular/animations'
import { Component, EventEmitter, Input, Output } from '@angular/core'
import { Component, EventEmitter, Inject, Input, Optional, Output } from '@angular/core'
import { UntilDestroy } from '@ngneat/until-destroy'
import { AppStateService, ThemeService } from '@onecx/angular-integration-interface'
import { ImageLogoUrlUtils } from '@onecx/portal-integration-angular'
import { combineLatest, map, Observable } from 'rxjs'
import { SHELL_BFF_PREFIX } from '../../model/constants'
import { Observable, combineLatest, filter, map, mergeMap, of } from 'rxjs'
import {
WORKSPACE_CONFIG_BFF_SERVICE_PROVIDER,
WorkspaceConfigBffService,
} from '../../shell-interface/workspace-config-bff-service-provider'

@Component({
selector: 'ocx-shell-header',
Expand Down Expand Up @@ -39,18 +41,36 @@ export class HeaderComponent {

logoUrl$: Observable<string | undefined>

constructor(private themeService: ThemeService, private appStateService: AppStateService) {
constructor(
private themeService: ThemeService,
private appStateService: AppStateService,
@Optional()
@Inject(WORKSPACE_CONFIG_BFF_SERVICE_PROVIDER)
public workspaceConfigBffService: WorkspaceConfigBffService | undefined
) {
this.logoUrl$ = combineLatest([
this.themeService.currentTheme$.asObservable(),
this.appStateService.currentWorkspace$.asObservable(),
]).pipe(
map(([theme, portal]) => {
return ImageLogoUrlUtils.createLogoUrl(SHELL_BFF_PREFIX, theme.logoUrl || portal.logoUrl)
mergeMap(([theme, portal]) => {
if (!theme.logoUrl && !portal.logoUrl) {
return (this.workspaceConfigBffService?.getThemeLogoByName(theme.name ?? '') ?? of()).pipe(
filter((blob) => !!blob),
map((blob) => URL.createObjectURL(blob))
)
}
return of(theme.logoUrl || portal.logoUrl)
})
)
}

onMenuButtonClick(e: Event) {
this.menuButtonClick.emit(e)
}

onLoad(logoUrl: string) {
if (logoUrl.startsWith('blob: ')) {
URL.revokeObjectURL(logoUrl)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { HttpClient } from '@angular/common/http'
import { Component, HostListener, Inject, InjectionToken, OnDestroy, OnInit, Optional, Renderer2 } from '@angular/core'
import { Component, HostListener, Inject, OnDestroy, OnInit, Optional, Renderer2 } from '@angular/core'
import { Router } from '@angular/router'
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'
import {
Expand All @@ -10,13 +10,12 @@ import {
UserService,
} from '@onecx/angular-integration-interface'
import { MessageService, PrimeNGConfig } from 'primeng/api'
import { BehaviorSubject, filter, first, from, mergeMap, of } from 'rxjs'

export const SHOW_CONTENT_PROVIDER = new InjectionToken<ShowContentProvider>('SHOW_CONTENT_PROVIDER')

export interface ShowContentProvider {
showContent$: BehaviorSubject<boolean>
}
import { filter, first, from, mergeMap, of } from 'rxjs'
import { SHOW_CONTENT_PROVIDER, ShowContentProvider } from '../../shell-interface/show-content-provider'
import {
WORKSPACE_CONFIG_BFF_SERVICE_PROVIDER,
WorkspaceConfigBffService,
} from '../../shell-interface/workspace-config-bff-service-provider'

@Component({
selector: 'ocx-shell-portal-viewport',
Expand Down Expand Up @@ -51,7 +50,10 @@ export class PortalViewportComponent implements OnInit, OnDestroy {
private themeService: ThemeService,
private httpClient: HttpClient,
private router: Router,
@Optional() @Inject(SHOW_CONTENT_PROVIDER) public showContentProvider: ShowContentProvider | undefined
@Optional() @Inject(SHOW_CONTENT_PROVIDER) public showContentProvider: ShowContentProvider | undefined,
@Optional()
@Inject(WORKSPACE_CONFIG_BFF_SERVICE_PROVIDER)
public workspaceConfigBffService: WorkspaceConfigBffService | undefined
) {
this.portalMessageService.message$.subscribe((message: Message) => this.messageService.add(message))
this.userService.profile$.pipe(untilDestroyed(this)).subscribe((profile) => {
Expand All @@ -70,19 +72,22 @@ export class PortalViewportComponent implements OnInit, OnDestroy {
.pipe(
first(),
mergeMap((theme) => {
return theme.faviconUrl
? this.httpClient.get(theme.faviconUrl, { responseType: 'blob' }).pipe(
mergeMap((blob) => {
return from(
new Promise((resolve) => {
const reader = new FileReader()
reader.onload = (e) => resolve(e.target?.result)
reader.readAsDataURL(blob)
})
)
return (
theme.faviconUrl
? this.httpClient.get(theme.faviconUrl ?? '', { responseType: 'blob' })
: (this.workspaceConfigBffService?.getThemeFaviconByName(theme.name ?? '') ?? of())
).pipe(
filter((blob) => !!blob),
mergeMap((blob) => {
return from(
new Promise((resolve) => {
const reader = new FileReader()
reader.onload = (e) => resolve(e.target?.result)
reader.readAsDataURL(blob)
})
)
: of('')
})
)
})
)
.subscribe((url) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { InjectionToken } from "@angular/core"
import { BehaviorSubject } from "rxjs"

export const SHOW_CONTENT_PROVIDER = new InjectionToken<ShowContentProvider>('SHOW_CONTENT_PROVIDER')

export interface ShowContentProvider {
showContent$: BehaviorSubject<boolean>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { HttpContext, HttpResponse, HttpEvent } from '@angular/common/http'
import { InjectionToken } from '@angular/core'
import { Observable } from 'rxjs'

export const WORKSPACE_CONFIG_BFF_SERVICE_PROVIDER = new InjectionToken<WorkspaceConfigBffService>(
'WORKSPACE_CONFIG_BFF_SERVICE_PROVIDER'
)

export interface WorkspaceConfigBffService {
getThemeFaviconByName(
name: string,
observe?: 'body',
reportProgress?: boolean,
options?: { httpHeaderAccept?: 'image/*'; context?: HttpContext }
): Observable<Blob>
getThemeFaviconByName(
name: string,
observe?: 'response',
reportProgress?: boolean,
options?: { httpHeaderAccept?: 'image/*'; context?: HttpContext }
): Observable<HttpResponse<Blob>>
getThemeFaviconByName(
name: string,
observe?: 'events',
reportProgress?: boolean,
options?: { httpHeaderAccept?: 'image/*'; context?: HttpContext }
): Observable<HttpEvent<Blob>>
getThemeFaviconByName(
name: string,
observe: 'body',
reportProgress: false,
options?: { httpHeaderAccept?: 'image/*'; context?: HttpContext }
): Observable<any>

getThemeLogoByName(
name: string,
observe?: 'body',
reportProgress?: boolean,
options?: { httpHeaderAccept?: 'image/*'; context?: HttpContext }
): Observable<Blob>
getThemeLogoByName(
name: string,
observe?: 'response',
reportProgress?: boolean,
options?: { httpHeaderAccept?: 'image/*'; context?: HttpContext }
): Observable<HttpResponse<Blob>>
getThemeLogoByName(
name: string,
observe?: 'events',
reportProgress?: boolean,
options?: { httpHeaderAccept?: 'image/*'; context?: HttpContext }
): Observable<HttpEvent<Blob>>
getThemeLogoByName(
name: string,
observe: 'body',
reportProgress: false,
options?: { httpHeaderAccept?: 'image/*'; context?: HttpContext }
): Observable<any>
}

0 comments on commit 477ab49

Please sign in to comment.