diff --git a/assets/javascripts/discourse/components/global-filter-container.js b/assets/javascripts/discourse/components/global-filter-container.js index d6361fc..7fae01b 100644 --- a/assets/javascripts/discourse/components/global-filter-container.js +++ b/assets/javascripts/discourse/components/global-filter-container.js @@ -6,7 +6,7 @@ export default Component.extend({ @discourseComputed("siteSettings.global_filters") globalFilters(filters) { - if (filters.length === 0) { + if (!filters) { return false; } return filters.split("|"); diff --git a/assets/javascripts/discourse/components/global-filter-item.js b/assets/javascripts/discourse/components/global-filter-item.js index d3fdcfa..a3d989d 100644 --- a/assets/javascripts/discourse/components/global-filter-item.js +++ b/assets/javascripts/discourse/components/global-filter-item.js @@ -1,12 +1,11 @@ import Component from "@ember/component"; import { action } from "@ember/object"; import discourseComputed from "discourse-common/utils/decorators"; -import { inject as service } from "@ember/service"; import { ajax } from "discourse/lib/ajax"; import { popupAjaxError } from "discourse/lib/ajax-error"; +import DiscourseURL from "discourse/lib/url"; export default Component.extend({ - router: service(), classNames: ["global-filter-item"], @discourseComputed("currentUser.custom_fields.global_filter_preference") @@ -23,7 +22,7 @@ export default Component.extend({ }, _filterTopicsByTag(tag) { - this.router.transitionTo("tag.show", tag); + DiscourseURL.routeTo(`/tag/${tag}`); }, _persistTagToServer(tag) { diff --git a/assets/javascripts/discourse/initializers/global-filter-preference.js b/assets/javascripts/discourse/initializers/global-filter-preference.js index c8b2b3e..d184bed 100644 --- a/assets/javascripts/discourse/initializers/global-filter-preference.js +++ b/assets/javascripts/discourse/initializers/global-filter-preference.js @@ -1,4 +1,4 @@ -import DiscourseURL, { getCategoryAndTagUrl } from "discourse/lib/url"; +import { run } from "@ember/runloop"; export default { name: "global-filter-preference", @@ -6,7 +6,7 @@ export default { initialize(container) { const siteSettings = container.lookup("site-settings:main"); const currentUser = container.lookup("current-user:main"); - let userGlobalFilterPref = + const userGlobalFilterPref = currentUser?.custom_fields?.global_filter_preference; if ( @@ -17,33 +17,19 @@ export default { } const router = container.lookup("router:main"); - const routesToRedirectOn = siteSettings.top_menu.split("|"); - routesToRedirectOn.push("/"); - - router.on("routeDidChange", () => { - if (routesToRedirectOn.includes(router.currentRoute.localName)) { - // grab the global_filter_preference in case it was updated - userGlobalFilterPref = - currentUser.custom_fields.global_filter_preference; - - let url = ""; - - url = getCategoryAndTagUrl( - this.currentCategory, - !this.noSubcategories, - userGlobalFilterPref - ); - - if (router.currentURL !== "/") { - url += `/l/${router.currentRoute.localName}`; - } - - if (router.currentRoute.queryParams) { - const params = router.currentURL.split("?"); - url += `?${params[1]}`; - } - - DiscourseURL.routeTo(url); + router.on("routeWillChange", (transition) => { + const routesToRedirectOn = siteSettings.top_menu.split("|"); + const localName = transition.to?.localName; + + if (localName && routesToRedirectOn.includes(localName)) { + run(router, function () { + return router.replaceWith( + `/tag/${userGlobalFilterPref}/l/${localName}`, + { + queryParams: transition.to.queryParams, + } + ); + }); } }); }, diff --git a/plugin.rb b/plugin.rb index 245c034..e4ec70a 100644 --- a/plugin.rb +++ b/plugin.rb @@ -40,22 +40,4 @@ class Engine < ::Rails::Engine register_editable_user_custom_field(GlobalFilter::GLOBAL_FILTER_PREFERENCE) register_user_custom_field_type(GlobalFilter::GLOBAL_FILTER_PREFERENCE, :string) DiscoursePluginRegistry.serialized_current_user_fields << GlobalFilter::GLOBAL_FILTER_PREFERENCE - - TopicQuery.add_custom_filter(:include_tags) do |results, topic_query| - user_custom_fields = topic_query&.user&.custom_fields - if user_custom_fields&.has_key?(GlobalFilter::GLOBAL_FILTER_PREFERENCE) - tag_id = Tag.find_by(name: user_custom_fields[GlobalFilter::GLOBAL_FILTER_PREFERENCE])&.id - return if !tag_id.present? - - results = results.where(<<~SQL, tag_id: tag_id) - topics.id IN ( - SELECT topic_tags.topic_id - FROM topic_tags - INNER JOIN tags ON tags.id = topic_tags.tag_id - WHERE tags.id IN (:tag_id) - ) - SQL - end - results - end end diff --git a/test/javascripts/acceptance/global-filter-preference-test.js b/test/javascripts/acceptance/global-filter-preference-test.js new file mode 100644 index 0000000..aaf76e6 --- /dev/null +++ b/test/javascripts/acceptance/global-filter-preference-test.js @@ -0,0 +1,93 @@ +import { click, currentURL, visit } from "@ember/test-helpers"; +import { acceptance } from "discourse/tests/helpers/qunit-helpers"; +import { test } from "qunit"; + +acceptance("Discourse Global Filter - Filter Preference", function (needs) { + needs.user({ custom_fields: { global_filter_preference: "support" } }); + needs.settings({ + discourse_global_filter_enabled: true, + global_filters: "support|feature", + }); + + needs.pretender((server, helper) => { + server.get("/tag/support/notifications", () => + helper.response({ + tag_notification: { id: "support", notification_level: 2 }, + }) + ); + + server.get("/tag/support/l/latest.json", () => { + return helper.response({ + users: [], + primary_groups: [], + topic_list: { + can_create_topic: true, + draft: null, + draft_key: "new_topic", + draft_sequence: 1, + per_page: 30, + tags: [], + topics: [], + }, + }); + }); + + server.get("/tag/support/l/top.json", () => { + return helper.response({ + users: [], + primary_groups: [], + topic_list: { + can_create_topic: true, + draft: null, + draft_key: "new_topic", + draft_sequence: 1, + per_page: 30, + tags: [], + topics: [], + }, + }); + }); + + server.put("/global_filter/filter_tags/support/assign.json", () => { + return helper.response({ success: true }); + }); + }); + + test("redirects to tag when selected", async function (assert) { + await visit("/"); + await click(".global-filter-container .global-filter-item button"); + + assert.equal(currentURL(), "/tag/support", "it redirects to the right tag"); + }); + + test("maintains tag filter when redirecting to a filtered topic view", async function (assert) { + await visit("/"); + await click("#navigation-bar .nav-item_top a"); + + assert.equal( + currentURL(), + "/tag/support/l/top", + "it redirects to the user's global_filter_preference" + ); + }); + + test("maintains tag filter when redirecting to root URL", async function (assert) { + await visit("/"); + + assert.equal( + currentURL(), + "/tag/support/l/latest", + "it redirects to the user's global_filter_preference" + ); + }); + + test("maintains params when redirecting", async function (assert) { + await visit("/latest?f=tracked"); + + assert.equal( + currentURL(), + "/tag/support/l/latest?f=tracked", + "it redirects to the user's global_filter_preference" + ); + }); +}); diff --git a/test/javascripts/components/global-filter-container-test.js b/test/javascripts/components/global-filter-container-test.js new file mode 100644 index 0000000..b9a4fc7 --- /dev/null +++ b/test/javascripts/components/global-filter-container-test.js @@ -0,0 +1,15 @@ +import { visit } from "@ember/test-helpers"; +import { acceptance, exists } from "discourse/tests/helpers/qunit-helpers"; +import { test } from "qunit"; + +acceptance("Discourse Global Filter - Filter Container", function (needs) { + needs.settings({ + discourse_global_filter_enabled: true, + global_filters: "support|feature", + }); + + test("is present when a tag is included in global_filters", async function (assert) { + await visit("/"); + assert.ok(exists(".global-filter-container"), "container is present"); + }); +}); diff --git a/test/javascripts/components/global-filter-item-test.js b/test/javascripts/components/global-filter-item-test.js new file mode 100644 index 0000000..8d094cf --- /dev/null +++ b/test/javascripts/components/global-filter-item-test.js @@ -0,0 +1,62 @@ +import { click, visit } from "@ember/test-helpers"; +import { + acceptance, + exists, + queryAll, +} from "discourse/tests/helpers/qunit-helpers"; +import { test } from "qunit"; + +acceptance("Discourse Global Filter - Filter Item", function (needs) { + needs.user(); + needs.settings({ + discourse_global_filter_enabled: true, + global_filters: "support|feature", + }); + + needs.pretender((server, helper) => { + server.get("/tag/support/notifications", () => + helper.response({ + tag_notification: { id: "support", notification_level: 2 }, + }) + ); + + server.get("/tag/support/l/latest.json", () => { + return helper.response({ + users: [], + primary_groups: [], + topic_list: { + can_create_topic: true, + draft: null, + draft_key: "new_topic", + draft_sequence: 1, + per_page: 30, + tags: [], + topics: [], + }, + }); + }); + + server.put("/global_filter/filter_tags/support/assign.json", () => { + return helper.response({ success: true }); + }); + }); + + test("is present when included in global_filters", async function (assert) { + await visit("/"); + let tags = []; + queryAll(".global-filter-container .global-filter-item").each((_, el) => + tags.push(el.innerText.trim()) + ); + assert.deepEqual(tags, this.siteSettings.global_filters.split("|")); + }); + + test("adds active class to filter when selected", async function (assert) { + await visit("/"); + await click(".global-filter-container .global-filter-item button"); + + assert.ok( + exists(".global-filter-container .global-filter-item button.active"), + "button is active" + ); + }); +});