From 5ddd644e000aaf9e50269a325a79bcac6974cee0 Mon Sep 17 00:00:00 2001 From: Vinoth Kannan Date: Thu, 14 Mar 2019 00:41:07 +0530 Subject: [PATCH] FEATURE: Show dropdown to filter topic lists by solved status --- .../topic-status-filter.hbs | 1 + .../topic-status-filter.js.es6 | 60 +++++++++++++++++++ config/locales/client.en.yml | 4 ++ config/locales/server.en.yml | 1 + config/settings.yml | 3 + plugin.rb | 13 ++++ spec/models/site_spec.rb | 16 +++++ 7 files changed, 98 insertions(+) create mode 100644 assets/javascripts/discourse/connectors/bread-crumbs-right/topic-status-filter.hbs create mode 100644 assets/javascripts/discourse/connectors/bread-crumbs-right/topic-status-filter.js.es6 create mode 100644 spec/models/site_spec.rb diff --git a/assets/javascripts/discourse/connectors/bread-crumbs-right/topic-status-filter.hbs b/assets/javascripts/discourse/connectors/bread-crumbs-right/topic-status-filter.hbs new file mode 100644 index 0000000..e85eadc --- /dev/null +++ b/assets/javascripts/discourse/connectors/bread-crumbs-right/topic-status-filter.hbs @@ -0,0 +1 @@ +{{combo-box content=statuses value=status valueAttribute="value" onSelect=(action "changeStatus")}} diff --git a/assets/javascripts/discourse/connectors/bread-crumbs-right/topic-status-filter.js.es6 b/assets/javascripts/discourse/connectors/bread-crumbs-right/topic-status-filter.js.es6 new file mode 100644 index 0000000..3319e23 --- /dev/null +++ b/assets/javascripts/discourse/connectors/bread-crumbs-right/topic-status-filter.js.es6 @@ -0,0 +1,60 @@ +import DiscourseUrl from "discourse/lib/url"; + +export default { + shouldRender(args, component) { + if (!component.siteSettings.show_filter_by_solved_status) { + return false; + } else if (component.siteSettings.allow_solved_on_all_topics) { + return true; + } else { + const controller = Discourse.__container__.lookup( + "controller:navigation/category" + ); + + return controller && controller.get("category.enable_accepted_answers"); + } + }, + + setupComponent(args, component) { + const statuses = ["all", "solved", "unsolved"].map(status => { + return { + name: I18n.t(`solved.topic_status_filter.${status}`), + value: status + }; + }); + component.set("statuses", statuses); + + const queryStrings = window.location.search; + if (queryStrings.match(/solved=yes/)) { + component.set("status", "solved"); + } else if (queryStrings.match(/solved=no/)) { + component.set("status", "unsolved"); + } else { + component.set("status", "all"); + } + }, + + actions: { + changeStatus(newStatus) { + let location = window.location; + let queryStrings = location.search; + let params = queryStrings.startsWith("?") + ? queryStrings.substr(1).split("&") + : []; + + params = params.filter(param => { + return !param.startsWith("solved="); + }); + + if (newStatus && newStatus !== "all") { + newStatus = newStatus === "solved" ? "yes" : "no"; + params.push(`solved=${newStatus}`); + } + + queryStrings = params.length > 0 ? `?${params.join("&")}` : ""; + DiscourseUrl.routeTo( + `${location.pathname}${queryStrings}${location.hash}` + ); + } + } +}; diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 16abec3..e1ab2d9 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -18,6 +18,10 @@ en: other: "solutions" accepted_html: "{{icon}} Solved by {{username}} in post #{{post_number}}" accepted_notification: "

{{username}} {{description}}

" + topic_status_filter: + all: "all" + solved: "solved" + unsolved: "unsolved" topic_statuses: solved: diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 25ccf27..752ec08 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -6,6 +6,7 @@ en: empty_box_on_unsolved: "Display an empty box next to unsolved topics" solved_quote_length: "Number of characters to quote when displaying the solution under the first post" solved_topics_auto_close_hours: "Auto close topic (n) hours after the last reply once the topic has been marked as solved" + show_filter_by_solved_status: "Show a dropdown to filter a topic list by solved status." reports: accepted_solutions: title: "Accepted solutions" diff --git a/config/settings.yml b/config/settings.yml index da6d43e..5bbd6c6 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -16,3 +16,6 @@ plugins: client: false solved_topics_auto_close_hours: default: 0 + show_filter_by_solved_status: + default: false + client: true diff --git a/plugin.rb b/plugin.rb index 68af667..3de7396 100644 --- a/plugin.rb +++ b/plugin.rb @@ -324,6 +324,19 @@ SQL end end + require_dependency 'basic_category_serializer' + class ::BasicCategorySerializer + attributes :custom_fields + + def custom_fields + object.custom_fields.slice("enable_accepted_answers") + end + + def include_custom_fields? + custom_fields.present? + end + end + require_dependency 'topic_view_serializer' class ::TopicViewSerializer attributes :accepted_answer diff --git a/spec/models/site_spec.rb b/spec/models/site_spec.rb new file mode 100644 index 0000000..09cfac3 --- /dev/null +++ b/spec/models/site_spec.rb @@ -0,0 +1,16 @@ +require 'rails_helper' +require_dependency 'site' + +describe Site do + let(:category) { Fabricate(:category) } + let(:guardian) { Guardian.new } + + it "includes `enable_accepted_answers` custom field for categories" do + category.custom_fields["enable_accepted_answers"] = true + category.save_custom_fields + + json = Site.json_for(guardian) + + expect(json).to include("enable_accepted_answers") + end +end