- + + fxFlex class="mat-toolbar-tools">
@@ -73,7 +73,7 @@ + *ngIf="!hideLoadingBar && (isLoading$ | async)">
diff --git a/ui-ngx/src/app/modules/home/home.component.ts b/ui-ngx/src/app/modules/home/home.component.ts index e83e4ad91e..a18a2150c5 100644 --- a/ui-ngx/src/app/modules/home/home.component.ts +++ b/ui-ngx/src/app/modules/home/home.component.ts @@ -30,6 +30,8 @@ import { MatSidenav } from '@angular/material/sidenav'; import { AuthState } from '@core/auth/auth.models'; import { WINDOW } from '@core/services/window.service'; import { instanceOfSearchableComponent, ISearchableComponent } from '@home/models/searchable-component.models'; +import { ActiveComponentService } from '@core/services/active-component.service'; +import { RouterTabsComponent } from '@home/components/router-tabs.component'; @Component({ selector: 'tb-home', @@ -65,8 +67,11 @@ export class HomeComponent extends PageComponent implements AfterViewInit, OnIni showSearch = false; searchText = ''; + hideLoadingBar = false; + constructor(protected store: Store, @Inject(WINDOW) private window: Window, + private activeComponentService: ActiveComponentService, public breakpointObserver: BreakpointObserver) { super(store); } @@ -133,6 +138,8 @@ export class HomeComponent extends PageComponent implements AfterViewInit, OnIni this.showSearch = false; this.searchText = ''; this.activeComponent = activeComponent; + this.hideLoadingBar = activeComponent && activeComponent instanceof RouterTabsComponent; + this.activeComponentService.setCurrentActiveComponent(activeComponent); if (this.activeComponent && instanceOfSearchableComponent(this.activeComponent)) { this.searchEnabled = true; this.searchableComponent = this.activeComponent; diff --git a/ui-ngx/src/app/modules/home/menu/menu-link.component.html b/ui-ngx/src/app/modules/home/menu/menu-link.component.html index d07dc16b7e..fb79fde48c 100644 --- a/ui-ngx/src/app/modules/home/menu/menu-link.component.html +++ b/ui-ngx/src/app/modules/home/menu/menu-link.component.html @@ -15,8 +15,8 @@ limitations under the License. --> - - {{section.icon}} - + + {{section.icon}} + {{section.name | translate}} diff --git a/ui-ngx/src/app/modules/home/menu/menu-toggle.component.html b/ui-ngx/src/app/modules/home/menu/menu-toggle.component.html index 3cd9922707..e84c7ebd69 100644 --- a/ui-ngx/src/app/modules/home/menu/menu-toggle.component.html +++ b/ui-ngx/src/app/modules/home/menu/menu-toggle.component.html @@ -15,13 +15,12 @@ limitations under the License. --> - - {{section.icon}} - + + {{section.icon}} + {{section.name | translate}} + [ngClass]="{'tb-toggled' : section.opened}">
  • diff --git a/ui-ngx/src/app/modules/home/menu/menu-toggle.component.ts b/ui-ngx/src/app/modules/home/menu/menu-toggle.component.ts index eedc09612b..1d7fb7993b 100644 --- a/ui-ngx/src/app/modules/home/menu/menu-toggle.component.ts +++ b/ui-ngx/src/app/modules/home/menu/menu-toggle.component.ts @@ -17,6 +17,9 @@ import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; import { MenuSection } from '@core/services/menu.models'; import { Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { ActionPreferencesUpdateOpenedMenuSection } from '@core/auth/auth.actions'; @Component({ selector: 'tb-menu-toggle', @@ -28,24 +31,26 @@ export class MenuToggleComponent implements OnInit { @Input() section: MenuSection; - constructor(private router: Router) { + constructor(private router: Router, + private store: Store) { } ngOnInit() { } - sectionActive(): boolean { - return this.router.isActive(this.section.path, false); - } - sectionHeight(): string { - if (this.router.isActive(this.section.path, false)) { + if (this.section.opened) { return this.section.height; } else { return '0px'; } } + toggleSection() { + this.section.opened = !this.section.opened; + this.store.dispatch(new ActionPreferencesUpdateOpenedMenuSection({path: this.section.path, opened: this.section.opened})); + } + trackBySectionPages(index: number, section: MenuSection){ return section.id; } diff --git a/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts b/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts index ea34794a3c..252acf0156 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts @@ -36,6 +36,16 @@ import { QueuesTableConfigResolver } from '@home/pages/admin/queue/queues-table- import { RepositoryAdminSettingsComponent } from '@home/pages/admin/repository-admin-settings.component'; import { AutoCommitAdminSettingsComponent } from '@home/pages/admin/auto-commit-admin-settings.component'; import { TwoFactorAuthSettingsComponent } from '@home/pages/admin/two-factor-auth-settings.component'; +import { WidgetsBundlesTableConfigResolver } from '@home/pages/widget/widgets-bundles-table-config.resolver'; +import { + WidgetEditorAddDataResolver, widgetEditorBreadcumbLabelFunction, + WidgetEditorDataResolver, + WidgetsBundleResolver, + WidgetsTypesDataResolver, widgetTypesBreadcumbLabelFunction +} from '@home/pages/widget/widget-library-routing.module'; +import { WidgetLibraryComponent } from '@home/pages/widget/widget-library.component'; +import { WidgetEditorComponent } from '@home/pages/widget/widget-editor.component'; +import { RouterTabsComponent } from '@home/components/router-tabs.component'; @Injectable() export class OAuth2LoginProcessingUrlResolver implements Resolve { @@ -50,12 +60,12 @@ export class OAuth2LoginProcessingUrlResolver implements Resolve { const routes: Routes = [ { - path: 'settings', + path: 'resources', data: { auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN], breadcrumb: { - label: 'admin.system-settings', - icon: 'settings' + label: 'admin.resources', + icon: 'folder' } }, children: [ @@ -64,99 +74,94 @@ const routes: Routes = [ children: [], data: { auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN], - redirectTo: { - SYS_ADMIN: '/settings/general', - TENANT_ADMIN: '/settings/home' - } - } - }, - { - path: 'general', - component: GeneralSettingsComponent, - canDeactivate: [ConfirmOnExitGuard], - data: { - auth: [Authority.SYS_ADMIN], - title: 'admin.general-settings', - breadcrumb: { - label: 'admin.general', - icon: 'settings_applications' - } + redirectTo: '/resources/widgets-bundles' } }, { - path: 'outgoing-mail', - component: MailServerComponent, - canDeactivate: [ConfirmOnExitGuard], + path: 'widgets-bundles', data: { - auth: [Authority.SYS_ADMIN], - title: 'admin.outgoing-mail-settings', breadcrumb: { - label: 'admin.outgoing-mail', - icon: 'mail' - } - } - }, - { - path: 'sms-provider', - component: SmsProviderComponent, - canDeactivate: [ConfirmOnExitGuard], - data: { - auth: [Authority.SYS_ADMIN], - title: 'admin.sms-provider-settings', - breadcrumb: { - label: 'admin.sms-provider', - icon: 'sms' - } - } - }, - { - path: 'security-settings', - component: SecuritySettingsComponent, - canDeactivate: [ConfirmOnExitGuard], - data: { - auth: [Authority.SYS_ADMIN], - title: 'admin.security-settings', - breadcrumb: { - label: 'admin.security-settings', - icon: 'security' - } - } - }, - { - path: 'oauth2', - component: OAuth2SettingsComponent, - canDeactivate: [ConfirmOnExitGuard], - data: { - auth: [Authority.SYS_ADMIN], - title: 'admin.oauth2.oauth2', - breadcrumb: { - label: 'admin.oauth2.oauth2', - icon: 'security' + label: 'widgets-bundle.widgets-bundles', + icon: 'now_widgets' } }, - resolve: { - loginProcessingUrl: OAuth2LoginProcessingUrlResolver - } - }, - { - path: 'home', - component: HomeSettingsComponent, - canDeactivate: [ConfirmOnExitGuard], - data: { - auth: [Authority.TENANT_ADMIN], - title: 'admin.home-settings', - breadcrumb: { - label: 'admin.home-settings', - icon: 'settings_applications' + children: [ + { + path: '', + component: EntitiesTableComponent, + data: { + auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN], + title: 'widgets-bundle.widgets-bundles' + }, + resolve: { + entitiesTableConfig: WidgetsBundlesTableConfigResolver + } + }, + { + path: ':widgetsBundleId/widgetTypes', + data: { + breadcrumb: { + labelFunction: widgetTypesBreadcumbLabelFunction, + icon: 'now_widgets' + } as BreadCrumbConfig + }, + resolve: { + widgetsBundle: WidgetsBundleResolver + }, + children: [ + { + path: '', + component: WidgetLibraryComponent, + data: { + auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN], + title: 'widget.widget-library' + }, + resolve: { + widgetsData: WidgetsTypesDataResolver + } + }, + { + path: ':widgetTypeId', + component: WidgetEditorComponent, + canDeactivate: [ConfirmOnExitGuard], + data: { + auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN], + title: 'widget.editor', + breadcrumb: { + labelFunction: widgetEditorBreadcumbLabelFunction, + icon: 'insert_chart' + } as BreadCrumbConfig + }, + resolve: { + widgetEditorData: WidgetEditorDataResolver + } + }, + { + path: 'add/:widgetType', + component: WidgetEditorComponent, + canDeactivate: [ConfirmOnExitGuard], + data: { + auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN], + title: 'widget.editor', + breadcrumb: { + labelFunction: widgetEditorBreadcumbLabelFunction, + icon: 'insert_chart' + } as BreadCrumbConfig + }, + resolve: { + widgetEditorData: WidgetEditorAddDataResolver + } + } + ] } - } + ] }, { path: 'resources-library', data: { breadcrumb: { label: 'resource.resources-library', - icon: 'folder' + icon: 'mdi:rhombus-split' } }, children: [ @@ -178,7 +183,7 @@ const routes: Routes = [ data: { breadcrumb: { labelFunction: entityDetailsPageBreadcrumbLabelFunction, - icon: 'folder' + icon: 'mdi:rhombus-split' } as BreadCrumbConfig, auth: [Authority.TENANT_ADMIN, Authority.SYS_ADMIN], title: 'resource.resources-library' @@ -188,6 +193,69 @@ const routes: Routes = [ } } ] + } + ] + }, + { + path: 'settings', + component: RouterTabsComponent, + data: { + auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN], + breadcrumb: { + label: 'admin.system-settings', + icon: 'settings' + } + }, + children: [ + { + path: '', + children: [], + data: { + auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN], + redirectTo: { + SYS_ADMIN: '/settings/general', + TENANT_ADMIN: '/settings/home' + } + } + }, + { + path: 'general', + component: GeneralSettingsComponent, + canDeactivate: [ConfirmOnExitGuard], + data: { + auth: [Authority.SYS_ADMIN], + title: 'admin.general-settings', + breadcrumb: { + label: 'admin.general', + icon: 'settings_applications' + } + } + }, + { + path: 'outgoing-mail', + component: MailServerComponent, + canDeactivate: [ConfirmOnExitGuard], + data: { + auth: [Authority.SYS_ADMIN], + title: 'admin.outgoing-mail-settings', + breadcrumb: { + label: 'admin.outgoing-mail', + icon: 'mail' + } + } + }, + { + path: 'notifications', + component: SmsProviderComponent, + canDeactivate: [ConfirmOnExitGuard], + data: { + auth: [Authority.SYS_ADMIN], + title: 'admin.notifications-settings', + breadcrumb: { + label: 'admin.notifications', + icon: 'mdi:message-badge' + } + } }, { path: 'queues', @@ -228,16 +296,15 @@ const routes: Routes = [ ] }, { - path: '2fa', - component: TwoFactorAuthSettingsComponent, + path: 'home', + component: HomeSettingsComponent, canDeactivate: [ConfirmOnExitGuard], data: { - auth: [Authority.SYS_ADMIN], - title: 'admin.2fa.2fa', + auth: [Authority.TENANT_ADMIN], + title: 'admin.home-settings', breadcrumb: { - label: 'admin.2fa.2fa', - icon: 'mdi:two-factor-authentication', - isMdiIcon: true + label: 'admin.home-settings', + icon: 'settings_applications' } } }, @@ -266,6 +333,98 @@ const routes: Routes = [ icon: 'settings_backup_restore' } } + }, + { + path: 'security-settings', + redirectTo: '/security-settings/general' + }, + { + path: 'oauth2', + redirectTo: '/security-settings/oauth2' + }, + { + path: 'resources-library', + pathMatch: 'full', + redirectTo: '/resources/resources-library' + }, + { + path: 'resources-library/:entityId', + redirectTo: '/resources/resources-library/:entityId' + }, + { + path: '2fa', + redirectTo: '/security-settings/2fa' + }, + { + path: 'sms-provider', + redirectTo: '/settings/notifications' + } + ] + }, + { + path: 'security-settings', + component: RouterTabsComponent, + data: { + auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN], + breadcrumb: { + label: 'security.security', + icon: 'security' + } + }, + children: [ + { + path: '', + children: [], + data: { + auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN], + redirectTo: { + SYS_ADMIN: '/security-settings/general', + TENANT_ADMIN: '/security-settings/audit-logs' + } + } + }, + { + path: 'general', + component: SecuritySettingsComponent, + canDeactivate: [ConfirmOnExitGuard], + data: { + auth: [Authority.SYS_ADMIN], + title: 'admin.general', + breadcrumb: { + label: 'admin.general', + icon: 'settings_applications' + } + } + }, + { + path: '2fa', + component: TwoFactorAuthSettingsComponent, + canDeactivate: [ConfirmOnExitGuard], + data: { + auth: [Authority.SYS_ADMIN], + title: 'admin.2fa.2fa', + breadcrumb: { + label: 'admin.2fa.2fa', + icon: 'mdi:two-factor-authentication', + isMdiIcon: true + } + } + }, + { + path: 'oauth2', + component: OAuth2SettingsComponent, + canDeactivate: [ConfirmOnExitGuard], + data: { + auth: [Authority.SYS_ADMIN], + title: 'admin.oauth2.oauth2', + breadcrumb: { + label: 'admin.oauth2.oauth2', + icon: 'mdi:shield-account' + } + }, + resolve: { + loginProcessingUrl: OAuth2LoginProcessingUrlResolver + } } ] } @@ -277,7 +436,12 @@ const routes: Routes = [ providers: [ OAuth2LoginProcessingUrlResolver, ResourcesLibraryTableConfigResolver, - QueuesTableConfigResolver + QueuesTableConfigResolver, + WidgetsBundlesTableConfigResolver, + WidgetsBundleResolver, + WidgetsTypesDataResolver, + WidgetEditorDataResolver, + WidgetEditorAddDataResolver ] }) export class AdminRoutingModule { } diff --git a/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library-table-config.resolve.ts b/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library-table-config.resolve.ts index da85bde598..a488bd3807 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library-table-config.resolve.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library-table-config.resolve.ts @@ -123,7 +123,7 @@ export class ResourcesLibraryTableConfigResolver implements Resolve
    - admin.sms-provider-settings + admin.notifications-settings
    diff --git a/ui-ngx/src/app/modules/home/pages/home-pages.models.ts b/ui-ngx/src/app/modules/home/pages/home-pages.models.ts index 2d43c56a49..cd6190bb00 100644 --- a/ui-ngx/src/app/modules/home/pages/home-pages.models.ts +++ b/ui-ngx/src/app/modules/home/pages/home-pages.models.ts @@ -19,6 +19,6 @@ import { EntityDetailsPageComponent } from '@home/components/entity/entity-detai export const entityDetailsPageBreadcrumbLabelFunction: BreadCrumbLabelFunction = ((route, translate, component) => { - return component.entity?.name || component.headerSubtitle; + return component.entity?.name; }); diff --git a/ui-ngx/src/app/modules/home/pages/tenant-profile/tenant-profile-tabs.component.html b/ui-ngx/src/app/modules/home/pages/tenant-profile/tenant-profile-tabs.component.html index 62caa10e47..cec78fd60d 100644 --- a/ui-ngx/src/app/modules/home/pages/tenant-profile/tenant-profile-tabs.component.html +++ b/ui-ngx/src/app/modules/home/pages/tenant-profile/tenant-profile-tabs.component.html @@ -36,8 +36,3 @@ label="{{ 'alarm.alarms' | translate }}" #alarmsTab="matTab"> - - - diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-library-routing.module.ts b/ui-ngx/src/app/modules/home/pages/widget/widget-library-routing.module.ts index 974f0f0ae7..46f2379be5 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-library-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-library-routing.module.ts @@ -123,82 +123,22 @@ export const widgetEditorBreadcumbLabelFunction: BreadCrumbLabelFunction - }, - resolve: { - widgetsBundle: WidgetsBundleResolver - }, - children: [ - { - path: '', - component: WidgetLibraryComponent, - data: { - auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN], - title: 'widget.widget-library' - }, - resolve: { - widgetsData: WidgetsTypesDataResolver - } - }, - { - path: ':widgetTypeId', - component: WidgetEditorComponent, - canDeactivate: [ConfirmOnExitGuard], - data: { - auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN], - title: 'widget.editor', - breadcrumb: { - labelFunction: widgetEditorBreadcumbLabelFunction, - icon: 'insert_chart' - } as BreadCrumbConfig - }, - resolve: { - widgetEditorData: WidgetEditorDataResolver - } - }, - { - path: 'add/:widgetType', - component: WidgetEditorComponent, - canDeactivate: [ConfirmOnExitGuard], - data: { - auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN], - title: 'widget.editor', - breadcrumb: { - labelFunction: widgetEditorBreadcumbLabelFunction, - icon: 'insert_chart' - } as BreadCrumbConfig - }, - resolve: { - widgetEditorData: WidgetEditorAddDataResolver - } - } - ] - } - ] + pathMatch: 'full', + redirectTo: '/resources/widgets-bundles' + }, + { + path: 'widgets-bundles/:widgetsBundleId/widgetTypes', + pathMatch: 'full', + redirectTo: '/resources/widgets-bundles/:widgetsBundleId/widgetTypes', + }, + { + path: 'widgets-bundles/:widgetsBundleId/widgetTypes/:widgetTypeId', + pathMatch: 'full', + redirectTo: '/resources/widgets-bundles/:widgetsBundleId/widgetTypes/:widgetTypeId', + }, + { + path: 'widgets-bundles/:widgetsBundleId/widgetTypes/add/:widgetType', + redirectTo: '/resources/widgets-bundles/:widgetsBundleId/widgetTypes/add/:widgetType', } ]; @@ -206,12 +146,6 @@ export const routes: Routes = [ @NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule], - providers: [ - WidgetsBundlesTableConfigResolver, - WidgetsBundleResolver, - WidgetsTypesDataResolver, - WidgetEditorDataResolver, - WidgetEditorAddDataResolver - ] + providers: [] }) export class WidgetLibraryRoutingModule { } diff --git a/ui-ngx/src/app/modules/home/pages/widget/widgets-bundles-table-config.resolver.ts b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundles-table-config.resolver.ts index f501007883..6fd2804ae3 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widgets-bundles-table-config.resolver.ts +++ b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundles-table-config.resolver.ts @@ -160,7 +160,7 @@ export class WidgetsBundlesTableConfigResolver implements Resolve

    - {{ breadcrumb.ignoreTranslate ? (breadcrumb.labelFunction ? breadcrumb.labelFunction() : breadcrumb.label) : (breadcrumb.label | translate) }} + {{ breadcrumb.ignoreTranslate + ? (breadcrumb.labelFunction ? breadcrumb.labelFunction() : utils.customTranslation(breadcrumb.label, breadcrumb.label)) + : (breadcrumb.label | translate) }}

    - - - - {{ breadcrumb.icon }} - - {{ breadcrumb.ignoreTranslate ? (breadcrumb.labelFunction ? breadcrumb.labelFunction() : breadcrumb.label) : (breadcrumb.label | translate) }} + + - - - - {{ breadcrumb.icon }} - - {{ breadcrumb.ignoreTranslate ? (breadcrumb.labelFunction ? breadcrumb.labelFunction() : breadcrumb.label) : (breadcrumb.label | translate) }} + + >
    + + + + + + {{ breadcrumb.icon }} + + {{ breadcrumb.ignoreTranslate + ? (breadcrumb.labelFunction ? breadcrumb.labelFunction() : utils.customTranslation(breadcrumb.label, breadcrumb.label)) + : (breadcrumb.label | translate) }} + diff --git a/ui-ngx/src/app/shared/components/breadcrumb.component.ts b/ui-ngx/src/app/shared/components/breadcrumb.component.ts index df57460eb2..edb11439aa 100644 --- a/ui-ngx/src/app/shared/components/breadcrumb.component.ts +++ b/ui-ngx/src/app/shared/components/breadcrumb.component.ts @@ -18,10 +18,12 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy import { BehaviorSubject, Subject, Subscription } from 'rxjs'; import { BreadCrumb, BreadCrumbConfig } from './breadcrumb'; import { ActivatedRoute, ActivatedRouteSnapshot, NavigationEnd, Router } from '@angular/router'; -import { distinctUntilChanged, filter, map } from 'rxjs/operators'; +import { distinctUntilChanged, filter, map, tap } from 'rxjs/operators'; import { TranslateService } from '@ngx-translate/core'; import { guid } from '@core/utils'; import { BroadcastService } from '@core/services/broadcast.service'; +import { ActiveComponentService } from '@core/services/active-component.service'; +import { UtilsService } from '@core/services/utils.service'; @Component({ selector: 'tb-breadcrumb', @@ -34,8 +36,7 @@ export class BreadcrumbComponent implements OnInit, OnDestroy { activeComponentValue: any; updateBreadcrumbsSubscription: Subscription = null; - @Input() - set activeComponent(activeComponent: any) { + setActiveComponent(activeComponent: any) { if (this.updateBreadcrumbsSubscription) { this.updateBreadcrumbsSubscription.unsubscribe(); this.updateBreadcrumbsSubscription = null; @@ -48,7 +49,7 @@ export class BreadcrumbComponent implements OnInit, OnDestroy { } } - breadcrumbs$: Subject> = new BehaviorSubject>(this.buildBreadCrumbs(this.activatedRoute.snapshot)); + breadcrumbs$: Subject> = new BehaviorSubject>([]); routerEventsSubscription = this.router.events.pipe( filter((event) => event instanceof NavigationEnd ), @@ -56,6 +57,8 @@ export class BreadcrumbComponent implements OnInit, OnDestroy { map( () => this.buildBreadCrumbs(this.activatedRoute.snapshot) ) ).subscribe(breadcrumns => this.breadcrumbs$.next(breadcrumns) ); + activeComponentSubscription = this.activeComponentService.onActiveComponentChanged().subscribe(comp => this.setActiveComponent(comp)); + lastBreadcrumb$ = this.breadcrumbs$.pipe( map( breadcrumbs => breadcrumbs[breadcrumbs.length - 1]) ); @@ -63,20 +66,26 @@ export class BreadcrumbComponent implements OnInit, OnDestroy { constructor(private router: Router, private activatedRoute: ActivatedRoute, private broadcast: BroadcastService, + private activeComponentService: ActiveComponentService, private cd: ChangeDetectorRef, - private translate: TranslateService) { + private translate: TranslateService, + public utils: UtilsService) { } ngOnInit(): void { this.broadcast.on('updateBreadcrumb', () => { this.cd.markForCheck(); }); + this.setActiveComponent(this.activeComponentService.getCurrentActiveComponent()); } ngOnDestroy(): void { if (this.routerEventsSubscription) { this.routerEventsSubscription.unsubscribe(); } + if (this.activeComponentSubscription) { + this.activeComponentSubscription.unsubscribe(); + } } private lastChild(route: ActivatedRouteSnapshot) { @@ -100,9 +109,7 @@ export class BreadcrumbComponent implements OnInit, OnDestroy { let labelFunction; let ignoreTranslate; if (breadcrumbConfig.labelFunction) { - labelFunction = () => { - return breadcrumbConfig.labelFunction(route, this.translate, this.activeComponentValue, lastChild.data); - }; + labelFunction = () => breadcrumbConfig.labelFunction(route, this.translate, this.activeComponentValue, lastChild.data); ignoreTranslate = true; } else { label = breadcrumbConfig.label || 'home.home'; diff --git a/ui-ngx/src/app/shared/models/public-api.ts b/ui-ngx/src/app/shared/models/public-api.ts index b21ad86d59..e2074a5768 100644 --- a/ui-ngx/src/app/shared/models/public-api.ts +++ b/ui-ngx/src/app/shared/models/public-api.ts @@ -48,6 +48,7 @@ export * from './rule-node.models'; export * from './settings.models'; export * from './tenant.model'; export * from './user.model'; +export * from './user-preferences.models'; export * from './widget.models'; export * from './widgets-bundle.model'; export * from './window-message.model'; diff --git a/ui-ngx/src/app/shared/models/user-preferences.models.ts b/ui-ngx/src/app/shared/models/user-preferences.models.ts new file mode 100644 index 0000000000..7d4682967a --- /dev/null +++ b/ui-ngx/src/app/shared/models/user-preferences.models.ts @@ -0,0 +1,23 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +export interface UserPreferences { + openedMenuSections?: string[]; +} + +export const initialUserPreferences: UserPreferences = { + openedMenuSections: [] +}; diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 949ebd4d23..03652d046b 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -404,8 +404,11 @@ "generate-key": "Generate key", "info-header": "All users will be to re-logined", "info-message": "Change of the JWT Signing Key will cause all issued tokens to be invalid. All users will need to re-login. This will also affect scripts that use Rest API/Websockets." - } - }, + }, + "resources": "Resources", + "notifications": "Notifications", + "notifications-settings": "Notifications settings" + }, "alarm": { "alarm": "Alarm", "alarms": "Alarms", diff --git a/ui-ngx/src/assets/mdi.svg b/ui-ngx/src/assets/mdi.svg deleted file mode 100644 index abc8408067..0000000000 --- a/ui-ngx/src/assets/mdi.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index 115348d382..56c8bfccee 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -1701,6 +1701,11 @@ prop-types "^15.7.2" react-is "^16.8.0 || ^17.0.0" +"@mdi/svg@^7.1.96": + version "7.1.96" + resolved "https://registry.yarnpkg.com/@mdi/svg/-/svg-7.1.96.tgz#4911ee6d2f3457f016be8b7a454cf1a8e5c361f0" + integrity sha512-QO+CyF7eZsYBJpyb9Q77r1O6PFdp/Ircx8FMV7+cFS7g0p5rF55PA9zrmzuZqi1LyPKANDpr0oULNLHgeQuXZQ== + "@ngrx/effects@^14.3.3": version "14.3.3" resolved "https://registry.yarnpkg.com/@ngrx/effects/-/effects-14.3.3.tgz#5c9e43e4dc5e1d544f4604fc6a32feec2380c413"