Refactor quota limit summary template

Refactor the quota limit summary template to allow easier customisation.
Also change it so that it removes the 'of' when there is no quota limits in
place so that it just reads Used 'x' (No Limit).

Added tests for checking usage['charts'] is in the context and that (No Limit)
is present when there is an infinite quota on the page.

Change-Id: Iba62ca89e53f0d6b9c583e4cc450e853c18ba107
Closes-bug: 1439717
This commit is contained in:
Bradley Jones 2015-04-02 15:22:00 +01:00
parent 6d33c076bf
commit 286245b423
5 changed files with 73 additions and 52 deletions

View File

@ -2,53 +2,19 @@
<div class="quota-dynamic">
<h3 class="quota-heading">{% trans "Limit Summary" %}</h3>
{% for quota in charts %}
<div class="d3_quota_bar">
<div class="d3_pie_chart_usage" data-used="{% quotapercent usage.limits.totalInstancesUsed usage.limits.maxTotalInstances %}"></div>
<strong>{% trans "Instances" %} <br />
{% blocktrans with used=usage.limits.totalInstancesUsed|intcomma available=usage.limits.maxTotalInstances|quotainf|intcomma %}Used <span> {{ used }} </span> of <span> {{ available }} </span>{% endblocktrans %}
<div class="d3_pie_chart_usage" data-used="{% quotapercent quota.used quota.max %}"></div>
<strong> {{ quota.name }} <br />
{{ quota.text|default:_("Used") }}
<span> {{quota.used|intcomma }} </span>
{% if quota.max|quotainf != '-1' %}
{% trans "of" %} <span> {{ quota.max|quotainf|intcomma }} </span>
{% else %}
<span> {% trans "(No Limit)" %} </span>
{% endif %}
</strong>
</div>
{% endfor %}
<div class="d3_quota_bar">
<div class="d3_pie_chart_usage" data-used="{% quotapercent usage.limits.totalCoresUsed usage.limits.maxTotalCores %}"></div>
<strong>{% trans "VCPUs" %} <br />
{% blocktrans with used=usage.limits.totalCoresUsed|intcomma available=usage.limits.maxTotalCores|quotainf|intcomma %}Used <span> {{ used }} </span> of <span> {{ available }} </span>{% endblocktrans %}
</strong>
</div>
<div class="d3_quota_bar">
<div class="d3_pie_chart_usage" data-used="{% quotapercent usage.limits.totalRAMUsed usage.limits.maxTotalRAMSize %}"></div>
<strong>{% trans "RAM" %} <br />
{% blocktrans with used=usage.limits.totalRAMUsed|mb_float_format available=usage.limits.maxTotalRAMSize|quotainf|mb_float_format %}Used <span> {{ used }} </span> of <span> {{ available }} </span>{% endblocktrans %}
</strong>
</div>
<div class="d3_quota_bar">
<div class="d3_pie_chart_usage" data-used="{% quotapercent usage.limits.totalFloatingIpsUsed usage.limits.maxTotalFloatingIps %}"></div>
<strong>{% trans "Floating IPs" %} <br />
{% blocktrans with used=usage.limits.totalFloatingIpsUsed|intcomma available=usage.limits.maxTotalFloatingIps|quotainf|intcomma %}Allocated <span> {{ used }} </span> of <span> {{ available }} </span>{% endblocktrans %}
</strong>
</div>
<div class="d3_quota_bar">
<div class="d3_pie_chart_usage" data-used="{% quotapercent usage.limits.totalSecurityGroupsUsed usage.limits.maxSecurityGroups %}"></div>
<strong>{% trans "Security Groups" %} <br />
{% blocktrans with used=usage.limits.totalSecurityGroupsUsed|intcomma available=usage.limits.maxSecurityGroups|quotainf|intcomma %}Used <span> {{ used }} </span> of <span> {{ available }} </span>{% endblocktrans %}
</strong>
</div>
{% if usage.limits.totalVolumesUsed >= 0 %}
<div class="d3_quota_bar">
<div class="d3_pie_chart_usage" data-used="{% quotapercent usage.limits.totalVolumesUsed usage.limits.maxTotalVolumes %}"></div>
<strong>{% trans "Volumes" %} <br />
{% blocktrans with used=usage.limits.totalVolumesUsed|intcomma available=usage.limits.maxTotalVolumes|quotainf|intcomma %}Used <span> {{ used }} </span> of <span> {{ available }} </span>{% endblocktrans %}
</strong>
</div>
<div class="d3_quota_bar">
<div class="d3_pie_chart_usage" data-used="{% quotapercent usage.limits.totalGigabytesUsed usage.limits.maxTotalVolumeGigabytes %}"></div>
<strong>{% trans "Volume Storage" %} <br />
{% blocktrans with used=usage.limits.totalGigabytesUsed|diskgbformat available=usage.limits.maxTotalVolumeGigabytes|quotainf|diskgbformat %}Used <span> {{ used }} </span> of <span> {{ available }} </span>{% endblocktrans %}
</strong>
</div>
{% endif %}
</div>

View File

@ -134,7 +134,7 @@ def horizon_dashboard_nav(context):
@register.filter
def quota(val, units=None):
if val == float("inf"):
return _("No Limit")
return _("(No Limit)")
elif units is not None:
return "%s %s %s" % (val, force_text(units),
force_text(_("Available")))
@ -145,7 +145,7 @@ def quota(val, units=None):
@register.filter
def quotainf(val, units=None):
if val == float("inf"):
return _("No Limit")
return '-1'
elif units is not None:
return "%s %s" % (val, units)
else:

View File

@ -104,7 +104,7 @@ class TemplateTagTests(test.TestCase):
text = ('{{ test.val1|quota:"TB" }}#{{ test.val2|quota }}#'
'{{ test.val3|quota }}')
expected = u' 100 TB Available#1000 Available#No Limit'
expected = u' 100 TB Available#1000 Available#(No Limit)'
rendered_str = self.render_template(tag_require='horizon',
template_text=text,

View File

@ -240,13 +240,16 @@ class UsageViewTests(test.TestCase):
.AndReturn(self.neutron_quotas.first())
self.mox.ReplayAll()
self._test_usage_with_neutron_check(neutron_sg_enabled)
self._test_usage_with_neutron_check(neutron_sg_enabled,
neutron_fip_enabled)
def _test_usage_with_neutron_check(self, neutron_sg_enabled=True,
neutron_fip_expected=True,
max_fip_expected=50,
max_sg_expected=20):
res = self.client.get(reverse('horizon:project:overview:index'))
self.assertContains(res, 'Floating IPs')
if neutron_fip_expected:
self.assertContains(res, 'Floating IPs')
self.assertContains(res, 'Security Groups')
res_limits = res.context['usage'].limits
@ -264,7 +267,8 @@ class UsageViewTests(test.TestCase):
api.neutron.is_extension_supported(
IsA(http.HttpRequest), 'quotas').AndRaise(self.exceptions.neutron)
self.mox.ReplayAll()
self._test_usage_with_neutron_check(max_fip_expected=float("inf"),
self._test_usage_with_neutron_check(neutron_fip_expected=False,
max_fip_expected=float("inf"),
max_sg_expected=float("inf"))
@test.update_settings(OPENSTACK_NEUTRON_NETWORK={'enable_quotas': True})
@ -276,7 +280,8 @@ class UsageViewTests(test.TestCase):
IsA(http.HttpRequest),
'security-group').AndRaise(self.exceptions.neutron)
self.mox.ReplayAll()
self._test_usage_with_neutron_check(max_fip_expected=float("inf"),
self._test_usage_with_neutron_check(neutron_fip_expected=False,
max_fip_expected=float("inf"),
max_sg_expected=float("inf"))
def test_usage_with_cinder(self):
@ -309,3 +314,23 @@ class UsageViewTests(test.TestCase):
self.assertEqual(usages.limits['maxTotalVolumeGigabytes'], 1000)
else:
self.assertNotIn('totalVolumesUsed', usages.limits)
def _test_usage_charts(self):
self._stub_nova_api_calls(False)
self._stub_neutron_api_calls()
self._stub_cinder_api_calls()
self.mox.ReplayAll()
return self.client.get(reverse('horizon:project:overview:index'))
def test_usage_charts_created(self):
res = self._test_usage_charts()
self.assertTrue('charts' in res.context)
def test_usage_charts_infinite_quota(self):
res = self._test_usage_charts()
max_floating_ips = res.context['usage'].limits['maxTotalFloatingIps']
self.assertEqual(max_floating_ips, float("inf"))
self.assertContains(res, '(No Limit)')

View File

@ -60,6 +60,36 @@ class UsageView(tables.DataTableView):
context['table'].kwargs['usage'] = self.usage
context['form'] = self.usage.form
context['usage'] = self.usage
context['charts'] = []
# (Used key, Max key, Human Readable Name, text to display when
# describing the quota by default it is 'Used')
types = [("totalInstancesUsed", "maxTotalInstances", _("Instances")),
("totalCoresUsed", "maxTotalCores", _("VCPUs")),
("totalRAMUsed", "maxTotalRAMSize", _("RAM")),
("totalFloatingIpsUsed", "maxTotalFloatingIps",
"Floating IPs", _("Allocated")),
("totalSecurityGroupsUsed", "maxSecurityGroups",
_("Security Groups"))]
# Check for volume usage
if 'totalVolumesUsed' in self.usage.limits and self.usage.limits[
'totalVolumesUsed'] >= 0:
types.append(("totalVolumesUsed", "maxTotalVolumes",
_("Volumes")))
types.append(("totalGigabytesUsed", "maxTotalVolumeGigabytes",
_("Volume Storage")))
for t in types:
if t[0] in self.usage.limits and t[1] in self.usage.limits:
text = False
if len(t) > 3:
text = t[3]
context['charts'].append({
'name': t[2],
'used': self.usage.limits[t[0]],
'max': self.usage.limits[t[1]],
'text': text
})
try:
context['simple_tenant_usage_enabled'] = \
api.nova.extension_supported('SimpleTenantUsage', self.request)