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:
parent
5b1d9d602f
commit
7c5e3eacda
|
@ -16,6 +16,7 @@ import { AUTO_DELETE_PREFERENCES } from "discourse/models/bookmark";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import I18n from "discourse-i18n";
|
import I18n from "discourse-i18n";
|
||||||
|
|
||||||
|
// same as UserOption::HOMEPAGES
|
||||||
const USER_HOMES = {
|
const USER_HOMES = {
|
||||||
1: "latest",
|
1: "latest",
|
||||||
2: "categories",
|
2: "categories",
|
||||||
|
@ -24,6 +25,7 @@ const USER_HOMES = {
|
||||||
5: "top",
|
5: "top",
|
||||||
6: "bookmarks",
|
6: "bookmarks",
|
||||||
7: "unseen",
|
7: "unseen",
|
||||||
|
8: "hot",
|
||||||
};
|
};
|
||||||
|
|
||||||
const TEXT_SIZES = ["smallest", "smaller", "normal", "larger", "largest"];
|
const TEXT_SIZES = ["smallest", "smaller", "normal", "larger", "largest"];
|
||||||
|
@ -44,10 +46,6 @@ export default Controller.extend({
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
|
||||||
this.set("selectedDarkColorSchemeId", this.session.userDarkSchemeId);
|
this.set("selectedDarkColorSchemeId", this.session.userDarkSchemeId);
|
||||||
|
|
||||||
if (this.siteSettings.top_menu.split("|").includes("hot")) {
|
|
||||||
USER_HOMES[8] = "hot";
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
@discourseComputed("makeThemeDefault")
|
@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];
|
let id = homeValues[m];
|
||||||
if (id) {
|
if (id) {
|
||||||
result.push({ name: I18n.t(`filters.${m}.title`), value: Number(id) });
|
result.push({ name: I18n.t(`filters.${m}.title`), value: Number(id) });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -2,19 +2,27 @@ import { click, visit } from "@ember/test-helpers";
|
||||||
import { test } from "qunit";
|
import { test } from "qunit";
|
||||||
import Sinon from "sinon";
|
import Sinon from "sinon";
|
||||||
import DiscourseURL from "discourse/lib/url";
|
import DiscourseURL from "discourse/lib/url";
|
||||||
|
import discoveryFixtures from "discourse/tests/fixtures/discovery-fixtures";
|
||||||
import {
|
import {
|
||||||
acceptance,
|
acceptance,
|
||||||
publishToMessageBus,
|
publishToMessageBus,
|
||||||
} from "discourse/tests/helpers/qunit-helpers";
|
} from "discourse/tests/helpers/qunit-helpers";
|
||||||
|
import { cloneJSON } from "discourse-common/lib/object";
|
||||||
|
|
||||||
acceptance("Software update refresh", function (needs) {
|
acceptance("Software update refresh", function (needs) {
|
||||||
needs.user();
|
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) {
|
test("Refreshes page on next navigation", async function (assert) {
|
||||||
const redirectStub = Sinon.stub(DiscourseURL, "redirectTo");
|
const redirectStub = Sinon.stub(DiscourseURL, "redirectTo");
|
||||||
|
|
||||||
await visit("/");
|
await visit("/");
|
||||||
await click(".nav-item_top a");
|
await click(".nav-item_hot a");
|
||||||
assert.true(
|
assert.true(
|
||||||
redirectStub.notCalled,
|
redirectStub.notCalled,
|
||||||
"redirect was not triggered by default"
|
"redirect was not triggered by default"
|
||||||
|
@ -24,16 +32,16 @@ acceptance("Software update refresh", function (needs) {
|
||||||
|
|
||||||
redirectStub.resetHistory();
|
redirectStub.resetHistory();
|
||||||
await visit("/");
|
await visit("/");
|
||||||
await click(".nav-item_top a");
|
await click(".nav-item_hot a");
|
||||||
assert.true(
|
assert.true(
|
||||||
redirectStub.calledWith("/top"),
|
redirectStub.calledWith("/hot"),
|
||||||
"redirect was triggered after asset change"
|
"redirect was triggered after asset change"
|
||||||
);
|
);
|
||||||
|
|
||||||
redirectStub.resetHistory();
|
redirectStub.resetHistory();
|
||||||
await visit("/");
|
await visit("/");
|
||||||
await click("#create-topic");
|
await click("#create-topic");
|
||||||
await click(".nav-item_top a");
|
await click(".nav-item_hot a");
|
||||||
assert.true(
|
assert.true(
|
||||||
redirectStub.notCalled,
|
redirectStub.notCalled,
|
||||||
"redirect is not triggered while composer is open"
|
"redirect is not triggered while composer is open"
|
||||||
|
@ -42,9 +50,9 @@ acceptance("Software update refresh", function (needs) {
|
||||||
redirectStub.resetHistory();
|
redirectStub.resetHistory();
|
||||||
await visit("/");
|
await visit("/");
|
||||||
await click(".save-or-cancel .cancel");
|
await click(".save-or-cancel .cancel");
|
||||||
await click(".nav-item_top a");
|
await click(".nav-item_hot a");
|
||||||
assert.true(
|
assert.true(
|
||||||
redirectStub.calledWith("/top"),
|
redirectStub.calledWith("/hot"),
|
||||||
"redirect is triggered on next navigation after composer closed"
|
"redirect is triggered on next navigation after composer closed"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -285,7 +285,7 @@ acceptance("Tag info", function (needs) {
|
||||||
[
|
[
|
||||||
"/tags/c/faq/4/planters/l/latest.json",
|
"/tags/c/faq/4/planters/l/latest.json",
|
||||||
"/tags/c/feature/2/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",
|
"/tags/c/feature/2/none/planters/l/latest.json",
|
||||||
].forEach((url) => {
|
].forEach((url) => {
|
||||||
server.get(url, () => {
|
server.get(url, () => {
|
||||||
|
@ -565,8 +565,8 @@ acceptance("Tag info", function (needs) {
|
||||||
await click(".nav-item_latest a[href]");
|
await click(".nav-item_latest a[href]");
|
||||||
assert.strictEqual(currentURL(), "/tags/c/feature/2/planters/l/latest");
|
assert.strictEqual(currentURL(), "/tags/c/feature/2/planters/l/latest");
|
||||||
|
|
||||||
await click(".nav-item_top a[href]");
|
await click(".nav-item_hot a[href]");
|
||||||
assert.strictEqual(currentURL(), "/tags/c/feature/2/planters/l/top");
|
assert.strictEqual(currentURL(), "/tags/c/feature/2/planters/l/hot");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("admin can manage tags", async function (assert) {
|
test("admin can manage tags", async function (assert) {
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { skip, test } from "qunit";
|
||||||
import { configureEyeline } from "discourse/lib/eyeline";
|
import { configureEyeline } from "discourse/lib/eyeline";
|
||||||
import { ScrollingDOMMethods } from "discourse/mixins/scrolling";
|
import { ScrollingDOMMethods } from "discourse/mixins/scrolling";
|
||||||
import discoveryFixtures from "discourse/tests/fixtures/discovery-fixtures";
|
import discoveryFixtures from "discourse/tests/fixtures/discovery-fixtures";
|
||||||
|
import topFixtures from "discourse/tests/fixtures/top-fixtures";
|
||||||
import {
|
import {
|
||||||
acceptance,
|
acceptance,
|
||||||
exists,
|
exists,
|
||||||
|
@ -17,6 +18,12 @@ acceptance("Topic Discovery", function (needs) {
|
||||||
show_pinned_excerpt_desktop: true,
|
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) {
|
test("Visit Discovery Pages", async function (assert) {
|
||||||
await visit("/");
|
await visit("/");
|
||||||
assert.ok(
|
assert.ok(
|
||||||
|
@ -143,13 +150,13 @@ acceptance("Topic Discovery", function (needs) {
|
||||||
"shows the correct latest topics"
|
"shows the correct latest topics"
|
||||||
);
|
);
|
||||||
|
|
||||||
await click(".navigation-container a[href='/top']");
|
await click(".navigation-container a[href='/hot']");
|
||||||
assert.strictEqual(currentURL(), "/top", "switches to top");
|
assert.strictEqual(currentURL(), "/hot", "switches to hot");
|
||||||
|
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
query(".topic-list-body .topic-list-item:first-of-type").dataset.topicId,
|
query(".topic-list-body .topic-list-item:first-of-type").dataset.topicId,
|
||||||
"13088",
|
"13088",
|
||||||
"shows the correct top topics"
|
"shows the correct hot topics"
|
||||||
);
|
);
|
||||||
|
|
||||||
await click(".navigation-container a[href='/categories']");
|
await click(".navigation-container a[href='/categories']");
|
||||||
|
|
|
@ -94,8 +94,8 @@ acceptance("Topic Discovery Tracked", function (needs) {
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.ok(
|
assert.ok(
|
||||||
query("#navigation-bar li.top a").href.endsWith("/top?f=tracked"),
|
query("#navigation-bar li.hot a").href.endsWith("/hot?f=tracked"),
|
||||||
"top link has tracked filter"
|
"hot link has tracked filter"
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.ok(
|
assert.ok(
|
||||||
|
|
|
@ -41,6 +41,7 @@ export default {
|
||||||
"posted",
|
"posted",
|
||||||
"search",
|
"search",
|
||||||
"bookmarks",
|
"bookmarks",
|
||||||
|
"hot",
|
||||||
],
|
],
|
||||||
periods: ["all", "yearly", "quarterly", "monthly", "weekly", "daily"],
|
periods: ["all", "yearly", "quarterly", "monthly", "weekly", "daily"],
|
||||||
top_menu_items: [
|
top_menu_items: [
|
||||||
|
@ -51,10 +52,10 @@ export default {
|
||||||
"read",
|
"read",
|
||||||
"posted",
|
"posted",
|
||||||
"categories",
|
"categories",
|
||||||
"top",
|
"hot",
|
||||||
"bookmarks",
|
"bookmarks",
|
||||||
],
|
],
|
||||||
anonymous_top_menu_items: ["latest", "top", "categories"],
|
anonymous_top_menu_items: ["latest", "hot", "categories"],
|
||||||
uncategorized_category_id: 17,
|
uncategorized_category_id: 17,
|
||||||
is_readonly: false,
|
is_readonly: false,
|
||||||
categories: [
|
categories: [
|
||||||
|
|
|
@ -54,9 +54,9 @@ PreloadStore.store("site", {
|
||||||
"read",
|
"read",
|
||||||
"posted",
|
"posted",
|
||||||
"categories",
|
"categories",
|
||||||
"top",
|
"hot",
|
||||||
],
|
],
|
||||||
anonymous_top_menu_items: ["latest", "categories", "top"],
|
anonymous_top_menu_items: ["latest", "categories", "hot"],
|
||||||
uncategorized_category_id: 17,
|
uncategorized_category_id: 17,
|
||||||
categories: [
|
categories: [
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,7 +10,7 @@ class UserOption < ActiveRecord::Base
|
||||||
5 => "top",
|
5 => "top",
|
||||||
6 => "bookmarks",
|
6 => "bookmarks",
|
||||||
7 => "unseen",
|
7 => "unseen",
|
||||||
# 8 => reserved for "hot"
|
8 => "hot",
|
||||||
}
|
}
|
||||||
|
|
||||||
self.ignored_columns = [
|
self.ignored_columns = [
|
||||||
|
|
|
@ -1881,7 +1881,7 @@ en:
|
||||||
max_reply_history: "Maximum number of replies to expand when expanding in-reply-to"
|
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_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."
|
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)."
|
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."
|
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)"
|
prioritize_username_in_ux: "Show username first on user page, user card and posts (when disabled name is shown first)"
|
||||||
|
|
|
@ -190,7 +190,7 @@ basic:
|
||||||
refresh: true
|
refresh: true
|
||||||
type: list
|
type: list
|
||||||
list_type: simple
|
list_type: simple
|
||||||
default: "latest|new|unread|top|categories"
|
default: "latest|new|unread|hot|categories"
|
||||||
regex: "latest"
|
regex: "latest"
|
||||||
regex_error: "site_settings.errors.must_include_latest"
|
regex_error: "site_settings.errors.must_include_latest"
|
||||||
validator: RegexPresenceValidator
|
validator: RegexPresenceValidator
|
||||||
|
|
|
@ -29,7 +29,7 @@ describe "Homepage", type: :system do
|
||||||
|
|
||||||
homepage_picker = PageObjects::Components::SelectKit.new("#home-selector")
|
homepage_picker = PageObjects::Components::SelectKit.new("#home-selector")
|
||||||
homepage_picker.expand
|
homepage_picker.expand
|
||||||
homepage_picker.select_row_by_name("Top")
|
homepage_picker.select_row_by_name("Hot")
|
||||||
page.find(".btn-primary.save-changes").click
|
page.find(".btn-primary.save-changes").click
|
||||||
|
|
||||||
# Wait for the save to complete
|
# Wait for the save to complete
|
||||||
|
@ -37,8 +37,7 @@ describe "Homepage", type: :system do
|
||||||
|
|
||||||
visit "/"
|
visit "/"
|
||||||
|
|
||||||
expect(page).to have_css(".navigation-container .top.active", text: "Top")
|
expect(page).to have_css(".navigation-container .hot.active", text: "Hot")
|
||||||
expect(page).to have_css(".top-lists")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "defaults to first top_menu item as anonymous homepage" do
|
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 = PageObjects::Components::SelectKit.new("#home-selector")
|
||||||
homepage_picker.expand
|
homepage_picker.expand
|
||||||
# user overrides theme custom homepage
|
# 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
|
page.find(".btn-primary.save-changes").click
|
||||||
|
|
||||||
# Wait for the save to complete
|
# Wait for the save to complete
|
||||||
find(".btn-primary.save-changes:not([disabled])", wait: 5)
|
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
|
click_logo
|
||||||
expect(page).to have_css(".navigation-container .top.active", text: "Top")
|
expect(page).to have_css(".navigation-container .hot.active", text: "Hot")
|
||||||
expect(page).to have_css(".top-lists")
|
|
||||||
|
|
||||||
visit "/u/#{user.username}/preferences/interface"
|
visit "/u/#{user.username}/preferences/interface"
|
||||||
|
|
||||||
|
@ -107,7 +105,7 @@ describe "Homepage", type: :system do
|
||||||
|
|
||||||
# Wait for the save to complete
|
# Wait for the save to complete
|
||||||
find(".btn-primary.save-changes:not([disabled])", wait: 5)
|
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
|
click_logo
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,10 @@ module PageObjects
|
||||||
component.find(".select-kit-collection li[data-value='#{value}']")
|
component.find(".select-kit-collection li[data-value='#{value}']")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def has_no_option_value?(value)
|
||||||
|
component.has_no_css?(".select-kit-collection li[data-value='#{value}']")
|
||||||
|
end
|
||||||
|
|
||||||
def expand
|
def expand
|
||||||
collapsed_component.find(":not(.is-expanded) .select-kit-header", visible: :all).click
|
collapsed_component.find(":not(.is-expanded) .select-kit-header", visible: :all).click
|
||||||
expanded_component
|
expanded_component
|
||||||
|
|
|
@ -31,4 +31,34 @@ describe "User preferences | Interface", type: :system do
|
||||||
end
|
end
|
||||||
end
|
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
|
end
|
||||||
|
|
Loading…
Reference in New Issue