Prevent long names breaking table layouts

Adds a word-break class that can be added to tables to prevent large
column values breaking the table shape.

Change-Id: Icca10d9c29254d176dc7f8b7c039bc19c3f52c72
Related-Bug: 1565724
Closes-Bug: 1584785
This commit is contained in:
Rob Cresswell 2016-05-31 15:12:57 +01:00
parent 3f35caf180
commit 07d33cf462
36 changed files with 109 additions and 96 deletions

View File

@ -26,6 +26,7 @@ from horizon.tables.actions import UpdateAction # noqa
from horizon.tables.base import Column # noqa from horizon.tables.base import Column # noqa
from horizon.tables.base import DataTable # noqa from horizon.tables.base import DataTable # noqa
from horizon.tables.base import Row # noqa from horizon.tables.base import Row # noqa
from horizon.tables.base import WrappingColumn # noqa
from horizon.tables.views import DataTableView # noqa from horizon.tables.views import DataTableView # noqa
from horizon.tables.views import MixedDataTableView # noqa from horizon.tables.views import MixedDataTableView # noqa
from horizon.tables.views import MultiTableMixin # noqa from horizon.tables.views import MultiTableMixin # noqa

View File

@ -463,6 +463,14 @@ class Column(html.HTMLElement):
return None return None
class WrappingColumn(Column):
"""A column that wraps its contents. Useful for data like UUIDs or names"""
def __init__(self, *args, **kwargs):
super(WrappingColumn, self).__init__(*args, **kwargs)
self.classes.append('word-break')
class Row(html.HTMLElement): class Row(html.HTMLElement):
"""Represents a row in the table. """Represents a row in the table.

View File

