├── docs ├── .gitignore ├── CNAME ├── _config.yml ├── images │ ├── divider.png │ ├── features.png │ ├── activeadmin.png │ ├── code-header.png │ └── tidelift.svg ├── Gemfile ├── _includes │ ├── footer.html │ ├── head.html │ ├── google-analytics.html │ └── top-menu.html ├── 3-index-pages │ ├── index-as-block.md │ ├── index-as-grid.md │ └── custom-index.md ├── _layouts │ └── default.html └── README.md ├── .rspec ├── .mdlrc ├── lib ├── active_admin │ ├── orm │ │ ├── mongoid │ │ │ └── .gitkeep │ │ ├── mongoid.rb │ │ ├── active_record │ │ │ └── comments │ │ │ │ ├── views.rb │ │ │ │ ├── namespace_helper.rb │ │ │ │ ├── resource_helper.rb │ │ │ │ ├── show_page_helper.rb │ │ │ │ └── comment.rb │ │ └── active_record.rb │ ├── version.rb │ ├── component.rb │ ├── helpers │ │ ├── i18n.rb │ │ ├── routes │ │ │ └── url_helpers.rb │ │ ├── collection.rb │ │ ├── scope_chain.rb │ │ └── optional_display.rb │ ├── views.rb │ ├── resource │ │ ├── ordering.rb │ │ ├── includes.rb │ │ ├── controllers.rb │ │ ├── pagination.rb │ │ └── sidebars.rb │ ├── view_helpers │ │ ├── title_helper.rb │ │ ├── view_factory_helper.rb │ │ ├── sidebar_helper.rb │ │ ├── active_admin_application_helper.rb │ │ ├── scope_name_helper.rb │ │ ├── flash_helper.rb │ │ └── form_helper.rb │ ├── deprecation.rb │ ├── controller_action.rb │ ├── views │ │ ├── tabbed_navigation.rb │ │ ├── components │ │ │ ├── sidebar.rb │ │ │ ├── blank_slate.rb │ │ │ ├── unsupported_browser.rb │ │ │ ├── sidebar_section.rb │ │ │ ├── menu.rb │ │ │ ├── panel.rb │ │ │ ├── tabs.rb │ │ │ └── site_title.rb │ │ ├── action_items.rb │ │ ├── header.rb │ │ ├── footer.rb │ │ ├── pages │ │ │ ├── page.rb │ │ │ └── layout.rb │ │ └── index_as_block.rb │ ├── localizers.rb │ ├── inputs │ │ ├── filters │ │ │ ├── numeric_input.rb │ │ │ ├── date_picker_input.rb │ │ │ ├── text_input.rb │ │ │ ├── boolean_input.rb │ │ │ ├── string_input.rb │ │ │ └── base.rb │ │ └── datepicker_input.rb │ ├── resource_controller │ │ ├── sidebars.rb │ │ ├── resource_class_methods.rb │ │ ├── action_builder.rb │ │ └── scoping.rb │ ├── settings_node.rb │ ├── inputs.rb │ ├── filters.rb │ ├── view_helpers.rb │ ├── filters │ │ ├── dsl.rb │ │ └── active.rb │ ├── page_controller.rb │ ├── batch_actions.rb │ ├── engine.rb │ ├── dynamic_settings_node.rb │ ├── page_presenter.rb │ ├── page_dsl.rb │ ├── cancan_adapter.rb │ ├── sidebar_section.rb │ ├── asset_registration.rb │ ├── reloader.rb │ ├── dynamic_setting.rb │ ├── base_controller │ │ └── menu.rb │ ├── generators │ │ └── boilerplate.rb │ ├── localizers │ │ └── resource_localizer.rb │ ├── abstract_view_factory.rb │ ├── batch_actions │ │ └── views │ │ │ └── batch_action_form.rb │ ├── order_clause.rb │ └── view_factory.rb ├── activeadmin.rb ├── generators │ └── active_admin │ │ ├── assets │ │ ├── templates │ │ │ ├── active_admin.js │ │ │ └── active_admin.scss │ │ └── assets_generator.rb │ │ ├── page │ │ ├── templates │ │ │ └── page.rb │ │ ├── USAGE │ │ └── page_generator.rb │ │ ├── install │ │ └── templates │ │ │ ├── migrations │ │ │ └── create_active_admin_comments.rb.erb │ │ │ ├── admin_users.rb.erb │ │ │ └── dashboard.rb │ │ └── resource │ │ └── resource_generator.rb └── ransack_ext.rb ├── app ├── views │ ├── active_admin │ │ ├── resource │ │ │ ├── new.html.arb │ │ │ ├── edit.html.arb │ │ │ ├── index.html.arb │ │ │ └── show.html.arb │ │ ├── page │ │ │ └── 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 │ │ │ ├── confirmations │ │ │ └── new.html.erb │ │ │ ├── sessions │ │ │ └── new.html.erb │ │ │ └── registrations │ │ │ └── new.html.erb │ ├── layouts │ │ ├── active_admin.html.arb │ │ └── active_admin_logged_out.html.erb │ └── kaminari │ │ └── active_admin │ │ ├── _gap.html.erb │ │ ├── _last_page.html.erb │ │ ├── _first_page.html.erb │ │ ├── _next_page.html.erb │ │ ├── _prev_page.html.erb │ │ ├── _page.html.erb │ │ └── _paginator.html.erb └── assets │ ├── stylesheets │ └── active_admin │ │ ├── _mixins.scss │ │ ├── components │ │ ├── _columns.scss │ │ ├── _links.scss │ │ ├── _batch_actions.scss │ │ ├── _buttons.scss │ │ ├── _index_list.scss │ │ ├── _panels.scss │ │ ├── _scopes.scss │ │ ├── _status_tags.scss │ │ ├── _grid.scss │ │ ├── _unsupported_browser.scss │ │ ├── _breadcrumbs.scss │ │ ├── _blank_slates.scss │ │ ├── _modal_dialog.scss │ │ ├── _flash_messages.scss │ │ ├── _pagination.scss │ │ └── _comments.scss │ │ ├── mixins │ │ ├── _typography.scss │ │ ├── _all.scss │ │ ├── _utilities.scss │ │ ├── _shadows.scss │ │ ├── _rounded.scss │ │ ├── _gradients.scss │ │ └── _sections.scss │ │ ├── structure │ │ ├── _footer.scss │ │ ├── _main_structure.scss │ │ └── _title_bar.scss │ │ └── pages │ │ └── _logged_out.scss │ ├── images │ └── active_admin │ │ ├── orderable.png │ │ ├── nested_menu_arrow.gif │ │ └── nested_menu_arrow_dark.gif │ └── javascripts │ └── active_admin │ ├── initializers │ ├── tabs.es6 │ └── datepicker.es6 │ ├── ext │ ├── jquery.es6 │ └── jquery-ui.es6 │ ├── base.es6 │ └── lib │ ├── table-checkbox-toggler.es6 │ ├── active_admin.es6 │ └── per_page.es6 ├── .yardopts ├── features ├── step_definitions │ ├── index_views_steps.rb │ ├── blog_steps.rb │ ├── layout_steps.rb │ ├── meta_tag_steps.rb │ ├── root_steps.rb │ ├── column_steps.rb │ ├── action_item_steps.rb │ ├── tab_steps.rb │ ├── member_link_steps.rb │ ├── breadcrumb_steps.rb │ ├── attributes_table_title_steps.rb │ ├── flash_steps.rb │ ├── menu_steps.rb │ ├── i18n_steps.rb │ ├── pagination_steps.rb │ ├── sidebar_steps.rb │ ├── dashboard_steps.rb │ ├── footer_steps.rb │ ├── asset_steps.rb │ ├── action_link_steps.rb │ ├── attribute_steps.rb │ ├── site_title_steps.rb │ └── comment_steps.rb ├── support │ ├── regular_env.rb │ ├── reload_env.rb │ └── selectors.rb ├── users │ └── logging_out.feature ├── dashboard.feature ├── index │ ├── index_as_block.feature │ └── page_title.feature ├── root_to.feature ├── favicon.feature ├── first_boot.feature ├── comments │ └── viewing_index.feature ├── meta_tags.feature ├── show │ ├── columns.feature │ └── tabs.feature ├── footer.feature ├── global_navigation.feature ├── development_reloading.feature ├── registering_resources.feature ├── renamed_resource.feature ├── registering_assets.feature ├── authorization_pundit.feature ├── filter_attributes.feature └── decorators.feature ├── spec ├── javascripts │ ├── helpers │ │ └── SpecHelper.js │ ├── fixtures │ │ ├── checkboxes.html │ │ └── table_checkboxes.html │ ├── support │ │ └── jasmine_runner.rb │ └── coffeescripts │ │ └── jquery.aa.table-checkbox-toggler-spec.js.coffee ├── support │ └── templates │ │ ├── admin │ │ └── stores.rb │ │ ├── policies │ │ ├── category_policy.rb │ │ ├── store_policy.rb │ │ ├── user_policy.rb │ │ ├── active_admin │ │ │ ├── comment_policy.rb │ │ │ └── page_policy.rb │ │ ├── admin_user_policy.rb │ │ ├── post_policy.rb │ │ └── application_policy.rb │ │ ├── en.yml │ │ └── post_decorator.rb ├── unit │ ├── page_controller_spec.rb │ ├── active_admin_spec.rb │ ├── resource │ │ ├── menu_spec.rb │ │ ├── includes_spec.rb │ │ ├── pagination_spec.rb │ │ ├── ordering_spec.rb │ │ └── sidebars_spec.rb │ ├── views │ │ ├── pages │ │ │ ├── base_spec.rb │ │ │ └── show_spec.rb │ │ └── components │ │ │ ├── sidebar_spec.rb │ │ │ ├── blank_slate_spec.rb │ │ │ └── menu_item_spec.rb │ ├── component_spec.rb │ ├── filters │ │ └── active_spec.rb │ ├── authorization │ │ └── index_overriding_spec.rb │ ├── settings_node_spec.rb │ ├── generators │ │ └── install_spec.rb │ ├── view_factory_spec.rb │ ├── dynamic_settings_spec.rb │ ├── namespace │ │ └── authorization_spec.rb │ ├── view_helpers │ │ └── flash_helper_spec.rb │ ├── resource_controller │ │ └── sidebars_spec.rb │ ├── helpers │ │ └── scope_chain_spec.rb │ ├── localizers │ │ └── resource_localizer_spec.rb │ └── cancan_adapter_spec.rb ├── spec_helper.rb ├── requests │ ├── stylesheets_spec.rb │ └── memory_spec.rb ├── bug_report_templates_spec.rb ├── gemfiles_spec.lint.rb ├── changelog_spec.lint.rb └── i18n_spec.lint.rb ├── .rspec_parallel ├── config ├── mdl_style.rb └── i18n-tasks.yml ├── .simplecov ├── tasks ├── gemfiles.rake ├── local.rake └── test.rake ├── Gemfile ├── gemfiles ├── rails_50.gemfile └── rails_51.gemfile ├── codecov.yml ├── vendor └── assets │ └── javascripts │ └── jquery-ui │ ├── version.js │ ├── ie.js │ ├── escape-selector.js │ ├── safe-blur.js │ ├── form.js │ ├── keycode.js │ ├── tabbable.js │ ├── data.js │ ├── unique-id.js │ ├── safe-active-element.js │ ├── plugin.js │ └── disable-selection.js ├── cucumber.yml ├── bin └── install_chromedriver.sh ├── Rakefile ├── .gitignore ├── .github └── ISSUE_TEMPLATE.md ├── LICENSE └── activeadmin.gemspec /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _site/ 2 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | activeadmin.info -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --require spec_helper 2 | -------------------------------------------------------------------------------- /.mdlrc: -------------------------------------------------------------------------------- 1 | style "config/mdl_style.rb" 2 | -------------------------------------------------------------------------------- /lib/active_admin/orm/mongoid/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/activeadmin.rb: -------------------------------------------------------------------------------- 1 | require 'active_admin' 2 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | plugins: 2 | - jekyll-redirect-from 3 | -------------------------------------------------------------------------------- /app/views/active_admin/resource/new.html.arb: -------------------------------------------------------------------------------- 1 | insert_tag renderer_for(:new) 2 | -------------------------------------------------------------------------------- /app/views/layouts/active_admin.html.arb: -------------------------------------------------------------------------------- 1 | insert_tag view_factory.layout 2 | -------------------------------------------------------------------------------- /app/views/active_admin/resource/edit.html.arb: -------------------------------------------------------------------------------- 1 | insert_tag renderer_for(:edit) 2 | -------------------------------------------------------------------------------- /app/views/active_admin/resource/index.html.arb: -------------------------------------------------------------------------------- 1 | insert_tag renderer_for(:index) 2 | -------------------------------------------------------------------------------- /app/views/active_admin/resource/show.html.arb: -------------------------------------------------------------------------------- 1 | insert_tag renderer_for(:show) 2 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/_mixins.scss: -------------------------------------------------------------------------------- 1 | @import "active_admin/mixins/all"; 2 | -------------------------------------------------------------------------------- /lib/active_admin/orm/mongoid.rb: -------------------------------------------------------------------------------- 1 | # Mongoid-specific plugins should be required here 2 | -------------------------------------------------------------------------------- /lib/active_admin/version.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | VERSION = '2.0.0.alpha' 3 | end 4 | -------------------------------------------------------------------------------- /lib/generators/active_admin/assets/templates/active_admin.js: -------------------------------------------------------------------------------- 1 | //= require active_admin/base 2 | -------------------------------------------------------------------------------- /app/views/active_admin/page/index.html.arb: -------------------------------------------------------------------------------- 1 | insert_tag active_admin_application.view_factory["page"] 2 | -------------------------------------------------------------------------------- /docs/images/divider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/augment/activeadmin/master/docs/images/divider.png -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/components/_columns.scss: -------------------------------------------------------------------------------- 1 | .columns { 2 | margin-bottom: 10px; 3 | } 4 | -------------------------------------------------------------------------------- /docs/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'github-pages' 4 | gem 'jekyll-redirect-from' 5 | -------------------------------------------------------------------------------- /docs/images/features.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/augment/activeadmin/master/docs/images/features.png -------------------------------------------------------------------------------- /.yardopts: -------------------------------------------------------------------------------- 1 | lib/**/*.rb 2 | --protected 3 | --no-private 4 | - 5 | README.md 6 | CHANGELOG.md 7 | docs/**/*.md 8 | -------------------------------------------------------------------------------- /docs/images/activeadmin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/augment/activeadmin/master/docs/images/activeadmin.png -------------------------------------------------------------------------------- /docs/images/code-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/augment/activeadmin/master/docs/images/code-header.png -------------------------------------------------------------------------------- /features/step_definitions/index_views_steps.rb: -------------------------------------------------------------------------------- 1 | When /^I click "(.*?)"$/ do |link| 2 | click_link(link) 3 | end 4 | -------------------------------------------------------------------------------- /lib/active_admin/component.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | class Component < Arbre::Component 3 | 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /spec/javascripts/helpers/SpecHelper.js: -------------------------------------------------------------------------------- 1 | beforeEach(function() { 2 | window.inject = $.jasmine.inject; 3 | }); 4 | -------------------------------------------------------------------------------- /.rspec_parallel: -------------------------------------------------------------------------------- 1 | --format progress 2 | --format ParallelTests::RSpec::RuntimeLogger --out tmp/parallel_runtime_rspec.log 3 | -------------------------------------------------------------------------------- /app/assets/images/active_admin/orderable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/augment/activeadmin/master/app/assets/images/active_admin/orderable.png -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/mixins/_typography.scss: -------------------------------------------------------------------------------- 1 | @mixin sans-family { 2 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 3 | } 4 | -------------------------------------------------------------------------------- /spec/support/templates/admin/stores.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register Store do 2 | 3 | permit_params :name 4 | 5 | index pagination_total: false 6 | 7 | end 8 | -------------------------------------------------------------------------------- /app/assets/images/active_admin/nested_menu_arrow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/augment/activeadmin/master/app/assets/images/active_admin/nested_menu_arrow.gif -------------------------------------------------------------------------------- /lib/active_admin/helpers/i18n.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Helpers 3 | module I18n 4 | PLURAL_MANY_COUNT = 2.1 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/generators/active_admin/page/templates/page.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register_page "<%= class_name %>" do 2 | content do 3 | # your content 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /lib/active_admin/orm/active_record/comments/views.rb: -------------------------------------------------------------------------------- 1 | require 'active_admin/views' 2 | require 'active_admin/orm/active_record/comments/views/active_admin_comments' 3 | -------------------------------------------------------------------------------- /app/assets/images/active_admin/nested_menu_arrow_dark.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/augment/activeadmin/master/app/assets/images/active_admin/nested_menu_arrow_dark.gif -------------------------------------------------------------------------------- /features/step_definitions/blog_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^I should see a blog header "([^"]*)"$/ do |header_text| 2 | expect(page).to have_css 'h3', text: header_text 3 | end 4 | -------------------------------------------------------------------------------- /features/step_definitions/layout_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^I should see the Active Admin layout$/ do 2 | expect(page).to have_css '#active_admin_content #main_content_wrapper' 3 | end 4 | -------------------------------------------------------------------------------- /features/support/regular_env.rb: -------------------------------------------------------------------------------- 1 | if ENV["COVERAGE"] == "true" 2 | require 'simplecov' 3 | 4 | SimpleCov.command_name "regular features" 5 | end 6 | 7 | require_relative 'env' 8 | -------------------------------------------------------------------------------- /features/support/reload_env.rb: -------------------------------------------------------------------------------- 1 | if ENV["COVERAGE"] == "true" 2 | require 'simplecov' 3 | 4 | SimpleCov.command_name "reload features" 5 | end 6 | 7 | require_relative 'env' 8 | -------------------------------------------------------------------------------- /spec/unit/page_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe ActiveAdmin::PageController do 4 | let(:controller) { ActiveAdmin::PageController.new } 5 | end 6 | -------------------------------------------------------------------------------- /spec/support/templates/policies/category_policy.rb: -------------------------------------------------------------------------------- 1 | class CategoryPolicy < ApplicationPolicy 2 | class Scope < Scope 3 | def resolve 4 | scope 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/components/_links.scss: -------------------------------------------------------------------------------- 1 | a, a:link, a:visited { 2 | color: $link-color; 3 | text-decoration: underline; 4 | } 5 | a:hover { text-decoration: none; } 6 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/components/_batch_actions.scss: -------------------------------------------------------------------------------- 1 | #collection_selection_toggle_panel { 2 | @include clearfix; 3 | >.resource_selection_toggle_cell { 4 | float:left; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /app/assets/javascripts/active_admin/initializers/tabs.es6: -------------------------------------------------------------------------------- 1 | let onDOMReady = () => 2 | $('#active_admin_content .tabs').tabs() 3 | 4 | $(document). 5 | ready(onDOMReady). 6 | on('page:load turbolinks:load', onDOMReady) 7 | -------------------------------------------------------------------------------- /lib/generators/active_admin/page/USAGE: -------------------------------------------------------------------------------- 1 | Description: 2 | Registers pages with Active Admin 3 | 4 | Example: 5 | rails generate active_admin:page Thing 6 | 7 | This will create: 8 | app/admin/thing.rb 9 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /spec/support/templates/policies/store_policy.rb: -------------------------------------------------------------------------------- 1 | class StorePolicy < ApplicationPolicy 2 | class Scope < Scope 3 | def resolve 4 | scope 5 | end 6 | end 7 | 8 | def destroy? 9 | false 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/support/templates/policies/user_policy.rb: -------------------------------------------------------------------------------- 1 | class UserPolicy < ApplicationPolicy 2 | class Scope < Scope 3 | def resolve 4 | scope 5 | end 6 | end 7 | 8 | def destroy_all? 9 | true 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/active_admin/resource/ordering.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | class Resource 3 | module Ordering 4 | 5 | def ordering 6 | @ordering ||= {}.with_indifferent_access 7 | end 8 | 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /spec/support/templates/policies/active_admin/comment_policy.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | class CommentPolicy < ApplicationPolicy 3 | class Scope < Scope 4 | def resolve 5 | scope 6 | end 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/active_admin/orm/active_record.rb: -------------------------------------------------------------------------------- 1 | # ActiveRecord-specific plugins should be required here 2 | 3 | ActiveAdmin::DatabaseHitDuringLoad.database_error_classes << ActiveRecord::StatementInvalid 4 | 5 | require 'active_admin/orm/active_record/comments' 6 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/components/_buttons.scss: -------------------------------------------------------------------------------- 1 | a.member_link { 2 | margin-right: 7px; 3 | white-space: nowrap; 4 | } 5 | 6 | a.button, a:link.button, a:visited.button, input[type=submit], input[type=button], button { @include dark-button; } 7 | -------------------------------------------------------------------------------- /config/mdl_style.rb: -------------------------------------------------------------------------------- 1 | all 2 | 3 | exclude_rule "first-header-h1" 4 | 5 | exclude_rule "line-length" 6 | 7 | exclude_rule "no-duplicate-header" 8 | 9 | rule "no-trailing-punctuation", punctuation: ".,;:!" 10 | 11 | exclude_rule "first-line-h1" 12 | -------------------------------------------------------------------------------- /features/step_definitions/meta_tag_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^the site should contain a meta tag with name "([^"]*)" and content "([^"]*)"$/ do |name, content| 2 | expect(page).to have_xpath("//meta[@name='#{name}' and @content='#{content}']", visible: false) 3 | end 4 | -------------------------------------------------------------------------------- /spec/support/templates/policies/admin_user_policy.rb: -------------------------------------------------------------------------------- 1 | class AdminUserPolicy < ApplicationPolicy 2 | class Scope < Scope 3 | def resolve 4 | scope 5 | end 6 | end 7 | 8 | def destroy? 9 | record != user 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /features/step_definitions/root_steps.rb: -------------------------------------------------------------------------------- 1 | Around '@root' do |scenario, block| 2 | previous_root = ActiveAdmin.application.root_to 3 | 4 | begin 5 | block.call 6 | ensure 7 | ActiveAdmin.application.root_to = previous_root 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/support/templates/en.yml: -------------------------------------------------------------------------------- 1 | # Sample translations used to test ActiveAdmin's I18n integration. 2 | activerecord: 3 | models: 4 | store: 5 | one: Bookstore 6 | other: Bookstores 7 | active_admin: 8 | download: "Download this:" 9 | -------------------------------------------------------------------------------- /.simplecov: -------------------------------------------------------------------------------- 1 | SimpleCov.start do 2 | add_filter 'spec/rails/' 3 | end 4 | 5 | if ENV['CI'] == 'true' 6 | require 'codecov' 7 | SimpleCov.formatters = [ 8 | SimpleCov::Formatter::HTMLFormatter, 9 | SimpleCov::Formatter::Codecov 10 | ] 11 | end 12 | -------------------------------------------------------------------------------- /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_namespace.view_factory 7 | end 8 | 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/components/_index_list.scss: -------------------------------------------------------------------------------- 1 | .indexes { 2 | float: right; 3 | 4 | li { 5 | .count { 6 | color: #8e979e; 7 | font-weight: normal; 8 | font-size: 0.9em; 9 | line-height: 10px; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/active_admin/deprecation.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Deprecation 3 | module_function 4 | 5 | def warn(message, callstack = caller) 6 | ActiveSupport::Deprecation.warn "Active Admin: #{message}", callstack 7 | end 8 | 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/active_admin/resource/includes.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | class Resource 3 | module Includes 4 | 5 | # Return an array of includes for this resource 6 | def includes 7 | @includes ||= [] 8 | end 9 | 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /tasks/gemfiles.rake: -------------------------------------------------------------------------------- 1 | desc "Bundle all Gemfiles" 2 | task :bundle do |_t, opts| 3 | ["Gemfile", *Dir.glob("gemfiles/*.gemfile")].each do |gemfile| 4 | Bundler.with_original_env do 5 | system({ "BUNDLE_GEMFILE" => gemfile }, "bundle", *opts) 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | eval_gemfile(File.expand_path("Gemfile.common", __dir__)) 4 | 5 | gem "rails", "~> 5.2.x" 6 | gem "devise", "~> 4.4" 7 | gem "draper", "~> 3.0" 8 | gem "activerecord-jdbcsqlite3-adapter", ">= 52.0", platforms: :jruby 9 | 10 | gemspec path: "." 11 | -------------------------------------------------------------------------------- /features/step_definitions/column_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^I should see a columns container$/ do 2 | expect(page).to have_css '.columns' 3 | end 4 | 5 | Then /^I should see (a|\d+) columns?$/ do |count| 6 | count = count == 'a' ? 1 : count.to_i 7 | expect(page).to have_css '.column', count: count 8 | end 9 | -------------------------------------------------------------------------------- /spec/support/templates/policies/post_policy.rb: -------------------------------------------------------------------------------- 1 | class PostPolicy < ApplicationPolicy 2 | class Scope < Scope 3 | def resolve 4 | scope 5 | end 6 | end 7 | 8 | def update? 9 | record.author == user 10 | end 11 | 12 | def destroy? 13 | update? 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/components/_panels.scss: -------------------------------------------------------------------------------- 1 | // ----------------------------------- Helper class to apply to elements to make them sections 2 | .section, .panel{ @include section; } 3 | 4 | // ----------------------------------- Sidebar Sections 5 | 6 | .sidebar_section { @include section; } 7 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/components/_scopes.scss: -------------------------------------------------------------------------------- 1 | .scopes { 2 | li { 3 | .count { 4 | color: #8e979e; 5 | font-weight: normal; 6 | font-size: 0.9em; 7 | line-height: 10px; 8 | } 9 | &:first-child a { 10 | margin-left: 10px; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /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/views/tabbed_navigation.rb: -------------------------------------------------------------------------------- 1 | require_relative 'components/menu' 2 | 3 | module ActiveAdmin 4 | module Views 5 | class TabbedNavigation < Menu 6 | def build(menu, options = {}) 7 | super(menu, options.reverse_merge(id: 'tabs')) 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/active_admin/localizers.rb: -------------------------------------------------------------------------------- 1 | require 'active_admin/localizers/resource_localizer' 2 | 3 | module ActiveAdmin 4 | module Localizers 5 | class << self 6 | def resource(active_admin_config) 7 | ResourceLocalizer.from_resource(active_admin_config) 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /docs/_includes/footer.html: -------------------------------------------------------------------------------- 1 |
3 | Copyright 2011 Greg Bell and VersaPay 4 |
5 |
6 | Tweet

7 |
8 |

9 | -------------------------------------------------------------------------------- /lib/active_admin/orm/active_record/comments/namespace_helper.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Comments 3 | 4 | module NamespaceHelper 5 | 6 | # Returns true if the namespace allows comments 7 | def comments? 8 | comments == true 9 | end 10 | 11 | end 12 | 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /features/step_definitions/action_item_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^I should see an action item link to "([^"]*)"$/ do |link| 2 | expect(page).to have_css('.action_item a', text: link) 3 | end 4 | 5 | Then /^I should not see an action item link to "([^"]*)"$/ do |link| 6 | expect(page).to_not have_css('.action_item a', text: link) 7 | end 8 | -------------------------------------------------------------------------------- /features/step_definitions/tab_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^the "([^"]*)" tab should be selected$/ do |name| 2 | step %{I should see "#{name}" within "ul#tabs li.current"} 3 | end 4 | 5 | Then(/^I should see two tabs "(.*?)" and "(.*?)"$/) do |tab_1, tab_2| 6 | expect(page).to have_link(tab_1) 7 | expect(page).to have_link(tab_2) 8 | end 9 | -------------------------------------------------------------------------------- /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/member_link_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^I should see an action item button "([^"]*)"$/ do |content| 2 | expect(page).to have_css '.action_items a', text: content 3 | end 4 | 5 | Then /^I should not see an action item button "([^"]*)"$/ do |content| 6 | expect(page).to_not have_css '.action_items', text: content 7 | end 8 | -------------------------------------------------------------------------------- /gemfiles/rails_50.gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | eval_gemfile(File.expand_path(File.join("..", "Gemfile.common"), __dir__)) 4 | 5 | gem "rails", "5.0.7" 6 | gem "devise", "~> 4.0" 7 | gem "draper", "~> 3.0" 8 | gem "activerecord-jdbcsqlite3-adapter", "~> 50.0", platforms: :jruby 9 | 10 | gemspec path: "../" 11 | -------------------------------------------------------------------------------- /gemfiles/rails_51.gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | eval_gemfile(File.expand_path(File.join("..", "Gemfile.common"), __dir__)) 4 | 5 | gem "rails", "5.1.6" 6 | gem "devise", "~> 4.3" 7 | gem "draper", "~> 3.0" 8 | gem "activerecord-jdbcsqlite3-adapter", "~> 51.0", platforms: :jruby 9 | 10 | gemspec path: "../" 11 | -------------------------------------------------------------------------------- /lib/active_admin/views/components/sidebar.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Views 3 | 4 | class Sidebar < Component 5 | builder_method :sidebar 6 | 7 | def build(sections, attributes = {}) 8 | super(attributes) 9 | sections.map(&method(:sidebar_section)) 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/unit/active_admin_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe ActiveAdmin do 4 | %w(register register_page unload! load! routes).each do |method| 5 | it "delegates ##{method} to application" do 6 | expect(ActiveAdmin.application).to receive(method) 7 | 8 | ActiveAdmin.send(method) 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/components/_status_tags.scss: -------------------------------------------------------------------------------- 1 | .status_tag { 2 | background: darken($secondary-color, 15%); 3 | color: #fff; 4 | text-transform: uppercase; 5 | letter-spacing: 0.15em; 6 | padding: 3px 5px 2px 5px; 7 | font-size: 0.8em; 8 | 9 | &.yes { background: #6090DB } 10 | &.no { background: grey } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /lib/active_admin/inputs/filters/numeric_input.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Inputs 3 | module Filters 4 | class NumericInput < ::Formtastic::Inputs::NumberInput 5 | include Base 6 | include Base::SearchMethodSelect 7 | 8 | filter :equals, :greater_than, :less_than 9 | end 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /app/assets/javascripts/active_admin/ext/jquery.es6: -------------------------------------------------------------------------------- 1 | // `serializeArray` generates => [{ name: 'foo', value: 'bar' }] 2 | // This function remaps it to => { foo: 'bar' } 3 | $.fn.serializeObject = function() { 4 | return this.serializeArray() 5 | .reduce((obj, item) => { 6 | obj[item.name] = item.value 7 | return obj 8 | }, {}); 9 | }; 10 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/components/_grid.scss: -------------------------------------------------------------------------------- 1 | // -------------------------------------- Index as Grid 2 | table.index_grid td { border: none; background: none; padding: 0 20px 20px 0; margin: 0;} 3 | 4 | // -------------------------------------- Columns 5 | .columns { 6 | clear: both; 7 | padding: 0; 8 | .column { float: left; } 9 | } 10 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | codecov: 4 | notify: 5 | require_ci_to_pass: true 6 | 7 | comment: off 8 | 9 | coverage: 10 | precision: 2 11 | 12 | range: 13 | - 70.0 14 | - 100.0 15 | 16 | round: down 17 | 18 | status: 19 | changes: false 20 | 21 | patch: true 22 | 23 | project: 24 | default: 25 | threshold: 1% 26 | -------------------------------------------------------------------------------- /lib/active_admin/inputs/filters/date_picker_input.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Inputs 3 | module Filters 4 | class DatePickerInput < ::Formtastic::Inputs::DatePickerInput 5 | include Base 6 | 7 | def input_html_options 8 | super.merge(class: "datepicker") 9 | end 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /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/resource_controller/sidebars.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | class ResourceController < BaseController 3 | 4 | module Sidebars 5 | 6 | protected 7 | 8 | def skip_sidebar! 9 | @skip_sidebar = true 10 | end 11 | 12 | def skip_sidebar? 13 | @skip_sidebar == true 14 | end 15 | end 16 | 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lib/generators/active_admin/page/page_generator.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Generators 3 | class PageGenerator < Rails::Generators::NamedBase 4 | source_root File.expand_path('../templates', __FILE__) 5 | 6 | def generate_config_file 7 | template "page.rb", "app/admin/#{file_path.tr('/', '_')}.rb" 8 | end 9 | 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/active_admin/view_helpers/scope_name_helper.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module ViewHelpers 3 | module ScopeNameHelper 4 | 5 | def scope_name(scope) 6 | case scope.name 7 | when Proc then 8 | self.instance_exec(&scope.name).to_s 9 | else 10 | scope.name.to_s 11 | end 12 | end 13 | 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/mixins/_all.scss: -------------------------------------------------------------------------------- 1 | @import "active_admin/mixins/variables"; 2 | @import "active_admin/mixins/gradients"; 3 | @import "active_admin/mixins/shadows"; 4 | @import "active_admin/mixins/rounded"; 5 | @import "active_admin/mixins/buttons"; 6 | @import "active_admin/mixins/sections"; 7 | @import "active_admin/mixins/utilities"; 8 | @import "active_admin/mixins/typography"; 9 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/structure/_footer.scss: -------------------------------------------------------------------------------- 1 | #footer { 2 | padding: 30px 30px; 3 | font-size: 0.8em; 4 | clear: both; 5 | 6 | p { 7 | padding-top: 10px 8 | } 9 | } 10 | 11 | // -------------------------------------- Index Footer (Under Table) 12 | #index_footer { padding-top: 5px; text-align: right; font-size: 0.85em; } 13 | 14 | .index_content { clear: both; } 15 | -------------------------------------------------------------------------------- /lib/active_admin/helpers/routes/url_helpers.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Helpers 3 | module Routes 4 | module UrlHelpers 5 | include Rails.application.routes.url_helpers 6 | end 7 | 8 | extend UrlHelpers 9 | 10 | def self.default_url_options 11 | Rails.application.routes.default_url_options || {} 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/support/templates/policies/active_admin/page_policy.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | class PagePolicy < ApplicationPolicy 3 | class Scope < Scope 4 | def resolve 5 | scope 6 | end 7 | end 8 | 9 | def show? 10 | case record.name 11 | when "Dashboard" 12 | true 13 | else 14 | false 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/components/_unsupported_browser.scss: -------------------------------------------------------------------------------- 1 | .unsupported_browser { 2 | padding: 10px 30px; 3 | color: #211e14; 4 | background-color: #fae692; 5 | @include gradient(#feefae, #fae692); 6 | border-bottom: 1px solid #b3a569; 7 | 8 | h1 { 9 | font-size: 13px; 10 | font-weight: bold; 11 | } 12 | 13 | p { 14 | margin-bottom: 0.5em; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'simplecov' if ENV["COVERAGE"] == "true" 2 | 3 | RSpec.configure do |config| 4 | config.disable_monkey_patching! 5 | config.filter_run focus: true 6 | config.filter_run_excluding skip: true 7 | config.run_all_when_everything_filtered = true 8 | config.color = true 9 | config.order = :random 10 | config.example_status_persistence_file_path = ".rspec_failures" 11 | end 12 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/jquery-ui/version.js: -------------------------------------------------------------------------------- 1 | ( function( factory ) { 2 | if ( typeof define === "function" && define.amd ) { 3 | 4 | // AMD. Register as an anonymous module. 5 | define( [ "jquery" ], factory ); 6 | } else { 7 | 8 | // Browser globals 9 | factory( jQuery ); 10 | } 11 | } ( function( $ ) { 12 | 13 | $.ui = $.ui || {}; 14 | 15 | return $.ui.version = "1.12.1"; 16 | 17 | } ) ); 18 | -------------------------------------------------------------------------------- /app/views/kaminari/active_admin/_gap.html.erb: -------------------------------------------------------------------------------- 1 | <%# Non-link tag that stands for skipped pages... 2 | - available local variables 3 | current_page: a page object for the currently displayed page 4 | total_pages: total number of pages 5 | per_page: number of items to fetch per page 6 | remote: data-remote 7 | -%> 8 | <%= t('views.pagination.truncate').html_safe %> 9 | -------------------------------------------------------------------------------- /lib/active_admin/orm/active_record/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) || comments == true 13 | end 14 | end 15 | 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /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.html_class do 9 | instance_exec(&action_item.block) 10 | end 11 | end 12 | end 13 | 14 | end 15 | 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/assets/javascripts/active_admin/ext/jquery-ui.es6: -------------------------------------------------------------------------------- 1 | // Short-circuits `_focusTabbable` to focus on the modal itself instead of 2 | // elements inside the modal. Without this, if a datepicker is the first input, 3 | // it'll immediately pop up when the modal opens. 4 | // See this ticket for more info: http://bugs.jqueryui.com/ticket/4731 5 | $.ui.dialog.prototype._focusTabbable = function() { 6 | this.uiDialog.focus(); 7 | }; 8 | -------------------------------------------------------------------------------- /spec/javascripts/fixtures/checkboxes.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | -------------------------------------------------------------------------------- /features/step_definitions/breadcrumb_steps.rb: -------------------------------------------------------------------------------- 1 | Around '@breadcrumb' do |scenario, block| 2 | previous_breadcrumb = ActiveAdmin.application.breadcrumb 3 | 4 | begin 5 | block.call 6 | ensure 7 | ActiveAdmin.application.breadcrumb = previous_breadcrumb 8 | end 9 | end 10 | 11 | Then /^I should see a link to "([^"]*)" in the breadcrumb$/ do |text| 12 | expect(page).to have_css '.breadcrumb > a', text: text 13 | end 14 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/mixins/_utilities.scss: -------------------------------------------------------------------------------- 1 | @mixin clearfix { 2 | &:after { 3 | visibility: hidden; 4 | display: block; 5 | content: ""; 6 | clear: both; 7 | height: 0; 8 | } 9 | } 10 | 11 | @mixin border-colors($top, $sides, $bottom) { 12 | border-color: $sides; 13 | border-top-color: $top; 14 | border-right-color: $sides; 15 | border-bottom-color: $bottom; 16 | border-left-color: $sides; 17 | } 18 | -------------------------------------------------------------------------------- /features/step_definitions/attributes_table_title_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^I should see the panel title "([^"]*)"$/ do |title| 2 | expect(page).to have_css '.panel > h3', text: title 3 | end 4 | 5 | Then /^I should not see the panel title "([^"]*)"$/ do |title| 6 | expect(page).to_not have_css '.panel > h3', text: title 7 | end 8 | 9 | Then /^I should see the attributes table$/ do 10 | expect(page).to have_css '.panel .attributes_table' 11 | end 12 | -------------------------------------------------------------------------------- /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(content) 12 | super(span(content.html_safe, class: "blank_slate")) 13 | end 14 | 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /features/step_definitions/flash_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^I should see a flash with "([^"]*)"$/ do |text| 2 | expect(page).to have_content text 3 | end 4 | 5 | Then /^I should see a successful create flash$/ do 6 | expect(page).to have_css 'div.flash_notice', text: /was successfully created/ 7 | end 8 | 9 | Then /^I should not see a successful create flash$/ do 10 | expect(page).to_not have_css 'div.flash_notice', text: /was successfully created/ 11 | end 12 | -------------------------------------------------------------------------------- /spec/unit/resource/menu_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | module ActiveAdmin 4 | RSpec.describe Resource, "Menu" 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 | # TODO... 16 | 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /cucumber.yml: -------------------------------------------------------------------------------- 1 | <% 2 | std_opts = "--format progress --order random" 3 | default_opts = std_opts + " --format ParallelTests::Gherkin::RuntimeLogger --out tmp/parallel_runtime_cucumber.log" 4 | %> 5 | 6 | default: <%= default_opts %> --require features/support/regular_env.rb features --tags 'not @requires-reloading' --tags 'not @wip' 7 | class-reloading: CLASS_RELOADING=true <%= std_opts %> --require features/support/reload_env.rb features --tags @requires-reloading 8 | -------------------------------------------------------------------------------- /features/step_definitions/menu_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^I should see a menu item for "([^"]*)"$/ do |name| 2 | expect(page).to have_css '#tabs > li > a', text: name 3 | end 4 | 5 | Then /^I should not see a menu item for "([^"]*)"$/ do |name| 6 | expect(page).to_not have_css '#tabs > li > a', text: name 7 | end 8 | 9 | Then /^I should see a nested menu item for "([^"]*)"$/ do |name| 10 | expect(page).to have_css '#tabs > li > ul > li > a', text: name 11 | end 12 | -------------------------------------------------------------------------------- /spec/unit/views/pages/base_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe ActiveAdmin::Views::Pages::Base do 4 | class NewPage < ActiveAdmin::Views::Pages::Base 5 | end 6 | 7 | it "defines a default title" do 8 | expect(NewPage.new.title).to eq 'NewPage' 9 | end 10 | 11 | it "defines default main content" do 12 | expect(NewPage.new.main_content).to eq 'Please implement NewPage#main_content to display content.' 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /bin/install_chromedriver.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | curl --silent \ 6 | --show-error \ 7 | --location \ 8 | --fail \ 9 | --retry 3 \ 10 | --output /tmp/chromedriver_linux64.zip \ 11 | https://chromedriver.storage.googleapis.com/2.38/chromedriver_linux64.zip 12 | 13 | unzip /tmp/chromedriver_linux64.zip chromedriver -d ~/.local/bin 14 | 15 | rm /tmp/chromedriver_linux64.zip 16 | 17 | chromedriver --version 18 | -------------------------------------------------------------------------------- /features/step_definitions/i18n_steps.rb: -------------------------------------------------------------------------------- 1 | Given /^String "([^"]*)" corresponds to "([^"]*)"$/ do |translation, key| 2 | *seq, last_key = key.split('.') 3 | result = seq.reverse.inject({last_key.to_sym => translation}) do |temp_result, nested_key| 4 | {nested_key.to_sym => temp_result} 5 | end 6 | I18n.backend.store_translations :en, active_admin: result 7 | end 8 | 9 | When /^I set my locale to "([^"]*)"$/ do |lang| 10 | I18n.locale = lang 11 | end 12 | -------------------------------------------------------------------------------- /lib/active_admin/views/components/unsupported_browser.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Views 3 | class UnsupportedBrowser < Component 4 | def build 5 | h1 I18n.t("active_admin.unsupported_browser.headline").html_safe 6 | para I18n.t("active_admin.unsupported_browser.recommendation").html_safe 7 | para I18n.t("active_admin.unsupported_browser.turn_off_compatibility_view").html_safe 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/mixins/_shadows.scss: -------------------------------------------------------------------------------- 1 | @mixin shadow($x: 0, $y: 1px, $blur: 2px, $color: rgba(0,0,0,0.37)) { 2 | box-shadow: $x $y $blur $color; 3 | } 4 | 5 | @mixin no-shadow { 6 | box-shadow: none; 7 | } 8 | 9 | @mixin inset-shadow($x: 0, $y: 1px, $blur: 2px, $color: #aaa) { 10 | box-shadow: inset $x $y $blur $color; 11 | } 12 | 13 | @mixin text-shadow($color: #fff, $x: 0, $y: 1px, $blur: 0) { 14 | text-shadow: $color $x $y $blur; 15 | } 16 | -------------------------------------------------------------------------------- /lib/generators/active_admin/assets/assets_generator.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Generators 3 | class AssetsGenerator < Rails::Generators::Base 4 | 5 | source_root File.expand_path("../templates", __FILE__) 6 | 7 | def install_assets 8 | template 'active_admin.js', 'app/assets/javascripts/active_admin.js' 9 | template "active_admin.scss", "app/assets/stylesheets/active_admin.scss" 10 | end 11 | 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/jquery-ui/ie.js: -------------------------------------------------------------------------------- 1 | //= require jquery-ui/version 2 | 3 | ( function( factory ) { 4 | if ( typeof define === "function" && define.amd ) { 5 | 6 | // AMD. Register as an anonymous module. 7 | define( [ "jquery", "./version" ], factory ); 8 | } else { 9 | 10 | // Browser globals 11 | factory( jQuery ); 12 | } 13 | } ( function( $ ) { 14 | 15 | // This file is deprecated 16 | return $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); 17 | } ) ); 18 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /app/views/kaminari/active_admin/_last_page.html.erb: -------------------------------------------------------------------------------- 1 | <%# Link to the "Last" page 2 | - available local variables 3 | url: url to the last page 4 | current_page: a page object for the currently displayed page 5 | total_pages: total number of pages 6 | per_page: number of items to fetch per page 7 | remote: data-remote 8 | -%> 9 | 10 | <%= link_to_unless current_page.last?, t('views.pagination.last').html_safe, url, remote: remote %> 11 | 12 | -------------------------------------------------------------------------------- /app/views/kaminari/active_admin/_first_page.html.erb: -------------------------------------------------------------------------------- 1 | <%# Link to the "First" page 2 | - available local variables 3 | url: url to the first page 4 | current_page: a page object for the currently displayed page 5 | total_pages: total number of pages 6 | per_page: number of items to fetch per page 7 | remote: data-remote 8 | -%> 9 | 10 | <%= link_to_unless current_page.first?, t('views.pagination.first').html_safe, url, remote: remote %> 11 | 12 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/components/_breadcrumbs.scss: -------------------------------------------------------------------------------- 1 | .breadcrumb { 2 | display: block; 3 | font-size: 0.9em; 4 | font-weight: normal; 5 | line-height: 1.0em; 6 | margin-bottom: 12px; 7 | text-transform: uppercase; 8 | 9 | a, a:link, a:visited, a:active { 10 | color: $breadcrumbs-color; 11 | text-decoration: none; 12 | } 13 | 14 | a:hover { text-decoration: underline; } 15 | 16 | .breadcrumb_sep { 17 | margin: 0 2px; 18 | color: $breadcrumbs-separator-color; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/views/kaminari/active_admin/_next_page.html.erb: -------------------------------------------------------------------------------- 1 | <%# Link to the "Next" page 2 | - available local variables 3 | url: url to the next page 4 | current_page: a page object for the currently displayed page 5 | total_pages: total number of pages 6 | per_page: number of items to fetch per page 7 | remote: data-remote 8 | -%> 9 | 10 | <%= link_to_unless current_page.last?, t('views.pagination.next').html_safe, url, rel: 'next', remote: remote %> 11 | 12 | -------------------------------------------------------------------------------- /spec/requests/stylesheets_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe "Stylesheets", type: :request do 4 | 5 | require "sprockets" 6 | 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 | expect(css).to_not eq nil 13 | end 14 | it "should not have any syntax errors" do 15 | expect(css.to_s).to_not include("Syntax error:") 16 | end 17 | 18 | end 19 | -------------------------------------------------------------------------------- /features/step_definitions/pagination_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^I should not see pagination$/ do 2 | expect(page).to_not have_css '.pagination' 3 | end 4 | 5 | Then /^I should see pagination with (\d+) pages$/ do |count| 6 | expect(page).to have_css '.pagination span.page', count: count 7 | end 8 | 9 | Then /^I should see the pagination "Next" link/ do 10 | expect(page).to have_css "a", text: "Next" 11 | end 12 | 13 | Then /^I should not see the pagination "Next" link/ do 14 | expect(page).to_not have_css "a", text: "Next" 15 | end 16 | -------------------------------------------------------------------------------- /spec/javascripts/support/jasmine_runner.rb: -------------------------------------------------------------------------------- 1 | $:.unshift(ENV['JASMINE_GEM_PATH']) if ENV['JASMINE_GEM_PATH'] # for gem testing purposes 2 | 3 | require 'jasmine' 4 | require 'spec' 5 | 6 | jasmine_config = Jasmine::Config.new 7 | spec_builder = Jasmine::SpecBuilder.new(jasmine_config) 8 | 9 | should_stop = false 10 | 11 | Spec::Runner.configure do |config| 12 | config.after(:suite) do 13 | spec_builder.stop if should_stop 14 | end 15 | end 16 | 17 | spec_builder.start 18 | should_stop = true 19 | spec_builder.declare_suites 20 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler/gem_tasks' 2 | 3 | # Import all our rake tasks 4 | FileList['tasks/**/*.rake'].each { |task| import task } 5 | 6 | task default: :test 7 | 8 | begin 9 | require 'jasmine' 10 | load 'jasmine/tasks/jasmine.rake' 11 | rescue LoadError 12 | task :jasmine do 13 | abort 'Jasmine is not available. In order to run jasmine, you must: (sudo) gem install jasmine' 14 | end 15 | end 16 | 17 | task :console do 18 | require 'irb' 19 | require 'irb/completion' 20 | 21 | ARGV.clear 22 | IRB.start 23 | end 24 | -------------------------------------------------------------------------------- /app/assets/javascripts/active_admin/initializers/datepicker.es6: -------------------------------------------------------------------------------- 1 | (($) => { 2 | 3 | $(document) 4 | .on('focus', 'input.datepicker:not(.hasDatepicker)', function() { 5 | const input = $(this); 6 | 7 | // Only create datepickers in compatible browsers 8 | if (input[0].type === 'date') { return; } 9 | 10 | const defaults = { dateFormat: 'yy-mm-dd' }; 11 | const options = input.data('datepicker-options'); 12 | 13 | input.datepicker($.extend(defaults, options)); 14 | }); 15 | 16 | })(jQuery); 17 | -------------------------------------------------------------------------------- /app/views/kaminari/active_admin/_prev_page.html.erb: -------------------------------------------------------------------------------- 1 | <%# Link to the "Previous" page 2 | - available local variables 3 | url: url to the previous page 4 | current_page: a page object for the currently displayed page 5 | total_pages: total number of pages 6 | per_page: number of items to fetch per page 7 | remote: data-remote 8 | -%> 9 | 10 | <%= link_to_unless current_page.first?, t('views.pagination.previous').html_safe, url, rel: 'prev', remote: remote %> 11 | 12 | -------------------------------------------------------------------------------- /docs/3-index-pages/index-as-block.md: -------------------------------------------------------------------------------- 1 | --- 2 | redirect_from: /docs/3-index-pages/index-as-block.html 3 | --- 4 | 5 | # Index as a Block 6 | 7 | If you want to fully customize the display of your resources on the index 8 | screen, Index as a Block allows you to render a block of content for each 9 | resource. 10 | 11 | ```ruby 12 | index as: :block do |product| 13 | div for: product do 14 | resource_selection_cell product 15 | h2 auto_link product.title 16 | div simple_format product.description 17 | end 18 | end 19 | ``` 20 | -------------------------------------------------------------------------------- /lib/active_admin/settings_node.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | 3 | class SettingsNode 4 | class << self 5 | # Never instantiated. Variables are stored in the singleton_class. 6 | private_class_method :new 7 | 8 | # @return anonymous class with same accessors as the superclass. 9 | def build(superclass = self) 10 | Class.new(superclass) 11 | end 12 | 13 | def register(name, value) 14 | class_attribute name 15 | send "#{name}=", value 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/unit/component_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | class MockComponentClass < ActiveAdmin::Component; end 4 | 5 | RSpec.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 | expect(ActiveAdmin::Component.ancestors).to include(Arbre::HTML::Div) 12 | end 13 | 14 | it "should render to a div, even as a subclass" do 15 | expect(component.tag_name).to eq 'div' 16 | end 17 | 18 | end 19 | -------------------------------------------------------------------------------- /lib/active_admin/inputs.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Inputs 3 | extend ActiveSupport::Autoload 4 | 5 | autoload :DatepickerInput 6 | 7 | module Filters 8 | extend ActiveSupport::Autoload 9 | 10 | autoload :Base 11 | autoload :StringInput 12 | autoload :TextInput 13 | autoload :DatePickerInput 14 | autoload :DateRangeInput 15 | autoload :NumericInput 16 | autoload :SelectInput 17 | autoload :CheckBoxesInput 18 | autoload :BooleanInput 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /features/dashboard.feature: -------------------------------------------------------------------------------- 1 | Feature: Dashboard 2 | 3 | Scenario: With default configuration 4 | Given a configuration of: 5 | """ 6 | ActiveAdmin.register_page "Dashboard" do 7 | content do 8 | para "Hello world from the dashboard page" 9 | end 10 | end 11 | """ 12 | Given I am logged in 13 | When I go to the dashboard 14 | Then I should see the Active Admin layout 15 | And I should not see the default welcome message 16 | And I should see "Hello world from the dashboard page" 17 | -------------------------------------------------------------------------------- /lib/active_admin/view_helpers/flash_helper.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module ViewHelpers 3 | module FlashHelper 4 | 5 | # Returns all the flash keys to display in any Active Admin view. 6 | # This method removes the :timedout key that Devise uses by default. 7 | # Note Rails >= 4.1 normalizes keys to strings automatically. 8 | def flash_messages 9 | @flash_messages ||= flash.to_hash.with_indifferent_access.except(*active_admin_application.flash_keys_to_except) 10 | end 11 | 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /docs/_includes/head.html: -------------------------------------------------------------------------------- 1 | 2 | Active Admin | The administration framework for Ruby on Rails 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/active_admin/views/header.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Views 3 | class Header < Component 4 | 5 | def build(namespace, menu) 6 | super(id: "header") 7 | 8 | @namespace = namespace 9 | @menu = menu 10 | @utility_menu = @namespace.fetch_menu(:utility_navigation) 11 | 12 | site_title @namespace 13 | global_navigation @menu, class: 'header-item tabs' 14 | utility_navigation @utility_menu, id: "utility_nav", class: 'header-item tabs' 15 | end 16 | 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /app/views/kaminari/active_admin/_page.html.erb: -------------------------------------------------------------------------------- 1 | <%# Link showing page number 2 | - available local variables 3 | page: a page object for "this" page 4 | url: url to this page 5 | current_page: a page object for the currently displayed page 6 | total_pages: total number of pages 7 | per_page: number of items to fetch per page 8 | remote: data-remote 9 | -%> 10 | 11 | <%= link_to_unless page.current?, page, url, {remote: remote, rel: page.rel} %> 12 | 13 | -------------------------------------------------------------------------------- /features/step_definitions/sidebar_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^I should see a sidebar titled "([^"]*)"$/ do |title| 2 | expect(page).to have_css '.sidebar_section h3', text: title 3 | end 4 | 5 | Then /^I should not see a sidebar titled "([^"]*)"$/ do |title| 6 | expect(page).not_to have_css '.sidebar_section h3', text: title 7 | end 8 | 9 | Then(/^I should see a sidebar titled "(.*?)" above sidebar titled "(.*?)"$/) do |top_title, bottom_title| 10 | expect(page).to have_css %Q(.sidebar_section:contains('#{top_title}') + .sidebar_section:contains('#{bottom_title}')) 11 | end 12 | -------------------------------------------------------------------------------- /lib/active_admin/filters.rb: -------------------------------------------------------------------------------- 1 | require 'active_admin/filters/dsl' 2 | require 'active_admin/filters/resource_extension' 3 | require 'active_admin/filters/formtastic_addons' 4 | require 'active_admin/filters/forms' 5 | require 'active_admin/helpers/optional_display' 6 | require 'active_admin/filters/active_sidebar' 7 | 8 | # Add our Extensions 9 | ActiveAdmin::ResourceDSL.send :include, ActiveAdmin::Filters::DSL 10 | ActiveAdmin::Resource.send :include, ActiveAdmin::Filters::ResourceExtension 11 | ActiveAdmin::ViewHelpers.send :include, ActiveAdmin::Filters::ViewHelper 12 | -------------------------------------------------------------------------------- /features/root_to.feature: -------------------------------------------------------------------------------- 1 | @root 2 | Feature: Namespace root 3 | 4 | As a developer 5 | In order to customize the welcome page 6 | I want to set it in the configuration 7 | 8 | Scenario: Default root is the Dashboard 9 | Given I am logged in with capybara 10 | Then I should be on the dashboard 11 | 12 | Scenario: Set root to "stores#index" 13 | Given a configuration of: 14 | """ 15 | ActiveAdmin.application.root_to = 'stores#index' 16 | """ 17 | Given I am logged in with capybara 18 | Then I should see the page title "Bookstores" 19 | -------------------------------------------------------------------------------- /features/favicon.feature: -------------------------------------------------------------------------------- 1 | Feature: Favicon 2 | 3 | Configuring a Favicon file 4 | 5 | Background: 6 | Given a configuration of: 7 | """ 8 | ActiveAdmin.register Post 9 | ActiveAdmin.application.favicon = "a/favicon.ico" 10 | """ 11 | 12 | Scenario: Logged out views show Favicon 13 | Given I am logged out 14 | When I am on the login page 15 | Then I should see the favicon "favicon" 16 | 17 | Scenario: Logged in views show Favicon 18 | Given I am logged in 19 | When I am on the dashboard 20 | Then I should see the favicon "favicon" -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /config/i18n-tasks.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # The "main" locale 4 | base_locale: en 5 | 6 | # Read and write translations 7 | data: 8 | yaml: 9 | write: 10 | # Do not wrap lines at 80 characters 11 | line_width: -1 12 | 13 | # Find translate calls 14 | search: 15 | # Paths or `File.find` patterns to search in 16 | paths: 17 | - app 18 | - lib 19 | 20 | # Files or `File.fnmatch` patterns to exclude from search 21 | exclude: 22 | - app/assets/images 23 | - lib/bug_report_templates/tmp 24 | 25 | # Guess usages such as t("categories.#{category}.title") 26 | strict: false 27 | -------------------------------------------------------------------------------- /docs/_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% include head.html %} 4 | 5 |
6 | {% include top-menu.html %} 7 |
8 |
9 | {% include toc.html %} 10 |
11 |
12 |
13 | {{ content }} 14 |
15 |
16 |
17 | {% include footer.html %} 18 |
19 | {% include google-analytics.html %} 20 | 21 | 22 | -------------------------------------------------------------------------------- /lib/active_admin/helpers/collection.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Helpers 3 | module Collection 4 | # 1. removes `select` and `order` to prevent invalid SQL 5 | # 2. correctly handles the Hash returned when `group by` is used 6 | def collection_size(c = collection) 7 | return c.count if c.is_a?(Array) 8 | 9 | c = c.except :select, :order 10 | 11 | c.group_values.present? ? c.count.count : c.count 12 | end 13 | 14 | def collection_is_empty?(c = collection) 15 | collection_size(c) == 0 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/active_admin/resource/controllers.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | class Resource 3 | module Controllers 4 | delegate :resources_configuration, to: :controller 5 | 6 | # Returns a properly formatted controller name for this 7 | # config within its namespace 8 | def controller_name 9 | [namespace.module_name, resource_name.plural.camelize + "Controller"].compact.join('::') 10 | end 11 | 12 | # Returns the controller for this config 13 | def controller 14 | @controller ||= controller_name.constantize 15 | end 16 | 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /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 ActiveAdminApplicationHelper 8 | include AutoLinkHelper 9 | include BreadcrumbHelper 10 | include DisplayHelper 11 | include MethodOrProcHelper 12 | include SidebarHelper 13 | include FormHelper 14 | include TitleHelper 15 | include ViewFactoryHelper 16 | include FlashHelper 17 | include ScopeNameHelper 18 | 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/generators/active_admin/install/templates/migrations/create_active_admin_comments.rb.erb: -------------------------------------------------------------------------------- 1 | class CreateActiveAdminComments < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version.to_s %>] 2 | def self.up 3 | create_table :active_admin_comments do |t| 4 | t.string :namespace 5 | t.text :body 6 | t.references :resource, polymorphic: true 7 | t.references :author, polymorphic: true 8 | t.timestamps 9 | end 10 | add_index :active_admin_comments, [:namespace] 11 | end 12 | 13 | def self.down 14 | drop_table :active_admin_comments 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/unit/filters/active_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe ActiveAdmin::Filters::Active do 4 | 5 | let(:resource) do 6 | namespace = ActiveAdmin::Namespace.new(ActiveAdmin::Application.new, :admin) 7 | namespace.register(Post) 8 | end 9 | 10 | subject { described_class.new(resource, search) } 11 | 12 | let(:params) do 13 | ::ActionController::Parameters.new(q: {author_id_eq: 1}) 14 | end 15 | 16 | let(:search) do 17 | Post.ransack(params[:q]) 18 | end 19 | 20 | it 'should have filters' do 21 | expect(subject.filters.size).to eq(1) 22 | end 23 | 24 | end 25 | -------------------------------------------------------------------------------- /docs/_includes/google-analytics.html: -------------------------------------------------------------------------------- 1 | 17 | -------------------------------------------------------------------------------- /features/step_definitions/dashboard_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^I should see the default welcome message$/ do 2 | step %{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 | step %{I should not see "Welcome to Active Admin"} 7 | end 8 | 9 | Then /^I should see a dashboard widget "([^"]*)"$/ do |name| 10 | expect(page).to have_css '.dashboard .panel h3', text: name 11 | end 12 | 13 | Then /^I should not see a dashboard widget "([^"]*)"$/ do |name| 14 | expect(page).to_not have_css '.dashboard .panel h3', text: name 15 | end 16 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/structure/_main_structure.scss: -------------------------------------------------------------------------------- 1 | #wrapper { 2 | width: 100%; 3 | } 4 | 5 | .index #wrapper { 6 | display: table; 7 | } 8 | 9 | #active_admin_content { 10 | margin: 0; 11 | padding: $horizontal-page-margin; 12 | 13 | #main_content_wrapper { 14 | float: left; 15 | width: 100%; 16 | 17 | #main_content{ 18 | margin-right: 300px; 19 | } 20 | } 21 | 22 | &.without_sidebar #main_content_wrapper #main_content{ margin-right: 0; } 23 | 24 | #sidebar { 25 | float: left; 26 | width: $sidebar-width; 27 | margin-left: -$sidebar-width; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Mac 2 | .DS_Store 3 | 4 | ## Windows 5 | .Thumbs.db 6 | 7 | ## TextMate 8 | *.tm_project 9 | *.tmproj 10 | tmtags 11 | 12 | ## Emacs 13 | *~ 14 | \#* 15 | .\#* 16 | 17 | ## Vim 18 | *.swp 19 | # IDEA / RUBYMINE 20 | .idea 21 | 22 | ## RVM 23 | .rvmrc 24 | .ruby-version 25 | .ruby-gemset 26 | 27 | ## Project (general) 28 | tags 29 | tmp 30 | coverage 31 | rdoc 32 | doc 33 | .yardoc 34 | pkg 35 | 36 | ## Project (specific) 37 | .bundle 38 | spec/rails 39 | *.sqlite3-journal 40 | .test-rails-apps 41 | public 42 | .rspec_failures 43 | .rails-version 44 | .rbenv-version 45 | .localeapp/* 46 | lib/bug_report_templates/tmp 47 | -------------------------------------------------------------------------------- /spec/javascripts/fixtures/table_checkboxes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
5 | 6 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /spec/unit/authorization/index_overriding_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe 'Index overriding', type: :controller do 4 | before do 5 | load_resources { ActiveAdmin.register Post } 6 | @controller = Admin::PostsController.new 7 | 8 | @controller.instance_eval do 9 | def index 10 | super do 11 | render body: 'Rendered from passed block' 12 | return 13 | end 14 | end 15 | end 16 | end 17 | 18 | it 'should call block passed to overridden index' do 19 | get :index 20 | expect(response.body).to eq 'Rendered from passed block' 21 | end 22 | 23 | end 24 | -------------------------------------------------------------------------------- /lib/active_admin/resource/pagination.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | 3 | class Resource 4 | module Pagination 5 | 6 | # The default number of records to display per page 7 | attr_accessor :per_page 8 | 9 | # The default number of records to display per page 10 | attr_accessor :max_per_page 11 | 12 | # Enable / disable pagination (defaults to true) 13 | attr_accessor :paginate 14 | 15 | def initialize(*args) 16 | super 17 | @paginate = true 18 | @per_page = namespace.default_per_page 19 | @max_per_page = namespace.max_per_page 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/unit/views/components/sidebar_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe ActiveAdmin::Views::Sidebar do 4 | 5 | let(:section) do 6 | ActiveAdmin::SidebarSection.new("Section") do 7 | para 'Section content.' 8 | end 9 | end 10 | 11 | let(:html) do 12 | render_arbre_component sections: [section] do 13 | sidebar assigns[:sections], id: 'sidebar' 14 | end 15 | end 16 | 17 | it "should have an id of 'sidebar'" do 18 | expect(html.id).to eq 'sidebar' 19 | end 20 | 21 | it "renders the section" do 22 | expect(html.find_by_tag('p').first.content).to eq 'Section content.' 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/jquery-ui/escape-selector.js: -------------------------------------------------------------------------------- 1 | //= require jquery-ui/version 2 | 3 | ( function( factory ) { 4 | if ( typeof define === "function" && define.amd ) { 5 | 6 | // AMD. Register as an anonymous module. 7 | define( [ "jquery", "./version" ], factory ); 8 | } else { 9 | 10 | // Browser globals 11 | factory( jQuery ); 12 | } 13 | } ( function( $ ) { 14 | 15 | // Internal use only 16 | return $.ui.escapeSelector = ( function() { 17 | var selectorEscape = /([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g; 18 | return function( selector ) { 19 | return selector.replace( selectorEscape, "\\$1" ); 20 | }; 21 | } )(); 22 | 23 | } ) ); 24 | -------------------------------------------------------------------------------- /spec/support/templates/post_decorator.rb: -------------------------------------------------------------------------------- 1 | require 'draper' 2 | 3 | class PostDecorator < Draper::Decorator 4 | decorates :post 5 | delegate_all 6 | 7 | # @param attributes [Hash] 8 | def assign_attributes(attributes) 9 | object.assign_attributes attributes.except(:virtual_title) 10 | self.virtual_title = attributes.fetch(:virtual_title) if attributes.key?(:virtual_title) 11 | end 12 | 13 | def virtual_title 14 | object.title 15 | end 16 | 17 | def virtual_title=(virtual_title) 18 | object.title = virtual_title 19 | end 20 | 21 | def decorator_method 22 | 'A method only available on the decorator' 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /app/views/active_admin/devise/unlocks/new.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

<%= active_admin_application.site_title(self) %> <%= title t('active_admin.devise.unlock.title') %>

3 | 4 | <%= devise_error_messages! %> 5 | <%= active_admin_form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| 6 | f.inputs do 7 | f.input :email 8 | end 9 | f.actions do 10 | f.action :submit, label: t('active_admin.devise.unlock.submit'), button_html: { value: t('active_admin.devise.unlock.submit') } 11 | end 12 | end %> 13 | 14 | <%= render partial: "active_admin/devise/shared/links" %> 15 |
16 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/jquery-ui/safe-blur.js: -------------------------------------------------------------------------------- 1 | //= require jquery-ui/version 2 | 3 | ( function( factory ) { 4 | if ( typeof define === "function" && define.amd ) { 5 | 6 | // AMD. Register as an anonymous module. 7 | define( [ "jquery", "./version" ], factory ); 8 | } else { 9 | 10 | // Browser globals 11 | factory( jQuery ); 12 | } 13 | } ( function( $ ) { 14 | return $.ui.safeBlur = function( element ) { 15 | 16 | // Support: IE9 - 10 only 17 | // If the is blurred, IE will switch windows, see #9420 18 | if ( element && element.nodeName.toLowerCase() !== "body" ) { 19 | $( element ).trigger( "blur" ); 20 | } 21 | }; 22 | 23 | } ) ); 24 | -------------------------------------------------------------------------------- /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 | Arbre::Context.new({}, self) do 7 | active_admin_form_for resource, options, &block 8 | end.content 9 | end 10 | 11 | def hidden_field_tags_for(params, options = {}) 12 | fields_for_params(params.to_unsafe_hash, options).map do |kv| 13 | k, v = kv.first 14 | hidden_field_tag k, v, id: sanitize_to_id("hidden_active_admin_#{k}") 15 | end.join("\n").html_safe 16 | end 17 | 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /features/step_definitions/footer_steps.rb: -------------------------------------------------------------------------------- 1 | Around '@footer' do |scenario, block| 2 | previous_footer = ActiveAdmin.application.footer 3 | 4 | begin 5 | block.call 6 | ensure 7 | ActiveAdmin.application.footer = previous_footer 8 | end 9 | end 10 | 11 | Then /^I should see the default footer$/ do 12 | expect(page).to have_css '#footer', text: "Powered by Active Admin #{ActiveAdmin::VERSION}" 13 | end 14 | 15 | Then /^I should see the footer "([^"]*)"$/ do |footer| 16 | expect(page).to have_css '#footer', text: footer 17 | end 18 | 19 | Then /^I should not see the footer "([^"]*)"$/ do |footer| 20 | expect(page).to_not have_css '#footer', text: footer 21 | end 22 | -------------------------------------------------------------------------------- /lib/generators/active_admin/install/templates/admin_users.rb.erb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register <%= @user_class %> do 2 | permit_params :email, :password, :password_confirmation 3 | 4 | index do 5 | selectable_column 6 | id_column 7 | column :email 8 | column :current_sign_in_at 9 | column :sign_in_count 10 | column :created_at 11 | actions 12 | end 13 | 14 | filter :email 15 | filter :current_sign_in_at 16 | filter :sign_in_count 17 | filter :created_at 18 | 19 | form do |f| 20 | f.inputs do 21 | f.input :email 22 | f.input :password 23 | f.input :password_confirmation 24 | end 25 | f.actions 26 | end 27 | 28 | end 29 | -------------------------------------------------------------------------------- /docs/images/tidelift.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/views/active_admin/devise/passwords/new.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

