mirror of
https://git.proxmox.com/git/pve-manager
synced 2025-08-13 17:45:15 +00:00
ui: declarative LXC Create
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
parent
658bf72581
commit
7adbc4a457
@ -1,328 +1,316 @@
|
||||
/*global
|
||||
FileReader
|
||||
*/
|
||||
|
||||
/*jslint confusion: true*/
|
||||
Ext.define('PVE.lxc.CreateWizard', {
|
||||
extend: 'PVE.window.Wizard',
|
||||
mixins: ['Proxmox.Mixin.CBind'],
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
viewModel: {
|
||||
data: {
|
||||
nodename: '',
|
||||
storage: '',
|
||||
unprivileged: false
|
||||
}
|
||||
},
|
||||
|
||||
var summarystore = Ext.create('Ext.data.Store', {
|
||||
model: 'KeyValue',
|
||||
sorters: [
|
||||
cbindData: {
|
||||
nodename: undefined
|
||||
},
|
||||
|
||||
subject: gettext('LXC Container'),
|
||||
|
||||
items: [
|
||||
{
|
||||
xtype: 'inputpanel',
|
||||
title: gettext('General'),
|
||||
onlineHelp: 'pct_general',
|
||||
column1: [
|
||||
{
|
||||
property : 'key',
|
||||
direction: 'ASC'
|
||||
xtype: 'pveNodeSelector',
|
||||
name: 'nodename',
|
||||
cbind: {
|
||||
selectCurNode: '{!nodename}',
|
||||
preferredValue: '{nodename}'
|
||||
},
|
||||
bind: {
|
||||
value: '{nodename}'
|
||||
},
|
||||
fieldLabel: gettext('Node'),
|
||||
allowBlank: false,
|
||||
onlineValidator: true
|
||||
},
|
||||
{
|
||||
xtype: 'pveGuestIDSelector',
|
||||
name: 'vmid', // backend only knows vmid
|
||||
guestType: 'lxc',
|
||||
value: '',
|
||||
loadNextFreeID: true,
|
||||
validateExists: false
|
||||
},
|
||||
{
|
||||
xtype: 'proxmoxtextfield',
|
||||
name: 'hostname',
|
||||
vtype: 'DnsName',
|
||||
value: '',
|
||||
fieldLabel: gettext('Hostname'),
|
||||
skipEmptyText: true,
|
||||
allowBlank: true
|
||||
},
|
||||
{
|
||||
xtype: 'proxmoxcheckbox',
|
||||
name: 'unprivileged',
|
||||
value: false,
|
||||
bind: {
|
||||
value: '{unprivileged}'
|
||||
},
|
||||
fieldLabel: gettext('Unprivileged container')
|
||||
}
|
||||
],
|
||||
column2: [
|
||||
{
|
||||
xtype: 'pvePoolSelector',
|
||||
fieldLabel: gettext('Resource Pool'),
|
||||
name: 'pool',
|
||||
submitValue: false,
|
||||
value: '',
|
||||
allowBlank: true
|
||||
},
|
||||
{
|
||||
xtype: 'textfield',
|
||||
inputType: 'password',
|
||||
name: 'password',
|
||||
value: '',
|
||||
fieldLabel: gettext('Password'),
|
||||
allowBlank: false,
|
||||
minLength: 5,
|
||||
change: function(f, value) {
|
||||
if (f.rendered) {
|
||||
f.up().down('field[name=confirmpw]').validate();
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'textfield',
|
||||
inputType: 'password',
|
||||
name: 'confirmpw',
|
||||
value: '',
|
||||
fieldLabel: gettext('Confirm password'),
|
||||
allowBlank: true,
|
||||
submitValue: false,
|
||||
validator: function(value) {
|
||||
var pw = this.up().down('field[name=password]').getValue();
|
||||
if (pw !== value) {
|
||||
return "Passwords do not match!";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'proxmoxtextfield',
|
||||
name: 'ssh-public-keys',
|
||||
value: '',
|
||||
fieldLabel: gettext('SSH public key'),
|
||||
allowBlank: true,
|
||||
validator: function(value) {
|
||||
var pwfield = this.up().down('field[name=password]');
|
||||
if (value.length) {
|
||||
var key = PVE.Parser.parseSSHKey(value);
|
||||
if (!key) {
|
||||
return "Failed to recognize ssh key";
|
||||
}
|
||||
pwfield.allowBlank = true;
|
||||
} else {
|
||||
pwfield.allowBlank = false;
|
||||
}
|
||||
pwfield.validate();
|
||||
return true;
|
||||
},
|
||||
afterRender: function() {
|
||||
if (!window.FileReader) {
|
||||
// No FileReader support in this browser
|
||||
return;
|
||||
}
|
||||
var cancel = function(ev) {
|
||||
ev = ev.event;
|
||||
if (ev.preventDefault) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
};
|
||||
var field = this;
|
||||
field.inputEl.on('dragover', cancel);
|
||||
field.inputEl.on('dragenter', cancel);
|
||||
field.inputEl.on('drop', function(ev) {
|
||||
ev = ev.event;
|
||||
if (ev.preventDefault) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
var files = ev.dataTransfer.files;
|
||||
PVE.Utils.loadSSHKeyFromFile(files[0], function(v) {
|
||||
field.setValue(v);
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'filebutton',
|
||||
name: 'file',
|
||||
hidden: !window.FileReader,
|
||||
text: gettext('Load SSH Key File'),
|
||||
listeners: {
|
||||
change: function(btn, e, value) {
|
||||
e = e.event;
|
||||
var field = this.up().down('proxmoxtextfield[name=ssh-public-keys]');
|
||||
PVE.Utils.loadSSHKeyFromFile(e.target.files[0], function(v) {
|
||||
field.setValue(v);
|
||||
});
|
||||
btn.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
var tmplsel = Ext.create('PVE.form.FileSelector', {
|
||||
name: 'ostemplate',
|
||||
storageContent: 'vztmpl',
|
||||
fieldLabel: gettext('Template'),
|
||||
allowBlank: false
|
||||
});
|
||||
|
||||
var tmplstoragesel = Ext.create('PVE.form.StorageSelector', {
|
||||
name: 'tmplstorage',
|
||||
fieldLabel: gettext('Storage'),
|
||||
storageContent: 'vztmpl',
|
||||
autoSelect: true,
|
||||
allowBlank: false,
|
||||
listeners: {
|
||||
change: function(f, value) {
|
||||
tmplsel.setStorage(value);
|
||||
},
|
||||
{
|
||||
xtype: 'inputpanel',
|
||||
title: gettext('Template'),
|
||||
onlineHelp: 'pct_container_images',
|
||||
column1: [
|
||||
{
|
||||
xtype: 'pveStorageSelector',
|
||||
name: 'tmplstorage',
|
||||
fieldLabel: gettext('Storage'),
|
||||
storageContent: 'vztmpl',
|
||||
autoSelect: true,
|
||||
allowBlank: false,
|
||||
bind: {
|
||||
value: '{storage}',
|
||||
nodename: '{nodename}'
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'pveFileSelector',
|
||||
name: 'ostemplate',
|
||||
storageContent: 'vztmpl',
|
||||
fieldLabel: gettext('Template'),
|
||||
bind: {
|
||||
storage: '{storage}',
|
||||
nodename: '{nodename}'
|
||||
},
|
||||
allowBlank: false
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var rootfspanel = Ext.create('PVE.lxc.MountPointInputPanel', {
|
||||
]
|
||||
},
|
||||
{
|
||||
xtype: 'pveLxcMountPointInputPanel',
|
||||
title: gettext('Root Disk'),
|
||||
insideWizard: true,
|
||||
isCreate: true,
|
||||
unused: false,
|
||||
unprivileged: false,
|
||||
bind: {
|
||||
nodename: '{nodename}',
|
||||
unprivileged: '{unprivileged}'
|
||||
},
|
||||
confid: 'rootfs'
|
||||
});
|
||||
|
||||
var networkpanel = Ext.create('PVE.lxc.NetworkInputPanel', {
|
||||
},
|
||||
{
|
||||
xtype: 'pveLxcCPUInputPanel',
|
||||
title: gettext('CPU'),
|
||||
insideWizard: true
|
||||
},
|
||||
{
|
||||
xtype: 'pveLxcMemoryInputPanel',
|
||||
title: gettext('Memory'),
|
||||
insideWizard: true
|
||||
},
|
||||
{
|
||||
xtype: 'pveLxcNetworkInputPanel',
|
||||
title: gettext('Network'),
|
||||
insideWizard: true,
|
||||
bind: {
|
||||
nodename: '{nodename}'
|
||||
},
|
||||
isCreate: true
|
||||
});
|
||||
|
||||
var passwordfield = Ext.createWidget('textfield', {
|
||||
inputType: 'password',
|
||||
name: 'password',
|
||||
value: '',
|
||||
fieldLabel: gettext('Password'),
|
||||
allowBlank: false,
|
||||
minLength: 5,
|
||||
change: function(f, value) {
|
||||
if (!me.rendered) {
|
||||
return;
|
||||
}
|
||||
me.down('field[name=confirmpw]').validate();
|
||||
}
|
||||
});
|
||||
|
||||
/*jslint confusion: true */
|
||||
/* the validator function can return either a string or a boolean */
|
||||
me.sshkeyfield = Ext.createWidget('proxmoxtextfield', {
|
||||
name: 'ssh-public-keys',
|
||||
value: '',
|
||||
fieldLabel: gettext('SSH public key'),
|
||||
allowBlank: true,
|
||||
validator: function(value) {
|
||||
if (value.length) {
|
||||
var key = PVE.Parser.parseSSHKey(value);
|
||||
if (!key) {
|
||||
return "Failed to recognize ssh key";
|
||||
}
|
||||
me.down('field[name=password]').allowBlank = true;
|
||||
} else {
|
||||
me.down('field[name=password]').allowBlank = false;
|
||||
}
|
||||
me.down('field[name=password]').validate();
|
||||
return true;
|
||||
},
|
||||
afterRender: function() {
|
||||
if (!window.FileReader) {
|
||||
// No FileReader support in this browser
|
||||
return;
|
||||
}
|
||||
var cancel = function(ev) {
|
||||
ev = ev.event;
|
||||
if (ev.preventDefault) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
};
|
||||
me.sshkeyfield.inputEl.on('dragover', cancel);
|
||||
me.sshkeyfield.inputEl.on('dragenter', cancel);
|
||||
me.sshkeyfield.inputEl.on('drop', function(ev) {
|
||||
ev = ev.event;
|
||||
if (ev.preventDefault) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
var files = ev.dataTransfer.files;
|
||||
PVE.Utils.loadSSHKeyFromFile(files[0], function (v) {
|
||||
me.sshkeyfield.setValue(v);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var column2 = [
|
||||
{
|
||||
xtype: 'pvePoolSelector',
|
||||
fieldLabel: gettext('Resource Pool'),
|
||||
name: 'pool',
|
||||
value: '',
|
||||
allowBlank: true
|
||||
},
|
||||
passwordfield,
|
||||
{
|
||||
xtype: 'textfield',
|
||||
inputType: 'password',
|
||||
name: 'confirmpw',
|
||||
value: '',
|
||||
fieldLabel: gettext('Confirm password'),
|
||||
allowBlank: true,
|
||||
validator: function(value) {
|
||||
var pw = me.down('field[name=password]').getValue();
|
||||
if (pw !== value) {
|
||||
return "Passwords do not match!";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},
|
||||
me.sshkeyfield
|
||||
];
|
||||
/*jslint confusion: false */
|
||||
|
||||
if (window.FileReader) {
|
||||
column2.push({
|
||||
xtype: 'filebutton',
|
||||
name: 'file',
|
||||
text: gettext('Load SSH Key File'),
|
||||
listeners: {
|
||||
change: function(btn, e, value) {
|
||||
e = e.event;
|
||||
PVE.Utils.loadSSHKeyFromFile(e.target.files[0], function (v) {
|
||||
me.sshkeyfield.setValue(v);
|
||||
});
|
||||
btn.reset();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Ext.applyIf(me, {
|
||||
subject: gettext('LXC Container'),
|
||||
},
|
||||
{
|
||||
xtype: 'pveLxcDNSInputPanel',
|
||||
title: gettext('DNS'),
|
||||
insideWizard: true
|
||||
},
|
||||
{
|
||||
title: gettext('Confirm'),
|
||||
layout: 'fit',
|
||||
items: [
|
||||
{
|
||||
xtype: 'inputpanel',
|
||||
title: gettext('General'),
|
||||
onlineHelp: 'pct_general',
|
||||
column1: [
|
||||
{
|
||||
xtype: 'pveNodeSelector',
|
||||
name: 'nodename',
|
||||
selectCurNode: !me.nodename,
|
||||
preferredValue: me.nodename,
|
||||
fieldLabel: gettext('Node'),
|
||||
allowBlank: false,
|
||||
onlineValidator: true,
|
||||
listeners: {
|
||||
change: function(f, value) {
|
||||
tmplstoragesel.setNodename(value);
|
||||
tmplsel.setStorage(undefined, value);
|
||||
networkpanel.setNodename(value);
|
||||
rootfspanel.setNodename(value);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'pveGuestIDSelector',
|
||||
name: 'vmid', // backend only knows vmid
|
||||
guestType: 'lxc',
|
||||
value: '',
|
||||
loadNextFreeID: true,
|
||||
validateExists: false
|
||||
},
|
||||
{
|
||||
xtype: 'proxmoxtextfield',
|
||||
name: 'hostname',
|
||||
vtype: 'DnsName',
|
||||
value: '',
|
||||
fieldLabel: gettext('Hostname'),
|
||||
skipEmptyText: true,
|
||||
allowBlank: true
|
||||
},
|
||||
{
|
||||
xtype: 'proxmoxcheckbox',
|
||||
name: 'unprivileged',
|
||||
value: '',
|
||||
listeners: {
|
||||
change: function(f, value) {
|
||||
if (value) {
|
||||
rootfspanel.down('field[name=quota]').setValue(false);
|
||||
}
|
||||
rootfspanel.unprivileged = value;
|
||||
var hdsel = rootfspanel.down('#hdstorage');
|
||||
hdsel.fireEvent('change', hdsel, hdsel.getValue());
|
||||
}
|
||||
},
|
||||
fieldLabel: gettext('Unprivileged container')
|
||||
}
|
||||
],
|
||||
column2: column2,
|
||||
onGetValues: function(values) {
|
||||
delete values.confirmpw;
|
||||
if (!values.pool) {
|
||||
delete values.pool;
|
||||
}
|
||||
return values;
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'inputpanel',
|
||||
title: gettext('Template'),
|
||||
onlineHelp: 'pct_container_images',
|
||||
column1: [ tmplstoragesel, tmplsel]
|
||||
},
|
||||
rootfspanel,
|
||||
{
|
||||
xtype: 'pveLxcCPUInputPanel',
|
||||
title: gettext('CPU'),
|
||||
insideWizard: true
|
||||
},
|
||||
{
|
||||
xtype: 'pveLxcMemoryInputPanel',
|
||||
title: gettext('Memory'),
|
||||
insideWizard: true
|
||||
},
|
||||
networkpanel,
|
||||
{
|
||||
xtype: 'pveLxcDNSInputPanel',
|
||||
title: gettext('DNS'),
|
||||
insideWizard: true
|
||||
},
|
||||
{
|
||||
title: gettext('Confirm'),
|
||||
layout: 'fit',
|
||||
items: [
|
||||
{
|
||||
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) {
|
||||
if (key === 'delete' || key === 'tmplstorage') { // ignore
|
||||
return;
|
||||
}
|
||||
if (key === 'password') { // don't show pw
|
||||
return;
|
||||
}
|
||||
var html = Ext.htmlEncode(Ext.JSON.encode(value));
|
||||
data.push({ key: key, value: value });
|
||||
});
|
||||
summarystore.suspendEvents();
|
||||
summarystore.removeAll();
|
||||
summarystore.add(data);
|
||||
summarystore.sort();
|
||||
summarystore.resumeEvents();
|
||||
summarystore.fireEvent('refresh');
|
||||
}
|
||||
xtype: 'grid',
|
||||
store: {
|
||||
model: 'KeyValue',
|
||||
sorters: [{
|
||||
property : 'key',
|
||||
direction: 'ASC'
|
||||
}]
|
||||
},
|
||||
onSubmit: function() {
|
||||
var kv = me.getValues();
|
||||
delete kv['delete'];
|
||||
|
||||
var nodename = kv.nodename;
|
||||
delete kv.nodename;
|
||||
delete kv.tmplstorage;
|
||||
|
||||
if (!kv.password.length && kv['ssh-public-keys']) {
|
||||
delete kv.password;
|
||||
}
|
||||
|
||||
Proxmox.Utils.API2Request({
|
||||
url: '/nodes/' + nodename + '/lxc',
|
||||
waitMsgTarget: me,
|
||||
method: 'POST',
|
||||
params: kv,
|
||||
success: function(response, opts){
|
||||
var upid = response.result.data;
|
||||
|
||||
var win = Ext.create('Proxmox.window.TaskViewer', {
|
||||
upid: upid
|
||||
});
|
||||
win.show();
|
||||
me.close();
|
||||
},
|
||||
failure: function(response, opts) {
|
||||
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
|
||||
}
|
||||
});
|
||||
}
|
||||
columns: [
|
||||
{header: 'Key', width: 150, dataIndex: 'key'},
|
||||
{header: 'Value', flex: 1, dataIndex: 'value'}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
],
|
||||
listeners: {
|
||||
show: function(panel) {
|
||||
var wizard = this.up('window');
|
||||
var kv = wizard.getValues();
|
||||
var data = [];
|
||||
Ext.Object.each(kv, function(key, value) {
|
||||
if (key === 'delete' || key === 'tmplstorage') { // ignore
|
||||
return;
|
||||
}
|
||||
if (key === 'password') { // don't show pw
|
||||
return;
|
||||
}
|
||||
var html = Ext.htmlEncode(Ext.JSON.encode(value));
|
||||
data.push({ key: key, value: value });
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
var summarystore = panel.down('grid').getStore();
|
||||
summarystore.suspendEvents();
|
||||
summarystore.removeAll();
|
||||
summarystore.add(data);
|
||||
summarystore.sort();
|
||||
summarystore.resumeEvents();
|
||||
summarystore.fireEvent('refresh');
|
||||
}
|
||||
},
|
||||
onSubmit: function() {
|
||||
var wizard = this.up('window');
|
||||
var kv = wizard.getValues();
|
||||
delete kv['delete'];
|
||||
|
||||
var nodename = kv.nodename;
|
||||
delete kv.nodename;
|
||||
delete kv.tmplstorage;
|
||||
|
||||
if (!kv.password.length && kv['ssh-public-keys']) {
|
||||
delete kv.password;
|
||||
}
|
||||
|
||||
Proxmox.Utils.API2Request({
|
||||
url: '/nodes/' + nodename + '/lxc',
|
||||
waitMsgTarget: wizard,
|
||||
method: 'POST',
|
||||
params: kv,
|
||||
success: function(response, opts){
|
||||
var upid = response.result.data;
|
||||
|
||||
var win = Ext.create('Proxmox.window.TaskViewer', {
|
||||
upid: upid
|
||||
});
|
||||
win.show();
|
||||
wizard.close();
|
||||
},
|
||||
failure: function(response, opts) {
|
||||
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user