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:
parent
38b4be52d4
commit
20ff47185f
@ -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
|
||||
------------------------------
|
||||
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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();
|
||||
});
|
||||
|
||||
|
@ -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">
|
||||
|
@ -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>
|
||||
|
@ -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 %}
|
||||
|
80
horizon/templates/auth/_login_form.html
Normal file
80
horizon/templates/auth/_login_form.html
Normal 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 %}
|
28
horizon/templates/auth/_login_modal.html
Normal file
28
horizon/templates/auth/_login_modal.html
Normal 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 %}
|
23
horizon/templates/auth/_login_page.html
Normal file
23
horizon/templates/auth/_login_page.html
Normal 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 %}
|
@ -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 %}
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
7
openstack_dashboard/static/dashboard/scss/_util.scss
Normal file
7
openstack_dashboard/static/dashboard/scss/_util.scss
Normal file
@ -0,0 +1,7 @@
|
||||
/* Some utility classes useful everywhere */
|
||||
|
||||
.row .horizontal-center,
|
||||
.horizontal-center {
|
||||
float: none;
|
||||
margin: 0 auto;
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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):
|
||||
|
@ -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';
|
@ -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;
|
||||
|
@ -0,0 +1,3 @@
|
||||
.panel {
|
||||
@include box-shadow(0 3px 7px rgba(0, 0, 0, 0.3));
|
||||
}
|
@ -10,4 +10,14 @@
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user