mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-27 09:36:19 -05:00
FEATURE: Custom orders for user fields
This commit is contained in:
parent
8e603503e6
commit
aa6f792ce1
16 changed files with 126 additions and 83 deletions
|
@ -6,6 +6,9 @@ export default Ember.Component.extend(bufferedProperty('userField'), {
|
|||
editing: Ember.computed.empty('userField.id'),
|
||||
classNameBindings: [':user-field'],
|
||||
|
||||
cantMoveUp: Discourse.computed.propertyEqual('userField', 'firstField'),
|
||||
cantMoveDown: Discourse.computed.propertyEqual('userField', 'lastField'),
|
||||
|
||||
userFieldsDescription: function() {
|
||||
return I18n.t('admin.user_fields.description');
|
||||
}.property(),
|
||||
|
@ -55,13 +58,20 @@ export default Ember.Component.extend(bufferedProperty('userField'), {
|
|||
'show_on_profile',
|
||||
'options');
|
||||
|
||||
this.get('userField').save(attrs).then(function(res) {
|
||||
self.set('userField.id', res.user_field.id);
|
||||
this.get('userField').save(attrs).then(function() {
|
||||
self.set('editing', false);
|
||||
self.commitBuffer();
|
||||
}).catch(popupAjaxError);
|
||||
},
|
||||
|
||||
moveUp() {
|
||||
this.sendAction('moveUpAction', this.get('userField'));
|
||||
},
|
||||
|
||||
moveDown() {
|
||||
this.sendAction('moveDownAction', this.get('userField'));
|
||||
},
|
||||
|
||||
edit() {
|
||||
this.set('editing', true);
|
||||
},
|
||||
|
|
|
@ -1,31 +1,60 @@
|
|||
import UserField from 'admin/models/user-field';
|
||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||
|
||||
export default Ember.ArrayController.extend({
|
||||
const MAX_FIELDS = 20;
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
fieldTypes: null,
|
||||
createDisabled: Em.computed.gte('model.length', 20),
|
||||
createDisabled: Em.computed.gte('model.length', MAX_FIELDS),
|
||||
|
||||
_performDestroy(f, model) {
|
||||
return f.destroy().then(function() {
|
||||
model.removeObject(f);
|
||||
arrangedContent: function() {
|
||||
return Ember.ArrayProxy.extend(Ember.SortableMixin).create({
|
||||
sortProperties: ['position'],
|
||||
content: this.get('model')
|
||||
});
|
||||
},
|
||||
}.property('model'),
|
||||
|
||||
actions: {
|
||||
createField() {
|
||||
this.pushObject(UserField.create({ field_type: 'text' }));
|
||||
const f = this.store.createRecord('user-field', { field_type: 'text', position: MAX_FIELDS });
|
||||
this.get('model').pushObject(f);
|
||||
},
|
||||
|
||||
moveUp(f) {
|
||||
const idx = this.get('arrangedContent').indexOf(f);
|
||||
if (idx) {
|
||||
const prev = this.get('arrangedContent').objectAt(idx-1);
|
||||
const prevPos = prev.get('position');
|
||||
|
||||
prev.update({ position: f.get('position') });
|
||||
f.update({ position: prevPos });
|
||||
}
|
||||
},
|
||||
|
||||
moveDown(f) {
|
||||
const idx = this.get('arrangedContent').indexOf(f);
|
||||
if (idx > -1) {
|
||||
const next = this.get('arrangedContent').objectAt(idx+1);
|
||||
const nextPos = next.get('position');
|
||||
|
||||
next.update({ position: f.get('position') });
|
||||
f.update({ position: nextPos });
|
||||
}
|
||||
},
|
||||
|
||||
destroy(f) {
|
||||
const model = this.get('model'),
|
||||
self = this;
|
||||
const model = this.get('model');
|
||||
|
||||
// Only confirm if we already been saved
|
||||
if (f.get('id')) {
|
||||
bootbox.confirm(I18n.t("admin.user_fields.delete_confirm"), function(result) {
|
||||
if (result) { self._performDestroy(f, model); }
|
||||
if (result) {
|
||||
f.destroyRecord().then(function() {
|
||||
model.removeObject(f);
|
||||
}).catch(popupAjaxError);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
self._performDestroy(f, model);
|
||||
model.removeObject(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,47 +1,12 @@
|
|||
const UserField = Ember.Object.extend({
|
||||
import RestModel from 'discourse/models/rest';
|
||||
|
||||
destroy() {
|
||||
const self = this;
|
||||
return new Ember.RSVP.Promise(function(resolve) {
|
||||
const id = self.get('id');
|
||||
if (id) {
|
||||
return Discourse.ajax("/admin/customize/user_fields/" + id, { type: 'DELETE' }).then(function() {
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
},
|
||||
|
||||
save(attrs) {
|
||||
const id = this.get('id');
|
||||
if (!id) {
|
||||
return Discourse.ajax("/admin/customize/user_fields", {
|
||||
type: "POST",
|
||||
data: { user_field: attrs }
|
||||
});
|
||||
} else {
|
||||
return Discourse.ajax("/admin/customize/user_fields/" + id, {
|
||||
type: "PUT",
|
||||
data: { user_field: attrs }
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
const UserField = RestModel.extend();
|
||||
|
||||
const UserFieldType = Ember.Object.extend({
|
||||
name: Discourse.computed.i18n('id', 'admin.user_fields.field_types.%@')
|
||||
});
|
||||
|
||||
UserField.reopenClass({
|
||||
findAll() {
|
||||
return Discourse.ajax("/admin/customize/user_fields").then(function(result) {
|
||||
return result.user_fields.map(function(uf) {
|
||||
return UserField.create(uf);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
fieldTypes() {
|
||||
if (!this._fieldTypes) {
|
||||
this._fieldTypes = [
|
||||
|
|
|
@ -2,13 +2,10 @@ import UserField from 'admin/models/user-field';
|
|||
|
||||
export default Discourse.Route.extend({
|
||||
model: function() {
|
||||
return UserField.findAll();
|
||||
return this.store.findAll('user-field');
|
||||
},
|
||||
|
||||
setupController: function(controller, model) {
|
||||
controller.setProperties({
|
||||
model: model,
|
||||
fieldTypes: UserField.fieldTypes()
|
||||
});
|
||||
controller.setProperties({ model, fieldTypes: UserField.fieldTypes() });
|
||||
}
|
||||
});
|
||||
|
|
|
@ -35,13 +35,17 @@
|
|||
{{/admin-form-row}}
|
||||
{{else}}
|
||||
<div class="row">
|
||||
<div class='form-display'><strong>{{userField.name}}</strong></div>
|
||||
<div class='form-display'>{{{userField.description}}}</div>
|
||||
<div class='form-display'>
|
||||
<strong>{{userField.name}}</strong>
|
||||
<br/>
|
||||
{{{userField.description}}}
|
||||
</div>
|
||||
<div class='form-display'>{{fieldName}}</div>
|
||||
<div class='form-display'></div>
|
||||
<div class='form-element controls'>
|
||||
{{d-button action="edit" class="btn-default" icon="pencil" label="admin.user_fields.edit"}}
|
||||
{{d-button action="destroy" class="btn-danger" icon="trash-o" label="admin.user_fields.delete"}}
|
||||
{{d-button action="moveUp" icon="arrow-up" disabled=cantMoveUp}}
|
||||
{{d-button action="moveDown" icon="arrow-down" disabled=cantMoveDown}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">{{flags}}</div>
|
||||
|
|
|
@ -4,8 +4,14 @@
|
|||
<p class="desc">{{i18n 'admin.user_fields.help'}}</p>
|
||||
|
||||
{{#if model}}
|
||||
{{#each model as |uf|}}
|
||||
{{admin-user-field-item userField=uf fieldTypes=fieldTypes destroyAction="destroy"}}
|
||||
{{#each arrangedContent as |uf|}}
|
||||
{{admin-user-field-item userField=uf
|
||||
fieldTypes=fieldTypes
|
||||
firstField=arrangedContent.firstObject
|
||||
lastField=arrangedContent.lastObject
|
||||
destroyAction="destroy"
|
||||
moveUpAction="moveUp"
|
||||
moveDownAction="moveDown"}}
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
|
||||
|
|
|
@ -17,10 +17,14 @@ function rethrow(error) {
|
|||
}
|
||||
|
||||
export default Ember.Object.extend({
|
||||
pathFor(store, type, findArgs) {
|
||||
let path = "/" + Ember.String.underscore(store.pluralize(type));
|
||||
|
||||
if (ADMIN_MODELS.indexOf(type) !== -1) { path = "/admin" + path; }
|
||||
basePath(store, type) {
|
||||
if (ADMIN_MODELS.indexOf(type) !== -1) { return "/admin/"; }
|
||||
return "/";
|
||||
},
|
||||
|
||||
pathFor(store, type, findArgs) {
|
||||
let path = this.basePath(store, type, findArgs) + Ember.String.underscore(store.pluralize(type));
|
||||
|
||||
if (findArgs) {
|
||||
if (typeof findArgs === "object") {
|
||||
|
@ -51,9 +55,10 @@ export default Ember.Object.extend({
|
|||
|
||||
update(store, type, id, attrs) {
|
||||
const data = {};
|
||||
data[Ember.String.underscore(type)] = attrs;
|
||||
const typeField = Ember.String.underscore(type);
|
||||
data[typeField] = attrs;
|
||||
return ajax(this.pathFor(store, type, id), { method: 'PUT', data }).then(function(json) {
|
||||
return new Result(json[type], json);
|
||||
return new Result(json[typeField], json);
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
import RestAdapter from 'discourse/adapters/rest';
|
||||
|
||||
export default RestAdapter.extend({
|
||||
basePath() {
|
||||
return "/admin/customize/";
|
||||
}
|
||||
});
|
|
@ -394,11 +394,8 @@ export default DiscourseController.extend(ModalFunctionality, {
|
|||
|
||||
let userFields = this.site.get('user_fields');
|
||||
if (userFields) {
|
||||
userFields = userFields.map(function(f) {
|
||||
return Ember.Object.create({
|
||||
value: null,
|
||||
field: f
|
||||
});
|
||||
userFields = _.sortBy(userFields, 'position').map(function(f) {
|
||||
return Ember.Object.create({ value: null, field: f });
|
||||
});
|
||||
}
|
||||
this.set('userFields', userFields);
|
||||
|
|
|
@ -18,7 +18,6 @@ const RestModel = Ember.Object.extend(Presence, {
|
|||
const self = this;
|
||||
self.set('isSaving', true);
|
||||
return store.update(type, this.get('id'), props).then(function(res) {
|
||||
|
||||
const payload = self.__munge(res.payload || res.responseJson);
|
||||
|
||||
if (payload.success === "OK") {
|
||||
|
|
|
@ -1460,7 +1460,6 @@ tr.not-activated {
|
|||
.controls {
|
||||
float: right;
|
||||
text-align: right;
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.clearfix {
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
class Admin::UserFieldsController < Admin::AdminController
|
||||
|
||||
def self.columns
|
||||
[:name, :field_type, :editable, :description, :required, :show_on_profile]
|
||||
[:name, :field_type, :editable, :description, :required, :show_on_profile, :position]
|
||||
end
|
||||
|
||||
def create
|
||||
field = UserField.new(params.require(:user_field).permit(*Admin::UserFieldsController.columns))
|
||||
|
||||
field.position = (UserField.maximum(:position) || 0) + 1
|
||||
field.required = params[:required] == "true"
|
||||
fetch_options(field)
|
||||
|
||||
|
@ -15,33 +17,35 @@ class Admin::UserFieldsController < Admin::AdminController
|
|||
end
|
||||
|
||||
def index
|
||||
user_fields = UserField.all.includes(:user_field_options)
|
||||
user_fields = UserField.all.includes(:user_field_options).order(:position)
|
||||
render_serialized(user_fields, UserFieldSerializer, root: 'user_fields')
|
||||
end
|
||||
|
||||
def update
|
||||
field_params = params.require(:user_field)
|
||||
|
||||
field_params = params[:user_field]
|
||||
field = UserField.where(id: params.require(:id)).first
|
||||
|
||||
Admin::UserFieldsController.columns.each do |col|
|
||||
field.send("#{col}=", field_params[col] || false)
|
||||
unless field_params[col].nil?
|
||||
field.send("#{col}=", field_params[col])
|
||||
end
|
||||
end
|
||||
UserFieldOption.where(user_field_id: field.id).delete_all
|
||||
fetch_options(field)
|
||||
|
||||
json_result(field, serializer: UserFieldSerializer) do
|
||||
field.save
|
||||
if field.save
|
||||
render_serialized(field, UserFieldSerializer, root: 'user_field')
|
||||
else
|
||||
render_json_error(field)
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
field = UserField.where(id: params.require(:id)).first
|
||||
field.destroy if field.present?
|
||||
render nothing: true
|
||||
render json: success_json
|
||||
end
|
||||
|
||||
|
||||
protected
|
||||
|
||||
def fetch_options(field)
|
||||
|
|
|
@ -6,6 +6,7 @@ class UserFieldSerializer < ApplicationSerializer
|
|||
:editable,
|
||||
:required,
|
||||
:show_on_profile,
|
||||
:position,
|
||||
:options
|
||||
|
||||
def options
|
||||
|
|
6
db/migrate/20150730154830_add_position_to_user_fields.rb
Normal file
6
db/migrate/20150730154830_add_position_to_user_fields.rb
Normal file
|
@ -0,0 +1,6 @@
|
|||
class AddPositionToUserFields < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :user_fields, :position, :integer, default: 0
|
||||
execute "UPDATE user_fields SET position = (SELECT COUNT(*) from user_fields as uf2 where uf2.id < user_fields.id)"
|
||||
end
|
||||
end
|
|
@ -249,6 +249,12 @@ export default function() {
|
|||
return response({ widget });
|
||||
});
|
||||
|
||||
this.put('/cool_things/:cool_thing_id', function(request) {
|
||||
const cool_thing = parsePostData(request.requestBody).cool_thing;
|
||||
return response({ cool_thing });
|
||||
});
|
||||
|
||||
|
||||
this.get('/widgets', function(request) {
|
||||
let result = _widgets;
|
||||
|
||||
|
|
|
@ -70,6 +70,14 @@ test('update', function() {
|
|||
});
|
||||
});
|
||||
|
||||
test('update with a multi world name', function(assert) {
|
||||
const store = createStore();
|
||||
return store.update('cool-thing', 123, {name: 'hello'}).then(function(result) {
|
||||
assert.ok(result);
|
||||
assert.equal(result.payload.name, 'hello');
|
||||
});
|
||||
});
|
||||
|
||||
test('findAll', function() {
|
||||
const store = createStore();
|
||||
return store.findAll('widget').then(function(result) {
|
||||
|
@ -84,7 +92,7 @@ test('destroyRecord', function(assert) {
|
|||
const store = createStore();
|
||||
return store.find('widget', 123).then(function(w) {
|
||||
store.destroyRecord('widget', w).then(function(result) {
|
||||
ok(result);
|
||||
assert.ok(result);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue