]> git.proxmox.com Git - pve-manager.git/commitdiff
ui: add vnet permissions panel
authorAlexandre Derumier <aderumier@odiso.com>
Wed, 7 Jun 2023 12:03:56 +0000 (14:03 +0200)
committerFabian Grünbichler <f.gruenbichler@proxmox.com>
Mon, 12 Jun 2023 11:18:12 +0000 (13:18 +0200)
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
www/manager6/Makefile
www/manager6/sdn/Browser.js
www/manager6/sdn/VnetACLView.js [new file with mode: 0644]
www/manager6/sdn/ZoneContentPanel.js [new file with mode: 0644]
www/manager6/sdn/ZoneContentView.js

index 71ab928ff9ac9ab2cfd8c21182eda5f7f49b6a4b..9b6dd13bc53ba6bedf2dbb241b1eb7e9bb883bc9 100644 (file)
@@ -252,10 +252,12 @@ JSSRC=                                                    \
        sdn/StatusView.js                               \
        sdn/VnetEdit.js                                 \
        sdn/VnetView.js                                 \
+       sdn/VnetACLView.js                                      \
        sdn/VnetPanel.js                                \
        sdn/SubnetEdit.js                               \
        sdn/SubnetView.js                               \
        sdn/ZoneContentView.js                          \
+       sdn/ZoneContentPanel.js                         \
        sdn/ZoneView.js                                 \
        sdn/OptionsPanel.js                             \
        sdn/controllers/Base.js                         \
