simple_admin 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/.gitignore +6 -0
  2. data/.rspec +2 -0
  3. data/Gemfile +12 -0
  4. data/README.rdoc +318 -0
  5. data/Rakefile +67 -0
  6. data/TODO.rdoc +4 -0
  7. data/app/assets/images/simple_admin/active_admin/admin_notes_icon.png +0 -0
  8. data/app/assets/images/simple_admin/active_admin/loading.gif +0 -0
  9. data/app/assets/images/simple_admin/active_admin/nested_menu_arrow.gif +0 -0
  10. data/app/assets/images/simple_admin/active_admin/nested_menu_arrow_dark.gif +0 -0
  11. data/app/assets/images/simple_admin/active_admin/orderable.png +0 -0
  12. data/app/assets/javascripts/simple_admin/active_admin.js +434 -0
  13. data/app/assets/stylesheets/simple_admin/active_admin.css +1445 -0
  14. data/app/controllers/simple_admin/admin_controller.rb +117 -0
  15. data/app/helpers/simple_admin/admin_helper.rb +11 -0
  16. data/app/helpers/simple_admin/display_helper.rb +38 -0
  17. data/app/helpers/simple_admin/filter_helper.rb +147 -0
  18. data/app/helpers/simple_admin/header_helper.rb +60 -0
  19. data/app/helpers/simple_admin/path_helper.rb +12 -0
  20. data/app/helpers/simple_admin/sidebar_helper.rb +9 -0
  21. data/app/helpers/simple_admin/table_helper.rb +39 -0
  22. data/app/helpers/simple_admin/title_helper.rb +35 -0
  23. data/app/views/layouts/simple_admin.html.erb +41 -0
  24. data/app/views/simple_admin/admin/_form.html.erb +16 -0
  25. data/app/views/simple_admin/admin/edit.html.erb +7 -0
  26. data/app/views/simple_admin/admin/index.csv.erb +19 -0
  27. data/app/views/simple_admin/admin/index.html.erb +82 -0
  28. data/app/views/simple_admin/admin/new.html.erb +7 -0
  29. data/app/views/simple_admin/admin/show.html.erb +22 -0
  30. data/config/routes.rb +8 -0
  31. data/lib/rails/generators/simple_admin/simple_admin_generator.rb +33 -0
  32. data/lib/rails/generators/simple_admin/templates/initializer.rb +76 -0
  33. data/lib/simple_admin.rb +100 -0
  34. data/lib/simple_admin/attributes.rb +80 -0
  35. data/lib/simple_admin/breadcrumbs.rb +24 -0
  36. data/lib/simple_admin/builder.rb +35 -0
  37. data/lib/simple_admin/engine.rb +8 -0
  38. data/lib/simple_admin/filters.rb +5 -0
  39. data/lib/simple_admin/interface.rb +55 -0
  40. data/lib/simple_admin/section.rb +30 -0
  41. data/lib/simple_admin/version.rb +3 -0
  42. data/rails/init.rb +2 -0
  43. data/simple_admin.gemspec +34 -0
  44. data/spec/acceptance/admin_thing_spec.rb +13 -0
  45. data/spec/controllers/simple_admin/admin_controller_spec.rb +95 -0
  46. data/spec/factories.rb +14 -0
  47. data/spec/simple_admin/attributes_spec.rb +106 -0
  48. data/spec/simple_admin/breadcrumbs_spec.rb +18 -0
  49. data/spec/simple_admin/builder_spec.rb +57 -0
  50. data/spec/simple_admin/engine_spec.rb +9 -0
  51. data/spec/simple_admin/filters_spec.rb +16 -0
  52. data/spec/simple_admin/interface_spec.rb +98 -0
  53. data/spec/simple_admin/section_spec.rb +63 -0
  54. data/spec/simple_admin/simple_admin_spec.rb +68 -0
  55. data/spec/spec_helper.rb +32 -0
  56. metadata +285 -0
