DEV: Introduce default 'auto' mode for glimmer header (#26467)
This will automatically enable the glimmer header when all installed themes/plugins are ready. This replaces the old group-based site setting. In 'auto' mode, we check for calls to deprecated APIs (e.g. decorateWidget) which affect the old header. If any are present, we stick to the old header implementation and print a message to the console alongside the normal deprecation messages. To override this automatic behavior, a new `glimmer_header_mode` site setting can be set to 'disabled' or 'enabled'. This change also means that our test suite is running with the glimmer header. This unveiled a couple of small issues (e.g. some incorrect `aria-*` and `alt` text) which are now fixed. A number of selectors had to be updated to ensure the tests were clicking the actual `<button>` elements rather than the surrounding `<li>` elements.
This commit is contained in:
parent
5d0471ebe4
commit
3733db866c
|
@ -22,7 +22,10 @@ export default class Contents extends Component {
|
|||
<div class="contents">
|
||||
{{#if this.site.desktopView}}
|
||||
{{#if @sidebarEnabled}}
|
||||
<SidebarToggle @toggleHamburger={{@toggleHamburger}} />
|
||||
<SidebarToggle
|
||||
@toggleHamburger={{@toggleHamburger}}
|
||||
@showSidebar={{@showSidebar}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import Component from "@glimmer/component";
|
|||
import { hash } from "@ember/helper";
|
||||
import { on } from "@ember/modifier";
|
||||
import { action } from "@ember/object";
|
||||
import { waitForPromise } from "@ember/test-waiters";
|
||||
import { isDocumentRTL } from "discourse/lib/text-direction";
|
||||
import { prefersReducedMotion } from "discourse/lib/utilities";
|
||||
import { isTesting } from "discourse-common/config/environment";
|
||||
|
@ -9,14 +10,13 @@ import discourseLater from "discourse-common/lib/later";
|
|||
import closeOnClickOutside from "../../modifiers/close-on-click-outside";
|
||||
import HamburgerDropdown from "../sidebar/hamburger-dropdown";
|
||||
|
||||
const CLOSE_ON_CLICK_SELECTORS =
|
||||
"a[href], .sidebar-section-header-button, .sidebar-section-link-button, .sidebar-section-link";
|
||||
|
||||
export default class HamburgerDropdownWrapper extends Component {
|
||||
@action
|
||||
click(e) {
|
||||
if (
|
||||
e.target.closest(
|
||||
".sidebar-section-header-button, .sidebar-section-link-button, .sidebar-section-link"
|
||||
)
|
||||
) {
|
||||
if (e.target.closest(CLOSE_ON_CLICK_SELECTORS)) {
|
||||
this.args.toggleHamburger();
|
||||
}
|
||||
}
|
||||
|
@ -30,9 +30,9 @@ export default class HamburgerDropdownWrapper extends Component {
|
|||
const panel = document.querySelector(".menu-panel");
|
||||
const headerCloak = document.querySelector(".header-cloak");
|
||||
const finishPosition = isDocumentRTL() ? "340px" : "-340px";
|
||||
panel
|
||||
const panelAnimatePromise = panel
|
||||
.animate([{ transform: `translate3d(${finishPosition}, 0, 0)` }], {
|
||||
duration: 200,
|
||||
duration: isTesting() ? 0 : 200,
|
||||
fill: "forwards",
|
||||
easing: "ease-in",
|
||||
})
|
||||
|
@ -43,11 +43,13 @@ export default class HamburgerDropdownWrapper extends Component {
|
|||
discourseLater(() => this.args.toggleHamburger());
|
||||
}
|
||||
});
|
||||
headerCloak.animate([{ opacity: 0 }], {
|
||||
duration: 200,
|
||||
const cloakAnimatePromise = headerCloak.animate([{ opacity: 0 }], {
|
||||
duration: isTesting() ? 0 : 200,
|
||||
fill: "forwards",
|
||||
easing: "ease-in",
|
||||
});
|
||||
}).finished;
|
||||
waitForPromise(panelAnimatePromise);
|
||||
waitForPromise(cloakAnimatePromise);
|
||||
} else {
|
||||
this.args.toggleHamburger();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { hash } from "@ember/helper";
|
||||
import { concat } from "@ember/helper";
|
||||
import emoji from "discourse/helpers/emoji";
|
||||
import I18n from "discourse-i18n";
|
||||
|
||||
|
@ -17,7 +17,8 @@ const UserStatusBubble = <template>
|
|||
<div class="user-status-background">
|
||||
{{emoji
|
||||
@status.emoji
|
||||
(hash title=(title @status.description @status.ends_at @timezone))
|
||||
title=(title @status.description @status.ends_at @timezone)
|
||||
alt=(concat ":" @status.emoji ":")
|
||||
}}
|
||||
</div>
|
||||
</template>;
|
||||
|
|
|
@ -13,6 +13,7 @@ export default Controller.extend({
|
|||
showTop: true,
|
||||
router: service(),
|
||||
footer: service(),
|
||||
header: service(),
|
||||
sidebarState: service(),
|
||||
showSidebar: false,
|
||||
sidebarDisabledRouteOverride: false,
|
||||
|
|
|
@ -24,6 +24,7 @@ export default {
|
|||
applicationController.calculateShowSidebar()
|
||||
);
|
||||
applicationController.appEvents.trigger("site-header:force-refresh");
|
||||
owner.lookup("service:header").hamburgerVisible = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -203,19 +203,6 @@ function wrapWithErrorHandler(func, messageKey) {
|
|||
};
|
||||
}
|
||||
|
||||
function deprecatedHeaderWidgetOverride(widgetName, override) {
|
||||
if (DEPRECATED_HEADER_WIDGETS.includes(widgetName)) {
|
||||
deprecated(
|
||||
`The ${widgetName} widget has been deprecated and ${override} is no longer a supported override.`,
|
||||
{
|
||||
since: "v3.3.0.beta1-dev",
|
||||
id: "discourse.header-widget-overrides",
|
||||
url: "https://meta.discourse.org/t/296544",
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PluginApi {
|
||||
constructor(version, container) {
|
||||
this.version = version;
|
||||
|
@ -560,7 +547,7 @@ class PluginApi {
|
|||
**/
|
||||
decorateWidget(name, fn) {
|
||||
const widgetName = name.split(":")[0];
|
||||
deprecatedHeaderWidgetOverride(widgetName, "decorateWidget");
|
||||
this.#deprecatedHeaderWidgetOverride(widgetName, "decorateWidget");
|
||||
|
||||
decorateWidget(name, fn);
|
||||
}
|
||||
|
@ -591,7 +578,7 @@ class PluginApi {
|
|||
return;
|
||||
}
|
||||
|
||||
deprecatedHeaderWidgetOverride(widget, "attachWidgetAction");
|
||||
this.#deprecatedHeaderWidgetOverride(widget, "attachWidgetAction");
|
||||
|
||||
widgetClass.prototype[actionName] = fn;
|
||||
}
|
||||
|
@ -910,7 +897,7 @@ class PluginApi {
|
|||
*
|
||||
**/
|
||||
changeWidgetSetting(widgetName, settingName, newValue) {
|
||||
deprecatedHeaderWidgetOverride(widgetName, "changeWidgetSetting");
|
||||
this.#deprecatedHeaderWidgetOverride(widgetName, "changeWidgetSetting");
|
||||
changeSetting(widgetName, settingName, newValue);
|
||||
}
|
||||
|
||||
|
@ -944,7 +931,7 @@ class PluginApi {
|
|||
**/
|
||||
|
||||
reopenWidget(name, args) {
|
||||
deprecatedHeaderWidgetOverride(name, "reopenWidget");
|
||||
this.#deprecatedHeaderWidgetOverride(name, "reopenWidget");
|
||||
return reopenWidget(name, args);
|
||||
}
|
||||
|
||||
|
@ -979,6 +966,7 @@ class PluginApi {
|
|||
url: "https://meta.discourse.org/t/296544",
|
||||
}
|
||||
);
|
||||
this.container.lookup("service:header").anyWidgetHeaderOverrides = true;
|
||||
attachAdditionalPanel(name, toggle, transformAttrs);
|
||||
}
|
||||
|
||||
|
@ -2952,6 +2940,20 @@ class PluginApi {
|
|||
|
||||
registerAdminPluginConfigNav(pluginId, mode, links);
|
||||
}
|
||||
|
||||
#deprecatedHeaderWidgetOverride(widgetName, override) {
|
||||
if (DEPRECATED_HEADER_WIDGETS.includes(widgetName)) {
|
||||
this.container.lookup("service:header").anyWidgetHeaderOverrides = true;
|
||||
deprecated(
|
||||
`The ${widgetName} widget has been deprecated and ${override} is no longer a supported override.`,
|
||||
{
|
||||
since: "v3.3.0.beta1-dev",
|
||||
id: "discourse.header-widget-overrides",
|
||||
url: "https://meta.discourse.org/t/296544",
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// from http://stackoverflow.com/questions/6832596/how-to-compare-software-version-number-using-js-only-number
|
||||
|
|
|
@ -26,7 +26,7 @@ export default class CloseOnClickOutside extends Modifier {
|
|||
}
|
||||
|
||||
if (
|
||||
document.querySelector(this.targetSelector).contains(event.target) ||
|
||||
document.querySelector(this.targetSelector)?.contains(event.target) ||
|
||||
(this.secondaryTargetSelector &&
|
||||
document
|
||||
.querySelector(this.secondaryTargetSelector)
|
||||
|
|
|
@ -1,10 +1,32 @@
|
|||
import { tracked } from "@glimmer/tracking";
|
||||
import Service from "@ember/service";
|
||||
import Service, { service } from "@ember/service";
|
||||
import { disableImplicitInjections } from "discourse/lib/implicit-injections";
|
||||
|
||||
@disableImplicitInjections
|
||||
export default class Header extends Service {
|
||||
@service siteSettings;
|
||||
|
||||
@tracked topic = null;
|
||||
@tracked hamburgerVisible = false;
|
||||
@tracked userVisible = false;
|
||||
@tracked anyWidgetHeaderOverrides = false;
|
||||
|
||||
get useGlimmerHeader() {
|
||||
if (this.siteSettings.glimmer_header_mode === "disabled") {
|
||||
return false;
|
||||
} else if (this.siteSettings.glimmer_header_mode === "enabled") {
|
||||
return true;
|
||||
} else {
|
||||
// Auto
|
||||
if (this.anyWidgetHeaderOverrides) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(
|
||||
"Using legacy 'widget' header because themes and/or plugins are using deprecated APIs. https://meta.discourse.org/t/296544"
|
||||
);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
/>
|
||||
|
||||
{{#if this.showSiteHeader}}
|
||||
{{#if this.currentUser.glimmer_header_enabled}}
|
||||
{{#if this.header.useGlimmerHeader}}
|
||||
<GlimmerSiteHeader
|
||||
@canSignUp={{this.canSignUp}}
|
||||
@showCreateAccount={{route-action "showCreateAccount"}}
|
||||
|
|
|
@ -27,7 +27,7 @@ acceptance("Do not disturb", function (needs) {
|
|||
updateCurrentUser({ do_not_disturb_until: null });
|
||||
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
await click(".header-dropdown-toggle.current-user button");
|
||||
await click("#user-menu-button-profile");
|
||||
await click("#quick-access-profile .do-not-disturb .btn");
|
||||
|
||||
|
@ -52,7 +52,7 @@ acceptance("Do not disturb", function (needs) {
|
|||
updateCurrentUser({ do_not_disturb_until: null });
|
||||
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
await click(".header-dropdown-toggle.current-user button");
|
||||
await click("#user-menu-button-profile");
|
||||
await click("#quick-access-profile .do-not-disturb .btn");
|
||||
|
||||
|
@ -94,7 +94,7 @@ acceptance("Do not disturb", function (needs) {
|
|||
"The active dnd icon is shown"
|
||||
);
|
||||
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
await click(".header-dropdown-toggle.current-user button");
|
||||
await click("#user-menu-button-profile");
|
||||
assert.strictEqual(
|
||||
query(".do-not-disturb .relative-date").textContent.trim(),
|
||||
|
@ -126,7 +126,7 @@ acceptance("Do not disturb", function (needs) {
|
|||
this.siteSettings.enable_user_status = true;
|
||||
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
await click(".header-dropdown-toggle.current-user button");
|
||||
await click("#user-menu-button-profile");
|
||||
await click("#quick-access-profile .do-not-disturb .btn");
|
||||
|
||||
|
@ -137,7 +137,7 @@ acceptance("Do not disturb", function (needs) {
|
|||
updateCurrentUser({ do_not_disturb_until: DoNotDisturb.forever });
|
||||
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
await click(".header-dropdown-toggle.current-user button");
|
||||
await click("#user-menu-button-profile");
|
||||
|
||||
assert.dom(".do-not-disturb .relative-date").doesNotExist();
|
||||
|
|
|
@ -51,7 +51,7 @@ acceptance(
|
|||
|
||||
test("history modal is shown when navigating from a non-topic page", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
await click(".header-dropdown-toggle.current-user button");
|
||||
await click(".notification.edited a");
|
||||
const [v1, v2] = queryAll(".history-modal .revision-content");
|
||||
|
||||
|
@ -88,7 +88,7 @@ acceptance(
|
|||
|
||||
test("history modal is not shown when navigating from a non-topic page", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
await click(".header-dropdown-toggle.current-user button");
|
||||
await click(".notification.edited a");
|
||||
assert
|
||||
.dom(".history-modal")
|
||||
|
@ -117,7 +117,7 @@ acceptance(
|
|||
|
||||
test("history modal is not shown when navigating from a non-topic page", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
await click(".header-dropdown-toggle.current-user button");
|
||||
await click(".notification.edited a");
|
||||
assert
|
||||
.dom(".history-modal")
|
||||
|
|
|
@ -8,6 +8,9 @@ import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
|||
// header is the default.
|
||||
acceptance("Header API - authenticated", function (needs) {
|
||||
needs.user();
|
||||
needs.settings({
|
||||
glimmer_header_mode: "disabled",
|
||||
});
|
||||
|
||||
test("can add buttons to the header", async function (assert) {
|
||||
withPluginApi("1.29.0", (api) => {
|
||||
|
@ -93,7 +96,7 @@ acceptance("Header API - anonymous", function () {
|
|||
acceptance("Glimmer Header API - authenticated", function (needs) {
|
||||
needs.user({ groups: AUTO_GROUPS.everyone });
|
||||
needs.settings({
|
||||
experimental_glimmer_header_groups: AUTO_GROUPS.everyone,
|
||||
glimmer_header_mode: "enabled",
|
||||
});
|
||||
|
||||
test("can add buttons to the header", async function (assert) {
|
||||
|
|
|
@ -64,8 +64,9 @@ async function triggerSwipeEnd({ x, y, touchTarget }) {
|
|||
// new Touch() isn't available in Firefox, so this is skipped there
|
||||
acceptance("Mobile - menu swipes", function (needs) {
|
||||
needs.mobileView();
|
||||
needs.user({
|
||||
glimmer_header_enabled: true,
|
||||
needs.user();
|
||||
needs.settings({
|
||||
glimmer_header_mode: "enabled",
|
||||
});
|
||||
|
||||
chromeTest("swipe to close hamburger", async function (assert) {
|
||||
|
|
|
@ -2,6 +2,7 @@ import {
|
|||
click,
|
||||
currentURL,
|
||||
fillIn,
|
||||
triggerEvent,
|
||||
triggerKeyEvent,
|
||||
visit,
|
||||
} from "@ember/test-helpers";
|
||||
|
@ -19,6 +20,9 @@ import {
|
|||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
import I18n from "discourse-i18n";
|
||||
|
||||
const clickOutside = () =>
|
||||
triggerEvent(document.querySelector("header.d-header"), "pointerdown");
|
||||
|
||||
acceptance("Search - Anonymous", function (needs) {
|
||||
needs.pretender((server, helper) => {
|
||||
server.get("/search/query", (request) => {
|
||||
|
@ -106,7 +110,7 @@ acceptance("Search - Anonymous", function (needs) {
|
|||
await click("#search-button");
|
||||
assert.ok(exists(".search-menu"));
|
||||
|
||||
await click(".d-header"); // click outside
|
||||
await clickOutside();
|
||||
assert.ok(!exists(".search-menu"));
|
||||
|
||||
await click("#search-button");
|
||||
|
@ -1249,7 +1253,7 @@ acceptance("Search - assistant", function (needs) {
|
|||
|
||||
assert.notOk(exists(".btn.search-context"), "it removes the button");
|
||||
|
||||
await click(".d-header");
|
||||
await clickOutside();
|
||||
await click("#search-button");
|
||||
assert.ok(
|
||||
exists(".btn.search-context"),
|
||||
|
|
|
@ -30,7 +30,7 @@ acceptance("Sidebar - Anonymous User", function (needs) {
|
|||
this.siteSettings.navigation_menu = "header dropdown";
|
||||
|
||||
await visit("/");
|
||||
await click(".hamburger-dropdown");
|
||||
await click(".hamburger-dropdown button");
|
||||
|
||||
assert.ok(
|
||||
exists(".sidebar-hamburger-dropdown .sidebar-sections-anonymous"),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { click, visit, waitFor } from "@ember/test-helpers";
|
||||
import { click, triggerEvent, visit, waitFor } from "@ember/test-helpers";
|
||||
import $ from "jquery";
|
||||
import { test } from "qunit";
|
||||
import { acceptance, exists } from "discourse/tests/helpers/qunit-helpers";
|
||||
|
@ -38,7 +38,8 @@ acceptance("Sidebar - Narrow Desktop", function (needs) {
|
|||
"cloak sidebar is displayed"
|
||||
);
|
||||
|
||||
await click("#main-outlet");
|
||||
await triggerEvent(document.querySelector(".header-cloak"), "pointerdown");
|
||||
|
||||
assert.ok(
|
||||
!exists(".sidebar-hamburger-dropdown"),
|
||||
"cloak sidebar is collapsed"
|
||||
|
@ -66,7 +67,7 @@ acceptance("Sidebar - Narrow Desktop", function (needs) {
|
|||
timeout: 5000,
|
||||
});
|
||||
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
await click(".header-dropdown-toggle.current-user button");
|
||||
$(".header-dropdown-toggle.current-user").click();
|
||||
|
||||
assert.ok(exists(".quick-access-panel"));
|
||||
|
|
|
@ -21,7 +21,7 @@ acceptance(
|
|||
|
||||
test("sections are collapsable", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".hamburger-dropdown");
|
||||
await click("#toggle-hamburger-menu");
|
||||
|
||||
assert.ok(
|
||||
exists(".sidebar-section-header.sidebar-section-header-collapsable"),
|
||||
|
@ -42,14 +42,14 @@ acceptance(
|
|||
|
||||
test("showing and hiding sidebar", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".hamburger-dropdown");
|
||||
await click("#toggle-hamburger-menu");
|
||||
|
||||
assert.ok(
|
||||
exists(".sidebar-hamburger-dropdown"),
|
||||
"displays the sidebar dropdown"
|
||||
);
|
||||
|
||||
await click(".hamburger-dropdown");
|
||||
await click("#toggle-hamburger-menu");
|
||||
|
||||
assert.notOk(
|
||||
exists(".sidebar-hamburger-dropdown"),
|
||||
|
@ -59,7 +59,7 @@ acceptance(
|
|||
|
||||
test("sections are not collapsable", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".hamburger-dropdown");
|
||||
await click("#toggle-hamburger-menu");
|
||||
|
||||
assert.notOk(
|
||||
exists(".sidebar-section-header.sidebar-section-header-collapsable"),
|
||||
|
@ -69,7 +69,7 @@ acceptance(
|
|||
|
||||
test("'more' dropdown should display as regular list items in header dropdown mode", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".hamburger-dropdown");
|
||||
await click("#toggle-hamburger-menu");
|
||||
|
||||
assert.ok(
|
||||
exists("[data-link-name='admin']"),
|
||||
|
|
|
@ -3,6 +3,7 @@ import {
|
|||
click,
|
||||
currentRouteName,
|
||||
currentURL,
|
||||
triggerEvent,
|
||||
triggerKeyEvent,
|
||||
visit,
|
||||
} from "@ember/test-helpers";
|
||||
|
@ -60,7 +61,7 @@ acceptance("User menu", function (needs) {
|
|||
|
||||
test("notifications panel has a11y attributes", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
const panel = query("#quick-access-all-notifications");
|
||||
assert.strictEqual(panel.getAttribute("tabindex"), "-1");
|
||||
assert.strictEqual(
|
||||
|
@ -71,7 +72,7 @@ acceptance("User menu", function (needs) {
|
|||
|
||||
test("replies notifications panel has a11y attributes", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
await click("#user-menu-button-replies");
|
||||
const panel = query("#quick-access-replies");
|
||||
assert.strictEqual(panel.getAttribute("tabindex"), "-1");
|
||||
|
@ -83,7 +84,7 @@ acceptance("User menu", function (needs) {
|
|||
|
||||
test("profile panel has a11y attributes", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
await click("#user-menu-button-profile");
|
||||
const panel = query("#quick-access-profile");
|
||||
assert.strictEqual(panel.getAttribute("tabindex"), "-1");
|
||||
|
@ -95,7 +96,7 @@ acceptance("User menu", function (needs) {
|
|||
|
||||
test("clicking on an unread notification", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
|
||||
let repliesBadgeNotification = query(
|
||||
"#user-menu-button-replies .badge-notification"
|
||||
|
@ -114,7 +115,7 @@ acceptance("User menu", function (needs) {
|
|||
"the Discourse-Clear-Notifications request header is set to the notification id in the next ajax request"
|
||||
);
|
||||
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
repliesBadgeNotification = query(
|
||||
"#user-menu-button-replies .badge-notification"
|
||||
);
|
||||
|
@ -129,7 +130,7 @@ acceptance("User menu", function (needs) {
|
|||
updateCurrentUser({ reviewable_count: 1 });
|
||||
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
await click("#user-menu-button-review-queue");
|
||||
|
||||
assert.strictEqual(
|
||||
|
@ -152,7 +153,7 @@ acceptance("User menu", function (needs) {
|
|||
"clicking on an item closes the menu after navigating"
|
||||
);
|
||||
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
await click("#user-menu-button-review-queue");
|
||||
await click("#quick-access-review-queue li.reviewable.pending a");
|
||||
|
||||
|
@ -216,7 +217,7 @@ acceptance("User menu", function (needs) {
|
|||
"user-menu-button-profile": I18n.t("user_menu.tabs.profile"),
|
||||
};
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
for (const [key, title] of Object.entries(expectedTitles)) {
|
||||
assert.strictEqual(
|
||||
query(`#${key}`).title,
|
||||
|
@ -291,7 +292,7 @@ acceptance("User menu", function (needs) {
|
|||
};
|
||||
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
|
||||
assert.ok(
|
||||
exists("#user-menu-button-custom-tab-1"),
|
||||
|
@ -377,7 +378,7 @@ acceptance("User menu", function (needs) {
|
|||
});
|
||||
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
|
||||
const notifications = queryAll(
|
||||
"#quick-access-all-notifications ul li.notification"
|
||||
|
@ -404,7 +405,7 @@ acceptance("User menu", function (needs) {
|
|||
});
|
||||
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
await click("#user-menu-button-bookmarks");
|
||||
|
||||
const bookmarks = queryAll("#quick-access-bookmarks ul li.bookmark");
|
||||
|
@ -431,7 +432,7 @@ acceptance("User menu", function (needs) {
|
|||
});
|
||||
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
await click("#user-menu-button-messages");
|
||||
|
||||
const messages = queryAll("#quick-access-messages ul li.message");
|
||||
|
@ -442,9 +443,12 @@ acceptance("User menu", function (needs) {
|
|||
});
|
||||
|
||||
test("the profile tab", async function (assert) {
|
||||
const clickOutside = () =>
|
||||
triggerEvent(document.querySelector("header.d-header"), "pointerdown");
|
||||
|
||||
updateCurrentUser({ draft_count: 13 });
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
await click("#user-menu-button-profile");
|
||||
|
||||
const summaryLink = query("#quick-access-profile ul li.summary a");
|
||||
|
@ -492,9 +496,10 @@ acceptance("User menu", function (needs) {
|
|||
"invites link has the right icon"
|
||||
);
|
||||
|
||||
await click("header.d-header"); // close the menu
|
||||
await clickOutside();
|
||||
updateCurrentUser({ can_invite_to_forum: false });
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
|
||||
await click("#user-menu-button-profile");
|
||||
|
||||
assert.notOk(
|
||||
|
@ -548,11 +553,11 @@ acceptance("User menu", function (needs) {
|
|||
"Do Not Disturb button has the right icon"
|
||||
);
|
||||
|
||||
await click("header.d-header"); // close the menu
|
||||
await clickOutside();
|
||||
const date = new Date();
|
||||
date.setHours(date.getHours() + 2);
|
||||
updateCurrentUser({ do_not_disturb_until: date.toISOString() });
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
await click("#user-menu-button-profile");
|
||||
|
||||
doNotDisturbButton = query(
|
||||
|
@ -591,9 +596,9 @@ acceptance("User menu", function (needs) {
|
|||
"toggle anonymous button has the right icon when the user isn't anonymous"
|
||||
);
|
||||
|
||||
await click("header.d-header"); // close the menu
|
||||
await clickOutside();
|
||||
updateCurrentUser({ is_anonymous: true });
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
await click("#user-menu-button-profile");
|
||||
|
||||
toggleAnonButton = query(
|
||||
|
@ -612,7 +617,7 @@ acceptance("User menu", function (needs) {
|
|||
"toggle anonymous button has the right icon when the user is anonymous"
|
||||
);
|
||||
|
||||
await click("header.d-header"); // close the menu
|
||||
await clickOutside();
|
||||
updateCurrentUser({
|
||||
is_anonymous: false,
|
||||
can_post_anonymously: false,
|
||||
|
@ -623,7 +628,7 @@ acceptance("User menu", function (needs) {
|
|||
AUTO_GROUPS.trust_level_2,
|
||||
],
|
||||
});
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
await click("#user-menu-button-profile");
|
||||
|
||||
assert.notOk(
|
||||
|
@ -635,7 +640,7 @@ acceptance("User menu", function (needs) {
|
|||
"toggle anon button isn't shown when the user can't use it"
|
||||
);
|
||||
|
||||
await click("header.d-header"); // close the menu
|
||||
await clickOutside();
|
||||
updateCurrentUser({
|
||||
is_anonymous: true,
|
||||
trust_level: 2,
|
||||
|
@ -646,7 +651,7 @@ acceptance("User menu", function (needs) {
|
|||
AUTO_GROUPS.trust_level_2,
|
||||
],
|
||||
});
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
await click("#user-menu-button-profile");
|
||||
|
||||
assert.ok(
|
||||
|
@ -654,7 +659,7 @@ acceptance("User menu", function (needs) {
|
|||
"toggle anon button is always shown if the user is anonymous"
|
||||
);
|
||||
|
||||
await click("header.d-header"); // close the menu
|
||||
await clickOutside();
|
||||
updateCurrentUser({
|
||||
is_anonymous: true,
|
||||
can_post_anonymously: true,
|
||||
|
@ -667,7 +672,7 @@ acceptance("User menu", function (needs) {
|
|||
AUTO_GROUPS.trust_level_4,
|
||||
],
|
||||
});
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
await click("#user-menu-button-profile");
|
||||
|
||||
assert.notOk(
|
||||
|
@ -675,7 +680,7 @@ acceptance("User menu", function (needs) {
|
|||
"toggle anon button is not shown if the allow_anonymous_posting setting is false"
|
||||
);
|
||||
|
||||
await click("header.d-header"); // close the menu
|
||||
await clickOutside();
|
||||
updateCurrentUser({
|
||||
is_anonymous: false,
|
||||
can_post_anonymously: false,
|
||||
|
@ -686,7 +691,7 @@ acceptance("User menu", function (needs) {
|
|||
AUTO_GROUPS.trust_level_2,
|
||||
],
|
||||
});
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
await click("#user-menu-button-profile");
|
||||
|
||||
assert.notOk(
|
||||
|
@ -726,7 +731,7 @@ acceptance("User menu", function (needs) {
|
|||
});
|
||||
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
await click("#user-menu-button-profile");
|
||||
|
||||
const item1 = query("#quick-access-profile ul li.test-1-item");
|
||||
|
@ -792,7 +797,7 @@ acceptance("User menu", function (needs) {
|
|||
});
|
||||
});
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
await click("#user-menu-button-all-notifications");
|
||||
assert.strictEqual(
|
||||
currentURL(),
|
||||
|
@ -812,7 +817,7 @@ acceptance("User menu", function (needs) {
|
|||
["#user-menu-button-profile", "/u/eviltrout/summary"],
|
||||
];
|
||||
for (const [id, expectedLink] of tabs) {
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
await click(id);
|
||||
await click(id);
|
||||
if (expectedLink) {
|
||||
|
@ -837,7 +842,7 @@ acceptance("User menu", function (needs) {
|
|||
|
||||
test("tabs have hrefs and can be opened in new window/tab", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
|
||||
assert
|
||||
.dom("#user-menu-button-replies")
|
||||
|
@ -865,7 +870,7 @@ acceptance("User menu", function (needs) {
|
|||
|
||||
test("tabs without hrefs can be visited with the keyboard", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
|
||||
await triggerKeyEvent(
|
||||
"#user-menu-button-other-notifications",
|
||||
|
@ -881,7 +886,7 @@ acceptance("User menu", function (needs) {
|
|||
|
||||
test("closes the menu when navigating away", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
await click("#user-menu-button-profile");
|
||||
await click(".quick-access-panel .preferences a");
|
||||
|
||||
|
@ -947,7 +952,7 @@ acceptance("User menu - Dismiss button", function (needs) {
|
|||
|
||||
test("shows confirmation modal for the all-notifications list", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
|
||||
await click(".user-menu .notifications-dismiss");
|
||||
assert.strictEqual(
|
||||
|
@ -968,7 +973,7 @@ acceptance("User menu - Dismiss button", function (needs) {
|
|||
|
||||
test("shows confirmation modal for the bookmarks list", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
|
||||
assert.strictEqual(
|
||||
query("#user-menu-button-bookmarks .badge-notification").textContent,
|
||||
|
@ -1024,7 +1029,7 @@ acceptance("User menu - Dismiss button", function (needs) {
|
|||
|
||||
test("shows confirmation modal for the messages list", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
|
||||
assert.strictEqual(
|
||||
query("#user-menu-button-messages .badge-notification").textContent,
|
||||
|
@ -1080,7 +1085,7 @@ acceptance("User menu - Dismiss button", function (needs) {
|
|||
|
||||
test("doesn't show confirmation modal for the likes notifications list", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
|
||||
await click("#user-menu-button-likes");
|
||||
await click(".user-menu .notifications-dismiss");
|
||||
|
@ -1092,7 +1097,7 @@ acceptance("User menu - Dismiss button", function (needs) {
|
|||
|
||||
test("doesn't show confirmation modal for the other notifications list", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
|
||||
await click("#user-menu-button-other-notifications");
|
||||
let othersBadgeNotification = query(
|
||||
|
@ -1125,14 +1130,14 @@ acceptance("User menu - avatars", function (needs) {
|
|||
|
||||
test("It shows user avatars for various notifications on all notifications pane", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
assert.ok(exists("li.notification.edited .icon-avatar"));
|
||||
assert.ok(exists("li.notification.replied .icon-avatar"));
|
||||
});
|
||||
|
||||
test("It shows user avatars for messages", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
await click("#user-menu-button-messages");
|
||||
|
||||
assert.ok(exists("li.notification.private-message .icon-avatar"));
|
||||
|
@ -1141,7 +1146,7 @@ acceptance("User menu - avatars", function (needs) {
|
|||
|
||||
test("It shows user avatars for bookmark items and bookmark reminder notification items", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
await click("#user-menu-button-bookmarks");
|
||||
|
||||
assert.ok(exists("li.notification.bookmark-reminder .icon-avatar"));
|
||||
|
@ -1150,7 +1155,7 @@ acceptance("User menu - avatars", function (needs) {
|
|||
|
||||
test("Icon avatars have correct class names based on system avatar usage", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
await click(".d-header-icons .current-user button");
|
||||
assert.ok(exists("li.group-message-summary .icon-avatar.system-avatar"));
|
||||
assert.ok(exists("li.notification.replied .icon-avatar.user-avatar"));
|
||||
});
|
||||
|
|
|
@ -9,7 +9,7 @@ import {
|
|||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
|
||||
async function openUserStatusModal() {
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
await click(".header-dropdown-toggle.current-user button");
|
||||
await click("#user-menu-button-profile");
|
||||
await click(".set-user-status button");
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ acceptance("User Status", function (needs) {
|
|||
});
|
||||
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
await click(".header-dropdown-toggle.current-user button");
|
||||
await click("#user-menu-button-profile");
|
||||
|
||||
assert.equal(
|
||||
|
@ -155,7 +155,7 @@ acceptance("User Status", function (needs) {
|
|||
"shows user status emoji on the user avatar in the header"
|
||||
);
|
||||
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
await click(".header-dropdown-toggle.current-user button");
|
||||
await click("#user-menu-button-profile");
|
||||
assert.equal(
|
||||
query(
|
||||
|
@ -184,7 +184,7 @@ acceptance("User Status", function (needs) {
|
|||
await pickEmoji(userStatusEmoji);
|
||||
await click(".btn-primary"); // save
|
||||
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
await click(".header-dropdown-toggle.current-user button");
|
||||
await click("#user-menu-button-profile");
|
||||
assert.equal(
|
||||
query(
|
||||
|
@ -222,7 +222,7 @@ acceptance("User Status", function (needs) {
|
|||
await click("#tap_tile_one_hour");
|
||||
await click(".btn-primary"); // save
|
||||
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
await click(".header-dropdown-toggle.current-user button");
|
||||
await click("#user-menu-button-profile");
|
||||
|
||||
assert.equal(
|
||||
|
@ -476,7 +476,7 @@ acceptance("User Status - user menu", function (needs) {
|
|||
this.siteSettings.enable_user_status = false;
|
||||
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
await click(".header-dropdown-toggle.current-user button");
|
||||
await click("#user-menu-button-profile");
|
||||
|
||||
assert.notOk(exists("li.set-user-status"));
|
||||
|
@ -486,7 +486,7 @@ acceptance("User Status - user menu", function (needs) {
|
|||
this.siteSettings.enable_user_status = true;
|
||||
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
await click(".header-dropdown-toggle.current-user button");
|
||||
await click("#user-menu-button-profile");
|
||||
|
||||
assert.ok(exists("li.set-user-status .btn"), "shows the button");
|
||||
|
@ -503,7 +503,7 @@ acceptance("User Status - user menu", function (needs) {
|
|||
});
|
||||
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
await click(".header-dropdown-toggle.current-user button");
|
||||
await click("#user-menu-button-profile");
|
||||
|
||||
assert.equal(
|
||||
|
@ -529,7 +529,7 @@ acceptance("User Status - user menu", function (needs) {
|
|||
this.siteSettings.enable_user_status = true;
|
||||
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
await click(".header-dropdown-toggle.current-user button");
|
||||
await click("#user-menu-button-profile");
|
||||
await click(".set-user-status button");
|
||||
|
||||
|
|
|
@ -98,13 +98,14 @@ export function performEmojiUnescape(string, opts) {
|
|||
isReplaceableInlineEmoji(string, index, opts.inlineEmoji);
|
||||
|
||||
const title = opts.title ?? emojiVal;
|
||||
const alt = opts.alt ?? opts.title ?? emojiVal;
|
||||
const tabIndex = opts.tabIndex ? ` tabindex='${opts.tabIndex}'` : "";
|
||||
return url && isReplacable
|
||||
? `<img width="20" height="20" src='${url}' ${
|
||||
opts.skipTitle ? "" : `title='${title}'`
|
||||
} ${
|
||||
opts.lazy ? "loading='lazy' " : ""
|
||||
}alt='${title}' class='${classes}'${tabIndex}>`
|
||||
}alt='${alt}' class='${classes}'${tabIndex}>`
|
||||
: m;
|
||||
};
|
||||
|
||||
|
|
|
@ -1823,10 +1823,6 @@ class User < ActiveRecord::Base
|
|||
in_any_groups?(SiteSetting.experimental_new_new_view_groups_map)
|
||||
end
|
||||
|
||||
def glimmer_header_enabled?
|
||||
in_any_groups?(SiteSetting.experimental_glimmer_header_groups_map)
|
||||
end
|
||||
|
||||
def watched_precedence_over_muted
|
||||
if user_option.watched_precedence_over_muted.nil?
|
||||
SiteSetting.watched_precedence_over_muted
|
||||
|
|
|
@ -74,7 +74,6 @@ class CurrentUserSerializer < BasicUserSerializer
|
|||
:new_new_view_enabled?,
|
||||
:use_experimental_topic_bulk_actions?,
|
||||
:use_admin_sidebar,
|
||||
:glimmer_header_enabled?,
|
||||
:can_view_raw_email
|
||||
|
||||
delegate :user_stat, to: :object, private: true
|
||||
|
|
|
@ -2620,7 +2620,7 @@ en:
|
|||
experimental_topics_filter: "EXPERIMENTAL: Enables the experimental topics filter route at /filter"
|
||||
enable_experimental_lightbox: "EXPERIMENTAL: Replace the default image lightbox with the revamped design."
|
||||
enable_experimental_bookmark_redesign_groups: "EXPERIMENTAL: Show a quick access menu for bookmarks on posts and a new redesigned modal"
|
||||
experimental_glimmer_header_groups: "EXPERIMENTAL: Render the site header as glimmer components."
|
||||
glimmer_header_mode: "Control whether the new 'glimmer' header implementation is used. Defaults to 'auto', which will enable automatically once all your themes and plugins are ready. https://meta.discourse.org/t/296544"
|
||||
experimental_form_templates: "EXPERIMENTAL: Enable the form templates feature. <b>After enabled,</b> manage the templates at <a href='%{base_path}/admin/customize/form-templates'>Customize / Templates</a>."
|
||||
admin_sidebar_enabled_groups: "EXPERIMENTAL: Enable sidebar navigation for the admin UI for the specified groups, which replaces the top-level admin navigation buttons."
|
||||
lazy_load_categories_groups: "EXPERIMENTAL: Lazy load category information only for users of these groups. This improves performance on sites with many categories."
|
||||
|
|
|
@ -2352,12 +2352,14 @@ developer:
|
|||
instrument_gc_stat_per_request:
|
||||
default: false
|
||||
hidden: true
|
||||
experimental_glimmer_header_groups:
|
||||
glimmer_header_mode:
|
||||
client: true
|
||||
type: group_list
|
||||
list_type: compact
|
||||
default: ""
|
||||
allow_any: false
|
||||
type: enum
|
||||
choices:
|
||||
- disabled
|
||||
- auto
|
||||
- enabled
|
||||
default: auto
|
||||
admin_sidebar_enabled_groups:
|
||||
type: group_list
|
||||
list_type: compact
|
||||
|
|
|
@ -5,7 +5,7 @@ RSpec.describe "Glimmer Header", type: :system do
|
|||
let(:search) { PageObjects::Pages::Search.new }
|
||||
fab!(:current_user) { Fabricate(:user) }
|
||||
fab!(:topic)
|
||||
before { SiteSetting.experimental_glimmer_header_groups = Group::AUTO_GROUPS[:everyone] }
|
||||
before { SiteSetting.glimmer_header_mode = "enabled" }
|
||||
|
||||
it "renders basics" do
|
||||
visit "/"
|
||||
|
|
Loading…
Reference in New Issue