@ -135,7 +135,7 @@ def safe_unordered_list(value):
class HostAggregatesTable(tables.DataTable): class HostAggregatesTable(tables.DataTable):
name = tables.Column('name', verbose_name=_('Name')) name = tables.WrappingColumn('name', verbose_name=_('Name'))
availability_zone = tables.Column('availability_zone', availability_zone = tables.Column('availability_zone',
verbose_name=_('Availability Zone')) verbose_name=_('Availability Zone'))
hosts = tables.Column(get_aggregate_hosts, hosts = tables.Column(get_aggregate_hosts,
@ -161,8 +161,8 @@ class HostAggregatesTable(tables.DataTable):
class AvailabilityZonesTable(tables.DataTable): class AvailabilityZonesTable(tables.DataTable):
name = tables.Column('zoneName', name = tables.WrappingColumn('zoneName',
verbose_name=_('Availability Zone Name')) verbose_name=_('Availability Zone Name'))
hosts = tables.Column(get_zone_hosts, hosts = tables.Column(get_zone_hosts,
verbose_name=_('Hosts'), verbose_name=_('Hosts'),
wrap_list=True, wrap_list=True,

View File

@ -143,7 +143,7 @@ def get_extra_specs(flavor):
class FlavorsTable(tables.DataTable): class FlavorsTable(tables.DataTable):
name = tables.Column('name', verbose_name=_('Flavor Name')) name = tables.WrappingColumn('name', verbose_name=_('Flavor Name'))
vcpus = tables.Column('vcpus', verbose_name=_('VCPUs')) vcpus = tables.Column('vcpus', verbose_name=_('VCPUs'))
ram = tables.Column(get_size, ram = tables.Column(get_size,
verbose_name=_('RAM'), verbose_name=_('RAM'),

View File

@ -124,7 +124,7 @@ class ComputeHostTable(tables.DataTable):
u"Down")), u"Down")),
) )
host = tables.Column('host', verbose_name=_('Host')) host = tables.WrappingColumn('host', verbose_name=_('Host'))
zone = tables.Column('zone', verbose_name=_('Availability zone')) zone = tables.Column('zone', verbose_name=_('Availability zone'))
status = tables.Column('status', status = tables.Column('status',
status=True, status=True,

View File

@ -19,9 +19,9 @@ from horizon.templatetags import sizeformat
class AdminHypervisorsTable(tables.DataTable): class AdminHypervisorsTable(tables.DataTable):
hostname = tables.Column("hypervisor_hostname", hostname = tables.WrappingColumn("hypervisor_hostname",
link="horizon:admin:hypervisors:detail", link="horizon:admin:hypervisors:detail",
verbose_name=_("Hostname")) verbose_name=_("Hostname"))
hypervisor_type = tables.Column("hypervisor_type", hypervisor_type = tables.Column("hypervisor_type",
verbose_name=_("Type")) verbose_name=_("Type"))
@ -65,9 +65,9 @@ class AdminHypervisorsTable(tables.DataTable):
class AdminHypervisorInstancesTable(tables.DataTable): class AdminHypervisorInstancesTable(tables.DataTable):
name = tables.Column("name", name = tables.WrappingColumn("name",
link="horizon:admin:instances:detail", link="horizon:admin:instances:detail",
verbose_name=_("Instance Name")) verbose_name=_("Instance Name"))
instance_id = tables.Column("uuid", instance_id = tables.Column("uuid",
verbose_name=_("Instance ID")) verbose_name=_("Instance ID"))

View File

@ -86,10 +86,9 @@ class AdminImageFilterAction(tables.FilterAction):
class AdminImagesTable(project_tables.ImagesTable): class AdminImagesTable(project_tables.ImagesTable):
name = tables.Column("name", name = tables.WrappingColumn("name",
link="horizon:admin:images:detail", link="horizon:admin:images:detail",
truncate=40, verbose_name=_("Image Name"))
verbose_name=_("Image Name"))
tenant = tables.Column(lambda obj: getattr(obj, 'tenant_name', obj.owner), tenant = tables.Column(lambda obj: getattr(obj, 'tenant_name', obj.owner),
verbose_name=_("Project")) verbose_name=_("Project"))

View File

@ -135,9 +135,9 @@ class AdminInstancesTable(tables.DataTable):
host = tables.Column("OS-EXT-SRV-ATTR:host", host = tables.Column("OS-EXT-SRV-ATTR:host",
verbose_name=_("Host"), verbose_name=_("Host"),
classes=('nowrap-col',)) classes=('nowrap-col',))
name = tables.Column("name", name = tables.WrappingColumn("name",
link="horizon:admin:instances:detail", link="horizon:admin:instances:detail",
verbose_name=_("Name")) verbose_name=_("Name"))
image_name = tables.Column("image_name", image_name = tables.Column("image_name",
verbose_name=_("Image Name")) verbose_name=_("Image Name"))
ip = tables.Column(project_tables.get_ips, ip = tables.Column(project_tables.get_ips,

View File

@ -80,9 +80,9 @@ class UpdatePort(project_tables.UpdatePort):
class PortsTable(project_tables.PortsTable): class PortsTable(project_tables.PortsTable):
name = tables.Column("name_or_id", name = tables.WrappingColumn("name_or_id",
verbose_name=_("Name"), verbose_name=_("Name"),
link="horizon:admin:networks:ports:detail") link="horizon:admin:networks:ports:detail")
class Meta(object): class Meta(object):
name = "ports" name = "ports"

View File

@ -101,8 +101,8 @@ def subnet_ip_availability(availability):
class SubnetsTable(tables.DataTable): class SubnetsTable(tables.DataTable):
name = tables.Column("name_or_id", verbose_name=_("Name"), name = tables.WrappingColumn("name_or_id", verbose_name=_("Name"),
link='horizon:admin:networks:subnets:detail') link='horizon:admin:networks:subnets:detail')
cidr = tables.Column("cidr", verbose_name=_("CIDR")) cidr = tables.Column("cidr", verbose_name=_("CIDR"))
ip_version = tables.Column("ipver_str", verbose_name=_("IP Version")) ip_version = tables.Column("ipver_str", verbose_name=_("IP Version"))
gateway_ip = tables.Column("gateway_ip", verbose_name=_("Gateway IP")) gateway_ip = tables.Column("gateway_ip", verbose_name=_("Gateway IP"))

View File

@ -86,8 +86,8 @@ DISPLAY_CHOICES = (
class NetworksTable(tables.DataTable): class NetworksTable(tables.DataTable):
tenant = tables.Column("tenant_name", verbose_name=_("Project")) tenant = tables.Column("tenant_name", verbose_name=_("Project"))
name = tables.Column("name_or_id", verbose_name=_("Network Name"), name = tables.WrappingColumn("name_or_id", verbose_name=_("Network Name"),
link='horizon:admin:networks:detail') link='horizon:admin:networks:detail')
subnets = tables.Column(project_tables.get_subnets, subnets = tables.Column(project_tables.get_subnets,
verbose_name=_("Subnets Associated"),) verbose_name=_("Subnets Associated"),)
num_agents = tables.Column("num_agents", num_agents = tables.Column("num_agents",

View File

@ -37,9 +37,9 @@ class UpdateRow(tables.Row):
class RoutersTable(r_tables.RoutersTable): class RoutersTable(r_tables.RoutersTable):
tenant = tables.Column("tenant_name", verbose_name=_("Project")) tenant = tables.Column("tenant_name", verbose_name=_("Project"))
name = tables.Column("name", name = tables.WrappingColumn("name",
verbose_name=_("Name"), verbose_name=_("Name"),
link="horizon:admin:routers:detail") link="horizon:admin:routers:detail")
class Meta(object): class Meta(object):
name = "routers" name = "routers"

View File

@ -56,8 +56,8 @@ class UpdateRow(tables.Row):
class VolumeSnapshotsTable(volumes_tables.VolumesTableBase): class VolumeSnapshotsTable(volumes_tables.VolumesTableBase):
name = tables.Column("name", verbose_name=_("Name"), name = tables.WrappingColumn("name", verbose_name=_("Name"),
link="horizon:admin:volumes:snapshots:detail") link="horizon:admin:volumes:snapshots:detail")
volume_name = snapshots_tables.SnapshotVolumeNameColumn( volume_name = snapshots_tables.SnapshotVolumeNameColumn(
"name", verbose_name=_("Volume Name"), "name", verbose_name=_("Volume Name"),
link="horizon:admin:volumes:volumes:detail") link="horizon:admin:volumes:volumes:detail")

View File

@ -196,8 +196,8 @@ class UpdateRow(tables.Row):
class VolumeTypesTable(tables.DataTable): class VolumeTypesTable(tables.DataTable):
name = tables.Column("name", verbose_name=_("Name"), name = tables.WrappingColumn("name", verbose_name=_("Name"),
form_field=forms.CharField(max_length=64)) form_field=forms.CharField(max_length=64))
description = tables.Column(lambda obj: getattr(obj, 'description', None), description = tables.Column(lambda obj: getattr(obj, 'description', None),
verbose_name=_('Description'), verbose_name=_('Description'),
form_field=forms.CharField( form_field=forms.CharField(
@ -294,7 +294,7 @@ class EditConsumer(tables.LinkAction):
class QosSpecsTable(tables.DataTable): class QosSpecsTable(tables.DataTable):
name = tables.Column('name', verbose_name=_('Name')) name = tables.WrappingColumn('name', verbose_name=_('Name'))
consumer = tables.Column('consumer', verbose_name=_('Consumer')) consumer = tables.Column('consumer', verbose_name=_('Consumer'))
specs = tables.Column(render_spec_keys, specs = tables.Column(render_spec_keys,
verbose_name=_('Specs'), verbose_name=_('Specs'),

View File

@ -87,9 +87,9 @@ class UpdateVolumeStatusAction(tables.LinkAction):
class VolumesTable(volumes_tables.VolumesTable): class VolumesTable(volumes_tables.VolumesTable):
name = tables.Column("name", name = tables.WrappingColumn("name",
verbose_name=_("Name"), verbose_name=_("Name"),
link="horizon:admin:volumes:volumes:detail") link="horizon:admin:volumes:volumes:detail")
host = tables.Column("os-vol-host-attr:host", verbose_name=_("Host")) host = tables.Column("os-vol-host-attr:host", verbose_name=_("Host"))
tenant = tables.Column(lambda obj: getattr(obj, 'tenant_name', None), tenant = tables.Column(lambda obj: getattr(obj, 'tenant_name', None),
verbose_name=_("Project")) verbose_name=_("Project"))

View File

@ -275,7 +275,7 @@ class UnsetDomainContext(tables.Action):
class DomainsTable(tables.DataTable): class DomainsTable(tables.DataTable):
name = tables.Column('name', verbose_name=_('Name')) name = tables.WrappingColumn('name', verbose_name=_('Name'))
description = tables.Column(lambda obj: getattr(obj, 'description', None), description = tables.Column(lambda obj: getattr(obj, 'description', None),
verbose_name=_('Description')) verbose_name=_('Description'))
id = tables.Column('id', verbose_name=_('Domain ID')) id = tables.Column('id', verbose_name=_('Domain ID'))

View File

@ -188,7 +188,7 @@ class AddMembersLink(tables.LinkAction):
class UsersTable(tables.DataTable): class UsersTable(tables.DataTable):
name = tables.Column('name', verbose_name=_('User Name')) name = tables.WrappingColumn('name', verbose_name=_('User Name'))
email = tables.Column('email', verbose_name=_('Email'), email = tables.Column('email', verbose_name=_('Email'),
filters=[defaultfilters.escape, filters=[defaultfilters.escape,
defaultfilters.urlize]) defaultfilters.urlize])

View File

@ -221,9 +221,9 @@ class UpdateRow(tables.Row):
class TenantsTable(tables.DataTable): class TenantsTable(tables.DataTable):
name = tables.Column('name', verbose_name=_('Name'), name = tables.WrappingColumn('name', verbose_name=_('Name'),
link=("horizon:identity:projects:detail"), link=("horizon:identity:projects:detail"),
form_field=forms.CharField(max_length=64)) form_field=forms.CharField(max_length=64))
description = tables.Column(lambda obj: getattr(obj, 'description', None), description = tables.Column(lambda obj: getattr(obj, 'description', None),
verbose_name=_('Description'), verbose_name=_('Description'),
form_field=forms.CharField( form_field=forms.CharField(

View File

@ -78,7 +78,7 @@ class RoleFilterAction(tables.FilterAction):
class RolesTable(tables.DataTable): class RolesTable(tables.DataTable):
name = tables.Column('name', verbose_name=_('Role Name')) name = tables.WrappingColumn('name', verbose_name=_('Role Name'))
id = tables.Column('id', verbose_name=_('Role ID')) id = tables.Column('id', verbose_name=_('Role ID'))
class Meta(object): class Meta(object):

View File

@ -178,10 +178,10 @@ class UsersTable(tables.DataTable):
("true", True), ("true", True),
("false", False) ("false", False)
) )
name = tables.Column('name', name = tables.WrappingColumn('name',
link="horizon:identity:users:detail", link="horizon:identity:users:detail",
verbose_name=_('User Name'), verbose_name=_('User Name'),
form_field=forms.CharField(required=False)) form_field=forms.CharField(required=False))
description = tables.Column(lambda obj: getattr(obj, 'description', None), description = tables.Column(lambda obj: getattr(obj, 'description', None),
verbose_name=_('Description'), verbose_name=_('Description'),
hidden=KEYSTONE_V2_ENABLED, hidden=KEYSTONE_V2_ENABLED,

View File

@ -300,10 +300,9 @@ class ImagesTable(tables.DataTable):
("image", pgettext_lazy("Type of an image", u"Image")), ("image", pgettext_lazy("Type of an image", u"Image")),
("snapshot", pgettext_lazy("Type of an image", u"Snapshot")), ("snapshot", pgettext_lazy("Type of an image", u"Snapshot")),
) )
name = tables.Column(get_image_name, name = tables.WrappingColumn(get_image_name,
link="horizon:project:images:images:detail", link="horizon:project:images:images:detail",
truncate=40, verbose_name=_("Image Name"),)
verbose_name=_("Image Name"),)
image_type = tables.Column(get_image_type, image_type = tables.Column(get_image_type,
verbose_name=_("Type"), verbose_name=_("Type"),
display_choices=TYPE_CHOICES) display_choices=TYPE_CHOICES)

View File

@ -1195,9 +1195,9 @@ class InstancesTable(tables.DataTable):
("shelved", True), ("shelved", True),
("shelved_offloaded", True), ("shelved_offloaded", True),
) )
name = tables.Column("name", name = tables.WrappingColumn("name",
link="horizon:project:instances:detail", link="horizon:project:instances:detail",
verbose_name=_("Instance Name")) verbose_name=_("Instance Name"))
image_name = tables.Column("image_name", image_name = tables.Column("image_name",
verbose_name=_("Image Name")) verbose_name=_("Image Name"))
ip = tables.Column(get_ips, ip = tables.Column(get_ips,

View File

@ -65,9 +65,9 @@ STATUS_DISPLAY_CHOICES = (
class PortsTable(tables.DataTable): class PortsTable(tables.DataTable):
name = tables.Column("name_or_id", name = tables.WrappingColumn("name_or_id",
verbose_name=_("Name"), verbose_name=_("Name"),
link="horizon:project:networks:ports:detail") link="horizon:project:networks:ports:detail")
fixed_ips = tables.Column(get_fixed_ips, verbose_name=_("Fixed IPs")) fixed_ips = tables.Column(get_fixed_ips, verbose_name=_("Fixed IPs"))
attached = tables.Column(get_attached, verbose_name=_("Attached Device")) attached = tables.Column(get_attached, verbose_name=_("Attached Device"))
status = tables.Column("status", status = tables.Column("status",

View File

@ -128,8 +128,10 @@ class UpdateSubnet(SubnetPolicyTargetMixin, CheckNetworkEditable,
class SubnetsTable(tables.DataTable): class SubnetsTable(tables.DataTable):
name = tables.Column("name_or_id", verbose_name=_("Name"), name = tables.WrappingColumn(
link='horizon:project:networks:subnets:detail') "name_or_id",
verbose_name=_("Name"),
link='horizon:project:networks:subnets:detail')
cidr = tables.Column("cidr", verbose_name=_("Network Address")) cidr = tables.Column("cidr", verbose_name=_("Network Address"))
ip_version = tables.Column("ipver_str", verbose_name=_("IP Version")) ip_version = tables.Column("ipver_str", verbose_name=_("IP Version"))
gateway_ip = tables.Column("gateway_ip", verbose_name=_("Gateway IP")) gateway_ip = tables.Column("gateway_ip", verbose_name=_("Gateway IP"))

View File

@ -168,9 +168,9 @@ class NetworksFilterAction(tables.FilterAction):
class NetworksTable(tables.DataTable): class NetworksTable(tables.DataTable):
name = tables.Column("name_or_id", name = tables.WrappingColumn("name_or_id",
verbose_name=_("Name"), verbose_name=_("Name"),
link='horizon:project:networks:detail') link='horizon:project:networks:detail')
subnets = tables.Column(get_subnets, subnets = tables.Column(get_subnets,
verbose_name=_("Subnets Associated"),) verbose_name=_("Subnets Associated"),)
shared = tables.Column("shared", verbose_name=_("Shared"), shared = tables.Column("shared", verbose_name=_("Shared"),

View File

@ -209,9 +209,9 @@ ADMIN_STATE_DISPLAY_CHOICES = (
class RoutersTable(tables.DataTable): class RoutersTable(tables.DataTable):
name = tables.Column("name", name = tables.WrappingColumn("name",
verbose_name=_("Name"), verbose_name=_("Name"),
link="horizon:project:routers:detail") link="horizon:project:routers:detail")
status = tables.Column("status", status = tables.Column("status",
verbose_name=_("Status"), verbose_name=_("Status"),
status=True, status=True,

View File

@ -50,7 +50,7 @@ limitations under the License.
<span class="fa fa-chevron-right" hz-expand-detail <span class="fa fa-chevron-right" hz-expand-detail
title="{$ ::expandDetailsText $}"></span> title="{$ ::expandDetailsText $}"></span>
</td> </td>
<td class="rsp-p1">{$ ::item.name $}</td> <td class="rsp-p1 word-break">{$ ::item.name $}</td>
<td class="rsp-p1"> <td class="rsp-p1">
<span class="invalid fa fa-exclamation-triangle" <span class="invalid fa fa-exclamation-triangle"
ng-show="item.errors.vcpus" ng-show="item.errors.vcpus"
@ -161,7 +161,7 @@ limitations under the License.
<span class="fa fa-chevron-right" hz-expand-detail <span class="fa fa-chevron-right" hz-expand-detail
title="{$ ::expandDetailsText $}"></span> title="{$ ::expandDetailsText $}"></span>
</td> </td>
<td class="rsp-p1">{$ ::item.name $}</td> <td class="rsp-p1 word-break">{$ ::item.name $}</td>
<td class="rsp-p1"> <td class="rsp-p1">
<span class="invalid fa fa-exclamation-triangle" <span class="invalid fa fa-exclamation-triangle"
ng-show="item.errors.vcpus" ng-show="item.errors.vcpus"

View File

@ -45,7 +45,7 @@
<span class="fa fa-chevron-right" hz-expand-detail <span class="fa fa-chevron-right" hz-expand-detail
title="{$ 'Click to see more details'|translate $}"></span> title="{$ 'Click to see more details'|translate $}"></span>
</td> </td>
<td class="rsp-p1">{$ row.name $}</td> <td class="rsp-p1 word-break">{$ row.name $}</td>
<td class="rsp-p2"> <td class="rsp-p2">
<div ng-repeat="subnet in row.subnets">{$ subnet.name $}</div> <div ng-repeat="subnet in row.subnets">{$ subnet.name $}</div>
</td> </td>
@ -120,7 +120,7 @@
<span class="fa fa-chevron-right" hz-expand-detail <span class="fa fa-chevron-right" hz-expand-detail
title="{$ 'Click to see more details'|translate $}"></span> title="{$ 'Click to see more details'|translate $}"></span>
</td> </td>
<td class="rsp-p1">{$ row.name$}</td> <td class="rsp-p1 word-break">{$ row.name$}</td>
<td class="rsp-p2"> <td class="rsp-p2">
<div ng-repeat="subnet in row.subnets">{$ subnet.name $}</div> <div ng-repeat="subnet in row.subnets">{$ subnet.name $}</div>
</td> </td>

View File

@ -32,12 +32,12 @@
<td class="reorder"> <td class="reorder">
<span class="fa fa-sort" title="{$ 'Re-order items using drag and drop'|translate $}"></span> <span class="fa fa-sort" title="{$ 'Re-order items using drag and drop'|translate $}"></span>
{$ $index + 1 $} {$ $index + 1 $}
</td> </td>
<td class="expander"> <td class="expander">
<span class="fa fa-chevron-right" hz-expand-detail <span class="fa fa-chevron-right" hz-expand-detail
title="{$ 'Click to see more details'|translate $}"></span> title="{$ 'Click to see more details'|translate $}"></span>
</td> </td>
<td class="rsp-p1">{$ ctrl.nameOrID(item) $}</td> <td class="rsp-p1 word-break">{$ ctrl.nameOrID(item) $}</td>
<td class="rsp-p2"> <td class="rsp-p2">
<div ng-repeat="ip in item.fixed_ips"> <div ng-repeat="ip in item.fixed_ips">
{$ ip.ip_address $} on subnet: {$ item.subnet_names[ip.ip_address] $} {$ ip.ip_address $} on subnet: {$ item.subnet_names[ip.ip_address] $}
@ -103,14 +103,14 @@
No available items No available items
</div> </div>
</td> </td>
</tr> </tr>
<tr ng-repeat-start="item in ctrl.tableDataMulti.displayedAvailable track by item.id" <tr ng-repeat-start="item in ctrl.tableDataMulti.displayedAvailable track by item.id"
ng-if="!trCtrl.allocatedIds[item.id]"> ng-if="!trCtrl.allocatedIds[item.id]">
<td class="expander"> <td class="expander">
<span class="fa fa-chevron-right" hz-expand-detail <span class="fa fa-chevron-right" hz-expand-detail
title="{$ 'Click to see more details'|translate $}"></span> title="{$ 'Click to see more details'|translate $}"></span>
</td> </td>
<td class="rsp-p1">{$ ctrl.nameOrID(item) $}</td> <td class="rsp-p1 word-break">{$ ctrl.nameOrID(item) $}</td>
<td class="rsp-p2"> <td class="rsp-p2">
<div ng-repeat="ip in item.fixed_ips"> <div ng-repeat="ip in item.fixed_ips">
{$ ip.ip_address $} on subnet: {$ item.subnet_names[ip.ip_address] $} {$ ip.ip_address $} on subnet: {$ item.subnet_names[ip.ip_address] $}

View File

@ -31,7 +31,7 @@
<span class="fa fa-chevron-right" hz-expand-detail <span class="fa fa-chevron-right" hz-expand-detail
title="{$ ::trCtrl.helpText.expandDetailsText $}"></span> title="{$ ::trCtrl.helpText.expandDetailsText $}"></span>
</td> </td>
<td class="rsp-p1">{$ row.name $}</td> <td class="rsp-p1 word-break">{$ row.name $}</td>
<td class="rsp-p2">{$ row.description $}</td> <td class="rsp-p2">{$ row.description $}</td>
<td class="actions_column"> <td class="actions_column">
<action-list> <action-list>
@ -81,7 +81,7 @@
<span class="fa fa-chevron-right" hz-expand-detail <span class="fa fa-chevron-right" hz-expand-detail
title="{$ ::trCtrl.helpText.expandDetailsText $}"></span> title="{$ ::trCtrl.helpText.expandDetailsText $}"></span>
</td> </td>
<td class="rsp-p1">{$ row.name$}</td> <td class="rsp-p1 word-break">{$ row.name$}</td>
<td class="rsp-p1">{$ row.description $}</td> <td class="rsp-p1">{$ row.description $}</td>
<td class="actions_column"> <td class="actions_column">
<action-list> <action-list>

View File

@ -170,28 +170,28 @@
// Mapping for dynamic table data // Mapping for dynamic table data
var tableBodyCellsMap = { var tableBodyCellsMap = {
image: [ image: [
{ key: 'name', classList: ['hi-light'] }, { key: 'name', classList: ['hi-light', 'word-break'] },
{ key: 'updated_at', filter: dateFilter, filterArg: 'short' }, { key: 'updated_at', filter: dateFilter, filterArg: 'short' },
{ key: 'size', filter: bytesFilter, classList: ['number'] }, { key: 'size', filter: bytesFilter, classList: ['number'] },
{ key: 'disk_format', filter: diskFormatFilter, filterRawData: true }, { key: 'disk_format', filter: diskFormatFilter, filterRawData: true },
{ key: 'is_public', filter: decodeFilter, filterArg: _visibilitymap } { key: 'is_public', filter: decodeFilter, filterArg: _visibilitymap }
], ],
snapshot: [ snapshot: [
{ key: 'name', classList: ['hi-light'] }, { key: 'name', classList: ['hi-light', 'word-break'] },
{ key: 'updated_at', filter: dateFilter, filterArg: 'short' }, { key: 'updated_at', filter: dateFilter, filterArg: 'short' },
{ key: 'size', filter: bytesFilter, classList: ['number'] }, { key: 'size', filter: bytesFilter, classList: ['number'] },
{ key: 'disk_format', filter: diskFormatFilter, filterRawData: true }, { key: 'disk_format', filter: diskFormatFilter, filterRawData: true },
{ key: 'is_public', filter: decodeFilter, filterArg: _visibilitymap } { key: 'is_public', filter: decodeFilter, filterArg: _visibilitymap }
], ],
volume: [ volume: [
{ key: 'name', classList: ['hi-light'] }, { key: 'name', classList: ['hi-light', 'word-break'] },
{ key: 'description' }, { key: 'description' },
{ key: 'size', filter: gbFilter, classList: ['number'] }, { key: 'size', filter: gbFilter, classList: ['number'] },
{ key: 'volume_image_metadata', filter: diskFormatFilter }, { key: 'volume_image_metadata', filter: diskFormatFilter },
{ key: 'availability_zone' } { key: 'availability_zone' }
], ],
volume_snapshot: [ volume_snapshot: [
{ key: 'name', classList: ['hi-light'] }, { key: 'name', classList: ['hi-light', 'word-break'] },
{ key: 'description' }, { key: 'description' },
{ key: 'size', filter: gbFilter, classList: ['number'] }, { key: 'size', filter: gbFilter, classList: ['number'] },
{ key: 'created_at', filter: dateFilter, filterArg: 'short' }, { key: 'created_at', filter: dateFilter, filterArg: 'short' },

View File

@ -140,9 +140,9 @@ class VolumeCGroupsTable(tables.DataTable):
pgettext_lazy("Current status of Consistency Group", u"Error")), pgettext_lazy("Current status of Consistency Group", u"Error")),
) )
name = tables.Column("name", name = tables.WrappingColumn("name",
verbose_name=_("Name"), verbose_name=_("Name"),
link="horizon:project:volumes:cgroups:detail") link="horizon:project:volumes:cgroups:detail")
description = tables.Column("description", description = tables.Column("description",
verbose_name=_("Description"), verbose_name=_("Description"),
truncate=40) truncate=40)

View File

@ -141,7 +141,7 @@ class UpdateRow(tables.Row):
return snapshot return snapshot
class SnapshotVolumeNameColumn(tables.Column): class SnapshotVolumeNameColumn(tables.WrappingColumn):
def get_raw_data(self, snapshot): def get_raw_data(self, snapshot):
volume = snapshot._volume volume = snapshot._volume
if volume: if volume:
@ -168,9 +168,10 @@ class VolumeSnapshotsFilterAction(tables.FilterAction):
class VolumeSnapshotsTable(volume_tables.VolumesTableBase): class VolumeSnapshotsTable(volume_tables.VolumesTableBase):
name = tables.Column("name", name = tables.WrappingColumn(
verbose_name=_("Name"), "name",
link="horizon:project:volumes:snapshots:detail") verbose_name=_("Name"),
link="horizon:project:volumes:snapshots:detail")
volume_name = SnapshotVolumeNameColumn( volume_name = SnapshotVolumeNameColumn(
"name", "name",
verbose_name=_("Volume Name"), verbose_name=_("Volume Name"),

View File

@ -364,7 +364,7 @@ def get_attachment_name(request, attachment):
return instance return instance
class AttachmentColumn(tables.Column): class AttachmentColumn(tables.WrappingColumn):
"""Customized column class. """Customized column class.
So it that does complex processing on the attachments So it that does complex processing on the attachments
@ -470,9 +470,9 @@ class VolumesFilterAction(tables.FilterAction):
class VolumesTable(VolumesTableBase): class VolumesTable(VolumesTableBase):
name = tables.Column("name", name = tables.WrappingColumn("name",
verbose_name=_("Name"), verbose_name=_("Name"),
link="horizon:project:volumes:volumes:detail") link="horizon:project:volumes:volumes:detail")
volume_type = tables.Column(get_volume_type, volume_type = tables.Column(get_volume_type,
verbose_name=_("Type")) verbose_name=_("Type"))
attachments = AttachmentColumn("attachments", attachments = AttachmentColumn("attachments",
@ -543,7 +543,7 @@ class DetachVolume(tables.BatchAction):
return reverse('horizon:project:volumes:index') return reverse('horizon:project:volumes:index')
class AttachedInstanceColumn(tables.Column): class AttachedInstanceColumn(tables.WrappingColumn):
"""Customized column class that does complex processing on the attachments """Customized column class that does complex processing on the attachments
for a volume instance. for a volume instance.
""" """

View File

@ -153,3 +153,12 @@
.nowrap-col { .nowrap-col {
white-space: nowrap; white-space: nowrap;
} }
// Make sure long UUIDs, names etc. don't force the table outside a
// modal, by forcing a word break. The 'td' specificity is required
// because the class is applied in a column, but we don't want the
// <th> to wrap.
// See launchpad bugs 1565724 && 1584785
td.word-break {
word-break: break-all;
}

View File

@ -15,10 +15,4 @@
.magic-search-bar, .basic-search-bar { .magic-search-bar, .basic-search-bar {
margin: $padding-small-vertical 0; margin: $padding-small-vertical 0;
} }
// Make sure long UUIDs don't force the table outside the modal
// See https://bugs.launchpad.net/horizon/+bug/1565724
td {
word-break: break-all;
}
} }