mirror of
https://git.proxmox.com/git/proxmox-widget-toolkit
synced 2025-12-07 21:12:59 +00:00
add DiskSmart window and DiskList from PVE
for use with other produts. the models are now all prefixed with 'pmx' instead of pve, so they should not conflict includes some changes to the model for remapping some fields and some small refactors (change to controller for the DiskList, some cleanup of the initComponent of the DiskSmart window) Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
This commit is contained in:
parent
4f0c076470
commit
402991a79d
@ -34,6 +34,7 @@ JSSRC= \
|
||||
button/HelpButton.js \
|
||||
grid/ObjectGrid.js \
|
||||
grid/PendingObjectGrid.js \
|
||||
grid/DiskList.js \
|
||||
panel/InputPanel.js \
|
||||
panel/LogView.js \
|
||||
panel/JournalView.js \
|
||||
@ -43,6 +44,7 @@ JSSRC= \
|
||||
window/PasswordEdit.js \
|
||||
window/TaskViewer.js \
|
||||
window/LanguageEdit.js \
|
||||
window/DiskSmart.js \
|
||||
node/APT.js \
|
||||
node/NetworkEdit.js \
|
||||
node/NetworkView.js \
|
||||
|
||||
233
src/grid/DiskList.js
Normal file
233
src/grid/DiskList.js
Normal file
@ -0,0 +1,233 @@
|
||||
Ext.define('pmx-disk-list', {
|
||||
extend: 'Ext.data.Model',
|
||||
fields: [
|
||||
'devpath', 'used',
|
||||
{ name: 'size', type: 'number' },
|
||||
{ name: 'osdid', type: 'number' },
|
||||
{
|
||||
name: 'status',
|
||||
convert: function(value, rec) {
|
||||
if (value) return value;
|
||||
if (rec.data.health) {
|
||||
return rec.data.health;
|
||||
}
|
||||
return Proxmox.Utils.unknownText;
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
convert: function(value, rec) {
|
||||
if (value) return value;
|
||||
if (rec.data.devpath) return rec.data.devpath;
|
||||
return undefined;
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'disk-type',
|
||||
convert: function(value, rec) {
|
||||
if (value) return value;
|
||||
if (rec.data.type) return rec.data.type;
|
||||
return undefined;
|
||||
},
|
||||
},
|
||||
'vendor', 'model', 'serial', 'rpm', 'type', 'wearout', 'health',
|
||||
],
|
||||
idProperty: 'devpath',
|
||||
});
|
||||
|
||||
Ext.define('Proxmox.DiskList', {
|
||||
extend: 'Ext.grid.GridPanel',
|
||||
alias: 'widget.pmxDiskList',
|
||||
|
||||
emptyText: gettext('No Disks found'),
|
||||
|
||||
stateful: true,
|
||||
stateId: 'grid-node-disks',
|
||||
|
||||
controller: {
|
||||
xclass: 'Ext.app.ViewController',
|
||||
|
||||
reload: function() {
|
||||
let me = this;
|
||||
me.getView().getStore().load();
|
||||
},
|
||||
|
||||
openSmartWindow: function() {
|
||||
let me = this;
|
||||
let view = me.getView();
|
||||
let selection = view.getSelection();
|
||||
if (!selection || selection.length < 1) return;
|
||||
|
||||
let rec = selection[0];
|
||||
Ext.create('Proxmox.window.DiskSmart', {
|
||||
baseurl: view.baseurl,
|
||||
dev: rec.data.name,
|
||||
}).show();
|
||||
},
|
||||
|
||||
initGPT: function() {
|
||||
let me = this;
|
||||
let view = me.getView();
|
||||
let selection = view.getSelection();
|
||||
if (!selection || selection.length < 1) return;
|
||||
|
||||
let rec = selection[0];
|
||||
Proxmox.Utils.API2Request({
|
||||
url: `${view.baseurl}/initgpt`,
|
||||
waitMsgTarget: view,
|
||||
method: 'POST',
|
||||
params: { disk: rec.data.devpath },
|
||||
failure: function(response, options) {
|
||||
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
|
||||
},
|
||||
success: function(response, options) {
|
||||
var upid = response.result.data;
|
||||
var win = Ext.create('Proxmox.window.TaskProgress', {
|
||||
upid: upid,
|
||||
});
|
||||
win.show();
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
init: function(view) {
|
||||
Proxmox.Utils.monStoreErrors(view, view.getStore(), true);
|
||||
|
||||
let nodename = view.nodename || 'localhost';
|
||||
view.baseurl = `/api2/json/nodes/${nodename}/disks`;
|
||||
view.getStore().getProxy().setUrl(`${view.baseurl}/list`);
|
||||
view.getStore().load();
|
||||
},
|
||||
},
|
||||
|
||||
store: {
|
||||
model: 'pmx-disk-list',
|
||||
proxy: {
|
||||
type: 'proxmox',
|
||||
},
|
||||
sorters: [
|
||||
{
|
||||
property: 'dev',
|
||||
direction: 'ASC',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
tbar: [
|
||||
{
|
||||
text: gettext('Reload'),
|
||||
handler: 'reload',
|
||||
},
|
||||
{
|
||||
xtype: 'proxmoxButton',
|
||||
text: gettext('Show S.M.A.R.T. values'),
|
||||
disabled: true,
|
||||
handler: 'openSmartWindow',
|
||||
},
|
||||
{
|
||||
xtype: 'proxmoxButton',
|
||||
text: gettext('Initialize Disk with GPT'),
|
||||
disabled: true,
|
||||
enableFn: function(rec) {
|
||||
if (!rec || rec.data.used) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
handler: 'initGPT',
|
||||
},
|
||||
],
|
||||
|
||||
columns: [
|
||||
{
|
||||
header: gettext('Device'),
|
||||
width: 150,
|
||||
sortable: true,
|
||||
dataIndex: 'devpath',
|
||||
},
|
||||
{
|
||||
header: gettext('Type'),
|
||||
width: 80,
|
||||
sortable: true,
|
||||
dataIndex: 'disk-type',
|
||||
renderer: function(v) {
|
||||
if (v === undefined) return Proxmox.Utils.unknownText;
|
||||
switch (v) {
|
||||
case 'ssd': return 'SSD';
|
||||
case 'hdd': return 'Hard Disk';
|
||||
case 'usb': return 'USB';
|
||||
default: return v;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
header: gettext('Usage'),
|
||||
width: 150,
|
||||
sortable: false,
|
||||
renderer: v => v || Proxmox.Utils.noText,
|
||||
dataIndex: 'used',
|
||||
},
|
||||
{
|
||||
header: gettext('Size'),
|
||||
width: 100,
|
||||
align: 'right',
|
||||
sortable: true,
|
||||
renderer: Proxmox.Utils.format_size,
|
||||
dataIndex: 'size',
|
||||
},
|
||||
{
|
||||
header: 'GPT',
|
||||
width: 60,
|
||||
align: 'right',
|
||||
renderer: Proxmox.Utils.format_boolean,
|
||||
dataIndex: 'gpt',
|
||||
},
|
||||
{
|
||||
header: gettext('Vendor'),
|
||||
width: 100,
|
||||
sortable: true,
|
||||
hidden: true,
|
||||
renderer: Ext.String.htmlEncode,
|
||||
dataIndex: 'vendor',
|
||||
},
|
||||
{
|
||||
header: gettext('Model'),
|
||||
width: 200,
|
||||
sortable: true,
|
||||
renderer: Ext.String.htmlEncode,
|
||||
dataIndex: 'model',
|
||||
},
|
||||
{
|
||||
header: gettext('Serial'),
|
||||
width: 200,
|
||||
sortable: true,
|
||||
renderer: Ext.String.htmlEncode,
|
||||
dataIndex: 'serial',
|
||||
},
|
||||
{
|
||||
header: 'S.M.A.R.T.',
|
||||
width: 100,
|
||||
sortable: true,
|
||||
renderer: Ext.String.htmlEncode,
|
||||
dataIndex: 'status',
|
||||
},
|
||||
{
|
||||
header: 'Wearout',
|
||||
width: 90,
|
||||
sortable: true,
|
||||
align: 'right',
|
||||
dataIndex: 'wearout',
|
||||
renderer: function(value) {
|
||||
if (Ext.isNumeric(value)) {
|
||||
return (100 - value).toString() + '%';
|
||||
}
|
||||
return 'N/A';
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
listeners: {
|
||||
itemdblclick: 'openSmartWindow',
|
||||
},
|
||||
});
|
||||
133
src/window/DiskSmart.js
Normal file
133
src/window/DiskSmart.js
Normal file
@ -0,0 +1,133 @@
|
||||
Ext.define('Proxmox.window.DiskSmart', {
|
||||
extend: 'Ext.window.Window',
|
||||
alias: 'widget.pmxSmartWindow',
|
||||
|
||||
modal: true,
|
||||
|
||||
items: [
|
||||
{
|
||||
xtype: 'gridpanel',
|
||||
layout: {
|
||||
type: 'fit',
|
||||
},
|
||||
emptyText: gettext('No S.M.A.R.T. Values'),
|
||||
scrollable: true,
|
||||
flex: 1,
|
||||
itemId: 'smarts',
|
||||
reserveScrollbar: true,
|
||||
columns: [
|
||||
{ text: 'ID', dataIndex: 'id', width: 50 },
|
||||
{ text: gettext('Attribute'), flex: 1, dataIndex: 'name', renderer: Ext.String.htmlEncode },
|
||||
{ text: gettext('Value'), dataIndex: 'raw', renderer: Ext.String.htmlEncode },
|
||||
{ text: gettext('Normalized'), dataIndex: 'value', width: 60 },
|
||||
{ text: gettext('Threshold'), dataIndex: 'threshold', width: 60 },
|
||||
{ text: gettext('Worst'), dataIndex: 'worst', width: 60 },
|
||||
{ text: gettext('Flags'), dataIndex: 'flags' },
|
||||
{ text: gettext('Failing'), dataIndex: 'fail', renderer: Ext.String.htmlEncode },
|
||||
],
|
||||
},
|
||||
{
|
||||
xtype: 'component',
|
||||
itemId: 'text',
|
||||
layout: {
|
||||
type: 'fit',
|
||||
},
|
||||
hidden: true,
|
||||
style: {
|
||||
'background-color': 'white',
|
||||
'white-space': 'pre',
|
||||
'font-family': 'monospace',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
buttons: [
|
||||
{
|
||||
text: gettext('Reload'),
|
||||
name: 'reload',
|
||||
handler: function() {
|
||||
var me = this;
|
||||
me.up('window').store.reload();
|
||||
},
|
||||
},
|
||||
{
|
||||
text: gettext('Close'),
|
||||
name: 'close',
|
||||
handler: function() {
|
||||
var me = this;
|
||||
me.up('window').close();
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
layout: {
|
||||
type: 'vbox',
|
||||
align: 'stretch',
|
||||
},
|
||||
width: 800,
|
||||
height: 500,
|
||||
minWidth: 600,
|
||||
minHeight: 400,
|
||||
bodyPadding: 5,
|
||||
title: gettext('S.M.A.R.T. Values'),
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
if (!me.baseurl) {
|
||||
throw "no baseurl specified";
|
||||
}
|
||||
|
||||
var dev = me.dev;
|
||||
if (!dev) {
|
||||
throw "no device specified";
|
||||
}
|
||||
|
||||
me.store = Ext.create('Ext.data.Store', {
|
||||
model: 'pmx-disk-smart',
|
||||
proxy: {
|
||||
type: 'proxmox',
|
||||
url: `${me.baseurl}/smart?disk=${dev}`,
|
||||
},
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
var grid = me.down('#smarts');
|
||||
var text = me.down('#text');
|
||||
|
||||
Proxmox.Utils.monStoreErrors(grid, me.store);
|
||||
me.mon(me.store, 'load', function(s, records, success) {
|
||||
if (success && records.length > 0) {
|
||||
var rec = records[0];
|
||||
if (rec.data.type === 'text') {
|
||||
grid.setVisible(false);
|
||||
text.setVisible(true);
|
||||
text.setHtml(Ext.String.htmlEncode(rec.data.text));
|
||||
} else {
|
||||
grid.setVisible(true);
|
||||
text.setVisible(false);
|
||||
grid.setStore(rec.attributes());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
me.store.load();
|
||||
},
|
||||
}, function() {
|
||||
Ext.define('pmx-disk-smart', {
|
||||
extend: 'Ext.data.Model',
|
||||
fields: [
|
||||
{ name: 'health' },
|
||||
{ name: 'type' },
|
||||
{ name: 'text' },
|
||||
],
|
||||
hasMany: { model: 'pmx-smart-attribute', name: 'attributes' },
|
||||
});
|
||||
Ext.define('pmx-smart-attribute', {
|
||||
extend: 'Ext.data.Model',
|
||||
fields: [
|
||||
{ name: 'id', type: 'number' }, 'name', 'value', 'worst', 'threshold', 'flags', 'fail', 'raw',
|
||||
],
|
||||
idProperty: 'name',
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user