]> git.proxmox.com Git - proxmox-widget-toolkit.git/blob - src/panel/DiskList.js
disk list: move title bar initialization to initComponent
[proxmox-widget-toolkit.git] / src / panel / DiskList.js
1 Ext.define('pmx-disk-list', {
2 extend: 'Ext.data.Model',
3 fields: [
4 'devpath', 'used',
5 { name: 'size', type: 'number' },
6 { name: 'osdid', type: 'number', defaultValue: -1 },
7 {
8 name: 'status',
9 convert: function(value, rec) {
10 if (value) return value;
11 if (rec.data.health) {
12 return rec.data.health;
13 }
14
15 if (rec.data.type === 'partition') {
16 return "";
17 }
18
19 return Proxmox.Utils.unknownText;
20 },
21 },
22 {
23 name: 'name',
24 convert: function(value, rec) {
25 if (value) return value;
26 if (rec.data.devpath) return rec.data.devpath;
27 return undefined;
28 },
29 },
30 {
31 name: 'disk-type',
32 convert: function(value, rec) {
33 if (value) return value;
34 if (rec.data.type) return rec.data.type;
35 return undefined;
36 },
37 },
38 'vendor', 'model', 'serial', 'rpm', 'type', 'wearout', 'health',
39 ],
40 idProperty: 'devpath',
41 });
42
43 Ext.define('Proxmox.DiskList', {
44 extend: 'Ext.tree.Panel',
45 alias: 'widget.pmxDiskList',
46
47 rootVisible: false,
48
49 emptyText: gettext('No Disks found'),
50
51 stateful: true,
52 stateId: 'tree-node-disks',
53
54 controller: {
55 xclass: 'Ext.app.ViewController',
56
57 reload: function() {
58 let me = this;
59 let view = me.getView();
60
61 let extraParams = {};
62 if (view.includePartitions) {
63 extraParams['include-partitions'] = 1;
64 }
65
66 let url = `${view.baseurl}/list`;
67 me.store.setProxy({
68 type: 'proxmox',
69 extraParams: extraParams,
70 url: url,
71 });
72 me.store.load();
73 },
74
75 openSmartWindow: function() {
76 let me = this;
77 let view = me.getView();
78 let selection = view.getSelection();
79 if (!selection || selection.length < 1) return;
80
81 let rec = selection[0];
82 Ext.create('Proxmox.window.DiskSmart', {
83 baseurl: view.baseurl,
84 dev: rec.data.name,
85 }).show();
86 },
87
88 initGPT: function() {
89 let me = this;
90 let view = me.getView();
91 let selection = view.getSelection();
92 if (!selection || selection.length < 1) return;
93
94 let rec = selection[0];
95 Proxmox.Utils.API2Request({
96 url: `${view.exturl}/initgpt`,
97 waitMsgTarget: view,
98 method: 'POST',
99 params: { disk: rec.data.name },
100 failure: function(response, options) {
101 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
102 },
103 success: function(response, options) {
104 var upid = response.result.data;
105 var win = Ext.create('Proxmox.window.TaskProgress', {
106 upid: upid,
107 taskDone: function() {
108 me.reload();
109 },
110 });
111 win.show();
112 },
113 });
114 },
115
116 init: function(view) {
117 let nodename = view.nodename || 'localhost';
118 view.baseurl = `/api2/json/nodes/${nodename}/disks`;
119 view.exturl = `/api2/extjs/nodes/${nodename}/disks`;
120
121 this.store = Ext.create('Ext.data.Store', {
122 model: 'pmx-disk-list',
123 });
124 this.store.on('load', this.onLoad, this);
125
126 Proxmox.Utils.monStoreErrors(view, this.store);
127 this.reload();
128 },
129
130 onLoad: function(store, records, success, operation) {
131 let me = this;
132 let view = this.getView();
133
134 if (!success) {
135 Proxmox.Utils.setErrorMask(
136 view,
137 Proxmox.Utils.getResponseErrorMessage(operation.getError()),
138 );
139 return;
140 }
141
142 let disks = {};
143
144 for (const item of records) {
145 let data = item.data;
146 data.leaf = true;
147 data.expanded = true;
148 data.children = [];
149 data.iconCls = 'fa fa-fw fa-hdd-o x-fa-tree';
150 if (!data.parent) {
151 disks[data.devpath] = data;
152 }
153 }
154 for (const item of records) {
155 let data = item.data;
156 if (data.parent) {
157 disks[data.parent].leaf = false;
158 disks[data.parent].children.push(data);
159 }
160 }
161
162 let children = [];
163 for (const [_, device] of Object.entries(disks)) {
164 children.push(device);
165 }
166
167 view.setRootNode({
168 expanded: true,
169 children: children,
170 });
171
172 Proxmox.Utils.setErrorMask(view, false);
173 },
174 },
175
176 renderDiskType: function(v) {
177 if (v === undefined) return Proxmox.Utils.unknownText;
178 switch (v) {
179 case 'ssd': return 'SSD';
180 case 'hdd': return 'Hard Disk';
181 case 'usb': return 'USB';
182 default: return v;
183 }
184 },
185
186 renderDiskUsage: function(v, metaData, rec) {
187 let extendedInfo = '';
188 if (rec) {
189 let types = [];
190 if (rec.data.osdid !== undefined && rec.data.osdid >= 0) {
191 types.push(`OSD.${rec.data.osdid.toString()}`);
192 }
193 if (rec.data.journals > 0) {
194 types.push('Journal');
195 }
196 if (rec.data.db > 0) {
197 types.push('DB');
198 }
199 if (rec.data.wal > 0) {
200 types.push('WAL');
201 }
202 if (types.length > 0) {
203 extendedInfo = `, Ceph (${types.join(', ')})`;
204 }
205 }
206 return v ? `${v}${extendedInfo}` : Proxmox.Utils.noText;
207 },
208
209 columns: [
210 {
211 xtype: 'treecolumn',
212 header: gettext('Device'),
213 width: 150,
214 sortable: true,
215 dataIndex: 'devpath',
216 },
217 {
218 header: gettext('Type'),
219 width: 80,
220 sortable: true,
221 dataIndex: 'disk-type',
222 renderer: function(v) {
223 let me = this;
224 return me.renderDiskType(v);
225 },
226 },
227 {
228 header: gettext('Usage'),
229 width: 150,
230 sortable: false,
231 renderer: function(v, metaData, rec) {
232 let me = this;
233 return me.renderDiskUsage(v, metaData, rec);
234 },
235 dataIndex: 'used',
236 },
237 {
238 header: gettext('Size'),
239 width: 100,
240 align: 'right',
241 sortable: true,
242 renderer: Proxmox.Utils.format_size,
243 dataIndex: 'size',
244 },
245 {
246 header: 'GPT',
247 width: 60,
248 align: 'right',
249 renderer: Proxmox.Utils.format_boolean,
250 dataIndex: 'gpt',
251 },
252 {
253 header: gettext('Vendor'),
254 width: 100,
255 sortable: true,
256 hidden: true,
257 renderer: Ext.String.htmlEncode,
258 dataIndex: 'vendor',
259 },
260 {
261 header: gettext('Model'),
262 width: 200,
263 sortable: true,
264 renderer: Ext.String.htmlEncode,
265 dataIndex: 'model',
266 },
267 {
268 header: gettext('Serial'),
269 width: 200,
270 sortable: true,
271 renderer: Ext.String.htmlEncode,
272 dataIndex: 'serial',
273 },
274 {
275 header: 'S.M.A.R.T.',
276 width: 100,
277 sortable: true,
278 renderer: Ext.String.htmlEncode,
279 dataIndex: 'status',
280 },
281 {
282 header: 'Wearout',
283 width: 90,
284 sortable: true,
285 align: 'right',
286 dataIndex: 'wearout',
287 renderer: function(value) {
288 if (Ext.isNumeric(value)) {
289 return (100 - value).toString() + '%';
290 }
291 return 'N/A';
292 },
293 },
294 ],
295
296 listeners: {
297 itemdblclick: 'openSmartWindow',
298 },
299
300 initComponent: function() {
301 let me = this;
302
303 let tbar = [
304 {
305 text: gettext('Reload'),
306 handler: 'reload',
307 },
308 {
309 xtype: 'proxmoxButton',
310 text: gettext('Show S.M.A.R.T. values'),
311 parentXType: 'treepanel',
312 disabled: true,
313 enableFn: function(rec) {
314 if (!rec || rec.data.parent) {
315 return false;
316 } else {
317 return true;
318 }
319 },
320 handler: 'openSmartWindow',
321 },
322 {
323 xtype: 'proxmoxButton',
324 text: gettext('Initialize Disk with GPT'),
325 parentXType: 'treepanel',
326 disabled: true,
327 enableFn: function(rec) {
328 if (!rec || rec.data.parent ||
329 (rec.data.used && rec.data.used !== 'unused')) {
330 return false;
331 } else {
332 return true;
333 }
334 },
335 handler: 'initGPT',
336 },
337 ];
338
339 me.tbar = tbar;
340
341 me.callParent();
342 },
343 });