* [pve-devel] [PATCH v3 manager 01/20] fix extension filter for upload window
2020-11-13 13:16 [pve-devel] [PATCH-SERIES v3 manager] split up content view into a view for each type Fabian Ebner
@ 2020-11-13 13:16 ` Fabian Ebner
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 02/20] config panel: allow new nodes to be added later Fabian Ebner
` (19 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Fabian Ebner @ 2020-11-13 13:16 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>
---
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 a879cc19..bc144fa4 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] 22+ messages in thread
* [pve-devel] [PATCH v3 manager 02/20] config panel: allow new nodes to be added later
2020-11-13 13:16 [pve-devel] [PATCH-SERIES v3 manager] split up content view into a view for each type Fabian Ebner
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 01/20] fix extension filter for upload window Fabian Ebner
@ 2020-11-13 13:16 ` Fabian Ebner
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 03/20] storage panel/browser: use insertNodes function Fabian Ebner
` (18 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Fabian Ebner @ 2020-11-13 13:16 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] 22+ messages in thread
* [pve-devel] [PATCH v3 manager 03/20] storage panel/browser: use insertNodes function
2020-11-13 13:16 [pve-devel] [PATCH-SERIES v3 manager] split up content view into a view for each type Fabian Ebner
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 01/20] fix extension filter for upload window Fabian Ebner
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 02/20] config panel: allow new nodes to be added later Fabian Ebner
@ 2020-11-13 13:16 ` Fabian Ebner
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 04/20] add CD ROM and lxc icons for treelist-item-icon Fabian Ebner
` (17 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Fabian Ebner @ 2020-11-13 13:16 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] 22+ messages in thread
* [pve-devel] [PATCH v3 manager 04/20] add CD ROM and lxc icons for treelist-item-icon
2020-11-13 13:16 [pve-devel] [PATCH-SERIES v3 manager] split up content view into a view for each type Fabian Ebner
` (2 preceding siblings ...)
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 03/20] storage panel/browser: use insertNodes function Fabian Ebner
@ 2020-11-13 13:16 ` Fabian Ebner
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 05/20] use separate view for each content type Fabian Ebner
` (16 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Fabian Ebner @ 2020-11-13 13:16 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---
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 6430ffc4..3b7a896b 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] 22+ messages in thread
* [pve-devel] [PATCH v3 manager 05/20] use separate view for each content type
2020-11-13 13:16 [pve-devel] [PATCH-SERIES v3 manager] split up content view into a view for each type Fabian Ebner
` (3 preceding siblings ...)
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 04/20] add CD ROM and lxc icons for treelist-item-icon Fabian Ebner
@ 2020-11-13 13:16 ` Fabian Ebner
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 06/20] remove the now unnecessary grouping by " Fabian Ebner
` (15 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Fabian Ebner @ 2020-11-13 13:16 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>
---
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 bc144fa4..19ba1e36 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,
@@ -640,37 +643,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] 22+ messages in thread
* [pve-devel] [PATCH v3 manager 06/20] remove the now unnecessary grouping by content type
2020-11-13 13:16 [pve-devel] [PATCH-SERIES v3 manager] split up content view into a view for each type Fabian Ebner
` (4 preceding siblings ...)
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 05/20] use separate view for each content type Fabian Ebner
@ 2020-11-13 13:16 ` Fabian Ebner
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 07/20] remove the now unneccessary content type column Fabian Ebner
` (14 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Fabian Ebner @ 2020-11-13 13:16 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---
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 19ba1e36..0d52cb2b 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] 22+ messages in thread
* [pve-devel] [PATCH v3 manager 07/20] remove the now unneccessary content type column
2020-11-13 13:16 [pve-devel] [PATCH-SERIES v3 manager] split up content view into a view for each type Fabian Ebner
` (5 preceding siblings ...)
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 06/20] remove the now unnecessary grouping by " Fabian Ebner
@ 2020-11-13 13:16 ` Fabian Ebner
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 08/20] content view: allow specifying title bar elements for init Fabian Ebner
` (13 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Fabian Ebner @ 2020-11-13 13:16 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---
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 0d52cb2b..d1df4a35 100644
--- a/www/manager6/storage/ContentView.js
+++ b/www/manager6/storage/ContentView.js
@@ -617,12 +617,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] 22+ messages in thread
* [pve-devel] [PATCH v3 manager 08/20] content view: allow specifying title bar elements for init
2020-11-13 13:16 [pve-devel] [PATCH-SERIES v3 manager] split up content view into a view for each type Fabian Ebner
` (6 preceding siblings ...)
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 07/20] remove the now unneccessary content type column Fabian Ebner
@ 2020-11-13 13:16 ` Fabian Ebner
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 09/20] turn {nodename, storage, sm} into object variables Fabian Ebner
` (12 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Fabian Ebner @ 2020-11-13 13:16 UTC (permalink / raw)
To: pve-devel
in preparation to create derived classes.
Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---
using --color-moved=zebra --color-moved-ws=ignore-all-space --patience
makes it easier to read
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 d1df4a35..36e14292 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] 22+ messages in thread
* [pve-devel] [PATCH v3 manager 09/20] turn {nodename, storage, sm} into object variables
2020-11-13 13:16 [pve-devel] [PATCH-SERIES v3 manager] split up content view into a view for each type Fabian Ebner
` (7 preceding siblings ...)
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 08/20] content view: allow specifying title bar elements for init Fabian Ebner
@ 2020-11-13 13:16 ` Fabian Ebner
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 10/20] add upload button conditionally Fabian Ebner
` (11 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Fabian Ebner @ 2020-11-13 13:16 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 36e14292..b9a53e11 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] 22+ messages in thread
* [pve-devel] [PATCH v3 manager 10/20] add upload button conditionally
2020-11-13 13:16 [pve-devel] [PATCH-SERIES v3 manager] split up content view into a view for each type Fabian Ebner
` (8 preceding siblings ...)
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 09/20] turn {nodename, storage, sm} into object variables Fabian Ebner
@ 2020-11-13 13:16 ` Fabian Ebner
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 11/20] create and use TemplateView Fabian Ebner
` (10 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Fabian Ebner @ 2020-11-13 13:16 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 b9a53e11..de319095 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] 22+ messages in thread
* [pve-devel] [PATCH v3 manager 11/20] create and use TemplateView
2020-11-13 13:16 [pve-devel] [PATCH-SERIES v3 manager] split up content view into a view for each type Fabian Ebner
` (9 preceding siblings ...)
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 10/20] add upload button conditionally Fabian Ebner
@ 2020-11-13 13:16 ` Fabian Ebner
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 12/20] create and use BackupView Fabian Ebner
` (9 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Fabian Ebner @ 2020-11-13 13:16 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 b0c9dc4f..3a076eac 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -249,6 +249,7 @@ JSSRC= \
storage/RBDEdit.js \
storage/StatusView.js \
storage/Summary.js \
+ storage/TemplateView.js \
storage/ZFSEdit.js \
storage/ZFSPoolEdit.js \
Workspace.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 de319095..1a4a9963 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] 22+ messages in thread
* [pve-devel] [PATCH v3 manager 12/20] create and use BackupView
2020-11-13 13:16 [pve-devel] [PATCH-SERIES v3 manager] split up content view into a view for each type Fabian Ebner
` (10 preceding siblings ...)
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 11/20] create and use TemplateView Fabian Ebner
@ 2020-11-13 13:16 ` Fabian Ebner
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 13/20] get rid of unneccessary enableFn's Fabian Ebner
` (8 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Fabian Ebner @ 2020-11-13 13:16 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 3a076eac..be1f1888 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -234,6 +234,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 1a4a9963..8da2db7e 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] 22+ messages in thread
* [pve-devel] [PATCH v3 manager 13/20] get rid of unneccessary enableFn's
2020-11-13 13:16 [pve-devel] [PATCH-SERIES v3 manager] split up content view into a view for each type Fabian Ebner
` (11 preceding siblings ...)
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 12/20] create and use BackupView Fabian Ebner
@ 2020-11-13 13:16 ` Fabian Ebner
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 14/20] create ImageView and use it for VM and CT images Fabian Ebner
` (7 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Fabian Ebner @ 2020-11-13 13:16 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] 22+ messages in thread
* [pve-devel] [PATCH v3 manager 14/20] create ImageView and use it for VM and CT images
2020-11-13 13:16 [pve-devel] [PATCH-SERIES v3 manager] split up content view into a view for each type Fabian Ebner
` (12 preceding siblings ...)
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 13/20] get rid of unneccessary enableFn's Fabian Ebner
@ 2020-11-13 13:16 ` Fabian Ebner
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 15/20] simplify reload call Fabian Ebner
` (6 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Fabian Ebner @ 2020-11-13 13:16 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>
---
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 be1f1888..6111a9ce 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -242,6 +242,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 8da2db7e..f3174e2e 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] 22+ messages in thread
* [pve-devel] [PATCH v3 manager 15/20] simplify reload call
2020-11-13 13:16 [pve-devel] [PATCH-SERIES v3 manager] split up content view into a view for each type Fabian Ebner
` (13 preceding siblings ...)
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 14/20] create ImageView and use it for VM and CT images Fabian Ebner
@ 2020-11-13 13:16 ` Fabian Ebner
2020-11-13 13:16 ` [pve-devel] [RFC v3 manager 16/20] content view: allow specifying which columns to show on init Fabian Ebner
` (5 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Fabian Ebner @ 2020-11-13 13:16 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] 22+ messages in thread
* [pve-devel] [RFC v3 manager 16/20] content view: allow specifying which columns to show on init
2020-11-13 13:16 [pve-devel] [PATCH-SERIES v3 manager] split up content view into a view for each type Fabian Ebner
` (14 preceding siblings ...)
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 15/20] simplify reload call Fabian Ebner
@ 2020-11-13 13:16 ` Fabian Ebner
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 17/20] group backups by backup groups in backup view Fabian Ebner
` (4 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Fabian Ebner @ 2020-11-13 13:16 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, verification for backups, etc. Of course the
properties would have to be added to the model and the availableColumns first
Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---
www/manager6/storage/ContentView.js | 72 ++++++++++++++++-------------
1 file changed, 41 insertions(+), 31 deletions(-)
diff --git a/www/manager6/storage/ContentView.js b/www/manager6/storage/ContentView.js
index f3174e2e..38dd5cab 100644
--- a/www/manager6/storage/ContentView.js
+++ b/www/manager6/storage/ContentView.js
@@ -311,41 +311,51 @@ Ext.define('PVE.storage.ContentView', {
}
);
+ var availableColumns = {
+ 'name': {
+ header: gettext('Name'),
+ flex: 2,
+ sortable: true,
+ renderer: PVE.Utils.render_storage_content,
+ dataIndex: 'text'
+ },
+ 'comment': {
+ header: gettext('Comment'),
+ flex: 1,
+ renderer: Ext.htmlEncode,
+ dataIndex: 'comment',
+ },
+ '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', 'comment', '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: 2,
- sortable: true,
- renderer: PVE.Utils.render_storage_content,
- dataIndex: 'text'
- },
- {
- header: gettext('Comment'),
- flex: 1,
- renderer: Ext.htmlEncode,
- dataIndex: 'comment',
- },
- {
- 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] 22+ messages in thread
* [pve-devel] [PATCH v3 manager 17/20] group backups by backup groups in backup view
2020-11-13 13:16 [pve-devel] [PATCH-SERIES v3 manager] split up content view into a view for each type Fabian Ebner
` (15 preceding siblings ...)
2020-11-13 13:16 ` [pve-devel] [RFC v3 manager 16/20] content view: allow specifying which columns to show on init Fabian Ebner
@ 2020-11-13 13:16 ` Fabian Ebner
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 18/20] allow child classes of ContentView to specify their own listeners Fabian Ebner
` (3 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Fabian Ebner @ 2020-11-13 13:16 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>
---
www/manager6/storage/BackupView.js | 26 ++++++++++++++++++++++++--
www/manager6/storage/ContentView.js | 1 +
2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/www/manager6/storage/BackupView.js b/www/manager6/storage/BackupView.js
index 2669d2ca..9ced7947 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,24 @@ 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;
+ let format = val.data.format;
+
+ if (!vmid) {
+ return 'other';
+ }
+ if (name.startsWith('vzdump-lxc-') || format === "pbs-ct") {
+ return 'CT/' + vmid;
+ } else if (name.startsWith('vzdump-qemu-') || format === "pbs-vm") {
+ return 'VM/' + vmid;
+ }
+ return 'other';
+ },
+ });
+
me.callParent();
},
});
diff --git a/www/manager6/storage/ContentView.js b/www/manager6/storage/ContentView.js
index 38dd5cab..1cd13c0e 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] 22+ messages in thread
* [pve-devel] [PATCH v3 manager 18/20] allow child classes of ContentView to specify their own listeners
2020-11-13 13:16 [pve-devel] [PATCH-SERIES v3 manager] split up content view into a view for each type Fabian Ebner
` (16 preceding siblings ...)
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 17/20] group backups by backup groups in backup view Fabian Ebner
@ 2020-11-13 13:16 ` Fabian Ebner
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 19/20] add CSS for button in grid's group header Fabian Ebner
` (2 subsequent siblings)
20 siblings, 0 replies; 22+ messages in thread
From: Fabian Ebner @ 2020-11-13 13:16 UTC (permalink / raw)
To: pve-devel
Ext.apply would simply overwrite possibly existing listeners. Needed for
introducing the prune button.
Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---
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 1cd13c0e..c8c50b3a 100644
--- a/www/manager6/storage/ContentView.js
+++ b/www/manager6/storage/ContentView.js
@@ -357,11 +357,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] 22+ messages in thread
* [pve-devel] [PATCH v3 manager 19/20] add CSS for button in grid's group header
2020-11-13 13:16 [pve-devel] [PATCH-SERIES v3 manager] split up content view into a view for each type Fabian Ebner
` (17 preceding siblings ...)
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 18/20] allow child classes of ContentView to specify their own listeners Fabian Ebner
@ 2020-11-13 13:16 ` Fabian Ebner
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 20/20] backup view: add prune window Fabian Ebner
2020-11-16 9:11 ` [pve-devel] patrially-applied-series: [PATCH-SERIES v3 manager] split up content view into a view for each type Thomas Lamprecht
20 siblings, 0 replies; 22+ messages in thread
From: Fabian Ebner @ 2020-11-13 13:16 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---
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 3b7a896b..d6c0bab4 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] 22+ messages in thread
* [pve-devel] [PATCH v3 manager 20/20] backup view: add prune window
2020-11-13 13:16 [pve-devel] [PATCH-SERIES v3 manager] split up content view into a view for each type Fabian Ebner
` (18 preceding siblings ...)
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 19/20] add CSS for button in grid's group header Fabian Ebner
@ 2020-11-13 13:16 ` Fabian Ebner
2020-11-16 9:11 ` [pve-devel] patrially-applied-series: [PATCH-SERIES v3 manager] split up content view into a view for each type Thomas Lamprecht
20 siblings, 0 replies; 22+ messages in thread
From: Fabian Ebner @ 2020-11-13 13:16 UTC (permalink / raw)
To: pve-devel
adapted from PBS. Main differences are:
* loading of the prune-backups options from the storage configuration
* API has GET/DELETE distinction instead of 'dry-run'
* API expects a single property string for the prune options
Also, had to change the clear trigger, because now there can be original
values (from the storage config), but it doesn't really make sense to
reset to that value when clearing, so always set to 'null' when clearing
Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---
Depends on this patch (otherwise it would error
out when all numberfields are cleared):
https://lists.proxmox.com/pipermail/pve-devel/2020-November/045916.html
www/manager6/Makefile | 1 +
www/manager6/storage/BackupView.js | 34 +++-
www/manager6/window/Prune.js | 306 +++++++++++++++++++++++++++++
3 files changed, 340 insertions(+), 1 deletion(-)
create mode 100644 www/manager6/window/Prune.js
diff --git a/www/manager6/Makefile b/www/manager6/Makefile
index 6111a9ce..a23b3a1e 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -97,6 +97,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 9ced7947..9ee14399 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>',
+ ),
},
],
@@ -91,6 +103,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..f211dc91
--- /dev/null
+++ b/www/manager6/window/Prune.js
@@ -0,0 +1,306 @@
+Ext.define('pve-prune-list', {
+ extend: 'Ext.data.Model',
+ fields: [
+ 'type',
+ 'vmid',
+ {
+ name: 'ctime',
+ type: 'date',
+ dateFormat: 'timestamp',
+ },
+ ],
+});
+
+Ext.define('PVE.PruneKeepInput', {
+ extend: 'Proxmox.form.field.Integer',
+ alias: 'widget.pvePruneKeepInput',
+
+ allowBlank: true,
+ minValue: 1,
+
+ listeners: {
+ change: function(field, newValue, oldValue) {
+ if (newValue === 0) { // might be configured in the storage options
+ this.setValue(null);
+ this.triggers.clear.setVisible(false);
+ } else {
+ this.triggers.clear.setVisible(newValue !== null);
+ }
+ },
+ },
+ triggers: {
+ clear: {
+ cls: 'pmx-clear-trigger',
+ weight: -1,
+ hidden: true,
+ handler: function() {
+ this.triggers.clear.setVisible(false);
+ this.setValue(null);
+ },
+ },
+ },
+});
+
+Ext.define('PVE.PruneInputPanel', {
+ extend: 'Proxmox.panel.InputPanel',
+ alias: 'widget.pvePruneInputPanel',
+ mixins: ['Proxmox.Mixin.CBind'],
+
+ onGetValues: function(values) {
+ let me = this;
+
+ // the API expects a single prune-backups property string
+ let pruneBackups = PVE.Parser.printPropertyString(values);
+ values = {
+ 'prune-backups': pruneBackups,
+ 'type': me.backup_type,
+ '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() {
+ let view = this.getView();
+
+ // helper to allow showing why a backup is kept
+ let addKeepReasons = function(backups, params) {
+ const rules = [
+ 'keep-last',
+ 'keep-hourly',
+ 'keep-daily',
+ 'keep-weekly',
+ 'keep-monthly',
+ 'keep-yearly',
+ 'keep-all', // when all keep options are not set
+ ];
+ let counter = {};
+
+ backups.sort(function(a, b) {
+ return a.ctime < b.ctime;
+ });
+
+ let ruleIndex = -1;
+ let nextRule = function() {
+ let rule;
+ do {
+ ruleIndex++;
+ rule = rules[ruleIndex];
+ } while (!params[rule] && rule !== 'keep-all');
+ counter[rule] = 0;
+ return rule;
+ };
+
+ let rule = nextRule();
+ for (let backup of backups) {
+ if (backup.mark === 'keep') {
+ counter[rule]++;
+ if (rule !== 'keep-all') {
+ backup.keepReason = rule + ': ' + counter[rule];
+ if (counter[rule] >= params[rule]) {
+ rule = nextRule();
+ }
+ } else {
+ backup.keepReason = rule;
+ }
+ }
+ }
+ };
+
+ let params = view.getValues();
+ let keepParams = PVE.Parser.parsePropertyString(params["prune-backups"]);
+
+ Proxmox.Utils.API2Request({
+ url: view.url,
+ method: "GET",
+ params: params,
+ callback: function() {
+ // for easy breakpoint setting
+ },
+ failure: function(response, opts) {
+ Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+ },
+ success: function(response, options) {
+ var data = response.result.data;
+ addKeepReasons(data, keepParams);
+ view.pruneStore.setData(data);
+ },
+ });
+ },
+
+ control: {
+ field: { change: 'reload' },
+ },
+ },
+
+ column1: [
+ {
+ xtype: 'pvePruneKeepInput',
+ name: 'keep-last',
+ fieldLabel: gettext('keep-last'),
+ },
+ {
+ xtype: 'pvePruneKeepInput',
+ name: 'keep-hourly',
+ fieldLabel: gettext('keep-hourly'),
+ },
+ {
+ xtype: 'pvePruneKeepInput',
+ name: 'keep-daily',
+ fieldLabel: gettext('keep-daily'),
+ },
+ {
+ xtype: 'pvePruneKeepInput',
+ name: 'keep-weekly',
+ fieldLabel: gettext('keep-weekly'),
+ },
+ {
+ xtype: 'pvePruneKeepInput',
+ name: 'keep-monthly',
+ fieldLabel: gettext('keep-monthly'),
+ },
+ {
+ xtype: 'pvePruneKeepInput',
+ name: 'keep-yearly',
+ fieldLabel: gettext('keep-yearly'),
+ },
+ ],
+
+ 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 (reason)',
+ dataIndex: 'mark',
+ renderer: function(value, metaData, record) {
+ if (record.data.mark === 'keep') {
+ return 'true (' + record.data.keepReason + ')';
+ } else if (record.data.mark === 'protected') {
+ return 'true (strange name)';
+ } else {
+ return 'false';
+ }
+ },
+ flex: 1,
+ },
+ ],
+ },
+ ];
+
+ me.callParent();
+ },
+});
+
+Ext.define('PVE.window.Prune', {
+ extend: 'Proxmox.window.Edit',
+
+ method: 'DELETE',
+ submitText: gettext("Prune"),
+
+ fieldDefaults: { labelWidth: 130 },
+
+ 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] 22+ messages in thread
* [pve-devel] patrially-applied-series: [PATCH-SERIES v3 manager] split up content view into a view for each type
2020-11-13 13:16 [pve-devel] [PATCH-SERIES v3 manager] split up content view into a view for each type Fabian Ebner
` (19 preceding siblings ...)
2020-11-13 13:16 ` [pve-devel] [PATCH v3 manager 20/20] backup view: add prune window Fabian Ebner
@ 2020-11-16 9:11 ` Thomas Lamprecht
20 siblings, 0 replies; 22+ messages in thread
From: Thomas Lamprecht @ 2020-11-16 9:11 UTC (permalink / raw)
To: Proxmox VE development discussion, Fabian Ebner
On 13.11.20 14:16, Fabian Ebner wrote:
> 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. (see #16)
>
> 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 introduce grouping of backups
> and introduce the prune window, which was essentially copied from the PBS code.
>
> The prune window patch depends on this patch (otherwise it would error
> out when all numberfields are cleared):
> https://lists.proxmox.com/pipermail/pve-devel/2020-November/045916.html
>
> Changes from v2:
> * rebase on current master and deal with the new comment column
> * fix backup grouping for PBS storages
> * base prune window on the current prune window from PBS (there were
> some changes in the time since I sent v2)
>
> 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 | 128 +++++++
> www/manager6/storage/Browser.js | 97 ++++-
> www/manager6/storage/ContentView.js | 551 +++++++--------------------
> www/manager6/storage/ImageView.js | 74 ++++
> www/manager6/storage/TemplateView.js | 215 +++++++++++
> www/manager6/window/Prune.js | 306 +++++++++++++++
> 9 files changed, 1018 insertions(+), 478 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
>
applied all up to the RFC patch 16/20; with a few followups, some not directly related
to your series, rather the state of the code in general.
^ permalink raw reply [flat|nested] 22+ messages in thread