using the better View, ViewModel, Controller style, while doing this, make it generic so that we can use it for qemu and lxc
Signed-off-by: Dominik Csapak <d.csa...@proxmox.com> --- www/manager6/Makefile | 3 +- www/manager6/lxc/Config.js | 3 +- www/manager6/lxc/SnapshotTree.js | 330 --------------------------- www/manager6/qemu/Config.js | 3 +- www/manager6/qemu/SnapshotTree.js | 320 -------------------------- www/manager6/tree/SnapshotTree.js | 361 ++++++++++++++++++++++++++++++ 6 files changed, 366 insertions(+), 654 deletions(-) delete mode 100644 www/manager6/lxc/SnapshotTree.js delete mode 100644 www/manager6/qemu/SnapshotTree.js create mode 100644 www/manager6/tree/SnapshotTree.js diff --git a/www/manager6/Makefile b/www/manager6/Makefile index 3c99ec6c..eb7ac004 100644 --- a/www/manager6/Makefile +++ b/www/manager6/Makefile @@ -98,6 +98,7 @@ JSSRC= \ grid/FirewallAliases.js \ grid/FirewallOptions.js \ tree/ResourceTree.js \ + tree/SnapshotTree.js \ panel/IPSet.js \ panel/ConfigPanel.js \ grid/BackupView.js \ @@ -147,7 +148,6 @@ JSSRC= \ qemu/ScsiHwEdit.js \ qemu/QemuBiosEdit.js \ qemu/Options.js \ - qemu/SnapshotTree.js \ qemu/Config.js \ qemu/CreateWizard.js \ qemu/USBEdit.js \ @@ -167,7 +167,6 @@ JSSRC= \ lxc/DNS.js \ lxc/Config.js \ lxc/CreateWizard.js \ - lxc/SnapshotTree.js \ lxc/ResourceEdit.js \ lxc/MPResize.js \ lxc/MPEdit.js \ diff --git a/www/manager6/lxc/Config.js b/www/manager6/lxc/Config.js index e14b5ad2..29464706 100644 --- a/www/manager6/lxc/Config.js +++ b/www/manager6/lxc/Config.js @@ -266,7 +266,8 @@ Ext.define('PVE.lxc.Config', { me.items.push({ title: gettext('Snapshots'), iconCls: 'fa fa-history', - xtype: 'pveLxcSnapshotTree', + xtype: 'pveGuestSnapshotTree', + type: 'lxc', itemId: 'snapshot' }); } diff --git a/www/manager6/lxc/SnapshotTree.js b/www/manager6/lxc/SnapshotTree.js deleted file mode 100644 index 0c1d9a6b..00000000 --- a/www/manager6/lxc/SnapshotTree.js +++ /dev/null @@ -1,330 +0,0 @@ -Ext.define('PVE.lxc.SnapshotTree', { - extend: 'Ext.tree.Panel', - alias: ['widget.pveLxcSnapshotTree'], - - onlineHelp: 'pct_snapshots', - - load_delay: 3000, - - old_digest: 'invalid', - - stateful: true, - stateId: 'grid-lxc-snapshots', - - sorterFn: function(rec1, rec2) { - var v1 = rec1.data.snaptime; - var v2 = rec2.data.snaptime; - - if (rec1.data.name === 'current') { - return 1; - } - if (rec2.data.name === 'current') { - return -1; - } - - return (v1 > v2 ? 1 : (v1 < v2 ? -1 : 0)); - }, - - reload: function(repeat) { - var me = this; - - Proxmox.Utils.API2Request({ - url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + '/snapshot', - method: 'GET', - failure: function(response, opts) { - Proxmox.Utils.setErrorMask(me, response.htmlStatus); - me.load_task.delay(me.load_delay); - }, - success: function(response, opts) { - Proxmox.Utils.setErrorMask(me, false); - var digest = 'invalid'; - var idhash = {}; - var root = { name: '__root', expanded: true, children: [] }; - Ext.Array.each(response.result.data, function(item) { - item.leaf = true; - item.children = []; - if (item.name === 'current') { - digest = item.digest + item.running; - if (item.running) { - item.iconCls = 'fa fa-fw fa-desktop x-fa-tree-running'; - } else { - item.iconCls = 'fa fa-fw fa-desktop x-fa-tree'; - } - } else { - item.iconCls = 'fa fa-fw fa-history x-fa-tree'; - } - idhash[item.name] = item; - }); - - if (digest !== me.old_digest) { - me.old_digest = digest; - - Ext.Array.each(response.result.data, function(item) { - if (item.parent && idhash[item.parent]) { - var parent_item = idhash[item.parent]; - parent_item.children.push(item); - parent_item.leaf = false; - parent_item.expanded = true; - parent_item.expandable = false; - } else { - root.children.push(item); - } - }); - - me.setRootNode(root); - } - - me.load_task.delay(me.load_delay); - } - }); - - Proxmox.Utils.API2Request({ - url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + '/feature', - params: { feature: 'snapshot' }, - method: 'GET', - success: function(response, options) { - var res = response.result.data; - if (res.hasFeature) { - var snpBtns = Ext.ComponentQuery.query('#snapshotBtn'); - snpBtns.forEach(function(item){ - item.enable(); - }); - } - } - }); - - - }, - - listeners: { - beforestatesave: function(grid, state, eopts) { - // extjs cannot serialize functions, - // so a the sorter with only the sorterFn will - // not be a valid sorter when restoring the state - delete state.storeState.sorters; - } - }, - - initComponent: function() { - var me = this; - - me.nodename = me.pveSelNode.data.node; - if (!me.nodename) { - throw "no node name specified"; - } - - me.vmid = me.pveSelNode.data.vmid; - if (!me.vmid) { - throw "no VM ID specified"; - } - - me.load_task = new Ext.util.DelayedTask(me.reload, me); - - var sm = Ext.create('Ext.selection.RowModel', {}); - - var valid_snapshot = function(record) { - return record && record.data && record.data.name && - record.data.name !== 'current'; - }; - - var valid_snapshot_rollback = function(record) { - return record && record.data && record.data.name && - record.data.name !== 'current' && !record.data.snapstate; - }; - - var run_editor = function() { - var rec = sm.getSelection()[0]; - if (valid_snapshot(rec)) { - var win = Ext.create('PVE.window.LxcSnapshot', { - type: 'lxc', - snapname: rec.data.name, - nodename: me.nodename, - vmid: me.vmid - }); - win.show(); - me.mon(win, 'close', me.reload, me); - } - }; - - var editBtn = new Proxmox.button.Button({ - text: gettext('Edit'), - disabled: true, - selModel: sm, - enableFn: valid_snapshot, - handler: run_editor - }); - - var rollbackBtn = new Proxmox.button.Button({ - text: gettext('Rollback'), - disabled: true, - dangerous: true, - selModel: sm, - enableFn: valid_snapshot_rollback, - confirmMsg: function(rec) { - var taskdescription = Proxmox.Utils.format_task_description('vzrollback', me.vmid); - var snaptime = Ext.Date.format(rec.data.snaptime,'Y-m-d H:i:s'); - var snapname = rec.data.name; - - var msg = Ext.String.format(gettext('{0} to {1} ({2})'), - taskdescription, snapname, snaptime); - msg += '<p>' + gettext('Note: Rollback stops CT') + '</p>'; - - return msg; - }, - handler: function(btn, event) { - var rec = sm.getSelection()[0]; - if (!rec) { - return; - } - var snapname = rec.data.name; - - Proxmox.Utils.API2Request({ - url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + '/snapshot/' + snapname + '/rollback', - method: 'POST', - waitMsgTarget: me, - callback: function() { - me.reload(); - }, - failure: function (response, opts) { - Ext.Msg.alert(gettext('Error'), response.htmlStatus); - }, - success: function(response, options) { - var upid = response.result.data; - var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid }); - win.show(); - } - }); - } - }); - - var removeBtn = new Proxmox.button.Button({ - text: gettext('Remove'), - disabled: true, - selModel: sm, - confirmMsg: function(rec) { - var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'), - "'" + rec.data.name + "'"); - return msg; - }, - enableFn: valid_snapshot, - handler: function(btn, event) { - var rec = sm.getSelection()[0]; - if (!rec) { - return; - } - var snapname = rec.data.name; - - Proxmox.Utils.API2Request({ - url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + '/snapshot/' + snapname, - method: 'DELETE', - waitMsgTarget: me, - callback: function() { - me.reload(); - }, - failure: function (response, opts) { - Ext.Msg.alert(gettext('Error'), response.htmlStatus); - }, - success: function(response, options) { - var upid = response.result.data; - var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid }); - win.show(); - } - }); - } - }); - - var snapshotBtn = Ext.create('Ext.Button', { - itemId: 'snapshotBtn', - text: gettext('Take Snapshot'), - disabled: true, - handler: function() { - var win = Ext.create('PVE.window.LxcSnapshot', { - type: 'lxc', - isCreate: true, - submitText: gettext('Take Snapshot'), - nodename: me.nodename, - vmid: me.vmid - }); - win.show(); - } - }); - - Ext.apply(me, { - layout: 'fit', - rootVisible: false, - animate: false, - sortableColumns: false, - selModel: sm, - tbar: [ snapshotBtn, rollbackBtn, removeBtn, editBtn ], - fields: [ - 'name', 'description', 'snapstate', 'vmstate', 'running', - { name: 'snaptime', type: 'date', dateFormat: 'timestamp' } - ], - columns: [ - { - xtype: 'treecolumn', - text: gettext('Name'), - dataIndex: 'name', - width: 200, - renderer: function(value, metaData, record) { - if (value === 'current') { - return "NOW"; - } else { - return value; - } - } - }, -// { -// text: gettext('RAM'), -// align: 'center', -// resizable: false, -// dataIndex: 'vmstate', -// width: 50, -// renderer: function(value, metaData, record) { -// if (record.data.name !== 'current') { -// return Proxmox.Utils.format_boolean(value); -// } -// } -// }, - { - text: gettext('Date') + "/" + gettext("Status"), - dataIndex: 'snaptime', - resizable: false, - width: 150, - renderer: function(value, metaData, record) { - if (record.data.snapstate) { - return record.data.snapstate; - } - if (value) { - return Ext.Date.format(value,'Y-m-d H:i:s'); - } - } - }, - { - text: gettext('Description'), - dataIndex: 'description', - flex: 1, - renderer: function(value, metaData, record) { - if (record.data.name === 'current') { - return gettext("You are here!"); - } else { - return Ext.String.htmlEncode(value); - } - } - } - ], - columnLines: true, - listeners: { - activate: me.reload, - destroy: me.load_task.cancel, - itemdblclick: run_editor - } - }); - - me.callParent(); - - me.store.sorters.add(new Ext.util.Sorter({ - sorterFn: me.sorterFn - })); - } -}); diff --git a/www/manager6/qemu/Config.js b/www/manager6/qemu/Config.js index 195db3a2..ea8b6137 100644 --- a/www/manager6/qemu/Config.js +++ b/www/manager6/qemu/Config.js @@ -298,7 +298,8 @@ Ext.define('PVE.qemu.Config', { me.items.push({ title: gettext('Snapshots'), iconCls: 'fa fa-history', - xtype: 'pveQemuSnapshotTree', + type: 'qemu', + xtype: 'pveGuestSnapshotTree', itemId: 'snapshot' }); } diff --git a/www/manager6/qemu/SnapshotTree.js b/www/manager6/qemu/SnapshotTree.js deleted file mode 100644 index a3891433..00000000 --- a/www/manager6/qemu/SnapshotTree.js +++ /dev/null @@ -1,320 +0,0 @@ -Ext.define('PVE.qemu.SnapshotTree', { - extend: 'Ext.tree.Panel', - alias: ['widget.pveQemuSnapshotTree'], - - load_delay: 3000, - - old_digest: 'invalid', - - stateful: true, - stateId: 'grid-qemu-snapshots', - - sorterFn: function(rec1, rec2) { - var v1 = rec1.data.snaptime; - var v2 = rec2.data.snaptime; - - if (rec1.data.name === 'current') { - return 1; - } - if (rec2.data.name === 'current') { - return -1; - } - - return (v1 > v2 ? 1 : (v1 < v2 ? -1 : 0)); - }, - - reload: function(repeat) { - var me = this; - - Proxmox.Utils.API2Request({ - url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/snapshot', - method: 'GET', - failure: function(response, opts) { - Proxmox.Utils.setErrorMask(me, response.htmlStatus); - me.load_task.delay(me.load_delay); - }, - success: function(response, opts) { - Proxmox.Utils.setErrorMask(me, false); - var digest = 'invalid'; - var idhash = {}; - var root = { name: '__root', expanded: true, children: [] }; - Ext.Array.each(response.result.data, function(item) { - item.leaf = true; - item.children = []; - if (item.name === 'current') { - digest = item.digest + item.running; - if (item.running) { - item.iconCls = 'fa fa-fw fa-desktop x-fa-tree-running'; - } else { - item.iconCls = 'fa fa-fw fa-desktop x-fa-tree'; - } - } else { - item.iconCls = 'fa fa-fw fa-history x-fa-tree'; - } - idhash[item.name] = item; - }); - - if (digest !== me.old_digest) { - me.old_digest = digest; - - Ext.Array.each(response.result.data, function(item) { - if (item.parent && idhash[item.parent]) { - var parent_item = idhash[item.parent]; - parent_item.children.push(item); - parent_item.leaf = false; - parent_item.expanded = true; - parent_item.expandable = false; - } else { - root.children.push(item); - } - }); - - me.setRootNode(root); - } - - me.load_task.delay(me.load_delay); - } - }); - - Proxmox.Utils.API2Request({ - url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/feature', - params: { feature: 'snapshot' }, - method: 'GET', - success: function(response, options) { - var res = response.result.data; - if (res.hasFeature) { - var snpBtns = Ext.ComponentQuery.query('#snapshotBtn'); - snpBtns.forEach(function(item){ - item.enable(); - }); - } - } - }); - - - }, - - listeners: { - beforestatesave: function(grid, state, eopts) { - // extjs cannot serialize functions, - // so a the sorter with only the sorterFn will - // not be a valid sorter when restoring the state - delete state.storeState.sorters; - } - }, - - initComponent: function() { - var me = this; - - me.nodename = me.pveSelNode.data.node; - if (!me.nodename) { - throw "no node name specified"; - } - - me.vmid = me.pveSelNode.data.vmid; - if (!me.vmid) { - throw "no VM ID specified"; - } - - me.load_task = new Ext.util.DelayedTask(me.reload, me); - - var sm = Ext.create('Ext.selection.RowModel', {}); - - var valid_snapshot = function(record) { - return record && record.data && record.data.name && - record.data.name !== 'current'; - }; - - var valid_snapshot_rollback = function(record) { - return record && record.data && record.data.name && - record.data.name !== 'current' && !record.data.snapstate; - }; - - var run_editor = function() { - var rec = sm.getSelection()[0]; - if (valid_snapshot(rec)) { - var win = Ext.create('PVE.window.Snapshot', { - type: 'qemu', - snapname: rec.data.name, - nodename: me.nodename, - vmid: me.vmid - }); - win.show(); - me.mon(win, 'close', me.reload, me); - } - }; - - var editBtn = new Proxmox.button.Button({ - text: gettext('Edit'), - disabled: true, - selModel: sm, - enableFn: valid_snapshot, - handler: run_editor - }); - - var rollbackBtn = new Proxmox.button.Button({ - text: gettext('Rollback'), - disabled: true, - selModel: sm, - enableFn: valid_snapshot_rollback, - confirmMsg: function(rec) { - return Proxmox.Utils.format_task_description('qmrollback', me.vmid) + - " '" + rec.data.name + "'"; - }, - handler: function(btn, event) { - var rec = sm.getSelection()[0]; - if (!rec) { - return; - } - var snapname = rec.data.name; - - Proxmox.Utils.API2Request({ - url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/snapshot/' + snapname + '/rollback', - method: 'POST', - waitMsgTarget: me, - callback: function() { - me.reload(); - }, - failure: function (response, opts) { - Ext.Msg.alert(gettext('Error'), response.htmlStatus); - }, - success: function(response, options) { - var upid = response.result.data; - var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid }); - win.show(); - } - }); - } - }); - - var removeBtn = new Proxmox.button.Button({ - text: gettext('Remove'), - disabled: true, - selModel: sm, - confirmMsg: function(rec) { - var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'), - "'" + rec.data.name + "'"); - return msg; - }, - enableFn: valid_snapshot, - handler: function(btn, event) { - var rec = sm.getSelection()[0]; - if (!rec) { - return; - } - var snapname = rec.data.name; - - Proxmox.Utils.API2Request({ - url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/snapshot/' + snapname, - method: 'DELETE', - waitMsgTarget: me, - callback: function() { - me.reload(); - }, - failure: function (response, opts) { - Ext.Msg.alert(gettext('Error'), response.htmlStatus); - }, - success: function(response, options) { - var upid = response.result.data; - var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid }); - win.show(); - } - }); - } - }); - - var snapshotBtn = Ext.create('Ext.Button', { - itemId: 'snapshotBtn', - text: gettext('Take Snapshot'), - disabled: true, - handler: function() { - var win = Ext.create('PVE.window.Snapshot', { - isCreate: true, - type: 'qemu', - submitText: gettext('Take Snapshot'), - nodename: me.nodename, - vmid: me.vmid - }); - win.show(); - } - }); - - Ext.apply(me, { - layout: 'fit', - rootVisible: false, - animate: false, - sortableColumns: false, - selModel: sm, - tbar: [ snapshotBtn, rollbackBtn, removeBtn, editBtn ], - fields: [ - 'name', 'description', 'snapstate', 'vmstate', 'running', - { name: 'snaptime', type: 'date', dateFormat: 'timestamp' } - ], - columns: [ - { - xtype: 'treecolumn', - text: gettext('Name'), - dataIndex: 'name', - width: 200, - renderer: function(value, metaData, record) { - if (value === 'current') { - return "NOW"; - } else { - return value; - } - } - }, - { - text: gettext('RAM'), - align: 'center', - resizable: false, - dataIndex: 'vmstate', - width: 50, - renderer: function(value, metaData, record) { - if (record.data.name !== 'current') { - return Proxmox.Utils.format_boolean(value); - } - } - }, - { - text: gettext('Date') + "/" + gettext("Status"), - dataIndex: 'snaptime', - width: 150, - renderer: function(value, metaData, record) { - if (record.data.snapstate) { - return record.data.snapstate; - } - if (value) { - return Ext.Date.format(value,'Y-m-d H:i:s'); - } - } - }, - { - text: gettext('Description'), - dataIndex: 'description', - flex: 1, - renderer: function(value, metaData, record) { - if (record.data.name === 'current') { - return gettext("You are here!"); - } else { - return Ext.String.htmlEncode(value); - } - } - } - ], - columnLines: true, // will work in 4.1? - listeners: { - activate: me.reload, - destroy: me.load_task.cancel, - itemdblclick: run_editor - } - }); - - me.callParent(); - - me.store.sorters.add(new Ext.util.Sorter({ - sorterFn: me.sorterFn - })); - } -}); - diff --git a/www/manager6/tree/SnapshotTree.js b/www/manager6/tree/SnapshotTree.js new file mode 100644 index 00000000..d4007efa --- /dev/null +++ b/www/manager6/tree/SnapshotTree.js @@ -0,0 +1,361 @@ +Ext.define('PVE.guest.SnapshotTree', { + extend: 'Ext.tree.Panel', + xtype: 'pveGuestSnapshotTree', + + stateful: true, + stateId: 'grid-snapshots', + + viewModel: { + data: { + // should be 'qemu' or 'lxc' + type: undefined, + nodename: undefined, + vmid: undefined, + snapshotAllowed: false, + rollbackAllowed: false, + snapshotFeature: false, + selected: '', + load_delay: 3000, + }, + formulas: { + canSnapshot: function(get) { + return get('snapshotAllowed') && get('snapshotFeature'); + }, + canRollback: function(get) { + return get('rollbackAllowed') && + get('selected') && get('selected') !== 'current'; + }, + canRemove: function(get) { + return get('snapshotAllowed') && + get('selected') && get('selected') !== 'current'; + }, + isSnapshot: function(get) { + return get('selected') && get('selected') !== 'current'; + }, + buttonText: function(get) { + return get('snapshotAllowed') ? gettext('Edit') : gettext('View'); + }, + showMemory: function(get) { + return get('type') === 'qemu'; + }, + }, + }, + + controller: { + xclass: 'Ext.app.ViewController', + + newSnapshot: function() { + this.run_editor(false); + }, + + editSnapshot: function() { + this.run_editor(true); + }, + + run_editor: function(edit) { + let me = this; + let vm = me.getViewModel(); + let snapname; + if (edit) { + snapname = vm.get('selected'); + if (!snapname || snapname === 'current') { return; } + } + let win = Ext.create('PVE.window.Snapshot', { + nodename: vm.get('nodename'), + vmid: vm.get('vmid'), + viewonly: !vm.get('snapshotAllowed'), + type: vm.get('type'), + isCreate: !edit, + submitText: !edit ? gettext('Take Snapshot') : undefined, + snapname: snapname, + }); + win.show(); + me.mon(win, 'destroy', me.reload, me); + }, + + snapshotAction: function(action, method) { + let me = this; + let view = me.getView(); + let vm = me.getViewModel(); + let snapname = vm.get('selected'); + if (!snapname) { return; } + + let nodename = vm.get('nodename'); + let type = vm.get('type'); + let vmid = vm.get('vmid'); + + Proxmox.Utils.API2Request({ + url: `/nodes/${nodename}/${type}/${vmid}/snapshot/${snapname}/${action}`, + method: method, + waitMsgTarget: view, + callback: function() { + me.reload(); + }, + failure: function (response, opts) { + Ext.Msg.alert(gettext('Error'), response.htmlStatus); + }, + success: function(response, options) { + var upid = response.result.data; + var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid }); + win.show(); + } + }); + }, + + rollback: function() { this.snapshotAction('rollback', 'POST'); }, + remove: function() { this.snapshotAction('', 'DELETE'); }, + + cancel: function() { + this.load_task.cancel(); + }, + + reload: function() { + let me = this; + let view = me.getView(); + let vm = me.getViewModel(); + let nodename = vm.get('nodename'); + let vmid = vm.get('vmid'); + let type = vm.get('type'); + let load_delay = vm.get('load_delay'); + + Proxmox.Utils.API2Request({ + url: `/nodes/${nodename}/${type}/${vmid}/snapshot`, + method: 'GET', + failure: function(response, opts) { + Proxmox.Utils.setErrorMask(view, response.htmlStatus); + me.load_task.delay(load_delay); + }, + success: function(response, opts) { + Proxmox.Utils.setErrorMask(view, false); + var digest = 'invalid'; + var idhash = {}; + var root = { name: '__root', expanded: true, children: [] }; + Ext.Array.each(response.result.data, function(item) { + item.leaf = true; + item.children = []; + if (item.name === 'current') { + digest = item.digest + item.running; + item.iconCls = PVE.Utils.get_object_icon_class(vm.get('type'), item); + } else { + item.iconCls = 'fa fa-fw fa-history x-fa-tree'; + } + idhash[item.name] = item; + }); + + if (digest !== me.old_digest) { + me.old_digest = digest; + + Ext.Array.each(response.result.data, function(item) { + if (item.parent && idhash[item.parent]) { + var parent_item = idhash[item.parent]; + parent_item.children.push(item); + parent_item.leaf = false; + parent_item.expanded = true; + parent_item.expandable = false; + } else { + root.children.push(item); + } + }); + + me.getView().setRootNode(root); + } + + me.load_task.delay(load_delay); + } + }); + + // if we do not have the permissions, we don't have to check + // if we can create a snapshot, since the butten stays disabled + if (!vm.get('snapshotAllowed')) { + return; + } + + Proxmox.Utils.API2Request({ + url: `/nodes/${nodename}/${type}/${vmid}/feature`, + params: { feature: 'snapshot' }, + method: 'GET', + success: function(response, options) { + var res = response.result.data; vm.set('snapshotFeature', !!res.hasFeature); } + }); + }, + + select: function(grid, val) { + let vm = this.getViewModel(); + if (val.length < 1) { + vm.set('selected', ''); + return; + } + vm.set('selected', val[0].data.name); + }, + + init: function(view) { + let me = this; + let vm = me.getViewModel(); + me.load_task = new Ext.util.DelayedTask(me.reload, me); + + if (!view.type) { + throw 'guest type not set'; + } + vm.set('type', view.type); + + if (!view.pveSelNode.data.node) { + throw "no node name specified"; + } + vm.set('nodename', view.pveSelNode.data.node); + + if (!view.pveSelNode.data.vmid) { + throw "no VM ID specified"; + } + vm.set('vmid', view.pveSelNode.data.vmid); + + let caps = Ext.state.Manager.get('GuiCap'); + vm.set('snapshotAllowed', !!caps.vms['VM.Snapshot']); + vm.set('rollbackAllowed', !!caps.vms['VM.Snapshot.Rollback']); + + view.getStore().sorters.add({ + property: 'order', + direction: 'ASC', + }); + + me.reload(); + }, + }, + + listeners: { + selectionchange: 'select', + itemdblclick: 'editSnapshot', + destroy: 'cancel', + }, + + layout: 'fit', + rootVisible: false, + animate: false, + sortableColumns: false, + + tbar: [ + { + xtype: 'proxmoxButton', + text: gettext('Take Snapshot'), + disabled: true, + bind: { + disabled: "{!canSnapshot}", + }, + handler: 'newSnapshot', + }, + { + xtype: 'proxmoxButton', + text: gettext('Rollback'), + disabled: true, + bind: { + disabled: '{!canRollback}', + }, + confirmMsg: function() { + let view = this.up('treepanel'); + let rec = view.getSelection()[0]; + let vmid = view.getViewModel().get('vmid'); + return Proxmox.Utils.format_task_description('qmrollback', vmid) + + " '" + rec.data.name + "'"; + }, + handler: 'rollback', + }, + { + xtype: 'proxmoxButton', + text: gettext('Remove'), + disabled: true, + bind: { + disabled: '{!canRemove}', + }, + confirmMsg: function() { + let view = this.up('treepanel'); + let rec = view.getSelection()[0]; + return Ext.String.format( + gettext('Are you sure you want to remove entry {0}'), + `'${rec.data.name}'` + ); + }, + handler: 'remove', + }, + { + xtype: 'proxmoxButton', + text: gettext('Edit'), + bind: { + text: '{buttonText}', + disabled: '{!isSnapshot}', + }, + disabled: true, + edit: true, + handler: 'editSnapshot', + } + ], + + columnLines: true, + + fields: [ + 'name', 'description', 'snapstate', 'vmstate', 'running', + { name: 'snaptime', type: 'date', dateFormat: 'timestamp' }, + { + name: 'order', + calculate: function(data) { + return data.snaptime || (data.name === 'current' ? 'ZZZ' : data.snapstate); + } + } + ], + + columns: [ + { + xtype: 'treecolumn', + text: gettext('Name'), + dataIndex: 'name', + width: 200, + renderer: function(value, metaData, record) { + if (value === 'current') { + return gettext('NOW'); + } else { + return value; + } + } + }, + { + text: gettext('RAM'), + hidden: true, + bind: { + hidden: '{!showMemory}', + }, + align: 'center', + resizable: false, + dataIndex: 'vmstate', + width: 50, + renderer: function(value, metaData, record) { + if (record.data.name !== 'current') { + return Proxmox.Utils.format_boolean(value); + } + } + }, + { + text: gettext('Date') + "/" + gettext("Status"), + dataIndex: 'snaptime', + width: 150, + renderer: function(value, metaData, record) { + if (record.data.snapstate) { + return record.data.snapstate; + } + if (value) { + return Ext.Date.format(value,'Y-m-d H:i:s'); + } + } + }, + { + text: gettext('Description'), + dataIndex: 'description', + flex: 1, + renderer: function(value, metaData, record) { + if (record.data.name === 'current') { + return gettext("You are here!"); + } else { + return Ext.String.htmlEncode(value); + } + } + } + ], + +}); -- 2.20.1 _______________________________________________ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel