FEATURE: Offline indicator controlled by message-bus connectivity (#21324)
This commit is contained in:
parent
685e1de3ea
commit
b1da670898
|
@ -0,0 +1,10 @@
|
|||
{{#if this.showing}}
|
||||
<div class="offline-indicator">
|
||||
<span>{{i18n "offline_indicator.no_internet"}}</span>
|
||||
<DButton
|
||||
@label="offline_indicator.refresh_page"
|
||||
@display="link"
|
||||
@action={{this.refresh}}
|
||||
/>
|
||||
</div>
|
||||
{{/if}}
|
|
@ -0,0 +1,16 @@
|
|||
import Component from "@glimmer/component";
|
||||
import { action } from "@ember/object";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class OfflineIndicator extends Component {
|
||||
@service messageBusConnectivity;
|
||||
|
||||
get showing() {
|
||||
return !this.messageBusConnectivity.connected;
|
||||
}
|
||||
|
||||
@action
|
||||
refresh() {
|
||||
window.location.reload(true);
|
||||
}
|
||||
}
|
|
@ -5,23 +5,16 @@ import { handleLogoff } from "discourse/lib/ajax";
|
|||
import userPresent, { onPresenceChange } from "discourse/lib/user-presence";
|
||||
|
||||
const LONG_POLL_AFTER_UNSEEN_TIME = 1200000; // 20 minutes
|
||||
const CONNECTIVITY_ERROR_CLASS = "message-bus-offline";
|
||||
|
||||
function updateConnectivityIndicator(stat) {
|
||||
if (stat === "error") {
|
||||
document.documentElement.classList.add(CONNECTIVITY_ERROR_CLASS);
|
||||
} else {
|
||||
document.documentElement.classList.remove(CONNECTIVITY_ERROR_CLASS);
|
||||
}
|
||||
}
|
||||
|
||||
function ajax(opts) {
|
||||
function ajax(opts, messageBusConnectivity) {
|
||||
if (opts.complete) {
|
||||
const oldComplete = opts.complete;
|
||||
opts.complete = function (xhr, stat) {
|
||||
handleLogoff(xhr);
|
||||
oldComplete(xhr, stat);
|
||||
updateConnectivityIndicator(stat);
|
||||
messageBusConnectivity.setConnectivity(
|
||||
stat === "abort" || xhr.readyState === 4
|
||||
);
|
||||
};
|
||||
} else {
|
||||
opts.complete = handleLogoff;
|
||||
|
@ -42,7 +35,10 @@ export default {
|
|||
|
||||
const messageBus = container.lookup("service:message-bus"),
|
||||
user = container.lookup("service:current-user"),
|
||||
siteSettings = container.lookup("service:site-settings");
|
||||
siteSettings = container.lookup("service:site-settings"),
|
||||
messageBusConnectivity = container.lookup(
|
||||
"service:message-bus-connectivity"
|
||||
);
|
||||
|
||||
messageBus.alwaysLongPoll = !isProduction();
|
||||
messageBus.shouldLongPollCallback = () =>
|
||||
|
@ -97,7 +93,7 @@ export default {
|
|||
if (userPresent()) {
|
||||
opts.headers["Discourse-Present"] = "true";
|
||||
}
|
||||
return ajax(opts);
|
||||
return ajax(opts, messageBusConnectivity);
|
||||
};
|
||||
} else {
|
||||
messageBus.ajax = function (opts) {
|
||||
|
@ -105,7 +101,7 @@ export default {
|
|||
if (userPresent()) {
|
||||
opts.headers["Discourse-Present"] = "true";
|
||||
}
|
||||
return ajax(opts);
|
||||
return ajax(opts, messageBusConnectivity);
|
||||
};
|
||||
|
||||
messageBus.baseUrl = getURL("/");
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import Service from "@ember/service";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
|
||||
const CONNECTIVITY_ERROR_CLASS = "message-bus-offline";
|
||||
|
||||
export default class MessageBusConnectivity extends Service {
|
||||
@tracked connected = true;
|
||||
|
||||
setConnectivity(connected) {
|
||||
this.connected = connected;
|
||||
document.documentElement.classList.toggle(
|
||||
CONNECTIVITY_ERROR_CLASS,
|
||||
!connected
|
||||
);
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@
|
|||
{{/if}}
|
||||
|
||||
<SoftwareUpdatePrompt />
|
||||
<OfflineIndicator />
|
||||
|
||||
<PluginOutlet
|
||||
@name="below-site-header"
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
@import "ignored-user-list";
|
||||
@import "keyboard_shortcuts";
|
||||
@import "navs";
|
||||
@import "offline-indicator";
|
||||
@import "pick-files-button";
|
||||
@import "relative-time-picker";
|
||||
@import "share-and-invite-modal";
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
.offline-indicator {
|
||||
position: fixed;
|
||||
top: var(--header-offset);
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
padding: 0.5em 1em;
|
||||
background-color: var(--primary-very-low);
|
||||
border-radius: var(--d-nav-pill-border-radius);
|
||||
z-index: z("header") - 10;
|
||||
}
|
|
@ -2065,6 +2065,10 @@ en:
|
|||
intro: "Hello! Looks like you’re enjoying the discussion, but you haven’t signed up for an account yet."
|
||||
value_prop: "Tired of scrolling through the same posts? When you create an account you’ll always come back to where you left off. With an account you can also be notified of new replies, save bookmarks, and use likes to thank others. We can all work together to make this community great. :heart:"
|
||||
|
||||
offline_indicator:
|
||||
no_internet: "No internet connection."
|
||||
refresh_page: "Refresh page"
|
||||
|
||||
summary:
|
||||
enabled_description: "You're viewing a summary of this topic: the most interesting posts as determined by the community."
|
||||
description:
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.describe "Network Disconnected", type: :system, js: true do
|
||||
fab!(:current_user) { Fabricate(:user) }
|
||||
|
||||
def with_network_disconnected
|
||||
page.driver.browser.network_conditions = { offline: true }
|
||||
yield
|
||||
page.driver.browser.network_conditions = { offline: false }
|
||||
end
|
||||
|
||||
it "Message bus connectivity service adds class to DOM and displays offline indicator" do
|
||||
sign_in(current_user)
|
||||
visit("/c")
|
||||
|
||||
expect(page).to have_no_css("html.message-bus-offline")
|
||||
expect(page).to have_no_css(".offline-indicator")
|
||||
|
||||
with_network_disconnected do
|
||||
# Message bus connectivity services adds the disconnected class to the DOM
|
||||
expect(page).to have_css("html.message-bus-offline")
|
||||
|
||||
# Offline indicator is rendered
|
||||
expect(page).to have_css(".offline-indicator")
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue