Skip to content

Commit

Permalink
Merge pull request #7911 from hashicorp/f-ui/csi-availability-gauge
Browse files Browse the repository at this point in the history
UI: CSI Availability Gauges
  • Loading branch information
DingoEatingFuzz committed May 13, 2020
2 parents 71037b4 + 0a258b1 commit 5456147
Show file tree
Hide file tree
Showing 14 changed files with 471 additions and 12 deletions.
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

0 comments on commit 5456147

Please sign in to comment.