### File

`src/app/dashboard/dashboard.component.ts`

### Implements

`OnInit` `AfterViewInit` `OnDestroy`

### Metadata

providers | `ResourceService` `InstanceService`
selector | `hi-dashboard`
styleUrls | `./dashboard.component.scss`
templateUrl | `./dashboard.component.html`

### Index

###### Properties
Public clusterName Public edges Public instanceToId Public isLoading Public nodes Public resourceToId Public selectedInstance Public selectedResource Public updateInterval Public updateSubscription Public visNetwork Public visNetworkData Public visNetworkOptions
###### Methods
Protected fetchResources initDashboard networkInitialized ngAfterViewInit ngOnDestroy ngOnInit Protected onNodeSelected updateResources

### Constructor

Public `constructor(el: ElementRef, route: ActivatedRoute, visNetworkService: VisNetworkService, resourceService: ResourceService, instanceService: InstanceService, helper: HelperService)`
Defined in src/app/dashboard/dashboard.component.ts:39
Parameters :
Name | Type | Optional
el | `ElementRef` | No
route | `ActivatedRoute` | No
visNetworkService | `VisNetworkService` | No
resourceService | `ResourceService` | No
instanceService | `InstanceService` | No
helper | `HelperService` | No

### Methods

Protected fetchResources
`fetchResources()`
Defined in src/app/dashboard/dashboard.component.ts:162
Returns : `void`

initDashboard
`initDashboard()`
Defined in src/app/dashboard/dashboard.component.ts:129
Returns : `void`

networkInitialized
`networkInitialized()`
Defined in src/app/dashboard/dashboard.component.ts:50
Returns : `void`

ngAfterViewInit
`ngAfterViewInit()`
Defined in src/app/dashboard/dashboard.component.ts:149
Returns : `void`

ngOnDestroy
`ngOnDestroy()`
Defined in src/app/dashboard/dashboard.component.ts:153
Returns : `void`

ngOnInit
`ngOnInit()`
Defined in src/app/dashboard/dashboard.component.ts:81
Returns : `void`

Protected onNodeSelected
`onNodeSelected(id)`
Defined in src/app/dashboard/dashboard.component.ts:224
Parameters :
Name | Optional
id | No
Returns : `void`

updateResources
`updateResources()`
Defined in src/app/dashboard/dashboard.component.ts:209
Returns : `void`

### Properties

Public clusterName
Type : `string`
Defined in src/app/dashboard/dashboard.component.ts:32

Public edges
Type : `Edge[]`
Defined in src/app/dashboard/dashboard.component.ts:30

Public instanceToId
Type : `object`
Default value : `{}`
Defined in src/app/dashboard/dashboard.component.ts:35

Public isLoading
Default value : `false`
Defined in src/app/dashboard/dashboard.component.ts:33

Public nodes
Type : `Node[]`
Defined in src/app/dashboard/dashboard.component.ts:29

Public resourceToId
Type : `object`
Default value : `{}`
Defined in src/app/dashboard/dashboard.component.ts:34

Public selectedInstance
Type : `any`
Defined in src/app/dashboard/dashboard.component.ts:37

Public selectedResource
Type : `any`
Defined in src/app/dashboard/dashboard.component.ts:36

Public updateInterval
Type : `number`
Default value : `3000`
Defined in src/app/dashboard/dashboard.component.ts:39

Public updateSubscription
Type : `Subscription`
Defined in src/app/dashboard/dashboard.component.ts:38

Public visNetwork
Type : `string`
Default value : `'cluster-dashboard'`
Defined in src/app/dashboard/dashboard.component.ts:26

Public visNetworkData
Type : `Data`
Defined in src/app/dashboard/dashboard.component.ts:27

