* [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