Upstream proxmox-git/pve-manager state of the touched files before cf848bda29

This commit is contained in:
upstream committed 2026-09-25 07:15:08 +02:00
1 parent c09a3d7d49
commit 92f8784d03
2 files changed
+338

No files matched your search

+108
View File
@@ -0,0 +1,108 @@
Ext.define('PVE.form.NodeSelector', {
extend: 'Proxmox.form.ComboGrid',
alias: ['widget.pveNodeSelector'],
// invalidate nodes which are offline
onlineValidator: false,
selectCurNode: false,
// do not allow those nodes (array)
disallowedNodes: undefined,
// only allow those nodes (array)
allowedNodes: undefined,
valueField: 'node',
displayField: 'node',
store: {
fields: ['node', 'cpu', 'maxcpu', 'mem', 'maxmem', 'uptime'],
proxy: {
type: 'proxmox',
url: '/api2/json/nodes',
},
sorters: [
{
property: 'node',
direction: 'ASC',
},
{
property: 'mem',
direction: 'DESC',
},
],
},
listConfig: {
columns: [
{
header: gettext('Node'),
dataIndex: 'node',
sortable: true,
hideable: false,
flex: 1,
},
{
header: gettext('Memory usage') + ' %',
renderer: PVE.Utils.render_mem_usage_percent,
sortable: true,
width: 100,
dataIndex: 'mem',
},
{
header: gettext('CPU usage'),
renderer: Proxmox.Utils.render_cpu,
sortable: true,
width: 100,
dataIndex: 'cpu',
},
],
},
validator: function (value) {
let me = this;
if (!me.onlineValidator || (me.allowBlank && !value)) {
return true;
}
let offline = [],
notAllowed = [];
Ext.Array.each(value.split(/\s*,\s*/), function (node) {
let rec = me.store.findRecord(me.valueField, node, 0, false, true, true);
if (!(rec && rec.data) || rec.data.status !== 'online') {
offline.push(node);
} else if (me.allowedNodes && !Ext.Array.contains(me.allowedNodes, node)) {
notAllowed.push(node);
}
});
if (value && notAllowed.length !== 0) {
return 'Node ' + notAllowed.join(', ') + ' is not allowed for this action!';
}
if (value && offline.length !== 0) {
return 'Node ' + offline.join(', ') + ' seems to be offline!';
}
return true;
},
initComponent: function () {
var me = this;
if (me.selectCurNode && PVE.curSelectedNode && PVE.curSelectedNode.data.node) {
me.preferredValue = PVE.curSelectedNode.data.node;
}
me.callParent();
me.getStore().load();
me.getStore().addFilter(
new Ext.util.Filter({
// filter out disallowed nodes
filterFn: (item) =>
!(me.disallowedNodes && me.disallowedNodes.includes(item.data.node)),
}),
);
me.mon(me.getStore(), 'load', () => me.isValid());
},
});
+230
View File
@@ -0,0 +1,230 @@
Ext.define('PVE.forms.NodePrioritySelector', {
extend: 'Ext.grid.Panel',
alias: 'widget.pveNodePrioritySelector',
mixins: {
field: 'Ext.form.field.Field',
},
allowBlank: true,
isFormField: true,
config: {
useNodePriority: null,
},
publishes: ['useNodePriority'],
viewModel: {
data: {
showNodePriority: null,
},
},
store: {
autoLoad: true,
fields: ['node', 'cpu', 'mem', 'priority'],
proxy: {
type: 'proxmox',
url: '/api2/json/nodes',
},
sorters: [
{
property: 'node',
direction: 'ASC',
},
],
},
columns: [
{
header: gettext('Node'),
width: 150,
dataIndex: 'node',
},
{
header: gettext('Memory usage') + ' %',
renderer: PVE.Utils.render_mem_usage_percent,
sortable: true,
width: 150,
dataIndex: 'mem',
},
{
header: gettext('CPU usage'),
renderer: Proxmox.Utils.render_cpu,
sortable: true,
flex: 1,
dataIndex: 'cpu',
},
{
header: gettext('Priority'),
xtype: 'widgetcolumn',
dataIndex: 'priority',
sortable: true,
stopSelection: true,
widget: {
xtype: 'proxmoxintegerfield',
minValue: 0,
maxValue: 1000,
isFormField: false,
listeners: {
change: function (field, value) {
let record = field.getWidgetRecord();
record.set('priority', value);
record.commit();
},
},
bind: {
hidden: '{!showNodePriority}',
disabled: '{!showNodePriority}',
},
},
bind: {
hidden: '{!showNodePriority}',
disabled: '{!showNodePriority}',
},
},
],
selModel: {
selType: 'checkboxmodel',
mode: 'SIMPLE',
},
checkChangeEvents: ['selectionchange'],
listeners: {
selectionchange: function () {
// to trigger validity and error checks
this.checkChange();
},
},
invertCheckboxSelection: function () {
let me = this;
let sm = me.getSelectionModel();
let allNodeModels = sm.getStore().getRange();
let selectedNodeModels = new Set(sm.getSelection());
if (!allNodeModels.length || !selectedNodeModels.size) {
return;
}
sm.deselectAll();
sm.select(allNodeModels.filter((node) => !selectedNodeModels.has(node)));
},
applyUseNodePriority: function (newValue) {
let me = this;
me.getViewModel().set('showNodePriority', newValue);
return newValue;
},
getSubmitData: function () {
let me = this;
let res = {};
res[me.name] = me.getValue();
return res;
},
getValue: function () {
let me = this;
if (me.savedValue !== undefined) {
return me.savedValue;
}
let sm = me.getSelectionModel();
let selectedNodeModels = sm.getSelection();
let nodes = selectedNodeModels
.map(({ data }) => {
let nodeEntry = data.node;
if (me.useNodePriority && data.priority) {
nodeEntry += `:${data.priority}`;
}
return nodeEntry;
})
.join(',');
return nodes;
},
setValueSelection: function (value) {
let me = this;
let store = me.getStore();
store.beginUpdate();
let nodenames = value.length ? value.split(',') : [];
let nodes = nodenames.map((item) => {
let [node, priority] = item.split(':');
let record = store.findRecord('node', node, 0, false, true, true);
if (record) {
record.set('priority', priority);
record.commit();
} else {
let addedRecords = store.add({ node, priority });
record = addedRecords[0];
}
return record;
});
store.endUpdate();
let sm = me.getSelectionModel();
if (nodes.length) {
sm.select(nodes);
} else {
sm.deselectAll();
}
me.getErrors();
},
setValue: function (value) {
let me = this;
let store = me.getStore();
if (!store.isLoaded()) {
me.savedValue = value;
store.on(
'load',
function () {
me.setValueSelection(value);
delete me.savedValue;
},
{ single: true },
);
} else {
me.setValueSelection(value);
}
return me.mixins.field.setValue.call(me, value);
},
getErrors: function (value) {
let me = this;
if (!me.isDisabled() && me.allowBlank === false && me.getValue().length === 0) {
me.addBodyCls(['x-form-trigger-wrap-default', 'x-form-trigger-wrap-invalid']);
return [gettext('No nodes selected')];
}
me.removeBodyCls(['x-form-trigger-wrap-default', 'x-form-trigger-wrap-invalid']);
return [];
},
initComponent: function () {
let me = this;
me.callParent();
me.initField();
},
});