]>
Commit | Line | Data |
---|---|---|
3bde324f | 1 | Ext.define('PVE.window.GuestDiskReassign', { |
a8d854af AL |
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: { | |
d72ad78b | 40 | title: get => get('isQemu') ? gettext('Reassign Disk') : gettext('Reassign Volume'), |
a8d854af AL |
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 | ||
2281ca32 | 122 | defaultFocus: 'sourceDisk', |
a8d854af AL |
123 | items: [ |
124 | { | |
14ea602f TL |
125 | xtype: 'displayfield', |
126 | name: 'sourceDisk', | |
127 | fieldLabel: gettext('Source'), | |
128 | cbind: { | |
129 | name: get => get('isQemu') ? 'disk' : 'volume', | |
130 | value: '{disk}', | |
131 | }, | |
132 | allowBlank: false, | |
133 | }, | |
134 | { | |
135 | xtype: 'vmComboSelector', | |
136 | reference: 'targetVMID', | |
137 | name: 'targetVmid', | |
138 | allowBlank: false, | |
d72ad78b | 139 | fieldLabel: gettext('Target Guest'), |
14ea602f TL |
140 | bind: { |
141 | value: '{targetVMID}', | |
142 | }, | |
143 | store: { | |
144 | model: 'PVEResources', | |
145 | autoLoad: true, | |
146 | sorters: 'vmid', | |
147 | cbind: {}, // for nested cbinds | |
148 | filters: [ | |
149 | { | |
150 | property: 'type', | |
151 | cbind: { | |
152 | value: get => get('isQemu') ? 'qemu' : 'lxc', | |
153 | }, | |
154 | }, | |
155 | { | |
156 | property: 'node', | |
157 | cbind: { | |
158 | value: '{nodename}', | |
159 | }, | |
160 | }, | |
161 | { | |
162 | property: 'vmid', | |
163 | operator: '!=', | |
164 | cbind: { | |
165 | value: '{vmid}', | |
166 | }, | |
167 | }, | |
168 | { | |
169 | property: 'template', | |
170 | value: 0, | |
171 | }, | |
172 | ], | |
173 | }, | |
174 | listeners: { change: 'onTargetVMChange' }, | |
175 | }, | |
176 | { | |
177 | xtype: 'pveControllerSelector', | |
178 | reference: 'diskSelector', | |
179 | withUnused: true, | |
180 | disabled: true, | |
181 | cbind: { | |
182 | hidden: '{!isQemu}', | |
183 | }, | |
184 | }, | |
185 | { | |
186 | xtype: 'container', | |
187 | layout: 'hbox', | |
188 | cbind: { | |
189 | hidden: '{isQemu}', | |
190 | disabled: '{isQemu}', | |
a8d854af AL |
191 | }, |
192 | items: [ | |
193 | { | |
14ea602f | 194 | xtype: 'pmxDisplayEditField', |
a8d854af | 195 | cbind: { |
14ea602f TL |
196 | editable: get => !get('disk').match(/^unused\d+/), |
197 | value: get => get('disk').match(/^unused\d+/) ? 'unused' : 'mp', | |
a8d854af | 198 | }, |
14ea602f TL |
199 | disabled: true, |
200 | name: 'mpType', | |
201 | reference: 'mpType', | |
202 | fieldLabel: gettext('Add as'), | |
203 | submitValue: true, | |
204 | flex: 4, | |
205 | editConfig: { | |
206 | xtype: 'proxmoxKVComboBox', | |
207 | name: 'mpTypeCombo', | |
208 | reference: 'mpTypeCombo', | |
209 | deleteEmpty: false, | |
210 | cbind: { | |
211 | hidden: '{isQemu}', | |
212 | }, | |
213 | comboItems: [ | |
214 | ['mp', gettext('Mount Point')], | |
215 | ['unused', gettext('Unused')], | |
a8d854af | 216 | ], |
14ea602f | 217 | listeners: { change: 'onMpTypeChange' }, |
a8d854af | 218 | }, |
a8d854af AL |
219 | }, |
220 | { | |
14ea602f TL |
221 | xtype: 'proxmoxintegerfield', |
222 | name: 'mpId', | |
223 | reference: 'mpIdSelector', | |
224 | minValue: 0, | |
225 | flex: 1, | |
226 | allowBlank: false, | |
227 | validateOnChange: true, | |
a8d854af | 228 | disabled: true, |
14ea602f TL |
229 | bind: { |
230 | maxValue: '{mpMaxCount}', | |
a8d854af | 231 | }, |
14ea602f TL |
232 | validator: function(value) { |
233 | let view = this.up('window'); | |
234 | let type = view.getViewModel().get('mpType'); | |
235 | if (Ext.isDefined(view.VMConfig[`${type}${value}`])) { | |
236 | return "Mount point is already in use."; | |
237 | } | |
238 | return true; | |
a8d854af | 239 | }, |
a8d854af AL |
240 | }, |
241 | ], | |
242 | }, | |
243 | ], | |
244 | ||
245 | initComponent: function() { | |
246 | let me = this; | |
247 | ||
248 | if (!me.nodename) { | |
249 | throw "no node name specified"; | |
250 | } | |
251 | ||
252 | if (!me.vmid) { | |
253 | throw "no VM ID specified"; | |
254 | } | |
255 | ||
256 | if (!me.type) { | |
257 | throw "no type specified"; | |
258 | } | |
259 | ||
260 | me.callParent(); | |
261 | }, | |
262 | }); |