committed by
GitHub
219 changed files with 2011 additions and 1085 deletions
@ -0,0 +1,149 @@ |
|||
///
|
|||
/// Copyright © 2016-2026 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.
|
|||
///
|
|||
|
|||
import { Injectable } from '@angular/core'; |
|||
import { BehaviorSubject, merge, shareReplay, Subject, Subscription } from 'rxjs'; |
|||
import { BreadCrumb, BreadCrumbConfig } from '@shared/components/breadcrumb'; |
|||
import { ActivatedRoute, ActivatedRouteSnapshot, NavigationEnd, Router } from '@angular/router'; |
|||
import { TranslateService } from '@ngx-translate/core'; |
|||
import { MenuService } from '@core/services/menu.service'; |
|||
import { distinctUntilChanged, filter, first, map, switchMap } from 'rxjs/operators'; |
|||
import { MenuSection, menuSectionMap } from '@core/services/menu.models'; |
|||
import { guid } from '@core/utils'; |
|||
import { ActiveComponentService } from '@core/services/active-component.service'; |
|||
import { Store } from '@ngrx/store'; |
|||
import { AppState } from '@core/core.state'; |
|||
import { getCurrentAuthUser } from '@core/auth/auth.selectors'; |
|||
|
|||
@Injectable({ |
|||
providedIn: 'root' |
|||
}) |
|||
export class BreadcrumbService { |
|||
|
|||
private updateBreadcrumbsSubscription: Subscription = null; |
|||
private breadcrumbsSubject: Subject<Array<BreadCrumb>> = new BehaviorSubject<Array<BreadCrumb>>([]); |
|||
private activeComponent: any; |
|||
|
|||
get breadcrumbs$() { |
|||
return this.breadcrumbsSubject.asObservable().pipe(shareReplay(1)); |
|||
} |
|||
|
|||
get lastBreadcrumb$() { |
|||
return this.breadcrumbs$.pipe<BreadCrumb>( |
|||
map( (breadcrumbs: BreadCrumb[]) => breadcrumbs.length ? breadcrumbs[breadcrumbs.length - 1] : null) |
|||
); |
|||
} |
|||
|
|||
constructor(private router: Router, |
|||
private store: Store<AppState>, |
|||
private activatedRoute: ActivatedRoute, |
|||
private translate: TranslateService, |
|||
private menuService: MenuService, |
|||
private activeComponentService: ActiveComponentService) { |
|||
|
|||
merge(this.router.events.pipe( |
|||
filter((event) => event instanceof NavigationEnd ), |
|||
distinctUntilChanged()), this.menuService.availableMenuSections()).pipe( |
|||
switchMap(() => this.menuService.availableMenuSections().pipe(first())), |
|||
map( (sections: MenuSection[]) => this.buildBreadCrumbs(this.activatedRoute.snapshot, sections) ) |
|||
).subscribe((breadcrumbs: BreadCrumb[]) => this.breadcrumbsSubject.next(breadcrumbs) ); |
|||
|
|||
this.activeComponentService.onActiveComponentChanged().subscribe(comp => this.setActiveComponent(comp)); |
|||
} |
|||
|
|||
private setActiveComponent(activeComponent: any) { |
|||
if (this.updateBreadcrumbsSubscription) { |
|||
this.updateBreadcrumbsSubscription.unsubscribe(); |
|||
this.updateBreadcrumbsSubscription = null; |
|||
} |
|||
this.activeComponent = activeComponent; |
|||
if (this.activeComponent) { |
|||
if (this.activeComponent.updateBreadcrumbs) { |
|||
this.updateBreadcrumbsSubscription = this.activeComponent.updateBreadcrumbs.subscribe(() => { |
|||
this.menuService.availableMenuSections().pipe(first()).subscribe((sections: MenuSection[]) => { |
|||
const breadcrumbs = this.buildBreadCrumbs(this.activatedRoute.snapshot, sections); |
|||
this.breadcrumbsSubject.next(breadcrumbs); |
|||
}); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private buildBreadCrumbs(route: ActivatedRouteSnapshot, availableMenuSections: MenuSection[], |
|||
breadcrumbs: Array<BreadCrumb> = [], |
|||
lastChild?: ActivatedRouteSnapshot): Array<BreadCrumb> { |
|||
if (!lastChild) { |
|||
lastChild = this.lastChild(route); |
|||
} |
|||
let newBreadcrumbs = breadcrumbs; |
|||
if (route.routeConfig && route.routeConfig.data) { |
|||
const breadcrumbConfig = route.routeConfig.data.breadcrumb as BreadCrumbConfig<any>; |
|||
if (breadcrumbConfig && !breadcrumbConfig.skip) { |
|||
let labelFunction: () => string; |
|||
let section: MenuSection = null; |
|||
let menuId = breadcrumbConfig.menuId; |
|||
if (!menuId && breadcrumbConfig.menuIdByAuthority) { |
|||
const authority = getCurrentAuthUser(this.store).authority; |
|||
menuId = breadcrumbConfig.menuIdByAuthority[authority]; |
|||
} |
|||
if (menuId) { |
|||
section = availableMenuSections.find(menu => menu.id === menuId); |
|||
if (!section) { |
|||
section = menuSectionMap.get(menuId); |
|||
} |
|||
} |
|||
const label = section?.name || breadcrumbConfig.label || 'home.home'; |
|||
const customTranslate = section?.customTranslate || false; |
|||
if (breadcrumbConfig.labelFunction) { |
|||
labelFunction = () => { |
|||
if (this.activeComponent) { |
|||
try { |
|||
return breadcrumbConfig.labelFunction(route, this.translate, this.activeComponent, lastChild.data); |
|||
} catch { |
|||
return label; |
|||
} |
|||
} else { |
|||
return label; |
|||
} |
|||
} |
|||
} |
|||
const link = [ route.pathFromRoot.map(v => v.url.map(segment => segment.toString()).join('/')).join('/') ]; |
|||
const breadcrumb = { |
|||
id: guid(), |
|||
label, |
|||
customTranslate, |
|||
labelFunction, |
|||
link, |
|||
queryParams: null |
|||
}; |
|||
newBreadcrumbs = [...breadcrumbs, breadcrumb]; |
|||
} |
|||
} |
|||
if (route.firstChild) { |
|||
return this.buildBreadCrumbs(route.firstChild, availableMenuSections, newBreadcrumbs, lastChild); |
|||
} |
|||
return newBreadcrumbs; |
|||
} |
|||
|
|||
private lastChild(route: ActivatedRouteSnapshot) { |
|||
let child = route; |
|||
while (child.firstChild !== null) { |
|||
child = child.firstChild; |
|||
} |
|||
return child; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,70 @@ |
|||
///
|
|||
/// Copyright © 2016-2026 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.
|
|||
///
|
|||
|
|||
import { EventEmitter, Injectable } from '@angular/core'; |
|||
import { ActiveComponentService } from '@core/services/active-component.service'; |
|||
import { BehaviorSubject, Observable, shareReplay, Subject } from 'rxjs'; |
|||
import { distinctUntilChanged } from 'rxjs/operators'; |
|||
import { RouterTabsComponent } from '@home/components/router-tabs.component'; |
|||
import { isDefinedAndNotNull } from '@core/utils'; |
|||
import { PageComponent } from '@shared/components/page.component'; |
|||
|
|||
@Injectable({ |
|||
providedIn: 'root' |
|||
}) |
|||
export class HomeService { |
|||
|
|||
private hideMainToolbarSubject: Subject<boolean> = new BehaviorSubject<boolean>(false); |
|||
private hideLoadingBarSubject: Subject<boolean> = new BehaviorSubject<boolean>(false); |
|||
|
|||
get hideMainToolbar$() { |
|||
return this.hideMainToolbarSubject.asObservable().pipe(distinctUntilChanged(), shareReplay(1)); |
|||
} |
|||
|
|||
get hideLoadingBar$() { |
|||
return this.hideLoadingBarSubject.asObservable().pipe(distinctUntilChanged(), shareReplay(1)); |
|||
} |
|||
|
|||
toggleSideBar = new EventEmitter<void>(); |
|||
|
|||
constructor(private activeComponentService: ActiveComponentService) { |
|||
this.activeComponentService.onActiveComponentChanged().subscribe(activeComponent => { |
|||
Promise.resolve().then(() => { |
|||
this.activeComponentChanged(activeComponent); |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
public setHideMainToolbar(hide: boolean): void { |
|||
Promise.resolve().then(() => { |
|||
this.hideMainToolbarSubject.next(hide); |
|||
}); |
|||
} |
|||
|
|||
private activeComponentChanged(activeComponent: any) { |
|||
this.hideMainToolbarSubject.next(false); |
|||
let hideLoadingBar = false; |
|||
if (activeComponent && activeComponent instanceof RouterTabsComponent |
|||
&& isDefinedAndNotNull(activeComponent.activatedRoute?.snapshot?.data?.showMainLoadingBar)) { |
|||
hideLoadingBar = !activeComponent.activatedRoute.snapshot.data.showMainLoadingBar; |
|||
} else if (activeComponent && activeComponent instanceof PageComponent |
|||
&& isDefinedAndNotNull(activeComponent?.showMainLoadingBar)) { |
|||
hideLoadingBar = !activeComponent.showMainLoadingBar; |
|||
} |
|||
this.hideLoadingBarSubject.next(hideLoadingBar); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
///
|
|||
/// Copyright © 2016-2026 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.
|
|||
///
|
|||
|
|||
import { NgModule } from '@angular/core'; |
|||
import { CommonModule } from '@angular/common'; |
|||
import { SharedModule } from '@app/shared/shared.module'; |
|||
import { GithubBadgeComponent } from '@home/components/github-badge/github-badge.component'; |
|||
|
|||
@NgModule({ |
|||
declarations: |
|||
[ |
|||
GithubBadgeComponent |
|||
], |
|||
imports: [ |
|||
CommonModule, |
|||
SharedModule |
|||
], |
|||
exports: [ |
|||
GithubBadgeComponent |
|||
] |
|||
}) |
|||
export class GithubBadgeModule { } |
|||
@ -0,0 +1,38 @@ |
|||
///
|
|||
/// Copyright © 2016-2026 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.
|
|||
///
|
|||
|
|||
import { NgModule } from '@angular/core'; |
|||
import { CommonModule } from '@angular/common'; |
|||
import { SharedModule } from '@app/shared/shared.module'; |
|||
import { NotificationBellComponent } from '@home/components/notification/notification-bell.component'; |
|||
import { ShowNotificationPopoverComponent } from '@home/components/notification/show-notification-popover.component'; |
|||
|
|||
@NgModule({ |
|||
declarations: |
|||
[ |
|||
NotificationBellComponent, |
|||
ShowNotificationPopoverComponent |
|||
], |
|||
imports: [ |
|||
CommonModule, |
|||
SharedModule |
|||
], |
|||
exports: [ |
|||
NotificationBellComponent, |
|||
ShowNotificationPopoverComponent |
|||
] |
|||
}) |
|||
export class NotificationBellModule { } |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue