]>
git.proxmox.com Git - pve-manager.git/blob - www/manager6/lxc/Resources.js
1 Ext
.define('PVE.lxc.RessourceView', {
2 extend
: 'Proxmox.grid.PendingObjectGrid',
3 alias
: ['widget.pveLxcRessourceView'],
5 onlineHelp
: 'pct_configuration',
7 renderKey: function(key
, metaData
, rec
, rowIndex
, colIndex
, store
) {
9 let rowdef
= me
.rows
[key
] || {};
11 let txt
= rowdef
.header
|| key
;
14 metaData
.tdAttr
= "valign=middle";
16 metaData
.tdCls
= rowdef
.tdCls
;
17 } else if (rowdef
.iconCls
) {
18 icon
= `<i class='pve-grid-fa fa fa-fw fa-${rowdef.iconCls}'></i>`;
19 metaData
.tdCls
+= " pve-itype-fa";
21 // only return icons in grid but not remove dialog
22 if (rowIndex
!== undefined) {
29 initComponent: function() {
33 var nodename
= me
.pveSelNode
.data
.node
;
35 throw "no node name specified";
38 var vmid
= me
.pveSelNode
.data
.vmid
;
40 throw "no VM ID specified";
43 var caps
= Ext
.state
.Manager
.get('GuiCap');
44 var diskCap
= caps
.vms
['VM.Config.Disk'];
46 var mpeditor
= caps
.vms
['VM.Config.Disk'] ? 'PVE.lxc.MountPointEdit' : undefined;
50 header
: gettext('Memory'),
51 editor
: caps
.vms
['VM.Config.Memory'] ? 'PVE.lxc.MemoryEdit' : undefined,
53 tdCls
: 'pmx-itype-icon-memory',
55 renderer: function(value
) {
56 return Proxmox
.Utils
.format_size(value
*1024*1024);
60 header
: gettext('Swap'),
61 editor
: caps
.vms
['VM.Config.Memory'] ? 'PVE.lxc.MemoryEdit' : undefined,
65 renderer: function(value
) {
66 return Proxmox
.Utils
.format_size(value
*1024*1024);
70 header
: gettext('Cores'),
71 editor
: caps
.vms
['VM.Config.CPU'] ? 'PVE.lxc.CPUEdit' : undefined,
73 tdCls
: 'pmx-itype-icon-processor',
75 renderer: function(value
) {
76 var cpulimit
= me
.getObjectValue('cpulimit');
77 var cpuunits
= me
.getObjectValue('cpuunits');
82 res
= gettext('unlimited');
86 res
+= ' [cpulimit=' + cpulimit
+ ']';
90 res
+= ' [cpuunits=' + cpuunits
+ ']';
96 header
: gettext('Root Disk'),
97 defaultValue
: Proxmox
.Utils
.noneText
,
113 PVE
.Utils
.forEachMP(function(bus
, i
) {
118 header
= gettext('Mount Point') + ' (' + confid
+ ')';
120 header
= gettext('Unused Disk') + ' ' + i
;
126 tdCls
: 'pve-itype-icon-storage',
132 var baseurl
= 'nodes/' + nodename
+ '/lxc/' + vmid
+ '/config';
134 me
.selModel
= Ext
.create('Ext.selection.RowModel', {});
136 var run_resize = function() {
137 var rec
= me
.selModel
.getSelection()[0];
142 var win
= Ext
.create('PVE.window.MPResize', {
151 var run_remove = function(b
, e
, rec
) {
152 Proxmox
.Utils
.API2Request({
153 url
: '/api2/extjs/' + baseurl
,
157 'delete': rec
.data
.key
,
159 failure: function(response
, opts
) {
160 Ext
.Msg
.alert('Error', response
.htmlStatus
);
165 let run_move = function() {
166 let rec
= me
.selModel
.getSelection()[0];
171 var win
= Ext
.create('PVE.window.HDMove', {
180 win
.on('destroy', me
.reload
, me
);
183 let run_reassign = function() {
184 let rec
= me
.selModel
.getSelection()[0];
189 Ext
.create('PVE.window.HDReassign', {
196 destroy
: () => me
.reload(),
201 var edit_btn
= new Proxmox
.button
.Button({
202 text
: gettext('Edit'),
203 selModel
: me
.selModel
,
205 enableFn: function(rec
) {
209 var rowdef
= rows
[rec
.data
.key
];
210 return !!rowdef
.editor
;
212 handler: function() { me
.run_editor(); },
215 var remove_btn
= new Proxmox
.button
.Button({
216 text
: gettext('Remove'),
217 defaultText
: gettext('Remove'),
218 altText
: gettext('Detach'),
219 selModel
: me
.selModel
,
222 confirmMsg: function(rec
) {
223 let warn
= Ext
.String
.format(gettext('Are you sure you want to remove entry {0}'));
224 if (this.text
=== this.altText
) {
225 warn
= gettext('Are you sure you want to detach entry {0}');
227 let rendered
= me
.renderKey(rec
.data
.key
, {}, rec
);
228 let msg
= Ext
.String
.format(warn
, `'${rendered}'`);
230 if (rec
.data
.key
.match(/^unused\d+$/)) {
231 msg
+= " " + gettext('This will permanently erase all data.');
237 render: function(btn
) {
238 // hack: calculate the max button width on first display to prevent the whole
239 // toolbar to move when we switch between the "Remove" and "Detach" labels
240 let def
= btn
.getSize().width
;
242 btn
.setText(btn
.altText
);
243 let alt
= btn
.getSize().width
;
245 btn
.setText(btn
.defaultText
);
247 let optimal
= alt
> def
? alt
: def
;
248 btn
.setSize({ width
: optimal
});
253 let move_menuitem
= new Ext
.menu
.Item({
254 text
: gettext('Move Storage'),
255 tooltip
: gettext('Move volume to another storage'),
256 iconCls
: 'fa fa-database',
257 selModel
: me
.selModel
,
261 let reassign_menuitem
= new Ext
.menu
.Item({
262 text
: gettext('Reassign Owner'),
263 tooltip
: gettext('Reassign volume to another CT'),
264 iconCls
: 'fa fa-cube',
265 handler
: run_reassign
,
266 reference
: 'reassing_item',
269 let resize_menuitem
= new Ext
.menu
.Item({
270 text
: gettext('Resize'),
271 iconCls
: 'fa fa-plus',
272 selModel
: me
.selModel
,
276 let volumeaction_btn
= new Proxmox
.button
.Button({
277 text
: gettext('Volume Action'),
288 var revert_btn
= new PVE
.button
.PendingRevert();
290 var set_button_status = function() {
291 var rec
= me
.selModel
.getSelection()[0];
295 remove_btn
.disable();
296 volumeaction_btn
.disable();
297 revert_btn
.disable();
300 var key
= rec
.data
.key
;
301 var value
= rec
.data
.value
;
302 var rowdef
= rows
[key
];
304 var pending
= rec
.data
.delete || me
.hasPendingChanges(key
);
305 let isRootFS
= key
=== 'rootfs';
306 let isDisk
= isRootFS
|| key
.match(/^(mp|unused)\d+/);
307 var isUnusedDisk
= key
.match(/^unused\d+/);
308 var isUsedDisk
= isDisk
&& !isUnusedDisk
;
310 var noedit
= rec
.data
.delete || !rowdef
.editor
;
311 if (!noedit
&& Proxmox
.UserName
!== 'root@pam' && key
.match(/^mp\d+$/)) {
312 var mp
= PVE
.Parser
.parseLxcMountPoint(value
);
313 if (mp
.type
!== 'volume') {
317 edit_btn
.setDisabled(noedit
);
319 volumeaction_btn
.setDisabled(!isDisk
|| !diskCap
);
320 move_menuitem
.setDisabled(isUnusedDisk
);
321 reassign_menuitem
.setDisabled(isRootFS
);
322 resize_menuitem
.setDisabled(isUnusedDisk
);
324 remove_btn
.setDisabled(!isDisk
|| isRootFS
|| !diskCap
|| pending
);
325 revert_btn
.setDisabled(!pending
);
327 remove_btn
.setText(isUsedDisk
? remove_btn
.altText
: remove_btn
.defaultText
);
330 var sorterFn = function(rec1
, rec2
) {
331 var v1
= rec1
.data
.key
;
332 var v2
= rec2
.data
.key
;
333 var g1
= rows
[v1
].group
|| 0;
334 var g2
= rows
[v2
].group
|| 0;
335 var order1
= rows
[v1
].order
|| 0;
336 var order2
= rows
[v2
].order
|| 0;
342 if (order1
- order2
!== 0) {
343 return order1
- order2
;
348 } else if (v1
< v2
) {
356 url
: "/api2/json/nodes/" + nodename
+ "/lxc/" + vmid
+ "/pending",
357 selModel
: me
.selModel
,
362 text
: gettext('Add'),
363 menu
: new Ext
.menu
.Menu({
366 text
: gettext('Mount Point'),
367 iconCls
: 'fa fa-fw fa-hdd-o black',
368 disabled
: !caps
.vms
['VM.Config.Disk'],
369 handler: function() {
370 Ext
.create('PVE.lxc.MountPointEdit', {
372 url
: `/api2/extjs/${baseurl}`,
373 unprivileged
: me
.getObjectValue('unprivileged'),
374 pveSelNode
: me
.pveSelNode
,
376 destroy
: () => me
.reload(),
392 pveSelNode
: me
.pveSelNode
,
393 url
: '/api2/extjs/' + baseurl
,
396 itemdblclick
: me
.run_editor
,
397 selectionchange
: set_button_status
,
403 me
.on('activate', me
.rstore
.startUpdate
);
404 me
.on('destroy', me
.rstore
.stopUpdate
);
405 me
.on('deactivate', me
.rstore
.stopUpdate
);
407 me
.mon(me
.getStore(), 'datachanged', function() {
411 Ext
.apply(me
.editorConfig
, { unprivileged
: me
.getObjectValue('unprivileged') });