Match python/ angular table styles

This patch unifies the Python and Angular table styles (there is no
reason for them to look drastically different).

- Clean up table header in _data_table.html
- Remove page_header styling for default theme, as it causes the angular
  panels to shift downwards on the page
- Removed styling workarounds from default themes
- Removed several chunks of angular specific scss code, including the
  'modern' class
- Removed the "Actions" header in python tables, to match Angular
- Removed duplicate 'no items to display' info in footer, when table is
  empty.
- Also fixes the Containers header, which was different to all the
  others

Closes-Bug: 1517081
Co-Authored-By: Diana Whitten <hurgleburgler@gmail.com>
Change-Id: Id71aab6e8bbbcd1f7fa4d5575156e4d3c6aa990d
This commit is contained in:
Rob Cresswell 2016-01-27 11:26:29 +00:00
parent 347023f35a
commit b69ff722c1
32 changed files with 79 additions and 238 deletions

View File

@ -7,7 +7,7 @@
</button>
<!-- Dropdown caret button -->
<button class="split-caret dropdown-toggle" dropdown-toggle
ng-class="actionClasses + ' pull-right'"
ng-class="actionClasses"
aria-expanded="false">
<span class="fa fa-caret-down"></span>
<span class="sr-only" translate>Toggle Dropdown</span>

View File

