Merge pull request #755 from mikeller/added_release_checking

Added checking for latest configurator release and update notification.
10.3.x-maintenance 10.0.0-rc3
Michael Keller 2017-12-04 09:58:56 +13:00 committed by GitHub
commit 7252c30c18
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 225 additions and 199 deletions

View File

@ -5,12 +5,12 @@
"warningTitle": {
"message": "Warning"
},
"noticeTitle": {
"message": "Notice"
},
"options_title": {
"message": "Application Options"
},
"options_receive_app_notifications": {
"message": "Receive desktop <strong>notification</strong> when application updates"
},
"connect": {
"message": "Connect"
},
@ -35,6 +35,12 @@
"permanentExpertMode": {
"message": "Permanently enable Expert Mode"
},
"checkForConfiguratorUnstableVersions": {
"message": "Show update notifications for unstable versions of the configurator"
},
"configuratorUpdateNotice": {
"message": "You are using an outdated version of the <b>Betaflight Configurator</b>.<br>Version <b>$1</b> is available online, please visit <a href=\"$2\" target=\"_blank\">the release page</a> to download and install the latest version with fixes and improvements.<br>Please close the configurator window before updating."
},
"deviceRebooting": {
"message": "Device - <span style=\"color: red\">Rebooting</span>"
},

View File

