]> git.proxmox.com Git - pve-manager.git/blobdiff - www/manager6/tree/ResourceTree.js
gui: add lock to resource store and tree
[pve-manager.git] / www / manager6 / tree / ResourceTree.js
index ee3dd44df68c8c58757535d088e13364ca490cce..360e7e73b5e033a7548fbe1337e8e0656ec666dc 100644 (file)
@@ -8,31 +8,28 @@ Ext.define('PVE.tree.ResourceTree', {
     statics: {
        typeDefaults: {
            node: { 
-               iconCls: 'fa fa-building  x-fa-tree',
+               iconCls: 'fa fa-building',
                text: gettext('Nodes')
            },
            pool: { 
-               iconCls: 'fa fa-tags fa-dark  x-fa-tree',
+               iconCls: 'fa fa-tags',
                text: gettext('Resource Pool')
            },
            storage: {
-               iconCls: 'fa fa-database fa-dark  x-fa-tree',
+               iconCls: 'fa fa-database',
                text: gettext('Storage')
            },
            qemu: {
-               iconCls: 'fa fa-desktop  x-fa-tree',
+               iconCls: 'fa fa-desktop',
                text: gettext('Virtual Machine')
            },
            lxc: {
                //iconCls: 'x-tree-node-lxc',
-               iconCls: 'fa fa-cube  x-fa-tree',
+               iconCls: 'fa fa-cube',
                text: gettext('LXC Container')
            },
            template: {
-               iconCls: 'fa fa-file-o fa-dark  x-fa-tree-template'
-           },
-           datacenter: {
-               iconCls: 'fa fa-server x-fa-tree-datacenter'
+               iconCls: 'fa fa-file-o'
            }
        }
     },
@@ -71,7 +68,7 @@ Ext.define('PVE.tree.ResourceTree', {
                }
            }
 
-           return n1.text > n2.text ? 1 : (n1.text < n2.text ? -1 : 0);
+           return n1.id > n2.id ? 1 : (n1.id < n2.id ? -1 : 0);
        } else if (n1.groupbyid) {
            return -1;
        } else if (n2.groupbyid) {
@@ -102,36 +99,49 @@ Ext.define('PVE.tree.ResourceTree', {
     setIconCls: function(info) {
        var me = this;
 
-       var defaults = PVE.tree.ResourceTree.typeDefaults[info.type];
-       if (info.id === 'root') {
-           defaults = PVE.tree.ResourceTree.typeDefaults.datacenter;
-       } else if (info.type === 'type') {
-           defaults = PVE.tree.ResourceTree.typeDefaults[info.groupbyid];
+       var cls = PVE.Utils.get_object_icon_class(info.type, info);
+
+       if (cls !== '') {
+           info.iconCls = cls;
        }
-       if (defaults && defaults.iconCls) {
-           var iconClsAdd = '';
-
-           if (info.running && info.type === 'node') {
-               iconClsAdd = '-online';
-           } else if (info.running) {
-               iconClsAdd = '-running';
-               if (info.status === 'paused') {
-                   iconClsAdd = '-paused';
-               }
-           } else if (info.type === 'lxc' || info.type === 'qemu') {
-               iconClsAdd = '-stopped';
-           } else if (info.type === 'node') {
-               iconClsAdd = '-offline';
-           }
+    },
 
-           info.iconCls = defaults.iconCls + iconClsAdd;
+    // add additional elements to text
+    // at the moment only the usage indicator for storages
+    setText: function(info) {
+       var me = this;
 
-           if (info.template) {
-               iconClsAdd = '-template';
-               info.iconCls = PVE.tree.ResourceTree.typeDefaults.template.iconCls + '-' + info.type;
+       var status = '';
+       if (info.type === 'storage') {
+           var maxdisk = info.maxdisk;
+           var disk = info.disk;
+           var usage = disk/maxdisk;
+           var cls = '';
+           if (usage <= 1.0 && usage >= 0.0) {
+               var height = (usage*100).toFixed(0);
+               var neg_height = (100-usage*100).toFixed(0);
+               status = '<div class="usage-wrapper">';
+               status += '<div class="usage-negative" style="height: ';
+               status += neg_height + '%"></div>';
+               status += '<div class="usage" style="height: '+ height +'%"></div>';
+               status += '</div> ';
            }
+       }
+
+       info.text = status + info.text;
+    },
+
+    setToolTip: function(info) {
+       if (info.type === 'pool' || info.groupbyid !== undefined) {
+           return;
+       }
 
+       var qtips = [gettext('Status') + ': ' + (info.qmpstatus || info.status)];
+       if (info.hastate != 'unmanaged') {
+           qtips.push(gettext('HA State') + ": " + info.hastate);
        }
+
+       info.qtip = qtips.join(', ');
     },
 
     // private
@@ -139,10 +149,12 @@ Ext.define('PVE.tree.ResourceTree', {
        var me = this;
 
        me.setIconCls(info);
+       me.setText(info);
+       me.setToolTip(info);
 
        var defaults;
        if (info.groupbyid) {
-           info.text = info.groupbyid;     
+           info.text = info.groupbyid;
            if (info.type === 'type') {
                defaults = PVE.tree.ResourceTree.typeDefaults[info.groupbyid];
                if (defaults && defaults.text) {
@@ -188,8 +200,6 @@ Ext.define('PVE.tree.ResourceTree', {
                groupinfo.leaf = false;
                groupinfo.groupbyid = v; 
                group = me.addChildSorted(node, groupinfo);
-               // fixme: remove when EXTJS has fixed those bugs?!
-               group.expand(); group.collapse();
            }
            if (info.type === groupby) {
                return group;
@@ -222,7 +232,8 @@ Ext.define('PVE.tree.ResourceTree', {
            root: {
                expanded: true,
                id: 'root',
-               text: gettext('Datacenter')
+               text: gettext('Datacenter'),
+               iconCls: 'fa fa-server'
            }
        });
 
@@ -231,14 +242,14 @@ Ext.define('PVE.tree.ResourceTree', {
        var updateTree = function() {
            var tmp;
 
-           // fixme: suspend events ?
+           store.suspendEvents();
 
            var rootnode = me.store.getRootNode();
-           me.setIconCls(rootnode.data);
            // remember selected node (and all parents)
            var sm = me.getSelectionModel();
 
            var lastsel = sm.getSelection()[0];
+           var reselect = false;
            var parents = [];
            var p = lastsel;
            while (p && !!(p = p.parentNode)) {
@@ -285,12 +296,18 @@ Ext.define('PVE.tree.ResourceTree', {
                        }
 
                        // tree item has been updated
-                       if ((item.data.text !== olditem.data.text) ||
-                           (item.data.running !== olditem.data.running) ||
-                           (item.data.template !== olditem.data.template) ||
-                           (item.data.status !== olditem.data.status)) {
-                           //console.log("changed node/text/running " + olditem.data.id);
-                           changed = true;
+                       var fields = [
+                           'text', 'running', 'template', 'status',
+                           'qmpstatus', 'hastate', 'lock'
+                       ];
+
+                       var field;
+                       for (i = 0; i < fields.length; i++) {
+                           field = fields[i];
+                           if (item.data[field] !== olditem.data[field]) {
+                               changed = true;
+                               break;
+                           }
                        }
 
                        // fixme: also test filterfn()?
@@ -302,12 +319,24 @@ Ext.define('PVE.tree.ResourceTree', {
                        var info = olditem.data;
                        Ext.apply(info, item.data);
                        me.setIconCls(info);
+                       me.setText(info);
+                       me.setToolTip(info);
                        olditem.commit();
                    }
                    if ((!item || moved) && olditem.isLeaf()) {
                        //console.log("REM UID: " + key + " ITEM " + olditem.data.id);
                        delete index[key];
                        var parentNode = olditem.parentNode;
+                       // when the selected item disappears,
+                       // we have to deselect it here, and reselect it
+                       // later
+                       if (lastsel && olditem.data.id === lastsel.data.id) {
+                           reselect = true;
+                           sm.deselect(olditem);
+                       }
+                       // since the store events are suspended, we
+                       // manually remove the item from the store also
+                       store.remove(olditem);
                        parentNode.removeChild(olditem, true);
                    }
                }
@@ -334,6 +363,9 @@ Ext.define('PVE.tree.ResourceTree', {
                }
            });
 
+           store.resumeEvents();
+           store.fireEvent('refresh', store);
+
            // select parent node is selection vanished
            if (lastsel && !rootnode.findChild('id', lastsel.data.id, true)) {
                lastsel = rootnode;
@@ -344,11 +376,12 @@ Ext.define('PVE.tree.ResourceTree', {
                    }
                }
                me.selectById(lastsel.data.id);
+           } else if (lastsel && reselect) {
+               me.selectById(lastsel.data.id);
            }
 
            // on first tree load set the selection from the stateful provider
            if (!pdata.updateCount) {
-               rootnode.collapse();
                rootnode.expand();
                me.applyState(sp.get(stateid));
            }
@@ -380,20 +413,35 @@ Ext.define('PVE.tree.ResourceTree', {
                    rstore.un("load", updateTree);
                },
                beforecellmousedown: function (tree, td, cellIndex, record, tr, rowIndex, ev) {
+                   var sm = me.getSelectionModel();
                    // disable selection when right clicking
-                   me.allowSelection = (ev.button !== 2);
+                   // except the record is already selected
+                   me.allowSelection = (ev.button !== 2) || sm.isSelected(record);
                },
                beforeselect: function (tree, record, index, eopts) {
                    var allow = me.allowSelection;
                    me.allowSelection = true;
                    return allow;
-               }
+               },
+               itemdblclick: PVE.Utils.openTreeConsole
            },
            setViewFilter: function(view) {
                me.viewFilter = view;
                me.clearTree();
                updateTree();
            },
+           setDatacenterText: function(clustername) {
+               var rootnode = me.store.getRootNode();
+
+               var rnodeText = gettext('Datacenter');
+               if (clustername !== undefined) {
+                   rnodeText += ' (' + clustername + ')';
+               }
+
+               rootnode.beginEdit();
+               rootnode.data.text = rnodeText;
+               rootnode.commit();
+           },
            clearTree: function() {
                pdata.updateCount = 0;
                var rootnode = me.store.getRootNode();
@@ -427,20 +475,7 @@ Ext.define('PVE.tree.ResourceTree', {
                if (node) {
                    me.selectExpand(node);
                }
-           },
-           checkVmMigration: function(record) {
-               if (!(record.data.type === 'qemu' || record.data.type === 'lxc')) {
-                   throw "not a vm type";
-               }
-
-               var rootnode = me.store.getRootNode();
-               var node = rootnode.findChild('id', record.data.id, true);
-
-               if (node && node.data.type === record.data.type &&
-                   node.data.node !== record.data.node) {
-                   // defer select (else we get strange errors)
-                   Ext.defer(function() { me.selectExpand(node); }, 100, me);
-               }
+               return node;
            },
            applyState : function(state) {
                var sm = me.getSelectionModel();