9 const callSystemBoard = rpc.declare({
14 const check_setting = [ 'attendedsysupgrade', 'client', 'login_check_for_upgrades' ];
16 function setSetUpgradeCheck(pref) {
17 uci.set(...check_setting, pref);
19 .then(L.bind(L.ui.changes.init, L.ui.changes))
20 .then(L.bind(L.ui.changes.displayChanges, L.ui.changes));
23 function showUpgradeNotification(type, boardinfo, version, upgrade_info)
26 // TODO show the toggle for _('Look online for upgrades upon status page load')...
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 ],
35 const table = E('table', { 'class': 'table' });
38 E('tr', { 'class': 'tr' }, [
39 E('th', { 'class': 'th' }, [ ]),
40 E('th', { 'class': 'th' }, [ _('Current') ]),
41 E('th', { 'class': 'th' }, [ _('Available') ])
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 ?? '?' ]),
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)),
59 E('a', {href: '/cgi-bin/luci/admin/system/attendedsysupgrade'}, _('Attended Sysupgrade')),
61 E('a', {href: `https://openwrt.org/releases/${branch}/notes-${version}`}, _('release notes')),
63 E('div', { class: 'btn', click: () => setSetUpgradeCheck(false) }, _('Stop showing upgrade alerts')),
67 function shouldUpgrade(installed, available)
69 // If installed is any snapshot (release or main), don't upgrade.
71 if (! available) return false;
72 if (! installed) return false;
73 if (installed.includes('SNAPSHOT')) return false;
75 // At this point we know the versions are in one of two forms:
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)
85 const [aParts, iParts] = [parse(available), parse(installed)];
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;
97 async function checkDeviceAvailable(boardinfo, new_version)
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())
103 // special case for x86, armsr and loongarch
104 if (Object.keys(data?.profiles).length == 1 && Object.keys(data?.profiles)[0] == "generic") {
108 for (const profileName in data?.profiles) {
109 if (profileName === boardinfo?.board_name) {
112 const profile = data?.profiles[profileName];
113 if (profile.supported_devices?.includes(boardinfo?.board_name)) {
118 return [false, null];
121 console.error('Failed to fetch firmware upgrade profile information:', error);
122 return [false, null];
126 return baseclass.extend({
131 L.resolveDefault(callSystemBoard(), {}),
132 uci.load(check_setting[0]),
137 oneshot: function(data) {
138 var boardinfo = data[0];
139 const check_upgrades = uci.get_bool(...check_setting);
141 if (check_upgrades) {
142 fetch('https://downloads.openwrt.org/.versions.json')
143 .then(response => response.json())
144 .then(async (versions) => {
146 var new_version = null;
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".
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.
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;
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);
177 console.error('Failed to fetch firmware upgrade version information:', error);
182 render: function(data) {
183 const isReadOnlyView = !L.hasViewPermission();
187 let check_upgrades = uci.get(...check_setting);
188 if (check_upgrades != null)
192 E('p', _('Checking for firmware upgrades requires access to several files ' +
193 'on the downloads site, so requires internet access.')),
195 E('p', _('The check will be performed every time the Status -> Overview page is loaded.')),
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.')),
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')),
207 ui.showModal(_('Check online for firmware upgrades'), modal_body);