[PATCH v3 0/8] Debug Report Rename Feature

Enable debug report rename feature in this patch set. Please apply the following patch set first: * [PATCH v2 0/4] Fix: Report Overwritten when Provided Name Existing v2 -> v3: 3a) Added check for name existence when renaming a report (Yu Xin's comment) v1 -> v2: 2a) Retrieved the Right Generated Time for Debug Report (Wen Wang's comment) 2b) Sorted debug reports by Generated Time Descendingly (Wen Wang's comment) 2c) Enabled Form Fields after Request Processed (Yuxin's comment) Hongliang Wang (8): Debug Report Rename: Update API.json Debug Report Rename: Update API.md Debug Report Rename: Implement Back-end Debug Report: Use Generated Time instead of Most Changed Time Debug Report: Sort Reports by Generated Time Descendingly Debug Report Rename UI: Add API in kimchi.api.js Debug Report Rename UI: Add Rename Page Debug Report Rename UI: Enable Rename in Host Tab docs/API.md | 3 ++ src/kimchi/API.json | 11 +++++++ src/kimchi/control/debugreports.py | 8 ++++- src/kimchi/model/debugreports.py | 18 +++++++++++- ui/css/theme-default/report-rename.css | 22 ++++++++++++++ ui/js/src/kimchi.api.js | 12 ++++++++ ui/js/src/kimchi.host.js | 35 +++++++++++++++------- ui/js/src/kimchi.report_rename_main.js | 41 ++++++++++++++++++++++++++ ui/pages/report-rename.html.tmpl | 53 ++++++++++++++++++++++++++++++++++ 9 files changed, 190 insertions(+), 13 deletions(-) create mode 100644 ui/css/theme-default/report-rename.css create mode 100644 ui/js/src/kimchi.report_rename_main.js create mode 100644 ui/pages/report-rename.html.tmpl -- 1.8.1.4

