FEATURE: anonymous sidebar categories and tags (#18038)
Default sidebar tags for not authenticated users can be defined in admin panel. Otherwise, top 5 categories and tags are taken. Optionally, if categories are set up in permanent order, then the first 5 categories are taken.
This commit is contained in:
parent
1d1a7db182
commit
2d58996a3b
|
@ -0,0 +1,22 @@
|
||||||
|
<Sidebar::Section
|
||||||
|
@sectionName="categories"
|
||||||
|
@headerLinkText={{i18n "sidebar.sections.categories.header_link_text"}} >
|
||||||
|
|
||||||
|
{{#each this.sectionLinks as |sectionLink|}}
|
||||||
|
<Sidebar::SectionLink
|
||||||
|
@route={{sectionLink.route}}
|
||||||
|
@title={{sectionLink.title}}
|
||||||
|
@content={{sectionLink.text}}
|
||||||
|
@currentWhen={{sectionLink.currentWhen}}
|
||||||
|
@model={{sectionLink.model}}
|
||||||
|
@prefixType={{sectionLink.prefixType}}
|
||||||
|
@prefixValue={{sectionLink.prefixValue}}
|
||||||
|
@prefixColor={{sectionLink.prefixColor}} >
|
||||||
|
</Sidebar::SectionLink>
|
||||||
|
{{/each}}
|
||||||
|
<Sidebar::SectionLink
|
||||||
|
@linkName="more-categories"
|
||||||
|
@content={{i18n "sidebar.more"}}
|
||||||
|
@route="discovery.categories"
|
||||||
|
/>
|
||||||
|
</Sidebar::Section>
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { cached } from "@glimmer/tracking";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import Component from "@glimmer/component";
|
||||||
|
import CategorySectionLink from "discourse/lib/sidebar/user/categories-section/category-section-link";
|
||||||
|
|
||||||
|
export default class SidebarAnonymousCategoriesSection extends Component {
|
||||||
|
@service topicTrackingState;
|
||||||
|
@service site;
|
||||||
|
@service siteSettings;
|
||||||
|
|
||||||
|
@cached
|
||||||
|
get sectionLinks() {
|
||||||
|
let categories = this.site.categoriesList;
|
||||||
|
|
||||||
|
if (this.siteSettings.default_sidebar_categories) {
|
||||||
|
const defaultCategoryIds = this.siteSettings.default_sidebar_categories
|
||||||
|
.split("|")
|
||||||
|
.map((categoryId) => parseInt(categoryId, 10));
|
||||||
|
|
||||||
|
categories = categories.filter((category) =>
|
||||||
|
defaultCategoryIds.includes(category.id)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
categories = categories
|
||||||
|
.filter((category) => !category.parent_category_id)
|
||||||
|
.slice(0, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
return categories.map((category) => {
|
||||||
|
return new CategorySectionLink({
|
||||||
|
category,
|
||||||
|
topicTrackingState: this.topicTrackingState,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,6 @@
|
||||||
<div class="sidebar-sections sidebar-sections-anonymous">
|
<div class="sidebar-sections sidebar-sections-anonymous">
|
||||||
{{!-- add sections for anonymous user --}}
|
<Sidebar::Anonymous::CategoriesSection />
|
||||||
|
{{#if this.siteSettings.tagging_enabled}}
|
||||||
|
<Sidebar::Anonymous::TagsSection />
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
import Component from "@glimmer/component";
|
import Component from "@glimmer/component";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
|
||||||
export default class SidebarAnonymousSections extends Component {}
|
export default class SidebarAnonymousSections extends Component {
|
||||||
|
@service siteSettings;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
<Sidebar::Section
|
||||||
|
@sectionName="tags"
|
||||||
|
@headerLinkText={{i18n "sidebar.sections.tags.header_link_text"}} >
|
||||||
|
|
||||||
|
{{#each this.sectionLinks as |sectionLink|}}
|
||||||
|
<Sidebar::SectionLink
|
||||||
|
@route={{sectionLink.route}}
|
||||||
|
@content={{sectionLink.text}}
|
||||||
|
@currentWhen={{sectionLink.currentWhen}}
|
||||||
|
@models={{sectionLink.models}} >
|
||||||
|
</Sidebar::SectionLink>
|
||||||
|
{{/each}}
|
||||||
|
<Sidebar::SectionLink
|
||||||
|
@linkName="more-tags"
|
||||||
|
@content={{i18n "sidebar.more"}}
|
||||||
|
@route="tags"
|
||||||
|
/>
|
||||||
|
</Sidebar::Section>
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { cached } from "@glimmer/tracking";
|
||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import TagSectionLink from "discourse/lib/sidebar/user/tags-section/tag-section-link";
|
||||||
|
|
||||||
|
export default class SidebarAnonymousTagsSection extends Component {
|
||||||
|
@service router;
|
||||||
|
@service topicTrackingState;
|
||||||
|
@service site;
|
||||||
|
|
||||||
|
@cached
|
||||||
|
get sectionLinks() {
|
||||||
|
let tags;
|
||||||
|
|
||||||
|
if (this.site.anonymous_default_sidebar_tags) {
|
||||||
|
tags = this.site.anonymous_default_sidebar_tags;
|
||||||
|
} else {
|
||||||
|
tags = this.site.top_tags.slice(0, 5);
|
||||||
|
}
|
||||||
|
return tags.map((tagName) => {
|
||||||
|
return new TagSectionLink({
|
||||||
|
tagName,
|
||||||
|
topicTrackingState: this.topicTrackingState,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,14 +38,14 @@ export default class SidebarUserTagsSection extends Component {
|
||||||
if (tag.pm_only) {
|
if (tag.pm_only) {
|
||||||
links.push(
|
links.push(
|
||||||
new PMTagSectionLink({
|
new PMTagSectionLink({
|
||||||
tag,
|
tagName: tag.name,
|
||||||
currentUser: this.currentUser,
|
currentUser: this.currentUser,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
links.push(
|
links.push(
|
||||||
new TagSectionLink({
|
new TagSectionLink({
|
||||||
tag,
|
tagName: tag.name,
|
||||||
topicTrackingState: this.topicTrackingState,
|
topicTrackingState: this.topicTrackingState,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
export default class PMTagSectionLink {
|
export default class PMTagSectionLink {
|
||||||
constructor({ tag, currentUser }) {
|
constructor({ tagName, currentUser }) {
|
||||||
this.tag = tag;
|
this.tagName = tagName;
|
||||||
this.currentUser = currentUser;
|
this.currentUser = currentUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
get name() {
|
get name() {
|
||||||
return this.tag.name;
|
return this.tagName;
|
||||||
}
|
}
|
||||||
|
|
||||||
get models() {
|
get models() {
|
||||||
return [this.currentUser, this.tag.name];
|
return [this.currentUser, this.tagName];
|
||||||
}
|
}
|
||||||
|
|
||||||
get route() {
|
get route() {
|
||||||
|
@ -17,6 +17,6 @@ export default class PMTagSectionLink {
|
||||||
}
|
}
|
||||||
|
|
||||||
get text() {
|
get text() {
|
||||||
return this.tag.name;
|
return this.tagName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,8 @@ export default class TagSectionLink {
|
||||||
@tracked totalUnread = 0;
|
@tracked totalUnread = 0;
|
||||||
@tracked totalNew = 0;
|
@tracked totalNew = 0;
|
||||||
|
|
||||||
constructor({ tag, topicTrackingState }) {
|
constructor({ tagName, topicTrackingState }) {
|
||||||
this.tagName = tag.name;
|
this.tagName = tagName;
|
||||||
this.topicTrackingState = topicTrackingState;
|
this.topicTrackingState = topicTrackingState;
|
||||||
this.refreshCounts();
|
this.refreshCounts();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
import { test } from "qunit";
|
||||||
|
import { visit } from "@ember/test-helpers";
|
||||||
|
import {
|
||||||
|
acceptance,
|
||||||
|
exists,
|
||||||
|
queryAll,
|
||||||
|
} from "discourse/tests/helpers/qunit-helpers";
|
||||||
|
|
||||||
|
acceptance("Sidebar - Anonymous Categories Section", function (needs) {
|
||||||
|
needs.settings({
|
||||||
|
enable_experimental_sidebar_hamburger: true,
|
||||||
|
enable_sidebar: true,
|
||||||
|
suppress_uncategorized_badge: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
test("category section links", async function (assert) {
|
||||||
|
await visit("/");
|
||||||
|
|
||||||
|
const categories = queryAll(
|
||||||
|
".sidebar-section-categories .sidebar-section-link-wrapper"
|
||||||
|
);
|
||||||
|
assert.strictEqual(categories.length, 6);
|
||||||
|
assert.strictEqual(categories[0].textContent.trim(), "support");
|
||||||
|
assert.strictEqual(categories[1].textContent.trim(), "bug");
|
||||||
|
assert.strictEqual(categories[2].textContent.trim(), "feature");
|
||||||
|
assert.strictEqual(categories[3].textContent.trim(), "dev");
|
||||||
|
assert.strictEqual(categories[4].textContent.trim(), "ux");
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
exists("a.sidebar-section-link-more-categories"),
|
||||||
|
"more link is visible"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("default sidebar categories", async function (assert) {
|
||||||
|
this.siteSettings.default_sidebar_categories = "3|13|1";
|
||||||
|
await visit("/");
|
||||||
|
|
||||||
|
const categories = queryAll(
|
||||||
|
".sidebar-section-categories .sidebar-section-link-wrapper"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.strictEqual(categories.length, 4);
|
||||||
|
assert.strictEqual(categories[0].textContent.trim(), "bug");
|
||||||
|
assert.strictEqual(categories[1].textContent.trim(), "meta");
|
||||||
|
assert.strictEqual(categories[2].textContent.trim(), "blog");
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
exists("a.sidebar-section-link-more-categories"),
|
||||||
|
"more link is visible"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,89 @@
|
||||||
|
import { test } from "qunit";
|
||||||
|
import { visit } from "@ember/test-helpers";
|
||||||
|
import {
|
||||||
|
acceptance,
|
||||||
|
exists,
|
||||||
|
queryAll,
|
||||||
|
} from "discourse/tests/helpers/qunit-helpers";
|
||||||
|
|
||||||
|
acceptance("Sidebar - Anonymous Tags Section", function (needs) {
|
||||||
|
needs.settings({
|
||||||
|
enable_experimental_sidebar_hamburger: true,
|
||||||
|
enable_sidebar: true,
|
||||||
|
suppress_uncategorized_badge: false,
|
||||||
|
tagging_enabled: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
needs.site({
|
||||||
|
top_tags: ["design", "development", "fun"],
|
||||||
|
});
|
||||||
|
|
||||||
|
test("tag section links", async function (assert) {
|
||||||
|
await visit("/");
|
||||||
|
|
||||||
|
const categories = queryAll(
|
||||||
|
".sidebar-section-tags .sidebar-section-link-wrapper"
|
||||||
|
);
|
||||||
|
assert.strictEqual(categories.length, 4);
|
||||||
|
assert.strictEqual(categories[0].textContent.trim(), "design");
|
||||||
|
assert.strictEqual(categories[1].textContent.trim(), "development");
|
||||||
|
assert.strictEqual(categories[2].textContent.trim(), "fun");
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
exists("a.sidebar-section-link-more-tags"),
|
||||||
|
"more link is visible"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
acceptance("Sidebar - Anonymous Tags Section - default tags", function (needs) {
|
||||||
|
needs.settings({
|
||||||
|
enable_experimental_sidebar_hamburger: true,
|
||||||
|
enable_sidebar: true,
|
||||||
|
suppress_uncategorized_badge: false,
|
||||||
|
tagging_enabled: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
needs.site({
|
||||||
|
top_tags: ["design", "development", "fun"],
|
||||||
|
anonymous_default_sidebar_tags: ["random", "meta"],
|
||||||
|
});
|
||||||
|
|
||||||
|
test("tag section links", async function (assert) {
|
||||||
|
await visit("/");
|
||||||
|
|
||||||
|
const categories = queryAll(
|
||||||
|
".sidebar-section-tags .sidebar-section-link-wrapper"
|
||||||
|
);
|
||||||
|
assert.strictEqual(categories.length, 3);
|
||||||
|
assert.strictEqual(categories[0].textContent.trim(), "random");
|
||||||
|
assert.strictEqual(categories[1].textContent.trim(), "meta");
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
exists("a.sidebar-section-link-more-tags"),
|
||||||
|
"more link is visible"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
acceptance(
|
||||||
|
"Sidebar - Anonymous Tags Section - Tagging disabled",
|
||||||
|
function (needs) {
|
||||||
|
needs.settings({
|
||||||
|
enable_experimental_sidebar_hamburger: true,
|
||||||
|
enable_sidebar: true,
|
||||||
|
suppress_uncategorized_badge: false,
|
||||||
|
tagging_enabled: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
needs.site({
|
||||||
|
top_tags: ["design", "development", "fun"],
|
||||||
|
});
|
||||||
|
|
||||||
|
test("tag section links", async function (assert) {
|
||||||
|
await visit("/");
|
||||||
|
|
||||||
|
assert.ok(!exists(".sidebar-section-tags"), "section is not visible");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
|
@ -1670,6 +1670,15 @@ class User < ActiveRecord::Base
|
||||||
categories_ids
|
categories_ids
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def sidebar_tags
|
||||||
|
return custom_sidebar_tags if custom_sidebar_tags.present?
|
||||||
|
if SiteSetting.default_sidebar_tags.present?
|
||||||
|
tag_names = SiteSetting.default_sidebar_tags.split("|") - DiscourseTagging.hidden_tag_names(guardian)
|
||||||
|
return Tag.where(name: tag_names)
|
||||||
|
end
|
||||||
|
Tag.none
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def badge_grant
|
def badge_grant
|
||||||
|
@ -1962,15 +1971,6 @@ class User < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def sidebar_tags
|
|
||||||
return custom_sidebar_tags if custom_sidebar_tags.present?
|
|
||||||
if SiteSetting.default_sidebar_tags.present?
|
|
||||||
tag_names = SiteSetting.default_sidebar_tags.split("|") - DiscourseTagging.hidden_tag_names(guardian)
|
|
||||||
return Tag.where(name: tag_names)
|
|
||||||
end
|
|
||||||
[]
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.ensure_consistency!
|
def self.ensure_consistency!
|
||||||
DB.exec <<~SQL
|
DB.exec <<~SQL
|
||||||
UPDATE users
|
UPDATE users
|
||||||
|
|
|
@ -35,7 +35,8 @@ class SiteSerializer < ApplicationSerializer
|
||||||
:categories,
|
:categories,
|
||||||
:markdown_additional_options,
|
:markdown_additional_options,
|
||||||
:displayed_about_plugin_stat_groups,
|
:displayed_about_plugin_stat_groups,
|
||||||
:show_welcome_topic_banner
|
:show_welcome_topic_banner,
|
||||||
|
:anonymous_default_sidebar_tags
|
||||||
)
|
)
|
||||||
|
|
||||||
has_many :archetypes, embed: :objects, serializer: ArchetypeSerializer
|
has_many :archetypes, embed: :objects, serializer: ArchetypeSerializer
|
||||||
|
@ -218,6 +219,14 @@ class SiteSerializer < ApplicationSerializer
|
||||||
Site.show_welcome_topic_banner?(scope)
|
Site.show_welcome_topic_banner?(scope)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def anonymous_default_sidebar_tags
|
||||||
|
User.new.sidebar_tags.pluck(:name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def include_anonymous_default_sidebar_tags?
|
||||||
|
SiteSetting.default_sidebar_tags.present?
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def ordered_flags(flags)
|
def ordered_flags(flags)
|
||||||
|
|
|
@ -124,4 +124,15 @@ RSpec.describe SiteSerializer do
|
||||||
serialized = described_class.new(Site.new(admin_guardian), scope: admin_guardian, root: false).as_json
|
serialized = described_class.new(Site.new(admin_guardian), scope: admin_guardian, root: false).as_json
|
||||||
expect(serialized[:show_welcome_topic_banner]).to eq(true)
|
expect(serialized[:show_welcome_topic_banner]).to eq(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'includes anonymous_default_sidebar_tags' do
|
||||||
|
Fabricate(:tag, name: "dev")
|
||||||
|
Fabricate(:tag, name: "random")
|
||||||
|
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
|
||||||
|
expect(serialized[:anonymous_default_sidebar_tags]).to eq(nil)
|
||||||
|
|
||||||
|
SiteSetting.default_sidebar_tags = "dev|random"
|
||||||
|
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
|
||||||
|
expect(serialized[:anonymous_default_sidebar_tags]).to eq(["dev", "random"])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue