remove unused files
This commit is contained in:
parent
eb3b3e2905
commit
dda060e7c0
@ -1,89 +0,0 @@
|
||||
include $(top_builddir)/common.mk
|
||||
|
||||
JSSRC= \
|
||||
PVEUtils.js \
|
||||
StateProvider.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/Checkbox.js \
|
||||
form/TextField.js \
|
||||
form/RRDTypeSelector.js \
|
||||
form/ComboGrid.js \
|
||||
form/NetworkCardSelector.js \
|
||||
form/DiskFormatSelector.js \
|
||||
form/BusTypeSelector.js \
|
||||
form/RealmComboBox.js \
|
||||
form/BondModeSelector.js \
|
||||
form/ViewSelector.js \
|
||||
form/NodeSelector.js \
|
||||
form/FileSelector.js \
|
||||
form/StorageSelector.js \
|
||||
dc/Tasks.js \
|
||||
dc/Log.js \
|
||||
panel/StatusPanel.js \
|
||||
panel/RRDView.js \
|
||||
window/LoginWindow.js \
|
||||
window/TaskViewer.js \
|
||||
window/Wizard.js \
|
||||
grid/SelectFeature.js \
|
||||
grid/ObjectGrid.js \
|
||||
grid/ResourceGrid.js \
|
||||
tree/ResourceTree.js \
|
||||
panel/ConfigPanel.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/Syslog.js \
|
||||
node/Tasks.js \
|
||||
node/Config.js \
|
||||
qemu/StatusView.js \
|
||||
qemu/Summary.js \
|
||||
qemu/Config.js \
|
||||
qemu/HardwareView.js \
|
||||
qemu/CreateWizard.js \
|
||||
openvz/CreateWizard.js \
|
||||
storage/Browser.js \
|
||||
dc/UserView.js \
|
||||
dc/GroupView.js \
|
||||
dc/RoleView.js \
|
||||
dc/ACLView.js \
|
||||
dc/AuthView.js \
|
||||
dc/Config.js \
|
||||
Workspace.js
|
||||
|
||||
pvemanagerlib.js: ${JSSRC}
|
||||
cat ${JSSRC} >$@
|
||||
|
||||
pvelib_DATA = pvemanagerlib.js
|
||||
pvelibdir = ${WWW_EXTDIR}
|
||||
|
||||
privatedir = ${WWW_BASEDIR}
|
||||
private_SCRIPTS = \
|
||||
startup.pl
|
||||
|
||||
managerdir = ${WWW_ROOTDIR}
|
||||
manager_SCRIPTS = \
|
||||
index.pl
|
||||
|
||||
install-data-hook:
|
||||
chown -R www-data:www-data ${DESTDIR}/${privatedir}
|
||||
chown -R www-data:www-data ${DESTDIR}/${managerdir}
|
||||
chown -R www-data:www-data ${DESTDIR}/${pvelibdir}
|
||||
|
||||
clean-local:
|
||||
-rm -rf *~ store/*~ pvemanagerlib.js
|
||||
|
||||
|
@ -1,430 +0,0 @@
|
||||
Ext.ns('PVE');
|
||||
|
||||
// avoid errors when running without development tools
|
||||
if (!Ext.isDefined(Ext.global.console)) {
|
||||
var console = {
|
||||
dir: function() {},
|
||||
log: function() {}
|
||||
};
|
||||
}
|
||||
console.log("Starting PVE Manager");
|
||||
|
||||
Ext.Ajax.defaultHeaders = {
|
||||
'Accept': 'application/json'
|
||||
};
|
||||
|
||||
// do not send '_dc' parameter
|
||||
Ext.Ajax.disableCaching = false;
|
||||
|
||||
Ext.Ajax.on('beforerequest', function(conn, options) {
|
||||
if (PVE.CSRFPreventionToken) {
|
||||
if (!options.headers)
|
||||
options.headers = {};
|
||||
options.headers['CSRFPreventionToken'] = PVE.CSRFPreventionToken;
|
||||
}
|
||||
});
|
||||
|
||||
// custom Vtype for vtype:'IPAddress'
|
||||
Ext.apply(Ext.form.field.VTypes, {
|
||||
IPAddress: function(v) {
|
||||
return /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(v);
|
||||
},
|
||||
IPAddressText: 'Must be a numeric IP address',
|
||||
IPAddressMask: /[\d\.]/i,
|
||||
|
||||
BridgeName: function(v) {
|
||||
return /^vmbr\d{1,4}$/.test(v);
|
||||
},
|
||||
BridgeNameText: 'Allowable bridge names: vmbr<b>N</b>, where 0 <= <b>N</b> <= 9999',
|
||||
|
||||
BondName: function(v) {
|
||||
return /^bond\d{1,4}$/.test(v);
|
||||
},
|
||||
BondNameText: 'Allowable bond names: bond<b>N</b>, where 0 <= <b>N</b> <= 9999'
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
Ext.define('PVE.Utils', {
|
||||
singleton: true,
|
||||
|
||||
statics: {
|
||||
|
||||
log_severity_hash: {
|
||||
0: "panic",
|
||||
1: "alert",
|
||||
2: "critical",
|
||||
3: "error",
|
||||
4: "warning",
|
||||
5: "notice",
|
||||
6: "info",
|
||||
7: "debug"
|
||||
}
|
||||
},
|
||||
|
||||
authOK: function() {
|
||||
return Ext.util.Cookies.get('PVEAuthCookie');
|
||||
},
|
||||
|
||||
authClear: function() {
|
||||
Ext.util.Cookies.clear("PVEAuthCookie");
|
||||
},
|
||||
|
||||
// fixme: remove - not needed?
|
||||
gridLineHeigh: function() {
|
||||
return 21;
|
||||
|
||||
//if (Ext.isGecko)
|
||||
//return 23;
|
||||
//return 21;
|
||||
},
|
||||
|
||||
extractRequestError: function(result, verbose) {
|
||||
var msg = 'Successful';
|
||||
|
||||
if (!result.success) {
|
||||
var msg = "Unknown error";
|
||||
if (result.message) {
|
||||
msg = result.message;
|
||||
if (result.status)
|
||||
msg += ' (' + result.status + ')';
|
||||
}
|
||||
if (verbose && Ext.isObject(result.errors)) {
|
||||
msg += "<br>";
|
||||
Ext.Object.each(result.errors, function(prop, desc) {
|
||||
msg += "<br><b>" + Ext.htmlEncode(prop) + "</b>: " +
|
||||
Ext.htmlEncode(desc);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return msg;
|
||||
},
|
||||
|
||||
extractFormActionError: function(action) {
|
||||
var msg;
|
||||
switch (action.failureType) {
|
||||
case Ext.form.action.Action.CLIENT_INVALID:
|
||||
msg = 'Form fields may not be submitted with invalid values';
|
||||
break;
|
||||
case Ext.form.action.Action.CONNECT_FAILURE:
|
||||
msg = 'Connect failure';
|
||||
var resp = action.response;
|
||||
if (resp.status && resp.statusText)
|
||||
msg += " " + resp.status + ": " + resp.statusText;
|
||||
break;
|
||||
case Ext.form.action.Action.LOAD_FAILURE:
|
||||
case Ext.form.action.Action.SERVER_INVALID:
|
||||
msg = PVE.Utils.extractRequestError(action.result, true);
|
||||
break;
|
||||
}
|
||||
return msg;
|
||||
},
|
||||
|
||||
// Ext.Ajax.request
|
||||
API2Request: function(options) {
|
||||
var callbackFn = options.callback;
|
||||
var successFn = options.success;
|
||||
var failureFn = options.failure;
|
||||
|
||||
options.url = '/api2/extjs' + options.url;
|
||||
|
||||
delete options.callback;
|
||||
|
||||
options.success = function(response, options) {
|
||||
var result = Ext.decode(response.responseText);
|
||||
if (!result.success) {
|
||||
response.htmlStatus = PVE.Utils.extractRequestError(result, true);
|
||||
Ext.callback(callbackFn, options.scope, [options, false, response])
|
||||
Ext.callback(failureFn, options.scope, [response, options])
|
||||
return;
|
||||
}
|
||||
Ext.callback(callbackFn, options.scope, [options, true, response])
|
||||
Ext.callback(successFn, options.scope, [response, options])
|
||||
};
|
||||
|
||||
options.failure = function(response, options) {
|
||||
var msg = "Connection error - server offline?";
|
||||
if (response.status && response.statusText)
|
||||
msg = "Connection error " + response.status + ": " + response.statusText;
|
||||
response.htmlStatus = msg;
|
||||
Ext.callback(callbackFn, options.scope, [options, false, response])
|
||||
Ext.callback(failureFn, options.scope, [response, options])
|
||||
};
|
||||
|
||||
Ext.Ajax.request(options);
|
||||
},
|
||||
|
||||
assemble_field_data: function(values, data) {
|
||||
if (Ext.isObject(data)) {
|
||||
Ext.iterate(data, function(name, val) {
|
||||
if (name in values) {
|
||||
var bucket = values[name],
|
||||
isArray = Ext.isArray;
|
||||
if (!isArray(bucket)) {
|
||||
bucket = values[name] = [bucket];
|
||||
}
|
||||
if (isArray(val)) {
|
||||
values[name] = bucket.concat(val);
|
||||
} else {
|
||||
bucket.push(val);
|
||||
}
|
||||
} else {
|
||||
values[name] = val;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
format_task_description: function(type, id) {
|
||||
|
||||
if (type == 'vncproxy')
|
||||
return "VNC connection to VM " + id;
|
||||
|
||||
if (type == 'vncshell')
|
||||
return "VNC shell";
|
||||
|
||||
return type;
|
||||
},
|
||||
|
||||
|
||||
parse_task_upid: function(upid) {
|
||||
var task = {};
|
||||
|
||||
var res = upid.match(/^UPID:(\w+):([0-9A-Fa-f]{8}):([0-9A-Fa-f]{8}):([0-9A-Fa-f]{8}):([^:\s]+):([^:\s]*):([^:\s]+):$/);
|
||||
if (!res)
|
||||
throw "unable to parse upid '" + upid + "'";
|
||||
|
||||
task.node = res[1];
|
||||
task.pid = parseInt(res[2], 16);
|
||||
task.pstart = parseInt(res[3], 16);
|
||||
task.starttime = parseInt(res[4], 16);
|
||||
task.type = res[5];
|
||||
task.id = res[6];
|
||||
task.user = res[7];
|
||||
|
||||
task.desc = PVE.Utils.format_task_description(task.type, task.id);
|
||||
|
||||
return task;
|
||||
},
|
||||
|
||||
format_size: function(size) {
|
||||
|
||||
var kb = size / 1024;
|
||||
|
||||
if (kb < 1024)
|
||||
return kb.toFixed(0) + "KB";
|
||||
|
||||
var mb = size / (1024*1024);
|
||||
|
||||
if (mb < 1024)
|
||||
return mb.toFixed(0) + "MB";
|
||||
|
||||
var gb = mb / 1024;
|
||||
|
||||
if (gb < 1024)
|
||||
return gb.toFixed(2) + "GB";
|
||||
|
||||
var tb = gb / 1024;
|
||||
|
||||
return tb.toFixed(2) + "TB";
|
||||
|
||||
},
|
||||
|
||||
format_html_bar: function(per, text) {
|
||||
|
||||
return "<div class='pve-bar-wrap'>" + text + "<div class='pve-bar-border'>" +
|
||||
"<div class='pve-bar-inner' style='width:" + per + "%;'></div>" +
|
||||
"</div></div>";
|
||||
|
||||
},
|
||||
|
||||
format_cpu_bar: function(per1, per2, text) {
|
||||
|
||||
return "<div class='pve-bar-border'>" +
|
||||
"<div class='pve-bar-inner' style='width:" + per1 + "%;'></div>" +
|
||||
"<div class='pve-bar-inner2' style='width:" + per2 + "%;'></div>" +
|
||||
"<div class='pve-bar-text'>" + text + "</div>" +
|
||||
"</div>";
|
||||
},
|
||||
|
||||
format_large_bar: function(per, text) {
|
||||
|
||||
if (!text)
|
||||
text = per.toFixed(1) + "%";
|
||||
|
||||
return "<div class='pve-largebar-border'>" +
|
||||
"<div class='pve-largebar-inner' style='width:" + per + "%;'></div>" +
|
||||
"<div class='pve-largebar-text'>" + text + "</div>" +
|
||||
"</div>";
|
||||
},
|
||||
|
||||
format_duration_long: function(ut) {
|
||||
|
||||
var days = Math.floor(ut / 86400);
|
||||
ut -= days*86400;
|
||||
var hours = Math.floor(ut / 3600);
|
||||
ut -= hours*3600;
|
||||
var mins = Math.floor(ut / 60);
|
||||
ut -= mins*60;
|
||||
|
||||
hours = "00" + hours;
|
||||
hours = hours.substr(hours.length - 2);
|
||||
mins = "00" + mins;
|
||||
mins = mins.substr(mins.length - 2);
|
||||
ut = "00" + ut;
|
||||
ut = ut.substr(ut.length - 2);
|
||||
|
||||
if (days) {
|
||||
var ds = days > 1 ? 'days' : 'day';
|
||||
return days + ' ' + ds + ' ' +
|
||||
hours + ':' + mins + ':' + ut;
|
||||
} else {
|
||||
return hours + ':' + mins + ':' + ut;
|
||||
}
|
||||
},
|
||||
|
||||
format_duration_short: function(ut) {
|
||||
|
||||
if (ut < 60)
|
||||
return ut + 's';
|
||||
|
||||
if (ut < 3600) {
|
||||
var mins = ut / 60;
|
||||
return mins.toFixed(0) + 'm';
|
||||
}
|
||||
|
||||
if (ut < 86400) {
|
||||
var hours = ut / 3600;
|
||||
return hours.toFixed(0) + 'h';
|
||||
}
|
||||
|
||||
var days = ut / 86400;
|
||||
return days.toFixed(0) + 'd';
|
||||
},
|
||||
|
||||
format_storage_type: function(value) {
|
||||
var desc = {
|
||||
dir: 'Directory',
|
||||
nfs: 'NFS',
|
||||
lvm: 'LVM',
|
||||
iscsi: 'iSCSI'
|
||||
};
|
||||
return desc[value] || 'unknown';
|
||||
},
|
||||
|
||||
format_boolean: function(value) {
|
||||
return value ? 'Yes' : 'No';
|
||||
},
|
||||
|
||||
format_neg_boolean: function(value) {
|
||||
return !value ? 'Yes' : 'No';
|
||||
},
|
||||
|
||||
format_content_types: function(value) {
|
||||
var cta = [];
|
||||
|
||||
Ext.each(value.split(','), function(ct) {
|
||||
if (ct === 'images')
|
||||
cta.push('Images');
|
||||
if (ct === 'backup')
|
||||
cta.push('Backups');
|
||||
if (ct === 'vztmpl')
|
||||
cta.push('Templates');
|
||||
if (ct === 'iso')
|
||||
cta.push('ISO');
|
||||
});
|
||||
|
||||
return cta.join(', ');
|
||||
},
|
||||
|
||||
render_serverity: function (value) {
|
||||
return PVE.Utils.statics().log_severity_hash[value] || value;
|
||||
},
|
||||
|
||||
render_cpu: function(value, metaData, record, rowIndex, colIndex, store) {
|
||||
|
||||
var maxcpu = record.data.maxcpu;
|
||||
|
||||
if (!record.data.uptime)
|
||||
return '';
|
||||
|
||||
if (!(Ext.isNumeric(value) && Ext.isNumeric(maxcpu) && (maxcpu >= 1)))
|
||||
return ''
|
||||
|
||||
var per = (value * 100) / maxcpu;
|
||||
|
||||
return per.toFixed(1) + '% of ' + maxcpu + (maxcpu > 1 ? 'CPUs' : 'CPU');
|
||||
},
|
||||
|
||||
render_size: function(value, metaData, record, rowIndex, colIndex, store) {
|
||||
|
||||
if (!Ext.isNumeric(value))
|
||||
return '';
|
||||
|
||||
return PVE.Utils.format_size(value);
|
||||
},
|
||||
|
||||
render_timestamp: function(value, metaData, record, rowIndex, colIndex, store) {
|
||||
var servertime = new Date(value * 1000);
|
||||
return Ext.Date.format(servertime, 'Y-m-d H:i:s');
|
||||
},
|
||||
|
||||
render_mem_usage: function(value, metaData, record, rowIndex, colIndex, store) {
|
||||
|
||||
var mem = value;
|
||||
var maxmem = record.data.maxmem;
|
||||
|
||||
if (!record.data.uptime)
|
||||
return '';
|
||||
|
||||
if (!(Ext.isNumeric(mem) && maxmem))
|
||||
return ''
|
||||
|
||||
var per = (mem * 100) / maxmem;
|
||||
|
||||
return per.toFixed(1) + '%';
|
||||
},
|
||||
|
||||
render_disk_usage: function(value, metaData, record, rowIndex, colIndex, store) {
|
||||
|
||||
var disk = value;
|
||||
var maxdisk = record.data.maxdisk;
|
||||
|
||||
if (!(Ext.isNumeric(disk) && maxdisk))
|
||||
return ''
|
||||
|
||||
var per = (disk * 100) / maxdisk;
|
||||
|
||||
return per.toFixed(1) + '%';
|
||||
},
|
||||
|
||||
render_resource_type: function(value, metaData, record, rowIndex, colIndex, store) {
|
||||
|
||||
var cls = 'pve-itype-icon-' + value;
|
||||
metaData.css = cls;
|
||||
return value;
|
||||
},
|
||||
|
||||
render_uptime: function(value, metaData, record, rowIndex, colIndex, store) {
|
||||
|
||||
var uptime = value;
|
||||
|
||||
if (uptime === undefined)
|
||||
return '';
|
||||
|
||||
if (uptime <= 0)
|
||||
return '-';
|
||||
|
||||
return PVE.Utils.format_duration_long(uptime);
|
||||
},
|
||||
|
||||
render_upid: function(value, metaData, record) {
|
||||
var type = record.data.type;
|
||||
var id = record.data.id;
|
||||
|
||||
return PVE.Utils.format_task_description(type, id);
|
||||
}
|
||||
});
|
||||
|
@ -1,212 +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', 'clog'],
|
||||
['nodetab', ''],
|
||||
['storagetab', ''],
|
||||
['kvmtab', ''],
|
||||
['dctab', '']
|
||||
],
|
||||
|
||||
hprefix: 'v1',
|
||||
|
||||
compDict: {
|
||||
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 === '') {
|
||||
// do nothing
|
||||
} else 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 = confirm('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){
|
||||
var me = this;
|
||||
var data;
|
||||
|
||||
if (typeof me.UIState[name] != "undefined") {
|
||||
data = { value: me.UIState[name] };
|
||||
} else {
|
||||
data = me.callParent(arguments);
|
||||
}
|
||||
|
||||
//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,334 +0,0 @@
|
||||
PVE_vnc_console_event = function(appletid, action, err) {
|
||||
//console.log("TESTINIT param1 " + appletid + " action " + action);
|
||||
|
||||
return;
|
||||
|
||||
var el = Ext.get(appletid);
|
||||
if (!el)
|
||||
return;
|
||||
|
||||
if (action === "close") {
|
||||
// el.remove();
|
||||
} else if (action === "error") {
|
||||
// console.log("TESTERROR: " + err);
|
||||
// var compid = appletid.replace("-vncapp", "");
|
||||
// var comp = Ext.getCmp(compid);
|
||||
}
|
||||
|
||||
//Ext.get('mytestid').remove();
|
||||
};
|
||||
|
||||
Ext.define('PVE.VNCConsole', {
|
||||
extend: 'Ext.panel.Panel',
|
||||
alias: ['widget.pveVNCConsole'],
|
||||
|
||||
initComponent : function() {
|
||||
var me = this;
|
||||
|
||||
if (!me.url)
|
||||
throw "no url specified";
|
||||
|
||||
var myid = me.id + "-vncapp";
|
||||
|
||||
me.appletID = myid;
|
||||
|
||||
var box = Ext.create('Ext.Component', {
|
||||
border: false,
|
||||
html: ""
|
||||
});
|
||||
|
||||
var resize_window = function() {
|
||||
//console.log("resize");
|
||||
|
||||
var applet = Ext.getDom(myid);
|
||||
//console.log("resize " + myid + " " + applet);
|
||||
|
||||
// try again when dom element is available
|
||||
if (!(applet && Ext.isFunction(applet.getPreferredSize)))
|
||||
return Ext.Function.defer(resize_window, 1000);
|
||||
|
||||
var tbh = me.tbar ? me.tbar.getHeight() : 0;
|
||||
var ps = applet.getPreferredSize();
|
||||
var aw = ps.width;
|
||||
var ah = ps.height;
|
||||
|
||||
if (aw < 640) aw = 640;
|
||||
if (ah < 400) ah = 400;
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
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() {
|
||||
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) {
|
||||
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() {
|
||||
PVE.Utils.API2Request({
|
||||
url: me.url,
|
||||
params: me.params,
|
||||
method: me.method || 'POST',
|
||||
failure: function(response, opts) {
|
||||
box.update("Error " + response.htmlStatus);
|
||||
},
|
||||
success: function(response, opts) {
|
||||
var obj = Ext.decode(response.responseText);
|
||||
start_vnc_viewer(obj.data);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
if (me.toplevel) {
|
||||
me.on("render", function() { me.reloadApplet();});
|
||||
} else {
|
||||
me.on("show", function() { 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 vm_command = function(cmd, reload_applet) {
|
||||
me.setLoading(true, true);
|
||||
PVE.Utils.API2Request({
|
||||
params: { command: cmd },
|
||||
url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + "/status",
|
||||
method: 'PUT',
|
||||
callback: function() {
|
||||
me.setLoading(false);
|
||||
},
|
||||
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: 'Start',
|
||||
handler: function() {
|
||||
vm_command("start", 1);
|
||||
}
|
||||
},
|
||||
{
|
||||
text: 'Stop',
|
||||
handler: function() {
|
||||
var msg = "Do you really want to stop the VM?";
|
||||
Ext.Msg.confirm('Confirm', msg, function(btn) {
|
||||
if (btn !== 'yes')
|
||||
return;
|
||||
vm_command("stop");
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
text: 'Reset',
|
||||
handler: function() {
|
||||
var msg = "Do you really want to reset the VM?";
|
||||
Ext.Msg.confirm('Confirm', msg, function(btn) {
|
||||
if (btn !== 'yes')
|
||||
return;
|
||||
vm_command("reset");
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
text: 'Shutdown',
|
||||
handler: function() {
|
||||
var msg = "Do you really want to shutdown the VM?";
|
||||
Ext.Msg.confirm('Confirm', msg, function(btn) {
|
||||
if (btn !== 'yes')
|
||||
return;
|
||||
vm_command('shutdown');
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
text: 'Suspend',
|
||||
handler: function() {
|
||||
var msg = "Do you really want to suspend the VM?";
|
||||
Ext.Msg.confirm('Confirm', msg, function(btn) {
|
||||
if (btn !== 'yes')
|
||||
return;
|
||||
vm_command("suspend");
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
text: 'Resume',
|
||||
handler: function() {
|
||||
vm_command("resume");
|
||||
}
|
||||
},
|
||||
'->',
|
||||
{
|
||||
text: 'Refresh',
|
||||
handler: function() {
|
||||
var applet = Ext.getDom(me.appletID);
|
||||
applet.sendRefreshRequest();
|
||||
}
|
||||
},
|
||||
{
|
||||
text: 'Reload',
|
||||
handler: function () {
|
||||
me.reloadApplet();
|
||||
}
|
||||
},
|
||||
{
|
||||
text: 'Console',
|
||||
handler: function() {
|
||||
var url = Ext.urlEncode({
|
||||
console: 'kvm',
|
||||
vmid: me.vmid,
|
||||
node: me.nodename
|
||||
});
|
||||
var nw = window.open("?" + url, '_blank',
|
||||
"innerWidth=745,innerheight=427");
|
||||
nw.focus();
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
Ext.apply(me, {
|
||||
tbar: tbar,
|
||||
url: "/nodes/" + me.nodename + "/qemu/" + me.vmid + "/vncproxy"
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
||||
|
||||
Ext.define('PVE.Shell', {
|
||||
extend: 'PVE.VNCConsole',
|
||||
alias: ['widget.pveShell'],
|
||||
|
||||
initComponent : function() {
|
||||
var me = this;
|
||||
|
||||
if (!me.nodename)
|
||||
throw "no node name specified";
|
||||
|
||||
var tbar = [
|
||||
'->',
|
||||
{
|
||||
text: 'Refresh',
|
||||
handler: function() {
|
||||
var applet = Ext.getDom(me.appletID);
|
||||
applet.sendRefreshRequest();
|
||||
}
|
||||
},
|
||||
{
|
||||
text: 'Reload',
|
||||
handler: function () { me.reloadApplet(); }
|
||||
},
|
||||
{
|
||||
text: 'Shell',
|
||||
handler: function() {
|
||||
var url = Ext.urlEncode({
|
||||
console: 'shell',
|
||||
node: me.nodename
|
||||
});
|
||||
var nw = window.open("?" + url, '_blank',
|
||||
"innerWidth=745,innerheight=427");
|
||||
nw.focus();
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
Ext.apply(me, {
|
||||
tbar: tbar,
|
||||
url: "/nodes/" + me.nodename + "/vncshell"
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,364 +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',
|
||||
requires: [
|
||||
'Ext.tip.*',
|
||||
'PVE.Utils',
|
||||
'PVE.window.LoginWindow'
|
||||
],
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
me.onLogin(null);
|
||||
me.login.show();
|
||||
},
|
||||
|
||||
initComponent : function() {
|
||||
var me = this;
|
||||
|
||||
Ext.tip.QuickTipManager.init();
|
||||
|
||||
// fixme: what about other errors
|
||||
Ext.Ajax.on('requestexception', function(conn, response, options) {
|
||||
if (response.status == 401) { // auth failure
|
||||
me.showLogin();
|
||||
}
|
||||
});
|
||||
|
||||
document.title = me.title;
|
||||
|
||||
me.callParent();
|
||||
|
||||
if (!PVE.Utils.authOK())
|
||||
me.showLogin();
|
||||
else
|
||||
if (me.loginData)
|
||||
me.onLogin(me.loginData);
|
||||
|
||||
Ext.TaskManager.start({
|
||||
run: function() {
|
||||
var ticket = PVE.Utils.authOK();
|
||||
if (!ticket || !PVE.UserName)
|
||||
return;
|
||||
|
||||
Ext.Ajax.request({
|
||||
params: {
|
||||
username: PVE.UserName,
|
||||
password: ticket
|
||||
},
|
||||
url: '/api2/json/access/ticket',
|
||||
method: 'POST',
|
||||
success: function(response, opts) {
|
||||
// cookie is automatically updated
|
||||
var obj = Ext.decode(response.responseText);
|
||||
me.updateLoginData(obj.data);
|
||||
}
|
||||
});
|
||||
},
|
||||
interval: 15*60*1000
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
Ext.define('PVE.ConsoleWorkspace', {
|
||||
extend: 'PVE.Workspace',
|
||||
requires: [
|
||||
'PVE.KVMConsole'
|
||||
],
|
||||
|
||||
alias: ['widget.pveConsoleWorkspace'],
|
||||
|
||||
title: 'Proxmox Console',
|
||||
|
||||
initComponent : function() {
|
||||
var me = this;
|
||||
|
||||
var param = Ext.Object.fromQueryString(window.location.search);
|
||||
var consoleType = me.consoleType || param.console;
|
||||
|
||||
var content;
|
||||
if (consoleType === 'kvm') {
|
||||
me.title = "VM " + param.vmid;
|
||||
content = {
|
||||
xtype: 'pveKVMConsole',
|
||||
vmid: param.vmid,
|
||||
nodename: param.node,
|
||||
toplevel: true
|
||||
};
|
||||
} else if (consoleType === 'shell') {
|
||||
me.title = "node " + param.node + " - Proxmox Shell"
|
||||
content = {
|
||||
xtype: 'pveShell',
|
||||
nodename: param.node,
|
||||
toplevel: true
|
||||
};
|
||||
} else {
|
||||
content = {
|
||||
border: false,
|
||||
bodyPadding: 10,
|
||||
html: 'Error: No such console type'
|
||||
};
|
||||
}
|
||||
|
||||
Ext.apply(me, {
|
||||
layout: 'fit',
|
||||
border: false,
|
||||
items: content
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
||||
|
||||
Ext.define('PVE.StdWorkspace', {
|
||||
extend: 'PVE.Workspace',
|
||||
requires: [
|
||||
'Ext.History',
|
||||
'Ext.state.*',
|
||||
'Ext.selection.*',
|
||||
'PVE.form.ViewSelector',
|
||||
'PVE.data.ResourceStore',
|
||||
'PVE.tree.ResourceTree'
|
||||
],
|
||||
|
||||
alias: ['widget.pveStdWorkspace'],
|
||||
|
||||
// private
|
||||
defaultContent: {
|
||||
title: 'Nothing selected',
|
||||
region: 'center'
|
||||
},
|
||||
|
||||
setContent: function(comp) {
|
||||
var me = this;
|
||||
|
||||
if (!comp)
|
||||
comp = me.defaultContent;
|
||||
|
||||
var cont = me.child('#content');
|
||||
cont.removeAll(true);
|
||||
cont.add(comp);
|
||||
cont.doLayout();
|
||||
},
|
||||
|
||||
selectById: function(nodeid) {
|
||||
var me = this;
|
||||
var tree = me.down('pveResourceTree');
|
||||
tree.selectById(nodeid);
|
||||
},
|
||||
|
||||
onLogin: function(loginData) {
|
||||
var me = this;
|
||||
|
||||
me.updateUserInfo();
|
||||
|
||||
if (loginData)
|
||||
PVE.data.ResourceStore.startUpdate();
|
||||
},
|
||||
|
||||
updateUserInfo: function() {
|
||||
var me = this;
|
||||
|
||||
var ui = me.query('#userinfo')[0];
|
||||
|
||||
if (PVE.UserName) {
|
||||
ui.update('<div class="x-unselectable" style="white-space:nowrap;">You are logged in as "' + PVE.UserName + '"</div>');
|
||||
} else {
|
||||
ui.update('');
|
||||
}
|
||||
ui.doLayout();
|
||||
},
|
||||
|
||||
initComponent : function() {
|
||||
var me = this;
|
||||
|
||||
Ext.History.init();
|
||||
Ext.state.Manager.setProvider(Ext.create('PVE.StateProvider'));
|
||||
|
||||
//document.title = ;
|
||||
|
||||
var selview = new PVE.form.ViewSelector({
|
||||
listeners: {
|
||||
select: function(combo, records) {
|
||||
if (records && records.length) {
|
||||
var view = combo.getViewFilter();
|
||||
combo.up('pveResourceTree').setViewFilter(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var rtree = Ext.createWidget('pveResourceTree', {
|
||||
width: 200,
|
||||
region: 'west',
|
||||
margins: '0 0 0 5',
|
||||
split: true,
|
||||
viewFilter: selview.getViewFilter(),
|
||||
tbar: [ ' ', selview ],
|
||||
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',
|
||||
storage: 'PVE.storage.Browser'
|
||||
};
|
||||
|
||||
if (selected.length > 0) {
|
||||
var n = selected[0];
|
||||
comp = {
|
||||
xtype: tlckup[n.data.type || 'root'] ||
|
||||
'PVE.panel.Config',
|
||||
layout: 'fit',
|
||||
showSearch: (n.data.id === 'root') ||
|
||||
Ext.isDefined(n.data.groupbyid),
|
||||
pveSelNode: n,
|
||||
viewFilter: selview.getViewFilter()
|
||||
};
|
||||
}
|
||||
|
||||
me.setContent(comp);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
layout: '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,
|
||||
html: '<span class="x-panel-header-text">Proxmox Virtual Environment<br>Version ' + PVE.GUIVersion + "</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: "Logout",
|
||||
handler: function() {
|
||||
PVE.data.ResourceStore.stopUpdate();
|
||||
me.showLogin();
|
||||
me.setContent();
|
||||
var rt = me.down('pveResourceTree');
|
||||
rt.clearTree();
|
||||
}
|
||||
},
|
||||
{
|
||||
pack: 'end',
|
||||
margins: '3 5 0 0',
|
||||
xtype: 'button',
|
||||
baseCls: 'x-btn',
|
||||
text: "Create VM",
|
||||
handler: function() {
|
||||
var wiz = Ext.create('PVE.qemu.CreateWizard', {});
|
||||
wiz.show();
|
||||
}
|
||||
},
|
||||
{
|
||||
pack: 'end',
|
||||
margins: '3 5 0 0',
|
||||
xtype: 'button',
|
||||
baseCls: 'x-btn',
|
||||
text: "Create CT",
|
||||
handler: function() {
|
||||
var wiz = Ext.create('PVE.openvz.CreateWizard', {});
|
||||
wiz.show();
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
region: 'center',
|
||||
id: 'content',
|
||||
xtype: 'panel',
|
||||
layout: 'fit',
|
||||
border: false,
|
||||
stateful: false,
|
||||
margins:'0 5 0 0',
|
||||
items: me.defaultContent
|
||||
},
|
||||
rtree,
|
||||
{
|
||||
xtype: 'pveStatusPanel',
|
||||
region: 'south',
|
||||
margins:'0 5 5 5',
|
||||
height: 200,
|
||||
collapsible: true,
|
||||
split:true
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
me.updateUserInfo();
|
||||
}
|
||||
});
|
||||
|
@ -1,72 +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',
|
||||
|
||||
constructor: function(config) {
|
||||
var me = this;
|
||||
|
||||
var 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.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();
|
||||
|
||||
first_load = false;
|
||||
|
||||
me.resumeEvents();
|
||||
me.fireEvent('datachanged', me);
|
||||
});
|
||||
}
|
||||
});
|
@ -1,26 +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,
|
||||
reader: {
|
||||
type: 'jsonobject',
|
||||
rows: config.rows
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent([config]);
|
||||
}
|
||||
});
|
@ -1,84 +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: 'data'
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent([config]);
|
||||
}
|
||||
|
||||
}, function() {
|
||||
|
||||
Ext.define('pve-domains', {
|
||||
extend: "Ext.data.Model",
|
||||
fields: [ 'realm', 'type', 'comment', 'default' ],
|
||||
proxy: {
|
||||
type: 'pve',
|
||||
url: "/api2/json/access/domains"
|
||||
}
|
||||
});
|
||||
|
||||
Ext.define('KeyValue', {
|
||||
extend: "Ext.data.Model",
|
||||
fields: [ 'key', 'value' ],
|
||||
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,190 +0,0 @@
|
||||
Ext.define('PVE.data.ResourceStore', {
|
||||
extend: 'PVE.data.UpdateStore',
|
||||
requires: ['PVE.Utils'],
|
||||
singleton: true,
|
||||
|
||||
findNextVMID: function() {
|
||||
var me = this, i;
|
||||
|
||||
for (i = 100; i < 10000; i++) {
|
||||
if (me.findExact('vmid', i) < 0)
|
||||
return i;
|
||||
}
|
||||
},
|
||||
|
||||
findVMID: function(vmid) {
|
||||
var me = this, i;
|
||||
|
||||
return (me.findExact('vmid', parseInt(vmid)) >= 0);
|
||||
},
|
||||
|
||||
constructor: function(config) {
|
||||
var me = this;
|
||||
|
||||
config = config || {};
|
||||
|
||||
var field_defaults = {
|
||||
type: {
|
||||
header: '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
|
||||
},
|
||||
text: {
|
||||
header: 'Text',
|
||||
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 === 'storage') {
|
||||
text = info.storage + ' (' + info.node + ')';
|
||||
} else if (info.type === 'qemu' || info.type === 'openvz') {
|
||||
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: 'Name',
|
||||
hidden: true,
|
||||
sortable: true,
|
||||
type: 'text'
|
||||
},
|
||||
disk: {
|
||||
header: 'Disk usage',
|
||||
type: 'integer',
|
||||
renderer: PVE.Utils.render_disk_usage,
|
||||
sortable: true,
|
||||
width: 100
|
||||
},
|
||||
maxdisk: {
|
||||
header: 'Disk size',
|
||||
type: 'integer',
|
||||
renderer: PVE.Utils.render_size,
|
||||
sortable: true,
|
||||
hidden: true,
|
||||
width: 100
|
||||
},
|
||||
mem: {
|
||||
header: 'Memory usage',
|
||||
type: 'integer',
|
||||
renderer: PVE.Utils.render_mem_usage,
|
||||
sortable: true,
|
||||
width: 100
|
||||
},
|
||||
maxmem: {
|
||||
header: 'Mem size',
|
||||
type:'integer',
|
||||
renderer: PVE.Utils.render_size,
|
||||
hidden: true,
|
||||
sortable: true,
|
||||
width: 100
|
||||
},
|
||||
cpu: {
|
||||
header: 'CPU usage',
|
||||
type: 'float',
|
||||
renderer: PVE.Utils.render_cpu,
|
||||
sortable: true,
|
||||
width: 100
|
||||
},
|
||||
maxcpu: {
|
||||
header: 'maxcpu',
|
||||
type: 'integer',
|
||||
hidden: true,
|
||||
sortable: true,
|
||||
width: 60
|
||||
},
|
||||
uptime: {
|
||||
header: 'Uptime',
|
||||
type: 'integer',
|
||||
renderer: PVE.Utils.render_uptime,
|
||||
sortable: true,
|
||||
width: 110
|
||||
},
|
||||
node: {
|
||||
header: 'Node',
|
||||
type: 'text',
|
||||
hidden: true,
|
||||
sortable: true,
|
||||
width: 110
|
||||
},
|
||||
storage: {
|
||||
header: 'Storage',
|
||||
type: 'text',
|
||||
hidden: true,
|
||||
sortable: true,
|
||||
width: 110
|
||||
}
|
||||
};
|
||||
|
||||
var fields = [];
|
||||
Ext.Object.each(field_defaults, function(key, value) {
|
||||
if (!Ext.isDefined(value.convert))
|
||||
fields.push({name: key, type: value.type});
|
||||
else if (key === 'text')
|
||||
fields.push({name: key, type: value.type, convert: value.convert});
|
||||
});
|
||||
|
||||
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',
|
||||
autoDestory: false,
|
||||
defaultColums: function() {
|
||||
|
||||
var res = [];
|
||||
for (field in field_defaults) {
|
||||
var info = field_defaults[field];
|
||||
var fi = Ext.apply({ dataIndex: field }, info);
|
||||
res.push(fi);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent([config]);
|
||||
}
|
||||
});
|
@ -1,438 +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;
|
||||
|
||||
var statics = me.statics();
|
||||
|
||||
config = config || {};
|
||||
|
||||
Ext.regModel('Timezone', {
|
||||
fields: ['zone'],
|
||||
proxy: {
|
||||
type: 'memory',
|
||||
reader: 'array'
|
||||
}
|
||||
});
|
||||
|
||||
Ext.apply(config, {
|
||||
model: 'Timezone',
|
||||
data: statics.timezones
|
||||
});
|
||||
|
||||
me.callParent([config]);
|
||||
}
|
||||
});
|
@ -1,44 +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 store = queue.shift();
|
||||
if (!store)
|
||||
return;
|
||||
|
||||
queue_idx[store.storeid] = null;
|
||||
|
||||
idle = false;
|
||||
store.load({
|
||||
callback: function(records, operation, success) {
|
||||
idle = true;
|
||||
start_update();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Ext.apply(me, {
|
||||
queue: function(store) {
|
||||
if (!store.storeid)
|
||||
throw "unable to queue store without storeid";
|
||||
if (!queue_idx[store.storeid]) {
|
||||
queue_idx[store.storeid] = store;
|
||||
queue.push(store);
|
||||
}
|
||||
start_update();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
@ -1,46 +0,0 @@
|
||||
Ext.define('PVE.data.UpdateStore', {
|
||||
extend: 'Ext.data.Store',
|
||||
requires: [
|
||||
'PVE.Utils',
|
||||
'Ext.util.*',
|
||||
'PVE.data.UpdateQueue'
|
||||
],
|
||||
|
||||
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);
|
||||
load_task.delay(config.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() {
|
||||
loadtask.cancel();
|
||||
});
|
||||
}
|
||||
});
|
@ -1,66 +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: { data: "xyz" }
|
||||
* example2: [ { data: "xyz" } ]
|
||||
*/
|
||||
|
||||
Ext.define('PVE.data.reader.JsonObject', {
|
||||
extend: 'Ext.data.reader.Json',
|
||||
alias : 'reader.jsonobject',
|
||||
|
||||
root: 'data',
|
||||
|
||||
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 (Ext.isArray(root)) {
|
||||
if (root.length == 1)
|
||||
root = 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,52 +0,0 @@
|
||||
Ext.define('PVE.dc.Config', {
|
||||
extend: 'PVE.panel.Config',
|
||||
alias: 'widget.PVE.dc.Config',
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
Ext.apply(me, {
|
||||
title: "Datacenter",
|
||||
hstateid: 'dctab',
|
||||
items: [
|
||||
{
|
||||
title: 'Summary',
|
||||
itemId: 'summary',
|
||||
html: 'summary '
|
||||
},
|
||||
{
|
||||
title: 'Storage',
|
||||
itemId: 'storage',
|
||||
html: 'storage '
|
||||
},
|
||||
{
|
||||
xtype: 'pveUserView',
|
||||
title: 'Users',
|
||||
itemId: 'users'
|
||||
},
|
||||
{
|
||||
xtype: 'pveGroupView',
|
||||
title: 'Groups',
|
||||
itemId: 'groups'
|
||||
},
|
||||
{
|
||||
xtype: 'pveACLView',
|
||||
title: 'Permissions',
|
||||
itemId: 'permissions'
|
||||
},
|
||||
{
|
||||
xtype: 'pveRoleView',
|
||||
title: 'Roles',
|
||||
itemId: 'roles'
|
||||
},
|
||||
{
|
||||
xtype: 'pveAuthView',
|
||||
title: 'Authentication',
|
||||
itemId: 'domains'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,56 +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: Ext.define('pve-groups', {
|
||||
extend: 'Ext.data.Model',
|
||||
fields: [ 'groupid', 'comment' ],
|
||||
idProperty: 'groupid'
|
||||
}),
|
||||
proxy: {
|
||||
type: 'pve',
|
||||
url: "/api2/json/access/groups"
|
||||
},
|
||||
sorters: {
|
||||
property: 'groupid',
|
||||
order: 'DESC'
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Ext.apply(me, {
|
||||
store: store,
|
||||
stateful: false,
|
||||
|
||||
viewConfig: {
|
||||
trackOver: false
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
header: 'Group name',
|
||||
width: 200,
|
||||
sortable: true,
|
||||
dataIndex: 'groupid'
|
||||
},
|
||||
{
|
||||
header: 'Comment',
|
||||
sortable: false,
|
||||
dataIndex: 'comment',
|
||||
flex: 1
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
show: function() {
|
||||
store.load();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,89 +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: "Start Time",
|
||||
dataIndex: 'time',
|
||||
width: 100,
|
||||
renderer: function(value) {
|
||||
return Ext.Date.format(value, "M d H:i:s");
|
||||
}
|
||||
},
|
||||
{
|
||||
header: "Node",
|
||||
dataIndex: 'node',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
header: "Tag",
|
||||
dataIndex: 'tag',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
header: "PID",
|
||||
dataIndex: 'pid',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
header: "User",
|
||||
dataIndex: 'user',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
header: "Severity",
|
||||
dataIndex: 'pri',
|
||||
renderer: PVE.Utils.render_serverity,
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
header: "Message",
|
||||
dataIndex: 'msg',
|
||||
flex: 1
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
show: logstore.startUpdate,
|
||||
hide: logstore.stopUpdate,
|
||||
destroy: logstore.stopUpdate
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,68 +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: Ext.define('pve-roles', {
|
||||
extend: 'Ext.data.Model',
|
||||
fields: [ 'roleid', 'privs' ],
|
||||
idProperty: 'roleid'
|
||||
}),
|
||||
proxy: {
|
||||
type: 'pve',
|
||||
url: "/api2/json/access/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, ' ');
|
||||
};
|
||||
|
||||
Ext.apply(me, {
|
||||
store: store,
|
||||
stateful: false,
|
||||
|
||||
viewConfig: {
|
||||
trackOver: false
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
header: 'Role name',
|
||||
width: 150,
|
||||
sortable: true,
|
||||
dataIndex: 'roleid'
|
||||
},
|
||||
{
|
||||
id: 'privs',
|
||||
header: 'Privileges',
|
||||
sortable: false,
|
||||
renderer: render_privs,
|
||||
dataIndex: 'privs',
|
||||
flex: 1
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
show: function() {
|
||||
store.load();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,120 +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'
|
||||
},
|
||||
sorters: [
|
||||
{
|
||||
property : 'starttime',
|
||||
direction: 'ASC'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
var store = Ext.create('PVE.data.DiffStore', {
|
||||
rstore: taskstore,
|
||||
appendAtStart: true
|
||||
});
|
||||
|
||||
var run_task_viewer = function() {
|
||||
var sm = me.getSelectionModel();
|
||||
var rec = sm.getLastSelected();
|
||||
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: "Start Time",
|
||||
dataIndex: 'starttime',
|
||||
width: 100,
|
||||
renderer: function(value) {
|
||||
return Ext.Date.format(value, "M d H:i:s");
|
||||
}
|
||||
},
|
||||
{
|
||||
header: "End Time",
|
||||
dataIndex: 'endtime',
|
||||
width: 100,
|
||||
renderer: function(value, metaData, record) {
|
||||
if (record.data.pid) {
|
||||
metaData.css = "x-grid-row-loading";
|
||||
return "";
|
||||
}
|
||||
return Ext.Date.format(value, "M d H:i:s");
|
||||
}
|
||||
},
|
||||
{
|
||||
header: "Node",
|
||||
dataIndex: 'node',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
header: "User",
|
||||
dataIndex: 'user',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
header: "Description",
|
||||
dataIndex: 'upid',
|
||||
flex: 1,
|
||||
renderer: PVE.Utils.render_upid
|
||||
},
|
||||
{
|
||||
header: "Status",
|
||||
dataIndex: 'status',
|
||||
width: 200,
|
||||
renderer: function(value, metaData, record) {
|
||||
if (record.data.pid) {
|
||||
metaData.css = "x-grid-row-loading";
|
||||
return "";
|
||||
}
|
||||
if (value == 'OK')
|
||||
return 'OK';
|
||||
// metaData.attr = 'style="color:red;"';
|
||||
return "ERROR: " + value;
|
||||
}
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
itemdblclick: run_task_viewer,
|
||||
show: taskstore.startUpdate,
|
||||
hide: taskstore.stopUpdate,
|
||||
destroy: taskstore.stopUpdate
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,111 +0,0 @@
|
||||
Ext.define('PVE.dc.UserView', {
|
||||
extend: 'Ext.grid.GridPanel',
|
||||
|
||||
alias: ['widget.pveUserView'],
|
||||
|
||||
initComponent : function() {
|
||||
var me = this;
|
||||
|
||||
var store = new Ext.data.Store({
|
||||
model: Ext.define('pve-users', {
|
||||
extend: 'Ext.data.Model',
|
||||
fields: [
|
||||
'userid', 'firstname', 'lastname' , 'email', 'comment',
|
||||
{ type: 'boolean', name: 'enabled' },
|
||||
{ type: 'date', dateFormat: 'timestamp', name: 'expire' },
|
||||
],
|
||||
idProperty: 'userid'
|
||||
}),
|
||||
proxy: {
|
||||
type: 'pve',
|
||||
url: "/api2/json/access/users"
|
||||
},
|
||||
sorters: {
|
||||
property: 'userid',
|
||||
order: 'DESC'
|
||||
}
|
||||
});
|
||||
|
||||
var render_expire = function(date) {
|
||||
if (!date)
|
||||
return 'never';
|
||||
|
||||
return Ext.Date.format(date, "Y-m-d");
|
||||
};
|
||||
|
||||
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,
|
||||
stateful: false,
|
||||
|
||||
viewConfig: {
|
||||
trackOver: false
|
||||
},
|
||||
|
||||
columns: [
|
||||
{
|
||||
header: 'User name',
|
||||
width: 200,
|
||||
sortable: true,
|
||||
renderer: render_username,
|
||||
dataIndex: 'userid'
|
||||
},
|
||||
{
|
||||
header: 'Realm',
|
||||
width: 100,
|
||||
sortable: true,
|
||||
renderer: render_realm,
|
||||
dataIndex: 'userid'
|
||||
},
|
||||
{
|
||||
header: 'Enabled',
|
||||
width: 80,
|
||||
sortable: true,
|
||||
dataIndex: 'enabled'
|
||||
},
|
||||
{
|
||||
header: 'Expire',
|
||||
width: 80,
|
||||
sortable: true,
|
||||
renderer: render_expire,
|
||||
dataIndex: 'expire'
|
||||
},
|
||||
{
|
||||
header: 'Name',
|
||||
width: 150,
|
||||
sortable: true,
|
||||
renderer: render_full_name,
|
||||
dataIndex: 'firstname'
|
||||
},
|
||||
{
|
||||
id: 'comment',
|
||||
header: 'Comment',
|
||||
sortable: false,
|
||||
dataIndex: 'comment',
|
||||
flex: 1
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
show: function() {
|
||||
store.load();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,31 +0,0 @@
|
||||
Ext.define('PVE.form.BondModeSelector', {
|
||||
extend: 'Ext.form.field.ComboBox',
|
||||
alias: ['widget.bondModeSelector'],
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
var store = Ext.create('Ext.data.ArrayStore', {
|
||||
model: 'KeyValue',
|
||||
data : [
|
||||
['balance-rr', ''],
|
||||
['active-backup', ''],
|
||||
['balance-xor', ''],
|
||||
['broadcast', ''],
|
||||
['802.3ad', ''],
|
||||
['balance-tlb', ''],
|
||||
['balance-alb', ''],
|
||||
]
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
store: store,
|
||||
queryMode: 'local',
|
||||
editable: false,
|
||||
displayField: 'key',
|
||||
valueField: 'key'
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,27 +0,0 @@
|
||||
Ext.define('PVE.form.BusTypeSelector', {
|
||||
extend: 'Ext.form.field.ComboBox',
|
||||
alias: ['widget.PVE.form.BusTypeSelector'],
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
var store = Ext.create('Ext.data.ArrayStore', {
|
||||
model: 'KeyValue',
|
||||
data : [
|
||||
['ide', 'IDE'],
|
||||
['virtio', 'VIRTIO'],
|
||||
['scsi', 'SCSI']
|
||||
]
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
store: store,
|
||||
queryMode: 'local',
|
||||
editable: false,
|
||||
displayField: 'value',
|
||||
valueField: 'key'
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,16 +0,0 @@
|
||||
Ext.define('PVE.form.Checkbox', {
|
||||
extend: 'Ext.form.field.Checkbox',
|
||||
alias: ['widget.pvecheckbox'],
|
||||
|
||||
inputValue: '1',
|
||||
|
||||
// also accept integer 1 as true
|
||||
setRawValue: function(value) {
|
||||
var me = this;
|
||||
|
||||
if (value === 1)
|
||||
value = true;
|
||||
|
||||
me.callParent([value]);
|
||||
}
|
||||
});
|
@ -1,97 +0,0 @@
|
||||
Ext.define('PVE.form.ComboGrid', {
|
||||
extend: 'Ext.form.ComboBox',
|
||||
requires: [
|
||||
'Ext.grid.Panel',
|
||||
'PVE.Utils'
|
||||
],
|
||||
alias: ['widget.PVE.form.ComboGrid'],
|
||||
|
||||
computeHeight: function() {
|
||||
var me = this;
|
||||
var lh = PVE.Utils.gridLineHeigh();
|
||||
var count = me.store.getCount();
|
||||
return (count > 10) ? 10*lh : 26+count*lh;
|
||||
},
|
||||
|
||||
// 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());
|
||||
},
|
||||
scope: me
|
||||
});
|
||||
|
||||
me.mon(picker.getSelectionModel(), {
|
||||
selectionChange: me.onListSelectionChange,
|
||||
scope: me
|
||||
});
|
||||
|
||||
return picker;
|
||||
},
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
Ext.apply(me, {
|
||||
queryMode: 'local',
|
||||
editable: false,
|
||||
matchFieldWidth: false
|
||||
});
|
||||
|
||||
Ext.applyIf(me.listConfig, { width: 400 });
|
||||
|
||||
me.callParent();
|
||||
|
||||
me.store.on('beforeload', function() {
|
||||
me.up('form').setLoading(true, true);
|
||||
});
|
||||
|
||||
// hack: autoSelect does not work
|
||||
me.store.on('load', function(store, r, success, o) {
|
||||
if (success) {
|
||||
var def = me.getValue();
|
||||
if (!def || !store.findRecord(me.valueField, def)) {
|
||||
var rec = me.store.first();
|
||||
if (me.autoSelect && rec && rec.data) {
|
||||
def = rec.data[me.valueField];
|
||||
me.setValue(def);
|
||||
} else {
|
||||
me.setValue('');
|
||||
}
|
||||
}
|
||||
}
|
||||
me.up('form').setLoading(false);
|
||||
});
|
||||
}
|
||||
});
|
@ -1,27 +0,0 @@
|
||||
Ext.define('PVE.form.DiskFormatSelector', {
|
||||
extend: 'Ext.form.field.ComboBox',
|
||||
alias: ['widget.PVE.form.DiskFormatSelector'],
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
var store = Ext.create('Ext.data.ArrayStore', {
|
||||
model: 'KeyValue',
|
||||
data : [
|
||||
['raw', 'Raw disk image (raw)'],
|
||||
['qcow2', 'QEMU image format (qcow2)'],
|
||||
['vmdk', 'VMware image format (vmdk)']
|
||||
]
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
store: store,
|
||||
queryMode: 'local',
|
||||
editable: false,
|
||||
displayField: 'value',
|
||||
valueField: 'key'
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,85 +0,0 @@
|
||||
Ext.define('PVE.form.FileSelector', {
|
||||
extend: 'PVE.form.ComboGrid',
|
||||
requires: [
|
||||
'Ext.data.Store',
|
||||
'PVE.RestProxy'
|
||||
],
|
||||
alias: ['widget.PVE.form.FileSelector'],
|
||||
|
||||
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;
|
||||
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', {
|
||||
fields: [ 'volid', 'format', 'size', 'used', 'vmid',
|
||||
{ name: 'text',
|
||||
convert: function(value, record) {
|
||||
if (value)
|
||||
return value;
|
||||
return record.data.volid.replace(/^.*:.*\//,'');;
|
||||
}
|
||||
}],
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
store: store,
|
||||
allowBlank: false,
|
||||
autoSelect: false,
|
||||
valueField: 'volid',
|
||||
displayField: 'text',
|
||||
listConfig: {
|
||||
columns: [
|
||||
{
|
||||
header: 'Name',
|
||||
dataIndex: 'text',
|
||||
hideable: false,
|
||||
flex: 1
|
||||
},
|
||||
{
|
||||
header: 'Format',
|
||||
width: 60,
|
||||
dataIndex: 'format'
|
||||
},
|
||||
{
|
||||
header: 'Size',
|
||||
width: 60,
|
||||
dataIndex: 'size',
|
||||
renderer: PVE.Utils.format_size
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
me.setStorage(me.storage, me.nodename);
|
||||
}
|
||||
});
|
@ -1,27 +0,0 @@
|
||||
Ext.define('PVE.form.NetworkCardSelector', {
|
||||
extend: 'Ext.form.field.ComboBox',
|
||||
alias: ['widget.PVE.form.NetworkCardSelector'],
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
var store = Ext.create('Ext.data.ArrayStore', {
|
||||
model: 'KeyValue',
|
||||
data : [
|
||||
['rtl8139', 'Realtec RTL8139'],
|
||||
['e1000', 'Intel E1000'],
|
||||
['virtio', 'VirtIO (paravirtualized)']
|
||||
]
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
store: store,
|
||||
queryMode: 'local',
|
||||
editable: false,
|
||||
displayField: 'value',
|
||||
valueField: 'key'
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,71 +0,0 @@
|
||||
Ext.define('PVE.form.NodeSelector', {
|
||||
extend: 'PVE.form.ComboGrid',
|
||||
requires: [
|
||||
'Ext.data.Store',
|
||||
'PVE.RestProxy'
|
||||
],
|
||||
alias: ['widget.PVE.form.NodeSelector'],
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
var store = Ext.create('Ext.data.Store', {
|
||||
fields: [ 'name', 'cpu', 'maxcpu', 'mem', 'maxmem', 'uptime' ],
|
||||
autoLoad: true,
|
||||
proxy: {
|
||||
type: 'pve',
|
||||
url: '/api2/json/nodes'
|
||||
},
|
||||
autoDestory: true,
|
||||
sorters: [
|
||||
{
|
||||
property : 'mem',
|
||||
direction: 'DESC'
|
||||
},
|
||||
{
|
||||
property : 'name',
|
||||
direction: 'ASC'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
store: store,
|
||||
allowBlank: false,
|
||||
valueField: 'name',
|
||||
displayField: 'name',
|
||||
listConfig: {
|
||||
columns: [
|
||||
{
|
||||
header: 'Node',
|
||||
dataIndex: 'name',
|
||||
hideable: false,
|
||||
flex: 1
|
||||
},
|
||||
{
|
||||
header: 'Memory usage',
|
||||
renderer: PVE.Utils.render_mem_usage,
|
||||
width: 100,
|
||||
dataIndex: 'mem'
|
||||
},
|
||||
{
|
||||
header: 'CPU usage',
|
||||
renderer: PVE.Utils.render_cpu,
|
||||
sortable: true,
|
||||
width: 100,
|
||||
dataIndex: 'cpu'
|
||||
}
|
||||
]
|
||||
},
|
||||
validator: function(value) {
|
||||
var rec = me.store.findRecord(me.valueField, value);
|
||||
if (rec && rec.data && Ext.isNumeric(rec.data.mem))
|
||||
return true;
|
||||
|
||||
return "Node " + value + " seems to be offline!";
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,67 +0,0 @@
|
||||
Ext.define('PVE.form.RRDTypeSelector', {
|
||||
extend: 'Ext.form.field.ComboBox',
|
||||
requires: [
|
||||
'Ext.state.Manager'
|
||||
],
|
||||
|
||||
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,61 +0,0 @@
|
||||
Ext.define('PVE.form.RealmComboBox', {
|
||||
extend: 'Ext.form.ComboBox',
|
||||
requires: ['Ext.data.Store', 'PVE.RestProxy'],
|
||||
alias: ['widget.pveRealmComboBox'],
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
var stateid = 'pveloginrealm';
|
||||
|
||||
var realmstore = Ext.create('Ext.data.Store', {
|
||||
model: 'pve-domains',
|
||||
autoDestory: true
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
fieldLabel: 'Realm',
|
||||
name: 'realm',
|
||||
store: realmstore,
|
||||
queryMode: 'local',
|
||||
allowBlank: false,
|
||||
forceSelection: true,
|
||||
autoSelect: false,
|
||||
triggerAction: 'all',
|
||||
valueField: 'realm',
|
||||
displayField: 'comment',
|
||||
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)) {
|
||||
if (r[0] && r[0].data)
|
||||
def = r[0].data.realm;
|
||||
Ext.each(r, function(record) {
|
||||
if (record.data && record.data["default"])
|
||||
def = record.data.realm;
|
||||
});
|
||||
}
|
||||
if (def)
|
||||
me.setValue(def)
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
@ -1,75 +0,0 @@
|
||||
Ext.define('PVE.form.StorageSelector', {
|
||||
extend: 'PVE.form.ComboGrid',
|
||||
requires: [
|
||||
'Ext.data.Store',
|
||||
'PVE.RestProxy'
|
||||
],
|
||||
alias: ['widget.PVE.form.StorageSelector'],
|
||||
|
||||
setNodename: function(nodename) {
|
||||
var me = this;
|
||||
|
||||
if (!nodename || (me.nodename === nodename))
|
||||
return;
|
||||
|
||||
me.nodename = nodename;
|
||||
|
||||
var url = '/api2/json/nodes/' + me.nodename + '/storage';
|
||||
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', {
|
||||
fields: [ 'storage', 'active', 'type', 'used', 'total' ],
|
||||
autoDestory: true
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
store: store,
|
||||
allowBlank: false,
|
||||
valueField: 'storage',
|
||||
displayField: 'storage',
|
||||
listConfig: {
|
||||
columns: [
|
||||
{
|
||||
header: 'Name',
|
||||
dataIndex: 'storage',
|
||||
hideable: false,
|
||||
flex: 1
|
||||
},
|
||||
{
|
||||
header: 'Type',
|
||||
width: 60,
|
||||
dataIndex: 'type'
|
||||
},
|
||||
{
|
||||
header: 'Used',
|
||||
width: 60,
|
||||
dataIndex: 'used',
|
||||
renderer: PVE.Utils.format_size
|
||||
},
|
||||
{
|
||||
header: 'Capacity',
|
||||
width: 60,
|
||||
dataIndex: 'total',
|
||||
renderer: PVE.Utils.format_size
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
me.setNodename(me.nodename);
|
||||
}
|
||||
});
|
@ -1,35 +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,94 +0,0 @@
|
||||
Ext.define('PVE.form.ViewSelector', {
|
||||
extend: 'Ext.form.ComboBox',
|
||||
requires: ['Ext.data.Store'],
|
||||
alias: ['widget.pveViewSelector'],
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
var default_views = {
|
||||
server: {
|
||||
text: 'Server View',
|
||||
groups: ['node']
|
||||
},
|
||||
folder: {
|
||||
text: 'Folder View',
|
||||
groups: ['type']
|
||||
},
|
||||
storage: {
|
||||
text: 'Storage View',
|
||||
groups: ['node'],
|
||||
filterfn: function(node) {
|
||||
return node.data.type === 'storage';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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,
|
||||
autoDestory: 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,120 +0,0 @@
|
||||
Ext.define('PVE.grid.ObjectGrid', {
|
||||
extend: 'Ext.grid.GridPanel',
|
||||
requires: [
|
||||
'Ext.grid.*',
|
||||
'PVE.data.ObjectStore'
|
||||
],
|
||||
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,
|
||||
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 });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}));
|
||||
|
||||
var load_count = 0;
|
||||
|
||||
me.mon(rstore, 'load', function(s, records, success) {
|
||||
|
||||
load_count++;
|
||||
|
||||
me.setLoading(false);
|
||||
|
||||
if (!success) {
|
||||
me.setLoading("Data load error");
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
Ext.applyIf(me, {
|
||||
store: store,
|
||||
hideHeaders: true,
|
||||
stateful: false,
|
||||
columns: [
|
||||
{
|
||||
header: 'Name',
|
||||
width: me.cwidth1 || 100,
|
||||
dataIndex: 'key',
|
||||
renderer: me.renderKey
|
||||
},
|
||||
{
|
||||
flex: 1,
|
||||
header: 'Value',
|
||||
dataIndex: 'value',
|
||||
renderer: me.renderValue
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
me.on('afterlayout', function() {
|
||||
if (!load_count)
|
||||
me.setLoading(true);
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,203 +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',
|
||||
requires: [
|
||||
'Ext.grid.*',
|
||||
'Ext.grid.feature.Chunking',
|
||||
'Ext.state.Manager',
|
||||
'Ext.data.*',
|
||||
'Ext.data.Store',
|
||||
'Ext.util.*',
|
||||
'PVE.Utils',
|
||||
'PVE.data.ResourceStore'
|
||||
],
|
||||
alias: ['widget.pveResourceGrid'],
|
||||
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) {
|
||||
var cs = cn.childNodes,
|
||||
len = cs.length,
|
||||
i = 0, n, res;
|
||||
|
||||
var orgnode = rstore.data.get(cn.data.id);
|
||||
if (orgnode) {
|
||||
if ((!filterfn || filterfn(cn)) &&
|
||||
(!textfilter || textfilter_match(cn)))
|
||||
nodeidx[cn.data.id] = orgnode;
|
||||
}
|
||||
|
||||
for (; i < len; i++) {
|
||||
gather_child_nodes(cs[i]);
|
||||
}
|
||||
};
|
||||
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 = [];
|
||||
for (var key in nodeidx) {
|
||||
if (!nodeidx.hasOwnProperty(key))
|
||||
continue;
|
||||
|
||||
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;
|
||||
store.model.prototype.fields.eachKey(function(field) {
|
||||
if (field != 'id' && item.data[field] != olditem.data[field]) {
|
||||
changes = true;
|
||||
//console.log("changed item " + item.id + " " + field + " " + item.data[field] + " != " + olditem.data[field]);
|
||||
olditem.beginEdit()
|
||||
olditem.set(field, item.data[field]);
|
||||
}
|
||||
});
|
||||
if (changes) {
|
||||
olditem.endEdit(true)
|
||||
olditem.commit(true);
|
||||
}
|
||||
};
|
||||
|
||||
if (addlist.length)
|
||||
store.add(addlist);
|
||||
|
||||
store.sort();
|
||||
|
||||
store.resumeEvents();
|
||||
|
||||
store.fireEvent('datachanged', store);
|
||||
|
||||
//console.log("END GRID UPDATE");
|
||||
};
|
||||
|
||||
|
||||
var filter_task = new Ext.util.DelayedTask(function(){
|
||||
updateGrid();
|
||||
});
|
||||
|
||||
|
||||
var load_cb = function() { updateGrid(); };
|
||||
|
||||
Ext.apply(me, {
|
||||
title: 'Search',
|
||||
store: store,
|
||||
tbar: [
|
||||
'->',
|
||||
'Search:', ' ',
|
||||
{
|
||||
xtype: 'textfield',
|
||||
width: 200,
|
||||
value: textfilter,
|
||||
enableKeyEvents: true,
|
||||
listeners: {
|
||||
keyup: function(field, e) {
|
||||
var v = field.getValue();
|
||||
textfilter = v;
|
||||
filter_task.delay(500);
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
viewConfig: {
|
||||
stripeRows: true,
|
||||
trackOver: false
|
||||
},
|
||||
listeners: {
|
||||
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,34 +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 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,91 +0,0 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
use strict;
|
||||
use mod_perl2 '1.9922';
|
||||
use Encode;
|
||||
use CGI;
|
||||
use PVE::pvecfg;
|
||||
use PVE::JSONSchema;
|
||||
use PVE::AccessControl;
|
||||
use PVE::REST;
|
||||
|
||||
sub send_output {
|
||||
my ($r, $data) = @_;
|
||||
|
||||
my $encdata = encode('UTF-8', $data);
|
||||
$r->no_cache (1);
|
||||
my $x = length ($encdata);
|
||||
$r->content_type ("text/html;charset=UTF-8");
|
||||
$r->headers_out->set ("Content-length", "$x");
|
||||
$r->headers_out->set ("Pragma", "no-cache");
|
||||
|
||||
$r->print ($encdata);
|
||||
}
|
||||
|
||||
# NOTE: Requests to this page are not authenticated
|
||||
# so we must be very careful here
|
||||
|
||||
my $r = Apache2::RequestUtil->request();
|
||||
my $username;
|
||||
my $token = 'null';
|
||||
if (my $cookie = $r->headers_in->{Cookie}) {
|
||||
my $ticket = PVE::REST::extract_auth_cookie($cookie);
|
||||
if (($username = PVE::AccessControl::verify_ticket($ticket, 1))) {
|
||||
$token = PVE::AccessControl::assemble_csrf_prevention_token($username);
|
||||
}
|
||||
}
|
||||
my $version = PVE::pvecfg::version() . "/" . PVE::pvecfg::repoid();
|
||||
$username = '' if !$username;
|
||||
|
||||
my $cgi = CGI->new($r);
|
||||
my %args = $cgi->Vars();
|
||||
|
||||
my $workspace = defined($args{console}) ?
|
||||
"PVE.ConsoleWorkspace" : "PVE.StdWorkspace";
|
||||
|
||||
my $jssrc = <<_EOJS;
|
||||
if (!PVE) PVE = {};
|
||||
PVE.GUIVersion = '$version';
|
||||
PVE.UserName = '$username';
|
||||
PVE.CSRFPreventionToken = '$token';
|
||||
|
||||
Ext.require(['*', '$workspace']);
|
||||
|
||||
// we need this (the java applet ignores the zindex)
|
||||
Ext.useShims = true;
|
||||
|
||||
Ext.History.fieldid = 'x-history-field';
|
||||
|
||||
Ext.onReady(function() { Ext.create('$workspace');});
|
||||
|
||||
_EOJS
|
||||
|
||||
$jssrc .= "";
|
||||
|
||||
my $page = <<_EOD;
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<title>Proxmox Virtual Environment</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/pve2/ext4/resources/css/ext-all.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/pve2/css/ext-pve.css" />
|
||||
|
||||
<script type="text/javascript" src="/pve2/ext4/ext-all-debug.js"></script>
|
||||
<script type="text/javascript" src="/pve2/ext4/pvemanagerlib.js"></script>
|
||||
|
||||
<script type="text/javascript">$jssrc</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<!-- Fields required for history management -->
|
||||
<form id="history-form" class="x-hidden">
|
||||
<input type="hidden" id="x-history-field"/>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
_EOD
|
||||
|
||||
send_output ($r, $page);
|
||||
exit (0);
|
@ -1,56 +0,0 @@
|
||||
Ext.define('PVE.node.Config', {
|
||||
extend: 'PVE.panel.Config',
|
||||
alias: 'widget.PVE.node.Config',
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
var nodename = me.pveSelNode.data.node;
|
||||
if (!nodename)
|
||||
throw "no node name specified";
|
||||
|
||||
Ext.apply(me, {
|
||||
title: "Node '" + nodename + "'",
|
||||
hstateid: 'nodetab',
|
||||
items: [
|
||||
{
|
||||
title: 'Summary',
|
||||
itemId: 'summary',
|
||||
xtype: 'pveNodeSummary'
|
||||
},
|
||||
{
|
||||
title: 'Services',
|
||||
itemId: 'services',
|
||||
xtype: 'pveNodeServiceView'
|
||||
},
|
||||
{
|
||||
title: 'Network',
|
||||
itemId: 'network',
|
||||
xtype: 'pveNodeNetworkView'
|
||||
},
|
||||
{
|
||||
title: 'DNS',
|
||||
itemId: 'dns',
|
||||
xtype: 'pveNodeDNSView',
|
||||
},
|
||||
{
|
||||
title: 'Time',
|
||||
itemId: 'time',
|
||||
xtype: 'pveNodeTimeView'
|
||||
},
|
||||
{
|
||||
title: 'Syslog',
|
||||
itemId: 'syslog',
|
||||
xtype: 'pveNodeSyslog'
|
||||
},
|
||||
{
|
||||
title: 'Task History',
|
||||
itemId: 'tasks',
|
||||
xtype: 'pveNodeTasks'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,114 +0,0 @@
|
||||
Ext.define('PVE.node.DNSEdit', {
|
||||
extend: 'Ext.window.Window',
|
||||
requires: [
|
||||
'PVE.Utils'
|
||||
],
|
||||
|
||||
alias: ['widget.pveNodeDNSEdit'],
|
||||
|
||||
initComponent : function() {
|
||||
var me = this;
|
||||
|
||||
var nodename = me.pveSelNode.data.node;
|
||||
if (!nodename)
|
||||
throw "no node name specified";
|
||||
|
||||
var formpanel = Ext.create('Ext.form.Panel', {
|
||||
url: "/api2/extjs/nodes/" + nodename + "/dns",
|
||||
method: 'PUT',
|
||||
trackResetOnLoad: true,
|
||||
bodyPadding: 10,
|
||||
|
||||
fieldDefaults: {
|
||||
labelWidth: 130,
|
||||
anchor: '100%'
|
||||
},
|
||||
items: [
|
||||
{
|
||||
xtype: 'textfield',
|
||||
fieldLabel: 'Search domain',
|
||||
name: 'search',
|
||||
allowBlank: false
|
||||
},
|
||||
{
|
||||
xtype: 'textfield',
|
||||
fieldLabel: 'First DNS server',
|
||||
vtype: 'IPAddress',
|
||||
name: 'dns1'
|
||||
},
|
||||
{
|
||||
xtype: 'textfield',
|
||||
fieldLabel: 'Second DNS server',
|
||||
vtype: 'IPAddress',
|
||||
name: 'dns2'
|
||||
},
|
||||
{
|
||||
xtype: 'textfield',
|
||||
fieldLabel: 'Third DNS server',
|
||||
vtype: 'IPAddress',
|
||||
name: 'dns3'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
var form = formpanel.getForm();
|
||||
|
||||
var submitBtn = Ext.create('Ext.Button', {
|
||||
text: 'OK',
|
||||
disabled: true,
|
||||
handler: function() {
|
||||
formpanel.submit({
|
||||
success: function() {
|
||||
me.close();
|
||||
},
|
||||
failure: function(form, action) {
|
||||
Ext.Msg.alert('Error', PVE.Utils.extractFormActionError(action));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var resetBtn = Ext.create('Ext.Button', {
|
||||
text: 'Reset',
|
||||
disabled: true,
|
||||
handler: function(){
|
||||
form.reset();
|
||||
}
|
||||
});
|
||||
|
||||
var set_button_status = function() {
|
||||
var valid = form.isValid();
|
||||
var dirty = form.isDirty();
|
||||
submitBtn.setDisabled(!(valid && dirty));
|
||||
resetBtn.setDisabled(!dirty);
|
||||
|
||||
};
|
||||
|
||||
form.on('dirtychange', set_button_status);
|
||||
form.on('validitychange', set_button_status);
|
||||
|
||||
formpanel.load({
|
||||
method: 'GET',
|
||||
failure: function(form, action) {
|
||||
var msg = PVE.Utils.extractFormActionError(action);
|
||||
Ext.Msg.alert("Load failed", msg, function() {
|
||||
me.close();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Ext.applyIf(me, {
|
||||
title: "Edit DNS settings",
|
||||
modal: true,
|
||||
width: 400,
|
||||
height: 200,
|
||||
layout: 'fit',
|
||||
border: false,
|
||||
items: formpanel,
|
||||
buttons: [ submitBtn, resetBtn ]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,47 +0,0 @@
|
||||
Ext.define('PVE.node.DNSView', {
|
||||
extend: 'PVE.grid.ObjectGrid',
|
||||
alias: ['widget.pveNodeDNSView'],
|
||||
|
||||
initComponent : function() {
|
||||
var me = this;
|
||||
|
||||
var nodename = me.pveSelNode.data.node;
|
||||
if (!nodename)
|
||||
throw "no node name specified";
|
||||
|
||||
|
||||
var run_editor = function() {
|
||||
var win = Ext.create('PVE.node.DNSEdit', {
|
||||
pveSelNode: me.pveSelNode
|
||||
});
|
||||
win.show();
|
||||
};
|
||||
|
||||
Ext.applyIf(me, {
|
||||
url: "/api2/json/nodes/" + nodename + "/dns",
|
||||
cwidth1: 130,
|
||||
interval: 1000,
|
||||
rows: {
|
||||
search: { header: 'Search domain', required: true },
|
||||
dns1: { header: 'First DNS server', required: true },
|
||||
dns2: { header: 'Second DNS server' },
|
||||
dns3: { header: 'Third DNS server' },
|
||||
},
|
||||
tbar: [
|
||||
{
|
||||
text: "Edit",
|
||||
handler: run_editor
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
itemdblclick: run_editor
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
me.on('show', me.rstore.startUpdate);
|
||||
me.on('hide', me.rstore.stopUpdate);
|
||||
me.on('destroy', me.rstore.stopUpdate);
|
||||
}
|
||||
});
|
@ -1,218 +0,0 @@
|
||||
Ext.define('PVE.node.NetworkEdit', {
|
||||
extend: 'Ext.window.Window',
|
||||
alias: ['widget.pveNodeNetworkEdit'],
|
||||
|
||||
initComponent : function() {
|
||||
var me = this;
|
||||
|
||||
var nodename = me.pveSelNode.data.node;
|
||||
if (!nodename)
|
||||
throw "no node name specified";
|
||||
|
||||
if (!me.iftype)
|
||||
throw "no network device type specified";
|
||||
|
||||
var create = !me.iface;
|
||||
|
||||
var title;
|
||||
var iface_vtype;
|
||||
|
||||
if (create) {
|
||||
if (me.iftype === 'bridge') {
|
||||
title = "Create Bridge";
|
||||
iface_vtype = 'BridgeName';
|
||||
} else if (me.iftype === 'bond') {
|
||||
title = "Create Bond";
|
||||
iface_vtype = 'BondName';
|
||||
} else
|
||||
throw "can't create unknown device type";
|
||||
} else {
|
||||
title = "Edit network device '" + me.iface + "'";
|
||||
}
|
||||
|
||||
var col2 = [
|
||||
{
|
||||
xtype: 'pvecheckbox',
|
||||
fieldLabel: 'Autostart',
|
||||
name: 'autostart',
|
||||
uncheckedValue: 0,
|
||||
checked: create ? true : undefined
|
||||
}
|
||||
];
|
||||
|
||||
if (me.iftype === 'bridge') {
|
||||
col2.push({
|
||||
xtype: 'textfield',
|
||||
fieldLabel: 'Bridge ports',
|
||||
name: 'bridge_ports'
|
||||
});
|
||||
} else if (me.iftype === 'bond') {
|
||||
col2.push({
|
||||
xtype: 'textfield',
|
||||
fieldLabel: 'Slaves',
|
||||
name: 'slaves'
|
||||
});
|
||||
col2.push({
|
||||
xtype: 'bondModeSelector',
|
||||
fieldLabel: 'Mode',
|
||||
name: 'bond_mode',
|
||||
value: create ? 'balance-rr' : undefined,
|
||||
allowBlank: false
|
||||
});
|
||||
}
|
||||
|
||||
var url;
|
||||
var method;
|
||||
|
||||
if (create) {
|
||||
url = "/api2/extjs/nodes/" + nodename + "/network";
|
||||
method = 'POST';
|
||||
} else {
|
||||
url = "/api2/extjs/nodes/" + nodename + "/network/" + me.iface;
|
||||
method = 'PUT';
|
||||
}
|
||||
|
||||
var formpanel = Ext.create('Ext.form.Panel', {
|
||||
url: url,
|
||||
method: method,
|
||||
trackResetOnLoad: true,
|
||||
bodyPadding: 10,
|
||||
border: false,
|
||||
fieldDefaults: {
|
||||
labelWidth: 100,
|
||||
anchor: '100%'
|
||||
},
|
||||
layout: 'column',
|
||||
defaultType: 'container',
|
||||
items: [
|
||||
{
|
||||
columnWidth: .5,
|
||||
items: [
|
||||
{
|
||||
xtype: 'textfield',
|
||||
fieldLabel: 'Name',
|
||||
name: 'iface',
|
||||
value: me.iface,
|
||||
disabled: !create,
|
||||
vtype: iface_vtype,
|
||||
allowBlank: false
|
||||
},
|
||||
{
|
||||
xtype: 'pvetextfield',
|
||||
deleteEmpty: !create,
|
||||
fieldLabel: 'IP address',
|
||||
vtype: 'IPAddress',
|
||||
name: 'address'
|
||||
},
|
||||
{
|
||||
xtype: 'pvetextfield',
|
||||
deleteEmpty: !create,
|
||||
fieldLabel: 'Subnet mask',
|
||||
vtype: 'IPAddress',
|
||||
name: 'netmask',
|
||||
validator: function(value) {
|
||||
if (!me.items)
|
||||
return true;
|
||||
var address = me.down('field[name=address]').getValue();
|
||||
if (value !== '') {
|
||||
if (address === '')
|
||||
return "Subnet mask requires option 'IP address'";
|
||||
} else {
|
||||
if (address !== '')
|
||||
return "Option 'IP address' requires a subnet mask";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'pvetextfield',
|
||||
deleteEmpty: !create,
|
||||
fieldLabel: 'Gateway',
|
||||
vtype: 'IPAddress',
|
||||
name: 'gateway'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
columnWidth: .5,
|
||||
items: col2
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
var form = formpanel.getForm();
|
||||
|
||||
var submitBtn = Ext.create('Ext.Button', {
|
||||
text: 'OK',
|
||||
disabled: true,
|
||||
handler: function() {
|
||||
formpanel.submit({
|
||||
success: function() {
|
||||
me.close();
|
||||
},
|
||||
failure: function(form, action) {
|
||||
Ext.Msg.alert('Error', PVE.Utils.extractFormActionError(action));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var resetBtn = Ext.create('Ext.Button', {
|
||||
text: 'Reset',
|
||||
disabled: true,
|
||||
handler: function(){
|
||||
form.reset();
|
||||
}
|
||||
});
|
||||
|
||||
var set_button_status = function() {
|
||||
var valid = form.isValid();
|
||||
var dirty = form.isDirty();
|
||||
submitBtn.setDisabled(!(valid && dirty));
|
||||
resetBtn.setDisabled(!dirty);
|
||||
|
||||
};
|
||||
|
||||
form.on('dirtychange', set_button_status);
|
||||
form.on('validitychange', set_button_status);
|
||||
|
||||
if (!create) {
|
||||
formpanel.load({
|
||||
url: "/api2/extjs/nodes/" + nodename + "/network/" + me.iface,
|
||||
method: 'GET',
|
||||
failure: function(form, action) {
|
||||
var msg = PVE.Utils.extractFormActionError(action);
|
||||
Ext.Msg.alert("Load failed", msg, function() {
|
||||
me.close();
|
||||
});
|
||||
},
|
||||
success: function(form, action) {
|
||||
if (action.result.data.type !== me.iftype) {
|
||||
var msg = "Got unexpected device type";
|
||||
Ext.Msg.alert("Load failed", msg, function() {
|
||||
me.close();
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Ext.applyIf(me, {
|
||||
title: title,
|
||||
modal: true,
|
||||
width: 600,
|
||||
height: 200,
|
||||
layout: 'fit',
|
||||
border: false,
|
||||
items: formpanel,
|
||||
buttons: [ submitBtn, resetBtn ]
|
||||
});
|
||||
|
||||
if (create)
|
||||
form.findField('iface').setValue(me.iface_default);
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,282 +0,0 @@
|
||||
Ext.define('PVE.node.NetworkView', {
|
||||
extend: 'Ext.panel.Panel',
|
||||
|
||||
alias: ['widget.pveNodeNetworkView'],
|
||||
|
||||
initComponent : function() {
|
||||
var me = this;
|
||||
|
||||
var nodename = me.pveSelNode.data.node;
|
||||
if (!nodename)
|
||||
throw "no node name specified";
|
||||
|
||||
var rstore = Ext.create('PVE.data.UpdateStore', {
|
||||
interval: 1000,
|
||||
storeid: 'pve-networks',
|
||||
model: Ext.define('pve-networks', {
|
||||
extend: 'Ext.data.Model',
|
||||
fields: [
|
||||
'iface', 'type', 'active', 'autostart',
|
||||
'bridge_ports', 'slaves', 'address',
|
||||
'netmask', 'gateway'
|
||||
],
|
||||
idProperty: 'iface',
|
||||
proxy: {
|
||||
type: 'pve',
|
||||
url: "/api2/json/nodes/" + nodename + "/network",
|
||||
}
|
||||
}),
|
||||
sorters: [
|
||||
{
|
||||
property : 'iface',
|
||||
direction: 'ASC'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
var store = Ext.create('PVE.data.DiffStore', { rstore: rstore });
|
||||
|
||||
var view_changes = function() {
|
||||
var changeitem = me.down('#changes');
|
||||
PVE.Utils.API2Request({
|
||||
url: '/nodes/' + nodename + '/network_changes',
|
||||
failure: function(response, opts) {
|
||||
changeitem.update('Error: ' + response.htmlStatus);
|
||||
},
|
||||
success: function(response, opts) {
|
||||
var result = Ext.decode(response.responseText);
|
||||
var data = result.data;
|
||||
if (data === '')
|
||||
data = "no changes"
|
||||
changeitem.update("<pre>" + Ext.htmlEncode(data) + "</pre>");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var reload = function() {
|
||||
rstore.load();
|
||||
view_changes();
|
||||
};
|
||||
|
||||
var run_editor = function() {
|
||||
var grid = me.down('gridpanel');
|
||||
var sm = grid.getSelectionModel();
|
||||
var rec = sm.getLastSelected();
|
||||
if (!rec)
|
||||
return;
|
||||
|
||||
var win = Ext.create('PVE.node.NetworkEdit', {
|
||||
pveSelNode: me.pveSelNode,
|
||||
iface: rec.data.iface,
|
||||
iftype: rec.data.type
|
||||
});
|
||||
win.show();
|
||||
win.on('destroy', reload)
|
||||
};
|
||||
|
||||
var edit_btn = new Ext.Button({
|
||||
text: 'Edit',
|
||||
disabled: true,
|
||||
handler: run_editor
|
||||
});
|
||||
|
||||
var del_btn = new Ext.Button({
|
||||
text: 'Delete',
|
||||
disabled: true,
|
||||
handler: function(){
|
||||
var grid = me.down('gridpanel');
|
||||
var sm = grid.getSelectionModel();
|
||||
var rec = sm.getLastSelected();
|
||||
if (!rec)
|
||||
return;
|
||||
|
||||
var iface = rec.data.iface;
|
||||
|
||||
me.setLoading(true, true);
|
||||
PVE.Utils.API2Request({
|
||||
url: '/nodes/' + nodename + '/network/' + iface,
|
||||
method: 'DELETE',
|
||||
callback: function() {
|
||||
me.setLoading(false);
|
||||
reload();
|
||||
},
|
||||
failure: function(response, opts) {
|
||||
Ext.Msg.alert('Error', response.htmlStatus);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var set_button_status = function() {
|
||||
var grid = me.down('gridpanel');
|
||||
var sm = grid.getSelectionModel();
|
||||
var rec = sm.getLastSelected();
|
||||
|
||||
edit_btn.setDisabled(!rec);
|
||||
del_btn.setDisabled(!rec);
|
||||
};
|
||||
|
||||
me.mon(rstore, 'load', function(s, records, success) {
|
||||
if (!success) {
|
||||
me.setLoading("Data load error");
|
||||
return;
|
||||
} else {
|
||||
me.setLoading(false);
|
||||
}
|
||||
});
|
||||
|
||||
var render_ports = function(value, metaData, record) {
|
||||
if (value === 'bridge')
|
||||
return record.data.bridge_ports;
|
||||
if (value === 'bond')
|
||||
return record.data.slaves;
|
||||
};
|
||||
|
||||
Ext.apply(me, {
|
||||
layout: 'border',
|
||||
tbar: [
|
||||
{
|
||||
text: 'Create',
|
||||
menu: new Ext.menu.Menu({
|
||||
items: [
|
||||
{
|
||||
text: 'Bridge',
|
||||
handler: function() {
|
||||
var next;
|
||||
for (next = 0; next <= 9999; next++) {
|
||||
if (!rstore.data.get('vmbr' + next))
|
||||
break;
|
||||
}
|
||||
|
||||
var win = Ext.create('PVE.node.NetworkEdit', {
|
||||
pveSelNode: me.pveSelNode,
|
||||
iftype: 'bridge',
|
||||
iface_default: 'vmbr' + next
|
||||
});
|
||||
win.on('destroy', reload)
|
||||
win.show();
|
||||
}
|
||||
},
|
||||
{
|
||||
text: 'Bond',
|
||||
handler: function() {
|
||||
var next;
|
||||
for (next = 0; next <= 9999; next++) {
|
||||
if (!rstore.data.get('bond' + next))
|
||||
break;
|
||||
}
|
||||
var win = Ext.create('PVE.node.NetworkEdit', {
|
||||
pveSelNode: me.pveSelNode,
|
||||
iftype: 'bond',
|
||||
iface_default: 'bond' + next
|
||||
});
|
||||
win.on('destroy', reload)
|
||||
win.show();
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
}, ' ',
|
||||
{
|
||||
text: 'Revert changes',
|
||||
handler: function() {
|
||||
me.setLoading(true, true);
|
||||
PVE.Utils.API2Request({
|
||||
url: '/nodes/' + nodename + '/network_changes',
|
||||
method: 'DELETE',
|
||||
callback: function() {
|
||||
me.setLoading(false);
|
||||
reload();
|
||||
},
|
||||
failure: function(response, opts) {
|
||||
Ext.Msg.alert('Error', response.htmlStatus);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
edit_btn,
|
||||
del_btn
|
||||
],
|
||||
items: [
|
||||
{
|
||||
xtype: 'gridpanel',
|
||||
stateful: false,
|
||||
store: store,
|
||||
region: 'center',
|
||||
border: false,
|
||||
columns: [
|
||||
{
|
||||
header: 'Interface Name',
|
||||
width: 100,
|
||||
sortable: true,
|
||||
dataIndex: 'iface'
|
||||
},
|
||||
{
|
||||
xtype: 'booleancolumn',
|
||||
header: 'Active',
|
||||
width: 80,
|
||||
sortable: true,
|
||||
dataIndex: 'active',
|
||||
trueText: 'Yes',
|
||||
falseText: 'No',
|
||||
undefinedText: 'No'
|
||||
},
|
||||
{
|
||||
xtype: 'booleancolumn',
|
||||
header: 'Autostart',
|
||||
width: 80,
|
||||
sortable: true,
|
||||
dataIndex: 'autostart',
|
||||
trueText: 'Yes',
|
||||
falseText: 'No',
|
||||
undefinedText: 'No'
|
||||
},
|
||||
{
|
||||
header: 'Ports/Slaves',
|
||||
dataIndex: 'type',
|
||||
renderer: render_ports
|
||||
},
|
||||
{
|
||||
header: 'IP address',
|
||||
sortable: true,
|
||||
dataIndex: 'address'
|
||||
},
|
||||
{
|
||||
header: 'Subnet mask',
|
||||
sortable: true,
|
||||
dataIndex: 'netmask'
|
||||
},
|
||||
{
|
||||
header: 'Gateway',
|
||||
sortable: true,
|
||||
dataIndex: 'gateway'
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
selectionchange: set_button_status,
|
||||
itemdblclick: run_editor
|
||||
}
|
||||
},
|
||||
{
|
||||
border: false,
|
||||
region: 'south',
|
||||
autoScroll: true,
|
||||
itemId: 'changes',
|
||||
tbar: [
|
||||
'Pending changes (please reboot to activate changes)'
|
||||
],
|
||||
split: true,
|
||||
bodyPadding: 5,
|
||||
flex: 0.6,
|
||||
html: "no changes"
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
show: reload
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
||||
|
@ -1,151 +0,0 @@
|
||||
Ext.define('PVE.node.ServiceView', {
|
||||
extend: 'Ext.grid.GridPanel',
|
||||
|
||||
alias: ['widget.pveNodeServiceView'],
|
||||
|
||||
initComponent : function() {
|
||||
var me = this;
|
||||
|
||||
var nodename = me.pveSelNode.data.node;
|
||||
if (!nodename)
|
||||
throw "no node name specified";
|
||||
|
||||
var rstore = Ext.create('PVE.data.UpdateStore', {
|
||||
interval: 1000,
|
||||
storeid: 'pve-services',
|
||||
model: Ext.define('pve-services', {
|
||||
extend: 'Ext.data.Model',
|
||||
fields: [ 'service', 'name', 'desc', 'state' ],
|
||||
idProperty: 'service',
|
||||
proxy: {
|
||||
type: 'pve',
|
||||
url: "/api2/json/nodes/" + nodename + "/services",
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
var store = Ext.create('PVE.data.DiffStore', { rstore: rstore });
|
||||
|
||||
var service_cmd = function(cmd) {
|
||||
var sm = me.getSelectionModel();
|
||||
var rec = sm.getLastSelected();
|
||||
PVE.Utils.API2Request({
|
||||
url: "/nodes/" + nodename + "/services/" + rec.data.service,
|
||||
params: { command: cmd },
|
||||
method: 'PUT',
|
||||
failure: function(response, opts) {
|
||||
Ext.Msg.alert('Error', response.htmlStatus);
|
||||
me.loading = true;
|
||||
},
|
||||
success: function(response, opts) {
|
||||
rstore.startUpdate();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var start_btn = new Ext.Button({
|
||||
text: 'Start',
|
||||
disabled: true,
|
||||
handler: function(){
|
||||
service_cmd("start");
|
||||
}
|
||||
});
|
||||
|
||||
var stop_btn = new Ext.Button({
|
||||
text: 'Stop',
|
||||
disabled: true,
|
||||
handler: function(){
|
||||
service_cmd("stop");
|
||||
}
|
||||
});
|
||||
|
||||
var restart_btn = new Ext.Button({
|
||||
text: 'Restart',
|
||||
disabled: true,
|
||||
handler: function(){
|
||||
service_cmd("restart");
|
||||
}
|
||||
});
|
||||
|
||||
var set_button_status = function() {
|
||||
var sm = me.getSelectionModel();
|
||||
var rec = sm.getLastSelected();
|
||||
|
||||
if (!rec) {
|
||||
start_btn.disable();
|
||||
stop_btn.disable();
|
||||
restart_btn.disable();
|
||||
return;
|
||||
}
|
||||
var service = rec.data.service;
|
||||
var state = rec.data.state;
|
||||
if (service == 'apache' ||
|
||||
service == 'pvecluster' ||
|
||||
service == 'pvedaemon') {
|
||||
if (state == 'running') {
|
||||
start_btn.disable();
|
||||
restart_btn.enable();
|
||||
} else {
|
||||
start_btn.enable();
|
||||
restart_btn.disable();
|
||||
}
|
||||
stop_btn.disable();
|
||||
} else {
|
||||
if (state == 'running') {
|
||||
start_btn.disable();
|
||||
restart_btn.enable();
|
||||
stop_btn.enable();
|
||||
} else {
|
||||
start_btn.enable();
|
||||
restart_btn.disable();
|
||||
stop_btn.disable();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
me.mon(store, 'datachanged', set_button_status);
|
||||
|
||||
me.mon(rstore, 'load', function(s, records, success) {
|
||||
if (!success) {
|
||||
me.setLoading("Data load error");
|
||||
return;
|
||||
} else {
|
||||
me.setLoading(false);
|
||||
}
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
store: store,
|
||||
stateful: false,
|
||||
tbar: [ start_btn, stop_btn, restart_btn ],
|
||||
columns: [
|
||||
{
|
||||
header: 'Name',
|
||||
width: 100,
|
||||
sortable: true,
|
||||
dataIndex: 'name'
|
||||
},
|
||||
{
|
||||
header: 'State',
|
||||
width: 100,
|
||||
sortable: true,
|
||||
dataIndex: 'state'
|
||||
},
|
||||
{
|
||||
header: 'Description',
|
||||
dataIndex: 'desc',
|
||||
flex: 1
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
selectionchange: set_button_status,
|
||||
show: rstore.startUpdate,
|
||||
hide: rstore.stopUpdate,
|
||||
destroy: rstore.stopUpdate,
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
||||
|
@ -1,50 +0,0 @@
|
||||
Ext.define('PVE.node.StatusView', {
|
||||
extend: 'PVE.grid.ObjectGrid',
|
||||
alias: ['widget.pveNodeStatusView'],
|
||||
|
||||
initComponent : function() {
|
||||
var me = this;
|
||||
|
||||
var render_cpuinfo = function(value) {
|
||||
return value.cpus + " x " + value.model;
|
||||
};
|
||||
|
||||
var render_loadavg = function(value) {
|
||||
return value[0] + ", " + value[1] + ", " + value[2];
|
||||
};
|
||||
|
||||
var render_cpu = function(value) {
|
||||
var per = value * 100;
|
||||
return per.toFixed(2) + "%";
|
||||
};
|
||||
|
||||
var render_meminfo = function(value) {
|
||||
var per = (value.used / value.total)*100;
|
||||
var text = "<div>Total: " + PVE.Utils.format_size(value.total) + "</div>" +
|
||||
"<div>Used: " + PVE.Utils.format_size(value.used) + "</div>";
|
||||
return text;
|
||||
};
|
||||
|
||||
var rows = {
|
||||
uptime: { header: 'Uptime', required: true, renderer: PVE.Utils.format_duration_long },
|
||||
loadavg: { header: 'Load average', required: true, renderer: render_loadavg },
|
||||
cpuinfo: { header: 'CPUs', required: true, renderer: render_cpuinfo },
|
||||
cpu: { header: 'CPU usage',required: true, renderer: render_cpu },
|
||||
wait: { header: 'IO delay', required: true, renderer: render_cpu },
|
||||
memory: { header: 'RAM usage', required: true, renderer: render_meminfo },
|
||||
swap: { header: 'SWAP usage', required: true, renderer: render_meminfo },
|
||||
rootfs: { header: 'HD space (root)', required: true, renderer: render_meminfo },
|
||||
pveversion: { header: 'PVE Manager version', required: true,},
|
||||
kversion: { header: 'Kernel version', required: true,}
|
||||
};
|
||||
|
||||
Ext.applyIf(me, {
|
||||
cwidth1: 150,
|
||||
interval: 1000,
|
||||
height: 286,
|
||||
rows: rows
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,139 +0,0 @@
|
||||
Ext.define('PVE.node.Summary', {
|
||||
extend: 'Ext.panel.Panel',
|
||||
alias: 'widget.pveNodeSummary',
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
var nodename = me.pveSelNode.data.node;
|
||||
if (!nodename)
|
||||
throw "no node name specified";
|
||||
|
||||
rstore = Ext.create('PVE.data.ObjectStore', {
|
||||
url: "/api2/json/nodes/" + nodename + "/status",
|
||||
interval: 1000
|
||||
});
|
||||
|
||||
var node_command = function(cmd) {
|
||||
me.setLoading(true, true);
|
||||
PVE.Utils.API2Request({
|
||||
params: { command: cmd },
|
||||
url: '/nodes/' + nodename + '/status',
|
||||
method: 'POST',
|
||||
callback: function() {
|
||||
me.setLoading(false);
|
||||
},
|
||||
failure: function(response, opts) {
|
||||
Ext.Msg.alert('Error', response.htmlStatus);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var rrdurl = "/api2/png/nodes/" + nodename + "/rrd";
|
||||
|
||||
var tbar = Ext.create('Ext.toolbar.Toolbar', {
|
||||
items: [
|
||||
{
|
||||
itemId: 'reboot',
|
||||
text: 'Reboot',
|
||||
handler: function() {
|
||||
var msg = "Do you really want to reboot node '" + nodename + "'?";
|
||||
Ext.Msg.confirm('Confirm', msg, function(btn) {
|
||||
if (btn !== 'yes')
|
||||
return;
|
||||
node_command('reboot');
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
itemId: 'shutdown',
|
||||
text: 'Shutdown',
|
||||
handler: function() {
|
||||
var msg = "Do you really want to shutdown node '" + nodename + "'?";
|
||||
Ext.Msg.confirm('Confirm', msg, function(btn) {
|
||||
if (btn !== 'yes')
|
||||
return;
|
||||
node_command('shutdown');
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
itemId: 'shell',
|
||||
text: 'Shell',
|
||||
handler: function() {
|
||||
var url = Ext.urlEncode({
|
||||
console: 'shell',
|
||||
node: nodename
|
||||
});
|
||||
var nw = window.open("?" + url, '_blank',
|
||||
"innerWidth=745,innerheight=427");
|
||||
nw.focus();
|
||||
}
|
||||
}, '->',
|
||||
{
|
||||
xtype: 'pveRRDTypeSelector'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
me.mon(rstore, 'load', function(s, records, success) {
|
||||
var uptimerec = s.data.get('uptime');
|
||||
var uptime = uptimerec ? uptimerec.data.value : false;
|
||||
|
||||
tbar.down('#reboot').setDisabled(!uptime);
|
||||
tbar.down('#shutdown').setDisabled(!uptime);
|
||||
tbar.down('#shell').setDisabled(!uptime);
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
layout: {
|
||||
type: 'table',
|
||||
columns: 1
|
||||
},
|
||||
autoScroll: true,
|
||||
bodyStyle: 'padding:10px',
|
||||
defaults: {
|
||||
style: 'padding-bottom:10px'
|
||||
},
|
||||
tbar: tbar,
|
||||
items: [
|
||||
{
|
||||
title: 'Status',
|
||||
xtype: 'pveNodeStatusView',
|
||||
rstore: rstore,
|
||||
width: 800
|
||||
},
|
||||
{
|
||||
xtype: 'pveRRDView',
|
||||
title: "CPU usage %",
|
||||
datasource: 'cpu,iowait',
|
||||
rrdurl: rrdurl
|
||||
},
|
||||
{
|
||||
xtype: 'pveRRDView',
|
||||
title: "Server load",
|
||||
datasource: 'loadavg',
|
||||
rrdurl: rrdurl
|
||||
},
|
||||
{
|
||||
xtype: 'pveRRDView',
|
||||
title: "Memory usage",
|
||||
datasource: 'memtotal,memused',
|
||||
rrdurl: rrdurl
|
||||
},
|
||||
{
|
||||
xtype: 'pveRRDView',
|
||||
title: "Network traffic",
|
||||
datasource: 'netin,netout',
|
||||
rrdurl: rrdurl
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
me.on('show', rstore.startUpdate);
|
||||
me.on('hide', rstore.stopUpdate);
|
||||
me.on('destroy', rstore.stopUpdate);
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,47 +0,0 @@
|
||||
Ext.define('PVE.node.Syslog', {
|
||||
extend: 'Ext.grid.GridPanel',
|
||||
|
||||
alias: ['widget.pveNodeSyslog'],
|
||||
|
||||
initComponent : function() {
|
||||
var me = this;
|
||||
|
||||
var nodename = me.pveSelNode.data.node;
|
||||
if (!nodename)
|
||||
throw "no node name specified";
|
||||
|
||||
var store = Ext.create('Ext.data.Store', {
|
||||
pageSize: 500,
|
||||
buffered: true,
|
||||
model: 'pve-string-list',
|
||||
proxy: {
|
||||
type: 'pve',
|
||||
startParam: 'start',
|
||||
limitParam: 'limit',
|
||||
url: "/api2/json/nodes/" + nodename + "/syslog"
|
||||
}
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
store: store,
|
||||
features: [ {ftype: 'selectable'}],
|
||||
stateful: false,
|
||||
verticalScrollerType: 'paginggridscroller',
|
||||
loadMask: true,
|
||||
invalidateScrollerOnRefresh: false,
|
||||
viewConfig: {
|
||||
trackOver: false,
|
||||
stripeRows: false
|
||||
},
|
||||
hideHeaders: true,
|
||||
columns: [
|
||||
{ header: "Text", dataIndex: 't', flex: 1 }
|
||||
]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
store.guaranteeRange(0, store.pageSize - 1);
|
||||
}
|
||||
});
|
||||
|
@ -1,159 +0,0 @@
|
||||
Ext.define('PVE.node.Tasks', {
|
||||
extend: 'Ext.grid.GridPanel',
|
||||
|
||||
alias: ['widget.pveNodeTasks'],
|
||||
|
||||
initComponent : function() {
|
||||
var me = this;
|
||||
|
||||
var nodename = me.pveSelNode.data.node;
|
||||
if (!nodename)
|
||||
throw "no node name specified";
|
||||
|
||||
var store = Ext.create('Ext.data.Store', {
|
||||
pageSize: 500,
|
||||
buffered: true,
|
||||
remoteFilter: true,
|
||||
model: 'pve-tasks',
|
||||
proxy: {
|
||||
type: 'pve',
|
||||
startParam: 'start',
|
||||
limitParam: 'limit',
|
||||
|
||||
url: "/api2/json/nodes/" + nodename + "/tasks"
|
||||
},
|
||||
});
|
||||
|
||||
var userfilter = '';
|
||||
var filter_errors = 0;
|
||||
|
||||
// fixme: scroller update fails
|
||||
// http://www.sencha.com/forum/showthread.php?133677-scroller-does-not-adjust-to-the-filtered-grid-data&p=602887
|
||||
var reload_task = new Ext.util.DelayedTask(function() {
|
||||
var params = {
|
||||
errors: filter_errors
|
||||
};
|
||||
if (userfilter)
|
||||
params.userfilter = userfilter;
|
||||
|
||||
store.proxy.extraParams = params;
|
||||
store.filter();
|
||||
});
|
||||
|
||||
var run_task_viewer = function() {
|
||||
var sm = me.getSelectionModel();
|
||||
var rec = sm.getLastSelected();
|
||||
if (!rec)
|
||||
return;
|
||||
|
||||
var win = Ext.create('PVE.window.TaskViewer', {
|
||||
upid: rec.data.upid
|
||||
});
|
||||
win.show();
|
||||
};
|
||||
|
||||
var view_btn = new Ext.Button({
|
||||
text: 'View',
|
||||
disabled: true,
|
||||
handler: run_task_viewer
|
||||
});
|
||||
|
||||
|
||||
Ext.apply(me, {
|
||||
store: store,
|
||||
stateful: false,
|
||||
verticalScrollerType: 'paginggridscroller',
|
||||
loadMask: true,
|
||||
invalidateScrollerOnRefresh: 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";
|
||||
}
|
||||
},
|
||||
tbar: [
|
||||
view_btn, '->', 'User:', ' ',
|
||||
{
|
||||
xtype: 'textfield',
|
||||
width: 200,
|
||||
value: userfilter,
|
||||
enableKeyEvents: true,
|
||||
listeners: {
|
||||
keyup: function(field, e) {
|
||||
userfilter = field.getValue();
|
||||
reload_task.delay(500);
|
||||
}
|
||||
}
|
||||
}, ' ', 'Only Errors:', ' ',
|
||||
{
|
||||
xtype: 'checkbox',
|
||||
hideLabel: true,
|
||||
checked: filter_errors,
|
||||
listeners: {
|
||||
change: function(field, checked) {
|
||||
filter_errors = checked ? 1 : 0;
|
||||
reload_task.delay(10);
|
||||
}
|
||||
}
|
||||
}, ' '
|
||||
],
|
||||
sortableColumns: false,
|
||||
columns: [
|
||||
{
|
||||
header: "Start Time", dataIndex: 'starttime',
|
||||
width: 100,
|
||||
renderer: function(value) {
|
||||
return Ext.Date.format(value, "M d H:i:s");
|
||||
}
|
||||
},
|
||||
{
|
||||
header: "End Time", dataIndex: 'endtime',
|
||||
width: 100,
|
||||
renderer: function(value, metaData, record) {
|
||||
return Ext.Date.format(value,"M d H:i:s");
|
||||
}
|
||||
},
|
||||
{
|
||||
header: "Node", dataIndex: 'node',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
header: "User", dataIndex: 'user',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
header: "Description", dataIndex: 'upid',
|
||||
flex: 1,
|
||||
renderer: PVE.Utils.render_upid
|
||||
},
|
||||
{
|
||||
header: "Status", dataIndex: 'status',
|
||||
width: 200,
|
||||
renderer: function(value, metaData, record) {
|
||||
if (value == 'OK')
|
||||
return 'OK';
|
||||
// metaData.attr = 'style="color:red;"';
|
||||
return "ERROR: " + value;
|
||||
}
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
itemdblclick: run_task_viewer,
|
||||
selectionchange: function(v, selections) {
|
||||
view_btn.setDisabled(!(selections && selections[0]));
|
||||
},
|
||||
show: function() { reload_task.delay(10); }
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
store.guaranteeRange(0, store.pageSize - 1);
|
||||
}
|
||||
});
|
||||
|
@ -1,98 +0,0 @@
|
||||
Ext.define('PVE.node.TimeEdit', {
|
||||
extend: 'Ext.window.Window',
|
||||
requires: ['PVE.data.TimezoneStore'],
|
||||
alias: ['widget.pveNodeTimeEdit'],
|
||||
|
||||
initComponent : function() {
|
||||
var me = this;
|
||||
|
||||
var nodename = me.pveSelNode.data.node;
|
||||
if (!nodename)
|
||||
throw "no node name specified";
|
||||
|
||||
var formpanel = Ext.create('Ext.form.Panel', {
|
||||
url: "/api2/extjs/nodes/" + nodename + "/time",
|
||||
method: 'PUT',
|
||||
trackResetOnLoad: true,
|
||||
bodyPadding: 10,
|
||||
|
||||
fieldDefaults: {
|
||||
labelWidth: 80,
|
||||
anchor: '100%'
|
||||
},
|
||||
|
||||
items: {
|
||||
xtype: 'combo',
|
||||
fieldLabel: 'Time zone',
|
||||
name: 'timezone',
|
||||
queryMode: 'local',
|
||||
store: new PVE.data.TimezoneStore({autoDestory: true}),
|
||||
valueField: 'zone',
|
||||
displayField: 'zone',
|
||||
triggerAction: 'all',
|
||||
forceSelection: true,
|
||||
editable: false,
|
||||
allowBlank: false
|
||||
}
|
||||
});
|
||||
|
||||
var form = formpanel.getForm();
|
||||
|
||||
var submitBtn = Ext.create('Ext.Button', {
|
||||
text: 'OK',
|
||||
disabled: true,
|
||||
handler: function() {
|
||||
formpanel.submit({
|
||||
success: function() {
|
||||
me.close();
|
||||
},
|
||||
failure: function(form, action) {
|
||||
Ext.Msg.alert('Error', PVE.Utils.extractFormActionError(action));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var resetBtn = Ext.create('Ext.Button', {
|
||||
text: 'Reset',
|
||||
disabled: true,
|
||||
handler: function(){
|
||||
form.reset();
|
||||
}
|
||||
});
|
||||
|
||||
var set_button_status = function() {
|
||||
var valid = form.isValid();
|
||||
var dirty = form.isDirty();
|
||||
submitBtn.setDisabled(!(valid && dirty));
|
||||
resetBtn.setDisabled(!dirty);
|
||||
|
||||
};
|
||||
|
||||
form.on('dirtychange', set_button_status);
|
||||
form.on('validitychange', set_button_status);
|
||||
|
||||
formpanel.load({
|
||||
method: 'GET',
|
||||
failure: function(form, action) {
|
||||
var msg = PVE.Utils.extractFormActionError(action);
|
||||
Ext.Msg.alert("Load failed", msg, function() {
|
||||
me.close();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Ext.applyIf(me, {
|
||||
title: "Set time zone",
|
||||
modal: true,
|
||||
width: 400,
|
||||
height: 110,
|
||||
layout: 'fit',
|
||||
border: false,
|
||||
items: formpanel,
|
||||
buttons: [ submitBtn, resetBtn ]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,57 +0,0 @@
|
||||
Ext.define('PVE.node.TimeView', {
|
||||
extend: 'PVE.grid.ObjectGrid',
|
||||
alias: ['widget.pveNodeTimeView'],
|
||||
|
||||
initComponent : function() {
|
||||
var me = this;
|
||||
|
||||
var nodename = me.pveSelNode.data.node;
|
||||
if (!nodename)
|
||||
throw "no node name specified";
|
||||
|
||||
var tzoffset = (new Date()).getTimezoneOffset()*60000;
|
||||
var renderlocaltime = function(value) {
|
||||
var servertime = new Date((value * 1000) + tzoffset);
|
||||
return Ext.Date.format(servertime, 'Y-m-d H:i:s');
|
||||
};
|
||||
|
||||
var run_editor = function() {
|
||||
var win = Ext.create('PVE.node.TimeEdit', {
|
||||
pveSelNode: me.pveSelNode
|
||||
});
|
||||
win.show();
|
||||
};
|
||||
|
||||
Ext.applyIf(me, {
|
||||
url: "/api2/json/nodes/" + nodename + "/time",
|
||||
cwidth1: 150,
|
||||
interval: 1000,
|
||||
rows: {
|
||||
timezone: {
|
||||
header: 'Time zone',
|
||||
required: true,
|
||||
},
|
||||
localtime: {
|
||||
header: 'Server time',
|
||||
required: true,
|
||||
renderer: renderlocaltime
|
||||
}
|
||||
},
|
||||
tbar: [
|
||||
{
|
||||
text: "Edit",
|
||||
handler: run_editor
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
itemdblclick: run_editor
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
me.on('show', me.rstore.startUpdate);
|
||||
me.on('hide', me.rstore.stopUpdate);
|
||||
me.on('destroy', me.rstore.stopUpdate);
|
||||
}
|
||||
});
|
@ -1,24 +0,0 @@
|
||||
Ext.define('PVE.openvz.CreateWizard', {
|
||||
extend: 'PVE.window.Wizard',
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
Ext.applyIf(me, {
|
||||
title: 'Create new container',
|
||||
items: [
|
||||
{
|
||||
title: 'Not implemented',
|
||||
descr: 'Sorry, this fuctionality is not implelemnted',
|
||||
layout: 'fit',
|
||||
html: 'not implemented'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
@ -1,85 +0,0 @@
|
||||
Ext.define('PVE.panel.Config', {
|
||||
extend: 'Ext.tab.Panel',
|
||||
requires: [
|
||||
'Ext.state.Manager',
|
||||
'PVE.grid.ResourceGrid'
|
||||
],
|
||||
alias: 'widget.PVE.panel.Config',
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
var stateid = me.hstateid;
|
||||
|
||||
var sp = Ext.state.Manager.getProvider();
|
||||
|
||||
var items = me.items || [];
|
||||
me.items = null;
|
||||
|
||||
Ext.applyIf(me, {
|
||||
title: me.pveSelNode.data.text,
|
||||
showSearch: true,
|
||||
defaults: {}
|
||||
});
|
||||
|
||||
// pass rstore, pveSelNode and viewFilter to all children
|
||||
Ext.apply(me.defaults, {
|
||||
pveSelNode: me.pveSelNode,
|
||||
viewFilter: me.viewFilter,
|
||||
border: false
|
||||
});
|
||||
|
||||
if (me.showSearch) {
|
||||
items.unshift({
|
||||
itemId: 'search',
|
||||
xtype: 'pveResourceGrid'
|
||||
});
|
||||
}
|
||||
|
||||
Ext.apply(me, {
|
||||
listeners: {
|
||||
tabchange: function(tp, newcard, oldcard) {
|
||||
var ntab = newcard.itemId;
|
||||
// Note: '' is alias for first tab.
|
||||
// First tab can be 'search' or something else
|
||||
if (newcard.itemId === items[0].itemId)
|
||||
ntab = '';
|
||||
var state = { value: ntab };
|
||||
if (stateid) {
|
||||
sp.set(stateid, state);
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
items: items
|
||||
});
|
||||
|
||||
if (stateid) {
|
||||
var state = sp.get(stateid);
|
||||
if (state && state.value) {
|
||||
me.activeTab = state.value;
|
||||
}
|
||||
}
|
||||
|
||||
me.callParent();
|
||||
|
||||
me.items.get(0).fireEvent('show', me.items.get(0));
|
||||
|
||||
var statechange = function(sp, key, state) {
|
||||
if (stateid && key === stateid) {
|
||||
var atab = me.getActiveTab().itemId;
|
||||
var ntab = state.value || items[0].itemId;
|
||||
if (state && ntab && (atab != ntab)) {
|
||||
me.setActiveTab(ntab);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (stateid) {
|
||||
sp.on('statechange', statechange);
|
||||
me.on('destroy', function() {
|
||||
sp.un('statechange', statechange);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
@ -1,89 +0,0 @@
|
||||
Ext.define('PVE.panel.RRDView', {
|
||||
extend: 'Ext.panel.Panel',
|
||||
alias: 'widget.pveRRDView',
|
||||
|
||||
initComponent : function() {
|
||||
var me = this;
|
||||
|
||||
if (!me.timeframe)
|
||||
me.timeframe = 'hour';
|
||||
if (!me.rrdcffn)
|
||||
me.rrdcffn = 'AVERAGE';
|
||||
|
||||
if (!me.datasource)
|
||||
throw "no datasource specified";
|
||||
|
||||
if (!me.rrdurl)
|
||||
throw "no rrdurl specified";
|
||||
|
||||
var datasource = me.datasource;
|
||||
|
||||
// fixme: dcindex??
|
||||
var dcindex = 0;
|
||||
var create_url = function() {
|
||||
var url = me.rrdurl + "?ds=" + datasource +
|
||||
"&timeframe=" + me.timeframe + "&cf=" + me.rrdcffn +
|
||||
"&_dc=" + dcindex;
|
||||
dcindex++;
|
||||
return url;
|
||||
}
|
||||
|
||||
var stateid = 'pveRRDTypeSelection';
|
||||
|
||||
Ext.apply(me, {
|
||||
layout: 'fit',
|
||||
html: {
|
||||
tag: 'img',
|
||||
width: 800,
|
||||
height: 200,
|
||||
src: create_url()
|
||||
},
|
||||
applyState : function(state) {
|
||||
if (state && state.id) {
|
||||
me.timeframe = state.timeframe;
|
||||
me.rrdcffn = state.cf;
|
||||
me.reload_task.delay(10);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
me.reload_task = new Ext.util.DelayedTask(function() {
|
||||
if (me.rendered) {
|
||||
try {
|
||||
var html = {
|
||||
tag: 'img',
|
||||
width: 800,
|
||||
height: 200,
|
||||
src: create_url()
|
||||
};
|
||||
me.update(html);
|
||||
} catch (e) {
|
||||
// fixme:
|
||||
console.log(e);
|
||||
}
|
||||
me.reload_task.delay(30000);
|
||||
} else {
|
||||
me.reload_task.delay(1000);
|
||||
}
|
||||
});
|
||||
|
||||
me.reload_task.delay(30000);
|
||||
|
||||
me.on('destroy', function() {
|
||||
me.reload_task.cancel();
|
||||
});
|
||||
|
||||
var sp = Ext.state.Manager.getProvider();
|
||||
me.applyState(sp.get(stateid));
|
||||
|
||||
var state_change_fn = function(prov, key, value) {
|
||||
if (key == stateid) {
|
||||
me.applyState(value);
|
||||
}
|
||||
};
|
||||
|
||||
me.mon(sp, 'statechange', state_change_fn);
|
||||
}
|
||||
});
|
@ -1,66 +0,0 @@
|
||||
Ext.define('PVE.panel.StatusPanel', {
|
||||
extend: 'Ext.tab.Panel',
|
||||
requires: [
|
||||
'Ext.state.Manager',
|
||||
'PVE.dc.Log',
|
||||
'PVE.dc.Tasks'
|
||||
],
|
||||
alias: 'widget.pveStatusPanel',
|
||||
|
||||
title: "Realtime logfile viewer",
|
||||
tabPosition: 'bottom',
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
var stateid = 'ltab';
|
||||
var sp = Ext.state.Manager.getProvider();
|
||||
|
||||
var state = sp.get(stateid);
|
||||
if (state && state.value) {
|
||||
me.activeTab = state.value;
|
||||
}
|
||||
|
||||
Ext.apply(me, {
|
||||
listeners: {
|
||||
tabchange: function() {
|
||||
var atab = me.getActiveTab().itemId;
|
||||
var state = { value: atab };
|
||||
sp.set(stateid, state);
|
||||
}
|
||||
},
|
||||
items: [
|
||||
{
|
||||
itemId: 'clog',
|
||||
title: 'Cluster log',
|
||||
xtype: 'pveClusterLog'
|
||||
},
|
||||
{
|
||||
itemId: 'tasks',
|
||||
title: 'Recent tasks',
|
||||
xtype: 'pveClusterTasks'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
me.items.get(0).fireEvent('show', me.items.get(0));
|
||||
|
||||
var statechange = function(sp, key, state) {
|
||||
if (key === stateid) {
|
||||
var atab = me.getActiveTab().itemId;
|
||||
var ntab = state.value;
|
||||
if (state && ntab && (atab != ntab)) {
|
||||
me.setActiveTab(ntab);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
sp.on('statechange', statechange);
|
||||
me.on('destroy', function() {
|
||||
sp.un('statechange', statechange);
|
||||
});
|
||||
|
||||
}
|
||||
});
|
@ -1,57 +0,0 @@
|
||||
Ext.define('PVE.qemu.Config', {
|
||||
extend: 'PVE.panel.Config',
|
||||
alias: 'widget.PVE.qemu.Config',
|
||||
|
||||
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 vmname = me.pveSelNode.data.name;
|
||||
var descr = vmname ? "'" + vmname + "' " : '';
|
||||
Ext.apply(me, {
|
||||
title: "Virtual machine " + descr + "'KVM " + vmid +
|
||||
"' on node '" + nodename + "'",
|
||||
hstateid: 'kvmtab',
|
||||
items: [
|
||||
{
|
||||
title: 'Summary',
|
||||
xtype: 'pveQemuSummary',
|
||||
itemId: 'summary'
|
||||
},
|
||||
{
|
||||
title: 'Hardware',
|
||||
itemId: 'hardware',
|
||||
xtype: 'PVE.qemu.HardwareView'
|
||||
},
|
||||
{
|
||||
title: 'Options',
|
||||
itemId: 'options',
|
||||
html: 'options ' + vmid
|
||||
},
|
||||
{
|
||||
xtype: 'pveKVMConsole',
|
||||
title: 'Console',
|
||||
itemId: 'console',
|
||||
//disabled: true,
|
||||
nodename: nodename,
|
||||
vmid: vmid
|
||||
},
|
||||
{
|
||||
title: 'Permissions',
|
||||
itemId: 'permissions',
|
||||
html: 'permissions ' + vmid
|
||||
}
|
||||
|
||||
]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,429 +0,0 @@
|
||||
Ext.define('PVE.qemu.CreateWizard', {
|
||||
extend: 'PVE.window.Wizard',
|
||||
requires: [
|
||||
'Ext.form.*',
|
||||
'PVE.data.ResourceStore'
|
||||
],
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
var nextvmid = PVE.data.ResourceStore.findNextVMID();
|
||||
|
||||
var summarystore = Ext.create('Ext.data.Store', {
|
||||
model: 'KeyValue',
|
||||
sorters: [
|
||||
{
|
||||
property : 'key',
|
||||
direction: 'ASC'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
var cdfilesel = Ext.create('PVE.form.FileSelector', {
|
||||
name: 'cdimage',
|
||||
storageContent: 'iso',
|
||||
fieldLabel: 'ISO Image',
|
||||
labelAlign: 'right',
|
||||
allowBlank: false
|
||||
});
|
||||
|
||||
var cdstoragesel = Ext.create('PVE.form.StorageSelector', {
|
||||
name: 'cdstorage',
|
||||
fieldLabel: 'Storage',
|
||||
storageContent: 'iso',
|
||||
labelAlign: 'right',
|
||||
allowBlank: false,
|
||||
listeners: {
|
||||
change: function(f, value) {
|
||||
cdfilesel.setStorage(value);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var hdstoragesel = Ext.create('PVE.form.StorageSelector', {
|
||||
name: 'hdstorage',
|
||||
fieldLabel: 'Storage',
|
||||
labelAlign: 'right',
|
||||
storageContent: 'images',
|
||||
allowBlank: false
|
||||
});
|
||||
|
||||
Ext.applyIf(me, {
|
||||
title: 'Create new virtual machine',
|
||||
items: [
|
||||
{
|
||||
xtype: 'inputpanel',
|
||||
title: 'General',
|
||||
items: [
|
||||
{
|
||||
xtype: 'PVE.form.NodeSelector',
|
||||
name: 'nodename',
|
||||
fieldLabel: 'Node',
|
||||
allowBlank: false,
|
||||
listeners: {
|
||||
change: function(f, value) {
|
||||
hdstoragesel.setNodename(value);
|
||||
cdstoragesel.setNodename(value);
|
||||
cdfilesel.setStorage(undefined, value);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
name: 'vmid',
|
||||
value: nextvmid,
|
||||
minValue: 100,
|
||||
maxValue: 999999999,
|
||||
fieldLabel: 'VM ID',
|
||||
allowBlank: false,
|
||||
validator: function(value) {
|
||||
if (!PVE.data.ResourceStore.findVMID(value))
|
||||
return true;
|
||||
return "This VM ID is already in use."
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'textfield',
|
||||
name: 'name',
|
||||
fieldLabel: 'VM name',
|
||||
allowBlank: true
|
||||
}
|
||||
],
|
||||
onGetValues: function(values) {
|
||||
if (!values.name)
|
||||
delete values.name;
|
||||
return values;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'OS Type',
|
||||
layout: 'fit',
|
||||
items: {
|
||||
xtype: 'radiogroup',
|
||||
allowBlank: false,
|
||||
layout: 'column',
|
||||
defaultType: 'container',
|
||||
items: [{
|
||||
columnWidth: .5,
|
||||
items: [
|
||||
{
|
||||
xtype: 'component',
|
||||
html: 'Microsoft Windows',
|
||||
cls:'x-form-check-group-label'
|
||||
},
|
||||
{
|
||||
xtype: 'radiofield',
|
||||
name: 'ostype',
|
||||
inputValue: 'win7',
|
||||
boxLabel: 'Microsoft Windows 7/2008r2'
|
||||
},
|
||||
{
|
||||
xtype: 'radiofield',
|
||||
name: 'ostype',
|
||||
inputValue: 'w2k8',
|
||||
boxLabel: 'Microsoft Windows Vista/2008'
|
||||
},
|
||||
{
|
||||
xtype: 'radiofield',
|
||||
name: 'ostype',
|
||||
inputValue: 'wxp',
|
||||
boxLabel: 'Microsoft Windows XP/2003'
|
||||
},
|
||||
{
|
||||
xtype: 'radiofield',
|
||||
name: 'ostype',
|
||||
inputValue: 'w2k',
|
||||
boxLabel: 'Microsoft Windows 2000'
|
||||
}
|
||||
]
|
||||
},{
|
||||
columnWidth: .5,
|
||||
items: [
|
||||
{
|
||||
xtype: 'component',
|
||||
html: 'Linux/Other',
|
||||
cls:'x-form-check-group-label'
|
||||
},
|
||||
{
|
||||
xtype: 'radiofield',
|
||||
name: 'ostype',
|
||||
inputValue: 'l26',
|
||||
boxLabel: 'Linux 2.6 Kernel'
|
||||
},
|
||||
{
|
||||
xtype: 'radiofield',
|
||||
name: 'ostype',
|
||||
inputValue: 'l24',
|
||||
boxLabel: 'Linux 2.4 Kernel'
|
||||
},
|
||||
{
|
||||
xtype: 'radiofield',
|
||||
name: 'ostype',
|
||||
inputValue: 'other',
|
||||
boxLabel: 'Other'
|
||||
}
|
||||
]
|
||||
}]
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'inputpanel',
|
||||
title: 'Installation Media',
|
||||
items: [
|
||||
{
|
||||
xtype: 'radiofield',
|
||||
name: 'mediaType',
|
||||
inputValue: 'iso',
|
||||
boxLabel: 'Use CD/DVD disc image file (iso)',
|
||||
checked: true,
|
||||
listeners: {
|
||||
change: function(f, value) {
|
||||
me.down('field[name=cdstorage]').setDisabled(!value);
|
||||
me.down('field[name=cdimage]').setDisabled(!value);
|
||||
}
|
||||
}
|
||||
},
|
||||
cdstoragesel,
|
||||
cdfilesel,
|
||||
{
|
||||
xtype: 'radiofield',
|
||||
name: 'mediaType',
|
||||
inputValue: 'cdrom',
|
||||
boxLabel: 'Use physical CD/DVD Drive'
|
||||
},
|
||||
{
|
||||
xtype: 'radiofield',
|
||||
name: 'mediaType',
|
||||
inputValue: 'none',
|
||||
boxLabel: 'Do not use any installation media'
|
||||
}
|
||||
],
|
||||
onGetValues: function(values) {
|
||||
if (values.mediaType === 'iso')
|
||||
return { cdrom: values.cdimage };
|
||||
if (values.mediaType === 'cdrom')
|
||||
return { cdrom: 'cdrom' };
|
||||
return { cdrom: 'none' };
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'inputpanel',
|
||||
title: 'Harddisk',
|
||||
items: [
|
||||
{
|
||||
xtype: 'radiofield',
|
||||
name: 'hdType',
|
||||
inputValue: 'image',
|
||||
boxLabel: 'Create new disk image',
|
||||
checked: true,
|
||||
listeners: {
|
||||
change: function(f, value) {
|
||||
me.down('field[name=hdstorage]').setDisabled(!value);
|
||||
me.down('field[name=disksize]').setDisabled(!value);
|
||||
me.down('field[name=controller]').setDisabled(!value);
|
||||
me.down('field[name=diskformat]').setDisabled(!value);
|
||||
}
|
||||
}
|
||||
},
|
||||
hdstoragesel,
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
name: 'disksize',
|
||||
labelAlign: 'right',
|
||||
minValue: 1,
|
||||
maxValue: 128*1024,
|
||||
value: 32,
|
||||
fieldLabel: 'Disk size (GB)',
|
||||
allowBlank: false
|
||||
},
|
||||
{
|
||||
xtype: 'PVE.form.BusTypeSelector',
|
||||
name: 'controller',
|
||||
labelAlign: 'right',
|
||||
fieldLabel: 'Controller',
|
||||
value: 'ide',
|
||||
allowBlank: false
|
||||
},
|
||||
{
|
||||
xtype: 'PVE.form.DiskFormatSelector',
|
||||
name: 'diskformat',
|
||||
labelAlign: 'right',
|
||||
fieldLabel: 'Image format',
|
||||
value: 'raw',
|
||||
allowBlank: false
|
||||
},
|
||||
{
|
||||
xtype: 'radiofield',
|
||||
name: 'hdType',
|
||||
inputValue: 'none',
|
||||
boxLabel: 'Do not attach a hard disk'
|
||||
}
|
||||
],
|
||||
onGetValues: function(values) {
|
||||
if (values.hdType === 'none')
|
||||
return {};
|
||||
|
||||
var str = values.hdstorage + ':' + values.disksize +
|
||||
',format=' + values.diskformat;
|
||||
var busid = 0;
|
||||
var key = values.controller + "" + busid;
|
||||
var res = {};
|
||||
res[key] = str;
|
||||
return res;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'CPU',
|
||||
items: [
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
name: 'sockets',
|
||||
minValue: 1,
|
||||
maxValue: 4,
|
||||
value: 1,
|
||||
fieldLabel: 'Sockets',
|
||||
allowBlank: false,
|
||||
listeners: {
|
||||
change: function(f, value) {
|
||||
var sockets = me.down('field[name=sockets]').getValue();
|
||||
var cores = me.down('field[name=cores]').getValue();
|
||||
me.down('field[name=totalcores]').setValue(sockets*cores);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
name: 'cores',
|
||||
minValue: 1,
|
||||
maxValue: 32,
|
||||
value: 1,
|
||||
fieldLabel: 'Cores',
|
||||
allowBlank: false,
|
||||
listeners: {
|
||||
change: function(f, value) {
|
||||
var sockets = me.down('field[name=sockets]').getValue();
|
||||
var cores = me.down('field[name=cores]').getValue();
|
||||
me.down('field[name=totalcores]').setValue(sockets*cores);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'displayfield',
|
||||
fieldLabel: 'Total cores',
|
||||
name: 'totalcores',
|
||||
value: 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Memory',
|
||||
items: [
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
name: 'memory',
|
||||
minValue: 32,
|
||||
maxValue: 128*1024,
|
||||
value: 512,
|
||||
step: 32,
|
||||
fieldLabel: 'Memory (MB)',
|
||||
allowBlank: false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
xtype: 'inputpanel',
|
||||
title: 'Network',
|
||||
items: [
|
||||
{
|
||||
xtype: 'textfield',
|
||||
name: 'bridge',
|
||||
value: 'vmbr0',
|
||||
fieldLabel: 'Bridge',
|
||||
allowBlank: false
|
||||
},
|
||||
{
|
||||
xtype: 'PVE.form.NetworkCardSelector',
|
||||
name: 'netcard',
|
||||
fieldLabel: 'Network card',
|
||||
value: 'rtl8139',
|
||||
allowBlank: false
|
||||
},
|
||||
{
|
||||
xtype: 'textfield',
|
||||
name: 'mac',
|
||||
fieldLabel: 'MAC address',
|
||||
allowBlank: true,
|
||||
emptyText: 'auto'
|
||||
}
|
||||
],
|
||||
onGetValues: function(values) {
|
||||
var str = values.netcard;
|
||||
if (values.mac)
|
||||
str += '=' + values.mac;
|
||||
str += ',bridge=' + values.bridge;
|
||||
|
||||
return { net0: str };
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Confirm',
|
||||
layout: 'fit',
|
||||
items: [
|
||||
{
|
||||
title: 'Settings',
|
||||
xtype: 'grid',
|
||||
store: summarystore,
|
||||
columns: [
|
||||
{header: 'Key', width: 150, dataIndex: 'key'},
|
||||
{header: 'Value', flex: 1, dataIndex: 'value'}
|
||||
]
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
show: function(panel) {
|
||||
var form = me.down('form').getForm();
|
||||
var kv = me.getValues();
|
||||
var data = [];
|
||||
Ext.Object.each(kv, function(key, value) {
|
||||
var html = Ext.htmlEncode(Ext.JSON.encode(value));
|
||||
data.push({ key: key, value: value });
|
||||
});
|
||||
summarystore.removeAll();
|
||||
summarystore.add(data);
|
||||
summarystore.sort();
|
||||
}
|
||||
},
|
||||
onSubmit: function() {
|
||||
var kv = me.getValues();
|
||||
|
||||
var nodename = kv.nodename;
|
||||
delete kv.nodename;
|
||||
|
||||
me.down('form').setLoading(true, true);
|
||||
PVE.Utils.API2Request({
|
||||
url: '/nodes/' + nodename + '/qemu',
|
||||
method: 'POST',
|
||||
params: kv,
|
||||
callback: function() {
|
||||
me.down('form').setLoading(false);
|
||||
},
|
||||
success: function(response){
|
||||
me.close();
|
||||
},
|
||||
failure: function(response, opts) {
|
||||
Ext.Msg.alert('Error', response.htmlStatus);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
@ -1,114 +0,0 @@
|
||||
Ext.define('PVE.qemu.HardwareView', {
|
||||
extend: 'PVE.grid.ObjectGrid',
|
||||
alias: ['widget.PVE.qemu.HardwareView'],
|
||||
|
||||
renderKey: function(key, metaData, record, rowIndex, colIndex, store) {
|
||||
var me = this;
|
||||
var rows = me.rows;
|
||||
var rowdef = rows[key] || {};
|
||||
|
||||
if (rowdef.css) {
|
||||
if (rowdef.css == 'pve-itype-icon-storage') {
|
||||
if (record.data.value.match(/media=cdrom/)) {
|
||||
metaData.css = 'pve-itype-icon-cdrom';
|
||||
return 'CD/DVD';
|
||||
} else {
|
||||
metaData.css = rowdef.css;
|
||||
return 'Hard Disk';
|
||||
}
|
||||
} else
|
||||
metaData.css = rowdef.css;
|
||||
}
|
||||
return rowdef.header || key;
|
||||
},
|
||||
|
||||
initComponent : function() {
|
||||
var me = this;
|
||||
var i;
|
||||
|
||||
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 rows = {
|
||||
memory: {
|
||||
header: 'Memory',
|
||||
css: 'pve-itype-icon-memory',
|
||||
renderer: function(value) {
|
||||
return PVE.Utils.format_size(value*1024*1024);
|
||||
}
|
||||
},
|
||||
sockets: {
|
||||
header: 'Processors',
|
||||
css: 'pve-itype-icon-processor',
|
||||
defaultValue: 1,
|
||||
renderer: function(value, metaData, record, rowIndex, colIndex, store) {
|
||||
var cores = (store.snapshot || store.data).get('cores');
|
||||
return cores ? value * cores.data.value : value;
|
||||
}
|
||||
},
|
||||
keyboard: {
|
||||
header: 'Keyboard',
|
||||
css: 'pve-itype-icon-keyboard',
|
||||
defaultValue: 'default'
|
||||
},
|
||||
vga: {
|
||||
header: 'Display',
|
||||
css: 'pve-itype-icon-display',
|
||||
defaultValue: 'default'
|
||||
},
|
||||
cores: {
|
||||
header: 'Cores',
|
||||
visible: false
|
||||
}
|
||||
};
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
rows["ide" + i] = {
|
||||
css: 'pve-itype-icon-storage',
|
||||
header: 'Hard Disk (IDE)'
|
||||
};
|
||||
}
|
||||
for (i = 0; i < 16; i++) {
|
||||
rows["net" + i] = {
|
||||
css: 'pve-itype-icon-network',
|
||||
header: 'Network Adapter'
|
||||
};
|
||||
}
|
||||
|
||||
var run_editor = function() {
|
||||
|
||||
console.log("TEST EDIT");
|
||||
|
||||
me.rstore.load();
|
||||
};
|
||||
|
||||
Ext.applyIf(me, {
|
||||
url: "/api2/json/nodes/" + nodename + "/qemu/" + vmid + "/config",
|
||||
cwidth1: 150,
|
||||
tbar: [
|
||||
{
|
||||
text: "Edit",
|
||||
handler: run_editor
|
||||
}
|
||||
],
|
||||
rows: rows,
|
||||
listeners: {
|
||||
itemdblclick: function() {
|
||||
run_editor();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
me.on('show', function() {
|
||||
me.rstore.load();
|
||||
});
|
||||
|
||||
}
|
||||
});
|
@ -1,58 +0,0 @@
|
||||
Ext.define('PVE.qemu.StatusView', {
|
||||
extend: 'PVE.grid.ObjectGrid',
|
||||
alias: ['widget.pveQemuStatusView'],
|
||||
|
||||
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 render_cpu = function(value, metaData, record, rowIndex, colIndex, store) {
|
||||
if (!me.getObjectValue('uptime'))
|
||||
return '-';
|
||||
|
||||
var maxcpu = me.getObjectValue('cpus', 1);
|
||||
|
||||
if (!(Ext.isNumeric(value) && Ext.isNumeric(maxcpu) && (maxcpu >= 1)))
|
||||
return '-'
|
||||
|
||||
var per = (value * 100) / maxcpu;
|
||||
|
||||
return per.toFixed(1) + '% of ' + maxcpu + (maxcpu > 1 ? 'CPUs' : 'CPU');
|
||||
};
|
||||
|
||||
var render_mem = function(value, metaData, record, rowIndex, colIndex, store) {
|
||||
var maxmem = me.getObjectValue('maxmem', 0);
|
||||
var per = (value / maxmem)*100;
|
||||
var text = "<div>Total: " + PVE.Utils.format_size(maxmem) + "</div>" +
|
||||
"<div>Used: " + PVE.Utils.format_size(value) + "</div>";
|
||||
return text;
|
||||
};
|
||||
|
||||
var rows = {
|
||||
name: { header: 'Name', defaultValue: 'no name specified' },
|
||||
status: { header: 'Status', defaultValue: 'unknown' },
|
||||
cpu: { header: 'CPU usage', required: true, renderer: render_cpu },
|
||||
cpus: { visible: false },
|
||||
mem: { header: 'Memory usage', required: true, renderer: render_mem },
|
||||
maxmem: { visible: false },
|
||||
uptime: { header: 'Uptime', required: true, renderer: PVE.Utils.render_uptime }
|
||||
};
|
||||
|
||||
Ext.applyIf(me, {
|
||||
url: "/api2/json/nodes/" + nodename + "/qemu/" + vmid + "/status",
|
||||
cwidth1: 150,
|
||||
height: 145,
|
||||
interval: 1000,
|
||||
rows: rows
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,203 +0,0 @@
|
||||
Ext.define('PVE.qemu.Summary', {
|
||||
extend: 'Ext.panel.Panel',
|
||||
alias: 'widget.pveQemuSummary',
|
||||
|
||||
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 statusview = Ext.create('PVE.qemu.StatusView', {
|
||||
title: 'Status',
|
||||
pveSelNode: me.pveSelNode,
|
||||
width: 400
|
||||
})
|
||||
|
||||
rstore = statusview.rstore;
|
||||
|
||||
var rrdurl = "/api2/png/nodes/" + nodename + "/qemu/" + vmid + "/rrd";
|
||||
|
||||
var vm_command = function(cmd) {
|
||||
me.setLoading(true, true);
|
||||
PVE.Utils.API2Request({
|
||||
params: { command: cmd },
|
||||
url: '/nodes/' + nodename + '/qemu/' + vmid + "/status",
|
||||
method: 'PUT',
|
||||
callback: function() {
|
||||
me.setLoading(false);
|
||||
},
|
||||
failure: function(response, opts) {
|
||||
Ext.Msg.alert('Error', response.htmlStatus);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var tbar = Ext.create('Ext.toolbar.Toolbar', {
|
||||
items: [
|
||||
{
|
||||
itemId: 'start',
|
||||
text: 'Start',
|
||||
handler: function() {
|
||||
vm_command('start');
|
||||
}
|
||||
},
|
||||
{
|
||||
itemId: 'stop',
|
||||
text: 'Stop',
|
||||
handler: function() {
|
||||
var msg = "Do you really want to stop the VM?";
|
||||
Ext.Msg.confirm('Confirm', msg, function(btn) {
|
||||
if (btn !== 'yes')
|
||||
return;
|
||||
vm_command("stop");
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
text: 'Reset',
|
||||
itemId: 'reset',
|
||||
handler: function() {
|
||||
var msg = "Do you really want to reset the VM?";
|
||||
Ext.Msg.confirm('Confirm', msg, function(btn) {
|
||||
if (btn !== 'yes')
|
||||
return;
|
||||
vm_command("reset");
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
itemId: 'shutdown',
|
||||
text: 'Shutdown',
|
||||
handler: function() {
|
||||
var msg = "Do you really want to shutdown the VM?";
|
||||
Ext.Msg.confirm('Confirm', msg, function(btn) {
|
||||
if (btn !== 'yes')
|
||||
return;
|
||||
vm_command('shutdown');
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
itemId: 'remove',
|
||||
text: 'Remove',
|
||||
handler: function() {
|
||||
var msg = 'Are you sure you want to remove VM ' +
|
||||
vmid + '? This will permanently erase all VM data.';
|
||||
Ext.Msg.confirm('Confirm', msg, function(btn) {
|
||||
if (btn !== 'yes')
|
||||
return;
|
||||
|
||||
me.setLoading(true, true);
|
||||
PVE.Utils.API2Request({
|
||||
url: '/nodes/' + nodename + '/qemu/' + vmid,
|
||||
method: 'DELETE',
|
||||
callback: function() {
|
||||
me.setLoading(false);
|
||||
},
|
||||
failure: function(response, opts) {
|
||||
Ext.Msg.alert('Error', response.htmlStatus);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
itemId: 'console',
|
||||
text: 'Console',
|
||||
handler: function() {
|
||||
var url = Ext.urlEncode({
|
||||
console: 'kvm',
|
||||
vmid: vmid,
|
||||
node: nodename
|
||||
});
|
||||
var nw = window.open("?" + url, '_blank',
|
||||
"innerWidth=745,innerheight=427");
|
||||
nw.focus();
|
||||
}
|
||||
}, '->',
|
||||
{
|
||||
xtype: 'pveRRDTypeSelector'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
me.mon(rstore, 'load', function(s, records, success) {
|
||||
var statusrec = s.data.get('status');
|
||||
var status = statusrec ? statusrec.data.value : 'unknown';
|
||||
|
||||
tbar.down('#start').setDisabled(status === 'running');
|
||||
tbar.down('#reset').setDisabled(status !== 'running');
|
||||
tbar.down('#shutdown').setDisabled(status !== 'running');
|
||||
tbar.down('#stop').setDisabled(status === 'stopped');
|
||||
tbar.down('#console').setDisabled(status !== 'running');
|
||||
tbar.down('#remove').setDisabled(status !== 'stopped');
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
tbar: tbar,
|
||||
layout: {
|
||||
type: 'table',
|
||||
columns: 1
|
||||
},
|
||||
autoScroll: true,
|
||||
bodyStyle: 'padding:10px',
|
||||
defaults: {
|
||||
style: 'padding-bottom:10px'
|
||||
},
|
||||
items: [
|
||||
{
|
||||
layout: {
|
||||
type: 'hbox',
|
||||
align: 'stretchmax'
|
||||
},
|
||||
width: 800,
|
||||
border: false,
|
||||
items: [
|
||||
statusview,
|
||||
{
|
||||
title: 'Comments',
|
||||
style: 'padding-left:10px',
|
||||
pveSelNode: me.pveSelNode,
|
||||
rstore: rstore,
|
||||
html: "test",
|
||||
width: 400
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
xtype: 'pveRRDView',
|
||||
title: "CPU usage %",
|
||||
pveSelNode: me.pveSelNode,
|
||||
datasource: 'cpu',
|
||||
rrdurl: rrdurl
|
||||
},
|
||||
{
|
||||
xtype: 'pveRRDView',
|
||||
title: "Memory usage",
|
||||
pveSelNode: me.pveSelNode,
|
||||
datasource: 'mem,maxmem',
|
||||
rrdurl: rrdurl
|
||||
},
|
||||
{
|
||||
xtype: 'pveRRDView',
|
||||
title: "Network traffic",
|
||||
pveSelNode: me.pveSelNode,
|
||||
datasource: 'netin,netout',
|
||||
rrdurl: rrdurl
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
me.on('show', rstore.startUpdate);
|
||||
me.on('hide', rstore.stopUpdate);
|
||||
me.on('destroy', rstore.stopUpdate);
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,52 +0,0 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
use strict;
|
||||
|
||||
use PVE::SafeSyslog;
|
||||
|
||||
use ModPerl::Util (); #for CORE::GLOBAL::exit
|
||||
|
||||
use Apache2::RequestRec ();
|
||||
use Apache2::RequestIO ();
|
||||
use Apache2::RequestUtil ();
|
||||
use Apache2::Access;
|
||||
use Apache2::Response;
|
||||
use Apache2::Util;
|
||||
|
||||
use Apache2::ServerUtil ();
|
||||
use Apache2::Connection ();
|
||||
use Apache2::Log ();
|
||||
|
||||
use APR::Table ();
|
||||
|
||||
use ModPerl::Registry ();
|
||||
|
||||
use Apache2::Const -compile => ':common';
|
||||
use APR::Const -compile => ':common';
|
||||
|
||||
initlog ('proxwww', 'daemon');
|
||||
|
||||
use PVE::pvecfg;
|
||||
use PVE::REST;
|
||||
use PVE::Cluster;
|
||||
use PVE::INotify;
|
||||
use PVE::RPCEnvironment;
|
||||
|
||||
sub childinit {
|
||||
syslog ('info', "Starting new child $$");
|
||||
PVE::INotify::inotify_init();
|
||||
PVE::RPCEnvironment->init('pub');
|
||||
|
||||
PVE::Config::inotify_init();
|
||||
}
|
||||
|
||||
sub childexit {
|
||||
syslog ('info', "Finish child $$");
|
||||
}
|
||||
|
||||
my $s = Apache2::ServerUtil->server;
|
||||
$s->push_handlers(PerlChildInitHandler => \&childinit);
|
||||
$s->push_handlers(PerlChildExitHandler => \&childexit);
|
||||
|
||||
1;
|
||||
|
@ -1,40 +0,0 @@
|
||||
Ext.define('PVE.storage.Browser', {
|
||||
extend: 'PVE.panel.Config',
|
||||
alias: 'widget.PVE.storage.Browser',
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
var nodename = me.pveSelNode.data.node;
|
||||
if (!nodename)
|
||||
throw "no node name specified";
|
||||
|
||||
var storeid = me.pveSelNode.data.storage;
|
||||
if (!storeid)
|
||||
throw "no storage ID specified";
|
||||
|
||||
Ext.apply(me, {
|
||||
title: "Storage '" + storeid + "'" + "' on node '" + nodename + "'",
|
||||
hstateid: 'storagetab',
|
||||
items: [
|
||||
{
|
||||
title: 'Summary',
|
||||
//xtype: 'pveStorageSummary',
|
||||
itemId: 'summary'
|
||||
},
|
||||
{
|
||||
//xtype: 'pveStorageContent',
|
||||
title: 'Content',
|
||||
itemId: 'content'
|
||||
},
|
||||
{
|
||||
title: 'Permissions',
|
||||
itemId: 'permissions',
|
||||
html: 'Permissions '
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,347 +0,0 @@
|
||||
Ext.define('PVE.tree.ResourceTree', {
|
||||
extend: 'Ext.tree.TreePanel',
|
||||
requires: ['Ext.tree.*',
|
||||
'Ext.state.Manager',
|
||||
'PVE.Utils',
|
||||
'PVE.data.ResourceStore'],
|
||||
alias: ['widget.pveResourceTree'],
|
||||
|
||||
statics: {
|
||||
typeDefaults: {
|
||||
node: {
|
||||
iconCls: 'x-tree-node-server',
|
||||
text: 'Node list'
|
||||
},
|
||||
storage: {
|
||||
iconCls: 'x-tree-node-harddisk',
|
||||
text: 'Storage list'
|
||||
},
|
||||
qemu: {
|
||||
iconCls: 'x-tree-node-computer',
|
||||
text: 'Virtual machines'
|
||||
},
|
||||
openvz: {
|
||||
iconCls: 'x-tree-node-computer',
|
||||
text: 'OpenVZ containers'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// private
|
||||
nodeSortFn: function(node1, node2) {
|
||||
var n1 = node1.data;
|
||||
var n2 = node2.data;
|
||||
|
||||
if ((n1.groupbyid && n2.groupbyid) ||
|
||||
!(n1.groupbyid || n2.groupbyid)) {
|
||||
|
||||
var tcmp;
|
||||
|
||||
var v1 = n1.type;
|
||||
var v2 = n2.type;
|
||||
|
||||
if ((tcmp = v1 > v2 ? 1 : (v1 < v2 ? -1 : 0)) != 0)
|
||||
return tcmp;
|
||||
|
||||
// numeric compare for VM IDs
|
||||
if (v1 === 'qemu' || v1 === 'openvz') {
|
||||
v1 = n1.vmid;
|
||||
v2 = n2.vmid;
|
||||
if ((tcmp = v1 > v2 ? 1 : (v1 < v2 ? -1 : 0)) != 0)
|
||||
return tcmp;
|
||||
}
|
||||
|
||||
return n1.text > n2.text ? 1 : (n1.text < n2.text ? -1 : 0);
|
||||
} else if (n1.groupbyid) {
|
||||
return -1;
|
||||
} else if (n2.groupbyid) {
|
||||
return 1;
|
||||
}
|
||||
},
|
||||
|
||||
// private: fast binary search
|
||||
findInsertIndex: function(node, child, start, end) {
|
||||
var me = this;
|
||||
|
||||
var diff = end - start;
|
||||
|
||||
var mid = start + (diff>>1);
|
||||
|
||||
if (diff <= 0)
|
||||
return start;
|
||||
|
||||
var res = me.nodeSortFn(child, node.childNodes[mid]);
|
||||
if (res <= 0)
|
||||
return me.findInsertIndex(node, child, start, mid);
|
||||
else
|
||||
return me.findInsertIndex(node, child, mid + 1, end);
|
||||
},
|
||||
|
||||
// private
|
||||
addChildSorted: function(node, info) {
|
||||
var me = this;
|
||||
|
||||
var statics = me.statics();
|
||||
var defaults = statics.typeDefaults[info.type];
|
||||
if (defaults && defaults.iconCls)
|
||||
info.iconCls = defaults.iconCls;
|
||||
|
||||
if (info.groupbyid) {
|
||||
info.text = info.groupbyid;
|
||||
if (info.type === 'type') {
|
||||
defaults = statics.typeDefaults[info.groupbyid];
|
||||
if (defaults && defaults.text)
|
||||
info.text = defaults.text;
|
||||
}
|
||||
}
|
||||
var child = Ext.ModelMgr.create(info, 'PVETree', info.id);
|
||||
|
||||
var cs = node.childNodes;
|
||||
var pos;
|
||||
if (cs) {
|
||||
var len = cs.length;
|
||||
index = me.findInsertIndex(node, child, 0, len);
|
||||
pos = cs[index];
|
||||
}
|
||||
|
||||
//var expanded = node.isExpanded();
|
||||
//if (expanded)
|
||||
//node.collapse();
|
||||
node.insertBefore(child, pos);
|
||||
//if (expanded)
|
||||
//node.expand();
|
||||
|
||||
return child;
|
||||
},
|
||||
|
||||
// private
|
||||
groupChild: function(node, info, groups, level) {
|
||||
var me = this;
|
||||
|
||||
var groupby = groups[level];
|
||||
var v = info[groupby];
|
||||
|
||||
if (v) {
|
||||
var group = node.findChild('groupbyid', v);
|
||||
if (!group) {
|
||||
var groupinfo;
|
||||
if (info.type === groupby) {
|
||||
groupinfo = info;
|
||||
} else {
|
||||
groupinfo = {
|
||||
type: groupby,
|
||||
id : groupby + "/" + v
|
||||
};
|
||||
if (groupby !== 'type')
|
||||
groupinfo[groupby] = v;
|
||||
}
|
||||
groupinfo.leaf = false;
|
||||
groupinfo.groupbyid = v;
|
||||
group = me.addChildSorted(node, groupinfo);
|
||||
// fixme: remove when EXTJS has fixed those bugs?!
|
||||
group.expand(); group.collapse();
|
||||
}
|
||||
if (info.type === groupby)
|
||||
return group;
|
||||
if (group)
|
||||
return me.groupChild(group, info, groups, level + 1);
|
||||
}
|
||||
|
||||
return me.addChildSorted(node, info);
|
||||
},
|
||||
|
||||
initComponent : function() {
|
||||
var me = this;
|
||||
|
||||
var rstore = PVE.data.ResourceStore;
|
||||
var sp = Ext.state.Manager.getProvider();
|
||||
|
||||
if (!me.viewFilter)
|
||||
me.viewFilter = {};
|
||||
|
||||
var pdata = {
|
||||
dataIndex: {},
|
||||
updateCount: 0
|
||||
};
|
||||
|
||||
var store = Ext.create('Ext.data.TreeStore', {
|
||||
model: 'PVETree',
|
||||
root: {
|
||||
expanded: true,
|
||||
id: 'root',
|
||||
text: "Datacenter"
|
||||
}
|
||||
});
|
||||
|
||||
var stateid = 'rid';
|
||||
|
||||
var updateTree = function() {
|
||||
var tmp;
|
||||
|
||||
// fixme: suspend events ?
|
||||
|
||||
var rootnode = me.store.getRootNode();
|
||||
|
||||
// remember selected node (and all parents)
|
||||
var sm = me.getSelectionModel();
|
||||
var lastsel = sm.getLastSelected();
|
||||
var parents = [];
|
||||
var p = lastsel;
|
||||
while(p && (p = p.parentNode))
|
||||
parents.push(p);
|
||||
|
||||
var index = pdata.dataIndex;
|
||||
|
||||
var groups = me.viewFilter.groups || [];
|
||||
var filterfn = me.viewFilter.filterfn;
|
||||
|
||||
// remove vanished or changed items
|
||||
for (var key in index) {
|
||||
if (!index.hasOwnProperty(key))
|
||||
continue;
|
||||
|
||||
var olditem = index[key];
|
||||
|
||||
// getById() use find(), which is slow (ExtJS4 DP5)
|
||||
//var item = rstore.getById(olditem.data.id);
|
||||
var item = rstore.data.get(olditem.data.id);
|
||||
|
||||
var changed = false;
|
||||
if (item) {
|
||||
// test if any grouping attributes changed
|
||||
for (var i = 0, len = groups.length; i < len; i++) {
|
||||
var attr = groups[i];
|
||||
if (item.data[attr] != olditem.data[attr]) {
|
||||
//console.log("changed " + attr);
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// fixme: also test filterfn()?
|
||||
}
|
||||
|
||||
if (!item || changed) {
|
||||
//console.log("REM UID: " + key + " ITEM " + olditem.data.id);
|
||||
delete index[key];
|
||||
var parentNode = olditem.parentNode;
|
||||
//var expanded = parentNode.isExpanded();
|
||||
//if (expanded)
|
||||
//parentNode.collapse();
|
||||
parentNode.removeChild(olditem, true);
|
||||
//if (expanded)
|
||||
//parentNode.expand();
|
||||
}
|
||||
}
|
||||
|
||||
// add new items
|
||||
rstore.each(function(item) {
|
||||
var olditem = index[item.data.id];
|
||||
if (olditem)
|
||||
return;
|
||||
|
||||
if (filterfn && !filterfn(item))
|
||||
return;
|
||||
|
||||
//console.log("ADD UID: " + item.data.id);
|
||||
|
||||
var info = Ext.apply({ leaf: true }, item.data);
|
||||
|
||||
var child = me.groupChild(rootnode, info, groups, 0);
|
||||
if (child)
|
||||
index[item.data.id] = child;
|
||||
});
|
||||
|
||||
// select parent node is selection vanished
|
||||
if (lastsel && !rootnode.findChild('id', lastsel.data.id, true)) {
|
||||
lastsel = rootnode;
|
||||
while (p = parents.shift()) {
|
||||
if (tmp = rootnode.findChild('id', p.data.id, true)) {
|
||||
lastsel = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
me.selectById(lastsel.data.id);
|
||||
}
|
||||
|
||||
if (!pdata.updateCount) {
|
||||
rootnode.collapse();
|
||||
rootnode.expand();
|
||||
me.applyState(sp.get(stateid));
|
||||
}
|
||||
|
||||
pdata.updateCount++;
|
||||
};
|
||||
|
||||
var statechange = function(sp, key, value) {
|
||||
if (key === stateid) {
|
||||
me.applyState(value);
|
||||
}
|
||||
};
|
||||
|
||||
sp.on('statechange', statechange);
|
||||
|
||||
Ext.apply(me, {
|
||||
store: store,
|
||||
//useArrows: true,
|
||||
//rootVisible: false,
|
||||
title: 'Resource Tree',
|
||||
listeners: {
|
||||
destroy: function() {
|
||||
rstore.un("load", updateTree)
|
||||
}
|
||||
},
|
||||
setViewFilter: function(view) {
|
||||
me.viewFilter = view;
|
||||
me.clearTree();
|
||||
updateTree();
|
||||
},
|
||||
clearTree: function() {
|
||||
pdata.updateCount = 0;
|
||||
var rootnode = me.store.getRootNode();
|
||||
rootnode.collapse();
|
||||
rootnode.removeAll(true);
|
||||
pdata.dataIndex = {};
|
||||
me.getSelectionModel().deselectAll();
|
||||
},
|
||||
selectById: function(nodeid) {
|
||||
var rootnode = me.store.getRootNode();
|
||||
var sm = me.getSelectionModel();
|
||||
var node;
|
||||
if (nodeid === 'root')
|
||||
node = rootnode;
|
||||
else
|
||||
node = rootnode.findChild('id', nodeid, true);
|
||||
if (node) {
|
||||
if (!sm.isSelected(node)) {
|
||||
sm.select(node);
|
||||
var cn = node;
|
||||
while ((cn = cn.parentNode)) {
|
||||
if (!cn.isExpanded())
|
||||
cn.expand();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
applyState : function(state) {
|
||||
var sm = me.getSelectionModel();
|
||||
if (state && state.value) {
|
||||
me.selectById(state.value);
|
||||
} else {
|
||||
sm.deselectAll();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
var sm = me.getSelectionModel();
|
||||
sm.on('select', function(sm, n) {
|
||||
sp.set(stateid, { value: n.data.id});
|
||||
});
|
||||
|
||||
rstore.on("load", updateTree);
|
||||
rstore.startUpdate();
|
||||
//rstore.stopUpdate();
|
||||
}
|
||||
|
||||
});
|
@ -1,116 +0,0 @@
|
||||
Ext.define('PVE.window.LoginWindow', {
|
||||
extend: 'Ext.window.Window',
|
||||
requires: ['PVE.form.RealmComboBox'],
|
||||
|
||||
// private
|
||||
onLogon: function() {
|
||||
var me = this;
|
||||
|
||||
var form = me.getComponent(0).getForm();
|
||||
|
||||
if(form.isValid()){
|
||||
me.el.mask('Please wait...', 'x-mask-loading');
|
||||
|
||||
form.submit({
|
||||
failure: function(f, resp){
|
||||
me.el.unmask();
|
||||
Ext.MessageBox.alert('Failure', "Login failed. Please try again", function() {
|
||||
var uf = form.findField('username');
|
||||
uf.focus(true);
|
||||
});
|
||||
},
|
||||
success: function(f, resp){
|
||||
me.el.unmask();
|
||||
|
||||
var handler = me.handler || Ext.emptyFn;
|
||||
handler.call(me, resp.result.data);
|
||||
me.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
Ext.apply(me, {
|
||||
width: 400,
|
||||
height: 160,
|
||||
modal: true,
|
||||
border: false,
|
||||
draggable: true,
|
||||
closable: false,
|
||||
resizable: false,
|
||||
layout: 'fit',
|
||||
title: 'Proxmox VE Login',
|
||||
|
||||
items: [{
|
||||
xtype: 'form',
|
||||
frame: true,
|
||||
url: '/api2/extjs/access/ticket',
|
||||
|
||||
fieldDefaults: {
|
||||
labelWidth: 70,
|
||||
labelAlign : 'right',
|
||||
},
|
||||
|
||||
defaults: {
|
||||
anchor: '-5',
|
||||
allowBlank: false
|
||||
},
|
||||
|
||||
items: [
|
||||
{
|
||||
xtype: 'textfield',
|
||||
fieldLabel: 'User name',
|
||||
name: 'username',
|
||||
blankText: "Enter your user name",
|
||||
listeners: {
|
||||
render: function(f) {
|
||||
f.focus(true);
|
||||
},
|
||||
specialkey: function(f, e) {
|
||||
if (e.getKey() === e.ENTER) {
|
||||
var pf = me.query('textfield[name="password"]')[0];
|
||||
if (pf.getValue()) {
|
||||
me.onLogon();
|
||||
} else {
|
||||
pf.focus(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'textfield',
|
||||
inputType: 'password',
|
||||
fieldLabel: 'Password',
|
||||
name: 'password',
|
||||
blankText:"Enter your password",
|
||||
listeners: {
|
||||
specialkey: function(field, e) {
|
||||
if (e.getKey() === e.ENTER) {
|
||||
me.onLogon();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'pveRealmComboBox',
|
||||
name: 'realm'
|
||||
}
|
||||
],
|
||||
buttons: [
|
||||
{
|
||||
text: 'Login',
|
||||
handler: function(){
|
||||
me.onLogon();
|
||||
}
|
||||
}
|
||||
]
|
||||
}]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
@ -1,156 +0,0 @@
|
||||
Ext.define('PVE.window.TaskViewer', {
|
||||
extend: 'Ext.window.Window',
|
||||
requires: [
|
||||
'PVE.Utils'
|
||||
],
|
||||
alias: 'widget.pveTaskViewer',
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
if (!me.upid)
|
||||
throw "no task specified";
|
||||
|
||||
var task = PVE.Utils.parse_task_upid(me.upid);
|
||||
|
||||
var rows = {
|
||||
status: {
|
||||
header: 'Status',
|
||||
defaultValue: 'unknown'
|
||||
},
|
||||
type: {
|
||||
header: 'Task type',
|
||||
required: true
|
||||
},
|
||||
user: {
|
||||
header: 'User name',
|
||||
required: true
|
||||
},
|
||||
node: {
|
||||
header: 'Node',
|
||||
required: true
|
||||
},
|
||||
pid: {
|
||||
header: 'Process ID',
|
||||
required: true
|
||||
},
|
||||
starttime: {
|
||||
header: 'Start time',
|
||||
required: true,
|
||||
renderer: PVE.Utils.render_timestamp
|
||||
},
|
||||
upid: {
|
||||
header: 'Unique task ID'
|
||||
}
|
||||
};
|
||||
|
||||
var store = Ext.create('Ext.data.Store', {
|
||||
model: 'pve-string-list',
|
||||
pageSize: 200,
|
||||
buffered: true,
|
||||
proxy: {
|
||||
type: 'pve',
|
||||
startParam: 'start',
|
||||
limitParam: 'limit',
|
||||
url: "/api2/json/nodes/" + task.node + "/tasks/" + me.upid + "/log"
|
||||
}
|
||||
});
|
||||
|
||||
var statstore = Ext.create('PVE.data.ObjectStore', {
|
||||
url: "/api2/json/nodes/" + task.node + "/tasks/" + me.upid + "/status",
|
||||
interval: 1000,
|
||||
rows: rows,
|
||||
});
|
||||
|
||||
me.on('destroy', statstore.stopUpdate);
|
||||
|
||||
var stop_task = function() {
|
||||
me.setLoading(true, true);
|
||||
PVE.Utils.API2Request({
|
||||
url: "/nodes/" + task.node + "/tasks/" + me.upid,
|
||||
method: 'DELETE',
|
||||
callback: function() {
|
||||
me.setLoading(false);
|
||||
},
|
||||
failure: function(response, opts) {
|
||||
Ext.Msg.alert('Error', response.htmlStatus);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var stop_btn1 = new Ext.Button({
|
||||
text: 'Stop',
|
||||
disabled: true,
|
||||
handler: stop_task
|
||||
});
|
||||
var stop_btn2 = new Ext.Button({
|
||||
text: 'Stop',
|
||||
disabled: true,
|
||||
handler: stop_task
|
||||
});
|
||||
|
||||
var statgrid = Ext.create('PVE.grid.ObjectGrid', {
|
||||
title: 'Status',
|
||||
layout: 'fit',
|
||||
tbar: [ stop_btn1 ],
|
||||
rstore: statstore,
|
||||
rows: rows,
|
||||
border: false
|
||||
});
|
||||
|
||||
me.mon(statstore, 'load', function() {
|
||||
var status = statgrid.getObjectValue('status');
|
||||
if (status === 'stopped')
|
||||
statstore.stopUpdate();
|
||||
|
||||
stop_btn1.setDisabled(status !== 'running');
|
||||
stop_btn2.setDisabled(status !== 'running');
|
||||
});
|
||||
|
||||
statstore.startUpdate();
|
||||
|
||||
Ext.applyIf(me, {
|
||||
title: "Task viewer: " + task.desc,
|
||||
width: 800,
|
||||
height: 400,
|
||||
layout: 'fit',
|
||||
modal: true,
|
||||
bodyPadding: 5,
|
||||
items: [{
|
||||
xtype: 'tabpanel',
|
||||
region: 'center',
|
||||
items: [
|
||||
{
|
||||
title: 'Output',
|
||||
tbar: [ stop_btn2 ],
|
||||
border: false,
|
||||
xtype: 'gridpanel',
|
||||
features: [ {ftype: 'selectable'}],
|
||||
store: store,
|
||||
stateful: false,
|
||||
//tbar: [ 'test' ],
|
||||
verticalScrollerType: 'paginggridscroller',
|
||||
loadMask: true,
|
||||
disableSelection: true,
|
||||
invalidateScrollerOnRefresh: false,
|
||||
viewConfig: {
|
||||
trackOver: false,
|
||||
stripeRows: false
|
||||
},
|
||||
hideHeaders: true,
|
||||
columns: [
|
||||
//{ header: "Line", dataIndex: 'n', width: 50 },
|
||||
{ header: "Text", dataIndex: 't', flex: 1 }
|
||||
]
|
||||
},
|
||||
statgrid
|
||||
]
|
||||
}]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
store.guaranteeRange(0, store.pageSize - 1);
|
||||
}
|
||||
});
|
||||
|
@ -1,277 +0,0 @@
|
||||
Ext.define('PVE.panel.InputPanel', {
|
||||
extend: 'Ext.panel.Panel',
|
||||
requires: [
|
||||
'PVE.Utils'
|
||||
],
|
||||
alias: ['widget.inputpanel'],
|
||||
|
||||
getValues: function(dirtyOnly) {
|
||||
var me = this;
|
||||
|
||||
if (Ext.isFunction(me.onGetValues))
|
||||
dirtyOnly = false;
|
||||
|
||||
var values = {};
|
||||
|
||||
Ext.Array.each(me.query('[isFormField]'), function(field) {
|
||||
if (!dirtyOnly || field.isDirty()) {
|
||||
PVE.Utils.assemble_field_data(values, field.getSubmitData());
|
||||
}
|
||||
});
|
||||
|
||||
if (Ext.isFunction(me.onGetValues))
|
||||
return me.onGetValues(values, dirtyOnly);
|
||||
|
||||
return values;
|
||||
},
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
Ext.applyIf(me, {
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
||||
|
||||
Ext.define('PVE.window.Wizard', {
|
||||
extend: 'Ext.window.Window',
|
||||
requires: [
|
||||
'PVE.Utils'
|
||||
],
|
||||
|
||||
getValues: function(dirtyOnly) {
|
||||
var me = this;
|
||||
|
||||
var values = {};
|
||||
|
||||
var form = me.down('form').getForm();
|
||||
|
||||
form.getFields().each(function(field) {
|
||||
if (!field.up('inputpanel') && (!dirtyOnly || field.isDirty())) {
|
||||
PVE.Utils.assemble_field_data(values, field.getSubmitData());
|
||||
}
|
||||
});
|
||||
|
||||
Ext.Array.each(me.query('inputpanel'), function(panel) {
|
||||
PVE.Utils.assemble_field_data(values, panel.getValues(dirtyOnly));
|
||||
});
|
||||
|
||||
return values;
|
||||
},
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
var tabs = me.items || [];
|
||||
delete me.items;
|
||||
|
||||
/*
|
||||
* Items may have the following functions:
|
||||
* validator(): per tab custom validation
|
||||
* onSubmit(): submit handler
|
||||
* onGetValues(): overwrite getValues results
|
||||
*/
|
||||
|
||||
Ext.Array.each(tabs, function(tab) {
|
||||
tab.disabled = true;
|
||||
});
|
||||
tabs[0].disabled = false;
|
||||
|
||||
var check_card = function(card) {
|
||||
var valid = true;
|
||||
var fields = card.query('field, fieldcontainer');
|
||||
Ext.Array.each(fields, function(field) {
|
||||
if (!field.isValid())
|
||||
valid = false;
|
||||
});
|
||||
|
||||
if (Ext.isFunction(card.validator))
|
||||
return card.validator();
|
||||
|
||||
return valid;
|
||||
};
|
||||
|
||||
|
||||
var tbar = Ext.create('Ext.toolbar.Toolbar', {
|
||||
ui: 'footer',
|
||||
region: 'south',
|
||||
margins: '0 5 5 5',
|
||||
items: [
|
||||
'->',
|
||||
{
|
||||
text: 'Back',
|
||||
disabled: true,
|
||||
itemId: 'back',
|
||||
minWidth: 60,
|
||||
handler: function() {
|
||||
var tp = me.down('#wizcontent');
|
||||
var atab = tp.getActiveTab();
|
||||
var prev = tp.items.indexOf(atab) - 1;
|
||||
if (prev < 0) {
|
||||
return;
|
||||
}
|
||||
var ntab = tp.items.getAt(prev);
|
||||
if (ntab) {
|
||||
tp.setActiveTab(ntab);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
{
|
||||
text: 'Next',
|
||||
disabled: true,
|
||||
itemId: 'next',
|
||||
minWidth: 60,
|
||||
handler: function() {
|
||||
|
||||
var form = me.down('form').getForm();
|
||||
|
||||
var tp = me.down('#wizcontent');
|
||||
var atab = tp.getActiveTab();
|
||||
if (!check_card(atab))
|
||||
return;
|
||||
|
||||
var next = tp.items.indexOf(atab) + 1;
|
||||
var ntab = tp.items.getAt(next);
|
||||
if (ntab) {
|
||||
ntab.enable();
|
||||
tp.setActiveTab(ntab);
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
{
|
||||
text: 'Finish',
|
||||
minWidth: 60,
|
||||
hidden: true,
|
||||
itemId: 'submit',
|
||||
handler: function() {
|
||||
var tp = me.down('#wizcontent');
|
||||
var atab = tp.getActiveTab();
|
||||
atab.onSubmit();
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
var display_header = function(newcard) {
|
||||
var html = '<h1>' + newcard.title + '</h1>';
|
||||
if (newcard.descr)
|
||||
html += newcard.descr;
|
||||
|
||||
me.down('#header').update(html);
|
||||
};
|
||||
|
||||
var disable_at = function(card) {
|
||||
var tp = me.down('#wizcontent');
|
||||
var idx = tp.items.indexOf(card);
|
||||
for(;idx < tp.items.getCount();idx++) {
|
||||
var nc = tp.items.getAt(idx);
|
||||
if (nc)
|
||||
nc.disable();
|
||||
}
|
||||
};
|
||||
|
||||
var tabchange = function(tp, newcard, oldcard) {
|
||||
if (newcard.onSubmit) {
|
||||
me.down('#next').setVisible(false);
|
||||
me.down('#submit').setVisible(true);
|
||||
} else {
|
||||
me.down('#next').setVisible(true);
|
||||
me.down('#submit').setVisible(false);
|
||||
}
|
||||
var valid = check_card(newcard);
|
||||
me.down('#next').setDisabled(!valid);
|
||||
me.down('#submit').setDisabled(!valid);
|
||||
me.down('#back').setDisabled(tp.items.indexOf(newcard) == 0);
|
||||
|
||||
if (oldcard && !check_card(oldcard)) {
|
||||
disable_at(oldcard);
|
||||
}
|
||||
|
||||
var next = tp.items.indexOf(newcard) + 1;
|
||||
var ntab = tp.items.getAt(next);
|
||||
if (valid && ntab && !newcard.onSubmit) {
|
||||
ntab.enable();
|
||||
}
|
||||
};
|
||||
|
||||
Ext.applyIf(me, {
|
||||
width: 600,
|
||||
height: 400,
|
||||
modal: true,
|
||||
border: false,
|
||||
draggable: true,
|
||||
closable: true,
|
||||
resizable: false,
|
||||
layout: 'border',
|
||||
title: 'Proxmox VE Wizard',
|
||||
items: [
|
||||
{
|
||||
// disabled for now - not really needed
|
||||
hidden: true,
|
||||
region: 'north',
|
||||
itemId: 'header',
|
||||
layout: 'fit',
|
||||
margins: '5 5 0 5',
|
||||
bodyPadding: 10,
|
||||
html: ''
|
||||
},
|
||||
{
|
||||
xtype: 'form',
|
||||
region: 'center',
|
||||
layout: 'fit',
|
||||
border: false,
|
||||
margins: '5 5 0 5',
|
||||
fieldDefaults: {
|
||||
labelWidth: 100,
|
||||
width: 300
|
||||
},
|
||||
items: {
|
||||
itemId: 'wizcontent',
|
||||
xtype: 'tabpanel',
|
||||
activeItem: 0,
|
||||
bodyPadding: 10,
|
||||
defaults: {
|
||||
layout: 'vbox'
|
||||
},
|
||||
listeners: {
|
||||
afterrender: function(tp) {
|
||||
var atab = this.getActiveTab();
|
||||
tabchange(tp, atab);
|
||||
},
|
||||
tabchange: function(tp, newcard, oldcard) {
|
||||
display_header(newcard);
|
||||
tabchange(tp, newcard, oldcard);
|
||||
}
|
||||
},
|
||||
items: tabs
|
||||
}
|
||||
},
|
||||
tbar
|
||||
]
|
||||
});
|
||||
me.callParent();
|
||||
display_header(tabs[0]);
|
||||
|
||||
Ext.Array.each(me.query('field'), function(field) {
|
||||
field.on('validitychange', function(f) {
|
||||
var tp = me.down('#wizcontent');
|
||||
var atab = tp.getActiveTab();
|
||||
var valid = check_card(atab);
|
||||
me.down('#next').setDisabled(!valid);
|
||||
me.down('#submit').setDisabled(!valid);
|
||||
var next = tp.items.indexOf(atab) + 1;
|
||||
var ntab = tp.items.getAt(next);
|
||||
if (!valid) {
|
||||
disable_at(ntab);
|
||||
} else if (ntab && !atab.onSubmit) {
|
||||
ntab.enable();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
@ -1,376 +0,0 @@
|
||||
Ext.ns("PVE");
|
||||
|
||||
PVE.UserView = Ext.extend(PVE.grid.StdGrid, {
|
||||
|
||||
initComponent : function() {
|
||||
var self = this;
|
||||
|
||||
var store = new Ext.data.JsonStore({
|
||||
url: "/api2/json/access/users",
|
||||
autoDestory: true,
|
||||
root: 'data',
|
||||
restful: true, // use GET, not POST
|
||||
fields: [
|
||||
'userid', 'firstname', 'lastname' , 'email', 'comment',
|
||||
{ type: 'boolean', name: 'enabled' },
|
||||
{ type: 'date', dateFormat: 'timestamp', name: 'expire' },
|
||||
],
|
||||
idProperty: 'userid',
|
||||
sortInfo: { field: 'userid', order: 'DESC' }
|
||||
});
|
||||
|
||||
var render_expire = function(date) {
|
||||
if (!date)
|
||||
return 'never';
|
||||
|
||||
return date.format("Y-m-d");
|
||||
};
|
||||
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(self, {
|
||||
store: store,
|
||||
autoExpandColumn: 'comment',
|
||||
stateful: false,
|
||||
columns: [
|
||||
{
|
||||
header: 'User name',
|
||||
width: 200,
|
||||
sortable: true,
|
||||
renderer: render_username,
|
||||
dataIndex: 'userid'
|
||||
},
|
||||
{
|
||||
header: 'Realm',
|
||||
width: 100,
|
||||
sortable: true,
|
||||
renderer: render_realm,
|
||||
dataIndex: 'userid'
|
||||
},
|
||||
{
|
||||
header: 'Enabled',
|
||||
width: 50,
|
||||
sortable: true,
|
||||
dataIndex: 'enabled'
|
||||
},
|
||||
{
|
||||
header: 'Expire',
|
||||
width: 80,
|
||||
sortable: true,
|
||||
renderer: render_expire,
|
||||
dataIndex: 'expire'
|
||||
},
|
||||
{
|
||||
header: 'Name',
|
||||
width: 150,
|
||||
sortable: true,
|
||||
renderer: render_full_name,
|
||||
dataIndex: 'firstname'
|
||||
},
|
||||
{
|
||||
id: 'comment',
|
||||
header: 'Comment',
|
||||
sortable: false,
|
||||
dataIndex: 'comment'
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
show: function() {
|
||||
store.load();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
PVE.UserView.superclass.initComponent.call(self);
|
||||
}
|
||||
});
|
||||
Ext.reg('pveUserView', PVE.UserView);
|
||||
|
||||
PVE.GroupView = Ext.extend(PVE.grid.StdGrid, {
|
||||
|
||||
initComponent : function() {
|
||||
var self = this;
|
||||
|
||||
var store = new Ext.data.JsonStore({
|
||||
url: "/api2/json/access/groups",
|
||||
autoDestory: true,
|
||||
root: 'data',
|
||||
restful: true, // use GET, not POST
|
||||
fields: [ 'groupid', 'comment' ],
|
||||
idProperty: 'groupid',
|
||||
sortInfo: { field: 'groupid', order: 'DESC' }
|
||||
});
|
||||
|
||||
Ext.apply(self, {
|
||||
store: store,
|
||||
autoExpandColumn: 'comment',
|
||||
stateful: false,
|
||||
columns: [
|
||||
{
|
||||
header: 'Group name',
|
||||
width: 200,
|
||||
sortable: true,
|
||||
dataIndex: 'groupid'
|
||||
},
|
||||
{
|
||||
id: 'comment',
|
||||
header: 'Comment',
|
||||
sortable: false,
|
||||
dataIndex: 'comment'
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
show: function() {
|
||||
store.load();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
PVE.GroupView.superclass.initComponent.call(self);
|
||||
}
|
||||
});
|
||||
Ext.reg('pveGroupView', PVE.GroupView);
|
||||
|
||||
PVE.RoleView = Ext.extend(PVE.grid.StdGrid, {
|
||||
|
||||
initComponent : function() {
|
||||
var self = this;
|
||||
|
||||
var store = new Ext.data.JsonStore({
|
||||
url: "/api2/json/access/roles",
|
||||
autoDestory: true,
|
||||
root: 'data',
|
||||
restful: true, // use GET, not POST
|
||||
fields: [ 'roleid', 'privs' ],
|
||||
idProperty: 'roleid',
|
||||
sortInfo: { field: 'roleid', order: 'DESC' }
|
||||
});
|
||||
|
||||
var render_privs = function(value) {
|
||||
|
||||
if (!value)
|
||||
return '-';
|
||||
|
||||
// allow word wrap
|
||||
return '<div style="white-space:normal;">'
|
||||
+ value.replace(/\,/g, ' ') + "</div>";
|
||||
|
||||
};
|
||||
|
||||
Ext.apply(self, {
|
||||
store: store,
|
||||
autoExpandColumn: 'privs',
|
||||
stateful: false,
|
||||
columns: [
|
||||
{
|
||||
header: 'Role name',
|
||||
width: 150,
|
||||
sortable: true,
|
||||
dataIndex: 'roleid'
|
||||
},
|
||||
{
|
||||
id: 'privs',
|
||||
header: 'Privileges',
|
||||
sortable: false,
|
||||
renderer: render_privs,
|
||||
dataIndex: 'privs'
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
show: function() {
|
||||
store.load();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
PVE.RoleView.superclass.initComponent.call(self);
|
||||
}
|
||||
});
|
||||
Ext.reg('pveRoleView', PVE.RoleView);
|
||||
|
||||
PVE.ACLView = Ext.extend(PVE.grid.StdGrid, {
|
||||
|
||||
initComponent : function() {
|
||||
var self = this;
|
||||
|
||||
var store = new Ext.data.JsonStore({
|
||||
url: "/api2/json/access/acl",
|
||||
autoDestory: true,
|
||||
root: 'data',
|
||||
restful: true, // use GET, not POST
|
||||
fields: [ 'path', 'type', 'ugid', 'roleid',
|
||||
{ name: 'propagate', type: 'boolean'} ],
|
||||
sortInfo: { field: 'path', order: 'DESC' }
|
||||
});
|
||||
|
||||
var render_ugid = function(ugid, metaData, record) {
|
||||
if (record.data.type == 'group')
|
||||
return '@' + ugid;
|
||||
|
||||
return ugid;
|
||||
};
|
||||
|
||||
Ext.apply(self, {
|
||||
store: store,
|
||||
stateful: false,
|
||||
columns: [
|
||||
{
|
||||
header: 'Path',
|
||||
width: 200,
|
||||
sortable: true,
|
||||
dataIndex: 'path'
|
||||
},
|
||||
{
|
||||
header: 'User/Group',
|
||||
width: 200,
|
||||
sortable: true,
|
||||
renderer: render_ugid,
|
||||
dataIndex: 'ugid'
|
||||
},
|
||||
{
|
||||
header: 'Role',
|
||||
width: 150,
|
||||
sortable: true,
|
||||
dataIndex: 'roleid'
|
||||
},
|
||||
{
|
||||
header: 'Propagate',
|
||||
width: 80,
|
||||
sortable: true,
|
||||
dataIndex: 'propagate'
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
show: function() {
|
||||
store.load();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
PVE.ACLView.superclass.initComponent.call(self);
|
||||
}
|
||||
});
|
||||
Ext.reg('pveACLView', PVE.ACLView);
|
||||
|
||||
PVE.AuthView = Ext.extend(PVE.grid.StdGrid, {
|
||||
|
||||
initComponent : function() {
|
||||
var self = this;
|
||||
|
||||
var store = new Ext.data.JsonStore({
|
||||
url: "/api2/json/access/domains",
|
||||
autoDestory: true,
|
||||
root: 'data',
|
||||
restful: true, // use GET, not POST
|
||||
fields: [ 'realm', 'type', 'comment' ],
|
||||
idProperty: 'realm',
|
||||
sortInfo: { field: 'realm', order: 'DESC' }
|
||||
});
|
||||
|
||||
Ext.apply(self, {
|
||||
store: store,
|
||||
autoExpandColumn: 'comment',
|
||||
stateful: false,
|
||||
columns: [
|
||||
{
|
||||
header: 'Realm',
|
||||
width: 100,
|
||||
sortable: true,
|
||||
dataIndex: 'realm'
|
||||
},
|
||||
{
|
||||
header: 'Type',
|
||||
width: 100,
|
||||
sortable: true,
|
||||
dataIndex: 'type'
|
||||
},
|
||||
{
|
||||
id: 'comment',
|
||||
header: 'Comment',
|
||||
sortable: false,
|
||||
dataIndex: 'comment'
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
show: function() {
|
||||
store.load();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
PVE.AuthView.superclass.initComponent.call(self);
|
||||
}
|
||||
});
|
||||
Ext.reg('pveAuthView', PVE.AuthView);
|
||||
|
||||
PVE.ClusterConfig = Ext.extend(PVE.ConfigPanel, {
|
||||
|
||||
initComponent : function() {
|
||||
var self = this;
|
||||
|
||||
var clusterid = self.clusterid;
|
||||
|
||||
if (!clusterid)
|
||||
throw "no cluster ID specified";
|
||||
|
||||
Ext.apply(self, {
|
||||
title: "Cluster '" + clusterid + "'",
|
||||
layout: 'fit',
|
||||
border: false,
|
||||
showSearch: true,
|
||||
items: [
|
||||
{
|
||||
title: 'Summary',
|
||||
id: 'summary',
|
||||
html: 'summary ' + clusterid
|
||||
},
|
||||
{
|
||||
title: 'Storage',
|
||||
id: 'storage',
|
||||
html: 'storage ' + clusterid
|
||||
},
|
||||
{
|
||||
xtype: 'pveUserView',
|
||||
title: 'Users',
|
||||
id: 'users'
|
||||
},
|
||||
{
|
||||
xtype: 'pveGroupView',
|
||||
title: 'Groups',
|
||||
id: 'groups'
|
||||
},
|
||||
{
|
||||
xtype: 'pveACLView',
|
||||
title: 'Permissions',
|
||||
id: 'permissions',
|
||||
},
|
||||
{
|
||||
xtype: 'pveRoleView',
|
||||
title: 'Roles',
|
||||
id: 'roles'
|
||||
},
|
||||
{
|
||||
xtype: 'pveAuthView',
|
||||
title: 'Authentication',
|
||||
id: 'domains'
|
||||
},
|
||||
]
|
||||
});
|
||||
|
||||
PVE.ClusterConfig.superclass.initComponent.call(self);
|
||||
}
|
||||
});
|
||||
|
||||
Ext.reg('pveClusterConfig', PVE.ClusterConfig);
|
||||
|
@ -1,56 +0,0 @@
|
||||
Ext.ns("PVE");
|
||||
|
||||
PVE.ConfigPanel = Ext.extend(Ext.Panel, {
|
||||
|
||||
initComponent : function() {
|
||||
var self = this;
|
||||
|
||||
var pveselnode = self.pveSelNode;
|
||||
|
||||
if (!self.xtype)
|
||||
throw "no xtype specified";
|
||||
|
||||
var items = self.items || [];
|
||||
self.items = null;
|
||||
|
||||
if (PVE.ConfigPanel.activeTab[self.xtype] === undefined) {
|
||||
PVE.ConfigPanel.activeTab[self.xtype] = 0;
|
||||
}
|
||||
|
||||
if (self.showSearch) {
|
||||
items.unshift({
|
||||
pveSelNode: pveselnode,
|
||||
id: 'search',
|
||||
layout: 'fit',
|
||||
xtype: 'pveSearch'
|
||||
});
|
||||
} else {
|
||||
if (PVE.ConfigPanel.activeTab[self.xtype] === 'search') {
|
||||
PVE.ConfigPanel.activeTab[self.xtype] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
var tabs = new Ext.TabPanel({
|
||||
activeTab: PVE.ConfigPanel.activeTab[self.xtype],
|
||||
border: false,
|
||||
items: items,
|
||||
listeners: {
|
||||
tabchange: function(tab, item) {
|
||||
var id = item.getId();
|
||||
if (id)
|
||||
PVE.ConfigPanel.activeTab[self.xtype] = id;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
self.items = tabs;
|
||||
|
||||
PVE.ConfigPanel.superclass.initComponent.call(self);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
PVE.ConfigPanel.activeTab = {};
|
||||
|
||||
Ext.reg('pveConfigPanel', PVE.ConfigPanel);
|
||||
|
@ -1,63 +0,0 @@
|
||||
Ext.ns("PVE");
|
||||
|
||||
PVE.KVMConfig = Ext.extend(PVE.ConfigPanel, {
|
||||
|
||||
initComponent : function() {
|
||||
var self = this;
|
||||
|
||||
var vmid = self.confdata.id;
|
||||
var node = self.confdata.node || 'localhost';
|
||||
|
||||
if (!vmid)
|
||||
throw "no vmid specified";
|
||||
|
||||
Ext.apply(self, {
|
||||
title: "Virtual machine 'KVM " + vmid + " on node " + node + "'",
|
||||
layout: 'fit',
|
||||
border: false,
|
||||
items: [
|
||||
{
|
||||
title: 'Summary',
|
||||
id: 'summary',
|
||||
tbar: [
|
||||
{ text: 'Start'},
|
||||
{ text: 'Stop'},
|
||||
{ text: 'Reset'},
|
||||
{ text: 'Shutdown'},
|
||||
{ text: 'Remove'}
|
||||
],
|
||||
html: 'summary ' + vmid
|
||||
},
|
||||
{
|
||||
title: 'Hardware',
|
||||
id: 'hardware',
|
||||
html: 'hardware ' + vmid
|
||||
},
|
||||
{
|
||||
title: 'Options',
|
||||
id: 'options',
|
||||
html: 'options ' + vmid
|
||||
},
|
||||
{
|
||||
xtype: 'pveConsole',
|
||||
title: 'Console',
|
||||
id: 'console',
|
||||
vmid: vmid,
|
||||
node: node,
|
||||
border: false
|
||||
},
|
||||
{
|
||||
title: 'Permissions',
|
||||
id: 'permissions',
|
||||
html: 'permissions ' + vmid
|
||||
}
|
||||
|
||||
]
|
||||
});
|
||||
|
||||
PVE.KVMConfig.superclass.initComponent.call(self);
|
||||
}
|
||||
});
|
||||
|
||||
Ext.reg('pveKVMConfig', PVE.KVMConfig);
|
||||
|
@ -1,53 +0,0 @@
|
||||
include $(top_builddir)/common.mk
|
||||
|
||||
JSSRC= \
|
||||
../ext/extjs/examples/ux/MultiSelect.js \
|
||||
../ext/extjs/examples/ux/BufferView.js \
|
||||
../ext/extjs/examples/ux/fileuploadfield/FileUploadField.js \
|
||||
PVEUtils.js \
|
||||
util/base64.js \
|
||||
data/ObjectReader.js \
|
||||
data/ObjectStore.js \
|
||||
data/UpdateStore.js \
|
||||
data/SearchStore.js \
|
||||
grid/ObjectView.js \
|
||||
PVECache.js \
|
||||
StatusPanel.js \
|
||||
Workspace.js \
|
||||
window/ModalDialog.js \
|
||||
window/LoginWindow.js \
|
||||
form/StdForm.js \
|
||||
form/ModifyDirStorage.js \
|
||||
PVEFilter.js \
|
||||
ResourceTree.js \
|
||||
ConfigPanel.js \
|
||||
PVEConsole.js \
|
||||
KVMConfig.js \
|
||||
NodeConfig.js \
|
||||
StorageBrowser.js \
|
||||
ClusterConfig.js \
|
||||
PVESearch.js
|
||||
|
||||
pvemanagerlib.js: ${JSSRC}
|
||||
cat ${JSSRC} >$@
|
||||
|
||||
pvelib_DATA = pvemanagerlib.js
|
||||
pvelibdir = ${WWW_EXTDIR}
|
||||
|
||||
privatedir = ${WWW_BASEDIR}
|
||||
private_SCRIPTS = \
|
||||
startup.pl
|
||||
|
||||
managerdir = ${WWW_ROOTDIR}
|
||||
manager_SCRIPTS = \
|
||||
index.pl
|
||||
|
||||
install-data-hook:
|
||||
chown -R www-data:www-data ${DESTDIR}/${privatedir}
|
||||
chown -R www-data:www-data ${DESTDIR}/${managerdir}
|
||||
chown -R www-data:www-data ${DESTDIR}/${pvelibdir}
|
||||
|
||||
clean-local:
|
||||
-rm -rf *~ store/*~ pvemanagerlib.js
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,82 +0,0 @@
|
||||
Ext.ns("PVE");
|
||||
|
||||
PVE.Cache = function() {
|
||||
|
||||
var defaults = {};
|
||||
|
||||
var pvecache = {
|
||||
|
||||
startUpdate: function() {
|
||||
Ext.each(this.storelist, function(store) {
|
||||
store.startUpdate();
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
// fixme: use a single store instead of three
|
||||
// URl: /api2/json/cluster/index
|
||||
|
||||
nodestore: function(){
|
||||
|
||||
var fields = PVE.Utils.get_field_defaults(['name', 'storage', 'cpu', 'maxcpu',
|
||||
'mem', 'maxmem', 'uptime']);
|
||||
|
||||
var store = new PVE.data.UpdateStore({
|
||||
itype: 'node',
|
||||
idProperty: 'name',
|
||||
autoDestroy: false,
|
||||
url: '/api2/json/nodes',
|
||||
fields: fields
|
||||
});
|
||||
|
||||
return store;
|
||||
|
||||
}(),
|
||||
|
||||
vmstore: function(){
|
||||
|
||||
var fields = PVE.Utils.get_field_defaults(['id', 'name', 'node', 'storage', 'cpu', 'maxcpu',
|
||||
'mem', 'maxmem', 'disk', 'maxdisk', 'uptime']);
|
||||
var store = new PVE.data.UpdateStore({
|
||||
itype: 'vm',
|
||||
idProperty: 'id',
|
||||
autoDestroy: false,
|
||||
url: '/api2/json/cluster/vms',
|
||||
fields: fields
|
||||
});
|
||||
|
||||
return store;
|
||||
|
||||
}(),
|
||||
|
||||
ststore: function(){
|
||||
|
||||
var fields = PVE.Utils.get_field_defaults(['name', 'storage', 'node', 'shared', 'disk', 'maxdisk']);
|
||||
|
||||
var store = new PVE.data.UpdateStore({
|
||||
itype: 'storage',
|
||||
idProperty: 'name',
|
||||
autoDestroy: false,
|
||||
url: '/api2/json/cluster/storage',
|
||||
fields: fields
|
||||
});
|
||||
|
||||
return store;
|
||||
|
||||
}(),
|
||||
|
||||
dummy: "ignore me"
|
||||
};
|
||||
|
||||
pvecache.storelist = [
|
||||
pvecache.nodestore,
|
||||
pvecache.vmstore,
|
||||
pvecache.ststore
|
||||
];
|
||||
|
||||
pvecache.searchstore = new PVE.data.SearchStore({ storelist: pvecache.storelist });
|
||||
|
||||
return pvecache;
|
||||
|
||||
}();
|
||||
|
@ -1,325 +0,0 @@
|
||||
Ext.ns("PVE");
|
||||
|
||||
PVE_vnc_console_event = function(appletid, action, err) {
|
||||
//console.log("TESTINIT param1 " + appletid + " action " + action);
|
||||
|
||||
var el = Ext.get(appletid);
|
||||
if (!el)
|
||||
return;
|
||||
|
||||
if (action === "close") {
|
||||
// el.remove();
|
||||
} else if (action === "error") {
|
||||
// console.log("TESTERROR: " + err);
|
||||
// var compid = appletid.replace("-vncapp", "");
|
||||
// var comp = Ext.getCmp(compid);
|
||||
}
|
||||
|
||||
//Ext.get('mytestid').remove();
|
||||
};
|
||||
|
||||
PVE.VNCConsole = Ext.extend(Ext.Panel, {
|
||||
|
||||
initComponent : function() {
|
||||
var self = this;
|
||||
|
||||
var myid = self.id + "-vncapp";
|
||||
|
||||
self.appletID = myid;
|
||||
|
||||
//console.log("consoleid " + self.id);
|
||||
|
||||
var resize_window = function() {
|
||||
//console.log("resize");
|
||||
|
||||
var applet = Ext.getDom(myid);
|
||||
//console.log("resize " + myid + " " + applet);
|
||||
|
||||
// try again when dom element is available
|
||||
if (!(applet && Ext.isFunction(applet.getPreferredSize)))
|
||||
return resize_window.defer(1000, this);
|
||||
|
||||
var tbh = self.tbar.getHeight();
|
||||
var ps = applet.getPreferredSize();
|
||||
var aw = ps.width;
|
||||
var ah = ps.height;
|
||||
|
||||
if (aw < 320) aw = 320;
|
||||
if (ah < 200) ah = 200;
|
||||
|
||||
var oh;
|
||||
var ow;
|
||||
|
||||
//console.log("size0 " + aw + " " + ah + " tbh " + tbh);
|
||||
|
||||
if (this.innerHeight) {
|
||||
oh = this.innerHeight;
|
||||
ow = this.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";
|
||||
}
|
||||
|
||||
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 { this.resizeBy(offsetw, offseth); } catch (e) {}
|
||||
}
|
||||
|
||||
resize_window.defer(1000, this);
|
||||
};
|
||||
|
||||
var box = new Ext.BoxComponent({
|
||||
border: false,
|
||||
html: ""
|
||||
});
|
||||
|
||||
var resize_box = function() {
|
||||
var applet = Ext.getDom(myid);
|
||||
// try again when dom element is available
|
||||
if (!(applet && Ext.isFunction(applet.getPreferredSize)))
|
||||
return resize_box.defer(1000, this);
|
||||
|
||||
var ps = applet.getPreferredSize();
|
||||
Ext.fly(applet).setSize(ps.width, ps.height);
|
||||
|
||||
resize_box.defer(1000, this);
|
||||
};
|
||||
|
||||
var start_vnc_viewer = function(param) {
|
||||
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 (self.toplevel) {
|
||||
resize_window.defer(1000, window);
|
||||
} else {
|
||||
resize_box.defer(1000, self);
|
||||
}
|
||||
};
|
||||
|
||||
self.reloadApplet = function() {
|
||||
Ext.Ajax.request({
|
||||
url: self.url,
|
||||
params: self.params,
|
||||
method: 'POST',
|
||||
failure: function(response, opts) {
|
||||
box.update("Error " + response.status + ": " + response.statusText);
|
||||
},
|
||||
success: function(response, opts) {
|
||||
var obj = Ext.decode(response.responseText);
|
||||
start_vnc_viewer(obj.data);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
self.on("show", function() { self.reloadApplet();});
|
||||
self.on("hide", function() { box.update(""); });
|
||||
|
||||
Ext.apply(self, {
|
||||
layout: 'fit',
|
||||
border: false,
|
||||
autoScroll: self.toplevel ? false : true,
|
||||
items: box
|
||||
});
|
||||
|
||||
PVE.VNCConsole.superclass.initComponent.call(self);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
PVE.Console = Ext.extend(PVE.VNCConsole, {
|
||||
|
||||
initComponent : function() {
|
||||
var self = this;
|
||||
|
||||
var vmid = self.vmid;
|
||||
var node = self.node;
|
||||
|
||||
if (!vmid)
|
||||
throw "no vmid specified";
|
||||
|
||||
if (!node)
|
||||
throw "no node specified";
|
||||
|
||||
// Hint: we cant display html over the applet (applet z-index bug)
|
||||
// So we need to use aller()/confirm() instead of Ext.Msg
|
||||
|
||||
var vm_command = function(cmd, reload_applet) {
|
||||
Ext.Ajax.request({
|
||||
url: "/api2/json/nodes/" + node + "/qemu/" + vmid + "/status",
|
||||
params: { command: cmd },
|
||||
method: 'PUT',
|
||||
failure: function(response, opts) {
|
||||
alert("Command '" + cmd + "' failed" +
|
||||
"- error " + response.status + ": "
|
||||
+ response.statusText);
|
||||
},
|
||||
success: function() {
|
||||
if (reload_applet)
|
||||
self.reloadApplet.defer(1000, self);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var tbar = [
|
||||
{
|
||||
text: 'Start',
|
||||
handler: function() {
|
||||
vm_command("start", 1);
|
||||
}
|
||||
}, '-',
|
||||
{
|
||||
text: 'Stop',
|
||||
handler: function() {
|
||||
if (confirm("Do you really want to stop the VM?"))
|
||||
vm_command("stop");
|
||||
}
|
||||
}, '-',
|
||||
{
|
||||
text: 'Reset',
|
||||
handler: function() {
|
||||
if (confirm("Do you really want to reset the VM?"))
|
||||
vm_command("reset");
|
||||
}
|
||||
}, '-',
|
||||
{
|
||||
text: 'Shutdown',
|
||||
handler: function() {
|
||||
// normally, the OS ask the user
|
||||
//if (confirm("Do you really want to shut down the VM?"))
|
||||
vm_command("shutdown");
|
||||
}
|
||||
}, '-',
|
||||
{
|
||||
text: 'Suspend',
|
||||
handler: function() {
|
||||
if (confirm("Do you really want to suspend the VM?"))
|
||||
vm_command("suspend");
|
||||
}
|
||||
}, '-',
|
||||
{
|
||||
text: 'Resume',
|
||||
handler: function() {
|
||||
vm_command("resume");
|
||||
}
|
||||
},
|
||||
'->',
|
||||
{
|
||||
text: 'Refresh',
|
||||
handler: function() {
|
||||
var applet = Ext.getDom(self.appletID);
|
||||
applet.sendRefreshRequest();
|
||||
}
|
||||
}, '-',
|
||||
{
|
||||
text: 'Reload',
|
||||
handler: function () { self.reloadApplet(); }
|
||||
}, '-',
|
||||
{
|
||||
text: 'New Window',
|
||||
handler: function() {
|
||||
var url = Ext.urlEncode({
|
||||
console: 'kvm',
|
||||
vmid: vmid,
|
||||
node: node
|
||||
});
|
||||
var nw = window.open("?" + url, '_blank',
|
||||
"innerWidth=745,innerheight=427");
|
||||
nw.focus();
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
Ext.apply(self, {
|
||||
tbar: tbar,
|
||||
url: "/api2/json/nodes/" + node + "/qemu/" + vmid + "/vncproxy",
|
||||
method: 'POST'
|
||||
});
|
||||
|
||||
PVE.Console.superclass.initComponent.call(self);
|
||||
}
|
||||
});
|
||||
|
||||
Ext.reg('pveConsole', PVE.Console);
|
||||
|
||||
PVE.newShellWindow = function(nodename) {
|
||||
var url = Ext.urlEncode({
|
||||
console: 'shell',
|
||||
node: nodename
|
||||
});
|
||||
var nw = window.open("?" + url, '_blank', "innerWidth=745,innerheight=427");
|
||||
nw.focus();
|
||||
};
|
||||
|
||||
PVE.Shell = Ext.extend(PVE.VNCConsole, {
|
||||
|
||||
initComponent : function() {
|
||||
var self = this;
|
||||
|
||||
var node = self.node;
|
||||
|
||||
if (!node)
|
||||
throw "no node specified";
|
||||
|
||||
var tbar = [
|
||||
'->',
|
||||
{
|
||||
text: 'Refresh',
|
||||
handler: function() {
|
||||
var applet = Ext.getDom(self.appletID);
|
||||
applet.sendRefreshRequest();
|
||||
}
|
||||
}, '-',
|
||||
{
|
||||
text: 'Reload',
|
||||
handler: function () { self.reloadApplet(); }
|
||||
}, '-',
|
||||
{
|
||||
text: 'New Window',
|
||||
handler: function() {
|
||||
PVE.newShellWindow(node);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
Ext.apply(self, {
|
||||
tbar: tbar,
|
||||
url: "/api2/json/nodes/" + node + "/vncshell"
|
||||
});
|
||||
|
||||
PVE.Shell.superclass.initComponent.call(self);
|
||||
}
|
||||
});
|
||||
|
||||
Ext.reg('pveShell', PVE.Shell);
|
||||
|
||||
|
@ -1,325 +0,0 @@
|
||||
Ext.namespace('PVE');
|
||||
|
||||
PVE.FilterGrid = Ext.extend(Ext.grid.EditorGridPanel, {
|
||||
|
||||
constructor : function(config) {
|
||||
|
||||
config = config || {};
|
||||
|
||||
var store = new Ext.data.ArrayStore({
|
||||
// store configs
|
||||
autoDestroy: true,
|
||||
idIndex: 0,
|
||||
fields: [
|
||||
{name: 'attrib', type: 'text'},
|
||||
{name: 'cond', type: 'text'},
|
||||
{name: 'value', type: 'text'}
|
||||
]
|
||||
|
||||
//sortInfo: {field:'attrib', direction:'ASC'}
|
||||
|
||||
});
|
||||
|
||||
config.store = store;
|
||||
config.autoExpandColumn = 2;
|
||||
|
||||
var comboRenderer = function(combo){
|
||||
return function(value){
|
||||
var record = combo.findRecord(combo.valueField, value);
|
||||
return record ? record.get(combo.displayField) : combo.valueNotFoundText;
|
||||
}
|
||||
}
|
||||
|
||||
var fields = PVE.Utils.getFields();
|
||||
var attrib_list = [];
|
||||
for (field in fields) {
|
||||
var info = fields[field];
|
||||
attrib_list.push([field, info.header]);
|
||||
}
|
||||
|
||||
var attrib_combo = new Ext.form.ComboBox({
|
||||
allowBlank: false,
|
||||
store: attrib_list,
|
||||
forceSelection: true,
|
||||
triggerAction: 'all'
|
||||
});
|
||||
|
||||
var cond_list = [
|
||||
[ 'contains', 'Contains' ],
|
||||
[ '==', 'is equal' ],
|
||||
[ '!=', 'is not equal' ]
|
||||
];
|
||||
var cond_combo = new Ext.form.ComboBox({
|
||||
allowBlank: false,
|
||||
store: cond_list,
|
||||
forceSelection: true,
|
||||
triggerAction: 'all'
|
||||
});
|
||||
|
||||
var cm = new Ext.grid.ColumnModel({
|
||||
// specify any defaults for each column
|
||||
defaults: {
|
||||
sortable: true // columns are not sortable by default
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
header: 'Attribute',
|
||||
dataIndex: 'attrib',
|
||||
width: 220,
|
||||
renderer: comboRenderer(attrib_combo),
|
||||
editor: attrib_combo
|
||||
},
|
||||
{
|
||||
header: 'Condition',
|
||||
dataIndex: 'cond',
|
||||
width: 100,
|
||||
renderer: comboRenderer(cond_combo),
|
||||
editor: cond_combo
|
||||
},
|
||||
{
|
||||
header: 'Value',
|
||||
dataIndex: 'value',
|
||||
//width: 220,
|
||||
editor: new Ext.form.TextField({
|
||||
allowBlank: false
|
||||
})
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
|
||||
Ext.apply(config, {
|
||||
cm: cm,
|
||||
sm: new Ext.grid.RowSelectionModel({
|
||||
singleSelect:true
|
||||
}),
|
||||
view: new Ext.grid.GridView({
|
||||
markDirty: false
|
||||
}),
|
||||
clicksToEdit: 1
|
||||
});
|
||||
|
||||
PVE.FilterGrid.superclass.constructor.call(this, config);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
PVE.Filter = Ext.extend(Ext.Window, {
|
||||
|
||||
constructor : function(config) {
|
||||
|
||||
var win = this;
|
||||
|
||||
var viewinfo = PVE.Utils.default_views[config.loadview || PVE.Utils.default_view];
|
||||
|
||||
var grid = new PVE.FilterGrid({ border: false });
|
||||
|
||||
var fields = PVE.Utils.getFields();
|
||||
var combo_list = [];
|
||||
var checkbox_list = [];
|
||||
for (field in fields) {
|
||||
var info = fields[field];
|
||||
combo_list.push([field, info.header]);
|
||||
var cb = {
|
||||
boxLabel: info.header,
|
||||
name: field
|
||||
};
|
||||
if (viewinfo.fields[field])
|
||||
cb.checked = true;
|
||||
checkbox_list.push(new Ext.form.Checkbox(cb));
|
||||
}
|
||||
|
||||
combo_list.unshift(['-', "Remove this group"]);
|
||||
|
||||
var groupcbs = [];
|
||||
|
||||
var create_groupby_cb = function(config) {
|
||||
|
||||
var cb = Ext.apply (config || {}, {
|
||||
store: combo_list,
|
||||
triggerAction: 'all',
|
||||
width: 100,
|
||||
listeners: {
|
||||
select: function(combo, rec) {
|
||||
var value = rec.get(combo.valueField);
|
||||
if (value == '-') {
|
||||
for (var i = 0, len = groupcbs.length; i < len; i++) {
|
||||
if (groupcbs[i] == combo) {
|
||||
groupcbs.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
combo.destroy();
|
||||
}
|
||||
for (var i = 0, len = groupcbs.length; i < len; i++) {
|
||||
var cb = groupcbs[i];
|
||||
console.log("TEST " + i + " V = " + cb.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return new Ext.form.ComboBox(cb);
|
||||
};
|
||||
|
||||
var viewlist = [];
|
||||
for (var viewname in PVE.Utils.default_views) {
|
||||
var btn = {
|
||||
text: PVE.Utils.default_views[viewname].text,
|
||||
itemId: viewname,
|
||||
listeners: {
|
||||
click: function(btn) {
|
||||
console.log("load view " + btn.itemId);
|
||||
}
|
||||
}
|
||||
};
|
||||
viewlist.push(btn);
|
||||
};
|
||||
|
||||
var tbar = new Ext.Toolbar({
|
||||
items: [
|
||||
{
|
||||
text: 'Load',
|
||||
menu: {
|
||||
items: viewlist
|
||||
}
|
||||
},
|
||||
'-',
|
||||
{
|
||||
text: 'Group by:',
|
||||
listeners: {
|
||||
click: function() {
|
||||
if (groupcbs.length >= 3)
|
||||
return;
|
||||
for (var i = 0, len = groupcbs.length; i < len; i++) {
|
||||
var cb = groupcbs[i];
|
||||
if (!cb.getValue())
|
||||
return;
|
||||
}
|
||||
|
||||
var tbfill = tbar.findById('tbinsertpos');
|
||||
var pos = tbar.items.indexOf(tbfill);
|
||||
var cb = create_groupby_cb();
|
||||
groupcbs.push(cb);
|
||||
tbar.insertButton(pos, cb);
|
||||
tbar.doLayout();
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'tbinsertpos',
|
||||
xtype: 'tbfill'
|
||||
},
|
||||
{
|
||||
text: 'Add Filter',
|
||||
handler: function() {
|
||||
// access the Record constructor through the grid's store
|
||||
var store = grid.getStore();
|
||||
var rec = store.recordType;
|
||||
var p = new rec({ attrib: "Type" , cond: '==' });
|
||||
grid.stopEditing();
|
||||
store.insert(0, p);
|
||||
grid.startEditing(0, 0);
|
||||
}
|
||||
},
|
||||
'-',
|
||||
{
|
||||
text: 'Delete Filter',
|
||||
handler: function() {
|
||||
var store = grid.getStore();
|
||||
grid.stopEditing();
|
||||
var s = grid.getSelectionModel().getSelections();
|
||||
for(var i = 0, r; r = s[i]; i++){
|
||||
store.remove(r);
|
||||
}
|
||||
}
|
||||
},
|
||||
'-',
|
||||
{
|
||||
text: 'Show fields',
|
||||
menu: {
|
||||
xtype: 'menu',
|
||||
plain: true,
|
||||
items: {
|
||||
xtype: 'checkboxgroup',
|
||||
columns: 1,
|
||||
items: checkbox_list
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
Ext.each(viewinfo.groups, function(group) {
|
||||
var tbfill = tbar.findById('tbinsertpos');
|
||||
var pos = tbar.items.indexOf(tbfill);
|
||||
var cb = create_groupby_cb({ value: group});
|
||||
groupcbs.push(cb);
|
||||
tbar.insertButton(pos, cb);
|
||||
});
|
||||
|
||||
var apply_settings = function() {
|
||||
|
||||
var groups = []
|
||||
Ext.each(groupcbs, function(cb) {
|
||||
var v = cb.getValue();
|
||||
if (!v || v === '-')
|
||||
return false;
|
||||
groups.push(v);
|
||||
});
|
||||
|
||||
var fields = {};
|
||||
|
||||
Ext.each(checkbox_list, function(cb) {
|
||||
if (cb.checked)
|
||||
fields[cb.name] = true;
|
||||
});
|
||||
|
||||
win.fireEvent('changeview', 'custom', {
|
||||
groups: groups,
|
||||
fields: fields
|
||||
});
|
||||
};
|
||||
|
||||
Ext.apply(win, {
|
||||
id: 'pvefilterwindow',
|
||||
autoDestroy: true,
|
||||
title: "Filter",
|
||||
border: false,
|
||||
width: 600,
|
||||
height: 300,
|
||||
layout: 'fit',
|
||||
tbar: tbar,
|
||||
stateful: false,
|
||||
items: [
|
||||
grid
|
||||
],
|
||||
buttons: [
|
||||
{
|
||||
text: 'Apply',
|
||||
handler: apply_settings
|
||||
},
|
||||
{
|
||||
text: 'OK',
|
||||
handler: function() {
|
||||
apply_settings();
|
||||
win.close();
|
||||
}
|
||||
},
|
||||
{
|
||||
text: 'Cancel',
|
||||
handler: function() {
|
||||
win.close() }
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
PVE.Filter.superclass.constructor.call(this, config);
|
||||
|
||||
win.addEvents('changeview');
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
Ext.reg('pvefilter', PVE.Filter);
|
@ -1,85 +0,0 @@
|
||||
Ext.ns("PVE");
|
||||
|
||||
PVE.Search = Ext.extend(Ext.grid.GridPanel, {
|
||||
|
||||
initComponent : function() {
|
||||
|
||||
var n = this.pveSelNode;
|
||||
var tree = n.getOwnerTree();
|
||||
var viewname = tree.viewname;
|
||||
|
||||
//console.log("VIEW " + viewname);
|
||||
|
||||
var groupfilter = [];
|
||||
|
||||
while(n) {
|
||||
//console.log("SELECT1 " + n.id + " ATTR " + n.attributes.itype + " = " + n.attributes.groupbyid);
|
||||
if (n.attributes.groupbyid && n.attributes.itype)
|
||||
groupfilter.unshift({ field: n.attributes.itype, value: n.attributes.groupbyid});
|
||||
n = n.parentNode;
|
||||
}
|
||||
|
||||
var store = PVE.Cache.searchstore;
|
||||
|
||||
store.setGroupFilter(viewname, groupfilter);
|
||||
|
||||
var textfilter = store.getTextFilter();
|
||||
|
||||
var coldef = PVE.Utils.get_column_defaults(viewname);
|
||||
|
||||
Ext.apply(this, {
|
||||
title: 'Search',
|
||||
store: PVE.Cache.searchstore,
|
||||
border: false,
|
||||
tbar: [
|
||||
{
|
||||
text: "Create VM"
|
||||
}, '-',
|
||||
{
|
||||
text: "Create Container"
|
||||
}, '-',
|
||||
{
|
||||
text: "Add Storage"
|
||||
},
|
||||
'->', 'Search:', ' ',
|
||||
{
|
||||
xtype: 'textfield',
|
||||
width: 200,
|
||||
value: textfilter,
|
||||
enableKeyEvents: true,
|
||||
listeners: {
|
||||
keyup: function(field, e) {
|
||||
var v = field.getValue();
|
||||
PVE.Cache.searchstore.setTextFilter.defer(100, PVE.Cache.searchstore, [v]);
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
//trackMouseOver: false,
|
||||
colModel: new Ext.grid.ColumnModel({
|
||||
defaults: {
|
||||
width: 200,
|
||||
sortable: true
|
||||
},
|
||||
columns: coldef
|
||||
}),
|
||||
|
||||
view: new Ext.ux.grid.BufferView({
|
||||
//view: new Ext.grid.GridView({
|
||||
rowHeight: 36,
|
||||
// forceFit: true,
|
||||
// render rows as they come into viewable area.
|
||||
scrollDelay: false
|
||||
}),
|
||||
|
||||
stateful: false,
|
||||
stateId: 'pveseachgrid'
|
||||
});
|
||||
|
||||
PVE.Search.superclass.initComponent.call(this);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
Ext.reg('pveSearch', PVE.Search);
|
||||
|
@ -1,455 +0,0 @@
|
||||
// avoid errors when running without development tools
|
||||
if (typeof console == "undefined") {
|
||||
var console = {
|
||||
dir: function() {},
|
||||
log: function() {}
|
||||
};
|
||||
}
|
||||
|
||||
Ext.ns("PVE");
|
||||
|
||||
Ext.Ajax.defaultHeaders = {
|
||||
'Accept': 'application/json'
|
||||
};
|
||||
|
||||
Ext.Ajax.on('beforerequest', function(conn, options) {
|
||||
if (PVECSRFPreventionToken) {
|
||||
if (!options.headers)
|
||||
options.headers = {};
|
||||
options.headers['CSRFPreventionToken'] = PVECSRFPreventionToken;
|
||||
}
|
||||
});
|
||||
|
||||
// do not send '_dc' parameter
|
||||
Ext.Ajax.disableCaching = false;
|
||||
|
||||
Ext.Ajax.on('requestexception', function(conn, response, options) {
|
||||
if (response.status == 401) {
|
||||
PVE.Workspace.showLogin();
|
||||
}
|
||||
});
|
||||
|
||||
// custom Vtype for vtype:'IPAddress'
|
||||
Ext.apply(Ext.form.VTypes, {
|
||||
IPAddress: function(v) {
|
||||
return /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(v);
|
||||
},
|
||||
IPAddressText: 'Must be a numeric IP address',
|
||||
IPAddressMask: /[\d\.]/i
|
||||
});
|
||||
|
||||
PVE.Utils = function() {
|
||||
|
||||
var log_severity_hash = {
|
||||
0: "panic",
|
||||
1: "alert",
|
||||
2: "critical",
|
||||
3: "error",
|
||||
4: "warning",
|
||||
5: "notice",
|
||||
6: "info",
|
||||
7: "debug"
|
||||
};
|
||||
|
||||
|
||||
var utils = {
|
||||
|
||||
authOK: function() {
|
||||
return Ext.util.Cookies.get('PVEAuthCookie');
|
||||
},
|
||||
|
||||
authClear: function() {
|
||||
Ext.util.Cookies.clear("PVEAuthCookie");
|
||||
},
|
||||
|
||||
format_size: function(size) {
|
||||
|
||||
var kb = size / 1024;
|
||||
|
||||
if (kb < 1024)
|
||||
return kb.toFixed(0) + "KB";
|
||||
|
||||
var mb = size / (1024*1024);
|
||||
|
||||
if (mb < 1024)
|
||||
return mb.toFixed(0) + "MB";
|
||||
|
||||
var gb = mb / 1024;
|
||||
|
||||
if (gb < 1024)
|
||||
return gb.toFixed(2) + "GB";
|
||||
|
||||
var tb = gb / 1024;
|
||||
return tb.toFixed(2) + "TB";
|
||||
|
||||
},
|
||||
|
||||
format_html_bar: function(per, text) {
|
||||
|
||||
return "<div class='pve-bar-wrap'>" + text + "<div class='pve-bar-border'>" +
|
||||
"<div class='pve-bar-inner' style='width:" + per + "%;'></div>" +
|
||||
"</div></div>";
|
||||
|
||||
},
|
||||
|
||||
format_cpu_bar: function(per1, per2, text) {
|
||||
|
||||
return "<div class='pve-bar-border'>" +
|
||||
"<div class='pve-bar-inner' style='width:" + per1 + "%;'></div>" +
|
||||
"<div class='pve-bar-inner2' style='width:" + per2 + "%;'></div>" +
|
||||
"<div class='pve-bar-text'>" + text + "</div>" +
|
||||
"</div>";
|
||||
},
|
||||
|
||||
format_large_bar: function(per, text) {
|
||||
|
||||
if (!text)
|
||||
text = per.toFixed(1) + "%";
|
||||
|
||||
return "<div class='pve-largebar-border'>" +
|
||||
"<div class='pve-largebar-inner' style='width:" + per + "%;'></div>" +
|
||||
"<div class='pve-largebar-text'>" + text + "</div>" +
|
||||
"</div>";
|
||||
},
|
||||
|
||||
format_duration_long: function(ut) {
|
||||
|
||||
var days = Math.floor(ut / 86400);
|
||||
ut -= days*86400;
|
||||
var hours = Math.floor(ut / 3600);
|
||||
ut -= hours*3600;
|
||||
var mins = Math.floor(ut / 60);
|
||||
ut -= mins*60;
|
||||
|
||||
hours = "00" + hours;
|
||||
hours = hours.substr(hours.length - 2);
|
||||
mins = "00" + mins;
|
||||
mins = mins.substr(mins.length - 2);
|
||||
ut = "00" + ut;
|
||||
ut = ut.substr(ut.length - 2);
|
||||
|
||||
if (days) {
|
||||
var ds = days > 1 ? 'days' : 'day';
|
||||
return days + ' ' + ds + ' ' +
|
||||
hours + ':' + mins + ':' + ut;
|
||||
} else {
|
||||
return hours + ':' + mins + ':' + ut;
|
||||
}
|
||||
},
|
||||
|
||||
format_duration_short: function(ut) {
|
||||
|
||||
if (ut < 60)
|
||||
return ut + 's';
|
||||
|
||||
if (ut < 3600) {
|
||||
var mins = ut / 60;
|
||||
return mins.toFixed(0) + 'm';
|
||||
}
|
||||
|
||||
if (ut < 86400) {
|
||||
var hours = ut / 3600;
|
||||
return hours.toFixed(0) + 'h';
|
||||
}
|
||||
|
||||
var days = ut / 86400;
|
||||
return days.toFixed(0) + 'd';
|
||||
},
|
||||
|
||||
format_storage_type: function(value) {
|
||||
var desc = {
|
||||
dir: 'Directory',
|
||||
nfs: 'NFS',
|
||||
lvm: 'LVM',
|
||||
iscsi: 'iSCSI'
|
||||
};
|
||||
return desc[value] || 'unknown';
|
||||
},
|
||||
|
||||
format_boolean: function(value) {
|
||||
return value ? 'Yes' : 'No';
|
||||
},
|
||||
|
||||
format_neg_boolean: function(value) {
|
||||
return !value ? 'Yes' : 'No';
|
||||
},
|
||||
|
||||
format_content_types: function(value) {
|
||||
var cta = [];
|
||||
|
||||
Ext.each(value.split(','), function(ct) {
|
||||
if (ct === 'images')
|
||||
cta.push('Images');
|
||||
if (ct === 'backup')
|
||||
cta.push('Backups');
|
||||
if (ct === 'vztmpl')
|
||||
cta.push('Templates');
|
||||
if (ct === 'iso')
|
||||
cta.push('ISO');
|
||||
});
|
||||
|
||||
return cta.join(', ');
|
||||
},
|
||||
|
||||
render_serverity: function (value) {
|
||||
|
||||
return log_severity_hash[value] || value;
|
||||
},
|
||||
|
||||
render_upid: function(value, metaData, record) {
|
||||
var type = record.data.type;
|
||||
var id = record.data.id;
|
||||
|
||||
if (type == 'vncproxy') {
|
||||
return "VNC connection to VM " + id;
|
||||
}
|
||||
if (type == 'vncshell') {
|
||||
return "VNC shell";
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
|
||||
render_cpu: function(value, metaData, record, rowIndex, colIndex, store) {
|
||||
|
||||
var cpu = value;
|
||||
var maxcpu = record.data.maxcpu;
|
||||
|
||||
if (cpu === undefined || maxcpu === undefined)
|
||||
return ''
|
||||
|
||||
var per = (cpu * 100) / maxcpu;
|
||||
|
||||
return PVE.Utils.format_html_bar(per, per.toFixed(0) + '% of ' +
|
||||
maxcpu + (maxcpu > 1 ? 'CPUs' : 'CPU'));
|
||||
},
|
||||
|
||||
render_mem: function(value, metaData, record, rowIndex, colIndex, store) {
|
||||
|
||||
var mem = value;
|
||||
var maxmem = record.data.maxmem;
|
||||
|
||||
if (record.data.itype == 'storage' || mem === undefined || maxmem === undefined)
|
||||
return ''
|
||||
|
||||
return PVE.Utils.format_html_bar((mem * 100) / maxmem,
|
||||
PVE.Utils.format_size(mem));
|
||||
|
||||
},
|
||||
|
||||
render_disk: function(value, metaData, record, rowIndex, colIndex, store) {
|
||||
|
||||
var disk = value;
|
||||
var maxdisk = record.data.maxdisk;
|
||||
|
||||
if (disk === undefined || maxdisk === undefined)
|
||||
return ''
|
||||
|
||||
return PVE.Utils.format_html_bar((disk * 100) / maxdisk,
|
||||
PVE.Utils.format_size(disk));
|
||||
},
|
||||
|
||||
render_itype: function(value, metaData, record, rowIndex, colIndex, store) {
|
||||
|
||||
var cls = 'pve-itype-icon-' + value;
|
||||
|
||||
return "<div class='" + cls + "'</div><div>" + value + "</div>";
|
||||
},
|
||||
|
||||
render_uptime: function(value, metaData, record, rowIndex, colIndex, store) {
|
||||
|
||||
var uptime = value;
|
||||
|
||||
if (uptime === undefined)
|
||||
return '';
|
||||
|
||||
if (uptime <= 0)
|
||||
return '-';
|
||||
|
||||
return PVE.Utils.format_duration_long(uptime);
|
||||
},
|
||||
|
||||
dummy: "ignore me"
|
||||
};
|
||||
|
||||
var field_defaults = {
|
||||
itype: {
|
||||
header: 'Type',
|
||||
type: 'text',
|
||||
renderer: utils.render_itype,
|
||||
width: 50
|
||||
},
|
||||
id: {
|
||||
header: 'ID',
|
||||
hidden: true,
|
||||
type: 'text'
|
||||
},
|
||||
name: {
|
||||
header: 'Name',
|
||||
type: 'text'
|
||||
},
|
||||
disk: {
|
||||
header: 'Disk',
|
||||
type: 'integer',
|
||||
renderer: utils.render_disk,
|
||||
width: 60
|
||||
},
|
||||
maxdisk: {
|
||||
header: 'maxdisk',
|
||||
type:'integer',
|
||||
hidden: true,
|
||||
width: 60
|
||||
},
|
||||
mem: {
|
||||
header: 'Memory',
|
||||
type: 'integer',
|
||||
renderer: utils.render_mem,
|
||||
width: 60
|
||||
},
|
||||
maxmem: {
|
||||
header: 'maxmem',
|
||||
type:'integer',
|
||||
hidden: true,
|
||||
width: 60
|
||||
},
|
||||
cpu: {
|
||||
header: 'CPU',
|
||||
type:'float',
|
||||
renderer: utils.render_cpu,
|
||||
width: 85
|
||||
},
|
||||
maxcpu: {
|
||||
header: 'maxcpu',
|
||||
type:'integer',
|
||||
hidden: true,
|
||||
width: 60
|
||||
},
|
||||
uptime: {
|
||||
header: 'Uptime',
|
||||
type:'integer',
|
||||
renderer: utils.render_uptime,
|
||||
width: 110
|
||||
},
|
||||
node: {
|
||||
header: 'Node',
|
||||
type: 'text',
|
||||
hidden: true,
|
||||
width: 110
|
||||
},
|
||||
storage: {
|
||||
header: 'Storage',
|
||||
type: 'text',
|
||||
hidden: true,
|
||||
width: 110
|
||||
},
|
||||
shared: {
|
||||
header: 'Shared',
|
||||
type: 'boolean',
|
||||
hidden: true,
|
||||
width: 60
|
||||
}
|
||||
};
|
||||
|
||||
var visible_fields = function() {
|
||||
var res = {};
|
||||
for (field in field_defaults) {
|
||||
if (!field_defaults[field].hidden)
|
||||
res[field] = true;
|
||||
}
|
||||
return res;
|
||||
}();
|
||||
|
||||
utils.getFields = function() {
|
||||
return Ext.apply({}, field_defaults);
|
||||
};
|
||||
|
||||
utils.base_fields = function() {
|
||||
var res = [];
|
||||
for (field in field_defaults) {
|
||||
res.push(field);
|
||||
}
|
||||
return res;
|
||||
}();
|
||||
|
||||
utils.get_field_defaults = function(fieldlist) {
|
||||
|
||||
var res = [];
|
||||
|
||||
Ext.each(fieldlist, function(field) {
|
||||
var info = field_defaults[field];
|
||||
if (!info)
|
||||
throw "no such field '" + field + "'";
|
||||
var fi = { name: field };
|
||||
|
||||
if (info.type)
|
||||
fi.type = info.type;
|
||||
|
||||
res.push(fi);
|
||||
});
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
utils.default_view = 'server';
|
||||
|
||||
utils.default_views = {
|
||||
custom: {
|
||||
text: 'Custom View',
|
||||
fields: Ext.apply({}, visible_fields),
|
||||
groups: []
|
||||
},
|
||||
folder: {
|
||||
text: 'Folder View',
|
||||
fields: Ext.apply({}, visible_fields),
|
||||
groups: ['itype']
|
||||
},
|
||||
server: {
|
||||
text: 'Server View',
|
||||
fields: Ext.apply({}, visible_fields),
|
||||
groups: ['node']
|
||||
},
|
||||
storage: {
|
||||
text: 'Storage View',
|
||||
fields: Ext.apply({}, visible_fields),
|
||||
groups: ['node'],
|
||||
filterfn: function(n, itype) {
|
||||
return itype === 'storage';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
utils.changeViewDefaults = function(view, viewinfo) {
|
||||
console.log("change view defaults" + view);
|
||||
utils.default_views[view].fields =
|
||||
Ext.apply({}, viewinfo.fields);
|
||||
utils.default_views[view].groups =
|
||||
[].concat(viewinfo.groups);
|
||||
};
|
||||
|
||||
utils.get_column_defaults = function(view) {
|
||||
|
||||
var res = [];
|
||||
|
||||
var viewinfo = utils.default_views[view];
|
||||
|
||||
for (field in field_defaults) {
|
||||
var info = field_defaults[field];
|
||||
var fi = { header: info.header, dataIndex: field };
|
||||
|
||||
if (info.renderer)
|
||||
fi.renderer = info.renderer;
|
||||
if (info.width)
|
||||
fi.width = info.width;
|
||||
if (!viewinfo.fields[field])
|
||||
fi.hidden = true;
|
||||
|
||||
res.push(fi);
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
return utils;
|
||||
|
||||
}();
|
||||
|
@ -1,428 +0,0 @@
|
||||
Ext.ns("PVE");
|
||||
|
||||
PVE.DynTreeNode = Ext.extend(Ext.tree.TreeNode, {
|
||||
|
||||
nodeSortFn: function(n1, n2) {
|
||||
if ((n1.groupbyid && n2.groupbyid) ||
|
||||
!(n1.groupbyid || n2.groupbyid)) {
|
||||
|
||||
var tcmp;
|
||||
|
||||
var v1 = n1.attributes.itype;
|
||||
var v2 = n2.attributes.itype;
|
||||
if ((tcmp = v1 > v2 ? 1 : (v1 < v2 ? -1 : 0)) != 0)
|
||||
return tcmp;
|
||||
|
||||
// var v1 = n1.text.length;
|
||||
// var v2 = n2.text.length;
|
||||
// if ((tcmp = v1 > v2 ? 1 : (v1 < v2 ? -1 : 0)) != 0)
|
||||
// return tcmp;
|
||||
|
||||
return n1.text > n2.text ? 1 : (n1.text < n2.text ? -1 : 0);
|
||||
} else if (n1.groupbyid) {
|
||||
return -1;
|
||||
} else if (n2.groupbyid) {
|
||||
return 1;
|
||||
}
|
||||
},
|
||||
|
||||
applyDefaults: function(info) {
|
||||
|
||||
var itype = info.itype;
|
||||
|
||||
if (itype === 'node') {
|
||||
Ext.apply(info, {
|
||||
cls: 'x-tree-node-server',
|
||||
target: {
|
||||
xtype: 'pveNodeConfig',
|
||||
nodename: info.itemid
|
||||
}
|
||||
});
|
||||
} else if (itype === 'storage') {
|
||||
Ext.apply(info, {
|
||||
cls: 'x-tree-node-harddisk',
|
||||
target: {
|
||||
xtype: 'pveStorageBrowser',
|
||||
confdata: info.data
|
||||
}
|
||||
});
|
||||
} else if (itype === 'vm') {
|
||||
Ext.apply(info, {
|
||||
cls: 'x-tree-node-computer',
|
||||
target: {
|
||||
xtype: 'pveKVMConfig',
|
||||
confdata: info.data
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Ext.apply(info, {
|
||||
cls: 'x-tree-node-collapsed',
|
||||
target: {
|
||||
title: "Resources",
|
||||
layout: 'fit',
|
||||
border: false,
|
||||
xtype: 'pveConfigPanel'
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// fast binary search
|
||||
findInsertIndex: function(n, start, end) {
|
||||
var diff = end - start;
|
||||
|
||||
var mid = start + (diff>>1);
|
||||
|
||||
if (diff <= 0)
|
||||
return start;
|
||||
|
||||
var res = this.nodeSortFn(n, this.childNodes[mid]);
|
||||
if (res <= 0)
|
||||
return this.findInsertIndex(n, start, mid);
|
||||
else
|
||||
return this.findInsertIndex(n, mid + 1, end);
|
||||
},
|
||||
|
||||
addSorted: function(n) {
|
||||
var cs = this.childNodes;
|
||||
var len = cs.length;
|
||||
var index = this.findInsertIndex(n, 0, len);
|
||||
var pos = cs[index]
|
||||
this.insertBefore(n, pos);
|
||||
return;
|
||||
},
|
||||
|
||||
groupChild: function(info, groups, level) {
|
||||
var obj = this;
|
||||
var groupby = groups[level];
|
||||
|
||||
var v = (groupby === 'itype') ? info.itype : info.data[groupby];
|
||||
|
||||
var add_group = function(nodeinfo, gbid) {
|
||||
obj.applyDefaults(nodeinfo);
|
||||
nodeinfo.leaf = false;
|
||||
nodeinfo.groupbyid = gbid;
|
||||
nodeinfo.target.showSearch = true;
|
||||
var group = new PVE.DynTreeNode(nodeinfo);
|
||||
obj.addSorted(group);
|
||||
return group;
|
||||
};
|
||||
|
||||
if (info.itype === groupby) {
|
||||
|
||||
var group = this.findChild('groupbyid', info.itemid);
|
||||
if (group)
|
||||
return group;
|
||||
|
||||
return add_group(info, info.itemid);
|
||||
|
||||
} else if (v) {
|
||||
var group = this.findChild('groupbyid', v);
|
||||
if (!group) {
|
||||
var groupinfo = {
|
||||
itype: groupby,
|
||||
itemid: v,
|
||||
text: v
|
||||
};
|
||||
group = add_group(groupinfo, v);
|
||||
}
|
||||
|
||||
return group.groupChild(info, groups, level +1);
|
||||
|
||||
}
|
||||
|
||||
this.applyDefaults(info);
|
||||
|
||||
var child = new Ext.tree.TreeNode(info);
|
||||
this.addSorted(child);
|
||||
return child;
|
||||
},
|
||||
|
||||
removeStaleGroups: function() {
|
||||
var cs = this.childNodes;
|
||||
|
||||
for(var i = 0, len = cs.length; i < len; i++) {
|
||||
var child = cs[i];
|
||||
if (!child)
|
||||
continue;
|
||||
|
||||
if (!child.hasChildNodes()) {
|
||||
if (child.groupbyid) {
|
||||
child.remove(true);
|
||||
}
|
||||
} else {
|
||||
child.removeStaleGroups();
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
constructor: function(config){
|
||||
|
||||
PVE.DynTreeNode.superclass.constructor.call(this, Ext.apply(this, config));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Ext.tree.TreePanel.nodeTypes.pvedyn = PVE.DynTreeNode;
|
||||
|
||||
PVE.ResourceTree = Ext.extend(Ext.tree.TreePanel, {
|
||||
|
||||
viewname: PVE.Utils.default_view,
|
||||
|
||||
initView: function(viewname) {
|
||||
this.viewname = viewname;
|
||||
},
|
||||
|
||||
setView: function(viewname) {
|
||||
var tree = this;
|
||||
|
||||
tree.initView(viewname);
|
||||
|
||||
var sm = this.getSelectionModel();
|
||||
|
||||
var sel = sm.getSelectedNode();
|
||||
|
||||
var oldid;
|
||||
if (sel) {
|
||||
oldid = sel.id;
|
||||
}
|
||||
|
||||
// make sure we do not show the search panel - for performance reasons
|
||||
PVE.Workspace.setView(null);
|
||||
|
||||
var rootnode = this.getRootNode();
|
||||
|
||||
this.el.mask('Please wait...', 'x-mask-loading');
|
||||
|
||||
rootnode.collapse(false, false);
|
||||
rootnode.removeAll(true);
|
||||
|
||||
this.data = {};
|
||||
|
||||
Ext.each(tree.storelist, function(store) {
|
||||
tree.updateTree(store, store.itype);
|
||||
});
|
||||
|
||||
rootnode.expand(false, false);
|
||||
this.el.unmask();
|
||||
|
||||
if (oldid && this.data[oldid]) {
|
||||
node = this.data[oldid].treenode;
|
||||
if (node) {
|
||||
this.selectNode(node);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.selectNode(rootnode);
|
||||
|
||||
},
|
||||
|
||||
updateTree: function(store, itype) {
|
||||
|
||||
var tree = this;
|
||||
|
||||
//console.log("update tree " + tree);
|
||||
|
||||
var groups = [].concat(PVE.Utils.default_views[this.viewname].groups);
|
||||
var filterfn = PVE.Utils.default_views[this.viewname].filterfn;
|
||||
|
||||
var rootnode = tree.getRootNode();
|
||||
if (!rootnode)
|
||||
throw "no rootnode in tree";
|
||||
|
||||
// remove vanished or changed items
|
||||
for (var uid in tree.data) {
|
||||
var info = tree.data[uid];
|
||||
if (!info)
|
||||
continue;
|
||||
if (info.itype !== itype)
|
||||
continue;
|
||||
|
||||
var item = store.getById(info.itemid);
|
||||
var changed = false;
|
||||
|
||||
if (item) {
|
||||
// test if any grouping attributes changed
|
||||
for (var i = 0, len = groups.length; i < len; i++) {
|
||||
var attr = groups[i];
|
||||
if (attr === 'itype') {
|
||||
continue;
|
||||
} else if (item.data[attr] != info.data[attr]) {
|
||||
//console.log("changed");
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// fixme: also test filterfn()?
|
||||
}
|
||||
|
||||
if (!item || changed) {
|
||||
info.treenode.remove(); // fixme: destroy?
|
||||
tree.data[uid] = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// add new items
|
||||
store.each(function(item) {
|
||||
var uid = itype + "." + item.id;
|
||||
|
||||
var olddata = tree.data[uid];
|
||||
|
||||
if (filterfn && !filterfn(item, itype)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!olddata) {
|
||||
|
||||
var info = { data: {} };
|
||||
|
||||
Ext.apply(info.data, item.data);
|
||||
|
||||
Ext.apply(info, {
|
||||
itype: itype,
|
||||
id: uid,
|
||||
text: item.id,
|
||||
itemid: item.id,
|
||||
leaf: true
|
||||
});
|
||||
|
||||
var child = rootnode.groupChild(info, groups, 0);
|
||||
if (child) {
|
||||
info.treenode = child;
|
||||
tree.data[uid] = info;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// this can cause unwanted ui updates
|
||||
// remove groups with no children
|
||||
// rootnode.removeStaleGroups();
|
||||
|
||||
},
|
||||
|
||||
selectNode: function(sel) {
|
||||
|
||||
sel.ensureVisible();
|
||||
sel.select();
|
||||
|
||||
//console.log("SELECT " + sel.attributes.target);
|
||||
|
||||
var comp = { pveSelNode: sel };
|
||||
Ext.apply(comp, sel.attributes.target);
|
||||
|
||||
PVE.Workspace.setView(comp);
|
||||
},
|
||||
|
||||
initComponent: function() {
|
||||
|
||||
var tree = this;
|
||||
|
||||
var rootnode = new PVE.DynTreeNode({
|
||||
expanded: true,
|
||||
id: 'root',
|
||||
text: "Datacenter 1",
|
||||
cls: 'x-tree-node-collapsed',
|
||||
target: {
|
||||
xtype: 'pveClusterConfig',
|
||||
clusterid: 'default'
|
||||
}
|
||||
});
|
||||
|
||||
tree.storelist = PVE.Cache.storelist;
|
||||
|
||||
var groupdef = [];
|
||||
for (var viewname in PVE.Utils.default_views) {
|
||||
groupdef.push([viewname, PVE.Utils.default_views[viewname].text]);
|
||||
};
|
||||
|
||||
var viewcombo = new Ext.form.ComboBox({
|
||||
width: 150,
|
||||
allowBlank: false,
|
||||
editable: false,
|
||||
store: groupdef,
|
||||
forceSelection: true,
|
||||
triggerAction: 'all',
|
||||
value: tree.viewname,
|
||||
listeners: {
|
||||
select: function(combo, record, index) {
|
||||
tree.setView(combo.getValue());
|
||||
}
|
||||
},
|
||||
getState: function() {
|
||||
return { view: this.getValue() };
|
||||
},
|
||||
applyState : function(state) {
|
||||
if (state && state.view) {
|
||||
this.setValue(state.view);
|
||||
tree.initView(state.view);
|
||||
}
|
||||
},
|
||||
stateEvents: [ 'select' ],
|
||||
stateful: true,
|
||||
stateId: 'pvetreeviewselection'
|
||||
});
|
||||
|
||||
Ext.apply(this, {
|
||||
data: {},
|
||||
width: 250,
|
||||
title: 'Resource Tree',
|
||||
autoScroll: true,
|
||||
containerScroll: true,
|
||||
rootVisible: true,
|
||||
root: rootnode,
|
||||
tbar: [
|
||||
viewcombo,
|
||||
'->', {
|
||||
text: 'Filter',
|
||||
handler: function() {
|
||||
if (Ext.get('pvefilterwindow'))
|
||||
return;
|
||||
|
||||
var w = new PVE.Filter({
|
||||
loadview: tree.viewname,
|
||||
listeners: {
|
||||
changeview: function(view, viewinfo) {
|
||||
PVE.Utils.changeViewDefaults(view, viewinfo);
|
||||
viewcombo.setValue(view);
|
||||
// fixme: save custom view
|
||||
viewcombo.saveState();
|
||||
tree.setView(view);
|
||||
}
|
||||
}
|
||||
});
|
||||
w.show();
|
||||
}
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
click: function(n) {
|
||||
tree.selectNode(n);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
tree.initView(tree.viewname);
|
||||
|
||||
PVE.ResourceTree.superclass.initComponent.call(this);
|
||||
|
||||
Ext.each(tree.storelist, function(store) {
|
||||
var update_store = function() {
|
||||
tree.updateTree(store, store.itype);
|
||||
};
|
||||
|
||||
store.on('load', update_store);
|
||||
|
||||
tree.on('destroy', function () {
|
||||
store.un('load', update_store);
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Ext.reg('pveResourceTree', PVE.ResourceTree);
|
@ -1,210 +0,0 @@
|
||||
Ext.ns("PVE");
|
||||
|
||||
PVE.LogViewer = Ext.extend(Ext.list.ListView, {
|
||||
|
||||
initComponent : function() {
|
||||
var self = this;
|
||||
|
||||
var fields = [
|
||||
{ name: 'time', type : 'date', dateFormat: 'timestamp' },
|
||||
{ name: 'pri', type: 'int' },
|
||||
{ name: 'pid', type: 'int' },
|
||||
'node', 'user', 'tag', 'msg' ];
|
||||
|
||||
var logstore = new PVE.data.UpdateStore({
|
||||
itype: 'log',
|
||||
autoDestroy: true,
|
||||
url: self.url,
|
||||
fields: fields
|
||||
});
|
||||
|
||||
Ext.apply(self, {
|
||||
store: logstore,
|
||||
startUpdate: function() { logstore.startUpdate(); },
|
||||
stopUpdate: function() { logstore.stopUpdate(); },
|
||||
columnSort: false,
|
||||
columns: [
|
||||
{ header: "Time", width: 0.10, dataIndex: 'time',
|
||||
tpl: '{time:date("M d H:i:s")}'
|
||||
},
|
||||
{ header: "Node", width: 0.05, dataIndex: 'node' },
|
||||
{ header: "Tag", width: 0.05, dataIndex: 'tag' },
|
||||
{ header: "PID", width: 0.05, dataIndex: 'pid' },
|
||||
{ header: "User", width: 0.05, dataIndex: 'user' },
|
||||
{ header: "Severity", width: 0.05, dataIndex: 'pri',
|
||||
tpl: '{[ PVE.Utils.render_serverity(values.pri) ]}'
|
||||
},
|
||||
{ header: "Message", dataIndex: 'msg' }
|
||||
]});
|
||||
|
||||
var move_to_end = true;
|
||||
|
||||
logstore.on("load", function() {
|
||||
if (move_to_end) {
|
||||
move_to_end = false;
|
||||
var count = logstore.getCount();
|
||||
if (count) {
|
||||
var item = self.getNode(count - 1);
|
||||
if (item)
|
||||
Ext.fly(item).scrollIntoView(self.innerBody.dom.parentNode);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
PVE.LogViewer.superclass.initComponent.call(self);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
PVE.ClusterTasks = Ext.extend(Ext.grid.GridPanel, {
|
||||
|
||||
initComponent : function() {
|
||||
var self = this;
|
||||
|
||||
var fields = [
|
||||
{ name: 'starttime', type : 'date', dateFormat: 'timestamp' },
|
||||
{ name: 'endtime', type : 'date', dateFormat: 'timestamp' },
|
||||
{ name: 'pid', type: 'int' },
|
||||
'node', 'upid', 'user', 'status', 'type', 'id'];
|
||||
|
||||
// fixme: use/define a storage which append new values, but
|
||||
// defer removing old values until a maximum numer of entries
|
||||
// is reached
|
||||
var taskstore = new PVE.data.UpdateStore({
|
||||
itype: 'tasks',
|
||||
autoDestroy: true,
|
||||
url: '/api2/json/cluster/tasks',
|
||||
idProperty: 'upid',
|
||||
fields: fields
|
||||
});
|
||||
|
||||
Ext.apply(self, {
|
||||
store: taskstore,
|
||||
border: false,
|
||||
startUpdate: function() { taskstore.startUpdate(); },
|
||||
stopUpdate: function() { taskstore.stopUpdate(); },
|
||||
columnSort: false,
|
||||
autoExpandColumn: 'status',
|
||||
viewConfig: {
|
||||
getRowClass: function(record, index) {
|
||||
var status = record.get('status');
|
||||
|
||||
if (status && status != 'OK')
|
||||
return "x-form-invalid";
|
||||
}
|
||||
},
|
||||
columns: [
|
||||
{ header: "Start Time", dataIndex: 'starttime',
|
||||
width: 100,
|
||||
renderer: function(value) { return value.format("M d H:i:s"); }
|
||||
},
|
||||
{ header: "End Time", dataIndex: 'endtime',
|
||||
width: 100,
|
||||
renderer: function(value, metaData, record) {
|
||||
if (record.data.pid) {
|
||||
metaData.css = "x-grid-row-loading";
|
||||
return "";
|
||||
}
|
||||
return value.format("M d H:i:s");
|
||||
}
|
||||
},
|
||||
{ header: "Node", dataIndex: 'node',
|
||||
width: 100
|
||||
},
|
||||
{ header: "User", dataIndex: 'user',
|
||||
width: 150
|
||||
},
|
||||
{ id: 'desc', header: "Description", dataIndex: 'upid',
|
||||
width: 400,
|
||||
renderer: PVE.Utils.render_upid
|
||||
},
|
||||
{ id: 'status', header: "Status", dataIndex: 'status',
|
||||
width: 200,
|
||||
renderer: function(value, metaData, record) {
|
||||
if (record.data.pid) {
|
||||
metaData.css = "x-grid-row-loading";
|
||||
return "";
|
||||
}
|
||||
if (value == 'OK')
|
||||
return 'OK';
|
||||
// metaData.attr = 'style="color:red;"';
|
||||
return "ERROR: " + value;
|
||||
}
|
||||
}
|
||||
]});
|
||||
|
||||
PVE.ClusterTasks.superclass.initComponent.call(self);
|
||||
}
|
||||
});
|
||||
|
||||
PVE.StatusPanel = Ext.extend(Ext.Panel, {
|
||||
|
||||
initComponent : function() {
|
||||
var self = this;
|
||||
|
||||
self.title = "Realtime logfile viewer";
|
||||
self.layout = 'fit';
|
||||
|
||||
var syslogview = new PVE.LogViewer({
|
||||
url: '/api2/json/nodes/localhost/syslog'
|
||||
});
|
||||
var cllogview = new PVE.LogViewer({
|
||||
url: '/api2/json/cluster/log',
|
||||
});
|
||||
var tasklist = new PVE.ClusterTasks();
|
||||
|
||||
self.items = {
|
||||
xtype: 'tabpanel',
|
||||
border: false,
|
||||
tabPosition: 'bottom',
|
||||
activeTab: 0,
|
||||
|
||||
defaults: { layout: 'fit' },
|
||||
|
||||
items: [
|
||||
{
|
||||
title: 'Cluster Log',
|
||||
items: cllogview,
|
||||
listeners: {
|
||||
show: function() {
|
||||
cllogview.startUpdate();
|
||||
},
|
||||
hide: function() {
|
||||
cllogview.stopUpdate();
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'System Log',
|
||||
items: syslogview,
|
||||
listeners: {
|
||||
show: function() {
|
||||
syslogview.startUpdate();
|
||||
},
|
||||
hide: function() {
|
||||
syslogview.stopUpdate();
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Task list',
|
||||
items: tasklist,
|
||||
listeners: {
|
||||
show: function() {
|
||||
tasklist.startUpdate();
|
||||
},
|
||||
hide: function() {
|
||||
tasklist.stopUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
PVE.StatusPanel.superclass.initComponent.call(self);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
Ext.reg('pveStatusPanel', PVE.StatusPanel);
|
||||
|
@ -1,363 +0,0 @@
|
||||
Ext.ns("PVE");
|
||||
|
||||
PVE.StorageContent = Ext.extend(PVE.grid.StdGrid, {
|
||||
|
||||
initComponent : function() {
|
||||
var self = this;
|
||||
|
||||
var storeid = self.confdata.storage;
|
||||
var node = self.confdata.node || 'localhost';
|
||||
|
||||
if (!storeid)
|
||||
throw "no storage id specified";
|
||||
|
||||
var ct = self.content_type;
|
||||
var params = ct ? { content: ct } : null;
|
||||
|
||||
var store = new Ext.data.JsonStore({
|
||||
url: "/api2/json/nodes/" + node + "/storage/" + storeid,
|
||||
autoDestory: true,
|
||||
root: 'data',
|
||||
restful: true, // use GET, not POST
|
||||
baseParams: params,
|
||||
fields: [ 'format', 'size', 'volid' ]
|
||||
});
|
||||
|
||||
Ext.apply(self, {
|
||||
stateful: false,
|
||||
store: store,
|
||||
autoExpandColumn: 'volid',
|
||||
tbar: [
|
||||
'->',
|
||||
{
|
||||
xtype: 'form',
|
||||
url: "/api2/htmljs/nodes/" + node + "/upload",
|
||||
baseParams: { storage: storeid },
|
||||
fileUpload: true,
|
||||
height: 22,
|
||||
border: false,
|
||||
baseCls: 'plain',
|
||||
items: {
|
||||
xtype: 'fileuploadfield',
|
||||
name: 'filename',
|
||||
buttonOnly: true,
|
||||
buttonText: 'Upload',
|
||||
listeners: {
|
||||
fileselected: function(field, v) {
|
||||
self.el.mask('Please wait...', 'x-mask-loading');
|
||||
var form = field.ownerCt.getForm();
|
||||
//alert("selected " + v);
|
||||
form.submit({
|
||||
failure: function(f, resp){
|
||||
self.el.unmask();
|
||||
f.reset();
|
||||
var msg = "Please try again";
|
||||
if (resp.result && resp.result.message) {
|
||||
msg = resp.result.message;
|
||||
}
|
||||
Ext.MessageBox.alert('Failure', "Upload failed. " + msg);
|
||||
},
|
||||
success: function(f, resp){
|
||||
self.el.unmask();
|
||||
f.reset();
|
||||
Ext.MessageBox.alert('Failure', "Upload succesful");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
columns: [
|
||||
{
|
||||
id: 'volid',
|
||||
header: 'Name',
|
||||
dataIndex: 'volid'
|
||||
},
|
||||
{
|
||||
header: 'Format',
|
||||
width: 100,
|
||||
dataIndex: 'format'
|
||||
},
|
||||
{
|
||||
header: 'Size',
|
||||
width: 100,
|
||||
renderer: PVE.Utils.format_size,
|
||||
dataIndex: 'size'
|
||||
}
|
||||
],
|
||||
|
||||
listeners: {
|
||||
show: function() {
|
||||
store.load();
|
||||
}
|
||||
},
|
||||
|
||||
sm: new Ext.grid.RowSelectionModel({singleSelect:true})
|
||||
|
||||
});
|
||||
|
||||
PVE.StorageContent.superclass.initComponent.call(self);
|
||||
}
|
||||
});
|
||||
|
||||
Ext.reg('pveStorageContent', PVE.StorageContent);
|
||||
|
||||
PVE.StorageStatus = Ext.extend(PVE.grid.ObjectView, {
|
||||
|
||||
initComponent : function() {
|
||||
var self = this;
|
||||
|
||||
var storeid = self.confdata.storage;
|
||||
var node = self.confdata.node || 'localhost';
|
||||
|
||||
if (!storeid)
|
||||
throw "no storage id specified";
|
||||
|
||||
var store = new PVE.data.ObjectStore({
|
||||
url: "/api2/json/nodes/" + node + "/storage/",
|
||||
baseParams: { storage: storeid },
|
||||
method: 'GET',
|
||||
restful: true, // use GET, not POST
|
||||
autoDestroy: true,
|
||||
rows: {
|
||||
total: { header: 'Capacity' },
|
||||
used: { header: 'Used' },
|
||||
free: { header: 'Free' }
|
||||
}
|
||||
});
|
||||
|
||||
store.load();
|
||||
|
||||
Ext.apply(self, {
|
||||
layout: 'fit',
|
||||
tbar: [
|
||||
"<b>Status", '->',
|
||||
{
|
||||
text: "Refresh",
|
||||
handler: function() { store.load(); }
|
||||
}
|
||||
],
|
||||
store: store
|
||||
});
|
||||
|
||||
PVE.StorageStatus.superclass.initComponent.call(self);
|
||||
}
|
||||
});
|
||||
|
||||
PVE.StorageSummary = Ext.extend(Ext.Panel, {
|
||||
|
||||
initComponent : function() {
|
||||
var self = this;
|
||||
|
||||
var storeid = self.confdata.storage;
|
||||
|
||||
var update_config = function() {
|
||||
self.store.load();
|
||||
};
|
||||
|
||||
Ext.apply(self, {
|
||||
layout: 'hbox',
|
||||
autoScroll: true,
|
||||
|
||||
layoutConfig: {
|
||||
defaultMargins: "10 10 10 0",
|
||||
align: 'stretchmax'
|
||||
},
|
||||
|
||||
items: [
|
||||
{
|
||||
xtype: 'pveObjectView',
|
||||
store: self.store,
|
||||
margins: "10 10 10 10",
|
||||
height: 200,
|
||||
width: 300,
|
||||
tbar: [
|
||||
"<b>Configuration", "->",
|
||||
{
|
||||
text: "Edit",
|
||||
handler: function() {
|
||||
|
||||
var form = new PVE.form.ModifyDirStorage({
|
||||
confdata: self.confdata
|
||||
});
|
||||
var win = new PVE.window.ModalDialog({
|
||||
title: "Modify Directory Storage",
|
||||
items: form,
|
||||
width: 400,
|
||||
height: 300,
|
||||
buttons: [
|
||||
{
|
||||
text: 'OK',
|
||||
handler: function(){
|
||||
form.submitHandler({
|
||||
success: function() {
|
||||
win.close();
|
||||
update_config();
|
||||
}
|
||||
});
|
||||
}
|
||||
},{
|
||||
text: 'Cancel',
|
||||
handler: function(){
|
||||
win.close();
|
||||
update_config();
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
win.show();
|
||||
}
|
||||
}
|
||||
]
|
||||
//flex: 1,
|
||||
},
|
||||
new PVE.StorageStatus ({
|
||||
confdata: self.confdata,
|
||||
height: 200,
|
||||
width: 300
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
PVE.StorageSummary.superclass.initComponent.call(self);
|
||||
}
|
||||
});
|
||||
|
||||
Ext.reg('pveStorageSummary', PVE.StorageSummary);
|
||||
|
||||
PVE.StorageBrowser = Ext.extend(PVE.ConfigPanel, {
|
||||
|
||||
initComponent : function() {
|
||||
var self = this;
|
||||
|
||||
var node = self.confdata.node;
|
||||
var storeid = self.confdata.storage;
|
||||
var shared = self.confdata.shared;
|
||||
|
||||
if (!storeid)
|
||||
throw "no storage ID specified";
|
||||
|
||||
if (!shared && !node)
|
||||
throw "no node specified";
|
||||
|
||||
var title = "Storage '" + storeid + "'";
|
||||
|
||||
if (!shared)
|
||||
title = title + " on node '" + node + "'";
|
||||
|
||||
var cond_view_comp = function(id, enable) {
|
||||
|
||||
var tabs = self.get(0);
|
||||
var comp = self.findById(id);
|
||||
if (!comp)
|
||||
return;
|
||||
|
||||
if (enable) {
|
||||
tabs.unhideTabStripItem(id);
|
||||
} else {
|
||||
var active = tabs.getActiveTab();
|
||||
tabs.hideTabStripItem(id);
|
||||
if (active) {
|
||||
active = Ext.isObject(active) ? active.getId() : active;
|
||||
if (active === id) {
|
||||
tabs.setActiveTab(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var store = new PVE.data.ObjectStore({
|
||||
url: "/api2/json/storage/" + storeid,
|
||||
method: 'GET',
|
||||
autoDestory: true,
|
||||
rows: {
|
||||
type: { header: 'Storage Type', renderer: PVE.Utils.format_storage_type },
|
||||
path: { header: 'Path' },
|
||||
shared: { header: 'Shared', renderer: PVE.Utils.format_boolean },
|
||||
disable: { header: 'Disabled', renderer: PVE.Utils.format_boolean },
|
||||
content: { header: 'Content', renderer: PVE.Utils.format_content_types }
|
||||
}
|
||||
});
|
||||
|
||||
var set_visible_tabs = function() {
|
||||
var rec = store.getById('content');
|
||||
if (!rec)
|
||||
return;
|
||||
|
||||
var ct = rec.data.value || '';
|
||||
var cthash = {};
|
||||
Ext.each(ct.split(','), function(item) { cthash[item] = 1 });
|
||||
|
||||
cond_view_comp('images', cthash.images);
|
||||
cond_view_comp('iso', cthash.iso);
|
||||
cond_view_comp('vztmpl', cthash.vztmpl);
|
||||
cond_view_comp('backup', cthash.backup);
|
||||
};
|
||||
|
||||
store.on('load', set_visible_tabs);
|
||||
|
||||
Ext.apply(self, {
|
||||
title: title,
|
||||
layout: 'fit',
|
||||
border: false,
|
||||
|
||||
defaults: {
|
||||
border: false
|
||||
},
|
||||
items: [
|
||||
{
|
||||
title: 'Summary',
|
||||
xtype: 'pveStorageSummary',
|
||||
listeners: {
|
||||
show: function() {
|
||||
store.load();
|
||||
}
|
||||
},
|
||||
confdata: self.confdata,
|
||||
store: store,
|
||||
id: 'status'
|
||||
},
|
||||
{
|
||||
xtype: 'pveStorageContent',
|
||||
confdata: self.confdata,
|
||||
content_type: 'images',
|
||||
title: 'Images',
|
||||
id: 'images'
|
||||
},
|
||||
{
|
||||
xtype: 'pveStorageContent',
|
||||
confdata: self.confdata,
|
||||
content_type: 'iso',
|
||||
title: 'ISO',
|
||||
id: 'iso'
|
||||
},
|
||||
{
|
||||
xtype: 'pveStorageContent',
|
||||
confdata: self.confdata,
|
||||
content_type: 'vztmpl',
|
||||
title: 'Templates',
|
||||
id: 'vztmpl'
|
||||
},
|
||||
{
|
||||
xtype: 'pveStorageContent',
|
||||
confdata: self.confdata,
|
||||
content_type: 'backup',
|
||||
title: 'Backups',
|
||||
id: 'backup'
|
||||
},
|
||||
{
|
||||
title: 'Permissions',
|
||||
id: 'permissions',
|
||||
html: 'services '
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
PVE.StorageBrowser.superclass.initComponent.call(self);
|
||||
}
|
||||
});
|
||||
|
||||
Ext.reg('pveStorageBrowser', PVE.StorageBrowser);
|
||||
|
@ -1,136 +0,0 @@
|
||||
Ext.ns("PVE");
|
||||
|
||||
PVE.Workspace = function() {
|
||||
|
||||
var viewport, content, login;
|
||||
|
||||
var defaultView = {
|
||||
//xtype: "pveTestPanel",
|
||||
title: 'Nothing selected',
|
||||
border: false,
|
||||
region:'center'
|
||||
};
|
||||
|
||||
var buildDefaultView = function() {
|
||||
|
||||
PVE.Cache.startUpdate();
|
||||
|
||||
return new Ext.Panel({
|
||||
layout: 'border',
|
||||
border: false,
|
||||
//frame: true,
|
||||
tbar: [
|
||||
'<img src="/images/proxmox_logo.png">',
|
||||
'->',
|
||||
{
|
||||
text: 'Logout',
|
||||
handler: PVE.Workspace.showLogin
|
||||
}],
|
||||
items: [
|
||||
{
|
||||
layout: 'fit',
|
||||
region: 'center',
|
||||
margins:'5 0 0 0',
|
||||
items: defaultView
|
||||
},
|
||||
{
|
||||
xtype: 'pveResourceTree',
|
||||
region: 'west',
|
||||
margins:'5 0 0 0',
|
||||
split:true,
|
||||
collapsible: true
|
||||
},
|
||||
{
|
||||
xtype: 'pveStatusPanel',
|
||||
region:'south',
|
||||
margins:'0 0 0 0',
|
||||
height: 200,
|
||||
collapsible: true,
|
||||
split:true
|
||||
}
|
||||
]
|
||||
});
|
||||
};
|
||||
|
||||
var buildContent = function() {
|
||||
|
||||
var href = window.location.href;
|
||||
var hrefcomp = href.split('?', 2);
|
||||
if (hrefcomp.length == 2) {
|
||||
var param = Ext.urlDecode(hrefcomp[1]);
|
||||
if (param.console !== undefined) {
|
||||
if (param.console == "kvm") {
|
||||
content = new PVE.Console({
|
||||
vmid: param.vmid,
|
||||
node: param.node,
|
||||
toplevel: true
|
||||
});
|
||||
} else if (param.console == "shell") {
|
||||
content = new PVE.Shell({
|
||||
node: param.node,
|
||||
toplevel: true
|
||||
});
|
||||
}
|
||||
} else {
|
||||
content = buildDefaultView();
|
||||
}
|
||||
} else {
|
||||
content = buildDefaultView();
|
||||
}
|
||||
|
||||
viewport.add(content);
|
||||
viewport.doLayout();
|
||||
content.show(); // fire 'show' for PVE.Console
|
||||
};
|
||||
|
||||
var workspace = {
|
||||
|
||||
init: function() {
|
||||
|
||||
Ext.QuickTips.init();
|
||||
|
||||
Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
|
||||
|
||||
viewport = new Ext.Viewport({ layout : 'fit' });
|
||||
|
||||
if (!PVE.Utils.authOK()) {
|
||||
PVE.Workspace.showLogin();
|
||||
} else {
|
||||
buildContent();
|
||||
}
|
||||
},
|
||||
|
||||
setView: function(comp) {
|
||||
|
||||
if (!content) return;
|
||||
|
||||
if (!comp) comp = defaultView;
|
||||
|
||||
var cont = content.find("region", 'center')[0];
|
||||
cont.removeAll(true);
|
||||
cont.add(comp);
|
||||
content.doLayout();
|
||||
},
|
||||
|
||||
showLogin: function() {
|
||||
PVE.Utils.authClear();
|
||||
|
||||
if (!login) {
|
||||
login = new PVE.window.LoginWindow({
|
||||
handler: function() {
|
||||
if (!content)
|
||||
buildContent();
|
||||
login = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
login.show();
|
||||
},
|
||||
|
||||
dummy: "ignore me"
|
||||
};
|
||||
|
||||
return workspace;
|
||||
|
||||
}();
|
||||
|
@ -1,57 +0,0 @@
|
||||
Ext.ns("PVE.data");
|
||||
|
||||
/* 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: { data: "xyz" }
|
||||
* example2: [ { data: "xyz" } ]
|
||||
*/
|
||||
PVE.data.ObjectReader = Ext.extend(Ext.data.JsonReader, {
|
||||
|
||||
constructor: function(config){
|
||||
PVE.data.ObjectReader.superclass.constructor.call(this, Ext.apply(config, {
|
||||
root: 'data',
|
||||
idProperty: 'name',
|
||||
fields: [
|
||||
{name: 'name', type: 'text'},
|
||||
{name: 'value', type: 'text'}
|
||||
]
|
||||
}));
|
||||
this.rows = config.rows;
|
||||
},
|
||||
|
||||
extractData : function(root, returnRecords) {
|
||||
|
||||
if (returnRecords !== true)
|
||||
throw "not implemented";
|
||||
|
||||
if (Ext.isArray(root)) {
|
||||
if (root.length == 1)
|
||||
root = root[0];
|
||||
else
|
||||
root = {};
|
||||
}
|
||||
|
||||
var Record = this.recordType;
|
||||
var rs = [];
|
||||
var rows = this.rows;
|
||||
|
||||
if (rows) {
|
||||
Ext.iterate(rows, function(key, rowdef) {
|
||||
var value = root[key];
|
||||
if (Ext.isDefined(value)) {
|
||||
var rec = new Record({ name: key, value: value }, key);
|
||||
rs.push(rec);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Ext.iterate(root, function(key, value) {
|
||||
var rec = new Record({ name: key, value: value }, key);
|
||||
rs.push(rec);
|
||||
});
|
||||
}
|
||||
|
||||
return rs;
|
||||
}
|
||||
});
|
@ -1,11 +0,0 @@
|
||||
Ext.ns("PVE.data");
|
||||
|
||||
// a store for simple JSON Object (hash)
|
||||
|
||||
PVE.data.ObjectStore = Ext.extend(Ext.data.Store, {
|
||||
constructor: function(config) {
|
||||
PVE.data.ObjectStore.superclass.constructor.call(this, Ext.apply(config, {
|
||||
reader: new PVE.data.ObjectReader(config)
|
||||
}));
|
||||
}
|
||||
});
|
@ -1,266 +0,0 @@
|
||||
Ext.ns("PVE.data");
|
||||
|
||||
PVE.data.SearchStore = Ext.extend(Ext.data.Store, {
|
||||
|
||||
constructor: function(config) {
|
||||
var self = this;
|
||||
|
||||
config = config || {};
|
||||
|
||||
if (!config.storelist)
|
||||
throw "no storage list specified";
|
||||
|
||||
var text_filter = '';
|
||||
|
||||
var text_filter_fn = function(item) {
|
||||
if (text_filter) {
|
||||
var match = false;
|
||||
Ext.each(['name', 'storage', 'node'], function(field) {
|
||||
var v = item.data[field];
|
||||
if (v !== undefined) {
|
||||
v = v.toLowerCase();
|
||||
if (v.indexOf(text_filter) >= 0) {
|
||||
match = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
return !match;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
var item_filter_fn;
|
||||
|
||||
var group_filter = [];
|
||||
|
||||
var filterFn = function(item, itype) {
|
||||
|
||||
if (item_filter_fn && !item_filter_fn(item, itype)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (var i = 0, len = group_filter.length; i < len; i++) {
|
||||
var filter = group_filter[i];
|
||||
var field = filter.field;
|
||||
if (field === 'itype') {
|
||||
if (itype != filter.value)
|
||||
return true;
|
||||
} else if (item.data[field] != filter.value)
|
||||
return true;
|
||||
}
|
||||
|
||||
return text_filter_fn(item);
|
||||
};
|
||||
|
||||
var load_info = {};
|
||||
|
||||
var task_search = null;
|
||||
|
||||
var run_search_task = function(delay) {
|
||||
|
||||
if (!task_search) {
|
||||
|
||||
task_search = new Ext.util.DelayedTask(function() {
|
||||
|
||||
console.log("text filter " + text_filter);
|
||||
|
||||
self.suspendEvents();
|
||||
|
||||
self.removeAll();
|
||||
|
||||
Ext.each(config.storelist, function(store) {
|
||||
self.initStore(store, store.itype);
|
||||
});
|
||||
|
||||
self.applySort();
|
||||
|
||||
self.resumeEvents();
|
||||
|
||||
self.fireEvent('datachanged', self);
|
||||
|
||||
self.fireEvent('load', self);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
task_search.delay(delay);
|
||||
};
|
||||
|
||||
var basefields = PVE.Utils.base_fields;
|
||||
|
||||
var myfields = ['objectid', 'itype', 'itemid'].concat(basefields);;
|
||||
|
||||
var reader = new Ext.data.ArrayReader({
|
||||
fields: myfields,
|
||||
idIndex: 0
|
||||
});
|
||||
|
||||
Ext.apply(config, {
|
||||
|
||||
reader: reader,
|
||||
|
||||
sortInfo: {
|
||||
field: 'itype',
|
||||
direction: 'DESC'
|
||||
},
|
||||
|
||||
getTextFilter: function() {
|
||||
return text_filter;
|
||||
},
|
||||
|
||||
setTextFilter: function(text) {
|
||||
|
||||
if (text_filter === text)
|
||||
return;
|
||||
|
||||
text_filter = text.toLowerCase();
|
||||
|
||||
run_search_task(200);
|
||||
},
|
||||
|
||||
setGroupFilter: function(viewname, filterinfo) {
|
||||
|
||||
item_filter_fn = PVE.Utils.default_views[viewname].filterfn;
|
||||
|
||||
group_filter = filterinfo;
|
||||
|
||||
run_search_task(10);
|
||||
},
|
||||
|
||||
createRec: function(item, uid, itype) {
|
||||
|
||||
var info = Ext.apply({}, item.data);
|
||||
|
||||
Ext.apply(info, {
|
||||
itype: itype,
|
||||
id: uid,
|
||||
text: item.id,
|
||||
itemid: item.id,
|
||||
leaf: true
|
||||
});
|
||||
|
||||
var rec = new self.reader.recordType(info, uid);
|
||||
|
||||
return rec;
|
||||
},
|
||||
|
||||
initStore: function(basestore, itype) {
|
||||
|
||||
console.log("basestore init " + itype);
|
||||
|
||||
load_info[itype] = true;
|
||||
|
||||
basestore.each(function(item) {
|
||||
|
||||
if (filterFn(item, itype))
|
||||
return true;
|
||||
|
||||
var uid = itype + "." + item.id;
|
||||
|
||||
//console.log("add item " + uid);
|
||||
|
||||
var rec = self.createRec(item, uid, itype);
|
||||
self.add(rec);
|
||||
});
|
||||
},
|
||||
|
||||
updateStore: function(basestore, itype) {
|
||||
|
||||
//console.log("basestore load " + itype);
|
||||
|
||||
if (!load_info[itype]) {
|
||||
|
||||
//console.log("basestore first load " + itype);
|
||||
|
||||
self.suspendEvents();
|
||||
|
||||
self.initStore(basestore, itype);
|
||||
|
||||
self.applySort();
|
||||
|
||||
self.resumeEvents();
|
||||
|
||||
self.fireEvent('datachanged', self);
|
||||
|
||||
} else {
|
||||
|
||||
// update tree
|
||||
//console.log("basestore update start");
|
||||
|
||||
self.suspendEvents();
|
||||
|
||||
// remove vanished or changed items
|
||||
var rmlist = [];
|
||||
self.each(function(item) {
|
||||
|
||||
if (item.data.itype !== itype)
|
||||
return true;
|
||||
|
||||
var newitem = basestore.getById(item.data.itemid);
|
||||
|
||||
if (!newitem)
|
||||
rmlist.push(item);
|
||||
});
|
||||
|
||||
if (rmlist.length)
|
||||
self.remove(rmlist); //fixme:
|
||||
|
||||
var addlist = [];
|
||||
basestore.each(function(newitem) {
|
||||
|
||||
if (filterFn(newitem, itype))
|
||||
return true;
|
||||
|
||||
var uid = itype + "." + newitem.id;
|
||||
|
||||
var item = self.getById(uid);
|
||||
if (!item) {
|
||||
//console.log("add item " + uid);
|
||||
var rec = self.createRec(newitem, uid, itype);
|
||||
addlist.push(rec);
|
||||
} else {
|
||||
var changes = false;
|
||||
for (var i = 0, len = basefields.length; i < len; i++) {
|
||||
field = basefields[i];
|
||||
if (field != 'id' && item[field] != newitem.data[field]) {
|
||||
item.beginEdit()
|
||||
item.set(field,newitem.data[field]);
|
||||
changes = true;
|
||||
//item[field] = newitem.data[field];
|
||||
}
|
||||
};
|
||||
if (changes)
|
||||
item.commit(true);
|
||||
}
|
||||
});
|
||||
|
||||
if (addlist.length)
|
||||
self.add(addlist);
|
||||
|
||||
self.applySort();
|
||||
|
||||
self.resumeEvents();
|
||||
|
||||
self.fireEvent('datachanged', self);
|
||||
|
||||
//console.log("basestore update end " + itype);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
PVE.data.SearchStore.superclass.constructor.call(self, config);
|
||||
|
||||
Ext.each(config.storelist, function(store) {
|
||||
var update_store = function() {
|
||||
self.updateStore(store, store.itype);
|
||||
};
|
||||
|
||||
store.on('load', update_store);
|
||||
|
||||
self.on('destroy', function () {
|
||||
store.un('load', update_store);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
@ -1,99 +0,0 @@
|
||||
Ext.ns("PVE.data");
|
||||
|
||||
// Serialize load (avoid too many parallel connections)
|
||||
PVE.data.UpdateQueue = function() {
|
||||
|
||||
var queue = [];
|
||||
var queue_idx = {};
|
||||
|
||||
var idle = true;
|
||||
|
||||
var start_update = function() {
|
||||
if (!idle)
|
||||
return;
|
||||
var store = queue.shift();
|
||||
if (!store)
|
||||
return;
|
||||
|
||||
queue_idx[store.itype] = null;
|
||||
|
||||
idle = false;
|
||||
store.load({
|
||||
callback: function() {
|
||||
idle = true;
|
||||
start_update();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
queue: function(store) {
|
||||
if (queue_idx[store.itype])
|
||||
return;
|
||||
queue_idx[store.itype] = store;
|
||||
queue.push(store);
|
||||
start_update();
|
||||
}
|
||||
};
|
||||
}();
|
||||
|
||||
PVE.data.UpdateStore = Ext.extend(Ext.data.JsonStore, {
|
||||
|
||||
constructor: function(config) {
|
||||
var self = this;
|
||||
|
||||
var load_task;
|
||||
|
||||
var run_load_task = function(delay) {
|
||||
if (!load_task) {
|
||||
load_task = new Ext.util.DelayedTask(function() {
|
||||
PVE.data.UpdateQueue.queue(self);
|
||||
});
|
||||
}
|
||||
|
||||
load_task.delay(delay === undefined ? self.interval : delay);
|
||||
};
|
||||
|
||||
config = config || {};
|
||||
|
||||
if (!config.interval)
|
||||
config.interval = 3000;
|
||||
|
||||
if (!config.itype)
|
||||
throw "no itype specifued";
|
||||
|
||||
Ext.apply(config, {
|
||||
root: 'data',
|
||||
|
||||
startUpdate: function() {
|
||||
run_load_task(10);
|
||||
},
|
||||
|
||||
stopUpdate: function() {
|
||||
if (!load_task)
|
||||
return;
|
||||
|
||||
load_task.cancel();
|
||||
},
|
||||
|
||||
listeners: {
|
||||
beforeload: function() {
|
||||
if (!PVE.Utils.authOK()) {
|
||||
run_load_task(1000);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
load: function() {
|
||||
run_load_task();
|
||||
},
|
||||
exception: function() {
|
||||
// fixme: what to do here ?
|
||||
//console.log("got load expection");
|
||||
run_load_task();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
PVE.data.UpdateStore.superclass.constructor.call(self, config);
|
||||
}
|
||||
});
|
@ -1,88 +0,0 @@
|
||||
Ext.ns("PVE.form");
|
||||
|
||||
PVE.form.ModifyDirStorage = Ext.extend(PVE.form.StdForm, {
|
||||
|
||||
initComponent : function() {
|
||||
var self = this;
|
||||
|
||||
var storeid = self.confdata.storage;
|
||||
|
||||
var cts = [['images', 'Images']];
|
||||
|
||||
if (storeid === 'local') {
|
||||
cts.push(['vztmpl', 'OpenVZ Templates']);
|
||||
cts.push(['iso', 'ISO']);
|
||||
} else {
|
||||
cts.push(['backup', 'Backup']);
|
||||
}
|
||||
|
||||
var items = [
|
||||
{
|
||||
xtype: 'hidden',
|
||||
name: 'digest'
|
||||
},
|
||||
{
|
||||
xtype: 'textfield',
|
||||
fieldLabel: 'Storage name',
|
||||
name: 'storage',
|
||||
value: storeid,
|
||||
disabled: true
|
||||
},
|
||||
{
|
||||
xtype: 'textfield',
|
||||
fieldLabel: 'Directory',
|
||||
name: 'path',
|
||||
disabled: true
|
||||
},
|
||||
{
|
||||
xtype: 'checkbox',
|
||||
fieldLabel: 'Disabled',
|
||||
inputValue: 1,
|
||||
name: 'disable'
|
||||
},
|
||||
{
|
||||
xtype: 'checkbox',
|
||||
fieldLabel: 'Shared',
|
||||
inputValue: 1,
|
||||
name: 'shared'
|
||||
},
|
||||
{
|
||||
xtype: storeid === 'local' ? 'multiselect' : 'combo',
|
||||
forceSelection: true,
|
||||
editable: false,
|
||||
triggerAction: 'all',
|
||||
fieldLabel: 'Content',
|
||||
name: storeid === 'local' ? 'content' : 'hiddencontent',
|
||||
mode: 'local',
|
||||
style : 'margin-bottom:10px',// avoid scrolbars with Firefox
|
||||
width: 150,
|
||||
height: 'auto',
|
||||
store: cts,
|
||||
hiddenName: 'content'
|
||||
}
|
||||
];
|
||||
|
||||
// NOTE: If subclassing FormPanel, any configuration options for
|
||||
// the BasicForm must be applied to initialConfig
|
||||
Ext.apply(self, Ext.apply(self.initialConfig, {
|
||||
url: "/api2/extjs/storage/" + storeid,
|
||||
method: 'PUT',
|
||||
items: {
|
||||
layout: 'form',
|
||||
defaults: { anchor: '-20' },
|
||||
border: false,
|
||||
items: items
|
||||
}
|
||||
}));
|
||||
|
||||
PVE.form.ModifyDirStorage.superclass.initComponent.call(self);
|
||||
|
||||
var form = self.getForm();
|
||||
|
||||
form.load({
|
||||
url: "/api2/extjs/storage/" + storeid,
|
||||
method: 'GET'
|
||||
});
|
||||
|
||||
}
|
||||
});
|
@ -1,70 +0,0 @@
|
||||
Ext.ns("PVE.form");
|
||||
|
||||
PVE.form.StdForm = Ext.extend(Ext.FormPanel, {
|
||||
|
||||
initComponent : function() {
|
||||
var self = this;
|
||||
|
||||
// NOTE: If subclassing FormPanel, any configuration options for
|
||||
// the BasicForm must be applied to initialConfig
|
||||
Ext.apply(self, Ext.apply(self.initialConfig, {
|
||||
bodyStyle: 'padding:5px',
|
||||
autoScroll: true,
|
||||
|
||||
submitHandler: function(options) {
|
||||
|
||||
var form = self.getForm();
|
||||
|
||||
// NOTE: we add parameter for unset checkbox (because html
|
||||
// does not sent them by default)
|
||||
var params = {};
|
||||
form.items.each(function(f) {
|
||||
n = f.getName();
|
||||
val = f.getValue();
|
||||
xt = f.getXType();
|
||||
|
||||
if (xt === 'checkbox' && !val) {
|
||||
params[n] = 0;
|
||||
}
|
||||
});
|
||||
|
||||
if(form.isValid()){
|
||||
self.el.mask('Please wait...', 'x-mask-loading');
|
||||
|
||||
form.submit({
|
||||
params: params,
|
||||
failure: function(f, resp){
|
||||
self.el.unmask();
|
||||
if (Ext.isFunction(options.failure)) {
|
||||
options.failure();
|
||||
} else {
|
||||
var msg = "Please try again";
|
||||
if (resp.result && resp.result.message) {
|
||||
msg = resp.result.message;
|
||||
}
|
||||
Ext.MessageBox.alert('Failure', msg);
|
||||
}
|
||||
},
|
||||
success: function(f, resp){
|
||||
self.el.unmask();
|
||||
if (Ext.isFunction(options.success)) {
|
||||
options.success();
|
||||
} else {
|
||||
Ext.MessageBox.alert('Success', "Submit successful");
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (Ext.isFunction(options.failure)) {
|
||||
options.failure();
|
||||
} else {
|
||||
Ext.MessageBox.alert('Failure', "Verify failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
PVE.form.StdForm.superclass.initComponent.call(self);
|
||||
}
|
||||
});
|
||||
|
@ -1,86 +0,0 @@
|
||||
Ext.ns("PVE.grid");
|
||||
|
||||
// a grid which displays 'load' exception messages inline
|
||||
PVE.grid.StdGrid = Ext.extend(Ext.grid.GridPanel, {
|
||||
|
||||
initComponent : function() {
|
||||
var self = this;
|
||||
|
||||
if (!self.store)
|
||||
throw "no store specified";
|
||||
|
||||
PVE.grid.StdGrid.superclass.initComponent.call(self);
|
||||
|
||||
var display_exception = function(t, type, action, options, response, arg) {
|
||||
var msg;
|
||||
self.store.removeAll();
|
||||
if (type == 'response') {
|
||||
msg = "Error " + response.status + ": " + response.statusText;
|
||||
} else {
|
||||
msg = "Data load error";
|
||||
}
|
||||
self.getView().mainBody.update('<div class="x-form-invalid">' + msg + '</div>');
|
||||
};
|
||||
|
||||
self.store.on('exception', display_exception);
|
||||
self.on('beforedestroy', function() { self.store.un('exception', display_exception) });
|
||||
}
|
||||
});
|
||||
|
||||
// a special grid to display PVE.data.ObjectStore
|
||||
|
||||
PVE.grid.ObjectView = Ext.extend(PVE.grid.StdGrid, {
|
||||
|
||||
initComponent : function() {
|
||||
var self = this;
|
||||
|
||||
if (!self.store)
|
||||
throw "no store specified";
|
||||
|
||||
var rows = self.store.rows || {};
|
||||
|
||||
var render_key = function(key) {
|
||||
var rowdef = rows[key] || {};
|
||||
return rowdef.header|| key;
|
||||
};
|
||||
|
||||
var render_value = function(value, metaData, record, rowIndex, colIndex, store) {
|
||||
var key = record.data.name;
|
||||
var rowdef = rows[key] || {};
|
||||
|
||||
var renderer = rowdef.renderer;
|
||||
if (renderer)
|
||||
return renderer(value, metaData, record, rowIndex, colIndex, store);
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
Ext.apply(self, {
|
||||
hideHeaders: true,
|
||||
stateful: false,
|
||||
enableHdMenu: false,
|
||||
autoExpandColumn: 'value',
|
||||
columns: [
|
||||
{
|
||||
header: 'Name',
|
||||
width: self.cwidth1,
|
||||
dataIndex: 'name',
|
||||
sortable: false,
|
||||
renderer: render_key
|
||||
},{
|
||||
id: 'value',
|
||||
header: 'Value',
|
||||
dataIndex: 'value',
|
||||
sortable: false,
|
||||
renderer: render_value
|
||||
}
|
||||
],
|
||||
sm: new Ext.grid.RowSelectionModel({singleSelect:true})
|
||||
});
|
||||
|
||||
PVE.grid.ObjectView.superclass.initComponent.call(self);
|
||||
}
|
||||
});
|
||||
|
||||
Ext.reg('pveObjectView', PVE.grid.ObjectView);
|
||||
|
@ -1,89 +0,0 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
use strict;
|
||||
use mod_perl2 '1.9922';
|
||||
use Encode;
|
||||
use CGI;
|
||||
use PVE::AccessControl;
|
||||
use PVE::REST;
|
||||
|
||||
sub send_output {
|
||||
my ($r, $data) = @_;
|
||||
|
||||
my $encdata = encode('UTF-8', $data);
|
||||
$r->no_cache (1);
|
||||
my $x = length ($encdata);
|
||||
$r->content_type ("text/html;charset=UTF-8");
|
||||
$r->headers_out->set ("Content-length", "$x");
|
||||
$r->headers_out->set ("Pragma", "no-cache");
|
||||
|
||||
$r->print ($encdata);
|
||||
}
|
||||
|
||||
# NOTE: Requests to this page are not authenticated
|
||||
# so we must be very careful here
|
||||
|
||||
my $r = Apache2::RequestUtil->request();
|
||||
|
||||
my $token = 'null';
|
||||
if (my $cookie = $r->headers_in->{Cookie}) {
|
||||
my $ticket = PVE::REST::extract_auth_cookie($cookie);
|
||||
if (PVE::AccessControl::verify_ticket($ticket, 1)) {
|
||||
$token = PVE::AccessControl::assemble_csrf_prevention_token($ticket);
|
||||
}
|
||||
}
|
||||
|
||||
my $cgi = CGI->new($r);
|
||||
my %args = $cgi->Vars();
|
||||
|
||||
my $console = $args{console};
|
||||
|
||||
my $title = "Proxmox Virtual Environment";
|
||||
if (defined($console)) {
|
||||
if ($console eq 'kvm' && $args{vmid}) {
|
||||
my $name = "VM $args{vmid}"; # fixme: use real VM name
|
||||
$title = "$name - Proxmox Console";
|
||||
} elsif ($console eq 'shell' && $args{node}) {
|
||||
$title = "node $args{node} - Proxmox Console";
|
||||
}
|
||||
}
|
||||
|
||||
my $jssrc = <<_EOJS;
|
||||
PVECSRFPreventionToken = '$token';
|
||||
Ext.onReady(PVE.Workspace.init, PVE.Workspace);
|
||||
_EOJS
|
||||
|
||||
|
||||
my $page = <<_EOD;
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<title id='title'>$title</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/ext/ext-all.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/css/ext-pve.css" />
|
||||
|
||||
<script type="text/javascript" src="/ext/ext-base-debug.js"></script>
|
||||
<script type="text/javascript" src="/ext/ext-all-debug.js"></script>
|
||||
<script type="text/javascript" src="/ext/pvemanagerlib.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
Ext.BLANK_IMAGE_URL = '/images/default/s.gif';
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">$jssrc</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<!-- Fields required for history management -->
|
||||
<form id="history-form" class="x-hidden">
|
||||
<input type="hidden" id="x-history-field"/>
|
||||
<iframe id="x-history-frame"></iframe>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
_EOD
|
||||
|
||||
send_output ($r, $page);
|
||||
exit (0);
|
@ -1,52 +0,0 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
use strict;
|
||||
|
||||
use PVE::SafeSyslog;
|
||||
|
||||
use ModPerl::Util (); #for CORE::GLOBAL::exit
|
||||
|
||||
use Apache2::RequestRec ();
|
||||
use Apache2::RequestIO ();
|
||||
use Apache2::RequestUtil ();
|
||||
use Apache2::Access;
|
||||
use Apache2::Response;
|
||||
use Apache2::Util;
|
||||
|
||||
use Apache2::ServerUtil ();
|
||||
use Apache2::Connection ();
|
||||
use Apache2::Log ();
|
||||
|
||||
use APR::Table ();
|
||||
|
||||
use ModPerl::Registry ();
|
||||
|
||||
use Apache2::Const -compile => ':common';
|
||||
use APR::Const -compile => ':common';
|
||||
|
||||
initlog ('proxwww', 'daemon');
|
||||
|
||||
use PVE::pvecfg;
|
||||
use PVE::REST;
|
||||
use PVE::Cluster;
|
||||
use PVE::INotify;
|
||||
use PVE::RPCEnvironment;
|
||||
|
||||
sub childinit {
|
||||
syslog ('info', "Starting new child $$");
|
||||
PVE::INotify::inotify_init();
|
||||
PVE::RPCEnvironment->init('pub');
|
||||
|
||||
PVE::Config::inotify_init();
|
||||
}
|
||||
|
||||
sub childexit {
|
||||
syslog ('info', "Finish child $$");
|
||||
}
|
||||
|
||||
my $s = Apache2::ServerUtil->server;
|
||||
$s->push_handlers(PerlChildInitHandler => \&childinit);
|
||||
$s->push_handlers(PerlChildExitHandler => \&childexit);
|
||||
|
||||
1;
|
||||
|
@ -1,52 +0,0 @@
|
||||
|
||||
// code from ExtJs Forum
|
||||
|
||||
Ext.util.base64 = {
|
||||
|
||||
base64s : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
|
||||
|
||||
encode: function(decStr){
|
||||
if (typeof btoa === 'function') {
|
||||
return btoa(decStr);
|
||||
}
|
||||
var base64s = this.base64s;
|
||||
var bits;
|
||||
var dual;
|
||||
var i = 0;
|
||||
var encOut = "";
|
||||
while(decStr.length >= i + 3){
|
||||
bits = (decStr.charCodeAt(i++) & 0xff) <<16 | (decStr.charCodeAt(i++) & 0xff) <<8 | decStr.charCodeAt(i++) & 0xff;
|
||||
encOut += base64s.charAt((bits & 0x00fc0000) >>18) + base64s.charAt((bits & 0x0003f000) >>12) + base64s.charAt((bits & 0x00000fc0) >> 6) + base64s.charAt((bits & 0x0000003f));
|
||||
}
|
||||
if(decStr.length -i > 0 && decStr.length -i < 3){
|
||||
dual = Boolean(decStr.length -i -1);
|
||||
bits = ((decStr.charCodeAt(i++) & 0xff) <<16) | (dual ? (decStr.charCodeAt(i) & 0xff) <<8 : 0);
|
||||
encOut += base64s.charAt((bits & 0x00fc0000) >>18) + base64s.charAt((bits & 0x0003f000) >>12) + (dual ? base64s.charAt((bits & 0x00000fc0) >>6) : '=') + '=';
|
||||
}
|
||||
return(encOut);
|
||||
},
|
||||
|
||||
decode: function(encStr){
|
||||
if (typeof atob === 'function') {
|
||||
return atob(encStr);
|
||||
}
|
||||
var base64s = this.base64s;
|
||||
var bits;
|
||||
var decOut = "";
|
||||
var i = 0;
|
||||
for(; i<encStr.length; i += 4){
|
||||
bits = (base64s.indexOf(encStr.charAt(i)) & 0xff) <<18 | (base64s.indexOf(encStr.charAt(i +1)) & 0xff) <<12 | (base64s.indexOf(encStr.charAt(i +2)) & 0xff) << 6 | base64s.indexOf(encStr.charAt(i +3)) & 0xff;
|
||||
decOut += String.fromCharCode((bits & 0xff0000) >>16, (bits & 0xff00) >>8, bits & 0xff);
|
||||
}
|
||||
if(encStr.charCodeAt(i -2) == 61){
|
||||
return(decOut.substring(0, decOut.length -2));
|
||||
}
|
||||
else if(encStr.charCodeAt(i -1) == 61){
|
||||
return(decOut.substring(0, decOut.length -1));
|
||||
}
|
||||
else {
|
||||
return(decOut);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
@ -1,168 +0,0 @@
|
||||
Ext.ns("PVE.window");
|
||||
|
||||
PVE.window.LoginWindow = Ext.extend(Ext.Window, {
|
||||
|
||||
onLogon: function() {
|
||||
var self = this;
|
||||
|
||||
var form = self.get(0).getForm();
|
||||
|
||||
if(form.isValid()){
|
||||
self.el.mask('Please wait...', 'x-mask-loading');
|
||||
|
||||
form.submit({
|
||||
failure: function(f, resp){
|
||||
self.el.unmask();
|
||||
Ext.MessageBox.alert('Failure', "Login failed. Please try again", function() {
|
||||
var uf = form.findField('username');
|
||||
uf.focus(true);
|
||||
});
|
||||
},
|
||||
success: function(f, resp){
|
||||
self.el.unmask();
|
||||
|
||||
if (resp.result && resp.result.data)
|
||||
PVECSRFPreventionToken = resp.result.data.CSRFPreventionToken;
|
||||
|
||||
var handler = self.handler || Ext.emptyFn;
|
||||
handler.call(self);
|
||||
self.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
initComponent: function() {
|
||||
var self = this;
|
||||
|
||||
var realmstore = new Ext.data.JsonStore({
|
||||
url: "/api2/json/access/domains",
|
||||
autoDestory: true,
|
||||
root: 'data',
|
||||
restful: true, // use GET, not POST
|
||||
fields: [ 'realm', 'comment', 'default' ],
|
||||
idProperty: 'realm',
|
||||
sortInfo: { field: 'realm', order: 'DESC' }
|
||||
});
|
||||
|
||||
var combo = new Ext.form.ComboBox({
|
||||
fieldLabel: 'Realm',
|
||||
hiddenName: 'realm',
|
||||
store: realmstore,
|
||||
mode: 'local',
|
||||
allowBlank: false,
|
||||
forceSelection: true,
|
||||
autoSelect: false,
|
||||
triggerAction: 'all',
|
||||
valueField: 'realm',
|
||||
displayField: 'comment',
|
||||
getState: function() {
|
||||
return { value: this.getValue() };
|
||||
},
|
||||
applyState : function(state) {
|
||||
if (state && state.value) {
|
||||
this.setValue(state.value);
|
||||
}
|
||||
},
|
||||
stateEvents: [ 'select' ],
|
||||
stateful: true,
|
||||
stateId: 'pveloginrealm'
|
||||
});
|
||||
|
||||
realmstore.load({
|
||||
callback: function(r, o, success) {
|
||||
if (success) {
|
||||
var def = combo.getValue();
|
||||
if (!def) {
|
||||
if (r[0] && r[0].data)
|
||||
def = r[0].data.realm;
|
||||
Ext.each(r, function(record) {
|
||||
if (record.data && record.data["default"])
|
||||
def = record.data.realm;
|
||||
});
|
||||
}
|
||||
if (def)
|
||||
combo.setValue(def)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Ext.apply(self, {
|
||||
width: 400,
|
||||
height: 160,
|
||||
modal: true,
|
||||
border: false,
|
||||
draggable: false,
|
||||
closable: false,
|
||||
resizable: false,
|
||||
layout: 'fit',
|
||||
title: 'PVE Manager Login',
|
||||
|
||||
items: [{
|
||||
xtype: 'form',
|
||||
frame: true,
|
||||
url: '/api2/extjs/access/ticket',
|
||||
|
||||
labelWidth: 70,
|
||||
labelAlign : 'right',
|
||||
|
||||
defaults: {
|
||||
anchor: '-5',
|
||||
allowBlank: false
|
||||
},
|
||||
|
||||
items: [
|
||||
{
|
||||
xtype: 'textfield',
|
||||
fieldLabel: 'User name',
|
||||
name: 'username',
|
||||
blankText:"Enter your user name",
|
||||
listeners: {
|
||||
render: function(f) {
|
||||
f.focus(true, 500);
|
||||
},
|
||||
specialkey: function(f, e) {
|
||||
var form = f.findParentByType("form").getForm();
|
||||
if (e.getKey() === e.ENTER) {
|
||||
var pf = form.findField('password');
|
||||
if (pf.getValue()) {
|
||||
self.onLogon();
|
||||
} else {
|
||||
pf.focus(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'textfield',
|
||||
inputType: 'password',
|
||||
fieldLabel: 'Password',
|
||||
name: 'password',
|
||||
blankText:"Enter your password",
|
||||
listeners: {
|
||||
specialkey: function(field, e) {
|
||||
if (e.getKey() === e.ENTER) {
|
||||
self.onLogon();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
combo
|
||||
],
|
||||
buttons: [
|
||||
{
|
||||
text: 'Login',
|
||||
handler: function(){
|
||||
self.onLogon();
|
||||
}
|
||||
}
|
||||
]
|
||||
}]
|
||||
});
|
||||
|
||||
PVE.window.LoginWindow.superclass.initComponent.call(self);
|
||||
}
|
||||
|
||||
});
|
@ -1,20 +0,0 @@
|
||||
Ext.ns("PVE.window");
|
||||
|
||||
PVE.window.ModalDialog = Ext.extend(Ext.Window, {
|
||||
|
||||
initComponent: function() {
|
||||
var self = this;
|
||||
|
||||
//self.width = self.width || 800;
|
||||
//self.height = self.height || 400;
|
||||
|
||||
Ext.apply(self, {
|
||||
modal: true,
|
||||
border: false,
|
||||
layout: 'fit',
|
||||
maximizable: true
|
||||
});
|
||||
|
||||
PVE.window.ModalDialog.superclass.initComponent.call(self);
|
||||
}
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user