mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-23 22:50:09 +03:00
Feature #3748: Marketplace import dialog
This commit is contained in:
parent
34ea6e7f20
commit
4b22d563b2
@ -2,6 +2,8 @@ define(function(require) {
|
||||
var OpenNebulaAction = require('./action');
|
||||
var OpenNebulaError = require('./error');
|
||||
var OpenNebulaHelper = require('./helper');
|
||||
var Notifier = require('utils/notifier');
|
||||
var Locale = require('utils/locale');
|
||||
|
||||
var RESOURCE = "MARKETPLACE";
|
||||
|
||||
@ -9,7 +11,7 @@ define(function(require) {
|
||||
"resource": RESOURCE,
|
||||
"show" : function(params) {
|
||||
params.error = function() {
|
||||
return notifyError(Locale.tr("Cannot connect to OpenNebula Marketplace"));
|
||||
return Notifier.notifyError(Locale.tr("Cannot connect to OpenNebula Marketplace"));
|
||||
};
|
||||
OpenNebulaAction.show(params, RESOURCE);
|
||||
},
|
||||
|
@ -8,6 +8,7 @@ define(function(require) {
|
||||
var DATATABLE_ID = "dataTableMarketplace";
|
||||
|
||||
var _dialogs = [
|
||||
require('./marketplace-tab/dialogs/import')
|
||||
];
|
||||
|
||||
var _panels = [
|
||||
|
@ -7,7 +7,7 @@ define(function(require) {
|
||||
|
||||
var RESOURCE = "Marketplace";
|
||||
var TAB_ID = require('./tabId');
|
||||
//var IMPORT_DIALOG_ID = require('./dialogs/import/dialogId');
|
||||
var IMPORT_DIALOG_ID = require('./dialogs/import/dialogId');
|
||||
|
||||
var _actions = {
|
||||
"Marketplace.list" : {
|
||||
@ -32,7 +32,22 @@ define(function(require) {
|
||||
},
|
||||
|
||||
"Marketplace.import" : {
|
||||
// TODO
|
||||
type: "multiple",
|
||||
call: OpenNebulaResource.show,
|
||||
callback: function(request, response) {
|
||||
if (response['status'] && response['status'] != 'ready') {
|
||||
Notifier.notifyError(Locale.tr("The appliance is not ready"));
|
||||
return;
|
||||
}
|
||||
|
||||
Sunstone.getDialog(IMPORT_DIALOG_ID).setParams({element: response});
|
||||
Sunstone.getDialog(IMPORT_DIALOG_ID).reset();
|
||||
Sunstone.getDialog(IMPORT_DIALOG_ID).show();
|
||||
},
|
||||
elements: function() {
|
||||
return Sunstone.getDataTable(TAB_ID).elements();
|
||||
},
|
||||
error: Notifier.onError
|
||||
},
|
||||
|
||||
"Marketplace.show" : {
|
||||
|
285
src/sunstone/public/app/tabs/marketplace-tab/dialogs/import.js
Normal file
285
src/sunstone/public/app/tabs/marketplace-tab/dialogs/import.js
Normal file
@ -0,0 +1,285 @@
|
||||
define(function(require) {
|
||||
/*
|
||||
DEPENDENCIES
|
||||
*/
|
||||
|
||||
var BaseDialog = require('utils/dialogs/dialog');
|
||||
var TemplateHTML = require('hbs!./import/html');
|
||||
var ContentHTML = require('hbs!./import/content');
|
||||
var Sunstone = require('sunstone');
|
||||
var Notifier = require('utils/notifier');
|
||||
var Locale = require('utils/locale');
|
||||
var ResourceSelect = require('utils/resource-select');
|
||||
var OpenNebulaImage = require('opennebula/image');
|
||||
var OpenNebulaTemplate = require('opennebula/template');
|
||||
|
||||
/*
|
||||
CONSTANTS
|
||||
*/
|
||||
|
||||
var DIALOG_ID = require('./import/dialogId');
|
||||
var TAB_ID = require('../tabId');
|
||||
|
||||
/*
|
||||
CONSTRUCTOR
|
||||
*/
|
||||
|
||||
function Dialog() {
|
||||
this.dialogId = DIALOG_ID;
|
||||
|
||||
BaseDialog.call(this);
|
||||
}
|
||||
|
||||
Dialog.DIALOG_ID = DIALOG_ID;
|
||||
Dialog.prototype = Object.create(BaseDialog.prototype);
|
||||
Dialog.prototype.constructor = Dialog;
|
||||
Dialog.prototype.html = _html;
|
||||
Dialog.prototype.onShow = _onShow;
|
||||
Dialog.prototype.setup = _setup;
|
||||
Dialog.prototype.setParams = _setParams;
|
||||
Dialog.prototype.try_to_create_template = _try_to_create_template;
|
||||
|
||||
return Dialog;
|
||||
|
||||
/*
|
||||
FUNCTION DEFINITIONS
|
||||
*/
|
||||
|
||||
function _html() {
|
||||
return TemplateHTML({
|
||||
'dialogId': this.dialogId
|
||||
});
|
||||
}
|
||||
|
||||
function _setup(context) {
|
||||
var that = this;
|
||||
|
||||
$("#market_import_dialog_content", context).html(
|
||||
ContentHTML({'element': this.element})
|
||||
);
|
||||
|
||||
// Filter out DS with type system (1) or file (2)
|
||||
var filter_att = ["TYPE", "TYPE"];
|
||||
var filter_val = ["1", "2"];
|
||||
|
||||
ResourceSelect.insert('div#market_img_datastore', context, "Datastore",
|
||||
null, false, null, filter_att, filter_val);
|
||||
|
||||
context.off('invalid.fndtn.abide', '#' + DIALOG_ID + 'Form');
|
||||
context.off('valid.fndtn.abide', '#' + DIALOG_ID + 'Form');
|
||||
|
||||
context.on('invalid.fndtn.abide', '#' + DIALOG_ID + 'Form', function(e) {
|
||||
// Fix for valid event firing twice
|
||||
if (e.namespace != 'abide.fndtn') { return; }
|
||||
|
||||
Notifier.notifyError(Locale.tr("One or more required fields are missing or malformed."));
|
||||
}).on('valid.fndtn.abide', '#' + DIALOG_ID + 'Form', function(e) {
|
||||
// Fix for valid event firing twice
|
||||
if (e.namespace != 'abide.fndtn') { return; }
|
||||
|
||||
|
||||
that.number_of_files = that.element['files'].length;
|
||||
that.template_created = false;
|
||||
that.images_information = [];
|
||||
|
||||
|
||||
$("input, button", context).attr("disabled", "disabled");
|
||||
$(".market_image_result:not(.success)", context).html(
|
||||
'<span class="fa-stack fa-2x" style="color: #dfdfdf">'+
|
||||
'<i class="fa fa-cloud fa-stack-2x"></i>'+
|
||||
'<i class="fa fa-spinner fa-spin fa-stack-1x fa-inverse"></i>'+
|
||||
'</span>');
|
||||
$(".market_template_result", context).html(
|
||||
'<span class="fa-stack fa-2x" style="color: #dfdfdf">'+
|
||||
'<i class="fa fa-cloud fa-stack-2x"></i>'+
|
||||
'<i class="fa fa-spinner fa-spin fa-stack-1x fa-inverse"></i>'+
|
||||
'</span>');
|
||||
|
||||
var template_context = $("#market_import_file_template", context);
|
||||
|
||||
$.each(that.element['files'], function(index, value){
|
||||
var local_context = $("#market_import_file_"+index, local_context);
|
||||
|
||||
if ($(".market_image_result:not(.success)", local_context).length > 0) {
|
||||
img_obj = {
|
||||
"image" : {
|
||||
"NAME": $("input.name",local_context).val(),
|
||||
"PATH": that.element['links']['download']['href']+'/'+index,
|
||||
"TYPE": value['type'],
|
||||
"MD5": value['md5'],
|
||||
"SHA1": value['sha1'],
|
||||
"DRIVER": value['driver'],
|
||||
"DEV_PREFIX": value['dev_prefix'],
|
||||
"FROM_APP": that.element['_id']["$oid"],
|
||||
"FROM_APP_NAME": that.element['name'],
|
||||
"FROM_APP_FILE": index
|
||||
},
|
||||
"ds_id" : $("#market_img_datastore select", context).val()
|
||||
};
|
||||
|
||||
OpenNebulaImage.create({
|
||||
timeout: true,
|
||||
data: img_obj,
|
||||
success: function (file_index, file_context){
|
||||
return function(request, response) {
|
||||
$(".market_image_result", file_context).addClass("success").html(
|
||||
'<span class="fa-stack fa-2x" style="color: #dfdfdf">'+
|
||||
'<i class="fa fa-cloud fa-stack-2x"></i>'+
|
||||
'<i class="fa fa-check fa-stack-1x fa-inverse"></i>'+
|
||||
'</span>');
|
||||
|
||||
$(".market_image_response", file_context).html(
|
||||
'<p style="font-size:12px" class="running-color">'+
|
||||
Locale.tr("Image created successfully")+' ID:'+response.IMAGE.ID+
|
||||
'</p>');
|
||||
|
||||
that.images_information[file_index] = response;
|
||||
|
||||
that.try_to_create_template(context);
|
||||
};
|
||||
}(index, local_context),
|
||||
error: function (request, error_json){
|
||||
$(".market_template_result", template_context).html('');
|
||||
|
||||
$(".market_image_result", local_context).html(
|
||||
'<span class="fa-stack fa-2x" style="color: #dfdfdf">'+
|
||||
'<i class="fa fa-cloud fa-stack-2x"></i>'+
|
||||
'<i class="fa fa-warning fa-stack-1x fa-inverse"></i>'+
|
||||
'</span>');
|
||||
|
||||
$(".market_image_response", local_context).html(
|
||||
'<p style="font-size:12px" class="error-color">'+
|
||||
(error_json.error.message || Locale.tr("Cannot contact server: is it running and reachable?"))+
|
||||
'</p>');
|
||||
|
||||
$("input", template_context).removeAttr("disabled");
|
||||
$("input", local_context).removeAttr("disabled");
|
||||
$("button", context).removeAttr("disabled");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
that.try_to_create_template(context);
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
context.foundation('reflow', 'abide');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function _onShow(context) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} params
|
||||
* - params.element : Marketplace appliance as returned by a .show call
|
||||
*/
|
||||
function _setParams(params) {
|
||||
this.element = params.element;
|
||||
}
|
||||
|
||||
|
||||
function _try_to_create_template(context){
|
||||
var that = this;
|
||||
|
||||
var template_context = $("#market_import_file_template", context);
|
||||
|
||||
var images_created = $(".market_image_result.success", context).length;
|
||||
|
||||
if ((images_created == this.number_of_files) && !that.template_created) {
|
||||
that.template_created = true;
|
||||
|
||||
if (that.element['opennebula_template'] && that.element['opennebula_template'] !== "CPU=1") {
|
||||
var vm_template;
|
||||
try {
|
||||
vm_template = JSON.parse(that.element['opennebula_template']);
|
||||
} catch (error) {
|
||||
$(".market_template_result", template_context).html(
|
||||
'<span class="fa-stack fa-2x" style="color: #dfdfdf">'+
|
||||
'<i class="fa fa-cloud fa-stack-2x"></i>'+
|
||||
'<i class="fa fa-warning fa-stack-1x fa-inverse"></i>'+
|
||||
'</span>');
|
||||
|
||||
$(".market_template_response", template_context).html(
|
||||
'<p style="font-size:12px" class="error-color">'+
|
||||
(error.message || Locale.tr("Cannot contact server: is it running and reachable?"))+
|
||||
'</p>');
|
||||
|
||||
$("input", template_context).removeAttr("disabled");
|
||||
$("button", context).removeAttr("disabled");
|
||||
that.template_created = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($.isEmptyObject(vm_template.DISK)){
|
||||
vm_template.DISK = [];
|
||||
} else if (!$.isArray(vm_template.DISK)){
|
||||
vm_template.DISK = [vm_template.DISK];
|
||||
}
|
||||
|
||||
vm_template.NAME = $("input", template_context).val();
|
||||
if (!vm_template.CPU){
|
||||
vm_template.CPU = "1";
|
||||
}
|
||||
if (!vm_template.MEMORY){
|
||||
vm_template.MEMORY = "1024";
|
||||
}
|
||||
|
||||
$.each(that.images_information, function(image_index, image_info){
|
||||
if (!vm_template.DISK[image_index]) {
|
||||
vm_template.DISK[image_index] = {};
|
||||
}
|
||||
|
||||
vm_template.DISK[image_index].IMAGE = image_info.IMAGE.NAME;
|
||||
vm_template.DISK[image_index].IMAGE_UNAME = image_info.IMAGE.UNAME;
|
||||
});
|
||||
|
||||
vm_template.FROM_APP = that.element['_id']["$oid"];
|
||||
vm_template.FROM_APP_NAME = that.element['name'];
|
||||
|
||||
OpenNebulaTemplate.create({
|
||||
timeout: true,
|
||||
data: {vmtemplate: vm_template},
|
||||
success: function (request, response){
|
||||
$(".market_template_result", template_context).addClass("success").html(
|
||||
'<span class="fa-stack fa-2x" style="color: #dfdfdf">'+
|
||||
'<i class="fa fa-cloud fa-stack-2x"></i>'+
|
||||
'<i class="fa fa-check fa-stack-1x fa-inverse"></i>'+
|
||||
'</span>');
|
||||
|
||||
$(".market_template_response", template_context).html(
|
||||
'<p style="font-size:12px" class="running-color">'+
|
||||
Locale.tr("Template created successfully")+' ID:'+response.VMTEMPLATE.ID+
|
||||
'</p>');
|
||||
|
||||
$("button", context).hide();
|
||||
},
|
||||
error: function (request, error_json){
|
||||
$(".market_template_result", template_context).html(
|
||||
'<span class="fa-stack fa-2x" style="color: #dfdfdf">'+
|
||||
'<i class="fa fa-cloud fa-stack-2x"></i>'+
|
||||
'<i class="fa fa-warning fa-stack-1x fa-inverse"></i>'+
|
||||
'</span>');
|
||||
|
||||
$(".market_template_response", template_context).html(
|
||||
'<p style="font-size:12px" class="error-color">'+
|
||||
(error_json.error.message || Locale.tr("Cannot contact server: is it running and reachable?"))+
|
||||
'</p>');
|
||||
|
||||
$("input", template_context).removeAttr("disabled");
|
||||
$("button", context).removeAttr("disabled");
|
||||
that.template_created = false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$("button", context).hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
@ -0,0 +1,65 @@
|
||||
<div class="row">
|
||||
<div class="large-12 columns">
|
||||
<p style="font-size:14px">{{tr "The following images will be created in OpenNebula."}} {{tr "If you want to edit parameters of the image you can do it later in the images tab"}} </p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="large-10 large-centered columns">
|
||||
<div class="large-10 columns">
|
||||
<label for="market_img_datastore">{{tr "Select the datastore for the images"}}
|
||||
</label>
|
||||
<div id="market_img_datastore" name="market_img_datastore">
|
||||
</div>
|
||||
</div>
|
||||
<div class="large-2 columns">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{#each element.files}}
|
||||
<div class="row" id="market_import_file_{{@index}}">
|
||||
<div class="large-10 large-centered columns">
|
||||
<div class="large-10 columns">
|
||||
<label>
|
||||
<i class="fa fa-fw fa-download"/>
|
||||
 {{@index}} - {{tr "Image Name"}}
|
||||
<span class="right">{{humanizeSize "B" size}}</span>
|
||||
</label>
|
||||
{{#if name}}
|
||||
<input type="text" class="name" value="{{name}}"/>
|
||||
{{else}}
|
||||
<input type="text" class="name" value="{{element.name}}"/>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="large-2 columns market_image_result">
|
||||
</div>
|
||||
</div>
|
||||
<div class="large-10 columns market_image_response">
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
{{#if element.opennebula_template}}
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="large-12 columns">
|
||||
<p style="font-size:14px">{{tr "The following template will be created in OpenNebula and the previous images will be referenced in the disks"}} {{tr "If you want to edit parameters of the template you can do it later in the templates tab"}} </p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" id="market_import_file_template">
|
||||
<div class="large-10 large-centered columns">
|
||||
<div class="large-10 columns">
|
||||
<label>
|
||||
<i class="fa fa-fw fa-file-text-o"/> {{tr "Template Name"}}
|
||||
</label>
|
||||
{{#if NAME}}
|
||||
<input type="text" class="name" value="NAME"/>
|
||||
{{else}}
|
||||
<input type="text" class="name" value="{{element.name}}"/>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="large-2 columns market_template_result">
|
||||
</div>
|
||||
</div>
|
||||
<div class="large-10 columns market_template_response">
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
@ -0,0 +1,3 @@
|
||||
define(function(require){
|
||||
return 'importMarketplaceDialog';
|
||||
});
|
@ -0,0 +1,15 @@
|
||||
<div id="{{dialogId}}" class="reveal-modal medium" role="dialog" data-reveal >
|
||||
<div class="row">
|
||||
<h3 class="subheader">{{tr "Import Appliance"}}</h3>
|
||||
</div>
|
||||
<form data-abide="ajax" id="{{dialogId}}Form">
|
||||
<div id="market_import_dialog_content">
|
||||
</div>
|
||||
<div class="form_buttons row">
|
||||
<button type="submit" class="button radius right">
|
||||
{{tr "Import"}}
|
||||
</button>
|
||||
</div>
|
||||
<a class="close-reveal-modal">×</a>
|
||||
</form>
|
||||
</div>
|
Loading…
x
Reference in New Issue
Block a user