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 301951FF13B for ; Wed, 11 Mar 2026 16:13:44 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 64D693017B; Wed, 11 Mar 2026 16:13:39 +0100 (CET) From: Hannes Laimer To: pbs-devel@lists.proxmox.com Subject: [PATCH proxmox-backup v4 6/7] ui: add move group action Date: Wed, 11 Mar 2026 16:13:14 +0100 Message-ID: <20260311151315.133637-7-h.laimer@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260311151315.133637-1-h.laimer@proxmox.com> References: <20260311151315.133637-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: 1773241978739 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.068 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: IJ2YZ763OS5E62NU2ZV42KRU7HAI7CW3 X-Message-ID-Hash: IJ2YZ763OS5E62NU2ZV42KRU7HAI7CW3 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 | 61 ++++++++++++++++++++++++++++++++++++++++ www/window/GroupMove.js | 56 ++++++++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 www/window/GroupMove.js diff --git a/www/Makefile b/www/Makefile index 9ebf0445..db775b64 100644 --- a/www/Makefile +++ b/www/Makefile @@ -77,6 +77,7 @@ JSSRC= \ window/ACLEdit.js \ window/BackupGroupChangeOwner.js \ window/CreateDirectory.js \ + window/GroupMove.js \ window/DataStoreEdit.js \ window/NamespaceEdit.js \ window/MaintenanceOptions.js \ diff --git a/www/datastore/Content.js b/www/datastore/Content.js index a2aa1949..ccd48616 100644 --- a/www/datastore/Content.js +++ b/www/datastore/Content.js @@ -635,6 +635,50 @@ Ext.define('PBS.DataStoreContent', { }); }, + moveNS: function () { + let me = this; + let view = me.getView(); + if (!view.namespace || view.namespace === '') { + return; + } + let win = Ext.create('PBS.window.NamespaceMove', { + datastore: view.datastore, + namespace: view.namespace, + taskDone: (success) => { + if (success) { + let newNs = win.getNewNamespace(); + view.down('pbsNamespaceSelector').store?.load(); + me.nsChange(null, newNs); + } + }, + }); + win.show(); + }, + + 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); + } else if (data.ty === 'ns') { + me.moveNS(); + } + }, + + forgetGroup: function (data) { let me = this; let view = me.getView(); @@ -1080,6 +1124,23 @@ Ext.define('PBS.DataStoreContent', { }, isActionDisabled: (v, r, c, i, rec) => rec.data.ty !== 'dir', }, + { + handler: 'onMove', + getTip: (v, m, { data }) => { + if (data.ty === 'group') { + return Ext.String.format(gettext("Move group '{0}'"), v); + } + return Ext.String.format(gettext("Move namespace '{0}'"), v); + }, + getClass: (v, m, { data }) => { + if (data.ty === 'group') { return 'fa fa-arrows'; } + if (data.ty === 'ns' && !data.isRootNS && data.ns === undefined) { + return 'fa fa-arrows'; + } + return 'pmx-hidden'; + }, + isActionDisabled: (v, r, c, i, { data }) => false, + }, { handler: 'onForget', getTip: (v, m, { data }) => { 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