FEATURE: Allow users to customize bonuses for reviewable types

FEATURE: Allow users to customize bonuses for reviewable types

A new settings section in the review queue allows admins to specify that certain types of flags should be weighted higher than others.

diff --git a/app/assets/javascripts/discourse/adapters/reviewable-settings.js.es6 b/app/assets/javascripts/discourse/adapters/reviewable-settings.js.es6
new file mode 100644
index 0000000..8b29903
--- /dev/null
+++ b/app/assets/javascripts/discourse/adapters/reviewable-settings.js.es6
@@ -0,0 +1,7 @@
+import RestAdapter from "discourse/adapters/rest";
+
+export default RestAdapter.extend({
+  pathFor() {
+    return "/review/settings";
+  }
+});
diff --git a/app/assets/javascripts/discourse/components/nav-item.js.es6 b/app/assets/javascripts/discourse/components/nav-item.js.es6
index d83952c..20d6d80 100644
--- a/app/assets/javascripts/discourse/components/nav-item.js.es6
+++ b/app/assets/javascripts/discourse/components/nav-item.js.es6
@@ -1,4 +1,5 @@
 /* You might be looking for navigation-item. */
+import { iconHTML } from "discourse-common/lib/icon-library";
 import computed from "ember-addons/ember-computed-decorators";
 
 export default Ember.Component.extend({
@@ -6,9 +7,13 @@ export default Ember.Component.extend({
   classNameBindings: ["active"],
   router: Ember.inject.service(),
 
-  @computed("path")
-  fullPath(path) {
-    return Discourse.getURL(path);
+  @computed("label", "i18nLabel", "icon")
+  contents(label, i18nLabel, icon) {
+    let text = i18nLabel || I18n.t(label);
+    if (icon) {
+      return `${iconHTML(icon)} ${text}`.htmlSafe();
+    }
+    return text;
   },
 
   @computed("route", "router.currentRoute")
diff --git a/app/assets/javascripts/discourse/controllers/review-settings.js.es6 b/app/assets/javascripts/discourse/controllers/review-settings.js.es6
new file mode 100644
index 0000000..339b005
--- /dev/null
+++ b/app/assets/javascripts/discourse/controllers/review-settings.js.es6
@@ -0,0 +1,24 @@
+import { ajax } from "discourse/lib/ajax";
+import { popupAjaxError } from "discourse/lib/ajax-error";
+
+export default Ember.Controller.extend({
+  saving: false,
+  saved: false,
+
+  actions: {
+    save() {
+      let bonuses = {};
+      this.get("settings.reviewable_score_types").forEach(st => {
+        bonuses[st.id] = parseFloat(st.score_bonus);
+      });
+
+      this.set("saving", true);
+      ajax("/review/settings", { method: "PUT", data: { bonuses } })
+        .then(() => {
+          this.set("saved", true);
+        })
+        .catch(popupAjaxError)
+        .finally(() => this.set("saving", false));
+    }
+  }
+});
diff --git a/app/assets/javascripts/discourse/routes/app-route-map.js.es6 b/app/assets/javascripts/discourse/routes/app-route-map.js.es6
index 05023b3..fe84822 100644
--- a/app/assets/javascripts/discourse/routes/app-route-map.js.es6
+++ b/app/assets/javascripts/discourse/routes/app-route-map.js.es6
@@ -173,6 +173,7 @@ export default function() {
     this.route("show", { path: "/:reviewable_id" });
     this.route("index", { path: "/" });
     this.route("topics", { path: "/topics" });
+    this.route("settings", { path: "/settings" });
   });
   this.route("signup", { path: "/signup" });
   this.route("login", { path: "/login" });
diff --git a/app/assets/javascripts/discourse/routes/review-settings.js.es6 b/app/assets/javascripts/discourse/routes/review-settings.js.es6
new file mode 100644
index 0000000..46ed6f1
--- /dev/null
+++ b/app/assets/javascripts/discourse/routes/review-settings.js.es6
@@ -0,0 +1,9 @@
+export default Discourse.Route.extend({
+  model() {
+    return this.store.find("reviewable-settings");
+  },
+
+  setupController(controller, model) {
+    controller.set("settings", model);
+  }
+});
diff --git a/app/assets/javascripts/discourse/templates/components/nav-item.hbs b/app/assets/javascripts/discourse/templates/components/nav-item.hbs
index 96c49a6..1205e1b 100644
--- a/app/assets/javascripts/discourse/templates/components/nav-item.hbs
+++ b/app/assets/javascripts/discourse/templates/components/nav-item.hbs
@@ -1,17 +1,7 @@
 {{#if routeParam}}
-  {{#if i18nLabel}}
-    {{#link-to route routeParam}}{{i18nLabel}}{{/link-to}}
-  {{else}}
-    {{#link-to route routeParam}}{{i18n label}}{{/link-to}}
-  {{/if}}
+  {{#link-to route routeParam}}{{contents}}{{/link-to}}
+{{else if route}}
+  {{#link-to route}}{{contents}}{{/link-to}}
 {{else}}
-  {{#if route}}
-    {{#link-to route}}{{i18n label}}{{/link-to}}
-  {{else}}
-    {{#if path}}
-      <a href="{{unbound fullPath}}" data-auto-route="true">{{i18n label}}</a>
-    {{else}}
-      <a href="{{unbound href}}" data-auto-route="true">{{i18n label}}</a>
-    {{/if}}
-  {{/if}}
+  <a href="{{get-url path}}" data-auto-route="true">{{contents}}</a>
 {{/if}}
diff --git a/app/assets/javascripts/discourse/templates/review-index.hbs b/app/assets/javascripts/discourse/templates/review-index.hbs
index b1110be..fc78197 100644
--- a/app/assets/javascripts/discourse/templates/review-index.hbs
+++ b/app/assets/javascripts/discourse/templates/review-index.hbs
@@ -1,83 +1,76 @@
-<div class="reviewable">
-  <ul class="nav nav-pills reviewable-title">
-    {{nav-item route='review.index' label='review.view_all'}}
-    {{nav-item route='review.topics' label='review.grouped_by_topic'}}
-  </ul>
-
-  <div class="reviewable-container">
-    <div class="reviewable-list">
-      {{#if reviewables}}
-        {{#load-more selector=".reviewable-item" action=(action "loadMore")}}
-          <div class='reviewables'>
-            {{#each reviewables as |r|}}
-              {{reviewable-item reviewable=r remove=(action "remove")}}
-            {{/each}}
-          </div>
-        {{/load-more}}
-        {{conditional-loading-spinner condition=reviewables.loadingMore}}
-      {{else}}
-        <div class="no-review">
-          {{i18n "review.none"}}
+<div class="reviewable-container">
+  <div class="reviewable-list">
+    {{#if reviewables}}
+      {{#load-more selector=".reviewable-item" action=(action "loadMore")}}
+        <div class='reviewables'>
+          {{#each reviewables as |r|}}
+            {{reviewable-item reviewable=r remove=(action "remove")}}
+          {{/each}}
         </div>
-      {{/if}}
+      {{/load-more}}
+      {{conditional-loading-spinner condition=reviewables.loadingMore}}
+    {{else}}
+      <div class="no-review">
+        {{i18n "review.none"}}
+      </div>
+    {{/if}}
+  </div>
+
+  <div class='reviewable-filters'>
+    <div class='reviewable-filter'>
+      <label class='filter-label'>{{i18n "review.filters.status"}}</label>
+      {{combo-box value=filterStatus content=statuses}}
     </div>
 
-    <div class='reviewable-filters'>
+    {{#if filtersExpanded}}
       <div class='reviewable-filter'>
-        <label class='filter-label'>{{i18n "review.filters.status"}}</label>
-        {{combo-box value=filterStatus content=statuses}}
+        <label class='filter-label'>{{i18n "review.filters.type.title"}}</label>
+        {{combo-box value=filterType content=allTypes none="review.filters.type.all"}}
       </div>
 
-      {{#if filtersExpanded}}
-        <div class='reviewable-filter'>
-          <label class='filter-label'>{{i18n "review.filters.type.title"}}</label>
-          {{combo-box value=filterType content=allTypes none="review.filters.type.all"}}
-        </div>
+      <div class='reviewable-filter'>
+        <label class='filter-label'>{{i18n "review.filters.minimum_score"}}</label>
+        {{input value=filterScore class="score-filter"}}
+      </div>
 
-        <div class='reviewable-filter'>
-          <label class='filter-label'>{{i18n "review.filters.minimum_score"}}</label>
-          {{input value=filterScore class="score-filter"}}
-        </div>
+      <div class='reviewable-filter'>
+        <label class='filter-label'>{{i18n "review.filters.category"}}</label>
+        {{category-chooser none="category.all" value=filterCategoryId}}
+      </div>
 
-        <div class='reviewable-filter'>
-          <label class='filter-label'>{{i18n "review.filters.category"}}</label>
-          {{category-chooser none="category.all" value=filterCategoryId}}
-        </div>
+      <div class='reviewable-filter topic-filter'>

[... diff too long, it was truncated ...]

GitHub sha: 62956003