index 09b0c4fe566c16c6f3d4dde51d8158fb11f9158a..3dc5a5ad771a988102fa3b4d98be75acfc721470 100644 (file)
@@ -25,14 +25,15 @@ Ext.define('PVE.sdn.Browser', {
 
        const caps = Ext.state.Manager.get('GuiCap');
 
-       if (caps.sdn['SDN.Audit']) {
-           me.items.push({
-               xtype: 'pveSDNZoneContentView',
-               title: gettext('Content'),
-               iconCls: 'fa fa-th',
-               itemId: 'content',
-           });
-       }
+       me.items.push({
+           nodename: nodename,
+           zone: sdnId,
+           xtype: 'pveSDNZoneContentPanel',
+           title: gettext('Content'),
+           iconCls: 'fa fa-th',
+           itemId: 'content',
+       });
+
        if (caps.sdn['Permissions.Modify']) {
            me.items.push({
                xtype: 'pveACLView',
diff --git a/www/manager6/sdn/VnetACLView.js b/www/manager6/sdn/VnetACLView.js
new file mode 100644 (file)
index 0000000..af10d95
--- /dev/null
@@ -0,0 +1,289 @@
+Ext.define('PVE.sdn.VnetACLAdd', {
+    extend: 'Proxmox.window.Edit',
+    alias: ['widget.pveSDNVnetACLAdd'],
+
+    url: '/access/acl',
+    method: 'PUT',
+    isAdd: true,
+    isCreate: true,
+
+    width: 400,
+    initComponent: function() {
+        let me = this;
+
+       let items = [
+           {
+               xtype: 'hiddenfield',
+               name: 'path',
+               value: me.path,
+               allowBlank: false,
+               fieldLabel: gettext('Path'),
+           },
+       ];
+
+       if (me.aclType === 'group') {
+           me.subject = gettext("Group Permission");
+           items.push({
+               xtype: 'pveGroupSelector',
+               name: 'groups',
+               fieldLabel: gettext('Group'),
+           });
+       } else if (me.aclType === 'user') {
+           me.subject = gettext("User Permission");
+           items.push({
+               xtype: 'pmxUserSelector',
+               name: 'users',
+               fieldLabel: gettext('User'),
+           });
+       } else if (me.aclType === 'token') {
+           me.subject = gettext("API Token Permission");
+           items.push({
+               xtype: 'pveTokenSelector',
+               name: 'tokens',
+               fieldLabel: gettext('API Token'),
+           });
+       } else {
+           throw "unknown ACL type";
+       }
+
+       items.push({
+           xtype: 'pmxRoleSelector',
+           name: 'roles',
+           value: 'NoAccess',
+           fieldLabel: gettext('Role'),
+       });
+
+       items.push({
+           xtype: 'proxmoxintegerfield',
+           name: 'vlan',
+           minValue: 1,
+           maxValue: 4096,
+            allowBlank: true,
+           fieldLabel: 'Vlan',
+           emptyText: gettext('All'),
+       });
+
+       let ipanel = Ext.create('Proxmox.panel.InputPanel', {
+           items: items,
+           onlineHelp: 'pveum_permission_management',
+           onGetValues: function(values) {
+               if (values.vlan) {
+                   values.path = values.path + "/" + values.vlan;
+                   delete values.vlan;
+               }
+               return values;
+           },
+       });
+
+       Ext.apply(me, {
+           items: [ipanel],
+       });
+
+       me.callParent();
+    },
+});
+
+Ext.define('PVE.sdn.VnetACLView', {
+    extend: 'Ext.grid.GridPanel',
+
+    alias: ['widget.pveSDNVnetACLView'],
+
+    onlineHelp: 'chapter_user_management',
+
+    stateful: true,
+    stateId: 'grid-acls',
+
+    // use fixed path
+    path: undefined,
+
+    setPath: function(path) {
+        let me = this;
+
+        me.path = path;
+
+        if (path === undefined) {
+           me.down('#groupmenu').setDisabled(true);
+           me.down('#usermenu').setDisabled(true);
+           me.down('#tokenmenu').setDisabled(true);
+        } else {
+           me.down('#groupmenu').setDisabled(false);
+           me.down('#usermenu').setDisabled(false);
+           me.down('#tokenmenu').setDisabled(false);
+            me.store.load();
+        }
+    },
+    initComponent: function() {
+       let me = this;
+
+       let store = Ext.create('Ext.data.Store', {
+           model: 'pve-acl',
+           proxy: {
+                type: 'proxmox',
+               url: "/api2/json/access/acl",
+           },
+           sorters: {
+               property: 'path',
+               direction: 'ASC',
+           },
+       });
+
+       store.addFilter(Ext.create('Ext.util.Filter', {
+           filterFn: item => item.data.path.replace(/(\/sdn\/zones\/(.*)\/(.*))\/[0-9]*$/, '$1') === me.path,
+       }));
+
+       let render_ugid = function(ugid, metaData, record) {
+           if (record.data.type === 'group') {
+               return '@' + ugid;
+           }
+
+           return Ext.String.htmlEncode(ugid);
+       };
+
+       let render_vlan = function(path, metaData, record) {
+           let vlan = 'any';
+           const match = path.match(/(\/sdn\/zones\/)(.*)\/(.*)\/([0-9]*)$/);
+           if (match) {
+               vlan = match[4];
+           }
+
+           return Ext.String.htmlEncode(vlan);
+       };
+
+       let columns = [
+           {
+               header: gettext('User') + '/' + gettext('Group') + '/' + gettext('API Token'),
+               flex: 1,
+               sortable: true,
+               renderer: render_ugid,
+               dataIndex: 'ugid',
+           },
+           {
+               header: gettext('Role'),
+               flex: 1,
+               sortable: true,
+               dataIndex: 'roleid',
+           },
+           {
+               header: gettext('Vlan'),
+               flex: 1,
+               sortable: true,
+               renderer: render_vlan,
+               dataIndex: 'path',
+           },
+       ];
+
+
+       let sm = Ext.create('Ext.selection.RowModel', {});
+
+       let remove_btn = new Proxmox.button.Button({
+           text: gettext('Remove'),
+           disabled: true,
+           selModel: sm,
+           confirmMsg: gettext('Are you sure you want to remove this entry'),
+           handler: function(btn, event, rec) {
+               var params = {
+                   'delete': 1,
+                   path: rec.data.path,
+                   roles: rec.data.roleid,
+               };
+               if (rec.data.type === 'group') {
+                   params.groups = rec.data.ugid;
+               } else if (rec.data.type === 'user') {
+                   params.users = rec.data.ugid;
+               } else if (rec.data.type === 'token') {
+                   params.tokens = rec.data.ugid;
+               } else {
+                   throw 'unknown data type';
+               }
+
+               Proxmox.Utils.API2Request({
+                   url: '/access/acl',
+                   params: params,
+                   method: 'PUT',
+                   waitMsgTarget: me,
+                   callback: () => store.load(),
+                   failure: response => Ext.Msg.alert(gettext('Error'), response.htmlStatus),
+               });
+           },
+       });
+
+       Proxmox.Utils.monStoreErrors(me, store);
+
+       Ext.apply(me, {
+           store: store,
+           selModel: sm,
+           tbar: [
+               {
+                   text: gettext('Add'),
+                   menu: {
+                       xtype: 'menu',
+                       items: [
+                           {
+                               text: gettext('Group Permission'),
+                               disabled: !me.path,
+                               itemId: 'groupmenu',
+                               iconCls: 'fa fa-fw fa-group',
+                               handler: function() {
+                                   var win = Ext.create('PVE.sdn.VnetACLAdd', {
+                                       aclType: 'group',
+                                       path: me.path,
+                                   });
+                                   win.on('destroy', () => store.load());
+                                   win.show();
+                               },
+                           },
+                           {
+                               text: gettext('User Permission'),
+                               disabled: !me.path,
+                               itemId: 'usermenu',
+                               iconCls: 'fa fa-fw fa-user',
+                               handler: function() {
+                                   var win = Ext.create('PVE.sdn.VnetACLAdd', {
+                                       aclType: 'user',
+                                       path: me.path,
+                                   });
+                                   win.on('destroy', () => store.load());
+                                   win.show();
+                               },
+                           },
+                           {
+                               text: gettext('API Token Permission'),
+                               disabled: !me.path,
+                               itemId: 'tokenmenu',
+                               iconCls: 'fa fa-fw fa-user-o',
+                               handler: function() {
+                                   let win = Ext.create('PVE.sdn.VnetACLAdd', {
+                                       aclType: 'token',
+                                       path: me.path,
+                                   });
+                                   win.on('destroy', () => store.load());
+                                   win.show();
+                               },
+                           },
+                       ],
+                   },
+               },
+               remove_btn,
+           ],
+           viewConfig: {
+               trackOver: false,
+           },
+           columns: columns,
+           listeners: {
+           },
+       });
+
+       me.callParent();
+    },
+}, function() {
+    Ext.define('pve-acl-vnet', {
+       extend: 'Ext.data.Model',
+       fields: [
+           'path', 'type', 'ugid', 'roleid',
+           {
+               name: 'propagate',
+               type: 'boolean',
+           },
+       ],
+    });
+});
diff --git a/www/manager6/sdn/ZoneContentPanel.js b/www/manager6/sdn/ZoneContentPanel.js
new file mode 100644 (file)
index 0000000..5bb081b
--- /dev/null
@@ -0,0 +1,41 @@
+Ext.define('PVE.sdn.ZoneContentPanel', {
+    extend: 'Ext.panel.Panel',
+    alias: 'widget.pveSDNZoneContentPanel',
+
+    title: 'Vnet',
+
+    onlineHelp: 'pvesdn_config_vnet',
+
+    initComponent: function() {
+       var me = this;
+
+       var permissions_panel = Ext.createWidget('pveSDNVnetACLView', {
+           title: gettext('Vnet Permissions'),
+           region: 'center',
+           border: false,
+       });
+
+       var vnetview_panel = Ext.createWidget('pveSDNZoneContentView', {
+           title: 'Vnets',
+           region: 'west',
+           permissions_panel: permissions_panel,
+           nodename: me.nodename,
+           zone: me.zone,
+           width: '50%',
+           border: false,
+           split: true,
+       });
+
+       Ext.apply(me, {
+           layout: 'border',
+           items: [vnetview_panel, permissions_panel],
+           listeners: {
+               show: function() {
+                   permissions_panel.fireEvent('show', permissions_panel);
+               },
+           },
+       });
+
+       me.callParent();
+    },
+});
index 1ea65450b7360c0c3693ded0ca3a7cdfc3a69dc6..4bc92718399d73aac94871acd33b5adb6444e4da 100644 (file)
@@ -17,17 +17,15 @@ Ext.define('PVE.sdn.ZoneContentView', {
     initComponent: function() {
        var me = this;
 
-       var nodename = me.pveSelNode.data.node;
-       if (!nodename) {
+       if (!me.nodename) {
            throw "no node name specified";
        }
 
-       var zone = me.pveSelNode.data.sdn;
-       if (!zone) {
+       if (!me.zone) {
            throw "no zone ID specified";
        }
 
-       var baseurl = "/nodes/" + nodename + "/sdn/zones/" + zone + "/content";
+       var baseurl = "/nodes/" + me.nodename + "/sdn/zones/" + me.zone + "/content";
        var store = Ext.create('Ext.data.Store', {
            model: 'pve-sdnzone-content',
            groupField: 'content',
@@ -48,7 +46,6 @@ Ext.define('PVE.sdn.ZoneContentView', {
        };
 
        Proxmox.Utils.monStoreErrors(me, store);
-
        Ext.apply(me, {
            store: store,
            selModel: sm,
@@ -79,11 +76,19 @@ Ext.define('PVE.sdn.ZoneContentView', {
                    dataIndex: 'statusmsg',
                },
            ],
-           listeners: {
-               activate: reload,
-           },
+            listeners: {
+                activate: reload,
+                show: reload,
+                select: function(_sm, rec) {
+                    let path = `/sdn/zones/${me.zone}/${rec.data.vnet}`;
+                    me.permissions_panel.setPath(path);
+                },
+                deselect: function() {
+                    me.permissions_panel.setPath(undefined);
+                },
+            },
        });
-
+       store.load();
        me.callParent();
     },
 }, function() {