]>
Commit | Line | Data |
---|---|---|
a8d854af AL |
1 | Ext.define('PVE.window.HDReassign', { |
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 | this.getView().getViewModel().set('mpType', value.getValue()); | |
76 | this.getView().lookup('mpIdSelector').validate(); | |
77 | }, | |
78 | ||
79 | onTargetVMChange: function(f, vmid) { | |
80 | let me = this; | |
81 | let view = me.getView(); | |
82 | let diskSelector = view.lookup('diskSelector'); | |
83 | if (!vmid) { | |
84 | diskSelector.setVMConfig(null); | |
85 | me.VMConfig = null; | |
86 | return; | |
87 | } | |
88 | ||
89 | let type = view.qemu ? 'qemu' : 'lxc'; | |
90 | ||
91 | let url = `/nodes/${view.nodename}/${type}/${vmid}/config`; | |
92 | Proxmox.Utils.API2Request({ | |
93 | url: url, | |
94 | method: 'GET', | |
95 | failure: response => Ext.Msg.alert(gettext('Error'), response.htmlStatus), | |
96 | success: function(response, options) { | |
97 | if (view.qemu) { | |
98 | diskSelector.setVMConfig(response.result.data); | |
99 | diskSelector.setDisabled(false); | |
100 | } else { | |
101 | let mpIdSelector = view.lookup('mpIdSelector'); | |
102 | let mpType = view.lookup('mpType'); | |
103 | ||
104 | view.VMConfig = response.result.data; | |
105 | ||
106 | mpIdSelector.setValue( | |
107 | PVE.Utils.nextFreeMP( | |
108 | view.getViewModel().get('mpType'), | |
109 | view.VMConfig, | |
110 | ).id, | |
111 | ); | |
112 | ||
113 | mpType.setDisabled(false); | |
114 | mpIdSelector.setDisabled(false); | |
115 | mpIdSelector.validate(); | |
116 | } | |
117 | }, | |
118 | }); | |
119 | }, | |
120 | }, | |
121 | ||
122 | items: [ | |
123 | { | |
124 | xtype: 'form', | |
125 | reference: 'moveFormPanel', | |
126 | border: false, | |
127 | fieldDefaults: { | |
128 | labelWidth: 100, | |
129 | anchor: '100%', | |
130 | }, | |
131 | items: [ | |
132 | { | |
133 | xtype: 'displayfield', | |
134 | name: 'sourceDisk', | |
135 | fieldLabel: gettext('Source'), | |
136 | cbind: { | |
137 | name: get => get('isQemu') ? 'disk' : 'volume', | |
138 | value: '{disk}', | |
139 | }, | |
140 | allowBlank: false, | |
141 | }, | |
142 | { | |
143 | xtype: 'vmComboSelector', | |
144 | reference: 'targetVMID', | |
145 | name: 'targetVmid', | |
146 | allowBlank: false, | |
147 | fieldLabel: gettext('Target'), | |
148 | bind: { | |
149 | value: '{targetVMID}', | |
150 | }, | |
151 | store: { | |
152 | model: 'PVEResources', | |
153 | autoLoad: true, | |
154 | sorters: 'vmid', | |
155 | cbind: {}, // for nested cbinds | |
156 | filters: [ | |
157 | { | |
158 | property: 'type', | |
159 | cbind: { | |
160 | value: get => get('isQemu') ? 'qemu' : 'lxc', | |
161 | }, | |
162 | }, | |
163 | { | |
164 | property: 'node', | |
165 | cbind: { | |
166 | value: '{nodename}', | |
167 | }, | |
168 | }, | |
169 | { | |
170 | property: 'vmid', | |
171 | operator: '!=', | |
172 | cbind: { | |
173 | value: '{vmid}', | |
174 | }, | |
175 | }, | |
176 | { | |
177 | property: 'template', | |
178 | value: 0, | |
179 | }, | |
180 | ], | |
181 | }, | |
182 | listeners: { change: 'onTargetVMChange' }, | |
183 | }, | |
184 | { | |
185 | xtype: 'pveControllerSelector', | |
186 | reference: 'diskSelector', | |
187 | withUnused: true, | |
188 | disabled: true, | |
189 | cbind: { | |
190 | hidden: '{!isQemu}', | |
191 | }, | |
192 | }, | |
193 | { | |
194 | xtype: 'container', | |
195 | layout: 'hbox', | |
196 | cbind: { | |
197 | hidden: '{isQemu}', | |
198 | disabled: '{isQemu}', | |
199 | }, | |
200 | items: [ | |
201 | { | |
202 | xtype: 'pmxDisplayEditField', | |
203 | cbind: { | |
204 | editable: get => !get('disk').match(/^unused\d+/), | |
205 | value: get => get('disk').match(/^unused\d+/) ? 'unused' : 'mp', | |
206 | }, | |
207 | disabled: true, | |
208 | name: 'mpType', | |
209 | reference: 'mpType', | |
210 | fieldLabel: gettext('Add as'), | |
211 | submitValue: true, | |
212 | flex: 4, | |
213 | editConfig: { | |
214 | xtype: 'proxmoxKVComboBox', | |
215 | name: 'mpTypeCombo', | |
216 | reference: 'mpTypeCombo', | |
217 | deleteEmpty: false, | |
218 | cbind: { | |
219 | hidden: '{isQemu}', | |
220 | }, | |
221 | comboItems: [ | |
222 | ['mp', gettext('Mount Point')], | |
223 | ['unused', gettext('Unused')], | |
224 | ], | |
225 | listeners: { change: 'onMpTypeChange' }, | |
226 | }, | |
227 | }, | |
228 | { | |
229 | xtype: 'proxmoxintegerfield', | |
230 | name: 'mpId', | |
231 | reference: 'mpIdSelector', | |
232 | minValue: 0, | |
233 | flex: 1, | |
234 | allowBlank: false, | |
235 | validateOnChange: true, | |
236 | disabled: true, | |
237 | bind: { | |
238 | maxValue: '{mpMaxCount}', | |
239 | }, | |
240 | validator: function(value) { | |
241 | let view = this.up('window'); | |
242 | let type = view.getViewModel().get('mpType'); | |
243 | if (Ext.isDefined(view.VMConfig[`${type}${value}`])) { | |
244 | return "Mount point is already in use."; | |
245 | } | |
246 | return true; | |
247 | }, | |
248 | }, | |
249 | ], | |
250 | }, | |
251 | ], | |
252 | }, | |
253 | ], | |
254 | ||
255 | initComponent: function() { | |
256 | let me = this; | |
257 | ||
258 | if (!me.nodename) { | |
259 | throw "no node name specified"; | |
260 | } | |
261 | ||
262 | if (!me.vmid) { | |
263 | throw "no VM ID specified"; | |
264 | } | |
265 | ||
266 | if (!me.type) { | |
267 | throw "no type specified"; | |
268 | } | |
269 | ||
270 | me.callParent(); | |
271 | }, | |
272 | }); |