DEV: Replace filter-mode mixin with lib functions (#22986)

The filter-mode mixin was previously serving two distinct purposes via a complex arrangement of getters/setters:

1. To calculate a filterMode, given values for category, filterType and noSubcategories

2. To calculate a filterType, given a filterMode

This commit splits the mixin into two functions, and updates all call sites to use them instead of the mixin.
This commit is contained in:
David Taylor 2023-08-07 15:11:54 +01:00 committed by GitHub
parent 7f2e42c826
commit a0e45a1e0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 104 additions and 67 deletions

View File

@ -1,16 +1,24 @@
import Component from "@ember/component"; import Component from "@ember/component";
import FilterModeMixin from "discourse/mixins/filter-mode"; import { filterTypeForMode } from "discourse/lib/filter-mode";
import NavItem from "discourse/models/nav-item"; import NavItem from "discourse/models/nav-item";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import { NotificationLevels } from "discourse/lib/notification-levels"; 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 { tracked } from "@glimmer/tracking";
import { dependentKeyCompat } from "@ember/object/compat";
export default Component.extend(FilterModeMixin, { export default Component.extend({
router: service(), router: service(),
dialog: service(), dialog: service(),
tagName: "", tagName: "",
filterMode: tracked(),
@dependentKeyCompat
get filterType() {
return filterTypeForMode(this.filterMode);
},
// 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

View File

@ -2,13 +2,21 @@ import discourseComputed, { observes } from "discourse-common/utils/decorators";
import Component from "@ember/component"; import Component from "@ember/component";
import { action } from "@ember/object"; import { action } from "@ember/object";
import DiscourseURL from "discourse/lib/url"; import DiscourseURL from "discourse/lib/url";
import FilterModeMixin from "discourse/mixins/filter-mode";
import { next } from "@ember/runloop"; import { next } from "@ember/runloop";
import { filterTypeForMode } from "discourse/lib/filter-mode";
import { dependentKeyCompat } from "@ember/object/compat";
import { tracked } from "@glimmer/tracking";
export default Component.extend(FilterModeMixin, { export default Component.extend({
tagName: "ul", tagName: "ul",
classNameBindings: [":nav", ":nav-pills"], classNameBindings: [":nav", ":nav-pills"],
elementId: "navigation-bar", elementId: "navigation-bar",
filterMode: tracked(),
@dependentKeyCompat
get filterType() {
return filterTypeForMode(this.filterMode);
},
init() { init() {
this._super(...arguments); this._super(...arguments);

View File

@ -1,8 +1,10 @@
import Component from "@ember/component"; import Component from "@ember/component";
import FilterModeMixin from "discourse/mixins/filter-mode";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import { filterTypeForMode } from "discourse/lib/filter-mode";
import { dependentKeyCompat } from "@ember/object/compat";
import { tracked } from "@glimmer/tracking";
export default Component.extend(FilterModeMixin, { export default Component.extend({
tagName: "li", tagName: "li",
classNameBindings: [ classNameBindings: [
"active", "active",
@ -15,6 +17,12 @@ export default Component.extend(FilterModeMixin, {
hidden: false, hidden: false,
activeClass: "", activeClass: "",
hrefLink: null, hrefLink: null,
filterMode: tracked(),
@dependentKeyCompat
get filterType() {
return filterTypeForMode(this.filterMode);
},
@discourseComputed("content.filterType", "filterType", "content.active") @discourseComputed("content.filterType", "filterType", "content.active")
active(contentFilterType, filterType, active) { active(contentFilterType, filterType, active) {

View File

@ -1,6 +1,19 @@
import FilterModeMixin from "discourse/mixins/filter-mode";
import NavigationDefaultController from "discourse/controllers/navigation/default"; import NavigationDefaultController from "discourse/controllers/navigation/default";
import { calculateFilterMode } from "discourse/lib/filter-mode";
import { dependentKeyCompat } from "@ember/object/compat";
import { tracked } from "@glimmer/tracking";
export default class NavigationCategoryController extends NavigationDefaultController.extend( export default class NavigationCategoryController extends NavigationDefaultController {
FilterModeMixin @tracked category;
) {} @tracked filterType;
@tracked noSubcategories;
@dependentKeyCompat
get filterMode() {
return calculateFilterMode({
category: this.category,
filterType: this.filterType,
noSubcategories: this.noSubcategories,
});
}
}

View File

@ -1,14 +1,27 @@
import { inject as service } from "@ember/service"; import { inject as service } from "@ember/service";
import Controller, { inject as controller } from "@ember/controller"; import Controller, { inject as controller } from "@ember/controller";
import FilterModeMixin from "discourse/mixins/filter-mode";
import { TRACKED_QUERY_PARAM_VALUE } from "discourse/lib/topic-list-tracked-filter"; import { TRACKED_QUERY_PARAM_VALUE } from "discourse/lib/topic-list-tracked-filter";
import { calculateFilterMode } from "discourse/lib/filter-mode";
import { dependentKeyCompat } from "@ember/object/compat";
import { tracked } from "@glimmer/tracking";
export default class NavigationDefaultController extends Controller.extend( export default class NavigationDefaultController extends Controller {
FilterModeMixin
) {
@service router; @service router;
@controller discovery; @controller discovery;
@tracked category;
@tracked filterType;
@tracked noSubcategories;
@dependentKeyCompat
get filterMode() {
return calculateFilterMode({
category: this.category,
filterType: this.filterType,
noSubcategories: this.noSubcategories,
});
}
get skipCategoriesNavItem() { get skipCategoriesNavItem() {
return this.router.currentRoute.queryParams.f === TRACKED_QUERY_PARAM_VALUE; return this.router.currentRoute.queryParams.f === TRACKED_QUERY_PARAM_VALUE;
} }

View File

@ -3,7 +3,6 @@ import { inject as controller } from "@ember/controller";
import discourseComputed, { observes } from "discourse-common/utils/decorators"; import discourseComputed, { observes } from "discourse-common/utils/decorators";
import BulkTopicSelection from "discourse/mixins/bulk-topic-selection"; import BulkTopicSelection from "discourse/mixins/bulk-topic-selection";
import DismissTopics from "discourse/mixins/dismiss-topics"; import DismissTopics from "discourse/mixins/dismiss-topics";
import FilterModeMixin from "discourse/mixins/filter-mode";
import I18n from "I18n"; import I18n from "I18n";
import NavItem from "discourse/models/nav-item"; import NavItem from "discourse/models/nav-item";
import Topic from "discourse/models/topic"; import Topic from "discourse/models/topic";
@ -11,11 +10,14 @@ import { readOnly } from "@ember/object/computed";
import { endWith } from "discourse/lib/computed"; import { endWith } from "discourse/lib/computed";
import { action } from "@ember/object"; import { action } from "@ember/object";
import { inject as service } from "@ember/service"; import { inject as service } from "@ember/service";
import { calculateFilterMode } from "discourse/lib/filter-mode";
import { dependentKeyCompat } from "@ember/object/compat";
import { tracked } from "@glimmer/tracking";
export default DiscoverySortableController.extend( export default DiscoverySortableController.extend(
BulkTopicSelection, BulkTopicSelection,
DismissTopics, DismissTopics,
FilterModeMixin,
{ {
application: controller(), application: controller(),
dialog: service(), dialog: service(),
@ -33,6 +35,19 @@ export default DiscoverySortableController.extend(
showInfo: false, showInfo: false,
top: endWith("list.filter", "top"), top: endWith("list.filter", "top"),
category: tracked(),
filterType: tracked(),
noSubcategories: tracked(),
@dependentKeyCompat
get filterMode() {
return calculateFilterMode({
category: this.category,
filterType: this.filterType,
noSubcategories: this.noSubcategories,
});
},
@discourseComputed( @discourseComputed(
"canCreateTopic", "canCreateTopic",
"category", "category",
@ -97,14 +112,14 @@ export default DiscoverySortableController.extend(
}, },
callResetNew(dismissPosts = false, dismissTopics = false, untrack = false) { callResetNew(dismissPosts = false, dismissTopics = false, untrack = false) {
const tracked = const filterTracked =
(this.router.currentRoute.queryParams["f"] || (this.router.currentRoute.queryParams["f"] ||
this.router.currentRoute.queryParams["filter"]) === "tracked"; this.router.currentRoute.queryParams["filter"]) === "tracked";
let topicIds = this.selected ? this.selected.mapBy("id") : null; let topicIds = this.selected ? this.selected.mapBy("id") : null;
Topic.resetNew(this.category, !this.noSubcategories, { Topic.resetNew(this.category, !this.noSubcategories, {
tracked, tracked: filterTracked,
tag: this.tag, tag: this.tag,
topicIds, topicIds,
dismissPosts, dismissPosts,
@ -114,7 +129,9 @@ export default DiscoverySortableController.extend(
if (result.topic_ids) { if (result.topic_ids) {
this.topicTrackingState.removeTopics(result.topic_ids); this.topicTrackingState.removeTopics(result.topic_ids);
} }
this.refresh(tracked ? { skipResettingParams: ["filter", "f"] } : {}); this.refresh(
filterTracked ? { skipResettingParams: ["filter", "f"] } : {}
);
}); });
}, },

View File

@ -0,0 +1,15 @@
import Category from "discourse/models/category";
export function calculateFilterMode({ category, filterType, noSubcategories }) {
if (category) {
return `c/${Category.slugFor(category)}${
noSubcategories ? "/none" : ""
}/l/${filterType}`;
} else {
return filterType;
}
}
export function filterTypeForMode(mode) {
return mode.split("/").pop();
}

View File

@ -1,44 +0,0 @@
import Category from "discourse/models/category";
import Mixin from "@ember/object/mixin";
import { computed } from "@ember/object";
export default Mixin.create({
filterModeInternal: computed(
"rawFilterMode",
"filterType",
"category",
"noSubcategories",
function () {
const rawFilterMode = this.rawFilterMode;
if (rawFilterMode) {
return rawFilterMode;
} else {
const category = this.category;
const filterType = this.filterType;
if (category) {
const noSubcategories = this.noSubcategories;
return `c/${Category.slugFor(category)}${
noSubcategories ? "/none" : ""
}/l/${filterType}`;
} else {
return filterType;
}
}
}
),
filterMode: computed("filterModeInternal", {
get() {
return this.filterModeInternal;
},
set(key, value) {
this.set("rawFilterMode", value);
this.set("filterType", value.split("/").pop());
return value;
},
}),
});

View File

@ -9,7 +9,6 @@ import {
import Category from "discourse/models/category"; import Category from "discourse/models/category";
import Composer from "discourse/models/composer"; import Composer from "discourse/models/composer";
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
import FilterModeMixin from "discourse/mixins/filter-mode";
import I18n from "I18n"; import I18n from "I18n";
import PermissionType from "discourse/models/permission-type"; import PermissionType from "discourse/models/permission-type";
import { escapeExpression } from "discourse/lib/utilities"; import { escapeExpression } from "discourse/lib/utilities";
@ -23,7 +22,7 @@ import { inject as service } from "@ember/service";
const NONE = "none"; const NONE = "none";
const ALL = "all"; const ALL = "all";
export default DiscourseRoute.extend(FilterModeMixin, { export default DiscourseRoute.extend({
composer: service(), composer: service(),
navMode: "latest", navMode: "latest",

View File

@ -1,6 +1,6 @@
<DSection @bodyClass="navigation-categories" @class="navigation-container"> <DSection @bodyClass="navigation-categories" @class="navigation-container">
<DNavigation <DNavigation
@filterType="categories" @filterMode="categories"
@showCategoryAdmin={{this.showCategoryAdmin}} @showCategoryAdmin={{this.showCategoryAdmin}}
@createCategory={{route-action "createCategory"}} @createCategory={{route-action "createCategory"}}
@reorderCategories={{route-action "reorderCategories"}} @reorderCategories={{route-action "reorderCategories"}}

View File

@ -20,7 +20,7 @@ module("Integration | Component | d-navigation", function (hooks) {
}); });
test("filters indirectly muted categories", async function (assert) { test("filters indirectly muted categories", async function (assert) {
await render(hbs`<DNavigation @filterType="categories" />`); await render(hbs`<DNavigation @filterMode="categories" />`);
await click(".category-drop .select-kit-header-wrapper"); await click(".category-drop .select-kit-header-wrapper");
assert.strictEqual( assert.strictEqual(