]>
git.proxmox.com Git - proxmox-widget-toolkit.git/blob - src/node/APTRepositories.js
1 Ext
.define('apt-repolist', {
2 extend
: 'Ext.data.Model',
18 Ext
.define('Proxmox.node.APTRepositoriesErrors', {
19 extend
: 'Ext.grid.GridPanel',
21 xtype
: 'proxmoxNodeAPTRepositoriesErrors',
23 title
: gettext('Errors'),
29 getRowClass
: () => 'proxmox-invalid-row',
34 header
: gettext('File'),
36 renderer: function(value
, cell
, record
) {
37 return "<i class='pve-grid-fa fa fa-fw " +
38 "fa-exclamation-triangle'></i>" + value
;
43 header
: gettext('Error'),
50 Ext
.define('Proxmox.node.APTRepositoriesGrid', {
51 extend
: 'Ext.grid.GridPanel',
53 xtype
: 'proxmoxNodeAPTRepositoriesGrid',
55 title
: gettext('APT Repositories'),
59 text
: gettext('Reload'),
60 iconCls
: 'fa fa-refresh',
63 me
.up('proxmoxNodeAPTRepositories').reload();
68 sortableColumns
: false,
72 header
: gettext('Official'),
73 dataIndex
: 'OfficialHost',
74 renderer: function(value
, cell
, record
) {
75 let icon
= (cls
) => `<i class="fa fa-fw ${cls}"></i>`;
77 const enabled
= record
.data
.Enabled
;
79 if (value
=== undefined || value
=== null) {
80 return icon('fa-question-circle-o');
83 return icon('fa-times ' + (enabled
? 'critical' : 'faded'));
85 return icon('fa-check ' + (enabled
? 'good' : 'faded'));
90 header
: gettext('Enabled'),
92 renderer
: Proxmox
.Utils
.format_enabled_toggle
,
96 header
: gettext('Types'),
98 renderer: function(types
, cell
, record
) {
99 return types
.join(' ');
104 header
: gettext('URIs'),
106 renderer: function(uris
, cell
, record
) {
107 return uris
.join(' ');
112 header
: gettext('Suites'),
114 renderer: function(suites
, cell
, record
) {
115 return suites
.join(' ');
120 header
: gettext('Components'),
121 dataIndex
: 'Components',
122 renderer: function(components
, cell
, record
) {
123 return components
.join(' ');
128 header
: gettext('Options'),
129 dataIndex
: 'Options',
130 renderer: function(options
, cell
, record
) {
135 let filetype
= record
.data
.FileType
;
138 options
.forEach(function(option
) {
139 let key
= option
.Key
;
140 if (filetype
=== 'list') {
141 let values
= option
.Values
.join(',');
142 text
+= `${key}=${values} `;
143 } else if (filetype
=== 'sources') {
144 let values
= option
.Values
.join(' ');
145 text
+= `${key}: ${values}<br>`;
147 throw "unkown file type";
155 header
: gettext('Comment'),
156 dataIndex
: 'Comment',
161 addAdditionalInfos: function(gridData
, infos
) {
165 let officialHosts
= {};
167 let addLine = function(obj
, key
, line
) {
176 for (const info
of infos
) {
177 const key
= `${info.path}:${info.index}`;
178 if (info
.kind
=== 'warning' ||
179 (info
.kind
=== 'ignore-pre-upgrade-warning' && !me
.majorUpgradeAllowed
)) {
180 addLine(warnings
, key
, gettext('Warning') + ": " + info
.message
);
181 } else if (info
.kind
=== 'badge' && info
.message
=== 'official host name') {
182 officialHosts
[key
] = true;
186 gridData
.forEach(function(record
) {
187 const key
= `${record.Path}:${record.Index}`;
188 record
.OfficialHost
= !!officialHosts
[key
];
191 me
.rowBodyFeature
.getAdditionalData = function(innerData
, rowIndex
, record
, orig
) {
192 let headerCt
= this.view
.headerCt
;
193 let colspan
= headerCt
.getColumnCount();
195 const key
= `${innerData.Path}:${innerData.Index}`;
196 const warning_text
= warnings
[key
];
199 rowBody
: '<div style="color: red; white-space: pre-line">' +
200 Ext
.String
.htmlEncode(warning_text
) + '</div>',
201 rowBodyCls
: warning_text
? '' : Ext
.baseCSSPrefix
+ 'grid-row-body-hidden',
202 rowBodyColspan
: colspan
,
207 initComponent: function() {
211 throw "no node name specified";
214 let store
= Ext
.create('Ext.data.Store', {
215 model
: 'apt-repolist',
225 let rowBodyFeature
= Ext
.create('Ext.grid.feature.RowBody', {});
227 let groupingFeature
= Ext
.create('Ext.grid.feature.Grouping', {
228 groupHeaderTpl
: '{[ "File: " + values.name ]} ({rows.length} ' +
229 'repositor{[values.rows.length > 1 ? "ies" : "y"]})',
230 enableGroupingMenu
: false,
233 let sm
= Ext
.create('Ext.selection.RowModel', {});
238 rowBodyFeature
: rowBodyFeature
,
239 features
: [groupingFeature
, rowBodyFeature
],
246 Ext
.define('Proxmox.node.APTRepositories', {
247 extend
: 'Ext.panel.Panel',
249 xtype
: 'proxmoxNodeAPTRepositories',
250 mixins
: ['Proxmox.Mixin.CBind'],
257 subscriptionActive
: '',
258 noSubscriptionRepo
: '',
262 noErrors
: (get) => get('errorCount') === 0,
263 mainWarning: function(get) {
264 // Not yet initialized
265 if (get('subscriptionActive') === '' ||
266 get('enterpriseRepo') === '') {
270 let withStyle
= (msg
) => "<div style='color:red;'><i class='fa fa-fw " +
271 "fa-exclamation-triangle'></i>" + gettext('Warning') + ': ' + msg
+ "</div>";
273 if (!get('subscriptionActive') && get('enterpriseRepo')) {
274 return withStyle(gettext('The enterprise repository is ' +
275 'enabled, but there is no active subscription!'));
278 if (get('noSubscriptionRepo')) {
279 return withStyle(gettext('The no-subscription repository is ' +
280 'not recommended for production use!'));
283 if (!get('enterpriseRepo') && !get('noSubscriptionRepo')) {
284 return withStyle(gettext('No Proxmox repository is enabled!'));
294 title
: gettext('Warning'),
295 name
: 'repositoriesMainWarning',
298 title
: '{mainWarning}',
299 hidden
: '{!mainWarning}',
303 xtype
: 'proxmoxNodeAPTRepositoriesErrors',
304 name
: 'repositoriesErrors',
307 hidden
: '{noErrors}',
311 xtype
: 'proxmoxNodeAPTRepositoriesGrid',
312 name
: 'repositoriesGrid',
314 nodename
: '{nodename}',
316 majorUpgradeAllowed
: false, // TODO get release information from an API call?
320 check_subscription: function() {
322 let vm
= me
.getViewModel();
324 Proxmox
.Utils
.API2Request({
325 url
: `/nodes/${me.nodename}/subscription`,
327 failure: function(response
, opts
) {
328 Ext
.Msg
.alert(gettext('Error'), response
.htmlStatus
);
330 success: function(response
, opts
) {
331 const res
= response
.result
;
332 const subscription
= !(res
=== null || res
=== undefined ||
333 !res
|| res
.data
.status
.toLowerCase() !== 'active');
334 vm
.set('subscriptionActive', subscription
);
339 updateStandardRepos: function(standardRepos
) {
341 let vm
= me
.getViewModel();
343 for (const standardRepo
of standardRepos
) {
344 const handle
= standardRepo
.handle
;
345 const status
= standardRepo
.status
;
347 if (handle
=== "enterprise") {
348 vm
.set('enterpriseRepo', status
);
349 } else if (handle
=== "no-subscription") {
350 vm
.set('noSubscriptionRepo', status
);
357 let vm
= me
.getViewModel();
358 let repoGrid
= me
.down('proxmoxNodeAPTRepositoriesGrid');
359 let errorGrid
= me
.down('proxmoxNodeAPTRepositoriesErrors');
361 me
.store
.load(function(records
, operation
, success
) {
366 if (success
&& records
.length
> 0) {
367 let data
= records
[0].data
;
368 let files
= data
.files
;
369 errors
= data
.errors
;
370 digest
= data
.digest
;
372 files
.forEach(function(file
) {
373 for (let n
= 0; n
< file
.repositories
.length
; n
++) {
374 let repo
= file
.repositories
[n
];
375 repo
.Path
= file
.path
;
381 repoGrid
.addAdditionalInfos(gridData
, data
.infos
);
382 repoGrid
.store
.loadData(gridData
);
384 me
.updateStandardRepos(data
['standard-repos']);
389 vm
.set('errorCount', errors
.length
);
390 errorGrid
.store
.loadData(errors
);
393 me
.check_subscription();
397 activate: function() {
403 initComponent: function() {
407 throw "no node name specified";
410 let store
= Ext
.create('Ext.data.Store', {
413 url
: `/api2/json/nodes/${me.nodename}/apt/repositories`,
417 Ext
.apply(me
, { store
: store
});
419 Proxmox
.Utils
.monStoreErrors(me
, me
.store
, true);