<%= active_admin_application.site_title(self) %> <%= title t('active_admin.devise.reset_password.title') %>

3 | 4 | <%= devise_error_messages! %> 5 | <%= active_admin_form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| 6 | f.inputs do 7 | f.input :email 8 | end 9 | f.actions do 10 | f.action :submit, label: t('active_admin.devise.reset_password.submit'), button_html: { value: t('active_admin.devise.reset_password.submit') } 11 | end 12 | end %> 13 | 14 | <%= render partial: "active_admin/devise/shared/links" %> 15 |
16 | -------------------------------------------------------------------------------- /lib/active_admin/inputs/filters/text_input.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Inputs 3 | module Filters 4 | class TextInput < ::Formtastic::Inputs::TextInput 5 | include Base 6 | include Base::SearchMethodSelect 7 | 8 | def input_html_options 9 | { 10 | cols: builder.default_text_area_width, 11 | rows: builder.default_text_area_height 12 | }.merge(super) 13 | end 14 | 15 | def to_html 16 | input_wrapping do 17 | label_html << 18 | builder.text_area(method, input_html_options) 19 | end 20 | end 21 | 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/requests/memory_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe "Memory Leak", type: :request, if: RUBY_ENGINE == 'ruby' do 4 | before do 5 | load_defaults! 6 | end 7 | 8 | def count_instances_of(klass) 9 | ObjectSpace.each_object(klass) { } 10 | end 11 | 12 | [ActiveAdmin::Namespace, ActiveAdmin::Resource].each do |klass| 13 | it "should not leak #{klass}" do 14 | previously_disabled = GC.enable 15 | GC.start 16 | count = count_instances_of(klass) 17 | 18 | load_defaults! 19 | 20 | GC.start 21 | GC.disable if previously_disabled 22 | expect(count_instances_of klass).to be <= count 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /features/step_definitions/asset_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^I should see the css file "([^"]*)"$/ do |path| 2 | step %{I should see the css file "#{path}" of media "screen"} 3 | end 4 | 5 | Then /^I should see the css file "([^"]*)" of media "([^"]*)"$/ do |path, media| 6 | expect(page).to have_xpath("//link[contains(@href, '#{path}') and contains(@media, '#{media}')]", visible: false) 7 | end 8 | 9 | Then /^I should see the js file "([^"]*)"$/ do |path| 10 | expect(page).to have_xpath("//script[contains(@src, '#{path}')]", visible: false) 11 | end 12 | 13 | Then /^I should see the favicon "([^"]*)"$/ do |path| 14 | expect(page).to have_xpath("//link[contains(@href, '#{path}')]", visible: false) 15 | end 16 | -------------------------------------------------------------------------------- /lib/active_admin/inputs/filters/boolean_input.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Inputs 3 | module Filters 4 | class BooleanInput < ::Formtastic::Inputs::SelectInput 5 | include Base 6 | 7 | def input_name 8 | return method if seems_searchable? 9 | 10 | "#{method}_eq" 11 | end 12 | 13 | def input_html_options_name 14 | "#{object_name}[#{input_name}]" # was "#{object_name}[#{association_primary_key}]" 15 | end 16 | 17 | # Provide the AA translation to the blank input field. 18 | def include_blank 19 | I18n.t 'active_admin.any' if super 20 | end 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /lib/generators/active_admin/assets/templates/active_admin.scss: -------------------------------------------------------------------------------- 1 | // SASS variable overrides must be declared before loading up Active Admin's styles. 2 | // 3 | // To view the variables that Active Admin provides, take a look at 4 | // `app/assets/stylesheets/active_admin/mixins/_variables.scss` in the 5 | // Active Admin source. 6 | // 7 | // For example, to change the sidebar width: 8 | // $sidebar-width: 242px; 9 | 10 | // Active Admin's got SASS! 11 | @import "active_admin/mixins"; 12 | @import "active_admin/base"; 13 | 14 | // Overriding any non-variable SASS must be done after the fact. 15 | // For example, to change the default status-tag color: 16 | // 17 | // .status_tag { background: #6090DB; } 18 | -------------------------------------------------------------------------------- /lib/active_admin/resource/sidebars.rb: -------------------------------------------------------------------------------- 1 | require 'active_admin/helpers/optional_display' 2 | 3 | module ActiveAdmin 4 | 5 | class Resource 6 | module Sidebars 7 | 8 | def sidebar_sections 9 | @sidebar_sections ||= [] 10 | end 11 | 12 | def clear_sidebar_sections! 13 | @sidebar_sections = [] 14 | end 15 | 16 | def sidebar_sections_for(action, render_context = nil) 17 | sidebar_sections.select{|section| section.display_on?(action, render_context) } 18 | .sort_by(&:priority) 19 | end 20 | 21 | def sidebar_sections? 22 | !!@sidebar_sections && @sidebar_sections.any? 23 | end 24 | 25 | end 26 | end 27 | 28 | end 29 | -------------------------------------------------------------------------------- /lib/active_admin/filters/dsl.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Filters 3 | module DSL 4 | 5 | # For docs, please see ActiveAdmin::Filters::ResourceExtension#add_filter 6 | def filter(attribute, options = {}) 7 | config.add_filter(attribute, options) 8 | end 9 | 10 | # For docs, please see ActiveAdmin::Filters::ResourceExtension#remove_filter 11 | def remove_filter(*attributes) 12 | config.remove_filter(*attributes) 13 | end 14 | 15 | # For docs, please see ActiveAdmin::Filters::ResourceExtension#preserve_default_filters! 16 | def preserve_default_filters! 17 | config.preserve_default_filters! 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /spec/unit/resource/includes_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | module ActiveAdmin 4 | RSpec.describe Resource, "Includes" do 5 | describe "#includes" do 6 | 7 | let(:application) { ActiveAdmin::Application.new } 8 | let(:namespace) { ActiveAdmin::Namespace.new application, :admin } 9 | let(:resource_config) { ActiveAdmin::Resource.new namespace, Post } 10 | let(:dsl){ ActiveAdmin::ResourceDSL.new(resource_config) } 11 | 12 | it "should register the includes in the config" do 13 | dsl.run_registration_block do 14 | includes :taggings, :author 15 | end 16 | expect(resource_config.includes.size).to eq(2) 17 | end 18 | 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/mixins/_rounded.scss: -------------------------------------------------------------------------------- 1 | @mixin rounded($radius: 3px) { 2 | border-radius: $radius; 3 | } 4 | 5 | @mixin rounded-all($top-left:3px, $top-right:3px, $bottom-right:3px, $bottom-left:3px) { 6 | border-top-right-radius: $top-right; 7 | border-top-left-radius: $top-left; 8 | border-bottom-right-radius: $bottom-right; 9 | border-bottom-left-radius: $bottom-left; 10 | } 11 | 12 | @mixin rounded-top($radius: 3px) { 13 | @include rounded(0); 14 | border-top-right-radius: $radius; 15 | border-top-left-radius: $radius; 16 | } 17 | 18 | @mixin rounded-bottom($radius: 3px) { 19 | @include rounded(0); 20 | border-bottom-right-radius: $radius; 21 | border-bottom-left-radius: $radius; 22 | } 23 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/jquery-ui/form.js: -------------------------------------------------------------------------------- 1 | //= require jquery-ui/version 2 | 3 | ( function( factory ) { 4 | if ( typeof define === "function" && define.amd ) { 5 | 6 | // AMD. Register as an anonymous module. 7 | define( [ "jquery", "./version" ], factory ); 8 | } else { 9 | 10 | // Browser globals 11 | factory( jQuery ); 12 | } 13 | } ( function( $ ) { 14 | 15 | // Support: IE8 Only 16 | // IE8 does not support the form attribute and when it is supplied. It overwrites the form prop 17 | // with a string, so we need to find the proper form. 18 | return $.fn.form = function() { 19 | return typeof this[ 0 ].form === "string" ? this.closest( "form" ) : $( this[ 0 ].form ); 20 | }; 21 | 22 | } ) ); 23 | -------------------------------------------------------------------------------- /spec/unit/settings_node_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe ActiveAdmin::SettingsNode do 4 | subject { ActiveAdmin::SettingsNode.build } 5 | let!(:child) { ActiveAdmin::SettingsNode.build(subject) } 6 | 7 | context 'parent setting includes foo' do 8 | before { subject.register :foo, true } 9 | 10 | it 'returns parent settings' do 11 | expect(child.foo).to eq true 12 | end 13 | 14 | it 'fails if setting undefined' do 15 | expect do 16 | child.bar 17 | end.to raise_error(NoMethodError) 18 | end 19 | 20 | context 'child overrides foo' do 21 | before { child.foo = false } 22 | 23 | it { expect(child.foo).to eq false } 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/generators/active_admin/resource/resource_generator.rb: -------------------------------------------------------------------------------- 1 | require 'active_admin/generators/boilerplate' 2 | 3 | module ActiveAdmin 4 | module Generators 5 | class ResourceGenerator < Rails::Generators::NamedBase 6 | desc "Registers resources with Active Admin" 7 | 8 | class_option :include_boilerplate, type: :boolean, default: false, 9 | desc: "Generate boilerplate code for your resource." 10 | 11 | source_root File.expand_path("../templates", __FILE__) 12 | 13 | def generate_config_file 14 | @boilerplate = ActiveAdmin::Generators::Boilerplate.new(class_name) 15 | template "admin.rb.erb", "app/admin/#{file_path.tr('/', '_').pluralize}.rb" 16 | end 17 | 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /app/views/active_admin/devise/confirmations/new.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

<%= active_admin_application.site_title(self) %> <%= title t('active_admin.devise.resend_confirmation_instructions.title') %>

