Horizon Login now inherits from Bootstrap Theme

The Horizon login page was not properly inheriting its styles from
its theme.  The implementation was making use of the _modal_form.html
template just to inherit a form, but there was no way to remove
the modal classes with that implementation.

The login page now uses a standard Bootstrap 'panel'.  This will
inherit the look and feel of any theme more naturally when its not
inside of a modal, as not all themes use box-shadow outside of a
modal; some chose to be very flat on purpose, and the built in
panels take advantage of this.

When used within the Region selector, it does need to exist within
a modal, so some simple logic was added for the classes necessary.

The panel is a little bit wider than it was before, but it is now
a standard Bootstrap column size, so its responsive down to a very
small screen size.

The modal is a little bit wider than it was before as well, as it is
is now the standard medium modal size for Bootstrap.

Improvements:
 * Logo is now an <img> tag, which means it can automagically resize
   to fit in the available space
 * Unneccesary styles removed
 * _splash.scss was only being used in _login.html, which was
   confusing, so _splash.scss is renamed to _login.scss, and is now a
   class based style, so it can live in /components
 * Its now Theme ready and responsive
 * Region Selector Login now has a proper modal backdrop
 * has-error help-text should not be alert alert-danger

Partially-Implements: blueprint horizon-theme-css-reorg
Partially-Implements: blueprint bootstrap-html-standards
Change-Id: Ie968414ab8ef2154623edfc21ce5623e8c4057c6
This commit is contained in:
Diana Whitten 2015-09-01 18:25:01 -07:00
parent 38b4be52d4
commit 20ff47185f
21 changed files with 227 additions and 110 deletions

View File

@ -128,6 +128,7 @@ full use of the Bootstrap theme architecture.
~~~~~~~~~~~~~~
* Tables_
* Login_
Step 1
------
@ -197,6 +198,25 @@ The standard Bootstrap tables will be borderless by default. If you wish to
add a border, like the ``default`` theme, see
``openstack_dashboard/themes/default/horizon/components/_tables.scss``
.. _Login:
Login
-----
Login Splash Page
~~~~~~~~~~~~~~~~~
The login splash page now uses a standard Bootstrap panel in its implementation.
See the **Panels** section in your variables file to variables to easily
customize.
Modal Login
~~~~~~~~~~~
The modal login experience, as used when switching regions, uses a standard
Bootstrap dialog. See the **Modals** section of your variables file for
specific variables to customize.
Bootswatch and Material Design
------------------------------

View File

@ -47,7 +47,7 @@
* `helpText` exists outside of element,
* so we have to traverse one node up
*/
var helpText = element.parent().find('#help_text');
var helpText = element.parent().find('.help_text');
helpText.hide();
// Update the visuals when user selects item from dropdown

View File

@ -1,5 +1,5 @@
<form>
<p id="help_text">Some help text.</p>
<p class="help_text">Some help text.</p>
<fieldset hz-login-finder>
<div class="form-group"><input id="id_username"></div>
<div class="form-group"><input id="id_password"></div>

View File

@ -64,7 +64,7 @@
authType = element.find('#id_auth_type');
userInput = element.find("#id_username").parents('.form-group');
passwordInput = element.find("#id_password").parents('.form-group');
helpText = element.find('#help_text');
helpText = element.find('.help_text');
$rootScope.$apply();
});
@ -96,7 +96,7 @@
passwordInput = element.find("#id_password").parents('.form-group');
domainInput = element.find("#id_domain").parents('.form-group');
regionInput = element.find("#id_region").parents('.form-group');
helpText = element.find('#help_text');
helpText = element.find('.help_text');
$rootScope.$apply();
});

View File

@ -1,5 +1,5 @@
<form>
<p id="help_text">Some help text.</p>
<p class="help_text">Some help text.</p>
<fieldset hz-login-finder>
<div>
<select id="id_auth_type">

View File

