Minor extensibility improvements.

* Allow exceptions.handle to include user-defined exception types.
    Fixes bug 948536.
  * Adds a wrapper around the form/table header/table in the base
    _data_table.html template for easier targeting/styling.
  * Moves the rest of the main nav templating into a single template
    for easier customization. Fixes bug 948508.

Change-Id: I045c29744ee01f60b080f2c1bbdc79ea5acf1b86
This commit is contained in:
Gabriel Hurley 2012-03-06 17:43:15 -08:00
parent 8ff0f46b46
commit a32f67967e
5 changed files with 58 additions and 45 deletions

View File

@ -49,6 +49,9 @@ HORIZON_CONFIG = {
# Name of a default dashboard; defaults to first alphabetically if None # Name of a default dashboard; defaults to first alphabetically if None
'default_dashboard': None, 'default_dashboard': None,
'user_home': None, 'user_home': None,
'exceptions': {'unauthorized': [],
'not_found': [],
'recoverable': []}
} }

View File

@ -21,6 +21,7 @@ Exceptions raised by the Horizon code and the machinery for handling them.
import logging import logging
import sys import sys
from django.conf import settings
from django.contrib import messages from django.contrib import messages
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from cloudfiles import errors as swiftclient from cloudfiles import errors as swiftclient
@ -107,6 +108,10 @@ class HandledException(HorizonException):
self.wrapped = wrapped self.wrapped = wrapped
HORIZON_CONFIG = getattr(settings, "HORIZON_CONFIG", {})
EXCEPTION_CONFIG = HORIZON_CONFIG.get("exceptions", {})
UNAUTHORIZED = (keystoneclient.Unauthorized, UNAUTHORIZED = (keystoneclient.Unauthorized,
keystoneclient.Forbidden, keystoneclient.Forbidden,
novaclient.Unauthorized, novaclient.Unauthorized,
@ -115,12 +120,15 @@ UNAUTHORIZED = (keystoneclient.Unauthorized,
glanceclient.NotAuthorized, glanceclient.NotAuthorized,
swiftclient.AuthenticationFailed, swiftclient.AuthenticationFailed,
swiftclient.AuthenticationError) swiftclient.AuthenticationError)
UNAUTHORIZED += tuple(EXCEPTION_CONFIG.get('unauthorized', []))
NOT_FOUND = (keystoneclient.NotFound, NOT_FOUND = (keystoneclient.NotFound,
novaclient.NotFound, novaclient.NotFound,
glanceclient.NotFound, glanceclient.NotFound,
swiftclient.NoSuchContainer, swiftclient.NoSuchContainer,
swiftclient.NoSuchObject) swiftclient.NoSuchObject)
NOT_FOUND += tuple(EXCEPTION_CONFIG.get('not_found', []))
# NOTE(gabriel): This is very broad, and may need to be dialed in. # NOTE(gabriel): This is very broad, and may need to be dialed in.
RECOVERABLE = (keystoneclient.ClientException, RECOVERABLE = (keystoneclient.ClientException,
@ -128,6 +136,7 @@ RECOVERABLE = (keystoneclient.ClientException,
glanceclient.GlanceException, glanceclient.GlanceException,
swiftclient.Error, swiftclient.Error,
AlreadyExists) AlreadyExists)
RECOVERABLE += tuple(EXCEPTION_CONFIG.get('recoverable', []))
def handle(request, message=None, redirect=None, ignore=False, escalate=False): def handle(request, message=None, redirect=None, ignore=False, escalate=False):

View File

@ -1,9 +1,13 @@
{% load horizon %} {% load horizon i18n %}
{% for component in components %} <h1 class="brand clearfix"><a href="{% url horizon:user_home %}">{% trans "OpenStack Dashboard" %}</a></h1>
<div class='clearfix'>
<ul class="nav nav-tabs">
{% for component in components %}
{% if user|can_haz:component %} {% if user|can_haz:component %}
<li{% if current == component.slug %} class="active"{% endif %}> <li{% if current == component.slug %} class="active"{% endif %}>
<a href="{{ component.get_absolute_url }}" tabindex='1'>{{ component.name }}</a> <a href="{{ component.get_absolute_url }}" tabindex='1'>{{ component.name }}</a>
</li> </li>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</ul>
</div>

View File

@ -1,10 +1,11 @@
<form action="{{ table.get_absolute_url }}" method="POST">{% csrf_token %} <div class="table_wrapper">
<div class='table_header'> <form action="{{ table.get_absolute_url }}" method="POST">{% csrf_token %}
<div class='table_header'>
<h3 class='table_title'>{{ table }}</h3> <h3 class='table_title'>{{ table }}</h3>
{{ table.render_table_actions }} {{ table.render_table_actions }}
</div> </div>
{% with columns=table.get_columns rows=table.get_rows %} {% with columns=table.get_columns rows=table.get_rows %}
<table id="{{ table.name }}" class="table table-bordered table-striped"> <table id="{{ table.name }}" class="table table-bordered table-striped">
<thead> <thead>
<tr> <tr>
{% for column in columns %} {% for column in columns %}
@ -32,6 +33,7 @@
</td> </td>
</td> </td>
</tfoot> </tfoot>
</table> </table>
{% endwith %} {% endwith %}
</form> </form>
</div>

View File

@ -1,12 +1,7 @@
{% load horizon i18n %} {% load horizon i18n %}
<div class='sidebar'> <div class='sidebar'>
<h1 class="brand clearfix"><a href="{% url horizon:user_home %}">{% trans "OpenStack Dashboard" %}</a></h1>
<div class='clearfix'>
<ul class="nav nav-tabs">
{% horizon_main_nav %} {% horizon_main_nav %}
</ul>
</div>
{% if request.horizon.dashboard.supports_tenants %} {% if request.horizon.dashboard.supports_tenants %}
<div id="tenant_switcher" class="dropdown switcher_bar" tabindex='1'> <div id="tenant_switcher" class="dropdown switcher_bar" tabindex='1'>