]> git.proxmox.com Git - pve-manager-legacy.git/blame - www/manager/tree/ResourceTree.js
resource tree : display template icon is vm is a template
[pve-manager-legacy.git] / www / manager / tree / ResourceTree.js
CommitLineData
5910d3b7
DM
1Ext.define('PVE.tree.ResourceTree', {
2 extend: 'Ext.tree.TreePanel',
5910d3b7
DM
3 alias: ['widget.pveResourceTree'],
4
5 statics: {
6 typeDefaults: {
7 node: {
8 iconCls: 'x-tree-node-server',
50c1c8a5 9 text: gettext('Node list')
5910d3b7 10 },
996d34c3
DM
11 pool: {
12 iconCls: 'x-tree-node-pool',
13 text: gettext('Resource Pool')
14 },
5910d3b7
DM
15 storage: {
16 iconCls: 'x-tree-node-harddisk',
50c1c8a5 17 text: gettext('Storage list')
5910d3b7
DM
18 },
19 qemu: {
20 iconCls: 'x-tree-node-computer',
6c37b50f 21 text: gettext('Virtual Machine')
5910d3b7
DM
22 },
23 openvz: {
52943683 24 iconCls: 'x-tree-node-openvz',
6c37b50f 25 text: gettext('OpenVZ Container')
5910d3b7
DM
26 }
27 }
28 },
29
30 // private
31 nodeSortFn: function(node1, node2) {
32 var n1 = node1.data;
33 var n2 = node2.data;
34
35 if ((n1.groupbyid && n2.groupbyid) ||
36 !(n1.groupbyid || n2.groupbyid)) {
37
38 var tcmp;
39
40 var v1 = n1.type;
41 var v2 = n2.type;
42
43 if ((tcmp = v1 > v2 ? 1 : (v1 < v2 ? -1 : 0)) != 0) {
44 return tcmp;
45 }
46
47 // numeric compare for VM IDs
48 if (v1 === 'qemu' || v1 === 'openvz') {
49 v1 = n1.vmid;
50 v2 = n2.vmid;
51 if ((tcmp = v1 > v2 ? 1 : (v1 < v2 ? -1 : 0)) != 0) {
52 return tcmp;
53 }
54 }
55
56 return n1.text > n2.text ? 1 : (n1.text < n2.text ? -1 : 0);
57 } else if (n1.groupbyid) {
58 return -1;
59 } else if (n2.groupbyid) {
60 return 1;
61 }
62 },
63
64 // private: fast binary search
65 findInsertIndex: function(node, child, start, end) {
66 var me = this;
67
68 var diff = end - start;
69
70 var mid = start + (diff>>1);
71
72 if (diff <= 0) {
73 return start;
74 }
75
76 var res = me.nodeSortFn(child, node.childNodes[mid]);
77 if (res <= 0) {
78 return me.findInsertIndex(node, child, start, mid);
79 } else {
80 return me.findInsertIndex(node, child, mid + 1, end);
81 }
82 },
83
d30bec0a 84 setIconCls: function(info) {
5910d3b7
DM
85 var me = this;
86
87 var defaults = PVE.tree.ResourceTree.typeDefaults[info.type];
88 if (defaults && defaults.iconCls) {
7152cde1
AD
89 var running = info.running ? '-running' : '';
90 var template = info.template ? '-template' : '';
91 info.iconCls = defaults.iconCls + running + template;
5910d3b7 92 }
d30bec0a
DM
93 },
94
95 // private
96 addChildSorted: function(node, info) {
97 var me = this;
98
99 me.setIconCls(info);
5910d3b7 100
d30bec0a 101 var defaults;
5910d3b7
DM
102 if (info.groupbyid) {
103 info.text = info.groupbyid;
104 if (info.type === 'type') {
105 defaults = PVE.tree.ResourceTree.typeDefaults[info.groupbyid];
106 if (defaults && defaults.text) {
107 info.text = defaults.text;
108 }
109 }
110 }
111 var child = Ext.ModelMgr.create(info, 'PVETree', info.id);
112
113 var cs = node.childNodes;
114 var pos;
115 if (cs) {
116 pos = cs[me.findInsertIndex(node, child, 0, cs.length)];
117 }
118
5910d3b7 119 node.insertBefore(child, pos);
5910d3b7
DM
120
121 return child;
122 },
123
124 // private
125 groupChild: function(node, info, groups, level) {
126 var me = this;
127
128 var groupby = groups[level];
129 var v = info[groupby];
130
131 if (v) {
132 var group = node.findChild('groupbyid', v);
133 if (!group) {
134 var groupinfo;
135 if (info.type === groupby) {
136 groupinfo = info;
137 } else {
138 groupinfo = {
139 type: groupby,
140 id : groupby + "/" + v
141 };
142 if (groupby !== 'type') {
143 groupinfo[groupby] = v;
144 }
145 }
146 groupinfo.leaf = false;
147 groupinfo.groupbyid = v;
148 group = me.addChildSorted(node, groupinfo);
149 // fixme: remove when EXTJS has fixed those bugs?!
150 group.expand(); group.collapse();
151 }
152 if (info.type === groupby) {
153 return group;
154 }
155 if (group) {
156 return me.groupChild(group, info, groups, level + 1);
157 }
158 }
159
160 return me.addChildSorted(node, info);
161 },
162
163 initComponent : function() {
164 var me = this;
165
166 var rstore = PVE.data.ResourceStore;
167 var sp = Ext.state.Manager.getProvider();
168
169 if (!me.viewFilter) {
170 me.viewFilter = {};
171 }
172
173 var pdata = {
174 dataIndex: {},
175 updateCount: 0
176 };
177
178 var store = Ext.create('Ext.data.TreeStore', {
179 model: 'PVETree',
180 root: {
181 expanded: true,
182 id: 'root',
50c1c8a5 183 text: gettext('Datacenter')
5910d3b7
DM
184 }
185 });
186
187 var stateid = 'rid';
188
189 var updateTree = function() {
190 var tmp;
191
192 // fixme: suspend events ?
193
194 var rootnode = me.store.getRootNode();
195
196 // remember selected node (and all parents)
197 var sm = me.getSelectionModel();
198
199 var lastsel = sm.getSelection()[0];
200 var parents = [];
201 var p = lastsel;
202 while (p && !!(p = p.parentNode)) {
203 parents.push(p);
204 }
205
206 var index = pdata.dataIndex;
207
208 var groups = me.viewFilter.groups || [];
209 var filterfn = me.viewFilter.filterfn;
210
211 // remove vanished or changed items
212 var key;
213 for (key in index) {
214 if (index.hasOwnProperty(key)) {
215 var olditem = index[key];
216
217 // getById() use find(), which is slow (ExtJS4 DP5)
218 //var item = rstore.getById(olditem.data.id);
219 var item = rstore.data.get(olditem.data.id);
220
221 var changed = false;
222 if (item) {
223 // test if any grouping attributes changed
224 var i, len;
225 for (i = 0, len = groups.length; i < len; i++) {
226 var attr = groups[i];
227 if (item.data[attr] != olditem.data[attr]) {
228 //console.log("changed " + attr);
229 changed = true;
230 break;
231 }
232 }
233 if ((item.data.text !== olditem.data.text) ||
2a0bc39f 234 (item.data.node !== olditem.data.node) ||
5910d3b7 235 (item.data.running !== olditem.data.running)) {
2a0bc39f 236 //console.log("changed node/text/running " + olditem.data.id);
5910d3b7
DM
237 changed = true;
238 }
239
240 // fixme: also test filterfn()?
241 }
242
243 if (!item || changed) {
244 //console.log("REM UID: " + key + " ITEM " + olditem.data.id);
d30bec0a
DM
245 if (olditem.isLeaf()) {
246 delete index[key];
247 var parentNode = olditem.parentNode;
248 parentNode.removeChild(olditem, true);
249 } else {
250 if (item && changed) {
251 olditem.beginEdit();
252 //console.log("REM UPDATE UID: " + key + " ITEM " + item.data.running);
253 var info = olditem.data;
254 Ext.apply(info, item.data);
255 me.setIconCls(info);
256 olditem.commit();
257 }
258 }
5910d3b7
DM
259 }
260 }
261 }
262
263 // add new items
264 rstore.each(function(item) {
265 var olditem = index[item.data.id];
266 if (olditem) {
267 return;
268 }
269
270 if (filterfn && !filterfn(item)) {
271 return;
272 }
273
274 //console.log("ADD UID: " + item.data.id);
275
276 var info = Ext.apply({ leaf: true }, item.data);
277
278 var child = me.groupChild(rootnode, info, groups, 0);
279 if (child) {
280 index[item.data.id] = child;
281 }
282 });
283
284 // select parent node is selection vanished
285 if (lastsel && !rootnode.findChild('id', lastsel.data.id, true)) {
286 lastsel = rootnode;
287 while (!!(p = parents.shift())) {
288 if (!!(tmp = rootnode.findChild('id', p.data.id, true))) {
289 lastsel = tmp;
290 break;
291 }
292 }
293 me.selectById(lastsel.data.id);
294 }
295
296 if (!pdata.updateCount) {
297 rootnode.collapse();
298 rootnode.expand();
299 me.applyState(sp.get(stateid));
300 }
301
302 pdata.updateCount++;
303 };
304
305 var statechange = function(sp, key, value) {
306 if (key === stateid) {
307 me.applyState(value);
308 }
309 };
310
311 sp.on('statechange', statechange);
312
313 Ext.apply(me, {
314 store: store,
315 viewConfig: {
316 // note: animate cause problems with applyState
317 animate: false
318 },
319 //useArrows: true,
320 //rootVisible: false,
a9a1e2f2 321 //title: 'Resource Tree',
5910d3b7 322 listeners: {
b82d8626
DM
323 itemcontextmenu: function(v, record, item, index, event) {
324 event.stopEvent();
325 //v.select(record);
326 var menu;
327
328 if (record.data.type === 'qemu') {
329 menu = Ext.create('PVE.qemu.CmdMenu', {
47b80718 330 pveSelNode: record
b82d8626
DM
331 });
332 } else if (record.data.type === 'openvz') {
333 menu = Ext.create('PVE.openvz.CmdMenu', {
47b80718 334 pveSelNode: record
b82d8626
DM
335 });
336 } else {
337 return;
338 }
339
340 menu.showAt(event.getXY());
341 },
5910d3b7
DM
342 destroy: function() {
343 rstore.un("load", updateTree);
344 }
345 },
346 setViewFilter: function(view) {
347 me.viewFilter = view;
348 me.clearTree();
349 updateTree();
350 },
351 clearTree: function() {
352 pdata.updateCount = 0;
353 var rootnode = me.store.getRootNode();
354 rootnode.collapse();
355 rootnode.removeAll(true);
356 pdata.dataIndex = {};
357 me.getSelectionModel().deselectAll();
358 },
31cd039b
DM
359 selectExpand: function(node) {
360 var sm = me.getSelectionModel();
361 if (!sm.isSelected(node)) {
362 sm.select(node);
363 var cn = node;
364 while (!!(cn = cn.parentNode)) {
365 if (!cn.isExpanded()) {
366 cn.expand();
367 }
368 }
369 }
370 },
5910d3b7
DM
371 selectById: function(nodeid) {
372 var rootnode = me.store.getRootNode();
373 var sm = me.getSelectionModel();
374 var node;
375 if (nodeid === 'root') {
376 node = rootnode;
377 } else {
378 node = rootnode.findChild('id', nodeid, true);
379 }
380 if (node) {
31cd039b
DM
381 me.selectExpand(node);
382 }
383 },
2a0bc39f 384 checkVmMigration: function(record) {
31cd039b
DM
385 if (!(record.data.type === 'qemu' || record.data.type === 'openvz')) {
386 throw "not a vm type";
387 }
388
389 var rootnode = me.store.getRootNode();
390 var node = rootnode.findChild('id', record.data.id, true);
391
392 if (node && node.data.type === record.data.type &&
393 node.data.node !== record.data.node) {
394 // defer select (else we get strange errors)
f6e64492 395 Ext.defer(function() { me.selectExpand(node); }, 100, me);
5910d3b7
DM
396 }
397 },
398 applyState : function(state) {
399 var sm = me.getSelectionModel();
400 if (state && state.value) {
401 me.selectById(state.value);
402 } else {
403 sm.deselectAll();
404 }
405 }
406 });
407
408 me.callParent();
409
410 var sm = me.getSelectionModel();
411 sm.on('select', function(sm, n) {
412 sp.set(stateid, { value: n.data.id});
413 });
414
415 rstore.on("load", updateTree);
416 rstore.startUpdate();
417 //rstore.stopUpdate();
418 }
419
420});