Public visNetworkOptions
Type : `Options`
Defined in src/app/dashboard/dashboard.component.ts:28

    import {
      Component,
      ElementRef,
      OnInit,
      AfterViewInit,
      OnDestroy,
    } from '@angular/core';
    import { ActivatedRoute } from '@angular/router';
    import { Subscription } from 'rxjs';
    import { map } from 'rxjs/operators';

    import _ from 'lodash';
    import { forEach as lodashForEach } from 'lodash';
    import { Data, Edge, Node, Options, VisNetworkService } from 'ngx-vis';

    import { ResourceService } from '../resource/shared/resource.service';
    import { InstanceService } from '../instance/shared/instance.service';
    import { HelperService } from '../shared/helper.service';
    @Component({
      selector: 'hi-dashboard',
      templateUrl: './dashboard.component.html',
      styleUrls: ['./dashboard.component.scss'],
      providers: [ResourceService, InstanceService],
    })
    export class DashboardComponent implements OnInit, AfterViewInit, OnDestroy {
      public visNetwork = 'cluster-dashboard';
      public visNetworkData: Data;
      public visNetworkOptions: Options;
      public nodes: Node[];
      public edges: Edge[];

      public clusterName: string;
      public isLoading = false;
      public resourceToId = {};
      public instanceToId = {};
      public selectedResource: any;
      public selectedInstance: any;
      public updateSubscription: Subscription;
      public updateInterval = 3000;

      public constructor(
        private el: ElementRef,
        private route: ActivatedRoute,
        protected visNetworkService: VisNetworkService,
        protected resourceService: ResourceService,
        protected instanceService: InstanceService,
        protected helper: HelperService
      ) {}

      networkInitialized() {
        this.visNetworkService.on(this.visNetwork, 'click');
        this.visNetworkService.on(this.visNetwork, 'zoom');

        this.visNetworkService.click.subscribe((eventData: any[]) => {
          if (eventData[0] === this.visNetwork) {
            // clear the edges
            this.visNetworkData.edges = [];
            this.selectedResource = null;
            this.selectedInstance = null;

            //
            if (eventData[1].nodes.length) {
              const id = eventData[1].nodes[0];
              this.onNodeSelected(id);
            }
          }
        });

        this.visNetworkService.zoom.subscribe((eventData: any) => {
          if (eventData[0] === this.visNetwork) {
            const scale = eventData[1].scale;
            if (scale == 10) {
              // too big
            } else if (scale < 0.3) {
              // small enough
            }
          }
        });
      }

      ngOnInit() {
        this.nodes = [];
        this.edges = [];
        this.visNetworkData = { nodes: this.nodes, edges: this.edges };
        this.visNetworkOptions = {
          interaction: {
            navigationButtons: true,
            keyboard: true,
          },
          layout: {
            // layout will be the same every time the nodes are settled
            randomSeed: 7,
          },
          physics: {
            // default is barnesHut
            solver: 'forceAtlas2Based',
            forceAtlas2Based: {
              // default: -50
              gravitationalConstant: -30,
              // default: 0
              // avoidOverlap: 0.3
            },
          },
          groups: {
            resource: {
              color: '#7FCAC3',
              shape: 'ellipse',
              widthConstraint: { maximum: 140 },
            },
            instance: {
              color: '#90CAF9',
              shape: 'box',
              widthConstraint: { maximum: 140 },
            },
            instance_bad: {
              color: '#CA7F86',
              shape: 'box',
              widthConstraint: { maximum: 140 },
            },
            partition: {
              color: '#98D4B1',
              shape: 'ellipse',
              widthConstraint: { maximum: 140 },
            },
          },
        };
      }

      initDashboard() {
        // resize container according to the parent
        const width = this.el.nativeElement.offsetWidth;
        const height = this.el.nativeElement.offsetHeight - 36;
        const dashboardDom = this.el.nativeElement.getElementsByClassName(
          this.visNetwork
        )[0];
        dashboardDom.style.width = `${width}px`;
        dashboardDom.style.height = `${height}px`;

        // load data
        if (this.route && this.route.parent) {
          this.route.parent.params.pipe(map((p) => p.name)).subscribe((name) => {
            this.clusterName = name;
            this.fetchResources();
            // this.updateResources();
          });
        }
      }

      ngAfterViewInit() {
        setTimeout((_) => this.initDashboard());
      }

      ngOnDestroy(): void {
        if (this.updateSubscription) {
          this.updateSubscription.unsubscribe();
        }

        this.visNetworkService.off(this.visNetwork, 'zoom');
        this.visNetworkService.off(this.visNetwork, 'click');
      }

      protected fetchResources() {
        this.isLoading = true;

        this.resourceService.getAll(this.clusterName).subscribe(
          (result) => {
            lodashForEach(result, (resource) => {
              const lastId = this.nodes.length;
              const newId = this.nodes.length + 1;
              this.resourceToId[resource.name] = newId;
              (this.visNetworkData.nodes as Node[])[
                this.visNetworkData.nodes.length
              ] = {
                id: newId,
                label: resource.name,
                group: 'resource',
                title: JSON.stringify(resource),
              };
            });

            this.visNetworkService.fit(this.visNetwork);
          },
          (error) => this.helper.showError(error),
          () => (this.isLoading = false)
        );

        this.instanceService.getAll(this.clusterName).subscribe(
          (result) => {
            lodashForEach(result, (instance) => {
              const newId = this.visNetworkData.nodes.length + 1;
              this.instanceToId[instance.name] = newId;
              (this.visNetworkData.nodes as Node[])[
                this.visNetworkData.nodes.length
              ] = {
                id: newId,
                label: instance.name,
                group: instance.healthy ? 'instance' : 'instance_bad',
                title: JSON.stringify(instance),
              };
            });

            this.visNetworkService.fit(this.visNetwork);
          },
          (error) => this.helper.showError(error),
          () => (this.isLoading = false)
        );
      }

      updateResources() {
        /* disable auto-update for now
        this.updateSubscription = Observable
          .interval(this.updateInterval)
          .flatMap(i => this.instanceService.getAll(this.clusterName))*/
        this.instanceService.getAll(this.clusterName).subscribe((result) => {
          _.forEach(result, (instance, index, _collection) => {
            (this.visNetworkData.nodes as Node[])[index] = {
              id: this.instanceToId[instance.name],
              group: instance.healthy ? 'instance' : 'instance_bad',
            };
          });
        });
      }

      protected onNodeSelected(id) {
        const instanceName = _.findKey(this.instanceToId, (value) => value === id);
        if (instanceName) {
          this.selectedInstance = instanceName;
          // fetch relationships
          this.resourceService
            .getAllOnInstance(this.clusterName, instanceName)
            .subscribe(
              (resources) => {
                lodashForEach(resources, (resource) => {
                  (this.visNetworkData.edges as Edge[])[
                    this.visNetworkData.nodes.length
                  ] = {
                    from: id,
                    to: this.resourceToId[resource.name],
                  };
                });
              },
              (error) => this.helper.showError(error)
            );
        } else {
          const resourceName = _.findKey(
            this.resourceToId,
            (value) => value === id
          );
          if (resourceName) {
            this.selectedResource = resourceName;
            this.resourceService.get(this.clusterName, resourceName).subscribe(
              (resource) => {
                _(resource.partitions)
                  .flatMap('replicas')
                  .unionBy('instanceName')
                  .map('instanceName')
                  .forEach((instanceName) => {
                    (this.visNetworkData.edges as Edge[])[
                      this.visNetworkData.nodes.length
                    ] = {
                      from: this.instanceToId[instanceName],
                      to: this.resourceToId[resourceName],
                    };
                  });
              },
              (error) => this.helper.showError(error)
            );
          }
        }
      }
    }

    <!--
      ~ Licensed to the Apache Software Foundation (ASF) under one
      ~ or more contributor license agreements.  See the NOTICE file
      ~ distributed with this work for additional information
      ~ regarding copyright ownership.  The ASF licenses this file
      ~ to you 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.
      -->

    <section fxLayout="column" fxFlex>
      <section
        class="info"
        fxLayout="row"
        fxLayoutAlign="start center"
        fxLayoutGap="10px"
      >
        <div class="oval">Resource</div>
        <div class="rectangle">Instance</div>
        <div class="hint">(Scroll to zoom; Drag to move; Click for details)</div>
        <span fxFlex="1 1 auto"></span>
        <button mat-button (click)="updateResources()">
          <mat-icon>refresh</mat-icon>
          Refresh Status
        </button>
        <button
          mat-button
          *ngIf="selectedResource || selectedInstance"
          color="accent"
          [routerLink]="[
            '../',
            selectedResource ? 'resources' : 'instances',
            selectedResource || selectedInstance
          ]"
        >
          {{ selectedResource || selectedInstance }}
          <mat-icon>arrow_forward</mat-icon>
        </button>
      </section>
      <section
        class="cluster-dashboard"
        [visNetwork]="visNetwork"
        [visNetworkData]="visNetworkData"
        [visNetworkOptions]="visNetworkOptions"
        (initialized)="networkInitialized()"
      ></section>
    </section>

`./dashboard.component.scss`

    :host {
      width: 100%;
      height: 100%;
    }

    .cluster-dashboard {
      width: 800px;
      height: 600px;
    }

    .info {
      font-size: 12px;
      height: 36px;
      background-color: #fff;
      border-bottom: 1px solid #ccc;
      text-align: center;
      vertical-align: middle;
      line-height: 24px;
    }

    .oval {
      width: 80px;
      height: 24px;
      background-color: #7fcac3;
      border: 1px solid #65a19c;
      -moz-border-radius: 80px / 24px;
      -webkit-border-radius: 80px / 24px;
      border-radius: 80px / 24px;
    }

    .rectangle {
      width: 80px;
      height: 24px;
      background-color: #90caf9;
      border: 1px solid #73a1c7;
      -moz-border-radius: 5px;
      -webkit-border-radius: 5px;
      border-radius: 5px;
    }

    .hint {
      color: gray;
    }

Legend
Html element
Component
Html element with directive

# results matching ""

# No results matching ""