From 65ec74434d6297c50311bdda313732f0460da403 Mon Sep 17 00:00:00 2001 From: Aashish Sharma Date: Tue, 5 Dec 2023 11:28:25 +0530 Subject: [PATCH] mgr/dashboard: increase the number of plottable graphs in charts Fixes: https://tracker.ceph.com/issues/64024 Signed-off-by: Aashish Sharma --- .../dashboard-area-chart.component.html | 27 ++-- .../dashboard-area-chart.component.scss | 9 +- .../dashboard-area-chart.component.spec.ts | 46 +++--- .../dashboard-area-chart.component.ts | 148 ++++++++++-------- .../dashboard/dashboard-v3.component.html | 90 +++++------ .../dashboard/dashboard-v3.component.ts | 20 +-- .../rgw-overview-dashboard.component.html | 16 +- .../rgw-overview-dashboard.component.ts | 10 +- .../src/app/shared/api/prometheus.service.ts | 2 + .../styles/defaults/_bootstrap-defaults.scss | 18 ++- 10 files changed, 196 insertions(+), 190 deletions(-) diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-area-chart/dashboard-area-chart.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-area-chart/dashboard-area-chart.component.html index cebfcf9037810..6151843e4e01d 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-area-chart/dashboard-area-chart.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-area-chart/dashboard-area-chart.component.html @@ -3,29 +3,22 @@
{{ chartTitle }} -
-
-
-
-
{{ label }}: +
+
- {{ currentData || 'N/A' }} {{ currentDataUnits }} -
used of - {{ maxConvertedValue }} {{ maxConvertedValueUnits }} +
{{ data.label }}:
+ {{ data?.currentData || 'N/A' }} {{ data?.currentDataUnits }} +
+ used of {{ maxConvertedValue }} {{ maxConvertedValueUnits }}
-
-
-
-
{{ label2 }}:
-
{{ currentData2 || 'N/A' }} {{ currentDataUnits2 }}
-
-
+
{ beforeEach(() => { fixture = TestBed.createComponent(DashboardAreaChartComponent); component = fixture.componentInstance; - component.data = [ - [1, '110'], - [3, '130'] + component.dataArray = [ + [ + [1, '110'], + [3, '130'] + ], + [ + [2, '120'], + [4, '140'] + ], + [ + [5, '150'], + [6, '160'] + ] ]; + component.labelsArray = ['Read', 'Write', 'Total']; }); it('should create', () => { @@ -43,25 +54,22 @@ describe('DashboardAreaChartComponent', () => { expect(chartElement).toBeTruthy(); }); - it('should have two datasets', () => { - component.data2 = [ - [2, '120'], - [4, '140'] - ]; + it('should have three datasets', () => { + component.ngOnChanges({ dataArray: new SimpleChange(null, component.dataArray, false) }); expect(component.chartData.dataset[0].data).toBeDefined(); expect(component.chartData.dataset[1].data).toBeDefined(); + expect(component.chartData.dataset[2].data).toBeDefined(); }); it('should set label', () => { - component.label = 'Write'; - expect(component.label).toBe('Write'); + component.ngOnChanges({ dataArray: new SimpleChange(null, component.dataArray, false) }); + expect(component.chartData.dataset[0].label).toEqual('Read'); + expect(component.chartData.dataset[1].label).toEqual('Write'); + expect(component.chartData.dataset[2].label).toEqual('Total'); }); it('should transform and update data', () => { - expect(component.chartData.dataset[0].data).toEqual([{ x: 0, y: 0 }]); - - component.ngOnChanges({ data: new SimpleChange(null, component.data, false) }); - + component.ngOnChanges({ dataArray: new SimpleChange(null, component.dataArray, false) }); expect(component.chartData.dataset[0].data).toEqual([ { x: 1000, y: 110 }, { x: 3000, y: 130 } @@ -69,8 +77,8 @@ describe('DashboardAreaChartComponent', () => { }); it('should set currentData to last value', () => { - component.ngOnChanges({ data: new SimpleChange(null, component.data, false) }); - expect(component.currentData).toBe('130'); + component.ngOnChanges({ dataArray: new SimpleChange(null, component.dataArray, false) }); + expect(component.currentChartData.dataset[0].currentData).toBe('130'); }); it('should keep data units consistency', () => { @@ -78,12 +86,8 @@ describe('DashboardAreaChartComponent', () => { setTimeout(() => { fixture.detectChanges(); - component.data = [ - [1, '1100'], - [3, '1300'] - ]; component.dataUnits = 'B'; - component.ngOnChanges({ data: new SimpleChange(null, component.data, false) }); + component.ngOnChanges({ dataArray: new SimpleChange(null, component.dataArray, false) }); expect(component.currentDataUnits).toBe('KiB'); expect(component.chartDataUnits).toBe('KiB'); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-area-chart/dashboard-area-chart.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-area-chart/dashboard-area-chart.component.ts index cbf97691d27dc..4a0d95f5421d1 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-area-chart/dashboard-area-chart.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-area-chart/dashboard-area-chart.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnChanges, SimpleChanges, ViewChild } from '@angular/core'; +import { Component, Input, ViewChild, OnChanges, SimpleChanges } from '@angular/core'; import { CssHelper } from '~/app/shared/classes/css-helper'; import { DimlessBinaryPipe } from '~/app/shared/pipes/dimless-binary.pipe'; @@ -24,26 +24,48 @@ export class DashboardAreaChartComponent implements OnChanges { @Input() dataUnits: string; @Input() - data: Array<[number, string]>; + dataArray?: Array>; // Array of query results @Input() - data2?: Array<[number, string]>; - @Input() - label: string; - @Input() - label2?: string; + labelsArray?: string[] = []; // Array of chart labels @Input() decimals?: number = 1; currentDataUnits: string; currentData: number; - currentDataUnits2?: string; - currentData2?: number; maxConvertedValue?: number; maxConvertedValueUnits?: string; chartDataUnits: string; - chartData: any; - options: any; + chartData: any = { dataset: [] }; + options: any = {}; + currentChartData: any = {}; + + chartColors: any[] = [ + [ + this.cssHelper.propertyValue('chart-color-strong-blue'), + this.cssHelper.propertyValue('chart-color-translucent-blue') + ], + [ + this.cssHelper.propertyValue('chart-color-orange'), + this.cssHelper.propertyValue('chart-color-translucent-orange') + ], + [ + this.cssHelper.propertyValue('chart-color-green'), + this.cssHelper.propertyValue('chart-color-translucent-green') + ], + [ + this.cssHelper.propertyValue('chart-color-cyan'), + this.cssHelper.propertyValue('chart-color-translucent-cyan') + ], + [ + this.cssHelper.propertyValue('chart-color-purple'), + this.cssHelper.propertyValue('chart-color-translucent-purple') + ], + [ + this.cssHelper.propertyValue('chart-color-red'), + this.cssHelper.propertyValue('chart-color-translucent-red') + ] + ]; public chartAreaBorderPlugin: any[] = [ { @@ -74,35 +96,6 @@ export class DashboardAreaChartComponent implements OnChanges { private formatter: FormatterService, private numberFormatter: NumberFormatterService ) { - this.chartData = { - dataset: [ - { - label: '', - data: [{ x: 0, y: 0 }], - tension: 0.2, - pointBackgroundColor: this.cssHelper.propertyValue('chart-color-strong-blue'), - backgroundColor: this.cssHelper.propertyValue('chart-color-translucent-blue'), - borderColor: this.cssHelper.propertyValue('chart-color-strong-blue'), - borderWidth: 1, - fill: { - target: 'origin' - } - }, - { - label: '', - data: [], - tension: 0.2, - pointBackgroundColor: this.cssHelper.propertyValue('chart-color-orange'), - backgroundColor: this.cssHelper.propertyValue('chart-color-translucent-yellow'), - borderColor: this.cssHelper.propertyValue('chart-color-orange'), - borderWidth: 1, - fill: { - target: 'origin' - } - } - ] - }; - this.options = { plugins: { legend: { @@ -179,27 +172,50 @@ export class DashboardAreaChartComponent implements OnChanges { this.updateChartData(changes); } + ngAfterViewInit() { + this.updateChartData(null); + } + private updateChartData(changes: SimpleChanges): void { - this.chartData.dataset[0].label = this.label; - this.chartData.dataset[1].label = this.label2; - this.setChartTicks(); - if (changes.data && changes.data.currentValue) { - this.data = changes.data.currentValue; - this.chartData.dataset[0].data = this.formatData(this.data); - [this.currentData, this.currentDataUnits] = this.convertUnits( - this.data[this.data.length - 1][1] - ).split(' '); - [this.maxConvertedValue, this.maxConvertedValueUnits] = this.convertUnits( - this.maxValue - ).split(' '); + for (let index = 0; index < this.labelsArray.length; index++) { + const colorIndex = index % this.chartColors.length; + this.chartData.dataset[index] = { + label: '', + data: [], + tension: 0.2, + pointBackgroundColor: this.chartColors[colorIndex][0], + backgroundColor: this.chartColors[colorIndex][1], + borderColor: this.chartColors[colorIndex][0], + borderWidth: 1, + fill: { + target: 'origin' + } + }; + this.chartData.dataset[index].label = this.labelsArray[index]; } - if (changes.data2 && changes.data2.currentValue) { - this.data2 = changes.data2.currentValue; - this.chartData.dataset[1].data = this.formatData(this.data2); - [this.currentData2, this.currentDataUnits2] = this.convertUnits( - this.data2[this.data2.length - 1][1] - ).split(' '); + + this.setChartTicks(); + + if (this.dataArray) { + this.dataArray = changes?.dataArray?.currentValue || this.dataArray; + this.currentChartData = this.chartData; + for (let index = 0; index < this.dataArray.length; index++) { + this.chartData.dataset[index].data = this.formatData(this.dataArray[index]); + let currentDataValue = this.dataArray[index][this.dataArray[index].length - 1] + ? this.dataArray[index][this.dataArray[index].length - 1][1] + : 0; + if (currentDataValue) { + [ + this.currentChartData.dataset[index]['currentData'], + this.currentChartData.dataset[index]['currentDataUnits'] + ] = this.convertUnits(currentDataValue).split(' '); + [this.maxConvertedValue, this.maxConvertedValueUnits] = this.convertUnits( + this.maxValue + ).split(' '); + } + } } + if (this.chart) { this.chart.chart.update(); } @@ -273,16 +289,12 @@ export class DashboardAreaChartComponent implements OnChanges { let maxValue = 0; let maxValueDataUnits = ''; - if (this.data) { - let maxValueData = Math.max(...this.data.map((values: any) => values[1])); - if (this.data2) { - let maxValueData2 = Math.max(...this.data2.map((values: any) => values[1])); - maxValue = Math.max(maxValueData, maxValueData2); - } else { - maxValue = maxValueData; - } - [maxValue, maxValueDataUnits] = this.convertUnits(maxValue).split(' '); - } + const allDataValues = this.dataArray.reduce((array: string[], data) => { + return array.concat(data.map((values: [number, string]) => values[1])); + }, []); + + maxValue = Math.max(...allDataValues.map(Number)); + [maxValue, maxValueDataUnits] = this.convertUnits(maxValue).split(' '); const yAxesTicks = this.chart.chart.options.scales.y; yAxesTicks.ticks.callback = (value: any) => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.html index 85dc5c96970b7..4c290746b45b1 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.html @@ -4,7 +4,7 @@
-
+
-
- -
- - - - - - - - - - - +
+ +
+ + + + - - -
-
-
+ + + + + + + + + +
+
+
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.ts index 7ec0cd4495be8..3c44bd36a8905 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.ts @@ -54,15 +54,17 @@ export class DashboardV3Component extends PrometheusListHelper implements OnInit healthData: any; categoryPgAmount: Record = {}; totalPgs = 0; - queriesResults: any = { - USEDCAPACITY: '', - IPS: '', - OPS: '', - READLATENCY: '', - WRITELATENCY: '', - READCLIENTTHROUGHPUT: '', - WRITECLIENTTHROUGHPUT: '', - RECOVERYBYTES: '' + queriesResults: { [key: string]: [] } = { + USEDCAPACITY: [], + IPS: [], + OPS: [], + READLATENCY: [], + WRITELATENCY: [], + READCLIENTTHROUGHPUT: [], + WRITECLIENTTHROUGHPUT: [], + RECOVERYBYTES: [], + READIOPS: [], + WRITEIOPS: [] }; telemetryEnabled: boolean; telemetryURL = 'https://telemetry-public.ceph.com/'; diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-overview-dashboard/rgw-overview-dashboard.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-overview-dashboard/rgw-overview-dashboard.component.html index 0bcc48b4be2d1..66f3ec5a5a7ab 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-overview-dashboard/rgw-overview-dashboard.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-overview-dashboard/rgw-overview-dashboard.component.html @@ -55,22 +55,18 @@ + [labelsArray]="['Requests/sec']" + [dataArray]="[queriesResults.RGW_REQUEST_PER_SECOND]"> + [labelsArray]="['GET', 'PUT']" + [dataArray]="[queriesResults.AVG_GET_LATENCY, queriesResults.AVG_PUT_LATENCY]"> + [labelsArray]="['GET', 'PUT']" + [dataArray]="[queriesResults.GET_BANDWIDTH, queriesResults.PUT_BANDWIDTH]">
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-overview-dashboard/rgw-overview-dashboard.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-overview-dashboard/rgw-overview-dashboard.component.ts index 00537b32af008..8b5901769c357 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-overview-dashboard/rgw-overview-dashboard.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-overview-dashboard/rgw-overview-dashboard.component.ts @@ -46,11 +46,11 @@ export class RgwOverviewDashboardComponent implements OnInit, OnDestroy { ZoneSUb: Subscription; HealthSub: Subscription; BucketSub: Subscription; - queriesResults: any = { - RGW_REQUEST_PER_SECOND: '', - BANDWIDTH: '', - AVG_GET_LATENCY: '', - AVG_PUT_LATENCY: '' + queriesResults: { [key: string]: [] } = { + RGW_REQUEST_PER_SECOND: [], + BANDWIDTH: [], + AVG_GET_LATENCY: [], + AVG_PUT_LATENCY: [] }; timerGetPrometheusDataSub: Subscription; chartTitles = ['Metadata Sync', 'Data Sync']; diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/prometheus.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/prometheus.service.ts index 6917b37662a6f..e1aa7a07cafc2 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/prometheus.service.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/prometheus.service.ts @@ -154,6 +154,8 @@ export class PrometheusService { }).subscribe((data: any) => { if (data.result.length) { queriesResults[queryName] = data.result[0].values; + } else { + queriesResults[queryName] = []; } if ( queriesResults[queryName] !== undefined && diff --git a/src/pybind/mgr/dashboard/frontend/src/styles/defaults/_bootstrap-defaults.scss b/src/pybind/mgr/dashboard/frontend/src/styles/defaults/_bootstrap-defaults.scss index d69abf12bc8e8..8147d9381ce66 100644 --- a/src/pybind/mgr/dashboard/frontend/src/styles/defaults/_bootstrap-defaults.scss +++ b/src/pybind/mgr/dashboard/frontend/src/styles/defaults/_bootstrap-defaults.scss @@ -15,13 +15,18 @@ $black: #000 !default; $blue: #007bff !default; $indigo: #6610f2 !default; $purple: #6f42c1 !default; +$purple-dim: #6f42c180 !default; $pink: #a94442 !default; $red: #dc3545 !default; +$red-dim: #dc354580 !default; $orange: #fd7e14 !default; +$orange-dim: #fd7e1480 !default; $yellow: #d48200 !default; $green: #008a00 !default; +$green-dim: #008a0080 !default; $teal: #20c997 !default; $cyan: #17a2b8 !default; +$cyan-dim: #17a2b880 !default; $barley-white: #fcecba !default; $primary: #25828e !default; @@ -75,17 +80,22 @@ $health-color-warning-800: #9d6d10 !default; // Chart colors. $chart-color-red: $red !default; -$chart-color-blue: #06c !default; -$chart-color-orange: #ef9234 !default; $chart-color-yellow: #f6d173 !default; +$chart-color-translucent-red: $red-dim !default; +$chart-color-blue: $blue !default; +$chart-color-orange: $orange !default; +$chart-color-translucent-orange: $orange-dim !default; +$chart-color-translucent-green: $green-dim !default; +$chart-color-translucent-cyan: $cyan-dim !default; +$chart-color-yellow: $yellow !default; $chart-color-green: $green !default; $chart-color-gray: #ededed !default; $chart-color-cyan: $primary-500 !default; $chart-color-light-gray: #f0f0f0 !default; $chart-color-slight-dark-gray: #d7d7d7 !default; $chart-color-dark-gray: #afafaf !default; -$chart-color-cyan: #73c5c5 !default; -$chart-color-purple: #3c3d99 !default; +$chart-color-purple: $purple !default; +$chart-color-translucent-purple: $purple-dim !default; $chart-color-white: #fff !default; $chart-color-center-text: #151515 !default; $chart-color-center-text-description: #72767b !default; -- 2.39.5