summaryrefslogtreecommitdiffstats
path: root/install
diff options
context:
space:
mode:
authorPetr Vobornik <pvoborni@redhat.com>2012-04-04 16:33:48 +0200
committerPetr Vobornik <pvoborni@redhat.com>2012-05-11 18:30:48 +0200
commit8c3eadf978dc14c4e22da5c32e51d407b9770a28 (patch)
treeb31e2bbba7503d0cf96e23643abc610619f7ea0b /install
parent12401fe4da9620ce7dae3339f9928f9d2a770fbd (diff)
downloadfreeipa-8c3eadf978dc14c4e22da5c32e51d407b9770a28.tar.gz
freeipa-8c3eadf978dc14c4e22da5c32e51d407b9770a28.tar.xz
freeipa-8c3eadf978dc14c4e22da5c32e51d407b9770a28.zip
Action lists
This patch add support fo Action Lists. Action list is a select widget with actions as options located in facet header. Action can be selected and then executed by clickin on 'apply' button. Actions lists are defined on facet level. Facet header takes them from facet. Action list options actions: list of actions state_evaluator: a state evaluator which is needed for enabling/disabling options. Can encapsulate more evaluators. State evaluator object ---------------------- State evaluator is resposible for evaluating a state from result set. State is a array of strings. Each evaluator should inherit from IPA.state_evaluator and override evaluate method. Methods: evaluate(record): should return string array which represents the state get_description(): human readable representation of a state Action ------ Action is a object which can perform certain action on a facet. Action has enabling and disabling conditions. action options: name: string, required, name of the option label: string, required, human readable name of the option enable_cond: string array, states which need to be present in order to run this action disable_cond: string array, states which must not be present in order to run this action handler: function, contains action's logic needs_confirm: boolean, default false, indicates if action needs user confirmation confirm_msg: string, default generic message, human readable confirmation message. Action list should contain logic which enables/disables action based on facet state and action's enabling/disabling conditions. It should also enforce presence of confirmation. In this patch is also slightly modified facet header, mostly title part. It was revised to contain status icon, title and action list on single line. Facet header is using state evaluator's get_description method to properly set tooltip for state icon. https://fedorahosted.org/freeipa/ticket/2247
Diffstat (limited to 'install')
-rw-r--r--install/ui/facet.js370
-rw-r--r--install/ui/ipa.css55
-rw-r--r--install/ui/ipa.js4
-rw-r--r--install/ui/test/data/ipa_init.json6
-rw-r--r--install/ui/widget.js104
5 files changed, 521 insertions, 18 deletions
diff --git a/install/ui/facet.js b/install/ui/facet.js
index 01e8a935f..5e78d57f6 100644
--- a/install/ui/facet.js
+++ b/install/ui/facet.js
@@ -42,6 +42,7 @@ IPA.facet = function(spec) {
that.disable_breadcrumb = spec.disable_breadcrumb;
that.disable_facet_tabs = spec.disable_facet_tabs;
+ that.action_list = spec.action_list;
that.header = spec.header || IPA.facet_header({ facet: that });
that._needs_update = spec.needs_update;
@@ -309,6 +310,23 @@ IPA.facet_header = function(spec) {
that.facet = spec.facet;
+ var init = function() {
+
+ if (that.facet.action_list) {
+
+ var widget_builder = IPA.widget_builder({
+ widget_options: {
+ entity: that.facet.entity
+ }
+ });
+
+ that.action_list = widget_builder.build_widget(that.facet.action_list);
+ that.action_list.init();
+ }
+
+ that.title_widget = IPA.facet_title();
+ };
+
that.select_tab = function() {
if (that.facet.disable_facet_tabs) return;
@@ -372,16 +390,14 @@ IPA.facet_header = function(spec) {
}).appendTo(that.path);
}
- that.title_container.empty();
- var h3 = $('<h3/>').appendTo(that.title_container);
- h3.append(that.facet.label);
- h3.append(': ');
+ var title_info = {
+ title: that.facet.label,
+ pkey: limited_value,
+ pkey_tooltip: value
+ };
+ that.title_widget.update(title_info);
- $('<span/>', {
- 'class': 'facet-pkey',
- title: value,
- text: limited_value
- }).appendTo(h3);
+ that.adjust_elements();
};
that.create_facet_link = function(container, other_facet) {
@@ -431,6 +447,8 @@ IPA.facet_header = function(spec) {
that.create = function(container) {
+ that.container = container;
+
if (!that.facet.disable_breadcrumb) {
that.breadcrumb = $('<div/>', {
'class': 'breadcrumb'
@@ -456,13 +474,16 @@ IPA.facet_header = function(spec) {
}).appendTo(that.breadcrumb);
}
- that.title_container = $('<div/>', {
- 'class': 'facet-title'
- }).appendTo(container);
+ that.title_widget.create(container);
+ that.title_widget.update({ title: that.facet.label });
- var span = $('<h3/>', {
- text: that.facet.label
- }).appendTo(that.title_container);
+ if (that.action_list) {
+ that.action_list_container = $('<div/>', {
+ 'class': 'facet-action-list'
+ }).appendTo(container);
+
+ that.action_list.create(that.action_list_container);
+ }
if (!that.facet.disable_facet_tabs) {
that.facet_tabs = $('<div/>', {
@@ -518,12 +539,112 @@ IPA.facet_header = function(spec) {
}
}
}
+
+ if (that.action_list) {
+ that.action_list.update(result);
+
+ var state = that.action_list.state;
+ var icon_tooltip = that.action_list.state_evaluator.get_description();
+ if (state.length > 0) {
+ var css_class = state.join(' ');
+ that.title_widget.set_class(css_class);
+ that.title_widget.set_icon_tooltip(icon_tooltip);
+ }
+ }
+
+ that.adjust_elements();
+ };
+
+ that.adjust_elements = function() {
+
+ if (that.action_list) {
+
+ var action_list = that.action_list.container;
+ var max_width = that.container.width();
+ var al_width = action_list.width();
+ var title_width = that.title_widget.title_container.width();
+ var title_max = max_width - al_width;
+
+ that.title_widget.set_max_width(title_max);
+ action_list.css('left', title_width + 'px');
+ }
};
that.clear = function() {
that.load();
};
+ init();
+
+ return that;
+};
+
+IPA.facet_title = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.update = function(data) {
+
+ var tooltip = data.tooltip || data.title;
+ var pkey_tooltip = data.pkey_tooltip || data.pkey;
+ var icon_tooltip = data.icon_tooltip || '';
+
+ that.title.text(data.title);
+ that.title.attr('title', tooltip);
+
+ if (data.pkey) {
+ that.title.text(data.title + ': ');
+ that.pkey.text(data.pkey);
+ that.pkey.attr('title', pkey_tooltip);
+ }
+
+ if (data.css_class) that.set_class(data.css_class);
+
+ that.set_icon_tooltip(icon_tooltip);
+ };
+
+ that.create = function(container) {
+
+ that.title_container = $('<div/>', {
+ 'class': 'facet-title'
+ }).appendTo(container);
+
+ that.icon = $('<div />', {
+ 'class': 'header-icon'
+ }).appendTo(that.title_container);
+
+ var h3 = $('<h3/>').appendTo(that.title_container);
+
+ that.title = $('<span/>').appendTo(h3);
+
+ that.pkey = $('<span/>', {
+ 'class': 'facet-pkey'
+ }).appendTo(h3);
+ };
+
+ that.set_max_width = function(width) {
+ that.title_container.css('max-width', width+'px');
+ };
+
+ that.set_class = function(css_class) {
+
+ if (that.css_class) {
+ that.title_container.removeClass(that.css_class);
+ }
+
+ if (css_class) {
+ that.title_container.addClass(css_class);
+ }
+
+ that.css_class = css_class;
+ };
+
+ that.set_icon_tooltip = function(tooltip) {
+ that.icon.attr('title', tooltip);
+ };
+
return that;
};
@@ -1025,7 +1146,7 @@ IPA.facet_builder = function(entity) {
(IPA.metadata.objects[spec.other_entity] ?
IPA.metadata.objects[spec.other_entity].label : spec.other_entity);
- if(that.has_indirect_attribute_member(spec)) {
+ if (that.has_indirect_attribute_member(spec)) {
spec.indirect_attribute_member = spec.attribute_member + 'indirect';
}
@@ -1042,8 +1163,8 @@ IPA.facet_builder = function(entity) {
that.has_indirect_attribute_member = function(spec) {
var indirect_members = entity.metadata.attribute_members[spec.attribute_member + 'indirect'];
- if(indirect_members) {
- if(indirect_members.indexOf(spec.other_entity) > -1) {
+ if (indirect_members) {
+ if (indirect_members.indexOf(spec.other_entity) > -1) {
return true;
}
}
@@ -1054,3 +1175,216 @@ IPA.facet_builder = function(entity) {
return that;
};
+
+IPA.action = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.name = spec.name;
+ that.label = spec.label;
+ that.enable_cond = spec.enable_cond || [];
+ that.disable_cond = spec.disable_cond || [];
+ that.handler = spec.handler;
+ that.needs_confirm = spec.needs_confirm !== undefined ? spec.needs_confirm : true;
+ that.confirm_msg = spec.confirm_msg || IPA.messages.actions.confirm;
+
+ that.execute = function(facet, on_success, on_error) {
+
+ if (that.handler) {
+ that.handler(facet, on_success, on_error);
+ }
+ };
+
+ return that;
+};
+
+IPA.action_builder = function(spec) {
+
+ spec = spec || {};
+ spec.factory = spec.factory || IPA.action;
+ var that = IPA.builder(spec);
+ return that;
+};
+
+IPA.state_evaluator = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.evaluate = function() {
+ that.state = [];
+ return that.state;
+ };
+
+ that.get_description = function() {
+ return that.description || '';
+ };
+
+ return that;
+};
+
+
+IPA.action_list_widget = function(spec) {
+
+ spec = spec || {};
+
+ spec.widgets = spec.widgets || [
+ {
+ type: 'html',
+ css_class: 'separator'
+ },
+ {
+ type: 'select',
+ name: 'action',
+ undo: false
+ },
+ {
+ type: 'button',
+ name: 'apply',
+ label: "Apply" //TODO: translate
+ }
+ ];
+
+ var that = IPA.composite_widget(spec);
+
+ that.actions = IPA.build(spec.actions, IPA.action_builder) || [];
+ that.state_evaluator = IPA.build(spec.state_evaluator);
+ that.state = [];
+
+ that.init = function() {
+ that.action_select = that.widgets.get_widget('action');
+ that.apply_button = that.widgets.get_widget('apply');
+
+ that.action_select.value_changed.attach(that.on_action_change);
+ that.apply_button.click = that.on_apply;
+
+ var options = [];
+
+ for (var i=0; i< that.actions.length; i++) {
+ var action = that.actions[i];
+ options.push({
+ label: action.label,
+ value: action.name
+ });
+ }
+
+ that.action_select.options = options;
+ };
+
+ that.on_action_change = function() {
+
+ var selected = that.action_select.save()[0];
+ var action = that.get_action(selected);
+ var enabled = that.action_enabled(action);
+ that.apply_button.set_enabled(enabled);
+ };
+
+ that.on_apply = function() {
+ var selected = that.action_select.save()[0];
+ var action = that.get_action(selected);
+ var enabled = that.action_enabled(action);
+ var facet = that.entity.get_facet();
+
+ if (enabled) {
+ action.execute(facet,
+ that.on_action_success,
+ that.on_action_error);
+ }
+ };
+
+ that.on_action_success = function() {
+ var facet = that.entity.get_facet();
+ facet.refresh();
+ };
+
+ that.on_action_error = function() {
+ var facet = that.entity.get_facet();
+ facet.refresh();
+ };
+
+ that.update = function(result) {
+
+ that.get_state(result);
+ var disabled = that.get_disabled();
+ that.action_select.enable_options();
+ that.action_select.disable_options(disabled);
+ that.select_first_enabled();
+ };
+
+ that.get_state = function(result) {
+
+ if (that.state_evaluator) {
+ that.state = that.state_evaluator.evaluate(result);
+ }
+ };
+
+ that.get_action = function(name) {
+
+ for (var i=0; i< that.actions.length; i++) {
+ var action = that.actions[i];
+ if (action.name === name) {
+ return action;
+ }
+ }
+ return null;
+ };
+
+ that.get_disabled = function() {
+
+ var disabled = [];
+
+ for (var i=0; i< that.actions.length; i++) {
+ var action = that.actions[i];
+ if (!that.action_enabled(action)) {
+ disabled.push(action.name);
+ }
+ }
+
+ return disabled;
+ };
+
+ that.action_enabled = function(action) {
+
+ var i, cond;
+
+ if (action.disable_cond) {
+ for (i=0; i<action.disable_cond.length; i++) {
+ cond = action.disable_cond[i];
+ if (that.state.indexOf(cond) > -1) {
+ return false;
+ }
+ }
+ }
+
+ if (action.enable_cond) {
+ for (i=0; i<action.enable_cond.length; i++) {
+ cond = action.enable_cond[i];
+ if (that.state.indexOf(cond) < 0) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ };
+
+ that.select_first_enabled = function() {
+
+ var first = that.actions[0].name;
+
+ for (var i=0; i< that.actions.length; i++) {
+ var action = that.actions[i];
+ if (that.action_enabled(action)) {
+ first = action.name;
+ break;
+ }
+ }
+
+ that.action_select.update([first]);
+ };
+
+ return that;
+}; \ No newline at end of file
diff --git a/install/ui/ipa.css b/install/ui/ipa.css
index 7e7956603..d83c7e148 100644
--- a/install/ui/ipa.css
+++ b/install/ui/ipa.css
@@ -1052,6 +1052,11 @@ span.main-separator{
cursor: default;
}
+.button-disabled {
+ color: gray;
+ cursor: default;
+}
+
.aci-attribute-table tbody {
border-bottom: 1px solid #8a8a8a;
height:10em;
@@ -1637,3 +1642,53 @@ form#login {
.auth-dialog h3 {
margin: 0.5em;
}
+
+/* --- Action list --- */
+
+.facet-action-list {
+ position: absolute;
+ left: 200px;
+ top: 15px;
+ height: 24px;
+ vertical-align: top;
+}
+
+.facet-action-list div {
+ display: inline-block;
+ vertical-align: top;
+}
+
+.facet-action-list div[name=apply] {
+ margin-left: 10px;
+}
+
+ #content .facet-action-list div[name=apply] a.ui-state-default {
+ padding: 3px 5px 1px 5px;
+}
+
+.facet-action-list select {
+ font-size: 11px;
+ padding-left: 4px;
+ padding-right: 4px;
+ height: 24px;
+}
+
+.facet-action-list .separator {
+ width: 1px;
+ height: 24px;
+ margin-left: 10px;
+ margin-right: 15px;
+ background-color: #a1a1a1;
+}
+
+/* --- Facet title states --- */
+
+.facet-title h3 {
+ display: inline-block;
+}
+
+.facet-title .header-icon {
+ display: none;
+ width: 17px;
+ height: 17px;
+}
diff --git a/install/ui/ipa.js b/install/ui/ipa.js
index 4470d9484..648fcfc31 100644
--- a/install/ui/ipa.js
+++ b/install/ui/ipa.js
@@ -1657,6 +1657,10 @@ IPA.array_diff = function(a, b) {
return false;
};
+IPA.confirm = function(msg) {
+ return window.confirm(msg);
+};
+
IPA.config = {
default_priority: 500
};
diff --git a/install/ui/test/data/ipa_init.json b/install/ui/test/data/ipa_init.json
index 7d394f8a3..333cb19a3 100644
--- a/install/ui/test/data/ipa_init.json
+++ b/install/ui/test/data/ipa_init.json
@@ -13,6 +13,12 @@
"title": "Kerberos ticket no longer valid."
}
},
+ "actions": {
+ "confirm": "Are you sure you want to proceed with the action.",
+ "delete_confirm": "Are you sure you want to delete ${object}",
+ "disable_confirm": "Are you sure you want to disable ${object}",
+ "enable_confirm": "Are you sure you want to enable ${object}"
+ },
"association": {
"add": {
"ipasudorunas": "Add RunAs ${other_entity} into ${entity} ${primary_key}",
diff --git a/install/ui/widget.js b/install/ui/widget.js
index ff7759747..d3efe499b 100644
--- a/install/ui/widget.js
+++ b/install/ui/widget.js
@@ -891,6 +891,19 @@ IPA.select_widget = function(spec) {
$('option', that.select).attr('selected', '');
};
+ that.enable_options = function() {
+ $('option', that.select).attr('disabled', '');
+ };
+
+ that.disable_options = function(options) {
+
+ for (var i=0; i<options.length;i++) {
+ var value = options[i];
+ var option = $('option[value="'+value+'"]', that.select);
+ option.attr('disabled', 'disabled');
+ }
+ };
+
// methods that should be invoked by subclasses
that.select_save = that.save;
that.select_update = that.update;
@@ -2432,6 +2445,95 @@ IPA.button = function(spec) {
return button;
};
+IPA.button_widget = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.widget(spec);
+
+ that.href = spec.href;
+ that.style = spec.style;
+ that.click = spec.click;
+ that['class'] = spec['class'];
+ that.disabled_class = 'button-disabled';
+
+ that.on_click = function() {
+
+ if (that.click) {
+ that.click();
+ }
+ return false;
+ };
+
+ that.create = function(container) {
+ that.button = IPA.button({
+ id: that.id,
+ name: that.name,
+ href: that.href,
+ title: that.tooltip,
+ label: that.label,
+ 'class': that['class'],
+ style: that.style,
+ click: that.on_click
+ }).appendTo(container);
+ };
+
+ that.get_enabled = function() {
+
+ var enabled = true;
+
+ if (that.button) {
+ enabled = that.button.hasClass(that.disabled_class);
+ }
+
+ return enabled;
+ };
+
+ that.set_enabled = function(enabled) {
+
+ enabled ? that.enable() : that.disable();
+ };
+
+ that.enable = function() {
+ if (that.button) {
+ that.button.removeClass(that.disabled_class);
+ }
+ };
+
+ that.disable = function() {
+ if (that.button) {
+ that.button.addClass(that.disabled_class);
+ }
+ };
+
+ return that;
+};
+
+IPA.html_widget = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.widget(spec);
+
+ that.html = spec.html;
+ that.css_class = spec.css_class;
+
+ that.create = function(container) {
+
+ that.widget_create(container);
+
+ if (that.css_class) {
+ container.addClass(that.css_class);
+ }
+
+ if (that.html) {
+ container.append(that.html);
+ }
+ };
+
+ return that;
+};
+
IPA.composite_widget = function(spec) {
spec = spec || {};
@@ -3016,6 +3118,7 @@ IPA.sshkey_widget = function(spec) {
IPA.widget_factories['attribute_table'] = IPA.attribute_table_widget;
+IPA.widget_factories['button'] = IPA.button_widget;
IPA.widget_factories['checkbox'] = IPA.checkbox_widget;
IPA.widget_factories['checkboxes'] = IPA.checkboxes_widget;
IPA.widget_factories['combobox'] = IPA.combobox_widget;
@@ -3025,6 +3128,7 @@ IPA.widget_factories['details_table_section_nc'] = IPA.details_table_section_nc;
IPA.widget_factories['enable'] = IPA.enable_widget;
IPA.widget_factories['entity_select'] = IPA.entity_select_widget;
IPA.widget_factories['header'] = IPA.header_widget;
+IPA.widget_factories['html'] = IPA.html_widget;
IPA.widget_factories['link'] = IPA.link_widget;
IPA.widget_factories['multivalued'] = IPA.multivalued_widget;
IPA.widget_factories['password'] = IPA.password_widget;