+Ext.define('PVE.window.GuestDiskReassign', {
+ extend: 'Proxmox.window.Edit',
+ mixins: ['Proxmox.Mixin.CBind'],
+
+ resizable: false,
+ modal: true,
+ width: 350,
+ border: false,
+ layout: 'fit',
+ showReset: false,
+ showProgress: true,
+ method: 'POST',
+
+ viewModel: {
+ data: {
+ mpType: '',
+ },
+ formulas: {
+ mpMaxCount: get => get('mpType') === 'mp'
+ ? PVE.Utils.mp_counts.mps - 1
+ : PVE.Utils.mp_counts.unused - 1,
+ },
+ },
+
+ cbindData: function() {
+ let me = this;
+ return {
+ vmid: me.vmid,
+ disk: me.disk,
+ isQemu: me.type === 'qemu',
+ nodename: me.nodename,
+ url: () => {
+ let endpoint = me.type === 'qemu' ? 'move_disk' : 'move_volume';
+ return `/nodes/${me.nodename}/${me.type}/${me.vmid}/${endpoint}`;
+ },
+ };
+ },
+
+ cbind: {
+ title: get => get('isQemu') ? gettext('Reassign disk') : gettext('Reassign volume'),
+ submitText: get => get('title'),
+ qemu: '{isQemu}',
+ url: '{url}',
+ },
+
+ getValues: function() {
+ let me = this;
+ let values = me.formPanel.getForm().getValues();
+
+ let params = {
+ vmid: me.vmid,
+ 'target-vmid': values.targetVmid,
+ };
+
+ params[me.qemu ? 'disk' : 'volume'] = me.disk;
+
+ if (me.qemu) {
+ params['target-disk'] = `${values.controller}${values.deviceid}`;
+ } else {
+ params['target-volume'] = `${values.mpType}${values.mpId}`;
+ }
+ return params;
+ },
+
+ controller: {
+ xclass: 'Ext.app.ViewController',
+
+ initViewModel: function(model) {
+ let view = this.getView();
+ let mpTypeValue = view.disk.match(/^unused\d+/) ? 'unused' : 'mp';
+ model.set('mpType', mpTypeValue);
+ },
+
+ onMpTypeChange: function(value) {
+ this.getView().getViewModel().set('mpType', value.getValue());
+ this.getView().lookup('mpIdSelector').validate();
+ },
+
+ onTargetVMChange: function(f, vmid) {
+ let me = this;
+ let view = me.getView();
+ let diskSelector = view.lookup('diskSelector');
+ if (!vmid) {
+ diskSelector.setVMConfig(null);
+ me.VMConfig = null;
+ return;
+ }
+
+ let type = view.qemu ? 'qemu' : 'lxc';
+
+ let url = `/nodes/${view.nodename}/${type}/${vmid}/config`;
+ Proxmox.Utils.API2Request({
+ url: url,
+ method: 'GET',
+ failure: response => Ext.Msg.alert(gettext('Error'), response.htmlStatus),
+ success: function(response, options) {
+ if (view.qemu) {
+ diskSelector.setVMConfig(response.result.data);
+ diskSelector.setDisabled(false);
+ } else {
+ let mpIdSelector = view.lookup('mpIdSelector');
+ let mpType = view.lookup('mpType');
+
+ view.VMConfig = response.result.data;
+
+ mpIdSelector.setValue(
+ PVE.Utils.nextFreeMP(
+ view.getViewModel().get('mpType'),
+ view.VMConfig,
+ ).id,
+ );
+
+ mpType.setDisabled(false);
+ mpIdSelector.setDisabled(false);
+ mpIdSelector.validate();
+ }
+ },
+ });
+ },
+ },
+
+ items: [
+ {
+ xtype: 'form',
+ reference: 'moveFormPanel',
+ border: false,
+ fieldDefaults: {
+ labelWidth: 100,
+ anchor: '100%',
+ },
+ items: [
+ {
+ xtype: 'displayfield',
+ name: 'sourceDisk',
+ fieldLabel: gettext('Source'),
+ cbind: {
+ name: get => get('isQemu') ? 'disk' : 'volume',
+ value: '{disk}',
+ },
+ allowBlank: false,
+ },
+ {
+ xtype: 'vmComboSelector',
+ reference: 'targetVMID',
+ name: 'targetVmid',
+ allowBlank: false,
+ fieldLabel: gettext('Target'),
+ bind: {
+ value: '{targetVMID}',
+ },
+ store: {
+ model: 'PVEResources',
+ autoLoad: true,
+ sorters: 'vmid',
+ cbind: {}, // for nested cbinds
+ filters: [
+ {
+ property: 'type',
+ cbind: {
+ value: get => get('isQemu') ? 'qemu' : 'lxc',
+ },
+ },
+ {
+ property: 'node',
+ cbind: {
+ value: '{nodename}',
+ },
+ },
+ {
+ property: 'vmid',
+ operator: '!=',
+ cbind: {
+ value: '{vmid}',
+ },
+ },
+ {
+ property: 'template',
+ value: 0,
+ },
+ ],
+ },
+ listeners: { change: 'onTargetVMChange' },
+ },
+ {
+ xtype: 'pveControllerSelector',
+ reference: 'diskSelector',
+ withUnused: true,
+ disabled: true,
+ cbind: {
+ hidden: '{!isQemu}',
+ },
+ },
+ {
+ xtype: 'container',
+ layout: 'hbox',
+ cbind: {
+ hidden: '{isQemu}',
+ disabled: '{isQemu}',
+ },
+ items: [
+ {
+ xtype: 'pmxDisplayEditField',
+ cbind: {
+ editable: get => !get('disk').match(/^unused\d+/),
+ value: get => get('disk').match(/^unused\d+/) ? 'unused' : 'mp',
+ },
+ disabled: true,
+ name: 'mpType',
+ reference: 'mpType',
+ fieldLabel: gettext('Add as'),
+ submitValue: true,
+ flex: 4,
+ editConfig: {
+ xtype: 'proxmoxKVComboBox',
+ name: 'mpTypeCombo',
+ reference: 'mpTypeCombo',
+ deleteEmpty: false,
+ cbind: {
+ hidden: '{isQemu}',
+ },
+ comboItems: [
+ ['mp', gettext('Mount Point')],
+ ['unused', gettext('Unused')],
+ ],
+ listeners: { change: 'onMpTypeChange' },
+ },
+ },
+ {
+ xtype: 'proxmoxintegerfield',
+ name: 'mpId',
+ reference: 'mpIdSelector',
+ minValue: 0,
+ flex: 1,
+ allowBlank: false,
+ validateOnChange: true,
+ disabled: true,
+ bind: {
+ maxValue: '{mpMaxCount}',
+ },
+ validator: function(value) {
+ let view = this.up('window');
+ let type = view.getViewModel().get('mpType');
+ if (Ext.isDefined(view.VMConfig[`${type}${value}`])) {
+ return "Mount point is already in use.";
+ }
+ return true;
+ },
+ },
+ ],
+ },
+ ],
+ },
+ ],
+
+ initComponent: function() {
+ let me = this;
+
+ if (!me.nodename) {
+ throw "no node name specified";
+ }
+
+ if (!me.vmid) {
+ throw "no VM ID specified";
+ }
+
+ if (!me.type) {
+ throw "no type specified";
+ }
+
+ me.callParent();
+ },
+});