FELIX-569 : Improve Configuration Page - Apply patch from Valentin Valchev
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@921443 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ConfigManager.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ConfigManager.java
index 5ae091e..fb8e90a 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ConfigManager.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ConfigManager.java
@@ -41,6 +41,7 @@
import org.apache.felix.webconsole.DefaultVariableResolver;
import org.apache.felix.webconsole.WebConsoleUtil;
+import org.apache.felix.webconsole.internal.Util;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -131,6 +132,11 @@
WebConsoleUtil.sendRedirect(request, response, redirect);
}
+ else
+ {
+ response.setContentType("text/plain");
+ response.getWriter().print("true");
+ }
return;
}
@@ -144,7 +150,8 @@
if ( request.getParameter( "unbind" ) != null )
{
config.setBundleLocation( null );
- WebConsoleUtil.sendRedirect( request, response, config.getPid() );
+ response.setContentType("text/plain");
+ response.getWriter().print("true");
return;
}
@@ -212,7 +219,7 @@
while ( i.hasNext() ) {
final String servicePid = i.next().toString();
- final Configuration config = this.getConfiguration(ca, servicePid);
+ final Configuration config = getConfiguration(ca, servicePid);
if ( config != null ) {
if ( printColon ) {
pw.print(',');
@@ -283,7 +290,7 @@
try
{
json.put("status", ca != null ? Boolean.TRUE : Boolean.FALSE);
- listConfigurations(json, ca, pidFilter, locale);
+ listConfigurations(json, ca, pidFilter, locale, loc);
listFactoryConfigurations(json, pidFilter, locale);
}
catch (JSONException e)
@@ -313,7 +320,7 @@
}
- private Configuration getConfiguration( ConfigurationAdmin ca, String pid )
+ private static final Configuration getConfiguration( ConfigurationAdmin ca, String pid )
{
if ( ca != null && pid != null )
{
@@ -367,7 +374,7 @@
}
private final void listConfigurations(JSONObject json, ConfigurationAdmin ca,
- String pidFilter, String locale)
+ String pidFilter, String locale, Locale loc)
{
try
{
@@ -411,7 +418,26 @@
{
String id = (String) i.next();
Object name = optionsPlain.get(id);
- json.append("pids", new JSONObject().put("id", id).put("name", name));
+
+ final Configuration config = getConfiguration(ca, id);
+ JSONObject data = new JSONObject().put("id", id).put("name", name);
+ if (null != config)
+ {
+ final String fpid = config.getFactoryPid();
+ if (null != fpid)
+ {
+ data.put("fpid", fpid);
+ }
+
+ final Bundle bundle = getBoundBundle(config);
+ if (null != bundle)
+ {
+ data.put("bundle", bundle.getBundleId());
+ data.put("bundle_name", Util.getName(bundle, loc));
+ }
+ }
+
+ json.append("pids", data);
}
}
catch (Exception e)
@@ -420,6 +446,24 @@
}
}
+ private final Bundle getBoundBundle(Configuration config)
+ {
+ if (null == config)
+ return null;
+ final String location = config.getBundleLocation();
+ if (null == location)
+ return null;
+
+ final Bundle bundles[] = getBundleContext().getBundles();
+ for (int i = 0; bundles != null && i < bundles.length; i++)
+ {
+ if (bundles[i].getLocation().equals(location))
+ return bundles[i];
+
+ }
+ return null;
+ }
+
private SortedMap getServices( String serviceClass, String serviceFilter, String locale, boolean ocdRequired )
throws InvalidSyntaxException
{
@@ -767,7 +811,7 @@
Configuration config = ca.getConfiguration( pid, null );
config.delete();
}
- return request.getHeader( "Referer" );
+ return null; // return request.getHeader( "Referer" );
}
String factoryPid = request.getParameter( ConfigManager.factoryPID );
diff --git a/webconsole/src/main/resources/OSGI-INF/l10n/bundle.properties b/webconsole/src/main/resources/OSGI-INF/l10n/bundle.properties
index 3e1eba6..c431bf1 100644
--- a/webconsole/src/main/resources/OSGI-INF/l10n/bundle.properties
+++ b/webconsole/src/main/resources/OSGI-INF/l10n/bundle.properties
@@ -170,7 +170,10 @@
config.del.config=Configuration:
config.del.bundle=Bundle:
config.unbind.ask=Are you sure to unbind this configuration ?
-
+config.factories.title=Factory Configurations
+config.configurations.title=Configurations
+config.create.tip=Create new factory configuration
+config.edit.tip=Edit the configuration values
# License plugin
license.status.ok=The following bundles contains license files.
diff --git a/webconsole/src/main/resources/res/ui/config.css b/webconsole/src/main/resources/res/ui/config.css
index 8f96a81..55e62f7 100644
--- a/webconsole/src/main/resources/res/ui/config.css
+++ b/webconsole/src/main/resources/res/ui/config.css
@@ -27,6 +27,8 @@
margin:0;
padding:0
}
-.multiselect {
- display: block;
-}
+.multiselect { display: block }
+.col_Actions { width: 6em !important }
+.pointer { cursor: pointer }
+#editor, div.ui-dialog-buttonpane button { font-size: 50% }
+#factoryTableCaption { margin-top: 1.5em }
diff --git a/webconsole/src/main/resources/res/ui/config.js b/webconsole/src/main/resources/res/ui/config.js
index 01d2624..7e96f45 100644
--- a/webconsole/src/main/resources/res/ui/config.js
+++ b/webconsole/src/main/resources/res/ui/config.js
@@ -14,58 +14,40 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+// tables container - will get hidden, when no config service available
+var configContent = false;
+
+// config table list
+var configTable = false;
+var configBody = false;
+var configRow = false;
+
+// factories table list
+var factoryTable = false;
+var factoryBody = false;
+var factoryRow = false;
-function configure() {
- var select = document.getElementById('configSelection_pid');
- var pid = select.options[select.selectedIndex].value;
- var parm = pluginRoot + '/' + pid;
- $.post(parm, null, displayConfigForm, "json");
-}
+// editor dialog
+var editor = false;
-
-function create() {
- var select = document.getElementById('configSelection_factory');
- var pid = select.options[select.selectedIndex].value;
- var parm = pluginRoot + '/' + pid + '?create=true';
- $.post(parm, null, displayConfigForm, "json");
+function configure(pid, create) {
+ var uri = pluginRoot + '/' + pid;
+ $.post(create ? uri + '?create=1' : uri, null, displayConfigForm, 'json');
}
function displayConfigForm(obj) {
- var span1 = document.getElementById('configField');
- var span2 = document.getElementById('factoryField');
- if (!span1 && !span2) {
- return;
- }
-
- var parent = span1 ? span1.parentNode : span2.parentNode;
-
- clearChildren( parent );
-
- if (span1) {
- parent.appendChild( span1 );
- }
- if (span2) {
- parent.appendChild( span2 );
- }
-
- var trEl = tr( null );
- var tdEl = createElement( "th", null, { colSpan: "2" } );
- addText( tdEl, obj.title );
- trEl.appendChild( tdEl );
- parent.appendChild( trEl );
+ var parent = document.getElementById('editorTable');
+ clearChildren( parent )
- trEl = tr( );
+ var trEl = tr( );
parent.appendChild( trEl );
- tdEl = td( );
- addText( tdEl, "\u00a0" );
- trEl.appendChild( tdEl );
-
- tdEl = td( );
+ var tdEl = td( null, { colSpan: "2" } );
trEl.appendChild( tdEl );
var formEl = createElement( "form", null, {
+ id : "editorForm",
method: "POST",
action: pluginRoot + "/" + obj.pid
});
@@ -133,28 +115,9 @@
{
printForm(bodyEl, obj);
}
-
- trEl = tr( );
- bodyEl.appendChild( trEl );
-
- tdEl = td( );
- addText( tdEl, "\u00a0" );
- trEl.appendChild( tdEl );
-
- tdEl = td( );
- trEl.appendChild( tdEl );
-
- // define this TD as innerHTML otherwise the onClick event handler
- // of the Delete button is not accepted by IE6 (!)...
- var innerHTML = '<input type="submit" name="submit" value="'+i18n.save+'" />';
- innerHTML += ' ';
- innerHTML += '<input type="reset" name="reset" value="'+i18n.reset+'" />';
- innerHTML += ' ';
- innerHTML += '<input type="submit" name="delete" value="'+i18n.del+'" onClick="return confirmDelete(\'' + obj.pid + '\', \'' + obj.bundleLocation + '\');"/>';
- tdEl.innerHTML = innerHTML;
printConfigurationInfo(parent, obj);
- initStaticWidgets($(parent));
+ initStaticWidgets(editor.attr('__pid', obj.pid).dialog('option', 'title', obj.title).dialog('open'));
}
function printTextArea(/* Element */ parent, props )
@@ -291,29 +254,7 @@
])
])
);
-
- if (obj.bundleLocation)
- {
- var form = createElement( "form", null, {
- method: "POST",
- action: pluginRoot + "/" + obj.pid
- });
- // define this form contents as innerHTML otherwise the onClick
- // event handler of the Unbind button is not accepted by IE6 (!)...
- var formInner = '<input type="hidden" name="unbind" value="true"/>';
- formInner += '<input type="submit" name="submit" value="'+i18n.unbind_btn+'" class="ui-state-default ui-corner-all" title="'+i18n.unbind_tip+'" onClick="return confirmUnbind(\'' + obj.pid + '\', \'' + obj.bundleLocation + '\');"/>';
- form.innerHTML = formInner;
-
- parent.appendChild( tr( null, null, [
- td( null, null, [
- text( " " )
- ]),
- td( null, null, [ form ] )
- ])
- );
- }
- //$(form).ready(initStaticWidgets);
}
@@ -475,7 +416,7 @@
function confirmDelete(/* String */ title, /* String */ location)
{
- return configConfirm(i18n.unbind_ask, title, location);
+ return configConfirm(i18n.del_ask, title, location);
}
function confirmUnbind(/* String */ title, /* String */ location)
@@ -483,26 +424,95 @@
return configConfirm(i18n.unbind_ask, title, location);
}
-function addOption(list, target)
-{
- var html = "";
- for (i in list) {
- var sel = list[i].id == selectedPid ? '" selected="selected' : '';
- html += '<option value="' + list[i].id + sel + '">' + list[i].name + '</option>';
- }
- if (html) target.html(html);
+function addConfig(conf) {
+ var tr = configRow.clone().appendTo(configBody);
+ tr.find('td:eq(0)').text(conf.fpid ? conf.fpid : '-'); // fpid
+ tr.find('td:eq(1)').text(conf.name).click(function() { // name & edit
+ configure(conf.id);
+ });
+ tr.find('td:eq(2)').html(conf.bundle ? '<a href="' + pluginRoot + '/../bundles/' + conf.bundle + '">' + conf.bundle_name + '</a>' : '-'); // binding
+
+ // buttons
+ tr.find('li:eq(0)').click(function() { // edit
+ configure(conf.id);
+ });
+ tr.find('li:eq(2)').click(function() { // delete
+ if ( confirmDelete(conf.id, conf.bundle_name) ) {
+ $.post(pluginRoot + '/' + conf.id + '?apply=1&delete=1', null, function() {
+ document.location.href = pluginRoot;
+ }, 'json');
+ }
+ });
+ if (conf.bundle) tr.find('li:eq(1)').click(function() { // unbind
+ if ( confirmUnbind(conf.id, conf.bundle_name) ) {
+ $.post(pluginRoot + '/' + conf.id + '?apply=1&delete=1', null, function() {
+ document.location.href = pluginRoot + '/' + conf.id;
+ }, 'json');
+ }
+ }).removeClass('ui-state-disabled');
}
-var configSelection_pid = false;
-var configSelection_factory = false;
+function addFactoryConfig(conf) {
+ var tr = factoryRow.clone().appendTo(factoryBody);
+ tr.find('td:eq(0)').text(conf.id); // fpid
+ tr.find('td:eq(1)').text(conf.name).click(function() { // name & edit
+ configure(conf.id, true);
+ });
+ // buttons
+ tr.find('li:eq(0)').click(function() { // edit
+ configure(conf.id, true);
+ });
+}
+
$(document).ready(function() {
- configSelection_pid = $('#configSelection_pid');
- configSelection_factory = $('#configSelection_factory');
- $(".statline").html(configData.status ? i18n.stat_ok : i18n.stat_missing);
- $("#config_content").css("display", configData.status ? "block" : "none");
- if (configData.status) {
- addOption(configData.pids, $("#configSelection_pid"));
- addOption(configData.fpids, $("#configSelection_factory"));
+ configContent = $('#configContent');
+ // config table list
+ configTable = configContent.find('table:eq(0)').tablesorter({
+ headers: { 3: { sorter: false } },
+ textExtraction:mixedLinksExtraction
+ });
+ configBody = configTable.find('tbody');
+ configRow = configBody.find('tr').clone();
+
+ // factories table list
+ factoryTable = configContent.find('table:eq(1)').tablesorter({
+ headers: { 2: { sorter: false } }
+ });
+ factoryBody = factoryTable.find('tbody');
+ factoryRow = factoryBody.find('tr').clone();
+
+ // setup button - cannot inline in dialog option because of i18n
+ var _buttons = {};
+ _buttons[i18n.abort] = function() {
+ $(this).dialog('close');
}
- if (selectedPid) configure();
+ _buttons[i18n.reset] = function() {
+ var form = document.getElementById('editorForm');
+ if (form) form.reset();
+ }
+ _buttons[i18n.save] = function() {
+ $.post(pluginRoot + '/' + $(this).attr('__pid') + '?' + $(this).find('form').serialize());
+ $(this).dialog('close');
+ }
+ // prepare editor, but don't open yet!
+ editor = $('#editor').dialog({
+ autoOpen : false,
+ modal : true,
+ width : '90%',
+ closeText: i18n.abort,
+ buttons : _buttons
+ });
+
+ // display the configuration data
+ $(".statline").html(configData.status ? i18n.stat_ok : i18n.stat_missing);
+ if (configData.status) {
+ configBody.empty(); factoryBody.empty();
+
+ for(var i in configData.pids) addConfig(configData.pids[i]);
+ for(var i in configData.fpids) addFactoryConfig(configData.fpids[i]);
+ initStaticWidgets(configContent);
+ } else {
+ configContent.addClass('ui-helper-hidden');
+ }
+ if (selectedPid) configure(selectedPid);
});
\ No newline at end of file
diff --git a/webconsole/src/main/resources/templates/config.html b/webconsole/src/main/resources/templates/config.html
index 6c4b3d2..34629c5 100644
--- a/webconsole/src/main/resources/templates/config.html
+++ b/webconsole/src/main/resources/templates/config.html
@@ -1,4 +1,4 @@
-<script type="text/javascript" src="res/ui/config.js"></script>
+<script type="text/javascript" src="res/ui/config.js"></script>
<script type="text/javascript">
// <![CDATA[
// data
@@ -10,6 +10,7 @@
save : '${save}',
reset : '${reset}',
del : '${delete}',
+ abort : '${abort}',
props_title : '${config.properties}',
props_enter : '${config.properties.enter}', // "Enter Name-Value pairs of configuration properties"
cfg_title : '${config.info.title}', // "Configuration Information"
@@ -22,10 +23,7 @@
del_ask : '${config.del.ask}', // "Are you sure to delete this configuration ?";
del_config : '${config.del.config}', // "Configuration: ";
del_bundle : '${config.del.bundle}', // "Bundle: ";
- unbind_ask : '${config.unbind.ask}', // "Are you sure to unbind this configuration ?"
- 'xx' : '${config.form.properties}',
- 'xx' : '${config.form.properties}',
-
+ unbind_ask : '${config.unbind.ask}' // "Are you sure to unbind this configuration ?"
}
// ]]>
</script>
@@ -33,27 +31,65 @@
<!-- status line -->
<p class="statline"> </p>
-<div id="config_content" >
- <table class="nicetable">
- <tr id="configField">
- <td>Configurations</td>
- <td>
- <select name="pid" id="configSelection_pid" onchange="configure();">
- <option> </option>
- </select>
-
- <button onclick="configure();">Configure</button>
- </td>
- </tr>
- <tr id="factoryField">
- <td>Factory Configurations</td>
- <td>
- <select name="pid" id="configSelection_factory" onchange="create();">
- <option> </option>
- </select>
-
- <button onclick="create();">Create</button>
- </td>
- </tr>
+
+<div id="configContent" >
+ <div id="fPidsSelect" class="ui-widget-header ui-corner-top buttonGroup">
+ ${config.configurations.title}
+ </div>
+ <table class="tablesorter nicetable noauto">
+ <thead>
+ <tr>
+ <th class="col_FPID">Factory PID</th>
+ <th class="col_Name">Name</th>
+ <th class="col_Binding">Bundle</th>
+ <th class="col_Actions" style="width: 7em">Actions</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td> </td>
+ <td class="pointer"> </td>
+ <td> </td>
+ <td>
+ <ul class="icons">
+ <li class="dynhover" title="${config.edit.tip}"><span class="ui-icon ui-icon-pencil"> </span></li>
+ <li class="ui-state-disabled dynhover" title="${config.unbind.tip}"><span class="ui-icon ui-icon-transferthick-e-w"> </span></li>
+ <li class="dynhover" title="${delete}"><span class="ui-icon ui-icon-trash"> </span></li>
+ </ul>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+ <div id="factoryTableCaption" class="ui-widget-header ui-corner-top buttonGroup">
+ ${config.factories.title}
+ </div>
+ <table class="tablesorter nicetable noauto">
+ <thead>
+ <tr>
+ <th class="col_FPID">Factory PID</th>
+ <th class="col_Name">Name</th>
+ <th class="col_Actions" style="width: 7em">Actions</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td> </td>
+ <td class="pointer"> </td>
+ <td>
+ <ul class="icons">
+ <li class="dynhover" title="${config.create.tip}"><span class="ui-icon ui-icon-plusthick"> </span></li>
+ </ul>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+</div>
+
+<!-- placeholder for property editor -->
+<div id="editor" class="ui-helper-hidden">
+ <table id="editorTable" class="nicetable">
+ <tr><td> </td></tr>
</table>
</div>