New primary-metric component

It encapsulates all the tracker, polling, and markup for this style
of metric.
This commit is contained in:
Michael Lange
2018-09-13 16:32:29 -07:00
parent 44b16b2b7c
commit 48910d8334
3 changed files with 130 additions and 3 deletions

View File

@@ -0,0 +1,103 @@
import Ember from 'ember';
import Component from '@ember/component';
import { inject as service } from '@ember/service';
import { computed } from '@ember/object';
import NodeStatsTracker from 'nomad-ui/utils/classes/node-stats-tracker';
import AllocationStatsTracker from 'nomad-ui/utils/classes/allocation-stats-tracker';
import { task, timeout } from 'ember-concurrency';
export default Component.extend({
token: service(),
// One of Node, Allocation, or TaskState
resource: null,
// cpu or memory
metric: null,
// An instance of a StatsTracker. An alternative interface to resource
tracker: computed('trackedResource', 'type', function() {
const resource = this.get('trackedResource');
if (!resource) return;
const Constructor = this.get('type') === 'node' ? NodeStatsTracker : AllocationStatsTracker;
const resourceProp = this.get('type') === 'node' ? 'node' : 'allocation';
return Constructor.create({
fetch: url => this.get('token').authorizedRequest(url),
[resourceProp]: resource,
});
}),
type: computed('resource', function() {
const resource = this.get('resource');
return resource && resource.constructor.modelName;
}),
trackedResource: computed('resource', 'type', function() {
// TaskStates use the allocation stats tracker
return this.get('type') === 'task-state'
? this.get('resource.allocation')
: this.get('resource');
}),
metricLabel: computed('metric', function() {
const metric = this.get('metric');
const mappings = {
cpu: 'CPU',
memory: 'Memory',
};
return mappings[metric] || metric;
}),
data: computed('resource', 'metric', 'type', function() {
if (!this.get('tracker')) return [];
const metric = this.get('metric');
if (this.get('type') === 'task-state') {
// handle getting the right task out of the tracker
const task = this.get('tracker.tasks').findBy('task', this.get('resource.name'));
return task && task[metric];
}
return this.get(`tracker.${metric}`);
}),
reservedAmount: computed('resource', 'metric', 'type', function() {
const metricProperty = this.get('metric') === 'cpu' ? 'reservedCPU' : 'reservedMemory';
if (this.get('type') === 'task-state') {
const task = this.get('tracker.tasks').findBy('task', this.get('resource.name'));
return task[metricProperty];
}
return this.get(`tracker.${metricProperty}`);
}),
chartClass: computed('metric', function() {
const metric = this.get('metric');
const mappings = {
cpu: 'is-info',
memory: 'is-danger',
};
return mappings[metric] || 'is-primary';
}),
poller: task(function*() {
do {
yield this.get('tracker').poll();
yield timeout(2000);
} while (!Ember.testing);
}),
didReceiveAttrs() {
if (this.get('tracker')) {
this.get('poller').perform();
}
},
willDestroy() {
this.get('poller').cancelAll();
},
});

View File

@@ -0,0 +1,26 @@
{{metricLabel}}
<div style="height: 200px">
{{stats-time-series data=data chartClass=chartClass}}
</div>
<div class="columns">
<div class="column">
<div class="inline-chart">
<progress
class="progress {{chartClass}} is-small"
value="{{data.lastObject.percent}}"
max="1">
{{data.lastObject.percent}}
</progress>
</div>
</div>
<div class="column is-minimum">
{{format-percentage data.lastObject.percent total=1}}
</div>
</div>
{{#if (eq metric "cpu")}}
{{data.lastObject.used}} Mhz / {{reservedAmount}} Mhz reserved
{{else if (eq metric "memory")}}
{{format-bytes data.lastObject.used}} MiB / {{reservedAmount}} MiB reserved
{{else}}
{{data.lastObject.used}} / {{reservedAmount}} reserved
{{/if}}

View File

@@ -19,9 +19,7 @@ export default Mixin.create({
assert('Url must be defined', url);
return this.get('fetch')(url)
.then(res => {
return res.json();
})
.then(res => res.json())
.then(frame => this.append(frame));
},
});