summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--horizon/base.py11
-rw-r--r--openstack_dashboard/dashboards/admin/networks/tables.py4
-rw-r--r--openstack_dashboard/dashboards/project/instances/templates/instances/_flavors_and_quotas.html6
-rw-r--r--openstack_dashboard/dashboards/project/instances/utils.py2
-rw-r--r--openstack_dashboard/dashboards/project/volumes/templates/volumes/volumes/_extend_limits.html2
-rw-r--r--openstack_dashboard/dashboards/project/volumes/templates/volumes/volumes/_limits.html4
-rw-r--r--openstack_dashboard/dashboards/project/volumes/templates/volumes/volumes/_snapshot_limits.html2
-rw-r--r--openstack_dashboard/test/helpers.py3
-rw-r--r--openstack_dashboard/test/test_panels/plugin_panel/views.py4
-rw-r--r--openstack_dashboard/test/test_panels/second_panel/__init__.py0
-rw-r--r--openstack_dashboard/test/test_panels/second_panel/panel.py18
-rw-r--r--openstack_dashboard/test/test_panels/second_panel/templates/second_panel/index.html11
-rw-r--r--openstack_dashboard/test/test_panels/second_panel/urls.py21
-rw-r--r--openstack_dashboard/test/test_panels/second_panel/views.py18
-rw-r--r--openstack_dashboard/test/test_plugins/panel_group_config/_30_admin_add_second_panel_group.py6
-rw-r--r--openstack_dashboard/test/test_plugins/panel_group_config/_40_admin_add_panel_to_second_group.py10
-rw-r--r--openstack_dashboard/test/test_plugins/panel_group_tests.py28
-rw-r--r--openstack_dashboard/test/test_plugins/panel_tests.py10
-rw-r--r--requirements.txt2
19 files changed, 140 insertions, 22 deletions
diff --git a/horizon/base.py b/horizon/base.py
index ee0bf2d09..61f944f0f 100644
--- a/horizon/base.py
+++ b/horizon/base.py
@@ -871,14 +871,21 @@ class Site(Registry, HorizonComponent):
"""
panel_customization = self._conf.get("panel_customization", [])
+ # Process all the panel groups first so that they exist before panels
+ # are added to them and Dashboard._autodiscover() doesn't wipe out any
+ # panels previously added when its panel groups are instantiated.
+ panel_configs = []
for config in panel_customization:
if config.get('PANEL'):
- self._process_panel_configuration(config)
+ panel_configs.append(config)
elif config.get('PANEL_GROUP'):
self._process_panel_group_configuration(config)
else:
LOG.warning("Skipping %s because it doesn't have PANEL or "
"PANEL_GROUP defined.", config.__name__)
+ # Now process the panels.
+ for config in panel_configs:
+ self._process_panel_configuration(config)
def _process_panel_configuration(self, config):
"""Add, remove and set default panels on the dashboard."""
@@ -914,8 +921,6 @@ class Site(Registry, HorizonComponent):
panel = getattr(mod, panel_cls)
dashboard_cls.register(panel)
if panel_group:
- dashboard_cls.get_panel_group(panel_group).__class__.\
- panels.append(panel.slug)
dashboard_cls.get_panel_group(panel_group).\
panels.append(panel.slug)
else:
diff --git a/openstack_dashboard/dashboards/admin/networks/tables.py b/openstack_dashboard/dashboards/admin/networks/tables.py
index 9807f124d..6b2fc2590 100644
--- a/openstack_dashboard/dashboards/admin/networks/tables.py
+++ b/openstack_dashboard/dashboards/admin/networks/tables.py
@@ -99,7 +99,9 @@ class NetworksTable(tables.DataTable):
verbose_name=_("DHCP Agents"))
shared = tables.Column("shared", verbose_name=_("Shared"),
filters=(filters.yesno, filters.capfirst))
- status = tables.Column("status", verbose_name=_("Status"))
+ status = tables.Column(
+ "status", verbose_name=_("Status"),
+ display_choices=project_tables.STATUS_DISPLAY_CHOICES)
admin_state = tables.Column("admin_state",
verbose_name=_("Admin State"),
display_choices=DISPLAY_CHOICES)
diff --git a/openstack_dashboard/dashboards/project/instances/templates/instances/_flavors_and_quotas.html b/openstack_dashboard/dashboards/project/instances/templates/instances/_flavors_and_quotas.html
index 8c3416f0d..e14d15933 100644
--- a/openstack_dashboard/dashboards/project/instances/templates/instances/_flavors_and_quotas.html
+++ b/openstack_dashboard/dashboards/project/instances/templates/instances/_flavors_and_quotas.html
@@ -19,21 +19,21 @@
<h4>{% trans "Project Limits" %}</h4>
<div class="quota_title clearfix">
<strong>{% trans "Number of Instances" %}</strong>
- {% blocktrans with used=usages.totalInstancesUsed|intcomma quota=usages.maxTotalInstances|quotainf|intcomma %}<p>{{ used }} of {{ quota }} Used</p>{% endblocktrans %}
+ {% blocktrans with used=usages.totalInstancesUsed|intcomma quota=usages.maxTotalInstances|intcomma|quotainf %}<p>{{ used }} of {{ quota }} Used</p>{% endblocktrans %}
</div>
<div id="{{ resize_instance|yesno:"quota_resize_instance,quota_instances" }}" class="quota_bar" data-progress-indicator-flavor data-quota-limit="{{ usages.maxTotalInstances }}" data-quota-used="{{ usages.totalInstancesUsed }}">
</div>
<div class="quota_title clearfix">
<strong>{% trans "Number of VCPUs" %}</strong>
- {% blocktrans with used=usages.totalCoresUsed|intcomma quota=usages.maxTotalCores|quotainf|intcomma %}<p>{{ used }} of {{ quota }} Used</p>{% endblocktrans %}
+ {% blocktrans with used=usages.totalCoresUsed|intcomma quota=usages.maxTotalCores|intcomma|quotainf %}<p>{{ used }} of {{ quota }} Used</p>{% endblocktrans %}
</div>
<div id="quota_vcpus" class="quota_bar" data-progress-indicator-flavor data-quota-limit="{{ usages.maxTotalCores }}" data-quota-used="{{ usages.totalCoresUsed }}">
</div>
<div class="quota_title clearfix">
<strong>{% trans "Total RAM" %}</strong>
- {% blocktrans with used=usages.totalRAMUsed|intcomma quota=usages.maxTotalRAMSize|quotainf|intcomma %}<p>{{ used }} of {{ quota }} MB Used</p>{% endblocktrans %}
+ {% blocktrans with used=usages.totalRAMUsed|intcomma quota=usages.maxTotalRAMSize|intcomma|quotainf %}<p>{{ used }} of {{ quota }} MB Used</p>{% endblocktrans %}
</div>
<div id="quota_ram" data-progress-indicator-flavor data-quota-limit="{{ usages.maxTotalRAMSize }}" data-quota-used="{{ usages.totalRAMUsed }}" class="quota_bar">
</div>
diff --git a/openstack_dashboard/dashboards/project/instances/utils.py b/openstack_dashboard/dashboards/project/instances/utils.py
index 730701247..5c2880126 100644
--- a/openstack_dashboard/dashboards/project/instances/utils.py
+++ b/openstack_dashboard/dashboards/project/instances/utils.py
@@ -86,6 +86,7 @@ def network_field_data(request, include_empty_option=False):
:return: list of (id, name) tuples
"""
tenant_id = request.user.tenant_id
+ networks = []
try:
networks = api.neutron.network_list_for_tenant(request, tenant_id)
networks = [(n.id, n.name_or_id) for n in networks]
@@ -121,7 +122,6 @@ def keypair_field_data(request, include_empty_option=False):
keypair_list = [(kp.name, kp.name) for kp in keypairs]
except Exception:
exceptions.handle(request, _('Unable to retrieve key pairs.'))
- keypair_list = []
if not keypair_list:
if include_empty_option:
diff --git a/openstack_dashboard/dashboards/project/volumes/templates/volumes/volumes/_extend_limits.html b/openstack_dashboard/dashboards/project/volumes/templates/volumes/volumes/_extend_limits.html
index 6ec6a03ea..815ceeba8 100644
--- a/openstack_dashboard/dashboards/project/volumes/templates/volumes/volumes/_extend_limits.html
+++ b/openstack_dashboard/dashboards/project/volumes/templates/volumes/volumes/_extend_limits.html
@@ -8,7 +8,7 @@
<div class="quota_title clearfix">
<strong>{% trans "Total Gigabytes" %} <span>({{ usages.gigabytesUsed|intcomma }} {% trans "GB" %})</span></strong>
- <p>{{ usages.maxTotalVolumeGigabytes|quota:_("GB")|intcomma }}</p>
+ <p>{{ usages.maxTotalVolumeGigabytes|intcomma|quota:_("GB") }}</p>
</div>
<div id="quota_size" data-progress-indicator-for="id_new_size" data-quota-limit="{{ usages.maxTotalVolumeGigabytes }}" data-quota-used="{{ usages.gigabytesUsed }}" class="quota_bar">
diff --git a/openstack_dashboard/dashboards/project/volumes/templates/volumes/volumes/_limits.html b/openstack_dashboard/dashboards/project/volumes/templates/volumes/volumes/_limits.html
index 7df18735e..27ad12306 100644
--- a/openstack_dashboard/dashboards/project/volumes/templates/volumes/volumes/_limits.html
+++ b/openstack_dashboard/dashboards/project/volumes/templates/volumes/volumes/_limits.html
@@ -8,7 +8,7 @@
<div class="quota_title clearfix">
<strong>{% trans "Total Gigabytes" %} <span>({% block gigabytes_used %}{{ usages.gigabytesUsed|intcomma }}{% endblock %} {% trans "GB" %})</span></strong>
- <p>{{ usages.maxTotalVolumeGigabytes|quota:_("GB")|intcomma }}</p>
+ <p>{{ usages.maxTotalVolumeGigabytes|intcomma|quota:_("GB") }}</p>
</div>
<div id="quota_size" data-progress-indicator-for="id_size" data-quota-limit="{{ usages.maxTotalVolumeGigabytes }}" data-quota-used={% block gigabytes_used_progress %}"{{ usages.gigabytesUsed }}"{% endblock %} class="quota_bar">
@@ -16,7 +16,7 @@
<div class="quota_title clearfix">
<strong>{% block type_title %}{% trans "Number of Volumes" %}{% endblock %} <span>({% block used %}{{ usages.volumesUsed|intcomma }}{% endblock %})</span></strong>
- <p>{% block total %}{{ usages.maxTotalVolumes|quota|intcomma }}{% endblock %}</p>
+ <p>{% block total %}{{ usages.maxTotalVolumes|intcomma|quota }}{% endblock %}</p>
</div>
<div id={% block type_id %}"quota_volumes"{% endblock %} data-progress-indicator-step-by="1" data-quota-limit={% block total_progress %}"{{ usages.maxTotalVolumes }}"{% endblock %} data-quota-used={% block used_progress %}"{{ usages.volumesUsed }}"{% endblock %} class="quota_bar">
diff --git a/openstack_dashboard/dashboards/project/volumes/templates/volumes/volumes/_snapshot_limits.html b/openstack_dashboard/dashboards/project/volumes/templates/volumes/volumes/_snapshot_limits.html
index cc8e14f67..1f3c5323f 100644
--- a/openstack_dashboard/dashboards/project/volumes/templates/volumes/volumes/_snapshot_limits.html
+++ b/openstack_dashboard/dashboards/project/volumes/templates/volumes/volumes/_snapshot_limits.html
@@ -26,7 +26,7 @@
{% endblock %}
{% block total %}
- {{ usages.maxTotalSnapshots|quota|intcomma }}
+ {{ usages.maxTotalSnapshots|intcomma|quota }}
{% endblock %}
{% block type_id %}
diff --git a/openstack_dashboard/test/helpers.py b/openstack_dashboard/test/helpers.py
index 324810ced..c73888542 100644
--- a/openstack_dashboard/test/helpers.py
+++ b/openstack_dashboard/test/helpers.py
@@ -534,9 +534,6 @@ class PluginTestCase(TestCase):
self.old_horizon_config = conf.HORIZON_CONFIG
conf.HORIZON_CONFIG = conf.LazySettings()
base.Horizon._urls()
- # Trigger discovery, registration, and URLconf generation if it
- # hasn't happened yet.
- self.client.get("/")
# Store our original dashboards
self._discovered_dashboards = base.Horizon._registry.keys()
# Gather up and store our original panels for each dashboard
diff --git a/openstack_dashboard/test/test_panels/plugin_panel/views.py b/openstack_dashboard/test/test_panels/plugin_panel/views.py
index db3f98b88..49c4f7ad2 100644
--- a/openstack_dashboard/test/test_panels/plugin_panel/views.py
+++ b/openstack_dashboard/test/test_panels/plugin_panel/views.py
@@ -10,11 +10,9 @@
# License for the specific language governing permissions and limitations
# under the License.
-from django.utils.translation import ugettext_lazy as _
-
from horizon import views
class IndexView(views.HorizonTemplateView):
template_name = 'admin/plugin_panel/index.html'
- page_title = _("Plugin-based Panel")
+ page_title = 'Plugin-based Panel'
diff --git a/openstack_dashboard/test/test_panels/second_panel/__init__.py b/openstack_dashboard/test/test_panels/second_panel/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/openstack_dashboard/test/test_panels/second_panel/__init__.py
diff --git a/openstack_dashboard/test/test_panels/second_panel/panel.py b/openstack_dashboard/test/test_panels/second_panel/panel.py
new file mode 100644
index 000000000..52f61b981
--- /dev/null
+++ b/openstack_dashboard/test/test_panels/second_panel/panel.py
@@ -0,0 +1,18 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import horizon
+
+
+class SecondPanel(horizon.Panel):
+ name = "Second Plugin Panel"
+ slug = 'second_panel'
diff --git a/openstack_dashboard/test/test_panels/second_panel/templates/second_panel/index.html b/openstack_dashboard/test/test_panels/second_panel/templates/second_panel/index.html
new file mode 100644
index 000000000..62a1d6b49
--- /dev/null
+++ b/openstack_dashboard/test/test_panels/second_panel/templates/second_panel/index.html
@@ -0,0 +1,11 @@
+{% extends 'base.html' %}
+{% load i18n %}
+{% block title %}Second Plugin-based Panel{% endblock %}
+
+{% block main %}
+<div class="row">
+ <div class="col-sm-12">
+ Second Plugin-based Panel
+ </div>
+</div>
+{% endblock %}
diff --git a/openstack_dashboard/test/test_panels/second_panel/urls.py b/openstack_dashboard/test/test_panels/second_panel/urls.py
new file mode 100644
index 000000000..277a98229
--- /dev/null
+++ b/openstack_dashboard/test/test_panels/second_panel/urls.py
@@ -0,0 +1,21 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from django.conf.urls import patterns
+from django.conf.urls import url
+
+from openstack_dashboard.test.test_panels.second_panel import views
+
+urlpatterns = patterns(
+ '',
+ url(r'^$', views.IndexView.as_view(), name='index'),
+)
diff --git a/openstack_dashboard/test/test_panels/second_panel/views.py b/openstack_dashboard/test/test_panels/second_panel/views.py
new file mode 100644
index 000000000..b656b6cb2
--- /dev/null
+++ b/openstack_dashboard/test/test_panels/second_panel/views.py
@@ -0,0 +1,18 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from horizon import views
+
+
+class IndexView(views.HorizonTemplateView):
+ template_name = 'admin/second_panel/index.html'
+ page_title = 'Second Plugin-based Panel'
diff --git a/openstack_dashboard/test/test_plugins/panel_group_config/_30_admin_add_second_panel_group.py b/openstack_dashboard/test/test_plugins/panel_group_config/_30_admin_add_second_panel_group.py
new file mode 100644
index 000000000..407d19984
--- /dev/null
+++ b/openstack_dashboard/test/test_plugins/panel_group_config/_30_admin_add_second_panel_group.py
@@ -0,0 +1,6 @@
+# The name of the panel group to be added to HORIZON_CONFIG. Required.
+PANEL_GROUP = 'second_panel_group'
+# The display name of the PANEL_GROUP. Required.
+PANEL_GROUP_NAME = 'Second Plugin Panel Group'
+# The name of the dashboard the PANEL_GROUP associated with. Required.
+PANEL_GROUP_DASHBOARD = 'admin'
diff --git a/openstack_dashboard/test/test_plugins/panel_group_config/_40_admin_add_panel_to_second_group.py b/openstack_dashboard/test/test_plugins/panel_group_config/_40_admin_add_panel_to_second_group.py
new file mode 100644
index 000000000..7ce597584
--- /dev/null
+++ b/openstack_dashboard/test/test_plugins/panel_group_config/_40_admin_add_panel_to_second_group.py
@@ -0,0 +1,10 @@
+# The name of the panel to be added to HORIZON_CONFIG. Required.
+PANEL = 'second_panel'
+# The name of the dashboard the PANEL associated with. Required.
+PANEL_DASHBOARD = 'admin'
+# The name of the panel group the PANEL is associated with.
+PANEL_GROUP = 'second_panel_group'
+
+# Python panel class of the PANEL to be added.
+ADD_PANEL = \
+ 'openstack_dashboard.test.test_panels.second_panel.panel.SecondPanel'
diff --git a/openstack_dashboard/test/test_plugins/panel_group_tests.py b/openstack_dashboard/test/test_plugins/panel_group_tests.py
index 4ae184f26..7e85802de 100644
--- a/openstack_dashboard/test/test_plugins/panel_group_tests.py
+++ b/openstack_dashboard/test/test_plugins/panel_group_tests.py
@@ -20,11 +20,14 @@ import horizon
from openstack_dashboard.test import helpers as test
from openstack_dashboard.test.test_panels.plugin_panel \
import panel as plugin_panel
+from openstack_dashboard.test.test_panels.second_panel \
+ import panel as second_panel
import openstack_dashboard.test.test_plugins.panel_group_config
from openstack_dashboard.utils import settings as util_settings
PANEL_GROUP_SLUG = 'plugin_panel_group'
+SECOND_PANEL_GROUP_SLUG = 'second_panel_group'
HORIZON_CONFIG = copy.deepcopy(settings.HORIZON_CONFIG)
INSTALLED_APPS = list(settings.INSTALLED_APPS)
@@ -45,12 +48,31 @@ class PanelGroupPluginTests(test.PluginTestCase):
dashboard = horizon.get_dashboard("admin")
self.assertIsNotNone(dashboard.get_panel_group(PANEL_GROUP_SLUG))
+ def test_add_second_panel_group(self):
+ # Check that the second panel group was added to the dashboard.
+ dashboard = horizon.get_dashboard("admin")
+ self.assertIsNotNone(
+ dashboard.get_panel_group(SECOND_PANEL_GROUP_SLUG))
+
def test_add_panel(self):
+ # Check that the panel is in its configured dashboard and panel group.
dashboard = horizon.get_dashboard("admin")
+ panel_group = dashboard.get_panel_group(PANEL_GROUP_SLUG)
self.assertIn(plugin_panel.PluginPanel,
[p.__class__ for p in dashboard.get_panels()])
+ self.assertIn(plugin_panel.PluginPanel,
+ [p.__class__ for p in panel_group])
- def test_unregistered_panel_group(self):
- dashboard = horizon.get_dashboard("admin")
- self.assertIsNone(dashboard.get_panel_group("nonexistent_panel"))
+ def test_add_second_panel(self):
+ # Check that the second panel is in its configured dashboard and panel
+ # group.
+ dashboard = horizon.get_dashboard("admin")
+ second_panel_group = dashboard.get_panel_group(SECOND_PANEL_GROUP_SLUG)
+ self.assertIn(second_panel.SecondPanel,
+ [p.__class__ for p in dashboard.get_panels()])
+ self.assertIn(second_panel.SecondPanel,
+ [p.__class__ for p in second_panel_group])
+ def test_unregistered_panel_group(self):
+ dashboard = horizon.get_dashboard("admin")
+ self.assertIsNone(dashboard.get_panel_group("nonexistent_panel"))
diff --git a/openstack_dashboard/test/test_plugins/panel_tests.py b/openstack_dashboard/test/test_plugins/panel_tests.py
index 059a3f509..83afb2612 100644
--- a/openstack_dashboard/test/test_plugins/panel_tests.py
+++ b/openstack_dashboard/test/test_plugins/panel_tests.py
@@ -43,13 +43,23 @@ util_settings.update_dashboards([
class PanelPluginTests(test.PluginTestCase):
def test_add_panel(self):
dashboard = horizon.get_dashboard("admin")
+ panel_group = dashboard.get_panel_group('admin')
+ # Check that the panel is in its configured dashboard.
self.assertIn(plugin_panel.PluginPanel,
[p.__class__ for p in dashboard.get_panels()])
+ # Check that the panel is in its configured panel group.
+ self.assertIn(plugin_panel.PluginPanel,
+ [p.__class__ for p in panel_group])
def test_remove_panel(self):
dashboard = horizon.get_dashboard("admin")
+ panel_group = dashboard.get_panel_group('admin')
+ # Check that the panel is no longer in the configured dashboard.
self.assertNotIn(info_panel.Info,
[p.__class__ for p in dashboard.get_panels()])
+ # Check that the panel is no longer in the configured panel group.
+ self.assertNotIn(info_panel.Info,
+ [p.__class__ for p in panel_group])
def test_default_panel(self):
dashboard = horizon.get_dashboard("admin")
diff --git a/requirements.txt b/requirements.txt
index 6c2f2f4d1..821b06fa1 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -14,7 +14,7 @@ Django>=1.4.2,<1.8
Pint>=0.5 # BSD
django_compressor>=1.4
django_openstack_auth>=1.1.7,!=1.1.8,<1.3.0
-django-pyscss>=1.0.3,!=2.0.0 # BSD License (2 clause)
+django-pyscss>=1.0.3,<2.0.0 # BSD License (2 clause)
eventlet>=0.16.1,!=0.17.0
httplib2>=0.7.5
iso8601>=0.1.9