@ -84,22 +84,18 @@ chrome.runtime.onInstalled.addListener(function (details) {
// only fire up notification sequence when one of the major version numbers changed
if (currentVersionArr[0] > previousVersionArr[0] || currentVersionArr[1] > previousVersionArr[1]) {
chrome.storage.local.get('update_notify', function (result) {
if (result.update_notify === 'undefined' || result.update_notify) {
var manifest = chrome.runtime.getManifest();
var options = {
priority: 0,
type: 'basic',
title: manifest.name,
message: chrome.i18n.getMessage('notifications_app_just_updated_to_version', [getManifestVersion(manifest)]),
iconUrl: '/images/icon_128.png',
buttons: [{'title': chrome.i18n.getMessage('notifications_click_here_to_start_app')}]
};
var manifest = chrome.runtime.getManifest();
var options = {
priority: 0,
type: 'basic',
title: manifest.name,
message: chrome.i18n.getMessage('notifications_app_just_updated_to_version', [getManifestVersion(manifest)]),
iconUrl: '/images/icon_128.png',
buttons: [{'title': chrome.i18n.getMessage('notifications_click_here_to_start_app')}]
};
chrome.notifications.create('baseflight_update', options, function (notificationId) {
// empty
});
}
chrome.notifications.create('baseflight_update', options, function (notificationId) {
// empty
});
}
}

View File

@ -202,6 +202,7 @@ gulp.task('dist', ['clean-dist'], function () {
'./js/RateCurve.js',
'./js/Features.js',
'./js/Beepers.js',
'./js/release_checker.js',
'./tabs/adjustments.js',
'./tabs/auxiliary.js',
'./tabs/cli.js',

View File

@ -325,8 +325,7 @@ GUI_control.prototype.show_modal = function (title, message) {
var popup = new jBox('Modal', {
title: title,
content: message,
closeButton: 'title',
closeOnClick: 'box'
closeButton: 'title'
});
popup.open();

58
js/release_checker.js Normal file
View File

@ -0,0 +1,58 @@
'use strict;'
var ReleaseChecker = function (releaseName, releaseUrl) {
var self = this;
self._releaseName = releaseName;
self._releaseDataTag = `${self._releaseName}ReleaseData`;
self._releaseLastUpdateTag = `${self._releaseName}ReleaseLastUpdate`
self._releaseUrl = releaseUrl;
}
ReleaseChecker.prototype.loadReleaseData = function (processFunction) {
var self = this;
chrome.storage.local.get([self._releaseLastUpdateTag, self._releaseDataTag], function (result) {
var releaseDataTimestamp = $.now();
var cacheReleaseData = result[self._releaseDataTag];
var cachedReleaseLastUpdate = result[self._releaseLastUpdateTag];
if (!cacheReleaseData || !cachedReleaseLastUpdate || releaseDataTimestamp - cachedReleaseLastUpdate > 3600 * 1000) {
$.get(self._releaseUrl, function (releaseData) {
GUI.log(`Loaded release information for ${self._releaseName} from GitHub.`);
var data = {};
data[self._releaseDataTag] = releaseData
data[self._releaseLastUpdateTag] = releaseDataTimestamp
chrome.storage.local.set(data, function () {});
self._processReleaseData(releaseData, processFunction);
}).fail(function (data) {
var message = '';
if (data['responseJSON']) {
message = data['responseJSON'].message;
}
GUI.log(`<b>GitHub query for ${self._releaseName} releases failed, using cached information. Reason: <code>${message}</code></b>`);
self._processReleaseData(cacheReleaseData, processFunction);
});
} else {
if (cacheReleaseData) {
GUI.log(`Using cached release information for ${self._releaseName} releases.`);
}
self._processReleaseData(cacheReleaseData, processFunction);
}
});
}
ReleaseChecker.prototype._processReleaseData = function (releaseData, processFunction) {
if (releaseData) {
processFunction(releaseData);
} else {
GUI.log(`No release information available for ${self._releaseName}.`);
processFunction();
}
}

View File

@ -73,6 +73,7 @@
<script type="text/javascript" src="./js/RateCurve.js"></script>
<script type="text/javascript" src="./js/Features.js"></script>
<script type="text/javascript" src="./js/Beepers.js"></script>
<script type="text/javascript" src="./js/release_checker.js"></script>
<script type="text/javascript" src="./main.js"></script>
<script type="text/javascript" src="./tabs/landing.js"></script>
<script type="text/javascript" src="./tabs/setup.js"></script>

92
main.js
View File

@ -28,35 +28,7 @@ $(document).ready(function () {
break;
}
// check for newer releases online to inform people in case they are running an old release
chrome.storage.local.get(['lastVersionChecked', 'lastVersionAvailableOnline'], function (result) {
if (typeof result.lastVersionChecked === undefined || ($.now() - result.lastVersionChecked) > 3600 * 1000) {
try {
var url = 'https://api.github.com/repos/betaflight/betaflight-configurator/tags';
$.get(url).done(function (data) {
var versions = data.sort(function (v1, v2) {
try {
return semver.compare(v2.name, v1.name);
} catch (e) {
return false;
}
});
chrome.storage.local.set({
'lastVersionChecked': $.now(),
'lastVersionAvailableOnline': versions[0].name
}, function (result) {
console.log("Latest version available online: " + versions[0].name);
});
notifyOutdatedVersion(versions[0].name);
});
} catch (e) {
// Just to catch and supress warnings if no internet connection is available
}
} else if (result.lastVersionAvailableOnline) {
notifyOutdatedVersion(result.lastVersionAvailableOnline);
}
});
checkForConfiguratorUpdates();
chrome.storage.local.get('logopen', function (result) {
if (result.logopen) {
@ -212,19 +184,6 @@ $(document).ready(function () {
// translate to user-selected language
localize();
// if notifications are enabled, or wasn't set, check the notifications checkbox
chrome.storage.local.get('update_notify', function (result) {
if (typeof result.update_notify === 'undefined' || result.update_notify) {
$('div.notifications input').prop('checked', true);
}
$('div.notifications input').change(function () {
var check = $(this).is(':checked');
chrome.storage.local.set({'update_notify': check});
});
});
chrome.storage.local.get('permanentExpertMode', function (result) {
if (result.permanentExpertMode) {
$('div.permanentExpertMode input').prop('checked', true);
@ -243,6 +202,21 @@ $(document).ready(function () {
}).change();
});
chrome.storage.local.get('checkForConfiguratorUnstableVersions', function (result) {
$('div.checkForConfiguratorUnstableVersions input').change(function () {
var checked = $(this).is(':checked');
chrome.storage.local.set({'checkForConfiguratorUnstableVersions': checked});
$('input[name="checkForConfiguratorUnstableVersions"]').prop('checked', checked).change();
checkForConfiguratorUpdates();
});
if (result.checkForConfiguratorUnstableVersions) {
$('div.checkForConfiguratorUnstableVersions input').prop('checked', true);
}
});
function close_and_cleanup(e) {
if (e.type == 'click' && !$.contains($('div#options-window')[0], e.target) || e.type == 'keyup' && e.keyCode == 27) {
$(document).unbind('click keyup', close_and_cleanup);
@ -377,10 +351,36 @@ $(document).ready(function () {
});
});
function notifyOutdatedVersion(version) {
if (semver.lt(getManifestVersion(), version)) {
GUI.log('You are using an old version of ' + chrome.runtime.getManifest().name + '. Version ' + version + ' is available online with possible improvements and fixes.');
}
function checkForConfiguratorUpdates() {
var releaseChecker = new ReleaseChecker('configurator', 'https://api.github.com/repos/betaflight/betaflight-configurator/releases');
releaseChecker.loadReleaseData(notifyOutdatedVersion);
}
function notifyOutdatedVersion(releaseData) {
chrome.storage.local.get('checkForConfiguratorUnstableVersions', function (result) {
var showUnstableReleases = false;
if (result.checkForConfiguratorUnstableVersions) {
showUnstableReleases = true;
}
var versions = releaseData.filter(function (version) {
var semVerVersion = semver.parse(version.tag_name);
if (semVerVersion && (showUnstableReleases || semVerVersion.prerelease.length === 0)) {
return version;
}
}).sort(function (v1, v2) {
try {
return semver.compare(v2.tag_name, v1.tag_name);
} catch (e) {
return false;
}
});
if (versions.length > 0 && semver.lt(getManifestVersion(), versions[0].tag_name)) {
GUI.show_modal(chrome.i18n.getMessage('noticeTitle'), chrome.i18n.getMessage('configuratorUpdateNotice', [versions[0].tag_name, versions[0].html_url]));
GUI.log(chrome.i18n.getMessage('configuratorUpdateNotice', [versions[0].tag_name, versions[0].html_url]));
}
});
}
function update_packet_error(caller) {

View File

@ -2,6 +2,7 @@
TABS.firmware_flasher = {
releases: null,
releaseChecker: new ReleaseChecker('firmware', 'https://api.github.com/repos/betaflight/betaflight/releases')
};
TABS.firmware_flasher.initialize = function (callback) {
@ -30,144 +31,108 @@ TABS.firmware_flasher.initialize = function (callback) {
}
function buildBoardOptions(releaseData) {
var boards_e = $('select[name="board"]').empty();
var showDevReleases = ($('input.show_development_releases').is(':checked'));
boards_e.append($("<option value='0'>{0}</option>".format(chrome.i18n.getMessage('firmwareFlasherOptionLabelSelectBoard'))));
var versions_e = $('select[name="firmware_version"]').empty();
versions_e.append($("<option value='0'>{0}</option>".format(chrome.i18n.getMessage('firmwareFlasherOptionLabelSelectFirmwareVersion'))));
var releases = {};
var sortedTargets = [];
var unsortedTargets = [];
releaseData.forEach(function(release){
release.assets.forEach(function(asset){
var targetFromFilenameExpression = /betaflight_([\d.]+)?_?(\w+)(\-.*)?\.(.*)/;
var match = targetFromFilenameExpression.exec(asset.name);
if ((!showDevReleases && release.prerelease) || !match) {
return;
}
var target = match[2];
if($.inArray(target, unsortedTargets) == -1) {
unsortedTargets.push(target);
}
});
sortedTargets = unsortedTargets.sort();
});
sortedTargets.forEach(function(release) {
releases[release] = [];
});
releaseData.forEach(function(release){
var versionFromTagExpression = /v?(.*)/;
var matchVersionFromTag = versionFromTagExpression.exec(release.tag_name);
var version = matchVersionFromTag[1];
release.assets.forEach(function(asset){
var targetFromFilenameExpression = /betaflight_([\d.]+)?_?(\w+)(\-.*)?\.(.*)/;
var match = targetFromFilenameExpression.exec(asset.name);
if ((!showDevReleases && release.prerelease) || !match) {
return;
}
var target = match[2];
var format = match[4];
if (format != 'hex') {
return;
}
var date = new Date(release.published_at);
var formattedDate = ("0" + date.getDate()).slice(-2) + "-" + ("0"+(date.getMonth()+1)).slice(-2) + "-" +
date.getFullYear() + " " + ("0" + date.getHours()).slice(-2) + ":" + ("0" + date.getMinutes()).slice(-2);
var descriptor = {
"releaseUrl": release.html_url,
"name" : version,
"version" : version,
"url" : asset.browser_download_url,
"file" : asset.name,
"target" : target,
"date" : formattedDate,
"notes" : release.body,
"status" : release.prerelease ? "release-candidate" : "stable"
};
releases[target].push(descriptor);
});
});
var selectTargets = [];
Object.keys(releases)
.sort()
.forEach(function(target, i) {
var descriptors = releases[target];
descriptors.forEach(function(descriptor){
if($.inArray(target, selectTargets) == -1) {
selectTargets.push(target);
var select_e =
$("<option value='{0}'>{0}</option>".format(
descriptor.target
)).data('summary', descriptor);
boards_e.append(select_e);
}
});
});
TABS.firmware_flasher.releases = releases;
chrome.storage.local.get('selected_board', function (result) {
if (result.selected_board) {
$('select[name="board"]').val(result.selected_board);
$('select[name="board"]').trigger("change");
}
});
};
function loadReleaseData() {
chrome.storage.local.get(['releaseDataLastUpdate', 'releaseData'], function (result) {
var releaseDataTimestamp = $.now();
if (!result.releaseData || !result.releaseDataLastUpdate || releaseDataTimestamp - result.releaseDataLastUpdate > 3600 * 1000) {
$.get('https://api.github.com/repos/betaflight/betaflight/releases', function (releaseData) {
GUI.log("Loaded release information from GitHub.");
chrome.storage.local.set({'releaseDataLastUpdate': releaseDataTimestamp, 'releaseData': releaseData}, function () {});
processReleaseData(releaseData);
}).fail(function (data){
processReleaseData(result.releaseData);
var message = '';
if (data["responseJSON"]) {
message = data["responseJSON"].message;
}
GUI.log("<b>GitHub query failed: <code>{0}</code></b>".format(message));
});
} else {
if (result.releaseData) {
GUI.log("Using cached release information.");
}
processReleaseData(result.releaseData);
}
});
}
function processReleaseData(releaseData) {
if (releaseData) {
buildBoardOptions(releaseData);
} else {
GUI.log("No release information available.");
if (!releaseData) {
$('select[name="board"]').empty().append('<option value="0">Offline</option>');
$('select[name="firmware_version"]').empty().append('<option value="0">Offline</option>');
} else {
var boards_e = $('select[name="board"]').empty();
var showDevReleases = ($('input.show_development_releases').is(':checked'));
boards_e.append($("<option value='0'>{0}</option>".format(chrome.i18n.getMessage('firmwareFlasherOptionLabelSelectBoard'))));
var versions_e = $('select[name="firmware_version"]').empty();
versions_e.append($("<option value='0'>{0}</option>".format(chrome.i18n.getMessage('firmwareFlasherOptionLabelSelectFirmwareVersion'))));
var releases = {};
var sortedTargets = [];
var unsortedTargets = [];
releaseData.forEach(function(release){
release.assets.forEach(function(asset){
var targetFromFilenameExpression = /betaflight_([\d.]+)?_?(\w+)(\-.*)?\.(.*)/;
var match = targetFromFilenameExpression.exec(asset.name);
if ((!showDevReleases && release.prerelease) || !match) {
return;
}
var target = match[2];
if($.inArray(target, unsortedTargets) == -1) {
unsortedTargets.push(target);
}
});
sortedTargets = unsortedTargets.sort();
});
sortedTargets.forEach(function(release) {
releases[release] = [];
});
releaseData.forEach(function(release){
var versionFromTagExpression = /v?(.*)/;
var matchVersionFromTag = versionFromTagExpression.exec(release.tag_name);
var version = matchVersionFromTag[1];
release.assets.forEach(function(asset){
var targetFromFilenameExpression = /betaflight_([\d.]+)?_?(\w+)(\-.*)?\.(.*)/;
var match = targetFromFilenameExpression.exec(asset.name);
if ((!showDevReleases && release.prerelease) || !match) {
return;
}
var target = match[2];
var format = match[4];
if (format != 'hex') {
return;
}
var date = new Date(release.published_at);
var formattedDate = ("0" + date.getDate()).slice(-2) + "-" + ("0"+(date.getMonth()+1)).slice(-2) + "-" + date.getFullYear() + " " + ("0" + date.getHours()).slice(-2) + ":" + ("0" + date.getMinutes()).slice(-2);
var descriptor = {
"releaseUrl": release.html_url,
"name" : version,
"version" : version,
"url" : asset.browser_download_url,
"file" : asset.name,
"target" : target,
"date" : formattedDate,
"notes" : release.body,
"status" : release.prerelease ? "release-candidate" : "stable"
};
releases[target].push(descriptor);
});
});
var selectTargets = [];
Object.keys(releases)
.sort()
.forEach(function(target, i) {
var descriptors = releases[target];
descriptors.forEach(function(descriptor){
if($.inArray(target, selectTargets) == -1) {
selectTargets.push(target);
var select_e =
$("<option value='{0}'>{0}</option>".format(
descriptor.target
)).data('summary', descriptor);
boards_e.append(select_e);
}
});
});
TABS.firmware_flasher.releases = releases;
chrome.storage.local.get('selected_board', function (result) {
if (result.selected_board) {
$('select[name="board"]').val(result.selected_board);
$('select[name="board"]').trigger("change");
}
});
}
}
};
// translate to user-selected language
localize();
// bind events
$('input.show_development_releases').click(function () {
loadReleaseData();
self.releaseChecker.loadReleaseData(buildBoardOptions);
});
$('select[name="board"]').change(function() {
@ -518,7 +483,7 @@ TABS.firmware_flasher.initialize = function (callback) {
$('input.show_development_releases').prop('checked', false);
}
loadReleaseData();
self.releaseChecker.loadReleaseData(buildBoardOptions);
$('input.show_development_releases').change(function () {
chrome.storage.local.set({'show_development_releases': $(this).is(':checked')});

View File

@ -1,6 +1,6 @@
<div class="notifications">
<label><input type="checkbox" /><span i18n="options_receive_app_notifications"></span></label>
</div>
<div class="permanentExpertMode">
<label><input type="checkbox" /><span i18n="permanentExpertMode"></span></label>
</div>
<div class="checkForConfiguratorUnstableVersions">
<label><input type="checkbox" /><span i18n="checkForConfiguratorUnstableVersions"></span></label>
</div>