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 <sam@code-smash.net> Change-Id: Ifbdfbf46127e9445395207c547c2b81ea9459dac Closes-Bug: 1378895
This commit is contained in:
parent
4fdc42cf63
commit
14b2e700e8
|
@ -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")
|
|
@ -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,)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
{% load i18n sizeformat parse_date %}
|
||||
|
||||
<h3>{% blocktrans with router_name=router.name %}Router Overview: {{ router_name }}{% endblocktrans %}</h3>
|
||||
|
||||
<div class="info detail">
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "Name" %}</dt>
|
||||
<dd>{{ router.name|default:_("None") }}</dd>
|
||||
<dt>{% trans "ID" %}</dt>
|
||||
<dd>{{ router.id }}</dd>
|
||||
<dt>{% trans "Project ID" %}</dt>
|
||||
<dd>{{ router.tenant_id }}</dd>
|
||||
<dt>{% trans "Status" %}</dt>
|
||||
<dd>{{ router.status|capfirst }}</dd>
|
||||
<dt>{% trans "Admin State" %}</dt>
|
||||
<dd>{{ router.admin_state|default:_("Unknown") }}</dd>
|
||||
{% if dvr_supported %}
|
||||
<dt>{% trans "Distributed" %}</dt>
|
||||
<dd>{{ router.distributed|yesno|capfirst }}</dd>
|
||||
{% endif %}
|
||||
{% if ha_supported %}
|
||||
<dt>{% trans "High Availability Mode" %}</dt>
|
||||
<dd>{{ router.ha|yesno|capfirst }}</dd>
|
||||
{% endif %}
|
||||
{% if router.external_gateway_info %}
|
||||
<dt>{% trans "External Gateway Information" %}</dt>
|
||||
<dd>
|
||||
{% blocktrans with router_gw_info_network=router.external_gateway_info.network %}Connected External Network: {{ router_gw_info_network }}{% endblocktrans %}
|
||||
</dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
</div>
|
|
@ -3,10 +3,9 @@
|
|||
{% block title %}{% trans "Router Details" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
{% include "admin/routers/_detail_overview.html" %}
|
||||
{{ tab_group.render }}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
{{ tab_group.render }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -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 = []
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
{% load i18n sizeformat parse_date %}
|
||||
|
||||
<h3>
|
||||
{% blocktrans with router_name=router.name|default:_("None") %}Router Overview: {{ router_name }}{% endblocktrans %}
|
||||
</h3>
|
||||
|
||||
<div class="info detail">
|
||||
<div class="detail">
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "Name" %}</dt>
|
||||
<dd>{{ router.name|default:_("None") }}</dd>
|
||||
<dt>{% trans "ID" %}</dt>
|
||||
<dd>{{ router.id|default:_("None") }}</dd>
|
||||
<dd>{{ router.id }}</dd>
|
||||
<dt>{% trans "Project ID" %}</dt>
|
||||
<dd>{{ router.tenant_id }}</dd>
|
||||
<dt>{% trans "Status" %}</dt>
|
||||
<dd>{{ router.status|default:_("Unknown") }}</dd>
|
||||
<dd>{{ router.status|capfirst }}</dd>
|
||||
<dt>{% trans "Admin State" %}</dt>
|
||||
<dd>{{ router.admin_state|default:_("Unknown") }}</dd>
|
||||
{% if dvr_supported %}
|
||||
|
@ -22,11 +20,38 @@
|
|||
<dt>{% trans "High Availability Mode" %}</dt>
|
||||
<dd>{{ router.ha|yesno|capfirst }}</dd>
|
||||
{% endif %}
|
||||
|
||||
{% if router.external_gateway_info %}
|
||||
<dt>{% trans "External Gateway" %}</dt>
|
||||
<dd>{% trans "Connected External Network:" %}
|
||||
{{ router.external_gateway_info.network }}</dd>
|
||||
</dl>
|
||||
<h4>{% trans "External Gateway" %}</h4>
|
||||
<hr class="header_rule">
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "Network Name" %}</dt>
|
||||
<dd>{{ router.external_gateway_info.network|default:_("None") }}</dd>
|
||||
{% url 'horizon:admin:networks:detail' router.external_gateway_info.network_id as network_url %}
|
||||
<dt>{% trans "Network ID" %}</dt>
|
||||
<dd><a href="{{ network_url }}">{{ router.external_gateway_info.network_id|default:_("Unknown") }}</a></dd>
|
||||
<dt>{% trans "External Fixed IPs" %}</dt>
|
||||
<dd>
|
||||
<ul>
|
||||
{% for ip in router.external_gateway_info.external_fixed_ips %}
|
||||
{% url 'horizon:project:networks:subnets:detail' ip.subnet_id as subnet_url %}
|
||||
<li><strong>{% trans "Subnet ID" %}</strong> <a href="{{ subnet_url }}">{{ ip.subnet_id|default:_("Unknown") }}</a></li>
|
||||
<li><strong>{% trans "IP Address" %}</strong> {{ ip.ip_address }}</li>
|
||||
{% empty %}
|
||||
{% trans "None" %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</dd>
|
||||
<dt>{% trans "SNAT" %}</dt>
|
||||
{% if router.external_gateway_info.enable_snat %}
|
||||
<dd>{% trans "Enabled" %}</dd>
|
||||
{% else %}
|
||||
<dd>{% trans "Disabled" %}</dd>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<dt>{% trans "External Gateway"%}</dt>
|
||||
<dd>{% trans "None" %}</dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -3,10 +3,9 @@
|
|||
{% block title %}{% trans "Router Details" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
{% include "project/routers/_detail_overview.html" %}
|
||||
{{ tab_group.render }}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
{{ tab_group.render }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -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()])
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue