]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard_v2: extract cephfs chart into a component
authorTiago Melo <tmelo@suse.com>
Wed, 28 Feb 2018 18:45:49 +0000 (18:45 +0000)
committerTiago Melo <tmelo@suse.com>
Mon, 12 Mar 2018 14:50:11 +0000 (14:50 +0000)
Signed-off-by: Tiago Melo <tmelo@suse.com>
src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.html [new file with mode: 0644]
src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.scss [new file with mode: 0644]
src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.spec.ts [new file with mode: 0644]
src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.ts [new file with mode: 0644]
src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs.module.ts
src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs/cephfs.component.html
src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs/cephfs.component.scss
src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs/cephfs.component.spec.ts
src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs/cephfs.component.ts

diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.html b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.html
new file mode 100644 (file)
index 0000000..b98d708
--- /dev/null
@@ -0,0 +1,12 @@
+<div class="chart-container">
+  <canvas baseChart
+          #chartCanvas
+          [datasets]="chart?.datasets"
+          [options]="chart?.options"
+          [chartType]="chart?.chartType">
+  </canvas>
+  <div class="chartjs-tooltip"
+       #chartTooltip>
+    <table></table>
+  </div>
+</div>
diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.scss b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.scss
new file mode 100644 (file)
index 0000000..23aaa35
--- /dev/null
@@ -0,0 +1,6 @@
+.chart-container {
+  position: relative;
+  margin: auto;
+  height: 500px;
+  width: 100%;
+}
diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.spec.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.spec.ts
new file mode 100644 (file)
index 0000000..6d55204
--- /dev/null
@@ -0,0 +1,29 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ChartsModule } from 'ng2-charts/ng2-charts';
+
+import { CephfsChartComponent } from './cephfs-chart.component';
+
+describe('CephfsChartComponent', () => {
+  let component: CephfsChartComponent;
+  let fixture: ComponentFixture<CephfsChartComponent>;
+
+  beforeEach(
+    async(() => {
+      TestBed.configureTestingModule({
+        imports: [ChartsModule],
+        declarations: [CephfsChartComponent]
+      }).compileComponents();
+    })
+  );
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(CephfsChartComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.ts
new file mode 100644 (file)
index 0000000..fb4a394
--- /dev/null
@@ -0,0 +1,128 @@
+import { Component, Input, OnChanges, OnInit } from '@angular/core';
+
+import * as _ from 'lodash';
+
+@Component({
+  selector: 'cd-cephfs-chart',
+  templateUrl: './cephfs-chart.component.html',
+  styleUrls: ['./cephfs-chart.component.scss']
+})
+export class CephfsChartComponent implements OnChanges, OnInit {
+  @Input() mdsCounter: any;
+
+  lhsCounter = 'mds.inodes';
+  rhsCounter = 'mds_server.handle_client_request';
+
+  chart: any;
+
+  constructor() {}
+
+  ngOnInit() {
+    if (_.isUndefined(this.mdsCounter)) {
+      return;
+    }
+
+    const lhsData = this.convert_timeseries(this.mdsCounter[this.lhsCounter]);
+    const rhsData = this.delta_timeseries(this.mdsCounter[this.rhsCounter]);
+
+    this.chart = {
+      datasets: [
+        {
+          label: this.lhsCounter,
+          yAxisID: 'LHS',
+          data: lhsData,
+          tension: 0.1
+        },
+        {
+          label: this.rhsCounter,
+          yAxisID: 'RHS',
+          data: rhsData,
+          tension: 0.1
+        }
+      ],
+      options: {
+        responsive: true,
+        maintainAspectRatio: false,
+        legend: {
+          position: 'top'
+        },
+        scales: {
+          xAxes: [
+            {
+              position: 'top',
+              type: 'time',
+              time: {
+                displayFormats: {
+                  quarter: 'MMM YYYY'
+                }
+              }
+            }
+          ],
+          yAxes: [
+            {
+              id: 'LHS',
+              type: 'linear',
+              position: 'left',
+              min: 0
+            },
+            {
+              id: 'RHS',
+              type: 'linear',
+              position: 'right',
+              min: 0
+            }
+          ]
+        }
+      },
+      chartType: 'line'
+    };
+  }
+
+  ngOnChanges() {
+    if (!this.chart) {
+      return;
+    }
+
+    const lhsData = this.convert_timeseries(this.mdsCounter[this.lhsCounter]);
+    const rhsData = this.delta_timeseries(this.mdsCounter[this.rhsCounter]);
+
+    this.chart.datasets[0].data = lhsData;
+    this.chart.datasets[1].data = rhsData;
+  }
+
+  // Convert ceph-mgr's time series format (list of 2-tuples
+  // with seconds-since-epoch timestamps) into what chart.js
+  // can handle (list of objects with millisecs-since-epoch
+  // timestamps)
+  convert_timeseries(sourceSeries) {
+    const data = [];
+    _.each(sourceSeries, dp => {
+      data.push({
+        x: dp[0] * 1000,
+        y: dp[1]
+      });
+    });
+
+    return data;
+  }
+
+  delta_timeseries(sourceSeries) {
+    let i;
+    let prev = sourceSeries[0];
+    const result = [];
+    for (i = 1; i < sourceSeries.length; i++) {
+      const cur = sourceSeries[i];
+      const tdelta = cur[0] - prev[0];
+      const vdelta = cur[1] - prev[1];
+      const rate = vdelta / tdelta;
+
+      result.push({
+        x: cur[0] * 1000,
+        y: rate
+      });
+
+      prev = cur;
+    }
+    return result;
+  }
+}
index 2c1432d168ef0615ad9896da7fc20da279e33172..c47051c18e6e3705ec36e8cfe33df52bf7f8f846 100644 (file)
@@ -6,6 +6,7 @@ import { ProgressbarModule } from 'ngx-bootstrap/progressbar';
 
 import { AppRoutingModule } from '../../app-routing.module';
 import { SharedModule } from '../../shared/shared.module';
+import { CephfsChartComponent } from './cephfs-chart/cephfs-chart.component';
 import { CephfsService } from './cephfs.service';
 import { CephfsComponent } from './cephfs/cephfs.component';
 import { ClientsComponent } from './clients/clients.component';
@@ -18,7 +19,7 @@ import { ClientsComponent } from './clients/clients.component';
     ChartsModule,
     ProgressbarModule.forRoot()
   ],
-  declarations: [CephfsComponent, ClientsComponent],
+  declarations: [CephfsComponent, ClientsComponent, CephfsChartComponent],
   providers: [CephfsService]
 })
 export class CephfsModule {}
