Skip to content
Permalink
Browse files

Bootstrap 2!

Implements blueprint bootstrap-2.

Notable changes:

  * Uses new split-dropdown buttons. Fixes bug 920820 and fixes bug 918452.
  * Uses bootstrap dropdowns for all menus. No differing implementations now.
  * Reworks how css class attributes are consructed on actions to make them
    easier to works with and support default classes.

Change-Id: Ia25edb6d8ca8a2d1ef30e8f9a36331eff4c7ae86
  • Loading branch information...
gabrielhurley committed Jan 24, 2012
1 parent f60aa08 commit db1842c3d674a3155e0a193e98db8684a882f737
Showing with 14,347 additions and 3,075 deletions.
  1. +0 −3 horizon/horizon/dashboards/nova/templates/nova/base.html
  2. +1 −1 horizon/horizon/dashboards/nova/templates/nova/images_and_snapshots/images/_launch.html
  3. +1 −1 horizon/horizon/dashboards/nova/templates/nova/images_and_snapshots/images/index.html
  4. +1 −1 horizon/horizon/dashboards/nova/templates/nova/instances_and_volumes/instances/_no_instances.html
  5. +1 −1 horizon/horizon/dashboards/nova/templates/nova/networks/detail.html
  6. +1 −1 horizon/horizon/dashboards/nova/templates/nova/networks/index.html
  7. +1 −1 horizon/horizon/dashboards/nova/templates/nova/overview/usage.html
  8. +0 −3 horizon/horizon/dashboards/settings/templates/settings/base.html
  9. +0 −3 horizon/horizon/dashboards/syspanel/overview/views.py
  10. +0 −3 horizon/horizon/dashboards/syspanel/templates/syspanel/base.html
  11. +7 −5 horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/usage.html
  12. +19 −2 horizon/horizon/tables/actions.py
  13. +4 −4 horizon/horizon/templates/horizon/_messages.html
  14. +1 −1 horizon/horizon/templates/horizon/common/_data_table.html
  15. +5 −0 horizon/horizon/templates/horizon/common/_data_table_row_action.html
  16. +22 −10 horizon/horizon/templates/horizon/common/_data_table_row_actions.html
  17. +1 −1 horizon/horizon/templates/horizon/common/_modal_form.html
  18. +11 −0 horizon/horizon/templates/horizon/common/_region_selector.html
  19. +7 −7 horizon/horizon/templates/horizon/common/_sidebar.html
  20. +1 −3 horizon/horizon/tests/table_tests.py
  21. +2,391 −1,516 openstack-dashboard/dashboard/static/dashboard/css/bootstrap.css
  22. +511 −298 openstack-dashboard/dashboard/static/dashboard/css/bootstrap.min.css
  23. +90 −114 openstack-dashboard/dashboard/static/dashboard/css/style.css
  24. +106 −0 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/README.md
  25. +85 −0 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/bootstrap-alert.js
  26. +0 −111 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/bootstrap-alerts.js
  27. +98 −0 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/bootstrap-button.js
  28. +153 −0 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/bootstrap-carousel.js
  29. +134 −0 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/bootstrap-collapse.js
  30. +50 −20 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/bootstrap-dropdown.js
  31. +87 −126 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/bootstrap-modal.js
  32. +46 −28 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/bootstrap-popover.js
  33. +59 −43 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/bootstrap-scrollspy.js
  34. +125 −0 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/bootstrap-tab.js
  35. +0 −77 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/bootstrap-tabs.js
  36. +270 −0 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/bootstrap-tooltip.js
  37. +51 −0 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/bootstrap-transition.js
  38. +0 −303 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/bootstrap-twipsy.js
  39. +252 −0 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/bootstrap-typeahead.js
  40. +19 −8 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/tests/index.html
  41. +5 −5 ...ard/dashboard/static/dashboard/js/bootstrap/tests/unit/{bootstrap-alerts.js → bootstrap-alert.js}
  42. +54 −0 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/tests/unit/bootstrap-button.js
  43. +25 −0 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/tests/unit/bootstrap-collapse.js
  44. +11 −10 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/tests/unit/bootstrap-dropdown.js
  45. +75 −141 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/tests/unit/bootstrap-modal.js
  46. +24 −7 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/tests/unit/bootstrap-popover.js
  47. +3 −3 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/tests/unit/bootstrap-scrollspy.js
  48. +46 −0 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/tests/unit/bootstrap-tab.js
  49. +0 −77 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/tests/unit/bootstrap-tabs.js
  50. +62 −0 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/tests/unit/bootstrap-tooltip.js
  51. +13 −0 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/tests/unit/bootstrap-transition.js
  52. +0 −81 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/tests/unit/bootstrap-twipsy.js
  53. +128 −0 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/tests/unit/bootstrap-typeahead.js
  54. +9,252 −0 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/tests/vendor/jquery.js
  55. +2 −2 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/tests/vendor/qunit.css
  56. +1 −1 openstack-dashboard/dashboard/static/dashboard/js/bootstrap/tests/vendor/qunit.js
  57. +4 −23 openstack-dashboard/dashboard/static/dashboard/js/forms.js
  58. +5 −2 openstack-dashboard/dashboard/static/dashboard/js/modals.js
  59. +1 −1 openstack-dashboard/dashboard/static/dashboard/js/navigation.js
  60. +7 −1 openstack-dashboard/dashboard/templates/_header.html
  61. +18 −26 openstack-dashboard/dashboard/templates/base.html
@@ -5,9 +5,6 @@
{% endblock %}

{% block main %}
<div id='main_content' class="content">
{% block page_header %}{% endblock %}
{% include "horizon/_messages.html" %}
{% block dash_main %}{% endblock %}
</div>
{% endblock %}
@@ -16,7 +16,7 @@
<div class="right">
<h3>{% trans "Description:" %}</h3>
<p>{% trans "Specify the details for launching an instance. Also please make note of the table below; all tenants have quotas which define the limit of resources they are allowed to provision." %}</p>
<table border="0">
<table class="table table-striped table-bordered">
<tr>
<th>{% trans "Quota Name" %}</th>
<th>{% trans "Limit" %}</th>
@@ -12,7 +12,7 @@
{% if images %}
{% include 'nova/images_and_snapshots/images/_list.html' %}
{% else %}
<div class="alert-message block-message info">
<div class="alert alert-block alert-info">
<p><strong>{% trans "Info: " %}</strong>{% trans "There are currently no images." %}</p>
</div>
{% endif %}
@@ -1,6 +1,6 @@
{% load i18n %}

<div class="alert-message block-message info">
<div class="alert alert-block alert-info">
<p><strong>{% trans "Info: " %}</strong>{% trans "There are no instances running. Launch an instance from the Images Page." %}</p>
<div class="alert-actions">
<a class="btn small primary" href='{% url horizon:nova:images_and_snapshots:index %}'>{% trans "Images Page" %}</a>
@@ -13,7 +13,7 @@
{% include 'nova/networks/_detail.html' %}
<a id="network_create_link" class="btn small" href="{% url horizon:nova:networks:port_create network.id %}">{% trans "Create Ports" %}</a>
{% else %}
<div class="alert-message block-message info">
<div class="alert alert-block alert-info">
<h2>{% trans "Info" %}</h2>
<p>{% trans "There are currently no ports in this network." %} <a class='btn small' href="{% url horizon:nova:networks:port_create network.id %}">{% trans "Create Ports" %}</a></p>
</div>
@@ -14,7 +14,7 @@
{% url horizon:nova:networks:create as dash_net_url %}
<a id="network_create_link" class="btn small" href="{{ dash_net_url }}">{% trans "Create New Network" %}</a>
{% else %}
<div class="alert-message block-message info">
<div class="alert alert-block alert-info">
<p><strong>{% trans "Info: " %}</strong>{% trans "There are currently no networks." %}</p>
<div class="alert-actions">
<a class="btn small primary" href='{% url horizon:nova:networks:create %}'>{% trans "Create A Network" %}</a>
@@ -46,7 +46,7 @@ <h3>Disk</h3>
<h3>Server Usage Summary</h3>
</div>

<table class="zebra-striped">
<table class="table table-striped table-bordered">
<tr id='headings'>
<th>{% trans "Name" %}</th>
<th>{% trans "User" %}</th>
@@ -5,9 +5,6 @@
{% endblock %}

{% block main %}
<div id='main_content' class="content">
{% block page_header %}{% endblock %}
{% include "horizon/_messages.html" %}
{% block settings_main %}{% endblock %}
</div>
{% endblock %}
@@ -22,8 +22,6 @@
import logging

from dateutil.relativedelta import relativedelta
from django import template
from django import http
from django import shortcuts
from django.conf import settings
from django.contrib import messages
@@ -120,7 +118,6 @@ def usage(request):
global_summary = GlobalSummary(request)
if date_start > GlobalSummary.current_month():
messages.error(request, _('No data for the selected period'))
date_end = date_start
datetime_end = datetime_start
else:
global_summary.usage(datetime_start, datetime_end)
@@ -5,9 +5,6 @@
{% endblock %}

