]> git.proxmox.com Git - ceph.git/blame - ceph/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/crushmap/crushmap.component.ts
import ceph pacific 16.2.5
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / ceph / cluster / crushmap / crushmap.component.ts
CommitLineData
f67539c2 1import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
11fdf7f2 2
9f95a23c
TL
3import {
4 ITreeOptions,
9f95a23c
TL
5 TreeComponent,
6 TreeModel,
e306af50
TL
7 TreeNode,
8 TREE_ACTIONS
f67539c2 9} from '@circlon/angular-tree-component';
b3b6e05e 10import { Observable, Subscription } from 'rxjs';
11fdf7f2 11
b3b6e05e 12import { CrushRuleService } from '~/app/shared/api/crush-rule.service';
f67539c2
TL
13import { Icons } from '~/app/shared/enum/icons.enum';
14import { TimerService } from '~/app/shared/services/timer.service';
11fdf7f2
TL
15
16@Component({
17 selector: 'cd-crushmap',
18 templateUrl: './crushmap.component.html',
19 styleUrls: ['./crushmap.component.scss']
20})
b3b6e05e 21export class CrushmapComponent implements OnDestroy, OnInit {
f67539c2
TL
22 private sub = new Subscription();
23
24 @ViewChild('tree') tree: TreeComponent;
9f95a23c
TL
25
26 icons = Icons;
27 loadingIndicator = true;
28 nodes: any[] = [];
29 treeOptions: ITreeOptions = {
30 useVirtualScroll: true,
adb31ebb 31 nodeHeight: 22,
9f95a23c
TL
32 actionMapping: {
33 mouse: {
34 click: this.onNodeSelected.bind(this)
35 }
36 }
37 };
38
11fdf7f2
TL
39 metadata: any;
40 metadataTitle: string;
9f95a23c 41 metadataKeyMap: { [key: number]: any } = {};
b3b6e05e 42 data$: Observable<object>;
11fdf7f2 43
b3b6e05e 44 constructor(private crushRuleService: CrushRuleService, private timerService: TimerService) {}
11fdf7f2
TL
45
46 ngOnInit() {
f67539c2 47 this.sub = this.timerService
b3b6e05e 48 .get(() => this.crushRuleService.getInfo(), 5000)
f67539c2 49 .subscribe((data: any) => {
b3b6e05e 50 this.loadingIndicator = false;
f67539c2
TL
51 this.nodes = this.abstractTreeData(data);
52 });
53 }
54
55 ngOnDestroy() {
56 this.sub.unsubscribe();
11fdf7f2
TL
57 }
58
9f95a23c 59 private abstractTreeData(data: any): any[] {
b3b6e05e
TL
60 const nodes = data.nodes || [];
61 const rootNodes = data.roots || [];
11fdf7f2
TL
62 const treeNodeMap: { [key: number]: any } = {};
63
64 if (0 === nodes.length) {
9f95a23c
TL
65 return [
66 {
67 name: 'No nodes!'
68 }
69 ];
11fdf7f2
TL
70 }
71
9f95a23c
TL
72 const roots: any[] = [];
73 nodes.reverse().forEach((node: any) => {
b3b6e05e 74 if (rootNodes.includes(node.id)) {
81eedcae
TL
75 roots.push(node.id);
76 }
11fdf7f2
TL
77 treeNodeMap[node.id] = this.generateTreeLeaf(node, treeNodeMap);
78 });
79
81eedcae
TL
80 const children = roots.map((id) => {
81 return treeNodeMap[id];
82 });
83
9f95a23c 84 return children;
11fdf7f2
TL
85 }
86
9f95a23c
TL
87 private generateTreeLeaf(node: any, treeNodeMap: any) {
88 const cdId = node.id;
89 this.metadataKeyMap[cdId] = node;
11fdf7f2 90
9f95a23c 91 const name: string = node.name + ' (' + node.type + ')';
11fdf7f2
TL
92 const status: string = node.status;
93
94 const children: any[] = [];
9f95a23c 95 const resultNode = { name, status, cdId, type: node.type };
11fdf7f2 96 if (node.children) {
9f95a23c 97 node.children.sort().forEach((childId: any) => {
11fdf7f2
TL
98 children.push(treeNodeMap[childId]);
99 });
100
9f95a23c 101 resultNode['children'] = children;
11fdf7f2
TL
102 }
103
9f95a23c
TL
104 return resultNode;
105 }
106
107 onNodeSelected(tree: TreeModel, node: TreeNode) {
108 TREE_ACTIONS.ACTIVATE(tree, node, true);
109 if (node.data.cdId !== undefined) {
110 const { name, type, status, ...remain } = this.metadataKeyMap[node.data.cdId];
111 this.metadata = remain;
112 this.metadataTitle = name + ' (' + type + ')';
113 } else {
114 delete this.metadata;
115 delete this.metadataTitle;
116 }
11fdf7f2
TL
117 }
118
9f95a23c
TL
119 onUpdateData() {
120 this.tree.treeModel.expandAll();
11fdf7f2
TL
121 }
122}