]>
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-sdn-vnet',
27 iconCls
: 'fa fa-desktop',
28 text
: gettext('Virtual Machine')
31 //iconCls: 'x-tree-node-lxc',
32 iconCls
: 'fa fa-cube',
33 text
: gettext('LXC Container')
36 iconCls
: 'fa fa-file-o'
44 nodeSortFn: function(node1
, node2
) {
48 if ((n1
.groupbyid
&& n2
.groupbyid
) ||
49 !(n1
.groupbyid
|| n2
.groupbyid
)) {
56 if ((tcmp
= v1
> v2
? 1 : (v1
< v2
? -1 : 0)) != 0) {
60 // numeric compare for VM IDs
61 // sort templates after regular VMs
62 if (v1
=== 'qemu' || v1
=== 'lxc') {
63 if (n1
.template
&& !n2
.template
) {
65 } else if (n2
.template
&& !n1
.template
) {
70 if ((tcmp
= v1
> v2
? 1 : (v1
< v2
? -1 : 0)) != 0) {
75 return n1
.id
> n2
.id
? 1 : (n1
.id
< n2
.id
? -1 : 0);
76 } else if (n1
.groupbyid
) {
78 } else if (n2
.groupbyid
) {
83 // private: fast binary search
84 findInsertIndex: function(node
, child
, start
, end
) {
87 var diff
= end
- start
;
89 var mid
= start
+ (diff
>>1);
95 var res
= me
.nodeSortFn(child
, node
.childNodes
[mid
]);
97 return me
.findInsertIndex(node
, child
, start
, mid
);
99 return me
.findInsertIndex(node
, child
, mid
+ 1, end
);
103 setIconCls: function(info
) {
106 var cls
= PVE
.Utils
.get_object_icon_class(info
.type
, info
);
113 // add additional elements to text
114 // at the moment only the usage indicator for storages
115 setText: function(info
) {
119 if (info
.type
=== 'storage') {
120 var maxdisk
= info
.maxdisk
;
121 var disk
= info
.disk
;
122 var usage
= disk
/maxdisk
;
124 if (usage
<= 1.0 && usage
>= 0.0) {
125 var height
= (usage
*100).toFixed(0);
126 var neg_height
= (100-usage
*100).toFixed(0);
127 status
= '<div class="usage-wrapper">';
128 status
+= '<div class="usage-negative" style="height: ';
129 status
+= neg_height
+ '%"></div>';
130 status
+= '<div class="usage" style="height: '+ height
+'%"></div>';
135 info
.text
= status
+ info
.text
;
138 setToolTip: function(info
) {
139 if (info
.type
=== 'pool' || info
.groupbyid
!== undefined) {
143 var qtips
= [gettext('Status') + ': ' + (info
.qmpstatus
|| info
.status
)];
145 qtips
.push('Config locked (' + info
.lock
+ ')');
147 if (info
.hastate
!= 'unmanaged') {
148 qtips
.push(gettext('HA State') + ": " + info
.hastate
);
151 info
.qtip
= qtips
.join(', ');
155 addChildSorted: function(node
, info
) {
163 if (info
.groupbyid
) {
164 info
.text
= info
.groupbyid
;
165 if (info
.type
=== 'type') {
166 defaults
= PVE
.tree
.ResourceTree
.typeDefaults
[info
.groupbyid
];
167 if (defaults
&& defaults
.text
) {
168 info
.text
= defaults
.text
;
172 var child
= Ext
.create('PVETree', info
);
174 var cs
= node
.childNodes
;
177 pos
= cs
[me
.findInsertIndex(node
, child
, 0, cs
.length
)];
180 node
.insertBefore(child
, pos
);
186 groupChild: function(node
, info
, groups
, level
) {
189 var groupby
= groups
[level
];
190 var v
= info
[groupby
];
193 var group
= node
.findChild('groupbyid', v
);
196 if (info
.type
=== groupby
) {
201 id
: groupby
+ "/" + v
203 if (groupby
!== 'type') {
204 groupinfo
[groupby
] = v
;
207 groupinfo
.leaf
= false;
208 groupinfo
.groupbyid
= v
;
209 group
= me
.addChildSorted(node
, groupinfo
);
211 if (info
.type
=== groupby
) {
215 return me
.groupChild(group
, info
, groups
, level
+ 1);
219 return me
.addChildSorted(node
, info
);
222 initComponent : function() {
225 var rstore
= PVE
.data
.ResourceStore
;
226 var sp
= Ext
.state
.Manager
.getProvider();
228 if (!me
.viewFilter
) {
237 var store
= Ext
.create('Ext.data.TreeStore', {
242 text
: gettext('Datacenter'),
243 iconCls
: 'fa fa-server'
249 var updateTree = function() {
252 store
.suspendEvents();
254 var rootnode
= me
.store
.getRootNode();
255 // remember selected node (and all parents)
256 var sm
= me
.getSelectionModel();
258 var lastsel
= sm
.getSelection()[0];
259 var reselect
= false;
262 while (p
&& !!(p
= p
.parentNode
)) {
266 var index
= pdata
.dataIndex
;
268 var groups
= me
.viewFilter
.groups
|| [];
269 var filterfn
= me
.viewFilter
.filterfn
;
271 // remove vanished or moved items
272 // update in place changed items
275 if (index
.hasOwnProperty(key
)) {
276 var olditem
= index
[key
];
278 // getById() use find(), which is slow (ExtJS4 DP5)
279 //var item = rstore.getById(olditem.data.id);
280 var item
= rstore
.data
.get(olditem
.data
.id
);
285 // test if any grouping attributes changed
286 // this will also catch migrated nodes
289 for (i
= 0, len
= groups
.length
; i
< len
; i
++) {
290 var attr
= groups
[i
];
291 if (item
.data
[attr
] != olditem
.data
[attr
]) {
292 //console.log("changed " + attr);
298 // explicitly check for node, since
299 // in some views, node is not a grouping
301 if (!moved
&& item
.data
.node
!== olditem
.data
.node
) {
305 // tree item has been updated
307 'text', 'running', 'template', 'status',
308 'qmpstatus', 'hastate', 'lock'
312 for (i
= 0; i
< fields
.length
; i
++) {
314 if (item
.data
[field
] !== olditem
.data
[field
]) {
320 // fixme: also test filterfn()?
325 //console.log("REM UPDATE UID: " + key + " ITEM " + item.data.running);
326 var info
= olditem
.data
;
327 Ext
.apply(info
, item
.data
);
333 if ((!item
|| moved
) && olditem
.isLeaf()) {
334 //console.log("REM UID: " + key + " ITEM " + olditem.data.id);
336 var parentNode
= olditem
.parentNode
;
337 // when the selected item disappears,
338 // we have to deselect it here, and reselect it
340 if (lastsel
&& olditem
.data
.id
=== lastsel
.data
.id
) {
342 sm
.deselect(olditem
);
344 // since the store events are suspended, we
345 // manually remove the item from the store also
346 store
.remove(olditem
);
347 parentNode
.removeChild(olditem
, true);
353 rstore
.each(function(item
) {
354 var olditem
= index
[item
.data
.id
];
359 if (filterfn
&& !filterfn(item
)) {
363 //console.log("ADD UID: " + item.data.id);
365 var info
= Ext
.apply({ leaf
: true }, item
.data
);
367 var child
= me
.groupChild(rootnode
, info
, groups
, 0);
369 index
[item
.data
.id
] = child
;
373 store
.resumeEvents();
374 store
.fireEvent('refresh', store
);
376 // select parent node is selection vanished
377 if (lastsel
&& !rootnode
.findChild('id', lastsel
.data
.id
, true)) {
379 while (!!(p
= parents
.shift())) {
380 if (!!(tmp
= rootnode
.findChild('id', p
.data
.id
, true))) {
385 me
.selectById(lastsel
.data
.id
);
386 } else if (lastsel
&& reselect
) {
387 me
.selectById(lastsel
.data
.id
);
390 // on first tree load set the selection from the stateful provider
391 if (!pdata
.updateCount
) {
393 me
.applyState(sp
.get(stateid
));
399 var statechange = function(sp
, key
, value
) {
400 if (key
=== stateid
) {
401 me
.applyState(value
);
405 sp
.on('statechange', statechange
);
408 allowSelection
: true,
411 // note: animate cause problems with applyState
415 //rootVisible: false,
416 //title: 'Resource Tree',
418 itemcontextmenu
: PVE
.Utils
.createCmdMenu
,
419 destroy: function() {
420 rstore
.un("load", updateTree
);
422 beforecellmousedown: function (tree
, td
, cellIndex
, record
, tr
, rowIndex
, ev
) {
423 var sm
= me
.getSelectionModel();
424 // disable selection when right clicking
425 // except the record is already selected
426 me
.allowSelection
= (ev
.button
!== 2) || sm
.isSelected(record
);
428 beforeselect: function (tree
, record
, index
, eopts
) {
429 var allow
= me
.allowSelection
;
430 me
.allowSelection
= true;
433 itemdblclick
: PVE
.Utils
.openTreeConsole
435 setViewFilter: function(view
) {
436 me
.viewFilter
= view
;
440 setDatacenterText: function(clustername
) {
441 var rootnode
= me
.store
.getRootNode();
443 var rnodeText
= gettext('Datacenter');
444 if (clustername
!== undefined) {
445 rnodeText
+= ' (' + clustername
+ ')';
448 rootnode
.beginEdit();
449 rootnode
.data
.text
= rnodeText
;
452 clearTree: function() {
453 pdata
.updateCount
= 0;
454 var rootnode
= me
.store
.getRootNode();
456 rootnode
.removeAll();
457 pdata
.dataIndex
= {};
458 me
.getSelectionModel().deselectAll();
460 selectExpand: function(node
) {
461 var sm
= me
.getSelectionModel();
462 if (!sm
.isSelected(node
)) {
465 while (!!(cn
= cn
.parentNode
)) {
466 if (!cn
.isExpanded()) {
470 me
.getView().focusRow(node
);
473 selectById: function(nodeid
) {
474 var rootnode
= me
.store
.getRootNode();
475 var sm
= me
.getSelectionModel();
477 if (nodeid
=== 'root') {
480 node
= rootnode
.findChild('id', nodeid
, true);
483 me
.selectExpand(node
);
487 applyState : function(state
) {
488 var sm
= me
.getSelectionModel();
489 if (state
&& state
.value
) {
490 me
.selectById(state
.value
);
499 var sm
= me
.getSelectionModel();
500 sm
.on('select', function(sm
, n
) {
501 sp
.set(stateid
, { value
: n
.data
.id
});
504 rstore
.on("load", updateTree
);
505 rstore
.startUpdate();
506 //rstore.stopUpdate();