{% block main %}
<div id='main_content' class="content">
{% block page_header %}{% endblock %}
{% include "horizon/_messages.html" %}
{% block syspanel_main %}{% endblock %}
</div>
{% endblock %}
@@ -19,7 +19,7 @@ <h3>{% trans "Monitoring" %}: </h3>
</div>
{% endif %}

<form action="" method="get" id="date_form">
<form action="" method="get" id="date_form" class="form-horizontal">
<h3>{% trans "Select a month to query its usage" %}: </h3>
<div class="form-row">
{{ dateform.month }}
@@ -36,12 +36,14 @@ <h3>{% trans "Select a month to query its usage" %}: </h3>

{% if usage_list %}
<div id="usage">
<div class='table_title wide'>
<a class="csv_download_link pull-right" href="{{ csv_link }}">{% trans "Download CSV" %} &raquo;</a>
<h3>{% trans "Server Usage Summary" %}</h3>
<div class="table_header">
<div class='table_title wide'>
<a class="csv_download_link pull-right" href="{{ csv_link }}">{% trans "Download CSV" %} &raquo;</a>
<h3>{% trans "Server Usage Summary" %}</h3>
</div>
</div>

<table class="zebra-striped">
<table class="table table-striped table-bordered">
<tr id="headings">
<th>{% trans "Tenant" %}</th>
<th>{% trans "Instances" %}</th>
@@ -14,10 +14,12 @@
# License for the specific language governing permissions and limitations
# under the License.

import copy
import logging
import new

from django import shortcuts
from django.conf import settings
from django.forms.util import flatatt
from django.contrib import messages
from django.core import urlresolvers
@@ -28,14 +30,20 @@

LOG = logging.getLogger(__name__)

# For Bootstrap integration, can be overridden in settings.
ACTION_CSS_CLASSES = ("btn", "small")


class BaseAction(object):
""" Common base class for all ``Action`` classes. """
table = None
handles_multiple = False
attrs = {}
requires_input = False

def __init__(self):
self.attrs = getattr(self, "attrs", {})
self.classes = []

def allowed(self, request, datum):
""" Determine whether this action is allowed for the current request.
@@ -60,7 +68,16 @@ def attr_string(self):
Returns a flattened string of HTML attributes based on the
``attrs`` dict provided to the class.
"""
return flatatt(self.attrs)
final_attrs = copy.copy(self.attrs)
# Handle css class concatenation
default = " ".join(getattr(settings,
"ACTION_CSS_CLASSES",
ACTION_CSS_CLASSES))
defined = self.attrs.get('class', '')
additional = " ".join(self.classes)
final_classes = " ".join((defined, default, additional)).strip()
final_attrs.update({'class': final_classes})
return flatatt(final_attrs)

def __repr__(self):
return "<%s: %s>" % (self.__class__.__name__, self.name)
@@ -1,22 +1,22 @@
{% load i18n %}
{% for message in messages %}
{% if "info" in message.tags %}
<div class="alert-message info">
<div class="alert alert-block alert-info">
<p><strong>{% trans "Info: " %}</strong>{{ message }}</p>
</div>
{% endif %}
{% if "warning" in message.tags %}
<div class="alert-message warning">
<div class="alert alert-block alert-warning">
<p><strong>{% trans "Warning: " %}</strong>{{ message }}</p>
</div>
{% endif %}
{% if "success" in message.tags %}
<div class="alert-message success">
<div class="alert alert-block alert-success">
<p><strong>{% trans "Success: " %}</strong>{{ message }}</p>
</div>
{% endif %}
{% if "error" in message.tags %}
<div class="alert-message error">
<div class="alert alert-block alert-error">
<p><strong>{% trans "Error: " %}</strong>{{ message }}</p>
</div>
{% endif %}
@@ -4,7 +4,7 @@ <h3 class='table_title'>{{ table }}</h3>
{{ table.render_table_actions }}
</div>
{% with columns=table.get_columns rows=table.get_rows %}
<table id="{{ table.name }}" class="zebra-striped">
<table id="{{ table.name }}" class="table table-bordered table-striped">
<thead>
<tr>
{% for column in columns %}
@@ -0,0 +1,5 @@
{% if action.method != "GET" %}
<button {{ action.attr_string|safe }} name="action" value="{{ action.table.name }}__{{ action.name }}__{{ row_id }}" type="submit">{{ action.verbose_name }}</button>
{% else %}
<a href='{{ action.bound_url }}' {{ action.attr_string|safe }}>{{ action.verbose_name }}</a>
{% endif %}
@@ -1,15 +1,27 @@
{% load horizon %}

