From b27e12445dc9b27cc5063044b65d7adcb5d6d3fa Mon Sep 17 00:00:00 2001 From: Osama Sayegh Date: Thu, 22 Jun 2023 19:04:13 +0300 Subject: [PATCH] FEATURE: Split navigation preference for count and behavior of sidebar links (#22203) This PR splits up the preference that controls the count vs dot and destination of sidebar links, which is really hard to understand, into 2 simpler checkboxes: The new preferences/checkboxes are off by default, but there are database migrations to switch the old preference to the new ones so that existing users don't have to update their preferences to keep their preferred behavior of sidebar links when this changed is rolled out. Internal topic: t/103529. --- .../preferences/navigation-menu.js | 47 ++-- .../everything-section-link.js | 45 ++-- .../category-section-link.js | 20 +- .../my-posts-section-link.js | 18 +- .../user/tags-section/tag-section-link.js | 43 ++-- .../javascripts/discourse/app/models/user.js | 24 ++- .../app/routes/preferences-navigation-menu.js | 3 +- .../templates/preferences/navigation-menu.hbs | 20 +- .../acceptance/sidebar-plugin-api-test.js | 6 +- .../sidebar-user-categories-section-test.js | 162 +++++++++++++- .../sidebar-user-community-section-test.js | 203 ++++++++++++++---- .../sidebar-user-tags-section-test.js | 154 ++++++++++++- .../user-preferences-navigation-menu-test.js | 153 ++++++++++++- app/models/user_option.rb | 10 +- .../concerns/user_sidebar_mixin.rb | 12 -- .../current_user_option_serializer.rb | 4 +- app/serializers/current_user_serializer.rb | 1 - app/serializers/user_option_serializer.rb | 4 +- app/serializers/user_serializer.rb | 1 - app/services/user_updater.rb | 3 +- config/locales/client.en.yml | 6 +- config/site_settings.yml | 7 - ...ar_link_to_filtered_list_to_user_option.rb | 13 ++ ..._show_count_of_new_items_to_user_option.rb | 17 ++ ...efault_sidebar_list_destination_setting.rb | 11 + .../api/schemas/json/user_get_response.json | 7 +- spec/serializers/user_serializer_spec.rb | 1 - .../user_sidebar_serializer_attributes.rb | 18 -- .../pages/user_preferences_navigation_menu.rb | 10 +- ...iewing_navigation_menu_preferences_spec.rb | 14 +- 30 files changed, 788 insertions(+), 249 deletions(-) create mode 100644 db/migrate/20230618041001_add_sidebar_link_to_filtered_list_to_user_option.rb create mode 100644 db/migrate/20230618041123_add_sidebar_show_count_of_new_items_to_user_option.rb create mode 100644 db/migrate/20230620050614_remove_default_sidebar_list_destination_setting.rb diff --git a/app/assets/javascripts/discourse/app/controllers/preferences/navigation-menu.js b/app/assets/javascripts/discourse/app/controllers/preferences/navigation-menu.js index 583abbec60e..9ec75d04f30 100644 --- a/app/assets/javascripts/discourse/app/controllers/preferences/navigation-menu.js +++ b/app/assets/javascripts/discourse/app/controllers/preferences/navigation-menu.js @@ -5,36 +5,27 @@ import I18n from "I18n"; import { popupAjaxError } from "discourse/lib/ajax-error"; -export const DEFAULT_LIST_DESTINATION = "default"; -export const UNREAD_LIST_DESTINATION = "unread_new"; - export default class extends Controller { @tracked saved = false; @tracked selectedSidebarCategories = []; @tracked selectedSidebarTagNames = []; + subpageTitle = I18n.t("user.preferences_nav.navigation_menu"); saveAttrNames = [ "sidebar_category_ids", "sidebar_tag_names", - "sidebar_list_destination", - ]; - - sidebarListDestinations = [ - { - name: I18n.t("user.experimental_sidebar.list_destination_default"), - value: DEFAULT_LIST_DESTINATION, - }, - { - name: I18n.t("user.experimental_sidebar.list_destination_unread_new"), - value: UNREAD_LIST_DESTINATION, - }, + "sidebar_link_to_filtered_list", + "sidebar_show_count_of_new_items", ]; @action save() { const initialSidebarCategoryIds = this.model.sidebarCategoryIds; - const initialSidebarListDestination = this.model.sidebar_list_destination; + const initialSidebarLinkToFilteredList = + this.model.sidebarLinkToFilteredList; + const initialSidebarShowCountOfNewItems = + this.model.sidebarShowCountOfNewItems; this.model.set( "sidebarCategoryIds", @@ -44,8 +35,12 @@ export default class extends Controller { this.model.set("sidebar_tag_names", this.selectedSidebarTagNames); this.model.set( - "user_option.sidebar_list_destination", - this.newSidebarListDestination + "user_option.sidebar_link_to_filtered_list", + this.newSidebarLinkToFilteredList + ); + this.model.set( + "user_option.sidebar_show_count_of_new_items", + this.newSidebarShowCountOfNewItems ); this.model @@ -54,22 +49,24 @@ export default class extends Controller { if (result.user.sidebar_tags) { this.model.set("sidebar_tags", result.user.sidebar_tags); } - this.model.set( - "sidebar_list_destination", - this.newSidebarListDestination - ); this.saved = true; }) .catch((error) => { this.model.set("sidebarCategoryIds", initialSidebarCategoryIds); + this.model.set( + "user_option.sidebar_link_to_filtered_list", + initialSidebarLinkToFilteredList + ); + this.model.set( + "user_option.sidebar_show_count_of_new_items", + initialSidebarShowCountOfNewItems + ); + popupAjaxError(error); }) .finally(() => { this.model.set("sidebar_tag_names", []); - if (initialSidebarListDestination !== this.newSidebarListDestination) { - window.location.reload(); - } }); } } diff --git a/app/assets/javascripts/discourse/app/lib/sidebar/common/community-section/everything-section-link.js b/app/assets/javascripts/discourse/app/lib/sidebar/common/community-section/everything-section-link.js index c541ad9b0c7..61657ada2ea 100644 --- a/app/assets/javascripts/discourse/app/lib/sidebar/common/community-section/everything-section-link.js +++ b/app/assets/javascripts/discourse/app/lib/sidebar/common/community-section/everything-section-link.js @@ -2,13 +2,10 @@ import I18n from "I18n"; import { tracked } from "@glimmer/tracking"; import BaseSectionLink from "discourse/lib/sidebar/base-community-section-link"; -import { UNREAD_LIST_DESTINATION } from "discourse/controllers/preferences/navigation-menu"; export default class EverythingSectionLink extends BaseSectionLink { @tracked totalUnread = 0; @tracked totalNew = 0; - @tracked hideCount = - this.currentUser?.sidebarListDestination !== UNREAD_LIST_DESTINATION; constructor() { super(...arguments); @@ -26,11 +23,15 @@ export default class EverythingSectionLink extends BaseSectionLink { this.totalUnread = this.topicTrackingState.countUnread(); - if (this.totalUnread === 0 || this.#linkToNew) { + if (this.totalUnread === 0 || this.#newNewViewEnabled) { this.totalNew = this.topicTrackingState.countNew(); } } + get showCount() { + return this.currentUser?.sidebarShowCountOfNewItems; + } + get name() { return "everything"; } @@ -55,16 +56,13 @@ export default class EverythingSectionLink extends BaseSectionLink { } get badgeText() { - if (this.#linkToNew) { - if (this.#unreadAndNewCount > 0) { - return this.#unreadAndNewCount.toString(); - } + if (!this.showCount) { return; } - if (this.hideCount) { - return; - } - if (this.totalUnread > 0) { + + if (this.#newNewViewEnabled && this.#unreadAndNewCount > 0) { + return this.#unreadAndNewCount.toString(); + } else if (this.totalUnread > 0) { return I18n.t("sidebar.unread_count", { count: this.totalUnread, }); @@ -76,19 +74,12 @@ export default class EverythingSectionLink extends BaseSectionLink { } get route() { - if (this.#linkToNew) { - if (this.#unreadAndNewCount > 0) { + if (this.currentUser?.sidebarLinkToFilteredList) { + if (this.#newNewViewEnabled && this.#unreadAndNewCount > 0) { return "discovery.new"; - } else { - return "discovery.latest"; - } - } else if ( - this.currentUser?.sidebarListDestination === UNREAD_LIST_DESTINATION - ) { - if (this.totalUnread > 0) { + } else if (this.totalUnread > 0) { return "discovery.unread"; - } - if (this.totalNew > 0) { + } else if (this.totalNew > 0) { return "discovery.new"; } } @@ -108,11 +99,7 @@ export default class EverythingSectionLink extends BaseSectionLink { } get suffixValue() { - if ( - this.hideCount && - (this.totalUnread || this.totalNew) && - !this.#linkToNew - ) { + if (!this.showCount && (this.totalUnread || this.totalNew)) { return "circle"; } } @@ -121,7 +108,7 @@ export default class EverythingSectionLink extends BaseSectionLink { return this.totalUnread + this.totalNew; } - get #linkToNew() { + get #newNewViewEnabled() { return !!this.currentUser?.new_new_view_enabled; } } diff --git a/app/assets/javascripts/discourse/app/lib/sidebar/user/categories-section/category-section-link.js b/app/assets/javascripts/discourse/app/lib/sidebar/user/categories-section/category-section-link.js index 26fcf5720f7..43fae208a45 100644 --- a/app/assets/javascripts/discourse/app/lib/sidebar/user/categories-section/category-section-link.js +++ b/app/assets/javascripts/discourse/app/lib/sidebar/user/categories-section/category-section-link.js @@ -5,7 +5,6 @@ import { get, set } from "@ember/object"; import { bind } from "discourse-common/utils/decorators"; import Category from "discourse/models/category"; -import { UNREAD_LIST_DESTINATION } from "discourse/controllers/preferences/navigation-menu"; const UNREAD_AND_NEW_COUNTABLE = { propertyName: "unreadAndNewCount", @@ -120,7 +119,7 @@ export default class CategorySectionLink { #countables() { const countables = []; - if (this.#linkToNew) { + if (this.#newNewViewEnabled) { countables.push(UNREAD_AND_NEW_COUNTABLE); } else { countables.push(...DEFAULT_COUNTABLES); @@ -149,8 +148,8 @@ export default class CategorySectionLink { return countables; } - get hideCount() { - return this.currentUser?.sidebarListDestination !== UNREAD_LIST_DESTINATION; + get showCount() { + return this.currentUser?.sidebarShowCountOfNewItems; } @bind @@ -221,7 +220,7 @@ export default class CategorySectionLink { } get badgeText() { - if (this.hideCount && !this.#linkToNew) { + if (!this.showCount) { return; } @@ -235,10 +234,7 @@ export default class CategorySectionLink { } get route() { - if ( - this.currentUser?.sidebarListDestination === UNREAD_LIST_DESTINATION || - this.#linkToNew - ) { + if (this.currentUser?.sidebarLinkToFilteredList) { const activeCountable = this.activeCountable; if (activeCountable) { @@ -250,7 +246,7 @@ export default class CategorySectionLink { } get query() { - if (this.currentUser?.sidebarListDestination === UNREAD_LIST_DESTINATION) { + if (this.currentUser?.sidebarLinkToFilteredList) { const activeCountable = this.activeCountable; if (activeCountable?.routeQuery) { @@ -268,12 +264,12 @@ export default class CategorySectionLink { } get suffixValue() { - if (this.hideCount && this.activeCountable && !this.#linkToNew) { + if (!this.showCount && this.activeCountable) { return "circle"; } } - get #linkToNew() { + get #newNewViewEnabled() { return !!this.currentUser?.new_new_view_enabled; } } diff --git a/app/assets/javascripts/discourse/app/lib/sidebar/user/community-section/my-posts-section-link.js b/app/assets/javascripts/discourse/app/lib/sidebar/user/community-section/my-posts-section-link.js index cc3b9988ed1..033143f430c 100644 --- a/app/assets/javascripts/discourse/app/lib/sidebar/user/community-section/my-posts-section-link.js +++ b/app/assets/javascripts/discourse/app/lib/sidebar/user/community-section/my-posts-section-link.js @@ -2,14 +2,11 @@ import I18n from "I18n"; import { tracked } from "@glimmer/tracking"; import BaseSectionLink from "discourse/lib/sidebar/base-community-section-link"; -import { UNREAD_LIST_DESTINATION } from "discourse/controllers/preferences/navigation-menu"; const USER_DRAFTS_CHANGED_EVENT = "user-drafts:changed"; export default class MyPostsSectionLink extends BaseSectionLink { @tracked draftCount = this.currentUser?.draft_count; - @tracked hideCount = - this.currentUser?.sidebarListDestination !== UNREAD_LIST_DESTINATION; constructor() { super(...arguments); @@ -37,6 +34,10 @@ export default class MyPostsSectionLink extends BaseSectionLink { this.draftCount = this.currentUser.draft_count; } + get showCount() { + return this.currentUser.sidebarShowCountOfNewItems; + } + get name() { return "my-posts"; } @@ -81,10 +82,13 @@ export default class MyPostsSectionLink extends BaseSectionLink { } get badgeText() { - if (this._hasDraft && this.currentUser?.new_new_view_enabled) { - return this.draftCount.toString(); + if (!this.showCount || !this._hasDraft) { + return; } - if (this._hasDraft && !this.hideCount) { + + if (this.currentUser.new_new_view_enabled) { + return this.draftCount.toString(); + } else { return I18n.t("sidebar.sections.community.links.my_posts.draft_count", { count: this.draftCount, }); @@ -111,7 +115,7 @@ export default class MyPostsSectionLink extends BaseSectionLink { } get suffixValue() { - if (this._hasDraft && this.hideCount) { + if (this._hasDraft && !this.showCount) { return "circle"; } } diff --git a/app/assets/javascripts/discourse/app/lib/sidebar/user/tags-section/tag-section-link.js b/app/assets/javascripts/discourse/app/lib/sidebar/user/tags-section/tag-section-link.js index 4f5d188c8c7..0aaaf5451bd 100644 --- a/app/assets/javascripts/discourse/app/lib/sidebar/user/tags-section/tag-section-link.js +++ b/app/assets/javascripts/discourse/app/lib/sidebar/user/tags-section/tag-section-link.js @@ -4,13 +4,10 @@ import { tracked } from "@glimmer/tracking"; import { bind } from "discourse-common/utils/decorators"; import BaseTagSectionLink from "discourse/lib/sidebar/user/tags-section/base-tag-section-link"; -import { UNREAD_LIST_DESTINATION } from "discourse/controllers/preferences/navigation-menu"; export default class TagSectionLink extends BaseTagSectionLink { @tracked totalUnread = 0; @tracked totalNew = 0; - @tracked hideCount = - this.currentUser?.sidebarListDestination !== UNREAD_LIST_DESTINATION; constructor({ topicTrackingState }) { super(...arguments); @@ -24,30 +21,28 @@ export default class TagSectionLink extends BaseTagSectionLink { tagId: this.tagName, }); - if (this.totalUnread === 0 || this.#linkToNew) { + if (this.totalUnread === 0 || this.#newNewViewEnabled) { this.totalNew = this.topicTrackingState.countNew({ tagId: this.tagName, }); } } + get showCount() { + return this.currentUser?.sidebarShowCountOfNewItems; + } + get models() { return [this.tagName]; } get route() { - if (this.#linkToNew) { - if (this.#unreadAndNewCount > 0) { + if (this.currentUser?.sidebarLinkToFilteredList) { + if (this.#newNewViewEnabled && this.#unreadAndNewCount > 0) { return "tag.showNew"; - } else { - return "tag.show"; - } - } - if (this.currentUser?.sidebarListDestination === UNREAD_LIST_DESTINATION) { - if (this.totalUnread > 0) { + } else if (this.totalUnread > 0) { return "tag.showUnread"; - } - if (this.totalNew > 0) { + } else if (this.totalNew > 0) { return "tag.showNew"; } } @@ -59,17 +54,13 @@ export default class TagSectionLink extends BaseTagSectionLink { } get badgeText() { - if (this.#linkToNew) { - if (this.#unreadAndNewCount > 0) { - return this.#unreadAndNewCount.toString(); - } + if (!this.showCount) { return; } - if (this.hideCount) { - return; - } - if (this.totalUnread > 0) { + if (this.#newNewViewEnabled && this.#unreadAndNewCount > 0) { + return this.#unreadAndNewCount.toString(); + } else if (this.totalUnread > 0) { return I18n.t("sidebar.unread_count", { count: this.totalUnread, }); @@ -89,11 +80,7 @@ export default class TagSectionLink extends BaseTagSectionLink { } get suffixValue() { - if ( - this.hideCount && - (this.totalUnread || this.totalNew) && - !this.#linkToNew - ) { + if (!this.showCount && (this.totalUnread || this.totalNew)) { return "circle"; } } @@ -102,7 +89,7 @@ export default class TagSectionLink extends BaseTagSectionLink { return this.totalUnread + this.totalNew; } - get #linkToNew() { + get #newNewViewEnabled() { return !!this.currentUser?.new_new_view_enabled; } } diff --git a/app/assets/javascripts/discourse/app/models/user.js b/app/assets/javascripts/discourse/app/models/user.js index 30f327232c6..b861f48564f 100644 --- a/app/assets/javascripts/discourse/app/models/user.js +++ b/app/assets/javascripts/discourse/app/models/user.js @@ -2,15 +2,7 @@ import EmberObject, { computed, get, getProperties } from "@ember/object"; import { camelize } from "@ember/string"; import cookie, { removeCookie } from "discourse/lib/cookie"; import { defaultHomepage, escapeExpression } from "discourse/lib/utilities"; -import { - alias, - equal, - filterBy, - gt, - mapBy, - or, - readOnly, -} from "@ember/object/computed"; +import { alias, equal, filterBy, gt, mapBy, or } from "@ember/object/computed"; import getURL, { getURLWithCDN } from "discourse-common/lib/get-url"; import { A } from "@ember/array"; import Badge from "discourse/models/badge"; @@ -137,7 +129,8 @@ let userOptionFields = [ "seen_popups", "default_calendar", "bookmark_auto_delete_preference", - "sidebar_list_destination", + "sidebar_link_to_filtered_list", + "sidebar_show_count_of_new_items", ]; export function addSaveableUserOptionField(fieldName) { @@ -410,7 +403,6 @@ const User = RestModel.extend({ sidebarSections: alias("sidebar_sections"), sidebarTagNames: mapBy("sidebarTags", "name"), - sidebarListDestination: readOnly("sidebar_list_destination"), changeUsername(new_username) { return ajax(userPath(`${this.username_lower}/preferences/username`), { @@ -919,6 +911,16 @@ const User = RestModel.extend({ return !this.siteSettings.enable_discourse_connect && canDeleteAccount; }, + @dependentKeyCompat + get sidebarLinkToFilteredList() { + return this.get("user_option.sidebar_link_to_filtered_list"); + }, + + @dependentKeyCompat + get sidebarShowCountOfNewItems() { + return this.get("user_option.sidebar_show_count_of_new_items"); + }, + delete() { if (this.can_delete_account) { return ajax(userPath(this.username + ".json"), { diff --git a/app/assets/javascripts/discourse/app/routes/preferences-navigation-menu.js b/app/assets/javascripts/discourse/app/routes/preferences-navigation-menu.js index a82ac9a5815..8f01ffdfe56 100644 --- a/app/assets/javascripts/discourse/app/routes/preferences-navigation-menu.js +++ b/app/assets/javascripts/discourse/app/routes/preferences-navigation-menu.js @@ -8,12 +8,13 @@ export default RestrictedUserRoute.extend({ const props = { model: user, selectedSidebarCategories: Category.findByIds(user.sidebarCategoryIds), + newSidebarLinkToFilteredList: user.sidebarLinkToFilteredList, + newSidebarShowCountOfNewItems: user.sidebarShowCountOfNewItems, }; if (this.siteSettings.tagging_enabled) { props.selectedSidebarTagNames = user.sidebarTagNames; } - props.newSidebarListDestination = user.sidebarListDestination; controller.setProperties(props); }, diff --git a/app/assets/javascripts/discourse/app/templates/preferences/navigation-menu.hbs b/app/assets/javascripts/discourse/app/templates/preferences/navigation-menu.hbs index 2de39d91d4a..ce03f6496e5 100644 --- a/app/assets/javascripts/discourse/app/templates/preferences/navigation-menu.hbs +++ b/app/assets/javascripts/discourse/app/templates/preferences/navigation-menu.hbs @@ -46,16 +46,20 @@ "user.experimental_sidebar.navigation_section" }} -
+
- +
diff --git a/app/assets/javascripts/discourse/tests/acceptance/sidebar-plugin-api-test.js b/app/assets/javascripts/discourse/tests/acceptance/sidebar-plugin-api-test.js index 81e57e843c1..879271a56ba 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/sidebar-plugin-api-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/sidebar-plugin-api-test.js @@ -16,7 +16,6 @@ import { resetCustomCountables, } from "discourse/lib/sidebar/user/categories-section/category-section-link"; import { resetCustomTagSectionLinkPrefixIcons } from "discourse/lib/sidebar/user/tags-section/base-tag-section-link"; -import { UNREAD_LIST_DESTINATION } from "discourse/controllers/preferences/navigation-menu"; import { bind } from "discourse-common/utils/decorators"; acceptance("Sidebar - Plugin API", function (needs) { @@ -713,7 +712,10 @@ acceptance("Sidebar - Plugin API", function (needs) { ); updateCurrentUser({ - sidebar_list_destination: UNREAD_LIST_DESTINATION, + user_option: { + sidebar_link_to_filtered_list: true, + sidebar_show_count_of_new_items: true, + }, }); assert.strictEqual( diff --git a/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-categories-section-test.js b/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-categories-section-test.js index 146aa2a970e..407a681cfd0 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-categories-section-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-categories-section-test.js @@ -480,9 +480,11 @@ acceptance("Sidebar - Logged on user - Categories Section", function (needs) { ); }); - test("clicking section links - sidebar_list_destination set to unread/new and no unread or new topics", async function (assert) { + test("clicking section links - sidebar_link_to_filtered_list set to true and no unread or new topics", async function (assert) { updateCurrentUser({ - sidebar_list_destination: "unread_new", + user_option: { + sidebar_link_to_filtered_list: true, + }, }); const { category1 } = setupUserSidebarCategories(); @@ -514,7 +516,7 @@ acceptance("Sidebar - Logged on user - Categories Section", function (needs) { ); }); - test("clicking section links - sidebar_list_destination set to unread/new with new topics", async function (assert) { + test("clicking section links - sidebar_link_to_filtered_list set to true with new topics", async function (assert) { const { category1 } = setupUserSidebarCategories(); const topicTrackingState = this.container.lookup( "service:topic-tracking-state" @@ -527,7 +529,9 @@ acceptance("Sidebar - Logged on user - Categories Section", function (needs) { created_in_new_period: true, }); updateCurrentUser({ - sidebar_list_destination: "unread_new", + user_option: { + sidebar_link_to_filtered_list: true, + }, }); await visit("/"); @@ -558,7 +562,7 @@ acceptance("Sidebar - Logged on user - Categories Section", function (needs) { ); }); - test("clicking section links - sidebar_list_destination set to unread/new with new and unread topics", async function (assert) { + test("clicking section links - sidebar_link_to_filtered_list set to true with new and unread topics", async function (assert) { const { category1 } = setupUserSidebarCategories(); const topicTrackingState = this.container.lookup( "service:topic-tracking-state" @@ -579,7 +583,9 @@ acceptance("Sidebar - Logged on user - Categories Section", function (needs) { created_in_new_period: true, }); updateCurrentUser({ - sidebar_list_destination: "unread_new", + user_option: { + sidebar_link_to_filtered_list: true, + }, }); await visit("/"); @@ -754,7 +760,9 @@ acceptance("Sidebar - Logged on user - Categories Section", function (needs) { const { category1 } = setupUserSidebarCategories(); updateCurrentUser({ - sidebar_list_destination: "default", + user_option: { + sidebar_show_count_of_new_items: false, + }, }); this.container.lookup("service:topic-tracking-state").loadStates([ @@ -826,7 +834,9 @@ acceptance("Sidebar - Logged on user - Categories Section", function (needs) { const { category1, category2 } = setupUserSidebarCategories(); updateCurrentUser({ - sidebar_list_destination: "unread_new", + user_option: { + sidebar_show_count_of_new_items: true, + }, }); this.container.lookup("service:topic-tracking-state").loadStates([ @@ -995,7 +1005,7 @@ acceptance( needs.user({ new_new_view_enabled: true }); - test("count shown next to category link", async function (assert) { + test("count shown next to category link when sidebar_show_count_of_new_items is true", async function (assert) { const categories = Site.current().categories; const category1 = categories[0]; const category2 = categories[1]; @@ -1003,6 +1013,9 @@ acceptance( updateCurrentUser({ sidebar_category_ids: [category1.id, category2.id, category3.id], + user_option: { + sidebar_show_count_of_new_items: true, + }, }); this.container.lookup("service:topic-tracking-state").loadStates([ @@ -1085,7 +1098,7 @@ acceptance( ); }); - test("category link href", async function (assert) { + test("dot shown next to category link when sidebar_show_count_of_new_items is false", async function (assert) { const categories = Site.current().categories; const category1 = categories[0]; const category2 = categories[1]; @@ -1093,6 +1106,66 @@ acceptance( updateCurrentUser({ sidebar_category_ids: [category1.id, category2.id, category3.id], + user_option: { + sidebar_show_count_of_new_items: false, + }, + }); + + this.container.lookup("service:topic-tracking-state").loadStates([ + { + topic_id: 1, + highest_post_number: 1, + last_read_post_number: null, + created_at: "2022-05-11T03:09:31.959Z", + category_id: category1.id, + notification_level: null, + created_in_new_period: true, + treat_as_new_topic_start_date: "2022-05-09T03:17:34.286Z", + }, + { + topic_id: 2, + highest_post_number: 12, + last_read_post_number: 11, + created_at: "2020-02-09T09:40:02.672Z", + category_id: category2.id, + notification_level: 2, + created_in_new_period: false, + treat_as_new_topic_start_date: "2022-05-09T03:17:34.286Z", + }, + ]); + + await visit("/"); + + assert + .dom( + `.sidebar-section-link-wrapper[data-category-id="${category1.id}"] .sidebar-section-link-suffix.icon.unread` + ) + .exists("category1 has a dot because it has a new topic"); + assert + .dom( + `.sidebar-section-link-wrapper[data-category-id="${category2.id}"] .sidebar-section-link-suffix.icon.unread` + ) + .exists("category2 has a dot because it has an unread topic"); + assert + .dom( + `.sidebar-section-link-wrapper[data-category-id="${category3.id}"] .sidebar-section-link-suffix.icon.unread` + ) + .doesNotExist( + "category3 doesn't have a dot because it has no new or unread topics" + ); + }); + + test("category link href is the new topics list of the category when sidebar_link_to_filtered_list is true and there are unread/new topics in the category", async function (assert) { + const categories = Site.current().categories; + const category1 = categories[0]; + const category2 = categories[1]; + const category3 = categories[2]; + + updateCurrentUser({ + sidebar_category_ids: [category1.id, category2.id, category3.id], + user_option: { + sidebar_link_to_filtered_list: true, + }, }); this.container.lookup("service:topic-tracking-state").loadStates([ @@ -1151,5 +1224,74 @@ acceptance( "links to the latest topics list for the category because there are no unread or new topics" ); }); + + test("category link href is always the latest topics list when sidebar_link_to_filtered_list is false", async function (assert) { + const categories = Site.current().categories; + const category1 = categories[0]; + const category2 = categories[1]; + const category3 = categories[2]; + + updateCurrentUser({ + sidebar_category_ids: [category1.id, category2.id, category3.id], + user_option: { + sidebar_link_to_filtered_list: false, + }, + }); + + this.container.lookup("service:topic-tracking-state").loadStates([ + { + topic_id: 1, + highest_post_number: 1, + last_read_post_number: null, + created_at: "2022-05-11T03:09:31.959Z", + category_id: category1.id, + notification_level: null, + created_in_new_period: true, + treat_as_new_topic_start_date: "2022-05-09T03:17:34.286Z", + }, + { + topic_id: 2, + highest_post_number: 12, + last_read_post_number: 11, + created_at: "2020-02-09T09:40:02.672Z", + category_id: category2.id, + notification_level: 2, + created_in_new_period: false, + treat_as_new_topic_start_date: "2022-05-09T03:17:34.286Z", + }, + ]); + + await visit("/"); + + assert + .dom( + `.sidebar-section-link-wrapper[data-category-id="${category1.id}"] a` + ) + .hasAttribute( + "href", + "/c/meta/3", + "category1 links to the latest topics list for the category" + ); + + assert + .dom( + `.sidebar-section-link-wrapper[data-category-id="${category2.id}"] a` + ) + .hasAttribute( + "href", + "/c/howto/10", + "category2 links to the latest topics list for the category" + ); + + assert + .dom( + `.sidebar-section-link-wrapper[data-category-id="${category3.id}"] a` + ) + .hasAttribute( + "href", + "/c/feature/spec/26", + "category3 links to the latest topics list for the category" + ); + }); } ); diff --git a/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-community-section-test.js b/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-community-section-test.js index 17734586c44..6c34905b864 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-community-section-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-community-section-test.js @@ -179,9 +179,11 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) { ); }); - test("clicking on everything link - sidebar_list_destination set to unread/new and no unread or new topics", async function (assert) { + test("clicking on everything link - sidebar_link_to_filtered_list set to true and no unread or new topics", async function (assert) { updateCurrentUser({ - sidebar_list_destination: "unread_new", + user_option: { + sidebar_link_to_filtered_list: true, + }, }); await visit("/t/280"); @@ -210,7 +212,7 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) { ); }); - test("clicking on everything link - sidebar_list_destination set to unread/new with new topics", async function (assert) { + test("clicking on everything link - sidebar_link_to_filtered_list set to true with new topics", async function (assert) { const topicTrackingState = this.container.lookup( "service:topic-tracking-state" ); @@ -222,7 +224,9 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) { created_in_new_period: true, }); updateCurrentUser({ - sidebar_list_destination: "unread_new", + user_option: { + sidebar_link_to_filtered_list: true, + }, }); await visit("/t/280"); await click( @@ -251,7 +255,7 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) { ); }); - test("clicking on everything link - sidebar_list_destination set to unread/new with new and unread topics", async function (assert) { + test("clicking on everything link - sidebar_link_to_filtered_list set to true with new and unread topics", async function (assert) { const topicTrackingState = this.container.lookup( "service:topic-tracking-state" ); @@ -271,7 +275,9 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) { created_in_new_period: true, }); updateCurrentUser({ - sidebar_list_destination: "unread_new", + user_option: { + sidebar_link_to_filtered_list: true, + }, }); await visit("/t/280"); await click( @@ -666,7 +672,9 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) { test("my posts changes its text when drafts are present and new new view experiment is enabled", async function (assert) { updateCurrentUser({ - sidebar_list_destination: "unread_new", + user_option: { + sidebar_show_count_of_new_items: true, + }, new_new_view_enabled: true, }); await visit("/"); @@ -758,7 +766,9 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) { test("show suffix indicator for unread and new content on everything link", async function (assert) { updateCurrentUser({ - sidebar_list_destination: "default", + user_option: { + sidebar_show_count_of_new_items: false, + }, }); this.container.lookup("service:topic-tracking-state").loadStates([ @@ -846,7 +856,9 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) { test("new and unread count for everything link", async function (assert) { updateCurrentUser({ - sidebar_list_destination: "unread_new", + user_option: { + sidebar_show_count_of_new_items: true, + }, }); this.container.lookup("service:topic-tracking-state").loadStates([ @@ -1187,7 +1199,12 @@ acceptance( navigation_menu: "sidebar", }); - test("count shown next to the everything link", async function (assert) { + test("count is shown next to the everything link when sidebar_show_count_of_new_items is true", async function (assert) { + updateCurrentUser({ + user_option: { + sidebar_show_count_of_new_items: true, + }, + }); this.container.lookup("service:topic-tracking-state").loadStates([ { topic_id: 1, @@ -1225,14 +1242,19 @@ acceptance( assert.strictEqual( query( - ".sidebar-section[data-section-name='community'] .sidebar-section-link[data-link-name='everything'] .sidebar-section-link-content-badge" + ".sidebar-section-link[data-link-name='everything'] .sidebar-section-link-content-badge" ).textContent.trim(), "2", "count is 2 because there's 1 unread topic and 1 new topic" ); }); - test("everything link href", async function (assert) { + test("dot is shown next to the everything link when sidebar_show_count_of_new_items is false", async function (assert) { + updateCurrentUser({ + user_option: { + sidebar_show_count_of_new_items: false, + }, + }); this.container.lookup("service:topic-tracking-state").loadStates([ { topic_id: 1, @@ -1258,28 +1280,30 @@ acceptance( await visit("/"); - assert.true( - query( - ".sidebar-section[data-section-name='community'] .sidebar-section-link[data-link-name='everything']" - ).href.endsWith("/new"), - "links to /new because there are 1 new and 1 unread topics" - ); + assert + .dom( + ".sidebar-section-link[data-link-name='everything'] .sidebar-section-link-suffix.icon.unread" + ) + .exists( + "everything link has a dot because there are unread or new topics" + ); await publishToMessageBus("/unread", { topic_id: 1, message_type: "read", payload: { - last_read_post_number: 3, - highest_post_number: 3, + last_read_post_number: 1, + highest_post_number: 1, }, }); - assert.true( - query( - ".sidebar-section[data-section-name='community'] .sidebar-section-link[data-link-name='everything']" - ).href.endsWith("/new"), - "links to /new because there is 1 unread topic" - ); + assert + .dom( + ".sidebar-section-link[data-link-name='everything'] .sidebar-section-link-suffix.icon.unread" + ) + .exists( + "everything link has a dot because there are unread or new topics" + ); await publishToMessageBus("/unread", { topic_id: 2, @@ -1290,12 +1314,88 @@ acceptance( }, }); - assert.true( - query( - ".sidebar-section[data-section-name='community'] .sidebar-section-link[data-link-name='everything']" - ).href.endsWith("/latest"), - "links to /latest because there are no unread or new topics" - ); + assert + .dom( + ".sidebar-section-link[data-link-name='everything'] .sidebar-section-link-suffix.icon.unread" + ) + .doesNotExist( + "everything link no longer has a dot because there are no more unread or new topics" + ); + }); + + test("everything link's href is the new topics list when sidebar_link_to_filtered_list is true", async function (assert) { + updateCurrentUser({ + user_option: { + sidebar_link_to_filtered_list: true, + }, + }); + this.container.lookup("service:topic-tracking-state").loadStates([ + { + topic_id: 1, + highest_post_number: 1, + last_read_post_number: null, + created_at: "2022-05-11T03:09:31.959Z", + category_id: 1, + notification_level: null, + created_in_new_period: true, + treat_as_new_topic_start_date: "2022-05-09T03:17:34.286Z", + }, + { + topic_id: 2, + highest_post_number: 12, + last_read_post_number: 11, + created_at: "2020-02-09T09:40:02.672Z", + category_id: 2, + notification_level: 2, + created_in_new_period: false, + treat_as_new_topic_start_date: "2022-05-09T03:17:34.286Z", + }, + ]); + + await visit("/"); + + assert + .dom(".sidebar-section-link[data-link-name='everything']") + .hasAttribute( + "href", + "/new", + + "links to /new because there are 1 new and 1 unread topics" + ); + + await publishToMessageBus("/unread", { + topic_id: 1, + message_type: "read", + payload: { + last_read_post_number: 3, + highest_post_number: 3, + }, + }); + + assert + .dom(".sidebar-section-link[data-link-name='everything']") + .hasAttribute( + "href", + "/new", + "links to /new because there is 1 unread topic" + ); + + await publishToMessageBus("/unread", { + topic_id: 2, + message_type: "read", + payload: { + last_read_post_number: 12, + highest_post_number: 12, + }, + }); + + assert + .dom(".sidebar-section-link[data-link-name='everything']") + .hasAttribute( + "href", + "/latest", + "links to /latest because there are no unread or new topics" + ); await publishToMessageBus("/unread", { topic_id: 1, @@ -1306,12 +1406,39 @@ acceptance( }, }); - assert.true( - query( - ".sidebar-section[data-section-name='community'] .sidebar-section-link[data-link-name='everything']" - ).href.endsWith("/new"), - "links to /new because there is 1 new topic" - ); + assert + .dom(".sidebar-section-link[data-link-name='everything']") + .hasAttribute( + "href", + "/new", + "links to /new because there is 1 new topic" + ); + }); + + test("everything link's href is always the latest topics list when sidebar_link_to_filtered_list is false", async function (assert) { + updateCurrentUser({ + user_option: { + sidebar_link_to_filtered_list: false, + }, + }); + this.container.lookup("service:topic-tracking-state").loadStates([ + { + topic_id: 1, + highest_post_number: 1, + last_read_post_number: null, + created_at: "2022-05-11T03:09:31.959Z", + category_id: 1, + notification_level: null, + created_in_new_period: true, + treat_as_new_topic_start_date: "2022-05-09T03:17:34.286Z", + }, + ]); + + await visit("/"); + + assert + .dom(".sidebar-section-link[data-link-name='everything']") + .hasAttribute("href", "/latest", "everything link href is /latest"); }); } ); diff --git a/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-tags-section-test.js b/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-tags-section-test.js index 8a78344f836..b943d4c9b61 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-tags-section-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-tags-section-test.js @@ -250,9 +250,11 @@ acceptance("Sidebar - Logged on user - Tags section", function (needs) { ); }); - test("clicking tag section links - sidebar_list_destination set to unread/new and no unread or new topics", async function (assert) { + test("clicking tag section links - sidebar_link_to_filtered_list set to true and no unread or new topics", async function (assert) { updateCurrentUser({ - sidebar_list_destination: "unread_new", + user_option: { + sidebar_link_to_filtered_list: true, + }, }); await visit("/"); @@ -278,9 +280,11 @@ acceptance("Sidebar - Logged on user - Tags section", function (needs) { ); }); - test("clicking tag section links - sidebar_list_destination set to unread/new with new topics", async function (assert) { + test("clicking tag section links - sidebar_link_to_filtered_list set to true with new topics", async function (assert) { updateCurrentUser({ - sidebar_list_destination: "unread_new", + user_option: { + sidebar_link_to_filtered_list: true, + }, }); this.container.lookup("service:topic-tracking-state").loadStates([ @@ -320,9 +324,11 @@ acceptance("Sidebar - Logged on user - Tags section", function (needs) { ); }); - test("clicking tag section links - sidebar_list_destination set to unread/new with unread topics", async function (assert) { + test("clicking tag section links - sidebar_link_to_filtered_list set to true with unread topics", async function (assert) { updateCurrentUser({ - sidebar_list_destination: "unread_new", + user_option: { + sidebar_link_to_filtered_list: true, + }, }); this.container.lookup("service:topic-tracking-state").loadStates([ @@ -440,7 +446,9 @@ acceptance("Sidebar - Logged on user - Tags section", function (needs) { test("show suffix indicator for new content on tag section links", async function (assert) { updateCurrentUser({ - sidebar_list_destination: "default", + user_option: { + sidebar_show_count_of_new_items: false, + }, }); this.container.lookup("service:topic-tracking-state").loadStates([ @@ -537,7 +545,9 @@ acceptance("Sidebar - Logged on user - Tags section", function (needs) { test("new and unread count for tag section links", async function (assert) { updateCurrentUser({ - sidebar_list_destination: "unread_new", + user_option: { + sidebar_show_count_of_new_items: true, + }, }); this.container.lookup("service:topic-tracking-state").loadStates([ @@ -711,7 +721,13 @@ acceptance( ], }); - test("count shown next to tag link", async function (assert) { + test("count shown next to tag link when sidebar_show_count_of_new_items is true", async function (assert) { + updateCurrentUser({ + user_option: { + sidebar_show_count_of_new_items: true, + }, + }); + this.container.lookup("service:topic-tracking-state").loadStates([ { topic_id: 1, @@ -775,7 +791,66 @@ acceptance( ); }); - test("tag link href", async function (assert) { + test("dot shown next to tag link when sidebar_show_count_of_new_items is false", async function (assert) { + updateCurrentUser({ + user_option: { + sidebar_show_count_of_new_items: false, + }, + }); + + this.container.lookup("service:topic-tracking-state").loadStates([ + { + topic_id: 1, + highest_post_number: 1, + last_read_post_number: null, + created_at: "2022-05-11T03:09:31.959Z", + category_id: 1, + notification_level: null, + created_in_new_period: true, + treat_as_new_topic_start_date: "2022-05-09T03:17:34.286Z", + tags: ["tag1"], + }, + { + topic_id: 2, + highest_post_number: 12, + last_read_post_number: 11, + created_at: "2020-02-09T09:40:02.672Z", + category_id: 2, + notification_level: 2, + created_in_new_period: false, + treat_as_new_topic_start_date: "2022-05-09T03:17:34.286Z", + tags: ["tag2"], + }, + ]); + + await visit("/"); + + assert + .dom( + '.sidebar-section-link-wrapper[data-tag-name="tag1"] .sidebar-section-link-suffix.icon.unread' + ) + .exists("tag1 has a dot because it has a new topic"); + assert + .dom( + '.sidebar-section-link-wrapper[data-tag-name="tag2"] .sidebar-section-link-suffix.icon.unread' + ) + .exists("tag2 has a dot because it has an unread topic"); + assert + .dom( + '.sidebar-section-link-wrapper[data-tag-name="tag3"] .sidebar-section-link-suffix.icon.unread' + ) + .doesNotExist( + "tag3 doesn't have a dot because it has no new or unread topics" + ); + }); + + test("tag link href is to the new topics list when sidebar_link_to_filtered_list is true and there are unread/new topics with the tag", async function (assert) { + updateCurrentUser({ + user_option: { + sidebar_link_to_filtered_list: true, + }, + }); + this.container.lookup("service:topic-tracking-state").loadStates([ { topic_id: 1, @@ -835,5 +910,64 @@ acceptance( "links to the latest topics list for the tag because there are no unread or new topics" ); }); + + test("tag link href is always to the latest topics list when sidebar_link_to_filtered_list is false", async function (assert) { + updateCurrentUser({ + user_option: { + sidebar_link_to_filtered_list: false, + }, + }); + + this.container.lookup("service:topic-tracking-state").loadStates([ + { + topic_id: 1, + highest_post_number: 1, + last_read_post_number: null, + created_at: "2022-05-11T03:09:31.959Z", + category_id: 1, + notification_level: null, + created_in_new_period: true, + treat_as_new_topic_start_date: "2022-05-09T03:17:34.286Z", + tags: ["tag1"], + }, + { + topic_id: 2, + highest_post_number: 12, + last_read_post_number: 11, + created_at: "2020-02-09T09:40:02.672Z", + category_id: 2, + notification_level: 2, + created_in_new_period: false, + treat_as_new_topic_start_date: "2022-05-09T03:17:34.286Z", + tags: ["tag2"], + }, + ]); + + await visit("/"); + + assert + .dom('.sidebar-section-link-wrapper[data-tag-name="tag1"] a') + .hasAttribute( + "href", + "/tag/tag1", + "tag1 links to the latest topics list for the tag" + ); + + assert + .dom('.sidebar-section-link-wrapper[data-tag-name="tag2"] a') + .hasAttribute( + "href", + "/tag/tag2", + "tag2 links to the latest topics list for the tag" + ); + + assert + .dom('.sidebar-section-link-wrapper[data-tag-name="tag3"] a') + .hasAttribute( + "href", + "/tag/tag3", + "tag3 links to the latest topics list for the tag" + ); + }); } ); diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-preferences-navigation-menu-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-preferences-navigation-menu-test.js index 2ac3354aa16..c158ff983cb 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/user-preferences-navigation-menu-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/user-preferences-navigation-menu-test.js @@ -8,6 +8,8 @@ import { updateCurrentUser, } from "discourse/tests/helpers/qunit-helpers"; import selectKit from "discourse/tests/helpers/select-kit-helper"; +import Site from "discourse/models/site"; +import I18n from "I18n"; acceptance("User Preferences - Navigation Menu", function (needs) { needs.user({ @@ -45,7 +47,6 @@ acceptance("User Preferences - Navigation Menu", function (needs) { { name: "monkey", pm_only: false }, { name: "gazelle", pm_only: false }, ], - sidebar_list_destination: "unread_new", }, }); } @@ -278,4 +279,154 @@ acceptance("User Preferences - Navigation Menu", function (needs) { "contains the right request body to update user's sidebar tag links" ); }); + + test("user enabling sidebar_show_count_of_new_items preference", async function (assert) { + const categories = Site.current().categories; + const category1 = categories[0]; + + updateCurrentUser({ + sidebar_category_ids: [category1.id], + }); + + this.container.lookup("service:topic-tracking-state").loadStates([ + { + topic_id: 1, + highest_post_number: 1, + last_read_post_number: null, + created_at: "2022-05-11T03:09:31.959Z", + category_id: category1.id, + notification_level: null, + created_in_new_period: true, + treat_as_new_topic_start_date: "2022-05-09T03:17:34.286Z", + }, + ]); + + await visit("/u/eviltrout/preferences/navigation-menu"); + + assert + .dom( + '.sidebar-section-link[data-link-name="everything"] .sidebar-section-link-suffix.icon.unread' + ) + .exists("everything link has a dot before the preference is enabled"); + assert + .dom( + `.sidebar-section-link[data-link-name="everything"] .sidebar-section-link-content-badge` + ) + .doesNotExist( + "everything link doesn't have badge text before the preference is enabled" + ); + + assert + .dom( + `.sidebar-section-link-wrapper[data-category-id="${category1.id}"] .sidebar-section-link-suffix.icon.unread` + ) + .exists("category1 has a dot before the preference is enabled"); + assert + .dom( + `.sidebar-section-link-wrapper[data-category-id="${category1.id}"] .sidebar-section-link-content-badge` + ) + .doesNotExist( + "category1 doesn't have badge text before the preference is enabled" + ); + + await click( + ".preferences-navigation-menu-navigation .pref-show-count-new-items input" + ); + await click(".save-changes"); + + assert + .dom( + '.sidebar-section-link[data-link-name="everything"] .sidebar-section-link-suffix.icon.unread' + ) + .doesNotExist( + "everything link no longer has a dot after the preference is enabled" + ); + assert + .dom( + `.sidebar-section-link[data-link-name="everything"] .sidebar-section-link-content-badge` + ) + .hasText( + I18n.t("sidebar.new_count", { count: 1 }), + "everything link now has badge text after the preference is enabled" + ); + + assert + .dom( + `.sidebar-section-link-wrapper[data-category-id="${category1.id}"] .sidebar-section-link-suffix.icon.unread` + ) + .doesNotExist( + "category1 doesn't have a dot anymore after the preference is enabled" + ); + assert + .dom( + `.sidebar-section-link-wrapper[data-category-id="${category1.id}"] .sidebar-section-link-content-badge` + ) + .hasText( + I18n.t("sidebar.new_count", { count: 1 }), + "category1 now has badge text after the preference is enabled" + ); + }); + + test("user enabling sidebar_link_to_filtered_list preference", async function (assert) { + const categories = Site.current().categories; + const category1 = categories[0]; + + updateCurrentUser({ + sidebar_category_ids: [category1.id], + }); + + this.container.lookup("service:topic-tracking-state").loadStates([ + { + topic_id: 1, + highest_post_number: 1, + last_read_post_number: null, + created_at: "2022-05-11T03:09:31.959Z", + category_id: category1.id, + notification_level: null, + created_in_new_period: true, + treat_as_new_topic_start_date: "2022-05-09T03:17:34.286Z", + }, + ]); + + await visit("/u/eviltrout/preferences/navigation-menu"); + + assert + .dom('.sidebar-section-link[data-link-name="everything"]') + .hasAttribute( + "href", + "/latest", + "everything link's href is the latest topics list before the preference is enabled" + ); + assert + .dom( + `.sidebar-section-link-wrapper[data-category-id="${category1.id}"] .sidebar-section-link` + ) + .hasAttribute( + "href", + "/c/meta/3", + "category1's link href is the latest topics list of the category before the preference is enabled" + ); + + await click( + ".preferences-navigation-menu-navigation .pref-link-to-filtered-list input" + ); + await click(".save-changes"); + + assert + .dom('.sidebar-section-link[data-link-name="everything"]') + .hasAttribute( + "href", + "/new", + "everything link's href is the new topics list after the preference is enabled" + ); + assert + .dom( + `.sidebar-section-link-wrapper[data-category-id="${category1.id}"] .sidebar-section-link` + ) + .hasAttribute( + "href", + "/c/meta/3/l/new", + "category1's link href is the new topics list of the category after the preference is enabled" + ); + }); }); diff --git a/app/models/user_option.rb b/app/models/user_option.rb index 06eebd364f7..7b76591237a 100644 --- a/app/models/user_option.rb +++ b/app/models/user_option.rb @@ -3,6 +3,7 @@ class UserOption < ActiveRecord::Base self.ignored_columns = [ "disable_jump_reply", # Remove once 20210706091905 is promoted from post_deploy to regular migration + "sidebar_list_destination", # TODO(osama): Remove in January 2024 ] self.primary_key = :user_id @@ -14,12 +15,6 @@ class UserOption < ActiveRecord::Base scope :human_users, -> { where("user_id > 0") } enum default_calendar: { none_selected: 0, ics: 1, google: 2 }, _scopes: false - enum sidebar_list_destination: { - none_selected: 0, - default: 0, - unread_new: 1, - }, - _prefix: "sidebar_list" def self.ensure_consistency! sql = <<~SQL @@ -291,8 +286,9 @@ end # chat_email_frequency :integer default(1), not null # enable_experimental_sidebar :boolean default(FALSE) # seen_popups :integer is an Array -# sidebar_list_destination :integer default("none_selected"), not null # chat_header_indicator_preference :integer default(0), not null +# sidebar_link_to_filtered_list :boolean default(FALSE), not null +# sidebar_show_count_of_new_items :boolean default(FALSE), not null # # Indexes # diff --git a/app/serializers/concerns/user_sidebar_mixin.rb b/app/serializers/concerns/user_sidebar_mixin.rb index 8266a2f1f0f..a606de5ff59 100644 --- a/app/serializers/concerns/user_sidebar_mixin.rb +++ b/app/serializers/concerns/user_sidebar_mixin.rb @@ -32,18 +32,6 @@ module UserSidebarMixin sidebar_navigation_menu? end - def sidebar_list_destination - if object.user_option.sidebar_list_none_selected? - SiteSetting.default_sidebar_list_destination - else - object.user_option.sidebar_list_destination - end - end - - def include_sidebar_list_destination? - sidebar_navigation_menu? - end - def sidebar_sections object .sidebar_sections diff --git a/app/serializers/current_user_option_serializer.rb b/app/serializers/current_user_option_serializer.rb index 93c57a49049..09810ff33f7 100644 --- a/app/serializers/current_user_option_serializer.rb +++ b/app/serializers/current_user_option_serializer.rb @@ -17,7 +17,9 @@ class CurrentUserOptionSerializer < ApplicationSerializer :seen_popups, :should_be_redirected_to_top, :redirected_to_top, - :treat_as_new_topic_start_date + :treat_as_new_topic_start_date, + :sidebar_link_to_filtered_list, + :sidebar_show_count_of_new_items def likes_notifications_disabled object.likes_notifications_disabled? diff --git a/app/serializers/current_user_serializer.rb b/app/serializers/current_user_serializer.rb index a4333679c52..7290c5c5f38 100644 --- a/app/serializers/current_user_serializer.rb +++ b/app/serializers/current_user_serializer.rb @@ -66,7 +66,6 @@ class CurrentUserSerializer < BasicUserSerializer :display_sidebar_tags, :sidebar_tags, :sidebar_category_ids, - :sidebar_list_destination, :sidebar_sections, :new_new_view_enabled?, :new_edit_sidebar_categories_tags_interface_groups_enabled?, diff --git a/app/serializers/user_option_serializer.rb b/app/serializers/user_option_serializer.rb index d78dad82ebd..1eba9b30951 100644 --- a/app/serializers/user_option_serializer.rb +++ b/app/serializers/user_option_serializer.rb @@ -36,7 +36,9 @@ class UserOptionSerializer < ApplicationSerializer :skip_new_user_tips, :default_calendar, :oldest_search_log_date, - :seen_popups + :seen_popups, + :sidebar_link_to_filtered_list, + :sidebar_show_count_of_new_items def auto_track_topics_after_msecs object.auto_track_topics_after_msecs || SiteSetting.default_other_auto_track_topics_after_msecs diff --git a/app/serializers/user_serializer.rb b/app/serializers/user_serializer.rb index 91c267d9ad6..2da59c7e787 100644 --- a/app/serializers/user_serializer.rb +++ b/app/serializers/user_serializer.rb @@ -64,7 +64,6 @@ class UserSerializer < UserCardSerializer :use_logo_small_as_avatar, :sidebar_tags, :sidebar_category_ids, - :sidebar_list_destination, :display_sidebar_tags untrusted_attributes :bio_raw, :bio_cooked, :profile_background_upload_url diff --git a/app/services/user_updater.rb b/app/services/user_updater.rb index 8c740f4c0e7..b660728ef5d 100644 --- a/app/services/user_updater.rb +++ b/app/services/user_updater.rb @@ -48,8 +48,9 @@ class UserUpdater skip_new_user_tips seen_popups default_calendar - sidebar_list_destination bookmark_auto_delete_preference + sidebar_link_to_filtered_list + sidebar_show_count_of_new_items ] NOTIFICATION_SCHEDULE_ATTRS = -> do diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 7279ae28ad4..acd76ec69a0 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1211,9 +1211,9 @@ en: tags_section: "Tags Section" tags_section_instruction: "Selected tags will be displayed under Navigation Menu's tags section. If no tags are selected, the site's top tags will be displayed." navigation_section: "Navigation" - list_destination_instruction: "When there's new content in the navigation menu..." - list_destination_default: "use the default link and show a badge for new items" - list_destination_unread_new: "link to unread/new and show a count of new items" + navigation_section_instruction: "When a topic list in the navigation menu has new or unread items…" + link_to_filtered_list_checkbox_description: "Link to the filtered list" + show_count_new_items_checkbox_description: "Show a count of the new items" change: "change" featured_topic: "Featured Topic" moderator: "%{user} is a moderator" diff --git a/config/site_settings.yml b/config/site_settings.yml index 9244d50286c..55f8be4bf8a 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -2139,13 +2139,6 @@ navigation: type: tag_list default: "" client: true - default_sidebar_list_destination: - hidden: true - default: "default" - type: "list" - choices: - - "default" - - "unread_new" embedding: embed_by_username: diff --git a/db/migrate/20230618041001_add_sidebar_link_to_filtered_list_to_user_option.rb b/db/migrate/20230618041001_add_sidebar_link_to_filtered_list_to_user_option.rb new file mode 100644 index 00000000000..25bae7a2ebb --- /dev/null +++ b/db/migrate/20230618041001_add_sidebar_link_to_filtered_list_to_user_option.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class AddSidebarLinkToFilteredListToUserOption < ActiveRecord::Migration[7.0] + def change + add_column :user_options, :sidebar_link_to_filtered_list, :boolean, default: false, null: false + + execute <<~SQL + UPDATE user_options + SET sidebar_link_to_filtered_list = true + WHERE sidebar_list_destination = 1 + SQL + end +end diff --git a/db/migrate/20230618041123_add_sidebar_show_count_of_new_items_to_user_option.rb b/db/migrate/20230618041123_add_sidebar_show_count_of_new_items_to_user_option.rb new file mode 100644 index 00000000000..4ec3f496a61 --- /dev/null +++ b/db/migrate/20230618041123_add_sidebar_show_count_of_new_items_to_user_option.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddSidebarShowCountOfNewItemsToUserOption < ActiveRecord::Migration[7.0] + def change + add_column :user_options, + :sidebar_show_count_of_new_items, + :boolean, + default: false, + null: false + + execute <<~SQL + UPDATE user_options + SET sidebar_show_count_of_new_items = true + WHERE sidebar_list_destination = 1 + SQL + end +end diff --git a/db/migrate/20230620050614_remove_default_sidebar_list_destination_setting.rb b/db/migrate/20230620050614_remove_default_sidebar_list_destination_setting.rb new file mode 100644 index 00000000000..ea42a186124 --- /dev/null +++ b/db/migrate/20230620050614_remove_default_sidebar_list_destination_setting.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class RemoveDefaultSidebarListDestinationSetting < ActiveRecord::Migration[7.0] + def up + execute("DELETE FROM site_settings WHERE name = 'default_sidebar_list_destination'") + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/spec/requests/api/schemas/json/user_get_response.json b/spec/requests/api/schemas/json/user_get_response.json index a5e43be2be4..01cb1a18b35 100644 --- a/spec/requests/api/schemas/json/user_get_response.json +++ b/spec/requests/api/schemas/json/user_get_response.json @@ -771,8 +771,11 @@ "oldest_search_log_date": { "type": ["string", "null"] }, - "sidebar_list_destination": { - "type": "string" + "sidebar_link_to_filtered_list": { + "type": "boolean" + }, + "sidebar_show_count_of_new_items": { + "type": "boolean" }, "seen_popups": { "type": ["array", "null"] diff --git a/spec/serializers/user_serializer_spec.rb b/spec/serializers/user_serializer_spec.rb index f33b71431bb..bfa4ebde243 100644 --- a/spec/serializers/user_serializer_spec.rb +++ b/spec/serializers/user_serializer_spec.rb @@ -449,7 +449,6 @@ RSpec.describe UserSerializer do expect(serializer.as_json[:sidebar_category_ids]).to eq(nil) expect(serializer.as_json[:sidebar_tags]).to eq(nil) - expect(serializer.as_json[:sidebar_list_destination]).to eq(nil) expect(serializer.as_json[:display_sidebar_tags]).to eq(nil) end end diff --git a/spec/support/user_sidebar_serializer_attributes.rb b/spec/support/user_sidebar_serializer_attributes.rb index 9bf6eaa5d5c..5e8f908e3ea 100644 --- a/spec/support/user_sidebar_serializer_attributes.rb +++ b/spec/support/user_sidebar_serializer_attributes.rb @@ -7,24 +7,6 @@ RSpec.shared_examples "User Sidebar Serializer Attributes" do |serializer_klass| before { SiteSetting.navigation_menu = "sidebar" } - describe "#sidebar_list_destination" do - it "is not included when navigation menu is legacy" do - SiteSetting.navigation_menu = "legacy" - - expect(serializer.as_json[:sidebar_list_destination]).to eq(nil) - end - - it "returns choosen value or default" do - expect(serializer.as_json[:sidebar_list_destination]).to eq( - SiteSetting.default_sidebar_list_destination, - ) - - user.user_option.update!(sidebar_list_destination: "unread_new") - - expect(serializer.as_json[:sidebar_list_destination]).to eq("unread_new") - end - end - describe "#sidebar_category_ids" do fab!(:group) { Fabricate(:group) } fab!(:category) { Fabricate(:category) } diff --git a/spec/system/page_objects/pages/user_preferences_navigation_menu.rb b/spec/system/page_objects/pages/user_preferences_navigation_menu.rb index 5cc9224325e..6ea0522abcf 100644 --- a/spec/system/page_objects/pages/user_preferences_navigation_menu.rb +++ b/spec/system/page_objects/pages/user_preferences_navigation_menu.rb @@ -18,14 +18,8 @@ module PageObjects tag_selector_header.has_content?(tags.map(&:name).join(", ")) end - def has_navigation_menu_list_destination_preference?(type) - list_selector_header = - page.find( - ".preferences-navigation-menu-navigation__list-destination-selector .select-kit-header-wrapper", - ) - list_selector_header.has_content?( - I18n.t("js.user.experimental_sidebar.list_destination_#{type}"), - ) + def has_navigation_menu_preference_checked?(preference) + page.find(".#{preference} input").checked? end end end diff --git a/spec/system/viewing_navigation_menu_preferences_spec.rb b/spec/system/viewing_navigation_menu_preferences_spec.rb index 0acae658f15..0fe2220c16a 100644 --- a/spec/system/viewing_navigation_menu_preferences_spec.rb +++ b/spec/system/viewing_navigation_menu_preferences_spec.rb @@ -30,7 +30,10 @@ describe "Viewing sidebar preferences", type: :system do before { sign_in(admin) } it "should be able to view navigation menu preferences of another user" do - user.user_option.update!(sidebar_list_destination: "unread_new") + user.user_option.update!( + sidebar_link_to_filtered_list: true, + sidebar_show_count_of_new_items: true, + ) user_preferences_navigation_menu_page.visit(user) @@ -42,9 +45,12 @@ describe "Viewing sidebar preferences", type: :system do tag, tag2, ) - expect( - user_preferences_navigation_menu_page, - ).to have_navigation_menu_list_destination_preference("unread_new") + expect(user_preferences_navigation_menu_page).to have_navigation_menu_preference_checked( + "pref-show-count-new-items", + ) + expect(user_preferences_navigation_menu_page).to have_navigation_menu_preference_checked( + "pref-link-to-filtered-list", + ) end end end