close #3181: ui: display guest name in confirm dialogs

The confirmation dialogs of the following actions are affected by this
change:
* Remove
* Clone
* Migrate
* Snapshot
* Snapshot restore
* Backup VM/CT from config view
* Restore VM/CT from config view

A combination of VM/CT id and name is added to each confirmation dialog.
The order of id and name depends on the sort field selected in the tree
settings. If "Name" is selected, the confirmation dialogs will show "VM
name (VMID)". In any other case, "VMID (VM name)" will be used.

The VM/CT name is considered optional in all handled cases. If it is
undefined, only the VMID will be displayed in the dialog window. No
exceptions are thrown in case of an undefined guest name because it
only extends the information displayed to the user and is not essential
for performing any of the actions above.

Signed-off-by: Michael Köppl <m.koeppl@proxmox.com>
This commit is contained in:
Michael Köppl 2025-04-07 10:38:06 +02:00 committed by Thomas Lamprecht
parent 0457881c56
commit 708de5b341
12 changed files with 92 additions and 18 deletions

View File

@ -1970,8 +1970,19 @@ Ext.define('PVE.Utils', {
return languageCookie || Proxmox.defaultLang || 'en';
},
getFormattedGuestIdentifier: function(vmid, guestName) {
if (PVE.UIOptions.getTreeSortingValue('sort-field') === 'vmid') {
return guestName ? `${vmid} (${guestName})` : vmid;
} else {
return guestName ? `${guestName} (${vmid})` : vmid;
}
},
formatGuestTaskConfirmation: function(taskType, vmid, guestName) {
let description = Proxmox.Utils.format_task_description(taskType, `${vmid} (${guestName})`);
let description = Proxmox.Utils.format_task_description(
taskType,
this.getFormattedGuestIdentifier(vmid, guestName),
);
return Ext.htmlEncode(description);
},
},

View File

