[Kimchi-devel] [PATCH v2 3/4] Storage Pool Add Volume UI: Implement Download/Upload Volume Function

Hongliang Wang hlwang at linux.vnet.ibm.com
Fri Sep 12 09:42:44 UTC 2014


Implemented download and upload volumes functions.

Signed-off-by: Hongliang Wang <hlwang at 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 at 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




More information about the Kimchi-devel mailing list