]>
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'),
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
)) {
55 if ((tcmp
= v1
> v2
? 1 : (v1
< v2
? -1 : 0)) != 0) {
59 // numeric compare for VM IDs
60 // sort templates after regular VMs
61 if (v1
=== 'qemu' || v1
=== 'lxc') {
62 if (n1
.template
&& !n2
.template
) {
64 } else if (n2
.template
&& !n1
.template
) {
69 if ((tcmp
= v1
> v2
? 1 : (v1
< v2
? -1 : 0)) != 0) {
74 return n1
.id
> n2
.id
? 1 : (n1
.id
< n2
.id
? -1 : 0);
75 } else if (n1
.groupbyid
) {
77 } else if (n2
.groupbyid
) {
82 // private: fast binary search
83 findInsertIndex: function(node
, child
, start
, end
) {
86 var diff
= end
- start
;
88 var mid
= start
+ (diff
>>1);
94 var res
= me
.nodeSortFn(child
, node
.childNodes
[mid
]);
96 return me
.findInsertIndex(node
, child
, start
, mid
);
98 return me
.findInsertIndex(node
, child
, mid
+ 1, end
);
102 setIconCls: function(info
) {
105 var cls
= PVE
.Utils
.get_object_icon_class(info
.type
, info
);
112 // add additional elements to text
113 // at the moment only the usage indicator for storages
114 setText: function(info
) {
118 if (info
.type
=== 'storage') {
119 var maxdisk
= info
.maxdisk
;
120 var disk
= info
.disk
;
121 var usage
= disk
/maxdisk
;
123 if (usage
<= 1.0 && usage
>= 0.0) {
124 var height
= (usage
*100).toFixed(0);
125 var neg_height
= (100-usage
*100).toFixed(0);
126 status
= '<div class="usage-wrapper">';
127 status
+= '<div class="usage-negative" style="height: ';
128 status
+= neg_height
+ '%"></div>';
129 status
+= '<div class="usage" style="height: '+ height
+'%"></div>';
134 info
.text
= status
+ info
.text
;
137 setToolTip: function(info
) {
138 if (info
.type
=== 'pool' || info
.groupbyid
!== undefined) {
142 var qtips
= [gettext('Status') + ': ' + (info
.qmpstatus
|| info
.status
)];
144 qtips
.push('Config locked (' + info
.lock
+ ')');
146 if (info
.hastate
!= 'unmanaged') {
147 qtips
.push(gettext('HA State') + ": " + info
.hastate
);
150 info
.qtip
= qtips
.join(', ');
154 addChildSorted: function(node
, info
) {
162 if (info
.groupbyid
) {
163 info
.text
= info
.groupbyid
;
164 if (info
.type
=== 'type') {
165 defaults
= PVE
.tree
.ResourceTree
.typeDefaults
[info
.groupbyid
];
166 if (defaults
&& defaults
.text
) {
167 info
.text
= defaults
.text
;
171 var child
= Ext
.create('PVETree', info
);
173 var cs
= node
.childNodes
;
176 pos
= cs
[me
.findInsertIndex(node
, child
, 0, cs
.length
)];
179 node
.insertBefore(child
, pos
);
185 groupChild: function(node
, info
, groups
, level
) {
188 var groupby
= groups
[level
];
189 var v
= info
[groupby
];
192 var group
= node
.findChild('groupbyid', v
);
195 if (info
.type
=== groupby
) {
200 id
: groupby
+ "/" + v
,
202 if (groupby
!== 'type') {
203 groupinfo
[groupby
] = v
;
206 groupinfo
.leaf
= false;
207 groupinfo
.groupbyid
= v
;
208 group
= me
.addChildSorted(node
, groupinfo
);
210 if (info
.type
=== groupby
) {
214 return me
.groupChild(group
, info
, groups
, level
+ 1);
218 return me
.addChildSorted(node
, info
);
221 initComponent: function() {
224 var rstore
= PVE
.data
.ResourceStore
;
225 var sp
= Ext
.state
.Manager
.getProvider();
227 if (!me
.viewFilter
) {
236 var store
= Ext
.create('Ext.data.TreeStore', {
241 text
: gettext('Datacenter'),
242 iconCls
: 'fa fa-server',
248 var updateTree = function() {
251 store
.suspendEvents();
253 var rootnode
= me
.store
.getRootNode();
254 // remember selected node (and all parents)
255 var sm
= me
.getSelectionModel();
257 var lastsel
= sm
.getSelection()[0];
258 var reselect
= false;
261 while (p
&& !!(p
= p
.parentNode
)) {
265 var index
= pdata
.dataIndex
;
267 var groups
= me
.viewFilter
.groups
|| [];
268 var filterfn
= me
.viewFilter
.filterfn
;
270 // remove vanished or moved items
271 // update in place changed items
274 if (index
.hasOwnProperty(key
)) {
275 var olditem
= index
[key
];
277 // getById() use find(), which is slow (ExtJS4 DP5)
278 //var item = rstore.getById(olditem.data.id);
279 var item
= rstore
.data
.get(olditem
.data
.id
);
284 // test if any grouping attributes changed
285 // this will also catch migrated nodes
288 for (i
= 0, len
= groups
.length
; i
< len
; i
++) {
289 var attr
= groups
[i
];
290 if (item
.data
[attr
] != olditem
.data
[attr
]) {
291 //console.log("changed " + attr);
297 // explicitly check for node, since
298 // in some views, node is not a grouping
300 if (!moved
&& item
.data
.node
!== olditem
.data
.node
) {
304 // tree item has been updated
306 'text', 'running', 'template', 'status',
307 'qmpstatus', 'hastate', 'lock',
311 for (i
= 0; i
< fields
.length
; i
++) {
313 if (item
.data
[field
] !== olditem
.data
[field
]) {
319 // fixme: also test filterfn()?
324 //console.log("REM UPDATE UID: " + key + " ITEM " + item.data.running);
325 var info
= olditem
.data
;
326 Ext
.apply(info
, item
.data
);
332 if ((!item
|| moved
) && olditem
.isLeaf()) {
333 //console.log("REM UID: " + key + " ITEM " + olditem.data.id);
335 var parentNode
= olditem
.parentNode
;
336 // when the selected item disappears,
337 // we have to deselect it here, and reselect it
339 if (lastsel
&& olditem
.data
.id
=== lastsel
.data
.id
) {
341 sm
.deselect(olditem
);
343 // since the store events are suspended, we
344 // manually remove the item from the store also
345 store
.remove(olditem
);
346 parentNode
.removeChild(olditem
, true);
352 rstore
.each(function(item
) {
353 var olditem
= index
[item
.data
.id
];
358 if (filterfn
&& !filterfn(item
)) {
362 //console.log("ADD UID: " + item.data.id);
364 var info
= Ext
.apply({ leaf
: true }, item
.data
);
366 var child
= me
.groupChild(rootnode
, info
, groups
, 0);
368 index
[item
.data
.id
] = child
;
372 store
.resumeEvents();
373 store
.fireEvent('refresh', store
);
375 // select parent node is selection vanished
376 if (lastsel
&& !rootnode
.findChild('id', lastsel
.data
.id
, true)) {
378 while (!!(p
= parents
.shift())) {
379 if (!!(tmp
= rootnode
.findChild('id', p
.data
.id
, true))) {
384 me
.selectById(lastsel
.data
.id
);
385 } else if (lastsel
&& reselect
) {
386 me
.selectById(lastsel
.data
.id
);
389 // on first tree load set the selection from the stateful provider
390 if (!pdata
.updateCount
) {
392 me
.applyState(sp
.get(stateid
));
398 var statechange = function(sp
, key
, value
) {
399 if (key
=== stateid
) {
400 me
.applyState(value
);
404 sp
.on('statechange', statechange
);
407 allowSelection
: true,
410 // note: animate cause problems with applyState
414 //rootVisible: false,
415 //title: 'Resource Tree',
417 itemcontextmenu
: PVE
.Utils
.createCmdMenu
,
418 destroy: function() {
419 rstore
.un("load", updateTree
);
421 beforecellmousedown: function(tree
, td
, cellIndex
, record
, tr
, rowIndex
, ev
) {
422 var sm
= me
.getSelectionModel();
423 // disable selection when right clicking
424 // except the record is already selected
425 me
.allowSelection
= (ev
.button
!== 2) || sm
.isSelected(record
);
427 beforeselect: function(tree
, record
, index
, eopts
) {
428 var allow
= me
.allowSelection
;
429 me
.allowSelection
= true;
432 itemdblclick
: PVE
.Utils
.openTreeConsole
,
434 setViewFilter: function(view
) {
435 me
.viewFilter
= view
;
439 setDatacenterText: function(clustername
) {
440 var rootnode
= me
.store
.getRootNode();
442 var rnodeText
= gettext('Datacenter');
443 if (clustername
!== undefined) {
444 rnodeText
+= ' (' + clustername
+ ')';
447 rootnode
.beginEdit();
448 rootnode
.data
.text
= rnodeText
;
451 clearTree: function() {
452 pdata
.updateCount
= 0;
453 var rootnode
= me
.store
.getRootNode();
455 rootnode
.removeAll();
456 pdata
.dataIndex
= {};
457 me
.getSelectionModel().deselectAll();
459 selectExpand: function(node
) {
460 var sm
= me
.getSelectionModel();
461 if (!sm
.isSelected(node
)) {
464 while (!!(cn
= cn
.parentNode
)) {
465 if (!cn
.isExpanded()) {
469 me
.getView().focusRow(node
);
472 selectById: function(nodeid
) {
473 var rootnode
= me
.store
.getRootNode();
474 var sm
= me
.getSelectionModel();
476 if (nodeid
=== 'root') {
479 node
= rootnode
.findChild('id', nodeid
, true);
482 me
.selectExpand(node
);
486 applyState: function(state
) {
487 var sm
= me
.getSelectionModel();
488 if (state
&& state
.value
) {
489 me
.selectById(state
.value
);
498 var sm
= me
.getSelectionModel();
499 sm
.on('select', function(sm
, n
) {
500 sp
.set(stateid
, { value
: n
.data
.id
});
503 rstore
.on("load", updateTree
);
504 rstore
.startUpdate();
505 //rstore.stopUpdate();