Skip to content
Permalink
Browse files

REFACTOR: Handle queries in more robust, customizable way

* Create custom query lib file

* Get topic list by category

* Get topic list with both categories and tags

* Count tags and pass back to controller in object

* Filter topic list by param-passed tag list

* FIX: Correctly serialize topic list data

* Filter results by search term (title only

* Debug commit

* Working multi-tag filtering

* FIX: case insensitive search terms

* Begin refactor of front end for new api changes

* REFACTOR: Use model for refreshing data
Instead of just using a route, which introduces full page refreshes, use
the route to pull the data initially, then update it using a model as to
refresh only the relevant parts of the page.

* Working topic load

* FIX: Visual alignment

* Refactor tests to follow new patterns

* Fixes suggested by eviltrout

* FEATURE: Load more topics

* FIX: Paginate records on return to the front end in a better fashion

* FIX: Prevent loadMore while loading more

* Fix pagination of topics to truncate list properly

* Inherit rubocop from discourse

* Make rubocop happynated

* Set list to unordered
  • Loading branch information...
justindirose committed Oct 31, 2019
1 parent 1257f13 commit a34e4468c112a904d5678eeade5bea07df185a87
@@ -0,0 +1 @@
.rubocop-https---raw-githubusercontent-com-discourse-discourse-master--rubocop-yml
@@ -0,0 +1 @@
inherit_from: https://raw.githubusercontent.com/discourse/discourse/master/.rubocop.yml
@@ -3,135 +3,18 @@
module KnowledgeExplorer
class KnowledgeExplorerController < ApplicationController
requires_plugin 'knowledge-explorer'
before_action :init_guardian

def index

filters = {
tags: params[:tags],
category: params[:category]
category: params[:category],
search_term: params[:search],
page: params[:page]
}

if filters[:category]
category_topic_lists = get_topics_from_categories(category_by_filter(filters[:category]))
else
category_topic_lists = get_topics_from_categories(knowledge_explorer_categories)
end

tag_topic_lists = get_topics_from_tags(knowledge_explorer_tags)

# Deduplicate results

topics = []

category_topic_lists.each do |list|
list[:topic_list][:topics].each do |t|
if topics.none?{|item| item[:id] == t[:id]}
if t[:id] != Category.find(t[:category_id]).topic_id
topics << t
end
end
end
end
tag_topic_lists.each do |list|
list[:topic_list][:topics].each do |t|
if topics.none?{|item| item[:id] == t[:id]}
topics << t
end
end
end

if filters[:tags]
tag_filter = filters[:tags].split(' ')
topics = topics.select { |topic| (topic[:tags] & tag_filter).size >= 1}
end

topics = count_tags(topics)

render json: topics
end

def get_topics_from_categories(categories)
category_topic_lists = []

categories.each do |c|
if topic_list = TopicQuery.new(current_user, category: c.id, no_subcategories: true).list_latest
category_topic_lists << TopicListSerializer.new(topic_list, scope: @guardian).as_json
end
end

category_topic_lists
end

def get_topics_from_tags(tags)
tag_topic_lists = []

tags.each do |t|
if topic_list = TopicQuery.new(current_user, tags: t.name).list_latest
tag_topic_lists << TopicListSerializer.new(topic_list, scope: @guardian).as_json
end
end

tag_topic_lists
end

def count_tags(topics)
tags = []

topics.each do |topic|
topic[:tags].each do |tag|
if params[:tags]
active = params[:tags].include?(tag)
end
if tags.none? { |item| item[:id].to_s == tag }
tags << { id: tag, count: 1 , active: active || false }
else
tag_index = tags.index(tags.find { |item| item[:id].to_s == tag })
tags[tag_index][:count] += 1
end
end
end

{ tags: tags, topics: topics }
end

private

def init_guardian
@guardian = Guardian.new(current_user)
end

def knowledge_explorer_categories
selected_categories = SiteSetting.knowledge_explorer_categories.split("|")

if selected_categories
categories = Category.where('id IN (?)', selected_categories)

return categories.select { |c| @guardian.can_see_category?(c) }
end
end

def knowledge_explorer_tags
selected_tags = SiteSetting.knowledge_explorer_tags.split("|")

if selected_tags
return Tag.where('name IN (?)', selected_tags)
end
end

def category_by_filter(category_filter)
selected_category = category_filter

category = Category.where('slug IN (?)', selected_category)

category.select { |c| @guardian.can_see_category?(c) }
end
query = KnowledgeExplorer::Query.new(current_user, filters).list

def tags_by_filter(tags)
selected_tags = tags.split(' ')
if (selected_tags)
return Tag.where('name IN (?)', selected_tags)
end
render json: query
end
end
end
@@ -2,64 +2,117 @@ import {
default as computed,
observes
} from "ember-addons/ember-computed-decorators";
import knowledgeExplorer from "discourse/plugins/discourse-knowledge-explorer/discourse/models/knowledge-explorer";
import KnowledgeExplorer from "discourse/plugins/discourse-knowledge-explorer/discourse/models/knowledge-explorer";

export default Ember.Controller.extend({
application: Ember.inject.controller(),
queryParams: {
filterCategory: "category",
filterTags: "tags",
searchTerm: "search",
selectedTopic: "topic"
},
isLoading: false,
isLoadingMore: false,
loadMoreUrl: Ember.computed.alias("model.topics.load_more_url"),
@computed("loadMoreUrl")
canLoadMore(loadMoreUrl) {
if (loadMoreUrl === null || this.isLoadingMore) {
return false;
}
return true;
},
isTopicLoading: false,
topics: Ember.computed.alias("model.topics.topic_list.topics"),
tags: Ember.computed.readOnly("model.tags"),
filterTags: null,
filterCategory: null,

searchTerm: null,
searchResults: null,

selectedTopic: null,
topic: null,

searchCount: Ember.computed.readOnly("searchResults.length"),
emptySearchResults: Ember.computed.equal("searchCount", 0),
@computed("searchTerm")
isSearching(searchTerm) {
return !!searchTerm;
},

@computed("searchResults")
hasSearchResults(results) {
return !!results;
@computed("isSearching", "topics")
searchCount(isSearching, topics) {
if (isSearching) return topics.length;
},
emptySearchResults: Ember.computed.equal("searchCount", 0),

@computed("filterTags")
filtered(filterTags) {
return !!filterTags;
},

actions: {
setSelectedTopic(topicID) {
this.set("selectedTopic", topicID);
setSelectedTopic(topicId) {
this.set("isTopicLoading", true);
this.set("selectedTopic", topicId);
KnowledgeExplorer.getTopic(topicId).then(result => {
this.set("topic", result);
this.set("isTopicLoading", false);
});
},
updateSelectedTags(tag) {
let filter = this.filterTags;
if (filter && filter.includes(tag.id)) {
filter = filter.replace(tag.id, "");
filter = filter.replace("++", "+");
filter = filter.replace(/^\++|\++$/g, "");
filter = filter.replace("|", "|");
filter = filter.replace(/^\|+|\|+$/g, "");
} else if (filter) {
filter = `${filter}+${tag.id}`;
filter = `${filter}|${tag.id}`;
} else {
filter = tag.id;
}

this.set("filterTags", filter);
this.set("selectedTopic", null);
this.send("refreshModel");
},
performSearch(term) {
if (term === "") {
this.set("searchTerm", null);
this.send("refreshModel");
return false;
}

if (term.length < this.siteSettings.min_search_term_length) {
this.set("searchResults", null);
return false;
}

const tags = this.get("filterTags") || null;
this.set("searchTerm", term);
this.set("selectedTopic", null);
this.send("refreshModel");
},
loadMore() {
if (this.canLoadMore) {
this.set("isLoadingMore", true);

KnowledgeExplorer.loadMore(this.loadMoreUrl).then(result => {
let topics = this.topics;

knowledgeExplorer.search(term, tags).then(result => {
this.set("searchResults", result.topics || []);
topics = topics.concat(result.topics.topic_list.topics);

this.set("topics", topics);
this.set("loadMoreUrl", result.topics.load_more_url || null);
this.set("isLoadingMore", false);
});
}
},
refreshModel() {
this.set("isLoading", true);
const params = this.getProperties(
"filterCategory",
"filterTags",
"searchTerm"
);
KnowledgeExplorer.list(params).then(result => {
this.set("model", result);
this.set("isLoading", false);
});
}
}
@@ -1,12 +1,18 @@
import { ajax } from "discourse/lib/ajax";

export default {
//write as one liner
//use + instead of space for query param
search(filter, tags) {
let params = [filter];
if (tags) params.push(`tags:${tags}`);
const endpoint = `/search.json?q=in:kb ${params.join(" ")}`;
return ajax(endpoint);
list(params) {
let filters = [];
if (params.filterTags) filters.push(`tags=${params.filterTags}`);
if (params.searchTerm) filters.push(`search=${params.searchTerm}`);
if (params.page) filters.push(`page=${params.page}`);

return ajax(`/knowledge-explorer.json?${filters.join("&")}`);
},
loadMore(loadMoreUrl) {
return ajax(loadMoreUrl);
},
getTopic(id) {
return ajax(`/t/${id}.json`);
}
};
@@ -1,37 +1,8 @@
import { ajax } from "discourse/lib/ajax";
import KnowledgeExplorer from "discourse/plugins/discourse-knowledge-explorer/discourse/models/knowledge-explorer";

export default Ember.Route.extend({
queryParams: {
filterTags: {
refreshModel: true
},
selectedTopic: {
refreshModel: true
}
},
model(params) {
if (params.filterTags) {
const tags = params.filterTags;
return ajax(`/knowledge-explorer.json?tags=${tags}`);
} else if (params.selectedTopic) {
return ajax(`/t/${params.selectedTopic}.json`);
} else {
return ajax("/knowledge-explorer.json");
}
},

setupController(controller, model) {
if (model.tags && model.topics) {
controller.setProperties({
tags: model.tags,
topics: model.topics
});
} else {
controller.setProperties({
tags: [],
topics: [],
topic: model
});
}
return KnowledgeExplorer.list(params);
}
});
@@ -1,3 +1,4 @@
{{#load-more selector=".topic-list tr" action=loadMore}}
<table class="topic-list">
<thead>
<th>Topic</th>
@@ -23,4 +24,5 @@
{{/each}}
</tbody>
</table>

{{/load-more}}
{{conditional-loading-spinner condition=loading}}
@@ -1,5 +1,8 @@
<a class="knowledge-explorer-nav-link return" href="/knowledge-explorer">Return to Knowledge Explorer</a>
{{#link-to 'knowledgeExplorer' (query-params topic=null) class='knowledge-explorer-nav-link return'}}
{{i18n 'knowledge_explorer.topic.back'}}
{{/link-to}}
<div class="topic-content">
<h1>{{topic.title}}</h1>
{{{originalPostContent}}}
</div>
<a class="knowledge-explorer-nav-link more" href="/t/{{topic.id}}">View the discussion on this topic</a>
<a class="knowledge-explorer-nav-link more" href="/t/{{topic.id}}">{{i18n 'knowledge_explorer.topic.navigate_to_topic'}}</a>

0 comments on commit a34e446

Please sign in to comment.
You can’t perform that action at this time.