]> git.99rst.org Git - openwrt-luci.git/blob
c4edcad15806f4ff6896bc570320854f5453cade
[openwrt-luci.git] /
1 'use strict';
2 'require baseclass';
3 'require fs';
4 'require rpc';
5 'require uci'
6 'require ui';
7
8
9 const callSystemBoard = rpc.declare({
10 object: 'system',
11 method: 'board'
12 });
13
14 const check_setting = [ 'attendedsysupgrade', 'client', 'login_check_for_upgrades' ];
15
16 function setSetUpgradeCheck(pref) {
17 uci.set(...check_setting, pref);
18 return uci.save()
19 .then(L.bind(L.ui.changes.init, L.ui.changes))
20 .then(L.bind(L.ui.changes.displayChanges, L.ui.changes));
21 }
22
23 function showUpgradeNotification(type, boardinfo, version, upgrade_info)
24 {
25
26 // TODO show the toggle for _('Look online for upgrades upon status page load')...
27
28 const table_rows = [
29 // Title Current Available
30 [_('Firmware Version'), boardinfo.release.version, upgrade_info.version_number ],
31 [_('Revision'), boardinfo.release.revision, upgrade_info.version_code ],
32 [_('Kernel Version'), boardinfo.kernel, upgrade_info.linux_kernel?.version ],
33 ];
34
35 const table = E('table', { 'class': 'table' });
36
37 table.appendChild(
38 E('tr', { 'class': 'tr' }, [
39 E('th', { 'class': 'th' }, [ ]),
40 E('th', { 'class': 'th' }, [ _('Current') ]),
41 E('th', { 'class': 'th' }, [ _('Available') ])
42 ])
43 );
44
45 table_rows.forEach(([c1, c2, c3]) => {
46 table.appendChild(E('tr', { 'class': 'tr' }, [
47 E('td', { 'class': 'td left', 'width': '33%' }, [ c1 ]),
48 E('td', { 'class': 'td left' }, [ c2 ?? '?' ]),
49 E('td', { 'class': 'td left' }, [ c3 ?? '?' ]),
50 ]));
51 });
52
53 const branch = version.split('.').slice(0, 2).join('.');
54 ui.addTimeLimitedNotification(_('New Firmware Available'), [
55 E('p', _('A new %s version of OpenWrt is available:').format(type)),
56 table,
57 E('p', [
58 _('Check') + ' ',
59 E('a', {href: '/cgi-bin/luci/admin/system/attendedsysupgrade'}, _('Attended Sysupgrade')),
60 ' ' + _('and') + ' ',
61 E('a', {href: `https://openwrt.org/releases/${branch}/notes-${version}`}, _('release notes')),
62 ]),
63 E('div', { class: 'btn', click: () => setSetUpgradeCheck(false) }, _('Stop showing upgrade alerts')),
64 ], 60000, 'notice');
65 }
66
67 function shouldUpgrade(installed, available)
68 {
69 // If installed is any snapshot (release or main), don't upgrade.
70
71 if (! available) return false;
72 if (! installed) return false;
73 if (installed.includes('SNAPSHOT')) return false;
74
75 // At this point we know the versions are in one of two forms:
76 // MM.mm.rr
77 // MM.mm.rr-rcN
78 // so partition them up into a 4-element array, with a value of
79 // 99 for the "release candidate" part of any release.
80 const parse = (v) => [
81 ...v.split('-')[0].split('.').map(Number),
82 Number(v.split(/rc/)[1] || 99)
83 ];
84
85 const [aParts, iParts] = [parse(available), parse(installed)];
86
87 for (let i = 0; i < iParts.length; i++) {
88 const aVal = aParts[i];
89 const iVal = iParts[i];
90 if (aVal > iVal) return true;
91 if (aVal < iVal) return false;
92 }
93
94 return false;
95 }
96
97 async function checkDeviceAvailable(boardinfo, new_version)
98 {
99 const profile_url = `https://downloads.openwrt.org/releases/${new_version}/targets/${boardinfo?.release?.target}/profiles.json`;
100 return fetch(profile_url)
101 .then(response => response.json())
102 .then(data => {
103 // special case for x86, armsr and loongarch
104 if (Object.keys(data?.profiles).length == 1 && Object.keys(data?.profiles)[0] == "generic") {
105 return [true, data];
106 }
107
108 for (const profileName in data?.profiles) {
109 if (profileName === boardinfo?.board_name) {
110 return [true, data];
111 }
112 const profile = data?.profiles[profileName];
113 if (profile.supported_devices?.includes(boardinfo?.board_name)) {
114 return [true, data];
115 }
116 }
117
118 return [false, null];
119 })
120 .catch(error => {
121 console.error('Failed to fetch firmware upgrade profile information:', error);
122 return [false, null];
123 });
124 };
125
126 return baseclass.extend({
127 title: '',
128
129 load: function() {
130 return Promise.all([
131 L.resolveDefault(callSystemBoard(), {}),
132 uci.load(check_setting[0]),
133 ]);
134 },
135
136
137 oneshot: function(data) {
138 var boardinfo = data[0];
139 const check_upgrades = uci.get_bool(...check_setting);
140
141 if (check_upgrades) {
142 fetch('https://downloads.openwrt.org/.versions.json')
143 .then(response => response.json())
144 .then(async (versions) => {
145 var label = null;
146 var new_version = null;
147
148 const installed_version = boardinfo?.release?.version;
149 const prev_version = versions?.oldstable_version;
150 const curr_version = versions?.stable_version;
151 const next_version = versions?.upcoming_version; // Only available during "rc".
152
153 if (shouldUpgrade(installed_version, prev_version)) {
154 // On old branch, and a newer 'old stable' is available.
155 label = 'old stable';
156 new_version = prev_version;
157 } else if (shouldUpgrade(installed_version, curr_version)) {
158 // On old stable or current branch, and newer stable is available.
159 label = 'stable';
160 new_version = curr_version;
161 } else if (shouldUpgrade(installed_version, next_version)) {
162 // On current stable or rc branch, a newer rc is available.
163 label = 'release candidate';
164 new_version = next_version;
165 }
166
167 if (new_version) {
168 (async function(label, new_version) {
169 const [available, upgrade_info] = await checkDeviceAvailable(boardinfo, new_version);
170 if (available && upgrade_info)
171 showUpgradeNotification(label, boardinfo, new_version, upgrade_info);
172 })(label, new_version);
173 }
174
175 })
176 .catch(error => {
177 console.error('Failed to fetch firmware upgrade version information:', error);
178 });
179 }
180 },
181
182 render: function(data) {
183 const isReadOnlyView = !L.hasViewPermission();
184 if (isReadOnlyView)
185 return null;
186
187 let check_upgrades = uci.get(...check_setting);
188 if (check_upgrades != null)
189 return null;
190
191 let modal_body = [
192 E('p', _('Checking for firmware upgrades requires access to several files ' +
193 'on the downloads site, so requires internet access.')),
194
195 E('p', _('The check will be performed every time the Status -> Overview page is loaded.')),
196
197 E('p', _('You have not yet specified a preference for this setting. ' +
198 'Once set, this dialog will not be shown again, but you can go to ' +
199 'System -> Attended Sysupgrade configuration to change the setting.')),
200
201 E('div', { class: 'right' }, [
202 E('div', { class: 'btn', click: () => setSetUpgradeCheck(true) }, _('Yes, enable checking')),
203 E('div', { class: 'btn', click: () => setSetUpgradeCheck(false) }, _('No, disable checking')),
204 E('div', { class: 'btn', click: ui.hideModal }, _('Close')),
205 ]),
206 ];
207 ui.showModal(_('Check online for firmware upgrades'), modal_body);
208
209 return null;
210 }
211 });
git clone https://git.99rst.org/PROJECT