DEV: Introduce dedicated controller and route for `discovery.filter` (#20837)
Instead of being tied to the old implementation and constraints, a dedicated route and controller for the `discovery.filter` app route will allow us to iterate on changes much faster.
This commit is contained in:
parent
9c36a49668
commit
e0155b6955
|
@ -1,33 +1,19 @@
|
||||||
{{#if this.isQueryFilterMode}}
|
<BreadCrumbs
|
||||||
<div class="topic-query-filter">
|
|
||||||
<div class="topic-query-filter__input">
|
|
||||||
{{d-icon "filter" class="topic-query-filter__icon"}}
|
|
||||||
<Input
|
|
||||||
class="topic-query-filter__filter-term"
|
|
||||||
@value={{this.queryString}}
|
|
||||||
@enter={{action @updateTopicsListQueryParams this.queryString}}
|
|
||||||
@type="text"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{else}}
|
|
||||||
<BreadCrumbs
|
|
||||||
@categories={{this.categories}}
|
@categories={{this.categories}}
|
||||||
@category={{this.category}}
|
@category={{this.category}}
|
||||||
@noSubcategories={{this.noSubcategories}}
|
@noSubcategories={{this.noSubcategories}}
|
||||||
@tag={{this.tag}}
|
@tag={{this.tag}}
|
||||||
@additionalTags={{this.additionalTags}}
|
@additionalTags={{this.additionalTags}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{{#unless this.additionalTags}}
|
{{#unless this.additionalTags}}
|
||||||
{{! nav bar doesn't work with tag intersections }}
|
{{! nav bar doesn't work with tag intersections }}
|
||||||
<NavigationBar
|
<NavigationBar
|
||||||
@navItems={{this.navItems}}
|
@navItems={{this.navItems}}
|
||||||
@filterMode={{this.filterMode}}
|
@filterMode={{this.filterMode}}
|
||||||
@category={{this.category}}
|
@category={{this.category}}
|
||||||
/>
|
/>
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<div class="navigation-controls">
|
<div class="navigation-controls">
|
||||||
{{#if (and this.notCategoriesRoute this.site.mobileView this.canBulk)}}
|
{{#if (and this.notCategoriesRoute this.site.mobileView this.canBulk)}}
|
||||||
|
|
|
@ -6,18 +6,11 @@ import { NotificationLevels } from "discourse/lib/notification-levels";
|
||||||
import { getOwner } from "discourse-common/lib/get-owner";
|
import { getOwner } from "discourse-common/lib/get-owner";
|
||||||
import { htmlSafe } from "@ember/template";
|
import { htmlSafe } from "@ember/template";
|
||||||
import { inject as service } from "@ember/service";
|
import { inject as service } from "@ember/service";
|
||||||
import { equal } from "@ember/object/computed";
|
|
||||||
|
|
||||||
export default Component.extend(FilterModeMixin, {
|
export default Component.extend(FilterModeMixin, {
|
||||||
router: service(),
|
router: service(),
|
||||||
dialog: service(),
|
dialog: service(),
|
||||||
tagName: "",
|
tagName: "",
|
||||||
queryString: "",
|
|
||||||
|
|
||||||
init() {
|
|
||||||
this._super(...arguments);
|
|
||||||
this.queryString = this.filterQueryString;
|
|
||||||
},
|
|
||||||
|
|
||||||
// Should be a `readOnly` instead but some themes/plugins still pass
|
// Should be a `readOnly` instead but some themes/plugins still pass
|
||||||
// the `categories` property into this component
|
// the `categories` property into this component
|
||||||
|
@ -147,8 +140,6 @@ export default Component.extend(FilterModeMixin, {
|
||||||
return controller.canBulkSelect;
|
return controller.canBulkSelect;
|
||||||
},
|
},
|
||||||
|
|
||||||
isQueryFilterMode: equal("filterMode", "filter"),
|
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
changeCategoryNotificationLevel(notificationLevel) {
|
changeCategoryNotificationLevel(notificationLevel) {
|
||||||
this.category.setNotification(notificationLevel);
|
this.category.setNotification(notificationLevel);
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import Controller from "@ember/controller";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
|
||||||
|
export default class extends Controller {
|
||||||
|
@tracked status = "";
|
||||||
|
|
||||||
|
queryParams = ["status"];
|
||||||
|
|
||||||
|
get queryString() {
|
||||||
|
let paramStrings = [];
|
||||||
|
|
||||||
|
this.queryParams.forEach((key) => {
|
||||||
|
if (this[key]) {
|
||||||
|
paramStrings.push(`${key}:${this[key]}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return paramStrings.join(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
updateTopicsListQueryParams(queryString) {
|
||||||
|
for (const match of queryString.matchAll(/(\w+):([^:\s]+)/g)) {
|
||||||
|
const key = match[1];
|
||||||
|
const value = match[2];
|
||||||
|
|
||||||
|
if (this.queryParams.includes(key)) {
|
||||||
|
this.set(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,4 @@
|
||||||
import Controller, { inject as controller } from "@ember/controller";
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
|
||||||
import { action } from "@ember/object";
|
|
||||||
|
|
||||||
// Just add query params here to have them automatically passed to topic list filters.
|
// Just add query params here to have them automatically passed to topic list filters.
|
||||||
export const queryParams = {
|
export const queryParams = {
|
||||||
|
@ -29,31 +27,6 @@ export const queryParams = {
|
||||||
const controllerOpts = {
|
const controllerOpts = {
|
||||||
discoveryTopics: controller("discovery/topics"),
|
discoveryTopics: controller("discovery/topics"),
|
||||||
queryParams: Object.keys(queryParams),
|
queryParams: Object.keys(queryParams),
|
||||||
|
|
||||||
@discourseComputed(...Object.keys(queryParams))
|
|
||||||
queryString() {
|
|
||||||
let paramStrings = [];
|
|
||||||
|
|
||||||
this.queryParams.forEach((key) => {
|
|
||||||
if (this[key]) {
|
|
||||||
paramStrings.push(`${key}:${this[key]}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return paramStrings.join(" ");
|
|
||||||
},
|
|
||||||
|
|
||||||
@action
|
|
||||||
updateTopicsListQueryParams(queryString) {
|
|
||||||
for (const match of queryString.matchAll(/(\w+):([^:\s]+)/g)) {
|
|
||||||
const key = match[1];
|
|
||||||
const value = match[2];
|
|
||||||
|
|
||||||
if (controllerOpts.queryParams.includes(key)) {
|
|
||||||
this.set(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Default to `undefined`
|
// Default to `undefined`
|
||||||
|
|
|
@ -6,7 +6,6 @@ import { TRACKED_QUERY_PARAM_VALUE } from "discourse/lib/topic-list-tracked-filt
|
||||||
|
|
||||||
export default Controller.extend(FilterModeMixin, {
|
export default Controller.extend(FilterModeMixin, {
|
||||||
discovery: controller(),
|
discovery: controller(),
|
||||||
discoveryFilter: controller("discovery.filter"),
|
|
||||||
router: service(),
|
router: service(),
|
||||||
|
|
||||||
@discourseComputed("router.currentRoute.queryParams.f")
|
@discourseComputed("router.currentRoute.queryParams.f")
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
|
|
||||||
|
export default class extends Controller {
|
||||||
|
@controller("discovery/filter") discoveryFilter;
|
||||||
|
|
||||||
|
queryString = "";
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(...arguments);
|
||||||
|
this.queryString = this.discoveryFilter.queryString;
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,13 +11,6 @@ export default {
|
||||||
name: "dynamic-route-builders",
|
name: "dynamic-route-builders",
|
||||||
|
|
||||||
initialize(_container, app) {
|
initialize(_container, app) {
|
||||||
app.register(
|
|
||||||
"controller:discovery.filter",
|
|
||||||
DiscoverySortableController.extend()
|
|
||||||
);
|
|
||||||
|
|
||||||
app.register("route:discovery.filter", buildTopicRoute("filter"));
|
|
||||||
|
|
||||||
app.register(
|
app.register(
|
||||||
"controller:discovery.category",
|
"controller:discovery.category",
|
||||||
DiscoverySortableController.extend()
|
DiscoverySortableController.extend()
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
import I18n from "I18n";
|
||||||
|
|
||||||
|
import DiscourseRoute from "discourse/routes/discourse";
|
||||||
|
import { isEmpty } from "@ember/utils";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
|
||||||
|
export default class extends DiscourseRoute {
|
||||||
|
queryParams = {
|
||||||
|
status: { replace: true, refreshModel: true },
|
||||||
|
};
|
||||||
|
|
||||||
|
model(data) {
|
||||||
|
return this.store.findFiltered("topicList", {
|
||||||
|
filter: "filter",
|
||||||
|
params: this.#filterQueryParams(data),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
titleToken() {
|
||||||
|
const filterText = I18n.t("filters.filter.title");
|
||||||
|
return I18n.t("filters.with_topics", { filter: filterText });
|
||||||
|
}
|
||||||
|
|
||||||
|
setupController(_controller, model) {
|
||||||
|
this.controllerFor("discovery/topics").setProperties({ model });
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTemplate() {
|
||||||
|
this.render("navigation/filter", { outlet: "navigation-bar" });
|
||||||
|
|
||||||
|
this.render("discovery/topics", {
|
||||||
|
controller: "discovery/topics",
|
||||||
|
outlet: "list-container",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(tgxworld): This action is required by the `discovery/topics` controller which is not necessary for this route.
|
||||||
|
// Figure out a way to remove this.
|
||||||
|
@action
|
||||||
|
changeSort() {}
|
||||||
|
|
||||||
|
#filterQueryParams(data) {
|
||||||
|
const params = {};
|
||||||
|
|
||||||
|
Object.keys(this.queryParams).forEach((key) => {
|
||||||
|
if (!isEmpty(data[key])) {
|
||||||
|
params[key] = data[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,5 @@
|
||||||
@hasDraft={{this.currentUser.has_topic_draft}}
|
@hasDraft={{this.currentUser.has_topic_draft}}
|
||||||
@createTopic={{route-action "createTopic"}}
|
@createTopic={{route-action "createTopic"}}
|
||||||
@skipCategoriesNavItem={{this.skipCategoriesNavItem}}
|
@skipCategoriesNavItem={{this.skipCategoriesNavItem}}
|
||||||
@filterQueryString={{this.discoveryFilter.queryString}}
|
|
||||||
@updateTopicsListQueryParams={{this.discoveryFilter.updateTopicsListQueryParams}}
|
|
||||||
/>
|
/>
|
||||||
</DSection>
|
</DSection>
|
|
@ -0,0 +1,20 @@
|
||||||
|
<DSection
|
||||||
|
@bodyClass="navigation-filter"
|
||||||
|
@class="navigation-container"
|
||||||
|
@scrollTop={{false}}
|
||||||
|
>
|
||||||
|
<div class="topic-query-filter">
|
||||||
|
<div class="topic-query-filter__input">
|
||||||
|
{{d-icon "filter" class="topic-query-filter__icon"}}
|
||||||
|
<Input
|
||||||
|
class="topic-query-filter__filter-term"
|
||||||
|
@value={{this.queryString}}
|
||||||
|
@enter={{action
|
||||||
|
this.discoveryFilter.updateTopicsListQueryParams
|
||||||
|
this.queryString
|
||||||
|
}}
|
||||||
|
@type="text"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DSection>
|
Loading…
Reference in New Issue