mirror of https://github.com/rancher/ui.git
Merge pull request #2282 from westlywright/progress-bar
Alert Users of Remaining Project Resource Quotas
This commit is contained in:
commit
59ce6f88a3
|
|
@ -39,6 +39,8 @@
|
||||||
editing=(or editing isNew)
|
editing=(or editing isNew)
|
||||||
expanded=expanded
|
expanded=expanded
|
||||||
limit=primaryResource.resourceQuota.limit
|
limit=primaryResource.resourceQuota.limit
|
||||||
|
projectLimit=primaryResource.project.resourceQuota.limit
|
||||||
|
usedLimit=primaryResource.project.resourceQuota.usedLimit
|
||||||
nsDefaultQuota=primaryResource.project.namespaceDefaultResourceQuota.limit
|
nsDefaultQuota=primaryResource.project.namespaceDefaultResourceQuota.limit
|
||||||
changed=(action "updateNsQuota")
|
changed=(action "updateNsQuota")
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,13 @@
|
||||||
<td class="pr-10">
|
<td class="pr-10">
|
||||||
{{resource-quota-select editing=false quota=quota}}
|
{{resource-quota-select editing=false quota=quota}}
|
||||||
</td>
|
</td>
|
||||||
|
<td class="pr-10">
|
||||||
|
{{progress-bar-multi
|
||||||
|
values=quota.currentProjectUse
|
||||||
|
tooltipValues=quota.totalLimits
|
||||||
|
max=quota.max
|
||||||
|
}}
|
||||||
|
</td>
|
||||||
<td class="pr-10">
|
<td class="pr-10">
|
||||||
{{input-resource-quota editing=editing quota=quota key='value'}}
|
{{input-resource-quota editing=editing quota=quota key='value'}}
|
||||||
</td>
|
</td>
|
||||||
|
|
@ -4,11 +4,15 @@ import Component from '@ember/component';
|
||||||
import { convertToMillis } from 'shared/utils/util';
|
import { convertToMillis } from 'shared/utils/util';
|
||||||
import { parseSi } from 'shared/utils/parse-unit';
|
import { parseSi } from 'shared/utils/parse-unit';
|
||||||
import layout from './template';
|
import layout from './template';
|
||||||
|
import { inject as service } from '@ember/service';
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
layout,
|
intl: service(),
|
||||||
|
|
||||||
|
layout,
|
||||||
limit: null,
|
limit: null,
|
||||||
|
usedLimit: null,
|
||||||
|
projectlimit: null,
|
||||||
projectQuota: null,
|
projectQuota: null,
|
||||||
nsDefaultQuota: null,
|
nsDefaultQuota: null,
|
||||||
|
|
||||||
|
|
@ -51,21 +55,49 @@ export default Component.extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
this.sendAction('changed', Object.keys(out).length ? out : null);
|
this.sendAction('changed', Object.keys(out).length ? out : null);
|
||||||
|
this.updateLimits();
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
updateLimits() {
|
||||||
|
( get(this, 'quotaArray') || [] ).forEach((quota) => {
|
||||||
|
if ( quota.key ) {
|
||||||
|
const value = parseInt(get(quota, 'value'), 10) || 0;
|
||||||
|
const usedValue = get(quota, 'currentProjectUse.firstObject.value');
|
||||||
|
const newUse = get(quota, 'currentProjectUse.lastObject');
|
||||||
|
const totalLimits = get(quota, 'totalLimits.firstObject');
|
||||||
|
const myNewUse = usedValue + value;
|
||||||
|
const translation = get(this, 'intl').t('formResourceQuota.table.resources.tooltip', {
|
||||||
|
usedValue,
|
||||||
|
newUse: myNewUse,
|
||||||
|
remaining: ( get(quota, 'max') - ( myNewUse ) ),
|
||||||
|
});
|
||||||
|
|
||||||
|
set(newUse, 'value', value);
|
||||||
|
set(totalLimits, 'value', translation);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
initQuotaArray() {
|
initQuotaArray() {
|
||||||
let limit = get(this, 'limit');
|
const limit = get(this, 'limit');
|
||||||
const nsDefaultQuota = get(this, 'nsDefaultQuota');
|
const nsDefaultQuota = get(this, 'nsDefaultQuota');
|
||||||
const array = [];
|
const array = [];
|
||||||
|
const used = get(this, 'usedLimit');
|
||||||
|
const currentProjectLimit = get(this, 'projectLimit')
|
||||||
|
const intl = get(this, 'intl');
|
||||||
|
|
||||||
Object.keys(nsDefaultQuota).forEach((key) => {
|
Object.keys(nsDefaultQuota).forEach((key) => {
|
||||||
if ( key !== 'type' && typeof nsDefaultQuota[key] === 'string') {
|
if ( key !== 'type' && typeof nsDefaultQuota[key] === 'string') {
|
||||||
let value;
|
let value, currentProjectUse, totalLimits;
|
||||||
|
let usedValue = '';
|
||||||
|
let max = '';
|
||||||
|
let newUse = null;
|
||||||
|
|
||||||
if ( limit && !limit[key] ) {
|
if ( limit && !limit[key] ) {
|
||||||
array.push({
|
array.push({
|
||||||
key,
|
key,
|
||||||
value: '',
|
value: '',
|
||||||
|
currentProjectUse: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
@ -73,16 +105,60 @@ export default Component.extend({
|
||||||
|
|
||||||
value = limit && limit[key] ? limit[key] : nsDefaultQuota[key];
|
value = limit && limit[key] ? limit[key] : nsDefaultQuota[key];
|
||||||
|
|
||||||
if ( key === 'limitsCpu' || key === 'requestsCpu' ) {
|
switch (key) {
|
||||||
value = convertToMillis(value);
|
case 'limitsCpu':
|
||||||
} else if ( key === 'limitsMemory' || key === 'requestsMemory' ) {
|
case 'requestsCpu':
|
||||||
value = parseSi(value, 1024) / 1048576;
|
value = convertToMillis(value);
|
||||||
} else if ( key === 'requestsStorage' ) {
|
usedValue = convertToMillis(get(used, key));
|
||||||
value = parseSi(value) / (1024 ** 3);
|
max = convertToMillis(get(currentProjectLimit, key));
|
||||||
|
break;
|
||||||
|
case 'limitsMemory':
|
||||||
|
case 'requestsMemory':
|
||||||
|
value = parseSi(value, 1024) / 1048576;
|
||||||
|
usedValue = parseSi(get(used, key), 1024) / 1048576;
|
||||||
|
max = parseSi(get(currentProjectLimit, key), 1024) / 1048576;
|
||||||
|
break;
|
||||||
|
case 'requestsStorage':
|
||||||
|
value = parseSi(value) / (1024 ** 3);
|
||||||
|
usedValue = parseSi(get(used, key)) / (1024 ** 3);
|
||||||
|
max = parseSi(get(currentProjectLimit, key)) / (1024 ** 3);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
newUse = usedValue + value;
|
||||||
|
|
||||||
|
currentProjectUse = [
|
||||||
|
{
|
||||||
|
// current use
|
||||||
|
color: 'bg-error',
|
||||||
|
label: key,
|
||||||
|
value: usedValue,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// only need the new value here because progress-multi-bar adds this to the previous
|
||||||
|
color: 'bg-warning',
|
||||||
|
label: key,
|
||||||
|
value,
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
totalLimits = [{
|
||||||
|
label: get(this, 'intl').t(`formResourceQuota.resources.${ key }`),
|
||||||
|
value: intl.t('formResourceQuota.table.resources.tooltip', {
|
||||||
|
usedValue,
|
||||||
|
newUse,
|
||||||
|
remaining: ( max - newUse ),
|
||||||
|
})
|
||||||
|
}];
|
||||||
|
|
||||||
array.push({
|
array.push({
|
||||||
|
currentProjectUse,
|
||||||
key,
|
key,
|
||||||
|
max,
|
||||||
|
totalLimits,
|
||||||
value,
|
value,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{{t 'formResourceQuota.table.type.label'}}</th>
|
<th>{{t 'formResourceQuota.table.type.label'}}</th>
|
||||||
|
<th width="200px">{{t 'formResourceQuota.table.resources.label'}}</th>
|
||||||
<th>{{t 'formResourceQuota.table.value.label'}}</th>
|
<th>{{t 'formResourceQuota.table.value.label'}}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
|
||||||
|
|
@ -15,14 +15,13 @@
|
||||||
}}
|
}}
|
||||||
{{#if (eq kind "row")}}
|
{{#if (eq kind "row")}}
|
||||||
<tr class="main-row">
|
<tr class="main-row">
|
||||||
<td valign="middle" class="row-check" style="padding-top: 2px;">
|
<td valign="middle" class="row-check" style="padding-top: 2px;">
|
||||||
{{#if projectsWithoutNamespace.length}}
|
{{#if (and projectsWithoutNamespace.length (not model.length))}}
|
||||||
|
|
||||||
{{else}}
|
{{else}}
|
||||||
{{check-box nodeId=ns.id}}
|
{{check-box nodeId=ns.id}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
</td>
|
||||||
</td>
|
|
||||||
<td>
|
<td>
|
||||||
{{badge-state model=ns}}
|
{{badge-state model=ns}}
|
||||||
</td>
|
</td>
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@
|
||||||
{{#copy-inline clipboardText=model.displayIp}}{{format-ip model.displayIp}}{{/copy-inline}} /
|
{{#copy-inline clipboardText=model.displayIp}}{{format-ip model.displayIp}}{{/copy-inline}} /
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if (and showNode model.node)}}
|
{{#if (and showNode model.node)}}
|
||||||
{{log model.node}}
|
|
||||||
<a href="{{href-to "node" scope.currentCluster.id model.node.id}}">{{model.node.displayName}}</a> /
|
<a href="{{href-to "node" scope.currentCluster.id model.node.id}}">{{model.node.displayName}}</a> /
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{t 'generic.createdDate' date=(date-from-now model.created) htmlSafe=true}}
|
{{t 'generic.createdDate' date=(date-from-now model.created) htmlSafe=true}}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { defineProperty, computed, get } from '@ember/object';
|
import { defineProperty, computed, get, observer } from '@ember/object';
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
import layout from './template';
|
import layout from './template';
|
||||||
|
|
||||||
|
|
@ -28,19 +28,19 @@ export default Component.extend({
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
let colorKey = this.get('colorKey');
|
let colorKey = get(this, 'colorKey');
|
||||||
let labelKey = this.get('labelKey');
|
let labelKey = get(this, 'labelKey');
|
||||||
let valueKey = this.get('valueKey');
|
let valueKey = get(this, 'valueKey');
|
||||||
|
|
||||||
let valueDep = `values.@each.{${ colorKey },${ labelKey },${ valueKey }}`;
|
let valueDep = `values.@each.{${ colorKey },${ labelKey },${ valueKey }}`;
|
||||||
|
|
||||||
defineProperty(this, 'pieces', computed('min', 'max', valueDep, () => {
|
defineProperty(this, 'pieces', computed('min', 'max', valueDep, () => {
|
||||||
let min = this.get('min');
|
let min = get(this, 'min');
|
||||||
let max = this.get('max');
|
let max = get(this, 'max');
|
||||||
|
|
||||||
var out = [];
|
var out = [];
|
||||||
|
|
||||||
(this.get('values') || []).forEach((obj) => {
|
(get(this, 'values') || []).forEach((obj) => {
|
||||||
out.push({
|
out.push({
|
||||||
color: get(obj, colorKey),
|
color: get(obj, colorKey),
|
||||||
label: get(obj, labelKey),
|
label: get(obj, labelKey),
|
||||||
|
|
@ -56,7 +56,7 @@ export default Component.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
let sum = 0;
|
let sum = 0;
|
||||||
let minPercent = this.get('minPercent');
|
let minPercent = get(this, 'minPercent');
|
||||||
|
|
||||||
out.forEach((obj) => {
|
out.forEach((obj) => {
|
||||||
let per = Math.max(minPercent, toPercent(obj.value, min, max));
|
let per = Math.max(minPercent, toPercent(obj.value, min, max));
|
||||||
|
|
@ -79,12 +79,12 @@ export default Component.extend({
|
||||||
|
|
||||||
valueDep = `tooltipValues.@each.{${ labelKey },${ valueKey }}`;
|
valueDep = `tooltipValues.@each.{${ labelKey },${ valueKey }}`;
|
||||||
defineProperty(this, 'tooltipContent', computed(valueDep, () => {
|
defineProperty(this, 'tooltipContent', computed(valueDep, () => {
|
||||||
let labelKey = this.get('labelKey');
|
let labelKey = get(this, 'labelKey');
|
||||||
let valueKey = this.get('valueKey');
|
let valueKey = get(this, 'valueKey');
|
||||||
|
|
||||||
var out = [];
|
var out = [];
|
||||||
|
|
||||||
(this.get('tooltipValues') || []).forEach((obj) => {
|
(get(this, 'tooltipValues') || []).forEach((obj) => {
|
||||||
out.push(`${ get(obj, labelKey) }: ${ get(obj, valueKey) }`);
|
out.push(`${ get(obj, labelKey) }: ${ get(obj, valueKey) }`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -95,8 +95,9 @@ export default Component.extend({
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
this.zIndexDidChange();
|
this.zIndexDidChange();
|
||||||
},
|
},
|
||||||
zIndexDidChange: function() {
|
|
||||||
this.$().css('zIndex', this.get('zIndex') || 'inherit');
|
zIndexDidChange: observer('zIndex', function() {
|
||||||
}.observes('zIndex'),
|
this.$().css('zIndex', get(this, 'zIndex') || 'inherit');
|
||||||
|
}),
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,12 @@
|
||||||
{{#tooltip-element type="tooltip-basic" model=tooltipContent tooltipTemplate='tooltip-static' aria-describedby="tooltip-base" tooltipFor="progress-bar" inlineBlock=false}}
|
{{#tooltip-element
|
||||||
|
type="tooltip-basic"
|
||||||
|
model=tooltipContent
|
||||||
|
tooltipTemplate='tooltip-static'
|
||||||
|
aria-describedby="tooltip-base"
|
||||||
|
tooltipFor="progress-bar"
|
||||||
|
inlineBlock=true
|
||||||
|
classNames="full-width"
|
||||||
|
}}
|
||||||
<div class="progress">
|
<div class="progress">
|
||||||
{{~#each pieces as |obj|~}}
|
{{~#each pieces as |obj|~}}
|
||||||
<div class="progress-bar {{obj.color}}" style={{obj.css}}></div>
|
<div class="progress-bar {{obj.color}}" style={{obj.css}}></div>
|
||||||
|
|
|
||||||
|
|
@ -40,11 +40,11 @@
|
||||||
|
|
||||||
<td data-title="{{dt.scale}}" class="text-center">
|
<td data-title="{{dt.scale}}" class="text-center">
|
||||||
{{progress-bar-multi
|
{{progress-bar-multi
|
||||||
classNames="mt-5"
|
classNames="mt-5"
|
||||||
labelKey="state"
|
labelKey="state"
|
||||||
valueKey="count"
|
valueKey="count"
|
||||||
values=model.podStates.byColor
|
values=model.podStates.byColor
|
||||||
tooltipValues=model.podStates.byName
|
tooltipValues=model.podStates.byName
|
||||||
}}
|
}}
|
||||||
<small class="text-muted">
|
<small class="text-muted">
|
||||||
{{model.displayScale}}
|
{{model.displayScale}}
|
||||||
|
|
|
||||||
|
|
@ -3379,6 +3379,9 @@ formResourceQuota:
|
||||||
placeholder: e.g. 10
|
placeholder: e.g. 10
|
||||||
milliCpuPlaceholder: e.g. 500
|
milliCpuPlaceholder: e.g. 500
|
||||||
memoryPlaceholder: e.g. 1Gi
|
memoryPlaceholder: e.g. 1Gi
|
||||||
|
resources:
|
||||||
|
label: Project Resource Availability
|
||||||
|
tooltip: "Reserved - { usedValue }, This Namespace - { newUse }, Available - { remaining }"
|
||||||
projectLimit:
|
projectLimit:
|
||||||
label: Project Limit
|
label: Project Limit
|
||||||
placeholder: e.g. 50
|
placeholder: e.g. 50
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue