]>
git.proxmox.com Git - pve-manager.git/blob - www/manager6/tree/ResourceTree.js
2 * Left Treepanel, containing all the resources we manage in this datacenter: server nodes, server storages, VMs and Containers
4 Ext
.define('PVE.tree.ResourceTree', {
5 extend
: 'Ext.tree.TreePanel',
6 alias
: ['widget.pveResourceTree'],
11 iconCls
: 'fa fa-building',
12 text
: gettext('Nodes')
15 iconCls
: 'fa fa-tags',
16 text
: gettext('Resource Pool')
19 iconCls
: 'fa fa-database',
20 text
: gettext('Storage')
23 iconCls
: 'fa fa-desktop',
24 text
: gettext('Virtual Machine')
27 //iconCls: 'x-tree-node-lxc',
28 iconCls
: 'fa fa-cube',
29 text
: gettext('LXC Container')
32 iconCls
: 'fa fa-file-o'
40 nodeSortFn: function(node1
, node2
) {
44 if ((n1
.groupbyid
&& n2
.groupbyid
) ||
45 !(n1
.groupbyid
|| n2
.groupbyid
)) {
52 if ((tcmp
= v1
> v2
? 1 : (v1
< v2
? -1 : 0)) != 0) {
56 // numeric compare for VM IDs
57 // sort templates after regular VMs
58 if (v1
=== 'qemu' || v1
=== 'lxc') {
59 if (n1
.template
&& !n2
.template
) {
61 } else if (n2
.template
&& !n1
.template
) {
66 if ((tcmp
= v1
> v2
? 1 : (v1
< v2
? -1 : 0)) != 0) {
71 return n1
.id
> n2
.id
? 1 : (n1
.id
< n2
.id
? -1 : 0);
72 } else if (n1
.groupbyid
) {
74 } else if (n2
.groupbyid
) {
79 // private: fast binary search
80 findInsertIndex: function(node
, child
, start
, end
) {
83 var diff
= end
- start
;
85 var mid
= start
+ (diff
>>1);
91 var res
= me
.nodeSortFn(child
, node
.childNodes
[mid
]);
93 return me
.findInsertIndex(node
, child
, start
, mid
);
95 return me
.findInsertIndex(node
, child
, mid
+ 1, end
);
99 setIconCls: function(info
) {
102 var cls
= PVE
.Utils
.get_object_icon_class(info
.type
, info
);
109 // add additional elements to text
110 // at the moment only the usage indicator for storages
111 setText: function(info
) {
115 if (info
.type
=== 'storage') {
116 var maxdisk
= info
.maxdisk
;
117 var disk
= info
.disk
;
118 var usage
= disk
/maxdisk
;
120 if (usage
<= 1.0 && usage
>= 0.0) {
121 var height
= (usage
*100).toFixed(0);
122 var neg_height
= (100-usage
*100).toFixed(0);
123 status
= '<div class="usage-wrapper">';
124 status
+= '<div class="usage-negative" style="height: ';
125 status
+= neg_height
+ '%"></div>';
126 status
+= '<div class="usage" style="height: '+ height
+'%"></div>';
131 info
.text
= status
+ info
.text
;
134 setToolTip: function(info
) {
135 if (info
.type
=== 'pool' || info
.groupbyid
!== undefined) {
139 var qtips
= [gettext('Status') + ': ' + (info
.qmpstatus
|| info
.status
)];
141 qtips
.push('Config locked (' + info
.lock
+ ')');
143 if (info
.hastate
!= 'unmanaged') {
144 qtips
.push(gettext('HA State') + ": " + info
.hastate
);
147 info
.qtip
= qtips
.join(', ');
151 addChildSorted: function(node
, info
) {
159 if (info
.groupbyid
) {
160 info
.text
= info
.groupbyid
;
161 if (info
.type
=== 'type') {
162 defaults
= PVE
.tree
.ResourceTree
.typeDefaults
[info
.groupbyid
];
163 if (defaults
&& defaults
.text
) {
164 info
.text
= defaults
.text
;
168 var child
= Ext
.create('PVETree', info
);
170 var cs
= node
.childNodes
;
173 pos
= cs
[me
.findInsertIndex(node
, child
, 0, cs
.length
)];
176 node
.insertBefore(child
, pos
);
182 groupChild: function(node
, info
, groups
, level
) {
185 var groupby
= groups
[level
];
186 var v
= info
[groupby
];
189 var group
= node
.findChild('groupbyid', v
);
192 if (info
.type
=== groupby
) {
197 id
: groupby
+ "/" + v
199 if (groupby
!== 'type') {
200 groupinfo
[groupby
] = v
;
203 groupinfo
.leaf
= false;
204 groupinfo
.groupbyid
= v
;
205 group
= me
.addChildSorted(node
, groupinfo
);
207 if (info
.type
=== groupby
) {
211 return me
.groupChild(group
, info
, groups
, level
+ 1);
215 return me
.addChildSorted(node
, info
);
218 initComponent : function() {
221 var rstore
= PVE
.data
.ResourceStore
;
222 var sp
= Ext
.state
.Manager
.getProvider();
224 if (!me
.viewFilter
) {
233 var store
= Ext
.create('Ext.data.TreeStore', {
238 text
: gettext('Datacenter'),
239 iconCls
: 'fa fa-server'
245 var updateTree = function() {
248 store
.suspendEvents();
250 var rootnode
= me
.store
.getRootNode();
251 // remember selected node (and all parents)
252 var sm
= me
.getSelectionModel();
254 var lastsel
= sm
.getSelection()[0];
255 var reselect
= false;
258 while (p
&& !!(p
= p
.parentNode
)) {
262 var index
= pdata
.dataIndex
;
264 var groups
= me
.viewFilter
.groups
|| [];
265 var filterfn
= me
.viewFilter
.filterfn
;
267 // remove vanished or moved items
268 // update in place changed items
271 if (index
.hasOwnProperty(key
)) {
272 var olditem
= index
[key
];
274 // getById() use find(), which is slow (ExtJS4 DP5)
275 //var item = rstore.getById(olditem.data.id);
276 var item
= rstore
.data
.get(olditem
.data
.id
);
281 // test if any grouping attributes changed
282 // this will also catch migrated nodes
285 for (i
= 0, len
= groups
.length
; i
< len
; i
++) {
286 var attr
= groups
[i
];
287 if (item
.data
[attr
] != olditem
.data
[attr
]) {
288 //console.log("changed " + attr);
294 // explicitly check for node, since
295 // in some views, node is not a grouping
297 if (!moved
&& item
.data
.node
!== olditem
.data
.node
) {
301 // tree item has been updated
303 'text', 'running', 'template', 'status',
304 'qmpstatus', 'hastate', 'lock'
308 for (i
= 0; i
< fields
.length
; i
++) {
310 if (item
.data
[field
] !== olditem
.data
[field
]) {
316 // fixme: also test filterfn()?
321 //console.log("REM UPDATE UID: " + key + " ITEM " + item.data.running);
322 var info
= olditem
.data
;
323 Ext
.apply(info
, item
.data
);
329 if ((!item
|| moved
) && olditem
.isLeaf()) {
330 //console.log("REM UID: " + key + " ITEM " + olditem.data.id);
332 var parentNode
= olditem
.parentNode
;
333 // when the selected item disappears,
334 // we have to deselect it here, and reselect it
336 if (lastsel
&& olditem
.data
.id
=== lastsel
.data
.id
) {
338 sm
.deselect(olditem
);
340 // since the store events are suspended, we
341 // manually remove the item from the store also
342 store
.remove(olditem
);
343 parentNode
.removeChild(olditem
, true);
349 rstore
.each(function(item
) {
350 var olditem
= index
[item
.data
.id
];
355 if (filterfn
&& !filterfn(item
)) {
359 //console.log("ADD UID: " + item.data.id);
361 var info
= Ext
.apply({ leaf
: true }, item
.data
);
363 var child
= me
.groupChild(rootnode
, info
, groups
, 0);
365 index
[item
.data
.id
] = child
;
369 store
.resumeEvents();
370 store
.fireEvent('refresh', store
);
372 // select parent node is selection vanished
373 if (lastsel
&& !rootnode
.findChild('id', lastsel
.data
.id
, true)) {
375 while (!!(p
= parents
.shift())) {
376 if (!!(tmp
= rootnode
.findChild('id', p
.data
.id
, true))) {
381 me
.selectById(lastsel
.data
.id
);
382 } else if (lastsel
&& reselect
) {
383 me
.selectById(lastsel
.data
.id
);
386 // on first tree load set the selection from the stateful provider
387 if (!pdata
.updateCount
) {
389 me
.applyState(sp
.get(stateid
));
395 var statechange = function(sp
, key
, value
) {
396 if (key
=== stateid
) {
397 me
.applyState(value
);
401 sp
.on('statechange', statechange
);
404 allowSelection
: true,
407 // note: animate cause problems with applyState
411 //rootVisible: false,
412 //title: 'Resource Tree',
414 itemcontextmenu
: PVE
.Utils
.createCmdMenu
,
415 destroy: function() {
416 rstore
.un("load", updateTree
);
418 beforecellmousedown: function (tree
, td
, cellIndex
, record
, tr
, rowIndex
, ev
) {
419 var sm
= me
.getSelectionModel();
420 // disable selection when right clicking
421 // except the record is already selected
422 me
.allowSelection
= (ev
.button
!== 2) || sm
.isSelected(record
);
424 beforeselect: function (tree
, record
, index
, eopts
) {
425 var allow
= me
.allowSelection
;
426 me
.allowSelection
= true;
429 itemdblclick
: PVE
.Utils
.openTreeConsole
431 setViewFilter: function(view
) {
432 me
.viewFilter
= view
;
436 setDatacenterText: function(clustername
) {
437 var rootnode
= me
.store
.getRootNode();
439 var rnodeText
= gettext('Datacenter');
440 if (clustername
!== undefined) {
441 rnodeText
+= ' (' + clustername
+ ')';
444 rootnode
.beginEdit();
445 rootnode
.data
.text
= rnodeText
;
448 clearTree: function() {
449 pdata
.updateCount
= 0;
450 var rootnode
= me
.store
.getRootNode();
452 rootnode
.removeAll();
453 pdata
.dataIndex
= {};
454 me
.getSelectionModel().deselectAll();
456 selectExpand: function(node
) {
457 var sm
= me
.getSelectionModel();
458 if (!sm
.isSelected(node
)) {
461 while (!!(cn
= cn
.parentNode
)) {
462 if (!cn
.isExpanded()) {
466 me
.getView().focusRow(node
);
469 selectById: function(nodeid
) {
470 var rootnode
= me
.store
.getRootNode();
471 var sm
= me
.getSelectionModel();
473 if (nodeid
=== 'root') {
476 node
= rootnode
.findChild('id', nodeid
, true);
479 me
.selectExpand(node
);
483 applyState : function(state
) {
484 var sm
= me
.getSelectionModel();
485 if (state
&& state
.value
) {
486 me
.selectById(state
.value
);
495 var sm
= me
.getSelectionModel();
496 sm
.on('select', function(sm
, n
) {
497 sp
.set(stateid
, { value
: n
.data
.id
});
500 rstore
.on("load", updateTree
);
501 rstore
.startUpdate();
502 //rstore.stopUpdate();