mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-23 15:40:01 -06:00
parent
b69d30072a
commit
3b9280c974
@ -120,38 +120,6 @@ textarea[readonly] {
|
||||
padding: 0.2em;
|
||||
}
|
||||
|
||||
/* ---- Header ---- */
|
||||
.header {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 6px;
|
||||
right: 6px;
|
||||
height: 34px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.header a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.header a:link {
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.header a:visited {
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.header span.header-logo {
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
.header span.header-logo a img {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* ---- Password expiration */
|
||||
|
||||
.header-passwordexpires {
|
||||
@ -164,20 +132,6 @@ textarea[readonly] {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* ---- Logged-in As ---- */
|
||||
.header-right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.header-loggedinas {
|
||||
line-height: 34px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.header-loggedinas .login {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* ---- Notification area ---- */
|
||||
|
||||
.notification-area {
|
||||
@ -231,7 +185,7 @@ textarea[readonly] {
|
||||
|
||||
.facet {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
top: 110px;
|
||||
left: 10px;
|
||||
right: 10px;
|
||||
bottom: 0;
|
||||
@ -253,7 +207,7 @@ textarea[readonly] {
|
||||
|
||||
.facet-title {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
top: 10px;
|
||||
left: 0;
|
||||
color: gray;
|
||||
display: block;
|
||||
@ -261,6 +215,7 @@ textarea[readonly] {
|
||||
|
||||
.facet-title h3 {
|
||||
margin: 0;
|
||||
line-height: 1.8em;
|
||||
}
|
||||
|
||||
.facet-title span {
|
||||
|
32
install/ui/less/brand.less
Normal file
32
install/ui/less/brand.less
Normal file
@ -0,0 +1,32 @@
|
||||
/* Authors:
|
||||
* Petr Vobornik <pvoborni@redhat.com>
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat
|
||||
* see file 'COPYING' for use and warranty information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// This file contains overrides of reference RCUE implementation to comply
|
||||
// with IPA design
|
||||
|
||||
.header.rcue {
|
||||
// Use blue instead of red
|
||||
border-top: 3px solid #1d85d9;
|
||||
.brand {
|
||||
// Lower vertical padding by 5px
|
||||
// FreeIPA uses logo with height: 20px instead of 10px.
|
||||
padding: 2px 0;
|
||||
}
|
||||
}
|
@ -4,3 +4,4 @@
|
||||
@import "rcue/navbar";
|
||||
@import "rcue/buttons";
|
||||
@import "rcue/forms";
|
||||
@import "brand";
|
||||
|
@ -31,10 +31,11 @@ define(['dojo/_base/declare',
|
||||
'dojo/Evented',
|
||||
'dojo/Stateful',
|
||||
'./Menu',
|
||||
'./DropdownWidget',
|
||||
'dojo/NodeList-dom'
|
||||
],
|
||||
function(declare, lang, array, dom, construct, prop, dom_class,
|
||||
dom_style, query, on, Stateful, Evented, Menu) {
|
||||
dom_style, query, on, Stateful, Evented, Menu, DropdownWidget) {
|
||||
|
||||
/**
|
||||
* Main application widget
|
||||
@ -59,14 +60,8 @@ define(['dojo/_base/declare',
|
||||
|
||||
password_expires_node: null,
|
||||
|
||||
logged_nodes: null,
|
||||
|
||||
logged_user_node: null,
|
||||
|
||||
logged_user_link_node: null,
|
||||
|
||||
logout_link_node: null,
|
||||
|
||||
menu_node: null,
|
||||
|
||||
content_node: null,
|
||||
@ -77,9 +72,7 @@ define(['dojo/_base/declare',
|
||||
|
||||
_loggedSetter: function(value) {
|
||||
this.logged = value;
|
||||
if (this.logged_nodes) {
|
||||
this.logged_nodes.style('visibility', value ? 'visible' : 'hidden');
|
||||
}
|
||||
//TODO show/hide menu
|
||||
},
|
||||
|
||||
fullname: '',
|
||||
@ -92,8 +85,6 @@ define(['dojo/_base/declare',
|
||||
},
|
||||
|
||||
render: function() {
|
||||
// TODO: this method may be split into several components
|
||||
|
||||
|
||||
this.domNode = construct.create('div', {
|
||||
id: this.app_id,
|
||||
@ -106,9 +97,6 @@ define(['dojo/_base/declare',
|
||||
|
||||
this._render_header();
|
||||
|
||||
this.menu_node = this.menu_widget.render();
|
||||
construct.place(this.menu_node, this.header_node);
|
||||
|
||||
this.content_node = construct.create('div', {
|
||||
'class': 'content'
|
||||
}, this.domNode);
|
||||
@ -117,57 +105,116 @@ define(['dojo/_base/declare',
|
||||
_render_header: function() {
|
||||
this.header_node = construct.create('div', {
|
||||
'class': 'header rcue'
|
||||
}, this.domNode);
|
||||
});
|
||||
|
||||
// logo
|
||||
construct.place(''+
|
||||
'<span class="header-logo">'+
|
||||
'<a href="#"><img src="images/ipa-logo.png" />'+
|
||||
'<img src="images/ipa-banner.png" /></a>'+
|
||||
'</span>', this.header_node);
|
||||
this._render_nav_util();
|
||||
construct.place(this.nav_util_node, this.header_node);
|
||||
|
||||
// right part
|
||||
construct.place(''+
|
||||
'<span class="header-right">'+
|
||||
'<span class="header-passwordexpires"></span>'+
|
||||
'<span class="loggedinas header-loggedinas" style="visibility:hidden;">'+
|
||||
'<a href="#"><span class="login_header">Logged in as</span>: <span class="login"></span></a>'+
|
||||
'</span>'+
|
||||
'<span class="header-loggedinas" style="visibility:hidden;">'+
|
||||
' | <a href="#logout" class="logout">Logout</a>'+
|
||||
'</span>'+
|
||||
'<span class="header-network-activity-indicator network-activity-indicator">'+
|
||||
'<img src="images/spinner-header.gif" />'+
|
||||
'</span>'+
|
||||
'</span>', this.header_node);
|
||||
|
||||
|
||||
this.password_expires_node = query('.header-passwordexpires', this.header_node)[0];
|
||||
this.logged_nodes = query('.header-loggedinas', this.header_node);
|
||||
this.logged_header_node = query('.login_header')[0];
|
||||
this.logged_user_node = query('.loggedinas .login', this.header_node)[0];
|
||||
this.logged_user_link_node = query('.loggedinas a', this.header_node)[0];
|
||||
this.logout_link_node = query('.logout')[0];
|
||||
|
||||
on(this.logout_link_node, 'click', lang.hitch(this,this.on_logout));
|
||||
on(this.logged_user_link_node, 'click', lang.hitch(this,this.on_profile));
|
||||
this.menu_node = this.menu_widget.render();
|
||||
construct.place(this.menu_node, this.header_node);
|
||||
|
||||
construct.place(this.header_node, this.domNode);
|
||||
},
|
||||
|
||||
on_profile: function(event) {
|
||||
event.preventDefault();
|
||||
this.emit('profile-click');
|
||||
_render_nav_util: function() {
|
||||
this.nav_util_node = construct.create('div', {
|
||||
'class': 'navbar utility'
|
||||
});
|
||||
|
||||
this.nav_util_inner_node = construct.create('div', {
|
||||
'class': 'navbar-inner'
|
||||
}, this.nav_util_node);
|
||||
|
||||
this._render_brand();
|
||||
construct.place(this.brand_node, this.nav_util_inner_node);
|
||||
|
||||
this.nav_util_tool_node = construct.create('ul', {
|
||||
'class': 'nav pull-right'
|
||||
}, this.nav_util_inner_node);
|
||||
|
||||
this.password_expires_node = construct.create('li', {
|
||||
'class': 'header-passwordexpires'
|
||||
}, this.nav_util_tool_node);
|
||||
|
||||
var network_activity = construct.create('li', {
|
||||
'class': 'header-network-activity-indicator network-activity-indicator'
|
||||
}, this.nav_util_tool_node);
|
||||
|
||||
construct.create('img', {
|
||||
'src': 'images/spinner-header.gif'
|
||||
}, network_activity);
|
||||
|
||||
var user_toggle = this._render_user_toggle_nodes();
|
||||
this.user_menu.set('toggle_content', user_toggle);
|
||||
construct.place(this.user_menu.render(), this.nav_util_tool_node);
|
||||
|
||||
return this.nav_util_node;
|
||||
},
|
||||
|
||||
on_logout: function(event) {
|
||||
event.preventDefault();
|
||||
this.emit('logout-click');
|
||||
_render_brand: function() {
|
||||
this.brand_node = construct.create('a', {
|
||||
'class': 'brand',
|
||||
href: '#'
|
||||
});
|
||||
|
||||
construct.create('img', {
|
||||
src: 'images/header-logo.png',
|
||||
alt: 'FreeIPA' // TODO: replace with configuration value
|
||||
}, this.brand_node);
|
||||
|
||||
return this.brand_node;
|
||||
},
|
||||
|
||||
_render_user_toggle_nodes: function() {
|
||||
|
||||
var nodes = [];
|
||||
|
||||
nodes.push(construct.create('span', {
|
||||
'class': 'icon-user icon-white'
|
||||
}));
|
||||
|
||||
this.logged_user_node = construct.create('span', {
|
||||
'class': 'loggedinas'
|
||||
});
|
||||
nodes.push(this.logged_user_node);
|
||||
|
||||
nodes.push(construct.create('b', {
|
||||
'class': 'caret'
|
||||
}));
|
||||
|
||||
return nodes;
|
||||
},
|
||||
|
||||
on_user_menu_click: function(item) {
|
||||
|
||||
if (item.name === 'profile') {
|
||||
this.emit('profile-click');
|
||||
} else if (item.name === 'logout') {
|
||||
this.emit('logout-click');
|
||||
}
|
||||
},
|
||||
|
||||
constructor: function(spec) {
|
||||
spec = spec || {};
|
||||
this.menu_widget = new Menu();
|
||||
this.user_menu = new DropdownWidget({
|
||||
el_type: 'li',
|
||||
name: 'profile-menu',
|
||||
items: [
|
||||
{
|
||||
name: 'profile',
|
||||
label: 'Profile'
|
||||
},
|
||||
{
|
||||
'class': 'divider'
|
||||
},
|
||||
{
|
||||
name: 'logout',
|
||||
label: 'Logout'
|
||||
}
|
||||
]
|
||||
});
|
||||
on(this.user_menu, 'item-click', lang.hitch(this, this.on_user_menu_click));
|
||||
}
|
||||
|
||||
});
|
||||
|
211
install/ui/src/freeipa/widgets/DropdownWidget.js
Normal file
211
install/ui/src/freeipa/widgets/DropdownWidget.js
Normal file
@ -0,0 +1,211 @@
|
||||
/* Authors:
|
||||
* Petr Vobornik <pvoborni@redhat.com>
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat
|
||||
* see file 'COPYING' for use and warranty information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
define(['dojo/_base/declare',
|
||||
'dojo/_base/array',
|
||||
'dojo/_base/lang',
|
||||
'dojo/dom',
|
||||
'dojo/dom-construct',
|
||||
'dojo/dom-prop',
|
||||
'dojo/dom-class',
|
||||
'dojo/dom-style',
|
||||
'dojo/dom-attr',
|
||||
'dojo/query',
|
||||
'dojo/Evented',
|
||||
'dojo/Stateful',
|
||||
'dojo/on',
|
||||
'../jquery',
|
||||
'../ipa'], function(declare, array, lang, dom, construct, prop, dom_class,
|
||||
dom_style, attr, query, Evented, Stateful, on, $, IPA) {
|
||||
|
||||
return declare([Stateful, Evented], {
|
||||
/**
|
||||
* Represents and creates a dropdown widget. It can contain multiple
|
||||
* levels.
|
||||
*
|
||||
* @class widgets.DropdownWidget
|
||||
*/
|
||||
|
||||
/**
|
||||
* Raised when menu item is clicked
|
||||
* @event item-click
|
||||
*/
|
||||
|
||||
/**
|
||||
* Dropdown name
|
||||
* @property {string}
|
||||
*/
|
||||
name: '',
|
||||
|
||||
/**
|
||||
* Element type
|
||||
* @property {string}
|
||||
*/
|
||||
el_type: 'div',
|
||||
|
||||
/**
|
||||
* Element class
|
||||
* @property {string}
|
||||
*/
|
||||
'class': 'dropdown',
|
||||
|
||||
/**
|
||||
* Submenu class
|
||||
*/
|
||||
submenu_class: 'dropdown-submenu',
|
||||
|
||||
/**
|
||||
* Toggle button text
|
||||
* @property {string}
|
||||
*/
|
||||
toggle_text: '',
|
||||
|
||||
/**
|
||||
* Toggle button content. Replaces toggle button text if set. Can be
|
||||
* use for more complex toggle buttons.
|
||||
* @property {HTMLElement|HTMLElement[]}
|
||||
*/
|
||||
toggle_content: null,
|
||||
|
||||
/**
|
||||
* Array of dropdown items to display. Item can have `items` field
|
||||
* with an array of child items.
|
||||
* @property {Array}
|
||||
*/
|
||||
items: [],
|
||||
|
||||
/**
|
||||
* domNode of this widget
|
||||
* @property {HTMLElement}
|
||||
*/
|
||||
dom_node: null,
|
||||
|
||||
render: function() {
|
||||
if (this.dom_node) {
|
||||
construct.empty(this.dom_node);
|
||||
|
||||
} else {
|
||||
this.dom_node = construct.create(this.el_type, {
|
||||
name: this.name || '',
|
||||
'class': this['class']
|
||||
});
|
||||
}
|
||||
|
||||
this._render_toggle(this.dom_node);
|
||||
this._render_items(this.items, this.dom_node);
|
||||
|
||||
return this.dom_node;
|
||||
},
|
||||
|
||||
_render_toggle: function(container) {
|
||||
|
||||
this.toggle_node = construct.create('a', {
|
||||
'class': 'dropdown-toggle',
|
||||
'data-toggle': 'dropdown',
|
||||
href: '#'
|
||||
});
|
||||
|
||||
this._update_toggle();
|
||||
if (container) {
|
||||
construct.place(this.toggle_node, container);
|
||||
}
|
||||
return this.toggle_node;
|
||||
},
|
||||
|
||||
_update_toggle: function() {
|
||||
if (!this.toggle_node) return;
|
||||
if (this.toggle_content) {
|
||||
if (lang.isArray(this.toggle_content)) {
|
||||
array.forEach(this.toggle_content, function(item) {
|
||||
construct.place(item, this.toggle_node);
|
||||
}, this);
|
||||
} else {
|
||||
construct.place(this.toggle_content, this.toggle_node);
|
||||
}
|
||||
} else {
|
||||
prop.set(this.toggle_node, 'textContent', this.toggle_text);
|
||||
}
|
||||
},
|
||||
|
||||
_toggle_textSetter: function(value) {
|
||||
this.toggle_text = value;
|
||||
this._update_toggle();
|
||||
},
|
||||
|
||||
_toggle_contentSetter: function(value) {
|
||||
this.toggle_content = value;
|
||||
this._update_toggle();
|
||||
},
|
||||
|
||||
_render_items: function(items, container) {
|
||||
var ul = construct.create('ul', {
|
||||
'class': 'dropdown-menu'
|
||||
});
|
||||
|
||||
array.forEach(items, function(item) {
|
||||
this._render_item(item, ul);
|
||||
}, this);
|
||||
|
||||
if (container) {
|
||||
construct.place(ul, container);
|
||||
}
|
||||
return ul;
|
||||
},
|
||||
|
||||
_render_item: function(item, container) {
|
||||
|
||||
var li = construct.create('li', {
|
||||
'data-name': item.name || ''
|
||||
});
|
||||
var a = construct.create('a', {
|
||||
'href': '#' + item.name || '',
|
||||
innerHTML: item.label || ''
|
||||
}, li);
|
||||
|
||||
if (item['class']) {
|
||||
dom_class.add(li, item['class']);
|
||||
}
|
||||
|
||||
if (item.items && item.items.length > 0) {
|
||||
dom_class.add(li, 'dropdown-submenu');
|
||||
this._render_items(item.items, li);
|
||||
} else {
|
||||
on(a, 'click', lang.hitch(this, function(event) {
|
||||
this.on_item_click(event, item);
|
||||
event.preventDefault();
|
||||
}));
|
||||
}
|
||||
|
||||
if (container) {
|
||||
construct.place(li, container);
|
||||
}
|
||||
return li;
|
||||
},
|
||||
|
||||
on_item_click: function(event, item) {
|
||||
|
||||
if (item.click) item.click();
|
||||
this.emit('item-click', item);
|
||||
},
|
||||
|
||||
constructor: function(spec) {
|
||||
declare.safeMixin(this, spec);
|
||||
}
|
||||
});
|
||||
});
|
@ -234,7 +234,7 @@ class UI_driver(object):
|
||||
"""
|
||||
Test if dependencies were loaded. (Checks if UI has been rendered)
|
||||
"""
|
||||
indicator = self.find("span.network-activity-indicator", By.CSS_SELECTOR)
|
||||
indicator = self.find(".network-activity-indicator", By.CSS_SELECTOR)
|
||||
return indicator is not None
|
||||
|
||||
def has_ca(self):
|
||||
@ -259,7 +259,7 @@ class UI_driver(object):
|
||||
"""
|
||||
Check if there is running AJAX request
|
||||
"""
|
||||
indicator = self.find("span.network-activity-indicator", By.CSS_SELECTOR)
|
||||
indicator = self.find(".network-activity-indicator", By.CSS_SELECTOR)
|
||||
displayed = indicator and indicator.is_displayed()
|
||||
return displayed
|
||||
|
||||
@ -343,14 +343,13 @@ class UI_driver(object):
|
||||
"""
|
||||
Check if user is logged in
|
||||
"""
|
||||
login_as = self.find('header-loggedinas', 'class name')
|
||||
visible_name = login_as and login_as.is_displayed()
|
||||
login_as = self.find('loggedinas', 'class name')
|
||||
visible_name = len(login_as.text) > 0
|
||||
logged_in = not self.auth_dialog_opened() and visible_name
|
||||
return logged_in
|
||||
|
||||
def logout(self):
|
||||
btn = self.find('logout', 'class name')
|
||||
btn.click()
|
||||
self.profile_menu_action('logout')
|
||||
|
||||
def get_auth_dialog(self):
|
||||
"""
|
||||
@ -380,7 +379,7 @@ class UI_driver(object):
|
||||
parent = parts[0:-1]
|
||||
self.navigate_by_menu('/'.join(parent), complete)
|
||||
|
||||
s = ".navigation a[href='#%s']" % item
|
||||
s = ".navbar a[href='#%s']" % item
|
||||
link = self.find(s, By.CSS_SELECTOR, strict=True)
|
||||
assert link.is_displayed(), 'Navigation link is not displayed'
|
||||
link.click()
|
||||
@ -595,6 +594,16 @@ class UI_driver(object):
|
||||
btn.click()
|
||||
self.wait_for_request()
|
||||
|
||||
def profile_menu_action (self, name):
|
||||
"""
|
||||
Execute action from profile menu
|
||||
"""
|
||||
menu_toggle = self.find('[name=profile-menu] > a', By.CSS_SELECTOR)
|
||||
menu_toggle.click()
|
||||
s = "[name=profile-menu] a[href='#%s']" % name
|
||||
btn = self.find(s, By.CSS_SELECTOR, strict=True)
|
||||
btn.click()
|
||||
|
||||
def get_form(self):
|
||||
"""
|
||||
Get last dialog or visible facet
|
||||
|
Loading…
Reference in New Issue
Block a user