]> git.proxmox.com Git - pve-manager.git/blob - www/manager6/lxc/Config.js
ui: {lxc, qemu}/Config: show Tags and make them editable
[pve-manager.git] / www / manager6 / lxc / Config.js
1 Ext.define('PVE.lxc.Config', {
2 extend: 'PVE.panel.Config',
3 alias: 'widget.pveLXCConfig',
4
5 onlineHelp: 'chapter_pct',
6
7 userCls: 'proxmox-tags-full',
8
9 initComponent: function() {
10 var me = this;
11 var vm = me.pveSelNode.data;
12
13 var nodename = vm.node;
14 if (!nodename) {
15 throw "no node name specified";
16 }
17
18 var vmid = vm.vmid;
19 if (!vmid) {
20 throw "no VM ID specified";
21 }
22
23 var template = !!vm.template;
24
25 var running = !!vm.uptime;
26
27 var caps = Ext.state.Manager.get('GuiCap');
28
29 var base_url = '/nodes/' + nodename + '/lxc/' + vmid;
30
31 me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
32 url: '/api2/json' + base_url + '/status/current',
33 interval: 1000,
34 });
35
36 var vm_command = function(cmd, params) {
37 Proxmox.Utils.API2Request({
38 params: params,
39 url: base_url + "/status/" + cmd,
40 waitMsgTarget: me,
41 method: 'POST',
42 failure: function(response, opts) {
43 Ext.Msg.alert('Error', response.htmlStatus);
44 },
45 });
46 };
47
48 var startBtn = Ext.create('Ext.Button', {
49 text: gettext('Start'),
50 disabled: !caps.vms['VM.PowerMgmt'] || running,
51 hidden: template,
52 handler: function() {
53 vm_command('start');
54 },
55 iconCls: 'fa fa-play',
56 });
57
58 var shutdownBtn = Ext.create('PVE.button.Split', {
59 text: gettext('Shutdown'),
60 disabled: !caps.vms['VM.PowerMgmt'] || !running,
61 hidden: template,
62 confirmMsg: Proxmox.Utils.format_task_description('vzshutdown', vmid),
63 handler: function() {
64 vm_command('shutdown');
65 },
66 menu: {
67 items: [{
68 text: gettext('Reboot'),
69 disabled: !caps.vms['VM.PowerMgmt'],
70 confirmMsg: Proxmox.Utils.format_task_description('vzreboot', vmid),
71 tooltip: Ext.String.format(gettext('Reboot {0}'), 'CT'),
72 handler: function() {
73 vm_command("reboot");
74 },
75 iconCls: 'fa fa-refresh',
76 },
77 {
78 text: gettext('Stop'),
79 disabled: !caps.vms['VM.PowerMgmt'],
80 confirmMsg: Proxmox.Utils.format_task_description('vzstop', vmid),
81 tooltip: Ext.String.format(gettext('Stop {0} immediately'), 'CT'),
82 dangerous: true,
83 handler: function() {
84 vm_command("stop");
85 },
86 iconCls: 'fa fa-stop',
87 }],
88 },
89 iconCls: 'fa fa-power-off',
90 });
91
92 var migrateBtn = Ext.create('Ext.Button', {
93 text: gettext('Migrate'),
94 disabled: !caps.vms['VM.Migrate'],
95 hidden: PVE.data.ResourceStore.getNodes().length < 2,
96 handler: function() {
97 var win = Ext.create('PVE.window.Migrate', {
98 vmtype: 'lxc',
99 nodename: nodename,
100 vmid: vmid,
101 });
102 win.show();
103 },
104 iconCls: 'fa fa-send-o',
105 });
106
107 var moreBtn = Ext.create('Proxmox.button.Button', {
108 text: gettext('More'),
109 menu: {
110 items: [
111 {
112 text: gettext('Clone'),
113 iconCls: 'fa fa-fw fa-clone',
114 hidden: !caps.vms['VM.Clone'],
115 handler: function() {
116 PVE.window.Clone.wrap(nodename, vmid, template, 'lxc');
117 },
118 },
119 {
120 text: gettext('Convert to template'),
121 disabled: template,
122 xtype: 'pveMenuItem',
123 iconCls: 'fa fa-fw fa-file-o',
124 hidden: !caps.vms['VM.Allocate'],
125 confirmMsg: Proxmox.Utils.format_task_description('vztemplate', vmid),
126 handler: function() {
127 Proxmox.Utils.API2Request({
128 url: base_url + '/template',
129 waitMsgTarget: me,
130 method: 'POST',
131 failure: function(response, opts) {
132 Ext.Msg.alert('Error', response.htmlStatus);
133 },
134 });
135 },
136 },
137 {
138 iconCls: 'fa fa-heartbeat ',
139 hidden: !caps.nodes['Sys.Console'],
140 text: gettext('Manage HA'),
141 handler: function() {
142 var ha = vm.hastate;
143 Ext.create('PVE.ha.VMResourceEdit', {
144 vmid: vmid,
145 guestType: 'ct',
146 isCreate: !ha || ha === 'unmanaged',
147 }).show();
148 },
149 },
150 {
151 text: gettext('Remove'),
152 disabled: !caps.vms['VM.Allocate'],
153 itemId: 'removeBtn',
154 handler: function() {
155 Ext.create('PVE.window.SafeDestroyGuest', {
156 url: base_url,
157 item: { type: 'CT', id: vmid },
158 taskName: 'vzdestroy',
159 }).show();
160 },
161 iconCls: 'fa fa-trash-o',
162 },
163 ],
164 },
165 });
166
167 var consoleBtn = Ext.create('PVE.button.ConsoleButton', {
168 disabled: !caps.vms['VM.Console'],
169 consoleType: 'lxc',
170 consoleName: vm.name,
171 hidden: template,
172 nodename: nodename,
173 vmid: vmid,
174 });
175
176 var statusTxt = Ext.create('Ext.toolbar.TextItem', {
177 data: {
178 lock: undefined,
179 },
180 tpl: [
181 '<tpl if="lock">',
182 '<i class="fa fa-lg fa-lock"></i> ({lock})',
183 '</tpl>',
184 ],
185 });
186
187 let tagsContainer = Ext.create('PVE.panel.TagEditContainer', {
188 tags: vm.tags,
189 listeners: {
190 change: function(tags) {
191 Proxmox.Utils.API2Request({
192 url: base_url + '/config',
193 method: 'PUT',
194 params: {
195 tags,
196 },
197 success: function() {
198 me.statusStore.load();
199 },
200 failure: function(response) {
201 Ext.Msg.alert('Error', response.htmlStatus);
202 me.statusStore.load();
203 },
204 });
205 },
206 },
207 });
208
209 Ext.apply(me, {
210 title: Ext.String.format(gettext("Container {0} on node '{1}'"), vm.text, nodename),
211 hstateid: 'lxctab',
212 tbarSpacing: false,
213 tbar: [statusTxt, tagsContainer, '->', startBtn, shutdownBtn, migrateBtn, consoleBtn, moreBtn],
214 defaults: { statusStore: me.statusStore },
215 items: [
216 {
217 title: gettext('Summary'),
218 xtype: 'pveGuestSummary',
219 iconCls: 'fa fa-book',
220 itemId: 'summary',
221 },
222 ],
223 });
224
225 if (caps.vms['VM.Console'] && !template) {
226 me.items.push(
227 {
228 title: gettext('Console'),
229 itemId: 'consolejs',
230 iconCls: 'fa fa-terminal',
231 xtype: 'pveNoVncConsole',
232 vmid: vmid,
233 consoleType: 'lxc',
234 xtermjs: true,
235 nodename: nodename,
236 },
237 );
238 }
239
240 me.items.push(
241 {
242 title: gettext('Resources'),
243 itemId: 'resources',
244 expandedOnInit: true,
245 iconCls: 'fa fa-cube',
246 xtype: 'pveLxcRessourceView',
247 },
248 {
249 title: gettext('Network'),
250 iconCls: 'fa fa-exchange',
251 itemId: 'network',
252 xtype: 'pveLxcNetworkView',
253 },
254 {
255 title: gettext('DNS'),
256 iconCls: 'fa fa-globe',
257 itemId: 'dns',
258 xtype: 'pveLxcDNS',
259 },
260 {
261 title: gettext('Options'),
262 itemId: 'options',
263 iconCls: 'fa fa-gear',
264 xtype: 'pveLxcOptions',
265 },
266 {
267 title: gettext('Task History'),
268 itemId: 'tasks',
269 iconCls: 'fa fa-list-alt',
270 xtype: 'proxmoxNodeTasks',
271 nodename: nodename,
272 preFilter: {
273 vmid,
274 },
275 },
276 );
277
278 if (caps.vms['VM.Backup']) {
279 me.items.push({
280 title: gettext('Backup'),
281 iconCls: 'fa fa-floppy-o',
282 xtype: 'pveBackupView',
283 itemId: 'backup',
284 },
285 {
286 title: gettext('Replication'),
287 iconCls: 'fa fa-retweet',
288 xtype: 'pveReplicaView',
289 itemId: 'replication',
290 });
291 }
292
293 if ((caps.vms['VM.Snapshot'] || caps.vms['VM.Snapshot.Rollback'] ||
294 caps.vms['VM.Audit']) && !template) {
295 me.items.push({
296 title: gettext('Snapshots'),
297 iconCls: 'fa fa-history',
298 xtype: 'pveGuestSnapshotTree',
299 type: 'lxc',
300 itemId: 'snapshot',
301 });
302 }
303
304 if (caps.vms['VM.Console']) {
305 me.items.push(
306 {
307 xtype: 'pveFirewallRules',
308 title: gettext('Firewall'),
309 iconCls: 'fa fa-shield',
310 allow_iface: true,
311 base_url: base_url + '/firewall/rules',
312 list_refs_url: base_url + '/firewall/refs',
313 itemId: 'firewall',
314 },
315 {
316 xtype: 'pveFirewallOptions',
317 groups: ['firewall'],
318 iconCls: 'fa fa-gear',
319 onlineHelp: 'pve_firewall_vm_container_configuration',
320 title: gettext('Options'),
321 base_url: base_url + '/firewall/options',
322 fwtype: 'vm',
323 itemId: 'firewall-options',
324 },
325 {
326 xtype: 'pveFirewallAliases',
327 title: gettext('Alias'),
328 groups: ['firewall'],
329 iconCls: 'fa fa-external-link',
330 base_url: base_url + '/firewall/aliases',
331 itemId: 'firewall-aliases',
332 },
333 {
334 xtype: 'pveIPSet',
335 title: gettext('IPSet'),
336 groups: ['firewall'],
337 iconCls: 'fa fa-list-ol',
338 base_url: base_url + '/firewall/ipset',
339 list_refs_url: base_url + '/firewall/refs',
340 itemId: 'firewall-ipset',
341 },
342 {
343 title: gettext('Log'),
344 groups: ['firewall'],
345 iconCls: 'fa fa-list',
346 onlineHelp: 'chapter_pve_firewall',
347 itemId: 'firewall-fwlog',
348 xtype: 'proxmoxLogView',
349 url: '/api2/extjs' + base_url + '/firewall/log',
350 },
351 );
352 }
353
354 if (caps.vms['Permissions.Modify']) {
355 me.items.push({
356 xtype: 'pveACLView',
357 title: gettext('Permissions'),
358 itemId: 'permissions',
359 iconCls: 'fa fa-unlock',
360 path: '/vms/' + vmid,
361 });
362 }
363
364 me.callParent();
365
366 var prevStatus = 'unknown';
367 me.mon(me.statusStore, 'load', function(s, records, success) {
368 var status;
369 var lock;
370 var rec;
371
372 if (!success) {
373 status = 'unknown';
374 } else {
375 rec = s.data.get('status');
376 status = rec ? rec.data.value : 'unknown';
377 rec = s.data.get('template');
378 template = rec ? rec.data.value : false;
379 rec = s.data.get('lock');
380 lock = rec ? rec.data.value : undefined;
381 }
382
383 statusTxt.update({ lock: lock });
384
385 rec = s.data.get('tags');
386 tagsContainer.loadTags(rec?.data?.value);
387
388 startBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status === 'running' || template);
389 shutdownBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status !== 'running');
390 me.down('#removeBtn').setDisabled(!caps.vms['VM.Allocate'] || status !== 'stopped');
391 consoleBtn.setDisabled(template);
392
393 if (prevStatus === 'stopped' && status === 'running') {
394 let con = me.down('#consolejs');
395 if (con) {
396 con.reload();
397 }
398 }
399
400 prevStatus = status;
401 });
402
403 me.on('afterrender', function() {
404 me.statusStore.startUpdate();
405 });
406
407 me.on('destroy', function() {
408 me.statusStore.stopUpdate();
409 });
410 },
411 });