activeadmin 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activeadmin might be problematic. Click here for more details.
- data/.document +5 -0
- data/.gitignore +25 -0
- data/Gemfile +16 -0
- data/LICENSE +20 -0
- data/README.rdoc +201 -0
- data/Rakefile +71 -0
- data/active_admin.gemspec +22 -0
- data/lib/active_admin.rb +229 -0
- data/lib/active_admin/action_builder.rb +60 -0
- data/lib/active_admin/action_items.rb +48 -0
- data/lib/active_admin/asset_registration.rb +34 -0
- data/lib/active_admin/breadcrumbs.rb +26 -0
- data/lib/active_admin/dashboards.rb +50 -0
- data/lib/active_admin/dashboards/dashboard_controller.rb +40 -0
- data/lib/active_admin/dashboards/renderer.rb +45 -0
- data/lib/active_admin/dashboards/section.rb +43 -0
- data/lib/active_admin/dashboards/section_renderer.rb +28 -0
- data/lib/active_admin/filters.rb +189 -0
- data/lib/active_admin/form_builder.rb +91 -0
- data/lib/active_admin/helpers/optional_display.rb +34 -0
- data/lib/active_admin/menu.rb +42 -0
- data/lib/active_admin/menu_item.rb +67 -0
- data/lib/active_admin/namespace.rb +111 -0
- data/lib/active_admin/page_config.rb +15 -0
- data/lib/active_admin/pages.rb +11 -0
- data/lib/active_admin/pages/base.rb +92 -0
- data/lib/active_admin/pages/edit.rb +21 -0
- data/lib/active_admin/pages/index.rb +58 -0
- data/lib/active_admin/pages/index/blog.rb +65 -0
- data/lib/active_admin/pages/index/table.rb +48 -0
- data/lib/active_admin/pages/index/thumbnails.rb +40 -0
- data/lib/active_admin/pages/new.rb +21 -0
- data/lib/active_admin/pages/show.rb +54 -0
- data/lib/active_admin/renderer.rb +72 -0
- data/lib/active_admin/resource.rb +96 -0
- data/lib/active_admin/resource_controller.rb +325 -0
- data/lib/active_admin/sidebar.rb +78 -0
- data/lib/active_admin/table_builder.rb +162 -0
- data/lib/active_admin/tabs_renderer.rb +39 -0
- data/lib/active_admin/version.rb +3 -0
- data/lib/active_admin/view_helpers.rb +106 -0
- data/lib/active_admin/views/active_admin_dashboard/index.html.erb +1 -0
- data/lib/active_admin/views/active_admin_default/edit.html.erb +1 -0
- data/lib/active_admin/views/active_admin_default/index.csv.erb +2 -0
- data/lib/active_admin/views/active_admin_default/index.html.erb +1 -0
- data/lib/active_admin/views/active_admin_default/new.html.erb +1 -0
- data/lib/active_admin/views/active_admin_default/show.html.erb +1 -0
- data/lib/active_admin/views/layouts/active_admin.html.erb +40 -0
- data/lib/activeadmin.rb +1 -0
- data/lib/generators/active_admin/install/install_generator.rb +31 -0
- data/lib/generators/active_admin/install/templates/active_admin.css +325 -0
- data/lib/generators/active_admin/install/templates/active_admin.js +10 -0
- data/lib/generators/active_admin/install/templates/active_admin.rb +47 -0
- data/lib/generators/active_admin/install/templates/active_admin_vendor.js +382 -0
- data/lib/generators/active_admin/install/templates/dashboards.rb +36 -0
- data/lib/generators/active_admin/install/templates/images/orderable.gif +0 -0
- data/lib/generators/active_admin/resource/resource_generator.rb +16 -0
- data/lib/generators/active_admin/resource/templates/admin.rb +3 -0
- data/spec/integration/dashboard_spec.rb +44 -0
- data/spec/integration/index_as_blog_spec.rb +65 -0
- data/spec/integration/index_as_csv_spec.rb +40 -0
- data/spec/integration/index_as_table_spec.rb +160 -0
- data/spec/integration/index_as_thumbnails_spec.rb +43 -0
- data/spec/integration/layout_spec.rb +82 -0
- data/spec/integration/new_view_spec.rb +52 -0
- data/spec/integration/show_view_spec.rb +91 -0
- data/spec/spec_helper.rb +104 -0
- data/spec/support/rails_template.rb +19 -0
- data/spec/unit/action_builder_spec.rb +76 -0
- data/spec/unit/action_items_spec.rb +41 -0
- data/spec/unit/active_admin_spec.rb +52 -0
- data/spec/unit/asset_registration_spec.rb +37 -0
- data/spec/unit/controller_filters_spec.rb +26 -0
- data/spec/unit/dashboard_section_spec.rb +63 -0
- data/spec/unit/dashboards_spec.rb +59 -0
- data/spec/unit/filter_form_builder_spec.rb +157 -0
- data/spec/unit/form_builder_spec.rb +238 -0
- data/spec/unit/menu_item_spec.rb +137 -0
- data/spec/unit/menu_spec.rb +53 -0
- data/spec/unit/namespace_spec.rb +107 -0
- data/spec/unit/registration_spec.rb +46 -0
- data/spec/unit/renderer_spec.rb +100 -0
- data/spec/unit/resource_controller_spec.rb +48 -0
- data/spec/unit/resource_spec.rb +197 -0
- data/spec/unit/routing_spec.rb +12 -0
- data/spec/unit/sidebar_spec.rb +96 -0
- data/spec/unit/table_builder_spec.rb +162 -0
- data/spec/unit/tabs_renderer_spec.rb +34 -0
- metadata +247 -0
@@ -0,0 +1,91 @@
|
|
1
|
+
module ActiveAdmin
|
2
|
+
class FormBuilder < ::Formtastic::SemanticFormBuilder
|
3
|
+
|
4
|
+
def initialize(*args)
|
5
|
+
@form_buffers = ["".html_safe]
|
6
|
+
@skip_form_buffer = false
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
# Sets up buffering for this form which allows
|
11
|
+
# the entire form to be built in a block outside
|
12
|
+
# of the context of the view. Ie: you don't need
|
13
|
+
# to use erb tags.
|
14
|
+
def self.buffer_output_for(*method_names)
|
15
|
+
method_names.each do |method_name|
|
16
|
+
module_eval <<-EOF
|
17
|
+
def #{method_name}(*args)
|
18
|
+
content = block_given? ? with_new_form_buffer{ super } : super
|
19
|
+
return content if @skip_form_buffer
|
20
|
+
@form_buffers.last << content.html_safe
|
21
|
+
end
|
22
|
+
EOF
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
buffer_output_for :submit,
|
27
|
+
:label,
|
28
|
+
:inputs_for_nested_attributes,
|
29
|
+
:semantic_fields_for,
|
30
|
+
:text_field,
|
31
|
+
:text_area,
|
32
|
+
:datetime_select,
|
33
|
+
:time_select,
|
34
|
+
:date_select,
|
35
|
+
:radio_button,
|
36
|
+
:file_field,
|
37
|
+
:hidden_field,
|
38
|
+
:select,
|
39
|
+
:grouped_collection_select,
|
40
|
+
:collection_select
|
41
|
+
|
42
|
+
def inputs(*args, &block)
|
43
|
+
# Store that we are creating inputs without a block
|
44
|
+
@inputs_with_no_block = true unless block_given?
|
45
|
+
content = with_new_form_buffer { super }
|
46
|
+
@form_buffers.last << content.html_safe
|
47
|
+
end
|
48
|
+
|
49
|
+
# The input method returns a properly formatted string for
|
50
|
+
# its contents, so we want to skip the internal buffering
|
51
|
+
# while building up its contents
|
52
|
+
def input(*args)
|
53
|
+
@skip_form_buffer = true
|
54
|
+
content = with_new_form_buffer { super }
|
55
|
+
@skip_form_buffer = false
|
56
|
+
return content.html_safe if @inputs_with_no_block
|
57
|
+
@form_buffers.last << content.html_safe
|
58
|
+
end
|
59
|
+
|
60
|
+
# The buttons method always needs to be wrapped in a new buffer
|
61
|
+
def buttons(*args, &block)
|
62
|
+
content = with_new_form_buffer{ super }
|
63
|
+
@form_buffers.last << content.html_safe
|
64
|
+
end
|
65
|
+
|
66
|
+
def datepicker_input(method, options)
|
67
|
+
options = options.dup
|
68
|
+
options[:input_html] ||= {}
|
69
|
+
options[:input_html][:class] = [options[:input_html][:class], "datepicker"].compact.join(' ')
|
70
|
+
options[:input_html][:size] ||= "10"
|
71
|
+
string_input(method, options)
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def with_new_form_buffer
|
77
|
+
@form_buffers << "".html_safe
|
78
|
+
return_value = yield
|
79
|
+
@form_buffers.pop
|
80
|
+
return_value
|
81
|
+
end
|
82
|
+
|
83
|
+
def skip_form_buffers
|
84
|
+
@skip_form_buffer = true
|
85
|
+
return_value = yield
|
86
|
+
@skip_form_buffer = false
|
87
|
+
return_value
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module ActiveAdmin
|
2
|
+
|
3
|
+
# Shareable module to give a #display_on?(action) method
|
4
|
+
# which returns true or false depending on an options hash.
|
5
|
+
#
|
6
|
+
# The options hash accepts:
|
7
|
+
#
|
8
|
+
# :only => :index
|
9
|
+
# :only => [:index, :show]
|
10
|
+
# :except => :index
|
11
|
+
# :except => [:index, :show]
|
12
|
+
#
|
13
|
+
# call #normalize_display_options! after @options has been set
|
14
|
+
# to ensure that the display options are setup correctly
|
15
|
+
|
16
|
+
module OptionalDisplay
|
17
|
+
def display_on?(action)
|
18
|
+
return @options[:only].include?(action.to_sym) if @options[:only]
|
19
|
+
return !@options[:except].include?(action.to_sym) if @options[:except]
|
20
|
+
true
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def normalize_display_options!
|
26
|
+
if @options[:only]
|
27
|
+
@options[:only] = @options[:only].is_a?(Array) ? @options[:only] : [@options[:only]]
|
28
|
+
end
|
29
|
+
if @options[:except]
|
30
|
+
@options[:except] = @options[:except].is_a?(Array) ? @options[:except] : [@options[:except]]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module ActiveAdmin
|
2
|
+
class Menu
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@items = []
|
6
|
+
yield(self) if block_given?
|
7
|
+
end
|
8
|
+
|
9
|
+
def add(*args, &block)
|
10
|
+
@items << MenuItem.new(*args, &block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def [](name)
|
14
|
+
items.find{ |i| i.name == name }
|
15
|
+
end
|
16
|
+
|
17
|
+
def items
|
18
|
+
@items.sort
|
19
|
+
end
|
20
|
+
|
21
|
+
def find_by_url(url)
|
22
|
+
recursive_find_by_url(items, url)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def recursive_find_by_url(collection, url)
|
28
|
+
found = nil
|
29
|
+
collection.each do |item|
|
30
|
+
if item.url == url
|
31
|
+
found = item
|
32
|
+
break
|
33
|
+
else
|
34
|
+
found = recursive_find_by_url(item.children, url)
|
35
|
+
break if found
|
36
|
+
end
|
37
|
+
end
|
38
|
+
found
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module ActiveAdmin
|
2
|
+
class MenuItem
|
3
|
+
|
4
|
+
# Use this to get to the routes
|
5
|
+
include Rails.application.routes.url_helpers
|
6
|
+
|
7
|
+
attr_accessor :name, :url, :priority, :parent, :display_if_block
|
8
|
+
|
9
|
+
def initialize(name, url, priority = 10, options = {})
|
10
|
+
@name, @url, @priority = name, url, priority
|
11
|
+
@children = []
|
12
|
+
@cached_url = {} # Stores the cached url in a hash to allow us to change it and still cache it
|
13
|
+
|
14
|
+
@display_if_block = options.delete(:if)
|
15
|
+
|
16
|
+
yield(self) if block_given? # Builder style syntax
|
17
|
+
end
|
18
|
+
|
19
|
+
def add(name, url, priority=10, options = {}, &block)
|
20
|
+
item = MenuItem.new(name, url, priority, options, &block)
|
21
|
+
item.parent = self
|
22
|
+
@children << item
|
23
|
+
end
|
24
|
+
|
25
|
+
def children
|
26
|
+
@children.sort
|
27
|
+
end
|
28
|
+
|
29
|
+
def parent?
|
30
|
+
!parent.nil?
|
31
|
+
end
|
32
|
+
|
33
|
+
def dom_id
|
34
|
+
name.downcase.gsub( " ", '_' ).gsub( /[^a-z0-9_]/, '' )
|
35
|
+
end
|
36
|
+
|
37
|
+
def url
|
38
|
+
case @url
|
39
|
+
when Symbol
|
40
|
+
generated = send(@url) # Call the named route
|
41
|
+
else
|
42
|
+
generated = @url
|
43
|
+
end
|
44
|
+
@cached_url[@url] ||= generated
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns an array of the ancestory of this menu item
|
48
|
+
# The first item is the immediate parent fo the item
|
49
|
+
def ancestors
|
50
|
+
return [] unless parent?
|
51
|
+
[parent, parent.ancestors].flatten
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns the child item with the name passed in
|
55
|
+
# @blog_menu["Create New"] => <#MenuItem @name="Create New" >
|
56
|
+
def [](name)
|
57
|
+
@children.find{ |i| i.name == name }
|
58
|
+
end
|
59
|
+
|
60
|
+
def <=>(other)
|
61
|
+
result = priority <=> other.priority
|
62
|
+
result = name <=> other.name if result == 0
|
63
|
+
result
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module ActiveAdmin
|
2
|
+
class Namespace
|
3
|
+
|
4
|
+
attr_reader :resources, :name, :menu
|
5
|
+
|
6
|
+
def initialize(name)
|
7
|
+
@name = name.to_s.underscore.to_sym
|
8
|
+
@resources = {}
|
9
|
+
@menu = Menu.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def register(resource, options = {}, &block)
|
13
|
+
# Init and store the resource
|
14
|
+
config = Resource.new(self, resource, options)
|
15
|
+
@resources[config.camelized_resource_name] = config
|
16
|
+
|
17
|
+
# Register the resource
|
18
|
+
register_module unless root?
|
19
|
+
register_resource_controller(config, &block)
|
20
|
+
register_dashboard_controller(config)
|
21
|
+
register_with_menu(config)
|
22
|
+
|
23
|
+
# Return the config
|
24
|
+
config
|
25
|
+
end
|
26
|
+
|
27
|
+
def root?
|
28
|
+
name == :root
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns the name of the module if required. Will be nil if none
|
32
|
+
# is required.
|
33
|
+
#
|
34
|
+
# eg:
|
35
|
+
# Namespace.new(:admin).module_name # => 'Admin'
|
36
|
+
# Namespace.new(:root).module_name # => nil
|
37
|
+
#
|
38
|
+
def module_name
|
39
|
+
return nil if root?
|
40
|
+
@module_name ||= name.to_s.camelize
|
41
|
+
end
|
42
|
+
|
43
|
+
# Unload all the registered resources for this namespace
|
44
|
+
def unload!
|
45
|
+
unload_resources!
|
46
|
+
unload_dashboard!
|
47
|
+
unload_menu!
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
|
52
|
+
def unload_resources!
|
53
|
+
resources.each do |name, config|
|
54
|
+
parent = (module_name || 'Object').constantize
|
55
|
+
const_name = config.controller_name.split('::').last
|
56
|
+
# Remove the const if its been defined
|
57
|
+
parent.send(:remove_const, const_name) if parent.const_defined?(const_name)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def unload_dashboard!
|
62
|
+
# TODO: Only clear out my sections
|
63
|
+
Dashboards.clear_all_sections!
|
64
|
+
end
|
65
|
+
|
66
|
+
def unload_menu!
|
67
|
+
@menu = Menu.new
|
68
|
+
end
|
69
|
+
|
70
|
+
# Creates a ruby module to namespace all the classes in if required
|
71
|
+
def register_module
|
72
|
+
eval "module ::#{module_name}; end"
|
73
|
+
end
|
74
|
+
|
75
|
+
def register_resource_controller(config, &block)
|
76
|
+
eval "class ::#{config.controller_name} < ActiveAdmin::ResourceController; end"
|
77
|
+
config.controller.active_admin_config = config
|
78
|
+
config.controller.class_eval(&block) if block_given?
|
79
|
+
end
|
80
|
+
|
81
|
+
# Creates a dashboard controller for this config
|
82
|
+
def register_dashboard_controller(config)
|
83
|
+
eval "class ::#{config.dashboard_controller_name} < ActiveAdmin::Dashboards::DashboardController; end"
|
84
|
+
end
|
85
|
+
|
86
|
+
# Does all the work of registernig a config with the menu system
|
87
|
+
def register_with_menu(config)
|
88
|
+
menu.add("Dashboard", "#{name}_dashboard_path".to_sym, 1) unless menu["Dashboard"]
|
89
|
+
|
90
|
+
# The menu we're going to add this resource to
|
91
|
+
add_to = menu
|
92
|
+
|
93
|
+
# Adding as a child
|
94
|
+
if config.parent_menu_item_name
|
95
|
+
# Create the parent if it doesn't exist
|
96
|
+
menu.add(config.parent_menu_item_name, '#') unless menu[config.parent_menu_item_name]
|
97
|
+
add_to = menu[config.parent_menu_item_name]
|
98
|
+
end
|
99
|
+
|
100
|
+
# Check if this menu item has already been created
|
101
|
+
if add_to[config.menu_item_name]
|
102
|
+
# Update the url if it's already been created
|
103
|
+
add_to[config.menu_item_name].url = config.route_collection_path
|
104
|
+
else
|
105
|
+
add_to.add(config.menu_item_name, config.route_collection_path)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module ActiveAdmin
|
2
|
+
module Pages
|
3
|
+
|
4
|
+
autoload :Base, 'active_admin/pages/base'
|
5
|
+
autoload :Index, 'active_admin/pages/index'
|
6
|
+
autoload :New, 'active_admin/pages/new'
|
7
|
+
autoload :Show, 'active_admin/pages/show'
|
8
|
+
autoload :Edit, 'active_admin/pages/edit'
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module ActiveAdmin
|
2
|
+
module Pages
|
3
|
+
class Base < ::ActiveAdmin::Renderer
|
4
|
+
|
5
|
+
def breadcrumb(separator = "/")
|
6
|
+
content_tag :span, :class => "breadcrumb" do
|
7
|
+
@breadcrumbs.map { |txt, path| link_to_unless((path.blank? || current_page?(path)), h(txt), path) }.join(" #{content_tag(:span, separator, :class => "breadcrumb_sep")} ")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def main_content
|
12
|
+
"Please implement #{self.class.name}#main_content to display content.".html_safe
|
13
|
+
end
|
14
|
+
|
15
|
+
def title_bar
|
16
|
+
content_for :title_bar do
|
17
|
+
[breadcrumb, title_tag, action_items].join.html_safe
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def title_tag
|
22
|
+
content_tag :h2, title, :id => 'page_title'
|
23
|
+
end
|
24
|
+
|
25
|
+
def title
|
26
|
+
self.class.name
|
27
|
+
end
|
28
|
+
|
29
|
+
# Set's the page title for the layout to render
|
30
|
+
def set_page_title
|
31
|
+
set_ivar_on_view "@page_title", title
|
32
|
+
end
|
33
|
+
|
34
|
+
def action_items_renderer
|
35
|
+
ActiveAdmin::ActionItems::Renderer
|
36
|
+
end
|
37
|
+
|
38
|
+
def action_items
|
39
|
+
items = controller.class.action_items_for(params[:action])
|
40
|
+
action_items_renderer.new(self).to_html(items)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns the renderer class to use to render the sidebar
|
44
|
+
#
|
45
|
+
# You could override this method and return your own custom
|
46
|
+
# sidebar renderer
|
47
|
+
def sidebar_renderer
|
48
|
+
ActiveAdmin::Sidebar::Renderer
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns the sidebar sections to render for the current action
|
52
|
+
def sidebar_sections
|
53
|
+
controller.class.sidebar_sections_for(params[:action])
|
54
|
+
end
|
55
|
+
|
56
|
+
# Renders the sidebar
|
57
|
+
def sidebar
|
58
|
+
content_for :sidebar do
|
59
|
+
sidebar_renderer.new(self).to_html(sidebar_sections)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Renders the content for the footer
|
64
|
+
def footer
|
65
|
+
content_for :footer do
|
66
|
+
content_tag :p, "Powered by #{link_to("Active Admin", "http://www.activeadmin.info")} #{ActiveAdmin::VERSION}".html_safe
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def flash_messages
|
71
|
+
content_for :flash_messages do
|
72
|
+
if flash.keys.any?
|
73
|
+
content_tag :div, :class => 'flashes' do
|
74
|
+
flash.collect do |type, message|
|
75
|
+
content_tag :div, message, :class => "flash flash_#{type}"
|
76
|
+
end.join
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def to_html
|
83
|
+
set_page_title
|
84
|
+
title_bar
|
85
|
+
flash_messages
|
86
|
+
footer
|
87
|
+
sidebar
|
88
|
+
main_content
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|