From ced9a5ee6dbf908cbc029cf679c4944df7cb73fd Mon Sep 17 00:00:00 2001 From: Alan Guo Xiang Tan Date: Fri, 10 Jun 2022 09:49:36 +0800 Subject: [PATCH] FEATURE: First pass tags section for experimental sidebar. (#17048) Counts for the section links will be added in a follow up commit. --- .../app/components/sidebar/tags-section.js | 13 + .../sidebar/tags-section/tag-section-link.js | 25 ++ .../app/templates/components/sidebar.hbs | 4 + .../components/sidebar/tags-section.hbs | 23 ++ .../acceptance/sidebar-tags-section-test.js | 229 ++++++++++++++++++ config/locales/client.en.yml | 4 + 6 files changed, 298 insertions(+) create mode 100644 app/assets/javascripts/discourse/app/components/sidebar/tags-section.js create mode 100644 app/assets/javascripts/discourse/app/lib/sidebar/tags-section/tag-section-link.js create mode 100644 app/assets/javascripts/discourse/app/templates/components/sidebar/tags-section.hbs create mode 100644 app/assets/javascripts/discourse/tests/acceptance/sidebar-tags-section-test.js diff --git a/app/assets/javascripts/discourse/app/components/sidebar/tags-section.js b/app/assets/javascripts/discourse/app/components/sidebar/tags-section.js new file mode 100644 index 00000000000..c763d22bfe7 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/sidebar/tags-section.js @@ -0,0 +1,13 @@ +import { cached } from "@glimmer/tracking"; + +import GlimmerComponent from "discourse/components/glimmer"; +import TagSectionLink from "discourse/lib/sidebar/tags-section/tag-section-link"; + +export default class SidebarTagsSection extends GlimmerComponent { + @cached + get sectionLinks() { + return this.currentUser.trackedTags.map((trackedTag) => { + return new TagSectionLink({ tag: trackedTag }); + }); + } +} diff --git a/app/assets/javascripts/discourse/app/lib/sidebar/tags-section/tag-section-link.js b/app/assets/javascripts/discourse/app/lib/sidebar/tags-section/tag-section-link.js new file mode 100644 index 00000000000..ff78f2db4e0 --- /dev/null +++ b/app/assets/javascripts/discourse/app/lib/sidebar/tags-section/tag-section-link.js @@ -0,0 +1,25 @@ +export default class TagSectionLink { + constructor({ tag }) { + this.tag = tag; + } + + get name() { + return this.tag; + } + + get model() { + return this.tag; + } + + get currentWhen() { + return "tag.show tag.showNew tag.showUnread tag.showTop"; + } + + get route() { + return "tag.show"; + } + + get text() { + return this.tag; + } +} diff --git a/app/assets/javascripts/discourse/app/templates/components/sidebar.hbs b/app/assets/javascripts/discourse/app/templates/components/sidebar.hbs index 9bbd1203aaf..9c69d3ae7c8 100644 --- a/app/assets/javascripts/discourse/app/templates/components/sidebar.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/sidebar.hbs @@ -3,6 +3,10 @@ {{/if}} diff --git a/app/assets/javascripts/discourse/app/templates/components/sidebar/tags-section.hbs b/app/assets/javascripts/discourse/app/templates/components/sidebar/tags-section.hbs new file mode 100644 index 00000000000..60c9b0fbbb3 --- /dev/null +++ b/app/assets/javascripts/discourse/app/templates/components/sidebar/tags-section.hbs @@ -0,0 +1,23 @@ + + + {{#if (gt this.sectionLinks.length 0)}} + {{#each this.sectionLinks as |sectionLink|}} + + + {{/each}} + {{else}} + + {{i18n "sidebar.sections.tags.no_tracked_tags"}} + + {{/if}} + diff --git a/app/assets/javascripts/discourse/tests/acceptance/sidebar-tags-section-test.js b/app/assets/javascripts/discourse/tests/acceptance/sidebar-tags-section-test.js new file mode 100644 index 00000000000..bed88ce3d04 --- /dev/null +++ b/app/assets/javascripts/discourse/tests/acceptance/sidebar-tags-section-test.js @@ -0,0 +1,229 @@ +import I18n from "I18n"; + +import { click, currentURL, visit } from "@ember/test-helpers"; + +import { + acceptance, + conditionalTest, + exists, + query, + queryAll, + updateCurrentUser, +} from "discourse/tests/helpers/qunit-helpers"; +import { isLegacyEmber } from "discourse-common/config/environment"; +import discoveryFixture from "discourse/tests/fixtures/discovery-fixtures"; +import { cloneJSON } from "discourse-common/lib/object"; + +acceptance("Sidebar - Tags section - tagging disabled", function (needs) { + needs.settings({ + tagging_enabled: false, + }); + + needs.user({ experimental_sidebar_enabled: true }); + + conditionalTest( + "tags section is not shown", + !isLegacyEmber(), + async function (assert) { + await visit("/"); + + assert.ok( + !exists(".sidebar-section-tags"), + "does not display the tags section" + ); + } + ); +}); + +acceptance("Sidebar - Tags section", function (needs) { + needs.settings({ + tagging_enabled: true, + }); + + needs.user({ + experimental_sidebar_enabled: true, + tracked_tags: ["tag1"], + watched_tags: ["tag2", "tag3"], + watching_first_post_tags: [], + }); + + needs.pretender((server, helper) => { + server.get("/tag/:tagId/notifications", (request) => { + return helper.response({ + tag_notification: { id: request.params.tagId }, + }); + }); + + ["latest", "top", "new", "unread"].forEach((type) => { + server.get(`/tag/:tagId/l/${type}.json`, () => { + return helper.response( + cloneJSON(discoveryFixture["/tag/important/l/latest.json"]) + ); + }); + }); + }); + + conditionalTest( + "clicking on section header link", + !isLegacyEmber(), + async function (assert) { + await visit("/"); + await click(".sidebar-section-tags .sidebar-section-header-link"); + + assert.strictEqual( + currentURL(), + "/tags", + "it should transition to the tags page" + ); + } + ); + + conditionalTest( + "section content when user does not have any tracked tags", + !isLegacyEmber(), + async function (assert) { + updateCurrentUser({ + tracked_tags: [], + watched_tags: [], + watching_first_post_tags: [], + }); + + await visit("/"); + + assert.strictEqual( + query( + ".sidebar-section-tags .sidebar-section-message" + ).textContent.trim(), + I18n.t("sidebar.sections.tags.no_tracked_tags"), + "the no tracked tags message is displayed" + ); + } + ); + + conditionalTest( + "tag section links for tracked tags", + !isLegacyEmber(), + async function (assert) { + await visit("/"); + + assert.strictEqual( + queryAll(".sidebar-section-tags .sidebar-section-link").length, + 3, + "3 section links under the section" + ); + + assert.strictEqual( + query(".sidebar-section-link-tag1").textContent.trim(), + "tag1", + "displays the tag1 name for the link text" + ); + + assert.strictEqual( + query(".sidebar-section-link-tag2").textContent.trim(), + "tag2", + "displays the tag2 name for the link text" + ); + + assert.strictEqual( + query(".sidebar-section-link-tag3").textContent.trim(), + "tag3", + "displays the tag3 name for the link text" + ); + + await click(".sidebar-section-link-tag1"); + + assert.strictEqual( + currentURL(), + "/tag/tag1", + "it should transition to tag1's topics discovery page" + ); + + assert.strictEqual( + queryAll(".sidebar-section-tags .sidebar-section-link.active").length, + 1, + "only one link is marked as active" + ); + + assert.ok( + exists(`.sidebar-section-link-tag1.active`), + "the tag1 section link is marked as active" + ); + + await click(".sidebar-section-link-tag2"); + + assert.strictEqual( + currentURL(), + "/tag/tag2", + "it should transition to tag2's topics discovery page" + ); + + assert.strictEqual( + queryAll(".sidebar-section-tags .sidebar-section-link.active").length, + 1, + "only one link is marked as active" + ); + + assert.ok( + exists(`.sidebar-section-link-tag2.active`), + "the tag2 section link is marked as active" + ); + } + ); + + conditionalTest( + "visiting tag discovery top route for tracked tags", + !isLegacyEmber(), + async function (assert) { + await visit(`/tag/tag1/l/top`); + + assert.strictEqual( + queryAll(".sidebar-section-tags .sidebar-section-link.active").length, + 1, + "only one link is marked as active" + ); + + assert.ok( + exists(".sidebar-section-link-tag1.active"), + "the tag1 section link is marked as active for the top route" + ); + } + ); + + conditionalTest( + "visiting tag discovery new route for tracked tags", + !isLegacyEmber(), + async function (assert) { + await visit(`/tag/tag1/l/new`); + + assert.strictEqual( + queryAll(".sidebar-section-tags .sidebar-section-link.active").length, + 1, + "only one link is marked as active" + ); + + assert.ok( + exists(".sidebar-section-link-tag1.active"), + "the tag1 section link is marked as active for the new route" + ); + } + ); + + conditionalTest( + "visiting tag discovery unread route for tracked tags", + !isLegacyEmber(), + async function (assert) { + await visit(`/tag/tag1/l/unread`); + + assert.strictEqual( + queryAll(".sidebar-section-tags .sidebar-section-link.active").length, + 1, + "only one link is marked as active" + ); + + assert.ok( + exists(".sidebar-section-link-tag1.active"), + "the tag1 section link is marked as active for the unread route" + ); + } + ); +}); diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 1260392cb0e..3a58d4bb83a 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -4041,6 +4041,10 @@ en: unread_count: "%{count} unread" new_count: "%{count} new" sections: + tags: + no_tracked_tags: "You are not tracking any tags." + header_link_title: "all tags" + header_link_text: "Tags" categories: no_tracked_categories: "You are not tracking any categories." header_link_title: "all categories"