From 14b2e700e8157ccefecb323962358e31d0676e69 Mon Sep 17 00:00:00 2001 From: Rob Date: Tue, 20 Jan 2015 16:41:46 -0800 Subject: [PATCH] Fixes inconsistent Router Details page This patch addresses the stylistic inconsistencies in the Router details pages, by changing it into a tabbed detail page - Fixed bug on the Interfaces table causing the Name field to be empty - Overview page has also been restyled to more clearly show information and link to relevant network - Increased inheritance where possible, to reduce duplicate code - Deleted unused files/functions. These can always be added as required later, but there is no need for unnecessary code bloat Co-Authored-By: Sam Betts Change-Id: Ifbdfbf46127e9445395207c547c2b81ea9459dac Closes-Bug: 1378895 --- .../admin/routers/extensions/__init__.py | 0 .../extensions/routerrules/__init__.py | 0 .../routers/extensions/routerrules/tables.py | 29 ------------ .../dashboards/admin/routers/ports/tables.py | 3 ++ .../dashboards/admin/routers/tabs.py | 10 ++-- .../templates/routers/_detail_overview.html | 32 ------------- .../routers/templates/routers/detail.html | 9 ++-- .../routers/extensions/routerrules/tabs.py | 16 ++++--- .../dashboards/project/routers/tabs.py | 33 +++++-------- .../templates/routers/_detail_overview.html | 47 ++++++++++++++----- .../routers/templates/routers/detail.html | 9 ++-- .../dashboards/project/routers/tests.py | 4 -- .../dashboards/project/routers/views.py | 18 +++++-- 13 files changed, 88 insertions(+), 122 deletions(-) delete mode 100644 openstack_dashboard/dashboards/admin/routers/extensions/__init__.py delete mode 100644 openstack_dashboard/dashboards/admin/routers/extensions/routerrules/__init__.py delete mode 100644 openstack_dashboard/dashboards/admin/routers/extensions/routerrules/tables.py delete mode 100644 openstack_dashboard/dashboards/admin/routers/templates/routers/_detail_overview.html diff --git a/openstack_dashboard/dashboards/admin/routers/extensions/__init__.py b/openstack_dashboard/dashboards/admin/routers/extensions/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/openstack_dashboard/dashboards/admin/routers/extensions/routerrules/__init__.py b/openstack_dashboard/dashboards/admin/routers/extensions/routerrules/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/openstack_dashboard/dashboards/admin/routers/extensions/routerrules/tables.py b/openstack_dashboard/dashboards/admin/routers/extensions/routerrules/tables.py deleted file mode 100644 index 32e2109e51..0000000000 --- a/openstack_dashboard/dashboards/admin/routers/extensions/routerrules/tables.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2013, Big Switch Networks, Inc. -# -# 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.utils.translation import ugettext_lazy as _ - -from horizon import tables - - -class RouterRulesTable(tables.DataTable): - source = tables.Column("source", verbose_name=_("Source CIDR")) - destination = tables.Column("destination", - verbose_name=_("Destination CIDR")) - action = tables.Column("action", verbose_name=_("Action")) - nexthops = tables.Column("nexthops", verbose_name=_("Next Hops")) - - class Meta(object): - name = "routerrules" - verbose_name = _("Router Rules") diff --git a/openstack_dashboard/dashboards/admin/routers/ports/tables.py b/openstack_dashboard/dashboards/admin/routers/ports/tables.py index c093a5de6e..5d36307ce6 100644 --- a/openstack_dashboard/dashboards/admin/routers/ports/tables.py +++ b/openstack_dashboard/dashboards/admin/routers/ports/tables.py @@ -27,3 +27,6 @@ class PortsTable(routers_tables.PortsTable): class Meta(object): name = "interfaces" verbose_name = _("Interfaces") + table_actions = (routers_tables.AddInterface, + routers_tables.RemoveInterface) + row_actions = (routers_tables.RemoveInterface,) diff --git a/openstack_dashboard/dashboards/admin/routers/tabs.py b/openstack_dashboard/dashboards/admin/routers/tabs.py index 44813193a6..a60389fc8a 100644 --- a/openstack_dashboard/dashboards/admin/routers/tabs.py +++ b/openstack_dashboard/dashboards/admin/routers/tabs.py @@ -12,16 +12,14 @@ # License for the specific language governing permissions and limitations # under the License. -from openstack_dashboard.dashboards.admin.\ - routers.extensions.routerrules import tables as rrtbl from openstack_dashboard.dashboards.admin.routers.ports import tables as ptbl from openstack_dashboard.dashboards.project.routers.extensions.routerrules\ import tabs as rr_tabs from openstack_dashboard.dashboards.project.routers import tabs as r_tabs -class RouterRulesTab(rr_tabs.RouterRulesTab): - table_classes = (rrtbl.RouterRulesTable,) +class OverviewTab(r_tabs.OverviewTab): + template_name = "project/routers/_detail_overview.html" class InterfacesTab(r_tabs.InterfacesTab): @@ -29,6 +27,6 @@ class InterfacesTab(r_tabs.InterfacesTab): class RouterDetailTabs(r_tabs.RouterDetailTabs): - slug = "router_details" - tabs = (InterfacesTab, rr_tabs.RouterRulesTab) + tabs = (OverviewTab, InterfacesTab, rr_tabs.RulesGridTab, + rr_tabs.RouterRulesTab) sticky = True diff --git a/openstack_dashboard/dashboards/admin/routers/templates/routers/_detail_overview.html b/openstack_dashboard/dashboards/admin/routers/templates/routers/_detail_overview.html deleted file mode 100644 index 095a81eaec..0000000000 --- a/openstack_dashboard/dashboards/admin/routers/templates/routers/_detail_overview.html +++ /dev/null @@ -1,32 +0,0 @@ -{% load i18n sizeformat parse_date %} - -

{% blocktrans with router_name=router.name %}Router Overview: {{ router_name }}{% endblocktrans %}

- -
-
-
{% trans "Name" %}
-
{{ router.name|default:_("None") }}
-
{% trans "ID" %}
-
{{ router.id }}
-
{% trans "Project ID" %}
-
{{ router.tenant_id }}
-
{% trans "Status" %}
-
{{ router.status|capfirst }}
-
{% trans "Admin State" %}
-
{{ router.admin_state|default:_("Unknown") }}
- {% if dvr_supported %} -
{% trans "Distributed" %}
-
{{ router.distributed|yesno|capfirst }}
- {% endif %} - {% if ha_supported %} -
{% trans "High Availability Mode" %}
-
{{ router.ha|yesno|capfirst }}
- {% endif %} - {% if router.external_gateway_info %} -
{% trans "External Gateway Information" %}
-
- {% blocktrans with router_gw_info_network=router.external_gateway_info.network %}Connected External Network: {{ router_gw_info_network }}{% endblocktrans %} -
- {% endif %} -
-
\ No newline at end of file diff --git a/openstack_dashboard/dashboards/admin/routers/templates/routers/detail.html b/openstack_dashboard/dashboards/admin/routers/templates/routers/detail.html index cb7125820d..1a32366505 100644 --- a/openstack_dashboard/dashboards/admin/routers/templates/routers/detail.html +++ b/openstack_dashboard/dashboards/admin/routers/templates/routers/detail.html @@ -3,10 +3,9 @@ {% block title %}{% trans "Router Details" %}{% endblock %} {% block main %} -
-
- {% include "admin/routers/_detail_overview.html" %} - {{ tab_group.render }} +
+
+ {{ tab_group.render }} +
-
{% endblock %} diff --git a/openstack_dashboard/dashboards/project/routers/extensions/routerrules/tabs.py b/openstack_dashboard/dashboards/project/routers/extensions/routerrules/tabs.py index dc5781d11c..1de7761b05 100644 --- a/openstack_dashboard/dashboards/project/routers/extensions/routerrules/tabs.py +++ b/openstack_dashboard/dashboards/project/routers/extensions/routerrules/tabs.py @@ -35,14 +35,15 @@ class RouterRulesTab(tabs.TableTab): def allowed(self, request): try: - getattr(self.tab_group.router, 'router_rules') + getattr(self.tab_group.kwargs['router'], 'router_rules') return True except Exception: return False def get_routerrules_data(self): try: - routerrules = getattr(self.tab_group.router, 'router_rules') + routerrules = getattr(self.tab_group.kwargs['router'], + 'router_rules') except Exception: routerrules = [] return [rulemanager.RuleObject(r) for r in routerrules] @@ -51,8 +52,8 @@ class RouterRulesTab(tabs.TableTab): if request.POST['action'] == 'routerrules__resetrules': kwargs['reset_rules'] = True rulemanager.remove_rules(request, [], **kwargs) - self.tab_group.router = api.neutron.router_get(request, - kwargs['router_id']) + self.tab_group.kwargs['router'] = \ + api.neutron.router_get(request, kwargs['router_id']) class RulesGridTab(tabs.Tab): @@ -62,7 +63,7 @@ class RulesGridTab(tabs.Tab): def allowed(self, request): try: - getattr(self.tab_group.router, 'router_rules') + getattr(self.tab_group.kwargs['router'], 'router_rules') return True except Exception: return False @@ -82,7 +83,7 @@ class RulesGridTab(tabs.Tab): return data def get_routerrulesgrid_data(self, rules): - ports = self.tab_group.ports + ports = self.tab_group.kwargs['ports'] networks = api.neutron.network_list_for_tenant( self.request, self.request.user.tenant_id) netnamemap = {} @@ -214,7 +215,8 @@ class RulesGridTab(tabs.Tab): def get_routerrules_data(self, checksupport=False): try: - routerrules = getattr(self.tab_group.router, 'router_rules') + routerrules = getattr(self.tab_group.kwargs['router'], + 'router_rules') supported = True except Exception: routerrules = [] diff --git a/openstack_dashboard/dashboards/project/routers/tabs.py b/openstack_dashboard/dashboards/project/routers/tabs.py index d4f8d120d4..1dbf1ab4a1 100644 --- a/openstack_dashboard/dashboards/project/routers/tabs.py +++ b/openstack_dashboard/dashboards/project/routers/tabs.py @@ -14,14 +14,22 @@ from django.utils.translation import ugettext_lazy as _ -from horizon import exceptions from horizon import tabs -from openstack_dashboard import api + from openstack_dashboard.dashboards.project.routers.extensions.routerrules\ import tabs as rr_tabs from openstack_dashboard.dashboards.project.routers.ports import tables as ptbl +class OverviewTab(tabs.Tab): + name = _("Overview") + slug = "overview" + template_name = "project/routers/_detail_overview.html" + + def get_context_data(self, request): + return {"router": self.tab_group.kwargs['router']} + + class InterfacesTab(tabs.TableTab): table_classes = (ptbl.PortsTable,) name = _("Interfaces") @@ -29,26 +37,11 @@ class InterfacesTab(tabs.TableTab): template_name = "horizon/common/_detail_table.html" def get_interfaces_data(self): - ports = self.tab_group.ports - return ports + return self.tab_group.kwargs['ports'] class RouterDetailTabs(tabs.TabGroup): slug = "router_details" - tabs = (InterfacesTab, rr_tabs.RulesGridTab, rr_tabs.RouterRulesTab) + tabs = (OverviewTab, InterfacesTab, rr_tabs.RulesGridTab, + rr_tabs.RouterRulesTab) sticky = True - - def __init__(self, request, **kwargs): - rid = kwargs['router_id'] - self.router = {} - if 'router' in kwargs: - self.router = kwargs['router'] - else: - self.router = api.neutron.router_get(request, rid) - try: - self.ports = api.neutron.port_list(request, device_id=rid) - except Exception: - self.ports = [] - msg = _('Unable to retrieve router details.') - exceptions.handle(request, msg) - super(RouterDetailTabs, self).__init__(request, **kwargs) diff --git a/openstack_dashboard/dashboards/project/routers/templates/routers/_detail_overview.html b/openstack_dashboard/dashboards/project/routers/templates/routers/_detail_overview.html index d9a673fa2b..ad33d11491 100644 --- a/openstack_dashboard/dashboards/project/routers/templates/routers/_detail_overview.html +++ b/openstack_dashboard/dashboards/project/routers/templates/routers/_detail_overview.html @@ -1,17 +1,15 @@ {% load i18n sizeformat parse_date %} -

- {% blocktrans with router_name=router.name|default:_("None") %}Router Overview: {{ router_name }}{% endblocktrans %} -

- -
+
{% trans "Name" %}
{{ router.name|default:_("None") }}
{% trans "ID" %}
-
{{ router.id|default:_("None") }}
+
{{ router.id }}
+
{% trans "Project ID" %}
+
{{ router.tenant_id }}
{% trans "Status" %}
-
{{ router.status|default:_("Unknown") }}
+
{{ router.status|capfirst }}
{% trans "Admin State" %}
{{ router.admin_state|default:_("Unknown") }}
{% if dvr_supported %} @@ -22,11 +20,38 @@
{% trans "High Availability Mode" %}
{{ router.ha|yesno|capfirst }}
{% endif %} + {% if router.external_gateway_info %} -
{% trans "External Gateway" %}
-
{% trans "Connected External Network:" %} - {{ router.external_gateway_info.network }}
+
+

{% trans "External Gateway" %}

+
+
+
{% trans "Network Name" %}
+
{{ router.external_gateway_info.network|default:_("None") }}
+ {% url 'horizon:admin:networks:detail' router.external_gateway_info.network_id as network_url %} +
{% trans "Network ID" %}
+
{{ router.external_gateway_info.network_id|default:_("Unknown") }}
+
{% trans "External Fixed IPs" %}
+
+
    + {% for ip in router.external_gateway_info.external_fixed_ips %} + {% url 'horizon:project:networks:subnets:detail' ip.subnet_id as subnet_url %} +
  • {% trans "Subnet ID" %} {{ ip.subnet_id|default:_("Unknown") }}
  • +
  • {% trans "IP Address" %} {{ ip.ip_address }}
  • + {% empty %} + {% trans "None" %} + {% endfor %} +
