From: Tiago Melo Date: Thu, 18 Apr 2019 15:09:07 +0000 (+0000) Subject: mgr/dashboard: Unify the look of dashboard charts X-Git-Tag: v15.1.0~2666^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=bcbc0edba604f5bf8e421f43349ad56f019a800e;p=ceph.git mgr/dashboard: Unify the look of dashboard charts Fixes: http://tracker.ceph.com/issues/39384 Signed-off-by: Tiago Melo --- diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health-pie/health-pie.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health-pie/health-pie.component.ts index a28afa613e85..1016254c5628 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health-pie/health-pie.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health-pie/health-pie.component.ts @@ -37,6 +37,8 @@ export class HealthPieComponent implements OnChanges, OnInit { displayLegend = false; @Input() tooltipFn: any; + @Input() + showLabelAsTooltip = false; @Output() prepareFn = new EventEmitter(); @@ -147,6 +149,10 @@ export class HealthPieComponent implements OnChanges, OnInit { private getChartTooltipBody(body) { const bodySplit = body[0].split(': '); + if (this.showLabelAsTooltip) { + return bodySplit[0]; + } + if (this.isBytesData) { bodySplit[1] = this.dimlessBinary.transform(bodySplit[1]); } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.html index 17d94d7bd5cc..592c14b8d8c4 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.html @@ -204,7 +204,8 @@ contentClass="content-chart" *ngIf="healthData.df"> diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.spec.ts index 99bc05fc8db2..b4823fc8485d 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.spec.ts @@ -249,6 +249,8 @@ describe('HealthComponent', () => { }); describe('preparePgStatus', () => { + const calcPercentage = (data) => Math.round((data / 10) * 100) || 0; + const expectedChart = (data: number[]) => ({ colors: [ { @@ -260,20 +262,29 @@ describe('HealthComponent', () => { ] } ], - labels: ['Clean', 'Working', 'Warning', 'Unknown'], + labels: [ + `Clean (${calcPercentage(data[0])}%)`, + `Working (${calcPercentage(data[1])}%)`, + `Warning (${calcPercentage(data[2])}%)`, + `Unknown (${calcPercentage(data[3])}%)` + ], + options: {}, dataset: [{ data: data }] }); it('gets no data', () => { - const chart = { dataset: [{}] }; - component.preparePgStatus(chart, { pg_info: {} }); + const chart = { dataset: [{}], options: {} }; + component.preparePgStatus(chart, { + pg_info: { pgs_per_osd: 0 } + }); expect(chart).toEqual(expectedChart([undefined, undefined, undefined, undefined])); }); it('gets data from all categories', () => { - const chart = { dataset: [{}] }; + const chart = { dataset: [{}], options: {} }; component.preparePgStatus(chart, { pg_info: { + pgs_per_osd: 10, statuses: { 'clean+active+scrubbing+nonMappedState': 4, 'clean+active+scrubbing': 2, diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.ts index c5748642d357..d43024bdcfd3 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.ts @@ -6,6 +6,7 @@ import { Subscription } from 'rxjs/Subscription'; import { HealthService } from '../../../shared/api/health.service'; import { Permissions } from '../../../shared/models/permissions'; +import { DimlessBinaryPipe } from '../../../shared/pipes/dimless-binary.pipe'; import { AuthStorageService } from '../../../shared/services/auth-storage.service'; import { FeatureTogglesMap$, @@ -32,7 +33,8 @@ export class HealthComponent implements OnInit, OnDestroy { private authStorageService: AuthStorageService, private pgCategoryService: PgCategoryService, private featureToggles: FeatureTogglesService, - private refreshIntervalService: RefreshIntervalService + private refreshIntervalService: RefreshIntervalService, + private dimlessBinary: DimlessBinaryPipe ) { this.permissions = this.authStorageService.getPermissions(); this.enabledFeature$ = this.featureToggles.get(); @@ -59,9 +61,14 @@ export class HealthComponent implements OnInit, OnDestroy { const ratioLabels = []; const ratioData = []; - ratioLabels.push(this.i18n('Writes')); + const total = + this.healthData.client_perf.write_op_per_sec + this.healthData.client_perf.read_op_per_sec; + const calcPercentage = (status) => + Math.round(((this.healthData.client_perf[status] || 0) / total) * 100); + + ratioLabels.push(`${this.i18n('Writes')} (${calcPercentage('write_op_per_sec')}%)`); ratioData.push(this.healthData.client_perf.write_op_per_sec); - ratioLabels.push(this.i18n('Reads')); + ratioLabels.push(`${this.i18n('Reads')} (${calcPercentage('read_op_per_sec')}%)`); ratioData.push(this.healthData.client_perf.read_op_per_sec); chart.dataset[0].data = ratioData; @@ -84,19 +91,23 @@ export class HealthComponent implements OnInit, OnDestroy { chart.options.cutoutPercentage = 65; } chart.labels = [ - `${this.i18n('Used')} (${percentUsed}%)`, - `${this.i18n('Avail.')} (${percentAvailable}%)` + `${this.dimlessBinary.transform(data.df.stats.total_used_raw_bytes)} ${this.i18n( + 'Used' + )} (${percentUsed}%)`, + `${this.dimlessBinary.transform( + data.df.stats.total_bytes - data.df.stats.total_used_raw_bytes + )} ${this.i18n('Avail.')} (${percentAvailable}%)` ]; + + chart.options.title = { + display: true, + text: `${this.dimlessBinary.transform(data.df.stats.total_bytes)} total`, + position: 'bottom' + }; } preparePgStatus(chart, data) { const categoryPgAmount = {}; - chart.labels = [ - this.i18n('Clean'), - this.i18n('Working'), - this.i18n('Warning'), - this.i18n('Unknown') - ]; chart.colors = [ { backgroundColor: [ @@ -120,6 +131,16 @@ export class HealthComponent implements OnInit, OnDestroy { chart.dataset[0].data = this.pgCategoryService .getAllTypes() .map((categoryType) => categoryPgAmount[categoryType]); + + const calcPercentage = (status) => + Math.round(((categoryPgAmount[status] || 0) / data.pg_info.pgs_per_osd) * 100) || 0; + + chart.labels = [ + `${this.i18n('Clean')} (${calcPercentage('clean')}%)`, + `${this.i18n('Working')} (${calcPercentage('working')}%)`, + `${this.i18n('Warning')} (${calcPercentage('warning')}%)`, + `${this.i18n('Unknown')} (${calcPercentage('unknown')}%)` + ]; } isClientReadWriteChartShowable() {