]>
Commit | Line | Data |
---|---|---|
1 | Ext.define('apt-repolist', { | |
2 | extend: 'Ext.data.Model', | |
3 | fields: [ | |
4 | 'Path', | |
5 | 'Index', | |
6 | 'Origin', | |
7 | 'FileType', | |
8 | 'Enabled', | |
9 | 'Comment', | |
10 | 'Types', | |
11 | 'URIs', | |
12 | 'Suites', | |
13 | 'Components', | |
14 | 'Options', | |
15 | ], | |
16 | }); | |
17 | ||
18 | Ext.define('Proxmox.window.APTRepositoryAdd', { | |
19 | extend: 'Proxmox.window.Edit', | |
20 | alias: 'widget.pmxAPTRepositoryAdd', | |
21 | ||
22 | isCreate: true, | |
23 | isAdd: true, | |
24 | ||
25 | subject: gettext('Repository'), | |
26 | width: 600, | |
27 | ||
28 | initComponent: function() { | |
29 | let me = this; | |
30 | ||
31 | if (!me.repoInfo || me.repoInfo.length === 0) { | |
32 | throw "repository information not initialized"; | |
33 | } | |
34 | ||
35 | let description = Ext.create('Ext.form.field.Display', { | |
36 | fieldLabel: gettext('Description'), | |
37 | name: 'description', | |
38 | }); | |
39 | ||
40 | let status = Ext.create('Ext.form.field.Display', { | |
41 | fieldLabel: gettext('Status'), | |
42 | name: 'status', | |
43 | renderer: function(value) { | |
44 | let statusText = gettext('Not yet configured'); | |
45 | if (value !== '') { | |
46 | statusText = Ext.String.format( | |
47 | '{0}: {1}', | |
48 | gettext('Configured'), | |
49 | value ? gettext('enabled') : gettext('disabled'), | |
50 | ); | |
51 | } | |
52 | ||
53 | return statusText; | |
54 | }, | |
55 | }); | |
56 | ||
57 | let repoSelector = Ext.create('Proxmox.form.KVComboBox', { | |
58 | fieldLabel: gettext('Repository'), | |
59 | xtype: 'proxmoxKVComboBox', | |
60 | name: 'handle', | |
61 | allowBlank: false, | |
62 | comboItems: me.repoInfo.map(info => [info.handle, info.name]), | |
63 | validator: function(renderedValue) { | |
64 | let handle = this.value; | |
65 | // we cannot use this.callParent in instantiations | |
66 | let valid = Proxmox.form.KVComboBox.prototype.validator.call(this, renderedValue); | |
67 | ||
68 | if (!valid || !handle) { | |
69 | return false; | |
70 | } | |
71 | ||
72 | const info = me.repoInfo.find(elem => elem.handle === handle); | |
73 | if (!info) { | |
74 | return false; | |
75 | } | |
76 | ||
77 | if (info.status) { | |
78 | return Ext.String.format(gettext('{0} is already configured'), renderedValue); | |
79 | } | |
80 | return valid; | |
81 | }, | |
82 | listeners: { | |
83 | change: function(f, value) { | |
84 | const info = me.repoInfo.find(elem => elem.handle === value); | |
85 | description.setValue(info.description); | |
86 | status.setValue(info.status); | |
87 | }, | |
88 | }, | |
89 | }); | |
90 | ||
91 | repoSelector.setValue(me.repoInfo[0].handle); | |
92 | ||
93 | Ext.apply(me, { | |
94 | items: [ | |
95 | repoSelector, | |
96 | description, | |
97 | status, | |
98 | ], | |
99 | repoSelector: repoSelector, | |
100 | }); | |
101 | ||
102 | me.callParent(); | |
103 | }, | |
104 | }); | |
105 | ||
106 | Ext.define('Proxmox.node.APTRepositoriesErrors', { | |
107 | extend: 'Ext.grid.GridPanel', | |
108 | ||
109 | xtype: 'proxmoxNodeAPTRepositoriesErrors', | |
110 | ||
111 | store: {}, | |
112 | ||
113 | scrollable: true, | |
114 | ||
115 | viewConfig: { | |
116 | stripeRows: false, | |
117 | getRowClass: (record) => { | |
118 | switch (record.data.status) { | |
119 | case 'warning': return 'proxmox-warning-row'; | |
120 | case 'critical': return 'proxmox-invalid-row'; | |
121 | default: return ''; | |
122 | } | |
123 | }, | |
124 | }, | |
125 | ||
126 | hideHeaders: true, | |
127 | ||
128 | columns: [ | |
129 | { | |
130 | dataIndex: 'status', | |
131 | renderer: (value) => `<i class="fa fa-fw ${Proxmox.Utils.get_health_icon(value, true)}"></i>`, | |
132 | width: 50, | |
133 | }, | |
134 | { | |
135 | dataIndex: 'message', | |
136 | flex: 1, | |
137 | }, | |
138 | ], | |
139 | }); | |
140 | ||
141 | Ext.define('Proxmox.node.APTRepositoriesGrid', { | |
142 | extend: 'Ext.grid.GridPanel', | |
143 | xtype: 'proxmoxNodeAPTRepositoriesGrid', | |
144 | ||
145 | title: gettext('APT Repositories'), | |
146 | ||
147 | cls: 'proxmox-apt-repos', // to allow applying styling to general components with local effect | |
148 | ||
149 | border: false, | |
150 | ||
151 | tbar: [ | |
152 | { | |
153 | text: gettext('Reload'), | |
154 | iconCls: 'fa fa-refresh', | |
155 | handler: function() { | |
156 | let me = this; | |
157 | me.up('proxmoxNodeAPTRepositories').reload(); | |
158 | }, | |
159 | }, | |
160 | { | |
161 | text: gettext('Add'), | |
162 | id: 'addButton', | |
163 | disabled: true, | |
164 | repoInfo: undefined, | |
165 | handler: function(button, event, record) { | |
166 | Proxmox.Utils.checked_command(() => { | |
167 | let me = this; | |
168 | let panel = me.up('proxmoxNodeAPTRepositories'); | |
169 | ||
170 | let extraParams = {}; | |
171 | if (panel.digest !== undefined) { | |
172 | extraParams.digest = panel.digest; | |
173 | } | |
174 | ||
175 | Ext.create('Proxmox.window.APTRepositoryAdd', { | |
176 | repoInfo: me.repoInfo, | |
177 | url: `/api2/extjs/nodes/${panel.nodename}/apt/repositories`, | |
178 | method: 'PUT', | |
179 | extraRequestParams: extraParams, | |
180 | listeners: { | |
181 | destroy: function() { | |
182 | panel.reload(); | |
183 | }, | |
184 | }, | |
185 | }).show(); | |
186 | }); | |
187 | }, | |
188 | }, | |
189 | '-', | |
190 | { | |
191 | xtype: 'proxmoxButton', | |
192 | text: gettext('Enable'), | |
193 | defaultText: gettext('Enable'), | |
194 | altText: gettext('Disable'), | |
195 | id: 'repoEnableButton', | |
196 | disabled: true, | |
197 | bind: { | |
198 | text: '{enableButtonText}', | |
199 | }, | |
200 | handler: function(button, event, record) { | |
201 | let me = this; | |
202 | let panel = me.up('proxmoxNodeAPTRepositories'); | |
203 | ||
204 | let params = { | |
205 | path: record.data.Path, | |
206 | index: record.data.Index, | |
207 | enabled: record.data.Enabled ? 0 : 1, // invert | |
208 | }; | |
209 | ||
210 | if (panel.digest !== undefined) { | |
211 | params.digest = panel.digest; | |
212 | } | |
213 | ||
214 | Proxmox.Utils.API2Request({ | |
215 | url: `/nodes/${panel.nodename}/apt/repositories`, | |
216 | method: 'POST', | |
217 | params: params, | |
218 | failure: function(response, opts) { | |
219 | Ext.Msg.alert(gettext('Error'), response.htmlStatus); | |
220 | panel.reload(); | |
221 | }, | |
222 | success: function(response, opts) { | |
223 | panel.reload(); | |
224 | }, | |
225 | }); | |
226 | }, | |
227 | listeners: { | |
228 | render: function(btn) { | |
229 | // HACK: calculate the max button width on first render to avoid toolbar glitches | |
230 | let defSize = btn.getSize().width; | |
231 | ||
232 | btn.setText(btn.altText); | |
233 | let altSize = btn.getSize().width; | |
234 | ||
235 | btn.setText(btn.defaultText); | |
236 | btn.setSize({ width: altSize > defSize ? altSize : defSize }); | |
237 | }, | |
238 | }, | |
239 | }, | |
240 | ], | |
241 | ||
242 | sortableColumns: false, | |
243 | viewConfig: { | |
244 | stripeRows: false, | |
245 | getRowClass: (record, index) => record.get('Enabled') ? '' : 'proxmox-disabled-row', | |
246 | }, | |
247 | ||
248 | columns: [ | |
249 | { | |
250 | xtype: 'checkcolumn', | |
251 | header: gettext('Enabled'), | |
252 | dataIndex: 'Enabled', | |
253 | listeners: { | |
254 | beforecheckchange: () => false, // veto, we don't want to allow inline change - to subtle | |
255 | }, | |
256 | width: 90, | |
257 | }, | |
258 | { | |
259 | header: gettext('Types'), | |
260 | dataIndex: 'Types', | |
261 | renderer: function(types, cell, record) { | |
262 | return types.join(' '); | |
263 | }, | |
264 | width: 100, | |
265 | }, | |
266 | { | |
267 | header: gettext('URIs'), | |
268 | dataIndex: 'URIs', | |
269 | renderer: function(uris, cell, record) { | |
270 | return uris.join(' '); | |
271 | }, | |
272 | width: 350, | |
273 | }, | |
274 | { | |
275 | header: gettext('Suites'), | |
276 | dataIndex: 'Suites', | |
277 | renderer: function(suites, metaData, record) { | |
278 | let err = ''; | |
279 | if (record.data.warnings && record.data.warnings.length > 0) { | |
280 | let txt = [gettext('Warning')]; | |
281 | record.data.warnings.forEach((warning) => { | |
282 | if (warning.property === 'Suites') { | |
283 | txt.push(warning.message); | |
284 | } | |
285 | }); | |
286 | metaData.tdAttr = `data-qtip="${Ext.htmlEncode(txt.join('<br>'))}"`; | |
287 | if (record.data.Enabled) { | |
288 | metaData.tdCls = 'proxmox-invalid-row'; | |
289 | err = '<i class="fa fa-fw critical fa-exclamation-circle"></i> '; | |
290 | } else { | |
291 | metaData.tdCls = 'proxmox-warning-row'; | |
292 | err = '<i class="fa fa-fw warning fa-exclamation-circle"></i> '; | |
293 | } | |
294 | } | |
295 | return suites.join(' ') + err; | |
296 | }, | |
297 | width: 130, | |
298 | }, | |
299 | { | |
300 | header: gettext('Components'), | |
301 | dataIndex: 'Components', | |
302 | renderer: function(components, metaData, record) { | |
303 | let err = ''; | |
304 | if (components.length === 1) { | |
305 | // FIXME: this should be a flag set to the actual repsotiories, i.e., a tristate | |
306 | // like production-ready = <yes|no|other> (Option<bool>) | |
307 | if (components[0].match(/\w+(-no-subscription|test)\s*$/i)) { | |
308 | metaData.tdCls = 'proxmox-warning-row'; | |
309 | err = '<i class="fa fa-fw warning fa-exclamation-circle"></i> '; | |
310 | ||
311 | let qtip = components[0].match(/no-subscription/) | |
312 | ? gettext('The no-subscription repository is NOT production-ready') | |
313 | : gettext('The test repository may contain unstable updates') | |
314 | ; | |
315 | metaData.tdAttr = `data-qtip="${Ext.htmlEncode(qtip)}"`; | |
316 | } | |
317 | } | |
318 | return components.join(' ') + err; | |
319 | }, | |
320 | width: 170, | |
321 | }, | |
322 | { | |
323 | header: gettext('Options'), | |
324 | dataIndex: 'Options', | |
325 | renderer: function(options, cell, record) { | |
326 | if (!options) { | |
327 | return ''; | |
328 | } | |
329 | ||
330 | let filetype = record.data.FileType; | |
331 | let text = ''; | |
332 | ||
333 | options.forEach(function(option) { | |
334 | let key = option.Key; | |
335 | if (filetype === 'list') { | |
336 | let values = option.Values.join(','); | |
337 | text += `${key}=${values} `; | |
338 | } else if (filetype === 'sources') { | |
339 | let values = option.Values.join(' '); | |
340 | text += `${key}: ${values}<br>`; | |
341 | } else { | |
342 | throw "unkown file type"; | |
343 | } | |
344 | }); | |
345 | return text; | |
346 | }, | |
347 | flex: 1, | |
348 | }, | |
349 | { | |
350 | header: gettext('Origin'), | |
351 | dataIndex: 'Origin', | |
352 | width: 120, | |
353 | renderer: (value, meta, rec) => { | |
354 | if (typeof value !== 'string' || value.length === 0) { | |
355 | value = gettext('Other'); | |
356 | } | |
357 | let cls = 'fa fa-fw fa-question-circle-o'; | |
358 | if (value.match(/^\s*Proxmox\s*$/i)) { | |
359 | cls = 'pmx-itype-icon pmx-itype-icon-proxmox-x'; | |
360 | } else if (value.match(/^\s*Debian\s*$/i)) { | |
361 | cls = 'pmx-itype-icon pmx-itype-icon-debian-swirl'; | |
362 | } | |
363 | return `<i class='${cls}'></i> ${value}`; | |
364 | }, | |
365 | }, | |
366 | { | |
367 | header: gettext('Comment'), | |
368 | dataIndex: 'Comment', | |
369 | flex: 2, | |
370 | }, | |
371 | ], | |
372 | ||
373 | initComponent: function() { | |
374 | let me = this; | |
375 | ||
376 | if (!me.nodename) { | |
377 | throw "no node name specified"; | |
378 | } | |
379 | ||
380 | let store = Ext.create('Ext.data.Store', { | |
381 | model: 'apt-repolist', | |
382 | groupField: 'Path', | |
383 | sorters: [ | |
384 | { | |
385 | property: 'Index', | |
386 | direction: 'ASC', | |
387 | }, | |
388 | ], | |
389 | }); | |
390 | ||
391 | let groupingFeature = Ext.create('Ext.grid.feature.Grouping', { | |
392 | groupHeaderTpl: '{[ "File: " + values.name ]} ({rows.length} ' + | |
393 | 'repositor{[values.rows.length > 1 ? "ies" : "y"]})', | |
394 | enableGroupingMenu: false, | |
395 | }); | |
396 | ||
397 | Ext.apply(me, { | |
398 | store: store, | |
399 | features: [groupingFeature], | |
400 | }); | |
401 | ||
402 | me.callParent(); | |
403 | }, | |
404 | }); | |
405 | ||
406 | Ext.define('Proxmox.node.APTRepositories', { | |
407 | extend: 'Ext.panel.Panel', | |
408 | xtype: 'proxmoxNodeAPTRepositories', | |
409 | mixins: ['Proxmox.Mixin.CBind'], | |
410 | ||
411 | digest: undefined, | |
412 | ||
413 | product: 'Proxmox VE', // default | |
414 | ||
415 | controller: { | |
416 | xclass: 'Ext.app.ViewController', | |
417 | ||
418 | selectionChange: function(grid, selection) { | |
419 | let me = this; | |
420 | if (!selection || selection.length < 1) { | |
421 | return; | |
422 | } | |
423 | let rec = selection[0]; | |
424 | let vm = me.getViewModel(); | |
425 | vm.set('selectionenabled', rec.get('Enabled')); | |
426 | vm.notify(); | |
427 | }, | |
428 | ||
429 | updateState: function() { | |
430 | let me = this; | |
431 | let vm = me.getViewModel(); | |
432 | ||
433 | let store = vm.get('errorstore'); | |
434 | store.removeAll(); | |
435 | ||
436 | let status = 'good'; // start with best, the helper below will downgrade if needed | |
437 | let text = gettext('All OK, you have production-ready repositories configured!'); | |
438 | ||
439 | let errors = vm.get('errors'); | |
440 | errors.forEach((error) => { | |
441 | status = 'critical'; | |
442 | store.add({ | |
443 | status: 'critical', | |
444 | message: `${error.path} - ${error.error}`, | |
445 | }); | |
446 | }); | |
447 | ||
448 | let addGood = message => store.add({ status: 'good', message }); | |
449 | ||
450 | let addWarn = message => { | |
451 | if (status !== 'critical') { | |
452 | status = 'warning'; | |
453 | text = message; | |
454 | } | |
455 | store.add({ status: 'warning', message }); | |
456 | }; | |
457 | ||
458 | let activeSubscription = vm.get('subscriptionActive'); | |
459 | let enterprise = vm.get('enterpriseRepo'); | |
460 | let nosubscription = vm.get('noSubscriptionRepo'); | |
461 | let test = vm.get('testRepo'); | |
462 | let wrongSuites = vm.get('suitesWarning'); | |
463 | ||
464 | if (!enterprise && !nosubscription && !test) { | |
465 | addWarn(Ext.String.format(gettext('No {0} repository is enabled!'), vm.get('product'))); | |
466 | } else if (enterprise && !nosubscription && !test && activeSubscription) { | |
467 | addGood(Ext.String.format(gettext('You get supported updates for {0}'), vm.get('product'))); | |
468 | } else if (nosubscription || test) { | |
469 | addGood(Ext.String.format(gettext('You get updates for {0}'), vm.get('product'))); | |
470 | } | |
471 | ||
472 | if (wrongSuites) { | |
473 | addWarn(gettext('Some Suites are misconfigured')); | |
474 | } | |
475 | ||
476 | if (!activeSubscription && enterprise) { | |
477 | addWarn(gettext('The enterprise repository is enabled, but there is no active subscription!')); | |
478 | } | |
479 | ||
480 | if (nosubscription) { | |
481 | addWarn(gettext('The no-subscription repository is not recommended for production use!')); | |
482 | } | |
483 | ||
484 | if (test) { | |
485 | addWarn(gettext('The test repository is not recommended for production use!')); | |
486 | } | |
487 | ||
488 | if (errors.length > 0) { | |
489 | text = gettext('Error parsing repositories'); | |
490 | } | |
491 | ||
492 | let iconCls = Proxmox.Utils.get_health_icon(status, true); | |
493 | ||
494 | vm.set('state', { | |
495 | iconCls, | |
496 | text, | |
497 | }); | |
498 | }, | |
499 | }, | |
500 | ||
501 | viewModel: { | |
502 | data: { | |
503 | product: 'Proxmox VE', // default | |
504 | errors: [], | |
505 | suitesWarning: false, | |
506 | subscriptionActive: '', | |
507 | noSubscriptionRepo: '', | |
508 | enterpriseRepo: '', | |
509 | testRepo: '', | |
510 | selectionenabled: false, | |
511 | state: {}, | |
512 | }, | |
513 | formulas: { | |
514 | enableButtonText: (get) => get('selectionenabled') | |
515 | ? gettext('Disable') : gettext('Enable'), | |
516 | }, | |
517 | stores: { | |
518 | errorstore: { | |
519 | fields: ['status', 'message'], | |
520 | }, | |
521 | }, | |
522 | }, | |
523 | ||
524 | scrollable: true, | |
525 | layout: { | |
526 | type: 'vbox', | |
527 | align: 'stretch', | |
528 | }, | |
529 | ||
530 | items: [ | |
531 | { | |
532 | xtype: 'panel', | |
533 | border: false, | |
534 | layout: { | |
535 | type: 'hbox', | |
536 | align: 'stretch', | |
537 | }, | |
538 | height: 200, | |
539 | title: gettext('Status'), | |
540 | items: [ | |
541 | { | |
542 | xtype: 'box', | |
543 | flex: 2, | |
544 | margin: 10, | |
545 | data: { | |
546 | iconCls: Proxmox.Utils.get_health_icon(undefined, true), | |
547 | text: '', | |
548 | }, | |
549 | bind: { | |
550 | data: '{state}', | |
551 | }, | |
552 | tpl: [ | |
553 | '<center class="centered-flex-column" style="font-size:15px;line-height: 25px;">', | |
554 | '<i class="fa fa-4x {iconCls}"></i>', | |
555 | '<br/><br/>', | |
556 | '{text}', | |
557 | '</center>', | |
558 | ], | |
559 | }, | |
560 | { | |
561 | xtype: 'proxmoxNodeAPTRepositoriesErrors', | |
562 | name: 'repositoriesErrors', | |
563 | flex: 7, | |
564 | margin: 10, | |
565 | bind: { | |
566 | store: '{errorstore}', | |
567 | }, | |
568 | }, | |
569 | ], | |
570 | }, | |
571 | { | |
572 | xtype: 'proxmoxNodeAPTRepositoriesGrid', | |
573 | name: 'repositoriesGrid', | |
574 | flex: 1, | |
575 | cbind: { | |
576 | nodename: '{nodename}', | |
577 | }, | |
578 | majorUpgradeAllowed: false, // TODO get release information from an API call? | |
579 | listeners: { | |
580 | selectionchange: 'selectionChange', | |
581 | }, | |
582 | }, | |
583 | ], | |
584 | ||
585 | check_subscription: function() { | |
586 | let me = this; | |
587 | let vm = me.getViewModel(); | |
588 | ||
589 | Proxmox.Utils.API2Request({ | |
590 | url: `/nodes/${me.nodename}/subscription`, | |
591 | method: 'GET', | |
592 | failure: (response, opts) => Ext.Msg.alert(gettext('Error'), response.htmlStatus), | |
593 | success: function(response, opts) { | |
594 | const res = response.result; | |
595 | const subscription = !(!res || !res.data || res.data.status.toLowerCase() !== 'active'); | |
596 | vm.set('subscriptionActive', subscription); | |
597 | me.getController().updateState(); | |
598 | }, | |
599 | }); | |
600 | }, | |
601 | ||
602 | updateStandardRepos: function(standardRepos) { | |
603 | let me = this; | |
604 | let vm = me.getViewModel(); | |
605 | ||
606 | let addButton = me.down('#addButton'); | |
607 | addButton.repoInfo = []; | |
608 | ||
609 | for (const standardRepo of standardRepos) { | |
610 | const handle = standardRepo.handle; | |
611 | const status = standardRepo.status; | |
612 | ||
613 | if (handle === "enterprise") { | |
614 | vm.set('enterpriseRepo', status); | |
615 | } else if (handle === "no-subscription") { | |
616 | vm.set('noSubscriptionRepo', status); | |
617 | } else if (handle === 'test') { | |
618 | vm.set('testRepo', status); | |
619 | } | |
620 | me.getController().updateState(); | |
621 | ||
622 | addButton.repoInfo.push(standardRepo); | |
623 | addButton.digest = me.digest; | |
624 | } | |
625 | ||
626 | addButton.setDisabled(false); | |
627 | }, | |
628 | ||
629 | reload: function() { | |
630 | let me = this; | |
631 | let vm = me.getViewModel(); | |
632 | let repoGrid = me.down('proxmoxNodeAPTRepositoriesGrid'); | |
633 | ||
634 | me.store.load(function(records, operation, success) { | |
635 | let gridData = []; | |
636 | let errors = []; | |
637 | let digest; | |
638 | let suitesWarning = false; | |
639 | ||
640 | if (success && records.length > 0) { | |
641 | let data = records[0].data; | |
642 | let files = data.files; | |
643 | errors = data.errors; | |
644 | digest = data.digest; | |
645 | ||
646 | let infos = {}; | |
647 | for (const info of data.infos) { | |
648 | let path = info.path; | |
649 | let idx = info.index; | |
650 | ||
651 | if (!infos[path]) { | |
652 | infos[path] = {}; | |
653 | } | |
654 | if (!infos[path][idx]) { | |
655 | infos[path][idx] = { | |
656 | origin: '', | |
657 | warnings: [], | |
658 | }; | |
659 | } | |
660 | ||
661 | if (info.kind === 'origin') { | |
662 | infos[path][idx].origin = info.message; | |
663 | } else if (info.kind === 'warning' || | |
664 | (info.kind === 'ignore-pre-upgrade-warning' && !repoGrid.majorUpgradeAllowed) | |
665 | ) { | |
666 | infos[path][idx].warnings.push(info); | |
667 | if (!suitesWarning && info.property === 'Suites') { | |
668 | suitesWarning = true; | |
669 | } | |
670 | } else { | |
671 | throw 'unknown info'; | |
672 | } | |
673 | } | |
674 | ||
675 | ||
676 | files.forEach(function(file) { | |
677 | for (let n = 0; n < file.repositories.length; n++) { | |
678 | let repo = file.repositories[n]; | |
679 | repo.Path = file.path; | |
680 | repo.Index = n; | |
681 | if (infos[file.path] && infos[file.path][n]) { | |
682 | repo.Origin = infos[file.path][n].origin || Proxmox.Utils.UnknownText; | |
683 | repo.warnings = infos[file.path][n].warnings || []; | |
684 | } | |
685 | gridData.push(repo); | |
686 | } | |
687 | }); | |
688 | ||
689 | repoGrid.store.loadData(gridData); | |
690 | ||
691 | me.updateStandardRepos(data['standard-repos']); | |
692 | } | |
693 | ||
694 | me.digest = digest; | |
695 | ||
696 | vm.set('errors', errors); | |
697 | vm.set('suitesWarning', suitesWarning); | |
698 | me.getController().updateState(); | |
699 | }); | |
700 | ||
701 | me.check_subscription(); | |
702 | }, | |
703 | ||
704 | listeners: { | |
705 | activate: function() { | |
706 | let me = this; | |
707 | me.reload(); | |
708 | }, | |
709 | }, | |
710 | ||
711 | initComponent: function() { | |
712 | let me = this; | |
713 | ||
714 | if (!me.nodename) { | |
715 | throw "no node name specified"; | |
716 | } | |
717 | ||
718 | let store = Ext.create('Ext.data.Store', { | |
719 | proxy: { | |
720 | type: 'proxmox', | |
721 | url: `/api2/json/nodes/${me.nodename}/apt/repositories`, | |
722 | }, | |
723 | }); | |
724 | ||
725 | Ext.apply(me, { store: store }); | |
726 | ||
727 | Proxmox.Utils.monStoreErrors(me, me.store, true); | |
728 | ||
729 | me.callParent(); | |
730 | ||
731 | me.getViewModel().set('product', me.product); | |
732 | }, | |
733 | }); |