]>
git.proxmox.com Git - proxmox-widget-toolkit.git/blob - src/panel/DiskList.js
1 Ext
.define('pmx-disk-list', {
2 extend
: 'Ext.data.Model',
5 { name
: 'size', type
: 'number' },
6 { name
: 'osdid', type
: 'number', defaultValue
: -1 },
9 convert: function(value
, rec
) {
10 if (value
) return value
;
11 if (rec
.data
.health
) {
12 return rec
.data
.health
;
15 if (rec
.data
.type
=== 'partition') {
19 return Proxmox
.Utils
.unknownText
;
24 convert: function(value
, rec
) {
25 if (value
) return value
;
26 if (rec
.data
.devpath
) return rec
.data
.devpath
;
32 convert: function(value
, rec
) {
33 if (value
) return value
;
34 if (rec
.data
.type
) return rec
.data
.type
;
38 'vendor', 'model', 'serial', 'rpm', 'type', 'wearout', 'health', 'mounted',
40 idProperty
: 'devpath',
43 Ext
.define('Proxmox.DiskList', {
44 extend
: 'Ext.tree.Panel',
45 alias
: 'widget.pmxDiskList',
47 supportsWipeDisk
: false,
51 emptyText
: gettext('No Disks found'),
54 stateId
: 'tree-node-disks',
57 xclass
: 'Ext.app.ViewController',
61 let view
= me
.getView();
64 if (view
.includePartitions
) {
65 extraParams
['include-partitions'] = 1;
68 let url
= `${view.baseurl}/list`;
71 extraParams
: extraParams
,
77 openSmartWindow: function() {
79 let view
= me
.getView();
80 let selection
= view
.getSelection();
81 if (!selection
|| selection
.length
< 1) return;
83 let rec
= selection
[0];
84 Ext
.create('Proxmox.window.DiskSmart', {
85 baseurl
: view
.baseurl
,
92 let view
= me
.getView();
93 let selection
= view
.getSelection();
94 if (!selection
|| selection
.length
< 1) return;
96 let rec
= selection
[0];
97 Proxmox
.Utils
.API2Request({
98 url
: `${view.exturl}/initgpt`,
101 params
: { disk
: rec
.data
.name
},
102 failure
: response
=> Ext
.Msg
.alert(gettext('Error'), response
.htmlStatus
),
103 success: function(response
, options
) {
104 Ext
.create('Proxmox.window.TaskProgress', {
105 upid
: response
.result
.data
,
106 taskDone: function() {
115 wipeDisk: function() {
117 let view
= me
.getView();
118 let selection
= view
.getSelection();
119 if (!selection
|| selection
.length
< 1) return;
121 let rec
= selection
[0];
122 Proxmox
.Utils
.API2Request({
123 url
: `${view.exturl}/wipedisk`,
126 params
: { disk
: rec
.data
.name
},
127 failure
: response
=> Ext
.Msg
.alert(gettext('Error'), response
.htmlStatus
),
128 success: function(response
, options
) {
129 Ext
.create('Proxmox.window.TaskProgress', {
130 upid
: response
.result
.data
,
131 taskDone: function() {
140 init: function(view
) {
141 let nodename
= view
.nodename
|| 'localhost';
142 view
.baseurl
= `/api2/json/nodes/${nodename}/disks`;
143 view
.exturl
= `/api2/extjs/nodes/${nodename}/disks`;
145 this.store
= Ext
.create('Ext.data.Store', {
146 model
: 'pmx-disk-list',
148 this.store
.on('load', this.onLoad
, this);
150 Proxmox
.Utils
.monStoreErrors(view
, this.store
);
154 onLoad: function(store
, records
, success
, operation
) {
156 let view
= this.getView();
159 Proxmox
.Utils
.setErrorMask(
161 Proxmox
.Utils
.getResponseErrorMessage(operation
.getError()),
168 for (const item
of records
) {
169 let data
= item
.data
;
170 data
.expanded
= true;
171 data
.children
= data
.partitions
?? [];
172 for (let p
of data
.children
) {
173 p
['disk-type'] = 'partition';
174 p
.iconCls
= 'fa fa-fw fa-hdd-o x-fa-tree';
175 p
.used
= p
.used
=== 'filesystem' ? p
.filesystem
: p
.used
;
176 p
.parent
= data
.devpath
;
180 data
.iconCls
= 'fa fa-fw fa-hdd-o x-fa-tree';
181 data
.leaf
= data
.children
.length
=== 0;
184 disks
[data
.devpath
] = data
;
187 for (const item
of records
) {
188 let data
= item
.data
;
190 disks
[data
.parent
].leaf
= false;
191 disks
[data
.parent
].children
.push(data
);
196 for (const [_
, device
] of Object
.entries(disks
)) {
197 children
.push(device
);
205 Proxmox
.Utils
.setErrorMask(view
, false);
209 renderDiskType: function(v
) {
210 if (v
=== undefined) return Proxmox
.Utils
.unknownText
;
212 case 'ssd': return 'SSD';
213 case 'hdd': return 'Hard Disk';
214 case 'usb': return 'USB';
219 renderDiskUsage: function(v
, metaData
, rec
) {
220 let extendedInfo
= '';
223 if (rec
.data
['osdid-list'] && rec
.data
['osdid-list'].length
> 0) {
224 for (const id
of rec
.data
['osdid-list'].sort()) {
225 types
.push(`OSD.${id.toString()}`);
227 } else if (rec
.data
.osdid
!== undefined && rec
.data
.osdid
>= 0) {
228 types
.push(`OSD.${rec.data.osdid.toString()}`);
230 if (rec
.data
.journals
> 0) {
231 types
.push('Journal');
233 if (rec
.data
.db
> 0) {
236 if (rec
.data
.wal
> 0) {
239 if (types
.length
> 0) {
240 extendedInfo
= `, Ceph (${types.join(', ')})`;
245 'zfsreserved': 'ZFS reserved',
251 v
= formatMap
[v
] || v
;
252 return v
? `${v}${extendedInfo}` : Proxmox
.Utils
.noText
;
258 header
: gettext('Device'),
261 dataIndex
: 'devpath',
264 header
: gettext('Type'),
267 dataIndex
: 'disk-type',
268 renderer: function(v
) {
270 return me
.renderDiskType(v
);
274 header
: gettext('Usage'),
277 renderer: function(v
, metaData
, rec
) {
279 return me
.renderDiskUsage(v
, metaData
, rec
);
284 header
: gettext('Size'),
288 renderer
: Proxmox
.Utils
.format_size
,
295 renderer
: Proxmox
.Utils
.format_boolean
,
299 header
: gettext('Vendor'),
303 renderer
: Ext
.String
.htmlEncode
,
307 header
: gettext('Model'),
310 renderer
: Ext
.String
.htmlEncode
,
314 header
: gettext('Serial'),
317 renderer
: Ext
.String
.htmlEncode
,
321 header
: 'S.M.A.R.T.',
324 renderer
: Ext
.String
.htmlEncode
,
328 header
: gettext('Mounted'),
331 renderer
: Proxmox
.Utils
.format_boolean
,
332 dataIndex
: 'mounted',
335 header
: gettext('Wearout'),
339 dataIndex
: 'wearout',
340 renderer: function(value
) {
341 if (Ext
.isNumeric(value
)) {
342 return (100 - value
).toString() + '%';
344 return gettext('N/A');
350 itemdblclick
: 'openSmartWindow',
353 initComponent: function() {
358 text
: gettext('Reload'),
362 xtype
: 'proxmoxButton',
363 text
: gettext('Show S.M.A.R.T. values'),
364 parentXType
: 'treepanel',
366 enableFn: function(rec
) {
367 if (!rec
|| rec
.data
.parent
) {
373 handler
: 'openSmartWindow',
376 xtype
: 'proxmoxButton',
377 text
: gettext('Initialize Disk with GPT'),
378 parentXType
: 'treepanel',
380 enableFn: function(rec
) {
381 if (!rec
|| rec
.data
.parent
||
382 (rec
.data
.used
&& rec
.data
.used
!== 'unused')) {
392 if (me
.supportsWipeDisk
) {
395 xtype
: 'proxmoxButton',
396 text
: gettext('Wipe Disk'),
397 parentXType
: 'treepanel',
399 confirmMsg: function(rec
) {
400 const data
= rec
.data
;
402 let mainMessage
= Ext
.String
.format(
403 gettext('Are you sure you want to wipe {0}?'),
406 mainMessage
+= `<br> ${gettext('All data on the device will be lost!')}`;
408 const type
= me
.renderDiskType(data
["disk-type"]);
411 if (data
.children
.length
> 0) {
412 const partitionUsage
= data
.children
.map(
413 partition
=> me
.renderDiskUsage(partition
.used
),
415 usage
= `${gettext('Partitions')} (${partitionUsage})`;
417 usage
= me
.renderDiskUsage(data
.used
, undefined, rec
);
420 const size
= Proxmox
.Utils
.format_size(data
.size
);
421 const serial
= Ext
.String
.htmlEncode(data
.serial
);
423 let additionalInfo
= `${gettext('Type')}: ${type}<br>`;
424 additionalInfo
+= `${gettext('Usage')}: ${usage}<br>`;
425 additionalInfo
+= `${gettext('Size')}: ${size}<br>`;
426 additionalInfo
+= `${gettext('Serial')}: ${serial}`;
428 return `${mainMessage}<br><br>${additionalInfo}`;