├── lib
├── activeadmin.rb
├── active_admin
│ ├── comments
│ │ ├── views
│ │ │ └── active_admin_comment.rb
│ │ ├── views.rb
│ │ ├── namespace_helper.rb
│ │ ├── resource_helper.rb
│ │ ├── configuration.rb
│ │ ├── comment.rb
│ │ └── show_page_helper.rb
│ ├── stylesheets
│ │ └── active_admin
│ │ │ └── mixins
│ │ │ └── _utilities.scss
│ ├── version.rb
│ ├── engine.rb
│ ├── arbre
│ │ ├── core_extensions.rb
│ │ ├── context.rb
│ │ ├── attributes.rb
│ │ ├── class_list.rb
│ │ ├── collection.rb
│ │ ├── text_node.rb
│ │ ├── document.rb
│ │ └── html5_elements.rb
│ ├── sass
│ │ ├── active_admin.scss
│ │ └── css_loader.rb
│ ├── views.rb
│ ├── view_helpers
│ │ ├── title_helper.rb
│ │ ├── assigns_with_indifferent_access_helper.rb
│ │ ├── view_factory_helper.rb
│ │ ├── icon_helper.rb
│ │ ├── sidebar_helper.rb
│ │ ├── active_admin_application_helper.rb
│ │ ├── form_helper.rb
│ │ ├── method_or_proc_helper.rb
│ │ ├── renderer_helper.rb
│ │ ├── breadcrumb_helper.rb
│ │ ├── display_helper.rb
│ │ └── auto_link_helper.rb
│ ├── controller_action.rb
│ ├── page_config.rb
│ ├── views
│ │ ├── action_items.rb
│ │ ├── dashboard_section_renderer.rb
│ │ ├── components
│ │ │ ├── panel.rb
│ │ │ ├── sidebar_section.rb
│ │ │ ├── blank_slate.rb
│ │ │ ├── columns.rb
│ │ │ ├── attributes_table.rb
│ │ │ ├── status_tag.rb
│ │ │ └── scopes.rb
│ │ ├── index_as_block.rb
│ │ ├── pages
│ │ │ ├── new.rb
│ │ │ ├── edit.rb
│ │ │ ├── show.rb
│ │ │ └── dashboard.rb
│ │ ├── index_as_grid.rb
│ │ ├── header_renderer.rb
│ │ ├── tabs_renderer.rb
│ │ └── index_as_blog.rb
│ ├── scope.rb
│ ├── component.rb
│ ├── resource_controller
│ │ ├── action_builder.rb
│ │ ├── menu.rb
│ │ ├── form.rb
│ │ ├── sidebars.rb
│ │ ├── callbacks.rb
│ │ ├── scoping.rb
│ │ ├── page_configurations.rb
│ │ └── filters.rb
│ ├── asset_registration.rb
│ ├── event.rb
│ ├── view_helpers.rb
│ ├── dashboards
│ │ ├── section.rb
│ │ └── dashboard_controller.rb
│ ├── arbre.rb
│ ├── reloader.rb
│ ├── menu.rb
│ ├── resource
│ │ ├── belongs_to.rb
│ │ ├── scopes.rb
│ │ ├── naming.rb
│ │ └── menu.rb
│ ├── action_items.rb
│ ├── view_factory.rb
│ ├── locales
│ │ ├── da.yml
│ │ ├── es.yml
│ │ ├── pt.yml
│ │ └── en.yml
│ ├── helpers
│ │ ├── optional_display.rb
│ │ └── settings.rb
│ ├── sidebar.rb
│ ├── devise.rb
│ ├── csv_builder.rb
│ ├── iconic.rb
│ ├── dashboards.rb
│ └── menu_item.rb
└── generators
│ └── active_admin
│ ├── assets
│ ├── templates
│ │ ├── 3.1
│ │ │ ├── active_admin.js
│ │ │ └── active_admin.css.scss
│ │ └── dashboards.rb
│ └── assets_generator.rb
│ ├── resource
│ ├── templates
│ │ └── admin.rb
│ └── resource_generator.rb
│ ├── install
│ ├── templates
│ │ ├── migrations
│ │ │ ├── 1_create_admin_notes.rb
│ │ │ └── 2_move_admin_notes_to_comments.rb
│ │ └── dashboards.rb
│ └── install_generator.rb
│ └── devise
│ └── devise_generator.rb
├── .travis.yml
├── app
├── views
│ ├── active_admin
│ │ ├── resource
│ │ │ ├── edit.html.arb
│ │ │ ├── index.html.arb
│ │ │ ├── new.html.arb
│ │ │ ├── show.html.arb
│ │ │ └── index.csv.erb
│ │ ├── dashboard
│ │ │ └── index.html.arb
│ │ └── devise
│ │ │ ├── mailer
│ │ │ ├── unlock_instructions.html.erb
│ │ │ └── reset_password_instructions.html.erb
│ │ │ ├── unlocks
│ │ │ └── new.html.erb
│ │ │ ├── passwords
│ │ │ ├── new.html.erb
│ │ │ └── edit.html.erb
│ │ │ ├── sessions
│ │ │ └── new.html.erb
│ │ │ └── shared
│ │ │ └── _links.erb
│ └── layouts
│ │ └── active_admin_logged_out.html.erb
└── assets
│ ├── stylesheets
│ └── active_admin
│ │ ├── _mixins.css.scss
│ │ ├── mixins
│ │ ├── _all.css.scss
│ │ ├── _variables.css.scss
│ │ ├── _icons.css.scss
│ │ ├── _shadows.css.scss
│ │ ├── _sections.css.scss
│ │ ├── _gradients.css.scss
│ │ ├── _buttons.css.scss
│ │ └── _rounded.css.scss
│ │ ├── _flash_messages.css.scss
│ │ └── _comments.css.scss
│ ├── images
│ └── active_admin
│ │ ├── loading.gif
│ │ ├── orderable.png
│ │ ├── admin_notes_icon.png
│ │ ├── nested_menu_arrow.gif
│ │ ├── nested_menu_arrow_dark.gif
│ │ └── datepicker
│ │ ├── datepicker-nipple.png
│ │ ├── datepicker-header-bg.png
│ │ ├── datepicker-input-icon.png
│ │ ├── datepicker-next-link-icon.png
│ │ └── datepicker-prev-link-icon.png
│ └── javascripts
│ └── active_admin
│ └── base.js
├── .document
├── features
├── step_definitions
│ ├── flash_steps.rb
│ ├── tab_steps.rb
│ ├── menu_steps.rb
│ ├── asset_steps.rb
│ ├── action_item_steps.rb
│ ├── comment_steps.rb
│ ├── pagination_steps.rb
│ ├── sidebar_steps.rb
│ ├── dashboard_steps.rb
│ ├── attribute_steps.rb
│ ├── user_steps.rb
│ ├── index_scope_steps.rb
│ ├── factory_steps.rb
│ ├── configuration_steps.rb
│ └── format_steps.rb
├── users
│ ├── logging_out.feature
│ └── logging_in.feature
├── index
│ ├── formats.feature
│ ├── index_as_block.feature
│ ├── pagination.feature
│ ├── index_as_grid.feature
│ ├── format_as_csv.feature
│ ├── index_as_blog.feature
│ ├── index_blank_slate.feature
│ └── index_scopes.feature
├── first_boot.feature
├── menu.feature
├── dashboard.feature
├── comments
│ └── viewing_index.feature
├── show
│ ├── page_title.feature
│ └── default_content.feature
├── global_navigation.feature
├── registering_resources.feature
├── registering_assets.feature
├── support
│ ├── selectors.rb
│ └── paths.rb
├── sti_resource.feature
└── specifying_actions.feature
├── cucumber.yml
├── .gitignore
├── spec
├── support
│ ├── detect_rails_version.rb
│ ├── integration_example_group.rb
│ ├── templates
│ │ └── cucumber.rb
│ ├── rails_template_with_data.rb
│ └── rails_template.rb
├── unit
│ ├── component_spec.rb
│ ├── generators
│ │ └── install_rails_3_1_spec.rb
│ ├── arbre
│ │ └── html
│ │ │ ├── context_spec.rb
│ │ │ ├── element_finder_methods_spec.rb
│ │ │ ├── tag_attributes_spec.rb
│ │ │ └── tag_spec.rb
│ ├── view_factory_spec.rb
│ ├── helpers
│ │ └── settings_spec.rb
│ ├── dashboard_controller_spec.rb
│ ├── reloader_spec.rb
│ ├── display_name_spec.rb
│ ├── action_items_spec.rb
│ ├── resource
│ │ ├── scopes_spec.rb
│ │ └── naming_spec.rb
│ ├── components
│ │ ├── panel_spec.rb
│ │ ├── blank_slate_spec.rb
│ │ ├── sidebar_section_spec.rb
│ │ └── columns_spec.rb
│ ├── controller_filters_spec.rb
│ ├── resource_controller
│ │ └── collection_spec.rb
│ ├── scope_spec.rb
│ ├── pretty_format_spec.rb
│ ├── auto_link_spec.rb
│ ├── asset_registration_spec.rb
│ ├── rails_spec.rb
│ ├── belongs_to_spec.rb
│ ├── event_spec.rb
│ ├── dashboard_section_spec.rb
│ ├── menu_spec.rb
│ ├── dashboards_spec.rb
│ ├── comments_spec.rb
│ └── csv_builder_spec.rb
└── integration
│ ├── stylesheets_spec.rb
│ └── belongs_to_spec.rb
├── script
├── use_rails
└── local
├── Gemfile
├── activeadmin.gemspec
├── LICENSE
└── CHANGELOG.rdoc
/lib/activeadmin.rb:
--------------------------------------------------------------------------------
1 | require 'active_admin'
2 |
--------------------------------------------------------------------------------
/lib/active_admin/comments/views/active_admin_comment.rb:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lib/active_admin/stylesheets/active_admin/mixins/_utilities.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | script: bundle exec rake
2 | rvm:
3 | - ree
4 | - 1.9.2
5 |
--------------------------------------------------------------------------------
/app/views/active_admin/resource/edit.html.arb:
--------------------------------------------------------------------------------
1 | render renderer_for(:edit)
2 |
--------------------------------------------------------------------------------
/app/views/active_admin/resource/index.html.arb:
--------------------------------------------------------------------------------
1 | render renderer_for(:index)
2 |
--------------------------------------------------------------------------------
/app/views/active_admin/resource/new.html.arb:
--------------------------------------------------------------------------------
1 | render renderer_for(:new)
2 |
--------------------------------------------------------------------------------
/app/views/active_admin/resource/show.html.arb:
--------------------------------------------------------------------------------
1 | render renderer_for(:show)
2 |
--------------------------------------------------------------------------------
/lib/active_admin/version.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | VERSION = '0.2.2'
3 | end
4 |
--------------------------------------------------------------------------------
/app/views/active_admin/dashboard/index.html.arb:
--------------------------------------------------------------------------------
1 | render view_factory.dashboard_page
2 |
--------------------------------------------------------------------------------
/.document:
--------------------------------------------------------------------------------
1 | README.rdoc
2 | lib/**/*.rb
3 | bin/*
4 | features/**/*.feature
5 | LICENSE
6 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/active_admin/_mixins.css.scss:
--------------------------------------------------------------------------------
1 | @import "active_admin/mixins/all";
2 |
--------------------------------------------------------------------------------
/lib/generators/active_admin/assets/templates/3.1/active_admin.js:
--------------------------------------------------------------------------------
1 | //= require active_admin/base
2 |
--------------------------------------------------------------------------------
/lib/active_admin/engine.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | class Engine < Rails::Engine
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/lib/active_admin/arbre/core_extensions.rb:
--------------------------------------------------------------------------------
1 | class Object
2 | def to_html
3 | to_s
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/lib/generators/active_admin/resource/templates/admin.rb:
--------------------------------------------------------------------------------
1 | ActiveAdmin.register <%= class_name.singularize %> do
2 |
3 | end
4 |
--------------------------------------------------------------------------------
/app/assets/images/active_admin/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fcoury/active_admin/master/app/assets/images/active_admin/loading.gif
--------------------------------------------------------------------------------
/app/assets/images/active_admin/orderable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fcoury/active_admin/master/app/assets/images/active_admin/orderable.png
--------------------------------------------------------------------------------
/features/step_definitions/flash_steps.rb:
--------------------------------------------------------------------------------
1 | Then /^I should see a flash with "([^"]*)"$/ do |text|
2 | Then %{I should see "#{text}"}
3 | end
4 |
--------------------------------------------------------------------------------
/lib/active_admin/sass/active_admin.scss:
--------------------------------------------------------------------------------
1 | // This file is included when using Rails 3.0
2 | @import "active_admin/mixins";
3 | @import "active_admin/base";
4 |
--------------------------------------------------------------------------------
/app/assets/images/active_admin/admin_notes_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fcoury/active_admin/master/app/assets/images/active_admin/admin_notes_icon.png
--------------------------------------------------------------------------------
/app/assets/images/active_admin/nested_menu_arrow.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fcoury/active_admin/master/app/assets/images/active_admin/nested_menu_arrow.gif
--------------------------------------------------------------------------------
/app/assets/images/active_admin/nested_menu_arrow_dark.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fcoury/active_admin/master/app/assets/images/active_admin/nested_menu_arrow_dark.gif
--------------------------------------------------------------------------------
/features/step_definitions/tab_steps.rb:
--------------------------------------------------------------------------------
1 | Then /^the "([^"]*)" tab should be selected$/ do |name|
2 | Then %{I should see "#{name}" within "ul#tabs li.current"}
3 | end
4 |
--------------------------------------------------------------------------------
/app/assets/images/active_admin/datepicker/datepicker-nipple.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fcoury/active_admin/master/app/assets/images/active_admin/datepicker/datepicker-nipple.png
--------------------------------------------------------------------------------
/app/assets/images/active_admin/datepicker/datepicker-header-bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fcoury/active_admin/master/app/assets/images/active_admin/datepicker/datepicker-header-bg.png
--------------------------------------------------------------------------------
/app/assets/images/active_admin/datepicker/datepicker-input-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fcoury/active_admin/master/app/assets/images/active_admin/datepicker/datepicker-input-icon.png
--------------------------------------------------------------------------------
/lib/active_admin/comments/views.rb:
--------------------------------------------------------------------------------
1 | require 'active_admin/views'
2 | require 'active_admin/comments/views/active_admin_comments'
3 | require 'active_admin/comments/views/active_admin_comment'
4 |
--------------------------------------------------------------------------------
/app/assets/images/active_admin/datepicker/datepicker-next-link-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fcoury/active_admin/master/app/assets/images/active_admin/datepicker/datepicker-next-link-icon.png
--------------------------------------------------------------------------------
/app/assets/images/active_admin/datepicker/datepicker-prev-link-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fcoury/active_admin/master/app/assets/images/active_admin/datepicker/datepicker-prev-link-icon.png
--------------------------------------------------------------------------------
/lib/active_admin/views.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Views
3 |
4 | # Loads all the classes in views/*.rb
5 | Dir[File.expand_path('../views', __FILE__) + "/**/*.rb"].sort.each{ |f| require f }
6 |
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/lib/active_admin/view_helpers/title_helper.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module ViewHelpers
3 | module TitleHelper
4 |
5 | def title(_title)
6 | @page_title = _title
7 | end
8 |
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/lib/active_admin/view_helpers/assigns_with_indifferent_access_helper.rb:
--------------------------------------------------------------------------------
1 | module AssignsWithIndifferentAccessHelper
2 |
3 | def assigns
4 | @assigns_with_indifferent_access_helper ||= HashWithIndifferentAccess.new(super)
5 | end
6 |
7 | end
8 |
--------------------------------------------------------------------------------
/lib/generators/active_admin/assets/templates/3.1/active_admin.css.scss:
--------------------------------------------------------------------------------
1 | // Active Admin CSS Styles
2 | @import "active_admin/mixins";
3 | @import "active_admin/base";
4 |
5 | // To customize the Active Admin interfaces, add your
6 | // styles here:
7 |
--------------------------------------------------------------------------------
/cucumber.yml:
--------------------------------------------------------------------------------
1 | default: --format 'progress' --require features/support/env.rb --require features/step_definitions features
2 | wip: --format 'progress' --require features/support/env.rb --require features/step_definitions features --tags @wip:3 --wip features
--------------------------------------------------------------------------------
/lib/active_admin/view_helpers/view_factory_helper.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module ViewHelpers
3 | module ViewFactoryHelper
4 |
5 | def view_factory
6 | active_admin_application.view_factory
7 | end
8 |
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/features/step_definitions/menu_steps.rb:
--------------------------------------------------------------------------------
1 | Then /^I should see a menu item for "([^"]*)"$/ do |name|
2 | page.should have_css('#tabs li a', :text => name)
3 | end
4 |
5 | Then /^I should not see a menu item for "([^"]*)"$/ do |name|
6 | page.should_not have_css('#tabs li a', :text => name)
7 | end
8 |
--------------------------------------------------------------------------------
/lib/active_admin/view_helpers/icon_helper.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module ViewHelpers
3 | module IconHelper
4 |
5 | # Render an icon from the Iconic icon set
6 | def icon(*args)
7 | ActiveAdmin::Iconic.icon(*args)
8 | end
9 |
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/lib/active_admin/controller_action.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | class ControllerAction
3 | attr_reader :name
4 | def initialize(name, options = {})
5 | @name, @options = name, options
6 | end
7 |
8 | def http_verb
9 | @options[:method] ||= :get
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/lib/active_admin/page_config.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | class PageConfig
3 |
4 | attr_reader :block
5 |
6 | def initialize(options = {}, &block)
7 | @options, @block = options, block
8 | end
9 |
10 | def [](key)
11 | @options[key]
12 | end
13 |
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/features/step_definitions/asset_steps.rb:
--------------------------------------------------------------------------------
1 | Then /^I should see the css file "([^"]*)"$/ do |path|
2 | page.should have_xpath("//link[contains(@href, /stylesheets/#{path})]")
3 | end
4 |
5 | Then /^I should see the js file "([^"]*)"$/ do |path|
6 | page.should have_xpath("//script[contains(@src, /javascripts/#{path})]")
7 | end
8 |
--------------------------------------------------------------------------------
/lib/active_admin/view_helpers/sidebar_helper.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module ViewHelpers
3 | module SidebarHelper
4 |
5 | def skip_sidebar!
6 | @skip_sidebar = true
7 | end
8 |
9 | def skip_sidebar?
10 | @skip_sidebar == true
11 | end
12 |
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/features/step_definitions/action_item_steps.rb:
--------------------------------------------------------------------------------
1 | Then /^I should see an action item button "([^"]*)"$/ do |content|
2 | page.should have_css(".action_items a", :text => content)
3 | end
4 |
5 | Then /^I should not see an action item button "([^"]*)"$/ do |content|
6 | page.should_not have_css(".action_items", :text => content)
7 | end
8 |
--------------------------------------------------------------------------------
/lib/active_admin/arbre/context.rb:
--------------------------------------------------------------------------------
1 | module Arbre
2 | class Context < Arbre::HTML::Element
3 | def indent_level
4 | # A context does not increment the indent_level
5 | super - 1
6 | end
7 |
8 | def length
9 | to_html.length
10 | end
11 | alias :bytesize :length
12 |
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/features/step_definitions/comment_steps.rb:
--------------------------------------------------------------------------------
1 | Then /^I should see a comment by "([^"]*)"$/ do |name|
2 | Then %{I should see "#{name}" within ".active_admin_comment_author"}
3 | end
4 |
5 | When /^I add a comment "([^"]*)"$/ do |comment|
6 | When %{I fill in "active_admin_comment_body" with "#{comment}"}
7 | And %{I press "Add Comment"}
8 | end
9 |
--------------------------------------------------------------------------------
/features/step_definitions/pagination_steps.rb:
--------------------------------------------------------------------------------
1 | Then /^I should not see pagination$/ do
2 | page.should_not have_css(".pagination")
3 | end
4 |
5 | Then /^I should see pagination with (\d+) pages$/ do |count|
6 | Then %{I should see "#{count}" within ".pagination a"}
7 | Then %{I should not see "#{count.to_i + 1}" within ".pagination a"}
8 | end
9 |
--------------------------------------------------------------------------------
/features/step_definitions/sidebar_steps.rb:
--------------------------------------------------------------------------------
1 | Then /^I should see a sidebar titled "([^"]*)"$/ do |title|
2 | page.should have_css(".sidebar_section h3", :text => title)
3 | end
4 |
5 | Then /^I should not see a sidebar titled "([^"]*)"$/ do |title|
6 | page.all(:css, "##{title.gsub(" ", '').underscore}_sidebar_section").count.should == 0
7 | end
8 |
--------------------------------------------------------------------------------
/lib/active_admin/view_helpers/active_admin_application_helper.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module ViewHelpers
3 | module ActiveAdminApplicationHelper
4 |
5 | # Returns the current Active Admin application instance
6 | def active_admin_application
7 | ActiveAdmin.application
8 | end
9 |
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/lib/active_admin/comments/namespace_helper.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Comments
3 |
4 | module NamespaceHelper
5 |
6 | # Returns true of the namespace allows comments
7 | def comments?
8 | application.allow_comments_in && application.allow_comments_in.include?(name)
9 | end
10 |
11 | end
12 |
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/lib/active_admin/view_helpers/form_helper.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module ViewHelpers
3 | module FormHelper
4 |
5 | def active_admin_form_for(resource, options = {}, &block)
6 | options[:builder] ||= ActiveAdmin::FormBuilder
7 | semantic_form_for resource, options, &block
8 | end
9 |
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/app/views/active_admin/devise/mailer/unlock_instructions.html.erb:
--------------------------------------------------------------------------------
1 |
Hello <%= @resource.email %>!
2 |
3 | Your account has been locked due to an excessive amount of unsuccessful sign in attempts.
4 |
5 | Click the link below to unlock your account:
6 |
7 | <%= link_to 'Unlock my account', unlock_url(@resource, :unlock_token => @resource.unlock_token) %>
8 |
--------------------------------------------------------------------------------
/lib/active_admin/comments/resource_helper.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Comments
3 |
4 | module ResourceHelper
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | attr_accessor :comments
9 | end
10 |
11 | def comments?
12 | namespace.comments? && comments != false
13 | end
14 | end
15 |
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/features/users/logging_out.feature:
--------------------------------------------------------------------------------
1 | Feature: User Logging out
2 |
3 | Logging out of the system as an admin user
4 |
5 | Scenario: Logging out successfully
6 | Given a configuration of:
7 | """
8 | ActiveAdmin.register Post
9 | """
10 | And I am logged in
11 | When I go to the dashboard
12 | And I follow "Logout"
13 | Then I should see "Login"
14 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/active_admin/mixins/_all.css.scss:
--------------------------------------------------------------------------------
1 | @import "active_admin/mixins/variables";
2 | @import "active_admin/mixins/reset";
3 | @import "active_admin/mixins/gradients";
4 | @import "active_admin/mixins/shadows";
5 | @import "active_admin/mixins/icons";
6 | @import "active_admin/mixins/rounded";
7 | @import "active_admin/mixins/buttons";
8 | @import "active_admin/mixins/sections";
9 |
--------------------------------------------------------------------------------
/lib/active_admin/views/action_items.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Views
3 |
4 | class ActionItems < ActiveAdmin::Component
5 |
6 | def build(action_items)
7 | action_items.each do |action_item|
8 | span :class => "action_item" do
9 | instance_eval(&action_item.block)
10 | end
11 | end
12 | end
13 |
14 | end
15 |
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/active_admin/_flash_messages.css.scss:
--------------------------------------------------------------------------------
1 | .flash {
2 | @include primary-gradient;
3 | @include shadow;
4 | @include text-shadow(#222);
5 | border: none;
6 | font-weight: bold;
7 | padding: 10px 10px 8px 10px;
8 | margin-bottom: 10px;
9 | color: #fff;
10 |
11 | &.flash_notice { @include gradient(#87a28b, #657b6a); }
12 | &.flash_error { @include gradient(#ca5b4f, #97443c); }
13 | }
14 |
--------------------------------------------------------------------------------
/features/index/formats.feature:
--------------------------------------------------------------------------------
1 | Feature: Index Formats
2 |
3 | Scenario: View index with default formats
4 | Given an index configuration of:
5 | """
6 | ActiveAdmin.register Post
7 | """
8 | And 1 post exists
9 | When I am on the index page for posts
10 | Then I should see a link to download "CSV"
11 | And I should see a link to download "XML"
12 | And I should see a link to download "JSON"
13 |
--------------------------------------------------------------------------------
/lib/active_admin/arbre/attributes.rb:
--------------------------------------------------------------------------------
1 | module Arbre
2 | module HTML
3 |
4 | class Attributes < Hash
5 |
6 | def to_html
7 | self.collect do |name, value|
8 | "#{html_escape(name)}=\"#{html_escape(value)}\""
9 | end.join(" ")
10 | end
11 |
12 | protected
13 |
14 | def html_escape(s)
15 | ERB::Util.html_escape(s)
16 | end
17 | end
18 |
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## MAC OS
2 | .DS_Store
3 |
4 | ## TEXTMATE
5 | *.tmproj
6 | tmtags
7 |
8 | ## EMACS
9 | *~
10 | \#*
11 | .\#*
12 |
13 | ## VIM
14 | *.swp
15 |
16 | ## PROJECT::GENERAL
17 | tags
18 | coverage
19 | rdoc
20 | doc
21 | .yardoc
22 | pkg
23 |
24 | ## PROJECT::SPECIFIC
25 | .bundle
26 | spec/rails
27 | *.sqlite3-journal
28 | Gemfile.lock
29 | Gemfile-*.lock
30 | capybara*
31 | viewcumber
32 | test-rails*
33 | public
34 | .rvmrc
35 |
--------------------------------------------------------------------------------
/spec/support/detect_rails_version.rb:
--------------------------------------------------------------------------------
1 | # Detects the current version of Rails that is being used
2 | #
3 | # You can pass it in as an ENV variable or it will use
4 | # the current Gemfile.lock to find it
5 | def detect_rails_version
6 | return ENV['RAILS'] if ENV['RAILS']
7 | return nil unless (File.exists?("Gemfile.lock") || File.symlink?("Gemfile.lock"))
8 |
9 | File.read("Gemfile.lock").match(/^\W*rails \(([a-z\d.]*)\)/)
10 | return $1
11 | end
12 |
--------------------------------------------------------------------------------
/app/views/active_admin/devise/unlocks/new.html.erb:
--------------------------------------------------------------------------------
1 | Resend unlock instructions
2 |
3 | <%= form_for(resource, :as => resource_name, :url => unlock_path(resource_name), :html => { :method => :post }) do |f| %>
4 | <%= devise_error_messages! %>
5 |
6 | <%= f.label :email %>
7 | <%= f.text_field :email %>
8 |
9 | <%= f.submit "Resend unlock instructions" %>
10 | <% end %>
11 |
12 | <%= render :partial => "devise/shared/links" %>
--------------------------------------------------------------------------------
/lib/active_admin/scope.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | class Scope
3 |
4 | attr_reader :name, :scope_method, :id, :scope_block
5 |
6 | def initialize(name, method = nil, &block)
7 | @name = name.to_s.titleize
8 | @scope_method = method || name.to_sym
9 | @id = @name.gsub(' ', '').underscore
10 | if block_given?
11 | @scope_method = nil
12 | @scope_block = block
13 | end
14 | end
15 |
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/lib/active_admin/comments/configuration.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Comments
3 |
4 | module Configuration
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | # Set the namespaces that can create and view comments
9 | #
10 | # config.allow_comments_in = [:admin, :root]
11 | #
12 | attr_accessor_with_default :allow_comments_in, [:admin]
13 | end
14 |
15 | end
16 |
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/lib/active_admin/views/dashboard_section_renderer.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Views
3 | class DashboardSection < ActiveAdmin::Views::Panel
4 |
5 | def build(section)
6 | @section = section
7 | super(title, :icon => @section.icon)
8 | instance_eval &@section.block
9 | end
10 |
11 | protected
12 |
13 | def title
14 | @section.name.to_s.titleize
15 | end
16 |
17 | end
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/features/step_definitions/dashboard_steps.rb:
--------------------------------------------------------------------------------
1 | Then /^I should see the default welcome message$/ do
2 | Then %{I should see "Welcome to Active Admin" within "#dashboard_default_message"}
3 | end
4 |
5 | Then /^I should not see the default welcome message$/ do
6 | Then %{I should not see "Welcome to Active Admin"}
7 | end
8 |
9 | Then /^I should see a dashboard widget "([^"]*)"$/ do |name|
10 | Then %{I should see "#{name}" within ".dashboard .panel h3"}
11 | end
12 |
--------------------------------------------------------------------------------
/app/views/active_admin/devise/passwords/new.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
Forgot your password?
3 |
4 | <%= active_admin_form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post }) do |f|
5 | f.inputs do
6 | f.input :email
7 | end
8 | f.buttons do
9 | f.commit_button "Reset My Password"
10 | end
11 | end %>
12 |
13 | <%= render :partial => "devise/shared/links" %>
14 |
15 |
--------------------------------------------------------------------------------
/lib/active_admin/component.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | class Component < Arbre::HTML::Div
3 |
4 | # By default components render a div
5 | def tag_name
6 | 'div'
7 | end
8 |
9 | def initialize(*)
10 | super
11 | add_class default_class_name
12 | end
13 |
14 | protected
15 |
16 | # By default, add a css class named after the ruby class
17 | def default_class_name
18 | self.class.name.demodulize.underscore
19 | end
20 |
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/app/views/active_admin/devise/mailer/reset_password_instructions.html.erb:
--------------------------------------------------------------------------------
1 | Hello <%= @resource.email %>!
2 |
3 | Someone has requested a link to change your password, and you can do this through the link below.
4 |
5 | <%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @resource.reset_password_token) %>
6 |
7 | If you didn't request this, please ignore this email.
8 | Your password won't change until you access the link above and create a new one.
9 |
--------------------------------------------------------------------------------
/spec/unit/component_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | class MockComponentClass < ActiveAdmin::Component; end
4 |
5 | describe ActiveAdmin::Component do
6 |
7 | let(:component_class){ MockComponentClass }
8 | let(:component){ component_class.new }
9 |
10 | it "should be a subclass of an html div" do
11 | ActiveAdmin::Component.ancestors.should include(Arbre::HTML::Div)
12 | end
13 |
14 | it "should render to a div, even as a subclass" do
15 | component.tag_name.should == 'div'
16 | end
17 |
18 | end
19 |
--------------------------------------------------------------------------------
/lib/active_admin/arbre/class_list.rb:
--------------------------------------------------------------------------------
1 | require 'set'
2 |
3 | module Arbre
4 | module HTML
5 |
6 | # Holds a set of classes
7 | class ClassList < Set
8 |
9 | def add(class_names)
10 | class_names.to_s.split(" ").each do |class_name|
11 | super(class_name)
12 | end
13 | self
14 | end
15 | alias :<< :add
16 |
17 | def to_s
18 | to_html
19 | end
20 |
21 | def to_html
22 | to_a.join(" ")
23 | end
24 |
25 | end
26 |
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/lib/active_admin/resource_controller/action_builder.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | class ResourceController < ::InheritedResources::Base
3 |
4 | module ActionBuilder
5 | extend ActiveSupport::Concern
6 |
7 | module ClassMethods
8 |
9 | def clear_member_actions!
10 | active_admin_config.clear_member_actions!
11 | end
12 |
13 | def clear_collection_actions!
14 | active_admin_config.clear_collection_actions!
15 | end
16 | end
17 |
18 | end
19 |
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/lib/generators/active_admin/resource/resource_generator.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Generators
3 | class ResourceGenerator < Rails::Generators::NamedBase
4 | desc "Installs ActiveAdmin in a rails 3 application"
5 |
6 | def self.source_root
7 | @_active_admin_source_root ||= File.expand_path("../templates", __FILE__)
8 | end
9 |
10 | def generate_config_file
11 | template "admin.rb", "app/admin/#{file_path.gsub('/', '_').pluralize}.rb"
12 | end
13 |
14 | end
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/spec/unit/generators/install_rails_3_1_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 |
4 | if Rails.version[0..2] == '3.1'
5 | describe "Installing in Rails 3.1" do
6 |
7 | it "should add active_admin.css to app/assets/stylesheets/" do
8 | File.exists?(Rails.root + "app/assets/stylesheets/active_admin.css.scss").should be_true
9 | end
10 |
11 | it "should add active_admin.js to app/assets/javascripts" do
12 | File.exists?(Rails.root + "app/assets/javascripts/active_admin.js").should be_true
13 | end
14 |
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/active_admin/mixins/_variables.css.scss:
--------------------------------------------------------------------------------
1 | // Variables used throughout Active Admin
2 | $horizontal-page-margin: 30px;
3 | $primary-color: #5E6469;
4 | $secondary-color: #f0f0f0;
5 | $text-color: #323537;
6 | $link-color: #38678b;
7 | $section-header-text-color: $primary-color;
8 | $cell-padding: 5px 10px 3px 10px;
9 | $cell-horizontal-padding: 12px;
10 | $current-menu-item-background: lighten($primary-color, 12%);
11 | $hover-menu-item-background: lighten($primary-color, 12%);
12 | $table-stripe-color: lighten($primary-color, 57%);
13 |
--------------------------------------------------------------------------------
/spec/unit/arbre/html/context_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Arbre::Context do
4 | include Arbre::HTML
5 | let(:assigns){ {} }
6 |
7 | before do
8 | h1 # Add some HTML to the context
9 | end
10 |
11 | it "should return a bytesize" do
12 | current_dom_context.bytesize.should == 10
13 | end
14 |
15 | it "should return a length" do
16 | current_dom_context.length.should == 10
17 | end
18 |
19 | it "should not increment the indent_level" do
20 | current_dom_context.indent_level.should == -1
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/features/index/index_as_block.feature:
--------------------------------------------------------------------------------
1 | Feature: Index as Block
2 |
3 | Viewing the resource as a block which is renderered by the user
4 |
5 | Scenario: Viewing the index as a block
6 | Given a post with the title "Hello World from Block" exists
7 | And an index configuration of:
8 | """
9 | ActiveAdmin.register Post do
10 | index :as => :block do |post|
11 | span(link_to(post.title, admin_post_path(post)))
12 | end
13 | end
14 | """
15 | Then I should see "Hello World from Block" within ".index_as_block"
16 |
--------------------------------------------------------------------------------
/lib/active_admin/arbre/collection.rb:
--------------------------------------------------------------------------------
1 | module Arbre
2 | module HTML
3 |
4 | # Stores a collection of Element objects
5 | class Collection < Array
6 |
7 | def +(other)
8 | self.class.new(super)
9 | end
10 |
11 | def -(other)
12 | self.class.new(super)
13 | end
14 |
15 | def &(other)
16 | self.class.new(super)
17 | end
18 |
19 | def to_html
20 | self.collect do |element|
21 | element.to_html
22 | end.join.html_safe
23 | end
24 | end
25 |
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/lib/active_admin/sass/css_loader.rb:
--------------------------------------------------------------------------------
1 | require 'sass/importers'
2 |
3 | # This monkey patches the SASS filesystem importer to work with files
4 | # that are named *.css.scss. This allows us to be compatible with both
5 | # Rails 3.0.* and Rails 3.1
6 | #
7 | # This should only be loaded in Rails 3.0 apps.
8 | class Sass::Importers::Filesystem
9 |
10 | # We want to ensure that all *.css.scss files are loaded as scss files
11 | def extensions_with_css
12 | extensions_without_css.merge('css.scss' => :scss)
13 | end
14 | alias_method_chain :extensions, :css
15 |
16 | end
17 |
--------------------------------------------------------------------------------
/features/first_boot.feature:
--------------------------------------------------------------------------------
1 | Feature: First Boot
2 |
3 | As a developer
4 | In order to ensure I have a great first experience
5 | I want Active Admin to just work on install
6 |
7 | Scenario: Visiting /admin and logging in with no configurations
8 | Given a configuration of:
9 | """
10 | """
11 | And an admin user "admin@example.com" exists
12 | When I go to the dashboard
13 | When I fill in "Email" with "admin@example.com"
14 | And I fill in "Password" with "password"
15 | And I press "Login"
16 | Then I should be on the the dashboard
17 |
--------------------------------------------------------------------------------
/lib/generators/active_admin/install/templates/migrations/1_create_admin_notes.rb:
--------------------------------------------------------------------------------
1 | class CreateAdminNotes < ActiveRecord::Migration
2 | def self.up
3 | create_table :admin_notes do |t|
4 | t.references :resource, :polymorphic => true, :null => false
5 | t.references :admin_user, :polymorphic => true
6 | t.text :body
7 | t.timestamps
8 | end
9 | add_index :admin_notes, [:resource_type, :resource_id]
10 | add_index :admin_notes, [:admin_user_type, :admin_user_id]
11 | end
12 |
13 | def self.down
14 | drop_table :admin_notes
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/active_admin/mixins/_icons.css.scss:
--------------------------------------------------------------------------------
1 | span.icon { vertical-align: middle; display: inline-block; }
2 | span.icon svg { vertical-align: baseline; }
3 |
4 | @mixin icon-color ($color) {
5 | span.icon svg {
6 | path, polygon, rect, circle { fill: $color !important; }
7 | }
8 | }
9 |
10 | @mixin icon-size ($size) {
11 | span.icon { width: $size; height: $size; }
12 | span.icon svg { width: $size; height: $size; }
13 | }
14 |
15 | @mixin icon($color, $size) {
16 | @include icon-color($color);
17 | @include icon-size($size);
18 | }
19 |
20 | @include icon-size(0.8em);
21 |
--------------------------------------------------------------------------------
/app/views/active_admin/resource/index.csv.erb:
--------------------------------------------------------------------------------
1 | <%-
2 | csv_lib = if RUBY_VERSION =~ /^1.8/
3 | require 'fastercsv'
4 | FasterCSV
5 | else
6 | require 'csv'
7 | CSV
8 | end
9 |
10 | csv_output = csv_lib.generate do |csv|
11 | columns = active_admin_config.csv_builder.columns
12 | csv << columns.map(&:name)
13 | collection.each do |resource|
14 | csv << columns.map do |column|
15 | call_method_or_proc_on resource, column.data
16 | end
17 | end
18 | end
19 | %>
20 | <%= csv_output.html_safe %>
21 |
--------------------------------------------------------------------------------
/features/index/pagination.feature:
--------------------------------------------------------------------------------
1 | Feature: Index Pagination
2 |
3 | Background:
4 | Given an index configuration of:
5 | """
6 | ActiveAdmin.register Post
7 | """
8 | Scenario: Viewing index when one page of resources exist
9 | Given 20 posts exist
10 | When I am on the index page for posts
11 | Then I should see "Displaying all 20 Posts"
12 | And I should not see pagination
13 |
14 | Scenario: Viewing index when multiple pages of resources exist
15 | Given 31 posts exist
16 | When I am on the index page for posts
17 | Then I should see pagination with 2 pages
18 |
--------------------------------------------------------------------------------
/app/views/active_admin/devise/passwords/edit.html.erb:
--------------------------------------------------------------------------------
1 | Change your password
2 |
3 | <%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put }) do |f| %>
4 | <%= devise_error_messages! %>
5 | <%= f.hidden_field :reset_password_token %>
6 |
7 | <%= f.label :password %>
8 | <%= f.password_field :password %>
9 |
10 | <%= f.label :password_confirmation %>
11 | <%= f.password_field :password_confirmation %>
12 |
13 | <%= f.submit "Change my password" %>
14 | <% end %>
15 |
16 | <%= render :partial => "devise/shared/links" %>
--------------------------------------------------------------------------------
/lib/active_admin/asset_registration.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module AssetRegistration
3 |
4 | # Stylesheets
5 |
6 | def register_stylesheet(name)
7 | stylesheets << name
8 | end
9 |
10 | def stylesheets
11 | @stylesheets ||= []
12 | end
13 |
14 | def clear_stylesheets!
15 | @stylesheets = []
16 | end
17 |
18 |
19 | # Javascripts
20 |
21 | def register_javascript(name)
22 | javascripts << name
23 | end
24 |
25 | def javascripts
26 | @javascripts ||= []
27 | end
28 |
29 | def clear_javascripts!
30 | @javascripts = []
31 | end
32 |
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/lib/active_admin/comments/comment.rb:
--------------------------------------------------------------------------------
1 | require 'kaminari/models/active_record_extension'
2 |
3 | module ActiveAdmin
4 |
5 | # manually initialize kaminari for this model
6 | ::ActiveRecord::Base.send :include, Kaminari::ActiveRecordExtension
7 |
8 | class Comment < ActiveRecord::Base
9 | self.table_name = "active_admin_comments"
10 |
11 | belongs_to :resource, :polymorphic => true
12 | belongs_to :author, :polymorphic => true
13 |
14 | validates_presence_of :resource_id
15 | validates_presence_of :resource_type
16 | validates_presence_of :body
17 | validates_presence_of :namespace
18 | end
19 |
20 | end
21 |
22 |
--------------------------------------------------------------------------------
/features/step_definitions/attribute_steps.rb:
--------------------------------------------------------------------------------
1 | Then /^I should see the attribute "([^"]*)" with "([^"]*)"$/ do |title, value|
2 | page.should have_css('.attributes_table th', :text => title)
3 | page.should have_css('.attributes_table td', :text => value)
4 | end
5 |
6 | Then /^I should see the attribute "([^"]*)" with a nicely formatted datetime$/ do |title|
7 | th = page.find('.attributes_table th', :text => title)
8 | page.find(:xpath, th.path.gsub(/th$/, 'td')).text.should =~ /\w+ \d{1,2}, \d{4} \d{2}:\d{2}/
9 | end
10 |
11 | Then /^I should not see the attribute "([^"]*)"$/ do |title|
12 | page.should_not have_css('.attributes_table th', :text => title)
13 | end
14 |
--------------------------------------------------------------------------------
/lib/active_admin/event.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 |
3 | class EventDispatcher
4 | def initialize
5 | @events = {}
6 | end
7 |
8 | def clear_all_subscribers!
9 | @events = {}
10 | end
11 |
12 | def subscribe(event, &block)
13 | @events[event] ||= []
14 | @events[event] << block
15 | end
16 |
17 | def subscribers(event)
18 | @events[event] || []
19 | end
20 |
21 | def dispatch(event, *args)
22 | subscribers(event).each do |subscriber|
23 | subscriber.call(*args)
24 | end
25 | end
26 | end
27 |
28 | # ActiveAdmin::Event is set to a dispatcher
29 | Event = EventDispatcher.new
30 |
31 | end
32 |
--------------------------------------------------------------------------------
/spec/unit/view_factory_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | def it_should_have_view(key, value)
4 | it "should have #{value} for view key '#{key}'" do
5 | subject.send(key).should == value
6 | end
7 | end
8 |
9 | describe ActiveAdmin::ViewFactory do
10 |
11 | it_should_have_view :global_navigation, ActiveAdmin::Views::TabsRenderer
12 | it_should_have_view :action_items, ActiveAdmin::Views::ActionItems
13 | it_should_have_view :header, ActiveAdmin::Views::HeaderRenderer
14 | it_should_have_view :blank_slate, ActiveAdmin::Views::BlankSlate
15 |
16 | it_should_have_view :dashboard_page, ActiveAdmin::Views::Pages::Dashboard
17 |
18 | end
19 |
--------------------------------------------------------------------------------
/lib/active_admin/views/components/panel.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Views
3 |
4 | class Panel < ActiveAdmin::Component
5 | builder_method :panel
6 |
7 | def build(title, attributes = {})
8 | icon_name = attributes.delete(:icon)
9 | icn = icon_name ? icon(icon_name) : ""
10 | super(attributes)
11 | add_class "panel"
12 | @title = h3(icn + title.to_s)
13 | @contents = div(:class => "panel_contents")
14 | end
15 |
16 | def add_child(child)
17 | if @contents
18 | @contents << child
19 | else
20 | super
21 | end
22 | end
23 | end
24 |
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/lib/active_admin/view_helpers.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module ViewHelpers
3 |
4 | # Require all ruby files in the view helpers dir
5 | Dir[File.expand_path('../view_helpers', __FILE__) + "/*.rb"].each{|f| require f }
6 |
7 | include AssignsWithIndifferentAccessHelper
8 | include ActiveAdminApplicationHelper
9 | include RendererHelper
10 | include AutoLinkHelper
11 | include BreadcrumbHelper
12 | include DisplayHelper
13 | include IconHelper
14 | include MethodOrProcHelper
15 | include SidebarHelper
16 | include FormHelper
17 | include FilterFormHelper
18 | include TitleHelper
19 | include ViewFactoryHelper
20 |
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/features/menu.feature:
--------------------------------------------------------------------------------
1 | Feature: Menu
2 |
3 | Background:
4 | Given I am logged in
5 |
6 | Scenario: Hide the menu item
7 | Given a configuration of:
8 | """
9 | ActiveAdmin.register Post do
10 | menu false
11 | end
12 | """
13 | When I am on the dashboard
14 | Then I should not see a menu item for "Posts"
15 |
16 | @wip
17 | Scenario: Set the menu item label
18 | Given a configuration of:
19 | """
20 | ActiveAdmin.register Post do
21 | menu :label => "Articles"
22 | end
23 | """
24 | When I am on the dashboard
25 | Then I should see a menu item for "Articles"
26 | And I should not see a menu item for "Posts"
27 |
--------------------------------------------------------------------------------
/lib/active_admin/views/index_as_block.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Views
3 |
4 | # Simplest rendering possible. Calls the block for each element in the collection.
5 | #
6 | # Example:
7 | #
8 | # ActiveAdmin.register Post do
9 | # index :as => :block do |post|
10 | # # render the post partial (app/views/admin/posts/_post)
11 | # render 'post', :post => post
12 | # end
13 | # end
14 | class IndexAsBlock < ActiveAdmin::Component
15 |
16 | def build(page_config, collection)
17 | collection.each do |obj|
18 | instance_exec(obj, &page_config.block)
19 | end
20 | end
21 |
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/active_admin/mixins/_shadows.css.scss:
--------------------------------------------------------------------------------
1 | @mixin shadow($x: 0, $y: 1px, $blur: 2px, $color: #aaa) {
2 | box-shadow: $x $y $blur $color;
3 | -moz-box-shadow: $x $y $blur $color;
4 | -webkit-box-shadow: $x $y $blur $color;
5 | }
6 |
7 | @mixin no-shadow {
8 | box-shadow: none;
9 | -moz-box-shadow: none;
10 | -webkit-box-shadow: none;
11 | }
12 |
13 | @mixin inset-shadow($x: 0, $y: 1px, $blur: 2px, $color: #aaa) {
14 | box-shadow: inset $x $y $blur $color;
15 | -moz-box-shadow: inset $x $y $blur $color;
16 | -webkit-box-shadow: inset $x $y $blur $color;
17 | }
18 |
19 | @mixin text-shadow($color: #fff, $x: 0, $y: 1px, $blur: 0) {
20 | text-shadow: $color $x $y $blur;
21 | }
22 |
--------------------------------------------------------------------------------
/lib/active_admin/arbre/text_node.rb:
--------------------------------------------------------------------------------
1 | require 'erb'
2 |
3 | module Arbre
4 | module HTML
5 |
6 | class TextNode < Element
7 |
8 | builder_method :text_node
9 |
10 | # Builds a text node from a string
11 | def self.from_string(string)
12 | node = new
13 | node.build(string)
14 | node
15 | end
16 |
17 | def add_child(*args)
18 | raise "TextNodes do not have children"
19 | end
20 |
21 | def build(string)
22 | @content = string
23 | end
24 |
25 | def tag_name
26 | nil
27 | end
28 |
29 | def to_html
30 | ERB::Util.html_escape(@content.to_html)
31 | end
32 | end
33 |
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/features/step_definitions/user_steps.rb:
--------------------------------------------------------------------------------
1 | Given /^I am logged out$/ do
2 | visit destroy_admin_user_session_path
3 | end
4 |
5 | Given /^I am logged in$/ do
6 | Given 'an admin user "admin@example.com" exists'
7 | visit destroy_admin_user_session_path
8 | visit new_admin_user_session_path
9 | fill_in "Email", :with => "admin@example.com"
10 | fill_in "Password", :with => "password"
11 | click_button "Login"
12 | end
13 |
14 | Given /^an admin user "([^"]*)" exists$/ do |admin_email|
15 | unless AdminUser.find_by_email(admin_email)
16 | AdminUser.create! :email => admin_email,
17 | :password => "password",
18 | :password_confirmation => "password"
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/app/views/active_admin/devise/sessions/new.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
<%= title "#{active_admin_application.site_title} Login" %>
3 |
4 | <% scope = Devise::Mapping.find_scope!(resource_name) %>
5 | <%= active_admin_form_for(resource, :as => resource_name, :url => send(:"#{scope}_session_path"), :html => { :id => "session_new" }) do |f|
6 | f.inputs do
7 | Devise.authentication_keys.each { |key| f.input key }
8 | f.input :password
9 | f.input :remember_me, :as => :boolean, :if => false #devise_mapping.rememberable? }
10 | end
11 | f.buttons do
12 | f.commit_button "Login"
13 | end
14 | end
15 | %>
16 |
17 | <%= render :partial => "devise/shared/links" %>
18 |
19 |
--------------------------------------------------------------------------------
/spec/unit/helpers/settings_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 | require 'active_admin/helpers/settings'
3 |
4 | describe ActiveAdmin::Settings do
5 |
6 | # A Class with settings module included
7 | let(:klass) do
8 | Class.new do
9 | include ActiveAdmin::Settings
10 | def initialize
11 | initialize_defaults!
12 | end
13 | end
14 | end
15 |
16 | it "should add a new setting with a default" do
17 | klass.setting :my_setting, "Hello World"
18 | klass.default_settings[:my_setting].should == "Hello World"
19 | end
20 |
21 | it "should initialize the defaults" do
22 | klass.setting :my_setting, "Hello World"
23 | klass.new.my_setting.should == "Hello World"
24 | end
25 |
26 | end
27 |
--------------------------------------------------------------------------------
/lib/active_admin/views/pages/new.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Views
3 | module Pages
4 | class New < Base
5 |
6 | def title
7 | I18n.t('active_admin.new_model', :model => active_admin_config.resource_name)
8 | end
9 |
10 | def main_content
11 | config = self.form_config.dup
12 | config.delete(:block)
13 | config.reverse_merge!({
14 | :url => collection_path
15 | })
16 |
17 | if form_config[:partial]
18 | render(form_config[:partial])
19 | else
20 | active_admin_form_for(resource, config, &form_config[:block])
21 | end
22 | end
23 | end
24 | end
25 |
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/lib/active_admin/views/pages/edit.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Views
3 | module Pages
4 | class Edit < Base
5 |
6 | def title
7 | I18n.t('active_admin.edit_model', :model => active_admin_config.resource_name)
8 | end
9 |
10 | def main_content
11 | config = self.form_config.dup
12 | config.delete(:block)
13 | config.reverse_merge!({
14 | :url => resource_path(resource)
15 | })
16 |
17 | if form_config[:partial]
18 | render form_config[:partial]
19 | else
20 | active_admin_form_for resource, config, &form_config[:block]
21 | end
22 | end
23 |
24 | end
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/spec/unit/dashboard_controller_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 |
4 | module Admin
5 | class DashboardController < ActiveAdmin::Dashboards::DashboardController
6 | end
7 | end
8 | class DashboardController < ActiveAdmin::Dashboards::DashboardController; end
9 |
10 | describe ActiveAdmin::Dashboards::DashboardController do
11 |
12 | describe "getting the namespace name" do
13 | subject{ controller.send :namespace }
14 |
15 | context "when admin namespace" do
16 | let(:controller){ Admin::DashboardController.new }
17 | it { should == :admin }
18 | end
19 |
20 | context "when root namespace" do
21 | let(:controller){ DashboardController.new }
22 | it { should == :root }
23 | end
24 | end
25 |
26 | end
27 |
--------------------------------------------------------------------------------
/features/dashboard.feature:
--------------------------------------------------------------------------------
1 | Feature: Dashboard
2 |
3 | Background:
4 | Given I am logged in
5 |
6 |
7 | Scenario: With no configuration
8 | Given a configuration of:
9 | """
10 | """
11 | When I go to the dashboard
12 | Then I should see the default welcome message
13 |
14 | Scenario: Displaying a dashboard widget
15 | Given a configuration of:
16 | """
17 | ActiveAdmin::Dashboards.build do
18 | section 'Hello World' do
19 | para "Hello world from the content"
20 | end
21 | end
22 | """
23 | When I go to the dashboard
24 | Then I should not see the default welcome message
25 | And I should see a dashboard widget "Hello World"
26 | And I should see "Hello world from the content"
27 |
--------------------------------------------------------------------------------
/lib/active_admin/views/components/sidebar_section.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Views
3 |
4 | class SidebarSection < Panel
5 | builder_method :sidebar_section
6 |
7 | # Takes a ActiveAdmin::Sidebar::Section instance
8 | def build(section)
9 | @section = section
10 | super(@section.title, :icon => @section.icon)
11 | self.id = @section.id
12 | build_sidebar_content
13 | end
14 |
15 | protected
16 |
17 | def build_sidebar_content
18 | if @section.block
19 | rvalue = instance_eval(&@section.block)
20 | self << rvalue if rvalue.is_a?(String)
21 | else
22 | text_node render(@section.partial_name)
23 | end
24 | end
25 | end
26 |
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/lib/active_admin/comments/show_page_helper.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Comments
3 |
4 | # Adds #active_admin_comments to the show page for use
5 | # and sets it up on the default main content
6 | module ShowPageHelper
7 |
8 | # Add admin comments to the main content if they are
9 | # turned on for the current resource
10 | def default_main_content
11 | super
12 | active_admin_comments if active_admin_config.comments?
13 | end
14 |
15 | # Display the comments for the resource. Same as calling
16 | # #active_admin_comments_for with the current resource
17 | def active_admin_comments(*args, &block)
18 | active_admin_comments_for(resource, *args, &block)
19 | end
20 | end
21 |
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/spec/unit/reloader_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | # Ensure we have both constants to play with
4 | begin
5 | ActionDispatch::Reloader
6 | rescue
7 | module ActionDispatch; module Reloader; end; end
8 | end
9 |
10 | begin
11 | ActionDispatch::Callbacks
12 | rescue
13 | module ActionDispatch; module Callbacks; end; end
14 | end
15 |
16 |
17 | describe ActiveAdmin::Reloader do
18 |
19 | it "should use ActionDispatch::Reloader if rails 3.1" do
20 | reloader = ActiveAdmin::Reloader.new '3.1.0'
21 | reloader.reloader_class.should == ActionDispatch::Reloader
22 | end
23 |
24 | it "should use ActionDispatch::Callbacks if rails 3.0" do
25 | reloader = ActiveAdmin::Reloader.new '3.0.0'
26 | reloader.reloader_class.should == ActionDispatch::Callbacks
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/features/comments/viewing_index.feature:
--------------------------------------------------------------------------------
1 | Feature: Viewing Index of Comments
2 |
3 | Background:
4 | Given a post with the title "Hello World" written by "Jane Doe" exists
5 | Given a show configuration of:
6 | """
7 | ActiveAdmin.register Post
8 | """
9 |
10 | Scenario: Viewing all commments for a namespace
11 | When I add a comment "Hello from Comment"
12 | When I am on the index page for comments
13 | Then I should see a table header with "Body"
14 | And I should see a table header with "Resource"
15 | And I should see a table header with "Author"
16 | And I should see "Hello from Comment"
17 | And I should see a link to "Hello World"
18 | And I should see "admin@example.com"
19 | And I should not see an action item button "New Comment"
20 |
--------------------------------------------------------------------------------
/lib/active_admin/arbre/document.rb:
--------------------------------------------------------------------------------
1 | module Arbre
2 | module HTML
3 |
4 | class Document < Tag
5 |
6 | def build(*args)
7 | super
8 | build_head
9 | build_body
10 | end
11 |
12 | def document
13 | self
14 | end
15 |
16 | def tag_name
17 | 'html'
18 | end
19 |
20 | def doctype
21 | ''.html_safe
22 | end
23 |
24 | def to_html
25 | doctype + super
26 | end
27 |
28 | protected
29 |
30 | def build_head
31 | @head = head do
32 | meta :"http-equiv" => "Content-type", :content => "text/html; charset=utf-8"
33 | end
34 | end
35 |
36 | def build_body
37 | @body = body
38 | end
39 | end
40 |
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/spec/unit/display_name_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe "display names" do
4 |
5 | include ActiveAdmin::ViewHelpers
6 |
7 | [:display_name, :full_name, :name, :username, :login, :title, :email, :to_s].each do |m|
8 | it "should return #{m} if defined" do
9 | r = Class.new do
10 | define_method m do
11 | m.to_s
12 | end
13 | end.new
14 | display_name(r).should == m.to_s
15 | end
16 | end
17 |
18 | it "should memeoize the result for the class" do
19 | c = Class.new do
20 | def name
21 | "My Name"
22 | end
23 | end
24 | display_name(c.new).should == "My Name"
25 | ActiveAdmin.application.should_not_receive(:display_name_methods)
26 | display_name(c.new).should == "My Name"
27 | end
28 |
29 | end
30 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/active_admin/mixins/_sections.css.scss:
--------------------------------------------------------------------------------
1 | @mixin section-header {
2 | @include secondary-gradient;
3 | @include shadow;
4 | @include text-shadow;
5 | border-bottom: 1px solid #ededed;
6 | padding: 5px 10px 3px 10px;
7 | font-size: 1.0em;
8 | font-weight: bold;
9 | line-height: 140%;
10 | margin-bottom: 0.5em;
11 | color: $section-header-text-color;
12 | @include icon($section-header-text-color, 1.0em);
13 | span.icon { margin-right: 5px; }
14 | }
15 |
16 | @mixin section-background {
17 | background: #f4f4f4;
18 | @include rounded(4px);
19 | @include inset-shadow(0,1px,4px, #ddd);
20 | }
21 |
22 | @mixin section {
23 | @include section-background;
24 | h3 { @include section-header; }
25 | margin-bottom: 20px;
26 | > div { padding: 3px 15px 15px 15px; }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/generators/active_admin/assets/assets_generator.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Generators
3 | class AssetsGenerator < Rails::Generators::Base
4 |
5 | def self.source_root
6 | @_active_admin_source_root ||= File.expand_path("../templates", __FILE__)
7 | end
8 |
9 | def install_assets
10 | if ActiveAdmin.use_asset_pipeline?
11 | template '3.1/active_admin.js', 'app/assets/javascripts/active_admin.js'
12 | template '3.1/active_admin.css.scss', 'app/assets/stylesheets/active_admin.css.scss'
13 | else
14 | template '3.0/active_admin.js', 'public/javascripts/active_admin.js'
15 | directory '../../../../../app/assets/images/active_admin', 'public/images/active_admin'
16 | end
17 | end
18 |
19 | end
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/spec/support/integration_example_group.rb:
--------------------------------------------------------------------------------
1 | require 'action_dispatch'
2 | require 'capybara/rails'
3 | require 'capybara/dsl'
4 |
5 | module RSpec
6 | module Rails
7 | module IntegrationExampleGroup
8 | extend ActiveSupport::Concern
9 |
10 | include ActionDispatch::Integration::Runner
11 | include RSpec::Rails::TestUnitAssertionAdapter
12 | include ActionDispatch::Assertions
13 | include Capybara::DSL
14 | include RSpec::Matchers
15 |
16 | module InstanceMethods
17 | def app
18 | ::Rails.application
19 | end
20 |
21 | def last_response
22 | page
23 | end
24 | end
25 |
26 | included do
27 | before do
28 | @router = ::Rails.application.routes
29 | end
30 | end
31 | end
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/lib/active_admin/dashboards/section.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Dashboards
3 | class Section
4 |
5 | DEFAULT_PRIORITY = 10
6 |
7 | attr_accessor :name, :block
8 | attr_reader :namespace, :options
9 |
10 | def initialize(namespace, name, options = {}, &block)
11 | @namespace = namespace
12 | @name = name
13 | @options = options
14 | @block = block
15 | end
16 |
17 | def priority
18 | @options[:priority] || DEFAULT_PRIORITY
19 | end
20 |
21 | def icon
22 | @options[:icon]
23 | end
24 |
25 | # Sort by priority then by name
26 | def <=>(other)
27 | result = priority <=> other.priority
28 | result = name.to_s <=> other.name.to_s if result == 0
29 | result
30 | end
31 |
32 | end
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/spec/unit/action_items_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe ActiveAdmin::ActionItems do
4 |
5 | describe "rendering" do
6 | include Arbre::HTML
7 | let(:assigns){ {} }
8 | let(:action_item) do
9 | ActiveAdmin::ActionItems::ActionItem.new do
10 | h2 "Hello World"
11 | end
12 | end
13 |
14 | let(:rendered){ insert_tag ActiveAdmin::Views::ActionItems, [action_item]}
15 |
16 | it "should have a parent .action_items div" do
17 | rendered.tag_name.should == 'div'
18 | rendered.class_list.should include('action_items')
19 | end
20 |
21 | it "should render the contents of each action item" do
22 | rendered.children.size.should == 1
23 | rendered.content.strip.should == "\n Hello World
\n "
24 | end
25 | end
26 |
27 | end
28 |
--------------------------------------------------------------------------------
/features/step_definitions/index_scope_steps.rb:
--------------------------------------------------------------------------------
1 | Then /^I should see the scope "([^"]*)"$/ do |name|
2 | Then %{I should see "#{name}" within ".scopes"}
3 | end
4 |
5 | Then /^I should see the scope "([^"]*)" selected$/ do |name|
6 | Then %{I should see "#{name}" within ".scopes span.selected"}
7 | end
8 |
9 | Then /^I should see the scope "([^"]*)" not selected$/ do |name|
10 | Then %{I should see the scope "#{name}"}
11 | page.should_not have_css('.scopes span.selected', :text => name)
12 | end
13 |
14 | Then /^I should see the scope "([^"]*)" with the count (\d+)$/ do |name, count|
15 | Then %{I should see "#{count}" within ".scopes .#{name.downcase} .count"}
16 | end
17 |
18 | Then /^I should see (\d+) ([\w]*) in the table$/ do |count, resource_type|
19 | page.should have_css("table##{resource_type} tr > td:first", :count => count.to_i)
20 | end
21 |
--------------------------------------------------------------------------------
/lib/active_admin/arbre.rb:
--------------------------------------------------------------------------------
1 | require "active_admin/arbre/html"
2 | require "active_admin/arbre/attributes"
3 | require "active_admin/arbre/core_extensions"
4 | require "active_admin/arbre/element"
5 | require "active_admin/arbre/context"
6 | require "active_admin/arbre/collection"
7 | require "active_admin/arbre/class_list"
8 | require "active_admin/arbre/tag"
9 | require "active_admin/arbre/document"
10 | require "active_admin/arbre/html5_elements"
11 | require "active_admin/arbre/text_node"
12 |
13 | # Arbre - The DOM Tree in Ruby
14 | #
15 | # Arbre is a ruby library for building HTML in pure Object Oriented Ruby
16 | module Arbre
17 | end
18 |
19 | require 'action_view'
20 |
21 | ActionView::Template.register_template_handler :arb, lambda { |template|
22 | "self.class.send :include, Arbre::HTML; @_helpers = self; begin; #{template.source}; end; current_dom_context"
23 | }
24 |
--------------------------------------------------------------------------------
/spec/unit/resource/scopes_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | module ActiveAdmin
4 | describe Resource, "Scopes" do
5 |
6 | before { load_defaults! }
7 |
8 | let(:application){ ActiveAdmin::Application.new }
9 | let(:namespace){ Namespace.new(application, :admin) }
10 |
11 | def config(options = {})
12 | @config ||= Resource.new(namespace, Category, options)
13 | end
14 |
15 | describe "adding a scope" do
16 |
17 | it "should add a scope" do
18 | config.scope :published
19 | config.scopes.first.should be_a(ActiveAdmin::Scope)
20 | config.scopes.first.name.should == "Published"
21 | end
22 |
23 | it "should retrive a scope by its id" do
24 | config.scope :published
25 | config.get_scope_by_id(:published).name.should == "Published"
26 | end
27 |
28 | end
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/lib/active_admin/view_helpers/method_or_proc_helper.rb:
--------------------------------------------------------------------------------
1 | module MethodOrProcHelper
2 |
3 | # Many times throughout the views we want to either call a method on an object
4 | # or instance_exec a proc passing in the object as the first parameter. This
5 | # method takes care of this functionality.
6 | #
7 | # call_method_or_proc_on(@my_obj, :size) same as @my_obj.size
8 | # OR
9 | # proc = Proc.new{|s| s.size }
10 | # call_method_or_proc_on(@my_obj, proc)
11 | #
12 | def call_method_or_proc_on(obj, symbol_or_proc, options = {})
13 | exec = options[:exec].nil? ? true : options[:exec]
14 | case symbol_or_proc
15 | when Symbol, String
16 | obj.send(symbol_or_proc.to_sym)
17 | when Proc
18 | if exec
19 | instance_exec(obj, &symbol_or_proc)
20 | else
21 | symbol_or_proc.call(obj)
22 | end
23 | end
24 | end
25 |
26 | end
27 |
--------------------------------------------------------------------------------
/lib/active_admin/reloader.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | # Deals with reloading Active Admin on each request in
3 | # development and once in production.
4 | class Reloader
5 |
6 | # @param [String] rails_version
7 | # The version of Rails we're using. We use this to switch between
8 | # the correcr Rails reloader class.
9 | def initialize(rails_version)
10 | @rails_version = rails_version.to_s
11 | end
12 |
13 | # Attach to Rails and perform the reload on each request.
14 | def attach!
15 | reloader_class.to_prepare do
16 | ActiveAdmin.application.unload!
17 | Rails.application.reload_routes!
18 | end
19 | end
20 |
21 | def reloader_class
22 | if @rails_version[0..2] == '3.1'
23 | ActionDispatch::Reloader
24 | else
25 | ActionDispatch::Callbacks
26 | end
27 | end
28 |
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/active_admin/mixins/_gradients.css.scss:
--------------------------------------------------------------------------------
1 | $secondary-gradient-start: #efefef;
2 | $secondary-gradient-stop: #dfe1e2;
3 |
4 | @mixin gradient($start, $end){
5 | background: $start;
6 | background: -webkit-gradient(linear, left top, left bottom, from($start), to($end));
7 | background: -moz-linear-gradient(-90deg, $start, $end);
8 | // IE 6 & 7
9 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#{$start}, endColorstr=#{$end});
10 | // IE 8
11 | -ms-filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#{$start}, endColorstr=#{$end});
12 | }
13 |
14 | @mixin primary-gradient {
15 | @include gradient(lighten($primary-color, 5%), darken($primary-color, 7%));
16 | border-bottom: 1px solid darken($primary-color, 11%);
17 | }
18 |
19 | @mixin secondary-gradient {
20 | @include gradient($secondary-gradient-start, $secondary-gradient-stop);
21 | }
22 |
--------------------------------------------------------------------------------
/spec/unit/components/panel_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe ActiveAdmin::Views::Panel do
4 | include Arbre::HTML
5 | let(:assigns){ {} }
6 |
7 | let(:helpers) { action_view }
8 |
9 | let(:the_panel) do
10 | panel "My Title" do
11 | span("Hello World")
12 | end
13 | end
14 |
15 | it "should have a title h3" do
16 | the_panel.find_by_tag("h3").first.content.should == "My Title"
17 | end
18 |
19 | it "should have a contents div" do
20 | the_panel.find_by_tag("div").first.class_list.should include("panel_contents")
21 | end
22 |
23 | it "should add children to the contents div" do
24 | the_panel.find_by_tag("span").first.parent.should == the_panel.find_by_tag("div").first
25 | end
26 |
27 | it "should set the icon" do
28 | panel("Title", :icon => :arrow_down).find_by_tag("h3").first.content.should include("span class=\"icon")
29 | end
30 |
31 | end
32 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/active_admin/mixins/_buttons.css.scss:
--------------------------------------------------------------------------------
1 | @mixin default-button {
2 | @include shadow;
3 | @include gradient(lighten($primary-color, 15%), darken($primary-color, 12%));
4 | @include rounded(200px);
5 | @include text-shadow(#000);
6 | text-decoration: none;
7 | margin-right: 3px;
8 | font-weight: bold;
9 | font-size: 1.0em;
10 | cursor: pointer;
11 | padding: .6em 1.4em .5em 1.3em;
12 | border: none;
13 | color: #efefef;
14 | &:hover { color: #fff; @include icon-color(#fff); @include shadow(0, 1px, 3px, #888) }
15 | &:active { @include inset-shadow(0, 1px, 2px, #000); }
16 | }
17 |
18 | @mixin light-button {
19 | @include default-button;
20 | @include gradient(#f9f9f9, #dddbdb);
21 | @include text-shadow;
22 | color: #777;
23 | &:hover { color: #444; @include icon-color(#444) }
24 | &:active { @include inset-shadow; }
25 | }
26 |
27 | @mixin dark-button { @include default-button; }
28 |
--------------------------------------------------------------------------------
/lib/active_admin/resource_controller/menu.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | class ResourceController < ::InheritedResources::Base
3 | module Menu
4 | extend ActiveSupport::Concern
5 |
6 | included do
7 | before_filter :set_current_tab
8 | helper_method :current_menu
9 | end
10 |
11 | protected
12 |
13 | def current_menu
14 | active_admin_config.namespace.menu
15 | end
16 |
17 | # Set's @current_tab to be name of the tab to mark as current
18 | # Get's called through a before filter
19 | def set_current_tab
20 | @current_tab = if active_admin_config.belongs_to? && parent?
21 | active_admin_config.belongs_to_config.target.menu_item_name
22 | else
23 | [active_admin_config.parent_menu_item_name, active_admin_config.menu_item_name].compact.join("/")
24 | end
25 | end
26 |
27 | end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/lib/active_admin/view_helpers/renderer_helper.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module ViewHelpers
3 | module RendererHelper
4 |
5 | # Adds the ability to render ActiveAdmin::Renderers using the
6 | # standard render method.
7 | #
8 | # Example:
9 | #
10 | # render MyRendererClass, "Arg1", "Arg2"
11 | #
12 | # which is the same as doing
13 | #
14 | # MyRendererClass.new(self).to_html("Arg1", "Arg2")
15 | def render(*args)
16 | if args[0].is_a?(Class) && args[0].ancestors.include?(ActiveAdmin::Renderer)
17 | renderer = args.shift
18 | renderer.new(self).to_html(*args)
19 | elsif args[0].is_a?(Class) && args[0].ancestors.include?(Arbre::HTML::Tag)
20 | tag_class = args.shift
21 | insert_tag tag_class, *args
22 | else
23 | super
24 | end
25 | end
26 |
27 | end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/lib/active_admin/menu.rb:
--------------------------------------------------------------------------------
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
43 |
--------------------------------------------------------------------------------
/lib/active_admin/resource/belongs_to.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | class Resource
3 | class BelongsTo
4 |
5 | class TargetNotFound < StandardError; end
6 |
7 | # The resource which initiated this relationship
8 | attr_reader :owner
9 |
10 | def initialize(owner_resource, target_name, options = {})
11 | @owner, @target_name = owner_resource, target_name
12 | @options = options
13 | end
14 |
15 | # Returns the target resource class or raises an exception if it doesn't exist
16 | def target
17 | namespace.resources[@target_name.to_s.camelize] or
18 | raise TargetNotFound, "Could not find registered resource #{@target_name} in #{namespace.name} with #{namespace.resources.keys.inspect}"
19 | end
20 |
21 | def namespace
22 | @owner.namespace
23 | end
24 |
25 | def optional?
26 | @options[:optional]
27 | end
28 |
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/lib/active_admin/resource/scopes.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | class Resource
3 | module Scopes
4 |
5 | # Return an array of scopes for this resource
6 | def scopes
7 | @scopes ||= []
8 | end
9 |
10 | # Returns a scope for this object by its identifier
11 | def get_scope_by_id(id)
12 | id = id.to_s
13 | scopes.find{|s| s.id == id }
14 | end
15 |
16 | def default_scope
17 | @default_scope
18 | end
19 |
20 | # Create a new scope object for this resource.
21 | # If you want to internationalize the scope name, you can add
22 | # to your i18n files a key like "active_admin.scopes.scope_method".
23 | def scope(*args, &block)
24 | options = args.extract_options!
25 | self.scopes << ActiveAdmin::Scope.new(*args, &block)
26 | if options[:default]
27 | @default_scope = scopes.last
28 | end
29 | end
30 |
31 | end
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/lib/active_admin/resource_controller/form.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | class ResourceController < ::InheritedResources::Base
3 | module Form
4 | extend ActiveSupport::Concern
5 |
6 | included do
7 | helper_method :form_config
8 | end
9 |
10 | module ClassMethods
11 |
12 | def form_config=(config)
13 | @form_config = config
14 | end
15 |
16 | def form_config
17 | @form_config ||= default_form_config
18 | end
19 |
20 | def reset_form_config!
21 | @form_config = nil
22 | end
23 |
24 | def default_form_config
25 | config = {}
26 | config[:block] = lambda do |f|
27 | f.inputs
28 | f.buttons
29 | end
30 | config
31 | end
32 | end
33 |
34 | protected
35 |
36 | def form_config
37 | @form_config ||= self.class.form_config
38 | end
39 |
40 | end
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/spec/support/templates/cucumber.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('config/environments/test', Rails.root)
2 |
3 | # rails/railties/lib/rails/test_help.rb aborts if the environment is not 'test'. (Rails 3.0.0.beta3)
4 | # We can't run Cucumber/RSpec/Test_Unit tests in different environments then.
5 | #
6 | # For now, I patch StringInquirer so that Rails.env.test? returns true when Rails.env is 'test' or 'cucumber'
7 | #
8 | # https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/4458-rails-should-allow-test-to-run-in-cucumber-environment
9 | module ActiveSupport
10 | class StringInquirer < String
11 | def method_missing(method_name, *arguments)
12 | if method_name.to_s[-1,1] == "?"
13 | test_string = method_name.to_s[0..-2]
14 | if test_string == 'test'
15 | self == 'test' or self == 'cucumber'
16 | else
17 | self == test_string
18 | end
19 | else
20 | super
21 | end
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/spec/unit/components/blank_slate_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe ActiveAdmin::Views::BlankSlate do
4 | include Arbre::HTML
5 |
6 | let(:assigns){ {} }
7 |
8 | let(:helpers) { action_view }
9 |
10 | describe "#blank_slate" do
11 | subject { blank_slate("Posts", "/posts/new") }
12 |
13 | its(:tag_name) { should eql 'div' }
14 | its(:class_list) { should include('blank_slate_container') }
15 |
16 | describe "content" do
17 | subject { blank_slate("Posts", "/posts/new").content }
18 |
19 | context "when url passed in" do
20 | it { should include 'There are no Posts yet. Create one' }
21 | end
22 |
23 | context "when no url passed in" do
24 | subject { blank_slate("Posts").content }
25 |
26 | it { should include 'There are no Posts yet.' }
27 | end
28 | end
29 |
30 | end
31 | end
--------------------------------------------------------------------------------
/lib/active_admin/action_items.rb:
--------------------------------------------------------------------------------
1 | require 'active_admin/helpers/optional_display'
2 |
3 | module ActiveAdmin
4 | module ActionItems
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | self.class_inheritable_accessor :action_items
9 | self.action_items = []
10 | end
11 |
12 | module ClassMethods
13 | def action_item(options = {}, &block)
14 | self.action_items << ActiveAdmin::ActionItems::ActionItem.new(options, &block)
15 | end
16 |
17 | def clear_action_items!
18 | self.action_items = []
19 | end
20 |
21 | def action_items_for(action)
22 | action_items.select{|item| item.display_on?(action) }
23 | end
24 | end
25 |
26 | class ActionItem
27 | include ActiveAdmin::OptionalDisplay
28 |
29 | attr_accessor :block
30 |
31 | def initialize(options = {}, &block)
32 | @options, @block = options, block
33 | normalize_display_options!
34 | end
35 | end
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/lib/active_admin/resource_controller/sidebars.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | class ResourceController < ::InheritedResources::Base
3 |
4 | module Sidebars
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | self.class_inheritable_accessor :sidebar_sections
9 | self.sidebar_sections = []
10 | end
11 |
12 | module ClassMethods
13 | def sidebar(name, options = {}, &block)
14 | self.sidebar_sections << ActiveAdmin::Sidebar::Section.new(name, options, &block)
15 | end
16 |
17 | def clear_sidebar_sections!
18 | self.sidebar_sections = []
19 | end
20 |
21 | def sidebar_sections_for(action)
22 | sidebar_sections.select{|section| section.display_on?(action) }
23 | end
24 | end
25 |
26 | protected
27 |
28 | def skip_sidebar!
29 | @skip_sidebar = true
30 | end
31 |
32 | def skip_sidebar?
33 | @skip_sidebar == true
34 | end
35 | end
36 |
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/script/use_rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # Switches the development environment to use the given
4 | # version of rails. Caches the Gemfile.locks so that
5 | # switching it very fast.
6 |
7 | def cmd(command)
8 | puts command
9 | system command
10 | end
11 |
12 | version = ARGV[0]
13 |
14 | unless version
15 | puts "usage: ./script/#{__FILE__} VERSION"
16 | exit(1)
17 | end
18 |
19 | def file_or_symlink?(path)
20 | File.exist?(path) || File.symlink?(path)
21 | end
22 |
23 | gem_lock_dir = ".gemfile-locks"
24 | gem_lock_file = "#{gem_lock_dir}/Gemfile-#{version}.lock"
25 |
26 | # Ensure our lock dir is created
27 | cmd "mkdir #{gem_lock_dir}" unless File.exists?(gem_lock_dir)
28 |
29 | unless File.exists?(gem_lock_file)
30 | cmd "rm Gemfile.lock" if file_or_symlink?("Gemfile.lock")
31 | cmd "export RAILS=#{version} && bundle install"
32 | cmd "mv Gemfile.lock #{gem_lock_file}"
33 | end
34 |
35 | cmd("rm Gemfile.lock") if file_or_symlink?("Gemfile.lock")
36 | cmd("ln -s #{gem_lock_file} Gemfile.lock")
37 |
--------------------------------------------------------------------------------
/app/views/active_admin/devise/shared/_links.erb:
--------------------------------------------------------------------------------
1 | <%- if controller_name != 'sessions' %>
2 | <% scope = Devise::Mapping.find_scope!(resource_name) %>
3 | <%= link_to "Sign in", send(:"new_#{scope}_session_path") }")br />
4 | <% end -%>
5 |
6 | <%- if devise_mapping.registerable? && controller_name != 'registrations' %>
7 | <%= link_to "Sign up", new_registration_path(resource_name) %>
8 | <% end -%>
9 |
10 | <%- if devise_mapping.recoverable? && controller_name != 'passwords' %>
11 | <%= link_to "Forgot your password?", new_password_path(resource_name) %>
12 | <% end -%>
13 |
14 | <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
15 | <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
16 | <% end -%>
17 |
18 | <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
19 | <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
20 | <% end -%>
21 |
--------------------------------------------------------------------------------
/spec/unit/components/sidebar_section_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe ActiveAdmin::Views::SidebarSection do
4 | include Arbre::HTML
5 | let(:assigns){ {} }
6 |
7 | let(:section) do
8 | ActiveAdmin::Sidebar::Section.new(:help) do
9 | span "Help Me"
10 | end
11 | end
12 |
13 | let(:html) do
14 | sidebar_section(section)
15 | end
16 |
17 | it "should have a title h3" do
18 | html.find_by_tag("h3").first.content.should == "Help"
19 | end
20 |
21 | it "should have the class of 'sidebar_section'" do
22 | html.class_list.should include("sidebar_section")
23 | end
24 |
25 | it "should have an id based on the title" do
26 | html.id.should == "help_sidebar_section"
27 | end
28 |
29 | it "should have a contents div" do
30 | html.find_by_tag("div").first.class_list.should include("panel_contents")
31 | end
32 |
33 | it "should add children to the contents div" do
34 | html.find_by_tag("span").first.parent.should == html.find_by_tag("div").first
35 | end
36 |
37 | end
38 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/active_admin/_comments.css.scss:
--------------------------------------------------------------------------------
1 | // -------------------------------------- Admin Notes
2 | .comments {
3 |
4 | .active_admin_comment {
5 | clear: both;
6 | margin-top: 10px;
7 | margin-bottom: 40px;
8 | max-width: 700px;
9 |
10 | .active_admin_comment_meta {
11 | width: 130px;
12 | float: left;
13 | font-size: 0.9em;
14 | color: lighten($primary-color, 10%);
15 | .active_admin_comment_author {
16 | font-size: 1.2em;
17 | font-weight: bold;
18 | margin: 0;
19 | color: $primary-color;
20 | }
21 | }
22 | .active_admin_comment_body {
23 | margin-left: 150px;
24 | }
25 | }
26 | form.active_admin_comment {
27 | margin: 0;
28 | padding: 0;
29 | margin-left: 150px;
30 |
31 | fieldset.inputs {
32 | margin: 0;
33 | padding: 0;
34 | background: none;
35 | @include no-shadow;
36 | }
37 | li { padding: 0; }
38 | fieldset.buttons { padding: 0; margin-top: 5px;}
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/lib/active_admin/view_helpers/breadcrumb_helper.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module ViewHelpers
3 | module BreadcrumbHelper
4 |
5 | # Returns an array of links to use in a breadcrumb
6 | def breadcrumb_links(path = nil)
7 | path ||= request.fullpath
8 | parts = path.gsub(/^\//, '').split('/')
9 | parts.pop unless %w{ create update }.include?(params[:action])
10 | crumbs = []
11 | parts.each_with_index do |part, index|
12 | name = ""
13 | if part =~ /^\d/ && parent = parts[index - 1]
14 | begin
15 | parent_class = parent.singularize.camelcase.constantize
16 | obj = parent_class.find(part.to_i)
17 | name = obj.display_name if obj.respond_to?(:display_name)
18 | rescue
19 | end
20 | end
21 | name = part.titlecase if name == ""
22 | crumbs << link_to(name, "/" + parts[0..index].join('/'))
23 | end
24 | crumbs
25 | end
26 |
27 | end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/features/show/page_title.feature:
--------------------------------------------------------------------------------
1 | Feature: Show - Page Title
2 |
3 | Modifying the page title on the show screen
4 |
5 | Background:
6 | Given a post with the title "Hello World" written by "Jane Doe" exists
7 |
8 | Scenario: Set a method to be called on the resource as the title
9 | Given a show configuration of:
10 | """
11 | ActiveAdmin.register Post do
12 | show :title => :title
13 | end
14 | """
15 | Then I should see the page title "Hello World"
16 |
17 | Scenario: Set a string as the title
18 | Given a show configuration of:
19 | """
20 | ActiveAdmin.register Post do
21 | show :title => "Title From String"
22 | end
23 | """
24 | Then I should see the page title "Title From String"
25 |
26 | Scenario: Set a proc as the title
27 | Given a show configuration of:
28 | """
29 | ActiveAdmin.register Post do
30 | show :title => proc{|post| "Title: " + post.title }
31 | end
32 | """
33 | Then I should see the page title "Title: Hello World"
34 |
--------------------------------------------------------------------------------
/spec/unit/controller_filters_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe ActiveAdmin, "filters" do
4 | let(:application){ ActiveAdmin::Application.new }
5 |
6 | describe "before filters" do
7 | it "should add a new before filter to ActiveAdmin::ResourceController" do
8 | ActiveAdmin::ResourceController.should_receive(:before_filter).and_return(true)
9 | application.before_filter :my_filter, :only => :show
10 | end
11 | end
12 |
13 | describe "after filters" do
14 | it "should add a new after filter to ActiveAdmin::ResourceController" do
15 | ActiveAdmin::ResourceController.should_receive(:after_filter).and_return(true)
16 | application.after_filter :my_filter, :only => :show
17 | end
18 | end
19 |
20 | describe "around filters" do
21 | it "should add a new around filter to ActiveAdmin::ResourceController" do
22 | ActiveAdmin::ResourceController.should_receive(:around_filter).and_return(true)
23 | application.around_filter :my_filter, :only => :show
24 | end
25 | end
26 |
27 | end
28 |
--------------------------------------------------------------------------------
/spec/unit/resource_controller/collection_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe ActiveAdmin::ResourceController::Collection do
4 | let(:params) do
5 | {}
6 | end
7 |
8 | let(:controller) do
9 | rc = Admin::PostsController.new
10 | rc.stub!(:params) do
11 | params
12 | end
13 | rc
14 | end
15 |
16 | describe ActiveAdmin::ResourceController::Collection::Search do
17 | let(:params){ {:q => {} }}
18 | it "should call the metasearch method" do
19 | chain = mock("ChainObj")
20 | chain.should_receive(:metasearch).with(params[:q]).once.and_return(Post.search)
21 | controller.send :search, chain
22 | end
23 | end
24 |
25 | describe ActiveAdmin::ResourceController::Collection::Sorting do
26 | let(:params){ {:order => "id_asc" }}
27 | it "should prepend the table name" do
28 | chain = mock("ChainObj")
29 | chain.should_receive(:order).with("\"posts\".id asc").once.and_return(Post.search)
30 | controller.send :sort_order, chain
31 | end
32 | end
33 |
34 | end
35 |
--------------------------------------------------------------------------------
/app/views/layouts/active_admin_logged_out.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | <%= [@page_title, active_admin_application.site_title].join(" | ") %>
7 |
8 | <% ActiveAdmin.application.stylesheets.each do |path| %>
9 | <%= stylesheet_link_tag path %>
10 | <% end %>
11 | <% ActiveAdmin.application.javascripts.each do |path| %>
12 | <%= javascript_include_tag path %>
13 | <% end %>
14 |
15 | <%= csrf_meta_tag %>
16 |
17 |
18 |
19 |
20 |
21 | <% if flash.keys.any? %>
22 | <% flash.each do |type, message| %>
23 | <%= content_tag :div, message, :class => "flash flash_#{type}" %>
24 | <% end %>
25 | <% end %>
26 |
27 | <%= yield %>
28 |
29 |
30 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'http://rubygems.org'
2 |
3 | gemspec
4 |
5 | require File.expand_path('../spec/support/detect_rails_version', __FILE__)
6 |
7 | case detect_rails_version
8 | when /3.0.(\d)*/
9 | gem 'rails', "= 3.0.#{$1}"
10 | gem "meta_search", '~> 1.0.0'
11 | when /3.1.(.*)/
12 | gem 'rails', "= 3.1.#{$1}"
13 | gem "meta_search", '>= 1.1.0.pre'
14 | gem "uglifier"
15 | gem 'sass-rails', "~> 3.1.0.rc"
16 | gem 'coffee-script'
17 | gem 'execjs'
18 | gem 'therubyracer'
19 | end
20 |
21 | group :development, :test do
22 | gem 'sqlite3-ruby', :require => 'sqlite3'
23 | gem 'rake', '0.8.7', :require => false
24 | gem 'haml', '~> 3.1.1', :require => false
25 | end
26 |
27 | group :test do
28 | gem 'rspec', '~> 2.6.0'
29 | gem 'rspec-rails', '~> 2.6.0'
30 | gem 'capybara', '1.0.0'
31 | gem 'cucumber', '0.10.6'
32 | gem 'cucumber-rails', '0.5.2'
33 | gem 'database_cleaner'
34 | gem 'shoulda', '2.11.2', :require => nil
35 | gem 'launchy'
36 | end
37 |
--------------------------------------------------------------------------------
/lib/active_admin/view_factory.rb:
--------------------------------------------------------------------------------
1 | require 'active_admin/abstract_view_factory'
2 |
3 | module ActiveAdmin
4 | class ViewFactory < AbstractViewFactory
5 |
6 | # Register Helper Renderers
7 | register :global_navigation => ActiveAdmin::Views::TabsRenderer,
8 | :action_items => ActiveAdmin::Views::ActionItems,
9 | :header => ActiveAdmin::Views::HeaderRenderer,
10 | :dashboard_section => ActiveAdmin::Views::DashboardSection,
11 | :index_scopes => ActiveAdmin::Views::Scopes,
12 | :blank_slate => ActiveAdmin::Views::BlankSlate
13 |
14 | # Register All The Pages
15 | register :dashboard_page => ActiveAdmin::Views::Pages::Dashboard,
16 | :index_page => ActiveAdmin::Views::Pages::Index,
17 | :show_page => ActiveAdmin::Views::Pages::Show,
18 | :new_page => ActiveAdmin::Views::Pages::New,
19 | :edit_page => ActiveAdmin::Views::Pages::Edit
20 |
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/features/step_definitions/factory_steps.rb:
--------------------------------------------------------------------------------
1 | Given /^a post with the title "([^"]*)" exists$/ do |title|
2 | Post.create! :title => title
3 | end
4 |
5 | Given /^a post with the title "([^"]*)" and body "([^"]*)" exists$/ do |title, body|
6 | Post.create! :title => title, :body => body
7 | end
8 |
9 | Given /^a post with the title "([^"]*)" written by "([^"]*)" exists$/ do |title, author_name|
10 | first, last = author_name.split(' ')
11 | author = User.find_or_create_by_first_name_and_last_name(first, last, :username => author_name.gsub(' ', '').underscore)
12 | Post.create! :title => title, :author => author
13 | end
14 |
15 | Given /^(\d+) posts? exists?/ do |count|
16 | (0...count.to_i).each do |i|
17 | Post.create! :title => "Hello World #{i}"
18 | end
19 | end
20 |
21 | Given /^a category named "([^"]*)" exists$/ do |name|
22 | Category.create! :name => name
23 | end
24 |
25 | Given /^a user named "([^"]*)" exists$/ do |name|
26 | first, last = name.split(" ")
27 | User.create! :first_name => first, :last_name => last, :username => name
28 | end
29 |
--------------------------------------------------------------------------------
/lib/active_admin/locales/da.yml:
--------------------------------------------------------------------------------
1 | da:
2 | active_admin:
3 | dashboard_welcome:
4 | welcome: "Velkommen til Active Admin. Dette er standardoversigtssiden."
5 | call_to_action: "Rediger 'app/admin/dashboards.rb' for at tilføje nye elementer til oversigtssiden."
6 | view: "Vis"
7 | edit: "Rediger"
8 | delete: "Slet"
9 | delete_confirmation: "Er du sikker på at du ønsker at slette?"
10 | new_model: "Ny(t) %{model}"
11 | edit_model: "Rediger %{model}"
12 | delete_model: "Slet %{model}"
13 | details: "%{model} detaljer"
14 | cancel: "Fortryd"
15 | empty: "Tom"
16 | previous: "Forrige"
17 | next: "Næste"
18 | download: "Download:"
19 | has_many_new: "Tilføj ny(t) %{model}"
20 | has_many_delete: "Slet"
21 | filter: "Filtrer"
22 | clear_filters: "Ryd filtre"
23 | search_field: "Søg %{field}"
24 | equal_to: "lig"
25 | greater_than: "større end"
26 | less_than: "mindre end"
27 | main_content: "Implementer venligst %{model}#main_content for at vise noget indhold."
28 | logout: "Log ud"
29 |
--------------------------------------------------------------------------------
/features/global_navigation.feature:
--------------------------------------------------------------------------------
1 | Feature: Global Navigation
2 |
3 |
4 | Background:
5 | Given a configuration of:
6 | """
7 | ActiveAdmin.register Post
8 | """
9 | Given I am logged in
10 | And 10 posts exist
11 |
12 | Scenario: Viewing the current section in the global navigation
13 | Given I am on the index page for posts
14 | Then the "Posts" tab should be selected
15 |
16 | Scenario: Viewing the current section in the global navigation when on new page
17 | Given I am on the index page for posts
18 | And I follow "New Post"
19 | Then the "Posts" tab should be selected
20 |
21 | Scenario: Viewing the current section in the global navigation when on show page
22 | Given I am on the index page for posts
23 | And I follow "View"
24 | Then the "Posts" tab should be selected
25 |
26 | Scenario: Viewing the current section in the global navigation when on edit page
27 | Given I am on the index page for posts
28 | And I follow "View"
29 | And I follow "Edit Post"
30 | Then the "Posts" tab should be selected
31 |
--------------------------------------------------------------------------------
/features/registering_resources.feature:
--------------------------------------------------------------------------------
1 | Feature: Registering Resources
2 |
3 | Registering resources within Active Admin
4 |
5 | Background:
6 | Given I am logged in
7 | And a post with the title "Hello World" exists
8 |
9 | Scenario: Registering a resource with the defaults
10 | Given a configuration of:
11 | """
12 | ActiveAdmin.register Post
13 | """
14 | When I go to the dashboard
15 | Then I should see "Posts"
16 | When I follow "Posts"
17 | Then I should see "Hello World"
18 | When I follow "View"
19 | Then I should see "Hello World"
20 | And I should be in the resource section for Post
21 |
22 | Scenario: Registering a resource with another name
23 | Given a configuration of:
24 | """
25 | ActiveAdmin.register Post, :as => "My Post"
26 | """
27 | When I go to the dashboard
28 | Then I should see "My Posts"
29 | When I follow "My Posts"
30 | Then I should see "Hello World"
31 | When I follow "View"
32 | Then I should see "Hello World"
33 | And I should be in the resource section for My Post
34 |
--------------------------------------------------------------------------------
/lib/active_admin/views/components/blank_slate.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Views
3 | # Build a Blank Slate
4 | class BlankSlate < ActiveAdmin::Component
5 | builder_method :blank_slate
6 |
7 | def default_class_name
8 | 'blank_slate_container'
9 | end
10 |
11 | def build(name, url = nil)
12 | if url
13 | super(span(blank_slate_content_with_link(name, url), :class => "blank_slate"))
14 | else
15 | super(span(blank_slate_content_without_link(name), :class => "blank_slate"))
16 | end
17 | end
18 |
19 | private
20 |
21 | def blank_slate_content_with_link(name, url)
22 | I18n.t('active_admin.blank_slate.content', :resource_name => name).html_safe +
23 | " " +
24 | link_to(I18n.t('active_admin.blank_slate.link').html_safe, url)
25 | end
26 |
27 | def blank_slate_content_without_link(name)
28 | I18n.t('active_admin.blank_slate.content', :resource_name => name).html_safe
29 | end
30 |
31 | end
32 | end
33 | end
--------------------------------------------------------------------------------
/lib/active_admin/dashboards/dashboard_controller.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Dashboards
3 | class DashboardController < ResourceController
4 |
5 | before_filter :skip_sidebar!
6 |
7 | actions :index
8 |
9 | clear_action_items!
10 |
11 | def index
12 | @dashboard_sections = find_sections
13 | render 'active_admin/dashboard/index.html.arb'
14 | end
15 |
16 | protected
17 |
18 | def set_current_tab
19 | @current_tab = "Dashboard"
20 | end
21 |
22 | def find_sections
23 | ActiveAdmin::Dashboards.sections_for_namespace(namespace)
24 | end
25 |
26 | def namespace
27 | class_name = self.class.name
28 | if class_name.include?('::')
29 | self.class.name.split('::').first.underscore.to_sym
30 | else
31 | :root
32 | end
33 | end
34 |
35 | # Return the current menu for the view. This is a helper method
36 | def current_menu
37 | ActiveAdmin.application.namespaces[namespace].menu
38 | end
39 |
40 | end
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/features/step_definitions/configuration_steps.rb:
--------------------------------------------------------------------------------
1 | Given /^a configuration of:$/ do |configuration_content|
2 | eval configuration_content
3 | Rails.application.reload_routes!
4 | ActiveAdmin.application.namespaces.values.each{|n| n.load_menu! }
5 | end
6 |
7 | Given /^an index configuration of:$/ do |configuration_content|
8 | eval configuration_content
9 | Rails.application.reload_routes!
10 | ActiveAdmin.application.namespaces.values.each{|n| n.load_menu! }
11 |
12 | And 'I am logged in'
13 | When "I am on the index page for posts"
14 | end
15 |
16 | Given /^a show configuration of:$/ do |configuration_content|
17 | eval configuration_content
18 | Rails.application.reload_routes!
19 | ActiveAdmin.application.namespaces.values.each{|n| n.load_menu! }
20 |
21 | And 'I am logged in'
22 | When "I am on the index page for posts"
23 | And 'I follow "View"'
24 | end
25 |
26 | Given /^"([^"]*)" contains:$/ do |filename, contents|
27 | require 'fileutils'
28 | filepath = Rails.root + filename
29 | FileUtils.mkdir_p File.dirname(filepath)
30 | File.open(filepath, 'w+'){|f| f << contents }
31 | end
32 |
--------------------------------------------------------------------------------
/spec/unit/scope_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe ActiveAdmin::Scope do
4 |
5 | describe "creating a scope" do
6 | subject{ scope }
7 |
8 | context "when just a scope method" do
9 | let(:scope) { ActiveAdmin::Scope.new :published }
10 | its(:name) { should == "Published"}
11 | its(:id) { should == "published"}
12 | its(:scope_method) { should == :published }
13 | end
14 |
15 | context "when a name and scope method" do
16 | let(:scope) { ActiveAdmin::Scope.new "My Scope", :scope_method }
17 | its(:name) { should == "My Scope"}
18 | its(:id) { should == "my_scope"}
19 | its(:scope_method) { should == :scope_method }
20 | end
21 |
22 | context "when a name and scope block" do
23 | let(:scope) { ActiveAdmin::Scope.new("My Scope"){|s| s } }
24 | its(:name) { should == "My Scope"}
25 | its(:id) { should == "my_scope"}
26 | its(:scope_method) { should == nil }
27 | its(:scope_block) { should be_a(Proc)}
28 | end
29 | end
30 |
31 | end
32 |
--------------------------------------------------------------------------------
/lib/active_admin/helpers/optional_display.rb:
--------------------------------------------------------------------------------
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
35 |
--------------------------------------------------------------------------------
/features/registering_assets.feature:
--------------------------------------------------------------------------------
1 | Feature: Registering Assets
2 |
3 | Registering CSS and JS files
4 |
5 | Background:
6 | Given a configuration of:
7 | """
8 | ActiveAdmin.register Post
9 | """
10 | And I am logged in
11 |
12 |
13 | Scenario: Viewing default asset files
14 | When I am on the index page for posts
15 | Then I should see the css file "admin/active_admin.css"
16 | Then I should see the js file "active_admin_vendor.js"
17 | Then I should see the js file "active_admin.js"
18 |
19 | Scenario: Registering a CSS file
20 | Given a configuration of:
21 | """
22 | ActiveAdmin.application.register_stylesheet "some-random-css.css"
23 | ActiveAdmin.register Post
24 | """
25 | When I am on the index page for posts
26 | Then I should see the css file "some-random-css.css"
27 |
28 | Scenario: Registering a JS file
29 | Given a configuration of:
30 | """
31 | ActiveAdmin.application.register_javascript "some-random-js.js"
32 | ActiveAdmin.register Post
33 | """
34 | When I am on the index page for posts
35 | Then I should see the js file "some-random-js.js"
36 |
--------------------------------------------------------------------------------
/spec/support/rails_template_with_data.rb:
--------------------------------------------------------------------------------
1 | # Use the default
2 | apply File.expand_path("../rails_template.rb", __FILE__)
3 |
4 | # Register Active Admin controllers
5 | %w{ Post User Category }.each do |type|
6 | generate :'active_admin:resource', type
7 | end
8 |
9 | # Setup some default data
10 | append_file "db/seeds.rb", <<-EOF
11 | users = ["Jimi Hendrix", "Jimmy Page", "Yngwie Malmsteen", "Eric Clapton", "Kirk Hammett"].collect do |name|
12 | first, last = name.split(" ")
13 | User.create! :first_name => first,
14 | :last_name => last,
15 | :username => [first,last].join('-').downcase
16 | end
17 |
18 | categories = ["Rock", "Pop Rock", "Alt-Country", "Blues", "Dub-Step"].collect do |name|
19 | Category.create! :name => name
20 | end
21 |
22 | 1_000.times do |i|
23 | user = users[i % users.size]
24 | cat = categories[i % categories.size]
25 | Post.create :title => "Blog Post \#{i}",
26 | :body => "Blog post \#{i} is written by \#{user.username} about \#{cat.name}",
27 | :category => cat,
28 | :author => user
29 | end
30 | EOF
31 |
32 | rake 'db:seed'
33 |
--------------------------------------------------------------------------------
/lib/active_admin/helpers/settings.rb:
--------------------------------------------------------------------------------
1 | require 'active_support/concern'
2 |
3 | module ActiveAdmin
4 |
5 | # Adds a class method to a class to create settings with default values.
6 | #
7 | # Example:
8 | #
9 | # class Configuration
10 | # include ActiveAdmin::Settings
11 | #
12 | # setting :site_title, "Default Site Title"
13 | #
14 | # def initialize
15 | # # You must call this method to initialize the defaults
16 | # initialize_defaults!
17 | # end
18 | #
19 | module Settings
20 | extend ActiveSupport::Concern
21 |
22 | module InstanceMethods
23 |
24 | def default_settings
25 | self.class.default_settings
26 | end
27 |
28 | def initialize_defaults!
29 | default_settings.each do |key, value|
30 | send("#{key}=".to_sym, value)
31 | end
32 | end
33 |
34 | end
35 |
36 | module ClassMethods
37 |
38 | def setting(name, default)
39 | default_settings[name] = default
40 | attr_accessor(name)
41 | end
42 |
43 | def default_settings
44 | @default_settings ||= {}
45 | end
46 |
47 | end
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/lib/active_admin/sidebar.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Sidebar
3 |
4 | class Section
5 | include ActiveAdmin::OptionalDisplay
6 |
7 | attr_accessor :name, :options, :block
8 |
9 | def initialize(name, options = {}, &block)
10 | @name, @options, @block = name, options, block
11 | normalize_display_options!
12 | end
13 |
14 | # The id gets used for the div in the view
15 | def id
16 | name.to_s.downcase.underscore + '_sidebar_section'
17 | end
18 |
19 | def icon?
20 | options[:icon]
21 | end
22 |
23 | def icon
24 | options[:icon] if icon?
25 | end
26 |
27 | # The title gets displayed within the section in the view
28 | def title
29 | begin
30 | I18n.t!("active_admin.sidebars.#{name.to_s}")
31 | rescue I18n::MissingTranslationData
32 | name.to_s.titlecase
33 | end
34 | end
35 |
36 | # If a block is not passed in, the name of the partial to render
37 | def partial_name
38 | options[:partial] || "#{name.to_s.downcase.gsub(' ', '_')}_sidebar"
39 | end
40 | end
41 |
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/lib/active_admin/resource/naming.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | class Resource
3 | module Naming
4 |
5 | # An underscored safe representation internally for this resource
6 | def underscored_resource_name
7 | @underscored_resource_name ||= if @options[:as]
8 | @options[:as].gsub(' ', '').underscore.singularize
9 | else
10 | resource.name.gsub('::','').underscore
11 | end
12 | end
13 |
14 | # A camelized safe representation for this resource
15 | def camelized_resource_name
16 | underscored_resource_name.camelize
17 | end
18 |
19 | # Returns the name to call this resource.
20 | # By default will use resource.model_name.human
21 | def resource_name
22 | @resource_name ||= if @options[:as] || !resource.respond_to?(:model_name)
23 | underscored_resource_name.titleize
24 | else
25 | resource.model_name.human.titleize
26 | end
27 | end
28 |
29 | # Returns the plural version of this resource
30 | def plural_resource_name
31 | @plural_resource_name ||= resource_name.pluralize
32 | end
33 |
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/lib/active_admin/devise.rb:
--------------------------------------------------------------------------------
1 | require 'devise'
2 |
3 | module ActiveAdmin
4 | module Devise
5 |
6 | def self.config
7 | {
8 | :path => ActiveAdmin.application.default_namespace,
9 | :controllers => ActiveAdmin::Devise.controllers,
10 | :path_names => { :sign_in => 'login', :sign_out => "logout" }
11 | }
12 | end
13 |
14 | def self.controllers
15 | {
16 | :sessions => "active_admin/devise/sessions",
17 | :passwords => "active_admin/devise/passwords"
18 | }
19 | end
20 |
21 | module Controller
22 | extend ::ActiveSupport::Concern
23 | included do
24 | layout 'active_admin_logged_out'
25 | helper ::ActiveAdmin::ViewHelpers
26 | end
27 |
28 | # Redirect to the default namespace on logout
29 | def root_path
30 | "/#{ActiveAdmin.application.default_namespace}"
31 | end
32 | end
33 |
34 | class SessionsController < ::Devise::SessionsController
35 | include ::ActiveAdmin::Devise::Controller
36 | end
37 |
38 | class PasswordsController < ::Devise::PasswordsController
39 | include ::ActiveAdmin::Devise::Controller
40 | end
41 |
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/lib/active_admin/resource_controller/callbacks.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | class ResourceController < ::InheritedResources::Base
3 |
4 | module Callbacks
5 | extend ActiveSupport::Concern
6 | include ::ActiveAdmin::Callbacks
7 |
8 | included do
9 | define_active_admin_callbacks :build, :create, :update, :save, :destroy
10 | end
11 |
12 | protected
13 |
14 | def build_resource
15 | object = super
16 | run_build_callbacks object
17 | object
18 | end
19 |
20 | def create_resource(object)
21 | run_create_callbacks object do
22 | save_resource(object)
23 | end
24 | end
25 |
26 | def save_resource(object)
27 | run_save_callbacks object do
28 | object.save
29 | end
30 | end
31 |
32 | def update_resource(object, attributes)
33 | object.attributes = attributes
34 | run_update_callbacks object do
35 | save_resource(object)
36 | end
37 | end
38 |
39 | def destroy_resource(object)
40 | run_destroy_callbacks object do
41 | object.destroy
42 | end
43 | end
44 | end
45 |
46 | end
47 | end
48 |
--------------------------------------------------------------------------------
/lib/active_admin/views/index_as_grid.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Views
3 | class IndexAsGrid < ActiveAdmin::Component
4 |
5 | def build(page_config, collection)
6 | @page_config = page_config
7 | @collection = collection
8 | build_table
9 | end
10 |
11 | def number_of_columns
12 | @page_config[:columns] || default_number_of_columns
13 | end
14 |
15 | protected
16 |
17 | def build_table
18 | table :class => "index_grid" do
19 | collection.in_groups_of(number_of_columns).each do |group|
20 | build_row(group)
21 | end
22 | end
23 | end
24 |
25 | def build_row(group)
26 | tr do
27 | group.each do |item|
28 | item ? build_item(item) : build_empty_cell
29 | end
30 | end
31 | end
32 |
33 | def build_item(item)
34 | td :for => item do
35 | instance_exec(item, &@page_config.block)
36 | end
37 | end
38 |
39 | def build_empty_cell
40 | td ' '.html_safe
41 | end
42 |
43 | def default_number_of_columns
44 | 3
45 | end
46 |
47 | end
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/activeadmin.gemspec:
--------------------------------------------------------------------------------
1 | # -*- encoding: utf-8 -*-
2 | $:.push File.expand_path("../lib", __FILE__)
3 | require "active_admin/version"
4 |
5 | Gem::Specification.new do |s|
6 | s.name = %q{activeadmin}
7 | s.version = ActiveAdmin::VERSION
8 | s.platform = Gem::Platform::RUBY
9 | s.homepage = %q{http://activeadmin.info}
10 | s.authors = ["Greg Bell"]
11 | s.email = ["gregdbell@gmail.com"]
12 | s.description = %q{The administration framework for Ruby on Rails.}
13 | s.summary = %q{The administration framework for Ruby on Rails.}
14 |
15 | s.files = `git ls-files`.split("\n").sort
16 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18 | s.require_paths = ["lib"]
19 |
20 | s.add_dependency("rails", ">= 3.0.0")
21 | s.add_dependency("meta_search", ">= 0.9.2")
22 | s.add_dependency("devise", ">= 1.1.2")
23 | s.add_dependency("formtastic", ">= 1.1.0")
24 | s.add_dependency("inherited_resources", ">= 0")
25 | s.add_dependency("kaminari", ">= 0.12.4")
26 | s.add_dependency("sass", ">= 3.1.0")
27 | s.add_dependency("fastercsv", ">= 0")
28 | end
29 |
--------------------------------------------------------------------------------
/spec/unit/pretty_format_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe "#pretty_format" do
4 | include ActiveAdmin::ViewHelpers::DisplayHelper
5 |
6 | context "when a String is passed in" do
7 | it "should return the String passed in" do
8 | pretty_format("hello").should == "hello"
9 | end
10 | end
11 |
12 | context "when a Date or a Time is passed in" do
13 | it "should return a localized Date or Time with long format" do
14 | t = Time.now
15 | self.should_receive(:localize).with(t, {:format => :long}) { "Just Now!" }
16 | pretty_format(t).should == "Just Now!"
17 | end
18 | end
19 |
20 | context "when an ActiveRecord object is passed in" do
21 | it "should delegate to auto_link" do
22 | post = Post.new
23 | self.should_receive(:auto_link).with(post) { "model name" }
24 | pretty_format(post).should == "model name"
25 | end
26 | end
27 |
28 | context "when something else is passed in" do
29 | it "should delegate to display_name" do
30 | something = Class.new.new
31 | self.should_receive(:display_name).with(something) { "I'm not famous" }
32 | pretty_format(something).should == "I'm not famous"
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/features/users/logging_in.feature:
--------------------------------------------------------------------------------
1 | Feature: User Logging In
2 |
3 | Logging in to the system as an admin user
4 |
5 | Background:
6 | Given a configuration of:
7 | """
8 | ActiveAdmin.register Post
9 | """
10 | And I am logged out
11 | And an admin user "admin@example.com" exists
12 | When I go to the dashboard
13 |
14 | Scenario: Logging in Successfully
15 | When I fill in "Email" with "admin@example.com"
16 | And I fill in "Password" with "password"
17 | And I press "Login"
18 | Then I should be on the the dashboard
19 | And I should see "Logout"
20 | And I should see "admin@example.com"
21 |
22 | Scenario: Attempting to log in with an incorrent email address
23 | When I fill in "Email" with "not-an-admin@example.com"
24 | And I fill in "Password" with "not-my-password"
25 | And I press "Login"
26 | Then I should see "Login"
27 | And I should see "Invalid email or password."
28 |
29 | Scenario: Attempting to log in with an incorrect password
30 | When I fill in "Email" with "admin@example.com"
31 | And I fill in "Password" with "not-my-password"
32 | And I press "Login"
33 | Then I should see "Login"
34 | And I should see "Invalid email or password."
35 |
--------------------------------------------------------------------------------
/lib/active_admin/views/header_renderer.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Views
3 |
4 | # Renderer for the header of the application. Includes the page
5 | # title, global navigation and utility navigation.
6 | class HeaderRenderer < ::ActiveAdmin::Renderer
7 |
8 | def to_html
9 | title + global_navigation + utility_navigation
10 | end
11 |
12 | protected
13 |
14 | def title
15 | content_tag 'h1', active_admin_application.site_title, :id => 'site_title'
16 | end
17 |
18 | # Renders the global navigation returned by
19 | # ActiveAdmin::ResourceController#current_menu
20 | #
21 | # It uses the ActiveAdmin.tabs_renderer option
22 | def global_navigation
23 | render view_factory.global_navigation, current_menu
24 | end
25 |
26 | def utility_navigation
27 | content_tag 'p', :id => "utility_nav" do
28 | if current_active_admin_user?
29 | content_tag(:span, display_name(current_active_admin_user), :class => "current_user") +
30 | link_to(I18n.t('active_admin.logout'), "/#{active_admin_application.default_namespace}/logout")
31 | end
32 | end
33 | end
34 | end
35 |
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/spec/unit/auto_link_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | class AutoLinkMockResource
4 | attr_accessor :namespace
5 | def initialize(namespace)
6 | @namespace = namespace
7 | end
8 | end
9 |
10 | describe "auto linking resources" do
11 | include ActiveAdmin::ViewHelpers::ActiveAdminApplicationHelper
12 | include ActiveAdmin::ViewHelpers::AutoLinkHelper
13 | include ActiveAdmin::ViewHelpers::DisplayHelper
14 |
15 | let(:active_admin_config) { AutoLinkMockResource.new(namespace) }
16 | let(:namespace){ ActiveAdmin::Namespace.new(ActiveAdmin::Application.new, :admin) }
17 | let(:post){ Post.create! :title => "Hello World" }
18 |
19 | def admin_post_path(post)
20 | "/admin/posts/#{post.id}"
21 | end
22 |
23 | context "when the resource is not registered" do
24 | it "should return the display name of the object" do
25 | auto_link(post).should == "Hello World"
26 | end
27 | end
28 |
29 | context "when the resource is registered" do
30 | before do
31 | namespace.register Post
32 | end
33 | it "should return a link with the display name of the object" do
34 | self.should_receive(:link_to).with("Hello World", admin_post_path(post))
35 | auto_link(post)
36 | end
37 | end
38 |
39 | end
40 |
--------------------------------------------------------------------------------
/lib/active_admin/view_helpers/display_helper.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module ViewHelpers
3 | module DisplayHelper
4 |
5 | def display_name_method_for(resource)
6 | @@display_name_methods_cache ||= {}
7 | @@display_name_methods_cache[resource.class] ||=
8 | active_admin_application.display_name_methods.find{|method| resource.respond_to? method }
9 | end
10 |
11 | # Tries to display an object with as friendly of output
12 | # as possible.
13 | def display_name(resource)
14 | resource.send(display_name_method_for(resource))
15 | end
16 |
17 | # Return a pretty string for any object
18 | # Date Time are formatted via #localize with :format => :long
19 | # ActiveRecord objects are formatted via #auto_link
20 | # We attempt to #display_name of any other objects
21 | def pretty_format(object)
22 | case object
23 | when String
24 | object
25 | when Arbre::HTML::Element
26 | object
27 | when Date, Time
28 | localize(object, :format => :long)
29 | when ActiveRecord::Base
30 | auto_link(object)
31 | else
32 | display_name(object)
33 | end
34 | end
35 |
36 | end
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/features/support/selectors.rb:
--------------------------------------------------------------------------------
1 | module HtmlSelectorsHelpers
2 | # Maps a name to a selector. Used primarily by the
3 | #
4 | # When /^(.+) within (.+)$/ do |step, scope|
5 | #
6 | # step definitions in web_steps.rb
7 | #
8 | def selector_for(locator)
9 | case locator
10 |
11 | when "the page"
12 | "html > body"
13 |
14 | # Add more mappings here.
15 | # Here is an example that pulls values out of the Regexp:
16 | #
17 | # when /^the (notice|error|info) flash$/
18 | # ".flash.#{$1}"
19 |
20 | # You can also return an array to use a different selector
21 | # type, like:
22 | #
23 | # when /the header/
24 | # [:xpath, "//header"]
25 |
26 | when "index grid"
27 | [:css, "table.index_grid"]
28 |
29 | when /^the "([^"]*)" sidebar$/
30 | [:css, "##{$1.gsub(" ", '').underscore}_sidebar_section"]
31 |
32 | # This allows you to provide a quoted selector as the scope
33 | # for "within" steps as was previously the default for the
34 | # web steps:
35 | when /^"(.+)"$/
36 | $1
37 |
38 | else
39 | raise "Can't find mapping from \"#{locator}\" to a selector.\n" +
40 | "Now, go and add a mapping in #{__FILE__}"
41 | end
42 | end
43 | end
44 |
45 | World(HtmlSelectorsHelpers)
46 |
--------------------------------------------------------------------------------
/lib/active_admin/csv_builder.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | # CSVBuilder stores CSV configuration
3 | #
4 | # Usage example:
5 | #
6 | # csv_builder = CSVBuilder.new
7 | # csv_builder.column :id
8 | # csv_builder.column("Name") { |resource| resource.full_name }
9 | #
10 | class CSVBuilder
11 |
12 | # Return a default CSVBuilder for a resource
13 | # The CSVBuilder's columns would be Id followed by this
14 | # resource's content columns
15 | def self.default_for_resource(resource)
16 | new.tap do |csv_builder|
17 | csv_builder.column(:id)
18 | resource.content_columns.each do |content_column|
19 | csv_builder.column(content_column.name.to_sym)
20 | end
21 | end
22 | end
23 |
24 | attr_reader :columns
25 |
26 | def initialize(&block)
27 | @columns = []
28 | instance_eval &block if block_given?
29 | end
30 |
31 | # Add a column
32 | def column(name, &block)
33 | @columns << Column.new(name, block)
34 | end
35 |
36 | class Column
37 | attr_reader :name, :data
38 |
39 | def initialize(name, block = nil)
40 | @name = name.is_a?(Symbol) ? name.to_s.titleize : name
41 | @data = block || name.to_sym
42 | end
43 | end
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/spec/integration/stylesheets_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe "Stylesheets" do
4 | if Rails.version[0..2] == '3.1'
5 | require "sprockets"
6 | context "when Rails 3.1.x" do
7 | let(:css) do
8 | assets = Rails.application.assets
9 | assets.find_asset("active_admin.css")
10 | end
11 | it "should successfully render the scss stylesheets using sprockets" do
12 | css.should_not be_nil
13 | end
14 | it "should not have any syntax errors" do
15 | css.to_s.should_not include("Syntax error:")
16 | end
17 | end
18 | end
19 |
20 | if Rails.version[0..2] == '3.0'
21 | context "when Rails 3.0.x" do
22 | let(:stylesheet_path) do
23 | Rails.root + 'public/stylesheets/active_admin.css'
24 | end
25 |
26 | before do
27 | "rm #{stylesheet_path}" if File.exists?(stylesheet_path)
28 | Sass::Plugin.force_update_stylesheets
29 | end
30 |
31 | it "should render the scss stylesheets using SASS" do
32 | File.exists?(stylesheet_path).should be_true
33 | end
34 |
35 | it "should not have any syntax errors" do
36 | css = File.read(stylesheet_path)
37 | css.should_not include("Syntax error:")
38 | end
39 | end
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/spec/unit/asset_registration_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | module MockRegistration
4 | extend ActiveAdmin::AssetRegistration
5 | end
6 |
7 | describe ActiveAdmin::AssetRegistration do
8 |
9 | before do
10 | MockRegistration.clear_stylesheets!
11 | MockRegistration.clear_javascripts!
12 | end
13 |
14 | it "should register a stylesheet file" do
15 | MockRegistration.register_stylesheet "active_admin.css"
16 | MockRegistration.stylesheets.should == ["active_admin.css"]
17 | end
18 |
19 | it "should clear all existing stylesheets" do
20 | MockRegistration.register_stylesheet "active_admin.css"
21 | MockRegistration.stylesheets.should == ["active_admin.css"]
22 | MockRegistration.clear_stylesheets!
23 | MockRegistration.stylesheets.should == []
24 | end
25 |
26 | it "should register a javascript file" do
27 | MockRegistration.register_javascript "active_admin.js"
28 | MockRegistration.javascripts.should == ["active_admin.js"]
29 | end
30 |
31 | it "should clear all existing javascripts" do
32 | MockRegistration.register_javascript "active_admin.js"
33 | MockRegistration.javascripts.should == ["active_admin.js"]
34 | MockRegistration.clear_javascripts!
35 | MockRegistration.javascripts.should == []
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/features/step_definitions/format_steps.rb:
--------------------------------------------------------------------------------
1 | Then "I should see nicely formatted datetimes" do
2 | page.body.should =~ /\w+ \d{1,2}, \d{4} \d{2}:\d{2}/
3 | end
4 |
5 | Then /^I should see a link to download "([^"]*)"$/ do |format_type|
6 | page.should have_css("#index_footer a", :text => format_type)
7 | end
8 |
9 | # Check first rows of the displayed CSV.
10 | Then /^I should download a CSV file for "([^"]*)" containing:$/ do |resource_name, table|
11 | page.response_headers['Content-Type'].should == 'text/csv; charset=utf-8'
12 | csv_filename = "#{resource_name}-#{Time.now.strftime("%Y-%m-%d")}.csv"
13 | page.response_headers['Content-Disposition'].should == %{attachment; filename="#{csv_filename}"}
14 | body = page.driver.response.body
15 |
16 | begin
17 | csv = CSV.parse(body)
18 | table.raw.each_with_index do |expected_row, row_index|
19 | expected_row.each_with_index do |expected_cell, col_index|
20 | cell = csv.try(:[], row_index).try(:[], col_index)
21 | if expected_cell.blank?
22 | cell.should be_nil
23 | else
24 | (cell || '').should match(/#{expected_cell}/)
25 | end
26 | end
27 | end
28 | rescue
29 | puts "Expecting:"
30 | p table.raw
31 | puts "to match:"
32 | p csv
33 | raise $!
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/lib/active_admin/resource_controller/scoping.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | class ResourceController < ::InheritedResources::Base
3 |
4 | # This module deals with scoping entire controllers to a relation
5 | module Scoping
6 | extend ActiveSupport::Concern
7 |
8 | protected
9 |
10 | # Override the default InheritedResource #begin_of_association_chain to allow
11 | # the scope to be defined in the active admin configuration.
12 | #
13 | # If scope_to is a proc, we eval it, otherwise we call the method on the controller.
14 | def begin_of_association_chain
15 | return nil unless active_admin_config.scope_to
16 | case active_admin_config.scope_to
17 | when Proc
18 | instance_eval &active_admin_config.scope_to
19 | when Symbol
20 | send active_admin_config.scope_to
21 | else
22 | raise ArgumentError, "#scope_to accepts a symbol or a block"
23 | end
24 | end
25 |
26 | # Overriding from InheritedResources::BaseHelpers
27 | #
28 | # Returns the method for the association chain when using
29 | # the scope_to option
30 | def method_for_association_chain
31 | active_admin_config.scope_to_association_method || super
32 | end
33 |
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/spec/integration/belongs_to_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe_with_capybara "Belongs To" do
4 |
5 | let(:user){ User.create(:first_name => "John", :last_name => "Doe", :username => "johndoe") }
6 | let(:post){ user.posts.create :title => "Hello World", :body => "woot!"}
7 |
8 | before do
9 | # Make sure both are created
10 | user
11 | post
12 | end
13 |
14 | describe "the index page" do
15 | before do
16 | visit admin_user_posts_path(user)
17 | end
18 |
19 | describe "the main content" do
20 | it "should display the default table" do
21 | page.should have_content(post.title)
22 | end
23 | end
24 |
25 | describe "the breadcrumb" do
26 | it "should have a link to the parent's index" do
27 | page.body.should have_tag("a", "Users", :attributes => { :href => "/admin/users" })
28 | end
29 | it "should have a link to the parent" do
30 | page.body.should have_tag("a", user.id.to_s, :attributes => { :href => "/admin/users/#{user.id}" })
31 | end
32 | end
33 |
34 | describe "the view links" do
35 | it "should take you to the sub resource" do
36 | click_link "View"
37 | current_path.should == "/admin/users/#{user.id}/posts/#{post.id}"
38 | end
39 | end
40 | end
41 |
42 | end
43 |
--------------------------------------------------------------------------------
/spec/unit/rails_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe ActiveAdmin do
4 |
5 | describe "use_asset_pipeline?" do
6 |
7 | before(:each) do
8 | @orig_rails_version = Rails::VERSION::MINOR
9 | end
10 |
11 | after(:each) do
12 | silence_warnings { Rails::VERSION::MINOR = @orig_rails_version }
13 | end
14 |
15 | it "should be false when using rails 3.0.x" do
16 | silence_warnings { Rails::VERSION::MINOR = 0 }
17 | ActiveAdmin.use_asset_pipeline?.should be_false
18 | end
19 |
20 | context "when rails 3.1.x" do
21 | before(:each) do
22 | @orig_rails_app = Rails.application.dup
23 | silence_warnings { Rails::VERSION::MINOR = 1 }
24 | end
25 |
26 | after(:each) do
27 | Rails.application = @orig_rails_app
28 | end
29 |
30 | it "should be false without asset pipeline enabled" do
31 | assets = mock(:enabled => false)
32 | Rails.application.config.stub!(:assets => assets)
33 | ActiveAdmin.use_asset_pipeline?.should be_false
34 | end
35 |
36 | it "should be true with asset pipeline enabled" do
37 | assets = mock(:enabled => true)
38 | Rails.application.config.stub!(:assets => assets)
39 | ActiveAdmin.use_asset_pipeline?.should be_true
40 | end
41 | end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/lib/active_admin/views/components/columns.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Views
3 |
4 | class Columns < ActiveAdmin::Component
5 | builder_method :columns
6 |
7 | def column(*args, &block)
8 | insert_tag Column, *args, &block
9 | end
10 |
11 | # Override add child to set widths
12 | def add_child(*)
13 | super
14 | calculate_columns!
15 | end
16 |
17 | protected
18 |
19 | def margin_size
20 | 2
21 | end
22 |
23 | def calculate_columns!
24 | # Calculate our columns sizes and margins
25 | count = children.size
26 | margins_width = margin_size * (count - 1)
27 | column_width = (100.00 - margins_width) / count
28 |
29 | # Convert to an integer if its not a float
30 | column_width = column_width.to_i == column_width ? column_width.to_i : column_width
31 |
32 | children.each_with_index do |col, i|
33 | col.set_attribute :style, "width: #{column_width}%;"
34 | col.attr(:style) << " margin-right: #{margin_size}%;" unless i == (count - 1)
35 | end
36 | end
37 |
38 | def to_html
39 | super.to_s + "".html_safe
40 | end
41 |
42 | end
43 |
44 | class Column < ActiveAdmin::Component
45 | end
46 | end
47 | end
48 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2010 Greg Bell, VersaPay Corporation
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
22 | Iconic Icons are designed by P.J. Onori and are shared under
23 | the Creative Commons Attribution-Share Alike 3.0 license:
24 | http://creativecommons.org/licenses/by-sa/3.0/us
25 | http://somerandomdude.com/projects/iconic/
26 |
--------------------------------------------------------------------------------
/lib/active_admin/locales/es.yml:
--------------------------------------------------------------------------------
1 | es:
2 | active_admin:
3 | dashboard_welcome:
4 | welcome: "Bienvenido a Active Admin. Esta es la página de panel predeterminada."
5 | call_to_action: "Para agregar secciones edita 'app/admin/dashboards.rb'"
6 | view: "Ver"
7 | edit: "Editar"
8 | delete: "Eliminar"
9 | delete_confirmation: "¿Está seguro que quiere eliminar esto?"
10 | new_model: "Nuevo %{model}"
11 | edit_model: "Editar %{model}"
12 | delete_model: "Eliminar %{model}"
13 | details: "Detalles de %{model}"
14 | cancel: "Cancelar"
15 | empty: "Vacio"
16 | previous: "Anterior"
17 | next: "Siguiente"
18 | download: "Descargar:"
19 | has_many_new: "Agregar nuevo %{model}"
20 | has_many_delete: "Eliminar"
21 | filter: "Filtrar"
22 | clear_filters: "Quitar Filtros"
23 | search_field: "Buscar %{field}"
24 | equal_to: "Igual a"
25 | greater_than: "Mayor que"
26 | less_than: "Menor que"
27 | main_content: "Por favor implemente %{model}#main_content para mostrar contenido."
28 | logout: "Salir"
29 | sidebars:
30 | filters: "Filtros"
31 | pagination:
32 | empty: "Ningún %{model} encontrado"
33 | one: "Mostrando 1 %{model}"
34 | one_page: "Mostrando todos los %{n} %{model}"
35 | multiple: "Mostrando %{model} %{from} - %{to} de un total de %{total}"
36 | any: "Todos"
37 |
--------------------------------------------------------------------------------
/lib/generators/active_admin/assets/templates/dashboards.rb:
--------------------------------------------------------------------------------
1 | ActiveAdmin::Dashboards.build do
2 |
3 | # Define your dashboard sections here. Each block will be
4 | # rendered on the dashboard in the context of the view. So just
5 | # return the content which you would like to display.
6 |
7 | # == Simple Dashboard Section
8 | # Here is an example of a simple dashboard section
9 | #
10 | # section "Recent Posts" do
11 | # ul do
12 | # Post.recent(5).collect do |post|
13 | # li link_to(post.title, admin_post_path(post))
14 | # end
15 | # end
16 | # end
17 |
18 | # == Render Partial Section
19 | # The block is rendererd within the context of the view, so you can
20 | # easily render a partial rather than build content in ruby.
21 | #
22 | # section "Recent Posts" do
23 | # render 'recent_posts' # => this will render /app/views/admin/dashboard/_recent_posts.html.erb
24 | # end
25 |
26 | # == Section Ordering
27 | # The dashboard sections are ordered by a given priority from top left to
28 | # bottom right. The default priority is 10. By giving a section numerically lower
29 | # priority it will be sorted higher. For example:
30 | #
31 | # section "Recent Posts", :priority => 10
32 | # section "Recent User", :priority => 1
33 | #
34 | # Will render the "Recent Users" then the "Recent Posts" sections on the dashboard.
35 |
36 | end
37 |
--------------------------------------------------------------------------------
/script/local:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require File.expand_path('../../spec/support/detect_rails_version', __FILE__)
4 |
5 | unless ARGV[0]
6 | puts <<-EOF
7 | Usage: ./script/#{__FILE__} COMMAND [ARGS]
8 |
9 | The command will be run in the context of the local rails
10 | app stored in test-rails-app.
11 |
12 | Examples:
13 |
14 | ./script/local server
15 | ./script/local c
16 | ./script/local rake db:migrate
17 | EOF
18 | exit(1)
19 | end
20 |
21 | # Set up some variables
22 | rails_version = detect_rails_version || '3.0.0'
23 |
24 | test_app_dir = ".test-rails-apps"
25 | test_app_path = "#{test_app_dir}/test-rails-app-#{rails_version}"
26 |
27 | # Ensure .test-rails-apps is created
28 | system "mkdir #{test_app_dir}" unless File.exists?(test_app_dir)
29 |
30 | # Create the sample rails app if it doesn't already exist
31 | unless File.exists? test_app_path
32 | system "RAILS='#{rails_version}' bundle exec rails new #{test_app_path} -m spec/support/rails_template_with_data.rb"
33 | end
34 |
35 | # Link this rails app
36 | system "rm test-rails-app"
37 | system "ln -s #{test_app_path} test-rails-app"
38 |
39 | # If it's a rails command, auto add the rails script
40 | RAILS_COMMANDS = %w{generate console server dbconsole g c s runner}
41 | args = RAILS_COMMANDS.include?(ARGV[0]) ? ["rails", ARGV].flatten : ARGV
42 |
43 | # Run the command
44 | exec "cd test-rails-app && GEMFILE=../Gemfile bundle exec #{args.join(" ")}"
45 |
--------------------------------------------------------------------------------
/lib/active_admin/locales/pt.yml:
--------------------------------------------------------------------------------
1 | pt:
2 | active_admin:
3 | dashboard_welcome:
4 | welcome: "Bem vindo ao Active Admin. Esta é a página de painéis padrão."
5 | call_to_action: "Para adicionar seções ao painel, verifique 'app/admin/dashboards.rb'"
6 | view: "Visualizar"
7 | edit: "Editar"
8 | delete: "Remover"
9 | delete_confirmation: "Você tem certeza que deseja remover este item?"
10 | new_model: "Novo(a) %{model}"
11 | edit_model: "Editar %{model}"
12 | delete_model: "Remover %{model}"
13 | details: "Detalhes do(a) %{model}"
14 | cancel: "Cancelar"
15 | empty: "Vazio"
16 | previous: "Anterior"
17 | next: "Próximo"
18 | download: "Baixar:"
19 | has_many_new: "Adicionar Novo(a) %{model}"
20 | has_many_delete: "Remover"
21 | filter: "Filtrar"
22 | clear_filters: "Limpar Filtros"
23 | search_field: "Pesquisar %{field}"
24 | equal_to: "Igual A"
25 | greater_than: "Maior Que"
26 | less_than: "Menor Que"
27 | main_content: "Por favor implemente %{model}#main_content para exibir conteúdo."
28 | logout: "Sair"
29 | sidebars:
30 | filters: "Filtros"
31 | pagination:
32 | empty: "Nenhum(a) %{model} encontrado(a)"
33 | one: "Exibindo 1 %{model}"
34 | one_page: "Exibindo todos os(a) %{n} %{model}"
35 | multiple: "Exibindo %{model} %{from} - %{to} de um total de %{total}"
36 |
37 |
--------------------------------------------------------------------------------
/lib/active_admin/resource/menu.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | class Resource
3 | module Menu
4 |
5 | # Set the menu options. To not add this resource to the menu, just
6 | # call #menu(false)
7 | def menu(options = {})
8 | options = options == false ? { :display => false } : options
9 | @menu_options = options
10 | end
11 |
12 | # The options to use for the menu
13 | def menu_options
14 | @menu_options ||= {}
15 | end
16 |
17 | # Returns the name to put this resource under in the menu
18 | def parent_menu_item_name
19 | menu_options[:parent]
20 | end
21 |
22 | # Returns the name to be displayed in the menu for this resource
23 | def menu_item_name
24 | menu_options[:label] || plural_resource_name
25 | end
26 |
27 | # Returns the items priority for altering the default sort order
28 | def menu_item_priority
29 | menu_options[:priority] || 10
30 | end
31 |
32 | # Returns a proc for deciding whether to display the menu item or not in the view
33 | def menu_item_display_if
34 | menu_options[:if] || proc { true }
35 | end
36 |
37 | # Should this resource be added to the menu system?
38 | def include_in_menu?
39 | return false if menu_options[:display] == false
40 | !(belongs_to? && !belongs_to_config.optional?)
41 | end
42 |
43 | end
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/lib/generators/active_admin/install/templates/migrations/2_move_admin_notes_to_comments.rb:
--------------------------------------------------------------------------------
1 | class MoveAdminNotesToComments < ActiveRecord::Migration
2 | def self.up
3 | remove_index :admin_notes, [:admin_user_type, :admin_user_id]
4 | rename_table :admin_notes, :active_admin_comments
5 | rename_column :active_admin_comments, :admin_user_type, :author_type
6 | rename_column :active_admin_comments, :admin_user_id, :author_id
7 | add_column :active_admin_comments, :namespace, :string
8 | add_index :active_admin_comments, [:namespace]
9 | add_index :active_admin_comments, [:author_type, :author_id]
10 |
11 | # Update all the existing comments to the default namespace
12 | say "Updating any existing comments to the #{ActiveAdmin.application.default_namespace} namespace."
13 | execute "UPDATE active_admin_comments SET namespace='#{ActiveAdmin.application.default_namespace}'"
14 | end
15 |
16 | def self.down
17 | remove_index :active_admin_comments, :column => [:author_type, :author_id]
18 | remove_index :active_admin_comments, :column => [:namespace]
19 | remove_column :active_admin_comments, :namespace
20 | rename_column :active_admin_comments, :author_id, :admin_user_id
21 | rename_column :active_admin_comments, :author_type, :admin_user_type
22 | rename_table :active_admin_comments, :admin_notes
23 | add_index :admin_notes, [:admin_user_type, :admin_user_id]
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/lib/active_admin/iconic.rb:
--------------------------------------------------------------------------------
1 | require 'active_admin/iconic/icons'
2 |
3 | module ActiveAdmin
4 | module Iconic
5 |
6 | # Default color to use for icons
7 | @@default_color = "#5E6469"
8 | mattr_accessor :default_color
9 |
10 | # Default width to use for icons
11 | @@default_width = 15
12 | mattr_accessor :default_width
13 |
14 | # Default height to use for icons
15 | @@default_height = 15
16 | mattr_accessor :default_height
17 |
18 | # Render an icon:
19 | # Iconic.icon :loop
20 | def self.icon(name, options = {})
21 | options = {
22 | :color => default_color,
23 | :width => default_width,
24 | :height => default_height,
25 | :id => ""
26 | }.merge(options)
27 |
28 |
29 | options[:style] = "fill:#{options[:color]};"
30 | options[:fill] = options.delete(:color)
31 |
32 | # Convert to strings representations of pixels
33 | [:width, :height].each do |key|
34 | options[key] = "#{options[key]}px" unless options[key].is_a?(String)
35 | end
36 |
37 | template = ICONS[name.to_sym]
38 |
39 | if template
40 | svg = template.dup
41 | options.each do |key, value|
42 | svg.gsub!("{#{key}}", value)
43 | end
44 | "#{svg}".html_safe
45 | else
46 | raise "Could not find the icon named #{name}"
47 | end
48 | end
49 |
50 | end
51 | end
52 |
--------------------------------------------------------------------------------
/lib/generators/active_admin/install/install_generator.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Generators
3 | class InstallGenerator < Rails::Generators::Base
4 | desc "Installs Active Admin and generats the necessary migrations"
5 |
6 | hook_for :users, :default => "devise", :desc => "Admin user generator to run. Skip with --skip-users"
7 |
8 | include Rails::Generators::Migration
9 |
10 | def self.source_root
11 | @_active_admin_source_root ||= File.expand_path("../templates", __FILE__)
12 | end
13 |
14 | def self.next_migration_number(dirname)
15 | Time.now.strftime("%Y%m%d%H%M%S")
16 | end
17 |
18 | def copy_initializer
19 | template 'active_admin.rb.erb', 'config/initializers/active_admin.rb'
20 | end
21 |
22 | def setup_directory
23 | empty_directory "app/admin"
24 | template 'dashboards.rb', 'app/admin/dashboards.rb'
25 | end
26 |
27 | def setup_routes
28 | route "ActiveAdmin.routes(self)"
29 | end
30 |
31 | def create_assets
32 | generate "active_admin:assets"
33 | end
34 |
35 | def create_migrations
36 | Dir["#{self.class.source_root}/migrations/*.rb"].sort.each do |filepath|
37 | name = File.basename(filepath)
38 | migration_template "migrations/#{name}", "db/migrate/#{name.gsub(/^\d+_/,'')}"
39 | sleep 1
40 | end
41 | end
42 | end
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/lib/generators/active_admin/install/templates/dashboards.rb:
--------------------------------------------------------------------------------
1 | ActiveAdmin::Dashboards.build do
2 |
3 | # Define your dashboard sections here. Each block will be
4 | # rendered on the dashboard in the context of the view. So just
5 | # return the content which you would like to display.
6 |
7 | # == Simple Dashboard Section
8 | # Here is an example of a simple dashboard section
9 | #
10 | # section "Recent Posts" do
11 | # ul do
12 | # Post.recent(5).collect do |post|
13 | # li link_to(post.title, admin_post_path(post))
14 | # end
15 | # end
16 | # end
17 |
18 | # == Render Partial Section
19 | # The block is rendered within the context of the view, so you can
20 | # easily render a partial rather than build content in ruby.
21 | #
22 | # section "Recent Posts" do
23 | # div do
24 | # render 'recent_posts' # => this will render /app/views/admin/dashboard/_recent_posts.html.erb
25 | # end
26 | # end
27 |
28 | # == Section Ordering
29 | # The dashboard sections are ordered by a given priority from top left to
30 | # bottom right. The default priority is 10. By giving a section numerically lower
31 | # priority it will be sorted higher. For example:
32 | #
33 | # section "Recent Posts", :priority => 10
34 | # section "Recent User", :priority => 1
35 | #
36 | # Will render the "Recent Users" then the "Recent Posts" sections on the dashboard.
37 |
38 | end
39 |
--------------------------------------------------------------------------------
/lib/active_admin/locales/en.yml:
--------------------------------------------------------------------------------
1 | en:
2 | active_admin:
3 | dashboard_welcome:
4 | welcome: "Welcome to Active Admin. This is the default dashboard page."
5 | call_to_action: "To add dashboard sections, checkout 'app/admin/dashboards.rb'"
6 | view: "View"
7 | edit: "Edit"
8 | delete: "Delete"
9 | delete_confirmation: "Are you sure you want to delete this?"
10 | new_model: "New %{model}"
11 | edit_model: "Edit %{model}"
12 | delete_model: "Delete %{model}"
13 | details: "%{model} Details"
14 | cancel: "Cancel"
15 | empty: "Empty"
16 | previous: "Previous"
17 | next: "Next"
18 | download: "Download:"
19 | has_many_new: "Add New %{model}"
20 | has_many_delete: "Delete"
21 | filter: "Filter"
22 | clear_filters: "Clear Filters"
23 | search_field: "Search %{field}"
24 | equal_to: "Equal To"
25 | greater_than: "Greater Than"
26 | less_than: "Less Than"
27 | main_content: "Please implement %{model}#main_content to display content."
28 | logout: "Logout"
29 | sidebars:
30 | filters: "Filters"
31 | pagination:
32 | empty: "No %{model} found"
33 | one: "Displaying 1 %{model}"
34 | one_page: "Displaying all %{n} %{model}"
35 | multiple: "Displaying %{model} %{from} - %{to} of %{total} in total"
36 | any: "Any"
37 | blank_slate:
38 | content: "There are no %{resource_name} yet."
39 | link: "Create one"
--------------------------------------------------------------------------------
/spec/unit/belongs_to_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | module ActiveAdmin
4 | class Resource
5 | describe BelongsTo do
6 |
7 | let(:application){ ActiveAdmin::Application.new }
8 | let(:namespace){ Namespace.new(application, :admin) }
9 | let(:post){ namespace.register(Post) }
10 | let(:belongs_to){ BelongsTo.new(post, :user) }
11 |
12 | it "should have an owner" do
13 | belongs_to.owner.should == post
14 | end
15 |
16 | it "should have a namespace" do
17 | belongs_to.namespace.should == namespace
18 | end
19 |
20 | describe "finding the target" do
21 | context "when the resource has been registered" do
22 | let(:user){ namespace.register(User) }
23 | before { user } # Ensure user is registered
24 |
25 | it "should return the target resource" do
26 | belongs_to.target.should == user
27 | end
28 | end
29 |
30 | context "when the resource has not been registered" do
31 | it "should raise a ActiveAdmin::BelongsTo::TargetNotFound" do
32 | lambda {
33 | belongs_to.target
34 | }.should raise_error(ActiveAdmin::Resource::BelongsTo::TargetNotFound)
35 | end
36 | end
37 | end
38 |
39 | it "should be optional" do
40 | belongs_to = BelongsTo.new post, :user, :optional => true
41 | belongs_to.should be_optional
42 | end
43 | end
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/lib/active_admin/resource_controller/page_configurations.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | class ResourceController < ::InheritedResources::Base
3 |
4 | module PageConfigurations
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | helper_method :index_config
9 | helper_method :show_config
10 | end
11 |
12 | module ClassMethods
13 |
14 | def set_page_config(page, options, &block)
15 | active_admin_config.page_configs[page] = ActiveAdmin::PageConfig.new(options, &block)
16 | end
17 |
18 | def get_page_config(page)
19 | active_admin_config.page_configs[page]
20 | end
21 |
22 | def reset_page_config!(page)
23 | active_admin_config.page_configs[page] = nil
24 | end
25 |
26 | # Define the getting and re-setter for each configurable page
27 | [:index, :show].each do |page|
28 | # eg: index_config
29 | define_method :"#{page}_config" do
30 | get_page_config(page)
31 | end
32 |
33 | # eg: reset_index_config!
34 | define_method :"reset_#{page}_config!" do
35 | reset_page_config! page
36 | end
37 | end
38 |
39 | end
40 |
41 | protected
42 |
43 | def index_config
44 | @index_config ||= self.class.index_config
45 | end
46 |
47 | def show_config
48 | @show_config ||= self.class.show_config
49 | end
50 |
51 | end
52 | end
53 | end
54 |
--------------------------------------------------------------------------------
/lib/active_admin/dashboards.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Dashboards
3 |
4 | autoload :DashboardController, 'active_admin/dashboards/dashboard_controller'
5 | autoload :Section, 'active_admin/dashboards/section'
6 |
7 | @@sections = {}
8 | mattr_accessor :sections
9 |
10 | class << self
11 |
12 | # Eval an entire block in the context of this module to build
13 | # dashboards quicker.
14 | #
15 | # Example:
16 | #
17 | # ActiveAdmin::Dashboards.build do
18 | # section "Recent Post" do
19 | # # return a list of posts
20 | # end
21 | # end
22 | #
23 | def build(&block)
24 | module_eval(&block)
25 | end
26 |
27 | # Add a new dashboard section to a namespace. If no namespace is given
28 | # it will be added to the default namespace.
29 | def add_section(name, options = {}, &block)
30 | namespace = options.delete(:namespace) || ActiveAdmin.application.default_namespace || :root
31 | self.sections[namespace] ||= []
32 | self.sections[namespace] << Section.new(namespace, name, options, &block)
33 | self.sections[namespace].sort!
34 | end
35 | alias_method :section, :add_section
36 |
37 | def sections_for_namespace(namespace)
38 | @@sections[namespace] || []
39 | end
40 |
41 | def clear_all_sections!
42 | @@sections = {}
43 | end
44 |
45 | end
46 |
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/features/support/paths.rb:
--------------------------------------------------------------------------------
1 | module NavigationHelpers
2 | # Maps a name to a path. Used by the
3 | #
4 | # When /^I go to (.+)$/ do |page_name|
5 | #
6 | # step definition in web_steps.rb
7 | #
8 | def path_to(page_name)
9 | case page_name
10 |
11 | when /the home\s?page/
12 | '/'
13 | when /the dashboard/
14 | "/admin"
15 | when /the new post page/
16 | "/admin/posts/new"
17 |
18 | # the index page for posts in the root namespace
19 | # the index page for posts in the user_admin namespace
20 | when /^the index page for (.*) in the (.*) namespace$/
21 | if $2 != 'root'
22 | send(:"#{$2}_#{$1}_path")
23 | else
24 | send(:"#{$1}_path")
25 | end
26 |
27 | # same as above, except defaults to admin namespace
28 | when /^the index page for (.*)$/
29 | send(:"admin_#{$1}_path")
30 |
31 | # Add more mappings here.
32 | # Here is an example that pulls values out of the Regexp:
33 | #
34 | # when /^(.*)'s profile page$/i
35 | # user_profile_path(User.find_by_login($1))
36 |
37 | else
38 | begin
39 | page_name =~ /the (.*) page/
40 | path_components = $1.split(/\s+/)
41 | self.send(path_components.push('path').join('_').to_sym)
42 | rescue Object => e
43 | raise "Can't find mapping from \"#{page_name}\" to a path.\n" +
44 | "Now, go and add a mapping in #{__FILE__}"
45 | end
46 | end
47 | end
48 | end
49 |
50 | World(NavigationHelpers)
51 |
--------------------------------------------------------------------------------
/spec/unit/event_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 | require 'active_admin/event'
3 |
4 | describe ActiveAdmin::EventDispatcher do
5 |
6 | let(:test_event){ 'active_admin.test_event' }
7 | let(:dispatcher){ ActiveAdmin::EventDispatcher.new }
8 |
9 | it "should add a subscriber for an event" do
10 | dispatcher.subscribers(test_event).size.should == 0
11 | dispatcher.subscribe(test_event){ true }
12 | dispatcher.subscribers(test_event).size.should == 1
13 | end
14 |
15 | it "should call the dispatch block with no arguments" do
16 | dispatcher.subscribe(test_event){ raise StandardError, "From Event Handler" }
17 | lambda {
18 | dispatcher.dispatch(test_event)
19 | }.should raise_error(StandardError, "From Event Handler")
20 | end
21 |
22 | it "should call the dispatch block with one argument" do
23 | arg = nil
24 | dispatcher.subscribe(test_event){|passed_in| arg = passed_in }
25 | dispatcher.dispatch(test_event, "My Arg")
26 | arg.should == "My Arg"
27 | end
28 |
29 | it "should clear all subscribers" do
30 | dispatcher.subscribe(test_event){ false }
31 | dispatcher.subscribe(test_event + "_2"){ false }
32 | dispatcher.clear_all_subscribers!
33 | dispatcher.subscribers(test_event).size.should == 0
34 | dispatcher.subscribers(test_event + "_2").size.should == 0
35 | end
36 |
37 | it "should have a dispatcher available from ActiveAdmin::Event" do
38 | ActiveAdmin::Event.should be_an_instance_of(ActiveAdmin::EventDispatcher)
39 | end
40 |
41 | end
42 |
--------------------------------------------------------------------------------
/spec/unit/dashboard_section_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe ActiveAdmin::Dashboards::Section do
4 |
5 | def section(options = {})
6 | name = options.delete(:name) || "Recent Posts"
7 | ActiveAdmin::Dashboards::Section.new(:admin, name, options){ }
8 | end
9 |
10 | describe "accessors" do
11 | it "should have a namespace" do
12 | section.namespace.should == :admin
13 | end
14 |
15 | it "should have a block" do
16 | section.block.class.should == Proc
17 | end
18 |
19 | it "should have a name" do
20 | section.name.should == 'Recent Posts'
21 | end
22 | end
23 |
24 | describe "priority" do
25 | context "when not set" do
26 | subject{ section.priority }
27 | it { should == ActiveAdmin::Dashboards::Section::DEFAULT_PRIORITY }
28 | end
29 |
30 | context "when set" do
31 | subject{ section(:priority => 1).priority }
32 | it { should == 1 }
33 | end
34 | end
35 |
36 | describe "icon" do
37 | it "should set the icon" do
38 | s = section(:icon => :my_icon)
39 | s.icon.should == :my_icon
40 | end
41 | it "should be nil by default" do
42 | section.icon.should be_nil
43 | end
44 | end
45 |
46 | describe "sorting sections" do
47 | it "should sort by priority then alpha" do
48 | s1 = section :name => "Woot"
49 | s2 = section :name => :Alpha
50 | s3 = section :name => "Zulu", :priority => 1
51 | s4 = section :name => "Beta", :priority => 100
52 | [s1,s2,s3,s4].sort.should == [s3, s2, s1, s4]
53 | end
54 | end
55 |
56 | end
57 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/active_admin/mixins/_rounded.css.scss:
--------------------------------------------------------------------------------
1 | @mixin rounded($radius: 3px) {
2 | -webkit-border-radius: $radius;
3 | -moz-border-radius: $radius;
4 | border-radius: $radius;
5 | }
6 |
7 | @mixin rounded-all($top-left:3px, $top-right:3px, $bottom-right:3px, $bottom-left:3px) {
8 | border-top-right-radius: $top-right;
9 | -moz-border-radius-topright: $top-right;
10 | -webkit-border-top-right-radius: $top-right;
11 |
12 | border-top-left-radius: $top-left;
13 | -moz-border-radius-topleft: $top-left;
14 | -webkit-border-top-left-radius: $top-left;
15 |
16 | border-bottom-right-radius: $bottom-right;
17 | -moz-border-radius-bottomright: $bottom-right;
18 | -webkit-border-bottom-right-radius: $bottom-right;
19 |
20 | border-bottom-left-radius: $bottom-left;
21 | -moz-border-radius-bottomleft: $bottom-left;
22 | -webkit-border-bottom-left-radius: $bottom-left;
23 | }
24 |
25 | @mixin rounded-top($radius: 3px) {
26 | @include rounded(0);
27 | border-top-right-radius: $radius;
28 | border-top-left-radius: $radius;
29 | -moz-border-radius-topright: $radius;
30 | -moz-border-radius-topleft: $radius;
31 | -webkit-border-top-right-radius: $radius;
32 | -webkit-border-top-left-radius: $radius;
33 | }
34 |
35 | @mixin rounded-bottom($radius: 3px) {
36 | @include rounded(0);
37 | border-bottom-right-radius: $radius;
38 | border-bottom-left-radius: $radius;
39 | -moz-border-radius-bottomright: $radius;
40 | -moz-border-radius-bottomleft: $radius;
41 | -webkit-border-bottom-right-radius: $radius;
42 | -webkit-border-bottom-left-radius: $radius;
43 | }
44 |
--------------------------------------------------------------------------------
/lib/active_admin/view_helpers/auto_link_helper.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module ViewHelpers
3 | module AutoLinkHelper
4 |
5 | # Automatically links objects to their resource controllers. If
6 | # the resource has not been registered, a string representation of
7 | # the object is returned.
8 | #
9 | # The default content in the link is returned from ActiveAdmin::ViewHelpers::DisplayHelper#display_name
10 | #
11 | # You can pass in the content to display
12 | # eg: auto_link(@post, "My Link Content")
13 | #
14 | def auto_link(resource, link_content = nil)
15 | content = link_content || display_name(resource)
16 | if registration = active_admin_resource_for(resource.class)
17 | begin
18 | content = link_to(content, send(registration.route_instance_path, resource))
19 | rescue
20 | end
21 | end
22 | content
23 | end
24 |
25 | # Returns the ActiveAdmin::Resource instance for a class
26 | def active_admin_resource_for(klass)
27 | active_admin_namespace.resource_for(klass)
28 | end
29 |
30 | # Returns the current Active Admin namespace
31 | def active_admin_namespace
32 | if respond_to?(:active_admin_config) && active_admin_config
33 | active_admin_config.namespace
34 | else
35 | # Return a default namespace if none exists
36 | active_admin_application.find_or_create_namespace(active_admin_application.default_namespace)
37 | end
38 | end
39 |
40 | end
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/features/index/index_as_grid.feature:
--------------------------------------------------------------------------------
1 | Feature: Index as Grid
2 |
3 | Viewing resources as a grid on the index page
4 |
5 | Scenario: Viewing index as a grid with a simple block configuration
6 | Given 9 posts exist
7 | And an index configuration of:
8 | """
9 | ActiveAdmin.register Post do
10 | index :as => :grid do |post|
11 | h2 auto_link(post)
12 | end
13 | end
14 | """
15 | Then the table ".index_grid" should have 3 rows
16 | And the table ".index_grid" should have 3 columns
17 | And there should be 9 "a" tags within index grid
18 |
19 | Scenario: Viewing index as a grid and set the number of columns
20 | Given 9 posts exist
21 | And an index configuration of:
22 | """
23 | ActiveAdmin.register Post do
24 | index :as => :grid, :columns => 1 do |post|
25 | h2 auto_link(post)
26 | end
27 | end
28 | """
29 | Then the table ".index_grid" should have 9 rows
30 | And the table ".index_grid" should have 1 columns
31 | And there should be 9 "a" tags within "table.index_grid"
32 |
33 | Scenario: Viewing index as a grid with an odd number of items
34 | Given 9 posts exist
35 | And an index configuration of:
36 | """
37 | ActiveAdmin.register Post do
38 | index :as => :grid, :columns => 2 do |post|
39 | h2 auto_link(post)
40 | end
41 | end
42 | """
43 | Then the table ".index_grid" should have 5 rows
44 | And the table ".index_grid" should have 2 columns
45 | And there should be 9 "a" tags within "table.index_grid"
46 |
--------------------------------------------------------------------------------
/spec/unit/arbre/html/element_finder_methods_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Arbre::HTML::Element, "Finder Methods" do
4 | include Arbre::HTML
5 | let(:assigns){ {} }
6 |
7 | describe "finding elements by tag name" do
8 |
9 | it "should return 0 when no elements exist" do
10 | div.get_elements_by_tag_name("li").size.should == 0
11 | end
12 |
13 | it "should return a child element" do
14 | html = div do
15 | ul
16 | li
17 | ul
18 | end
19 | elements = html.get_elements_by_tag_name("li")
20 | elements.size.should == 1
21 | elements[0].should be_instance_of(Arbre::HTML::Li)
22 | end
23 |
24 | it "should return multple child elements" do
25 | html = div do
26 | ul
27 | li
28 | ul
29 | li
30 | end
31 | elements = html.get_elements_by_tag_name("li")
32 | elements.size.should == 2
33 | elements[0].should be_instance_of(Arbre::HTML::Li)
34 | elements[1].should be_instance_of(Arbre::HTML::Li)
35 | end
36 |
37 | it "should return children's child elements" do
38 | html = div do
39 | ul
40 | li do
41 | li
42 | end
43 | end
44 | elements = html.get_elements_by_tag_name("li")
45 | elements.size.should == 2
46 | elements[0].should be_instance_of(Arbre::HTML::Li)
47 | elements[1].should be_instance_of(Arbre::HTML::Li)
48 | elements[1].parent.should == elements[0]
49 | end
50 | end
51 |
52 | describe "finding an element by id"
53 | describe "finding an element by a class name"
54 | end
55 |
--------------------------------------------------------------------------------
/features/index/format_as_csv.feature:
--------------------------------------------------------------------------------
1 | Feature: Format as CSV
2 |
3 | Background:
4 | Given I am logged in
5 |
6 | Scenario: Default
7 | Given a configuration of:
8 | """
9 | ActiveAdmin.register Post
10 | """
11 | And a post with the title "Hello World" exists
12 | When I am on the index page for posts
13 | And I follow "CSV"
14 | And I should download a CSV file for "posts" containing:
15 | | Id | Title | Body | Published At | Created At | Updated At |
16 | | \d+ | Hello World | | | (.*) | (.*) |
17 |
18 | Scenario: Default with alias
19 | Given a configuration of:
20 | """
21 | ActiveAdmin.register Post, :as => "MyArticle"
22 | """
23 | And 1 post exists
24 | When I am on the index page for my_articles
25 | And I follow "CSV"
26 | And I should download a CSV file for "my-articles" containing:
27 | | Id | Title | Body | Published At | Created At | Updated At |
28 |
29 | Scenario: With CSV format customization
30 | Given a configuration of:
31 | """
32 | ActiveAdmin.register Post do
33 | csv do
34 | column :title
35 | column("Last update") { |post| post.updated_at }
36 | column("Copyright") { "Greg Bell" }
37 | end
38 | end
39 | """
40 | And a post with the title "Hello, World" exists
41 | When I am on the index page for posts
42 | And I follow "CSV"
43 | And I should download a CSV file for "posts" containing:
44 | | Title | Last update | Copyright |
45 | | Hello, World | (.*) | Greg Bell |
46 |
47 |
--------------------------------------------------------------------------------
/lib/active_admin/views/pages/show.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Views
3 | module Pages
4 | class Show < Base
5 |
6 | def config
7 | active_admin_config.page_configs[:show] || ::ActiveAdmin::PageConfig.new
8 | end
9 |
10 | def title
11 | case config[:title]
12 | when Symbol, Proc
13 | call_method_or_proc_on(resource, config[:title])
14 | when String
15 | config[:title]
16 | else
17 | default_title
18 | end
19 | end
20 |
21 | def main_content
22 | if config.block
23 | # Eval the show config from the controller
24 | instance_exec resource, &config.block
25 | else
26 | default_main_content
27 | end
28 | end
29 |
30 | def attributes_table(*args, &block)
31 | panel(I18n.t('active_admin.details', :model => active_admin_config.resource_name)) do
32 | attributes_table_for resource, *args, &block
33 | end
34 | end
35 |
36 | protected
37 |
38 | def default_title
39 | "#{active_admin_config.resource_name} ##{resource.id}"
40 | end
41 |
42 | module DefaultMainContent
43 | def default_main_content
44 | attributes_table *default_attribute_table_rows
45 | end
46 |
47 | def default_attribute_table_rows
48 | resource.class.columns.collect{|column| column.name.to_sym }
49 | end
50 | end
51 |
52 | include DefaultMainContent
53 | end
54 | end
55 | end
56 | end
57 |
--------------------------------------------------------------------------------
/features/show/default_content.feature:
--------------------------------------------------------------------------------
1 | Feature: Show - Default Content
2 |
3 | Viewing the show page for a resource
4 |
5 | Background:
6 | Given a post with the title "Hello World" written by "Jane Doe" exists
7 |
8 | Scenario: Viewing the default show page
9 | Given a show configuration of:
10 | """
11 | ActiveAdmin.register Post
12 | """
13 | Then I should see the attribute "Title" with "Hello World"
14 | And I should see the attribute "Body" with "Empty"
15 | And I should see the attribute "Created At" with a nicely formatted datetime
16 | And I should see the attribute "Author" with "jane_doe"
17 | And I should see an action item button "Delete Post"
18 | And I should see an action item button "Edit Post"
19 |
20 | Scenario: Attributes should link when linked resource is registered
21 | Given a show configuration of:
22 | """
23 | ActiveAdmin.register User
24 | ActiveAdmin.register Post
25 | """
26 | Then I should see the attribute "Author" with "jane_doe"
27 | And I should see a link to "jane_doe"
28 |
29 | Scenario: Customizing the attributes table with a set of attributes
30 | Given a show configuration of:
31 | """
32 | ActiveAdmin.register Post do
33 |
34 | show do
35 | attributes_table :title, :body, :created_at, :updated_at
36 | end
37 |
38 | end
39 | """
40 | Then I should see the attribute "Title" with "Hello World"
41 | And I should see the attribute "Body" with "Empty"
42 | And I should see the attribute "Created At" with a nicely formatted datetime
43 | And I should not see the attribute "Author"
44 |
--------------------------------------------------------------------------------
/spec/unit/menu_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe ActiveAdmin::Menu do
4 |
5 | context "with no items" do
6 | it "should be empty" do
7 | ActiveAdmin::Menu.new.items.should == []
8 | end
9 |
10 | it "should accept new items" do
11 | menu = ActiveAdmin::Menu.new
12 | menu.add "Dashboard", "/admin"
13 | menu.items.first.should be_an_instance_of(ActiveAdmin::MenuItem)
14 | menu.items.first.name.should == "Dashboard"
15 | end
16 |
17 | it "should default new items to the priority of 10" do
18 | menu = ActiveAdmin::Menu.new
19 | menu.add "Dashboard", "/admin"
20 | menu.items.first.priority.should == 10
21 | end
22 | end
23 |
24 | context "with many item" do
25 | let(:menu) do
26 | ActiveAdmin::Menu.new do |m|
27 | m.add "Dashboard", "/admin"
28 | m.add "Blog", "/admin/blog"
29 | m.add "Users", "/admin/users"
30 | m.add "Settings", "/admin/settings" do |s|
31 | s.add "Admin Settings", "/admin/settings/admin" do |as|
32 | s.add "User Settings", "/admin/settings/users"
33 | end
34 | end
35 | end
36 | end
37 |
38 | it "should give access to the menu item as an array" do
39 | menu['Dashboard'].name.should == 'Dashboard'
40 | end
41 |
42 | it "should find the item by a url on the top level" do
43 | menu.find_by_url("/admin").name.should == "Dashboard"
44 | end
45 |
46 | it "should find the item deep in the tree" do
47 | menu.find_by_url("/admin/settings/users").name.should == "User Settings"
48 | end
49 |
50 | end
51 |
52 | end
53 |
54 |
--------------------------------------------------------------------------------
/lib/active_admin/resource_controller/filters.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | class ResourceController < ::InheritedResources::Base
3 |
4 | module Filters
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | helper_method :filters_config
9 | end
10 |
11 | module ClassMethods
12 | def filter(attribute, options = {})
13 | return false if attribute.nil?
14 | @filters ||= []
15 | @filters << options.merge(:attribute => attribute)
16 | end
17 |
18 | def filters_config
19 | @filters && @filters.any? ? @filters : default_filters_config
20 | end
21 |
22 | def reset_filters!
23 | @filters = []
24 | end
25 |
26 | # Returns a sane set of filters by default for the object
27 | def default_filters_config
28 | default_association_filters + default_content_filters
29 | end
30 |
31 | # Returns a default set of filters for the associations
32 | def default_association_filters
33 | if resource_class.respond_to?(:reflections)
34 | resource_class.reflections.collect{|name, r| { :attribute => name }}
35 | else
36 | []
37 | end
38 | end
39 |
40 | # Returns a default set of filters for the content columns
41 | def default_content_filters
42 | if resource_class.respond_to?(:content_columns)
43 | resource_class.content_columns.collect{|c| { :attribute => c.name.to_sym } }
44 | else
45 | []
46 | end
47 | end
48 | end
49 |
50 | protected
51 |
52 | def filters_config
53 | self.class.filters_config
54 | end
55 | end
56 |
57 | end
58 | end
59 |
--------------------------------------------------------------------------------
/spec/unit/arbre/html/tag_attributes_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Arbre::HTML::Tag, "Attributes" do
4 | include Arbre::HTML
5 | let(:assigns){ {} }
6 |
7 | let(:tag){ Arbre::HTML::Tag.new }
8 |
9 | describe "attributes" do
10 | before { tag.build :id => "my_id" }
11 |
12 | it "should have an attributes hash" do
13 | tag.attributes.should == {:id => "my_id"}
14 | end
15 |
16 | it "should render the attributes to html" do
17 | tag.to_html.should == <<-HTML
18 |
19 | HTML
20 | end
21 |
22 | it "should get an attribute value" do
23 | tag.attr(:id).should == "my_id"
24 | end
25 |
26 | describe "#has_attribute?" do
27 | context "when the attribute exists" do
28 | it "should return true" do
29 | tag.has_attribute?(:id).should == true
30 | end
31 | end
32 |
33 | context "when the attribute does not exist" do
34 | it "should return false" do
35 | tag.has_attribute?(:class).should == false
36 | end
37 | end
38 | end
39 |
40 | it "should remove an attribute" do
41 | tag.attributes.should == {:id => "my_id"}
42 | tag.remove_attribute(:id).should == "my_id"
43 | tag.attributes.should == {}
44 | end
45 | end
46 |
47 | describe "rendering attributes" do
48 | it "should html safe the attribute values" do
49 | tag.set_attribute(:class, "\">bad things!")
50 | tag.to_html.should == <<-HTML
51 |
52 | HTML
53 | end
54 | it "should should escape the attribute names" do
55 | tag.set_attribute(">bad", "things")
56 | tag.to_html.should == <<-HTML
57 |
58 | HTML
59 | end
60 | end
61 | end
62 |
--------------------------------------------------------------------------------
/features/sti_resource.feature:
--------------------------------------------------------------------------------
1 | Feature: STI Resource
2 |
3 | Ensure that standard CRUD works with STI models
4 |
5 | Background:
6 | Given I am logged in
7 | And a configuration of:
8 | """
9 | ActiveAdmin.register Publisher
10 | ActiveAdmin.register User
11 | """
12 |
13 | Scenario: Create, update and delete a child STI resource
14 | Given I am on the index page for publishers
15 | When I follow "New Publisher"
16 | And I fill in "First name" with "Terry"
17 | And I fill in "Last name" with "Fox"
18 | And I fill in "Username" with "terry_fox"
19 | And I press "Create Publisher"
20 | Then I should see "Publisher was successfully created"
21 | And I should see "Terry"
22 |
23 | When I follow "Edit Publisher"
24 | And I fill in "First name" with "Joe"
25 | And I press "Update Publisher"
26 | Then I should see "Publisher was successfully updated"
27 | And I should see "Joe"
28 |
29 | When I follow "Delete Publisher"
30 | Then I should see "Publisher was successfully destroyed"
31 |
32 | Scenario: Create, update and delete a parent STI resource
33 | Given I am on the index page for users
34 | When I follow "New User"
35 | And I fill in "First name" with "Terry"
36 | And I fill in "Last name" with "Fox"
37 | And I fill in "Username" with "terry_fox"
38 | And I press "Create User"
39 | Then I should see "User was successfully created"
40 | And I should see "Terry"
41 |
42 | When I follow "Edit User"
43 | And I fill in "First name" with "Joe"
44 | And I press "Update User"
45 | Then I should see "User was successfully updated"
46 | And I should see "Joe"
47 |
48 | When I follow "Delete User"
49 | Then I should see "User was successfully destroyed"
50 |
--------------------------------------------------------------------------------
/features/index/index_as_blog.feature:
--------------------------------------------------------------------------------
1 | Feature: Index as Blog
2 |
3 | Viewing resources as a blog on the index page
4 |
5 | Scenario: Viewing the blog with a resource
6 | Given a post with the title "Hello World" exists
7 | And an index configuration of:
8 | """
9 | ActiveAdmin.register Post do
10 | index :as => :blog
11 | end
12 | """
13 | And I am logged in
14 | When I am on the index page for posts
15 | Then I should see "Hello World" within "h3"
16 | And I should see a link to "Hello World"
17 |
18 | Scenario: Viewing the blog with a resource as a simple configuration
19 | Given a post with the title "Hello World" and body "My great post body" exists
20 | And an index configuration of:
21 | """
22 | ActiveAdmin.register Post do
23 | index :as => :blog do
24 | title :title
25 | body :body
26 | end
27 | end
28 | """
29 | Then I should see "Hello World" within "h3"
30 | And I should see a link to "Hello World"
31 | And I should see "My great post body" within ".post"
32 |
33 | Scenario: Viewing the blog with a resource as a block configuration
34 | Given a post with the title "Hello World" and body "My great post body" exists
35 | And an index configuration of:
36 | """
37 | ActiveAdmin.register Post do
38 | index :as => :blog do
39 | title do |post|
40 | post.title + " From Block"
41 | end
42 | body do |post|
43 | post.body + " From Block"
44 | end
45 | end
46 | end
47 | """
48 | Then I should see "Hello World From Block" within "h3"
49 | And I should see a link to "Hello World From Block"
50 | And I should see "My great post body From Block" within ".post"
51 |
--------------------------------------------------------------------------------
/lib/active_admin/views/components/attributes_table.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Views
3 |
4 | class AttributesTable < ActiveAdmin::Component
5 | builder_method :attributes_table_for
6 |
7 | attr_reader :resource
8 |
9 | def build(record, *attrs)
10 | @record = record
11 | super(:for => @record)
12 | @table = table
13 | rows(*attrs)
14 | end
15 |
16 | def rows(*attrs)
17 | attrs.each {|attr| row(attr) }
18 | end
19 |
20 | def row(attr, &block)
21 | @table << tr do
22 | th do
23 | header_content_for(attr)
24 | end
25 | td do
26 | content_for(block || attr)
27 | end
28 | end
29 | end
30 |
31 | protected
32 |
33 | def default_id_for_prefix
34 | 'attributes_table'
35 | end
36 |
37 | def header_content_for(attr)
38 | @record.class.respond_to?(:human_attribute_name) ? @record.class.human_attribute_name(attr).titleize : attr.to_s.titleize
39 | end
40 |
41 | def empty_value
42 | span I18n.t('active_admin.empty'), :class => "empty"
43 | end
44 |
45 | def content_for(attr_or_proc)
46 | value = case attr_or_proc
47 | when Proc
48 | attr_or_proc.call
49 | else
50 | content_for_attribute(attr_or_proc)
51 | end
52 | value = pretty_format(value)
53 | value == "" || value == nil ? empty_value : value
54 | end
55 |
56 | def content_for_attribute(attr)
57 | if attr.to_s =~ /^([\w]+)_id$/ && @record.respond_to?($1.to_sym)
58 | content_for_attribute($1)
59 | else
60 | @record.send(attr.to_sym)
61 | end
62 | end
63 | end
64 |
65 | end
66 | end
67 |
--------------------------------------------------------------------------------
/lib/active_admin/views/components/status_tag.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Views
3 | # Build a StatusTag
4 | class StatusTag < ActiveAdmin::Component
5 | builder_method :status_tag
6 |
7 | def tag_name
8 | 'span'
9 | end
10 |
11 | def default_class_name
12 | 'status'
13 | end
14 |
15 | # @method status_tag(status, type = nil, options = {})
16 | #
17 | # @param [String] status the status to display. One of the span classes will be an underscored version of the status.
18 | # @param [Symbol] type type of status. Will become a class of the span. ActiveAdmin provide style for :ok, :warning and :error.
19 | # @param [Hash] options such as :class, :id etc
20 | #
21 | # @return [ActiveAdmin::Views::StatusTag]
22 | #
23 | # Examples:
24 | # status_tag('In Progress')
25 | # # => In Progress
26 | #
27 | # status_tag('active', :ok)
28 | # # => Active
29 | #
30 | # status_tag('active', :ok, :class => 'important', :id => 'status_123')
31 | # # => Active
32 | #
33 | def build(*args)
34 | options = args.extract_options!
35 | status = args[0]
36 | type = args[1]
37 | classes = options.delete(:class)
38 |
39 | status = status.titleize if status
40 |
41 | super(status, options)
42 |
43 | add_class(status_to_class(status)) if status
44 | add_class(type.to_s) if type
45 | add_class(classes) if classes
46 | end
47 |
48 | protected
49 |
50 | def status_to_class(status)
51 | status.titleize.gsub(/\s/, '').underscore
52 | end
53 | end
54 | end
55 | end
56 |
--------------------------------------------------------------------------------
/lib/active_admin/arbre/html5_elements.rb:
--------------------------------------------------------------------------------
1 | module Arbre
2 | module HTML
3 |
4 | AUTO_BUILD_ELEMENTS = [ :a, :abbr, :address, :area, :article, :aside, :audio, :b, :base,
5 | :bdo, :blockquote, :body, :br, :button, :canvas, :caption, :cite,
6 | :code, :col, :colgroup, :command, :datalist, :dd, :del, :details,
7 | :dfn, :div, :dl, :dt, :em, :embed, :fieldset, :figcaption, :figure,
8 | :footer, :form, :h1, :h2, :h3, :h4, :h5, :h6, :head, :header, :hgroup,
9 | :hr, :html, :i, :iframe, :img, :input, :ins, :keygen, :kbd, :label,
10 | :legend, :li, :link, :map, :mark, :menu, :meta, :meter, :nav, :noscript,
11 | :object, :ol, :optgroup, :option, :output, :pre, :progress, :q,
12 | :s, :samp, :script, :section, :select, :small, :source, :span,
13 | :strong, :style, :sub, :summary, :sup, :table, :tbody, :td,
14 | :textarea, :tfoot, :th, :thead, :time, :title, :tr, :ul, :var, :video ]
15 |
16 | HTML5_ELEMENTS = [ :p ] + AUTO_BUILD_ELEMENTS
17 |
18 | AUTO_BUILD_ELEMENTS.each do |name|
19 | class_eval <<-EOF
20 | class #{name.to_s.capitalize} < Tag
21 | builder_method :#{name}
22 | end
23 | EOF
24 | end
25 |
26 | class P < Tag
27 | builder_method :para
28 | end
29 |
30 | class Table < Tag
31 | def initialize(*)
32 | super
33 | set_table_tag_defaults
34 | end
35 |
36 | protected
37 |
38 | # Set some good defaults for tables
39 | def set_table_tag_defaults
40 | set_attribute :border, 0
41 | set_attribute :cellspacing, 0
42 | set_attribute :cellpadding, 0
43 | end
44 | end
45 |
46 | end
47 | end
48 |
--------------------------------------------------------------------------------
/features/index/index_blank_slate.feature:
--------------------------------------------------------------------------------
1 | Feature: Index Blank Slate
2 |
3 | Viewing an index page with no resources yet
4 |
5 | Scenario: Viewing the default table with no resources
6 | Given an index configuration of:
7 | """
8 | ActiveAdmin.register Post
9 | """
10 | Then I should not see a sortable table header
11 | And I should see "There are no Posts yet. Create one"
12 | And I should not see pagination
13 | When I follow "Create one"
14 | Then I should be on the new post page
15 |
16 | Scenario: Viewing the default table with no resources and no 'new' action
17 | Given an index configuration of:
18 | """
19 | ActiveAdmin.register Post do
20 | actions :index, :show
21 | end
22 | """
23 | And I should see "There are no Posts yet."
24 | And I should not see "Create one"
25 |
26 | Scenario: Viewing a index using a grid with no resources
27 | Given an index configuration of:
28 | """
29 | ActiveAdmin.register Post do
30 | index :as => :grid do |post|
31 | h2 auto_link(post)
32 | end
33 | end
34 | """
35 | And I should see "There are no Posts yet. Create one"
36 |
37 | Scenario: Viewing a index using blocks with no resources
38 | Given an index configuration of:
39 | """
40 | ActiveAdmin.register Post do
41 | index :as => :block do |post|
42 | span(link_to(post.title, admin_post_path(post)))
43 | end
44 | end
45 | """
46 | And I should see "There are no Posts yet. Create one"
47 |
48 | Scenario: Viewing a blog with no resources
49 | Given an index configuration of:
50 | """
51 | ActiveAdmin.register Post do
52 | index :as => :blog
53 | end
54 | """
55 | And I should see "There are no Posts yet. Create one"
--------------------------------------------------------------------------------
/app/assets/javascripts/active_admin/base.js:
--------------------------------------------------------------------------------
1 | //= require "active_admin/vendor"
2 |
3 | /* Active Admin JS */
4 |
5 | $(function(){
6 | $(".datepicker").datepicker({dateFormat: 'yy-mm-dd'});
7 |
8 | $(".clear_filters_btn").click(function(){
9 | window.location.search = "";
10 | return false;
11 | });
12 |
13 | // AJAX Comments
14 | $('form#admin_note_new').submit(function() {
15 |
16 | if ($(this).find('#admin_note_body').val() != "") {
17 | $(this).fadeOut('slow', function() {
18 | $('.loading_indicator').fadeIn();
19 | $.ajax({
20 | url: $(this).attr('action'),
21 | type: 'POST',
22 | dataType: 'json',
23 | data: $(this).serialize(),
24 | success: function(data, textStatus, xhr) {
25 | $('.loading_indicator').fadeOut('slow', function(){
26 |
27 | // Hide the empty message
28 | $('.admin_notes_list li.empty').fadeOut().remove();
29 |
30 | // Add the note
31 | $('.admin_notes_list').append(data['note']);
32 |
33 | // Update the number of notes
34 | $('.admin_notes h3 span.admin_notes_count').html("(" + data['number_of_notes'] + ")");
35 |
36 | // Reset the form
37 | $('form#new_active_admin_admin_note').find('#active_admin_admin_note_body').val("");
38 |
39 | // Show the form
40 | $('form#new_active_admin_admin_note').fadeIn('slow');
41 | })
42 | },
43 | error: function(xhr, textStatus, errorThrown) {
44 | //called when there is an error
45 | }
46 | });
47 | });
48 |
49 | };
50 |
51 | return false;
52 | });
53 | });
54 |
--------------------------------------------------------------------------------
/spec/support/rails_template.rb:
--------------------------------------------------------------------------------
1 | # Rails template to build the sample app for specs
2 |
3 | # Create a cucumber database and environment
4 | copy_file File.expand_path('../templates/cucumber.rb', __FILE__), "config/environments/cucumber.rb"
5 | gsub_file 'config/database.yml', /^test:.*\n/, "test: &test\n"
6 | gsub_file 'config/database.yml', /\z/, "\ncucumber:\n <<: *test\n database: db/cucumber.sqlite3"
7 |
8 | # Generate some test models
9 | generate :model, "post title:string body:text published_at:datetime author_id:integer category_id:integer"
10 | inject_into_file 'app/models/post.rb', " belongs_to :author, :class_name => 'User'\n belongs_to :category\n accepts_nested_attributes_for :author\n", :after => "class Post < ActiveRecord::Base\n"
11 | generate :model, "user type:string first_name:string last_name:string username:string"
12 | inject_into_file 'app/models/user.rb', " has_many :posts, :foreign_key => 'author_id'\n", :after => "class User < ActiveRecord::Base\n"
13 | generate :model, "publisher --migration=false --parent=User"
14 | generate :model, 'category name:string description:text'
15 | inject_into_file 'app/models/category.rb', " has_many :posts\n", :after => "class Category < ActiveRecord::Base\n"
16 |
17 | # Add our local Active Admin to the load path
18 | inject_into_file "config/environment.rb", "\n$LOAD_PATH.unshift('#{File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib'))}')\nrequire \"active_admin\"\n", :after => "require File.expand_path('../application', __FILE__)"
19 |
20 | run "rm Gemfile"
21 | run "rm -r test"
22 | run "rm -r spec"
23 |
24 | $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
25 | generate :'active_admin:install'
26 |
27 | # Setup a root path for devise
28 | route "root :to => 'admin/dashboard#index'"
29 |
30 | rake "db:migrate"
31 | rake "db:test:prepare"
32 | run "/usr/bin/env RAILS_ENV=cucumber rake db:migrate"
33 |
--------------------------------------------------------------------------------
/lib/active_admin/views/pages/dashboard.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Views
3 | module Pages
4 | class Dashboard < Base
5 |
6 | def main_content
7 | if assigns[:dashboard_sections] && assigns[:dashboard_sections].any?
8 | render_sections(assigns[:dashboard_sections])
9 | else
10 | default_welcome_section
11 | end
12 | end
13 |
14 | protected
15 |
16 | # Dashboards don't have a sidebar
17 | def build_sidebar; end
18 |
19 | def title
20 | "Dashboard"
21 | end
22 |
23 | def render_sections(sections)
24 | table :class => "dashboard" do
25 | sections.in_groups_of(3, false).each do |row|
26 | tr do
27 | row.each do |section|
28 | td do
29 | render_section(section)
30 | end
31 | end
32 | end
33 | end
34 | end
35 | end
36 |
37 | # Renders each section using their renderer
38 | def render_section(section)
39 | insert_tag section_renderer(section), section
40 | end
41 |
42 | def section_renderer(section)
43 | if section.options[:as]
44 | view_factory["dashboard_section_as_#{section.options[:as]}"]
45 | else
46 | view_factory.dashboard_section
47 | end
48 | end
49 |
50 | def default_welcome_section
51 | div :class => "blank_slate_container", :id => "dashboard_default_message" do
52 | span :class => "blank_slate" do
53 | span I18n.t('active_admin.dashboard_welcome.welcome')
54 | small I18n.t('active_admin.dashboard_welcome.call_to_action')
55 | end
56 | end
57 | end
58 |
59 | end
60 | end
61 | end
62 | end
63 |
--------------------------------------------------------------------------------
/spec/unit/arbre/html/tag_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Arbre::HTML::Tag do
4 | include Arbre::HTML
5 | let(:assigns){ {} }
6 |
7 | let(:tag){ Arbre::HTML::Tag.new }
8 |
9 | describe "building a new tag" do
10 | before { tag.build "Hello World", :id => "my_id" }
11 |
12 | it "should set the contents to a string" do
13 | tag.content.should == "Hello World"
14 | end
15 |
16 | it "should set the hash of options to the attributes" do
17 | tag.attributes.should == { :id => "my_id" }
18 | end
19 | end
20 |
21 | describe "creating a tag 'for' an object" do
22 | let(:model_name){ mock(:singular => "resource_class")}
23 | let(:resource_class){ mock(:model_name => model_name) }
24 | let(:resource){ mock(:class => resource_class, :to_key => ['5'])}
25 |
26 | before do
27 | tag.build :for => resource
28 | end
29 | it "should set the id to the type and id" do
30 | tag.id.should == "resource_class_5"
31 | end
32 | it "should add a class name" do
33 | tag.class_list.should include("resource_class")
34 | end
35 | end
36 |
37 | describe "css class names" do
38 | it "should add a class" do
39 | tag.add_class "hello_world"
40 | tag.class_names.should == "hello_world"
41 | end
42 |
43 | it "should remove_class" do
44 | tag.add_class "hello_world"
45 | tag.class_names.should == "hello_world"
46 | tag.remove_class "hello_world"
47 | tag.class_names.should == ""
48 | end
49 |
50 | it "should not add a class if it already exists" do
51 | tag.add_class "hello_world"
52 | tag.add_class "hello_world"
53 | tag.class_names.should == "hello_world"
54 | end
55 |
56 | it "should seperate classes with space" do
57 | tag.add_class "hello world"
58 | tag.class_list.size.should == 2
59 | end
60 | end
61 |
62 |
63 | end
64 |
--------------------------------------------------------------------------------
/spec/unit/dashboards_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe ActiveAdmin::Dashboards do
4 |
5 | after(:each) do
6 | ActiveAdmin::Dashboards.clear_all_sections!
7 | end
8 |
9 | describe "adding sections" do
10 | before do
11 | ActiveAdmin::Dashboards.clear_all_sections!
12 | ActiveAdmin::Dashboards.add_section('Recent Posts')
13 | end
14 | it "should add a new section namespaced" do
15 | ActiveAdmin::Dashboards.sections[:admin].first.should be_an_instance_of(ActiveAdmin::Dashboards::Section)
16 | end
17 | end
18 |
19 | describe "adding sections using the build syntax" do
20 | before do
21 | ActiveAdmin::Dashboards.clear_all_sections!
22 | ActiveAdmin::Dashboards.build do
23 | section "Recent Posts" do
24 | end
25 | end
26 | end
27 |
28 | it "should add a new section" do
29 | ActiveAdmin::Dashboards.sections[:admin].first.should be_an_instance_of(ActiveAdmin::Dashboards::Section)
30 | end
31 | end
32 |
33 | describe "clearing all sections" do
34 | before do
35 | ActiveAdmin::Dashboards.add_section('Recent Posts')
36 | end
37 | it "should clear all sections" do
38 | ActiveAdmin::Dashboards.clear_all_sections!
39 | ActiveAdmin::Dashboards.sections.keys.should be_empty
40 | end
41 | end
42 |
43 | describe "finding namespaced sections" do
44 | context "when the namespace exists" do
45 | before do
46 | ActiveAdmin::Dashboards.add_section('Recent Posts')
47 | end
48 | it "should return an array of sections" do
49 | ActiveAdmin::Dashboards.sections_for_namespace(:admin).should_not be_empty
50 | end
51 | end
52 |
53 | context "when the namespace does not exists" do
54 | it "should return an empty array" do
55 | ActiveAdmin::Dashboards.sections_for_namespace(:not_a_namespace).should be_empty
56 | end
57 | end
58 | end
59 | end
60 |
--------------------------------------------------------------------------------
/lib/active_admin/views/tabs_renderer.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Views
3 |
4 | # Renders out a horizontal list of tabs.
5 | class TabsRenderer < Renderer
6 |
7 | # Pass in an ActiveAdmin::Menu and it will display the first level
8 | # of navigation as a horizontal list of tabs
9 | def to_html(menu, options = {})
10 | @options = default_options.merge(options)
11 | render_menu(menu)
12 | end
13 |
14 | protected
15 |
16 | def render_menu(menu)
17 | content_tag :ul, :id => @options[:id] do
18 | menu.items.collect do |item|
19 | render_item(item)
20 | end.join.html_safe
21 | end
22 | end
23 |
24 | def render_item(item)
25 | if !call_method_or_proc_on(self, item.display_if_block)
26 | return
27 | elsif (!item.url or item.url == '#') and item.children.any? and (item.children.detect {|child| call_method_or_proc_on(self, child.display_if_block)}).nil?
28 | return
29 | end
30 |
31 | content_tag :li, :id => item.dom_id, :class => [("current" if current?(item)), ("has_nested" unless item.children.blank?)].compact.join(" ") do
32 | unless item.children.blank?
33 | link_to(item.name, item.url || "#") + render_nested_menu(item)
34 | else
35 | link_to item.name, item.url
36 | end
37 | end
38 | end
39 |
40 | def render_nested_menu(item)
41 | content_tag :ul do
42 | item.children.collect {|child| render_item(child)}.join.html_safe
43 | end
44 | end
45 |
46 | # Returns true if the menu item name is @current_tab
47 | def current?(menu_item)
48 | @current_tab.split("/").include?(menu_item.name) unless @current_tab.blank?
49 | end
50 |
51 | def default_options
52 | { :id => "tabs" }
53 | end
54 |
55 | end
56 |
57 | end
58 | end
59 |
--------------------------------------------------------------------------------
/spec/unit/resource/naming_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | module ActiveAdmin
4 | describe Resource, "Naming" do
5 |
6 | before { load_defaults! }
7 |
8 | let(:application){ ActiveAdmin::Application.new }
9 | let(:namespace){ Namespace.new(application, :admin) }
10 |
11 | def config(options = {})
12 | @config ||= Resource.new(namespace, Category, options)
13 | end
14 |
15 |
16 | describe "underscored resource name" do
17 | context "when class" do
18 | it "should be the underscored singular resource name" do
19 | config.underscored_resource_name.should == "category"
20 | end
21 | end
22 | context "when a class in a module" do
23 | it "should underscore the module and the class" do
24 | module ::Mock; class Resource; end; end
25 | Resource.new(namespace, Mock::Resource).underscored_resource_name.should == "mock_resource"
26 | end
27 | end
28 | context "when you pass the 'as' option" do
29 | it "should underscore the passed through string and singulralize" do
30 | config(:as => "Blog Categories").underscored_resource_name.should == "blog_category"
31 | end
32 | end
33 | end
34 |
35 | describe "camelized resource name" do
36 | it "should return a camelized version of the underscored resource name" do
37 | config(:as => "Blog Categories").camelized_resource_name.should == "BlogCategory"
38 | end
39 | end
40 |
41 | describe "resource name" do
42 | it "should return a pretty name" do
43 | config.resource_name.should == "Category"
44 | end
45 | it "should return the plural version" do
46 | config.plural_resource_name.should == "Categories"
47 | end
48 | context "when the :as option is given" do
49 | it "should return the custom name" do
50 | config(:as => "My Category").resource_name.should == "My Category"
51 | end
52 | end
53 | end
54 |
55 | end
56 | end
57 |
--------------------------------------------------------------------------------
/features/specifying_actions.feature:
--------------------------------------------------------------------------------
1 | Feature: Specifying Actions
2 |
3 | Specifying which actions to allow on my resource
4 |
5 | Scenario: Only creating the index action
6 | Given a configuration of:
7 | """
8 | ActiveAdmin.register Post do
9 | actions :index
10 | end
11 | """
12 | And I am logged in
13 | And a post with the title "Hello World" exists
14 | When I am on the index page for posts
15 | Then an "AbstractController::ActionNotFound" exception should be raised when I follow "View"
16 |
17 | Scenario: Specify a custom collection action with template
18 | Given a configuration of:
19 | """
20 | ActiveAdmin.register Post do
21 | action_item(:only => :index) do
22 | link_to('Import Posts', import_admin_posts_path)
23 | end
24 |
25 | collection_action :import
26 | end
27 | """
28 | Given "app/views/admin/posts/import.html.erb" contains:
29 | """
30 | We are currently working on this feature...
31 | """
32 | And I am logged in
33 | When I am on the index page for posts
34 | And I follow "Import"
35 | Then I should see "We are currently working on this feature"
36 |
37 | Scenario: Specify a custom member action with template
38 | Given a configuration of:
39 | """
40 | ActiveAdmin.register Post do
41 | action_item(:only => :show) do
42 | link_to('Review', review_admin_post_path)
43 | end
44 |
45 | member_action :review do
46 | @post = Post.find(params[:id])
47 | end
48 | end
49 | """
50 | Given "app/views/admin/posts/review.html.erb" contains:
51 | """
52 | Review: <%= @post.title %>
53 | """
54 | And I am logged in
55 | And a post with the title "Hello World" exists
56 | When I am on the index page for posts
57 | And I follow "View"
58 | And I follow "Review"
59 | Then I should see "Review: Hello World"
60 |
--------------------------------------------------------------------------------
/features/index/index_scopes.feature:
--------------------------------------------------------------------------------
1 | Feature: Index Scoping
2 |
3 | Viewing resources and scoping them
4 |
5 | Scenario: Viewing resources with one scope and no default
6 | Given 10 posts exist
7 | And an index configuration of:
8 | """
9 | ActiveAdmin.register Post do
10 | scope :all
11 | end
12 | """
13 | Then I should see the scope "All" not selected
14 | And I should see the scope "All" with the count 10
15 | And I should see 10 posts in the table
16 |
17 | Scenario: Viewing resources with one scope as the default
18 | Given 10 posts exist
19 | And an index configuration of:
20 | """
21 | ActiveAdmin.register Post do
22 | scope :all, :default => true
23 | end
24 | """
25 | Then I should see the scope "All" selected
26 | And I should see the scope "All" with the count 10
27 | And I should see 10 posts in the table
28 |
29 | Scenario: Viewing resources with mulitple scopes as blocks
30 | Given 10 posts exist
31 | And an index configuration of:
32 | """
33 | ActiveAdmin.register Post do
34 | scope 'Today', :default => true do |posts|
35 | posts.where(["created_at > ? AND created_at < ?", ::Time.zone.now.beginning_of_day, ::Time.zone.now.end_of_day])
36 | end
37 | scope 'Tomorrow' do |posts|
38 | posts.where(["created_at > ? AND created_at < ?", ::Time.zone.now.beginning_of_day + 1.day, ::Time.zone.now.end_of_day + 1.day])
39 | end
40 | end
41 | """
42 | Then I should see the scope "Today" selected
43 | And I should see the scope "Tomorrow" not selected
44 | And I should see the scope "Today" with the count 10
45 | And I should see the scope "Tomorrow" with the count 0
46 | And I should see 10 posts in the table
47 | And I should see a link to "Tomorrow"
48 |
49 | When I follow "Tomorrow"
50 | Then I should see the scope "Tomorrow" selected
51 | And I should see the scope "Today" not selected
52 | And I should see a link to "Today"
53 |
--------------------------------------------------------------------------------
/lib/active_admin/views/components/scopes.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Views
3 |
4 | # Renders a collection of ActiveAdmin::Scope objects as a
5 | # simple list with a seperator
6 | class Scopes < ActiveAdmin::Component
7 | builder_method :scopes_renderer
8 |
9 | def build(scopes)
10 | scopes.each do |scope|
11 | build_scope(scope)
12 | end
13 | end
14 |
15 | protected
16 |
17 | def build_scope(scope)
18 | span :class => classes_for_scope(scope) do
19 | begin
20 | scope_name = I18n.t!("active_admin.scopes.#{scope.scope_method}")
21 | rescue I18n::MissingTranslationData
22 | scope_name = scope.name
23 | end
24 |
25 | if current_scope?(scope)
26 | em(scope_name)
27 | else
28 | a(scope_name, :href => url_for(params.merge(:scope => scope.id, :page => 1)))
29 | end
30 | text_node(" ")
31 | scope_count(scope)
32 | text_node(" ")
33 | end
34 | end
35 |
36 | def classes_for_scope(scope)
37 | classes = ["scope", scope.id]
38 | classes << "selected" if current_scope?(scope)
39 | classes.join(" ")
40 | end
41 |
42 | def current_scope?(scope)
43 | if params[:scope]
44 | params[:scope] == scope.id
45 | else
46 | active_admin_config.default_scope == scope
47 | end
48 | end
49 |
50 | def scope_count(scope)
51 | span :class => 'count' do
52 | "(" + get_scope_count(scope).to_s + ")"
53 | end
54 | end
55 |
56 | def get_scope_count(scope)
57 | if scope.scope_method
58 | scoping_class.send(scope.scope_method).count
59 | else
60 | instance_exec(scoping_class, &scope.scope_block).count
61 | end
62 | end
63 |
64 | def scoping_class
65 | assigns["before_scope_collection"] || active_admin_config.resource
66 | end
67 |
68 | end
69 | end
70 | end
71 |
--------------------------------------------------------------------------------
/lib/generators/active_admin/devise/devise_generator.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Generators
3 | class DeviseGenerator < Rails::Generators::NamedBase
4 | desc "Creates an admin user and uses Devise for authentication"
5 |
6 | argument :name, :type => :string, :default => "AdminUser"
7 |
8 | class_option :registerable, :type => :boolean, :default => false,
9 | :desc => "Should the generated resource be registerable?"
10 |
11 | def install_devise
12 | require 'devise'
13 | if File.exists?(File.join(destination_root, "config", "initializers", "devise.rb"))
14 | log :generate, "No need to install devise, already done."
15 | else
16 | log :generate, "devise:install"
17 | invoke "devise:install"
18 | end
19 | end
20 |
21 | def create_admin_user
22 | invoke "devise", [name]
23 | end
24 |
25 | def remove_registerable_from_model
26 | unless options[:registerable]
27 | model_file = File.join(destination_root, "app", "models", "#{file_path}.rb")
28 | gsub_file model_file, /\:registerable([.]*,)?/, ""
29 | end
30 | end
31 |
32 | def set_namespace_for_path
33 | routes_file = File.join(destination_root, "config", "routes.rb")
34 | gsub_file routes_file, /devise_for :#{table_name}/, "devise_for :#{table_name}, ActiveAdmin::Devise.config"
35 | end
36 |
37 | def add_default_user_to_migration
38 | # Don't assume that we have a migration!
39 | devise_migrations = Dir["db/migrate/*_devise_create_#{table_name}.rb"]
40 | if devise_migrations.size > 0
41 | inject_into_file Dir["db/migrate/*_devise_create_#{table_name}.rb"].first,
42 | "# Create a default user\n #{class_name}.create!(:email => 'admin@example.com', :password => 'password', :password_confirmation => 'password')\n\n ",
43 | :before => "add_index :#{table_name}, :email"
44 | end
45 | end
46 |
47 | end
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/spec/unit/comments_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe "Comments" do
4 | let(:application){ ActiveAdmin::Application.new }
5 |
6 | describe "Configuration" do
7 | it "should have an array of namespaces which allow comments" do
8 | application.allow_comments_in.should be_an_instance_of(Array)
9 | end
10 |
11 | it "should allow comments in the default namespace by default" do
12 | application.allow_comments_in.should include(application.default_namespace)
13 | end
14 | end
15 |
16 | describe ActiveAdmin::Comment do
17 | describe "Associations and Validations" do
18 | it { should belong_to :resource }
19 | it { should belong_to :author }
20 |
21 | it { should validate_presence_of :resource_id }
22 | it { should validate_presence_of :resource_type }
23 | it { should validate_presence_of :body }
24 | it { should validate_presence_of :namespace }
25 | end
26 | end
27 |
28 | describe ActiveAdmin::Comments::NamespaceHelper do
29 | describe "#comments?" do
30 | it "should have comments if the namespace is in the settings" do
31 | ns = ActiveAdmin::Namespace.new(application, :admin)
32 | ns.comments?.should be_true
33 | end
34 | it "should not have comments if the namespace is not in the settings" do
35 | ns = ActiveAdmin::Namespace.new(application, :not_in_comments)
36 | ns.comments?.should be_false
37 | end
38 | end
39 | end
40 |
41 | describe ActiveAdmin::Comments::ResourceHelper do
42 | it "should add an attr_accessor :comments to ActiveAdmin::Resource" do
43 | ns = ActiveAdmin::Namespace.new(application, :admin)
44 | resource = ActiveAdmin::Resource.new(ns, Post)
45 | resource.comments.should be_nil
46 | resource.comments = true
47 | resource.comments.should be_true
48 | end
49 |
50 | it "should not have comment if set to false by in allow_comments_in" do
51 | ns = ActiveAdmin::Namespace.new(application, application.default_namespace)
52 | resource = ActiveAdmin::Resource.new(ns, Post)
53 | resource.comments = false
54 | resource.comments?.should be_false
55 | end
56 | end
57 | end
58 |
--------------------------------------------------------------------------------
/CHANGELOG.rdoc:
--------------------------------------------------------------------------------
1 | == 0.2.2 (2011-05-26)
2 |
3 | 68 Commits by 13 Contributors
4 |
5 | === Features & Enhancements
6 |
7 | * Arbre includes self closing tags (#100)
8 | * Controller class & action added to body as CSS classes (#99)
9 | * HAML is not required by default (#92)
10 | * Devise login now respects Devise.authentication_keys (#69)
11 | * Active Admin no longer uses ActiveRecord::Base#search (#28)
12 | * Resource's can now override the label in the menu (#48)
13 | * Subdirectories are now loaded in the Active Admin load path
14 |
15 | === Bug Fixes
16 |
17 | * Sort order now includes table name (#38)
18 | * Fixed table_for 'odd', 'even' row classes (#96)
19 | * Fixed Devise installation if AdminUser already exists (#95)
20 | * Fixed issues when ActiveAdmin.default_namespaces is false (#32)
21 | * Added styles for missing HTML 5 inputs (#31)
22 | * Fixed issue if adding empty Active Admin Comment (#21)
23 | * Fixed layout issues in FF 4 (#22)
24 | * Use Sass::Plugin.options[:css_location] instead of Rails.root (#55)
25 |
26 | === Test Suite
27 |
28 | * Update RSpec to latest & fix specs (Thanks Ben Marini & Jeremt Ruppel!) (#100)
29 | * Added tests for STI models (#52)
30 |
31 | === Contributors
32 |
33 | * Ben Marini
34 | * Bookis Smuin
35 | * Caley Woods
36 | * Doug Puchalski
37 | * Federico Romero
38 | * Greg Bell
39 | * Ian MacLeod
40 | * Jeremy Ruppel
41 | * Jordan Sitkin
42 | * Juha Suuraho
43 | * Mathieu Martin
44 | * Paul Annesley
45 | * Philippe Creux
46 |
47 | == 0.2.1 (2011-05-12)
48 |
49 | === Bug Fixes
50 | * Fixed issue with dashboard rendering a sidebar
51 |
52 | == 0.2.0 (2011-05-12)
53 |
54 | 0.2.0 is essentially an entire re-write of Active Admin. Here are some
55 | of the highlights. 250 commits. Enough said.
56 |
57 | === Features & Enhancements
58 |
59 | * Full visual redesign
60 | * Integrated Devise for authentication
61 | * Brand new view and component layer called Arbre (Project coming soon)
62 | * Added ActiveAdmin::Comments
63 |
64 | === Bug Fixes
65 |
66 | * Too many to list! Been in production for close to a year
67 |
68 | == 0.1.1 (2010-09-15)
69 |
70 | === Bug Fixes
71 |
72 | * Fixed issues running on Ruby 1.9.2
73 |
74 | == 0.1.0
75 |
76 | * Initial release
77 |
--------------------------------------------------------------------------------
/spec/unit/components/columns_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe ActiveAdmin::Views::Columns do
4 | include Arbre::HTML
5 | let(:assigns){ {} }
6 |
7 | describe "Rendering one column" do
8 | let(:cols) do
9 | columns do
10 | column { span "Hello World" }
11 | end
12 | end
13 |
14 | it "should have the class .columns" do
15 | cols.class_list.should include("columns")
16 | end
17 |
18 | it "should have one column" do
19 | cols.children.size.should == 1
20 | cols.children.first.class_list.should include("column")
21 | end
22 |
23 | it "should have one column with the width 100%" do
24 | cols.children.first.attr(:style).should include("width: 100%")
25 | end
26 | end
27 |
28 | describe "Rendering two columns" do
29 | let(:cols) do
30 | columns do
31 | column { span "Hello World" }
32 | column { span "Hello World" }
33 | end
34 | end
35 |
36 | it "should have two columns" do
37 | cols.children.size.should == 2
38 | end
39 |
40 | it "should have a first column with width 49% and margin 2%" do
41 | cols.children.first.attr(:style).should == "width: 49%; margin-right: 2%;"
42 | end
43 |
44 | it "should have a second column with width 49% and no right margin" do
45 | cols.children.last.attr(:style).should == "width: 49%;"
46 | end
47 | end
48 |
49 | describe "Rendering four columns" do
50 | let(:cols) do
51 | columns do
52 | column { span "Hello World" }
53 | column { span "Hello World" }
54 | column { span "Hello World" }
55 | column { span "Hello World" }
56 | end
57 | end
58 |
59 | it "should have four columns" do
60 | cols.children.size.should == 4
61 | end
62 |
63 |
64 | (0..2).to_a.each do |index|
65 | it "should have column #{index + 1} with width 49% and margin 2%" do
66 | cols.children[index].attr(:style).should == "width: 23.5%; margin-right: 2%;"
67 | end
68 | end
69 |
70 | it "should have column 4 with width 49% and no margin" do
71 | cols.children[3].attr(:style).should == "width: 23.5%;"
72 | end
73 | end
74 |
75 | end
76 |
--------------------------------------------------------------------------------
/lib/active_admin/menu_item.rb:
--------------------------------------------------------------------------------
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 | # Returns the display if block. If the block was not explicitly defined
67 | # a default block always returning true will be returned.
68 | def display_if_block
69 | @display_if_block || lambda { |_| true }
70 | end
71 |
72 | end
73 | end
74 |
--------------------------------------------------------------------------------
/spec/unit/csv_builder_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe ActiveAdmin::CSVBuilder do
4 |
5 | describe '.default_for_resource using Post' do
6 | let(:csv_builder) { ActiveAdmin::CSVBuilder.default_for_resource(Post) }
7 |
8 | it "should return a default csv_builder for Post" do
9 | csv_builder.should be_a(ActiveAdmin::CSVBuilder)
10 | end
11 |
12 | specify "the first column should be Id" do
13 | csv_builder.columns.first.name.should == 'Id'
14 | csv_builder.columns.first.data.should == :id
15 | end
16 |
17 | specify "the following columns should be content_column" do
18 | csv_builder.columns[1..-1].each_with_index do |column, index|
19 | column.name.should == Post.content_columns[index].name.titleize
20 | column.data.should == Post.content_columns[index].name.to_sym
21 | end
22 | end
23 | end
24 |
25 | context 'when empty' do
26 | let(:builder){ ActiveAdmin::CSVBuilder.new }
27 |
28 | it "should have no columns" do
29 | builder.columns.should == []
30 | end
31 | end
32 |
33 | context "with a symbol column (:title)" do
34 | let(:builder) do
35 | ActiveAdmin::CSVBuilder.new do
36 | column :title
37 | end
38 | end
39 |
40 | it "should have one colum" do
41 | builder.columns.size.should == 1
42 | end
43 |
44 | describe "the column" do
45 | let(:column){ builder.columns.first }
46 |
47 | it "should have a name of 'Title'" do
48 | column.name.should == "Title"
49 | end
50 |
51 | it "should have the data :title" do
52 | column.data.should == :title
53 | end
54 | end
55 | end
56 |
57 | context "with a block and title" do
58 | let(:builder) do
59 | ActiveAdmin::CSVBuilder.new do
60 | column "My title" do
61 | # nothing
62 | end
63 | end
64 | end
65 |
66 | it "should have one colum" do
67 | builder.columns.size.should == 1
68 | end
69 |
70 | describe "the column" do
71 | let(:column){ builder.columns.first }
72 |
73 | it "should have a name of 'My title'" do
74 | column.name.should == "My title"
75 | end
76 |
77 | it "should have the data :title" do
78 | column.data.should be_an_instance_of(Proc)
79 | end
80 | end
81 | end
82 |
83 | end
84 |
--------------------------------------------------------------------------------
/lib/active_admin/views/index_as_blog.rb:
--------------------------------------------------------------------------------
1 | module ActiveAdmin
2 | module Views
3 | class IndexAsBlog < ActiveAdmin::Component
4 |
5 | def build(page_config, collection)
6 | @page_config = page_config
7 | @collection = collection
8 |
9 | # Call the block passed in. This will set the
10 | # title and body methods
11 | instance_eval &page_config.block if page_config.block
12 |
13 | build_posts
14 | end
15 |
16 | # Setter method for the configuration of the title
17 | #
18 | # index :as => :blog do
19 | # title :a_method_to_call #=> Calls #a_method_to_call on the resource
20 | #
21 | # # OR
22 | #
23 | # title do |post|
24 | # post.a_method_to_call
25 | # end
26 | # end
27 | def title(method = nil, &block)
28 | if block_given? || method
29 | @title = block_given? ? block : method
30 | end
31 | @title
32 | end
33 |
34 | # Setter method for the configuration of the body
35 | #
36 | # index :as => :blog do
37 | # title :my_title
38 | #
39 | # body :a_method_to_call #=> Calls #a_method_to_call on the resource
40 | #
41 | # # OR
42 | #
43 | # title do |post|
44 | # post.a_method_to_call
45 | # end
46 | # end
47 | def body(method = nil, &block)
48 | if block_given? || method
49 | @body = block_given? ? block : method
50 | end
51 | @body
52 | end
53 |
54 | private
55 |
56 | def build_posts
57 | @collection.each do |post|
58 | build_post(post)
59 | end
60 | end
61 |
62 | def build_post(post)
63 | div :for => post do
64 | build_title(post)
65 | build_body(post)
66 | end
67 | end
68 |
69 | def build_title(post)
70 | if @title
71 | h3 do
72 | link_to(call_method_or_proc_on(post, @title), resource_path(post))
73 | end
74 | else
75 | h3 do
76 | auto_link(post)
77 | end
78 | end
79 | end
80 |
81 | def build_body(post)
82 | if @body
83 | div(call_method_or_proc_on(post, @body), :class => 'content')
84 | end
85 | end
86 |
87 | end # Posts
88 | end
89 | end
90 |
--------------------------------------------------------------------------------