]>
Commit | Line | Data |
---|---|---|
7a2a8d56 DM |
1 | Ext.define('PVE.qemu.Monitor', { |
2 | extend: 'Ext.panel.Panel', | |
3 | ||
4 | alias: 'widget.pveQemuMonitor', | |
5 | ||
8b0bb902 TL |
6 | // start to trim saved command output once there are *both*, more than `commandLimit` commands |
7 | // executed and the total of saved in+output is over `lineLimit` lines; repeat by dropping one | |
8 | // full command output until either condition is false again | |
66937c62 DC |
9 | commandLimit: 10, |
10 | lineLimit: 5000, | |
7a2a8d56 | 11 | |
8058410f | 12 | initComponent: function() { |
7a2a8d56 DM |
13 | var me = this; |
14 | ||
15 | var nodename = me.pveSelNode.data.node; | |
16 | if (!nodename) { | |
17 | throw "no node name specified"; | |
18 | } | |
19 | ||
20 | var vmid = me.pveSelNode.data.vmid; | |
21 | if (!vmid) { | |
22 | throw "no VM ID specified"; | |
23 | } | |
24 | ||
7f0b90e9 DC |
25 | var history = []; |
26 | var histNum = -1; | |
66937c62 | 27 | let commands = []; |
7a2a8d56 DM |
28 | |
29 | var textbox = Ext.createWidget('panel', { | |
30 | region: 'center', | |
31 | xtype: 'panel', | |
32 | autoScroll: true, | |
33 | border: true, | |
34 | margins: '5 5 5 5', | |
f6710aac | 35 | bodyStyle: 'font-family: monospace;', |
7a2a8d56 DM |
36 | }); |
37 | ||
38 | var scrollToEnd = function() { | |
39 | var el = textbox.getTargetEl(); | |
40 | var dom = Ext.getDom(el); | |
41 | ||
42 | var clientHeight = dom.clientHeight; | |
43 | // BrowserBug: clientHeight reports 0 in IE9 StrictMode | |
44 | // Instead we are using offsetHeight and hardcoding borders | |
45 | if (Ext.isIE9 && Ext.isStrict) { | |
46 | clientHeight = dom.offsetHeight + 2; | |
47 | } | |
48 | dom.scrollTop = dom.scrollHeight - clientHeight; | |
49 | }; | |
50 | ||
51 | var refresh = function() { | |
66937c62 | 52 | textbox.update(`<pre>${commands.flat(2).join('\n')}</pre>`); |
7a2a8d56 DM |
53 | scrollToEnd(); |
54 | }; | |
55 | ||
66937c62 DC |
56 | let recordInput = line => { |
57 | commands.push([line]); | |
58 | ||
59 | // drop oldest commands and their output until we're not over both limits anymore | |
60 | while (commands.length > me.commandLimit && commands.flat(2).length > me.lineLimit) { | |
61 | commands.shift(); | |
7a2a8d56 DM |
62 | } |
63 | }; | |
64 | ||
66937c62 DC |
65 | let addResponse = lines => commands[commands.length - 1].push(lines); |
66 | ||
7a2a8d56 | 67 | var executeCmd = function(cmd) { |
66937c62 | 68 | recordInput("# " + Ext.htmlEncode(cmd), true); |
7f0b90e9 DC |
69 | if (cmd) { |
70 | history.unshift(cmd); | |
71 | if (history.length > 20) { | |
72 | history.splice(20); | |
73 | } | |
74 | } | |
75 | histNum = -1; | |
76 | ||
7a2a8d56 | 77 | refresh(); |
e7ade592 | 78 | Proxmox.Utils.API2Request({ |
7a2a8d56 DM |
79 | params: { command: cmd }, |
80 | url: '/nodes/' + nodename + '/qemu/' + vmid + "/monitor", | |
81 | method: 'POST', | |
82 | waitMsgTarget: me, | |
83 | success: function(response, opts) { | |
2a4971d8 | 84 | var res = response.result.data; |
66937c62 | 85 | addResponse(res.split('\n').map(line => Ext.htmlEncode(line))); |
7a2a8d56 DM |
86 | refresh(); |
87 | }, | |
88 | failure: function(response, opts) { | |
89 | Ext.Msg.alert('Error', response.htmlStatus); | |
f6710aac | 90 | }, |
7a2a8d56 DM |
91 | }); |
92 | }; | |
93 | ||
94 | Ext.apply(me, { | |
95 | layout: { type: 'border' }, | |
96 | border: false, | |
97 | items: [ | |
98 | textbox, | |
99 | { | |
100 | region: 'south', | |
8058410f | 101 | margins: '0 5 5 5', |
7a2a8d56 DM |
102 | border: false, |
103 | xtype: 'textfield', | |
104 | name: 'cmd', | |
105 | value: '', | |
106 | fieldStyle: 'font-family: monospace;', | |
107 | allowBlank: true, | |
108 | listeners: { | |
109 | afterrender: function(f) { | |
110 | f.focus(false); | |
66937c62 | 111 | recordInput("Type 'help' for help."); |
7a2a8d56 DM |
112 | refresh(); |
113 | }, | |
114 | specialkey: function(f, e) { | |
7f0b90e9 DC |
115 | var key = e.getKey(); |
116 | switch (key) { | |
117 | case e.ENTER: | |
118 | var cmd = f.getValue(); | |
119 | f.setValue(''); | |
120 | executeCmd(cmd); | |
121 | break; | |
122 | case e.PAGE_UP: | |
123 | textbox.scrollBy(0, -0.9*textbox.getHeight(), false); | |
124 | break; | |
125 | case e.PAGE_DOWN: | |
126 | textbox.scrollBy(0, 0.9*textbox.getHeight(), false); | |
127 | break; | |
128 | case e.UP: | |
129 | if (histNum + 1 < history.length) { | |
130 | f.setValue(history[++histNum]); | |
131 | } | |
132 | e.preventDefault(); | |
133 | break; | |
134 | case e.DOWN: | |
135 | if (histNum > 0) { | |
136 | f.setValue(history[--histNum]); | |
137 | } | |
138 | e.preventDefault(); | |
139 | break; | |
140 | default: | |
141 | break; | |
7a2a8d56 | 142 | } |
f6710aac TL |
143 | }, |
144 | }, | |
145 | }, | |
7a2a8d56 DM |
146 | ], |
147 | listeners: { | |
148 | show: function() { | |
149 | var field = me.query('textfield[name="cmd"]')[0]; | |
150 | field.focus(false, true); | |
f6710aac TL |
151 | }, |
152 | }, | |
2a4971d8 | 153 | }); |
7a2a8d56 DM |
154 | |
155 | me.callParent(); | |
f6710aac | 156 | }, |
7a2a8d56 | 157 | }); |