From 26671fe4bfa9f18f5b179b44bf12652f860360c1 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 13 Jun 2026 20:13:26 +0200 Subject: [PATCH] Enable Bull Dashboard in tab --- .../admin-jobs/admin-jobs.component.ts | 23 ------- .../app/components/admin-jobs/admin-jobs.html | 9 --- .../app/pages/admin/admin-page.component.ts | 63 +++++++++++++++++-- .../lib/page-tabs/interfaces/interfaces.ts | 9 ++- .../lib/page-tabs/page-tabs.component.html | 44 ++++++++----- .../src/lib/page-tabs/page-tabs.component.ts | 3 +- 6 files changed, 95 insertions(+), 56 deletions(-) diff --git a/apps/client/src/app/components/admin-jobs/admin-jobs.component.ts b/apps/client/src/app/components/admin-jobs/admin-jobs.component.ts index b4c228881..fd90bff2c 100644 --- a/apps/client/src/app/components/admin-jobs/admin-jobs.component.ts +++ b/apps/client/src/app/components/admin-jobs/admin-jobs.component.ts @@ -1,8 +1,5 @@ -import { TokenStorageService } from '@ghostfolio/client/services/token-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { - BULL_BOARD_COOKIE_NAME, - BULL_BOARD_ROUTE, DATA_GATHERING_QUEUE_PRIORITY_HIGH, DATA_GATHERING_QUEUE_PRIORITY_LOW, DATA_GATHERING_QUEUE_PRIORITY_MEDIUM, @@ -10,7 +7,6 @@ import { } from '@ghostfolio/common/config'; import { getDateWithTimeFormatString } from '@ghostfolio/common/helper'; import { AdminJobs, User } from '@ghostfolio/common/interfaces'; -import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { NotificationService } from '@ghostfolio/ui/notifications'; import { AdminService } from '@ghostfolio/ui/services'; @@ -106,7 +102,6 @@ export class GfAdminJobsComponent implements OnInit { 'actions' ]; - protected hasPermissionToAccessBullBoard = false; protected isLoading = false; protected readonly statusFilterOptions = QUEUE_JOB_STATUS_LIST; @@ -116,7 +111,6 @@ export class GfAdminJobsComponent implements OnInit { private readonly changeDetectorRef = inject(ChangeDetectorRef); private readonly destroyRef = inject(DestroyRef); private readonly notificationService = inject(NotificationService); - private readonly tokenStorageService = inject(TokenStorageService); private readonly userService = inject(UserService); public constructor() { @@ -129,11 +123,6 @@ export class GfAdminJobsComponent implements OnInit { this.defaultDateTimeFormat = getDateWithTimeFormatString( this.user.settings.locale ); - - this.hasPermissionToAccessBullBoard = hasPermission( - this.user.permissions, - permissions.accessAdminControlBullBoard - ); } }); @@ -193,18 +182,6 @@ export class GfAdminJobsComponent implements OnInit { }); } - protected onOpenBullBoard() { - const token = this.tokenStorageService.getToken(); - - document.cookie = [ - `${BULL_BOARD_COOKIE_NAME}=${encodeURIComponent(token)}`, - 'path=/', - 'SameSite=Strict' - ].join('; '); - - window.open(BULL_BOARD_ROUTE, '_blank'); - } - protected onViewData(aData: AdminJobs['jobs'][0]['data']) { this.notificationService.alert({ title: JSON.stringify(aData, null, ' ') diff --git a/apps/client/src/app/components/admin-jobs/admin-jobs.html b/apps/client/src/app/components/admin-jobs/admin-jobs.html index d57704b86..e615db31b 100644 --- a/apps/client/src/app/components/admin-jobs/admin-jobs.html +++ b/apps/client/src/app/components/admin-jobs/admin-jobs.html @@ -1,15 +1,6 @@
- @if (hasPermissionToAccessBullBoard) { -
- -
- } -
diff --git a/apps/client/src/app/pages/admin/admin-page.component.ts b/apps/client/src/app/pages/admin/admin-page.component.ts index b933ff058..fea55b719 100644 --- a/apps/client/src/app/pages/admin/admin-page.component.ts +++ b/apps/client/src/app/pages/admin/admin-page.component.ts @@ -1,10 +1,19 @@ +import { TokenStorageService } from '@ghostfolio/client/services/token-storage.service'; +import { UserService } from '@ghostfolio/client/services/user/user.service'; +import { + BULL_BOARD_COOKIE_NAME, + BULL_BOARD_ROUTE +} from '@ghostfolio/common/config'; +import { User } from '@ghostfolio/common/interfaces'; +import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { internalRoutes } from '@ghostfolio/common/routes/routes'; import { GfPageTabsComponent, TabConfiguration } from '@ghostfolio/ui/page-tabs'; -import { Component, OnInit } from '@angular/core'; +import { Component, inject, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { addIcons } from 'ionicons'; import { flashOutline, @@ -24,7 +33,20 @@ import { export class AdminPageComponent implements OnInit { public tabs: TabConfiguration[] = []; + private user: User; + + private readonly tokenStorageService = inject(TokenStorageService); + private readonly userService = inject(UserService); + public constructor() { + this.userService.stateChanged + .pipe(takeUntilDestroyed()) + .subscribe((state) => { + this.user = state?.user; + + this.initializeTabs(); + }); + addIcons({ flashOutline, peopleOutline, @@ -35,6 +57,15 @@ export class AdminPageComponent implements OnInit { } public ngOnInit() { + this.initializeTabs(); + } + + private initializeTabs() { + const hasPermissionToAccessBullBoard = hasPermission( + this.user?.permissions, + permissions.accessAdminControlBullBoard + ); + this.tabs = [ { iconName: 'reader-outline', @@ -51,11 +82,19 @@ export class AdminPageComponent implements OnInit { label: internalRoutes.adminControl.subRoutes.marketData.title, routerLink: internalRoutes.adminControl.subRoutes.marketData.routerLink }, - { - iconName: 'flash-outline', - label: internalRoutes.adminControl.subRoutes.jobs.title, - routerLink: internalRoutes.adminControl.subRoutes.jobs.routerLink - }, + hasPermissionToAccessBullBoard + ? { + iconName: 'flash-outline', + label: $localize`Job Queue`, + onClick: () => { + this.onOpenBullBoard(); + } + } + : { + iconName: 'flash-outline', + label: internalRoutes.adminControl.subRoutes.jobs.title, + routerLink: internalRoutes.adminControl.subRoutes.jobs.routerLink + }, { iconName: 'people-outline', label: internalRoutes.adminControl.subRoutes.users.title, @@ -63,4 +102,16 @@ export class AdminPageComponent implements OnInit { } ]; } + + private onOpenBullBoard() { + const token = this.tokenStorageService.getToken(); + + document.cookie = [ + `${BULL_BOARD_COOKIE_NAME}=${encodeURIComponent(token)}`, + 'path=/', + 'SameSite=Strict' + ].join('; '); + + window.open(BULL_BOARD_ROUTE, '_blank'); + } } diff --git a/libs/ui/src/lib/page-tabs/interfaces/interfaces.ts b/libs/ui/src/lib/page-tabs/interfaces/interfaces.ts index 7b18b26ec..3d44d2870 100644 --- a/libs/ui/src/lib/page-tabs/interfaces/interfaces.ts +++ b/libs/ui/src/lib/page-tabs/interfaces/interfaces.ts @@ -1,6 +1,11 @@ -export interface TabConfiguration { +interface BaseTabConfiguration { iconName: string; label: string; - routerLink: string[]; showCondition?: boolean; } + +export type TabConfiguration = BaseTabConfiguration & + ( + | { onClick: () => void; routerLink?: never } + | { onClick?: never; routerLink: string[] } + ); diff --git a/libs/ui/src/lib/page-tabs/page-tabs.component.html b/libs/ui/src/lib/page-tabs/page-tabs.component.html index fa9af9b11..4514b329c 100644 --- a/libs/ui/src/lib/page-tabs/page-tabs.component.html +++ b/libs/ui/src/lib/page-tabs/page-tabs.component.html @@ -10,21 +10,35 @@ > @for (tab of tabs(); track tab) { @if (tab.showCondition !== false) { - - -
-
+ @if (tab.onClick) { + + + + } @else { + + + + } } } + + + +
+
diff --git a/libs/ui/src/lib/page-tabs/page-tabs.component.ts b/libs/ui/src/lib/page-tabs/page-tabs.component.ts index 61c2caf05..a6ab9cb18 100644 --- a/libs/ui/src/lib/page-tabs/page-tabs.component.ts +++ b/libs/ui/src/lib/page-tabs/page-tabs.component.ts @@ -1,3 +1,4 @@ +import { NgTemplateOutlet } from '@angular/common'; import { ChangeDetectionStrategy, Component, @@ -13,7 +14,7 @@ import { TabConfiguration } from './interfaces/interfaces'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, - imports: [IonIcon, MatTabsModule, RouterModule], + imports: [IonIcon, MatTabsModule, NgTemplateOutlet, RouterModule], selector: 'gf-page-tabs', styleUrls: ['./page-tabs.component.scss'], templateUrl: './page-tabs.component.html'