index 2333f770b66ad3e51a93c55865b729c311eb5704..eb970cec27065ea077d69bb54cf0565c6a92eb0a 100644 (file)
 </div>
 
 <div class="row"
-     *ngFor="let mdsCounter of objectValues(mdsCounters)">
+     *ngFor="let mdsCounter of objectValues(mdsCounters); trackBy: trackByFn">
   <div class="cold-md-12">
-    <div class="chart-container">
-      <canvas baseChart
-              [datasets]="mdsCounter.datasets"
-              [options]="mdsCounter.options"
-              [chartType]="mdsCounter.chartType">
-      </canvas>
-    </div>
+    <cd-cephfs-chart [mdsCounter]="mdsCounter"></cd-cephfs-chart>
   </div>
 </div>
 
index 567fbf3aa159514a238635fc0ee3bffb2469c399..d82829af85c4736324766acec6967d85bc328b44 100644 (file)
@@ -1,10 +1,3 @@
-.chart-container {
-  position: relative;
-  margin: auto;
-  height: 500px;
-  width: 100%;
-}
-
 .progress {
   margin-bottom: 0px;
 }
index 03e5b1ba3bc4ddabcd2161ecbbeeee7c381c2a10..3df655defa6dfb020f670eb94a56626a19ef9dbd 100644 (file)
@@ -6,6 +6,7 @@ import { BsDropdownModule, ProgressbarModule } from 'ngx-bootstrap';
 import { Observable } from 'rxjs/Observable';
 
 import { SharedModule } from '../../../shared/shared.module';
+import { CephfsChartComponent } from '../cephfs-chart/cephfs-chart.component';
 import { CephfsService } from '../cephfs.service';
 import { CephfsComponent } from './cephfs.component';
 
