]>
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;
48 const nodeInfo
= PVE
.data
.ResourceStore
.getNodes().find(node
=> node
.node
=== nodename
);
50 xtype
: 'pveLxcCPUEdit',
51 cgroupMode
: nodeInfo
['cgroup-mode'],
56 header
: gettext('Memory'),
57 editor
: caps
.vms
['VM.Config.Memory'] ? 'PVE.lxc.MemoryEdit' : undefined,
59 tdCls
: 'pmx-itype-icon-memory',
61 renderer: function(value
) {
62 return Proxmox
.Utils
.format_size(value
*1024*1024);
66 header
: gettext('Swap'),
67 editor
: caps
.vms
['VM.Config.Memory'] ? 'PVE.lxc.MemoryEdit' : undefined,
71 renderer: function(value
) {
72 return Proxmox
.Utils
.format_size(value
*1024*1024);
76 header
: gettext('Cores'),
77 editor
: caps
.vms
['VM.Config.CPU'] ? cpuEditor
: undefined,
79 tdCls
: 'pmx-itype-icon-processor',
81 renderer: function(value
) {
82 var cpulimit
= me
.getObjectValue('cpulimit');
83 var cpuunits
= me
.getObjectValue('cpuunits');
88 res
= gettext('unlimited');
92 res
+= ' [cpulimit=' + cpulimit
+ ']';
96 res
+= ' [cpuunits=' + cpuunits
+ ']';
102 header
: gettext('Root Disk'),
103 defaultValue
: Proxmox
.Utils
.noneText
,
119 PVE
.Utils
.forEachMP(function(bus
, i
) {
124 header
= gettext('Mount Point') + ' (' + confid
+ ')';
126 header
= gettext('Unused Disk') + ' ' + i
;
132 tdCls
: 'pve-itype-icon-storage',
138 var baseurl
= 'nodes/' + nodename
+ '/lxc/' + vmid
+ '/config';
140 me
.selModel
= Ext
.create('Ext.selection.RowModel', {});
142 var run_resize = function() {
143 var rec
= me
.selModel
.getSelection()[0];
148 var win
= Ext
.create('PVE.window.MPResize', {
157 var run_remove = function(b
, e
, rec
) {
158 Proxmox
.Utils
.API2Request({
159 url
: '/api2/extjs/' + baseurl
,
163 'delete': rec
.data
.key
,
165 failure: function(response
, opts
) {
166 Ext
.Msg
.alert('Error', response
.htmlStatus
);
171 let run_move = function() {
172 let rec
= me
.selModel
.getSelection()[0];
177 var win
= Ext
.create('PVE.window.HDMove', {
186 win
.on('destroy', me
.reload
, me
);
189 let run_reassign = function() {
190 let rec
= me
.selModel
.getSelection()[0];
195 Ext
.create('PVE.window.GuestDiskReassign', {
202 destroy
: () => me
.reload(),
207 var edit_btn
= new Proxmox
.button
.Button({
208 text
: gettext('Edit'),
209 selModel
: me
.selModel
,
211 enableFn: function(rec
) {
215 var rowdef
= rows
[rec
.data
.key
];
216 return !!rowdef
.editor
;
218 handler: function() { me
.run_editor(); },
221 var remove_btn
= new Proxmox
.button
.Button({
222 text
: gettext('Remove'),
223 defaultText
: gettext('Remove'),
224 altText
: gettext('Detach'),
225 selModel
: me
.selModel
,
228 confirmMsg: function(rec
) {
229 let warn
= Ext
.String
.format(gettext('Are you sure you want to remove entry {0}'));
230 if (this.text
=== this.altText
) {
231 warn
= gettext('Are you sure you want to detach entry {0}');
233 let rendered
= me
.renderKey(rec
.data
.key
, {}, rec
);
234 let msg
= Ext
.String
.format(warn
, `'${rendered}'`);
236 if (rec
.data
.key
.match(/^unused\d+$/)) {
237 msg
+= " " + gettext('This will permanently erase all data.');
243 render: function(btn
) {
244 // hack: calculate the max button width on first display to prevent the whole
245 // toolbar to move when we switch between the "Remove" and "Detach" labels
246 let def
= btn
.getSize().width
;
248 btn
.setText(btn
.altText
);
249 let alt
= btn
.getSize().width
;
251 btn
.setText(btn
.defaultText
);
253 let optimal
= alt
> def
? alt
: def
;
254 btn
.setSize({ width
: optimal
});
259 let move_menuitem
= new Ext
.menu
.Item({
260 text
: gettext('Move Storage'),
261 tooltip
: gettext('Move volume to another storage'),
262 iconCls
: 'fa fa-database',
263 selModel
: me
.selModel
,
267 let reassign_menuitem
= new Ext
.menu
.Item({
268 text
: gettext('Reassign Owner'),
269 tooltip
: gettext('Reassign volume to another CT'),
270 iconCls
: 'fa fa-cube',
271 handler
: run_reassign
,
272 reference
: 'reassing_item',
275 let resize_menuitem
= new Ext
.menu
.Item({
276 text
: gettext('Resize'),
277 iconCls
: 'fa fa-plus',
278 selModel
: me
.selModel
,
282 let volumeaction_btn
= new Proxmox
.button
.Button({
283 text
: gettext('Volume Action'),
294 let revert_btn
= new PVE
.button
.PendingRevert();
296 let set_button_status = function() {
297 let rec
= me
.selModel
.getSelection()[0];
301 remove_btn
.disable();
302 volumeaction_btn
.disable();
303 revert_btn
.disable();
306 let { key
, value
, 'delete': isDelete
} = rec
.data
;
307 let rowdef
= rows
[key
];
309 let pending
= isDelete
|| me
.hasPendingChanges(key
);
310 let isRootFS
= key
=== 'rootfs';
311 let isDisk
= isRootFS
|| key
.match(/^(mp|unused)\d+/);
312 let isUnusedDisk
= key
.match(/^unused\d+/);
313 let isUsedDisk
= isDisk
&& !isUnusedDisk
;
315 let noedit
= isDelete
|| !rowdef
.editor
;
316 if (!noedit
&& Proxmox
.UserName
!== 'root@pam' && key
.match(/^mp\d+$/)) {
317 let mp
= PVE
.Parser
.parseLxcMountPoint(value
);
318 if (mp
.type
!== 'volume') {
322 edit_btn
.setDisabled(noedit
);
324 volumeaction_btn
.setDisabled(!isDisk
|| !diskCap
);
325 move_menuitem
.setDisabled(isUnusedDisk
);
326 reassign_menuitem
.setDisabled(isRootFS
);
327 resize_menuitem
.setDisabled(isUnusedDisk
);
329 remove_btn
.setDisabled(!isDisk
|| isRootFS
|| !diskCap
|| pending
);
330 revert_btn
.setDisabled(!pending
);
332 remove_btn
.setText(isUsedDisk
? remove_btn
.altText
: remove_btn
.defaultText
);
335 let sorterFn = function(rec1
, rec2
) {
336 let v1
= rec1
.data
.key
, v2
= rec2
.data
.key
;
338 let g1
= rows
[v1
].group
|| 0, g2
= rows
[v2
].group
|| 0;
343 let order1
= rows
[v1
].order
|| 0, order2
= rows
[v2
].order
|| 0;
344 if (order1
- order2
!== 0) {
345 return order1
- order2
;
350 } else if (v1
< v2
) {
358 url
: `/api2/json/nodes/${nodename}/lxc/${vmid}/pending`,
359 selModel
: me
.selModel
,
364 text
: gettext('Add'),
365 menu
: new Ext
.menu
.Menu({
368 text
: gettext('Mount Point'),
369 iconCls
: 'fa fa-fw fa-hdd-o black',
370 disabled
: !caps
.vms
['VM.Config.Disk'],
371 handler: function() {
372 Ext
.create('PVE.lxc.MountPointEdit', {
374 url
: `/api2/extjs/${baseurl}`,
375 unprivileged
: me
.getObjectValue('unprivileged'),
376 pveSelNode
: me
.pveSelNode
,
378 destroy
: () => me
.reload(),
394 pveSelNode
: me
.pveSelNode
,
395 url
: '/api2/extjs/' + baseurl
,
398 itemdblclick
: me
.run_editor
,
399 selectionchange
: set_button_status
,
405 me
.on('activate', me
.rstore
.startUpdate
);
406 me
.on('destroy', me
.rstore
.stopUpdate
);
407 me
.on('deactivate', me
.rstore
.stopUpdate
);
409 me
.mon(me
.getStore(), 'datachanged', function() {
413 Ext
.apply(me
.editorConfig
, { unprivileged
: me
.getObjectValue('unprivileged') });