]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/breadcrumbs/breadcrumbs.component.ts
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / core / navigation / breadcrumbs / breadcrumbs.component.ts
1 /*
2 The MIT License
3
4 Copyright (c) 2017 (null) McNull https://github.com/McNull
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 THE SOFTWARE.
23 */
24
25 import { Component, Injector, OnDestroy } from '@angular/core';
26 import { Title } from '@angular/platform-browser';
27 import { ActivatedRouteSnapshot, NavigationEnd, NavigationStart, Router } from '@angular/router';
28
29 import { concat, from, Observable, of, Subscription } from 'rxjs';
30 import { distinct, filter, first, mergeMap, toArray } from 'rxjs/operators';
31
32 import { BreadcrumbsResolver, IBreadcrumb } from '~/app/shared/models/breadcrumbs';
33
34 @Component({
35 selector: 'cd-breadcrumbs',
36 templateUrl: './breadcrumbs.component.html',
37 styleUrls: ['./breadcrumbs.component.scss']
38 })
39 export class BreadcrumbsComponent implements OnDestroy {
40 crumbs: IBreadcrumb[] = [];
41 /**
42 * Useful for e2e tests.
43 * This allow us to mark the breadcrumb as pending during the navigation from
44 * one page to another.
45 * This resolves the problem of validating the breadcrumb of a new page and
46 * still get the value from the previous
47 */
48 finished = false;
49 subscription: Subscription;
50 private defaultResolver = new BreadcrumbsResolver();
51
52 constructor(private router: Router, private injector: Injector, private titleService: Title) {
53 this.subscription = this.router.events
54 .pipe(filter((x) => x instanceof NavigationStart))
55 .subscribe(() => {
56 this.finished = false;
57 });
58
59 this.subscription = this.router.events
60 .pipe(filter((x) => x instanceof NavigationEnd))
61 .subscribe(() => {
62 const currentRoot = router.routerState.snapshot.root;
63
64 this._resolveCrumbs(currentRoot)
65 .pipe(
66 mergeMap((x) => x),
67 distinct((x) => x.text),
68 toArray(),
69 mergeMap((x) => {
70 const y = this.postProcess(x);
71 return this.wrapIntoObservable<IBreadcrumb[]>(y).pipe(first());
72 })
73 )
74 .subscribe((x) => {
75 this.finished = true;
76 this.crumbs = x;
77 const title = this.getTitleFromCrumbs(this.crumbs);
78 this.titleService.setTitle(title);
79 });
80 });
81 }
82
83 ngOnDestroy(): void {
84 this.subscription.unsubscribe();
85 }
86
87 private _resolveCrumbs(route: ActivatedRouteSnapshot): Observable<IBreadcrumb[]> {
88 let crumbs$: Observable<IBreadcrumb[]>;
89
90 const data = route.routeConfig && route.routeConfig.data;
91
92 if (data && data.breadcrumbs) {
93 let resolver: BreadcrumbsResolver;
94
95 if (data.breadcrumbs.prototype instanceof BreadcrumbsResolver) {
96 resolver = this.injector.get<BreadcrumbsResolver>(data.breadcrumbs);
97 } else {
98 resolver = this.defaultResolver;
99 }
100
101 const result = resolver.resolve(route);
102 crumbs$ = this.wrapIntoObservable<IBreadcrumb[]>(result).pipe(first());
103 } else {
104 crumbs$ = of([]);
105 }
106
107 if (route.firstChild) {
108 crumbs$ = concat<IBreadcrumb[]>(crumbs$, this._resolveCrumbs(route.firstChild));
109 }
110
111 return crumbs$;
112 }
113
114 postProcess(breadcrumbs: IBreadcrumb[]) {
115 const result: IBreadcrumb[] = [];
116 breadcrumbs.forEach((element) => {
117 const split = element.text.split('/');
118 if (split.length > 1) {
119 element.text = split[split.length - 1];
120 for (let i = 0; i < split.length - 1; i++) {
121 result.push({ text: split[i], path: null });
122 }
123 }
124 result.push(element);
125 });
126 return result;
127 }
128
129 isPromise(value: any): boolean {
130 return value && typeof value.then === 'function';
131 }
132
133 wrapIntoObservable<T>(value: T | Promise<T> | Observable<T>): Observable<T> {
134 if (value instanceof Observable) {
135 return value;
136 }
137
138 if (this.isPromise(value)) {
139 return from(Promise.resolve(value));
140 }
141
142 return of(value as T);
143 }
144
145 private getTitleFromCrumbs(crumbs: IBreadcrumb[]): string {
146 const currentLocation = crumbs
147 .map((crumb: IBreadcrumb) => {
148 return crumb.text || '';
149 })
150 .join(' > ');
151 if (currentLocation.length > 0) {
152 return `Ceph: ${currentLocation}`;
153 } else {
154 return 'Ceph';
155 }
156 }
157 }