FEATURE: add period filter in top topics route for tags. (#13415)

And also move all the "top topics by period" routes to query string param.

/top/monthly => /top?period=monthly
/c/:slug/:id/l/top/monthly => /c/:slug/:id/l/top?period=monthly
/tag/:slug/l/top/daily => /tag/:slug/l/top?period=daily (new)
This commit is contained in:
Vinoth Kannan
2021-07-06 15:25:11 +05:30
committed by GitHub
parent 34387c5a38
commit 33eae4cbd8
24 changed files with 127 additions and 137 deletions
@@ -13,6 +13,7 @@ export const queryParams = {
before: { replace: true, refreshModel: true },
bumped_before: { replace: true, refreshModel: true },
f: { replace: true, refreshModel: true },
period: { replace: true, refreshModel: true },
};
// Basic controller options
@@ -37,9 +37,10 @@ export default Controller.extend({
}/l`;
}
url += "/top/" + period;
url += "/top";
const queryParams = this.router.currentRoute.queryParams;
let queryParams = this.router.currentRoute.queryParams;
queryParams.period = period;
if (Object.keys(queryParams).length) {
url =
`${url}?` +
@@ -1,12 +1,4 @@
import {
alias,
empty,
equal,
gt,
not,
notEmpty,
readOnly,
} from "@ember/object/computed";
import { alias, empty, equal, gt, not, readOnly } from "@ember/object/computed";
import BulkTopicSelection from "discourse/mixins/bulk-topic-selection";
import DiscoveryController from "discourse/controllers/discovery";
import I18n from "I18n";
@@ -140,7 +132,7 @@ const controllerOpts = {
allLoaded: empty("model.more_topics_url"),
latest: endWith("model.filter", "latest"),
new: endWith("model.filter", "new"),
top: notEmpty("period"),
top: endWith("model.filter", "top"),
yearly: equal("period", "yearly"),
quarterly: equal("period", "quarterly"),
monthly: equal("period", "monthly"),
@@ -8,6 +8,7 @@ import Topic from "discourse/models/topic";
import { alias } from "@ember/object/computed";
import bootbox from "bootbox";
import { queryParams } from "discourse/controllers/discovery-sortable";
import { endWith } from "discourse/lib/computed";
export default Controller.extend(BulkTopicSelection, FilterModeMixin, {
application: controller(),
@@ -27,6 +28,8 @@ export default Controller.extend(BulkTopicSelection, FilterModeMixin, {
max_posts: null,
q: null,
showInfo: false,
top: endWith("list.filter", "top"),
period: alias("list.for_period"),
@discourseComputed(
"canCreateTopic",
@@ -131,8 +134,30 @@ export default Controller.extend(BulkTopicSelection, FilterModeMixin, {
this.setProperties({ order, ascending: false });
}
let params = { order, ascending: this.ascending };
if (this.period) {
params.period = this.period;
}
this.transitionToRoute({
queryParams: { order, ascending: this.ascending },
queryParams: params,
});
},
changePeriod(p) {
this.set("period", p);
let params = { period: this.period };
if (!(this.order === "default" && this.ascending === false)) {
params = Object.assign(params, {
order: this.order,
ascending: this.ascending,
});
}
this.transitionToRoute({
queryParams: params,
});
},
@@ -36,13 +36,7 @@ export default Mixin.create({
set(key, value) {
this.set("rawFilterMode", value);
const parts = value.split("/");
if (parts.length >= 2 && parts[parts.length - 2] === "top") {
this.set("filterType", "top");
} else {
this.set("filterType", parts.pop());
}
this.set("filterType", value.split("/").pop());
return value;
},
@@ -34,7 +34,18 @@ export default {
app[
`Discovery${filterCapitalized}CategoryNoneController`
] = DiscoverySortableController.extend();
if (filter !== "top") {
if (filter === "top") {
app.DiscoveryTopRoute = buildTopicRoute("top", {
actions: {
willTransition() {
User.currentProp("should_be_redirected_to_top", false);
User.currentProp("redirected_to_top.reason", null);
return this._super(...arguments);
},
},
});
} else {
app[`Discovery${filterCapitalized}Route`] = buildTopicRoute(filter);
}
@@ -46,38 +57,6 @@ export default {
] = buildCategoryRoute(filter, { no_subcategories: true });
});
app.DiscoveryTopRoute = buildTopicRoute("top", {
actions: {
willTransition() {
User.currentProp("should_be_redirected_to_top", false);
User.currentProp("redirected_to_top.reason", null);
return this._super(...arguments);
},
},
});
site.get("periods").forEach((period) => {
const periodCapitalized = period.capitalize();
app[
`DiscoveryTop${periodCapitalized}Controller`
] = DiscoverySortableController.extend();
app[
`DiscoveryTop${periodCapitalized}CategoryController`
] = DiscoverySortableController.extend();
app[
`DiscoveryTop${periodCapitalized}CategoryNoneController`
] = DiscoverySortableController.extend();
app[`DiscoveryTop${periodCapitalized}Route`] = buildTopicRoute(
"top/" + period
);
app[`DiscoveryTop${periodCapitalized}CategoryRoute`] = buildCategoryRoute(
"top/" + period
);
app[
`DiscoveryTop${periodCapitalized}CategoryNoneRoute`
] = buildCategoryRoute("top/" + period, { no_subcategories: true });
});
app["TagsShowCategoryRoute"] = TagShowRoute.extend();
app["TagsShowCategoryNoneRoute"] = TagShowRoute.extend({
noSubcategories: true,
@@ -27,14 +27,7 @@ export default function () {
});
this.route("discovery", { path: "/", resetNamespace: true }, function () {
// top
this.route("top");
this.route("topCategoryNone", {
path: "/c/*category_slug_path_with_id/none/l/top",
});
this.route("topCategory", { path: "/c/*category_slug_path_with_id/l/top" });
// top by periods
// top by periods - legacy route
Site.currentProp("periods").forEach((period) => {
const top = "top" + period.capitalize();
@@ -47,7 +40,7 @@ export default function () {
});
});
// filters (e.g. bookmarks, posted, read, unread, latest)
// filters (e.g. bookmarks, posted, read, unread, latest, top)
Site.currentProp("filters").forEach((filter) => {
this.route(filter, { path: "/" + filter });
this.route(filter + "CategoryNone", {
@@ -148,8 +148,7 @@ export default (filterArg, params) => {
category = model.category,
canCreateTopic = topics.get("can_create_topic"),
canCreateTopicOnCategory =
canCreateTopic && category.get("permission") === PermissionType.FULL,
filter = this.filter(category);
canCreateTopic && category.get("permission") === PermissionType.FULL;
this.controllerFor("navigation/category").setProperties({
canCreateTopicOnCategory: canCreateTopicOnCategory,
@@ -162,7 +161,7 @@ export default (filterArg, params) => {
category,
period:
topics.get("for_period") ||
(filter.indexOf("/") > 0 ? filter.split("/")[1] : ""),
(model.modelParams && model.modelParams.period),
selected: [],
noSubcategories: params && !!params.no_subcategories,
expandAllPinned: true,
@@ -130,9 +130,7 @@ export default function (filter, extras) {
const topicOpts = {
model,
category: null,
period:
model.get("for_period") ||
(filter.indexOf("top/") >= 0 ? filter.split("/")[1] : ""),
period: model.get("for_period") || model.get("params.period"),
selected: [],
expandAllPinned: false,
expandGloballyPinned: true,
@@ -7,6 +7,7 @@ import OpenComposer from "discourse/mixins/open-composer";
import User from "discourse/models/user";
import { scrollTop } from "discourse/mixins/scroll-top";
import { setTopicList } from "discourse/lib/topic-list-tracker";
import Site from "discourse/models/site";
export default DiscourseRoute.extend(OpenComposer, {
queryParams: {
@@ -19,6 +20,7 @@ export default DiscourseRoute.extend(OpenComposer, {
beforeModel(transition) {
const url = transition.intent.url;
let matches;
if (
(url === "/" || url === "/latest" || url === "/categories") &&
transition.targetName.indexOf("discovery.top") === -1 &&
@@ -26,7 +28,19 @@ export default DiscourseRoute.extend(OpenComposer, {
) {
User.currentProp("should_be_redirected_to_top", false);
const period = User.currentProp("redirected_to_top.period") || "all";
this.replaceWith(`discovery.top${period.capitalize()}`);
this.replaceWith("discovery.top", {
queryParams: {
period: period,
},
});
} else if (url && (matches = url.match(/top\/(.*)$/))) {
if (Site.currentProp("periods").includes(matches[1])) {
this.replaceWith("discovery.top", {
queryParams: {
period: matches[1],
},
});
}
}
},
@@ -45,21 +45,26 @@
<div class="full-width">
<div id="list-area">
{{#unless loading}}
{{#if list.topics}}
{{#discovery-topics-list
model=list
refresh=(action "refresh")
autoAddTopicsToBulkSelect=autoAddTopicsToBulkSelect
bulkSelectEnabled=bulkSelectEnabled
addTopicsToBulkSelect=(action "addTopicsToBulkSelect")
as |discoveryTopicList|
{{#discovery-topics-list
model=list
refresh=(action "refresh")
autoAddTopicsToBulkSelect=autoAddTopicsToBulkSelect
bulkSelectEnabled=bulkSelectEnabled
addTopicsToBulkSelect=(action "addTopicsToBulkSelect")
as |discoveryTopicList|
}}
{{#if top}}
<div class="top-lists">
{{period-chooser period=period action=(action "changePeriod") fullDay=false}}
</div>
{{/if}}
{{bulk-select-button
selected=selected
action=(action "refresh")
category=category
}}
{{bulk-select-button
selected=selected
action=(action "refresh")
category=category
}}
{{#if list.topics}}
{{topic-list
topics=list.topics
canBulkSelect=canBulkSelect
@@ -74,8 +79,8 @@
onScroll=discoveryTopicList.saveScrollPosition
scrollOnLoad=true
}}
{{/discovery-topics-list}}
{{/if}}
{{/if}}
{{/discovery-topics-list}}
<footer class="topic-list-bottom">
{{topic-dismiss-buttons position="bottom" selectedTopics=selected
@@ -2,13 +2,13 @@ import {
acceptance,
updateCurrentUser,
} from "discourse/tests/helpers/qunit-helpers";
import { currentRouteName, visit } from "@ember/test-helpers";
import { currentURL, visit } from "@ember/test-helpers";
import DiscoveryFixtures from "discourse/tests/fixtures/discovery-fixtures";
import { test } from "qunit";
acceptance("Redirect to Top", function (needs) {
needs.pretender((server, helper) => {
server.get("/top/weekly.json", () => {
server.get("/top.json?period=weekly", () => {
return helper.response(DiscoveryFixtures["/latest.json"]);
});
server.get("/top/monthly.json", () => {
@@ -30,11 +30,7 @@ acceptance("Redirect to Top", function (needs) {
});
await visit("/categories");
assert.equal(
currentRouteName(),
"discovery.topWeekly",
"it works for categories"
);
assert.equal(currentURL(), "/top?period=weekly", "it works for categories");
});
test("redirects latest to monthly top", async function (assert) {
@@ -47,11 +43,7 @@ acceptance("Redirect to Top", function (needs) {
});
await visit("/latest");
assert.equal(
currentRouteName(),
"discovery.topMonthly",
"it works for latest"
);
assert.equal(currentURL(), "/top?period=monthly", "it works for latest");
});
test("redirects root to All top", async function (assert) {
@@ -64,6 +56,6 @@ acceptance("Redirect to Top", function (needs) {
});
await visit("/");
assert.equal(currentRouteName(), "discovery.topAll", "it works for root");
assert.equal(currentURL(), "/top?period=all", "it works for root");
});
});
@@ -124,7 +124,7 @@ acceptance("Topic Discovery", function (needs) {
await periodChooser.selectRowByValue("yearly");
assert.ok(
DiscourseURL.routeTo.calledWith("/top/yearly?f=foo&d=bar"),
DiscourseURL.routeTo.calledWith("/top?f=foo&d=bar&period=yearly"),
"it keeps the query params"
);
});
@@ -35,6 +35,7 @@ export default {
"latest",
"unread",
"new",
"top",
"starred",
"read",
"posted",
@@ -40,6 +40,7 @@ PreloadStore.store("site", {
"latest",
"unread",
"new",
"top",
"starred",
"read",
"posted",