Signed-off-by: Fabian Ebner <f.eb...@proxmox.com>
---

Changes from v4:
    * move code from activation listener into a reload() helper to be re-useable
    * add a reload button

 src/Makefile                |   1 +
 src/node/APTRepositories.js | 268 ++++++++++++++++++++++++++++++++++++
 2 files changed, 269 insertions(+)
 create mode 100644 src/node/APTRepositories.js

diff --git a/src/Makefile b/src/Makefile
index 9e3ad4e..9c00b98 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -67,6 +67,7 @@ JSSRC=                                        \
        window/ACMEDomains.js           \
        window/FileBrowser.js           \
        node/APT.js                     \
+       node/APTRepositories.js         \
        node/NetworkEdit.js             \
        node/NetworkView.js             \
        node/DNSEdit.js                 \
diff --git a/src/node/APTRepositories.js b/src/node/APTRepositories.js
new file mode 100644
index 0000000..71b141c
--- /dev/null
+++ b/src/node/APTRepositories.js
@@ -0,0 +1,268 @@
+Ext.define('apt-repolist', {
+    extend: 'Ext.data.Model',
+    fields: [
+       'Path',
+       'Number',
+       'FileType',
+       'Enabled',
+       'Comment',
+       'Types',
+       'URIs',
+       'Suites',
+       'Components',
+       'Options',
+    ],
+});
+
+Ext.define('Proxmox.node.APTRepositoriesErrors', {
+    extend: 'Ext.grid.GridPanel',
+
+    xtype: 'proxmoxNodeAPTRepositoriesErrors',
+
+    title: gettext('Errors'),
+
+    store: {},
+
+    viewConfig: {
+       stripeRows: false,
+       getRowClass: () => 'proxmox-invalid-row',
+    },
+
+    columns: [
+       {
+           header: gettext('File'),
+           dataIndex: 'path',
+           renderer: function(value, cell, record) {
+               return "<i class='pve-grid-fa fa fa-fw " +
+                   "fa-exclamation-triangle'></i>" + value;
+           },
+           width: 350,
+       },
+       {
+           header: gettext('Error'),
+           dataIndex: 'error',
+           flex: 1,
+       },
+    ],
+});
+
+Ext.define('Proxmox.node.APTRepositoriesGrid', {
+    extend: 'Ext.grid.GridPanel',
+
+    xtype: 'proxmoxNodeAPTRepositoriesGrid',
+
+    title: gettext('APT Repositories'),
+
+    sortableColumns: false,
+
+    columns: [
+       {
+           header: gettext('Enabled'),
+           dataIndex: 'Enabled',
+           renderer: Proxmox.Utils.format_enabled_toggle,
+           width: 90,
+       },
+       {
+           header: gettext('Types'),
+           dataIndex: 'Types',
+           renderer: function(types, cell, record) {
+               return types.join(' ');
+           },
+           width: 100,
+       },
+       {
+           header: gettext('URIs'),
+           dataIndex: 'URIs',
+           renderer: function(uris, cell, record) {
+               return uris.join(' ');
+           },
+           width: 350,
+       },
+       {
+           header: gettext('Suites'),
+           dataIndex: 'Suites',
+           renderer: function(suites, cell, record) {
+               return suites.join(' ');
+           },
+           width: 130,
+       },
+       {
+           header: gettext('Components'),
+           dataIndex: 'Components',
+           renderer: function(components, cell, record) {
+               return components.join(' ');
+           },
+           width: 170,
+       },
+       {
+           header: gettext('Options'),
+           dataIndex: 'Options',
+           renderer: function(options, cell, record) {
+               if (!options) {
+                   return '';
+               }
+
+               let filetype = record.data.FileType;
+               let text = '';
+
+               options.forEach(function(option) {
+                   let key = option.Key;
+                   if (filetype === 'list') {
+                       let values = option.Values.join(',');
+                       text += `${key}=${values} `;
+                   } else if (filetype === 'sources') {
+                       let values = option.Values.join(' ');
+                       text += `${key}: ${values}<br>`;
+                   } else {
+                       throw "unkown file type";
+                   }
+               });
+               return text;
+           },
+           flex: 1,
+       },
+       {
+           header: gettext('Comment'),
+           dataIndex: 'Comment',
+           flex: 2,
+       },
+    ],
+
+    initComponent: function() {
+       let me = this;
+
+       let store = Ext.create('Ext.data.Store', {
+           model: 'apt-repolist',
+           groupField: 'Path',
+           sorters: [
+               {
+                   property: 'Number',
+                   direction: 'ASC',
+               },
+           ],
+       });
+
+       let groupingFeature = Ext.create('Ext.grid.feature.Grouping', {
+           groupHeaderTpl: '{[ "File: " + values.name ]} ({rows.length} ' +
+               'repositor{[values.rows.length > 1 ? "ies" : "y"]})',
+           enableGroupingMenu: false,
+       });
+
+       let sm = Ext.create('Ext.selection.RowModel', {});
+
+       Ext.apply(me, {
+           store: store,
+           selModel: sm,
+           features: [groupingFeature],
+       });
+
+       me.callParent();
+    },
+});
+
+Ext.define('Proxmox.node.APTRepositories', {
+    extend: 'Ext.panel.Panel',
+
+    xtype: 'proxmoxNodeAPTRepositories',
+
+    digest: undefined,
+
+    viewModel: {
+       data: {
+           errorCount: 0,
+       },
+       formulas: {
+           noErrors: (get) => get('errorCount') === 0,
+       },
+    },
+
+    items: [
+       {
+           xtype: 'proxmoxNodeAPTRepositoriesErrors',
+           name: 'repositoriesErrors',
+           hidden: true,
+           bind: {
+               hidden: '{noErrors}',
+           },
+       },
+       {
+           xtype: 'proxmoxNodeAPTRepositoriesGrid',
+           name: 'repositoriesGrid',
+       },
+    ],
+
+    tbar: [
+       {
+           xtype: 'proxmoxButton',
+           text: gettext('Reload'),
+           handler: function() {
+               let me = this;
+               me.up('proxmoxNodeAPTRepositories').reload();
+           },
+       },
+    ],
+
+    reload: function() {
+       let me = this;
+       let vm = me.getViewModel();
+       let repoGrid = me.down('proxmoxNodeAPTRepositoriesGrid');
+       let errorGrid = me.down('proxmoxNodeAPTRepositoriesErrors');
+
+       me.store.load(function(records, operation, success) {
+           let gridData = [];
+           let errors = [];
+           let digest;
+
+           if (success && records.length > 0) {
+               let data = records[0].data;
+               let files = data.files;
+               errors = data.errors;
+               digest = data.digest;
+
+               files.forEach(function(file) {
+                   for (let n = 0; n < file.repositories.length; n++) {
+                       let repo = file.repositories[n];
+                       repo.Path = file.path;
+                       repo.Number = n + 1;
+                       gridData.push(repo);
+                   }
+               });
+           }
+
+           me.digest = digest;
+
+           repoGrid.store.loadData(gridData);
+
+           vm.set('errorCount', errors.length);
+           errorGrid.store.loadData(errors);
+       });
+    },
+
+    listeners: {
+       activate: function() {
+           let me = this;
+           me.reload();
+       },
+    },
+
+    initComponent: function() {
+       let me = this;
+
+       if (!me.nodename) {
+           throw "no node name specified";
+       }
+
+       let store = Ext.create('Ext.data.Store', {
+           proxy: {
+               type: 'proxmox',
+               url: `/api2/json/nodes/${me.nodename}/apt/repositories`,
+           },
+       });
+
+       Ext.apply(me, { store: store });
+
+       Proxmox.Utils.monStoreErrors(me, me.store, true);
+
+       me.callParent();
+    },
+});
-- 
2.20.1



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to