@ -4,10 +4,10 @@
This help text will only show up if websso is enabled
because websso introduces new authentication mechanisms.
{% endcomment %}
<p id="help_text">
<div class="help_text alert alert-info">
{% block websso-help-text %}
{% blocktrans %}
If you are not sure which authentication method to use, contact your administrator.
{% endblocktrans %}
{% endblock %}
</p>
</div>

View File

@ -1,46 +1,7 @@
{% extends "horizon/common/_modal_form.html" %}
{% load i18n %}
{% block modal-header %}{% trans "Log In" %}{% endblock %}
{% block modal_class %}login {% if hide %}modal{% endif %}{% endblock %}
{% block form_action %}{% url 'login' %}{% endblock %}
{% block ng_controller %}hzLoginController{% endblock %}
{% block autocomplete %}{{ HORIZON_CONFIG.password_autocomplete }}{% endblock %}
{% block modal-body %}
{% comment %}
These fake fields are required to prevent Chrome v34+ from autofilling form.
{% endcomment %}
{% if HORIZON_CONFIG.password_autocomplete != "on" %}
<div class="fake_credentials" style="display: none">
<input type="text" name="fake_email" value="" />
<input type="password" name="fake_password" value="" />
</div>
{%endif%}
{% include "auth/_description.html" %}
<fieldset hz-login-finder>
{% if request.user.is_authenticated and 'next' in request.GET %}
<div class="form-group clearfix error">
<span class="help-block"><p>{% trans "You do not have permission to access the resource:" %}</p>
<p><b>{{ request.GET.next }}</b></p>
<p>{% url 'horizon:user_home' as home_url %}{% blocktrans %}Login as different user or go back to <a href="{{ home_url }}"> home page</a>{% endblocktrans %}</p>
</span>
</div>
{% endif %}
{% if request.COOKIES.logout_reason %}
<div class="form-group clearfix error" id="logout_reason">
<span class="help-block alert alert-danger"><p>{{ request.COOKIES.logout_reason }}</p></span>
</div>
{% endif %}
{% if next %}<input type="hidden" name="{{ redirect_field_name }}" value="{{ next }}" />{% endif %}
{% include "horizon/common/_form_fields.html" %}
</fieldset>
{% endblock %}
{% block modal-footer %}
<button id="loginBtn" type="submit" class="btn btn-primary pull-right">
<span ng-show="auth_type==='credentials'">{% trans "Sign In" %}</span>
<span ng-hide="auth_type==='credentials'" ng-cloak>{% trans "Connect" %}</span>
</button>
{% endblock %}
{% if 'is_modal' in request.GET or 'is_modal' in request.POST %}
{% include 'auth/_login_modal.html' %}
{% else %}
{% include 'auth/_login_page.html' %}
{% endif %}

View File

@ -0,0 +1,80 @@
{% load i18n %}
{% load url from future %}
{% block pre_login %}
<form id="" class="ng-pristine ng-valid ng-scope"
method="POST"
action="{% url 'login' %}"
autocomplete="off"
ng-controller="hzLoginController">
{% csrf_token %}
{% endblock %}
<div class="panel panel-default">
<div class="panel-heading">
{% block login_header %}
<h3 class="login-title">
{% trans 'Log in' %}
</h3>
{% endblock %}
</div>
<div class="panel-body">
{% block login_body %}
{% comment %}
These fake fields are required to prevent Chrome v34+ from autofilling form.
{% endcomment %}
{% if HORIZON_CONFIG.password_autocomplete != "on" %}
<div class="fake_credentials" style="display: none">
<input type="text" name="fake_email" value="" />
<input type="password" name="fake_password" value="" />
</div>
{%endif%}
{% include "auth/_description.html" %}
<fieldset hz-login-finder>
{% if request.user.is_authenticated and 'next' in request.GET %}
<div class="form-group clearfix error help-block alert alert-danger">
<p>
{% trans "You do not have permission to access the resource:" %}
</p>
<p>
<strong>
{{ request.GET.next }}
</strong>
</p>
<p>
{% url 'horizon:user_home' as home_url %}
{% blocktrans %}
Login as different user or go back to <a href="{{ home_url }}">home page</a>
{% endblocktrans %}
</p>
</div>
{% endif %}
{% if request.COOKIES.logout_reason %}
<div class="form-group clearfix error help-block alert alert-danger" id="logout_reason">
<p>{{ request.COOKIES.logout_reason }}</p>
</div>
{% endif %}
{% if next %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ next }}" />
{% endif %}
{% include "horizon/common/_form_fields.html" %}
</fieldset>
{% endblock %}
</div>
<div class="panel-footer">
{% block login_footer %}
<button id="loginBtn" type="submit" class="btn btn-primary pull-right">
<span ng-show="auth_type==='credentials'">{% trans "Sign In" %}</span>
<span ng-hide="auth_type==='credentials'" ng-cloak>{% trans "Connect" %}</span>
</button>
<div class="clearfix"></div>
{% endblock %}
</div>
</div>
{% block post_login%}
</form>
{% endblock %}

View File

@ -0,0 +1,28 @@
{% extends 'auth/_login_form.html' %}
{% load i18n %}
{% block pre_login %}
<div class="login modal">
<div class="modal-dialog">
<div class="modal-content">
{{ block.super }}
{% endblock %}
{% block login_header %}
{{ block.super }}
<button class="close" aria-hidden="true" data-dismiss="modal" type="button">
<span class="fa fa-close"></span>
</button>
{% endblock %}
{% block login_body %}
{{ block.super }}
<input type="hidden" value="" name="is_modal">
{% endblock %}
{% block post_login %}
{{ block.super }}
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,23 @@
{% extends 'auth/_login_form.html' %}
{% load i18n %}
{% block pre_login %}
<div class="container login">
<div class="row">
<div class="col-xs-11 col-sm-8 col-md-6 col-lg-5 horizontal-center">
{{ block.super }}
{% endblock %}
{% block login_header %}
<div class="text-center">
<img class="splash-logo" src="{{ STATIC_URL }}dashboard/img/logo-splash.png">
</div>
{{ block.super }}
{% endblock %}
{% block post_login %}
{{ block.super }}
</div>
</div>
</div>
{% endblock %}

View File

@ -20,7 +20,7 @@
</label>
{% endif %}
{% for error in field.errors %}
<span class="help-block alert alert-danger {{ form.error_css_class }}">{{ error }}</span>
<span class="help-block {{ form.error_css_class }}">{{ error }}</span>
{% endfor %}
</div>
</div>
@ -42,7 +42,7 @@
{% endfor %}
{% for error in field.errors %}
<span class="help-block alert alert-danger {{ form.error_css_class }}">{{ error }}</span>
<span class="help-block {{ form.error_css_class }}">{{ error }}</span>
{% endfor %}
</div>
@ -70,7 +70,7 @@
{% endif %}
{% endwith %}
{% for error in field.errors %}
<span class="help-block alert alert-danger {{ form.error_css_class }}">{{ error }}</span>
<span class="help-block {{ form.error_css_class }}">{{ error }}</span>
{% endfor %}
</div>
{% endif %}

View File

@ -7,7 +7,7 @@
{% for region in regions.available %}
{% if region.name != regions.current.name %}
<li>
<a class="ajax-modal" href="{% url 'login' %}?region={{ region.endpoint|urlencode }}">
<a class="ajax-modal" href="{% url 'login' %}?region={{ region.endpoint|urlencode }}&is_modal">
{{ region.name }}
</a>
</li>

View File

@ -1,33 +0,0 @@
/**
* Styling for the splash/login page.
* Restyled for federated login.
*/
#splash {
.login {
background: url(../img/logo-splash.png) no-repeat center 35px;
position: absolute;
top: 80px;
left: 50%;
margin: 0 0 0 -195px;
padding-top: 170px;
width: 390px;
border: 1px solid $border-color;
max-height: none;
border-radius: 6px;
@include box-shadow(0 3px 7px rgba(0, 0, 0, 0.3));
background-clip: padding-box;
p#help_text {
display: none;
padding: 1em 0.5em;
margin: 0;
}
}
p.help-block {
display: none;
}
}

