diff --git a/install/static/Makefile.am b/install/static/Makefile.am new file mode 100644 index 000000000..762587179 --- /dev/null +++ b/install/static/Makefile.am @@ -0,0 +1,43 @@ +NULL = + +appdir = $(IPA_DATA_DIR)/static +app_DATA = \ + but-reset.png \ + but-update.png \ + but-selected.png \ + but-unselected.png \ + ipa_logo_180x50.png \ + ipa.js \ + ipa.css \ + jquery.js \ + group.js \ + group-details.inc \ + host.js \ + hostgroup.js \ + index.xhtml \ + jquery.cookie.js \ + navigation.js \ + netgroup.js \ + pageparams.js \ + search.js \ + details.js \ + user.js \ + user-add.inc \ + user-details.inc \ + ipalogo.png \ + gray-fade-line.png \ + Mainnav-background.png \ + Mainnav-offtab.png \ + Mainnav-ontab.png \ + Subnav-background.png \ + Subnav-offbutton.png \ + Subnav-onbutton.png \ + $(NULL) + +EXTRA_DIST = \ + $(app_DATA) \ + $(NULL) + +MAINTAINERCLEANFILES = \ + *~ \ + Makefile.in diff --git a/install/static/details.js b/install/static/details.js new file mode 100644 index 000000000..7d0e7846f --- /dev/null +++ b/install/static/details.js @@ -0,0 +1,559 @@ +/* Authors: + * Pavel Zuna + * + * Copyright (C) 2010 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; version 2 only + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* IPA Object Details - populating definiton lists from entry data */ + +/* REQUIRES: ipa.js */ + +var IPA_DETAILS_POPULATE = 1; +var IPA_DETAILS_UPDATE = 2; + +/* name of IPA object, that we're populating the lists for */ +var _ipa_obj_name = ''; + +/* initialize the IPA Object Details library */ +function ipa_details_init(obj_name, url) +{ + ipa_init(url); + _ipa_obj_name = obj_name; +} + +var _ipa_load_on_win_callback = null; +var _ipa_load_on_fail_callback = null; + +var ipa_details_cache = null; + +function ipa_details_load(pkey, on_win, on_fail) +{ + if (!pkey) + return; + + _ipa_load_on_win_callback = on_win; + _ipa_load_on_fail_callback = on_fail; + + ipa_cmd( + 'show', [pkey], {all: true}, _ipa_load_on_win, _ipa_load_on_fail, + _ipa_obj_name + ); +} + +function _ipa_load_on_win(data, text_status, xhr) +{ + if (_ipa_load_on_win_callback) + _ipa_load_on_win_callback(data, text_status, xhr); + + if (data['error']) + return; + + var result = data.result.result; + + ipa_details_cache = $.extend(true, {}, result); + ipa_details_display(result); +} + +function _ipa_load_on_fail(xhr, text_status, error_thrown) +{ + if (_ipa_load_on_fail_callback) + _ipa_load_on_fail_callback(xhr, text_status, error_thrown); +} + +var _ipa_update_on_win_callback = null; +var _ipa_update_on_fail_callback = null; + +function ipa_details_update(pkey, on_win, on_fail) +{ + if (!pkey) + return; + + var modlist = {'all': true, 'setattr': [], 'addattr': []}; + var attrs_wo_option = {}; + + $('.entryattrs input').each(function () { + var jobj = $(this); + + var dt = jobj.parent().prevAll('dt').slice(0, 1); + if (!dt) + return; + + var attr = dt.attr('title'); + if (!attr) + return; + + if (attr.indexOf('call_') == 0) { + var func = window[attr.substr(5)]; + if (!func) + return; + func(dt, modlist, IPA_DETAILS_UPDATE); + return; + } + + var param_info = ipa_get_param_info(attr); + if (param_info) { + modlist[attr] = jobj.val(); + return; + } + + if (!attrs_wo_option[attr]) + attrs_wo_option[attr] = []; + attrs_wo_option[attr].push(jobj.val()); + }); + + $('.entryattrs dt').each(function () { + var jobj = $(this); + + var attr = jobj.attr('title'); + if (!attr || attr.indexOf('call_') == 0) + return; + + var next = jobj.next('dd'); + if ((!next.length) || (!next.children('input').length)) + attrs_wo_option[attr] = ['']; + }); + + for (attr in attrs_wo_option) { + var values = attrs_wo_option[attr]; + modlist['setattr'].push(attr + '=' + values[0]); + for (var i = 1; i < values.length; ++i) + modlist['addattr'].push(attr + '=' + values[i]); + } + + _ipa_update_on_win_callback = on_win; + _ipa_update_on_fail_callback = on_fail; + + ipa_cmd( + 'mod', [pkey], modlist, _ipa_update_on_win, _ipa_update_on_fail, + _ipa_obj_name + ); +} + +function _ipa_update_on_win(data, text_status, xhr) +{ + if (_ipa_update_on_win_callback) + _ipa_update_on_win_callback(data, text_status, xhr); + + if (data['error']) + return; + + var result = data.result.result; + ipa_details_cache = $.extend(true, {}, result); + ipa_details_display(result); +} + +function _ipa_update_on_fail(xhr, text_status, error_thrown) +{ + if (_ipa_update_on_fail_callback) + _ipa_update_on_fail_callback(xhr, text_status, error_thrown); +} + +function ipa_details_create(dls) +{ + for (var i = 0; i < def_lists.length; ++i) { + var d = dls[i]; + ipa_generate_dl($('hr').last(), d[0], d[1], d[2]); + } +} + +var _ipa_h2_template = '

− I

'; +var _ipa_dl_template = '
'; +var _ipa_dt_template = '
N:
'; + +function ipa_generate_dl(jobj, id, name, dts) +{ + if (!dts) + return; + + jobj.after(_ipa_h2_template.replace('I', name)); + jobj = jobj.next(); + jobj.after(_ipa_dl_template.replace('I', id)); + jobj = jobj.next(); + jobj.after('
'); + + for (var i = 0; i < dts.length; ++i) { + var label = ''; + if (dts[i][0].indexOf('call_') != 0) { + var param_info = ipa_get_param_info(dts[i][0]); + if (param_info) + label = param_info['label']; + } + if ((!label) && (dts[i].length > 1)) + label = dts[i][1]; + jobj.append( + _ipa_dt_template.replace('T', dts[i][0]).replace('N', label) + ); + } +} + +/* HTML templates for ipa_details_display() */ +var _ipa_a_add_template = + 'Add'; + +/* populate definition lists with the class 'entryattrs' with entry attributes + * + * The list has to be specially crafted for this function to work properly: + *
tags should have the 'title' attribute set to an LDAP attribute name + * OR to a javascript function name prefixed with 'call_', which will be given + * the
object and entry_attrs as arguments. + * Example: + *
+ *
First Name:
+ *
Some Attribute:
+ *
+ * + * arguments: + * entry_attrs - 'result' field as returned by ipa *-show commnads + * (basically an associative array with attr:value pairs) */ +function ipa_details_display(entry_attrs) +{ + /* remove all
tags i.e. all attribute values */ + $('.entryattrs dd').remove(); + + /* go through all
tags and pair them with newly created
s */ + $('.entryattrs dt').each(function () { + var jobj = $(this); + + var attr = jobj.attr('title'); + if (attr.indexOf('call_') == 0) { + /* title contains callback instead of attribute name */ + var func = window[attr.substr(5)]; + if (func) + func(jobj, entry_attrs, IPA_DETAILS_POPULATE); + else + jobj.after(_ipa_dd_first_template.replace('I', '-')); + } else { + /* title contains attribute name - default behaviour */ + var value = entry_attrs[attr]; + if (value) { + ipa_insert_first_dd(jobj, ipa_create_input(attr, value[0])); + for (var i = 1; i < value.length; ++i) { + jobj = jobj.next(); + ipa_insert_other_dd(jobj, ipa_create_input(attr, value[i])); + } + } else { + ipa_insert_first_dd(jobj, _ipa_a_add_template.replace('A', attr)); + } + } + }); +} + +var _ipa_dd_first_template = '
I
'; + +function ipa_insert_first_dd(jobj, content) +{ + jobj.after(_ipa_dd_first_template.replace('I', content)); +} + +var _ipa_dd_other_template = '
I
'; + +function ipa_insert_other_dd(jobj, content) +{ + jobj.after(_ipa_dd_other_template.replace('I', content)); +} + + +/* mapping of parameter types to handlers used to create inputs */ +var _ipa_param_type_2_handler_map = { + 'Str': _ipa_create_text_input, + 'Int': _ipa_create_text_input, + 'Bool': _ipa_create_text_input, +}; + +/* create an HTML element for displaying/editing an attribute + * arguments: + * attr - LDAP attribute name + * value - the attributes value */ +function ipa_create_input(attr, value) +{ + var param_info = ipa_get_param_info(attr); + if (!param_info) { + /* no information about the param is available, default to text input */ + return ( + _ipa_create_text_input(attr, value, null) + + _ipa_create_remove_link(attr, null) + ); + } + + /* check if the param value can be modified */ + if (param_info['primary_key'] || ('no_update' in param_info['flags'])) + return (value.toString()); + + /* call handler by param class */ + var handler = _ipa_param_type_2_handler_map[param_info['class']]; + if (handler) { + return ( + handler(attr, value, param_info) + + _ipa_create_remove_link(attr, param_info) + ); + } + + /* no handler for this type? don't allow modification */ + return (value.toString()); +} + +/* HTML template for _ipa_create_remove_link() */ +var _ipa_a_remove_template = + 'Remove'; + +/* creates a Remove link for deleting attribute values */ +function _ipa_create_remove_link(attr, param_info) +{ + if (!param_info) + return (_ipa_a_remove_template.replace('A', attr)); + + /* check if the param is required or of the Password type + * if it is, then we don't want people to be able to remove it */ + if ((param_info['required']) || (param_info['class'] == 'Password')) + return (''); + + return (_ipa_a_remove_template.replace('A', attr)); +} + +/* HTML template for _ipa_create_text_input() */ +var _ipa_input_text_template = + ''; + +/* creates a input box for editing a string attribute */ +function _ipa_create_text_input(attr, value, param_info) +{ + return ( + _ipa_input_text_template.replace('A', attr).replace( + 'V', value.toString() + ) + ); +} + +function ipa_details_reset() +{ + if (ipa_details_cache) + ipa_details_display(ipa_details_cache); +} + +/* Event handlers */ + +function _ipa_add_on_click(obj) +{ + var jobj = $(obj); + var par = jobj.parent(); + par.append(ipa_create_input(jobj.attr('title'), '')); + jobj.next('input').focus(); + jobj.remove(); + return (false); +} + +function _ipa_remove_on_click(obj) +{ + var jobj = $(obj); + var attr = jobj.attr('title'); + var par = jobj.parent(); + + var next = par.next('dd'); + if (next.length) { + if (par.hasClass('first')) { + next.addClass('first'); + next.removeClass('other'); + } + par.remove(); + } else { + par.empty(); + par.append(_ipa_a_add_template.replace('A', attr)); + } + + return (false); +} + +var qs = ipa_parse_qs(); + +/* "Top-level" code */ + +function load_object(body,obj) +{ + if (!qs['pkey']) + return; + ipa_details_init(obj); + $('#butreset').click(reset_on_click); + $('#butupdate').click(update_on_click); + ipa_details_load(qs['pkey'], on_win); + $('h1').text('Managing user: ' + qs['pkey']); + +} + +function on_win(data, textStatus, xhr) +{ + if (data['error']) + alert(data['error']['message']); +} + +function reset_on_click() +{ + if (ipa_details_cache) + ipa_details_display(ipa_details_cache); + return (false); +} + +function update_on_click() +{ + ipa_details_update(qs['pkey'], on_win); + return (false); +} + +/* H2 expand/collapse */ + +function _h2_on_click(obj) +{ + var jobj = $(obj); + var txt = jobj.text().replace(/^\s*/, ''); + if (txt.charCodeAt(0) == 8722) { + obj.dl = jobj.next().detach(); + jobj.text('+' + txt.substr(1)); + } else { + if (obj.dl) + obj.dl.insertAfter(obj); + jobj.text( + String.fromCharCode(8722) + txt.substr(1) + ); + } +} + +/* Account status Toggle button */ + +function toggle_on_click(obj) +{ + var jobj = $(obj); + var val = jobj.attr('title'); + if (val == 'Active') { + ipa_cmd( + 'lock', [qs['pkey']], {}, on_lock_win, on_fail, + PluginData['name'] + ); + } else { + ipa_cmd( + 'unlock', [qs['pkey']], {}, on_lock_win, on_fail, + PluginData['name'] + ); + } + return (false); +} + +function on_lock_win(data, textStatus, xhr) +{ + if (data['error']) { + alert(data['error']['message']); + return; + } + + var jobj = $('a[title=Active]'); + if (jobj.length) { + if (ipa_details_cache) { + var memberof = ipa_details_cache['memberof']; + if (memberof) { + memberof.push( + 'cn=inactivated,cn=account inactivation' + ); + } else { + memberof = ['cn=inactivated,cn=account inactivation']; + } + ipa_details_cache['memberof'] = memberof; + a_status(jobj.parent().prev(), ipa_details_cache); + jobj.parent().remove() + } + return; + } + + var jobj = $('a[title=Inactive]'); + if (jobj.length) { + if (ipa_details_cache) { + var memberof = ipa_details_cache['memberof']; + if (memberof) { + for (var i = 0; i < memberof.length; ++i) { + if (memberof[i].indexOf('cn=inactivated,cn=account inactivation') != -1) { + memberof.splice(i, 1); + break; + } + } + } else { + memberof = []; + } + ipa_details_cache['memberof'] = memberof; + a_status(jobj.parent().prev(), ipa_details_cache); + jobj.parent().remove(); + } + return; + } +} + +/* ATTRIBUTE CALLBACKS */ + +var toggle_temp = 'S Toggle'; +function a_status(jobj, result, mode) +{ + if (mode != IPA_DETAILS_POPULATE) + return; + + var memberof = result['memberof']; + if (memberof) { + for (var i = 0; i < memberof.length; ++i) { + if (memberof[i].indexOf('cn=inactivated,cn=account inactivation') != -1) { + var t = toggle_temp.replace(/S/g, 'Inactive'); + ipa_insert_first_dd(jobj, t); + return; + } + } + } + ipa_insert_first_dd(jobj, toggle_temp.replace(/S/g, 'Inactive')); +} + +var pwd_temp = 'Reset Password'; +function a_password(jobj, result, mode) +{ + if (mode == IPA_DETAILS_POPULATE) + ipa_insert_first_dd(jobj, pwd_temp.replace('A', 'userpassword')); +} + +var select_temp = ''; +var option_temp = ''; +var states = [ + 'AL', 'AK', 'AS', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'DC', 'FM', + 'FL', 'GA', 'GU', 'HI', 'ID', 'IL', 'IN', 'IA', 'KS', 'KY', 'LA', + 'ME', 'MH', 'MD', 'MA', 'MI', 'MN', 'MS', 'MO', 'MT', 'NE', 'NV', + 'NH', 'NJ', 'NM', 'NY', 'NC', 'ND', 'MP', 'OH', 'OK', 'OR', 'PW', + 'PA', 'PR', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VT', 'VI', 'VA', + 'WA', 'WV', 'WI', 'WY', '', +]; +function a_st(jobj, result, mode) +{ + if (mode != IPA_DETAILS_POPULATE) + return; + + var next = jobj.next(); + next.css('clear', 'none'); + next.css('width', '70px'); + + ipa_insert_first_dd(jobj, select_temp); + + var sel = jobj.next().children().first(); + for (var i = 0; i < states.length; ++i) + sel.append(option_temp.replace(/V/g, states[i])); + + var st = result['st']; + if (st) + sel.val(st); + else + sel.val(''); +} + diff --git a/install/static/group-details.inc b/install/static/group-details.inc new file mode 100644 index 000000000..445042b8d --- /dev/null +++ b/install/static/group-details.inc @@ -0,0 +1,32 @@ + +

Managing group:

+
+ Reset + Update +
+ +
+ +

− Group Details

+
+
Group Name:
+
Description:
+
GID
+
+
+ + diff --git a/install/static/group.js b/install/static/group.js new file mode 100644 index 000000000..e1aa701be --- /dev/null +++ b/install/static/group.js @@ -0,0 +1,41 @@ +function setupGroup(facet){ + if (facet == "details"){ + setupGroupDetails(); + }else{ + setupGroupSearch(); + } +} + +function setupGroupDetails(){ + + $('#search').css("visibility","hidden"); + $('#content').css("visibility","visible"); + $('#content').load("group-details.inc"); + + sampleData = "sampledata/groupshow.json"; +} + +function setupGroupSearch(){ + + var columns = [ + {title:"Group Name", column:"cn",render: function(current,cell){ + renderDetailColumn(current,cell,current[this.column],"group"); + }}, + {title:"GID", column:"gidnumber",render: renderSimpleColumn}, + {title:"Description", column:"description",render: renderSimpleColumn} + ]; + + var groupSearchForm = new SearchForm("group", "find", columns); + + $("#query").unbind(); + $("#query").click(function(){ + sampleData = "sampledata/grouplist.json"; + executeSearch(groupSearchForm); + }); + $("#new").unbind(); + $("#new").click( function() { + alert("New Group..."); + }); + + +} diff --git a/install/static/groupmeta.js b/install/static/groupmeta.js new file mode 100644 index 000000000..10bb5d39d --- /dev/null +++ b/install/static/groupmeta.js @@ -0,0 +1,253 @@ + +var PluginData = { + "primary_key": "cn", + "default_attributes": [ + "cn", + "description", + "gidnumber", + "member", + "memberof" + ], + "object_name_plural": "groups", + "container_dn": "cn=groups,cn=accounts", + "object_class_config": "ipagroupobjectclasses", + "hidden_attributes": [ + "objectclass", + "aci" + ], + "uuid_attribute": "ipauniqueid", + "label": "User Groups", + "methods": [ + "add", + "add_member", + "del", + "find", + "mod", + "remove_member", + "show" + ], + "object_name": "group", + "takes_params": [ + { + "exclude": null, + "minlength": null, + "include": null, + "cli_name": "name", + "primary_key": true, + "name": "cn", + "default": null, + "doc": "Group name", + "required": true, + "flags": [], + "label": "Group name", + "autofill": false, + "multivalue": false, + "pattern": null, + "type": "unicode", + "attribute": false, + "query": false, + "cli_short_name": null, + "length": null, + "class": "Str", + "maxlength": null + }, + { + "exclude": null, + "minlength": null, + "include": null, + "cli_name": "desc", + "primary_key": false, + "name": "description", + "default": null, + "doc": "Group description", + "required": true, + "flags": [], + "label": "Description", + "autofill": false, + "multivalue": false, + "pattern": null, + "type": "unicode", + "attribute": false, + "query": false, + "cli_short_name": null, + "length": null, + "class": "Str", + "maxlength": null + }, + { + "exclude": null, + "include": null, + "cli_name": "gid", + "primary_key": false, + "minvalue": null, + "doc": "GID (use this option to set it manually)", + "required": false, + "flags": [], + "label": "GID", + "default": null, + "autofill": false, + "multivalue": false, + "attribute": false, + "query": false, + "maxvalue": null, + "cli_short_name": null, + "type": "int", + "class": "Int", + "name": "gidnumber" + }, + { + "exclude": null, + "minlength": null, + "include": null, + "cli_name": "member_group", + "primary_key": false, + "name": "member_group", + "default": null, + "doc": "Member groups", + "required": false, + "flags": [ + "no_update", + "no_create", + "no_search" + ], + "label": "Member groups", + "autofill": false, + "multivalue": false, + "pattern": null, + "type": "unicode", + "attribute": false, + "query": false, + "cli_short_name": null, + "length": null, + "class": "Str", + "maxlength": null + }, + { + "exclude": null, + "minlength": null, + "include": null, + "cli_name": "member_user", + "primary_key": false, + "name": "member_user", + "default": null, + "doc": "Member users", + "required": false, + "flags": [ + "no_update", + "no_create", + "no_search" + ], + "label": "Member users", + "autofill": false, + "multivalue": false, + "pattern": null, + "type": "unicode", + "attribute": false, + "query": false, + "cli_short_name": null, + "length": null, + "class": "Str", + "maxlength": null + }, + { + "exclude": null, + "minlength": null, + "include": null, + "cli_name": "member", + "primary_key": false, + "name": "member", + "default": null, + "doc": "Failed members", + "required": false, + "flags": [ + "no_update", + "no_create", + "no_search" + ], + "label": "Failed members", + "autofill": false, + "multivalue": false, + "pattern": null, + "type": "unicode", + "attribute": false, + "query": false, + "cli_short_name": null, + "length": null, + "class": "Str", + "maxlength": null + }, + { + "exclude": null, + "minlength": null, + "include": null, + "cli_name": "user", + "primary_key": false, + "name": "user", + "default": null, + "doc": "Users", + "required": false, + "flags": [ + "no_update", + "no_create", + "no_search" + ], + "label": "Users", + "autofill": false, + "multivalue": false, + "pattern": null, + "type": "unicode", + "attribute": false, + "query": false, + "cli_short_name": null, + "length": null, + "class": "Str", + "maxlength": null + }, + { + "exclude": null, + "minlength": null, + "include": null, + "cli_name": "group", + "primary_key": false, + "name": "group", + "default": null, + "doc": "Groups", + "required": false, + "flags": [ + "no_update", + "no_create", + "no_search" + ], + "label": "Groups", + "autofill": false, + "multivalue": false, + "pattern": null, + "type": "unicode", + "attribute": false, + "query": false, + "cli_short_name": null, + "length": null, + "class": "Str", + "maxlength": null + } + ], + "attribute_members": { + "member": [ + "user", + "group" + ], + "memberof": [ + "group", + "netgroup", + "rolegroup", + "taskgroup" + ] + }, + "parent_object": "", + "object_class": [ + "ipausergroup" + ], + "name": "group" +} + +ipa_objs['group'] = PluginData; diff --git a/install/static/host.js b/install/static/host.js new file mode 100644 index 000000000..b6881d836 --- /dev/null +++ b/install/static/host.js @@ -0,0 +1,38 @@ +function setupHost(facet){ + if (facet == "details"){ + setupHostDetails(); + }else{ + setupHostSearch(); + } +} + +function setupHostDetails(){ + var detailsForm = new DetailsForm(); +} + +function setupHostSearch(){ + + sampleData = "sampledata/hostlist.json"; + var columns = [ + {title:"Host",column:"fqdn",render: function(current,cell){ + renderDetailColumn(current,cell,current[this.column],"group"); + }}, + {title:"Comment", column: "description", render: renderSimpleColumn}, + {title:"Enrolled?", render: renderUnknownColumn}, + {title:"Manages?", render: renderUnknownColumn} + ]; + + var hostSearchForm = new SearchForm("host", "find", columns); + + $("#query").unbind(); + $("#query").click(function(){ + sampleData = "sampledata/hostlist.json"; + executeSearch(hostSearchForm); + }); + + $("#new").unbind(); + $("#new").click( function() { + alert("New Host..."); + }); + +} diff --git a/install/static/hostgroup.js b/install/static/hostgroup.js new file mode 100644 index 000000000..64eeb3afc --- /dev/null +++ b/install/static/hostgroup.js @@ -0,0 +1,35 @@ +function setupHostgroup(facet){ + if (facet == "details"){ + setupHostgroupDetails(); + }else{ + setupHostgroupSearch(); + } +} + +function setupHostgroupDetails(){ + var detailsForm = new DetailsForm(); +} + + +function setupHostgroupSearch(){ + + var columns = [ + {title:"Hostgroup",column:"cn",render: function(current,cell){ + renderDetailColumn(current,cell,current[this.column],"hostgroup"); + }}, + {title:"Description", column:"description",render: renderSimpleColumn}]; + + var hostgroupSearchForm = new SearchForm("hostgroup", "find", columns); + + $("#query").unbind(); + + $("#query").click(function(){ + sampleData = "sampledata/hostgrouplist.json"; + executeSearch(hostgroupSearchForm); + }); + $("#new").unbind(); + $("#new").click( function() { + alert("New Hostgroup..."); + }); + +} diff --git a/install/static/index.xhtml b/install/static/index.xhtml new file mode 100644 index 000000000..a33b08364 --- /dev/null +++ b/install/static/index.xhtml @@ -0,0 +1,69 @@ + + + + + IPA: Identity Policy Audit + + + + + + + +
+ + + Logged in as hardcoded@FREEIP.ORG + +
+ +