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">
|
||||
{{!-- add sections for anonymous user --}}
|
||||
<Sidebar::Anonymous::CategoriesSection />
|
||||
{{#if this.siteSettings.tagging_enabled}}
|
||||
<Sidebar::Anonymous::TagsSection />
|
||||
{{/if}}
|
||||
</div>
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
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) {
|
||||
links.push(
|
||||
new PMTagSectionLink({
|
||||
tag,
|
||||
tagName: tag.name,
|
||||
currentUser: this.currentUser,
|
||||
})
|
||||
);
|
||||
} else {
|
||||
links.push(
|
||||
new TagSectionLink({
|
||||
tag,
|
||||
tagName: tag.name,
|
||||
topicTrackingState: this.topicTrackingState,
|
||||
})
|
||||
);
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
export default class PMTagSectionLink {
|
||||
constructor({ tag, currentUser }) {
|
||||
this.tag = tag;
|
||||
constructor({ tagName, currentUser }) {
|
||||
this.tagName = tagName;
|
||||
this.currentUser = currentUser;
|
||||
}
|
||||
|
||||
get name() {
|
||||
return this.tag.name;
|
||||
return this.tagName;
|
||||
}
|
||||
|
||||
get models() {
|
||||
return [this.currentUser, this.tag.name];
|
||||
return [this.currentUser, this.tagName];
|
||||
}
|
||||
|
||||
get route() {
|
||||
|
@ -17,6 +17,6 @@ export default class PMTagSectionLink {
|
|||
}
|
||||
|
||||
get text() {
|
||||
return this.tag.name;
|
||||
return this.tagName;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,8 @@ export default class TagSectionLink {
|
|||
@tracked totalUnread = 0;
|
||||
@tracked totalNew = 0;
|
||||
|
||||
constructor({ tag, topicTrackingState }) {
|
||||
this.tagName = tag.name;
|
||||
constructor({ tagName, topicTrackingState }) {
|
||||
this.tagName = tagName;
|
||||
this.topicTrackingState = topicTrackingState;
|
||||
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
|
||||
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
|
||||
|
||||
def badge_grant
|
||||
|
@ -1962,15 +1971,6 @@ class User < ActiveRecord::Base
|
|||
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!
|
||||
DB.exec <<~SQL
|
||||
UPDATE users
|
||||
|
|
|
@ -35,7 +35,8 @@ class SiteSerializer < ApplicationSerializer
|
|||
:categories,
|
||||
:markdown_additional_options,
|
||||
:displayed_about_plugin_stat_groups,
|
||||
:show_welcome_topic_banner
|
||||
:show_welcome_topic_banner,
|
||||
:anonymous_default_sidebar_tags
|
||||
)
|
||||
|
||||
has_many :archetypes, embed: :objects, serializer: ArchetypeSerializer
|
||||
|
@ -218,6 +219,14 @@ class SiteSerializer < ApplicationSerializer
|
|||
Site.show_welcome_topic_banner?(scope)
|
||||
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
|
||||
|
||||
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
|
||||
expect(serialized[:show_welcome_topic_banner]).to eq(true)
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue