
Implemented download and upload volumes functions. Signed-off-by: Hongliang Wang <hlwang@linux.vnet.ibm.com> --- ui/css/theme-default/storagepool-add-volume.css | 36 ++++ ui/js/src/kimchi.storagepool_add_volume_main.js | 243 ++++++++++++++++++++++++ ui/pages/storagepool-add-volume.html.tmpl | 80 ++++++++ 3 files changed, 359 insertions(+) create mode 100644 ui/css/theme-default/storagepool-add-volume.css create mode 100644 ui/js/src/kimchi.storagepool_add_volume_main.js create mode 100644 ui/pages/storagepool-add-volume.html.tmpl diff --git a/ui/css/theme-default/storagepool-add-volume.css b/ui/css/theme-default/storagepool-add-volume.css new file mode 100644 index 0000000..6e8a551 --- /dev/null +++ b/ui/css/theme-default/storagepool-add-volume.css @@ -0,0 +1,36 @@ +/* + * 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. + */ +#sp-add-volume-window { + height: 400px; + width: 500px; +} + +#sp-add-volume-window .textbox-wrapper input[type="text"] { + box-sizing: border-box; + width: 100%; +} + +#sp-add-volume-window .textbox-wrapper label { + vertical-align: middle; +} + +#sp-add-volume-window input[type="text"][disabled] { + color: #bbb; + background-color: #fafafa; + cursor: not-allowed; +} diff --git a/ui/js/src/kimchi.storagepool_add_volume_main.js b/ui/js/src/kimchi.storagepool_add_volume_main.js new file mode 100644 index 0000000..9435e28 --- /dev/null +++ b/ui/js/src/kimchi.storagepool_add_volume_main.js @@ -0,0 +1,243 @@ +/* + * 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.sp_add_volume_main = function() { + // download from remote server or upload from local file + var type = 'download'; + + var addButton = $('#sp-add-volume-button'); + var remoteURLBox = $('#volume-remote-url'); + var localFileBox = $('#volume-input-file'); + var typeRadios = $('input.volume-type'); + + var isValidURL = function() { + var url = $(remoteURLBox).val(); + return kimchi.template_check_url(url); + }; + + var isValidFile = function() { + var fileName = $(localFileBox).val(); + return fileName && + /[Ii][Ss][Oo]/g.test(fileName.split('.').pop()); + }; + + $(typeRadios).change(function(event) { + $('.volume-input').prop('disabled', true); + $('.volume-input.' + this.value).prop('disabled', false); + type = this.value; + if(type == 'download') { + $(addButton).prop('disabled', !isValidURL()); + } + else { + $(addButton).prop('disabled', !isValidFile()); + } + }); + + $(remoteURLBox).on('input propertychange', function(event) { + $(addButton).prop('disabled', !isValidURL()); + }); + + $(localFileBox).on('change', function(event) { + $(addButton).prop('disabled', !isValidFile()); + }); + + if(!kimchi.volumeTransferTracker) { + kimchi.volumeTransferTracker = (function() { + var tasks = {}, + sps = {}; + var addTask = function(task) { + var taskID = task['id']; + tasks[taskID] = task; + var sp = task['sp']; + if(sps[sp] === undefined) { + sps[sp] = 1; + } + else { + sps[sp]++; + } + }; + var getTask = function(taskID) { + return tasks[taskID]; + }; + var removeTask = function(task) { + var taskID = task['id']; + var sp = tasks[taskID]['sp']; + delete tasks[taskID]; + if(--sps[sp] === 0) { + delete sps[sp]; + kimchi.topic('kimchi/allVolumeTasksFinished').publish({ + sp: sp + }); + } + }; + return { + add: addTask, + get: getTask, + remove: removeTask + }; + })(); + } + var taskTracker = kimchi.volumeTransferTracker; + + var makeCallback = function(trackType, sp, transType, callback) { + return function(resp) { + var taskID = resp['id']; + var volumeName = resp['target_uri'].split('/').pop(); + if(trackType === 'add') { + taskTracker.add({ + id: taskID, + sp: sp, + volume: volumeName + }); + } + callback(transType, resp); + }; + }; + + var extractProgressData = function(data) { + var sizeArray = /(\d+)\/(\d+)/g.exec(data) || [0, 0, 0]; + var downloaded = sizeArray[1]; + var percent = 0; + if(downloaded) { + var total = sizeArray[2]; + if(!isNaN(total)) { + percent = downloaded / total * 100; + } + } + var formatted = kimchi.formatMeasurement(downloaded); + var size = (1.0 * formatted['v']).toFixed(1) + formatted['s']; + return { + size: size, + percent: percent + }; + }; + + var onFinished = function(type, result) { + var progress = extractProgressData(resp['message']); + var task = taskTracker.get([result['id']]); + kimchi.topic('kimchi/volumeTransferFinished').publish($.extend(progress, { + sp: task['sp'], + type: type, + volume: task['volume'] + })); + taskTracker.remove({ + id: result['id'] + }); + }; + + var onProgress = function(type, resp) { + var progress = extractProgressData(resp['message']); + var task = taskTracker.get([resp['id']]); + kimchi.topic('kimchi/volumeTransferProgress').publish($.extend(progress, { + sp: task['sp'], + type: type, + volume: task['volume'] + })); + }; + + var onTransferError = function(type, result) { + if(!result) { + return; + } + var msg = result && (result['message'] || ( + result['responseJSON'] && result['responseJSON']['reason']) + ); + kimchi.message.error(msg); + + if(!result['target_uri']) { + return; + } + var task = taskTracker.get(result['id']); + kimchi.topic('kimchi/volumeTransferError').publish({ + sp: task['sp'], + type: type, + volume: task['volume'] + }); + taskTracker.remove({ + id: result['id'] + }); + }; + + var onAccepted = function(type, resp) { + var taskID = resp['id']; + var task = taskTracker.get(taskID); + kimchi.window.close(); + kimchi.topic('kimchi/volumeTransferStarted').publish({ + sp: task['sp'], + type: type, + volume: task['volume'] + }); + + kimchi.trackTask(taskID, function(resp) { + onFinished(type, resp); + }, function(resp) { + onTransferError(type, resp); + }, function(resp) { + onProgress(type, resp); + }); + }; + + var onError = function(result) { + $(this).prop('disabled', false); + $(typeRadios).prop('disabled', false); + if(!result) { + return; + } + var msg = result['message'] || ( + result['responseJSON'] && result['responseJSON']['reason'] + ); + kimchi.message.error(msg); + }; + + var fetchRemoteFile = function() { + var volumeURL = remoteURLBox.val(); + var volumeName = volumeURL.split(/(\\|\/)/g).pop(); + kimchi.downloadVolumeToSP({ + sp: kimchi.selectedSP, + name: volumeName, + url: volumeURL + }, makeCallback('add', kimchi.selectedSP, 'download', onAccepted), + onError + ); + }; + + var uploadFile = function() { + var blobFile = $(localFileBox)[0].files[0]; + var fileName = blobFile.name; + var fd = new FormData(); + fd.append('name', fileName); + fd.append('file', blobFile); + kimchi.uploadVolumeToSP({ + sp: kimchi.selectedSP, + formData: fd + }, makeCallback('add', kimchi.selectedSP, 'upload', onAccepted), + onError + ); + }; + + $(addButton).on('click', function(event) { + $(this).prop('disabled', true); + $(typeRadios).prop('disabled', true); + if(type === 'download') { + fetchRemoteFile(); + } + else { + uploadFile(); + } + event.preventDefault(); + }); +}; diff --git a/ui/pages/storagepool-add-volume.html.tmpl b/ui/pages/storagepool-add-volume.html.tmpl new file mode 100644 index 0000000..b01c942 --- /dev/null +++ b/ui/pages/storagepool-add-volume.html.tmpl @@ -0,0 +1,80 @@ +#* + * Project Kimchi + * + * Copyright IBM, Corp. 2014 + * + * Authors: + * Hongliang Wang <hlwang@linux.vnet.ibm.com> + * + * 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 +<div id="sp-add-volume-window" class="window"> + <form id="form-sp-add-volume"> + <header class="window-header"> + <h1 class="title">$_("Add a Volume to Storage Pool")</h1> + <div class="close">X</div> + </header> + <section> + <div class="content"> + <div class="form-section"> + <h2> + <input type="radio" id="volume-type-download" class="volume-type" name="volumeType" value="download" checked="checked" /> + <label for="volume-type-download"> + $_("Fetch from remote URL") + </label> + </h2> + <div class="field"> + <p class="text-help"> + $_("Enter the remote URL here.") + </p> + <div class="textbox-wrapper"> + <input type="text" id="volume-remote-url" class="text volume-input download" name="volumeRemoteURL" /> + </div> + </div> + </div> + <div class="form-section"> + <h2> + <input type="radio" id="volume-type-upload" class="volume-type" name="volumeType" value="upload"/> + <label for="volume-type-upload"> + $_("Upload an file") + </label> + </h2> + <div class="field"> + <p class="text-help"> + $_("Choose the ISO file (with .iso suffix) you want to upload.") + </p> + <div class="textbox-wrapper"> + <input type="file" class="volume-input upload" id="volume-input-file" name="volumeLocalFile" disabled="disabled" /> + </div> + </div> + </div> + </div> + </section> + <footer> + <div class="btn-group"> + <button type="submit" id="sp-add-volume-button" class="btn-normal" disabled="disabled"> + <span class="text">$_("Add")</span> + </button> + </div> + </footer> + </form> +</div> +<script type="text/javascript"> + kimchi.sp_add_volume_main(); +</script> -- 1.8.1.4