]> git.proxmox.com Git - proxmox-widget-toolkit.git/blob - src/panel/DiskList.js
panel/DiskList: return empty text for status on partitions
[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 tbar: [
177 {
178 text: gettext('Reload'),
179 handler: 'reload',
180 },
181 {
182 xtype: 'proxmoxButton',
183 text: gettext('Show S.M.A.R.T. values'),
184 parentXType: 'treepanel',
185 disabled: true,
186 enableFn: function(rec) {
187 if (!rec || rec.data.parent) {
188 return false;
189 } else {
190 return true;
191 }
192 },
193 handler: 'openSmartWindow',
194 },
195 {
196 xtype: 'proxmoxButton',
197 text: gettext('Initialize Disk with GPT'),
198 parentXType: 'treepanel',
199 disabled: true,
200 enableFn: function(rec) {
201 if (!rec || rec.data.parent ||
202 (rec.data.used && rec.data.used !== 'unused')) {
203 return false;
204 } else {
205 return true;
206 }
207 },
208 handler: 'initGPT',
209 },
210 ],
211
212 columns: [
213 {
214 xtype: 'treecolumn',
215 header: gettext('Device'),
216 width: 150,
217 sortable: true,
218 dataIndex: 'devpath',
219 },
220 {
221 header: gettext('Type'),
222 width: 80,
223 sortable: true,
224 dataIndex: 'disk-type',
225 renderer: function(v) {
226 if (v === undefined) return Proxmox.Utils.unknownText;
227 switch (v) {
228 case 'ssd': return 'SSD';
229 case 'hdd': return 'Hard Disk';
230 case 'usb': return 'USB';
231 default: return v;
232 }
233 },
234 },
235 {
236 header: gettext('Usage'),
237 width: 150,
238 sortable: false,
239 renderer: function(v, metaData, rec) {
240 let extendedInfo = ' ';
241 if (rec) {
242 let types = [];
243 if (rec.data.osdid !== undefined && rec.data.osdid >= 0) {
244 types.push(`OSD.${rec.data.osdid.toString()}`);
245 }
246 if (rec.data.journals > 0) {
247 types.push('Journal');
248 }
249 if (rec.data.db > 0) {
250 types.push('DB');
251 }
252 if (rec.data.wal > 0) {
253 types.push('WAL');
254 }
255 if (types.length > 0) {
256 extendedInfo = `, Ceph (${types.join(', ')})`;
257 }
258 }
259 return v ? `${v}${extendedInfo}` : Proxmox.Utils.noText;
260 },
261 dataIndex: 'used',
262 },
263 {
264 header: gettext('Size'),
265 width: 100,
266 align: 'right',
267 sortable: true,
268 renderer: Proxmox.Utils.format_size,
269 dataIndex: 'size',
270 },
271 {
272 header: 'GPT',
273 width: 60,
274 align: 'right',
275 renderer: Proxmox.Utils.format_boolean,
276 dataIndex: 'gpt',
277 },
278 {
279 header: gettext('Vendor'),
280 width: 100,
281 sortable: true,
282 hidden: true,
283 renderer: Ext.String.htmlEncode,
284 dataIndex: 'vendor',
285 },
286 {
287 header: gettext('Model'),
288 width: 200,
289 sortable: true,
290 renderer: Ext.String.htmlEncode,
291 dataIndex: 'model',
292 },
293 {
294 header: gettext('Serial'),
295 width: 200,
296 sortable: true,
297 renderer: Ext.String.htmlEncode,
298 dataIndex: 'serial',
299 },
300 {
301 header: 'S.M.A.R.T.',
302 width: 100,
303 sortable: true,
304 renderer: Ext.String.htmlEncode,
305 dataIndex: 'status',
306 },
307 {
308 header: 'Wearout',
309 width: 90,
310 sortable: true,
311 align: 'right',
312 dataIndex: 'wearout',
313 renderer: function(value) {
314 if (Ext.isNumeric(value)) {
315 return (100 - value).toString() + '%';
316 }
317 return 'N/A';
318 },
319 },
320 ],
321
322 listeners: {
323 itemdblclick: 'openSmartWindow',
324 },
325 });