Improve the version checking part of the changelog feature
- There is no client caching of the changelog/version anymore. Instead, server returns the expiration date of its cache, and that is used by the client as well. - There is now a "Check now" button on the client that appears when data is stale. This means that info is fetched only once and never refreshed (it was refreshed every hour before) unless the user explicitly wants to check latest version, which in turn is as stale as server info is, i.e. 15 minutes max. - Button style is shared with the "Join a channel" feature, `.btn-small` (not `.btn-sm` to be explicit that this is not a Bootstrap thing). - Version checker content is now centralized in the `version_checker` template, instead of being partially in the checker template, partially in the Help template, and partially in the code. - A "Try again" button lets user attempt to fetch info instead of forcing them to reload the page. - Use Flexbox to display a nicer version checker: icon is slightly bigger, and button is always aligned on the right. - Changelog logic has been removed from `lounge.js` and moved into the component file. - Changelog template is only passed what it needs instead of everything the server gives us. - Public version now displays version checker, since server is caching things. - Cleaner code overall.
This commit is contained in:
parent
d2106f1782
commit
238e894377
@ -137,6 +137,10 @@ kbd {
|
|||||||
cursor: pointer; /* This is useful for `<button>` elements */
|
cursor: pointer; /* This is useful for `<button>` elements */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-small {
|
||||||
|
padding: 5px 13px;
|
||||||
|
}
|
||||||
|
|
||||||
.btn:disabled,
|
.btn:disabled,
|
||||||
.btn:hover,
|
.btn:hover,
|
||||||
.btn:focus {
|
.btn:focus {
|
||||||
@ -235,7 +239,7 @@ kbd {
|
|||||||
#chat .nick .from::before,
|
#chat .nick .from::before,
|
||||||
#chat .action .from::before,
|
#chat .action .from::before,
|
||||||
#chat .toggle-button::after,
|
#chat .toggle-button::after,
|
||||||
.changelog-version::before,
|
#version-checker::before,
|
||||||
.context-menu-item::before,
|
.context-menu-item::before,
|
||||||
#help .website-link::before,
|
#help .website-link::before,
|
||||||
#help .documentation-link::before,
|
#help .documentation-link::before,
|
||||||
@ -991,9 +995,7 @@ kbd {
|
|||||||
#sidebar .join-form .btn {
|
#sidebar .join-form .btn {
|
||||||
display: block;
|
display: block;
|
||||||
width: 80%;
|
width: 80%;
|
||||||
padding: 1px;
|
|
||||||
margin: auto;
|
margin: auto;
|
||||||
height: 29px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#sidebar .add-channel-tooltip {
|
#sidebar .add-channel-tooltip {
|
||||||
@ -1635,47 +1637,70 @@ part/quit messages where we don't load previews (adds a blank line otherwise) */
|
|||||||
padding-bottom: 7px;
|
padding-bottom: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.changelog-version {
|
#version-checker {
|
||||||
display: block;
|
display: flex;
|
||||||
padding: 16px;
|
align-items: center;
|
||||||
|
padding: 10px;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
background-color: #d9edf7;
|
|
||||||
color: #31708f;
|
|
||||||
transition: color 0.2s, background-color 0.2s;
|
transition: color 0.2s, background-color 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.changelog-version::before {
|
#version-checker p,
|
||||||
margin-right: 6px;
|
#version-checker button {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#version-checker p {
|
||||||
|
flex: 1;
|
||||||
|
padding-top: 6px;
|
||||||
|
padding-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#version-checker::before {
|
||||||
|
margin-left: 6px;
|
||||||
|
margin-right: 12px;
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#version-checker.loading {
|
||||||
|
background-color: #d9edf7;
|
||||||
|
color: #31708f;
|
||||||
|
}
|
||||||
|
|
||||||
|
#version-checker.loading::before {
|
||||||
content: "\f250"; /* http://fontawesome.io/icon/hourglass-o/ */
|
content: "\f250"; /* http://fontawesome.io/icon/hourglass-o/ */
|
||||||
}
|
}
|
||||||
|
|
||||||
.changelog-version.new-version {
|
#version-checker.new-version {
|
||||||
color: #8a6d3b;
|
color: #8a6d3b;
|
||||||
background-color: #fcf8e3;
|
background-color: #fcf8e3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.changelog-version.new-version::before {
|
#version-checker.new-version::before {
|
||||||
content: "\f087"; /* http://fontawesome.io/icon/thumbs-o-up/ */
|
content: "\f087"; /* http://fontawesome.io/icon/thumbs-o-up/ */
|
||||||
}
|
}
|
||||||
|
|
||||||
.changelog-version.error {
|
#version-checker.error {
|
||||||
color: #a94442;
|
color: #a94442;
|
||||||
background-color: #f2dede;
|
background-color: #f2dede;
|
||||||
}
|
}
|
||||||
|
|
||||||
.changelog-version.error::before {
|
#version-checker.error::before {
|
||||||
margin-right: 6px;
|
|
||||||
content: "\f06a"; /* http://fontawesome.io/icon/exclamation-circle/ */
|
content: "\f06a"; /* http://fontawesome.io/icon/exclamation-circle/ */
|
||||||
}
|
}
|
||||||
|
|
||||||
.changelog-version.up-to-date {
|
#version-checker.up-to-date {
|
||||||
background-color: #dff0d8;
|
background-color: #dff0d8;
|
||||||
color: #3c763d;
|
color: #3c763d;
|
||||||
}
|
}
|
||||||
|
|
||||||
.changelog-version.up-to-date::before {
|
#version-checker.up-to-date #check-now {
|
||||||
margin-right: 6px;
|
/* "Check now" button is hidden until data expires */
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#version-checker.up-to-date::before {
|
||||||
content: "\f00c"; /* http://fontawesome.io/icon/check/ */
|
content: "\f00c"; /* http://fontawesome.io/icon/check/ */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ const utils = require("./utils");
|
|||||||
require("./webpush");
|
require("./webpush");
|
||||||
require("./keybinds");
|
require("./keybinds");
|
||||||
require("./clipboard");
|
require("./clipboard");
|
||||||
|
const Changelog = require("./socket-events/changelog");
|
||||||
const JoinChannel = require("./join-channel");
|
const JoinChannel = require("./join-channel");
|
||||||
|
|
||||||
$(function() {
|
$(function() {
|
||||||
@ -332,8 +333,6 @@ $(function() {
|
|||||||
$(this).closest(".msg.condensed").toggleClass("closed");
|
$(this).closest(".msg.condensed").toggleClass("closed");
|
||||||
});
|
});
|
||||||
|
|
||||||
let changelogRequestedAt = 0;
|
|
||||||
|
|
||||||
const openWindow = function openWindow(e, data) {
|
const openWindow = function openWindow(e, data) {
|
||||||
var self = $(this);
|
var self = $(this);
|
||||||
var target = self.data("target");
|
var target = self.data("target");
|
||||||
@ -426,12 +425,7 @@ $(function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (target === "#help" || target === "#changelog") {
|
if (target === "#help" || target === "#changelog") {
|
||||||
const now = Date.now();
|
Changelog.requestIfNeeded();
|
||||||
// Don't check more than once an hour
|
|
||||||
if (now - changelogRequestedAt > 3600 * 1000) {
|
|
||||||
changelogRequestedAt = now;
|
|
||||||
socket.emit("changelog");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
focus();
|
focus();
|
||||||
|
@ -4,19 +4,60 @@ const $ = require("jquery");
|
|||||||
const socket = require("../socket");
|
const socket = require("../socket");
|
||||||
const templates = require("../../views");
|
const templates = require("../../views");
|
||||||
|
|
||||||
socket.on("changelog", function(data) {
|
module.exports = {
|
||||||
const container = $("#changelog-version-container");
|
requestIfNeeded,
|
||||||
|
};
|
||||||
|
|
||||||
if (data.latest) {
|
// Requests version information if it hasn't been retrieved before (or if it has
|
||||||
container.addClass("new-version");
|
// been removed from the page, i.e. when clicking on "Check now". Displays a
|
||||||
container.html(templates.new_version(data));
|
// loading state until received.
|
||||||
} else if (data.current.changelog) {
|
function requestIfNeeded() {
|
||||||
container.addClass("up-to-date");
|
if ($("#version-checker").is(":empty")) {
|
||||||
container.text("The Lounge is up to date!");
|
renderVersionChecker({status: "loading"});
|
||||||
} else {
|
socket.emit("changelog");
|
||||||
container.addClass("error");
|
}
|
||||||
container.text("An error has occurred, try to reload the page.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#changelog").html(templates.windows.changelog(data));
|
socket.on("changelog", function(data) {
|
||||||
|
// 1. Release notes window for the current version
|
||||||
|
$("#changelog").html(templates.windows.changelog(data.current));
|
||||||
|
|
||||||
|
// 2. Version checker visible in Help window
|
||||||
|
let status;
|
||||||
|
|
||||||
|
if (data.latest) {
|
||||||
|
status = "new-version";
|
||||||
|
} else if (data.current.changelog) {
|
||||||
|
status = "up-to-date";
|
||||||
|
} else {
|
||||||
|
status = "error";
|
||||||
|
}
|
||||||
|
|
||||||
|
renderVersionChecker({
|
||||||
|
latest: data.latest,
|
||||||
|
status,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// When there is a button to refresh the checker available, display it when
|
||||||
|
// data is expired. Before that, server would return same information anyway.
|
||||||
|
if (data.expiresAt) {
|
||||||
|
setTimeout(
|
||||||
|
() => $("#version-checker #check-now").show(),
|
||||||
|
data.expiresAt - Date.now()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// When clicking the "Check now" button, remove current checker information and
|
||||||
|
// request a new one. Loading will be displayed in the meantime.
|
||||||
|
$("#help").on("click", "#check-now", () => {
|
||||||
|
$("#version-checker").empty();
|
||||||
|
requestIfNeeded();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Given a status and latest release information, update the version checker
|
||||||
|
// (CSS class and content)
|
||||||
|
function renderVersionChecker({status, latest}) {
|
||||||
|
$("#version-checker").attr("class", status)
|
||||||
|
.html(templates.version_checker({latest, status}));
|
||||||
|
}
|
||||||
|
@ -31,7 +31,6 @@ module.exports = {
|
|||||||
|
|
||||||
chan: require("./chan.tpl"),
|
chan: require("./chan.tpl"),
|
||||||
chat: require("./chat.tpl"),
|
chat: require("./chat.tpl"),
|
||||||
new_version: require("./new_version.tpl"),
|
|
||||||
contextmenu_divider: require("./contextmenu_divider.tpl"),
|
contextmenu_divider: require("./contextmenu_divider.tpl"),
|
||||||
contextmenu_item: require("./contextmenu_item.tpl"),
|
contextmenu_item: require("./contextmenu_item.tpl"),
|
||||||
date_marker: require("./date-marker.tpl"),
|
date_marker: require("./date-marker.tpl"),
|
||||||
@ -50,4 +49,5 @@ module.exports = {
|
|||||||
user: require("./user.tpl"),
|
user: require("./user.tpl"),
|
||||||
user_filtered: require("./user_filtered.tpl"),
|
user_filtered: require("./user_filtered.tpl"),
|
||||||
user_name: require("./user_name.tpl"),
|
user_name: require("./user_name.tpl"),
|
||||||
|
version_checker: require("./version_checker.tpl"),
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<form id="join-channel-{{id}}" class="join-form" method="post" action="" autocomplete="off">
|
<form id="join-channel-{{id}}" class="join-form" method="post" action="" autocomplete="off">
|
||||||
<input type="text" class="input" name="channel" placeholder="Channel" pattern="[^\s]+" maxlength="200" title="The channel name may not contain spaces" required>
|
<input type="text" class="input" name="channel" placeholder="Channel" pattern="[^\s]+" maxlength="200" title="The channel name may not contain spaces" required>
|
||||||
<input type="password" class="input" name="key" placeholder="Password (optional)" pattern="[^\s]+" maxlength="200" title="The channel password may not contain spaces">
|
<input type="password" class="input" name="key" placeholder="Password (optional)" pattern="[^\s]+" maxlength="200" title="The channel password may not contain spaces">
|
||||||
<button type="submit" class="btn joinchan:submit" data-id="{{id}}">Join</button>
|
<button type="submit" class="btn btn-small" data-id="{{id}}">Join</button>
|
||||||
</form>
|
</form>
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
The Lounge <b>{{latest.version}}</b>{{#if latest.prerelease}} (pre-release){{/if}}
|
|
||||||
is now available.
|
|
||||||
|
|
||||||
<a href="{{latest.url}}" target="_blank" rel="noopener">
|
|
||||||
Read more on GitHub
|
|
||||||
</a>
|
|
27
client/views/version_checker.tpl
Normal file
27
client/views/version_checker.tpl
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{{#equal status "loading"}}
|
||||||
|
<p>
|
||||||
|
Checking for updates...
|
||||||
|
</p>
|
||||||
|
{{else equal status "new-version"}}
|
||||||
|
<p>
|
||||||
|
The Lounge <b>{{latest.version}}</b>{{#if latest.prerelease}} (pre-release){{/if}}
|
||||||
|
is now available.
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<a href="{{latest.url}}" target="_blank" rel="noopener">
|
||||||
|
Read more on GitHub
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
{{else equal status "up-to-date"}}
|
||||||
|
<p>
|
||||||
|
The Lounge is up to date!
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<button id="check-now" class="btn btn-small">Check now</button>
|
||||||
|
{{else equal status "error"}}
|
||||||
|
<p>
|
||||||
|
Information about latest releases could not be retrieved.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<button id="check-now" class="btn btn-small">Try again</button>
|
||||||
|
{{/equal}}
|
@ -4,15 +4,15 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<a href="#" id="back-to-help" data-target="#help">« Help</a>
|
<a href="#" id="back-to-help" data-target="#help">« Help</a>
|
||||||
|
|
||||||
{{#if current}}
|
{{#if version}}
|
||||||
<h1 class="title">Release notes for {{current.version}}</h1>
|
<h1 class="title">Release notes for {{version}}</h1>
|
||||||
|
|
||||||
{{#if current.changelog}}
|
{{#if changelog}}
|
||||||
<h3>Introduction</h3>
|
<h3>Introduction</h3>
|
||||||
<div class="changelog-text">{{{current.changelog}}}</div>
|
<div class="changelog-text">{{{changelog}}}</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
<p>Unable to retrieve releases from GitHub.</p>
|
<p>Unable to retrieve releases from GitHub.</p>
|
||||||
<p><a href="https://github.com/thelounge/lounge/releases/tag/v{{current.version}}" target="_blank" rel="noopener">View release notes for this version on GitHub</a></p>
|
<p><a href="https://github.com/thelounge/lounge/releases/tag/v{{version}}" target="_blank" rel="noopener">View release notes for this version on GitHub</a></p>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<p>Loading changelog…</p>
|
<p>Loading changelog…</p>
|
||||||
|
@ -13,11 +13,7 @@
|
|||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<div class="about">
|
<div class="about">
|
||||||
{{#unless public}}
|
<div id="version-checker"></div>
|
||||||
<p id="changelog-version-container" class="changelog-version">
|
|
||||||
Checking for updates...
|
|
||||||
</p>
|
|
||||||
{{/unless}}
|
|
||||||
|
|
||||||
{{#if gitCommit}}
|
{{#if gitCommit}}
|
||||||
<p>
|
<p>
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
const pkg = require("../../package.json");
|
const pkg = require("../../package.json");
|
||||||
const request = require("request");
|
const request = require("request");
|
||||||
|
|
||||||
|
const TIME_TO_LIVE = 15 * 60 * 1000; // 15 minutes, in milliseconds
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
fetch,
|
fetch,
|
||||||
};
|
};
|
||||||
@ -67,12 +69,14 @@ function fetch(callback) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emptying cached information after 15 minutes
|
// Add expiration date to the data to send to the client for later refresh
|
||||||
|
versions.expiresAt = Date.now() + TIME_TO_LIVE;
|
||||||
|
|
||||||
|
// Emptying cached information after reaching said expiration date
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
delete versions.current.changelog;
|
delete versions.current.changelog;
|
||||||
delete versions.latest;
|
delete versions.latest;
|
||||||
}, 15 * 60 * 1000
|
}, TIME_TO_LIVE);
|
||||||
);
|
|
||||||
|
|
||||||
callback(versions);
|
callback(versions);
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user