Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI: CSI Availability Gauges #7911

Merged
merged 9 commits into from
May 13, 2020
86 changes: 86 additions & 0 deletions ui/app/components/gauge-chart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import Component from '@ember/component';
import { computed } from '@ember/object';
import { assert } from '@ember/debug';
import { guidFor } from '@ember/object/internals';
import { run } from '@ember/runloop';
import d3Shape from 'd3-shape';
import WindowResizable from 'nomad-ui/mixins/window-resizable';

export default Component.extend(WindowResizable, {
classNames: ['chart', 'gauge-chart'],

value: null,
complement: null,
total: null,
chartClass: 'is-info',

width: 0,
height: 0,

percent: computed('value', 'complement', 'total', function() {
assert(
'Provide complement OR total to GaugeChart, not both.',
this.complement != null || this.total != null
);

if (this.complement != null) {
return this.value / (this.value + this.complement);
}

return this.value / this.total;
}),

fillId: computed(function() {
return `gauge-chart-fill-${guidFor(this)}`;
}),

maskId: computed(function() {
return `gauge-chart-mask-${guidFor(this)}`;
}),

radius: computed('width', function() {
return this.width / 2;
}),

weight: 4,

backgroundArc: computed('radius', 'weight', function() {
const { radius, weight } = this;
const arc = d3Shape
.arc()
.outerRadius(radius)
.innerRadius(radius - weight)
.cornerRadius(weight)
.startAngle(-Math.PI / 2)
.endAngle(Math.PI / 2);
return arc();
}),

valueArc: computed('radius', 'weight', 'percent', function() {
const { radius, weight, percent } = this;

const arc = d3Shape
.arc()
.outerRadius(radius)
.innerRadius(radius - weight)
.cornerRadius(weight)
.startAngle(-Math.PI / 2)
.endAngle(-Math.PI / 2 + Math.PI * percent);
return arc();
}),

didInsertElement() {
this.updateDimensions();
},

updateDimensions() {
const $svg = this.$('svg');
const width = $svg.width();

this.setProperties({ width, height: width / 2 });
},

windowResizeHandler() {
run.once(this, this.updateDimensions);
},
});
4 changes: 2 additions & 2 deletions ui/app/helpers/format-percentage.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ export function formatPercentage(params, options = {}) {
let ratio;
let total = options.total;

if (total !== undefined) {
if (total != undefined) {
total = safeNumber(total);
} else if (complement !== undefined) {
} else if (complement != undefined) {
total = value + safeNumber(complement);
} else {
// Ensures that ratio is between 0 and 1 when neither total or complement are defined
Expand Down
1 change: 1 addition & 0 deletions ui/app/styles/charts.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@import './charts/distribution-bar';
@import './charts/gauge-chart';
@import './charts/line-chart';
@import './charts/tooltip';
@import './charts/colors';
Expand Down
52 changes: 52 additions & 0 deletions ui/app/styles/charts/gauge-chart.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
.gauge-chart {
position: relative;
display: block;
width: auto;

svg {
display: block;
margin: auto;
width: 100%;
max-width: 200px;
height: 100%;
}

.background,
.fill {
transform: translate(50%, 100%);
}

.background {
fill: $ui-gray-100;
}

@each $name, $pair in $colors {
$color: nth($pair, 1);

.canvas.is-#{$name} {
.line {
stroke: $color;
}
}

linearGradient {
&.is-#{$name} {
> .start {
stop-color: $color;
stop-opacity: 0.2;
}

> .end {
stop-color: $color;
stop-opacity: 1;
}
}
}
}

.metric {
position: absolute;
bottom: 0;
width: 100%;
}
}
27 changes: 18 additions & 9 deletions ui/app/styles/components/metrics.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
.metric {
padding: 0.75em 1em;
border: 1px solid $grey-blue;
text-align: center;
display: flex;
flex-direction: column;
min-width: 120px;
Expand Down Expand Up @@ -50,15 +49,25 @@
}
}

.label {
font-size: 1.1em;
font-weight: $weight-semibold;
margin-bottom: 0;
&.is-hollow {
border-color: transparent;
background: transparent;
}
}
}

.value {
font-size: 2em;
margin-bottom: 0;
}
.metric {
text-align: center;

.label {
font-size: 1.1em;
font-weight: $weight-semibold;
margin-bottom: 0;
}

.value {
font-size: 2em;
margin-bottom: 0;
line-height: 1;
}
}
4 changes: 4 additions & 0 deletions ui/app/styles/core/columns.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@
flex-grow: 0;
}
}

&.is-bottom-aligned {
align-items: flex-end;
}
}
28 changes: 27 additions & 1 deletion ui/app/styles/storybook.scss
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
}

.description {
font-size: .8rem;
font-size: 0.8rem;
padding-bottom: 5px;
}

Expand Down Expand Up @@ -116,4 +116,30 @@
margin: 0;
}
}

.multiples {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
}

.chart-container {
width: 200px;
padding: 15px;
border: 1px solid $ui-gray-200;
display: inline-block;

&.is-small {
width: 150px;
}

&.is-large {
width: 250px;
}

&.is-xlarge {
width: 300px;
}
}
}
1 change: 1 addition & 0 deletions ui/app/styles/utils/structure-colors.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
$ui-gray-100: #ebeef2;
$ui-gray-200: #dce0e6;
$ui-gray-300: #bac1cc;
$ui-gray-400: #8e96a3;
Expand Down
19 changes: 19 additions & 0 deletions ui/app/templates/components/gauge-chart.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<svg data-test-gauge-svg role="img" height={{height}}>
<defs>
<linearGradient x1="0" x2="1" y1="0" y2="0" class="{{chartClass}}" id="{{fillId}}">
<stop class="start" offset="0%" />
<stop class="end" offset="100%" />
</linearGradient>
<clipPath id="{{maskId}}">
<path class="fill" d="{{valueArc}}" />
</clipPath>
</defs>
<g class="canvas {{chartClass}}">
<path class="background" d="{{backgroundArc}}" />
<rect class="area" x="0" y="0" width="100%" height="100%" fill="url(#{{fillId}})" clip-path="url(#{{maskId}})" />
</g>
</svg>
<div class="metric">
<h3 data-test-label class="label">{{label}}</h3>
<p data-test-percentage class="value">{{format-percentage value total=total complement=complement}}</p>
</div>
57 changes: 57 additions & 0 deletions ui/app/templates/csi/plugins/plugin.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,63 @@
</div>
</div>

<div class="columns">
<div class="column">
<div class="boxed-section">
<div class="boxed-section-head is-hollow">Controller Health</div>
<div class="boxed-section-body">
<div class="columns is-bottom-aligned">
<div class="column is-half">
{{gauge-chart
label="Availability"
value=model.controllersHealthy
total=model.controllersExpected}}
</div>
<div class="column">
<div class="metric">
<h3 class="label">Available</h3>
<p class="value">{{model.controllersHealthy}}</p>
</div>
</div>
<div class="column">
<div class="metric">
<h3 class="label">Expected</h3>
<p class="value">{{model.controllersExpected}}</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="column">
<div class="boxed-section">
<div class="boxed-section-head is-hollow">Node Health</div>
<div class="boxed-section-body">
<div class="columns is-bottom-aligned">
<div class="column is-half">
{{gauge-chart
label="Availability"
value=model.nodesHealthy
total=model.nodesExpected}}
</div>
<div class="column">
<div class="metric">
<h3 class="label">Available</h3>
<p class="value">{{model.nodesHealthy}}</p>
</div>
</div>
<div class="column">
<div class="metric">
<h3 class="label">Expected</h3>
<p class="value">{{model.nodesExpected}}</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

<div class="boxed-section">
<div class="boxed-section-head">
Controller Allocations
Expand Down
Loading