@ -39,6 +39,8 @@ Ext.define('PVE.grid.BackupView', {
throw "unsupported VM type '" + vmtype + "'";
}
let vmname = me.pveSelNode.data.name;
var searchFilter = {
property: 'volid',
value: '',
@ -167,6 +169,7 @@ Ext.define('PVE.grid.BackupView', {
nodename: nodename,
vmid: vmid,
vmtype: vmtype,
vmname: vmname,
storage: storagesel.getValue(),
listeners: {
close: function() {
@ -189,6 +192,7 @@ Ext.define('PVE.grid.BackupView', {
let win = Ext.create('PVE.window.Restore', {
nodename: nodename,
vmid: vmid,
vmname: vmname,
volid: rec.data.volid,
volidText: PVE.Utils.render_storage_content(rec.data.volid, {}, rec),
vmtype: vmtype,

View File

@ -89,7 +89,13 @@ Ext.define('PVE.lxc.CmdMenu', {
text: gettext('Clone'),
iconCls: 'fa fa-fw fa-clone',
hidden: !caps.vms['VM.Clone'],
handler: () => PVE.window.Clone.wrap(info.node, info.vmid, me.isTemplate, 'lxc'),
handler: () => PVE.window.Clone.wrap(
info.node,
info.vmid,
info.name,
me.isTemplate,
'lxc',
),
},
{
text: gettext('Migrate'),
@ -100,6 +106,7 @@ Ext.define('PVE.lxc.CmdMenu', {
vmtype: 'lxc',
nodename: info.node,
vmid: info.vmid,
vmname: info.name,
autoShow: true,
});
},

View File

@ -100,6 +100,7 @@ Ext.define('PVE.lxc.Config', {
vmtype: 'lxc',
nodename: nodename,
vmid: vmid,
vmname: vm.name,
});
win.show();
},
@ -115,7 +116,13 @@ Ext.define('PVE.lxc.Config', {
iconCls: 'fa fa-fw fa-clone',
hidden: !caps.vms['VM.Clone'],
handler: function() {
PVE.window.Clone.wrap(nodename, vmid, template, 'lxc');
PVE.window.Clone.wrap(
nodename,
vmid,
vm.name,
template,
'lxc',
);
},
},
{
@ -156,7 +163,11 @@ Ext.define('PVE.lxc.Config', {
handler: function() {
Ext.create('PVE.window.SafeDestroyGuest', {
url: base_url,
item: { type: 'CT', id: vmid },
item: {
type: 'CT',
id: vmid,
formattedIdentifier: PVE.Utils.getFormattedGuestIdentifier(vmid, vm.name),
},
taskName: 'vzdestroy',
}).show();
},

View File

@ -121,6 +121,7 @@ Ext.define('PVE.qemu.CmdMenu', {
vmtype: 'qemu',
nodename: info.node,
vmid: info.vmid,
vmname: info.name,
autoShow: true,
});
},
@ -129,7 +130,13 @@ Ext.define('PVE.qemu.CmdMenu', {
text: gettext('Clone'),
iconCls: 'fa fa-fw fa-clone',
hidden: !caps.vms['VM.Clone'],
handler: () => PVE.window.Clone.wrap(info.node, info.vmid, me.isTemplate, 'qemu'),
handler: () => PVE.window.Clone.wrap(
info.node,
info.vmid,
info.name,
me.isTemplate,
'qemu',
),
},
{
text: gettext('Convert to template'),

View File

@ -73,6 +73,7 @@ Ext.define('PVE.qemu.Config', {
vmtype: 'qemu',
nodename: nodename,
vmid: vmid,
vmname: vm.name,
});
win.show();
},
@ -88,7 +89,13 @@ Ext.define('PVE.qemu.Config', {
iconCls: 'fa fa-fw fa-clone',
hidden: !caps.vms['VM.Clone'],
handler: function() {
PVE.window.Clone.wrap(nodename, vmid, template, 'qemu');
PVE.window.Clone.wrap(
nodename,
vmid,
vm.name,
template,
'qemu',
);
},
},
{
@ -128,7 +135,11 @@ Ext.define('PVE.qemu.Config', {
handler: function() {
Ext.create('PVE.window.SafeDestroyGuest', {
url: base_url,
item: { type: 'VM', id: vmid },
item: {
type: 'VM',
id: vmid,
formattedIdentifier: PVE.Utils.getFormattedGuestIdentifier(vmid, vm.name),
},
taskName: 'qmdestroy',
}).show();
},

View File

@ -11,6 +11,7 @@ Ext.define('PVE.guest.SnapshotTree', {
type: undefined,
nodename: undefined,
vmid: undefined,
vmname: undefined,
snapshotAllowed: false,
rollbackAllowed: false,
snapshotFeature: false,
@ -50,6 +51,7 @@ Ext.define('PVE.guest.SnapshotTree', {
let win = Ext.create('PVE.window.Snapshot', {
nodename: vm.get('nodename'),
vmid: vm.get('vmid'),
vmname: vm.get('vmname'),
viewonly: !vm.get('snapshotAllowed'),
type: vm.get('type'),
isCreate: !edit,
@ -213,6 +215,8 @@ Ext.define('PVE.guest.SnapshotTree', {
}
vm.set('vmid', view.pveSelNode.data.vmid);
vm.set('vmname', view.pveSelNode.data.name);
let caps = Ext.state.Manager.get('GuiCap');
vm.set('snapshotAllowed', !!caps.vms['VM.Snapshot']);
vm.set('rollbackAllowed', !!caps.vms['VM.Snapshot.Rollback']);
@ -259,8 +263,12 @@ Ext.define('PVE.guest.SnapshotTree', {
let view = this.up('treepanel');
let rec = view.getSelection()[0];
let vmid = view.getViewModel().get('vmid');
let message = Proxmox.Utils.format_task_description('qmrollback', vmid) +
` '${rec.data.name}'? ${gettext("Current state will be lost.")}`;
let vmname = view.getViewModel().get('vmname');
let message = PVE.Utils.formatGuestTaskConfirmation(
'qmrollback',
vmid,
vmname,
) + ` '${rec.data.name}'? ${gettext("Current state will be lost.")}`;
return Ext.htmlEncode(message);
},
handler: 'rollback',

View File

@ -360,9 +360,9 @@ Ext.define('PVE.window.Backup', {
hidden: false,
});
var title = gettext('Backup') + " " +
(me.vmtype === 'lxc' ? "CT" : "VM") +
" " + me.vmid;
let guestTypeStr = me.vmtype === 'lxc' ? "CT" : "VM";
let formattedGuestIdentifier = PVE.Utils.getFormattedGuestIdentifier(me.vmid, me.vmname);
let title = `${gettext('Backup')} ${guestTypeStr} ${formattedGuestIdentifier}`;
Ext.apply(me, {
title: title,

View File

@ -21,7 +21,7 @@ Ext.define('PVE.window.Clone', {
statics: {
// display a snapshot selector only if needed
wrap: function(nodename, vmid, isTemplate, guestType) {
wrap: function(nodename, vmid, vmname, isTemplate, guestType) {
Proxmox.Utils.API2Request({
url: '/nodes/' + nodename + '/' + guestType + '/' + vmid +'/snapshot',
failure: function(response, opts) {
@ -36,6 +36,7 @@ Ext.define('PVE.window.Clone', {
nodename: nodename,
guestType: guestType,
vmid: vmid,
vmname: vmname,
isTemplate: isTemplate,
hasSnapshots: hasSnapshots,
}).show();
@ -155,7 +156,9 @@ Ext.define('PVE.window.Clone', {
if (me.isTemplate) {
titletext += ' Template';
}
me.title = "Clone " + titletext + " " + me.vmid;
let formattedGuestIdentifier = PVE.Utils.getFormattedGuestIdentifier(me.vmid, me.vmname);
me.title = `Clone ${titletext} ${formattedGuestIdentifier}`;
var col1 = [];
var col2 = [];

View File

@ -4,6 +4,7 @@ Ext.define('PVE.window.Migrate', {
vmtype: undefined,
nodename: undefined,
vmid: undefined,
vmname: undefined,
maxHeight: 450,
viewModel: {
@ -92,9 +93,14 @@ Ext.define('PVE.window.Migrate', {
}
vm.set('vmtype', view.vmtype);
view.setTitle(
Ext.String.format('{0} {1} {2}', gettext('Migrate'), vm.get(view.vmtype).commonName, view.vmid),
let title = Ext.String.format(
'{0} {1} {2}',
gettext('Migrate'),
vm.get(view.vmtype).commonName,
PVE.Utils.getFormattedGuestIdentifier(view.vmid, view.vmname),
);
view.setTitle(title);
me.lookup('proxmoxHelpButton').setHelpConfig({
onlineHelp: vm.get(view.vmtype).onlineHelp,
});

View File

@ -357,7 +357,8 @@ Ext.define('PVE.window.Restore', {
let title = gettext('Restore') + ": " + (me.vmtype === 'lxc' ? 'CT' : 'VM');
if (me.vmid) {
title = `${gettext('Overwrite')} ${title} ${me.vmid}`;
let formattedGuestIdentifier = PVE.Utils.getFormattedGuestIdentifier(me.vmid, me.vmname);
title = `${gettext('Overwrite')} ${title} ${formattedGuestIdentifier}`;
}
Ext.apply(me, {

View File

@ -137,7 +137,12 @@ Ext.define('PVE.window.Snapshot', {
let subject;
if (me.isCreate) {
subject = (me.type === 'qemu' ? 'VM' : 'CT') + me.vmid + ' ' + gettext('Snapshot');
let guestTypeStr = me.type === 'qemu' ? 'VM' : 'CT';
let formattedGuestIdentifier = PVE.Utils.getFormattedGuestIdentifier(
me.vmid,
me.vmname,
);
subject = `${guestTypeStr} ${formattedGuestIdentifier} ${gettext('Snapshot')}}`;
me.method = 'POST';
me.showTaskViewer = true;
} else {