adapted from PBS. Main differences are:
1. loading of the prune-backups options from the storage
configuration, when the window is opened
2. API has GET/DELETE distinction instead of 'dry-run'
3. API expects a single property string for the prune options

Signed-off-by: Fabian Ebner <[email protected]>
---

Changes from v1:
    * adapt to the new gropuing
    * add button to group header

 www/manager6/Makefile              |   1 +
 www/manager6/storage/BackupView.js |  34 ++++-
 www/manager6/window/Prune.js       | 230 +++++++++++++++++++++++++++++
 3 files changed, 264 insertions(+), 1 deletion(-)
 create mode 100644 www/manager6/window/Prune.js

diff --git a/www/manager6/Makefile b/www/manager6/Makefile
index 4b9dcf58..b34bb41d 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -249,6 +249,7 @@ JSSRC=                                                      
\
        window/LoginWindow.js                           \
        window/Migrate.js                               \
        window/NotesEdit.js                             \
+       window/Prune.js                                 \
        window/Restore.js                               \
        window/SafeDestroy.js                           \
        window/Settings.js                              \
diff --git a/www/manager6/storage/BackupView.js 
b/www/manager6/storage/BackupView.js
index ad377de6..9b243974 100644
--- a/www/manager6/storage/BackupView.js
+++ b/www/manager6/storage/BackupView.js
@@ -6,7 +6,19 @@ Ext.define('PVE.storage.BackupView', {
     features: [
        {
            ftype: 'grouping',
-           groupHeaderTpl: '{name} ({rows.length} Backup{[values.rows.length > 
1 ? "s" : ""]})',
+           groupHeaderTpl: new Ext.XTemplate(
+               '<tpl for=".">',
+               '{name} ({rows.length} Backup{[values.rows.length > 1 ? "s" : 
""]})',
+               '<tpl if="name != \'other\'">',
+               ' | ' + gettext('Prune') + ': ',
+               '<button id="prune-btn" ' +
+                   'class="x-btn x-unselectable x-btn-custom-groupheader" ' +
+                   'data-qtip="Prune">',
+               '<i id="prune-btn-icon" class="fa fa-scissors"></i>',
+               '</button>',
+               '</tpl>',
+               '</tpl>',
+           ),
        },
     ],
 
@@ -89,6 +101,26 @@ Ext.define('PVE.storage.BackupView', {
            },
        });
 
+       Ext.apply(me, {
+           listeners: {
+               groupclick: function (view, node, group, e, eOpts) {
+                   if (e.getTarget().id.startsWith('prune-btn')) {
+                       view.features[0].expand(group); // keep group to be 
pruned expanded
+
+                       let [ type, vmid ] = group.split('/');
+                       var win = Ext.create('PVE.window.Prune', {
+                           nodename: nodename,
+                           storage: storage,
+                           backup_id: vmid,
+                           backup_type: type,
+                       });
+                       win.show();
+                       win.on('destroy', reload);
+                   }
+               },
+           },
+       });
+
        me.callParent();
     },
 });
