]> git.proxmox.com Git - pve-manager.git/commitdiff
rename manager5 to manager6
authorDietmar Maurer <dietmar@proxmox.com>
Fri, 13 Nov 2015 06:16:44 +0000 (07:16 +0100)
committerDietmar Maurer <dietmar@proxmox.com>
Fri, 22 Jan 2016 10:24:10 +0000 (11:24 +0100)
221 files changed:
Makefile
www/manager5/Parser.js [deleted file]
www/manager5/Readme.md [deleted file]
www/manager5/StateProvider.js [deleted file]
www/manager5/Toolkit.js [deleted file]
www/manager5/Utils.js [deleted file]
www/manager5/VNCConsole.js [deleted file]
www/manager5/Workspace.js [deleted file]
www/manager5/button/Button.js [deleted file]
www/manager5/button/ConsoleButton.js [deleted file]
www/manager5/data/DiffStore.js [deleted file]
www/manager5/data/ObjectStore.js [deleted file]
www/manager5/data/PVEProxy.js [deleted file]
www/manager5/data/ResourceStore.js [deleted file]
www/manager5/data/TimezoneStore.js [deleted file]
www/manager5/data/UpdateQueue.js [deleted file]
www/manager5/data/UpdateStore.js [deleted file]
www/manager5/data/reader/JsonObject.js [deleted file]
www/manager5/dc/ACLView.js [deleted file]
www/manager5/dc/AuthEdit.js [deleted file]
www/manager5/dc/AuthView.js [deleted file]
www/manager5/dc/Backup.js [deleted file]
www/manager5/dc/Config.js [deleted file]
www/manager5/dc/GroupEdit.js [deleted file]
www/manager5/dc/GroupView.js [deleted file]
www/manager5/dc/Log.js [deleted file]
www/manager5/dc/OptionView.js [deleted file]
www/manager5/dc/PoolEdit.js [deleted file]
www/manager5/dc/PoolView.js [deleted file]
www/manager5/dc/RoleView.js [deleted file]
www/manager5/dc/SecurityGroups.js [deleted file]
www/manager5/dc/StorageView.js [deleted file]
www/manager5/dc/Summary.js [deleted file]
www/manager5/dc/Support.js [deleted file]
www/manager5/dc/Tasks.js [deleted file]
www/manager5/dc/UserEdit.js [deleted file]
www/manager5/dc/UserView.js [deleted file]
www/manager5/form/BackupModeSelector.js [deleted file]
www/manager5/form/BondModeSelector.js [deleted file]
www/manager5/form/Boolean.js [deleted file]
www/manager5/form/BridgeSelector.js [deleted file]
www/manager5/form/BusTypeSelector.js [deleted file]
www/manager5/form/CPUModelSelector.js [deleted file]
www/manager5/form/CacheTypeSelector.js [deleted file]
www/manager5/form/Checkbox.js [deleted file]
www/manager5/form/ComboGrid.js [deleted file]
www/manager5/form/CompressionSelector.js [deleted file]
www/manager5/form/ContentTypeSelector.js [deleted file]
www/manager5/form/ControllerSelector.js [deleted file]
www/manager5/form/DayOfWeekSelector.js [deleted file]
www/manager5/form/DiskFormatSelector.js [deleted file]
www/manager5/form/DisplaySelector.js [deleted file]
www/manager5/form/EmailNotificationSelector.js [deleted file]
www/manager5/form/FileSelector.js [deleted file]
www/manager5/form/FirewallPolicySelector.js [deleted file]
www/manager5/form/GroupSelector.js [deleted file]
www/manager5/form/HotplugFeatureSelector.js [deleted file]
www/manager5/form/IPProtocolSelector.js [deleted file]
www/manager5/form/IPRefSelector.js [deleted file]
www/manager5/form/KVComboBox.js [deleted file]
www/manager5/form/LanguageSelector.js [deleted file]
www/manager5/form/MemoryField.js [deleted file]
www/manager5/form/NetworkCardSelector.js [deleted file]
www/manager5/form/NodeSelector.js [deleted file]
www/manager5/form/PoolSelector.js [deleted file]
www/manager5/form/RRDTypeSelector.js [deleted file]
www/manager5/form/RealmComboBox.js [deleted file]
www/manager5/form/RoleSelector.js [deleted file]
www/manager5/form/ScsiHwSelector.js [deleted file]
www/manager5/form/SecurityGroupSelector.js [deleted file]
www/manager5/form/SnapshotSelector.js [deleted file]
www/manager5/form/StorageSelector.js [deleted file]
www/manager5/form/TextField.js [deleted file]
www/manager5/form/UserSelector.js [deleted file]
www/manager5/form/VLanField.js [deleted file]
www/manager5/form/VMIDSelector.js [deleted file]
www/manager5/form/VNCKeyboardSelector.js [deleted file]
www/manager5/form/ViewSelector.js [deleted file]
www/manager5/form/iScsiProviderSelector.js [deleted file]
www/manager5/grid/BackupView.js [deleted file]
www/manager5/grid/CheckColumn.js [deleted file]
www/manager5/grid/FirewallAliases.js [deleted file]
www/manager5/grid/FirewallOptions.js [deleted file]
www/manager5/grid/FirewallRules.js [deleted file]
www/manager5/grid/ObjectGrid.js [deleted file]
www/manager5/grid/PendingObjectGrid.js [deleted file]
www/manager5/grid/PoolMembers.js [deleted file]
www/manager5/grid/ResourceGrid.js [deleted file]
www/manager5/grid/SelectFeature.js [deleted file]
www/manager5/panel/ConfigPanel.js [deleted file]
www/manager5/panel/Firewall.js [deleted file]
www/manager5/panel/IPSet.js [deleted file]
www/manager5/panel/InputPanel.js [deleted file]
www/manager5/panel/LogView.js [deleted file]
www/manager5/panel/NotesView.js [deleted file]
www/manager5/panel/RRDView.js [deleted file]
www/manager5/panel/StatusPanel.js [deleted file]
www/manager5/panel/SubConfigPanel.js [deleted file]
www/manager5/pool/Config.js [deleted file]
www/manager5/pool/StatusView.js [deleted file]
www/manager5/pool/Summary.js [deleted file]
www/manager5/tree/ResourceTree.js [deleted file]
www/manager5/window/Backup.js [deleted file]
www/manager5/window/Edit.js [deleted file]
www/manager5/window/LoginWindow.js [deleted file]
www/manager5/window/Migrate.js [deleted file]
www/manager5/window/MigrateAll.js [deleted file]
www/manager5/window/NotesEdit.js [deleted file]
www/manager5/window/Restore.js [deleted file]
www/manager5/window/TaskViewer.js [deleted file]
www/manager5/window/Wizard.js [deleted file]
www/manager6/Parser.js [new file with mode: 0644]
www/manager6/Readme.md [new file with mode: 0644]
www/manager6/StateProvider.js [new file with mode: 0644]
www/manager6/Toolkit.js [new file with mode: 0644]
www/manager6/Utils.js [new file with mode: 0644]
www/manager6/VNCConsole.js [new file with mode: 0644]
www/manager6/Workspace.js [new file with mode: 0644]
www/manager6/button/Button.js [new file with mode: 0644]
www/manager6/button/ConsoleButton.js [new file with mode: 0644]
www/manager6/data/DiffStore.js [new file with mode: 0644]
www/manager6/data/ObjectStore.js [new file with mode: 0644]
www/manager6/data/PVEProxy.js [new file with mode: 0644]
www/manager6/data/ResourceStore.js [new file with mode: 0644]
www/manager6/data/TimezoneStore.js [new file with mode: 0644]
www/manager6/data/UpdateQueue.js [new file with mode: 0644]
www/manager6/data/UpdateStore.js [new file with mode: 0644]
www/manager6/data/reader/JsonObject.js [new file with mode: 0644]
www/manager6/dc/ACLView.js [new file with mode: 0644]
www/manager6/dc/AuthEdit.js [new file with mode: 0644]
www/manager6/dc/AuthView.js [new file with mode: 0644]
www/manager6/dc/Backup.js [new file with mode: 0644]
www/manager6/dc/Config.js [new file with mode: 0644]
www/manager6/dc/GroupEdit.js [new file with mode: 0644]
www/manager6/dc/GroupView.js [new file with mode: 0644]
www/manager6/dc/Log.js [new file with mode: 0644]
www/manager6/dc/OptionView.js [new file with mode: 0644]
www/manager6/dc/PoolEdit.js [new file with mode: 0644]
www/manager6/dc/PoolView.js [new file with mode: 0644]
www/manager6/dc/RoleView.js [new file with mode: 0644]
www/manager6/dc/SecurityGroups.js [new file with mode: 0644]
www/manager6/dc/StorageView.js [new file with mode: 0644]
www/manager6/dc/Summary.js [new file with mode: 0644]
www/manager6/dc/Support.js [new file with mode: 0644]
www/manager6/dc/Tasks.js [new file with mode: 0644]
www/manager6/dc/UserEdit.js [new file with mode: 0644]
www/manager6/dc/UserView.js [new file with mode: 0644]
www/manager6/form/BackupModeSelector.js [new file with mode: 0644]
www/manager6/form/BondModeSelector.js [new file with mode: 0644]
www/manager6/form/Boolean.js [new file with mode: 0644]
www/manager6/form/BridgeSelector.js [new file with mode: 0644]
www/manager6/form/BusTypeSelector.js [new file with mode: 0644]
www/manager6/form/CPUModelSelector.js [new file with mode: 0644]
www/manager6/form/CacheTypeSelector.js [new file with mode: 0644]
www/manager6/form/Checkbox.js [new file with mode: 0644]
www/manager6/form/ComboGrid.js [new file with mode: 0644]
www/manager6/form/CompressionSelector.js [new file with mode: 0644]
www/manager6/form/ContentTypeSelector.js [new file with mode: 0644]
www/manager6/form/ControllerSelector.js [new file with mode: 0644]
www/manager6/form/DayOfWeekSelector.js [new file with mode: 0644]
www/manager6/form/DiskFormatSelector.js [new file with mode: 0644]
www/manager6/form/DisplaySelector.js [new file with mode: 0644]
www/manager6/form/EmailNotificationSelector.js [new file with mode: 0644]
www/manager6/form/FileSelector.js [new file with mode: 0644]
www/manager6/form/FirewallPolicySelector.js [new file with mode: 0644]
www/manager6/form/GroupSelector.js [new file with mode: 0644]
www/manager6/form/HotplugFeatureSelector.js [new file with mode: 0644]
www/manager6/form/IPProtocolSelector.js [new file with mode: 0644]
www/manager6/form/IPRefSelector.js [new file with mode: 0644]
www/manager6/form/KVComboBox.js [new file with mode: 0644]
www/manager6/form/LanguageSelector.js [new file with mode: 0644]
www/manager6/form/MemoryField.js [new file with mode: 0644]
www/manager6/form/NetworkCardSelector.js [new file with mode: 0644]
www/manager6/form/NodeSelector.js [new file with mode: 0644]
www/manager6/form/PoolSelector.js [new file with mode: 0644]
www/manager6/form/RRDTypeSelector.js [new file with mode: 0644]
www/manager6/form/RealmComboBox.js [new file with mode: 0644]
www/manager6/form/RoleSelector.js [new file with mode: 0644]
www/manager6/form/ScsiHwSelector.js [new file with mode: 0644]
www/manager6/form/SecurityGroupSelector.js [new file with mode: 0644]
www/manager6/form/SnapshotSelector.js [new file with mode: 0644]
www/manager6/form/StorageSelector.js [new file with mode: 0644]
www/manager6/form/TextField.js [new file with mode: 0644]
www/manager6/form/UserSelector.js [new file with mode: 0644]
www/manager6/form/VLanField.js [new file with mode: 0644]
www/manager6/form/VMIDSelector.js [new file with mode: 0644]
www/manager6/form/VNCKeyboardSelector.js [new file with mode: 0644]
www/manager6/form/ViewSelector.js [new file with mode: 0644]
www/manager6/form/iScsiProviderSelector.js [new file with mode: 0644]
www/manager6/grid/BackupView.js [new file with mode: 0644]
www/manager6/grid/CheckColumn.js [new file with mode: 0644]
www/manager6/grid/FirewallAliases.js [new file with mode: 0644]
www/manager6/grid/FirewallOptions.js [new file with mode: 0644]
www/manager6/grid/FirewallRules.js [new file with mode: 0644]
www/manager6/grid/ObjectGrid.js [new file with mode: 0644]
www/manager6/grid/PendingObjectGrid.js [new file with mode: 0644]
www/manager6/grid/PoolMembers.js [new file with mode: 0644]
www/manager6/grid/ResourceGrid.js [new file with mode: 0644]
www/manager6/grid/SelectFeature.js [new file with mode: 0644]
www/manager6/panel/ConfigPanel.js [new file with mode: 0644]
www/manager6/panel/Firewall.js [new file with mode: 0644]
www/manager6/panel/IPSet.js [new file with mode: 0644]
www/manager6/panel/InputPanel.js [new file with mode: 0644]
www/manager6/panel/LogView.js [new file with mode: 0644]
www/manager6/panel/NotesView.js [new file with mode: 0644]
www/manager6/panel/RRDView.js [new file with mode: 0644]
www/manager6/panel/StatusPanel.js [new file with mode: 0644]
www/manager6/panel/SubConfigPanel.js [new file with mode: 0644]
www/manager6/pool/Config.js [new file with mode: 0644]
www/manager6/pool/StatusView.js [new file with mode: 0644]
www/manager6/pool/Summary.js [new file with mode: 0644]
www/manager6/tree/ResourceTree.js [new file with mode: 0644]
www/manager6/window/Backup.js [new file with mode: 0644]
www/manager6/window/Edit.js [new file with mode: 0644]
www/manager6/window/LoginWindow.js [new file with mode: 0644]
www/manager6/window/Migrate.js [new file with mode: 0644]
www/manager6/window/MigrateAll.js [new file with mode: 0644]
www/manager6/window/NotesEdit.js [new file with mode: 0644]
www/manager6/window/Restore.js [new file with mode: 0644]
www/manager6/window/TaskViewer.js [new file with mode: 0644]
www/manager6/window/Wizard.js [new file with mode: 0644]

index 80d511da09e665d95364fb0da6ff369fd9344e56..dc5f3a518e3a0dbf22b24d4b0bf387122ce05109 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -100,8 +100,8 @@ install: country.dat vznet.conf vzdump.conf vzdump-hook-script.pl pve-apt.conf p
        install -m 0644 copyright ${DOCDIR}
        install -m 0644 debian/changelog.Debian ${DOCDIR}
        install -m 0644 country.dat ${DESTDIR}/usr/share/${PACKAGE}
-       # temporary: set ExtJS 5 migration devel directory
-       install -d ${DESTDIR}/usr/share/${PACKAGE}/manager5
+       # temporary: set ExtJS 6 migration devel directory
+       install -d ${DESTDIR}/usr/share/${PACKAGE}/manager6
        set -e && for i in ${SUBDIRS}; do ${MAKE} -C $$i $@; done
 
 .PHONY: distclean
diff --git a/www/manager5/Parser.js b/www/manager5/Parser.js
deleted file mode 100644 (file)
index 5f15a76..0000000
+++ /dev/null
@@ -1,343 +0,0 @@
-// Some configuration values are complex strings -
-// so we need parsers/generators for them.
-
-Ext.define('PVE.Parser', { statics: {
-
-    // this class only contains static functions
-
-    parseQemuNetwork: function(key, value) {
-       if (!(key && value)) {
-           return;
-       }
-
-       var res = {};
-
-       var errors = false;
-       Ext.Array.each(value.split(','), function(p) {
-           if (!p || p.match(/^\s*$/)) {
-               return; // continue
-           }
-
-           var match_res;
-
-           if ((match_res = p.match(/^(ne2k_pci|e1000|e1000-82540em|e1000-82544gc|e1000-82545em|vmxnet3|rtl8139|pcnet|virtio|ne2k_isa|i82551|i82557b|i82559er)(=([0-9a-f]{2}(:[0-9a-f]{2}){5}))?$/i)) !== null) {
-               res.model = match_res[1].toLowerCase();
-               if (match_res[3]) {
-                   res.macaddr = match_res[3];
-               }
-           } else if ((match_res = p.match(/^bridge=(\S+)$/)) !== null) {
-               res.bridge = match_res[1];
-           } else if ((match_res = p.match(/^rate=(\d+(\.\d+)?)$/)) !== null) {
-               res.rate = match_res[1];
-           } else if ((match_res = p.match(/^tag=(\d+(\.\d+)?)$/)) !== null) {
-                res.tag = match_res[1];
-           } else if ((match_res = p.match(/^firewall=(\d+)$/)) !== null) {
-                res.firewall = match_res[1];
-           } else if ((match_res = p.match(/^link_down=(\d+)$/)) !== null) {
-                res.disconnect = match_res[1];
-           } else if ((match_res = p.match(/^queues=(\d+)$/)) !== null) {
-                res.queues = match_res[1];
-           } else {
-               errors = true;
-               return false; // break
-           }
-       });
-
-       if (errors || !res.model) {
-           return;
-       }
-
-       return res;
-    },
-
-    printQemuNetwork: function(net) {
-
-       var netstr = net.model;
-       if (net.macaddr) {
-           netstr += "=" + net.macaddr;
-       }
-       if (net.bridge) {
-           netstr += ",bridge=" + net.bridge;
-           if (net.tag) {
-               netstr += ",tag=" + net.tag;
-           }
-           if (net.firewall) {
-               netstr += ",firewall=" + net.firewall;
-           }
-       }
-       if (net.rate) {
-           netstr += ",rate=" + net.rate;
-       }
-       if (net.queues) {
-           netstr += ",queues=" + net.queues;
-       }
-       if (net.disconnect) {
-           netstr += ",link_down=" + net.disconnect;
-       }
-       return netstr;
-    },
-
-    parseQemuDrive: function(key, value) {
-       if (!(key && value)) {
-           return;
-       }
-
-       var res = {};
-
-       var match_res = key.match(/^([a-z]+)(\d+)$/);
-       if (!match_res) {
-           return;
-       }
-       res['interface'] = match_res[1];
-       res.index = match_res[2];
-
-       var errors = false;
-       Ext.Array.each(value.split(','), function(p) {
-           if (!p || p.match(/^\s*$/)) {
-               return; // continue
-           }
-           var match_res = p.match(/^([a-z_]+)=(\S+)$/);
-           if (!match_res) {
-               if (!p.match(/\=/)) {
-                   res.file = p;
-                   return; // continue
-               }
-               errors = true;
-               return false; // break
-           }
-           var k = match_res[1];
-           if (k === 'volume') {
-               k = 'file';
-           }
-
-           if (Ext.isDefined(res[k])) {
-               errors = true;
-               return false; // break
-           }
-
-           var v = match_res[2];
-
-           if (k === 'cache' && v === 'off') {
-               v = 'none';
-           }
-
-           res[k] = v;
-       });
-
-       if (errors || !res.file) {
-           return;
-       }
-
-       return res;
-    },
-
-    printQemuDrive: function(drive) {
-
-       var drivestr = drive.file;
-
-       Ext.Object.each(drive, function(key, value) {
-           if (!Ext.isDefined(value) || key === 'file' ||
-               key === 'index' || key === 'interface') {
-               return; // continue
-           }
-           drivestr += ',' + key + '=' + value;
-       });
-
-       return drivestr;
-    },
-
-    parseOpenVZNetIf: function(value) {
-       if (!value) {
-           return;
-       }
-
-       var res = {};
-
-       var errors = false;
-       Ext.Array.each(value.split(';'), function(item) {
-           if (!item || item.match(/^\s*$/)) {
-               return; // continue
-           }
-
-           var data = {};
-           Ext.Array.each(item.split(','), function(p) {
-               if (!p || p.match(/^\s*$/)) {
-                   return; // continue
-               }
-               var match_res = p.match(/^(ifname|mac|bridge|host_ifname|host_mac|mac_filter)=(\S+)$/);
-               if (!match_res) {
-                   errors = true;
-                   return false; // break
-               }
-               if (match_res[1] === 'bridge'){
-                   var bridgevlanf = match_res[2];
-                   var bridge_res = bridgevlanf.match(/^(vmbr(\d+))(v(\d+))?(f)?$/);
-                   if (!bridge_res) {
-                       errors = true;
-                       return false; // break
-                   }
-                   data['bridge'] = bridge_res[1];
-                   data['tag'] = bridge_res[4];
-                   data['firewall'] = bridge_res[5] ? 1 : 0;
-               } else {
-                   data[match_res[1]] = match_res[2];
-               }
-           });
-
-           if (errors || !data.ifname) {
-               errors = true;
-               return false; // break
-           }
-
-           data.raw = item;
-
-           res[data.ifname] = data;
-       });
-
-       return errors ? undefined: res;
-    },
-
-    printOpenVZNetIf: function(netif) {
-       var netarray = [];
-
-       Ext.Object.each(netif, function(iface, data) {
-           var tmparray = [];
-           Ext.Array.each(['ifname', 'mac', 'bridge', 'host_ifname' , 'host_mac', 'mac_filter', 'tag', 'firewall'], function(key) {
-               var value = data[key];
-               if (key === 'bridge'){
-                   if(data['tag']){
-                       value = value + 'v' + data['tag'];
-                   }
-                   if (data['firewall']){
-                       value = value + 'f';
-                   }
-               }
-               if (value) {
-                   tmparray.push(key + '=' + value);
-               }
-
-           });
-           netarray.push(tmparray.join(','));
-       });
-
-       return netarray.join(';');
-    },
-
-    parseLxcNetwork: function(value) {
-       if (!value) {
-           return;
-       }
-
-       var data = {};
-       Ext.Array.each(value.split(','), function(p) {
-           if (!p || p.match(/^\s*$/)) {
-               return; // continue
-           }
-           var match_res = p.match(/^(bridge|hwaddr|mtu|name|ip|ip6|gw|gw6|firewall|tag)=(\S+)$/);
-           if (!match_res) {
-               // todo: simply ignore errors ?
-               return; // continue
-           }
-           data[match_res[1]] = match_res[2];
-       });
-
-       return data;
-    },
-
-    printLxcNetwork: function(data) {
-       var tmparray = [];
-       Ext.Array.each(['bridge', 'hwaddr', 'mtu', 'name', 'ip',
-                       'gw', 'ip6', 'gw6', 'firewall', 'tag'], function(key) {
-               var value = data[key];
-               if (value) {
-                   tmparray.push(key + '=' + value);
-               }
-       });
-       
-       return tmparray.join(',');
-    },
-
-    parseStartup: function(value) {
-       if (value === undefined) {
-           return;
-       }
-
-       var res = {};
-
-       var errors = false;
-       Ext.Array.each(value.split(','), function(p) {
-           if (!p || p.match(/^\s*$/)) {
-               return; // continue
-           }
-
-           var match_res;
-
-           if ((match_res = p.match(/^(order)?=(\d+)$/)) !== null) {
-               res.order = match_res[2];
-           } else if ((match_res = p.match(/^up=(\d+)$/)) !== null) {
-               res.up = match_res[1];
-           } else if ((match_res = p.match(/^down=(\d+)$/)) !== null) {
-                res.down = match_res[1];
-           } else {
-               errors = true;
-               return false; // break
-           }
-       });
-
-       if (errors) {
-           return;
-       }
-
-       return res;
-    },
-
-    printStartup: function(startup) {
-       var arr = [];
-       if (startup.order !== undefined && startup.order !== '') {
-           arr.push('order=' + startup.order);
-       }
-       if (startup.up !== undefined && startup.up !== '') {
-           arr.push('up=' + startup.up);
-       }
-       if (startup.down !== undefined && startup.down !== '') {
-           arr.push('down=' + startup.down);
-       }
-
-       return arr.join(',');
-    },
-
-    parseQemuSmbios1: function(value) {
-       var res = {};
-
-       Ext.Array.each(value.split(','), function(p) {
-           var kva = p.split(/=/, 2);
-           res[kva[0]] = kva[1];
-       });
-
-       return res;
-    },
-
-    printQemuSmbios1: function(data) {
-
-       var datastr = '';
-
-       Ext.Object.each(data, function(key, value) {
-           if (value === '') return;
-           datastr += (datastr !== '' ? ',' : '') + key + '=' + value;
-       });
-
-       return datastr;
-    },
-
-    parseTfaConfig: function(value) {
-       var res = {};
-
-       Ext.Array.each(value.split(','), function(p) {
-           var kva = p.split(/=/, 2);
-           res[kva[0]] = kva[1];
-       });
-
-       return res;
-    }
-
-}});
diff --git a/www/manager5/Readme.md b/www/manager5/Readme.md
deleted file mode 100644 (file)
index 1c1ccf9..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-pveproxy with ExtJS 6 developpement mini howto
-==============================================
-
-unpack the ExtJS 6 sources, and copy them to /usr/share/pve-manager/ext6
-
-    cd www/ext6/
-    make install
-
-symlink the ext6 dir in pve-manager to the manager5 directory
-
-    cd /usr/share/pve-manager
-    ln -s PATH_TO_YOUR_GIT_REPO/www/manager5 #this is not a typo
-
-access the PVE proxy with ExtJS 6
-
-    https://localhost:8006/?ext6=1
-
-
-With the extra parameter **ext6=1**, pve-proxy will call the function **PVE::ExtJSIndex6::get_index()**
-which returns a HTML page, with all javascript symlinked from your git repository.
-Provided you included the javascript files in **PVE/ExtJSIndex5.pm**, after editing a file in the git repository, a simple refresh is enough to see your changes in the browser.
diff --git a/www/manager5/StateProvider.js b/www/manager5/StateProvider.js
deleted file mode 100644 (file)
index a93c803..0000000
+++ /dev/null
@@ -1,233 +0,0 @@
-/* This state provider keeps part of the state inside
- * the browser history.
- *
- * We compress (shorten) url using dictionary based compression
- * i.e. use column separated list instead of url encoded hash:
- * #v\d*       version/format
- * :=          indicates string values
- * :\d+        lookup value in dictionary hash
- * #v1:=value1:5:=value2:=value3:...
-*/
-
-Ext.define('PVE.StateProvider', {
-    extend: 'Ext.state.LocalStorageProvider',
-
-    // private
-    setHV: function(name, newvalue, fireEvents) {
-       var me = this;
-
-       var changes = false;
-       var oldtext = Ext.encode(me.UIState[name]);
-       var newtext = Ext.encode(newvalue);
-       if (newtext != oldtext) {
-           changes = true;
-           me.UIState[name] = newvalue;
-           //console.log("changed old " + name + " " + oldtext);
-           //console.log("changed new " + name + " " + newtext);
-           if (fireEvents) {
-               me.fireEvent("statechange", me, name, { value: newvalue });
-           }
-       }
-       return changes;
-    },
-
-    // private
-    hslist: [
-       // order is important for notifications
-       // [ name, default ]
-       ['view', 'server'],
-       ['rid', 'root'],
-       ['ltab', 'tasks'],
-       ['nodetab', ''],
-       ['storagetab', ''],
-       ['pooltab', ''],
-       ['kvmtab', ''],
-       ['ovztab', ''],
-       ['dctab', '']
-    ],
-
-    hprefix: 'v1',
-
-    compDict: {
-       snapshot: 29,
-       ha: 28,
-       support: 27,
-       pool: 26,
-       syslog: 25,
-       ubc: 24,
-       initlog: 23,
-       openvz: 22,
-       backup: 21,
-       ressources: 20,
-       content: 19,
-       root: 18,
-       domains: 17,
-       roles: 16,
-       groups: 15,
-       users: 14,
-       time: 13,
-       dns: 12,
-       network: 11,
-       services: 10,
-       options: 9,
-       console: 8,
-       hardware: 7,
-       permissions: 6,
-       summary: 5,
-       tasks: 4,
-       clog: 3,
-       storage: 2,
-       folder: 1,
-       server: 0
-    },
-
-    decodeHToken: function(token) {
-       var me = this;
-
-       var state = {};
-       if (!token) {
-           Ext.Array.each(me.hslist, function(rec) {
-               state[rec[0]] = rec[1];
-           });
-           return state;
-       }
-
-       // return Ext.urlDecode(token);
-
-       var items = token.split(':');
-       var prefix = items.shift();
-
-       if (prefix != me.hprefix) {
-           return me.decodeHToken();
-       }
-
-       Ext.Array.each(me.hslist, function(rec) {
-           var value = items.shift();
-           if (value) {
-               if (value[0] === '=') {
-                   value = decodeURIComponent(value.slice(1));
-               } else {
-                   Ext.Object.each(me.compDict, function(key, cv) {
-                       if (value == cv) {
-                           value = key;
-                           return false;
-                       }
-                   });
-               }
-           }
-           state[rec[0]] = value;
-       });
-
-       return state;
-    },
-
-    encodeHToken: function(state) {
-       var me = this;
-
-       // return Ext.urlEncode(state);
-
-       var ctoken = me.hprefix;
-       Ext.Array.each(me.hslist, function(rec) {
-           var value = state[rec[0]];
-           if (!Ext.isDefined(value)) {
-               value = rec[1];
-           }
-           value = encodeURIComponent(value);
-           if (!value) {
-               ctoken += ':';
-           } else {
-               var comp = me.compDict[value];
-               if (Ext.isDefined(comp)) {
-                   ctoken += ":" + comp;
-               } else {
-                   ctoken += ":=" + value;
-               }
-           }
-       });
-
-       return ctoken;
-    },
-
-    constructor: function(config){
-       var me = this;
-
-       me.callParent([config]);
-
-       me.UIState = me.decodeHToken(); // set default
-
-       var history_change_cb = function(token) {
-           //console.log("HC " + token);
-           if (!token) {
-               var res = window.confirm(gettext('Are you sure you want to navigate away from this page?'));
-               if (res){
-                   // process text value and close...
-                   Ext.History.back();
-               } else {
-                   Ext.History.forward();
-               }
-               return;
-           }
-
-           var newstate = me.decodeHToken(token);
-           Ext.Array.each(me.hslist, function(rec) {
-               if (typeof newstate[rec[0]] == "undefined") {
-                   return;
-               }
-               me.setHV(rec[0], newstate[rec[0]], true);
-           });
-       };
-
-       var start_token = Ext.History.getToken();
-       if (start_token) {
-           history_change_cb(start_token);
-       } else {
-           var htext = me.encodeHToken(me.UIState);
-           Ext.History.add(htext);
-       }
-
-       Ext.History.on('change', history_change_cb);
-    },
-
-    get: function(name, defaultValue){
-       /*jslint confusion: true */
-       var me = this;
-       var data;
-
-       if (typeof me.UIState[name] != "undefined") {
-           data = { value: me.UIState[name] };
-       } else {
-           data = me.callParent(arguments);
-           if (!data && name === 'GuiCap') {
-               data = { vms: {}, storage: {}, access: {}, nodes: {}, dc: {} };
-           }
-       }
-
-       //console.log("GET " + name + " " + Ext.encode(data));
-       return data;
-    },
-
-    clear: function(name){
-       var me = this;
-
-       if (typeof me.UIState[name] != "undefined") {
-           me.UIState[name] = null;
-       }
-
-       me.callParent(arguments);
-    },
-
-    set: function(name, value){
-        var me = this;
-
-       //console.log("SET " + name + " " + Ext.encode(value));
-       if (typeof me.UIState[name] != "undefined") {
-           var newvalue = value ? value.value : null;
-           if (me.setHV(name, newvalue, false)) {
-               var htext = me.encodeHToken(me.UIState);
-               Ext.History.add(htext);
-           }
-       } else {
-           me.callParent(arguments);
-       }
-    }
-});
diff --git a/www/manager5/Toolkit.js b/www/manager5/Toolkit.js
deleted file mode 100644 (file)
index 201d131..0000000
+++ /dev/null
@@ -1,256 +0,0 @@
-// ExtJS related things
-
-PVE.Utils.toolkit = 'extjs',
-
- // do not send '_dc' parameter
-Ext.Ajax.disableCaching = false;
-
-// custom Vtypes
-Ext.apply(Ext.form.field.VTypes, {
-    IPAddress:  function(v) {
-       return IP4_match.test(v);
-    },
-    IPAddressText:  gettext('Example') + ': 192.168.1.1',
-    IPAddressMask: /[\d\.]/i,
-
-    IPCIDRAddress:  function(v) {
-       return IP4_cidr_match.test(v);
-    },
-    IPCIDRAddressText:  gettext('Example') + ': 192.168.1.1/24',
-    IPCIDRAddressMask: /[\d\.\/]/i,
-
-    IP6Address:  function(v) {
-        return IP6_match.test(v);
-    },
-    IP6AddressText:  gettext('Example') + ': 2001:DB8::42',
-    IP6AddressMask: /[A-Fa-f0-9:]/,
-
-    IP6CIDRAddress:  function(v) {
-       return IP6_cidr_match.test(v);
-    },
-    IP6CIDRAddressText:  gettext('Example') + ': 2001:DB8::42/64',
-    IP6CIDRAddressMask:  /[A-Fa-f0-9:\/]/,
-
-    IP6PrefixLength:  function(v) {
-       return v >= 0 && v <= 128;
-    },
-    IP6PrefixLengthText:  gettext('Example') + ': X, where 0 <= X <= 128',
-    IP6PrefixLengthMask:  /[0-9]/,
-    
-    IP64Address:  function(v) {
-        return IP64_match.test(v);
-    },
-    IP64AddressText:  gettext('Example') + ': 192.168.1.1 2001:DB8::42',
-    IP64AddressMask: /[A-Fa-f0-9\.:]/,
-
-    MacAddress: function(v) {
-       return (/^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$/).test(v);
-    },
-    MacAddressMask: /[a-fA-F0-9:]/,
-    MacAddressText: gettext('Example') + ': 01:23:45:67:89:ab',
-
-    BridgeName: function(v) {
-        return (/^vmbr\d{1,4}$/).test(v);
-    },
-    BridgeNameText: gettext('Format') + ': vmbr<b>N</b>, where 0 <= <b>N</b> <= 9999',
-
-    BondName: function(v) {
-        return (/^bond\d{1,4}$/).test(v);
-    },
-    BondNameText: gettext('Format') + ': bond<b>N</b>, where 0 <= <b>N</b> <= 9999',
-
-    InterfaceName: function(v) {
-        return (/^[a-z][a-z0-9_]{1,20}$/).test(v);
-    },
-    InterfaceNameText: gettext('Format') + ': [a-z][a-z0-9_]{1,20}',
-
-
-    QemuStartDate: function(v) {
-       return (/^(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)$/).test(v);
-    },
-    QemuStartDateText: gettext('Format') + ': "now" or "2006-06-17T16:01:21" or "2006-06-17"',
-
-    StorageId:  function(v) {
-        return (/^[a-z][a-z0-9\-\_\.]*[a-z0-9]$/i).test(v);
-    },
-    StorageIdText: gettext("Allowed characters") + ":  'A-Z', 'a-z', '0-9', '-', '_', '.'",
-
-    ConfigId:  function(v) {
-        return (/^[a-z][a-z0-9\_]+$/i).test(v);
-    },
-    ConfigIdText: gettext("Allowed characters") + ": 'A-Z', 'a-z', '0-9', '_'",
-
-    HttpProxy:  function(v) {
-        return (/^http:\/\/.*$/).test(v);
-    },
-    HttpProxyText: gettext('Example') + ": http://username:password&#64;host:port/",
-
-    DnsName: function(v) {
-       return (/^(([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?)\.)*([A-Za-z0-9]([A-Za-z0-9\-]*[A-Za-z0-9])?)$/).test(v);
-    },
-    DnsNameText: gettext('This is not a valid DNS name')
-});
-
-// we dont want that a displayfield set the form dirty flag! 
-Ext.override(Ext.form.field.Display, {
-    isDirty: function() { return false; }
-});
-
-// hack: ExtJS does not display the correct value if we
-// call setValue while the store is loading, so we need
-// to call it again after loading
-Ext.override(Ext.form.field.ComboBox, {
-    onLoad: function() {
-       this.setValue(this.value, false);
-        this.callOverridden(arguments);
-    }
-});
-
-Ext.define('Ext.ux.IFrame', {
-    extend: 'Ext.Component',
-
-    alias: 'widget.uxiframe',
-
-    loadMask: 'Loading...',
-
-    src: 'about:blank',
-
-    renderTpl: [
-        '<iframe src="{src}" name="{frameName}" width="100%" height="100%" frameborder="0"></iframe>'
-    ],
-
-    initComponent: function () {
-        this.callParent();
-
-       this.frameName = this.frameName || this.id + '-frame';
-
-        this.addEvents(
-            'beforeload',
-            'load'
-        );
-
-        Ext.apply(this.renderSelectors, {
-            iframeEl: 'iframe'
-        });
-    },
-
-    initEvents : function() {
-        var me = this;
-        me.callParent();
-        me.iframeEl.on('load', me.onLoad, me);
-    },
-
-    initRenderData: function() {
-        return Ext.apply(this.callParent(), {
-            src: this.src,
-            frameName: this.frameName
-        });
-    },
-
-    getBody: function() {
-        var doc = this.getDoc();
-        return doc.body || doc.documentElement;
-    },
-
-    getDoc: function() {
-        try {
-            return this.getWin().document;
-        } catch (ex) {
-            return null;
-        }
-    },
-
-    getWin: function() {
-        var me = this,
-            name = me.frameName,
-            win = Ext.isIE
-                ? me.iframeEl.dom.contentWindow
-                : window.frames[name];
-        return win;
-    },
-
-    getFrame: function() {
-        var me = this;
-        return me.iframeEl.dom;
-    },
-
-    beforeDestroy: function () {
-        this.cleanupListeners(true);
-        this.callParent();
-    },
-    
-    cleanupListeners: function(destroying){
-        var doc, prop;
-
-        if (this.rendered) {
-            try {
-               doc = this.getDoc();
-                if (doc) {
-                    Ext.EventManager.removeAll(doc);
-                    if (destroying) {
-                        for (prop in doc) {
-                            if (doc.hasOwnProperty && doc.hasOwnProperty(prop)) {
-                                delete doc[prop];
-                            }
-                        }
-                    }
-                }
-            } catch(e) { }
-        }
-    },
-
-    onLoad: function() {
-        var me = this,
-            doc = me.getDoc(),
-            fn = me.onRelayedEvent;
-
-        if (doc) {
-            try {
-                Ext.EventManager.removeAll(doc);
-
-                // These events need to be relayed from the inner document (where they stop
-                // bubbling) up to the outer document. This has to be done at the DOM level so
-                // the event reaches listeners on elements like the document body. The effected
-                // mechanisms that depend on this bubbling behavior are listed to the right
-                // of the event.
-                Ext.EventManager.on(doc, {
-                    mousedown: fn, // menu dismisal (MenuManager) and Window onMouseDown (toFront)
-                    mousemove: fn, // window resize drag detection
-                    mouseup: fn,   // window resize termination
-                    click: fn,     // not sure, but just to be safe
-                    dblclick: fn,  // not sure again
-                    scope: me
-                });
-            } catch(e) {
-                // cannot do this xss
-            }
-
-            // We need to be sure we remove all our events from the iframe on unload or we're going to LEAK!
-            Ext.EventManager.on(this.getWin(), 'beforeunload', me.cleanupListeners, me);
-
-            this.el.unmask();
-            this.fireEvent('load', this);
-
-        } else if(me.src && me.src != '') {
-
-            this.el.unmask();
-            this.fireEvent('error', this);
-        }
-
-
-    },
-
-    load: function (src) {
-        var me = this,
-            text = me.loadMask,
-            frame = me.getFrame();
-
-        if (me.fireEvent('beforeload', me, src) !== false) {
-            if (text && me.el) {
-                me.el.mask(text);
-            }
-
-            frame.src = me.src = (src || me.src);
-        }
-    }
-});
diff --git a/www/manager5/Utils.js b/www/manager5/Utils.js
deleted file mode 100644 (file)
index 71c1654..0000000
+++ /dev/null
@@ -1,1087 +0,0 @@
-Ext.ns('PVE');
-
-// avoid errors when running without development tools
-if (!Ext.isDefined(Ext.global.console)) {   
-    var console = { 
-       dir: function() {}, 
-       log: function() {} 
-    };
-}
-console.log("Starting PVE Manager"); 
-
-Ext.Ajax.defaultHeaders = {
-    'Accept': 'application/json'
-};
-
-Ext.Ajax.on('beforerequest', function(conn, options) {
-    if (PVE.CSRFPreventionToken) {
-       if (!options.headers) { 
-           options.headers = {};
-       }
-       options.headers.CSRFPreventionToken = PVE.CSRFPreventionToken;
-    }
-});
-
-var IPV4_OCTET = "(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])";
-var IPV4_REGEXP = "(?:(?:" + IPV4_OCTET + "\\.){3}" + IPV4_OCTET + ")";
-var IPV6_H16 = "(?:[0-9a-fA-F]{1,4})";
-var IPV6_LS32 = "(?:(?:" + IPV6_H16 + ":" + IPV6_H16 + ")|" + IPV4_REGEXP + ")";
-
-
-var IP4_match = new RegExp("^(?:" + IPV4_REGEXP + ")$");
-var IP4_cidr_match = new RegExp("^(?:" + IPV4_REGEXP + ")\/[1-3][0-9]?$");
-
-var IPV6_REGEXP = "(?:" +
-    "(?:(?:"                                                  + "(?:" + IPV6_H16 + ":){6})" + IPV6_LS32 + ")|" +
-    "(?:(?:"                                         +   "::" + "(?:" + IPV6_H16 + ":){5})" + IPV6_LS32 + ")|" +
-    "(?:(?:(?:"                           + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){4})" + IPV6_LS32 + ")|" +
-    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,1}" + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){3})" + IPV6_LS32 + ")|" +
-    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,2}" + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){2})" + IPV6_LS32 + ")|" +
-    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,3}" + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){1})" + IPV6_LS32 + ")|" +
-    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,4}" + IPV6_H16 + ")?::" +                         ")" + IPV6_LS32 + ")|" +
-    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,5}" + IPV6_H16 + ")?::" +                         ")" + IPV6_H16  + ")|" +
-    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,7}" + IPV6_H16 + ")?::" +                         ")"             + ")"  +
-    ")";
-
-var IP6_match = new RegExp("^(?:" + IPV6_REGEXP + ")$");
-var IP6_cidr_match = new RegExp("^(?:" + IPV6_REGEXP + ")\/[0-9]{1,3}?$");
-var IP6_bracket_match = new RegExp("^\\[(" + IPV6_REGEXP + ")\\]");
-
-var IP64_match = new RegExp("^(?:" + IPV6_REGEXP + "|" + IPV4_REGEXP + ")$");
-
-Ext.define('PVE.Utils', { statics: {
-
-    // this class only contains static functions
-
-    toolkit: undefined, // (extjs|touch), set inside Toolkit.js 
-
-    log_severity_hash: {
-       0: "panic",
-       1: "alert",
-       2: "critical",
-       3: "error",
-       4: "warning",
-       5: "notice",
-       6: "info",
-       7: "debug"
-    },
-
-    support_level_hash: {
-       'c': gettext('Community'),
-       'b': gettext('Basic'),
-       's': gettext('Standard'),
-       'p': gettext('Premium')
-    },
-
-    noSubKeyHtml: 'You do not have a valid subscription for this server. Please visit <a target="_blank" href="http://www.proxmox.com/products/proxmox-ve/subscription-service-plans">www.proxmox.com</a> to get a list of available options.',
-
-    kvm_ostypes: {
-       other: gettext('Other OS types'),
-       wxp: 'Microsoft Windows XP/2003',
-       w2k: 'Microsoft Windows 2000',
-       w2k8: 'Microsoft Windows Vista/2008',
-       win7: 'Microsoft Windows 7/2008r2',
-       win8: 'Microsoft Windows 8/2012',
-       l24: 'Linux 2.4 Kernel',
-       l26: 'Linux 3.X/2.6 Kernel',
-       solaris: 'Solaris Kernel'
-    },
-
-    render_kvm_ostype: function (value) {
-       if (!value) {
-           return gettext('Other OS types');
-       }
-       var text = PVE.Utils.kvm_ostypes[value];
-       if (text) {
-           return text + ' (' + value + ')';
-       }
-       return value;
-    },
-
-    render_hotplug_features: function (value) {
-       var fa = [];
-
-       if (!value || (value === '0')) {
-           return gettext('disabled');
-       }
-
-       Ext.each(value.split(','), function(el) {
-           if (el === 'disk') {
-               fa.push(gettext('Disk'));
-           } else if (el === 'network') {
-               fa.push(gettext('Network'));
-           } else if (el === 'usb') {
-               fa.push(gettext('USB'));
-           } else if (el === 'memory') {
-               fa.push(gettext('Memory'));
-           } else if (el === 'cpu') {
-               fa.push(gettext('CPU'));
-           } else {
-               fa.push(el);
-           }
-       });
-
-       return fa.join(', ');
-    },
-
-    network_iface_types: {
-       eth: gettext("Network Device"),
-       bridge: 'Linux Bridge',
-       bond: 'Linux Bond',
-       OVSBridge: 'OVS Bridge',
-       OVSBond: 'OVS Bond',
-       OVSPort: 'OVS Port',
-       OVSIntPort: 'OVS IntPort'
-    },
-
-    render_network_iface_type: function(value) {
-       return PVE.Utils.network_iface_types[value] || 
-           PVE.Utils.unknownText;
-    },
-
-    render_scsihw: function(value) {
-       if (!value) {
-           return PVE.Utils.defaultText + ' (LSI 53C895A)';
-       } else if (value === 'lsi') {
-           return 'LSI 53C895A';
-       } else if (value === 'lsi53c810') {
-           return 'LSI 53C810';
-       } else if (value === 'megasas') {
-           return 'MegaRAID SAS 8708EM2';
-       } else if (value === 'virtio-scsi-pci') {
-           return 'VIRTIO';
-       } else if (value === 'pvscsi') {
-           return 'VMware PVSCSI';
-       } else {
-           return value;
-       }
-    },
-
-    // fixme: auto-generate this
-    // for now, please keep in sync with PVE::Tools::kvmkeymaps
-    kvm_keymaps: {
-       //ar: 'Arabic',
-       da: 'Danish',
-       de: 'German', 
-       'de-ch': 'German (Swiss)', 
-       'en-gb': 'English (UK)', 
-       'en-us': 'English (USA)',
-       es: 'Spanish',
-       //et: 'Estonia',
-       fi: 'Finnish',
-       //fo: 'Faroe Islands', 
-       fr: 'French', 
-       'fr-be': 'French (Belgium)', 
-       'fr-ca': 'French (Canada)',
-       'fr-ch': 'French (Swiss)',
-       //hr: 'Croatia',
-       hu: 'Hungarian',
-       is: 'Icelandic',
-       it: 'Italian', 
-       ja: 'Japanese',
-       lt: 'Lithuanian',
-       //lv: 'Latvian',
-       mk: 'Macedonian', 
-       nl: 'Dutch',
-       //'nl-be': 'Dutch (Belgium)',
-       no: 'Norwegian', 
-       pl: 'Polish',
-       pt: 'Portuguese',
-       'pt-br': 'Portuguese (Brazil)',
-       //ru: 'Russian',
-       sl: 'Slovenian',
-       sv: 'Swedish',
-       //th: 'Thai',
-       tr: 'Turkish'
-    },
-
-    kvm_vga_drivers: {
-       std: gettext('Standard VGA'),
-       vmware: gettext('VMWare compatible'),
-       cirrus: 'Cirrus Logic GD5446',
-       qxl: 'SPICE',
-       qxl2: 'SPICE dual monitor',
-       qxl3: 'SPICE three monitors',
-       qxl4: 'SPICE four monitors',
-       serial0: gettext('Serial terminal') + ' 0',
-       serial1: gettext('Serial terminal') + ' 1',
-       serial2: gettext('Serial terminal') + ' 2',
-       serial3: gettext('Serial terminal') + ' 3'
-    },
-
-    render_kvm_language: function (value) {
-       if (!value) {
-           return PVE.Utils.defaultText;
-       }
-       var text = PVE.Utils.kvm_keymaps[value];
-       if (text) {
-           return text + ' (' + value + ')';
-       }
-       return value;
-    },
-
-    kvm_keymap_array: function() {
-       var data = [['', PVE.Utils.render_kvm_language('')]];
-       Ext.Object.each(PVE.Utils.kvm_keymaps, function(key, value) {
-           data.push([key, PVE.Utils.render_kvm_language(value)]);
-       });
-
-       return data;
-    },
-
-    render_console_viewer: function(value) {
-       if (!value) {
-           return PVE.Utils.defaultText + ' (HTML5)';
-       } else if (value === 'applet') {
-           return 'Java VNC Applet';
-       } else if (value === 'vv') {
-           return  'SPICE (remote-viewer)';
-       } else if (value === 'html5') {
-           return  'HTML5 (noVNC)';
-       } else {
-           return value;
-       }
-    },
-
-    language_map: {
-       zh_CN: 'Chinese',
-       ca: 'Catalan',
-       da: 'Danish',
-       en: 'English',
-       eu: 'Euskera (Basque)',
-       fr: 'French',
-       de: 'German',
-       it: 'Italian',
-       ja: 'Japanese',
-       nb: 'Norwegian (Bokmal)',
-       nn: 'Norwegian (Nynorsk)',
-       fa: 'Persian (Farsi)',
-       pl: 'Polish',
-       pt_BR: 'Portuguese (Brazil)',
-       ru: 'Russian',
-       sl: 'Slovenian',
-       es: 'Spanish',
-       sv: 'Swedish',
-       tr: 'Turkish'
-    },
-
-    render_language: function (value) {
-       if (!value) {
-           return PVE.Utils.defaultText + ' (English)';
-       }
-       var text = PVE.Utils.language_map[value];
-       if (text) {
-           return text + ' (' + value + ')';
-       }
-       return value;
-    },
-
-    language_array: function() {
-       var data = [['', PVE.Utils.render_language('')]];
-       Ext.Object.each(PVE.Utils.language_map, function(key, value) {
-           data.push([key, PVE.Utils.render_language(value)]);
-       });
-
-       return data;
-    },
-
-    render_kvm_vga_driver: function (value) {
-       if (!value) {
-           return PVE.Utils.defaultText;
-       }
-       var text = PVE.Utils.kvm_vga_drivers[value];
-       if (text) { 
-           return text + ' (' + value + ')';
-       }
-       return value;
-    },
-
-    kvm_vga_driver_array: function() {
-       var data = [['', PVE.Utils.render_kvm_vga_driver('')]];
-       Ext.Object.each(PVE.Utils.kvm_vga_drivers, function(key, value) {
-           data.push([key, PVE.Utils.render_kvm_vga_driver(value)]);
-       });
-
-       return data;
-    },
-
-    render_kvm_startup: function(value) {
-       var startup = PVE.Parser.parseStartup(value);
-
-       var res = 'order=';
-       if (startup.order === undefined) {
-           res += 'any';
-       } else {
-           res += startup.order;
-       }
-       if (startup.up !== undefined) {
-           res += ',up=' + startup.up;
-       }
-       if (startup.down !== undefined) {
-           res += ',down=' + startup.down;
-       }
-
-       return res;
-    },
-
-    authOK: function() {
-       return Ext.util.Cookies.get('PVEAuthCookie');
-    },
-
-    authClear: function() {
-       Ext.util.Cookies.clear("PVEAuthCookie");
-    },
-
-    // fixme: remove - not needed?
-    gridLineHeigh: function() {
-       return 21;
-       
-       //if (Ext.isGecko)
-       //return 23;
-       //return 21;
-    },
-
-    extractRequestError: function(result, verbose) {
-       var msg = gettext('Successful');
-
-       if (!result.success) {
-           msg = gettext("Unknown error");
-           if (result.message) {
-               msg = result.message;
-               if (result.status) {
-                   msg += ' (' + result.status + ')';
-               }
-           }
-           if (verbose && Ext.isObject(result.errors)) {
-               msg += "<br>";
-               Ext.Object.each(result.errors, function(prop, desc) {
-                   msg += "<br><b>" + Ext.htmlEncode(prop) + "</b>: " + 
-                       Ext.htmlEncode(desc);
-               });
-           }   
-       }
-
-       return msg;
-    },
-
-    extractFormActionError: function(action) {
-       var msg;
-       switch (action.failureType) {
-       case Ext.form.action.Action.CLIENT_INVALID:
-           msg = gettext('Form fields may not be submitted with invalid values');
-           break;
-       case Ext.form.action.Action.CONNECT_FAILURE:
-           msg = gettext('Connection error');
-           var resp = action.response;
-           if (resp.status && resp.statusText) {
-               msg += " " + resp.status + ": " + resp.statusText;
-           }
-           break;
-       case Ext.form.action.Action.LOAD_FAILURE:
-       case Ext.form.action.Action.SERVER_INVALID:
-           msg = PVE.Utils.extractRequestError(action.result, true);
-           break;
-       }
-       return msg;
-    },
-
-    // Ext.Ajax.request
-    API2Request: function(reqOpts) {
-
-       var newopts = Ext.apply({
-           waitMsg: gettext('Please wait...')
-       }, reqOpts);
-
-       if (!newopts.url.match(/^\/api2/)) {
-           newopts.url = '/api2/extjs' + newopts.url;
-       }
-       delete newopts.callback;
-
-       var createWrapper = function(successFn, callbackFn, failureFn) {
-           Ext.apply(newopts, {
-               success: function(response, options) {
-                   if (options.waitMsgTarget) {
-                       if (PVE.Utils.toolkit === 'touch') {
-                           options.waitMsgTarget.setMasked(false);
-                       } else {
-                           options.waitMsgTarget.setLoading(false);
-                       }
-                   }
-                   var result = Ext.decode(response.responseText);
-                   response.result = result;
-                   if (!result.success) {
-                       response.htmlStatus = PVE.Utils.extractRequestError(result, true);
-                       Ext.callback(callbackFn, options.scope, [options, false, response]);
-                       Ext.callback(failureFn, options.scope, [response, options]);
-                       return;
-                   }
-                   Ext.callback(callbackFn, options.scope, [options, true, response]);
-                   Ext.callback(successFn, options.scope, [response, options]);
-               },
-               failure: function(response, options) {
-                   if (options.waitMsgTarget) {
-                       if (PVE.Utils.toolkit === 'touch') {
-                           options.waitMsgTarget.setMasked(false);
-                       } else {
-                           options.waitMsgTarget.setLoading(false);
-                       }
-                   }
-                   response.result = {};
-                   try {
-                       response.result = Ext.decode(response.responseText);
-                   } catch(e) {}
-                   var msg = gettext('Connection error') + ' - server offline?';
-                   if (response.aborted) {
-                       msg = gettext('Connection error') + ' - aborted.';
-                   } else if (response.timedout) {
-                       msg = gettext('Connection error') + ' - Timeout.';
-                   } else if (response.status && response.statusText) {
-                       msg = gettext('Connection error') + ' ' + response.status + ': ' + response.statusText;
-                   }
-                   response.htmlStatus = msg;
-                   Ext.callback(callbackFn, options.scope, [options, false, response]);
-                   Ext.callback(failureFn, options.scope, [response, options]);
-               }
-           });
-       };
-
-       createWrapper(reqOpts.success, reqOpts.callback, reqOpts.failure);
-
-       var target = newopts.waitMsgTarget;
-       if (target) {
-           if (PVE.Utils.toolkit === 'touch') {
-               target.setMasked({ xtype: 'loadmask', message: newopts.waitMsg} );
-           } else {
-               // Note: ExtJS bug - this does not work when component is not rendered
-               target.setLoading(newopts.waitMsg);
-           }
-       }
-       Ext.Ajax.request(newopts);
-    },
-
-    assemble_field_data: function(values, data) {
-        if (Ext.isObject(data)) {
-           Ext.Object.each(data, function(name, val) {
-               if (values.hasOwnProperty(name)) {
-                    var bucket = values[name];
-                    if (!Ext.isArray(bucket)) {
-                        bucket = values[name] = [bucket];
-                    }
-                    if (Ext.isArray(val)) {
-                        values[name] = bucket.concat(val);
-                    } else {
-                        bucket.push(val);
-                    }
-                } else {
-                   values[name] = val;
-                }
-            });
-       }
-    },
-
-    checked_command: function(orig_cmd) {
-       PVE.Utils.API2Request({
-           url: '/nodes/localhost/subscription',
-           method: 'GET',
-           //waitMsgTarget: me,
-           failure: function(response, opts) {
-               Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-           },
-           success: function(response, opts) {
-               var data = response.result.data;
-
-               if (data.status !== 'Active') {
-                   Ext.Msg.show({
-                       title: gettext('No valid subscription'),
-                       icon: Ext.Msg.WARNING,
-                       msg: PVE.Utils.noSubKeyHtml,
-                       buttons: Ext.Msg.OK,
-                       callback: function(btn) {
-                           if (btn !== 'ok') {
-                               return;
-                           }
-                           orig_cmd();
-                       }
-                   });
-               } else {
-                   orig_cmd();
-               }
-           }
-       });
-    },
-
-    task_desc_table: {
-       vncproxy: [ 'VM/CT', gettext('Console') ],
-       spiceproxy: [ 'VM/CT', gettext('Console') + ' (Spice)' ],
-       vncshell: [ '', gettext('Shell') ],
-       spiceshell: [ '', gettext('Shell')  + ' (Spice)' ],
-       qmsnapshot: [ 'VM', gettext('Snapshot') ],
-       qmrollback: [ 'VM', gettext('Rollback') ],
-       qmdelsnapshot: [ 'VM', gettext('Delete Snapshot') ],
-       qmcreate: [ 'VM', gettext('Create') ],
-       qmrestore: [ 'VM', gettext('Restore') ],
-       qmdestroy: [ 'VM', gettext('Destroy') ],
-       qmigrate: [ 'VM', gettext('Migrate') ],
-       qmclone: [ 'VM', gettext('Clone') ],
-       qmmove: [ 'VM', gettext('Move disk') ],
-       qmtemplate: [ 'VM', gettext('Convert to template') ],
-       qmstart: [ 'VM', gettext('Start') ],
-       qmstop: [ 'VM', gettext('Stop') ],
-       qmreset: [ 'VM', gettext('Reset') ],
-       qmshutdown: [ 'VM', gettext('Shutdown') ],
-       qmsuspend: [ 'VM', gettext('Suspend') ],
-       qmresume: [ 'VM', gettext('Resume') ],
-       qmconfig: [ 'VM', gettext('Configure') ],
-       vzcreate: ['CT', gettext('Create') ],
-       vzrestore: ['CT', gettext('Restore') ],
-       vzdestroy: ['CT', gettext('Destroy') ],
-       vzmigrate: [ 'CT', gettext('Migrate') ],
-       vzstart: ['CT', gettext('Start') ],
-       vzstop: ['CT', gettext('Stop') ],
-       vzmount: ['CT', gettext('Mount') ],
-       vzumount: ['CT', gettext('Unmount') ],
-       vzshutdown: ['CT', gettext('Shutdown') ],
-       vzsuspend: [ 'CT', gettext('Suspend') ],
-       vzresume: [ 'CT', gettext('Resume') ],
-       hamigrate: [ 'HA', gettext('Migrate') ],
-       hastart: [ 'HA', gettext('Start') ],
-       hastop: [ 'HA', gettext('Stop') ],
-       srvstart: ['SRV', gettext('Start') ],
-       srvstop: ['SRV', gettext('Stop') ],
-       srvrestart: ['SRV', gettext('Restart') ],
-       srvreload: ['SRV', gettext('Reload') ],
-       cephcreatemon: ['Ceph Monitor', gettext('Create') ],
-       cephdestroymon: ['Ceph Monitor', gettext('Destroy') ],
-       cephcreateosd: ['Ceph OSD', gettext('Create') ],
-       cephdestroyosd: ['Ceph OSD', gettext('Destroy') ],
-       imgcopy: ['', gettext('Copy data') ],
-       imgdel: ['', gettext('Erase data') ],
-       download: ['', gettext('Download') ],
-       vzdump: ['', gettext('Backup') ],
-       aptupdate: ['', gettext('Update package database') ],
-       startall: [ '', gettext('Start all VMs and Containers') ],
-       stopall: [ '', gettext('Stop all VMs and Containers') ],
-       migrateall: [ '', gettext('Migrate all VMs and Containers') ]
-    },
-
-    format_task_description: function(type, id) {      
-       var farray = PVE.Utils.task_desc_table[type];
-       if (!farray) {
-           return type;
-       }
-       var prefix = farray[0];
-       var text = farray[1];
-       if (prefix) {
-           return prefix + ' ' + id + ' - ' + text; 
-       }
-       return text;
-    },
-
-    parse_task_upid: function(upid) {
-       var task = {};
-
-       var res = upid.match(/^UPID:(\S+):([0-9A-Fa-f]{8}):([0-9A-Fa-f]{8,9}):([0-9A-Fa-f]{8}):([^:\s]+):([^:\s]*):([^:\s]+):$/);
-       if (!res) {
-           throw "unable to parse upid '" + upid + "'";
-       }
-       task.node = res[1];
-       task.pid = parseInt(res[2], 16);
-       task.pstart = parseInt(res[3], 16);
-       task.starttime = parseInt(res[4], 16);
-       task.type = res[5];
-       task.id = res[6];
-       task.user = res[7];
-
-       task.desc = PVE.Utils.format_task_description(task.type, task.id);
-
-       return task;
-    },
-
-    format_size: function(size) {
-       /*jslint confusion: true */
-
-       if (size < 1024) {
-           return size;
-       }
-
-       var kb = size / 1024;
-
-       if (kb < 1024) {
-           return kb.toFixed(0) + "KB";
-       }
-
-       var mb = size / (1024*1024);
-
-       if (mb < 1024) {
-           return mb.toFixed(0) + "MB";
-       }
-
-       var gb = mb / 1024;
-
-       if (gb < 1024) {
-           return gb.toFixed(2) + "GB";
-       }
-
-       var tb =  gb / 1024;
-
-       return tb.toFixed(2) + "TB";
-
-    },
-
-    format_html_bar: function(per, text) {
-
-       return "<div class='pve-bar-wrap'>" + text + "<div class='pve-bar-border'>" +
-           "<div class='pve-bar-inner' style='width:" + per + "%;'></div>" +
-           "</div></div>";
-       
-    },
-
-    format_cpu_bar: function(per1, per2, text) {
-
-       return "<div class='pve-bar-border'>" +
-           "<div class='pve-bar-inner' style='width:" + per1 + "%;'></div>" +
-           "<div class='pve-bar-inner2' style='width:" + per2 + "%;'></div>" +
-           "<div class='pve-bar-text'>" + text + "</div>" + 
-           "</div>";
-    },
-
-    format_large_bar: function(per, text) {
-
-       if (!text) {
-           text = per.toFixed(1) + "%";
-       }
-
-       return "<div class='pve-largebar-border'>" +
-           "<div class='pve-largebar-inner' style='width:" + per + "%;'></div>" +
-           "<div class='pve-largebar-text'>" + text + "</div>" + 
-           "</div>";
-    },
-
-    format_duration_long: function(ut) {
-
-       var days = Math.floor(ut / 86400);
-       ut -= days*86400;
-       var hours = Math.floor(ut / 3600);
-       ut -= hours*3600;
-       var mins = Math.floor(ut / 60);
-       ut -= mins*60;
-
-       var hours_str = '00' + hours.toString();
-       hours_str = hours_str.substr(hours_str.length - 2);
-       var mins_str = "00" + mins.toString();
-       mins_str = mins_str.substr(mins_str.length - 2);
-       var ut_str = "00" + ut.toString();
-       ut_str = ut_str.substr(ut_str.length - 2);
-
-       if (days) {
-           var ds = days > 1 ? PVE.Utils.daysText : PVE.Utils.dayText;
-           return days.toString() + ' ' + ds + ' ' + 
-               hours_str + ':' + mins_str + ':' + ut_str;
-       } else {
-           return hours_str + ':' + mins_str + ':' + ut_str;
-       }
-    },
-
-    format_duration_short: function(ut) {
-       
-       if (ut < 60) {
-           return ut.toString() + 's';
-       }
-
-       if (ut < 3600) {
-           var mins = ut / 60;
-           return mins.toFixed(0) + 'm';
-       }
-
-       if (ut < 86400) {
-           var hours = ut / 3600;
-           return hours.toFixed(0) + 'h';
-       }
-
-       var days = ut / 86400;
-       return days.toFixed(0) + 'd';   
-    },
-
-    yesText: gettext('Yes'),
-    noText: gettext('No'),
-    noneText: gettext('none'),
-    errorText: gettext('Error'),
-    unknownText: gettext('Unknown'),
-    defaultText: gettext('Default'),
-    daysText: gettext('days'),
-    dayText: gettext('day'),
-    runningText: gettext('running'),
-    stoppedText: gettext('stopped'),
-    neverText: gettext('never'),
-    totalText: gettext('Total'),
-    usedText: gettext('Used'),
-    directoryText: gettext('Directory'),
-    imagesText: gettext('Disk image'),
-    backupFileText: gettext('VZDump backup file'),
-    vztmplText: gettext('Container template'),
-    isoImageText: gettext('ISO image'),
-    containersText: gettext('Container'),
-
-    format_expire: function(date) {
-       if (!date) {
-           return PVE.Utils.neverText;
-       }
-       return Ext.Date.format(date, "Y-m-d");
-    },
-
-    format_storage_type: function(value) {
-       if (value === 'dir') {
-           return PVE.Utils.directoryText;
-       } else if (value === 'nfs') {
-           return 'NFS';
-       } else if (value === 'glusterfs') {
-           return 'GlusterFS';
-       } else if (value === 'lvm') {
-           return 'LVM';
-       } else if (value === 'iscsi') {
-           return 'iSCSI';
-       } else if (value === 'rbd') {
-           return 'RBD';
-       } else if (value === 'sheepdog') {
-           return 'Sheepdog';
-       } else if (value === 'zfs') {
-           return 'ZFS over iSCSI';
-       } else if (value === 'zfspool') {
-           return 'ZFS';
-       } else if (value === 'iscsidirect') {
-           return 'iSCSIDirect';
-       } else {
-           return PVE.Utils.unknownText;
-       }
-    },
-
-    format_boolean_with_default: function(value) {
-       if (Ext.isDefined(value) && value !== '') {
-           return value ? PVE.Utils.yesText : PVE.Utils.noText;
-       }
-       return PVE.Utils.defaultText;
-    },
-
-    format_boolean: function(value) {
-       return value ? PVE.Utils.yesText : PVE.Utils.noText;
-    },
-
-    format_neg_boolean: function(value) {
-       return !value ? PVE.Utils.yesText : PVE.Utils.noText;
-    },
-
-    format_content_types: function(value) {
-       var cta = [];
-
-       Ext.each(value.split(',').sort(), function(ct) {
-           if (ct === 'images') {
-               cta.push(PVE.Utils.imagesText);
-           } else if (ct === 'backup') {
-               cta.push(PVE.Utils.backupFileText);
-           } else if (ct === 'vztmpl') {
-               cta.push(PVE.Utils.vztmplText);
-           } else if (ct === 'iso') {
-               cta.push(PVE.Utils.isoImageText);
-           } else if (ct === 'rootdir') {
-               cta.push(PVE.Utils.containersText);
-           }
-       });
-
-       return cta.join(', ');
-    },
-
-    render_storage_content: function(value, metaData, record) {
-       var data = record.data;
-       if (Ext.isNumber(data.channel) &&
-           Ext.isNumber(data.id) &&
-           Ext.isNumber(data.lun)) {
-           return "CH " + 
-               Ext.String.leftPad(data.channel,2, '0') + 
-               " ID " + data.id + " LUN " + data.lun;
-       }
-       return data.volid.replace(/^.*:(.*\/)?/,'');
-    },
-
-    render_serverity: function (value) {
-       return PVE.Utils.log_severity_hash[value] || value;
-    },
-
-    render_cpu: function(value, metaData, record, rowIndex, colIndex, store) {
-
-       if (!(record.data.uptime && Ext.isNumeric(value))) {
-           return '';
-       }
-
-       var maxcpu = record.data.maxcpu || 1;
-
-       if (!Ext.isNumeric(maxcpu) && (maxcpu >= 1)) {
-           return '';
-       }
-       
-       var per = value * 100;
-
-       return per.toFixed(1) + '% of ' + maxcpu.toString() + (maxcpu > 1 ? 'CPUs' : 'CPU');
-    },
-
-    render_size: function(value, metaData, record, rowIndex, colIndex, store) {
-       /*jslint confusion: true */
-
-       if (!Ext.isNumeric(value)) {
-           return '';
-       }
-
-       return PVE.Utils.format_size(value);
-    },
-
-    render_timestamp: function(value, metaData, record, rowIndex, colIndex, store) {
-       var servertime = new Date(value * 1000);
-       return Ext.Date.format(servertime, 'Y-m-d H:i:s');
-    },
-
-    render_mem_usage: function(value, metaData, record, rowIndex, colIndex, store) {
-
-       var mem = value;
-       var maxmem = record.data.maxmem;
-       
-       if (!record.data.uptime) {
-           return '';
-       }
-
-       if (!(Ext.isNumeric(mem) && maxmem)) {
-           return '';
-       }
-
-       var per = (mem * 100) / maxmem;
-
-       return per.toFixed(1) + '%';
-    },
-
-    render_disk_usage: function(value, metaData, record, rowIndex, colIndex, store) {
-
-       var disk = value;
-       var maxdisk = record.data.maxdisk;
-
-       if (!(Ext.isNumeric(disk) && maxdisk)) {
-           return '';
-       }
-
-       var per = (disk * 100) / maxdisk;
-
-       return per.toFixed(1) + '%';
-    },
-
-    render_resource_type: function(value, metaData, record, rowIndex, colIndex, store) {
-
-       var cls = 'pve-itype-icon-' + value;
-
-       if (record.data.running) {
-           metaData.tdCls = cls + "-running";
-       } else if (record.data.template) {
-           metaData.tdCls = cls + "-template";     
-       } else {
-           metaData.tdCls = cls;
-       }
-
-       return value;
-    },
-
-    render_uptime: function(value, metaData, record, rowIndex, colIndex, store) {
-
-       var uptime = value;
-
-       if (uptime === undefined) {
-           return '';
-       }
-       
-       if (uptime <= 0) {
-           return '-';
-       }
-
-       return PVE.Utils.format_duration_long(uptime);
-    },
-
-    render_support_level: function(value, metaData, record) {
-       return PVE.Utils.support_level_hash[value] || '-';
-    },
-
-    render_upid: function(value, metaData, record) { 
-       var type = record.data.type;
-       var id = record.data.id;
-
-       return PVE.Utils.format_task_description(type, id);
-    },
-
-    dialog_title: function(subject, create, isAdd) {
-       if (create) {
-           if (isAdd) {
-               return gettext('Add') + ': ' + subject;
-           } else {
-               return gettext('Create') + ': ' + subject;
-           }
-       } else {
-           return gettext('Edit') + ': ' + subject;
-       }
-    },
-
-    windowHostname: function() {
-       return window.location.hostname.replace(IP6_bracket_match,
-            function(m, addr, offset, original) { return addr; });
-    },
-    openDefaultConsoleWindow: function(allowSpice, vmtype, vmid, nodename, vmname) {
-       var dv = PVE.Utils.defaultViewer(allowSpice);
-       PVE.Utils.openConsoleWindow(dv, vmtype, vmid, nodename, vmname);
-    },
-
-    openConsoleWindow: function(viewer, vmtype, vmid, nodename, vmname) {
-       // kvm, lxc, shell, upgrade
-
-       if (vmid == undefined && (vmtype === 'kvm' || vmtype === 'lxc')) {
-           throw "missing vmid";
-       }
-
-       if (!nodename) {
-           throw "no nodename specified";
-       }
-
-       if (viewer === 'applet' || viewer === 'html5') {
-           PVE.Utils.openVNCViewer(vmtype, vmid, nodename, vmname, viewer === 'html5');
-       } else if (viewer === 'vv') {
-           var url;
-           var params = { proxy: PVE.Utils.windowHostname() };
-           if (vmtype === 'kvm') {
-               url = '/nodes/' + nodename + '/qemu/' + vmid.toString() + '/spiceproxy';
-               PVE.Utils.openSpiceViewer(url, params);
-           } else if (vmtype === 'lxc') {
-               url = '/nodes/' + nodename + '/lxc/' + vmid.toString() + '/spiceproxy';
-               PVE.Utils.openSpiceViewer(url, params);
-           } else if (vmtype === 'shell') {
-               url = '/nodes/' + nodename + '/spiceshell';
-               PVE.Utils.openSpiceViewer(url, params);
-           } else if (vmtype === 'upgrade') {
-               url = '/nodes/' + nodename + '/spiceshell';
-               params.upgrade = 1;
-               PVE.Utils.openSpiceViewer(url, params);
-           }
-       } else {
-           throw "unknown viewer type";
-       }
-    },
-
-    defaultViewer: function(allowSpice) {
-       var vncdefault = 'html5';
-       var dv = PVE.VersionInfo.console || vncdefault;
-       if (dv === 'vv' && !allowSpice) {
-           dv = vncdefault;
-       }
-
-       return dv;
-    },
-
-    openVNCViewer: function(vmtype, vmid, nodename, vmname, novnc) {
-       var url = Ext.urlEncode({
-           console: vmtype, // kvm, lxc, upgrade or shell
-           novnc: novnc ? 1 : 0,
-           vmid: vmid,
-           vmname: vmname,
-           node: nodename
-       });
-       var nw = window.open("?" + url, '_blank', "innerWidth=745,innerheight=427");
-       nw.focus();
-    },
-
-    openSpiceViewer: function(url, params){
-
-       var downloadWithName = function(uri, name) {
-           var link = Ext.DomHelper.append(document.body, {
-               tag: 'a',
-               href: uri,
-               css : 'display:none;visibility:hidden;height:0px;'
-           });
-
-           // Note: we need to tell android the correct file name extension
-           // but we do not set 'download' tag for other environments, because
-           // It can have strange side effects (additional user prompt on firefox)
-           var andriod = navigator.userAgent.match(/Android/i) ? true : false;
-           if (andriod) {
-               link.download = name;
-           }
-
-           if (link.fireEvent) {
-               link.fireEvent('onclick');
-           } else {
-                var evt = document.createEvent("MouseEvents");
-                evt.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
-               link.dispatchEvent(evt);
-           }
-       };
-
-       PVE.Utils.API2Request({
-           url: url,
-           params: params,
-           method: 'POST',
-           failure: function(response, opts){
-               Ext.Msg.alert('Error', response.htmlStatus);
-           },
-           success: function(response, opts){
-               var raw = "[virt-viewer]\n";
-               Ext.Object.each(response.result.data, function(k, v) {
-                   raw += k + "=" + v + "\n";
-               });
-               var url = 'data:application/x-virt-viewer;charset=UTF-8,' +
-                   encodeURIComponent(raw);
-                   
-               downloadWithName(url, "pve-spice.vv");
-           }
-       });
-    },
-
-    // comp.setLoading() is buggy in ExtJS 4.0.7, so we 
-    // use el.mask() instead
-    setErrorMask: function(comp, msg) {
-       var el = comp.el;
-       if (!el) {
-           return;
-       }
-       if (!msg) {
-           el.unmask();
-       } else {
-           if (msg === true) {
-               el.mask(gettext("Loading..."));
-           } else {
-               el.mask(msg);
-           }
-       }
-    },
-
-    monStoreErrors: function(me, store) {
-       me.mon(store, 'beforeload', function(s, operation, eOpts) {
-           if (!me.loadCount) {
-               me.loadCount = 0; // make sure it is numeric
-               PVE.Utils.setErrorMask(me, true);
-           }
-       });
-
-       // only works with 'pve' proxy
-       me.mon(store.proxy, 'afterload', function(proxy, request, success) {
-           me.loadCount++;
-
-           if (success) {
-               PVE.Utils.setErrorMask(me, false);
-               return;
-           }
-
-           var msg;
-           var operation = request.operation;
-           var error = operation.getError();
-           if (error.statusText) {
-               msg = error.statusText + ' (' + error.status + ')';
-           } else {
-               msg = gettext('Connection error');
-           }
-           PVE.Utils.setErrorMask(me, msg);
-       });
-    }
-
-}});
-
diff --git a/www/manager5/VNCConsole.js b/www/manager5/VNCConsole.js
deleted file mode 100644 (file)
index db90388..0000000
+++ /dev/null
@@ -1,591 +0,0 @@
-Ext.define('PVE.noVncConsole', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNoVncConsole',
-
-    nodename: undefined,
-
-    vmid: undefined,
-
-    consoleType: undefined, // lxc or kvm
-    
-    initComponent : function() {
-       var me = this;
-
-       if (!me.nodename) {
-           throw "no node name specified";
-       }
-
-       if (!me.consoleType) {
-           throw "no console type specified";
-       }
-
-       if (!me.vmid && me.consoleType !== 'shell') {
-           throw "no VM ID specified";
-       }
-       
-       // always use same iframe, to avoid running several noVnc clients
-       // at same time (to avoid performance problems)
-       var box = Ext.create('widget.uxiframe', { id: "vncconsole" });
-
-       Ext.apply(me, {
-           layout: { type: 'fit' },
-           border: false,
-           items: box,
-           listeners: {
-               show: function() {
-                   var url = '/?console=' + me.consoleType + '&novnc=1&node=' + me.nodename + '&resize=scale';
-                   if (me.vmid) {
-                       url += '&vmid='+ me.vmid;
-                   }
-                   box.load(url);
-               }
-           }
-       });             
-
-       me.callParent();
-    }
-});
-
-PVE_vnc_console_event = function(appletid, action, err) {
-    //console.log("TESTINIT param1 " + appletid + " action " + action);
-
-    if (action === "error") {
-       var compid = appletid.replace("-vncapp", "");
-       var comp = Ext.getCmp(compid);
-
-       if (!comp || !comp.vmid || !comp.toplevel) {
-           return;
-       }
-
-       comp.detectMigratedVM();
-    }
-
-    return;
- };
-
-Ext.define('PVE.VNCConsole', {
-    extend: 'Ext.panel.Panel',
-    alias: ['widget.pveVNCConsole'],
-
-    novnc: false,
-
-    last_novnc_state: undefined,
-    last_novnc_msg: undefined,
-
-    detectMigratedVM: function() {
-       var me = this;
-       
-       if (!me.vmid) {
-           return;
-       }
-
-       // try to detect migrated VM
-       PVE.Utils.API2Request({
-           url: '/cluster/resources',
-           method: 'GET',
-           success: function(response) {
-               var list = response.result.data;
-               Ext.Array.each(list, function(item) {
-                   if (item.type === 'qemu' && item.vmid == me.vmid) {
-                       if (item.node !== me.nodename) {
-                           me.nodename = item.node;
-                           me.url = "/nodes/" + me.nodename + "/" + item.type + "/" + me.vmid + "/vncproxy";
-                           me.wsurl = "/nodes/" + me.nodename + "/" + item.type + "/" + me.vmid + "/vncwebsocket";
-                           me.reloadApplet();
-                       }
-                       return false; // break
-                   }
-               });
-           }
-       });
-    },
-
-    initComponent : function() {
-       var me = this;
-
-       if (!me.url) {
-           throw "no url specified";
-       }
-
-       var myid = me.id + "-vncapp";
-
-       me.appletID = myid;
-
-       var box;
-
-       if (me.novnc) {
-           if (!me.wsurl) {
-               throw "no web socket url specified";
-           }
-           box = Ext.create('widget.uxiframe', { id: myid });
-       } else {
-           box = Ext.create('Ext.Component', { border: false, html: "" });
-       }
-
-       var resize_window = function() {
-           //console.log("resize");
-
-           var aw;
-           var ah;
-           var applet;
-
-           if (me.novnc) {
-               var novnciframe = box.getFrame();
-               // noVNC_canvas
-               var innerDoc = novnciframe.contentDocument || novnciframe.contentWindow.document;
-               aw = innerDoc.getElementById('noVNC_canvas').width;
-               ah = innerDoc.getElementById('noVNC_canvas').height + 8;
-
-               var novnc_state = innerDoc.getElementById('noVNC_status_state').innerHTML;
-               var novnc_msg = innerDoc.getElementById('noVNC_status_msg').innerHTML;
-
-               if (novnc_state !== me.last_novnc_state || novnc_msg !== me.last_novnc_msg) {
-                   me.last_novnc_state = novnc_state; 
-                   me.last_novnc_msg = novnc_msg; 
-
-                   if (novnc_state !== 'normal') {
-                       PVE.Utils.setErrorMask(box, novnc_msg || 'unknown');
-                   } else {
-                       PVE.Utils.setErrorMask(box); // clear mask
-                   }
-
-                   if (novnc_state === 'disconnected') {
-                       me.detectMigratedVM();
-                   }
-               }
-
-           } else {
-               applet = Ext.getDom(myid);
-           
-               // try again when dom element is available
-               if (!(applet && Ext.isFunction(applet.getPreferredSize))) {
-                   return Ext.Function.defer(resize_window, 1000);
-               }
-
-               var ps = applet.getPreferredSize();
-               aw = ps.width;
-               ah = ps.height;
-           }
-
-           if (aw < 640) { aw = 640; }
-           if (ah < 400) { ah = 400; }
-
-           var tbar = me.getDockedItems("[dock=top]")[0];
-           var tbh = tbar ? tbar.getHeight() : 0;
-
-           var oh;
-           var ow;
-
-           //console.log("size0 " + aw + " " + ah + " tbh " + tbh);
-
-           if (window.innerHeight) {
-               oh = window.innerHeight;
-               ow = window.innerWidth;
-           } else if (document.documentElement && 
-                      document.documentElement.clientHeight) {
-               oh = document.documentElement.clientHeight;
-               ow = document.documentElement.clientWidth;
-           } else if (document.body) {
-               oh = document.body.clientHeight;
-               ow = document.body.clientWidth;
-           }  else {
-               throw "can't get window size";
-           }
-
-           if (!me.novnc) {
-               Ext.fly(applet).setSize(aw, ah + tbh);
-           }
-
-           var offsetw = aw - ow;
-           var offseth = ah + tbh - oh;
-
-           if (offsetw !== 0 || offseth !== 0) {
-               //console.log("try resize by " + offsetw + " " + offseth);
-               try { window.resizeBy(offsetw, offseth); } catch (e) {}
-           }
-
-           Ext.Function.defer(resize_window, 1000);
-       };
-
-       var resize_box = function() {
-           if (me.novnc) {
-               throw "implement me";
-           } else {
-               var applet = Ext.getDom(myid);
-
-               if ((applet && Ext.isFunction(applet.getPreferredSize))) {
-                   var ps = applet.getPreferredSize();
-                   Ext.fly(applet).setSize(ps.width, ps.height);
-               }
-           }
-
-           Ext.Function.defer(resize_box, 1000);
-       };
-
-       var start_vnc_viewer = function(param) {
-           
-           if (me.novnc) {
-               
-               var pveparams = Ext.urlEncode({
-                   port: param.port,
-                   vncticket: param.ticket
-               });
-
-               var urlparams = Ext.urlEncode({
-                   encrypt: 1,
-                   path: "api2/json" + me.wsurl + "?" + pveparams,
-                   password: param.ticket
-               });
-               box.load('/novnc/vnc_pve.html?' + urlparams);
-           
-           } else {
-
-               var cert = param.cert;
-               cert = cert.replace(/\n/g, "|");
-
-               box.update({
-                   id: myid,
-                   border: false,
-                   tag: 'applet',
-                   code: 'com.tigervnc.vncviewer.VncViewer',
-                   archive: '/vncterm/VncViewer.jar',
-                   // NOTE: set size to '100%' -  else resize does not work
-                   width: "100%",
-                   height: "100%", 
-                   cn: [
-                       {tag: 'param', name: 'id', value: myid},
-                       {tag: 'param', name: 'PORT', value: param.port},
-                       {tag: 'param', name: 'PASSWORD', value: param.ticket},
-                       {tag: 'param', name: 'USERNAME', value: param.user},
-                       {tag: 'param', name: 'Show Controls', value: 'No'},
-                       {tag: 'param', name: 'Offer Relogin', value: 'No'},
-                       {tag: 'param', name: 'PVECert', value: cert}
-                   ]
-               });
-           }
-
-            if (me.toplevel) {
-               Ext.Function.defer(resize_window, 1000);
-            } else {
-               Ext.Function.defer(resize_box, 1000);
-            }
-       };
-
-       Ext.apply(me, {
-           layout: 'fit',
-           border: false,
-           autoScroll: me.toplevel ? false : true,
-           items: box,
-           reloadApplet: function() {
-               var params = Ext.apply({}, me.params);
-               if (me.novnc) {
-                   params.websocket = 1;
-               } 
-               PVE.Utils.API2Request({
-                   url: me.url,
-                   params: params,
-                   method: me.method || 'POST',
-                   failure: function(response, opts) {
-                       box.update(gettext('Error') + ' ' + response.htmlStatus);
-                   },
-                   success: function(response, opts) {
-                       start_vnc_viewer(response.result.data);
-                   }
-               });
-           }
-       });
-
-       me.callParent();
-
-       if (me.toplevel) {
-           me.on("render", me.reloadApplet);
-       } else {
-           me.on("show", me.reloadApplet);
-           me.on("hide", function() { box.update(""); });
-       }
-    }
-});
-
-Ext.define('PVE.KVMConsole', {
-    extend: 'PVE.VNCConsole',
-    alias: ['widget.pveKVMConsole'],
-
-    initComponent : function() {
-       var me = this;
-       if (!me.nodename) { 
-           throw "no node name specified";
-       }
-
-       if (!me.vmid) {
-           throw "no VM ID specified";
-       }
-
-       var baseUrl = "/nodes/" + me.nodename + "/qemu/" + me.vmid;
-
-       var vm_command = function(cmd, params, reload_applet) {
-           PVE.Utils.API2Request({
-               params: params,
-               url: baseUrl + "/status/" + cmd,
-               method: 'POST',
-               waitMsgTarget: me,
-               failure: function(response, opts) {
-                   Ext.Msg.alert('Error', response.htmlStatus);
-               },
-               success: function() {
-                   if (reload_applet) {
-                       Ext.Function.defer(me.reloadApplet, 1000, me);
-                   }
-               }
-           });
-       };
-
-       var tbar = [ 
-           { 
-               text: gettext('Start'),
-               handler: function() { 
-                   vm_command("start", {}, 1);
-               }
-           },
-           { 
-               text: gettext('Shutdown'),
-               handler: function() {
-                   var msg = Ext.String.format(gettext("Do you really want to shutdown VM {0}?"), me.vmid);
-                   Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-                       if (btn !== 'yes') {
-                           return;
-                       }
-                       vm_command('shutdown');
-                   });
-               }                           
-           }, 
-           { 
-               text: gettext('Stop'),
-               handler: function() {
-                   var msg = Ext.String.format(gettext("Do you really want to stop VM {0}?"), me.vmid);
-                   Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-                       if (btn !== 'yes') {
-                           return;
-                       }
-                       vm_command("stop");
-                   }); 
-               }
-           },
-           { 
-               xtype: 'pveQemuSendKeyMenu',
-               nodename: me.nodename,
-               vmid: me.vmid
-           },
-           { 
-               text: gettext('Reset'),
-               handler: function() { 
-                   var msg = Ext.String.format(gettext("Do you really want to reset VM {0}?"), me.vmid);
-                   Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-                       if (btn !== 'yes') {
-                           return;
-                       }
-                       vm_command("reset");
-                   });
-               }
-           },
-           { 
-               text: gettext('Suspend'),
-               handler: function() {
-                   var msg = Ext.String.format(gettext("Do you really want to suspend VM {0}?"), me.vmid);
-                   Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-                       if (btn !== 'yes') {
-                           return;
-                       }
-                       vm_command("suspend");
-                   }); 
-               }
-           },
-           { 
-               text: gettext('Resume'),
-               handler: function() {
-                   vm_command("resume"); 
-               }
-           },
-           // Note: no migrate here, because we can't display migrate log
-            { 
-                text: gettext('Console'),
-                handler: function() {
-                   PVE.Utils.openVNCViewer('kvm', me.vmid, me.nodename, me.vmname, me.novnc);
-               }
-            },
-            '->',
-           {
-                text: gettext('Refresh'),
-               hidden: me.novnc ? true : false,
-               handler: function() { 
-                   var applet = Ext.getDom(me.appletID);
-                   applet.sendRefreshRequest();
-               }
-           },
-           {
-                text: gettext('Reload'),
-                handler: function () { 
-                   me.reloadApplet(); 
-               }
-           }
-       ];
-
-       
-       Ext.apply(me, {
-           tbar: tbar,
-           url: baseUrl + "/vncproxy",
-           wsurl: baseUrl + "/vncwebsocket"
-       });
-
-       me.callParent();
-    }
-});
-
-Ext.define('PVE.LxcConsole', {
-    extend: 'PVE.VNCConsole',
-    alias: ['widget.pveLxcConsole'],
-
-    initComponent : function() {
-       var me = this;
-       if (!me.nodename) { 
-           throw "no node name specified";
-       }
-
-       if (!me.vmid) {
-           throw "no VM ID specified";
-       }
-
-       var baseUrl = "/nodes/" + me.nodename + "/lxc/" + me.vmid;
-       var vm_command = function(cmd, params, reload_applet) {
-           PVE.Utils.API2Request({
-               params: params,
-               url: baseUrl + "/status/" + cmd,
-               waitMsgTarget: me,
-               method: 'POST',
-               failure: function(response, opts) {
-                   Ext.Msg.alert('Error', response.htmlStatus);
-               },
-               success: function() {
-                   if (reload_applet) {
-                       Ext.Function.defer(me.reloadApplet, 1000, me);
-                   }
-               }
-           });
-       };
-
-       var tbar = [ 
-           { 
-               text: gettext('Start'),
-               handler: function() { 
-                   vm_command("start");
-               }
-           },
-           { 
-               text: gettext('Shutdown'),
-               handler: function() {
-                   var msg = Ext.String.format(gettext("Do you really want to shutdown VM {0}?"), me.vmid);
-                   Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-                       if (btn !== 'yes') {
-                           return;
-                       }
-                       vm_command("shutdown");
-                   }); 
-               }
-           },
-           { 
-               text: gettext('Stop'),
-               handler: function() {
-                   var msg = Ext.String.format(gettext("Do you really want to stop VM {0}?"), me.vmid);
-                   Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-                       if (btn !== 'yes') {
-                           return;
-                       }
-                       vm_command("stop");
-                   }); 
-               }
-           },
-           // Note: no migrate here, because we can't display migrate log
-            '->',
-           {
-                text: gettext('Refresh'),
-               hidden: me.novnc ? true : false,
-               handler: function() { 
-                   var applet = Ext.getDom(me.appletID);
-                   applet.sendRefreshRequest();
-               }
-           },
-           {
-                text: gettext('Reload'),
-                handler: function () { 
-                   me.reloadApplet(); 
-               }
-           }
-       ];
-
-       Ext.apply(me, {
-           tbar: tbar,
-           url: baseUrl + "/vncproxy",
-           wsurl: baseUrl + "/vncwebsocket"
-       });
-
-       me.callParent();
-    }
-});
-
-Ext.define('PVE.Shell', {
-    extend: 'PVE.VNCConsole',
-    alias: ['widget.pveShell'],
-
-    ugradeSystem: false, // set to true to run "apt-get dist-upgrade"
-
-    initComponent : function() {
-       var me = this;
-       if (!me.nodename) { 
-           throw "no node name specified";
-       }
-
-       var tbar = [ '->' ];
-
-       if (!me.novnc) {
-           tbar.push({
-                text: gettext('Refresh'),
-               handler: function() { 
-                   var applet = Ext.getDom(me.appletID);
-                   applet.sendRefreshRequest();
-               }
-           });
-       }
-
-       if (!me.ugradeSystem) {
-           // we dont want to restart the upgrade script
-           tbar.push({
-                text: gettext('Reload'),
-                handler: function () { me.reloadApplet(); }
-           });
-       }
-
-       tbar.push({ 
-           text: gettext('Shell'),
-           handler: function() {
-               PVE.Utils.openVNCViewer('shell', undefined, me.nodename, undefined, me.novnc);
-           }
-       });
-
-       var baseUrl = "/nodes/" + me.nodename;
-
-       Ext.apply(me, {
-           tbar: tbar,
-           url: baseUrl + "/vncshell",
-           wsurl: baseUrl + "/vncwebsocket"
-       });
-
-       if (me.ugradeSystem) {
-           me.params = { upgrade: 1 };     
-       }
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/Workspace.js b/www/manager5/Workspace.js
deleted file mode 100644 (file)
index a4102eb..0000000
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * Workspace base class
- *
- * popup login window when auth fails (call onLogin handler)
- * update (re-login) ticket every 15 minutes
- *
- */
-
-Ext.define('PVE.Workspace', {
-    extend: 'Ext.container.Viewport',
-
-    title: 'Proxmox Virtual Environment',
-
-    loginData: null, // Data from last login call
-
-    onLogin: function(loginData) {},
-
-    // private
-    updateLoginData: function(loginData) {
-       var me = this;
-       me.loginData = loginData;
-       PVE.CSRFPreventionToken = loginData.CSRFPreventionToken;
-       PVE.UserName = loginData.username;
-
-       if (loginData.cap) {
-           Ext.state.Manager.set('GuiCap', loginData.cap);
-       }
-
-       // creates a session cookie (expire = null) 
-       // that way the cookie gets deleted after browser window close
-       Ext.util.Cookies.set('PVEAuthCookie', loginData.ticket, null, '/', null, true);
-       me.onLogin(loginData);
-    },
-
-    // private
-    showLogin: function() {
-       var me = this;
-
-       PVE.Utils.authClear();
-       PVE.UserName = null;
-       me.loginData = null;
-
-       if (!me.login) {
-           me.login = Ext.create('PVE.window.LoginWindow', {
-               handler: function(data) {
-                   me.login = null;
-                   me.updateLoginData(data);
-                   PVE.Utils.checked_command(function() {}); // display subscription status
-               }
-           });
-       }
-       me.onLogin(null);
-        me.login.show();
-    },
-
-    initComponent : function() {
-       var me = this;
-
-       Ext.tip.QuickTipManager.init();
-
-       // fixme: what about other errors
-       Ext.Ajax.on('requestexception', function(conn, response, options) {
-           if (response.status == 401) { // auth failure
-               me.showLogin();
-           }
-       });
-
-       document.title = me.title;
-
-       me.callParent();
-
-        if (!PVE.Utils.authOK()) {
-           me.showLogin();
-       } else { 
-           if (me.loginData) {
-               me.onLogin(me.loginData);
-           }
-       }
-
-       Ext.TaskManager.start({
-           run: function() {
-               var ticket = PVE.Utils.authOK();
-               if (!ticket || !PVE.UserName) {
-                   return;
-               }
-
-               Ext.Ajax.request({
-                   params: { 
-                       username: PVE.UserName,
-                       password: ticket
-                   },
-                   url: '/api2/json/access/ticket',
-                   method: 'POST',
-                   success: function(response, opts) {
-                       var obj = Ext.decode(response.responseText);
-                       me.updateLoginData(obj.data);
-                   }
-               });
-           },
-           interval: 15*60*1000
-       });
-
-    }
-});
-
-Ext.define('PVE.ConsoleWorkspace', {
-    extend: 'PVE.Workspace',
-
-    alias: ['widget.pveConsoleWorkspace'],
-
-    title: gettext('Console'),
-
-    initComponent : function() {
-       var me = this;
-
-       var param = Ext.Object.fromQueryString(window.location.search);
-       var consoleType = me.consoleType || param.console;
-
-       param.novnc = (param.novnc === '1') ? true : false;
-
-       var content;
-       if (consoleType === 'kvm') {
-           me.title = "VM " + param.vmid;
-           if (param.vmname) {
-               me.title += " ('" + param.vmname + "')";
-           }
-           content = {
-               xtype: 'pveKVMConsole',
-               novnc: param.novnc,
-               vmid: param.vmid,
-               nodename: param.node,
-               vmname: param.vmname,
-               toplevel: true
-           };
-       } else if (consoleType === 'lxc') {
-           me.title = "CT " + param.vmid;
-           if (param.vmname) {
-               me.title += " ('" + param.vmname + "')";
-           }
-           content = {
-               xtype: 'pveLxcConsole',
-               novnc: param.novnc,
-               vmid: param.vmid,
-               nodename: param.node,
-               vmname: param.vmname,
-               toplevel: true
-           };
-       } else if (consoleType === 'shell') {
-           me.title = "node '" + param.node + "'";
-           content = {
-               xtype: 'pveShell',
-               novnc: param.novnc,
-               nodename: param.node,
-               toplevel: true
-           };
-       } else if (consoleType === 'upgrade') {
-           me.title = Ext.String.format(gettext('System upgrade on node {0}'), "'" + param.node + "'");
-           content = {
-               xtype: 'pveShell',
-               novnc: param.novnc,
-               nodename: param.node,
-               ugradeSystem: true,
-               toplevel: true
-           };
-       } else {
-           content = {
-               border: false,
-               bodyPadding: 10,
-               html: gettext('Error') + ': No such console type'
-           };
-       }
-
-       Ext.apply(me, {
-           layout: { type: 'fit' },
-           border: false,
-           items: [ content ]
-       });
-
-       me.callParent();       
-    }
-});
-
-Ext.define('PVE.StdWorkspace', {
-    extend: 'PVE.Workspace',
-
-    alias: ['widget.pveStdWorkspace'],
-
-    // private
-    setContent: function(comp) {
-       var me = this;
-       
-       var cont = me.child('#content');
-       cont.removeAll(true);
-
-       if (comp) {
-           PVE.Utils.setErrorMask(cont, false);
-           comp.border = false;
-           cont.add(comp);
-           cont.doLayout();
-       } 
-       // else {
-           // TODO: display something useful
-
-           // Note:: error mask has wrong zindex, so we do not
-           // use that - see bug 114
-           // PVE.Utils.setErrorMask(cont, 'nothing selected');
-       //}
-    },
-
-    selectById: function(nodeid) {
-       var me = this;
-       var tree = me.down('pveResourceTree');
-       tree.selectById(nodeid);
-    },
-
-    checkVmMigration: function(record) {
-       var me = this;
-       var tree = me.down('pveResourceTree');
-       tree.checkVmMigration(record);
-    },
-
-    onLogin: function(loginData) {
-       var me = this;
-
-       me.updateUserInfo();
-
-       if (loginData) {
-           PVE.data.ResourceStore.startUpdate();
-
-           PVE.Utils.API2Request({
-               url: '/version',
-               method: 'GET',
-               success: function(response) {
-                   PVE.VersionInfo = response.result.data;
-                   me.updateVersionInfo();
-               }
-           });
-       }
-    },
-
-    updateUserInfo: function() {
-       var me = this;
-
-       var ui = me.query('#userinfo')[0];
-
-       if (PVE.UserName) {
-           var msg =  Ext.String.format(gettext("You are logged in as {0}"), "'" + PVE.UserName + "'");
-           ui.update('<div class="x-unselectable" style="white-space:nowrap;">' + msg + '</div>');
-       } else {
-           ui.update('');
-       }
-       ui.doLayout();
-    },
-
-    updateVersionInfo: function() {
-       var me = this;
-
-       var ui = me.query('#versioninfo')[0];
-
-       if (PVE.VersionInfo) {
-           var version = PVE.VersionInfo.version + '-' + PVE.VersionInfo.release + '/' +
-               PVE.VersionInfo.repoid;
-           ui.update('Proxmox Virtual Environment<br>' + gettext('Version') + ': ' + version);
-       } else {
-           ui.update('Proxmox Virtual Environment');
-       }
-       ui.doLayout();
-    },
-
-    initComponent : function() {
-       var me = this;
-
-       Ext.History.init();
-
-       var sprovider = Ext.create('PVE.StateProvider');
-       Ext.state.Manager.setProvider(sprovider);
-
-       var selview = new PVE.form.ViewSelector({});
-
-       var rtree = Ext.createWidget('pveResourceTree', {
-           viewFilter: selview.getViewFilter(),
-           flex: 1,
-           selModel: new Ext.selection.TreeModel({
-               listeners: {
-                   selectionchange: function(sm, selected) {
-                       var comp;
-                       var tlckup = {
-                           root: 'PVE.dc.Config',
-                           node: 'PVE.node.Config',
-                           qemu: 'PVE.qemu.Config',
-                           lxc: 'PVE.lxc.Config',
-                           storage: 'PVE.storage.Browser',
-                           pool: 'pvePoolConfig'
-                       };
-                       
-                       if (selected.length > 0) {
-                           var n = selected[0];
-                           comp = {
-                               xtype: tlckup[n.data.type || 'root'] || 
-                                   'pvePanelConfig',
-                               layout: { type: 'fit' },
-                               showSearch: (n.data.id === 'root') ||
-                                   Ext.isDefined(n.data.groupbyid),
-                               pveSelNode: n,
-                               workspace: me,
-                               viewFilter: selview.getViewFilter()
-                           };
-                           PVE.curSelectedNode = n;
-                       }
-
-                       me.setContent(comp);
-                   }
-               }
-           })
-       });
-
-       selview.on('select', function(combo, records) { 
-           if (records && records.length) {
-               var view = combo.getViewFilter();
-               rtree.setViewFilter(view);
-           }
-       });
-
-       var caps = sprovider.get('GuiCap');
-
-       var createVM = Ext.createWidget('button', {
-           pack: 'end',
-           margin: '3 5 0 0',
-           baseCls: 'x-btn',
-           text: gettext("Create VM"),
-           disabled: !caps.vms['VM.Allocate'],
-           handler: function() {
-               var wiz = Ext.create('PVE.qemu.CreateWizard', {});
-               wiz.show();
-           } 
-       });
-
-       var createCT = Ext.createWidget('button', {
-           pack: 'end',
-           margin: '3 5 0 0',
-           baseCls: 'x-btn',
-           text: gettext("Create CT"),
-           disabled: !caps.vms['VM.Allocate'],
-           handler: function() {
-               var wiz = Ext.create('PVE.lxc.CreateWizard', {});
-               wiz.show();
-           } 
-       });
-
-       sprovider.on('statechange', function(sp, key, value) {
-           if (key === 'GuiCap' && value) {
-               caps = value;
-               createVM.setDisabled(!caps.vms['VM.Allocate']);
-               createCT.setDisabled(!caps.vms['VM.Allocate']);
-           }
-       });
-
-       Ext.apply(me, {
-           layout: { type: 'border' },
-           border: false,
-           items: [
-               {
-                   region: 'north',
-                   height: 30,
-                   layout: { 
-                       type: 'hbox',
-                   },
-                   baseCls: 'x-plain',         
-                   defaults: {
-                       baseCls: 'x-plain'                      
-                   },
-                   border: false,
-                   margin: '2 0 5 0',
-                   items: [
-                       {
-                           margin: '0 0 0 4',
-                           html: '<a class="x-unselectable" target=_blank href="http://www.proxmox.com">' +
-                               '<img height=30 width=209 src="/pve2/images/proxmox_logo.png"/></a>'
-                       },
-                       {
-                           minWidth: 200,
-                           flex: 1,
-                           id: 'versioninfo',
-                           html: 'Proxmox Virtual Environment',
-                           height: 30
-                       },
-                       {
-                           pack: 'end',
-                           margin: '8 10 0 10',
-                           id: 'userinfo',
-                           stateful: false
-                       },
-                       {
-                           pack: 'end',
-                           margin: '3 5 0 0',
-                           xtype: 'button',
-                           baseCls: 'x-btn',
-                           text: gettext("Logout"),
-                           handler: function() { 
-                               PVE.data.ResourceStore.stopUpdate();
-                               me.showLogin(); 
-                               me.setContent(); 
-                               var rt = me.down('pveResourceTree');
-                               rt.clearTree();
-                           }
-                       }, 
-                       createVM, 
-                       createCT
-                   ]
-               },
-               {
-                   region: 'center',
-                   id: 'content',
-                   xtype: 'container',
-                   layout: { type: 'fit' },
-                   border: false,
-                   stateful: false,
-                   margin: '0 5 0 0',
-                   items: []
-               },
-               {
-                   region: 'west',
-                   xtype: 'container',
-                   border: false,
-                   layout: { type: 'vbox', align: 'stretch' },
-                   margin: '0 0 0 5',
-                   split: true,
-                   width: 200,
-                   items: [ selview, rtree ]
-               },
-               {
-                   xtype: 'pveStatusPanel',
-                   region: 'south',
-                   margin:'0 5 5 5',
-                   height: 200,       
-                   split:true
-               }
-           ]
-       });
-
-       me.callParent();
-
-       me.updateUserInfo();
-    }
-});
-
diff --git a/www/manager5/button/Button.js b/www/manager5/button/Button.js
deleted file mode 100644 (file)
index 3866899..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/* Button features:
- * - observe selection changes to enable/disable the button using enableFn()
- * - pop up confirmation dialog using confirmMsg()
- */
-Ext.define('PVE.button.Button', {
-    extend: 'Ext.button.Button',
-    alias: 'widget.pveButton',
-
-    // the selection model to observe
-    selModel: undefined,
-
-    // if 'false' handler will not be called (button disabled)
-    enableFn: function(record) { },
-
-    // function(record) or text
-    confirmMsg: false,
-
-    // take special care in confirm box (select no as default).
-    dangerous: false,
-
-    initComponent: function() {
-       /*jslint confusion: true */
-
-        var me = this;
-
-       if (me.handler) {
-           me.realHandler = me.handler;
-
-           me.handler = function(button, event) {
-               var rec, msg;
-               if (me.selModel) {
-                   rec = me.selModel.getSelection()[0];
-                   if (!rec || (me.enableFn(rec) === false)) {
-                       return;
-                   }
-               }
-
-               if (me.confirmMsg) {
-                   msg = me.confirmMsg;
-                   if (Ext.isFunction(me.confirmMsg)) {
-                       msg = me.confirmMsg(rec);
-                   }
-                   Ext.MessageBox.defaultButton = me.dangerous ? 2 : 1;
-                   Ext.Msg.show({
-                       title: gettext('Confirm'),
-                       icon: me.dangerous ? Ext.Msg.WARNING : Ext.Msg.QUESTION,
-                       msg: msg,
-                       buttons: Ext.Msg.YESNO,
-                       callback: function(btn) {
-                           if (btn !== 'yes') {
-                               return;
-                           }
-                           me.realHandler(button, event, rec);
-                       }
-                   });
-               } else {
-                   me.realHandler(button, event, rec);
-               }
-           };
-       }
-
-       me.callParent();
-
-       if (me.selModel) {
-
-           me.mon(me.selModel, "selectionchange", function() {
-               var rec = me.selModel.getSelection()[0];
-               if (!rec || (me.enableFn(rec) === false)) {
-                   me.setDisabled(true);
-               } else  {
-                   me.setDisabled(false);
-               }
-           });
-       }
-    }
-});
diff --git a/www/manager5/button/ConsoleButton.js b/www/manager5/button/ConsoleButton.js
deleted file mode 100644 (file)
index cba4984..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-Ext.define('PVE.button.ConsoleButton', {
-    extend: 'Ext.button.Split',
-    alias: 'widget.pveConsoleButton',
-
-    consoleType: 'shell', // one of 'shell', 'kvm', 'lxc', 'upgrade'
-
-    consoleName: undefined,
-
-    enableSpice: true,
-
-    nodename: undefined,
-
-    vmid: 0,
-
-    setEnableSpice: function(enable){
-       var me = this;
-
-       me.enableSpice = enable;
-       me.spiceMenu.setDisabled(!enable);
-    },
-
-    initComponent: function() {
-        var me = this;
-
-       if (!me.nodename) {
-           throw "no node name specified";
-       }
-
-       me.spiceMenu = Ext.create('Ext.menu.Item', {
-           text: 'SPICE',
-           iconCls: 'pve-itype-icon-virt-viewer',
-           handler: function() { 
-               PVE.Utils.openConsoleWindow('vv', me.consoleType, me.vmid, me.nodename, me.consoleName);
-           }
-       });
-
-       var noVncMenu = Ext.create('Ext.menu.Item', {
-           text: 'noVNC',
-           iconCls: 'pve-itype-icon-novnc',
-           handler: function() { 
-               PVE.Utils.openConsoleWindow('html5', me.consoleType, me.vmid, me.nodename, me.consoleName);
-           }
-       });
-
-       Ext.applyIf(me, { text: gettext('Console') });
-
-       Ext.apply(me, {
-           handler: function() {
-               PVE.Utils.openDefaultConsoleWindow(me.enableSpice, me.consoleType, me.vmid, 
-                                                  me.nodename, me.consoleName);
-           },
-           menu: new Ext.menu.Menu({
-               items: [ noVncMenu, me.spiceMenu ]
-           })
-       });
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/data/DiffStore.js b/www/manager5/data/DiffStore.js
deleted file mode 100644 (file)
index 66bcfed..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * The DiffStore acts as proxy between an UpdateStore instance and a component.
- * Its purpose is to redisplay the component *only* if the data has been changed
- * inside the UpdateStore, to avoid the annoying visual flickering of using
- * the UpdateStore directly.
- *
- * Implementation:
- * The DiffStore monitors via mon() the 'load' events sent by the target store.
- * On each 'load' event, the DiffStore compares its own content with the target
- * store (call to cond_add_item()) and then fires a 'refresh' event.
- * The 'refresh' event will automatically trigger a view refresh on the component
- * who binds to this store.
- */
-
-/* Config properties:
- * rstore: A target store to track changes
- * Only works if rstore has a model and use 'idProperty'
- */
-Ext.define('PVE.data.DiffStore', {
-    extend: 'Ext.data.Store',
-
-    sortAfterUpdate: false,
-    
-    constructor: function(config) {
-       var me = this;
-
-       config = config || {};
-
-       if (!config.rstore) {
-           throw "no rstore specified";
-       }
-
-       if (!config.rstore.model) {
-           throw "no rstore model specified";
-       }
-
-       var rstore = config.rstore;
-
-       Ext.apply(config, {
-           model: rstore.model,
-           proxy: { type: 'memory' }
-       });
-
-       me.callParent([config]);
-
-       var first_load = true;
-
-       var cond_add_item = function(data, id) {
-           var olditem = me.getById(id);
-           if (olditem) {
-               olditem.beginEdit();
-               Ext.Array.each(me.model.prototype.fields, function(field) {
-                   if (olditem.data[field.name] !== data[field.name]) {
-                       olditem.set(field.name, data[field.name]);
-                   }
-               });
-               olditem.endEdit(true);
-               olditem.commit(); 
-           } else {
-               var newrec = Ext.create(me.model, data);
-               var pos = (me.appendAtStart && !first_load) ? 0 : me.data.length;
-               me.insert(pos, newrec);
-           }
-       };
-
-       me.mon(rstore, 'load', function(s, records, success) {
-
-           if (!success) {
-               return;
-           }
-
-           me.suspendEvents();
-
-           // remove vanished items
-           (me.snapshot || me.data).each(function(olditem) {
-               var item = rstore.getById(olditem.getId());
-               if (!item) {
-                   me.remove(olditem);
-               }
-           });
-
-           rstore.each(function(item) {
-               cond_add_item(item.data, item.getId());
-           });
-
-           me.filter();
-
-           if (me.sortAfterUpdate) {
-               me.sort();
-           }
-
-           first_load = false;
-
-           me.resumeEvents();
-           me.fireEvent('refresh', me);
-       });
-    }
-});
diff --git a/www/manager5/data/ObjectStore.js b/www/manager5/data/ObjectStore.js
deleted file mode 100644 (file)
index 6db1e6c..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/* This store encapsulates data items which are organized as an Array of key-values Objects
- * ie data[0] contains something like {key: "keyboard", value: "da"}
-*
-* Designed to work with the KeyValue model and the JsonObject data reader
-*/
-Ext.define('PVE.data.ObjectStore',  {
-    extend: 'PVE.data.UpdateStore',
-
-    constructor: function(config) {
-       var me = this;
-
-        config = config || {};
-
-       if (!config.storeid) {
-           config.storeid =  'pve-store-' + (++Ext.idSeed);
-       }
-
-        Ext.applyIf(config, {
-           model: 'KeyValue',
-            proxy: {
-                type: 'pve',
-               url: config.url,
-               extraParams: config.extraParams,
-                reader: {
-                   type: 'jsonobject',
-                   rows: config.rows,
-                   readArray: config.readArray,
-                   rootProperty: config.root || 'data'
-               }
-            }
-        });
-
-        me.callParent([config]);
-    }
-});
diff --git a/www/manager5/data/PVEProxy.js b/www/manager5/data/PVEProxy.js
deleted file mode 100644 (file)
index 01c20cb..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-Ext.define('PVE.RestProxy', {
-    extend: 'Ext.data.RestProxy',
-    alias : 'proxy.pve',
-    
-    pageParam : null,
-    startParam: null,
-    limitParam: null,
-    groupParam: null,
-    sortParam: null,
-    filterParam: null,
-    noCache : false,
-    afterRequest: function(request, success) {
-               this.fireEvent('afterload', this, request, success);
-               return;
-       },
-
-    constructor: function(config) {
-
-       Ext.applyIf(config, {       
-           reader: {
-               type: 'json',
-               rootProperty: config.root || 'data'
-           },
-       });
-
-       this.callParent([config]); 
-    }
-
-}, function() {
-
-    Ext.define('pve-domains', {
-       extend: "Ext.data.Model",
-       fields: [ 'realm', 'type', 'comment', 'default', 'tfa',
-                 { 
-                     name: 'descr',
-                     // Note: We use this in the RealmComboBox.js
-                     // (see Bug #125)
-                     convert: function(value, record) {
-                         var info = record.data;
-                         var text;
-
-                         if (value) {
-                             return value;
-                         }
-                         // return realm if there is no comment
-                         text = info.comment || info.realm;
-
-                         if (info.tfa) {
-                             text += " (+ " + info.tfa + ")";
-                         }
-
-                         return text;
-                     }
-                 }
-               ],
-       proxy: {
-           type: 'pve',
-           url: "/api2/json/access/domains"
-       }
-    });
-
-    Ext.define('KeyValue', {
-       extend: "Ext.data.Model",
-       fields: [ 'key', 'value' ]
-    });
-
-    Ext.define('KeyValuePendingDelete', {
-       extend: "Ext.data.Model",
-       fields: [ 'key', 'value', 'pending', 'delete' ],
-       idProperty: 'key'
-    });
-
-    Ext.define('pve-string-list', {
-       extend: 'Ext.data.Model',
-       fields:  [ 'n', 't' ],
-       idProperty: 'n'
-    });
-
-    Ext.define('pve-tasks', {
-       extend: 'Ext.data.Model',
-       fields:  [ 
-           { name: 'starttime', type : 'date', dateFormat: 'timestamp' }, 
-           { name: 'endtime', type : 'date', dateFormat: 'timestamp' }, 
-           { name: 'pid', type: 'int' },
-           'node', 'upid', 'user', 'status', 'type', 'id'
-       ],
-       idProperty: 'upid'
-    });
-
-    Ext.define('pve-cluster-log', {
-       extend: 'Ext.data.Model',
-       fields:  [ 
-           { name: 'uid' , type: 'int' },
-           { name: 'time', type : 'date', dateFormat: 'timestamp' }, 
-           { name: 'pri', type: 'int' },
-           { name: 'pid', type: 'int' },
-           'node', 'user', 'tag', 'msg',
-           {
-               name: 'id',
-               convert: function(value, record) {
-                   var info = record.data;
-                   var text;
-
-                   if (value) {
-                       return value;
-                   }
-                   // compute unique ID
-                   return info.uid + ':' + info.node;
-               }
-           }
-       ],
-       idProperty: 'id'
-    });
-});
diff --git a/www/manager5/data/ResourceStore.js b/www/manager5/data/ResourceStore.js
deleted file mode 100644 (file)
index c757a46..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-Ext.define('PVE.data.ResourceStore', {
-    extend: 'PVE.data.UpdateStore',
-    singleton: true,
-
-    findVMID: function(vmid) {
-       var me = this, i;
-       
-       return (me.findExact('vmid', parseInt(vmid, 10)) >= 0);
-    },
-    constructor: function(config) {
-       // fixme: how to avoid those warnings
-       /*jslint confusion: true */
-
-       var me = this;
-
-       config = config || {};
-
-       var field_defaults = {
-           type: {
-               header: gettext('Type'),
-               type: 'string',
-               renderer: PVE.Utils.render_resource_type,
-               sortable: true,
-               hideable: false,
-               width: 80
-           },
-           id: {
-               header: 'ID',
-               type: 'string',
-               hidden: true,
-               sortable: true,
-               width: 80
-           },
-           running: {
-               header: gettext('Online'),
-               type: 'boolean',
-               renderer: PVE.Utils.format_boolean,
-               hidden: true,
-               convert: function(value, record) {
-                   var info = record.data;
-                   if (info.type === 'qemu' || info.type === 'lxc' || info.type === 'node') {
-                       return (Ext.isNumeric(info.uptime) && (info.uptime > 0));
-                   } else {
-                       return false;
-                   }
-               }
-           },
-           text: {
-               header: gettext('Description'),
-               type: 'string',
-               sortable: true,
-               width: 200,
-               convert: function(value, record) {
-                   var info = record.data;
-                   var text;
-
-                   if (value) {
-                       return value;
-                   }
-
-                   if (info.type === 'node') {
-                       text = info.node;
-                   } else if (info.type === 'pool') {
-                       text = info.pool;
-                   } else if (info.type === 'storage') {
-                       text = info.storage + ' (' + info.node + ')';
-                   } else if (info.type === 'qemu' || info.type === 'lxc') {
-                       text = String(info.vmid);
-                       if (info.name) {
-                           text += " (" + info.name + ')';
-                       }
-                   } else {
-                       text = info.id;
-                   }
-                   return text;
-               }
-           },
-           vmid: {
-               header: 'VMID',
-               type: 'integer',
-               hidden: true,
-               sortable: true,
-               width: 80
-           },
-           name: {
-               header: gettext('Name'),
-               hidden: true,
-               sortable: true,
-               type: 'string'
-           },
-           disk: {
-               header: gettext('Disk usage'),
-               type: 'integer',
-               renderer: PVE.Utils.render_disk_usage,
-               sortable: true,
-               width: 100
-           },
-           maxdisk: {
-               header: gettext('Disk size'),
-               type: 'integer',
-               renderer: PVE.Utils.render_size,
-               sortable: true,
-               hidden: true,
-               width: 100
-           },
-           mem: {
-               header: gettext('Memory usage'),
-               type: 'integer',
-               renderer: PVE.Utils.render_mem_usage,
-               sortable: true,
-               width: 100
-           },
-           maxmem: {
-               header: gettext('Memory size'),
-               type: 'integer',
-               renderer: PVE.Utils.render_size,
-               hidden: true,
-               sortable: true,
-               width: 100
-           },
-           cpu: {
-               header: gettext('CPU usage'),
-               type: 'float',
-               renderer: PVE.Utils.render_cpu,
-               sortable: true,
-               width: 100
-           },
-           maxcpu: {
-               header: gettext('maxcpu'),
-               type: 'integer',
-               hidden: true,
-               sortable: true,
-               width: 60
-           },
-           diskread: {
-               header: gettext('Total Disk Read'),
-               type: 'integer',
-               hidden: true,
-               sortable: true,
-               renderer: PVE.Utils.format_size,
-               width: 100
-           },
-           diskwrite: {
-               header: gettext('Total Disk Write'),
-               type: 'integer',
-               hidden: true,
-               sortable: true,
-               renderer: PVE.Utils.format_size,
-               width: 100
-           },
-           netin: {
-               header: gettext('Total NetIn'),
-               type: 'integer',
-               hidden: true,
-               sortable: true,
-               renderer: PVE.Utils.format_size,
-               width: 100
-           },
-           netout: {
-               header: gettext('Total NetOut'),
-               type: 'integer',
-               hidden: true,
-               sortable: true,
-               renderer: PVE.Utils.format_size,
-               width: 100
-           },
-           template: {
-               header: gettext('Template'),
-               type: 'integer',
-               hidden: true,
-               sortable: true,
-               width: 60
-           },
-           uptime: {
-               header: gettext('Uptime'),
-               type: 'integer',
-               renderer: PVE.Utils.render_uptime,
-               sortable: true,
-               width: 110
-           }, 
-           node: {
-               header: gettext('Node'),
-               type: 'string',
-               hidden: true,
-               sortable: true,
-               width: 110
-           },
-           storage: {
-               header: gettext('Storage'),
-               type: 'string',
-               hidden: true,
-               sortable: true,
-               width: 110
-           },
-           pool: {
-               header: gettext('Pool'),
-               type: 'string',
-               hidden: true,
-               sortable: true,
-               width: 110
-           }
-       };
-
-       var fields = [];
-       var fieldNames = [];
-       Ext.Object.each(field_defaults, function(key, value) {
-           if (!Ext.isDefined(value.convert)) {
-               fields.push({name: key, type: value.type});
-               fieldNames.push(key);
-           } else if (key === 'text' || key === 'running') { 
-               fields.push({name: key, type: value.type, convert: value.convert});
-               fieldNames.push(key);
-           }           
-       });
-
-       Ext.define('PVEResources', {
-           extend: "Ext.data.Model",
-           fields: fields,
-           proxy: {
-               type: 'pve',
-               url: '/api2/json/cluster/resources'
-           }
-       });
-
-       Ext.define('PVETree', {
-           extend: "Ext.data.Model",
-           fields: fields,
-           proxy: { type: 'memory' }
-       });
-
-       Ext.apply(config, {
-           storeid: 'PVEResources',
-           model: 'PVEResources',
-           defaultColums: function() {
-               var res = [];
-               Ext.Object.each(field_defaults, function(field, info) {
-                   var fi = Ext.apply({ dataIndex: field }, info);
-                   res.push(fi);
-               });
-               return res;
-           },
-           fieldNames: fieldNames
-       });
-
-       me.callParent([config]);
-    }
-});
diff --git a/www/manager5/data/TimezoneStore.js b/www/manager5/data/TimezoneStore.js
deleted file mode 100644 (file)
index f00cc2f..0000000
+++ /dev/null
@@ -1,436 +0,0 @@
-Ext.define('PVE.data.TimezoneStore', {
-    extend: 'Ext.data.Store',
-
-    statics: {
-       timezones: [
-           ['Africa/Abidjan'],
-           ['Africa/Accra'],
-           ['Africa/Addis_Ababa'],
-           ['Africa/Algiers'],
-           ['Africa/Asmara'],
-           ['Africa/Bamako'],
-           ['Africa/Bangui'],
-           ['Africa/Banjul'],
-           ['Africa/Bissau'],
-           ['Africa/Blantyre'],
-           ['Africa/Brazzaville'],
-           ['Africa/Bujumbura'],
-           ['Africa/Cairo'],
-           ['Africa/Casablanca'],
-           ['Africa/Ceuta'],
-           ['Africa/Conakry'],
-           ['Africa/Dakar'],
-           ['Africa/Dar_es_Salaam'],
-           ['Africa/Djibouti'],
-           ['Africa/Douala'],
-           ['Africa/El_Aaiun'],
-           ['Africa/Freetown'],
-           ['Africa/Gaborone'],
-           ['Africa/Harare'],
-           ['Africa/Johannesburg'],
-           ['Africa/Kampala'],
-           ['Africa/Khartoum'],
-           ['Africa/Kigali'],
-           ['Africa/Kinshasa'],
-           ['Africa/Lagos'],
-           ['Africa/Libreville'],
-           ['Africa/Lome'],
-           ['Africa/Luanda'],
-           ['Africa/Lubumbashi'],
-           ['Africa/Lusaka'],
-           ['Africa/Malabo'],
-           ['Africa/Maputo'],
-           ['Africa/Maseru'],
-           ['Africa/Mbabane'],
-           ['Africa/Mogadishu'],
-           ['Africa/Monrovia'],
-           ['Africa/Nairobi'],
-           ['Africa/Ndjamena'],
-           ['Africa/Niamey'],
-           ['Africa/Nouakchott'],
-           ['Africa/Ouagadougou'],
-           ['Africa/Porto-Novo'],
-           ['Africa/Sao_Tome'],
-           ['Africa/Tripoli'],
-           ['Africa/Tunis'],
-           ['Africa/Windhoek'],
-           ['America/Adak'],
-           ['America/Anchorage'],
-           ['America/Anguilla'],
-           ['America/Antigua'],
-           ['America/Araguaina'],
-           ['America/Argentina/Buenos_Aires'],
-           ['America/Argentina/Catamarca'],
-           ['America/Argentina/Cordoba'],
-           ['America/Argentina/Jujuy'],
-           ['America/Argentina/La_Rioja'],
-           ['America/Argentina/Mendoza'],
-           ['America/Argentina/Rio_Gallegos'],
-           ['America/Argentina/Salta'],
-           ['America/Argentina/San_Juan'],
-           ['America/Argentina/San_Luis'],
-           ['America/Argentina/Tucuman'],
-           ['America/Argentina/Ushuaia'],
-           ['America/Aruba'],
-           ['America/Asuncion'],
-           ['America/Atikokan'],
-           ['America/Bahia'],
-           ['America/Bahia_Banderas'],
-           ['America/Barbados'],
-           ['America/Belem'],
-           ['America/Belize'],
-           ['America/Blanc-Sablon'],
-           ['America/Boa_Vista'],
-           ['America/Bogota'],
-           ['America/Boise'],
-           ['America/Cambridge_Bay'],
-           ['America/Campo_Grande'],
-           ['America/Cancun'],
-           ['America/Caracas'],
-           ['America/Cayenne'],
-           ['America/Cayman'],
-           ['America/Chicago'],
-           ['America/Chihuahua'],
-           ['America/Costa_Rica'],
-           ['America/Cuiaba'],
-           ['America/Curacao'],
-           ['America/Danmarkshavn'],
-           ['America/Dawson'],
-           ['America/Dawson_Creek'],
-           ['America/Denver'],
-           ['America/Detroit'],
-           ['America/Dominica'],
-           ['America/Edmonton'],
-           ['America/Eirunepe'],
-           ['America/El_Salvador'],
-           ['America/Fortaleza'],
-           ['America/Glace_Bay'],
-           ['America/Godthab'],
-           ['America/Goose_Bay'],
-           ['America/Grand_Turk'],
-           ['America/Grenada'],
-           ['America/Guadeloupe'],
-           ['America/Guatemala'],
-           ['America/Guayaquil'],
-           ['America/Guyana'],
-           ['America/Halifax'],
-           ['America/Havana'],
-           ['America/Hermosillo'],
-           ['America/Indiana/Indianapolis'],
-           ['America/Indiana/Knox'],
-           ['America/Indiana/Marengo'],
-           ['America/Indiana/Petersburg'],
-           ['America/Indiana/Tell_City'],
-           ['America/Indiana/Vevay'],
-           ['America/Indiana/Vincennes'],
-           ['America/Indiana/Winamac'],
-           ['America/Inuvik'],
-           ['America/Iqaluit'],
-           ['America/Jamaica'],
-           ['America/Juneau'],
-           ['America/Kentucky/Louisville'],
-           ['America/Kentucky/Monticello'],
-           ['America/La_Paz'],
-           ['America/Lima'],
-           ['America/Los_Angeles'],
-           ['America/Maceio'],
-           ['America/Managua'],
-           ['America/Manaus'],
-           ['America/Marigot'],
-           ['America/Martinique'],
-           ['America/Matamoros'],
-           ['America/Mazatlan'],
-           ['America/Menominee'],
-           ['America/Merida'],
-           ['America/Mexico_City'],
-           ['America/Miquelon'],
-           ['America/Moncton'],
-           ['America/Monterrey'],
-           ['America/Montevideo'],
-           ['America/Montreal'],
-           ['America/Montserrat'],
-           ['America/Nassau'],
-           ['America/New_York'],
-           ['America/Nipigon'],
-           ['America/Nome'],
-           ['America/Noronha'],
-           ['America/North_Dakota/Center'],
-           ['America/North_Dakota/New_Salem'],
-           ['America/Ojinaga'],
-           ['America/Panama'],
-           ['America/Pangnirtung'],
-           ['America/Paramaribo'],
-           ['America/Phoenix'],
-           ['America/Port-au-Prince'],
-           ['America/Port_of_Spain'],
-           ['America/Porto_Velho'],
-           ['America/Puerto_Rico'],
-           ['America/Rainy_River'],
-           ['America/Rankin_Inlet'],
-           ['America/Recife'],
-           ['America/Regina'],
-           ['America/Resolute'],
-           ['America/Rio_Branco'],
-           ['America/Santa_Isabel'],
-           ['America/Santarem'],
-           ['America/Santiago'],
-           ['America/Santo_Domingo'],
-           ['America/Sao_Paulo'],
-           ['America/Scoresbysund'],
-           ['America/Shiprock'],
-           ['America/St_Barthelemy'],
-           ['America/St_Johns'],
-           ['America/St_Kitts'],
-           ['America/St_Lucia'],
-           ['America/St_Thomas'],
-           ['America/St_Vincent'],
-           ['America/Swift_Current'],
-           ['America/Tegucigalpa'],
-           ['America/Thule'],
-           ['America/Thunder_Bay'],
-           ['America/Tijuana'],
-           ['America/Toronto'],
-           ['America/Tortola'],
-           ['America/Vancouver'],
-           ['America/Whitehorse'],
-           ['America/Winnipeg'],
-           ['America/Yakutat'],
-           ['America/Yellowknife'],
-           ['Antarctica/Casey'],
-           ['Antarctica/Davis'],
-           ['Antarctica/DumontDUrville'],
-           ['Antarctica/Macquarie'],
-           ['Antarctica/Mawson'],
-           ['Antarctica/McMurdo'],
-           ['Antarctica/Palmer'],
-           ['Antarctica/Rothera'],
-           ['Antarctica/South_Pole'],
-           ['Antarctica/Syowa'],
-           ['Antarctica/Vostok'],
-           ['Arctic/Longyearbyen'],
-           ['Asia/Aden'],
-           ['Asia/Almaty'],
-           ['Asia/Amman'],
-           ['Asia/Anadyr'],
-           ['Asia/Aqtau'],
-           ['Asia/Aqtobe'],
-           ['Asia/Ashgabat'],
-           ['Asia/Baghdad'],
-           ['Asia/Bahrain'],
-           ['Asia/Baku'],
-           ['Asia/Bangkok'],
-           ['Asia/Beirut'],
-           ['Asia/Bishkek'],
-           ['Asia/Brunei'],
-           ['Asia/Choibalsan'],
-           ['Asia/Chongqing'],
-           ['Asia/Colombo'],
-           ['Asia/Damascus'],
-           ['Asia/Dhaka'],
-           ['Asia/Dili'],
-           ['Asia/Dubai'],
-           ['Asia/Dushanbe'],
-           ['Asia/Gaza'],
-           ['Asia/Harbin'],
-           ['Asia/Ho_Chi_Minh'],
-           ['Asia/Hong_Kong'],
-           ['Asia/Hovd'],
-           ['Asia/Irkutsk'],
-           ['Asia/Jakarta'],
-           ['Asia/Jayapura'],
-           ['Asia/Jerusalem'],
-           ['Asia/Kabul'],
-           ['Asia/Kamchatka'],
-           ['Asia/Karachi'],
-           ['Asia/Kashgar'],
-           ['Asia/Kathmandu'],
-           ['Asia/Kolkata'],
-           ['Asia/Krasnoyarsk'],
-           ['Asia/Kuala_Lumpur'],
-           ['Asia/Kuching'],
-           ['Asia/Kuwait'],
-           ['Asia/Macau'],
-           ['Asia/Magadan'],
-           ['Asia/Makassar'],
-           ['Asia/Manila'],
-           ['Asia/Muscat'],
-           ['Asia/Nicosia'],
-           ['Asia/Novokuznetsk'],
-           ['Asia/Novosibirsk'],
-           ['Asia/Omsk'],
-           ['Asia/Oral'],
-           ['Asia/Phnom_Penh'],
-           ['Asia/Pontianak'],
-           ['Asia/Pyongyang'],
-           ['Asia/Qatar'],
-           ['Asia/Qyzylorda'],
-           ['Asia/Rangoon'],
-           ['Asia/Riyadh'],
-           ['Asia/Sakhalin'],
-           ['Asia/Samarkand'],
-           ['Asia/Seoul'],
-           ['Asia/Shanghai'],
-           ['Asia/Singapore'],
-           ['Asia/Taipei'],
-           ['Asia/Tashkent'],
-           ['Asia/Tbilisi'],
-           ['Asia/Tehran'],
-           ['Asia/Thimphu'],
-           ['Asia/Tokyo'],
-           ['Asia/Ulaanbaatar'],
-           ['Asia/Urumqi'],
-           ['Asia/Vientiane'],
-           ['Asia/Vladivostok'],
-           ['Asia/Yakutsk'],
-           ['Asia/Yekaterinburg'],
-           ['Asia/Yerevan'],
-           ['Atlantic/Azores'],
-           ['Atlantic/Bermuda'],
-           ['Atlantic/Canary'],
-           ['Atlantic/Cape_Verde'],
-           ['Atlantic/Faroe'],
-           ['Atlantic/Madeira'],
-           ['Atlantic/Reykjavik'],
-           ['Atlantic/South_Georgia'],
-           ['Atlantic/St_Helena'],
-           ['Atlantic/Stanley'],
-           ['Australia/Adelaide'],
-           ['Australia/Brisbane'],
-           ['Australia/Broken_Hill'],
-           ['Australia/Currie'],
-           ['Australia/Darwin'],
-           ['Australia/Eucla'],
-           ['Australia/Hobart'],
-           ['Australia/Lindeman'],
-           ['Australia/Lord_Howe'],
-           ['Australia/Melbourne'],
-           ['Australia/Perth'],
-           ['Australia/Sydney'],
-           ['Europe/Amsterdam'],
-           ['Europe/Andorra'],
-           ['Europe/Athens'],
-           ['Europe/Belgrade'],
-           ['Europe/Berlin'],
-           ['Europe/Bratislava'],
-           ['Europe/Brussels'],
-           ['Europe/Bucharest'],
-           ['Europe/Budapest'],
-           ['Europe/Chisinau'],
-           ['Europe/Copenhagen'],
-           ['Europe/Dublin'],
-           ['Europe/Gibraltar'],
-           ['Europe/Guernsey'],
-           ['Europe/Helsinki'],
-           ['Europe/Isle_of_Man'],
-           ['Europe/Istanbul'],
-           ['Europe/Jersey'],
-           ['Europe/Kaliningrad'],
-           ['Europe/Kiev'],
-           ['Europe/Lisbon'],
-           ['Europe/Ljubljana'],
-           ['Europe/London'],
-           ['Europe/Luxembourg'],
-           ['Europe/Madrid'],
-           ['Europe/Malta'],
-           ['Europe/Mariehamn'],
-           ['Europe/Minsk'],
-           ['Europe/Monaco'],
-           ['Europe/Moscow'],
-           ['Europe/Oslo'],
-           ['Europe/Paris'],
-           ['Europe/Podgorica'],
-           ['Europe/Prague'],
-           ['Europe/Riga'],
-           ['Europe/Rome'],
-           ['Europe/Samara'],
-           ['Europe/San_Marino'],
-           ['Europe/Sarajevo'],
-           ['Europe/Simferopol'],
-           ['Europe/Skopje'],
-           ['Europe/Sofia'],
-           ['Europe/Stockholm'],
-           ['Europe/Tallinn'],
-           ['Europe/Tirane'],
-           ['Europe/Uzhgorod'],
-           ['Europe/Vaduz'],
-           ['Europe/Vatican'],
-           ['Europe/Vienna'],
-           ['Europe/Vilnius'],
-           ['Europe/Volgograd'],
-           ['Europe/Warsaw'],
-           ['Europe/Zagreb'],
-           ['Europe/Zaporozhye'],
-           ['Europe/Zurich'],
-           ['Indian/Antananarivo'],
-           ['Indian/Chagos'],
-           ['Indian/Christmas'],
-           ['Indian/Cocos'],
-           ['Indian/Comoro'],
-           ['Indian/Kerguelen'],
-           ['Indian/Mahe'],
-           ['Indian/Maldives'],
-           ['Indian/Mauritius'],
-           ['Indian/Mayotte'],
-           ['Indian/Reunion'],
-           ['Pacific/Apia'],
-           ['Pacific/Auckland'],
-           ['Pacific/Chatham'],
-           ['Pacific/Chuuk'],
-           ['Pacific/Easter'],
-           ['Pacific/Efate'],
-           ['Pacific/Enderbury'],
-           ['Pacific/Fakaofo'],
-           ['Pacific/Fiji'],
-           ['Pacific/Funafuti'],
-           ['Pacific/Galapagos'],
-           ['Pacific/Gambier'],
-           ['Pacific/Guadalcanal'],
-           ['Pacific/Guam'],
-           ['Pacific/Honolulu'],
-           ['Pacific/Johnston'],
-           ['Pacific/Kiritimati'],
-           ['Pacific/Kosrae'],
-           ['Pacific/Kwajalein'],
-           ['Pacific/Majuro'],
-           ['Pacific/Marquesas'],
-           ['Pacific/Midway'],
-           ['Pacific/Nauru'],
-           ['Pacific/Niue'],
-           ['Pacific/Norfolk'],
-           ['Pacific/Noumea'],
-           ['Pacific/Pago_Pago'],
-           ['Pacific/Palau'],
-           ['Pacific/Pitcairn'],
-           ['Pacific/Pohnpei'],
-           ['Pacific/Port_Moresby'],
-           ['Pacific/Rarotonga'],
-           ['Pacific/Saipan'],
-           ['Pacific/Tahiti'],
-           ['Pacific/Tarawa'],
-           ['Pacific/Tongatapu'],
-           ['Pacific/Wake'],
-           ['Pacific/Wallis']
-       ]
-    },
-
-    constructor: function(config) {
-       var me = this;
-
-       config = config || {};
-
-       Ext.regModel('Timezone', {
-           fields: ['zone'],
-           proxy: {
-               type: 'memory',
-               reader: 'array'
-           }
-       });
-
-       Ext.apply(config, {
-           model: 'Timezone',
-           data: PVE.data.TimezoneStore.timezones
-       });
-
-       me.callParent([config]);        
-    }
-});
\ No newline at end of file
diff --git a/www/manager5/data/UpdateQueue.js b/www/manager5/data/UpdateQueue.js
deleted file mode 100644 (file)
index 121aba6..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-// Serialize load (avoid too many parallel connections)
-Ext.define('PVE.data.UpdateQueue', {
-    singleton: true,
-
-    constructor : function(){
-        var me = this;
-
-       var queue = [];
-       var queue_idx = {};
-
-       var idle = true;
-
-       var start_update = function() {
-           if (!idle) {
-               return;
-           }
-
-           var storeid = queue.shift();
-           if (!storeid) {
-               return;
-           }
-           var info = queue_idx[storeid];
-           queue_idx[storeid] = null;
-
-           info.updatestart = new Date();
-
-           idle = false;
-           info.store.load({
-               callback: function(records, operation, success) {
-                   idle = true;
-                   if (info.callback) {
-                       var runtime = (new Date()).getTime() - info.updatestart.getTime();
-                       info.callback(runtime, success);
-                   }
-                   start_update();
-               }
-           });
-       };
-
-       Ext.apply(me, {
-           queue: function(store, cb) {
-               var storeid = store.storeid;
-               if (!storeid) {
-                   throw "unable to queue store without storeid";
-               }
-               if (!queue_idx[storeid]) {
-                   queue_idx[storeid] = {
-                       store: store,
-                       callback: cb
-                   };
-                   queue.push(storeid);
-               }
-               start_update();
-           }
-       });
-    }
-});
diff --git a/www/manager5/data/UpdateStore.js b/www/manager5/data/UpdateStore.js
deleted file mode 100644 (file)
index bf48611..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Extends the Ext.data.Store type
- * with  startUpdate() and stopUpdate() methods
- * to refresh the store data in the background
- * Components using this store directly will flicker
- * due to the redisplay of the element ater 'config.interval' ms
- */
-Ext.define('PVE.data.UpdateStore', {
-    extend: 'Ext.data.Store',
-
-    constructor: function(config) {
-       var me = this;
-
-       config = config || {};
-
-       if (!config.interval) {
-           config.interval = 3000;
-       }
-
-       if (!config.storeid) {
-           throw "no storeid specified";
-       }
-
-       var load_task = new Ext.util.DelayedTask();
-
-       var run_load_task = function() {
-           if (PVE.Utils.authOK()) {
-               PVE.data.UpdateQueue.queue(me, function(runtime, success) {
-                   var interval = config.interval + runtime*2;
-                   load_task.delay(interval, run_load_task);
-               });
-           } else {
-               load_task.delay(200, run_load_task);
-           }
-       };
-
-       Ext.apply(config, {
-           startUpdate: function() {
-               run_load_task();
-           },
-           stopUpdate: function() {
-               load_task.cancel();
-           }
-       });
-
-       me.callParent([config]);
-
-       me.on('destroy', function() {
-           load_task.cancel();
-       });
-    }
-});
diff --git a/www/manager5/data/reader/JsonObject.js b/www/manager5/data/reader/JsonObject.js
deleted file mode 100644 (file)
index 4323e3e..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/* A reader to store a single JSON Object (hash) into a storage.
- * Also accepts an array containing a single hash. 
- *
- * So it can read:
- *
- * example1: {data1: "xyz", data2: "abc"} 
- * returns [{key: "data1", value: "xyz"}, {key: "data2", value: "abc"}]
- *
- * example2: [ {data1: "xyz", data2: "abc"} ] 
- * returns [{key: "data1", value: "xyz"}, {key: "data2", value: "abc"}]
- *
- * If you set 'readArray', the reader expexts the object as array:
- *
- * example3: [ { key: "data1", value: "xyz", p2: "cde" },  { key: "data2", value: "abc", p2: "efg" }]
- * returns [{key: "data1", value: "xyz", p2: "cde}, {key: "data2", value: "abc", p2: "efg"}]
- *
- * Note: The records can contain additional properties (like 'p2' above) when you use 'readArray'
- *
- * Additional feature: specify allowed properties with default values with 'rows' object
- *
- * var rows = {
- *   memory: {
- *     required: true,
- *     defaultValue: 512
- *   }
- * }
- *
- */
-
-Ext.define('PVE.data.reader.JsonObject', {
-    extend: 'Ext.data.reader.Json',
-    alias : 'reader.jsonobject',
-    
-    readArray: false,
-
-    rows: undefined,
-
-    constructor: function(config) {
-        var me = this;
-
-        Ext.apply(me, config || {});
-
-       me.callParent([config]);
-    },
-
-    getResponseData: function(response) {
-       var me = this;
-
-       var data = [];
-        try {
-        var result = Ext.decode(response.responseText);
-        // get our data items inside the server response
-        var root = result[me.getRootProperty()];
-
-           if (me.readArray) {
-
-               var rec_hash = {};
-               Ext.Array.each(root, function(rec) {
-                   if (Ext.isDefined(rec.key)) {
-                       rec_hash[rec.key] = rec;
-                   }
-               });
-
-               if (me.rows) {
-                   Ext.Object.each(me.rows, function(key, rowdef) {
-                       var rec = rec_hash[key];
-                       if (Ext.isDefined(rec)) {
-                           if (!Ext.isDefined(rec.value)) {
-                               rec.value = rowdef.defaultValue;
-                           }
-                           data.push(rec);
-                       } else if (Ext.isDefined(rowdef.defaultValue)) {
-                           data.push({key: key, value: rowdef.defaultValue} );
-                       } else if (rowdef.required) {
-                           data.push({key: key, value: undefined });
-                       }
-                   });
-               } else {
-                   Ext.Array.each(root, function(rec) {
-                       if (Ext.isDefined(rec.key)) {
-                           data.push(rec);
-                       }
-                   });
-               }
-               
-           } else { 
-               
-               var org_root = root;
-
-               if (Ext.isArray(org_root)) {
-                   if (root.length == 1) {
-                       root = org_root[0];
-                   } else {
-                       root = {};
-                   }
-               }
-
-               if (me.rows) {
-                   Ext.Object.each(me.rows, function(key, rowdef) {
-                       if (Ext.isDefined(root[key])) {
-                           data.push({key: key, value: root[key]});
-                       } else if (Ext.isDefined(rowdef.defaultValue)) {
-                           data.push({key: key, value: rowdef.defaultValue});
-                       } else if (rowdef.required) {
-                           data.push({key: key, value: undefined});
-                       }
-                   });
-               } else {
-                   Ext.Object.each(root, function(key, value) {
-                       data.push({key: key, value: value });
-                   });
-               }
-           }
-       }
-        catch (ex) {
-            Ext.Error.raise({
-                response: response,
-                json: response.responseText,
-                parseError: ex,
-                msg: 'Unable to parse the JSON returned by the server: ' + ex.toString()
-            });
-        }
-
-       return data;
-    }
-});
-
diff --git a/www/manager5/dc/ACLView.js b/www/manager5/dc/ACLView.js
deleted file mode 100644 (file)
index 7ea314c..0000000
+++ /dev/null
@@ -1,244 +0,0 @@
-Ext.define('PVE.dc.ACLAdd', {
-    extend: 'PVE.window.Edit',
-    alias: ['widget.pveACLAdd'],
-
-    initComponent : function() {
-       /*jslint confusion: true */
-        var me = this;
-
-       me.create = true;
-
-       var items = [
-           {
-               xtype: me.path ? 'hiddenfield' : 'textfield',
-               name: 'path',
-               value: me.path,
-               allowBlank: false,
-               fieldLabel: gettext('Path')
-           }
-       ];
-
-       if (me.aclType === 'group') {
-           me.subject = gettext("Group Permission");
-           items.push({
-               xtype: 'pveGroupSelector',
-               name: 'groups',
-               fieldLabel: gettext('Group')
-           });
-       } else if (me.aclType === 'user') {
-           me.subject = gettext("User Permission");
-           items.push({
-               xtype: 'pveUserSelector',
-               name: 'users',
-               fieldLabel: gettext('User')
-           });
-       } else {
-           throw "unknown ACL type";
-       }
-
-       items.push({
-           xtype: 'pveRoleSelector',
-           name: 'roles',
-           value: 'NoAccess',
-           fieldLabel: gettext('Role')
-       });
-
-       if (!me.path) {
-           items.push({
-               xtype: 'pvecheckbox',
-               name: 'propagate',
-               checked: true,
-               fieldLabel: gettext('Propagate')
-           });
-       }
-
-       var ipanel = Ext.create('PVE.panel.InputPanel', {
-           items: items
-       });
-
-       Ext.apply(me, {
-           url: '/access/acl',
-           method: 'PUT',
-           isAdd: true,
-           items: [ ipanel ]
-       });
-           
-       me.callParent();
-    }
-});
-
-Ext.define('PVE.dc.ACLView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveACLView'],
-
-    // use fixed path
-    path: undefined,
-
-    initComponent : function() {
-       var me = this;
-
-       var store = new Ext.data.Store({
-           model: 'pve-acl',
-           proxy: {
-                type: 'pve',
-               url: "/api2/json/access/acl"
-           },
-           sorters: { 
-               property: 'path', 
-               order: 'DESC' 
-           }
-       });
-
-       if (me.path) {
-           store.filters.add(new Ext.util.Filter({
-               filterFn: function(item) {
-                   if (item.data.path === me.path) {
-                       return true;
-                   }
-               }
-           }));
-       }
-
-       var render_ugid = function(ugid, metaData, record) {
-           if (record.data.type == 'group') {
-               return '@' + ugid;
-           }
-
-           return ugid;
-       };
-
-       var columns = [
-           {
-               header: gettext('User') + '/' + gettext('Group'),
-               flex: 1,
-               sortable: true,
-               renderer: render_ugid,
-               dataIndex: 'ugid'
-           },
-           {
-               header: gettext('Role'),
-               flex: 1,
-               sortable: true,
-               dataIndex: 'roleid'
-           }
-       ];
-
-       if (!me.path) {
-           columns.unshift({
-               header: gettext('Path'),
-               flex: 1,
-               sortable: true,
-               dataIndex: 'path'
-           });
-           columns.push({
-               header: gettext('Propagate'),
-               width: 80,
-               sortable: true,
-               dataIndex: 'propagate'
-           });
-       }
-
-       var sm = Ext.create('Ext.selection.RowModel', {});
-
-       var reload = function() {
-           store.load();
-       };
-
-       var remove_btn = new PVE.button.Button({
-           text: gettext('Remove'),
-           disabled: true,
-           selModel: sm,
-           confirmMsg: gettext('Are you sure you want to remove this entry'),
-           handler: function(btn, event, rec) {
-               var params = { 
-                   'delete': 1, 
-                   path: rec.data.path, 
-                   roles: rec.data.roleid
-               };
-               if (rec.data.type === 'group') {
-                   params.groups = rec.data.ugid;
-               } else if (rec.data.type === 'user') {
-                   params.users = rec.data.ugid;
-               } else {
-                   throw 'unknown data type';
-               }
-
-               PVE.Utils.API2Request({
-                   url: '/access/acl',
-                   params: params,
-                   method: 'PUT',
-                   waitMsgTarget: me,
-                   callback: function() {
-                       reload();
-                   },
-                   failure: function (response, opts) {
-                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-                   }
-               });
-           }
-       });
-
-       PVE.Utils.monStoreErrors(me, store);
-
-       Ext.apply(me, {
-           store: store,
-           selModel: sm,
-           stateful: false,
-           tbar: [
-               {
-                   text: gettext('Add'),
-                   menu: new Ext.menu.Menu({
-                       items: [
-                           {
-                               text: gettext('Group Permission'),
-                               handler: function() {
-                                   var win = Ext.create('PVE.dc.ACLAdd',{
-                                       aclType: 'group',
-                                       path: me.path
-                                   });
-                                   win.on('destroy', reload);
-                                   win.show();
-                               }
-                           },
-                           {
-                               text: gettext('User Permission'),
-                               handler: function() {
-                                   var win = Ext.create('PVE.dc.ACLAdd',{
-                                       aclType: 'user',
-                                       path: me.path
-                                   });
-                                   win.on('destroy', reload);
-                                   win.show();
-                               }
-                           }
-                       ]
-                   })
-               },
-               remove_btn
-           ],
-           viewConfig: {
-               trackOver: false
-           },
-           columns: columns,
-           listeners: {
-               show: reload
-           }
-       });
-
-       me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-acl', {
-       extend: 'Ext.data.Model',
-       fields: [ 
-           'path', 'type', 'ugid', 'roleid', 
-           { 
-               name: 'propagate', 
-               type: 'boolean'
-           } 
-       ]
-    });
-
-});
\ No newline at end of file
diff --git a/www/manager5/dc/AuthEdit.js b/www/manager5/dc/AuthEdit.js
deleted file mode 100644 (file)
index 356f004..0000000
+++ /dev/null
@@ -1,284 +0,0 @@
-Ext.define('PVE.dc.AuthEdit', {
-    extend: 'PVE.window.Edit',
-    alias: ['widget.pveDcAuthEdit'],
-
-    isAdd: true,
-
-    initComponent : function() {
-        var me = this;
-
-        me.create = !me.realm;
-
-        var url;
-        var method;
-        var serverlist;
-
-        if (me.create) {
-            url = '/api2/extjs/access/domains';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/access/domains/' + me.realm;
-            method = 'PUT';
-        }
-
-        var column1 = [
-            {
-                xtype: me.create ? 'textfield' : 'displayfield',
-               height: 22, // hack: set same height as text fields
-                name: 'realm',
-                fieldLabel: gettext('Realm'),
-                value: me.realm,
-                allowBlank: false
-            }
-       ];
-
-       if (me.authType === 'ad') {
-
-           me.subject = gettext('Active Directory Server');
-
-            column1.push({
-                xtype: 'textfield',
-                name: 'domain',
-                fieldLabel: gettext('Domain'),
-                emptyText: 'company.net',
-                allowBlank: false
-            });
-
-       } else if (me.authType === 'ldap') {
-
-           me.subject = gettext('LDAP Server');
-
-            column1.push({
-                xtype: 'textfield',
-                name: 'base_dn',
-                fieldLabel: gettext('Base Domain Name'),
-               emptyText: 'CN=Users,DC=Company,DC=net',
-                allowBlank: false
-            });
-
-            column1.push({
-                xtype: 'textfield',
-                name: 'user_attr',
-                emptyText: 'uid / sAMAccountName',
-                fieldLabel: gettext('User Attribute Name'),
-                allowBlank: false
-            });
-       } else if (me.authType === 'pve') {
-
-           if (me.create) throw 'unknown auth type';
-
-           me.subject = 'Proxmox VE authentication server';
-
-       } else if (me.authType === 'pam') {
-
-           if (me.create) throw 'unknown auth type';
-
-           me.subject = 'linux PAM';
-
-       } else {
-           throw 'unknown auth type ';
-       }
-
-        column1.push({
-            xtype: 'pvecheckbox',
-            fieldLabel: gettext('Default'),
-            name: 'default',
-            uncheckedValue: 0
-        });
-
-        var column2 = [];
-
-       if (me.authType === 'ldap' || me.authType === 'ad') {
-           column2.push([
-               {
-                    xtype: 'textfield',
-                    fieldLabel: gettext('Server'),
-                    name: 'server1',
-                    allowBlank: false
-               },
-               {
-                    xtype: 'pvetextfield',
-                    fieldLabel: gettext('Fallback Server'),
-                   deleteEmpty: !me.create,
-                   name: 'server2'
-               },
-               {
-                    xtype: 'numberfield',
-                    name: 'port',
-                    fieldLabel: gettext('Port'),
-                    minValue: 1,
-                    maxValue: 65535,
-                   emptyText: gettext('Default'),
-                   submitEmptyText: false
-               },
-               {
-                    xtype: 'pvecheckbox',
-                    fieldLabel: 'SSL',
-                    name: 'secure',
-                    uncheckedValue: 0
-               }
-            ]);
-       }
-
-       // Two Factor Auth settings
-
-        column2.push({
-            xtype: 'pveKVComboBox',
-            name: 'tfa',
-           deleteEmpty: !me.create,
-           value: '',
-            fieldLabel: gettext('TFA'),
-           data: [ ['', PVE.Utils.noneText], ['oath', 'OATH'], ['yubico', 'Yubico']],
-           listeners: {
-               change: function(f, value) {
-                   if (!me.rendered) {
-                       return;
-                   }
-                   me.down('field[name=oath_step]').setVisible(value === 'oath');
-                   me.down('field[name=oath_digits]').setVisible(value === 'oath');
-                   me.down('field[name=yubico_api_id]').setVisible(value === 'yubico');
-                   me.down('field[name=yubico_api_key]').setVisible(value === 'yubico');
-                   me.down('field[name=yubico_url]').setVisible(value === 'yubico');
-               }
-           }
-        });
-
-       column2.push({
-            xtype: 'numberfield',
-            name: 'oath_step',
-           value: '',
-           minValue: 10,
-           step: 1,
-           allowDecimals: false,
-           allowBlank: true,
-           emptyText: PVE.Utils.defaultText + ' (30)',
-           submitEmptyText: false,
-           hidden: true,
-            fieldLabel: 'OATH time step'
-        });
-
-       column2.push({
-            xtype: 'numberfield',
-            name: 'oath_digits',
-           value: '',
-           minValue: 6,
-           maxValue: 8,
-           step: 1,
-           allowDecimals: false,
-           allowBlank: true,
-           emptyText: PVE.Utils.defaultText + ' (6)',
-           submitEmptyText: false,
-           hidden: true,
-            fieldLabel: 'OATH password length'
-        });
-
-       column2.push({
-            xtype: 'textfield',
-            name: 'yubico_api_id',
-           hidden: true,
-            fieldLabel: 'Yubico API Id'
-        });
-
-       column2.push({
-            xtype: 'textfield',
-            name: 'yubico_api_key',
-           hidden: true,
-            fieldLabel: 'Yubico API Key'
-        });
-
-       column2.push({
-            xtype: 'textfield',
-            name: 'yubico_url',
-           hidden: true,
-            fieldLabel: 'Yubico URL'
-        });
-
-       var ipanel = Ext.create('PVE.panel.InputPanel', {
-           column1: column1,
-           column2: column2,
-           columnB: [{
-               xtype: 'textfield',
-               name: 'comment',
-               fieldLabel: gettext('Comment')
-            }],
-           onGetValues: function(values) {
-               if (!values.port) {
-                   if (!me.create) {
-                       PVE.Utils.assemble_field_data(values, { 'delete': 'port' });
-                   }
-                   delete values.port;
-               }
-
-               if (me.create) {
-                   values.type = me.authType;
-               }
-
-               if (values.tfa === 'oath') {
-                   values.tfa = "type=oath";
-                   if (values.oath_step) {
-                       values.tfa += ",step=" + values.oath_step;
-                   }
-                   if (values.oath_digits) {
-                       values.tfa += ",digits=" + values.oath_digits;
-                   }
-               } else if (values.tfa === 'yubico') {
-                   values.tfa = "type=yubico";
-                   values.tfa += ",id=" + values.yubico_api_id;
-                   values.tfa += ",key=" + values.yubico_api_key;
-                   if (values.yubico_url) {
-                       values.tfa += ",url=" + values.yubico_url;
-                   }
-               } else {
-                   delete values.tfa;
-               }
-
-               delete values.oath_step;
-               delete values.oath_digits;
-               delete values.yubico_api_id;
-               delete values.yubico_api_key;
-               delete values.yubico_url;
-               
-               return values;
-           }
-       });
-
-       Ext.applyIf(me, {
-            url: url,
-            method: method,
-           fieldDefaults: {
-               labelWidth: 120
-           },
-           items: [ ipanel ]
-        });
-
-        me.callParent();
-
-        if (!me.create) {
-            me.load({
-                success: function(response, options) {
-                   var data = response.result.data || {};
-                   // just to be sure (should not happen)
-                   if (data.type !== me.authType) {
-                       me.close();
-                       throw "got wrong auth type";
-                   }
-
-                   if (data.tfa) {
-                       var tfacfg = PVE.Parser.parseTfaConfig(data.tfa);
-                       data.tfa = tfacfg.type;
-                       if (tfacfg.type === 'yubico') {
-                           data.yubico_api_key = tfacfg.key;
-                           data.yubico_api_id = tfacfg.id;
-                           data.yubico_url = tfacfg.url;
-                       } else if (tfacfg.type === 'oath') {
-                           data.oath_step = tfacfg.step;
-                           data.oath_digits = tfacfg.digits;
-                       }
-                   }
-
-                    me.setValues(data);
-                }
-            });
-        }
-    }
-});
diff --git a/www/manager5/dc/AuthView.js b/www/manager5/dc/AuthView.js
deleted file mode 100644 (file)
index 83e79c6..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-Ext.define('PVE.dc.AuthView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveAuthView'],
-
-    initComponent : function() {
-       var me = this;
-
-       var store = new Ext.data.Store({
-           model: 'pve-domains',
-           sorters: { 
-               property: 'realm', 
-               order: 'DESC' 
-           }
-       });
-
-       var reload = function() {
-           store.load();
-       };
-
-       var sm = Ext.create('Ext.selection.RowModel', {});
-
-       var run_editor = function() {
-           var rec = sm.getSelection()[0];
-           if (!rec) {
-               return;
-           }
-
-            var win = Ext.create('PVE.dc.AuthEdit',{
-                realm: rec.data.realm,
-               authType: rec.data.type
-            });
-            win.on('destroy', reload);
-            win.show();
-       };
-
-       var edit_btn = new PVE.button.Button({
-           text: gettext('Edit'),
-           disabled: true,
-           selModel: sm,
-           handler: run_editor
-       });
-
-       var remove_btn = new PVE.button.Button({
-           text: gettext('Remove'),
-           disabled: true,
-           selModel: sm,
-           confirmMsg: function (rec) {
-               return Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-                                        "'" + rec.data.realm + "'");
-           },
-           enableFn: function(rec) {
-               return !(rec.data.type === 'pve' || rec.data.type === 'pam');
-           },
-           handler: function(btn, event, rec) {
-               var realm = rec.data.realm;
-
-               PVE.Utils.API2Request({
-                   url: '/access/domains/' + realm,
-                   method: 'DELETE',
-                   waitMsgTarget: me,
-                   callback: function() {
-                       reload();
-                   },
-                   failure: function (response, opts) {
-                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-                   }
-               });
-           }
-        });
-
-        var tbar = [
-           {
-               text: gettext('Add'),
-               menu: new Ext.menu.Menu({
-                   items: [
-                       {
-                           text: gettext('Active Directory Server'),
-                           handler: function() {
-                               var win = Ext.create('PVE.dc.AuthEdit', {
-                                   authType: 'ad'
-                               });
-                               win.on('destroy', reload);
-                               win.show();
-                           }
-                       },
-                       {
-                           text: gettext('LDAP Server'),
-                           handler: function() {
-                               var win = Ext.create('PVE.dc.AuthEdit',{
-                                   authType: 'ldap'
-                               });
-                               win.on('destroy', reload);
-                               win.show();
-                           }
-                       }
-                   ]
-               })
-           },
-           edit_btn, remove_btn
-        ];
-
-       Ext.apply(me, {
-           store: store,
-           selModel: sm,
-           stateful: false,
-            tbar: tbar,
-           viewConfig: {
-               trackOver: false
-           },
-           columns: [
-               {
-                   header: gettext('Realm'),
-                   width: 100,
-                   sortable: true,
-                   dataIndex: 'realm'
-               },
-               {
-                   header: gettext('Type'),
-                   width: 100,
-                   sortable: true,
-                   dataIndex: 'type'
-               },
-               {
-                   header: gettext('TFA'),
-                   width: 100,
-                   sortable: true,
-                   dataIndex: 'tfa'
-               },
-               {
-                   id: 'comment',
-                   header: gettext('Comment'),
-                   sortable: false,
-                   dataIndex: 'comment',
-                   flex: 1
-               }
-           ],
-           listeners: {
-               show: reload,
-               itemdblclick: run_editor
-           }
-       });
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/dc/Backup.js b/www/manager5/dc/Backup.js
deleted file mode 100644 (file)
index 9cc2f7d..0000000
+++ /dev/null
@@ -1,473 +0,0 @@
-Ext.define('PVE.dc.BackupEdit', {
-    extend: 'PVE.window.Edit',
-    alias: ['widget.pveDcBackupEdit'],
-
-    initComponent : function() {
-       /*jslint confusion: true */
-         var me = this;
-
-        me.create = !me.jobid;
-
-       var url;
-       var method;
-
-       if (me.create) {
-            url = '/api2/extjs/cluster/backup';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/cluster/backup/' + me.jobid;
-            method = 'PUT';
-        }
-
-       var vmidField = Ext.create('Ext.form.field.Hidden', {
-           name: 'vmid'
-       });
-
-       var selModeField =  Ext.create('PVE.form.KVComboBox', {
-           xtype: 'pveKVComboBox',
-           data: [
-               ['include', gettext('Include selected VMs')],
-               ['all', gettext('All')],
-               ['exclude', gettext('Exclude selected VMs')]
-           ],
-           fieldLabel: gettext('Selection mode'),
-           name: 'selMode',
-           value: ''
-       });
-
-       var insideUpdate = false;
-       
-       var sm = Ext.create('Ext.selection.CheckboxModel', {
-           mode: 'SIMPLE',
-           listeners: {
-               selectionchange: function(model, selected) {
-                   if (!insideUpdate) { // avoid endless loop
-                       var sel = [];
-                       Ext.Array.each(selected, function(record) {
-                           sel.push(record.data.vmid);
-                       });
-
-                       insideUpdate = true;
-                       vmidField.setValue(sel);
-                       insideUpdate = false;
-                   }
-               }
-           }
-       });
-
-       var storagesel = Ext.create('PVE.form.StorageSelector', {
-           fieldLabel: gettext('Storage'),
-           nodename: 'localhost',
-           storageContent: 'backup',
-           allowBlank: false,
-           name: 'storage'
-       });
-
-       var store = new Ext.data.Store({
-           model: 'PVEResources',
-           sorters: { 
-               property: 'vmid', 
-               order: 'ASC' 
-           }
-       });
-
-       var vmgrid = Ext.createWidget('grid', {
-           store: store,
-           border: true,
-           height: 300,
-           selModel: sm,
-           disabled: true,
-           columns: [
-               { 
-                   header: 'ID',
-                   dataIndex: 'vmid',
-                   width: 60
-               },
-               { 
-                   header: gettext('Node'),
-                   dataIndex: 'node'
-               },
-               { 
-                   header: gettext('Status'),
-                   dataIndex: 'uptime',
-                   renderer: function(value) {
-                       if (value) {
-                           return PVE.Utils.runningText;
-                       } else {
-                           return PVE.Utils.stoppedText;
-                       }
-                   }
-               },
-               { 
-                   header: gettext('Name'), 
-                   dataIndex: 'name',
-                   flex: 1 
-               },
-               { 
-                   header: gettext('Type'), 
-                   dataIndex: 'type'
-               }
-           ]
-       });
-
-       var nodesel = Ext.create('PVE.form.NodeSelector', {
-           name: 'node',
-           fieldLabel: gettext('Node'),
-           allowBlank: true,
-           editable: true,
-           autoSelect: false,
-           emptyText: '-- ' + gettext('All') + ' --',
-           listeners: {
-               change: function(f, value) {
-                   storagesel.setNodename(value || 'localhost');
-                   var mode = selModeField.getValue();
-                   store.clearFilter();
-                   store.filterBy(function(rec) {
-                       return (!value || rec.get('node') === value);
-                   });
-                   if (mode === 'all') {
-                       sm.selectAll(true);
-                   }
-               }
-           }
-       });
-
-       var column1 = [
-           nodesel,
-           storagesel,
-           {
-               xtype: 'pveDayOfWeekSelector',
-               name: 'dow',
-               fieldLabel: gettext('Day of week'),
-               multiSelect: true,
-               value: ['sat'],
-               allowBlank: false
-           },
-           {
-               xtype: 'timefield',
-               fieldLabel: gettext('Start Time'),
-               name: 'starttime',
-               format: 'H:i',
-               value: '00:00',
-               allowBlank: false
-           },
-           selModeField
-       ];
-
-       var column2 = [
-           {
-               xtype: 'textfield',
-               fieldLabel: gettext('Send email to'),
-               name: 'mailto'
-           },
-           {
-               xtype: 'pveEmailNotificationSelector',
-               fieldLabel: gettext('Email notification'),
-               name: 'mailnotification',
-               deleteEmpty: me.create ? false : true,
-               value: me.create ? 'always' : ''
-           },
-           {
-               xtype: 'pveCompressionSelector',
-               fieldLabel: gettext('Compression'),
-               name: 'compress',
-               deleteEmpty: me.create ? false : true,
-               value: me.create ? 'lzo' : ''
-           },
-           {
-               xtype: 'pveBackupModeSelector',
-               fieldLabel: gettext('Mode'),
-               value: 'snapshot',
-               name: 'mode'
-           },
-           vmidField
-       ];
-
-       var ipanel = Ext.create('PVE.panel.InputPanel', {
-           column1: column1,
-           column2:  column2,
-           onGetValues: function(values) {
-               if (!values.node) {
-                   if (!me.create) {
-                       PVE.Utils.assemble_field_data(values, { 'delete': 'node' }); 
-                   }
-                   delete values.node;
-               }
-
-               var selMode = values.selMode;
-               delete values.selMode;
-
-               if (selMode === 'all') {
-                   values.all = 1;
-                   values.exclude = '';
-                   delete values.vmid;
-               } else if (selMode === 'exclude') {
-                   values.all = 1;
-                   values.exclude = values.vmid;
-                   delete values.vmid;
-               }
-               return values;
-           }
-       });
-
-       var update_vmid_selection = function(list, mode) {
-           if (insideUpdate) {
-               return; // should not happen - just to be sure
-           }
-           insideUpdate = true;
-           if (mode !== 'all') {
-               sm.deselectAll(true);
-               if (list) {
-                   Ext.Array.each(list.split(','), function(vmid) {
-                       var rec = store.findRecord('vmid', vmid);
-                       if (rec) {
-                           sm.select(rec, true);
-                       }
-                   });
-               }
-           }
-           insideUpdate = false;
-       };
-
-       vmidField.on('change', function(f, value) {
-           var mode = selModeField.getValue();
-           update_vmid_selection(value, mode);
-       });
-
-       selModeField.on('change', function(f, value, oldValue) {
-           if (value === 'all') {
-               sm.selectAll(true);
-               vmgrid.setDisabled(true);
-           } else {
-               vmgrid.setDisabled(false);
-           }
-           if (oldValue === 'all') {
-               sm.deselectAll(true);
-               vmidField.setValue('');
-           }
-           var list = vmidField.getValue();
-           update_vmid_selection(list, value);
-       });
-                
-       var reload = function() {
-           store.load({
-               params: { type: 'vm' },
-               callback: function() {
-                   var node = nodesel.getValue();
-                   store.clearFilter();
-                   store.filterBy(function(rec) {
-                       return (!node || rec.get('node') === node);
-                   });
-                   var list = vmidField.getValue();
-                   var mode = selModeField.getValue();
-                   if (mode === 'all') {
-                       sm.selectAll(true);
-                   } else {
-                       update_vmid_selection(list, mode);
-                   }
-               }
-           });
-       };
-
-        Ext.applyIf(me, {
-            subject: gettext("Backup Job"),
-            url: url,
-            method: method,
-           items: [ ipanel, vmgrid ]
-        });
-
-        me.callParent();
-
-        if (me.create) {
-           selModeField.setValue('include');
-       } else {
-            me.load({
-               success: function(response, options) {
-                   var data = response.result.data;
-
-                   data.dow = data.dow.split(',');
-
-                   if (data.all || data.exclude) {
-                       if (data.exclude) {
-                           data.vmid = data.exclude;
-                           data.selMode = 'exclude';
-                       } else {
-                           data.vmid = '';
-                           data.selMode = 'all';
-                       }
-                   } else {
-                       data.selMode = 'include';
-                   }
-
-                   me.setValues(data);
-               }
-            });
-        }
-
-       reload();
-    }
-});
-
-
-Ext.define('PVE.dc.BackupView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveDcBackupView'],
-
-    allText: '-- ' + gettext('All') + ' --',
-    allExceptText: gettext('All except {0}'),
-
-    initComponent : function() {
-       var me = this;
-
-       var store = new Ext.data.Store({
-           model: 'pve-cluster-backup',
-           proxy: {
-                type: 'pve',
-               url: "/api2/json/cluster/backup"
-           }
-       });
-
-       var reload = function() {
-           store.load();
-       };
-
-       var sm = Ext.create('Ext.selection.RowModel', {});
-
-       var run_editor = function() {
-           var rec = sm.getSelection()[0];
-           if (!rec) {
-               return;
-           }
-
-            var win = Ext.create('PVE.dc.BackupEdit',{
-                jobid: rec.data.id
-            });
-            win.on('destroy', reload);
-            win.show();
-       };
-
-       var edit_btn = new PVE.button.Button({
-           text: gettext('Edit'),
-           disabled: true,
-           selModel: sm,
-           handler: run_editor
-       });
-
-       var remove_btn = new PVE.button.Button({
-           text: gettext('Remove'),
-           disabled: true,
-           selModel: sm,
-           confirmMsg: gettext('Are you sure you want to remove this entry'),
-           handler: function(btn, event, rec) {
-               PVE.Utils.API2Request({
-                   url: '/cluster/backup/' + rec.data.id,
-                   method: 'DELETE',
-                   waitMsgTarget: me,
-                   callback: function() {
-                       reload();
-                   },
-                   failure: function (response, opts) {
-                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-                   }
-               });
-           }
-       });
-
-       PVE.Utils.monStoreErrors(me, store);
-
-       Ext.apply(me, {
-           store: store,
-           selModel: sm,
-           stateful: false,
-           viewConfig: {
-               trackOver: false
-           },
-           tbar: [
-               {
-                   text: gettext('Add'),
-                   handler: function() {
-                       var win = Ext.create('PVE.dc.BackupEdit',{});
-                       win.on('destroy', reload);
-                       win.show();
-                   }
-               },
-               remove_btn,
-               edit_btn
-           ],          
-           columns: [
-               {
-                   header: gettext('Node'),
-                   width: 100,
-                   sortable: true,
-                   dataIndex: 'node',
-                   renderer: function(value) {
-                       if (value) {
-                           return value;
-                       }
-                       return me.allText;
-                   }
-               },
-               {
-                   header: gettext('Day of week'),
-                   width: 200,
-                   sortable: false,
-                   dataIndex: 'dow'
-               },
-               {
-                   header: gettext('Start Time'),
-                   width: 60,
-                   sortable: true,
-                   dataIndex: 'starttime'
-               },
-               {
-                   header: gettext('Storage'),
-                   width: 100,
-                   sortable: true,
-                   dataIndex: 'storage'
-               },
-               {
-                   header: gettext('Selection'),
-                   flex: 1,
-                   sortable: false,
-                   dataIndex: 'vmid',
-                   renderer: function(value, metaData, record) {
-                       /*jslint confusion: true */
-                       if (record.data.all) {
-                           if (record.data.exclude) {
-                               return Ext.String.format(me.allExceptText, record.data.exclude);
-                           }
-                           return me.allText;
-                       }
-                       if (record.data.vmid) {
-                           return record.data.vmid;
-                       }
-
-                       return "-";
-                   }
-               }
-           ],
-           listeners: {
-               show: reload,
-               itemdblclick: run_editor
-           }
-       });
-       
-       me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-cluster-backup', {
-       extend: 'Ext.data.Model',
-       fields: [ 
-           'id', 'starttime', 'dow',
-           'storage', 'node', 'vmid', 'exclude',
-           'mailto',
-           { name: 'all', type: 'boolean' },
-           { name: 'snapshot', type: 'boolean' },
-           { name: 'stop', type: 'boolean' },
-           { name: 'suspend', type: 'boolean' },
-           { name: 'compress', type: 'boolean' }
-       ]
-    });
-});
\ No newline at end of file
diff --git a/www/manager5/dc/Config.js b/www/manager5/dc/Config.js
deleted file mode 100644 (file)
index 01f7c72..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Datacenter config panel, located in the center of the ViewPort after the Datacenter view is selected
- */
-
-Ext.define('PVE.dc.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.dc.Config',
-
-    initComponent: function() {
-        var me = this;
-
-       var caps = Ext.state.Manager.get('GuiCap');
-
-       me.items = [];
-
-       Ext.apply(me, {
-           title: gettext("Datacenter"),
-           hstateid: 'dctab'
-       });
-
-       if (caps.dc['Sys.Audit']) {
-           me.items.push({
-           title: gettext('Summary'),
-               xtype: 'pveDcSummary',
-               itemId: 'summary'
-               });
-
-           me.items.push({
-           xtype: 'pveDcOptionView',
-               title: gettext('Options'),
-               itemId: 'options'
-               });
-       }
-
-       if (caps.storage['Datastore.Allocate'] || caps.dc['Sys.Audit']) {
-           me.items.push({
-               xtype: 'pveStorageView',
-               title: gettext('Storage'),
-               itemId: 'storage'
-           });
-       }
-
-       if (caps.dc['Sys.Audit']) {
-               me.items.push({
-               xtype: 'pveDcBackupView',
-               title: gettext('Backup'),
-               itemId: 'backup'
-           });
-       }
-
-       me.items.push({
-           xtype: 'pveUserView',
-           title: gettext('Users'),
-           itemId: 'users'
-       });
-
-       if (caps.dc['Sys.Audit']) {
-           me.items.push({
-                   xtype: 'pveGroupView',
-                   title: gettext('Groups'),
-                   itemId: 'groups'
-               });
-
-           me.items.push({
-                   xtype: 'pvePoolView',
-                   title: gettext('Pools'),
-                   itemId: 'pools'
-               });
-
-           me.items.push({
-                   xtype: 'pveACLView',
-                   title: gettext('Permissions'),
-                   itemId: 'permissions'
-               });
-
-           me.items.push({
-                   xtype: 'pveRoleView',
-                   title: gettext('Roles'),
-                   itemId: 'roles'
-               });
-
-           me.items.push({
-//                 xtype: 'pveAuthView',
-//                 title: gettext('Authentication'),
-                   xtype: 'gridpanel',
-                   title: 'AuthenTODO',
-                   itemId: 'domains'
-               });
-
-           me.items.push({
-//                 xtype: 'pveHAPanel',
-//                 title: 'HA',
-               xtype: 'gridpanel',
-               title: 'HATODO',
-               phstateid: me.hstateid,
-                   itemId: 'ha'
-               });
-
-           me.items.push({
-//                 xtype: 'pveFirewallPanel',
-//                 title: gettext('Firewall'),
-               xtype: 'gridpanel',
-               title: 'FireTODO',
-                   base_url: '/cluster/firewall',
-                   fwtype: 'dc',
-                   phstateid: me.hstateid,
-                   itemId: 'firewall'
-               });
-
-           me.items.push({
-               xtype: 'pveDcSupport',
-               title: gettext('Support'),
-               itemId: 'support'
-           });
-       }
-
-       me.callParent();
-   }
-});
diff --git a/www/manager5/dc/GroupEdit.js b/www/manager5/dc/GroupEdit.js
deleted file mode 100644 (file)
index cb5a433..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-Ext.define('PVE.dc.GroupEdit', {
-    extend: 'PVE.window.Edit',
-    alias: ['widget.pveDcGroupEdit'],
-
-    initComponent : function() {
-        var me = this;
-
-        me.create = !me.groupid;
-
-        var url;
-        var method;
-
-        if (me.create) {
-            url = '/api2/extjs/access/groups';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/access/groups/' + me.groupid;
-            method = 'PUT';
-        }
-
-        Ext.applyIf(me, {
-            subject: gettext('Group'),
-            url: url,
-            method: method,
-            items: [
-                {
-                   xtype: me.create ? 'pvetextfield' : 'displayfield',
-                   fieldLabel: gettext('Name'),
-                   name: 'groupid',
-                   value: me.groupid,
-                   allowBlank: false
-               },
-                {
-                   xtype: 'textfield',
-                   fieldLabel: gettext('Comment'),
-                   name: 'comment',
-                   allowBlank: true
-               }
-            ]
-        });
-
-        me.callParent();
-
-        if (!me.create) {
-            me.load();
-        }
-    }
-});
diff --git a/www/manager5/dc/GroupView.js b/www/manager5/dc/GroupView.js
deleted file mode 100644 (file)
index 6950a46..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-Ext.define('PVE.dc.GroupView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveGroupView'],
-
-    initComponent : function() {
-       var me = this;
-
-       var store = new Ext.data.Store({
-           model: 'pve-groups',
-           sorters: { 
-               property: 'groupid', 
-               order: 'DESC' 
-           }
-       });
-
-        var reload = function() {
-            store.load();
-        };
-
-       var sm = Ext.create('Ext.selection.RowModel', {});
-
-       var remove_btn = new PVE.button.Button({
-           text: gettext('Remove'),
-           disabled: true,
-           selModel: sm,
-           confirmMsg: function (rec) {
-               return Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-                                        "'" + rec.data.groupid + "'");
-           },
-           handler: function(btn, event, rec) {
-               PVE.Utils.API2Request({
-                   url: '/access/groups/' + rec.data.groupid,
-                   method: 'DELETE',
-                   waitMsgTarget: me,
-                   callback: function() {
-                       reload();
-                   },
-                   failure: function (response, opts) {
-                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-                   }
-               });
-           }
-       });
-
-       var run_editor = function() {
-           var rec = sm.getSelection()[0];
-           if (!rec) {
-               return;
-           }
-
-            var win = Ext.create('PVE.dc.GroupEdit',{
-                groupid: rec.data.groupid
-            });
-            win.on('destroy', reload);
-            win.show();
-       };
-
-       var edit_btn = new PVE.button.Button({
-           text: gettext('Edit'),
-           disabled: true,
-           selModel: sm,
-           handler: run_editor
-       });
-
-       var tbar = [
-            {
-               text: gettext('Create'),
-               handler: function() {
-                   var win = Ext.create('PVE.dc.GroupEdit', {});
-                   win.on('destroy', reload);
-                   win.show();
-               }
-            },
-           edit_btn, remove_btn
-        ];
-
-       PVE.Utils.monStoreErrors(me, store);
-
-       Ext.apply(me, {
-           store: store,
-           selModel: sm,
-           stateful: false,
-           tbar: tbar,
-           viewConfig: {
-               trackOver: false
-           },
-           columns: [
-               {
-                   header: gettext('Name'),
-                   width: 200,
-                   sortable: true,
-                   dataIndex: 'groupid'
-               },
-               {
-                   header: gettext('Comment'),
-                   sortable: false,
-                   dataIndex: 'comment',
-                   flex: 1
-               }
-           ],
-           listeners: {
-               show: reload,
-               itemdblclick: run_editor
-           }
-       });
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/dc/Log.js b/www/manager5/dc/Log.js
deleted file mode 100644 (file)
index 385823b..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/* This class defines the "Cluster log" tab of the bottom status panel
- * A log entry is a timestamp associated with an action on a cluster
- */
-
-Ext.define('PVE.dc.Log', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveClusterLog'],
-
-    initComponent : function() {
-       var me = this;
-
-       var logstore = new PVE.data.UpdateStore({
-           storeid: 'pve-cluster-log',
-           model: 'pve-cluster-log',
-           proxy: {
-                type: 'pve',
-               url: '/api2/json/cluster/log'
-           }
-       });
-
-       var store = Ext.create('PVE.data.DiffStore', { 
-           rstore: logstore,
-           appendAtStart: true 
-       });
-
-       Ext.apply(me, {
-           store: store,
-           stateful: false,
-
-           viewConfig: {
-               trackOver: false,
-               stripeRows: true,
-               getRowClass: function(record, index) {
-                   var pri = record.get('pri');
-
-                   if (pri && pri <= 3) {
-                       return "x-form-invalid-field";
-                   }
-               }
-           },
-           sortableColumns: false,
-           columns: [
-               { 
-                   header: gettext("Time"), 
-                   dataIndex: 'time',
-                   width: 150,
-                   renderer: function(value) { 
-                       return Ext.Date.format(value, "M d H:i:s"); 
-                   }
-               },
-               { 
-                   header: gettext("Node"), 
-                   dataIndex: 'node',
-                   width: 150
-               },
-               { 
-                   header: gettext("Service"), 
-                   dataIndex: 'tag',
-                   width: 100
-               },
-               { 
-                   header: "PID", 
-                   dataIndex: 'pid',
-                   width: 100 
-               },
-               { 
-                   header: gettext("User name"), 
-                   dataIndex: 'user',
-                   width: 150
-               },
-               { 
-                   header: gettext("Severity"), 
-                   dataIndex: 'pri',
-                   renderer: PVE.Utils.render_serverity,
-                   width: 100 
-               },
-               { 
-                   header: gettext("Message"), 
-                   dataIndex: 'msg',
-                   flex: 1       
-               }
-           ],
-           listeners: {
-               show: logstore.startUpdate,
-               hide: logstore.stopUpdate,
-               destroy: logstore.stopUpdate
-           }
-       });
-
-       me.callParent();
-    }
-});
\ No newline at end of file
diff --git a/www/manager5/dc/OptionView.js b/www/manager5/dc/OptionView.js
deleted file mode 100644 (file)
index 3a98bce..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-Ext.define('PVE.dc.HttpProxyEdit', {
-    extend: 'PVE.window.Edit',
-
-    initComponent : function() {
-       var me = this;
-
-       Ext.applyIf(me, {
-           subject: gettext('HTTP proxy'),
-           items: {
-               xtype: 'pvetextfield',
-               name: 'http_proxy',
-               vtype: 'HttpProxy',
-               emptyText: gettext('Do not use any proxy'),
-               deleteEmpty: true,
-               value: '',
-               fieldLabel: gettext('HTTP proxy')
-           }
-       });
-
-       me.callParent();
-
-       me.load();
-    }
-});
-
-Ext.define('PVE.dc.KeyboardEdit', {
-    extend: 'PVE.window.Edit',
-
-    initComponent : function() {
-       var me = this;
-
-       Ext.applyIf(me, {
-           subject: gettext('Keyboard Layout'),
-           items: {
-               xtype: 'VNCKeyboardSelector',
-               name: 'keyboard',
-               value: '',
-               fieldLabel: gettext('Keyboard Layout')
-           }
-       });
-
-       me.callParent();
-
-       me.load();
-    }
-});
-
-Ext.define('PVE.dc.ConsoleViewerEdit', {
-    extend: 'PVE.window.Edit',
-
-    initComponent : function() {
-       var me = this;
-
-       var data = [];
-
-       Ext.Array.each(['', 'vv', 'html5'], function(value) {
-           data.push([value, PVE.Utils.render_console_viewer(value)]);
-       });
-
-       Ext.applyIf(me, {
-           subject: gettext('Console Viewer'),
-           items: {
-               xtype: 'pveKVComboBox',
-               name: 'console',
-               value: '',
-               fieldLabel: gettext('Console Viewer'),
-               comboItems: data,
-           }
-       });
-
-       me.callParent();
-
-       me.load();
-    }
-});
-
-Ext.define('PVE.dc.EmailFromEdit', {
-    extend: 'PVE.window.Edit',
-
-    initComponent : function() {
-       var me = this;
-
-       Ext.applyIf(me, {
-           subject: gettext('Email from address'),
-           items: {
-               xtype: 'pvetextfield',
-               name: 'email_from',
-               vtype: 'email',
-               emptyText: gettext('Send emails from root@$hostname'),
-               deleteEmpty: true,
-               value: '',
-               fieldLabel: gettext('Email from address')
-           }
-       });
-
-       me.callParent();
-
-       me.load();
-    }
-});
-
-Ext.define('PVE.dc.OptionView', {
-    extend: 'PVE.grid.ObjectGrid',
-    alias: ['widget.pveDcOptionView'],
-
-    noProxyText: gettext('Do not use any proxy'),
-    noEmailFromText: gettext('Send emails from root@$hostname'),
-
-    initComponent : function() {
-       var me = this;
-
-       var reload = function() {
-           me.rstore.load();
-       };
-
-       var rows = {
-           keyboard: { 
-               header: gettext('Keyboard Layout'), 
-               editor: 'PVE.dc.KeyboardEdit',
-               renderer: PVE.Utils.render_kvm_language,
-               required: true 
-           },
-           http_proxy: { 
-               header: gettext('HTTP proxy'),
-               editor: 'PVE.dc.HttpProxyEdit', 
-               required: true,
-               renderer: function(value) {
-                   if (!value) {
-                       return me.noProxyText;
-                   }
-                   return value;
-               }
-           },
-           console: {
-               header: gettext('Console Viewer'),
-               editor: 'PVE.dc.ConsoleViewerEdit',
-               required: true,
-               renderer: PVE.Utils.render_console_viewer
-           },
-           email_from: { 
-               header: gettext('Email from address'),
-               editor: 'PVE.dc.EmailFromEdit', 
-               required: true,
-               renderer: function(value) {
-                   if (!value) {
-                       return me.noEmailFromText;
-                   }
-                   return value;
-               }
-           }
-       };
-
-       var sm = Ext.create('Ext.selection.RowModel', {});
-
-       var run_editor = function() {
-           var rec = sm.getSelection()[0];
-           if (!rec) {
-               return;
-           }
-
-           var rowdef = rows[rec.data.key];
-           if (!rowdef.editor) {
-               return;
-           }
-           
-           var win = Ext.create(rowdef.editor, {
-               url: "/api2/extjs/cluster/options",
-               confid: rec.data.key
-           });
-           win.show();
-           win.on('destroy', reload);
-       };
-
-       var edit_btn = new PVE.button.Button({
-           text: gettext('Edit'),
-           disabled: true,
-           selModel: sm,
-           handler: run_editor
-       });
-
-       Ext.applyIf(me, {
-           url: "/api2/json/cluster/options",
-           cwidth1: 130,
-           interval: 1000,
-           selModel: sm,
-           tbar: [ edit_btn ],
-           rows: rows,
-           listeners: {
-               itemdblclick: run_editor
-           }
-       });
-
-       me.callParent();
-
-       me.on('show', reload);
-    }
-});
diff --git a/www/manager5/dc/PoolEdit.js b/www/manager5/dc/PoolEdit.js
deleted file mode 100644 (file)
index 42196e7..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-Ext.define('PVE.dc.PoolEdit', {
-    extend: 'PVE.window.Edit',
-    alias: ['widget.pveDcPoolEdit'],
-
-    initComponent : function() {
-        var me = this;
-
-        me.create = !me.poolid;
-
-        var url;
-        var method;
-
-        if (me.create) {
-            url = '/api2/extjs/pools';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/pools/' + me.poolid;
-            method = 'PUT';
-        }
-
-        Ext.applyIf(me, {
-            subject: gettext('Pool'),
-            url: url,
-            method: method,
-            items: [
-                {
-                   xtype: me.create ? 'pvetextfield' : 'displayfield',
-                   fieldLabel: gettext('Name'),
-                   name: 'poolid',
-                   value: me.poolid,
-                   allowBlank: false
-               },
-                {
-                   xtype: 'textfield',
-                   fieldLabel: gettext('Comment'),
-                   name: 'comment',
-                   allowBlank: true
-               }
-            ]
-        });
-
-        me.callParent();
-
-        if (!me.create) {
-            me.load();
-        }
-    }
-});
diff --git a/www/manager5/dc/PoolView.js b/www/manager5/dc/PoolView.js
deleted file mode 100644 (file)
index 4ae99e2..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-Ext.define('PVE.dc.PoolView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pvePoolView'],
-
-    initComponent : function() {
-       var me = this;
-
-       var store = new Ext.data.Store({
-           model: 'pve-pools',
-           sorters: { 
-               property: 'poolid', 
-               order: 'DESC' 
-           }
-       });
-
-        var reload = function() {
-            store.load();
-        };
-
-       var sm = Ext.create('Ext.selection.RowModel', {});
-
-       var remove_btn = new PVE.button.Button({
-           text: gettext('Remove'),
-           disabled: true,
-           selModel: sm,
-           confirmMsg: function (rec) {
-               return Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-                                        "'" + rec.data.poolid + "'");
-           },
-           handler: function(btn, event, rec) {
-               PVE.Utils.API2Request({
-                   url: '/pools/' + rec.data.poolid,
-                   method: 'DELETE',
-                   waitMsgTarget: me,
-                   callback: function() {
-                       reload();
-                   },
-                   failure: function (response, opts) {
-                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-                   }
-               });
-           }
-       });
-
-       var run_editor = function() {
-           var rec = sm.getSelection()[0];
-           if (!rec) {
-               return;
-           }
-
-            var win = Ext.create('PVE.dc.PoolEdit',{
-                poolid: rec.data.poolid
-            });
-            win.on('destroy', reload);
-            win.show();
-       };
-
-       var edit_btn = new PVE.button.Button({
-           text: gettext('Edit'),
-           disabled: true,
-           selModel: sm,
-           handler: run_editor
-       });
-
-       var tbar = [
-            {
-               text: gettext('Create'),
-               handler: function() {
-                   var win = Ext.create('PVE.dc.PoolEdit', {});
-                   win.on('destroy', reload);
-                   win.show();
-               }
-            },
-           edit_btn, remove_btn
-        ];
-
-       PVE.Utils.monStoreErrors(me, store);
-
-       Ext.apply(me, {
-           store: store,
-           selModel: sm,
-           stateful: false,
-           tbar: tbar,
-           viewConfig: {
-               trackOver: false
-           },
-           columns: [
-               {
-                   header: gettext('Name'),
-                   width: 200,
-                   sortable: true,
-                   dataIndex: 'poolid'
-               },
-               {
-                   header: gettext('Comment'),
-                   sortable: false,
-                   dataIndex: 'comment',
-                   flex: 1
-               }
-           ],
-           listeners: {
-               show: reload,
-               itemdblclick: run_editor
-           }
-       });
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/dc/RoleView.js b/www/manager5/dc/RoleView.js
deleted file mode 100644 (file)
index cbfe82d..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-Ext.define('PVE.dc.RoleView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveRoleView'],
-
-    initComponent : function() {
-       var me = this;
-
-       var store = new Ext.data.Store({
-           model: 'pve-roles',
-           sorters: { 
-               property: 'roleid', 
-               order: 'DESC' 
-           }
-       });
-
-       var render_privs = function(value, metaData) {
-
-           if (!value) {
-               return '-';
-           }
-
-           // allow word wrap
-           metaData.style = 'white-space:normal;';
-
-           return value.replace(/\,/g, ' ');
-       };
-
-       PVE.Utils.monStoreErrors(me, store);
-
-       Ext.apply(me, {
-           store: store,
-           stateful: false,
-
-           viewConfig: {
-               trackOver: false
-           },
-           columns: [
-               {
-                   header: gettext('Name'),
-                   width: 150,
-                   sortable: true,
-                   dataIndex: 'roleid'
-               },
-               {
-                   id: 'privs',
-                   header: gettext('Privileges'),
-                   sortable: false,
-                   renderer: render_privs,
-                   dataIndex: 'privs',
-                   flex: 1
-               }
-           ],
-           listeners: {
-               show: function() {
-                   store.load();
-               }
-           }
-       });
-
-       me.callParent();
-    }
-});
\ No newline at end of file
diff --git a/www/manager5/dc/SecurityGroups.js b/www/manager5/dc/SecurityGroups.js
deleted file mode 100644 (file)
index 0e31295..0000000
+++ /dev/null
@@ -1,230 +0,0 @@
-Ext.define('PVE.SecurityGroupEdit', {
-    extend: 'PVE.window.Edit',
-
-    base_url: "/cluster/firewall/groups",
-
-    allow_iface: false,
-
-    initComponent : function() {
-       /*jslint confusion: true */
-       var me = this;
-
-       me.create = (me.group_name === undefined);
-
-       var subject;
-
-        me.url = '/api2/extjs' + me.base_url;
-        me.method = 'POST';
-       
-       var items = [       
-           {
-               xtype: 'textfield',
-               name: 'group',
-               value: me.group_name || '',
-               fieldLabel: gettext('Name'),
-               allowBlank: false
-           },
-           {
-               xtype: 'textfield',
-               name: 'comment',
-               value: me.group_comment || '',
-               fieldLabel: gettext('Comment')
-           }
-       ];
-
-       if (me.create) {
-           subject = gettext('Security Group');
-        } else {
-           subject = gettext('Security Group') + " '" + me.group_name + "'";
-           items.push({
-               xtype: 'hiddenfield',
-               name: 'rename',
-               value: me.group_name
-           });
-        }
-
-       var ipanel = Ext.create('PVE.panel.InputPanel', {
-           create: me.create,
-           items: items 
-       });
-
-
-       Ext.apply(me, {
-            subject: subject,
-           items: [ ipanel ]
-       });
-
-       me.callParent();
-    }
-});
-
-Ext.define('PVE.SecurityGroupList', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveSecurityGroupList',
-
-    rule_panel: undefined,
-
-    addBtn: undefined,
-    removeBtn: undefined,
-    editBtn: undefined,
-
-    base_url: "/cluster/firewall/groups",
-
-    initComponent: function() {
-       /*jslint confusion: true */
-        var me = this;
-
-       if (me.rule_panel == undefined) {
-           throw "no rule panel specified";
-       }
-
-       if (me.base_url == undefined) {
-           throw "no base_url specified";
-       }
-
-       var store = new Ext.data.Store({
-           fields: [ 'group', 'comment', 'digest' ],
-           proxy: {
-               type: 'pve',
-               url: '/api2/json' + me.base_url
-           },
-           idProperty: 'group',
-           sorters: {
-               property: 'group',
-               order: 'DESC'
-           }
-       });
-
-       var sm = Ext.create('Ext.selection.RowModel', {});
-
-       var reload = function() {
-           var oldrec = sm.getSelection()[0];
-           store.load(function(records, operation, success) {
-               if (oldrec) {
-                   var rec = store.findRecord('group', oldrec.data.group);
-                   if (rec) {
-                       sm.select(rec);
-                   }
-               }
-           });
-       };
-
-       var run_editor = function() {
-           var rec = sm.getSelection()[0];
-           if (!rec) {
-               return;
-           }
-           var win = Ext.create('PVE.SecurityGroupEdit', {
-               digest: rec.data.digest,
-               group_name: rec.data.group,
-               group_comment: rec.data.comment
-           });
-           win.show();
-           win.on('destroy', reload);
-       };
-
-       me.editBtn = new PVE.button.Button({
-           text: gettext('Edit'),
-           disabled: true,
-           selModel: sm,
-           handler: run_editor
-       });
-
-       me.addBtn = new PVE.button.Button({
-           text: gettext('Create'),
-           handler: function() {
-               sm.deselectAll();
-               var win = Ext.create('PVE.SecurityGroupEdit', {});
-               win.show();
-               win.on('destroy', reload);
-           }
-       });
-
-       me.removeBtn = new PVE.button.Button({
-           text: gettext('Remove'),
-           selModel: sm,
-           disabled: true,
-           handler: function() {
-               var rec = sm.getSelection()[0];
-               if (!rec || !me.base_url) {
-                   return;
-               }
-               PVE.Utils.API2Request({
-                   url: me.base_url + '/' + rec.data.group,
-                   method: 'DELETE',
-                   waitMsgTarget: me,
-                   failure: function(response, options) {
-                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-                   },
-                   callback: reload
-               });
-           }
-       });
-
-       Ext.apply(me, {
-           store: store,
-           tbar: [ '<b>' + gettext('Group') + ':</b>', me.addBtn, me.removeBtn, me.editBtn ],
-           selModel: sm,
-           columns: [
-               { header: gettext('Group'), dataIndex: 'group', width: 100 },
-               { header: gettext('Comment'), dataIndex: 'comment', flex: 1 }
-           ],
-           listeners: {
-               itemdblclick: run_editor,
-               select: function(sm, rec) {
-                   var url = '/cluster/firewall/groups/' + rec.data.group;
-                   me.rule_panel.setBaseUrl(url);
-               },
-               deselect: function() {
-                   me.rule_panel.setBaseUrl(undefined);
-               },
-               show: reload
-           }
-       });
-
-       me.callParent();
-
-       store.load();
-    }
-});
-
-Ext.define('PVE.SecurityGroups', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveSecurityGroups',
-
-    title: 'Security Groups',
-
-    initComponent: function() {
-       var me = this;
-
-       var rule_panel = Ext.createWidget('pveFirewallRules', {
-           region: 'center',
-           allow_groups: false,
-           list_refs_url: '/cluster/firewall/refs',
-           tbar_prefix: '<b>' + gettext('Rules') + ':</b>',
-           flex: 0.75,
-           border: false
-       });
-
-       var sglist = Ext.createWidget('pveSecurityGroupList', {
-           region: 'west',
-           rule_panel: rule_panel,
-           flex: 0.25,
-           border: false,
-           split: true
-       });
-
-
-       Ext.apply(me, {
-            layout: 'border',
-            items: [ sglist, rule_panel ],
-           listeners: {
-               show: function() {
-                   sglist.fireEvent('show', sglist);
-               }
-           }
-       });
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/dc/StorageView.js b/www/manager5/dc/StorageView.js
deleted file mode 100644 (file)
index 4bcf3b7..0000000
+++ /dev/null
@@ -1,267 +0,0 @@
-
-Ext.define('PVE.dc.StorageView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveStorageView'],
-
-    initComponent : function() {
-       var me = this;
-
-       var store = new Ext.data.Store({
-           model: 'pve-storage',
-           proxy: {
-                type: 'pve',
-               url: "/api2/json/storage"
-           },
-           sorters: { 
-               property: 'storage', 
-               order: 'DESC' 
-           }
-       });
-
-       var reload = function() {
-           store.load();
-       };
-
-       var sm = Ext.create('Ext.selection.RowModel', {});
-
-       var run_editor = function() {
-           var rec = sm.getSelection()[0];
-           if (!rec) {
-               return;
-           }
-           var type = rec.data.type;
-           
-           var editor;
-           if (type === 'dir') {
-               editor = 'PVE.storage.DirEdit';
-           } else if (type === 'nfs') {
-               editor = 'PVE.storage.NFSEdit';
-           } else if (type === 'glusterfs') {
-               editor = 'PVE.storage.GlusterFsEdit';
-           } else if (type === 'lvm') {
-               editor = 'PVE.storage.LVMEdit';
-           } else if (type === 'iscsi') {
-               editor = 'PVE.storage.IScsiEdit';
-           } else if (type === 'rbd') {
-               editor = 'PVE.storage.RBDEdit';
-           } else if (type === 'sheepdog') {
-               editor = 'PVE.storage.SheepdogEdit';
-           } else if (type === 'zfs') {
-               editor = 'PVE.storage.ZFSEdit';
-           } else if (type === 'zfspool') {
-               editor = 'PVE.storage.ZFSPoolEdit';
-           } else {
-               return;
-           }
-           var win = Ext.create(editor, {
-               storageId: rec.data.storage
-           });
-
-           win.show();
-           win.on('destroy', reload);
-       };
-       
-       var edit_btn = new PVE.button.Button({
-           text: gettext('Edit'),
-           disabled: true,
-           selModel: sm,
-           handler: run_editor
-       });
-
-       var remove_btn = new PVE.button.Button({
-           text: gettext('Remove'),
-           disabled: true,
-           selModel: sm,
-           confirmMsg: function (rec) {
-               return Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-                                        "'" + rec.data.storage + "'");
-           },
-           handler: function(btn, event, rec) {
-               PVE.Utils.API2Request({
-                   url: '/storage/' + rec.data.storage,
-                   method: 'DELETE',
-                   waitMsgTarget: me,
-                   callback: function() {
-                       reload();
-                   },
-                   failure: function (response, opts) {
-                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-                   }
-               });
-           }
-       });
-
-       Ext.apply(me, {
-           store: store,
-           selModel: sm,
-           stateful: false,
-           viewConfig: {
-               trackOver: false
-           },
-           tbar: [ 
-               {
-                   text: gettext('Add'),
-                   menu: new Ext.menu.Menu({
-                       items: [
-                           {
-                               text:  PVE.Utils.format_storage_type('dir'),
-                               iconCls: 'pve-itype-icon-itype',
-                               handler: function() {
-                                   var win = Ext.create('PVE.storage.DirEdit', {});
-                                   win.on('destroy', reload);
-                                   win.show();
-                               }
-
-                           },
-                           {
-                               text:  PVE.Utils.format_storage_type('lvm'),
-                               iconCls: 'pve-itype-icon-storage',
-                               handler: function() {
-                                   var win = Ext.create('PVE.storage.LVMEdit', {});
-                                   win.on('destroy', reload);
-                                   win.show();
-                               }
-                           },
-                           {
-                               text:  PVE.Utils.format_storage_type('nfs'),
-                               iconCls: 'pve-itype-icon-network-server',
-                               handler: function() {
-                                   var win = Ext.create('PVE.storage.NFSEdit', {});
-                                   win.on('destroy', reload);
-                                   win.show();
-                               }
-                           },
-                           {
-                               text: PVE.Utils.format_storage_type('iscsi'),
-                               iconCls: 'pve-itype-icon-network-server',
-                               handler: function() {
-                                   var win = Ext.create('PVE.storage.IScsiEdit', {});
-                                   win.on('destroy', reload);
-                                   win.show();
-                               }
-                           },
-                           {
-                               text: PVE.Utils.format_storage_type('glusterfs'),
-                               iconCls: 'pve-itype-icon-network-server',
-                               handler: function() {
-                                   var win = Ext.create('PVE.storage.GlusterFsEdit', {});
-                                   win.on('destroy', reload);
-                                   win.show();
-                               }
-                           },
-                           {
-                               text: PVE.Utils.format_storage_type('rbd'),
-                               iconCls: 'pve-itype-icon-network-server',
-                               handler: function() {
-                                   var win = Ext.create('PVE.storage.RBDEdit', {});
-                                   win.on('destroy', reload);
-                                   win.show();
-                               }
-                           },
-                           {
-                               text: PVE.Utils.format_storage_type('zfs'),
-                               iconCls: 'pve-itype-icon-network-server',
-                               handler: function() {
-                                   var win = Ext.create('PVE.storage.ZFSEdit', {});
-                                   win.on('destroy', reload);
-                                   win.show();
-                               }
-                           },
-                           {
-                                text: PVE.Utils.format_storage_type('zfspool'),
-                                iconCls: 'pve-itype-icon-storage',
-                                handler: function() {
-                                    var win = Ext.create('PVE.storage.ZFSPoolEdit', {});
-                                    win.on('destroy', reload);
-                                    win.show();
-                                }
-                            },
-
-/* the following type are conidered unstable
- * so we do not enable that on the GUI for now
-                           {
-                               text: PVE.Utils.format_storage_type('sheepdog'),
-                               iconCls: 'pve-itype-icon-network-server',
-                               handler: function() {
-                                   var win = Ext.create('PVE.storage.SheepdogEdit', {});
-                                   win.on('destroy', reload);
-                                   win.show();
-                               }
-                           }
-*/
-                       ]
-                   })
-               },
-               remove_btn,
-               edit_btn
-           ],
-           columns: [
-               {
-                   header: 'ID',
-                   width: 100,
-                   sortable: true,
-                   dataIndex: 'storage'
-               },
-               {
-                   header: gettext('Type'),
-                   width: 60,
-                   sortable: true,
-                   dataIndex: 'type',
-                   renderer: PVE.Utils.format_storage_type
-               },
-               {
-                   header: gettext('Content'),
-                   width: 150,
-                   sortable: true,
-                   dataIndex: 'content',
-                   renderer: PVE.Utils.format_content_types
-               },
-               {
-                   header: gettext('Path') + '/' + gettext('Target'),
-                   flex: 1,
-                   sortable: true,
-                   dataIndex: 'path',
-                   renderer: function(value, metaData, record) {
-                       if (record.data.target) {
-                           return record.data.target;
-                       }
-                       return value;
-                   }
-               },
-               {
-                   header: gettext('Shared'),
-                   width: 80,
-                   sortable: true,
-                   dataIndex: 'shared',
-                   renderer: PVE.Utils.format_boolean
-               },
-               {
-                   header: gettext('Enable'),
-                   width: 80,
-                   sortable: true,
-                   dataIndex: 'disable',
-                   renderer: PVE.Utils.format_neg_boolean
-               }
-           ],
-           listeners: {
-               show: reload,
-               itemdblclick: run_editor
-           }
-       });
-
-       me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-storage', {
-       extend: 'Ext.data.Model',
-       fields: [ 
-           'path', 'type', 'content', 'server', 'portal', 'target', 'export', 'storage',
-           { name: 'shared', type: 'boolean'},
-           { name: 'disable', type: 'boolean'} 
-       ],
-       idProperty: 'storage'
-    });
-
-});
diff --git a/www/manager5/dc/Summary.js b/www/manager5/dc/Summary.js
deleted file mode 100644 (file)
index b0f8b32..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-Ext.define('PVE.dc.NodeView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveDcNodeView'],
-
-    initComponent : function() {
-       var me = this;
-
-       var rstore = Ext.create('PVE.data.UpdateStore', {
-           interval: 3000,
-           storeid: 'pve-dc-nodes',
-           model: 'pve-dc-nodes',
-           proxy: {
-                type: 'pve',
-                url: "/api2/json/cluster/status"
-           },
-           filters: {
-               property: 'type',
-               value   : 'node'
-           }
-       });
-
-       var store = Ext.create('PVE.data.DiffStore', { rstore: rstore });
-
-       var noClusterText = gettext("Standalone node - no cluster defined");
-       var status = Ext.create('Ext.Component', {
-           padding: 2,
-           html: '&nbsp;',
-           dock: 'bottom'
-       });
-
-       Ext.apply(me, {
-           store: store,
-           stateful: false,
-           bbar: [ status ],
-           columns: [
-               {
-                   header: gettext('Name'),
-                   width: 200,
-                   sortable: true,
-                   dataIndex: 'name'
-               },
-               {
-                   header: 'ID',
-                   width: 50,
-                   sortable: true,
-                   dataIndex: 'nodeid'
-               },
-               {
-                   header: gettext('Online'),
-                   width: 100,
-                   sortable: true,
-                   dataIndex: 'online',
-                   renderer: PVE.Utils.format_boolean
-               },
-               {
-                   header: gettext('Support'),
-                   width: 100,
-                   sortable: true,
-                   dataIndex: 'level',
-                   renderer: PVE.Utils.render_support_level
-               },
-               {
-                   header: gettext('Server Address'),
-                   flex: 1,
-                   sortable: true,
-                   dataIndex: 'ip'
-               }
-           ], 
-           listeners: {
-               show: rstore.startUpdate,
-               hide: rstore.stopUpdate,
-               destroy: rstore.stopUpdate
-           }
-       });
-
-       me.callParent();
-
-       rstore.on('load', function(s, records, success) {
-           if (!success) {
-               return;
-           }
-
-           var cluster_rec = rstore.getById('cluster');
-
-           if (!cluster_rec) {
-               status.update(noClusterText);
-               return;
-           }
-
-           var cluster_raw = cluster_rec.raw;
-           if (!cluster_raw) {
-               status.update(noClusterText);
-               return;
-           }
-           var text = gettext("Cluster") + ": " + cluster_raw.name + ",  " +
-               gettext("Quorate") + ": " + PVE.Utils.format_boolean(cluster_raw.quorate);
-           status.update(text);
-       });
-
-    }
-}, function() {
-
-    Ext.define('pve-dc-nodes', {
-       extend: 'Ext.data.Model',
-       fields: [ 'id', 'type', 'name', 'nodeid', 'ip', 'level', 'local', 'online'],
-       idProperty: 'id'
-    });
-
-});
-
-Ext.define('PVE.dc.Summary', {
-    extend: 'Ext.panel.Panel',
-
-    alias: ['widget.pveDcSummary'],
-
-    initComponent: function() {
-        var me = this;
-
-       var nodegrid = Ext.create('PVE.dc.NodeView', {
-           title: gettext('Nodes'),
-           border: false,
-           region: 'center',
-           flex: 3
-       });
-
-       Ext.apply(me, {
-           layout: 'border',
-           items: [ nodegrid ],
-           listeners: {
-               show: function() {
-                   nodegrid.fireEvent('show', nodegrid);
-               },
-               hide: function() {
-                   nodegrid.fireEvent('hide', nodegrid);
-               }
-           }
-       });
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/dc/Support.js b/www/manager5/dc/Support.js
deleted file mode 100644 (file)
index 1ed32d4..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-Ext.define('PVE.dc.Support', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveDcSupport',
-
-    invalidHtml: '<h1>No valid subscription</h1>' + PVE.Utils.noSubKeyHtml,
-
-    communityHtml: 'Please use the public community <a target="_blank" href="http://forum.proxmox.com">forum</a> for any questions.',
-
-    activeHtml: 'Please use our <a target="_blank" href="https://my.proxmox.com">support portal</a> for any questions. You can also use the public community <a target="_blank" href="http://forum.proxmox.com">forum</a> to get additional information.',
-
-    bugzillaHtml: '<h1>Bug Tracking</h1>Our bug tracking system is available <a target="_blank" href="https://bugzilla.proxmox.com">here</a>.',
-
-    docuHtml: '<h1>Documentation</h1>Complete documentation, tutorials, videos and more is available at our <a target="_blank" href="http://pve.proxmox.com/wiki/Documentation">wiki</a>.',
-
-    updateActive: function(data) {
-       var me = this;
-       
-       var html = '<h1>' + data.productname + '</h1>' + me.activeHtml; 
-       html += '<br><br>' + me.docuHtml;
-       html += '<br><br>' + me.bugzillaHtml;
-
-       me.update(html);
-    },
-
-    updateCommunity: function(data) {
-       var me = this;
-
-       var html = '<h1>' + data.productname + '</h1>' + me.communityHtml; 
-       html += '<br><br>' + me.docuHtml;
-       html += '<br><br>' + me.bugzillaHtml;
-
-       me.update(html);
-    },
-        
-    updateInactive: function(data) {
-       var me = this;
-       me.update(me.invalidHtml);
-    },
-
-    initComponent: function() {
-        var me = this;
-
-       var reload = function() {
-           PVE.Utils.API2Request({
-               url: '/nodes/localhost/subscription',
-               method: 'GET',
-               waitMsgTarget: me,
-               failure: function(response, opts) {
-                   Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-                   me.update(gettext('Unable to load subscription status') + ": " + response.htmlStatus);
-               },
-               success: function(response, opts) {
-                   var data = response.result.data;
-
-                   if (data.status === 'Active') {
-                       if (data.level === 'c') {
-                           me.updateCommunity(data);
-                       } else {
-                           me.updateActive(data);
-                       }
-                   } else {
-                       me.updateInactive(data);
-                   }
-               }
-           });
-       };
-
-       Ext.apply(me, {
-           autoScroll: true,
-           bodyStyle: 'padding:10px',
-           listeners: {
-               show: reload
-           }
-       });
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/dc/Tasks.js b/www/manager5/dc/Tasks.js
deleted file mode 100644 (file)
index 58d09a5..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/* This class defines the "Tasks" tab of the bottom status panel
- * Tasks are jobs with a start, end and log output
- */
-
-Ext.define('PVE.dc.Tasks', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveClusterTasks'],
-
-    initComponent : function() {
-       var me = this;
-
-       var taskstore = new PVE.data.UpdateStore({
-           storeid: 'pve-cluster-tasks',
-           model: 'pve-tasks',
-           proxy: {
-                type: 'pve',
-               url: '/api2/json/cluster/tasks'
-           }
-       });
-
-       var store = Ext.create('PVE.data.DiffStore', { 
-           rstore: taskstore,
-           sortAfterUpdate: true,
-           appendAtStart: true,
-           sorters: [
-               {
-                   property : 'pid',
-                   direction: 'DESC'
-               },
-               {
-                   property : 'starttime',
-                   direction: 'DESC'
-               }
-           ]
-
-       });
-
-       var run_task_viewer = function() {
-           var sm = me.getSelectionModel();
-           var rec = sm.getSelection()[0];
-           if (!rec) {
-               return;
-           }
-
-           var win = Ext.create('PVE.window.TaskViewer', { 
-               upid: rec.data.upid
-           });
-           win.show();
-       };
-
-       Ext.apply(me, {
-           store: store,
-           stateful: false,
-
-           viewConfig: {
-               trackOver: false,
-               stripeRows: true, // does not work with getRowClass()
-               getRowClass: function(record, index) {
-                   var status = record.get('status');
-
-                   if (status && status != 'OK') {
-                       return "x-form-invalid-field";
-                   }
-               }
-           },
-           sortableColumns: false,
-           columns: [
-               { 
-                   header: gettext("Start Time"), 
-                   dataIndex: 'starttime',
-                   width: 150,
-                   renderer: function(value) { 
-                       return Ext.Date.format(value, "M d H:i:s"); 
-                   }
-               },
-               { 
-                   header: gettext("End Time"), 
-                   dataIndex: 'endtime',
-                   width: 150,
-                   renderer: function(value, metaData, record) {
-                       if (record.data.pid) {
-                           if (record.data.type == "vncproxy" || 
-                               record.data.type == "vncshell" ||
-                               record.data.type == "spiceproxy") {
-                               metaData.tdCls =  "x-grid-row-console";
-                           } else {
-                               metaData.tdCls =  "x-grid-row-loading";
-                           }
-                           return "";
-                       }
-                       return Ext.Date.format(value, "M d H:i:s"); 
-                   }
-               },
-               { 
-                   header: gettext("Node"), 
-                   dataIndex: 'node',
-                   width: 100
-               },
-               { 
-                   header: gettext("User name"), 
-                   dataIndex: 'user',
-                   width: 150
-               },
-               { 
-                   header: gettext("Description"), 
-                   dataIndex: 'upid', 
-                   flex: 1,              
-                   renderer: PVE.Utils.render_upid
-               },
-               { 
-                   header: gettext("Status"), 
-                   dataIndex: 'status', 
-                   width: 200,
-                   renderer: function(value, metaData, record) { 
-                       if (record.data.pid) {
-                           if (record.data.type != "vncproxy") {
-                               metaData.tdCls =  "x-grid-row-loading";
-                           }
-                           return "";
-                       }
-                       if (value == 'OK') {
-                           return 'OK';
-                       }
-                       // metaData.attr = 'style="color:red;"'; 
-                       return PVE.Utils.errorText + ': ' + value;
-                   }
-               }
-           ],
-           listeners: {
-               itemdblclick: run_task_viewer,
-               show: taskstore.startUpdate,
-               hide: taskstore.stopUpdate,
-               destroy: taskstore.stopUpdate
-           }
-       });
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/dc/UserEdit.js b/www/manager5/dc/UserEdit.js
deleted file mode 100644 (file)
index bb110b5..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-Ext.define('PVE.dc.UserEdit', {
-    extend: 'PVE.window.Edit',
-    alias: ['widget.pveDcUserEdit'],
-
-    isAdd: true,
-
-    initComponent : function() {
-        var me = this;
-
-        me.create = !me.userid;
-
-        var url;
-        var method;
-        var realm;
-
-        if (me.create) {
-            url = '/api2/extjs/access/users';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/access/users/' + me.userid;
-            method = 'PUT';
-       }
-
-       var verifypw;
-       var pwfield;
-
-       var validate_pw = function() {
-           if (verifypw.getValue() !== pwfield.getValue()) {
-               return gettext("Passwords does not match");
-           }
-           return true;
-       };
-
-       verifypw = Ext.createWidget('textfield', { 
-           inputType: 'password',
-           fieldLabel: gettext('Confirm password'), 
-           name: 'verifypassword',
-           submitValue: false,
-           disabled: true,
-           hidden: true,
-           validator: validate_pw
-       });
-
-       pwfield = Ext.createWidget('textfield', { 
-           inputType: 'password',
-           fieldLabel: gettext('Password'), 
-           minLength: 5,
-           name: 'password',
-           disabled: true,
-           hidden: true,
-           validator: validate_pw
-       });
-
-       var update_passwd_field = function(realm) {
-           if (realm === 'pve') {
-               pwfield.setVisible(true);
-               pwfield.setDisabled(false);
-               verifypw.setVisible(true);
-               verifypw.setDisabled(false);
-           } else {
-               pwfield.setVisible(false);
-               pwfield.setDisabled(true);
-               verifypw.setVisible(false);
-               verifypw.setDisabled(true);
-           }
-
-       };
-
-        var column1 = [
-            {
-                xtype: me.create ? 'textfield' : 'displayfield',
-               height: 22, // hack: set same height as text fields
-                name: 'userid',
-                fieldLabel: gettext('User name'),
-                value: me.userid,
-                allowBlank: false,
-                submitValue: me.create ? true : false
-            },
-           pwfield, verifypw,
-           {
-               xtype: 'pveGroupSelector',
-               name: 'groups',
-               multiSelect: true,
-               allowBlank: true,
-               fieldLabel: gettext('Group')
-           },
-            {
-                xtype: 'datefield',
-                name: 'expire',
-               emptyText: 'never',
-               format: 'Y-m-d',
-               submitFormat: 'U',
-                fieldLabel: gettext('Expire')
-            },
-           {
-               xtype: 'pvecheckbox',
-               fieldLabel: gettext('Enabled'),
-               name: 'enable',
-               uncheckedValue: 0,
-               defaultValue: 1,
-               checked: true
-           }
-        ];
-
-        var column2 = [
-           {
-               xtype: 'textfield',
-               name: 'firstname',
-               fieldLabel: gettext('First Name')
-           },
-           {
-               xtype: 'textfield',
-               name: 'lastname',
-               fieldLabel: gettext('Last Name')
-           },
-           {
-               xtype: 'textfield',
-               name: 'email',
-               fieldLabel: gettext('E-Mail'),
-               vtype: 'email'
-           }
-       ];
-
-       var columnB = [
-           {
-               xtype: 'textfield',
-               name: 'comment',
-               fieldLabel: gettext('Comment')
-           },
-           {
-               xtype: 'textfield',
-               name: 'keys',
-               fieldLabel: gettext('Key IDs')
-           }
-       ];
-        if (me.create) {
-            column1.splice(1,0,{
-                xtype: 'pveRealmComboBox',
-                name: 'realm',
-                fieldLabel: gettext('Realm'),
-                allowBlank: false,
-               matchFieldWidth: false,
-               listConfig: { width: 300 },
-                listeners: {
-                    change: function(combo, newValue){
-                        realm = newValue;
-                       update_passwd_field(realm);
-                    }
-                },
-                submitValue: false
-            });
-        }
-
-       var ipanel = Ext.create('PVE.panel.InputPanel', {
-           column1: column1,
-           column2: column2,
-           columnB: columnB,
-           onGetValues: function(values) {
-               // hack: ExtJS datefield does not submit 0, so we need to set that
-               if (!values.expire) {
-                   values.expire = 0;
-               }
-
-               if (realm) {
-                   values.userid = values.userid + '@' + realm;
-               }
-
-               if (!values.password) {
-                   delete values.password;
-               }
-
-               return values;
-           }
-       });
-
-       Ext.applyIf(me, {
-            subject: gettext('User'),
-            url: url,
-            method: method,
-           fieldDefaults: {
-               labelWidth: 110 // for spanish translation 
-           },
-           items: [ ipanel ]
-        });
-
-        me.callParent();
-
-        if (!me.create) {
-            me.load({
-               success: function(response, options) {
-                   var data = response.result.data;
-                   if (Ext.isDefined(data.expire)) {
-                       if (data.expire) {
-                           data.expire = new Date(data.expire * 1000);
-                       } else {
-                           // display 'never' instead of '1970-01-01'
-                           data.expire = null;
-                       }
-                   }
-                   me.setValues(data);
-                }
-            });
-        }
-    }
-});
diff --git a/www/manager5/dc/UserView.js b/www/manager5/dc/UserView.js
deleted file mode 100644 (file)
index c4f8a8b..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-Ext.define('PVE.window.PasswordEdit', {
-    extend: 'PVE.window.Edit',
-
-    initComponent : function() {
-       var me = this;
-
-       if (!me.userid) {
-           throw "no userid specified";
-       }
-
-       var verifypw;
-       var pwfield;
-
-       var validate_pw = function() {
-           if (verifypw.getValue() !== pwfield.getValue()) {
-               return gettext("Passwords does not match");
-           }
-           return true;
-       };
-
-       verifypw = Ext.createWidget('textfield', { 
-           inputType: 'password',
-           fieldLabel: gettext('Confirm password'), 
-           name: 'verifypassword',
-           submitValue: false,
-           validator: validate_pw
-       });
-
-       pwfield = Ext.createWidget('textfield', { 
-           inputType: 'password',
-           fieldLabel: gettext('Password'), 
-           minLength: 5,
-           name: 'password',
-           validator: validate_pw
-       });
-
-       Ext.apply(me, {
-           subject: gettext('Password'),
-           url: '/api2/extjs/access/password',
-           items: [
-               pwfield, verifypw,
-               {
-                   xtype: 'hiddenfield',
-                   name: 'userid',
-                   value: me.userid
-               }
-           ]
-       });
-
-       me.callParent();
-    }
-});
-
-Ext.define('PVE.dc.UserView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveUserView'],
-
-    initComponent : function() {
-       var me = this;
-
-       var caps = Ext.state.Manager.get('GuiCap');
-
-       var store = new Ext.data.Store({
-            id: "users",
-           model: 'pve-users',
-           sorters: { 
-               property: 'userid', 
-               order: 'DESC' 
-           }
-       });
-
-       var reload = function() {
-           store.load();
-       };
-
-       var sm = Ext.create('Ext.selection.RowModel', {});
-
-       var remove_btn = new PVE.button.Button({
-           text: gettext('Remove'),
-           disabled: true,
-           selModel: sm,
-           enableFn: function(rec) {
-               if (!caps.access['User.Modify']) {
-                   return false;
-               }
-               return rec.data.userid !== 'root@pam';
-           },
-           confirmMsg: function (rec) {
-               return Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-                                        "'" + rec.data.userid + "'");
-           },
-           handler: function(btn, event, rec) {
-               var userid = rec.data.userid;
-
-               PVE.Utils.API2Request({
-                   url: '/access/users/' + userid,
-                   method: 'DELETE',
-                   waitMsgTarget: me,
-                   callback: function() {
-                       reload();
-                   },
-                   failure: function (response, opts) {
-                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-                   }
-               });
-           }
-        });
-       var run_editor = function() {
-           var rec = sm.getSelection()[0];
-           if (!rec || !caps.access['User.Modify']) {
-               return;
-           }
-
-            var win = Ext.create('PVE.dc.UserEdit',{
-                userid: rec.data.userid
-            });
-            win.on('destroy', reload);
-            win.show();
-       };
-
-       var edit_btn = new PVE.button.Button({
-           text: gettext('Edit'),
-           disabled: true,
-           enableFn: function(rec) {
-               return !!caps.access['User.Modify'];
-           },
-           selModel: sm,
-           handler: run_editor
-       });
-
-       var pwchange_btn = new PVE.button.Button({
-           text: gettext('Password'),
-           disabled: true,
-           selModel: sm,
-           handler: function(btn, event, rec) {
-               var win = Ext.create('PVE.window.PasswordEdit',{
-                    userid: rec.data.userid
-               });
-               win.on('destroy', reload);
-               win.show();
-           }
-       });
-
-        var tbar = [
-            {
-               text: gettext('Add'),
-               disabled: !caps.access['User.Modify'],
-               handler: function() {
-                    var win = Ext.create('PVE.dc.UserEdit',{
-                    });
-                    win.on('destroy', reload);
-                    win.show();
-               }
-            },
-           edit_btn, remove_btn, pwchange_btn
-        ];
-
-       var render_full_name = function(firstname, metaData, record) {
-
-           var first = firstname || '';
-           var last = record.data.lastname || '';
-           return first + " " + last;
-       };
-
-       var render_username = function(userid) {
-           return userid.match(/^(.+)(@[^@]+)$/)[1];
-       };
-
-       var render_realm = function(userid) {
-           return userid.match(/@([^@]+)$/)[1];
-       };
-
-       Ext.apply(me, {
-           store: store,
-           selModel: sm,
-           stateful: false,
-           tbar: tbar,
-           viewConfig: {
-               trackOver: false
-           },
-           columns: [
-               {
-                   header: gettext('User name'),
-                   width: 200,
-                   sortable: true,
-                   renderer: render_username,
-                   dataIndex: 'userid'
-               },
-               {
-                   header: gettext('Realm'),
-                   width: 100,
-                   sortable: true,
-                   renderer: render_realm,
-                   dataIndex: 'userid'
-               },
-               {
-                   header: gettext('Enabled'),
-                   width: 80,
-                   sortable: true,
-                   renderer: PVE.Utils.format_boolean,
-                   dataIndex: 'enable'
-               },
-               {
-                   header: gettext('Expire'),
-                   width: 80,
-                   sortable: true,
-                   renderer: PVE.Utils.format_expire, 
-                   dataIndex: 'expire'
-               },
-               {
-                   header: gettext('Name'),
-                   width: 150,
-                   sortable: true,
-                   renderer: render_full_name,
-                   dataIndex: 'firstname'
-               },
-               {
-                   id: 'comment',
-                   header: gettext('Comment'),
-                   sortable: false,
-                   dataIndex: 'comment',
-                   flex: 1
-               }
-           ],
-           listeners: {
-               show: reload,
-               itemdblclick: run_editor
-           }
-       });
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/form/BackupModeSelector.js b/www/manager5/form/BackupModeSelector.js
deleted file mode 100644 (file)
index c97b691..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-Ext.define('PVE.form.BackupModeSelector', {
-    extend: 'PVE.form.KVComboBox',
-    alias: ['widget.pveBackupModeSelector'],
-    comboItems: [
-                ['snapshot', gettext('Snapshot')],
-                ['suspend', gettext('Suspend')],
-                ['stop', gettext('Stop')]
-    ]
-});
diff --git a/www/manager5/form/BondModeSelector.js b/www/manager5/form/BondModeSelector.js
deleted file mode 100644 (file)
index 4504e8b..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-Ext.define('PVE.form.BondModeSelector', {
-    extend: 'PVE.form.KVComboBox',
-    alias: ['widget.bondModeSelector'],
-  
-    openvswitch: false,
-
-    initComponent: function() {
-       var me = this;
-
-       if (me.openvswitch) {
-           me.data = [ 
-              ['active-backup', 'active-backup'],
-              ['balance-slb', 'balance-slb'],
-              ['lacp-balance-slb', 'LACP (balance-slb)'],
-              ['lacp-balance-tcp', 'LACP (balance-tcp)']
-          ];
-       } else {
-            me.data = [ 
-               ['balance-rr', 'balance-rr'], 
-               ['active-backup', 'active-backup'], 
-               ['balance-xor', 'balance-xor'], 
-               ['broadcast', 'broadcast'], 
-               ['802.3ad', 'LACP (802.3ad)'], 
-               ['balance-tlb', 'balance-tlb'], 
-               ['balance-alb', 'balance-alb']
-           ];
-       }
-       me.callParent();
-    }
-});
-
-Ext.define('PVE.form.BondPolicySelector', {
-    extend: 'PVE.form.KVComboBox',
-    alias: ['widget.bondPolicySelector'],
-
-    initComponent: function() {
-       var me = this;
-        me.data = [
-           ['layer2', 'layer2'],
-           ['layer2+3', 'layer2+3'], 
-           ['layer3+4', 'layer3+4']
-       ];
-       me.callParent();
-    }
-});
-
diff --git a/www/manager5/form/Boolean.js b/www/manager5/form/Boolean.js
deleted file mode 100644 (file)
index 1bcba95..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// boolean type including 'Default' (delete property from file)
-Ext.define('PVE.form.Boolean', {
-    extend: 'PVE.form.KVComboBox',
-    alias: ['widget.booleanfield'],
-  
-    initComponent: function() {
-       var me = this;
-
-       me.data = [
-           ['', gettext('Default')],
-           [1, gettext('Yes')],
-           [0, gettext('No')]
-       ];
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/form/BridgeSelector.js b/www/manager5/form/BridgeSelector.js
deleted file mode 100644 (file)
index 945a2d2..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-Ext.define('PVE.form.BridgeSelector', {
-    extend: 'PVE.form.ComboGrid',
-    alias: ['widget.PVE.form.BridgeSelector'],
-
-    bridgeType: 'any_bridge', // bridge, OVSBridge or any_bridge
-
-    setNodename: function(nodename) {
-       var me = this;
-
-       if (!nodename || (me.nodename === nodename)) {
-           return;
-       }
-
-       me.nodename = nodename;
-
-       me.store.setProxy({
-           type: 'pve',
-           url: '/api2/json/nodes/' + me.nodename + '/network?type=' +
-               me.bridgeType
-       });
-
-       me.store.load();
-    },
-
-    initComponent: function() {
-       var me = this;
-
-       var nodename = me.nodename;
-       me.nodename = undefined; 
-
-       var store = Ext.create('Ext.data.Store', {
-           fields: [ 'iface', 'active', 'type' ],
-           filterOnLoad: true,
-           sorters: [
-               {
-                   property : 'iface',
-                   direction: 'ASC'
-               }
-           ]
-       });
-
-       Ext.apply(me, {
-           store: store,
-           valueField: 'iface',
-           displayField: 'iface',
-            listConfig: {
-               columns: [
-                   {
-                       header: gettext('Bridge'),
-                       dataIndex: 'iface',
-                       hideable: false,
-                       flex: 1
-                   },
-                   {
-                       header: gettext('Active'),  
-                       width: 60, 
-                       dataIndex: 'active', 
-                       renderer: PVE.Utils.format_boolean
-                   }
-               ]
-           }
-       });
-
-        me.callParent();
-
-       if (nodename) {
-           me.setNodename(nodename);
-       }
-    }
-});
-
diff --git a/www/manager5/form/BusTypeSelector.js b/www/manager5/form/BusTypeSelector.js
deleted file mode 100644 (file)
index 00f8281..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-Ext.define('PVE.form.BusTypeSelector', {
-    extend: 'PVE.form.KVComboBox',
-    alias: ['widget.PVE.form.BusTypeSelector'],
-  
-    noVirtIO: false,
-
-    noScsi: false,
-
-    initComponent: function() {
-       var me = this;
-
-       me.data = [['ide', 'IDE'], ['sata', 'SATA']];
-
-       if (!me.noVirtIO) {
-           me.data.push(['virtio', 'VIRTIO']);
-       }
-
-       if (!me.noScsi) {
-           me.data.push(['scsi', 'SCSI']);
-       }
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/form/CPUModelSelector.js b/www/manager5/form/CPUModelSelector.js
deleted file mode 100644 (file)
index 901aab5..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-Ext.define('PVE.form.CPUModelSelector', {
-    extend: 'PVE.form.KVComboBox',
-    alias: ['widget.CPUModelSelector'],
-  
-    initComponent: function() {
-       var me = this;
-
-        me.data = [ 
-           ['', PVE.Utils.defaultText + ' (kvm64)'],
-           ['486', '486'],
-           ['athlon', 'athlon'],
-           ['core2duo', 'core2duo'],
-           ['coreduo', 'coreduo'],
-           ['kvm32', 'kvm32'],
-           ['kvm64', 'kvm64'],
-           ['pentium', 'pentium'],
-           ['pentium2', 'pentium2'],
-           ['pentium3', 'pentium3'],
-           ['phenom', 'phenom'],
-           ['qemu32', 'qemu32'],
-           ['qemu64', 'qemu64'],
-           ['Conroe', 'Conroe'],
-           ['Penryn', 'Penryn'],
-           ['Nehalem', 'Nehalem'],
-           ['Westmere', 'Westmere'],
-           ['SandyBridge', 'SandyBridge'],
-           ['IvyBridge', 'IvyBridge'],
-           ['Haswell', 'Haswell'],
-           ['Broadwell', 'Broadwell'],
-           ['Opteron_G1', 'Opteron_G1'],
-           ['Opteron_G2', 'Opteron_G2'],
-           ['Opteron_G3', 'Opteron_G3'],
-           ['Opteron_G4', 'Opteron_G4'],
-           ['Opteron_G5', 'Opteron_G5'],
-           ['host', 'host']
-       ];
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/form/CacheTypeSelector.js b/www/manager5/form/CacheTypeSelector.js
deleted file mode 100644 (file)
index 3d96981..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-Ext.define('PVE.form.CacheTypeSelector', {
-    extend: 'PVE.form.KVComboBox',
-    alias: ['widget.CacheTypeSelector'],
-  
-    initComponent: function() {
-       var me = this;
-
-       me.data = [
-           ['', PVE.Utils.defaultText + " (" + gettext('No cache') + ")"],
-           ['directsync', 'Direct sync'],
-           ['writethrough', 'Write through'],
-           ['writeback', 'Write back'],
-           ['unsafe', 'Write back (' + gettext('unsafe') + ')'],
-           ['none', gettext('No cache')]
-       ];
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/form/Checkbox.js b/www/manager5/form/Checkbox.js
deleted file mode 100644 (file)
index 3ce41b6..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-Ext.define('PVE.form.Checkbox', {
-    extend: 'Ext.form.field.Checkbox',
-    alias: ['widget.pvecheckbox'],
-
-    defaultValue: undefined,
-
-    deleteDefaultValue: false,
-    deleteEmpty: false,
-    inputValue: '1',
-
-    height: 22, // hack: set same height as text fields
-
-    getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue) {
-            val = me.getSubmitValue();
-            if (val !== null) {
-                data = {};
-               if ((val == me.defaultValue) && me.deleteDefaultValue) {
-                   data['delete'] = me.getName();
-               } else {
-                    data[me.getName()] = val;
-               }
-            } else if (me.deleteEmpty) {
-               data = {};
-               data['delete'] = me.getName();
-           }
-        }
-        return data;
-    },
-
-    // also accept integer 1 as true
-    setRawValue: function(value) {
-       var me = this;
-
-       if (value === 1) {
-            me.callParent([true]);
-       } else {
-            me.callParent([value]);
-       }
-    }
-
-});
\ No newline at end of file
diff --git a/www/manager5/form/ComboGrid.js b/www/manager5/form/ComboGrid.js
deleted file mode 100644 (file)
index 26a57b4..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-Ext.define('PVE.form.ComboGrid', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: ['widget.PVE.form.ComboGrid'],
-
-    // this value is used as default value after load()
-    preferredValue: undefined,
-
-    computeHeight: function() {
-       var me = this;
-       var lh = PVE.Utils.gridLineHeigh();
-       var count = me.store.getTotalCount();
-       return (count > 10) ? 10*lh : 26+count*lh;
-    },
-
-    // hack: allow to select empty value
-    // seems extjs does not allow that when 'editable == false'
-    onKeyUp: function(e, t) {
-        var me = this;
-        var key = e.getKey();
-
-        if (!me.editable && me.allowBlank && !me.multiSelect &&
-           (key == e.BACKSPACE || key == e.DELETE)) {
-           me.setValue('');
-       }
-
-        me.callParent(arguments);      
-    },
-
-    // copied from ComboBox 
-    createPicker: function() {
-        var me = this,
-        picker,
-        menuCls = Ext.baseCSSPrefix + 'menu',
-
-        opts = Ext.apply({
-            selModel: {
-                mode: me.multiSelect ? 'SIMPLE' : 'SINGLE'
-            },
-            floating: true,
-            hidden: true,
-            ownerCt: me.ownerCt,
-            cls: me.el.up('.' + menuCls) ? menuCls : '',
-            store: me.store,
-            displayField: me.displayField,
-            focusOnToFront: false,
-           height: me.computeHeight(),
-            pageSize: me.pageSize
-        }, me.listConfig, me.defaultListConfig);
-
-       // NOTE: we simply use a grid panel
-        //picker = me.picker = Ext.create('Ext.view.BoundList', opts);
-       picker = me.picker = Ext.create('Ext.grid.Panel', opts);
-
-       // pass getNode() to the view
-       picker.getNode = function() {
-           picker.getView().getNode(arguments);
-       };
-
-        me.mon(picker, {
-            itemclick: me.onItemClick,
-            refresh: me.onListRefresh,
-           show: function() {
-               picker.setHeight(me.computeHeight());
-               me.syncSelection();
-           },
-            scope: me
-        });
-
-        me.mon(picker.getSelectionModel(), 'selectionchange', me.onListSelectionChange, me);
-
-        return picker;
-    },
-
-    initComponent: function() {
-       var me = this;
-
-       if (me.initialConfig.editable === undefined) {
-           me.editable = false;
-       }
-
-       Ext.apply(me, {
-           queryMode: 'local',
-           matchFieldWidth: false
-       });
-
-       Ext.applyIf(me, { value: ''}); // hack: avoid ExtJS validate() bug
-
-       Ext.applyIf(me.listConfig, { width: 400 });
-
-        me.callParent();
-
-       me.store.on('beforeload', function() {   
-           if (!me.isDisabled()) {
-               me.setDisabled(true);
-               me.enableAfterLoad = true;
-           }
-       });
-
-       // hack: autoSelect does not work
-       me.store.on('load', function(store, r, success, o) {
-           if (success) {
-               me.clearInvalid();
-               
-               if (me.enableAfterLoad) {
-                   delete me.enableAfterLoad;
-                   me.setDisabled(false);
-               }
-
-               var def = me.getValue() || me.preferredValue;
-               if (def) {
-                   me.setValue(def, true); // sync with grid
-               }
-               var found = false;
-               if (def) {
-                   if (Ext.isArray(def)) {
-                       Ext.Array.each(def, function(v) {
-                           if (store.findRecord(me.valueField, v)) {
-                               found = true;
-                               return false; // break
-                           }
-                       });
-                   } else {
-                       found = store.findRecord(me.valueField, def);
-                   }
-               }
-
-               if (!found) {
-                   var rec = me.store.first();
-                   if (me.autoSelect && rec && rec.data) {
-                       def = rec.data[me.valueField];
-                       me.setValue(def, true);
-                   } else {
-                       me.setValue(me.editable ? def : '', true);
-                   }
-               }
-           }
-       });
-    }
-});
diff --git a/www/manager5/form/CompressionSelector.js b/www/manager5/form/CompressionSelector.js
deleted file mode 100644 (file)
index 0c96eab..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-Ext.define('PVE.form.CompressionSelector', {
-    extend: 'PVE.form.KVComboBox',
-    alias: ['widget.pveCompressionSelector'],
-    comboItems: [
-                ['', PVE.Utils.noneText],
-                ['lzo', 'LZO (' + gettext('fast') + ')'],
-                ['gzip', 'GZIP (' + gettext('good') + ')']
-    ]
-});
diff --git a/www/manager5/form/ContentTypeSelector.js b/www/manager5/form/ContentTypeSelector.js
deleted file mode 100644 (file)
index 0c74524..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-Ext.define('PVE.form.ContentTypeSelector', {
-    extend: 'PVE.form.KVComboBox',
-    alias: ['widget.pveContentTypeSelector'],
-  
-    cts: undefined,
-
-    initComponent: function() {
-       var me = this;
-
-       me.data = [];
-
-       if (me.cts === undefined) {
-           me.cts = ['images', 'iso', 'vztmpl', 'backup', 'rootdir'];
-       }
-
-       Ext.Array.each(me.cts, function(ct) {
-           me.data.push([ct, PVE.Utils.format_content_types(ct)]);
-       });
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/form/ControllerSelector.js b/www/manager5/form/ControllerSelector.js
deleted file mode 100644 (file)
index dfff96b..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-Ext.define('PVE.form.ControllerSelector', {
-    extend: 'Ext.form.FieldContainer',
-    alias: ['widget.PVE.form.ControllerSelector'],
-   
-    statics: {
-       maxIds: {
-           ide: 3,
-           sata: 5,
-           virtio: 15,
-           scsi: 13
-       }
-    },
-
-    noVirtIO: false,
-
-    noScsi: false,
-
-    vmconfig: {}, // used to check for existing devices
-
-    setVMConfig: function(vmconfig, autoSelect) {
-       var me = this;
-
-       me.vmconfig = Ext.apply({}, vmconfig);
-       if (autoSelect) {
-           var clist = ['ide', 'virtio', 'scsi', 'sata'];
-           if (autoSelect === 'cdrom') {
-               clist = ['ide', 'scsi', 'sata'];
-               if (!Ext.isDefined(me.vmconfig.ide2)) {
-                   me.down('field[name=controller]').setValue('ide');
-                   me.down('field[name=deviceid]').setValue(2);
-                   return;
-               }
-           } else if (me.vmconfig.ostype === 'l26') {
-               clist = ['virtio', 'ide', 'scsi', 'sata'];
-           }
-
-           Ext.Array.each(clist, function(controller) {
-               var confid, i;
-               if ((controller === 'virtio' && me.noVirtIO) ||
-                   (controller === 'scsi' && me.noScsi)) {
-                   return; //continue
-               }
-               me.down('field[name=controller]').setValue(controller);
-               for (i = 0; i <= PVE.form.ControllerSelector.maxIds[controller]; i++) {
-                   confid = controller + i.toString();
-                   if (!Ext.isDefined(me.vmconfig[confid])) {
-                       me.down('field[name=deviceid]').setValue(i);
-                       return false; // break
-                   }
-               }
-           });
-       }
-       me.down('field[name=deviceid]').validate();
-    },
-
-    initComponent: function() {
-       var me = this;
-
-       Ext.apply(me, {
-           fieldLabel: gettext('Bus/Device'),
-           layout: 'hbox',
-           height: 22, // hack: set to same height as other fields
-           defaults: {
-                flex: 1,
-                hideLabel: true
-           },
-           items: [
-               {
-                   xtype: 'PVE.form.BusTypeSelector',
-                   name: 'controller',
-                   value: 'ide',
-                   noVirtIO: me.noVirtIO,
-                   noScsi: me.noScsi,
-                   allowBlank: false,
-                   listeners: {
-                       change: function(t, value) {
-                           if (!me.rendered || !value) {
-                               return;
-                           }
-                           var field = me.down('field[name=deviceid]');
-                           field.setMaxValue(PVE.form.ControllerSelector.maxIds[value]);
-                           field.validate();
-                       }
-                   }
-               },
-               {
-                   xtype: 'numberfield',
-                   name: 'deviceid',
-                   minValue: 0,
-                   maxValue: PVE.form.ControllerSelector.maxIds.ide,
-                   value: '0',
-                   validator: function(value) {
-                       /*jslint confusion: true */
-                       if (!me.rendered) {
-                           return;
-                       }
-                       var field = me.down('field[name=controller]');
-                       var controller = field.getValue();
-                       var confid = controller + value;
-                       if (Ext.isDefined(me.vmconfig[confid])) {
-                           return "This device is already in use.";
-                       }
-                       return true;
-                   }
-               }
-           ]
-       });
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/form/DayOfWeekSelector.js b/www/manager5/form/DayOfWeekSelector.js
deleted file mode 100644 (file)
index 4fbc180..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-Ext.define('PVE.form.DayOfWeekSelector', {
-    extend: 'PVE.form.KVComboBox',
-    alias: ['widget.pveDayOfWeekSelector'],
-    comboItems: [
-           ['sun', Ext.util.Format.htmlDecode(Ext.Date.dayNames[0])],
-           ['mon', Ext.util.Format.htmlDecode(Ext.Date.dayNames[1])],
-           ['tue', Ext.util.Format.htmlDecode(Ext.Date.dayNames[2])],
-           ['wed', Ext.util.Format.htmlDecode(Ext.Date.dayNames[3])],
-           ['thu', Ext.util.Format.htmlDecode(Ext.Date.dayNames[4])],
-           ['fri', Ext.util.Format.htmlDecode(Ext.Date.dayNames[5])],
-           ['sat', Ext.util.Format.htmlDecode(Ext.Date.dayNames[6])]
-       ]
-});
diff --git a/www/manager5/form/DiskFormatSelector.js b/www/manager5/form/DiskFormatSelector.js
deleted file mode 100644 (file)
index 30de6ec..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-Ext.define('PVE.form.DiskFormatSelector', {
-    extend: 'PVE.form.KVComboBox',
-    alias: ['widget.PVE.form.DiskFormatSelector'],
-  
-    initComponent: function() {
-       var me = this;
-
-        me.data = [ 
-           ['raw', gettext('Raw disk image') + ' (raw)'], 
-           ['qcow2', gettext('QEMU image format') + ' (qcow2)'],
-           ['vmdk', gettext('VMware image format') + ' (vmdk)']
-       ];
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/form/DisplaySelector.js b/www/manager5/form/DisplaySelector.js
deleted file mode 100644 (file)
index 755d059..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-Ext.define('PVE.form.DisplaySelector', {
-    extend: 'PVE.form.KVComboBox',
-    alias: ['widget.DisplaySelector'],
-  
-    initComponent: function() {
-       var me = this;
-
-       me.data = PVE.Utils.kvm_vga_driver_array();
-       me.callParent();
-    }
-});
diff --git a/www/manager5/form/EmailNotificationSelector.js b/www/manager5/form/EmailNotificationSelector.js
deleted file mode 100644 (file)
index 36e35c5..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-Ext.define('PVE.form.EmailNotificationSelector', {
-    extend: 'PVE.form.KVComboBox',
-    alias: ['widget.pveEmailNotificationSelector'],
-    comboItems: [
-                ['always', gettext('Always')],
-                ['failure', gettext('On failure only')]
-    ]
-});
diff --git a/www/manager5/form/FileSelector.js b/www/manager5/form/FileSelector.js
deleted file mode 100644 (file)
index 50f9442..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-Ext.define('PVE.form.FileSelector', {
-    extend: 'PVE.form.ComboGrid',
-    alias: ['widget.pveFileSelector'],
-
-    setStorage: function(storage, nodename) {
-       var me = this;
-
-       var change = false;
-       if (storage && (me.storage !== storage)) {
-           me.storage = storage;
-           change = true;
-       }
-
-       if (nodename && (me.nodename !== nodename)) {
-           me.nodename = nodename;
-           change = true;
-       }
-
-       if (!(me.storage && me.nodename && change)) {
-           return;
-       }
-
-       var url = '/api2/json/nodes/' + me.nodename + '/storage/' + me.storage + '/content';
-       if (me.storageContent) {
-           url += '?content=' + me.storageContent;
-       }
-
-       me.store.setProxy({
-           type: 'pve',
-           url: url
-       });
-
-       me.store.load();
-    },
-
-    initComponent: function() {
-       var me = this;
-
-       var store = Ext.create('Ext.data.Store', {
-           model: 'pve-storage-content'
-       });
-
-       Ext.apply(me, {
-           store: store,
-           allowBlank: false,
-           autoSelect: false,
-           valueField: 'volid',
-           displayField: 'text',
-            listConfig: {
-               columns: [
-                   {
-                       header: gettext('Name'),
-                       dataIndex: 'text',
-                       hideable: false,
-                       flex: 1
-                   },
-                   {
-                       header: gettext('Format'),
-                       width: 60, 
-                       dataIndex: 'format'
-                   },
-                   {
-                       header: gettext('Size'),
-                       width: 60, 
-                       dataIndex: 'size', 
-                       renderer: PVE.Utils.format_size 
-                   }
-               ]
-           }
-       });
-
-        me.callParent();
-
-       me.setStorage(me.storage, me.nodename);
-    }
-});
diff --git a/www/manager5/form/FirewallPolicySelector.js b/www/manager5/form/FirewallPolicySelector.js
deleted file mode 100644 (file)
index 81492a6..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-Ext.define('PVE.form.FirewallPolicySelector', {
-    extend: 'PVE.form.KVComboBox',
-    alias: ['widget.pveFirewallPolicySelector'],
-  
-    initComponent: function() {
-       var me = this;
-
-       me.data = [ 
-           ['ACCEPT', 'ACCEPT'], 
-           ['REJECT', 'REJECT'],
-           [ 'DROP', 'DROP']
-       ];
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/form/GroupSelector.js b/www/manager5/form/GroupSelector.js
deleted file mode 100644 (file)
index f4e4b63..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-Ext.define('PVE.form.GroupSelector', {
-    extend: 'PVE.form.ComboGrid',
-    alias: ['widget.pveGroupSelector'],
-
-    allowBlank: false,
-
-    initComponent: function() {
-       var me = this;
-
-       var store = new Ext.data.Store({
-           model: 'pve-groups'
-       });
-
-       Ext.apply(me, {
-           store: store,
-           autoSelect: false,
-           valueField: 'groupid',
-           displayField: 'groupid',
-            listConfig: {
-               columns: [
-                   {
-                       header: gettext('Group'),
-                       sortable: true,
-                       dataIndex: 'groupid',
-                       flex: 1
-                   },
-                   {
-                       id: 'comment',
-                       header: gettext('Comment'),
-                       sortable: false,
-                       dataIndex: 'comment',
-                       flex: 1
-                   }
-               ]
-           }
-       });
-
-        me.callParent();
-
-       store.load();
-    }
-
-}, function() {
-
-    Ext.define('pve-groups', {
-       extend: 'Ext.data.Model',
-       fields: [ 'groupid', 'comment' ],
-       proxy: {
-            type: 'pve',
-           url: "/api2/json/access/groups"
-       },
-       idProperty: 'groupid'
-    });
-
-});
diff --git a/www/manager5/form/HotplugFeatureSelector.js b/www/manager5/form/HotplugFeatureSelector.js
deleted file mode 100644 (file)
index e0dac4b..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-Ext.define('PVE.form.HotplugFeatureSelector', {
-    extend: 'PVE.form.KVComboBox',
-    alias: ['widget.pveHotplugFeatureSelector'],
-
-    multiSelect: true,
-    allowBlank: true,
-    deleteEmpty: false,
-
-    setValue: function(value, doSelect) {
-       var me = this;
-
-       if (me.multiSelect && Ext.isString(value)) {
-           if (value === '0') {
-               value = [];
-           } else if (value === '1') {
-               value = ['disk', 'network', 'usb'];
-           } else {
-               value = value.split(',');
-           }
-       }
-
-       me.callParent([value, doSelect]);
-    },
-
-    getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue) {
-            val = me.getSubmitValue();
-           if (Ext.isArray(val)) {
-               val = val.join(',') || '0';
-           }
-            if (val !== null && val !== '') {
-                data = {};
-                data[me.getName()] = val;
-            } else if (me.deleteEmpty) {
-               data = {};
-                data['delete'] = me.getName();
-           }
-        }
-        return data;
-    },
-
-  
-    initComponent: function() {
-       var me = this;
-
-       me.data = [['disk', gettext('Disk')], 
-                  ['network',  gettext('Network')], 
-                  ['usb',  gettext('USB')],
-                  ['memory',  gettext('Memory')],
-                  ['cpu',  gettext('CPU')]];
-       
-       me.callParent();
-    }
-});
diff --git a/www/manager5/form/IPProtocolSelector.js b/www/manager5/form/IPProtocolSelector.js
deleted file mode 100644 (file)
index 55a95d9..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-Ext.define('PVE.form.IPProtocolSelector', {
-    extend: 'PVE.form.ComboGrid',
-    alias: ['widget.pveIPProtocolSelector'],
-
-    initComponent: function() {
-       var me = this;
-       
-       var store = Ext.create('Ext.data.Store', {
-           fields: [ 'p', 'd', 'n'],
-           data: [
-               { p: 'tcp', n: 6, d: 'Transmission Control Protocol' },
-               { p: 'udp', n: 17, d: 'User Datagram Protocol' },
-               { p: 'icmp', n: 1, d: 'Internet Control Message Protocol' },
-               { p: 'igmp', n: 2,  d: 'Internet Group Management' },
-               { p: 'ggp', n: 3, d: 'gateway-gateway protocol' },
-               { p: 'ipencap', n: 4, d: 'IP encapsulated in IP' },
-               { p: 'st', n: 5, d: 'ST datagram mode' },
-               { p: 'egp', n: 8, d: 'exterior gateway protocol' },
-               { p: 'igp', n: 9, d: 'any private interior gateway (Cisco)' },
-               { p: 'pup', n: 12, d: 'PARC universal packet protocol' },
-               { p: 'hmp', n: 20, d: 'host monitoring protocol' },
-               { p: 'xns-idp', n: 22, d: 'Xerox NS IDP' },
-               { p: 'rdp', n: 27, d: '"reliable datagram" protocol' },
-               { p: 'iso-tp4', n: 29, d: 'ISO Transport Protocol class 4 [RFC905]' },
-               { p: 'dccp', n: 33, d: 'Datagram Congestion Control Prot. [RFC4340]' },
-               { p: 'xtp', n: 36, d: 'Xpress Transfer Protocol' },
-               { p: 'ddp', n: 37, d: 'Datagram Delivery Protocol' },
-               { p: 'idpr-cmtp', n: 38, d: 'IDPR Control Message Transport' },
-               { p: 'ipv6', n: 41, d: 'Internet Protocol, version 6' },
-               { p: 'ipv6-route', n: 43, d: 'Routing Header for IPv6' },
-               { p: 'ipv6-frag', n: 44, d: 'Fragment Header for IPv6' },
-               { p: 'idrp', n: 45, d: 'Inter-Domain Routing Protocol' },
-               { p: 'rsvp', n: 46, d: 'Reservation Protocol' },
-               { p: 'gre', n: 47, d: 'General Routing Encapsulation' },
-               { p: 'esp', n: 50, d: 'Encap Security Payload [RFC2406]' },
-               { p: 'ah', n: 51, d: 'Authentication Header [RFC2402]' },
-               { p: 'skip', n: 57, d: 'SKIP' },
-               { p: 'ipv6-icmp', n: 58, d: 'ICMP for IPv6' },
-               { p: 'ipv6-nonxt', n: 59, d: 'No Next Header for IPv6' },
-               { p: 'ipv6-opts', n: 60, d: 'Destination Options for IPv6' },
-               { p: 'vmtp', n: 81, d: 'Versatile Message Transport' },
-               { p: 'eigrp', n: 88, d: 'Enhanced Interior Routing Protocol (Cisco)' },
-               { p: 'ospf', n: 89, d: 'Open Shortest Path First IGP' },
-               { p: 'ax.25', n: 93, d: 'AX.25 frames' },
-               { p: 'ipip', n: 94, d: 'IP-within-IP Encapsulation Protocol' },
-               { p: 'etherip', n: 97, d: 'Ethernet-within-IP Encapsulation [RFC3378]' },
-               { p: 'encap', n: 98, d: 'Yet Another IP encapsulation [RFC1241]' },
-               { p: 'pim', n: 103, d: 'Protocol Independent Multicast' },
-               { p: 'ipcomp', n: 108, d: 'IP Payload Compression Protocol' },
-               { p: 'vrrp', n: 112, d: 'Virtual Router Redundancy Protocol [RFC5798]' },
-               { p: 'l2tp', n: 115, d: 'Layer Two Tunneling Protocol [RFC2661]' },
-               { p: 'isis', n: 124, d: 'IS-IS over IPv4' },
-               { p: 'sctp', n: 132, d: 'Stream Control Transmission Protocol' },
-               { p: 'fc', n: 133, d: 'Fibre Channel' },
-               { p: 'mobility-header', n: 135, d: 'Mobility Support for IPv6 [RFC3775]' },
-               { p: 'udplite', n: 136, d: 'UDP-Lite [RFC3828]' },
-               { p: 'mpls-in-ip', n: 137, d: 'MPLS-in-IP [RFC4023]' },
-               { p: 'hip', n: 139, d: 'Host Identity Protocol' },
-               { p: 'shim6', n: 140, d: 'Shim6 Protocol [RFC5533]' },
-               { p: 'wesp', n: 141, d: 'Wrapped Encapsulating Security Payload' },
-               { p: 'rohc', n: 142, d: 'Robust Header Compression' }
-           ]
-       });
-
-       Ext.apply(me, {
-           store: store,
-           valueField: 'p',
-           displayField: 'p',
-            listConfig: {
-               columns: [
-                   {
-                       header: gettext('Protocol'),
-                       dataIndex: 'p',
-                       hideable: false,
-                       sortable: false,
-                       width: 100
-                   },
-                   {
-                       header: gettext('Number'),
-                       dataIndex: 'n',
-                       hideable: false,
-                       sortable: false,
-                       width: 50
-                   },
-                   {
-                       header: gettext('Description'),
-                       dataIndex: 'd',
-                       hideable: false,
-                       sortable: false,
-                       flex: 1
-                   }
-               ]
-           }
-       });
-
-        me.callParent();
-    }
-});
diff --git a/www/manager5/form/IPRefSelector.js b/www/manager5/form/IPRefSelector.js
deleted file mode 100644 (file)
index a017e15..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-Ext.define('PVE.form.IPRefSelector', {
-    extend: 'PVE.form.ComboGrid',
-    alias: ['widget.pveIPRefSelector'],
-
-    base_url: undefined,
-
-    preferredValue: '', // hack: else Form sets dirty flag?
-
-    ref_type: undefined, // undefined = any [undefined, 'ipset' or 'alias']
-
-    initComponent: function() {
-       var me = this;
-
-       if (!me.base_url) {
-           throw "no base_url specified";
-       }
-
-       var url = "/api2/json" + me.base_url;
-       if (me.ref_type) {
-           url += "?type=" + me.ref_type;
-       }
-
-       var store = Ext.create('Ext.data.Store', {
-           autoLoad: true,
-           fields: [ 'type', 'name', 'ref', 'comment' ],
-           idProperty: 'ref',
-           proxy: {
-               type: 'pve',
-               url: url
-           },
-           sorters: {
-               property: 'ref',
-               order: 'DESC'
-           }
-       });
-
-       var disable_query_for_ips = function(f, value) {
-           if (value === null || 
-               value.match(/^\d/)) { // IP address starts with \d
-               f.queryDelay = 9999999999; // hack: disbale with long delay
-           } else {
-               f.queryDelay = 10;
-           }
-       };
-
-       var columns = [];
-
-       if (!me.ref_type) {
-           columns.push({
-               header: gettext('Type'),
-               dataIndex: 'type',
-               hideable: false,
-               width: 60
-           });
-       }
-
-       columns.push([
-           {
-               header: gettext('Name'),
-               dataIndex: 'ref',
-               hideable: false,
-               width: 140
-           },
-           {
-               header: gettext('Comment'),  
-               dataIndex: 'comment', 
-               flex: 1
-           }
-       ]);
-
-       Ext.apply(me, {
-           store: store,
-           valueField: 'ref',
-           displayField: 'ref',
-            listConfig: { columns: columns }
-       });
-
-       me.on('change', disable_query_for_ips);
-
-        me.callParent();
-    }
-});
-
diff --git a/www/manager5/form/KVComboBox.js b/www/manager5/form/KVComboBox.js
deleted file mode 100644 (file)
index 5247c86..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Key-Value ComboBox
- *
- * config properties:
- * comboItems: an array of Key - Value pairs
- * deleteEmpty: if set to true (default), an empty value received from the
- * comboBox will reset the property to its default value
- */
-Ext.define('PVE.form.KVComboBox', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveKVComboBox',
-
-    deleteEmpty: true,
-    comboItems: undefined,
-
-    getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue) {
-            val = me.getSubmitValue();
-            if (val !== null && val !== '') {
-                data = {};
-                data[me.getName()] = val;
-            } else if (me.deleteEmpty) {
-                data = {};
-                data['delete'] = me.getName();
-            }
-        }
-        return data;
-    },
-
-    initComponent: function() {
-       var me = this;
-
-       me.store = Ext.create('Ext.data.ArrayStore', {
-           model: 'KeyValue',
-           data : me.comboItems,
-       });
-
-       if (me.initialConfig.editable === undefined) {
-           me.editable = false;
-       }
-
-       Ext.apply(me, {
-           displayField: 'value',
-           valueField: 'key',
-           queryMode: 'local'
-       });
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/form/LanguageSelector.js b/www/manager5/form/LanguageSelector.js
deleted file mode 100644 (file)
index 5e30ee6..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-Ext.define('PVE.form.LanguageSelector', {
-    extend: 'PVE.form.KVComboBox',
-    alias: ['widget.pveLanguageSelector'],
-    comboItems: PVE.Utils.language_array()
-});
diff --git a/www/manager5/form/MemoryField.js b/www/manager5/form/MemoryField.js
deleted file mode 100644 (file)
index 1d8bdb2..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-Ext.define('PVE.form.MemoryField', {
-    extend: 'Ext.form.field.Number',
-    alias: 'widget.pveMemoryField',
-
-    allowBlank: false,
-
-    hotplug: false,
-
-    minValue: 32,
-
-    maxValue: 4178944,
-
-    step: 32,
-
-    value: '512', // qm default
-
-    computeUpDown: function(value) {
-       var me = this;
-
-       if (!me.hotplug) {
-           return { up: value + me.step, down: value - me.step };
-       }
-       
-       var dimm_size = 512;
-       var prev_dimm_size = 0;
-       var min_size = 1024;
-       var current_size = min_size;
-       var value_up = min_size;
-       var value_down = min_size;
-       var value_start = min_size;
-
-       var i, j;
-       for (j = 0; j < 9; j++) {
-           for (i = 0; i < 32; i++) {
-               if ((value >= current_size) && (value < (current_size + dimm_size))) {
-                   value_start = current_size,
-                   value_up = current_size + dimm_size;
-                   value_down = current_size - ((i === 0) ? prev_dimm_size : dimm_size);
-               }
-               current_size += dimm_size;                              
-           }
-           prev_dimm_size = dimm_size;
-           dimm_size = dimm_size*2;
-       }
-
-       return { up: value_up, down: value_down, start: value_start };
-    },
-
-    onSpinUp: function() {
-       var me = this;
-       if (!me.readOnly) {
-           var res = me.computeUpDown(me.getValue());
-           me.setValue(Ext.Number.constrain(res.up, me.minValue, me.maxValue));
-       }
-    },
-
-    onSpinDown: function() {
-       var me = this;
-       if (!me.readOnly) {
-           var res = me.computeUpDown(me.getValue());
-           me.setValue(Ext.Number.constrain(res.down, me.minValue, me.maxValue));
-       }
-    },
-
-    initComponent: function() {
-        var me = this;
-
-       if (me.hotplug) {
-           me.minValue = 1024;
-
-           me.on('blur', function(field) {
-               value = me.getValue();
-               var res = me.computeUpDown(value);
-               if (value === res.start || value === res.up || value === res.down) {
-                   return;
-               }
-               field.setValue(res.up);
-           });
-       }
-
-        me.callParent();
-    }
-});
diff --git a/www/manager5/form/NetworkCardSelector.js b/www/manager5/form/NetworkCardSelector.js
deleted file mode 100644 (file)
index 6e5ef93..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-Ext.define('PVE.form.NetworkCardSelector', {
-    extend: 'PVE.form.KVComboBox',
-    alias: ['widget.PVE.form.NetworkCardSelector'],
-  
-    initComponent: function() {
-       var me = this;
-
-        me.data = [ 
-           ['e1000', 'Intel E1000'],
-           ['virtio', 'VirtIO (' + gettext('paravirtualized') + ')'],
-           ['rtl8139', 'Realtek RTL8139'],
-           ['vmxnet3', 'VMWare vmxnet3']
-       ];
-       me.callParent();
-    }
-});
diff --git a/www/manager5/form/NodeSelector.js b/www/manager5/form/NodeSelector.js
deleted file mode 100644 (file)
index 4a6a788..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-Ext.define('PVE.form.NodeSelector', {
-    extend: 'PVE.form.ComboGrid',
-    alias: ['widget.PVE.form.NodeSelector'],
-
-    // invalidate nodes which are offline
-    onlineValidator: false,
-
-    selectCurNode: false,
-
-    // only allow those nodes (array)
-    allowedNodes: undefined,
-
-    initComponent: function() {
-       var me = this;
-
-       var store = Ext.create('Ext.data.Store', {
-           fields: [ 'node', 'cpu', 'maxcpu', 'mem', 'maxmem', 'uptime' ],
-           autoLoad: true,
-           proxy: {
-               type: 'pve',
-               url: '/api2/json/nodes'
-           },
-           sorters: [
-               {
-                   property : 'node',
-                   direction: 'ASC'
-               },
-               {
-                   property : 'mem',
-                   direction: 'DESC'
-               }
-           ]
-       });
-
-       Ext.apply(me, {
-           store: store,
-           valueField: 'node',
-           displayField: 'node',
-            listConfig: {
-               columns: [
-                   {
-                       header: gettext('Node'),
-                       dataIndex: 'node',
-                       sortable: true,
-                       hideable: false,
-                       flex: 1
-                   },
-                   {
-                       header: gettext('Memory usage'),                        
-                       renderer: PVE.Utils.render_mem_usage,
-                       sortable: true,
-                       width: 100,
-                       dataIndex: 'mem'
-                   },
-                   {
-                       header: gettext('CPU usage'),
-                       renderer: PVE.Utils.render_cpu,
-                       sortable: true,
-                       width: 100,
-                       dataIndex: 'cpu'
-                   }
-               ]
-           },
-           validator: function(value) {
-               /*jslint confusion: true */
-               if (!me.onlineValidator || (me.allowBlank && !value)) {
-                   return true;
-               }
-               
-               var offline = [];
-               var notAllowed = [];
-
-               Ext.Array.each(value.split(/\s*,\s*/), function(node) {
-                   var rec = me.store.findRecord(me.valueField, node);
-                   if (!(rec && rec.data) || !Ext.isNumeric(rec.data.mem)) {
-                       offline.push(node);
-                   } else if (me.allowedNodes && !Ext.Array.contains(me.allowedNodes, node)) {
-                       notAllowed.push(node);
-                   }
-               });
-
-               if (notAllowed.length !== 0) {
-                   return "Node " + notAllowed.join(', ') + " is not allowed for this action!";
-               } 
-
-               if (offline.length !== 0) {
-                   return "Node " + offline.join(', ') + " seems to be offline!";
-               }
-               return true;
-           }
-       });
-
-        if (me.selectCurNode && PVE.curSelectedNode.data.node) {
-            me.preferredValue = PVE.curSelectedNode.data.node;
-        }
-
-        me.callParent();
-    }
-});
diff --git a/www/manager5/form/PoolSelector.js b/www/manager5/form/PoolSelector.js
deleted file mode 100644 (file)
index a607589..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-Ext.define('PVE.form.PoolSelector', {
-    extend: 'PVE.form.ComboGrid',
-    alias: ['widget.pvePoolSelector'],
-
-    allowBlank: false,
-
-    initComponent: function() {
-       var me = this;
-
-       var store = new Ext.data.Store({
-           model: 'pve-pools'
-       });
-
-       Ext.apply(me, {
-           store: store,
-           autoSelect: false,
-           valueField: 'poolid',
-           displayField: 'poolid',
-            listConfig: {
-               columns: [
-                   {
-                       header: gettext('Pool'),
-                       sortable: true,
-                       dataIndex: 'poolid',
-                       flex: 1
-                   },
-                   {
-                       id: 'comment',
-                       header: gettext('Comment'),
-                       sortable: false,
-                       dataIndex: 'comment',
-                       flex: 1
-                   }
-               ]
-           }
-       });
-
-        me.callParent();
-
-       store.load();
-    }
-
-}, function() {
-
-    Ext.define('pve-pools', {
-       extend: 'Ext.data.Model',
-       fields: [ 'poolid', 'comment' ],
-       proxy: {
-            type: 'pve',
-           url: "/api2/json/pools"
-       },
-       idProperty: 'poolid'
-    });
-
-});
diff --git a/www/manager5/form/RRDTypeSelector.js b/www/manager5/form/RRDTypeSelector.js
deleted file mode 100644 (file)
index 973a64a..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-Ext.define('PVE.form.RRDTypeSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: ['widget.pveRRDTypeSelector'],
-  
-    initComponent: function() {
-        var me = this;
-       
-       var store = new Ext.data.ArrayStore({
-            fields: [ 'id', 'timeframe', 'cf', 'text' ],
-            data : [
-               [ 'hour', 'hour', 'AVERAGE', "Hour (average)" ],
-               [ 'hourmax', 'hour', 'MAX', "Hour (max)" ],
-               [ 'day', 'day', 'AVERAGE', "Day (average)" ],
-               [ 'daymax', 'day', 'MAX', "Day (max)" ],
-               [ 'week', 'week', 'AVERAGE', "Week (average)" ],
-               [ 'weekmax', 'week', 'MAX', "Week (max)" ],
-               [ 'month', 'month', 'AVERAGE', "Month (average)" ],
-               [ 'monthmax', 'month', 'MAX', "Month (max)" ],
-               [ 'year', 'year', 'AVERAGE', "Year (average)" ],
-               [ 'yearmax', 'year', 'MAX', "Year (max)" ]
-           ]
-       });
-
-       Ext.apply(me, {
-            store: store,
-            displayField: 'text',
-           valueField: 'id',
-           editable: false,
-            queryMode: 'local',
-           value: 'hour',
-           getState: function() {
-               var ind = store.findExact('id', me.getValue());
-               var rec = store.getAt(ind);
-               if (!rec) {
-                   return;
-               }
-               return { 
-                   id: rec.data.id,
-                   timeframe: rec.data.timeframe,
-                   cf: rec.data.cf
-               };
-           },
-           applyState : function(state) {
-               if (state && state.id) {
-                   me.setValue(state.id);
-               }
-           },
-           stateEvents: [ 'select' ],
-           stateful: true,
-           id: 'pveRRDTypeSelection'        
-       });
-
-       me.callParent();
-
-       var statechange = function(sp, key, value) {
-           if (key === me.id) {
-               me.applyState(value);
-           }
-       };
-
-       var sp = Ext.state.Manager.getProvider();
-       me.mon(sp, 'statechange', statechange, me);
-    }
-});
-
diff --git a/www/manager5/form/RealmComboBox.js b/www/manager5/form/RealmComboBox.js
deleted file mode 100644 (file)
index 34b417d..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-Ext.define('PVE.form.RealmComboBox', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: ['widget.pveRealmComboBox'],
-
-    needOTP: function(realm) {
-       var me = this;
-
-       var rec = me.store.findRecord('realm', realm);
-
-       return rec && rec.data && rec.data.tfa ? rec.data.tfa : undefined;
-    },
-
-    initComponent: function() {
-       var me = this;
-
-       var stateid = 'pveloginrealm';
-
-       var realmstore = Ext.create('Ext.data.Store', {
-           model: 'pve-domains',
-       });
-
-       Ext.apply(me, {
-           fieldLabel: gettext('Realm'),
-           name: 'realm',
-           store: realmstore,
-           queryMode: 'local',
-           allowBlank: false,
-           forceSelection: true,
-           autoSelect: false,
-           triggerAction: 'all',
-           valueField: 'realm',
-           displayField: 'descr',
-           getState: function() {
-               return { value: this.getValue() };
-           },
-           applyState : function(state) {
-               if (state && state.value) {
-                   this.setValue(state.value);
-               }
-           },
-           stateEvents: [ 'select' ],
-           stateful: true,
-           id: stateid, // fixme: remove (Stateful does not work without)  
-           stateID: stateid
-       });
-
-        me.callParent();
-
-       realmstore.load({
-           callback: function(r, o, success) {
-               if (success) {
-                   var def = me.getValue();
-                   if (!def || !realmstore.findRecord('realm', def)) {
-                       def = 'pam';
-                       Ext.each(r, function(record) {
-                           if (record.data && record.data["default"]) { 
-                               def = record.data.realm;
-                           }
-                       });
-                   }
-                   if (def) {
-                       me.setValue(def);
-                   }
-               }
-           }
-       });
-    }
-});
diff --git a/www/manager5/form/RoleSelector.js b/www/manager5/form/RoleSelector.js
deleted file mode 100644 (file)
index 7ffcad2..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-Ext.define('PVE.form.RoleSelector', {
-    extend: 'PVE.form.ComboGrid',
-    alias: ['widget.pveRoleSelector'],
-
-    initComponent: function() {
-       var me = this;
-
-       var store = new Ext.data.Store({
-           model: 'pve-roles'
-       });
-
-       Ext.apply(me, {
-           store: store,
-           allowBlank: false,
-           autoSelect: false,
-           valueField: 'roleid',
-           displayField: 'roleid',
-            listConfig: {
-               columns: [
-                   {
-                       header: gettext('Role'),
-                       sortable: true,
-                       dataIndex: 'roleid',
-                       flex: 1
-                   }
-               ]
-           }
-       });
-
-        me.callParent();
-
-       store.load();
-    }
-
-}, function() {
-
-    Ext.define('pve-roles', {
-       extend: 'Ext.data.Model',
-       fields: [ 'roleid', 'privs' ],
-       proxy: {
-            type: 'pve',
-           url: "/api2/json/access/roles"
-       },
-       idProperty: 'roleid'
-    });
-
-});
diff --git a/www/manager5/form/ScsiHwSelector.js b/www/manager5/form/ScsiHwSelector.js
deleted file mode 100644 (file)
index dc868c5..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-Ext.define('PVE.form.ScsiHwSelector', {
-    extend: 'PVE.form.KVComboBox',
-    alias: ['widget.pveScsiHwSelector'],
-  
-    initComponent: function() {
-       var me = this;
-
-        me.data = [ 
-           ['', PVE.Utils.render_scsihw('')],
-           ['lsi', PVE.Utils.render_scsihw('lsi')],
-           ['lsi53c810', PVE.Utils.render_scsihw('lsi53c810')],
-           ['megasas', PVE.Utils.render_scsihw('megasas')],
-           ['virtio-scsi-pci', PVE.Utils.render_scsihw('virtio-scsi-pci')],
-           ['virtio-scsi-single', PVE.Utils.render_scsihw('virtio-scsi-single')],
-           ['pvscsi', PVE.Utils.render_scsihw('pvscsi')]
-       ];
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/form/SecurityGroupSelector.js b/www/manager5/form/SecurityGroupSelector.js
deleted file mode 100644 (file)
index 37e6bac..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-Ext.define('PVE.form.SecurityGroupsSelector', {
-    extend: 'PVE.form.ComboGrid',
-    alias: ['widget.pveSecurityGroupsSelector'],
-
-    initComponent: function() {
-       var me = this;
-
-       var store = Ext.create('Ext.data.Store', {
-           autoLoad: true,
-           fields: [ 'group', 'comment' ],
-           idProperty: 'group',
-           proxy: {
-               type: 'pve',
-               url: "/api2/json/cluster/firewall/groups"
-           },
-           sorters: {
-               property: 'group',
-               order: 'DESC'
-           }
-       });
-
-       Ext.apply(me, {
-           store: store,
-           valueField: 'group',
-           displayField: 'group',
-            listConfig: {
-               columns: [
-                   {
-                       header: gettext('Security Group'),
-                       dataIndex: 'group',
-                       hideable: false,
-                       width: 100
-                   },
-                   {
-                       header: gettext('Comment'),  
-                       dataIndex: 'comment', 
-                       flex: 1
-                   }
-               ]
-           }
-       });
-
-        me.callParent();
-    }
-});
-
diff --git a/www/manager5/form/SnapshotSelector.js b/www/manager5/form/SnapshotSelector.js
deleted file mode 100644 (file)
index 074e405..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-Ext.define('PVE.form.SnapshotSelector', {
-    extend: 'PVE.form.ComboGrid',
-    alias: ['widget.PVE.form.SnapshotSelector'],
-
-    loadStore: function(nodename, vmid) {
-       var me = this;
-
-       if (!nodename) {
-           return;
-       }
-
-       me.nodename = nodename;
-
-        if (!vmid) {
-           return;
-        }
-
-       me.vmid = vmid;
-
-       me.store.setProxy({
-           type: 'pve',
-           url: '/api2/json/nodes/' + me.nodename + '/qemu/' + me.vmid +'/snapshot'
-       });
-
-       me.store.load();
-    },
-
-    initComponent: function() {
-       var me = this;
-
-        if (!me.nodename) {
-            throw "no node name specified";
-        }
-
-        if (!me.vmid) {
-            throw "no VM ID specified";
-        }
-
-       var store = Ext.create('Ext.data.Store', {
-           fields: [ 'name'],
-           filterOnLoad: true
-       });
-
-       Ext.apply(me, {
-           store: store,
-           valueField: 'name',
-           displayField: 'name',
-            listConfig: {
-               columns: [
-                   {
-                       header: gettext('Snapshot'),
-                       dataIndex: 'name',
-                       hideable: false,
-                       flex: 1
-                   }
-               ]
-           }
-       });
-
-        me.callParent();
-
-       me.loadStore(me.nodename, me.vmid);
-    }
-});
diff --git a/www/manager5/form/StorageSelector.js b/www/manager5/form/StorageSelector.js
deleted file mode 100644 (file)
index 28b60ef..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-Ext.define('PVE.form.StorageSelector', {
-    extend: 'PVE.form.ComboGrid',
-    alias: ['widget.PVE.form.StorageSelector'],
-
-    reloadStorageList: function() {
-       var me = this;
-       if (!me.nodename) {
-           return;
-       }
-
-       var params = {};
-       var url = '/api2/json/nodes/' + me.nodename + '/storage';
-       if (me.storageContent) {
-           params.content = me.storageContent;
-       }
-       if (me.targetNode) {
-           params.target = me.targetNode;
-           params.enabled = 1; // skip disabled storages
-       }
-       me.store.setProxy({
-           type: 'pve',
-           url: url,
-           extraParams: params
-       });
-
-       me.store.load();
-    },
-
-    setTargetNode: function(targetNode) {
-       var me = this;
-
-       if (!targetNode || (me.targetNode === targetNode)) {
-           return;
-       }
-
-       me.targetNode = targetNode;
-
-       me.reloadStorageList();
-    },
-
-    setNodename: function(nodename) {
-       var me = this;
-
-       if (!nodename || (me.nodename === nodename)) {
-           return;
-       }
-
-       me.nodename = nodename;
-
-       me.reloadStorageList();
-    },
-
-    initComponent: function() {
-       var me = this;
-
-       var nodename = me.nodename;
-       me.nodename = undefined; 
-
-       var store = Ext.create('Ext.data.Store', {
-           model: 'pve-storage-status',
-           sorters: {
-               property: 'storage', 
-               order: 'DESC' 
-           }
-       });
-
-       Ext.apply(me, {
-           store: store,
-           allowBlank: false,
-           valueField: 'storage',
-           displayField: 'storage',
-            listConfig: {
-               columns: [
-                   {
-                       header: gettext('Name'),
-                       dataIndex: 'storage',
-                       hideable: false,
-                       flex: 1
-                   },
-                   {
-                       header: gettext('Type'),
-                       width: 60, 
-                       dataIndex: 'type'
-                   },
-                   {
-                       header: gettext('Avail'),
-                       width: 80, 
-                       dataIndex: 'avail', 
-                       renderer: PVE.Utils.format_size 
-                   },
-                   {
-                       header: gettext('Capacity'),
-                       width: 80, 
-                       dataIndex: 'total', 
-                       renderer: PVE.Utils.format_size 
-                   }
-               ]
-           }
-       });
-
-        me.callParent();
-
-       if (nodename) {
-           me.setNodename(nodename);
-       }
-    }
-}, function() {
-
-    Ext.define('pve-storage-status', {
-       extend: 'Ext.data.Model',
-       fields: [ 'storage', 'active', 'type', 'avail', 'total' ],
-       idProperty: 'storage'
-    });
-
-});
diff --git a/www/manager5/form/TextField.js b/www/manager5/form/TextField.js
deleted file mode 100644 (file)
index 60e42eb..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-Ext.define('PVE.form.Textfield', {
-    extend: 'Ext.form.field.Text',
-    alias: ['widget.pvetextfield'],
-
-    skipEmptyText: true,
-    
-    deleteEmpty: false,
-    
-    getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue && !me.isFileUpload()) {
-            val = me.getSubmitValue();
-            if (val !== null) {
-                data = {};
-                data[me.getName()] = val;
-            } else if (me.deleteEmpty) {
-               data = {};
-                data['delete'] = me.getName();
-           }
-        }
-        return data;
-    },
-
-    getSubmitValue: function() {
-       var me = this;
-
-        var value = this.processRawValue(this.getRawValue());
-       if (value !== '') {
-           return value;
-       }
-
-       return me.skipEmptyText ? null: value; 
-    }
-});
\ No newline at end of file
diff --git a/www/manager5/form/UserSelector.js b/www/manager5/form/UserSelector.js
deleted file mode 100644 (file)
index 3ba4d1b..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-Ext.define('PVE.form.UserSelector', {
-    extend: 'PVE.form.ComboGrid',
-    alias: ['widget.pveUserSelector'],
-
-    initComponent: function() {
-       var me = this;
-
-       var store = new Ext.data.Store({
-           model: 'pve-users'
-       });
-
-       var render_full_name = function(firstname, metaData, record) {
-
-           var first = firstname || '';
-           var last = record.data.lastname || '';
-           return first + " " + last;
-       };
-
-       Ext.apply(me, {
-           store: store,
-           allowBlank: false,
-           autoSelect: false,
-           valueField: 'userid',
-           displayField: 'userid',
-            listConfig: {
-               columns: [
-                   {
-                       header: gettext('User'),
-                       sortable: true,
-                       dataIndex: 'userid',
-                       flex: 1
-                   },
-                   {
-                       header: gettext('Name'),
-                       sortable: true,
-                       renderer: render_full_name,
-                       dataIndex: 'firstname',
-                       flex: 1
-                   },
-                   {
-                       id: 'comment',
-                       header: gettext('Comment'),
-                       sortable: false,
-                       dataIndex: 'comment',
-                       flex: 1
-                   }
-               ]
-           }
-       });
-
-        me.callParent();
-
-       store.load({ params: { enabled: 1 }});
-    }
-
-}, function() {
-
-    Ext.define('pve-users', {
-       extend: 'Ext.data.Model',
-       fields: [ 
-           'userid', 'firstname', 'lastname' , 'email', 'comment',
-           { type: 'boolean', name: 'enable' }, 
-           { type: 'date', dateFormat: 'timestamp', name: 'expire' }
-       ],
-       proxy: {
-            type: 'pve',
-           url: "/api2/json/access/users"
-       },
-       idProperty: 'userid'
-    });
-
-});
-
-
diff --git a/www/manager5/form/VLanField.js b/www/manager5/form/VLanField.js
deleted file mode 100644 (file)
index c699907..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-Ext.define('PVE.form.VlanField', {
-    extend: 'Ext.form.field.Number',
-    alias: ['widget.pveVlanField'],
-
-    deleteEmpty: false,
-
-    emptyText: 'no VLAN',
-    
-    fieldLabel: gettext('VLAN Tag'),
-
-    allowBlank: true,
-    
-    getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue) {
-            val = me.getSubmitValue();
-            if (val) {
-                data = {};
-                data[me.getName()] = val;
-            } else if (me.deleteEmpty) {
-               data = {};
-                data['delete'] = me.getName();
-           }
-        }
-        return data;
-    },
-
-    initComponent: function() {
-       var me = this;
-
-       Ext.apply(me, {
-           minValue: 1,
-           maxValue: 4094
-       });
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/form/VMIDSelector.js b/www/manager5/form/VMIDSelector.js
deleted file mode 100644 (file)
index 92a1781..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-Ext.define('PVE.form.VMIDSelector', {
-    extend: 'Ext.form.field.Number',
-    alias: 'widget.pveVMIDSelector',
-
-    allowBlank: false,
-  
-    minValue: 100,
-
-    maxValue: 999999999,
-
-    validateExists: undefined,
-
-    loadNextFreeVMID: false,
-
-    initComponent: function() {
-        var me = this;
-
-       Ext.applyIf(me, {
-           fieldLabel: 'VM ID',
-           listeners: {
-               'change': function(field, newValue, oldValue) {
-                   if (!Ext.isDefined(me.validateExists)) {
-                       return;
-                   }
-                   PVE.Utils.API2Request({
-                       params: { vmid: newValue },
-                       url: '/cluster/nextid',
-                       method: 'GET',
-                       success: function(response, opts) {
-                           if (me.validateExists === true) {
-                               me.markInvalid(gettext('This VM ID does not exists'));
-                           }
-                       },
-                       failure: function(response, opts) {
-                           if (me.validateExists === false) {
-                               me.markInvalid(gettext('This VM ID is already in use'));
-                           }
-                       }
-                   });
-               }
-           }
-       });
-
-        me.callParent();
-
-       if (me.loadNextFreeVMID) {
-           PVE.Utils.API2Request({
-               url: '/cluster/nextid',
-               method: 'GET',
-               success: function(response, opts) {
-                   me.setRawValue(response.result.data);
-               }
-           });
-       }
-    }
-});
diff --git a/www/manager5/form/VNCKeyboardSelector.js b/www/manager5/form/VNCKeyboardSelector.js
deleted file mode 100644 (file)
index ffc1911..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-Ext.define('PVE.form.VNCKeyboardSelector', {
-    extend: 'PVE.form.KVComboBox',
-    alias: ['widget.VNCKeyboardSelector'],
-    comboItems: PVE.Utils.kvm_keymap_array()
-});
diff --git a/www/manager5/form/ViewSelector.js b/www/manager5/form/ViewSelector.js
deleted file mode 100644 (file)
index 32181e2..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Top left combobox, used to select a view of the underneath RessourceTree
- */
-Ext.define('PVE.form.ViewSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: ['widget.pveViewSelector'],
-
-    initComponent: function() {
-       var me = this;
-
-       var default_views = {
-           server: {
-               text: gettext('Server View'),
-               groups: ['node']
-           },
-           folder: {
-               text: gettext('Folder View'),
-               groups: ['type']
-           },
-           storage: {
-               text: gettext('Storage View'),
-               groups: ['node'],
-               filterfn: function(node) {
-                   return node.data.type === 'storage' || node.data.type === 'node';
-               }
-           },
-           pool: { 
-               text: gettext('Pool View'), 
-               groups: ['pool'],
-                // Pool View only lists VMs and Containers
-                filterfn: function(node) {
-                    return node.data.type === 'qemu' || node.data.type === 'lxc' || node.data.type === 'openvz' || 
-                       node.data.type === 'pool';
-                }
-           }
-       };
-
-       var groupdef = [];
-       Ext.Object.each(default_views, function(viewname, value) {
-           groupdef.push([viewname, value.text]);
-       });
-
-       var store = Ext.create('Ext.data.Store', {
-           model: 'KeyValue',
-            proxy: {
-               type: 'memory',
-               reader: 'array'
-            },
-           data: groupdef,
-           autoload: true,
-       });
-
-       Ext.apply(me, {
-           hideLabel: true,
-           store: store,
-           value: groupdef[0][0],
-           editable: false,
-           allowBlank: false,
-           forceSelection: true,
-           autoSelect: false,
-           valueField: 'key',
-           displayField: 'value',
-
-           getViewFilter: function() {
-               var view = me.getValue();
-               return Ext.apply({ id: view }, default_views[view] || default_views.server);
-           },
-
-           getState: function() {
-               return { value: me.getValue() };
-           },
-
-           applyState : function(state, doSelect) {
-               var view = me.getValue();
-               if (state && state.value && (view != state.value)) {
-                   var record = store.findRecord('key', state.value);
-                   if (record) {
-                       me.setValue(state.value, true);
-                       if (doSelect) {
-                           me.fireEvent('select', me, [record]);
-                       }
-                   }
-               }
-           },
-           stateEvents: [ 'select' ],
-           stateful: true,
-           id: 'view'
-       });
-
-       me.callParent();
-
-       var statechange = function(sp, key, value) {
-           if (key === me.id) {
-               me.applyState(value, true);
-           }
-       };
-
-       var sp = Ext.state.Manager.getProvider();
-
-       me.mon(sp, 'statechange', statechange, me);
-    }
-});
diff --git a/www/manager5/form/iScsiProviderSelector.js b/www/manager5/form/iScsiProviderSelector.js
deleted file mode 100644 (file)
index 9ea34a1..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-Ext.define('PVE.form.iScsiProviderSelector', {
-    extend: 'PVE.form.KVComboBox',
-    alias: ['widget.pveiScsiProviderSelector'],
-  
-    initComponent: function() {
-       var me = this;
-
-       me.data = [
-           ['comstar', 'Comstar'],
-           [ 'istgt', 'istgt'],
-           [ 'iet', 'IET']
-       ];
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/grid/BackupView.js b/www/manager5/grid/BackupView.js
deleted file mode 100644 (file)
index aba6d2d..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-Ext.define('PVE.grid.BackupView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveBackupView'],
-
-
-    initComponent : function() {
-       var me = this;
-
-       var nodename = me.pveSelNode.data.node;
-       if (!nodename) {
-           throw "no node name specified";
-       }
-
-       var vmid = me.pveSelNode.data.vmid;
-       if (!vmid) {
-           throw "no VM ID specified";
-       }
-
-       var vmtype = me.pveSelNode.data.type;
-       if (!vmtype) {
-           throw "no VM type specified";
-       }
-
-       var filterFn;
-       if (vmtype === 'openvz') {
-           filterFn = function(item) {
-               return item.data.volid.match(':backup/vzdump-openvz-');
-           };
-       } else if (vmtype === 'lxc') {
-           filterFn = function(item) {
-               return item.data.volid.match(':backup/vzdump-lxc-');
-           };
-       } else if (vmtype === 'qemu') {
-           filterFn = function(item) {
-               return item.data.volid.match(':backup/vzdump-qemu-');
-           };
-       } else {
-           throw "unsupported VM type '" + vmtype + "'";
-       }
-
-       me.store = Ext.create('Ext.data.Store', {
-           model: 'pve-storage-content',
-           sorters: { 
-               property: 'volid', 
-               order: 'DESC' 
-           },
-           filters: { filterFn: filterFn }
-       });
-
-       var reload = Ext.Function.createBuffered(function() {
-           if (me.store.proxy.url) {
-               me.store.load();
-           }
-       }, 100);
-
-       var setStorage = function(storage) {
-           var url = '/api2/json/nodes/' + nodename + '/storage/' + storage + '/content';
-           url += '?content=backup';
-
-           me.store.setProxy({
-               type: 'pve',
-               url: url
-           });
-
-           reload();
-       };
-
-       var storagesel = Ext.create('PVE.form.StorageSelector', {
-           nodename: nodename,
-           fieldLabel: gettext('Storage'),
-           labelAlign: 'right',
-           storageContent: 'backup',
-           allowBlank: false,
-           listeners: {
-               change: function(f, value) {
-                   setStorage(value);
-               }
-           }
-       });
-
-       var storagefilter = Ext.create('Ext.form.field.Text', {
-           fieldLabel: gettext('Search'),
-           labelWidth: 50,
-           labelAlign: 'right',
-           enableKeyEvents: true,
-           listeners: {
-               buffer: 500,
-               keyup: function(field) {
-                   me.store.clearFilter(true);
-                   me.store.filter([
-                       {
-                           property: 'volid',
-                           value: field.getValue(),
-                           anyMatch: true,
-                           caseSensitive: false
-                       }
-                   ]);
-               }
-           }
-       });
-
-       var sm = Ext.create('Ext.selection.RowModel', {});
-
-       var backup_btn = Ext.create('Ext.button.Button', {
-           text: gettext('Backup now'),
-           handler: function() {
-               var win = Ext.create('PVE.window.Backup', { 
-                   nodename: nodename,
-                   vmid: vmid,
-                   vmtype: vmtype,
-                   storage: storagesel.getValue()
-               });
-               win.show();
-           }
-       });
-
-       var restore_btn = Ext.create('PVE.button.Button', {
-           text: gettext('Restore'),
-           disabled: true,
-           selModel: sm,
-           enableFn: function(rec) {
-               return !!rec;
-           },
-           handler: function(b, e, rec) {
-               var volid = rec.data.volid;
-
-               var win = Ext.create('PVE.window.Restore', {
-                   nodename: nodename,
-                   vmid: vmid,
-                   volid: rec.data.volid,
-                   volidText: PVE.Utils.render_storage_content(rec.data.volid, {}, rec),
-                   vmtype: vmtype
-               });
-               win.show();
-               win.on('destroy', reload);
-           }
-       });
-
-       var delete_btn = Ext.create('PVE.button.Button', {
-           text: gettext('Remove'),
-           disabled: true,
-           selModel: sm,
-           dangerous: true,        
-           confirmMsg: function(rec) {
-               var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-                                           "'" + rec.data.volid + "'");
-               msg += " " + gettext('This will permanently erase all image data.');
-
-               return msg;
-           },
-           enableFn: function(rec) {
-               return !!rec;
-           },
-           handler: function(b, e, rec){
-               var storage = storagesel.getValue();
-               if (!storage) {
-                   return;
-               }
-
-               var volid = rec.data.volid;
-               PVE.Utils.API2Request({
-                   url: "/nodes/" + nodename + "/storage/" + storage + "/content/" + volid,
-                   method: 'DELETE',
-                   waitMsgTarget: me,
-                   failure: function(response, opts) {
-                       Ext.Msg.alert('Error', response.htmlStatus);
-                   },
-                   success: function(response, options) {
-                       reload();
-                   }
-               });
-           }
-       });
-
-       Ext.apply(me, {
-           stateful: false,
-           selModel: sm,
-           tbar: [ backup_btn, restore_btn, delete_btn, '->', storagesel, storagefilter ],
-           columns: [
-               {
-                   header: gettext('Name'),
-                   flex: 1,
-                   sortable: true,
-                   renderer: PVE.Utils.render_storage_content,
-                   dataIndex: 'volid'
-               },
-               {
-                   header: gettext('Format'),
-                   width: 100,
-                   dataIndex: 'format'
-               },
-               {
-                   header: gettext('Size'),
-                   width: 100,
-                   renderer: PVE.Utils.format_size,
-                   dataIndex: 'size'
-               }
-           ],
-           listeners: {
-               show: reload
-           }
-       });
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/grid/CheckColumn.js b/www/manager5/grid/CheckColumn.js
deleted file mode 100644 (file)
index b57aca7..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-
-// partly copied from extjs/examples/ux/CheckColumn.js
-
-Ext.define('PVE.CheckColumn', {
-    extend: 'Ext.grid.column.Column',
-    alias: 'widget.checkcolumn',
-
-    constructor: function(cfg) {
-       this.renderer = function(value){
-            var cssPrefix = Ext.baseCSSPrefix,
-            cls = [cssPrefix + 'grid-checkheader'];
-
-            if (value) {
-               cls.push(cssPrefix + 'grid-checkheader-checked');
-            }
-            return '<div class="' + cls.join(' ') + '">&#160;</div>';
-       };
-
-       this.addEvents('checkchange');
-
-        this.callParent(arguments);
-    },
-
-    processEvent: function(type, view, cell, recordIndex, cellIndex, e) {
-        if (type == 'mousedown') {
-            var record = view.panel.store.getAt(recordIndex),
-                dataIndex = this.dataIndex,
-                checked = !record.get(dataIndex);
-            record.set(dataIndex, checked);
-            this.fireEvent('checkchange', this, record, checked);
-            return false;
-        } else {
-            return this.callParent(arguments);
-        }
-    }
-
-});
-
diff --git a/www/manager5/grid/FirewallAliases.js b/www/manager5/grid/FirewallAliases.js
deleted file mode 100644 (file)
index 353b97c..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-Ext.define('PVE.FirewallAliasEdit', {
-    extend: 'PVE.window.Edit',
-
-    base_url: undefined,
-    
-    alias_name: undefined,
-
-    initComponent : function() {
-       /*jslint confusion: true */
-       var me = this;
-
-       me.create = (me.alias_name === undefined);
-
-       if (me.create) {
-            me.url = '/api2/extjs' + me.base_url;
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs' + me.base_url + '/' + me.alias_name;
-            me.method = 'PUT';
-        }
-
-       var items =  [
-           {
-               xtype: 'textfield',
-               name: me.create ? 'name' : 'rename',
-               fieldLabel: gettext('Name'),
-               allowBlank: false
-           },
-           {
-               xtype: 'textfield',
-               name: 'cidr',
-               fieldLabel: gettext('IP/CIDR'),
-               allowBlank: false
-           },
-           {
-               xtype: 'textfield',
-               name: 'comment',
-               fieldLabel: gettext('Comment')
-           }
-       ];
-
-       var ipanel = Ext.create('PVE.panel.InputPanel', {
-           create: me.create,
-           items: items
-       });
-
-       Ext.apply(me, {
-            subject: gettext('Alias'),
-           isAdd: true,
-           items: [ ipanel ]
-       });
-
-       me.callParent();
-
-       if (!me.create) {
-           me.load({
-               success:  function(response, options) {
-                   var values = response.result.data;
-                   values.rename = values.name;
-                   ipanel.setValues(values);
-               }
-           });
-       }
-    }
-});
-
-Ext.define('PVE.FirewallAliases', {
-    extend: 'Ext.grid.Panel',
-    alias: ['widget.pveFirewallAliases'],
-
-    base_url: undefined,
-
-    title: gettext('Alias'),
-
-    initComponent : function() {
-       /*jslint confusion: true */
-
-       var me = this;
-
-       if (!me.base_url) {
-           throw "missing base_url configuration";
-       }
-
-       var store = new Ext.data.Store({
-           fields: [ 'name', 'cidr', 'comment', 'digest' ],
-           proxy: {
-               type: 'pve',
-               url: "/api2/json" + me.base_url
-           },
-           idProperty: 'name',
-           sorters: {
-               property: 'name',
-               order: 'DESC'
-           }
-       });
-
-       var sm = Ext.create('Ext.selection.RowModel', {});
-
-       var reload = function() {
-           var oldrec = sm.getSelection()[0];
-           store.load(function(records, operation, success) {
-               if (oldrec) {
-                   var rec = store.findRecord('name', oldrec.data.name);
-                   if (rec) {
-                       sm.select(rec);
-                   }
-               }
-           });
-       };
-
-       var run_editor = function() {
-           var sm = me.getSelectionModel();
-           var rec = sm.getSelection()[0];
-           if (!rec) {
-               return;
-           }
-
-           var win = Ext.create('PVE.FirewallAliasEdit', {
-               base_url: me.base_url,
-               alias_name: rec.data.name
-           });
-
-           win.show();
-           win.on('destroy', reload);
-       };
-
-       me.editBtn = new PVE.button.Button({
-           text: gettext('Edit'),
-           disabled: true,
-           selModel: sm,
-           handler: run_editor
-       });
-
-       me.addBtn =  Ext.create('Ext.Button', {
-           text: gettext('Add'),
-           handler: function() {
-               var win = Ext.create('PVE.FirewallAliasEdit', {
-                   base_url: me.base_url
-               });
-               win.on('destroy', reload);
-               win.show();
-           }
-       });
-
-       me.removeBtn = new PVE.button.Button({
-           text: gettext('Remove'),
-           selModel: sm,
-           disabled: true,
-           handler: function() {
-               var rec = sm.getSelection()[0];
-               if (!rec) {
-                   return;
-               }
-               PVE.Utils.API2Request({
-                   url: me.base_url + '/' + rec.data.name,
-                   method: 'DELETE',
-                   waitMsgTarget: me,
-                   failure: function(response, options) {
-                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-                   },
-                   callback: reload
-               });
-           }
-       });
-
-
-       Ext.applyIf(me, {
-           store: store,
-           tbar: [ me.addBtn, me.removeBtn, me.editBtn ],
-           selModel: sm,
-           columns: [
-               { header: gettext('Name'), dataIndex: 'name', width: 100 },
-               { header:  gettext('IP/CIDR'), dataIndex: 'cidr', width: 100 },
-               { header: gettext('Comment'), dataIndex: 'comment', flex: 1 }
-           ],
-           listeners: {
-               itemdblclick: run_editor
-           }
-       });
-
-       me.callParent();
-
-       me.on('show', reload);
-    }
-});
diff --git a/www/manager5/grid/FirewallOptions.js b/www/manager5/grid/FirewallOptions.js
deleted file mode 100644 (file)
index f94be6c..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-Ext.define('PVE.FirewallOptions', {
-    extend: 'PVE.grid.ObjectGrid',
-    alias: ['widget.pveFirewallOptions'],
-
-    fwtype: undefined, // 'dc', 'node' or 'vm'
-
-    base_url: undefined,
-
-    initComponent : function() {
-       /*jslint confusion: true */
-
-       var me = this;
-
-       if (!me.base_url) {
-           throw "missing base_url configuration";
-       }
-
-       if (me.fwtype === 'dc' || me.fwtype === 'node' || me.fwtype === 'vm') {
-           if (me.fwtype === 'node') {
-               me.cwidth1 = 250;
-           }
-       } else {
-           throw "unknown firewall option type";
-       }
-
-       var rows = {};
-
-       var add_boolean_row = function(name, text, defaultValue, labelWidth) {
-           rows[name] = {
-               header: text,
-               required: true,
-               defaultValue: defaultValue || 0,
-               renderer: PVE.Utils.format_boolean,
-               editor: {
-                   xtype: 'pveWindowEdit',
-                   subject: text,
-                   fieldDefaults: { labelWidth: labelWidth || 100 },
-                   items: {
-                       xtype: 'pvecheckbox',
-                       defaultValue: defaultValue || 0,
-                       checked: defaultValue ? true : false,
-                       name: name,
-                       uncheckedValue: 0,
-                       fieldLabel: text
-                   }
-               }
-           };
-       };
-
-       var add_integer_row = function(name, text, labelWidth, minValue) {
-           rows[name] = {
-               header: text,
-               required: true,
-               renderer: function(value) {
-                   return value || PVE.Utils.defaultText;
-               },
-               editor: {
-                   xtype: 'pveWindowEdit',
-                   subject: text,
-                   fieldDefaults: { labelWidth: labelWidth || 100 },
-                   items: {
-                       xtype: 'numberfield',
-                       name: name,
-                       minValue: minValue,
-                       decimalPrecision: 0,
-                       fieldLabel: text,
-                       emptyText: gettext('Default'),
-                       getSubmitData: function() {
-                           var me = this;
-                           var val = me.getSubmitValue();
-                           if (val !== null && val !== '') {
-                               var data = {};
-                               data[name] = val;
-                               return data;
-                           } else {
-                               return { 'delete' : name };
-                           }
-                       }
-                   }
-               }
-           };
-       };
-
-       var add_log_row = function(name, labelWidth) {
-           rows[name] = {
-               header: name,
-               required: true,
-               defaultValue: 'nolog',
-               editor: {
-                   xtype: 'pveWindowEdit',
-                   subject: name,
-                   fieldDefaults: { labelWidth: labelWidth || 100 },
-                   items: {
-                       xtype: 'pveKVComboBox',
-                       name: name,
-                       fieldLabel: name,
-                       data: [['nolog', 'nolog'], ['info', 'info'], ['err', 'err'],
-                              ['warning', 'warning'], ['crit', 'crit'], ['alert', 'alert'],
-                              ['emerg', 'emerg'], ['debug', 'debug']]
-                   }
-               }
-           };
-       };
-
-
-       if (me.fwtype === 'node') {
-           add_boolean_row('enable', gettext('Enable Firewall'), 1);
-           add_boolean_row('nosmurfs', gettext('SMURFS filter'), 1);
-           add_boolean_row('tcpflags', gettext('TCP flags filter'), 0);
-           add_integer_row('nf_conntrack_max', 'nf_conntrack_max', 120, 32768);
-           add_integer_row('nf_conntrack_tcp_timeout_established', 
-                           'nf_conntrack_tcp_timeout_established', 250, 7875);
-           add_log_row('log_level_in');
-           add_log_row('log_level_out');
-           add_log_row('tcp_flags_log_level', 120);
-           add_log_row('smurf_log_level');
-       } else if (me.fwtype === 'vm') {
-           add_boolean_row('enable', gettext('Enable Firewall'), 0);
-           add_boolean_row('dhcp', gettext('Enable DHCP'), 0);
-           add_boolean_row('macfilter', gettext('MAC filter'), 1);
-           add_log_row('log_level_in');
-           add_log_row('log_level_out');
-       } else if (me.fwtype === 'dc') {
-           add_boolean_row('enable', gettext('Enable Firewall'), 0);
-       } 
-       if (me.fwtype === 'dc' || me.fwtype === 'vm') {
-           rows.policy_in = {
-               header: gettext('Input Policy'),
-               required: true,
-               defaultValue: 'DROP',
-               editor: {
-                   xtype: 'pveWindowEdit',
-                   subject: gettext('Input Policy'),
-                   items: {
-                       xtype: 'pveFirewallPolicySelector',
-                       name: 'policy_in',
-                       value: 'DROP',
-                       fieldLabel: gettext('Input Policy')
-                   }
-               }
-           };
-
-           rows.policy_out = {
-               header: gettext('Output Policy'),
-               required: true,
-               defaultValue: 'ACCEPT',
-               editor: {
-                   xtype: 'pveWindowEdit',
-                   subject: gettext('Output Policy'),
-                   items: {
-                       xtype: 'pveFirewallPolicySelector',
-                       name: 'policy_out',
-                       value: 'ACCEPT',
-                       fieldLabel: gettext('Output Policy')
-                   }
-               }
-           };
-       }
-
-       var reload = function() {
-           me.rstore.load();
-       };
-
-       var run_editor = function() {
-           var sm = me.getSelectionModel();
-           var rec = sm.getSelection()[0];
-           if (!rec) {
-               return;
-           }
-
-           var rowdef = rows[rec.data.key];
-           if (!rowdef.editor) {
-               return;
-           }
-
-           var win;
-           if (Ext.isString(rowdef.editor)) {
-               win = Ext.create(rowdef.editor, {
-                   pveSelNode: me.pveSelNode,
-                   confid: rec.data.key,
-                   url: '/api2/extjs' + me.base_url
-               });
-           } else {
-               var config = Ext.apply({
-                   pveSelNode: me.pveSelNode,
-                   confid: rec.data.key,
-                   url: '/api2/extjs' + me.base_url
-               }, rowdef.editor);
-               win = Ext.createWidget(rowdef.editor.xtype, config);
-               win.load();
-           }
-
-           win.show();
-           win.on('destroy', reload);
-       };
-
-       var edit_btn = new Ext.Button({
-           text: gettext('Edit'),
-           disabled: true,
-           handler: run_editor
-       });
-
-       var set_button_status = function() {
-           var sm = me.getSelectionModel();
-           var rec = sm.getSelection()[0];
-
-           if (!rec) {
-               edit_btn.disable();
-               return;
-           }
-           var rowdef = rows[rec.data.key];
-           edit_btn.setDisabled(!rowdef.editor);
-       };
-
-       Ext.applyIf(me, {
-           url: "/api2/json" + me.base_url,
-           cwidth1: 150,
-           tbar: [ edit_btn ],
-           rows: rows,
-           listeners: {
-               itemdblclick: run_editor,
-               selectionchange: set_button_status
-           }
-       });
-
-       me.callParent();
-
-       me.on('show', reload);
-    }
-});
diff --git a/www/manager5/grid/FirewallRules.js b/www/manager5/grid/FirewallRules.js
deleted file mode 100644 (file)
index ae53637..0000000
+++ /dev/null
@@ -1,776 +0,0 @@
-Ext.define('PVE.form.FWMacroSelector', {
-    extend: 'PVE.form.ComboGrid',
-    alias: 'widget.pveFWMacroSelector',
-
-    initComponent: function() {
-       var me = this;
-
-       var store = Ext.create('Ext.data.Store', {
-           autoLoad: true,
-           fields: [ 'macro', 'descr' ],
-           idProperty: 'macro',
-           proxy: {
-               type: 'pve',
-               url: "/api2/json/cluster/firewall/macros"
-           },
-           sorters: {
-               property: 'macro',
-               order: 'DESC'
-           }
-       });
-
-       Ext.apply(me, {
-           store: store,
-           allowBlank: true,
-           autoSelect: false,
-           valueField: 'macro',
-           displayField: 'macro',
-            listConfig: {
-               columns: [
-                   {
-                       header: gettext('Macro'),
-                       dataIndex: 'macro',
-                       hideable: false,
-                       width: 100
-                   },
-                   {
-                       header: gettext('Description'),
-                       flex: 1,
-                       dataIndex: 'descr'
-                   }
-               ]
-           }
-       });
-
-       me.callParent();
-    }
-});
-
-Ext.define('PVE.FirewallRulePanel', {
-    extend: 'PVE.panel.InputPanel',
-
-    allow_iface: false,
-
-    list_refs_url: undefined,
-
-    onGetValues: function(values) {
-       var me = this;
-
-       // hack: editable ComboGrid returns nothing when empty, so we need to set ''
-       // Also, disabled text fields return nothing, so we need to set ''
-
-       Ext.Array.each(['source', 'dest', 'proto', 'sport', 'dport'], function(key) {
-           if (values[key] === undefined) {
-               values[key] = '';
-           }
-       });
-
-       delete values.modified_marker;
-       return values;
-    },
-
-    initComponent : function() {
-       var me = this;
-
-       if (!me.list_refs_url) {
-           throw "no list_refs_url specified";
-       }
-
-       me.column1 = [
-           {
-               // hack: we use this field to mark the form 'dirty' when the
-               // record has errors- so that the user can safe the unmodified 
-               // form again.
-               xtype: 'hiddenfield',
-               name: 'modified_marker',
-               value: '',
-           },
-           {
-               xtype: 'pveKVComboBox',
-               name: 'type',
-               value: 'in',
-               data: [['in', 'in'], ['out', 'out']],
-               fieldLabel: gettext('Direction'),
-               allowBlank: false
-           },
-           {
-               xtype: 'pveKVComboBox',
-               name: 'action',
-               value: 'ACCEPT',
-               data: [['ACCEPT', 'ACCEPT'], ['DROP', 'DROP'], ['REJECT', 'REJECT']],
-               fieldLabel: gettext('Action'),
-               allowBlank: false
-           }
-        ];
-
-       if (me.allow_iface) {
-           me.column1.push({
-               xtype: 'pvetextfield',
-               name: 'iface',
-               deleteEmpty: !me.create,
-               value: '',
-               fieldLabel: gettext('Interface')
-           });
-       } else {
-           me.column1.push({
-               xtype: 'displayfield',
-               fieldLabel: '',
-               height: 22, // hack: set same height as text fields
-               value: ''
-           });
-       }
-
-       me.column1.push([
-           {
-               xtype: 'displayfield',
-               fieldLabel: '',
-               height: 7,
-               value: ''
-           },
-           {
-               xtype: 'pveIPRefSelector',
-               name: 'source',
-               autoSelect: false,
-               editable: true,
-               base_url: me.list_refs_url,
-               value: '',
-               fieldLabel: gettext('Source')
-
-           },
-           {
-               xtype: 'pveIPRefSelector',
-               name: 'dest',
-               autoSelect: false,
-               editable: true,
-               base_url: me.list_refs_url,
-               value: '',
-               fieldLabel: gettext('Destination')
-           }
-       ]);
-
-       
-       me.column2 = [
-           {
-               xtype: 'pvecheckbox',
-               name: 'enable',
-               checked: false,
-               height: 22, // hack: set same height as text fields
-               uncheckedValue: 0,
-               fieldLabel: gettext('Enable')
-           },
-           {
-               xtype: 'pveFWMacroSelector',
-               name: 'macro',
-               value: '',
-               fieldLabel: gettext('Macro'),
-               allowBlank: true,
-               listeners: {
-                   change: function(f, value) {
-                        if (value === '') {
-                           me.down('field[name=proto]').setDisabled(false);
-                           me.down('field[name=sport]').setDisabled(false);
-                           me.down('field[name=dport]').setDisabled(false);
-                        } else {
-                           me.down('field[name=proto]').setDisabled(true);
-                           me.down('field[name=proto]').setValue('');
-                           me.down('field[name=sport]').setDisabled(true);
-                           me.down('field[name=sport]').setValue('');
-                           me.down('field[name=dport]').setDisabled(true);
-                           me.down('field[name=dport]').setValue('');
-                       }
-                    }
-                }
-           },
-           {
-               xtype: 'pveIPProtocolSelector',
-               name: 'proto',
-               autoSelect: false,
-               editable: true,
-               value: '',
-               fieldLabel: gettext('Protocol')
-           },
-           {
-               xtype: 'displayfield',
-               fieldLabel: '',
-               height: 7,
-               value: ''
-           },
-           {
-               xtype: 'textfield',
-               name: 'sport',
-               value: '',
-               fieldLabel: gettext('Source port')
-           },
-           {
-               xtype: 'textfield',
-               name: 'dport',
-               height: 22, // hack: set same height as text fields
-               value: '',
-               fieldLabel: gettext('Dest. port')
-           }
-       ];
-       
-       me.columnB = [
-           {
-               xtype: 'textfield',
-               name: 'comment',
-               value: '',
-               fieldLabel: gettext('Comment')
-           }
-       ];
-
-       me.callParent();
-    }
-});
-
-Ext.define('PVE.FirewallRuleEdit', {
-    extend: 'PVE.window.Edit',
-
-    base_url: undefined,
-    list_refs_url: undefined,
-
-    allow_iface: false,
-
-    initComponent : function() {
-       /*jslint confusion: true */
-       var me = this;
-
-       if (!me.base_url) {
-           throw "no base_url specified";
-       }
-       if (!me.list_refs_url) {
-           throw "no list_refs_url specified";
-       }
-
-       me.create = (me.rule_pos === undefined);
-
-       if (me.create) {
-            me.url = '/api2/extjs' + me.base_url;
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs' + me.base_url + '/' + me.rule_pos.toString();
-            me.method = 'PUT';
-        }
-
-       var ipanel = Ext.create('PVE.FirewallRulePanel', {
-           create: me.create,
-           list_refs_url: me.list_refs_url,
-           allow_iface: me.allow_iface,
-           rule_pos: me.rule_pos
-       });
-
-       Ext.apply(me, {
-            subject: gettext('Rule'),
-           isAdd: true,
-           items: [ ipanel ]
-       });
-
-       me.callParent();
-
-       if (!me.create) {
-           me.load({
-               success: function(response, options) {
-                   var values = response.result.data;
-                   ipanel.setValues(values);
-                   if (values.errors) {
-                       var field = me.query('[isFormField][name=modified_marker]')[0];
-                       field.setValue(1);
-                       Ext.Function.defer(function() {
-                           var form = ipanel.up('form').getForm();
-                           form.markInvalid(values.errors)
-                       }, 100);
-                   }
-               }
-           });
-       }
-    }
-});
-
-Ext.define('PVE.FirewallGroupRuleEdit', {
-    extend: 'PVE.window.Edit',
-
-    base_url: undefined,
-
-    allow_iface: false,
-
-    initComponent : function() {
-       /*jslint confusion: true */
-       var me = this;
-
-       me.create = (me.rule_pos === undefined);
-
-       if (me.create) {
-            me.url = '/api2/extjs' + me.base_url;
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs' + me.base_url + '/' + me.rule_pos.toString();
-            me.method = 'PUT';
-        }
-
-       var column1 = [
-           {
-               xtype: 'hiddenfield',
-               name: 'type',
-               value: 'group'
-           },
-           {
-               xtype: 'pveSecurityGroupsSelector',
-               name: 'action',
-               value: '',
-               fieldLabel: gettext('Security Group'),
-               allowBlank: false
-           }
-       ];
-
-       if (me.allow_iface) {
-           column1.push({
-               xtype: 'pvetextfield',
-               name: 'iface',
-               deleteEmpty: !me.create,
-               value: '',
-               fieldLabel: gettext('Interface')
-           });
-       }
-
-       var ipanel = Ext.create('PVE.panel.InputPanel', {
-           create: me.create,
-           column1: column1,
-           column2: [
-               {
-                   xtype: 'pvecheckbox',
-                   name: 'enable',
-                   checked: false,
-                   height: 22, // hack: set same height as text fields
-                   uncheckedValue: 0,
-                   fieldLabel: gettext('Enable')
-               }
-           ],
-           columnB: [
-               {
-                   xtype: 'textfield',
-                   name: 'comment',
-                   value: '',
-                   fieldLabel: gettext('Comment')
-               }
-           ]
-       });
-
-       Ext.apply(me, {
-            subject: gettext('Rule'),
-           isAdd: true,
-           items: [ ipanel ]
-       });
-
-       me.callParent();
-
-       if (!me.create) {
-           me.load({
-               success:  function(response, options) {
-                   var values = response.result.data;
-                   ipanel.setValues(values);
-               }
-           });
-       }
-    }
-});
-
-Ext.define('PVE.FirewallRules', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveFirewallRules',
-
-    base_url: undefined,
-    list_refs_url: undefined,
-
-    addBtn: undefined,
-    removeBtn: undefined,
-    editBtn: undefined,
-    groupBtn: undefined,
-
-    tbar_prefix: undefined,
-
-    allow_groups: true,
-    allow_iface: false,
-
-    setBaseUrl: function(url) {
-        var me = this;
-
-       me.base_url = url;
-
-       if (url === undefined) {
-           me.addBtn.setDisabled(true);
-           if (me.groupBtn) {
-               me.groupBtn.setDisabled(true);
-           }
-           me.store.removeAll();
-       } else {
-           me.addBtn.setDisabled(false);
-           if (me.groupBtn) {
-               me.groupBtn.setDisabled(false);
-           }
-           me.store.setProxy({
-               type: 'pve',
-               url: '/api2/json' + url
-           });
-
-           me.store.load();
-       }
-    },
-
-    moveRule: function(from, to) {
-        var me = this;
-
-       if (!me.base_url) { 
-           return;
-       }
-
-       PVE.Utils.API2Request({
-           url: me.base_url + "/" + from,
-           method: 'PUT',
-           params: { moveto: to },
-           waitMsgTarget: me,
-           failure: function(response, options) {
-               Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-           },
-           callback: function() {
-               me.store.load();
-           }
-       });
-    },
-
-    updateRule: function(rule) {
-        var me = this;
-
-       if (!me.base_url) { 
-           return;
-       }
-
-       rule.enable = rule.enable ? 1 : 0;
-
-       var pos = rule.pos;
-       delete rule.pos;
-       delete rule.errors;
-
-       PVE.Utils.API2Request({
-           url: me.base_url + '/' + pos.toString(),
-           method: 'PUT',
-           params: rule,
-           waitMsgTarget: me,
-           failure: function(response, options) {
-               Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-           },
-           callback: function() {
-               me.store.load();
-           }
-       });
-    },
-
-    deleteRule: function(rule) {
-        var me = this;
-
-       if (!me.base_url) {
-           return;
-       }
-
-       PVE.Utils.API2Request({
-           url: me.base_url + '/' + rule.pos.toString() +
-               '?digest=' + encodeURIComponent(rule.digest),
-           method: 'DELETE',
-           waitMsgTarget: me,
-           failure: function(response, options) {
-               Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-           },
-           callback: function() {
-               me.store.load();
-           }
-       });
-    },
-
-    initComponent: function() {
-       /*jslint confusion: true */
-        var me = this;
-
-       if (!me.list_refs_url) {
-           throw "no list_refs_url specified";
-       }
-
-       var store = new Ext.data.Store({
-           model: 'pve-fw-rule'
-       });
-
-       var reload = function() {
-           store.load();
-       };
-
-       var sm = Ext.create('Ext.selection.RowModel', {});
-
-       var run_editor = function() {
-           var rec = sm.getSelection()[0];
-           if (!rec) {
-               return;
-           }
-           var type = rec.data.type;
-
-           var editor;
-           if (type === 'in' || type === 'out') {
-               editor = 'PVE.FirewallRuleEdit';
-           } else if (type === 'group') {
-               editor = 'PVE.FirewallGroupRuleEdit';
-           } else {
-               return;
-           }
-
-           var win = Ext.create(editor, {
-               digest: rec.data.digest,
-               allow_iface: me.allow_iface,
-               base_url: me.base_url,
-               list_refs_url: me.list_refs_url,
-               rule_pos: rec.data.pos
-           });
-
-           win.show();
-           win.on('destroy', reload);
-       };
-
-       me.editBtn = new PVE.button.Button({
-           text: gettext('Edit'),
-           disabled: true,
-           selModel: sm,
-           handler: run_editor
-       });
-
-       me.addBtn =  Ext.create('Ext.Button', {
-           text: gettext('Add'),
-           disabled: true,
-           handler: function() {
-               var win = Ext.create('PVE.FirewallRuleEdit', {
-                   allow_iface: me.allow_iface,
-                   base_url: me.base_url,
-                   list_refs_url: me.list_refs_url
-               });
-               win.on('destroy', reload);
-               win.show();
-           }
-       });
-
-       if (me.allow_groups) {
-           me.groupBtn =  Ext.create('Ext.Button', {
-               text: gettext('Insert') + ': ' + 
-                   gettext('Security Group'),
-               disabled: true,
-               handler: function() {
-                   var win = Ext.create('PVE.FirewallGroupRuleEdit', {
-                       allow_iface: me.allow_iface,
-                       base_url: me.base_url
-                   });
-                   win.on('destroy', reload);
-                   win.show();
-               }
-           });
-       }
-
-       me.removeBtn = new PVE.button.Button({
-           text: gettext('Remove'),
-           selModel: sm,
-           disabled: true,
-           handler: function() {
-               var rec = sm.getSelection()[0];
-               if (!rec) {
-                   return;
-               }
-               me.deleteRule(rec.data);
-           }
-       });
-
-       var tbar = me.tbar_prefix ? [ me.tbar_prefix ] : [];
-       tbar.push(me.addBtn);
-       if (me.groupBtn) {
-           tbar.push(me.groupBtn);
-       }
-       tbar.push([ me.removeBtn, me.editBtn ]);
-
-       var render_errors = function(name, value, metaData, record) {
-           var errors = record.data.errors;
-           if (errors && errors[name]) {
-               metaData.tdCls = 'x-form-invalid-field';
-               var html = '<p>' +  Ext.htmlEncode(errors[name]) + '</p>';
-               metaData.tdAttr = 'data-qwidth=600 data-qtitle="ERROR" data-qtip="' + 
-                   html.replace(/\"/g,'&quot;') + '"';
-           }
-           return value;
-       };
-
-       var columns = [
-           {
-               // similar to xtype: 'rownumberer',
-               dataIndex: 'pos',
-               resizable: false,
-               width: 23,
-               sortable: false,
-               align: 'right',
-               hideable: false,
-               menuDisabled: true,
-               renderer: function(value, metaData, record, rowIdx, colIdx, store) {
-                   metaData.tdCls = Ext.baseCSSPrefix + 'grid-cell-special';
-                   if (value >= 0) {
-                       return value;
-                   }
-                   return '';
-               }
-           },
-           {
-               xtype: 'checkcolumn',
-               header: gettext('Enable'),
-               dataIndex: 'enable',
-               listeners: {
-                   checkchange: function(column, record, checked) {
-                       record.commit();
-                       var data = {};
-                       record.fields.each(function(field) {
-                           data[field.name] = record.get(field.name);
-                       });
-                       if (!me.allow_iface || !data.iface) {
-                           delete data.iface;
-                       }
-                       me.updateRule(data);
-                   }
-               },
-               width: 50
-           },
-           {
-               header: gettext('Type'),
-               dataIndex: 'type',
-               renderer: function(value, metaData, record) {
-                   return render_errors('type', value, metaData, record);
-               },
-               width: 50
-           },
-           {
-               header: gettext('Action'),
-               dataIndex: 'action',
-               renderer: function(value, metaData, record) {
-                   return render_errors('action', value, metaData, record);
-               },
-               width: 80
-           },
-           {
-               header: gettext('Macro'),
-               dataIndex: 'macro',
-               renderer: function(value, metaData, record) {
-                   return render_errors('macro', value, metaData, record);
-               },
-               width: 80
-           }
-       ];
-
-       if (me.allow_iface) {
-           columns.push({
-               header: gettext('Interface'),
-               dataIndex: 'iface',
-               renderer: function(value, metaData, record) {
-                   return render_errors('iface', value, metaData, record);
-               },
-               width: 80
-           });
-       }
-
-       columns.push([
-           {
-               header: gettext('Source'),
-               dataIndex: 'source',
-               renderer: function(value, metaData, record) {
-                   return render_errors('source', value, metaData, record);
-               },
-               width: 100
-           },
-           {
-               header: gettext('Destination'),
-               dataIndex: 'dest',
-               renderer: function(value, metaData, record) {
-                   return render_errors('dest', value, metaData, record);
-               },
-               width: 100
-           },
-           {
-               header: gettext('Protocol'),
-               dataIndex: 'proto',
-               renderer: function(value, metaData, record) {
-                   return render_errors('proto', value, metaData, record);
-               },
-               width: 100
-           },
-           {
-               header: gettext('Dest. port'),
-               dataIndex: 'dport',
-               renderer: function(value, metaData, record) {
-                   return render_errors('dport', value, metaData, record);
-               },
-               width: 100
-           },
-           {
-               header: gettext('Source port'),
-               dataIndex: 'sport',
-               renderer: function(value, metaData, record) {
-                   return render_errors('sport', value, metaData, record);
-               },
-               width: 100
-           },
-           {
-               header: gettext('Comment'),
-               dataIndex: 'comment',
-               flex: 1,
-               renderer: function(value, metaData, record) {
-                   return render_errors('comment', Ext.util.Format.htmlEncode(value), metaData, record);
-               }
-           }
-       ]);
-
-       Ext.apply(me, {
-           store: store,
-           selModel: sm,
-           tbar: tbar,
-            viewConfig: {
-               plugins: [
-                   {
-                       ptype: 'gridviewdragdrop',
-                       dragGroup: 'FWRuleDDGroup',
-                       dropGroup: 'FWRuleDDGroup'
-                   }
-               ],
-               listeners: {
-                    beforedrop: function(node, data, dropRec, dropPosition) {
-                       if (!dropRec) {
-                           return false; // empty view
-                       }
-                       var moveto = dropRec.get('pos');
-                       if (dropPosition === 'after') {
-                           moveto++;
-                       }
-                       var pos = data.records[0].get('pos');
-                       me.moveRule(pos, moveto);
-                       return 0;
-                    },
-                   itemdblclick: run_editor
-               }
-           },
-           sortableColumns: false,
-           columns: columns
-       });
-
-       me.callParent();
-
-       if (me.base_url) {
-           me.setBaseUrl(me.base_url); // load
-       }
-    }
-}, function() {
-
-    Ext.define('pve-fw-rule', {
-       extend: 'Ext.data.Model',
-       fields: [ { name: 'enable', type: 'boolean' },
-                 'type', 'action', 'macro', 'source', 'dest', 'proto', 'iface',
-                 'dport', 'sport', 'comment', 'pos', 'digest', 'errors' ],
-       idProperty: 'pos'
-    });
-
-});
diff --git a/www/manager5/grid/ObjectGrid.js b/www/manager5/grid/ObjectGrid.js
deleted file mode 100644 (file)
index cd135a1..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-Ext.define('PVE.grid.ObjectGrid', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveObjectGrid'],
-
-    getObjectValue: function(key, defaultValue) {
-       var me = this;
-       var rec = me.store.getById(key);
-       if (rec) {
-           return rec.data.value;
-       }
-       return defaultValue;
-    },
-
-    renderKey: function(key, metaData, record, rowIndex, colIndex, store) {
-       var me = this;
-       var rows = me.rows;
-       var rowdef = (rows && rows[key]) ?  rows[key] : {};
-       return rowdef.header || key;
-    },
-
-    renderValue: function(value, metaData, record, rowIndex, colIndex, store) {
-       var me = this;
-       var rows = me.rows;
-       var key = record.data.key;
-       var rowdef = (rows && rows[key]) ?  rows[key] : {};
-
-       var renderer = rowdef.renderer;
-       if (renderer) {
-           return renderer(value, metaData, record, rowIndex, colIndex, store);
-       }
-
-       return value;
-    },
-
-    initComponent : function() {
-       var me = this;
-
-       var rows = me.rows;
-
-       if (!me.rstore) {
-           if (!me.url) {
-               throw "no url specified";
-           }
-
-           me.rstore = Ext.create('PVE.data.ObjectStore', {
-               url: me.url,
-               interval: me.interval,
-               extraParams: me.extraParams,
-               rows: me.rows
-           });
-       }
-
-       var rstore = me.rstore;
-
-       var store = Ext.create('PVE.data.DiffStore', { rstore: rstore });
-
-       if (rows) {
-           Ext.Object.each(rows, function(key, rowdef) {
-               if (Ext.isDefined(rowdef.defaultValue)) {
-                   store.add({ key: key, value: rowdef.defaultValue });
-               } else if (rowdef.required) {
-                   store.add({ key: key, value: undefined });
-               }
-           });
-       }
-
-       if (me.sorterFn) {
-           store.sorters.add(new Ext.util.Sorter({
-               sorterFn: me.sorterFn
-           }));
-       }
-
-       store.filters.add(new Ext.util.Filter({
-           filterFn: function(item) {
-               if (rows) {
-                   var rowdef = rows[item.data.key];
-                   if (!rowdef || (rowdef.visible === false)) {
-                       return false;
-                   }
-               }
-               return true;
-           }
-       }));
-
-       PVE.Utils.monStoreErrors(me, rstore);
-
-       Ext.applyIf(me, {
-           store: store,
-           hideHeaders: true,
-           stateful: false,
-           columns: [
-               {
-                   header: gettext('Name'),
-                   width: me.cwidth1 || 100,
-                   dataIndex: 'key',
-                   renderer: me.renderKey
-               },
-               {
-                   flex: 1,
-                   header: gettext('Value'),
-                   dataIndex: 'value',
-                   renderer: me.renderValue
-               }
-           ]
-       });
-
-       me.callParent();
-   }
-});
diff --git a/www/manager5/grid/PendingObjectGrid.js b/www/manager5/grid/PendingObjectGrid.js
deleted file mode 100644 (file)
index 051951a..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-Ext.define('PVE.grid.PendingObjectGrid', {
-    extend: 'PVE.grid.ObjectGrid',
-    alias: ['widget.pvePendingObjectGrid'],
-
-    getObjectValue: function(key, defaultValue, pending) {
-       var me = this;
-       var rec = me.store.getById(key);
-       if (rec) {
-           var value = (pending && Ext.isDefined(rec.data.pending) && (rec.data.pending !== '')) ? 
-               rec.data.pending : rec.data.value;
-
-            if (Ext.isDefined(value) && (value !== '')) {
-               return value;
-            } else {
-               return defaultValue;
-            }
-       }
-       return defaultValue;
-    },
-
-    hasPendingChanges: function(key) {
-       var me = this;
-       var rows = me.rows;
-       var rowdef = (rows && rows[key]) ?  rows[key] : {};
-       var keys = rowdef.multiKey ||  [ key ];
-       var pending = false;
-
-       Ext.Array.each(keys, function(k) {
-           var rec = me.store.getById(k);
-           if (rec && rec.data && Ext.isDefined(rec.data.pending) && (rec.data.pending !== '')) {
-               pending = true;
-           }
-       });
-
-       return pending;
-    },
-
-    renderValue: function(value, metaData, record, rowIndex, colIndex, store) {
-       var me = this;
-       var rows = me.rows;
-       var key = record.data.key;
-       var rowdef = (rows && rows[key]) ?  rows[key] : {};
-       var renderer = rowdef.renderer;
-       var current = '';
-       var pendingdelete = '';
-       var pending = '';
-
-       if (renderer) {
-           current = renderer(value, metaData, record, rowIndex, colIndex, store, false);
-           if (me.hasPendingChanges(key)) {
-               pending = renderer(record.data.pending, metaData, record, rowIndex, colIndex, store, true);
-           }
-           if (pending == current) {
-               pending = undefined;
-           }
-       } else {
-           current = value;
-           pending = record.data.pending;
-       }
-
-       if (record.data['delete']) {
-           pendingdelete = '<div style="text-decoration: line-through;">'+ current +'</div>';
-       }
-
-       if (pending || pendingdelete) {
-           return current + '<div style="color:red">' + pending + pendingdelete + '</div>';
-       } else {
-           return current;
-       }
-    },
-
-    initComponent : function() {
-       var me = this;
-
-       var rows = me.rows;
-
-       if (!me.rstore) {
-           if (!me.url) {
-               throw "no url specified";
-           }
-
-           me.rstore = Ext.create('PVE.data.ObjectStore', {
-               model: 'KeyValuePendingDelete',
-               readArray: true,
-               url: me.url,
-               interval: me.interval,
-               extraParams: me.extraParams,
-               rows: me.rows
-           });
-       }
-
-       me.callParent();
-   }
-});
diff --git a/www/manager5/grid/PoolMembers.js b/www/manager5/grid/PoolMembers.js
deleted file mode 100644 (file)
index 932f475..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-Ext.define('PVE.pool.AddVM', {
-    extend: 'PVE.window.Edit',
-
-    initComponent : function() {
-       /*jslint confusion: true */
-       var me = this;
-
-       if (!me.pool) {
-           throw "no pool specified";
-       }
-
-       me.create = true;
-       me.isAdd = true;
-       me.url = "/pools/" + me.pool;
-       me.method = 'PUT';
-       
-       Ext.apply(me, {
-           subject: gettext('Virtual Machine'),
-           width: 350,
-           items: [
-               {
-                   xtype: 'pveVMIDSelector',
-                   name: 'vms',
-                   validateExists: true,
-                   value:  '',
-                   fieldLabel: "VM ID"
-               }
-           ]
-       });
-
-       me.callParent();
-    }
-});
-
-Ext.define('PVE.pool.AddStorage', {
-    extend: 'PVE.window.Edit',
-
-    initComponent : function() {
-       /*jslint confusion: true */
-       var me = this;
-
-       if (!me.pool) {
-           throw "no pool specified";
-       }
-
-       me.create = true;
-       me.isAdd = true;
-       me.url = "/pools/" + me.pool;
-       me.method = 'PUT';
-       
-       Ext.apply(me, {
-           subject: gettext('Storage'),
-           width: 350,
-           items: [
-               {
-                   xtype: 'PVE.form.StorageSelector',
-                   name: 'storage',
-                   nodename: 'localhost',
-                   autoSelect: false,
-                   value:  '',
-                   fieldLabel: gettext("Storage")
-               }
-           ]
-       });
-
-       me.callParent();
-    }
-});
-
-Ext.define('PVE.grid.PoolMembers', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pvePoolMembers'],
-
-    // fixme: dynamic status update ?
-
-    initComponent : function() {
-       var me = this;
-
-       if (!me.pool) {
-           throw "no pool specified";
-       }
-
-       var store = Ext.create('Ext.data.Store', {
-           model: 'PVEResources',
-           sorters: [
-               {
-                   property : 'type',
-                   direction: 'ASC'
-               }
-           ],
-           proxy: { 
-               type: 'pve',
-               root: 'data.members',
-               url: "/api2/json/pools/" + me.pool
-           }
-       });
-
-       var coldef = PVE.data.ResourceStore.defaultColums();
-
-       var reload = function() {
-           store.load();
-       };
-
-       var sm = Ext.create('Ext.selection.RowModel', {});
-
-       var remove_btn = new PVE.button.Button({
-           text: gettext('Remove'),
-           disabled: true,
-           selModel: sm,
-           confirmMsg: function (rec) {
-               return Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-                                        "'" + rec.data.id + "'");
-           },
-           handler: function(btn, event, rec) {
-               var params = { 'delete': 1 };
-               if (rec.data.type === 'storage') {
-                   params.storage = rec.data.storage;
-               } else if (rec.data.type === 'qemu' || rec.data.type === 'lxc' || rec.data.type === 'openvz') {
-                   params.vms = rec.data.vmid;
-               } else {
-                   throw "unknown resource type";
-               }
-
-               PVE.Utils.API2Request({
-                   url: '/pools/' + me.pool,
-                   method: 'PUT',
-                   params: params,
-                   waitMsgTarget: me,
-                   callback: function() {
-                       reload();
-                   },
-                   failure: function (response, opts) {
-                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-                   }
-               });
-           }
-       });
-
-       Ext.apply(me, {
-           store: store,
-           selModel: sm,
-           tbar: [
-               {
-                   text: gettext('Add'),
-                   menu: new Ext.menu.Menu({
-                       items: [
-                           {
-                               text: gettext('Virtual Machine'),
-                               iconCls: 'pve-itype-icon-qemu',
-                               handler: function() {
-                                   var win = Ext.create('PVE.pool.AddVM', { pool: me.pool });
-                                   win.on('destroy', reload);
-                                   win.show();
-                               }
-                           },
-                           {
-                               text: gettext('Storage'),
-                               iconCls: 'pve-itype-icon-storage',
-                               handler: function() {
-                                   var win = Ext.create('PVE.pool.AddStorage', { pool: me.pool });
-                                   win.on('destroy', reload);
-                                   win.show();
-                               }
-                           }
-                       ]
-                   })
-               },
-               remove_btn
-           ],
-           viewConfig: {
-               stripeRows: true
-            },
-            columns: coldef,
-           listeners: {
-               show: reload
-           }
-       });
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/grid/ResourceGrid.js b/www/manager5/grid/ResourceGrid.js
deleted file mode 100644 (file)
index e638ec1..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-Ext.define('PVE.grid.ResourceGrid', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveResourceGrid'],
-
-    //fixme: this makes still problems with the scrollbar
-    //features: [ {ftype: 'chunking'}],
-    
-    title: gettext('Search'),
-
-    initComponent : function() {
-       var me = this;
-
-       var rstore = PVE.data.ResourceStore;
-       var sp = Ext.state.Manager.getProvider();
-
-       var coldef = rstore.defaultColums();
-
-       var store = Ext.create('Ext.data.Store', {
-           model: 'PVEResources',
-           sorters: [
-               {
-                   property : 'type',
-                   direction: 'ASC'
-               }
-           ],
-           proxy: { type: 'memory' }
-       });
-
-       var textfilter = '';
-
-       var textfilter_match = function(item) {
-           var match = false;
-           Ext.each(['name', 'storage', 'node', 'type', 'text'], function(field) {
-               var v = item.data[field];
-               if (v !== undefined) {
-                   v = v.toLowerCase();
-                   if (v.indexOf(textfilter) >= 0) {
-                       match = true;
-                       return false;
-                   }
-               }
-           });
-           return match;
-       };
-
-       var updateGrid = function() {
-
-           var filterfn = me.viewFilter ? me.viewFilter.filterfn : null;
-           
-           //console.log("START GRID UPDATE " +  me.viewFilter);
-
-           store.suspendEvents();
-
-           var nodeidx = {};
-           var gather_child_nodes = function(cn) {
-               if (!cn) {
-                   return;
-               }
-                var cs = cn.childNodes;
-               if (!cs) {
-                   return;
-               }
-               var len = cs.length, i = 0, n, res;
-
-                for (; i < len; i++) {
-                   var child = cs[i];
-                   var orgnode = rstore.data.get(child.data.id);
-                   if (orgnode) {
-                       if ((!filterfn || filterfn(child)) &&
-                           (!textfilter || textfilter_match(child))) {
-                           nodeidx[child.data.id] = orgnode;
-                       }
-                   }
-                   gather_child_nodes(child);
-               }
-           };
-           gather_child_nodes(me.pveSelNode);
-
-           // remove vanished items
-           var rmlist = [];
-           store.each(function(olditem) {
-               var item = nodeidx[olditem.data.id];
-               if (!item) {
-                   //console.log("GRID REM UID: " + olditem.data.id);
-                   rmlist.push(olditem);
-               }
-           });
-
-           if (rmlist.length) {
-               store.remove(rmlist);
-           }
-
-           // add new items
-           var addlist = [];
-           var key;
-           for (key in nodeidx) {
-               if (nodeidx.hasOwnProperty(key)) {
-                   var item = nodeidx[key];
-               
-                   // getById() use find(), which is slow (ExtJS4 DP5) 
-                   //var olditem = store.getById(item.data.id);
-                   var olditem = store.data.get(item.data.id);
-
-                   if (!olditem) {
-                       //console.log("GRID ADD UID: " + item.data.id);
-                       var info = Ext.apply({}, item.data);
-                       var child = Ext.create(store.model, info);
-                       addlist.push(item);
-                       continue;
-                   }
-                   // try to detect changes
-                   var changes = false;
-                   var fieldkeys = PVE.data.ResourceStore.fieldNames;
-                   var fieldcount = fieldkeys.length;
-                   var fieldind;
-                   for (fieldind = 0; fieldind < fieldcount; fieldind++) {
-                       var field = fieldkeys[fieldind];
-                       if (field != 'id' && item.data[field] != olditem.data[field]) {
-                           changes = true;
-                           //console.log("changed item " + item.id + " " + field + " " + item.data[field] + " != " + olditem.data[field]);
-                           olditem.beginEdit();
-                           olditem.set(field, item.data[field]);
-                       }
-                   }
-                   if (changes) {
-                       olditem.endEdit(true);
-                       olditem.commit(true); 
-                   }
-               }
-           }
-
-           if (addlist.length) {
-               store.add(addlist);
-           }
-
-           store.sort();
-
-           store.resumeEvents();
-
-           store.fireEvent('datachanged', store);
-
-           //console.log("END GRID UPDATE");
-       };
-
-       var filter_task = new Ext.util.DelayedTask(function(){
-           updateGrid();
-       });
-
-       var load_cb = function() { 
-           updateGrid(); 
-       };
-
-       Ext.apply(me, {
-           store: store,
-           tbar: [
-               '->', 
-               gettext('Search') + ':', ' ',
-               {
-                   xtype: 'textfield',
-                   width: 200,
-                   value: textfilter,
-                   enableKeyEvents: true,
-                   listeners: {
-                       keyup: function(field, e) {
-                           var v = field.getValue();
-                           textfilter = v.toLowerCase();
-                           filter_task.delay(500);
-                       }
-                   }
-               }
-           ],
-           viewConfig: {
-               stripeRows: true
-            },
-           listeners: {
-               itemcontextmenu: function(v, record, item, index, event) {
-                   event.stopEvent();
-                   v.select(record);
-                   var menu;
-                   
-                   if (record.data.type === 'qemu' && !record.data.template) {
-                       menu = Ext.create('PVE.qemu.CmdMenu', {
-                           pveSelNode: record
-                       });
-                   } else if (record.data.type === 'qemu' && record.data.template) {
-                       menu = Ext.create('PVE.qemu.TemplateMenu', {
-                           pveSelNode: record
-                       });
-                   } else if (record.data.type === 'lxc') {
-                       menu = Ext.create('PVE.lxc.CmdMenu', {
-                           pveSelNode: record
-                       });
-                   } else {
-                       return;
-                   }
-
-                   menu.showAt(event.getXY());
-               },
-               itemdblclick: function(v, record) {
-                   var ws = me.up('pveStdWorkspace');
-                   ws.selectById(record.data.id);
-               },
-               destroy: function() {
-                   rstore.un("load", load_cb);
-               }
-           },
-            columns: coldef
-       });
-
-       me.callParent();
-
-       updateGrid();
-       rstore.on("load", load_cb);
-    }
-});
diff --git a/www/manager5/grid/SelectFeature.js b/www/manager5/grid/SelectFeature.js
deleted file mode 100644 (file)
index eb5e719..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
- Ext.override(Ext.view.Table, {
-    afterRender: function() {
-        var me = this;
-        
-        me.callParent();
-// EXT5DEBUG
-//        me.mon(me.el, {
-//            scroll: me.fireBodyScroll,
-//            scope: me
-//        });
-//     if (!me.featuresMC ||
-//         (me.featuresMC.findIndex('ftype', 'selectable') < 0)) {
-//            me.el.unselectable();
-//     }
-//
-//        me.attachEventsForFeatures();
-    }
-});
-
-Ext.define('PVE.grid.SelectFeature', {
-    extend: 'Ext.grid.feature.Feature',
-    alias: 'feature.selectable',
-
-    mutateMetaRowTpl: function(metaRowTpl) {
-       var tpl, i,
-       ln = metaRowTpl.length;
-       
-       for (i = 0; i < ln; i++) {
-           tpl = metaRowTpl[i];
-           tpl = tpl.replace(/x-grid-row/, 'x-grid-row x-selectable');
-           tpl = tpl.replace(/x-grid-cell-inner x-unselectable/g, 'x-grid-cell-inner');
-           tpl = tpl.replace(/unselectable="on"/g, '');
-           metaRowTpl[i] = tpl;
-       }
-    }  
-});
diff --git a/www/manager5/panel/ConfigPanel.js b/www/manager5/panel/ConfigPanel.js
deleted file mode 100644 (file)
index 1878564..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-Ext.define('PVE.panel.Config', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pvePanelConfig',
-
-    initComponent: function() {
-        var me = this;
-
-       var stateid = me.hstateid;
-
-       var sp = Ext.state.Manager.getProvider();
-
-       var activeTab;
-
-       var hsregex =  /^([^\-\s]+)(-\S+)?$/;
-
-       if (stateid) {
-           var state = sp.get(stateid);
-           if (state && state.value) {
-               var res = hsregex.exec(state.value);
-               if (res && res[1]) {
-                   activeTab = res[1];
-               }
-           }
-       }
-
-       var items = me.items || [];
-       me.items = undefined;
-
-       var tbar = me.tbar || [];
-       me.tbar = undefined;
-
-       var title = me.title || me.pveSelNode.data.text;
-       me.title = undefined;
-
-       tbar.unshift('->');
-       tbar.unshift({
-           xtype: 'tbtext',
-           text: title,
-           baseCls: 'x-panel-header-text',
-           padding: '0 0 5 0'
-       });
-
-       Ext.applyIf(me, { showSearch: true });
-
-       if (me.showSearch) {
-           items.unshift({
-               itemId: 'search', 
-               xtype: 'pveResourceGrid'
-           });
-       }
-
-       var toolbar = Ext.create('Ext.toolbar.Toolbar', {
-           items: tbar,
-           style: 'border:0px;',
-           height: 28
-       });
-
-       var tab = Ext.create('Ext.tab.Panel', {
-           flex: 1,
-           border: true,
-           activeTab: activeTab,
-           defaults: Ext.apply(me.defaults ||  {}, {
-               pveSelNode: me.pveSelNode,
-               viewFilter: me.viewFilter,
-               workspace: me.workspace,
-               border: false
-           }),
-           items: items,
-           listeners: {
-               afterrender: function(tp) {
-                   var first =  tp.items.get(0);
-                   if (first) {
-                       first.fireEvent('show', first);
-                   }
-               },
-               tabchange: function(tp, newcard, oldcard) {
-                   var ntab = newcard.itemId;
-
-                   // Note: '' is alias for first tab.
-                   // First tab can be 'search' or something else
-                   if (newcard.itemId === items[0].itemId) {
-                       ntab = '';
-                   }
-                   if (stateid) {
-                       if (newcard.phstateid) {
-                           sp.set(newcard.phstateid, newcard.getHState());
-                       } else {
-                           sp.set(stateid, { value: ntab });
-                       }
-                   }
-               }
-           }
-       });
-
-       Ext.apply(me, {
-           layout: { type: 'vbox', align: 'stretch' },
-           items: [ toolbar, tab]
-       });
-
-       me.callParent();
-
-       var statechange = function(sp, key, state) {
-           if (stateid && (key === stateid) && state) {
-               var atab = tab.getActiveTab().itemId;
-               var res = hsregex.exec(state.value);
-               var ntab = (res && res[1]) ? res[1] : items[0].itemId;
-               if (ntab && (atab != ntab)) {
-                   tab.setActiveTab(ntab);
-               }
-           }
-       };
-
-       if (stateid) {
-           me.mon(sp, 'statechange', statechange);
-       }
-    }
-});
diff --git a/www/manager5/panel/Firewall.js b/www/manager5/panel/Firewall.js
deleted file mode 100644 (file)
index 4e7efd3..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-Ext.define('PVE.panel.Firewall', {
-    extend: 'PVE.panel.SubConfig',
-    alias: 'widget.pveFirewallPanel',
-
-    configPrefix: 'firewall',
-
-    fwtype: undefined, // 'dc', 'node' or 'vm'
-
-    base_url: undefined,
-
-    initComponent: function() {
-       /*jslint confusion: true */
-        var me = this;
-
-       if (!me.base_url) {
-           throw "no base_url specified";
-       }
-
-       if (!(me.fwtype === 'dc' || me.fwtype === 'node' || me.fwtype === 'vm')) {
-           throw "unknown firewall panel type";
-       }
-
-       var list_refs_url = me.fwtype === 'vm' ? (me.base_url + '/refs') : 
-           '/cluster/firewall/refs';
-
-       var items = [
-           {
-               xtype: 'pveFirewallRules',
-               title: gettext('Rules'),
-               allow_iface: true,
-               base_url: me.base_url + '/rules',
-               list_refs_url: list_refs_url,
-               itemId: 'rules'
-           }
-       ];
-
-       if (me.fwtype === 'dc') {
-           items.push({
-               xtype: 'pveSecurityGroups',
-               title: gettext('Security Group'),
-               itemId: 'sg'
-           });
-           items.push({
-               xtype: 'pveFirewallAliases',
-               base_url: '/cluster/firewall/aliases',              
-               itemId: 'aliases'
-           });
-           items.push({
-               xtype: 'pveIPSet',
-               base_url: '/cluster/firewall/ipset',
-               list_refs_url: list_refs_url,               
-               itemId: 'ipset'
-           });
-       }
-
-       if (me.fwtype === 'vm') {
-           items.push({
-               xtype: 'pveFirewallAliases',
-               base_url: me.base_url + '/aliases',                 
-               itemId: 'aliases'
-           });
-           items.push({
-               xtype: 'pveIPSet',
-               base_url: me.base_url + '/ipset',                   
-               list_refs_url: list_refs_url,               
-               itemId: 'ipset'
-           });
-       }
-
-       items.push({
-           xtype: 'pveFirewallOptions',
-           title: gettext('Options'),
-           base_url: me.base_url + '/options',
-           fwtype: me.fwtype,
-           itemId: 'options'
-       });
-
-       if (me.fwtype !== 'dc') {
-           items.push({
-               title: 'Log',
-               itemId: 'fwlog',
-               xtype: 'pveLogView',
-               url: '/api2/extjs' + me.base_url + '/log'
-           });
-       }
-
-       Ext.apply(me, {
-           defaults: {
-               border: false,
-               pveSelNode: me.pveSelNode
-           },
-           items: items
-       });
-
-       me.callParent();
-    }
-});
\ No newline at end of file
diff --git a/www/manager5/panel/IPSet.js b/www/manager5/panel/IPSet.js
deleted file mode 100644 (file)
index 2aae7df..0000000
+++ /dev/null
@@ -1,474 +0,0 @@
-Ext.define('PVE.IPSetList', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveIPSetList',
-
-    ipset_panel: undefined,
-
-    base_url: undefined,
-
-    addBtn: undefined,
-    removeBtn: undefined,
-    editBtn: undefined,
-
-    initComponent: function() {
-       /*jslint confusion: true */
-        var me = this;
-
-       if (me.ipset_panel == undefined) {
-           throw "no rule panel specified";
-       }
-
-       if (me.base_url == undefined) {
-           throw "no base_url specified";
-       }
-
-       var store = new Ext.data.Store({
-           fields: [ 'name', 'comment', 'digest' ],
-           proxy: {
-               type: 'pve',
-               url: "/api2/json" + me.base_url
-           },
-           idProperty: 'name',
-           sorters: {
-               property: 'name',
-               order: 'DESC'
-           }
-       });
-
-       var sm = Ext.create('Ext.selection.RowModel', {});
-
-       var reload = function() {
-           var oldrec = sm.getSelection()[0];
-           store.load(function(records, operation, success) {
-               if (oldrec) {
-                   var rec = store.findRecord('name', oldrec.data.name);
-                   if (rec) {
-                       sm.select(rec);
-                   }
-               }
-           });
-       };
-
-       var run_editor = function() {
-           var rec = sm.getSelection()[0];
-           if (!rec) {
-               return;
-           }
-           var win = Ext.create('PVE.window.Edit', {
-               subject: "IPSet '" + rec.data.name + "'",
-               url: me.base_url,
-               method: 'POST',
-               digest: rec.data.digest,
-               items: [
-                   {
-                       xtype: 'hiddenfield',
-                       name: 'rename',
-                       value: rec.data.name
-                   },
-                   {
-                       xtype: 'textfield',
-                       name: 'name',
-                       value: rec.data.name,
-                       fieldLabel: gettext('Name'),
-                       allowBlank: false
-                   },
-                   {
-                       xtype: 'textfield',
-                       name: 'comment',
-                       value: rec.data.comment,
-                       fieldLabel: gettext('Comment')
-                   }
-               ]
-           });
-           win.show();
-           win.on('destroy', reload);
-       };
-
-       me.editBtn = new PVE.button.Button({
-           text: gettext('Edit'),
-           disabled: true,
-           selModel: sm,
-           handler: run_editor
-       });
-
-       me.addBtn = new PVE.button.Button({
-           text: gettext('Create'),
-           handler: function() {
-               sm.deselectAll();
-               var win = Ext.create('PVE.window.Edit', {
-                   subject: 'IPSet',
-                   url: me.base_url,
-                   method: 'POST',
-                   items: [
-                       {
-                           xtype: 'textfield',
-                           name: 'name',
-                           value: '',
-                           fieldLabel: gettext('Name'),
-                           allowBlank: false
-                       },
-                       {
-                           xtype: 'textfield',
-                           name: 'comment',
-                           value: '',
-                           fieldLabel: gettext('Comment')
-                       }
-                   ]
-               });
-               win.show();
-               win.on('destroy', reload);
-
-           }
-       });
-
-       me.removeBtn = new PVE.button.Button({
-           text: gettext('Remove'),
-           selModel: sm,
-           disabled: true,
-           handler: function() {
-               var rec = sm.getSelection()[0];
-               if (!rec || !me.base_url) {
-                   return;
-               }
-               PVE.Utils.API2Request({
-                   url: me.base_url + '/' + rec.data.name,
-                   method: 'DELETE',
-                   waitMsgTarget: me,
-                   failure: function(response, options) {
-                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-                   },
-                   callback: reload
-               });
-           }
-       });
-
-       Ext.apply(me, {
-           store: store,
-           tbar: [ '<b>IPSet:</b>', me.addBtn, me.removeBtn, me.editBtn ],
-           selModel: sm,
-           columns: [
-               { header: 'IPSet', dataIndex: 'name', width: 100 },
-               { header: gettext('Comment'), dataIndex: 'comment', flex: 1 }
-           ],
-           listeners: {
-               itemdblclick: run_editor,
-               select: function(sm, rec) {
-                   var url = me.base_url + '/' + rec.data.name;
-                   me.ipset_panel.setBaseUrl(url);
-               },
-               deselect: function() {
-                   me.ipset_panel.setBaseUrl(undefined);
-               },
-               show: reload
-           }
-       });
-
-       me.callParent();
-
-       store.load();
-    }
-});
-
-Ext.define('PVE.IPSetCidrEdit', {
-    extend: 'PVE.window.Edit',
-
-    cidr: undefined,
-
-    initComponent : function() {
-       /*jslint confusion: true */
-       var me = this;
-
-       me.create = (me.cidr === undefined);
-
-
-       if (me.create) {
-            me.url = '/api2/extjs' + me.base_url;
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs' + me.base_url + '/' + me.cidr;
-            me.method = 'PUT';
-        }
-
-       var column1 = [];
-
-       if (me.create) {
-           if (!me.list_refs_url) {
-               throw "no alias_base_url specified";
-           }
-
-           column1.push({
-               xtype: 'pveIPRefSelector',
-               name: 'cidr',
-               ref_type: 'alias',
-               autoSelect: false,
-               editable: true,
-               base_url: me.list_refs_url,
-               value: '',
-               fieldLabel: gettext('IP/CIDR')
-           });
-       } else {
-           column1.push({
-               xtype: 'displayfield',
-               name: 'cidr',
-               height: 22, // hack: set same height as text fields
-               value: '',
-               fieldLabel: gettext('IP/CIDR')
-           });
-       }
-
-       var ipanel = Ext.create('PVE.panel.InputPanel', {
-           create: me.create,
-           column1: column1,
-           column2: [
-               {
-                   xtype: 'pvecheckbox',
-                   name: 'nomatch',
-                   checked: false,
-                   height: 22, // hack: set same height as text fields
-                   uncheckedValue: 0,
-                   fieldLabel: gettext('nomatch')
-               }
-           ],
-           columnB: [
-               {
-                   xtype: 'textfield',
-                   name: 'comment',
-                   value: '',
-                   fieldLabel: gettext('Comment')
-               }
-           ]
-       });
-
-       Ext.apply(me, {
-           subject: gettext('IP/CIDR'),
-           items: [ ipanel ]
-       });
-
-       me.callParent();
-
-       if (!me.create) {
-           me.load({
-               success:  function(response, options) {
-                   var values = response.result.data;
-                   ipanel.setValues(values);
-               }
-           });
-       }
-    }
-});
-
-Ext.define('PVE.IPSetGrid', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveIPSetGrid',
-
-    base_url: undefined,
-    list_refs_url: undefined,
-
-    addBtn: undefined,
-    removeBtn: undefined,
-    editBtn: undefined,
-
-    setBaseUrl: function(url) {
-        var me = this;
-
-       me.base_url = url;
-
-       if (url === undefined) {
-           me.addBtn.setDisabled(true);
-           me.store.removeAll();
-       } else {
-           me.addBtn.setDisabled(false);
-           me.store.setProxy({
-               type: 'pve',
-               url: '/api2/json' + url
-           });
-
-           me.store.load();
-       }
-    },
-
-    initComponent: function() {
-       /*jslint confusion: true */
-        var me = this;
-
-       if (!me.list_refs_url) {
-           throw "no1 list_refs_url specified";
-       }
-
-       var store = new Ext.data.Store({
-           model: 'pve-ipset'
-       });
-
-       var reload = function() {
-           store.load();
-       };
-
-       var sm = Ext.create('Ext.selection.RowModel', {});
-
-       var run_editor = function() {
-           var rec = sm.getSelection()[0];
-           if (!rec) {
-               return;
-           }
-           var win = Ext.create('PVE.IPSetCidrEdit', {
-               base_url: me.base_url,
-               cidr: rec.data.cidr
-           });
-           win.show();
-           win.on('destroy', reload);
-       };
-
-       me.editBtn = new PVE.button.Button({
-           text: gettext('Edit'),
-           disabled: true,
-           selModel: sm,
-           handler: run_editor
-       });
-
-       me.addBtn = new PVE.button.Button({
-           text: gettext('Add'),
-           disabled: true,
-           handler: function() {
-               if (!me.base_url) {
-                   return;
-               }
-               var win = Ext.create('PVE.IPSetCidrEdit', {
-                   base_url: me.base_url,
-                   list_refs_url: me.list_refs_url
-               });
-               win.show();
-               win.on('destroy', reload);
-           }
-       });
-
-       me.removeBtn = new PVE.button.Button({
-           text: gettext('Remove'),
-           selModel: sm,
-           disabled: true,
-           handler: function() {
-               var rec = sm.getSelection()[0];
-               if (!rec || !me.base_url) {
-                   return;
-               }
-
-               PVE.Utils.API2Request({
-                   url: me.base_url + '/' + rec.data.cidr,
-                   method: 'DELETE',
-                   waitMsgTarget: me,
-                   failure: function(response, options) {
-                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-                   },
-                   callback: reload
-               });
-           }
-       });
-
-       var render_errors = function(value, metaData, record) {
-           var errors = record.data.errors;
-           if (errors) {
-               var msg = errors.cidr || errors.nomatch;
-               if (msg) {
-                   metaData.tdCls = 'x-form-invalid-field';
-                   var html = '<p>' +  Ext.htmlEncode(msg) + '</p>';
-                   metaData.tdAttr = 'data-qwidth=600 data-qtitle="ERROR" data-qtip="' + 
-                       html.replace(/\"/g,'&quot;') + '"';
-               }
-           }
-           return value;
-       };
-
-       Ext.apply(me, {
-           tbar: [ '<b>IP/CIDR:</b>', me.addBtn, me.removeBtn, me.editBtn ],
-           store: store,
-           selModel: sm,
-           listeners: {
-               itemdblclick: run_editor
-           },
-           columns: [
-               {
-                   xtype: 'rownumberer'
-               },
-               {
-                   header: gettext('IP/CIDR'),
-                   dataIndex: 'cidr',
-                   width: 150,
-                   renderer: function(value, metaData, record) {
-                       value = render_errors(value, metaData, record);
-                       if (record.data.nomatch) {
-                           return '<b>! </b>' + value;
-                       }
-                       return value;
-                   }
-               },
-               {
-                   header: gettext('Comment'),
-                   dataIndex: 'comment',
-                   flex: 1,
-                   renderer: function(value) {
-                       return Ext.util.Format.htmlEncode(value);
-                   }
-               }
-           ]
-       });
-
-       me.callParent();
-
-       if (me.base_url) {
-           me.setBaseUrl(me.base_url); // load
-       }
-    }
-}, function() {
-
-    Ext.define('pve-ipset', {
-       extend: 'Ext.data.Model',
-       fields: [ { name: 'nomatch', type: 'boolean' },
-                 'cidr', 'comment', 'errors' ],
-       idProperty: 'cidr'
-    });
-
-});
-
-Ext.define('PVE.IPSet', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveIPSet',
-
-    title: 'IPSet',
-
-    list_refs_url: undefined,
-
-    initComponent: function() {
-       var me = this;
-
-       if (!me.list_refs_url) {
-           throw "no list_refs_url specified";
-       }
-
-       var ipset_panel = Ext.createWidget('pveIPSetGrid', {
-           region: 'center',
-           list_refs_url: me.list_refs_url,
-           flex: 0.5,
-           border: false
-       });
-
-       var ipset_list = Ext.createWidget('pveIPSetList', {
-           region: 'west',
-           ipset_panel: ipset_panel,
-           base_url: me.base_url,
-           flex: 0.5,
-           border: false,
-           split: true
-       });
-
-       Ext.apply(me, {
-            layout: 'border',
-            items: [ ipset_list, ipset_panel ],
-           listeners: {
-               show: function() {
-                   ipset_list.fireEvent('show', ipset_list);
-               }
-           }
-       });
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/panel/InputPanel.js b/www/manager5/panel/InputPanel.js
deleted file mode 100644 (file)
index 8ab1e33..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-Ext.define('PVE.panel.InputPanel', {
-    extend: 'Ext.panel.Panel',
-    alias: ['widget.inputpanel'],
-
-    border: false,
-
-    // overwrite this to modify submit data
-    onGetValues: function(values) {
-       return values;
-    },
-
-    getValues: function(dirtyOnly) {
-       var me = this;
-
-       if (Ext.isFunction(me.onGetValues)) {
-           dirtyOnly = false;
-       }
-
-       var values = {};
-
-       Ext.Array.each(me.query('[isFormField]'), function(field) {
-            if (!dirtyOnly || field.isDirty()) {
-                PVE.Utils.assemble_field_data(values, field.getSubmitData());
-           }
-       });
-
-       return me.onGetValues(values);
-    },
-
-    setValues: function(values) {
-       var me = this;
-
-       var form = me.up('form');
-
-        Ext.iterate(values, function(fieldId, val) {
-           var field = me.query('[isFormField][name=' + fieldId + ']')[0];
-            if (field) {
-               field.setValue(val);
-                if (form.trackResetOnLoad) {
-                    field.resetOriginalValue();
-                }
-            }
-       });
-    },
-
-    initComponent: function() {
-       var me = this;
-
-       var items;
-       
-       if (me.items) {
-           me.columns = 1;
-           items = [
-               {
-                   columnWidth: 1,
-                   layout: 'anchor',
-                   items: me.items
-               }
-           ];
-           me.items = undefined;
-       } else if (me.column1) {
-           me.columns = 2;
-           items = [
-               {
-                   columnWidth: 0.5,
-                   padding: '0 10 0 0',
-                   layout: 'anchor',
-                   items: me.column1
-               },
-               {
-                   columnWidth: 0.5,
-                   padding: '0 0 0 10',
-                   layout: 'anchor',
-                   items: me.column2 || [] // allow empty column
-               }
-           ];
-           if (me.columnB) {
-               items.push({
-                   columnWidth: 1,
-                   padding: '10 0 0 0',
-                   layout: 'anchor',
-                   items: me.columnB
-               });
-           }
-       } else {
-           throw "unsupported config";
-       }
-
-       if (me.useFieldContainer) {
-           Ext.apply(me, {
-               layout: 'fit',
-               items: Ext.apply(me.useFieldContainer, { 
-                   layout: 'column',
-                   defaultType: 'container',
-                   items: items
-               })
-           });
-       } else {
-           Ext.apply(me, {
-               layout: 'column',
-               defaultType: 'container',
-               items: items
-           });
-       }
-       
-       me.callParent();
-    }
-});
diff --git a/www/manager5/panel/LogView.js b/www/manager5/panel/LogView.js
deleted file mode 100644 (file)
index 49be118..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Display log entries in a panel with scrollbar
- * The log entries are automatically refreshed via a background task,
- * with newest entries comming at the bottom
- */
-Ext.define('PVE.panel.LogView', {
-    extend: 'Ext.panel.Panel',
-
-    alias: ['widget.pveLogView'],
-
-    pageSize: 500,
-
-    lineHeight: 16,
-
-    viewInfo: undefined,
-
-    scrollToEnd: true,
-
-    getMaxDown: function(scrollToEnd) {
-        var me = this;
-
-       var target = me.getTargetEl();
-       var dom = target.dom;
-       if (scrollToEnd) {
-           dom.scrollTop = dom.scrollHeight - dom.clientHeight;
-       }
-
-       var maxDown = dom.scrollHeight - dom.clientHeight - 
-           dom.scrollTop;
-
-       return maxDown;
-    },
-
-    updateView: function(start, end, total, text) {
-        var me = this;
-       var el = me.dataCmp.el;
-
-       if (me.viewInfo && me.viewInfo.start === start &&
-           me.viewInfo.end === end && me.viewInfo.total === total &&
-           me.viewInfo.textLength === text.length) {
-           return; // same content
-       }
-
-       var maxDown = me.getMaxDown();
-       var scrollToEnd = (maxDown <= 0) && me.scrollToEnd;
-
-       el.setStyle('padding-top', start*me.lineHeight + 'px');
-       el.update(text);
-       me.dataCmp.setHeight(total*me.lineHeight);
-
-       if (scrollToEnd) {
-           me.getMaxDown(true);
-       }
-
-       me.viewInfo = {
-           start: start,
-           end: end,
-           total: total,
-           textLength:  text.length
-       };
-    },
-
-    doAttemptLoad: function(start) {
-        var me = this;
-
-       PVE.Utils.API2Request({
-           url: me.url,
-           params: {
-               start: start,
-               limit: me.pageSize
-           },
-           method: 'GET',
-           success: function(response) {
-               PVE.Utils.setErrorMask(me, false);
-               var list = response.result.data;
-               var total = response.result.total;
-               var first = 0, last = 0;
-               var text = '';
-               Ext.Array.each(list, function(item) {
-                   if (!first|| item.n < first) {
-                       first = item.n;
-                   }
-                   if (!last || item.n > last) {
-                       last = item.n;
-                   }
-                   text = text + Ext.htmlEncode(item.t) + "<br>";
-               });
-
-               if (first && last && total) {
-                   me.updateView(first -1 , last -1, total, text);
-               } else {
-                   me.updateView(0, 0, 0, '');
-               }
-           },
-           failure: function(response) {
-               var msg = response.htmlStatus;
-               PVE.Utils.setErrorMask(me, msg);
-           }
-       });                           
-    },
-
-    attemptLoad: function(start) {
-        var me = this;
-        if (!me.loadTask) {
-            me.loadTask = Ext.create('Ext.util.DelayedTask', me.doAttemptLoad, me, []);
-        }
-        me.loadTask.delay(200, me.doAttemptLoad, me, [start]);
-    },
-
-    requestUpdate: function(top, force) {
-       var me = this;
-
-       if (top === undefined) {
-           var target = me.getTargetEl();
-           top = target.dom.scrollTop;
-       }
-
-       var viewStart = parseInt((top / me.lineHeight) - 1, 10);
-       if (viewStart < 0) {
-           viewStart = 0;
-       }
-       var viewEnd = parseInt(((top + me.getHeight())/ me.lineHeight) + 1, 10);
-       var info = me.viewInfo;
-
-       if (info && !force) {
-           if (viewStart >= info.start && viewEnd <= info.end) {
-               return;
-           }
-       }
-
-       var line = parseInt((top / me.lineHeight) - (me.pageSize / 2) + 10, 10);
-       if (line < 0) {
-           line = 0;
-       }
-
-       me.attemptLoad(line);
-    },
-
-    afterRender: function() {
-       var me = this;
-
-        me.callParent(arguments);
-       Ext.Function.defer(function() {
-           var target = me.getTargetEl();
-           target.on('scroll',  function(e) {
-               me.requestUpdate();
-           });
-           me.requestUpdate(0);
-       }, 20);
-    },
-
-    initComponent : function() {
-       /*jslint confusion: true */
-
-       var me = this;
-
-       if (!me.url) {
-           throw "no url specified";
-       }
-
-       me.dataCmp = Ext.create('Ext.Component', {
-           style: 'font:normal 11px tahoma, arial, verdana, sans-serif;' +
-               'line-height: ' + me.lineHeight.toString() + 'px; white-space: pre;'
-       });
-
-       me.task = Ext.TaskManager.start({
-           run: function() {
-               if (!me.isVisible() || !me.scrollToEnd || !me.viewInfo) {
-                   return;
-               }
-               
-               var maxDown = me.getMaxDown();
-               if (maxDown > 0) {
-                   return;
-               }
-
-               me.requestUpdate(undefined, true);
-           },
-           interval: 1000
-       });
-
-       Ext.apply(me, {
-           autoScroll: true,
-           layout: 'auto',
-           items: me.dataCmp,
-           bodyStyle: 'padding: 5px;',
-           listeners: {
-               show: function() {
-                   var target = me.getTargetEl();
-                   if (target && target.dom) {
-                       target.dom.scrollTop = me.savedScrollTop;
-                   }
-               },
-               beforehide: function() {
-                   // Hack: chrome reset scrollTop to 0, so we save/restore
-                   var target = me.getTargetEl();
-                   if (target && target.dom) {
-                       me.savedScrollTop = target.dom.scrollTop;
-                   }
-               },
-               destroy: function() {
-                   Ext.TaskManager.stop(me.task);
-               }
-           }
-       });
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/panel/NotesView.js b/www/manager5/panel/NotesView.js
deleted file mode 100644 (file)
index add9e5e..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-Ext.define('PVE.panel.NotesView', {
-    extend: 'Ext.panel.Panel',
-
-    load: function() {
-       var me = this;
-       
-       PVE.Utils.API2Request({
-           url: me.url,
-           waitMsgTarget: me,
-           failure: function(response, opts) {
-               me.update(gettext('Error') + " " + response.htmlStatus);
-           },
-           success: function(response, opts) {
-               var data = response.result.data.description || '';
-               me.update(Ext.htmlEncode(data));
-           }
-       });
-    },
-
-    initComponent : function() {
-       var me = this;
-
-       var nodename = me.pveSelNode.data.node;
-       if (!nodename) {
-           throw "no node name specified";
-       }
-
-       var vmid = me.pveSelNode.data.vmid;
-       if (!vmid) {
-           throw "no VM ID specified";
-       }
-
-       var vmtype = me.pveSelNode.data.type;
-       var url;
-
-       if (vmtype === 'qemu') {
-           me.url = '/api2/extjs/nodes/' + nodename + '/qemu/' + vmid + '/config';
-       } else if (vmtype === 'lxc') {
-           me.url = '/api2/extjs/nodes/' + nodename + '/lxc/' + vmid + '/config';
-       } else {
-           throw "unknown vm type '" + vmtype + "'";
-       }
-
-       Ext.apply(me, {
-           title: gettext("Notes"),
-           style: 'padding-left:10px',
-           bodyStyle: 'white-space:pre',
-           bodyPadding: 10,
-           autoScroll: true,
-           listeners: {
-               render: function(c) {
-                   c.el.on('dblclick', function() { 
-                       var win = Ext.create('PVE.window.NotesEdit', {
-                           pveSelNode: me.pveSelNode,
-                           url: me.url
-                       });
-                       win.show();
-                       win.on('destroy', me.load, me);
-                   });
-               }
-           }
-       });
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/panel/RRDView.js b/www/manager5/panel/RRDView.js
deleted file mode 100644 (file)
index 9fd3c47..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-Ext.define('PVE.panel.RRDView', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveRRDView',
-
-    initComponent : function() {
-       var me = this;
-
-       if (!me.datasource) {
-           throw "no datasource specified";
-       }
-
-       if (!me.rrdurl) {
-           throw "no rrdurl specified";
-       }
-
-       var stateid = 'pveRRDTypeSelection';
-       var sp = Ext.state.Manager.getProvider();
-       var stateinit = sp.get(stateid);
-
-        if (stateinit) {
-           if(stateinit.timeframe !== me.timeframe || stateinit.cf !== me.rrdcffn){
-               me.timeframe = stateinit.timeframe;
-               me.rrdcffn = stateinit.cf;
-           }
-       }
-
-       if (!me.timeframe) {
-           if(stateinit && stateinit.timeframe){
-               me.timeframe = stateinit.timeframe;
-           }else{
-               me.timeframe = 'hour';
-           }
-       }
-
-       if (!me.rrdcffn) {
-           if(stateinit && stateinit.rrdcffn){
-               me.rrdcffn = stateinit.cf;
-           }else{
-               me.rrdcffn = 'AVERAGE';
-           }
-       }
-
-
-       var datasource = me.datasource;
-
-       // fixme: dcindex??
-       var dcindex = 0;
-       var create_url = function() {
-           var url = me.rrdurl + "?ds=" + datasource + 
-               "&timeframe=" + me.timeframe + "&cf=" + me.rrdcffn +
-               "&_dc=" + dcindex.toString();
-           dcindex++;
-           return url;
-       };
-
-
-       Ext.apply(me, {
-           layout: 'fit',
-           html: {
-               tag: 'img',
-               width: 800,
-               height: 200,
-               src:  create_url()
-           },
-           applyState : function(state) {
-               if (state && state.id) {
-                   if(state.timeframe !== me.timeframe || state.cf !== me.rrdcffn){
-                       me.timeframe = state.timeframe;
-                       me.rrdcffn = state.cf;
-                       me.reload_task.delay(10);
-                   }
-               }
-           }
-       });
-       
-       me.callParent();
-   
-       me.reload_task = new Ext.util.DelayedTask(function() {
-           if (me.rendered) {
-               try {
-                   var html = {
-                       tag: 'img',
-                       width: 800,
-                       height: 200,
-                       src:  create_url()
-                   };
-                   me.update(html);
-               } catch (e) {
-                   // fixme:
-                   console.log(e);
-               }
-               me.reload_task.delay(30000);
-           } else {
-               me.reload_task.delay(1000);
-           }
-       });
-
-       me.reload_task.delay(30000);
-
-       me.on('destroy', function() {
-           me.reload_task.cancel();
-       });
-
-       var state_change_fn = function(prov, key, value) {
-           if (key == stateid) {
-               me.applyState(value);
-           }
-       };
-
-       me.mon(sp, 'statechange', state_change_fn);
-    }
-});
diff --git a/www/manager5/panel/StatusPanel.js b/www/manager5/panel/StatusPanel.js
deleted file mode 100644 (file)
index 92d4d99..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * This class describes the bottom panel
- */
-Ext.define('PVE.panel.StatusPanel', {
-    extend: 'Ext.tab.Panel',
-    alias: 'widget.pveStatusPanel',
-
-    
-    //title: "Logs",
-    //tabPosition: 'bottom',
-
-    initComponent: function() {
-        var me = this;
-
-       var stateid = 'ltab';
-       var sp = Ext.state.Manager.getProvider();
-
-       var state = sp.get(stateid);
-       if (state && state.value) {
-           me.activeTab = state.value;
-       }
-
-       Ext.apply(me, {
-           listeners: {
-               tabchange: function() {
-                   var atab = me.getActiveTab().itemId;
-                   var state = { value: atab };
-                   sp.set(stateid, state);
-               }
-           },
-           items: [
-               {
-                   itemId: 'tasks',
-                   title: gettext('Tasks'),
-                   xtype: 'pveClusterTasks'
-               },
-               {
-                   itemId: 'clog',
-                   title: gettext('Cluster log'),
-                   xtype: 'pveClusterLog'
-               }
-           ]
-       });
-
-       me.callParent();
-
-       me.items.get(0).fireEvent('show', me.items.get(0));
-
-       var statechange = function(sp, key, state) {
-           if (key === stateid) {
-               var atab = me.getActiveTab().itemId;
-               var ntab = state.value;
-               if (state && ntab && (atab != ntab)) {
-                   me.setActiveTab(ntab);
-               }
-           }
-       };
-
-       sp.on('statechange', statechange);
-       me.on('destroy', function() {
-           sp.un('statechange', statechange);              
-       });
-
-    }
-});
diff --git a/www/manager5/panel/SubConfigPanel.js b/www/manager5/panel/SubConfigPanel.js
deleted file mode 100644 (file)
index 849fd04..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-Ext.define('PVE.panel.SubConfig', {
-    extend: 'Ext.tab.Panel',
-    alias: ['widget.pvePanelSubConfig'],
-
-    configPrefix: undefined,
-
-    getHState: function(itemId) {
-        /*jslint confusion: true */
-        var me = this;
-       
-       if (!itemId) {
-           itemId = me.getActiveTab().itemId;
-       }
-
-       var first =  me.items.get(0);
-       var ntab;
-
-       // Note: '' is alias for first tab.
-       if (itemId === first.itemId) {
-           ntab = me.configPrefix;
-       } else {
-           ntab = me.configPrefix + '-' + itemId;
-       }
-
-       return { value: ntab };
-    },
-
-    initComponent: function() {
-        var me = this;
-
-       if (!me.phstateid) {
-           throw "no parent history state specified";
-       }
-
-       var sp = Ext.state.Manager.getProvider();
-       var state = sp.get(me.phstateid);
-       
-       var hsregex =  /^([^\-\s]+)-(\S+)?$/;
-
-       if (state && state.value) {
-           var res = hsregex.exec(state.value);
-           if (res && res[1] && res[2] && res[1] === me.configPrefix) {
-               me.activeTab = res[2];
-           }
-       }
-
-       Ext.apply(me, {
-           plain: true,
-           tabPosition: 'bottom',
-           listeners: {
-               afterrender: function(tp) {
-                   var first =  tp.items.get(0);
-                   if (first) {
-                       first.fireEvent('show', first);
-                   }
-               },
-               tabchange: function(tp, newcard, oldcard) {
-                   var state = me.getHState(newcard.itemId);
-                   sp.set(me.phstateid, state);
-               }
-           }
-       });
-
-       me.callParent();
-
-       var statechange = function(sp, key, state) {
-           if ((key === me.phstateid) && state) {
-               var first = me.items.get(0);
-               var atab = me.getActiveTab().itemId;
-               var res = hsregex.exec(state.value);
-               var ntab = (res && res[1]) ? res[1] : first.itemId;
-               if (ntab && (atab != ntab)) {
-                   me.setActiveTab(ntab);
-               }
-           }
-       };
-
-       me.mon(sp, 'statechange', statechange);
-    }
-});
diff --git a/www/manager5/pool/Config.js b/www/manager5/pool/Config.js
deleted file mode 100644 (file)
index 8683cca..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-Ext.define('PVE.pool.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.pvePoolConfig',
-
-    initComponent: function() {
-        var me = this;
-
-       var pool = me.pveSelNode.data.pool;
-       if (!pool) {
-           throw "no pool specified";
-       }
-
-       Ext.apply(me, {
-           title: Ext.String.format(gettext("Resource Pool") + ': ' + pool),
-           hstateid: 'pooltab',
-           items: [
-               {
-                   title: gettext('Summary'),
-                   xtype: 'pvePoolSummary',
-                   itemId: 'summary'
-               },
-               {
-                   title: gettext('Members'),
-                   xtype: 'pvePoolMembers',
-                   pool: pool,
-                   itemId: 'members'
-               },
-               {
-                   xtype: 'pveACLView',
-                   title: gettext('Permissions'),
-                   itemId: 'permissions',
-                   path: '/pool/' + pool
-               }
-           ]
-       });
-
-       me.callParent();
-   }
-});
diff --git a/www/manager5/pool/StatusView.js b/www/manager5/pool/StatusView.js
deleted file mode 100644 (file)
index 8049364..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-Ext.define('PVE.pool.StatusView', {
-    extend: 'PVE.grid.ObjectGrid',
-    alias: ['widget.pvePoolStatusView'],
-
-    initComponent : function() {
-       var me = this;
-
-       var pool = me.pveSelNode.data.pool;
-       if (!pool) {
-           throw "no pool specified";
-       }
-
-       var rows = {
-           comment: {
-               header: gettext('Comment'), 
-               required: true
-           }
-       };
-
-       Ext.applyIf(me, {
-           title: gettext('Status'),
-           url: "/api2/json/pools/" + pool,
-           cwidth1: 150,
-           interval: 30000,
-           //height: 195,
-           rows: rows
-       });
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/pool/Summary.js b/www/manager5/pool/Summary.js
deleted file mode 100644 (file)
index 2f23de3..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-Ext.define('PVE.pool.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pvePoolSummary',
-
-    initComponent: function() {
-        var me = this;
-
-       var pool = me.pveSelNode.data.pool;
-       if (!pool) {
-           throw "no pool specified";
-       }
-
-       var statusview = Ext.create('PVE.pool.StatusView', {
-           pveSelNode: me.pveSelNode,
-           style: 'padding-top:0px'
-       });
-
-       var rstore = statusview.rstore;
-
-       Ext.apply(me, {
-           autoScroll: true,
-           bodyStyle: 'padding:10px',
-           defaults: {
-               style: 'padding-top:10px',
-               width: 800
-           },
-           items: [ statusview ]
-       });
-
-       me.on('show', rstore.startUpdate);
-       me.on('hide', rstore.stopUpdate);
-       me.on('destroy', rstore.stopUpdate);    
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/tree/ResourceTree.js b/www/manager5/tree/ResourceTree.js
deleted file mode 100644 (file)
index 48c1da6..0000000
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Left Treepanel, containing all the ressources we manage in this datacenter: server nodes, server storages, VMs and Containers
- */
-Ext.define('PVE.tree.ResourceTree', {
-    extend: 'Ext.tree.TreePanel',
-    alias: ['widget.pveResourceTree'],
-
-    statics: {
-       typeDefaults: {
-           node: { 
-               iconCls: 'x-tree-node-server',
-               text: gettext('Node list')
-           },
-           pool: { 
-               iconCls: 'x-tree-node-pool',
-               text: gettext('Resource Pool')
-           },
-           storage: {
-               iconCls: 'x-tree-node-harddisk',
-               text: gettext('Storage list')
-           },
-           qemu: {
-               iconCls: 'x-tree-node-computer',
-               text: gettext('Virtual Machine')
-           },
-           lxc: {
-               iconCls: 'x-tree-node-lxc',
-               text: gettext('LXC Container')
-           } 
-       }
-    },
-
-    // private
-    nodeSortFn: function(node1, node2) {
-       var n1 = node1.data;
-       var n2 = node2.data;
-
-       if ((n1.groupbyid && n2.groupbyid) ||
-           !(n1.groupbyid || n2.groupbyid)) {
-
-           var tcmp;
-
-           var v1 = n1.type;
-           var v2 = n2.type;
-
-           if ((tcmp = v1 > v2 ? 1 : (v1 < v2 ? -1 : 0)) != 0) {
-               return tcmp;
-           }
-
-           // numeric compare for VM IDs
-           // sort templates after regular VMs
-           if (v1 === 'qemu' || v1 === 'lxc') {
-               if (n1.template && !n2.template) {
-                   return 1;
-               } else if (n2.template && !n1.template) {
-                   return -1;
-               }
-               v1 = n1.vmid;
-               v2 = n2.vmid;
-               if ((tcmp = v1 > v2 ? 1 : (v1 < v2 ? -1 : 0)) != 0) {
-                   return tcmp;
-               }
-           }
-
-           return n1.text > n2.text ? 1 : (n1.text < n2.text ? -1 : 0);
-       } else if (n1.groupbyid) {
-           return -1;
-       } else if (n2.groupbyid) {
-           return 1;
-       }
-    },
-
-    // private: fast binary search
-    findInsertIndex: function(node, child, start, end) {
-       var me = this;
-
-       var diff = end - start;
-
-       var mid = start + (diff>>1);
-
-       if (diff <= 0) {
-           return start;
-       }
-
-       var res = me.nodeSortFn(child, node.childNodes[mid]);
-       if (res <= 0) {
-           return me.findInsertIndex(node, child, start, mid);
-       } else {
-           return me.findInsertIndex(node, child, mid + 1, end);
-       }
-    },
-
-    setIconCls: function(info) {
-       var me = this;
-
-       var defaults = PVE.tree.ResourceTree.typeDefaults[info.type];
-       if (defaults && defaults.iconCls) {
-           var running = info.running ? '-running' : '';
-           var template = info.template ? '-template' : '';
-           info.iconCls = defaults.iconCls + running + template;
-       }
-    },
-
-    // private
-    addChildSorted: function(node, info) {
-       var me = this;
-
-       me.setIconCls(info);
-
-       var defaults;
-       if (info.groupbyid) {
-           info.text = info.groupbyid;     
-           if (info.type === 'type') {
-               defaults = PVE.tree.ResourceTree.typeDefaults[info.groupbyid];
-               if (defaults && defaults.text) {
-                   info.text = defaults.text;
-               }
-           }
-       }
-       var child = Ext.create('PVETree', info);
-
-        var cs = node.childNodes;
-       var pos;
-       if (cs) {
-           pos = cs[me.findInsertIndex(node, child, 0, cs.length)];
-       }
-
-       node.insertBefore(child, pos);
-
-       return child;
-    },
-
-    // private
-    groupChild: function(node, info, groups, level) {
-       var me = this;
-
-       var groupby = groups[level];
-       var v = info[groupby];
-
-       if (v) {
-            var group = node.findChild('groupbyid', v);
-           if (!group) {
-               var groupinfo;
-               if (info.type === groupby) {
-                   groupinfo = info;
-               } else {
-                   groupinfo = {
-                       type: groupby,
-                       id : groupby + "/" + v
-                   };
-                   if (groupby !== 'type') {
-                       groupinfo[groupby] = v;
-                   }
-               }
-               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;
-           }
-           if (group) {
-               return me.groupChild(group, info, groups, level + 1);
-           }
-       }
-
-       return me.addChildSorted(node, info);
-    },
-
-    initComponent : function() {
-       var me = this;
-
-       var rstore = PVE.data.ResourceStore;
-       var sp = Ext.state.Manager.getProvider();
-
-       if (!me.viewFilter) {
-           me.viewFilter = {};
-       }
-
-       var pdata = {
-           dataIndex: {},
-           updateCount: 0
-       };
-
-       var store = Ext.create('Ext.data.TreeStore', {
-           model: 'PVETree',
-           root: {
-               expanded: true,
-               id: 'root',
-               text: gettext('Datacenter')
-           }
-       });
-
-       var stateid = 'rid';
-
-       var updateTree = function() {
-           var tmp;
-
-           // fixme: suspend events ?
-
-           var rootnode = me.store.getRootNode();
-           
-           // remember selected node (and all parents)
-           var sm = me.getSelectionModel();
-
-           var lastsel = sm.getSelection()[0];
-           var parents = [];
-           var p = lastsel;
-           while (p && !!(p = p.parentNode)) {
-               parents.push(p);
-           }
-
-           var index = pdata.dataIndex;
-
-           var groups = me.viewFilter.groups || [];
-           var filterfn = me.viewFilter.filterfn;
-
-           // remove vanished or changed items
-           var key;
-           for (key in index) {
-               if (index.hasOwnProperty(key)) {
-                   var olditem = index[key];
-
-                   // getById() use find(), which is slow (ExtJS4 DP5) 
-                   //var item = rstore.getById(olditem.data.id);
-                   var item = rstore.data.get(olditem.data.id);
-
-                   var changed = false;
-                   if (item) {
-                       // test if any grouping attributes changed
-                       var i, len;
-                       for (i = 0, len = groups.length; i < len; i++) {
-                           var attr = groups[i];
-                           if (item.data[attr] != olditem.data[attr]) {
-                               //console.log("changed " + attr);
-                               changed = true;
-                               break;
-                           }
-                       }
-                       if ((item.data.text !== olditem.data.text) ||
-                           (item.data.node !== olditem.data.node) ||
-                           (item.data.running !== olditem.data.running) ||
-                           (item.data.template !== olditem.data.template)) {
-                           //console.log("changed node/text/running " + olditem.data.id);
-                           changed = true;
-                       }
-
-                       // fixme: also test filterfn()?
-                   }
-
-                   if (!item || changed) {
-                       //console.log("REM UID: " + key + " ITEM " + olditem.data.id);
-                       if (olditem.isLeaf()) {
-                           delete index[key];
-                           var parentNode = olditem.parentNode;
-                           parentNode.removeChild(olditem, true);
-                       } else {
-                           if (item && changed) {
-                               olditem.beginEdit();
-                               //console.log("REM UPDATE UID: " + key + " ITEM " + item.data.running);
-                               var info = olditem.data;
-                               Ext.apply(info, item.data);
-                               me.setIconCls(info);
-                               olditem.commit();
-                           }
-                       }
-                   }
-               }
-           }
-
-           // add new items
-            rstore.each(function(item) {
-               var olditem = index[item.data.id];
-               if (olditem) {
-                   return;
-               }
-
-               if (filterfn && !filterfn(item)) {
-                   return;
-               }
-
-               //console.log("ADD UID: " + item.data.id);
-
-               var info = Ext.apply({ leaf: true }, item.data);
-
-               var child = me.groupChild(rootnode, info, groups, 0);
-               if (child) {
-                   index[item.data.id] = child;
-               }
-           });
-
-           // select parent node is selection vanished
-           if (lastsel && !rootnode.findChild('id', lastsel.data.id, true)) {
-               lastsel = rootnode;
-               while (!!(p = parents.shift())) {
-                   if (!!(tmp = rootnode.findChild('id', p.data.id, true))) {
-                       lastsel = tmp;
-                       break;
-                   }
-               }
-               me.selectById(lastsel.data.id);
-           }
-
-           if (!pdata.updateCount) {
-               rootnode.collapse();
-               rootnode.expand();
-               me.applyState(sp.get(stateid));
-           }
-
-           pdata.updateCount++;
-       };
-
-       var statechange = function(sp, key, value) {
-           if (key === stateid) {
-               me.applyState(value);
-           }
-       };
-
-       sp.on('statechange', statechange);
-
-       Ext.apply(me, {
-           store: store,
-           viewConfig: {
-               // note: animate cause problems with applyState
-               animate: false
-           },
-           //useArrows: true,
-            //rootVisible: false,
-            //title: 'Resource Tree',
-           listeners: {
-               itemcontextmenu: function(v, record, item, index, event) {
-                   event.stopEvent();
-                   //v.select(record);
-                   var menu;
-                   
-                   if (record.data.type === 'qemu' && !record.data.template) {
-                       menu = Ext.create('PVE.qemu.CmdMenu', {
-                           pveSelNode: record
-                       });
-                   } else if (record.data.type === 'qemu' && record.data.template) {
-                       menu = Ext.create('PVE.qemu.TemplateMenu', {
-                           pveSelNode: record
-                       });
-                   } else if (record.data.type === 'lxc') {
-                       menu = Ext.create('PVE.lxc.CmdMenu', {
-                           pveSelNode: record
-                       });
-                   } else {
-                       return;
-                   }
-
-                   menu.showAt(event.getXY());
-               },
-               destroy: function() {
-                   rstore.un("load", updateTree);
-               }
-           },
-           setViewFilter: function(view) {
-               me.viewFilter = view;
-               me.clearTree();
-               updateTree();
-           },
-           clearTree: function() {
-               pdata.updateCount = 0;
-               var rootnode = me.store.getRootNode();
-               rootnode.collapse();
-               rootnode.removeAll(true);
-               pdata.dataIndex = {};
-               me.getSelectionModel().deselectAll();
-           },
-           selectExpand: function(node) {
-               var sm = me.getSelectionModel();
-               if (!sm.isSelected(node)) {
-                   sm.select(node);
-                   var cn = node;
-                   while (!!(cn = cn.parentNode)) {
-                       if (!cn.isExpanded()) {
-                           cn.expand();
-                       }
-                   }
-               }
-           },
-           selectById: function(nodeid) {
-               var rootnode = me.store.getRootNode();
-               var sm = me.getSelectionModel();
-               var node;
-               if (nodeid === 'root') {
-                   node = rootnode;
-               } else {
-                   node = rootnode.findChild('id', nodeid, true);
-               }
-               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);
-               }
-           },
-           applyState : function(state) {
-               var sm = me.getSelectionModel();
-               if (state && state.value) {
-                   me.selectById(state.value);
-               } else {
-                   sm.deselectAll();
-               }
-           }
-       });
-
-       me.callParent();
-
-       var sm = me.getSelectionModel();
-       sm.on('select', function(sm, n) {                   
-           sp.set(stateid, { value: n.data.id});
-       });
-
-       rstore.on("load", updateTree);
-       rstore.startUpdate();
-       //rstore.stopUpdate();
-    }
-
-});
diff --git a/www/manager5/window/Backup.js b/www/manager5/window/Backup.js
deleted file mode 100644 (file)
index f7b30d5..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-Ext.define('PVE.window.Backup', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    initComponent : function() {
-       var me = this;
-
-       if (!me.nodename) {
-           throw "no node name specified";
-       }
-
-       if (!me.vmid) {
-           throw "no VM ID specified";
-       }
-
-       if (!me.vmtype) {
-           throw "no VM type specified";
-       }
-
-       var storagesel = Ext.create('PVE.form.StorageSelector', {
-           nodename: me.nodename,
-           name: 'storage',
-           value: me.storage,
-           fieldLabel: gettext('Storage'),
-           storageContent: 'backup',
-           allowBlank: false
-       });
-
-       me.formPanel = Ext.create('Ext.form.Panel', {
-           bodyPadding: 10,
-           border: false,
-           fieldDefaults: {
-               labelWidth: 100,
-               anchor: '100%'
-           },
-           items: [
-               storagesel,
-               {
-                   xtype: 'pveBackupModeSelector',
-                   fieldLabel: gettext('Mode'),
-                   value: 'snapshot',
-                   name: 'mode'
-               },
-               {
-                   xtype: 'pveCompressionSelector',
-                   name: 'compress',
-                   value: 'lzo',
-                   fieldLabel: gettext('Compression')
-               }
-           ]
-       });
-
-       var form = me.formPanel.getForm();
-
-       var submitBtn = Ext.create('Ext.Button', {
-           text: gettext('Backup'),
-           handler: function(){
-               var storage = storagesel.getValue();
-               var values = form.getValues();
-               var params = {
-                   storage: storage,
-                   vmid: me.vmid,
-                   mode: values.mode,
-                   remove: 0
-               };
-               if (values.compress) {
-                   params.compress = values.compress;
-               }
-
-               PVE.Utils.API2Request({
-                   url: '/nodes/' + me.nodename + '/vzdump',
-                   params: params,
-                   method: 'POST',
-                   failure: function (response, opts) {
-                       Ext.Msg.alert('Error',response.htmlStatus);
-                   },
-                   success: function(response, options) {
-                       var upid = response.result.data;
-                       
-                       var win = Ext.create('PVE.window.TaskViewer', { 
-                           upid: upid
-                       });
-                       win.show();
-                       me.close();
-                   }
-               });
-           }
-       });
-
-       var title = gettext('Backup') + " " + 
-           ((me.vmtype === 'openvz') ? "CT" : "VM") +
-           " " + me.vmid;
-
-       Ext.apply(me, {
-           title: title,
-           width: 350,
-           modal: true,
-           layout: 'auto',
-           border: false,
-           items: [ me.formPanel ],
-           buttons: [ submitBtn ]
-       });
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/window/Edit.js b/www/manager5/window/Edit.js
deleted file mode 100644 (file)
index e150cf1..0000000
+++ /dev/null
@@ -1,255 +0,0 @@
-// fixme: how can we avoid those lint errors?
-/*jslint confusion: true */
-Ext.define('PVE.window.Edit', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.pveWindowEdit',
-    resizable: false,
-
-    // use this tio atimatically generate a title like
-    // Create: <subject>
-    subject: undefined,
-
-    // set create to true if you want a Create button (instead 
-    // OK and RESET) 
-    create: false, 
-
-    // set to true if you want an Add button (instead of Create)
-    isAdd: false,
-
-    // set to true if you want an Remove button (instead of Create)
-    isRemove: false,
-
-    backgroundDelay: 0,
-
-    showProgress: false,
-
-    isValid: function() {
-       var me = this;
-
-       var form = me.formPanel.getForm();
-       return form.isValid();
-    },
-
-    getValues: function(dirtyOnly) {
-       var me = this;
-
-        var values = {};
-
-       var form = me.formPanel.getForm();
-
-        form.getFields().each(function(field) {
-            if (!field.up('inputpanel') && (!dirtyOnly || field.isDirty())) {
-                PVE.Utils.assemble_field_data(values, field.getSubmitData());
-            }
-        });
-
-       Ext.Array.each(me.query('inputpanel'), function(panel) {
-           PVE.Utils.assemble_field_data(values, panel.getValues(dirtyOnly));
-       });
-
-        return values;
-    },
-
-    setValues: function(values) {
-       var me = this;
-
-       var form = me.formPanel.getForm();
-
-       Ext.iterate(values, function(fieldId, val) {
-           var field = form.findField(fieldId);
-           if (field && !field.up('inputpanel')) {
-               field.setValue(val);
-                if (form.trackResetOnLoad) {
-                    field.resetOriginalValue();
-                }
-            }
-       });
-       Ext.Array.each(me.query('inputpanel'), function(panel) {
-           panel.setValues(values);
-       });
-    },
-
-    submit: function() {
-       var me = this;
-
-       var form = me.formPanel.getForm();
-
-       var values = me.getValues();
-       Ext.Object.each(values, function(name, val) {
-           if (values.hasOwnProperty(name)) {
-                if (Ext.isArray(val) && !val.length) {
-                   values[name] = '';
-               }
-           }
-       });
-
-       if (me.digest) {
-           values.digest = me.digest;
-       }
-
-       if (me.backgroundDelay) {
-           values.background_delay = me.backgroundDelay;
-       }
-
-       var url =  me.url;
-       if (me.method === 'DELETE') {
-           url = url + "?" + Ext.Object.toQueryString(values);
-           values = undefined;
-       }
-
-       PVE.Utils.API2Request({
-           url: url,
-           waitMsgTarget: me,
-           method: me.method || (me.backgroundDelay ? 'POST' : 'PUT'),
-           params: values,
-           failure: function(response, options) {
-               if (response.result && response.result.errors) {
-                   form.markInvalid(response.result.errors);
-               }
-               Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-           },
-           success: function(response, options) {
-               me.close();
-               if ((me.backgroundDelay || me.showProgress) && 
-                   response.result.data) {
-                   var upid = response.result.data;
-                   var win = Ext.create('PVE.window.TaskProgress', { 
-                       upid: upid
-                   });
-                   win.show();
-               }
-           }
-       });
-    },
-
-    load: function(options) {
-       var me = this;
-
-       var form = me.formPanel.getForm();
-
-       options = options || {};
-
-       var newopts = Ext.apply({
-           waitMsgTarget: me
-       }, options);
-
-       var createWrapper = function(successFn) {
-           Ext.apply(newopts, {
-               url: me.url,
-               method: 'GET',
-               success: function(response, opts) {
-                   form.clearInvalid();
-                   me.digest = response.result.data.digest;
-                   if (successFn) {
-                       successFn(response, opts);
-                   } else {
-                       me.setValues(response.result.data);
-                   }
-                   // hack: fix ExtJS bug
-                   Ext.Array.each(me.query('radiofield'), function(f) {
-                       f.resetOriginalValue();
-                   });
-               },
-               failure: function(response, opts) {
-                   Ext.Msg.alert(gettext('Error'), response.htmlStatus, function() {
-                       me.close();
-                   });
-               }
-           });
-       };
-
-       createWrapper(options.success);
-
-       PVE.Utils.API2Request(newopts);
-    },
-
-    initComponent : function() {
-       var me = this;
-
-       if (!me.url) {
-           throw "no url specified";
-       }
-
-       var items = Ext.isArray(me.items) ? me.items : [ me.items ];
-
-       me.items = undefined;
-
-       me.formPanel = Ext.create('Ext.form.Panel', {
-           url: me.url,
-           method: me.method || 'PUT',
-           trackResetOnLoad: true,
-           bodyPadding: 10,
-           border: false,
-           defaults: {
-               border: false
-           },
-           fieldDefaults: Ext.apply({}, me.fieldDefaults, {
-               labelWidth: 100,
-               anchor: '100%'
-            }),
-           items: items
-       });
-
-       var form = me.formPanel.getForm();
-
-       var submitBtn = Ext.create('Ext.Button', {
-           text: me.create ? (me.isAdd ? gettext('Add') : ( me.isRemove ? gettext('Remove') : gettext('Create'))) : gettext('OK'),
-           disabled: !me.create,
-           handler: function() {
-               me.submit();
-           }
-       });
-
-       var resetBtn = Ext.create('Ext.Button', {
-           text: 'Reset',
-           disabled: true,
-           handler: function(){
-               form.reset();
-           }
-       });
-
-       var set_button_status = function() {
-           var valid = form.isValid();
-           var dirty = form.isDirty();
-           submitBtn.setDisabled(!valid || !(dirty || me.create));
-           resetBtn.setDisabled(!dirty);
-       };
-
-       form.on('dirtychange', set_button_status);
-       form.on('validitychange', set_button_status);
-
-       var colwidth = 300;
-       if (me.fieldDefaults && me.fieldDefaults.labelWidth) {
-           colwidth += me.fieldDefaults.labelWidth - 100;
-       }
-       
-
-       var twoColumn = items[0].column1 || items[0].column2;
-
-       if (me.subject && !me.title) {
-           me.title = PVE.Utils.dialog_title(me.subject, me.create, me.isAdd);
-       }
-
-       if (me.create) {
-               me.buttons = [ submitBtn ] ;
-       } else {
-               me.buttons = [ submitBtn, resetBtn ];
-       }
-
-       Ext.applyIf(me, {
-           modal: true,
-           width: twoColumn ? colwidth*2 : colwidth,
-           border: false,
-           items: [ me.formPanel ],
-       });
-
-       me.callParent();
-
-       // always mark invalid fields
-       me.on('afterlayout', function() {
-           me.isValid();
-       });
-    }
-});
diff --git a/www/manager5/window/LoginWindow.js b/www/manager5/window/LoginWindow.js
deleted file mode 100644 (file)
index 3331444..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-Ext.define('PVE.window.LoginWindow', {
-    extend: 'Ext.window.Window',
-
-    // private
-    onLogon: function() {
-       var me = this;
-
-       var form = me.getComponent(0).getForm();
-
-       if(form.isValid()){
-            me.el.mask(gettext('Please wait...'), 'x-mask-loading');
-
-           form.submit({
-               failure: function(f, resp){
-                   me.el.unmask();
-                   Ext.MessageBox.alert(gettext('Error'), 
-                                        gettext("Login failed. Please try again"), 
-                                        function() {
-                       var uf = form.findField('username');
-                       uf.focus(true, true);
-                   });
-               },
-               success: function(f, resp){
-                   me.el.unmask();
-                   
-                   var handler = me.handler || Ext.emptyFn;
-                   handler.call(me, resp.result.data);
-                   me.close();
-               }
-           });
-       }
-    },
-
-    initComponent: function() {
-       var me = this;
-
-       var otp_field = Ext.createWidget('textfield', { 
-           fieldLabel: gettext('OTP'), 
-           name: 'otp',
-           allowBlank: false,
-           hidden: true
-       });
-
-       Ext.apply(me, {
-           width: 400,
-           modal: true,
-           border: false,
-           draggable: true,
-           closable: false,
-           resizable: false,
-           layout: 'auto',
-           title: gettext('Proxmox VE Login'),
-
-           items: [{
-               xtype: 'form',
-               frame: true,
-               url: '/api2/extjs/access/ticket',
-
-               fieldDefaults: {
-                   labelAlign: 'right'
-               },
-
-               defaults: {
-                   anchor: '-5',
-                   allowBlank: false
-               },
-               
-               items: [
-                   { 
-                       xtype: 'textfield', 
-                       fieldLabel: gettext('User name'), 
-                       name: 'username',
-                       blankText: gettext("Enter your user name"),
-                       listeners: {
-                           afterrender: function(f) {
-                               // Note: only works if we pass delay 1000
-                               f.focus(true, 1000);
-                           },
-                           specialkey: function(f, e) {
-                               if (e.getKey() === e.ENTER) {
-                                   var pf = me.query('textfield[name="password"]')[0];
-                                   if (pf.getValue()) {
-                                       me.onLogon();
-                                   } else {
-                                       pf.focus(false);
-                                   }
-                               }
-                           }
-                       }
-                   },
-                   { 
-                       xtype: 'textfield', 
-                       inputType: 'password',
-                       fieldLabel: gettext('Password'), 
-                       name: 'password',
-                       blankText: gettext("Enter your password"),
-                       listeners: {
-                           specialkey: function(field, e) {
-                               if (e.getKey() === e.ENTER) {
-                                   me.onLogon();
-                               }
-                           }
-                       }
-                   },
-                   otp_field,
-                   {
-                       xtype: 'pveRealmComboBox',
-                       name: 'realm',
-                       listeners: {
-                           change: function(f, value) {
-                               if (f.needOTP(value)) {
-                                   otp_field.setVisible(true);
-                                   otp_field.setDisabled(false);
-                               } else {
-                                   otp_field.setVisible(false);
-                                   otp_field.setDisabled(true);
-                               }
-                           }
-                       }
-                   },
-                   {   
-                       xtype: 'pveLanguageSelector',
-                       fieldLabel: gettext('Language'), 
-                       value: Ext.util.Cookies.get('PVELangCookie') || 'en',
-                       name: 'lang',
-                       submitValue: false,
-                       listeners: {
-                           change: function(t, value) {
-                               var dt = Ext.Date.add(new Date(), Ext.Date.YEAR, 10);
-                               Ext.util.Cookies.set('PVELangCookie', value, dt);
-                               me.el.mask(gettext('Please wait...'), 'x-mask-loading');
-                               window.location.reload();
-                           }
-                       }
-                   }
-               ],
-               buttons: [
-                   {
-                       text: gettext('Login'),
-                       handler: function(){
-                           me.onLogon();
-                       }
-                   }
-               ]
-           }]
-       });
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/window/Migrate.js b/www/manager5/window/Migrate.js
deleted file mode 100644 (file)
index 322e3f6..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-Ext.define('PVE.window.Migrate', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    migrate: function(target, online) {
-       var me = this;
-       PVE.Utils.API2Request({
-           params: { target: target, online: online },
-           url: '/nodes/' + me.nodename + '/' + me.vmtype + '/' + me.vmid + "/migrate",
-           waitMsgTarget: me,
-           method: 'POST',
-           failure: function(response, opts) {
-               Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-           },
-           success: function(response, options) {
-               var upid = response.result.data;
-
-               var win = Ext.create('PVE.window.TaskViewer', { 
-                   upid: upid
-               });
-               win.show();
-               me.close();
-           }
-       });
-    },
-
-    initComponent : function() {
-       var me = this;
-
-       if (!me.nodename) {
-           throw "no node name specified";
-       }
-
-       if (!me.vmid) {
-           throw "no VM ID specified";
-       }
-
-       if (!me.vmtype) {
-           throw "no VM type specified";
-       }
-
-       var running = false;
-       var vmrec = PVE.data.ResourceStore.findRecord('vmid', me.vmid,
-                                                     0, false, false, true);
-       if (vmrec && vmrec.data && vmrec.data.running) {
-           running = true;
-       }
-
-       me.formPanel = Ext.create('Ext.form.Panel', {
-           bodyPadding: 10,
-           border: false,
-           fieldDefaults: {
-               labelWidth: 100,
-               anchor: '100%'
-           },
-           items: [
-               {
-                   xtype: 'PVE.form.NodeSelector',
-                   name: 'target',
-                   fieldLabel: gettext('Target node'),
-                   allowBlank: false,
-                   onlineValidator: true
-               },
-               {
-                   xtype: 'pvecheckbox',
-                   name: 'online',
-                   uncheckedValue: 0,
-                   defaultValue: 0,
-                   checked: running,
-                   fieldLabel: gettext('Online')
-               }
-           ]
-       });
-
-       var form = me.formPanel.getForm();
-
-       var submitBtn = Ext.create('Ext.Button', {
-           text: gettext('Migrate'),
-           handler: function() {
-               var values = form.getValues();
-               me.migrate(values.target, values.online);
-           }
-       });
-
-       Ext.apply(me, {
-           title: gettext('Migrate') + ' VM ' + me.vmid,
-           width: 350,
-           modal: true,
-           layout: 'auto',
-           border: false,
-           items: [ me.formPanel ],
-           buttons: [ submitBtn ]
-       });
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/window/MigrateAll.js b/www/manager5/window/MigrateAll.js
deleted file mode 100644 (file)
index fb677f5..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-Ext.define('PVE.window.MigrateAll', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    migrate: function(target, maxworkers) {
-       var me = this;
-       PVE.Utils.API2Request({
-           params: { target: target, maxworkers: maxworkers},
-           url: '/nodes/' + me.nodename + '/' + "/migrateall",
-           waitMsgTarget: me,
-           method: 'POST',
-           failure: function(response, opts) {
-               Ext.Msg.alert('Error', response.htmlStatus);
-           },
-           success: function(response, options) {
-               var upid = response.result.data;
-
-               var win = Ext.create('PVE.window.TaskViewer', {
-                   upid: upid
-               });
-               win.show();
-               me.close();
-           }
-       });
-    },
-
-    initComponent : function() {
-       var me = this;
-
-       if (!me.nodename) {
-           throw "no node name specified";
-       }
-
-       me.formPanel = Ext.create('Ext.form.Panel', {
-           bodyPadding: 10,
-           border: false,
-           fieldDefaults: {
-               labelWidth: 100,
-               anchor: '100%'
-           },
-           items: [
-               {
-                   xtype: 'PVE.form.NodeSelector',
-                   name: 'target',
-                   fieldLabel: 'Target node',
-                   allowBlank: false,
-                   onlineValidator: true
-               },
-               {
-                   xtype: 'numberfield',
-                   name: 'maxworkers',
-                   minValue: 1,
-                   maxValue: 100,
-                   value: 1,
-                   fieldLabel: 'Parallel jobs',
-                   allowBlank: false
-               },
-           ]
-       });
-
-       var form = me.formPanel.getForm();
-
-       var submitBtn = Ext.create('Ext.Button', {
-           text: 'Migrate',
-           handler: function() {
-               var values = form.getValues();
-               me.migrate(values.target, values.maxworkers);
-           }
-       });
-
-       Ext.apply(me, {
-           title: "Migrate All VMs",
-           width: 350,
-           modal: true,
-           layout: 'auto',
-           border: false,
-           items: [ me.formPanel ],
-           buttons: [ submitBtn ]
-       });
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/window/NotesEdit.js b/www/manager5/window/NotesEdit.js
deleted file mode 100644 (file)
index 650b196..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-Ext.define('PVE.window.NotesEdit', {
-    extend: 'PVE.window.Edit',
-
-    initComponent : function() {
-       var me = this;
-
-       Ext.apply(me, {
-           title: gettext('Notes'),
-           width: 600,
-           layout: 'fit',
-           items: {
-               xtype: 'textarea',
-               name: 'description',
-               rows: 7,
-               value: '',
-               hideLabel: true
-           }
-       });
-
-       me.callParent();
-
-       me.load();
-    }
-});
diff --git a/www/manager5/window/Restore.js b/www/manager5/window/Restore.js
deleted file mode 100644 (file)
index b862157..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-Ext.define('PVE.window.Restore', {
-    extend: 'Ext.window.Window', // fixme: PVE.window.Edit?
-
-    resizable: false,
-
-    initComponent : function() {
-       var me = this;
-
-       if (!me.nodename) {
-           throw "no node name specified";
-       }
-
-       if (!me.volid) {
-           throw "no volume ID specified";
-       }
-
-       if (!me.vmtype) {
-           throw "no vmtype specified";
-       }
-
-       var storagesel = Ext.create('PVE.form.StorageSelector', {
-           nodename: me.nodename,
-           name: 'storage',
-           value: '',
-           fieldLabel: gettext('Storage'),
-           storageContent: (me.vmtype === 'lxc') ? 'rootdir' : 'images',
-           allowBlank: true
-       });
-
-       me.formPanel = Ext.create('Ext.form.Panel', {
-           bodyPadding: 10,
-           border: false,
-           fieldDefaults: {
-               labelWidth: 100,
-               anchor: '100%'
-           },
-           items: [
-               {
-                   xtype: 'displayfield',
-                   value: me.volidText || me.volid,
-                   fieldLabel: gettext('Source')
-               },
-               storagesel,
-               {
-                   xtype: me.vmid ? 'displayfield' : 'pveVMIDSelector',
-                   name: 'vmid',
-                   fieldLabel: 'VM ID',
-                   value: me.vmid,
-                   loadNextFreeVMID: me.vmid ? false: true,
-                   validateExists: false
-               }
-           ]
-       });
-
-       var form = me.formPanel.getForm();
-
-       var doRestore = function(url, params) {
-           PVE.Utils.API2Request({
-               url: url,
-               params: params,
-               method: 'POST',
-               waitMsgTarget: me,
-               failure: function (response, opts) {
-                   Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-               },
-               success: function(response, options) {
-                   var upid = response.result.data;
-                   
-                   var win = Ext.create('PVE.window.TaskViewer', { 
-                       upid: upid
-                   });
-                   win.show();
-                   me.close();
-               }
-           });
-       };
-
-       var submitBtn = Ext.create('Ext.Button', {
-           text: gettext('Restore'),
-           handler: function(){
-               var storage = storagesel.getValue();
-               var values = form.getValues();
-
-               var params = {
-                   storage: storage,
-                   vmid: me.vmid || values.vmid,
-                   force: me.vmid ? 1 : 0
-               };
-
-               var url;
-               if (me.vmtype === 'lxc') {
-                   url = '/nodes/' + me.nodename + '/lxc';
-                   params.ostemplate = me.volid;
-                   params.restore = 1;
-               } else if (me.vmtype === 'qemu') {
-                   url = '/nodes/' + me.nodename + '/qemu';
-                   params.archive = me.volid;
-               } else {
-                   throw 'unknown VM type';
-               }
-
-               if (me.vmid) {
-                   var msg = gettext('Are you sure you want to restore this VM?') + ' ' +
-                       gettext('This will permanently erase current VM data.');
-                   Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-                       if (btn !== 'yes') {
-                           return;
-                       }
-                       doRestore(url, params);
-                   });
-               } else {
-                   doRestore(url, params);
-               }
-           }
-       });
-
-       form.on('validitychange', function(f, valid) {
-           submitBtn.setDisabled(!valid);
-       });
-
-       var title = (me.vmtype === 'openvz') ? gettext('Restore CT') : 
-           gettext('Restore VM');
-
-       Ext.apply(me, {
-           title: title,
-           width: 500,
-           modal: true,
-           layout: 'auto',
-           border: false,
-           items: [ me.formPanel ],
-           buttons: [ submitBtn ]
-       });
-
-       me.callParent();
-    }
-});
diff --git a/www/manager5/window/TaskViewer.js b/www/manager5/window/TaskViewer.js
deleted file mode 100644 (file)
index 43b3cf7..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-Ext.define('PVE.window.TaskProgress', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.pveTaskProgress',
-
-    initComponent: function() {
-        var me = this;
-
-       if (!me.upid) {
-           throw "no task specified";
-       }
-
-       var task = PVE.Utils.parse_task_upid(me.upid);
-
-       var statstore = Ext.create('PVE.data.ObjectStore', {
-            url: "/api2/json/nodes/" + task.node + "/tasks/" + me.upid + "/status",
-           interval: 1000,
-           rows: {
-               status: { defaultValue: 'unknown' },
-               exitstatus: { defaultValue: 'unknown' }
-           }
-       });
-
-       me.on('destroy', statstore.stopUpdate); 
-
-       var getObjectValue = function(key, defaultValue) {
-           var rec = statstore.getById(key);
-           if (rec) {
-               return rec.data.value;
-           }
-           return defaultValue;
-       };
-
-       var pbar = Ext.create('Ext.ProgressBar', { text: 'running...' });
-
-       me.mon(statstore, 'load', function() {
-           var status = getObjectValue('status');
-           if (status === 'stopped') {
-               var exitstatus = getObjectValue('exitstatus');
-               if (exitstatus == 'OK') {
-                   pbar.reset();
-                   pbar.updateText("Done!");
-                   Ext.Function.defer(me.close, 1000, me);
-               } else {
-                   me.close();
-                   Ext.Msg.alert('Task failed', exitstatus);
-               }
-           }
-       });
-
-       var descr = PVE.Utils.format_task_description(task.type, task.id);
-
-       Ext.applyIf(me, {
-           title: "Task: " + descr,
-           width: 300,
-           layout: 'auto',
-           modal: true,
-           bodyPadding: 5,
-           items: pbar,
-           buttons: [
-               { 
-                   text: gettext('Details'),
-                   handler: function() {                       
-                       var win = Ext.create('PVE.window.TaskViewer', { 
-                           upid: me.upid
-                       });
-                       win.show();
-                       me.close();
-                   }
-               }
-           ]
-       });
-
-       me.callParent();
-
-       statstore.startUpdate();
-
-       pbar.wait();
-    }
-});
-
-// fixme: how can we avoid those lint errors?
-/*jslint confusion: true */
-
-Ext.define('PVE.window.TaskViewer', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.pveTaskViewer',
-
-    initComponent: function() {
-        var me = this;
-
-       if (!me.upid) {
-           throw "no task specified";
-       }
-
-       var task = PVE.Utils.parse_task_upid(me.upid);
-
-       var statgrid;
-
-       var rows = {
-           status: {
-               header: gettext('Status'),
-               defaultValue: 'unknown',
-               renderer: function(value) {
-                   if (value != 'stopped') {
-                       return value;
-                   }
-                   var es = statgrid.getObjectValue('exitstatus');
-                   if (es) {
-                       return value + ': ' + es;
-                   }
-               }
-           },
-           exitstatus: { 
-               visible: false
-           },
-           type: {
-               header: gettext('Task type'),
-               required: true
-           },
-           user: {
-               header: gettext('User name'),
-               required: true 
-           },
-           node: {
-               header: gettext('Node'),
-               required: true 
-           },
-           pid: {
-               header: gettext('Process ID'),
-               required: true
-           },
-           starttime: {
-               header: gettext('Start Time'),
-               required: true, 
-               renderer: PVE.Utils.render_timestamp
-           },
-           upid: {
-               header: gettext('Unique task ID')
-           }
-       };
-
-       var statstore = Ext.create('PVE.data.ObjectStore', {
-            url: "/api2/json/nodes/" + task.node + "/tasks/" + me.upid + "/status",
-           interval: 1000,
-           rows: rows
-       });
-
-       me.on('destroy', statstore.stopUpdate); 
-
-       var stop_task = function() {
-           PVE.Utils.API2Request({
-               url: "/nodes/" + task.node + "/tasks/" + me.upid,
-               waitMsgTarget: me,
-               method: 'DELETE',
-               failure: function(response, opts) {
-                   Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-               }
-           });
-       };
-
-       var stop_btn1 = new Ext.Button({
-           text: gettext('Stop'),
-           disabled: true,
-           handler: stop_task
-       });
-
-       var stop_btn2 = new Ext.Button({
-           text: gettext('Stop'),
-           disabled: true,
-           handler: stop_task
-       });
-
-       statgrid = Ext.create('PVE.grid.ObjectGrid', {
-           title: gettext('Status'),
-           layout: 'fit',
-           tbar: [ stop_btn1 ],
-           rstore: statstore,
-           rows: rows,
-           border: false
-       });
-
-       var logView = Ext.create('PVE.panel.LogView', {
-           title: gettext('Output'),
-           tbar: [ stop_btn2 ],
-           border: false,
-           url: "/api2/extjs/nodes/" + task.node + "/tasks/" + me.upid + "/log"
-       });
-
-       me.mon(statstore, 'load', function() {
-           var status = statgrid.getObjectValue('status');
-           
-           if (status === 'stopped') {
-               logView.requestUpdate(undefined, true);
-               logView.scrollToEnd = false;
-               statstore.stopUpdate();
-           }
-
-           stop_btn1.setDisabled(status !== 'running');
-           stop_btn2.setDisabled(status !== 'running');
-       });
-
-       statstore.startUpdate();
-
-       Ext.applyIf(me, {
-           title: "Task viewer: " + task.desc,
-           width: 800,
-           height: 400,
-           layout: 'fit',
-           modal: true,
-           bodyPadding: 5,
-           items: [{
-               xtype: 'tabpanel',
-               region: 'center',
-               items: [ logView, statgrid ]
-           }]
-        });
-
-       me.callParent();
-
-       logView.fireEvent('show', logView);
-    }
-});
-
diff --git a/www/manager5/window/Wizard.js b/www/manager5/window/Wizard.js
deleted file mode 100644 (file)
index 0e6b02d..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-Ext.define('PVE.window.Wizard', {
-    extend: 'Ext.window.Window',
-    
-    getValues: function(dirtyOnly) {
-       var me = this;
-
-        var values = {};
-
-       var form = me.down('form').getForm();
-
-        form.getFields().each(function(field) {
-            if (!field.up('inputpanel') && (!dirtyOnly || field.isDirty())) {
-                PVE.Utils.assemble_field_data(values, field.getSubmitData());
-            }
-        });
-
-       Ext.Array.each(me.query('inputpanel'), function(panel) {
-           PVE.Utils.assemble_field_data(values, panel.getValues(dirtyOnly));
-       });
-
-        return values;
-    },
-
-    initComponent: function() {
-       var me = this;
-
-       var tabs = me.items || [];
-       delete me.items;
-       
-       /* 
-        * Items may have the following functions:
-        * validator(): per tab custom validation
-        * onSubmit(): submit handler
-        * onGetValues(): overwrite getValues results
-        */
-
-       Ext.Array.each(tabs, function(tab) {
-           tab.disabled = true;
-       });
-       tabs[0].disabled = false;
-
-       var check_card = function(card) {
-           var valid = true;
-           var fields = card.query('field, fieldcontainer');
-           if (card.isXType('fieldcontainer')) {
-               fields.unshift(card);
-           }
-           Ext.Array.each(fields, function(field) {
-               // Note: not all fielcontainer have isValid()
-               if (Ext.isFunction(field.isValid) && !field.isValid()) {
-                   valid = false;
-               }
-           });
-
-           if (Ext.isFunction(card.validator)) {
-               return card.validator();
-           }
-
-           return valid;
-       };
-
-
-       var tbar = Ext.create('Ext.toolbar.Toolbar', {
-            ui: 'footer',
-           region: 'south',
-           margins: '0 5 5 5',
-           items: [  
-               '->', 
-               { 
-                   text: gettext('Back'),
-                   disabled: true,
-                   itemId: 'back',
-                   minWidth: 60,
-                   handler: function() {
-                       var tp = me.down('#wizcontent');
-                       var atab = tp.getActiveTab();
-                       var prev = tp.items.indexOf(atab) - 1;
-                       if (prev < 0) {
-                           return;
-                       }
-                       var ntab = tp.items.getAt(prev);
-                       if (ntab) {
-                           tp.setActiveTab(ntab);
-                       }
-
-
-                   }
-               },
-               {
-                   text: gettext('Next'),
-                   disabled: true,
-                   itemId: 'next',
-                   minWidth: 60,
-                   handler: function() {
-
-                       var form = me.down('form').getForm();
-
-                       var tp = me.down('#wizcontent');
-                       var atab = tp.getActiveTab();
-                       if (!check_card(atab)) {
-                           return;
-                       }
-                                      
-                       var next = tp.items.indexOf(atab) + 1;
-                       var ntab = tp.items.getAt(next);
-                       if (ntab) {
-                           ntab.enable();
-                           tp.setActiveTab(ntab);
-                       }
-                       
-                   }
-               },
-               {
-                   text: gettext('Finish'),
-                   minWidth: 60,
-                   hidden: true,
-                   itemId: 'submit',
-                   handler: function() {
-                       var tp = me.down('#wizcontent');
-                       var atab = tp.getActiveTab();
-                       atab.onSubmit();
-                   }
-               }
-           ]
-       });
-
-       var display_header = function(newcard) {
-           var html = '<h1>' + newcard.title + '</h1>';
-           if (newcard.descr) {
-               html += newcard.descr;
-           }
-           me.down('#header').update(html);
-       };
-
-       var disable_at = function(card) {
-           var tp = me.down('#wizcontent');
-           var idx = tp.items.indexOf(card);
-           for(;idx < tp.items.getCount();idx++) {
-               var nc = tp.items.getAt(idx);
-               if (nc) {
-                   nc.disable();
-               }
-           }
-       };
-
-       var tabchange = function(tp, newcard, oldcard) {
-           if (newcard.onSubmit) {
-               me.down('#next').setVisible(false);
-               me.down('#submit').setVisible(true); 
-           } else {
-               me.down('#next').setVisible(true);
-               me.down('#submit').setVisible(false); 
-           }
-           var valid = check_card(newcard);
-           me.down('#next').setDisabled(!valid);    
-           me.down('#submit').setDisabled(!valid);    
-           me.down('#back').setDisabled(tp.items.indexOf(newcard) == 0);
-
-           if (oldcard && !check_card(oldcard)) {
-               disable_at(oldcard);
-           }
-
-           var next = tp.items.indexOf(newcard) + 1;
-           var ntab = tp.items.getAt(next);
-           if (valid && ntab && !newcard.onSubmit) {
-               ntab.enable();
-           }
-       };
-
-       if (me.subject && !me.title) {
-           me.title = PVE.Utils.dialog_title(me.subject, true, false);
-       }
-
-       Ext.applyIf(me, {
-           width: 620,
-           height: 400,
-           modal: true,
-           border: false,
-           draggable: true,
-           closable: true,
-           resizable: false,
-           layout: 'border',
-           items: [
-               {
-                   // disabled for now - not really needed
-                   hidden: true, 
-                   region: 'north',
-                   itemId: 'header',
-                   layout: 'fit',
-                   margins: '5 5 0 5',
-                   bodyPadding: 10,
-                   html: ''
-               },
-               {
-                   xtype: 'form',
-                   region: 'center',
-                   layout: 'fit',
-                   border: false,
-                   margins: '5 5 0 5',
-                   fieldDefaults: {
-                       labelWidth: 100,
-                       anchor: '100%'
-                   },
-                   items: [{
-                       itemId: 'wizcontent',
-                       xtype: 'tabpanel',
-                       activeItem: 0,
-                       bodyPadding: 10,
-                       listeners: {
-                           afterrender: function(tp) {
-                               var atab = this.getActiveTab();
-                               tabchange(tp, atab);
-                           },
-                           tabchange: function(tp, newcard, oldcard) {
-                               display_header(newcard);
-                               tabchange(tp, newcard, oldcard);
-                           }
-                       },
-                       items: tabs
-                   }]
-               },
-               tbar
-           ]
-       });
-       me.callParent();
-       display_header(tabs[0]);
-
-       Ext.Array.each(me.query('field'), function(field) {
-           field.on('validitychange', function(f) {
-               var tp = me.down('#wizcontent');
-               var atab = tp.getActiveTab();
-               var valid = check_card(atab);
-               me.down('#next').setDisabled(!valid);
-               me.down('#submit').setDisabled(!valid);    
-               var next = tp.items.indexOf(atab) + 1;
-               var ntab = tp.items.getAt(next);
-               if (!valid) {
-                   disable_at(ntab);
-               } else if (ntab && !atab.onSubmit) {
-                   ntab.enable();
-               }
-           });
-       });
-    }
-});
diff --git a/www/manager6/Parser.js b/www/manager6/Parser.js
new file mode 100644 (file)
index 0000000..5f15a76
--- /dev/null
@@ -0,0 +1,343 @@
+// Some configuration values are complex strings -
+// so we need parsers/generators for them.
+
+Ext.define('PVE.Parser', { statics: {
+
+    // this class only contains static functions
+
+    parseQemuNetwork: function(key, value) {
+       if (!(key && value)) {
+           return;
+       }
+
+       var res = {};
+
+       var errors = false;
+       Ext.Array.each(value.split(','), function(p) {
+           if (!p || p.match(/^\s*$/)) {
+               return; // continue
+           }
+
+           var match_res;
+
+           if ((match_res = p.match(/^(ne2k_pci|e1000|e1000-82540em|e1000-82544gc|e1000-82545em|vmxnet3|rtl8139|pcnet|virtio|ne2k_isa|i82551|i82557b|i82559er)(=([0-9a-f]{2}(:[0-9a-f]{2}){5}))?$/i)) !== null) {
+               res.model = match_res[1].toLowerCase();
+               if (match_res[3]) {
+                   res.macaddr = match_res[3];
+               }
+           } else if ((match_res = p.match(/^bridge=(\S+)$/)) !== null) {
+               res.bridge = match_res[1];
+           } else if ((match_res = p.match(/^rate=(\d+(\.\d+)?)$/)) !== null) {
+               res.rate = match_res[1];
+           } else if ((match_res = p.match(/^tag=(\d+(\.\d+)?)$/)) !== null) {
+                res.tag = match_res[1];
+           } else if ((match_res = p.match(/^firewall=(\d+)$/)) !== null) {
+                res.firewall = match_res[1];
+           } else if ((match_res = p.match(/^link_down=(\d+)$/)) !== null) {
+                res.disconnect = match_res[1];
+           } else if ((match_res = p.match(/^queues=(\d+)$/)) !== null) {
+                res.queues = match_res[1];
+           } else {
+               errors = true;
+               return false; // break
+           }
+       });
+
+       if (errors || !res.model) {
+           return;
+       }
+
+       return res;
+    },
+
+    printQemuNetwork: function(net) {
+
+       var netstr = net.model;
+       if (net.macaddr) {
+           netstr += "=" + net.macaddr;
+       }
+       if (net.bridge) {
+           netstr += ",bridge=" + net.bridge;
+           if (net.tag) {
+               netstr += ",tag=" + net.tag;
+           }
+           if (net.firewall) {
+               netstr += ",firewall=" + net.firewall;
+           }
+       }
+       if (net.rate) {
+           netstr += ",rate=" + net.rate;
+       }
+       if (net.queues) {
+           netstr += ",queues=" + net.queues;
+       }
+       if (net.disconnect) {
+           netstr += ",link_down=" + net.disconnect;
+       }
+       return netstr;
+    },
+
+    parseQemuDrive: function(key, value) {
+       if (!(key && value)) {
+           return;
+       }
+
+       var res = {};
+
+       var match_res = key.match(/^([a-z]+)(\d+)$/);
+       if (!match_res) {
+           return;
+       }
+       res['interface'] = match_res[1];
+       res.index = match_res[2];
+
+       var errors = false;
+       Ext.Array.each(value.split(','), function(p) {
+           if (!p || p.match(/^\s*$/)) {
+               return; // continue
+           }
+           var match_res = p.match(/^([a-z_]+)=(\S+)$/);
+           if (!match_res) {
+               if (!p.match(/\=/)) {
+                   res.file = p;
+                   return; // continue
+               }
+               errors = true;
+               return false; // break
+           }
+           var k = match_res[1];
+           if (k === 'volume') {
+               k = 'file';
+           }
+
+           if (Ext.isDefined(res[k])) {
+               errors = true;
+               return false; // break
+           }
+
+           var v = match_res[2];
+
+           if (k === 'cache' && v === 'off') {
+               v = 'none';
+           }
+
+           res[k] = v;
+       });
+
+       if (errors || !res.file) {
+           return;
+       }
+
+       return res;
+    },
+
+    printQemuDrive: function(drive) {
+
+       var drivestr = drive.file;
+
+       Ext.Object.each(drive, function(key, value) {
+           if (!Ext.isDefined(value) || key === 'file' ||
+               key === 'index' || key === 'interface') {
+               return; // continue
+           }
+           drivestr += ',' + key + '=' + value;
+       });
+
+       return drivestr;
+    },
+
+    parseOpenVZNetIf: function(value) {
+       if (!value) {
+           return;
+       }
+
+       var res = {};
+
+       var errors = false;
+       Ext.Array.each(value.split(';'), function(item) {
+           if (!item || item.match(/^\s*$/)) {
+               return; // continue
+           }
+
+           var data = {};
+           Ext.Array.each(item.split(','), function(p) {
+               if (!p || p.match(/^\s*$/)) {
+                   return; // continue
+               }
+               var match_res = p.match(/^(ifname|mac|bridge|host_ifname|host_mac|mac_filter)=(\S+)$/);
+               if (!match_res) {
+                   errors = true;
+                   return false; // break
+               }
+               if (match_res[1] === 'bridge'){
+                   var bridgevlanf = match_res[2];
+                   var bridge_res = bridgevlanf.match(/^(vmbr(\d+))(v(\d+))?(f)?$/);
+                   if (!bridge_res) {
+                       errors = true;
+                       return false; // break
+                   }
+                   data['bridge'] = bridge_res[1];
+                   data['tag'] = bridge_res[4];
+                   data['firewall'] = bridge_res[5] ? 1 : 0;
+               } else {
+                   data[match_res[1]] = match_res[2];
+               }
+           });
+
+           if (errors || !data.ifname) {
+               errors = true;
+               return false; // break
+           }
+
+           data.raw = item;
+
+           res[data.ifname] = data;
+       });
+
+       return errors ? undefined: res;
+    },
+
+    printOpenVZNetIf: function(netif) {
+       var netarray = [];
+
+       Ext.Object.each(netif, function(iface, data) {
+           var tmparray = [];
+           Ext.Array.each(['ifname', 'mac', 'bridge', 'host_ifname' , 'host_mac', 'mac_filter', 'tag', 'firewall'], function(key) {
+               var value = data[key];
+               if (key === 'bridge'){
+                   if(data['tag']){
+                       value = value + 'v' + data['tag'];
+                   }
+                   if (data['firewall']){
+                       value = value + 'f';
+                   }
+               }
+               if (value) {
+                   tmparray.push(key + '=' + value);
+               }
+
+           });
+           netarray.push(tmparray.join(','));
+       });
+
+       return netarray.join(';');
+    },
+
+    parseLxcNetwork: function(value) {
+       if (!value) {
+           return;
+       }
+
+       var data = {};
+       Ext.Array.each(value.split(','), function(p) {
+           if (!p || p.match(/^\s*$/)) {
+               return; // continue
+           }
+           var match_res = p.match(/^(bridge|hwaddr|mtu|name|ip|ip6|gw|gw6|firewall|tag)=(\S+)$/);
+           if (!match_res) {
+               // todo: simply ignore errors ?
+               return; // continue
+           }
+           data[match_res[1]] = match_res[2];
+       });
+
+       return data;
+    },
+
+    printLxcNetwork: function(data) {
+       var tmparray = [];
+       Ext.Array.each(['bridge', 'hwaddr', 'mtu', 'name', 'ip',
+                       'gw', 'ip6', 'gw6', 'firewall', 'tag'], function(key) {
+               var value = data[key];
+               if (value) {
+                   tmparray.push(key + '=' + value);
+               }
+       });
+       
+       return tmparray.join(',');
+    },
+
+    parseStartup: function(value) {
+       if (value === undefined) {
+           return;
+       }
+
+       var res = {};
+
+       var errors = false;
+       Ext.Array.each(value.split(','), function(p) {
+           if (!p || p.match(/^\s*$/)) {
+               return; // continue
+           }
+
+           var match_res;
+
+           if ((match_res = p.match(/^(order)?=(\d+)$/)) !== null) {
+               res.order = match_res[2];
+           } else if ((match_res = p.match(/^up=(\d+)$/)) !== null) {
+               res.up = match_res[1];
+           } else if ((match_res = p.match(/^down=(\d+)$/)) !== null) {
+                res.down = match_res[1];
+           } else {
+               errors = true;
+               return false; // break
+           }
+       });
+
+       if (errors) {
+           return;
+       }
+
+       return res;
+    },
+
+    printStartup: function(startup) {
+       var arr = [];
+       if (startup.order !== undefined && startup.order !== '') {
+           arr.push('order=' + startup.order);
+       }
+       if (startup.up !== undefined && startup.up !== '') {
+           arr.push('up=' + startup.up);
+       }
+       if (startup.down !== undefined && startup.down !== '') {
+           arr.push('down=' + startup.down);
+       }
+
+       return arr.join(',');
+    },
+
+    parseQemuSmbios1: function(value) {
+       var res = {};
+
+       Ext.Array.each(value.split(','), function(p) {
+           var kva = p.split(/=/, 2);
+           res[kva[0]] = kva[1];
+       });
+
+       return res;
+    },
+
+    printQemuSmbios1: function(data) {
+
+       var datastr = '';
+
+       Ext.Object.each(data, function(key, value) {
+           if (value === '') return;
+           datastr += (datastr !== '' ? ',' : '') + key + '=' + value;
+       });
+
+       return datastr;
+    },
+
+    parseTfaConfig: function(value) {
+       var res = {};
+
+       Ext.Array.each(value.split(','), function(p) {
+           var kva = p.split(/=/, 2);
+           res[kva[0]] = kva[1];
+       });
+
+       return res;
+    }
+
+}});
diff --git a/www/manager6/Readme.md b/www/manager6/Readme.md
new file mode 100644 (file)
index 0000000..81c3b26
--- /dev/null
@@ -0,0 +1,21 @@
+pveproxy with ExtJS 6 developpement mini howto
+==============================================
+
+unpack the ExtJS 6 sources, and copy them to /usr/share/pve-manager/ext6
+
+    cd www/ext6/
+    make install
+
+symlink the ext6 dir in pve-manager to the manager5 directory
+
+    cd /usr/share/pve-manager
+    ln -s PATH_TO_YOUR_GIT_REPO/www/manager6
+
+access the PVE proxy with ExtJS 6
+
+    https://localhost:8006/?ext6=1
+
+
+With the extra parameter **ext6=1**, pve-proxy will call the function **PVE::ExtJSIndex6::get_index()**
+which returns a HTML page, with all javascript symlinked from your git repository.
+Provided you included the javascript files in **PVE/ExtJSIndex5.pm**, after editing a file in the git repository, a simple refresh is enough to see your changes in the browser.
diff --git a/www/manager6/StateProvider.js b/www/manager6/StateProvider.js
new file mode 100644 (file)
index 0000000..a93c803
--- /dev/null
@@ -0,0 +1,233 @@
+/* This state provider keeps part of the state inside
+ * the browser history.
+ *
+ * We compress (shorten) url using dictionary based compression
+ * i.e. use column separated list instead of url encoded hash:
+ * #v\d*       version/format
+ * :=          indicates string values
+ * :\d+        lookup value in dictionary hash
+ * #v1:=value1:5:=value2:=value3:...
+*/
+
+Ext.define('PVE.StateProvider', {
+    extend: 'Ext.state.LocalStorageProvider',
+
+    // private
+    setHV: function(name, newvalue, fireEvents) {
+       var me = this;
+
+       var changes = false;
+       var oldtext = Ext.encode(me.UIState[name]);
+       var newtext = Ext.encode(newvalue);
+       if (newtext != oldtext) {
+           changes = true;
+           me.UIState[name] = newvalue;
+           //console.log("changed old " + name + " " + oldtext);
+           //console.log("changed new " + name + " " + newtext);
+           if (fireEvents) {
+               me.fireEvent("statechange", me, name, { value: newvalue });
+           }
+       }
+       return changes;
+    },
+
+    // private
+    hslist: [
+       // order is important for notifications
+       // [ name, default ]
+       ['view', 'server'],
+       ['rid', 'root'],
+       ['ltab', 'tasks'],
+       ['nodetab', ''],
+       ['storagetab', ''],
+       ['pooltab', ''],
+       ['kvmtab', ''],
+       ['ovztab', ''],
+       ['dctab', '']
+    ],
+
+    hprefix: 'v1',
+
+    compDict: {
+       snapshot: 29,
+       ha: 28,
+       support: 27,
+       pool: 26,
+       syslog: 25,
+       ubc: 24,
+       initlog: 23,
+       openvz: 22,
+       backup: 21,
+       ressources: 20,
+       content: 19,
+       root: 18,
+       domains: 17,
+       roles: 16,
+       groups: 15,
+       users: 14,
+       time: 13,
+       dns: 12,
+       network: 11,
+       services: 10,
+       options: 9,
+       console: 8,
+       hardware: 7,
+       permissions: 6,
+       summary: 5,
+       tasks: 4,
+       clog: 3,
+       storage: 2,
+       folder: 1,
+       server: 0
+    },
+
+    decodeHToken: function(token) {
+       var me = this;
+
+       var state = {};
+       if (!token) {
+           Ext.Array.each(me.hslist, function(rec) {
+               state[rec[0]] = rec[1];
+           });
+           return state;
+       }
+
+       // return Ext.urlDecode(token);
+
+       var items = token.split(':');
+       var prefix = items.shift();
+
+       if (prefix != me.hprefix) {
+           return me.decodeHToken();
+       }
+
+       Ext.Array.each(me.hslist, function(rec) {
+           var value = items.shift();
+           if (value) {
+               if (value[0] === '=') {
+                   value = decodeURIComponent(value.slice(1));
+               } else {
+                   Ext.Object.each(me.compDict, function(key, cv) {
+                       if (value == cv) {
+                           value = key;
+                           return false;
+                       }
+                   });
+               }
+           }
+           state[rec[0]] = value;
+       });
+
+       return state;
+    },
+
+    encodeHToken: function(state) {
+       var me = this;
+
+       // return Ext.urlEncode(state);
+
+       var ctoken = me.hprefix;
+       Ext.Array.each(me.hslist, function(rec) {
+           var value = state[rec[0]];
+           if (!Ext.isDefined(value)) {
+               value = rec[1];
+           }
+           value = encodeURIComponent(value);
+           if (!value) {
+               ctoken += ':';
+           } else {
+               var comp = me.compDict[value];
+               if (Ext.isDefined(comp)) {
+                   ctoken += ":" + comp;
+               } else {
+                   ctoken += ":=" + value;
+               }
+           }
+       });
+
+       return ctoken;
+    },
+
+    constructor: function(config){
+       var me = this;
+
+       me.callParent([config]);
+
+       me.UIState = me.decodeHToken(); // set default
+
+       var history_change_cb = function(token) {
+           //console.log("HC " + token);
+           if (!token) {
+               var res = window.confirm(gettext('Are you sure you want to navigate away from this page?'));
+               if (res){
+                   // process text value and close...
+                   Ext.History.back();
+               } else {
+                   Ext.History.forward();
+               }
+               return;
+           }
+
+           var newstate = me.decodeHToken(token);
+           Ext.Array.each(me.hslist, function(rec) {
+               if (typeof newstate[rec[0]] == "undefined") {
+                   return;
+               }
+               me.setHV(rec[0], newstate[rec[0]], true);
+           });
+       };
+
+       var start_token = Ext.History.getToken();
+       if (start_token) {
+           history_change_cb(start_token);
+       } else {
+           var htext = me.encodeHToken(me.UIState);
+           Ext.History.add(htext);
+       }
+
+       Ext.History.on('change', history_change_cb);
+    },
+
+    get: function(name, defaultValue){
+       /*jslint confusion: true */
+       var me = this;
+       var data;
+
+       if (typeof me.UIState[name] != "undefined") {
+           data = { value: me.UIState[name] };
+       } else {
+           data = me.callParent(arguments);
+           if (!data && name === 'GuiCap') {
+               data = { vms: {}, storage: {}, access: {}, nodes: {}, dc: {} };
+           }
+       }
+
+       //console.log("GET " + name + " " + Ext.encode(data));
+       return data;
+    },
+
+    clear: function(name){
+       var me = this;
+
+       if (typeof me.UIState[name] != "undefined") {
+           me.UIState[name] = null;
+       }
+
+       me.callParent(arguments);
+    },
+
+    set: function(name, value){
+        var me = this;
+
+       //console.log("SET " + name + " " + Ext.encode(value));
+       if (typeof me.UIState[name] != "undefined") {
+           var newvalue = value ? value.value : null;
+           if (me.setHV(name, newvalue, false)) {
+               var htext = me.encodeHToken(me.UIState);
+               Ext.History.add(htext);
+           }
+       } else {
+           me.callParent(arguments);
+       }
+    }
+});
diff --git a/www/manager6/Toolkit.js b/www/manager6/Toolkit.js
new file mode 100644 (file)
index 0000000..201d131
--- /dev/null
@@ -0,0 +1,256 @@
+// ExtJS related things
+
+PVE.Utils.toolkit = 'extjs',
+
+ // do not send '_dc' parameter
+Ext.Ajax.disableCaching = false;
+
+// custom Vtypes
+Ext.apply(Ext.form.field.VTypes, {
+    IPAddress:  function(v) {
+       return IP4_match.test(v);
+    },
+    IPAddressText:  gettext('Example') + ': 192.168.1.1',
+    IPAddressMask: /[\d\.]/i,
+
+    IPCIDRAddress:  function(v) {
+       return IP4_cidr_match.test(v);
+    },
+    IPCIDRAddressText:  gettext('Example') + ': 192.168.1.1/24',
+    IPCIDRAddressMask: /[\d\.\/]/i,
+
+    IP6Address:  function(v) {
+        return IP6_match.test(v);
+    },
+    IP6AddressText:  gettext('Example') + ': 2001:DB8::42',
+    IP6AddressMask: /[A-Fa-f0-9:]/,
+
+    IP6CIDRAddress:  function(v) {
+       return IP6_cidr_match.test(v);
+    },
+    IP6CIDRAddressText:  gettext('Example') + ': 2001:DB8::42/64',
+    IP6CIDRAddressMask:  /[A-Fa-f0-9:\/]/,
+
+    IP6PrefixLength:  function(v) {
+       return v >= 0 && v <= 128;
+    },
+    IP6PrefixLengthText:  gettext('Example') + ': X, where 0 <= X <= 128',
+    IP6PrefixLengthMask:  /[0-9]/,
+    
+    IP64Address:  function(v) {
+        return IP64_match.test(v);
+    },
+    IP64AddressText:  gettext('Example') + ': 192.168.1.1 2001:DB8::42',
+    IP64AddressMask: /[A-Fa-f0-9\.:]/,
+
+    MacAddress: function(v) {
+       return (/^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$/).test(v);
+    },
+    MacAddressMask: /[a-fA-F0-9:]/,
+    MacAddressText: gettext('Example') + ': 01:23:45:67:89:ab',
+
+    BridgeName: function(v) {
+        return (/^vmbr\d{1,4}$/).test(v);
+    },
+    BridgeNameText: gettext('Format') + ': vmbr<b>N</b>, where 0 <= <b>N</b> <= 9999',
+
+    BondName: function(v) {
+        return (/^bond\d{1,4}$/).test(v);
+    },
+    BondNameText: gettext('Format') + ': bond<b>N</b>, where 0 <= <b>N</b> <= 9999',
+
+    InterfaceName: function(v) {
+        return (/^[a-z][a-z0-9_]{1,20}$/).test(v);
+    },
+    InterfaceNameText: gettext('Format') + ': [a-z][a-z0-9_]{1,20}',
+
+
+    QemuStartDate: function(v) {
+       return (/^(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)$/).test(v);
+    },
+    QemuStartDateText: gettext('Format') + ': "now" or "2006-06-17T16:01:21" or "2006-06-17"',
+
+    StorageId:  function(v) {
+        return (/^[a-z][a-z0-9\-\_\.]*[a-z0-9]$/i).test(v);
+    },
+    StorageIdText: gettext("Allowed characters") + ":  'A-Z', 'a-z', '0-9', '-', '_', '.'",
+
+    ConfigId:  function(v) {
+        return (/^[a-z][a-z0-9\_]+$/i).test(v);
+    },
+    ConfigIdText: gettext("Allowed characters") + ": 'A-Z', 'a-z', '0-9', '_'",
+
+    HttpProxy:  function(v) {
+        return (/^http:\/\/.*$/).test(v);
+    },
+    HttpProxyText: gettext('Example') + ": http://username:password&#64;host:port/",
+
+    DnsName: function(v) {
+       return (/^(([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?)\.)*([A-Za-z0-9]([A-Za-z0-9\-]*[A-Za-z0-9])?)$/).test(v);
+    },
+    DnsNameText: gettext('This is not a valid DNS name')
+});
+
+// we dont want that a displayfield set the form dirty flag! 
+Ext.override(Ext.form.field.Display, {
+    isDirty: function() { return false; }
+});
+
+// hack: ExtJS does not display the correct value if we
+// call setValue while the store is loading, so we need
+// to call it again after loading
+Ext.override(Ext.form.field.ComboBox, {
+    onLoad: function() {
+       this.setValue(this.value, false);
+        this.callOverridden(arguments);
+    }
+});
+
+Ext.define('Ext.ux.IFrame', {
+    extend: 'Ext.Component',
+
+    alias: 'widget.uxiframe',
+
+    loadMask: 'Loading...',
+
+    src: 'about:blank',
+
+    renderTpl: [
+        '<iframe src="{src}" name="{frameName}" width="100%" height="100%" frameborder="0"></iframe>'
+    ],
+
+    initComponent: function () {
+        this.callParent();
+
+       this.frameName = this.frameName || this.id + '-frame';
+
+        this.addEvents(
+            'beforeload',
+            'load'
+        );
+
+        Ext.apply(this.renderSelectors, {
+            iframeEl: 'iframe'
+        });
+    },
+
+    initEvents : function() {
+        var me = this;
+        me.callParent();
+        me.iframeEl.on('load', me.onLoad, me);
+    },
+
+    initRenderData: function() {
+        return Ext.apply(this.callParent(), {
+            src: this.src,
+            frameName: this.frameName
+        });
+    },
+
+    getBody: function() {
+        var doc = this.getDoc();
+        return doc.body || doc.documentElement;
+    },
+
+    getDoc: function() {
+        try {
+            return this.getWin().document;
+        } catch (ex) {
+            return null;
+        }
+    },
+
+    getWin: function() {
+        var me = this,
+            name = me.frameName,
+            win = Ext.isIE
+                ? me.iframeEl.dom.contentWindow
+                : window.frames[name];
+        return win;
+    },
+
+    getFrame: function() {
+        var me = this;
+        return me.iframeEl.dom;
+    },
+
+    beforeDestroy: function () {
+        this.cleanupListeners(true);
+        this.callParent();
+    },
+    
+    cleanupListeners: function(destroying){
+        var doc, prop;
+
+        if (this.rendered) {
+            try {
+               doc = this.getDoc();
+                if (doc) {
+                    Ext.EventManager.removeAll(doc);
+                    if (destroying) {
+                        for (prop in doc) {
+                            if (doc.hasOwnProperty && doc.hasOwnProperty(prop)) {
+                                delete doc[prop];
+                            }
+                        }
+                    }
+                }
+            } catch(e) { }
+        }
+    },
+
+    onLoad: function() {
+        var me = this,
+            doc = me.getDoc(),
+            fn = me.onRelayedEvent;
+
+        if (doc) {
+            try {
+                Ext.EventManager.removeAll(doc);
+
+                // These events need to be relayed from the inner document (where they stop
+                // bubbling) up to the outer document. This has to be done at the DOM level so
+                // the event reaches listeners on elements like the document body. The effected
+                // mechanisms that depend on this bubbling behavior are listed to the right
+                // of the event.
+                Ext.EventManager.on(doc, {
+                    mousedown: fn, // menu dismisal (MenuManager) and Window onMouseDown (toFront)
+                    mousemove: fn, // window resize drag detection
+                    mouseup: fn,   // window resize termination
+                    click: fn,     // not sure, but just to be safe
+                    dblclick: fn,  // not sure again
+                    scope: me
+                });
+            } catch(e) {
+                // cannot do this xss
+            }
+
+            // We need to be sure we remove all our events from the iframe on unload or we're going to LEAK!
+            Ext.EventManager.on(this.getWin(), 'beforeunload', me.cleanupListeners, me);
+
+            this.el.unmask();
+            this.fireEvent('load', this);
+
+        } else if(me.src && me.src != '') {
+
+            this.el.unmask();
+            this.fireEvent('error', this);
+        }
+
+
+    },
+
+    load: function (src) {
+        var me = this,
+            text = me.loadMask,
+            frame = me.getFrame();
+
+        if (me.fireEvent('beforeload', me, src) !== false) {
+            if (text && me.el) {
+                me.el.mask(text);
+            }
+
+            frame.src = me.src = (src || me.src);
+        }
+    }
+});
diff --git a/www/manager6/Utils.js b/www/manager6/Utils.js
new file mode 100644 (file)
index 0000000..71c1654
--- /dev/null
@@ -0,0 +1,1087 @@
+Ext.ns('PVE');
+
+// avoid errors when running without development tools
+if (!Ext.isDefined(Ext.global.console)) {   
+    var console = { 
+       dir: function() {}, 
+       log: function() {} 
+    };
+}
+console.log("Starting PVE Manager"); 
+
+Ext.Ajax.defaultHeaders = {
+    'Accept': 'application/json'
+};
+
+Ext.Ajax.on('beforerequest', function(conn, options) {
+    if (PVE.CSRFPreventionToken) {
+       if (!options.headers) { 
+           options.headers = {};
+       }
+       options.headers.CSRFPreventionToken = PVE.CSRFPreventionToken;
+    }
+});
+
+var IPV4_OCTET = "(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])";
+var IPV4_REGEXP = "(?:(?:" + IPV4_OCTET + "\\.){3}" + IPV4_OCTET + ")";
+var IPV6_H16 = "(?:[0-9a-fA-F]{1,4})";
+var IPV6_LS32 = "(?:(?:" + IPV6_H16 + ":" + IPV6_H16 + ")|" + IPV4_REGEXP + ")";
+
+
+var IP4_match = new RegExp("^(?:" + IPV4_REGEXP + ")$");
+var IP4_cidr_match = new RegExp("^(?:" + IPV4_REGEXP + ")\/[1-3][0-9]?$");
+
+var IPV6_REGEXP = "(?:" +
+    "(?:(?:"                                                  + "(?:" + IPV6_H16 + ":){6})" + IPV6_LS32 + ")|" +
+    "(?:(?:"                                         +   "::" + "(?:" + IPV6_H16 + ":){5})" + IPV6_LS32 + ")|" +
+    "(?:(?:(?:"                           + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){4})" + IPV6_LS32 + ")|" +
+    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,1}" + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){3})" + IPV6_LS32 + ")|" +
+    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,2}" + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){2})" + IPV6_LS32 + ")|" +
+    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,3}" + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){1})" + IPV6_LS32 + ")|" +
+    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,4}" + IPV6_H16 + ")?::" +                         ")" + IPV6_LS32 + ")|" +
+    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,5}" + IPV6_H16 + ")?::" +                         ")" + IPV6_H16  + ")|" +
+    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,7}" + IPV6_H16 + ")?::" +                         ")"             + ")"  +
+    ")";
+
+var IP6_match = new RegExp("^(?:" + IPV6_REGEXP + ")$");
+var IP6_cidr_match = new RegExp("^(?:" + IPV6_REGEXP + ")\/[0-9]{1,3}?$");
+var IP6_bracket_match = new RegExp("^\\[(" + IPV6_REGEXP + ")\\]");
+
+var IP64_match = new RegExp("^(?:" + IPV6_REGEXP + "|" + IPV4_REGEXP + ")$");
+
+Ext.define('PVE.Utils', { statics: {
+
+    // this class only contains static functions
+
+    toolkit: undefined, // (extjs|touch), set inside Toolkit.js 
+
+    log_severity_hash: {
+       0: "panic",
+       1: "alert",
+       2: "critical",
+       3: "error",
+       4: "warning",
+       5: "notice",
+       6: "info",
+       7: "debug"
+    },
+
+    support_level_hash: {
+       'c': gettext('Community'),
+       'b': gettext('Basic'),
+       's': gettext('Standard'),
+       'p': gettext('Premium')
+    },
+
+    noSubKeyHtml: 'You do not have a valid subscription for this server. Please visit <a target="_blank" href="http://www.proxmox.com/products/proxmox-ve/subscription-service-plans">www.proxmox.com</a> to get a list of available options.',
+
+    kvm_ostypes: {
+       other: gettext('Other OS types'),
+       wxp: 'Microsoft Windows XP/2003',
+       w2k: 'Microsoft Windows 2000',
+       w2k8: 'Microsoft Windows Vista/2008',
+       win7: 'Microsoft Windows 7/2008r2',
+       win8: 'Microsoft Windows 8/2012',
+       l24: 'Linux 2.4 Kernel',
+       l26: 'Linux 3.X/2.6 Kernel',
+       solaris: 'Solaris Kernel'
+    },
+
+    render_kvm_ostype: function (value) {
+       if (!value) {
+           return gettext('Other OS types');
+       }
+       var text = PVE.Utils.kvm_ostypes[value];
+       if (text) {
+           return text + ' (' + value + ')';
+       }
+       return value;
+    },
+
+    render_hotplug_features: function (value) {
+       var fa = [];
+
+       if (!value || (value === '0')) {
+           return gettext('disabled');
+       }
+
+       Ext.each(value.split(','), function(el) {
+           if (el === 'disk') {
+               fa.push(gettext('Disk'));
+           } else if (el === 'network') {
+               fa.push(gettext('Network'));
+           } else if (el === 'usb') {
+               fa.push(gettext('USB'));
+           } else if (el === 'memory') {
+               fa.push(gettext('Memory'));
+           } else if (el === 'cpu') {
+               fa.push(gettext('CPU'));
+           } else {
+               fa.push(el);
+           }
+       });
+
+       return fa.join(', ');
+    },
+
+    network_iface_types: {
+       eth: gettext("Network Device"),
+       bridge: 'Linux Bridge',
+       bond: 'Linux Bond',
+       OVSBridge: 'OVS Bridge',
+       OVSBond: 'OVS Bond',
+       OVSPort: 'OVS Port',
+       OVSIntPort: 'OVS IntPort'
+    },
+
+    render_network_iface_type: function(value) {
+       return PVE.Utils.network_iface_types[value] || 
+           PVE.Utils.unknownText;
+    },
+
+    render_scsihw: function(value) {
+       if (!value) {
+           return PVE.Utils.defaultText + ' (LSI 53C895A)';
+       } else if (value === 'lsi') {
+           return 'LSI 53C895A';
+       } else if (value === 'lsi53c810') {
+           return 'LSI 53C810';
+       } else if (value === 'megasas') {
+           return 'MegaRAID SAS 8708EM2';
+       } else if (value === 'virtio-scsi-pci') {
+           return 'VIRTIO';
+       } else if (value === 'pvscsi') {
+           return 'VMware PVSCSI';
+       } else {
+           return value;
+       }
+    },
+
+    // fixme: auto-generate this
+    // for now, please keep in sync with PVE::Tools::kvmkeymaps
+    kvm_keymaps: {
+       //ar: 'Arabic',
+       da: 'Danish',
+       de: 'German', 
+       'de-ch': 'German (Swiss)', 
+       'en-gb': 'English (UK)', 
+       'en-us': 'English (USA)',
+       es: 'Spanish',
+       //et: 'Estonia',
+       fi: 'Finnish',
+       //fo: 'Faroe Islands', 
+       fr: 'French', 
+       'fr-be': 'French (Belgium)', 
+       'fr-ca': 'French (Canada)',
+       'fr-ch': 'French (Swiss)',
+       //hr: 'Croatia',
+       hu: 'Hungarian',
+       is: 'Icelandic',
+       it: 'Italian', 
+       ja: 'Japanese',
+       lt: 'Lithuanian',
+       //lv: 'Latvian',
+       mk: 'Macedonian', 
+       nl: 'Dutch',
+       //'nl-be': 'Dutch (Belgium)',
+       no: 'Norwegian', 
+       pl: 'Polish',
+       pt: 'Portuguese',
+       'pt-br': 'Portuguese (Brazil)',
+       //ru: 'Russian',
+       sl: 'Slovenian',
+       sv: 'Swedish',
+       //th: 'Thai',
+       tr: 'Turkish'
+    },
+
+    kvm_vga_drivers: {
+       std: gettext('Standard VGA'),
+       vmware: gettext('VMWare compatible'),
+       cirrus: 'Cirrus Logic GD5446',
+       qxl: 'SPICE',
+       qxl2: 'SPICE dual monitor',
+       qxl3: 'SPICE three monitors',
+       qxl4: 'SPICE four monitors',
+       serial0: gettext('Serial terminal') + ' 0',
+       serial1: gettext('Serial terminal') + ' 1',
+       serial2: gettext('Serial terminal') + ' 2',
+       serial3: gettext('Serial terminal') + ' 3'
+    },
+
+    render_kvm_language: function (value) {
+       if (!value) {
+           return PVE.Utils.defaultText;
+       }
+       var text = PVE.Utils.kvm_keymaps[value];
+       if (text) {
+           return text + ' (' + value + ')';
+       }
+       return value;
+    },
+
+    kvm_keymap_array: function() {
+       var data = [['', PVE.Utils.render_kvm_language('')]];
+       Ext.Object.each(PVE.Utils.kvm_keymaps, function(key, value) {
+           data.push([key, PVE.Utils.render_kvm_language(value)]);
+       });
+
+       return data;
+    },
+
+    render_console_viewer: function(value) {
+       if (!value) {
+           return PVE.Utils.defaultText + ' (HTML5)';
+       } else if (value === 'applet') {
+           return 'Java VNC Applet';
+       } else if (value === 'vv') {
+           return  'SPICE (remote-viewer)';
+       } else if (value === 'html5') {
+           return  'HTML5 (noVNC)';
+       } else {
+           return value;
+       }
+    },
+
+    language_map: {
+       zh_CN: 'Chinese',
+       ca: 'Catalan',
+       da: 'Danish',
+       en: 'English',
+       eu: 'Euskera (Basque)',
+       fr: 'French',
+       de: 'German',
+       it: 'Italian',
+       ja: 'Japanese',
+       nb: 'Norwegian (Bokmal)',
+       nn: 'Norwegian (Nynorsk)',
+       fa: 'Persian (Farsi)',
+       pl: 'Polish',
+       pt_BR: 'Portuguese (Brazil)',
+       ru: 'Russian',
+       sl: 'Slovenian',
+       es: 'Spanish',
+       sv: 'Swedish',
+       tr: 'Turkish'
+    },
+
+    render_language: function (value) {
+       if (!value) {
+           return PVE.Utils.defaultText + ' (English)';
+       }
+       var text = PVE.Utils.language_map[value];
+       if (text) {
+           return text + ' (' + value + ')';
+       }
+       return value;
+    },
+
+    language_array: function() {
+       var data = [['', PVE.Utils.render_language('')]];
+       Ext.Object.each(PVE.Utils.language_map, function(key, value) {
+           data.push([key, PVE.Utils.render_language(value)]);
+       });
+
+       return data;
+    },
+
+    render_kvm_vga_driver: function (value) {
+       if (!value) {
+           return PVE.Utils.defaultText;
+       }
+       var text = PVE.Utils.kvm_vga_drivers[value];
+       if (text) { 
+           return text + ' (' + value + ')';
+       }
+       return value;
+    },
+
+    kvm_vga_driver_array: function() {
+       var data = [['', PVE.Utils.render_kvm_vga_driver('')]];
+       Ext.Object.each(PVE.Utils.kvm_vga_drivers, function(key, value) {
+           data.push([key, PVE.Utils.render_kvm_vga_driver(value)]);
+       });
+
+       return data;
+    },
+
+    render_kvm_startup: function(value) {
+       var startup = PVE.Parser.parseStartup(value);
+
+       var res = 'order=';
+       if (startup.order === undefined) {
+           res += 'any';
+       } else {
+           res += startup.order;
+       }
+       if (startup.up !== undefined) {
+           res += ',up=' + startup.up;
+       }
+       if (startup.down !== undefined) {
+           res += ',down=' + startup.down;
+       }
+
+       return res;
+    },
+
+    authOK: function() {
+       return Ext.util.Cookies.get('PVEAuthCookie');
+    },
+
+    authClear: function() {
+       Ext.util.Cookies.clear("PVEAuthCookie");
+    },
+
+    // fixme: remove - not needed?
+    gridLineHeigh: function() {
+       return 21;
+       
+       //if (Ext.isGecko)
+       //return 23;
+       //return 21;
+    },
+
+    extractRequestError: function(result, verbose) {
+       var msg = gettext('Successful');
+
+       if (!result.success) {
+           msg = gettext("Unknown error");
+           if (result.message) {
+               msg = result.message;
+               if (result.status) {
+                   msg += ' (' + result.status + ')';
+               }
+           }
+           if (verbose && Ext.isObject(result.errors)) {
+               msg += "<br>";
+               Ext.Object.each(result.errors, function(prop, desc) {
+                   msg += "<br><b>" + Ext.htmlEncode(prop) + "</b>: " + 
+                       Ext.htmlEncode(desc);
+               });
+           }   
+       }
+
+       return msg;
+    },
+
+    extractFormActionError: function(action) {
+       var msg;
+       switch (action.failureType) {
+       case Ext.form.action.Action.CLIENT_INVALID:
+           msg = gettext('Form fields may not be submitted with invalid values');
+           break;
+       case Ext.form.action.Action.CONNECT_FAILURE:
+           msg = gettext('Connection error');
+           var resp = action.response;
+           if (resp.status && resp.statusText) {
+               msg += " " + resp.status + ": " + resp.statusText;
+           }
+           break;
+       case Ext.form.action.Action.LOAD_FAILURE:
+       case Ext.form.action.Action.SERVER_INVALID:
+           msg = PVE.Utils.extractRequestError(action.result, true);
+           break;
+       }
+       return msg;
+    },
+
+    // Ext.Ajax.request
+    API2Request: function(reqOpts) {
+
+       var newopts = Ext.apply({
+           waitMsg: gettext('Please wait...')
+       }, reqOpts);
+
+       if (!newopts.url.match(/^\/api2/)) {
+           newopts.url = '/api2/extjs' + newopts.url;
+       }
+       delete newopts.callback;
+
+       var createWrapper = function(successFn, callbackFn, failureFn) {
+           Ext.apply(newopts, {
+               success: function(response, options) {
+                   if (options.waitMsgTarget) {
+                       if (PVE.Utils.toolkit === 'touch') {
+                           options.waitMsgTarget.setMasked(false);
+                       } else {
+                           options.waitMsgTarget.setLoading(false);
+                       }
+                   }
+                   var result = Ext.decode(response.responseText);
+                   response.result = result;
+                   if (!result.success) {
+                       response.htmlStatus = PVE.Utils.extractRequestError(result, true);
+                       Ext.callback(callbackFn, options.scope, [options, false, response]);
+                       Ext.callback(failureFn, options.scope, [response, options]);
+                       return;
+                   }
+                   Ext.callback(callbackFn, options.scope, [options, true, response]);
+                   Ext.callback(successFn, options.scope, [response, options]);
+               },
+               failure: function(response, options) {
+                   if (options.waitMsgTarget) {
+                       if (PVE.Utils.toolkit === 'touch') {
+                           options.waitMsgTarget.setMasked(false);
+                       } else {
+                           options.waitMsgTarget.setLoading(false);
+                       }
+                   }
+                   response.result = {};
+                   try {
+                       response.result = Ext.decode(response.responseText);
+                   } catch(e) {}
+                   var msg = gettext('Connection error') + ' - server offline?';
+                   if (response.aborted) {
+                       msg = gettext('Connection error') + ' - aborted.';
+                   } else if (response.timedout) {
+                       msg = gettext('Connection error') + ' - Timeout.';
+                   } else if (response.status && response.statusText) {
+                       msg = gettext('Connection error') + ' ' + response.status + ': ' + response.statusText;
+                   }
+                   response.htmlStatus = msg;
+                   Ext.callback(callbackFn, options.scope, [options, false, response]);
+                   Ext.callback(failureFn, options.scope, [response, options]);
+               }
+           });
+       };
+
+       createWrapper(reqOpts.success, reqOpts.callback, reqOpts.failure);
+
+       var target = newopts.waitMsgTarget;
+       if (target) {
+           if (PVE.Utils.toolkit === 'touch') {
+               target.setMasked({ xtype: 'loadmask', message: newopts.waitMsg} );
+           } else {
+               // Note: ExtJS bug - this does not work when component is not rendered
+               target.setLoading(newopts.waitMsg);
+           }
+       }
+       Ext.Ajax.request(newopts);
+    },
+
+    assemble_field_data: function(values, data) {
+        if (Ext.isObject(data)) {
+           Ext.Object.each(data, function(name, val) {
+               if (values.hasOwnProperty(name)) {
+                    var bucket = values[name];
+                    if (!Ext.isArray(bucket)) {
+                        bucket = values[name] = [bucket];
+                    }
+                    if (Ext.isArray(val)) {
+                        values[name] = bucket.concat(val);
+                    } else {
+                        bucket.push(val);
+                    }
+                } else {
+                   values[name] = val;
+                }
+            });
+       }
+    },
+
+    checked_command: function(orig_cmd) {
+       PVE.Utils.API2Request({
+           url: '/nodes/localhost/subscription',
+           method: 'GET',
+           //waitMsgTarget: me,
+           failure: function(response, opts) {
+               Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+           },
+           success: function(response, opts) {
+               var data = response.result.data;
+
+               if (data.status !== 'Active') {
+                   Ext.Msg.show({
+                       title: gettext('No valid subscription'),
+                       icon: Ext.Msg.WARNING,
+                       msg: PVE.Utils.noSubKeyHtml,
+                       buttons: Ext.Msg.OK,
+                       callback: function(btn) {
+                           if (btn !== 'ok') {
+                               return;
+                           }
+                           orig_cmd();
+                       }
+                   });
+               } else {
+                   orig_cmd();
+               }
+           }
+       });
+    },
+
+    task_desc_table: {
+       vncproxy: [ 'VM/CT', gettext('Console') ],
+       spiceproxy: [ 'VM/CT', gettext('Console') + ' (Spice)' ],
+       vncshell: [ '', gettext('Shell') ],
+       spiceshell: [ '', gettext('Shell')  + ' (Spice)' ],
+       qmsnapshot: [ 'VM', gettext('Snapshot') ],
+       qmrollback: [ 'VM', gettext('Rollback') ],
+       qmdelsnapshot: [ 'VM', gettext('Delete Snapshot') ],
+       qmcreate: [ 'VM', gettext('Create') ],
+       qmrestore: [ 'VM', gettext('Restore') ],
+       qmdestroy: [ 'VM', gettext('Destroy') ],
+       qmigrate: [ 'VM', gettext('Migrate') ],
+       qmclone: [ 'VM', gettext('Clone') ],
+       qmmove: [ 'VM', gettext('Move disk') ],
+       qmtemplate: [ 'VM', gettext('Convert to template') ],
+       qmstart: [ 'VM', gettext('Start') ],
+       qmstop: [ 'VM', gettext('Stop') ],
+       qmreset: [ 'VM', gettext('Reset') ],
+       qmshutdown: [ 'VM', gettext('Shutdown') ],
+       qmsuspend: [ 'VM', gettext('Suspend') ],
+       qmresume: [ 'VM', gettext('Resume') ],
+       qmconfig: [ 'VM', gettext('Configure') ],
+       vzcreate: ['CT', gettext('Create') ],
+       vzrestore: ['CT', gettext('Restore') ],
+       vzdestroy: ['CT', gettext('Destroy') ],
+       vzmigrate: [ 'CT', gettext('Migrate') ],
+       vzstart: ['CT', gettext('Start') ],
+       vzstop: ['CT', gettext('Stop') ],
+       vzmount: ['CT', gettext('Mount') ],
+       vzumount: ['CT', gettext('Unmount') ],
+       vzshutdown: ['CT', gettext('Shutdown') ],
+       vzsuspend: [ 'CT', gettext('Suspend') ],
+       vzresume: [ 'CT', gettext('Resume') ],
+       hamigrate: [ 'HA', gettext('Migrate') ],
+       hastart: [ 'HA', gettext('Start') ],
+       hastop: [ 'HA', gettext('Stop') ],
+       srvstart: ['SRV', gettext('Start') ],
+       srvstop: ['SRV', gettext('Stop') ],
+       srvrestart: ['SRV', gettext('Restart') ],
+       srvreload: ['SRV', gettext('Reload') ],
+       cephcreatemon: ['Ceph Monitor', gettext('Create') ],
+       cephdestroymon: ['Ceph Monitor', gettext('Destroy') ],
+       cephcreateosd: ['Ceph OSD', gettext('Create') ],
+       cephdestroyosd: ['Ceph OSD', gettext('Destroy') ],
+       imgcopy: ['', gettext('Copy data') ],
+       imgdel: ['', gettext('Erase data') ],
+       download: ['', gettext('Download') ],
+       vzdump: ['', gettext('Backup') ],
+       aptupdate: ['', gettext('Update package database') ],
+       startall: [ '', gettext('Start all VMs and Containers') ],
+       stopall: [ '', gettext('Stop all VMs and Containers') ],
+       migrateall: [ '', gettext('Migrate all VMs and Containers') ]
+    },
+
+    format_task_description: function(type, id) {      
+       var farray = PVE.Utils.task_desc_table[type];
+       if (!farray) {
+           return type;
+       }
+       var prefix = farray[0];
+       var text = farray[1];
+       if (prefix) {
+           return prefix + ' ' + id + ' - ' + text; 
+       }
+       return text;
+    },
+
+    parse_task_upid: function(upid) {
+       var task = {};
+
+       var res = upid.match(/^UPID:(\S+):([0-9A-Fa-f]{8}):([0-9A-Fa-f]{8,9}):([0-9A-Fa-f]{8}):([^:\s]+):([^:\s]*):([^:\s]+):$/);
+       if (!res) {
+           throw "unable to parse upid '" + upid + "'";
+       }
+       task.node = res[1];
+       task.pid = parseInt(res[2], 16);
+       task.pstart = parseInt(res[3], 16);
+       task.starttime = parseInt(res[4], 16);
+       task.type = res[5];
+       task.id = res[6];
+       task.user = res[7];
+
+       task.desc = PVE.Utils.format_task_description(task.type, task.id);
+
+       return task;
+    },
+
+    format_size: function(size) {
+       /*jslint confusion: true */
+
+       if (size < 1024) {
+           return size;
+       }
+
+       var kb = size / 1024;
+
+       if (kb < 1024) {
+           return kb.toFixed(0) + "KB";
+       }
+
+       var mb = size / (1024*1024);
+
+       if (mb < 1024) {
+           return mb.toFixed(0) + "MB";
+       }
+
+       var gb = mb / 1024;
+
+       if (gb < 1024) {
+           return gb.toFixed(2) + "GB";
+       }
+
+       var tb =  gb / 1024;
+
+       return tb.toFixed(2) + "TB";
+
+    },
+
+    format_html_bar: function(per, text) {
+
+       return "<div class='pve-bar-wrap'>" + text + "<div class='pve-bar-border'>" +
+           "<div class='pve-bar-inner' style='width:" + per + "%;'></div>" +
+           "</div></div>";
+       
+    },
+
+    format_cpu_bar: function(per1, per2, text) {
+
+       return "<div class='pve-bar-border'>" +
+           "<div class='pve-bar-inner' style='width:" + per1 + "%;'></div>" +
+           "<div class='pve-bar-inner2' style='width:" + per2 + "%;'></div>" +
+           "<div class='pve-bar-text'>" + text + "</div>" + 
+           "</div>";
+    },
+
+    format_large_bar: function(per, text) {
+
+       if (!text) {
+           text = per.toFixed(1) + "%";
+       }
+
+       return "<div class='pve-largebar-border'>" +
+           "<div class='pve-largebar-inner' style='width:" + per + "%;'></div>" +
+           "<div class='pve-largebar-text'>" + text + "</div>" + 
+           "</div>";
+    },
+
+    format_duration_long: function(ut) {
+
+       var days = Math.floor(ut / 86400);
+       ut -= days*86400;
+       var hours = Math.floor(ut / 3600);
+       ut -= hours*3600;
+       var mins = Math.floor(ut / 60);
+       ut -= mins*60;
+
+       var hours_str = '00' + hours.toString();
+       hours_str = hours_str.substr(hours_str.length - 2);
+       var mins_str = "00" + mins.toString();
+       mins_str = mins_str.substr(mins_str.length - 2);
+       var ut_str = "00" + ut.toString();
+       ut_str = ut_str.substr(ut_str.length - 2);
+
+       if (days) {
+           var ds = days > 1 ? PVE.Utils.daysText : PVE.Utils.dayText;
+           return days.toString() + ' ' + ds + ' ' + 
+               hours_str + ':' + mins_str + ':' + ut_str;
+       } else {
+           return hours_str + ':' + mins_str + ':' + ut_str;
+       }
+    },
+
+    format_duration_short: function(ut) {
+       
+       if (ut < 60) {
+           return ut.toString() + 's';
+       }
+
+       if (ut < 3600) {
+           var mins = ut / 60;
+           return mins.toFixed(0) + 'm';
+       }
+
+       if (ut < 86400) {
+           var hours = ut / 3600;
+           return hours.toFixed(0) + 'h';
+       }
+
+       var days = ut / 86400;
+       return days.toFixed(0) + 'd';   
+    },
+
+    yesText: gettext('Yes'),
+    noText: gettext('No'),
+    noneText: gettext('none'),
+    errorText: gettext('Error'),
+    unknownText: gettext('Unknown'),
+    defaultText: gettext('Default'),
+    daysText: gettext('days'),
+    dayText: gettext('day'),
+    runningText: gettext('running'),
+    stoppedText: gettext('stopped'),
+    neverText: gettext('never'),
+    totalText: gettext('Total'),
+    usedText: gettext('Used'),
+    directoryText: gettext('Directory'),
+    imagesText: gettext('Disk image'),
+    backupFileText: gettext('VZDump backup file'),
+    vztmplText: gettext('Container template'),
+    isoImageText: gettext('ISO image'),
+    containersText: gettext('Container'),
+
+    format_expire: function(date) {
+       if (!date) {
+           return PVE.Utils.neverText;
+       }
+       return Ext.Date.format(date, "Y-m-d");
+    },
+
+    format_storage_type: function(value) {
+       if (value === 'dir') {
+           return PVE.Utils.directoryText;
+       } else if (value === 'nfs') {
+           return 'NFS';
+       } else if (value === 'glusterfs') {
+           return 'GlusterFS';
+       } else if (value === 'lvm') {
+           return 'LVM';
+       } else if (value === 'iscsi') {
+           return 'iSCSI';
+       } else if (value === 'rbd') {
+           return 'RBD';
+       } else if (value === 'sheepdog') {
+           return 'Sheepdog';
+       } else if (value === 'zfs') {
+           return 'ZFS over iSCSI';
+       } else if (value === 'zfspool') {
+           return 'ZFS';
+       } else if (value === 'iscsidirect') {
+           return 'iSCSIDirect';
+       } else {
+           return PVE.Utils.unknownText;
+       }
+    },
+
+    format_boolean_with_default: function(value) {
+       if (Ext.isDefined(value) && value !== '') {
+           return value ? PVE.Utils.yesText : PVE.Utils.noText;
+       }
+       return PVE.Utils.defaultText;
+    },
+
+    format_boolean: function(value) {
+       return value ? PVE.Utils.yesText : PVE.Utils.noText;
+    },
+
+    format_neg_boolean: function(value) {
+       return !value ? PVE.Utils.yesText : PVE.Utils.noText;
+    },
+
+    format_content_types: function(value) {
+       var cta = [];
+
+       Ext.each(value.split(',').sort(), function(ct) {
+           if (ct === 'images') {
+               cta.push(PVE.Utils.imagesText);
+           } else if (ct === 'backup') {
+               cta.push(PVE.Utils.backupFileText);
+           } else if (ct === 'vztmpl') {
+               cta.push(PVE.Utils.vztmplText);
+           } else if (ct === 'iso') {
+               cta.push(PVE.Utils.isoImageText);
+           } else if (ct === 'rootdir') {
+               cta.push(PVE.Utils.containersText);
+           }
+       });
+
+       return cta.join(', ');
+    },
+
+    render_storage_content: function(value, metaData, record) {
+       var data = record.data;
+       if (Ext.isNumber(data.channel) &&
+           Ext.isNumber(data.id) &&
+           Ext.isNumber(data.lun)) {
+           return "CH " + 
+               Ext.String.leftPad(data.channel,2, '0') + 
+               " ID " + data.id + " LUN " + data.lun;
+       }
+       return data.volid.replace(/^.*:(.*\/)?/,'');
+    },
+
+    render_serverity: function (value) {
+       return PVE.Utils.log_severity_hash[value] || value;
+    },
+
+    render_cpu: function(value, metaData, record, rowIndex, colIndex, store) {
+
+       if (!(record.data.uptime && Ext.isNumeric(value))) {
+           return '';
+       }
+
+       var maxcpu = record.data.maxcpu || 1;
+
+       if (!Ext.isNumeric(maxcpu) && (maxcpu >= 1)) {
+           return '';
+       }
+       
+       var per = value * 100;
+
+       return per.toFixed(1) + '% of ' + maxcpu.toString() + (maxcpu > 1 ? 'CPUs' : 'CPU');
+    },
+
+    render_size: function(value, metaData, record, rowIndex, colIndex, store) {
+       /*jslint confusion: true */
+
+       if (!Ext.isNumeric(value)) {
+           return '';
+       }
+
+       return PVE.Utils.format_size(value);
+    },
+
+    render_timestamp: function(value, metaData, record, rowIndex, colIndex, store) {
+       var servertime = new Date(value * 1000);
+       return Ext.Date.format(servertime, 'Y-m-d H:i:s');
+    },
+
+    render_mem_usage: function(value, metaData, record, rowIndex, colIndex, store) {
+
+       var mem = value;
+       var maxmem = record.data.maxmem;
+       
+       if (!record.data.uptime) {
+           return '';
+       }
+
+       if (!(Ext.isNumeric(mem) && maxmem)) {
+           return '';
+       }
+
+       var per = (mem * 100) / maxmem;
+
+       return per.toFixed(1) + '%';
+    },
+
+    render_disk_usage: function(value, metaData, record, rowIndex, colIndex, store) {
+
+       var disk = value;
+       var maxdisk = record.data.maxdisk;
+
+       if (!(Ext.isNumeric(disk) && maxdisk)) {
+           return '';
+       }
+
+       var per = (disk * 100) / maxdisk;
+
+       return per.toFixed(1) + '%';
+    },
+
+    render_resource_type: function(value, metaData, record, rowIndex, colIndex, store) {
+
+       var cls = 'pve-itype-icon-' + value;
+
+       if (record.data.running) {
+           metaData.tdCls = cls + "-running";
+       } else if (record.data.template) {
+           metaData.tdCls = cls + "-template";     
+       } else {
+           metaData.tdCls = cls;
+       }
+
+       return value;
+    },
+
+    render_uptime: function(value, metaData, record, rowIndex, colIndex, store) {
+
+       var uptime = value;
+
+       if (uptime === undefined) {
+           return '';
+       }
+       
+       if (uptime <= 0) {
+           return '-';
+       }
+
+       return PVE.Utils.format_duration_long(uptime);
+    },
+
+    render_support_level: function(value, metaData, record) {
+       return PVE.Utils.support_level_hash[value] || '-';
+    },
+
+    render_upid: function(value, metaData, record) { 
+       var type = record.data.type;
+       var id = record.data.id;
+
+       return PVE.Utils.format_task_description(type, id);
+    },
+
+    dialog_title: function(subject, create, isAdd) {
+       if (create) {
+           if (isAdd) {
+               return gettext('Add') + ': ' + subject;
+           } else {
+               return gettext('Create') + ': ' + subject;
+           }
+       } else {
+           return gettext('Edit') + ': ' + subject;
+       }
+    },
+
+    windowHostname: function() {
+       return window.location.hostname.replace(IP6_bracket_match,
+            function(m, addr, offset, original) { return addr; });
+    },
+    openDefaultConsoleWindow: function(allowSpice, vmtype, vmid, nodename, vmname) {
+       var dv = PVE.Utils.defaultViewer(allowSpice);
+       PVE.Utils.openConsoleWindow(dv, vmtype, vmid, nodename, vmname);
+    },
+
+    openConsoleWindow: function(viewer, vmtype, vmid, nodename, vmname) {
+       // kvm, lxc, shell, upgrade
+
+       if (vmid == undefined && (vmtype === 'kvm' || vmtype === 'lxc')) {
+           throw "missing vmid";
+       }
+
+       if (!nodename) {
+           throw "no nodename specified";
+       }
+
+       if (viewer === 'applet' || viewer === 'html5') {
+           PVE.Utils.openVNCViewer(vmtype, vmid, nodename, vmname, viewer === 'html5');
+       } else if (viewer === 'vv') {
+           var url;
+           var params = { proxy: PVE.Utils.windowHostname() };
+           if (vmtype === 'kvm') {
+               url = '/nodes/' + nodename + '/qemu/' + vmid.toString() + '/spiceproxy';
+               PVE.Utils.openSpiceViewer(url, params);
+           } else if (vmtype === 'lxc') {
+               url = '/nodes/' + nodename + '/lxc/' + vmid.toString() + '/spiceproxy';
+               PVE.Utils.openSpiceViewer(url, params);
+           } else if (vmtype === 'shell') {
+               url = '/nodes/' + nodename + '/spiceshell';
+               PVE.Utils.openSpiceViewer(url, params);
+           } else if (vmtype === 'upgrade') {
+               url = '/nodes/' + nodename + '/spiceshell';
+               params.upgrade = 1;
+               PVE.Utils.openSpiceViewer(url, params);
+           }
+       } else {
+           throw "unknown viewer type";
+       }
+    },
+
+    defaultViewer: function(allowSpice) {
+       var vncdefault = 'html5';
+       var dv = PVE.VersionInfo.console || vncdefault;
+       if (dv === 'vv' && !allowSpice) {
+           dv = vncdefault;
+       }
+
+       return dv;
+    },
+
+    openVNCViewer: function(vmtype, vmid, nodename, vmname, novnc) {
+       var url = Ext.urlEncode({
+           console: vmtype, // kvm, lxc, upgrade or shell
+           novnc: novnc ? 1 : 0,
+           vmid: vmid,
+           vmname: vmname,
+           node: nodename
+       });
+       var nw = window.open("?" + url, '_blank', "innerWidth=745,innerheight=427");
+       nw.focus();
+    },
+
+    openSpiceViewer: function(url, params){
+
+       var downloadWithName = function(uri, name) {
+           var link = Ext.DomHelper.append(document.body, {
+               tag: 'a',
+               href: uri,
+               css : 'display:none;visibility:hidden;height:0px;'
+           });
+
+           // Note: we need to tell android the correct file name extension
+           // but we do not set 'download' tag for other environments, because
+           // It can have strange side effects (additional user prompt on firefox)
+           var andriod = navigator.userAgent.match(/Android/i) ? true : false;
+           if (andriod) {
+               link.download = name;
+           }
+
+           if (link.fireEvent) {
+               link.fireEvent('onclick');
+           } else {
+                var evt = document.createEvent("MouseEvents");
+                evt.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
+               link.dispatchEvent(evt);
+           }
+       };
+
+       PVE.Utils.API2Request({
+           url: url,
+           params: params,
+           method: 'POST',
+           failure: function(response, opts){
+               Ext.Msg.alert('Error', response.htmlStatus);
+           },
+           success: function(response, opts){
+               var raw = "[virt-viewer]\n";
+               Ext.Object.each(response.result.data, function(k, v) {
+                   raw += k + "=" + v + "\n";
+               });
+               var url = 'data:application/x-virt-viewer;charset=UTF-8,' +
+                   encodeURIComponent(raw);
+                   
+               downloadWithName(url, "pve-spice.vv");
+           }
+       });
+    },
+
+    // comp.setLoading() is buggy in ExtJS 4.0.7, so we 
+    // use el.mask() instead
+    setErrorMask: function(comp, msg) {
+       var el = comp.el;
+       if (!el) {
+           return;
+       }
+       if (!msg) {
+           el.unmask();
+       } else {
+           if (msg === true) {
+               el.mask(gettext("Loading..."));
+           } else {
+               el.mask(msg);
+           }
+       }
+    },
+
+    monStoreErrors: function(me, store) {
+       me.mon(store, 'beforeload', function(s, operation, eOpts) {
+           if (!me.loadCount) {
+               me.loadCount = 0; // make sure it is numeric
+               PVE.Utils.setErrorMask(me, true);
+           }
+       });
+
+       // only works with 'pve' proxy
+       me.mon(store.proxy, 'afterload', function(proxy, request, success) {
+           me.loadCount++;
+
+           if (success) {
+               PVE.Utils.setErrorMask(me, false);
+               return;
+           }
+
+           var msg;
+           var operation = request.operation;
+           var error = operation.getError();
+           if (error.statusText) {
+               msg = error.statusText + ' (' + error.status + ')';
+           } else {
+               msg = gettext('Connection error');
+           }
+           PVE.Utils.setErrorMask(me, msg);
+       });
+    }
+
+}});
+
diff --git a/www/manager6/VNCConsole.js b/www/manager6/VNCConsole.js
new file mode 100644 (file)
index 0000000..db90388
--- /dev/null
@@ -0,0 +1,591 @@
+Ext.define('PVE.noVncConsole', {
+    extend: 'Ext.panel.Panel',
+    alias: 'widget.pveNoVncConsole',
+
+    nodename: undefined,
+
+    vmid: undefined,
+
+    consoleType: undefined, // lxc or kvm
+    
+    initComponent : function() {
+       var me = this;
+
+       if (!me.nodename) {
+           throw "no node name specified";
+       }
+
+       if (!me.consoleType) {
+           throw "no console type specified";
+       }
+
+       if (!me.vmid && me.consoleType !== 'shell') {
+           throw "no VM ID specified";
+       }
+       
+       // always use same iframe, to avoid running several noVnc clients
+       // at same time (to avoid performance problems)
+       var box = Ext.create('widget.uxiframe', { id: "vncconsole" });
+
+       Ext.apply(me, {
+           layout: { type: 'fit' },
+           border: false,
+           items: box,
+           listeners: {
+               show: function() {
+                   var url = '/?console=' + me.consoleType + '&novnc=1&node=' + me.nodename + '&resize=scale';
+                   if (me.vmid) {
+                       url += '&vmid='+ me.vmid;
+                   }
+                   box.load(url);
+               }
+           }
+       });             
+
+       me.callParent();
+    }
+});
+
+PVE_vnc_console_event = function(appletid, action, err) {
+    //console.log("TESTINIT param1 " + appletid + " action " + action);
+
+    if (action === "error") {
+       var compid = appletid.replace("-vncapp", "");
+       var comp = Ext.getCmp(compid);
+
+       if (!comp || !comp.vmid || !comp.toplevel) {
+           return;
+       }
+
+       comp.detectMigratedVM();
+    }
+
+    return;
+ };
+
+Ext.define('PVE.VNCConsole', {
+    extend: 'Ext.panel.Panel',
+    alias: ['widget.pveVNCConsole'],
+
+    novnc: false,
+
+    last_novnc_state: undefined,
+    last_novnc_msg: undefined,
+
+    detectMigratedVM: function() {
+       var me = this;
+       
+       if (!me.vmid) {
+           return;
+       }
+
+       // try to detect migrated VM
+       PVE.Utils.API2Request({
+           url: '/cluster/resources',
+           method: 'GET',
+           success: function(response) {
+               var list = response.result.data;
+               Ext.Array.each(list, function(item) {
+                   if (item.type === 'qemu' && item.vmid == me.vmid) {
+                       if (item.node !== me.nodename) {
+                           me.nodename = item.node;
+                           me.url = "/nodes/" + me.nodename + "/" + item.type + "/" + me.vmid + "/vncproxy";
+                           me.wsurl = "/nodes/" + me.nodename + "/" + item.type + "/" + me.vmid + "/vncwebsocket";
+                           me.reloadApplet();
+                       }
+                       return false; // break
+                   }
+               });
+           }
+       });
+    },
+
+    initComponent : function() {
+       var me = this;
+
+       if (!me.url) {
+           throw "no url specified";
+       }
+
+       var myid = me.id + "-vncapp";
+
+       me.appletID = myid;
+
+       var box;
+
+       if (me.novnc) {
+           if (!me.wsurl) {
+               throw "no web socket url specified";
+           }
+           box = Ext.create('widget.uxiframe', { id: myid });
+       } else {
+           box = Ext.create('Ext.Component', { border: false, html: "" });
+       }
+
+       var resize_window = function() {
+           //console.log("resize");
+
+           var aw;
+           var ah;
+           var applet;
+
+           if (me.novnc) {
+               var novnciframe = box.getFrame();
+               // noVNC_canvas
+               var innerDoc = novnciframe.contentDocument || novnciframe.contentWindow.document;
+               aw = innerDoc.getElementById('noVNC_canvas').width;
+               ah = innerDoc.getElementById('noVNC_canvas').height + 8;
+
+               var novnc_state = innerDoc.getElementById('noVNC_status_state').innerHTML;
+               var novnc_msg = innerDoc.getElementById('noVNC_status_msg').innerHTML;
+
+               if (novnc_state !== me.last_novnc_state || novnc_msg !== me.last_novnc_msg) {
+                   me.last_novnc_state = novnc_state; 
+                   me.last_novnc_msg = novnc_msg; 
+
+                   if (novnc_state !== 'normal') {
+                       PVE.Utils.setErrorMask(box, novnc_msg || 'unknown');
+                   } else {
+                       PVE.Utils.setErrorMask(box); // clear mask
+                   }
+
+                   if (novnc_state === 'disconnected') {
+                       me.detectMigratedVM();
+                   }
+               }
+
+           } else {
+               applet = Ext.getDom(myid);
+           
+               // try again when dom element is available
+               if (!(applet && Ext.isFunction(applet.getPreferredSize))) {
+                   return Ext.Function.defer(resize_window, 1000);
+               }
+
+               var ps = applet.getPreferredSize();
+               aw = ps.width;
+               ah = ps.height;
+           }
+
+           if (aw < 640) { aw = 640; }
+           if (ah < 400) { ah = 400; }
+
+           var tbar = me.getDockedItems("[dock=top]")[0];
+           var tbh = tbar ? tbar.getHeight() : 0;
+
+           var oh;
+           var ow;
+
+           //console.log("size0 " + aw + " " + ah + " tbh " + tbh);
+
+           if (window.innerHeight) {
+               oh = window.innerHeight;
+               ow = window.innerWidth;
+           } else if (document.documentElement && 
+                      document.documentElement.clientHeight) {
+               oh = document.documentElement.clientHeight;
+               ow = document.documentElement.clientWidth;
+           } else if (document.body) {
+               oh = document.body.clientHeight;
+               ow = document.body.clientWidth;
+           }  else {
+               throw "can't get window size";
+           }
+
+           if (!me.novnc) {
+               Ext.fly(applet).setSize(aw, ah + tbh);
+           }
+
+           var offsetw = aw - ow;
+           var offseth = ah + tbh - oh;
+
+           if (offsetw !== 0 || offseth !== 0) {
+               //console.log("try resize by " + offsetw + " " + offseth);
+               try { window.resizeBy(offsetw, offseth); } catch (e) {}
+           }
+
+           Ext.Function.defer(resize_window, 1000);
+       };
+
+       var resize_box = function() {
+           if (me.novnc) {
+               throw "implement me";
+           } else {
+               var applet = Ext.getDom(myid);
+
+               if ((applet && Ext.isFunction(applet.getPreferredSize))) {
+                   var ps = applet.getPreferredSize();
+                   Ext.fly(applet).setSize(ps.width, ps.height);
+               }
+           }
+
+           Ext.Function.defer(resize_box, 1000);
+       };
+
+       var start_vnc_viewer = function(param) {
+           
+           if (me.novnc) {
+               
+               var pveparams = Ext.urlEncode({
+                   port: param.port,
+                   vncticket: param.ticket
+               });
+
+               var urlparams = Ext.urlEncode({
+                   encrypt: 1,
+                   path: "api2/json" + me.wsurl + "?" + pveparams,
+                   password: param.ticket
+               });
+               box.load('/novnc/vnc_pve.html?' + urlparams);
+           
+           } else {
+
+               var cert = param.cert;
+               cert = cert.replace(/\n/g, "|");
+
+               box.update({
+                   id: myid,
+                   border: false,
+                   tag: 'applet',
+                   code: 'com.tigervnc.vncviewer.VncViewer',
+                   archive: '/vncterm/VncViewer.jar',
+                   // NOTE: set size to '100%' -  else resize does not work
+                   width: "100%",
+                   height: "100%", 
+                   cn: [
+                       {tag: 'param', name: 'id', value: myid},
+                       {tag: 'param', name: 'PORT', value: param.port},
+                       {tag: 'param', name: 'PASSWORD', value: param.ticket},
+                       {tag: 'param', name: 'USERNAME', value: param.user},
+                       {tag: 'param', name: 'Show Controls', value: 'No'},
+                       {tag: 'param', name: 'Offer Relogin', value: 'No'},
+                       {tag: 'param', name: 'PVECert', value: cert}
+                   ]
+               });
+           }
+
+            if (me.toplevel) {
+               Ext.Function.defer(resize_window, 1000);
+            } else {
+               Ext.Function.defer(resize_box, 1000);
+            }
+       };
+
+       Ext.apply(me, {
+           layout: 'fit',
+           border: false,
+           autoScroll: me.toplevel ? false : true,
+           items: box,
+           reloadApplet: function() {
+               var params = Ext.apply({}, me.params);
+               if (me.novnc) {
+                   params.websocket = 1;
+               } 
+               PVE.Utils.API2Request({
+                   url: me.url,
+                   params: params,
+                   method: me.method || 'POST',
+                   failure: function(response, opts) {
+                       box.update(gettext('Error') + ' ' + response.htmlStatus);
+                   },
+                   success: function(response, opts) {
+                       start_vnc_viewer(response.result.data);
+                   }
+               });
+           }
+       });
+
+       me.callParent();
+
+       if (me.toplevel) {
+           me.on("render", me.reloadApplet);
+       } else {
+           me.on("show", me.reloadApplet);
+           me.on("hide", function() { box.update(""); });
+       }
+    }
+});
+
+Ext.define('PVE.KVMConsole', {
+    extend: 'PVE.VNCConsole',
+    alias: ['widget.pveKVMConsole'],
+
+    initComponent : function() {
+       var me = this;
+       if (!me.nodename) { 
+           throw "no node name specified";
+       }
+
+       if (!me.vmid) {
+           throw "no VM ID specified";
+       }
+
+       var baseUrl = "/nodes/" + me.nodename + "/qemu/" + me.vmid;
+
+       var vm_command = function(cmd, params, reload_applet) {
+           PVE.Utils.API2Request({
+               params: params,
+               url: baseUrl + "/status/" + cmd,
+               method: 'POST',
+               waitMsgTarget: me,
+               failure: function(response, opts) {
+                   Ext.Msg.alert('Error', response.htmlStatus);
+               },
+               success: function() {
+                   if (reload_applet) {
+                       Ext.Function.defer(me.reloadApplet, 1000, me);
+                   }
+               }
+           });
+       };
+
+       var tbar = [ 
+           { 
+               text: gettext('Start'),
+               handler: function() { 
+                   vm_command("start", {}, 1);
+               }
+           },
+           { 
+               text: gettext('Shutdown'),
+               handler: function() {
+                   var msg = Ext.String.format(gettext("Do you really want to shutdown VM {0}?"), me.vmid);
+                   Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
+                       if (btn !== 'yes') {
+                           return;
+                       }
+                       vm_command('shutdown');
+                   });
+               }                           
+           }, 
+           { 
+               text: gettext('Stop'),
+               handler: function() {
+                   var msg = Ext.String.format(gettext("Do you really want to stop VM {0}?"), me.vmid);
+                   Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
+                       if (btn !== 'yes') {
+                           return;
+                       }
+                       vm_command("stop");
+                   }); 
+               }
+           },
+           { 
+               xtype: 'pveQemuSendKeyMenu',
+               nodename: me.nodename,
+               vmid: me.vmid
+           },
+           { 
+               text: gettext('Reset'),
+               handler: function() { 
+                   var msg = Ext.String.format(gettext("Do you really want to reset VM {0}?"), me.vmid);
+                   Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
+                       if (btn !== 'yes') {
+                           return;
+                       }
+                       vm_command("reset");
+                   });
+               }
+           },
+           { 
+               text: gettext('Suspend'),
+               handler: function() {
+                   var msg = Ext.String.format(gettext("Do you really want to suspend VM {0}?"), me.vmid);
+                   Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
+                       if (btn !== 'yes') {
+                           return;
+                       }
+                       vm_command("suspend");
+                   }); 
+               }
+           },
+           { 
+               text: gettext('Resume'),
+               handler: function() {
+                   vm_command("resume"); 
+               }
+           },
+           // Note: no migrate here, because we can't display migrate log
+            { 
+                text: gettext('Console'),
+                handler: function() {
+                   PVE.Utils.openVNCViewer('kvm', me.vmid, me.nodename, me.vmname, me.novnc);
+               }
+            },
+            '->',
+           {
+                text: gettext('Refresh'),
+               hidden: me.novnc ? true : false,
+               handler: function() { 
+                   var applet = Ext.getDom(me.appletID);
+                   applet.sendRefreshRequest();
+               }
+           },
+           {
+                text: gettext('Reload'),
+                handler: function () { 
+                   me.reloadApplet(); 
+               }
+           }
+       ];
+
+       
+       Ext.apply(me, {
+           tbar: tbar,
+           url: baseUrl + "/vncproxy",
+           wsurl: baseUrl + "/vncwebsocket"
+       });
+
+       me.callParent();
+    }
+});
+
+Ext.define('PVE.LxcConsole', {
+    extend: 'PVE.VNCConsole',
+    alias: ['widget.pveLxcConsole'],
+
+    initComponent : function() {
+       var me = this;
+       if (!me.nodename) { 
+           throw "no node name specified";
+       }
+
+       if (!me.vmid) {
+           throw "no VM ID specified";
+       }
+
+       var baseUrl = "/nodes/" + me.nodename + "/lxc/" + me.vmid;
+       var vm_command = function(cmd, params, reload_applet) {
+           PVE.Utils.API2Request({
+               params: params,
+               url: baseUrl + "/status/" + cmd,
+               waitMsgTarget: me,
+               method: 'POST',
+               failure: function(response, opts) {
+                   Ext.Msg.alert('Error', response.htmlStatus);
+               },
+               success: function() {
+                   if (reload_applet) {
+                       Ext.Function.defer(me.reloadApplet, 1000, me);
+                   }
+               }
+           });
+       };
+
+       var tbar = [ 
+           { 
+               text: gettext('Start'),
+               handler: function() { 
+                   vm_command("start");
+               }
+           },
+           { 
+               text: gettext('Shutdown'),
+               handler: function() {
+                   var msg = Ext.String.format(gettext("Do you really want to shutdown VM {0}?"), me.vmid);
+                   Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
+                       if (btn !== 'yes') {
+                           return;
+                       }
+                       vm_command("shutdown");
+                   }); 
+               }
+           },
+           { 
+               text: gettext('Stop'),
+               handler: function() {
+                   var msg = Ext.String.format(gettext("Do you really want to stop VM {0}?"), me.vmid);
+                   Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
+                       if (btn !== 'yes') {
+                           return;
+                       }
+                       vm_command("stop");
+                   }); 
+               }
+           },
+           // Note: no migrate here, because we can't display migrate log
+            '->',
+           {
+                text: gettext('Refresh'),
+               hidden: me.novnc ? true : false,
+               handler: function() { 
+                   var applet = Ext.getDom(me.appletID);
+                   applet.sendRefreshRequest();
+               }
+           },
+           {
+                text: gettext('Reload'),
+                handler: function () { 
+                   me.reloadApplet(); 
+               }
+           }
+       ];
+
+       Ext.apply(me, {
+           tbar: tbar,
+           url: baseUrl + "/vncproxy",
+           wsurl: baseUrl + "/vncwebsocket"
+       });
+
+       me.callParent();
+    }
+});
+
+Ext.define('PVE.Shell', {
+    extend: 'PVE.VNCConsole',
+    alias: ['widget.pveShell'],
+
+    ugradeSystem: false, // set to true to run "apt-get dist-upgrade"
+
+    initComponent : function() {
+       var me = this;
+       if (!me.nodename) { 
+           throw "no node name specified";
+       }
+
+       var tbar = [ '->' ];
+
+       if (!me.novnc) {
+           tbar.push({
+                text: gettext('Refresh'),
+               handler: function() { 
+                   var applet = Ext.getDom(me.appletID);
+                   applet.sendRefreshRequest();
+               }
+           });
+       }
+
+       if (!me.ugradeSystem) {
+           // we dont want to restart the upgrade script
+           tbar.push({
+                text: gettext('Reload'),
+                handler: function () { me.reloadApplet(); }
+           });
+       }
+
+       tbar.push({ 
+           text: gettext('Shell'),
+           handler: function() {
+               PVE.Utils.openVNCViewer('shell', undefined, me.nodename, undefined, me.novnc);
+           }
+       });
+
+       var baseUrl = "/nodes/" + me.nodename;
+
+       Ext.apply(me, {
+           tbar: tbar,
+           url: baseUrl + "/vncshell",
+           wsurl: baseUrl + "/vncwebsocket"
+       });
+
+       if (me.ugradeSystem) {
+           me.params = { upgrade: 1 };     
+       }
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/Workspace.js b/www/manager6/Workspace.js
new file mode 100644 (file)
index 0000000..a4102eb
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+ * Workspace base class
+ *
+ * popup login window when auth fails (call onLogin handler)
+ * update (re-login) ticket every 15 minutes
+ *
+ */
+
+Ext.define('PVE.Workspace', {
+    extend: 'Ext.container.Viewport',
+
+    title: 'Proxmox Virtual Environment',
+
+    loginData: null, // Data from last login call
+
+    onLogin: function(loginData) {},
+
+    // private
+    updateLoginData: function(loginData) {
+       var me = this;
+       me.loginData = loginData;
+       PVE.CSRFPreventionToken = loginData.CSRFPreventionToken;
+       PVE.UserName = loginData.username;
+
+       if (loginData.cap) {
+           Ext.state.Manager.set('GuiCap', loginData.cap);
+       }
+
+       // creates a session cookie (expire = null) 
+       // that way the cookie gets deleted after browser window close
+       Ext.util.Cookies.set('PVEAuthCookie', loginData.ticket, null, '/', null, true);
+       me.onLogin(loginData);
+    },
+
+    // private
+    showLogin: function() {
+       var me = this;
+
+       PVE.Utils.authClear();
+       PVE.UserName = null;
+       me.loginData = null;
+
+       if (!me.login) {
+           me.login = Ext.create('PVE.window.LoginWindow', {
+               handler: function(data) {
+                   me.login = null;
+                   me.updateLoginData(data);
+                   PVE.Utils.checked_command(function() {}); // display subscription status
+               }
+           });
+       }
+       me.onLogin(null);
+        me.login.show();
+    },
+
+    initComponent : function() {
+       var me = this;
+
+       Ext.tip.QuickTipManager.init();
+
+       // fixme: what about other errors
+       Ext.Ajax.on('requestexception', function(conn, response, options) {
+           if (response.status == 401) { // auth failure
+               me.showLogin();
+           }
+       });
+
+       document.title = me.title;
+
+       me.callParent();
+
+        if (!PVE.Utils.authOK()) {
+           me.showLogin();
+       } else { 
+           if (me.loginData) {
+               me.onLogin(me.loginData);
+           }
+       }
+
+       Ext.TaskManager.start({
+           run: function() {
+               var ticket = PVE.Utils.authOK();
+               if (!ticket || !PVE.UserName) {
+                   return;
+               }
+
+               Ext.Ajax.request({
+                   params: { 
+                       username: PVE.UserName,
+                       password: ticket
+                   },
+                   url: '/api2/json/access/ticket',
+                   method: 'POST',
+                   success: function(response, opts) {
+                       var obj = Ext.decode(response.responseText);
+                       me.updateLoginData(obj.data);
+                   }
+               });
+           },
+           interval: 15*60*1000
+       });
+
+    }
+});
+
+Ext.define('PVE.ConsoleWorkspace', {
+    extend: 'PVE.Workspace',
+
+    alias: ['widget.pveConsoleWorkspace'],
+
+    title: gettext('Console'),
+
+    initComponent : function() {
+       var me = this;
+
+       var param = Ext.Object.fromQueryString(window.location.search);
+       var consoleType = me.consoleType || param.console;
+
+       param.novnc = (param.novnc === '1') ? true : false;
+
+       var content;
+       if (consoleType === 'kvm') {
+           me.title = "VM " + param.vmid;
+           if (param.vmname) {
+               me.title += " ('" + param.vmname + "')";
+           }
+           content = {
+               xtype: 'pveKVMConsole',
+               novnc: param.novnc,
+               vmid: param.vmid,
+               nodename: param.node,
+               vmname: param.vmname,
+               toplevel: true
+           };
+       } else if (consoleType === 'lxc') {
+           me.title = "CT " + param.vmid;
+           if (param.vmname) {
+               me.title += " ('" + param.vmname + "')";
+           }
+           content = {
+               xtype: 'pveLxcConsole',
+               novnc: param.novnc,
+               vmid: param.vmid,
+               nodename: param.node,
+               vmname: param.vmname,
+               toplevel: true
+           };
+       } else if (consoleType === 'shell') {
+           me.title = "node '" + param.node + "'";
+           content = {
+               xtype: 'pveShell',
+               novnc: param.novnc,
+               nodename: param.node,
+               toplevel: true
+           };
+       } else if (consoleType === 'upgrade') {
+           me.title = Ext.String.format(gettext('System upgrade on node {0}'), "'" + param.node + "'");
+           content = {
+               xtype: 'pveShell',
+               novnc: param.novnc,
+               nodename: param.node,
+               ugradeSystem: true,
+               toplevel: true
+           };
+       } else {
+           content = {
+               border: false,
+               bodyPadding: 10,
+               html: gettext('Error') + ': No such console type'
+           };
+       }
+
+       Ext.apply(me, {
+           layout: { type: 'fit' },
+           border: false,
+           items: [ content ]
+       });
+
+       me.callParent();       
+    }
+});
+
+Ext.define('PVE.StdWorkspace', {
+    extend: 'PVE.Workspace',
+
+    alias: ['widget.pveStdWorkspace'],
+
+    // private
+    setContent: function(comp) {
+       var me = this;
+       
+       var cont = me.child('#content');
+       cont.removeAll(true);
+
+       if (comp) {
+           PVE.Utils.setErrorMask(cont, false);
+           comp.border = false;
+           cont.add(comp);
+           cont.doLayout();
+       } 
+       // else {
+           // TODO: display something useful
+
+           // Note:: error mask has wrong zindex, so we do not
+           // use that - see bug 114
+           // PVE.Utils.setErrorMask(cont, 'nothing selected');
+       //}
+    },
+
+    selectById: function(nodeid) {
+       var me = this;
+       var tree = me.down('pveResourceTree');
+       tree.selectById(nodeid);
+    },
+
+    checkVmMigration: function(record) {
+       var me = this;
+       var tree = me.down('pveResourceTree');
+       tree.checkVmMigration(record);
+    },
+
+    onLogin: function(loginData) {
+       var me = this;
+
+       me.updateUserInfo();
+
+       if (loginData) {
+           PVE.data.ResourceStore.startUpdate();
+
+           PVE.Utils.API2Request({
+               url: '/version',
+               method: 'GET',
+               success: function(response) {
+                   PVE.VersionInfo = response.result.data;
+                   me.updateVersionInfo();
+               }
+           });
+       }
+    },
+
+    updateUserInfo: function() {
+       var me = this;
+
+       var ui = me.query('#userinfo')[0];
+
+       if (PVE.UserName) {
+           var msg =  Ext.String.format(gettext("You are logged in as {0}"), "'" + PVE.UserName + "'");
+           ui.update('<div class="x-unselectable" style="white-space:nowrap;">' + msg + '</div>');
+       } else {
+           ui.update('');
+       }
+       ui.doLayout();
+    },
+
+    updateVersionInfo: function() {
+       var me = this;
+
+       var ui = me.query('#versioninfo')[0];
+
+       if (PVE.VersionInfo) {
+           var version = PVE.VersionInfo.version + '-' + PVE.VersionInfo.release + '/' +
+               PVE.VersionInfo.repoid;
+           ui.update('Proxmox Virtual Environment<br>' + gettext('Version') + ': ' + version);
+       } else {
+           ui.update('Proxmox Virtual Environment');
+       }
+       ui.doLayout();
+    },
+
+    initComponent : function() {
+       var me = this;
+
+       Ext.History.init();
+
+       var sprovider = Ext.create('PVE.StateProvider');
+       Ext.state.Manager.setProvider(sprovider);
+
+       var selview = new PVE.form.ViewSelector({});
+
+       var rtree = Ext.createWidget('pveResourceTree', {
+           viewFilter: selview.getViewFilter(),
+           flex: 1,
+           selModel: new Ext.selection.TreeModel({
+               listeners: {
+                   selectionchange: function(sm, selected) {
+                       var comp;
+                       var tlckup = {
+                           root: 'PVE.dc.Config',
+                           node: 'PVE.node.Config',
+                           qemu: 'PVE.qemu.Config',
+                           lxc: 'PVE.lxc.Config',
+                           storage: 'PVE.storage.Browser',
+                           pool: 'pvePoolConfig'
+                       };
+                       
+                       if (selected.length > 0) {
+                           var n = selected[0];
+                           comp = {
+                               xtype: tlckup[n.data.type || 'root'] || 
+                                   'pvePanelConfig',
+                               layout: { type: 'fit' },
+                               showSearch: (n.data.id === 'root') ||
+                                   Ext.isDefined(n.data.groupbyid),
+                               pveSelNode: n,
+                               workspace: me,
+                               viewFilter: selview.getViewFilter()
+                           };
+                           PVE.curSelectedNode = n;
+                       }
+
+                       me.setContent(comp);
+                   }
+               }
+           })
+       });
+
+       selview.on('select', function(combo, records) { 
+           if (records && records.length) {
+               var view = combo.getViewFilter();
+               rtree.setViewFilter(view);
+           }
+       });
+
+       var caps = sprovider.get('GuiCap');
+
+       var createVM = Ext.createWidget('button', {
+           pack: 'end',
+           margin: '3 5 0 0',
+           baseCls: 'x-btn',
+           text: gettext("Create VM"),
+           disabled: !caps.vms['VM.Allocate'],
+           handler: function() {
+               var wiz = Ext.create('PVE.qemu.CreateWizard', {});
+               wiz.show();
+           } 
+       });
+
+       var createCT = Ext.createWidget('button', {
+           pack: 'end',
+           margin: '3 5 0 0',
+           baseCls: 'x-btn',
+           text: gettext("Create CT"),
+           disabled: !caps.vms['VM.Allocate'],
+           handler: function() {
+               var wiz = Ext.create('PVE.lxc.CreateWizard', {});
+               wiz.show();
+           } 
+       });
+
+       sprovider.on('statechange', function(sp, key, value) {
+           if (key === 'GuiCap' && value) {
+               caps = value;
+               createVM.setDisabled(!caps.vms['VM.Allocate']);
+               createCT.setDisabled(!caps.vms['VM.Allocate']);
+           }
+       });
+
+       Ext.apply(me, {
+           layout: { type: 'border' },
+           border: false,
+           items: [
+               {
+                   region: 'north',
+                   height: 30,
+                   layout: { 
+                       type: 'hbox',
+                   },
+                   baseCls: 'x-plain',         
+                   defaults: {
+                       baseCls: 'x-plain'                      
+                   },
+                   border: false,
+                   margin: '2 0 5 0',
+                   items: [
+                       {
+                           margin: '0 0 0 4',
+                           html: '<a class="x-unselectable" target=_blank href="http://www.proxmox.com">' +
+                               '<img height=30 width=209 src="/pve2/images/proxmox_logo.png"/></a>'
+                       },
+                       {
+                           minWidth: 200,
+                           flex: 1,
+                           id: 'versioninfo',
+                           html: 'Proxmox Virtual Environment',
+                           height: 30
+                       },
+                       {
+                           pack: 'end',
+                           margin: '8 10 0 10',
+                           id: 'userinfo',
+                           stateful: false
+                       },
+                       {
+                           pack: 'end',
+                           margin: '3 5 0 0',
+                           xtype: 'button',
+                           baseCls: 'x-btn',
+                           text: gettext("Logout"),
+                           handler: function() { 
+                               PVE.data.ResourceStore.stopUpdate();
+                               me.showLogin(); 
+                               me.setContent(); 
+                               var rt = me.down('pveResourceTree');
+                               rt.clearTree();
+                           }
+                       }, 
+                       createVM, 
+                       createCT
+                   ]
+               },
+               {
+                   region: 'center',
+                   id: 'content',
+                   xtype: 'container',
+                   layout: { type: 'fit' },
+                   border: false,
+                   stateful: false,
+                   margin: '0 5 0 0',
+                   items: []
+               },
+               {
+                   region: 'west',
+                   xtype: 'container',
+                   border: false,
+                   layout: { type: 'vbox', align: 'stretch' },
+                   margin: '0 0 0 5',
+                   split: true,
+                   width: 200,
+                   items: [ selview, rtree ]
+               },
+               {
+                   xtype: 'pveStatusPanel',
+                   region: 'south',
+                   margin:'0 5 5 5',
+                   height: 200,       
+                   split:true
+               }
+           ]
+       });
+
+       me.callParent();
+
+       me.updateUserInfo();
+    }
+});
+
diff --git a/www/manager6/button/Button.js b/www/manager6/button/Button.js
new file mode 100644 (file)
index 0000000..3866899
--- /dev/null
@@ -0,0 +1,76 @@
+/* Button features:
+ * - observe selection changes to enable/disable the button using enableFn()
+ * - pop up confirmation dialog using confirmMsg()
+ */
+Ext.define('PVE.button.Button', {
+    extend: 'Ext.button.Button',
+    alias: 'widget.pveButton',
+
+    // the selection model to observe
+    selModel: undefined,
+
+    // if 'false' handler will not be called (button disabled)
+    enableFn: function(record) { },
+
+    // function(record) or text
+    confirmMsg: false,
+
+    // take special care in confirm box (select no as default).
+    dangerous: false,
+
+    initComponent: function() {
+       /*jslint confusion: true */
+
+        var me = this;
+
+       if (me.handler) {
+           me.realHandler = me.handler;
+
+           me.handler = function(button, event) {
+               var rec, msg;
+               if (me.selModel) {
+                   rec = me.selModel.getSelection()[0];
+                   if (!rec || (me.enableFn(rec) === false)) {
+                       return;
+                   }
+               }
+
+               if (me.confirmMsg) {
+                   msg = me.confirmMsg;
+                   if (Ext.isFunction(me.confirmMsg)) {
+                       msg = me.confirmMsg(rec);
+                   }
+                   Ext.MessageBox.defaultButton = me.dangerous ? 2 : 1;
+                   Ext.Msg.show({
+                       title: gettext('Confirm'),
+                       icon: me.dangerous ? Ext.Msg.WARNING : Ext.Msg.QUESTION,
+                       msg: msg,
+                       buttons: Ext.Msg.YESNO,
+                       callback: function(btn) {
+                           if (btn !== 'yes') {
+                               return;
+                           }
+                           me.realHandler(button, event, rec);
+                       }
+                   });
+               } else {
+                   me.realHandler(button, event, rec);
+               }
+           };
+       }
+
+       me.callParent();
+
+       if (me.selModel) {
+
+           me.mon(me.selModel, "selectionchange", function() {
+               var rec = me.selModel.getSelection()[0];
+               if (!rec || (me.enableFn(rec) === false)) {
+                   me.setDisabled(true);
+               } else  {
+                   me.setDisabled(false);
+               }
+           });
+       }
+    }
+});
diff --git a/www/manager6/button/ConsoleButton.js b/www/manager6/button/ConsoleButton.js
new file mode 100644 (file)
index 0000000..cba4984
--- /dev/null
@@ -0,0 +1,59 @@
+Ext.define('PVE.button.ConsoleButton', {
+    extend: 'Ext.button.Split',
+    alias: 'widget.pveConsoleButton',
+
+    consoleType: 'shell', // one of 'shell', 'kvm', 'lxc', 'upgrade'
+
+    consoleName: undefined,
+
+    enableSpice: true,
+
+    nodename: undefined,
+
+    vmid: 0,
+
+    setEnableSpice: function(enable){
+       var me = this;
+
+       me.enableSpice = enable;
+       me.spiceMenu.setDisabled(!enable);
+    },
+
+    initComponent: function() {
+        var me = this;
+
+       if (!me.nodename) {
+           throw "no node name specified";
+       }
+
+       me.spiceMenu = Ext.create('Ext.menu.Item', {
+           text: 'SPICE',
+           iconCls: 'pve-itype-icon-virt-viewer',
+           handler: function() { 
+               PVE.Utils.openConsoleWindow('vv', me.consoleType, me.vmid, me.nodename, me.consoleName);
+           }
+       });
+
+       var noVncMenu = Ext.create('Ext.menu.Item', {
+           text: 'noVNC',
+           iconCls: 'pve-itype-icon-novnc',
+           handler: function() { 
+               PVE.Utils.openConsoleWindow('html5', me.consoleType, me.vmid, me.nodename, me.consoleName);
+           }
+       });
+
+       Ext.applyIf(me, { text: gettext('Console') });
+
+       Ext.apply(me, {
+           handler: function() {
+               PVE.Utils.openDefaultConsoleWindow(me.enableSpice, me.consoleType, me.vmid, 
+                                                  me.nodename, me.consoleName);
+           },
+           menu: new Ext.menu.Menu({
+               items: [ noVncMenu, me.spiceMenu ]
+           })
+       });
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/data/DiffStore.js b/www/manager6/data/DiffStore.js
new file mode 100644 (file)
index 0000000..66bcfed
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * The DiffStore acts as proxy between an UpdateStore instance and a component.
+ * Its purpose is to redisplay the component *only* if the data has been changed
+ * inside the UpdateStore, to avoid the annoying visual flickering of using
+ * the UpdateStore directly.
+ *
+ * Implementation:
+ * The DiffStore monitors via mon() the 'load' events sent by the target store.
+ * On each 'load' event, the DiffStore compares its own content with the target
+ * store (call to cond_add_item()) and then fires a 'refresh' event.
+ * The 'refresh' event will automatically trigger a view refresh on the component
+ * who binds to this store.
+ */
+
+/* Config properties:
+ * rstore: A target store to track changes
+ * Only works if rstore has a model and use 'idProperty'
+ */
+Ext.define('PVE.data.DiffStore', {
+    extend: 'Ext.data.Store',
+
+    sortAfterUpdate: false,
+    
+    constructor: function(config) {
+       var me = this;
+
+       config = config || {};
+
+       if (!config.rstore) {
+           throw "no rstore specified";
+       }
+
+       if (!config.rstore.model) {
+           throw "no rstore model specified";
+       }
+
+       var rstore = config.rstore;
+
+       Ext.apply(config, {
+           model: rstore.model,
+           proxy: { type: 'memory' }
+       });
+
+       me.callParent([config]);
+
+       var first_load = true;
+
+       var cond_add_item = function(data, id) {
+           var olditem = me.getById(id);
+           if (olditem) {
+               olditem.beginEdit();
+               Ext.Array.each(me.model.prototype.fields, function(field) {
+                   if (olditem.data[field.name] !== data[field.name]) {
+                       olditem.set(field.name, data[field.name]);
+                   }
+               });
+               olditem.endEdit(true);
+               olditem.commit(); 
+           } else {
+               var newrec = Ext.create(me.model, data);
+               var pos = (me.appendAtStart && !first_load) ? 0 : me.data.length;
+               me.insert(pos, newrec);
+           }
+       };
+
+       me.mon(rstore, 'load', function(s, records, success) {
+
+           if (!success) {
+               return;
+           }
+
+           me.suspendEvents();
+
+           // remove vanished items
+           (me.snapshot || me.data).each(function(olditem) {
+               var item = rstore.getById(olditem.getId());
+               if (!item) {
+                   me.remove(olditem);
+               }
+           });
+
+           rstore.each(function(item) {
+               cond_add_item(item.data, item.getId());
+           });
+
+           me.filter();
+
+           if (me.sortAfterUpdate) {
+               me.sort();
+           }
+
+           first_load = false;
+
+           me.resumeEvents();
+           me.fireEvent('refresh', me);
+       });
+    }
+});
diff --git a/www/manager6/data/ObjectStore.js b/www/manager6/data/ObjectStore.js
new file mode 100644 (file)
index 0000000..6db1e6c
--- /dev/null
@@ -0,0 +1,35 @@
+/* This store encapsulates data items which are organized as an Array of key-values Objects
+ * ie data[0] contains something like {key: "keyboard", value: "da"}
+*
+* Designed to work with the KeyValue model and the JsonObject data reader
+*/
+Ext.define('PVE.data.ObjectStore',  {
+    extend: 'PVE.data.UpdateStore',
+
+    constructor: function(config) {
+       var me = this;
+
+        config = config || {};
+
+       if (!config.storeid) {
+           config.storeid =  'pve-store-' + (++Ext.idSeed);
+       }
+
+        Ext.applyIf(config, {
+           model: 'KeyValue',
+            proxy: {
+                type: 'pve',
+               url: config.url,
+               extraParams: config.extraParams,
+                reader: {
+                   type: 'jsonobject',
+                   rows: config.rows,
+                   readArray: config.readArray,
+                   rootProperty: config.root || 'data'
+               }
+            }
+        });
+
+        me.callParent([config]);
+    }
+});
diff --git a/www/manager6/data/PVEProxy.js b/www/manager6/data/PVEProxy.js
new file mode 100644 (file)
index 0000000..01c20cb
--- /dev/null
@@ -0,0 +1,114 @@
+Ext.define('PVE.RestProxy', {
+    extend: 'Ext.data.RestProxy',
+    alias : 'proxy.pve',
+    
+    pageParam : null,
+    startParam: null,
+    limitParam: null,
+    groupParam: null,
+    sortParam: null,
+    filterParam: null,
+    noCache : false,
+    afterRequest: function(request, success) {
+               this.fireEvent('afterload', this, request, success);
+               return;
+       },
+
+    constructor: function(config) {
+
+       Ext.applyIf(config, {       
+           reader: {
+               type: 'json',
+               rootProperty: config.root || 'data'
+           },
+       });
+
+       this.callParent([config]); 
+    }
+
+}, function() {
+
+    Ext.define('pve-domains', {
+       extend: "Ext.data.Model",
+       fields: [ 'realm', 'type', 'comment', 'default', 'tfa',
+                 { 
+                     name: 'descr',
+                     // Note: We use this in the RealmComboBox.js
+                     // (see Bug #125)
+                     convert: function(value, record) {
+                         var info = record.data;
+                         var text;
+
+                         if (value) {
+                             return value;
+                         }
+                         // return realm if there is no comment
+                         text = info.comment || info.realm;
+
+                         if (info.tfa) {
+                             text += " (+ " + info.tfa + ")";
+                         }
+
+                         return text;
+                     }
+                 }
+               ],
+       proxy: {
+           type: 'pve',
+           url: "/api2/json/access/domains"
+       }
+    });
+
+    Ext.define('KeyValue', {
+       extend: "Ext.data.Model",
+       fields: [ 'key', 'value' ]
+    });
+
+    Ext.define('KeyValuePendingDelete', {
+       extend: "Ext.data.Model",
+       fields: [ 'key', 'value', 'pending', 'delete' ],
+       idProperty: 'key'
+    });
+
+    Ext.define('pve-string-list', {
+       extend: 'Ext.data.Model',
+       fields:  [ 'n', 't' ],
+       idProperty: 'n'
+    });
+
+    Ext.define('pve-tasks', {
+       extend: 'Ext.data.Model',
+       fields:  [ 
+           { name: 'starttime', type : 'date', dateFormat: 'timestamp' }, 
+           { name: 'endtime', type : 'date', dateFormat: 'timestamp' }, 
+           { name: 'pid', type: 'int' },
+           'node', 'upid', 'user', 'status', 'type', 'id'
+       ],
+       idProperty: 'upid'
+    });
+
+    Ext.define('pve-cluster-log', {
+       extend: 'Ext.data.Model',
+       fields:  [ 
+           { name: 'uid' , type: 'int' },
+           { name: 'time', type : 'date', dateFormat: 'timestamp' }, 
+           { name: 'pri', type: 'int' },
+           { name: 'pid', type: 'int' },
+           'node', 'user', 'tag', 'msg',
+           {
+               name: 'id',
+               convert: function(value, record) {
+                   var info = record.data;
+                   var text;
+
+                   if (value) {
+                       return value;
+                   }
+                   // compute unique ID
+                   return info.uid + ':' + info.node;
+               }
+           }
+       ],
+       idProperty: 'id'
+    });
+});
diff --git a/www/manager6/data/ResourceStore.js b/www/manager6/data/ResourceStore.js
new file mode 100644 (file)
index 0000000..c757a46
--- /dev/null
@@ -0,0 +1,248 @@
+Ext.define('PVE.data.ResourceStore', {
+    extend: 'PVE.data.UpdateStore',
+    singleton: true,
+
+    findVMID: function(vmid) {
+       var me = this, i;
+       
+       return (me.findExact('vmid', parseInt(vmid, 10)) >= 0);
+    },
+    constructor: function(config) {
+       // fixme: how to avoid those warnings
+       /*jslint confusion: true */
+
+       var me = this;
+
+       config = config || {};
+
+       var field_defaults = {
+           type: {
+               header: gettext('Type'),
+               type: 'string',
+               renderer: PVE.Utils.render_resource_type,
+               sortable: true,
+               hideable: false,
+               width: 80
+           },
+           id: {
+               header: 'ID',
+               type: 'string',
+               hidden: true,
+               sortable: true,
+               width: 80
+           },
+           running: {
+               header: gettext('Online'),
+               type: 'boolean',
+               renderer: PVE.Utils.format_boolean,
+               hidden: true,
+               convert: function(value, record) {
+                   var info = record.data;
+                   if (info.type === 'qemu' || info.type === 'lxc' || info.type === 'node') {
+                       return (Ext.isNumeric(info.uptime) && (info.uptime > 0));
+                   } else {
+                       return false;
+                   }
+               }
+           },
+           text: {
+               header: gettext('Description'),
+               type: 'string',
+               sortable: true,
+               width: 200,
+               convert: function(value, record) {
+                   var info = record.data;
+                   var text;
+
+                   if (value) {
+                       return value;
+                   }
+
+                   if (info.type === 'node') {
+                       text = info.node;
+                   } else if (info.type === 'pool') {
+                       text = info.pool;
+                   } else if (info.type === 'storage') {
+                       text = info.storage + ' (' + info.node + ')';
+                   } else if (info.type === 'qemu' || info.type === 'lxc') {
+                       text = String(info.vmid);
+                       if (info.name) {
+                           text += " (" + info.name + ')';
+                       }
+                   } else {
+                       text = info.id;
+                   }
+                   return text;
+               }
+           },
+           vmid: {
+               header: 'VMID',
+               type: 'integer',
+               hidden: true,
+               sortable: true,
+               width: 80
+           },
+           name: {
+               header: gettext('Name'),
+               hidden: true,
+               sortable: true,
+               type: 'string'
+           },
+           disk: {
+               header: gettext('Disk usage'),
+               type: 'integer',
+               renderer: PVE.Utils.render_disk_usage,
+               sortable: true,
+               width: 100
+           },
+           maxdisk: {
+               header: gettext('Disk size'),
+               type: 'integer',
+               renderer: PVE.Utils.render_size,
+               sortable: true,
+               hidden: true,
+               width: 100
+           },
+           mem: {
+               header: gettext('Memory usage'),
+               type: 'integer',
+               renderer: PVE.Utils.render_mem_usage,
+               sortable: true,
+               width: 100
+           },
+           maxmem: {
+               header: gettext('Memory size'),
+               type: 'integer',
+               renderer: PVE.Utils.render_size,
+               hidden: true,
+               sortable: true,
+               width: 100
+           },
+           cpu: {
+               header: gettext('CPU usage'),
+               type: 'float',
+               renderer: PVE.Utils.render_cpu,
+               sortable: true,
+               width: 100
+           },
+           maxcpu: {
+               header: gettext('maxcpu'),
+               type: 'integer',
+               hidden: true,
+               sortable: true,
+               width: 60
+           },
+           diskread: {
+               header: gettext('Total Disk Read'),
+               type: 'integer',
+               hidden: true,
+               sortable: true,
+               renderer: PVE.Utils.format_size,
+               width: 100
+           },
+           diskwrite: {
+               header: gettext('Total Disk Write'),
+               type: 'integer',
+               hidden: true,
+               sortable: true,
+               renderer: PVE.Utils.format_size,
+               width: 100
+           },
+           netin: {
+               header: gettext('Total NetIn'),
+               type: 'integer',
+               hidden: true,
+               sortable: true,
+               renderer: PVE.Utils.format_size,
+               width: 100
+           },
+           netout: {
+               header: gettext('Total NetOut'),
+               type: 'integer',
+               hidden: true,
+               sortable: true,
+               renderer: PVE.Utils.format_size,
+               width: 100
+           },
+           template: {
+               header: gettext('Template'),
+               type: 'integer',
+               hidden: true,
+               sortable: true,
+               width: 60
+           },
+           uptime: {
+               header: gettext('Uptime'),
+               type: 'integer',
+               renderer: PVE.Utils.render_uptime,
+               sortable: true,
+               width: 110
+           }, 
+           node: {
+               header: gettext('Node'),
+               type: 'string',
+               hidden: true,
+               sortable: true,
+               width: 110
+           },
+           storage: {
+               header: gettext('Storage'),
+               type: 'string',
+               hidden: true,
+               sortable: true,
+               width: 110
+           },
+           pool: {
+               header: gettext('Pool'),
+               type: 'string',
+               hidden: true,
+               sortable: true,
+               width: 110
+           }
+       };
+
+       var fields = [];
+       var fieldNames = [];
+       Ext.Object.each(field_defaults, function(key, value) {
+           if (!Ext.isDefined(value.convert)) {
+               fields.push({name: key, type: value.type});
+               fieldNames.push(key);
+           } else if (key === 'text' || key === 'running') { 
+               fields.push({name: key, type: value.type, convert: value.convert});
+               fieldNames.push(key);
+           }           
+       });
+
+       Ext.define('PVEResources', {
+           extend: "Ext.data.Model",
+           fields: fields,
+           proxy: {
+               type: 'pve',
+               url: '/api2/json/cluster/resources'
+           }
+       });
+
+       Ext.define('PVETree', {
+           extend: "Ext.data.Model",
+           fields: fields,
+           proxy: { type: 'memory' }
+       });
+
+       Ext.apply(config, {
+           storeid: 'PVEResources',
+           model: 'PVEResources',
+           defaultColums: function() {
+               var res = [];
+               Ext.Object.each(field_defaults, function(field, info) {
+                   var fi = Ext.apply({ dataIndex: field }, info);
+                   res.push(fi);
+               });
+               return res;
+           },
+           fieldNames: fieldNames
+       });
+
+       me.callParent([config]);
+    }
+});
diff --git a/www/manager6/data/TimezoneStore.js b/www/manager6/data/TimezoneStore.js
new file mode 100644 (file)
index 0000000..f00cc2f
--- /dev/null
@@ -0,0 +1,436 @@
+Ext.define('PVE.data.TimezoneStore', {
+    extend: 'Ext.data.Store',
+
+    statics: {
+       timezones: [
+           ['Africa/Abidjan'],
+           ['Africa/Accra'],
+           ['Africa/Addis_Ababa'],
+           ['Africa/Algiers'],
+           ['Africa/Asmara'],
+           ['Africa/Bamako'],
+           ['Africa/Bangui'],
+           ['Africa/Banjul'],
+           ['Africa/Bissau'],
+           ['Africa/Blantyre'],
+           ['Africa/Brazzaville'],
+           ['Africa/Bujumbura'],
+           ['Africa/Cairo'],
+           ['Africa/Casablanca'],
+           ['Africa/Ceuta'],
+           ['Africa/Conakry'],
+           ['Africa/Dakar'],
+           ['Africa/Dar_es_Salaam'],
+           ['Africa/Djibouti'],
+           ['Africa/Douala'],
+           ['Africa/El_Aaiun'],
+           ['Africa/Freetown'],
+           ['Africa/Gaborone'],
+           ['Africa/Harare'],
+           ['Africa/Johannesburg'],
+           ['Africa/Kampala'],
+           ['Africa/Khartoum'],
+           ['Africa/Kigali'],
+           ['Africa/Kinshasa'],
+           ['Africa/Lagos'],
+           ['Africa/Libreville'],
+           ['Africa/Lome'],
+           ['Africa/Luanda'],
+           ['Africa/Lubumbashi'],
+           ['Africa/Lusaka'],
+           ['Africa/Malabo'],
+           ['Africa/Maputo'],
+           ['Africa/Maseru'],
+           ['Africa/Mbabane'],
+           ['Africa/Mogadishu'],
+           ['Africa/Monrovia'],
+           ['Africa/Nairobi'],
+           ['Africa/Ndjamena'],
+           ['Africa/Niamey'],
+           ['Africa/Nouakchott'],
+           ['Africa/Ouagadougou'],
+           ['Africa/Porto-Novo'],
+           ['Africa/Sao_Tome'],
+           ['Africa/Tripoli'],
+           ['Africa/Tunis'],
+           ['Africa/Windhoek'],
+           ['America/Adak'],
+           ['America/Anchorage'],
+           ['America/Anguilla'],
+           ['America/Antigua'],
+           ['America/Araguaina'],
+           ['America/Argentina/Buenos_Aires'],
+           ['America/Argentina/Catamarca'],
+           ['America/Argentina/Cordoba'],
+           ['America/Argentina/Jujuy'],
+           ['America/Argentina/La_Rioja'],
+           ['America/Argentina/Mendoza'],
+           ['America/Argentina/Rio_Gallegos'],
+           ['America/Argentina/Salta'],
+           ['America/Argentina/San_Juan'],
+           ['America/Argentina/San_Luis'],
+           ['America/Argentina/Tucuman'],
+           ['America/Argentina/Ushuaia'],
+           ['America/Aruba'],
+           ['America/Asuncion'],
+           ['America/Atikokan'],
+           ['America/Bahia'],
+           ['America/Bahia_Banderas'],
+           ['America/Barbados'],
+           ['America/Belem'],
+           ['America/Belize'],
+           ['America/Blanc-Sablon'],
+           ['America/Boa_Vista'],
+           ['America/Bogota'],
+           ['America/Boise'],
+           ['America/Cambridge_Bay'],
+           ['America/Campo_Grande'],
+           ['America/Cancun'],
+           ['America/Caracas'],
+           ['America/Cayenne'],
+           ['America/Cayman'],
+           ['America/Chicago'],
+           ['America/Chihuahua'],
+           ['America/Costa_Rica'],
+           ['America/Cuiaba'],
+           ['America/Curacao'],
+           ['America/Danmarkshavn'],
+           ['America/Dawson'],
+           ['America/Dawson_Creek'],
+           ['America/Denver'],
+           ['America/Detroit'],
+           ['America/Dominica'],
+           ['America/Edmonton'],
+           ['America/Eirunepe'],
+           ['America/El_Salvador'],
+           ['America/Fortaleza'],
+           ['America/Glace_Bay'],
+           ['America/Godthab'],
+           ['America/Goose_Bay'],
+           ['America/Grand_Turk'],
+           ['America/Grenada'],
+           ['America/Guadeloupe'],
+           ['America/Guatemala'],
+           ['America/Guayaquil'],
+           ['America/Guyana'],
+           ['America/Halifax'],
+           ['America/Havana'],
+           ['America/Hermosillo'],
+           ['America/Indiana/Indianapolis'],
+           ['America/Indiana/Knox'],
+           ['America/Indiana/Marengo'],
+           ['America/Indiana/Petersburg'],
+           ['America/Indiana/Tell_City'],
+           ['America/Indiana/Vevay'],
+           ['America/Indiana/Vincennes'],
+           ['America/Indiana/Winamac'],
+           ['America/Inuvik'],
+           ['America/Iqaluit'],
+           ['America/Jamaica'],
+           ['America/Juneau'],
+           ['America/Kentucky/Louisville'],
+           ['America/Kentucky/Monticello'],
+           ['America/La_Paz'],
+           ['America/Lima'],
+           ['America/Los_Angeles'],
+           ['America/Maceio'],
+           ['America/Managua'],
+           ['America/Manaus'],
+           ['America/Marigot'],
+           ['America/Martinique'],
+           ['America/Matamoros'],
+           ['America/Mazatlan'],
+           ['America/Menominee'],
+           ['America/Merida'],
+           ['America/Mexico_City'],
+           ['America/Miquelon'],
+           ['America/Moncton'],
+           ['America/Monterrey'],
+           ['America/Montevideo'],
+           ['America/Montreal'],
+           ['America/Montserrat'],
+           ['America/Nassau'],
+           ['America/New_York'],
+           ['America/Nipigon'],
+           ['America/Nome'],
+           ['America/Noronha'],
+           ['America/North_Dakota/Center'],
+           ['America/North_Dakota/New_Salem'],
+           ['America/Ojinaga'],
+           ['America/Panama'],
+           ['America/Pangnirtung'],
+           ['America/Paramaribo'],
+           ['America/Phoenix'],
+           ['America/Port-au-Prince'],
+           ['America/Port_of_Spain'],
+           ['America/Porto_Velho'],
+           ['America/Puerto_Rico'],
+           ['America/Rainy_River'],
+           ['America/Rankin_Inlet'],
+           ['America/Recife'],
+           ['America/Regina'],
+           ['America/Resolute'],
+           ['America/Rio_Branco'],
+           ['America/Santa_Isabel'],
+           ['America/Santarem'],
+           ['America/Santiago'],
+           ['America/Santo_Domingo'],
+           ['America/Sao_Paulo'],
+           ['America/Scoresbysund'],
+           ['America/Shiprock'],
+           ['America/St_Barthelemy'],
+           ['America/St_Johns'],
+           ['America/St_Kitts'],
+           ['America/St_Lucia'],
+           ['America/St_Thomas'],
+           ['America/St_Vincent'],
+           ['America/Swift_Current'],
+           ['America/Tegucigalpa'],
+           ['America/Thule'],
+           ['America/Thunder_Bay'],
+           ['America/Tijuana'],
+           ['America/Toronto'],
+           ['America/Tortola'],
+           ['America/Vancouver'],
+           ['America/Whitehorse'],
+           ['America/Winnipeg'],
+           ['America/Yakutat'],
+           ['America/Yellowknife'],
+           ['Antarctica/Casey'],
+           ['Antarctica/Davis'],
+           ['Antarctica/DumontDUrville'],
+           ['Antarctica/Macquarie'],
+           ['Antarctica/Mawson'],
+           ['Antarctica/McMurdo'],
+           ['Antarctica/Palmer'],
+           ['Antarctica/Rothera'],
+           ['Antarctica/South_Pole'],
+           ['Antarctica/Syowa'],
+           ['Antarctica/Vostok'],
+           ['Arctic/Longyearbyen'],
+           ['Asia/Aden'],
+           ['Asia/Almaty'],
+           ['Asia/Amman'],
+           ['Asia/Anadyr'],
+           ['Asia/Aqtau'],
+           ['Asia/Aqtobe'],
+           ['Asia/Ashgabat'],
+           ['Asia/Baghdad'],
+           ['Asia/Bahrain'],
+           ['Asia/Baku'],
+           ['Asia/Bangkok'],
+           ['Asia/Beirut'],
+           ['Asia/Bishkek'],
+           ['Asia/Brunei'],
+           ['Asia/Choibalsan'],
+           ['Asia/Chongqing'],
+           ['Asia/Colombo'],
+           ['Asia/Damascus'],
+           ['Asia/Dhaka'],
+           ['Asia/Dili'],
+           ['Asia/Dubai'],
+           ['Asia/Dushanbe'],
+           ['Asia/Gaza'],
+           ['Asia/Harbin'],
+           ['Asia/Ho_Chi_Minh'],
+           ['Asia/Hong_Kong'],
+           ['Asia/Hovd'],
+           ['Asia/Irkutsk'],
+           ['Asia/Jakarta'],
+           ['Asia/Jayapura'],
+           ['Asia/Jerusalem'],
+           ['Asia/Kabul'],
+           ['Asia/Kamchatka'],
+           ['Asia/Karachi'],
+           ['Asia/Kashgar'],
+           ['Asia/Kathmandu'],
+           ['Asia/Kolkata'],
+           ['Asia/Krasnoyarsk'],
+           ['Asia/Kuala_Lumpur'],
+           ['Asia/Kuching'],
+           ['Asia/Kuwait'],
+           ['Asia/Macau'],
+           ['Asia/Magadan'],
+           ['Asia/Makassar'],
+           ['Asia/Manila'],
+           ['Asia/Muscat'],
+           ['Asia/Nicosia'],
+           ['Asia/Novokuznetsk'],
+           ['Asia/Novosibirsk'],
+           ['Asia/Omsk'],
+           ['Asia/Oral'],
+           ['Asia/Phnom_Penh'],
+           ['Asia/Pontianak'],
+           ['Asia/Pyongyang'],
+           ['Asia/Qatar'],
+           ['Asia/Qyzylorda'],
+           ['Asia/Rangoon'],
+           ['Asia/Riyadh'],
+           ['Asia/Sakhalin'],
+           ['Asia/Samarkand'],
+           ['Asia/Seoul'],
+           ['Asia/Shanghai'],
+           ['Asia/Singapore'],
+           ['Asia/Taipei'],
+           ['Asia/Tashkent'],
+           ['Asia/Tbilisi'],
+           ['Asia/Tehran'],
+           ['Asia/Thimphu'],
+           ['Asia/Tokyo'],
+           ['Asia/Ulaanbaatar'],
+           ['Asia/Urumqi'],
+           ['Asia/Vientiane'],
+           ['Asia/Vladivostok'],
+           ['Asia/Yakutsk'],
+           ['Asia/Yekaterinburg'],
+           ['Asia/Yerevan'],
+           ['Atlantic/Azores'],
+           ['Atlantic/Bermuda'],
+           ['Atlantic/Canary'],
+           ['Atlantic/Cape_Verde'],
+           ['Atlantic/Faroe'],
+           ['Atlantic/Madeira'],
+           ['Atlantic/Reykjavik'],
+           ['Atlantic/South_Georgia'],
+           ['Atlantic/St_Helena'],
+           ['Atlantic/Stanley'],
+           ['Australia/Adelaide'],
+           ['Australia/Brisbane'],
+           ['Australia/Broken_Hill'],
+           ['Australia/Currie'],
+           ['Australia/Darwin'],
+           ['Australia/Eucla'],
+           ['Australia/Hobart'],
+           ['Australia/Lindeman'],
+           ['Australia/Lord_Howe'],
+           ['Australia/Melbourne'],
+           ['Australia/Perth'],
+           ['Australia/Sydney'],
+           ['Europe/Amsterdam'],
+           ['Europe/Andorra'],
+           ['Europe/Athens'],
+           ['Europe/Belgrade'],
+           ['Europe/Berlin'],
+           ['Europe/Bratislava'],
+           ['Europe/Brussels'],
+           ['Europe/Bucharest'],
+           ['Europe/Budapest'],
+           ['Europe/Chisinau'],
+           ['Europe/Copenhagen'],
+           ['Europe/Dublin'],
+           ['Europe/Gibraltar'],
+           ['Europe/Guernsey'],
+           ['Europe/Helsinki'],
+           ['Europe/Isle_of_Man'],
+           ['Europe/Istanbul'],
+           ['Europe/Jersey'],
+           ['Europe/Kaliningrad'],
+           ['Europe/Kiev'],
+           ['Europe/Lisbon'],
+           ['Europe/Ljubljana'],
+           ['Europe/London'],
+           ['Europe/Luxembourg'],
+           ['Europe/Madrid'],
+           ['Europe/Malta'],
+           ['Europe/Mariehamn'],
+           ['Europe/Minsk'],
+           ['Europe/Monaco'],
+           ['Europe/Moscow'],
+           ['Europe/Oslo'],
+           ['Europe/Paris'],
+           ['Europe/Podgorica'],
+           ['Europe/Prague'],
+           ['Europe/Riga'],
+           ['Europe/Rome'],
+           ['Europe/Samara'],
+           ['Europe/San_Marino'],
+           ['Europe/Sarajevo'],
+           ['Europe/Simferopol'],
+           ['Europe/Skopje'],
+           ['Europe/Sofia'],
+           ['Europe/Stockholm'],
+           ['Europe/Tallinn'],
+           ['Europe/Tirane'],
+           ['Europe/Uzhgorod'],
+           ['Europe/Vaduz'],
+           ['Europe/Vatican'],
+           ['Europe/Vienna'],
+           ['Europe/Vilnius'],
+           ['Europe/Volgograd'],
+           ['Europe/Warsaw'],
+           ['Europe/Zagreb'],
+           ['Europe/Zaporozhye'],
+           ['Europe/Zurich'],
+           ['Indian/Antananarivo'],
+           ['Indian/Chagos'],
+           ['Indian/Christmas'],
+           ['Indian/Cocos'],
+           ['Indian/Comoro'],
+           ['Indian/Kerguelen'],
+           ['Indian/Mahe'],
+           ['Indian/Maldives'],
+           ['Indian/Mauritius'],
+           ['Indian/Mayotte'],
+           ['Indian/Reunion'],
+           ['Pacific/Apia'],
+           ['Pacific/Auckland'],
+           ['Pacific/Chatham'],
+           ['Pacific/Chuuk'],
+           ['Pacific/Easter'],
+           ['Pacific/Efate'],
+           ['Pacific/Enderbury'],
+           ['Pacific/Fakaofo'],
+           ['Pacific/Fiji'],
+           ['Pacific/Funafuti'],
+           ['Pacific/Galapagos'],
+           ['Pacific/Gambier'],
+           ['Pacific/Guadalcanal'],
+           ['Pacific/Guam'],
+           ['Pacific/Honolulu'],
+           ['Pacific/Johnston'],
+           ['Pacific/Kiritimati'],
+           ['Pacific/Kosrae'],
+           ['Pacific/Kwajalein'],
+           ['Pacific/Majuro'],
+           ['Pacific/Marquesas'],
+           ['Pacific/Midway'],
+           ['Pacific/Nauru'],
+           ['Pacific/Niue'],
+           ['Pacific/Norfolk'],
+           ['Pacific/Noumea'],
+           ['Pacific/Pago_Pago'],
+           ['Pacific/Palau'],
+           ['Pacific/Pitcairn'],
+           ['Pacific/Pohnpei'],
+           ['Pacific/Port_Moresby'],
+           ['Pacific/Rarotonga'],
+           ['Pacific/Saipan'],
+           ['Pacific/Tahiti'],
+           ['Pacific/Tarawa'],
+           ['Pacific/Tongatapu'],
+           ['Pacific/Wake'],
+           ['Pacific/Wallis']
+       ]
+    },
+
+    constructor: function(config) {
+       var me = this;
+
+       config = config || {};
+
+       Ext.regModel('Timezone', {
+           fields: ['zone'],
+           proxy: {
+               type: 'memory',
+               reader: 'array'
+           }
+       });
+
+       Ext.apply(config, {
+           model: 'Timezone',
+           data: PVE.data.TimezoneStore.timezones
+       });
+
+       me.callParent([config]);        
+    }
+});
\ No newline at end of file
diff --git a/www/manager6/data/UpdateQueue.js b/www/manager6/data/UpdateQueue.js
new file mode 100644 (file)
index 0000000..121aba6
--- /dev/null
@@ -0,0 +1,57 @@
+// Serialize load (avoid too many parallel connections)
+Ext.define('PVE.data.UpdateQueue', {
+    singleton: true,
+
+    constructor : function(){
+        var me = this;
+
+       var queue = [];
+       var queue_idx = {};
+
+       var idle = true;
+
+       var start_update = function() {
+           if (!idle) {
+               return;
+           }
+
+           var storeid = queue.shift();
+           if (!storeid) {
+               return;
+           }
+           var info = queue_idx[storeid];
+           queue_idx[storeid] = null;
+
+           info.updatestart = new Date();
+
+           idle = false;
+           info.store.load({
+               callback: function(records, operation, success) {
+                   idle = true;
+                   if (info.callback) {
+                       var runtime = (new Date()).getTime() - info.updatestart.getTime();
+                       info.callback(runtime, success);
+                   }
+                   start_update();
+               }
+           });
+       };
+
+       Ext.apply(me, {
+           queue: function(store, cb) {
+               var storeid = store.storeid;
+               if (!storeid) {
+                   throw "unable to queue store without storeid";
+               }
+               if (!queue_idx[storeid]) {
+                   queue_idx[storeid] = {
+                       store: store,
+                       callback: cb
+                   };
+                   queue.push(storeid);
+               }
+               start_update();
+           }
+       });
+    }
+});
diff --git a/www/manager6/data/UpdateStore.js b/www/manager6/data/UpdateStore.js
new file mode 100644 (file)
index 0000000..bf48611
--- /dev/null
@@ -0,0 +1,51 @@
+/* Extends the Ext.data.Store type
+ * with  startUpdate() and stopUpdate() methods
+ * to refresh the store data in the background
+ * Components using this store directly will flicker
+ * due to the redisplay of the element ater 'config.interval' ms
+ */
+Ext.define('PVE.data.UpdateStore', {
+    extend: 'Ext.data.Store',
+
+    constructor: function(config) {
+       var me = this;
+
+       config = config || {};
+
+       if (!config.interval) {
+           config.interval = 3000;
+       }
+
+       if (!config.storeid) {
+           throw "no storeid specified";
+       }
+
+       var load_task = new Ext.util.DelayedTask();
+
+       var run_load_task = function() {
+           if (PVE.Utils.authOK()) {
+               PVE.data.UpdateQueue.queue(me, function(runtime, success) {
+                   var interval = config.interval + runtime*2;
+                   load_task.delay(interval, run_load_task);
+               });
+           } else {
+               load_task.delay(200, run_load_task);
+           }
+       };
+
+       Ext.apply(config, {
+           startUpdate: function() {
+               run_load_task();
+           },
+           stopUpdate: function() {
+               load_task.cancel();
+           }
+       });
+
+       me.callParent([config]);
+
+       me.on('destroy', function() {
+           load_task.cancel();
+       });
+    }
+});
diff --git a/www/manager6/data/reader/JsonObject.js b/www/manager6/data/reader/JsonObject.js
new file mode 100644 (file)
index 0000000..4323e3e
--- /dev/null
@@ -0,0 +1,127 @@
+/* A reader to store a single JSON Object (hash) into a storage.
+ * Also accepts an array containing a single hash. 
+ *
+ * So it can read:
+ *
+ * example1: {data1: "xyz", data2: "abc"} 
+ * returns [{key: "data1", value: "xyz"}, {key: "data2", value: "abc"}]
+ *
+ * example2: [ {data1: "xyz", data2: "abc"} ] 
+ * returns [{key: "data1", value: "xyz"}, {key: "data2", value: "abc"}]
+ *
+ * If you set 'readArray', the reader expexts the object as array:
+ *
+ * example3: [ { key: "data1", value: "xyz", p2: "cde" },  { key: "data2", value: "abc", p2: "efg" }]
+ * returns [{key: "data1", value: "xyz", p2: "cde}, {key: "data2", value: "abc", p2: "efg"}]
+ *
+ * Note: The records can contain additional properties (like 'p2' above) when you use 'readArray'
+ *
+ * Additional feature: specify allowed properties with default values with 'rows' object
+ *
+ * var rows = {
+ *   memory: {
+ *     required: true,
+ *     defaultValue: 512
+ *   }
+ * }
+ *
+ */
+
+Ext.define('PVE.data.reader.JsonObject', {
+    extend: 'Ext.data.reader.Json',
+    alias : 'reader.jsonobject',
+    
+    readArray: false,
+
+    rows: undefined,
+
+    constructor: function(config) {
+        var me = this;
+
+        Ext.apply(me, config || {});
+
+       me.callParent([config]);
+    },
+
+    getResponseData: function(response) {
+       var me = this;
+
+       var data = [];
+        try {
+        var result = Ext.decode(response.responseText);
+        // get our data items inside the server response
+        var root = result[me.getRootProperty()];
+
+           if (me.readArray) {
+
+               var rec_hash = {};
+               Ext.Array.each(root, function(rec) {
+                   if (Ext.isDefined(rec.key)) {
+                       rec_hash[rec.key] = rec;
+                   }
+               });
+
+               if (me.rows) {
+                   Ext.Object.each(me.rows, function(key, rowdef) {
+                       var rec = rec_hash[key];
+                       if (Ext.isDefined(rec)) {
+                           if (!Ext.isDefined(rec.value)) {
+                               rec.value = rowdef.defaultValue;
+                           }
+                           data.push(rec);
+                       } else if (Ext.isDefined(rowdef.defaultValue)) {
+                           data.push({key: key, value: rowdef.defaultValue} );
+                       } else if (rowdef.required) {
+                           data.push({key: key, value: undefined });
+                       }
+                   });
+               } else {
+                   Ext.Array.each(root, function(rec) {
+                       if (Ext.isDefined(rec.key)) {
+                           data.push(rec);
+                       }
+                   });
+               }
+               
+           } else { 
+               
+               var org_root = root;
+
+               if (Ext.isArray(org_root)) {
+                   if (root.length == 1) {
+                       root = org_root[0];
+                   } else {
+                       root = {};
+                   }
+               }
+
+               if (me.rows) {
+                   Ext.Object.each(me.rows, function(key, rowdef) {
+                       if (Ext.isDefined(root[key])) {
+                           data.push({key: key, value: root[key]});
+                       } else if (Ext.isDefined(rowdef.defaultValue)) {
+                           data.push({key: key, value: rowdef.defaultValue});
+                       } else if (rowdef.required) {
+                           data.push({key: key, value: undefined});
+                       }
+                   });
+               } else {
+                   Ext.Object.each(root, function(key, value) {
+                       data.push({key: key, value: value });
+                   });
+               }
+           }
+       }
+        catch (ex) {
+            Ext.Error.raise({
+                response: response,
+                json: response.responseText,
+                parseError: ex,
+                msg: 'Unable to parse the JSON returned by the server: ' + ex.toString()
+            });
+        }
+
+       return data;
+    }
+});
+
diff --git a/www/manager6/dc/ACLView.js b/www/manager6/dc/ACLView.js
new file mode 100644 (file)
index 0000000..7ea314c
--- /dev/null
@@ -0,0 +1,244 @@
+Ext.define('PVE.dc.ACLAdd', {
+    extend: 'PVE.window.Edit',
+    alias: ['widget.pveACLAdd'],
+
+    initComponent : function() {
+       /*jslint confusion: true */
+        var me = this;
+
+       me.create = true;
+
+       var items = [
+           {
+               xtype: me.path ? 'hiddenfield' : 'textfield',
+               name: 'path',
+               value: me.path,
+               allowBlank: false,
+               fieldLabel: gettext('Path')
+           }
+       ];
+
+       if (me.aclType === 'group') {
+           me.subject = gettext("Group Permission");
+           items.push({
+               xtype: 'pveGroupSelector',
+               name: 'groups',
+               fieldLabel: gettext('Group')
+           });
+       } else if (me.aclType === 'user') {
+           me.subject = gettext("User Permission");
+           items.push({
+               xtype: 'pveUserSelector',
+               name: 'users',
+               fieldLabel: gettext('User')
+           });
+       } else {
+           throw "unknown ACL type";
+       }
+
+       items.push({
+           xtype: 'pveRoleSelector',
+           name: 'roles',
+           value: 'NoAccess',
+           fieldLabel: gettext('Role')
+       });
+
+       if (!me.path) {
+           items.push({
+               xtype: 'pvecheckbox',
+               name: 'propagate',
+               checked: true,
+               fieldLabel: gettext('Propagate')
+           });
+       }
+
+       var ipanel = Ext.create('PVE.panel.InputPanel', {
+           items: items
+       });
+
+       Ext.apply(me, {
+           url: '/access/acl',
+           method: 'PUT',
+           isAdd: true,
+           items: [ ipanel ]
+       });
+           
+       me.callParent();
+    }
+});
+
+Ext.define('PVE.dc.ACLView', {
+    extend: 'Ext.grid.GridPanel',
+
+    alias: ['widget.pveACLView'],
+
+    // use fixed path
+    path: undefined,
+
+    initComponent : function() {
+       var me = this;
+
+       var store = new Ext.data.Store({
+           model: 'pve-acl',
+           proxy: {
+                type: 'pve',
+               url: "/api2/json/access/acl"
+           },
+           sorters: { 
+               property: 'path', 
+               order: 'DESC' 
+           }
+       });
+
+       if (me.path) {
+           store.filters.add(new Ext.util.Filter({
+               filterFn: function(item) {
+                   if (item.data.path === me.path) {
+                       return true;
+                   }
+               }
+           }));
+       }
+
+       var render_ugid = function(ugid, metaData, record) {
+           if (record.data.type == 'group') {
+               return '@' + ugid;
+           }
+
+           return ugid;
+       };
+
+       var columns = [
+           {
+               header: gettext('User') + '/' + gettext('Group'),
+               flex: 1,
+               sortable: true,
+               renderer: render_ugid,
+               dataIndex: 'ugid'
+           },
+           {
+               header: gettext('Role'),
+               flex: 1,
+               sortable: true,
+               dataIndex: 'roleid'
+           }
+       ];
+
+       if (!me.path) {
+           columns.unshift({
+               header: gettext('Path'),
+               flex: 1,
+               sortable: true,
+               dataIndex: 'path'
+           });
+           columns.push({
+               header: gettext('Propagate'),
+               width: 80,
+               sortable: true,
+               dataIndex: 'propagate'
+           });
+       }
+
+       var sm = Ext.create('Ext.selection.RowModel', {});
+
+       var reload = function() {
+           store.load();
+       };
+
+       var remove_btn = new PVE.button.Button({
+           text: gettext('Remove'),
+           disabled: true,
+           selModel: sm,
+           confirmMsg: gettext('Are you sure you want to remove this entry'),
+           handler: function(btn, event, rec) {
+               var params = { 
+                   'delete': 1, 
+                   path: rec.data.path, 
+                   roles: rec.data.roleid
+               };
+               if (rec.data.type === 'group') {
+                   params.groups = rec.data.ugid;
+               } else if (rec.data.type === 'user') {
+                   params.users = rec.data.ugid;
+               } else {
+                   throw 'unknown data type';
+               }
+
+               PVE.Utils.API2Request({
+                   url: '/access/acl',
+                   params: params,
+                   method: 'PUT',
+                   waitMsgTarget: me,
+                   callback: function() {
+                       reload();
+                   },
+                   failure: function (response, opts) {
+                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+                   }
+               });
+           }
+       });
+
+       PVE.Utils.monStoreErrors(me, store);
+
+       Ext.apply(me, {
+           store: store,
+           selModel: sm,
+           stateful: false,
+           tbar: [
+               {
+                   text: gettext('Add'),
+                   menu: new Ext.menu.Menu({
+                       items: [
+                           {
+                               text: gettext('Group Permission'),
+                               handler: function() {
+                                   var win = Ext.create('PVE.dc.ACLAdd',{
+                                       aclType: 'group',
+                                       path: me.path
+                                   });
+                                   win.on('destroy', reload);
+                                   win.show();
+                               }
+                           },
+                           {
+                               text: gettext('User Permission'),
+                               handler: function() {
+                                   var win = Ext.create('PVE.dc.ACLAdd',{
+                                       aclType: 'user',
+                                       path: me.path
+                                   });
+                                   win.on('destroy', reload);
+                                   win.show();
+                               }
+                           }
+                       ]
+                   })
+               },
+               remove_btn
+           ],
+           viewConfig: {
+               trackOver: false
+           },
+           columns: columns,
+           listeners: {
+               show: reload
+           }
+       });
+
+       me.callParent();
+    }
+}, function() {
+
+    Ext.define('pve-acl', {
+       extend: 'Ext.data.Model',
+       fields: [ 
+           'path', 'type', 'ugid', 'roleid', 
+           { 
+               name: 'propagate', 
+               type: 'boolean'
+           } 
+       ]
+    });
+
+});
\ No newline at end of file
diff --git a/www/manager6/dc/AuthEdit.js b/www/manager6/dc/AuthEdit.js
new file mode 100644 (file)
index 0000000..356f004
--- /dev/null
@@ -0,0 +1,284 @@
+Ext.define('PVE.dc.AuthEdit', {
+    extend: 'PVE.window.Edit',
+    alias: ['widget.pveDcAuthEdit'],
+
+    isAdd: true,
+
+    initComponent : function() {
+        var me = this;
+
+        me.create = !me.realm;
+
+        var url;
+        var method;
+        var serverlist;
+
+        if (me.create) {
+            url = '/api2/extjs/access/domains';
+            method = 'POST';
+        } else {
+            url = '/api2/extjs/access/domains/' + me.realm;
+            method = 'PUT';
+        }
+
+        var column1 = [
+            {
+                xtype: me.create ? 'textfield' : 'displayfield',
+               height: 22, // hack: set same height as text fields
+                name: 'realm',
+                fieldLabel: gettext('Realm'),
+                value: me.realm,
+                allowBlank: false
+            }
+       ];
+
+       if (me.authType === 'ad') {
+
+           me.subject = gettext('Active Directory Server');
+
+            column1.push({
+                xtype: 'textfield',
+                name: 'domain',
+                fieldLabel: gettext('Domain'),
+                emptyText: 'company.net',
+                allowBlank: false
+            });
+
+       } else if (me.authType === 'ldap') {
+
+           me.subject = gettext('LDAP Server');
+
+            column1.push({
+                xtype: 'textfield',
+                name: 'base_dn',
+                fieldLabel: gettext('Base Domain Name'),
+               emptyText: 'CN=Users,DC=Company,DC=net',
+                allowBlank: false
+            });
+
+            column1.push({
+                xtype: 'textfield',
+                name: 'user_attr',
+                emptyText: 'uid / sAMAccountName',
+                fieldLabel: gettext('User Attribute Name'),
+                allowBlank: false
+            });
+       } else if (me.authType === 'pve') {
+
+           if (me.create) throw 'unknown auth type';
+
+           me.subject = 'Proxmox VE authentication server';
+
+       } else if (me.authType === 'pam') {
+
+           if (me.create) throw 'unknown auth type';
+
+           me.subject = 'linux PAM';
+
+       } else {
+           throw 'unknown auth type ';
+       }
+
+        column1.push({
+            xtype: 'pvecheckbox',
+            fieldLabel: gettext('Default'),
+            name: 'default',
+            uncheckedValue: 0
+        });
+
+        var column2 = [];
+
+       if (me.authType === 'ldap' || me.authType === 'ad') {
+           column2.push([
+               {
+                    xtype: 'textfield',
+                    fieldLabel: gettext('Server'),
+                    name: 'server1',
+                    allowBlank: false
+               },
+               {
+                    xtype: 'pvetextfield',
+                    fieldLabel: gettext('Fallback Server'),
+                   deleteEmpty: !me.create,
+                   name: 'server2'
+               },
+               {
+                    xtype: 'numberfield',
+                    name: 'port',
+                    fieldLabel: gettext('Port'),
+                    minValue: 1,
+                    maxValue: 65535,
+                   emptyText: gettext('Default'),
+                   submitEmptyText: false
+               },
+               {
+                    xtype: 'pvecheckbox',
+                    fieldLabel: 'SSL',
+                    name: 'secure',
+                    uncheckedValue: 0
+               }
+            ]);
+       }
+
+       // Two Factor Auth settings
+
+        column2.push({
+            xtype: 'pveKVComboBox',
+            name: 'tfa',
+           deleteEmpty: !me.create,
+           value: '',
+            fieldLabel: gettext('TFA'),
+           data: [ ['', PVE.Utils.noneText], ['oath', 'OATH'], ['yubico', 'Yubico']],
+           listeners: {
+               change: function(f, value) {
+                   if (!me.rendered) {
+                       return;
+                   }
+                   me.down('field[name=oath_step]').setVisible(value === 'oath');
+                   me.down('field[name=oath_digits]').setVisible(value === 'oath');
+                   me.down('field[name=yubico_api_id]').setVisible(value === 'yubico');
+                   me.down('field[name=yubico_api_key]').setVisible(value === 'yubico');
+                   me.down('field[name=yubico_url]').setVisible(value === 'yubico');
+               }
+           }
+        });
+
+       column2.push({
+            xtype: 'numberfield',
+            name: 'oath_step',
+           value: '',
+           minValue: 10,
+           step: 1,
+           allowDecimals: false,
+           allowBlank: true,
+           emptyText: PVE.Utils.defaultText + ' (30)',
+           submitEmptyText: false,
+           hidden: true,
+            fieldLabel: 'OATH time step'
+        });
+
+       column2.push({
+            xtype: 'numberfield',
+            name: 'oath_digits',
+           value: '',
+           minValue: 6,
+           maxValue: 8,
+           step: 1,
+           allowDecimals: false,
+           allowBlank: true,
+           emptyText: PVE.Utils.defaultText + ' (6)',
+           submitEmptyText: false,
+           hidden: true,
+            fieldLabel: 'OATH password length'
+        });
+
+       column2.push({
+            xtype: 'textfield',
+            name: 'yubico_api_id',
+           hidden: true,
+            fieldLabel: 'Yubico API Id'
+        });
+
+       column2.push({
+            xtype: 'textfield',
+            name: 'yubico_api_key',
+           hidden: true,
+            fieldLabel: 'Yubico API Key'
+        });
+
+       column2.push({
+            xtype: 'textfield',
+            name: 'yubico_url',
+           hidden: true,
+            fieldLabel: 'Yubico URL'
+        });
+
+       var ipanel = Ext.create('PVE.panel.InputPanel', {
+           column1: column1,
+           column2: column2,
+           columnB: [{
+               xtype: 'textfield',
+               name: 'comment',
+               fieldLabel: gettext('Comment')
+            }],
+           onGetValues: function(values) {
+               if (!values.port) {
+                   if (!me.create) {
+                       PVE.Utils.assemble_field_data(values, { 'delete': 'port' });
+                   }
+                   delete values.port;
+               }
+
+               if (me.create) {
+                   values.type = me.authType;
+               }
+
+               if (values.tfa === 'oath') {
+                   values.tfa = "type=oath";
+                   if (values.oath_step) {
+                       values.tfa += ",step=" + values.oath_step;
+                   }
+                   if (values.oath_digits) {
+                       values.tfa += ",digits=" + values.oath_digits;
+                   }
+               } else if (values.tfa === 'yubico') {
+                   values.tfa = "type=yubico";
+                   values.tfa += ",id=" + values.yubico_api_id;
+                   values.tfa += ",key=" + values.yubico_api_key;
+                   if (values.yubico_url) {
+                       values.tfa += ",url=" + values.yubico_url;
+                   }
+               } else {
+                   delete values.tfa;
+               }
+
+               delete values.oath_step;
+               delete values.oath_digits;
+               delete values.yubico_api_id;
+               delete values.yubico_api_key;
+               delete values.yubico_url;
+               
+               return values;
+           }
+       });
+
+       Ext.applyIf(me, {
+            url: url,
+            method: method,
+           fieldDefaults: {
+               labelWidth: 120
+           },
+           items: [ ipanel ]
+        });
+
+        me.callParent();
+
+        if (!me.create) {
+            me.load({
+                success: function(response, options) {
+                   var data = response.result.data || {};
+                   // just to be sure (should not happen)
+                   if (data.type !== me.authType) {
+                       me.close();
+                       throw "got wrong auth type";
+                   }
+
+                   if (data.tfa) {
+                       var tfacfg = PVE.Parser.parseTfaConfig(data.tfa);
+                       data.tfa = tfacfg.type;
+                       if (tfacfg.type === 'yubico') {
+                           data.yubico_api_key = tfacfg.key;
+                           data.yubico_api_id = tfacfg.id;
+                           data.yubico_url = tfacfg.url;
+                       } else if (tfacfg.type === 'oath') {
+                           data.oath_step = tfacfg.step;
+                           data.oath_digits = tfacfg.digits;
+                       }
+                   }
+
+                    me.setValues(data);
+                }
+            });
+        }
+    }
+});
diff --git a/www/manager6/dc/AuthView.js b/www/manager6/dc/AuthView.js
new file mode 100644 (file)
index 0000000..83e79c6
--- /dev/null
@@ -0,0 +1,146 @@
+Ext.define('PVE.dc.AuthView', {
+    extend: 'Ext.grid.GridPanel',
+
+    alias: ['widget.pveAuthView'],
+
+    initComponent : function() {
+       var me = this;
+
+       var store = new Ext.data.Store({
+           model: 'pve-domains',
+           sorters: { 
+               property: 'realm', 
+               order: 'DESC' 
+           }
+       });
+
+       var reload = function() {
+           store.load();
+       };
+
+       var sm = Ext.create('Ext.selection.RowModel', {});
+
+       var run_editor = function() {
+           var rec = sm.getSelection()[0];
+           if (!rec) {
+               return;
+           }
+
+            var win = Ext.create('PVE.dc.AuthEdit',{
+                realm: rec.data.realm,
+               authType: rec.data.type
+            });
+            win.on('destroy', reload);
+            win.show();
+       };
+
+       var edit_btn = new PVE.button.Button({
+           text: gettext('Edit'),
+           disabled: true,
+           selModel: sm,
+           handler: run_editor
+       });
+
+       var remove_btn = new PVE.button.Button({
+           text: gettext('Remove'),
+           disabled: true,
+           selModel: sm,
+           confirmMsg: function (rec) {
+               return Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
+                                        "'" + rec.data.realm + "'");
+           },
+           enableFn: function(rec) {
+               return !(rec.data.type === 'pve' || rec.data.type === 'pam');
+           },
+           handler: function(btn, event, rec) {
+               var realm = rec.data.realm;
+
+               PVE.Utils.API2Request({
+                   url: '/access/domains/' + realm,
+                   method: 'DELETE',
+                   waitMsgTarget: me,
+                   callback: function() {
+                       reload();
+                   },
+                   failure: function (response, opts) {
+                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+                   }
+               });
+           }
+        });
+
+        var tbar = [
+           {
+               text: gettext('Add'),
+               menu: new Ext.menu.Menu({
+                   items: [
+                       {
+                           text: gettext('Active Directory Server'),
+                           handler: function() {
+                               var win = Ext.create('PVE.dc.AuthEdit', {
+                                   authType: 'ad'
+                               });
+                               win.on('destroy', reload);
+                               win.show();
+                           }
+                       },
+                       {
+                           text: gettext('LDAP Server'),
+                           handler: function() {
+                               var win = Ext.create('PVE.dc.AuthEdit',{
+                                   authType: 'ldap'
+                               });
+                               win.on('destroy', reload);
+                               win.show();
+                           }
+                       }
+                   ]
+               })
+           },
+           edit_btn, remove_btn
+        ];
+
+       Ext.apply(me, {
+           store: store,
+           selModel: sm,
+           stateful: false,
+            tbar: tbar,
+           viewConfig: {
+               trackOver: false
+           },
+           columns: [
+               {
+                   header: gettext('Realm'),
+                   width: 100,
+                   sortable: true,
+                   dataIndex: 'realm'
+               },
+               {
+                   header: gettext('Type'),
+                   width: 100,
+                   sortable: true,
+                   dataIndex: 'type'
+               },
+               {
+                   header: gettext('TFA'),
+                   width: 100,
+                   sortable: true,
+                   dataIndex: 'tfa'
+               },
+               {
+                   id: 'comment',
+                   header: gettext('Comment'),
+                   sortable: false,
+                   dataIndex: 'comment',
+                   flex: 1
+               }
+           ],
+           listeners: {
+               show: reload,
+               itemdblclick: run_editor
+           }
+       });
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/dc/Backup.js b/www/manager6/dc/Backup.js
new file mode 100644 (file)
index 0000000..9cc2f7d
--- /dev/null
@@ -0,0 +1,473 @@
+Ext.define('PVE.dc.BackupEdit', {
+    extend: 'PVE.window.Edit',
+    alias: ['widget.pveDcBackupEdit'],
+
+    initComponent : function() {
+       /*jslint confusion: true */
+         var me = this;
+
+        me.create = !me.jobid;
+
+       var url;
+       var method;
+
+       if (me.create) {
+            url = '/api2/extjs/cluster/backup';
+            method = 'POST';
+        } else {
+            url = '/api2/extjs/cluster/backup/' + me.jobid;
+            method = 'PUT';
+        }
+
+       var vmidField = Ext.create('Ext.form.field.Hidden', {
+           name: 'vmid'
+       });
+
+       var selModeField =  Ext.create('PVE.form.KVComboBox', {
+           xtype: 'pveKVComboBox',
+           data: [
+               ['include', gettext('Include selected VMs')],
+               ['all', gettext('All')],
+               ['exclude', gettext('Exclude selected VMs')]
+           ],
+           fieldLabel: gettext('Selection mode'),
+           name: 'selMode',
+           value: ''
+       });
+
+       var insideUpdate = false;
+       
+       var sm = Ext.create('Ext.selection.CheckboxModel', {
+           mode: 'SIMPLE',
+           listeners: {
+               selectionchange: function(model, selected) {
+                   if (!insideUpdate) { // avoid endless loop
+                       var sel = [];
+                       Ext.Array.each(selected, function(record) {
+                           sel.push(record.data.vmid);
+                       });
+
+                       insideUpdate = true;
+                       vmidField.setValue(sel);
+                       insideUpdate = false;
+                   }
+               }
+           }
+       });
+
+       var storagesel = Ext.create('PVE.form.StorageSelector', {
+           fieldLabel: gettext('Storage'),
+           nodename: 'localhost',
+           storageContent: 'backup',
+           allowBlank: false,
+           name: 'storage'
+       });
+
+       var store = new Ext.data.Store({
+           model: 'PVEResources',
+           sorters: { 
+               property: 'vmid', 
+               order: 'ASC' 
+           }
+       });
+
+       var vmgrid = Ext.createWidget('grid', {
+           store: store,
+           border: true,
+           height: 300,
+           selModel: sm,
+           disabled: true,
+           columns: [
+               { 
+                   header: 'ID',
+                   dataIndex: 'vmid',
+                   width: 60
+               },
+               { 
+                   header: gettext('Node'),
+                   dataIndex: 'node'
+               },
+               { 
+                   header: gettext('Status'),
+                   dataIndex: 'uptime',
+                   renderer: function(value) {
+                       if (value) {
+                           return PVE.Utils.runningText;
+                       } else {
+                           return PVE.Utils.stoppedText;
+                       }
+                   }
+               },
+               { 
+                   header: gettext('Name'), 
+                   dataIndex: 'name',
+                   flex: 1 
+               },
+               { 
+                   header: gettext('Type'), 
+                   dataIndex: 'type'
+               }
+           ]
+       });
+
+       var nodesel = Ext.create('PVE.form.NodeSelector', {
+           name: 'node',
+           fieldLabel: gettext('Node'),
+           allowBlank: true,
+           editable: true,
+           autoSelect: false,
+           emptyText: '-- ' + gettext('All') + ' --',
+           listeners: {
+               change: function(f, value) {
+                   storagesel.setNodename(value || 'localhost');
+                   var mode = selModeField.getValue();
+                   store.clearFilter();
+                   store.filterBy(function(rec) {
+                       return (!value || rec.get('node') === value);
+                   });
+                   if (mode === 'all') {
+                       sm.selectAll(true);
+                   }
+               }
+           }
+       });
+
+       var column1 = [
+           nodesel,
+           storagesel,
+           {
+               xtype: 'pveDayOfWeekSelector',
+               name: 'dow',
+               fieldLabel: gettext('Day of week'),
+               multiSelect: true,
+               value: ['sat'],
+               allowBlank: false
+           },
+           {
+               xtype: 'timefield',
+               fieldLabel: gettext('Start Time'),
+               name: 'starttime',
+               format: 'H:i',
+               value: '00:00',
+               allowBlank: false
+           },
+           selModeField
+       ];
+
+       var column2 = [
+           {
+               xtype: 'textfield',
+               fieldLabel: gettext('Send email to'),
+               name: 'mailto'
+           },
+           {
+               xtype: 'pveEmailNotificationSelector',
+               fieldLabel: gettext('Email notification'),
+               name: 'mailnotification',
+               deleteEmpty: me.create ? false : true,
+               value: me.create ? 'always' : ''
+           },
+           {
+               xtype: 'pveCompressionSelector',
+               fieldLabel: gettext('Compression'),
+               name: 'compress',
+               deleteEmpty: me.create ? false : true,
+               value: me.create ? 'lzo' : ''
+           },
+           {
+               xtype: 'pveBackupModeSelector',
+               fieldLabel: gettext('Mode'),
+               value: 'snapshot',
+               name: 'mode'
+           },
+           vmidField
+       ];
+
+       var ipanel = Ext.create('PVE.panel.InputPanel', {
+           column1: column1,
+           column2:  column2,
+           onGetValues: function(values) {
+               if (!values.node) {
+                   if (!me.create) {
+                       PVE.Utils.assemble_field_data(values, { 'delete': 'node' }); 
+                   }
+                   delete values.node;
+               }
+
+               var selMode = values.selMode;
+               delete values.selMode;
+
+               if (selMode === 'all') {
+                   values.all = 1;
+                   values.exclude = '';
+                   delete values.vmid;
+               } else if (selMode === 'exclude') {
+                   values.all = 1;
+                   values.exclude = values.vmid;
+                   delete values.vmid;
+               }
+               return values;
+           }
+       });
+
+       var update_vmid_selection = function(list, mode) {
+           if (insideUpdate) {
+               return; // should not happen - just to be sure
+           }
+           insideUpdate = true;
+           if (mode !== 'all') {
+               sm.deselectAll(true);
+               if (list) {
+                   Ext.Array.each(list.split(','), function(vmid) {
+                       var rec = store.findRecord('vmid', vmid);
+                       if (rec) {
+                           sm.select(rec, true);
+                       }
+                   });
+               }
+           }
+           insideUpdate = false;
+       };
+
+       vmidField.on('change', function(f, value) {
+           var mode = selModeField.getValue();
+           update_vmid_selection(value, mode);
+       });
+
+       selModeField.on('change', function(f, value, oldValue) {
+           if (value === 'all') {
+               sm.selectAll(true);
+               vmgrid.setDisabled(true);
+           } else {
+               vmgrid.setDisabled(false);
+           }
+           if (oldValue === 'all') {
+               sm.deselectAll(true);
+               vmidField.setValue('');
+           }
+           var list = vmidField.getValue();
+           update_vmid_selection(list, value);
+       });
+                
+       var reload = function() {
+           store.load({
+               params: { type: 'vm' },
+               callback: function() {
+                   var node = nodesel.getValue();
+                   store.clearFilter();
+                   store.filterBy(function(rec) {
+                       return (!node || rec.get('node') === node);
+                   });
+                   var list = vmidField.getValue();
+                   var mode = selModeField.getValue();
+                   if (mode === 'all') {
+                       sm.selectAll(true);
+                   } else {
+                       update_vmid_selection(list, mode);
+                   }
+               }
+           });
+       };
+
+        Ext.applyIf(me, {
+            subject: gettext("Backup Job"),
+            url: url,
+            method: method,
+           items: [ ipanel, vmgrid ]
+        });
+
+        me.callParent();
+
+        if (me.create) {
+           selModeField.setValue('include');
+       } else {
+            me.load({
+               success: function(response, options) {
+                   var data = response.result.data;
+
+                   data.dow = data.dow.split(',');
+
+                   if (data.all || data.exclude) {
+                       if (data.exclude) {
+                           data.vmid = data.exclude;
+                           data.selMode = 'exclude';
+                       } else {
+                           data.vmid = '';
+                           data.selMode = 'all';
+                       }
+                   } else {
+                       data.selMode = 'include';
+                   }
+
+                   me.setValues(data);
+               }
+            });
+        }
+
+       reload();
+    }
+});
+
+
+Ext.define('PVE.dc.BackupView', {
+    extend: 'Ext.grid.GridPanel',
+
+    alias: ['widget.pveDcBackupView'],
+
+    allText: '-- ' + gettext('All') + ' --',
+    allExceptText: gettext('All except {0}'),
+
+    initComponent : function() {
+       var me = this;
+
+       var store = new Ext.data.Store({
+           model: 'pve-cluster-backup',
+           proxy: {
+                type: 'pve',
+               url: "/api2/json/cluster/backup"
+           }
+       });
+
+       var reload = function() {
+           store.load();
+       };
+
+       var sm = Ext.create('Ext.selection.RowModel', {});
+
+       var run_editor = function() {
+           var rec = sm.getSelection()[0];
+           if (!rec) {
+               return;
+           }
+
+            var win = Ext.create('PVE.dc.BackupEdit',{
+                jobid: rec.data.id
+            });
+            win.on('destroy', reload);
+            win.show();
+       };
+
+       var edit_btn = new PVE.button.Button({
+           text: gettext('Edit'),
+           disabled: true,
+           selModel: sm,
+           handler: run_editor
+       });
+
+       var remove_btn = new PVE.button.Button({
+           text: gettext('Remove'),
+           disabled: true,
+           selModel: sm,
+           confirmMsg: gettext('Are you sure you want to remove this entry'),
+           handler: function(btn, event, rec) {
+               PVE.Utils.API2Request({
+                   url: '/cluster/backup/' + rec.data.id,
+                   method: 'DELETE',
+                   waitMsgTarget: me,
+                   callback: function() {
+                       reload();
+                   },
+                   failure: function (response, opts) {
+                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+                   }
+               });
+           }
+       });
+
+       PVE.Utils.monStoreErrors(me, store);
+
+       Ext.apply(me, {
+           store: store,
+           selModel: sm,
+           stateful: false,
+           viewConfig: {
+               trackOver: false
+           },
+           tbar: [
+               {
+                   text: gettext('Add'),
+                   handler: function() {
+                       var win = Ext.create('PVE.dc.BackupEdit',{});
+                       win.on('destroy', reload);
+                       win.show();
+                   }
+               },
+               remove_btn,
+               edit_btn
+           ],          
+           columns: [
+               {
+                   header: gettext('Node'),
+                   width: 100,
+                   sortable: true,
+                   dataIndex: 'node',
+                   renderer: function(value) {
+                       if (value) {
+                           return value;
+                       }
+                       return me.allText;
+                   }
+               },
+               {
+                   header: gettext('Day of week'),
+                   width: 200,
+                   sortable: false,
+                   dataIndex: 'dow'
+               },
+               {
+                   header: gettext('Start Time'),
+                   width: 60,
+                   sortable: true,
+                   dataIndex: 'starttime'
+               },
+               {
+                   header: gettext('Storage'),
+                   width: 100,
+                   sortable: true,
+                   dataIndex: 'storage'
+               },
+               {
+                   header: gettext('Selection'),
+                   flex: 1,
+                   sortable: false,
+                   dataIndex: 'vmid',
+                   renderer: function(value, metaData, record) {
+                       /*jslint confusion: true */
+                       if (record.data.all) {
+                           if (record.data.exclude) {
+                               return Ext.String.format(me.allExceptText, record.data.exclude);
+                           }
+                           return me.allText;
+                       }
+                       if (record.data.vmid) {
+                           return record.data.vmid;
+                       }
+
+                       return "-";
+                   }
+               }
+           ],
+           listeners: {
+               show: reload,
+               itemdblclick: run_editor
+           }
+       });
+       
+       me.callParent();
+    }
+}, function() {
+
+    Ext.define('pve-cluster-backup', {
+       extend: 'Ext.data.Model',
+       fields: [ 
+           'id', 'starttime', 'dow',
+           'storage', 'node', 'vmid', 'exclude',
+           'mailto',
+           { name: 'all', type: 'boolean' },
+           { name: 'snapshot', type: 'boolean' },
+           { name: 'stop', type: 'boolean' },
+           { name: 'suspend', type: 'boolean' },
+           { name: 'compress', type: 'boolean' }
+       ]
+    });
+});
\ No newline at end of file
diff --git a/www/manager6/dc/Config.js b/www/manager6/dc/Config.js
new file mode 100644 (file)
index 0000000..01f7c72
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Datacenter config panel, located in the center of the ViewPort after the Datacenter view is selected
+ */
+
+Ext.define('PVE.dc.Config', {
+    extend: 'PVE.panel.Config',
+    alias: 'widget.PVE.dc.Config',
+
+    initComponent: function() {
+        var me = this;
+
+       var caps = Ext.state.Manager.get('GuiCap');
+
+       me.items = [];
+
+       Ext.apply(me, {
+           title: gettext("Datacenter"),
+           hstateid: 'dctab'
+       });
+
+       if (caps.dc['Sys.Audit']) {
+           me.items.push({
+           title: gettext('Summary'),
+               xtype: 'pveDcSummary',
+               itemId: 'summary'
+               });
+
+           me.items.push({
+           xtype: 'pveDcOptionView',
+               title: gettext('Options'),
+               itemId: 'options'
+               });
+       }
+
+       if (caps.storage['Datastore.Allocate'] || caps.dc['Sys.Audit']) {
+           me.items.push({
+               xtype: 'pveStorageView',
+               title: gettext('Storage'),
+               itemId: 'storage'
+           });
+       }
+
+       if (caps.dc['Sys.Audit']) {
+               me.items.push({
+               xtype: 'pveDcBackupView',
+               title: gettext('Backup'),
+               itemId: 'backup'
+           });
+       }
+
+       me.items.push({
+           xtype: 'pveUserView',
+           title: gettext('Users'),
+           itemId: 'users'
+       });
+
+       if (caps.dc['Sys.Audit']) {
+           me.items.push({
+                   xtype: 'pveGroupView',
+                   title: gettext('Groups'),
+                   itemId: 'groups'
+               });
+
+           me.items.push({
+                   xtype: 'pvePoolView',
+                   title: gettext('Pools'),
+                   itemId: 'pools'
+               });
+
+           me.items.push({
+                   xtype: 'pveACLView',
+                   title: gettext('Permissions'),
+                   itemId: 'permissions'
+               });
+
+           me.items.push({
+                   xtype: 'pveRoleView',
+                   title: gettext('Roles'),
+                   itemId: 'roles'
+               });
+
+           me.items.push({
+//                 xtype: 'pveAuthView',
+//                 title: gettext('Authentication'),
+                   xtype: 'gridpanel',
+                   title: 'AuthenTODO',
+                   itemId: 'domains'
+               });
+
+           me.items.push({
+//                 xtype: 'pveHAPanel',
+//                 title: 'HA',
+               xtype: 'gridpanel',
+               title: 'HATODO',
+               phstateid: me.hstateid,
+                   itemId: 'ha'
+               });
+
+           me.items.push({
+//                 xtype: 'pveFirewallPanel',
+//                 title: gettext('Firewall'),
+               xtype: 'gridpanel',
+               title: 'FireTODO',
+                   base_url: '/cluster/firewall',
+                   fwtype: 'dc',
+                   phstateid: me.hstateid,
+                   itemId: 'firewall'
+               });
+
+           me.items.push({
+               xtype: 'pveDcSupport',
+               title: gettext('Support'),
+               itemId: 'support'
+           });
+       }
+
+       me.callParent();
+   }
+});
diff --git a/www/manager6/dc/GroupEdit.js b/www/manager6/dc/GroupEdit.js
new file mode 100644 (file)
index 0000000..cb5a433
--- /dev/null
@@ -0,0 +1,48 @@
+Ext.define('PVE.dc.GroupEdit', {
+    extend: 'PVE.window.Edit',
+    alias: ['widget.pveDcGroupEdit'],
+
+    initComponent : function() {
+        var me = this;
+
+        me.create = !me.groupid;
+
+        var url;
+        var method;
+
+        if (me.create) {
+            url = '/api2/extjs/access/groups';
+            method = 'POST';
+        } else {
+            url = '/api2/extjs/access/groups/' + me.groupid;
+            method = 'PUT';
+        }
+
+        Ext.applyIf(me, {
+            subject: gettext('Group'),
+            url: url,
+            method: method,
+            items: [
+                {
+                   xtype: me.create ? 'pvetextfield' : 'displayfield',
+                   fieldLabel: gettext('Name'),
+                   name: 'groupid',
+                   value: me.groupid,
+                   allowBlank: false
+               },
+                {
+                   xtype: 'textfield',
+                   fieldLabel: gettext('Comment'),
+                   name: 'comment',
+                   allowBlank: true
+               }
+            ]
+        });
+
+        me.callParent();
+
+        if (!me.create) {
+            me.load();
+        }
+    }
+});
diff --git a/www/manager6/dc/GroupView.js b/www/manager6/dc/GroupView.js
new file mode 100644 (file)
index 0000000..6950a46
--- /dev/null
@@ -0,0 +1,110 @@
+Ext.define('PVE.dc.GroupView', {
+    extend: 'Ext.grid.GridPanel',
+
+    alias: ['widget.pveGroupView'],
+
+    initComponent : function() {
+       var me = this;
+
+       var store = new Ext.data.Store({
+           model: 'pve-groups',
+           sorters: { 
+               property: 'groupid', 
+               order: 'DESC' 
+           }
+       });
+
+        var reload = function() {
+            store.load();
+        };
+
+       var sm = Ext.create('Ext.selection.RowModel', {});
+
+       var remove_btn = new PVE.button.Button({
+           text: gettext('Remove'),
+           disabled: true,
+           selModel: sm,
+           confirmMsg: function (rec) {
+               return Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
+                                        "'" + rec.data.groupid + "'");
+           },
+           handler: function(btn, event, rec) {
+               PVE.Utils.API2Request({
+                   url: '/access/groups/' + rec.data.groupid,
+                   method: 'DELETE',
+                   waitMsgTarget: me,
+                   callback: function() {
+                       reload();
+                   },
+                   failure: function (response, opts) {
+                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+                   }
+               });
+           }
+       });
+
+       var run_editor = function() {
+           var rec = sm.getSelection()[0];
+           if (!rec) {
+               return;
+           }
+
+            var win = Ext.create('PVE.dc.GroupEdit',{
+                groupid: rec.data.groupid
+            });
+            win.on('destroy', reload);
+            win.show();
+       };
+
+       var edit_btn = new PVE.button.Button({
+           text: gettext('Edit'),
+           disabled: true,
+           selModel: sm,
+           handler: run_editor
+       });
+
+       var tbar = [
+            {
+               text: gettext('Create'),
+               handler: function() {
+                   var win = Ext.create('PVE.dc.GroupEdit', {});
+                   win.on('destroy', reload);
+                   win.show();
+               }
+            },
+           edit_btn, remove_btn
+        ];
+
+       PVE.Utils.monStoreErrors(me, store);
+
+       Ext.apply(me, {
+           store: store,
+           selModel: sm,
+           stateful: false,
+           tbar: tbar,
+           viewConfig: {
+               trackOver: false
+           },
+           columns: [
+               {
+                   header: gettext('Name'),
+                   width: 200,
+                   sortable: true,
+                   dataIndex: 'groupid'
+               },
+               {
+                   header: gettext('Comment'),
+                   sortable: false,
+                   dataIndex: 'comment',
+                   flex: 1
+               }
+           ],
+           listeners: {
+               show: reload,
+               itemdblclick: run_editor
+           }
+       });
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/dc/Log.js b/www/manager6/dc/Log.js
new file mode 100644 (file)
index 0000000..385823b
--- /dev/null
@@ -0,0 +1,94 @@
+/* This class defines the "Cluster log" tab of the bottom status panel
+ * A log entry is a timestamp associated with an action on a cluster
+ */
+
+Ext.define('PVE.dc.Log', {
+    extend: 'Ext.grid.GridPanel',
+
+    alias: ['widget.pveClusterLog'],
+
+    initComponent : function() {
+       var me = this;
+
+       var logstore = new PVE.data.UpdateStore({
+           storeid: 'pve-cluster-log',
+           model: 'pve-cluster-log',
+           proxy: {
+                type: 'pve',
+               url: '/api2/json/cluster/log'
+           }
+       });
+
+       var store = Ext.create('PVE.data.DiffStore', { 
+           rstore: logstore,
+           appendAtStart: true 
+       });
+
+       Ext.apply(me, {
+           store: store,
+           stateful: false,
+
+           viewConfig: {
+               trackOver: false,
+               stripeRows: true,
+               getRowClass: function(record, index) {
+                   var pri = record.get('pri');
+
+                   if (pri && pri <= 3) {
+                       return "x-form-invalid-field";
+                   }
+               }
+           },
+           sortableColumns: false,
+           columns: [
+               { 
+                   header: gettext("Time"), 
+                   dataIndex: 'time',
+                   width: 150,
+                   renderer: function(value) { 
+                       return Ext.Date.format(value, "M d H:i:s"); 
+                   }
+               },
+               { 
+                   header: gettext("Node"), 
+                   dataIndex: 'node',
+                   width: 150
+               },
+               { 
+                   header: gettext("Service"), 
+                   dataIndex: 'tag',
+                   width: 100
+               },
+               { 
+                   header: "PID", 
+                   dataIndex: 'pid',
+                   width: 100 
+               },
+               { 
+                   header: gettext("User name"), 
+                   dataIndex: 'user',
+                   width: 150
+               },
+               { 
+                   header: gettext("Severity"), 
+                   dataIndex: 'pri',
+                   renderer: PVE.Utils.render_serverity,
+                   width: 100 
+               },
+               { 
+                   header: gettext("Message"), 
+                   dataIndex: 'msg',
+                   flex: 1       
+               }
+           ],
+           listeners: {
+               show: logstore.startUpdate,
+               hide: logstore.stopUpdate,
+               destroy: logstore.stopUpdate
+           }
+       });
+
+       me.callParent();
+    }
+});
\ No newline at end of file
diff --git a/www/manager6/dc/OptionView.js b/www/manager6/dc/OptionView.js
new file mode 100644 (file)
index 0000000..3a98bce
--- /dev/null
@@ -0,0 +1,197 @@
+Ext.define('PVE.dc.HttpProxyEdit', {
+    extend: 'PVE.window.Edit',
+
+    initComponent : function() {
+       var me = this;
+
+       Ext.applyIf(me, {
+           subject: gettext('HTTP proxy'),
+           items: {
+               xtype: 'pvetextfield',
+               name: 'http_proxy',
+               vtype: 'HttpProxy',
+               emptyText: gettext('Do not use any proxy'),
+               deleteEmpty: true,
+               value: '',
+               fieldLabel: gettext('HTTP proxy')
+           }
+       });
+
+       me.callParent();
+
+       me.load();
+    }
+});
+
+Ext.define('PVE.dc.KeyboardEdit', {
+    extend: 'PVE.window.Edit',
+
+    initComponent : function() {
+       var me = this;
+
+       Ext.applyIf(me, {
+           subject: gettext('Keyboard Layout'),
+           items: {
+               xtype: 'VNCKeyboardSelector',
+               name: 'keyboard',
+               value: '',
+               fieldLabel: gettext('Keyboard Layout')
+           }
+       });
+
+       me.callParent();
+
+       me.load();
+    }
+});
+
+Ext.define('PVE.dc.ConsoleViewerEdit', {
+    extend: 'PVE.window.Edit',
+
+    initComponent : function() {
+       var me = this;
+
+       var data = [];
+
+       Ext.Array.each(['', 'vv', 'html5'], function(value) {
+           data.push([value, PVE.Utils.render_console_viewer(value)]);
+       });
+
+       Ext.applyIf(me, {
+           subject: gettext('Console Viewer'),
+           items: {
+               xtype: 'pveKVComboBox',
+               name: 'console',
+               value: '',
+               fieldLabel: gettext('Console Viewer'),
+               comboItems: data,
+           }
+       });
+
+       me.callParent();
+
+       me.load();
+    }
+});
+
+Ext.define('PVE.dc.EmailFromEdit', {
+    extend: 'PVE.window.Edit',
+
+    initComponent : function() {
+       var me = this;
+
+       Ext.applyIf(me, {
+           subject: gettext('Email from address'),
+           items: {
+               xtype: 'pvetextfield',
+               name: 'email_from',
+               vtype: 'email',
+               emptyText: gettext('Send emails from root@$hostname'),
+               deleteEmpty: true,
+               value: '',
+               fieldLabel: gettext('Email from address')
+           }
+       });
+
+       me.callParent();
+
+       me.load();
+    }
+});
+
+Ext.define('PVE.dc.OptionView', {
+    extend: 'PVE.grid.ObjectGrid',
+    alias: ['widget.pveDcOptionView'],
+
+    noProxyText: gettext('Do not use any proxy'),
+    noEmailFromText: gettext('Send emails from root@$hostname'),
+
+    initComponent : function() {
+       var me = this;
+
+       var reload = function() {
+           me.rstore.load();
+       };
+
+       var rows = {
+           keyboard: { 
+               header: gettext('Keyboard Layout'), 
+               editor: 'PVE.dc.KeyboardEdit',
+               renderer: PVE.Utils.render_kvm_language,
+               required: true 
+           },
+           http_proxy: { 
+               header: gettext('HTTP proxy'),
+               editor: 'PVE.dc.HttpProxyEdit', 
+               required: true,
+               renderer: function(value) {
+                   if (!value) {
+                       return me.noProxyText;
+                   }
+                   return value;
+               }
+           },
+           console: {
+               header: gettext('Console Viewer'),
+               editor: 'PVE.dc.ConsoleViewerEdit',
+               required: true,
+               renderer: PVE.Utils.render_console_viewer
+           },
+           email_from: { 
+               header: gettext('Email from address'),
+               editor: 'PVE.dc.EmailFromEdit', 
+               required: true,
+               renderer: function(value) {
+                   if (!value) {
+                       return me.noEmailFromText;
+                   }
+                   return value;
+               }
+           }
+       };
+
+       var sm = Ext.create('Ext.selection.RowModel', {});
+
+       var run_editor = function() {
+           var rec = sm.getSelection()[0];
+           if (!rec) {
+               return;
+           }
+
+           var rowdef = rows[rec.data.key];
+           if (!rowdef.editor) {
+               return;
+           }
+           
+           var win = Ext.create(rowdef.editor, {
+               url: "/api2/extjs/cluster/options",
+               confid: rec.data.key
+           });
+           win.show();
+           win.on('destroy', reload);
+       };
+
+       var edit_btn = new PVE.button.Button({
+           text: gettext('Edit'),
+           disabled: true,
+           selModel: sm,
+           handler: run_editor
+       });
+
+       Ext.applyIf(me, {
+           url: "/api2/json/cluster/options",
+           cwidth1: 130,
+           interval: 1000,
+           selModel: sm,
+           tbar: [ edit_btn ],
+           rows: rows,
+           listeners: {
+               itemdblclick: run_editor
+           }
+       });
+
+       me.callParent();
+
+       me.on('show', reload);
+    }
+});
diff --git a/www/manager6/dc/PoolEdit.js b/www/manager6/dc/PoolEdit.js
new file mode 100644 (file)
index 0000000..42196e7
--- /dev/null
@@ -0,0 +1,48 @@
+Ext.define('PVE.dc.PoolEdit', {
+    extend: 'PVE.window.Edit',
+    alias: ['widget.pveDcPoolEdit'],
+
+    initComponent : function() {
+        var me = this;
+
+        me.create = !me.poolid;
+
+        var url;
+        var method;
+
+        if (me.create) {
+            url = '/api2/extjs/pools';
+            method = 'POST';
+        } else {
+            url = '/api2/extjs/pools/' + me.poolid;
+            method = 'PUT';
+        }
+
+        Ext.applyIf(me, {
+            subject: gettext('Pool'),
+            url: url,
+            method: method,
+            items: [
+                {
+                   xtype: me.create ? 'pvetextfield' : 'displayfield',
+                   fieldLabel: gettext('Name'),
+                   name: 'poolid',
+                   value: me.poolid,
+                   allowBlank: false
+               },
+                {
+                   xtype: 'textfield',
+                   fieldLabel: gettext('Comment'),
+                   name: 'comment',
+                   allowBlank: true
+               }
+            ]
+        });
+
+        me.callParent();
+
+        if (!me.create) {
+            me.load();
+        }
+    }
+});
diff --git a/www/manager6/dc/PoolView.js b/www/manager6/dc/PoolView.js
new file mode 100644 (file)
index 0000000..4ae99e2
--- /dev/null
@@ -0,0 +1,110 @@
+Ext.define('PVE.dc.PoolView', {
+    extend: 'Ext.grid.GridPanel',
+
+    alias: ['widget.pvePoolView'],
+
+    initComponent : function() {
+       var me = this;
+
+       var store = new Ext.data.Store({
+           model: 'pve-pools',
+           sorters: { 
+               property: 'poolid', 
+               order: 'DESC' 
+           }
+       });
+
+        var reload = function() {
+            store.load();
+        };
+
+       var sm = Ext.create('Ext.selection.RowModel', {});
+
+       var remove_btn = new PVE.button.Button({
+           text: gettext('Remove'),
+           disabled: true,
+           selModel: sm,
+           confirmMsg: function (rec) {
+               return Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
+                                        "'" + rec.data.poolid + "'");
+           },
+           handler: function(btn, event, rec) {
+               PVE.Utils.API2Request({
+                   url: '/pools/' + rec.data.poolid,
+                   method: 'DELETE',
+                   waitMsgTarget: me,
+                   callback: function() {
+                       reload();
+                   },
+                   failure: function (response, opts) {
+                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+                   }
+               });
+           }
+       });
+
+       var run_editor = function() {
+           var rec = sm.getSelection()[0];
+           if (!rec) {
+               return;
+           }
+
+            var win = Ext.create('PVE.dc.PoolEdit',{
+                poolid: rec.data.poolid
+            });
+            win.on('destroy', reload);
+            win.show();
+       };
+
+       var edit_btn = new PVE.button.Button({
+           text: gettext('Edit'),
+           disabled: true,
+           selModel: sm,
+           handler: run_editor
+       });
+
+       var tbar = [
+            {
+               text: gettext('Create'),
+               handler: function() {
+                   var win = Ext.create('PVE.dc.PoolEdit', {});
+                   win.on('destroy', reload);
+                   win.show();
+               }
+            },
+           edit_btn, remove_btn
+        ];
+
+       PVE.Utils.monStoreErrors(me, store);
+
+       Ext.apply(me, {
+           store: store,
+           selModel: sm,
+           stateful: false,
+           tbar: tbar,
+           viewConfig: {
+               trackOver: false
+           },
+           columns: [
+               {
+                   header: gettext('Name'),
+                   width: 200,
+                   sortable: true,
+                   dataIndex: 'poolid'
+               },
+               {
+                   header: gettext('Comment'),
+                   sortable: false,
+                   dataIndex: 'comment',
+                   flex: 1
+               }
+           ],
+           listeners: {
+               show: reload,
+               itemdblclick: run_editor
+           }
+       });
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/dc/RoleView.js b/www/manager6/dc/RoleView.js
new file mode 100644 (file)
index 0000000..cbfe82d
--- /dev/null
@@ -0,0 +1,63 @@
+Ext.define('PVE.dc.RoleView', {
+    extend: 'Ext.grid.GridPanel',
+
+    alias: ['widget.pveRoleView'],
+
+    initComponent : function() {
+       var me = this;
+
+       var store = new Ext.data.Store({
+           model: 'pve-roles',
+           sorters: { 
+               property: 'roleid', 
+               order: 'DESC' 
+           }
+       });
+
+       var render_privs = function(value, metaData) {
+
+           if (!value) {
+               return '-';
+           }
+
+           // allow word wrap
+           metaData.style = 'white-space:normal;';
+
+           return value.replace(/\,/g, ' ');
+       };
+
+       PVE.Utils.monStoreErrors(me, store);
+
+       Ext.apply(me, {
+           store: store,
+           stateful: false,
+
+           viewConfig: {
+               trackOver: false
+           },
+           columns: [
+               {
+                   header: gettext('Name'),
+                   width: 150,
+                   sortable: true,
+                   dataIndex: 'roleid'
+               },
+               {
+                   id: 'privs',
+                   header: gettext('Privileges'),
+                   sortable: false,
+                   renderer: render_privs,
+                   dataIndex: 'privs',
+                   flex: 1
+               }
+           ],
+           listeners: {
+               show: function() {
+                   store.load();
+               }
+           }
+       });
+
+       me.callParent();
+    }
+});
\ No newline at end of file
diff --git a/www/manager6/dc/SecurityGroups.js b/www/manager6/dc/SecurityGroups.js
new file mode 100644 (file)
index 0000000..0e31295
--- /dev/null
@@ -0,0 +1,230 @@
+Ext.define('PVE.SecurityGroupEdit', {
+    extend: 'PVE.window.Edit',
+
+    base_url: "/cluster/firewall/groups",
+
+    allow_iface: false,
+
+    initComponent : function() {
+       /*jslint confusion: true */
+       var me = this;
+
+       me.create = (me.group_name === undefined);
+
+       var subject;
+
+        me.url = '/api2/extjs' + me.base_url;
+        me.method = 'POST';
+       
+       var items = [       
+           {
+               xtype: 'textfield',
+               name: 'group',
+               value: me.group_name || '',
+               fieldLabel: gettext('Name'),
+               allowBlank: false
+           },
+           {
+               xtype: 'textfield',
+               name: 'comment',
+               value: me.group_comment || '',
+               fieldLabel: gettext('Comment')
+           }
+       ];
+
+       if (me.create) {
+           subject = gettext('Security Group');
+        } else {
+           subject = gettext('Security Group') + " '" + me.group_name + "'";
+           items.push({
+               xtype: 'hiddenfield',
+               name: 'rename',
+               value: me.group_name
+           });
+        }
+
+       var ipanel = Ext.create('PVE.panel.InputPanel', {
+           create: me.create,
+           items: items 
+       });
+
+
+       Ext.apply(me, {
+            subject: subject,
+           items: [ ipanel ]
+       });
+
+       me.callParent();
+    }
+});
+
+Ext.define('PVE.SecurityGroupList', {
+    extend: 'Ext.grid.Panel',
+    alias: 'widget.pveSecurityGroupList',
+
+    rule_panel: undefined,
+
+    addBtn: undefined,
+    removeBtn: undefined,
+    editBtn: undefined,
+
+    base_url: "/cluster/firewall/groups",
+
+    initComponent: function() {
+       /*jslint confusion: true */
+        var me = this;
+
+       if (me.rule_panel == undefined) {
+           throw "no rule panel specified";
+       }
+
+       if (me.base_url == undefined) {
+           throw "no base_url specified";
+       }
+
+       var store = new Ext.data.Store({
+           fields: [ 'group', 'comment', 'digest' ],
+           proxy: {
+               type: 'pve',
+               url: '/api2/json' + me.base_url
+           },
+           idProperty: 'group',
+           sorters: {
+               property: 'group',
+               order: 'DESC'
+           }
+       });
+
+       var sm = Ext.create('Ext.selection.RowModel', {});
+
+       var reload = function() {
+           var oldrec = sm.getSelection()[0];
+           store.load(function(records, operation, success) {
+               if (oldrec) {
+                   var rec = store.findRecord('group', oldrec.data.group);
+                   if (rec) {
+                       sm.select(rec);
+                   }
+               }
+           });
+       };
+
+       var run_editor = function() {
+           var rec = sm.getSelection()[0];
+           if (!rec) {
+               return;
+           }
+           var win = Ext.create('PVE.SecurityGroupEdit', {
+               digest: rec.data.digest,
+               group_name: rec.data.group,
+               group_comment: rec.data.comment
+           });
+           win.show();
+           win.on('destroy', reload);
+       };
+
+       me.editBtn = new PVE.button.Button({
+           text: gettext('Edit'),
+           disabled: true,
+           selModel: sm,
+           handler: run_editor
+       });
+
+       me.addBtn = new PVE.button.Button({
+           text: gettext('Create'),
+           handler: function() {
+               sm.deselectAll();
+               var win = Ext.create('PVE.SecurityGroupEdit', {});
+               win.show();
+               win.on('destroy', reload);
+           }
+       });
+
+       me.removeBtn = new PVE.button.Button({
+           text: gettext('Remove'),
+           selModel: sm,
+           disabled: true,
+           handler: function() {
+               var rec = sm.getSelection()[0];
+               if (!rec || !me.base_url) {
+                   return;
+               }
+               PVE.Utils.API2Request({
+                   url: me.base_url + '/' + rec.data.group,
+                   method: 'DELETE',
+                   waitMsgTarget: me,
+                   failure: function(response, options) {
+                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+                   },
+                   callback: reload
+               });
+           }
+       });
+
+       Ext.apply(me, {
+           store: store,
+           tbar: [ '<b>' + gettext('Group') + ':</b>', me.addBtn, me.removeBtn, me.editBtn ],
+           selModel: sm,
+           columns: [
+               { header: gettext('Group'), dataIndex: 'group', width: 100 },
+               { header: gettext('Comment'), dataIndex: 'comment', flex: 1 }
+           ],
+           listeners: {
+               itemdblclick: run_editor,
+               select: function(sm, rec) {
+                   var url = '/cluster/firewall/groups/' + rec.data.group;
+                   me.rule_panel.setBaseUrl(url);
+               },
+               deselect: function() {
+                   me.rule_panel.setBaseUrl(undefined);
+               },
+               show: reload
+           }
+       });
+
+       me.callParent();
+
+       store.load();
+    }
+});
+
+Ext.define('PVE.SecurityGroups', {
+    extend: 'Ext.panel.Panel',
+    alias: 'widget.pveSecurityGroups',
+
+    title: 'Security Groups',
+
+    initComponent: function() {
+       var me = this;
+
+       var rule_panel = Ext.createWidget('pveFirewallRules', {
+           region: 'center',
+           allow_groups: false,
+           list_refs_url: '/cluster/firewall/refs',
+           tbar_prefix: '<b>' + gettext('Rules') + ':</b>',
+           flex: 0.75,
+           border: false
+       });
+
+       var sglist = Ext.createWidget('pveSecurityGroupList', {
+           region: 'west',
+           rule_panel: rule_panel,
+           flex: 0.25,
+           border: false,
+           split: true
+       });
+
+
+       Ext.apply(me, {
+            layout: 'border',
+            items: [ sglist, rule_panel ],
+           listeners: {
+               show: function() {
+                   sglist.fireEvent('show', sglist);
+               }
+           }
+       });
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/dc/StorageView.js b/www/manager6/dc/StorageView.js
new file mode 100644 (file)
index 0000000..4bcf3b7
--- /dev/null
@@ -0,0 +1,267 @@
+
+Ext.define('PVE.dc.StorageView', {
+    extend: 'Ext.grid.GridPanel',
+
+    alias: ['widget.pveStorageView'],
+
+    initComponent : function() {
+       var me = this;
+
+       var store = new Ext.data.Store({
+           model: 'pve-storage',
+           proxy: {
+                type: 'pve',
+               url: "/api2/json/storage"
+           },
+           sorters: { 
+               property: 'storage', 
+               order: 'DESC' 
+           }
+       });
+
+       var reload = function() {
+           store.load();
+       };
+
+       var sm = Ext.create('Ext.selection.RowModel', {});
+
+       var run_editor = function() {
+           var rec = sm.getSelection()[0];
+           if (!rec) {
+               return;
+           }
+           var type = rec.data.type;
+           
+           var editor;
+           if (type === 'dir') {
+               editor = 'PVE.storage.DirEdit';
+           } else if (type === 'nfs') {
+               editor = 'PVE.storage.NFSEdit';
+           } else if (type === 'glusterfs') {
+               editor = 'PVE.storage.GlusterFsEdit';
+           } else if (type === 'lvm') {
+               editor = 'PVE.storage.LVMEdit';
+           } else if (type === 'iscsi') {
+               editor = 'PVE.storage.IScsiEdit';
+           } else if (type === 'rbd') {
+               editor = 'PVE.storage.RBDEdit';
+           } else if (type === 'sheepdog') {
+               editor = 'PVE.storage.SheepdogEdit';
+           } else if (type === 'zfs') {
+               editor = 'PVE.storage.ZFSEdit';
+           } else if (type === 'zfspool') {
+               editor = 'PVE.storage.ZFSPoolEdit';
+           } else {
+               return;
+           }
+           var win = Ext.create(editor, {
+               storageId: rec.data.storage
+           });
+
+           win.show();
+           win.on('destroy', reload);
+       };
+       
+       var edit_btn = new PVE.button.Button({
+           text: gettext('Edit'),
+           disabled: true,
+           selModel: sm,
+           handler: run_editor
+       });
+
+       var remove_btn = new PVE.button.Button({
+           text: gettext('Remove'),
+           disabled: true,
+           selModel: sm,
+           confirmMsg: function (rec) {
+               return Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
+                                        "'" + rec.data.storage + "'");
+           },
+           handler: function(btn, event, rec) {
+               PVE.Utils.API2Request({
+                   url: '/storage/' + rec.data.storage,
+                   method: 'DELETE',
+                   waitMsgTarget: me,
+                   callback: function() {
+                       reload();
+                   },
+                   failure: function (response, opts) {
+                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+                   }
+               });
+           }
+       });
+
+       Ext.apply(me, {
+           store: store,
+           selModel: sm,
+           stateful: false,
+           viewConfig: {
+               trackOver: false
+           },
+           tbar: [ 
+               {
+                   text: gettext('Add'),
+                   menu: new Ext.menu.Menu({
+                       items: [
+                           {
+                               text:  PVE.Utils.format_storage_type('dir'),
+                               iconCls: 'pve-itype-icon-itype',
+                               handler: function() {
+                                   var win = Ext.create('PVE.storage.DirEdit', {});
+                                   win.on('destroy', reload);
+                                   win.show();
+                               }
+
+                           },
+                           {
+                               text:  PVE.Utils.format_storage_type('lvm'),
+                               iconCls: 'pve-itype-icon-storage',
+                               handler: function() {
+                                   var win = Ext.create('PVE.storage.LVMEdit', {});
+                                   win.on('destroy', reload);
+                                   win.show();
+                               }
+                           },
+                           {
+                               text:  PVE.Utils.format_storage_type('nfs'),
+                               iconCls: 'pve-itype-icon-network-server',
+                               handler: function() {
+                                   var win = Ext.create('PVE.storage.NFSEdit', {});
+                                   win.on('destroy', reload);
+                                   win.show();
+                               }
+                           },
+                           {
+                               text: PVE.Utils.format_storage_type('iscsi'),
+                               iconCls: 'pve-itype-icon-network-server',
+                               handler: function() {
+                                   var win = Ext.create('PVE.storage.IScsiEdit', {});
+                                   win.on('destroy', reload);
+                                   win.show();
+                               }
+                           },
+                           {
+                               text: PVE.Utils.format_storage_type('glusterfs'),
+                               iconCls: 'pve-itype-icon-network-server',
+                               handler: function() {
+                                   var win = Ext.create('PVE.storage.GlusterFsEdit', {});
+                                   win.on('destroy', reload);
+                                   win.show();
+                               }
+                           },
+                           {
+                               text: PVE.Utils.format_storage_type('rbd'),
+                               iconCls: 'pve-itype-icon-network-server',
+                               handler: function() {
+                                   var win = Ext.create('PVE.storage.RBDEdit', {});
+                                   win.on('destroy', reload);
+                                   win.show();
+                               }
+                           },
+                           {
+                               text: PVE.Utils.format_storage_type('zfs'),
+                               iconCls: 'pve-itype-icon-network-server',
+                               handler: function() {
+                                   var win = Ext.create('PVE.storage.ZFSEdit', {});
+                                   win.on('destroy', reload);
+                                   win.show();
+                               }
+                           },
+                           {
+                                text: PVE.Utils.format_storage_type('zfspool'),
+                                iconCls: 'pve-itype-icon-storage',
+                                handler: function() {
+                                    var win = Ext.create('PVE.storage.ZFSPoolEdit', {});
+                                    win.on('destroy', reload);
+                                    win.show();
+                                }
+                            },
+
+/* the following type are conidered unstable
+ * so we do not enable that on the GUI for now
+                           {
+                               text: PVE.Utils.format_storage_type('sheepdog'),
+                               iconCls: 'pve-itype-icon-network-server',
+                               handler: function() {
+                                   var win = Ext.create('PVE.storage.SheepdogEdit', {});
+                                   win.on('destroy', reload);
+                                   win.show();
+                               }
+                           }
+*/
+                       ]
+                   })
+               },
+               remove_btn,
+               edit_btn
+           ],
+           columns: [
+               {
+                   header: 'ID',
+                   width: 100,
+                   sortable: true,
+                   dataIndex: 'storage'
+               },
+               {
+                   header: gettext('Type'),
+                   width: 60,
+                   sortable: true,
+                   dataIndex: 'type',
+                   renderer: PVE.Utils.format_storage_type
+               },
+               {
+                   header: gettext('Content'),
+                   width: 150,
+                   sortable: true,
+                   dataIndex: 'content',
+                   renderer: PVE.Utils.format_content_types
+               },
+               {
+                   header: gettext('Path') + '/' + gettext('Target'),
+                   flex: 1,
+                   sortable: true,
+                   dataIndex: 'path',
+                   renderer: function(value, metaData, record) {
+                       if (record.data.target) {
+                           return record.data.target;
+                       }
+                       return value;
+                   }
+               },
+               {
+                   header: gettext('Shared'),
+                   width: 80,
+                   sortable: true,
+                   dataIndex: 'shared',
+                   renderer: PVE.Utils.format_boolean
+               },
+               {
+                   header: gettext('Enable'),
+                   width: 80,
+                   sortable: true,
+                   dataIndex: 'disable',
+                   renderer: PVE.Utils.format_neg_boolean
+               }
+           ],
+           listeners: {
+               show: reload,
+               itemdblclick: run_editor
+           }
+       });
+
+       me.callParent();
+    }
+}, function() {
+
+    Ext.define('pve-storage', {
+       extend: 'Ext.data.Model',
+       fields: [ 
+           'path', 'type', 'content', 'server', 'portal', 'target', 'export', 'storage',
+           { name: 'shared', type: 'boolean'},
+           { name: 'disable', type: 'boolean'} 
+       ],
+       idProperty: 'storage'
+    });
+
+});
diff --git a/www/manager6/dc/Summary.js b/www/manager6/dc/Summary.js
new file mode 100644 (file)
index 0000000..b0f8b32
--- /dev/null
@@ -0,0 +1,142 @@
+Ext.define('PVE.dc.NodeView', {
+    extend: 'Ext.grid.GridPanel',
+
+    alias: ['widget.pveDcNodeView'],
+
+    initComponent : function() {
+       var me = this;
+
+       var rstore = Ext.create('PVE.data.UpdateStore', {
+           interval: 3000,
+           storeid: 'pve-dc-nodes',
+           model: 'pve-dc-nodes',
+           proxy: {
+                type: 'pve',
+                url: "/api2/json/cluster/status"
+           },
+           filters: {
+               property: 'type',
+               value   : 'node'
+           }
+       });
+
+       var store = Ext.create('PVE.data.DiffStore', { rstore: rstore });
+
+       var noClusterText = gettext("Standalone node - no cluster defined");
+       var status = Ext.create('Ext.Component', {
+           padding: 2,
+           html: '&nbsp;',
+           dock: 'bottom'
+       });
+
+       Ext.apply(me, {
+           store: store,
+           stateful: false,
+           bbar: [ status ],
+           columns: [
+               {
+                   header: gettext('Name'),
+                   width: 200,
+                   sortable: true,
+                   dataIndex: 'name'
+               },
+               {
+                   header: 'ID',
+                   width: 50,
+                   sortable: true,
+                   dataIndex: 'nodeid'
+               },
+               {
+                   header: gettext('Online'),
+                   width: 100,
+                   sortable: true,
+                   dataIndex: 'online',
+                   renderer: PVE.Utils.format_boolean
+               },
+               {
+                   header: gettext('Support'),
+                   width: 100,
+                   sortable: true,
+                   dataIndex: 'level',
+                   renderer: PVE.Utils.render_support_level
+               },
+               {
+                   header: gettext('Server Address'),
+                   flex: 1,
+                   sortable: true,
+                   dataIndex: 'ip'
+               }
+           ], 
+           listeners: {
+               show: rstore.startUpdate,
+               hide: rstore.stopUpdate,
+               destroy: rstore.stopUpdate
+           }
+       });
+
+       me.callParent();
+
+       rstore.on('load', function(s, records, success) {
+           if (!success) {
+               return;
+           }
+
+           var cluster_rec = rstore.getById('cluster');
+
+           if (!cluster_rec) {
+               status.update(noClusterText);
+               return;
+           }
+
+           var cluster_raw = cluster_rec.raw;
+           if (!cluster_raw) {
+               status.update(noClusterText);
+               return;
+           }
+           var text = gettext("Cluster") + ": " + cluster_raw.name + ",  " +
+               gettext("Quorate") + ": " + PVE.Utils.format_boolean(cluster_raw.quorate);
+           status.update(text);
+       });
+
+    }
+}, function() {
+
+    Ext.define('pve-dc-nodes', {
+       extend: 'Ext.data.Model',
+       fields: [ 'id', 'type', 'name', 'nodeid', 'ip', 'level', 'local', 'online'],
+       idProperty: 'id'
+    });
+
+});
+
+Ext.define('PVE.dc.Summary', {
+    extend: 'Ext.panel.Panel',
+
+    alias: ['widget.pveDcSummary'],
+
+    initComponent: function() {
+        var me = this;
+
+       var nodegrid = Ext.create('PVE.dc.NodeView', {
+           title: gettext('Nodes'),
+           border: false,
+           region: 'center',
+           flex: 3
+       });
+
+       Ext.apply(me, {
+           layout: 'border',
+           items: [ nodegrid ],
+           listeners: {
+               show: function() {
+                   nodegrid.fireEvent('show', nodegrid);
+               },
+               hide: function() {
+                   nodegrid.fireEvent('hide', nodegrid);
+               }
+           }
+       });
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/dc/Support.js b/www/manager6/dc/Support.js
new file mode 100644 (file)
index 0000000..1ed32d4
--- /dev/null
@@ -0,0 +1,78 @@
+Ext.define('PVE.dc.Support', {
+    extend: 'Ext.panel.Panel',
+    alias: 'widget.pveDcSupport',
+
+    invalidHtml: '<h1>No valid subscription</h1>' + PVE.Utils.noSubKeyHtml,
+
+    communityHtml: 'Please use the public community <a target="_blank" href="http://forum.proxmox.com">forum</a> for any questions.',
+
+    activeHtml: 'Please use our <a target="_blank" href="https://my.proxmox.com">support portal</a> for any questions. You can also use the public community <a target="_blank" href="http://forum.proxmox.com">forum</a> to get additional information.',
+
+    bugzillaHtml: '<h1>Bug Tracking</h1>Our bug tracking system is available <a target="_blank" href="https://bugzilla.proxmox.com">here</a>.',
+
+    docuHtml: '<h1>Documentation</h1>Complete documentation, tutorials, videos and more is available at our <a target="_blank" href="http://pve.proxmox.com/wiki/Documentation">wiki</a>.',
+
+    updateActive: function(data) {
+       var me = this;
+       
+       var html = '<h1>' + data.productname + '</h1>' + me.activeHtml; 
+       html += '<br><br>' + me.docuHtml;
+       html += '<br><br>' + me.bugzillaHtml;
+
+       me.update(html);
+    },
+
+    updateCommunity: function(data) {
+       var me = this;
+
+       var html = '<h1>' + data.productname + '</h1>' + me.communityHtml; 
+       html += '<br><br>' + me.docuHtml;
+       html += '<br><br>' + me.bugzillaHtml;
+
+       me.update(html);
+    },
+        
+    updateInactive: function(data) {
+       var me = this;
+       me.update(me.invalidHtml);
+    },
+
+    initComponent: function() {
+        var me = this;
+
+       var reload = function() {
+           PVE.Utils.API2Request({
+               url: '/nodes/localhost/subscription',
+               method: 'GET',
+               waitMsgTarget: me,
+               failure: function(response, opts) {
+                   Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+                   me.update(gettext('Unable to load subscription status') + ": " + response.htmlStatus);
+               },
+               success: function(response, opts) {
+                   var data = response.result.data;
+
+                   if (data.status === 'Active') {
+                       if (data.level === 'c') {
+                           me.updateCommunity(data);
+                       } else {
+                           me.updateActive(data);
+                       }
+                   } else {
+                       me.updateInactive(data);
+                   }
+               }
+           });
+       };
+
+       Ext.apply(me, {
+           autoScroll: true,
+           bodyStyle: 'padding:10px',
+           listeners: {
+               show: reload
+           }
+       });
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/dc/Tasks.js b/www/manager6/dc/Tasks.js
new file mode 100644 (file)
index 0000000..58d09a5
--- /dev/null
@@ -0,0 +1,141 @@
+/* This class defines the "Tasks" tab of the bottom status panel
+ * Tasks are jobs with a start, end and log output
+ */
+
+Ext.define('PVE.dc.Tasks', {
+    extend: 'Ext.grid.GridPanel',
+
+    alias: ['widget.pveClusterTasks'],
+
+    initComponent : function() {
+       var me = this;
+
+       var taskstore = new PVE.data.UpdateStore({
+           storeid: 'pve-cluster-tasks',
+           model: 'pve-tasks',
+           proxy: {
+                type: 'pve',
+               url: '/api2/json/cluster/tasks'
+           }
+       });
+
+       var store = Ext.create('PVE.data.DiffStore', { 
+           rstore: taskstore,
+           sortAfterUpdate: true,
+           appendAtStart: true,
+           sorters: [
+               {
+                   property : 'pid',
+                   direction: 'DESC'
+               },
+               {
+                   property : 'starttime',
+                   direction: 'DESC'
+               }
+           ]
+
+       });
+
+       var run_task_viewer = function() {
+           var sm = me.getSelectionModel();
+           var rec = sm.getSelection()[0];
+           if (!rec) {
+               return;
+           }
+
+           var win = Ext.create('PVE.window.TaskViewer', { 
+               upid: rec.data.upid
+           });
+           win.show();
+       };
+
+       Ext.apply(me, {
+           store: store,
+           stateful: false,
+
+           viewConfig: {
+               trackOver: false,
+               stripeRows: true, // does not work with getRowClass()
+               getRowClass: function(record, index) {
+                   var status = record.get('status');
+
+                   if (status && status != 'OK') {
+                       return "x-form-invalid-field";
+                   }
+               }
+           },
+           sortableColumns: false,
+           columns: [
+               { 
+                   header: gettext("Start Time"), 
+                   dataIndex: 'starttime',
+                   width: 150,
+                   renderer: function(value) { 
+                       return Ext.Date.format(value, "M d H:i:s"); 
+                   }
+               },
+               { 
+                   header: gettext("End Time"), 
+                   dataIndex: 'endtime',
+                   width: 150,
+                   renderer: function(value, metaData, record) {
+                       if (record.data.pid) {
+                           if (record.data.type == "vncproxy" || 
+                               record.data.type == "vncshell" ||
+                               record.data.type == "spiceproxy") {
+                               metaData.tdCls =  "x-grid-row-console";
+                           } else {
+                               metaData.tdCls =  "x-grid-row-loading";
+                           }
+                           return "";
+                       }
+                       return Ext.Date.format(value, "M d H:i:s"); 
+                   }
+               },
+               { 
+                   header: gettext("Node"), 
+                   dataIndex: 'node',
+                   width: 100
+               },
+               { 
+                   header: gettext("User name"), 
+                   dataIndex: 'user',
+                   width: 150
+               },
+               { 
+                   header: gettext("Description"), 
+                   dataIndex: 'upid', 
+                   flex: 1,              
+                   renderer: PVE.Utils.render_upid
+               },
+               { 
+                   header: gettext("Status"), 
+                   dataIndex: 'status', 
+                   width: 200,
+                   renderer: function(value, metaData, record) { 
+                       if (record.data.pid) {
+                           if (record.data.type != "vncproxy") {
+                               metaData.tdCls =  "x-grid-row-loading";
+                           }
+                           return "";
+                       }
+                       if (value == 'OK') {
+                           return 'OK';
+                       }
+                       // metaData.attr = 'style="color:red;"'; 
+                       return PVE.Utils.errorText + ': ' + value;
+                   }
+               }
+           ],
+           listeners: {
+               itemdblclick: run_task_viewer,
+               show: taskstore.startUpdate,
+               hide: taskstore.stopUpdate,
+               destroy: taskstore.stopUpdate
+           }
+       });
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/dc/UserEdit.js b/www/manager6/dc/UserEdit.js
new file mode 100644 (file)
index 0000000..bb110b5
--- /dev/null
@@ -0,0 +1,206 @@
+Ext.define('PVE.dc.UserEdit', {
+    extend: 'PVE.window.Edit',
+    alias: ['widget.pveDcUserEdit'],
+
+    isAdd: true,
+
+    initComponent : function() {
+        var me = this;
+
+        me.create = !me.userid;
+
+        var url;
+        var method;
+        var realm;
+
+        if (me.create) {
+            url = '/api2/extjs/access/users';
+            method = 'POST';
+        } else {
+            url = '/api2/extjs/access/users/' + me.userid;
+            method = 'PUT';
+       }
+
+       var verifypw;
+       var pwfield;
+
+       var validate_pw = function() {
+           if (verifypw.getValue() !== pwfield.getValue()) {
+               return gettext("Passwords does not match");
+           }
+           return true;
+       };
+
+       verifypw = Ext.createWidget('textfield', { 
+           inputType: 'password',
+           fieldLabel: gettext('Confirm password'), 
+           name: 'verifypassword',
+           submitValue: false,
+           disabled: true,
+           hidden: true,
+           validator: validate_pw
+       });
+
+       pwfield = Ext.createWidget('textfield', { 
+           inputType: 'password',
+           fieldLabel: gettext('Password'), 
+           minLength: 5,
+           name: 'password',
+           disabled: true,
+           hidden: true,
+           validator: validate_pw
+       });
+
+       var update_passwd_field = function(realm) {
+           if (realm === 'pve') {
+               pwfield.setVisible(true);
+               pwfield.setDisabled(false);
+               verifypw.setVisible(true);
+               verifypw.setDisabled(false);
+           } else {
+               pwfield.setVisible(false);
+               pwfield.setDisabled(true);
+               verifypw.setVisible(false);
+               verifypw.setDisabled(true);
+           }
+
+       };
+
+        var column1 = [
+            {
+                xtype: me.create ? 'textfield' : 'displayfield',
+               height: 22, // hack: set same height as text fields
+                name: 'userid',
+                fieldLabel: gettext('User name'),
+                value: me.userid,
+                allowBlank: false,
+                submitValue: me.create ? true : false
+            },
+           pwfield, verifypw,
+           {
+               xtype: 'pveGroupSelector',
+               name: 'groups',
+               multiSelect: true,
+               allowBlank: true,
+               fieldLabel: gettext('Group')
+           },
+            {
+                xtype: 'datefield',
+                name: 'expire',
+               emptyText: 'never',
+               format: 'Y-m-d',
+               submitFormat: 'U',
+                fieldLabel: gettext('Expire')
+            },
+           {
+               xtype: 'pvecheckbox',
+               fieldLabel: gettext('Enabled'),
+               name: 'enable',
+               uncheckedValue: 0,
+               defaultValue: 1,
+               checked: true
+           }
+        ];
+
+        var column2 = [
+           {
+               xtype: 'textfield',
+               name: 'firstname',
+               fieldLabel: gettext('First Name')
+           },
+           {
+               xtype: 'textfield',
+               name: 'lastname',
+               fieldLabel: gettext('Last Name')
+           },
+           {
+               xtype: 'textfield',
+               name: 'email',
+               fieldLabel: gettext('E-Mail'),
+               vtype: 'email'
+           }
+       ];
+
+       var columnB = [
+           {
+               xtype: 'textfield',
+               name: 'comment',
+               fieldLabel: gettext('Comment')
+           },
+           {
+               xtype: 'textfield',
+               name: 'keys',
+               fieldLabel: gettext('Key IDs')
+           }
+       ];
+        if (me.create) {
+            column1.splice(1,0,{
+                xtype: 'pveRealmComboBox',
+                name: 'realm',
+                fieldLabel: gettext('Realm'),
+                allowBlank: false,
+               matchFieldWidth: false,
+               listConfig: { width: 300 },
+                listeners: {
+                    change: function(combo, newValue){
+                        realm = newValue;
+                       update_passwd_field(realm);
+                    }
+                },
+                submitValue: false
+            });
+        }
+
+       var ipanel = Ext.create('PVE.panel.InputPanel', {
+           column1: column1,
+           column2: column2,
+           columnB: columnB,
+           onGetValues: function(values) {
+               // hack: ExtJS datefield does not submit 0, so we need to set that
+               if (!values.expire) {
+                   values.expire = 0;
+               }
+
+               if (realm) {
+                   values.userid = values.userid + '@' + realm;
+               }
+
+               if (!values.password) {
+                   delete values.password;
+               }
+
+               return values;
+           }
+       });
+
+       Ext.applyIf(me, {
+            subject: gettext('User'),
+            url: url,
+            method: method,
+           fieldDefaults: {
+               labelWidth: 110 // for spanish translation 
+           },
+           items: [ ipanel ]
+        });
+
+        me.callParent();
+
+        if (!me.create) {
+            me.load({
+               success: function(response, options) {
+                   var data = response.result.data;
+                   if (Ext.isDefined(data.expire)) {
+                       if (data.expire) {
+                           data.expire = new Date(data.expire * 1000);
+                       } else {
+                           // display 'never' instead of '1970-01-01'
+                           data.expire = null;
+                       }
+                   }
+                   me.setValues(data);
+                }
+            });
+        }
+    }
+});
diff --git a/www/manager6/dc/UserView.js b/www/manager6/dc/UserView.js
new file mode 100644 (file)
index 0000000..c4f8a8b
--- /dev/null
@@ -0,0 +1,235 @@
+Ext.define('PVE.window.PasswordEdit', {
+    extend: 'PVE.window.Edit',
+
+    initComponent : function() {
+       var me = this;
+
+       if (!me.userid) {
+           throw "no userid specified";
+       }
+
+       var verifypw;
+       var pwfield;
+
+       var validate_pw = function() {
+           if (verifypw.getValue() !== pwfield.getValue()) {
+               return gettext("Passwords does not match");
+           }
+           return true;
+       };
+
+       verifypw = Ext.createWidget('textfield', { 
+           inputType: 'password',
+           fieldLabel: gettext('Confirm password'), 
+           name: 'verifypassword',
+           submitValue: false,
+           validator: validate_pw
+       });
+
+       pwfield = Ext.createWidget('textfield', { 
+           inputType: 'password',
+           fieldLabel: gettext('Password'), 
+           minLength: 5,
+           name: 'password',
+           validator: validate_pw
+       });
+
+       Ext.apply(me, {
+           subject: gettext('Password'),
+           url: '/api2/extjs/access/password',
+           items: [
+               pwfield, verifypw,
+               {
+                   xtype: 'hiddenfield',
+                   name: 'userid',
+                   value: me.userid
+               }
+           ]
+       });
+
+       me.callParent();
+    }
+});
+
+Ext.define('PVE.dc.UserView', {
+    extend: 'Ext.grid.GridPanel',
+
+    alias: ['widget.pveUserView'],
+
+    initComponent : function() {
+       var me = this;
+
+       var caps = Ext.state.Manager.get('GuiCap');
+
+       var store = new Ext.data.Store({
+            id: "users",
+           model: 'pve-users',
+           sorters: { 
+               property: 'userid', 
+               order: 'DESC' 
+           }
+       });
+
+       var reload = function() {
+           store.load();
+       };
+
+       var sm = Ext.create('Ext.selection.RowModel', {});
+
+       var remove_btn = new PVE.button.Button({
+           text: gettext('Remove'),
+           disabled: true,
+           selModel: sm,
+           enableFn: function(rec) {
+               if (!caps.access['User.Modify']) {
+                   return false;
+               }
+               return rec.data.userid !== 'root@pam';
+           },
+           confirmMsg: function (rec) {
+               return Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
+                                        "'" + rec.data.userid + "'");
+           },
+           handler: function(btn, event, rec) {
+               var userid = rec.data.userid;
+
+               PVE.Utils.API2Request({
+                   url: '/access/users/' + userid,
+                   method: 'DELETE',
+                   waitMsgTarget: me,
+                   callback: function() {
+                       reload();
+                   },
+                   failure: function (response, opts) {
+                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+                   }
+               });
+           }
+        });
+       var run_editor = function() {
+           var rec = sm.getSelection()[0];
+           if (!rec || !caps.access['User.Modify']) {
+               return;
+           }
+
+            var win = Ext.create('PVE.dc.UserEdit',{
+                userid: rec.data.userid
+            });
+            win.on('destroy', reload);
+            win.show();
+       };
+
+       var edit_btn = new PVE.button.Button({
+           text: gettext('Edit'),
+           disabled: true,
+           enableFn: function(rec) {
+               return !!caps.access['User.Modify'];
+           },
+           selModel: sm,
+           handler: run_editor
+       });
+
+       var pwchange_btn = new PVE.button.Button({
+           text: gettext('Password'),
+           disabled: true,
+           selModel: sm,
+           handler: function(btn, event, rec) {
+               var win = Ext.create('PVE.window.PasswordEdit',{
+                    userid: rec.data.userid
+               });
+               win.on('destroy', reload);
+               win.show();
+           }
+       });
+
+        var tbar = [
+            {
+               text: gettext('Add'),
+               disabled: !caps.access['User.Modify'],
+               handler: function() {
+                    var win = Ext.create('PVE.dc.UserEdit',{
+                    });
+                    win.on('destroy', reload);
+                    win.show();
+               }
+            },
+           edit_btn, remove_btn, pwchange_btn
+        ];
+
+       var render_full_name = function(firstname, metaData, record) {
+
+           var first = firstname || '';
+           var last = record.data.lastname || '';
+           return first + " " + last;
+       };
+
+       var render_username = function(userid) {
+           return userid.match(/^(.+)(@[^@]+)$/)[1];
+       };
+
+       var render_realm = function(userid) {
+           return userid.match(/@([^@]+)$/)[1];
+       };
+
+       Ext.apply(me, {
+           store: store,
+           selModel: sm,
+           stateful: false,
+           tbar: tbar,
+           viewConfig: {
+               trackOver: false
+           },
+           columns: [
+               {
+                   header: gettext('User name'),
+                   width: 200,
+                   sortable: true,
+                   renderer: render_username,
+                   dataIndex: 'userid'
+               },
+               {
+                   header: gettext('Realm'),
+                   width: 100,
+                   sortable: true,
+                   renderer: render_realm,
+                   dataIndex: 'userid'
+               },
+               {
+                   header: gettext('Enabled'),
+                   width: 80,
+                   sortable: true,
+                   renderer: PVE.Utils.format_boolean,
+                   dataIndex: 'enable'
+               },
+               {
+                   header: gettext('Expire'),
+                   width: 80,
+                   sortable: true,
+                   renderer: PVE.Utils.format_expire, 
+                   dataIndex: 'expire'
+               },
+               {
+                   header: gettext('Name'),
+                   width: 150,
+                   sortable: true,
+                   renderer: render_full_name,
+                   dataIndex: 'firstname'
+               },
+               {
+                   id: 'comment',
+                   header: gettext('Comment'),
+                   sortable: false,
+                   dataIndex: 'comment',
+                   flex: 1
+               }
+           ],
+           listeners: {
+               show: reload,
+               itemdblclick: run_editor
+           }
+       });
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/form/BackupModeSelector.js b/www/manager6/form/BackupModeSelector.js
new file mode 100644 (file)
index 0000000..c97b691
--- /dev/null
@@ -0,0 +1,9 @@
+Ext.define('PVE.form.BackupModeSelector', {
+    extend: 'PVE.form.KVComboBox',
+    alias: ['widget.pveBackupModeSelector'],
+    comboItems: [
+                ['snapshot', gettext('Snapshot')],
+                ['suspend', gettext('Suspend')],
+                ['stop', gettext('Stop')]
+    ]
+});
diff --git a/www/manager6/form/BondModeSelector.js b/www/manager6/form/BondModeSelector.js
new file mode 100644 (file)
index 0000000..4504e8b
--- /dev/null
@@ -0,0 +1,48 @@
+Ext.define('PVE.form.BondModeSelector', {
+    extend: 'PVE.form.KVComboBox',
+    alias: ['widget.bondModeSelector'],
+  
+    openvswitch: false,
+
+    initComponent: function() {
+       var me = this;
+
+       if (me.openvswitch) {
+           me.data = [ 
+              ['active-backup', 'active-backup'],
+              ['balance-slb', 'balance-slb'],
+              ['lacp-balance-slb', 'LACP (balance-slb)'],
+              ['lacp-balance-tcp', 'LACP (balance-tcp)']
+          ];
+       } else {
+            me.data = [ 
+               ['balance-rr', 'balance-rr'], 
+               ['active-backup', 'active-backup'], 
+               ['balance-xor', 'balance-xor'], 
+               ['broadcast', 'broadcast'], 
+               ['802.3ad', 'LACP (802.3ad)'], 
+               ['balance-tlb', 'balance-tlb'], 
+               ['balance-alb', 'balance-alb']
+           ];
+       }
+       me.callParent();
+    }
+});
+
+Ext.define('PVE.form.BondPolicySelector', {
+    extend: 'PVE.form.KVComboBox',
+    alias: ['widget.bondPolicySelector'],
+
+    initComponent: function() {
+       var me = this;
+        me.data = [
+           ['layer2', 'layer2'],
+           ['layer2+3', 'layer2+3'], 
+           ['layer3+4', 'layer3+4']
+       ];
+       me.callParent();
+    }
+});
+
diff --git a/www/manager6/form/Boolean.js b/www/manager6/form/Boolean.js
new file mode 100644 (file)
index 0000000..1bcba95
--- /dev/null
@@ -0,0 +1,17 @@
+// boolean type including 'Default' (delete property from file)
+Ext.define('PVE.form.Boolean', {
+    extend: 'PVE.form.KVComboBox',
+    alias: ['widget.booleanfield'],
+  
+    initComponent: function() {
+       var me = this;
+
+       me.data = [
+           ['', gettext('Default')],
+           [1, gettext('Yes')],
+           [0, gettext('No')]
+       ];
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/form/BridgeSelector.js b/www/manager6/form/BridgeSelector.js
new file mode 100644 (file)
index 0000000..945a2d2
--- /dev/null
@@ -0,0 +1,71 @@
+Ext.define('PVE.form.BridgeSelector', {
+    extend: 'PVE.form.ComboGrid',
+    alias: ['widget.PVE.form.BridgeSelector'],
+
+    bridgeType: 'any_bridge', // bridge, OVSBridge or any_bridge
+
+    setNodename: function(nodename) {
+       var me = this;
+
+       if (!nodename || (me.nodename === nodename)) {
+           return;
+       }
+
+       me.nodename = nodename;
+
+       me.store.setProxy({
+           type: 'pve',
+           url: '/api2/json/nodes/' + me.nodename + '/network?type=' +
+               me.bridgeType
+       });
+
+       me.store.load();
+    },
+
+    initComponent: function() {
+       var me = this;
+
+       var nodename = me.nodename;
+       me.nodename = undefined; 
+
+       var store = Ext.create('Ext.data.Store', {
+           fields: [ 'iface', 'active', 'type' ],
+           filterOnLoad: true,
+           sorters: [
+               {
+                   property : 'iface',
+                   direction: 'ASC'
+               }
+           ]
+       });
+
+       Ext.apply(me, {
+           store: store,
+           valueField: 'iface',
+           displayField: 'iface',
+            listConfig: {
+               columns: [
+                   {
+                       header: gettext('Bridge'),
+                       dataIndex: 'iface',
+                       hideable: false,
+                       flex: 1
+                   },
+                   {
+                       header: gettext('Active'),  
+                       width: 60, 
+                       dataIndex: 'active', 
+                       renderer: PVE.Utils.format_boolean
+                   }
+               ]
+           }
+       });
+
+        me.callParent();
+
+       if (nodename) {
+           me.setNodename(nodename);
+       }
+    }
+});
+
diff --git a/www/manager6/form/BusTypeSelector.js b/www/manager6/form/BusTypeSelector.js
new file mode 100644 (file)
index 0000000..00f8281
--- /dev/null
@@ -0,0 +1,24 @@
+Ext.define('PVE.form.BusTypeSelector', {
+    extend: 'PVE.form.KVComboBox',
+    alias: ['widget.PVE.form.BusTypeSelector'],
+  
+    noVirtIO: false,
+
+    noScsi: false,
+
+    initComponent: function() {
+       var me = this;
+
+       me.data = [['ide', 'IDE'], ['sata', 'SATA']];
+
+       if (!me.noVirtIO) {
+           me.data.push(['virtio', 'VIRTIO']);
+       }
+
+       if (!me.noScsi) {
+           me.data.push(['scsi', 'SCSI']);
+       }
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/form/CPUModelSelector.js b/www/manager6/form/CPUModelSelector.js
new file mode 100644 (file)
index 0000000..901aab5
--- /dev/null
@@ -0,0 +1,40 @@
+Ext.define('PVE.form.CPUModelSelector', {
+    extend: 'PVE.form.KVComboBox',
+    alias: ['widget.CPUModelSelector'],
+  
+    initComponent: function() {
+       var me = this;
+
+        me.data = [ 
+           ['', PVE.Utils.defaultText + ' (kvm64)'],
+           ['486', '486'],
+           ['athlon', 'athlon'],
+           ['core2duo', 'core2duo'],
+           ['coreduo', 'coreduo'],
+           ['kvm32', 'kvm32'],
+           ['kvm64', 'kvm64'],
+           ['pentium', 'pentium'],
+           ['pentium2', 'pentium2'],
+           ['pentium3', 'pentium3'],
+           ['phenom', 'phenom'],
+           ['qemu32', 'qemu32'],
+           ['qemu64', 'qemu64'],
+           ['Conroe', 'Conroe'],
+           ['Penryn', 'Penryn'],
+           ['Nehalem', 'Nehalem'],
+           ['Westmere', 'Westmere'],
+           ['SandyBridge', 'SandyBridge'],
+           ['IvyBridge', 'IvyBridge'],
+           ['Haswell', 'Haswell'],
+           ['Broadwell', 'Broadwell'],
+           ['Opteron_G1', 'Opteron_G1'],
+           ['Opteron_G2', 'Opteron_G2'],
+           ['Opteron_G3', 'Opteron_G3'],
+           ['Opteron_G4', 'Opteron_G4'],
+           ['Opteron_G5', 'Opteron_G5'],
+           ['host', 'host']
+       ];
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/form/CacheTypeSelector.js b/www/manager6/form/CacheTypeSelector.js
new file mode 100644 (file)
index 0000000..3d96981
--- /dev/null
@@ -0,0 +1,19 @@
+Ext.define('PVE.form.CacheTypeSelector', {
+    extend: 'PVE.form.KVComboBox',
+    alias: ['widget.CacheTypeSelector'],
+  
+    initComponent: function() {
+       var me = this;
+
+       me.data = [
+           ['', PVE.Utils.defaultText + " (" + gettext('No cache') + ")"],
+           ['directsync', 'Direct sync'],
+           ['writethrough', 'Write through'],
+           ['writeback', 'Write back'],
+           ['unsafe', 'Write back (' + gettext('unsafe') + ')'],
+           ['none', gettext('No cache')]
+       ];
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/form/Checkbox.js b/www/manager6/form/Checkbox.js
new file mode 100644 (file)
index 0000000..3ce41b6
--- /dev/null
@@ -0,0 +1,46 @@
+Ext.define('PVE.form.Checkbox', {
+    extend: 'Ext.form.field.Checkbox',
+    alias: ['widget.pvecheckbox'],
+
+    defaultValue: undefined,
+
+    deleteDefaultValue: false,
+    deleteEmpty: false,
+    inputValue: '1',
+
+    height: 22, // hack: set same height as text fields
+
+    getSubmitData: function() {
+        var me = this,
+            data = null,
+            val;
+        if (!me.disabled && me.submitValue) {
+            val = me.getSubmitValue();
+            if (val !== null) {
+                data = {};
+               if ((val == me.defaultValue) && me.deleteDefaultValue) {
+                   data['delete'] = me.getName();
+               } else {
+                    data[me.getName()] = val;
+               }
+            } else if (me.deleteEmpty) {
+               data = {};
+               data['delete'] = me.getName();
+           }
+        }
+        return data;
+    },
+
+    // also accept integer 1 as true
+    setRawValue: function(value) {
+       var me = this;
+
+       if (value === 1) {
+            me.callParent([true]);
+       } else {
+            me.callParent([value]);
+       }
+    }
+
+});
\ No newline at end of file
diff --git a/www/manager6/form/ComboGrid.js b/www/manager6/form/ComboGrid.js
new file mode 100644 (file)
index 0000000..26a57b4
--- /dev/null
@@ -0,0 +1,139 @@
+Ext.define('PVE.form.ComboGrid', {
+    extend: 'Ext.form.field.ComboBox',
+    alias: ['widget.PVE.form.ComboGrid'],
+
+    // this value is used as default value after load()
+    preferredValue: undefined,
+
+    computeHeight: function() {
+       var me = this;
+       var lh = PVE.Utils.gridLineHeigh();
+       var count = me.store.getTotalCount();
+       return (count > 10) ? 10*lh : 26+count*lh;
+    },
+
+    // hack: allow to select empty value
+    // seems extjs does not allow that when 'editable == false'
+    onKeyUp: function(e, t) {
+        var me = this;
+        var key = e.getKey();
+
+        if (!me.editable && me.allowBlank && !me.multiSelect &&
+           (key == e.BACKSPACE || key == e.DELETE)) {
+           me.setValue('');
+       }
+
+        me.callParent(arguments);      
+    },
+
+    // copied from ComboBox 
+    createPicker: function() {
+        var me = this,
+        picker,
+        menuCls = Ext.baseCSSPrefix + 'menu',
+
+        opts = Ext.apply({
+            selModel: {
+                mode: me.multiSelect ? 'SIMPLE' : 'SINGLE'
+            },
+            floating: true,
+            hidden: true,
+            ownerCt: me.ownerCt,
+            cls: me.el.up('.' + menuCls) ? menuCls : '',
+            store: me.store,
+            displayField: me.displayField,
+            focusOnToFront: false,
+           height: me.computeHeight(),
+            pageSize: me.pageSize
+        }, me.listConfig, me.defaultListConfig);
+
+       // NOTE: we simply use a grid panel
+        //picker = me.picker = Ext.create('Ext.view.BoundList', opts);
+       picker = me.picker = Ext.create('Ext.grid.Panel', opts);
+
+       // pass getNode() to the view
+       picker.getNode = function() {
+           picker.getView().getNode(arguments);
+       };
+
+        me.mon(picker, {
+            itemclick: me.onItemClick,
+            refresh: me.onListRefresh,
+           show: function() {
+               picker.setHeight(me.computeHeight());
+               me.syncSelection();
+           },
+            scope: me
+        });
+
+        me.mon(picker.getSelectionModel(), 'selectionchange', me.onListSelectionChange, me);
+
+        return picker;
+    },
+
+    initComponent: function() {
+       var me = this;
+
+       if (me.initialConfig.editable === undefined) {
+           me.editable = false;
+       }
+
+       Ext.apply(me, {
+           queryMode: 'local',
+           matchFieldWidth: false
+       });
+
+       Ext.applyIf(me, { value: ''}); // hack: avoid ExtJS validate() bug
+
+       Ext.applyIf(me.listConfig, { width: 400 });
+
+        me.callParent();
+
+       me.store.on('beforeload', function() {   
+           if (!me.isDisabled()) {
+               me.setDisabled(true);
+               me.enableAfterLoad = true;
+           }
+       });
+
+       // hack: autoSelect does not work
+       me.store.on('load', function(store, r, success, o) {
+           if (success) {
+               me.clearInvalid();
+               
+               if (me.enableAfterLoad) {
+                   delete me.enableAfterLoad;
+                   me.setDisabled(false);
+               }
+
+               var def = me.getValue() || me.preferredValue;
+               if (def) {
+                   me.setValue(def, true); // sync with grid
+               }
+               var found = false;
+               if (def) {
+                   if (Ext.isArray(def)) {
+                       Ext.Array.each(def, function(v) {
+                           if (store.findRecord(me.valueField, v)) {
+                               found = true;
+                               return false; // break
+                           }
+                       });
+                   } else {
+                       found = store.findRecord(me.valueField, def);
+                   }
+               }
+
+               if (!found) {
+                   var rec = me.store.first();
+                   if (me.autoSelect && rec && rec.data) {
+                       def = rec.data[me.valueField];
+                       me.setValue(def, true);
+                   } else {
+                       me.setValue(me.editable ? def : '', true);
+                   }
+               }
+           }
+       });
+    }
+});
diff --git a/www/manager6/form/CompressionSelector.js b/www/manager6/form/CompressionSelector.js
new file mode 100644 (file)
index 0000000..0c96eab
--- /dev/null
@@ -0,0 +1,9 @@
+Ext.define('PVE.form.CompressionSelector', {
+    extend: 'PVE.form.KVComboBox',
+    alias: ['widget.pveCompressionSelector'],
+    comboItems: [
+                ['', PVE.Utils.noneText],
+                ['lzo', 'LZO (' + gettext('fast') + ')'],
+                ['gzip', 'GZIP (' + gettext('good') + ')']
+    ]
+});
diff --git a/www/manager6/form/ContentTypeSelector.js b/www/manager6/form/ContentTypeSelector.js
new file mode 100644 (file)
index 0000000..0c74524
--- /dev/null
@@ -0,0 +1,22 @@
+Ext.define('PVE.form.ContentTypeSelector', {
+    extend: 'PVE.form.KVComboBox',
+    alias: ['widget.pveContentTypeSelector'],
+  
+    cts: undefined,
+
+    initComponent: function() {
+       var me = this;
+
+       me.data = [];
+
+       if (me.cts === undefined) {
+           me.cts = ['images', 'iso', 'vztmpl', 'backup', 'rootdir'];
+       }
+
+       Ext.Array.each(me.cts, function(ct) {
+           me.data.push([ct, PVE.Utils.format_content_types(ct)]);
+       });
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/form/ControllerSelector.js b/www/manager6/form/ControllerSelector.js
new file mode 100644 (file)
index 0000000..dfff96b
--- /dev/null
@@ -0,0 +1,111 @@
+Ext.define('PVE.form.ControllerSelector', {
+    extend: 'Ext.form.FieldContainer',
+    alias: ['widget.PVE.form.ControllerSelector'],
+   
+    statics: {
+       maxIds: {
+           ide: 3,
+           sata: 5,
+           virtio: 15,
+           scsi: 13
+       }
+    },
+
+    noVirtIO: false,
+
+    noScsi: false,
+
+    vmconfig: {}, // used to check for existing devices
+
+    setVMConfig: function(vmconfig, autoSelect) {
+       var me = this;
+
+       me.vmconfig = Ext.apply({}, vmconfig);
+       if (autoSelect) {
+           var clist = ['ide', 'virtio', 'scsi', 'sata'];
+           if (autoSelect === 'cdrom') {
+               clist = ['ide', 'scsi', 'sata'];
+               if (!Ext.isDefined(me.vmconfig.ide2)) {
+                   me.down('field[name=controller]').setValue('ide');
+                   me.down('field[name=deviceid]').setValue(2);
+                   return;
+               }
+           } else if (me.vmconfig.ostype === 'l26') {
+               clist = ['virtio', 'ide', 'scsi', 'sata'];
+           }
+
+           Ext.Array.each(clist, function(controller) {
+               var confid, i;
+               if ((controller === 'virtio' && me.noVirtIO) ||
+                   (controller === 'scsi' && me.noScsi)) {
+                   return; //continue
+               }
+               me.down('field[name=controller]').setValue(controller);
+               for (i = 0; i <= PVE.form.ControllerSelector.maxIds[controller]; i++) {
+                   confid = controller + i.toString();
+                   if (!Ext.isDefined(me.vmconfig[confid])) {
+                       me.down('field[name=deviceid]').setValue(i);
+                       return false; // break
+                   }
+               }
+           });
+       }
+       me.down('field[name=deviceid]').validate();
+    },
+
+    initComponent: function() {
+       var me = this;
+
+       Ext.apply(me, {
+           fieldLabel: gettext('Bus/Device'),
+           layout: 'hbox',
+           height: 22, // hack: set to same height as other fields
+           defaults: {
+                flex: 1,
+                hideLabel: true
+           },
+           items: [
+               {
+                   xtype: 'PVE.form.BusTypeSelector',
+                   name: 'controller',
+                   value: 'ide',
+                   noVirtIO: me.noVirtIO,
+                   noScsi: me.noScsi,
+                   allowBlank: false,
+                   listeners: {
+                       change: function(t, value) {
+                           if (!me.rendered || !value) {
+                               return;
+                           }
+                           var field = me.down('field[name=deviceid]');
+                           field.setMaxValue(PVE.form.ControllerSelector.maxIds[value]);
+                           field.validate();
+                       }
+                   }
+               },
+               {
+                   xtype: 'numberfield',
+                   name: 'deviceid',
+                   minValue: 0,
+                   maxValue: PVE.form.ControllerSelector.maxIds.ide,
+                   value: '0',
+                   validator: function(value) {
+                       /*jslint confusion: true */
+                       if (!me.rendered) {
+                           return;
+                       }
+                       var field = me.down('field[name=controller]');
+                       var controller = field.getValue();
+                       var confid = controller + value;
+                       if (Ext.isDefined(me.vmconfig[confid])) {
+                           return "This device is already in use.";
+                       }
+                       return true;
+                   }
+               }
+           ]
+       });
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/form/DayOfWeekSelector.js b/www/manager6/form/DayOfWeekSelector.js
new file mode 100644 (file)
index 0000000..4fbc180
--- /dev/null
@@ -0,0 +1,13 @@
+Ext.define('PVE.form.DayOfWeekSelector', {
+    extend: 'PVE.form.KVComboBox',
+    alias: ['widget.pveDayOfWeekSelector'],
+    comboItems: [
+           ['sun', Ext.util.Format.htmlDecode(Ext.Date.dayNames[0])],
+           ['mon', Ext.util.Format.htmlDecode(Ext.Date.dayNames[1])],
+           ['tue', Ext.util.Format.htmlDecode(Ext.Date.dayNames[2])],
+           ['wed', Ext.util.Format.htmlDecode(Ext.Date.dayNames[3])],
+           ['thu', Ext.util.Format.htmlDecode(Ext.Date.dayNames[4])],
+           ['fri', Ext.util.Format.htmlDecode(Ext.Date.dayNames[5])],
+           ['sat', Ext.util.Format.htmlDecode(Ext.Date.dayNames[6])]
+       ]
+});
diff --git a/www/manager6/form/DiskFormatSelector.js b/www/manager6/form/DiskFormatSelector.js
new file mode 100644 (file)
index 0000000..30de6ec
--- /dev/null
@@ -0,0 +1,16 @@
+Ext.define('PVE.form.DiskFormatSelector', {
+    extend: 'PVE.form.KVComboBox',
+    alias: ['widget.PVE.form.DiskFormatSelector'],
+  
+    initComponent: function() {
+       var me = this;
+
+        me.data = [ 
+           ['raw', gettext('Raw disk image') + ' (raw)'], 
+           ['qcow2', gettext('QEMU image format') + ' (qcow2)'],
+           ['vmdk', gettext('VMware image format') + ' (vmdk)']
+       ];
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/form/DisplaySelector.js b/www/manager6/form/DisplaySelector.js
new file mode 100644 (file)
index 0000000..755d059
--- /dev/null
@@ -0,0 +1,11 @@
+Ext.define('PVE.form.DisplaySelector', {
+    extend: 'PVE.form.KVComboBox',
+    alias: ['widget.DisplaySelector'],
+  
+    initComponent: function() {
+       var me = this;
+
+       me.data = PVE.Utils.kvm_vga_driver_array();
+       me.callParent();
+    }
+});
diff --git a/www/manager6/form/EmailNotificationSelector.js b/www/manager6/form/EmailNotificationSelector.js
new file mode 100644 (file)
index 0000000..36e35c5
--- /dev/null
@@ -0,0 +1,8 @@
+Ext.define('PVE.form.EmailNotificationSelector', {
+    extend: 'PVE.form.KVComboBox',
+    alias: ['widget.pveEmailNotificationSelector'],
+    comboItems: [
+                ['always', gettext('Always')],
+                ['failure', gettext('On failure only')]
+    ]
+});
diff --git a/www/manager6/form/FileSelector.js b/www/manager6/form/FileSelector.js
new file mode 100644 (file)
index 0000000..50f9442
--- /dev/null
@@ -0,0 +1,76 @@
+Ext.define('PVE.form.FileSelector', {
+    extend: 'PVE.form.ComboGrid',
+    alias: ['widget.pveFileSelector'],
+
+    setStorage: function(storage, nodename) {
+       var me = this;
+
+       var change = false;
+       if (storage && (me.storage !== storage)) {
+           me.storage = storage;
+           change = true;
+       }
+
+       if (nodename && (me.nodename !== nodename)) {
+           me.nodename = nodename;
+           change = true;
+       }
+
+       if (!(me.storage && me.nodename && change)) {
+           return;
+       }
+
+       var url = '/api2/json/nodes/' + me.nodename + '/storage/' + me.storage + '/content';
+       if (me.storageContent) {
+           url += '?content=' + me.storageContent;
+       }
+
+       me.store.setProxy({
+           type: 'pve',
+           url: url
+       });
+
+       me.store.load();
+    },
+
+    initComponent: function() {
+       var me = this;
+
+       var store = Ext.create('Ext.data.Store', {
+           model: 'pve-storage-content'
+       });
+
+       Ext.apply(me, {
+           store: store,
+           allowBlank: false,
+           autoSelect: false,
+           valueField: 'volid',
+           displayField: 'text',
+            listConfig: {
+               columns: [
+                   {
+                       header: gettext('Name'),
+                       dataIndex: 'text',
+                       hideable: false,
+                       flex: 1
+                   },
+                   {
+                       header: gettext('Format'),
+                       width: 60, 
+                       dataIndex: 'format'
+                   },
+                   {
+                       header: gettext('Size'),
+                       width: 60, 
+                       dataIndex: 'size', 
+                       renderer: PVE.Utils.format_size 
+                   }
+               ]
+           }
+       });
+
+        me.callParent();
+
+       me.setStorage(me.storage, me.nodename);
+    }
+});
diff --git a/www/manager6/form/FirewallPolicySelector.js b/www/manager6/form/FirewallPolicySelector.js
new file mode 100644 (file)
index 0000000..81492a6
--- /dev/null
@@ -0,0 +1,16 @@
+Ext.define('PVE.form.FirewallPolicySelector', {
+    extend: 'PVE.form.KVComboBox',
+    alias: ['widget.pveFirewallPolicySelector'],
+  
+    initComponent: function() {
+       var me = this;
+
+       me.data = [ 
+           ['ACCEPT', 'ACCEPT'], 
+           ['REJECT', 'REJECT'],
+           [ 'DROP', 'DROP']
+       ];
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/form/GroupSelector.js b/www/manager6/form/GroupSelector.js
new file mode 100644 (file)
index 0000000..f4e4b63
--- /dev/null
@@ -0,0 +1,55 @@
+Ext.define('PVE.form.GroupSelector', {
+    extend: 'PVE.form.ComboGrid',
+    alias: ['widget.pveGroupSelector'],
+
+    allowBlank: false,
+
+    initComponent: function() {
+       var me = this;
+
+       var store = new Ext.data.Store({
+           model: 'pve-groups'
+       });
+
+       Ext.apply(me, {
+           store: store,
+           autoSelect: false,
+           valueField: 'groupid',
+           displayField: 'groupid',
+            listConfig: {
+               columns: [
+                   {
+                       header: gettext('Group'),
+                       sortable: true,
+                       dataIndex: 'groupid',
+                       flex: 1
+                   },
+                   {
+                       id: 'comment',
+                       header: gettext('Comment'),
+                       sortable: false,
+                       dataIndex: 'comment',
+                       flex: 1
+                   }
+               ]
+           }
+       });
+
+        me.callParent();
+
+       store.load();
+    }
+
+}, function() {
+
+    Ext.define('pve-groups', {
+       extend: 'Ext.data.Model',
+       fields: [ 'groupid', 'comment' ],
+       proxy: {
+            type: 'pve',
+           url: "/api2/json/access/groups"
+       },
+       idProperty: 'groupid'
+    });
+
+});
diff --git a/www/manager6/form/HotplugFeatureSelector.js b/www/manager6/form/HotplugFeatureSelector.js
new file mode 100644 (file)
index 0000000..e0dac4b
--- /dev/null
@@ -0,0 +1,57 @@
+Ext.define('PVE.form.HotplugFeatureSelector', {
+    extend: 'PVE.form.KVComboBox',
+    alias: ['widget.pveHotplugFeatureSelector'],
+
+    multiSelect: true,
+    allowBlank: true,
+    deleteEmpty: false,
+
+    setValue: function(value, doSelect) {
+       var me = this;
+
+       if (me.multiSelect && Ext.isString(value)) {
+           if (value === '0') {
+               value = [];
+           } else if (value === '1') {
+               value = ['disk', 'network', 'usb'];
+           } else {
+               value = value.split(',');
+           }
+       }
+
+       me.callParent([value, doSelect]);
+    },
+
+    getSubmitData: function() {
+        var me = this,
+            data = null,
+            val;
+        if (!me.disabled && me.submitValue) {
+            val = me.getSubmitValue();
+           if (Ext.isArray(val)) {
+               val = val.join(',') || '0';
+           }
+            if (val !== null && val !== '') {
+                data = {};
+                data[me.getName()] = val;
+            } else if (me.deleteEmpty) {
+               data = {};
+                data['delete'] = me.getName();
+           }
+        }
+        return data;
+    },
+
+  
+    initComponent: function() {
+       var me = this;
+
+       me.data = [['disk', gettext('Disk')], 
+                  ['network',  gettext('Network')], 
+                  ['usb',  gettext('USB')],
+                  ['memory',  gettext('Memory')],
+                  ['cpu',  gettext('CPU')]];
+       
+       me.callParent();
+    }
+});
diff --git a/www/manager6/form/IPProtocolSelector.js b/www/manager6/form/IPProtocolSelector.js
new file mode 100644 (file)
index 0000000..55a95d9
--- /dev/null
@@ -0,0 +1,98 @@
+Ext.define('PVE.form.IPProtocolSelector', {
+    extend: 'PVE.form.ComboGrid',
+    alias: ['widget.pveIPProtocolSelector'],
+
+    initComponent: function() {
+       var me = this;
+       
+       var store = Ext.create('Ext.data.Store', {
+           fields: [ 'p', 'd', 'n'],
+           data: [
+               { p: 'tcp', n: 6, d: 'Transmission Control Protocol' },
+               { p: 'udp', n: 17, d: 'User Datagram Protocol' },
+               { p: 'icmp', n: 1, d: 'Internet Control Message Protocol' },
+               { p: 'igmp', n: 2,  d: 'Internet Group Management' },
+               { p: 'ggp', n: 3, d: 'gateway-gateway protocol' },
+               { p: 'ipencap', n: 4, d: 'IP encapsulated in IP' },
+               { p: 'st', n: 5, d: 'ST datagram mode' },
+               { p: 'egp', n: 8, d: 'exterior gateway protocol' },
+               { p: 'igp', n: 9, d: 'any private interior gateway (Cisco)' },
+               { p: 'pup', n: 12, d: 'PARC universal packet protocol' },
+               { p: 'hmp', n: 20, d: 'host monitoring protocol' },
+               { p: 'xns-idp', n: 22, d: 'Xerox NS IDP' },
+               { p: 'rdp', n: 27, d: '"reliable datagram" protocol' },
+               { p: 'iso-tp4', n: 29, d: 'ISO Transport Protocol class 4 [RFC905]' },
+               { p: 'dccp', n: 33, d: 'Datagram Congestion Control Prot. [RFC4340]' },
+               { p: 'xtp', n: 36, d: 'Xpress Transfer Protocol' },
+               { p: 'ddp', n: 37, d: 'Datagram Delivery Protocol' },
+               { p: 'idpr-cmtp', n: 38, d: 'IDPR Control Message Transport' },
+               { p: 'ipv6', n: 41, d: 'Internet Protocol, version 6' },
+               { p: 'ipv6-route', n: 43, d: 'Routing Header for IPv6' },
+               { p: 'ipv6-frag', n: 44, d: 'Fragment Header for IPv6' },
+               { p: 'idrp', n: 45, d: 'Inter-Domain Routing Protocol' },
+               { p: 'rsvp', n: 46, d: 'Reservation Protocol' },
+               { p: 'gre', n: 47, d: 'General Routing Encapsulation' },
+               { p: 'esp', n: 50, d: 'Encap Security Payload [RFC2406]' },
+               { p: 'ah', n: 51, d: 'Authentication Header [RFC2402]' },
+               { p: 'skip', n: 57, d: 'SKIP' },
+               { p: 'ipv6-icmp', n: 58, d: 'ICMP for IPv6' },
+               { p: 'ipv6-nonxt', n: 59, d: 'No Next Header for IPv6' },
+               { p: 'ipv6-opts', n: 60, d: 'Destination Options for IPv6' },
+               { p: 'vmtp', n: 81, d: 'Versatile Message Transport' },
+               { p: 'eigrp', n: 88, d: 'Enhanced Interior Routing Protocol (Cisco)' },
+               { p: 'ospf', n: 89, d: 'Open Shortest Path First IGP' },
+               { p: 'ax.25', n: 93, d: 'AX.25 frames' },
+               { p: 'ipip', n: 94, d: 'IP-within-IP Encapsulation Protocol' },
+               { p: 'etherip', n: 97, d: 'Ethernet-within-IP Encapsulation [RFC3378]' },
+               { p: 'encap', n: 98, d: 'Yet Another IP encapsulation [RFC1241]' },
+               { p: 'pim', n: 103, d: 'Protocol Independent Multicast' },
+               { p: 'ipcomp', n: 108, d: 'IP Payload Compression Protocol' },
+               { p: 'vrrp', n: 112, d: 'Virtual Router Redundancy Protocol [RFC5798]' },
+               { p: 'l2tp', n: 115, d: 'Layer Two Tunneling Protocol [RFC2661]' },
+               { p: 'isis', n: 124, d: 'IS-IS over IPv4' },
+               { p: 'sctp', n: 132, d: 'Stream Control Transmission Protocol' },
+               { p: 'fc', n: 133, d: 'Fibre Channel' },
+               { p: 'mobility-header', n: 135, d: 'Mobility Support for IPv6 [RFC3775]' },
+               { p: 'udplite', n: 136, d: 'UDP-Lite [RFC3828]' },
+               { p: 'mpls-in-ip', n: 137, d: 'MPLS-in-IP [RFC4023]' },
+               { p: 'hip', n: 139, d: 'Host Identity Protocol' },
+               { p: 'shim6', n: 140, d: 'Shim6 Protocol [RFC5533]' },
+               { p: 'wesp', n: 141, d: 'Wrapped Encapsulating Security Payload' },
+               { p: 'rohc', n: 142, d: 'Robust Header Compression' }
+           ]
+       });
+
+       Ext.apply(me, {
+           store: store,
+           valueField: 'p',
+           displayField: 'p',
+            listConfig: {
+               columns: [
+                   {
+                       header: gettext('Protocol'),
+                       dataIndex: 'p',
+                       hideable: false,
+                       sortable: false,
+                       width: 100
+                   },
+                   {
+                       header: gettext('Number'),
+                       dataIndex: 'n',
+                       hideable: false,
+                       sortable: false,
+                       width: 50
+                   },
+                   {
+                       header: gettext('Description'),
+                       dataIndex: 'd',
+                       hideable: false,
+                       sortable: false,
+                       flex: 1
+                   }
+               ]
+           }
+       });
+
+        me.callParent();
+    }
+});
diff --git a/www/manager6/form/IPRefSelector.js b/www/manager6/form/IPRefSelector.js
new file mode 100644 (file)
index 0000000..a017e15
--- /dev/null
@@ -0,0 +1,83 @@
+Ext.define('PVE.form.IPRefSelector', {
+    extend: 'PVE.form.ComboGrid',
+    alias: ['widget.pveIPRefSelector'],
+
+    base_url: undefined,
+
+    preferredValue: '', // hack: else Form sets dirty flag?
+
+    ref_type: undefined, // undefined = any [undefined, 'ipset' or 'alias']
+
+    initComponent: function() {
+       var me = this;
+
+       if (!me.base_url) {
+           throw "no base_url specified";
+       }
+
+       var url = "/api2/json" + me.base_url;
+       if (me.ref_type) {
+           url += "?type=" + me.ref_type;
+       }
+
+       var store = Ext.create('Ext.data.Store', {
+           autoLoad: true,
+           fields: [ 'type', 'name', 'ref', 'comment' ],
+           idProperty: 'ref',
+           proxy: {
+               type: 'pve',
+               url: url
+           },
+           sorters: {
+               property: 'ref',
+               order: 'DESC'
+           }
+       });
+
+       var disable_query_for_ips = function(f, value) {
+           if (value === null || 
+               value.match(/^\d/)) { // IP address starts with \d
+               f.queryDelay = 9999999999; // hack: disbale with long delay
+           } else {
+               f.queryDelay = 10;
+           }
+       };
+
+       var columns = [];
+
+       if (!me.ref_type) {
+           columns.push({
+               header: gettext('Type'),
+               dataIndex: 'type',
+               hideable: false,
+               width: 60
+           });
+       }
+
+       columns.push([
+           {
+               header: gettext('Name'),
+               dataIndex: 'ref',
+               hideable: false,
+               width: 140
+           },
+           {
+               header: gettext('Comment'),  
+               dataIndex: 'comment', 
+               flex: 1
+           }
+       ]);
+
+       Ext.apply(me, {
+           store: store,
+           valueField: 'ref',
+           displayField: 'ref',
+            listConfig: { columns: columns }
+       });
+
+       me.on('change', disable_query_for_ips);
+
+        me.callParent();
+    }
+});
+
diff --git a/www/manager6/form/KVComboBox.js b/www/manager6/form/KVComboBox.js
new file mode 100644 (file)
index 0000000..5247c86
--- /dev/null
@@ -0,0 +1,52 @@
+/* Key-Value ComboBox
+ *
+ * config properties:
+ * comboItems: an array of Key - Value pairs
+ * deleteEmpty: if set to true (default), an empty value received from the
+ * comboBox will reset the property to its default value
+ */
+Ext.define('PVE.form.KVComboBox', {
+    extend: 'Ext.form.field.ComboBox',
+    alias: 'widget.pveKVComboBox',
+
+    deleteEmpty: true,
+    comboItems: undefined,
+
+    getSubmitData: function() {
+        var me = this,
+            data = null,
+            val;
+        if (!me.disabled && me.submitValue) {
+            val = me.getSubmitValue();
+            if (val !== null && val !== '') {
+                data = {};
+                data[me.getName()] = val;
+            } else if (me.deleteEmpty) {
+                data = {};
+                data['delete'] = me.getName();
+            }
+        }
+        return data;
+    },
+
+    initComponent: function() {
+       var me = this;
+
+       me.store = Ext.create('Ext.data.ArrayStore', {
+           model: 'KeyValue',
+           data : me.comboItems,
+       });
+
+       if (me.initialConfig.editable === undefined) {
+           me.editable = false;
+       }
+
+       Ext.apply(me, {
+           displayField: 'value',
+           valueField: 'key',
+           queryMode: 'local'
+       });
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/form/LanguageSelector.js b/www/manager6/form/LanguageSelector.js
new file mode 100644 (file)
index 0000000..5e30ee6
--- /dev/null
@@ -0,0 +1,5 @@
+Ext.define('PVE.form.LanguageSelector', {
+    extend: 'PVE.form.KVComboBox',
+    alias: ['widget.pveLanguageSelector'],
+    comboItems: PVE.Utils.language_array()
+});
diff --git a/www/manager6/form/MemoryField.js b/www/manager6/form/MemoryField.js
new file mode 100644 (file)
index 0000000..1d8bdb2
--- /dev/null
@@ -0,0 +1,83 @@
+Ext.define('PVE.form.MemoryField', {
+    extend: 'Ext.form.field.Number',
+    alias: 'widget.pveMemoryField',
+
+    allowBlank: false,
+
+    hotplug: false,
+
+    minValue: 32,
+
+    maxValue: 4178944,
+
+    step: 32,
+
+    value: '512', // qm default
+
+    computeUpDown: function(value) {
+       var me = this;
+
+       if (!me.hotplug) {
+           return { up: value + me.step, down: value - me.step };
+       }
+       
+       var dimm_size = 512;
+       var prev_dimm_size = 0;
+       var min_size = 1024;
+       var current_size = min_size;
+       var value_up = min_size;
+       var value_down = min_size;
+       var value_start = min_size;
+
+       var i, j;
+       for (j = 0; j < 9; j++) {
+           for (i = 0; i < 32; i++) {
+               if ((value >= current_size) && (value < (current_size + dimm_size))) {
+                   value_start = current_size,
+                   value_up = current_size + dimm_size;
+                   value_down = current_size - ((i === 0) ? prev_dimm_size : dimm_size);
+               }
+               current_size += dimm_size;                              
+           }
+           prev_dimm_size = dimm_size;
+           dimm_size = dimm_size*2;
+       }
+
+       return { up: value_up, down: value_down, start: value_start };
+    },
+
+    onSpinUp: function() {
+       var me = this;
+       if (!me.readOnly) {
+           var res = me.computeUpDown(me.getValue());
+           me.setValue(Ext.Number.constrain(res.up, me.minValue, me.maxValue));
+       }
+    },
+
+    onSpinDown: function() {
+       var me = this;
+       if (!me.readOnly) {
+           var res = me.computeUpDown(me.getValue());
+           me.setValue(Ext.Number.constrain(res.down, me.minValue, me.maxValue));
+       }
+    },
+
+    initComponent: function() {
+        var me = this;
+
+       if (me.hotplug) {
+           me.minValue = 1024;
+
+           me.on('blur', function(field) {
+               value = me.getValue();
+               var res = me.computeUpDown(value);
+               if (value === res.start || value === res.up || value === res.down) {
+                   return;
+               }
+               field.setValue(res.up);
+           });
+       }
+
+        me.callParent();
+    }
+});
diff --git a/www/manager6/form/NetworkCardSelector.js b/www/manager6/form/NetworkCardSelector.js
new file mode 100644 (file)
index 0000000..6e5ef93
--- /dev/null
@@ -0,0 +1,17 @@
+Ext.define('PVE.form.NetworkCardSelector', {
+    extend: 'PVE.form.KVComboBox',
+    alias: ['widget.PVE.form.NetworkCardSelector'],
+  
+    initComponent: function() {
+       var me = this;
+
+        me.data = [ 
+           ['e1000', 'Intel E1000'],
+           ['virtio', 'VirtIO (' + gettext('paravirtualized') + ')'],
+           ['rtl8139', 'Realtek RTL8139'],
+           ['vmxnet3', 'VMWare vmxnet3']
+       ];
+       me.callParent();
+    }
+});
diff --git a/www/manager6/form/NodeSelector.js b/www/manager6/form/NodeSelector.js
new file mode 100644 (file)
index 0000000..4a6a788
--- /dev/null
@@ -0,0 +1,99 @@
+Ext.define('PVE.form.NodeSelector', {
+    extend: 'PVE.form.ComboGrid',
+    alias: ['widget.PVE.form.NodeSelector'],
+
+    // invalidate nodes which are offline
+    onlineValidator: false,
+
+    selectCurNode: false,
+
+    // only allow those nodes (array)
+    allowedNodes: undefined,
+
+    initComponent: function() {
+       var me = this;
+
+       var store = Ext.create('Ext.data.Store', {
+           fields: [ 'node', 'cpu', 'maxcpu', 'mem', 'maxmem', 'uptime' ],
+           autoLoad: true,
+           proxy: {
+               type: 'pve',
+               url: '/api2/json/nodes'
+           },
+           sorters: [
+               {
+                   property : 'node',
+                   direction: 'ASC'
+               },
+               {
+                   property : 'mem',
+                   direction: 'DESC'
+               }
+           ]
+       });
+
+       Ext.apply(me, {
+           store: store,
+           valueField: 'node',
+           displayField: 'node',
+            listConfig: {
+               columns: [
+                   {
+                       header: gettext('Node'),
+                       dataIndex: 'node',
+                       sortable: true,
+                       hideable: false,
+                       flex: 1
+                   },
+                   {
+                       header: gettext('Memory usage'),                        
+                       renderer: PVE.Utils.render_mem_usage,
+                       sortable: true,
+                       width: 100,
+                       dataIndex: 'mem'
+                   },
+                   {
+                       header: gettext('CPU usage'),
+                       renderer: PVE.Utils.render_cpu,
+                       sortable: true,
+                       width: 100,
+                       dataIndex: 'cpu'
+                   }
+               ]
+           },
+           validator: function(value) {
+               /*jslint confusion: true */
+               if (!me.onlineValidator || (me.allowBlank && !value)) {
+                   return true;
+               }
+               
+               var offline = [];
+               var notAllowed = [];
+
+               Ext.Array.each(value.split(/\s*,\s*/), function(node) {
+                   var rec = me.store.findRecord(me.valueField, node);
+                   if (!(rec && rec.data) || !Ext.isNumeric(rec.data.mem)) {
+                       offline.push(node);
+                   } else if (me.allowedNodes && !Ext.Array.contains(me.allowedNodes, node)) {
+                       notAllowed.push(node);
+                   }
+               });
+
+               if (notAllowed.length !== 0) {
+                   return "Node " + notAllowed.join(', ') + " is not allowed for this action!";
+               } 
+
+               if (offline.length !== 0) {
+                   return "Node " + offline.join(', ') + " seems to be offline!";
+               }
+               return true;
+           }
+       });
+
+        if (me.selectCurNode && PVE.curSelectedNode.data.node) {
+            me.preferredValue = PVE.curSelectedNode.data.node;
+        }
+
+        me.callParent();
+    }
+});
diff --git a/www/manager6/form/PoolSelector.js b/www/manager6/form/PoolSelector.js
new file mode 100644 (file)
index 0000000..a607589
--- /dev/null
@@ -0,0 +1,55 @@
+Ext.define('PVE.form.PoolSelector', {
+    extend: 'PVE.form.ComboGrid',
+    alias: ['widget.pvePoolSelector'],
+
+    allowBlank: false,
+
+    initComponent: function() {
+       var me = this;
+
+       var store = new Ext.data.Store({
+           model: 'pve-pools'
+       });
+
+       Ext.apply(me, {
+           store: store,
+           autoSelect: false,
+           valueField: 'poolid',
+           displayField: 'poolid',
+            listConfig: {
+               columns: [
+                   {
+                       header: gettext('Pool'),
+                       sortable: true,
+                       dataIndex: 'poolid',
+                       flex: 1
+                   },
+                   {
+                       id: 'comment',
+                       header: gettext('Comment'),
+                       sortable: false,
+                       dataIndex: 'comment',
+                       flex: 1
+                   }
+               ]
+           }
+       });
+
+        me.callParent();
+
+       store.load();
+    }
+
+}, function() {
+
+    Ext.define('pve-pools', {
+       extend: 'Ext.data.Model',
+       fields: [ 'poolid', 'comment' ],
+       proxy: {
+            type: 'pve',
+           url: "/api2/json/pools"
+       },
+       idProperty: 'poolid'
+    });
+
+});
diff --git a/www/manager6/form/RRDTypeSelector.js b/www/manager6/form/RRDTypeSelector.js
new file mode 100644 (file)
index 0000000..973a64a
--- /dev/null
@@ -0,0 +1,65 @@
+Ext.define('PVE.form.RRDTypeSelector', {
+    extend: 'Ext.form.field.ComboBox',
+    alias: ['widget.pveRRDTypeSelector'],
+  
+    initComponent: function() {
+        var me = this;
+       
+       var store = new Ext.data.ArrayStore({
+            fields: [ 'id', 'timeframe', 'cf', 'text' ],
+            data : [
+               [ 'hour', 'hour', 'AVERAGE', "Hour (average)" ],
+               [ 'hourmax', 'hour', 'MAX', "Hour (max)" ],
+               [ 'day', 'day', 'AVERAGE', "Day (average)" ],
+               [ 'daymax', 'day', 'MAX', "Day (max)" ],
+               [ 'week', 'week', 'AVERAGE', "Week (average)" ],
+               [ 'weekmax', 'week', 'MAX', "Week (max)" ],
+               [ 'month', 'month', 'AVERAGE', "Month (average)" ],
+               [ 'monthmax', 'month', 'MAX', "Month (max)" ],
+               [ 'year', 'year', 'AVERAGE', "Year (average)" ],
+               [ 'yearmax', 'year', 'MAX', "Year (max)" ]
+           ]
+       });
+
+       Ext.apply(me, {
+            store: store,
+            displayField: 'text',
+           valueField: 'id',
+           editable: false,
+            queryMode: 'local',
+           value: 'hour',
+           getState: function() {
+               var ind = store.findExact('id', me.getValue());
+               var rec = store.getAt(ind);
+               if (!rec) {
+                   return;
+               }
+               return { 
+                   id: rec.data.id,
+                   timeframe: rec.data.timeframe,
+                   cf: rec.data.cf
+               };
+           },
+           applyState : function(state) {
+               if (state && state.id) {
+                   me.setValue(state.id);
+               }
+           },
+           stateEvents: [ 'select' ],
+           stateful: true,
+           id: 'pveRRDTypeSelection'        
+       });
+
+       me.callParent();
+
+       var statechange = function(sp, key, value) {
+           if (key === me.id) {
+               me.applyState(value);
+           }
+       };
+
+       var sp = Ext.state.Manager.getProvider();
+       me.mon(sp, 'statechange', statechange, me);
+    }
+});
+
diff --git a/www/manager6/form/RealmComboBox.js b/www/manager6/form/RealmComboBox.js
new file mode 100644 (file)
index 0000000..34b417d
--- /dev/null
@@ -0,0 +1,68 @@
+Ext.define('PVE.form.RealmComboBox', {
+    extend: 'Ext.form.field.ComboBox',
+    alias: ['widget.pveRealmComboBox'],
+
+    needOTP: function(realm) {
+       var me = this;
+
+       var rec = me.store.findRecord('realm', realm);
+
+       return rec && rec.data && rec.data.tfa ? rec.data.tfa : undefined;
+    },
+
+    initComponent: function() {
+       var me = this;
+
+       var stateid = 'pveloginrealm';
+
+       var realmstore = Ext.create('Ext.data.Store', {
+           model: 'pve-domains',
+       });
+
+       Ext.apply(me, {
+           fieldLabel: gettext('Realm'),
+           name: 'realm',
+           store: realmstore,
+           queryMode: 'local',
+           allowBlank: false,
+           forceSelection: true,
+           autoSelect: false,
+           triggerAction: 'all',
+           valueField: 'realm',
+           displayField: 'descr',
+           getState: function() {
+               return { value: this.getValue() };
+           },
+           applyState : function(state) {
+               if (state && state.value) {
+                   this.setValue(state.value);
+               }
+           },
+           stateEvents: [ 'select' ],
+           stateful: true,
+           id: stateid, // fixme: remove (Stateful does not work without)  
+           stateID: stateid
+       });
+
+        me.callParent();
+
+       realmstore.load({
+           callback: function(r, o, success) {
+               if (success) {
+                   var def = me.getValue();
+                   if (!def || !realmstore.findRecord('realm', def)) {
+                       def = 'pam';
+                       Ext.each(r, function(record) {
+                           if (record.data && record.data["default"]) { 
+                               def = record.data.realm;
+                           }
+                       });
+                   }
+                   if (def) {
+                       me.setValue(def);
+                   }
+               }
+           }
+       });
+    }
+});
diff --git a/www/manager6/form/RoleSelector.js b/www/manager6/form/RoleSelector.js
new file mode 100644 (file)
index 0000000..7ffcad2
--- /dev/null
@@ -0,0 +1,47 @@
+Ext.define('PVE.form.RoleSelector', {
+    extend: 'PVE.form.ComboGrid',
+    alias: ['widget.pveRoleSelector'],
+
+    initComponent: function() {
+       var me = this;
+
+       var store = new Ext.data.Store({
+           model: 'pve-roles'
+       });
+
+       Ext.apply(me, {
+           store: store,
+           allowBlank: false,
+           autoSelect: false,
+           valueField: 'roleid',
+           displayField: 'roleid',
+            listConfig: {
+               columns: [
+                   {
+                       header: gettext('Role'),
+                       sortable: true,
+                       dataIndex: 'roleid',
+                       flex: 1
+                   }
+               ]
+           }
+       });
+
+        me.callParent();
+
+       store.load();
+    }
+
+}, function() {
+
+    Ext.define('pve-roles', {
+       extend: 'Ext.data.Model',
+       fields: [ 'roleid', 'privs' ],
+       proxy: {
+            type: 'pve',
+           url: "/api2/json/access/roles"
+       },
+       idProperty: 'roleid'
+    });
+
+});
diff --git a/www/manager6/form/ScsiHwSelector.js b/www/manager6/form/ScsiHwSelector.js
new file mode 100644 (file)
index 0000000..dc868c5
--- /dev/null
@@ -0,0 +1,20 @@
+Ext.define('PVE.form.ScsiHwSelector', {
+    extend: 'PVE.form.KVComboBox',
+    alias: ['widget.pveScsiHwSelector'],
+  
+    initComponent: function() {
+       var me = this;
+
+        me.data = [ 
+           ['', PVE.Utils.render_scsihw('')],
+           ['lsi', PVE.Utils.render_scsihw('lsi')],
+           ['lsi53c810', PVE.Utils.render_scsihw('lsi53c810')],
+           ['megasas', PVE.Utils.render_scsihw('megasas')],
+           ['virtio-scsi-pci', PVE.Utils.render_scsihw('virtio-scsi-pci')],
+           ['virtio-scsi-single', PVE.Utils.render_scsihw('virtio-scsi-single')],
+           ['pvscsi', PVE.Utils.render_scsihw('pvscsi')]
+       ];
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/form/SecurityGroupSelector.js b/www/manager6/form/SecurityGroupSelector.js
new file mode 100644 (file)
index 0000000..37e6bac
--- /dev/null
@@ -0,0 +1,46 @@
+Ext.define('PVE.form.SecurityGroupsSelector', {
+    extend: 'PVE.form.ComboGrid',
+    alias: ['widget.pveSecurityGroupsSelector'],
+
+    initComponent: function() {
+       var me = this;
+
+       var store = Ext.create('Ext.data.Store', {
+           autoLoad: true,
+           fields: [ 'group', 'comment' ],
+           idProperty: 'group',
+           proxy: {
+               type: 'pve',
+               url: "/api2/json/cluster/firewall/groups"
+           },
+           sorters: {
+               property: 'group',
+               order: 'DESC'
+           }
+       });
+
+       Ext.apply(me, {
+           store: store,
+           valueField: 'group',
+           displayField: 'group',
+            listConfig: {
+               columns: [
+                   {
+                       header: gettext('Security Group'),
+                       dataIndex: 'group',
+                       hideable: false,
+                       width: 100
+                   },
+                   {
+                       header: gettext('Comment'),  
+                       dataIndex: 'comment', 
+                       flex: 1
+                   }
+               ]
+           }
+       });
+
+        me.callParent();
+    }
+});
+
diff --git a/www/manager6/form/SnapshotSelector.js b/www/manager6/form/SnapshotSelector.js
new file mode 100644 (file)
index 0000000..074e405
--- /dev/null
@@ -0,0 +1,64 @@
+Ext.define('PVE.form.SnapshotSelector', {
+    extend: 'PVE.form.ComboGrid',
+    alias: ['widget.PVE.form.SnapshotSelector'],
+
+    loadStore: function(nodename, vmid) {
+       var me = this;
+
+       if (!nodename) {
+           return;
+       }
+
+       me.nodename = nodename;
+
+        if (!vmid) {
+           return;
+        }
+
+       me.vmid = vmid;
+
+       me.store.setProxy({
+           type: 'pve',
+           url: '/api2/json/nodes/' + me.nodename + '/qemu/' + me.vmid +'/snapshot'
+       });
+
+       me.store.load();
+    },
+
+    initComponent: function() {
+       var me = this;
+
+        if (!me.nodename) {
+            throw "no node name specified";
+        }
+
+        if (!me.vmid) {
+            throw "no VM ID specified";
+        }
+
+       var store = Ext.create('Ext.data.Store', {
+           fields: [ 'name'],
+           filterOnLoad: true
+       });
+
+       Ext.apply(me, {
+           store: store,
+           valueField: 'name',
+           displayField: 'name',
+            listConfig: {
+               columns: [
+                   {
+                       header: gettext('Snapshot'),
+                       dataIndex: 'name',
+                       hideable: false,
+                       flex: 1
+                   }
+               ]
+           }
+       });
+
+        me.callParent();
+
+       me.loadStore(me.nodename, me.vmid);
+    }
+});
diff --git a/www/manager6/form/StorageSelector.js b/www/manager6/form/StorageSelector.js
new file mode 100644 (file)
index 0000000..28b60ef
--- /dev/null
@@ -0,0 +1,116 @@
+Ext.define('PVE.form.StorageSelector', {
+    extend: 'PVE.form.ComboGrid',
+    alias: ['widget.PVE.form.StorageSelector'],
+
+    reloadStorageList: function() {
+       var me = this;
+       if (!me.nodename) {
+           return;
+       }
+
+       var params = {};
+       var url = '/api2/json/nodes/' + me.nodename + '/storage';
+       if (me.storageContent) {
+           params.content = me.storageContent;
+       }
+       if (me.targetNode) {
+           params.target = me.targetNode;
+           params.enabled = 1; // skip disabled storages
+       }
+       me.store.setProxy({
+           type: 'pve',
+           url: url,
+           extraParams: params
+       });
+
+       me.store.load();
+    },
+
+    setTargetNode: function(targetNode) {
+       var me = this;
+
+       if (!targetNode || (me.targetNode === targetNode)) {
+           return;
+       }
+
+       me.targetNode = targetNode;
+
+       me.reloadStorageList();
+    },
+
+    setNodename: function(nodename) {
+       var me = this;
+
+       if (!nodename || (me.nodename === nodename)) {
+           return;
+       }
+
+       me.nodename = nodename;
+
+       me.reloadStorageList();
+    },
+
+    initComponent: function() {
+       var me = this;
+
+       var nodename = me.nodename;
+       me.nodename = undefined; 
+
+       var store = Ext.create('Ext.data.Store', {
+           model: 'pve-storage-status',
+           sorters: {
+               property: 'storage', 
+               order: 'DESC' 
+           }
+       });
+
+       Ext.apply(me, {
+           store: store,
+           allowBlank: false,
+           valueField: 'storage',
+           displayField: 'storage',
+            listConfig: {
+               columns: [
+                   {
+                       header: gettext('Name'),
+                       dataIndex: 'storage',
+                       hideable: false,
+                       flex: 1
+                   },
+                   {
+                       header: gettext('Type'),
+                       width: 60, 
+                       dataIndex: 'type'
+                   },
+                   {
+                       header: gettext('Avail'),
+                       width: 80, 
+                       dataIndex: 'avail', 
+                       renderer: PVE.Utils.format_size 
+                   },
+                   {
+                       header: gettext('Capacity'),
+                       width: 80, 
+                       dataIndex: 'total', 
+                       renderer: PVE.Utils.format_size 
+                   }
+               ]
+           }
+       });
+
+        me.callParent();
+
+       if (nodename) {
+           me.setNodename(nodename);
+       }
+    }
+}, function() {
+
+    Ext.define('pve-storage-status', {
+       extend: 'Ext.data.Model',
+       fields: [ 'storage', 'active', 'type', 'avail', 'total' ],
+       idProperty: 'storage'
+    });
+
+});
diff --git a/www/manager6/form/TextField.js b/www/manager6/form/TextField.js
new file mode 100644 (file)
index 0000000..60e42eb
--- /dev/null
@@ -0,0 +1,36 @@
+Ext.define('PVE.form.Textfield', {
+    extend: 'Ext.form.field.Text',
+    alias: ['widget.pvetextfield'],
+
+    skipEmptyText: true,
+    
+    deleteEmpty: false,
+    
+    getSubmitData: function() {
+        var me = this,
+            data = null,
+            val;
+        if (!me.disabled && me.submitValue && !me.isFileUpload()) {
+            val = me.getSubmitValue();
+            if (val !== null) {
+                data = {};
+                data[me.getName()] = val;
+            } else if (me.deleteEmpty) {
+               data = {};
+                data['delete'] = me.getName();
+           }
+        }
+        return data;
+    },
+
+    getSubmitValue: function() {
+       var me = this;
+
+        var value = this.processRawValue(this.getRawValue());
+       if (value !== '') {
+           return value;
+       }
+
+       return me.skipEmptyText ? null: value; 
+    }
+});
\ No newline at end of file
diff --git a/www/manager6/form/UserSelector.js b/www/manager6/form/UserSelector.js
new file mode 100644 (file)
index 0000000..3ba4d1b
--- /dev/null
@@ -0,0 +1,74 @@
+Ext.define('PVE.form.UserSelector', {
+    extend: 'PVE.form.ComboGrid',
+    alias: ['widget.pveUserSelector'],
+
+    initComponent: function() {
+       var me = this;
+
+       var store = new Ext.data.Store({
+           model: 'pve-users'
+       });
+
+       var render_full_name = function(firstname, metaData, record) {
+
+           var first = firstname || '';
+           var last = record.data.lastname || '';
+           return first + " " + last;
+       };
+
+       Ext.apply(me, {
+           store: store,
+           allowBlank: false,
+           autoSelect: false,
+           valueField: 'userid',
+           displayField: 'userid',
+            listConfig: {
+               columns: [
+                   {
+                       header: gettext('User'),
+                       sortable: true,
+                       dataIndex: 'userid',
+                       flex: 1
+                   },
+                   {
+                       header: gettext('Name'),
+                       sortable: true,
+                       renderer: render_full_name,
+                       dataIndex: 'firstname',
+                       flex: 1
+                   },
+                   {
+                       id: 'comment',
+                       header: gettext('Comment'),
+                       sortable: false,
+                       dataIndex: 'comment',
+                       flex: 1
+                   }
+               ]
+           }
+       });
+
+        me.callParent();
+
+       store.load({ params: { enabled: 1 }});
+    }
+
+}, function() {
+
+    Ext.define('pve-users', {
+       extend: 'Ext.data.Model',
+       fields: [ 
+           'userid', 'firstname', 'lastname' , 'email', 'comment',
+           { type: 'boolean', name: 'enable' }, 
+           { type: 'date', dateFormat: 'timestamp', name: 'expire' }
+       ],
+       proxy: {
+            type: 'pve',
+           url: "/api2/json/access/users"
+       },
+       idProperty: 'userid'
+    });
+
+});
+
+
diff --git a/www/manager6/form/VLanField.js b/www/manager6/form/VLanField.js
new file mode 100644 (file)
index 0000000..c699907
--- /dev/null
@@ -0,0 +1,40 @@
+Ext.define('PVE.form.VlanField', {
+    extend: 'Ext.form.field.Number',
+    alias: ['widget.pveVlanField'],
+
+    deleteEmpty: false,
+
+    emptyText: 'no VLAN',
+    
+    fieldLabel: gettext('VLAN Tag'),
+
+    allowBlank: true,
+    
+    getSubmitData: function() {
+        var me = this,
+            data = null,
+            val;
+        if (!me.disabled && me.submitValue) {
+            val = me.getSubmitValue();
+            if (val) {
+                data = {};
+                data[me.getName()] = val;
+            } else if (me.deleteEmpty) {
+               data = {};
+                data['delete'] = me.getName();
+           }
+        }
+        return data;
+    },
+
+    initComponent: function() {
+       var me = this;
+
+       Ext.apply(me, {
+           minValue: 1,
+           maxValue: 4094
+       });
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/form/VMIDSelector.js b/www/manager6/form/VMIDSelector.js
new file mode 100644 (file)
index 0000000..92a1781
--- /dev/null
@@ -0,0 +1,56 @@
+Ext.define('PVE.form.VMIDSelector', {
+    extend: 'Ext.form.field.Number',
+    alias: 'widget.pveVMIDSelector',
+
+    allowBlank: false,
+  
+    minValue: 100,
+
+    maxValue: 999999999,
+
+    validateExists: undefined,
+
+    loadNextFreeVMID: false,
+
+    initComponent: function() {
+        var me = this;
+
+       Ext.applyIf(me, {
+           fieldLabel: 'VM ID',
+           listeners: {
+               'change': function(field, newValue, oldValue) {
+                   if (!Ext.isDefined(me.validateExists)) {
+                       return;
+                   }
+                   PVE.Utils.API2Request({
+                       params: { vmid: newValue },
+                       url: '/cluster/nextid',
+                       method: 'GET',
+                       success: function(response, opts) {
+                           if (me.validateExists === true) {
+                               me.markInvalid(gettext('This VM ID does not exists'));
+                           }
+                       },
+                       failure: function(response, opts) {
+                           if (me.validateExists === false) {
+                               me.markInvalid(gettext('This VM ID is already in use'));
+                           }
+                       }
+                   });
+               }
+           }
+       });
+
+        me.callParent();
+
+       if (me.loadNextFreeVMID) {
+           PVE.Utils.API2Request({
+               url: '/cluster/nextid',
+               method: 'GET',
+               success: function(response, opts) {
+                   me.setRawValue(response.result.data);
+               }
+           });
+       }
+    }
+});
diff --git a/www/manager6/form/VNCKeyboardSelector.js b/www/manager6/form/VNCKeyboardSelector.js
new file mode 100644 (file)
index 0000000..ffc1911
--- /dev/null
@@ -0,0 +1,5 @@
+Ext.define('PVE.form.VNCKeyboardSelector', {
+    extend: 'PVE.form.KVComboBox',
+    alias: ['widget.VNCKeyboardSelector'],
+    comboItems: PVE.Utils.kvm_keymap_array()
+});
diff --git a/www/manager6/form/ViewSelector.js b/www/manager6/form/ViewSelector.js
new file mode 100644 (file)
index 0000000..32181e2
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Top left combobox, used to select a view of the underneath RessourceTree
+ */
+Ext.define('PVE.form.ViewSelector', {
+    extend: 'Ext.form.field.ComboBox',
+    alias: ['widget.pveViewSelector'],
+
+    initComponent: function() {
+       var me = this;
+
+       var default_views = {
+           server: {
+               text: gettext('Server View'),
+               groups: ['node']
+           },
+           folder: {
+               text: gettext('Folder View'),
+               groups: ['type']
+           },
+           storage: {
+               text: gettext('Storage View'),
+               groups: ['node'],
+               filterfn: function(node) {
+                   return node.data.type === 'storage' || node.data.type === 'node';
+               }
+           },
+           pool: { 
+               text: gettext('Pool View'), 
+               groups: ['pool'],
+                // Pool View only lists VMs and Containers
+                filterfn: function(node) {
+                    return node.data.type === 'qemu' || node.data.type === 'lxc' || node.data.type === 'openvz' || 
+                       node.data.type === 'pool';
+                }
+           }
+       };
+
+       var groupdef = [];
+       Ext.Object.each(default_views, function(viewname, value) {
+           groupdef.push([viewname, value.text]);
+       });
+
+       var store = Ext.create('Ext.data.Store', {
+           model: 'KeyValue',
+            proxy: {
+               type: 'memory',
+               reader: 'array'
+            },
+           data: groupdef,
+           autoload: true,
+       });
+
+       Ext.apply(me, {
+           hideLabel: true,
+           store: store,
+           value: groupdef[0][0],
+           editable: false,
+           allowBlank: false,
+           forceSelection: true,
+           autoSelect: false,
+           valueField: 'key',
+           displayField: 'value',
+
+           getViewFilter: function() {
+               var view = me.getValue();
+               return Ext.apply({ id: view }, default_views[view] || default_views.server);
+           },
+
+           getState: function() {
+               return { value: me.getValue() };
+           },
+
+           applyState : function(state, doSelect) {
+               var view = me.getValue();
+               if (state && state.value && (view != state.value)) {
+                   var record = store.findRecord('key', state.value);
+                   if (record) {
+                       me.setValue(state.value, true);
+                       if (doSelect) {
+                           me.fireEvent('select', me, [record]);
+                       }
+                   }
+               }
+           },
+           stateEvents: [ 'select' ],
+           stateful: true,
+           id: 'view'
+       });
+
+       me.callParent();
+
+       var statechange = function(sp, key, value) {
+           if (key === me.id) {
+               me.applyState(value, true);
+           }
+       };
+
+       var sp = Ext.state.Manager.getProvider();
+
+       me.mon(sp, 'statechange', statechange, me);
+    }
+});
diff --git a/www/manager6/form/iScsiProviderSelector.js b/www/manager6/form/iScsiProviderSelector.js
new file mode 100644 (file)
index 0000000..9ea34a1
--- /dev/null
@@ -0,0 +1,16 @@
+Ext.define('PVE.form.iScsiProviderSelector', {
+    extend: 'PVE.form.KVComboBox',
+    alias: ['widget.pveiScsiProviderSelector'],
+  
+    initComponent: function() {
+       var me = this;
+
+       me.data = [
+           ['comstar', 'Comstar'],
+           [ 'istgt', 'istgt'],
+           [ 'iet', 'IET']
+       ];
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/grid/BackupView.js b/www/manager6/grid/BackupView.js
new file mode 100644 (file)
index 0000000..aba6d2d
--- /dev/null
@@ -0,0 +1,207 @@
+Ext.define('PVE.grid.BackupView', {
+    extend: 'Ext.grid.GridPanel',
+
+    alias: ['widget.pveBackupView'],
+
+
+    initComponent : function() {
+       var me = this;
+
+       var nodename = me.pveSelNode.data.node;
+       if (!nodename) {
+           throw "no node name specified";
+       }
+
+       var vmid = me.pveSelNode.data.vmid;
+       if (!vmid) {
+           throw "no VM ID specified";
+       }
+
+       var vmtype = me.pveSelNode.data.type;
+       if (!vmtype) {
+           throw "no VM type specified";
+       }
+
+       var filterFn;
+       if (vmtype === 'openvz') {
+           filterFn = function(item) {
+               return item.data.volid.match(':backup/vzdump-openvz-');
+           };
+       } else if (vmtype === 'lxc') {
+           filterFn = function(item) {
+               return item.data.volid.match(':backup/vzdump-lxc-');
+           };
+       } else if (vmtype === 'qemu') {
+           filterFn = function(item) {
+               return item.data.volid.match(':backup/vzdump-qemu-');
+           };
+       } else {
+           throw "unsupported VM type '" + vmtype + "'";
+       }
+
+       me.store = Ext.create('Ext.data.Store', {
+           model: 'pve-storage-content',
+           sorters: { 
+               property: 'volid', 
+               order: 'DESC' 
+           },
+           filters: { filterFn: filterFn }
+       });
+
+       var reload = Ext.Function.createBuffered(function() {
+           if (me.store.proxy.url) {
+               me.store.load();
+           }
+       }, 100);
+
+       var setStorage = function(storage) {
+           var url = '/api2/json/nodes/' + nodename + '/storage/' + storage + '/content';
+           url += '?content=backup';
+
+           me.store.setProxy({
+               type: 'pve',
+               url: url
+           });
+
+           reload();
+       };
+
+       var storagesel = Ext.create('PVE.form.StorageSelector', {
+           nodename: nodename,
+           fieldLabel: gettext('Storage'),
+           labelAlign: 'right',
+           storageContent: 'backup',
+           allowBlank: false,
+           listeners: {
+               change: function(f, value) {
+                   setStorage(value);
+               }
+           }
+       });
+
+       var storagefilter = Ext.create('Ext.form.field.Text', {
+           fieldLabel: gettext('Search'),
+           labelWidth: 50,
+           labelAlign: 'right',
+           enableKeyEvents: true,
+           listeners: {
+               buffer: 500,
+               keyup: function(field) {
+                   me.store.clearFilter(true);
+                   me.store.filter([
+                       {
+                           property: 'volid',
+                           value: field.getValue(),
+                           anyMatch: true,
+                           caseSensitive: false
+                       }
+                   ]);
+               }
+           }
+       });
+
+       var sm = Ext.create('Ext.selection.RowModel', {});
+
+       var backup_btn = Ext.create('Ext.button.Button', {
+           text: gettext('Backup now'),
+           handler: function() {
+               var win = Ext.create('PVE.window.Backup', { 
+                   nodename: nodename,
+                   vmid: vmid,
+                   vmtype: vmtype,
+                   storage: storagesel.getValue()
+               });
+               win.show();
+           }
+       });
+
+       var restore_btn = Ext.create('PVE.button.Button', {
+           text: gettext('Restore'),
+           disabled: true,
+           selModel: sm,
+           enableFn: function(rec) {
+               return !!rec;
+           },
+           handler: function(b, e, rec) {
+               var volid = rec.data.volid;
+
+               var win = Ext.create('PVE.window.Restore', {
+                   nodename: nodename,
+                   vmid: vmid,
+                   volid: rec.data.volid,
+                   volidText: PVE.Utils.render_storage_content(rec.data.volid, {}, rec),
+                   vmtype: vmtype
+               });
+               win.show();
+               win.on('destroy', reload);
+           }
+       });
+
+       var delete_btn = Ext.create('PVE.button.Button', {
+           text: gettext('Remove'),
+           disabled: true,
+           selModel: sm,
+           dangerous: true,        
+           confirmMsg: function(rec) {
+               var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
+                                           "'" + rec.data.volid + "'");
+               msg += " " + gettext('This will permanently erase all image data.');
+
+               return msg;
+           },
+           enableFn: function(rec) {
+               return !!rec;
+           },
+           handler: function(b, e, rec){
+               var storage = storagesel.getValue();
+               if (!storage) {
+                   return;
+               }
+
+               var volid = rec.data.volid;
+               PVE.Utils.API2Request({
+                   url: "/nodes/" + nodename + "/storage/" + storage + "/content/" + volid,
+                   method: 'DELETE',
+                   waitMsgTarget: me,
+                   failure: function(response, opts) {
+                       Ext.Msg.alert('Error', response.htmlStatus);
+                   },
+                   success: function(response, options) {
+                       reload();
+                   }
+               });
+           }
+       });
+
+       Ext.apply(me, {
+           stateful: false,
+           selModel: sm,
+           tbar: [ backup_btn, restore_btn, delete_btn, '->', storagesel, storagefilter ],
+           columns: [
+               {
+                   header: gettext('Name'),
+                   flex: 1,
+                   sortable: true,
+                   renderer: PVE.Utils.render_storage_content,
+                   dataIndex: 'volid'
+               },
+               {
+                   header: gettext('Format'),
+                   width: 100,
+                   dataIndex: 'format'
+               },
+               {
+                   header: gettext('Size'),
+                   width: 100,
+                   renderer: PVE.Utils.format_size,
+                   dataIndex: 'size'
+               }
+           ],
+           listeners: {
+               show: reload
+           }
+       });
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/grid/CheckColumn.js b/www/manager6/grid/CheckColumn.js
new file mode 100644 (file)
index 0000000..b57aca7
--- /dev/null
@@ -0,0 +1,38 @@
+
+// partly copied from extjs/examples/ux/CheckColumn.js
+
+Ext.define('PVE.CheckColumn', {
+    extend: 'Ext.grid.column.Column',
+    alias: 'widget.checkcolumn',
+
+    constructor: function(cfg) {
+       this.renderer = function(value){
+            var cssPrefix = Ext.baseCSSPrefix,
+            cls = [cssPrefix + 'grid-checkheader'];
+
+            if (value) {
+               cls.push(cssPrefix + 'grid-checkheader-checked');
+            }
+            return '<div class="' + cls.join(' ') + '">&#160;</div>';
+       };
+
+       this.addEvents('checkchange');
+
+        this.callParent(arguments);
+    },
+
+    processEvent: function(type, view, cell, recordIndex, cellIndex, e) {
+        if (type == 'mousedown') {
+            var record = view.panel.store.getAt(recordIndex),
+                dataIndex = this.dataIndex,
+                checked = !record.get(dataIndex);
+            record.set(dataIndex, checked);
+            this.fireEvent('checkchange', this, record, checked);
+            return false;
+        } else {
+            return this.callParent(arguments);
+        }
+    }
+
+});
+
diff --git a/www/manager6/grid/FirewallAliases.js b/www/manager6/grid/FirewallAliases.js
new file mode 100644 (file)
index 0000000..353b97c
--- /dev/null
@@ -0,0 +1,185 @@
+Ext.define('PVE.FirewallAliasEdit', {
+    extend: 'PVE.window.Edit',
+
+    base_url: undefined,
+    
+    alias_name: undefined,
+
+    initComponent : function() {
+       /*jslint confusion: true */
+       var me = this;
+
+       me.create = (me.alias_name === undefined);
+
+       if (me.create) {
+            me.url = '/api2/extjs' + me.base_url;
+            me.method = 'POST';
+        } else {
+            me.url = '/api2/extjs' + me.base_url + '/' + me.alias_name;
+            me.method = 'PUT';
+        }
+
+       var items =  [
+           {
+               xtype: 'textfield',
+               name: me.create ? 'name' : 'rename',
+               fieldLabel: gettext('Name'),
+               allowBlank: false
+           },
+           {
+               xtype: 'textfield',
+               name: 'cidr',
+               fieldLabel: gettext('IP/CIDR'),
+               allowBlank: false
+           },
+           {
+               xtype: 'textfield',
+               name: 'comment',
+               fieldLabel: gettext('Comment')
+           }
+       ];
+
+       var ipanel = Ext.create('PVE.panel.InputPanel', {
+           create: me.create,
+           items: items
+       });
+
+       Ext.apply(me, {
+            subject: gettext('Alias'),
+           isAdd: true,
+           items: [ ipanel ]
+       });
+
+       me.callParent();
+
+       if (!me.create) {
+           me.load({
+               success:  function(response, options) {
+                   var values = response.result.data;
+                   values.rename = values.name;
+                   ipanel.setValues(values);
+               }
+           });
+       }
+    }
+});
+
+Ext.define('PVE.FirewallAliases', {
+    extend: 'Ext.grid.Panel',
+    alias: ['widget.pveFirewallAliases'],
+
+    base_url: undefined,
+
+    title: gettext('Alias'),
+
+    initComponent : function() {
+       /*jslint confusion: true */
+
+       var me = this;
+
+       if (!me.base_url) {
+           throw "missing base_url configuration";
+       }
+
+       var store = new Ext.data.Store({
+           fields: [ 'name', 'cidr', 'comment', 'digest' ],
+           proxy: {
+               type: 'pve',
+               url: "/api2/json" + me.base_url
+           },
+           idProperty: 'name',
+           sorters: {
+               property: 'name',
+               order: 'DESC'
+           }
+       });
+
+       var sm = Ext.create('Ext.selection.RowModel', {});
+
+       var reload = function() {
+           var oldrec = sm.getSelection()[0];
+           store.load(function(records, operation, success) {
+               if (oldrec) {
+                   var rec = store.findRecord('name', oldrec.data.name);
+                   if (rec) {
+                       sm.select(rec);
+                   }
+               }
+           });
+       };
+
+       var run_editor = function() {
+           var sm = me.getSelectionModel();
+           var rec = sm.getSelection()[0];
+           if (!rec) {
+               return;
+           }
+
+           var win = Ext.create('PVE.FirewallAliasEdit', {
+               base_url: me.base_url,
+               alias_name: rec.data.name
+           });
+
+           win.show();
+           win.on('destroy', reload);
+       };
+
+       me.editBtn = new PVE.button.Button({
+           text: gettext('Edit'),
+           disabled: true,
+           selModel: sm,
+           handler: run_editor
+       });
+
+       me.addBtn =  Ext.create('Ext.Button', {
+           text: gettext('Add'),
+           handler: function() {
+               var win = Ext.create('PVE.FirewallAliasEdit', {
+                   base_url: me.base_url
+               });
+               win.on('destroy', reload);
+               win.show();
+           }
+       });
+
+       me.removeBtn = new PVE.button.Button({
+           text: gettext('Remove'),
+           selModel: sm,
+           disabled: true,
+           handler: function() {
+               var rec = sm.getSelection()[0];
+               if (!rec) {
+                   return;
+               }
+               PVE.Utils.API2Request({
+                   url: me.base_url + '/' + rec.data.name,
+                   method: 'DELETE',
+                   waitMsgTarget: me,
+                   failure: function(response, options) {
+                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+                   },
+                   callback: reload
+               });
+           }
+       });
+
+
+       Ext.applyIf(me, {
+           store: store,
+           tbar: [ me.addBtn, me.removeBtn, me.editBtn ],
+           selModel: sm,
+           columns: [
+               { header: gettext('Name'), dataIndex: 'name', width: 100 },
+               { header:  gettext('IP/CIDR'), dataIndex: 'cidr', width: 100 },
+               { header: gettext('Comment'), dataIndex: 'comment', flex: 1 }
+           ],
+           listeners: {
+               itemdblclick: run_editor
+           }
+       });
+
+       me.callParent();
+
+       me.on('show', reload);
+    }
+});
diff --git a/www/manager6/grid/FirewallOptions.js b/www/manager6/grid/FirewallOptions.js
new file mode 100644 (file)
index 0000000..f94be6c
--- /dev/null
@@ -0,0 +1,231 @@
+Ext.define('PVE.FirewallOptions', {
+    extend: 'PVE.grid.ObjectGrid',
+    alias: ['widget.pveFirewallOptions'],
+
+    fwtype: undefined, // 'dc', 'node' or 'vm'
+
+    base_url: undefined,
+
+    initComponent : function() {
+       /*jslint confusion: true */
+
+       var me = this;
+
+       if (!me.base_url) {
+           throw "missing base_url configuration";
+       }
+
+       if (me.fwtype === 'dc' || me.fwtype === 'node' || me.fwtype === 'vm') {
+           if (me.fwtype === 'node') {
+               me.cwidth1 = 250;
+           }
+       } else {
+           throw "unknown firewall option type";
+       }
+
+       var rows = {};
+
+       var add_boolean_row = function(name, text, defaultValue, labelWidth) {
+           rows[name] = {
+               header: text,
+               required: true,
+               defaultValue: defaultValue || 0,
+               renderer: PVE.Utils.format_boolean,
+               editor: {
+                   xtype: 'pveWindowEdit',
+                   subject: text,
+                   fieldDefaults: { labelWidth: labelWidth || 100 },
+                   items: {
+                       xtype: 'pvecheckbox',
+                       defaultValue: defaultValue || 0,
+                       checked: defaultValue ? true : false,
+                       name: name,
+                       uncheckedValue: 0,
+                       fieldLabel: text
+                   }
+               }
+           };
+       };
+
+       var add_integer_row = function(name, text, labelWidth, minValue) {
+           rows[name] = {
+               header: text,
+               required: true,
+               renderer: function(value) {
+                   return value || PVE.Utils.defaultText;
+               },
+               editor: {
+                   xtype: 'pveWindowEdit',
+                   subject: text,
+                   fieldDefaults: { labelWidth: labelWidth || 100 },
+                   items: {
+                       xtype: 'numberfield',
+                       name: name,
+                       minValue: minValue,
+                       decimalPrecision: 0,
+                       fieldLabel: text,
+                       emptyText: gettext('Default'),
+                       getSubmitData: function() {
+                           var me = this;
+                           var val = me.getSubmitValue();
+                           if (val !== null && val !== '') {
+                               var data = {};
+                               data[name] = val;
+                               return data;
+                           } else {
+                               return { 'delete' : name };
+                           }
+                       }
+                   }
+               }
+           };
+       };
+
+       var add_log_row = function(name, labelWidth) {
+           rows[name] = {
+               header: name,
+               required: true,
+               defaultValue: 'nolog',
+               editor: {
+                   xtype: 'pveWindowEdit',
+                   subject: name,
+                   fieldDefaults: { labelWidth: labelWidth || 100 },
+                   items: {
+                       xtype: 'pveKVComboBox',
+                       name: name,
+                       fieldLabel: name,
+                       data: [['nolog', 'nolog'], ['info', 'info'], ['err', 'err'],
+                              ['warning', 'warning'], ['crit', 'crit'], ['alert', 'alert'],
+                              ['emerg', 'emerg'], ['debug', 'debug']]
+                   }
+               }
+           };
+       };
+
+
+       if (me.fwtype === 'node') {
+           add_boolean_row('enable', gettext('Enable Firewall'), 1);
+           add_boolean_row('nosmurfs', gettext('SMURFS filter'), 1);
+           add_boolean_row('tcpflags', gettext('TCP flags filter'), 0);
+           add_integer_row('nf_conntrack_max', 'nf_conntrack_max', 120, 32768);
+           add_integer_row('nf_conntrack_tcp_timeout_established', 
+                           'nf_conntrack_tcp_timeout_established', 250, 7875);
+           add_log_row('log_level_in');
+           add_log_row('log_level_out');
+           add_log_row('tcp_flags_log_level', 120);
+           add_log_row('smurf_log_level');
+       } else if (me.fwtype === 'vm') {
+           add_boolean_row('enable', gettext('Enable Firewall'), 0);
+           add_boolean_row('dhcp', gettext('Enable DHCP'), 0);
+           add_boolean_row('macfilter', gettext('MAC filter'), 1);
+           add_log_row('log_level_in');
+           add_log_row('log_level_out');
+       } else if (me.fwtype === 'dc') {
+           add_boolean_row('enable', gettext('Enable Firewall'), 0);
+       } 
+       if (me.fwtype === 'dc' || me.fwtype === 'vm') {
+           rows.policy_in = {
+               header: gettext('Input Policy'),
+               required: true,
+               defaultValue: 'DROP',
+               editor: {
+                   xtype: 'pveWindowEdit',
+                   subject: gettext('Input Policy'),
+                   items: {
+                       xtype: 'pveFirewallPolicySelector',
+                       name: 'policy_in',
+                       value: 'DROP',
+                       fieldLabel: gettext('Input Policy')
+                   }
+               }
+           };
+
+           rows.policy_out = {
+               header: gettext('Output Policy'),
+               required: true,
+               defaultValue: 'ACCEPT',
+               editor: {
+                   xtype: 'pveWindowEdit',
+                   subject: gettext('Output Policy'),
+                   items: {
+                       xtype: 'pveFirewallPolicySelector',
+                       name: 'policy_out',
+                       value: 'ACCEPT',
+                       fieldLabel: gettext('Output Policy')
+                   }
+               }
+           };
+       }
+
+       var reload = function() {
+           me.rstore.load();
+       };
+
+       var run_editor = function() {
+           var sm = me.getSelectionModel();
+           var rec = sm.getSelection()[0];
+           if (!rec) {
+               return;
+           }
+
+           var rowdef = rows[rec.data.key];
+           if (!rowdef.editor) {
+               return;
+           }
+
+           var win;
+           if (Ext.isString(rowdef.editor)) {
+               win = Ext.create(rowdef.editor, {
+                   pveSelNode: me.pveSelNode,
+                   confid: rec.data.key,
+                   url: '/api2/extjs' + me.base_url
+               });
+           } else {
+               var config = Ext.apply({
+                   pveSelNode: me.pveSelNode,
+                   confid: rec.data.key,
+                   url: '/api2/extjs' + me.base_url
+               }, rowdef.editor);
+               win = Ext.createWidget(rowdef.editor.xtype, config);
+               win.load();
+           }
+
+           win.show();
+           win.on('destroy', reload);
+       };
+
+       var edit_btn = new Ext.Button({
+           text: gettext('Edit'),
+           disabled: true,
+           handler: run_editor
+       });
+
+       var set_button_status = function() {
+           var sm = me.getSelectionModel();
+           var rec = sm.getSelection()[0];
+
+           if (!rec) {
+               edit_btn.disable();
+               return;
+           }
+           var rowdef = rows[rec.data.key];
+           edit_btn.setDisabled(!rowdef.editor);
+       };
+
+       Ext.applyIf(me, {
+           url: "/api2/json" + me.base_url,
+           cwidth1: 150,
+           tbar: [ edit_btn ],
+           rows: rows,
+           listeners: {
+               itemdblclick: run_editor,
+               selectionchange: set_button_status
+           }
+       });
+
+       me.callParent();
+
+       me.on('show', reload);
+    }
+});
diff --git a/www/manager6/grid/FirewallRules.js b/www/manager6/grid/FirewallRules.js
new file mode 100644 (file)
index 0000000..ae53637
--- /dev/null
@@ -0,0 +1,776 @@
+Ext.define('PVE.form.FWMacroSelector', {
+    extend: 'PVE.form.ComboGrid',
+    alias: 'widget.pveFWMacroSelector',
+
+    initComponent: function() {
+       var me = this;
+
+       var store = Ext.create('Ext.data.Store', {
+           autoLoad: true,
+           fields: [ 'macro', 'descr' ],
+           idProperty: 'macro',
+           proxy: {
+               type: 'pve',
+               url: "/api2/json/cluster/firewall/macros"
+           },
+           sorters: {
+               property: 'macro',
+               order: 'DESC'
+           }
+       });
+
+       Ext.apply(me, {
+           store: store,
+           allowBlank: true,
+           autoSelect: false,
+           valueField: 'macro',
+           displayField: 'macro',
+            listConfig: {
+               columns: [
+                   {
+                       header: gettext('Macro'),
+                       dataIndex: 'macro',
+                       hideable: false,
+                       width: 100
+                   },
+                   {
+                       header: gettext('Description'),
+                       flex: 1,
+                       dataIndex: 'descr'
+                   }
+               ]
+           }
+       });
+
+       me.callParent();
+    }
+});
+
+Ext.define('PVE.FirewallRulePanel', {
+    extend: 'PVE.panel.InputPanel',
+
+    allow_iface: false,
+
+    list_refs_url: undefined,
+
+    onGetValues: function(values) {
+       var me = this;
+
+       // hack: editable ComboGrid returns nothing when empty, so we need to set ''
+       // Also, disabled text fields return nothing, so we need to set ''
+
+       Ext.Array.each(['source', 'dest', 'proto', 'sport', 'dport'], function(key) {
+           if (values[key] === undefined) {
+               values[key] = '';
+           }
+       });
+
+       delete values.modified_marker;
+       return values;
+    },
+
+    initComponent : function() {
+       var me = this;
+
+       if (!me.list_refs_url) {
+           throw "no list_refs_url specified";
+       }
+
+       me.column1 = [
+           {
+               // hack: we use this field to mark the form 'dirty' when the
+               // record has errors- so that the user can safe the unmodified 
+               // form again.
+               xtype: 'hiddenfield',
+               name: 'modified_marker',
+               value: '',
+           },
+           {
+               xtype: 'pveKVComboBox',
+               name: 'type',
+               value: 'in',
+               data: [['in', 'in'], ['out', 'out']],
+               fieldLabel: gettext('Direction'),
+               allowBlank: false
+           },
+           {
+               xtype: 'pveKVComboBox',
+               name: 'action',
+               value: 'ACCEPT',
+               data: [['ACCEPT', 'ACCEPT'], ['DROP', 'DROP'], ['REJECT', 'REJECT']],
+               fieldLabel: gettext('Action'),
+               allowBlank: false
+           }
+        ];
+
+       if (me.allow_iface) {
+           me.column1.push({
+               xtype: 'pvetextfield',
+               name: 'iface',
+               deleteEmpty: !me.create,
+               value: '',
+               fieldLabel: gettext('Interface')
+           });
+       } else {
+           me.column1.push({
+               xtype: 'displayfield',
+               fieldLabel: '',
+               height: 22, // hack: set same height as text fields
+               value: ''
+           });
+       }
+
+       me.column1.push([
+           {
+               xtype: 'displayfield',
+               fieldLabel: '',
+               height: 7,
+               value: ''
+           },
+           {
+               xtype: 'pveIPRefSelector',
+               name: 'source',
+               autoSelect: false,
+               editable: true,
+               base_url: me.list_refs_url,
+               value: '',
+               fieldLabel: gettext('Source')
+
+           },
+           {
+               xtype: 'pveIPRefSelector',
+               name: 'dest',
+               autoSelect: false,
+               editable: true,
+               base_url: me.list_refs_url,
+               value: '',
+               fieldLabel: gettext('Destination')
+           }
+       ]);
+
+       
+       me.column2 = [
+           {
+               xtype: 'pvecheckbox',
+               name: 'enable',
+               checked: false,
+               height: 22, // hack: set same height as text fields
+               uncheckedValue: 0,
+               fieldLabel: gettext('Enable')
+           },
+           {
+               xtype: 'pveFWMacroSelector',
+               name: 'macro',
+               value: '',
+               fieldLabel: gettext('Macro'),
+               allowBlank: true,
+               listeners: {
+                   change: function(f, value) {
+                        if (value === '') {
+                           me.down('field[name=proto]').setDisabled(false);
+                           me.down('field[name=sport]').setDisabled(false);
+                           me.down('field[name=dport]').setDisabled(false);
+                        } else {
+                           me.down('field[name=proto]').setDisabled(true);
+                           me.down('field[name=proto]').setValue('');
+                           me.down('field[name=sport]').setDisabled(true);
+                           me.down('field[name=sport]').setValue('');
+                           me.down('field[name=dport]').setDisabled(true);
+                           me.down('field[name=dport]').setValue('');
+                       }
+                    }
+                }
+           },
+           {
+               xtype: 'pveIPProtocolSelector',
+               name: 'proto',
+               autoSelect: false,
+               editable: true,
+               value: '',
+               fieldLabel: gettext('Protocol')
+           },
+           {
+               xtype: 'displayfield',
+               fieldLabel: '',
+               height: 7,
+               value: ''
+           },
+           {
+               xtype: 'textfield',
+               name: 'sport',
+               value: '',
+               fieldLabel: gettext('Source port')
+           },
+           {
+               xtype: 'textfield',
+               name: 'dport',
+               height: 22, // hack: set same height as text fields
+               value: '',
+               fieldLabel: gettext('Dest. port')
+           }
+       ];
+       
+       me.columnB = [
+           {
+               xtype: 'textfield',
+               name: 'comment',
+               value: '',
+               fieldLabel: gettext('Comment')
+           }
+       ];
+
+       me.callParent();
+    }
+});
+
+Ext.define('PVE.FirewallRuleEdit', {
+    extend: 'PVE.window.Edit',
+
+    base_url: undefined,
+    list_refs_url: undefined,
+
+    allow_iface: false,
+
+    initComponent : function() {
+       /*jslint confusion: true */
+       var me = this;
+
+       if (!me.base_url) {
+           throw "no base_url specified";
+       }
+       if (!me.list_refs_url) {
+           throw "no list_refs_url specified";
+       }
+
+       me.create = (me.rule_pos === undefined);
+
+       if (me.create) {
+            me.url = '/api2/extjs' + me.base_url;
+            me.method = 'POST';
+        } else {
+            me.url = '/api2/extjs' + me.base_url + '/' + me.rule_pos.toString();
+            me.method = 'PUT';
+        }
+
+       var ipanel = Ext.create('PVE.FirewallRulePanel', {
+           create: me.create,
+           list_refs_url: me.list_refs_url,
+           allow_iface: me.allow_iface,
+           rule_pos: me.rule_pos
+       });
+
+       Ext.apply(me, {
+            subject: gettext('Rule'),
+           isAdd: true,
+           items: [ ipanel ]
+       });
+
+       me.callParent();
+
+       if (!me.create) {
+           me.load({
+               success: function(response, options) {
+                   var values = response.result.data;
+                   ipanel.setValues(values);
+                   if (values.errors) {
+                       var field = me.query('[isFormField][name=modified_marker]')[0];
+                       field.setValue(1);
+                       Ext.Function.defer(function() {
+                           var form = ipanel.up('form').getForm();
+                           form.markInvalid(values.errors)
+                       }, 100);
+                   }
+               }
+           });
+       }
+    }
+});
+
+Ext.define('PVE.FirewallGroupRuleEdit', {
+    extend: 'PVE.window.Edit',
+
+    base_url: undefined,
+
+    allow_iface: false,
+
+    initComponent : function() {
+       /*jslint confusion: true */
+       var me = this;
+
+       me.create = (me.rule_pos === undefined);
+
+       if (me.create) {
+            me.url = '/api2/extjs' + me.base_url;
+            me.method = 'POST';
+        } else {
+            me.url = '/api2/extjs' + me.base_url + '/' + me.rule_pos.toString();
+            me.method = 'PUT';
+        }
+
+       var column1 = [
+           {
+               xtype: 'hiddenfield',
+               name: 'type',
+               value: 'group'
+           },
+           {
+               xtype: 'pveSecurityGroupsSelector',
+               name: 'action',
+               value: '',
+               fieldLabel: gettext('Security Group'),
+               allowBlank: false
+           }
+       ];
+
+       if (me.allow_iface) {
+           column1.push({
+               xtype: 'pvetextfield',
+               name: 'iface',
+               deleteEmpty: !me.create,
+               value: '',
+               fieldLabel: gettext('Interface')
+           });
+       }
+
+       var ipanel = Ext.create('PVE.panel.InputPanel', {
+           create: me.create,
+           column1: column1,
+           column2: [
+               {
+                   xtype: 'pvecheckbox',
+                   name: 'enable',
+                   checked: false,
+                   height: 22, // hack: set same height as text fields
+                   uncheckedValue: 0,
+                   fieldLabel: gettext('Enable')
+               }
+           ],
+           columnB: [
+               {
+                   xtype: 'textfield',
+                   name: 'comment',
+                   value: '',
+                   fieldLabel: gettext('Comment')
+               }
+           ]
+       });
+
+       Ext.apply(me, {
+            subject: gettext('Rule'),
+           isAdd: true,
+           items: [ ipanel ]
+       });
+
+       me.callParent();
+
+       if (!me.create) {
+           me.load({
+               success:  function(response, options) {
+                   var values = response.result.data;
+                   ipanel.setValues(values);
+               }
+           });
+       }
+    }
+});
+
+Ext.define('PVE.FirewallRules', {
+    extend: 'Ext.grid.Panel',
+    alias: 'widget.pveFirewallRules',
+
+    base_url: undefined,
+    list_refs_url: undefined,
+
+    addBtn: undefined,
+    removeBtn: undefined,
+    editBtn: undefined,
+    groupBtn: undefined,
+
+    tbar_prefix: undefined,
+
+    allow_groups: true,
+    allow_iface: false,
+
+    setBaseUrl: function(url) {
+        var me = this;
+
+       me.base_url = url;
+
+       if (url === undefined) {
+           me.addBtn.setDisabled(true);
+           if (me.groupBtn) {
+               me.groupBtn.setDisabled(true);
+           }
+           me.store.removeAll();
+       } else {
+           me.addBtn.setDisabled(false);
+           if (me.groupBtn) {
+               me.groupBtn.setDisabled(false);
+           }
+           me.store.setProxy({
+               type: 'pve',
+               url: '/api2/json' + url
+           });
+
+           me.store.load();
+       }
+    },
+
+    moveRule: function(from, to) {
+        var me = this;
+
+       if (!me.base_url) { 
+           return;
+       }
+
+       PVE.Utils.API2Request({
+           url: me.base_url + "/" + from,
+           method: 'PUT',
+           params: { moveto: to },
+           waitMsgTarget: me,
+           failure: function(response, options) {
+               Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+           },
+           callback: function() {
+               me.store.load();
+           }
+       });
+    },
+
+    updateRule: function(rule) {
+        var me = this;
+
+       if (!me.base_url) { 
+           return;
+       }
+
+       rule.enable = rule.enable ? 1 : 0;
+
+       var pos = rule.pos;
+       delete rule.pos;
+       delete rule.errors;
+
+       PVE.Utils.API2Request({
+           url: me.base_url + '/' + pos.toString(),
+           method: 'PUT',
+           params: rule,
+           waitMsgTarget: me,
+           failure: function(response, options) {
+               Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+           },
+           callback: function() {
+               me.store.load();
+           }
+       });
+    },
+
+    deleteRule: function(rule) {
+        var me = this;
+
+       if (!me.base_url) {
+           return;
+       }
+
+       PVE.Utils.API2Request({
+           url: me.base_url + '/' + rule.pos.toString() +
+               '?digest=' + encodeURIComponent(rule.digest),
+           method: 'DELETE',
+           waitMsgTarget: me,
+           failure: function(response, options) {
+               Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+           },
+           callback: function() {
+               me.store.load();
+           }
+       });
+    },
+
+    initComponent: function() {
+       /*jslint confusion: true */
+        var me = this;
+
+       if (!me.list_refs_url) {
+           throw "no list_refs_url specified";
+       }
+
+       var store = new Ext.data.Store({
+           model: 'pve-fw-rule'
+       });
+
+       var reload = function() {
+           store.load();
+       };
+
+       var sm = Ext.create('Ext.selection.RowModel', {});
+
+       var run_editor = function() {
+           var rec = sm.getSelection()[0];
+           if (!rec) {
+               return;
+           }
+           var type = rec.data.type;
+
+           var editor;
+           if (type === 'in' || type === 'out') {
+               editor = 'PVE.FirewallRuleEdit';
+           } else if (type === 'group') {
+               editor = 'PVE.FirewallGroupRuleEdit';
+           } else {
+               return;
+           }
+
+           var win = Ext.create(editor, {
+               digest: rec.data.digest,
+               allow_iface: me.allow_iface,
+               base_url: me.base_url,
+               list_refs_url: me.list_refs_url,
+               rule_pos: rec.data.pos
+           });
+
+           win.show();
+           win.on('destroy', reload);
+       };
+
+       me.editBtn = new PVE.button.Button({
+           text: gettext('Edit'),
+           disabled: true,
+           selModel: sm,
+           handler: run_editor
+       });
+
+       me.addBtn =  Ext.create('Ext.Button', {
+           text: gettext('Add'),
+           disabled: true,
+           handler: function() {
+               var win = Ext.create('PVE.FirewallRuleEdit', {
+                   allow_iface: me.allow_iface,
+                   base_url: me.base_url,
+                   list_refs_url: me.list_refs_url
+               });
+               win.on('destroy', reload);
+               win.show();
+           }
+       });
+
+       if (me.allow_groups) {
+           me.groupBtn =  Ext.create('Ext.Button', {
+               text: gettext('Insert') + ': ' + 
+                   gettext('Security Group'),
+               disabled: true,
+               handler: function() {
+                   var win = Ext.create('PVE.FirewallGroupRuleEdit', {
+                       allow_iface: me.allow_iface,
+                       base_url: me.base_url
+                   });
+                   win.on('destroy', reload);
+                   win.show();
+               }
+           });
+       }
+
+       me.removeBtn = new PVE.button.Button({
+           text: gettext('Remove'),
+           selModel: sm,
+           disabled: true,
+           handler: function() {
+               var rec = sm.getSelection()[0];
+               if (!rec) {
+                   return;
+               }
+               me.deleteRule(rec.data);
+           }
+       });
+
+       var tbar = me.tbar_prefix ? [ me.tbar_prefix ] : [];
+       tbar.push(me.addBtn);
+       if (me.groupBtn) {
+           tbar.push(me.groupBtn);
+       }
+       tbar.push([ me.removeBtn, me.editBtn ]);
+
+       var render_errors = function(name, value, metaData, record) {
+           var errors = record.data.errors;
+           if (errors && errors[name]) {
+               metaData.tdCls = 'x-form-invalid-field';
+               var html = '<p>' +  Ext.htmlEncode(errors[name]) + '</p>';
+               metaData.tdAttr = 'data-qwidth=600 data-qtitle="ERROR" data-qtip="' + 
+                   html.replace(/\"/g,'&quot;') + '"';
+           }
+           return value;
+       };
+
+       var columns = [
+           {
+               // similar to xtype: 'rownumberer',
+               dataIndex: 'pos',
+               resizable: false,
+               width: 23,
+               sortable: false,
+               align: 'right',
+               hideable: false,
+               menuDisabled: true,
+               renderer: function(value, metaData, record, rowIdx, colIdx, store) {
+                   metaData.tdCls = Ext.baseCSSPrefix + 'grid-cell-special';
+                   if (value >= 0) {
+                       return value;
+                   }
+                   return '';
+               }
+           },
+           {
+               xtype: 'checkcolumn',
+               header: gettext('Enable'),
+               dataIndex: 'enable',
+               listeners: {
+                   checkchange: function(column, record, checked) {
+                       record.commit();
+                       var data = {};
+                       record.fields.each(function(field) {
+                           data[field.name] = record.get(field.name);
+                       });
+                       if (!me.allow_iface || !data.iface) {
+                           delete data.iface;
+                       }
+                       me.updateRule(data);
+                   }
+               },
+               width: 50
+           },
+           {
+               header: gettext('Type'),
+               dataIndex: 'type',
+               renderer: function(value, metaData, record) {
+                   return render_errors('type', value, metaData, record);
+               },
+               width: 50
+           },
+           {
+               header: gettext('Action'),
+               dataIndex: 'action',
+               renderer: function(value, metaData, record) {
+                   return render_errors('action', value, metaData, record);
+               },
+               width: 80
+           },
+           {
+               header: gettext('Macro'),
+               dataIndex: 'macro',
+               renderer: function(value, metaData, record) {
+                   return render_errors('macro', value, metaData, record);
+               },
+               width: 80
+           }
+       ];
+
+       if (me.allow_iface) {
+           columns.push({
+               header: gettext('Interface'),
+               dataIndex: 'iface',
+               renderer: function(value, metaData, record) {
+                   return render_errors('iface', value, metaData, record);
+               },
+               width: 80
+           });
+       }
+
+       columns.push([
+           {
+               header: gettext('Source'),
+               dataIndex: 'source',
+               renderer: function(value, metaData, record) {
+                   return render_errors('source', value, metaData, record);
+               },
+               width: 100
+           },
+           {
+               header: gettext('Destination'),
+               dataIndex: 'dest',
+               renderer: function(value, metaData, record) {
+                   return render_errors('dest', value, metaData, record);
+               },
+               width: 100
+           },
+           {
+               header: gettext('Protocol'),
+               dataIndex: 'proto',
+               renderer: function(value, metaData, record) {
+                   return render_errors('proto', value, metaData, record);
+               },
+               width: 100
+           },
+           {
+               header: gettext('Dest. port'),
+               dataIndex: 'dport',
+               renderer: function(value, metaData, record) {
+                   return render_errors('dport', value, metaData, record);
+               },
+               width: 100
+           },
+           {
+               header: gettext('Source port'),
+               dataIndex: 'sport',
+               renderer: function(value, metaData, record) {
+                   return render_errors('sport', value, metaData, record);
+               },
+               width: 100
+           },
+           {
+               header: gettext('Comment'),
+               dataIndex: 'comment',
+               flex: 1,
+               renderer: function(value, metaData, record) {
+                   return render_errors('comment', Ext.util.Format.htmlEncode(value), metaData, record);
+               }
+           }
+       ]);
+
+       Ext.apply(me, {
+           store: store,
+           selModel: sm,
+           tbar: tbar,
+            viewConfig: {
+               plugins: [
+                   {
+                       ptype: 'gridviewdragdrop',
+                       dragGroup: 'FWRuleDDGroup',
+                       dropGroup: 'FWRuleDDGroup'
+                   }
+               ],
+               listeners: {
+                    beforedrop: function(node, data, dropRec, dropPosition) {
+                       if (!dropRec) {
+                           return false; // empty view
+                       }
+                       var moveto = dropRec.get('pos');
+                       if (dropPosition === 'after') {
+                           moveto++;
+                       }
+                       var pos = data.records[0].get('pos');
+                       me.moveRule(pos, moveto);
+                       return 0;
+                    },
+                   itemdblclick: run_editor
+               }
+           },
+           sortableColumns: false,
+           columns: columns
+       });
+
+       me.callParent();
+
+       if (me.base_url) {
+           me.setBaseUrl(me.base_url); // load
+       }
+    }
+}, function() {
+
+    Ext.define('pve-fw-rule', {
+       extend: 'Ext.data.Model',
+       fields: [ { name: 'enable', type: 'boolean' },
+                 'type', 'action', 'macro', 'source', 'dest', 'proto', 'iface',
+                 'dport', 'sport', 'comment', 'pos', 'digest', 'errors' ],
+       idProperty: 'pos'
+    });
+
+});
diff --git a/www/manager6/grid/ObjectGrid.js b/www/manager6/grid/ObjectGrid.js
new file mode 100644 (file)
index 0000000..cd135a1
--- /dev/null
@@ -0,0 +1,109 @@
+Ext.define('PVE.grid.ObjectGrid', {
+    extend: 'Ext.grid.GridPanel',
+    alias: ['widget.pveObjectGrid'],
+
+    getObjectValue: function(key, defaultValue) {
+       var me = this;
+       var rec = me.store.getById(key);
+       if (rec) {
+           return rec.data.value;
+       }
+       return defaultValue;
+    },
+
+    renderKey: function(key, metaData, record, rowIndex, colIndex, store) {
+       var me = this;
+       var rows = me.rows;
+       var rowdef = (rows && rows[key]) ?  rows[key] : {};
+       return rowdef.header || key;
+    },
+
+    renderValue: function(value, metaData, record, rowIndex, colIndex, store) {
+       var me = this;
+       var rows = me.rows;
+       var key = record.data.key;
+       var rowdef = (rows && rows[key]) ?  rows[key] : {};
+
+       var renderer = rowdef.renderer;
+       if (renderer) {
+           return renderer(value, metaData, record, rowIndex, colIndex, store);
+       }
+
+       return value;
+    },
+
+    initComponent : function() {
+       var me = this;
+
+       var rows = me.rows;
+
+       if (!me.rstore) {
+           if (!me.url) {
+               throw "no url specified";
+           }
+
+           me.rstore = Ext.create('PVE.data.ObjectStore', {
+               url: me.url,
+               interval: me.interval,
+               extraParams: me.extraParams,
+               rows: me.rows
+           });
+       }
+
+       var rstore = me.rstore;
+
+       var store = Ext.create('PVE.data.DiffStore', { rstore: rstore });
+
+       if (rows) {
+           Ext.Object.each(rows, function(key, rowdef) {
+               if (Ext.isDefined(rowdef.defaultValue)) {
+                   store.add({ key: key, value: rowdef.defaultValue });
+               } else if (rowdef.required) {
+                   store.add({ key: key, value: undefined });
+               }
+           });
+       }
+
+       if (me.sorterFn) {
+           store.sorters.add(new Ext.util.Sorter({
+               sorterFn: me.sorterFn
+           }));
+       }
+
+       store.filters.add(new Ext.util.Filter({
+           filterFn: function(item) {
+               if (rows) {
+                   var rowdef = rows[item.data.key];
+                   if (!rowdef || (rowdef.visible === false)) {
+                       return false;
+                   }
+               }
+               return true;
+           }
+       }));
+
+       PVE.Utils.monStoreErrors(me, rstore);
+
+       Ext.applyIf(me, {
+           store: store,
+           hideHeaders: true,
+           stateful: false,
+           columns: [
+               {
+                   header: gettext('Name'),
+                   width: me.cwidth1 || 100,
+                   dataIndex: 'key',
+                   renderer: me.renderKey
+               },
+               {
+                   flex: 1,
+                   header: gettext('Value'),
+                   dataIndex: 'value',
+                   renderer: me.renderValue
+               }
+           ]
+       });
+
+       me.callParent();
+   }
+});
diff --git a/www/manager6/grid/PendingObjectGrid.js b/www/manager6/grid/PendingObjectGrid.js
new file mode 100644 (file)
index 0000000..051951a
--- /dev/null
@@ -0,0 +1,94 @@
+Ext.define('PVE.grid.PendingObjectGrid', {
+    extend: 'PVE.grid.ObjectGrid',
+    alias: ['widget.pvePendingObjectGrid'],
+
+    getObjectValue: function(key, defaultValue, pending) {
+       var me = this;
+       var rec = me.store.getById(key);
+       if (rec) {
+           var value = (pending && Ext.isDefined(rec.data.pending) && (rec.data.pending !== '')) ? 
+               rec.data.pending : rec.data.value;
+
+            if (Ext.isDefined(value) && (value !== '')) {
+               return value;
+            } else {
+               return defaultValue;
+            }
+       }
+       return defaultValue;
+    },
+
+    hasPendingChanges: function(key) {
+       var me = this;
+       var rows = me.rows;
+       var rowdef = (rows && rows[key]) ?  rows[key] : {};
+       var keys = rowdef.multiKey ||  [ key ];
+       var pending = false;
+
+       Ext.Array.each(keys, function(k) {
+           var rec = me.store.getById(k);
+           if (rec && rec.data && Ext.isDefined(rec.data.pending) && (rec.data.pending !== '')) {
+               pending = true;
+           }
+       });
+
+       return pending;
+    },
+
+    renderValue: function(value, metaData, record, rowIndex, colIndex, store) {
+       var me = this;
+       var rows = me.rows;
+       var key = record.data.key;
+       var rowdef = (rows && rows[key]) ?  rows[key] : {};
+       var renderer = rowdef.renderer;
+       var current = '';
+       var pendingdelete = '';
+       var pending = '';
+
+       if (renderer) {
+           current = renderer(value, metaData, record, rowIndex, colIndex, store, false);
+           if (me.hasPendingChanges(key)) {
+               pending = renderer(record.data.pending, metaData, record, rowIndex, colIndex, store, true);
+           }
+           if (pending == current) {
+               pending = undefined;
+           }
+       } else {
+           current = value;
+           pending = record.data.pending;
+       }
+
+       if (record.data['delete']) {
+           pendingdelete = '<div style="text-decoration: line-through;">'+ current +'</div>';
+       }
+
+       if (pending || pendingdelete) {
+           return current + '<div style="color:red">' + pending + pendingdelete + '</div>';
+       } else {
+           return current;
+       }
+    },
+
+    initComponent : function() {
+       var me = this;
+
+       var rows = me.rows;
+
+       if (!me.rstore) {
+           if (!me.url) {
+               throw "no url specified";
+           }
+
+           me.rstore = Ext.create('PVE.data.ObjectStore', {
+               model: 'KeyValuePendingDelete',
+               readArray: true,
+               url: me.url,
+               interval: me.interval,
+               extraParams: me.extraParams,
+               rows: me.rows
+           });
+       }
+
+       me.callParent();
+   }
+});
diff --git a/www/manager6/grid/PoolMembers.js b/www/manager6/grid/PoolMembers.js
new file mode 100644 (file)
index 0000000..932f475
--- /dev/null
@@ -0,0 +1,181 @@
+Ext.define('PVE.pool.AddVM', {
+    extend: 'PVE.window.Edit',
+
+    initComponent : function() {
+       /*jslint confusion: true */
+       var me = this;
+
+       if (!me.pool) {
+           throw "no pool specified";
+       }
+
+       me.create = true;
+       me.isAdd = true;
+       me.url = "/pools/" + me.pool;
+       me.method = 'PUT';
+       
+       Ext.apply(me, {
+           subject: gettext('Virtual Machine'),
+           width: 350,
+           items: [
+               {
+                   xtype: 'pveVMIDSelector',
+                   name: 'vms',
+                   validateExists: true,
+                   value:  '',
+                   fieldLabel: "VM ID"
+               }
+           ]
+       });
+
+       me.callParent();
+    }
+});
+
+Ext.define('PVE.pool.AddStorage', {
+    extend: 'PVE.window.Edit',
+
+    initComponent : function() {
+       /*jslint confusion: true */
+       var me = this;
+
+       if (!me.pool) {
+           throw "no pool specified";
+       }
+
+       me.create = true;
+       me.isAdd = true;
+       me.url = "/pools/" + me.pool;
+       me.method = 'PUT';
+       
+       Ext.apply(me, {
+           subject: gettext('Storage'),
+           width: 350,
+           items: [
+               {
+                   xtype: 'PVE.form.StorageSelector',
+                   name: 'storage',
+                   nodename: 'localhost',
+                   autoSelect: false,
+                   value:  '',
+                   fieldLabel: gettext("Storage")
+               }
+           ]
+       });
+
+       me.callParent();
+    }
+});
+
+Ext.define('PVE.grid.PoolMembers', {
+    extend: 'Ext.grid.GridPanel',
+    alias: ['widget.pvePoolMembers'],
+
+    // fixme: dynamic status update ?
+
+    initComponent : function() {
+       var me = this;
+
+       if (!me.pool) {
+           throw "no pool specified";
+       }
+
+       var store = Ext.create('Ext.data.Store', {
+           model: 'PVEResources',
+           sorters: [
+               {
+                   property : 'type',
+                   direction: 'ASC'
+               }
+           ],
+           proxy: { 
+               type: 'pve',
+               root: 'data.members',
+               url: "/api2/json/pools/" + me.pool
+           }
+       });
+
+       var coldef = PVE.data.ResourceStore.defaultColums();
+
+       var reload = function() {
+           store.load();
+       };
+
+       var sm = Ext.create('Ext.selection.RowModel', {});
+
+       var remove_btn = new PVE.button.Button({
+           text: gettext('Remove'),
+           disabled: true,
+           selModel: sm,
+           confirmMsg: function (rec) {
+               return Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
+                                        "'" + rec.data.id + "'");
+           },
+           handler: function(btn, event, rec) {
+               var params = { 'delete': 1 };
+               if (rec.data.type === 'storage') {
+                   params.storage = rec.data.storage;
+               } else if (rec.data.type === 'qemu' || rec.data.type === 'lxc' || rec.data.type === 'openvz') {
+                   params.vms = rec.data.vmid;
+               } else {
+                   throw "unknown resource type";
+               }
+
+               PVE.Utils.API2Request({
+                   url: '/pools/' + me.pool,
+                   method: 'PUT',
+                   params: params,
+                   waitMsgTarget: me,
+                   callback: function() {
+                       reload();
+                   },
+                   failure: function (response, opts) {
+                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+                   }
+               });
+           }
+       });
+
+       Ext.apply(me, {
+           store: store,
+           selModel: sm,
+           tbar: [
+               {
+                   text: gettext('Add'),
+                   menu: new Ext.menu.Menu({
+                       items: [
+                           {
+                               text: gettext('Virtual Machine'),
+                               iconCls: 'pve-itype-icon-qemu',
+                               handler: function() {
+                                   var win = Ext.create('PVE.pool.AddVM', { pool: me.pool });
+                                   win.on('destroy', reload);
+                                   win.show();
+                               }
+                           },
+                           {
+                               text: gettext('Storage'),
+                               iconCls: 'pve-itype-icon-storage',
+                               handler: function() {
+                                   var win = Ext.create('PVE.pool.AddStorage', { pool: me.pool });
+                                   win.on('destroy', reload);
+                                   win.show();
+                               }
+                           }
+                       ]
+                   })
+               },
+               remove_btn
+           ],
+           viewConfig: {
+               stripeRows: true
+            },
+            columns: coldef,
+           listeners: {
+               show: reload
+           }
+       });
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/grid/ResourceGrid.js b/www/manager6/grid/ResourceGrid.js
new file mode 100644 (file)
index 0000000..e638ec1
--- /dev/null
@@ -0,0 +1,215 @@
+Ext.define('PVE.grid.ResourceGrid', {
+    extend: 'Ext.grid.GridPanel',
+    alias: ['widget.pveResourceGrid'],
+
+    //fixme: this makes still problems with the scrollbar
+    //features: [ {ftype: 'chunking'}],
+    
+    title: gettext('Search'),
+
+    initComponent : function() {
+       var me = this;
+
+       var rstore = PVE.data.ResourceStore;
+       var sp = Ext.state.Manager.getProvider();
+
+       var coldef = rstore.defaultColums();
+
+       var store = Ext.create('Ext.data.Store', {
+           model: 'PVEResources',
+           sorters: [
+               {
+                   property : 'type',
+                   direction: 'ASC'
+               }
+           ],
+           proxy: { type: 'memory' }
+       });
+
+       var textfilter = '';
+
+       var textfilter_match = function(item) {
+           var match = false;
+           Ext.each(['name', 'storage', 'node', 'type', 'text'], function(field) {
+               var v = item.data[field];
+               if (v !== undefined) {
+                   v = v.toLowerCase();
+                   if (v.indexOf(textfilter) >= 0) {
+                       match = true;
+                       return false;
+                   }
+               }
+           });
+           return match;
+       };
+
+       var updateGrid = function() {
+
+           var filterfn = me.viewFilter ? me.viewFilter.filterfn : null;
+           
+           //console.log("START GRID UPDATE " +  me.viewFilter);
+
+           store.suspendEvents();
+
+           var nodeidx = {};
+           var gather_child_nodes = function(cn) {
+               if (!cn) {
+                   return;
+               }
+                var cs = cn.childNodes;
+               if (!cs) {
+                   return;
+               }
+               var len = cs.length, i = 0, n, res;
+
+                for (; i < len; i++) {
+                   var child = cs[i];
+                   var orgnode = rstore.data.get(child.data.id);
+                   if (orgnode) {
+                       if ((!filterfn || filterfn(child)) &&
+                           (!textfilter || textfilter_match(child))) {
+                           nodeidx[child.data.id] = orgnode;
+                       }
+                   }
+                   gather_child_nodes(child);
+               }
+           };
+           gather_child_nodes(me.pveSelNode);
+
+           // remove vanished items
+           var rmlist = [];
+           store.each(function(olditem) {
+               var item = nodeidx[olditem.data.id];
+               if (!item) {
+                   //console.log("GRID REM UID: " + olditem.data.id);
+                   rmlist.push(olditem);
+               }
+           });
+
+           if (rmlist.length) {
+               store.remove(rmlist);
+           }
+
+           // add new items
+           var addlist = [];
+           var key;
+           for (key in nodeidx) {
+               if (nodeidx.hasOwnProperty(key)) {
+                   var item = nodeidx[key];
+               
+                   // getById() use find(), which is slow (ExtJS4 DP5) 
+                   //var olditem = store.getById(item.data.id);
+                   var olditem = store.data.get(item.data.id);
+
+                   if (!olditem) {
+                       //console.log("GRID ADD UID: " + item.data.id);
+                       var info = Ext.apply({}, item.data);
+                       var child = Ext.create(store.model, info);
+                       addlist.push(item);
+                       continue;
+                   }
+                   // try to detect changes
+                   var changes = false;
+                   var fieldkeys = PVE.data.ResourceStore.fieldNames;
+                   var fieldcount = fieldkeys.length;
+                   var fieldind;
+                   for (fieldind = 0; fieldind < fieldcount; fieldind++) {
+                       var field = fieldkeys[fieldind];
+                       if (field != 'id' && item.data[field] != olditem.data[field]) {
+                           changes = true;
+                           //console.log("changed item " + item.id + " " + field + " " + item.data[field] + " != " + olditem.data[field]);
+                           olditem.beginEdit();
+                           olditem.set(field, item.data[field]);
+                       }
+                   }
+                   if (changes) {
+                       olditem.endEdit(true);
+                       olditem.commit(true); 
+                   }
+               }
+           }
+
+           if (addlist.length) {
+               store.add(addlist);
+           }
+
+           store.sort();
+
+           store.resumeEvents();
+
+           store.fireEvent('datachanged', store);
+
+           //console.log("END GRID UPDATE");
+       };
+
+       var filter_task = new Ext.util.DelayedTask(function(){
+           updateGrid();
+       });
+
+       var load_cb = function() { 
+           updateGrid(); 
+       };
+
+       Ext.apply(me, {
+           store: store,
+           tbar: [
+               '->', 
+               gettext('Search') + ':', ' ',
+               {
+                   xtype: 'textfield',
+                   width: 200,
+                   value: textfilter,
+                   enableKeyEvents: true,
+                   listeners: {
+                       keyup: function(field, e) {
+                           var v = field.getValue();
+                           textfilter = v.toLowerCase();
+                           filter_task.delay(500);
+                       }
+                   }
+               }
+           ],
+           viewConfig: {
+               stripeRows: true
+            },
+           listeners: {
+               itemcontextmenu: function(v, record, item, index, event) {
+                   event.stopEvent();
+                   v.select(record);
+                   var menu;
+                   
+                   if (record.data.type === 'qemu' && !record.data.template) {
+                       menu = Ext.create('PVE.qemu.CmdMenu', {
+                           pveSelNode: record
+                       });
+                   } else if (record.data.type === 'qemu' && record.data.template) {
+                       menu = Ext.create('PVE.qemu.TemplateMenu', {
+                           pveSelNode: record
+                       });
+                   } else if (record.data.type === 'lxc') {
+                       menu = Ext.create('PVE.lxc.CmdMenu', {
+                           pveSelNode: record
+                       });
+                   } else {
+                       return;
+                   }
+
+                   menu.showAt(event.getXY());
+               },
+               itemdblclick: function(v, record) {
+                   var ws = me.up('pveStdWorkspace');
+                   ws.selectById(record.data.id);
+               },
+               destroy: function() {
+                   rstore.un("load", load_cb);
+               }
+           },
+            columns: coldef
+       });
+
+       me.callParent();
+
+       updateGrid();
+       rstore.on("load", load_cb);
+    }
+});
diff --git a/www/manager6/grid/SelectFeature.js b/www/manager6/grid/SelectFeature.js
new file mode 100644 (file)
index 0000000..eb5e719
--- /dev/null
@@ -0,0 +1,36 @@
+ Ext.override(Ext.view.Table, {
+    afterRender: function() {
+        var me = this;
+        
+        me.callParent();
+// EXT5DEBUG
+//        me.mon(me.el, {
+//            scroll: me.fireBodyScroll,
+//            scope: me
+//        });
+//     if (!me.featuresMC ||
+//         (me.featuresMC.findIndex('ftype', 'selectable') < 0)) {
+//            me.el.unselectable();
+//     }
+//
+//        me.attachEventsForFeatures();
+    }
+});
+
+Ext.define('PVE.grid.SelectFeature', {
+    extend: 'Ext.grid.feature.Feature',
+    alias: 'feature.selectable',
+
+    mutateMetaRowTpl: function(metaRowTpl) {
+       var tpl, i,
+       ln = metaRowTpl.length;
+       
+       for (i = 0; i < ln; i++) {
+           tpl = metaRowTpl[i];
+           tpl = tpl.replace(/x-grid-row/, 'x-grid-row x-selectable');
+           tpl = tpl.replace(/x-grid-cell-inner x-unselectable/g, 'x-grid-cell-inner');
+           tpl = tpl.replace(/unselectable="on"/g, '');
+           metaRowTpl[i] = tpl;
+       }
+    }  
+});
diff --git a/www/manager6/panel/ConfigPanel.js b/www/manager6/panel/ConfigPanel.js
new file mode 100644 (file)
index 0000000..1878564
--- /dev/null
@@ -0,0 +1,117 @@
+Ext.define('PVE.panel.Config', {
+    extend: 'Ext.panel.Panel',
+    alias: 'widget.pvePanelConfig',
+
+    initComponent: function() {
+        var me = this;
+
+       var stateid = me.hstateid;
+
+       var sp = Ext.state.Manager.getProvider();
+
+       var activeTab;
+
+       var hsregex =  /^([^\-\s]+)(-\S+)?$/;
+
+       if (stateid) {
+           var state = sp.get(stateid);
+           if (state && state.value) {
+               var res = hsregex.exec(state.value);
+               if (res && res[1]) {
+                   activeTab = res[1];
+               }
+           }
+       }
+
+       var items = me.items || [];
+       me.items = undefined;
+
+       var tbar = me.tbar || [];
+       me.tbar = undefined;
+
+       var title = me.title || me.pveSelNode.data.text;
+       me.title = undefined;
+
+       tbar.unshift('->');
+       tbar.unshift({
+           xtype: 'tbtext',
+           text: title,
+           baseCls: 'x-panel-header-text',
+           padding: '0 0 5 0'
+       });
+
+       Ext.applyIf(me, { showSearch: true });
+
+       if (me.showSearch) {
+           items.unshift({
+               itemId: 'search', 
+               xtype: 'pveResourceGrid'
+           });
+       }
+
+       var toolbar = Ext.create('Ext.toolbar.Toolbar', {
+           items: tbar,
+           style: 'border:0px;',
+           height: 28
+       });
+
+       var tab = Ext.create('Ext.tab.Panel', {
+           flex: 1,
+           border: true,
+           activeTab: activeTab,
+           defaults: Ext.apply(me.defaults ||  {}, {
+               pveSelNode: me.pveSelNode,
+               viewFilter: me.viewFilter,
+               workspace: me.workspace,
+               border: false
+           }),
+           items: items,
+           listeners: {
+               afterrender: function(tp) {
+                   var first =  tp.items.get(0);
+                   if (first) {
+                       first.fireEvent('show', first);
+                   }
+               },
+               tabchange: function(tp, newcard, oldcard) {
+                   var ntab = newcard.itemId;
+
+                   // Note: '' is alias for first tab.
+                   // First tab can be 'search' or something else
+                   if (newcard.itemId === items[0].itemId) {
+                       ntab = '';
+                   }
+                   if (stateid) {
+                       if (newcard.phstateid) {
+                           sp.set(newcard.phstateid, newcard.getHState());
+                       } else {
+                           sp.set(stateid, { value: ntab });
+                       }
+                   }
+               }
+           }
+       });
+
+       Ext.apply(me, {
+           layout: { type: 'vbox', align: 'stretch' },
+           items: [ toolbar, tab]
+       });
+
+       me.callParent();
+
+       var statechange = function(sp, key, state) {
+           if (stateid && (key === stateid) && state) {
+               var atab = tab.getActiveTab().itemId;
+               var res = hsregex.exec(state.value);
+               var ntab = (res && res[1]) ? res[1] : items[0].itemId;
+               if (ntab && (atab != ntab)) {
+                   tab.setActiveTab(ntab);
+               }
+           }
+       };
+
+       if (stateid) {
+           me.mon(sp, 'statechange', statechange);
+       }
+    }
+});
diff --git a/www/manager6/panel/Firewall.js b/www/manager6/panel/Firewall.js
new file mode 100644 (file)
index 0000000..4e7efd3
--- /dev/null
@@ -0,0 +1,97 @@
+Ext.define('PVE.panel.Firewall', {
+    extend: 'PVE.panel.SubConfig',
+    alias: 'widget.pveFirewallPanel',
+
+    configPrefix: 'firewall',
+
+    fwtype: undefined, // 'dc', 'node' or 'vm'
+
+    base_url: undefined,
+
+    initComponent: function() {
+       /*jslint confusion: true */
+        var me = this;
+
+       if (!me.base_url) {
+           throw "no base_url specified";
+       }
+
+       if (!(me.fwtype === 'dc' || me.fwtype === 'node' || me.fwtype === 'vm')) {
+           throw "unknown firewall panel type";
+       }
+
+       var list_refs_url = me.fwtype === 'vm' ? (me.base_url + '/refs') : 
+           '/cluster/firewall/refs';
+
+       var items = [
+           {
+               xtype: 'pveFirewallRules',
+               title: gettext('Rules'),
+               allow_iface: true,
+               base_url: me.base_url + '/rules',
+               list_refs_url: list_refs_url,
+               itemId: 'rules'
+           }
+       ];
+
+       if (me.fwtype === 'dc') {
+           items.push({
+               xtype: 'pveSecurityGroups',
+               title: gettext('Security Group'),
+               itemId: 'sg'
+           });
+           items.push({
+               xtype: 'pveFirewallAliases',
+               base_url: '/cluster/firewall/aliases',              
+               itemId: 'aliases'
+           });
+           items.push({
+               xtype: 'pveIPSet',
+               base_url: '/cluster/firewall/ipset',
+               list_refs_url: list_refs_url,               
+               itemId: 'ipset'
+           });
+       }
+
+       if (me.fwtype === 'vm') {
+           items.push({
+               xtype: 'pveFirewallAliases',
+               base_url: me.base_url + '/aliases',                 
+               itemId: 'aliases'
+           });
+           items.push({
+               xtype: 'pveIPSet',
+               base_url: me.base_url + '/ipset',                   
+               list_refs_url: list_refs_url,               
+               itemId: 'ipset'
+           });
+       }
+
+       items.push({
+           xtype: 'pveFirewallOptions',
+           title: gettext('Options'),
+           base_url: me.base_url + '/options',
+           fwtype: me.fwtype,
+           itemId: 'options'
+       });
+
+       if (me.fwtype !== 'dc') {
+           items.push({
+               title: 'Log',
+               itemId: 'fwlog',
+               xtype: 'pveLogView',
+               url: '/api2/extjs' + me.base_url + '/log'
+           });
+       }
+
+       Ext.apply(me, {
+           defaults: {
+               border: false,
+               pveSelNode: me.pveSelNode
+           },
+           items: items
+       });
+
+       me.callParent();
+    }
+});
\ No newline at end of file
diff --git a/www/manager6/panel/IPSet.js b/www/manager6/panel/IPSet.js
new file mode 100644 (file)
index 0000000..2aae7df
--- /dev/null
@@ -0,0 +1,474 @@
+Ext.define('PVE.IPSetList', {
+    extend: 'Ext.grid.Panel',
+    alias: 'widget.pveIPSetList',
+
+    ipset_panel: undefined,
+
+    base_url: undefined,
+
+    addBtn: undefined,
+    removeBtn: undefined,
+    editBtn: undefined,
+
+    initComponent: function() {
+       /*jslint confusion: true */
+        var me = this;
+
+       if (me.ipset_panel == undefined) {
+           throw "no rule panel specified";
+       }
+
+       if (me.base_url == undefined) {
+           throw "no base_url specified";
+       }
+
+       var store = new Ext.data.Store({
+           fields: [ 'name', 'comment', 'digest' ],
+           proxy: {
+               type: 'pve',
+               url: "/api2/json" + me.base_url
+           },
+           idProperty: 'name',
+           sorters: {
+               property: 'name',
+               order: 'DESC'
+           }
+       });
+
+       var sm = Ext.create('Ext.selection.RowModel', {});
+
+       var reload = function() {
+           var oldrec = sm.getSelection()[0];
+           store.load(function(records, operation, success) {
+               if (oldrec) {
+                   var rec = store.findRecord('name', oldrec.data.name);
+                   if (rec) {
+                       sm.select(rec);
+                   }
+               }
+           });
+       };
+
+       var run_editor = function() {
+           var rec = sm.getSelection()[0];
+           if (!rec) {
+               return;
+           }
+           var win = Ext.create('PVE.window.Edit', {
+               subject: "IPSet '" + rec.data.name + "'",
+               url: me.base_url,
+               method: 'POST',
+               digest: rec.data.digest,
+               items: [
+                   {
+                       xtype: 'hiddenfield',
+                       name: 'rename',
+                       value: rec.data.name
+                   },
+                   {
+                       xtype: 'textfield',
+                       name: 'name',
+                       value: rec.data.name,
+                       fieldLabel: gettext('Name'),
+                       allowBlank: false
+                   },
+                   {
+                       xtype: 'textfield',
+                       name: 'comment',
+                       value: rec.data.comment,
+                       fieldLabel: gettext('Comment')
+                   }
+               ]
+           });
+           win.show();
+           win.on('destroy', reload);
+       };
+
+       me.editBtn = new PVE.button.Button({
+           text: gettext('Edit'),
+           disabled: true,
+           selModel: sm,
+           handler: run_editor
+       });
+
+       me.addBtn = new PVE.button.Button({
+           text: gettext('Create'),
+           handler: function() {
+               sm.deselectAll();
+               var win = Ext.create('PVE.window.Edit', {
+                   subject: 'IPSet',
+                   url: me.base_url,
+                   method: 'POST',
+                   items: [
+                       {
+                           xtype: 'textfield',
+                           name: 'name',
+                           value: '',
+                           fieldLabel: gettext('Name'),
+                           allowBlank: false
+                       },
+                       {
+                           xtype: 'textfield',
+                           name: 'comment',
+                           value: '',
+                           fieldLabel: gettext('Comment')
+                       }
+                   ]
+               });
+               win.show();
+               win.on('destroy', reload);
+
+           }
+       });
+
+       me.removeBtn = new PVE.button.Button({
+           text: gettext('Remove'),
+           selModel: sm,
+           disabled: true,
+           handler: function() {
+               var rec = sm.getSelection()[0];
+               if (!rec || !me.base_url) {
+                   return;
+               }
+               PVE.Utils.API2Request({
+                   url: me.base_url + '/' + rec.data.name,
+                   method: 'DELETE',
+                   waitMsgTarget: me,
+                   failure: function(response, options) {
+                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+                   },
+                   callback: reload
+               });
+           }
+       });
+
+       Ext.apply(me, {
+           store: store,
+           tbar: [ '<b>IPSet:</b>', me.addBtn, me.removeBtn, me.editBtn ],
+           selModel: sm,
+           columns: [
+               { header: 'IPSet', dataIndex: 'name', width: 100 },
+               { header: gettext('Comment'), dataIndex: 'comment', flex: 1 }
+           ],
+           listeners: {
+               itemdblclick: run_editor,
+               select: function(sm, rec) {
+                   var url = me.base_url + '/' + rec.data.name;
+                   me.ipset_panel.setBaseUrl(url);
+               },
+               deselect: function() {
+                   me.ipset_panel.setBaseUrl(undefined);
+               },
+               show: reload
+           }
+       });
+
+       me.callParent();
+
+       store.load();
+    }
+});
+
+Ext.define('PVE.IPSetCidrEdit', {
+    extend: 'PVE.window.Edit',
+
+    cidr: undefined,
+
+    initComponent : function() {
+       /*jslint confusion: true */
+       var me = this;
+
+       me.create = (me.cidr === undefined);
+
+
+       if (me.create) {
+            me.url = '/api2/extjs' + me.base_url;
+            me.method = 'POST';
+        } else {
+            me.url = '/api2/extjs' + me.base_url + '/' + me.cidr;
+            me.method = 'PUT';
+        }
+
+       var column1 = [];
+
+       if (me.create) {
+           if (!me.list_refs_url) {
+               throw "no alias_base_url specified";
+           }
+
+           column1.push({
+               xtype: 'pveIPRefSelector',
+               name: 'cidr',
+               ref_type: 'alias',
+               autoSelect: false,
+               editable: true,
+               base_url: me.list_refs_url,
+               value: '',
+               fieldLabel: gettext('IP/CIDR')
+           });
+       } else {
+           column1.push({
+               xtype: 'displayfield',
+               name: 'cidr',
+               height: 22, // hack: set same height as text fields
+               value: '',
+               fieldLabel: gettext('IP/CIDR')
+           });
+       }
+
+       var ipanel = Ext.create('PVE.panel.InputPanel', {
+           create: me.create,
+           column1: column1,
+           column2: [
+               {
+                   xtype: 'pvecheckbox',
+                   name: 'nomatch',
+                   checked: false,
+                   height: 22, // hack: set same height as text fields
+                   uncheckedValue: 0,
+                   fieldLabel: gettext('nomatch')
+               }
+           ],
+           columnB: [
+               {
+                   xtype: 'textfield',
+                   name: 'comment',
+                   value: '',
+                   fieldLabel: gettext('Comment')
+               }
+           ]
+       });
+
+       Ext.apply(me, {
+           subject: gettext('IP/CIDR'),
+           items: [ ipanel ]
+       });
+
+       me.callParent();
+
+       if (!me.create) {
+           me.load({
+               success:  function(response, options) {
+                   var values = response.result.data;
+                   ipanel.setValues(values);
+               }
+           });
+       }
+    }
+});
+
+Ext.define('PVE.IPSetGrid', {
+    extend: 'Ext.grid.Panel',
+    alias: 'widget.pveIPSetGrid',
+
+    base_url: undefined,
+    list_refs_url: undefined,
+
+    addBtn: undefined,
+    removeBtn: undefined,
+    editBtn: undefined,
+
+    setBaseUrl: function(url) {
+        var me = this;
+
+       me.base_url = url;
+
+       if (url === undefined) {
+           me.addBtn.setDisabled(true);
+           me.store.removeAll();
+       } else {
+           me.addBtn.setDisabled(false);
+           me.store.setProxy({
+               type: 'pve',
+               url: '/api2/json' + url
+           });
+
+           me.store.load();
+       }
+    },
+
+    initComponent: function() {
+       /*jslint confusion: true */
+        var me = this;
+
+       if (!me.list_refs_url) {
+           throw "no1 list_refs_url specified";
+       }
+
+       var store = new Ext.data.Store({
+           model: 'pve-ipset'
+       });
+
+       var reload = function() {
+           store.load();
+       };
+
+       var sm = Ext.create('Ext.selection.RowModel', {});
+
+       var run_editor = function() {
+           var rec = sm.getSelection()[0];
+           if (!rec) {
+               return;
+           }
+           var win = Ext.create('PVE.IPSetCidrEdit', {
+               base_url: me.base_url,
+               cidr: rec.data.cidr
+           });
+           win.show();
+           win.on('destroy', reload);
+       };
+
+       me.editBtn = new PVE.button.Button({
+           text: gettext('Edit'),
+           disabled: true,
+           selModel: sm,
+           handler: run_editor
+       });
+
+       me.addBtn = new PVE.button.Button({
+           text: gettext('Add'),
+           disabled: true,
+           handler: function() {
+               if (!me.base_url) {
+                   return;
+               }
+               var win = Ext.create('PVE.IPSetCidrEdit', {
+                   base_url: me.base_url,
+                   list_refs_url: me.list_refs_url
+               });
+               win.show();
+               win.on('destroy', reload);
+           }
+       });
+
+       me.removeBtn = new PVE.button.Button({
+           text: gettext('Remove'),
+           selModel: sm,
+           disabled: true,
+           handler: function() {
+               var rec = sm.getSelection()[0];
+               if (!rec || !me.base_url) {
+                   return;
+               }
+
+               PVE.Utils.API2Request({
+                   url: me.base_url + '/' + rec.data.cidr,
+                   method: 'DELETE',
+                   waitMsgTarget: me,
+                   failure: function(response, options) {
+                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+                   },
+                   callback: reload
+               });
+           }
+       });
+
+       var render_errors = function(value, metaData, record) {
+           var errors = record.data.errors;
+           if (errors) {
+               var msg = errors.cidr || errors.nomatch;
+               if (msg) {
+                   metaData.tdCls = 'x-form-invalid-field';
+                   var html = '<p>' +  Ext.htmlEncode(msg) + '</p>';
+                   metaData.tdAttr = 'data-qwidth=600 data-qtitle="ERROR" data-qtip="' + 
+                       html.replace(/\"/g,'&quot;') + '"';
+               }
+           }
+           return value;
+       };
+
+       Ext.apply(me, {
+           tbar: [ '<b>IP/CIDR:</b>', me.addBtn, me.removeBtn, me.editBtn ],
+           store: store,
+           selModel: sm,
+           listeners: {
+               itemdblclick: run_editor
+           },
+           columns: [
+               {
+                   xtype: 'rownumberer'
+               },
+               {
+                   header: gettext('IP/CIDR'),
+                   dataIndex: 'cidr',
+                   width: 150,
+                   renderer: function(value, metaData, record) {
+                       value = render_errors(value, metaData, record);
+                       if (record.data.nomatch) {
+                           return '<b>! </b>' + value;
+                       }
+                       return value;
+                   }
+               },
+               {
+                   header: gettext('Comment'),
+                   dataIndex: 'comment',
+                   flex: 1,
+                   renderer: function(value) {
+                       return Ext.util.Format.htmlEncode(value);
+                   }
+               }
+           ]
+       });
+
+       me.callParent();
+
+       if (me.base_url) {
+           me.setBaseUrl(me.base_url); // load
+       }
+    }
+}, function() {
+
+    Ext.define('pve-ipset', {
+       extend: 'Ext.data.Model',
+       fields: [ { name: 'nomatch', type: 'boolean' },
+                 'cidr', 'comment', 'errors' ],
+       idProperty: 'cidr'
+    });
+
+});
+
+Ext.define('PVE.IPSet', {
+    extend: 'Ext.panel.Panel',
+    alias: 'widget.pveIPSet',
+
+    title: 'IPSet',
+
+    list_refs_url: undefined,
+
+    initComponent: function() {
+       var me = this;
+
+       if (!me.list_refs_url) {
+           throw "no list_refs_url specified";
+       }
+
+       var ipset_panel = Ext.createWidget('pveIPSetGrid', {
+           region: 'center',
+           list_refs_url: me.list_refs_url,
+           flex: 0.5,
+           border: false
+       });
+
+       var ipset_list = Ext.createWidget('pveIPSetList', {
+           region: 'west',
+           ipset_panel: ipset_panel,
+           base_url: me.base_url,
+           flex: 0.5,
+           border: false,
+           split: true
+       });
+
+       Ext.apply(me, {
+            layout: 'border',
+            items: [ ipset_list, ipset_panel ],
+           listeners: {
+               show: function() {
+                   ipset_list.fireEvent('show', ipset_list);
+               }
+           }
+       });
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/panel/InputPanel.js b/www/manager6/panel/InputPanel.js
new file mode 100644 (file)
index 0000000..8ab1e33
--- /dev/null
@@ -0,0 +1,108 @@
+Ext.define('PVE.panel.InputPanel', {
+    extend: 'Ext.panel.Panel',
+    alias: ['widget.inputpanel'],
+
+    border: false,
+
+    // overwrite this to modify submit data
+    onGetValues: function(values) {
+       return values;
+    },
+
+    getValues: function(dirtyOnly) {
+       var me = this;
+
+       if (Ext.isFunction(me.onGetValues)) {
+           dirtyOnly = false;
+       }
+
+       var values = {};
+
+       Ext.Array.each(me.query('[isFormField]'), function(field) {
+            if (!dirtyOnly || field.isDirty()) {
+                PVE.Utils.assemble_field_data(values, field.getSubmitData());
+           }
+       });
+
+       return me.onGetValues(values);
+    },
+
+    setValues: function(values) {
+       var me = this;
+
+       var form = me.up('form');
+
+        Ext.iterate(values, function(fieldId, val) {
+           var field = me.query('[isFormField][name=' + fieldId + ']')[0];
+            if (field) {
+               field.setValue(val);
+                if (form.trackResetOnLoad) {
+                    field.resetOriginalValue();
+                }
+            }
+       });
+    },
+
+    initComponent: function() {
+       var me = this;
+
+       var items;
+       
+       if (me.items) {
+           me.columns = 1;
+           items = [
+               {
+                   columnWidth: 1,
+                   layout: 'anchor',
+                   items: me.items
+               }
+           ];
+           me.items = undefined;
+       } else if (me.column1) {
+           me.columns = 2;
+           items = [
+               {
+                   columnWidth: 0.5,
+                   padding: '0 10 0 0',
+                   layout: 'anchor',
+                   items: me.column1
+               },
+               {
+                   columnWidth: 0.5,
+                   padding: '0 0 0 10',
+                   layout: 'anchor',
+                   items: me.column2 || [] // allow empty column
+               }
+           ];
+           if (me.columnB) {
+               items.push({
+                   columnWidth: 1,
+                   padding: '10 0 0 0',
+                   layout: 'anchor',
+                   items: me.columnB
+               });
+           }
+       } else {
+           throw "unsupported config";
+       }
+
+       if (me.useFieldContainer) {
+           Ext.apply(me, {
+               layout: 'fit',
+               items: Ext.apply(me.useFieldContainer, { 
+                   layout: 'column',
+                   defaultType: 'container',
+                   items: items
+               })
+           });
+       } else {
+           Ext.apply(me, {
+               layout: 'column',
+               defaultType: 'container',
+               items: items
+           });
+       }
+       
+       me.callParent();
+    }
+});
diff --git a/www/manager6/panel/LogView.js b/www/manager6/panel/LogView.js
new file mode 100644 (file)
index 0000000..49be118
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Display log entries in a panel with scrollbar
+ * The log entries are automatically refreshed via a background task,
+ * with newest entries comming at the bottom
+ */
+Ext.define('PVE.panel.LogView', {
+    extend: 'Ext.panel.Panel',
+
+    alias: ['widget.pveLogView'],
+
+    pageSize: 500,
+
+    lineHeight: 16,
+
+    viewInfo: undefined,
+
+    scrollToEnd: true,
+
+    getMaxDown: function(scrollToEnd) {
+        var me = this;
+
+       var target = me.getTargetEl();
+       var dom = target.dom;
+       if (scrollToEnd) {
+           dom.scrollTop = dom.scrollHeight - dom.clientHeight;
+       }
+
+       var maxDown = dom.scrollHeight - dom.clientHeight - 
+           dom.scrollTop;
+
+       return maxDown;
+    },
+
+    updateView: function(start, end, total, text) {
+        var me = this;
+       var el = me.dataCmp.el;
+
+       if (me.viewInfo && me.viewInfo.start === start &&
+           me.viewInfo.end === end && me.viewInfo.total === total &&
+           me.viewInfo.textLength === text.length) {
+           return; // same content
+       }
+
+       var maxDown = me.getMaxDown();
+       var scrollToEnd = (maxDown <= 0) && me.scrollToEnd;
+
+       el.setStyle('padding-top', start*me.lineHeight + 'px');
+       el.update(text);
+       me.dataCmp.setHeight(total*me.lineHeight);
+
+       if (scrollToEnd) {
+           me.getMaxDown(true);
+       }
+
+       me.viewInfo = {
+           start: start,
+           end: end,
+           total: total,
+           textLength:  text.length
+       };
+    },
+
+    doAttemptLoad: function(start) {
+        var me = this;
+
+       PVE.Utils.API2Request({
+           url: me.url,
+           params: {
+               start: start,
+               limit: me.pageSize
+           },
+           method: 'GET',
+           success: function(response) {
+               PVE.Utils.setErrorMask(me, false);
+               var list = response.result.data;
+               var total = response.result.total;
+               var first = 0, last = 0;
+               var text = '';
+               Ext.Array.each(list, function(item) {
+                   if (!first|| item.n < first) {
+                       first = item.n;
+                   }
+                   if (!last || item.n > last) {
+                       last = item.n;
+                   }
+                   text = text + Ext.htmlEncode(item.t) + "<br>";
+               });
+
+               if (first && last && total) {
+                   me.updateView(first -1 , last -1, total, text);
+               } else {
+                   me.updateView(0, 0, 0, '');
+               }
+           },
+           failure: function(response) {
+               var msg = response.htmlStatus;
+               PVE.Utils.setErrorMask(me, msg);
+           }
+       });                           
+    },
+
+    attemptLoad: function(start) {
+        var me = this;
+        if (!me.loadTask) {
+            me.loadTask = Ext.create('Ext.util.DelayedTask', me.doAttemptLoad, me, []);
+        }
+        me.loadTask.delay(200, me.doAttemptLoad, me, [start]);
+    },
+
+    requestUpdate: function(top, force) {
+       var me = this;
+
+       if (top === undefined) {
+           var target = me.getTargetEl();
+           top = target.dom.scrollTop;
+       }
+
+       var viewStart = parseInt((top / me.lineHeight) - 1, 10);
+       if (viewStart < 0) {
+           viewStart = 0;
+       }
+       var viewEnd = parseInt(((top + me.getHeight())/ me.lineHeight) + 1, 10);
+       var info = me.viewInfo;
+
+       if (info && !force) {
+           if (viewStart >= info.start && viewEnd <= info.end) {
+               return;
+           }
+       }
+
+       var line = parseInt((top / me.lineHeight) - (me.pageSize / 2) + 10, 10);
+       if (line < 0) {
+           line = 0;
+       }
+
+       me.attemptLoad(line);
+    },
+
+    afterRender: function() {
+       var me = this;
+
+        me.callParent(arguments);
+       Ext.Function.defer(function() {
+           var target = me.getTargetEl();
+           target.on('scroll',  function(e) {
+               me.requestUpdate();
+           });
+           me.requestUpdate(0);
+       }, 20);
+    },
+
+    initComponent : function() {
+       /*jslint confusion: true */
+
+       var me = this;
+
+       if (!me.url) {
+           throw "no url specified";
+       }
+
+       me.dataCmp = Ext.create('Ext.Component', {
+           style: 'font:normal 11px tahoma, arial, verdana, sans-serif;' +
+               'line-height: ' + me.lineHeight.toString() + 'px; white-space: pre;'
+       });
+
+       me.task = Ext.TaskManager.start({
+           run: function() {
+               if (!me.isVisible() || !me.scrollToEnd || !me.viewInfo) {
+                   return;
+               }
+               
+               var maxDown = me.getMaxDown();
+               if (maxDown > 0) {
+                   return;
+               }
+
+               me.requestUpdate(undefined, true);
+           },
+           interval: 1000
+       });
+
+       Ext.apply(me, {
+           autoScroll: true,
+           layout: 'auto',
+           items: me.dataCmp,
+           bodyStyle: 'padding: 5px;',
+           listeners: {
+               show: function() {
+                   var target = me.getTargetEl();
+                   if (target && target.dom) {
+                       target.dom.scrollTop = me.savedScrollTop;
+                   }
+               },
+               beforehide: function() {
+                   // Hack: chrome reset scrollTop to 0, so we save/restore
+                   var target = me.getTargetEl();
+                   if (target && target.dom) {
+                       me.savedScrollTop = target.dom.scrollTop;
+                   }
+               },
+               destroy: function() {
+                   Ext.TaskManager.stop(me.task);
+               }
+           }
+       });
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/panel/NotesView.js b/www/manager6/panel/NotesView.js
new file mode 100644 (file)
index 0000000..add9e5e
--- /dev/null
@@ -0,0 +1,66 @@
+Ext.define('PVE.panel.NotesView', {
+    extend: 'Ext.panel.Panel',
+
+    load: function() {
+       var me = this;
+       
+       PVE.Utils.API2Request({
+           url: me.url,
+           waitMsgTarget: me,
+           failure: function(response, opts) {
+               me.update(gettext('Error') + " " + response.htmlStatus);
+           },
+           success: function(response, opts) {
+               var data = response.result.data.description || '';
+               me.update(Ext.htmlEncode(data));
+           }
+       });
+    },
+
+    initComponent : function() {
+       var me = this;
+
+       var nodename = me.pveSelNode.data.node;
+       if (!nodename) {
+           throw "no node name specified";
+       }
+
+       var vmid = me.pveSelNode.data.vmid;
+       if (!vmid) {
+           throw "no VM ID specified";
+       }
+
+       var vmtype = me.pveSelNode.data.type;
+       var url;
+
+       if (vmtype === 'qemu') {
+           me.url = '/api2/extjs/nodes/' + nodename + '/qemu/' + vmid + '/config';
+       } else if (vmtype === 'lxc') {
+           me.url = '/api2/extjs/nodes/' + nodename + '/lxc/' + vmid + '/config';
+       } else {
+           throw "unknown vm type '" + vmtype + "'";
+       }
+
+       Ext.apply(me, {
+           title: gettext("Notes"),
+           style: 'padding-left:10px',
+           bodyStyle: 'white-space:pre',
+           bodyPadding: 10,
+           autoScroll: true,
+           listeners: {
+               render: function(c) {
+                   c.el.on('dblclick', function() { 
+                       var win = Ext.create('PVE.window.NotesEdit', {
+                           pveSelNode: me.pveSelNode,
+                           url: me.url
+                       });
+                       win.show();
+                       win.on('destroy', me.load, me);
+                   });
+               }
+           }
+       });
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/panel/RRDView.js b/www/manager6/panel/RRDView.js
new file mode 100644 (file)
index 0000000..9fd3c47
--- /dev/null
@@ -0,0 +1,112 @@
+Ext.define('PVE.panel.RRDView', {
+    extend: 'Ext.panel.Panel',
+    alias: 'widget.pveRRDView',
+
+    initComponent : function() {
+       var me = this;
+
+       if (!me.datasource) {
+           throw "no datasource specified";
+       }
+
+       if (!me.rrdurl) {
+           throw "no rrdurl specified";
+       }
+
+       var stateid = 'pveRRDTypeSelection';
+       var sp = Ext.state.Manager.getProvider();
+       var stateinit = sp.get(stateid);
+
+        if (stateinit) {
+           if(stateinit.timeframe !== me.timeframe || stateinit.cf !== me.rrdcffn){
+               me.timeframe = stateinit.timeframe;
+               me.rrdcffn = stateinit.cf;
+           }
+       }
+
+       if (!me.timeframe) {
+           if(stateinit && stateinit.timeframe){
+               me.timeframe = stateinit.timeframe;
+           }else{
+               me.timeframe = 'hour';
+           }
+       }
+
+       if (!me.rrdcffn) {
+           if(stateinit && stateinit.rrdcffn){
+               me.rrdcffn = stateinit.cf;
+           }else{
+               me.rrdcffn = 'AVERAGE';
+           }
+       }
+
+
+       var datasource = me.datasource;
+
+       // fixme: dcindex??
+       var dcindex = 0;
+       var create_url = function() {
+           var url = me.rrdurl + "?ds=" + datasource + 
+               "&timeframe=" + me.timeframe + "&cf=" + me.rrdcffn +
+               "&_dc=" + dcindex.toString();
+           dcindex++;
+           return url;
+       };
+
+
+       Ext.apply(me, {
+           layout: 'fit',
+           html: {
+               tag: 'img',
+               width: 800,
+               height: 200,
+               src:  create_url()
+           },
+           applyState : function(state) {
+               if (state && state.id) {
+                   if(state.timeframe !== me.timeframe || state.cf !== me.rrdcffn){
+                       me.timeframe = state.timeframe;
+                       me.rrdcffn = state.cf;
+                       me.reload_task.delay(10);
+                   }
+               }
+           }
+       });
+       
+       me.callParent();
+   
+       me.reload_task = new Ext.util.DelayedTask(function() {
+           if (me.rendered) {
+               try {
+                   var html = {
+                       tag: 'img',
+                       width: 800,
+                       height: 200,
+                       src:  create_url()
+                   };
+                   me.update(html);
+               } catch (e) {
+                   // fixme:
+                   console.log(e);
+               }
+               me.reload_task.delay(30000);
+           } else {
+               me.reload_task.delay(1000);
+           }
+       });
+
+       me.reload_task.delay(30000);
+
+       me.on('destroy', function() {
+           me.reload_task.cancel();
+       });
+
+       var state_change_fn = function(prov, key, value) {
+           if (key == stateid) {
+               me.applyState(value);
+           }
+       };
+
+       me.mon(sp, 'statechange', state_change_fn);
+    }
+});
diff --git a/www/manager6/panel/StatusPanel.js b/www/manager6/panel/StatusPanel.js
new file mode 100644 (file)
index 0000000..92d4d99
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * This class describes the bottom panel
+ */
+Ext.define('PVE.panel.StatusPanel', {
+    extend: 'Ext.tab.Panel',
+    alias: 'widget.pveStatusPanel',
+
+    
+    //title: "Logs",
+    //tabPosition: 'bottom',
+
+    initComponent: function() {
+        var me = this;
+
+       var stateid = 'ltab';
+       var sp = Ext.state.Manager.getProvider();
+
+       var state = sp.get(stateid);
+       if (state && state.value) {
+           me.activeTab = state.value;
+       }
+
+       Ext.apply(me, {
+           listeners: {
+               tabchange: function() {
+                   var atab = me.getActiveTab().itemId;
+                   var state = { value: atab };
+                   sp.set(stateid, state);
+               }
+           },
+           items: [
+               {
+                   itemId: 'tasks',
+                   title: gettext('Tasks'),
+                   xtype: 'pveClusterTasks'
+               },
+               {
+                   itemId: 'clog',
+                   title: gettext('Cluster log'),
+                   xtype: 'pveClusterLog'
+               }
+           ]
+       });
+
+       me.callParent();
+
+       me.items.get(0).fireEvent('show', me.items.get(0));
+
+       var statechange = function(sp, key, state) {
+           if (key === stateid) {
+               var atab = me.getActiveTab().itemId;
+               var ntab = state.value;
+               if (state && ntab && (atab != ntab)) {
+                   me.setActiveTab(ntab);
+               }
+           }
+       };
+
+       sp.on('statechange', statechange);
+       me.on('destroy', function() {
+           sp.un('statechange', statechange);              
+       });
+
+    }
+});
diff --git a/www/manager6/panel/SubConfigPanel.js b/www/manager6/panel/SubConfigPanel.js
new file mode 100644 (file)
index 0000000..849fd04
--- /dev/null
@@ -0,0 +1,80 @@
+Ext.define('PVE.panel.SubConfig', {
+    extend: 'Ext.tab.Panel',
+    alias: ['widget.pvePanelSubConfig'],
+
+    configPrefix: undefined,
+
+    getHState: function(itemId) {
+        /*jslint confusion: true */
+        var me = this;
+       
+       if (!itemId) {
+           itemId = me.getActiveTab().itemId;
+       }
+
+       var first =  me.items.get(0);
+       var ntab;
+
+       // Note: '' is alias for first tab.
+       if (itemId === first.itemId) {
+           ntab = me.configPrefix;
+       } else {
+           ntab = me.configPrefix + '-' + itemId;
+       }
+
+       return { value: ntab };
+    },
+
+    initComponent: function() {
+        var me = this;
+
+       if (!me.phstateid) {
+           throw "no parent history state specified";
+       }
+
+       var sp = Ext.state.Manager.getProvider();
+       var state = sp.get(me.phstateid);
+       
+       var hsregex =  /^([^\-\s]+)-(\S+)?$/;
+
+       if (state && state.value) {
+           var res = hsregex.exec(state.value);
+           if (res && res[1] && res[2] && res[1] === me.configPrefix) {
+               me.activeTab = res[2];
+           }
+       }
+
+       Ext.apply(me, {
+           plain: true,
+           tabPosition: 'bottom',
+           listeners: {
+               afterrender: function(tp) {
+                   var first =  tp.items.get(0);
+                   if (first) {
+                       first.fireEvent('show', first);
+                   }
+               },
+               tabchange: function(tp, newcard, oldcard) {
+                   var state = me.getHState(newcard.itemId);
+                   sp.set(me.phstateid, state);
+               }
+           }
+       });
+
+       me.callParent();
+
+       var statechange = function(sp, key, state) {
+           if ((key === me.phstateid) && state) {
+               var first = me.items.get(0);
+               var atab = me.getActiveTab().itemId;
+               var res = hsregex.exec(state.value);
+               var ntab = (res && res[1]) ? res[1] : first.itemId;
+               if (ntab && (atab != ntab)) {
+                   me.setActiveTab(ntab);
+               }
+           }
+       };
+
+       me.mon(sp, 'statechange', statechange);
+    }
+});
diff --git a/www/manager6/pool/Config.js b/www/manager6/pool/Config.js
new file mode 100644 (file)
index 0000000..8683cca
--- /dev/null
@@ -0,0 +1,39 @@
+Ext.define('PVE.pool.Config', {
+    extend: 'PVE.panel.Config',
+    alias: 'widget.pvePoolConfig',
+
+    initComponent: function() {
+        var me = this;
+
+       var pool = me.pveSelNode.data.pool;
+       if (!pool) {
+           throw "no pool specified";
+       }
+
+       Ext.apply(me, {
+           title: Ext.String.format(gettext("Resource Pool") + ': ' + pool),
+           hstateid: 'pooltab',
+           items: [
+               {
+                   title: gettext('Summary'),
+                   xtype: 'pvePoolSummary',
+                   itemId: 'summary'
+               },
+               {
+                   title: gettext('Members'),
+                   xtype: 'pvePoolMembers',
+                   pool: pool,
+                   itemId: 'members'
+               },
+               {
+                   xtype: 'pveACLView',
+                   title: gettext('Permissions'),
+                   itemId: 'permissions',
+                   path: '/pool/' + pool
+               }
+           ]
+       });
+
+       me.callParent();
+   }
+});
diff --git a/www/manager6/pool/StatusView.js b/www/manager6/pool/StatusView.js
new file mode 100644 (file)
index 0000000..8049364
--- /dev/null
@@ -0,0 +1,31 @@
+Ext.define('PVE.pool.StatusView', {
+    extend: 'PVE.grid.ObjectGrid',
+    alias: ['widget.pvePoolStatusView'],
+
+    initComponent : function() {
+       var me = this;
+
+       var pool = me.pveSelNode.data.pool;
+       if (!pool) {
+           throw "no pool specified";
+       }
+
+       var rows = {
+           comment: {
+               header: gettext('Comment'), 
+               required: true
+           }
+       };
+
+       Ext.applyIf(me, {
+           title: gettext('Status'),
+           url: "/api2/json/pools/" + pool,
+           cwidth1: 150,
+           interval: 30000,
+           //height: 195,
+           rows: rows
+       });
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/pool/Summary.js b/www/manager6/pool/Summary.js
new file mode 100644 (file)
index 0000000..2f23de3
--- /dev/null
@@ -0,0 +1,36 @@
+Ext.define('PVE.pool.Summary', {
+    extend: 'Ext.panel.Panel',
+    alias: 'widget.pvePoolSummary',
+
+    initComponent: function() {
+        var me = this;
+
+       var pool = me.pveSelNode.data.pool;
+       if (!pool) {
+           throw "no pool specified";
+       }
+
+       var statusview = Ext.create('PVE.pool.StatusView', {
+           pveSelNode: me.pveSelNode,
+           style: 'padding-top:0px'
+       });
+
+       var rstore = statusview.rstore;
+
+       Ext.apply(me, {
+           autoScroll: true,
+           bodyStyle: 'padding:10px',
+           defaults: {
+               style: 'padding-top:10px',
+               width: 800
+           },
+           items: [ statusview ]
+       });
+
+       me.on('show', rstore.startUpdate);
+       me.on('hide', rstore.stopUpdate);
+       me.on('destroy', rstore.stopUpdate);    
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/tree/ResourceTree.js b/www/manager6/tree/ResourceTree.js
new file mode 100644 (file)
index 0000000..48c1da6
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ * Left Treepanel, containing all the ressources we manage in this datacenter: server nodes, server storages, VMs and Containers
+ */
+Ext.define('PVE.tree.ResourceTree', {
+    extend: 'Ext.tree.TreePanel',
+    alias: ['widget.pveResourceTree'],
+
+    statics: {
+       typeDefaults: {
+           node: { 
+               iconCls: 'x-tree-node-server',
+               text: gettext('Node list')
+           },
+           pool: { 
+               iconCls: 'x-tree-node-pool',
+               text: gettext('Resource Pool')
+           },
+           storage: {
+               iconCls: 'x-tree-node-harddisk',
+               text: gettext('Storage list')
+           },
+           qemu: {
+               iconCls: 'x-tree-node-computer',
+               text: gettext('Virtual Machine')
+           },
+           lxc: {
+               iconCls: 'x-tree-node-lxc',
+               text: gettext('LXC Container')
+           } 
+       }
+    },
+
+    // private
+    nodeSortFn: function(node1, node2) {
+       var n1 = node1.data;
+       var n2 = node2.data;
+
+       if ((n1.groupbyid && n2.groupbyid) ||
+           !(n1.groupbyid || n2.groupbyid)) {
+
+           var tcmp;
+
+           var v1 = n1.type;
+           var v2 = n2.type;
+
+           if ((tcmp = v1 > v2 ? 1 : (v1 < v2 ? -1 : 0)) != 0) {
+               return tcmp;
+           }
+
+           // numeric compare for VM IDs
+           // sort templates after regular VMs
+           if (v1 === 'qemu' || v1 === 'lxc') {
+               if (n1.template && !n2.template) {
+                   return 1;
+               } else if (n2.template && !n1.template) {
+                   return -1;
+               }
+               v1 = n1.vmid;
+               v2 = n2.vmid;
+               if ((tcmp = v1 > v2 ? 1 : (v1 < v2 ? -1 : 0)) != 0) {
+                   return tcmp;
+               }
+           }
+
+           return n1.text > n2.text ? 1 : (n1.text < n2.text ? -1 : 0);
+       } else if (n1.groupbyid) {
+           return -1;
+       } else if (n2.groupbyid) {
+           return 1;
+       }
+    },
+
+    // private: fast binary search
+    findInsertIndex: function(node, child, start, end) {
+       var me = this;
+
+       var diff = end - start;
+
+       var mid = start + (diff>>1);
+
+       if (diff <= 0) {
+           return start;
+       }
+
+       var res = me.nodeSortFn(child, node.childNodes[mid]);
+       if (res <= 0) {
+           return me.findInsertIndex(node, child, start, mid);
+       } else {
+           return me.findInsertIndex(node, child, mid + 1, end);
+       }
+    },
+
+    setIconCls: function(info) {
+       var me = this;
+
+       var defaults = PVE.tree.ResourceTree.typeDefaults[info.type];
+       if (defaults && defaults.iconCls) {
+           var running = info.running ? '-running' : '';
+           var template = info.template ? '-template' : '';
+           info.iconCls = defaults.iconCls + running + template;
+       }
+    },
+
+    // private
+    addChildSorted: function(node, info) {
+       var me = this;
+
+       me.setIconCls(info);
+
+       var defaults;
+       if (info.groupbyid) {
+           info.text = info.groupbyid;     
+           if (info.type === 'type') {
+               defaults = PVE.tree.ResourceTree.typeDefaults[info.groupbyid];
+               if (defaults && defaults.text) {
+                   info.text = defaults.text;
+               }
+           }
+       }
+       var child = Ext.create('PVETree', info);
+
+        var cs = node.childNodes;
+       var pos;
+       if (cs) {
+           pos = cs[me.findInsertIndex(node, child, 0, cs.length)];
+       }
+
+       node.insertBefore(child, pos);
+
+       return child;
+    },
+
+    // private
+    groupChild: function(node, info, groups, level) {
+       var me = this;
+
+       var groupby = groups[level];
+       var v = info[groupby];
+
+       if (v) {
+            var group = node.findChild('groupbyid', v);
+           if (!group) {
+               var groupinfo;
+               if (info.type === groupby) {
+                   groupinfo = info;
+               } else {
+                   groupinfo = {
+                       type: groupby,
+                       id : groupby + "/" + v
+                   };
+                   if (groupby !== 'type') {
+                       groupinfo[groupby] = v;
+                   }
+               }
+               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;
+           }
+           if (group) {
+               return me.groupChild(group, info, groups, level + 1);
+           }
+       }
+
+       return me.addChildSorted(node, info);
+    },
+
+    initComponent : function() {
+       var me = this;
+
+       var rstore = PVE.data.ResourceStore;
+       var sp = Ext.state.Manager.getProvider();
+
+       if (!me.viewFilter) {
+           me.viewFilter = {};
+       }
+
+       var pdata = {
+           dataIndex: {},
+           updateCount: 0
+       };
+
+       var store = Ext.create('Ext.data.TreeStore', {
+           model: 'PVETree',
+           root: {
+               expanded: true,
+               id: 'root',
+               text: gettext('Datacenter')
+           }
+       });
+
+       var stateid = 'rid';
+
+       var updateTree = function() {
+           var tmp;
+
+           // fixme: suspend events ?
+
+           var rootnode = me.store.getRootNode();
+           
+           // remember selected node (and all parents)
+           var sm = me.getSelectionModel();
+
+           var lastsel = sm.getSelection()[0];
+           var parents = [];
+           var p = lastsel;
+           while (p && !!(p = p.parentNode)) {
+               parents.push(p);
+           }
+
+           var index = pdata.dataIndex;
+
+           var groups = me.viewFilter.groups || [];
+           var filterfn = me.viewFilter.filterfn;
+
+           // remove vanished or changed items
+           var key;
+           for (key in index) {
+               if (index.hasOwnProperty(key)) {
+                   var olditem = index[key];
+
+                   // getById() use find(), which is slow (ExtJS4 DP5) 
+                   //var item = rstore.getById(olditem.data.id);
+                   var item = rstore.data.get(olditem.data.id);
+
+                   var changed = false;
+                   if (item) {
+                       // test if any grouping attributes changed
+                       var i, len;
+                       for (i = 0, len = groups.length; i < len; i++) {
+                           var attr = groups[i];
+                           if (item.data[attr] != olditem.data[attr]) {
+                               //console.log("changed " + attr);
+                               changed = true;
+                               break;
+                           }
+                       }
+                       if ((item.data.text !== olditem.data.text) ||
+                           (item.data.node !== olditem.data.node) ||
+                           (item.data.running !== olditem.data.running) ||
+                           (item.data.template !== olditem.data.template)) {
+                           //console.log("changed node/text/running " + olditem.data.id);
+                           changed = true;
+                       }
+
+                       // fixme: also test filterfn()?
+                   }
+
+                   if (!item || changed) {
+                       //console.log("REM UID: " + key + " ITEM " + olditem.data.id);
+                       if (olditem.isLeaf()) {
+                           delete index[key];
+                           var parentNode = olditem.parentNode;
+                           parentNode.removeChild(olditem, true);
+                       } else {
+                           if (item && changed) {
+                               olditem.beginEdit();
+                               //console.log("REM UPDATE UID: " + key + " ITEM " + item.data.running);
+                               var info = olditem.data;
+                               Ext.apply(info, item.data);
+                               me.setIconCls(info);
+                               olditem.commit();
+                           }
+                       }
+                   }
+               }
+           }
+
+           // add new items
+            rstore.each(function(item) {
+               var olditem = index[item.data.id];
+               if (olditem) {
+                   return;
+               }
+
+               if (filterfn && !filterfn(item)) {
+                   return;
+               }
+
+               //console.log("ADD UID: " + item.data.id);
+
+               var info = Ext.apply({ leaf: true }, item.data);
+
+               var child = me.groupChild(rootnode, info, groups, 0);
+               if (child) {
+                   index[item.data.id] = child;
+               }
+           });
+
+           // select parent node is selection vanished
+           if (lastsel && !rootnode.findChild('id', lastsel.data.id, true)) {
+               lastsel = rootnode;
+               while (!!(p = parents.shift())) {
+                   if (!!(tmp = rootnode.findChild('id', p.data.id, true))) {
+                       lastsel = tmp;
+                       break;
+                   }
+               }
+               me.selectById(lastsel.data.id);
+           }
+
+           if (!pdata.updateCount) {
+               rootnode.collapse();
+               rootnode.expand();
+               me.applyState(sp.get(stateid));
+           }
+
+           pdata.updateCount++;
+       };
+
+       var statechange = function(sp, key, value) {
+           if (key === stateid) {
+               me.applyState(value);
+           }
+       };
+
+       sp.on('statechange', statechange);
+
+       Ext.apply(me, {
+           store: store,
+           viewConfig: {
+               // note: animate cause problems with applyState
+               animate: false
+           },
+           //useArrows: true,
+            //rootVisible: false,
+            //title: 'Resource Tree',
+           listeners: {
+               itemcontextmenu: function(v, record, item, index, event) {
+                   event.stopEvent();
+                   //v.select(record);
+                   var menu;
+                   
+                   if (record.data.type === 'qemu' && !record.data.template) {
+                       menu = Ext.create('PVE.qemu.CmdMenu', {
+                           pveSelNode: record
+                       });
+                   } else if (record.data.type === 'qemu' && record.data.template) {
+                       menu = Ext.create('PVE.qemu.TemplateMenu', {
+                           pveSelNode: record
+                       });
+                   } else if (record.data.type === 'lxc') {
+                       menu = Ext.create('PVE.lxc.CmdMenu', {
+                           pveSelNode: record
+                       });
+                   } else {
+                       return;
+                   }
+
+                   menu.showAt(event.getXY());
+               },
+               destroy: function() {
+                   rstore.un("load", updateTree);
+               }
+           },
+           setViewFilter: function(view) {
+               me.viewFilter = view;
+               me.clearTree();
+               updateTree();
+           },
+           clearTree: function() {
+               pdata.updateCount = 0;
+               var rootnode = me.store.getRootNode();
+               rootnode.collapse();
+               rootnode.removeAll(true);
+               pdata.dataIndex = {};
+               me.getSelectionModel().deselectAll();
+           },
+           selectExpand: function(node) {
+               var sm = me.getSelectionModel();
+               if (!sm.isSelected(node)) {
+                   sm.select(node);
+                   var cn = node;
+                   while (!!(cn = cn.parentNode)) {
+                       if (!cn.isExpanded()) {
+                           cn.expand();
+                       }
+                   }
+               }
+           },
+           selectById: function(nodeid) {
+               var rootnode = me.store.getRootNode();
+               var sm = me.getSelectionModel();
+               var node;
+               if (nodeid === 'root') {
+                   node = rootnode;
+               } else {
+                   node = rootnode.findChild('id', nodeid, true);
+               }
+               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);
+               }
+           },
+           applyState : function(state) {
+               var sm = me.getSelectionModel();
+               if (state && state.value) {
+                   me.selectById(state.value);
+               } else {
+                   sm.deselectAll();
+               }
+           }
+       });
+
+       me.callParent();
+
+       var sm = me.getSelectionModel();
+       sm.on('select', function(sm, n) {                   
+           sp.set(stateid, { value: n.data.id});
+       });
+
+       rstore.on("load", updateTree);
+       rstore.startUpdate();
+       //rstore.stopUpdate();
+    }
+
+});
diff --git a/www/manager6/window/Backup.js b/www/manager6/window/Backup.js
new file mode 100644 (file)
index 0000000..f7b30d5
--- /dev/null
@@ -0,0 +1,107 @@
+Ext.define('PVE.window.Backup', {
+    extend: 'Ext.window.Window',
+
+    resizable: false,
+
+    initComponent : function() {
+       var me = this;
+
+       if (!me.nodename) {
+           throw "no node name specified";
+       }
+
+       if (!me.vmid) {
+           throw "no VM ID specified";
+       }
+
+       if (!me.vmtype) {
+           throw "no VM type specified";
+       }
+
+       var storagesel = Ext.create('PVE.form.StorageSelector', {
+           nodename: me.nodename,
+           name: 'storage',
+           value: me.storage,
+           fieldLabel: gettext('Storage'),
+           storageContent: 'backup',
+           allowBlank: false
+       });
+
+       me.formPanel = Ext.create('Ext.form.Panel', {
+           bodyPadding: 10,
+           border: false,
+           fieldDefaults: {
+               labelWidth: 100,
+               anchor: '100%'
+           },
+           items: [
+               storagesel,
+               {
+                   xtype: 'pveBackupModeSelector',
+                   fieldLabel: gettext('Mode'),
+                   value: 'snapshot',
+                   name: 'mode'
+               },
+               {
+                   xtype: 'pveCompressionSelector',
+                   name: 'compress',
+                   value: 'lzo',
+                   fieldLabel: gettext('Compression')
+               }
+           ]
+       });
+
+       var form = me.formPanel.getForm();
+
+       var submitBtn = Ext.create('Ext.Button', {
+           text: gettext('Backup'),
+           handler: function(){
+               var storage = storagesel.getValue();
+               var values = form.getValues();
+               var params = {
+                   storage: storage,
+                   vmid: me.vmid,
+                   mode: values.mode,
+                   remove: 0
+               };
+               if (values.compress) {
+                   params.compress = values.compress;
+               }
+
+               PVE.Utils.API2Request({
+                   url: '/nodes/' + me.nodename + '/vzdump',
+                   params: params,
+                   method: 'POST',
+                   failure: function (response, opts) {
+                       Ext.Msg.alert('Error',response.htmlStatus);
+                   },
+                   success: function(response, options) {
+                       var upid = response.result.data;
+                       
+                       var win = Ext.create('PVE.window.TaskViewer', { 
+                           upid: upid
+                       });
+                       win.show();
+                       me.close();
+                   }
+               });
+           }
+       });
+
+       var title = gettext('Backup') + " " + 
+           ((me.vmtype === 'openvz') ? "CT" : "VM") +
+           " " + me.vmid;
+
+       Ext.apply(me, {
+           title: title,
+           width: 350,
+           modal: true,
+           layout: 'auto',
+           border: false,
+           items: [ me.formPanel ],
+           buttons: [ submitBtn ]
+       });
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/window/Edit.js b/www/manager6/window/Edit.js
new file mode 100644 (file)
index 0000000..e150cf1
--- /dev/null
@@ -0,0 +1,255 @@
+// fixme: how can we avoid those lint errors?
+/*jslint confusion: true */
+Ext.define('PVE.window.Edit', {
+    extend: 'Ext.window.Window',
+    alias: 'widget.pveWindowEdit',
+    resizable: false,
+
+    // use this tio atimatically generate a title like
+    // Create: <subject>
+    subject: undefined,
+
+    // set create to true if you want a Create button (instead 
+    // OK and RESET) 
+    create: false, 
+
+    // set to true if you want an Add button (instead of Create)
+    isAdd: false,
+
+    // set to true if you want an Remove button (instead of Create)
+    isRemove: false,
+
+    backgroundDelay: 0,
+
+    showProgress: false,
+
+    isValid: function() {
+       var me = this;
+
+       var form = me.formPanel.getForm();
+       return form.isValid();
+    },
+
+    getValues: function(dirtyOnly) {
+       var me = this;
+
+        var values = {};
+
+       var form = me.formPanel.getForm();
+
+        form.getFields().each(function(field) {
+            if (!field.up('inputpanel') && (!dirtyOnly || field.isDirty())) {
+                PVE.Utils.assemble_field_data(values, field.getSubmitData());
+            }
+        });
+
+       Ext.Array.each(me.query('inputpanel'), function(panel) {
+           PVE.Utils.assemble_field_data(values, panel.getValues(dirtyOnly));
+       });
+
+        return values;
+    },
+
+    setValues: function(values) {
+       var me = this;
+
+       var form = me.formPanel.getForm();
+
+       Ext.iterate(values, function(fieldId, val) {
+           var field = form.findField(fieldId);
+           if (field && !field.up('inputpanel')) {
+               field.setValue(val);
+                if (form.trackResetOnLoad) {
+                    field.resetOriginalValue();
+                }
+            }
+       });
+       Ext.Array.each(me.query('inputpanel'), function(panel) {
+           panel.setValues(values);
+       });
+    },
+
+    submit: function() {
+       var me = this;
+
+       var form = me.formPanel.getForm();
+
+       var values = me.getValues();
+       Ext.Object.each(values, function(name, val) {
+           if (values.hasOwnProperty(name)) {
+                if (Ext.isArray(val) && !val.length) {
+                   values[name] = '';
+               }
+           }
+       });
+
+       if (me.digest) {
+           values.digest = me.digest;
+       }
+
+       if (me.backgroundDelay) {
+           values.background_delay = me.backgroundDelay;
+       }
+
+       var url =  me.url;
+       if (me.method === 'DELETE') {
+           url = url + "?" + Ext.Object.toQueryString(values);
+           values = undefined;
+       }
+
+       PVE.Utils.API2Request({
+           url: url,
+           waitMsgTarget: me,
+           method: me.method || (me.backgroundDelay ? 'POST' : 'PUT'),
+           params: values,
+           failure: function(response, options) {
+               if (response.result && response.result.errors) {
+                   form.markInvalid(response.result.errors);
+               }
+               Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+           },
+           success: function(response, options) {
+               me.close();
+               if ((me.backgroundDelay || me.showProgress) && 
+                   response.result.data) {
+                   var upid = response.result.data;
+                   var win = Ext.create('PVE.window.TaskProgress', { 
+                       upid: upid
+                   });
+                   win.show();
+               }
+           }
+       });
+    },
+
+    load: function(options) {
+       var me = this;
+
+       var form = me.formPanel.getForm();
+
+       options = options || {};
+
+       var newopts = Ext.apply({
+           waitMsgTarget: me
+       }, options);
+
+       var createWrapper = function(successFn) {
+           Ext.apply(newopts, {
+               url: me.url,
+               method: 'GET',
+               success: function(response, opts) {
+                   form.clearInvalid();
+                   me.digest = response.result.data.digest;
+                   if (successFn) {
+                       successFn(response, opts);
+                   } else {
+                       me.setValues(response.result.data);
+                   }
+                   // hack: fix ExtJS bug
+                   Ext.Array.each(me.query('radiofield'), function(f) {
+                       f.resetOriginalValue();
+                   });
+               },
+               failure: function(response, opts) {
+                   Ext.Msg.alert(gettext('Error'), response.htmlStatus, function() {
+                       me.close();
+                   });
+               }
+           });
+       };
+
+       createWrapper(options.success);
+
+       PVE.Utils.API2Request(newopts);
+    },
+
+    initComponent : function() {
+       var me = this;
+
+       if (!me.url) {
+           throw "no url specified";
+       }
+
+       var items = Ext.isArray(me.items) ? me.items : [ me.items ];
+
+       me.items = undefined;
+
+       me.formPanel = Ext.create('Ext.form.Panel', {
+           url: me.url,
+           method: me.method || 'PUT',
+           trackResetOnLoad: true,
+           bodyPadding: 10,
+           border: false,
+           defaults: {
+               border: false
+           },
+           fieldDefaults: Ext.apply({}, me.fieldDefaults, {
+               labelWidth: 100,
+               anchor: '100%'
+            }),
+           items: items
+       });
+
+       var form = me.formPanel.getForm();
+
+       var submitBtn = Ext.create('Ext.Button', {
+           text: me.create ? (me.isAdd ? gettext('Add') : ( me.isRemove ? gettext('Remove') : gettext('Create'))) : gettext('OK'),
+           disabled: !me.create,
+           handler: function() {
+               me.submit();
+           }
+       });
+
+       var resetBtn = Ext.create('Ext.Button', {
+           text: 'Reset',
+           disabled: true,
+           handler: function(){
+               form.reset();
+           }
+       });
+
+       var set_button_status = function() {
+           var valid = form.isValid();
+           var dirty = form.isDirty();
+           submitBtn.setDisabled(!valid || !(dirty || me.create));
+           resetBtn.setDisabled(!dirty);
+       };
+
+       form.on('dirtychange', set_button_status);
+       form.on('validitychange', set_button_status);
+
+       var colwidth = 300;
+       if (me.fieldDefaults && me.fieldDefaults.labelWidth) {
+           colwidth += me.fieldDefaults.labelWidth - 100;
+       }
+       
+
+       var twoColumn = items[0].column1 || items[0].column2;
+
+       if (me.subject && !me.title) {
+           me.title = PVE.Utils.dialog_title(me.subject, me.create, me.isAdd);
+       }
+
+       if (me.create) {
+               me.buttons = [ submitBtn ] ;
+       } else {
+               me.buttons = [ submitBtn, resetBtn ];
+       }
+
+       Ext.applyIf(me, {
+           modal: true,
+           width: twoColumn ? colwidth*2 : colwidth,
+           border: false,
+           items: [ me.formPanel ],
+       });
+
+       me.callParent();
+
+       // always mark invalid fields
+       me.on('afterlayout', function() {
+           me.isValid();
+       });
+    }
+});
diff --git a/www/manager6/window/LoginWindow.js b/www/manager6/window/LoginWindow.js
new file mode 100644 (file)
index 0000000..3331444
--- /dev/null
@@ -0,0 +1,150 @@
+Ext.define('PVE.window.LoginWindow', {
+    extend: 'Ext.window.Window',
+
+    // private
+    onLogon: function() {
+       var me = this;
+
+       var form = me.getComponent(0).getForm();
+
+       if(form.isValid()){
+            me.el.mask(gettext('Please wait...'), 'x-mask-loading');
+
+           form.submit({
+               failure: function(f, resp){
+                   me.el.unmask();
+                   Ext.MessageBox.alert(gettext('Error'), 
+                                        gettext("Login failed. Please try again"), 
+                                        function() {
+                       var uf = form.findField('username');
+                       uf.focus(true, true);
+                   });
+               },
+               success: function(f, resp){
+                   me.el.unmask();
+                   
+                   var handler = me.handler || Ext.emptyFn;
+                   handler.call(me, resp.result.data);
+                   me.close();
+               }
+           });
+       }
+    },
+
+    initComponent: function() {
+       var me = this;
+
+       var otp_field = Ext.createWidget('textfield', { 
+           fieldLabel: gettext('OTP'), 
+           name: 'otp',
+           allowBlank: false,
+           hidden: true
+       });
+
+       Ext.apply(me, {
+           width: 400,
+           modal: true,
+           border: false,
+           draggable: true,
+           closable: false,
+           resizable: false,
+           layout: 'auto',
+           title: gettext('Proxmox VE Login'),
+
+           items: [{
+               xtype: 'form',
+               frame: true,
+               url: '/api2/extjs/access/ticket',
+
+               fieldDefaults: {
+                   labelAlign: 'right'
+               },
+
+               defaults: {
+                   anchor: '-5',
+                   allowBlank: false
+               },
+               
+               items: [
+                   { 
+                       xtype: 'textfield', 
+                       fieldLabel: gettext('User name'), 
+                       name: 'username',
+                       blankText: gettext("Enter your user name"),
+                       listeners: {
+                           afterrender: function(f) {
+                               // Note: only works if we pass delay 1000
+                               f.focus(true, 1000);
+                           },
+                           specialkey: function(f, e) {
+                               if (e.getKey() === e.ENTER) {
+                                   var pf = me.query('textfield[name="password"]')[0];
+                                   if (pf.getValue()) {
+                                       me.onLogon();
+                                   } else {
+                                       pf.focus(false);
+                                   }
+                               }
+                           }
+                       }
+                   },
+                   { 
+                       xtype: 'textfield', 
+                       inputType: 'password',
+                       fieldLabel: gettext('Password'), 
+                       name: 'password',
+                       blankText: gettext("Enter your password"),
+                       listeners: {
+                           specialkey: function(field, e) {
+                               if (e.getKey() === e.ENTER) {
+                                   me.onLogon();
+                               }
+                           }
+                       }
+                   },
+                   otp_field,
+                   {
+                       xtype: 'pveRealmComboBox',
+                       name: 'realm',
+                       listeners: {
+                           change: function(f, value) {
+                               if (f.needOTP(value)) {
+                                   otp_field.setVisible(true);
+                                   otp_field.setDisabled(false);
+                               } else {
+                                   otp_field.setVisible(false);
+                                   otp_field.setDisabled(true);
+                               }
+                           }
+                       }
+                   },
+                   {   
+                       xtype: 'pveLanguageSelector',
+                       fieldLabel: gettext('Language'), 
+                       value: Ext.util.Cookies.get('PVELangCookie') || 'en',
+                       name: 'lang',
+                       submitValue: false,
+                       listeners: {
+                           change: function(t, value) {
+                               var dt = Ext.Date.add(new Date(), Ext.Date.YEAR, 10);
+                               Ext.util.Cookies.set('PVELangCookie', value, dt);
+                               me.el.mask(gettext('Please wait...'), 'x-mask-loading');
+                               window.location.reload();
+                           }
+                       }
+                   }
+               ],
+               buttons: [
+                   {
+                       text: gettext('Login'),
+                       handler: function(){
+                           me.onLogon();
+                       }
+                   }
+               ]
+           }]
+       });
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/window/Migrate.js b/www/manager6/window/Migrate.js
new file mode 100644 (file)
index 0000000..322e3f6
--- /dev/null
@@ -0,0 +1,98 @@
+Ext.define('PVE.window.Migrate', {
+    extend: 'Ext.window.Window',
+
+    resizable: false,
+
+    migrate: function(target, online) {
+       var me = this;
+       PVE.Utils.API2Request({
+           params: { target: target, online: online },
+           url: '/nodes/' + me.nodename + '/' + me.vmtype + '/' + me.vmid + "/migrate",
+           waitMsgTarget: me,
+           method: 'POST',
+           failure: function(response, opts) {
+               Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+           },
+           success: function(response, options) {
+               var upid = response.result.data;
+
+               var win = Ext.create('PVE.window.TaskViewer', { 
+                   upid: upid
+               });
+               win.show();
+               me.close();
+           }
+       });
+    },
+
+    initComponent : function() {
+       var me = this;
+
+       if (!me.nodename) {
+           throw "no node name specified";
+       }
+
+       if (!me.vmid) {
+           throw "no VM ID specified";
+       }
+
+       if (!me.vmtype) {
+           throw "no VM type specified";
+       }
+
+       var running = false;
+       var vmrec = PVE.data.ResourceStore.findRecord('vmid', me.vmid,
+                                                     0, false, false, true);
+       if (vmrec && vmrec.data && vmrec.data.running) {
+           running = true;
+       }
+
+       me.formPanel = Ext.create('Ext.form.Panel', {
+           bodyPadding: 10,
+           border: false,
+           fieldDefaults: {
+               labelWidth: 100,
+               anchor: '100%'
+           },
+           items: [
+               {
+                   xtype: 'PVE.form.NodeSelector',
+                   name: 'target',
+                   fieldLabel: gettext('Target node'),
+                   allowBlank: false,
+                   onlineValidator: true
+               },
+               {
+                   xtype: 'pvecheckbox',
+                   name: 'online',
+                   uncheckedValue: 0,
+                   defaultValue: 0,
+                   checked: running,
+                   fieldLabel: gettext('Online')
+               }
+           ]
+       });
+
+       var form = me.formPanel.getForm();
+
+       var submitBtn = Ext.create('Ext.Button', {
+           text: gettext('Migrate'),
+           handler: function() {
+               var values = form.getValues();
+               me.migrate(values.target, values.online);
+           }
+       });
+
+       Ext.apply(me, {
+           title: gettext('Migrate') + ' VM ' + me.vmid,
+           width: 350,
+           modal: true,
+           layout: 'auto',
+           border: false,
+           items: [ me.formPanel ],
+           buttons: [ submitBtn ]
+       });
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/window/MigrateAll.js b/www/manager6/window/MigrateAll.js
new file mode 100644 (file)
index 0000000..fb677f5
--- /dev/null
@@ -0,0 +1,84 @@
+Ext.define('PVE.window.MigrateAll', {
+    extend: 'Ext.window.Window',
+
+    resizable: false,
+
+    migrate: function(target, maxworkers) {
+       var me = this;
+       PVE.Utils.API2Request({
+           params: { target: target, maxworkers: maxworkers},
+           url: '/nodes/' + me.nodename + '/' + "/migrateall",
+           waitMsgTarget: me,
+           method: 'POST',
+           failure: function(response, opts) {
+               Ext.Msg.alert('Error', response.htmlStatus);
+           },
+           success: function(response, options) {
+               var upid = response.result.data;
+
+               var win = Ext.create('PVE.window.TaskViewer', {
+                   upid: upid
+               });
+               win.show();
+               me.close();
+           }
+       });
+    },
+
+    initComponent : function() {
+       var me = this;
+
+       if (!me.nodename) {
+           throw "no node name specified";
+       }
+
+       me.formPanel = Ext.create('Ext.form.Panel', {
+           bodyPadding: 10,
+           border: false,
+           fieldDefaults: {
+               labelWidth: 100,
+               anchor: '100%'
+           },
+           items: [
+               {
+                   xtype: 'PVE.form.NodeSelector',
+                   name: 'target',
+                   fieldLabel: 'Target node',
+                   allowBlank: false,
+                   onlineValidator: true
+               },
+               {
+                   xtype: 'numberfield',
+                   name: 'maxworkers',
+                   minValue: 1,
+                   maxValue: 100,
+                   value: 1,
+                   fieldLabel: 'Parallel jobs',
+                   allowBlank: false
+               },
+           ]
+       });
+
+       var form = me.formPanel.getForm();
+
+       var submitBtn = Ext.create('Ext.Button', {
+           text: 'Migrate',
+           handler: function() {
+               var values = form.getValues();
+               me.migrate(values.target, values.maxworkers);
+           }
+       });
+
+       Ext.apply(me, {
+           title: "Migrate All VMs",
+           width: 350,
+           modal: true,
+           layout: 'auto',
+           border: false,
+           items: [ me.formPanel ],
+           buttons: [ submitBtn ]
+       });
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/window/NotesEdit.js b/www/manager6/window/NotesEdit.js
new file mode 100644 (file)
index 0000000..650b196
--- /dev/null
@@ -0,0 +1,24 @@
+Ext.define('PVE.window.NotesEdit', {
+    extend: 'PVE.window.Edit',
+
+    initComponent : function() {
+       var me = this;
+
+       Ext.apply(me, {
+           title: gettext('Notes'),
+           width: 600,
+           layout: 'fit',
+           items: {
+               xtype: 'textarea',
+               name: 'description',
+               rows: 7,
+               value: '',
+               hideLabel: true
+           }
+       });
+
+       me.callParent();
+
+       me.load();
+    }
+});
diff --git a/www/manager6/window/Restore.js b/www/manager6/window/Restore.js
new file mode 100644 (file)
index 0000000..b862157
--- /dev/null
@@ -0,0 +1,136 @@
+Ext.define('PVE.window.Restore', {
+    extend: 'Ext.window.Window', // fixme: PVE.window.Edit?
+
+    resizable: false,
+
+    initComponent : function() {
+       var me = this;
+
+       if (!me.nodename) {
+           throw "no node name specified";
+       }
+
+       if (!me.volid) {
+           throw "no volume ID specified";
+       }
+
+       if (!me.vmtype) {
+           throw "no vmtype specified";
+       }
+
+       var storagesel = Ext.create('PVE.form.StorageSelector', {
+           nodename: me.nodename,
+           name: 'storage',
+           value: '',
+           fieldLabel: gettext('Storage'),
+           storageContent: (me.vmtype === 'lxc') ? 'rootdir' : 'images',
+           allowBlank: true
+       });
+
+       me.formPanel = Ext.create('Ext.form.Panel', {
+           bodyPadding: 10,
+           border: false,
+           fieldDefaults: {
+               labelWidth: 100,
+               anchor: '100%'
+           },
+           items: [
+               {
+                   xtype: 'displayfield',
+                   value: me.volidText || me.volid,
+                   fieldLabel: gettext('Source')
+               },
+               storagesel,
+               {
+                   xtype: me.vmid ? 'displayfield' : 'pveVMIDSelector',
+                   name: 'vmid',
+                   fieldLabel: 'VM ID',
+                   value: me.vmid,
+                   loadNextFreeVMID: me.vmid ? false: true,
+                   validateExists: false
+               }
+           ]
+       });
+
+       var form = me.formPanel.getForm();
+
+       var doRestore = function(url, params) {
+           PVE.Utils.API2Request({
+               url: url,
+               params: params,
+               method: 'POST',
+               waitMsgTarget: me,
+               failure: function (response, opts) {
+                   Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+               },
+               success: function(response, options) {
+                   var upid = response.result.data;
+                   
+                   var win = Ext.create('PVE.window.TaskViewer', { 
+                       upid: upid
+                   });
+                   win.show();
+                   me.close();
+               }
+           });
+       };
+
+       var submitBtn = Ext.create('Ext.Button', {
+           text: gettext('Restore'),
+           handler: function(){
+               var storage = storagesel.getValue();
+               var values = form.getValues();
+
+               var params = {
+                   storage: storage,
+                   vmid: me.vmid || values.vmid,
+                   force: me.vmid ? 1 : 0
+               };
+
+               var url;
+               if (me.vmtype === 'lxc') {
+                   url = '/nodes/' + me.nodename + '/lxc';
+                   params.ostemplate = me.volid;
+                   params.restore = 1;
+               } else if (me.vmtype === 'qemu') {
+                   url = '/nodes/' + me.nodename + '/qemu';
+                   params.archive = me.volid;
+               } else {
+                   throw 'unknown VM type';
+               }
+
+               if (me.vmid) {
+                   var msg = gettext('Are you sure you want to restore this VM?') + ' ' +
+                       gettext('This will permanently erase current VM data.');
+                   Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
+                       if (btn !== 'yes') {
+                           return;
+                       }
+                       doRestore(url, params);
+                   });
+               } else {
+                   doRestore(url, params);
+               }
+           }
+       });
+
+       form.on('validitychange', function(f, valid) {
+           submitBtn.setDisabled(!valid);
+       });
+
+       var title = (me.vmtype === 'openvz') ? gettext('Restore CT') : 
+           gettext('Restore VM');
+
+       Ext.apply(me, {
+           title: title,
+           width: 500,
+           modal: true,
+           layout: 'auto',
+           border: false,
+           items: [ me.formPanel ],
+           buttons: [ submitBtn ]
+       });
+
+       me.callParent();
+    }
+});
diff --git a/www/manager6/window/TaskViewer.js b/www/manager6/window/TaskViewer.js
new file mode 100644 (file)
index 0000000..43b3cf7
--- /dev/null
@@ -0,0 +1,223 @@
+Ext.define('PVE.window.TaskProgress', {
+    extend: 'Ext.window.Window',
+    alias: 'widget.pveTaskProgress',
+
+    initComponent: function() {
+        var me = this;
+
+       if (!me.upid) {
+           throw "no task specified";
+       }
+
+       var task = PVE.Utils.parse_task_upid(me.upid);
+
+       var statstore = Ext.create('PVE.data.ObjectStore', {
+            url: "/api2/json/nodes/" + task.node + "/tasks/" + me.upid + "/status",
+           interval: 1000,
+           rows: {
+               status: { defaultValue: 'unknown' },
+               exitstatus: { defaultValue: 'unknown' }
+           }
+       });
+
+       me.on('destroy', statstore.stopUpdate); 
+
+       var getObjectValue = function(key, defaultValue) {
+           var rec = statstore.getById(key);
+           if (rec) {
+               return rec.data.value;
+           }
+           return defaultValue;
+       };
+
+       var pbar = Ext.create('Ext.ProgressBar', { text: 'running...' });
+
+       me.mon(statstore, 'load', function() {
+           var status = getObjectValue('status');
+           if (status === 'stopped') {
+               var exitstatus = getObjectValue('exitstatus');
+               if (exitstatus == 'OK') {
+                   pbar.reset();
+                   pbar.updateText("Done!");
+                   Ext.Function.defer(me.close, 1000, me);
+               } else {
+                   me.close();
+                   Ext.Msg.alert('Task failed', exitstatus);
+               }
+           }
+       });
+
+       var descr = PVE.Utils.format_task_description(task.type, task.id);
+
+       Ext.applyIf(me, {
+           title: "Task: " + descr,
+           width: 300,
+           layout: 'auto',
+           modal: true,
+           bodyPadding: 5,
+           items: pbar,
+           buttons: [
+               { 
+                   text: gettext('Details'),
+                   handler: function() {                       
+                       var win = Ext.create('PVE.window.TaskViewer', { 
+                           upid: me.upid
+                       });
+                       win.show();
+                       me.close();
+                   }
+               }
+           ]
+       });
+
+       me.callParent();
+
+       statstore.startUpdate();
+
+       pbar.wait();
+    }
+});
+
+// fixme: how can we avoid those lint errors?
+/*jslint confusion: true */
+
+Ext.define('PVE.window.TaskViewer', {
+    extend: 'Ext.window.Window',
+    alias: 'widget.pveTaskViewer',
+
+    initComponent: function() {
+        var me = this;
+
+       if (!me.upid) {
+           throw "no task specified";
+       }
+
+       var task = PVE.Utils.parse_task_upid(me.upid);
+
+       var statgrid;
+
+       var rows = {
+           status: {
+               header: gettext('Status'),
+               defaultValue: 'unknown',
+               renderer: function(value) {
+                   if (value != 'stopped') {
+                       return value;
+                   }
+                   var es = statgrid.getObjectValue('exitstatus');
+                   if (es) {
+                       return value + ': ' + es;
+                   }
+               }
+           },
+           exitstatus: { 
+               visible: false
+           },
+           type: {
+               header: gettext('Task type'),
+               required: true
+           },
+           user: {
+               header: gettext('User name'),
+               required: true 
+           },
+           node: {
+               header: gettext('Node'),
+               required: true 
+           },
+           pid: {
+               header: gettext('Process ID'),
+               required: true
+           },
+           starttime: {
+               header: gettext('Start Time'),
+               required: true, 
+               renderer: PVE.Utils.render_timestamp
+           },
+           upid: {
+               header: gettext('Unique task ID')
+           }
+       };
+
+       var statstore = Ext.create('PVE.data.ObjectStore', {
+            url: "/api2/json/nodes/" + task.node + "/tasks/" + me.upid + "/status",
+           interval: 1000,
+           rows: rows
+       });
+
+       me.on('destroy', statstore.stopUpdate); 
+
+       var stop_task = function() {
+           PVE.Utils.API2Request({
+               url: "/nodes/" + task.node + "/tasks/" + me.upid,
+               waitMsgTarget: me,
+               method: 'DELETE',
+               failure: function(response, opts) {
+                   Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+               }
+           });
+       };
+
+       var stop_btn1 = new Ext.Button({
+           text: gettext('Stop'),
+           disabled: true,
+           handler: stop_task
+       });
+
+       var stop_btn2 = new Ext.Button({
+           text: gettext('Stop'),
+           disabled: true,
+           handler: stop_task
+       });
+
+       statgrid = Ext.create('PVE.grid.ObjectGrid', {
+           title: gettext('Status'),
+           layout: 'fit',
+           tbar: [ stop_btn1 ],
+           rstore: statstore,
+           rows: rows,
+           border: false
+       });
+
+       var logView = Ext.create('PVE.panel.LogView', {
+           title: gettext('Output'),
+           tbar: [ stop_btn2 ],
+           border: false,
+           url: "/api2/extjs/nodes/" + task.node + "/tasks/" + me.upid + "/log"
+       });
+
+       me.mon(statstore, 'load', function() {
+           var status = statgrid.getObjectValue('status');
+           
+           if (status === 'stopped') {
+               logView.requestUpdate(undefined, true);
+               logView.scrollToEnd = false;
+               statstore.stopUpdate();
+           }
+
+           stop_btn1.setDisabled(status !== 'running');
+           stop_btn2.setDisabled(status !== 'running');
+       });
+
+       statstore.startUpdate();
+
+       Ext.applyIf(me, {
+           title: "Task viewer: " + task.desc,
+           width: 800,
+           height: 400,
+           layout: 'fit',
+           modal: true,
+           bodyPadding: 5,
+           items: [{
+               xtype: 'tabpanel',
+               region: 'center',
+               items: [ logView, statgrid ]
+           }]
+        });
+
+       me.callParent();
+
+       logView.fireEvent('show', logView);
+    }
+});
+
diff --git a/www/manager6/window/Wizard.js b/www/manager6/window/Wizard.js
new file mode 100644 (file)
index 0000000..0e6b02d
--- /dev/null
@@ -0,0 +1,245 @@
+Ext.define('PVE.window.Wizard', {
+    extend: 'Ext.window.Window',
+    
+    getValues: function(dirtyOnly) {
+       var me = this;
+
+        var values = {};
+
+       var form = me.down('form').getForm();
+
+        form.getFields().each(function(field) {
+            if (!field.up('inputpanel') && (!dirtyOnly || field.isDirty())) {
+                PVE.Utils.assemble_field_data(values, field.getSubmitData());
+            }
+        });
+
+       Ext.Array.each(me.query('inputpanel'), function(panel) {
+           PVE.Utils.assemble_field_data(values, panel.getValues(dirtyOnly));
+       });
+
+        return values;
+    },
+
+    initComponent: function() {
+       var me = this;
+
+       var tabs = me.items || [];
+       delete me.items;
+       
+       /* 
+        * Items may have the following functions:
+        * validator(): per tab custom validation
+        * onSubmit(): submit handler
+        * onGetValues(): overwrite getValues results
+        */
+
+       Ext.Array.each(tabs, function(tab) {
+           tab.disabled = true;
+       });
+       tabs[0].disabled = false;
+
+       var check_card = function(card) {
+           var valid = true;
+           var fields = card.query('field, fieldcontainer');
+           if (card.isXType('fieldcontainer')) {
+               fields.unshift(card);
+           }
+           Ext.Array.each(fields, function(field) {
+               // Note: not all fielcontainer have isValid()
+               if (Ext.isFunction(field.isValid) && !field.isValid()) {
+                   valid = false;
+               }
+           });
+
+           if (Ext.isFunction(card.validator)) {
+               return card.validator();
+           }
+
+           return valid;
+       };
+
+
+       var tbar = Ext.create('Ext.toolbar.Toolbar', {
+            ui: 'footer',
+           region: 'south',
+           margins: '0 5 5 5',
+           items: [  
+               '->', 
+               { 
+                   text: gettext('Back'),
+                   disabled: true,
+                   itemId: 'back',
+                   minWidth: 60,
+                   handler: function() {
+                       var tp = me.down('#wizcontent');
+                       var atab = tp.getActiveTab();
+                       var prev = tp.items.indexOf(atab) - 1;
+                       if (prev < 0) {
+                           return;
+                       }
+                       var ntab = tp.items.getAt(prev);
+                       if (ntab) {
+                           tp.setActiveTab(ntab);
+                       }
+
+
+                   }
+               },
+               {
+                   text: gettext('Next'),
+                   disabled: true,
+                   itemId: 'next',
+                   minWidth: 60,
+                   handler: function() {
+
+                       var form = me.down('form').getForm();
+
+                       var tp = me.down('#wizcontent');
+                       var atab = tp.getActiveTab();
+                       if (!check_card(atab)) {
+                           return;
+                       }
+                                      
+                       var next = tp.items.indexOf(atab) + 1;
+                       var ntab = tp.items.getAt(next);
+                       if (ntab) {
+                           ntab.enable();
+                           tp.setActiveTab(ntab);
+                       }
+                       
+                   }
+               },
+               {
+                   text: gettext('Finish'),
+                   minWidth: 60,
+                   hidden: true,
+                   itemId: 'submit',
+                   handler: function() {
+                       var tp = me.down('#wizcontent');
+                       var atab = tp.getActiveTab();
+                       atab.onSubmit();
+                   }
+               }
+           ]
+       });
+
+       var display_header = function(newcard) {
+           var html = '<h1>' + newcard.title + '</h1>';
+           if (newcard.descr) {
+               html += newcard.descr;
+           }
+           me.down('#header').update(html);
+       };
+
+       var disable_at = function(card) {
+           var tp = me.down('#wizcontent');
+           var idx = tp.items.indexOf(card);
+           for(;idx < tp.items.getCount();idx++) {
+               var nc = tp.items.getAt(idx);
+               if (nc) {
+                   nc.disable();
+               }
+           }
+       };
+
+       var tabchange = function(tp, newcard, oldcard) {
+           if (newcard.onSubmit) {
+               me.down('#next').setVisible(false);
+               me.down('#submit').setVisible(true); 
+           } else {
+               me.down('#next').setVisible(true);
+               me.down('#submit').setVisible(false); 
+           }
+           var valid = check_card(newcard);
+           me.down('#next').setDisabled(!valid);    
+           me.down('#submit').setDisabled(!valid);    
+           me.down('#back').setDisabled(tp.items.indexOf(newcard) == 0);
+
+           if (oldcard && !check_card(oldcard)) {
+               disable_at(oldcard);
+           }
+
+           var next = tp.items.indexOf(newcard) + 1;
+           var ntab = tp.items.getAt(next);
+           if (valid && ntab && !newcard.onSubmit) {
+               ntab.enable();
+           }
+       };
+
+       if (me.subject && !me.title) {
+           me.title = PVE.Utils.dialog_title(me.subject, true, false);
+       }
+
+       Ext.applyIf(me, {
+           width: 620,
+           height: 400,
+           modal: true,
+           border: false,
+           draggable: true,
+           closable: true,
+           resizable: false,
+           layout: 'border',
+           items: [
+               {
+                   // disabled for now - not really needed
+                   hidden: true, 
+                   region: 'north',
+                   itemId: 'header',
+                   layout: 'fit',
+                   margins: '5 5 0 5',
+                   bodyPadding: 10,
+                   html: ''
+               },
+               {
+                   xtype: 'form',
+                   region: 'center',
+                   layout: 'fit',
+                   border: false,
+                   margins: '5 5 0 5',
+                   fieldDefaults: {
+                       labelWidth: 100,
+                       anchor: '100%'
+                   },
+                   items: [{
+                       itemId: 'wizcontent',
+                       xtype: 'tabpanel',
+                       activeItem: 0,
+                       bodyPadding: 10,
+                       listeners: {
+                           afterrender: function(tp) {
+                               var atab = this.getActiveTab();
+                               tabchange(tp, atab);
+                           },
+                           tabchange: function(tp, newcard, oldcard) {
+                               display_header(newcard);
+                               tabchange(tp, newcard, oldcard);
+                           }
+                       },
+                       items: tabs
+                   }]
+               },
+               tbar
+           ]
+       });
+       me.callParent();
+       display_header(tabs[0]);
+
+       Ext.Array.each(me.query('field'), function(field) {
+           field.on('validitychange', function(f) {
+               var tp = me.down('#wizcontent');
+               var atab = tp.getActiveTab();
+               var valid = check_card(atab);
+               me.down('#next').setDisabled(!valid);
+               me.down('#submit').setDisabled(!valid);    
+               var next = tp.items.indexOf(atab) + 1;
+               var ntab = tp.items.getAt(next);
+               if (!valid) {
+                   disable_at(ntab);
+               } else if (ntab && !atab.onSubmit) {
+                   ntab.enable();
+               }
+           });
+       });
+    }
+});