+
+
{% trans "SNAT" %}
+ {% if router.external_gateway_info.enable_snat %} +
{% trans "Enabled" %}
+ {% else %} +
{% trans "Disabled" %}
+ {% endif %} + {% else %} +
{% trans "External Gateway"%}
+
{% trans "None" %}
{% endif %}
- diff --git a/openstack_dashboard/dashboards/project/routers/templates/routers/detail.html b/openstack_dashboard/dashboards/project/routers/templates/routers/detail.html index 066847514b..1a32366505 100644 --- a/openstack_dashboard/dashboards/project/routers/templates/routers/detail.html +++ b/openstack_dashboard/dashboards/project/routers/templates/routers/detail.html @@ -3,10 +3,9 @@ {% block title %}{% trans "Router Details" %}{% endblock %} {% block main %} -
-
- {% include "project/routers/_detail_overview.html" %} - {{ tab_group.render }} +
+
+ {{ tab_group.render }} +
-
{% endblock %} diff --git a/openstack_dashboard/dashboards/project/routers/tests.py b/openstack_dashboard/dashboards/project/routers/tests.py index c982be2558..cbfcfb8618 100644 --- a/openstack_dashboard/dashboards/project/routers/tests.py +++ b/openstack_dashboard/dashboards/project/routers/tests.py @@ -760,8 +760,6 @@ class RouterRuleTests(RouterMixin, test.TestCase): params = {} params['router_rules'] = rulemanager.format_for_api( post_router['router_rules']) - api.neutron.router_get(IsA(http.HttpRequest), - pre_router.id).AndReturn(pre_router) router_update = api.neutron.router_update(IsA(http.HttpRequest), pre_router.id, **params) router_update.AndReturn({'router': post_router}) @@ -797,8 +795,6 @@ class RouterRuleTests(RouterMixin, test.TestCase): router_update = api.neutron.router_update(IsA(http.HttpRequest), pre_router.id, **params) router_update.AndReturn({'router': post_router}) - api.neutron.router_get(IsA(http.HttpRequest), - pre_router.id).AndReturn(post_router) api.neutron.port_list(IsA(http.HttpRequest), device_id=pre_router.id)\ .AndReturn([self.ports.first()]) diff --git a/openstack_dashboard/dashboards/project/routers/views.py b/openstack_dashboard/dashboards/project/routers/views.py index 0fbb5eb25e..591c578f00 100644 --- a/openstack_dashboard/dashboards/project/routers/views.py +++ b/openstack_dashboard/dashboards/project/routers/views.py @@ -125,6 +125,17 @@ class DetailView(tabs.TabbedTableView): router.external_gateway_info['network'] = ext_net_id return router + @memoized.memoized_method + def _get_ports(self): + try: + ports = api.neutron.port_list(self.request, + device_id=self.kwargs['router_id']) + except Exception: + ports = [] + msg = _('Unable to retrieve port details.') + exceptions.handle(self.request, msg) + return ports + def get_context_data(self, **kwargs): context = super(DetailView, self).get_context_data(**kwargs) router = self._get_data() @@ -140,10 +151,11 @@ class DetailView(tabs.TabbedTableView): return context - def get(self, request, *args, **kwargs): + def get_tabs(self, request, *args, **kwargs): router = self._get_data() - self.kwargs['router'] = router - return super(DetailView, self).get(request, *args, **kwargs) + ports = self._get_ports() + return self.tab_group_class(request, router=router, + ports=ports, **kwargs) class CreateView(forms.ModalFormView):