@@ -0,0 +1,41 @@
1
+ <!DOCTYPE html><html>
2
+ <head>
3
+ <meta content="text/html; charset=utf-8" http-equiv="Content-type"/>
4
+ <title><%= title %></title>
5
+ <%- if protect_against_forgery? -%>
6
+ <meta name="authenticity-token" id="authenticity-token" content="<%= form_authenticity_token %>" />
7
+ <%- end -%>
8
+ <%= stylesheet_link_tag SimpleAdmin.stylesheet %>
9
+ <%= javascript_include_tag SimpleAdmin.javascript %>
10
+ </head>
11
+ <body class="index admin_occasions">
12
+ <div id="wrapper">
13
+ <div id="header">
14
+ <h1 id="site_title"><%= site_title %></h1>
15
+ <%= tabs %>
16
+ <%= utility_nav %>
17
+ </div>
18
+ <div id="title_bar">
19
+ <%= breadcrumbs %>
20
+ <h2 id="page_title"><%= page_title %></h2>
21
+ <%= action_items %>
22
+ </div>
23
+ <div class="with_sidebar" id="active_admin_content">
24
+ <div id="main_content_wrapper">
25
+ <div id="main_content">
26
+ <%= yield :content %>
27
+ </div>
28
+ </div>
29
+ <div id="sidebar">
30
+ <%= yield :sidebar %>
31
+ </div>
32
+ </div>
33
+ <div id="footer">
34
+ <%= yield :footer %>
35
+ </div>
36
+ </div>
37
+ </body>
38
+ </html>
39
+
40
+
41
+
@@ -0,0 +1,16 @@
1
+ <%= send(SimpleAdmin.form_for_helper, @resource, :as => @interface.member.to_sym,
2
+ :url => resource_path(@resource), :html => {:class => "formtastic #{@interface.member}"}) do |form| %>
3
+ <fieldset class="inputs">
4
+ <ol>
5
+ <% @interface.attributes_for(:form).each do |col| %>
6
+ <%= form.input col.attribute %>
7
+ <% end %>
8
+ </ol>
9
+ </fieldset>
10
+ <fieldset class="buttons">
11
+ <ol>
12
+ <li class="commit"><input class="save" name="commit" type="submit" value="Save <%= @interface.member.titleize %>"></li>
13
+ <li class="cancel"><%= link_to "Cancel", send("simple_admin_#{@interface.collection}_path") %></li>
14
+ </ol>
15
+ </fieldset>
16
+ <% end %>
@@ -0,0 +1,7 @@
1
+ <% content_for :content do %>
2
+ <% render :partial => 'form' %>
3
+ <% end %>
4
+
5
+ <% content_for :sidebar do %>
6
+ <%= sidebars %>
7
+ <% end %>
@@ -0,0 +1,19 @@
1
+ <%-
2
+ # Based on Active Admin
3
+ generator = RUBY_VERSION =~ /^1.8/ ? FasterCSV : CSV
4
+
5
+ output = generator.generate do |csv|
6
+ cols = @interface.attributes_for(:index)
7
+ csv << cols.map(&:title)
8
+ @collection.each do |object|
9
+ csv << cols.map do |col|
10
+ if col.data
11
+ col.data.call(object, col)
12
+ else
13
+ pretty_format(object.send(col.attribute))
14
+ end
15
+ end
16
+ end
17
+ end
18
+ %>
19
+ <%= output.html_safe %>
@@ -0,0 +1,82 @@
1
+ <% content_for :content do %>
2
+ <div class="paginated_collection">
3
+ <div class="pagination_information">
4
+ <% if @collection.num_pages < 2 %>
5
+ <% if @collection.size == 0 %>
6
+ No <%= @interface.collection.titleize %> found
7
+ <% elsif @collection.size == 1 %>
8
+ Displaying <b>1</b> <%= @interface.member.titleize %>
9
+ <% else %>
10
+ Displaying <b>all <%= @collection.size %></b> <%= @interface.collection.titleize %>
11
+ <% end %>
12
+ <% else %>
13
+ Displaying <%= @interface.collection.titleize %>
14
+ <b><%= (@collection.current_page * SimpleAdmin.default_per_page) - SimpleAdmin.default_per_page + 1 %>&nbsp;-&nbsp;<%= (@collection.current_page * SimpleAdmin.default_per_page) > @collection.total_count ? @collection.total_count : (@collection.current_page * SimpleAdmin.default_per_page) %></b>
15
+ of <b><%= @collection.total_count %></b> in total
16
+ <% end %>
17
+ </div>
18
+ <div class="paginated_collection_contents">
19
+ <div class="index_content">
20
+ <div class="index_as_table">
21
+ <table border="0" class="index_table" cellspacing="0" cellpadding="0" id="<%= @interface.collection %>">
22
+ <thead>
23
+ <tr>
24
+ <% @interface.attributes_for(:index).each do |col| %>
25
+ <th class="<%= sortable_header_classes_for(col) %>">
26
+ <%= link_to(col.title,
27
+ request.query_parameters.merge(:order => "#{col.sort_key}_#{order_for_sort_key(col.sort_key)}").except(:page)) %>
28
+ </th>
29
+ <% end %>
30
+ <th>&nbsp;</th>
31
+ </tr>
32
+ </thead>
33
+ <tbody>
34
+ <% @collection.each do |object| %>
35
+ <tr class="<%= cycle('odd', 'even') %>">
36
+ <% @interface.attributes_for(:index).each do |col| %>
37
+ <td>
38
+ <% if col.data %>
39
+ <%= col.data.call(object, col) %>
40
+ <% else %>
41
+ <%= pretty_format(object.send(col.attribute)) %>
42
+ <% end %>
43
+ </td>
44
+ <% end %>
45
+ <td><%= resource_actions(object) %></td>
46
+ </tr>
47
+ <% end %>
48
+ </tbody>
49
+ </table>
50
+ </div>
51
+ </div>
52
+ </div>
53
+ <div id="index_footer">
54
+ Download:&nbsp;
55
+ <% [:csv, :xml, :json].each do |format| %>
56
+ <%= link_to format.to_s.upcase, { :format => format}.merge(request.query_parameters.except(:commit, :format)) %>
57
+ <% end %>
58
+ </div>
59
+ <%= paginate(@collection) %>
60
+ </div>
61
+ <% end %>
62
+
63
+ <% content_for :sidebar do %>
64
+ <div class="panel sidebar_section" id="filters_sidebar_section">
65
+ <h3>Filters</h3>
66
+ <div class="panel_contents">
67
+ <%= form_tag '', :class => "q_search", :id => "q_search", :method => "get" do %>
68
+ <% @interface.filters_for(:index).each do |col| %>
69
+ <%= filter_for(col.attribute, @interface.constant) %>
70
+ <% end %>
71
+ <div class="buttons">
72
+ <input name="commit" type="submit" value="Filter" />
73
+ <a href="#" class="clear_filters_btn">Clear Filters</a>
74
+ <input id="order" name="order" type="hidden" value="id_desc" />
75
+ <input id="scope" name="scope" type="hidden" />
76
+ </div>
77
+ <% end %>
78
+ </div>
79
+ </div>
80
+
81
+ <%= sidebars %>
82
+ <% end %>
@@ -0,0 +1,7 @@
1
+ <% content_for :content do %>
2
+ <% render :partial => 'form' %>
3
+ <% end %>
4
+
5
+ <% content_for :sidebar do %>
6
+ <%= sidebars %>
7
+ <% end %>
@@ -0,0 +1,22 @@
1
+ <% content_for :content do %>
2
+ <div class="panel">
3
+ <h3><%= @interface.member.titleize %> Details</h3>
4
+ <div class="panel_contents">
5
+ <div class="<%= @interface.member %> attributes_table"
6
+ id="<%= ['attributes_table', @interface.member, @resource.to_param].join("_") %>">
7
+ <table border="0" cellspacing="0" cellpadding="0">
8
+ <% @interface.attributes_for(:show).each do |attr| %>
9
+ <tr>
10
+ <th><%= attr.title %></th>
11
+ <td><%= data_for(attr) %></td>
12
+ </tr>
13
+ <% end %>
14
+ </table>
15
+ </div>
16
+ </div>
17
+ </div>
18
+ <% end %>
19
+
20
+ <% content_for :sidebar do %>
21
+ <%= sidebars %>
22
+ <% end %>
@@ -0,0 +1,8 @@
1
+ SimpleAdmin::Engine.routes.draw do
2
+ SimpleAdmin::registered.each do |interface|
3
+ resources interface.collection,
4
+ :controller => :admin,
5
+ :as => "simple_admin_#{interface.collection}",
6
+ :defaults => {:interface => interface.collection}
7
+ end
8
+ end
@@ -0,0 +1,33 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+
4
+ class SimpleAdminGenerator < Rails::Generators::Base
5
+ desc <<-CONTENT
6
+ This will mount SimpleAdmin in your routes.rb using the admin \
7
+ path. It will also install a simple_admin initializer file in \
8
+ your config where you can setup the options.\
9
+ \
10
+ Once complete, register admin interfaces like app/admin/posts.rb:\
11
+ \
12
+ SimpleAdmin.register :posts do\
13
+ end\
14
+
15
+ CONTENT
16
+
17
+ def self.source_root
18
+ File.join(File.dirname(__FILE__), 'templates')
19
+ end
20
+
21
+ def copy_initializer_file
22
+ copy_file 'initializer.rb', 'config/initializers/simple_admin.rb'
23
+ end
24
+
25
+ def app_admin
26
+ empty_directory('app/admin')
27
+ end
28
+
29
+ def add_simple_admin_routes
30
+ simple_admin_routes = %(mount SimpleAdmin::Engine => '/admin'\n)
31
+ route simple_admin_routes
32
+ end
33
+ end
@@ -0,0 +1,76 @@
1
+ # You can use this file to setup all of your simple_admin
2
+ # configuration defaults. If you change this file, you may
3
+ # need to restart your Rails environment
4
+
5
+ SimpleAdmin.setup do |config|
6
+
7
+ # The +require_user_method+ setting allows you to specify which
8
+ # controller method should be called before rendering any admin
9
+ # pages. There is no default for this method. If it is not
10
+ # present then simple_admin will not do any admin verification
11
+ # prior to performing its controller actions.
12
+ #
13
+ # It is possible to check for admin status using application level
14
+ # before filters or even using the +before+ block within each
15
+ # individual admin interface registration.
16
+ #
17
+ # To set this, specify the controller method you want called as a
18
+ # symbol:
19
+ #
20
+ # config.require_user_method = :require_admin
21
+
22
+
23
+ # The +current_user_method+ is used by simple_admin to determine if
24
+ # there is a logged in user. There is no default for this property.
25
+ # If it is not present, no logged in user method will be checked and
26
+ # user information will not be displayed in the header of admin forms.
27
+ #
28
+ # To set this, specify the controller method you want called as a
29
+ # symbol:
30
+ #
31
+ # config.current_user_method = :current_user
32
+
33
+
34
+ # The +current_user_name_method+ is used by simple_admin to access the
35
+ # display name of the currently logged in user. There is no default for
36
+ # this property. If it is not present, any logged in user name will
37
+ # not be displayed in the header of admin forms.
38
+ #
39
+ # To set this, specify the controller method you want called as a
40
+ # symbol:
41
+ #
42
+ # config.current_user_name_method = :current_user_name
43
+
44
+
45
+ # The +site_title+ is displayed in the header of admin pages. If empty
46
+ # this value defaults to +Rails.application.class.parent_name.titleize+:
47
+ #
48
+ # config.site_title = "My Website"
49
+
50
+
51
+ # The +default_per_page+ value allows you to control how many results
52
+ # appear on admin index pages. This value is fed into kaminari and is
53
+ # defaulted to 25 if not present:
54
+ #
55
+ # config.default_per_page = 25
56
+
57
+
58
+ # The +form_for_helper+ defaults to the +:semantic_form_for+ helper
59
+ # from formtastic. If you want to use another engine, like +simple_form+
60
+ # you can change this property and the gem requirements. Note that the
61
+ # default styling from active_admin relies on formtastic output.
62
+ #
63
+ # config.form_for_helper = :semantic_form_for
64
+
65
+
66
+ # The +stylesheet+ and +javascript+ properties are used within the admin
67
+ # layout and are defaulted to the active_admin styles and scripts. You
68
+ # may want to override these styles, or simply move them to your public
69
+ # folder so that they are not served through rails. These properties allow
70
+ # you to manage where the assets are stored (either within the default
71
+ # pipeline or no):
72
+ #
73
+ # config.stylesheet = "simple_admin/active_admin.css"
74
+ # config.javascript = "simple_admin/active_admin.js"
75
+
76
+ end
@@ -0,0 +1,100 @@
1
+ module SimpleAdmin
2
+ require 'simple_admin/engine' if defined?(Rails) && Rails::VERSION::MAJOR == 3
3
+
4
+ mattr_accessor :require_user_method,
5
+ :current_user_method,
6
+ :current_user_name_method,
7
+ :site_title,
8
+ :default_per_page,
9
+ :form_for_helper,
10
+ :stylesheet,
11
+ :javascript
12
+
13
+ class << self
14
+ def site_title
15
+ @@site_title || Rails.application.class.parent_name.titleize
16
+ end
17
+
18
+ def default_per_page
19
+ @@default_per_page || 25
20
+ end
21
+
22
+ def form_for_helper
23
+ @@form_for_helper || :semantic_form_for
24
+ end
25
+
26
+ def stylesheet
27
+ @@stylesheet || "simple_admin/active_admin.css"
28
+ end
29
+
30
+ def javascript
31
+ @@javascript || "simple_admin/active_admin.js"
32
+ end
33
+
34
+ def registered
35
+ unless defined?(@@registered) && @@registered
36
+ @@registered = []
37
+ # We load up all of the admin files on launch, if they change you need to restart
38
+ begin
39
+ Dir[Rails.root.join("app/admin/**/*.rb")].each {|f| require f}
40
+ rescue LoadError => e
41
+ # For certain kinds of load errors, we want to give a more helpful message
42
+ if e.message.match(/Expected .* to define .*/)
43
+ raise(InvalidAdminFile.new(e))
44
+ else
45
+ raise e
46
+ end
47
+ end
48
+ end
49
+ @@registered
50
+ end
51
+
52
+ # Called by the initializer
53
+ #
54
+ # SimpleAdmin.setup do |config|
55
+ # config.site_title = "My Website"
56
+ # end
57
+ #
58
+ def setup
59
+ yield self
60
+ end
61
+
62
+ # Registers a model for administration:
63
+ #
64
+ # SimpleAdmin.register :post do
65
+ # end
66
+ #
67
+ # Various configuration options are available within the block
68
+ def register(resource, options={}, &block)
69
+ interface = SimpleAdmin::Interface.new(resource, options, &block)
70
+ self.registered << interface
71
+ interface
72
+ end
73
+ end
74
+
75
+ class ConfigurationNotFound < StandardError
76
+ attr_accessor :message
77
+
78
+ def initialize(option)
79
+ @message = "SimpleAdmin configuration option #{option} not found. " +
80
+ "Please set this in config/initializers/simple_admin.rb."
81
+ end
82
+ end
83
+
84
+ class InvalidAdminFile < LoadError
85
+ attr_accessor :message
86
+
87
+ def initialize(e)
88
+ @message = "#{e.message}. Try renaming app/admin/#{File.basename(e.blamed_files.first)} " +
89
+ "to app/admin/#{File.basename(e.blamed_files.first, '.rb')}s.rb"
90
+ end
91
+ end
92
+
93
+ class UnknownAdminInterface < StandardError
94
+ attr_accessor :message
95
+
96
+ def initialize(e)
97
+ @message = "SimpleAdmin interface unknown, make sure you mount SimpleAdmin in your routes and that you have registered an interface for this resource"
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,80 @@
1
+ module SimpleAdmin
2
+ class Attributes
3
+ # Which columns to skip when automatically rendering a form without any fields specified
4
+ SKIPPED_COLUMNS = [:created_at, :updated_at, :created_on, :updated_on, :lock_version, :version]
5
+
6
+ attr_reader :attributes
7
+
8
+ # Allows you to specify a set of attributes for a section
9
+ #
10
+ # Available options:
11
+ #
12
+ # :except An array of excluded attribute names as symbols
13
+ # :only An array of attribute names for this view
14
+ #
15
+ def initialize(interface, section, options={}, &block)
16
+ @interface = interface
17
+ @section = section
18
+ defaults(options)
19
+ instance_eval(&block) if block_given?
20
+ end
21
+
22
+ # Clear the attributes for this section
23
+ def clear
24
+ @attributes = []
25
+ end
26
+
27
+ # Define or override an attribute for this section
28
+ #
29
+ # Available options:
30
+ #
31
+ # :sortable +true+ or +false+ (defaults to +true+)
32
+ # :sort_key a column name used when sorting this column (defaults to the column for this attribute)
33
+ #
34
+ def attribute(name, options={}, &block)
35
+ attr = @attributes.find {|attr| attr.attribute == name.to_sym }
36
+ unless attr
37
+ attr = OpenStruct.new
38
+ @attributes << attr
39
+ end
40
+ attr.attribute = name.to_sym
41
+ attr.options = options
42
+ attr.data = block
43
+ attr.title = options[:title] || name.to_s.titleize
44
+ attr.sortable = options[:sortable].nil? || !(options[:sortable] === false)
45
+ attr.sort_key = (options[:sort_key] || name).to_s
46
+ attr
47
+ end
48
+
49
+ # Define the default attributes for this section
50
+ #
51
+ # If the current section is a form it will only use content columns and will
52
+ # skip timestamps and primary key fields.
53
+ #
54
+ # Available options:
55
+ #
56
+ # :except An array of excluded attribute names as symbols
57
+ # :only An array of attribute names for this view
58
+ #
59
+ def defaults(options={})
60
+ clear
61
+ if @section.section == :form
62
+ association_columns = @interface.constant.reflections.map do |name, ref|
63
+ if ref.macro == :belongs_to && ref.options[:polymorphic] != true
64
+ name.to_sym
65
+ end
66
+ end.compact
67
+
68
+ cols = @interface.constant.content_columns.map {|col| col.name.to_sym }
69
+ cols += association_columns
70
+ cols -= SKIPPED_COLUMNS
71
+ cols.compact!
72
+ else
73
+ cols = @interface.constant.columns.map{|col| col.name.to_sym }
74
+ end
75
+ cols -= options[:except] if options[:except]
76
+ cols &= options[:only] if options[:only]
77
+ cols.each {|col| attribute(col.to_s) }
78
+ end
79
+ end
80
+ end