{% if row_actions %}
<ul class="row_actions unstyled clearfix{% if row_actions|length == 1 %} single{% endif %}">
{% for action in row_actions %}
<li class="action{% if forloop.first and row_actions|length > 1 %} primary{% endif %}">
{% if action.method != "GET" %}
<button {{ action.attr_string }} name="action" value="{{ action.table.name }}__{{ action.name }}__{{ row_id }}" type="submit">{{ action.verbose_name }}</button>
{% if row_actions|length > 1 %}
<div class="btn-group">
{% for action in row_actions %}
{% if forloop.first %}
{% include "horizon/common/_data_table_row_action.html" %}
<a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
<span class="caret"></span>
</a>
<ul class="dropdown-menu row_actions clearfix">
{% else %}
<a href='{{ action.bound_url }}' {{ action.attr_string|safe }}>{{ action.verbose_name }}</a>
<li class="clearfix">
{% include "horizon/common/_data_table_row_action.html" %}
</li>
{% endif %}
</li>
{% endfor %}
</ul>
{% if forloop.last %}
</ul>
{% endif %}
{% endfor %}
</div>
{% endif %}
{% if row_actions|length == 1%}
{% for action in row_actions %}
{% include "horizon/common/_data_table_row_action.html" %}
{% endfor %}
{% endif %}
@@ -1,6 +1,6 @@
<div id="{% block modal_id %}{% endblock %}" class="{% block modal_class %}modal{% if hide %} hide {% else %} static_page{% endif %}{% endblock %}">
<div class="modal-header">
{% if hide %}<a href="#" class="close">&times;</a>{% endif %}
{% if hide %}<a href="#" class="close" data-dismiss="modal">&times;</a>{% endif %}
<h3>{% block modal-header %}{% endblock %}</h3>
</div>
{% if table %}
@@ -0,0 +1,11 @@
{% if region.support %}
<div id="region_switcher" class="dropdown switcher_bar" tabindex='1'>
<a class="dropdown-toggle" data-toggle="dropdown" href="#region_switcher">
{{ region.name }}
</a>
<ul id="region_list" class="dropdown-menu">
<li class='divider'></li>
<li><a href="{% url horizon:auth_logout %}">Change Regions</a></li>
</ul>
</div>
{% endif %}
@@ -1,21 +1,21 @@
{% load horizon i18n %}

<div class='sidebar'>
<div class='fluid-sidebar'>
<h1 class="brand clearfix"><a href="{% url horizon:user_home %}">{% trans "OpenStack Dashboard" %}</a></h1>
<div class='clearfix'>
<ul class="tabs">
<ul class="nav tabs">
{% horizon_main_nav %}
</ul>
</div>

{% if request.horizon.dashboard.supports_tenants %}
<div id="tenant_switcher" class="switcher_bar">
<a id="current_tenant" class="current_item" href="{% url horizon:nova:overview:index %}">
<div id="tenant_switcher" class="dropdown switcher_bar" tabindex='1'>
<a class="dropdown-toggle" data-toggle="dropdown" href="#tenant_switcher">
<h4>Project</h4>
<h3>{{ request.user.tenant_name }}</h3>
</a>
<a class="drop_btn" href="#">&nbsp;</a>
<ul id="user_tenant_list" class="item_list">
</a>
<ul id="tenant_list" class="dropdown-menu">
<li class='divider'></li>
{% for tenant in authorized_tenants %}
{% if tenant.enabled %}
<li><a href="{% url horizon:auth_switch tenant.id %}">{{ tenant.name }}</a></li>
@@ -18,7 +18,6 @@
from django import shortcuts
from django.core.urlresolvers import reverse

import horizon
from horizon import tables
from horizon import test

@@ -323,8 +322,7 @@ def test_table_rendering(self):
# Row actions
row_actions = self.table.render_row_actions(TEST_DATA[0])
resp = http.HttpResponse(row_actions)
self.assertContains(resp, "primary", 1)
self.assertContains(resp, "<li", 2)
self.assertContains(resp, "<li", 1)
self.assertContains(resp, "my_table__click__1", 1)
self.assertContains(resp, "/auth/login/", 1)
self.assertContains(resp, "ajax-modal", 1)

0 comments on commit db1842c

Please sign in to comment.
You can’t perform that action at this time.