Merge branch 'fix/includeReleasenotesInUpdateNotifications' into devel
Conflicts: src/octoprint/plugins/softwareupdate/static/css/softwareupdate.css src/octoprint/plugins/softwareupdate/static/js/softwareupdate.js src/octoprint/plugins/softwareupdate/static/less/softwareupdate.less src/octoprint/static/css/octoprint.css src/octoprint/static/less/octoprint.less
This commit is contained in:
commit
dcd67e7645
9 changed files with 118 additions and 32 deletions
|
|
@ -441,7 +441,7 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin,
|
|||
self._logger.warn("Unknown update check type for target {}: {}".format(target, check.get("type", "<n/a>")))
|
||||
continue
|
||||
|
||||
target_information = dict_merge(dict(local=dict(name="unknown", value="unknown"), remote=dict(name="unknown", value="unknown")), target_information)
|
||||
target_information = dict_merge(dict(local=dict(name="unknown", value="unknown"), remote=dict(name="unknown", value="unknown", release_notes=None)), target_information)
|
||||
|
||||
update_available = update_available or target_update_available
|
||||
update_possible = update_possible or (target_update_possible and target_update_available)
|
||||
|
|
@ -451,12 +451,25 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin,
|
|||
local_name = target_information["local"]["name"]
|
||||
local_value = target_information["local"]["value"]
|
||||
|
||||
release_notes = None
|
||||
if target_information and target_information["remote"] and target_information["remote"]["value"]:
|
||||
if "release_notes" in populated_check and populated_check["release_notes"]:
|
||||
release_notes = populated_check["release_notes"]
|
||||
elif "release_notes" in target_information["remote"]:
|
||||
release_notes = target_information["remote"]["release_notes"]
|
||||
|
||||
if release_notes:
|
||||
release_notes = release_notes.format(octoprint_version=octoprint_version,
|
||||
target_name=target_information["remote"]["name"],
|
||||
target_version=target_information["remote"]["value"])
|
||||
|
||||
information[target] = dict(updateAvailable=target_update_available,
|
||||
updatePossible=target_update_possible,
|
||||
information=target_information,
|
||||
displayName=populated_check["displayName"],
|
||||
displayVersion=populated_check["displayVersion"].format(octoprint_version=octoprint_version, local_name=local_name, local_value=local_value),
|
||||
check=populated_check)
|
||||
check=populated_check,
|
||||
releaseNotes=release_notes)
|
||||
|
||||
if self._version_cache_dirty:
|
||||
self._save_version_cache()
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
td.settings_plugin_softwareupdate_column_update{width:16px}#settings_plugin_softwareupdate_workingdialog_output{font-size:.8em}#settings_plugin_softwareupdate_workingdialog_output .message{font-weight:bold}#settings_plugin_softwareupdate_workingdialog_output .separator{font-weight:bold;color:#666}#settings_plugin_softwareupdate_workingdialog_output .stdout{color:#333}#settings_plugin_softwareupdate_workingdialog_output .stderr{color:#900}#settings_plugin_softwareupdate_workingdialog_output .call{color:#009}#settings_plugin_softwareupdate_workingdialog_output .message_error{font-weight:bold;color:#900}
|
||||
td.settings_plugin_softwareupdate_column_update{width:16px}#settings_plugin_softwareupdate_workingdialog_output{font-size:.8em}#settings_plugin_softwareupdate_workingdialog_output .message{font-weight:bold}#settings_plugin_softwareupdate_workingdialog_output .separator{font-weight:bold;color:#666}#settings_plugin_softwareupdate_workingdialog_output .stdout{color:#333}#settings_plugin_softwareupdate_workingdialog_output .stderr{color:#900}#settings_plugin_softwareupdate_workingdialog_output .call{color:#009}#settings_plugin_softwareupdate_workingdialog_output .message_error{font-weight:bold;color:#900}.softwareupdate_notification ul{margin:10px 0 10px 25px}.softwareupdate_notification ul .name{text-overflow:ellipsis;white-space:nowrap;overflow:hidden;display:block}
|
||||
|
|
@ -47,6 +47,8 @@ $(function() {
|
|||
self.settings = parameters[2];
|
||||
self.popup = undefined;
|
||||
|
||||
self.forceUpdate = false;
|
||||
|
||||
self.updateInProgress = false;
|
||||
self.waitingForRestart = false;
|
||||
self.restartTimeout = undefined;
|
||||
|
|
@ -67,6 +69,7 @@ $(function() {
|
|||
self.config_checkType = ko.observable();
|
||||
|
||||
self.configurationDialog = $("#settings_plugin_softwareupdate_configurationdialog");
|
||||
self.confirmationDialog = $("#softwareupdate_confirmation_dialog");
|
||||
|
||||
self.config_availableCheckTypes = [
|
||||
{"key": "github_release", "name": gettext("Release")},
|
||||
|
|
@ -95,6 +98,10 @@ $(function() {
|
|||
5
|
||||
);
|
||||
|
||||
self.availableAndPossible = ko.computed(function() {
|
||||
return _.filter(self.versions.items(), function(info) { return info.updateAvailable && info.updatePossible; });
|
||||
});
|
||||
|
||||
self.onUserLoggedIn = function() {
|
||||
self.performCheck();
|
||||
};
|
||||
|
|
@ -173,6 +180,11 @@ $(function() {
|
|||
if (!value.hasOwnProperty("displayVersion") || value.displayVersion == "") {
|
||||
value.displayVersion = value.information.local.name;
|
||||
}
|
||||
if (!value.hasOwnProperty("releaseNotes") || value.releaseNotes == "") {
|
||||
value.releaseNotes = undefined;
|
||||
}
|
||||
|
||||
value.fullName = _.sprintf(gettext("%(displayName)s: %(displayVersion)s"), value);
|
||||
|
||||
versions.push(value);
|
||||
});
|
||||
|
|
@ -198,22 +210,24 @@ $(function() {
|
|||
}
|
||||
|
||||
if (data.status == "updateAvailable" || data.status == "updatePossible") {
|
||||
var text = gettext("There are updates available for the following components:");
|
||||
var text = "<div class='softwareupdate_notification'>" + gettext("There are updates available for the following components:");
|
||||
|
||||
text += "<ul>";
|
||||
text += "<ul class='icons-ul'>";
|
||||
_.each(self.versions.items(), function(update_info) {
|
||||
if (update_info.updateAvailable) {
|
||||
var displayName = update_info.key;
|
||||
if (update_info.hasOwnProperty("displayName")) {
|
||||
displayName = update_info.displayName;
|
||||
}
|
||||
text += "<li>" + displayName + (update_info.updatePossible ? " <i class=\"icon-ok\"></i>" : "") + "</li>";
|
||||
text += "<li>"
|
||||
+ "<i class='icon-li " + (update_info.updatePossible ? "icon-ok" : "icon-remove")+ "'></i>"
|
||||
+ "<span class='name' title='" + update_info.fullName + "'>" + update_info.fullName + "</span>"
|
||||
+ (update_info.releaseNotes ? "<a href=\"" + update_info.releaseNotes + "\" target=\"_blank\">" + gettext("Release Notes") + "</a>" : "")
|
||||
+ "</li>";
|
||||
}
|
||||
});
|
||||
text += "</ul>";
|
||||
|
||||
text += "<small>" + gettext("Those components marked with <i class=\"icon-ok\"></i> can be updated directly.") + "</small>";
|
||||
|
||||
text += "</div>";
|
||||
|
||||
var options = {
|
||||
title: gettext("Update Available"),
|
||||
text: text,
|
||||
|
|
@ -302,7 +316,7 @@ $(function() {
|
|||
return result;
|
||||
};
|
||||
|
||||
self.performUpdate = function(force) {
|
||||
self.performUpdate = function(force, items) {
|
||||
self.updateInProgress = true;
|
||||
|
||||
var options = {
|
||||
|
|
@ -317,7 +331,7 @@ $(function() {
|
|||
};
|
||||
self._showPopup(options);
|
||||
|
||||
OctoPrint.plugins.softwareupdate.updateAll(force)
|
||||
OctoPrint.plugins.softwareupdate.updateAll(force, items)
|
||||
.done(function(data) {
|
||||
self.currentlyBeingUpdated = data.checks;
|
||||
self._markWorking(gettext("Updating..."), gettext("Updating, please wait."));
|
||||
|
|
@ -340,8 +354,6 @@ $(function() {
|
|||
if (self.updateInProgress) return;
|
||||
if (!self.loginState.isAdmin()) return;
|
||||
|
||||
force = (force == true);
|
||||
|
||||
if (self.printerState.isPrinting()) {
|
||||
self._showPopup({
|
||||
title: gettext("Can't update while printing"),
|
||||
|
|
@ -349,16 +361,18 @@ $(function() {
|
|||
type: "error"
|
||||
});
|
||||
} else {
|
||||
showConfirmationDialog({
|
||||
message: gettext("This will update your OctoPrint installation and restart the server."),
|
||||
onproceed: function(e) {
|
||||
self.performUpdate(force);
|
||||
}
|
||||
});
|
||||
self.forceUpdate = (force == true);
|
||||
self.confirmationDialog.modal("show");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
self.confirmUpdate = function() {
|
||||
self.confirmationDialog.hide();
|
||||
self.performUpdate(self.forceUpdate,
|
||||
_.map(self.availableAndPossible(), function(info) { return info.key }));
|
||||
};
|
||||
|
||||
self._showWorkingDialog = function(title) {
|
||||
if (!self.loginState.isAdmin()) {
|
||||
return;
|
||||
|
|
@ -592,5 +606,9 @@ $(function() {
|
|||
}
|
||||
|
||||
// view model class, parameters for constructor, container to bind to
|
||||
ADDITIONAL_VIEWMODELS.push([SoftwareUpdateViewModel, ["loginStateViewModel", "printerStateViewModel", "settingsViewModel"], document.getElementById("settings_plugin_softwareupdate")]);
|
||||
ADDITIONAL_VIEWMODELS.push([
|
||||
SoftwareUpdateViewModel,
|
||||
["loginStateViewModel", "printerStateViewModel", "settingsViewModel"],
|
||||
["#settings_plugin_softwareupdate", "#softwareupdate_confirmation_dialog"]
|
||||
]);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -31,3 +31,17 @@ td.settings_plugin_softwareupdate_column_update {
|
|||
.stderr;
|
||||
}
|
||||
}
|
||||
|
||||
.softwareupdate_notification {
|
||||
ul {
|
||||
margin: 10px 0 10px 25px;
|
||||
|
||||
.name {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
<div id="softwareupdate_confirmation_dialog" class="modal hide fade">
|
||||
<div class="modal-header">
|
||||
<a href="#" class="close" data-dismiss="modal" aria-hidden="true">×</a>
|
||||
<h3>{{ _('Are you sure you want to update now?') }}</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>
|
||||
{{ _('This will update the following components and restart the server:') }}
|
||||
</p>
|
||||
<ul>
|
||||
<!-- ko foreach: availableAndPossible -->
|
||||
<li>
|
||||
<span class="name" data-bind="text: fullName, attr: {title: fullName}"></span>
|
||||
<div class="releaseNotes" data-bind="visible: releaseNotes"><a data-bind="attr: {href: releaseNotes}">{{ _('Release Notes') }}</a></div>
|
||||
</li>
|
||||
<!-- /ko -->
|
||||
</ul>
|
||||
<p>
|
||||
{{ _('Be sure to read through any linked release notes, especially those for OctoPrint since they might contain important information you need to know <strong>before</strong> upgrading.') }}
|
||||
</p>
|
||||
<p>
|
||||
{{ _('Are you sure you want to proceed?') }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#" class="btn" data-dismiss="modal" aria-hidden="true">{{ _('Cancel') }}</a>
|
||||
<a href="#" class="btn btn-danger" data-bind="click: function() { $root.confirmUpdate(); }">{{ _('Proceed') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -32,7 +32,8 @@
|
|||
<strong data-bind="text: displayName"></strong>: <span data-bind="text: displayVersion"></span> <span data-bind="invisible: updatePossible"><i class="icon-exclamation-sign" title="{{ _('Update not possible, configuration ok?') }}"></i></span><br>
|
||||
<small class="muted">
|
||||
{{ _('Installed:') }} <span data-bind="text: information.local.name"></span><br>
|
||||
{{ _('Available:') }} <span data-bind="text: information.remote.name"></span>
|
||||
{{ _('Available:') }} <span data-bind="text: information.remote.name"></span><br>
|
||||
<span data-bind="visible: releaseNotes">{{ _('Release Notes:') }} <a data-bind="attr: {href: releaseNotes}, text: releaseNotes" target="_blank"></a></span>
|
||||
</small>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
|||
|
|
@ -15,33 +15,40 @@ RELEASE_URL = "https://api.github.com/repos/{user}/{repo}/releases"
|
|||
logger = logging.getLogger("octoprint.plugins.softwareupdate.version_checks.github_release")
|
||||
|
||||
def _get_latest_release(user, repo, include_prerelease=False):
|
||||
nothing = None, None, None
|
||||
r = requests.get(RELEASE_URL.format(user=user, repo=repo))
|
||||
|
||||
from . import log_github_ratelimit
|
||||
log_github_ratelimit(logger, r)
|
||||
|
||||
if not r.status_code == requests.codes.ok:
|
||||
return None, None
|
||||
return nothing
|
||||
|
||||
releases = r.json()
|
||||
|
||||
# sanitize
|
||||
required_fields = {"name", "tag_name", "html_url", "draft", "prerelease", "published_at"}
|
||||
releases = filter(lambda rel: set(rel.keys()) & required_fields == required_fields,
|
||||
releases)
|
||||
|
||||
# filter out prereleases and drafts
|
||||
if include_prerelease:
|
||||
releases = filter(lambda rel: not rel["draft"], releases)
|
||||
else:
|
||||
releases = filter(lambda rel: not rel["prerelease"] and not rel["draft"], releases)
|
||||
releases = filter(lambda rel: not rel["prerelease"] and not rel["draft"],
|
||||
releases)
|
||||
|
||||
if not releases:
|
||||
return None, None
|
||||
return nothing
|
||||
|
||||
# sort by date
|
||||
comp = lambda a, b: cmp(a["published_at"], b["published_at"])
|
||||
comp = lambda a, b: cmp(a.get("published_at", None), b["published_at"])
|
||||
releases = sorted(releases, cmp=comp)
|
||||
|
||||
# latest release = last in list
|
||||
latest = releases[-1]
|
||||
|
||||
return latest["name"], latest["tag_name"]
|
||||
return latest["name"], latest["tag_name"], latest.get("html_url", None)
|
||||
|
||||
|
||||
def _get_sanitized_version(version_string):
|
||||
|
|
@ -122,14 +129,14 @@ def get_latest(target, check, custom_compare=None):
|
|||
include_prerelease = check.get("prerelease", False)
|
||||
force_base = check.get("force_base", True)
|
||||
|
||||
remote_name, remote_tag = _get_latest_release(check["user"],
|
||||
check["repo"],
|
||||
include_prerelease=include_prerelease)
|
||||
remote_name, remote_tag, release_notes = _get_latest_release(check["user"],
|
||||
check["repo"],
|
||||
include_prerelease=include_prerelease)
|
||||
compare_type = check["release_compare"] if "release_compare" in check else "python"
|
||||
|
||||
information =dict(
|
||||
local=dict(name=current, value=current),
|
||||
remote=dict(name=remote_name, value=remote_tag)
|
||||
remote=dict(name=remote_name, value=remote_tag, release_notes=release_notes)
|
||||
)
|
||||
|
||||
logger.debug("Target: %s, local: %s, remote: %s" % (target, current, remote_tag))
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -925,6 +925,10 @@ textarea.block {
|
|||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.ui-pnotify a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/** Styles for Bootstrap Slider */
|
||||
|
||||
.slider {
|
||||
|
|
|
|||
Loading…
Reference in a new issue