]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/tree/SnapshotTree.js
ui snapshot: improve template string usage
[pve-manager.git] / www / manager6 / tree / SnapshotTree.js
CommitLineData
5b1b9360
DC
1Ext.define('PVE.guest.SnapshotTree', {
2 extend: 'Ext.tree.Panel',
3 xtype: 'pveGuestSnapshotTree',
4
5 stateful: true,
6 stateId: 'grid-snapshots',
7
8 viewModel: {
9 data: {
10 // should be 'qemu' or 'lxc'
11 type: undefined,
12 nodename: undefined,
13 vmid: undefined,
14 snapshotAllowed: false,
15 rollbackAllowed: false,
16 snapshotFeature: false,
17 selected: '',
18 load_delay: 3000,
19 },
20 formulas: {
b9c780c5
TL
21 canSnapshot: (get) => get('snapshotAllowed') && get('snapshotFeature'),
22 canRollback: (get) => get('rollbackAllowed') && get('isSnapshot'),
23 canRemove: (get) => get('snapshotAllowed') && get('isSnapshot'),
24 isSnapshot: (get) => get('selected') && get('selected') !== 'current',
25 buttonText: (get) => gettext(get('snapshotAllowed') ? 'Edit' : 'View'),
26 showMemory: (get) => get('type') === 'qemu',
5b1b9360
DC
27 },
28 },
29
30 controller: {
31 xclass: 'Ext.app.ViewController',
32
33 newSnapshot: function() {
34 this.run_editor(false);
35 },
36
37 editSnapshot: function() {
38 this.run_editor(true);
39 },
40
41 run_editor: function(edit) {
42 let me = this;
43 let vm = me.getViewModel();
44 let snapname;
45 if (edit) {
46 snapname = vm.get('selected');
47 if (!snapname || snapname === 'current') { return; }
48 }
49 let win = Ext.create('PVE.window.Snapshot', {
50 nodename: vm.get('nodename'),
51 vmid: vm.get('vmid'),
52 viewonly: !vm.get('snapshotAllowed'),
53 type: vm.get('type'),
54 isCreate: !edit,
55 submitText: !edit ? gettext('Take Snapshot') : undefined,
56 snapname: snapname,
57 });
58 win.show();
59 me.mon(win, 'destroy', me.reload, me);
60 },
61
62 snapshotAction: function(action, method) {
63 let me = this;
64 let view = me.getView();
65 let vm = me.getViewModel();
66 let snapname = vm.get('selected');
67 if (!snapname) { return; }
68
69 let nodename = vm.get('nodename');
70 let type = vm.get('type');
71 let vmid = vm.get('vmid');
72
73 Proxmox.Utils.API2Request({
74 url: `/nodes/${nodename}/${type}/${vmid}/snapshot/${snapname}/${action}`,
75 method: method,
76 waitMsgTarget: view,
77 callback: function() {
78 me.reload();
79 },
80 failure: function (response, opts) {
81 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
82 },
83 success: function(response, options) {
84 var upid = response.result.data;
85 var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
86 win.show();
87 }
88 });
89 },
90
9a6b894f
TL
91 rollback: function() {
92 this.snapshotAction('rollback', 'POST');
93 },
94 remove: function() {
95 this.snapshotAction('', 'DELETE');
96 },
5b1b9360
DC
97 cancel: function() {
98 this.load_task.cancel();
99 },
100
101 reload: function() {
102 let me = this;
103 let view = me.getView();
104 let vm = me.getViewModel();
105 let nodename = vm.get('nodename');
106 let vmid = vm.get('vmid');
107 let type = vm.get('type');
108 let load_delay = vm.get('load_delay');
109
110 Proxmox.Utils.API2Request({
111 url: `/nodes/${nodename}/${type}/${vmid}/snapshot`,
112 method: 'GET',
113 failure: function(response, opts) {
114 Proxmox.Utils.setErrorMask(view, response.htmlStatus);
115 me.load_task.delay(load_delay);
116 },
117 success: function(response, opts) {
118 Proxmox.Utils.setErrorMask(view, false);
119 var digest = 'invalid';
120 var idhash = {};
121 var root = { name: '__root', expanded: true, children: [] };
122 Ext.Array.each(response.result.data, function(item) {
123 item.leaf = true;
124 item.children = [];
125 if (item.name === 'current') {
126 digest = item.digest + item.running;
127 item.iconCls = PVE.Utils.get_object_icon_class(vm.get('type'), item);
128 } else {
129 item.iconCls = 'fa fa-fw fa-history x-fa-tree';
130 }
131 idhash[item.name] = item;
132 });
133
134 if (digest !== me.old_digest) {
135 me.old_digest = digest;
136
137 Ext.Array.each(response.result.data, function(item) {
138 if (item.parent && idhash[item.parent]) {
139 var parent_item = idhash[item.parent];
140 parent_item.children.push(item);
141 parent_item.leaf = false;
142 parent_item.expanded = true;
143 parent_item.expandable = false;
144 } else {
145 root.children.push(item);
146 }
147 });
148
149 me.getView().setRootNode(root);
150 }
151
152 me.load_task.delay(load_delay);
153 }
154 });
155
156 // if we do not have the permissions, we don't have to check
157 // if we can create a snapshot, since the butten stays disabled
158 if (!vm.get('snapshotAllowed')) {
159 return;
160 }
161
162 Proxmox.Utils.API2Request({
163 url: `/nodes/${nodename}/${type}/${vmid}/feature`,
164 params: { feature: 'snapshot' },
165 method: 'GET',
166 success: function(response, options) {
9a6b894f
TL
167 let res = response.result.data;
168 vm.set('snapshotFeature', !!res.hasFeature);
169 }
5b1b9360
DC
170 });
171 },
172
173 select: function(grid, val) {
174 let vm = this.getViewModel();
175 if (val.length < 1) {
176 vm.set('selected', '');
177 return;
178 }
179 vm.set('selected', val[0].data.name);
180 },
181
182 init: function(view) {
183 let me = this;
184 let vm = me.getViewModel();
185 me.load_task = new Ext.util.DelayedTask(me.reload, me);
186
187 if (!view.type) {
188 throw 'guest type not set';
189 }
190 vm.set('type', view.type);
191
192 if (!view.pveSelNode.data.node) {
193 throw "no node name specified";
194 }
195 vm.set('nodename', view.pveSelNode.data.node);
196
197 if (!view.pveSelNode.data.vmid) {
198 throw "no VM ID specified";
199 }
200 vm.set('vmid', view.pveSelNode.data.vmid);
201
202 let caps = Ext.state.Manager.get('GuiCap');
203 vm.set('snapshotAllowed', !!caps.vms['VM.Snapshot']);
204 vm.set('rollbackAllowed', !!caps.vms['VM.Snapshot.Rollback']);
205
206 view.getStore().sorters.add({
207 property: 'order',
208 direction: 'ASC',
209 });
210
211 me.reload();
212 },
213 },
214
215 listeners: {
216 selectionchange: 'select',
217 itemdblclick: 'editSnapshot',
218 destroy: 'cancel',
219 },
220
221 layout: 'fit',
222 rootVisible: false,
223 animate: false,
224 sortableColumns: false,
225
226 tbar: [
227 {
228 xtype: 'proxmoxButton',
229 text: gettext('Take Snapshot'),
230 disabled: true,
231 bind: {
232 disabled: "{!canSnapshot}",
233 },
234 handler: 'newSnapshot',
235 },
e1af1385 236 '-',
5b1b9360
DC
237 {
238 xtype: 'proxmoxButton',
239 text: gettext('Rollback'),
240 disabled: true,
241 bind: {
242 disabled: '{!canRollback}',
243 },
244 confirmMsg: function() {
245 let view = this.up('treepanel');
246 let rec = view.getSelection()[0];
247 let vmid = view.getViewModel().get('vmid');
248 return Proxmox.Utils.format_task_description('qmrollback', vmid) +
249 " '" + rec.data.name + "'";
250 },
251 handler: 'rollback',
252 },
253 {
254 xtype: 'proxmoxButton',
255 text: gettext('Remove'),
256 disabled: true,
257 bind: {
258 disabled: '{!canRemove}',
259 },
260 confirmMsg: function() {
261 let view = this.up('treepanel');
262 let rec = view.getSelection()[0];
263 return Ext.String.format(
264 gettext('Are you sure you want to remove entry {0}'),
265 `'${rec.data.name}'`
266 );
267 },
268 handler: 'remove',
269 },
270 {
271 xtype: 'proxmoxButton',
272 text: gettext('Edit'),
273 bind: {
274 text: '{buttonText}',
275 disabled: '{!isSnapshot}',
276 },
277 disabled: true,
278 edit: true,
279 handler: 'editSnapshot',
e1af1385
TL
280 },
281 {
282 xtype: 'label',
283 text: gettext("The current guest configuration does not support taking new snapshots"),
284 hidden: true,
285 bind: {
286 hidden: "{canSnapshot}",
287 },
288 },
5b1b9360
DC
289 ],
290
291 columnLines: true,
292
293 fields: [
294 'name', 'description', 'snapstate', 'vmstate', 'running',
295 { name: 'snaptime', type: 'date', dateFormat: 'timestamp' },
296 {
297 name: 'order',
298 calculate: function(data) {
299 return data.snaptime || (data.name === 'current' ? 'ZZZ' : data.snapstate);
300 }
301 }
302 ],
303
304 columns: [
305 {
306 xtype: 'treecolumn',
307 text: gettext('Name'),
308 dataIndex: 'name',
309 width: 200,
310 renderer: function(value, metaData, record) {
311 if (value === 'current') {
312 return gettext('NOW');
313 } else {
314 return value;
315 }
316 }
317 },
318 {
319 text: gettext('RAM'),
320 hidden: true,
321 bind: {
322 hidden: '{!showMemory}',
323 },
324 align: 'center',
325 resizable: false,
326 dataIndex: 'vmstate',
327 width: 50,
328 renderer: function(value, metaData, record) {
329 if (record.data.name !== 'current') {
330 return Proxmox.Utils.format_boolean(value);
331 }
332 }
333 },
334 {
335 text: gettext('Date') + "/" + gettext("Status"),
336 dataIndex: 'snaptime',
337 width: 150,
338 renderer: function(value, metaData, record) {
339 if (record.data.snapstate) {
340 return record.data.snapstate;
341 }
342 if (value) {
343 return Ext.Date.format(value,'Y-m-d H:i:s');
344 }
345 }
346 },
347 {
348 text: gettext('Description'),
349 dataIndex: 'description',
350 flex: 1,
351 renderer: function(value, metaData, record) {
352 if (record.data.name === 'current') {
353 return gettext("You are here!");
354 } else {
355 return Ext.String.htmlEncode(value);
356 }
357 }
358 }
359 ],
360
361});