]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/panel/MultiDiskEdit.js
ui: container guest status: show distro logo and name in summary header
[pve-manager.git] / www / manager6 / panel / MultiDiskEdit.js
CommitLineData
5f219fd3
DC
1Ext.define('PVE.panel.MultiDiskPanel', {
2 extend: 'Ext.panel.Panel',
3
4 setNodename: function(nodename) {
5 this.items.each((panel) => panel.setNodename(nodename));
6 },
7
8 border: false,
9 bodyBorder: false,
10
11 layout: 'card',
12
13 controller: {
14 xclass: 'Ext.app.ViewController',
15
16 vmconfig: {},
17
18 onAdd: function() {
19 let me = this;
20 me.lookup('addButton').setDisabled(true);
21 me.addDisk();
22 let count = me.lookup('grid').getStore().getCount() + 1; // +1 is from ide2
23 me.lookup('addButton').setDisabled(count >= me.maxCount);
24 },
25
26 getNextFreeDisk: function(vmconfig) {
27 throw "implement in subclass";
28 },
29
30 addPanel: function(itemId, vmconfig, nextFreeDisk) {
31 throw "implement in subclass";
32 },
33
34 // define in subclass
35 diskSorter: undefined,
36
37 addDisk: function() {
38 let me = this;
39 let grid = me.lookup('grid');
40 let store = grid.getStore();
41
42 // get free disk id
43 let vmconfig = me.getVMConfig(true);
44 let nextFreeDisk = me.getNextFreeDisk(vmconfig);
45 if (!nextFreeDisk) {
46 return;
47 }
48
49 // add store entry + panel
50 let itemId = 'disk-card-' + ++Ext.idSeed;
51 let rec = store.add({
52 name: nextFreeDisk.confid,
53 itemId,
54 })[0];
55
56 let panel = me.addPanel(itemId, vmconfig, nextFreeDisk);
57 panel.updateVMConfig(vmconfig);
58
59 // we need to setup a validitychange handler, so that we can show
60 // that a disk has invalid fields
61 let fields = panel.query('field');
62 fields.forEach((el) => el.on('validitychange', () => {
63 let valid = fields.every((field) => field.isValid());
64 rec.set('valid', valid);
65 me.checkValidity();
66 }));
67
68 store.sort(me.diskSorter);
69
70 // select if the panel added is the only one
71 if (store.getCount() === 1) {
72 grid.getSelectionModel().select(0, false);
73 }
74 },
75
76 getBaseVMConfig: function() {
77 throw "implement in subclass";
78 },
79
80 getVMConfig: function(all) {
81 let me = this;
82
83 let vmconfig = me.getBaseVMConfig();
84
85 me.lookup('grid').getStore().each((rec) => {
86 if (all || rec.get('valid')) {
87 vmconfig[rec.get('name')] = rec.get('itemId');
88 }
89 });
90
91 return vmconfig;
92 },
93
94 checkValidity: function() {
95 let me = this;
96 let valid = me.lookup('grid').getStore().findExact('valid', false) === -1;
97 me.lookup('validationfield').setValue(valid);
98 },
99
100 updateVMConfig: function() {
101 let me = this;
102 let view = me.getView();
103 let grid = me.lookup('grid');
104 let store = grid.getStore();
105
106 let vmconfig = me.getVMConfig();
107
108 let valid = true;
109
110 store.each((rec) => {
111 let itemId = rec.get('itemId');
112 let name = rec.get('name');
113 let panel = view.getComponent(itemId);
114 if (!panel) {
115 throw "unexpected missing panel";
116 }
117
118 // copy config for each panel and remote its own id
119 let panel_vmconfig = Ext.apply({}, vmconfig);
120 if (panel_vmconfig[name] === itemId) {
121 delete panel_vmconfig[name];
122 }
123
124 if (!rec.get('valid')) {
125 valid = false;
126 }
127
128 panel.updateVMConfig(panel_vmconfig);
129 });
130
131 me.lookup('validationfield').setValue(valid);
132
133 return vmconfig;
134 },
135
136 onChange: function(panel, newVal) {
137 let me = this;
138 let store = me.lookup('grid').getStore();
139
140 let el = store.findRecord('itemId', panel.itemId, 0, false, true, true);
141 if (el.get('name') === newVal) {
142 // do not update if there was no change
143 return;
144 }
145
146 el.set('name', newVal);
147 el.commit();
148
149 store.sort(me.diskSorter);
150
151 // so that it happens after the layouting
152 setTimeout(function() {
153 me.updateVMConfig();
154 }, 10);
155 },
156
157 onRemove: function(tableview, rowIndex, colIndex, item, event, record) {
158 let me = this;
159 let grid = me.lookup('grid');
160 let store = grid.getStore();
161 let removed_idx = store.indexOf(record);
162
163 let selection = grid.getSelection()[0];
164 let selected_idx = store.indexOf(selection);
165
166 if (selected_idx === removed_idx) {
167 let newidx = store.getCount() > removed_idx + 1 ? removed_idx + 1: removed_idx - 1;
168 grid.getSelectionModel().select(newidx, false);
169 }
170
171 store.remove(record);
172 me.getView().remove(record.get('itemId'));
173 me.lookup('addButton').setDisabled(false);
174 me.updateVMConfig();
175 me.checkValidity();
176 },
177
178 onSelectionChange: function(grid, selection) {
179 let me = this;
180 if (!selection || selection.length < 1) {
181 return;
182 }
183
184 me.getView().setActiveItem(selection[0].data.itemId);
185 },
186
187 control: {
188 'inputpanel': {
189 diskidchange: 'onChange',
190 },
191 'grid[reference=grid]': {
192 selectionchange: 'onSelectionChange',
193 },
194 },
195
196 init: function(view) {
197 let me = this;
198 me.onAdd();
199 me.lookup('grid').getSelectionModel().select(0, false);
200 },
201 },
202
203 dockedItems: [
204 {
205 xtype: 'container',
206 layout: {
207 type: 'vbox',
208 align: 'stretch',
209 },
210 dock: 'left',
211 border: false,
212 width: 130,
213 items: [
214 {
215 xtype: 'grid',
216 hideHeaders: true,
217 reference: 'grid',
218 flex: 1,
219 emptyText: gettext('No Disks'),
220 margin: '0 0 5 0',
221 store: {
222 fields: ['name', 'itemId', 'valid'],
223 data: [],
224 },
225 columns: [
226 {
227 dataIndex: 'name',
228 renderer: function(val, md, rec) {
229 let warn = '';
230 if (!rec.get('valid')) {
231 warn = ' <i class="fa warning fa-warning"></i>';
232 }
233 return val + warn;
234 },
235 flex: 1,
236 },
237 {
238 xtype: 'actioncolumn',
239 width: 30,
240 align: 'center',
241 menuDisabled: true,
242 items: [
243 {
244 iconCls: 'x-fa fa-trash critical',
245 tooltip: 'Delete',
246 handler: 'onRemove',
247 isActionDisabled: 'deleteDisabled',
248 },
249 ],
250 },
251 ],
252 },
253 {
254 xtype: 'button',
255 reference: 'addButton',
256 text: gettext('Add'),
257 iconCls: 'fa fa-plus-circle',
258 handler: 'onAdd',
259 },
260 {
261 // dummy field to control wizard validation
262 xtype: 'textfield',
263 hidden: true,
264 reference: 'validationfield',
265 submitValue: false,
266 value: true,
267 validator: (val) => !!val,
268 },
269 ],
270 },
271 ],
272});