FEATURE: "Hot" replacing "Top" as default in the top menu (#28252)

This change only applies to instances that have not modified the
`top_menu` site setting.
This commit is contained in:
Penar Musaraj 2024-08-08 13:57:42 -04:00 committed by GitHub
parent 5b1d9d602f
commit 7c5e3eacda
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 88 additions and 34 deletions

View File

@ -16,6 +16,7 @@ import { AUTO_DELETE_PREFERENCES } from "discourse/models/bookmark";
import discourseComputed from "discourse-common/utils/decorators";
import I18n from "discourse-i18n";
// same as UserOption::HOMEPAGES
const USER_HOMES = {
1: "latest",
2: "categories",
@ -24,6 +25,7 @@ const USER_HOMES = {
5: "top",
6: "bookmarks",
7: "unseen",
8: "hot",
};
const TEXT_SIZES = ["smallest", "smaller", "normal", "larger", "largest"];
@ -44,10 +46,6 @@ export default Controller.extend({
this._super(...arguments);
this.set("selectedDarkColorSchemeId", this.session.userDarkSchemeId);
if (this.siteSettings.top_menu.split("|").includes("hot")) {
USER_HOMES[8] = "hot";
}
},
@discourseComputed("makeThemeDefault")
@ -213,12 +211,20 @@ export default Controller.extend({
});
}
this.siteSettings.top_menu.split("|").forEach((m) => {
const availableIds = this.siteSettings.top_menu.split("|");
const userHome = USER_HOMES[this.get("model.user_option.homepage_id")];
if (userHome && !availableIds.includes(userHome)) {
availableIds.push(USER_HOMES[this.homepageId]);
}
availableIds.forEach((m) => {
let id = homeValues[m];
if (id) {
result.push({ name: I18n.t(`filters.${m}.title`), value: Number(id) });
}
});
return result;
},

View File

@ -2,19 +2,27 @@ import { click, visit } from "@ember/test-helpers";
import { test } from "qunit";
import Sinon from "sinon";
import DiscourseURL from "discourse/lib/url";
import discoveryFixtures from "discourse/tests/fixtures/discovery-fixtures";
import {
acceptance,
publishToMessageBus,
} from "discourse/tests/helpers/qunit-helpers";
import { cloneJSON } from "discourse-common/lib/object";
acceptance("Software update refresh", function (needs) {
needs.user();
needs.pretender((server, helper) => {
server.get("/hot.json", () => {
return helper.response(cloneJSON(discoveryFixtures["/latest.json"]));
});
});
test("Refreshes page on next navigation", async function (assert) {
const redirectStub = Sinon.stub(DiscourseURL, "redirectTo");
await visit("/");
await click(".nav-item_top a");
await click(".nav-item_hot a");
assert.true(
redirectStub.notCalled,
"redirect was not triggered by default"
@ -24,16 +32,16 @@ acceptance("Software update refresh", function (needs) {
redirectStub.resetHistory();
await visit("/");
await click(".nav-item_top a");
await click(".nav-item_hot a");
assert.true(
redirectStub.calledWith("/top"),
redirectStub.calledWith("/hot"),
"redirect was triggered after asset change"
);
redirectStub.resetHistory();
await visit("/");
await click("#create-topic");
await click(".nav-item_top a");
await click(".nav-item_hot a");
assert.true(
redirectStub.notCalled,
"redirect is not triggered while composer is open"
@ -42,9 +50,9 @@ acceptance("Software update refresh", function (needs) {
redirectStub.resetHistory();
await visit("/");
await click(".save-or-cancel .cancel");
await click(".nav-item_top a");
await click(".nav-item_hot a");
assert.true(
redirectStub.calledWith("/top"),
redirectStub.calledWith("/hot"),
"redirect is triggered on next navigation after composer closed"
);
});

View File

@ -285,7 +285,7 @@ acceptance("Tag info", function (needs) {
[
"/tags/c/faq/4/planters/l/latest.json",
"/tags/c/feature/2/planters/l/latest.json",
"/tags/c/feature/2/planters/l/top.json",
"/tags/c/feature/2/planters/l/hot.json",
"/tags/c/feature/2/none/planters/l/latest.json",
].forEach((url) => {
server.get(url, () => {
@ -565,8 +565,8 @@ acceptance("Tag info", function (needs) {
await click(".nav-item_latest a[href]");
assert.strictEqual(currentURL(), "/tags/c/feature/2/planters/l/latest");
await click(".nav-item_top a[href]");
assert.strictEqual(currentURL(), "/tags/c/feature/2/planters/l/top");
await click(".nav-item_hot a[href]");
assert.strictEqual(currentURL(), "/tags/c/feature/2/planters/l/hot");
});
test("admin can manage tags", async function (assert) {

View File

@ -3,6 +3,7 @@ import { skip, test } from "qunit";
import { configureEyeline } from "discourse/lib/eyeline";
import { ScrollingDOMMethods } from "discourse/mixins/scrolling";
import discoveryFixtures from "discourse/tests/fixtures/discovery-fixtures";
import topFixtures from "discourse/tests/fixtures/top-fixtures";
import {
acceptance,
exists,
@ -17,6 +18,12 @@ acceptance("Topic Discovery", function (needs) {
show_pinned_excerpt_desktop: true,
});
needs.pretender((server, helper) => {
server.get("/hot.json", () => {
return helper.response(cloneJSON(topFixtures["/top.json"]));
});
});
test("Visit Discovery Pages", async function (assert) {
await visit("/");
assert.ok(
@ -143,13 +150,13 @@ acceptance("Topic Discovery", function (needs) {
"shows the correct latest topics"
);
await click(".navigation-container a[href='/top']");
assert.strictEqual(currentURL(), "/top", "switches to top");
await click(".navigation-container a[href='/hot']");
assert.strictEqual(currentURL(), "/hot", "switches to hot");
assert.deepEqual(
query(".topic-list-body .topic-list-item:first-of-type").dataset.topicId,
"13088",
"shows the correct top topics"
"shows the correct hot topics"
);
await click(".navigation-container a[href='/categories']");

View File

@ -94,8 +94,8 @@ acceptance("Topic Discovery Tracked", function (needs) {
);
assert.ok(
query("#navigation-bar li.top a").href.endsWith("/top?f=tracked"),
"top link has tracked filter"
query("#navigation-bar li.hot a").href.endsWith("/hot?f=tracked"),
"hot link has tracked filter"
);
assert.ok(

View File

@ -41,6 +41,7 @@ export default {
"posted",
"search",
"bookmarks",
"hot",
],
periods: ["all", "yearly", "quarterly", "monthly", "weekly", "daily"],
top_menu_items: [
@ -51,10 +52,10 @@ export default {
"read",
"posted",
"categories",
"top",
"hot",
"bookmarks",
],
anonymous_top_menu_items: ["latest", "top", "categories"],
anonymous_top_menu_items: ["latest", "hot", "categories"],
uncategorized_category_id: 17,
is_readonly: false,
categories: [

View File

@ -54,9 +54,9 @@ PreloadStore.store("site", {
"read",
"posted",
"categories",
"top",
"hot",
],
anonymous_top_menu_items: ["latest", "categories", "top"],
anonymous_top_menu_items: ["latest", "categories", "hot"],
uncategorized_category_id: 17,
categories: [
{

View File

@ -10,7 +10,7 @@ class UserOption < ActiveRecord::Base
5 => "top",
6 => "bookmarks",
7 => "unseen",
# 8 => reserved for "hot"
8 => "hot",
}
self.ignored_columns = [

View File

@ -1881,7 +1881,7 @@ en:
max_reply_history: "Maximum number of replies to expand when expanding in-reply-to"
topics_per_period_in_top_summary: "Number of top topics shown in the default top topics summary."
topics_per_period_in_top_page: "Number of top topics shown on the expanded 'Show More' top topics."
redirect_users_to_top_page: "Automatically redirect new and long absent users to the top page."
redirect_users_to_top_page: "Automatically redirect new and long absent users to the top page. Only applies when 'top' is present in the 'top menu' site setting."
top_page_default_timeframe: "Default top page time period for anonymous users (automatically adjusts for logged in users based on their last visit)."
moderators_view_emails: "Allow moderators to view user email addresses."
prioritize_username_in_ux: "Show username first on user page, user card and posts (when disabled name is shown first)"

View File

@ -190,7 +190,7 @@ basic:
refresh: true
type: list
list_type: simple
default: "latest|new|unread|top|categories"
default: "latest|new|unread|hot|categories"
regex: "latest"
regex_error: "site_settings.errors.must_include_latest"
validator: RegexPresenceValidator

View File

@ -29,7 +29,7 @@ describe "Homepage", type: :system do
homepage_picker = PageObjects::Components::SelectKit.new("#home-selector")
homepage_picker.expand
homepage_picker.select_row_by_name("Top")
homepage_picker.select_row_by_name("Hot")
page.find(".btn-primary.save-changes").click
# Wait for the save to complete
@ -37,8 +37,7 @@ describe "Homepage", type: :system do
visit "/"
expect(page).to have_css(".navigation-container .top.active", text: "Top")
expect(page).to have_css(".top-lists")
expect(page).to have_css(".navigation-container .hot.active", text: "Hot")
end
it "defaults to first top_menu item as anonymous homepage" do
@ -86,16 +85,15 @@ describe "Homepage", type: :system do
homepage_picker = PageObjects::Components::SelectKit.new("#home-selector")
homepage_picker.expand
# user overrides theme custom homepage
homepage_picker.select_row_by_name("Top")
homepage_picker.select_row_by_name("Hot")
page.find(".btn-primary.save-changes").click
# Wait for the save to complete
find(".btn-primary.save-changes:not([disabled])", wait: 5)
expect(user.user_option.homepage_id).to eq(UserOption::HOMEPAGES.key("top"))
expect(user.user_option.homepage_id).to eq(UserOption::HOMEPAGES.key("hot"))
click_logo
expect(page).to have_css(".navigation-container .top.active", text: "Top")
expect(page).to have_css(".top-lists")
expect(page).to have_css(".navigation-container .hot.active", text: "Hot")
visit "/u/#{user.username}/preferences/interface"
@ -107,7 +105,7 @@ describe "Homepage", type: :system do
# Wait for the save to complete
find(".btn-primary.save-changes:not([disabled])", wait: 5)
expect(user.reload.user_option.homepage_id).to_not eq(UserOption::HOMEPAGES.key("top"))
expect(user.reload.user_option.homepage_id).to_not eq(UserOption::HOMEPAGES.key("hot"))
click_logo

View File

@ -70,6 +70,10 @@ module PageObjects
component.find(".select-kit-collection li[data-value='#{value}']")
end
def has_no_option_value?(value)
component.has_no_css?(".select-kit-collection li[data-value='#{value}']")
end
def expand
collapsed_component.find(":not(.is-expanded) .select-kit-header", visible: :all).click
expanded_component

View File

@ -31,4 +31,34 @@ describe "User preferences | Interface", type: :system do
end
end
end
describe "Default Home Page" do
context "when a user has picked a home page that is no longer available in top_menu" do
it "shows the selected homepage" do
SiteSetting.top_menu = "latest|hot"
user.user_option.update!(homepage_id: UserOption::HOMEPAGES.key("unread"))
user_preferences_page.visit(user)
click_link(I18n.t("js.user.preferences_nav.interface"))
dropdown = PageObjects::Components::SelectKit.new("#home-selector")
expect(dropdown).to have_selected_name("Unread")
end
end
it "shows only the available home pages from top_menu" do
SiteSetting.top_menu = "latest|hot"
user_preferences_page.visit(user)
click_link(I18n.t("js.user.preferences_nav.interface"))
dropdown = PageObjects::Components::SelectKit.new("#home-selector")
dropdown.expand
expect(dropdown).to have_option_value(UserOption::HOMEPAGES.key("latest"))
expect(dropdown).to have_option_value(UserOption::HOMEPAGES.key("hot"))
expect(dropdown).to have_no_option_value(UserOption::HOMEPAGES.key("top"))
expect(dropdown).to have_no_option_value(UserOption::HOMEPAGES.key("new"))
end
end
end