diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ebb0e195d4..d4273f7bc7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,35 +12,43 @@ jobs: gemfile: [ gemfiles/rails_6.1.gemfile ] orm: [ active_record ] adapter: [ sqlite3 ] + asset: [ webpacker ] include: - ruby: 2.5 gemfile: gemfiles/rails_6.0.gemfile orm: active_record adapter: sqlite3 + asset: webpacker - ruby: 3.0 gemfile: gemfiles/rails_6.1.gemfile orm: active_record adapter: mysql2 + asset: webpacker - ruby: 3.0 gemfile: gemfiles/rails_6.1.gemfile orm: active_record adapter: postgresql + asset: webpacker - ruby: 3.0 gemfile: gemfiles/rails_7.0.gemfile orm: active_record adapter: sqlite3 + asset: webpacker - ruby: 2.7 gemfile: gemfiles/rails_6.0.gemfile orm: mongoid adapter: sqlite3 + asset: webpacker - ruby: 3.0 gemfile: gemfiles/rails_6.1.gemfile orm: mongoid adapter: sqlite3 + asset: webpacker - ruby: jruby gemfile: gemfiles/rails_6.1.gemfile orm: mongoid adapter: sqlite3 + asset: webpacker runs-on: ubuntu-latest services: mysql: @@ -64,6 +72,7 @@ jobs: env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} CI_ORM: ${{ matrix.orm }} + CI_ASSET: ${{ matrix.asset }} JRUBY_OPTS: --debug steps: - uses: actions/checkout@v2 @@ -76,17 +85,23 @@ jobs: env: MAKE: make --jobs 4 BUNDLE_WITHOUT: development + - name: Set up Node + uses: actions/setup-node@v2 + with: + node-version: '14' - name: Setup application env: BUNDLE_GEMFILE: ../../${{ matrix.gemfile }} CI_DB_ADAPTER: ${{ matrix.adapter }} RAILS_ENV: test run: | + yarn install cd spec/dummy_app bundle exec rake rails_admin:prepare_ci_env db:create db:migrate + yarn install cd ../../ - name: Run tests - run: bundle exec rake spec + run: bundle exec rspec - name: Coveralls Parallel uses: coverallsapp/github-action@master continue-on-error: true diff --git a/.gitignore b/.gitignore index 88aa68691b..7d482925d7 100644 --- a/.gitignore +++ b/.gitignore @@ -5,14 +5,16 @@ .bundle .idea/ .rvmrc +.sass-cache .yardoc /.emacs.desktop /gemfiles/*.lock +/node_modules/* /rails_admin.gems /spec/generators/tmp /spec/lib/tmp +/yarn.lock Gemfile.lock -Gemfile31.lock coverage/* db/*.sqlite3 db/*.sqlite3-journal @@ -26,7 +28,4 @@ spec/dummy_app/log/*.log spec/dummy_app/public/uploads spec/dummy_app/Gemfile.lock tmp/**/* -/.emacs.desktop -.idea/*.xml -.sass-cache nbproject diff --git a/.rspec b/.rspec index 97f3a5d316..af054e7f5c 100644 --- a/.rspec +++ b/.rspec @@ -1,3 +1,4 @@ --color --order=random --profile +--exclude-pattern 'dummy_app/node_modules/rails_admin/**/*_spec.rb' diff --git a/.rubocop.yml b/.rubocop.yml index 5492f39a5c..8e2a87c51c 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -3,11 +3,13 @@ inherit_from: .rubocop_todo.yml AllCops: Exclude: - 'gemfiles/*' + - 'node_modules/**/*' - 'spec/dummy_app/bin/**/*' - 'spec/dummy_app/db/schema.rb' - 'spec/dummy_app/tmp/**/*' - 'vendor/bundle/**/*' NewCops: disable + SuggestExtensions: false TargetRubyVersion: 2.5 Gemspec/DateAssignment: @@ -109,7 +111,7 @@ Metrics/MethodLength: Max: 29 # TODO: Lower to 15 Metrics/ModuleLength: - Max: 202 # TODO: Lower to 100 + Max: 204 # TODO: Lower to 100 Metrics/ParameterLists: Max: 8 # TODO: Lower to 4 diff --git a/Gemfile b/Gemfile index 99204a4112..4dd3bcb8f2 100644 --- a/Gemfile +++ b/Gemfile @@ -5,6 +5,7 @@ gem 'rails' gem 'haml' gem 'devise' gem 'webrick', '~> 1.7' +gem 'webpacker', require: false group :active_record do gem 'paper_trail' diff --git a/app/assets/javascripts/rails_admin/custom/ui.js b/app/assets/javascripts/rails_admin/custom/ui.js deleted file mode 100644 index 9d6e5c7cb2..0000000000 --- a/app/assets/javascripts/rails_admin/custom/ui.js +++ /dev/null @@ -1 +0,0 @@ -// override this file in your application to add custom behaviour diff --git a/app/assets/javascripts/rails_admin/jquery-ui.js b/app/assets/javascripts/rails_admin/jquery-ui.js deleted file mode 100644 index 2f31d7f9d9..0000000000 --- a/app/assets/javascripts/rails_admin/jquery-ui.js +++ /dev/null @@ -1,3 +0,0 @@ -//= require 'jquery-ui/effect' -//= require 'jquery-ui/widgets/sortable' -//= require 'jquery-ui/widgets/autocomplete' diff --git a/app/assets/javascripts/rails_admin/ra.i18n.js b/app/assets/javascripts/rails_admin/ra.i18n.js deleted file mode 100644 index ab42470e4e..0000000000 --- a/app/assets/javascripts/rails_admin/ra.i18n.js +++ /dev/null @@ -1,28 +0,0 @@ -(function() { - var Locale; - - this.RailsAdmin || (this.RailsAdmin = {}); - - this.RailsAdmin.I18n = Locale = (function() { - function Locale() {} - - Locale.init = function(locale, translations) { - this.locale = locale; - this.translations = translations; - moment.locale(this.locale); - if (typeof this.translations === "string") { - this.translations = JSON.parse(this.translations); - } - }; - - Locale.t = function(key) { - var humanize; - humanize = key.charAt(0).toUpperCase() + key.replace(/_/g, " ").slice(1); - return this.translations[key] || humanize; - }; - - return Locale; - - })(); - -}).call(this); diff --git a/app/assets/javascripts/rails_admin/rails_admin.js b/app/assets/javascripts/rails_admin/rails_admin.js index 0850ec2a76..8a5586ef0d 100644 --- a/app/assets/javascripts/rails_admin/rails_admin.js +++ b/app/assets/javascripts/rails_admin/rails_admin.js @@ -1,6 +1,5 @@ //= require 'jquery3' //= require 'rails-ujs' -//= require 'jquery.remotipart' //= require 'rails_admin/jquery-ui' //= require 'rails_admin/moment-with-locales' //= require 'rails_admin/bootstrap-datetimepicker' diff --git a/app/assets/stylesheets/rails_admin/aristo/images/bg_fallback.png b/app/assets/stylesheets/rails_admin/aristo/images/bg_fallback.png deleted file mode 100644 index 155ebd7e93..0000000000 Binary files a/app/assets/stylesheets/rails_admin/aristo/images/bg_fallback.png and /dev/null differ diff --git a/app/assets/stylesheets/rails_admin/aristo/images/icon_sprite.png b/app/assets/stylesheets/rails_admin/aristo/images/icon_sprite.png deleted file mode 100644 index 0b376bf66c..0000000000 Binary files a/app/assets/stylesheets/rails_admin/aristo/images/icon_sprite.png and /dev/null differ diff --git a/app/assets/stylesheets/rails_admin/aristo/images/progress_bar.gif b/app/assets/stylesheets/rails_admin/aristo/images/progress_bar.gif deleted file mode 100644 index c3d43fa40b..0000000000 Binary files a/app/assets/stylesheets/rails_admin/aristo/images/progress_bar.gif and /dev/null differ diff --git a/app/assets/stylesheets/rails_admin/aristo/images/slider_handles.png b/app/assets/stylesheets/rails_admin/aristo/images/slider_handles.png deleted file mode 100644 index 872eaac305..0000000000 Binary files a/app/assets/stylesheets/rails_admin/aristo/images/slider_handles.png and /dev/null differ diff --git a/app/assets/stylesheets/rails_admin/aristo/images/ui-icons_222222_256x240.png b/app/assets/stylesheets/rails_admin/aristo/images/ui-icons_222222_256x240.png deleted file mode 100644 index 664494d838..0000000000 Binary files a/app/assets/stylesheets/rails_admin/aristo/images/ui-icons_222222_256x240.png and /dev/null differ diff --git a/app/assets/stylesheets/rails_admin/aristo/images/ui-icons_454545_256x240.png b/app/assets/stylesheets/rails_admin/aristo/images/ui-icons_454545_256x240.png deleted file mode 100644 index 8cccf85760..0000000000 Binary files a/app/assets/stylesheets/rails_admin/aristo/images/ui-icons_454545_256x240.png and /dev/null differ diff --git a/app/assets/stylesheets/rails_admin/custom/mixins.scss b/app/assets/stylesheets/rails_admin/custom/mixins.scss deleted file mode 100644 index 70921182fa..0000000000 --- a/app/assets/stylesheets/rails_admin/custom/mixins.scss +++ /dev/null @@ -1,11 +0,0 @@ -/* - Customize Sass mixins from Twitter-Bootstrap/RailsAdmin theme or add new ones for your own use. - Copy this file to your app/assets/rails_admin/custom/mixins.scss, leave this one untouched - Don't require it in your application.rb - - Available mixins to use/override: - - https://github.com/twbs/bootstrap-sass/tree/master/assets/stylesheets/bootstrap/mixins - https://github.com/railsadminteam/rails_admin/blob/master/app/assets/stylesheets/rails_admin/base/mixins.scss - Plus the ones from your theme. -*/ diff --git a/app/assets/stylesheets/rails_admin/custom/theming.scss b/app/assets/stylesheets/rails_admin/custom/theming.scss deleted file mode 100644 index 72ca4ecae0..0000000000 --- a/app/assets/stylesheets/rails_admin/custom/theming.scss +++ /dev/null @@ -1,13 +0,0 @@ -/* - Customize RailsAdmin theme here. - Copy this file to your app/assets/stylesheets/rails_admin/custom/theming.scss, leave this one untouched - Don't require it in your application.rb - - Look at the markup in RailsAdmin and go there to get inspiration from: - - http://getbootstrap.com - - Test me: (actual color should be the one defined in variables.scss if you did) - - body { background-color: $link-color; } -*/ diff --git a/app/assets/stylesheets/rails_admin/custom/variables.scss b/app/assets/stylesheets/rails_admin/custom/variables.scss deleted file mode 100644 index 4e19047169..0000000000 --- a/app/assets/stylesheets/rails_admin/custom/variables.scss +++ /dev/null @@ -1,15 +0,0 @@ -/* - Customize Sass variables from Twitter-Bootstrap/RailsAdmin theme or add new ones for your own use. - Copy this file to your app/assets/rails_admin/custom/variables.scss, leave this one untouched - Don't require it in your application.rb - - Available variables to use/override: - - https://github.com/twbs/bootstrap-sass/blob/master/assets/stylesheets/bootstrap/_variables.scss - https://github.com/railsadminteam/rails_admin/blob/master/app/assets/stylesheets/rails_admin/base/variables.scss - Plus the ones from your themes. - - Test me: pink links - - $link-color: #F0F; -*/ diff --git a/app/views/layouts/rails_admin/_head.html.haml b/app/views/layouts/rails_admin/_head.html.haml index 12e92abc52..7e9226fd65 100644 --- a/app/views/layouts/rails_admin/_head.html.haml +++ b/app/views/layouts/rails_admin/_head.html.haml @@ -3,5 +3,9 @@ %meta{content: "width=device-width, initial-scale=1", name: "viewport; charset=utf-8"} %meta{content: "NONE,NOARCHIVE", name: "robots"} = csrf_meta_tag -= stylesheet_link_tag "rails_admin/rails_admin.css", media: :all -= javascript_include_tag "rails_admin/rails_admin.js" +- if RailsAdmin::config.asset_source == :webpacker + = javascript_pack_tag "rails_admin" + = stylesheet_pack_tag "rails_admin" +- else + = stylesheet_link_tag "rails_admin/rails_admin.css", media: :all + = javascript_include_tag "rails_admin/rails_admin.js" diff --git a/gemfiles/rails_6.0.gemfile b/gemfiles/rails_6.0.gemfile index 3bad56eedd..0d393372de 100644 --- a/gemfiles/rails_6.0.gemfile +++ b/gemfiles/rails_6.0.gemfile @@ -7,6 +7,7 @@ gem "rails", "~> 6.0.0" gem "haml" gem "devise", "~> 4.7" gem "webrick", "~> 1.7" +gem "webpacker", require: false gem "sassc-rails", "~> 2.1" group :active_record do diff --git a/gemfiles/rails_6.1.gemfile b/gemfiles/rails_6.1.gemfile index 6a4d438690..2186a7011e 100644 --- a/gemfiles/rails_6.1.gemfile +++ b/gemfiles/rails_6.1.gemfile @@ -7,6 +7,7 @@ gem "rails", "~> 6.1.0" gem "haml" gem "devise", "~> 4.7" gem "webrick", "~> 1.7" +gem "webpacker", require: false gem "sassc-rails", "~> 2.1" group :active_record do diff --git a/gemfiles/rails_7.0.gemfile b/gemfiles/rails_7.0.gemfile index e29e02dc1f..46476a0f8c 100644 --- a/gemfiles/rails_7.0.gemfile +++ b/gemfiles/rails_7.0.gemfile @@ -7,6 +7,7 @@ gem "rails", "~> 7.0.0.alpha2" gem "haml" gem "devise", "~> 4.7", github: "strobilomyces/devise", branch: "patch-1" gem "webrick", "~> 1.7" +gem "webpacker", require: false gem "sassc-rails", "~> 2.1" group :active_record do diff --git a/lib/rails_admin.rb b/lib/rails_admin.rb index bc08f44614..d75c91c88e 100644 --- a/lib/rails_admin.rb +++ b/lib/rails_admin.rb @@ -55,5 +55,3 @@ def self.yaml_dump(object) YAML.dump(object) end end - -require 'rails_admin/bootstrap-sass' unless defined? Bootstrap diff --git a/lib/rails_admin/bootstrap-sass.rb b/lib/rails_admin/bootstrap-sass.rb deleted file mode 100755 index 82fd00730d..0000000000 --- a/lib/rails_admin/bootstrap-sass.rb +++ /dev/null @@ -1,49 +0,0 @@ -module RailsAdmin - module Bootstrap - class FrameworkNotFound < StandardError; end - - # Inspired by Kaminari - def self.load! - if compass? - require 'rails_admin/bootstrap-sass/compass_functions' - register_compass_extension - elsif asset_pipeline? - require 'rails_admin/bootstrap-sass/sass_functions' - end - - require 'sassc-rails' if rails? - - unless rails? || compass? - raise(Bootstrap::FrameworkNotFound.new('bootstrap-sass requires either Rails > 3.1 or Compass, neither of which are loaded')) - end - - if defined?(::Sass) && ::Sass.respond_to?(:load_paths) - stylesheets = File.expand_path(File.join('..', 'vendor', 'assets', 'stylesheets')) - fonts = File.expand_path(File.join('..', 'vendor', 'assets', 'fonts')) - ::Sass.load_paths << stylesheets - ::Sass.load_paths << fonts - end - end - - def self.asset_pipeline? - defined?(::Sprockets) - end - - def self.compass? - defined?(::Compass) - end - - def self.rails? - defined?(::Rails) - end - - def self.register_compass_extension - base = File.join(File.dirname(__FILE__), '..') - styles = File.join(base, 'vendor', 'assets', 'stylesheets') - templates = File.join(base, 'templates') - ::Compass::Frameworks.register('bootstrap', path: base, stylesheets_directory: styles, templates_directory: templates) - end - end -end - -RailsAdmin::Bootstrap.load! diff --git a/lib/rails_admin/bootstrap-sass/compass_functions.rb b/lib/rails_admin/bootstrap-sass/compass_functions.rb deleted file mode 100755 index 3e5ff870fa..0000000000 --- a/lib/rails_admin/bootstrap-sass/compass_functions.rb +++ /dev/null @@ -1,28 +0,0 @@ -module Sass - module Script - module Functions - def image_path(source, _options = {}) - if defined?(::Sprockets) - ::Sass::Script::String.new sprockets_context.image_path(source.value).to_s, :string - elsif defined?(::Compass) - image_url(source, Sass::Script::Bool.new(true)) - else - # Revert to the old compass-agnostic path determination - asset_sans_quotes = source.value.delete('"') - Sass::Script::String.new("/images/#{asset_sans_quotes}", :string) - end - end - - protected - - def sprockets_context # :nodoc: - if options.key?(:sprockets) - options[:sprockets][:context] - else - # Compatibility with sprockets pre 2.10.0 - options[:importer].context - end - end - end - end -end diff --git a/lib/rails_admin/bootstrap-sass/sass_functions.rb b/lib/rails_admin/bootstrap-sass/sass_functions.rb deleted file mode 100755 index 146bc32666..0000000000 --- a/lib/rails_admin/bootstrap-sass/sass_functions.rb +++ /dev/null @@ -1,16 +0,0 @@ -module Sass - module Script - module Functions - # LARS: Snatched from compass - 2011-11-29 - used for gradients in IE6-9 - # returns an IE hex string for a color with an alpha channel - # suitable for passing to IE filters. - def ie_hex_str(color) - assert_type color, :Color - alpha = (color.alpha * 255).round - alphastr = alpha.to_s(16).rjust(2, '0') - Sass::Script::String.new("##{alphastr}#{color.send(:hex_str)[1..-1]}".upcase) - end - declare :ie_hex_str, [:color] if respond_to?(:declare) - end - end -end diff --git a/lib/rails_admin/config.rb b/lib/rails_admin/config.rb index 951daafb00..5d4d3f472c 100644 --- a/lib/rails_admin/config.rb +++ b/lib/rails_admin/config.rb @@ -86,6 +86,9 @@ class << self attr_accessor :navigation_static_links attr_accessor :navigation_static_label + # Set where RailsAdmin fetches JS/CSS from, defaults to :sprockets + attr_accessor :asset_source + # Finish initialization by executing deferred configuration blocks def initialize! @deferred_blocks.each { |block| block.call(self) } @@ -317,6 +320,7 @@ def reset @show_gravatar = true @navigation_static_links = {} @navigation_static_label = nil + @asset_source = (defined?(Webpacker) ? :webpacker : :sprockets) @parent_controller = '::ActionController::Base' @forgery_protection_settings = {with: :exception} RailsAdmin::Config::Actions.reset diff --git a/lib/rails_admin/engine.rb b/lib/rails_admin/engine.rb index 9b2cb2fd6e..821673bec7 100644 --- a/lib/rails_admin/engine.rb +++ b/lib/rails_admin/engine.rb @@ -5,7 +5,6 @@ require 'rack-pjax' require 'rails' require 'rails_admin' -require 'remotipart' module RailsAdmin class Engine < Rails::Engine @@ -14,10 +13,12 @@ class Engine < Rails::Engine config.action_dispatch.rescue_responses['RailsAdmin::ActionNotAllowed'] = :forbidden initializer 'RailsAdmin precompile hook', group: :all do |app| - app.config.assets.precompile += %w( - rails_admin/rails_admin.js - rails_admin/rails_admin.css - ) + if app.config.respond_to?(:assets) + app.config.assets.precompile += %w( + rails_admin/rails_admin.js + rails_admin/rails_admin.css + ) + end end initializer 'RailsAdmin setup middlewares' do |app| diff --git a/package.json b/package.json new file mode 100644 index 0000000000..5478f6d54d --- /dev/null +++ b/package.json @@ -0,0 +1,21 @@ +{ + "dependencies": { + "@fortawesome/fontawesome-free": "^5.15.4", + "@rails/ujs": "^6.1.4-1", + "bootstrap": "3.4.1", + "bootstrap-sass": "3.4.1", + "eonasdan-bootstrap-datetimepicker": "^4.17.49", + "jquery": "^3.6.0", + "jquery-ui": "^1.12.1", + "moment": "^2.29.1" + }, + "directories": { + "src": "./src" + }, + "version": "1.0.0", + "description": "RailsAdmin is a Rails engine that provides an easy-to-use interface for managing your data.", + "name": "rails_admin", + "scripts": { + "link": "yarn link && cd spec/dummy_app && yarn link rails_admin" + } +} diff --git a/rails_admin.gemspec b/rails_admin.gemspec index 696eacf733..1d7c12c622 100644 --- a/rails_admin.gemspec +++ b/rails_admin.gemspec @@ -13,7 +13,6 @@ Gem::Specification.new do |spec| spec.add_dependency 'nested_form', '~> 0.3' spec.add_dependency 'rack-pjax', '>= 0.7' spec.add_dependency 'rails', ['>= 6.0', '< 8'] - spec.add_dependency 'remotipart', '~> 1.3' spec.add_dependency 'sassc-rails', ['>= 1.3', '< 3'] spec.add_dependency 'activemodel-serializers-xml', '>= 1.0' spec.add_development_dependency 'bundler', '>= 1.0' diff --git a/spec/dummy_app/.browserslistrc b/spec/dummy_app/.browserslistrc new file mode 100644 index 0000000000..e94f8140cc --- /dev/null +++ b/spec/dummy_app/.browserslistrc @@ -0,0 +1 @@ +defaults diff --git a/spec/dummy_app/.gitignore b/spec/dummy_app/.gitignore index dd71abbe4e..e0c3904638 100644 --- a/spec/dummy_app/.gitignore +++ b/spec/dummy_app/.gitignore @@ -15,3 +15,11 @@ /tmp /public/system + +/public/packs +/public/packs-test +/node_modules +/yarn-error.log +/yarn.lock +yarn-debug.log* +.yarn-integrity diff --git a/spec/dummy_app/Gemfile b/spec/dummy_app/Gemfile index dbac492daa..c1716537cc 100644 --- a/spec/dummy_app/Gemfile +++ b/spec/dummy_app/Gemfile @@ -1,6 +1,7 @@ source 'https://rubygems.org' gem 'rails', '>= 6.0.0' +gem 'webpacker', require: false group :active_record do platforms :jruby do @@ -30,10 +31,11 @@ gem 'carrierwave', '>= 2.0.0.rc', '< 3.0' gem 'devise', '>= 3.2' gem 'dragonfly', '~> 1.0' gem 'mini_magick', '>= 3.4' -gem 'mlb', '>= 0.7' +gem 'mlb', '>= 0.7', github: 'mshibuya/mlb', branch: 'ruby-3' gem 'paperclip', '>= 3.4' gem 'rails_admin', path: '../../' gem 'shrine', '~> 3.0' +gem 'webrick', '~> 1.7' # Gems used only for assets and not required # in production environments by default. diff --git a/spec/dummy_app/app/assets/javascripts/application.js b/spec/dummy_app/app/assets/javascripts/application.js index 9097d830e2..116e594b8d 100644 --- a/spec/dummy_app/app/assets/javascripts/application.js +++ b/spec/dummy_app/app/assets/javascripts/application.js @@ -10,6 +10,5 @@ // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD // GO AFTER THE REQUIRES BELOW. // -//= require jquery -//= require jquery_ujs +//= require rails-ujs //= require_tree . diff --git a/spec/dummy_app/app/javascript/packs/application.js b/spec/dummy_app/app/javascript/packs/application.js new file mode 100644 index 0000000000..7c3021d7ed --- /dev/null +++ b/spec/dummy_app/app/javascript/packs/application.js @@ -0,0 +1,18 @@ +/* eslint no-console:0 */ +// This file is automatically compiled by Webpack, along with any other files +// present in this directory. You're encouraged to place your actual application logic in +// a relevant structure within app/javascript and only use these pack files to reference +// that code so it'll be compiled. +// +// To reference this file, add <%= javascript_pack_tag 'application' %> to the appropriate +// layout file, like app/views/layouts/application.html.erb + + +// Uncomment to copy all static images under ../images to the output folder and reference +// them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>) +// or the `imagePath` JavaScript helper below. +// +// const images = require.context('../images', true) +// const imagePath = (name) => images(name, true) + +console.log('Hello World from Webpacker') diff --git a/spec/dummy_app/app/javascript/packs/rails_admin.js b/spec/dummy_app/app/javascript/packs/rails_admin.js new file mode 100644 index 0000000000..470aa39994 --- /dev/null +++ b/spec/dummy_app/app/javascript/packs/rails_admin.js @@ -0,0 +1,2 @@ +import 'rails_admin/src/rails_admin/base' +import '../stylesheets/rails_admin.scss' \ No newline at end of file diff --git a/spec/dummy_app/app/javascript/stylesheets/rails_admin.scss b/spec/dummy_app/app/javascript/stylesheets/rails_admin.scss new file mode 100644 index 0000000000..185a07bb66 --- /dev/null +++ b/spec/dummy_app/app/javascript/stylesheets/rails_admin.scss @@ -0,0 +1 @@ +@import "~rails_admin/src/rails_admin/styles/base.scss"; \ No newline at end of file diff --git a/spec/dummy_app/babel.config.js b/spec/dummy_app/babel.config.js new file mode 100644 index 0000000000..19a07f3146 --- /dev/null +++ b/spec/dummy_app/babel.config.js @@ -0,0 +1,82 @@ +module.exports = function(api) { + var validEnv = ['development', 'test', 'production'] + var currentEnv = api.env() + var isDevelopmentEnv = api.env('development') + var isProductionEnv = api.env('production') + var isTestEnv = api.env('test') + + if (!validEnv.includes(currentEnv)) { + throw new Error( + 'Please specify a valid `NODE_ENV` or ' + + '`BABEL_ENV` environment variables. Valid values are "development", ' + + '"test", and "production". Instead, received: ' + + JSON.stringify(currentEnv) + + '.' + ) + } + + return { + presets: [ + isTestEnv && [ + '@babel/preset-env', + { + targets: { + node: 'current' + } + } + ], + (isProductionEnv || isDevelopmentEnv) && [ + '@babel/preset-env', + { + forceAllTransforms: true, + useBuiltIns: 'entry', + corejs: 3, + modules: false, + exclude: ['transform-typeof-symbol'] + } + ] + ].filter(Boolean), + plugins: [ + 'babel-plugin-macros', + '@babel/plugin-syntax-dynamic-import', + isTestEnv && 'babel-plugin-dynamic-import-node', + '@babel/plugin-transform-destructuring', + [ + '@babel/plugin-proposal-class-properties', + { + loose: true + } + ], + [ + '@babel/plugin-proposal-object-rest-spread', + { + useBuiltIns: true + } + ], + [ + '@babel/plugin-proposal-private-methods', + { + loose: true + } + ], + [ + '@babel/plugin-proposal-private-property-in-object', + { + loose: true + } + ], + [ + '@babel/plugin-transform-runtime', + { + helpers: false + } + ], + [ + '@babel/plugin-transform-regenerator', + { + async: false + } + ] + ].filter(Boolean) + } +} diff --git a/spec/dummy_app/bin/webpack b/spec/dummy_app/bin/webpack new file mode 100755 index 0000000000..1031168d01 --- /dev/null +++ b/spec/dummy_app/bin/webpack @@ -0,0 +1,18 @@ +#!/usr/bin/env ruby + +ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development" +ENV["NODE_ENV"] ||= "development" + +require "pathname" +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require "bundler/setup" + +require "webpacker" +require "webpacker/webpack_runner" + +APP_ROOT = File.expand_path("..", __dir__) +Dir.chdir(APP_ROOT) do + Webpacker::WebpackRunner.run(ARGV) +end diff --git a/spec/dummy_app/bin/webpack-dev-server b/spec/dummy_app/bin/webpack-dev-server new file mode 100755 index 0000000000..dd9662737a --- /dev/null +++ b/spec/dummy_app/bin/webpack-dev-server @@ -0,0 +1,18 @@ +#!/usr/bin/env ruby + +ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development" +ENV["NODE_ENV"] ||= "development" + +require "pathname" +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require "bundler/setup" + +require "webpacker" +require "webpacker/dev_server_runner" + +APP_ROOT = File.expand_path("..", __dir__) +Dir.chdir(APP_ROOT) do + Webpacker::DevServerRunner.run(ARGV) +end diff --git a/spec/dummy_app/config/application.rb b/spec/dummy_app/config/application.rb index e6350d480f..34e0c3e726 100644 --- a/spec/dummy_app/config/application.rb +++ b/spec/dummy_app/config/application.rb @@ -2,7 +2,6 @@ require 'action_controller/railtie' require 'action_mailer/railtie' -require 'sprockets/railtie' begin require CI_ORM.to_s @@ -14,6 +13,13 @@ require 'active_storage/engine' if CI_ORM == :active_record require 'action_text/engine' if CI_ORM == :active_record +case CI_ASSET +when :webpacker + require 'webpacker' +else + require "#{CI_ASSET}/railtie" +end + # Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. Bundler.require(*Rails.groups, CI_ORM) diff --git a/spec/dummy_app/config/boot.rb b/spec/dummy_app/config/boot.rb index 8e888c88d4..48e6a20cc2 100644 --- a/spec/dummy_app/config/boot.rb +++ b/spec/dummy_app/config/boot.rb @@ -1,4 +1,5 @@ CI_ORM = (ENV['CI_ORM'] || :active_record).to_sym unless defined?(CI_ORM) +CI_ASSET = (ENV['CI_ASSET'] || :sprockets).to_sym unless defined?(CI_ASSET) ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) require 'bundler/setup' # Set up gems listed in the Gemfile. diff --git a/spec/dummy_app/config/environments/development.rb b/spec/dummy_app/config/environments/development.rb index bd8043d9af..2bffc813e4 100644 --- a/spec/dummy_app/config/environments/development.rb +++ b/spec/dummy_app/config/environments/development.rb @@ -31,19 +31,21 @@ # Raise an error on page load if there are pending migrations. config.active_record.migration_error = :page_load if CI_ORM == :active_record - # Debug mode disables concatenation and preprocessing of assets. - # This option may cause significant delays in view rendering with a large - # number of complex assets. - config.assets.debug = true - - # Asset digests allow you to set far-future HTTP expiration dates on all assets, - # yet still be able to expire them through the digest params. - config.assets.digest = true - - # Adds additional error checking when serving assets at runtime. - # Checks for improperly declared sprockets dependencies. - # Raises helpful error messages. - config.assets.raise_runtime_errors = true + if config.respond_to?(:assets) + # Debug mode disables concatenation and preprocessing of assets. + # This option may cause significant delays in view rendering with a large + # number of complex assets. + config.assets.debug = true + + # Asset digests allow you to set far-future HTTP expiration dates on all assets, + # yet still be able to expire them through the digest params. + config.assets.digest = true + + # Adds additional error checking when serving assets at runtime. + # Checks for improperly declared sprockets dependencies. + # Raises helpful error messages. + config.assets.raise_runtime_errors = true + end # Raises error for missing translations # config.action_view.raise_on_missing_translations = true diff --git a/spec/dummy_app/config/initializers/assets.rb b/spec/dummy_app/config/initializers/assets.rb index 01ef3e6630..bdc864b95d 100644 --- a/spec/dummy_app/config/initializers/assets.rb +++ b/spec/dummy_app/config/initializers/assets.rb @@ -1,7 +1,7 @@ # Be sure to restart your server when you modify this file. # Version of your assets, change this if you want to expire all your assets. -Rails.application.config.assets.version = '1.0' +Rails.application.config.assets.version = '1.0' if Rails.application.config.respond_to?(:assets) # Add additional assets to the asset load path # Rails.application.config.assets.paths << Emoji.images_path diff --git a/spec/dummy_app/config/webpack/development.js b/spec/dummy_app/config/webpack/development.js new file mode 100644 index 0000000000..c5edff94ad --- /dev/null +++ b/spec/dummy_app/config/webpack/development.js @@ -0,0 +1,5 @@ +process.env.NODE_ENV = process.env.NODE_ENV || 'development' + +const environment = require('./environment') + +module.exports = environment.toWebpackConfig() diff --git a/spec/dummy_app/config/webpack/environment.js b/spec/dummy_app/config/webpack/environment.js new file mode 100644 index 0000000000..f75acd8462 --- /dev/null +++ b/spec/dummy_app/config/webpack/environment.js @@ -0,0 +1,11 @@ +const webpack = require('webpack'); +const { environment } = require('@rails/webpacker') + +environment.plugins.append( + 'ProvidePlugin-jQuery', + new webpack.ProvidePlugin({ + jQuery: 'jquery', + }) +); + +module.exports = environment diff --git a/spec/dummy_app/config/webpack/production.js b/spec/dummy_app/config/webpack/production.js new file mode 100644 index 0000000000..be0f53aacf --- /dev/null +++ b/spec/dummy_app/config/webpack/production.js @@ -0,0 +1,5 @@ +process.env.NODE_ENV = process.env.NODE_ENV || 'production' + +const environment = require('./environment') + +module.exports = environment.toWebpackConfig() diff --git a/spec/dummy_app/config/webpack/test.js b/spec/dummy_app/config/webpack/test.js new file mode 100644 index 0000000000..c5edff94ad --- /dev/null +++ b/spec/dummy_app/config/webpack/test.js @@ -0,0 +1,5 @@ +process.env.NODE_ENV = process.env.NODE_ENV || 'development' + +const environment = require('./environment') + +module.exports = environment.toWebpackConfig() diff --git a/spec/dummy_app/config/webpacker.yml b/spec/dummy_app/config/webpacker.yml new file mode 100644 index 0000000000..390a6c5d1e --- /dev/null +++ b/spec/dummy_app/config/webpacker.yml @@ -0,0 +1,93 @@ +# Note: You must restart bin/webpack-dev-server for changes to take effect + +default: &default + source_path: app/javascript + source_entry_path: packs + public_root_path: public + public_output_path: packs + cache_path: tmp/cache/webpacker + webpack_compile_output: true + + # Additional paths webpack should lookup modules + # ['app/assets', 'engine/foo/app/assets'] + additional_paths: ['node_modules/rails_admin/src'] + + # Reload manifest.json on all requests so we reload latest compiled packs + cache_manifest: false + + # Extract and emit a css file + extract_css: false + + static_assets_extensions: + - .jpg + - .jpeg + - .png + - .gif + - .tiff + - .ico + - .svg + - .eot + - .otf + - .ttf + - .woff + - .woff2 + + extensions: + - .mjs + - .js + - .sass + - .scss + - .css + - .module.sass + - .module.scss + - .module.css + - .png + - .svg + - .gif + - .jpeg + - .jpg + +development: + <<: *default + compile: true + + # Reference: https://webpack.js.org/configuration/dev-server/ + dev_server: + https: false + host: localhost + port: 3035 + public: localhost:3035 + hmr: false + # Inline should be set to true if using HMR + inline: true + overlay: true + compress: true + disable_host_check: true + use_local_ip: false + quiet: false + pretty: false + headers: + 'Access-Control-Allow-Origin': '*' + watch_options: + ignored: '**/node_modules/**' + + +test: + <<: *default + compile: true + additional_paths: ['src'] # relative from the project root + + # Compile test packs to a separate directory + public_output_path: packs-test + +production: + <<: *default + + # Production depends on precompilation of packs prior to booting for performance. + compile: false + + # Extract and emit a css file + extract_css: true + + # Cache manifest.json for performance + cache_manifest: true diff --git a/spec/dummy_app/package.json b/spec/dummy_app/package.json new file mode 100644 index 0000000000..d849b38f48 --- /dev/null +++ b/spec/dummy_app/package.json @@ -0,0 +1,14 @@ +{ + "name": "dummy_app", + "private": true, + "version": "0.1.0", + "dependencies": { + "@rails/webpacker": "5.4.3", + "webpack": "^4.46.0", + "webpack-cli": "^3.3.12", + "rails_admin": "file:../../" + }, + "devDependencies": { + "webpack-dev-server": "^3" + } +} diff --git a/spec/dummy_app/postcss.config.js b/spec/dummy_app/postcss.config.js new file mode 100644 index 0000000000..aa5998a809 --- /dev/null +++ b/spec/dummy_app/postcss.config.js @@ -0,0 +1,12 @@ +module.exports = { + plugins: [ + require('postcss-import'), + require('postcss-flexbugs-fixes'), + require('postcss-preset-env')({ + autoprefixer: { + flexbox: 'no-2009' + }, + stage: 3 + }) + ] +} diff --git a/spec/integration/rails_admin_spec.rb b/spec/integration/rails_admin_spec.rb index a4bc13ba1a..a4168a5c79 100644 --- a/spec/integration/rails_admin_spec.rb +++ b/spec/integration/rails_admin_spec.rb @@ -31,11 +31,21 @@ # Note: the [href^="/asset... syntax matches the start of a value. The reason # we just do that is to avoid being confused by rails' asset_ids. it 'loads stylesheets in header' do - is_expected.to have_selector('head link[href^="/assets/rails_admin/rails_admin"][href$=".css"]', visible: false) + case RailsAdmin.config.asset_source + when :sprockets + is_expected.to have_selector('head link[href^="/assets/rails_admin/rails_admin"][href$=".css"]', visible: false) + when :webpacker + is_expected.to have_no_selector('head link[href~="rails_admin"][href$=".css"]', visible: false) + end end it 'loads javascript files in body' do - is_expected.to have_selector('head script[src^="/assets/rails_admin/rails_admin"][src$=".js"]', visible: false) + case RailsAdmin.config.asset_source + when :sprockets + is_expected.to have_selector('head script[src^="/assets/rails_admin/rails_admin"][src$=".js"]', visible: false) + when :webpacker + is_expected.to have_selector('head script[src^="/packs-test/js/rails_admin"][src$=".js"]', visible: false) + end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 05b0619d18..41c13f805a 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -96,6 +96,10 @@ def password_digest(password) Capybara.reset! if example.metadata[:js] end + config.before(:all) do + Webpacker.instance.compiler.compile if defined?(Webpacker) + end + config.before do |example| DatabaseCleaner.strategy = (CI_ORM == :mongoid || example.metadata[:js]) ? :deletion : :transaction diff --git a/src/rails_admin/base.js b/src/rails_admin/base.js new file mode 100644 index 0000000000..32b9eb3353 --- /dev/null +++ b/src/rails_admin/base.js @@ -0,0 +1,21 @@ +import Rails from '@rails/ujs' +import jQuery from 'jquery' +import moment from 'moment' +import './vendor/jquery.pjax' +import './vendor/jquery_nested_form' +import 'bootstrap' +import 'moment/min/locales.js' +import 'eonasdan-bootstrap-datetimepicker' + +import './filter-box' +import './filtering-multiselect' +import './filtering-select' +import './nested-form-hooks' +import './remote-form' +import './sidescroll' +import './ui' +import './widgets' + +Rails.start(); +window.$ = window.jQuery = jQuery; +window.moment = moment; \ No newline at end of file diff --git a/app/assets/javascripts/rails_admin/ra.filter-box.js b/src/rails_admin/filter-box.js similarity index 86% rename from app/assets/javascripts/rails_admin/ra.filter-box.js rename to src/rails_admin/filter-box.js index 8439a218bf..c7584c05e3 100644 --- a/app/assets/javascripts/rails_admin/ra.filter-box.js +++ b/src/rails_admin/filter-box.js @@ -1,3 +1,7 @@ +import jQuery from 'jquery'; +import moment from 'moment' +import I18n from './i18n'; + (function($) { var filters; @@ -23,13 +27,13 @@ control = $('') .prop('name', value_name) .append('') - .append($('').prop('selected', field_value == "true").text(RailsAdmin.I18n.t("true"))) - .append($('').prop('selected', field_value == "false").text(RailsAdmin.I18n.t("false"))) + .append($('').prop('selected', field_value == "true").text(I18n.t("true"))) + .append($('').prop('selected', field_value == "false").text(I18n.t("false"))) if (!required) { control.append([ '', - $('').prop('selected', field_value == "_present").text(RailsAdmin.I18n.t("is_present")), - $('').prop('selected', field_value == "_blank").text(RailsAdmin.I18n.t("is_blank")) + $('').prop('selected', field_value == "_present").text(I18n.t("is_present")), + $('').prop('selected', field_value == "_blank").text(I18n.t("is_blank")) ]) } break; @@ -39,21 +43,21 @@ case 'time': control = control || $('') .prop('name', operator_name) - .append($('').prop('selected', field_operator == "default").text(RailsAdmin.I18n.t(field_type == "time" ? "time" : "date"))) - .append($('').prop('selected', field_operator == "between").text(RailsAdmin.I18n.t("between_and_"))) + .append($('').prop('selected', field_operator == "default").text(I18n.t(field_type == "time" ? "time" : "date"))) + .append($('').prop('selected', field_operator == "between").text(I18n.t("between_and_"))) if (field_type != 'time') { control.append([ - $('').prop('selected', field_operator == "today").text(RailsAdmin.I18n.t("today")), - $('').prop('selected', field_operator == "yesterday").text(RailsAdmin.I18n.t("yesterday")), - $('').prop('selected', field_operator == "this_week").text(RailsAdmin.I18n.t("this_week")), - $('').prop('selected', field_operator == "last_week").text(RailsAdmin.I18n.t("last_week")), + $('').prop('selected', field_operator == "today").text(I18n.t("today")), + $('').prop('selected', field_operator == "yesterday").text(I18n.t("yesterday")), + $('').prop('selected', field_operator == "this_week").text(I18n.t("this_week")), + $('').prop('selected', field_operator == "last_week").text(I18n.t("last_week")), ]) } if (!required) { control.append([ '', - $('').prop('selected', field_operator == "_not_null").text(RailsAdmin.I18n.t("is_present")), - $('').prop('selected', field_operator == "_null").text(RailsAdmin.I18n.t("is_blank")) + $('').prop('selected', field_operator == "_not_null").text(I18n.t("is_present")), + $('').prop('selected', field_operator == "_null").text(I18n.t("is_blank")) ]) } additional_control = @@ -83,8 +87,8 @@ .data('name', value_name) .append('') .append(required ? [] : [ - $('').prop('selected', field_value == "_present").text(RailsAdmin.I18n.t("is_present")), - $('').prop('selected', field_value == "_blank").text(RailsAdmin.I18n.t("is_blank")), + $('').prop('selected', field_value == "_present").text(I18n.t("is_present")), + $('').prop('selected', field_value == "_blank").text(I18n.t("is_blank")), '' ]) .append(select_options) @@ -107,15 +111,15 @@ .prop('value', field_operator) .prop('name', operator_name) .append('') - .append($('').prop('selected', field_operator == "like").text(RailsAdmin.I18n.t("contains"))) - .append($('').prop('selected', field_operator == "is").text(RailsAdmin.I18n.t("is_exactly"))) - .append($('').prop('selected', field_operator == "starts_with").text(RailsAdmin.I18n.t("starts_with"))) - .append($('').prop('selected', field_operator == "ends_with").text(RailsAdmin.I18n.t("ends_with"))) + .append($('').prop('selected', field_operator == "like").text(I18n.t("contains"))) + .append($('').prop('selected', field_operator == "is").text(I18n.t("is_exactly"))) + .append($('').prop('selected', field_operator == "starts_with").text(I18n.t("starts_with"))) + .append($('').prop('selected', field_operator == "ends_with").text(I18n.t("ends_with"))) if (!required) { control.append([ '', - $('').prop('selected', field_operator == "_present").text(RailsAdmin.I18n.t("is_present")), - $('').prop('selected', field_operator == "_blank").text(RailsAdmin.I18n.t("is_blank")) + $('').prop('selected', field_operator == "_present").text(I18n.t("is_present")), + $('').prop('selected', field_operator == "_blank").text(I18n.t("is_blank")) ]) } additional_control = $('') @@ -128,13 +132,13 @@ case 'float': control = $('') .prop('name', operator_name) - .append($('').prop('selected', field_operator == "default").text(RailsAdmin.I18n.t("number"))) - .append($('').prop('selected', field_operator == "between").text(RailsAdmin.I18n.t("between_and_"))) + .append($('').prop('selected', field_operator == "default").text(I18n.t("number"))) + .append($('').prop('selected', field_operator == "between").text(I18n.t("between_and_"))) if (!required) { control.append([ '', - $('').prop('selected', field_operator == "_not_null").text(RailsAdmin.I18n.t("is_present")), - $('').prop('selected', field_operator == "_null").text(RailsAdmin.I18n.t("is_blank")) + $('').prop('selected', field_operator == "_not_null").text(I18n.t("is_present")), + $('').prop('selected', field_operator == "_null").text(I18n.t("is_blank")) ]) } additional_control = @@ -184,7 +188,7 @@ $content.find('.date, .datetime').each(function() { $(this).datetimepicker({ date: moment($(this).siblings('[type=hidden]').val()), - locale: RailsAdmin.I18n.locale, + locale: I18n.locale, showTodayButton: true, format: options['datetimepicker_format'] }); @@ -216,7 +220,7 @@ $(document).on('click', "#filters_box .delete", function(e) { e.preventDefault(); - form = $(this).parents('form'); + var form = $(this).parents('form'); $(this).parents('.filter').remove(); !$("#filters_box").children().length && $("hr.filters_box:visible").hide('slow'); }); @@ -232,7 +236,8 @@ $(document).on('change', "#filters_box .switch-additional-fieldsets", function(e) { var selected_option = $(this).find('option:selected'); - if(klass = $(selected_option).data('additional-fieldset')) { + var klass = $(selected_option).data('additional-fieldset'); + if(klass) { $(this).siblings('.additional-fieldset:not(.' + klass + ')').hide('slow'); $(this).siblings('.' + klass).show('slow'); } else { diff --git a/app/assets/javascripts/rails_admin/ra.filtering-multiselect.js b/src/rails_admin/filtering-multiselect.js similarity index 97% rename from app/assets/javascripts/rails_admin/ra.filtering-multiselect.js rename to src/rails_admin/filtering-multiselect.js index 34350740e1..08b3d2cc43 100644 --- a/app/assets/javascripts/rails_admin/ra.filtering-multiselect.js +++ b/src/rails_admin/filtering-multiselect.js @@ -1,14 +1,7 @@ -/* - * RailsAdmin filtering multiselect @VERSION - * - * License - * - * http://www.railsadmin.org - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ +import jQuery from 'jquery'; +import 'jquery-ui/ui/widget'; +import I18n from './i18n'; + (function($) { $.widget("ra.filteringMultiselect", { _cache: {}, @@ -120,8 +113,8 @@ this.element.css({display: "none"}); - this.tooManyObjectsPlaceholder = $('