3 | 4 | <%= devise_error_messages! %> 5 | <%= active_admin_form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| 6 | f.inputs do 7 | f.input :email 8 | end 9 | f.actions do 10 | f.action :submit, label: t('active_admin.devise.resend_confirmation_instructions.submit'), button_html: { value: t('active_admin.devise.resend_confirmation_instructions.submit') } 11 | end 12 | end %> 13 | 14 | <%= render partial: "active_admin/devise/shared/links" %> 15 |
16 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/components/_blank_slates.scss: -------------------------------------------------------------------------------- 1 | .blank_slate_container { 2 | clear: both; 3 | text-align: center; 4 | 5 | .blank_slate { 6 | @include rounded; 7 | border: $blank-slate-border; 8 | color: $blank-slate-primary-color; 9 | display: inline-block; 10 | font-size: 1.2em; 11 | font-weight: bold; 12 | padding: 14px 25px; 13 | text-align: center; 14 | 15 | small { 16 | display: block; 17 | font-size: 0.9em; 18 | font-weight: normal; 19 | } 20 | } 21 | } 22 | 23 | .admin_dashboard .blank_slate_container .blank_slate { 24 | margin-top: 40px; 25 | margin-bottom: 40px; 26 | } 27 | 28 | .with_sidebar .blank_slate_container .blank_slate { 29 | margin-top: 80px; 30 | } 31 | -------------------------------------------------------------------------------- /lib/active_admin/views/footer.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Views 3 | class Footer < Component 4 | 5 | def build(namespace) 6 | super id: "footer" 7 | @namespace = namespace 8 | 9 | if footer_text.present? 10 | para footer_text 11 | else 12 | para powered_by_message 13 | end 14 | end 15 | 16 | private 17 | 18 | def footer_text 19 | @footer_text ||= @namespace.footer(self) 20 | end 21 | 22 | def powered_by_message 23 | I18n.t('active_admin.powered_by', 24 | active_admin: link_to("Active Admin", "https://activeadmin.info"), 25 | version: ActiveAdmin::VERSION).html_safe 26 | end 27 | 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /docs/_includes/top-menu.html: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /spec/bug_report_templates_spec.rb: -------------------------------------------------------------------------------- 1 | require 'open3' 2 | 3 | RSpec.describe 'bug_report_templates' do 4 | subject do 5 | Bundler.with_original_env do 6 | Dir.chdir(chdir_path) do 7 | Open3.capture2e( 8 | {'ACTIVE_ADMIN_PATH' => active_admin_root}, 9 | Gem.ruby, 10 | template_path 11 | )[1] 12 | end 13 | end 14 | end 15 | 16 | let(:active_admin_root) { File.expand_path('../..', __FILE__) } 17 | let(:chdir_path) { File.join(active_admin_root, 'lib', 'bug_report_templates') } 18 | 19 | context 'when runs active_admin_master.rb' do 20 | let(:template_path) { 'active_admin_master.rb' } 21 | 22 | it 'passes' do 23 | expect(subject).to be_truthy 24 | end 25 | end 26 | 27 | end 28 | -------------------------------------------------------------------------------- /spec/gemfiles_spec.lint.rb: -------------------------------------------------------------------------------- 1 | require "open3" 2 | 3 | RSpec.describe "Gemfile sanity" do 4 | shared_examples_for "a sane gemfile" do |gemfile| 5 | it "is up to date" do 6 | current_lockfile = File.read("#{gemfile}.lock") 7 | 8 | new_lockfile = Bundler.with_original_env do 9 | `BUNDLE_GEMFILE=#{gemfile} bundle lock --print` 10 | end 11 | 12 | msg = "Please update #{gemfile}'s lock file with `BUNDLE_GEMFILE=#{gemfile} bundle install` and commit the result" 13 | 14 | expect(current_lockfile).to eq(new_lockfile), msg 15 | end 16 | end 17 | 18 | it_behaves_like "a sane gemfile", "Gemfile" 19 | 20 | Dir.glob("gemfiles/*.gemfile").each do |gemfile| 21 | it_behaves_like "a sane gemfile", gemfile 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/active_admin/page_controller.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | 3 | # All Pages controllers inherit from this controller. 4 | class PageController < BaseController 5 | 6 | # Active admin actions don't require layout. All custom actions do. 7 | ACTIVE_ADMIN_ACTIONS = [:index] 8 | 9 | actions :index 10 | 11 | before_action :authorize_access! 12 | 13 | def index(options = {}, &block) 14 | render "active_admin/page/index" 15 | end 16 | 17 | def clear_page_actions! 18 | active_admin_config.clear_page_actions! 19 | end 20 | 21 | private 22 | 23 | def authorize_access! 24 | permission = action_to_permission(params[:action]) 25 | authorize! permission, active_admin_config 26 | end 27 | 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/active_admin/views/pages/page.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Views 3 | module Pages 4 | class Page < Base 5 | 6 | def main_content 7 | if page_presenter.block 8 | instance_exec &page_presenter.block 9 | else 10 | nil 11 | end 12 | end 13 | 14 | protected 15 | 16 | def page_presenter 17 | active_admin_config.get_page_presenter(:index) || ActiveAdmin::PagePresenter.new 18 | end 19 | 20 | def title 21 | if page_presenter[:title] 22 | render_or_call_method_or_proc_on self, page_presenter[:title] 23 | else 24 | active_admin_config.name 25 | end 26 | end 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /lib/active_admin/batch_actions.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.before_load do |app| 2 | require "active_admin/batch_actions/resource_extension" 3 | require "active_admin/batch_actions/controller" 4 | 5 | # Add our Extensions 6 | ActiveAdmin::Resource.send :include, ActiveAdmin::BatchActions::ResourceExtension 7 | ActiveAdmin::ResourceController.send :include, ActiveAdmin::BatchActions::Controller 8 | 9 | # Require all the views 10 | require "active_admin/batch_actions/views/batch_action_form" 11 | require "active_admin/batch_actions/views/selection_cells" 12 | require "active_admin/batch_actions/views/batch_action_selector" 13 | 14 | # Register the views with the view factory 15 | app.view_factory.register batch_action_selector: ActiveAdmin::BatchActions::BatchActionSelector 16 | end 17 | -------------------------------------------------------------------------------- /lib/active_admin/engine.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | class Engine < ::Rails::Engine 3 | initializer "active_admin.load_app_path" do |app| 4 | ActiveAdmin::Application.setting :app_path, app.root 5 | ActiveAdmin::Application.setting :load_paths, [File.expand_path('app/admin', app.root)] 6 | end 7 | 8 | initializer "active_admin.precompile", group: :all do |app| 9 | ActiveAdmin.application.stylesheets.each do |path, _| 10 | app.config.assets.precompile << path 11 | end 12 | ActiveAdmin.application.javascripts.each do |path| 13 | app.config.assets.precompile << path 14 | end 15 | end 16 | 17 | initializer 'active_admin.routes' do 18 | require 'active_admin/helpers/routes/url_helpers' 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /spec/changelog_spec.lint.rb: -------------------------------------------------------------------------------- 1 | SimpleCov.command_name "lint" 2 | 3 | RSpec.describe "Changelog" do 4 | subject(:changelog) do 5 | path = File.join(File.dirname(__dir__), "CHANGELOG.md") 6 | File.read(path) 7 | end 8 | 9 | it 'has definitions for all implicit links' do 10 | implicit_link_names = changelog.scan(/\[([^\]]+)\]\[\]/).flatten.uniq 11 | implicit_link_names.each do |name| 12 | expect(changelog).to include("[#{name}]: https") 13 | end 14 | end 15 | 16 | describe 'entry' do 17 | let(:lines) { changelog.each_line } 18 | 19 | subject(:entries) { lines.grep(/^\*/) } 20 | 21 | it 'does not end with a punctuation' do 22 | entries.each do |entry| 23 | expect(entry).not_to match(/\.$/) 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /features/meta_tags.feature: -------------------------------------------------------------------------------- 1 | Feature: Meta Tag 2 | 3 | Add custom meta tags to head of pages. 4 | 5 | Background: 6 | Given a configuration of: 7 | """ 8 | ActiveAdmin.register Post 9 | ActiveAdmin.application.meta_tags = { author: 'My Company' } 10 | ActiveAdmin.application.meta_tags_for_logged_out_pages = { robots: 'noindex' } 11 | """ 12 | 13 | Scenario: Logged out views include custom meta tags 14 | Given I am logged out 15 | When I am on the login page 16 | Then the site should contain a meta tag with name "robots" and content "noindex" 17 | 18 | Scenario: Logged in views include custom meta tags 19 | Given I am logged in 20 | When I am on the dashboard 21 | Then the site should contain a meta tag with name "author" and content "My Company" 22 | -------------------------------------------------------------------------------- /lib/active_admin/orm/active_record/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 | -------------------------------------------------------------------------------- /lib/active_admin/resource_controller/resource_class_methods.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | class ResourceController < BaseController 3 | module ResourceClassMethods 4 | 5 | # Override the default `resource_class` class and instance 6 | # methods to only return the class defined in the instance 7 | # of ActiveAdmin::Resource 8 | def override_resource_class_methods! 9 | class_exec do 10 | def self.resource_class=(klass); end 11 | 12 | def self.resource_class 13 | @active_admin_config ? @active_admin_config.resource_class : nil 14 | end 15 | 16 | private 17 | 18 | def resource_class 19 | self.class.resource_class 20 | end 21 | end 22 | end 23 | 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/ransack_ext.rb: -------------------------------------------------------------------------------- 1 | # This sets up aliases for old Metasearch query methods so they behave 2 | # identically to the versions given in Ransack. 3 | # 4 | Ransack.configure do |config| 5 | {'contains'=>'cont', 'starts_with'=>'start', 'ends_with'=>'end'}.each do |old, current| 6 | config.add_predicate old, Ransack::Constants::DERIVED_PREDICATES.detect{ |q, _| q == current }[1] 7 | end 8 | 9 | {'equals'=>'eq', 'greater_than'=>'gt', 'less_than'=>'lt'}.each do |old, current| 10 | config.add_predicate old, arel_predicate: current 11 | end 12 | 13 | config.add_predicate 'gteq_datetime', 14 | arel_predicate: 'gteq', 15 | formatter: ->(v) { v.beginning_of_day } 16 | 17 | config.add_predicate 'lteq_datetime', 18 | arel_predicate: 'lt', 19 | formatter: ->(v) { v + 1.day } 20 | end 21 | -------------------------------------------------------------------------------- /app/assets/javascripts/active_admin/base.es6: -------------------------------------------------------------------------------- 1 | //= require jquery3 2 | //= require jquery-ui/widgets/datepicker 3 | //= require jquery-ui/widgets/dialog 4 | //= require jquery-ui/widgets/sortable 5 | //= require jquery-ui/widgets/tabs 6 | //= require jquery-ui/widget 7 | //= require jquery_ujs 8 | //= require_self 9 | //= require ./ext/jquery 10 | //= require ./ext/jquery-ui 11 | //= require ./lib/active_admin 12 | //= require ./lib/batch_actions 13 | //= require ./lib/dropdown-menu 14 | //= require ./lib/has_many 15 | //= require ./lib/modal_dialog 16 | //= require ./lib/per_page 17 | //= require ./lib/checkbox-toggler 18 | //= require ./lib/table-checkbox-toggler 19 | //= require ./initializers/datepicker 20 | //= require ./initializers/filters 21 | //= require ./initializers/tabs 22 | 23 | window.ActiveAdmin = {} 24 | -------------------------------------------------------------------------------- /features/step_definitions/action_link_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^I should see a member link to "([^"]*)"$/ do |name| 2 | expect(page).to have_css('a.member_link', text: name) 3 | end 4 | 5 | Then /^I should not see a member link to "([^"]*)"$/ do |name| 6 | %{Then I should not see "#{name}" within "a.member_link"} 7 | end 8 | 9 | Then /^I should see the actions column with the class "([^"]*)" and the title "([^"]*)"$/ do |klass, title| 10 | expect(page).to have_css "th#{'.'+klass}", text: title 11 | end 12 | 13 | Then /^I should see a dropdown menu item to "([^"]*)"$/ do |name| 14 | expect(page).to have_css('ul.dropdown_menu_list li a', text: name) 15 | end 16 | 17 | Then /^I should not see a dropdown menu item to "([^"]*)"$/ do |name| 18 | %{Then I should not see "#{name}" within "ul.dropdown_menu_list li a"} 19 | end 20 | -------------------------------------------------------------------------------- /lib/active_admin/helpers/scope_chain.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module ScopeChain 3 | private 4 | # Scope an ActiveRecord::Relation chain 5 | # 6 | # Example: 7 | # scope_chain(Scope.new(:published), Article) 8 | # # => Article.published 9 | # 10 | # @param scope The we want to scope on 11 | # @param chain The ActiveRecord::Relation chain or ActiveRecord::Base class to scope 12 | # @return The scoped relation chain 13 | # 14 | def scope_chain(scope, chain) 15 | if scope.scope_method 16 | chain.public_send scope.scope_method 17 | elsif scope.scope_block 18 | instance_exec chain, &scope.scope_block 19 | else 20 | chain 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /lib/active_admin/dynamic_settings_node.rb: -------------------------------------------------------------------------------- 1 | require 'active_admin/dynamic_setting' 2 | require 'active_admin/settings_node' 3 | 4 | module ActiveAdmin 5 | 6 | class DynamicSettingsNode < SettingsNode 7 | class << self 8 | def register(name, value, type = nil) 9 | class_attribute "#{name}_setting" 10 | add_reader(name) 11 | add_writer(name, type) 12 | send "#{name}=", value 13 | end 14 | 15 | def add_reader(name) 16 | define_singleton_method(name) do |*args| 17 | send("#{name}_setting").value(*args) 18 | end 19 | end 20 | 21 | def add_writer(name, type) 22 | define_singleton_method("#{name}=") do |value| 23 | send("#{name}_setting=", DynamicSetting.build(value, type)) 24 | end 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/active_admin/page_presenter.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | 3 | # A simple object that gets used to present different aspects of views 4 | # 5 | # Initialize with a set of options and a block. The options become 6 | # available using hash style syntax. 7 | # 8 | # Usage: 9 | # 10 | # presenter = PagePresenter.new as: :table do 11 | # # some awesome stuff 12 | # end 13 | # 14 | # presenter[:as] #=> :table 15 | # presenter.block #=> The block passed in to new 16 | # 17 | class PagePresenter 18 | 19 | attr_reader :block, :options 20 | 21 | delegate :has_key?, :fetch, to: :options 22 | 23 | def initialize(options = {}, &block) 24 | @options, @block = options, block 25 | end 26 | 27 | def [](key) 28 | @options[key] 29 | end 30 | 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /spec/unit/generators/install_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe "AA installation" do 4 | context "should create" do 5 | 6 | it "active_admin.scss" do 7 | path = Rails.root + "app/assets/stylesheets/active_admin.scss" 8 | 9 | expect(File.exist?(path)).to eq true 10 | end 11 | 12 | it "active_admin.js" do 13 | path = Rails.root + "app/assets/javascripts/active_admin.js" 14 | 15 | expect(File.exist?(path)).to eq true 16 | end 17 | 18 | it "the dashboard" do 19 | path = Rails.root + "app/admin/dashboard.rb" 20 | 21 | expect(File.exist?(path)).to eq true 22 | end 23 | 24 | it "the initializer" do 25 | path = Rails.root + "config/initializers/active_admin.rb" 26 | 27 | expect(File.exist?(path)).to eq true 28 | end 29 | 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /app/views/active_admin/devise/passwords/edit.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

<%= active_admin_application.site_title(self) %> <%= title t('active_admin.devise.change_password.title') %>

3 | 4 | <%= devise_error_messages! %> 5 | <%= active_admin_form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| 6 | f.inputs do 7 | f.input :password 8 | f.input :password_confirmation 9 | f.input :reset_password_token, as: :hidden, input_html: { value: resource.reset_password_token } 10 | end 11 | f.actions do 12 | f.action :submit, label: t('active_admin.devise.change_password.submit'), button_html: { value: t('active_admin.devise.change_password.submit') } 13 | end 14 | end 15 | %> 16 | 17 | <%= render 'active_admin/devise/shared/links' %> 18 |
19 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/mixins/_gradients.scss: -------------------------------------------------------------------------------- 1 | $secondary-gradient-start: #efefef !default; 2 | $secondary-gradient-stop: #dfe1e2 !default; 3 | 4 | @mixin gradient($start, $end){ 5 | background-color: $start; 6 | background-image: linear-gradient(180deg, $start, $end); 7 | } 8 | 9 | @mixin primary-gradient { 10 | @include gradient(lighten($primary-color, 5%), darken($primary-color, 7%)); 11 | border-bottom: 1px solid darken($primary-color, 11%); 12 | } 13 | 14 | @mixin secondary-gradient { 15 | @include gradient($secondary-gradient-start, $secondary-gradient-stop); 16 | } 17 | 18 | @mixin highlight-gradient { 19 | @include gradient(#75a1c2, #608cb4); 20 | } 21 | 22 | @mixin reverse-highlight-gradient { 23 | @include gradient(#608cb4, #75a1c2); 24 | } 25 | 26 | @mixin no-gradient { 27 | background-color: none; 28 | } 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | [Please follow the guidelines for creating a bug report](https://github.com/activeadmin/activeadmin/blob/master/CONTRIBUTING.md#4-did-you-find-a-bug). 2 | 3 | The issue tracker is only for bugs and feature requests. If you need general 4 | help please post to 5 | [StackOverflow](http://stackoverflow.com/questions/tagged/activeadmin). 6 | 7 | ### Expected behavior 8 | 9 | What do you think should happen? 10 | 11 | ### Actual behavior 12 | 13 | What actually happens? 14 | 15 | ### How to reproduce 16 | 17 | Your best chance of getting this bug looked at quickly is to provide an 18 | **executable test case** demonstrating the expected behavior that is not 19 | occurring. [Please follow the guidelines for creating a bug 20 | report](https://github.com/activeadmin/activeadmin/blob/master/CONTRIBUTING.md#4-did-you-find-a-bug). 21 | -------------------------------------------------------------------------------- /lib/active_admin/views/pages/layout.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Views 3 | module Pages 4 | 5 | # Acts as a standard Rails Layout for use when logged 6 | # out or when rendering custom actions. 7 | class Layout < Base 8 | 9 | def title 10 | assigns[:page_title] || I18n.t("active_admin.#{params[:action]}", default: params[:action].to_s.titleize) 11 | end 12 | 13 | # Render the content_for(:layout) into the main content area 14 | def main_content 15 | content_for_layout = content_for(:layout) 16 | if content_for_layout.is_a?(Arbre::Element) 17 | current_arbre_element.add_child content_for_layout.children 18 | else 19 | text_node content_for_layout 20 | end 21 | end 22 | end 23 | 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /spec/unit/view_factory_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | def it_should_have_view(key, value) 4 | it "should have #{value} for view key '#{key}'" do 5 | expect(subject.send(key)).to eq value 6 | end 7 | end 8 | 9 | RSpec.describe ActiveAdmin::ViewFactory do 10 | 11 | it_should_have_view :global_navigation, ActiveAdmin::Views::TabbedNavigation 12 | it_should_have_view :utility_navigation, ActiveAdmin::Views::TabbedNavigation 13 | it_should_have_view :site_title, ActiveAdmin::Views::SiteTitle 14 | it_should_have_view :action_items, ActiveAdmin::Views::ActionItems 15 | it_should_have_view :header, ActiveAdmin::Views::Header 16 | it_should_have_view :blank_slate, ActiveAdmin::Views::BlankSlate 17 | it_should_have_view :layout, ActiveAdmin::Views::Pages::Layout 18 | 19 | end 20 | -------------------------------------------------------------------------------- /tasks/local.rake: -------------------------------------------------------------------------------- 1 | require_relative "application_generator" 2 | 3 | desc 'Run a command against the local sample application' 4 | task :local do 5 | app_folder = ActiveAdmin::ApplicationGenerator.new( 6 | rails_env: 'development', 7 | template: 'rails_template_with_data' 8 | ).generate 9 | 10 | # Discard the "local" argument (name of the task) 11 | argv = ARGV[1..-1] 12 | 13 | # If it's a rails command, auto add the rails script 14 | if %w(generate console server db dbconsole g c s runner).include?(argv[0]) 15 | argv.unshift('rails') 16 | end 17 | 18 | command = ['bundle', 'exec', *argv].join(' ') 19 | gemfile = ENV['BUNDLE_GEMFILE'] || File.expand_path("../Gemfile", __dir__) 20 | env = { 'BUNDLE_GEMFILE' => gemfile } 21 | 22 | Dir.chdir(app_folder) do 23 | Bundler.with_original_env { Kernel.exec(env, command) } 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/active_admin/filters/active.rb: -------------------------------------------------------------------------------- 1 | require 'active_admin/filters/active_filter' 2 | 3 | module ActiveAdmin 4 | module Filters 5 | 6 | class Active 7 | attr_accessor :filters, :resource 8 | 9 | # Instantiate a `Active` object containing collection of current active filters 10 | 11 | # @param resource [ActiveAdmin::Resource] current resource 12 | # @param search [Ransack::Search] search object 13 | # 14 | # @see ActiveAdmin::ResourceController::DataAcces#apply_filtering 15 | def initialize(resource, search) 16 | @resource = resource 17 | @filters = build_filters(search.conditions) 18 | end 19 | 20 | private 21 | 22 | def build_filters(conditions) 23 | conditions.map { |condition| ActiveFilter.new(resource, condition.dup) } 24 | end 25 | 26 | end 27 | 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/active_admin/resource_controller/action_builder.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | class ResourceController < BaseController 3 | 4 | module ActionBuilder 5 | extend ActiveSupport::Concern 6 | 7 | module ClassMethods 8 | 9 | def clear_member_actions! 10 | remove_action_methods(:member) 11 | active_admin_config.clear_member_actions! 12 | end 13 | 14 | def clear_collection_actions! 15 | remove_action_methods(:collection) 16 | active_admin_config.clear_collection_actions! 17 | end 18 | 19 | private 20 | 21 | def remove_action_methods(actions_type) 22 | active_admin_config.public_send("#{actions_type}_actions").each do |action| 23 | remove_method action.name 24 | end 25 | end 26 | end 27 | 28 | end 29 | 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /docs/3-index-pages/index-as-grid.md: -------------------------------------------------------------------------------- 1 | --- 2 | redirect_from: /docs/3-index-pages/index-as-grid.html 3 | --- 4 | 5 | # Index as a Grid 6 | 7 | Sometimes you want to display the index screen for a set of resources as a grid 8 | (possibly a grid of thumbnail images). To do so, use the :grid option for the 9 | index block. 10 | 11 | ```ruby 12 | index as: :grid do |product| 13 | link_to image_tag(product.image_path), admin_product_path(product) 14 | end 15 | ``` 16 | 17 | The block is rendered within a cell in the grid once for each resource in the 18 | collection. The resource is passed into the block for you to use in the view. 19 | 20 | You can customize the number of columns that are rendered using the columns 21 | option: 22 | 23 | ```ruby 24 | index as: :grid, columns: 5 do |product| 25 | link_to image_tag(product.image_path), admin_product_path(product) 26 | end 27 | ``` 28 | -------------------------------------------------------------------------------- /lib/active_admin/inputs/filters/string_input.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Inputs 3 | module Filters 4 | class StringInput < ::Formtastic::Inputs::StringInput 5 | include Base 6 | include Base::SearchMethodSelect 7 | 8 | filter :contains, :equals, :starts_with, :ends_with 9 | 10 | # If the filter method includes a search condition, build a normal string search field. 11 | # Else, build a search field with a companion dropdown to choose a search condition from. 12 | def to_html 13 | if seems_searchable? 14 | input_wrapping do 15 | label_html << 16 | builder.text_field(method, input_html_options) 17 | end 18 | else 19 | super # SearchMethodSelect#to_html 20 | end 21 | end 22 | 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /spec/unit/views/components/blank_slate_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe ActiveAdmin::Views::BlankSlate do 4 | 5 | describe "#blank_slate" do 6 | subject do 7 | render_arbre_component do 8 | blank_slate("There are no Posts yet. Create one") 9 | end 10 | end 11 | 12 | describe '#tag_name' do 13 | subject { super().tag_name } 14 | it { is_expected.to eql 'div' } 15 | end 16 | 17 | describe '#class_list' do 18 | subject { super().class_list } 19 | it { is_expected.to include('blank_slate_container') } 20 | end 21 | 22 | describe '#content' do 23 | subject { super().content } 24 | it { is_expected.to include 'There are no Posts yet. Create one' } 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /features/step_definitions/attribute_steps.rb: -------------------------------------------------------------------------------- 1 | Then /^I should see the attribute "([^"]*)" with "([^"]*)"$/ do |title, value| 2 | elems = all ".attributes_table th:contains('#{title}') ~ td:contains('#{value}')" 3 | expect(elems.first).to_not eq(nil), "attribute missing" 4 | end 5 | 6 | Then /^I should see the attribute "([^"]*)" with a nicely formatted datetime$/ do |title| 7 | text = all(".attributes_table th:contains('#{title}') ~ td").first.text 8 | expect(text).to match /\w+ \d{1,2}, \d{4} \d{2}:\d{2}/ 9 | end 10 | 11 | Then /^the attribute "([^"]*)" should be empty$/ do |title| 12 | elems = all ".attributes_table th:contains('#{title}') ~ td > span.empty" 13 | expect(elems.first).to_not eq(nil), 'attribute not empty' 14 | end 15 | 16 | Then /^I should not see the attribute "([^"]*)"$/ do |title| 17 | expect(page).to_not have_css '.attributes_table th', text: title 18 | end 19 | -------------------------------------------------------------------------------- /lib/active_admin/inputs/datepicker_input.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Inputs 3 | class DatepickerInput < ::Formtastic::Inputs::StringInput 4 | def input_html_options 5 | super.tap do |options| 6 | options[:class] = [options[:class], "datepicker"].compact.join(' ') 7 | options[:data] ||= {} 8 | options[:data].merge! datepicker_options 9 | end 10 | end 11 | 12 | # Can pass proc to filter label option 13 | def label_from_options 14 | res = super 15 | res = res.call if res.is_a? Proc 16 | res 17 | end 18 | 19 | private 20 | def datepicker_options 21 | options = self.options.fetch(:datepicker_options, {}) 22 | options = Hash[options.map{ |k, v| [k.to_s.camelcase(:lower), v] }] 23 | { datepicker_options: options } 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/components/_modal_dialog.scss: -------------------------------------------------------------------------------- 1 | .ui-widget-overlay { 2 | position: fixed; 3 | background: rgba(0,0,0,.2); 4 | top: 0; left: 0; right: 0; bottom: 0; 5 | z-index: 1001; 6 | } 7 | 8 | .ui-dialog { 9 | position: fixed; 10 | z-index: 1002; 11 | @include section-background; 12 | box-shadow: rgba(0,0,0,0.5) 0 0 10px; 13 | 14 | .ui-dialog-titlebar { 15 | @include section-header; 16 | span { font-size: 1.1em } 17 | } 18 | 19 | ul { list-style-type: none } 20 | li { margin: 10px 0 } 21 | label { margin-right: 10px } 22 | 23 | .ui-dialog-buttonpane, form { 24 | padding: 7px 15px 13px 25 | } 26 | .ui-dialog-buttonpane button { 27 | & { @include dark-button } // OK 28 | &:last-child { @include light-button } // Cancel 29 | } 30 | } 31 | 32 | .active_admin_dialog.ui-dialog { 33 | .ui-dialog-titlebar-close { display: none } 34 | } 35 | -------------------------------------------------------------------------------- /features/show/columns.feature: -------------------------------------------------------------------------------- 1 | Feature: Show - Columns 2 | 3 | Columns in show page 4 | 5 | Background: 6 | Given a post with the title "Hello World" written by "Jane Doe" exists 7 | 8 | Scenario: 9 | Given a show configuration of: 10 | """ 11 | ActiveAdmin.register Post do 12 | 13 | show do 14 | columns do 15 | end 16 | end 17 | 18 | end 19 | """ 20 | Then I should see a columns container 21 | And I should see 0 column 22 | 23 | Scenario: 24 | Given a show configuration of: 25 | """ 26 | ActiveAdmin.register Post do 27 | 28 | show do 29 | columns do 30 | column do 31 | end 32 | column do 33 | end 34 | end 35 | end 36 | 37 | end 38 | """ 39 | Then I should see a columns container 40 | And I should see 2 columns 41 | -------------------------------------------------------------------------------- /spec/unit/dynamic_settings_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe ActiveAdmin::DynamicSettingsNode do 4 | subject { ActiveAdmin::DynamicSettingsNode.build } 5 | 6 | context "StringSymbolOrProcSetting" do 7 | before { subject.register :foo, 'bar', :string_symbol_or_proc } 8 | 9 | it "should pass through a string" do 10 | subject.foo = "string" 11 | expect(subject.foo(self)).to eq "string" 12 | end 13 | 14 | it "should instance_exec if context given" do 15 | ctx = Hash[i: 42] 16 | subject.foo = proc { self[:i] += 1 } 17 | expect(subject.foo(ctx)).to eq 43 18 | expect(subject.foo(ctx)).to eq 44 19 | end 20 | 21 | it "should send message if symbol given" do 22 | ctx = double 23 | expect(ctx).to receive(:quux).and_return 'qqq' 24 | subject.foo = :quux 25 | expect(subject.foo(ctx)).to eq 'qqq' 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/active_admin/page_dsl.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | # This is the class where all the register_page blocks are evaluated. 3 | class PageDSL < DSL 4 | 5 | # Page content. 6 | # 7 | # The block should define the view using Arbre. 8 | # 9 | # Example: 10 | # 11 | # ActiveAdmin.register "My Page" do 12 | # content do 13 | # para "Sweet!" 14 | # end 15 | # end 16 | # 17 | def content(options = {}, &block) 18 | config.set_page_presenter :index, ActiveAdmin::PagePresenter.new(options, &block) 19 | end 20 | 21 | def page_action(name, options = {}, &block) 22 | config.page_actions << ControllerAction.new(name, options) 23 | controller do 24 | define_method(name, &block || Proc.new{}) 25 | end 26 | end 27 | 28 | def belongs_to(target, options = {}) 29 | config.belongs_to(target, options) 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /spec/support/templates/policies/application_policy.rb: -------------------------------------------------------------------------------- 1 | class ApplicationPolicy 2 | attr_reader :user, :record 3 | 4 | def initialize(user, record) 5 | @user = user 6 | @record = record 7 | end 8 | 9 | def index? 10 | true 11 | end 12 | 13 | def show? 14 | scope.where(id: record.id).exists? 15 | end 16 | 17 | def new? 18 | create? 19 | end 20 | 21 | def create? 22 | true 23 | end 24 | 25 | def edit? 26 | update? 27 | end 28 | 29 | def update? 30 | true 31 | end 32 | 33 | def destroy? 34 | true 35 | end 36 | 37 | def destroy_all? 38 | true 39 | end 40 | 41 | def scope 42 | Pundit.policy_scope!(user, record.class) 43 | end 44 | 45 | class Scope 46 | attr_reader :user, :scope 47 | 48 | def initialize(user, scope) 49 | @user = user 50 | @scope = scope 51 | end 52 | 53 | def resolve 54 | scope 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /spec/i18n_spec.lint.rb: -------------------------------------------------------------------------------- 1 | require 'i18n/tasks' 2 | require 'i18n-spec' 3 | 4 | Dir.glob('config/locales/*.yml') do |locale_file| 5 | RSpec.describe locale_file do 6 | it { is_expected.to be_parseable } 7 | it { is_expected.to have_one_top_level_namespace } 8 | it { is_expected.to be_named_like_top_level_namespace } 9 | it { is_expected.to_not have_legacy_interpolations } 10 | it { is_expected.to have_a_valid_locale } 11 | it { is_expected.to be_a_subset_of 'config/locales/en.yml' } 12 | end 13 | end 14 | 15 | RSpec.describe 'I18n' do 16 | let(:i18n) { I18n::Tasks::BaseTask.new } 17 | let(:unused_keys) { i18n.unused_keys } 18 | let(:unused_key_count) { unused_keys.leaves.count } 19 | 20 | let(:failure_msg) do 21 | "#{unused_key_count} unused i18n keys, run `i18n-tasks unused' to show them" 22 | end 23 | 24 | it 'does not have unused keys' do 25 | expect(unused_keys).to be_empty, failure_msg 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/unit/namespace/authorization_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe ActiveAdmin::Resource, "authorization" do 4 | 5 | let(:app){ ActiveAdmin::Application.new } 6 | let(:namespace){ ActiveAdmin::Namespace.new(app, :admin) } 7 | let(:auth){ double } 8 | 9 | describe "authorization_adapter" do 10 | 11 | it "should return AuthorizationAdapter by default" do 12 | expect(app.authorization_adapter).to eq ActiveAdmin::AuthorizationAdapter 13 | expect(namespace.authorization_adapter).to eq ActiveAdmin::AuthorizationAdapter 14 | end 15 | 16 | it "should be settable on the namespace" do 17 | namespace.authorization_adapter = auth 18 | expect(namespace.authorization_adapter).to eq auth 19 | end 20 | 21 | it "should be settable on the application" do 22 | app.authorization_adapter = auth 23 | expect(app.authorization_adapter).to eq auth 24 | end 25 | 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/unit/view_helpers/flash_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe ActiveAdmin::ViewHelpers::FlashHelper do 4 | 5 | describe '.flash_messages' do 6 | let(:view) { mock_action_view } 7 | 8 | it "should not include 'timedout' flash messages by default" do 9 | view.request.flash[:alert] = "Alert" 10 | view.request.flash[:timedout] = true 11 | expect(view.flash_messages).to include 'alert' 12 | expect(view.flash_messages).to_not include 'timedout' 13 | end 14 | 15 | it "should not return flash messages included in flash_keys_to_except" do 16 | expect(view.active_admin_application).to receive(:flash_keys_to_except).and_return ["hideme"] 17 | view.request.flash[:alert] = "Alert" 18 | view.request.flash[:hideme] = "Do not show" 19 | expect(view.flash_messages).to include 'alert' 20 | expect(view.flash_messages).to_not include 'hideme' 21 | end 22 | 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # ActiveAdmin Documentation 2 | 3 | ## Content 4 | 5 | - [Installation](0-installation.md) 6 | - [General Configuration](1-general-configuration.md) 7 | - [Resource Customization](2-resource-customization.md) 8 | - [Index Pages](3-index-pages.md) 9 | - [Custom Index](3-index-pages/custom-index.md) 10 | - [Index as Table](3-index-pages/index-as-table.md) 11 | - [Index as Grid](3-index-pages/index-as-grid.md) 12 | - [Index as Blocks](3-index-pages/index-as-block.md) 13 | - [Index as Blog](3-index-pages/index-as-blog.md) 14 | - [Csv Format](4-csv-format.md) 15 | - [Forms](5-forms.md) 16 | - [Show Pages](6-show-pages.md) 17 | - [Sidebars](7-sidebars.md) 18 | - [Custom Actions](8-custom-actions.md) 19 | - [Batch Actions](9-batch-actions.md) 20 | - [Custom Pages](10-custom-pages.md) 21 | - [Decorators](11-decorators.md) 22 | - [Arbre Components](12-arbre-components.md) 23 | - [Authorization Adapter](13-authorization-adapter.md) 24 | - [Gotchas](14-gotchas.md) 25 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/structure/_title_bar.scss: -------------------------------------------------------------------------------- 1 | #title_bar { 2 | @include section-header; 3 | @include clearfix; 4 | box-sizing: border-box; 5 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.37); 6 | display: table; 7 | border-bottom-color: #EEE; 8 | width: 100%; 9 | position: relative; 10 | margin: 0; 11 | padding: 10px $horizontal-page-margin; 12 | z-index: 800; 13 | 14 | #titlebar_left, #titlebar_right { 15 | height: 50px; 16 | vertical-align: middle; 17 | display: table-cell; 18 | } 19 | 20 | #titlebar_right { 21 | text-align: right; 22 | } 23 | 24 | h2 { 25 | margin: 0; 26 | padding: 0; 27 | font-size: 2.6em; 28 | line-height: 100%; 29 | font-weight: bold; 30 | } 31 | 32 | .action_items { 33 | span.action_item { 34 | & > a, & > .dropdown_menu > a { 35 | @include light-button; 36 | padding: 12px 17px 10px; 37 | margin: 0px; 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /features/footer.feature: -------------------------------------------------------------------------------- 1 | @footer 2 | Feature: Site title 3 | 4 | As a developer 5 | In order to customize the site footer 6 | I want to set it in the configuration 7 | 8 | Background: 9 | Given I am logged in 10 | 11 | Scenario: No footer is set in the configuration (default) 12 | When I am on the dashboard 13 | And I should see the default footer 14 | 15 | Scenario: Set the footer in the configuration 16 | Given a configuration of: 17 | """ 18 | ActiveAdmin.application.footer = "MyApp Revision 123" 19 | """ 20 | When I am on the dashboard 21 | And I should see the footer "MyApp Revision 123" 22 | 23 | Scenario: Set the footer to a proc 24 | Given a configuration of: 25 | """ 26 | ActiveAdmin.application.footer = proc { "Enjoy MyApp Revision 123, #{controller.current_admin_user.try(:email)}!" } 27 | """ 28 | When I am on the dashboard 29 | And I should see the footer "Enjoy MyApp Revision 123, admin@example.com!" 30 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/components/_flash_messages.scss: -------------------------------------------------------------------------------- 1 | body.logged_in { 2 | .flash { 3 | @include gradient(#f7f1d3, #f5edc5); 4 | @include text-shadow(#fafafa); 5 | border-bottom: 1px solid #eee098; 6 | color: #cb9810; 7 | font-weight: bold; 8 | font-size: 1.1em; 9 | line-height: 1.0em; 10 | padding: 13px 30px 11px; 11 | position: relative; 12 | 13 | &.flash_notice { 14 | @include gradient(#dce9dd, #ccdfcd); 15 | border-bottom: 1px solid #adcbaf; 16 | color: #416347; 17 | } 18 | &.flash_error { 19 | @include gradient(#f5e4e4, #f1dcdc); 20 | border-bottom: 1px solid #e0c2c0; 21 | color: #b33c33; 22 | } 23 | } 24 | } 25 | 26 | body.logged_out { 27 | .flash { 28 | @include no-shadow; 29 | @include text-shadow(#fff); 30 | background: none; 31 | color: #666; 32 | font-weight: bold; 33 | line-height: 1.0em; 34 | padding: 0; 35 | margin-bottom: 8px; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/views/kaminari/active_admin/_paginator.html.erb: -------------------------------------------------------------------------------- 1 | <%# The container tag 2 | - available local variables 3 | current_page: a page object for the currently displayed page 4 | total_pages: total number of pages 5 | per_page: number of items to fetch per page 6 | remote: data-remote 7 | paginator: the paginator that renders the pagination tags inside 8 | -%> 9 | <%= paginator.render do -%> 10 | 25 | <% end -%> 26 | -------------------------------------------------------------------------------- /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::SidebarSection instance 8 | def build(section) 9 | @section = section 10 | super(@section.title) 11 | add_class @section.custom_class if @section.custom_class 12 | self.id = @section.id 13 | build_sidebar_content 14 | end 15 | 16 | # Renders attributes_table_for current resource 17 | def attributes_table(*args, &block) 18 | attributes_table_for resource, *args, &block 19 | end 20 | 21 | protected 22 | 23 | def build_sidebar_content 24 | if @section.block 25 | rvalue = instance_exec(&@section.block) 26 | self << rvalue if rvalue.is_a?(String) 27 | else 28 | render(@section.partial_name) 29 | end 30 | end 31 | end 32 | 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /features/show/tabs.feature: -------------------------------------------------------------------------------- 1 | Feature: Show - Tabs 2 | 3 | Add tabs with different content to the page 4 | 5 | Background: 6 | Given a post with the title "Hello World" written by "Jane Doe" exists 7 | 8 | @javascript 9 | Scenario: Set a method to be called on the resource as the title 10 | Given a show configuration of: 11 | """ 12 | ActiveAdmin.register Post do 13 | show do 14 | tabs do 15 | tab :overview do 16 | span "tab 1" 17 | end 18 | 19 | tab 'テスト', id: :test_non_ascii do 20 | span "tab 2" 21 | end 22 | end 23 | end 24 | end 25 | """ 26 | 27 | Then I should see two tabs "Overview" and "テスト" 28 | And I should see the element "#overview span" 29 | And I should not see the element "#test_non_ascii span" 30 | Then I follow "テスト" 31 | And I should see the element "#test_non_ascii span" 32 | And I should not see the element "#overview span" 33 | -------------------------------------------------------------------------------- /lib/active_admin/views/components/menu.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Views 3 | 4 | # Renders an ActiveAdmin::Menu as a set of unordered list items. 5 | # 6 | # This component takes cares of deciding which items should be 7 | # displayed given the current context and renders them appropriately. 8 | # 9 | # The entire component is rendered within one ul element. 10 | class Menu < Component 11 | attr_reader :menu 12 | builder_method :menu 13 | 14 | # @param [ActiveAdmin::Menu] menu the Menu to render 15 | # @param [Hash] options the options as passed to the underlying ul element. 16 | # 17 | def build(menu, options = {}) 18 | @menu = menu 19 | super(options) 20 | 21 | menu.items.each do |item| 22 | menu_item(item) if helpers.render_in_context self, item.should_display 23 | end 24 | children.sort! 25 | end 26 | 27 | def tag_name 28 | 'ul' 29 | end 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /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 | super(attributes) 9 | add_class "panel" 10 | @title = h3(title.to_s) 11 | @contents = div(class: "panel_contents") 12 | end 13 | 14 | def add_child(child) 15 | if @contents 16 | @contents << child 17 | else 18 | super 19 | end 20 | end 21 | 22 | # Override children? to only report children when the panel's 23 | # contents have been added to. This ensures that the panel 24 | # correcly appends string values, etc. 25 | def children? 26 | @contents.children? 27 | end 28 | 29 | def header_action(*args) 30 | action = args[0] 31 | 32 | @title << div(class: 'header_action') do 33 | action 34 | end 35 | end 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /spec/unit/views/components/menu_item_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | require 'active_admin/menu_item' 3 | require 'active_admin/views/components/menu_item' 4 | 5 | RSpec.describe ActiveAdmin::Views::MenuItem do 6 | let(:item) do 7 | i = ActiveAdmin::MenuItem.new(label: "Dashboard") 8 | i.add label: "Blog", url: 'blogs' 9 | i.add label: "Cars", url: 'cars' 10 | i.add label: "Restricted", url: 'secret', if: proc{false} 11 | i.add label: "Users", priority: 1, url: 'admin_users' 12 | i.add label: "Settings", priority: 2, url: 'setup' 13 | i.add label: "Analytics", priority: 44, url: 'reports' 14 | i 15 | end 16 | 17 | let(:arbe_menu_item) do 18 | render_arbre_component(item: item) do 19 | menu_item(item) 20 | end 21 | end 22 | 23 | let(:html) { Capybara.string(arbe_menu_item.to_s) } 24 | 25 | it "sorts the child items" do 26 | ids = html.all('li').map { |i| i[:id] } 27 | expect(ids).to eq %w(dashboard users settings blog cars analytics) 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/active_admin/cancan_adapter.rb: -------------------------------------------------------------------------------- 1 | unless ActiveAdmin::Dependency.cancan? || ActiveAdmin::Dependency.cancancan? 2 | ActiveAdmin::Dependency.cancan! 3 | end 4 | 5 | require 'cancan' 6 | 7 | # Add a setting to the application to configure the ability 8 | ActiveAdmin::Application.inheritable_setting :cancan_ability_class, "Ability" 9 | 10 | module ActiveAdmin 11 | 12 | class CanCanAdapter < AuthorizationAdapter 13 | 14 | def authorized?(action, subject = nil) 15 | cancan_ability.can?(action, subject) 16 | end 17 | 18 | def cancan_ability 19 | @cancan_ability ||= initialize_cancan_ability 20 | end 21 | 22 | def scope_collection(collection, action = ActiveAdmin::Auth::READ) 23 | collection.accessible_by(cancan_ability, action) 24 | end 25 | 26 | private 27 | 28 | def initialize_cancan_ability 29 | klass = resource.namespace.cancan_ability_class 30 | klass = klass.constantize if klass.is_a? String 31 | klass.new user 32 | end 33 | 34 | end 35 | 36 | end 37 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/mixins/_sections.scss: -------------------------------------------------------------------------------- 1 | @mixin section-header { 2 | @include secondary-gradient; 3 | @include text-shadow; 4 | border: solid 1px #cdcdcd; 5 | @include border-colors(#e6e6e6, #d4d4d4, #cdcdcd); 6 | box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 0 1px #FFF inset; 7 | 8 | font-size: 1em; 9 | font-weight: bold; 10 | line-height: 18px; 11 | margin-bottom: 0.5em; 12 | color: $section-header-text-color; 13 | 14 | padding: 5px 10px 3px 10px; 15 | } 16 | 17 | @mixin section-background { 18 | background: #f4f4f4; 19 | @include rounded(4px); 20 | @include inset-shadow(0,1px,4px, #ddd); 21 | } 22 | 23 | @mixin section { 24 | @include section-background; 25 | margin-bottom: 20px; 26 | 27 | > h3 { 28 | @include section-header; 29 | 30 | .header_action { 31 | float: right; 32 | } 33 | } 34 | 35 | > div { padding: 3px $section-padding $section-padding $section-padding; } 36 | 37 | hr { 38 | border: none; 39 | border-bottom: 1px solid #E8E8E8; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/active_admin/sidebar_section.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | 3 | class SidebarSection 4 | include ActiveAdmin::OptionalDisplay 5 | 6 | attr_accessor :name, :options, :block 7 | 8 | def initialize(name, options = {}, &block) 9 | @name, @options, @block = name.to_s, options, block 10 | normalize_display_options! 11 | end 12 | 13 | # The id gets used for the div in the view 14 | def id 15 | "#{name.downcase.underscore}_sidebar_section".parameterize 16 | end 17 | 18 | # The title gets displayed within the section in the view 19 | def title 20 | I18n.t("active_admin.sidebars.#{name}", default: name.titlecase) 21 | end 22 | 23 | # If a block is not passed in, the name of the partial to render 24 | def partial_name 25 | options[:partial] || "#{name.downcase.tr(' ', '_')}_sidebar" 26 | end 27 | 28 | def custom_class 29 | options[:class] 30 | end 31 | 32 | def priority 33 | options[:priority] || 10 34 | end 35 | end 36 | 37 | end 38 | -------------------------------------------------------------------------------- /lib/active_admin/asset_registration.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module AssetRegistration 3 | 4 | def register_stylesheet(path, options = {}) 5 | Deprecation.warn <<-MSG.strip_heredoc 6 | The `register_stylesheet` config is deprecated and will be removed 7 | in v2. Import your "#{path}" stylesheet in the active_admin.scss. 8 | MSG 9 | stylesheets[path] = options 10 | end 11 | 12 | def stylesheets 13 | @stylesheets ||= {} 14 | end 15 | 16 | def clear_stylesheets! 17 | stylesheets.clear 18 | end 19 | 20 | def register_javascript(name) 21 | Deprecation.warn <<-MSG.strip_heredoc 22 | The `register_javascript` config is deprecated and will be removed 23 | in v2. Import your "#{name}" javascript in the active_admin.js. 24 | MSG 25 | javascripts.add name 26 | end 27 | 28 | def javascripts 29 | @javascripts ||= Set.new 30 | end 31 | 32 | def clear_javascripts! 33 | javascripts.clear 34 | end 35 | 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /app/assets/javascripts/active_admin/lib/table-checkbox-toggler.es6: -------------------------------------------------------------------------------- 1 | ActiveAdmin.TableCheckboxToggler = class TableCheckboxToggler extends ActiveAdmin.CheckboxToggler { 2 | _bind() { 3 | super._bind(...arguments); 4 | 5 | this.$container 6 | .find('tbody td') 7 | .click(event => { 8 | if (event.target.type !== 'checkbox') { 9 | this._didClickCell(event.target); 10 | } 11 | }); 12 | } 13 | 14 | _didChangeCheckbox(checkbox) { 15 | super._didChangeCheckbox(...arguments); 16 | 17 | $(checkbox) 18 | .parents('tr') 19 | .toggleClass('selected', checkbox.checked); 20 | } 21 | 22 | _didChangeToggleAllCheckbox() { 23 | this.$container 24 | .find('tbody tr') 25 | .toggleClass('selected', super._didChangeToggleAllCheckbox(...arguments)); 26 | } 27 | 28 | _didClickCell(cell) { 29 | $(cell) 30 | .parent('tr') 31 | .find(':checkbox') 32 | .click(); 33 | } 34 | }; 35 | 36 | $.widget.bridge('tableCheckboxToggler', ActiveAdmin.TableCheckboxToggler); 37 | -------------------------------------------------------------------------------- /docs/3-index-pages/custom-index.md: -------------------------------------------------------------------------------- 1 | --- 2 | redirect_from: /docs/3-index-pages/custom-index.html 3 | --- 4 | 5 | # Custom Index 6 | 7 | If the supplied Active Admin index components are insufficient for your project 8 | feel free to define your own. Index classes inherit from `ActiveAdmin::Component` 9 | and require a `build` method and an `index_name` class method. 10 | 11 | ```ruby 12 | module ActiveAdmin 13 | module Views 14 | class IndexAsMyIdea < ActiveAdmin::Component 15 | 16 | def build(page_presenter, collection) 17 | # ... 18 | end 19 | 20 | def self.index_name 21 | "my_idea" 22 | end 23 | 24 | end 25 | end 26 | end 27 | ``` 28 | 29 | The build method takes a PagePresenter object and collection of whatever you 30 | choose. 31 | 32 | The `index_name` class method takes no arguments and returns a string that should 33 | be representative of the class name. If this method is not defined, your 34 | index component will not be able take advantage of Active Admin's 35 | *multiple index pages* feature. 36 | -------------------------------------------------------------------------------- /lib/active_admin/views/index_as_block.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Views 3 | 4 | # # Index as a Block 5 | # 6 | # If you want to fully customize the display of your resources on the index 7 | # screen, Index as a Block allows you to render a block of content for each 8 | # resource. 9 | # 10 | # ```ruby 11 | # index as: :block do |product| 12 | # div for: product do 13 | # resource_selection_cell product 14 | # h2 auto_link product.title 15 | # div simple_format product.description 16 | # end 17 | # end 18 | # ``` 19 | # 20 | class IndexAsBlock < ActiveAdmin::Component 21 | 22 | def build(page_presenter, collection) 23 | add_class "index" 24 | resource_selection_toggle_panel if active_admin_config.batch_actions.any? 25 | collection.each do |obj| 26 | instance_exec(obj, &page_presenter.block) 27 | end 28 | end 29 | 30 | def self.index_name 31 | "block" 32 | end 33 | 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/components/_pagination.scss: -------------------------------------------------------------------------------- 1 | .paginated_collection_contents { 2 | clear: both; 3 | } 4 | 5 | .pagination { 6 | float: right; 7 | font-size: 0.9em; 8 | margin-left: 10px; 9 | 10 | a { 11 | @include light-button; 12 | } 13 | 14 | span.page.current { 15 | @include default-button; 16 | } 17 | 18 | a, span.page.current { 19 | @include rounded(0px); 20 | margin-right: 4px; 21 | padding: 2px 5px; 22 | } 23 | } 24 | 25 | .pagination_information { 26 | float: right; 27 | margin-bottom: 5px; 28 | color: #b3bcc1; 29 | b { color: #5c6469; } 30 | } 31 | 32 | .download_links { 33 | float: left; 34 | } 35 | 36 | .pagination_per_page { 37 | float: right; 38 | margin-left: 4px; 39 | select { 40 | @include light-button; 41 | @include rounded(0px); 42 | padding: 1px 5px; 43 | } 44 | } 45 | 46 | .comments { 47 | .pagination { 48 | float: left; 49 | margin-bottom: 30px; 50 | } 51 | .pagination_information { 52 | float: left; 53 | color: #000; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/jquery-ui/keycode.js: -------------------------------------------------------------------------------- 1 | //= require jquery-ui/version 2 | 3 | /*! 4 | * jQuery UI Keycode 1.12.1 5 | * http://jqueryui.com 6 | * 7 | * Copyright jQuery Foundation and other contributors 8 | * Released under the MIT license. 9 | * http://jquery.org/license 10 | */ 11 | 12 | //>>label: Keycode 13 | //>>group: Core 14 | //>>description: Provide keycodes as keynames 15 | //>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/ 16 | 17 | ( function( factory ) { 18 | if ( typeof define === "function" && define.amd ) { 19 | 20 | // AMD. Register as an anonymous module. 21 | define( [ "jquery", "./version" ], factory ); 22 | } else { 23 | 24 | // Browser globals 25 | factory( jQuery ); 26 | } 27 | } ( function( $ ) { 28 | return $.ui.keyCode = { 29 | BACKSPACE: 8, 30 | COMMA: 188, 31 | DELETE: 46, 32 | DOWN: 40, 33 | END: 35, 34 | ENTER: 13, 35 | ESCAPE: 27, 36 | HOME: 36, 37 | LEFT: 37, 38 | PAGE_DOWN: 34, 39 | PAGE_UP: 33, 40 | PERIOD: 190, 41 | RIGHT: 39, 42 | SPACE: 32, 43 | TAB: 9, 44 | UP: 38 45 | }; 46 | 47 | } ) ); 48 | -------------------------------------------------------------------------------- /lib/active_admin/views/components/tabs.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Views 3 | class Tabs < ActiveAdmin::Component 4 | builder_method :tabs 5 | 6 | def tab(title, options = {}, &block) 7 | title = title.to_s.titleize if title.is_a? Symbol 8 | @menu << build_menu_item(title, options, &block) 9 | @tabs_content << build_content_item(title, options, &block) 10 | end 11 | 12 | def build(&block) 13 | @menu = ul(class: 'nav nav-tabs', role: "tablist") 14 | @tabs_content = div(class: 'tab-content') 15 | end 16 | 17 | def build_menu_item(title, options, &block) 18 | fragment = options.fetch(:id, title.parameterize) 19 | html_options = options.fetch(:html_options, {}) 20 | li html_options do 21 | link_to title, "##{fragment}" 22 | end 23 | end 24 | 25 | def build_content_item(title, options, &block) 26 | options = options.reverse_merge(id: title.parameterize) 27 | div(options, &block) 28 | end 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/pages/_logged_out.scss: -------------------------------------------------------------------------------- 1 | body.logged_out { 2 | background: #e8e9ea; 3 | 4 | #content_wrapper{ 5 | width: 500px; 6 | margin: 70px auto; 7 | #active_admin_content { 8 | @include shadow; 9 | background: #fff; 10 | padding: 13px 30px; 11 | } 12 | } 13 | 14 | h2 { 15 | @include section-header; 16 | @include primary-gradient; 17 | @include text-shadow(#000); 18 | box-shadow: 0 1px 3px rgba(0,0,0,0.3); 19 | border: none; 20 | color: #fff; 21 | margin: -13px -30px 20px -30px; 22 | } 23 | 24 | #login { 25 | /* Login Form */ 26 | form { 27 | fieldset { 28 | @include no-shadow; 29 | background: none; 30 | padding: 0; 31 | li { padding: 10px 0; } 32 | 33 | input[type=text], input[type=email], input[type=password] { 34 | width: 70%; 35 | } 36 | &.buttons { margin-left: 20%; } 37 | margin-bottom: 0; 38 | } 39 | } 40 | 41 | a { float: right; margin-top: -32px; } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /app/views/active_admin/devise/sessions/new.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

