public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [pve-devel] [PATCH-SERIES v2 manager] split up content view into a view for each type
@ 2020-09-16 12:50 Fabian Ebner
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 01/20] fix extension filter for upload window Fabian Ebner
                   ` (19 more replies)
  0 siblings, 20 replies; 21+ messages in thread
From: Fabian Ebner @ 2020-09-16 12:50 UTC (permalink / raw)
  To: pve-devel

The goal of doing this is to have more flexibility/cleaner code for
content-type-dependent features in the content view. Now only buttons
that are useful for each content type are displayed. And it might make
sense to display different columns for different content types, e.g.
'parent' for cloned VM/CT images. The mechanism introduced in this series
(patch #16) is not used yet, suggestions for which columns to use for
which types are welcome.

API calls might be faster if only one type of content is requested.
The obvious drawback is that there is no view with all contents anymore.

The first patch is not directly related. It fixes the extension filters
when selecting a file to upload.

The last four patches are not directly related, but group backups by backup group
and introduce the prune window, which was essentially copied from the PBS code.


Changes from v1:
    * fix extension filter for upload window
    * group backups and add prune button to the group header
    * make individual components stateful
    * better icons and text for the storage browser panel

Fabian Ebner (20):
  fix extension filter for upload window
  config panel: allow new nodes to be added later
  storage panel/browser: use insertNodes function
  add CD ROM and lxc icons for treelist-item-icon
  use separate view for each content type
  remove the now unnecessary grouping by content type
  remove the now unneccessary content type column
  content view: allow specifying title bar elements for init
  turn {nodename,storage,sm} into object variables
  add upload button conditionally
  create and use TemplateView
  create and use BackupView
  get rid of unneccessary enableFn's
  create ImageView and use it for VM and CT images
  simplify reload call
  content view: allow specifying which columns to show on init
  group backups by backup groups in backup view
  allow child classes of ContentView to specify their own listeners
  add CSS for button in grid's group header
  backup view: add prune window

 www/css/ext6-pve.css                 |  28 ++
 www/manager6/Makefile                |   4 +
 www/manager6/panel/ConfigPanel.js    |  93 ++---
 www/manager6/storage/BackupView.js   | 126 +++++++
 www/manager6/storage/Browser.js      |  97 ++++-
 www/manager6/storage/ContentView.js  | 539 ++++++---------------------
 www/manager6/storage/ImageView.js    |  74 ++++
 www/manager6/storage/TemplateView.js | 215 +++++++++++
 www/manager6/window/Prune.js         | 230 ++++++++++++
 9 files changed, 934 insertions(+), 472 deletions(-)
 create mode 100644 www/manager6/storage/BackupView.js
 create mode 100644 www/manager6/storage/ImageView.js
 create mode 100644 www/manager6/storage/TemplateView.js
 create mode 100644 www/manager6/window/Prune.js

-- 
2.20.1





^ permalink raw reply	[flat|nested] 21+ messages in thread

* [pve-devel] [PATCH v2 manager 01/20] fix extension filter for upload window
  2020-09-16 12:50 [pve-devel] [PATCH-SERIES v2 manager] split up content view into a view for each type Fabian Ebner
@ 2020-09-16 12:50 ` Fabian Ebner
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 02/20] config panel: allow new nodes to be added later Fabian Ebner
                   ` (18 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Fabian Ebner @ 2020-09-16 12:50 UTC (permalink / raw)
  To: pve-devel

so that it selects the correct filter for container templates

Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---

new in v2

 www/manager6/storage/ContentView.js | 43 ++++++++++++++++++++---------
 1 file changed, 30 insertions(+), 13 deletions(-)

diff --git a/www/manager6/storage/ContentView.js b/www/manager6/storage/ContentView.js
index 194ad42e..9e710d3a 100644
--- a/www/manager6/storage/ContentView.js
+++ b/www/manager6/storage/ContentView.js
@@ -193,6 +193,30 @@ Ext.define('PVE.storage.Upload', {
 	    hidden: true
 	});
 
+	let acceptedExtensions = {
+	    iso: ".img, .iso",
+	    vztmpl: ".tar.gz, .tar.xz",
+	};
+
+	let defaultContent = me.contents[0] || '';
+
+	let fileField = Ext.create('Ext.form.field.File', {
+	    name: 'filename',
+	    buttonText: gettext('Select File...'),
+	    allowBlank: false,
+	    setAccept: function(content) {
+		let acceptString = acceptedExtensions[content] || '';
+		this.fileInputEl.set({
+		    accept: acceptString,
+		});
+	    },
+	    listeners: {
+		afterrender: function(cmp) {
+		    cmp.setAccept(defaultContent);
+		},
+	    },
+	});
+
 	me.formPanel = Ext.create('Ext.form.Panel', {
 	    method: 'POST',
 	    waitMsgTarget: true,
@@ -209,22 +233,15 @@ Ext.define('PVE.storage.Upload', {
 		    cts: me.contents,
 		    fieldLabel: gettext('Content'),
 		    name: 'content',
-		    value: me.contents[0] || '',
-		    allowBlank: false
-		},
-		{
-		    xtype: 'filefield',
-		    name: 'filename',
-		    buttonText: gettext('Select File...'),
+		    value: defaultContent,
 		    allowBlank: false,
 		    listeners: {
-			afterrender: function(cmp) {
-			    cmp.fileInputEl.set({
-				accept: '.img, .iso'
-			    });
-			}
-		    }
+			change: function(cmp, newValue, oldValue) {
+			    fileField.setAccept(newValue);
+			},
+		    },
 		},
+		fileField,
 		pbar
 	    ]
 	});
-- 
2.20.1





^ permalink raw reply	[flat|nested] 21+ messages in thread

* [pve-devel] [PATCH v2 manager 02/20] config panel: allow new nodes to be added later
  2020-09-16 12:50 [pve-devel] [PATCH-SERIES v2 manager] split up content view into a view for each type Fabian Ebner
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 01/20] fix extension filter for upload window Fabian Ebner
@ 2020-09-16 12:50 ` Fabian Ebner
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 03/20] storage panel/browser: use insertNodes function Fabian Ebner
                   ` (17 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Fabian Ebner @ 2020-09-16 12:50 UTC (permalink / raw)
  To: pve-devel

in preparation for dynamically loading nodes for content-type-specific views.

Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---
 www/manager6/panel/ConfigPanel.js | 93 +++++++++++++++++--------------
 1 file changed, 50 insertions(+), 43 deletions(-)

diff --git a/www/manager6/panel/ConfigPanel.js b/www/manager6/panel/ConfigPanel.js
index 4356c24e..fabf9108 100644
--- a/www/manager6/panel/ConfigPanel.js
+++ b/www/manager6/panel/ConfigPanel.js
@@ -227,48 +227,7 @@ Ext.define('PVE.panel.Config', {
 	    }
 	});
 	var root = me.store.getRoot();
-	me.items.forEach(function(item){
-	    var treeitem = Ext.create('Ext.data.TreeModel',{
-		id: item.itemId,
-		text: item.title,
-		iconCls: item.iconCls,
-		leaf: true,
-		expanded: item.expandedOnInit
-	    });
-	    item.header = false;
-	    if (me.savedItems[item.itemId] !== undefined) {
-		throw "itemId already exists, please use another";
-	    }
-	    me.savedItems[item.itemId] = item;
-
-	    var group;
-	    var curnode = root;
-
-	    // get/create the group items
-	    while (Ext.isArray(item.groups) && item.groups.length > 0) {
-		group = item.groups.shift();
-
-		var child = curnode.findChild('id', group);
-		if (child === null) {
-		    // did not find the group item
-		    // so add it where we are
-		    break;
-		}
-		curnode = child;
-	    }
-
-	    // insert the item
-
-	    // lets see if it already exists
-	    var node = curnode.findChild('id', item.itemId);
-
-	    if (node === null) {
-		curnode.appendChild(treeitem);
-	    } else {
-		// should not happen!
-		throw "id already exists";
-	    }
-	});
+	me.insertNodes(me.items);
 
 	delete me.items;
 	me.defaults = me.defaults || {};
@@ -310,5 +269,53 @@ Ext.define('PVE.panel.Config', {
 	if (stateid) {
 	    me.mon(me.sp, 'statechange', statechange);
 	}
-    }
+    },
+
+    insertNodes: function(items) {
+	var me = this;
+	var root = me.store.getRoot();
+
+	items.forEach(function(item) {
+	    var treeitem = Ext.create('Ext.data.TreeModel',{
+		id: item.itemId,
+		text: item.title,
+		iconCls: item.iconCls,
+		leaf: true,
+		expanded: item.expandedOnInit
+	    });
+	    item.header = false;
+	    if (me.savedItems[item.itemId] !== undefined) {
+		throw "itemId already exists, please use another";
+	    }
+	    me.savedItems[item.itemId] = item;
+
+	    var group;
+	    var curnode = root;
+
+	    // get/create the group items
+	    while (Ext.isArray(item.groups) && item.groups.length > 0) {
+		group = item.groups.shift();
+
+		var child = curnode.findChild('id', group);
+		if (child === null) {
+		    // did not find the group item
+		    // so add it where we are
+		    break;
+		}
+		curnode = child;
+	    }
+
+	    // insert the item
+
+	    // lets see if it already exists
+	    var node = curnode.findChild('id', item.itemId);
+
+	    if (node === null) {
+		curnode.appendChild(treeitem);
+	    } else {
+		// should not happen!
+		throw "id already exists";
+	    }
+	});
+    },
 });
-- 
2.20.1





^ permalink raw reply	[flat|nested] 21+ messages in thread

* [pve-devel] [PATCH v2 manager 03/20] storage panel/browser: use insertNodes function
  2020-09-16 12:50 [pve-devel] [PATCH-SERIES v2 manager] split up content view into a view for each type Fabian Ebner
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 01/20] fix extension filter for upload window Fabian Ebner
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 02/20] config panel: allow new nodes to be added later Fabian Ebner
@ 2020-09-16 12:50 ` Fabian Ebner
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 04/20] add CD ROM and lxc icons for treelist-item-icon Fabian Ebner
                   ` (16 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Fabian Ebner @ 2020-09-16 12:50 UTC (permalink / raw)
  To: pve-devel

in preparation for dynamically loading nodes for content-type-specific views.

Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---
 www/manager6/storage/Browser.js | 35 +++++++++++++++++++--------------
 1 file changed, 20 insertions(+), 15 deletions(-)

diff --git a/www/manager6/storage/Browser.js b/www/manager6/storage/Browser.js
index e93aa8de..7537bdf1 100644
--- a/www/manager6/storage/Browser.js
+++ b/www/manager6/storage/Browser.js
@@ -35,27 +35,32 @@ Ext.define('PVE.storage.Browser', {
 	    hstateid: 'storagetab'
 	});
 
+	// call here, so there is a root for insertNodes()
+	me.callParent();
+
 	if (caps.storage['Datastore.Allocate'] ||
 	    caps.storage['Datastore.AllocateSpace'] ||
 	    caps.storage['Datastore.Audit']) {
-	    me.items.push({
-		xtype: 'pveStorageContentView',
-		title: gettext('Content'),
-		iconCls: 'fa fa-th',
-		itemId: 'content'
-	    });
+	    me.insertNodes([
+		{
+		    xtype: 'pveStorageContentView',
+		    title: gettext('Content'),
+		    iconCls: 'fa fa-th',
+		    itemId: 'content'
+		},
+	    ]);
 	}
 
 	if (caps.storage['Permissions.Modify']) {
-	    me.items.push({
-		xtype: 'pveACLView',
-		title: gettext('Permissions'),
-		iconCls: 'fa fa-unlock',
-		itemId: 'permissions',
-		path: '/storage/' + storeid
-	    });
+	    me.insertNodes([
+		{
+		    xtype: 'pveACLView',
+		    title: gettext('Permissions'),
+		    iconCls: 'fa fa-unlock',
+		    itemId: 'permissions',
+		    path: '/storage/' + storeid
+		},
+	    ]);
 	}
-
-	me.callParent();
    }
 });
-- 
2.20.1





^ permalink raw reply	[flat|nested] 21+ messages in thread

* [pve-devel] [PATCH v2 manager 04/20] add CD ROM and lxc icons for treelist-item-icon
  2020-09-16 12:50 [pve-devel] [PATCH-SERIES v2 manager] split up content view into a view for each type Fabian Ebner
                   ` (2 preceding siblings ...)
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 03/20] storage panel/browser: use insertNodes function Fabian Ebner
@ 2020-09-16 12:50 ` Fabian Ebner
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 05/20] use separate view for each content type Fabian Ebner
                   ` (15 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Fabian Ebner @ 2020-09-16 12:50 UTC (permalink / raw)
  To: pve-devel

Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---

new in v2

 www/css/ext6-pve.css | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/www/css/ext6-pve.css b/www/css/ext6-pve.css
index a91f1aaf..a7c0750c 100644
--- a/www/css/ext6-pve.css
+++ b/www/css/ext6-pve.css
@@ -230,6 +230,16 @@
     color: #CC1800;
 }
 
+/*
+ * using background-image doesn't work for treelist-items, so use content. See:
+ * https://forum.sencha.com/forum/showthread.php?339656-extjs-6-treelist-custom-iconcls-can-not-working
+ */
+.pve-itype-treelist-item-icon-cdrom {
+    top: 50%;
+    transform: translateY(-50%);
+    content: url(../images/icon-cd.png);
+}
+
 /* the lxc template */
 .x-tree-icon-custom.lxc:after,
 .x-grid-icon-custom.lxc:after {
@@ -237,6 +247,13 @@
     background: #fff;
 }
 
+.x-treelist-item-icon.lxc:after {
+    content: "\f1b2";
+    background: #fff;
+    font-size: 0.75em;
+    margin-left: -25%;
+}
+
 /* the qemu template */
 .x-tree-icon-custom.qemu:after,
 .x-grid-icon-custom.qemu:after {
@@ -245,12 +262,14 @@
 }
 
 /* fixes background on mouseover and selected items */
+.x-treelist-item-over .lxc:after,
 .x-grid-item-over .qemu:after,
 .x-grid-item-over .lxc:after {
     background-color: #e2eff9;
     text-shadow: -1px 0px 2px #e2eff9;
 }
 
+.x-treelist-item-selected .lxc:after,
 .x-grid-item-selected .qemu:after,
 .x-grid-item-selected .lxc:after {
     background-color: #c2ddf2;
-- 
2.20.1





^ permalink raw reply	[flat|nested] 21+ messages in thread

* [pve-devel] [PATCH v2 manager 05/20] use separate view for each content type
  2020-09-16 12:50 [pve-devel] [PATCH-SERIES v2 manager] split up content view into a view for each type Fabian Ebner
                   ` (3 preceding siblings ...)
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 04/20] add CD ROM and lxc icons for treelist-item-icon Fabian Ebner
@ 2020-09-16 12:50 ` Fabian Ebner
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 06/20] remove the now unnecessary grouping by " Fabian Ebner
                   ` (14 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Fabian Ebner @ 2020-09-16 12:50 UTC (permalink / raw)
  To: pve-devel

Organized as separate "if"s to allow changing properties easily later.

The StorageContentView now serves as a parent class, so the stateId
cannot be fixed there. Instead make each individual view stateful with a
unique stateId.

statusStore is not needed anymore, now there is a single fixed content type,
and the template and upload button are disabled depending on that type.

Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---

Changes from v1:
    * make each individual view stateful
    * better text and icons

 www/manager6/storage/Browser.js     | 83 ++++++++++++++++++++++++++---
 www/manager6/storage/ContentView.js | 62 ++++++---------------
 2 files changed, 93 insertions(+), 52 deletions(-)

diff --git a/www/manager6/storage/Browser.js b/www/manager6/storage/Browser.js
index 7537bdf1..1e1be6bc 100644
--- a/www/manager6/storage/Browser.js
+++ b/www/manager6/storage/Browser.js
@@ -41,14 +41,83 @@ Ext.define('PVE.storage.Browser', {
 	if (caps.storage['Datastore.Allocate'] ||
 	    caps.storage['Datastore.AllocateSpace'] ||
 	    caps.storage['Datastore.Audit']) {
-	    me.insertNodes([
-		{
-		    xtype: 'pveStorageContentView',
-		    title: gettext('Content'),
-		    iconCls: 'fa fa-th',
-		    itemId: 'content'
+
+	    Proxmox.Utils.API2Request({
+		url: "/nodes/" + nodename + "/storage/" + storeid + "/status",
+		method: 'GET',
+		success: function(response, opts) {
+		    var contents = response.result.data.content.split(',');
+		    var items = [];
+
+		    if (contents.includes('backup')) {
+			items.push({
+			    xtype: 'pveStorageContentView',
+			    title: gettext('Backups'),
+			    iconCls: 'fa fa-floppy-o',
+			    itemId: 'contentBackup',
+			    content: 'backup',
+			    stateful: true,
+			    stateId: 'grid-storage-content-backup',
+			});
+		    }
+		    if (contents.includes('images')) {
+			items.push({
+			    xtype: 'pveStorageContentView',
+			    title: gettext('Disk Images'),
+			    iconCls: 'fa fa-hdd-o',
+			    itemId: 'contentImages',
+			    content: 'images',
+			    stateful: true,
+			    stateId: 'grid-storage-content-images',
+			});
+		    }
+		    if (contents.includes('iso')) {
+			items.push({
+			    xtype: 'pveStorageContentView',
+			    title: gettext('ISO Images'),
+			    iconCls: 'pve-itype-treelist-item-icon-cdrom',
+			    itemId: 'contentIso',
+			    content: 'iso',
+			    stateful: true,
+			    stateId: 'grid-storage-content-iso',
+			});
+		    }
+		    if (contents.includes('rootdir')) {
+			items.push({
+			    xtype: 'pveStorageContentView',
+			    title: gettext('Container Data'),
+			    iconCls: 'fa fa-hdd-o',
+			    itemId: 'contentRootdir',
+			    content: 'rootdir',
+			    stateful: true,
+			    stateId: 'grid-storage-content-rootdir',
+			});
+		    }
+		    if (contents.includes('snippets')) {
+			items.push({
+			    xtype: 'pveStorageContentView',
+			    title: gettext('Snippets'),
+			    iconCls: 'fa fa-file-code-o',
+			    itemId: 'contentSnippets',
+			    content: 'snippets',
+			    stateful: true,
+			    stateId: 'grid-storage-content-snippets',
+			});
+		    }
+		    if (contents.includes('vztmpl')) {
+			items.push({
+			    xtype: 'pveStorageContentView',
+			    title: gettext('Container Templates'),
+			    iconCls: 'fa fa-file-o lxc',
+			    itemId: 'contentVztmpl',
+			    content: 'vztmpl',
+			    stateful: true,
+			    stateId: 'grid-storage-content-vztmpl',
+			});
+		    }
+		    me.insertNodes(items);
 		},
-	    ]);
+	    });
 	}
 
 	if (caps.storage['Permissions.Modify']) {
diff --git a/www/manager6/storage/ContentView.js b/www/manager6/storage/ContentView.js
index 9e710d3a..eb101635 100644
--- a/www/manager6/storage/ContentView.js
+++ b/www/manager6/storage/ContentView.js
@@ -368,8 +368,6 @@ Ext.define('PVE.storage.ContentView', {
 
     alias: 'widget.pveStorageContentView',
 
-    stateful: true,
-    stateId: 'grid-storage-content',
     viewConfig: {
 	trackOver: false,
 	loadMask: false
@@ -393,13 +391,21 @@ Ext.define('PVE.storage.ContentView', {
 	    throw "no storage ID specified";
 	}
 
+	var content = me.content;
+	if (!content) {
+	    throw "no content type specified";
+	}
+
 	var baseurl = "/nodes/" + nodename + "/storage/" + storage + "/content";
 	var store = Ext.create('Ext.data.Store',{
 	    model: 'pve-storage-content',
 	    groupField: 'content',
 	    proxy: {
                 type: 'proxmox',
-		url: '/api2/json' + baseurl
+		url: '/api2/json' + baseurl,
+		extraParams: {
+		    content: content,
+		},
 	    },
 	    sorters: {
 		property: 'volid',
@@ -411,7 +417,6 @@ Ext.define('PVE.storage.ContentView', {
 
 	var reload = function() {
 	    store.load();
-	    me.statusStore.load();
 	};
 
 	Proxmox.Utils.monStoreErrors(me, store);
@@ -428,6 +433,9 @@ Ext.define('PVE.storage.ContentView', {
 		win.show();
 	    }
 	});
+	if (content !== 'vztmpl') {
+	    templateButton.setDisabled(true);
+	}
 
 	var uploadButton = Ext.create('Proxmox.button.Button', {
 	    contents : ['iso','vztmpl'],
@@ -443,6 +451,11 @@ Ext.define('PVE.storage.ContentView', {
 		win.on('destroy', reload);
 	    }
 	});
+	if (content === 'iso' || content === 'vztmpl') {
+	    uploadButton.contents = [content];
+	} else {
+	    uploadButton.setDisabled(true);
+	}
 
 	var imageRemoveButton;
 	var removeButton = Ext.create('Proxmox.button.StdRemoveButton',{
@@ -477,8 +490,6 @@ Ext.define('PVE.storage.ContentView', {
 		return false;
 	    },
 	    handler: function(btn, event, rec) {
-		me = this;
-
 		var url = baseurl + '/' + rec.data.volid;
 		var vmid = rec.data.vmid;
 
@@ -509,19 +520,11 @@ Ext.define('PVE.storage.ContentView', {
 		    item: { type: 'Image', id: vmid }
 		}).show();
 		win.on('destroy', function() {
-		    me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-			url: '/api2/json/nodes/' + nodename + '/storage/' + storage + '/status'
-		    });
 		    reload();
-
 		});
 	    }
 	});
 
-	me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-	    url: '/api2/json/nodes/' + nodename + '/storage/' + storage + '/status'
-	});
-
 	Ext.apply(me, {
 	    store: store,
 	    selModel: sm,
@@ -634,37 +637,6 @@ Ext.define('PVE.storage.ContentView', {
 	});
 
 	me.callParent();
-
-	// disable the buttons/restrict the upload window
-	// if templates or uploads are not allowed
-	me.mon(me.statusStore, 'load', function(s, records, success) {
-	    var availcontent = [];
-	    Ext.Array.each(records, function(item){
-		if (item.id === 'content') {
-		    availcontent = item.data.value.split(',');
-		}
-	    });
-	    var templ = false;
-	    var upload = false;
-	    var cts = [];
-
-	    Ext.Array.each(availcontent, function(content) {
-		if (content === 'vztmpl') {
-		    templ = true;
-		    cts.push('vztmpl');
-		} else if (content === 'iso') {
-		    upload = true;
-		    cts.push('iso');
-		}
-	    });
-
-	    if (templ !== upload) {
-		uploadButton.contents = cts;
-	    }
-
-	    templateButton.setDisabled(!templ);
-	    uploadButton.setDisabled(!upload && !templ);
-	});
     }
 }, function() {
 
-- 
2.20.1





^ permalink raw reply	[flat|nested] 21+ messages in thread

* [pve-devel] [PATCH v2 manager 06/20] remove the now unnecessary grouping by content type
  2020-09-16 12:50 [pve-devel] [PATCH-SERIES v2 manager] split up content view into a view for each type Fabian Ebner
                   ` (4 preceding siblings ...)
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 05/20] use separate view for each content type Fabian Ebner
@ 2020-09-16 12:50 ` Fabian Ebner
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 07/20] remove the now unneccessary content type column Fabian Ebner
                   ` (13 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Fabian Ebner @ 2020-09-16 12:50 UTC (permalink / raw)
  To: pve-devel

Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---

Changes from v1:
    * also remove the groupField in store

 www/manager6/storage/ContentView.js | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/www/manager6/storage/ContentView.js b/www/manager6/storage/ContentView.js
index eb101635..9a6c6c7a 100644
--- a/www/manager6/storage/ContentView.js
+++ b/www/manager6/storage/ContentView.js
@@ -372,12 +372,6 @@ Ext.define('PVE.storage.ContentView', {
 	trackOver: false,
 	loadMask: false
     },
-    features: [
-	{
-	    ftype: 'grouping',
-	    groupHeaderTpl: '{name} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})'
-	}
-    ],
     initComponent : function() {
 	var me = this;
 
@@ -399,7 +393,6 @@ Ext.define('PVE.storage.ContentView', {
 	var baseurl = "/nodes/" + nodename + "/storage/" + storage + "/content";
 	var store = Ext.create('Ext.data.Store',{
 	    model: 'pve-storage-content',
-	    groupField: 'content',
 	    proxy: {
                 type: 'proxmox',
 		url: '/api2/json' + baseurl,
-- 
2.20.1





^ permalink raw reply	[flat|nested] 21+ messages in thread

* [pve-devel] [PATCH v2 manager 07/20] remove the now unneccessary content type column
  2020-09-16 12:50 [pve-devel] [PATCH-SERIES v2 manager] split up content view into a view for each type Fabian Ebner
                   ` (5 preceding siblings ...)
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 06/20] remove the now unnecessary grouping by " Fabian Ebner
@ 2020-09-16 12:50 ` Fabian Ebner
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 08/20] content view: allow specifying title bar elements for init Fabian Ebner
                   ` (12 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Fabian Ebner @ 2020-09-16 12:50 UTC (permalink / raw)
  To: pve-devel

Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---

new in v2

 www/manager6/storage/ContentView.js | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/www/manager6/storage/ContentView.js b/www/manager6/storage/ContentView.js
index 9a6c6c7a..53c93944 100644
--- a/www/manager6/storage/ContentView.js
+++ b/www/manager6/storage/ContentView.js
@@ -611,12 +611,6 @@ Ext.define('PVE.storage.ContentView', {
 		    width: 100,
 		    dataIndex: 'format'
 		},
-		{
-		    header: gettext('Type'),
-		    width: 100,
-		    dataIndex: 'content',
-		    renderer: PVE.Utils.format_content_types
-		},
 		{
 		    header: gettext('Size'),
 		    width: 100,
-- 
2.20.1





^ permalink raw reply	[flat|nested] 21+ messages in thread

* [pve-devel] [PATCH v2 manager 08/20] content view: allow specifying title bar elements for init
  2020-09-16 12:50 [pve-devel] [PATCH-SERIES v2 manager] split up content view into a view for each type Fabian Ebner
                   ` (6 preceding siblings ...)
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 07/20] remove the now unneccessary content type column Fabian Ebner
@ 2020-09-16 12:50 ` Fabian Ebner
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 09/20] turn {nodename, storage, sm} into object variables Fabian Ebner
                   ` (11 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Fabian Ebner @ 2020-09-16 12:50 UTC (permalink / raw)
  To: pve-devel

in preparation to create derived classes.

Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---

use --color-moved=zebra --color-moved-ws=ignore-all-space --patience
to the make patch more readable

 www/manager6/storage/ContentView.js | 145 ++++++++++++++--------------
 1 file changed, 75 insertions(+), 70 deletions(-)

diff --git a/www/manager6/storage/ContentView.js b/www/manager6/storage/ContentView.js
index 53c93944..1218f65c 100644
--- a/www/manager6/storage/ContentView.js
+++ b/www/manager6/storage/ContentView.js
@@ -518,81 +518,86 @@ Ext.define('PVE.storage.ContentView', {
 	    }
 	});
 
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		{
-		    xtype: 'proxmoxButton',
-		    text: gettext('Restore'),
-		    selModel: sm,
-		    disabled: true,
-		    enableFn: function(rec) {
-			return rec && rec.data.content === 'backup';
-		    },
-		    handler: function(b, e, rec) {
-			var vmtype;
-			if (PVE.Utils.volume_is_qemu_backup(rec.data.volid, rec.data.format)) {
-			    vmtype = 'qemu';
-			} else if (PVE.Utils.volume_is_lxc_backup(rec.data.volid, rec.data.format)) {
-			    vmtype = 'lxc';
-			} else {
-			    return;
-			}
-
-			var win = Ext.create('PVE.window.Restore', {
-			    nodename: nodename,
-			    volid: rec.data.volid,
-			    volidText: PVE.Utils.render_storage_content(rec.data.volid, {}, rec),
-			    vmtype: vmtype
-			});
-			win.show();
-			win.on('destroy', reload);
-		    }
+	if (!me.tbar) {
+	    me.tbar = [];
+	}
+	me.tbar.push(
+	    {
+		xtype: 'proxmoxButton',
+		text: gettext('Restore'),
+		selModel: sm,
+		disabled: true,
+		enableFn: function(rec) {
+		    return rec && rec.data.content === 'backup';
 		},
-		removeButton,
-		imageRemoveButton,
-		templateButton,
-		uploadButton,
-		{
-		    xtype: 'proxmoxButton',
-		    text: gettext('Show Configuration'),
-		    disabled: true,
-		    selModel: sm,
-		    enableFn: function(rec) {
-			return rec && rec.data.content === 'backup';
-		    },
-		    handler: function(b,e,rec) {
-			var win = Ext.create('PVE.window.BackupConfig', {
-			    volume: rec.data.volid,
-			    pveSelNode: me.pveSelNode
-			});
-
-			win.show();
+		handler: function(b, e, rec) {
+		    var vmtype;
+		    if (PVE.Utils.volume_is_qemu_backup(rec.data.volid, rec.data.format)) {
+			vmtype = 'qemu';
+		    } else if (PVE.Utils.volume_is_lxc_backup(rec.data.volid, rec.data.format)) {
+			vmtype = 'lxc';
+		    } else {
+			return;
 		    }
+
+		    var win = Ext.create('PVE.window.Restore', {
+			nodename: nodename,
+			volid: rec.data.volid,
+			volidText: PVE.Utils.render_storage_content(rec.data.volid, {}, rec),
+			vmtype: vmtype
+		    });
+		    win.show();
+		    win.on('destroy', reload);
+		}
+	    },
+	    removeButton,
+	    imageRemoveButton,
+	    templateButton,
+	    uploadButton,
+	    {
+		xtype: 'proxmoxButton',
+		text: gettext('Show Configuration'),
+		disabled: true,
+		selModel: sm,
+		enableFn: function(rec) {
+		    return rec && rec.data.content === 'backup';
 		},
-		'->',
-		gettext('Search') + ':', ' ',
-		{
-		    xtype: 'textfield',
-		    width: 200,
-		    enableKeyEvents: true,
-		    listeners: {
-			buffer: 500,
-			keyup: function(field) {
-			    store.clearFilter(true);
-			    store.filter([
-				{
-				    property: 'text',
-				    value: field.getValue(),
-				    anyMatch: true,
-				    caseSensitive: false
-				}
-			    ]);
-			}
+		handler: function(b,e,rec) {
+		    var win = Ext.create('PVE.window.BackupConfig', {
+			volume: rec.data.volid,
+			pveSelNode: me.pveSelNode
+		    });
+
+		    win.show();
+		}
+	    },
+	    '->',
+	    gettext('Search') + ':', ' ',
+	    {
+		xtype: 'textfield',
+		width: 200,
+		enableKeyEvents: true,
+		listeners: {
+		    buffer: 500,
+		    keyup: function(field) {
+			store.clearFilter(true);
+			store.filter([
+			    {
+				property: 'text',
+				value: field.getValue(),
+				anyMatch: true,
+				caseSensitive: false
+			    }
+			]);
 		    }
 		}
-	    ],
+	    }
+	);
+
+	Ext.apply(me, {
+	    store: store,
+	    selModel: sm,
+	    tbar: me.tbar,
 	    columns: [
 		{
 		    header: gettext('Name'),
-- 
2.20.1





^ permalink raw reply	[flat|nested] 21+ messages in thread

* [pve-devel] [PATCH v2 manager 09/20] turn {nodename, storage, sm} into object variables
  2020-09-16 12:50 [pve-devel] [PATCH-SERIES v2 manager] split up content view into a view for each type Fabian Ebner
                   ` (7 preceding siblings ...)
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 08/20] content view: allow specifying title bar elements for init Fabian Ebner
@ 2020-09-16 12:50 ` Fabian Ebner
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 10/20] add upload button conditionally Fabian Ebner
                   ` (10 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Fabian Ebner @ 2020-09-16 12:50 UTC (permalink / raw)
  To: pve-devel

so they can be used and specified in derived classes.

Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---
 www/manager6/storage/ContentView.js | 25 +++++++++++++++++--------
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/www/manager6/storage/ContentView.js b/www/manager6/storage/ContentView.js
index 1218f65c..6e7ae630 100644
--- a/www/manager6/storage/ContentView.js
+++ b/www/manager6/storage/ContentView.js
@@ -375,15 +375,21 @@ Ext.define('PVE.storage.ContentView', {
     initComponent : function() {
 	var me = this;
 
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
+	if (!me.nodename) {
+	    me.nodename = me.pveSelNode.data.node;
+	    if (!me.nodename) {
+		throw "no node name specified";
+	    }
 	}
+	var nodename = me.nodename;
 
-	var storage = me.pveSelNode.data.storage;
-	if (!storage) {
-	    throw "no storage ID specified";
+	if (!me.storage) {
+	    me.storage = me.pveSelNode.data.storage;
+	    if (!me.storage) {
+		throw "no storage ID specified";
+	    }
 	}
+	var storage = me.storage;
 
 	var content = me.content;
 	if (!content) {
@@ -391,7 +397,7 @@ Ext.define('PVE.storage.ContentView', {
 	}
 
 	var baseurl = "/nodes/" + nodename + "/storage/" + storage + "/content";
-	var store = Ext.create('Ext.data.Store',{
+	var store = me.store = Ext.create('Ext.data.Store', {
 	    model: 'pve-storage-content',
 	    proxy: {
                 type: 'proxmox',
@@ -406,7 +412,10 @@ Ext.define('PVE.storage.ContentView', {
 	    }
 	});
 
-	var sm = Ext.create('Ext.selection.RowModel', {});
+	if (!me.sm) {
+	    me.sm = Ext.create('Ext.selection.RowModel', {});
+	}
+	var sm = me.sm;
 
 	var reload = function() {
 	    store.load();
-- 
2.20.1





^ permalink raw reply	[flat|nested] 21+ messages in thread

* [pve-devel] [PATCH v2 manager 10/20] add upload button conditionally
  2020-09-16 12:50 [pve-devel] [PATCH-SERIES v2 manager] split up content view into a view for each type Fabian Ebner
                   ` (8 preceding siblings ...)
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 09/20] turn {nodename, storage, sm} into object variables Fabian Ebner
@ 2020-09-16 12:50 ` Fabian Ebner
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 11/20] create and use TemplateView Fabian Ebner
                   ` (9 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Fabian Ebner @ 2020-09-16 12:50 UTC (permalink / raw)
  To: pve-devel

Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---
 www/manager6/storage/Browser.js     |  2 ++
 www/manager6/storage/ContentView.js | 13 ++++---------
 2 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/www/manager6/storage/Browser.js b/www/manager6/storage/Browser.js
index 1e1be6bc..6e455625 100644
--- a/www/manager6/storage/Browser.js
+++ b/www/manager6/storage/Browser.js
@@ -80,6 +80,7 @@ Ext.define('PVE.storage.Browser', {
 			    content: 'iso',
 			    stateful: true,
 			    stateId: 'grid-storage-content-iso',
+			    useUploadButton: true,
 			});
 		    }
 		    if (contents.includes('rootdir')) {
@@ -113,6 +114,7 @@ Ext.define('PVE.storage.Browser', {
 			    content: 'vztmpl',
 			    stateful: true,
 			    stateId: 'grid-storage-content-vztmpl',
+			    useUploadButton: true,
 			});
 		    }
 		    me.insertNodes(items);
diff --git a/www/manager6/storage/ContentView.js b/www/manager6/storage/ContentView.js
index 6e7ae630..dfc98a05 100644
--- a/www/manager6/storage/ContentView.js
+++ b/www/manager6/storage/ContentView.js
@@ -440,24 +440,17 @@ Ext.define('PVE.storage.ContentView', {
 	}
 
 	var uploadButton = Ext.create('Proxmox.button.Button', {
-	    contents : ['iso','vztmpl'],
 	    text: gettext('Upload'),
 	    handler: function() {
-		var me = this;
 		var win = Ext.create('PVE.storage.Upload', {
 		    nodename: nodename,
 		    storage: storage,
-		    contents: me.contents
+		    contents: [content],
 		});
 		win.show();
 		win.on('destroy', reload);
 	    }
 	});
-	if (content === 'iso' || content === 'vztmpl') {
-	    uploadButton.contents = [content];
-	} else {
-	    uploadButton.setDisabled(true);
-	}
 
 	var imageRemoveButton;
 	var removeButton = Ext.create('Proxmox.button.StdRemoveButton',{
@@ -530,6 +523,9 @@ Ext.define('PVE.storage.ContentView', {
 	if (!me.tbar) {
 	    me.tbar = [];
 	}
+	if (me.useUploadButton) {
+	    me.tbar.push(uploadButton);
+	}
 	me.tbar.push(
 	    {
 		xtype: 'proxmoxButton',
@@ -562,7 +558,6 @@ Ext.define('PVE.storage.ContentView', {
 	    removeButton,
 	    imageRemoveButton,
 	    templateButton,
-	    uploadButton,
 	    {
 		xtype: 'proxmoxButton',
 		text: gettext('Show Configuration'),
-- 
2.20.1





^ permalink raw reply	[flat|nested] 21+ messages in thread

* [pve-devel] [PATCH v2 manager 11/20] create and use TemplateView
  2020-09-16 12:50 [pve-devel] [PATCH-SERIES v2 manager] split up content view into a view for each type Fabian Ebner
                   ` (9 preceding siblings ...)
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 10/20] add upload button conditionally Fabian Ebner
@ 2020-09-16 12:50 ` Fabian Ebner
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 12/20] create and use BackupView Fabian Ebner
                   ` (8 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Fabian Ebner @ 2020-09-16 12:50 UTC (permalink / raw)
  To: pve-devel

Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---
 www/manager6/Makefile                |   1 +
 www/manager6/storage/Browser.js      |   6 +-
 www/manager6/storage/ContentView.js  | 184 -----------------------
 www/manager6/storage/TemplateView.js | 215 +++++++++++++++++++++++++++
 4 files changed, 217 insertions(+), 189 deletions(-)
 create mode 100644 www/manager6/storage/TemplateView.js

diff --git a/www/manager6/Makefile b/www/manager6/Makefile
index 4288acdd..cece0aae 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -232,6 +232,7 @@ JSSRC= 							\
 	storage/RBDEdit.js				\
 	storage/StatusView.js				\
 	storage/Summary.js				\
+	storage/TemplateView.js				\
 	storage/ZFSEdit.js				\
 	storage/ZFSPoolEdit.js				\
 	tree/ResourceTree.js				\
diff --git a/www/manager6/storage/Browser.js b/www/manager6/storage/Browser.js
index 6e455625..468adae1 100644
--- a/www/manager6/storage/Browser.js
+++ b/www/manager6/storage/Browser.js
@@ -107,14 +107,10 @@ Ext.define('PVE.storage.Browser', {
 		    }
 		    if (contents.includes('vztmpl')) {
 			items.push({
-			    xtype: 'pveStorageContentView',
+			    xtype: 'pveStorageTemplateView',
 			    title: gettext('Container Templates'),
 			    iconCls: 'fa fa-file-o lxc',
 			    itemId: 'contentVztmpl',
-			    content: 'vztmpl',
-			    stateful: true,
-			    stateId: 'grid-storage-content-vztmpl',
-			    useUploadButton: true,
 			});
 		    }
 		    me.insertNodes(items);
diff --git a/www/manager6/storage/ContentView.js b/www/manager6/storage/ContentView.js
index dfc98a05..5f84789e 100644
--- a/www/manager6/storage/ContentView.js
+++ b/www/manager6/storage/ContentView.js
@@ -1,170 +1,3 @@
-Ext.define('PVE.grid.TemplateSelector', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: 'widget.pveTemplateSelector',
-
-    stateful: true,
-    stateId: 'grid-template-selector',
-    viewConfig: {
-	trackOver: false
-    },
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var baseurl = "/nodes/" + me.nodename + "/aplinfo";
-	var store = new Ext.data.Store({
-	    model: 'pve-aplinfo',
-	    groupField: 'section',
-	    proxy: {
-                type: 'proxmox',
-		url: '/api2/json' + baseurl
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var groupingFeature = Ext.create('Ext.grid.feature.Grouping',{
-            groupHeaderTpl: '{[ "Section: " + values.name ]} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})'
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		'->',
-		gettext('Search'),
-		{
-		    xtype: 'textfield',
-		    width: 200,
-		    enableKeyEvents: true,
-		    listeners: {
-			buffer: 500,
-			keyup: function(field) {
-			    var value = field.getValue().toLowerCase();
-			    store.clearFilter(true);
-			    store.filterBy(function(rec) {
-				return (rec.data['package'].toLowerCase().indexOf(value) !== -1)
-				|| (rec.data.headline.toLowerCase().indexOf(value) !== -1);
-			    });
-			}
-		    }
-		}
-	    ],
-	    features: [ groupingFeature ],
-	    columns: [
-		{
-		    header: gettext('Type'),
-		    width: 80,
-		    dataIndex: 'type'
-		},
-		{
-		    header: gettext('Package'),
-		    flex: 1,
-		    dataIndex: 'package'
-		},
-		{
-		    header: gettext('Version'),
-		    width: 80,
-		    dataIndex: 'version'
-		},
-		{
-		    header: gettext('Description'),
-		    flex: 1.5,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'headline'
-		}
-	    ],
-	    listeners: {
-		afterRender: reload
-	    }
-	});
-
-	me.callParent();
-    }
-
-}, function() {
-
-    Ext.define('pve-aplinfo', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'template', 'type', 'package', 'version', 'headline', 'infopage',
-	    'description', 'os', 'section'
-	],
-	idProperty: 'template'
-    });
-
-});
-
-Ext.define('PVE.storage.TemplateDownload', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.pveTemplateDownload',
-
-    modal: true,
-    title: gettext('Templates'),
-    layout: 'fit',
-    width: 900,
-    height: 600,
-    initComponent : function() {
-        var me = this;
-
-	var grid = Ext.create('PVE.grid.TemplateSelector', {
-	    border: false,
-	    scrollable: true,
-	    nodename: me.nodename
-	});
-
-	var sm = grid.getSelectionModel();
-
-	var submitBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Download'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: function(button, event, rec) {
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/aplinfo',
-		    params: {
-			storage: me.storage,
-			template: rec.data.template
-		    },
-		    method: 'POST',
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-
-			Ext.create('Proxmox.window.TaskViewer', {
-			    upid: upid,
-			    listeners: {
-				destroy: me.reloadGrid
-			    }
-			}).show();
-
-			me.close();
-		    }
-		});
-	    }
-	});
-
-        Ext.apply(me, {
-	    items: grid,
-	    buttons: [ submitBtn ]
-	});
-
-	me.callParent();
-    }
-});
-
 Ext.define('PVE.storage.Upload', {
     extend: 'Ext.window.Window',
     alias: 'widget.pveStorageUpload',
@@ -423,22 +256,6 @@ Ext.define('PVE.storage.ContentView', {
 
 	Proxmox.Utils.monStoreErrors(me, store);
 
-	var templateButton = Ext.create('Proxmox.button.Button',{
-	    itemId: 'tmpl-btn',
-	    text: gettext('Templates'),
-	    handler: function() {
-		var win = Ext.create('PVE.storage.TemplateDownload', {
-		    nodename: nodename,
-		    storage: storage,
-		    reloadGrid: reload
-		});
-		win.show();
-	    }
-	});
-	if (content !== 'vztmpl') {
-	    templateButton.setDisabled(true);
-	}
-
 	var uploadButton = Ext.create('Proxmox.button.Button', {
 	    text: gettext('Upload'),
 	    handler: function() {
@@ -557,7 +374,6 @@ Ext.define('PVE.storage.ContentView', {
 	    },
 	    removeButton,
 	    imageRemoveButton,
-	    templateButton,
 	    {
 		xtype: 'proxmoxButton',
 		text: gettext('Show Configuration'),
diff --git a/www/manager6/storage/TemplateView.js b/www/manager6/storage/TemplateView.js
new file mode 100644
index 00000000..8500ca21
--- /dev/null
+++ b/www/manager6/storage/TemplateView.js
@@ -0,0 +1,215 @@
+Ext.define('PVE.grid.TemplateSelector', {
+    extend: 'Ext.grid.GridPanel',
+
+    alias: 'widget.pveTemplateSelector',
+
+    stateful: true,
+    stateId: 'grid-template-selector',
+    viewConfig: {
+	trackOver: false
+    },
+    initComponent : function() {
+	var me = this;
+
+	if (!me.nodename) {
+	    throw "no node name specified";
+	}
+
+	var baseurl = "/nodes/" + me.nodename + "/aplinfo";
+	var store = new Ext.data.Store({
+	    model: 'pve-aplinfo',
+	    groupField: 'section',
+	    proxy: {
+                type: 'proxmox',
+		url: '/api2/json' + baseurl
+	    }
+	});
+
+	var sm = Ext.create('Ext.selection.RowModel', {});
+
+	var groupingFeature = Ext.create('Ext.grid.feature.Grouping',{
+            groupHeaderTpl: '{[ "Section: " + values.name ]} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})'
+	});
+
+	var reload = function() {
+	    store.load();
+	};
+
+	Proxmox.Utils.monStoreErrors(me, store);
+
+	Ext.apply(me, {
+	    store: store,
+	    selModel: sm,
+	    tbar: [
+		'->',
+		gettext('Search'),
+		{
+		    xtype: 'textfield',
+		    width: 200,
+		    enableKeyEvents: true,
+		    listeners: {
+			buffer: 500,
+			keyup: function(field) {
+			    var value = field.getValue().toLowerCase();
+			    store.clearFilter(true);
+			    store.filterBy(function(rec) {
+				return (rec.data['package'].toLowerCase().indexOf(value) !== -1)
+				|| (rec.data.headline.toLowerCase().indexOf(value) !== -1);
+			    });
+			}
+		    }
+		}
+	    ],
+	    features: [ groupingFeature ],
+	    columns: [
+		{
+		    header: gettext('Type'),
+		    width: 80,
+		    dataIndex: 'type'
+		},
+		{
+		    header: gettext('Package'),
+		    flex: 1,
+		    dataIndex: 'package'
+		},
+		{
+		    header: gettext('Version'),
+		    width: 80,
+		    dataIndex: 'version'
+		},
+		{
+		    header: gettext('Description'),
+		    flex: 1.5,
+		    renderer: Ext.String.htmlEncode,
+		    dataIndex: 'headline'
+		}
+	    ],
+	    listeners: {
+		afterRender: reload
+	    }
+	});
+
+	me.callParent();
+    }
+
+}, function() {
+
+    Ext.define('pve-aplinfo', {
+	extend: 'Ext.data.Model',
+	fields: [
+	    'template', 'type', 'package', 'version', 'headline', 'infopage',
+	    'description', 'os', 'section'
+	],
+	idProperty: 'template'
+    });
+
+});
+
+Ext.define('PVE.storage.TemplateDownload', {
+    extend: 'Ext.window.Window',
+    alias: 'widget.pveTemplateDownload',
+
+    modal: true,
+    title: gettext('Templates'),
+    layout: 'fit',
+    width: 900,
+    height: 600,
+    initComponent : function() {
+        var me = this;
+
+	var grid = Ext.create('PVE.grid.TemplateSelector', {
+	    border: false,
+	    scrollable: true,
+	    nodename: me.nodename
+	});
+
+	var sm = grid.getSelectionModel();
+
+	var submitBtn = Ext.create('Proxmox.button.Button', {
+	    text: gettext('Download'),
+	    disabled: true,
+	    selModel: sm,
+	    handler: function(button, event, rec) {
+		Proxmox.Utils.API2Request({
+		    url: '/nodes/' + me.nodename + '/aplinfo',
+		    params: {
+			storage: me.storage,
+			template: rec.data.template
+		    },
+		    method: 'POST',
+		    failure: function (response, opts) {
+			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+		    },
+		    success: function(response, options) {
+			var upid = response.result.data;
+
+			Ext.create('Proxmox.window.TaskViewer', {
+			    upid: upid,
+			    listeners: {
+				destroy: me.reloadGrid
+			    }
+			}).show();
+
+			me.close();
+		    }
+		});
+	    }
+	});
+
+        Ext.apply(me, {
+	    items: grid,
+	    buttons: [ submitBtn ]
+	});
+
+	me.callParent();
+    }
+});
+
+Ext.define('PVE.storage.TemplateView', {
+    extend: 'PVE.storage.ContentView',
+
+    alias: 'widget.pveStorageTemplateView',
+
+    stateful: true,
+    stateId: 'grid-storage-content-vztmpl',
+
+    initComponent: function() {
+	var me = this;
+
+	var nodename = me.nodename = me.pveSelNode.data.node;
+	if (!nodename) {
+	    throw "no node name specified";
+	}
+
+	var storage = me.storage = me.pveSelNode.data.storage;
+	if (!storage) {
+	    throw "no storage ID specified";
+	}
+
+	me.content = 'vztmpl';
+
+	var sm = me.sm = Ext.create('Ext.selection.RowModel', {});
+
+	var reload = function() {
+	    me.store.load();
+	}
+
+	var templateButton = Ext.create('Proxmox.button.Button',{
+	    itemId: 'tmpl-btn',
+	    text: gettext('Templates'),
+	    handler: function() {
+		var win = Ext.create('PVE.storage.TemplateDownload', {
+		    nodename: nodename,
+		    storage: storage,
+		    reloadGrid: reload
+		});
+		win.show();
+	    }
+	});
+
+	me.tbar = [ templateButton ];
+	me.useUploadButton = true;
+
+	me.callParent();
+    },
+});
-- 
2.20.1





^ permalink raw reply	[flat|nested] 21+ messages in thread

* [pve-devel] [PATCH v2 manager 12/20] create and use BackupView
  2020-09-16 12:50 [pve-devel] [PATCH-SERIES v2 manager] split up content view into a view for each type Fabian Ebner
                   ` (10 preceding siblings ...)
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 11/20] create and use TemplateView Fabian Ebner
@ 2020-09-16 12:50 ` Fabian Ebner
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 13/20] get rid of unneccessary enableFn's Fabian Ebner
                   ` (7 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Fabian Ebner @ 2020-09-16 12:50 UTC (permalink / raw)
  To: pve-devel

Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---
 www/manager6/Makefile               |  1 +
 www/manager6/storage/BackupView.js  | 80 +++++++++++++++++++++++++++++
 www/manager6/storage/Browser.js     |  5 +-
 www/manager6/storage/ContentView.js | 45 ----------------
 4 files changed, 82 insertions(+), 49 deletions(-)
 create mode 100644 www/manager6/storage/BackupView.js

diff --git a/www/manager6/Makefile b/www/manager6/Makefile
index cece0aae..26c91bef 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -217,6 +217,7 @@ JSSRC= 							\
 	sdn/zones/SimpleEdit.js				\
 	sdn/zones/VlanEdit.js				\
 	sdn/zones/VxlanEdit.js				\
+	storage/BackupView.js				\
 	storage/Base.js					\
 	storage/Browser.js				\
 	storage/CIFSEdit.js				\
diff --git a/www/manager6/storage/BackupView.js b/www/manager6/storage/BackupView.js
new file mode 100644
index 00000000..57312f8f
--- /dev/null
+++ b/www/manager6/storage/BackupView.js
@@ -0,0 +1,80 @@
+Ext.define('PVE.storage.BackupView', {
+    extend: 'PVE.storage.ContentView',
+
+    alias: 'widget.pveStorageBackupView',
+
+    stateful: true,
+    stateId: 'grid-storage-content-backup',
+
+    initComponent: function() {
+	var me = this;
+
+	var nodename = me.nodename = me.pveSelNode.data.node;
+	if (!nodename) {
+	    throw "no node name specified";
+	}
+
+	var storage = me.storage = me.pveSelNode.data.storage;
+	if (!storage) {
+	    throw "no storage ID specified";
+	}
+
+	me.content = 'backup';
+
+	var sm = me.sm = Ext.create('Ext.selection.RowModel', {});
+
+	var reload = function() {
+	    me.store.load();
+	};
+
+	me.tbar = [
+	    {
+		xtype: 'proxmoxButton',
+		text: gettext('Restore'),
+		selModel: sm,
+		disabled: true,
+		enableFn: function(rec) {
+		    return rec && rec.data.content === 'backup';
+		},
+		handler: function(b, e, rec) {
+		    var vmtype;
+		    if (PVE.Utils.volume_is_qemu_backup(rec.data.volid, rec.data.format)) {
+			vmtype = 'qemu';
+		    } else if (PVE.Utils.volume_is_lxc_backup(rec.data.volid, rec.data.format)) {
+			vmtype = 'lxc';
+		    } else {
+			return;
+		    }
+
+		    var win = Ext.create('PVE.window.Restore', {
+			nodename: nodename,
+			volid: rec.data.volid,
+			volidText: PVE.Utils.render_storage_content(rec.data.volid, {}, rec),
+			vmtype: vmtype
+		    });
+		    win.show();
+		    win.on('destroy', reload);
+		}
+	    },
+	    {
+		xtype: 'proxmoxButton',
+		text: gettext('Show Configuration'),
+		disabled: true,
+		selModel: sm,
+		enableFn: function(rec) {
+		    return rec && rec.data.content === 'backup';
+		},
+		handler: function(b,e,rec) {
+		    var win = Ext.create('PVE.window.BackupConfig', {
+			volume: rec.data.volid,
+			pveSelNode: me.pveSelNode
+		    });
+
+		    win.show();
+		}
+	    },
+	];
+
+	me.callParent();
+    },
+});
diff --git a/www/manager6/storage/Browser.js b/www/manager6/storage/Browser.js
index 468adae1..53d8828c 100644
--- a/www/manager6/storage/Browser.js
+++ b/www/manager6/storage/Browser.js
@@ -51,13 +51,10 @@ Ext.define('PVE.storage.Browser', {
 
 		    if (contents.includes('backup')) {
 			items.push({
-			    xtype: 'pveStorageContentView',
+			    xtype: 'pveStorageBackupView',
 			    title: gettext('Backups'),
 			    iconCls: 'fa fa-floppy-o',
 			    itemId: 'contentBackup',
-			    content: 'backup',
-			    stateful: true,
-			    stateId: 'grid-storage-content-backup',
 			});
 		    }
 		    if (contents.includes('images')) {
diff --git a/www/manager6/storage/ContentView.js b/www/manager6/storage/ContentView.js
index 5f84789e..542b07f7 100644
--- a/www/manager6/storage/ContentView.js
+++ b/www/manager6/storage/ContentView.js
@@ -344,53 +344,8 @@ Ext.define('PVE.storage.ContentView', {
 	    me.tbar.push(uploadButton);
 	}
 	me.tbar.push(
-	    {
-		xtype: 'proxmoxButton',
-		text: gettext('Restore'),
-		selModel: sm,
-		disabled: true,
-		enableFn: function(rec) {
-		    return rec && rec.data.content === 'backup';
-		},
-		handler: function(b, e, rec) {
-		    var vmtype;
-		    if (PVE.Utils.volume_is_qemu_backup(rec.data.volid, rec.data.format)) {
-			vmtype = 'qemu';
-		    } else if (PVE.Utils.volume_is_lxc_backup(rec.data.volid, rec.data.format)) {
-			vmtype = 'lxc';
-		    } else {
-			return;
-		    }
-
-		    var win = Ext.create('PVE.window.Restore', {
-			nodename: nodename,
-			volid: rec.data.volid,
-			volidText: PVE.Utils.render_storage_content(rec.data.volid, {}, rec),
-			vmtype: vmtype
-		    });
-		    win.show();
-		    win.on('destroy', reload);
-		}
-	    },
 	    removeButton,
 	    imageRemoveButton,
-	    {
-		xtype: 'proxmoxButton',
-		text: gettext('Show Configuration'),
-		disabled: true,
-		selModel: sm,
-		enableFn: function(rec) {
-		    return rec && rec.data.content === 'backup';
-		},
-		handler: function(b,e,rec) {
-		    var win = Ext.create('PVE.window.BackupConfig', {
-			volume: rec.data.volid,
-			pveSelNode: me.pveSelNode
-		    });
-
-		    win.show();
-		}
-	    },
 	    '->',
 	    gettext('Search') + ':', ' ',
 	    {
-- 
2.20.1





^ permalink raw reply	[flat|nested] 21+ messages in thread

* [pve-devel] [PATCH v2 manager 13/20] get rid of unneccessary enableFn's
  2020-09-16 12:50 [pve-devel] [PATCH-SERIES v2 manager] split up content view into a view for each type Fabian Ebner
                   ` (11 preceding siblings ...)
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 12/20] create and use BackupView Fabian Ebner
@ 2020-09-16 12:50 ` Fabian Ebner
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 14/20] create ImageView and use it for VM and CT images Fabian Ebner
                   ` (6 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Fabian Ebner @ 2020-09-16 12:50 UTC (permalink / raw)
  To: pve-devel

There's only backups in this view.

Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---
 www/manager6/storage/BackupView.js | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/www/manager6/storage/BackupView.js b/www/manager6/storage/BackupView.js
index 57312f8f..2669d2ca 100644
--- a/www/manager6/storage/BackupView.js
+++ b/www/manager6/storage/BackupView.js
@@ -33,9 +33,6 @@ Ext.define('PVE.storage.BackupView', {
 		text: gettext('Restore'),
 		selModel: sm,
 		disabled: true,
-		enableFn: function(rec) {
-		    return rec && rec.data.content === 'backup';
-		},
 		handler: function(b, e, rec) {
 		    var vmtype;
 		    if (PVE.Utils.volume_is_qemu_backup(rec.data.volid, rec.data.format)) {
@@ -61,9 +58,6 @@ Ext.define('PVE.storage.BackupView', {
 		text: gettext('Show Configuration'),
 		disabled: true,
 		selModel: sm,
-		enableFn: function(rec) {
-		    return rec && rec.data.content === 'backup';
-		},
 		handler: function(b,e,rec) {
 		    var win = Ext.create('PVE.window.BackupConfig', {
 			volume: rec.data.volid,
-- 
2.20.1





^ permalink raw reply	[flat|nested] 21+ messages in thread

* [pve-devel] [PATCH v2 manager 14/20] create ImageView and use it for VM and CT images
  2020-09-16 12:50 [pve-devel] [PATCH-SERIES v2 manager] split up content view into a view for each type Fabian Ebner
                   ` (12 preceding siblings ...)
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 13/20] get rid of unneccessary enableFn's Fabian Ebner
@ 2020-09-16 12:50 ` Fabian Ebner
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 15/20] simplify reload call Fabian Ebner
                   ` (5 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Fabian Ebner @ 2020-09-16 12:50 UTC (permalink / raw)
  To: pve-devel

The enableFn's that were responsible for switching
between the image remove button and the standard remove button
are not needed anymore.

Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---

use --color-moved=zebra --color-moved-ws=ignore-all-space for
better readability.

 www/manager6/Makefile               |  1 +
 www/manager6/storage/Browser.js     |  4 +-
 www/manager6/storage/ContentView.js | 64 ++----------------------
 www/manager6/storage/ImageView.js   | 76 +++++++++++++++++++++++++++++
 4 files changed, 82 insertions(+), 63 deletions(-)
 create mode 100644 www/manager6/storage/ImageView.js

diff --git a/www/manager6/Makefile b/www/manager6/Makefile
index 26c91bef..4b9dcf58 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -225,6 +225,7 @@ JSSRC= 							\
 	storage/ContentView.js				\
 	storage/DirEdit.js				\
 	storage/GlusterFsEdit.js			\
+	storage/ImageView.js				\
 	storage/IScsiEdit.js				\
 	storage/LVMEdit.js				\
 	storage/LvmThinEdit.js				\
diff --git a/www/manager6/storage/Browser.js b/www/manager6/storage/Browser.js
index 53d8828c..c815ad03 100644
--- a/www/manager6/storage/Browser.js
+++ b/www/manager6/storage/Browser.js
@@ -59,7 +59,7 @@ Ext.define('PVE.storage.Browser', {
 		    }
 		    if (contents.includes('images')) {
 			items.push({
-			    xtype: 'pveStorageContentView',
+			    xtype: 'pveStorageImageView',
 			    title: gettext('Disk Images'),
 			    iconCls: 'fa fa-hdd-o',
 			    itemId: 'contentImages',
@@ -82,7 +82,7 @@ Ext.define('PVE.storage.Browser', {
 		    }
 		    if (contents.includes('rootdir')) {
 			items.push({
-			    xtype: 'pveStorageContentView',
+			    xtype: 'pveStorageImageView',
 			    title: gettext('Container Data'),
 			    iconCls: 'fa fa-hdd-o',
 			    itemId: 'contentRootdir',
diff --git a/www/manager6/storage/ContentView.js b/www/manager6/storage/ContentView.js
index 542b07f7..3b6b817a 100644
--- a/www/manager6/storage/ContentView.js
+++ b/www/manager6/storage/ContentView.js
@@ -269,83 +269,25 @@ Ext.define('PVE.storage.ContentView', {
 	    }
 	});
 
-	var imageRemoveButton;
 	var removeButton = Ext.create('Proxmox.button.StdRemoveButton',{
 	    selModel: sm,
 	    delay: 5,
-	    enableFn: function(rec) {
-		if (rec && rec.data.content !== 'images' &&
-			   rec.data.content !== 'rootdir') {
-		    imageRemoveButton.setVisible(false);
-		    removeButton.setVisible(true);
-		    return true;
-		}
-		return false;
-	    },
 	    callback: function() {
 		reload();
 	    },
 	    baseurl: baseurl + '/'
 	});
 
-	imageRemoveButton = Ext.create('Proxmox.button.Button',{
-	    selModel: sm,
-	    hidden: true,
-	    text: gettext('Remove'),
-	    enableFn: function(rec) {
-		if (rec && (rec.data.content === 'images' ||
-			    rec.data.content === 'rootdir')) {
-		    removeButton.setVisible(false);
-		    imageRemoveButton.setVisible(true);
-		    return true;
-		}
-		return false;
-	    },
-	    handler: function(btn, event, rec) {
-		var url = baseurl + '/' + rec.data.volid;
-		var vmid = rec.data.vmid;
-
-		var store = PVE.data.ResourceStore;
-
-		if (vmid && store.findVMID(vmid)) {
-		    var guest_node = store.guestNode(vmid);
-		    var storage_path = 'storage/' + nodename + '/' + storage;
-
-		    // allow to delete local backed images if a VMID exists on another node.
-		    if (store.storageIsShared(storage_path) || guest_node == nodename) {
-			var msg = Ext.String.format(
-			    gettext("Cannot remove image, a guest with VMID '{0}' exists!"), vmid);
-			msg += '<br />' + gettext("You can delete the image from the guest's hardware pane");
-
-			Ext.Msg.show({
-			    title: gettext('Cannot remove disk image.'),
-			    icon: Ext.Msg.ERROR,
-			    msg: msg
-			});
-			return;
-		    }
-		}
-		var win = Ext.create('PVE.window.SafeDestroy', {
-		    title: Ext.String.format(gettext("Destroy '{0}'"), rec.data.volid),
-		    showProgress: true,
-		    url: url,
-		    item: { type: 'Image', id: vmid }
-		}).show();
-		win.on('destroy', function() {
-		    reload();
-		});
-	    }
-	});
-
 	if (!me.tbar) {
 	    me.tbar = [];
 	}
 	if (me.useUploadButton) {
 	    me.tbar.push(uploadButton);
 	}
+	if (!me.useCustomRemoveButton) {
+	    me.tbar.push(removeButton);
+	}
 	me.tbar.push(
-	    removeButton,
-	    imageRemoveButton,
 	    '->',
 	    gettext('Search') + ':', ' ',
 	    {
diff --git a/www/manager6/storage/ImageView.js b/www/manager6/storage/ImageView.js
new file mode 100644
index 00000000..97dae567
--- /dev/null
+++ b/www/manager6/storage/ImageView.js
@@ -0,0 +1,76 @@
+Ext.define('PVE.storage.ImageView', {
+    extend: 'PVE.storage.ContentView',
+
+    alias: 'widget.pveStorageImageView',
+
+    initComponent: function() {
+	var me = this;
+
+	var nodename = me.nodename = me.pveSelNode.data.node;
+	if (!me.nodename) {
+	    throw "no node name specified";
+	}
+
+	var storage = me.storage = me.pveSelNode.data.storage;
+	if (!me.storage) {
+	    throw "no storage ID specified";
+	}
+
+	if (!me.content || (me.content !== 'images' && me.content !== 'rootdir')) {
+	    throw "content needs to be either 'images' or 'rootdir'";
+	}
+
+	var sm = me.sm = Ext.create('Ext.selection.RowModel', {});
+
+	var reload = function() {
+	    me.store.load();
+	}
+
+	me.tbar = [
+	    {
+		xtype: 'proxmoxButton',
+		selModel: sm,
+		text: gettext('Remove'),
+		disabled: true,
+		handler: function(btn, event, rec) {
+		    var url = "/nodes/" + nodename + "/storage/" + storage +
+			      "/content" + '/' + rec.data.volid;
+		    var vmid = rec.data.vmid;
+
+		    var store = PVE.data.ResourceStore;
+
+		    if (vmid && store.findVMID(vmid)) {
+			var guest_node = store.guestNode(vmid);
+			var storage_path = 'storage/' + nodename + '/' + storage;
+
+			// allow to delete local backed images if a VMID exists on another node.
+			if (store.storageIsShared(storage_path) || guest_node == nodename) {
+			    var msg = Ext.String.format(
+				gettext("Cannot remove image, a guest with VMID '{0}' exists!"), vmid);
+			    msg += '<br />' + gettext("You can delete the image from the guest's hardware pane");
+
+			    Ext.Msg.show({
+				title: gettext('Cannot remove disk image.'),
+				icon: Ext.Msg.ERROR,
+				msg: msg
+			    });
+			    return;
+			}
+		    }
+		    var win = Ext.create('PVE.window.SafeDestroy', {
+			title: Ext.String.format(gettext("Destroy '{0}'"), rec.data.volid),
+			showProgress: true,
+			url: url,
+			item: { type: 'Image', id: vmid }
+		    }).show();
+		    win.on('destroy', function() {
+			reload();
+		    });
+		}
+	    },
+	];
+	me.useCustomRemoveButton = true;
+
+	me.callParent();
+    },
+});
-- 
2.20.1





^ permalink raw reply	[flat|nested] 21+ messages in thread

* [pve-devel] [PATCH v2 manager 15/20] simplify reload call
  2020-09-16 12:50 [pve-devel] [PATCH-SERIES v2 manager] split up content view into a view for each type Fabian Ebner
                   ` (13 preceding siblings ...)
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 14/20] create ImageView and use it for VM and CT images Fabian Ebner
@ 2020-09-16 12:50 ` Fabian Ebner
  2020-09-16 12:50 ` [pve-devel] [RFC v2 manager 16/20] content view: allow specifying which columns to show on init Fabian Ebner
                   ` (4 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Fabian Ebner @ 2020-09-16 12:50 UTC (permalink / raw)
  To: pve-devel

Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---
 www/manager6/storage/ImageView.js | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/www/manager6/storage/ImageView.js b/www/manager6/storage/ImageView.js
index 97dae567..d9f19035 100644
--- a/www/manager6/storage/ImageView.js
+++ b/www/manager6/storage/ImageView.js
@@ -63,9 +63,7 @@ Ext.define('PVE.storage.ImageView', {
 			url: url,
 			item: { type: 'Image', id: vmid }
 		    }).show();
-		    win.on('destroy', function() {
-			reload();
-		    });
+		    win.on('destroy', reload);
 		}
 	    },
 	];
-- 
2.20.1





^ permalink raw reply	[flat|nested] 21+ messages in thread

* [pve-devel] [RFC v2 manager 16/20] content view: allow specifying which columns to show on init
  2020-09-16 12:50 [pve-devel] [PATCH-SERIES v2 manager] split up content view into a view for each type Fabian Ebner
                   ` (14 preceding siblings ...)
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 15/20] simplify reload call Fabian Ebner
@ 2020-09-16 12:50 ` Fabian Ebner
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 17/20] group backups by backup groups in backup view Fabian Ebner
                   ` (3 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Fabian Ebner @ 2020-09-16 12:50 UTC (permalink / raw)
  To: pve-devel

depending on the content type we might want to show different
information, e.g. parent for cloned VM/CT images (would have to
be added to the model first)

Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---
 www/manager6/storage/ContentView.js | 60 +++++++++++++++++------------
 1 file changed, 35 insertions(+), 25 deletions(-)

diff --git a/www/manager6/storage/ContentView.js b/www/manager6/storage/ContentView.js
index 3b6b817a..0f1bbc0c 100644
--- a/www/manager6/storage/ContentView.js
+++ b/www/manager6/storage/ContentView.js
@@ -311,35 +311,45 @@ Ext.define('PVE.storage.ContentView', {
 	    }
 	);
 
+	var availableColumns = {
+	    'name': {
+		header: gettext('Name'),
+		flex: 1,
+		sortable: true,
+		renderer: PVE.Utils.render_storage_content,
+		dataIndex: 'text'
+	    },
+	    'date': {
+		header: gettext('Date'),
+		width: 150,
+		dataIndex: 'vdate'
+	    },
+	    'format': {
+		header: gettext('Format'),
+		width: 100,
+		dataIndex: 'format'
+	    },
+	    'size': {
+		header: gettext('Size'),
+		width: 100,
+		renderer: Proxmox.Utils.format_size,
+		dataIndex: 'size'
+	    },
+	};
+
+	if (!me.showColumns) {
+	    me.showColumns = ['name', 'date', 'format', 'size'];
+	}
+	var columns = [];
+	me.showColumns.forEach(function(datum) {
+	    columns.push(availableColumns[datum]);
+	});
+
 	Ext.apply(me, {
 	    store: store,
 	    selModel: sm,
 	    tbar: me.tbar,
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    flex: 1,
-		    sortable: true,
-		    renderer: PVE.Utils.render_storage_content,
-		    dataIndex: 'text'
-		},
-		{
-		    header: gettext('Date'),
-		    width: 150,
-		    dataIndex: 'vdate'
-		},
-		{
-		    header: gettext('Format'),
-		    width: 100,
-		    dataIndex: 'format'
-		},
-		{
-		    header: gettext('Size'),
-		    width: 100,
-		    renderer: Proxmox.Utils.format_size,
-		    dataIndex: 'size'
-		}
-	    ],
+	    columns: columns,
 	    listeners: {
 		activate: reload
 	    }
-- 
2.20.1





^ permalink raw reply	[flat|nested] 21+ messages in thread

* [pve-devel] [PATCH v2 manager 17/20] group backups by backup groups in backup view
  2020-09-16 12:50 [pve-devel] [PATCH-SERIES v2 manager] split up content view into a view for each type Fabian Ebner
                   ` (15 preceding siblings ...)
  2020-09-16 12:50 ` [pve-devel] [RFC v2 manager 16/20] content view: allow specifying which columns to show on init Fabian Ebner
@ 2020-09-16 12:50 ` Fabian Ebner
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 18/20] allow child classes of ContentView to specify their own listeners Fabian Ebner
                   ` (2 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Fabian Ebner @ 2020-09-16 12:50 UTC (permalink / raw)
  To: pve-devel

It was necessary to make the component not stateful, because of an ExtJS bug
where groupFn is not being preserved when the state is restored, see:
https://forum.sencha.com/forum/showthread.php?469145-Uncaught-TypeError-me-_groupFn-is-not-a-function

Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---

new in v2

Couldn't find a way to make this work with stateful: true...
Not using Ext.create and only passing along the Object with the properties
for the grouper doesn't seem to help either.

 www/manager6/storage/BackupView.js  | 24 ++++++++++++++++++++++--
 www/manager6/storage/ContentView.js |  1 +
 2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/www/manager6/storage/BackupView.js b/www/manager6/storage/BackupView.js
index 2669d2ca..ad377de6 100644
--- a/www/manager6/storage/BackupView.js
+++ b/www/manager6/storage/BackupView.js
@@ -3,8 +3,12 @@ Ext.define('PVE.storage.BackupView', {
 
     alias: 'widget.pveStorageBackupView',
 
-    stateful: true,
-    stateId: 'grid-storage-content-backup',
+    features: [
+	{
+	    ftype: 'grouping',
+	    groupHeaderTpl: '{name} ({rows.length} Backup{[values.rows.length > 1 ? "s" : ""]})',
+	},
+    ],
 
     initComponent: function() {
 	var me = this;
@@ -69,6 +73,22 @@ Ext.define('PVE.storage.BackupView', {
 	    },
 	];
 
+	me.grouper = Ext.create('Ext.util.Grouper', {
+	    groupFn: function(val) {
+		let name = val.data.text;
+		let vmid = val.data.vmid;
+		if (!vmid) {
+		    return 'other';
+		}
+		if (name.startsWith('vzdump-lxc-')) {
+		    return 'CT/' + vmid;
+		} else if (name.startsWith('vzdump-qemu-')) {
+		    return 'VM/' + vmid;
+		}
+		return 'other';
+	    },
+	});
+
 	me.callParent();
     },
 });
diff --git a/www/manager6/storage/ContentView.js b/www/manager6/storage/ContentView.js
index 0f1bbc0c..e563d3a3 100644
--- a/www/manager6/storage/ContentView.js
+++ b/www/manager6/storage/ContentView.js
@@ -232,6 +232,7 @@ Ext.define('PVE.storage.ContentView', {
 	var baseurl = "/nodes/" + nodename + "/storage/" + storage + "/content";
 	var store = me.store = Ext.create('Ext.data.Store', {
 	    model: 'pve-storage-content',
+	    grouper: me.grouper,
 	    proxy: {
                 type: 'proxmox',
 		url: '/api2/json' + baseurl,
-- 
2.20.1





^ permalink raw reply	[flat|nested] 21+ messages in thread

* [pve-devel] [PATCH v2 manager 18/20] allow child classes of ContentView to specify their own listeners
  2020-09-16 12:50 [pve-devel] [PATCH-SERIES v2 manager] split up content view into a view for each type Fabian Ebner
                   ` (16 preceding siblings ...)
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 17/20] group backups by backup groups in backup view Fabian Ebner
@ 2020-09-16 12:50 ` Fabian Ebner
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 19/20] add CSS for button in grid's group header Fabian Ebner
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 20/20] backup view: add prune window Fabian Ebner
  19 siblings, 0 replies; 21+ messages in thread
From: Fabian Ebner @ 2020-09-16 12:50 UTC (permalink / raw)
  To: pve-devel

Ext.apply would simply overwrite possibly existing listeners.

Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---

new in v2

 www/manager6/storage/ContentView.js | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/www/manager6/storage/ContentView.js b/www/manager6/storage/ContentView.js
index e563d3a3..c5dd5206 100644
--- a/www/manager6/storage/ContentView.js
+++ b/www/manager6/storage/ContentView.js
@@ -351,11 +351,11 @@ Ext.define('PVE.storage.ContentView', {
 	    selModel: sm,
 	    tbar: me.tbar,
 	    columns: columns,
-	    listeners: {
-		activate: reload
-	    }
 	});
 
+	// don't overwrite existing listeners
+	me.listeners = Object.assign({}, { activate: reload }, me.listeners);
+
 	me.callParent();
     }
 }, function() {
-- 
2.20.1





^ permalink raw reply	[flat|nested] 21+ messages in thread

* [pve-devel] [PATCH v2 manager 19/20] add CSS for button in grid's group header
  2020-09-16 12:50 [pve-devel] [PATCH-SERIES v2 manager] split up content view into a view for each type Fabian Ebner
                   ` (17 preceding siblings ...)
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 18/20] allow child classes of ContentView to specify their own listeners Fabian Ebner
@ 2020-09-16 12:50 ` Fabian Ebner
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 20/20] backup view: add prune window Fabian Ebner
  19 siblings, 0 replies; 21+ messages in thread
From: Fabian Ebner @ 2020-09-16 12:50 UTC (permalink / raw)
  To: pve-devel

Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---

new in v2

 www/css/ext6-pve.css | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/www/css/ext6-pve.css b/www/css/ext6-pve.css
index a7c0750c..18eb1ae9 100644
--- a/www/css/ext6-pve.css
+++ b/www/css/ext6-pve.css
@@ -6,6 +6,15 @@
     max-width: 100%;
 }
 
+/* for a button within a grid's group header */
+.x-btn-custom-groupheader {
+    border-radius: 3px;
+    border-width: 1px;
+    border-style: solid;
+    background-color: #f5f5f5;
+    border-color: #d8d8d8;
+}
+
 /* add missing class for context menu header */
 .x-menu-header {
     font: 400 13px/20px 'Open Sans', 'Helvetica Neue', helvetica, arial, verdana, sans-serif;
-- 
2.20.1





^ permalink raw reply	[flat|nested] 21+ messages in thread

* [pve-devel] [PATCH v2 manager 20/20] backup view: add prune window
  2020-09-16 12:50 [pve-devel] [PATCH-SERIES v2 manager] split up content view into a view for each type Fabian Ebner
                   ` (18 preceding siblings ...)
  2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 19/20] add CSS for button in grid's group header Fabian Ebner
@ 2020-09-16 12:50 ` Fabian Ebner
  19 siblings, 0 replies; 21+ messages in thread
From: Fabian Ebner @ 2020-09-16 12:50 UTC (permalink / raw)
  To: pve-devel

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 <f.ebner@proxmox.com>
---

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





^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2020-09-16 12:51 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-16 12:50 [pve-devel] [PATCH-SERIES v2 manager] split up content view into a view for each type Fabian Ebner
2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 01/20] fix extension filter for upload window Fabian Ebner
2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 02/20] config panel: allow new nodes to be added later Fabian Ebner
2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 03/20] storage panel/browser: use insertNodes function Fabian Ebner
2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 04/20] add CD ROM and lxc icons for treelist-item-icon Fabian Ebner
2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 05/20] use separate view for each content type Fabian Ebner
2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 06/20] remove the now unnecessary grouping by " Fabian Ebner
2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 07/20] remove the now unneccessary content type column Fabian Ebner
2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 08/20] content view: allow specifying title bar elements for init Fabian Ebner
2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 09/20] turn {nodename, storage, sm} into object variables Fabian Ebner
2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 10/20] add upload button conditionally Fabian Ebner
2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 11/20] create and use TemplateView Fabian Ebner
2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 12/20] create and use BackupView Fabian Ebner
2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 13/20] get rid of unneccessary enableFn's Fabian Ebner
2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 14/20] create ImageView and use it for VM and CT images Fabian Ebner
2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 15/20] simplify reload call Fabian Ebner
2020-09-16 12:50 ` [pve-devel] [RFC v2 manager 16/20] content view: allow specifying which columns to show on init Fabian Ebner
2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 17/20] group backups by backup groups in backup view Fabian Ebner
2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 18/20] allow child classes of ContentView to specify their own listeners Fabian Ebner
2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 19/20] add CSS for button in grid's group header Fabian Ebner
2020-09-16 12:50 ` [pve-devel] [PATCH v2 manager 20/20] backup view: add prune window Fabian Ebner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal