From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id A5F7E1FF13C for ; Thu, 19 Mar 2026 17:14:01 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id D0278516F; Thu, 19 Mar 2026 17:14:14 +0100 (CET) From: Hannes Laimer To: pbs-devel@lists.proxmox.com Subject: [PATCH proxmox-backup v5 7/9] ui: add move group action Date: Thu, 19 Mar 2026 17:13:23 +0100 Message-ID: <20260319161325.206846-8-h.laimer@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260319161325.206846-1-h.laimer@proxmox.com> References: <20260319161325.206846-1-h.laimer@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1773936778596 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.082 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: 2FWGMRN3G562YCWWWUBFM5A4JJE6Y4CS X-Message-ID-Hash: 2FWGMRN3G562YCWWWUBFM5A4JJE6Y4CS X-MailFrom: h.laimer@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox Backup Server development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Signed-off-by: Hannes Laimer --- www/Makefile | 1 + www/datastore/Content.js | 47 +++++++++++++++++++++++++++++++++ www/window/GroupMove.js | 56 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+) create mode 100644 www/window/GroupMove.js diff --git a/www/Makefile b/www/Makefile index 9ebf0445..7745d9f4 100644 --- a/www/Makefile +++ b/www/Makefile @@ -76,6 +76,7 @@ JSSRC= \ config/PruneAndGC.js \ window/ACLEdit.js \ window/BackupGroupChangeOwner.js \ + window/GroupMove.js \ window/CreateDirectory.js \ window/DataStoreEdit.js \ window/NamespaceEdit.js \ diff --git a/www/datastore/Content.js b/www/datastore/Content.js index 981acdc7..b56cc4ac 100644 --- a/www/datastore/Content.js +++ b/www/datastore/Content.js @@ -667,6 +667,27 @@ Ext.define('PBS.DataStoreContent', { }); }, + moveGroup: function (data) { + let me = this; + let view = me.getView(); + let group = `${data.backup_type}/${data.backup_id}`; + Ext.create('PBS.window.GroupMove', { + datastore: view.datastore, + namespace: view.namespace, + backupType: data.backup_type, + backupId: data.backup_id, + group, + taskDone: () => me.reload(), + }).show(); + }, + + onMove: function (table, rI, cI, item, e, { data }) { + let me = this; + if (data.ty === 'group') { + me.moveGroup(data); + } + }, + forgetGroup: function (data) { let me = this; let view = me.getView(); @@ -971,6 +992,7 @@ Ext.define('PBS.DataStoreContent', { onVerify: createControllerCallback('onVerify'), onChangeOwner: createControllerCallback('onChangeOwner'), onPrune: createControllerCallback('onPrune'), + onMove: createControllerCallback('onMove'), onForget: createControllerCallback('onForget'), }); } else if (record.data.ty === 'dir') { @@ -1085,6 +1107,20 @@ Ext.define('PBS.DataStoreContent', { : 'pmx-hidden', isActionDisabled: (v, r, c, i, rec) => !!rec.data.leaf, }, + { + handler: 'onMove', + getTip: (v, m, { data }) => { + if (data.ty === 'group') { + return Ext.String.format(gettext("Move group '{0}'"), v); + } + return ''; + }, + getClass: (v, m, { data }) => { + if (data.ty === 'group') { return 'fa fa-arrows'; } + return 'pmx-hidden'; + }, + isActionDisabled: (v, r, c, i, { data }) => false, + }, { handler: 'onChangeOwner', getClass: (v, m, { data }) => @@ -1437,6 +1473,7 @@ Ext.define('PBS.datastore.GroupCmdMenu', { onVerify: undefined, onChangeOwner: undefined, onPrune: undefined, + onMove: undefined, onForget: undefined, items: [ @@ -1460,6 +1497,16 @@ Ext.define('PBS.datastore.GroupCmdMenu', { hidden: '{!onVerify}', }, }, + { + text: gettext('Move'), + iconCls: 'fa fa-arrows', + handler: function () { + this.up('menu').onMove(); + }, + cbind: { + hidden: '{!onMove}', + }, + }, { text: gettext('Change owner'), iconCls: 'fa fa-user', diff --git a/www/window/GroupMove.js b/www/window/GroupMove.js new file mode 100644 index 00000000..f663c606 --- /dev/null +++ b/www/window/GroupMove.js @@ -0,0 +1,56 @@ +Ext.define('PBS.window.GroupMove', { + extend: 'Proxmox.window.Edit', + alias: 'widget.pbsGroupMove', + mixins: ['Proxmox.Mixin.CBind'], + + onlineHelp: 'storage-namespaces', + + isCreate: true, + submitText: gettext('Move'), + showTaskViewer: true, + + cbind: { + url: '/api2/extjs/admin/datastore/{datastore}/groups', + title: (get) => Ext.String.format(gettext("Move Backup Group '{0}'"), get('group')), + }, + method: 'PUT', + + width: 400, + fieldDefaults: { + labelWidth: 120, + }, + + items: { + xtype: 'inputpanel', + onGetValues: function (values) { + let win = this.up('window'); + let result = { + 'backup-type': win.backupType, + 'backup-id': win.backupId, + 'new-ns': values['new-ns'] || '', + }; + if (win.namespace && win.namespace !== '') { + result.ns = win.namespace; + } + return result; + }, + items: [ + { + xtype: 'displayfield', + fieldLabel: gettext('Group'), + cbind: { + value: '{group}', + }, + }, + { + xtype: 'pbsNamespaceSelector', + name: 'new-ns', + fieldLabel: gettext('Target Namespace'), + allowBlank: true, + cbind: { + datastore: '{datastore}', + }, + }, + ], + }, +}); -- 2.47.3