]> git.proxmox.com Git - proxmox-backup.git/commitdiff
ui: tape/Restore: allow simple namespace mapping
authorDominik Csapak <d.csapak@proxmox.com>
Fri, 13 May 2022 11:44:30 +0000 (13:44 +0200)
committerDominik Csapak <d.csapak@proxmox.com>
Fri, 13 May 2022 12:09:53 +0000 (14:09 +0200)
add a default namespace selector (of the current default store)
and a namespace selector per target datastore (for media-sets with
multiple datastores).

to achieve that we have to change the way we handle the mapping field a bit:
* don't use it as field directly (otherwise the value gets stringified),
  but use the 'getValue' method in 'onGetValues'.
* set the defaultStore there, not only that we have one
  (with this we can now easily show it as emptytext for each store)
* add a reference to the widgets to the record so that we can access
  them in the respective change handler (also clean those references up,
  else we have a cyclic reference between record <-> widget)

in onGetValues, if we have multiple datastores, the mapping grid does
all the work for us, otherwise, we have to create the ns mapping
ourselves there.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
www/form/NamespaceSelector.js
www/tape/window/TapeRestore.js

index 9f20d04ef64be151b5ed277eaf756645734fa7d3..6218a4e230a0f9fe8f4d6caa41c2621626a6c104 100644 (file)
@@ -66,6 +66,9 @@ Ext.define('PBS.form.NamespaceSelector', {
            }
            me.store.load();
            me.validate();
+       } else {
+           me.datastore = undefined;
+           me.setDisabled(true);
        }
     },
 
index f68ab0b99ad40aacdbba26c87147bf4f78ec1c0c..080100855bee1b806f2d32d60c6b41a38b52b2a4 100644 (file)
@@ -38,6 +38,8 @@ Ext.define('PBS.TapeManagement.TapeRestoreWindow', {
            singleSelectorLabel: get =>
                get('singleDatastore') ? gettext('Target Datastore') : gettext('Default Datastore'),
            singleSelectorEmptyText: get => get('singleDatastore') ? '' : Proxmox.Utils.NoneText,
+           singleSelectorLabelNs: get =>
+               get('singleDatastore') ? gettext('Target Namespace') : gettext('Default Namespace'),
        },
     },
 
