diff --git a/app/assets/javascripts/admin/controllers/admin-badges.js.es6 b/app/assets/javascripts/admin/controllers/admin-badges.js.es6
index 5089a712c..199c7eab1 100644
--- a/app/assets/javascripts/admin/controllers/admin-badges.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-badges.js.es6
@@ -7,6 +7,7 @@
@module Discourse
**/
export default Ember.ArrayController.extend({
+ needs: ['modal'],
itemController: 'admin-badge',
queryParams: ['badgeId'],
badgeId: Em.computed.alias('selectedId'),
diff --git a/app/assets/javascripts/admin/controllers/admin-edit-badge-groupings.js.es6 b/app/assets/javascripts/admin/controllers/admin-edit-badge-groupings.js.es6
new file mode 100644
index 000000000..2034d1036
--- /dev/null
+++ b/app/assets/javascripts/admin/controllers/admin-edit-badge-groupings.js.es6
@@ -0,0 +1,80 @@
+export default Ember.Controller.extend({
+ needs: ['modal'],
+
+ modelChanged: function(){
+
+ var grouping = Em.Object.extend({});
+
+ var model = this.get('model');
+ var copy = Em.A();
+
+ if(model){
+ model.forEach(function(o){
+ copy.pushObject(grouping.create(o));
+ });
+ }
+
+ this.set('workingCopy', copy);
+ }.observes('model'),
+
+ moveItem: function(item, delta){
+ var copy = this.get('workingCopy');
+ var index = copy.indexOf(item);
+ if (index + delta < 0 || index + delta >= copy.length){
+ return;
+ }
+
+ copy.removeAt(index);
+ copy.insertAt(index+delta, item);
+ },
+
+ actions: {
+ up: function(item){
+ this.moveItem(item, -1);
+ },
+ down: function(item){
+ this.moveItem(item, 1);
+ },
+ "delete": function(item){
+ this.get('workingCopy').removeObject(item);
+ },
+ cancel: function(){
+ this.set('model', null);
+ this.set('workingCopy', null);
+ this.send('closeModal');
+ },
+ edit: function(item){
+ item.set("editing", true);
+ },
+ save: function(item){
+ item.set("editing", false);
+ },
+ add: function(){
+ var obj = Em.Object.create({editing: true, name: "Enter Name"});
+ this.get('workingCopy').pushObject(obj);
+ },
+ saveAll: function(){
+ var self = this;
+ var items = this.get('workingCopy');
+ var groupIds = items.map(function(i){return i.get("id") || -1});
+ var names = items.map(function(i){return i.get("name")});
+
+ Discourse.ajax('/admin/badges/badge_groupings',{
+ data: {ids: groupIds, names: names},
+ method: 'POST'
+ }).then(function(data){
+ items = self.get("model");
+ items.clear();
+ data.badge_groupings.forEach(function(g){
+ items.pushObject(Em.Object.create(g));
+ });
+ self.set('model', null);
+ self.set('workingCopy', null);
+ self.send('closeModal');
+ },function(){
+ // TODO we can do better
+ bootbox.alert("Something went wrong");
+ });
+ }
+ }
+});
diff --git a/app/assets/javascripts/admin/routes/admin_badges_route.js b/app/assets/javascripts/admin/routes/admin_badges_route.js
index 6ac596b5c..ba8fb4f9c 100644
--- a/app/assets/javascripts/admin/routes/admin_badges_route.js
+++ b/app/assets/javascripts/admin/routes/admin_badges_route.js
@@ -1,7 +1,8 @@
Discourse.AdminBadgesRoute = Discourse.Route.extend({
setupController: function(controller) {
Discourse.ajax('/admin/badges.json').then(function(json){
- controller.set('badgeGroupings', json.badge_groupings);
+
+ controller.set('badgeGroupings', Em.A(json.badge_groupings));
controller.set('badgeTypes', json.badge_types);
controller.set('protectedSystemFields', json.admin_badges.protected_system_fields);
var triggers = [];
@@ -11,6 +12,12 @@ Discourse.AdminBadgesRoute = Discourse.Route.extend({
controller.set('badgeTriggers', triggers);
controller.set('model', Discourse.Badge.createFromJson(json));
});
+ },
+
+ actions: {
+ editGroupings: function(model){
+ Discourse.Route.showModal(this, 'admin_edit_badge_groupings', model);
+ }
}
});
diff --git a/app/assets/javascripts/admin/templates/badges.js.handlebars b/app/assets/javascripts/admin/templates/badges.js.handlebars
index e5cf7e2f5..782fb6c9d 100644
--- a/app/assets/javascripts/admin/templates/badges.js.handlebars
+++ b/app/assets/javascripts/admin/templates/badges.js.handlebars
@@ -53,6 +53,7 @@
content=controller.badgeGroupings
optionValuePath="content.id"
optionLabelPath="content.name"}}
+
diff --git a/app/assets/javascripts/admin/templates/modal/admin_edit_badge_groupings.js.handlebars b/app/assets/javascripts/admin/templates/modal/admin_edit_badge_groupings.js.handlebars
new file mode 100644
index 000000000..5b636de1e
--- /dev/null
+++ b/app/assets/javascripts/admin/templates/modal/admin_edit_badge_groupings.js.handlebars
@@ -0,0 +1,28 @@
+
+
+
+
+ {{#each workingCopy}}
+ -
+ {{#if editing}}
+ {{input value=this.name}}
+
+ {{else}}
+ {{this.name}}
+ {{/if}}
+
+
+
+
+
+
+
+ {{/each}}
+
+
+
+
+
diff --git a/app/assets/javascripts/admin/views/modals/admin_edit_badge_groupings_view.js b/app/assets/javascripts/admin/views/modals/admin_edit_badge_groupings_view.js
new file mode 100644
index 000000000..cf2227f35
--- /dev/null
+++ b/app/assets/javascripts/admin/views/modals/admin_edit_badge_groupings_view.js
@@ -0,0 +1,5 @@
+
+Discourse.AdminEditBadgeGroupingsView = Discourse.ModalBodyView.extend({
+ templateName: 'admin/templates/modal/admin_edit_badge_groupings',
+ title: I18n.t('admin.badges.badge_groupings.modal_title')
+});
diff --git a/app/assets/stylesheets/common/admin/admin_base.scss b/app/assets/stylesheets/common/admin/admin_base.scss
index f8f3eb15c..676a46810 100644
--- a/app/assets/stylesheets/common/admin/admin_base.scss
+++ b/app/assets/stylesheets/common/admin/admin_base.scss
@@ -1205,3 +1205,21 @@ and (max-width : 500px) {
}
}
+
+.badge-groupings {
+ list-style: none;
+ margin: 0;
+ padding: 10px 3px;
+ li {
+ padding: 6px 0;
+ width: 600px;
+ border-bottom: 1px solid #dfdfdf;
+ }
+ .actions {
+ font-size: 17px;
+ float: right;
+ a {
+ margin-left: 5px;
+ }
+ }
+}
diff --git a/app/controllers/admin/badges_controller.rb b/app/controllers/admin/badges_controller.rb
index 186f4e44b..1bd7d3b0e 100644
--- a/app/controllers/admin/badges_controller.rb
+++ b/app/controllers/admin/badges_controller.rb
@@ -2,8 +2,8 @@ class Admin::BadgesController < Admin::AdminController
def index
data = {
- badge_types: BadgeType.all.to_a,
- badge_groupings: BadgeGrouping.all.to_a,
+ badge_types: BadgeType.all.order(:id).to_a,
+ badge_groupings: BadgeGrouping.all.order(:position).to_a,
badges: Badge.all.to_a,
protected_system_fields: Badge.protected_system_fields,
triggers: Badge.trigger_hash
@@ -20,8 +20,24 @@ class Admin::BadgesController < Admin::AdminController
render_serialized(badge_types, BadgeTypeSerializer, root: "badge_types")
end
- def badge_groupings
- badge_groupings = BadgeGrouping.all.to_a
+ def save_badge_groupings
+
+ badge_groupings = BadgeGrouping.all.order(:position).to_a
+ ids = params[:ids].map(&:to_i)
+
+ params[:names].each_with_index do |name,index|
+ id = ids[index].to_i
+ group = badge_groupings.find{|b| b.id == id} || BadgeGrouping.new()
+ group.name = name
+ group.position = index
+ group.save
+ end
+
+ badge_groupings.each do |g|
+ g.destroy unless g.system? || ids.include?(g.id)
+ end
+
+ badge_groupings = BadgeGrouping.all.order(:position).to_a
render_serialized(badge_groupings, BadgeGroupingSerializer, root: "badge_groupings")
end
diff --git a/app/models/badge_grouping.rb b/app/models/badge_grouping.rb
index 92d9dc65f..8bdfe2467 100644
--- a/app/models/badge_grouping.rb
+++ b/app/models/badge_grouping.rb
@@ -8,6 +8,10 @@ class BadgeGrouping < ActiveRecord::Base
has_many :badges
+ def system?
+ id && id < 5
+ end
+
def default_position=(pos)
position ||= pos
end
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 4f90e8ae5..4907c6e4e 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -1889,6 +1889,8 @@ en:
description: Description
badge_type: Badge Type
badge_grouping: Group
+ badge_groupings:
+ modal_title: Badge Groupings
granted_by: Granted By
granted_at: Granted At
save: Save
diff --git a/config/routes.rb b/config/routes.rb
index c38ca9892..f87dcf0d0 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -146,7 +146,7 @@ Discourse::Application.routes.draw do
resources :badges, constraints: AdminConstraint.new do
collection do
get "types" => "badges#badge_types"
- get "groupings" => "badges#badge_groupings"
+ post "badge_groupings" => "badges#save_badge_groupings"
post "preview" => "badges#preview"
end
end
diff --git a/spec/controllers/admin/badges_controller_spec.rb b/spec/controllers/admin/badges_controller_spec.rb
index 5d418ba99..e36930e84 100644
--- a/spec/controllers/admin/badges_controller_spec.rb
+++ b/spec/controllers/admin/badges_controller_spec.rb
@@ -1,14 +1,35 @@
require 'spec_helper'
describe Admin::BadgesController do
- it "is a subclass of AdminController" do
- (Admin::BadgesController < Admin::AdminController).should be_true
- end
context "while logged in as an admin" do
let!(:user) { log_in(:admin) }
let!(:badge) { Fabricate(:badge) }
+ context '.save_badge_groupings' do
+
+ it 'can save badge groupings' do
+ groupings = BadgeGrouping.all.order(:position).to_a
+ groupings << BadgeGrouping.new(name: 'Test 1')
+ groupings << BadgeGrouping.new(name: 'Test 2')
+
+ groupings.shuffle!
+
+ names = groupings.map{|g| g.name}
+ ids = groupings.map{|g| g.id.to_s}
+
+
+ xhr :post, :save_badge_groupings, ids: ids, names: names
+
+ groupings2 = BadgeGrouping.all.order(:position).to_a
+
+ groupings2.map{|g| g.name}.should == names
+ (groupings.map(&:id) - groupings2.map{|g| g.id}).compact.should be_blank
+
+ ::JSON.parse(response.body)["badge_groupings"].length.should == groupings2.length
+ end
+ end
+
context '.badge_types' do
it 'returns success' do
xhr :get, :badge_types