9 const callSystemBoard = rpc.declare({
14 function showUpgradeNotification(type, boardinfo, new_version, upgrade_info)
17 // Title Current Available
18 [_('Firmware Version'), boardinfo.release.version, upgrade_info.version_number ],
19 [_('Revision'), boardinfo.release.revision, upgrade_info.version_code ],
20 [_('Kernel Version'), boardinfo?.kernel, upgrade_info.linux_kernel?.version ],
23 const table = E('table', { 'class': 'table' });
26 E('tr', { 'class': 'tr' }, [
27 E('th', { 'class': 'th' }, [ ]),
28 E('th', { 'class': 'th' }, [ _('Current') ]),
29 E('th', { 'class': 'th' }, [ _('Available') ])
33 table_rows.forEach((cols) => {
34 table.appendChild(E('tr', { 'class': 'tr' }, [
35 E('td', { 'class': 'td left', 'width': '33%' }, [ cols[0] ]),
36 E('td', { 'class': 'td left' }, [ cols[1] ?? '?' ]),
37 E('td', { 'class': 'td left' }, [ cols[2] ?? '?' ]),
41 ui.addTimeLimitedNotification(_('New Firmware Available'), [
42 E('p', _('A new %s version of OpenWrt is available:').format(type)),
46 E('a', {href: `/cgi-bin/luci/admin/system/attendedsysupgrade`}, _('Attended Sysupgrade')),
48 E('a', {href: `https://openwrt.org/releases/${new_version?.split('.').slice(0, 2).join('.')}/notes-${new_version}`}, _('release notes')),
53 function shouldUpgrade(installed, available)
55 // If installed is any snapshot (release or main), don't upgrade.
57 if (! available) return false;
58 if (! installed || installed.includes('SNAPSHOT')) return false
60 const parse = (v) => v.split(/[-+]/)[0]?.split('.').map(Number);
61 const parseRC = (v) => v.split(/[-+]/)[1]?.split('').map(Number);
62 const isPrerelease = (v) => /-/.test(v);
64 const [aParts, bParts] = [parse(available), parse(installed)];
66 for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {
67 const numA = aParts[i] || 0;
68 const numB = bParts[i] || 0;
69 if (numA > numB) return true;
70 if (numA < numB) return false;
73 const [aRC, bRC] = [parseRC(available), parseRC(installed)];
75 if (aRC > bRC) return true;
76 if (aRC < bRC) return false;
78 // If numeric parts are equal, handle release candidates
79 // if (isPrerelease(available) && !isPrerelease(installed)) return false;
80 if (!isPrerelease(available) && isPrerelease(installed)) return true;
84 async function checkDeviceAvailable(boardinfo, new_version)
86 const profile_url = `https://downloads.openwrt.org/releases/${new_version}/targets/${boardinfo?.release?.target}/profiles.json`;
87 return fetch(profile_url)
88 .then(response => response.json())
90 // special case for x86, armsr and loongarch
91 if (Object.keys(data?.profiles).length == 1 && Object.keys(data?.profiles)[0] == "generic") {
95 for (const profileName in data?.profiles) {
96 if (profileName === boardinfo?.board_name) {
99 const profile = data?.profiles[profileName];
100 if (profile.supported_devices?.includes(boardinfo?.board_name)) {
105 return [false, null];
108 console.error('Failed to fetch firmware upgrade profile information:', error);
109 return [false, null];
113 return baseclass.extend({
118 L.resolveDefault(callSystemBoard(), {}),
123 handleSetUpgradeCheck: function(pref, ev) {
124 ev.currentTarget.classList.add('spinning');
125 ev.currentTarget.blur();
127 uci.set('luci', 'main', 'check_for_newer_firmwares', pref);
130 .then(L.bind(L.ui.changes.init, L.ui.changes))
131 .then(L.bind(L.ui.changes.displayChanges, L.ui.changes));
134 oneshot: function(data) {
135 var boardinfo = data[0];
136 const check_upgrades = uci.get_bool('luci', 'main', 'check_for_newer_firmwares');
138 if (check_upgrades) {
139 fetch('https://downloads.openwrt.org/.versions.json')
140 .then(response => response.json())
141 .then(async (versions) => {
143 var new_version = null;
145 const installed_version = boardinfo?.release?.version;
146 const prev_version = versions?.oldstable_version;
147 const curr_version = versions?.stable_version;
148 const next_version = versions?.upcoming_version; // Only available during "rc".
150 if (shouldUpgrade(installed_version, prev_version)) {
151 // On old branch, and a newer 'old stable' is available.
152 label = 'old stable';
153 new_version = prev_version;
154 } else if (shouldUpgrade(installed_version, curr_version)) {
155 // On old stable or current branch, and newer stable is available.
157 new_version = curr_version;
158 } else if (shouldUpgrade(installed_version, next_version)) {
159 // On current stable or rc branch, a newer rc is available.
160 label = 'release candidate';
161 new_version = next_version;
165 (async function(label, new_version) {
166 const [available, upgrade_info] = await checkDeviceAvailable(boardinfo, new_version);
167 if (available && upgrade_info)
168 showUpgradeNotification(label, boardinfo, new_version, upgrade_info);
169 })(label, new_version);
174 console.error('Failed to fetch firmware upgrade version information:', error);
179 render: function(data) {
180 const check_upgrades = uci.get_bool('luci', 'main', 'check_for_newer_firmwares') ?? false;
181 const isReadonlyView = !L.hasViewPermission();
183 let perform_check_pref = E('input', { type: 'checkbox', 'click': L.bind(this.handleSetUpgradeCheck, this, !check_upgrades), });
184 perform_check_pref.checked = check_upgrades;
186 let perform_check_pref_p = E('div', [_('Look online for upgrades upon status page load') + ' ', perform_check_pref]);
188 return E('div', [!isReadonlyView ? perform_check_pref_p : '']);