remove old www/manager dir
This commit is contained in:
parent
8748401747
commit
b8571c2958
1
www/manager/.gitignore
vendored
1
www/manager/.gitignore
vendored
@ -1 +0,0 @@
|
||||
pvemanagerlib.js
|
@ -1,224 +0,0 @@
|
||||
include ../../defines.mk
|
||||
|
||||
JSSRC= \
|
||||
Utils.js \
|
||||
Toolkit.js \
|
||||
Parser.js \
|
||||
StateProvider.js \
|
||||
button/Button.js \
|
||||
button/ConsoleButton.js \
|
||||
qemu/SendKeyMenu.js \
|
||||
qemu/CmdMenu.js \
|
||||
qemu/TemplateMenu.js \
|
||||
lxc/CmdMenu.js \
|
||||
VNCConsole.js \
|
||||
data/TimezoneStore.js \
|
||||
data/reader/JsonObject.js \
|
||||
data/PVEProxy.js \
|
||||
data/UpdateQueue.js \
|
||||
data/UpdateStore.js \
|
||||
data/DiffStore.js \
|
||||
data/ObjectStore.js \
|
||||
data/ResourceStore.js \
|
||||
form/VLanField.js \
|
||||
form/Checkbox.js \
|
||||
form/TextField.js \
|
||||
form/RRDTypeSelector.js \
|
||||
form/ComboGrid.js \
|
||||
form/KVComboBox.js \
|
||||
form/Boolean.js \
|
||||
form/CompressionSelector.js \
|
||||
form/PoolSelector.js \
|
||||
form/GroupSelector.js \
|
||||
form/UserSelector.js \
|
||||
form/RoleSelector.js \
|
||||
form/VMIDSelector.js \
|
||||
form/MemoryField.js \
|
||||
form/NetworkCardSelector.js \
|
||||
form/DiskFormatSelector.js \
|
||||
form/BusTypeSelector.js \
|
||||
form/ControllerSelector.js \
|
||||
form/EmailNotificationSelector.js \
|
||||
form/RealmComboBox.js \
|
||||
form/BondModeSelector.js \
|
||||
form/ViewSelector.js \
|
||||
form/NodeSelector.js \
|
||||
form/FileSelector.js \
|
||||
form/StorageSelector.js \
|
||||
form/BridgeSelector.js \
|
||||
form/SecurityGroupSelector.js \
|
||||
form/IPRefSelector.js \
|
||||
form/IPProtocolSelector.js \
|
||||
form/CPUModelSelector.js \
|
||||
form/VNCKeyboardSelector.js \
|
||||
form/LanguageSelector.js \
|
||||
form/DisplaySelector.js \
|
||||
form/CacheTypeSelector.js \
|
||||
form/SnapshotSelector.js \
|
||||
form/ContentTypeSelector.js \
|
||||
form/HotplugFeatureSelector.js \
|
||||
form/iScsiProviderSelector.js \
|
||||
form/DayOfWeekSelector.js \
|
||||
form/BackupModeSelector.js \
|
||||
form/ScsiHwSelector.js \
|
||||
form/FirewallPolicySelector.js \
|
||||
form/QemuBiosSelector.js \
|
||||
dc/Tasks.js \
|
||||
dc/Log.js \
|
||||
panel/StatusPanel.js \
|
||||
panel/RRDView.js \
|
||||
panel/InputPanel.js \
|
||||
window/Edit.js \
|
||||
window/LoginWindow.js \
|
||||
window/TaskViewer.js \
|
||||
window/Wizard.js \
|
||||
window/NotesEdit.js \
|
||||
window/Backup.js \
|
||||
window/Restore.js \
|
||||
panel/NotesView.js \
|
||||
grid/CheckColumn.js \
|
||||
grid/SelectFeature.js \
|
||||
grid/ObjectGrid.js \
|
||||
grid/PendingObjectGrid.js \
|
||||
grid/ResourceGrid.js \
|
||||
grid/PoolMembers.js \
|
||||
grid/FirewallRules.js \
|
||||
grid/FirewallAliases.js \
|
||||
grid/FirewallOptions.js \
|
||||
tree/ResourceTree.js \
|
||||
panel/IPSet.js \
|
||||
panel/ConfigPanel.js \
|
||||
panel/SubConfigPanel.js \
|
||||
grid/BackupView.js \
|
||||
panel/LogView.js \
|
||||
panel/Firewall.js \
|
||||
ceph/Pool.js \
|
||||
ceph/OSD.js \
|
||||
ceph/Disks.js \
|
||||
ceph/Monitor.js \
|
||||
ceph/Crush.js \
|
||||
ceph/Status.js \
|
||||
ceph/Config.js \
|
||||
node/DNSEdit.js \
|
||||
node/DNSView.js \
|
||||
node/TimeView.js \
|
||||
node/TimeEdit.js \
|
||||
node/StatusView.js \
|
||||
node/Summary.js \
|
||||
node/ServiceView.js \
|
||||
node/NetworkEdit.js \
|
||||
node/NetworkView.js \
|
||||
node/Tasks.js \
|
||||
node/Subscription.js \
|
||||
node/APT.js \
|
||||
node/Config.js \
|
||||
qemu/StatusView.js \
|
||||
window/Migrate.js \
|
||||
window/MigrateAll.js \
|
||||
qemu/Monitor.js \
|
||||
qemu/Summary.js \
|
||||
qemu/OSTypeEdit.js \
|
||||
qemu/ProcessorEdit.js \
|
||||
qemu/BootOrderEdit.js \
|
||||
qemu/MemoryEdit.js \
|
||||
qemu/NetworkEdit.js \
|
||||
qemu/Smbios1Edit.js \
|
||||
qemu/CDEdit.js \
|
||||
qemu/HDEdit.js \
|
||||
qemu/HDResize.js \
|
||||
qemu/HDMove.js \
|
||||
qemu/HDThrottle.js \
|
||||
qemu/CPUOptions.js \
|
||||
qemu/DisplayEdit.js \
|
||||
qemu/KeyboardEdit.js \
|
||||
qemu/HardwareView.js \
|
||||
qemu/StartupEdit.js \
|
||||
qemu/ScsiHwEdit.js \
|
||||
qemu/QemuBiosEdit.js \
|
||||
qemu/Options.js \
|
||||
qemu/Snapshot.js \
|
||||
qemu/Clone.js \
|
||||
qemu/SnapshotTree.js \
|
||||
qemu/Config.js \
|
||||
qemu/CreateWizard.js \
|
||||
lxc/StatusView.js \
|
||||
lxc/Summary.js \
|
||||
lxc/Network.js \
|
||||
lxc/Resources.js \
|
||||
lxc/Options.js \
|
||||
lxc/DNS.js \
|
||||
lxc/Config.js \
|
||||
lxc/CreateWizard.js \
|
||||
lxc/SnapshotTree.js \
|
||||
lxc/Snapshot.js \
|
||||
lxc/ResourceEdit.js \
|
||||
lxc/MPResize.js \
|
||||
pool/StatusView.js \
|
||||
pool/Summary.js \
|
||||
pool/Config.js \
|
||||
storage/ContentView.js \
|
||||
storage/StatusView.js \
|
||||
storage/Summary.js \
|
||||
storage/Browser.js \
|
||||
storage/DirEdit.js \
|
||||
storage/NFSEdit.js \
|
||||
storage/GlusterFsEdit.js \
|
||||
storage/IScsiEdit.js \
|
||||
storage/LVMEdit.js \
|
||||
storage/LvmThinEdit.js \
|
||||
storage/RBDEdit.js \
|
||||
storage/SheepdogEdit.js \
|
||||
storage/ZFSEdit.js \
|
||||
storage/ZFSPoolEdit.js \
|
||||
ha/StatusView.js \
|
||||
ha/GroupSelector.js \
|
||||
ha/ResourceEdit.js \
|
||||
ha/Resources.js \
|
||||
ha/GroupEdit.js \
|
||||
ha/Groups.js \
|
||||
ha/Fencing.js \
|
||||
ha/Config.js \
|
||||
dc/Summary.js \
|
||||
dc/OptionView.js \
|
||||
dc/StorageView.js \
|
||||
dc/UserEdit.js \
|
||||
dc/UserView.js \
|
||||
dc/PoolView.js \
|
||||
dc/PoolEdit.js \
|
||||
dc/GroupView.js \
|
||||
dc/GroupEdit.js \
|
||||
dc/RoleView.js \
|
||||
dc/ACLView.js \
|
||||
dc/AuthView.js \
|
||||
dc/AuthEdit.js \
|
||||
dc/Backup.js \
|
||||
dc/Support.js \
|
||||
dc/SecurityGroups.js \
|
||||
dc/Config.js \
|
||||
Workspace.js
|
||||
|
||||
lint: ${JSSRC}
|
||||
jslint ${JSSRC}
|
||||
|
||||
pvemanagerlib.js: ${JSSRC}
|
||||
cat ${JSSRC} >$@.tmp
|
||||
mv $@.tmp $@
|
||||
|
||||
all: pvemanagerlib.js
|
||||
|
||||
.PHONY: install
|
||||
install: pvemanagerlib.js
|
||||
install -d ${WWWBASEDIR}/root
|
||||
install -d ${WWWEXT4DIR}
|
||||
install -m 0644 -o www-data -g www-data pvemanagerlib.js ${WWWEXT4DIR}
|
||||
|
||||
.PHONY: distclean
|
||||
distclean: clean
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
find . -name '*~' -exec rm {} ';'
|
||||
rm -rf pvemanagerlib.js
|
||||
|
||||
|
||||
|
@ -1,483 +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
|
||||
|
||||
parseBoolean: function(value, default_value) {
|
||||
if (!Ext.isDefined(value))
|
||||
return default_value;
|
||||
value = value.toLowerCase();
|
||||
return value === 1 || value === '1' ||
|
||||
value === 'on' ||
|
||||
value === 'yes' ||
|
||||
value === 'true';
|
||||
},
|
||||
|
||||
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(',');
|
||||
},
|
||||
|
||||
parseLxcMountPoint: function(value) {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
|
||||
var res = {};
|
||||
|
||||
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];
|
||||
|
||||
res[k] = v;
|
||||
});
|
||||
|
||||
if (errors || !res.file) {
|
||||
return;
|
||||
}
|
||||
|
||||
var m = res.file.match(/^([a-z][a-z0-9\-\_\.]*[a-z0-9]):/i);
|
||||
if (m) {
|
||||
res.storage = m[1];
|
||||
res.type = 'volume';
|
||||
} else if (res.file.match(/^\/dev\//)) {
|
||||
res.type = 'device';
|
||||
} else {
|
||||
res.type = 'bind';
|
||||
}
|
||||
|
||||
return res;
|
||||
},
|
||||
|
||||
printLxcMountPoint: function(mp) {
|
||||
var drivestr = mp.file;
|
||||
|
||||
Ext.Object.each(mp, function(key, value) {
|
||||
if (!Ext.isDefined(value) || key === 'file' ||
|
||||
key === 'type' || key === 'storage') {
|
||||
return; // continue
|
||||
}
|
||||
drivestr += ',' + key + '=' + value;
|
||||
});
|
||||
|
||||
return drivestr;
|
||||
},
|
||||
|
||||
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;
|
||||
},
|
||||
|
||||
parseQemuCpu: function(value) {
|
||||
if (!value) {
|
||||
return {};
|
||||
}
|
||||
|
||||
var res = {};
|
||||
|
||||
var errors = false;
|
||||
Ext.Array.each(value.split(','), function(p) {
|
||||
if (!p || p.match(/^\s*$/)) {
|
||||
return; // continue
|
||||
}
|
||||
|
||||
if (!p.match(/=/)) {
|
||||
if (Ext.isDefined(res['cpu'])) {
|
||||
errors = true;
|
||||
return false; // break
|
||||
}
|
||||
res.cputype = p;
|
||||
return; // continue
|
||||
}
|
||||
|
||||
var match_res = p.match(/^([a-z_]+)=(\S+)$/);
|
||||
if (!match_res) {
|
||||
errors = true;
|
||||
return false; // break
|
||||
}
|
||||
|
||||
var k = match_res[1];
|
||||
if (Ext.isDefined(res[k])) {
|
||||
errors = true;
|
||||
return false; // break
|
||||
}
|
||||
|
||||
res[k] = match_res[2];
|
||||
});
|
||||
|
||||
if (errors || !res.cputype) {
|
||||
return;
|
||||
}
|
||||
|
||||
return res;
|
||||
},
|
||||
|
||||
printQemuCpu: function(cpu) {
|
||||
var cpustr = cpu.cputype;
|
||||
var optstr = '';
|
||||
|
||||
Ext.Object.each(cpu, function(key, value) {
|
||||
if (!Ext.isDefined(value) || key === 'cputype') {
|
||||
return; // continue
|
||||
}
|
||||
optstr += ',' + key + '=' + value;
|
||||
});
|
||||
|
||||
if (!cpustr) {
|
||||
if (optstr)
|
||||
return 'kvm64' + optstr;
|
||||
return;
|
||||
}
|
||||
|
||||
return cpustr + optstr;
|
||||
},
|
||||
}});
|
@ -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);
|
||||
}
|
||||
}
|
||||
});
|
@ -1,262 +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@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'),
|
||||
|
||||
// workaround for https://www.sencha.com/forum/showthread.php?302150
|
||||
pveMail: function(v) {
|
||||
return (/^(\w+)([\-+.][\w]+)*@(\w[\-\w]*\.){1,5}([A-Za-z]){2,63}$/).test(v);
|
||||
},
|
||||
pveMailText: gettext('This field should be an e-mail address in the format "user@example.com"'),
|
||||
});
|
||||
|
||||
// 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" allowfullscreen="true"></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);
|
||||
}
|
||||
}
|
||||
});
|
1110
www/manager/Utils.js
1110
www/manager/Utils.js
File diff suppressed because it is too large
Load Diff
@ -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();
|
||||
}
|
||||
});
|
@ -1,444 +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();
|
||||
}
|
||||
});
|
||||
|
||||
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('<span class="x-panel-header-text">Proxmox Virtual Environment<br>' + gettext('Version') + ': ' + version + "</span>");
|
||||
} else {
|
||||
ui.update('<span class="x-panel-header-text">Proxmox Virtual Environment</span>');
|
||||
}
|
||||
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',
|
||||
margins: '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',
|
||||
margins: '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',
|
||||
align : 'middle'
|
||||
},
|
||||
baseCls: 'x-plain',
|
||||
defaults: {
|
||||
baseCls: 'x-plain'
|
||||
},
|
||||
border: false,
|
||||
margins: '2 0 5 0',
|
||||
items: [
|
||||
{
|
||||
margins: '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: '<span class="x-panel-header-text">Proxmox Virtual Environment</span>'
|
||||
},
|
||||
{
|
||||
pack: 'end',
|
||||
margins: '8 10 0 10',
|
||||
id: 'userinfo',
|
||||
stateful: false
|
||||
},
|
||||
{
|
||||
pack: 'end',
|
||||
margins: '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,
|
||||
margins: '0 5 0 0',
|
||||
items: []
|
||||
},
|
||||
{
|
||||
region: 'west',
|
||||
xtype: 'container',
|
||||
border: false,
|
||||
layout: { type: 'vbox', align: 'stretch' },
|
||||
margins: '0 0 0 5',
|
||||
split: true,
|
||||
width: 200,
|
||||
items: [ selview, rtree ]
|
||||
},
|
||||
{
|
||||
xtype: 'pveStatusPanel',
|
||||
region: 'south',
|
||||
margins:'0 5 5 5',
|
||||
height: 200,
|
||||
split:true
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
me.updateUserInfo();
|
||||
}
|
||||
});
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
@ -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();
|
||||
}
|
||||
});
|
@ -1,175 +0,0 @@
|
||||
Ext.define('PVE.node.CephConfig', {
|
||||
extend: 'Ext.panel.Panel',
|
||||
alias: ['widget.pveNodeCephConfig'],
|
||||
|
||||
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;
|
||||
me.update(Ext.htmlEncode(data));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
var nodename = me.pveSelNode.data.node;
|
||||
if (!nodename) {
|
||||
throw "no node name specified";
|
||||
}
|
||||
|
||||
Ext.apply(me, {
|
||||
url: '/nodes/' + nodename + '/ceph/config',
|
||||
bodyStyle: 'white-space:pre',
|
||||
bodyPadding: 5,
|
||||
autoScroll: true,
|
||||
listeners: {
|
||||
show: function() {
|
||||
me.load();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
me.load();
|
||||
}
|
||||
});
|
||||
|
||||
Ext.define('PVE.node.Ceph', {
|
||||
extend: 'Ext.tab.Panel',
|
||||
alias: ['widget.pveNodeCeph'],
|
||||
|
||||
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 = 'ceph';
|
||||
} else {
|
||||
ntab = 'ceph-' + itemId;
|
||||
}
|
||||
|
||||
return { value: ntab };
|
||||
},
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
var nodename = me.pveSelNode.data.node;
|
||||
if (!nodename) {
|
||||
throw "no node name specified";
|
||||
}
|
||||
|
||||
if (!me.phstateid) {
|
||||
throw "no parent history state specified";
|
||||
}
|
||||
|
||||
var sp = Ext.state.Manager.getProvider();
|
||||
var state = sp.get(me.phstateid);
|
||||
var hsregex = /^ceph-(\S+)$/;
|
||||
|
||||
if (state && state.value) {
|
||||
var res = hsregex.exec(state.value);
|
||||
if (res && res[1]) {
|
||||
me.activeTab = res[1];
|
||||
}
|
||||
}
|
||||
|
||||
Ext.apply(me, {
|
||||
plain: true,
|
||||
tabPosition: 'bottom',
|
||||
defaults: {
|
||||
border: false,
|
||||
pveSelNode: me.pveSelNode
|
||||
},
|
||||
items: [
|
||||
{
|
||||
xtype: 'pveNodeCephStatus',
|
||||
title: gettext('Status'),
|
||||
itemId: 'status'
|
||||
},
|
||||
{
|
||||
xtype: 'pveNodeCephConfig',
|
||||
title: gettext('Config'),
|
||||
itemId: 'config'
|
||||
},
|
||||
{
|
||||
xtype: 'pveNodeCephMonList',
|
||||
title: gettext('Monitor'),
|
||||
itemId: 'monlist'
|
||||
},
|
||||
{
|
||||
xtype: 'pveNodeCephDiskList',
|
||||
title: gettext('Disks'),
|
||||
itemId: 'disklist'
|
||||
},
|
||||
{
|
||||
xtype: 'pveNodeCephOsdTree',
|
||||
title: 'OSD',
|
||||
itemId: 'osdtree'
|
||||
},
|
||||
{
|
||||
xtype: 'pveNodeCephPoolList',
|
||||
title: gettext('Pools'),
|
||||
itemId: 'pools'
|
||||
},
|
||||
{
|
||||
title: 'Crush',
|
||||
xtype: 'pveNodeCephCrushMap',
|
||||
itemId: 'crushmap'
|
||||
},
|
||||
{
|
||||
title: gettext('Log'),
|
||||
itemId: 'log',
|
||||
xtype: 'pveLogView',
|
||||
url: "/api2/extjs/nodes/" + nodename + "/ceph/log"
|
||||
}
|
||||
],
|
||||
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);
|
||||
}
|
||||
});
|
@ -1,45 +0,0 @@
|
||||
Ext.define('PVE.node.CephCrushMap', {
|
||||
extend: 'Ext.panel.Panel',
|
||||
alias: ['widget.pveNodeCephCrushMap'],
|
||||
|
||||
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;
|
||||
me.update(Ext.htmlEncode(data));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
var nodename = me.pveSelNode.data.node;
|
||||
if (!nodename) {
|
||||
throw "no node name specified";
|
||||
}
|
||||
|
||||
Ext.apply(me, {
|
||||
url: '/nodes/' + nodename + '/ceph/crush',
|
||||
bodyStyle: 'white-space:pre',
|
||||
bodyPadding: 5,
|
||||
autoScroll: true,
|
||||
listeners: {
|
||||
show: function() {
|
||||
me.load();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
me.load();
|
||||
}
|
||||
});
|
@ -1,189 +0,0 @@
|
||||
|
||||
Ext.define('PVE.node.CephDiskList', {
|
||||
extend: 'Ext.grid.GridPanel',
|
||||
alias: ['widget.pveNodeCephDiskList'],
|
||||
|
||||
initComponent: function() {
|
||||
/*jslint confusion: true */
|
||||
var me = this;
|
||||
|
||||
var nodename = me.pveSelNode.data.node;
|
||||
if (!nodename) {
|
||||
throw "no node name specified";
|
||||
}
|
||||
|
||||
var sm = Ext.create('Ext.selection.RowModel', {});
|
||||
|
||||
var rstore = Ext.create('PVE.data.UpdateStore', {
|
||||
interval: 3000,
|
||||
storeid: 'ceph-disk-list',
|
||||
model: 'ceph-disk-list',
|
||||
proxy: {
|
||||
type: 'pve',
|
||||
url: "/api2/json/nodes/" + nodename + "/ceph/disks"
|
||||
},
|
||||
sorters: [
|
||||
{
|
||||
property : 'dev',
|
||||
direction: 'ASC'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
var store = Ext.create('PVE.data.DiffStore', { rstore: rstore });
|
||||
|
||||
PVE.Utils.monStoreErrors(me, rstore);
|
||||
|
||||
var create_btn = new PVE.button.Button({
|
||||
text: gettext('Create') + ': OSD',
|
||||
selModel: sm,
|
||||
disabled: true,
|
||||
enableFn: function(rec) {
|
||||
return !rec.data.used;
|
||||
},
|
||||
handler: function() {
|
||||
var rec = sm.getSelection()[0];
|
||||
|
||||
var win = Ext.create('PVE.CephCreateOsd', {
|
||||
nodename: nodename,
|
||||
dev: rec.data.dev
|
||||
});
|
||||
win.show();
|
||||
}
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
store: store,
|
||||
selModel: sm,
|
||||
stateful: false,
|
||||
tbar: [ create_btn ],
|
||||
columns: [
|
||||
{
|
||||
header: gettext('Device'),
|
||||
width: 100,
|
||||
sortable: true,
|
||||
dataIndex: 'dev'
|
||||
},
|
||||
{
|
||||
header: gettext('Usage'),
|
||||
width: 80,
|
||||
sortable: false,
|
||||
renderer: function(v, metaData, rec) {
|
||||
if (rec && (rec.data.osdid >= 0)) {
|
||||
return "osd." + rec.data.osdid;
|
||||
}
|
||||
return v || PVE.Utils.noText;
|
||||
},
|
||||
dataIndex: 'used'
|
||||
},
|
||||
{
|
||||
header: gettext('Size'),
|
||||
width: 100,
|
||||
align: 'right',
|
||||
sortable: false,
|
||||
renderer: PVE.Utils.format_size,
|
||||
dataIndex: 'size'
|
||||
},
|
||||
{
|
||||
header: gettext('Vendor'),
|
||||
width: 100,
|
||||
sortable: true,
|
||||
dataIndex: 'vendor'
|
||||
},
|
||||
{
|
||||
header: gettext('Model'),
|
||||
width: 200,
|
||||
sortable: true,
|
||||
dataIndex: 'model'
|
||||
},
|
||||
{
|
||||
header: gettext('Serial'),
|
||||
flex: 1,
|
||||
sortable: true,
|
||||
dataIndex: 'serial'
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
show: rstore.startUpdate,
|
||||
hide: rstore.stopUpdate,
|
||||
destroy: rstore.stopUpdate
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
}, function() {
|
||||
|
||||
Ext.define('ceph-disk-list', {
|
||||
extend: 'Ext.data.Model',
|
||||
fields: [ 'dev', 'used', { name: 'size', type: 'number'},
|
||||
{name: 'osdid', type: 'number'},
|
||||
'vendor', 'model', 'serial'],
|
||||
idProperty: 'dev'
|
||||
});
|
||||
});
|
||||
|
||||
Ext.define('PVE.form.CephDiskSelector', {
|
||||
extend: 'PVE.form.ComboGrid',
|
||||
alias: ['widget.pveCephDiskSelector'],
|
||||
|
||||
diskType: 'journal_disks',
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
var nodename = me.nodename;
|
||||
if (!nodename) {
|
||||
throw "no node name specified";
|
||||
}
|
||||
|
||||
var store = Ext.create('Ext.data.Store', {
|
||||
filterOnLoad: true,
|
||||
model: 'ceph-disk-list',
|
||||
proxy: {
|
||||
type: 'pve',
|
||||
url: "/api2/json/nodes/" + nodename + "/ceph/disks",
|
||||
extraParams: { type: me.diskType }
|
||||
},
|
||||
sorters: [
|
||||
{
|
||||
property : 'dev',
|
||||
direction: 'ASC'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
store: store,
|
||||
valueField: 'dev',
|
||||
displayField: 'dev',
|
||||
listConfig: {
|
||||
columns: [
|
||||
{
|
||||
header: gettext('Device'),
|
||||
width: 80,
|
||||
sortable: true,
|
||||
dataIndex: 'dev'
|
||||
},
|
||||
{
|
||||
header: gettext('Size'),
|
||||
width: 60,
|
||||
sortable: false,
|
||||
renderer: PVE.Utils.format_size,
|
||||
dataIndex: 'size'
|
||||
},
|
||||
{
|
||||
header: gettext('Serial'),
|
||||
flex: 1,
|
||||
sortable: true,
|
||||
dataIndex: 'serial'
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
store.load();
|
||||
}
|
||||
});
|
@ -1,207 +0,0 @@
|
||||
Ext.define('PVE.CephCreateMon', {
|
||||
extend: 'PVE.window.Edit',
|
||||
alias: ['widget.pveCephCreateMon'],
|
||||
|
||||
subject: 'Ceph Monitor',
|
||||
|
||||
showProgress: true,
|
||||
|
||||
setNode: function(nodename) {
|
||||
var me = this;
|
||||
|
||||
me.nodename = nodename;
|
||||
me.url = "/nodes/" + nodename + "/ceph/mon";
|
||||
},
|
||||
|
||||
initComponent : function() {
|
||||
/*jslint confusion: true */
|
||||
var me = this;
|
||||
|
||||
if (!me.nodename) {
|
||||
throw "no node name specified";
|
||||
}
|
||||
|
||||
me.setNode(me.nodename);
|
||||
|
||||
me.create = true;
|
||||
|
||||
Ext.applyIf(me, {
|
||||
method: 'POST',
|
||||
items: [
|
||||
{
|
||||
xtype: 'PVE.form.NodeSelector',
|
||||
submitValue: false,
|
||||
fieldLabel: gettext('Host'),
|
||||
selectCurNode: true,
|
||||
allowBlank: false,
|
||||
listeners: {
|
||||
change: function(f, value) {
|
||||
me.setNode(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
||||
|
||||
Ext.define('PVE.node.CephMonList', {
|
||||
extend: 'Ext.grid.GridPanel',
|
||||
alias: ['widget.pveNodeCephMonList'],
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
var nodename = me.pveSelNode.data.node;
|
||||
if (!nodename) {
|
||||
throw "no node name specified";
|
||||
}
|
||||
|
||||
var sm = Ext.create('Ext.selection.RowModel', {});
|
||||
|
||||
var rstore = Ext.create('PVE.data.UpdateStore', {
|
||||
interval: 3000,
|
||||
storeid: 'ceph-mon-list',
|
||||
model: 'ceph-mon-list',
|
||||
proxy: {
|
||||
type: 'pve',
|
||||
url: "/api2/json/nodes/" + nodename + "/ceph/mon"
|
||||
}
|
||||
});
|
||||
|
||||
var store = Ext.create('PVE.data.DiffStore', { rstore: rstore });
|
||||
|
||||
PVE.Utils.monStoreErrors(me, rstore);
|
||||
|
||||
var service_cmd = function(cmd) {
|
||||
var rec = sm.getSelection()[0];
|
||||
if (!rec.data.host) {
|
||||
Ext.Msg.alert(gettext('Error'), "entry has no host");
|
||||
return;
|
||||
}
|
||||
PVE.Utils.API2Request({
|
||||
url: "/nodes/" + rec.data.host + "/ceph/" + cmd,
|
||||
method: 'POST',
|
||||
params: { service: "mon." + rec.data.name },
|
||||
success: function(response, options) {
|
||||
var upid = response.result.data;
|
||||
var win = Ext.create('PVE.window.TaskProgress', { upid: upid });
|
||||
win.show();
|
||||
},
|
||||
failure: function(response, opts) {
|
||||
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var start_btn = new PVE.button.Button({
|
||||
text: gettext('Start'),
|
||||
selModel: sm,
|
||||
disabled: true,
|
||||
handler: function(){
|
||||
service_cmd("start");
|
||||
}
|
||||
});
|
||||
|
||||
var stop_btn = new PVE.button.Button({
|
||||
text: gettext('Stop'),
|
||||
selModel: sm,
|
||||
disabled: true,
|
||||
handler: function(){
|
||||
service_cmd("stop");
|
||||
}
|
||||
});
|
||||
|
||||
var create_btn = new Ext.Button({
|
||||
text: gettext('Create'),
|
||||
handler: function(){
|
||||
var win = Ext.create('PVE.CephCreateMon', {
|
||||
nodename: nodename
|
||||
});
|
||||
win.show();
|
||||
}
|
||||
});
|
||||
|
||||
var remove_btn = new PVE.button.Button({
|
||||
text: gettext('Remove'),
|
||||
selModel: sm,
|
||||
disabled: true,
|
||||
handler: function() {
|
||||
var rec = sm.getSelection()[0];
|
||||
|
||||
if (!rec.data.host) {
|
||||
Ext.Msg.alert(gettext('Error'), "entry has no host");
|
||||
return;
|
||||
}
|
||||
|
||||
PVE.Utils.API2Request({
|
||||
url: "/nodes/" + rec.data.host + "/ceph/mon/" +
|
||||
rec.data.name,
|
||||
method: 'DELETE',
|
||||
success: function(response, options) {
|
||||
var upid = response.result.data;
|
||||
var win = Ext.create('PVE.window.TaskProgress', { upid: upid });
|
||||
win.show();
|
||||
},
|
||||
failure: function(response, opts) {
|
||||
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
store: store,
|
||||
selModel: sm,
|
||||
stateful: false,
|
||||
tbar: [ start_btn, stop_btn, create_btn, remove_btn ],
|
||||
columns: [
|
||||
{
|
||||
header: gettext('Name'),
|
||||
width: 50,
|
||||
sortable: true,
|
||||
renderer: function(v) { return "mon." + v; },
|
||||
dataIndex: 'name'
|
||||
},
|
||||
{
|
||||
header: gettext('Host'),
|
||||
width: 100,
|
||||
sortable: true,
|
||||
renderer: function(v) {
|
||||
return v || 'unknown';
|
||||
},
|
||||
dataIndex: 'host'
|
||||
},
|
||||
{
|
||||
header: gettext('Quorum'),
|
||||
width: 50,
|
||||
sortable: false,
|
||||
renderer: PVE.Utils.format_boolean,
|
||||
dataIndex: 'quorum'
|
||||
},
|
||||
{
|
||||
header: gettext('Address'),
|
||||
flex: 1,
|
||||
sortable: true,
|
||||
dataIndex: 'addr'
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
show: rstore.startUpdate,
|
||||
hide: rstore.stopUpdate,
|
||||
destroy: rstore.stopUpdate
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
}, function() {
|
||||
|
||||
Ext.define('ceph-mon-list', {
|
||||
extend: 'Ext.data.Model',
|
||||
fields: [ 'addr', 'name', 'rank', 'host', 'quorum' ],
|
||||
idProperty: 'name'
|
||||
});
|
||||
});
|
@ -1,369 +0,0 @@
|
||||
Ext.define('PVE.CephCreateOsd', {
|
||||
extend: 'PVE.window.Edit',
|
||||
alias: ['widget.pveCephCreateOsd'],
|
||||
|
||||
subject: 'Ceph OSD',
|
||||
|
||||
showProgress: true,
|
||||
|
||||
initComponent : function() {
|
||||
/*jslint confusion: true */
|
||||
var me = this;
|
||||
|
||||
if (!me.nodename) {
|
||||
throw "no node name specified";
|
||||
}
|
||||
|
||||
me.create = true;
|
||||
|
||||
Ext.applyIf(me, {
|
||||
url: "/nodes/" + me.nodename + "/ceph/osd",
|
||||
method: 'POST',
|
||||
items: [
|
||||
{
|
||||
xtype: 'pveCephDiskSelector',
|
||||
name: 'dev',
|
||||
nodename: me.nodename,
|
||||
value: me.dev,
|
||||
diskType: 'unused',
|
||||
fieldLabel: gettext('Disk'),
|
||||
allowBlank: false
|
||||
},
|
||||
{
|
||||
xtype: 'pveCephDiskSelector',
|
||||
name: 'journal_dev',
|
||||
nodename: me.nodename,
|
||||
diskType: 'journal_disks',
|
||||
fieldLabel: gettext('Journal Disk'),
|
||||
value: '',
|
||||
autoSelect: false,
|
||||
allowBlank: true,
|
||||
emptyText: 'use OSD disk'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
||||
|
||||
Ext.define('PVE.CephRemoveOsd', {
|
||||
extend: 'PVE.window.Edit',
|
||||
alias: ['widget.pveCephRemoveOsd'],
|
||||
|
||||
isRemove: true,
|
||||
|
||||
showProgress: true,
|
||||
|
||||
initComponent : function() {
|
||||
/*jslint confusion: true */
|
||||
var me = this;
|
||||
|
||||
if (!me.nodename) {
|
||||
throw "no node name specified";
|
||||
}
|
||||
if (me.osdid === undefined || me.osdid < 0) {
|
||||
throw "no osdid specified";
|
||||
}
|
||||
|
||||
me.create = true;
|
||||
|
||||
me.title = gettext('Remove') + ': ' + 'Ceph OSD osd.' + me.osdid;
|
||||
|
||||
Ext.applyIf(me, {
|
||||
url: "/nodes/" + me.nodename + "/ceph/osd/" + me.osdid,
|
||||
method: 'DELETE',
|
||||
items: [
|
||||
{
|
||||
xtype: 'pvecheckbox',
|
||||
name: 'cleanup',
|
||||
checked: true,
|
||||
labelWidth: 130,
|
||||
fieldLabel: gettext('Remove Partitions')
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
||||
|
||||
Ext.define('PVE.node.CephOsdTree', {
|
||||
extend: 'Ext.tree.Panel',
|
||||
alias: ['widget.pveNodeCephOsdTree'],
|
||||
|
||||
initComponent: function() {
|
||||
/*jslint confusion: true */
|
||||
var me = this;
|
||||
|
||||
var nodename = me.pveSelNode.data.node;
|
||||
if (!nodename) {
|
||||
throw "no node name specified";
|
||||
}
|
||||
|
||||
var sm = Ext.create('Ext.selection.TreeModel', {});
|
||||
|
||||
var set_button_status; // defined later
|
||||
|
||||
var reload = function() {
|
||||
PVE.Utils.API2Request({
|
||||
url: "/nodes/" + nodename + "/ceph/osd",
|
||||
waitMsgTarget: me,
|
||||
method: 'GET',
|
||||
failure: function(response, opts) {
|
||||
PVE.Utils.setErrorMask(me, response.htmlStatus);
|
||||
},
|
||||
success: function(response, opts) {
|
||||
sm.deselectAll();
|
||||
me.setRootNode(response.result.data.root);
|
||||
me.expandAll();
|
||||
set_button_status();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var osd_cmd = function(cmd) {
|
||||
var rec = sm.getSelection()[0];
|
||||
if (!(rec && (rec.data.id >= 0) && rec.data.host)) {
|
||||
return;
|
||||
}
|
||||
PVE.Utils.API2Request({
|
||||
url: "/nodes/" + rec.data.host + "/ceph/osd/" +
|
||||
rec.data.id + '/' + cmd,
|
||||
waitMsgTarget: me,
|
||||
method: 'POST',
|
||||
success: reload,
|
||||
failure: function(response, opts) {
|
||||
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var service_cmd = function(cmd) {
|
||||
var rec = sm.getSelection()[0];
|
||||
if (!(rec && rec.data.name && rec.data.host)) {
|
||||
return;
|
||||
}
|
||||
PVE.Utils.API2Request({
|
||||
url: "/nodes/" + rec.data.host + "/ceph/" + cmd,
|
||||
params: { service: rec.data.name },
|
||||
waitMsgTarget: me,
|
||||
method: 'POST',
|
||||
success: function(response, options) {
|
||||
var upid = response.result.data;
|
||||
var win = Ext.create('PVE.window.TaskProgress', { upid: upid });
|
||||
win.show();
|
||||
me.mon(win, 'close', reload, me);
|
||||
},
|
||||
failure: function(response, opts) {
|
||||
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var start_btn = new Ext.Button({
|
||||
text: gettext('Start'),
|
||||
disabled: true,
|
||||
handler: function(){ service_cmd('start'); }
|
||||
});
|
||||
|
||||
var stop_btn = new Ext.Button({
|
||||
text: gettext('Stop'),
|
||||
disabled: true,
|
||||
handler: function(){ service_cmd('stop'); }
|
||||
});
|
||||
|
||||
var osd_out_btn = new Ext.Button({
|
||||
text: 'Out',
|
||||
disabled: true,
|
||||
handler: function(){ osd_cmd('out'); }
|
||||
});
|
||||
|
||||
var osd_in_btn = new Ext.Button({
|
||||
text: 'In',
|
||||
disabled: true,
|
||||
handler: function(){ osd_cmd('in'); }
|
||||
});
|
||||
|
||||
var remove_btn = new Ext.Button({
|
||||
text: gettext('Remove'),
|
||||
disabled: true,
|
||||
handler: function(){
|
||||
var rec = sm.getSelection()[0];
|
||||
if (!(rec && (rec.data.id >= 0) && rec.data.host)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var win = Ext.create('PVE.CephRemoveOsd', {
|
||||
nodename: rec.data.host,
|
||||
osdid: rec.data.id
|
||||
});
|
||||
win.show();
|
||||
me.mon(win, 'close', reload, me);
|
||||
}
|
||||
});
|
||||
|
||||
set_button_status = function() {
|
||||
var rec = sm.getSelection()[0];
|
||||
|
||||
if (!rec) {
|
||||
start_btn.setDisabled(true);
|
||||
stop_btn.setDisabled(true);
|
||||
remove_btn.setDisabled(true);
|
||||
osd_out_btn.setDisabled(true);
|
||||
osd_in_btn.setDisabled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
var isOsd = (rec.data.host && (rec.data.type === 'osd') && (rec.data.id >= 0));
|
||||
|
||||
start_btn.setDisabled(!(isOsd && (rec.data.status !== 'up')));
|
||||
stop_btn.setDisabled(!(isOsd && (rec.data.status !== 'down')));
|
||||
remove_btn.setDisabled(!(isOsd && (rec.data.status === 'down')));
|
||||
|
||||
osd_out_btn.setDisabled(!(isOsd && rec.data['in']));
|
||||
osd_in_btn.setDisabled(!(isOsd && !rec.data['in']));
|
||||
};
|
||||
|
||||
sm.on('selectionchange', set_button_status);
|
||||
|
||||
var reload_btn = new Ext.Button({
|
||||
text: gettext('Reload'),
|
||||
handler: reload
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
tbar: [ reload_btn, start_btn, stop_btn, osd_out_btn, osd_in_btn, remove_btn ],
|
||||
rootVisible: false,
|
||||
fields: ['name', 'type', 'status', 'host', 'in',
|
||||
{ type: 'integer', name: 'id' },
|
||||
{ type: 'number', name: 'reweight' },
|
||||
{ type: 'number', name: 'percent_used' },
|
||||
{ type: 'integer', name: 'bytes_used' },
|
||||
{ type: 'integer', name: 'total_space' },
|
||||
{ type: 'integer', name: 'apply_latency_ms' },
|
||||
{ type: 'integer', name: 'commit_latency_ms' },
|
||||
{ type: 'number', name: 'crush_weight' }],
|
||||
stateful: false,
|
||||
selModel: sm,
|
||||
columns: [
|
||||
{
|
||||
xtype: 'treecolumn',
|
||||
text: 'Name',
|
||||
dataIndex: 'name',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
text: 'Type',
|
||||
dataIndex: 'type',
|
||||
align: 'right',
|
||||
width: 60
|
||||
},
|
||||
{
|
||||
text: 'Status',
|
||||
dataIndex: 'status',
|
||||
align: 'right',
|
||||
renderer: function(value, metaData, rec) {
|
||||
if (!value) {
|
||||
return value;
|
||||
}
|
||||
var data = rec.data;
|
||||
return value + '/' + (data['in'] ? 'in' : 'out');
|
||||
},
|
||||
width: 60
|
||||
},
|
||||
{
|
||||
text: 'weight',
|
||||
dataIndex: 'crush_weight',
|
||||
align: 'right',
|
||||
renderer: function(value, metaData, rec) {
|
||||
if (rec.data.type !== 'osd') {
|
||||
return '';
|
||||
}
|
||||
return value;
|
||||
},
|
||||
width: 60
|
||||
},
|
||||
{
|
||||
text: 'reweight',
|
||||
dataIndex: 'reweight',
|
||||
align: 'right',
|
||||
renderer: function(value, metaData, rec) {
|
||||
if (rec.data.type !== 'osd') {
|
||||
return '';
|
||||
}
|
||||
return value;
|
||||
},
|
||||
width: 60
|
||||
},
|
||||
{
|
||||
header: gettext('Used'),
|
||||
columns: [
|
||||
{
|
||||
text: '%',
|
||||
dataIndex: 'percent_used',
|
||||
align: 'right',
|
||||
renderer: function(value, metaData, rec) {
|
||||
if (rec.data.type !== 'osd') {
|
||||
return '';
|
||||
}
|
||||
return Ext.util.Format.number(value, '0.00');
|
||||
},
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
text: gettext('Total'),
|
||||
dataIndex: 'total_space',
|
||||
align: 'right',
|
||||
renderer: function(value, metaData, rec) {
|
||||
if (rec.data.type !== 'osd') {
|
||||
return '';
|
||||
}
|
||||
return PVE.Utils.render_size(value);
|
||||
},
|
||||
width: 100
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
header: gettext('Latency (ms)'),
|
||||
columns: [
|
||||
{
|
||||
text: 'Apply',
|
||||
dataIndex: 'apply_latency_ms',
|
||||
align: 'right',
|
||||
renderer: function(value, metaData, rec) {
|
||||
if (rec.data.type !== 'osd') {
|
||||
return '';
|
||||
}
|
||||
return value;
|
||||
},
|
||||
width: 60
|
||||
},
|
||||
{
|
||||
text: 'Commit',
|
||||
dataIndex: 'commit_latency_ms',
|
||||
align: 'right',
|
||||
renderer: function(value, metaData, rec) {
|
||||
if (rec.data.type !== 'osd') {
|
||||
return '';
|
||||
}
|
||||
return value;
|
||||
},
|
||||
width: 60
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
show: function() {
|
||||
reload();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
reload();
|
||||
}
|
||||
});
|
@ -1,220 +0,0 @@
|
||||
Ext.define('PVE.CephCreatePool', {
|
||||
extend: 'PVE.window.Edit',
|
||||
alias: ['widget.pveCephCreatePool'],
|
||||
|
||||
subject: 'Ceph Pool',
|
||||
|
||||
initComponent : function() {
|
||||
/*jslint confusion: true */
|
||||
var me = this;
|
||||
|
||||
if (!me.nodename) {
|
||||
throw "no node name specified";
|
||||
}
|
||||
|
||||
Ext.applyIf(me, {
|
||||
create: true,
|
||||
url: "/nodes/" + me.nodename + "/ceph/pools",
|
||||
method: 'POST',
|
||||
items: [
|
||||
{
|
||||
xtype: 'textfield',
|
||||
fieldLabel: gettext('Name'),
|
||||
name: 'name',
|
||||
allowBlank: false
|
||||
},
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
fieldLabel: gettext('Size'),
|
||||
name: 'size',
|
||||
value: 2,
|
||||
minValue: 1,
|
||||
maxValue: 3,
|
||||
allowBlank: false
|
||||
},
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
fieldLabel: gettext('Min. Size'),
|
||||
name: 'min_size',
|
||||
value: 1,
|
||||
minValue: 1,
|
||||
maxValue: 3,
|
||||
allowBlank: false
|
||||
},
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
fieldLabel: gettext('Crush RuleSet'),
|
||||
name: 'crush_ruleset',
|
||||
value: 0,
|
||||
minValue: 0,
|
||||
maxValue: 32768,
|
||||
allowBlank: false
|
||||
},
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
fieldLabel: 'pg_num',
|
||||
name: 'pg_num',
|
||||
value: 64,
|
||||
minValue: 8,
|
||||
maxValue: 32768,
|
||||
allowBlank: false
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
||||
|
||||
Ext.define('PVE.node.CephPoolList', {
|
||||
extend: 'Ext.grid.GridPanel',
|
||||
alias: ['widget.pveNodeCephPoolList'],
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
var nodename = me.pveSelNode.data.node;
|
||||
if (!nodename) {
|
||||
throw "no node name specified";
|
||||
}
|
||||
|
||||
var sm = Ext.create('Ext.selection.RowModel', {});
|
||||
|
||||
var rstore = Ext.create('PVE.data.UpdateStore', {
|
||||
interval: 3000,
|
||||
storeid: 'ceph-pool-list',
|
||||
model: 'ceph-pool-list',
|
||||
proxy: {
|
||||
type: 'pve',
|
||||
url: "/api2/json/nodes/" + nodename + "/ceph/pools"
|
||||
}
|
||||
});
|
||||
|
||||
var store = Ext.create('PVE.data.DiffStore', { rstore: rstore });
|
||||
|
||||
PVE.Utils.monStoreErrors(me, rstore);
|
||||
|
||||
var create_btn = new Ext.Button({
|
||||
text: gettext('Create'),
|
||||
handler: function() {
|
||||
var win = Ext.create('PVE.CephCreatePool', {
|
||||
nodename: nodename
|
||||
});
|
||||
win.show();
|
||||
}
|
||||
});
|
||||
|
||||
var remove_btn = new PVE.button.Button({
|
||||
text: gettext('Remove'),
|
||||
selModel: sm,
|
||||
disabled: true,
|
||||
confirmMsg: function(rec) {
|
||||
var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
|
||||
"'" + rec.data.pool_name + "'");
|
||||
msg += " " + gettext('This will permanently erase all image data.');
|
||||
|
||||
return msg;
|
||||
},
|
||||
handler: function() {
|
||||
var rec = sm.getSelection()[0];
|
||||
|
||||
if (!rec.data.pool_name) {
|
||||
return;
|
||||
}
|
||||
|
||||
PVE.Utils.API2Request({
|
||||
url: "/nodes/" + nodename + "/ceph/pools/" +
|
||||
rec.data.pool_name,
|
||||
method: 'DELETE',
|
||||
failure: function(response, opts) {
|
||||
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
store: store,
|
||||
selModel: sm,
|
||||
stateful: false,
|
||||
tbar: [ create_btn, remove_btn ],
|
||||
features: [ { ftype: 'summary' } ],
|
||||
columns: [
|
||||
{
|
||||
header: gettext('Name'),
|
||||
width: 100,
|
||||
sortable: true,
|
||||
dataIndex: 'pool_name'
|
||||
},
|
||||
{
|
||||
header: gettext('Size') + '/min',
|
||||
width: 50,
|
||||
sortable: false,
|
||||
renderer: function(v, meta, rec) {
|
||||
return v + '/' + rec.data.min_size;
|
||||
},
|
||||
dataIndex: 'size'
|
||||
},
|
||||
{
|
||||
header: 'pg_num',
|
||||
width: 100,
|
||||
sortable: false,
|
||||
dataIndex: 'pg_num'
|
||||
},
|
||||
{
|
||||
header: 'ruleset',
|
||||
width: 50,
|
||||
sortable: false,
|
||||
dataIndex: 'crush_ruleset'
|
||||
},
|
||||
{
|
||||
header: gettext('Used'),
|
||||
columns: [
|
||||
{
|
||||
header: '%',
|
||||
width: 80,
|
||||
sortable: true,
|
||||
align: 'right',
|
||||
renderer: Ext.util.Format.numberRenderer('0.00'),
|
||||
dataIndex: 'percent_used',
|
||||
summaryType: 'sum',
|
||||
summaryRenderer: Ext.util.Format.numberRenderer('0.00')
|
||||
},
|
||||
{
|
||||
header: gettext('Total'),
|
||||
width: 100,
|
||||
sortable: true,
|
||||
renderer: PVE.Utils.render_size,
|
||||
align: 'right',
|
||||
dataIndex: 'bytes_used',
|
||||
summaryType: 'sum',
|
||||
summaryRenderer: PVE.Utils.render_size
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
show: rstore.startUpdate,
|
||||
hide: rstore.stopUpdate,
|
||||
destroy: rstore.stopUpdate
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
}, function() {
|
||||
|
||||
Ext.define('ceph-pool-list', {
|
||||
extend: 'Ext.data.Model',
|
||||
fields: [ 'pool_name',
|
||||
{ name: 'pool', type: 'integer'},
|
||||
{ name: 'size', type: 'integer'},
|
||||
{ name: 'min_size', type: 'integer'},
|
||||
{ name: 'pg_num', type: 'integer'},
|
||||
{ name: 'bytes_used', type: 'integer'},
|
||||
{ name: 'percent_used', type: 'number'},
|
||||
{ name: 'crush_ruleset', type: 'integer'}
|
||||
],
|
||||
idProperty: 'pool_name'
|
||||
});
|
||||
});
|
@ -1,129 +0,0 @@
|
||||
Ext.define('PVE.node.CephStatus', {
|
||||
extend: 'PVE.grid.ObjectGrid',
|
||||
alias: ['widget.pveNodeCephStatus'],
|
||||
|
||||
initComponent: function() {
|
||||
/*jslint confusion: true */
|
||||
var me = this;
|
||||
|
||||
var nodename = me.pveSelNode.data.node;
|
||||
if (!nodename) {
|
||||
throw "no node name specified";
|
||||
}
|
||||
|
||||
var renderquorum = function(value) {
|
||||
if (!value || value.length < 0) {
|
||||
return 'No';
|
||||
}
|
||||
|
||||
return 'Yes {' + value.join(' ') + '}';
|
||||
};
|
||||
|
||||
var rendermonmap = function(d) {
|
||||
if (!d) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var txt = 'e' + d.epoch + ': ' + d.mons.length + " mons at ";
|
||||
|
||||
Ext.Array.each(d.mons, function(d) {
|
||||
txt += d.name + '=' + d.addr + ',';
|
||||
});
|
||||
|
||||
return txt;
|
||||
};
|
||||
|
||||
var renderosdmap = function(value) {
|
||||
if (!value || !value.osdmap) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var d = value.osdmap;
|
||||
|
||||
var txt = 'e' + d.epoch + ': ';
|
||||
|
||||
txt += d.num_osds + ' osds: ' + d.num_up_osds + ' up, ' +
|
||||
d.num_in_osds + " in";
|
||||
|
||||
return txt;
|
||||
};
|
||||
|
||||
var renderhealth = function(value) {
|
||||
if (!value || !value.overall_status) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var txt = value.overall_status;
|
||||
|
||||
Ext.Array.each(value.summary, function(d) {
|
||||
txt += " " + d.summary + ';';
|
||||
});
|
||||
|
||||
return txt;
|
||||
};
|
||||
|
||||
var renderpgmap = function(d) {
|
||||
if (!d) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var txt = 'v' + d.version + ': ';
|
||||
|
||||
txt += d.num_pgs + " pgs:";
|
||||
|
||||
Ext.Array.each(d.pgs_by_state, function(s) {
|
||||
txt += " " + s.count + " " + s.state_name;
|
||||
});
|
||||
txt += '; ';
|
||||
|
||||
txt += PVE.Utils.format_size(d.data_bytes) + " data, ";
|
||||
txt += PVE.Utils.format_size(d.bytes_used) + " used, ";
|
||||
txt += PVE.Utils.format_size(d.bytes_avail) + " avail";
|
||||
|
||||
return txt;
|
||||
};
|
||||
|
||||
Ext.applyIf(me, {
|
||||
url: "/api2/json/nodes/" + nodename + "/ceph/status",
|
||||
cwidth1: 150,
|
||||
interval: 3000,
|
||||
rows: {
|
||||
health: {
|
||||
header: 'health',
|
||||
renderer: renderhealth,
|
||||
required: true
|
||||
},
|
||||
quorum_names: {
|
||||
header: 'quorum',
|
||||
renderer: renderquorum,
|
||||
required: true
|
||||
},
|
||||
fsid: {
|
||||
header: 'cluster',
|
||||
required: true
|
||||
},
|
||||
monmap: {
|
||||
header: 'monmap',
|
||||
renderer: rendermonmap,
|
||||
required: true
|
||||
},
|
||||
osdmap: {
|
||||
header: 'osdmap',
|
||||
renderer: renderosdmap,
|
||||
required: true
|
||||
},
|
||||
pgmap: {
|
||||
header: 'pgmap',
|
||||
renderer: renderpgmap,
|
||||
required: true
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
me.on('show', me.rstore.startUpdate);
|
||||
me.on('hide', me.rstore.stopUpdate);
|
||||
me.on('destroy', me.rstore.stopUpdate);
|
||||
}
|
||||
});
|
@ -1,84 +0,0 @@
|
||||
/* Config properties:
|
||||
* rstore: A storage 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();
|
||||
me.model.prototype.fields.eachKey(function(field) {
|
||||
if (olditem.data[field] !== data[field]) {
|
||||
olditem.set(field, data[field]);
|
||||
}
|
||||
});
|
||||
olditem.endEdit(true);
|
||||
olditem.commit();
|
||||
} else {
|
||||
var newrec = Ext.ModelMgr.create(data, me.model, id);
|
||||
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('datachanged', me);
|
||||
});
|
||||
}
|
||||
});
|
@ -1,29 +0,0 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent([config]);
|
||||
}
|
||||
});
|
@ -1,117 +0,0 @@
|
||||
Ext.define('PVE.RestProxy', {
|
||||
extend: 'Ext.data.RestProxy',
|
||||
alias : 'proxy.pve',
|
||||
|
||||
constructor: function(config) {
|
||||
var me = this;
|
||||
|
||||
config = config || {};
|
||||
|
||||
Ext.applyIf(config, {
|
||||
pageParam : null,
|
||||
startParam: null,
|
||||
limitParam: null,
|
||||
groupParam: null,
|
||||
sortParam: null,
|
||||
filterParam: null,
|
||||
noCache : false,
|
||||
reader: {
|
||||
type: 'json',
|
||||
root: config.root || 'data'
|
||||
},
|
||||
afterRequest: function(request, success) {
|
||||
me.fireEvent('afterload', me, request, success);
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
me.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' ],
|
||||
idProperty: 'key'
|
||||
});
|
||||
|
||||
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'
|
||||
});
|
||||
});
|
@ -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: 'text',
|
||||
renderer: PVE.Utils.render_resource_type,
|
||||
sortable: true,
|
||||
hideable: false,
|
||||
width: 80
|
||||
},
|
||||
id: {
|
||||
header: 'ID',
|
||||
type: 'text',
|
||||
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: 'text',
|
||||
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: 'text'
|
||||
},
|
||||
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: 'text',
|
||||
hidden: true,
|
||||
sortable: true,
|
||||
width: 110
|
||||
},
|
||||
storage: {
|
||||
header: gettext('Storage'),
|
||||
type: 'text',
|
||||
hidden: true,
|
||||
sortable: true,
|
||||
width: 110
|
||||
},
|
||||
pool: {
|
||||
header: gettext('Pool'),
|
||||
type: 'text',
|
||||
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]);
|
||||
}
|
||||
});
|
@ -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]);
|
||||
}
|
||||
});
|
@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
@ -1,45 +0,0 @@
|
||||
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();
|
||||
});
|
||||
}
|
||||
});
|
@ -1,128 +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',
|
||||
|
||||
root: 'data',
|
||||
|
||||
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);
|
||||
var root = me.getRoot(result);
|
||||
|
||||
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;
|
||||
}
|
||||
});
|
||||
|
@ -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'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
});
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
@ -1,147 +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',
|
||||
renderer: Ext.String.htmlEncode,
|
||||
flex: 1
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
show: reload,
|
||||
itemdblclick: run_editor
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,489 +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'
|
||||
},
|
||||
{
|
||||
xtype: 'pvecheckbox',
|
||||
fieldLabel: gettext('Enable'),
|
||||
name: 'enabled',
|
||||
uncheckedValue: 0,
|
||||
defaultValue: 1,
|
||||
checked: true
|
||||
},
|
||||
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('Enabled'),
|
||||
width: 50,
|
||||
dataIndex: 'enabled',
|
||||
renderer: PVE.Utils.format_boolean,
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
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: 'enabled', type: 'boolean' },
|
||||
{ name: 'all', type: 'boolean' },
|
||||
{ name: 'snapshot', type: 'boolean' },
|
||||
{ name: 'stop', type: 'boolean' },
|
||||
{ name: 'suspend', type: 'boolean' },
|
||||
{ name: 'compress', type: 'boolean' }
|
||||
]
|
||||
});
|
||||
});
|
@ -1,106 +0,0 @@
|
||||
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'
|
||||
},
|
||||
{
|
||||
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'
|
||||
},
|
||||
{
|
||||
xtype: 'pvePoolView',
|
||||
title: gettext('Pools'),
|
||||
itemId: 'pools'
|
||||
},
|
||||
{
|
||||
xtype: 'pveACLView',
|
||||
title: gettext('Permissions'),
|
||||
itemId: 'permissions'
|
||||
},
|
||||
{
|
||||
xtype: 'pveRoleView',
|
||||
title: gettext('Roles'),
|
||||
itemId: 'roles'
|
||||
},
|
||||
{
|
||||
xtype: 'pveAuthView',
|
||||
title: gettext('Authentication'),
|
||||
itemId: 'domains'
|
||||
},
|
||||
{
|
||||
xtype: 'pveHAPanel',
|
||||
title: 'HA',
|
||||
phstateid: me.hstateid,
|
||||
itemId: 'ha'
|
||||
},
|
||||
{
|
||||
xtype: 'pveFirewallPanel',
|
||||
title: gettext('Firewall'),
|
||||
base_url: '/cluster/firewall',
|
||||
fwtype: 'dc',
|
||||
phstateid: me.hstateid,
|
||||
itemId: 'firewall'
|
||||
}
|
||||
]);
|
||||
|
||||
me.items.push({
|
||||
xtype: 'pveDcSupport',
|
||||
title: gettext('Support'),
|
||||
itemId: 'support'
|
||||
});
|
||||
}
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -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();
|
||||
}
|
||||
}
|
||||
});
|
@ -1,111 +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,
|
||||
renderer: Ext.String.htmlEncode,
|
||||
dataIndex: 'comment',
|
||||
flex: 1
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
show: reload,
|
||||
itemdblclick: run_editor
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,90 +0,0 @@
|
||||
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: false, // does not work with getRowClass()
|
||||
|
||||
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: 100,
|
||||
renderer: function(value) {
|
||||
return Ext.Date.format(value, "M d H:i:s");
|
||||
}
|
||||
},
|
||||
{
|
||||
header: gettext("Node"),
|
||||
dataIndex: 'node',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
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();
|
||||
}
|
||||
});
|
@ -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',
|
||||
data: data,
|
||||
value: '',
|
||||
fieldLabel: gettext('Console Viewer')
|
||||
}
|
||||
});
|
||||
|
||||
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: 'pveMail',
|
||||
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);
|
||||
}
|
||||
});
|
@ -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();
|
||||
}
|
||||
}
|
||||
});
|
@ -1,111 +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',
|
||||
renderer: Ext.String.htmlEncode,
|
||||
flex: 1
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
show: reload,
|
||||
itemdblclick: run_editor
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -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();
|
||||
}
|
||||
});
|
@ -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', renderer: Ext.String.htmlEncode, 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();
|
||||
}
|
||||
});
|
@ -1,278 +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 === 'lvmthin') {
|
||||
editor = 'PVE.storage.LvmThinEdit';
|
||||
} 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('lvmthin'),
|
||||
iconCls: 'pve-itype-icon-storage',
|
||||
handler: function() {
|
||||
var win = Ext.create('PVE.storage.LvmThinEdit', {});
|
||||
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'
|
||||
});
|
||||
|
||||
});
|
@ -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: ' ',
|
||||
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();
|
||||
}
|
||||
});
|
@ -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();
|
||||
}
|
||||
});
|
@ -1,137 +0,0 @@
|
||||
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: false, // 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: 100,
|
||||
renderer: function(value) {
|
||||
return Ext.Date.format(value, "M d H:i:s");
|
||||
}
|
||||
},
|
||||
{
|
||||
header: gettext("End Time"),
|
||||
dataIndex: 'endtime',
|
||||
width: 100,
|
||||
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();
|
||||
}
|
||||
});
|
@ -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: 'pveMail'
|
||||
}
|
||||
];
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
@ -1,236 +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,
|
||||
renderer: Ext.String.htmlEncode,
|
||||
dataIndex: 'comment',
|
||||
flex: 1
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
show: reload,
|
||||
itemdblclick: run_editor
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,16 +0,0 @@
|
||||
Ext.define('PVE.form.BackupModeSelector', {
|
||||
extend: 'PVE.form.KVComboBox',
|
||||
alias: ['widget.pveBackupModeSelector'],
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
me.data = [
|
||||
['snapshot', gettext('Snapshot')],
|
||||
['suspend', gettext('Suspend')],
|
||||
['stop', gettext('Stop')]
|
||||
];
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -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();
|
||||
}
|
||||
});
|
||||
|
@ -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();
|
||||
}
|
||||
});
|
@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -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();
|
||||
}
|
||||
});
|
@ -1,42 +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'],
|
||||
['Haswell-noTSX', 'Haswell (no TSX)'],
|
||||
['Broadwell', 'Broadwell'],
|
||||
['Broadwell-noTSX', 'Broadwell (no TSX)'],
|
||||
['Opteron_G1', 'Opteron_G1'],
|
||||
['Opteron_G2', 'Opteron_G2'],
|
||||
['Opteron_G3', 'Opteron_G3'],
|
||||
['Opteron_G4', 'Opteron_G4'],
|
||||
['Opteron_G5', 'Opteron_G5'],
|
||||
['host', 'host']
|
||||
];
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -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();
|
||||
}
|
||||
});
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
@ -1,16 +0,0 @@
|
||||
Ext.define('PVE.form.CompressionSelector', {
|
||||
extend: 'PVE.form.KVComboBox',
|
||||
alias: ['widget.pveCompressionSelector'],
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
me.data = [
|
||||
['', PVE.Utils.noneText],
|
||||
['lzo', 'LZO (' + gettext('fast') + ')'],
|
||||
['gzip', 'GZIP (' + gettext('good') + ')']
|
||||
];
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -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();
|
||||
}
|
||||
});
|
@ -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();
|
||||
}
|
||||
});
|
@ -1,20 +0,0 @@
|
||||
Ext.define('PVE.form.DayOfWeekSelector', {
|
||||
extend: 'PVE.form.KVComboBox',
|
||||
alias: ['widget.pveDayOfWeekSelector'],
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
me.data = [
|
||||
['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])]
|
||||
];
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -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();
|
||||
}
|
||||
});
|
@ -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();
|
||||
}
|
||||
});
|
@ -1,15 +0,0 @@
|
||||
Ext.define('PVE.form.EmailNotificationSelector', {
|
||||
extend: 'PVE.form.KVComboBox',
|
||||
alias: ['widget.pveEmailNotificationSelector'],
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
me.data = [
|
||||
['always', gettext('Always')],
|
||||
['failure', gettext('On failure only')]
|
||||
];
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -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);
|
||||
}
|
||||
});
|
@ -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();
|
||||
}
|
||||
});
|
@ -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'
|
||||
});
|
||||
|
||||
});
|
@ -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();
|
||||
}
|
||||
});
|
@ -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();
|
||||
}
|
||||
});
|
@ -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();
|
||||
}
|
||||
});
|
||||
|
@ -1,44 +0,0 @@
|
||||
Ext.define('PVE.form.KVComboBox', {
|
||||
extend: 'Ext.form.field.ComboBox',
|
||||
alias: 'widget.pveKVComboBox',
|
||||
|
||||
deleteEmpty: true,
|
||||
|
||||
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.data
|
||||
});
|
||||
|
||||
if (me.initialConfig.editable === undefined) {
|
||||
me.editable = false;
|
||||
}
|
||||
|
||||
Ext.apply(me, {
|
||||
displayField: 'value',
|
||||
valueField: 'key',
|
||||
queryMode: 'local'
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,10 +0,0 @@
|
||||
Ext.define('PVE.form.LanguageSelector', {
|
||||
extend: 'PVE.form.KVComboBox',
|
||||
alias: ['widget.pveLanguageSelector'],
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
me.data = PVE.Utils.language_array();
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -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();
|
||||
}
|
||||
});
|
@ -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();
|
||||
}
|
||||
});
|
@ -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();
|
||||
}
|
||||
});
|
@ -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'
|
||||
});
|
||||
|
||||
});
|
@ -1,16 +0,0 @@
|
||||
Ext.define('PVE.form.QemuBiosSelector', {
|
||||
extend: 'PVE.form.KVComboBox',
|
||||
alias: ['widget.pveQemuBiosSelector'],
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
me.data = [
|
||||
['', PVE.Utils.render_qemu_bios('')],
|
||||
['seabios', PVE.Utils.render_qemu_bios('seabios')],
|
||||
['ovmf', PVE.Utils.render_qemu_bios('ovmf')]
|
||||
];
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
@ -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'
|
||||
});
|
||||
|
||||
});
|
@ -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();
|
||||
}
|
||||
});
|
@ -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();
|
||||
}
|
||||
});
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
@ -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'
|
||||
});
|
||||
|
||||
});
|
@ -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;
|
||||
}
|
||||
});
|
@ -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'
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
});
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
@ -1,10 +0,0 @@
|
||||
Ext.define('PVE.form.VNCKeyboardSelector', {
|
||||
extend: 'PVE.form.KVComboBox',
|
||||
alias: ['widget.VNCKeyboardSelector'],
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
me.data = PVE.Utils.kvm_keymap_array();
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,101 +0,0 @@
|
||||
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,
|
||||
queryMode: 'local',
|
||||
allowBlank: false,
|
||||
forceSelection: true,
|
||||
autoSelect: false,
|
||||
triggerAction: 'all',
|
||||
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);
|
||||
}
|
||||
});
|
@ -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();
|
||||
}
|
||||
});
|
@ -1,208 +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([
|
||||
filterFn,
|
||||
{
|
||||
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();
|
||||
}
|
||||
});
|
@ -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(' ') + '"> </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);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -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', renderer: Ext.String.htmlEncode, flex: 1 }
|
||||
],
|
||||
listeners: {
|
||||
itemdblclick: run_editor
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
me.on('show', reload);
|
||||
}
|
||||
});
|
@ -1,235 +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_boolean_row('ndp', gettext('Enable NDP'), 1);
|
||||
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('ndp', gettext('Enable NDP'), 1);
|
||||
add_boolean_row('radv', gettext('Allow Router Advertisement'), 0);
|
||||
add_boolean_row('macfilter', gettext('MAC filter'), 1);
|
||||
add_boolean_row('ipfilter', gettext('IP filter'), 0);
|
||||
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);
|
||||
}
|
||||
});
|
@ -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', 'macro'], 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'),
|
||||
editable: 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,'"') + '"';
|
||||
}
|
||||
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'
|
||||
});
|
||||
|
||||
});
|
@ -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();
|
||||
}
|
||||
});
|
@ -1,95 +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 false; // break
|
||||
}
|
||||
});
|
||||
|
||||
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();
|
||||
}
|
||||
});
|
@ -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();
|
||||
}
|
||||
});
|
@ -1,232 +0,0 @@
|
||||
// fixme: remove this fix
|
||||
// this hack is required for ExtJS 4.0.0
|
||||
Ext.override(Ext.grid.feature.Chunking, {
|
||||
attachEvents: function() {
|
||||
var grid = this.view.up('gridpanel'),
|
||||
scroller = grid.down('gridscroller[dock=right]');
|
||||
if (scroller === null ) {
|
||||
grid.on("afterlayout", this.attachEvents, this);
|
||||
return;
|
||||
}
|
||||
scroller.el.on('scroll', this.onBodyScroll, this, {buffer: 300});
|
||||
},
|
||||
rowHeight: PVE.Utils.gridLineHeigh()
|
||||
});
|
||||
|
||||
Ext.define('PVE.grid.ResourceGrid', {
|
||||
extend: 'Ext.grid.GridPanel',
|
||||
alias: ['widget.pveResourceGrid'],
|
||||
|
||||
//fixme: this makes still problems with the scrollbar
|
||||
//features: [ {ftype: 'chunking'}],
|
||||
|
||||
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.ModelMgr.create(info, store.model, info.id);
|
||||
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.applyIf(me, {
|
||||
title: gettext('Search')
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
@ -1,35 +0,0 @@
|
||||
Ext.override(Ext.view.Table, {
|
||||
afterRender: function() {
|
||||
var me = this;
|
||||
|
||||
me.callParent();
|
||||
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;
|
||||
}
|
||||
}
|
||||
});
|
@ -1,44 +0,0 @@
|
||||
Ext.define('PVE.panel.HA', {
|
||||
extend: 'PVE.panel.SubConfig',
|
||||
alias: 'widget.pveHAPanel',
|
||||
|
||||
configPrefix: 'ha',
|
||||
|
||||
initComponent: function() {
|
||||
/*jslint confusion: true */
|
||||
var me = this;
|
||||
|
||||
var items = [
|
||||
{
|
||||
title: gettext('Status'),
|
||||
xtype: 'pveHAStatusView',
|
||||
itemId: 'status'
|
||||
},
|
||||
{
|
||||
title: gettext('Resources'),
|
||||
xtype: 'pveHAResourcesView',
|
||||
itemId: 'resources'
|
||||
},
|
||||
{
|
||||
title: gettext('Groups'),
|
||||
xtype: 'pveHAGroupsView',
|
||||
itemId: 'groups'
|
||||
},
|
||||
{
|
||||
title: gettext('Fencing'),
|
||||
xtype: 'pveFencingView',
|
||||
itemId: 'fencing'
|
||||
}
|
||||
];
|
||||
|
||||
Ext.apply(me, {
|
||||
defaults: {
|
||||
border: false,
|
||||
pveSelNode: me.pveSelNode
|
||||
},
|
||||
items: items
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,47 +0,0 @@
|
||||
Ext.define('PVE.ha.FencingView', {
|
||||
extend: 'Ext.grid.GridPanel',
|
||||
alias: ['widget.pveFencingView'],
|
||||
|
||||
initComponent : function() {
|
||||
var me = this;
|
||||
|
||||
var store = new Ext.data.Store({
|
||||
model: 'pve-ha-fencing',
|
||||
data: []
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
store: store,
|
||||
stateful: false,
|
||||
viewConfig: {
|
||||
trackOver: false,
|
||||
deferEmptyText: false,
|
||||
emptyText: 'Use watchdog based fencing.'
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
header: 'Node',
|
||||
width: 100,
|
||||
sortable: true,
|
||||
dataIndex: 'node'
|
||||
},
|
||||
{
|
||||
header: gettext('Command'),
|
||||
flex: 1,
|
||||
dataIndex: 'command'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
}, function() {
|
||||
|
||||
Ext.define('pve-ha-fencing', {
|
||||
extend: 'Ext.data.Model',
|
||||
fields: [
|
||||
'node', 'command', 'digest'
|
||||
]
|
||||
});
|
||||
|
||||
});
|
@ -1,110 +0,0 @@
|
||||
Ext.define('PVE.ha.GroupInputPanel', {
|
||||
extend: 'PVE.panel.InputPanel',
|
||||
|
||||
groupId: undefined,
|
||||
|
||||
onGetValues: function(values) {
|
||||
var me = this;
|
||||
|
||||
if (me.create) {
|
||||
values.type = 'group';
|
||||
}
|
||||
|
||||
return values;
|
||||
},
|
||||
|
||||
initComponent : function() {
|
||||
var me = this;
|
||||
|
||||
me.column1 = [
|
||||
{
|
||||
xtype: me.create ? 'textfield' : 'displayfield',
|
||||
name: 'group',
|
||||
height: 22, // hack: set same height as text fields
|
||||
value: me.groupId || '',
|
||||
fieldLabel: 'ID',
|
||||
vtype: 'StorageId',
|
||||
allowBlank: false
|
||||
},
|
||||
{
|
||||
xtype: 'PVE.form.NodeSelector',
|
||||
name: 'nodes',
|
||||
fieldLabel: gettext('Nodes'),
|
||||
allowBlank: false,
|
||||
multiSelect: true,
|
||||
autoSelect: false
|
||||
}
|
||||
];
|
||||
|
||||
me.column2 = [
|
||||
{
|
||||
xtype: 'pvecheckbox',
|
||||
name: 'restricted',
|
||||
uncheckedValue: 0,
|
||||
fieldLabel: gettext('restricted')
|
||||
},
|
||||
{
|
||||
xtype: 'pvecheckbox',
|
||||
name: 'nofailback',
|
||||
uncheckedValue: 0,
|
||||
fieldLabel: gettext('nofailback')
|
||||
},
|
||||
];
|
||||
|
||||
me.columnB = [
|
||||
{
|
||||
xtype: 'textfield',
|
||||
name: 'comment',
|
||||
fieldLabel: gettext('Comment')
|
||||
}
|
||||
];
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
||||
|
||||
Ext.define('PVE.ha.GroupEdit', {
|
||||
extend: 'PVE.window.Edit',
|
||||
|
||||
groupId: undefined,
|
||||
|
||||
initComponent : function() {
|
||||
var me = this;
|
||||
|
||||
me.create = !me.groupId;
|
||||
|
||||
if (me.create) {
|
||||
me.url = '/api2/extjs/cluster/ha/groups';
|
||||
me.method = 'POST';
|
||||
} else {
|
||||
me.url = '/api2/extjs/cluster/ha/groups/' + me.groupId;
|
||||
me.method = 'PUT';
|
||||
}
|
||||
|
||||
var ipanel = Ext.create('PVE.ha.GroupInputPanel', {
|
||||
create: me.create,
|
||||
groupId: me.groupId
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
subject: gettext('HA Group'),
|
||||
items: [ ipanel ]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
if (!me.create) {
|
||||
me.load({
|
||||
success: function(response, options) {
|
||||
var values = response.result.data;
|
||||
|
||||
if (values.nodes) {
|
||||
values.nodes = values.nodes.split(',');
|
||||
}
|
||||
|
||||
ipanel.setValues(values);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user