]> git.proxmox.com Git - pve-manager.git/blob - www/manager6/qemu/SnapshotTree.js
use Proxmox.Utils instead of PVE.Utils
[pve-manager.git] / www / manager6 / qemu / SnapshotTree.js
1 Ext.define('PVE.qemu.SnapshotTree', {
2 extend: 'Ext.tree.Panel',
3 alias: ['widget.pveQemuSnapshotTree'],
4
5 load_delay: 3000,
6
7 old_digest: 'invalid',
8
9 stateful: true,
10 stateId: 'grid-qemu-snapshots',
11
12 sorterFn: function(rec1, rec2) {
13 var v1 = rec1.data.snaptime;
14 var v2 = rec2.data.snaptime;
15
16 if (rec1.data.name === 'current') {
17 return 1;
18 }
19 if (rec2.data.name === 'current') {
20 return -1;
21 }
22
23 return (v1 > v2 ? 1 : (v1 < v2 ? -1 : 0));
24 },
25
26 reload: function(repeat) {
27 var me = this;
28
29 Proxmox.Utils.API2Request({
30 url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/snapshot',
31 method: 'GET',
32 failure: function(response, opts) {
33 Proxmox.Utils.setErrorMask(me, response.htmlStatus);
34 me.load_task.delay(me.load_delay);
35 },
36 success: function(response, opts) {
37 Proxmox.Utils.setErrorMask(me, false);
38 var digest = 'invalid';
39 var idhash = {};
40 var root = { name: '__root', expanded: true, children: [] };
41 Ext.Array.each(response.result.data, function(item) {
42 item.leaf = true;
43 item.children = [];
44 if (item.name === 'current') {
45 digest = item.digest + item.running;
46 if (item.running) {
47 item.iconCls = 'fa fa-fw fa-desktop x-fa-tree-running';
48 } else {
49 item.iconCls = 'fa fa-fw fa-desktop x-fa-tree';
50 }
51 } else {
52 item.iconCls = 'fa fa-fw fa-history x-fa-tree';
53 }
54 idhash[item.name] = item;
55 });
56
57 if (digest !== me.old_digest) {
58 me.old_digest = digest;
59
60 Ext.Array.each(response.result.data, function(item) {
61 if (item.parent && idhash[item.parent]) {
62 var parent_item = idhash[item.parent];
63 parent_item.children.push(item);
64 parent_item.leaf = false;
65 parent_item.expanded = true;
66 parent_item.expandable = false;
67 } else {
68 root.children.push(item);
69 }
70 });
71
72 me.setRootNode(root);
73 }
74
75 me.load_task.delay(me.load_delay);
76 }
77 });
78
79 Proxmox.Utils.API2Request({
80 url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/feature',
81 params: { feature: 'snapshot' },
82 method: 'GET',
83 success: function(response, options) {
84 var res = response.result.data;
85 if (res.hasFeature) {
86 var snpBtns = Ext.ComponentQuery.query('#snapshotBtn');
87 snpBtns.forEach(function(item){
88 item.enable();
89 });
90 }
91 }
92 });
93
94
95 },
96
97 listeners: {
98 beforestatesave: function(grid, state, eopts) {
99 // extjs cannot serialize functions,
100 // so a the sorter with only the sorterFn will
101 // not be a valid sorter when restoring the state
102 delete state.storeState.sorters;
103 }
104 },
105
106 initComponent: function() {
107 var me = this;
108
109 me.nodename = me.pveSelNode.data.node;
110 if (!me.nodename) {
111 throw "no node name specified";
112 }
113
114 me.vmid = me.pveSelNode.data.vmid;
115 if (!me.vmid) {
116 throw "no VM ID specified";
117 }
118
119 me.load_task = new Ext.util.DelayedTask(me.reload, me);
120
121 var sm = Ext.create('Ext.selection.RowModel', {});
122
123 var valid_snapshot = function(record) {
124 return record && record.data && record.data.name &&
125 record.data.name !== 'current';
126 };
127
128 var valid_snapshot_rollback = function(record) {
129 return record && record.data && record.data.name &&
130 record.data.name !== 'current' && !record.data.snapstate;
131 };
132
133 var run_editor = function() {
134 var rec = sm.getSelection()[0];
135 if (valid_snapshot(rec)) {
136 var win = Ext.create('PVE.window.Snapshot', {
137 snapname: rec.data.name,
138 nodename: me.nodename,
139 vmid: me.vmid
140 });
141 win.show();
142 me.mon(win, 'close', me.reload, me);
143 }
144 };
145
146 var editBtn = new Proxmox.button.Button({
147 text: gettext('Edit'),
148 disabled: true,
149 selModel: sm,
150 enableFn: valid_snapshot,
151 handler: run_editor
152 });
153
154 var rollbackBtn = new Proxmox.button.Button({
155 text: gettext('Rollback'),
156 disabled: true,
157 selModel: sm,
158 enableFn: valid_snapshot_rollback,
159 confirmMsg: function(rec) {
160 return Proxmox.Utils.format_task_description('qmrollback', me.vmid) +
161 " '" + rec.data.name + "'";
162 },
163 handler: function(btn, event) {
164 var rec = sm.getSelection()[0];
165 if (!rec) {
166 return;
167 }
168 var snapname = rec.data.name;
169
170 Proxmox.Utils.API2Request({
171 url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/snapshot/' + snapname + '/rollback',
172 method: 'POST',
173 waitMsgTarget: me,
174 callback: function() {
175 me.reload();
176 },
177 failure: function (response, opts) {
178 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
179 },
180 success: function(response, options) {
181 var upid = response.result.data;
182 var win = Ext.create('PVE.window.TaskProgress', { upid: upid });
183 win.show();
184 }
185 });
186 }
187 });
188
189 var removeBtn = new Proxmox.button.Button({
190 text: gettext('Remove'),
191 disabled: true,
192 selModel: sm,
193 confirmMsg: function(rec) {
194 var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
195 "'" + rec.data.name + "'");
196 return msg;
197 },
198 enableFn: valid_snapshot,
199 handler: function(btn, event) {
200 var rec = sm.getSelection()[0];
201 if (!rec) {
202 return;
203 }
204 var snapname = rec.data.name;
205
206 Proxmox.Utils.API2Request({
207 url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/snapshot/' + snapname,
208 method: 'DELETE',
209 waitMsgTarget: me,
210 callback: function() {
211 me.reload();
212 },
213 failure: function (response, opts) {
214 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
215 },
216 success: function(response, options) {
217 var upid = response.result.data;
218 var win = Ext.create('PVE.window.TaskProgress', { upid: upid });
219 win.show();
220 }
221 });
222 }
223 });
224
225 var snapshotBtn = Ext.create('Ext.Button', {
226 itemId: 'snapshotBtn',
227 text: gettext('Take Snapshot'),
228 disabled: true,
229 handler: function() {
230 var win = Ext.create('PVE.window.Snapshot', {
231 nodename: me.nodename,
232 vmid: me.vmid
233 });
234 win.show();
235 }
236 });
237
238 Ext.apply(me, {
239 layout: 'fit',
240 rootVisible: false,
241 animate: false,
242 sortableColumns: false,
243 selModel: sm,
244 tbar: [ snapshotBtn, rollbackBtn, removeBtn, editBtn ],
245 fields: [
246 'name', 'description', 'snapstate', 'vmstate', 'running',
247 { name: 'snaptime', type: 'date', dateFormat: 'timestamp' }
248 ],
249 columns: [
250 {
251 xtype: 'treecolumn',
252 text: gettext('Name'),
253 dataIndex: 'name',
254 width: 200,
255 renderer: function(value, metaData, record) {
256 if (value === 'current') {
257 return "NOW";
258 } else {
259 return value;
260 }
261 }
262 },
263 {
264 text: gettext('RAM'),
265 align: 'center',
266 resizable: false,
267 dataIndex: 'vmstate',
268 width: 50,
269 renderer: function(value, metaData, record) {
270 if (record.data.name !== 'current') {
271 return Proxmox.Utils.format_boolean(value);
272 }
273 }
274 },
275 {
276 text: gettext('Date') + "/" + gettext("Status"),
277 dataIndex: 'snaptime',
278 width: 150,
279 renderer: function(value, metaData, record) {
280 if (record.data.snapstate) {
281 return record.data.snapstate;
282 }
283 if (value) {
284 return Ext.Date.format(value,'Y-m-d H:i:s');
285 }
286 }
287 },
288 {
289 text: gettext('Description'),
290 dataIndex: 'description',
291 flex: 1,
292 renderer: function(value, metaData, record) {
293 if (record.data.name === 'current') {
294 return gettext("You are here!");
295 } else {
296 return Ext.String.htmlEncode(value);
297 }
298 }
299 }
300 ],
301 columnLines: true, // will work in 4.1?
302 listeners: {
303 activate: me.reload,
304 destroy: me.load_task.cancel,
305 itemdblclick: run_editor
306 }
307 });
308
309 me.callParent();
310
311 me.store.sorters.add(new Ext.util.Sorter({
312 sorterFn: me.sorterFn
313 }));
314 }
315 });
316