[Kimchi-devel] [PATCH 12/17] Ginger Base : base plugin ui/js files

Aline Manera alinefm at linux.vnet.ibm.com
Thu Sep 10 13:59:23 UTC 2015


Most of files in this patch are being duplicated from Kimchi/wok. We 
need to think on how to avoid this code duplication.


On 01/09/2015 15:01, chandra at linux.vnet.ibm.com wrote:
> From: chandrureddy <chandra at linux.vnet.ibm.com>
>
> ---
>   plugins/gingerbase/ui/js/Makefile.am               |  27 +
>   plugins/gingerbase/ui/js/src/gingerbase.api.js     | 371 +++++++++
>   plugins/gingerbase/ui/js/src/gingerbase.form.js    |  48 ++
>   plugins/gingerbase/ui/js/src/gingerbase.grid.js    | 528 +++++++++++++
>   plugins/gingerbase/ui/js/src/gingerbase.host.js    | 859 +++++++++++++++++++++
>   .../gingerbase/ui/js/src/gingerbase.line-chart.js  | 202 +++++
>   plugins/gingerbase/ui/js/src/gingerbase.main.js    |  26 +
>   .../ui/js/src/gingerbase.report_add_main.js        |  72 ++
>   .../ui/js/src/gingerbase.report_rename_main.js     |  66 ++
>   .../ui/js/src/gingerbase.repository_add_main.js    |  96 +++
>   .../ui/js/src/gingerbase.repository_edit_main.js   |  74 ++
>   plugins/gingerbase/ui/js/src/gingerbase.select.js  |  50 ++
>   plugins/gingerbase/ui/js/widgets/circleGauge.js    | 100 +++
>   plugins/kimchi/ui/js/src/kimchi.host.js            | 858 --------------------
>   plugins/kimchi/ui/js/src/kimchi.report_add_main.js |  72 --
>   .../kimchi/ui/js/src/kimchi.report_rename_main.js  |  66 --
>   .../kimchi/ui/js/src/kimchi.repository_add_main.js |  96 ---
>   .../ui/js/src/kimchi.repository_edit_main.js       |  74 --
>   18 files changed, 2519 insertions(+), 1166 deletions(-)
>   create mode 100644 plugins/gingerbase/ui/js/Makefile.am
>   create mode 100644 plugins/gingerbase/ui/js/src/gingerbase.api.js
>   create mode 100644 plugins/gingerbase/ui/js/src/gingerbase.form.js
>   create mode 100644 plugins/gingerbase/ui/js/src/gingerbase.grid.js
>   create mode 100644 plugins/gingerbase/ui/js/src/gingerbase.host.js
>   create mode 100644 plugins/gingerbase/ui/js/src/gingerbase.line-chart.js
>   create mode 100644 plugins/gingerbase/ui/js/src/gingerbase.main.js
>   create mode 100644 plugins/gingerbase/ui/js/src/gingerbase.report_add_main.js
>   create mode 100644 plugins/gingerbase/ui/js/src/gingerbase.report_rename_main.js
>   create mode 100644 plugins/gingerbase/ui/js/src/gingerbase.repository_add_main.js
>   create mode 100644 plugins/gingerbase/ui/js/src/gingerbase.repository_edit_main.js
>   create mode 100644 plugins/gingerbase/ui/js/src/gingerbase.select.js
>   create mode 100644 plugins/gingerbase/ui/js/widgets/circleGauge.js
>   delete mode 100644 plugins/kimchi/ui/js/src/kimchi.host.js
>   delete mode 100644 plugins/kimchi/ui/js/src/kimchi.report_add_main.js
>   delete mode 100644 plugins/kimchi/ui/js/src/kimchi.report_rename_main.js
>   delete mode 100644 plugins/kimchi/ui/js/src/kimchi.repository_add_main.js
>   delete mode 100644 plugins/kimchi/ui/js/src/kimchi.repository_edit_main.js
>
> diff --git a/plugins/gingerbase/ui/js/Makefile.am b/plugins/gingerbase/ui/js/Makefile.am
> new file mode 100644
> index 0000000..142ccdb
> --- /dev/null
> +++ b/plugins/gingerbase/ui/js/Makefile.am
> @@ -0,0 +1,27 @@
> +#
> +# Kimchi
> +#
> +# Copyright IBM, Corp. 2013
> +#
> +# Licensed under the Apache License, Version 2.0 (the "License");
> +# you may not use this file except in compliance with the License.
> +# You may obtain a copy of the License at
> +#
> +#     http://www.apache.org/licenses/LICENSE-2.0
> +#
> +# Unless required by applicable law or agreed to in writing, software
> +# distributed under the License is distributed on an "AS IS" BASIS,
> +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> +# See the License for the specific language governing permissions and
> +# limitations under the License.
> +
> +EXTRA_DIST = src widgets
> +
> +jsdir = $(datadir)/wok/plugins/gingerbase/ui/js
> +
> +dist_js_DATA = gingerbase.min.js $(filter-out gingerbase.min.js, $(wildcard *.js))
> +
> +gingerbase.min.js: widgets/*.js src/*.js
> +	cat $(sort $^) > $@
> +
> +CLEANFILES = gingerbase.min.js
> diff --git a/plugins/gingerbase/ui/js/src/gingerbase.api.js b/plugins/gingerbase/ui/js/src/gingerbase.api.js
> new file mode 100644
> index 0000000..480f6fb
> --- /dev/null
> +++ b/plugins/gingerbase/ui/js/src/gingerbase.api.js
> @@ -0,0 +1,371 @@
> +/*
> + * Project Kimchi
> + *
> + * Copyright IBM, Corp. 2013-2015
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +var kimchi = {
> +
> +    widget: {},
> +
> +    trackingTasks: [],
> +
> +    /**
> +     *
> +     * Get host capabilities
> +     * suc: callback if succeed err: callback if failed
> +     */
> +    getCapabilities : function(suc, err, done) {
> +        done = typeof done !== 'undefined' ? done: function(){};
> +        wok.requestJSON({
> +            url : "plugins/gingerbase/host/capabilities",
> +            type : "GET",
> +            contentType : "application/json",
> +            dataType : "json",
> +            success: suc,
> +            error: err,
> +            complete: done
> +        });
> +    },
> +
> +    /**
> +     * Get the i18 strings.
> +     */
> +    getI18n: function(suc, err, url, sync) {
> +        wok.requestJSON({
> +            url : url ? url : 'plugins/gingerbase/i18n.json',
> +            type : 'GET',
> +            resend: true,
> +            dataType : 'json',
> +            async : !sync,
> +            success : suc,
> +            error: err
> +        });
> +    },
> +
> +    /**
> +     * Get the host static information.
> +     */
> +    getHost: function(suc, err) {
> +        wok.requestJSON({
> +            url : 'plugins/gingerbase/host',
> +            type : 'GET',
> +            resend: true,
> +            contentType : 'application/json',
> +            dataType : 'json',
> +            success : suc,
> +            error: err
> +        });
> +    },
> +
> +    /**
> +     * Get the dynamic host stats (usually used for monitoring).
> +     */
> +    getHostStats : function(suc, err) {
> +        wok.requestJSON({
> +            url : 'plugins/gingerbase/host/stats',
> +            type : 'GET',
> +            contentType : 'application/json',
> +            headers: {'Wok-Robot': 'wok-robot'},
> +            dataType : 'json',
> +            success : suc,
> +            error: err
> +        });
> +    },
> +
> +    /**
> +     * Get the historic host stats.
> +     */
> +    getHostStatsHistory : function(suc, err) {
> +        wok.requestJSON({
> +            url : 'plugins/gingerbase/host/stats/history',
> +            type : 'GET',
> +            resend: true,
> +            contentType : 'application/json',
> +            headers: {'Wok-Robot': 'wok-robot'},
> +            dataType : 'json',
> +            success : suc,
> +            error: err
> +        });
> +    },
> +
> +    getTask : function(taskId, suc, err) {
> +        wok.requestJSON({
> +            url : 'plugins/gingerbase/tasks/' + encodeURIComponent(taskId),
> +            type : 'GET',
> +            contentType : 'application/json',
> +            dataType : 'json',
> +            success : suc,
> +            error : err
> +        });
> +    },
> +
> +    getTasksByFilter : function(filter, suc, err, sync) {
> +        wok.requestJSON({
> +            url : 'plugins/gingerbase/tasks?' + filter,
> +            type : 'GET',
> +            contentType : 'application/json',
> +            dataType : 'json',
> +            async : !sync,
> +            success : suc,
> +            error : err
> +        });
> +    },
> +
> +    listReports : function(suc, err) {
> +        wok.requestJSON({
> +            url : 'plugins/gingerbase/debugreports',
> +            type : 'GET',
> +            contentType : 'application/json',
> +            dataType : 'json',
> +            resend: true,
> +            success : suc,
> +            error : err
> +        });
> +    },
> +
> +    trackTask : function(taskID, suc, err, progress) {
> +        var onTaskResponse = function(result) {
> +            var taskStatus = result['status'];
> +            switch(taskStatus) {
> +            case 'running':
> +                progress && progress(result);
> +                setTimeout(function() {
> +                    kimchi.trackTask(taskID, suc, err, progress);
> +                }, 2000);
> +                break;
> +            case 'finished':
> +                suc && suc(result);
> +                break;
> +            case 'failed':
> +                err && err(result);
> +                break;
> +            default:
> +                break;
> +            }
> +        };
> +
> +        kimchi.getTask(taskID, onTaskResponse, err);
> +        if(kimchi.trackingTasks.indexOf(taskID) < 0)
> +            kimchi.trackingTasks.push(taskID);
> +    },
> +
> +    createReport: function(settings, suc, err, progress) {
> +        var onResponse = function(data) {
> +            taskID = data['id'];
> +            kimchi.trackTask(taskID, suc, err, progress);
> +        };
> +
> +        wok.requestJSON({
> +            url : 'plugins/gingerbase/debugreports',
> +            type : "POST",
> +            contentType : "application/json",
> +            data : JSON.stringify(settings),
> +            dataType : "json",
> +            success : onResponse,
> +            error : err
> +        });
> +    },
> +
> +    renameReport : function(name, settings, suc, err) {
> +        $.ajax({
> +            url : "plugins/gingerbase/debugreports/" + encodeURIComponent(name),
> +            type : 'PUT',
> +            contentType : 'application/json',
> +            data : JSON.stringify(settings),
> +            dataType : 'json',
> +            success: suc,
> +            error: err
> +        });
> +    },
> +
> +    deleteReport: function(settings, suc, err) {
> +        var reportName = encodeURIComponent(settings['name']);
> +        wok.requestJSON({
> +            url : 'plugins/gingerbase/debugreports/' + reportName,
> +            type : 'DELETE',
> +            contentType : 'application/json',
> +            dataType : 'json',
> +            success : suc,
> +            error : err
> +        });
> +    },
> +
> +    downloadReport: function(settings, suc, err) {
> +        window.open(settings['file']);
> +    },
> +
> +    shutdown: function(settings, suc, err) {
> +        var reboot = settings && settings['reboot'] === true;
> +        var url = 'plugins/gingerbase/host/' + (reboot ? 'reboot' : 'shutdown');
> +        wok.requestJSON({
> +            url : url,
> +            type : 'POST',
> +            contentType : 'application/json',
> +            dataType : 'json',
> +            success : suc,
> +            error : err
> +        });
> +    },
> +
> +    listHostPartitions : function(suc, err) {
> +        wok.requestJSON({
> +            url : 'plugins/gingerbase/host/partitions',
> +            type : 'GET',
> +            contentType : 'application/json',
> +            dataType : 'json',
> +            success : suc,
> +            error : err
> +        });
> +    },
> +
> +    listSoftwareUpdates : function(suc, err) {
> +        wok.requestJSON({
> +            url : 'plugins/gingerbase/host/packagesupdate',
> +            type : 'GET',
> +            contentType : 'application/json',
> +            dataType : 'json',
> +            resend: true,
> +            success : suc,
> +            error : err
> +        });
> +    },
> +
> +    updateSoftware : function(suc, err, progress) {
> +        var taskID = -1;
> +        var onResponse = function(data) {
> +            taskID = data['id'];
> +            trackTask();
> +        };
> +
> +        var trackTask = function() {
> +            kimchi.getTask(taskID, onTaskResponse, err);
> +        };
> +
> +        var onTaskResponse = function(result) {
> +            var taskStatus = result['status'];
> +            switch(taskStatus) {
> +            case 'running':
> +                progress && progress(result);
> +                setTimeout(function() {
> +                    trackTask();
> +                }, 200);
> +                break;
> +            case 'finished':
> +            case 'failed':
> +                suc(result);
> +                break;
> +            default:
> +                break;
> +            }
> +        };
> +
> +        wok.requestJSON({
> +            url : 'plugins/gingerbase/host/swupdate',
> +            type : "POST",
> +            contentType : "application/json",
> +            dataType : "json",
> +            success : onResponse,
> +            error : err
> +        });
> +    },
> +
> +    createRepository : function(settings, suc, err) {
> +        wok.requestJSON({
> +            url : "plugins/gingerbase/host/repositories",
> +            type : "POST",
> +            contentType : "application/json",
> +            data : JSON.stringify(settings),
> +            dataType : "json",
> +            success: suc,
> +            error: err
> +        });
> +    },
> +
> +    retrieveRepository : function(repository, suc, err) {
> +        var reposID = encodeURIComponent(repository);
> +        wok.requestJSON({
> +            url : "plugins/gingerbase/host/repositories/" + reposID,
> +            type : 'GET',
> +            contentType : 'application/json',
> +            dataType : 'json',
> +            success : suc,
> +            error : err
> +        });
> +    },
> +
> +    updateRepository : function(name, settings, suc, err) {
> +        var reposID = encodeURIComponent(name);
> +        $.ajax({
> +            url : "plugins/gingerbase/host/repositories/" + reposID,
> +            type : 'PUT',
> +            contentType : 'application/json',
> +            data : JSON.stringify(settings),
> +            dataType : 'json',
> +            success : suc,
> +            error : err
> +        });
> +    },
> +
> +    enableRepository : function(name, enable, suc, err) {
> +        var reposID = encodeURIComponent(name);
> +        $.ajax({
> +            url : "plugins/gingerbase/host/repositories/" + reposID +
> +                  '/' + (enable === true ? 'enable' : 'disable'),
> +            type : 'POST',
> +            contentType : 'application/json',
> +            dataType : 'json',
> +            success : suc,
> +            error : err
> +        });
> +    },
> +
> +    deleteRepository : function(repository, suc, err) {
> +        var reposID = encodeURIComponent(repository);
> +        wok.requestJSON({
> +            url : 'plugins/gingerbase/host/repositories/' + reposID,
> +            type : 'DELETE',
> +            contentType : 'application/json',
> +            dataType : 'json',
> +            success : suc,
> +            error : err
> +        });
> +    },
> +
> +    listRepositories : function(suc, err) {
> +        wok.requestJSON({
> +            url : 'plugins/gingerbase/host/repositories',
> +            type : 'GET',
> +            contentType : 'application/json',
> +            dataType : 'json',
> +            resend: true,
> +            success : suc,
> +            error : err
> +        });
> +    },
> +
> +    getCPUInfo : function(suc, err) {
> +        wok.requestJSON({
> +            url : 'plugins/gingerbase/host/cpuinfo',
> +            type : 'GET',
> +            contentType : 'application/json',
> +            dataType : 'json',
> +            resend : true,
> +            success : suc,
> +            error : err ? err : function(data) {
> +                wok.message.error(data.responseJSON.reason);
> +            }
> +        });
> +    }
> +};
> diff --git a/plugins/gingerbase/ui/js/src/gingerbase.form.js b/plugins/gingerbase/ui/js/src/gingerbase.form.js
> new file mode 100644
> index 0000000..0bb7c4b
> --- /dev/null
> +++ b/plugins/gingerbase/ui/js/src/gingerbase.form.js
> @@ -0,0 +1,48 @@
> +/*
> + * Project Kimchi
> + *
> + * Copyright IBM, Corp. 2013-2014
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +
> +(function($) {
> +    $.fn.serializeObject = function() {
> +        var formDataArray = $(this).serializeArray();
> +        var formData = new Object();
> +        $.each(formDataArray, function(index, data) {
> +            formData.setDeepValue(data.name, data.value);
> +        });
> +        return formData;
> +    };
> +}(jQuery));
> +
> +(function($) {
> +    $.fn.fillWithObject = function(obj) {
> +        $(this).find("input").each(function(){
> +            switch($(this).attr('type')) {
> +                case 'text':
> +                    $(this).val(obj.getDeepValue($(this).attr("name")));
> +                    break;
> +                case 'radio':
> +                case 'checkbox':
> +                    var a=String($(this).val());
> +                    var b=String(obj.getDeepValue($(this).attr("name")));
> +                    $(this).prop("checked",(a==b));
> +                    break;
> +                default:
> +                    break;
> +                }
> +            });
> +     };
> +}(jQuery));
> diff --git a/plugins/gingerbase/ui/js/src/gingerbase.grid.js b/plugins/gingerbase/ui/js/src/gingerbase.grid.js
> new file mode 100644
> index 0000000..4553135
> --- /dev/null
> +++ b/plugins/gingerbase/ui/js/src/gingerbase.grid.js
> @@ -0,0 +1,528 @@
> +/*
> + * Project Kimchi
> + *
> + * Copyright IBM, Corp. 2013-2015
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +kimchi.widget.Grid = function(opts) {
> +    this.opts = $.extend({}, this.opts, opts);
> +    this.createDOM();
> +    this.reload();
> +};
> +
> +kimchi.widget.Grid.prototype = (function() {
> +    var htmlStr = [
> +        '<div id="{id}" class="grid">',
> +            '<div class="grid-content">',
> +                '<div class="grid-header">',
> +                    '<div class="grid-frozen-header-view">',
> +                        '<table class="grid-frozen-header-container">',
> +                        '</table>',
> +                    '</div>',
> +                    '<div class="grid-header-view">',
> +                        '<div class="grid-header-wrapper">',
> +                            '<table class="grid-header-container">',
> +                            '</table>',
> +                        '</div>',
> +                    '</div>',
> +                '</div>',
> +                '<div class="grid-body">',
> +                    '<div class="grid-frozen-body-view">',
> +                        '<div class="grid-frozen-body-wrapper">',
> +                            '<table class="grid-frozen-body-container">',
> +                            '</table>',
> +                        '</div>',
> +                    '</div>',
> +                    '<div class="grid-body-view">',
> +                        '<div class="grid-body-wrapper">',
> +                            '<table class="grid-body-container">',
> +                            '</table>',
> +                        '</div>',
> +                    '</div>',
> +                '</div>',
> +                '<div class="grid-resizer-leftmost hidden"></div>',
> +                '<div class="grid-resizer hidden"></div>',
> +            '</div>',
> +            '<div class="grid-footer"></div>',
> +            '<div class="grid-mask hidden">',
> +                '<div class="grid-loading">',
> +                    '<div class="grid-loading-icon"></div>',
> +                    '<div class="grid-loading-text">',
> +                        '{loading}',
> +                    '</div>',
> +                '</div>',
> +            '</div>',
> +            '<div class="grid-message hidden">',
> +                '<div class="grid-message-text">',
> +                    '{message}',
> +                    '<button class="retry-button btn-small">',
> +                        '{buttonLabel}',
> +                    '</button>',
> +                '</div>',
> +                '<div class="detailed-title">',
> +                    '{detailedLabel}',
> +                '</div>',
> +                '<div class="detailed-text"></div>',
> +            '</div>',
> +        '</div>'
> +    ].join('');
> +
> +    var CONTAINER_NORMAL = 0, CONTAINER_FROZEN = 1;
> +
> +    var setupHeaders = function(header, body, fields) {
> +        var colGroup = $('<colgroup></colgroup>').appendTo(header);
> +        var headerHeader = $('<thead></thead>');
> +        var headerRow = $('<tr></tr>').appendTo(headerHeader);
> +        $.each(fields || [], function(i, field) {
> +            $('<col class="' +
> +                field['class'] +
> +            '"/>')
> +                .appendTo(colGroup);
> +            $('<th><div class="cell-text-wrapper">' +
> +                field['label'] +
> +            '</div></th>').appendTo(headerRow);
> +        });
> +        headerHeader.appendTo(header);
> +
> +        var totalWidth = 0;
> +        $('col', colGroup).each(function(index, col) {
> +            var width = $(col).width();
> +            totalWidth += width;
> +            $(col).css('width', width + 'px');
> +        });
> +        $(body).append(colGroup.clone());
> +        return totalWidth;
> +    };
> +
> +    var getValue = function(name, obj) {
> +        var result=undefined;
> +        if(!Array.isArray(name)) {
> +            name=name.parseKey();
> +        }
> +        if(name.length!=0) {
> +            var tmpName=name.shift();
> +            if(obj[tmpName]!=undefined) {
> +                    result=obj[tmpName];
> +            }
> +            if(name.length!=0) {
> +                    result=getValue(name,obj[tmpName]);
> +            }
> +        }
> +        return(result);
> +    };
> +
> +    var fillBody = function(container, fields) {
> +        var data = this.data;
> +        var tbody = ($('tbody', container).length && $('tbody', container))
> +            || $('<tbody></tbody>').appendTo(container);
> +        tbody.empty();
> +        $.each(data, function(i, row) {
> +            var rowNode = $('<tr></tr>').appendTo(tbody);
> +            $.each(fields, function(fi, field) {
> +                var value = getValue(field['name'], row);
> +                $('<td><div class="cell-text-wrapper"' +
> +                    (field['makeTitle'] === true
> +                        ? ' title="' + value + '"'
> +                        : ''
> +                    ) + '>' + value.toString() + '</div></td>'
> +                ).appendTo(rowNode);
> +            });
> +        });
> +    };
> +
> +    var fixTableLayout = function(style) {
> +        $.each([
> +            this.frozenHeaderContainer,
> +            this.headerContainer,
> +            this.frozenBodyContainer,
> +            this.bodyContainer
> +        ], function(i, tableNode) {
> +            $(tableNode).css('table-layout', style || 'fixed');
> +        });
> +    };
> +
> +    var initResizing = function(event) {
> +        var resizer = event.data.resizer;
> +        var pageX = event.pageX;
> +        var tailPos = $(this).width() + $(this).offset()['left'];
> +        var atResizer = Math.abs(pageX - tailPos) <= 2;
> +        var isResizing = !$(resizer).hasClass('hidden');
> +        $('body')[(atResizer || isResizing)
> +            ? 'addClass'
> +            : 'removeClass'
> +        ]('resizing');
> +    };
> +
> +    var clearResizing = function(event) {
> +        $(event.data.resizer).hasClass('hidden') &&
> +            $('body').removeClass('resizing');
> +    };
> +
> +    var stylingRow = function(row, className, add) {
> +        var index = $(row).index() + 1;
> +        $('tr', this.frozenBodyContainer)
> +            .removeClass(className);
> +        $('tr', this.bodyContainer)
> +            .removeClass(className);
> +
> +        if(add === false) {
> +            return;
> +        }
> +
> +        $('tr:nth-child(' + index + ')', this.frozenBodyContainer)
> +            .addClass(className);
> +        $('tr:nth-child(' + index + ')', this.bodyContainer)
> +            .addClass(className);
> +    };
> +
> +    var setBodyListeners = function() {
> +        if(this['opts']['rowSelection'] != 'disabled') {
> +            $('tr', this.gridBody).on('mouseover', {
> +                grid: this
> +            }, function(event) {
> +                if (! $(this).hasClass('no-hover'))
> +                    stylingRow.call(event.data.grid, this, 'hover');
> +            });
> +
> +            $('tr', this.gridBody).on('mouseout', {
> +                grid: this
> +            }, function(event) {
> +                stylingRow.call(event.data.grid, this, 'hover', false);
> +            });
> +
> +            $('tr', this.gridBody).on('click', {
> +                grid: this
> +            }, function(event) {
> +                var grid = event.data.grid;
> +                grid.selectedIndex = $(this).index();
> +                stylingRow.call(grid, this, 'selected');
> +                grid['opts']['onRowSelected'] && grid['opts']['onRowSelected']();
> +            });
> +        }
> +
> +        $('.grid-body-view', this.domNode).on('scroll', {
> +            grid: this
> +        }, function(event) {
> +            var grid = event.data.grid;
> +            $('.grid-header .grid-header-view', grid.domNode)
> +                .prop('scrollLeft', this.scrollLeft);
> +            $('.grid-body .grid-frozen-body-view', grid.domNode)
> +                .prop('scrollTop', this.scrollTop);
> +        });
> +    };
> +
> +    var setData = function(data) {
> +        this.data = data;
> +        fillBody.call(this, this.frozenBodyContainer, this['opts']['frozenFields']);
> +        fillBody.call(this, this.bodyContainer, this['opts']['fields']);
> +        setBodyListeners.call(this);
> +    };
> +
> +    var getSelected = function() {
> +        return this.selectedIndex >= 0
> +            ? this.data[this.selectedIndex]
> +            : null;
> +    };
> +
> +    var startResizing = function(container, event) {
> +        var grid = event.data.grid;
> +        kimchi.widget.Grid.beingResized = grid;
> +        if(!($('body').hasClass('resizing')
> +                && $(grid.resizer).hasClass('hidden'))) {
> +            return;
> +        }
> +
> +        grid.columnBeingResized = container;
> +        var pageX = event.pageX;
> +        var gridOffsetX = grid.domNode.offset()['left'];
> +        var leftmostOffsetX = $(container).offset()['left'] - gridOffsetX;
> +        var left = pageX - gridOffsetX;
> +        var contentHeight = $('.grid-content', grid.domNode).height();
> +        $(grid.resizerLeftmost).css({
> +            left: leftmostOffsetX + 'px',
> +            height: contentHeight + 'px'
> +        });
> +        $(grid.resizer).css({
> +            left: left + 'px',
> +            height: contentHeight + 'px'
> +        });
> +        $(grid.resizerLeftmost).removeClass('hidden');
> +        $(grid.resizer).removeClass('hidden');
> +        event.preventDefault();
> +    };
> +
> +    var endResizing = function(event) {
> +        var grid = kimchi.widget.Grid.beingResized;
> +        if(!$('body').hasClass('resizing')) {
> +            return;
> +        }
> +        $(grid.resizerLeftmost).addClass('hidden');
> +        $(grid.resizer).addClass('hidden');
> +        $('body').removeClass('resizing');
> +        var leftmostOffset = $(grid.columnBeingResized).offset()['left'];
> +        var left = event.pageX;
> +        if(leftmostOffset > left) {
> +            return;
> +        }
> +        resizeColumnWidth.call(
> +            grid,
> +            $(grid.columnBeingResized).index(),
> +            left - leftmostOffset
> +        );
> +        fixTableLayout.call(grid);
> +        grid.columnBeingResized = null;
> +        kimchi.widget.Grid.beingResized = null;
> +    };
> +
> +    var resizeColumnWidth = function(index, width) {
> +        var width = Math.ceil(width);
> +        var widthArray = [];
> +        var totalWidth = 0;
> +        var header = this.headerContainer;
> +        var body = this.bodyContainer;
> +        if(this.containerBeingResized === CONTAINER_FROZEN) {
> +            header = this.frozenHeaderContainer;
> +            body = this.frozenBodyContainer;
> +        }
> +        $('col', header).each(function(i, colNode) {
> +            var w = index === i ? width : $(colNode).width();
> +            widthArray.push(w);
> +            totalWidth += w;
> +        });
> +        $.each([header, body], function(i, container) {
> +            container.css({
> +                'table-layout': 'fixed',
> +                width: totalWidth + 'px'
> +            });
> +            $('col:nth-child(' + (index + 1) + ')', container).css({
> +                width: width + 'px'
> +            });
> +        });
> +
> +        if(this.containerBeingResized === CONTAINER_FROZEN) {
> +            var headerView = $('.grid-header-view', this.domNode);
> +            var bodyView = $('.grid-body-view', this.domNode);
> +            $.each([headerView, bodyView], function(i, view) {
> +                view.css({
> +                    left: totalWidth + 'px'
> +                });
> +            });
> +        }
> +    };
> +
> +    var positionResizer = function(event) {
> +        var grid = event.data.grid;
> +        if($(grid.resizer).hasClass('hidden')) {
> +            return;
> +        }
> +
> +        var pageX = event.pageX;
> +        var gridOffsetX = $(grid.domNode).offset()['left'];
> +        var leftMost = $(grid.resizerLeftmost).position()['left'];
> +        var offsetX = pageX - gridOffsetX;
> +        offsetX = offsetX >= leftMost ? offsetX : leftMost;
> +        $(grid.resizer).css('left', offsetX + 'px');
> +    };
> +
> +    var showMessage = function(msg) {
> +        $('.detailed-text', this.messageNode).text(msg);
> +        $(this.messageNode).removeClass('hidden');
> +    };
> +
> +    var hideMessage = function() {
> +        $(this.messageNode).addClass('hidden');
> +    };
> +
> +    var reload = function() {
> +        var data = this['opts']['data'];
> +        if(!data) {
> +            return;
> +        }
> +
> +        $(this.messageNode).addClass('hidden');
> +
> +        if($.isArray(data)) {
> +            return this.setData(data);
> +        }
> +
> +        if($.isFunction(data)) {
> +            var loadData = data;
> +            $(this.maskNode).removeClass('hidden');
> +            loadData($.proxy(function(data) {
> +                this.setData(data);
> +                $(this.maskNode).addClass('hidden');
> +            }, this));
> +        }
> +    };
> +
> +    var destroy = function() {
> +        $('body').off('mousemove.grid#' + this['opts']['id'], positionResizer);
> +        $('body').off('mouseup.grid#' + this['opts']['id'], endResizing);
> +    };
> +
> +    var createDOM = function() {
> +        var containerID = this['opts']['container'];
> +        var container = $('#' + containerID);
> +        var gridID = this['opts']['id'];
> +        var rowSelection = this['opts']['rowSelection'] || 'single';
> +        var domNode = $(wok.substitute(htmlStr, {
> +            id: gridID,
> +            loading: i18n['GGBGRD6001M'],
> +            message: i18n['GGBGRD6002M'],
> +            buttonLabel: i18n['GGBGRD6003M'],
> +            detailedLabel: i18n['GGBGRD6004M']
> +        })).appendTo(container);
> +        this.domNode = domNode;
> +
> +        var height = domNode.height();
> +        var width = domNode.width();
> +
> +        var title = this['opts']['title'];
> +        var titleNode = null;
> +        if(title) {
> +            titleNode = $('<div class="grid-caption">' + title + '</div>')
> +                .prependTo(domNode);
> +        }
> +
> +        var toolbarButtons = this['opts']['toolbarButtons'];
> +        var toolbarNode = null;
> +        if(toolbarButtons) {
> +            toolbarNode = $('<div class="grid-toolbar"></div>');
> +            if(titleNode) {
> +                titleNode.after(toolbarNode);
> +            }
> +            else {
> +                toolbarNode.prependTo(domNode);
> +            }
> +
> +            $.each(toolbarButtons, function(i, button) {
> +                var btnHTML = [
> +                    '<button',
> +                        button['id'] ? (' id="' + button['id'] + '"') : '',
> +                        ' class="grid-toolbar-button',
> +                            button['class'] ? (' ' + button['class']) : '',
> +                            '"',
> +                            button['disabled'] === true ? ' disabled' : '',
> +                            '>',
> +                            button['label'],
> +                    '</button>'
> +                ].join('');
> +                var btnNode = $(btnHTML).appendTo(toolbarNode);
> +                button['onClick'] &&
> +                    btnNode.on('click', button['onClick']);
> +            });
> +        }
> +
> +        var frozenHeaderContainer = $('.grid-frozen-header-container', domNode);
> +        var frozenBodyContainer = $('.grid-frozen-body-container', domNode);
> +        var frozenWidth = setupHeaders(
> +                frozenHeaderContainer,
> +                frozenBodyContainer,
> +                this['opts']['frozenFields']
> +        );
> +        this.frozenHeaderContainer = frozenHeaderContainer;
> +        this.frozenBodyContainer = frozenBodyContainer;
> +
> +        var headerContainer = $('.grid-header-container', domNode);
> +        var bodyContainer = $('.grid-body-container', domNode);
> +        setupHeaders(headerContainer, bodyContainer, this['opts']['fields']);
> +        this.headerContainer = headerContainer;
> +        this.bodyContainer = bodyContainer;
> +
> +        fixTableLayout.call(this, 'auto');
> +
> +        var gridContentNode = $('.grid-content', domNode);
> +        var captionHeight = titleNode && $(titleNode).height() || 0;
> +        var toolbarHeight = toolbarNode && $(toolbarNode).height() || 0;
> +        gridContentNode.css('top', (captionHeight + toolbarHeight) + 'px');
> +
> +        var maskNode = $('.grid-mask', domNode);
> +        maskNode.css('top', captionHeight + 'px');
> +        this.maskNode = maskNode;
> +
> +        var messageNode = $('.grid-message', domNode);
> +        messageNode.css('top', captionHeight + 'px');
> +        this.messageNode = messageNode;
> +
> +        var headerView = $('.grid-header-view', domNode);
> +        var bodyView = $('.grid-body-view', domNode);
> +        headerView.css('left', (frozenWidth) + 'px');
> +        bodyView.css('left', (frozenWidth) + 'px');
> +
> +        var bodyWidth = width - frozenWidth;
> +        headerContainer.css('width', bodyWidth + 'px');
> +        bodyContainer.css('width', bodyWidth + 'px');
> +
> +        fixTableLayout.call(this);
> +
> +        var gridBody = $('.grid-body', domNode);
> +        this.gridBody = gridBody;
> +        this.resizerLeftmost = $('.grid-resizer-leftmost', domNode);
> +        this.resizer = $('.grid-resizer', domNode);
> +        var gridHeader = $('.grid-header', domNode);
> +        $('th', gridHeader).on('mouseover mousemove', {
> +            resizer: this.resizer
> +        }, initResizing);
> +
> +        $('th', gridHeader).on('mouseout', {
> +            resizer: this.resizer
> +        }, clearResizing);
> +
> +        this.containerBeingResized = CONTAINER_NORMAL;
> +        $('th', frozenHeaderContainer).on('mousedown', {
> +            grid: this
> +        }, function(event) {
> +                event.data.grid.containerBeingResized = CONTAINER_FROZEN;
> +                startResizing(this, event);
> +        });
> +        $('th', headerContainer).on('mousedown', {
> +            grid: this
> +        }, function(event) {
> +                event.data.grid.containerBeingResized = CONTAINER_NORMAL;
> +                startResizing(this, event);
> +        });
> +
> +        $('body').on('mousemove.grid#' + this['opts']['id'], {
> +            grid: this
> +        }, positionResizer);
> +        $('body').on('mouseup.grid#' + this['opts']['id'], endResizing);
> +
> +        var data = this['opts']['data'];
> +
> +        $('.retry-button', domNode).on('click', {
> +            grid: this
> +        }, function(event) {
> +            event.data.grid.reload();
> +        });
> +    };
> +
> +    return {
> +        opts: {
> +            container: null,
> +            id: null,
> +            rowSelection: 'single',
> +            onRowSelected: null,
> +            title: null,
> +            toolbarButtons: null,
> +            frozenFields: null,
> +            fields: null
> +        },
> +        createDOM: createDOM,
> +        setData: setData,
> +        getSelected: getSelected,
> +        reload: reload,
> +        destroy: destroy,
> +        showMessage: showMessage
> +    };
> +})();
> diff --git a/plugins/gingerbase/ui/js/src/gingerbase.host.js b/plugins/gingerbase/ui/js/src/gingerbase.host.js
> new file mode 100644
> index 0000000..989461c
> --- /dev/null
> +++ b/plugins/gingerbase/ui/js/src/gingerbase.host.js
> @@ -0,0 +1,859 @@
> +/*
> + * Project Kimchi
> + *
> + * Copyright IBM, Corp. 2013-2014
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +kimchi.host={};
> +
> +kimchi.host_main = function() {
> +    var expand = function(header, toExpand) {
> +        var controlledNode = $(header).attr('aria-controls');
> +        $('#' + controlledNode)[toExpand ? 'removeClass' : 'addClass']('hidden');
> +        $(header).attr('aria-expanded', toExpand ? 'true' : 'false');
> +    };
> +
> +    var repositoriesGrid = null;
> +    var initRepositoriesGrid = function(repo_type) {
> +        var gridFields=[];
> +        if (repo_type == "yum") {
> +                gridFields=[{
> +                    name: 'repo_id',
> +                    label: i18n['GGBREPO6004M'],
> +                    'class': 'repository-id'
> +                }, {
> +                    name: 'config[repo_name]',
> +                    label: i18n['GGBREPO6005M'],
> +                    'class': 'repository-name'
> +                }, {
> +                    name: 'enabled',
> +                    label: i18n['GGBREPO6009M'],
> +                    'class': 'repository-enabled'
> +                }];
> +        }
> +        else if (repo_type == "deb") {
> +                gridFields=[{
> +                    name: 'baseurl',
> +                    label: i18n['GGBREPO6006M'],
> +                    makeTitle: true,
> +                    'class': 'repository-baseurl deb'
> +                }, {
> +                    name: 'enabled',
> +                    label: i18n['GGBREPO6009M'],
> +                    'class': 'repository-enabled deb'
> +                }, {
> +                    name: 'config[dist]',
> +                    label: "dist",
> +                    'class': 'repository-gpgcheck deb'
> +                }, {
> +                    name: 'config[comps]',
> +                    label: "comps",
> +                    'class': 'repository-gpgcheck deb'
> +                }];
> +        }
> +        else {
> +            gridFields=[{
> +                name: 'repo_id',
> +                label: i18n['GGBREPO6004M'],
> +                'class': 'repository-id'
> +                }, {
> +                    name: 'enabled',
> +                    label: i18n['GGBREPO6009M'],
> +                    'class': 'repository-enabled'
> +                }, {
> +                    name: 'baseurl',
> +                    label: i18n['GGBREPO6006M'],
> +                    makeTitle: true,
> +                    'class': 'repository-baseurl'
> +                }];
> +        }
> +        repositoriesGrid = new kimchi.widget.Grid({
> +            container: 'repositories-grid-container',
> +            id: 'repositories-grid',
> +            title: i18n['GGBREPO6003M'],
> +            toolbarButtons: [{
> +                id: 'repositories-grid-add-button',
> +                label: i18n['GGBREPO6012M'],
> +                onClick: function(event) {
> +                    wok.window.open({url:'plugins/gingerbase/repository-add.html',
> +                                    class: repo_type});
> +                }
> +            }, {
> +                id: 'repositories-grid-enable-button',
> +                label: i18n['GGBREPO6016M'],
> +                disabled: true,
> +                onClick: function(event) {
> +                    var repository = repositoriesGrid.getSelected();
> +                    if(!repository) {
> +                        return;
> +                    }
> +                    var name = repository['repo_id'];
> +                    var enable = !repository['enabled'];
> +                    $(this).prop('disabled', true);
> +                    kimchi.enableRepository(name, enable, function() {
> +                        wok.topic('kimchi/repositoryUpdated').publish();
> +                    });
> +                }
> +            }, {
> +                id: 'repositories-grid-edit-button',
> +                label: i18n['GGBREPO6013M'],
> +                disabled: true,
> +                onClick: function(event) {
> +                    var repository = repositoriesGrid.getSelected();
> +                    if(!repository) {
> +                        return;
> +                    }
> +                    kimchi.selectedRepository = repository['repo_id'];
> +                    wok.window.open({url:'plugins/gingerbase/repository-edit.html',
> +                                    class: repo_type});
> +                }
> +            }, {
> +                id: 'repositories-grid-remove-button',
> +                label: i18n['GGBREPO6014M'],
> +                disabled: true,
> +                onClick: function(event) {
> +                    var repository = repositoriesGrid.getSelected();
> +                    if(!repository) {
> +                        return;
> +                    }
> +
> +                    var settings = {
> +                        title : i18n['GGBREPO6001M'],
> +                        content : i18n['GGBREPO6002M'],
> +                        confirm : i18n['GGBAPI6004M'],
> +                        cancel : i18n['GGBAPI6003M']
> +                    };
> +
> +                    wok.confirm(settings, function() {
> +                        kimchi.deleteRepository(
> +                            repository['repo_id'],
> +                            function(result) {
> +                                wok.topic('kimchi/repositoryDeleted').publish(result);
> +                            }, function(error) {
> +                            }
> +                        );
> +                    });
> +                }
> +            }],
> +            onRowSelected: function(row) {
> +                var repository = repositoriesGrid.getSelected();
> +                if(!repository) {
> +                    return;
> +                }
> +                $('#repositories-grid-remove-button').prop('disabled', false);
> +                $('#repositories-grid-edit-button').prop('disabled', false);
> +                var enabled = repository['enabled'];
> +                $('#repositories-grid-enable-button')
> +                    .text(i18n[enabled ? 'GGBREPO6017M' : 'GGBREPO6016M'])
> +                    .prop('disabled', false);
> +            },
> +            frozenFields: [],
> +            fields: gridFields,
> +            data: listRepositories
> +        });
> +    };
> +
> +    var listRepositories = function(gridCallback) {
> +        kimchi.listRepositories(function(repositories) {
> +            if($.isFunction(gridCallback)) {
> +                gridCallback(repositories);
> +            }
> +            else {
> +                if(repositoriesGrid) {
> +                    repositoriesGrid.setData(repositories);
> +                }
> +                else {
> +                    initRepositoriesGrid();
> +                    repositoriesGrid.setData(repositories);
> +                }
> +            }
> +        },
> +        function(error) {
> +            var message = error && error['responseJSON'] && error['responseJSON']['reason'];
> +
> +            if($.isFunction(gridCallback)) {
> +                gridCallback([]);
> +            }
> +            repositoriesGrid &&
> +                repositoriesGrid.showMessage(message || i18n['GGBUPD6008M']);
> +        });
> +
> +        $('#repositories-grid-remove-button').prop('disabled', true);
> +        $('#repositories-grid-edit-button').prop('disabled', true);
> +        $('#repositories-grid-enable-button').prop('disabled', true);
> +    };
> +
> +    var softwareUpdatesGridID = 'software-updates-grid';
> +    var softwareUpdatesGrid = null;
> +    var progressAreaID = 'software-updates-progress-textarea';
> +    var reloadProgressArea = function(result) {
> +        var progressArea = $('#' + progressAreaID)[0];
> +        $(progressArea).text(result['message']);
> +        var scrollTop = $(progressArea).prop('scrollHeight');
> +        $(progressArea).prop('scrollTop', scrollTop);
> +    };
> +
> +    var initSoftwareUpdatesGrid = function(softwareUpdates) {
> +        softwareUpdatesGrid = new kimchi.widget.Grid({
> +            container: 'software-updates-grid-container',
> +            id: softwareUpdatesGridID,
> +            title: i18n['GGBUPD6001M'],
> +            rowSelection: 'disabled',
> +            toolbarButtons: [{
> +                id: softwareUpdatesGridID + '-update-button',
> +                label: i18n['GGBUPD6006M'],
> +                disabled: true,
> +                onClick: function(event) {
> +                    var updateButton = $(this);
> +                    var progressArea = $('#' + progressAreaID)[0];
> +                    $('#software-updates-progress-container').removeClass('hidden');
> +                    $(progressArea).text('');
> +                    !wok.isElementInViewport(progressArea) &&
> +                        progressArea.scrollIntoView();
> +                    $(updateButton).text(i18n['GGBUPD6007M']).prop('disabled', true);
> +
> +                    kimchi.updateSoftware(function(result) {
> +                        reloadProgressArea(result);
> +                        $(updateButton).text(i18n['GGBUPD6006M']).prop('disabled', false);
> +                        wok.topic('kimchi/softwareUpdated').publish({
> +                            result: result
> +                        });
> +                    }, function(error) {
> +                        var message = error && error['responseJSON'] && error['responseJSON']['reason'];
> +                        wok.message.error(message || i18n['GGBUPD6009M']);
> +                        $(updateButton).text(i18n['GGBUPD6006M']).prop('disabled', false);
> +                    }, reloadProgressArea);
> +                }
> +            }],
> +            frozenFields: [],
> +            fields: [{
> +                name: 'package_name',
> +                label: i18n['GGBUPD6002M'],
> +                'class': 'software-update-name'
> +            }, {
> +                name: 'version',
> +                label: i18n['GGBUPD6003M'],
> +                'class': 'software-update-version'
> +            }, {
> +                name: 'arch',
> +                label: i18n['GGBUPD6004M'],
> +                'class': 'software-update-arch'
> +            }, {
> +                name: 'repository',
> +                label: i18n['GGBUPD6005M'],
> +                'class': 'software-update-repos'
> +            }],
> +            data: listSoftwareUpdates
> +        });
> +    };
> +
> +    var listSoftwareUpdates = function(gridCallback) {
> +        kimchi.listSoftwareUpdates(function(softwareUpdates) {
> +            if($.isFunction(gridCallback)) {
> +                gridCallback(softwareUpdates);
> +            }
> +            else {
> +                if(softwareUpdatesGrid) {
> +                    softwareUpdatesGrid.setData(softwareUpdates);
> +                }
> +                else {
> +                    initSoftwareUpdatesGrid(softwareUpdates);
> +                }
> +            }
> +
> +            var updateButton = $('#' + softwareUpdatesGridID + '-update-button');
> +            $(updateButton).prop('disabled', softwareUpdates.length === 0);
> +        }, function(error) {
> +            var message = error && error['responseJSON'] && error['responseJSON']['reason'];
> +            if($.isFunction(gridCallback)) {
> +                gridCallback([]);
> +            }
> +            softwareUpdatesGrid &&
> +                softwareUpdatesGrid.showMessage(message || i18n['GGBUPD6008M']);
> +        });
> +    };
> +
> +    var reportGridID = 'available-reports-grid';
> +    var reportGrid = null;
> +    var enableReportButtons = function(toEnable) {
> +        var buttonID = '#{grid}-{btn}-button';
> +        $.each(['rename', 'remove', 'download'], function(i, n) {
> +            $(wok.substitute(buttonID, {
> +                grid: reportGridID,
> +                btn: n
> +            })).prop('disabled', !toEnable);
> +        });
> +    };
> +    var initReportGrid = function(reports) {
> +        reportGrid = new kimchi.widget.Grid({
> +            container: 'available-reports-grid-container',
> +            id: reportGridID,
> +            title: i18n['GGBDR6002M'],
> +            toolbarButtons: [{
> +                id: reportGridID + '-generate-button',
> +                label: i18n['GGBDR6006M'],
> +                onClick: function(event) {
> +                    wok.window.open('plugins/gingerbase/report-add.html');
> +                }
> +            }, {
> +                id: reportGridID + '-rename-button',
> +                label: i18n['GGBDR6008M'],
> +                disabled: true,
> +                onClick: function(event) {
> +                    var report = reportGrid.getSelected();
> +                    if(!report) {
> +                        return;
> +                    }
> +
> +                    kimchi.selectedReport = report['name'];
> +                    wok.window.open('plugins/gingerbase/report-rename.html');
> +                }
> +            }, {
> +                id: reportGridID + '-remove-button',
> +                label: i18n['GGBDR6009M'],
> +                disabled: true,
> +                onClick: function(event) {
> +                    var report = reportGrid.getSelected();
> +                    if(!report) {
> +                        return;
> +                    }
> +
> +                    var settings = {
> +                        title : i18n['GGBAPI6004M'],
> +                        content : i18n['GGBDR6001M'],
> +                        confirm : i18n['GGBAPI6002M'],
> +                        cancel : i18n['GGBAPI6003M']
> +                    };
> +
> +                    wok.confirm(settings, function() {
> +                        kimchi.deleteReport({
> +                            name: report['name']
> +                        }, function(result) {
> +                            listDebugReports();
> +                        }, function(error) {
> +                           wok.message.error(error.responseJSON.reason);
> +                        });
> +                    });
> +                }
> +            }, {
> +                id: reportGridID + '-download-button',
> +                label: i18n['GGBDR6010M'],
> +                disabled: true,
> +                onClick: function(event) {
> +                    var report = reportGrid.getSelected();
> +                    if(!report) {
> +                        return;
> +                    }
> +
> +                    kimchi.downloadReport({
> +                        file: report['uri']
> +                    });
> +                }
> +            }],
> +            onRowSelected: function(row) {
> +                var report = reportGrid.getSelected();
> +                // Only enable report buttons if the selected line is not a
> +                // pending report
> +                if (report['time'] == i18n['GGBDR6007M']) {
> +                    var gridElement = $('#'+ reportGridID);
> +                    var row = $('tr:contains(' + report['name'] + ')', gridElement);
> +                    enableReportButtons(false);
> +                    row.attr('class', '');
> +                }
> +                else {
> +                    enableReportButtons(true);
> +                }
> +            },
> +            frozenFields: [],
> +            fields: [{
> +                name: 'name',
> +                label: i18n['GGBDR6003M'],
> +                'class': 'debug-report-name'
> +            }, {
> +                name: 'time',
> +                label: i18n['GGBDR6005M'],
> +                'class': 'debug-report-time'
> +            }],
> +            data: reports
> +        });
> +    };
> +
> +    var getPendingReports = function() {
> +        var reports = []
> +        var filter = 'status=running&target_uri=' + encodeURIComponent('^/plugins/gingerbase/debugreports/*')
> +
> +        kimchi.getTasksByFilter(filter, function(tasks) {
> +            for(var i = 0; i < tasks.length; i++) {
> +                reportName = tasks[i].target_uri.replace(/^\/plugins\/gingerbase\/debugreports\//, '') || i18n['GGBDR6012M'];
> +                reports.push({'name': reportName, 'time': i18n['GGBDR6007M']})
> +
> +                if(kimchi.trackingTasks.indexOf(tasks[i].id) >= 0) {
> +                    continue;
> +                }
> +
> +                kimchi.trackTask(tasks[i].id, function(result) {
> +                    wok.topic('kimchi/debugReportAdded').publish();
> +                }, function(result) {
> +                    // Error message from Async Task status
> +                    if (result['message']) {
> +                        var errText = result['message'];
> +                    }
> +                    // Error message from standard kimchi exception
> +                    else {
> +                        var errText = result['responseJSON']['reason'];
> +                    }
> +                    result && wok.message.error(errText);
> +                    wok.topic('kimchi/debugReportAdded').publish();
> +                }, null);
> +            }
> +        }, null, true);
> +
> +        return reports;
> +    };
> +
> +    var listDebugReports = function() {
> +        kimchi.listReports(function(reports) {
> +            pendingReports = getPendingReports();
> +            allReports = pendingReports.concat(reports);
> +            $('#debug-report-section').removeClass('hidden');
> +
> +            // Row selection will be cleared so disable buttons here
> +            enableReportButtons(false);
> +
> +            if(reportGrid) {
> +                reportGrid.setData(allReports);
> +            }
> +            else {
> +                initReportGrid(allReports);
> +            }
> +
> +            // Set id-debug-img to pending reports
> +            // It will display a loading icon
> +            var gridElement = $('#' + reportGridID);
> +                $.each($('td:contains(' + i18n['GGBDR6007M']  + ')', gridElement), function(index, row) {
> +                $(row).parent().addClass('no-hover');
> +                $(row).attr('id', 'id-debug-img');
> +            });
> +        }, function(error) {
> +            if(error['status'] == 403) {
> +                $('#debug-report-section').addClass('hidden');
> +                return;
> +            }
> +            $('#debug-report-section').removeClass('hidden');
> +        });
> +    };
> +
> +    var shutdownButtonID = '#host-button-shutdown';
> +    var restartButtonID = '#host-button-restart';
> +    var shutdownHost = function(params) {
> +        var settings = {
> +            title : i18n['GGBAPI6004M'],
> +            content : i18n['GGBHOST6008M'],
> +            confirm : i18n['GGBAPI6002M'],
> +            cancel : i18n['GGBAPI6003M']
> +        };
> +
> +        wok.confirm(settings, function() {
> +            kimchi.shutdown(params);
> +            $(shutdownButtonID).prop('disabled', true);
> +            $(restartButtonID).prop('disabled', true);
> +            // Check if there is any VM is running.
> +            // FIXME : Find alternative way to figure out if any vms running
> +            // kimchi.listVMs(function(vms) {
> +            //     for(var i = 0; i < vms.length; i++) {
> +            //         if(vms[i]['state'] === 'running') {
> +            //             wok.message.error.code('GGBHOST6001E');
> +            //             $(shutdownButtonID).prop('disabled', false);
> +            //             $(restartButtonID).prop('disabled', false);
> +            //             return;
> +            //         }
> +            //     }
> +            //
> +            // });
> +        }, function() {
> +        });
> +    };
> +
> +    var initPage = function() {
> +        $('#host-info-container .section-header').each(function(i, header) {
> +            $('<span class="arrow"></span>').prependTo(header);
> +            var toExpand = $(header).attr('aria-expanded') !== 'false';
> +            expand(header, toExpand);
> +        });
> +
> +        $('#host-info-container').on('click', '.section-header', function(event) {
> +            var toExpand = $(this).attr('aria-expanded') === 'false';
> +            expand(this, toExpand);
> +        });
> +
> +        $('#host-button-shutdown').on('click', function(event) {
> +            shutdownHost(null);
> +        });
> +
> +        $('#host-button-restart').on('click', function(event) {
> +            shutdownHost({
> +                reboot: true
> +            });
> +        });
> +
> +        var setupUI = function() {
> +            if (kimchi.capabilities == undefined) {
> +                setTimeout(setupUI, 2000);
> +                return;
> +            }
> +
> +            if((kimchi.capabilities['repo_mngt_tool']) && (kimchi.capabilities['repo_mngt_tool']!="None")) {
> +                initRepositoriesGrid(kimchi.capabilities['repo_mngt_tool']);
> +                $('#repositories-section').switchClass('hidden', kimchi.capabilities['repo_mngt_tool']);
> +                wok.topic('kimchi/repositoryAdded')
> +                    .subscribe(listRepositories);
> +                wok.topic('kimchi/repositoryUpdated')
> +                    .subscribe(listRepositories);
> +                wok.topic('kimchi/repositoryDeleted')
> +                    .subscribe(listRepositories);
> +            }
> +
> +            if(kimchi.capabilities['update_tool']) {
> +                $('#software-update-section').removeClass('hidden');
> +                initSoftwareUpdatesGrid();
> +                wok.topic('kimchi/softwareUpdated')
> +                    .subscribe(listSoftwareUpdates);
> +                $('#software-updates-progress-container').accordion({
> +                    collapsible: true
> +                });
> +            }
> +
> +            if(kimchi.capabilities['system_report_tool']) {
> +                listDebugReports();
> +                wok.topic('kimchi/debugReportAdded')
> +                    .subscribe(listDebugReports);
> +                wok.topic('kimchi/debugReportRenamed')
> +                    .subscribe(listDebugReports);
> +            }
> +        };
> +        setupUI();
> +    };
> +
> +    kimchi.getHost(function(data) {
> +        var htmlTmpl = $('#host-tmpl').html();
> +        data['logo'] = data['logo'] || '';
> +        data['memory'] = wok.formatMeasurement(data['memory'], {
> +            fixed: 2
> +        });
> +        var templated = wok.substitute(htmlTmpl, data);
> +        $('#host-content-container').html(templated);
> +
> +        initPage();
> +        initTracker();
> +    });
> +
> +    var StatsMgr = function() {
> +        var statsArray = {
> +            cpu: {
> +                u: {
> +                    type: 'percent',
> +                    legend: i18n['GGBHOST6002M'],
> +                    points: []
> +                }
> +            },
> +            memory: {
> +                u: {
> +                    type: 'value',
> +                    base: 2,
> +                    fixed: 2,
> +                    legend: i18n['GGBHOST6003M'],
> +                    points: []
> +                }
> +            },
> +            diskIO: {
> +                r: {
> +                    type: 'value',
> +                    base: 2,
> +                    fixed: 2,
> +                    unit: 'B/s',
> +                    legend: i18n['GGBHOST6004M'],
> +                    points: []
> +                },
> +                w: {
> +                    type: 'value',
> +                    base: 2,
> +                    fixed: 2,
> +                    unit: 'B/s',
> +                    legend: i18n['GGBHOST6005M'],
> +                    'class': 'disk-write',
> +                    points: []
> +                }
> +            },
> +            networkIO: {
> +                r: {
> +                    type: 'value',
> +                    base: 2,
> +                    fixed: 2,
> +                    unit: 'B/s',
> +                    legend: i18n['GGBHOST6006M'],
> +                    points: []
> +                },
> +                s: {
> +                    type: 'value',
> +                    base: 2,
> +                    fixed: 2,
> +                    unit: 'B/s',
> +                    legend: i18n['GGBHOST6007M'],
> +                    'class': 'network-sent',
> +                    points: []
> +                }
> +            }
> +        };
> +        var SIZE = 20;
> +        var cursor = SIZE;
> +
> +        var add = function(stats) {
> +            for(var key in stats) {
> +                var item = stats[key];
> +                for(var metrics in item) {
> +                    var value = item[metrics]['v'];
> +                    var max = item[metrics]['max'];
> +                    var unifiedMetrics = statsArray[key][metrics];
> +                    var ps = unifiedMetrics['points'];
> +                    if(!Array.isArray(value)){
> +                        ps.push(value);
> +                        if(ps.length > SIZE + 1) {
> +                            ps.shift();
> +                        }
> +                    }
> +                    else{
> +                        ps=ps.concat(value);
> +                        ps.splice(0, ps.length-SIZE-1);
> +                        unifiedMetrics['points']=ps;
> +                    }
> +                    if(max !== undefined) {
> +                        unifiedMetrics['max'] = max;
> +                    }
> +                    else {
> +                        if(unifiedMetrics['type'] !== 'value') {
> +                            continue;
> +                        }
> +                        max = -Infinity;
> +                        $.each(ps, function(i, value) {
> +                            if(value > max) {
> +                                max = value;
> +                            }
> +                        });
> +                        if(max === 0) {
> +                            ++max;
> +                        }
> +                        max *= 1.1;
> +                        unifiedMetrics['max'] = max;
> +                    }
> +                }
> +            }
> +            cursor++;
> +        };
> +
> +        var get = function(which) {
> +            var stats = statsArray[which];
> +            var lines = [];
> +            for(var k in stats) {
> +                var obj = stats[k];
> +                var line = {
> +                    type: obj['type'],
> +                    base: obj['base'],
> +                    unit: obj['unit'],
> +                    fixed: obj['fixed'],
> +                    legend: obj['legend']
> +                };
> +                if(obj['max']) {
> +                    line['max'] = obj['max'];
> +                }
> +                if(obj['class']) {
> +                    line['class'] = obj['class'];
> +                }
> +                var ps = obj['points'];
> +                var numStats = ps.length;
> +                var unifiedPoints = [];
> +                $.each(ps, function(i, value) {
> +                    unifiedPoints.push({
> +                        x: cursor - numStats + i,
> +                        y: value
> +                    });
> +                });
> +                line['points'] = unifiedPoints;
> +                lines.push(line);
> +            }
> +            return lines;
> +        };
> +
> +        return {
> +            add: add,
> +            get: get
> +        };
> +    };
> +
> +    var Tracker = function(charts) {
> +      var charts = charts;
> +      var timer = null;
> +      var statsPool = new StatsMgr();
> +      var setCharts = function(newCharts) {
> +          charts = newCharts;
> +          for(var key in charts) {
> +              var chart = charts[key];
> +              chart.updateUI(statsPool.get(key));
> +          }
> +      };
> +
> +      var self = this;
> +
> +      var UnifyStats = function(stats) {
> +          var result= {
> +              cpu: {
> +                  u: {
> +                      v: stats['cpu_utilization']
> +                  }
> +              },
> +              memory: {
> +                  u: {
> +                  }
> +              },
> +              diskIO: {
> +                  r: {
> +                      v: stats['disk_read_rate']
> +                  },
> +                  w: {
> +                      v: stats['disk_write_rate']
> +                  }
> +              },
> +              networkIO: {
> +                  r: {
> +                      v: stats['net_recv_rate']
> +                  },
> +                  s: {
> +                      v: stats['net_sent_rate']
> +                  }
> +              }
> +          };
> +          if(Array.isArray(stats['memory'])){
> +              result.memory.u['v']=[];
> +              result.memory.u['max']=-Infinity;
> +              for(var i=0;i<stats['memory'].length;i++){
> +                  result.memory.u['v'].push(stats['memory'][i]['avail']);
> +                  result.memory.u['max']=Math.max(result.memory.u['max'],stats['memory'][i]['total']);
> +              }
> +          }
> +          else {
> +              result.memory.u['v']=stats['memory']['avail'],
> +              result.memory.u['max']=stats['memory']['total']
> +          }
> +          return(result);
> +      };
> +
> +
> +      var statsCallback = function(stats) {
> +              var unifiedStats = UnifyStats(stats);
> +              statsPool.add(unifiedStats);
> +              for(var key in charts) {
> +                  var chart = charts[key];
> +                  chart.updateUI(statsPool.get(key));
> +              }
> +              timer = setTimeout(function() {
> +                  continueTrack();
> +              }, 1000);
> +          };
> +
> +      var track = function() {
> +          kimchi.getHostStatsHistory(statsCallback,
> +            function() {
> +                continueTrack();
> +            });
> +      };
> +
> +      var continueTrack = function() {
> +          kimchi.getHostStats(statsCallback,
> +            function() {
> +                continueTrack();
> +            });
> +      };
> +
> +      var destroy = function() {
> +          timer && clearTimeout(timer);
> +          timer = null;
> +      };
> +
> +      return {
> +        setCharts: setCharts,
> +        start: track,
> +        stop: destroy
> +      };
> +    };
> +
> +    var initTracker = function() {
> +        // TODO: Extend tabs with onUnload event to unregister timers.
> +        if(kimchi.hostTimer) {
> +            kimchi.hostTimer.stop();
> +            delete kimchi.hostTimer;
> +        }
> +
> +        var trackedCharts = {
> +            cpu: new kimchi.widget.LineChart({
> +                id: 'chart-cpu',
> +                node: 'container-chart-cpu',
> +                type: 'percent'
> +            }),
> +            memory: new kimchi.widget.LineChart({
> +                id: 'chart-memory',
> +                node: 'container-chart-memory',
> +                type: 'value'
> +            }),
> +            diskIO: new kimchi.widget.LineChart({
> +                id: 'chart-disk-io',
> +                node: 'container-chart-disk-io',
> +                type: 'value'
> +            }),
> +            networkIO: new kimchi.widget.LineChart({
> +                id: 'chart-network-io',
> +                node: 'container-chart-network-io',
> +                type: 'value'
> +            })
> +        };
> +
> +        if(kimchi.hostTimer) {
> +            kimchi.hostTimer.setCharts(trackedCharts);
> +        }
> +        else {
> +            kimchi.hostTimer = new Tracker(trackedCharts);
> +            kimchi.hostTimer.start();
> +        }
> +    };
> +
> +    $('#host-root-container').on('remove', function() {
> +        if(kimchi.hostTimer) {
> +            kimchi.hostTimer.stop();
> +            delete kimchi.hostTimer;
> +            }
> +
> +        repositoriesGrid && repositoriesGrid.destroy();
> +        wok.topic('kimchi/repositoryAdded')
> +            .unsubscribe(listRepositories);
> +        wok.topic('kimchi/repositoryUpdated')
> +            .unsubscribe(listRepositories);
> +        wok.topic('kimchi/repositoryDeleted')
> +            .unsubscribe(listRepositories);
> +
> +        softwareUpdatesGrid && softwareUpdatesGrid.destroy();
> +        wok.topic('kimchi/softwareUpdated').unsubscribe(listSoftwareUpdates);
> +
> +        reportGrid && reportGrid.destroy();
> +        wok.topic('kimchi/debugReportAdded').unsubscribe(listDebugReports);
> +        wok.topic('kimchi/debugReportRenamed').unsubscribe(listDebugReports);
> +    });
> +};
> diff --git a/plugins/gingerbase/ui/js/src/gingerbase.line-chart.js b/plugins/gingerbase/ui/js/src/gingerbase.line-chart.js
> new file mode 100644
> index 0000000..13bbee1
> --- /dev/null
> +++ b/plugins/gingerbase/ui/js/src/gingerbase.line-chart.js
> @@ -0,0 +1,202 @@
> +/*
> + * Project Kimchi
> + *
> + * Copyright IBM, Corp. 2013-2014
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +
> +/**
> + * new kimchi.widget.LineChart({
> + *   node: 'line-chart-cpu',
> + *   id: 'line-chart',
> + *   type: 'value'
> + * });
> + */
> +kimchi.widget.LineChart = function(params) {
> +    var container = $('#' + params['node']);
> +    container.addClass('chart-container');
> +    var height = container.height();
> +    var width = container.width();
> +    var numHLines = 4;
> +    var linesSpace = height / numHLines;
> +    var period = params['period'] || 20;
> +    var xFactor = width / period;
> +    var yFactor = height / 100;
> +    var xStart = params['xStart'] || 0;
> +    var linesOffset = 0;
> +    var canvasID = params['id'];
> +    var maxValue = params['maxValue'] || -Infinity;
> +    var type = params['type'];
> +    var chartVAxis = null;
> +    var chartTitle = null;
> +    var chartLegend = null;
> +    var seriesMap = {};
> +    var formatSettings = {};
> +
> +    var setMaxValue = function(newValue) {
> +        maxValue = newValue;
> +    };
> +
> +    /**
> +     *
> +     * settings: {
> +     *   'class': 'disk-read-rate'
> +     * }
> +     */
> +    var updateUI = function(data) {
> +        var container = $('#' + params['node']);
> +        if(!container.length) {
> +            return;
> +        }
> +
> +        if(!$.isArray(data)) {
> +            data = [data];
> +        }
> +        var seriesCount = 0;
> +        var singleSeries = data.length === 1;
> +        var firstSeries = data[0];
> +
> +        // TODO: Multiple axes support.
> +        if(type === 'value') {
> +            $.each(data, function(i, series) {
> +                if(series['max'] > maxValue) {
> +                    maxValue = series['max'];
> +                    formatSettings = {
> +                        base: series['base'],
> +                        unit: series['unit'],
> +                        fixed: series['fixed']
> +                    };
> +                }
> +            });
> +        }
> +
> +        var canvasNode = $('#' + canvasID);
> +        canvasNode.length && canvasNode.remove();
> +        var htmlStr = [
> +          '<svg id="', canvasID, '" class="line-chart"',
> +              ' height="', height, '" width="', width, '"',
> +          '>',
> +            '<rect height="', height, '" width="', width, '" class="background" />'
> +        ];
> +
> +        for(var x = linesOffset; x < width; x += linesSpace) {
> +            htmlStr.push(
> +                '<line x1="', x, '" y1="', 0, '" x2="', x, '" y2="', height, '" />'
> +            );
> +        }
> +
> +        linesOffset -= xFactor;
> +        while(linesOffset < 0) {
> +            linesOffset = linesSpace + linesOffset;
> +        }
> +
> +        for(var y = height - linesSpace; y > 0; y -= linesSpace) {
> +            htmlStr.push(
> +                '<line x1="', 0, '" y1="', y, '" x2="', width, '" y2="', y, '" />'
> +            );
> +        }
> +
> +        var maxValueLabel = i18n['GGBHOST6001M'] + ' ' +
> +            (type === 'value'
> +                ? wok.formatMeasurement(maxValue, formatSettings)
> +                : '100%');
> +        if(!chartVAxis) {
> +            chartVAxis = $('<div class="chart-vaxis-container">' +
> +                maxValueLabel +
> +                '</div>'
> +            );
> +            container.before(chartVAxis);
> +        }
> +        else {
> +            chartVAxis.text(maxValueLabel);
> +        }
> +
> +        seriesNames = [];
> +        $.each(data, function(i, series) {
> +            var points = series['points'];
> +            var className = series['class'];
> +            var latestPoint = points.slice(-1).pop();
> +            xStart = latestPoint['x'] - period;
> +
> +            htmlStr.push('<polyline',
> +                ' class="series', className ? ' ' + className : '', '"',
> +                ' points="'
> +            );
> +            var first = true;
> +            $.each(points, function(i, point) {
> +                if(first) {
> +                    first = false;
> +                }
> +                else {
> +                    htmlStr.push(' ');
> +                }
> +
> +                var x = xFactor * (point['x'] - xStart);
> +                var y = height - yFactor * (type === 'value' ?
> +                    point['y'] * 100 / maxValue :
> +                    point['y']
> +                );
> +                htmlStr.push(x, ',', y);
> +            });
> +            htmlStr.push('" />');
> +        });
> +
> +        htmlStr.push('</svg>');
> +
> +        var canvasNode = $(htmlStr.join('')).appendTo(container);
> +
> +        if(!chartLegend) {
> +            chartLegend = $('<div class="chart-legend-container"></div>');
> +            container.after(chartLegend);
> +        }
> +        else {
> +            chartLegend.empty();
> +        }
> +        $('polyline.series', canvasNode).each(function(i, polyline) {
> +            var wrapper = $('<div class="legend-wrapper"></div>')
> +                .appendTo(chartLegend);
> +            $([
> +                '<svg class="legend-icon" width="20" height="10">',
> +                    '<line x1="0" y1="5" x2="20" y2="5"/>',
> +                '</svg>'
> +            ].join('')).appendTo(wrapper);
> +            $('line', wrapper).css({
> +                stroke: $(polyline).css('stroke'),
> +                'stroke-width': $(polyline).css('stroke-width')
> +            });
> +            var label = data[i]['legend'];
> +            var base = data[i]['base'];
> +            $('<label class="legend-label">' + label + '</label>')
> +                .appendTo(wrapper);
> +            var latestPoint = data[i]['points'].slice(-1).pop();
> +            var latestValue = latestPoint['y'];
> +            if(type === 'value') {
> +                latestValue = wok.formatMeasurement(
> +                    latestValue,
> +                    formatSettings
> +                );
> +            }
> +            else {
> +                latestValue += '%';
> +            }
> +            $('<div class="latest-value">' + latestValue + '</div>')
> +                .appendTo(wrapper);
> +        });
> +    };
> +
> +    return {
> +        setMaxValue: setMaxValue,
> +        updateUI: updateUI
> +    }
> +};
> diff --git a/plugins/gingerbase/ui/js/src/gingerbase.main.js b/plugins/gingerbase/ui/js/src/gingerbase.main.js
> new file mode 100644
> index 0000000..2fdeb85
> --- /dev/null
> +++ b/plugins/gingerbase/ui/js/src/gingerbase.main.js
> @@ -0,0 +1,26 @@
> +/*
> + * Project Kimchi
> + *
> + * Copyright IBM, Corp. 2013-2014
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +kimchi.capabilities = undefined;
> +kimchi.getCapabilities(function(result) {
> +    kimchi.capabilities = result;
> +
> +    if(kimchi.capabilities.federation=="on")
> +        $('#peers').removeClass('hide-content');
> +}, function() {
> +    kimchi.capabilities = {};
> +});
> diff --git a/plugins/gingerbase/ui/js/src/gingerbase.report_add_main.js b/plugins/gingerbase/ui/js/src/gingerbase.report_add_main.js
> new file mode 100644
> index 0000000..87010b1
> --- /dev/null
> +++ b/plugins/gingerbase/ui/js/src/gingerbase.report_add_main.js
> @@ -0,0 +1,72 @@
> +/*
> + * Project Kimchi
> + *
> + * Copyright IBM, Corp. 2013-2014
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +kimchi.report_add_main = function() {
> +    var reportGridID = 'available-reports-grid';
> +    var addReportForm = $('#form-report-add');
> +    var submitButton = $('#button-report-add');
> +    var nameTextbox = $('input[name="name"]', addReportForm);
> +    nameTextbox.select();
> +
> +    var submitForm = function(event) {
> +        if(submitButton.prop('disabled')) {
> +            return false;
> +        }
> +        var reportName = nameTextbox.val();
> +        var validator = RegExp("^[_A-Za-z0-9-]*$");
> +        if (!validator.test(reportName)) {
> +            wok.message.error.code('GGBDR6011M');
> +            return false;
> +        }
> +        var formData = addReportForm.serializeObject();
> +        var taskAccepted = false;
> +        var onTaskAccepted = function() {
> +            if(taskAccepted) {
> +                return;
> +            }
> +            taskAccepted = true;
> +            wok.window.close();
> +            wok.topic('kimchi/debugReportAdded').publish();
> +        };
> +
> +        kimchi.createReport(formData, function(result) {
> +            onTaskAccepted();
> +            wok.topic('kimchi/debugReportAdded').publish();
> +        }, function(result) {
> +            // Error message from Async Task status
> +            if (result['message']) {
> +                var errText = result['message'];
> +            }
> +            // Error message from standard kimchi exception
> +            else {
> +                var errText = result['responseJSON']['reason'];
> +            }
> +            result && wok.message.error(errText);
> +
> +            taskAccepted &&
> +                $('.grid-body-view table tr:first-child',
> +                    '#' + reportGridID).remove();
> +            submitButton.prop('disabled', false);
> +            nameTextbox.select();
> +        }, onTaskAccepted);
> +
> +        event.preventDefault();
> +    };
> +
> +    addReportForm.on('submit', submitForm);
> +    submitButton.on('click', submitForm);
> +};
> diff --git a/plugins/gingerbase/ui/js/src/gingerbase.report_rename_main.js b/plugins/gingerbase/ui/js/src/gingerbase.report_rename_main.js
> new file mode 100644
> index 0000000..6134b2e
> --- /dev/null
> +++ b/plugins/gingerbase/ui/js/src/gingerbase.report_rename_main.js
> @@ -0,0 +1,66 @@
> +/*
> + * Project Kimchi
> + *
> + * Copyright IBM, Corp. 2014
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +kimchi.report_rename_main = function() {
> +    var renameReportForm = $('#form-report-rename');
> +    var submitButton = $('#button-report-rename');
> +    var nameTextbox = $('input[name="name"]', renameReportForm);
> +    var submitForm = function(event) {
> +        if(submitButton.prop('disabled')) {
> +            return false;
> +        }
> +        var reportName = nameTextbox.val();
> +
> +        // if the user hasn't changed the report's name,
> +        // nothing should be done.
> +        if (reportName == kimchi.selectedReport) {
> +            wok.message.error.code('GGBDR6013M');
> +            return false;
> +        }
> +
> +        var validator = RegExp("^[A-Za-z0-9-]*$");
> +        if (!validator.test(reportName)) {
> +            wok.message.error.code('GGBDR6011M');
> +            return false;
> +        }
> +        var formData = renameReportForm.serializeObject();
> +        submitButton.prop('disabled', true);
> +        nameTextbox.prop('disabled', true);
> +        kimchi.renameReport(kimchi.selectedReport, formData, function(result) {
> +            submitButton.prop('disabled', false);
> +            nameTextbox.prop('disabled', false);
> +            wok.window.close();
> +            wok.topic('kimchi/debugReportRenamed').publish({
> +                result: result
> +            });
> +        }, function(result) {
> +            var errText = result &&
> +                result['responseJSON'] &&
> +                result['responseJSON']['reason'];
> +            wok.message.error(errText);
> +            submitButton.prop('disabled', false);
> +            nameTextbox.prop('disabled', false).focus();
> +        });
> +
> +        event.preventDefault();
> +    };
> +
> +    renameReportForm.on('submit', submitForm);
> +    submitButton.on('click', submitForm);
> +
> +    nameTextbox.val(kimchi.selectedReport).select();
> +};
> diff --git a/plugins/gingerbase/ui/js/src/gingerbase.repository_add_main.js b/plugins/gingerbase/ui/js/src/gingerbase.repository_add_main.js
> new file mode 100644
> index 0000000..656306b
> --- /dev/null
> +++ b/plugins/gingerbase/ui/js/src/gingerbase.repository_add_main.js
> @@ -0,0 +1,96 @@
> +/*
> + * Project Kimchi
> + *
> + * Copyright IBM, Corp. 2014
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +kimchi.repository_add_main = function() {
> +
> +    var addForm = $('#form-repository-add');
> +    var addButton = $('#button-repository-add');
> +
> +    var validateField = function(event) {
> +        var valid=($(this).val()!=='');
> +        $(addButton).prop('disabled', !valid);
> +        return(valid);
> +    };
> +
> +    var validateForm = function(event) {
> +        var valid=false;
> +        addForm.find('input.required').each( function() {
> +            valid=($(this).val()!=='');
> +            return(!valid);
> +        });
> +        return(valid);
> +    }
> +
> +    addForm.find('input.required').on('input propertychange', validateField);
> +
> +    var weedObject = function(obj) {
> +        for (var key in obj) {
> +            if (obj.hasOwnProperty(key)) {
> +                if((typeof(obj[key])==="object") && !Array.isArray(obj[key])) {
> +                    weedObject(obj[key]);
> +                }
> +                else if(obj[key] == '') {
> +                    delete obj[key];
> +                }
> +            }
> +        }
> +    }
> +
> +    var addRepository = function(event) {
> +        var valid = validateForm();
> +        if(!valid) {
> +            return false;
> +        }
> +
> +        var formData = $(addForm).serializeObject();
> +
> +        if (formData && formData.isMirror!=undefined) {
> +            formData.isMirror=(String(formData.isMirror).toLowerCase() === 'true');
> +        }
> +        if(formData.isMirror) {
> +            if(formData.config==undefined) {
> +                formData.config=new Object();
> +            }
> +            formData.config.mirrorlist=formData.baseurl;
> +            delete formData.baseurl;
> +            delete formData.isMirror;
> +        }
> +        weedObject(formData);
> +        if(formData.config && formData.config.comps) {
> +            formData.config.comps=formData.config.comps.split(/[,\s]/);
> +            for(var i=0; i>formData.config.comps.length; i++) {
> +                formData.config.comps[i]=formData.config.comps[i].trim();
> +            }
> +            for (var j=formData.config.comps.indexOf(""); j!=-1; j=formData.config.comps.indexOf("")) {
> +                formData.config.comps.splice(j, 1);
> +            }
> +        }
> +
> +        kimchi.createRepository(formData, function() {
> +            wok.topic('kimchi/repositoryAdded').publish();
> +            wok.window.close();
> +        }, function(jqXHR, textStatus, errorThrown) {
> +            var reason = jqXHR &&
> +                jqXHR['responseJSON'] &&
> +                jqXHR['responseJSON']['reason'];
> +            wok.message.error(reason);
> +        });
> +        return false;
> +    };
> +
> +    $(addForm).on('submit', addRepository);
> +};
> diff --git a/plugins/gingerbase/ui/js/src/gingerbase.repository_edit_main.js b/plugins/gingerbase/ui/js/src/gingerbase.repository_edit_main.js
> new file mode 100644
> index 0000000..5bfc51e
> --- /dev/null
> +++ b/plugins/gingerbase/ui/js/src/gingerbase.repository_edit_main.js
> @@ -0,0 +1,74 @@
> +/*
> + * Project Kimchi
> + *
> + * Copyright IBM, Corp. 2014
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +kimchi.repository_edit_main = function() {
> +
> +    var editForm = $('#form-repository-edit');
> +
> +    var saveButton = $('#repository-edit-button-save');
> +
> +    if(kimchi.capabilities['repo_mngt_tool']=="yum") {
> +        editForm.find('input.deb').prop('disabled', true);
> +    }
> +    else if(kimchi.capabilities['repo_mngt_tool']=="deb") {
> +        editForm.find('input.yum').prop('disabled', true);
> +    }
> +
> +    kimchi.retrieveRepository(kimchi.selectedRepository, function(repository) {
> +        editForm.fillWithObject(repository);
> +
> +        $('input', editForm).on('input propertychange', function(event) {
> +            if($(this).val() !== '') {
> +                $(saveButton).prop('disabled', false);
> +            }
> +        });
> +    });
> +
> +
> +    var editRepository = function(event) {
> +        var formData = $(editForm).serializeObject();
> +
> +        if (formData && formData.config) {
> +            formData.config.gpgcheck=(String(formData.config.gpgcheck).toLowerCase() === 'true');
> +        }
> +
> +        if(formData.config && formData.config.comps) {
> +            formData.config.comps=formData.config.comps.split(/[,\s]/);
> +            for(var i=0; i>formData.config.comps.length; i++) {
> +                formData.config.comps[i]=formData.config.comps[i].trim();
> +            }
> +            for (var j=formData.config.comps.indexOf(""); j!=-1; j=formData.config.comps.indexOf("")) {
> +                formData.config.comps.splice(j, 1);
> +            }
> +        }
> +
> +        kimchi.updateRepository(kimchi.selectedRepository, formData, function() {
> +            wok.topic('kimchi/repositoryUpdated').publish();
> +            wok.window.close();
> +        }, function(jqXHR, textStatus, errorThrown) {
> +            var reason = jqXHR &&
> +                jqXHR['responseJSON'] &&
> +                jqXHR['responseJSON']['reason'];
> +            wok.message.error(reason);
> +        });
> +
> +        return false;
> +    };
> +
> +    $(editForm).on('submit', editRepository);
> +    $(saveButton).on('click', editRepository);
> +};
> diff --git a/plugins/gingerbase/ui/js/src/gingerbase.select.js b/plugins/gingerbase/ui/js/src/gingerbase.select.js
> new file mode 100644
> index 0000000..751167f
> --- /dev/null
> +++ b/plugins/gingerbase/ui/js/src/gingerbase.select.js
> @@ -0,0 +1,50 @@
> +/*
> + * Project Kimchi
> + *
> + * Copyright IBM, Corp. 2013-2014
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +
> +kimchi.select = function(id, options) {
> +    var listControl = $('#'+ id);
> +    var targetId = listControl.data('target');
> +    var labelId = listControl.data('label');
> +    var value = $('#' + targetId).val();
> +    var item;
> +    var itemTag = 'li';
> +    var selectedClass = 'active';
> +    $.each(options, function(index, option) {
> +        item = $('<' + itemTag + '></' + itemTag + '>');
> +        item.text(option.label);
> +        item.data('value', option.value);
> +        if(option.value === value) {
> +            item.addClass(selectedClass);
> +            $('#' + labelId).text(option.label);
> +        }
> +        listControl.append(item);
> +    });
> +
> +    listControl.on('click', itemTag, function() {
> +        listControl.children().removeClass(selectedClass);
> +        $(this).addClass(selectedClass);
> +        $('#' + labelId).text($(this).text());
> +        var target = $('#' + targetId);
> +        var oldValue = target.val();
> +        var newValue = $(this).data('value');
> +        target.val(newValue);
> +        if(oldValue !== newValue) {
> +            target.change();
> +        }
> +    });
> +};
> diff --git a/plugins/gingerbase/ui/js/widgets/circleGauge.js b/plugins/gingerbase/ui/js/widgets/circleGauge.js
> new file mode 100644
> index 0000000..32973ac
> --- /dev/null
> +++ b/plugins/gingerbase/ui/js/widgets/circleGauge.js
> @@ -0,0 +1,100 @@
> +/*
> + * Project Kimchi
> + *
> + * Copyright IBM, Corp. 2014
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> + (function($) {
> +    $.widget('kimchi.circleGauge', {
> +
> +        options : {
> +            color : '#87C004',
> +            fillColor : '#87C004',
> +            lineWidth : 20,
> +            shadowSize : '2px',
> +            font : 'bold 13px Geneva, sans-serif',
> +            textAlign : 'center',
> +            radius : 35,
> +            peakRate : 100,
> +            display : 0,
> +            circle : 0,
> +            label : ''
> +        },
> +
> +        _create : function() {
> +            //valuesAttr="{" + this.element.data('value')+ "}";
> +            //console.info(valuesAttr);
> +            //values=eval("(" + valuesAttr + ")");
> +            //$.extend(this.options, values);
> +            this.options.display=this.element.data('display');
> +            this.options.percentage=this.element.data('percentage');
> +            this._fixupPeakRate();
> +            this._draw();
> +        },
> +
> +        setValues : function(values) {
> +            $.extend(this.options, values);
> +            this._fixupPeakRate();
> +            this._draw();
> +        },
> +
> +        _fixupPeakRate : function() {
> +            if (this.options.circle>this.options.peakRate) {
> +                this.options.peakRate=this.options.circle;
> +            }
> +        },
> +
> +        _draw : function() {
> +            this.element.empty();
> +            var canvas = document.createElement('canvas');
> +            //this.element.append($(canvas));  //I don't quite understand this line so trying the one below...
> +            this.element.append(canvas);
> +
> +            var ctx = canvas.getContext('2d');
> +            var radius = this.options.radius;
> +
> +            var shadowSize = 2;
> +            var width = height = radius * 2;
> +            $(canvas).attr('height', height);
> +            $(canvas).attr('width', width);
> +
> +            $(canvas).css({
> +                'boxShadow' : shadowSize + 'px ' + shadowSize + 'px ' + shadowSize + 'px #fff, -' + shadowSize + 'px -' + shadowSize + 'px ' + shadowSize + 'px #eaeaea',
> +                borderRadius : radius + 'px'
> +            });
> +
> +            ctx.clearRect(0, 0, width, height);
> +            ctx.fillStyle = this.options.fillColor;
> +            ctx.font = this.options.font;
> +            ctx.textAlign = 'center';
> +            var originPos = radius;
> +            ctx.textBaseline = 'middle';
> +            ctx.fillText(this.options.display, originPos, originPos);
> +            ctx.strokeStyle = this.options.color;
> +            ctx.lineWidth = this.options.lineWidth;
> +            ctx.beginPath();
> +            ctx.arc(originPos, originPos, radius, -.5 * Math.PI, (this.options.percentage / 50 - .5) * Math.PI);
> +            ctx.stroke();
> +        },
> +
> +        destroy : function() {
> +            this.element.empty();
> +            $.Widget.prototype.destroy.call(this);
> +        }
> +    });
> +}(jQuery));
> +
> +kimchi.circleGauge = function(selector) {
> +    $(selector).circleGauge();
> +};
> diff --git a/plugins/kimchi/ui/js/src/kimchi.host.js b/plugins/kimchi/ui/js/src/kimchi.host.js
> deleted file mode 100644
> index ab02333..0000000
> --- a/plugins/kimchi/ui/js/src/kimchi.host.js
> +++ /dev/null
> @@ -1,858 +0,0 @@
> -/*
> - * Project Kimchi
> - *
> - * Copyright IBM, Corp. 2013-2014
> - *
> - * Licensed under the Apache License, Version 2.0 (the "License");
> - * you may not use this file except in compliance with the License.
> - * You may obtain a copy of the License at
> - *
> - *     http://www.apache.org/licenses/LICENSE-2.0
> - *
> - * Unless required by applicable law or agreed to in writing, software
> - * distributed under the License is distributed on an "AS IS" BASIS,
> - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> - * See the License for the specific language governing permissions and
> - * limitations under the License.
> - */
> -kimchi.host={};
> -
> -kimchi.host_main = function() {
> -    var expand = function(header, toExpand) {
> -        var controlledNode = $(header).attr('aria-controls');
> -        $('#' + controlledNode)[toExpand ? 'removeClass' : 'addClass']('hidden');
> -        $(header).attr('aria-expanded', toExpand ? 'true' : 'false');
> -    };
> -
> -    var repositoriesGrid = null;
> -    var initRepositoriesGrid = function(repo_type) {
> -        var gridFields=[];
> -        if (repo_type == "yum") {
> -                gridFields=[{
> -                    name: 'repo_id',
> -                    label: i18n['KCHREPO6004M'],
> -                    'class': 'repository-id'
> -                }, {
> -                    name: 'config[repo_name]',
> -                    label: i18n['KCHREPO6005M'],
> -                    'class': 'repository-name'
> -                }, {
> -                    name: 'enabled',
> -                    label: i18n['KCHREPO6009M'],
> -                    'class': 'repository-enabled'
> -                }];
> -        }
> -        else if (repo_type == "deb") {
> -                gridFields=[{
> -                    name: 'baseurl',
> -                    label: i18n['KCHREPO6006M'],
> -                    makeTitle: true,
> -                    'class': 'repository-baseurl deb'
> -                }, {
> -                    name: 'enabled',
> -                    label: i18n['KCHREPO6009M'],
> -                    'class': 'repository-enabled deb'
> -                }, {
> -                    name: 'config[dist]',
> -                    label: "dist",
> -                    'class': 'repository-gpgcheck deb'
> -                }, {
> -                    name: 'config[comps]',
> -                    label: "comps",
> -                    'class': 'repository-gpgcheck deb'
> -                }];
> -        }
> -        else {
> -            gridFields=[{
> -                name: 'repo_id',
> -                label: i18n['KCHREPO6004M'],
> -                'class': 'repository-id'
> -                }, {
> -                    name: 'enabled',
> -                    label: i18n['KCHREPO6009M'],
> -                    'class': 'repository-enabled'
> -                }, {
> -                    name: 'baseurl',
> -                    label: i18n['KCHREPO6006M'],
> -                    makeTitle: true,
> -                    'class': 'repository-baseurl'
> -                }];
> -        }
> -        repositoriesGrid = new kimchi.widget.Grid({
> -            container: 'repositories-grid-container',
> -            id: 'repositories-grid',
> -            title: i18n['KCHREPO6003M'],
> -            toolbarButtons: [{
> -                id: 'repositories-grid-add-button',
> -                label: i18n['KCHREPO6012M'],
> -                onClick: function(event) {
> -                    wok.window.open({url:'plugins/kimchi/repository-add.html',
> -                                    class: repo_type});
> -                }
> -            }, {
> -                id: 'repositories-grid-enable-button',
> -                label: i18n['KCHREPO6016M'],
> -                disabled: true,
> -                onClick: function(event) {
> -                    var repository = repositoriesGrid.getSelected();
> -                    if(!repository) {
> -                        return;
> -                    }
> -                    var name = repository['repo_id'];
> -                    var enable = !repository['enabled'];
> -                    $(this).prop('disabled', true);
> -                    kimchi.enableRepository(name, enable, function() {
> -                        wok.topic('kimchi/repositoryUpdated').publish();
> -                    });
> -                }
> -            }, {
> -                id: 'repositories-grid-edit-button',
> -                label: i18n['KCHREPO6013M'],
> -                disabled: true,
> -                onClick: function(event) {
> -                    var repository = repositoriesGrid.getSelected();
> -                    if(!repository) {
> -                        return;
> -                    }
> -                    kimchi.selectedRepository = repository['repo_id'];
> -                    wok.window.open({url:'plugins/kimchi/repository-edit.html',
> -                                    class: repo_type});
> -                }
> -            }, {
> -                id: 'repositories-grid-remove-button',
> -                label: i18n['KCHREPO6014M'],
> -                disabled: true,
> -                onClick: function(event) {
> -                    var repository = repositoriesGrid.getSelected();
> -                    if(!repository) {
> -                        return;
> -                    }
> -
> -                    var settings = {
> -                        title : i18n['KCHREPO6001M'],
> -                        content : i18n['KCHREPO6002M'],
> -                        confirm : i18n['KCHAPI6004M'],
> -                        cancel : i18n['KCHAPI6003M']
> -                    };
> -
> -                    wok.confirm(settings, function() {
> -                        kimchi.deleteRepository(
> -                            repository['repo_id'],
> -                            function(result) {
> -                                wok.topic('kimchi/repositoryDeleted').publish(result);
> -                            }, function(error) {
> -                            }
> -                        );
> -                    });
> -                }
> -            }],
> -            onRowSelected: function(row) {
> -                var repository = repositoriesGrid.getSelected();
> -                if(!repository) {
> -                    return;
> -                }
> -                $('#repositories-grid-remove-button').prop('disabled', false);
> -                $('#repositories-grid-edit-button').prop('disabled', false);
> -                var enabled = repository['enabled'];
> -                $('#repositories-grid-enable-button')
> -                    .text(i18n[enabled ? 'KCHREPO6017M' : 'KCHREPO6016M'])
> -                    .prop('disabled', false);
> -            },
> -            frozenFields: [],
> -            fields: gridFields,
> -            data: listRepositories
> -        });
> -    };
> -
> -    var listRepositories = function(gridCallback) {
> -        kimchi.listRepositories(function(repositories) {
> -            if($.isFunction(gridCallback)) {
> -                gridCallback(repositories);
> -            }
> -            else {
> -                if(repositoriesGrid) {
> -                    repositoriesGrid.setData(repositories);
> -                }
> -                else {
> -                    initRepositoriesGrid();
> -                    repositoriesGrid.setData(repositories);
> -                }
> -            }
> -        },
> -        function(error) {
> -            var message = error && error['responseJSON'] && error['responseJSON']['reason'];
> -
> -            if($.isFunction(gridCallback)) {
> -                gridCallback([]);
> -            }
> -            repositoriesGrid &&
> -                repositoriesGrid.showMessage(message || i18n['KCHUPD6008M']);
> -        });
> -
> -        $('#repositories-grid-remove-button').prop('disabled', true);
> -        $('#repositories-grid-edit-button').prop('disabled', true);
> -        $('#repositories-grid-enable-button').prop('disabled', true);
> -    };
> -
> -    var softwareUpdatesGridID = 'software-updates-grid';
> -    var softwareUpdatesGrid = null;
> -    var progressAreaID = 'software-updates-progress-textarea';
> -    var reloadProgressArea = function(result) {
> -        var progressArea = $('#' + progressAreaID)[0];
> -        $(progressArea).text(result['message']);
> -        var scrollTop = $(progressArea).prop('scrollHeight');
> -        $(progressArea).prop('scrollTop', scrollTop);
> -    };
> -
> -    var initSoftwareUpdatesGrid = function(softwareUpdates) {
> -        softwareUpdatesGrid = new kimchi.widget.Grid({
> -            container: 'software-updates-grid-container',
> -            id: softwareUpdatesGridID,
> -            title: i18n['KCHUPD6001M'],
> -            rowSelection: 'disabled',
> -            toolbarButtons: [{
> -                id: softwareUpdatesGridID + '-update-button',
> -                label: i18n['KCHUPD6006M'],
> -                disabled: true,
> -                onClick: function(event) {
> -                    var updateButton = $(this);
> -                    var progressArea = $('#' + progressAreaID)[0];
> -                    $('#software-updates-progress-container').removeClass('hidden');
> -                    $(progressArea).text('');
> -                    !wok.isElementInViewport(progressArea) &&
> -                        progressArea.scrollIntoView();
> -                    $(updateButton).text(i18n['KCHUPD6007M']).prop('disabled', true);
> -
> -                    kimchi.updateSoftware(function(result) {
> -                        reloadProgressArea(result);
> -                        $(updateButton).text(i18n['KCHUPD6006M']).prop('disabled', false);
> -                        wok.topic('kimchi/softwareUpdated').publish({
> -                            result: result
> -                        });
> -                    }, function(error) {
> -                        var message = error && error['responseJSON'] && error['responseJSON']['reason'];
> -                        wok.message.error(message || i18n['KCHUPD6009M']);
> -                        $(updateButton).text(i18n['KCHUPD6006M']).prop('disabled', false);
> -                    }, reloadProgressArea);
> -                }
> -            }],
> -            frozenFields: [],
> -            fields: [{
> -                name: 'package_name',
> -                label: i18n['KCHUPD6002M'],
> -                'class': 'software-update-name'
> -            }, {
> -                name: 'version',
> -                label: i18n['KCHUPD6003M'],
> -                'class': 'software-update-version'
> -            }, {
> -                name: 'arch',
> -                label: i18n['KCHUPD6004M'],
> -                'class': 'software-update-arch'
> -            }, {
> -                name: 'repository',
> -                label: i18n['KCHUPD6005M'],
> -                'class': 'software-update-repos'
> -            }],
> -            data: listSoftwareUpdates
> -        });
> -    };
> -
> -    var listSoftwareUpdates = function(gridCallback) {
> -        kimchi.listSoftwareUpdates(function(softwareUpdates) {
> -            if($.isFunction(gridCallback)) {
> -                gridCallback(softwareUpdates);
> -            }
> -            else {
> -                if(softwareUpdatesGrid) {
> -                    softwareUpdatesGrid.setData(softwareUpdates);
> -                }
> -                else {
> -                    initSoftwareUpdatesGrid(softwareUpdates);
> -                }
> -            }
> -
> -            var updateButton = $('#' + softwareUpdatesGridID + '-update-button');
> -            $(updateButton).prop('disabled', softwareUpdates.length === 0);
> -        }, function(error) {
> -            var message = error && error['responseJSON'] && error['responseJSON']['reason'];
> -            if($.isFunction(gridCallback)) {
> -                gridCallback([]);
> -            }
> -            softwareUpdatesGrid &&
> -                softwareUpdatesGrid.showMessage(message || i18n['KCHUPD6008M']);
> -        });
> -    };
> -
> -    var reportGridID = 'available-reports-grid';
> -    var reportGrid = null;
> -    var enableReportButtons = function(toEnable) {
> -        var buttonID = '#{grid}-{btn}-button';
> -        $.each(['rename', 'remove', 'download'], function(i, n) {
> -            $(wok.substitute(buttonID, {
> -                grid: reportGridID,
> -                btn: n
> -            })).prop('disabled', !toEnable);
> -        });
> -    };
> -    var initReportGrid = function(reports) {
> -        reportGrid = new kimchi.widget.Grid({
> -            container: 'available-reports-grid-container',
> -            id: reportGridID,
> -            title: i18n['KCHDR6002M'],
> -            toolbarButtons: [{
> -                id: reportGridID + '-generate-button',
> -                label: i18n['KCHDR6006M'],
> -                onClick: function(event) {
> -                    wok.window.open('plugins/kimchi/report-add.html');
> -                }
> -            }, {
> -                id: reportGridID + '-rename-button',
> -                label: i18n['KCHDR6008M'],
> -                disabled: true,
> -                onClick: function(event) {
> -                    var report = reportGrid.getSelected();
> -                    if(!report) {
> -                        return;
> -                    }
> -
> -                    kimchi.selectedReport = report['name'];
> -                    wok.window.open('plugins/kimchi/report-rename.html');
> -                }
> -            }, {
> -                id: reportGridID + '-remove-button',
> -                label: i18n['KCHDR6009M'],
> -                disabled: true,
> -                onClick: function(event) {
> -                    var report = reportGrid.getSelected();
> -                    if(!report) {
> -                        return;
> -                    }
> -
> -                    var settings = {
> -                        title : i18n['KCHAPI6004M'],
> -                        content : i18n['KCHDR6001M'],
> -                        confirm : i18n['KCHAPI6002M'],
> -                        cancel : i18n['KCHAPI6003M']
> -                    };
> -
> -                    wok.confirm(settings, function() {
> -                        kimchi.deleteReport({
> -                            name: report['name']
> -                        }, function(result) {
> -                            listDebugReports();
> -                        }, function(error) {
> -                           wok.message.error(error.responseJSON.reason);
> -                        });
> -                    });
> -                }
> -            }, {
> -                id: reportGridID + '-download-button',
> -                label: i18n['KCHDR6010M'],
> -                disabled: true,
> -                onClick: function(event) {
> -                    var report = reportGrid.getSelected();
> -                    if(!report) {
> -                        return;
> -                    }
> -
> -                    kimchi.downloadReport({
> -                        file: report['uri']
> -                    });
> -                }
> -            }],
> -            onRowSelected: function(row) {
> -                var report = reportGrid.getSelected();
> -                // Only enable report buttons if the selected line is not a
> -                // pending report
> -                if (report['time'] == i18n['KCHDR6007M']) {
> -                    var gridElement = $('#'+ reportGridID);
> -                    var row = $('tr:contains(' + report['name'] + ')', gridElement);
> -                    enableReportButtons(false);
> -                    row.attr('class', '');
> -                }
> -                else {
> -                    enableReportButtons(true);
> -                }
> -            },
> -            frozenFields: [],
> -            fields: [{
> -                name: 'name',
> -                label: i18n['KCHDR6003M'],
> -                'class': 'debug-report-name'
> -            }, {
> -                name: 'time',
> -                label: i18n['KCHDR6005M'],
> -                'class': 'debug-report-time'
> -            }],
> -            data: reports
> -        });
> -    };
> -
> -    var getPendingReports = function() {
> -        var reports = []
> -        var filter = 'status=running&target_uri=' + encodeURIComponent('^/plugins/kimchi/debugreports/*')
> -
> -        kimchi.getTasksByFilter(filter, function(tasks) {
> -            for(var i = 0; i < tasks.length; i++) {
> -                reportName = tasks[i].target_uri.replace(/^\/plugins\/kimchi\/debugreports\//, '') || i18n['KCHDR6012M'];
> -                reports.push({'name': reportName, 'time': i18n['KCHDR6007M']})
> -
> -                if(kimchi.trackingTasks.indexOf(tasks[i].id) >= 0) {
> -                    continue;
> -                }
> -
> -                kimchi.trackTask(tasks[i].id, function(result) {
> -                    wok.topic('kimchi/debugReportAdded').publish();
> -                }, function(result) {
> -                    // Error message from Async Task status
> -                    if (result['message']) {
> -                        var errText = result['message'];
> -                    }
> -                    // Error message from standard kimchi exception
> -                    else {
> -                        var errText = result['responseJSON']['reason'];
> -                    }
> -                    result && wok.message.error(errText);
> -                    wok.topic('kimchi/debugReportAdded').publish();
> -                }, null);
> -            }
> -        }, null, true);
> -
> -        return reports;
> -    };
> -
> -    var listDebugReports = function() {
> -        kimchi.listReports(function(reports) {
> -            pendingReports = getPendingReports();
> -            allReports = pendingReports.concat(reports);
> -            $('#debug-report-section').removeClass('hidden');
> -
> -            // Row selection will be cleared so disable buttons here
> -            enableReportButtons(false);
> -
> -            if(reportGrid) {
> -                reportGrid.setData(allReports);
> -            }
> -            else {
> -                initReportGrid(allReports);
> -            }
> -
> -            // Set id-debug-img to pending reports
> -            // It will display a loading icon
> -            var gridElement = $('#' + reportGridID);
> -                $.each($('td:contains(' + i18n['KCHDR6007M']  + ')', gridElement), function(index, row) {
> -                $(row).parent().addClass('no-hover');
> -                $(row).attr('id', 'id-debug-img');
> -            });
> -        }, function(error) {
> -            if(error['status'] == 403) {
> -                $('#debug-report-section').addClass('hidden');
> -                return;
> -            }
> -            $('#debug-report-section').removeClass('hidden');
> -        });
> -    };
> -
> -    var shutdownButtonID = '#host-button-shutdown';
> -    var restartButtonID = '#host-button-restart';
> -    var shutdownHost = function(params) {
> -        var settings = {
> -            title : i18n['KCHAPI6004M'],
> -            content : i18n['KCHHOST6008M'],
> -            confirm : i18n['KCHAPI6002M'],
> -            cancel : i18n['KCHAPI6003M']
> -        };
> -
> -        wok.confirm(settings, function() {
> -            kimchi.shutdown(params);
> -            $(shutdownButtonID).prop('disabled', true);
> -            $(restartButtonID).prop('disabled', true);
> -            // Check if there is any VM is running.
> -            kimchi.listVMs(function(vms) {
> -                for(var i = 0; i < vms.length; i++) {
> -                    if(vms[i]['state'] === 'running') {
> -                        wok.message.error.code('KCHHOST6001E');
> -                        $(shutdownButtonID).prop('disabled', false);
> -                        $(restartButtonID).prop('disabled', false);
> -                        return;
> -                    }
> -                }
> -
> -            });
> -        }, function() {
> -        });
> -    };
> -
> -    var initPage = function() {
> -        $('#host-info-container .section-header').each(function(i, header) {
> -            $('<span class="arrow"></span>').prependTo(header);
> -            var toExpand = $(header).attr('aria-expanded') !== 'false';
> -            expand(header, toExpand);
> -        });
> -
> -        $('#host-info-container').on('click', '.section-header', function(event) {
> -            var toExpand = $(this).attr('aria-expanded') === 'false';
> -            expand(this, toExpand);
> -        });
> -
> -        $('#host-button-shutdown').on('click', function(event) {
> -            shutdownHost(null);
> -        });
> -
> -        $('#host-button-restart').on('click', function(event) {
> -            shutdownHost({
> -                reboot: true
> -            });
> -        });
> -
> -        var setupUI = function() {
> -            if (kimchi.capabilities == undefined) {
> -                setTimeout(setupUI, 2000);
> -                return;
> -            }
> -
> -            if((kimchi.capabilities['repo_mngt_tool']) && (kimchi.capabilities['repo_mngt_tool']!="None")) {
> -                initRepositoriesGrid(kimchi.capabilities['repo_mngt_tool']);
> -                $('#repositories-section').switchClass('hidden', kimchi.capabilities['repo_mngt_tool']);
> -                wok.topic('kimchi/repositoryAdded')
> -                    .subscribe(listRepositories);
> -                wok.topic('kimchi/repositoryUpdated')
> -                    .subscribe(listRepositories);
> -                wok.topic('kimchi/repositoryDeleted')
> -                    .subscribe(listRepositories);
> -            }
> -
> -            if(kimchi.capabilities['update_tool']) {
> -                $('#software-update-section').removeClass('hidden');
> -                initSoftwareUpdatesGrid();
> -                wok.topic('kimchi/softwareUpdated')
> -                    .subscribe(listSoftwareUpdates);
> -                $('#software-updates-progress-container').accordion({
> -                    collapsible: true
> -                });
> -            }
> -
> -            if(kimchi.capabilities['system_report_tool']) {
> -                listDebugReports();
> -                wok.topic('kimchi/debugReportAdded')
> -                    .subscribe(listDebugReports);
> -                wok.topic('kimchi/debugReportRenamed')
> -                    .subscribe(listDebugReports);
> -            }
> -        };
> -        setupUI();
> -    };
> -
> -    kimchi.getHost(function(data) {
> -        var htmlTmpl = $('#host-tmpl').html();
> -        data['logo'] = data['logo'] || '';
> -        data['memory'] = wok.formatMeasurement(data['memory'], {
> -            fixed: 2
> -        });
> -        var templated = wok.substitute(htmlTmpl, data);
> -        $('#host-content-container').html(templated);
> -
> -        initPage();
> -        initTracker();
> -    });
> -
> -    var StatsMgr = function() {
> -        var statsArray = {
> -            cpu: {
> -                u: {
> -                    type: 'percent',
> -                    legend: i18n['KCHHOST6002M'],
> -                    points: []
> -                }
> -            },
> -            memory: {
> -                u: {
> -                    type: 'value',
> -                    base: 2,
> -                    fixed: 2,
> -                    legend: i18n['KCHHOST6003M'],
> -                    points: []
> -                }
> -            },
> -            diskIO: {
> -                r: {
> -                    type: 'value',
> -                    base: 2,
> -                    fixed: 2,
> -                    unit: 'B/s',
> -                    legend: i18n['KCHHOST6004M'],
> -                    points: []
> -                },
> -                w: {
> -                    type: 'value',
> -                    base: 2,
> -                    fixed: 2,
> -                    unit: 'B/s',
> -                    legend: i18n['KCHHOST6005M'],
> -                    'class': 'disk-write',
> -                    points: []
> -                }
> -            },
> -            networkIO: {
> -                r: {
> -                    type: 'value',
> -                    base: 2,
> -                    fixed: 2,
> -                    unit: 'B/s',
> -                    legend: i18n['KCHHOST6006M'],
> -                    points: []
> -                },
> -                s: {
> -                    type: 'value',
> -                    base: 2,
> -                    fixed: 2,
> -                    unit: 'B/s',
> -                    legend: i18n['KCHHOST6007M'],
> -                    'class': 'network-sent',
> -                    points: []
> -                }
> -            }
> -        };
> -        var SIZE = 20;
> -        var cursor = SIZE;
> -
> -        var add = function(stats) {
> -            for(var key in stats) {
> -                var item = stats[key];
> -                for(var metrics in item) {
> -                    var value = item[metrics]['v'];
> -                    var max = item[metrics]['max'];
> -                    var unifiedMetrics = statsArray[key][metrics];
> -                    var ps = unifiedMetrics['points'];
> -                    if(!Array.isArray(value)){
> -                        ps.push(value);
> -                        if(ps.length > SIZE + 1) {
> -                            ps.shift();
> -                        }
> -                    }
> -                    else{
> -                        ps=ps.concat(value);
> -                        ps.splice(0, ps.length-SIZE-1);
> -                        unifiedMetrics['points']=ps;
> -                    }
> -                    if(max !== undefined) {
> -                        unifiedMetrics['max'] = max;
> -                    }
> -                    else {
> -                        if(unifiedMetrics['type'] !== 'value') {
> -                            continue;
> -                        }
> -                        max = -Infinity;
> -                        $.each(ps, function(i, value) {
> -                            if(value > max) {
> -                                max = value;
> -                            }
> -                        });
> -                        if(max === 0) {
> -                            ++max;
> -                        }
> -                        max *= 1.1;
> -                        unifiedMetrics['max'] = max;
> -                    }
> -                }
> -            }
> -            cursor++;
> -        };
> -
> -        var get = function(which) {
> -            var stats = statsArray[which];
> -            var lines = [];
> -            for(var k in stats) {
> -                var obj = stats[k];
> -                var line = {
> -                    type: obj['type'],
> -                    base: obj['base'],
> -                    unit: obj['unit'],
> -                    fixed: obj['fixed'],
> -                    legend: obj['legend']
> -                };
> -                if(obj['max']) {
> -                    line['max'] = obj['max'];
> -                }
> -                if(obj['class']) {
> -                    line['class'] = obj['class'];
> -                }
> -                var ps = obj['points'];
> -                var numStats = ps.length;
> -                var unifiedPoints = [];
> -                $.each(ps, function(i, value) {
> -                    unifiedPoints.push({
> -                        x: cursor - numStats + i,
> -                        y: value
> -                    });
> -                });
> -                line['points'] = unifiedPoints;
> -                lines.push(line);
> -            }
> -            return lines;
> -        };
> -
> -        return {
> -            add: add,
> -            get: get
> -        };
> -    };
> -
> -    var Tracker = function(charts) {
> -      var charts = charts;
> -      var timer = null;
> -      var statsPool = new StatsMgr();
> -      var setCharts = function(newCharts) {
> -          charts = newCharts;
> -          for(var key in charts) {
> -              var chart = charts[key];
> -              chart.updateUI(statsPool.get(key));
> -          }
> -      };
> -
> -      var self = this;
> -
> -      var UnifyStats = function(stats) {
> -          var result= {
> -              cpu: {
> -                  u: {
> -                      v: stats['cpu_utilization']
> -                  }
> -              },
> -              memory: {
> -                  u: {
> -                  }
> -              },
> -              diskIO: {
> -                  r: {
> -                      v: stats['disk_read_rate']
> -                  },
> -                  w: {
> -                      v: stats['disk_write_rate']
> -                  }
> -              },
> -              networkIO: {
> -                  r: {
> -                      v: stats['net_recv_rate']
> -                  },
> -                  s: {
> -                      v: stats['net_sent_rate']
> -                  }
> -              }
> -          };
> -          if(Array.isArray(stats['memory'])){
> -              result.memory.u['v']=[];
> -              result.memory.u['max']=-Infinity;
> -              for(var i=0;i<stats['memory'].length;i++){
> -                  result.memory.u['v'].push(stats['memory'][i]['avail']);
> -                  result.memory.u['max']=Math.max(result.memory.u['max'],stats['memory'][i]['total']);
> -              }
> -          }
> -          else {
> -              result.memory.u['v']=stats['memory']['avail'],
> -              result.memory.u['max']=stats['memory']['total']
> -          }
> -          return(result);
> -      };
> -
> -
> -      var statsCallback = function(stats) {
> -              var unifiedStats = UnifyStats(stats);
> -              statsPool.add(unifiedStats);
> -              for(var key in charts) {
> -                  var chart = charts[key];
> -                  chart.updateUI(statsPool.get(key));
> -              }
> -              timer = setTimeout(function() {
> -                  continueTrack();
> -              }, 1000);
> -          };
> -
> -      var track = function() {
> -          kimchi.getHostStatsHistory(statsCallback,
> -            function() {
> -                continueTrack();
> -            });
> -      };
> -
> -      var continueTrack = function() {
> -          kimchi.getHostStats(statsCallback,
> -            function() {
> -                continueTrack();
> -            });
> -      };
> -
> -      var destroy = function() {
> -          timer && clearTimeout(timer);
> -          timer = null;
> -      };
> -
> -      return {
> -        setCharts: setCharts,
> -        start: track,
> -        stop: destroy
> -      };
> -    };
> -
> -    var initTracker = function() {
> -        // TODO: Extend tabs with onUnload event to unregister timers.
> -        if(kimchi.hostTimer) {
> -            kimchi.hostTimer.stop();
> -            delete kimchi.hostTimer;
> -        }
> -
> -        var trackedCharts = {
> -            cpu: new kimchi.widget.LineChart({
> -                id: 'chart-cpu',
> -                node: 'container-chart-cpu',
> -                type: 'percent'
> -            }),
> -            memory: new kimchi.widget.LineChart({
> -                id: 'chart-memory',
> -                node: 'container-chart-memory',
> -                type: 'value'
> -            }),
> -            diskIO: new kimchi.widget.LineChart({
> -                id: 'chart-disk-io',
> -                node: 'container-chart-disk-io',
> -                type: 'value'
> -            }),
> -            networkIO: new kimchi.widget.LineChart({
> -                id: 'chart-network-io',
> -                node: 'container-chart-network-io',
> -                type: 'value'
> -            })
> -        };
> -
> -        if(kimchi.hostTimer) {
> -            kimchi.hostTimer.setCharts(trackedCharts);
> -        }
> -        else {
> -            kimchi.hostTimer = new Tracker(trackedCharts);
> -            kimchi.hostTimer.start();
> -        }
> -    };
> -
> -    $('#host-root-container').on('remove', function() {
> -        if(kimchi.hostTimer) {
> -            kimchi.hostTimer.stop();
> -            delete kimchi.hostTimer;
> -            }
> -
> -        repositoriesGrid && repositoriesGrid.destroy();
> -        wok.topic('kimchi/repositoryAdded')
> -            .unsubscribe(listRepositories);
> -        wok.topic('kimchi/repositoryUpdated')
> -            .unsubscribe(listRepositories);
> -        wok.topic('kimchi/repositoryDeleted')
> -            .unsubscribe(listRepositories);
> -
> -        softwareUpdatesGrid && softwareUpdatesGrid.destroy();
> -        wok.topic('kimchi/softwareUpdated').unsubscribe(listSoftwareUpdates);
> -
> -        reportGrid && reportGrid.destroy();
> -        wok.topic('kimchi/debugReportAdded').unsubscribe(listDebugReports);
> -        wok.topic('kimchi/debugReportRenamed').unsubscribe(listDebugReports);
> -    });
> -};
> diff --git a/plugins/kimchi/ui/js/src/kimchi.report_add_main.js b/plugins/kimchi/ui/js/src/kimchi.report_add_main.js
> deleted file mode 100644
> index 5f098d3..0000000
> --- a/plugins/kimchi/ui/js/src/kimchi.report_add_main.js
> +++ /dev/null
> @@ -1,72 +0,0 @@
> -/*
> - * Project Kimchi
> - *
> - * Copyright IBM, Corp. 2013-2014
> - *
> - * Licensed under the Apache License, Version 2.0 (the "License");
> - * you may not use this file except in compliance with the License.
> - * You may obtain a copy of the License at
> - *
> - *     http://www.apache.org/licenses/LICENSE-2.0
> - *
> - * Unless required by applicable law or agreed to in writing, software
> - * distributed under the License is distributed on an "AS IS" BASIS,
> - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> - * See the License for the specific language governing permissions and
> - * limitations under the License.
> - */
> -kimchi.report_add_main = function() {
> -    var reportGridID = 'available-reports-grid';
> -    var addReportForm = $('#form-report-add');
> -    var submitButton = $('#button-report-add');
> -    var nameTextbox = $('input[name="name"]', addReportForm);
> -    nameTextbox.select();
> -
> -    var submitForm = function(event) {
> -        if(submitButton.prop('disabled')) {
> -            return false;
> -        }
> -        var reportName = nameTextbox.val();
> -        var validator = RegExp("^[_A-Za-z0-9-]*$");
> -        if (!validator.test(reportName)) {
> -            wok.message.error.code('KCHDR6011M');
> -            return false;
> -        }
> -        var formData = addReportForm.serializeObject();
> -        var taskAccepted = false;
> -        var onTaskAccepted = function() {
> -            if(taskAccepted) {
> -                return;
> -            }
> -            taskAccepted = true;
> -            wok.window.close();
> -            wok.topic('kimchi/debugReportAdded').publish();
> -        };
> -
> -        kimchi.createReport(formData, function(result) {
> -            onTaskAccepted();
> -            wok.topic('kimchi/debugReportAdded').publish();
> -        }, function(result) {
> -            // Error message from Async Task status
> -            if (result['message']) {
> -                var errText = result['message'];
> -            }
> -            // Error message from standard kimchi exception
> -            else {
> -                var errText = result['responseJSON']['reason'];
> -            }
> -            result && wok.message.error(errText);
> -
> -            taskAccepted &&
> -                $('.grid-body-view table tr:first-child',
> -                    '#' + reportGridID).remove();
> -            submitButton.prop('disabled', false);
> -            nameTextbox.select();
> -        }, onTaskAccepted);
> -
> -        event.preventDefault();
> -    };
> -
> -    addReportForm.on('submit', submitForm);
> -    submitButton.on('click', submitForm);
> -};
> diff --git a/plugins/kimchi/ui/js/src/kimchi.report_rename_main.js b/plugins/kimchi/ui/js/src/kimchi.report_rename_main.js
> deleted file mode 100644
> index 1bdb8d9..0000000
> --- a/plugins/kimchi/ui/js/src/kimchi.report_rename_main.js
> +++ /dev/null
> @@ -1,66 +0,0 @@
> -/*
> - * Project Kimchi
> - *
> - * Copyright IBM, Corp. 2014
> - *
> - * Licensed under the Apache License, Version 2.0 (the "License");
> - * you may not use this file except in compliance with the License.
> - * You may obtain a copy of the License at
> - *
> - *     http://www.apache.org/licenses/LICENSE-2.0
> - *
> - * Unless required by applicable law or agreed to in writing, software
> - * distributed under the License is distributed on an "AS IS" BASIS,
> - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> - * See the License for the specific language governing permissions and
> - * limitations under the License.
> - */
> -kimchi.report_rename_main = function() {
> -    var renameReportForm = $('#form-report-rename');
> -    var submitButton = $('#button-report-rename');
> -    var nameTextbox = $('input[name="name"]', renameReportForm);
> -    var submitForm = function(event) {
> -        if(submitButton.prop('disabled')) {
> -            return false;
> -        }
> -        var reportName = nameTextbox.val();
> -
> -        // if the user hasn't changed the report's name,
> -        // nothing should be done.
> -        if (reportName == kimchi.selectedReport) {
> -            wok.message.error.code('KCHDR6013M');
> -            return false;
> -        }
> -
> -        var validator = RegExp("^[A-Za-z0-9-]*$");
> -        if (!validator.test(reportName)) {
> -            wok.message.error.code('KCHDR6011M');
> -            return false;
> -        }
> -        var formData = renameReportForm.serializeObject();
> -        submitButton.prop('disabled', true);
> -        nameTextbox.prop('disabled', true);
> -        kimchi.renameReport(kimchi.selectedReport, formData, function(result) {
> -            submitButton.prop('disabled', false);
> -            nameTextbox.prop('disabled', false);
> -            wok.window.close();
> -            wok.topic('kimchi/debugReportRenamed').publish({
> -                result: result
> -            });
> -        }, function(result) {
> -            var errText = result &&
> -                result['responseJSON'] &&
> -                result['responseJSON']['reason'];
> -            wok.message.error(errText);
> -            submitButton.prop('disabled', false);
> -            nameTextbox.prop('disabled', false).focus();
> -        });
> -
> -        event.preventDefault();
> -    };
> -
> -    renameReportForm.on('submit', submitForm);
> -    submitButton.on('click', submitForm);
> -
> -    nameTextbox.val(kimchi.selectedReport).select();
> -};
> diff --git a/plugins/kimchi/ui/js/src/kimchi.repository_add_main.js b/plugins/kimchi/ui/js/src/kimchi.repository_add_main.js
> deleted file mode 100644
> index 656306b..0000000
> --- a/plugins/kimchi/ui/js/src/kimchi.repository_add_main.js
> +++ /dev/null
> @@ -1,96 +0,0 @@
> -/*
> - * Project Kimchi
> - *
> - * Copyright IBM, Corp. 2014
> - *
> - * Licensed under the Apache License, Version 2.0 (the "License");
> - * you may not use this file except in compliance with the License.
> - * You may obtain a copy of the License at
> - *
> - *     http://www.apache.org/licenses/LICENSE-2.0
> - *
> - * Unless required by applicable law or agreed to in writing, software
> - * distributed under the License is distributed on an "AS IS" BASIS,
> - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> - * See the License for the specific language governing permissions and
> - * limitations under the License.
> - */
> -kimchi.repository_add_main = function() {
> -
> -    var addForm = $('#form-repository-add');
> -    var addButton = $('#button-repository-add');
> -
> -    var validateField = function(event) {
> -        var valid=($(this).val()!=='');
> -        $(addButton).prop('disabled', !valid);
> -        return(valid);
> -    };
> -
> -    var validateForm = function(event) {
> -        var valid=false;
> -        addForm.find('input.required').each( function() {
> -            valid=($(this).val()!=='');
> -            return(!valid);
> -        });
> -        return(valid);
> -    }
> -
> -    addForm.find('input.required').on('input propertychange', validateField);
> -
> -    var weedObject = function(obj) {
> -        for (var key in obj) {
> -            if (obj.hasOwnProperty(key)) {
> -                if((typeof(obj[key])==="object") && !Array.isArray(obj[key])) {
> -                    weedObject(obj[key]);
> -                }
> -                else if(obj[key] == '') {
> -                    delete obj[key];
> -                }
> -            }
> -        }
> -    }
> -
> -    var addRepository = function(event) {
> -        var valid = validateForm();
> -        if(!valid) {
> -            return false;
> -        }
> -
> -        var formData = $(addForm).serializeObject();
> -
> -        if (formData && formData.isMirror!=undefined) {
> -            formData.isMirror=(String(formData.isMirror).toLowerCase() === 'true');
> -        }
> -        if(formData.isMirror) {
> -            if(formData.config==undefined) {
> -                formData.config=new Object();
> -            }
> -            formData.config.mirrorlist=formData.baseurl;
> -            delete formData.baseurl;
> -            delete formData.isMirror;
> -        }
> -        weedObject(formData);
> -        if(formData.config && formData.config.comps) {
> -            formData.config.comps=formData.config.comps.split(/[,\s]/);
> -            for(var i=0; i>formData.config.comps.length; i++) {
> -                formData.config.comps[i]=formData.config.comps[i].trim();
> -            }
> -            for (var j=formData.config.comps.indexOf(""); j!=-1; j=formData.config.comps.indexOf("")) {
> -                formData.config.comps.splice(j, 1);
> -            }
> -        }
> -
> -        kimchi.createRepository(formData, function() {
> -            wok.topic('kimchi/repositoryAdded').publish();
> -            wok.window.close();
> -        }, function(jqXHR, textStatus, errorThrown) {
> -            var reason = jqXHR &&
> -                jqXHR['responseJSON'] &&
> -                jqXHR['responseJSON']['reason'];
> -            wok.message.error(reason);
> -        });
> -        return false;
> -    };
> -
> -    $(addForm).on('submit', addRepository);
> -};
> diff --git a/plugins/kimchi/ui/js/src/kimchi.repository_edit_main.js b/plugins/kimchi/ui/js/src/kimchi.repository_edit_main.js
> deleted file mode 100644
> index 5bfc51e..0000000
> --- a/plugins/kimchi/ui/js/src/kimchi.repository_edit_main.js
> +++ /dev/null
> @@ -1,74 +0,0 @@
> -/*
> - * Project Kimchi
> - *
> - * Copyright IBM, Corp. 2014
> - *
> - * Licensed under the Apache License, Version 2.0 (the "License");
> - * you may not use this file except in compliance with the License.
> - * You may obtain a copy of the License at
> - *
> - *     http://www.apache.org/licenses/LICENSE-2.0
> - *
> - * Unless required by applicable law or agreed to in writing, software
> - * distributed under the License is distributed on an "AS IS" BASIS,
> - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> - * See the License for the specific language governing permissions and
> - * limitations under the License.
> - */
> -kimchi.repository_edit_main = function() {
> -
> -    var editForm = $('#form-repository-edit');
> -
> -    var saveButton = $('#repository-edit-button-save');
> -
> -    if(kimchi.capabilities['repo_mngt_tool']=="yum") {
> -        editForm.find('input.deb').prop('disabled', true);
> -    }
> -    else if(kimchi.capabilities['repo_mngt_tool']=="deb") {
> -        editForm.find('input.yum').prop('disabled', true);
> -    }
> -
> -    kimchi.retrieveRepository(kimchi.selectedRepository, function(repository) {
> -        editForm.fillWithObject(repository);
> -
> -        $('input', editForm).on('input propertychange', function(event) {
> -            if($(this).val() !== '') {
> -                $(saveButton).prop('disabled', false);
> -            }
> -        });
> -    });
> -
> -
> -    var editRepository = function(event) {
> -        var formData = $(editForm).serializeObject();
> -
> -        if (formData && formData.config) {
> -            formData.config.gpgcheck=(String(formData.config.gpgcheck).toLowerCase() === 'true');
> -        }
> -
> -        if(formData.config && formData.config.comps) {
> -            formData.config.comps=formData.config.comps.split(/[,\s]/);
> -            for(var i=0; i>formData.config.comps.length; i++) {
> -                formData.config.comps[i]=formData.config.comps[i].trim();
> -            }
> -            for (var j=formData.config.comps.indexOf(""); j!=-1; j=formData.config.comps.indexOf("")) {
> -                formData.config.comps.splice(j, 1);
> -            }
> -        }
> -
> -        kimchi.updateRepository(kimchi.selectedRepository, formData, function() {
> -            wok.topic('kimchi/repositoryUpdated').publish();
> -            wok.window.close();
> -        }, function(jqXHR, textStatus, errorThrown) {
> -            var reason = jqXHR &&
> -                jqXHR['responseJSON'] &&
> -                jqXHR['responseJSON']['reason'];
> -            wok.message.error(reason);
> -        });
> -
> -        return false;
> -    };
> -
> -    $(editForm).on('submit', editRepository);
> -    $(saveButton).on('click', editRepository);
> -};




More information about the Kimchi-devel mailing list