FEATURE: Move site updated modal into a less obtrusive prompt (#12577)
This moves the "This site was just updated" modal asking the user if they want to refresh into a subtle prompt that slides down from the header. Also in this PR I've added a helper to publish message bus messages in JS tests. So instead of this: ```javascript // Mimic a messagebus message MessageBus.callbacks .filterBy("channel", "/global/asset-version") .map((c) => c.func("somenewversion")); ``` We can have: ```javascript publishToMessageBus("/global/asset-version", "somenewversion"); ```
This commit is contained in:
parent
b0ff853f9f
commit
432b839997
|
@ -0,0 +1,56 @@
|
|||
import getURL from "discourse-common/lib/get-url";
|
||||
import { later } from "@ember/runloop";
|
||||
import discourseComputed, { on } from "discourse-common/utils/decorators";
|
||||
import Component from "@ember/component";
|
||||
|
||||
export default Component.extend({
|
||||
showPrompt: false,
|
||||
|
||||
classNameBindings: ["getClassNames"],
|
||||
attributeBindings: ["isHidden:aria-hidden"],
|
||||
|
||||
@discourseComputed
|
||||
rootUrl() {
|
||||
return getURL("/");
|
||||
},
|
||||
|
||||
@discourseComputed("showPrompt")
|
||||
getClassNames(showPrompt) {
|
||||
let classes = ["software-update-prompt"];
|
||||
|
||||
if (showPrompt) {
|
||||
classes.push("require-software-refresh");
|
||||
}
|
||||
|
||||
return classes.join(" ");
|
||||
},
|
||||
|
||||
@discourseComputed("showPrompt")
|
||||
isHidden(showPrompt) {
|
||||
return !showPrompt;
|
||||
},
|
||||
|
||||
@on("init")
|
||||
initSubscribtions() {
|
||||
let timeout;
|
||||
|
||||
this.messageBus.subscribe("/refresh_client", () => {
|
||||
this.session.requiresRefresh = true;
|
||||
});
|
||||
|
||||
let updatePrompt = this;
|
||||
this.messageBus.subscribe("/global/asset-version", (version) => {
|
||||
if (this.session.assetVersion !== version) {
|
||||
this.session.requiresRefresh = true;
|
||||
}
|
||||
|
||||
if (!timeout && this.session.requiresRefresh) {
|
||||
// Since we can do this transparently for people browsing the forum
|
||||
// hold back the message 24 hours.
|
||||
timeout = later(() => {
|
||||
updatePrompt.set("showPrompt", true);
|
||||
}, 1000 * 60 * 24 * 60);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
|
@ -1,40 +0,0 @@
|
|||
import I18n from "I18n";
|
||||
import bootbox from "bootbox";
|
||||
import { later } from "@ember/runloop";
|
||||
|
||||
// Subscribe to "asset-version" change events via the Message Bus
|
||||
export default {
|
||||
name: "asset-version",
|
||||
after: "message-bus",
|
||||
|
||||
initialize(container) {
|
||||
let timeout;
|
||||
const messageBus = container.lookup("message-bus:main");
|
||||
if (!messageBus) {
|
||||
return;
|
||||
}
|
||||
|
||||
let session = container.lookup("session:main");
|
||||
messageBus.subscribe("/refresh_client", () => {
|
||||
session.requiresRefresh = true;
|
||||
});
|
||||
|
||||
messageBus.subscribe("/global/asset-version", function (version) {
|
||||
if (session.assetVersion !== version) {
|
||||
session.requiresRefresh = true;
|
||||
}
|
||||
|
||||
if (!timeout && session.requiresRefresh) {
|
||||
// Since we can do this transparently for people browsing the forum
|
||||
// hold back the message 24 hours.
|
||||
timeout = later(() => {
|
||||
bootbox.confirm(I18n.t("assets_changed_confirm"), function (result) {
|
||||
if (result) {
|
||||
document.location.reload();
|
||||
}
|
||||
});
|
||||
}, 1000 * 60 * 24 * 60);
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
|
@ -7,6 +7,7 @@
|
|||
toggleMobileView=(route-action "toggleMobileView")
|
||||
toggleAnonymous=(route-action "toggleAnonymous")
|
||||
logout=(route-action "logout")}}
|
||||
{{software-update-prompt id="software-update-prompt"}}
|
||||
|
||||
{{plugin-outlet name="below-site-header" tagName="" args=(hash currentPath=router._router.currentPath)}}
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<div class="wrap">
|
||||
<a href={{rootUrl}} aria-live="polite">
|
||||
{{d-icon "redo"}} {{html-safe (i18n "software_update_prompt")}}
|
||||
</a>
|
||||
</div>
|
|
@ -1,10 +1,10 @@
|
|||
import {
|
||||
acceptance,
|
||||
exists,
|
||||
publishToMessageBus,
|
||||
queryAll,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import DiscourseURL from "discourse/lib/url";
|
||||
import MessageBus from "message-bus-client";
|
||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
import sinon from "sinon";
|
||||
import { test } from "qunit";
|
||||
|
@ -94,19 +94,16 @@ acceptance("Topic Discovery", function (needs) {
|
|||
"shows the topic unread"
|
||||
);
|
||||
|
||||
// Mimic a messagebus message
|
||||
MessageBus.callbacks.filterBy("channel", "/latest").map((c) =>
|
||||
c.func({
|
||||
message_type: "read",
|
||||
publishToMessageBus("/latest", {
|
||||
message_type: "read",
|
||||
topic_id: 11995,
|
||||
payload: {
|
||||
highest_post_number: 1,
|
||||
last_read_post_number: 2,
|
||||
notification_level: 1,
|
||||
topic_id: 11995,
|
||||
payload: {
|
||||
highest_post_number: 1,
|
||||
last_read_post_number: 2,
|
||||
notification_level: 1,
|
||||
topic_id: 11995,
|
||||
},
|
||||
})
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
await visit("/"); // We're already there, but use this to wait for re-render
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { TestModuleForComponent, render } from "@ember/test-helpers";
|
||||
import MessageBus from "message-bus-client";
|
||||
import EmberObject from "@ember/object";
|
||||
import { setupRenderingTest as EmberSetupRenderingTest } from "ember-qunit";
|
||||
import Session from "discourse/models/session";
|
||||
|
@ -67,6 +68,9 @@ export default function (name, opts) {
|
|||
instantiate: false,
|
||||
});
|
||||
this.registry.register("capabilities:main", EmberObject);
|
||||
this.registry.register("message-bus:main", MessageBus, {
|
||||
instantiate: false,
|
||||
});
|
||||
this.registry.register("site:main", this.site, { instantiate: false });
|
||||
this.registry.register("session:main", this.session, {
|
||||
instantiate: false,
|
||||
|
@ -80,6 +84,7 @@ export default function (name, opts) {
|
|||
this.registry.injection("component", "capabilities", "capabilities:main");
|
||||
this.registry.injection("component", "site", "site:main");
|
||||
this.registry.injection("component", "session", "session:main");
|
||||
this.registry.injection("component", "messageBus", "message-bus:main");
|
||||
|
||||
this.siteSettings = currentSettings();
|
||||
store = createStore();
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import QUnit, { module } from "qunit";
|
||||
import MessageBus from "message-bus-client";
|
||||
import {
|
||||
clearCache as clearOutletCache,
|
||||
resetExtraClasses,
|
||||
|
@ -437,3 +438,9 @@ export function count(selector) {
|
|||
export function exists(selector) {
|
||||
return count(selector) > 0;
|
||||
}
|
||||
|
||||
export function publishToMessageBus(channelPath, ...args) {
|
||||
MessageBus.callbacks
|
||||
.filterBy("channel", channelPath)
|
||||
.map((c) => c.func(...args));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
import componentTest, {
|
||||
setupRenderingTest,
|
||||
} from "discourse/tests/helpers/component-test";
|
||||
import sinon from "sinon";
|
||||
import {
|
||||
discourseModule,
|
||||
fakeTime,
|
||||
publishToMessageBus,
|
||||
queryAll,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import hbs from "htmlbars-inline-precompile";
|
||||
|
||||
let clock = null;
|
||||
discourseModule(
|
||||
"Integration | Component | software-update-prompt",
|
||||
function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
clock = fakeTime("2019-12-10T08:00:00", "Australia/Brisbane", true);
|
||||
});
|
||||
|
||||
hooks.afterEach(function () {
|
||||
clock.restore();
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
componentTest(
|
||||
"software-update-prompt gets correct CSS class after messageBus message",
|
||||
{
|
||||
template: hbs`{{software-update-prompt}}`,
|
||||
|
||||
test(assert) {
|
||||
assert.ok(
|
||||
queryAll("div.software-update-prompt.require-software-refresh")
|
||||
.length === 0,
|
||||
"it does not have the class to show the prompt"
|
||||
);
|
||||
assert.equal(
|
||||
queryAll("div.software-update-prompt")[0].getAttribute(
|
||||
"aria-hidden"
|
||||
),
|
||||
"",
|
||||
"it does have the aria-hidden attribute"
|
||||
);
|
||||
|
||||
publishToMessageBus("/global/asset-version", "somenewversion");
|
||||
|
||||
clock.tick(1000 * 60 * 24 * 60 + 10);
|
||||
|
||||
assert.ok(
|
||||
queryAll("div.software-update-prompt.require-software-refresh")
|
||||
.length === 1,
|
||||
"it does have the class to show the prompt"
|
||||
);
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
|
@ -10,4 +10,5 @@
|
|||
@import "common/printer-friendly";
|
||||
@import "common/base/_index";
|
||||
@import "common/d-editor";
|
||||
@import "common/software-update-prompt";
|
||||
@import "common/topic-timeline";
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
.software-update-prompt {
|
||||
position: fixed;
|
||||
flex: 1;
|
||||
right: 0;
|
||||
left: 0;
|
||||
background-color: var(--tertiary-low);
|
||||
color: var(--tertiary);
|
||||
max-height: 0;
|
||||
visibility: hidden;
|
||||
transition: max-height 1s;
|
||||
box-shadow: shadow("header");
|
||||
z-index: z("header") + 10;
|
||||
|
||||
a {
|
||||
display: block;
|
||||
padding: 0.5em 0;
|
||||
}
|
||||
|
||||
span {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.d-icon {
|
||||
margin-right: 0.33em;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
&.require-software-refresh {
|
||||
visibility: visible;
|
||||
overflow: hidden;
|
||||
max-height: 300px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
}
|
|
@ -178,6 +178,8 @@ en:
|
|||
wizard_required: "Welcome to your new Discourse! Let’s get started with <a href='%{url}' data-auto-route='true'>the setup wizard</a> ✨"
|
||||
emails_are_disabled: "All outgoing email has been globally disabled by an administrator. No email notifications of any kind will be sent."
|
||||
|
||||
software_update_prompt: "We've updated this site, <span>please refresh</span>, or you may experience unexpected behaviour."
|
||||
|
||||
bootstrap_mode_enabled:
|
||||
one: "To make launching your new site easier, you are in bootstrap mode. All new users will be granted trust level 1 and have daily email summary emails enabled. This will be automatically turned off when %{count} user has joined."
|
||||
other: "To make launching your new site easier, you are in bootstrap mode. All new users will be granted trust level 1 and have daily email summary emails enabled. This will be automatically turned off when %{count} users have joined."
|
||||
|
@ -1025,7 +1027,7 @@ en:
|
|||
no_messages_title: "You don’t have any messages"
|
||||
no_messages_body: >
|
||||
Need to have a direct personal conversation with someone, outside the normal conversational flow?<br><br>
|
||||
Message them by selecting their avatar and then look for the MESSAGE button.
|
||||
Message them by selecting their avatar and then look for the MESSAGE button.
|
||||
first_notification: "Your first notification! Select it to begin."
|
||||
dynamic_favicon: "Show counts on browser icon"
|
||||
skip_new_user_tips:
|
||||
|
|
Loading…
Reference in New Issue