@ -1,6 +1,11 @@
$em-per-priority: floor($table-col-avg-width / $font-size-base) * 3;
.table > thead > tr > th {
border-top: 0; // Remove once search bar is outside table HTML
}
[hz-table] {
td.action-col {
.popover {
min-width: 15em;
@ -24,12 +29,11 @@ $em-per-priority: floor($table-col-avg-width / $font-size-base) * 3;
}
.invalid {
color: $invalid-color;
color: $brand-warning;
}
.no-rows-help {
font-style: italic;
font-weight: normal;
text-align: center;
}
@ -41,62 +45,24 @@ $em-per-priority: floor($table-col-avg-width / $font-size-base) * 3;
.search-header {
padding: 0;
border-bottom: 0; // Remove once search bar is outside table HTML
.btn-addon {
display: table-cell;
padding-left: 0.3em;
vertical-align: top;
width: 1%;
}
.basic-search-bar {
margin-bottom: 0.2em;
width: 100%;
.input-group-sm .form-control:not(:first-child):not(:last-child) {
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
}
input[type="text"] {
@include input-placeholder {
font-weight: normal;
color: $placeholder-text-color;
}
}
}
.search-help {
color: $transfer-help-text-color;
font-size: 0.9em;
font-style: italic;
font-weight: 400;
margin: 0.2em 0.3em 0;
visibility: hidden;
&.searching {
visibility: visible;
}
}
}
}
.table-rsp {
border-collapse: separate;
border-spacing: 0 $table-gap-height;
width: 100%;
thead tr th, tfoot tr td {
background: none;
border: none;
padding: $table-padding;
}
tbody tr {
&[lr-drag-src] td:not(.expander) {
cursor: move;
}
&.lr-drop-target-before td {
border-top: $reorder-border !important;
}
@ -105,36 +71,6 @@ $em-per-priority: floor($table-col-avg-width / $font-size-base) * 3;
border-bottom: $reorder-border !important;
}
td {
background-color: #ffffff;
border-top: $table-border;
border-bottom: $table-border;
padding: $table-padding;
position: relative;
white-space: nowrap;
&:first-child, &.action-col {
border-left: $table-border;
}
&:last-child, &.select-col {
border-right: $table-border;
}
}
}
.select-col {
max-width: $select-col-width;
text-align: center;
width: $select-col-width;
}
.action-col {
position: relative;
text-align: right;
vertical-align: top;
min-width: $batch-action-width;
width: $batch-action-width;
}
.numeric {
@ -173,21 +109,6 @@ $em-per-priority: floor($table-col-avg-width / $font-size-base) * 3;
opacity: 1;
}
&.modern {
border-spacing: 0;
tbody tr {
td {
border: none;
border-top: $table-border;
}
&:last-child td {
border-bottom: $table-border;
}
}
}
&.table-detail {
border-spacing: 0;
@ -257,7 +178,7 @@ $em-per-priority: floor($table-col-avg-width / $font-size-base) * 3;
tbody {
tr {
&:nth-child(2n+1) > td, &:nth-child(2n+1) + .detail-row > td {
background-color: $table-stripe-bgcolor;
background-color: $table-bg-accent;
}
&.spacer-row > td, &.spacer-row:nth-child(6n+3) + tr + tr.detail-row td,
@ -268,18 +189,6 @@ $em-per-priority: floor($table-col-avg-width / $font-size-base) * 3;
}
}
}
&.modern {
.expanded + tr td {
border-top: $table-border;
}
.expanded {
td:not(.action-col), td.action-col:not([rowspan='2']) {
border-bottom: none;
}
}
}
}
@media only all {

View File

@ -1,7 +1,7 @@
<transfer-table tr-model="data" clone-content>
<table st-table="$displayedItems" st-safe-src="$sourceItems"
hz-table class="table-striped table-rsp table-detail modern">
hz-table class="table table-striped table-rsp table-detail">
<thead>
<!-- show search bar only for available table -->
<tr ng-show="$isAvailableTable">

View File

@ -38,7 +38,7 @@ horizon.datatables = {
row_count = horizon.datatables.update_footer_count($table, -1);
if(row_count === 0) {
colspan = $table.find('th[colspan]').attr('colspan');
colspan = $table.find('.table_column_header th').length;
template = horizon.templates.compiled_templates["#empty_row_template"];
params = {
"colspan": colspan,
@ -412,8 +412,12 @@ horizon.datatables.update_footer_count = function (el, modifier) {
$footer = $el.find('tfoot span.table_count');
}
row_count = $el.find('tbody tr:visible').length + modifier - $el.find('.empty').length;
if (row_count) {
footer_text_template = ngettext("Displaying %s item", "Displaying %s items", row_count);
footer_text = interpolate(footer_text_template, [row_count]);
} else {
footer_text = '';
}
$footer.text(footer_text);
return row_count;
};
@ -422,7 +426,7 @@ horizon.datatables.add_no_results_row = function (table) {
// Add a "no results" row if there are no results.
var template = horizon.templates.compiled_templates["#empty_row_template"];
if (!table.find("tbody tr:visible").length && typeof(template) !== "undefined") {
var colspan = table.find("th[colspan]").attr('colspan');
var colspan = $table.find('.table_column_header th').length;
var params = {
"colspan": colspan,
no_items_label: gettext("No items to display.")

View File

@ -5,21 +5,19 @@
{% with columns=table.get_columns rows=table.get_rows %}
{% block table %}
<table id="{{ table.slugify_name }}" class="{% block table_css_classes %}table table-striped datatable {{ table.css_classes }}{% endblock %}">
<thead>
{% block table_caption %}
<tr class='table_caption'>
<th class='table_header' colspan='{{ columns|length }}'>
<caption>
{% if not hidden_title %}
<h3 class='table_title'>{{ table }}</h3>
<span class='table-title'>{{ table }}</span>
{% endif %}
{{ table.render_table_actions }}
</th>
</tr>
</caption>
{% endblock table_caption %}
<thead>
{% block table_breadcrumb %}
{% if table.breadcrumb %}
<tr>
<td class="breadcrumb_td" colspan="{{ table.get_columns|length }}">
<td class="breadcrumb_td" colspan="{{ columns|length }}">
{{ table.breadcrumb.render }}
</td>
</tr>
@ -48,13 +46,13 @@
{{ row.render }}
{% empty %}
<tr class="{% cycle 'odd' 'even' %} empty">
<td colspan="{{ table.get_columns|length }}">{{ table.get_empty_message }}</td>
<td colspan="{{ columns|length }}">{{ table.get_empty_message }}</td>
</tr>
{% endfor %}
</tbody>
{% endblock table_body %}
{% block table_footer %}
{% if table.footer %}
{% if table.footer and rows %}
<tfoot>
{% if table.needs_summary_row %}
<tr class="summation">
@ -68,7 +66,7 @@
</tr>
{% endif %}
<tr>
<td colspan="{{ table.get_columns|length }}">
<td colspan="{{ columns|length }}">
<span class="table_count">{% blocktrans count counter=rows|length %}Displaying {{ counter }} item{% plural %}Displaying {{ counter }} items{% endblocktrans %}</span>
{% if table.has_prev_data or table.has_more_data %}
<span class="spacer">|</span>

View File

@ -652,7 +652,7 @@ class DataTableTests(test.TestCase):
# Whole table
resp = http.HttpResponse(self.table.render())
self.assertContains(resp, '<table id="my_table"', 1)
self.assertContains(resp, '<th ', 8)
self.assertContains(resp, '<th ', 7)
self.assertContains(resp, 'id="my_table__row__1"', 1)
self.assertContains(resp, 'id="my_table__row__2"', 1)
self.assertContains(resp, 'id="my_table__row__3"', 1)
@ -666,7 +666,7 @@ class DataTableTests(test.TestCase):
# Hidden Title = False shows the table title
self.table._meta.hidden_title = False
resp = http.HttpResponse(self.table.render())
self.assertContains(resp, "<h3 class='table_title'", 1)
self.assertContains(resp, "<span class='table-title'>", 1)
# Filter = False hides the search box
self.table._meta.filter = False

View File

@ -4,7 +4,7 @@
st-safe-src="table.flavors"
default-sort="ram"
default-sort-reverse="false"
class="table-striped table-rsp table-detail modern">
class="table table-striped table-rsp table-detail">
<thead>

View File

@ -2,6 +2,10 @@
{% load i18n %}
{% block title %}{% trans "Users" %}{% endblock %}
{% block page_header %}
<hz-page-header header="{$ 'Users' | translate $}"></hz-page-header>
{% endblock %}
{% block ng_route_base %}
<base href="{{ WEBROOT }}">
{% endblock %}

View File

@ -1,2 +0,0 @@
@import "users/users";
@import "projects/projects";

View File

@ -1,12 +1,10 @@
<hz-page-header header="{$ 'Users' | translate $}"></hz-page-header>
<table ng-controller="identityUsersTableController as table"
hz-table ng-cloak
st-table="table.iusers"
st-safe-src="table.users"
default-sort="name"
default-sort-reverse="false"
class="table-striped table-rsp table-detail modern">
class="table table-striped table-rsp table-detail">
<thead>
<!--
@ -15,7 +13,7 @@
-->
<tr>
<th colspan="100" class="search-header">
<hz-search-bar group-classes="input-group-sm" icon-classes="fa-search"></hz-search-bar>
<hz-search-bar icon-classes="fa-search"></hz-search-bar>
</th>
</tr>

View File

@ -1,11 +0,0 @@
table[ng-controller="identityUsersTableController as table"] {
.detail-expanded .row {
background: none;
padding-left: 2em;
}
&.table-rsp .action-col {
min-width: 12em;
}
}

View File

@ -3,12 +3,6 @@
{% block title %}{% trans "Containers" %}{% endblock %}
{% block page_header %}
<div class='page-header'>
<h2>{% trans "Containers" %}</h2>
</div>
{% endblock page_header %}
{% block main %}
{% if subfolders %}
<div class="page_title table_header">

View File

@ -46,6 +46,7 @@ from openstack_dashboard.dashboards.project.containers import utils
class ContainerView(browsers.ResourceBrowserView):
browser_class = project_browsers.ContainerBrowser
template_name = "project/containers/index.html"
page_title = _("Containers")
def get_containers_data(self):
containers = []

View File

@ -1,7 +1,10 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Images" %}{% endblock %}
{% block page_header %}{% endblock %}
{% block page_header %}
<hz-page-header header="{$ 'Images' | translate $}"></hz-page-header>
{% endblock %}
{% block ng_route_base %}
<base href="{{ WEBROOT }}">

View File

@ -14,7 +14,7 @@ limitations under the License.
-->
<table st-table="displayedItems"
st-safe-src="items"
hz-table class="table-striped table-rsp table-detail modern">
hz-table class="table table-striped table-rsp table-detail">
<thead>
<tr ng-show="showSearchBar">
<th class="search-header" colspan="9">

View File

@ -44,7 +44,7 @@
<allocated>
<table st-table="ctrl.tableData.displayedAllocated"
st-safe-src="ctrl.tableData.allocated" hz-table
class="table-striped table-rsp table-detail modern">
class="table table-striped table-rsp table-detail">
<thead>
<tr>
<th class="expander"></th>
@ -92,7 +92,7 @@
<available>
<table st-table="ctrl.tableData.displayedAvailable"
st-safe-src="ctrl.tableData.available"
hz-table class="table-striped table-rsp table-detail modern">
hz-table class="table table-striped table-rsp table-detail">
<thead>
<tr>
<th class="search-header" colspan="7">

View File

@ -15,7 +15,7 @@
<transfer-table tr-model="ctrl.tableDataMulti" help-text="ctrl.tableHelpText" limits="ctrl.tableLimits">
<allocated validate-number-min="1" ng-model="ctrl.tableDataMulti.allocated.length">
<table st-table="ctrl.tableDataMulti.displayedAllocated" st-safe-src="ctrl.tableDataMulti.allocated" hz-table
class="table-striped table-rsp table-detail modern">
class="table table-striped table-rsp table-detail">
<thead>
<tr>
<th class="reorder"></th>
@ -96,7 +96,7 @@
</allocated>
<available>
<table st-table="ctrl.tableDataMulti.displayedAvailable" st-safe-src="ctrl.tableDataMulti.available"
hz-table class="table-striped table-rsp table-detail modern">
hz-table class="table table-striped table-rsp table-detail">
<thead>
<tr>
<th class="search-header" colspan="8">

View File

@ -1,4 +1,4 @@
<table st-table="row.security_group_rules" class="table-rsp modern security-group-details">
<table st-table="row.security_group_rules" class="table table-rsp security-group-details">
<thead>
<tr>
<th st-sort="direction" st-sort-default translate>Direction</th>

View File

@ -12,7 +12,7 @@
<allocated>
<table st-table="ctrl.tableData.displayedAllocated"
st-safe-src="ctrl.tableData.allocated" hz-table
class="table-striped table-rsp table-detail modern">
class="table table-striped table-rsp table-detail">
<thead>
<tr>
<th class="expander"></th>
@ -58,7 +58,7 @@
<available>
<table st-table="ctrl.tableData.displayedAvailable"
st-safe-src="ctrl.tableData.available"
hz-table class="table-striped table-rsp table-detail modern">
hz-table class="table table-striped table-rsp table-detail">
<thead>
<tr>
<th class="search-header" colspan="7">

View File

@ -118,7 +118,7 @@
<transfer-table help-text="ctrl.helpText"
tr-model="ctrl.tableData">
<allocated validate-number-min="1" ng-model="ctrl.tableData.allocated.length">
<table class="table-striped table-rsp table-detail modern"
<table class="table table-striped table-rsp table-detail"
hz-table
st-safe-src="ctrl.tableData.allocated"
st-table="ctrl.tableData.displayAllocated">
@ -216,7 +216,7 @@
<table st-table="ctrl.tableData.displayedAvailable"
st-safe-src="ctrl.tableData.available"
hz-table
class="table-striped table-rsp table-detail modern">
class="table table-striped table-rsp table-detail">
<!-- transfer table, available table head -->
<thead>

View File

@ -24,7 +24,3 @@ ADD_ANGULAR_MODULES = [
]
AUTO_DISCOVER_STATIC_FILES = True
ADD_SCSS_FILES = [
'dashboard/identity/identity.scss'
]

View File

@ -4,10 +4,6 @@ table[ng-controller="horizon.app.core.images.table.ImagesController as table"] {
background: none;
padding-left: 2em;
}
&.table-rsp .action-col {
min-width: $table-action-col-width;
}
}
.textarea-fixed-width {

View File

@ -1,12 +1,10 @@
<hz-page-header header="{$ 'Images' | translate $}"></hz-page-header>
<table ng-controller="horizon.app.core.images.table.ImagesController as table"
hz-table ng-cloak
st-table="table.images"
st-safe-src="table.imagesSrc"
default-sort="name"
default-sort-reverse="false"
class="table-striped table-rsp table-detail modern">
class="table table-striped table-rsp table-detail">
<thead>
<tr>
<!--
@ -14,9 +12,8 @@
This is where batch actions like searching, creating, and deleting.
-->
<th colspan="100" class="search-header">
<hz-search-bar group-classes="input-group-sm" icon-classes="fa-search">
<actions allowed="table.getBatchActions" type="batch">
</actions>
<hz-search-bar group-classes="input-group" icon-classes="fa-search">
<actions allowed="table.getBatchActions" type="batch"></actions>
</hz-search-bar>
</th>
</tr>
@ -29,7 +26,7 @@
Include expander if you want to inline details.
Include action-col if you want to perform actions.
-->
<th class="select-col">
<th class="multi_select_column">
<input type="checkbox" hz-select-all="table.images">
</th>
@ -42,6 +39,7 @@
<th class="rsp-p2" st-sort="protected" translate>Protected</th>
<th class="rsp-p2" st-sort="disk_format" translate>Format</th>
<th class="rsp-p2" st-sort="size" translate>Size</th>
<th class="actions_column" translate>Actions</th>
</tr>
</thead>
@ -56,7 +54,7 @@
-->
<tr ng-repeat-start="image in table.images track by image.id">
<td class="select-col">
<td class="multi_select_column">
<input type="checkbox"
ng-model="tCtrl.selections[image.id].checked"
hz-select="image">
@ -75,7 +73,7 @@
<td class="rsp-p2">{$ image.disk_format | noValue | uppercase $}</td>
<td class="rsp-p2">{$ image.size | bytes $}</td>
<td class="action-col">
<td class="actions_column">
<!--
Table-row-action-column:
Actions taken here applies to a single item/row.

View File

@ -28,13 +28,3 @@ $navbar-true-height: $navbar-height + $navbar-border-size !default;
#content_body {
width: 100%;
}
.page-header {
margin-top: $padding-base-horizontal;
height: auto;
width: 100%;
h1 {
margin: 0;
}
}

View File

@ -126,14 +126,12 @@ $batch-action-padding: $batch-action-width + 1em !default;
$detail-row-padding: 1em !default;
$expander-width: 1.5em !default;
$reorder-border: 2px solid #1f83c6 !default;
$select-col-width: 2.5em !default;
$table-col-avg-width: 150px !default;
$table-border-color: #cccccc !default;
$table-border: 1px solid $table-border-color !default;
$table-gap-height: 0.5em !default;
$table-padding: 0.5em !default;
$table-stripe-bgcolor: #f9f9f9 !default;
$table-action-col-width: 15em;
/* Tooltip */
$tooltip-bg-color: #fefefe !default;

View File

@ -67,3 +67,7 @@
padding-right: $input-height-base;
}
}
td.actions_column {
width: 1px; // Slight hack to make sure the column shrinks to the button width
}

View File

@ -10,6 +10,14 @@
}
}
& > caption {
text-align: left;
& > .table-title {
font-size: $font-size-h3
}
}
.multi_select_column {
text-align: center;
}

View File

@ -5,5 +5,4 @@
@import "components/navbar";
@import "components/navs";
@import "components/panels";
@import "components/tables";
@import "components/type";

View File

@ -1,25 +0,0 @@
.table {
& > tbody tr,
& > tbody td,
& > tfoot {
border: 1px solid $table-border-color;
}
& > tfoot {
font-size: $font-size-small * .9;
}
& > thead,
& > tfoot {
background: $gray-lighter;
}
& > thead {
border-left: 1px solid $table-border-color;
border-right: 1px solid $table-border-color;
border-top: 1px solid $table-border-color;
th {
border-left: 1px solid $table-border-color;
}
}
}

View File

@ -1,3 +1,5 @@
.page-header {
border-bottom: 0;
margin: 0;
padding: 0;
}

View File

@ -1,15 +1,4 @@
.table {
& > thead {
border-left: none;
border-right: none;
border-top: none;
// Specificity Override
& > tr > .table_header {
border-bottom: 1px solid $table-border-color;
}
}
tr td {
@include transition(background 0.2s);
@ -18,18 +7,6 @@
@include transition(none);
}
}
.table_caption {
background-color: $body-bg;
th {
border-left: none;
}
}
}
.table_column_header {
border-right: 1px solid $table-border-color;
}
// Table sort indicator