@@ -371,16 +373,29 @@ Ext.define('PBS.TapeManagement.TapeRestoreWindow', {
                    xtype: 'inputpanel',
                    onGetValues: function(values) {
                        let me = this;
+                       let controller = me.up('window').getController();
                        let datastores = [];
                        if (values.store.toString() !== "") {
                            datastores.push(values.store);
                            delete values.store;
                        }
 
-                       if (values.mapping.toString() !== "") {
-                           datastores.push(values.mapping);
+                       let defaultNs = values.defaultNs;
+                       delete values.defaultNs;
+
+                       let [ds_map, ns_map] = me.down('pbsDataStoreMappingField').getValue();
+                       if (ds_map !== '') {
+                           datastores.push(ds_map);
+                       }
+                       if (ns_map.length > 0) {
+                           values.namespaces = ns_map;
+                       }
+
+                       if (defaultNs && ns_map.length === 0 && controller.datastores.length === 1) {
+                           // we only have one datastore and a default ns
+                           values.namespaces = [`store=${controller.datastores[0]},target=${defaultNs}`];
                        }
-                       delete values.mapping;
+
 
                        values.store = datastores.join(',');
 
@@ -427,7 +442,22 @@ Ext.define('PBS.TapeManagement.TapeRestoreWindow', {
                            },
                            listeners: {
                                change: function(field, value) {
-                                   this.up('window').lookup('mappingGrid').setNeedStores(!value);
+                                   this.up('window').lookup('mappingGrid').setDefaultStore(value);
+                                   this.up('window').lookup('defaultNs').setDatastore(value);
+                               },
+                           },
+                       },
+                       {
+                           xtype: 'pbsNamespaceSelector',
+                           name: 'defaultNs',
+                           reference: 'defaultNs',
+                           labelWidth: 120,
+                           bind: {
+                               fieldLabel: '{singleSelectorLabelNs}',
+                           },
+                           listeners: {
+                               change: function(field, value) {
+                                   this.up('window').lookup('mappingGrid').setDefaultNs(value);
                                },
                            },
                        },
@@ -444,9 +474,9 @@ Ext.define('PBS.TapeManagement.TapeRestoreWindow', {
                        },
                        {
                            xtype: 'pbsDataStoreMappingField',
-                           name: 'mapping',
+                           isFormField: false,
                            reference: 'mappingGrid',
-                           height: 260,
+                           height: 240,
                            defaultBindProperty: 'value',
                            bind: {
                                hidden: '{singleDatastore}',
@@ -473,28 +503,54 @@ Ext.define('PBS.TapeManagement.DataStoreMappingGrid', {
     getValue: function() {
        let me = this;
        let datastores = [];
+       let namespaces = [];
+       let defaultStore = me.getViewModel().get('defaultStore');
+       let defaultNs = me.getViewModel().get('defaultNs');
        me.getStore().each(rec => {
-           let { source, target } = rec.data;
+           let { source, target, targetns } = rec.data;
            if (target && target !== "") {
                datastores.push(`${source}=${target}`);
            }
+           if (target || defaultStore) {
+               let ns = targetns || defaultNs;
+               if (ns) {
+                   namespaces.push(`store=${source},target=${ns}`);
+               }
+           }
        });
 
-       return datastores.join(',');
+       return [datastores.join(','), namespaces];
     },
 
     viewModel: {
        data: {
-           needStores: false, // this determines if we need at least one valid mapping
+           defaultStore: '',
+           defaultNs: false,
        },
        formulas: {
-           emptyMeans: get => get('needStores') ? Proxmox.Utils.NoneText : Proxmox.Utils.defaultText,
+           emptyStore: get => get('defaultStore') || Proxmox.Utils.NoneText,
+           emptyNs: get => get('defaultNs') || gettext('Root'),
        },
     },
 
-    setNeedStores: function(needStores) {
+    setDefaultStore: function(store) {
        let me = this;
-       me.getViewModel().set('needStores', needStores);
+       me.getViewModel().set('defaultStore', store);
+       me.getStore().each((rec) => {
+           if (!rec.dswidget) {
+               return; // not yet attached
+           }
+           if (!rec.dswidget.getValue()) {
+               rec.nswidget.setDatastore(store);
+           }
+       });
+       me.checkChange();
+       me.validate();
+    },
+
+    setDefaultNs: function(defaultNs) {
+       let me = this;
+       me.getViewModel().set('defaultNs', defaultNs);
        me.checkChange();
        me.validate();
     },
@@ -509,7 +565,7 @@ Ext.define('PBS.TapeManagement.DataStoreMappingGrid', {
        let me = this;
        let error = false;
 
-       if (me.getViewModel().get('needStores')) {
+       if (me.getViewModel().get('defaultStore') !== '') {
            error = true;
            me.getStore().each(rec => {
                if (rec.data.target) {
@@ -543,6 +599,7 @@ Ext.define('PBS.TapeManagement.DataStoreMappingGrid', {
            data.push({
                source: datastore,
                target: '',
+               targetNs: '',
            });
        }
 
@@ -555,6 +612,16 @@ Ext.define('PBS.TapeManagement.DataStoreMappingGrid', {
 
     store: { data: [] },
 
+    listeners: {
+       beforedestroy: function() {
+           // break cyclic reference
+           this.getStore()?.each((rec) => {
+               delete rec.nswidget;
+               delete rec.dswidget;
+           });
+       },
+    },
+
     columns: [
        {
            text: gettext('Source Datastore'),
@@ -564,6 +631,10 @@ Ext.define('PBS.TapeManagement.DataStoreMappingGrid', {
        {
            text: gettext('Target Datastore'),
            xtype: 'widgetcolumn',
+           onWidgetAttach: function(col, widget, rec) {
+               // so that we can access it from the store
+               rec.dswidget = widget;
+           },
            dataIndex: 'target',
            flex: 1,
            widget: {
@@ -571,7 +642,7 @@ Ext.define('PBS.TapeManagement.DataStoreMappingGrid', {
                isFormField: false,
                allowBlank: true,
                bind: {
-                   emptyText: '{emptyMeans}',
+                   emptyText: '{emptyStore}',
                },
                listeners: {
                    change: function(selector, value) {
@@ -581,6 +652,36 @@ Ext.define('PBS.TapeManagement.DataStoreMappingGrid', {
                            return;
                        }
                        rec.set('target', value);
+                       rec.nswidget.setDatastore(value);
+                       me.up('grid').checkChange();
+                   },
+               },
+           },
+       },
+       {
+           text: gettext('Target Namespace'),
+           xtype: 'widgetcolumn',
+           onWidgetAttach: function(col, widget, rec) {
+               // so that we can access it from the store
+               rec.nswidget = widget;
+           },
+           dataIndex: 'targetns',
+           flex: 1,
+           widget: {
+               xtype: 'pbsNamespaceSelector',
+               isFormField: false,
+               allowBlank: true,
+               bind: {
+                   emptyText: '{emptyNs}',
+               },
+               listeners: {
+                   change: function(selector, value) {
+                       let me = this;
+                       let rec = me.getWidgetRecord();
+                       if (!rec) {
+                           return;
+                       }
+                       rec.set('targetns', value);
                        me.up('grid').checkChange();
                    },
                },