<%= active_admin_application.site_title(self) %> <%= title t('active_admin.devise.login.title') %>

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 | resource.class.authentication_keys.each_with_index { |key, index| 8 | f.input key, label: t("active_admin.devise.#{key}.title"), input_html: { autofocus: index.zero? } 9 | } 10 | f.input :password, label: t('active_admin.devise.password.title') 11 | f.input :remember_me, label: t('active_admin.devise.login.remember_me'), as: :boolean if devise_mapping.rememberable? 12 | end 13 | f.actions do 14 | f.action :submit, label: t('active_admin.devise.login.submit'), button_html: { value: t('active_admin.devise.login.submit') } 15 | end 16 | end 17 | %> 18 | 19 | <%= render partial: "active_admin/devise/shared/links" %> 20 |
21 | -------------------------------------------------------------------------------- /lib/active_admin/reloader.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Reloader 3 | # ActionDispatch::Reloader.to_prepare is deprecated in Rails 5.0 and will be removed from Rails 5.1 4 | # 5 | # Use ActiveSupport::Reloader if available for Rails 5, fall back to ActionDispatch::Reloader for earlier Rails 6 | def self.to_prepare(*args, &block) 7 | if defined? ActiveSupport::Reloader 8 | ActiveSupport::Reloader.to_prepare(*args, &block) 9 | else 10 | ActionDispatch::Reloader.to_prepare(*args, &block) 11 | end 12 | end 13 | 14 | # ActionDispatch::Reloader.to_cleanup is deprecated in Rails 5.0 and will be removed from Rails 5.1 15 | # 16 | # Use ActiveSupport::Reloader if available for Rails 5, fall back to ActionDispatch::Reloader for earlier Rails 17 | def self.to_complete(*args, &block) 18 | if defined? ActiveSupport::Reloader 19 | ActiveSupport::Reloader.to_complete(*args, &block) 20 | else 21 | ActionDispatch::Reloader.to_cleanup(*args, &block) 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin/components/_comments.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 | overflow: hidden; 14 | font-size: 0.9em; 15 | color: lighten($primary-color, 10%); 16 | .active_admin_comment_author { 17 | font-size: 1.2em; 18 | font-weight: bold; 19 | margin: 0; 20 | color: $primary-color; 21 | } 22 | } 23 | .active_admin_comment_body { 24 | margin-left: 150px; 25 | } 26 | } 27 | form.active_admin_comment { 28 | margin: 0; 29 | padding: 0; 30 | margin-left: 150px; 31 | 32 | fieldset.inputs { 33 | margin: 0; 34 | padding: 0; 35 | background: none; 36 | @include no-shadow; 37 | } 38 | li { padding: 0; } 39 | fieldset.buttons { padding: 0; margin-top: 5px;} 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /features/global_navigation.feature: -------------------------------------------------------------------------------- 1 | Feature: Global Navigation 2 | 3 | Background: 4 | Given a configuration of: 5 | """ 6 | ActiveAdmin.register Post 7 | """ 8 | Given I am logged in 9 | And 10 posts exist 10 | 11 | Scenario: Viewing the current section in the global navigation 12 | Given I am on the index page for posts 13 | Then the "Posts" tab should be selected 14 | 15 | Scenario: Viewing the current section in the global navigation when on new page 16 | Given I am on the index page for posts 17 | And I follow "New Post" 18 | Then the "Posts" tab should be selected 19 | 20 | Scenario: Viewing the current section in the global navigation when on show page 21 | Given I am on the index page for posts 22 | And I follow "View" 23 | Then the "Posts" tab should be selected 24 | 25 | Scenario: Viewing the current section in the global navigation when on edit page 26 | Given I am on the index page for posts 27 | And I follow "View" 28 | And I follow "Edit Post" 29 | Then the "Posts" tab should be selected 30 | -------------------------------------------------------------------------------- /spec/unit/resource_controller/sidebars_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe ActiveAdmin::ResourceController::Sidebars, type: :controller do 4 | let(:klass){ Admin::PostsController } 5 | 6 | shared_context 'with post config' do 7 | before do 8 | load_resources { post_config } 9 | 10 | @controller = klass.new 11 | 12 | get :index 13 | end 14 | end 15 | 16 | context 'without skip_sidebar! before filter' do 17 | include_context 'with post config' do 18 | let(:post_config) { ActiveAdmin.register Post } 19 | end 20 | 21 | it 'does not set @skip_sidebar' do 22 | expect(controller.instance_variable_get(:@skip_sidebar)).to eq nil 23 | end 24 | end 25 | 26 | context 'with skip_sidebar! before_action' do 27 | include_context 'with post config' do 28 | let(:post_config) do 29 | ActiveAdmin.register(Post) { before_action :skip_sidebar! } 30 | end 31 | end 32 | 33 | it 'works' do 34 | expect(controller.instance_variable_get(:@skip_sidebar)).to eq true 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /features/development_reloading.feature: -------------------------------------------------------------------------------- 1 | Feature: Development Reloading 2 | 3 | In order to quickly develop applications 4 | As a developer 5 | I want the application to reload itself in development 6 | 7 | @requires-reloading 8 | Scenario: Registering a resource that was not previously registered 9 | When I am logged in with capybara 10 | Then I should not see a menu item for "Posts" 11 | 12 | When "app/admin/posts.rb" contains: 13 | """ 14 | ActiveAdmin.register Post do 15 | permit_params :custom_category_id, :author_id, :title, 16 | :body, :position, :published_date, :starred 17 | end 18 | """ 19 | When I am logged in with capybara 20 | Then I should see a menu item for "Posts" 21 | 22 | When I create a new post with the title "A" 23 | Then I should see a successful create flash 24 | 25 | When I add "validates_presence_of :title" to the "post" model 26 | And I create a new post with the title "" 27 | Then I should not see a successful create flash 28 | And I should see a validation error "can't be blank" 29 | -------------------------------------------------------------------------------- /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/generators/active_admin/install/templates/dashboard.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register_page "Dashboard" do 2 | 3 | menu priority: 1, label: proc{ I18n.t("active_admin.dashboard") } 4 | 5 | content title: proc{ I18n.t("active_admin.dashboard") } do 6 | div class: "blank_slate_container", id: "dashboard_default_message" do 7 | span class: "blank_slate" do 8 | span I18n.t("active_admin.dashboard_welcome.welcome") 9 | small I18n.t("active_admin.dashboard_welcome.call_to_action") 10 | end 11 | end 12 | 13 | # Here is an example of a simple dashboard with columns and panels. 14 | # 15 | # columns do 16 | # column do 17 | # panel "Recent Posts" do 18 | # ul do 19 | # Post.recent(5).map do |post| 20 | # li link_to(post.title, admin_post_path(post)) 21 | # end 22 | # end 23 | # end 24 | # end 25 | 26 | # column do 27 | # panel "Info" do 28 | # para "Welcome to ActiveAdmin." 29 | # end 30 | # end 31 | # end 32 | end # content 33 | end 34 | -------------------------------------------------------------------------------- /lib/active_admin/dynamic_setting.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | 3 | class DynamicSetting 4 | def self.build(setting, type) 5 | (type ? klass(type) : self).new(setting) 6 | end 7 | 8 | def self.klass(type) 9 | klass = "#{type.to_s.camelcase}Setting" 10 | raise ArgumentError, "Unknown type: #{type}" unless ActiveAdmin.const_defined?(klass) 11 | ActiveAdmin.const_get(klass) 12 | end 13 | 14 | def initialize(setting) 15 | @setting = setting 16 | end 17 | 18 | def value(*_args) 19 | @setting 20 | end 21 | end 22 | 23 | # Many configuration options (Ex: site_title, title_image) could either be 24 | # static (String), methods (Symbol) or procs (Proc). This wrapper takes care of 25 | # returning the content when String or using instance_eval when Symbol or Proc. 26 | # 27 | class StringSymbolOrProcSetting < DynamicSetting 28 | def value(context = self) 29 | case @setting 30 | when Symbol, Proc 31 | context.instance_eval(&@setting) 32 | else 33 | @setting 34 | end 35 | end 36 | end 37 | 38 | end 39 | -------------------------------------------------------------------------------- /app/views/active_admin/devise/registrations/new.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