Update API.json for validation. Signed-off-by: Hongliang Wang <hlwang@linux.vnet.ibm.com> --- src/kimchi/API.json | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/kimchi/API.json b/src/kimchi/API.json index 06da9da..f5c6545 100644 --- a/src/kimchi/API.json +++ b/src/kimchi/API.json @@ -41,6 +41,17 @@ } } }, + "debugreport_update": { + "type": "object", + "properties": { + "name": { + "description": "New name of debug report", + "type": "string", + "pattern": "^[A-Za-z0-9-]*$", + "error": "KCHDR0007E" + } + } + }, "storagepools_create": { "type": "object", "error": "KCHPOOL0026E", -- 1.8.1.4

Update API.md accordingly. Signed-off-by: Hongliang Wang <hlwang@linux.vnet.ibm.com> --- docs/API.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/API.md b/docs/API.md index bac30eb..b628745 100644 --- a/docs/API.md +++ b/docs/API.md @@ -710,6 +710,9 @@ specific to the low level collection tool being used. * uri: The URI path to download a debug report * time: The time when the debug report is created +* **PUT**: rename an existed debug report + * name: The new name for this debug report + * **DELETE**: Remove the Debug Report * name: The debug report name used to identify the report -- 1.8.1.4

Added processing in model and controller. Signed-off-by: Hongliang Wang <hlwang@linux.vnet.ibm.com> --- src/kimchi/control/debugreports.py | 4 +++- src/kimchi/model/debugreports.py | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/kimchi/control/debugreports.py b/src/kimchi/control/debugreports.py index 3c12230..65b53a3 100644 --- a/src/kimchi/control/debugreports.py +++ b/src/kimchi/control/debugreports.py @@ -22,7 +22,7 @@ from kimchi.control.utils import internal_redirect from kimchi.control.utils import UrlSubNode -@UrlSubNode("debugreports", True, ['GET', 'POST']) +@UrlSubNode("debugreports", True, ['GET', 'PUT', 'POST']) class DebugReports(AsyncCollection): def __init__(self, model): super(DebugReports, self).__init__(model) @@ -32,6 +32,8 @@ class DebugReports(AsyncCollection): class DebugReport(Resource): def __init__(self, model, ident): super(DebugReport, self).__init__(model, ident) + self.update_params = ["name"] + self.uri_fmt = '/debugreports/%s' self.content = DebugReportContent(model, ident) @property diff --git a/src/kimchi/model/debugreports.py b/src/kimchi/model/debugreports.py index 7994fec..e5125c9 100644 --- a/src/kimchi/model/debugreports.py +++ b/src/kimchi/model/debugreports.py @@ -173,6 +173,22 @@ class DebugReportModel(object): return {'uri': file_target, 'ctime': ctime} + def update(self, name, params): + path = config.get_debugreports_path() + file_pattern = os.path.join(path, name + '.*') + try: + file_source = glob.glob(file_pattern)[0] + except IndexError: + raise NotFoundError("KCHDR0001E", {'name': name}) + + file_target = file_source.replace(name, params['name']) + if os.path.isfile(file_target): + raise ResourceAlreadyExists('KCHDR0008E', {'name': params['name']}) + + shutil.move(file_source, file_target) + kimchi_log.info('%s renamed to %s' % (file_source, file_target)) + return params['name'] + def delete(self, name): path = config.get_debugreports_path() file_pattern = os.path.join(path, name + '.*') -- 1.8.1.4

Currently debug report generation time is ctime, which stands for change time. Though getting creation time for file is dependent to platforms, and we'll use mtime which stands for modification time and for our case because debug report file will not be modified since it is generated. So mtime suits for our case. Signed-off-by: Hongliang Wang <hlwang@linux.vnet.ibm.com> --- src/kimchi/model/debugreports.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kimchi/model/debugreports.py b/src/kimchi/model/debugreports.py index e5125c9..b9b9d37 100644 --- a/src/kimchi/model/debugreports.py +++ b/src/kimchi/model/debugreports.py @@ -166,7 +166,7 @@ class DebugReportModel(object): except IndexError: raise NotFoundError("KCHDR0001E", {'name': name}) - ctime = os.stat(file_target).st_ctime + ctime = os.stat(file_target).st_mtime ctime = time.strftime("%Y-%m-%d-%H:%M:%S", time.localtime(ctime)) file_target = os.path.split(file_target)[-1] file_target = os.path.join("/data/debugreports", file_target) -- 1.8.1.4

Sorted reports by generated time descendingly. Signed-off-by: Hongliang Wang <hlwang@linux.vnet.ibm.com> --- src/kimchi/control/debugreports.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/kimchi/control/debugreports.py b/src/kimchi/control/debugreports.py index 65b53a3..444cb07 100644 --- a/src/kimchi/control/debugreports.py +++ b/src/kimchi/control/debugreports.py @@ -28,6 +28,10 @@ class DebugReports(AsyncCollection): super(DebugReports, self).__init__(model) self.resource = DebugReport + def _get_resources(self, filter_params): + res_list = super(DebugReports, self)._get_resources(filter_params) + return sorted(res_list, key=lambda x:x.data['time'], reverse=True) + class DebugReport(Resource): def __init__(self, model, ident): -- 1.8.1.4

Added API. Signed-off-by: Hongliang Wang <hlwang@linux.vnet.ibm.com> --- ui/js/src/kimchi.api.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js index 072d127..11b006e 100644 --- a/ui/js/src/kimchi.api.js +++ b/ui/js/src/kimchi.api.js @@ -683,6 +683,18 @@ var kimchi = { }); }, + renameReport : function(name, settings, suc, err) { + $.ajax({ + url : kimchi.url + "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']); kimchi.requestJSON({ -- 1.8.1.4

Added rename page including HTML, CSS, and JS. Signed-off-by: Hongliang Wang <hlwang@linux.vnet.ibm.com> --- ui/css/theme-default/report-rename.css | 22 ++++++++++++++ ui/js/src/kimchi.report_rename_main.js | 41 ++++++++++++++++++++++++++ ui/pages/report-rename.html.tmpl | 53 ++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 ui/css/theme-default/report-rename.css create mode 100644 ui/js/src/kimchi.report_rename_main.js create mode 100644 ui/pages/report-rename.html.tmpl diff --git a/ui/css/theme-default/report-rename.css b/ui/css/theme-default/report-rename.css new file mode 100644 index 0000000..959d577 --- /dev/null +++ b/ui/css/theme-default/report-rename.css @@ -0,0 +1,22 @@ +#report-rename-window { + height: 300px; + width: 400px; +} + +#report-rename-window .field { + font-size: 12px; +} + +#report-name-textbox { + -moz-box-sizing: border-box; + box-sizing: border-box; + margin: .5em 0; + width: 100%; +} + +#button-report-rename[disabled] { + background: #c0c0c0 url(../../images/theme-default/loading.gif) 7px + center no-repeat; + color: #DDD; + prenameing-left: 26px; +} diff --git a/ui/js/src/kimchi.report_rename_main.js b/ui/js/src/kimchi.report_rename_main.js new file mode 100644 index 0000000..09d03bd --- /dev/null +++ b/ui/js/src/kimchi.report_rename_main.js @@ -0,0 +1,41 @@ +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(); + var validator = RegExp("^[A-Za-z0-9-]*$"); + if (!validator.test(reportName)) { + kimchi.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); + kimchi.window.close(); + kimchi.topic('kimchi/debugReportRenamed').publish({ + result: result + }); + }, function(result) { + var errText = result && + result['responseJSON'] && + result['responseJSON']['reason']; + kimchi.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/ui/pages/report-rename.html.tmpl b/ui/pages/report-rename.html.tmpl new file mode 100644 index 0000000..7fab0b6 --- /dev/null +++ b/ui/pages/report-rename.html.tmpl @@ -0,0 +1,53 @@ +#* + * Project 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. + *# +#unicode UTF-8 +#import gettext +#from kimchi.cachebust import href +#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang) +#silent _ = t.gettext +#silent _t = t.gettext +<!DOCTYPE html> +<div id="report-rename-window" class="window"> + <header> + <h1 class="title">$_("Rename a Debug Report")</h1> + <div class="close">X</div> + </header> + <div class="content"> + <form id="form-report-rename"> + <section class="form-section"> + <h2> + <label for="report-name-textbox">$_("Report Name")</label> + </h2> + <div class="field"> + <span> + $_("The name used to identify the report. Name can contain: letters, digits and hyphen (\"-\").") + </span> + <input type="text" class="text" id="report-name-textbox" name="name" /> + </div> + </section> + </form> + </div> + <footer> + <div class="btn-group"> + <button id="button-report-rename" class="btn-normal"><span class="text">$_("Submit")</span></button> + </div> + </footer> +</div> +<script> + kimchi.report_rename_main(); +</script> -- 1.8.1.4

Enabled rename feature in host tab. Signed-off-by: Hongliang Wang <hlwang@linux.vnet.ibm.com> --- ui/js/src/kimchi.host.js | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/ui/js/src/kimchi.host.js b/ui/js/src/kimchi.host.js index f3de831..bf3fc3c 100644 --- a/ui/js/src/kimchi.host.js +++ b/ui/js/src/kimchi.host.js @@ -284,6 +284,15 @@ kimchi.host_main = function() { var reportGridID = 'available-reports-grid'; var reportGrid = null; + var enableReportButtons = function(toEnable) { + var buttonID = '#{grid}-{btn}-button'; + $.each(['rename', 'remove', 'download'], function(i, n) { + $(kimchi.substitute(buttonID, { + grid: reportGridID, + btn: n + })).prop('disabled', !toEnable); + }); + }; var initReportGrid = function(reports) { reportGrid = new kimchi.widget.Grid({ container: 'available-reports-grid-container', @@ -304,6 +313,13 @@ kimchi.host_main = function() { label: i18n['KCHDR6008M'], disabled: true, onClick: function(event) { + var report = reportGrid.getSelected(); + if(!report) { + return; + } + + kimchi.selectedReport = report['name']; + kimchi.window.open('report-rename.html'); } }, { id: reportGridID + '-remove-button', @@ -326,10 +342,6 @@ kimchi.host_main = function() { kimchi.deleteReport({ name: report['name'] }, function(result) { - $('#' + reportGridID + '-remove-button') - .prop('disabled', true); - $('#' + reportGridID + '-download-button') - .prop('disabled', true); listDebugReports(); }, function(error) { kimchi.message.error(error.responseJSON.reason); @@ -352,10 +364,7 @@ kimchi.host_main = function() { } }], onRowSelected: function(row) { - $('#' + reportGridID + '-remove-button') - .prop('disabled', false); - $('#' + reportGridID + '-download-button') - .prop('disabled', false); + enableReportButtons(true); }, frozenFields: [], fields: [{ @@ -374,9 +383,10 @@ kimchi.host_main = function() { var listDebugReports = function() { kimchi.listReports(function(reports) { $('#debug-report-section').removeClass('hidden'); - $.each(reports, function(i, item) { - reports[i]['id'] = i + 1; - }); + + // Row selection will be cleared so disable buttons here + enableReportButtons(false); + if(reportGrid) { reportGrid.setData(reports); } @@ -471,6 +481,8 @@ kimchi.host_main = function() { listDebugReports(); kimchi.topic('kimchi/debugReportAdded') .subscribe(listDebugReports); + kimchi.topic('kimchi/debugReportRenamed') + .subscribe(listDebugReports); } }); }; @@ -784,5 +796,6 @@ kimchi.host_main = function() { reportGrid && reportGrid.destroy(); kimchi.topic('kimchi/debugReportAdded').unsubscribe(listDebugReports); + kimchi.topic('kimchi/debugReportRenamed').unsubscribe(listDebugReports); }); }; -- 1.8.1.4
participants (1)
-
Hongliang Wang