summaryrefslogtreecommitdiffstats
path: root/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/breadcrumbs/breadcrumbs.component.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/pybind/mgr/dashboard/frontend/src/app/core/navigation/breadcrumbs/breadcrumbs.component.ts')
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/core/navigation/breadcrumbs/breadcrumbs.component.ts141
1 files changed, 141 insertions, 0 deletions
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/breadcrumbs/breadcrumbs.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/breadcrumbs/breadcrumbs.component.ts
new file mode 100644
index 000000000..d933081ab
--- /dev/null
+++ b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/breadcrumbs/breadcrumbs.component.ts
@@ -0,0 +1,141 @@
+/*
+The MIT License
+
+Copyright (c) 2017 (null) McNull https://github.com/McNull
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+
+import { Component, Injector, OnDestroy } from '@angular/core';
+import { ActivatedRouteSnapshot, NavigationEnd, NavigationStart, Router } from '@angular/router';
+
+import { concat, from, Observable, of, Subscription } from 'rxjs';
+import { distinct, filter, first, mergeMap, toArray } from 'rxjs/operators';
+
+import { BreadcrumbsResolver, IBreadcrumb } from '~/app/shared/models/breadcrumbs';
+
+@Component({
+ selector: 'cd-breadcrumbs',
+ templateUrl: './breadcrumbs.component.html',
+ styleUrls: ['./breadcrumbs.component.scss']
+})
+export class BreadcrumbsComponent implements OnDestroy {
+ crumbs: IBreadcrumb[] = [];
+ /**
+ * Useful for e2e tests.
+ * This allow us to mark the breadcrumb as pending during the navigation from
+ * one page to another.
+ * This resolves the problem of validating the breadcrumb of a new page and
+ * still get the value from the previous
+ */
+ finished = false;
+ subscription: Subscription;
+ private defaultResolver = new BreadcrumbsResolver();
+
+ constructor(private router: Router, private injector: Injector) {
+ this.subscription = this.router.events
+ .pipe(filter((x) => x instanceof NavigationStart))
+ .subscribe(() => {
+ this.finished = false;
+ });
+
+ this.subscription = this.router.events
+ .pipe(filter((x) => x instanceof NavigationEnd))
+ .subscribe(() => {
+ const currentRoot = router.routerState.snapshot.root;
+
+ this._resolveCrumbs(currentRoot)
+ .pipe(
+ mergeMap((x) => x),
+ distinct((x) => x.text),
+ toArray(),
+ mergeMap((x) => {
+ const y = this.postProcess(x);
+ return this.wrapIntoObservable<IBreadcrumb[]>(y).pipe(first());
+ })
+ )
+ .subscribe((x) => {
+ this.finished = true;
+ this.crumbs = x;
+ });
+ });
+ }
+
+ ngOnDestroy(): void {
+ this.subscription.unsubscribe();
+ }
+
+ private _resolveCrumbs(route: ActivatedRouteSnapshot): Observable<IBreadcrumb[]> {
+ let crumbs$: Observable<IBreadcrumb[]>;
+
+ const data = route.routeConfig && route.routeConfig.data;
+
+ if (data && data.breadcrumbs) {
+ let resolver: BreadcrumbsResolver;
+
+ if (data.breadcrumbs.prototype instanceof BreadcrumbsResolver) {
+ resolver = this.injector.get<BreadcrumbsResolver>(data.breadcrumbs);
+ } else {
+ resolver = this.defaultResolver;
+ }
+
+ const result = resolver.resolve(route);
+ crumbs$ = this.wrapIntoObservable<IBreadcrumb[]>(result).pipe(first());
+ } else {
+ crumbs$ = of([]);
+ }
+
+ if (route.firstChild) {
+ crumbs$ = concat<IBreadcrumb[]>(crumbs$, this._resolveCrumbs(route.firstChild));
+ }
+
+ return crumbs$;
+ }
+
+ postProcess(breadcrumbs: IBreadcrumb[]) {
+ const result: IBreadcrumb[] = [];
+ breadcrumbs.forEach((element) => {
+ const split = element.text.split('/');
+ if (split.length > 1) {
+ element.text = split[split.length - 1];
+ for (let i = 0; i < split.length - 1; i++) {
+ result.push({ text: split[i], path: null });
+ }
+ }
+ result.push(element);
+ });
+ return result;
+ }
+
+ isPromise(value: any): boolean {
+ return value && typeof value.then === 'function';
+ }
+
+ wrapIntoObservable<T>(value: T | Promise<T> | Observable<T>): Observable<T> {
+ if (value instanceof Observable) {
+ return value;
+ }
+
+ if (this.isPromise(value)) {
+ return from(Promise.resolve(value));
+ }
+
+ return of(value as T);
+ }
+}