<%= active_admin_application.site_title(self) %> <%= title t('active_admin.devise.sign_up.title') %>

3 | 4 | <% scope = Devise::Mapping.find_scope!(resource_name) %> 5 | <%= devise_error_messages! %> 6 | <%= active_admin_form_for(resource, as: resource_name, url: send(:"#{scope}_registration_path"), html: { id: "registration_new" }) do |f| 7 | f.inputs do 8 | resource.class.authentication_keys.each_with_index { |key, index| 9 | f.input key, label: t('active_admin.devise.'+key.to_s+'.title'), input_html: { autofocus: index.zero? } 10 | } 11 | f.input :password, label: t('active_admin.devise.password.title') 12 | f.input :password_confirmation, label: t('active_admin.devise.password_confirmation.title') 13 | end 14 | f.actions do 15 | f.action :submit, label: t('active_admin.devise.login.submit'), button_html: { value: t('active_admin.devise.sign_up.submit') } 16 | end 17 | end 18 | %> 19 | 20 | <%= render partial: "active_admin/devise/shared/links" %> 21 |
22 | 23 | -------------------------------------------------------------------------------- /spec/unit/resource/pagination_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | module ActiveAdmin 4 | RSpec.describe Resource, "Pagination" 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 "#paginate" do 16 | it "should default to true" do 17 | expect(config.paginate).to eq true 18 | end 19 | 20 | it "should be settable to false" do 21 | config.paginate = false 22 | expect(config.paginate).to eq false 23 | end 24 | end 25 | 26 | describe "#per_page" do 27 | it "should default to namespace.default_per_page" do 28 | expect(namespace).to receive(:default_per_page).and_return(5) 29 | expect(config.per_page).to eq 5 30 | end 31 | 32 | it "should be settable" do 33 | config.per_page = 5 34 | expect(config.per_page).to eq 5 35 | end 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /spec/unit/views/pages/show_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe ActiveAdmin::Views::Pages::Show do 4 | 5 | describe "the resource" do 6 | let(:helpers) { double resource: resource } 7 | let(:arbre_context) { Arbre::Context.new({}, helpers) } 8 | subject(:page) { ActiveAdmin::Views::Pages::Show.new(arbre_context) } 9 | 10 | context 'when the resource does not respond to #decorator' do 11 | let(:resource) { 'Test Resource' } 12 | 13 | it "normally returns the resource" do 14 | expect(page.resource).to eq 'Test Resource' 15 | end 16 | end 17 | 18 | context 'when you pass a block to main content' do 19 | let(:block) { lambda { } } 20 | let(:resource) { double('resource') } 21 | 22 | before { allow(page).to receive(:active_admin_config).and_return(double(comments?: false, resource_columns: [:field]))} 23 | 24 | it 'appends it to the output' do 25 | expect(page).to receive(:attributes_table).with(:field).and_yield 26 | page.default_main_content(&block) 27 | end 28 | end 29 | 30 | end 31 | 32 | end 33 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/jquery-ui/tabbable.js: -------------------------------------------------------------------------------- 1 | //= require jquery-ui/version 2 | //= require jquery-ui/focusable 3 | 4 | /*! 5 | * jQuery UI Tabbable 1.12.1 6 | * http://jqueryui.com 7 | * 8 | * Copyright jQuery Foundation and other contributors 9 | * Released under the MIT license. 10 | * http://jquery.org/license 11 | */ 12 | 13 | //>>label: :tabbable Selector 14 | //>>group: Core 15 | //>>description: Selects elements which can be tabbed to. 16 | //>>docs: http://api.jqueryui.com/tabbable-selector/ 17 | 18 | ( function( factory ) { 19 | if ( typeof define === "function" && define.amd ) { 20 | 21 | // AMD. Register as an anonymous module. 22 | define( [ "jquery", "./version", "./focusable" ], factory ); 23 | } else { 24 | 25 | // Browser globals 26 | factory( jQuery ); 27 | } 28 | } ( function( $ ) { 29 | 30 | return $.extend( $.expr[ ":" ], { 31 | tabbable: function( element ) { 32 | var tabIndex = $.attr( element, "tabindex" ), 33 | hasTabindex = tabIndex != null; 34 | return ( !hasTabindex || tabIndex >= 0 ) && $.ui.focusable( element, hasTabindex ); 35 | } 36 | } ); 37 | 38 | } ) ); 39 | -------------------------------------------------------------------------------- /lib/active_admin/orm/active_record/comments/comment.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | class Comment < ActiveRecord::Base 3 | 4 | self.table_name = "#{table_name_prefix}active_admin_comments#{table_name_suffix}" 5 | 6 | belongs_to :resource, polymorphic: true, optional: true 7 | belongs_to :author, polymorphic: true 8 | 9 | validates_presence_of :body, :namespace, :resource 10 | 11 | before_create :set_resource_type 12 | 13 | # @return [String] The name of the record to use for the polymorphic relationship 14 | def self.resource_type(resource) 15 | ResourceController::Decorators.undecorate(resource).class.base_class.name.to_s 16 | end 17 | 18 | def self.find_for_resource_in_namespace(resource, namespace) 19 | where( 20 | resource_type: resource_type(resource), 21 | resource_id: resource.id, 22 | namespace: namespace.to_s 23 | ).order(ActiveAdmin.application.namespaces[namespace.to_sym].comments_order) 24 | end 25 | 26 | def set_resource_type 27 | self.resource_type = self.class.resource_type(resource) 28 | end 29 | 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 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 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/jquery-ui/data.js: -------------------------------------------------------------------------------- 1 | //= require jquery-ui/version 2 | 3 | /*! 4 | * jQuery UI :data 1.12.1 5 | * http://jqueryui.com 6 | * 7 | * Copyright jQuery Foundation and other contributors 8 | * Released under the MIT license. 9 | * http://jquery.org/license 10 | */ 11 | 12 | //>>label: :data Selector 13 | //>>group: Core 14 | //>>description: Selects elements which have data stored under the specified key. 15 | //>>docs: http://api.jqueryui.com/data-selector/ 16 | 17 | ( function( factory ) { 18 | if ( typeof define === "function" && define.amd ) { 19 | 20 | // AMD. Register as an anonymous module. 21 | define( [ "jquery", "./version" ], factory ); 22 | } else { 23 | 24 | // Browser globals 25 | factory( jQuery ); 26 | } 27 | } ( function( $ ) { 28 | return $.extend( $.expr[ ":" ], { 29 | data: $.expr.createPseudo ? 30 | $.expr.createPseudo( function( dataName ) { 31 | return function( elem ) { 32 | return !!$.data( elem, dataName ); 33 | }; 34 | } ) : 35 | 36 | // Support: jQuery <1.8 37 | function( elem, i, match ) { 38 | return !!$.data( elem, match[ 3 ] ); 39 | } 40 | } ); 41 | } ) ); 42 | -------------------------------------------------------------------------------- /lib/active_admin/base_controller/menu.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | class BaseController < ::InheritedResources::Base 3 | module Menu 4 | extend ActiveSupport::Concern 5 | 6 | included do 7 | before_action :set_current_tab 8 | helper_method :current_menu 9 | end 10 | 11 | protected 12 | 13 | def current_menu 14 | active_admin_config.navigation_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 current_menu && active_admin_config.belongs_to? && parent? 21 | parent_item = active_admin_config.belongs_to_config.target.menu_item 22 | if current_menu.include? parent_item 23 | parent_item 24 | else 25 | active_admin_config.menu_item 26 | end 27 | else 28 | active_admin_config.menu_item 29 | end 30 | end 31 | 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /lib/active_admin/generators/boilerplate.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Generators 3 | class Boilerplate 4 | def initialize(class_name) 5 | @class_name = class_name 6 | end 7 | 8 | def attributes 9 | @class_name.constantize.new.attributes.keys 10 | end 11 | 12 | def rows 13 | attributes.map { |a| row(a) }.join("\n") 14 | end 15 | 16 | def row(name) 17 | "# row :#{name.gsub(/_id$/, '')}" 18 | end 19 | 20 | def columns 21 | attributes.map { |a| column(a) }.join("\n") 22 | end 23 | 24 | def column(name) 25 | "# column :#{name.gsub(/_id$/, '')}" 26 | end 27 | 28 | def filters 29 | attributes.map { |a| filter(a) }.join("\n") 30 | end 31 | 32 | def filter(name) 33 | "# filter :#{name.gsub(/_id$/, '')}" 34 | end 35 | 36 | def form_inputs 37 | attributes.reject{|a| %w(id created_at updated_at).include? a}.map{ |a| form_input(a) }.join("\n") 38 | end 39 | 40 | def form_input(name) 41 | "# f.input :#{name.gsub(/_id$/, '')}" 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /features/step_definitions/site_title_steps.rb: -------------------------------------------------------------------------------- 1 | Around '@site_title' do |scenario, block| 2 | previous_site_title = ActiveAdmin.application.site_title 3 | previous_site_title_link = ActiveAdmin.application.site_title_link 4 | previous_site_title_image = ActiveAdmin.application.site_title_image 5 | 6 | begin 7 | block.call 8 | ensure 9 | ActiveAdmin.application.site_title = previous_site_title 10 | ActiveAdmin.application.site_title_link = previous_site_title_link 11 | ActiveAdmin.application.site_title_image = previous_site_title_image 12 | end 13 | end 14 | 15 | Then /^I should see the site title "([^"]*)"$/ do |title| 16 | expect(page).to have_css 'h1#site_title', text: title 17 | end 18 | 19 | Then /^I should not see the site title "([^"]*)"$/ do |title| 20 | expect(page).to_not have_css 'h1#site_title', text: title 21 | end 22 | 23 | Then /^I should see the site title image "([^"]*)"$/ do |image| 24 | img = page.find('h1#site_title img') 25 | expect(img[:src]).to eq(image) 26 | end 27 | 28 | Then /^I should see the site title image linked to "([^"]*)"$/ do |url| 29 | link = page.find('h1#site_title a') 30 | expect(link[:href]).to eq(url) 31 | end 32 | -------------------------------------------------------------------------------- /lib/active_admin/resource_controller/scoping.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | class ResourceController < BaseController 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 | # 15 | # Collection can be scoped conditionally with an :if or :unless proc. 16 | def begin_of_association_chain 17 | return nil unless active_admin_config.scope_to?(self) 18 | StringSymbolOrProcSetting.new(active_admin_config.scope_to_method).value(self) 19 | end 20 | 21 | # Overriding from InheritedResources::BaseHelpers 22 | # 23 | # Returns the method for the association chain when using 24 | # the scope_to option 25 | def method_for_association_chain 26 | active_admin_config.scope_to_association_method || super 27 | end 28 | 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /spec/unit/helpers/scope_chain_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe ActiveAdmin::ScopeChain do 4 | 5 | include ActiveAdmin::ScopeChain 6 | 7 | describe "#scope_chain" do 8 | let(:relation) { double } 9 | 10 | context "when Scope has a scope method" do 11 | let(:scope) { ActiveAdmin::Scope.new :published } 12 | 13 | it "should call the method on the relation and return it" do 14 | expect(relation).to receive(:published).and_return(:scoped_relation) 15 | expect(scope_chain(scope, relation)).to eq :scoped_relation 16 | end 17 | end 18 | 19 | context "when Scope has the scope method method ':all'" do 20 | let(:scope) { ActiveAdmin::Scope.new :all } 21 | 22 | it "should return the relation" do 23 | expect(scope_chain(scope, relation)).to eq relation 24 | end 25 | end 26 | 27 | context "when Scope has a name and a scope block" do 28 | let(:scope) { ActiveAdmin::Scope.new("My Scope"){|s| :scoped_relation } } 29 | 30 | it "should instance_exec the block and return it" do 31 | expect(scope_chain(scope, relation)).to eq :scoped_relation 32 | end 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /features/renamed_resource.feature: -------------------------------------------------------------------------------- 1 | Feature: Renamed Resource 2 | 3 | Strong attributes for resources renamed with as: 'NewName' 4 | 5 | Background: 6 | Given a category named "Music" exists 7 | Given a user named "John Doe" exists 8 | And I am logged in 9 | Given a configuration of: 10 | """ 11 | ActiveAdmin.register Blog::Post, as: 'Post' do 12 | permit_params :custom_category_id, :author_id, :title, 13 | :body, :position, :published_date, :starred 14 | end 15 | """ 16 | When I am on the index page for posts 17 | 18 | Scenario: Default form with no config 19 | Given I follow "New Post" 20 | When I fill in "Title" with "Hello World" 21 | And I fill in "Body" with "This is the body" 22 | And I select "Music" from "Category" 23 | And I select "John Doe" from "Author" 24 | And I press "Create Post" 25 | Then I should see "Post was successfully created." 26 | And I should see the attribute "Title" with "Hello World" 27 | And I should see the attribute "Body" with "This is the body" 28 | #And I should see the attribute "Category" with "Music" 29 | And I should see the attribute "Author" with "John Doe" 30 | 31 | -------------------------------------------------------------------------------- /lib/active_admin/localizers/resource_localizer.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Localizers 3 | class ResourceLocalizer 4 | class << self 5 | def from_resource(resource_config) 6 | new(resource_config.resource_name.i18n_key, resource_config.resource_label) 7 | end 8 | 9 | def translate(key, options) 10 | new(options.delete(:model_name), options.delete(:model)).translate(key, options) 11 | end 12 | alias_method :t, :translate 13 | end 14 | 15 | def initialize(model_name, model = nil) 16 | @model_name = model_name 17 | @model = model || model_name.to_s.titleize 18 | end 19 | 20 | def translate(key, options = {}) 21 | scope = options.delete(:scope) 22 | specific_key = array_to_key('resources', @model_name, scope, key) 23 | defaults = [array_to_key(scope, key), key.to_s.titleize] 24 | ::I18n.t specific_key, options.reverse_merge(model: @model, default: defaults, scope: 'active_admin') 25 | end 26 | alias_method :t, :translate 27 | 28 | protected 29 | 30 | def array_to_key(*arr) 31 | arr.flatten.compact.join('.').to_sym 32 | end 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/jquery-ui/unique-id.js: -------------------------------------------------------------------------------- 1 | //= require jquery-ui/version 2 | 3 | /*! 4 | * jQuery UI Unique ID 1.12.1 5 | * http://jqueryui.com 6 | * 7 | * Copyright jQuery Foundation and other contributors 8 | * Released under the MIT license. 9 | * http://jquery.org/license 10 | */ 11 | 12 | //>>label: uniqueId 13 | //>>group: Core 14 | //>>description: Functions to generate and remove uniqueId's 15 | //>>docs: http://api.jqueryui.com/uniqueId/ 16 | 17 | ( function( factory ) { 18 | if ( typeof define === "function" && define.amd ) { 19 | 20 | // AMD. Register as an anonymous module. 21 | define( [ "jquery", "./version" ], factory ); 22 | } else { 23 | 24 | // Browser globals 25 | factory( jQuery ); 26 | } 27 | } ( function( $ ) { 28 | 29 | return $.fn.extend( { 30 | uniqueId: ( function() { 31 | var uuid = 0; 32 | 33 | return function() { 34 | return this.each( function() { 35 | if ( !this.id ) { 36 | this.id = "ui-id-" + ( ++uuid ); 37 | } 38 | } ); 39 | }; 40 | } )(), 41 | 42 | removeUniqueId: function() { 43 | return this.each( function() { 44 | if ( /^ui-id-\d+$/.test( this.id ) ) { 45 | $( this ).removeAttr( "id" ); 46 | } 47 | } ); 48 | } 49 | } ); 50 | 51 | } ) ); 52 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/jquery-ui/safe-active-element.js: -------------------------------------------------------------------------------- 1 | //= require jquery-ui/version 2 | 3 | ( function( factory ) { 4 | if ( typeof define === "function" && define.amd ) { 5 | 6 | // AMD. Register as an anonymous module. 7 | define( [ "jquery", "./version" ], factory ); 8 | } else { 9 | 10 | // Browser globals 11 | factory( jQuery ); 12 | } 13 | } ( function( $ ) { 14 | return $.ui.safeActiveElement = function( document ) { 15 | var activeElement; 16 | 17 | // Support: IE 9 only 18 | // IE9 throws an "Unspecified error" accessing document.activeElement from an