This commit implements support for custom form views for custom storage plugins. This is achieved by adapting the `createStorageEditWindow()` function to request the plugin's form view if it's a custom plugin. Whether a plugin is custom or not is first determined by fetching the metadata of all plugins.
Furthermore, custom storage plugins now show up in the menu of the "Add" button. If a custom plugin defines a form view, the user can create a new storage config entry using the GUI. The 'short-name' of custom plugins is now also displayed in the storage config list as well as the dropdown selection list of the "Add" button, if present. Otherwise, we fall back to just using the plugin's type, as we were already doing. The items in the menu of the "Add" button are now added dynamically. This is because making requests is asynchronous. Anything else has led to various exceptions being thrown while testing this, due to race conditions. Signed-off-by: Max R. Carrara <[email protected]> --- www/manager6/dc/StorageView.js | 134 +++++++++++++++++++++++++++------ 1 file changed, 113 insertions(+), 21 deletions(-) diff --git a/www/manager6/dc/StorageView.js b/www/manager6/dc/StorageView.js index e4c6f07d..f4515c94 100644 --- a/www/manager6/dc/StorageView.js +++ b/www/manager6/dc/StorageView.js @@ -11,6 +11,47 @@ Ext.define( stateId: 'grid-dc-storage', createStorageEditWindow: function (type, sid) { + let me = this; + + let metadataForPlugin = me.pluginMetadata[type]; + + if (!metadataForPlugin) { + Ext.Msg.alert(gettext('Error'), `Plugin '${type}' has no metadata`); + return; + } + + // NOTE: zfspool is only hardcoded for demonstration purposes + if (metadataForPlugin.kind === 'custom' || type === 'zfspool') { + Proxmox.Utils.API2Request({ + url: `/api2/extjs/plugins/storage/${type}/views/form`, + method: 'GET', + params: { + mode: sid ? 'update' : 'create', + }, + failure: function ({ htmlStatus }) { + Ext.Msg.alert(gettext('Error'), htmlStatus); + }, + success: function ({ result: { data } }) { + let formView = data; + + Ext.create('PVE.storage.CustomBaseEdit', { + paneltype: 'PVE.storage.CustomInputPanel', + type: type, + storageId: sid, + canDoBackups: metadataForPlugin.content.supported.includes('backup'), + formView: formView, + metadataForPlugin: metadataForPlugin, + autoShow: true, + listeners: { + destroy: me.reloadStore, + }, + }); + }, + }); + + return; + } + let schema = PVE.Utils.storageSchema[type]; if (!schema || !schema.ipanel) { throw 'no editor registered for storage type: ' + type; @@ -23,7 +64,7 @@ Ext.define( canDoBackups: schema.backups, autoShow: true, listeners: { - destroy: this.reloadStore, + destroy: me.reloadStore, }, }); }, @@ -45,6 +86,63 @@ Ext.define( let sm = Ext.create('Ext.selection.RowModel', {}); + me.pluginMetadata = {}; + + let menuButtonAdd = new Ext.menu.Menu({ + items: [], + }); + + let pushBuiltinPluginsToMenu = function () { + for (const [type, storage] of Object.entries(PVE.Utils.storageSchema)) { + console.log(`Adding builtin plugin '${type}' to Add Button`); + if (storage.hideAdd) { + continue; + } + + menuButtonAdd.add({ + text: PVE.Utils.format_storage_type(type), + iconCls: 'fa fa-fw fa-' + storage.faIcon, + handler: () => me.createStorageEditWindow(type), + }); + } + }; + + let pushCustomPluginsToMenu = function () { + for (const type in me.pluginMetadata) { + if (!Object.hasOwn(me.pluginMetadata, type)) { + continue; + } + + const metadata = me.pluginMetadata[type]; + + if (metadata.kind !== 'custom') { + continue; + } + + menuButtonAdd.add({ + text: metadata['short-name'] || PVE.Utils.format_storage_type(type), + iconCls: 'fa fa-fw fa-folder', + handler: () => me.createStorageEditWindow(type), + }); + } + }; + + Proxmox.Utils.API2Request({ + url: `/api2/extjs/plugins/storage`, + method: 'GET', + success: function ({ result: { data } }) { + data.forEach((metadata) => { + me.pluginMetadata[metadata.type] = metadata; + }); + + pushBuiltinPluginsToMenu(); + pushCustomPluginsToMenu(); + }, + failure: function ({ htmlStatus }) { + Ext.Msg.alert('Error', htmlStatus); + }, + }); + let run_editor = function () { let rec = sm.getSelection()[0]; if (!rec) { @@ -66,23 +164,19 @@ Ext.define( callback: () => store.load(), }); - // else we cannot dynamically generate the add menu handlers - let addHandleGenerator = function (type) { - return function () { - me.createStorageEditWindow(type); - }; - }; - let addMenuItems = []; - for (const [type, storage] of Object.entries(PVE.Utils.storageSchema)) { - if (storage.hideAdd) { - continue; + // value is plugin type here + let columnRendererType = function (value, meta, record) { + let metadataForPlugin = me.pluginMetadata[value]; + + if (metadataForPlugin && metadataForPlugin.kind === 'custom') { + return ( + metadataForPlugin['short-name'] || + PVE.Utils.format_storage_type(value, meta, record) + ); } - addMenuItems.push({ - text: PVE.Utils.format_storage_type(type), - iconCls: 'fa fa-fw fa-' + storage.faIcon, - handler: addHandleGenerator(type), - }); - } + + return PVE.Utils.format_storage_type(value, meta, record); + }; Ext.apply(me, { store: store, @@ -94,9 +188,7 @@ Ext.define( tbar: [ { text: gettext('Add'), - menu: new Ext.menu.Menu({ - items: addMenuItems, - }), + menu: menuButtonAdd, }, remove_btn, edit_btn, @@ -113,7 +205,7 @@ Ext.define( flex: 1, sortable: true, dataIndex: 'type', - renderer: PVE.Utils.format_storage_type, + renderer: columnRendererType, }, { header: gettext('Content'), -- 2.47.2 _______________________________________________ pve-devel mailing list [email protected] https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
