simple_admin 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +56 -0
- data/README.rdoc +8 -2
- data/app/controllers/simple_admin/admin_controller.rb +7 -8
- data/app/helpers/simple_admin/display_helper.rb +1 -1
- data/app/helpers/simple_admin/filter_helper.rb +24 -10
- data/app/helpers/simple_admin/sidebar_helper.rb +4 -2
- data/app/helpers/simple_admin/title_helper.rb +1 -1
- data/app/views/simple_admin/admin/index.csv.erb +1 -1
- data/app/views/simple_admin/admin/index.html.erb +2 -2
- data/lib/simple_admin.rb +13 -1
- data/lib/simple_admin/builder.rb +3 -0
- data/lib/simple_admin/engine.rb +12 -0
- data/lib/simple_admin/interface.rb +6 -5
- data/lib/simple_admin/version.rb +1 -1
- data/lib/tasks/routes.rake +31 -0
- data/spec/controllers/simple_admin/admin_controller_spec.rb +1 -1
- data/spec/simple_admin/interface_spec.rb +8 -0
- metadata +6 -4
data/LICENSE
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
MIT LICENSE
|
2
|
+
|
3
|
+
Copyright (c) 2011 Jeff Rafter
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
|
25
|
+
Some of the code contained in this project is subject to additional
|
26
|
+
Copyright and license:
|
27
|
+
|
28
|
+
Original license from ActiveAdmin, Greg Bell
|
29
|
+
--------------------------------------------
|
30
|
+
|
31
|
+
Copyright (c) 2010 Greg Bell, VersaPay Corporation
|
32
|
+
|
33
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
34
|
+
a copy of this software and associated documentation files (the
|
35
|
+
"Software"), to deal in the Software without restriction, including
|
36
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
37
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
38
|
+
permit persons to whom the Software is furnished to do so, subject to
|
39
|
+
the following conditions:
|
40
|
+
|
41
|
+
The above copyright notice and this permission notice shall be
|
42
|
+
included in all copies or substantial portions of the Software.
|
43
|
+
|
44
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
45
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
46
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
47
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
48
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
49
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
50
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
51
|
+
|
52
|
+
Iconic Icons are designed by P.J. Onori and are shared under
|
53
|
+
the Creative Commons Attribution-Share Alike 3.0 license:
|
54
|
+
http://creativecommons.org/licenses/by-sa/3.0/us
|
55
|
+
http://somerandomdude.com/projects/iconic/
|
56
|
+
|
data/README.rdoc
CHANGED
@@ -19,7 +19,8 @@ set of features.
|
|
19
19
|
|
20
20
|
== Getting started
|
21
21
|
|
22
|
-
In your Gemfile, include simple_admin and formtastic
|
22
|
+
In your Gemfile, include simple_admin and formtastic (and fastercsv
|
23
|
+
if you are on an older version of Ruby):
|
23
24
|
|
24
25
|
gem "simple_admin"
|
25
26
|
gem "formtastic"
|
@@ -184,7 +185,7 @@ of rendering:
|
|
184
185
|
|
185
186
|
SimpleAdmin.register :post do
|
186
187
|
index do
|
187
|
-
sidebar
|
188
|
+
sidebar do
|
188
189
|
# Within index you have @collection, in other views you have @resource
|
189
190
|
your_post_stats_helper(@collection)
|
190
191
|
end
|
@@ -217,6 +218,11 @@ generated at initialization. Available actions are:
|
|
217
218
|
* create
|
218
219
|
* update
|
219
220
|
|
221
|
+
You can also see the routes that are generated by your admin interfaces
|
222
|
+
by running:
|
223
|
+
|
224
|
+
rake routes:simple_admin
|
225
|
+
|
220
226
|
== Configuration options
|
221
227
|
|
222
228
|
All of the configuration for SimpleAdmin happens within the
|
@@ -5,8 +5,8 @@ module SimpleAdmin
|
|
5
5
|
class AdminController < ::ApplicationController
|
6
6
|
before_filter :require_user
|
7
7
|
before_filter :lookup_interface
|
8
|
+
before_filter :lookup_before
|
8
9
|
before_filter :lookup_resource, :only => [:show, :edit, :update, :destroy]
|
9
|
-
before_filter :handle_before
|
10
10
|
|
11
11
|
unloadable
|
12
12
|
|
@@ -25,7 +25,6 @@ module SimpleAdmin
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def show
|
28
|
-
@resource = @interface.constant.find(params[:id])
|
29
28
|
respond_with(@resource)
|
30
29
|
end
|
31
30
|
|
@@ -93,23 +92,23 @@ module SimpleAdmin
|
|
93
92
|
raise UnknownAdminInterface.new("Could not find the interface for simple admin") unless @interface
|
94
93
|
end
|
95
94
|
|
96
|
-
def
|
97
|
-
@resource = @interface.constant.find(params[:id])
|
98
|
-
end
|
99
|
-
|
100
|
-
def handle_before
|
95
|
+
def lookup_before
|
101
96
|
@interface.before.each do |before|
|
102
97
|
next unless before[:actions].include?(params[:action].to_sym)
|
103
98
|
instance_eval(&before[:data])
|
104
99
|
end
|
105
100
|
end
|
106
101
|
|
102
|
+
def lookup_resource
|
103
|
+
@resource ||= @interface.constant.find(params[:id])
|
104
|
+
end
|
105
|
+
|
107
106
|
def clean_search_params(search_params)
|
108
107
|
return {} unless search_params.is_a?(Hash)
|
109
108
|
search_params = search_params.dup
|
110
109
|
search_params.delete_if do |key, value|
|
111
110
|
value == "" ||
|
112
|
-
["utf8", "scope", "commit", "action", "order", "interface", "controller", "format"].include?(key)
|
111
|
+
["utf8", "scope", "commit", "action", "order", "interface", "controller", "format", "page"].include?(key)
|
113
112
|
end
|
114
113
|
search_params
|
115
114
|
end
|
@@ -26,7 +26,7 @@ module SimpleAdmin
|
|
26
26
|
|
27
27
|
def data_for(col)
|
28
28
|
value = if col.data
|
29
|
-
|
29
|
+
instance_exec(@resource, &col.data)
|
30
30
|
elsif col.attribute.to_s =~ /^([\w]+)_id$/ && @resource.respond_to?($1.to_sym)
|
31
31
|
pretty_format(@resource.send($1))
|
32
32
|
else
|
@@ -68,38 +68,52 @@ module SimpleAdmin
|
|
68
68
|
else
|
69
69
|
association_name
|
70
70
|
end
|
71
|
-
input_name = (input_name + "_eq").to_sym
|
71
|
+
input_name = (input_name.to_s + "_eq").to_sym
|
72
72
|
collection = find_collection_for_column(klass, association_name, options)
|
73
73
|
[ label(input_name, method.to_s.titlecase),
|
74
74
|
select_tag(input_name, options_for_select(collection, params[input_name]), :include_blank => options[:include_blank] || 'Any')
|
75
75
|
].join("\n").html_safe
|
76
76
|
end
|
77
77
|
|
78
|
+
def generate_association_input_name(klass, method) #:nodoc:
|
79
|
+
if reflection = reflection_for(klass, method)
|
80
|
+
if [:has_and_belongs_to_many, :has_many].include?(reflection.macro)
|
81
|
+
"#{method.to_s.singularize}_ids"
|
82
|
+
else
|
83
|
+
reflection.options[:foreign_key] || "#{method}_id"
|
84
|
+
end
|
85
|
+
else
|
86
|
+
method
|
87
|
+
end.to_sym
|
88
|
+
end
|
89
|
+
|
78
90
|
def find_collection_for_column(klass, column, options) #:nodoc:
|
79
91
|
collection = if options[:collection]
|
80
|
-
options.delete(:collection)
|
92
|
+
collection = options.delete(:collection)
|
93
|
+
collection = collection.to_a if collection.is_a?(Hash)
|
94
|
+
collection.map { |o| [pretty_format(o.first), o.last] }
|
81
95
|
elsif reflection = reflection_for(klass, column)
|
82
96
|
options[:find_options] ||= {}
|
83
97
|
if conditions = reflection.options[:conditions]
|
84
98
|
options[:find_options][:conditions] = reflection.klass.merge_conditions(conditions, options[:find_options][:conditions])
|
85
99
|
end
|
86
|
-
reflection.klass.find(:all, options[:find_options])
|
100
|
+
collection = reflection.klass.find(:all, options[:find_options])
|
101
|
+
collection.map { |o| [pretty_format(o), o.id] }
|
87
102
|
else
|
88
103
|
boolean_collection(klass, column, options)
|
89
104
|
end
|
90
|
-
collection
|
91
|
-
|
92
|
-
end
|
105
|
+
collection
|
106
|
+
end
|
93
107
|
|
94
108
|
def boolean_collection(klass, column, options)
|
95
109
|
[['Yes', true], ['No', false]]
|
96
110
|
end
|
97
111
|
|
98
112
|
def filter_check_boxes_input(klass, method, options = {})
|
99
|
-
input_name = (generate_association_input_name(method).to_s + "_in").to_sym
|
100
|
-
collection = find_collection_for_column(method, options)
|
101
|
-
selected_values =
|
102
|
-
checkboxes =
|
113
|
+
input_name = (generate_association_input_name(klass, method).to_s + "_in").to_sym
|
114
|
+
collection = find_collection_for_column(klass, method, options)
|
115
|
+
selected_values = params[input_name] || []
|
116
|
+
checkboxes = content_tag :div, :class => "check_boxes_wrapper" do
|
103
117
|
collection.map do |c|
|
104
118
|
label = c.is_a?(Array) ? c.first : c
|
105
119
|
value = c.is_a?(Array) ? c.last : c
|
@@ -1,9 +1,11 @@
|
|
1
1
|
module SimpleAdmin
|
2
2
|
module SidebarHelper
|
3
3
|
def sidebars
|
4
|
-
|
5
|
-
|
4
|
+
content = "".html_safe
|
5
|
+
@interface.sidebars_for(params[:action].to_sym).each do |sidebar|
|
6
|
+
content << instance_eval(&sidebar[:data])
|
6
7
|
end
|
8
|
+
content
|
7
9
|
end
|
8
10
|
end
|
9
11
|
end
|
@@ -12,7 +12,7 @@ module SimpleAdmin
|
|
12
12
|
options = @interface.options_for(params[:action].to_sym)
|
13
13
|
case options[:title]
|
14
14
|
when Proc
|
15
|
-
options[:title]
|
15
|
+
instance_exec(@resource, &options[:title])
|
16
16
|
when Symbol
|
17
17
|
if @resource
|
18
18
|
@resource.send(optons[:title])
|
@@ -36,7 +36,7 @@
|
|
36
36
|
<% @interface.attributes_for(:index).each do |col| %>
|
37
37
|
<td>
|
38
38
|
<% if col.data %>
|
39
|
-
<%=
|
39
|
+
<%= instance_exec(object, &col.data) %>
|
40
40
|
<% else %>
|
41
41
|
<%= pretty_format(object.send(col.attribute)) %>
|
42
42
|
<% end %>
|
@@ -66,7 +66,7 @@
|
|
66
66
|
<div class="panel_contents">
|
67
67
|
<%= form_tag '', :class => "q_search", :id => "q_search", :method => "get" do %>
|
68
68
|
<% @interface.filters_for(:index).each do |col| %>
|
69
|
-
<%= filter_for(col.attribute, @interface.constant) %>
|
69
|
+
<%= filter_for(col.attribute, @interface.constant, col.options) %>
|
70
70
|
<% end %>
|
71
71
|
<div class="buttons">
|
72
72
|
<input name="commit" type="submit" value="Filter" />
|
data/lib/simple_admin.rb
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
module SimpleAdmin
|
2
2
|
require 'simple_admin/engine' if defined?(Rails) && Rails::VERSION::MAJOR == 3
|
3
|
+
require 'simple_admin/interface'
|
4
|
+
require 'simple_admin/builder'
|
5
|
+
require 'simple_admin/section'
|
6
|
+
require 'simple_admin/attributes'
|
7
|
+
require 'simple_admin/filters'
|
8
|
+
require 'simple_admin/breadcrumbs'
|
9
|
+
|
3
10
|
|
4
11
|
mattr_accessor :require_user_method,
|
5
12
|
:current_user_method,
|
@@ -36,7 +43,7 @@ module SimpleAdmin
|
|
36
43
|
@@registered = []
|
37
44
|
# We load up all of the admin files on launch, if they change you need to restart
|
38
45
|
begin
|
39
|
-
Dir[Rails.root.join("app/admin/**/*.rb")].each {|f|
|
46
|
+
Dir[Rails.root.join("app/admin/**/*.rb")].each {|f| load f}
|
40
47
|
rescue LoadError => e
|
41
48
|
# For certain kinds of load errors, we want to give a more helpful message
|
42
49
|
if e.message.match(/Expected .* to define .*/)
|
@@ -49,6 +56,11 @@ module SimpleAdmin
|
|
49
56
|
@@registered
|
50
57
|
end
|
51
58
|
|
59
|
+
# Clear the routes and registered interfaces
|
60
|
+
def unregister
|
61
|
+
@@registered = nil
|
62
|
+
end
|
63
|
+
|
52
64
|
# Called by the initializer
|
53
65
|
#
|
54
66
|
# SimpleAdmin.setup do |config|
|
data/lib/simple_admin/builder.rb
CHANGED
data/lib/simple_admin/engine.rb
CHANGED
@@ -4,5 +4,17 @@ require 'rails'
|
|
4
4
|
module SimpleAdmin
|
5
5
|
class Engine < Rails::Engine
|
6
6
|
isolate_namespace SimpleAdmin
|
7
|
+
initializer 'simple_admin' do
|
8
|
+
if Rails.env == "development"
|
9
|
+
simple_admin_reloader = ActiveSupport::FileUpdateChecker.new(Dir["app/admin/**/*"], true) do
|
10
|
+
SimpleAdmin.unregister
|
11
|
+
Rails.application.reload_routes!
|
12
|
+
end
|
13
|
+
|
14
|
+
ActionDispatch::Callbacks.to_prepare do
|
15
|
+
simple_admin_reloader.execute_if_updated
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
7
19
|
end
|
8
20
|
end
|
@@ -7,7 +7,7 @@ module SimpleAdmin
|
|
7
7
|
def initialize(resource, options={}, &block)
|
8
8
|
if resource.is_a?(Class)
|
9
9
|
@constant = resource
|
10
|
-
@symbol = resource.name.
|
10
|
+
@symbol = resource.name.underscore.to_sym
|
11
11
|
else
|
12
12
|
@constant = resource.to_s.camelize.singularize.constantize
|
13
13
|
@symbol = resource.to_sym
|
@@ -22,19 +22,20 @@ module SimpleAdmin
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def filters_for(sym)
|
25
|
-
|
25
|
+
options_for(sym)[:filters].attributes
|
26
26
|
end
|
27
27
|
|
28
28
|
def attributes_for(sym)
|
29
|
-
|
29
|
+
options_for(sym)[:attributes].attributes
|
30
30
|
end
|
31
31
|
|
32
32
|
def sidebars_for(sym)
|
33
|
-
|
33
|
+
options_for(sym)[:sidebars] || []
|
34
34
|
end
|
35
35
|
|
36
36
|
def options_for(sym)
|
37
|
-
|
37
|
+
sym = :form if [:new, :edit].include?(sym)
|
38
|
+
section(sym).options || {}
|
38
39
|
end
|
39
40
|
|
40
41
|
def actions
|
data/lib/simple_admin/version.rb
CHANGED
@@ -0,0 +1,31 @@
|
|
1
|
+
# Based on the routes.rake tasks from Rails
|
2
|
+
namespace :routes do
|
3
|
+
desc 'Print out all defined routes in match order, with names. Target specific controller with CONTROLLER=x.'
|
4
|
+
task :simple_admin => :environment do
|
5
|
+
all_routes = SimpleAdmin::Engine.routes.routes
|
6
|
+
|
7
|
+
if ENV['CONTROLLER']
|
8
|
+
all_routes = all_routes.select{ |route| route.defaults[:controller] == ENV['CONTROLLER'] }
|
9
|
+
end
|
10
|
+
|
11
|
+
routes = all_routes.collect do |route|
|
12
|
+
|
13
|
+
reqs = route.requirements.dup
|
14
|
+
reqs[:to] = route.app unless route.app.class.name.to_s =~ /^ActionDispatch::Routing/
|
15
|
+
reqs = reqs.empty? ? "" : reqs.inspect
|
16
|
+
|
17
|
+
{:name => route.name.to_s, :verb => route.verb.to_s, :path => route.path, :reqs => reqs}
|
18
|
+
end
|
19
|
+
|
20
|
+
# Skip the route if it's internal info route
|
21
|
+
routes.reject! { |r| r[:path] =~ %r{/rails/info/properties|^/assets} }
|
22
|
+
|
23
|
+
name_width = routes.map{ |r| r[:name].length }.max
|
24
|
+
verb_width = routes.map{ |r| r[:verb].length }.max
|
25
|
+
path_width = routes.map{ |r| r[:path].length }.max
|
26
|
+
|
27
|
+
routes.each do |r|
|
28
|
+
puts "#{r[:name].rjust(name_width)} #{r[:verb].ljust(verb_width)} #{r[:path].ljust(path_width)} #{r[:reqs]}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -14,7 +14,7 @@ describe SimpleAdmin::AdminController do
|
|
14
14
|
|
15
15
|
it "should render the sidebars" do
|
16
16
|
SimpleAdmin.expects(:success)
|
17
|
-
@block = Proc.new {
|
17
|
+
@block = Proc.new { SimpleAdmin.success }
|
18
18
|
@sidebar = {:title => 'Awes!', :data => @block}
|
19
19
|
SimpleAdmin::Interface.any_instance.expects(:sidebars_for).with(:index).returns([@sidebar])
|
20
20
|
get :index, :interface => "things"
|
@@ -1,11 +1,19 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
+
class ThingWithCrazyClassName < Thing; end
|
4
|
+
|
3
5
|
describe SimpleAdmin::Interface do
|
4
6
|
it "accepts a constant as the resource" do
|
5
7
|
@interface = SimpleAdmin.register(Thing)
|
6
8
|
@interface.constant.should == Thing
|
7
9
|
end
|
8
10
|
|
11
|
+
it "accepts a crazy constant as the resource" do
|
12
|
+
@interface = SimpleAdmin.register(ThingWithCrazyClassName)
|
13
|
+
@interface.constant.should == ThingWithCrazyClassName
|
14
|
+
@interface.member.should == "thing_with_crazy_class_name"
|
15
|
+
end
|
16
|
+
|
9
17
|
it "accepts a symbol as the resource" do
|
10
18
|
@interface = SimpleAdmin.register(:thing)
|
11
19
|
@interface.constant.should == Thing
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple_admin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
+
- 2
|
8
9
|
- 1
|
9
|
-
|
10
|
-
version: 0.1.0
|
10
|
+
version: 0.2.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Jeff Rafter
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-06-
|
18
|
+
date: 2011-06-22 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -184,6 +184,7 @@ files:
|
|
184
184
|
- .gitignore
|
185
185
|
- .rspec
|
186
186
|
- Gemfile
|
187
|
+
- LICENSE
|
187
188
|
- README.rdoc
|
188
189
|
- Rakefile
|
189
190
|
- TODO.rdoc
|
@@ -222,6 +223,7 @@ files:
|
|
222
223
|
- lib/simple_admin/interface.rb
|
223
224
|
- lib/simple_admin/section.rb
|
224
225
|
- lib/simple_admin/version.rb
|
226
|
+
- lib/tasks/routes.rake
|
225
227
|
- rails/init.rb
|
226
228
|
- simple_admin.gemspec
|
227
229
|
- spec/acceptance/admin_thing_spec.rb
|