Translate status in network topology

Enables the translation of the status on
network topology.
Provides a json decoder that will resolve
lazy objects like translations.
Moves STATUS_DISPLAY_CHOICES and
ADMIN_STATE_DISPLAY_CHOICES out of the RoutersTable
for easy access to their status from other parts
of the code.
All network objects have their status translated
and a new item called original_status which provides
the untranslated status so the javascript code
is able to display the proper image (green/red)
based on the original status instead of doing it
on the translation.

Change-Id: Ic8cebafe7fbc291fa8933e8d1c2a244be20128e3
Closes-Bug: #1323599
Closes-Bug: #1484113
This commit is contained in:
Itxaka 2016-01-15 12:29:52 +01:00 committed by Doug Fish
parent eb2554ad9b
commit 031aed50a3
6 changed files with 101 additions and 24 deletions

View File

@ -918,7 +918,7 @@ horizon.network_topology = {
object.router_id = port.device_id;
object.url = port.url;
object.port_status = port.status;
object.port_status_css = (port.status === 'ACTIVE') ? 'active' : 'down';
object.port_status_css = (port.original_status === 'ACTIVE') ? 'active' : 'down';
var ipAddress = '';
try {
for (var ip in port.fixed_ips) {
@ -962,7 +962,7 @@ horizon.network_topology = {
type:d.type,
delete_label: gettext('Delete'),
status:d.status,
status_class: (d.status === 'ACTIVE') ? 'active' : 'down',
status_class: (d.original_status === 'ACTIVE') ? 'active' : 'down',
status_label: gettext('STATUS'),
id_label: gettext('ID'),
interfaces_label: gettext('Interfaces'),

View File

@ -0,0 +1,25 @@
# Copyright 2016 Red Hat, 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.core.serializers.json import DjangoJSONEncoder
from django.utils.encoding import force_text
from django.utils.functional import Promise
class LazyTranslationEncoder(DjangoJSONEncoder):
"""JSON encoder that resolves lazy objects like translations"""
def default(self, obj):
if isinstance(obj, Promise):
return force_text(obj)
return super(LazyTranslationEncoder, self).default(obj)

View File

@ -20,6 +20,8 @@ from mox3.mox import IsA # noqa
from oslo_serialization import jsonutils
from openstack_dashboard import api
from openstack_dashboard.dashboards.project.network_topology.views import \
TranslationHelper
from openstack_dashboard.test import helpers as test
from openstack_dashboard.usage import quotas
@ -28,6 +30,7 @@ INDEX_URL = reverse('horizon:project:network_topology:index')
class NetworkTopologyTests(test.TestCase):
trans = TranslationHelper()
@test.create_stubs({api.nova: ('server_list',),
api.neutron: ('network_list_for_tenant',
@ -83,7 +86,8 @@ class NetworkTopologyTests(test.TestCase):
expect_server_urls = [
{'id': server.id,
'name': server.name,
'status': server.status,
'status': self.trans.instance[server.status],
'original_status': server.status,
'task': None,
'url': '/project/instances/%s/' % server.id}
for server in self.servers.list()]
@ -98,7 +102,8 @@ class NetworkTopologyTests(test.TestCase):
'external_gateway_info':
router.external_gateway_info,
'name': router.name,
'status': router.status,
'status': self.trans.router[router.status],
'original_status': router.status,
'url': '/project/routers/%s/' % router.id}
for router in routers]
self.assertEqual(expect_router_urls, data['routers'])
@ -112,14 +117,16 @@ class NetworkTopologyTests(test.TestCase):
'url': '/project/networks/%s/detail' % net.id,
'name': net.name,
'router:external': net.router__external,
'status': net.status,
'status': self.trans.network[net.status],
'original_status': net.status,
'subnets': []}
for net in external_networks]
expect_net_urls += [{'id': net.id,
'url': '/project/networks/%s/detail' % net.id,
'name': net.name,
'router:external': net.router__external,
'status': net.status,
'status': self.trans.network[net.status],
'original_status': net.status,
'subnets': [{'cidr': subnet.cidr,
'id': subnet.id,
'url':
@ -139,7 +146,8 @@ class NetworkTopologyTests(test.TestCase):
'device_owner': port.device_owner,
'fixed_ips': port.fixed_ips,
'network_id': port.network_id,
'status': port.status,
'status': self.trans.port[port.status],
'original_status': port.status,
'url': '/project/networks/ports/%s/detail' % port.id}
for port in self.ports.list()]
if router_enable:

View File

@ -17,6 +17,7 @@
# under the License.
import json
import six
from django.conf import settings
from django.core.urlresolvers import reverse
@ -26,6 +27,7 @@ from django.utils.translation import ugettext_lazy as _
from django.views.generic import View # noqa
from horizon import exceptions
from horizon.utils.lazy_encoder import LazyTranslationEncoder
from horizon import views
from openstack_dashboard import api
@ -44,6 +46,8 @@ from openstack_dashboard.dashboards.project.network_topology.subnets \
from openstack_dashboard.dashboards.project.instances import\
console as i_console
from openstack_dashboard.dashboards.project.instances.tables import \
STATUS_DISPLAY_CHOICES as instance_choices
from openstack_dashboard.dashboards.project.instances import\
views as i_views
from openstack_dashboard.dashboards.project.instances.workflows import\
@ -52,16 +56,48 @@ from openstack_dashboard.dashboards.project.networks.subnets import\
views as s_views
from openstack_dashboard.dashboards.project.networks.subnets import\
workflows as s_workflows
from openstack_dashboard.dashboards.project.networks.tables import \
DISPLAY_CHOICES as network_display_choices
from openstack_dashboard.dashboards.project.networks.tables import \
STATUS_DISPLAY_CHOICES as network_choices
from openstack_dashboard.dashboards.project.networks import\
views as n_views
from openstack_dashboard.dashboards.project.networks import\
workflows as n_workflows
from openstack_dashboard.dashboards.project.routers.ports.tables import \
DISPLAY_CHOICES as ports_choices
from openstack_dashboard.dashboards.project.routers.ports.tables import \
STATUS_DISPLAY_CHOICES as ports_status_choices
from openstack_dashboard.dashboards.project.routers.ports import\
views as p_views
from openstack_dashboard.dashboards.project.routers.tables import \
ADMIN_STATE_DISPLAY_CHOICES as routers_admin_choices
from openstack_dashboard.dashboards.project.routers.tables import \
STATUS_DISPLAY_CHOICES as routers_status_choices
from openstack_dashboard.dashboards.project.routers import\
views as r_views
class TranslationHelper(object):
"""Helper class to provide the translations of instances, networks,
routers and ports from other parts of the code to the network topology
"""
def __init__(self):
# turn translation tuples into dicts for easy access
self.instance = dict(instance_choices)
self.network = dict(network_choices)
self.network.update(dict(network_display_choices))
self.router = dict(routers_admin_choices)
self.router.update(dict(routers_status_choices))
self.port = dict(ports_choices)
self.port.update(dict(ports_status_choices))
# and turn all the keys into Uppercase for simple access
self.instance = {k.upper(): v for k, v in six.iteritems(self.instance)}
self.network = {k.upper(): v for k, v in six.iteritems(self.network)}
self.router = {k.upper(): v for k, v in six.iteritems(self.router)}
self.port = {k.upper(): v for k, v in six.iteritems(self.port)}
class NTAddInterfaceView(p_views.AddInterfaceView):
success_url = "horizon:project:network_topology:index"
failure_url = "horizon:project:network_topology:index"
@ -183,6 +219,7 @@ class NetworkTopologyView(views.HorizonTemplateView):
class JSONView(View):
trans = TranslationHelper()
@property
def is_router_enabled(self):
@ -221,7 +258,8 @@ class JSONView(View):
console = None
server_data = {'name': server.name,
'status': server.status,
'status': self.trans.instance[server.status],
'original_status': server.status,
'task': getattr(server, 'OS-EXT-STS:task_state'),
'id': server.id}
if console:
@ -249,7 +287,8 @@ class JSONView(View):
'subnets': [{'id': subnet.id,
'cidr': subnet.cidr}
for subnet in network.subnets],
'status': network.status,
'status': self.trans.network[network.status],
'original_status': network.status,
'router:external': network['router:external']}
self.add_resource_url('horizon:project:networks:subnets:detail',
obj['subnets'])
@ -281,7 +320,8 @@ class JSONView(View):
'name': publicnet.name_or_id,
'id': publicnet.id,
'subnets': subnets,
'status': publicnet.status,
'status': self.trans.network[publicnet.status],
'original_status': publicnet.status,
'router:external': publicnet['router:external']})
self.add_resource_url('horizon:project:networks:detail',
@ -303,7 +343,8 @@ class JSONView(View):
routers = [{'id': router.id,
'name': router.name_or_id,
'status': router.status,
'status': self.trans.router[router.status],
'original_status': router.status,
'external_gateway_info': router.external_gateway_info}
for router in neutron_routers]
self.add_resource_url('horizon:project:routers:detail', routers)
@ -320,7 +361,8 @@ class JSONView(View):
'device_id': port.device_id,
'fixed_ips': port.fixed_ips,
'device_owner': port.device_owner,
'status': port.status}
'status': self.trans.port[port.status],
'original_status': port.status}
for port in neutron_ports
if port.device_owner != 'network:router_ha_interface']
self.add_resource_url('horizon:project:networks:ports:detail',
@ -354,5 +396,6 @@ class JSONView(View):
'ports': self._get_ports(request),
'routers': self._get_routers(request)}
self._prepare_gateway_ports(data['routers'], data['ports'])
json_string = json.dumps(data, ensure_ascii=False)
json_string = json.dumps(data, cls=LazyTranslationEncoder,
ensure_ascii=False)
return HttpResponse(json_string, content_type='text/json')

View File

@ -197,16 +197,17 @@ class RoutersFilterAction(tables.FilterAction):
if query in router.name.lower()]
class RoutersTable(tables.DataTable):
STATUS_DISPLAY_CHOICES = (
("active", pgettext_lazy("current status of router", u"Active")),
("error", pgettext_lazy("current status of router", u"Error")),
)
ADMIN_STATE_DISPLAY_CHOICES = (
("up", pgettext_lazy("Admin state of a Router", u"UP")),
("down", pgettext_lazy("Admin state of a Router", u"DOWN")),
)
STATUS_DISPLAY_CHOICES = (
("active", pgettext_lazy("current status of router", u"Active")),
("error", pgettext_lazy("current status of router", u"Error")),
)
ADMIN_STATE_DISPLAY_CHOICES = (
("up", pgettext_lazy("Admin state of a Router", u"UP")),
("down", pgettext_lazy("Admin state of a Router", u"DOWN")),
)
class RoutersTable(tables.DataTable):
name = tables.Column("name",
verbose_name=_("Name"),
link="horizon:project:routers:detail")

View File

@ -155,9 +155,9 @@ class DetailView(tabs.TabbedTableView):
self.request, "dvr", "get")
context['ha_supported'] = api.neutron.get_feature_permission(
self.request, "l3-ha", "get")
choices = table.STATUS_DISPLAY_CHOICES
choices = rtables.STATUS_DISPLAY_CHOICES
router.status_label = filters.get_display_label(choices, router.status)
choices = table.ADMIN_STATE_DISPLAY_CHOICES
choices = rtables.ADMIN_STATE_DISPLAY_CHOICES
router.admin_state_label = (
filters.get_display_label(choices, router.admin_state))
return context