diff --git a/www/manager6/window/Prune.js b/www/manager6/window/Prune.js
new file mode 100644
index 00000000..44ac8594
--- /dev/null
+++ b/www/manager6/window/Prune.js
@@ -0,0 +1,230 @@
+Ext.define('pve-prune-list', {
+    extend: 'Ext.data.Model',
+    fields: [
+       'backup-type',
+       'backup-id',
+       {
+           name: 'ctime',
+           type: 'date',
+           dateFormat: 'timestamp',
+       },
+    ],
+});
+
+Ext.define('PVE.PruneInputPanel', {
+    extend: 'Proxmox.panel.InputPanel',
+    alias: 'widget.pvePruneInputPanel',
+    mixins: ['Proxmox.Mixin.CBind'],
+
+    onGetValues: function(values) {
+       var me = this;
+
+       // the API expects a single prune-backups property string
+       let prune_opts = PVE.Parser.printPropertyString(values);
+       values = {};
+       values["prune-backups"] = prune_opts;
+       values.type = me.backup_type;
+       values.vmid = me.backup_id;
+
+       return values;
+    },
+
+    controller: {
+       xclass: 'Ext.app.ViewController',
+
+       init: function(view) {
+           if (!view.url) {
+               throw "no url specified";
+           }
+           if (!view.backup_type) {
+               throw "no backup_type specified";
+           }
+           if (!view.backup_id) {
+               throw "no backup_id specified";
+           }
+
+           this.reload(); // initial load
+       },
+
+       reload: function() {
+           var view = this.getView();
+
+           let params = view.getValues();
+
+           Proxmox.Utils.API2Request({
+               url: view.url,
+               method: "GET",
+               params: params,
+               callback: function() {
+                   return; // for easy breakpoint setting
+               },
+               failure: function(response, opts) {
+                   Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+               },
+               success: function(response, options) {
+                   var data = response.result.data;
+                   view.pruneStore.setData(data);
+               },
+           });
+       },
+
+       control: {
+           field: { change: 'reload' },
+       },
+    },
+
+    column1: [
+       {
+           xtype: 'proxmoxintegerfield',
+           name: 'keep-last',
+           allowBlank: true,
+           fieldLabel: gettext('keep-last'),
+           value: 1,
+           minValue: 1,
+       },
+       {
+           xtype: 'proxmoxintegerfield',
+           name: 'keep-hourly',
+           allowBlank: true,
+           fieldLabel: gettext('keep-hourly'),
+           minValue: 1,
+       },
+       {
+           xtype: 'proxmoxintegerfield',
+           name: 'keep-daily',
+           allowBlank: true,
+           fieldLabel: gettext('keep-daily'),
+           minValue: 1,
+       },
+       {
+           xtype: 'proxmoxintegerfield',
+           name: 'keep-weekly',
+           allowBlank: true,
+           fieldLabel: gettext('keep-weekly'),
+           minValue: 1,
+       },
+       {
+           xtype: 'proxmoxintegerfield',
+           name: 'keep-monthly',
+           allowBlank: true,
+           fieldLabel: gettext('keep-monthly'),
+           minValue: 1,
+       },
+       {
+           xtype: 'proxmoxintegerfield',
+           name: 'keep-yearly',
+           allowBlank: true,
+           fieldLabel: gettext('keep-yearly'),
+           minValue: 1,
+       },
+    ],
+
+    initComponent: function() {
+        var me = this;
+
+       me.pruneStore = Ext.create('Ext.data.Store', {
+           model: 'pve-prune-list',
+           sorters: { property: 'ctime', direction: 'DESC' },
+       });
+
+       Proxmox.Utils.API2Request({
+           url: "/storage",
+           method: 'GET',
+           success: function(response, opts) {
+               let scfg = response.result.data.find(x => x.storage === 
me.storage);
+               if (!scfg || !scfg["prune-backups"]) {
+                   return;
+               }
+               let prune_opts = 
PVE.Parser.parsePropertyString(scfg["prune-backups"]);
+               me.setValues(prune_opts);
+           },
+       });
+
+       me.column2 = [
+           {
+               xtype: 'grid',
+               height: 200,
+               store: me.pruneStore,
+               columns: [
+                   {
+                       header: gettext('Backup Time'),
+                       sortable: true,
+                       dataIndex: 'ctime',
+                       renderer: function(value, metaData, record) {
+                           let text = Ext.Date.format(value, 'Y-m-d H:i:s');
+                           if (record.data.mark === 'remove') {
+                               return '<div style="text-decoration: 
line-through;">'+ text +'</div>';
+                           } else {
+                               return text;
+                           }
+                       },
+                       flex: 1,
+                   },
+                   {
+                       text: "keep",
+                       dataIndex: 'mark',
+                   },
+               ],
+           },
+       ];
+
+       me.callParent();
+    },
+});
+
+Ext.define('PVE.window.Prune', {
+    extend: 'Proxmox.window.Edit',
+
+    method: 'DELETE',
+    submitText: gettext("Prune"),
+
+    isCreate: true,
+
+    initComponent: function() {
+        var me = this;
+
+       if (!me.nodename) {
+           throw "no nodename specified";
+       }
+       if (!me.storage) {
+           throw "no storage specified";
+       }
+       if (!me.backup_type) {
+           throw "no backup_type specified";
+       }
+       if (!me.backup_id) {
+           throw "no backup_id specified";
+       }
+
+       let backupGroupStr = me.backup_type + '/' + me.backup_id;
+
+       if (me.backup_type === 'CT') {
+           me.backup_type = 'lxc';
+       } else if (me.backup_type === 'VM') {
+           me.backup_type = 'qemu';
+       } else {
+           throw "unknown backup type";
+       }
+       let title = Ext.String.format(
+           gettext("Prune Backups for '{0}' on Storage '{1}'"),
+           backupGroupStr,
+           me.storage,
+       );
+
+       Ext.apply(me, {
+           url: '/api2/extjs/nodes/' + me.nodename + '/storage/' + me.storage 
+ "/prunebackups",
+           title: title,
+           items: [
+               {
+                   xtype: 'pvePruneInputPanel',
+                   url: '/api2/extjs/nodes/' + me.nodename + '/storage/' + 
me.storage + "/prunebackups",
+                   backup_type: me.backup_type,
+                   backup_id: me.backup_id,
+                   storage: me.storage,
+               },
+           ],
+       });
+
+       me.callParent();
+    },
+});
-- 
2.20.1



_______________________________________________
pve-devel mailing list
[email protected]
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to