mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-23 22:50:09 +03:00
Feature #3782: Add image snapshots to sunstone
This commit is contained in:
parent
979aa0d00a
commit
c9fc7a36da
@ -236,6 +236,7 @@ tabs:
|
||||
panel_tabs:
|
||||
image_info_tab: true
|
||||
image_vms_tab: true
|
||||
image_snapshots_tab: true
|
||||
table_columns:
|
||||
- 0 # Checkbox
|
||||
- 1 # ID
|
||||
@ -262,6 +263,9 @@ tabs:
|
||||
Image.nonpersistent: true
|
||||
Image.clone_dialog: true
|
||||
Image.delete: true
|
||||
Image.snapshot_flatten: true
|
||||
Image.snapshot_revert: true
|
||||
Image.snapshot_delete: true
|
||||
files-tab:
|
||||
panel_tabs:
|
||||
file_info_tab: true
|
||||
|
@ -236,6 +236,7 @@ tabs:
|
||||
panel_tabs:
|
||||
image_info_tab: true
|
||||
image_vms_tab: true
|
||||
image_snapshots_tab: false
|
||||
table_columns:
|
||||
- 0 # Checkbox
|
||||
- 1 # ID
|
||||
@ -262,6 +263,9 @@ tabs:
|
||||
Image.nonpersistent: true
|
||||
Image.clone_dialog: true
|
||||
Image.delete: true
|
||||
Image.snapshot_flatten: false
|
||||
Image.snapshot_revert: false
|
||||
Image.snapshot_delete: false
|
||||
files-tab:
|
||||
panel_tabs:
|
||||
file_info_tab: true
|
||||
|
@ -237,6 +237,7 @@ tabs:
|
||||
panel_tabs:
|
||||
image_info_tab: true
|
||||
image_vms_tab: true
|
||||
image_snapshots_tab: true
|
||||
table_columns:
|
||||
- 0 # Checkbox
|
||||
- 1 # ID
|
||||
@ -263,6 +264,9 @@ tabs:
|
||||
Image.nonpersistent: true
|
||||
Image.clone_dialog: true
|
||||
Image.delete: true
|
||||
Image.snapshot_flatten: true
|
||||
Image.snapshot_revert: true
|
||||
Image.snapshot_delete: true
|
||||
files-tab:
|
||||
panel_tabs:
|
||||
file_info_tab: true
|
||||
|
@ -60,6 +60,9 @@ module OpenNebulaJSON
|
||||
when "chtype" then self.chtype(action_hash['params'])
|
||||
when "clone" then self.clone(action_hash['params'])
|
||||
when "rename" then self.rename(action_hash['params'])
|
||||
when "snapshot_flatten" then self.snapshot_flatten(action_hash['params'])
|
||||
when "snapshot_revert" then self.snapshot_revert(action_hash['params'])
|
||||
when "snapshot_delete" then self.snapshot_delete(action_hash['params'])
|
||||
else
|
||||
error_msg = "#{action_hash['perform']} action not " <<
|
||||
" available for this resource"
|
||||
@ -110,5 +113,17 @@ module OpenNebulaJSON
|
||||
def rename(params=Hash.new)
|
||||
super(params['name'])
|
||||
end
|
||||
|
||||
def snapshot_flatten(params=Hash.new)
|
||||
super(params['snapshot_id'].to_i)
|
||||
end
|
||||
|
||||
def snapshot_revert(params=Hash.new)
|
||||
super(params['snapshot_id'].to_i)
|
||||
end
|
||||
|
||||
def snapshot_delete(params=Hash.new)
|
||||
super(params['snapshot_id'].to_i)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -108,6 +108,18 @@ define(function(require) {
|
||||
var action_obj = params.data.extra_param;
|
||||
OpenNebulaAction.simple_action(params, RESOURCE, "rename", action_obj);
|
||||
},
|
||||
"snapshot_flatten": function(params) {
|
||||
var action_obj = params.data.extra_param;
|
||||
OpenNebulaAction.simple_action(params, RESOURCE, "snapshot_flatten", action_obj);
|
||||
},
|
||||
"snapshot_revert": function(params) {
|
||||
var action_obj = params.data.extra_param;
|
||||
OpenNebulaAction.simple_action(params, RESOURCE, "snapshot_revert", action_obj);
|
||||
},
|
||||
"snapshot_delete": function(params) {
|
||||
var action_obj = params.data.extra_param;
|
||||
OpenNebulaAction.simple_action(params, RESOURCE, "snapshot_delete", action_obj);
|
||||
},
|
||||
"getName": function(id){
|
||||
return OpenNebulaAction.getName(id, RESOURCE);
|
||||
}
|
||||
|
@ -13,7 +13,8 @@ define(function(require) {
|
||||
|
||||
var _panels = [
|
||||
require('./images-tab/panels/info'),
|
||||
require('./images-tab/panels/vms')
|
||||
require('./images-tab/panels/vms'),
|
||||
require('./images-tab/panels/snapshots')
|
||||
];
|
||||
|
||||
var _formPanels = [
|
||||
|
@ -3,6 +3,7 @@ define(function(require) {
|
||||
var Notifier = require('utils/notifier');
|
||||
var Locale = require('utils/locale');
|
||||
var OpenNebulaImage = require('opennebula/image');
|
||||
var CommonActions = require('utils/common-actions');
|
||||
|
||||
var RESOURCE = "Image";
|
||||
var XML_ROOT = "IMAGE";
|
||||
@ -10,6 +11,8 @@ define(function(require) {
|
||||
var CREATE_DIALOG_ID = require('./form-panels/create/formPanelId');
|
||||
var CLONE_DIALOG_ID = require('./dialogs/clone/dialogId');
|
||||
|
||||
var _commonActions = new CommonActions(OpenNebulaImage, RESOURCE, TAB_ID);
|
||||
|
||||
var _actions = {
|
||||
"Image.create" : {
|
||||
type: "create",
|
||||
@ -209,7 +212,10 @@ define(function(require) {
|
||||
},
|
||||
error: Notifier.onError,
|
||||
notify: true
|
||||
}
|
||||
},
|
||||
"Image.snapshot_flatten": _commonActions.singleAction("snapshot_flatten"),
|
||||
"Image.snapshot_revert": _commonActions.singleAction("snapshot_revert"),
|
||||
"Image.snapshot_delete": _commonActions.singleAction("snapshot_delete"),
|
||||
};
|
||||
|
||||
return _actions;
|
||||
|
174
src/sunstone/public/app/tabs/images-tab/panels/snapshots.js
Normal file
174
src/sunstone/public/app/tabs/images-tab/panels/snapshots.js
Normal file
@ -0,0 +1,174 @@
|
||||
define(function(require){
|
||||
/*
|
||||
DEPENDENCIES
|
||||
*/
|
||||
|
||||
var Locale = require('utils/locale');
|
||||
var Humanize = require('utils/humanize');
|
||||
var Config = require('sunstone-config');
|
||||
var Sunstone = require('sunstone');
|
||||
var Tree = require('utils/tree');
|
||||
var TemplateHtml = require('hbs!./snapshots/html');
|
||||
var TemplateEmptyTable = require('hbs!utils/tab-datatable/empty-table');
|
||||
|
||||
/*
|
||||
CONSTANTS
|
||||
*/
|
||||
|
||||
var PANEL_ID = require('./snapshots/panelId');
|
||||
var RESOURCE = "Image";
|
||||
var XML_ROOT = "IMAGE";
|
||||
|
||||
/*
|
||||
CONSTRUCTOR
|
||||
*/
|
||||
|
||||
function Panel(info) {
|
||||
this.title = Locale.tr("Snapshots");
|
||||
this.icon = "fa-camera";
|
||||
|
||||
this.element = info[XML_ROOT];
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
Panel.PANEL_ID = PANEL_ID;
|
||||
Panel.prototype.html = _html;
|
||||
Panel.prototype.setup = _setup;
|
||||
|
||||
return Panel;
|
||||
|
||||
/*
|
||||
FUNCTION DEFINITIONS
|
||||
*/
|
||||
|
||||
function _html() {
|
||||
|
||||
var snapshotsHTML = TemplateEmptyTable();
|
||||
|
||||
if (!$.isEmptyObject(this.element.SNAPSHOTS)){
|
||||
var snapshots = this.element.SNAPSHOTS.SNAPSHOT;
|
||||
|
||||
if (!$.isArray(snapshots)){
|
||||
snapshots = [snapshots];
|
||||
}
|
||||
|
||||
var treeRoot = {
|
||||
htmlStr : '',
|
||||
subTree : []
|
||||
};
|
||||
|
||||
var indexedSnapshots = {};
|
||||
var noParent = [];
|
||||
|
||||
$.each(snapshots, function(){
|
||||
indexedSnapshots[this.ID] = this;
|
||||
|
||||
if(this.PARENT == "-1"){
|
||||
noParent.push(this.ID);
|
||||
}
|
||||
});
|
||||
|
||||
$.each(noParent, function(){
|
||||
treeRoot.subTree.push(
|
||||
_makeTree(indexedSnapshots[this], indexedSnapshots)
|
||||
);
|
||||
});
|
||||
|
||||
snapshotsHTML = Tree.html(treeRoot);
|
||||
}
|
||||
|
||||
return TemplateHtml({snapshotsHTML: snapshotsHTML});
|
||||
}
|
||||
|
||||
function _setup(context) {
|
||||
var that = this;
|
||||
|
||||
$(".snapshot_check_item", context).on("change", function() {
|
||||
// Unselect other check inputs
|
||||
var checked = $(this).is(':checked');
|
||||
$('.snapshot_check_item:checked', context).prop('checked', false);
|
||||
$(this).prop('checked', checked);
|
||||
|
||||
// Enable/disable buttons
|
||||
if ($(this).is(":checked")) {
|
||||
$("#snapshot_flatten", context).prop('disabled', false);
|
||||
$("#snapshot_revert", context).prop('disabled', false);
|
||||
$("#snapshot_delete", context).prop('disabled', false);
|
||||
} else {
|
||||
$("#snapshot_flatten", context).prop('disabled', true);
|
||||
$("#snapshot_revert", context).prop('disabled', true);
|
||||
$("#snapshot_delete", context).prop('disabled', true);
|
||||
}
|
||||
});
|
||||
|
||||
if (Config.isTabActionEnabled("images-tab", "Image.snapshot_flatten")) {
|
||||
$("#snapshot_flatten", context).on('click', function() {
|
||||
var snapshot_id = $(".snapshot_check_item:checked", context).attr('snapshot_id');
|
||||
|
||||
Sunstone.runAction('Image.snapshot_flatten', that.element.ID,
|
||||
{ "snapshot_id": snapshot_id});
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
if (Config.isTabActionEnabled("images-tab", "Image.snapshot_revert")) {
|
||||
$("#snapshot_revert", context).on('click', function() {
|
||||
var snapshot_id = $(".snapshot_check_item:checked", context).attr('snapshot_id');
|
||||
|
||||
Sunstone.runAction('Image.snapshot_revert', that.element.ID,
|
||||
{ "snapshot_id": snapshot_id});
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
if (Config.isTabActionEnabled("images-tab", "Image.snapshot_delete")) {
|
||||
$("#snapshot_delete", context).on('click', function() {
|
||||
var snapshot_id = $(".snapshot_check_item:checked", context).attr('snapshot_id');
|
||||
|
||||
Sunstone.runAction('Image.snapshot_delete', that.element.ID,
|
||||
{ "snapshot_id": snapshot_id});
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function _makeTree(snapshot, indexedSnapshots){
|
||||
var SPACE = ' ';
|
||||
|
||||
var subTree = [];
|
||||
|
||||
if (snapshot.CHILDREN){
|
||||
$.each(snapshot.CHILDREN.split(","), function(){
|
||||
subTree.push(
|
||||
_makeTree(indexedSnapshots[this], indexedSnapshots)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
var html = '<div class="snapshot_row nowrap">'+
|
||||
'<input class="snapshot_check_item" type="checkbox" snapshot_id="'+snapshot.ID+'"/>'+
|
||||
SPACE + snapshot.ID + SPACE;
|
||||
|
||||
var active = (snapshot.ACTIVE == "YES");
|
||||
|
||||
if(active){
|
||||
html += '<i class="fa fa-play-circle-o fa-lg" data-tooltip title="'+
|
||||
Locale.tr("Active")+'"/>' + SPACE;
|
||||
}
|
||||
|
||||
html += Humanize.prettyTime(snapshot.DATE) + SPACE +
|
||||
(snapshot.TAG ? snapshot.TAG + SPACE : '');
|
||||
|
||||
html += '</div>';
|
||||
|
||||
return {
|
||||
htmlStr : html,
|
||||
subTree : subTree
|
||||
};
|
||||
}
|
||||
});
|
@ -0,0 +1,26 @@
|
||||
<div class="row collapse">
|
||||
<div class="large-12 columns">
|
||||
<span class="right">
|
||||
{{#isTabActionEnabled "images-tab" "Image.snapshot_flatten"}}
|
||||
<button class="button secondary small radius" id="snapshot_flatten" disabled="disabled">
|
||||
<span class="fa fa-sort-amount-asc"></span>{{tr "Flatten"}}
|
||||
</button>
|
||||
{{/isTabActionEnabled}}
|
||||
{{#isTabActionEnabled "images-tab" "Image.snapshot_revert"}}
|
||||
<button class="button secondary small radius" id="snapshot_revert" disabled="disabled">
|
||||
<span class="fa fa-reply"></span>{{tr "Revert"}}
|
||||
</button>
|
||||
{{/isTabActionEnabled}}
|
||||
{{#isTabActionEnabled "images-tab" "Image.snapshot_delete"}}
|
||||
<button class="button secondary small radius" id="snapshot_delete" disabled="disabled">
|
||||
<span class="fa fa-times"></span>{{tr "Delete"}}
|
||||
</button>
|
||||
{{/isTabActionEnabled}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row collapse">
|
||||
<div class="large-12 columns" style="overflow-x:auto">
|
||||
{{{snapshotsHTML}}}
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,3 @@
|
||||
define(function(require){
|
||||
return 'image_snapshots_tab';
|
||||
});
|
@ -263,7 +263,8 @@ define(function(require) {
|
||||
$(this).children("span").addClass('fa-chevron-down');
|
||||
$(this).children("span").removeClass('fa-chevron-up');
|
||||
} else {
|
||||
var html = '<div class="snapshots" disk_id='+row.data().DISK_ID+' style="padding-left: 30px;">'+
|
||||
var html = '<div class="snapshots" disk_id='+row.data().DISK_ID+
|
||||
' style="padding-left: 30px; width:900px; overflow-x:auto">'+
|
||||
row.data().SNAPSHOTS+
|
||||
'</div>';
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
@ -1262,7 +1262,6 @@ hr {
|
||||
margin-left: 1em;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
.tree li{
|
||||
|
Loading…
x
Reference in New Issue
Block a user