]>
Commit | Line | Data |
---|---|---|
1 | Ext.define('PVE.window.GuestDiskReassign', { | |
2 | extend: 'Proxmox.window.Edit', | |
3 | mixins: ['Proxmox.Mixin.CBind'], | |
4 | ||
5 | resizable: false, | |
6 | modal: true, | |
7 | width: 350, | |
8 | border: false, | |
9 | layout: 'fit', | |
10 | showReset: false, | |
11 | showProgress: true, | |
12 | method: 'POST', | |
13 | ||
14 | viewModel: { | |
15 | data: { | |
16 | mpType: '', | |
17 | }, | |
18 | formulas: { | |
19 | mpMaxCount: get => get('mpType') === 'mp' | |
20 | ? PVE.Utils.mp_counts.mps - 1 | |
21 | : PVE.Utils.mp_counts.unused - 1, | |
22 | }, | |
23 | }, | |
24 | ||
25 | cbindData: function() { | |
26 | let me = this; | |
27 | return { | |
28 | vmid: me.vmid, | |
29 | disk: me.disk, | |
30 | isQemu: me.type === 'qemu', | |
31 | nodename: me.nodename, | |
32 | url: () => { | |
33 | let endpoint = me.type === 'qemu' ? 'move_disk' : 'move_volume'; | |
34 | return `/nodes/${me.nodename}/${me.type}/${me.vmid}/${endpoint}`; | |
35 | }, | |
36 | }; | |
37 | }, | |
38 | ||
39 | cbind: { | |
40 | title: get => get('isQemu') ? gettext('Reassign Disk') : gettext('Reassign Volume'), | |
41 | submitText: get => get('title'), | |
42 | qemu: '{isQemu}', | |
43 | url: '{url}', | |
44 | }, | |
45 | ||
46 | getValues: function() { | |
47 | let me = this; | |
48 | let values = me.formPanel.getForm().getValues(); | |
49 | ||
50 | let params = { | |
51 | vmid: me.vmid, | |
52 | 'target-vmid': values.targetVmid, | |
53 | }; | |
54 | ||
55 | params[me.qemu ? 'disk' : 'volume'] = me.disk; | |
56 | ||
57 | if (me.qemu) { | |
58 | params['target-disk'] = `${values.controller}${values.deviceid}`; | |
59 | } else { | |
60 | params['target-volume'] = `${values.mpType}${values.mpId}`; | |
61 | } | |
62 | return params; | |
63 | }, | |
64 | ||
65 | controller: { | |
66 | xclass: 'Ext.app.ViewController', | |
67 | ||
68 | initViewModel: function(model) { | |
69 | let view = this.getView(); | |
70 | let mpTypeValue = view.disk.match(/^unused\d+/) ? 'unused' : 'mp'; | |
71 | model.set('mpType', mpTypeValue); | |
72 | }, | |
73 | ||
74 | onMpTypeChange: function(value) { | |
75 | let view = this.getView(); | |
76 | view.getViewModel().set('mpType', value.getValue()); | |
77 | view.lookup('mpIdSelector').validate(); | |
78 | }, | |
79 | ||
80 | onTargetVMChange: function(f, vmid) { | |
81 | let me = this; | |
82 | let view = me.getView(); | |
83 | let diskSelector = view.lookup('diskSelector'); | |
84 | if (!vmid) { | |
85 | diskSelector.setVMConfig(null); | |
86 | me.VMConfig = null; | |
87 | return; | |
88 | } | |
89 | ||
90 | let url = `/nodes/${view.nodename}/${view.type}/${vmid}/config`; | |
91 | Proxmox.Utils.API2Request({ | |
92 | url: url, | |
93 | method: 'GET', | |
94 | failure: response => Ext.Msg.alert(gettext('Error'), response.htmlStatus), | |
95 | success: function({ result }, options) { | |
96 | if (view.qemu) { | |
97 | diskSelector.setVMConfig(result.data); | |
98 | diskSelector.setDisabled(false); | |
99 | } else { | |
100 | let mpIdSelector = view.lookup('mpIdSelector'); | |
101 | let mpType = view.lookup('mpType'); | |
102 | ||
103 | view.VMConfig = result.data; | |
104 | ||
105 | mpIdSelector.setValue( | |
106 | PVE.Utils.nextFreeMP( | |
107 | view.getViewModel().get('mpType'), | |
108 | view.VMConfig, | |
109 | ).id, | |
110 | ); | |
111 | ||
112 | mpType.setDisabled(false); | |
113 | mpIdSelector.setDisabled(false); | |
114 | mpIdSelector.validate(); | |
115 | } | |
116 | }, | |
117 | }); | |
118 | }, | |
119 | }, | |
120 | ||
121 | defaultFocus: 'sourceDisk', | |
122 | items: [ | |
123 | { | |
124 | xtype: 'displayfield', | |
125 | name: 'sourceDisk', | |
126 | fieldLabel: gettext('Source'), | |
127 | cbind: { | |
128 | name: get => get('isQemu') ? 'disk' : 'volume', | |
129 | value: '{disk}', | |
130 | }, | |
131 | allowBlank: false, | |
132 | }, | |
133 | { | |
134 | xtype: 'vmComboSelector', | |
135 | reference: 'targetVMID', | |
136 | name: 'targetVmid', | |
137 | allowBlank: false, | |
138 | fieldLabel: gettext('Target Guest'), | |
139 | bind: { | |
140 | value: '{targetVMID}', | |
141 | }, | |
142 | store: { | |
143 | model: 'PVEResources', | |
144 | autoLoad: true, | |
145 | sorters: 'vmid', | |
146 | cbind: {}, // for nested cbinds | |
147 | filters: [ | |
148 | { | |
149 | property: 'type', | |
150 | cbind: { value: '{type}' }, | |
151 | }, | |
152 | { | |
153 | property: 'node', | |
154 | cbind: { value: '{nodename}' }, | |
155 | }, | |
156 | // FIXME: remove, artificial restriction that doesn't gains us anything.. | |
157 | { | |
158 | property: 'vmid', | |
159 | operator: '!=', | |
160 | cbind: { value: '{vmid}' }, | |
161 | }, | |
162 | { | |
163 | property: 'template', | |
164 | value: 0, | |
165 | }, | |
166 | ], | |
167 | }, | |
168 | listeners: { change: 'onTargetVMChange' }, | |
169 | }, | |
170 | { | |
171 | xtype: 'pveControllerSelector', | |
172 | reference: 'diskSelector', | |
173 | withUnused: true, | |
174 | disabled: true, | |
175 | cbind: { | |
176 | hidden: '{!isQemu}', | |
177 | }, | |
178 | }, | |
179 | { | |
180 | xtype: 'container', | |
181 | layout: 'hbox', | |
182 | cbind: { | |
183 | hidden: '{isQemu}', | |
184 | disabled: '{isQemu}', | |
185 | }, | |
186 | items: [ | |
187 | { | |
188 | xtype: 'pmxDisplayEditField', | |
189 | cbind: { | |
190 | editable: get => !get('disk').match(/^unused\d+/), | |
191 | value: get => get('disk').match(/^unused\d+/) ? 'unused' : 'mp', | |
192 | }, | |
193 | disabled: true, | |
194 | name: 'mpType', | |
195 | reference: 'mpType', | |
196 | fieldLabel: gettext('Add as'), | |
197 | submitValue: true, | |
198 | flex: 4, | |
199 | editConfig: { | |
200 | xtype: 'proxmoxKVComboBox', | |
201 | name: 'mpTypeCombo', | |
202 | deleteEmpty: false, | |
203 | cbind: { | |
204 | hidden: '{isQemu}', | |
205 | }, | |
206 | comboItems: [ | |
207 | ['mp', gettext('Mount Point')], | |
208 | ['unused', gettext('Unused')], | |
209 | ], | |
210 | listeners: { change: 'onMpTypeChange' }, | |
211 | }, | |
212 | }, | |
213 | { | |
214 | xtype: 'proxmoxintegerfield', | |
215 | name: 'mpId', | |
216 | reference: 'mpIdSelector', | |
217 | minValue: 0, | |
218 | flex: 1, | |
219 | allowBlank: false, | |
220 | validateOnChange: true, | |
221 | disabled: true, | |
222 | bind: { | |
223 | maxValue: '{mpMaxCount}', | |
224 | }, | |
225 | validator: function(value) { | |
226 | let view = this.up('window'); | |
227 | let type = view.getViewModel().get('mpType'); | |
228 | if (Ext.isDefined(view.VMConfig[`${type}${value}`])) { | |
229 | return "Mount point is already in use."; | |
230 | } | |
231 | return true; | |
232 | }, | |
233 | }, | |
234 | ], | |
235 | }, | |
236 | ], | |
237 | ||
238 | initComponent: function() { | |
239 | let me = this; | |
240 | ||
241 | if (!me.nodename) { | |
242 | throw "no node name specified"; | |
243 | } | |
244 | ||
245 | if (!me.vmid) { | |
246 | throw "no VM ID specified"; | |
247 | } | |
248 | ||
249 | if (!me.type) { | |
250 | throw "no type specified"; | |
251 | } | |
252 | ||
253 | me.callParent(); | |
254 | }, | |
255 | }); |