View File

@ -0,0 +1,7 @@
/* Some utility classes useful everywhere */
.row .horizontal-center,
.horizontal-center {
float: none;
margin: 0 auto;
}

View File

@ -0,0 +1,28 @@
/**
* Styling for the splash/login page.
*/
.login {
margin-top: $navbar-height*2;
.splash-logo {
padding: $padding-large-horizontal $padding-large-vertical;
max-width: 100%;
}
.help_text {
display: none;
}
.login-title {
display: inline-block;
}
ul.errorlist {
padding-left: 0;
}
.modal-content .panel {
margin-bottom: 0;
}
}

View File

@ -7,13 +7,16 @@
// Horizon Mixins
@import "mixins";
// Horizon Util
@import "util";
// Vendor Components
@import "/bootstrap/scss/bootstrap";
@import "/horizon/lib/font-awesome/scss/font-awesome.scss";
@import "/horizon/lib/magic_search/magic_search.scss";
// Dashboard Components
@import "splash";
@import "components/login";
@import "components/resource_browser";
@import "components/sidebar";
@import "components/navbar";
@ -98,10 +101,6 @@ ul {
margin: 0;
}
.login ul.errorlist {
padding-left: 0;
}
// Disc-styled list. This list should be used to build bullet-items lists.
.list-bullet {
list-style: disc;
@ -254,7 +253,6 @@ a.current_item:hover h4 {
}
.modal > form,
.login > form,
.alert-actions > form {
margin-bottom: 0;
}
@ -318,17 +316,6 @@ a.current_item:hover h4 {
@extend .form-control;
}
form label {
text-align: left;
color: $gray;
font-weight: bold;
display: inline-block;
}
.login.modal .modal-dialog {
width: 390px;
}
.modal.fullscreen .modal-dialog {
width: 90%;
margin: auto;

View File

@ -24,7 +24,7 @@ class LoginPage(pageobject.PageObject):
_login_username_field_locator = (by.By.ID, 'id_username')
_login_password_field_locator = (by.By.ID, 'id_password')
_login_submit_button_locator = (by.By.CSS_SELECTOR,
'div.modal-footer button.btn')
'div.panel-footer button.btn')
_login_logout_reason_locator = (by.By.ID, 'logout_reason')
def __init__(self, driver, conf):

View File

@ -1,4 +1,7 @@
@import '/bootstrap/scss/bootstrap/mixins/vendor-prefixes';
@import 'components/dropdowns';
@import 'components/navbar';
@import 'components/navs';
@import 'components/panels';
@import 'components/tables';

View File

@ -689,16 +689,16 @@ $list-group-link-heading-color: #333 !default;
$panel-bg: #fff !default;
$panel-body-padding: 15px !default;
$panel-heading-padding: 10px 15px !default;
$panel-footer-padding: $panel-heading-padding !default;
$panel-footer-padding: 15px !default;
$panel-border-radius: $border-radius-base !default;
//** Border color for elements within panels
$panel-inner-border: #ddd !default;
$panel-footer-bg: #f5f5f5 !default;
$panel-footer-bg: $panel-bg !default;
$panel-default-text: $gray-dark !default;
$panel-default-border: #ddd !default;
$panel-default-heading-bg: #f5f5f5 !default;
$panel-default-heading-bg: $panel-bg !default;
$panel-primary-text: #fff !default;
$panel-primary-border: $brand-primary !default;

View File

@ -0,0 +1,3 @@
.panel {
@include box-shadow(0 3px 7px rgba(0, 0, 0, 0.3));
}

View File

@ -11,3 +11,13 @@
// The 114 is a legacy value to push the context-menu over
padding-right: 114px;
}
// TODO(hurgleburgler): This seems awfully global ... and strange
// need to look into why we are actually doing this.
form label {
text-align: left;
color: $gray;
font-weight: bold;
display: inline-block;
}