@@ -36,7 +37,7 @@ describe('CephfsComponent', () => {
           BsDropdownModule.forRoot(),
           ProgressbarModule.forRoot()
         ],
-        declarations: [CephfsComponent],
+        declarations: [CephfsComponent, CephfsChartComponent],
         providers: [
           { provide: CephfsService, useValue: fakeFilesystemService }
         ]
index 1cd93f3a9cacc5658e0c99e362ddce0b1d12f64d..d8fe382fec6f9b71b6b009795ec4837dd955fb21 100644 (file)
@@ -2,6 +2,7 @@ import { Component, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/c
 import { ActivatedRoute } from '@angular/router';
 
 import * as _ from 'lodash';
+import { Subscription } from 'rxjs/Subscription';
 
 import { DimlessBinaryPipe } from '../../../shared/pipes/dimless-binary.pipe';
 import { DimlessPipe } from '../../../shared/pipes/dimless.pipe';
@@ -16,15 +17,10 @@ export class CephfsComponent implements OnInit, OnDestroy {
   @ViewChild('poolProgressTmpl') poolProgressTmpl: TemplateRef<any>;
   @ViewChild('activityTmpl') activityTmpl: TemplateRef<any>;
 
-  routeParamsSubscribe: any;
+  routeParamsSubscribe: Subscription;
 
   objectValues = Object.values;
 
-  single: any[];
-  multi: any[];
-
-  view: any[] = [700, 400];
-
   id: number;
   name: string;
   ranks: any;
@@ -34,11 +30,6 @@ export class CephfsComponent implements OnInit, OnDestroy {
 
   mdsCounters = {};
 
-  lhsCounter = 'mds.inodes';
-  rhsCounter = 'mds_server.handle_client_request';
-  charts = {};
-  interval: any;
-
   constructor(
     private route: ActivatedRoute,
     private cephfsService: CephfsService,
@@ -113,119 +104,23 @@ export class CephfsComponent implements OnInit, OnDestroy {
       ];
       this.name = data.cephfs.name;
       this.clientCount = data.cephfs.client_count;
-      this.draw_chart();
     });
-  }
 
-  draw_chart() {
     this.cephfsService.getMdsCounters(this.id).subscribe(data => {
-      const topChart = true;
-
       _.each(this.mdsCounters, (value, key) => {
         if (data[key] === undefined) {
           delete this.mdsCounters[key];
         }
       });
 
-      _.each(data, (mdsData, mdsName) => {
-        const lhsData = this.convert_timeseries(mdsData[this.lhsCounter]);
-        const rhsData = this.delta_timeseries(mdsData[this.rhsCounter]);
-
-        if (this.mdsCounters[mdsName] === undefined) {
-          this.mdsCounters[mdsName] = {
-            datasets: [
-              {
-                label: this.lhsCounter,
-                yAxisID: 'LHS',
-                data: lhsData,
-                tension: 0.1
-              },
-              {
-                label: this.rhsCounter,
-                yAxisID: 'RHS',
-                data: rhsData,
-                tension: 0.1
-              }
-            ],
-            options: {
-              responsive: true,
-              maintainAspectRatio: false,
-              legend: {
-                position: 'top',
-                display: topChart
-              },
-              scales: {
-                xAxes: [
-                  {
-                    position: 'top',
-                    type: 'time',
-                    display: topChart,
-                    time: {
-                      displayFormats: {
-                        quarter: 'MMM YYYY'
-                      }
-                    }
-                  }
-                ],
-                yAxes: [
-                  {
-                    id: 'LHS',
-                    type: 'linear',
-                    position: 'left',
-                    min: 0
-                  },
-                  {
-                    id: 'RHS',
-                    type: 'linear',
-                    position: 'right',
-                    min: 0
-                  }
-                ]
-              }
-            },
-            chartType: 'line'
-          };
-        } else {
-          this.mdsCounters[mdsName].datasets[0].data = lhsData;
-          this.mdsCounters[mdsName].datasets[1].data = rhsData;
-        }
+      _.each(data, (mdsData: any, mdsName) => {
+        mdsData.name = mdsName;
+        this.mdsCounters[mdsName] = mdsData;
       });
     });
   }
 
-  // Convert ceph-mgr's time series format (list of 2-tuples
-  // with seconds-since-epoch timestamps) into what chart.js
-  // can handle (list of objects with millisecs-since-epoch
-  // timestamps)
-  convert_timeseries(sourceSeries) {
-    const data = [];
-    _.each(sourceSeries, dp => {
-      data.push({
-        x: dp[0] * 1000,
-        y: dp[1]
-      });
-    });
-
-    return data;
-  }
-
-  delta_timeseries(sourceSeries) {
-    let i;
-    let prev = sourceSeries[0];
-    const result = [];
-    for (i = 1; i < sourceSeries.length; i++) {
-      const cur = sourceSeries[i];
-      const tdelta = cur[0] - prev[0];
-      const vdelta = cur[1] - prev[1];
-      const rate = vdelta / tdelta;
-
-      result.push({
-        x: cur[0] * 1000,
-        y: rate
-      });
-
-      prev = cur;
-    }
-    return result;
+  trackByFn(index, item) {
+    return item.name;
   }
 }