diff --git a/assets/javascripts/discourse/components/knowledge-explorer-category.js.es6 b/assets/javascripts/discourse/components/knowledge-explorer-category.js.es6 new file mode 100644 index 0000000..3267555 --- /dev/null +++ b/assets/javascripts/discourse/components/knowledge-explorer-category.js.es6 @@ -0,0 +1,12 @@ +import { default as computed } from "ember-addons/ember-computed-decorators"; + +export default Ember.Component.extend({ + @computed("category") + categoryName(category) { + return this.site.categories.findBy("id", category.id).name; + }, + click() { + this.selectCategory(this.category); + return false; + } +}); diff --git a/assets/javascripts/discourse/controllers/knowledge-explorer.js.es6 b/assets/javascripts/discourse/controllers/knowledge-explorer.js.es6 index df20433..9a09e29 100644 --- a/assets/javascripts/discourse/controllers/knowledge-explorer.js.es6 +++ b/assets/javascripts/discourse/controllers/knowledge-explorer.js.es6 @@ -16,7 +16,7 @@ function mergeCategories(results) { export default Ember.Controller.extend({ application: Ember.inject.controller(), queryParams: { - filterCategory: "category", + filterCategories: "category", filterTags: "tags", searchTerm: "search", selectedTopic: "topic" @@ -25,10 +25,11 @@ export default Ember.Controller.extend({ isLoadingMore: false, loadMoreUrl: Ember.computed.alias("model.topics.load_more_url"), isTopicLoading: false, + categories: Ember.computed.readOnly("model.categories"), topics: Ember.computed.alias("model.topics.topic_list.topics"), tags: Ember.computed.readOnly("model.tags"), filterTags: null, - filterCategory: null, + filterCategories: null, searchTerm: null, selectedTopic: null, topic: null, @@ -93,6 +94,26 @@ export default Ember.Controller.extend({ this.send("refreshModel"); }, + updateSelectedCategories(category) { + let filter = this.filterCategories; + if (filter && filter.includes(category.id)) { + filter = filter + .replace(category.id, "") + .replace("|", "|") + .replace(/^\|+|\|+$/g, ""); + } else if (filter) { + filter = `${filter}|${category.id}`; + } else { + filter = category.id; + } + + this.setProperties({ + filterCategories: filter, + selectedTopic: null + }); + + this.send("refreshModel"); + }, performSearch(term) { if (term === "") { @@ -134,7 +155,7 @@ export default Ember.Controller.extend({ this.set("isLoading", true); const params = this.getProperties( - "filterCategory", + "filterCategories", "filterTags", "searchTerm" ); diff --git a/assets/javascripts/discourse/models/knowledge-explorer.js.es6 b/assets/javascripts/discourse/models/knowledge-explorer.js.es6 index c7b7712..7383f3b 100644 --- a/assets/javascripts/discourse/models/knowledge-explorer.js.es6 +++ b/assets/javascripts/discourse/models/knowledge-explorer.js.es6 @@ -3,6 +3,8 @@ import { ajax } from "discourse/lib/ajax"; export default { list(params) { let filters = []; + if (params.filterCategories) + filters.push(`category=${params.filterCategories}`); if (params.filterTags) filters.push(`tags=${params.filterTags}`); if (params.searchTerm) filters.push(`search=${params.searchTerm}`); if (params.page) filters.push(`page=${params.page}`); diff --git a/assets/javascripts/discourse/templates/components/knowledge-explorer-category.hbs b/assets/javascripts/discourse/templates/components/knowledge-explorer-category.hbs new file mode 100644 index 0000000..1f3185f --- /dev/null +++ b/assets/javascripts/discourse/templates/components/knowledge-explorer-category.hbs @@ -0,0 +1,10 @@ +
+ {{#unless category.active}} + {{d-icon "plus"}} + {{/unless}} + {{categoryName}} + ({{category.count}}) + {{#if category.active}} + {{d-icon "times-circle"}} + {{/if}} +
diff --git a/assets/javascripts/discourse/templates/knowledge-explorer.hbs b/assets/javascripts/discourse/templates/knowledge-explorer.hbs index 0cc3c9c..b729ec6 100644 --- a/assets/javascripts/discourse/templates/knowledge-explorer.hbs +++ b/assets/javascripts/discourse/templates/knowledge-explorer.hbs @@ -5,13 +5,25 @@ }} {{#conditional-loading-spinner condition=isLoading}}
-
- {{#each tags as |tag|}} - {{knowledge-explorer-tag - tag=tag - selectTag=(action "updateSelectedTags") - }} - {{/each}} +
+
+

{{i18n 'knowledge_explorer.categories'}}

+ {{#each categories as |category|}} + {{knowledge-explorer-category + category=category + selectCategory=(action "updateSelectedCategories") + }} + {{/each}} +
+
+

{{i18n 'knowledge_explorer.tags'}}

+ {{#each tags as |tag|}} + {{knowledge-explorer-tag + tag=tag + selectTag=(action "updateSelectedTags") + }} + {{/each}} +
{{#if selectedTopic}} {{#conditional-loading-spinner condition=isTopicLoading}} diff --git a/assets/stylesheets/common/knowledge-explorer.scss b/assets/stylesheets/common/knowledge-explorer.scss index 830d2fa..f7ed760 100644 --- a/assets/stylesheets/common/knowledge-explorer.scss +++ b/assets/stylesheets/common/knowledge-explorer.scss @@ -28,13 +28,15 @@ padding-left: 10px; } } - .knowledge-explorer-tags { + .knowledge-explorer-filters { flex-basis: 25%; + } + .knowledge-explorer-tags, .knowledge-explorer-categories { padding: 10px 10px 10px 0; a { color: $primary; } - .knowledge-explorer-tag { + .knowledge-explorer-tag, .knowledge-explorer-category { display: flex; align-items: center; cursor: pointer; diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index ee0e108..c3ced8b 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -2,6 +2,8 @@ en: js: knowledge_explorer: title: "Knowledge Explorer" + categories: "Categories" + tags: "Tags" search: results: one: "%{count} result found" diff --git a/lib/knowledge_explorer/query.rb b/lib/knowledge_explorer/query.rb index 5c8d123..b3e21a8 100644 --- a/lib/knowledge_explorer/query.rb +++ b/lib/knowledge_explorer/query.rb @@ -25,7 +25,7 @@ module KnowledgeExplorer # filter results by selected category if @filters[:category].present? - results = results.where('category_id IN (?)', @filters[:category]) + results = results.where('category_id IN (?)', @filters[:category].split('|')) end # filter results by selected tags @@ -50,6 +50,7 @@ module KnowledgeExplorer end tags = tag_count(results) + categories = categories_count(results) results_length = results.length @@ -75,7 +76,7 @@ module KnowledgeExplorer topic_list['load_more_url'] = nil end - { tags: tags, topics: topic_list } + { tags: tags, categories: categories, topics: topic_list } end def tag_count(results) @@ -96,6 +97,22 @@ module KnowledgeExplorer tags.sort_by { |tag| [tag[:active] ? 0 : 1, -tag[:count]] } end + def categories_count(results) + categories = [] + + results.each do |topic| + active = @filters[:category].include?(topic.category_id.to_s) if @filters[:category] + if categories.none? { |item| item[:id] == topic.category_id } + categories << { id: topic.category_id, count: 1, active: active || false } + else + category_index = categories.index(categories.find { |item| item[:id] == topic.category_id }) + categories[category_index][:count] += 1 + end + end + + categories.sort_by { |category| [category[:active] ? 0 : 1, -category[:count]] } + end + def load_more_url filters = [] diff --git a/spec/requests/knowledge_explorer_controller_spec.rb b/spec/requests/knowledge_explorer_controller_spec.rb index af8f767..a6e6cb6 100644 --- a/spec/requests/knowledge_explorer_controller_spec.rb +++ b/spec/requests/knowledge_explorer_controller_spec.rb @@ -63,7 +63,7 @@ describe KnowledgeExplorer::KnowledgeExplorerController do end context 'when filtering by tag' do - it 'should return a filtered list' do + it 'should return a list filtered by tag' do get '/knowledge-explorer.json?tags=test' expect(response.status).to eq(200) @@ -76,5 +76,40 @@ describe KnowledgeExplorer::KnowledgeExplorerController do expect(topics.size).to eq(1) end end + + context 'when filtering by category' do + let!(:category2) { Fabricate(:category) } + let!(:topic3) { Fabricate(:topic, category: category2) } + + before do + SiteSetting.knowledge_explorer_categories = "#{category.id}|#{category2.id}" + end + + it 'should return a list filtered by category' do + get "/knowledge-explorer.json?category=#{category2.id}" + + expect(response.status).to eq(200) + + json = JSON.parse(response.body) + categories = json['categories'] + topics = json['topics']['topic_list']['topics'] + + expect(categories.size).to eq(1) + expect(topics.size).to eq(1) + end + end + + context 'when searching' do + it 'should return a list filtered by search term in title' do + get "/knowledge-explorer.json?search=topic 1" + + expect(response.status).to eq(200) + + json = JSON.parse(response.body) + topics = json['topics']['topic_list']['topics'] + + expect(topics.size).to eq(1) + end + end end end