зеркало из
https://github.com/rs-pro/activeadmin-quill_editor.git
synced 2026-08-28 15:36:17 +03:00
Сравнить коммиты
138 Коммитов
| Автор | SHA1 | Дата | |
|---|---|---|---|
|
|
13e2e83f18 | ||
|
|
c4a0fd2d17 | ||
|
|
1a6a7c6878 | ||
|
|
39380e7276 | ||
|
|
0a12969370 | ||
|
|
10ea2928a4 | ||
|
|
22e8fb58da | ||
|
|
e5035f96b5 | ||
|
|
c7a2fec052 | ||
|
|
74cbb7853d | ||
|
|
cd97f2eeb8 | ||
|
|
9d11acb6ec | ||
|
|
4c8d511bf6 | ||
|
|
96166aaf12 | ||
|
|
c26aef65ab | ||
|
|
194518dea4 | ||
|
|
395a099a3c | ||
|
|
826a3dee1c | ||
|
|
21d1395b77 | ||
|
|
d588651863 | ||
|
|
7f3d842e3a | ||
|
|
f291f7e7e6 | ||
|
|
df944277b5 | ||
|
|
3cc5683d44 | ||
|
|
498cbbd0c9 | ||
|
|
bfc2e997f1 | ||
|
|
9bda446762 | ||
|
|
533471c0d6 | ||
|
|
3617aab7f2 | ||
|
|
5196a8811a | ||
|
|
5e9a3b6c5a | ||
|
|
181aab7fd6 | ||
|
|
300b4a0a03 | ||
|
|
451a225277 | ||
|
|
6cbb39daad | ||
|
|
d19fc7ddfc | ||
|
|
74790fc115 | ||
|
|
c3b129a212 | ||
|
|
ab858f7c6f | ||
|
|
6cf744b84c | ||
|
|
0ae4ce2035 | ||
|
|
dd9aa22cf5 | ||
|
|
b6f3c0c3a6 | ||
|
|
7d3a084977 | ||
|
|
1569b1ff18 | ||
|
|
3459800dbf | ||
|
|
af901f4f7d | ||
|
|
328ee0d9fa | ||
|
|
751196ef8c | ||
|
|
589b782866 | ||
|
|
554f6086e7 | ||
|
|
051ada9843 | ||
|
|
fd90851a6b | ||
|
|
bd32c5f28f | ||
|
|
21ec7a918b | ||
|
|
b310f9e71b | ||
|
|
bbee6f7681 | ||
|
|
57e151aa03 | ||
|
|
0913bb6915 | ||
|
|
728e3fa097 | ||
|
|
9d891f0602 | ||
|
|
21fc69c2c0 | ||
|
|
b0e770ca9e | ||
|
|
ba53f9febf | ||
|
|
d690b9906f | ||
|
|
99908f97f7 | ||
|
|
9389f9e32d | ||
|
|
4629ac4133 | ||
|
|
0d4485c321 | ||
|
|
0c1cfefa83 | ||
|
|
0c674025a9 | ||
|
|
770e069442 | ||
|
|
d346729cd1 | ||
|
|
ce65cfbb7e | ||
|
|
22a1c8714c | ||
|
|
489e1c35eb | ||
|
|
62efca80d6 | ||
|
|
46168cc7f8 | ||
|
|
02310804aa | ||
|
|
7e2f8733dc | ||
|
|
2d0a8f961f | ||
|
|
7262ad5523 | ||
|
|
71f227736d | ||
|
|
361da5096d | ||
|
|
17ef9aa5db | ||
|
|
b00fcd90ab | ||
|
|
edf5cbcb13 | ||
|
|
38e5406d5d | ||
|
|
c560dd5c60 | ||
|
|
597cae7adb | ||
|
|
6d0599c39e | ||
|
|
664765ac79 | ||
|
|
7be390701f | ||
|
|
e4401a469b | ||
|
|
d8632f069a | ||
|
|
7498cd65a1 | ||
|
|
038d66f387 | ||
|
|
7af25106a2 | ||
|
|
d021f3650e | ||
|
|
8a13dd49a4 | ||
|
|
1cad5a10c3 | ||
|
|
63b4c118f6 | ||
|
|
277d1a521a | ||
|
|
4a0ea5e8f2 | ||
|
|
ffc57e7d90 | ||
|
|
2ebc9176b4 | ||
|
|
0b44c683e6 | ||
|
|
9b460d36e3 | ||
|
|
d41f8450ea | ||
|
|
401d2528e8 | ||
|
|
e086bac0a7 | ||
|
|
36cd836ca8 | ||
|
|
c05666673e | ||
|
|
2d5429718c | ||
|
|
78126d0cd7 | ||
|
|
3190134973 | ||
|
|
8d6b05297a | ||
|
|
5d9b6f70fd | ||
|
|
6fa021c0c7 | ||
|
|
357ef382d6 | ||
|
|
43ae70c7c9 | ||
|
|
6daf6f6bc8 | ||
|
|
98c235d346 | ||
|
|
e6e6742753 | ||
|
|
c2c8d48795 | ||
|
|
72062c1a30 | ||
|
|
c4aa91225b | ||
|
|
3cc6edb302 | ||
|
|
d78fb2eb9c | ||
|
|
e5db64af96 | ||
|
|
c0d37ad94e | ||
|
|
96c70106a4 | ||
|
|
4ec6e80760 | ||
|
|
707f4a5cc7 | ||
|
|
dc97316303 | ||
|
|
e9b8abc88e | ||
|
|
582667dc59 | ||
|
|
76c06f5346 |
@@ -1,33 +0,0 @@
|
||||
version: 2.1
|
||||
orbs:
|
||||
ruby: circleci/ruby@0.1.2
|
||||
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: circleci/ruby:2.6.6-stretch-node-browsers
|
||||
executor: ruby/default
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
key: gem-cache-{{ checksum "activeadmin_quill_editor.gemspec" }}
|
||||
- run:
|
||||
name: Setup Bundler
|
||||
command: gem install bundler
|
||||
- run:
|
||||
name: Bundle Install
|
||||
command: bundle install --path vendor/bundle
|
||||
- save_cache:
|
||||
key: gem-cache-{{ checksum "activeadmin_quill_editor.gemspec" }}
|
||||
paths: vendor/bundle
|
||||
- run:
|
||||
name: Run Specs
|
||||
command: |
|
||||
bin/rspec \
|
||||
--profile 10 \
|
||||
--format RspecJunitFormatter \
|
||||
--out test_results/rspec.xml \
|
||||
--format progress \
|
||||
$(circleci tests glob "spec/**/*_spec.rb")
|
||||
- store_test_results:
|
||||
path: test_results
|
||||
7
.fasterer.yml
Обычный файл
7
.fasterer.yml
Обычный файл
@@ -0,0 +1,7 @@
|
||||
---
|
||||
exclude_paths:
|
||||
- bin/*
|
||||
- db/schema.rb
|
||||
- gemfiles/**/*
|
||||
- spec/dummy/**/*
|
||||
- vendor/**/*
|
||||
13
.github/FUNDING.yml
поставляемый
Обычный файл
13
.github/FUNDING.yml
поставляемый
Обычный файл
@@ -0,0 +1,13 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [blocknotes]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
84
.github/workflows/ci.yml
поставляемый
Обычный файл
84
.github/workflows/ci.yml
поставляемый
Обычный файл
@@ -0,0 +1,84 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, master]
|
||||
pull_request:
|
||||
branches: [main, master]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
ruby: ['3.2', '3.3', '3.4']
|
||||
gemfile:
|
||||
- rails_7.2_active_admin_4.x
|
||||
- rails_8.0_active_admin_4.x
|
||||
|
||||
env:
|
||||
BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile
|
||||
RAILS_ENV: test
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby }}
|
||||
bundler-cache: true
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: spec/dummy/package-lock.json
|
||||
|
||||
- name: Install npm dependencies for dummy app
|
||||
run: |
|
||||
cd spec/dummy
|
||||
npm install
|
||||
|
||||
- name: Build assets for dummy app
|
||||
run: |
|
||||
cd spec/dummy
|
||||
# Build JavaScript with esbuild
|
||||
npm run build:js || true
|
||||
# Build CSS with Tailwind
|
||||
npm run build:css || true
|
||||
|
||||
- name: Database setup
|
||||
run: |
|
||||
cd spec/dummy
|
||||
bundle exec rails db:create db:migrate db:test:prepare
|
||||
|
||||
- name: Run tests
|
||||
run: bundle exec rspec --format progress
|
||||
|
||||
- name: Upload screenshots on failure
|
||||
uses: actions/upload-artifact@v4
|
||||
if: failure()
|
||||
with:
|
||||
name: test-screenshots-${{ matrix.ruby }}-${{ matrix.gemfile }}
|
||||
path: spec/dummy/tmp/capybara
|
||||
if-no-files-found: ignore
|
||||
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: '3.4'
|
||||
bundler-cache: true
|
||||
|
||||
- name: Run RuboCop
|
||||
run: bundle exec rubocop --force-exclusion
|
||||
5
.gitignore
поставляемый
5
.gitignore
поставляемый
@@ -6,7 +6,12 @@
|
||||
/Gemfile.lock
|
||||
|
||||
/_misc/
|
||||
/coverage/
|
||||
/spec/dummy/db/*.sqlite3*
|
||||
/spec/dummy/db/schema-dev.rb
|
||||
/spec/dummy/log/
|
||||
/spec/dummy/storage/
|
||||
/spec/dummy/tmp/
|
||||
tmp/
|
||||
/spec/dummy/node_modules/
|
||||
/gemfiles/*.gemfile.lock
|
||||
|
||||
13
.overcommit.yml
Обычный файл
13
.overcommit.yml
Обычный файл
@@ -0,0 +1,13 @@
|
||||
CommitMsg:
|
||||
CapitalizedSubject:
|
||||
enabled: false
|
||||
|
||||
MessageFormat:
|
||||
enabled: true
|
||||
pattern: "^(fixup! ){0,1}(fix|feat|build|chore|ci|docs|style|refactor|perf|test)[!]{0,1}: .+$"
|
||||
expected_pattern_message: "<Commit type>: <Commit Message>"
|
||||
sample_message: "chore: add Overcommit config"
|
||||
|
||||
TextWidth:
|
||||
enabled: true
|
||||
max_subject_width: 72
|
||||
8
.reviewdog.yml
Обычный файл
8
.reviewdog.yml
Обычный файл
@@ -0,0 +1,8 @@
|
||||
---
|
||||
runner:
|
||||
fasterer:
|
||||
cmd: bin/fasterer
|
||||
level: info
|
||||
rubocop:
|
||||
cmd: bin/rubocop
|
||||
level: info
|
||||
1
.rspec
1
.rspec
@@ -1,3 +1,2 @@
|
||||
--require rails_helper
|
||||
--format documentation
|
||||
--profile
|
||||
|
||||
73
.rubocop.yml
73
.rubocop.yml
@@ -1,27 +1,70 @@
|
||||
inherit_from:
|
||||
- https://relaxed.ruby.style/rubocop.yml
|
||||
---
|
||||
plugins:
|
||||
- rubocop-capybara
|
||||
- rubocop-packaging
|
||||
- rubocop-performance
|
||||
- rubocop-rails
|
||||
- rubocop-rspec
|
||||
- rubocop-rspec_rails
|
||||
|
||||
inherit_mode:
|
||||
merge:
|
||||
- Exclude
|
||||
|
||||
AllCops:
|
||||
NewCops: enable
|
||||
TargetRubyVersion: 3.2
|
||||
SuggestExtensions: false
|
||||
DisplayCopNames: true
|
||||
CacheRootDirectory: tmp/rubocop-cache
|
||||
Exclude:
|
||||
- bin/*
|
||||
- coverage/**/*
|
||||
- db/schema.rb
|
||||
- docs/**/*
|
||||
- examples/**/*
|
||||
- gemfiles/**/*
|
||||
- spec/dummy/**/*
|
||||
NewCops: enable
|
||||
|
||||
Gemspec/RequiredRubyVersion:
|
||||
Enabled: false
|
||||
|
||||
Naming/FileName:
|
||||
Enabled: false
|
||||
- vendor/**/*
|
||||
|
||||
Layout/LineLength:
|
||||
Enabled: true
|
||||
Max: 120
|
||||
|
||||
Style/HashEachMethods:
|
||||
Metrics/BlockLength:
|
||||
Enabled: true
|
||||
Exclude:
|
||||
- spec/**/*
|
||||
- docs/**/*
|
||||
|
||||
Metrics/MethodLength:
|
||||
Max: 20
|
||||
Exclude:
|
||||
- spec/**/*
|
||||
|
||||
Style/Documentation:
|
||||
Enabled: false
|
||||
|
||||
Style/StringLiterals:
|
||||
EnforcedStyle: single_quotes
|
||||
|
||||
Style/StringLiteralsInInterpolation:
|
||||
EnforcedStyle: double_quotes
|
||||
|
||||
RSpec/ExampleLength:
|
||||
Max: 12
|
||||
Exclude:
|
||||
- spec/system/**/*
|
||||
|
||||
RSpec/MultipleExpectations:
|
||||
Max: 4
|
||||
Exclude:
|
||||
- spec/system/**/*
|
||||
|
||||
RSpec/MultipleMemoizedHelpers:
|
||||
Max: 10
|
||||
|
||||
Rails/SkipsModelValidations:
|
||||
Enabled: true
|
||||
|
||||
Style/HashTransformKeys:
|
||||
Enabled: true
|
||||
|
||||
Style/HashTransformValues:
|
||||
Rails/ActiveRecordAliases:
|
||||
Enabled: true
|
||||
|
||||
19
AGENTS.md
Обычный файл
19
AGENTS.md
Обычный файл
@@ -0,0 +1,19 @@
|
||||
# Repository Guidelines
|
||||
|
||||
## Project Structure & Module Organization
|
||||
The gem code lives in `lib/activeadmin` and `lib/formtastic`, with the public entry point in `lib/activeadmin_quill_editor.rb`. Ruby assets and templates that Active Admin mounts ship from `app/assets` and `app/views`. Front-end bundles exposed to consuming apps sit in `index.js` and the `app/assets/javascripts/activeadmin/quill_editor` tree. System specs exercise the dummy Rails app under `spec/dummy`, while reusable page helpers reside in `spec/page_objects`.
|
||||
|
||||
## Build, Test, and Development Commands
|
||||
`make up` builds the Docker environment defined in `extra/docker-compose.yml` and prepares the dummy app; add `RUBY`, `RAILS`, or `ACTIVEADMIN` env vars to test matrix combinations. Run `make specs` (or directly `bin/rspec --fail-fast`) to execute the suite, and `make lint` to invoke `bin/rubocop` inside the container. Use `make shell` for interactive debugging and `make server` to boot the dummy Rails instance at `SERVER_PORT`.
|
||||
|
||||
## Coding Style & Naming Conventions
|
||||
Follow the `.rubocop.yml` rules: two-space indentation, trailing commas on multiline literals, double quotes where interpolation occurs, and `snake_case` for Ruby identifiers. Use `CamelCase` for classes and modules under the `ActiveadminQuillEditor` namespace, mirroring existing files. JavaScript additions in `app/assets/javascripts` should align with the lintable ES module style in `index.js`; run `npx eslint index.js` if you modify the package entry point.
|
||||
|
||||
## Testing Guidelines
|
||||
RSpec powers the suite; place feature-level coverage in `spec/system`, supporting components in `spec/page_objects`, and pure Ruby behaviour in `spec`. Prefer descriptive example names (`it "renders toolbar buttons"`) and keep factories in the dummy app to mirror real usage. Start tests with `make specs`; use `bin/rspec spec/system/editor_spec.rb` to target a file.
|
||||
|
||||
## Commit & Pull Request Guidelines
|
||||
Recent history follows conventional prefixes (`fix:`, `ci:`, `chore:`); keep messages in the imperative mood and limit the subject to 72 characters. Every pull request should link related GitHub issues, summarize user-facing changes, and note any docs or assets touched. Include screenshots or GIFs when altering the editor UI, and confirm that both `make specs` and `make lint` pass in the PR description. Request review from a maintainer and re-run the pipeline after rebases.
|
||||
|
||||
## Security & Configuration Tips
|
||||
Store local-only overrides in `extra/.env` (kept out of version control) and avoid committing credentials to the dummy app. The docker-compose services mount the repository directly, so prefer editing files via your host editor rather than inside the container to prevent permission drift.
|
||||
19
Appraisals
Обычный файл
19
Appraisals
Обычный файл
@@ -0,0 +1,19 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Rails 7.2 with ActiveAdmin 4.x beta
|
||||
appraise 'rails-7.2-active-admin-4.x' do
|
||||
gem 'rails', '~> 7.2.0'
|
||||
gem 'activeadmin', '4.0.0.beta20'
|
||||
gem 'sqlite3' # 7.2 can use newer sqlite3
|
||||
gem 'importmap-rails'
|
||||
gem 'propshaft'
|
||||
end
|
||||
|
||||
# Rails 8.0 with ActiveAdmin 4.x beta
|
||||
appraise 'rails-8.0-active-admin-4.x' do
|
||||
gem 'rails', '~> 8.0.0'
|
||||
gem 'activeadmin', '4.0.0.beta20'
|
||||
gem 'sqlite3' # Rails 8 needs latest sqlite3
|
||||
gem 'importmap-rails'
|
||||
gem 'propshaft'
|
||||
end
|
||||
72
CHANGELOG.md
Обычный файл
72
CHANGELOG.md
Обычный файл
@@ -0,0 +1,72 @@
|
||||
# Quill Editor for ActiveAdmin
|
||||
|
||||
An Active Admin plugin to use Quill Rich Text Editor.
|
||||
|
||||
## v2.0.0 - 2025-04-15
|
||||
|
||||
- Update Quill from 1.3.7 to 2.0.3
|
||||
|
||||
## v1.3.0 - 2025-03-18
|
||||
|
||||
- Javascript API: expose Quill editor query functions
|
||||
- ImageUploader: reject the Promise if an url is not provided in the response
|
||||
|
||||
## v1.2.0 - 2024-02-29
|
||||
|
||||
- Update minimum supported Ruby version to 3.0
|
||||
|
||||
## v1.1.0 - 2023-08-20
|
||||
|
||||
- Support ActiveAdmin 3.x
|
||||
- Minor tests config improvements
|
||||
|
||||
## v1.0.0 - 2022-04-18
|
||||
|
||||
- Set minimum Ruby version to 2.6.0
|
||||
- Remove `sassc` dependency
|
||||
- Enable Ruby 3.0 specs support
|
||||
- Enable Rails 7.0 specs support
|
||||
- Internal improvements
|
||||
|
||||
## v0.3.4 - 2021-03-16
|
||||
|
||||
- Fix editor loading with Turbolinks
|
||||
|
||||
## v0.3.2 - 2021-03-14
|
||||
|
||||
- Specs improvements
|
||||
- Minor internal changes
|
||||
|
||||
## v0.3.0 - 2020-10-01
|
||||
|
||||
- Add Webpacker support
|
||||
|
||||
## v0.2.14 - 2020-09-10
|
||||
|
||||
- JS: enable strict directive
|
||||
- Minor specs improvement
|
||||
|
||||
## v0.2.12 - 2020-09-08
|
||||
|
||||
- JS refactoring
|
||||
|
||||
## v0.2.10 - 2020-09-05
|
||||
|
||||
- Include Image Uploader plugin
|
||||
|
||||
## v0.2.9 - 2020-09-04
|
||||
|
||||
- Fix not working alignments (issue #8)
|
||||
- Fix empty editor problem which produces `<p><br></p>` (pull request #9)
|
||||
|
||||
## v0.2.8 - 2020-09-03
|
||||
|
||||
- Minor style improvements
|
||||
- Add specs for editor in nested resources
|
||||
- Add Rubocop and remove SimpleCov gems
|
||||
|
||||
## v0.2.4 - 2020-09-01
|
||||
|
||||
- Update Quill editor to version 1.3.7
|
||||
- Add minimum specs (using RSpec)
|
||||
- Minor internal changes
|
||||
89
Gemfile
89
Gemfile
@@ -2,4 +2,91 @@
|
||||
|
||||
source 'https://rubygems.org'
|
||||
|
||||
gemspec
|
||||
def eval_version(dependency, version)
|
||||
return [dependency] if version.empty?
|
||||
|
||||
# Handle versions that already have operators like ~>, >=, etc.
|
||||
if version.match?(/^[~<>=]/)
|
||||
[dependency, version]
|
||||
else
|
||||
# Add ~> operator and ensure version has at least 2 dots
|
||||
version.count('.') < 2 ? [dependency, "~> #{version}.0"] : [dependency, "~> #{version}"]
|
||||
end
|
||||
end
|
||||
|
||||
if ENV['DEVEL'] == '1'
|
||||
gem 'activeadmin_quill_editor', path: './'
|
||||
else
|
||||
gemspec
|
||||
end
|
||||
|
||||
ruby_ver = ENV.fetch('RUBY_VERSION', '')
|
||||
|
||||
rails_ver = ENV.fetch('RAILS_VERSION', '')
|
||||
rails = eval_version('rails', rails_ver)
|
||||
gem(*rails)
|
||||
|
||||
active_admin_ver = ENV.fetch('ACTIVEADMIN_VERSION', '')
|
||||
active_admin_requirement =
|
||||
if active_admin_ver.empty?
|
||||
'~> 4.0.0.beta16'
|
||||
elsif active_admin_ver.match?(/[a-zA-Z]/) || active_admin_ver.match?(/^[~<>=]/)
|
||||
active_admin_ver
|
||||
else
|
||||
target = Gem::Version.new(active_admin_ver)
|
||||
if target >= Gem::Version.new('4.0')
|
||||
'~> 4.0.0.beta16'
|
||||
else
|
||||
active_admin_ver.count('.') < 2 ? "~> #{active_admin_ver}.0" : "~> #{active_admin_ver}"
|
||||
end
|
||||
end
|
||||
|
||||
gem 'activeadmin', active_admin_requirement
|
||||
|
||||
ruby32 = ruby_ver.empty? || Gem::Version.new(ruby_ver) >= Gem::Version.new('3.2')
|
||||
rails72 = rails_ver.empty? || Gem::Version.new(rails_ver) >= Gem::Version.new('7.2')
|
||||
sqlite3 = ruby32 && rails72 ? ['sqlite3'] : ['sqlite3', '~> 1.4']
|
||||
gem(*sqlite3)
|
||||
|
||||
gem 'zeitwerk', '~> 2.6.18' unless ruby32
|
||||
|
||||
# NOTE: to avoid error: uninitialized constant ActiveSupport::LoggerThreadSafeLevel::Logger
|
||||
gem 'concurrent-ruby', '1.3.4'
|
||||
|
||||
# Misc
|
||||
gem 'bigdecimal'
|
||||
gem 'csv'
|
||||
gem 'mutex_m'
|
||||
gem 'puma'
|
||||
|
||||
# Asset pipeline - use Propshaft for Rails 8, Sprockets for older versions
|
||||
rails80 = rails_ver.empty? || Gem::Version.new(rails_ver) >= Gem::Version.new('8.0')
|
||||
if rails80
|
||||
gem 'importmap-rails' # Required for ActiveAdmin 4
|
||||
gem 'propshaft'
|
||||
else
|
||||
gem 'sassc'
|
||||
gem 'sprockets-rails'
|
||||
end
|
||||
|
||||
# Testing
|
||||
gem 'capybara'
|
||||
gem 'cuprite'
|
||||
gem 'rspec_junit_formatter'
|
||||
gem 'rspec-rails'
|
||||
gem 'simplecov', require: false
|
||||
gem 'super_diff'
|
||||
|
||||
# Linters
|
||||
gem 'fasterer'
|
||||
gem 'rubocop'
|
||||
gem 'rubocop-capybara'
|
||||
gem 'rubocop-packaging'
|
||||
gem 'rubocop-performance'
|
||||
gem 'rubocop-rails'
|
||||
gem 'rubocop-rspec'
|
||||
gem 'rubocop-rspec_rails'
|
||||
|
||||
# Tools
|
||||
gem 'appraisal'
|
||||
gem 'pry-rails'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2017-2020 Mattia Roccoberton
|
||||
Copyright (c) 2017-2022 Mattia Roccoberton
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
47
Makefile
Обычный файл
47
Makefile
Обычный файл
@@ -0,0 +1,47 @@
|
||||
include extra/.env
|
||||
|
||||
help:
|
||||
@echo -e "${COMPOSE_PROJECT_NAME} - Main project commands:\n\
|
||||
make up # starts the dev services (optional env vars: RUBY / RAILS / ACTIVEADMIN)\n\
|
||||
make specs # run the tests (after up)\n\
|
||||
make lint # run the linters (after up)\n\
|
||||
make server # run the server (after up)\n\
|
||||
make shell # open a shell (after up)\n\
|
||||
make down # cleanup (after up)\n\
|
||||
Example: RUBY=3.2 RAILS=7.1 ACTIVEADMIN=3.2.0 make up"
|
||||
|
||||
# System commands
|
||||
|
||||
build:
|
||||
@rm -f Gemfile.lock spec/dummy/db/*.sqlite3
|
||||
@docker compose -f extra/docker-compose.yml build
|
||||
|
||||
db_reset:
|
||||
@docker compose -f extra/docker-compose.yml run --rm app bin/rails db:create db:migrate db:test:prepare
|
||||
|
||||
up: build db_reset
|
||||
@docker compose -f extra/docker-compose.yml up
|
||||
|
||||
shell:
|
||||
@docker compose -f extra/docker-compose.yml exec app bash
|
||||
|
||||
down:
|
||||
@docker compose -f extra/docker-compose.yml down --volumes --rmi local --remove-orphans
|
||||
|
||||
# App commands
|
||||
|
||||
seed:
|
||||
@docker compose -f extra/docker-compose.yml exec app bin/rails db:seed
|
||||
|
||||
console: seed
|
||||
@docker compose -f extra/docker-compose.yml exec app bin/rails console
|
||||
|
||||
lint:
|
||||
@docker compose -f extra/docker-compose.yml exec app bin/rubocop
|
||||
|
||||
server: seed
|
||||
@rm -f spec/dummy/tmp/pids/server.pid
|
||||
@docker compose -f extra/docker-compose.yml exec app bin/rails server -b 0.0.0.0 -p ${SERVER_PORT}
|
||||
|
||||
specs:
|
||||
@docker compose -f extra/docker-compose.yml exec app bin/rspec --fail-fast
|
||||
93
README.md
93
README.md
@@ -1,11 +1,23 @@
|
||||
# ActiveAdmin Quill Editor [](https://badge.fury.io/rb/activeadmin_quill_editor) [](https://circleci.com/gh/blocknotes/activeadmin_quill_editor)
|
||||
# ActiveAdmin Quill Editor
|
||||
[](https://badge.fury.io/rb/activeadmin_quill_editor)
|
||||
[](https://rubygems.org/gems/activeadmin_quill_editor)
|
||||
[](https://github.com/blocknotes/activeadmin_quill_editor/actions/workflows/ci.yml)
|
||||
|
||||
An Active Admin plugin to use [Quill Rich Text Editor](https://github.com/quilljs/quill)
|
||||
An Active Admin plugin to use [Quill Rich Text Editor](https://github.com/quilljs/quill) in form fields.
|
||||
|
||||

|
||||

|
||||
|
||||
Please :star: if you like it.
|
||||
|
||||
## Install
|
||||
- After installing Active Admin, add to your Gemfile: `gem 'activeadmin_quill_editor'` (and execute *bundle*)
|
||||
|
||||
_NOTE_: the gem 2.x provide Quill 2.x, while Quill 1.x is provided with the gem version 1.x
|
||||
|
||||
After installing Active Admin, add to your Gemfile: `gem 'activeadmin_quill_editor'` (and execute *bundle*)
|
||||
|
||||
If you installed Active Admin without Webpacker support (default for now):
|
||||
|
||||
- Add a SASS/SCSS gem to your Gemfile (ex. `gem 'sassc'`)
|
||||
- Add at the end of your Active Admin styles (_app/assets/stylesheets/active_admin.scss_):
|
||||
```scss
|
||||
@import 'activeadmin/quill_editor/quill.snow';
|
||||
@@ -16,15 +28,26 @@ An Active Admin plugin to use [Quill Rich Text Editor](https://github.com/quillj
|
||||
//= require activeadmin/quill_editor/quill
|
||||
//= require activeadmin/quill_editor_input
|
||||
```
|
||||
- Use the input with `as: :quill_editor` in Active Admin model conf
|
||||
|
||||
Why 2 separated scripts? In this way you can include a different version of *quill editor* if you like.
|
||||
If you installed Active Admin with Webpacker support:
|
||||
|
||||
> **UPDATE FROM VERSION <= 2.0**: please add to your _app/assets/stylesheets/active_admin.scss_ the line `@import 'activeadmin/quill_editor/quill.snow';`
|
||||
- Execute in your project root:
|
||||
```sh
|
||||
yarn add blocknotes/activeadmin_quill_editor
|
||||
```
|
||||
- Add to your *app/javascript/packs/active_admin.js*:
|
||||
```js
|
||||
require('activeadmin_quill_editor')
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
In your Active Admin models, form configuration, set the text inputs with `as: :quill_editor` where needed.
|
||||
|
||||
## Options
|
||||
**data-options**: permits to set *quill editor* options directly - see [options list](https://quilljs.com/docs/configuration/)
|
||||
|
||||
If you are using Action Text (`has_rich_text`) on the same field of the Quill editor please take a look at [this workaround](https://github.com/blocknotes/activeadmin_quill_editor/issues/33#issuecomment-1965996947) to avoid issues.
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic usage
|
||||
@@ -44,20 +67,56 @@ Why 2 separated scripts? In this way you can include a different version of *qui
|
||||
### Toolbar buttons configuration
|
||||
|
||||
```ruby
|
||||
f.input :description, as: :quill_editor, input_html: {data: {options: {modules: {toolbar: [['bold', 'italic', 'underline'], ['link']]}, placeholder: 'Type something...', theme: 'snow'}}}
|
||||
f.input :description, as: :quill_editor, input_html: { data: { options: { modules: { toolbar: [['bold', 'italic', 'underline'], ['link']] }, placeholder: 'Type something...', theme: 'snow' } } }
|
||||
```
|
||||
|
||||
## Notes
|
||||
- Upload functions (Images, Documents, Files, etc.) are not implemented yet
|
||||
### ImageUploader plugin
|
||||
|
||||
This plugin allows to upload images to the server (instead of storing them in *base64* by default), reference [here](https://github.com/NoelOConnell/quill-image-uploader).
|
||||
|
||||
```ruby
|
||||
# Upload method (to be included in the admin entity configuration)
|
||||
member_action :upload, method: [:post] do
|
||||
result = { success: resource.images.attach(params[:file_upload]) }
|
||||
result[:url] = url_for(resource.images.last) if result[:success]
|
||||
render json: result
|
||||
end
|
||||
```
|
||||
|
||||
```ruby
|
||||
# Form field
|
||||
unless object.new_record?
|
||||
plugin_opts = { image_uploader: { server_url: upload_admin_post_path(object.id), field_name: 'file_upload' } }
|
||||
f.input :description, as: :quill_editor, input_html: { data: { plugins: plugin_opts } }
|
||||
end
|
||||
```
|
||||
|
||||
For the relevant files of the upload example see [here](examples/upload_plugin_using_activestorage/).
|
||||
Consider that this is just a basic example: images are uploaded as soon as they are attached to the
|
||||
editor (regardless of the form submit), it shows the editor only for an existing record (because of
|
||||
the *upload_admin_post_path*) and it doesn't provide a way to remove images (just deleting them from
|
||||
the editor will not destroy them, you'll need to implement a purge logic for that).
|
||||
|
||||
## Javascript API
|
||||
|
||||
Some methods are provided for advanced use cases:
|
||||
|
||||
- `window.getQuillEditors()`: returns all the available Quill editors instances;
|
||||
- `window.getQuillEditorByIndex(n)`: returns the N-th Quill editor instance;
|
||||
- `window.getQuillEditorByElementId(id)`: returns the Quill editor instance related to the specified element id (e.g. _article_description_).
|
||||
|
||||
## Development
|
||||
|
||||
Project created by [Mattia Roccoberton](http://blocknot.es), thanks also to the good guys that opened issues and pull requests from time to time.
|
||||
|
||||
For development information please check [this document](extra/development.md).
|
||||
|
||||
## Do you like it? Star it!
|
||||
If you use this component just star it. A developer is more motivated to improve a project when there is some interest.
|
||||
|
||||
Take a look at [other Active Admin components](https://github.com/blocknotes?utf8=✓&tab=repositories&q=activeadmin&type=source) that I made if you are curious.
|
||||
If you use this component just star it. A developer is more motivated to improve a project when there is some interest. My other [Active Admin components](https://github.com/blocknotes?utf8=✓&tab=repositories&q=activeadmin&type=source).
|
||||
|
||||
## Contributors
|
||||
- [Mattia Roccoberton](http://blocknot.es): author
|
||||
- The good guys that opened issues and pull requests from time to time
|
||||
Or consider offering me a coffee, it's a small thing but it is greatly appreciated: [about me](https://www.blocknot.es/about-me).
|
||||
|
||||
## License
|
||||
- The gem is available as open-source under the terms of the [MIT](LICENSE.txt)
|
||||
|
||||
The gem is available as open-source under the terms of the [MIT](LICENSE.txt).
|
||||
|
||||
16
Rakefile
16
Rakefile
@@ -1,11 +1,25 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
begin
|
||||
require 'bundler/setup'
|
||||
rescue LoadError
|
||||
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
||||
end
|
||||
|
||||
APP_RAKEFILE = File.expand_path('spec/dummy/Rakefile', __dir__)
|
||||
load 'rails/tasks/engine.rake'
|
||||
|
||||
load 'rails/tasks/statistics.rake'
|
||||
|
||||
require 'bundler/gem_tasks'
|
||||
|
||||
begin
|
||||
require 'rspec/core/rake_task'
|
||||
|
||||
RSpec::Core::RakeTask.new(:spec)
|
||||
RSpec::Core::RakeTask.new(:spec) do |t|
|
||||
# t.ruby_opts = %w[-w]
|
||||
t.rspec_opts = ['--color', '--format documentation']
|
||||
end
|
||||
|
||||
task default: :spec
|
||||
rescue LoadError
|
||||
|
||||
30
activeadmin-quill_editor.gemspec
Обычный файл
30
activeadmin-quill_editor.gemspec
Обычный файл
@@ -0,0 +1,30 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
lib = File.expand_path('lib', __dir__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
require 'activeadmin/quill_editor/version'
|
||||
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = 'activeadmin-quill_editor'
|
||||
spec.version = ActiveAdmin::QuillEditor::VERSION
|
||||
spec.summary = 'Quill Editor for ActiveAdmin'
|
||||
spec.description = 'An Active Admin plugin to use Quill Rich Text Editor'
|
||||
spec.license = 'MIT'
|
||||
spec.authors = ['Mattia Roccoberton']
|
||||
spec.email = 'mat@blocknot.es'
|
||||
spec.homepage = 'https://github.com/rs-pro/activeadmin-quill_editor'
|
||||
|
||||
spec.required_ruby_version = '>= 3.2'
|
||||
|
||||
spec.metadata['homepage_uri'] = spec.homepage
|
||||
spec.metadata['changelog_uri'] = 'https://github.com/rs-pro/activeadmin-quill_editor/blob/main/CHANGELOG.md'
|
||||
spec.metadata['source_code_uri'] = spec.homepage
|
||||
|
||||
spec.metadata['rubygems_mfa_required'] = 'true'
|
||||
|
||||
spec.files = Dir['{app,lib,vendor}/**/*', 'LICENSE.txt', 'Rakefile', 'README.md']
|
||||
spec.require_paths = ['lib']
|
||||
|
||||
spec.add_dependency 'activeadmin', '>= 4.0.0.beta', '< 5'
|
||||
spec.add_dependency 'rails', '>= 7.2'
|
||||
end
|
||||
@@ -1,31 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
lib = File.expand_path('lib', __dir__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
require 'activeadmin/quill_editor/version'
|
||||
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = 'activeadmin_quill_editor'
|
||||
spec.version = ActiveAdmin::QuillEditor::VERSION
|
||||
spec.summary = 'Quill Editor for ActiveAdmin'
|
||||
spec.description = 'An Active Admin plugin to use Quill Rich Text Editor'
|
||||
spec.license = 'MIT'
|
||||
spec.authors = ['Mattia Roccoberton']
|
||||
spec.email = 'mat@blocknot.es'
|
||||
spec.homepage = 'https://github.com/blocknotes/activeadmin_quill_editor'
|
||||
|
||||
spec.files = Dir['{app,lib}/**/*', 'LICENSE.txt', 'Rakefile', 'README.md']
|
||||
spec.require_paths = ['lib']
|
||||
|
||||
spec.add_runtime_dependency 'activeadmin', '~> 2.0'
|
||||
|
||||
spec.add_development_dependency 'activestorage', '~> 6.0.3.2'
|
||||
spec.add_development_dependency 'capybara', '~> 3.33.0'
|
||||
spec.add_development_dependency 'pry', '~> 0.13.1'
|
||||
spec.add_development_dependency 'puma', '~> 4.3.5'
|
||||
spec.add_development_dependency 'rspec_junit_formatter', '~> 0.4.1'
|
||||
spec.add_development_dependency 'rspec-rails', '~> 4.0.1'
|
||||
spec.add_development_dependency 'rubocop', '~> 0.90.0'
|
||||
spec.add_development_dependency 'selenium-webdriver', '~> 3.142.7'
|
||||
spec.add_development_dependency 'sqlite3', '~> 1.4.2'
|
||||
end
|
||||
362
app/assets/javascripts/activeadmin/quill.imageUploader.js
Обычный файл
362
app/assets/javascripts/activeadmin/quill.imageUploader.js
Обычный файл
@@ -0,0 +1,362 @@
|
||||
/******/ (function(modules) { // webpackBootstrap
|
||||
/******/ // The module cache
|
||||
/******/ var installedModules = {};
|
||||
/******/
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
/******/
|
||||
/******/ // Check if module is in cache
|
||||
/******/ if(installedModules[moduleId]) {
|
||||
/******/ return installedModules[moduleId].exports;
|
||||
/******/ }
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = installedModules[moduleId] = {
|
||||
/******/ i: moduleId,
|
||||
/******/ l: false,
|
||||
/******/ exports: {}
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Execute the module function
|
||||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||
/******/
|
||||
/******/ // Flag the module as loaded
|
||||
/******/ module.l = true;
|
||||
/******/
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
/******/
|
||||
/******/
|
||||
/******/ // expose the modules object (__webpack_modules__)
|
||||
/******/ __webpack_require__.m = modules;
|
||||
/******/
|
||||
/******/ // expose the module cache
|
||||
/******/ __webpack_require__.c = installedModules;
|
||||
/******/
|
||||
/******/ // define getter function for harmony exports
|
||||
/******/ __webpack_require__.d = function(exports, name, getter) {
|
||||
/******/ if(!__webpack_require__.o(exports, name)) {
|
||||
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // define __esModule on exports
|
||||
/******/ __webpack_require__.r = function(exports) {
|
||||
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
||||
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||||
/******/ }
|
||||
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // create a fake namespace object
|
||||
/******/ // mode & 1: value is a module id, require it
|
||||
/******/ // mode & 2: merge all properties of value into the ns
|
||||
/******/ // mode & 4: return value when already ns object
|
||||
/******/ // mode & 8|1: behave like require
|
||||
/******/ __webpack_require__.t = function(value, mode) {
|
||||
/******/ if(mode & 1) value = __webpack_require__(value);
|
||||
/******/ if(mode & 8) return value;
|
||||
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
|
||||
/******/ var ns = Object.create(null);
|
||||
/******/ __webpack_require__.r(ns);
|
||||
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
|
||||
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
|
||||
/******/ return ns;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||
/******/ __webpack_require__.n = function(module) {
|
||||
/******/ var getter = module && module.__esModule ?
|
||||
/******/ function getDefault() { return module['default']; } :
|
||||
/******/ function getModuleExports() { return module; };
|
||||
/******/ __webpack_require__.d(getter, 'a', getter);
|
||||
/******/ return getter;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Object.prototype.hasOwnProperty.call
|
||||
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
||||
/******/
|
||||
/******/ // __webpack_public_path__
|
||||
/******/ __webpack_require__.p = "";
|
||||
/******/
|
||||
/******/
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ return __webpack_require__(__webpack_require__.s = 0);
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ([
|
||||
/* 0 */
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony import */ var _blots_image_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
|
||||
/* harmony import */ var _quill_imageUploader_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
|
||||
/* harmony import */ var _quill_imageUploader_css__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_quill_imageUploader_css__WEBPACK_IMPORTED_MODULE_1__);
|
||||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
|
||||
|
||||
|
||||
|
||||
var ImageUploader = function () {
|
||||
function ImageUploader(quill, options) {
|
||||
_classCallCheck(this, ImageUploader);
|
||||
|
||||
this.quill = quill;
|
||||
this.options = options;
|
||||
this.range = null;
|
||||
|
||||
if (typeof this.options.upload !== "function") {
|
||||
console.warn("[Missing config] upload function that returns a promise is required");
|
||||
}
|
||||
|
||||
if (this.options.loadingClass) {
|
||||
_blots_image_js__WEBPACK_IMPORTED_MODULE_0__["default"].className = this.options.loadingClass;
|
||||
}
|
||||
|
||||
var toolbar = this.quill.getModule("toolbar");
|
||||
toolbar.addHandler("image", this.selectLocalImage.bind(this));
|
||||
|
||||
this.handleDrop = this.handleDrop.bind(this);
|
||||
this.handlePaste = this.handlePaste.bind(this);
|
||||
|
||||
this.quill.root.addEventListener("drop", this.handleDrop, false);
|
||||
this.quill.root.addEventListener("paste", this.handlePaste, false);
|
||||
}
|
||||
|
||||
_createClass(ImageUploader, [{
|
||||
key: "selectLocalImage",
|
||||
value: function selectLocalImage() {
|
||||
var _this = this;
|
||||
|
||||
this.range = this.quill.getSelection();
|
||||
this.fileHolder = document.createElement("input");
|
||||
this.fileHolder.setAttribute("type", "file");
|
||||
this.fileHolder.setAttribute("accept", "image/*");
|
||||
this.fileHolder.setAttribute("style", "visibility:hidden");
|
||||
|
||||
this.fileHolder.onchange = this.fileChanged.bind(this);
|
||||
|
||||
document.body.appendChild(this.fileHolder);
|
||||
|
||||
this.fileHolder.click();
|
||||
|
||||
window.requestAnimationFrame(function () {
|
||||
document.body.removeChild(_this.fileHolder);
|
||||
});
|
||||
}
|
||||
}, {
|
||||
key: "handleDrop",
|
||||
value: function handleDrop(evt) {
|
||||
var _this2 = this;
|
||||
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
if (evt.dataTransfer && evt.dataTransfer.files && evt.dataTransfer.files.length) {
|
||||
if (document.caretRangeFromPoint) {
|
||||
var selection = document.getSelection();
|
||||
var range = document.caretRangeFromPoint(evt.clientX, evt.clientY);
|
||||
if (selection && range) {
|
||||
selection.setBaseAndExtent(range.startContainer, range.startOffset, range.startContainer, range.startOffset);
|
||||
}
|
||||
} else {
|
||||
var _selection = document.getSelection();
|
||||
var _range = document.caretPositionFromPoint(evt.clientX, evt.clientY);
|
||||
if (_selection && _range) {
|
||||
_selection.setBaseAndExtent(_range.offsetNode, _range.offset, _range.offsetNode, _range.offset);
|
||||
}
|
||||
}
|
||||
|
||||
this.range = this.quill.getSelection();
|
||||
var file = evt.dataTransfer.files[0];
|
||||
|
||||
setTimeout(function () {
|
||||
_this2.range = _this2.quill.getSelection();
|
||||
_this2.readAndUploadFile(file);
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: "handlePaste",
|
||||
value: function handlePaste(evt) {
|
||||
var _this3 = this;
|
||||
|
||||
var clipboard = evt.clipboardData || window.clipboardData;
|
||||
|
||||
// IE 11 is .files other browsers are .items
|
||||
if (clipboard && (clipboard.items || clipboard.files)) {
|
||||
var items = clipboard.items || clipboard.files;
|
||||
var IMAGE_MIME_REGEX = /^image\/(jpe?g|gif|png|svg|webp)$/i;
|
||||
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
if (IMAGE_MIME_REGEX.test(items[i].type)) {
|
||||
(function () {
|
||||
var file = items[i].getAsFile ? items[i].getAsFile() : items[i];
|
||||
|
||||
if (file) {
|
||||
_this3.range = _this3.quill.getSelection();
|
||||
evt.preventDefault();
|
||||
setTimeout(function () {
|
||||
_this3.range = _this3.quill.getSelection();
|
||||
_this3.readAndUploadFile(file);
|
||||
}, 0);
|
||||
}
|
||||
})();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: "readAndUploadFile",
|
||||
value: function readAndUploadFile(file) {
|
||||
var _this4 = this;
|
||||
|
||||
var isUploadReject = false;
|
||||
|
||||
var fileReader = new FileReader();
|
||||
|
||||
fileReader.addEventListener("load", function () {
|
||||
if (!isUploadReject) {
|
||||
var base64ImageSrc = fileReader.result;
|
||||
_this4.insertBase64Image(base64ImageSrc);
|
||||
}
|
||||
}, false);
|
||||
|
||||
if (file) {
|
||||
fileReader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
this.options.upload(file).then(function (imageUrl) {
|
||||
_this4.insertToEditor(imageUrl);
|
||||
}, function (error) {
|
||||
isUploadReject = true;
|
||||
_this4.removeBase64Image();
|
||||
console.warn(error);
|
||||
});
|
||||
}
|
||||
}, {
|
||||
key: "fileChanged",
|
||||
value: function fileChanged() {
|
||||
var file = this.fileHolder.files[0];
|
||||
this.readAndUploadFile(file);
|
||||
}
|
||||
}, {
|
||||
key: "insertBase64Image",
|
||||
value: function insertBase64Image(url) {
|
||||
var range = this.range;
|
||||
|
||||
this.quill.insertEmbed(range.index, _blots_image_js__WEBPACK_IMPORTED_MODULE_0__["default"].blotName, "" + url, "user");
|
||||
}
|
||||
}, {
|
||||
key: "insertToEditor",
|
||||
value: function insertToEditor(url) {
|
||||
var range = this.range;
|
||||
// Delete the placeholder image
|
||||
|
||||
this.quill.deleteText(range.index, 3, "user");
|
||||
// Insert the server saved image
|
||||
this.quill.insertEmbed(range.index, "image", "" + url, "user");
|
||||
|
||||
range.index++;
|
||||
this.quill.setSelection(range, "user");
|
||||
}
|
||||
}, {
|
||||
key: "removeBase64Image",
|
||||
value: function removeBase64Image() {
|
||||
var range = this.range;
|
||||
|
||||
this.quill.deleteText(range.index, 3, "user");
|
||||
}
|
||||
}]);
|
||||
|
||||
return ImageUploader;
|
||||
}();
|
||||
|
||||
window.ImageUploader = ImageUploader;
|
||||
/* harmony default export */ __webpack_exports__["default"] = (ImageUploader);
|
||||
|
||||
/***/ }),
|
||||
/* 1 */
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony import */ var quill__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
|
||||
/* harmony import */ var quill__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(quill__WEBPACK_IMPORTED_MODULE_0__);
|
||||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
||||
|
||||
var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
|
||||
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
||||
|
||||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
||||
|
||||
|
||||
|
||||
var InlineBlot = quill__WEBPACK_IMPORTED_MODULE_0___default.a.import('blots/block');
|
||||
|
||||
var LoadingImage = function (_InlineBlot) {
|
||||
_inherits(LoadingImage, _InlineBlot);
|
||||
|
||||
function LoadingImage() {
|
||||
_classCallCheck(this, LoadingImage);
|
||||
|
||||
return _possibleConstructorReturn(this, (LoadingImage.__proto__ || Object.getPrototypeOf(LoadingImage)).apply(this, arguments));
|
||||
}
|
||||
|
||||
_createClass(LoadingImage, [{
|
||||
key: 'deleteAt',
|
||||
value: function deleteAt(index, length) {
|
||||
_get(LoadingImage.prototype.__proto__ || Object.getPrototypeOf(LoadingImage.prototype), 'deleteAt', this).call(this, index, length);
|
||||
this.cache = {};
|
||||
}
|
||||
}], [{
|
||||
key: 'create',
|
||||
value: function create(src) {
|
||||
var node = _get(LoadingImage.__proto__ || Object.getPrototypeOf(LoadingImage), 'create', this).call(this, src);
|
||||
if (src === true) return node;
|
||||
|
||||
var image = document.createElement('img');
|
||||
image.setAttribute('src', src);
|
||||
node.appendChild(image);
|
||||
return node;
|
||||
}
|
||||
}, {
|
||||
key: 'value',
|
||||
value: function value(domNode) {
|
||||
var _domNode$dataset = domNode.dataset,
|
||||
src = _domNode$dataset.src,
|
||||
custom = _domNode$dataset.custom;
|
||||
|
||||
return { src: src, custom: custom };
|
||||
}
|
||||
}]);
|
||||
|
||||
return LoadingImage;
|
||||
}(InlineBlot);
|
||||
|
||||
LoadingImage.blotName = 'imageBlot';
|
||||
LoadingImage.className = 'quill-image-uploading';
|
||||
LoadingImage.tagName = 'span';
|
||||
quill__WEBPACK_IMPORTED_MODULE_0___default.a.register({ 'formats/imageBlot': LoadingImage });
|
||||
|
||||
/* harmony default export */ __webpack_exports__["default"] = (LoadingImage);
|
||||
|
||||
/***/ }),
|
||||
/* 2 */
|
||||
/***/ (function(module, exports) {
|
||||
|
||||
module.exports = Quill;
|
||||
|
||||
/***/ }),
|
||||
/* 3 */
|
||||
/***/ (function(module, exports) {
|
||||
|
||||
// removed by extract-text-webpack-plugin
|
||||
|
||||
/***/ })
|
||||
/******/ ]);
|
||||
1
app/assets/javascripts/activeadmin/quill.imageUploader.min.js
поставляемый
Обычный файл
1
app/assets/javascripts/activeadmin/quill.imageUploader.min.js
поставляемый
Обычный файл
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
8
app/assets/javascripts/activeadmin/quill_editor/quill.min.js
поставляемый
8
app/assets/javascripts/activeadmin/quill_editor/quill.min.js
поставляемый
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
@@ -1,45 +0,0 @@
|
||||
function initQuillEditors() {
|
||||
var editors = document.querySelectorAll('.quill-editor');
|
||||
var default_options = {
|
||||
modules: {
|
||||
toolbar: [
|
||||
['bold', 'italic', 'underline'],
|
||||
['link', 'blockquote', 'code-block'],
|
||||
[{ 'script': 'sub'}, { 'script': 'super' }],
|
||||
[{ 'align': [] }, { list: 'ordered' }, { list: 'bullet' }],
|
||||
[{ 'color': [] }, { 'background': [] }],
|
||||
['clean'],
|
||||
]
|
||||
},
|
||||
placeholder: '',
|
||||
theme: 'snow'
|
||||
};
|
||||
|
||||
for(var i = 0; i < editors.length; i++) {
|
||||
var content = editors[i].querySelector('.quill-editor-content');
|
||||
var isActive = editors[i].classList.contains('quill-editor--active');
|
||||
if(content && !isActive) {
|
||||
var options = editors[i].getAttribute('data-options') ? JSON.parse(editors[i].getAttribute('data-options')) : default_options;
|
||||
editors[i]['_quill-editor'] = new Quill(content, options);
|
||||
editors[i].classList += ' quill-editor--active';
|
||||
}
|
||||
}
|
||||
|
||||
var formtastic = document.querySelector('form.formtastic');
|
||||
if(formtastic) {
|
||||
formtastic.onsubmit = function() {
|
||||
for(var i = 0; i < editors.length; i++) {
|
||||
var input = editors[i].querySelector('input[type="hidden"]');
|
||||
input.value = editors[i]['_quill-editor'].root.innerHTML;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready( function() {
|
||||
initQuillEditors();
|
||||
});
|
||||
|
||||
$(document).on('has_many_add:after', function() {
|
||||
initQuillEditors();
|
||||
});
|
||||
@@ -1,4 +1,11 @@
|
||||
body.active_admin .quill-editor {
|
||||
// reset internal elements
|
||||
.ql-editor * {
|
||||
margin: initial;
|
||||
padding: initial;
|
||||
text-align: initial;
|
||||
}
|
||||
|
||||
body.active_admin [data-aa-quill-editor] {
|
||||
display: inline-block;
|
||||
width: calc(80% - 2px);
|
||||
|
||||
@@ -22,13 +29,7 @@ body.active_admin .quill-editor {
|
||||
max-height: 300px;
|
||||
min-height: 150px;
|
||||
padding: 10px;
|
||||
|
||||
// reset internal elements
|
||||
* {
|
||||
margin: initial;
|
||||
padding: initial;
|
||||
text-align: initial;
|
||||
}
|
||||
word-break: break-all;
|
||||
|
||||
ol {
|
||||
list-style-type: decimal;
|
||||
|
||||
33
app/assets/stylesheets/activeadmin/quill.imageUploader.min.css
поставляемый
Обычный файл
33
app/assets/stylesheets/activeadmin/quill.imageUploader.min.css
поставляемый
Обычный файл
@@ -0,0 +1,33 @@
|
||||
.quill-image-uploading {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.quill-image-uploading img {
|
||||
max-width: 98% !important;
|
||||
filter: blur(5px);
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.quill-image-uploading::before {
|
||||
content: "";
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin-top: -15px;
|
||||
margin-left: -15px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid #ccc;
|
||||
border-top-color: #1e40af;
|
||||
z-index: 1;
|
||||
animation: spinner 0.6s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spinner {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
29
bin/fasterer
Исполняемый файл
29
bin/fasterer
Исполняемый файл
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# This file was generated by Bundler.
|
||||
#
|
||||
# The application 'fasterer' is installed as part of a gem, and
|
||||
# this file is here to facilitate running it.
|
||||
#
|
||||
|
||||
require "pathname"
|
||||
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
||||
Pathname.new(__FILE__).realpath)
|
||||
|
||||
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
||||
|
||||
if File.file?(bundle_binstub)
|
||||
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
||||
load(bundle_binstub)
|
||||
else
|
||||
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
||||
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
||||
end
|
||||
end
|
||||
|
||||
require "rubygems"
|
||||
require "bundler/setup"
|
||||
|
||||
load Gem.bin_path("fasterer", "fasterer")
|
||||
35
bin/rails
35
bin/rails
@@ -1,29 +1,16 @@
|
||||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
# This command will automatically be run when you run "rails" with Rails gems
|
||||
# installed from the root of your application.
|
||||
|
||||
#
|
||||
# This file was generated by Bundler.
|
||||
#
|
||||
# The application 'rails' is installed as part of a gem, and
|
||||
# this file is here to facilitate running it.
|
||||
#
|
||||
ENV['RAILS_ENV'] ||= 'development'
|
||||
|
||||
require "pathname"
|
||||
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
||||
Pathname.new(__FILE__).realpath)
|
||||
ENGINE_ROOT = File.expand_path('..', __dir__)
|
||||
ENGINE_PATH = File.expand_path('../lib/activeadmin/quill_editor/engine', __dir__)
|
||||
APP_PATH = File.expand_path('../spec/dummy/config/application', __dir__)
|
||||
|
||||
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
||||
# Set up gems listed in the Gemfile.
|
||||
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
|
||||
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
|
||||
|
||||
if File.file?(bundle_binstub)
|
||||
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
||||
load(bundle_binstub)
|
||||
else
|
||||
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
||||
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
||||
end
|
||||
end
|
||||
|
||||
require "rubygems"
|
||||
require "bundler/setup"
|
||||
|
||||
load Gem.bin_path("railties", "rails")
|
||||
require 'rails/all'
|
||||
require 'rails/engine/commands'
|
||||
|
||||
169
docs/activeadmin-4-asset-setup.md
Обычный файл
169
docs/activeadmin-4-asset-setup.md
Обычный файл
@@ -0,0 +1,169 @@
|
||||
# ActiveAdmin 4 Asset Setup (Tailwind CSS v4)
|
||||
|
||||
## Overview
|
||||
This guide documents the current, working setup for ActiveAdmin 4.0.0.beta20 with Tailwind CSS v4 and Quill Editor.
|
||||
|
||||
## Requirements
|
||||
- ActiveAdmin 4.0.0.beta20
|
||||
- Tailwind CSS v4 via `tailwindcss-rails` (ships `bin/tailwindcss`)
|
||||
- ESBuild (or other JS bundler) for ActiveAdmin JS + Quill Editor
|
||||
|
||||
## 1. Gemfile
|
||||
|
||||
```ruby
|
||||
# ActiveAdmin 4 beta
|
||||
gem "activeadmin", "4.0.0.beta20"
|
||||
|
||||
gem "activeadmin_quill_editor"
|
||||
|
||||
# Tailwind CSS v4 (bundled CLI)
|
||||
gem "tailwindcss-rails", "~> 4.4.0"
|
||||
```
|
||||
|
||||
## 2. package.json
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"@activeadmin/activeadmin": "^4.0.0-beta20",
|
||||
"quill": "^2.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.27.2"
|
||||
},
|
||||
"scripts": {
|
||||
"build:js": "node esbuild-active_admin.config.js",
|
||||
"build:css": "bundle exec rake active_admin:build",
|
||||
"build": "npm run build:js && npm run build:css",
|
||||
"watch:js": "node esbuild-active_admin.config.js --watch",
|
||||
"watch:css": "bundle exec rake active_admin:watch",
|
||||
"dev": "npm run watch:js & npm run watch:css"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 3. JavaScript Entry (app/javascript/active_admin.js)
|
||||
|
||||
```javascript
|
||||
import "@activeadmin/activeadmin";
|
||||
|
||||
import Quill from "quill";
|
||||
window.Quill = Quill;
|
||||
|
||||
import "activeadmin_quill_editor";
|
||||
```
|
||||
|
||||
## 4. Tailwind Input (app/assets/stylesheets/active_admin.tailwind.css)
|
||||
|
||||
```css
|
||||
@import "tailwindcss";
|
||||
@config "../../../tailwind-active_admin.config.mjs";
|
||||
|
||||
@import "activeadmin/quill_editor/quill.snow";
|
||||
@import "activeadmin/quill_editor_input";
|
||||
```
|
||||
|
||||
## 5. Tailwind Config (tailwind-active_admin.config.mjs)
|
||||
|
||||
```javascript
|
||||
import { execSync } from "child_process";
|
||||
import activeAdminPlugin from "@activeadmin/activeadmin/plugin";
|
||||
|
||||
const activeAdminPath = execSync("bundle show activeadmin", {
|
||||
encoding: "utf-8"
|
||||
}).trim();
|
||||
|
||||
export default {
|
||||
content: [
|
||||
`${activeAdminPath}/vendor/javascript/flowbite.js`,
|
||||
`${activeAdminPath}/plugin.js`,
|
||||
`${activeAdminPath}/app/views/**/*.{arb,erb,html,rb}`,
|
||||
"./app/admin/**/*.{arb,erb,html,rb}`,
|
||||
"./app/views/active_admin/**/*.{arb,erb,html,rb}`,
|
||||
"./app/views/admin/**/*.{arb,erb,html,rb}`,
|
||||
"./app/views/layouts/active_admin*.{erb,html}`,
|
||||
"./app/javascript/**/*.js"
|
||||
],
|
||||
darkMode: "selector",
|
||||
plugins: [activeAdminPlugin]
|
||||
};
|
||||
```
|
||||
|
||||
## 6. Tailwind Build Tasks (lib/tasks/active_admin.rake)
|
||||
|
||||
```ruby
|
||||
namespace :active_admin do
|
||||
desc "Build Active Admin Tailwind stylesheets"
|
||||
task build: :environment do
|
||||
command = [
|
||||
Rails.root.join("bin/tailwindcss").to_s,
|
||||
"-i", Rails.root.join("app/assets/stylesheets/active_admin.tailwind.css").to_s,
|
||||
"-o", Rails.root.join("app/assets/builds/active_admin.css").to_s,
|
||||
"-m"
|
||||
]
|
||||
|
||||
system(*command, exception: true)
|
||||
end
|
||||
|
||||
desc "Watch Active Admin Tailwind stylesheets"
|
||||
task watch: :environment do
|
||||
command = [
|
||||
Rails.root.join("bin/tailwindcss").to_s,
|
||||
"--watch",
|
||||
"-i", Rails.root.join("app/assets/stylesheets/active_admin.tailwind.css").to_s,
|
||||
"-o", Rails.root.join("app/assets/builds/active_admin.css").to_s,
|
||||
"-m"
|
||||
]
|
||||
|
||||
system(*command, exception: true)
|
||||
end
|
||||
end
|
||||
|
||||
Rake::Task["assets:precompile"].enhance(["active_admin:build"])
|
||||
Rake::Task["test:prepare"].enhance(["active_admin:build"]) if Rake::Task.task_defined?("test:prepare")
|
||||
Rake::Task["spec:prepare"].enhance(["active_admin:build"]) if Rake::Task.task_defined?("spec:prepare")
|
||||
Rake::Task["db:test:prepare"].enhance(["active_admin:build"]) if Rake::Task.task_defined?("db:test:prepare")
|
||||
```
|
||||
|
||||
## 7. Tailwind CLI Binstub
|
||||
|
||||
```bash
|
||||
bundle binstubs tailwindcss-ruby --force
|
||||
```
|
||||
|
||||
## 8. Upgrade Notes (ActiveAdmin 4.0.0.beta20)
|
||||
|
||||
From ActiveAdmin's upgrade guide:
|
||||
- `_site_header.html.erb` container class changed from `sticky` to `fixed`.
|
||||
- `active_admin.html.erb` adds the `pt-16` utility class.
|
||||
- Tailwind v4 uses `@import "tailwindcss"` and `@config` (no `@tailwind` directives).
|
||||
- The Tailwind config file is ESM. Use `tailwind-active_admin.config.mjs`.
|
||||
- jQuery/jQuery UI removed; `columns` and `tabs` components removed.
|
||||
- Replace `default_main_content` with `render "show_default"`.
|
||||
- Replace `as: :datepicker` with `as: :date_picker`.
|
||||
- Replace `active_admin_comments` with `active_admin_comments_for(resource)`.
|
||||
- Replace `attributes_table` with `attributes_table_for(resource)` in sidebars.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### CSS not building
|
||||
- Ensure `tailwindcss-rails` is pinned to `~> 4.4.0`.
|
||||
- Run `bundle binstubs tailwindcss-ruby --force`.
|
||||
- Confirm `bin/tailwindcss` exists.
|
||||
|
||||
### ActiveAdmin styles not loading
|
||||
- Verify `app/assets/builds/active_admin.css` exists.
|
||||
- Check that `active_admin.tailwind.css` imports Quill Editor styles.
|
||||
|
||||
### Quill Editor not initializing
|
||||
- Verify `window.Quill` in the console.
|
||||
- Ensure `activeadmin_quill_editor` is imported.
|
||||
|
||||
## Migration Checklist
|
||||
|
||||
- [ ] Update ActiveAdmin to 4.0.0.beta20
|
||||
- [ ] Use Tailwind v4 `@import` + `@config`
|
||||
- [ ] Add `tailwindcss-rails` (~> 4.4.0) and binstub
|
||||
- [ ] Create `tailwind-active_admin.config.mjs` (ESM)
|
||||
- [ ] Update rake tasks to use `bin/tailwindcss` (no `-c`)
|
||||
- [ ] Rebuild assets and verify UI
|
||||
371
docs/activeadmin-4-changelog.md
Обычный файл
371
docs/activeadmin-4-changelog.md
Обычный файл
@@ -0,0 +1,371 @@
|
||||
# ActiveAdmin v4.0.0 Beta Changelog
|
||||
|
||||
This document contains all the changes from ActiveAdmin v4.0.0 beta releases.
|
||||
|
||||
**Source**: [https://github.com/activeadmin/activeadmin/releases](https://github.com/activeadmin/activeadmin/releases)
|
||||
|
||||
---
|
||||
|
||||
## v4.0.0.beta20 (2025-01-27)
|
||||
|
||||
### Breaking Changes 🚨
|
||||
- Drop support for Rails 7.0 and 7.1 [#8908](https://github.com/activeadmin/activeadmin/pull/8908)
|
||||
|
||||
### Template Updates 📝
|
||||
- Link to parent menu item [#8225](https://github.com/activeadmin/activeadmin/pull/8225)
|
||||
|
||||
### Enhancements ✨
|
||||
- resource: allow resource_class to be passed as a String [#8848](https://github.com/activeadmin/activeadmin/pull/8848)
|
||||
- Remove horizontal padding on comments pagination [#8925](https://github.com/activeadmin/activeadmin/pull/8925)
|
||||
- Add page anchor to comments form view [#8926](https://github.com/activeadmin/activeadmin/pull/8926)
|
||||
- Fix vertical spacing on has-many forms [#8927](https://github.com/activeadmin/activeadmin/pull/8927)
|
||||
- Remove no-wrap from table columns [#8928](https://github.com/activeadmin/activeadmin/pull/8928)
|
||||
|
||||
### Bug Fixes 🐛
|
||||
- Restore pointer cursor on eligible buttons [#8878](https://github.com/activeadmin/activeadmin/pull/8878)
|
||||
- Ignore extra bundler output when DEBUG is set [#8895](https://github.com/activeadmin/activeadmin/pull/8895)
|
||||
|
||||
### Other Changes 🛠
|
||||
- Test supported Rails versions against Ruby 4.0 [#8898](https://github.com/activeadmin/activeadmin/pull/8898)
|
||||
|
||||
**Full Changelog**: [v4.0.0.beta19...v4.0.0.beta20](https://github.com/activeadmin/activeadmin/compare/v4.0.0.beta19...v4.0.0.beta20)
|
||||
|
||||
---
|
||||
|
||||
## v4.0.0.beta19 (2024-11-20)
|
||||
|
||||
### Breaking Changes 🚨
|
||||
- Bump tailwind from 3.4.18 to 4.1.17 [#8709](https://github.com/activeadmin/activeadmin/pull/8709)
|
||||
|
||||
### Template Updates 📝
|
||||
- Bump tailwind from 3.4.18 to 4.1.17 [#8709](https://github.com/activeadmin/activeadmin/pull/8709)
|
||||
|
||||
### Bug Fixes 🐛
|
||||
- Remove self-reference to ActiveAdmin node package [#8847](https://github.com/activeadmin/activeadmin/pull/8847)
|
||||
|
||||
**Full Changelog**: [v4.0.0.beta18...v4.0.0.beta19](https://github.com/activeadmin/activeadmin/compare/v4.0.0.beta18...v4.0.0.beta19)
|
||||
|
||||
---
|
||||
|
||||
## v4.0.0.beta18 (2024-11-01)
|
||||
|
||||
### Enhancements ✨
|
||||
- Add Rails 8.1.0 compatibility [#8837](https://github.com/activeadmin/activeadmin/pull/8837)
|
||||
|
||||
**Full Changelog**: [v4.0.0.beta17...v4.0.0.beta18](https://github.com/activeadmin/activeadmin/compare/v4.0.0.beta17...v4.0.0.beta18)
|
||||
|
||||
---
|
||||
|
||||
## v4.0.0.beta17 (2024-10-21)
|
||||
|
||||
### Breaking Changes 🚨
|
||||
- Preserve custom string labels in AttributesTable headers [#8815](https://github.com/activeadmin/activeadmin/pull/8815)
|
||||
|
||||
### Enhancements ✨
|
||||
- Update French locales [#8770](https://github.com/activeadmin/activeadmin/pull/8770)
|
||||
- Improve text color contrast [#8535](https://github.com/activeadmin/activeadmin/pull/8535)
|
||||
- Remove unnecessary base CSS styles [#8803](https://github.com/activeadmin/activeadmin/pull/8803)
|
||||
- Update dark mode CSS styles [#8809](https://github.com/activeadmin/activeadmin/pull/8809)
|
||||
|
||||
**Full Changelog**: [v4.0.0.beta16...v4.0.0.beta17](https://github.com/activeadmin/activeadmin/compare/v4.0.0.beta16...v4.0.0.beta17)
|
||||
|
||||
---
|
||||
|
||||
## v4.0.0.beta16 (2024-07-23)
|
||||
|
||||
### Breaking Changes 🚨
|
||||
- Drop Ruby 3.1 and update dependencies [#8760](https://github.com/activeadmin/activeadmin/pull/8760)
|
||||
- Remove Tabs component [#8762](https://github.com/activeadmin/activeadmin/pull/8762)
|
||||
|
||||
### Template Updates 📝
|
||||
- Remove `frozen_string_literal` comment from `.arb` templates [#8600](https://github.com/activeadmin/activeadmin/pull/8600)
|
||||
|
||||
### Enhancements ✨
|
||||
- Bump Formtastic to 5.0 and remove legacy code [#8613](https://github.com/activeadmin/activeadmin/pull/8613)
|
||||
- Add Polish pagination entries translations [#8636](https://github.com/activeadmin/activeadmin/pull/8636)
|
||||
- Support sortable argument in id_column [#8639](https://github.com/activeadmin/activeadmin/pull/8639)
|
||||
- Support title for id_column [#8641](https://github.com/activeadmin/activeadmin/pull/8641)
|
||||
- Update pt-BR translations [#8679](https://github.com/activeadmin/activeadmin/pull/8679)
|
||||
- Upgrade Flowbite dependency to v3.1.2 [#8692](https://github.com/activeadmin/activeadmin/pull/8692)
|
||||
- Add some :uk locales [#8732](https://github.com/activeadmin/activeadmin/pull/8732)
|
||||
|
||||
### Bug Fixes 🐛
|
||||
- Fix deprecation warning in Ruby 3.4 [#8593](https://github.com/activeadmin/activeadmin/pull/8593)
|
||||
- Fix circular require warning in `belongs_to.rb` [#8599](https://github.com/activeadmin/activeadmin/pull/8599)
|
||||
- Fix pagination truncate translation key [#8678](https://github.com/activeadmin/activeadmin/pull/8678)
|
||||
- Fix typo in batch_actions locale translation key [#8712](https://github.com/activeadmin/activeadmin/pull/8712)
|
||||
- Enhance main navbar to improve bouncing on macOS [#8727](https://github.com/activeadmin/activeadmin/pull/8727)
|
||||
- Remove double bottom border on last table row [#8761](https://github.com/activeadmin/activeadmin/pull/8761)
|
||||
|
||||
### Other Changes 🛠
|
||||
- Normalize i18n locale files [#8715](https://github.com/activeadmin/activeadmin/pull/8715)
|
||||
|
||||
**Full Changelog**: [v4.0.0.beta15...v4.0.0.beta16](https://github.com/activeadmin/activeadmin/compare/v4.0.0.beta15...v4.0.0.beta16)
|
||||
|
||||
---
|
||||
|
||||
## v4.0.0.beta15 (2024-12-07)
|
||||
|
||||
### Template Updates 📝
|
||||
- Use ESM in tailwind config template [#8568](https://github.com/activeadmin/activeadmin/pull/8568)
|
||||
|
||||
### Enhancements ✨
|
||||
- Update Korean locale with new translations [#8554](https://github.com/activeadmin/activeadmin/pull/8554)
|
||||
- Update Arabic locale translations [#8555](https://github.com/activeadmin/activeadmin/pull/8555)
|
||||
- Fix an issue with Arabic translation [#8557](https://github.com/activeadmin/activeadmin/pull/8557)
|
||||
- Update Russian locale with new translations [#8558](https://github.com/activeadmin/activeadmin/pull/8558)
|
||||
|
||||
**Full Changelog**: [v4.0.0.beta14...v4.0.0.beta15](https://github.com/activeadmin/activeadmin/compare/v4.0.0.beta14...v4.0.0.beta15)
|
||||
|
||||
---
|
||||
|
||||
## v4.0.0.beta14 (2024-11-25)
|
||||
|
||||
### Breaking Changes 🚨
|
||||
- Drop support for Rails 6.1 [#8449](https://github.com/activeadmin/activeadmin/pull/8449)
|
||||
- Drop Ruby 3.0 compatibility [#8489](https://github.com/activeadmin/activeadmin/pull/8489)
|
||||
|
||||
### Enhancements ✨
|
||||
- Add polish translations for search status [#8487](https://github.com/activeadmin/activeadmin/pull/8487)
|
||||
- Update zh-TW & ja locale with new v4 keys [#8521](https://github.com/activeadmin/activeadmin/pull/8521)
|
||||
- Update zh-CN locale with new v4 keys [#8546](https://github.com/activeadmin/activeadmin/pull/8546)
|
||||
- Improve v3 docs regarding compatibility with vite_rails [#8549](https://github.com/activeadmin/activeadmin/pull/8549)
|
||||
- Remove redundant safe navigation operator [#8528](https://github.com/activeadmin/activeadmin/pull/8528)
|
||||
- Use safe navigation for `pundit_default_policy` [#8530](https://github.com/activeadmin/activeadmin/pull/8530)
|
||||
- Use safe navigation operator in layout helper [#8533](https://github.com/activeadmin/activeadmin/pull/8533)
|
||||
|
||||
### Bug Fixes 🐛
|
||||
- run update_resource inside a transaction to avoid autosaving relationships through assign_attributes when the record is invalid [#7437](https://github.com/activeadmin/activeadmin/pull/7437)
|
||||
- Fix attributes passed to form has_many not being set on new record form items [#8550](https://github.com/activeadmin/activeadmin/pull/8550)
|
||||
- Convert plugin.js to ESM because package.json has type set to module [#8536](https://github.com/activeadmin/activeadmin/pull/8536)
|
||||
|
||||
### Other Changes 🛠
|
||||
- Migrate docs to VitePress [#8194](https://github.com/activeadmin/activeadmin/pull/8194)
|
||||
|
||||
**Full Changelog**: [v4.0.0.beta13...v4.0.0.beta14](https://github.com/activeadmin/activeadmin/compare/v4.0.0.beta13...v4.0.0.beta14)
|
||||
|
||||
---
|
||||
|
||||
## v4.0.0.beta13 (2024-09-24)
|
||||
|
||||
### Enhancements ✨
|
||||
- Add polish translations for v4 keys [#8481](https://github.com/activeadmin/activeadmin/pull/8481)
|
||||
- Add spanish translations for v4 keys [#8483](https://github.com/activeadmin/activeadmin/pull/8483)
|
||||
- Prefer `require_relative` for internal requires [#8482](https://github.com/activeadmin/activeadmin/pull/8482)
|
||||
|
||||
**Full Changelog**: [v4.0.0.beta12...v4.0.0.beta13](https://github.com/activeadmin/activeadmin/compare/v4.0.0.beta12...v4.0.0.beta13)
|
||||
|
||||
---
|
||||
|
||||
## v4.0.0.beta12 (2024-09-15)
|
||||
|
||||
### Enhancements ✨
|
||||
- Bump `inherited_resources` requirement to `~> 2.0` [#8477](https://github.com/activeadmin/activeadmin/pull/8477)
|
||||
|
||||
**Full Changelog**: [v4.0.0.beta11...v4.0.0.beta12](https://github.com/activeadmin/activeadmin/compare/v4.0.0.beta11...v4.0.0.beta12)
|
||||
|
||||
---
|
||||
|
||||
## v4.0.0.beta11 (2024-08-31)
|
||||
|
||||
### Enhancements ✨
|
||||
- Unify specifying label in attributes_table component [#8458](https://github.com/activeadmin/activeadmin/pull/8458)
|
||||
- Optimize count query for `pagination_total: false` option [#6911](https://github.com/activeadmin/activeadmin/pull/6911)
|
||||
- Use attribute_types instead of columns_hash to determine type [#8457](https://github.com/activeadmin/activeadmin/pull/8457)
|
||||
|
||||
### Bug Fixes 🐛
|
||||
- Use consistent text-like inputs selector list for CSS styles [#8456](https://github.com/activeadmin/activeadmin/pull/8456)
|
||||
|
||||
**Full Changelog**: [v4.0.0.beta10...v4.0.0.beta11](https://github.com/activeadmin/activeadmin/compare/v4.0.0.beta10...v4.0.0.beta11)
|
||||
|
||||
---
|
||||
|
||||
## v4.0.0.beta10 (2024-08-24)
|
||||
|
||||
### Template Updates 📝
|
||||
- Add host app's layouts/active_admin to tailwind config [#8430](https://github.com/activeadmin/activeadmin/pull/8430)
|
||||
|
||||
### Enhancements ✨
|
||||
- Support async_count for scopes [#8394](https://github.com/activeadmin/activeadmin/pull/8394)
|
||||
- Add tbody_html and row_html options to TableFor and IndexAsTable [#8423](https://github.com/activeadmin/activeadmin/pull/8423)
|
||||
|
||||
### Bug Fixes 🐛
|
||||
- Improve form f.inputs attributes rendering [#8439](https://github.com/activeadmin/activeadmin/pull/8439), [#8448](https://github.com/activeadmin/activeadmin/pull/8448)
|
||||
- Fix batch action with partial and no confirm doesn't submit the form on click [#8442](https://github.com/activeadmin/activeadmin/pull/8442)
|
||||
|
||||
**Full Changelog**: [v4.0.0.beta9...v4.0.0.beta10](https://github.com/activeadmin/activeadmin/compare/v4.0.0.beta9...v4.0.0.beta10)
|
||||
|
||||
---
|
||||
|
||||
## v4.0.0.beta9 (2024-08-04)
|
||||
|
||||
### Template Updates 📝
|
||||
- Add accessible names for navigation buttons [#8338](https://github.com/activeadmin/activeadmin/pull/8338)
|
||||
|
||||
### Enhancements ✨
|
||||
- Better implementation of counter-cache-column check [#8411](https://github.com/activeadmin/activeadmin/pull/8411)
|
||||
|
||||
### Other Changes 🛠
|
||||
- Fix url redirects in documentation [#8407](https://github.com/activeadmin/activeadmin/pull/8407)
|
||||
|
||||
**Full Changelog**: [v4.0.0.beta8...v4.0.0.beta9](https://github.com/activeadmin/activeadmin/compare/v4.0.0.beta8...v4.0.0.beta9)
|
||||
|
||||
---
|
||||
|
||||
## v4.0.0.beta8 (2024-07-27)
|
||||
|
||||
### Enhancements ✨
|
||||
- Update Catalan translation [#8356](https://github.com/activeadmin/activeadmin/pull/8356)
|
||||
- Allow batch actions without a confirmation dialog [#8389](https://github.com/activeadmin/activeadmin/pull/8389)
|
||||
- Fix styles for select[multiple] form controls [#8406](https://github.com/activeadmin/activeadmin/pull/8406)
|
||||
|
||||
**Full Changelog**: [v4.0.0.beta7...v4.0.0.beta8](https://github.com/activeadmin/activeadmin/compare/v4.0.0.beta7...v4.0.0.beta8)
|
||||
|
||||
---
|
||||
|
||||
## v4.0.0.beta7 (2024-05-31)
|
||||
|
||||
### Enhancements ✨
|
||||
- Update de locale with new v4 keys [#8325](https://github.com/activeadmin/activeadmin/pull/8325)
|
||||
- Remove de-CH locale [#8326](https://github.com/activeadmin/activeadmin/pull/8326)
|
||||
|
||||
### Security Fixes 🔒
|
||||
- Fix potential XSS issue when rendering form legends [#8348](https://github.com/activeadmin/activeadmin/pull/8348)
|
||||
|
||||
**Full Changelog**: [v4.0.0.beta6...v4.0.0.beta7](https://github.com/activeadmin/activeadmin/compare/v4.0.0.beta6...v4.0.0.beta7)
|
||||
|
||||
---
|
||||
|
||||
## v4.0.0.beta6 (2024-05-03)
|
||||
|
||||
### Breaking Changes 🚨
|
||||
- Drop Ruby 2.7 support [#8259](https://github.com/activeadmin/activeadmin/pull/8259)
|
||||
|
||||
### Template Updates 📝
|
||||
- Use Tailwind's darkMode selector strategy [#8264](https://github.com/activeadmin/activeadmin/pull/8264)
|
||||
|
||||
### Enhancements ✨
|
||||
- Update zh-CN locale with new v4 keys [#8284](https://github.com/activeadmin/activeadmin/pull/8284)
|
||||
- Update zh-TW locale with new v4 keys [#8297](https://github.com/activeadmin/activeadmin/pull/8297)
|
||||
|
||||
### Bug Fixes 🐛
|
||||
- Add csv dependency to fix Ruby 3.3 warning [#8303](https://github.com/activeadmin/activeadmin/pull/8303)
|
||||
|
||||
**Full Changelog**: [v4.0.0.beta5...v4.0.0.beta6](https://github.com/activeadmin/activeadmin/compare/v4.0.0.beta5...v4.0.0.beta6)
|
||||
|
||||
---
|
||||
|
||||
## v4.0.0.beta5 (2024-02-14)
|
||||
|
||||
### Enhancements ✨
|
||||
- Improve Italian translation [#8235](https://github.com/activeadmin/activeadmin/pull/8235)
|
||||
- Bump flowbite to v2.3.0 [#8257](https://github.com/activeadmin/activeadmin/pull/8257)
|
||||
|
||||
### Bug Fixes 🐛
|
||||
- Use an anchor for tabs component toggle [#8242](https://github.com/activeadmin/activeadmin/pull/8242)
|
||||
|
||||
**Full Changelog**: [v4.0.0.beta4...v4.0.0.beta5](https://github.com/activeadmin/activeadmin/compare/v4.0.0.beta4...v4.0.0.beta5)
|
||||
|
||||
---
|
||||
|
||||
## v4.0.0.beta4 (2024-01-17)
|
||||
|
||||
### Template Updates 📝
|
||||
- Move pagination translations to active_admin scope [#8218](https://github.com/activeadmin/activeadmin/pull/8218)
|
||||
|
||||
### Enhancements ✨
|
||||
- Vendor rails-ujs ESM JS [#8217](https://github.com/activeadmin/activeadmin/pull/8217)
|
||||
- Include vendor JS files in NPM package [#8221](https://github.com/activeadmin/activeadmin/pull/8221)
|
||||
- Remove i18n-tasks.yml from gem release [#8227](https://github.com/activeadmin/activeadmin/pull/8227)
|
||||
- Make importmap-rails optional [#8228](https://github.com/activeadmin/activeadmin/pull/8228)
|
||||
- Exclude primary key from generated resource [#8232](https://github.com/activeadmin/activeadmin/pull/8232)
|
||||
- Make NPM package compatible with tools like vite_rails [#8234](https://github.com/activeadmin/activeadmin/pull/8234)
|
||||
|
||||
### Bug Fixes 🐛
|
||||
- Ensure form presenter is applied on create/update actions [#8238](https://github.com/activeadmin/activeadmin/pull/8238)
|
||||
|
||||
**Full Changelog**: [v4.0.0.beta3...v4.0.0.beta4](https://github.com/activeadmin/activeadmin/compare/v4.0.0.beta3...v4.0.0.beta4)
|
||||
|
||||
---
|
||||
|
||||
## v4.0.0.beta3 (2024-01-06)
|
||||
|
||||
- Include additional files in gem release [#8212](https://github.com/activeadmin/activeadmin/pull/8212)
|
||||
|
||||
**Full Changelog**: [v4.0.0.beta2...v4.0.0.beta3](https://github.com/activeadmin/activeadmin/compare/v4.0.0.beta2...v4.0.0.beta3)
|
||||
|
||||
---
|
||||
|
||||
## v4.0.0.beta2 (2024-01-06)
|
||||
|
||||
- Include vendor directory in gem release [#8211](https://github.com/activeadmin/activeadmin/pull/8211)
|
||||
|
||||
**Full Changelog**: [v4.0.0.beta1...v4.0.0.beta2](https://github.com/activeadmin/activeadmin/compare/v4.0.0.beta1...v4.0.0.beta2)
|
||||
|
||||
---
|
||||
|
||||
## v4.0.0.beta1 (2024-01-06)
|
||||
|
||||
**First beta release of ActiveAdmin v4!**
|
||||
|
||||
This release represents a complete redesign using TailwindCSS with **mobile web, dark mode and RTL support** and a default, **customizable theme through partials**.
|
||||
|
||||
### Key Features
|
||||
- **TailwindCSS**: Complete migration to TailwindCSS
|
||||
- **Mobile Support**: Fully responsive design
|
||||
- **Dark Mode**: Built-in dark mode support
|
||||
- **RTL Support**: Right-to-left language support
|
||||
- **ESM JavaScript**: Modern ES modules
|
||||
- **importmap-rails**: Uses importmap-rails for JS assets
|
||||
- **Customizable Theme**: Theme customization through partials
|
||||
|
||||
### Breaking Changes 🚨
|
||||
- Requires `cssbundling-rails` and `importmap-rails`
|
||||
- Removed all SCSS files (sassc-rails dependency removed)
|
||||
- Complete UI/UX redesign
|
||||
|
||||
### Major Changes
|
||||
- Prep Tailwind CSS migration (multiple PRs: #8035, #8036, #8037, #8116, #8122, #8139, #8155, #8170)
|
||||
- Remove old, since replaced JS [#8040](https://github.com/activeadmin/activeadmin/pull/8040)
|
||||
- Replace html/assets related configs with simple partials [#8156](https://github.com/activeadmin/activeadmin/pull/8156)
|
||||
- Remove sassc-rails and all SCSS files [#8157](https://github.com/activeadmin/activeadmin/pull/8157)
|
||||
- Extract headers, menu and sidebar components to partials [#8162](https://github.com/activeadmin/activeadmin/pull/8162)
|
||||
- Use ES format for JS [#8171](https://github.com/activeadmin/activeadmin/pull/8171)
|
||||
- Extract layout and pages to partials [#8172](https://github.com/activeadmin/activeadmin/pull/8172)
|
||||
- Use importmap-rails for JS assets [#8186](https://github.com/activeadmin/activeadmin/pull/8186)
|
||||
- Move kaminari templates to active_admin folder [#8190](https://github.com/activeadmin/activeadmin/pull/8190)
|
||||
- Improve RTL support all around [#8196](https://github.com/activeadmin/activeadmin/pull/8196)
|
||||
- Migrate view helpers to app/helpers path [#8202](https://github.com/activeadmin/activeadmin/pull/8202)
|
||||
|
||||
### Enhancements ✨
|
||||
- Provide detail in DB statement timeout error for filters [#8117](https://github.com/activeadmin/activeadmin/pull/8117)
|
||||
- Use active_admin_authorization as Ransack auth_object option [#8143](https://github.com/activeadmin/activeadmin/pull/8143)
|
||||
- Update FR locales [#8193](https://github.com/activeadmin/activeadmin/pull/8193)
|
||||
- Update nl.yml for v4 [#8195](https://github.com/activeadmin/activeadmin/pull/8195)
|
||||
|
||||
### Other Changes 🛠
|
||||
- Introduce RuboCop Performance [#8024](https://github.com/activeadmin/activeadmin/pull/8024)
|
||||
- Remove multiline ternary operator [#8034](https://github.com/activeadmin/activeadmin/pull/8034)
|
||||
- Prefer `match?` over `=~` to avoid MatchData [#8138](https://github.com/activeadmin/activeadmin/pull/8138)
|
||||
|
||||
**Full Changelog**: [v3.2.0...v4.0.0.beta1](https://github.com/activeadmin/activeadmin/compare/v3.2.0...v4.0.0.beta1)
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
**Minimum Requirements (as of v4.0.0.beta20):**
|
||||
- Rails 7.2+
|
||||
- Ruby 3.2+
|
||||
- cssbundling-rails
|
||||
- importmap-rails (optional as of beta4)
|
||||
|
||||
**Key Migration Path:**
|
||||
The v4.0.0 beta series represents a complete redesign of ActiveAdmin using TailwindCSS. The migration requires:
|
||||
1. Installing `cssbundling-rails` and configuring TailwindCSS
|
||||
2. Installing `importmap-rails` (optional since beta4)
|
||||
3. Running the assets generator
|
||||
4. Updating custom CSS/JS from the old SCSS/jQuery patterns
|
||||
5. Reviewing the [Upgrading guide](https://github.com/activeadmin/activeadmin/blob/master/UPGRADING.md)
|
||||
|
||||
See [demo app](https://github.com/activeadmin/demo.activeadmin.info) for a working example.
|
||||
136
docs/activeadmin-tailwind-4.md
Обычный файл
136
docs/activeadmin-tailwind-4.md
Обычный файл
@@ -0,0 +1,136 @@
|
||||
# ActiveAdmin + Tailwind CSS v4 Guide
|
||||
|
||||
This guide consolidates the ActiveAdmin 4.0.0.beta20 upgrade notes with a working Tailwind v4 build setup. Use it as a template when updating other ActiveAdmin extension gems.
|
||||
|
||||
## What Changed in ActiveAdmin 4.0.0.beta20 (from UPGRADING.md)
|
||||
|
||||
### Version Requirements
|
||||
- Rails 7.2+ (Rails 7.0 and 7.1 are no longer supported)
|
||||
- Ruby 3.2+ (Ruby 3.0 and 3.1 are no longer supported)
|
||||
|
||||
### Template Updates
|
||||
- `_site_header.html.erb` container class changed from `sticky` to `fixed`.
|
||||
- `active_admin.html.erb` now includes the `pt-16` utility class.
|
||||
|
||||
### Tailwind v4 Updates
|
||||
Replace the old Tailwind directives with the new v4 import and config:
|
||||
|
||||
```diff
|
||||
-@tailwind base;
|
||||
-@tailwind components;
|
||||
-@tailwind utilities;
|
||||
+@import "tailwindcss";
|
||||
+
|
||||
+@config "../../../tailwind-active_admin.config.mjs";
|
||||
```
|
||||
|
||||
Update your CSS build command:
|
||||
|
||||
```diff
|
||||
-"build:css": "tailwindcss -i ./app/assets/stylesheets/active_admin.css -o ./app/assets/builds/active_admin.css --minify -c tailwind-active_admin.config.js"
|
||||
+"build:css": "npx @tailwindcss/cli -i ./app/assets/stylesheets/active_admin.css -o ./app/assets/builds/active_admin.css --minify"
|
||||
```
|
||||
|
||||
If you use `tailwindcss-rails`, prefer the bundled `bin/tailwindcss` and the `@config` directive instead of passing `-c`.
|
||||
|
||||
### ESM Config Warning
|
||||
Tailwind config now uses ESM. To avoid the warning:
|
||||
- Rename `tailwind-active_admin.config.js` to `tailwind-active_admin.config.mjs`, or
|
||||
- Add `"type": "module"` to `package.json`.
|
||||
|
||||
### Breaking Changes Summary
|
||||
- jQuery and jQuery UI removed.
|
||||
- `columns` component removed (use Tailwind grid).
|
||||
- `tabs` component removed.
|
||||
- Replace `default_main_content` with `render "show_default"`.
|
||||
- Replace `as: :datepicker` with `as: :date_picker`.
|
||||
- Replace `active_admin_comments` with `active_admin_comments_for(resource)`.
|
||||
- Replace `attributes_table` with `attributes_table_for(resource)` in sidebars.
|
||||
- Removed `IndexAsBlog`, `IndexAsBlock`, `IndexAsGrid`.
|
||||
- Batch action form DSL replaced with partial support.
|
||||
- Deeply nested submenus removed (only one level supported).
|
||||
- Removed `Panel#header_action` and `index_column`.
|
||||
|
||||
### New in beta20
|
||||
- Parent menu item linking support
|
||||
- Improved comments pagination styling
|
||||
- Better vertical spacing for has-many forms
|
||||
- Pointer cursor restored on eligible buttons
|
||||
- Various accessibility improvements
|
||||
|
||||
## Recommended Build Setup (tailwindcss-rails)
|
||||
|
||||
### 1. Gemfile
|
||||
|
||||
```ruby
|
||||
gem "activeadmin", "4.0.0.beta20"
|
||||
gem "tailwindcss-rails", "~> 4.4.0"
|
||||
```
|
||||
|
||||
### 2. Tailwind Input
|
||||
|
||||
```css
|
||||
/* app/assets/stylesheets/active_admin.tailwind.css */
|
||||
@import "tailwindcss";
|
||||
@config "../../../tailwind-active_admin.config.mjs";
|
||||
```
|
||||
|
||||
### 3. Tailwind Config
|
||||
|
||||
```javascript
|
||||
// tailwind-active_admin.config.mjs
|
||||
import { execSync } from "child_process";
|
||||
import activeAdminPlugin from "@activeadmin/activeadmin/plugin";
|
||||
|
||||
const activeAdminPath = execSync("bundle show activeadmin", {
|
||||
encoding: "utf-8"
|
||||
}).trim();
|
||||
|
||||
export default {
|
||||
content: [
|
||||
`${activeAdminPath}/vendor/javascript/flowbite.js`,
|
||||
`${activeAdminPath}/plugin.js`,
|
||||
`${activeAdminPath}/app/views/**/*.{arb,erb,html,rb}`,
|
||||
"./app/admin/**/*.{arb,erb,html,rb}",
|
||||
"./app/views/active_admin/**/*.{arb,erb,html,rb}`,
|
||||
"./app/views/admin/**/*.{arb,erb,html,rb}`,
|
||||
"./app/views/layouts/active_admin*.{erb,html}`,
|
||||
"./app/javascript/**/*.js"
|
||||
],
|
||||
darkMode: "selector",
|
||||
plugins: [activeAdminPlugin]
|
||||
};
|
||||
```
|
||||
|
||||
### 4. Build Tasks
|
||||
|
||||
```ruby
|
||||
# lib/tasks/active_admin.rake
|
||||
namespace :active_admin do
|
||||
desc "Build Active Admin Tailwind stylesheets"
|
||||
task build: :environment do
|
||||
command = [
|
||||
Rails.root.join("bin/tailwindcss").to_s,
|
||||
"-i", Rails.root.join("app/assets/stylesheets/active_admin.tailwind.css").to_s,
|
||||
"-o", Rails.root.join("app/assets/builds/active_admin.css").to_s,
|
||||
"-m"
|
||||
]
|
||||
|
||||
system(*command, exception: true)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
### 5. Tailwind CLI Binstub
|
||||
|
||||
```bash
|
||||
bundle binstubs tailwindcss-ruby --force
|
||||
```
|
||||
|
||||
## Notes for Extension Gems
|
||||
|
||||
When updating other ActiveAdmin extension gems:
|
||||
- Keep all JS/CSS inside the gem or npm package; do not copy large files into host apps.
|
||||
- Add only a thin import to the host app (`import "your_gem"`).
|
||||
- Use Tailwind v4 `@import` + `@config` and ESM config files.
|
||||
- Avoid jQuery-based plugins or require them explicitly.
|
||||
141
docs/setup-activeadmin-app.md
Обычный файл
141
docs/setup-activeadmin-app.md
Обычный файл
@@ -0,0 +1,141 @@
|
||||
# Setting Up a Standalone ActiveAdmin 4 App (Tailwind v4)
|
||||
|
||||
This guide creates a new Rails app with ActiveAdmin 4.0.0.beta20, Tailwind CSS v4, and optional AA extension gems.
|
||||
|
||||
## 1. Create Rails App
|
||||
|
||||
```bash
|
||||
rails new my_admin_app --css=tailwind --javascript=esbuild
|
||||
cd my_admin_app
|
||||
```
|
||||
|
||||
## 2. Gemfile
|
||||
|
||||
```ruby
|
||||
# ActiveAdmin 4 beta
|
||||
gem "activeadmin", "4.0.0.beta20"
|
||||
|
||||
# Required by ActiveAdmin 4
|
||||
gem "importmap-rails", "~> 2.0"
|
||||
gem "propshaft"
|
||||
|
||||
# Tailwind CLI (v4)
|
||||
gem "tailwindcss-rails", "~> 4.4.0"
|
||||
```
|
||||
|
||||
```bash
|
||||
bundle install
|
||||
```
|
||||
|
||||
## 3. Install ActiveAdmin
|
||||
|
||||
```bash
|
||||
rails generate active_admin:install
|
||||
rails db:create db:migrate db:seed
|
||||
```
|
||||
|
||||
## 4. Install ActiveAdmin Assets
|
||||
|
||||
```bash
|
||||
rails generate active_admin:assets
|
||||
```
|
||||
|
||||
This creates:
|
||||
- `app/assets/stylesheets/active_admin.css`
|
||||
- `tailwind-active_admin.config.js` (ESM)
|
||||
|
||||
Rename to `.mjs` for Tailwind v4:
|
||||
|
||||
```bash
|
||||
mv tailwind-active_admin.config.js tailwind-active_admin.config.mjs
|
||||
```
|
||||
|
||||
## 5. Tailwind Input (ActiveAdmin)
|
||||
|
||||
Create or update the Tailwind input file:
|
||||
|
||||
```css
|
||||
/* app/assets/stylesheets/active_admin.tailwind.css */
|
||||
@import "tailwindcss";
|
||||
@config "../../../tailwind-active_admin.config.mjs";
|
||||
```
|
||||
|
||||
## 6. Build Tasks
|
||||
|
||||
```ruby
|
||||
# lib/tasks/active_admin.rake
|
||||
namespace :active_admin do
|
||||
desc "Build Active Admin Tailwind stylesheets"
|
||||
task build: :environment do
|
||||
command = [
|
||||
Rails.root.join("bin/tailwindcss").to_s,
|
||||
"-i", Rails.root.join("app/assets/stylesheets/active_admin.tailwind.css").to_s,
|
||||
"-o", Rails.root.join("app/assets/builds/active_admin.css").to_s,
|
||||
"-m"
|
||||
]
|
||||
|
||||
system(*command, exception: true)
|
||||
end
|
||||
|
||||
desc "Watch Active Admin Tailwind stylesheets"
|
||||
task watch: :environment do
|
||||
command = [
|
||||
Rails.root.join("bin/tailwindcss").to_s,
|
||||
"--watch",
|
||||
"-i", Rails.root.join("app/assets/stylesheets/active_admin.tailwind.css").to_s,
|
||||
"-o", Rails.root.join("app/assets/builds/active_admin.css").to_s,
|
||||
"-m"
|
||||
]
|
||||
|
||||
system(*command, exception: true)
|
||||
end
|
||||
end
|
||||
|
||||
Rake::Task["assets:precompile"].enhance(["active_admin:build"])
|
||||
```
|
||||
|
||||
## 7. JavaScript Entry
|
||||
|
||||
```javascript
|
||||
// app/javascript/active_admin.js
|
||||
import "@activeadmin/activeadmin";
|
||||
```
|
||||
|
||||
## 8. Build Assets
|
||||
|
||||
```bash
|
||||
bundle binstubs tailwindcss-ruby --force
|
||||
npm install @activeadmin/activeadmin@^4.0.0-beta20
|
||||
npm run build
|
||||
```
|
||||
|
||||
## 9. Start Server
|
||||
|
||||
```bash
|
||||
rails server
|
||||
```
|
||||
|
||||
Visit http://localhost:3000/admin
|
||||
|
||||
## ActiveAdmin 4.0.0.beta20 Notes (from upgrade guide)
|
||||
|
||||
**Version Requirements:**
|
||||
- Rails 7.2+ (Rails 7.0 and 7.1 are no longer supported)
|
||||
- Ruby 3.2+ (Ruby 3.0 and 3.1 are no longer supported)
|
||||
|
||||
**Breaking Changes from earlier v4 betas:**
|
||||
- `_site_header.html.erb` container class changed from `sticky` to `fixed`.
|
||||
- `active_admin.html.erb` adds the `pt-16` utility class.
|
||||
- Tailwind v4 requires `@import "tailwindcss"` + `@config`.
|
||||
- jQuery and jQuery UI removed; `columns` and `tabs` components removed.
|
||||
- Replace `default_main_content` with `render "show_default"`.
|
||||
- Replace `as: :datepicker` with `as: :date_picker`.
|
||||
- Replace `active_admin_comments` with `active_admin_comments_for(resource)`.
|
||||
- Replace `attributes_table` with `attributes_table_for(resource)` in sidebars.
|
||||
|
||||
**New in beta20:**
|
||||
- Parent menu item linking support
|
||||
- Improved comments pagination styling
|
||||
- Better vertical spacing for has-many forms
|
||||
- Pointer cursor restored on eligible buttons
|
||||
- Various accessibility improvements
|
||||
187
docs/setup-activeadmin-gem.md
Обычный файл
187
docs/setup-activeadmin-gem.md
Обычный файл
@@ -0,0 +1,187 @@
|
||||
# Setting Up an ActiveAdmin 4 Extension Gem (Combustion)
|
||||
|
||||
This guide mirrors the working setup used in this repo: ActiveAdmin 4.0.0.beta20 + Tailwind CSS v4 + test app.
|
||||
|
||||
## 1. Gem Dependencies
|
||||
|
||||
```ruby
|
||||
# Gemfile
|
||||
source "https://rubygems.org"
|
||||
gemspec
|
||||
|
||||
gem "rails", "~> 7.2"
|
||||
gem "activeadmin", "4.0.0.beta20"
|
||||
gem "sqlite3"
|
||||
gem "puma"
|
||||
|
||||
gem "importmap-rails", "~> 2.0"
|
||||
gem "propshaft"
|
||||
|
||||
gem "tailwindcss-rails", "~> 4.4.0"
|
||||
|
||||
group :development, :test do
|
||||
gem "combustion", "~> 1.3"
|
||||
gem "rspec-rails"
|
||||
gem "capybara"
|
||||
end
|
||||
```
|
||||
|
||||
## 2. Combustion Test App
|
||||
|
||||
```bash
|
||||
bundle exec combust
|
||||
```
|
||||
|
||||
## 3. config.ru Loading Order
|
||||
|
||||
```ruby
|
||||
# config.ru
|
||||
require "rubygems"
|
||||
require "bundler"
|
||||
|
||||
Bundler.setup(:default, :development)
|
||||
|
||||
require "combustion"
|
||||
Combustion.initialize! :active_record, :action_controller, :action_view do
|
||||
config.load_defaults Rails::VERSION::STRING.to_f if Rails::VERSION::MAJOR >= 7
|
||||
end
|
||||
|
||||
require "importmap-rails"
|
||||
require "active_admin"
|
||||
require "activeadmin_quill_editor"
|
||||
|
||||
run Combustion::Application
|
||||
```
|
||||
|
||||
## 4. Internal App Structure
|
||||
|
||||
```bash
|
||||
cd spec/internal
|
||||
mkdir -p app/admin app/assets/{builds,config,stylesheets} app/javascript
|
||||
```
|
||||
|
||||
## 5. ActiveAdmin Setup
|
||||
|
||||
```ruby
|
||||
# spec/internal/config/initializers/active_admin.rb
|
||||
ActiveAdmin.setup do |config|
|
||||
config.site_title = "Test App"
|
||||
config.authentication_method = false
|
||||
config.current_user_method = false
|
||||
end
|
||||
```
|
||||
|
||||
## 6. Tailwind Input + Config
|
||||
|
||||
```css
|
||||
/* spec/internal/app/assets/stylesheets/active_admin.tailwind.css */
|
||||
@import "tailwindcss";
|
||||
@config "../../../tailwind-active_admin.config.mjs";
|
||||
|
||||
/* Import Quill Editor CSS */
|
||||
@import "activeadmin/quill_editor/quill.snow";
|
||||
@import "activeadmin/quill_editor_input";
|
||||
```
|
||||
|
||||
```javascript
|
||||
// spec/internal/tailwind-active_admin.config.mjs
|
||||
import { execSync } from "child_process";
|
||||
import activeAdminPlugin from "@activeadmin/activeadmin/plugin";
|
||||
|
||||
const activeAdminPath = execSync("bundle show activeadmin", {
|
||||
encoding: "utf-8"
|
||||
}).trim();
|
||||
|
||||
export default {
|
||||
content: [
|
||||
`${activeAdminPath}/vendor/javascript/flowbite.js`,
|
||||
`${activeAdminPath}/plugin.js`,
|
||||
`${activeAdminPath}/app/views/**/*.{arb,erb,html,rb}`,
|
||||
"./app/admin/**/*.{arb,erb,html,rb}`,
|
||||
"./app/views/**/*.{arb,erb,html,rb}`,
|
||||
"./app/javascript/**/*.js",
|
||||
"../../app/assets/**/*.{js,css}"
|
||||
],
|
||||
darkMode: "selector",
|
||||
plugins: [activeAdminPlugin]
|
||||
};
|
||||
```
|
||||
|
||||
## 7. Tailwind Build Tasks
|
||||
|
||||
```ruby
|
||||
# spec/internal/lib/tasks/active_admin.rake
|
||||
namespace :active_admin do
|
||||
desc "Build Active Admin Tailwind stylesheets"
|
||||
task build: :environment do
|
||||
command = [
|
||||
Rails.root.join("bin/tailwindcss").to_s,
|
||||
"-i", Rails.root.join("app/assets/stylesheets/active_admin.tailwind.css").to_s,
|
||||
"-o", Rails.root.join("app/assets/builds/active_admin.css").to_s,
|
||||
"-m"
|
||||
]
|
||||
|
||||
system(*command, exception: true)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
## 8. Tailwind Binstub
|
||||
|
||||
```bash
|
||||
bundle binstubs tailwindcss-ruby --force
|
||||
```
|
||||
|
||||
## 9. JS Entry
|
||||
|
||||
```javascript
|
||||
// spec/internal/app/javascript/active_admin.js
|
||||
import "@activeadmin/activeadmin";
|
||||
|
||||
import Quill from "quill";
|
||||
window.Quill = Quill;
|
||||
|
||||
import "activeadmin_quill_editor";
|
||||
```
|
||||
|
||||
## 10. package.json (internal)
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "internal",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build:js": "node esbuild.config.js",
|
||||
"build:css": "bundle exec rake active_admin:build",
|
||||
"build": "npm run build:js && npm run build:css"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@activeadmin/activeadmin": "^4.0.0-beta20",
|
||||
"quill": "^2.0.3",
|
||||
"esbuild": "^0.24.2"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 11. ActiveAdmin 4.0.0.beta20 Notes (from upgrade guide)
|
||||
|
||||
**Version Requirements:**
|
||||
- Rails 7.2+ (Rails 7.0 and 7.1 are no longer supported)
|
||||
- Ruby 3.2+ (Ruby 3.0 and 3.1 are no longer supported)
|
||||
|
||||
**Breaking Changes from earlier v4 betas:**
|
||||
- `_site_header.html.erb` container class changed from `sticky` to `fixed`.
|
||||
- `active_admin.html.erb` adds the `pt-16` utility class.
|
||||
- Tailwind v4 requires `@import "tailwindcss"` + `@config`.
|
||||
- jQuery and jQuery UI removed; `columns` and `tabs` components removed.
|
||||
- Replace `default_main_content` with `render "show_default"`.
|
||||
- Replace `as: :datepicker` with `as: :date_picker`.
|
||||
- Replace `active_admin_comments` with `active_admin_comments_for(resource)`.
|
||||
- Replace `attributes_table` with `attributes_table_for(resource)` in sidebars.
|
||||
|
||||
**New in beta20:**
|
||||
- Parent menu item linking support
|
||||
- Improved comments pagination styling
|
||||
- Better vertical spacing for has-many forms
|
||||
- Pointer cursor restored on eligible buttons
|
||||
- Various accessibility improvements
|
||||
525
docs/update-quill.md
Обычный файл
525
docs/update-quill.md
Обычный файл
@@ -0,0 +1,525 @@
|
||||
# Quill Editor Migration Guide for ActiveAdmin 4
|
||||
|
||||
## Overview
|
||||
This guide helps you migrate the activeadmin-quill_editor gem to support ActiveAdmin 4 with modern Rails 8+ and Propshaft asset pipeline.
|
||||
|
||||
## Key Changes Made
|
||||
|
||||
### 1. Removed jQuery Dependency
|
||||
**Before**: JavaScript relied on jQuery for initialization and DOM manipulation
|
||||
**After**: Pure vanilla JavaScript with modern event listeners
|
||||
|
||||
### 2. Asset Pipeline Updates
|
||||
**Before**: Sprockets-based asset compilation with CDN dependencies
|
||||
**After**: Propshaft-compatible with NPM-based Quill installation
|
||||
|
||||
### 3. Ruby and Rails Version Requirements
|
||||
- **Minimum Ruby**: 3.2+ (previously 3.0+)
|
||||
- **Rails Support**: 7.0+ with ActiveAdmin 2.9-4.x
|
||||
- **ActiveAdmin 4**: Full support with Propshaft
|
||||
|
||||
## Installation & Setup
|
||||
|
||||
### Step 1: Update Your Gemfile
|
||||
```ruby
|
||||
gem 'activeadmin_quill_editor', '~> 2.0'
|
||||
```
|
||||
|
||||
### Step 2: Install Quill via NPM
|
||||
```bash
|
||||
# In your Rails app root
|
||||
npm install quill@^2.0.2
|
||||
```
|
||||
|
||||
Or add to `package.json`:
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"quill": "^2.0.2"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Configure JavaScript (Rails 8 with esbuild)
|
||||
|
||||
**IMPORTANT**: Do NOT copy the gem's JavaScript file into your application. The gem provides `activeadmin_quill_editor.js` via its vendor/assets directory. You should import it, not duplicate it.
|
||||
|
||||
Create or update `app/javascript/active_admin.js`:
|
||||
```javascript
|
||||
// Import ActiveAdmin - this already includes all features and Rails UJS
|
||||
// DO NOT import Rails separately as it's already included and started in ActiveAdmin
|
||||
import '@activeadmin/activeadmin';
|
||||
|
||||
// Import Quill from NPM and make it globally available
|
||||
import Quill from 'quill';
|
||||
window.Quill = Quill;
|
||||
|
||||
// Import the image uploader plugin if available (optional)
|
||||
try {
|
||||
const ImageUploader = require('quill-image-uploader');
|
||||
window.ImageUploader = ImageUploader.default || ImageUploader;
|
||||
} catch(e) {
|
||||
// Image uploader is optional (silent failure)
|
||||
}
|
||||
|
||||
// Import the Quill Editor initialization module from the gem
|
||||
// This imports from vendor/assets/javascripts/activeadmin/quill_editor.js
|
||||
import QuillEditorModule from 'activeadmin/quill_editor';
|
||||
|
||||
// Now that Quill is available, initialize the editors
|
||||
// This ensures proper initialization order without setTimeout hacks
|
||||
if (window.QuillEditor && window.QuillEditor.init) {
|
||||
window.QuillEditor.init();
|
||||
} else if (QuillEditorModule && QuillEditorModule.init) {
|
||||
QuillEditorModule.init();
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4: Configure CSS
|
||||
|
||||
#### With Tailwind CSS (ActiveAdmin 4)
|
||||
In `app/assets/stylesheets/active_admin.tailwind.css`:
|
||||
```css
|
||||
@import "tailwindcss/base";
|
||||
@import "tailwindcss/components";
|
||||
@import "tailwindcss/utilities";
|
||||
|
||||
/* Quill styles */
|
||||
@import "quill/dist/quill.snow.css";
|
||||
@import "quill/dist/quill.bubble.css";
|
||||
```
|
||||
|
||||
#### With Sass/SCSS (Legacy)
|
||||
In `app/assets/stylesheets/active_admin.scss`:
|
||||
```scss
|
||||
@import "active_admin/base";
|
||||
@import "quill/dist/quill.snow";
|
||||
// Optional bubble theme
|
||||
@import "quill/dist/quill.bubble";
|
||||
```
|
||||
|
||||
### Step 5: Build Configuration
|
||||
|
||||
#### esbuild.config.js
|
||||
```javascript
|
||||
#!/usr/bin/env node
|
||||
const esbuild = require('esbuild');
|
||||
const path = require('path');
|
||||
|
||||
// IMPORTANT: Set up the alias to resolve the gem's JavaScript file
|
||||
// For production apps, you can get the gem path dynamically:
|
||||
const { execSync } = require('child_process');
|
||||
const gemPath = execSync('bundle show activeadmin_quill_editor', { encoding: 'utf-8' }).trim();
|
||||
// Or for development/testing with a local gem:
|
||||
// const gemPath = path.resolve(__dirname, '../..'); // Adjust based on your setup
|
||||
|
||||
// Configuration for esbuild with proper module resolution
|
||||
const config = {
|
||||
entryPoints: ['app/javascript/active_admin.js'],
|
||||
bundle: true,
|
||||
sourcemap: true,
|
||||
format: 'iife',
|
||||
outdir: 'app/assets/builds',
|
||||
publicPath: '/assets',
|
||||
loader: {
|
||||
'.js': 'js',
|
||||
},
|
||||
// Define global Quill for the initialization script
|
||||
define: {
|
||||
'global': 'window'
|
||||
},
|
||||
// CRITICAL: Use alias to import the gem's JavaScript from vendor/assets
|
||||
alias: {
|
||||
'activeadmin/quill_editor': path.join(gemPath, 'vendor/assets/javascripts/activeadmin/quill_editor.js')
|
||||
}
|
||||
};
|
||||
|
||||
// Check if we're in watch mode
|
||||
const watchMode = process.argv.includes('--watch');
|
||||
|
||||
if (watchMode) {
|
||||
// Start the build with watch mode
|
||||
esbuild.context(config).then(ctx => {
|
||||
ctx.watch();
|
||||
console.log('Watching for changes...');
|
||||
}).catch(error => {
|
||||
console.error('Build failed:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
} else {
|
||||
// Single build
|
||||
esbuild.build(config).then(() => {
|
||||
console.log('Build completed');
|
||||
}).catch(error => {
|
||||
console.error('Build failed:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
#### package.json scripts
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"build:js": "node esbuild.config.js",
|
||||
"build:css": "tailwindcss -i app/assets/stylesheets/active_admin.tailwind.css -o app/assets/builds/active_admin.css -m",
|
||||
"build": "npm run build:js && npm run build:css"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Complete Example Files
|
||||
|
||||
These are complete working examples from our test suite that you can use as reference:
|
||||
|
||||
### tailwind.config.js
|
||||
```javascript
|
||||
const execSync = require('child_process').execSync;
|
||||
const activeAdminPath = execSync('bundle show activeadmin', { encoding: 'utf-8' }).trim();
|
||||
|
||||
module.exports = {
|
||||
content: [
|
||||
`${activeAdminPath}/vendor/javascript/flowbite.js`,
|
||||
`${activeAdminPath}/plugin.js`,
|
||||
`${activeAdminPath}/app/views/**/*.{arb,erb,html,rb}`,
|
||||
'./app/admin/**/*.{arb,erb,html,rb}',
|
||||
'./app/views/active_admin/**/*.{arb,erb,html,rb}',
|
||||
'./app/views/admin/**/*.{arb,erb,html,rb}',
|
||||
'./app/javascript/**/*.js',
|
||||
// Quill editor gem files
|
||||
'../../lib/**/*.rb',
|
||||
'../../app/**/*.rb'
|
||||
],
|
||||
darkMode: "class",
|
||||
plugins: [
|
||||
require('@activeadmin/activeadmin/plugin')
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
// Add any custom theme extensions here
|
||||
}
|
||||
},
|
||||
// CRITICAL: Safelist for ActiveAdmin 4 dynamic classes
|
||||
safelist: [
|
||||
// Grid and layout
|
||||
'grid', 'gap-4', 'gap-6', 'lg:grid-cols-3', 'md:grid-cols-2',
|
||||
'col-span-2', 'col-span-3', 'lg:col-span-2', 'lg:col-span-1',
|
||||
// Flexbox
|
||||
'flex', 'inline-flex', 'flex-col', 'flex-row', 'flex-wrap', 'flex-nowrap',
|
||||
'justify-start', 'justify-end', 'justify-center', 'justify-between', 'justify-around',
|
||||
'items-start', 'items-end', 'items-center', 'items-baseline', 'items-stretch',
|
||||
// Spacing
|
||||
'space-x-4', 'space-y-4', 'space-x-2', 'space-y-2',
|
||||
'p-0', 'p-1', 'p-2', 'p-3', 'p-4', 'p-5', 'p-6', 'p-8',
|
||||
'px-0', 'px-1', 'px-2', 'px-3', 'px-4', 'px-5', 'px-6', 'px-8',
|
||||
'py-0', 'py-1', 'py-2', 'py-3', 'py-4', 'py-5', 'py-6', 'py-8',
|
||||
'm-0', 'm-1', 'm-2', 'm-3', 'm-4', 'm-5', 'm-6', 'm-8',
|
||||
'mx-0', 'mx-1', 'mx-2', 'mx-3', 'mx-4', 'mx-5', 'mx-6', 'mx-8', 'mx-auto',
|
||||
'my-0', 'my-1', 'my-2', 'my-3', 'my-4', 'my-5', 'my-6', 'my-8', 'my-auto',
|
||||
'mt-0', 'mt-1', 'mt-2', 'mt-3', 'mt-4', 'mt-5', 'mt-6', 'mt-8',
|
||||
'mb-0', 'mb-1', 'mb-2', 'mb-3', 'mb-4', 'mb-5', 'mb-6', 'mb-8',
|
||||
'ml-0', 'ml-1', 'ml-2', 'ml-3', 'ml-4', 'ml-5', 'ml-6', 'ml-8', 'ml-auto',
|
||||
'mr-0', 'mr-1', 'mr-2', 'mr-3', 'mr-4', 'mr-5', 'mr-6', 'mr-8', 'mr-auto',
|
||||
// Display
|
||||
'block', 'inline-block', 'inline', 'hidden', 'table', 'table-cell', 'table-row',
|
||||
'lg:block', 'lg:inline-block', 'lg:hidden', 'lg:flex',
|
||||
'md:block', 'md:inline-block', 'md:hidden', 'md:flex',
|
||||
'sm:block', 'sm:inline-block', 'sm:hidden', 'sm:flex',
|
||||
// Width/Height
|
||||
'w-full', 'w-auto', 'w-1/2', 'w-1/3', 'w-2/3', 'w-1/4', 'w-3/4',
|
||||
'w-12', 'w-16', 'w-20', 'w-24', 'w-32', 'w-48', 'w-64', 'w-96',
|
||||
'h-full', 'h-screen', 'h-auto', 'h-12', 'h-16', 'h-32', 'h-64',
|
||||
'min-h-screen', 'min-h-full', 'max-w-7xl', 'max-w-full',
|
||||
// Typography
|
||||
'text-xs', 'text-sm', 'text-base', 'text-lg', 'text-xl', 'text-2xl', 'text-3xl',
|
||||
'font-thin', 'font-light', 'font-normal', 'font-medium', 'font-semibold', 'font-bold',
|
||||
'text-left', 'text-center', 'text-right', 'text-justify',
|
||||
'uppercase', 'lowercase', 'capitalize', 'normal-case',
|
||||
'italic', 'not-italic',
|
||||
'leading-none', 'leading-tight', 'leading-normal', 'leading-loose',
|
||||
// Colors (for dynamic theme)
|
||||
'text-gray-50', 'text-gray-100', 'text-gray-200', 'text-gray-300', 'text-gray-400',
|
||||
'text-gray-500', 'text-gray-600', 'text-gray-700', 'text-gray-800', 'text-gray-900',
|
||||
'bg-white', 'bg-gray-50', 'bg-gray-100', 'bg-gray-200', 'bg-gray-300',
|
||||
'bg-gray-400', 'bg-gray-500', 'bg-gray-600', 'bg-gray-700', 'bg-gray-800', 'bg-gray-900',
|
||||
'bg-transparent',
|
||||
'border-gray-100', 'border-gray-200', 'border-gray-300', 'border-gray-400',
|
||||
'border-gray-500', 'border-gray-600', 'border-gray-700', 'border-gray-800',
|
||||
// Dark mode
|
||||
'dark:bg-gray-700', 'dark:bg-gray-800', 'dark:bg-gray-900',
|
||||
'dark:text-gray-50', 'dark:text-gray-100', 'dark:text-gray-200', 'dark:text-gray-300', 'dark:text-gray-400',
|
||||
'dark:text-white',
|
||||
'dark:border-gray-600', 'dark:border-gray-700', 'dark:border-gray-800',
|
||||
// Borders and Rounding
|
||||
'border', 'border-0', 'border-2', 'border-4', 'border-8',
|
||||
'border-t', 'border-b', 'border-l', 'border-r',
|
||||
'border-t-0', 'border-b-0', 'border-l-0', 'border-r-0',
|
||||
'rounded', 'rounded-sm', 'rounded-md', 'rounded-lg', 'rounded-xl', 'rounded-2xl', 'rounded-full',
|
||||
'rounded-t', 'rounded-b', 'rounded-l', 'rounded-r',
|
||||
'rounded-t-md', 'rounded-b-md', 'rounded-l-md', 'rounded-r-md',
|
||||
// Shadows
|
||||
'shadow-none', 'shadow-sm', 'shadow', 'shadow-md', 'shadow-lg', 'shadow-xl', 'shadow-2xl',
|
||||
// Overflow
|
||||
'overflow-auto', 'overflow-hidden', 'overflow-visible', 'overflow-scroll',
|
||||
'overflow-x-auto', 'overflow-x-hidden', 'overflow-x-visible', 'overflow-x-scroll',
|
||||
'overflow-y-auto', 'overflow-y-hidden', 'overflow-y-visible', 'overflow-y-scroll',
|
||||
// Position
|
||||
'static', 'fixed', 'absolute', 'relative', 'sticky',
|
||||
'top-0', 'right-0', 'bottom-0', 'left-0',
|
||||
'inset-0', 'inset-x-0', 'inset-y-0',
|
||||
// Z-index
|
||||
'z-0', 'z-10', 'z-20', 'z-30', 'z-40', 'z-50', 'z-auto',
|
||||
// Opacity
|
||||
'opacity-0', 'opacity-25', 'opacity-50', 'opacity-75', 'opacity-100',
|
||||
// Cursor
|
||||
'cursor-auto', 'cursor-pointer', 'cursor-not-allowed', 'cursor-wait',
|
||||
// Forms
|
||||
'form-input', 'form-select', 'form-checkbox', 'form-radio',
|
||||
// Tables
|
||||
'table-auto', 'table-fixed', 'border-collapse', 'border-separate',
|
||||
// Transitions
|
||||
'transition', 'transition-all', 'transition-colors', 'transition-opacity',
|
||||
'duration-75', 'duration-100', 'duration-150', 'duration-200', 'duration-300',
|
||||
'ease-in', 'ease-out', 'ease-in-out', 'ease-linear',
|
||||
// Transform
|
||||
'transform', 'transform-none',
|
||||
'scale-90', 'scale-95', 'scale-100', 'scale-105', 'scale-110',
|
||||
// Visibility
|
||||
'visible', 'invisible',
|
||||
// Quill specific classes
|
||||
'ql-toolbar', 'ql-container', 'ql-editor', 'quill-editor',
|
||||
'ql-snow', 'ql-bubble'
|
||||
]
|
||||
};
|
||||
```
|
||||
|
||||
### lib/tasks/active_admin.rake
|
||||
```ruby
|
||||
namespace :active_admin do
|
||||
desc "Build Active Admin Tailwind stylesheets"
|
||||
task build: :environment do
|
||||
command = [
|
||||
"npx", "tailwindcss",
|
||||
"-i", Rails.root.join("app/assets/stylesheets/active_admin.css").to_s,
|
||||
"-o", Rails.root.join("app/assets/builds/active_admin.css").to_s,
|
||||
"-c", Rails.root.join("tailwind.config.js").to_s,
|
||||
"-m"
|
||||
]
|
||||
|
||||
system(*command, exception: true)
|
||||
end
|
||||
|
||||
desc "Watch Active Admin Tailwind stylesheets"
|
||||
task watch: :environment do
|
||||
command = [
|
||||
"npx", "tailwindcss",
|
||||
"--watch",
|
||||
"-i", Rails.root.join("app/assets/stylesheets/active_admin.css").to_s,
|
||||
"-o", Rails.root.join("app/assets/builds/active_admin.css").to_s,
|
||||
"-c", Rails.root.join("tailwind.config.js").to_s,
|
||||
"-m"
|
||||
]
|
||||
|
||||
system(*command)
|
||||
end
|
||||
end
|
||||
|
||||
Rake::Task["assets:precompile"].enhance(["active_admin:build"])
|
||||
|
||||
Rake::Task["test:prepare"].enhance(["active_admin:build"]) if Rake::Task.task_defined?("test:prepare")
|
||||
Rake::Task["spec:prepare"].enhance(["active_admin:build"]) if Rake::Task.task_defined?("spec:prepare")
|
||||
Rake::Task["db:test:prepare"].enhance(["active_admin:build"]) if Rake::Task.task_defined?("db:test:prepare")
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
```ruby
|
||||
# app/admin/posts.rb
|
||||
ActiveAdmin.register Post do
|
||||
permit_params :title, :content, :description
|
||||
|
||||
form do |f|
|
||||
f.inputs do
|
||||
f.input :title
|
||||
f.input :content, as: :quill_editor
|
||||
f.input :description, as: :quill_editor, input_html: {
|
||||
data: {
|
||||
options: {
|
||||
theme: 'snow',
|
||||
modules: {
|
||||
toolbar: [
|
||||
['bold', 'italic', 'underline'],
|
||||
['link', 'image'],
|
||||
[{ list: 'ordered' }, { list: 'bullet' }]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
f.actions
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
### Custom Toolbar Configuration
|
||||
```ruby
|
||||
f.input :content, as: :quill_editor, input_html: {
|
||||
data: {
|
||||
options: {
|
||||
theme: 'snow', # or 'bubble'
|
||||
modules: {
|
||||
toolbar: [
|
||||
[{ 'header': [1, 2, 3, false] }],
|
||||
['bold', 'italic', 'underline', 'strike'],
|
||||
[{ 'color': [] }, { 'background': [] }],
|
||||
[{ 'script': 'sub' }, { 'script': 'super' }],
|
||||
['blockquote', 'code-block'],
|
||||
[{ 'list': 'ordered' }, { 'list': 'bullet' }],
|
||||
[{ 'align': [] }],
|
||||
['link', 'image', 'video'],
|
||||
['clean']
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Image Upload Support (Optional)
|
||||
```bash
|
||||
npm install quill-image-uploader
|
||||
```
|
||||
|
||||
Configure in your form:
|
||||
```ruby
|
||||
f.input :content, as: :quill_editor, input_html: {
|
||||
data: {
|
||||
plugins: {
|
||||
image_uploader: {
|
||||
server_url: '/admin/upload',
|
||||
field_name: 'file'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## JavaScript API
|
||||
|
||||
The gem exposes these global functions:
|
||||
|
||||
```javascript
|
||||
// Get all Quill editor instances
|
||||
const editors = getQuillEditors();
|
||||
|
||||
// Get editor by index (0-based)
|
||||
const firstEditor = getQuillEditorByIndex(0);
|
||||
|
||||
// Get editor by element ID
|
||||
const editor = getQuillEditorByElementId('post_content');
|
||||
|
||||
// Access Quill API directly
|
||||
editor.getContents();
|
||||
editor.setText('New content');
|
||||
editor.format('bold', true);
|
||||
```
|
||||
|
||||
## Migration from Legacy Versions
|
||||
|
||||
### Removing jQuery Dependencies
|
||||
|
||||
**Old initialization (jQuery)**:
|
||||
```javascript
|
||||
$(document).ready(function() {
|
||||
// Initialization code
|
||||
});
|
||||
```
|
||||
|
||||
**New initialization (Vanilla JS)**:
|
||||
```javascript
|
||||
// Automatically handled by the gem
|
||||
// Or manually initialize:
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Custom initialization if needed
|
||||
});
|
||||
```
|
||||
|
||||
### Asset Pipeline Changes
|
||||
|
||||
**Old (Sprockets)**:
|
||||
```javascript
|
||||
//= require activeadmin/quill_editor/quill
|
||||
//= require activeadmin/quill_editor_input
|
||||
```
|
||||
|
||||
**New (Propshaft/esbuild)**:
|
||||
```javascript
|
||||
import Quill from 'quill';
|
||||
// Gem's initialization auto-loads
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Issue: Quill not initializing
|
||||
**Solution**: Ensure JavaScript is properly included:
|
||||
- Check that `window.Quill` is defined
|
||||
- Verify the gem's JS is loaded after Quill
|
||||
- Check browser console for errors
|
||||
|
||||
### Issue: Styles not loading
|
||||
**Solution**: Verify CSS imports:
|
||||
- Ensure Quill CSS is imported
|
||||
- Check that Tailwind processes the styles
|
||||
- Verify no CSS conflicts with ActiveAdmin
|
||||
|
||||
### Issue: Form submission not saving content
|
||||
**Solution**: The gem automatically handles form submission. Check:
|
||||
- Hidden input field is present in HTML
|
||||
- No JavaScript errors preventing update
|
||||
- Strong parameters permit the field
|
||||
|
||||
## Testing Your Implementation
|
||||
|
||||
### RSpec System Tests
|
||||
```ruby
|
||||
# spec/system/admin_posts_spec.rb
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Admin Posts', type: :system do
|
||||
it 'creates a post with Quill editor' do
|
||||
visit '/admin/posts/new'
|
||||
|
||||
# Fill in Quill editor
|
||||
within '[data-aa-quill-editor]' do
|
||||
find('.ql-editor').set('Test content')
|
||||
end
|
||||
|
||||
click_button 'Create Post'
|
||||
|
||||
expect(page).to have_content('Post was successfully created')
|
||||
expect(Post.last.content).to include('Test content')
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
## Version Compatibility Matrix
|
||||
|
||||
| Gem Version | ActiveAdmin | Rails | Ruby | Quill |
|
||||
|-------------|-------------|-------|------|-------|
|
||||
| 2.0.x | 2.9-4.x | 7.0-8.x | 3.2+ | 2.x |
|
||||
| 1.x | 2.x-3.x | 6.1-7.x | 3.0+ | 1.x |
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Quill Documentation](https://quilljs.com/)
|
||||
- [ActiveAdmin 4 Migration Guide](https://github.com/activeadmin/activeadmin/wiki)
|
||||
- [Propshaft Documentation](https://github.com/rails/propshaft)
|
||||
- [Rails 8 Asset Pipeline Guide](https://guides.rubyonrails.org/asset_pipeline.html)
|
||||
|
||||
## Support
|
||||
|
||||
For issues or questions:
|
||||
- GitHub Issues: https://github.com/rs-pro/activeadmin-quill_editor/issues
|
||||
- ActiveAdmin Community: https://github.com/activeadmin/activeadmin/discussions
|
||||
73
examples/upload_plugin_using_activestorage/app/admin/posts.rb
Обычный файл
73
examples/upload_plugin_using_activestorage/app/admin/posts.rb
Обычный файл
@@ -0,0 +1,73 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
ActiveAdmin.register Post do
|
||||
permit_params :author_id,
|
||||
:title,
|
||||
:description,
|
||||
:category,
|
||||
:dt,
|
||||
:position,
|
||||
:published,
|
||||
tag_ids: []
|
||||
|
||||
member_action :upload, method: [:post] do
|
||||
result = { success: resource.images.attach(params[:file_upload]) }
|
||||
result[:url] = url_for(resource.images.last) if result[:success]
|
||||
render json: result
|
||||
end
|
||||
|
||||
index do
|
||||
selectable_column
|
||||
id_column
|
||||
column :title
|
||||
column :author
|
||||
column :published
|
||||
column :created_at
|
||||
actions
|
||||
end
|
||||
|
||||
show do
|
||||
attributes_table do
|
||||
row :author
|
||||
row :title
|
||||
row :description
|
||||
row :category
|
||||
row :dt
|
||||
row :position
|
||||
row :published
|
||||
row :tags
|
||||
row :created_at
|
||||
row :updated_at
|
||||
row :images do |resurce|
|
||||
resurce.images.each do |image|
|
||||
div do
|
||||
link_to image.filename, image, target: '_blank', rel: 'noopener'
|
||||
end
|
||||
end
|
||||
nil
|
||||
end
|
||||
end
|
||||
active_admin_comments
|
||||
end
|
||||
|
||||
form do |f|
|
||||
f.inputs 'Post' do
|
||||
f.input :author
|
||||
f.input :title
|
||||
unless object.new_record?
|
||||
plugin_opts = { image_uploader: { server_url: upload_admin_post_path(object.id), field_name: 'file_upload' } }
|
||||
f.input :description, as: :quill_editor, input_html: { data: { plugins: plugin_opts } }
|
||||
end
|
||||
f.input :category
|
||||
f.input :dt
|
||||
f.input :position
|
||||
f.input :published
|
||||
end
|
||||
|
||||
f.inputs 'Tags' do
|
||||
f.input :tags
|
||||
end
|
||||
|
||||
f.actions
|
||||
end
|
||||
end
|
||||
@@ -2,3 +2,5 @@
|
||||
|
||||
//= require activeadmin/quill_editor/quill
|
||||
//= require activeadmin/quill_editor_input
|
||||
|
||||
//= require activeadmin/quill.imageUploader.min
|
||||
@@ -0,0 +1,7 @@
|
||||
@import 'active_admin/mixins';
|
||||
@import 'active_admin/base';
|
||||
|
||||
@import 'activeadmin/quill_editor/quill.snow';
|
||||
@import 'activeadmin/quill_editor_input';
|
||||
|
||||
@import 'activeadmin/quill.imageUploader.min';
|
||||
@@ -0,0 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Post < ApplicationRecord
|
||||
has_many_attached :images
|
||||
|
||||
validates :title, allow_blank: false, presence: true
|
||||
end
|
||||
3
extra/.bashrc
Обычный файл
3
extra/.bashrc
Обычный файл
@@ -0,0 +1,3 @@
|
||||
alias ls='ls --color'
|
||||
alias ll='ls -l'
|
||||
alias la='ls -la'
|
||||
7
extra/.env
Обычный файл
7
extra/.env
Обычный файл
@@ -0,0 +1,7 @@
|
||||
COMPOSE_PROJECT_NAME=activeadmin_quill_editor
|
||||
|
||||
BUNDLER_VERSION=2.5.23
|
||||
SERVER_PORT=4000
|
||||
|
||||
UID=1000
|
||||
GID=1000
|
||||
31
extra/Dockerfile
Обычный файл
31
extra/Dockerfile
Обычный файл
@@ -0,0 +1,31 @@
|
||||
ARG RUBY_IMAGE=ruby:3
|
||||
FROM ${RUBY_IMAGE}
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV DEVEL=1
|
||||
ENV LANG=C.UTF-8
|
||||
|
||||
RUN apt-get update -qq
|
||||
RUN apt-get install -yqq --no-install-recommends build-essential chromium less libyaml-dev nano netcat-traditional pkg-config
|
||||
|
||||
ARG BUNDLER_VERSION
|
||||
RUN gem install bundler -v ${BUNDLER_VERSION}
|
||||
RUN echo 'gem: --no-document' > /etc/gemrc
|
||||
|
||||
ARG UID
|
||||
RUN useradd -u $UID --shell /bin/bash app
|
||||
|
||||
RUN mkdir -p /home/app && chown -R app:app /home/app
|
||||
|
||||
ARG RAILS_VERSION
|
||||
ENV RAILS_VERSION=$RAILS_VERSION
|
||||
|
||||
ARG ACTIVEADMIN_VERSION
|
||||
ENV ACTIVEADMIN_VERSION=$ACTIVEADMIN_VERSION
|
||||
|
||||
WORKDIR /app
|
||||
COPY . /app
|
||||
RUN bundle install
|
||||
RUN chown -R app:app /usr/local/bundle
|
||||
|
||||
RUN ln -s /app/extra/.bashrc /home/app/.bashrc
|
||||
6
extra/Dockerfile.dockerignore
Обычный файл
6
extra/Dockerfile.dockerignore
Обычный файл
@@ -0,0 +1,6 @@
|
||||
# Ignore everything but the required files for bundle install
|
||||
/**/*
|
||||
|
||||
!/*.gemspec
|
||||
!/Gemfile
|
||||
!/lib
|
||||
6
extra/dev_setup.sh
Исполняемый файл
6
extra/dev_setup.sh
Исполняемый файл
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
export DEVEL=1
|
||||
|
||||
export RAILS_VERSION=7.2.2.1
|
||||
export ACTIVEADMIN_VERSION=3.3.0
|
||||
50
extra/development.md
Обычный файл
50
extra/development.md
Обычный файл
@@ -0,0 +1,50 @@
|
||||
## Development
|
||||
|
||||
### Dev setup
|
||||
|
||||
There are 2 ways to interact with this project:
|
||||
|
||||
1) Using Docker:
|
||||
|
||||
```sh
|
||||
make up # starts the dev services (optional env vars: RUBY / RAILS / ACTIVEADMIN)
|
||||
make specs # run the tests (after up)
|
||||
make lint # run the linters (after up)
|
||||
make server # run the server (after up)
|
||||
make shell # open a shell (after up)
|
||||
make down # cleanup (after up)
|
||||
|
||||
# Example using specific versions:
|
||||
RUBY=3.2 RAILS=7.1 ACTIVEADMIN=3.2.0 make up
|
||||
```
|
||||
|
||||
2) With a local setup:
|
||||
|
||||
```sh
|
||||
# Dev setup (set the required envs):
|
||||
source extra/dev_setup.sh
|
||||
# Install dependencies:
|
||||
bundle update
|
||||
# Run server (or any command):
|
||||
bin/rails s
|
||||
# To try different versions of Rails/ActiveAdmin edit extra/dev_setup.sh
|
||||
```
|
||||
|
||||
### Update the editor
|
||||
|
||||
- Update the CSS/JS editor assets:
|
||||
|
||||
```sh
|
||||
wget "https://cdn.jsdelivr.net/npm/quill@2/dist/quill.snow.css" -O "app/assets/stylesheets/activeadmin/quill_editor/quill.snow.css"
|
||||
wget "https://cdn.jsdelivr.net/npm/quill@2/dist/quill.bubble.css" -O "app/assets/stylesheets/activeadmin/quill_editor/quill.bubble.css"
|
||||
wget "https://cdn.jsdelivr.net/npm/quill@2/dist/quill.core.css" -O "app/assets/stylesheets/activeadmin/quill_editor/quill.core.css"
|
||||
|
||||
wget "https://cdn.jsdelivr.net/npm/quill@2/dist/quill.js" -O "app/assets/javascripts/activeadmin/quill_editor/quill.js"
|
||||
wget "https://cdn.jsdelivr.net/npm/quill@2/dist/quill.core.js" -O "app/assets/javascripts/activeadmin/quill_editor/quill.core.js"
|
||||
|
||||
wget "https://github.com/valentsea/quill2-image-uploader/raw/refs/heads/master/dist/quill.imageUploader.min.js" -O "app/assets/javascripts/activeadmin/quill.imageUploader.min.js"
|
||||
|
||||
wget "https://github.com/valentsea/quill2-image-uploader/raw/refs/heads/master/dist/quill.imageUploader.min.css" -O "app/assets/stylesheets/activeadmin/quill.imageUploader.min.css"
|
||||
```
|
||||
|
||||
- Check the changes, most of them should be for updated files plus some new / removed file
|
||||
19
extra/docker-compose.yml
Обычный файл
19
extra/docker-compose.yml
Обычный файл
@@ -0,0 +1,19 @@
|
||||
services:
|
||||
app:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: extra/Dockerfile
|
||||
args:
|
||||
BUNDLER_VERSION: ${BUNDLER_VERSION}
|
||||
RUBY_IMAGE: ruby:${RUBY:-3.4}-slim
|
||||
RAILS_VERSION: ${RAILS:-}
|
||||
ACTIVEADMIN_VERSION: ${ACTIVEADMIN:-}
|
||||
UID: ${UID}
|
||||
user: ${UID}:${GID}
|
||||
ports:
|
||||
- ${SERVER_PORT}:${SERVER_PORT}
|
||||
working_dir: /app
|
||||
volumes:
|
||||
- ..:/app
|
||||
stdin_open: true
|
||||
tty: true
|
||||
|
До Ширина: | Высота: | Размер: 52 KiB После Ширина: | Высота: | Размер: 52 KiB |
2
gemfiles/.bundle/config
Обычный файл
2
gemfiles/.bundle/config
Обычный файл
@@ -0,0 +1,2 @@
|
||||
---
|
||||
BUNDLE_RETRY: "1"
|
||||
32
gemfiles/rails_7.2_active_admin_4.x.gemfile
Обычный файл
32
gemfiles/rails_7.2_active_admin_4.x.gemfile
Обычный файл
@@ -0,0 +1,32 @@
|
||||
# This file was generated by Appraisal
|
||||
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem "rails", "~> 7.2.0"
|
||||
gem "activeadmin", "4.0.0.beta20"
|
||||
gem "sqlite3"
|
||||
gem "concurrent-ruby", "1.3.4"
|
||||
gem "bigdecimal"
|
||||
gem "csv"
|
||||
gem "mutex_m"
|
||||
gem "puma"
|
||||
gem "importmap-rails"
|
||||
gem "propshaft"
|
||||
gem "capybara"
|
||||
gem "cuprite"
|
||||
gem "rspec_junit_formatter"
|
||||
gem "rspec-rails"
|
||||
gem "simplecov", require: false
|
||||
gem "super_diff"
|
||||
gem "fasterer"
|
||||
gem "rubocop"
|
||||
gem "rubocop-capybara"
|
||||
gem "rubocop-packaging"
|
||||
gem "rubocop-performance"
|
||||
gem "rubocop-rails"
|
||||
gem "rubocop-rspec"
|
||||
gem "rubocop-rspec_rails"
|
||||
gem "appraisal"
|
||||
gem "pry-rails"
|
||||
|
||||
gemspec path: "../"
|
||||
32
gemfiles/rails_8.0_active_admin_4.x.gemfile
Обычный файл
32
gemfiles/rails_8.0_active_admin_4.x.gemfile
Обычный файл
@@ -0,0 +1,32 @@
|
||||
# This file was generated by Appraisal
|
||||
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem "rails", "~> 8.0.0"
|
||||
gem "activeadmin", "4.0.0.beta20"
|
||||
gem "sqlite3"
|
||||
gem "concurrent-ruby", "1.3.4"
|
||||
gem "bigdecimal"
|
||||
gem "csv"
|
||||
gem "mutex_m"
|
||||
gem "puma"
|
||||
gem "importmap-rails"
|
||||
gem "propshaft"
|
||||
gem "capybara"
|
||||
gem "cuprite"
|
||||
gem "rspec_junit_formatter"
|
||||
gem "rspec-rails"
|
||||
gem "simplecov", require: false
|
||||
gem "super_diff"
|
||||
gem "fasterer"
|
||||
gem "rubocop"
|
||||
gem "rubocop-capybara"
|
||||
gem "rubocop-packaging"
|
||||
gem "rubocop-performance"
|
||||
gem "rubocop-rails"
|
||||
gem "rubocop-rspec"
|
||||
gem "rubocop-rspec_rails"
|
||||
gem "appraisal"
|
||||
gem "pry-rails"
|
||||
|
||||
gemspec path: "../"
|
||||
7
index.js
Обычный файл
7
index.js
Обычный файл
@@ -0,0 +1,7 @@
|
||||
// Styles
|
||||
import 'activeadmin_quill_editor/app/assets/stylesheets/activeadmin/quill_editor/quill.snow'
|
||||
import 'activeadmin_quill_editor/app/assets/stylesheets/activeadmin/_quill_editor_input'
|
||||
|
||||
// JS
|
||||
window.Quill = require('activeadmin_quill_editor/app/assets/javascripts/activeadmin/quill_editor/quill')
|
||||
require('activeadmin_quill_editor/app/assets/javascripts/activeadmin/quill_editor_input')
|
||||
@@ -1,3 +1,4 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'activeadmin/quill_editor/engine'
|
||||
require 'formtastic/inputs/quill_editor_input'
|
||||
|
||||
@@ -6,6 +6,24 @@ module ActiveAdmin
|
||||
module QuillEditor
|
||||
class Engine < ::Rails::Engine
|
||||
engine_name 'activeadmin_quill_editor'
|
||||
|
||||
# Propshaft automatically includes vendor/assets and app/assets paths
|
||||
# No need for explicit asset path configuration with Propshaft
|
||||
|
||||
initializer 'activeadmin_quill_editor.assets' do |app|
|
||||
# Add assets to precompile list for both Propshaft and Sprockets
|
||||
if app.config.respond_to?(:assets)
|
||||
app.config.assets.precompile += %w[
|
||||
activeadmin/quill_editor.js
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
initializer 'activeadmin_quill_editor.formtastic' do
|
||||
ActiveSupport.on_load :active_admin do
|
||||
require 'formtastic/inputs/quill_editor_input'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
module ActiveAdmin
|
||||
module QuillEditor
|
||||
VERSION = '0.2.8'
|
||||
VERSION = '2.1.0'
|
||||
QUILL_VERSION = '2.0.3'
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,9 +6,9 @@ module Formtastic
|
||||
def to_html
|
||||
input_wrapping do
|
||||
label_html <<
|
||||
template.content_tag(:div, input_html_options.merge(class: 'quill-editor')) do
|
||||
template.content_tag(:div, input_html_options.merge('data-aa-quill-editor': '1')) do
|
||||
builder.hidden_field(input_name) <<
|
||||
template.content_tag(:div, class: 'quill-editor-content') do
|
||||
template.content_tag(:div, 'data-aa-quill-content': '1') do
|
||||
object.send(method).try :html_safe
|
||||
end
|
||||
end
|
||||
|
||||
18
package.json
Обычный файл
18
package.json
Обычный файл
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "activeadmin_quill_editor",
|
||||
"version": "2.0.0",
|
||||
"description": "Quill Editor for ActiveAdmin",
|
||||
"author": "Mattia Roccoberton <mat@blocknot.es>",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/blocknotes/activeadmin_quill_editor",
|
||||
"main": "index.js",
|
||||
"files": [
|
||||
"app/**/*",
|
||||
"index.js"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.22.0",
|
||||
"eslint": "^9.22.0",
|
||||
"globals": "^16.0.0"
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
ruby-2.7.1
|
||||
@@ -1 +0,0 @@
|
||||
ruby 2.6.6
|
||||
@@ -33,7 +33,7 @@ ActiveAdmin.register Author do
|
||||
row :profile
|
||||
row :posts
|
||||
end
|
||||
active_admin_comments
|
||||
active_admin_comments_for(resource) if active_admin_config.comments?
|
||||
end
|
||||
|
||||
form do |f|
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
ActiveAdmin.register Post do
|
||||
permit_params :author_id, :title, :description, :category, :dt, :position, :published, tag_ids: []
|
||||
permit_params :author_id, :title, :summary, :description, :category, :dt, :position, :published, tag_ids: []
|
||||
|
||||
member_action :upload, method: [:post] do
|
||||
result = { success: resource.images.attach(params[:file_upload]) }
|
||||
result[:url] = url_for(resource.images.last) if result[:success]
|
||||
render json: result
|
||||
end
|
||||
|
||||
index do
|
||||
selectable_column
|
||||
@@ -17,6 +23,7 @@ ActiveAdmin.register Post do
|
||||
attributes_table do
|
||||
row :author
|
||||
row :title
|
||||
row :summary
|
||||
row :description
|
||||
row :category
|
||||
row :dt
|
||||
@@ -34,14 +41,21 @@ ActiveAdmin.register Post do
|
||||
nil
|
||||
end
|
||||
end
|
||||
active_admin_comments
|
||||
active_admin_comments_for(resource) if active_admin_config.comments?
|
||||
end
|
||||
|
||||
form do |f|
|
||||
toolbar = %w[bold italic underline link]
|
||||
f.inputs 'Post' do
|
||||
f.input :author
|
||||
f.input :title
|
||||
f.input :description, as: :quill_editor
|
||||
f.input :summary, as: :quill_editor, input_html: { data: { options: { modules: { toolbar: toolbar } } } }
|
||||
if object.new_record?
|
||||
f.input :description, as: :quill_editor # using default options
|
||||
else
|
||||
plugin_opts = { image_uploader: { server_url: upload_admin_post_path(object.id), field_name: 'file_upload' } }
|
||||
f.input :description, as: :quill_editor, input_html: { data: { plugins: plugin_opts } }
|
||||
end
|
||||
f.input :category
|
||||
f.input :dt
|
||||
f.input :position
|
||||
|
||||
5
spec/dummy/app/admin/profiles.rb
Обычный файл
5
spec/dummy/app/admin/profiles.rb
Обычный файл
@@ -0,0 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
ActiveAdmin.register Profile do
|
||||
permit_params :author_id, :description
|
||||
end
|
||||
@@ -1,4 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
ActiveAdmin.register Tag do
|
||||
permit_params :name
|
||||
end
|
||||
|
||||
16
spec/dummy/app/assets/builds/active_admin.css
Обычный файл
16
spec/dummy/app/assets/builds/active_admin.css
Обычный файл
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
1
spec/dummy/app/assets/builds/active_admin.css.map
Обычный файл
1
spec/dummy/app/assets/builds/active_admin.css.map
Обычный файл
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
17146
spec/dummy/app/assets/builds/active_admin.js
Обычный файл
17146
spec/dummy/app/assets/builds/active_admin.js
Обычный файл
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
7
spec/dummy/app/assets/builds/active_admin.js.map
Обычный файл
7
spec/dummy/app/assets/builds/active_admin.js.map
Обычный файл
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
@@ -1,3 +1,7 @@
|
||||
//= link_tree ../images
|
||||
//= link_directory ../stylesheets .css
|
||||
//= link_directory ../javascripts .js
|
||||
//= link active_admin.css
|
||||
//= link active_admin.js
|
||||
//= link activeadmin_quill_editor.js
|
||||
//= link application.css
|
||||
// OFF link active_storage_db_manifest.js
|
||||
|
||||
6
spec/dummy/app/assets/javascripts/active_admin_legacy.js.bak
Обычный файл
6
spec/dummy/app/assets/javascripts/active_admin_legacy.js.bak
Обычный файл
@@ -0,0 +1,6 @@
|
||||
//= require active_admin/base
|
||||
|
||||
//= require activeadmin/quill_editor/quill
|
||||
//= require activeadmin/quill_editor_input
|
||||
|
||||
//= require activeadmin/quill.imageUploader.min
|
||||
2
spec/dummy/app/assets/javascripts/application.js
Обычный файл
2
spec/dummy/app/assets/javascripts/application.js
Обычный файл
@@ -0,0 +1,2 @@
|
||||
//= require_tree ../builds
|
||||
//= require activeadmin_quill_editor
|
||||
73
spec/dummy/app/assets/stylesheets/active_admin.css
Обычный файл
73
spec/dummy/app/assets/stylesheets/active_admin.css
Обычный файл
@@ -0,0 +1,73 @@
|
||||
@import "tailwindcss/base";
|
||||
@import "tailwindcss/components";
|
||||
@import "tailwindcss/utilities";
|
||||
|
||||
/* Import Quill styles */
|
||||
@import "../../../node_modules/quill/dist/quill.snow.css";
|
||||
@import "../../../node_modules/quill/dist/quill.bubble.css";
|
||||
|
||||
/* Custom Quill integration styles for ActiveAdmin */
|
||||
@layer components {
|
||||
.quill-editor {
|
||||
@apply border border-gray-300 rounded-md;
|
||||
}
|
||||
|
||||
.ql-toolbar {
|
||||
@apply border-b-0 rounded-t-md;
|
||||
}
|
||||
|
||||
.ql-container {
|
||||
@apply border border-gray-300 rounded-b-md;
|
||||
}
|
||||
|
||||
.ql-editor {
|
||||
@apply min-h-[200px];
|
||||
}
|
||||
|
||||
/* Dark mode support */
|
||||
.dark .quill-editor {
|
||||
@apply border-gray-600;
|
||||
}
|
||||
|
||||
.dark .ql-toolbar {
|
||||
@apply bg-gray-800 border-gray-600;
|
||||
}
|
||||
|
||||
.dark .ql-container {
|
||||
@apply bg-gray-900 border-gray-600;
|
||||
}
|
||||
|
||||
.dark .ql-editor {
|
||||
@apply text-gray-100;
|
||||
}
|
||||
|
||||
/* Fix toolbar button styles */
|
||||
.ql-toolbar button:hover {
|
||||
@apply bg-gray-100 dark:bg-gray-700;
|
||||
}
|
||||
|
||||
/* Ensure icons are visible in dark mode */
|
||||
.dark .ql-toolbar button svg {
|
||||
@apply text-gray-300;
|
||||
}
|
||||
|
||||
.dark .ql-toolbar button:hover svg {
|
||||
@apply text-white;
|
||||
}
|
||||
|
||||
.dark .ql-toolbar .ql-stroke {
|
||||
stroke: #9ca3af !important;
|
||||
}
|
||||
|
||||
.dark .ql-toolbar .ql-fill {
|
||||
fill: #9ca3af !important;
|
||||
}
|
||||
|
||||
.dark .ql-toolbar button:hover .ql-stroke {
|
||||
stroke: white !important;
|
||||
}
|
||||
|
||||
.dark .ql-toolbar button:hover .ql-fill {
|
||||
fill: white !important;
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,8 @@
|
||||
@import 'activeadmin/quill_editor/quill.snow';
|
||||
@import 'activeadmin/quill_editor_input';
|
||||
|
||||
@import 'activeadmin/quill.imageUploader.min';
|
||||
|
||||
// Overriding any non-variable SASS must be done after the fact.
|
||||
// For example, to change the default status-tag color:
|
||||
//
|
||||
26
spec/dummy/app/javascript/active_admin.js
Обычный файл
26
spec/dummy/app/javascript/active_admin.js
Обычный файл
@@ -0,0 +1,26 @@
|
||||
// Import ActiveAdmin - this already includes all features and Rails UJS
|
||||
// DO NOT import Rails separately as it's already included and started in ActiveAdmin
|
||||
import '@activeadmin/activeadmin';
|
||||
|
||||
// Import Quill from NPM and make it globally available
|
||||
import Quill from 'quill';
|
||||
window.Quill = Quill;
|
||||
|
||||
// Import the image uploader plugin if available (optional)
|
||||
try {
|
||||
const ImageUploader = require('quill-image-uploader');
|
||||
window.ImageUploader = ImageUploader.default || ImageUploader;
|
||||
} catch(e) {
|
||||
// Image uploader is optional (silent failure)
|
||||
}
|
||||
|
||||
// Import the Quill Editor initialization module
|
||||
import QuillEditorModule from 'activeadmin/quill_editor';
|
||||
|
||||
// Now that Quill is available, initialize the editors
|
||||
// This ensures proper initialization order without setTimeout hacks
|
||||
if (window.QuillEditor && window.QuillEditor.init) {
|
||||
window.QuillEditor.init();
|
||||
} else if (QuillEditorModule && QuillEditorModule.init) {
|
||||
QuillEditorModule.init();
|
||||
}
|
||||
@@ -23,4 +23,10 @@ class Author < ApplicationRecord
|
||||
def to_s
|
||||
"#{name} (#{age})"
|
||||
end
|
||||
|
||||
class << self
|
||||
def ransackable_attributes(_auth_object = nil)
|
||||
%w[age created_at email id name updated_at]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Post < ApplicationRecord
|
||||
enum state: %i[available unavailable arriving]
|
||||
|
||||
belongs_to :author, inverse_of: :posts, autosave: true
|
||||
|
||||
has_one :author_profile, through: :author, source: :profile
|
||||
@@ -26,4 +24,14 @@ class Post < ApplicationRecord
|
||||
def upper_title
|
||||
title.upcase
|
||||
end
|
||||
|
||||
class << self
|
||||
def ransackable_associations(_auth_object = nil)
|
||||
%w[author author_profile post_tags tags images_attachments images_blobs]
|
||||
end
|
||||
|
||||
def ransackable_attributes(_auth_object = nil)
|
||||
%w[author_id category created_at description dt id position published title summary updated_at]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,4 +6,10 @@ class PostTag < ApplicationRecord
|
||||
|
||||
validates :post, presence: true
|
||||
validates :tag, presence: true
|
||||
|
||||
class << self
|
||||
def ransackable_attributes(auth_object = nil)
|
||||
%w[created_at id post_id tag_id updated_at]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,4 +6,14 @@ class Profile < ApplicationRecord
|
||||
def to_s
|
||||
description
|
||||
end
|
||||
|
||||
class << self
|
||||
def ransackable_associations(_auth_object = nil)
|
||||
%w[author]
|
||||
end
|
||||
|
||||
def ransackable_attributes(_auth_object = nil)
|
||||
%w[author_id created_at description id updated_at]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,4 +3,14 @@
|
||||
class Tag < ApplicationRecord
|
||||
has_many :post_tags, inverse_of: :tag, dependent: :destroy
|
||||
has_many :posts, through: :post_tags
|
||||
|
||||
class << self
|
||||
def ransackable_associations(auth_object = nil)
|
||||
%w[post_tags posts]
|
||||
end
|
||||
|
||||
def ransackable_attributes(auth_object = nil)
|
||||
%w[created_at id id_value name updated_at]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<%= csp_meta_tag %>
|
||||
|
||||
<%= stylesheet_link_tag 'application', media: 'all' %>
|
||||
<%= javascript_include_tag 'application', 'data-turbo-track': 'reload', defer: true %>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@@ -6,13 +6,18 @@ Bundler.require(*Rails.groups)
|
||||
|
||||
module Dummy
|
||||
class Application < Rails::Application
|
||||
# Initialize configuration defaults for originally generated Rails version.
|
||||
config.load_defaults 6.0
|
||||
config.load_defaults Rails::VERSION::STRING.to_f
|
||||
|
||||
# Settings in config/environments/* take precedence over those specified here.
|
||||
# Application configuration can go into files in config/initializers
|
||||
# -- all .rb files in that directory are automatically loaded after loading
|
||||
# the framework and any gems in your application.
|
||||
config.active_support.deprecation = :raise
|
||||
|
||||
if Gem::Version.new(Rails.version) < Gem::Version.new('7.1')
|
||||
config.active_record.legacy_connection_handling = false
|
||||
end
|
||||
|
||||
if Gem::Version.new(Rails.version) > Gem::Version.new('7.0')
|
||||
config.before_configuration do
|
||||
ActiveSupport::Cache.format_version = 7.0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -3,6 +3,11 @@ default: &default
|
||||
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
|
||||
timeout: 5000
|
||||
|
||||
development:
|
||||
<<: *default
|
||||
database: db/development.sqlite3
|
||||
schema_dump: schema-dev.rb
|
||||
|
||||
test:
|
||||
<<: *default
|
||||
database: db/test.sqlite3
|
||||
|
||||
@@ -59,4 +59,8 @@ Rails.application.configure do
|
||||
# Use an evented file watcher to asynchronously detect changes in source code,
|
||||
# routes, locales, etc. This feature depends on the listen gem.
|
||||
# config.file_watcher = ActiveSupport::EventedFileUpdateChecker
|
||||
|
||||
###
|
||||
|
||||
config.active_support.to_time_preserves_timezone = :zone if Gem::Version.new(Rails.version) >= Gem::Version.new('8.0')
|
||||
end
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
Rails.application.configure do
|
||||
# Settings specified here will take precedence over those in config/application.rb.
|
||||
|
||||
# Code is not reloaded between requests.
|
||||
config.cache_classes = true
|
||||
|
||||
# Eager load code on boot. This eager loads most of Rails and
|
||||
# your application in memory, allowing both threaded web servers
|
||||
# and those relying on copy on write to perform better.
|
||||
# Rake tasks automatically ignore this option for performance.
|
||||
config.eager_load = true
|
||||
|
||||
# Full error reports are disabled and caching is turned on.
|
||||
config.consider_all_requests_local = false
|
||||
config.action_controller.perform_caching = true
|
||||
|
||||
# Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
|
||||
# or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
|
||||
# config.require_master_key = true
|
||||
|
||||
# Disable serving static files from the `/public` folder by default since
|
||||
# Apache or NGINX already handles this.
|
||||
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
|
||||
|
||||
# Compress CSS using a preprocessor.
|
||||
# config.assets.css_compressor = :sass
|
||||
|
||||
# Do not fallback to assets pipeline if a precompiled asset is missed.
|
||||
config.assets.compile = false
|
||||
|
||||
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
|
||||
# config.action_controller.asset_host = 'http://assets.example.com'
|
||||
|
||||
# Specifies the header that your server uses for sending files.
|
||||
# config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
|
||||
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
|
||||
|
||||
# Store uploaded files on the local file system (see config/storage.yml for options).
|
||||
config.active_storage.service = :local
|
||||
|
||||
# Mount Action Cable outside main process or domain.
|
||||
# config.action_cable.mount_path = nil
|
||||
# config.action_cable.url = 'wss://example.com/cable'
|
||||
# config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ]
|
||||
|
||||
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
|
||||
# config.force_ssl = true
|
||||
|
||||
# Use the lowest log level to ensure availability of diagnostic information
|
||||
# when problems arise.
|
||||
config.log_level = :debug
|
||||
|
||||
# Prepend all log lines with the following tags.
|
||||
config.log_tags = [ :request_id ]
|
||||
|
||||
# Use a different cache store in production.
|
||||
# config.cache_store = :mem_cache_store
|
||||
|
||||
# Use a real queuing backend for Active Job (and separate queues per environment).
|
||||
# config.active_job.queue_adapter = :resque
|
||||
# config.active_job.queue_name_prefix = "dummy_production"
|
||||
|
||||
# config.action_mailer.perform_caching = false
|
||||
|
||||
# Ignore bad email addresses and do not raise email delivery errors.
|
||||
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
|
||||
# config.action_mailer.raise_delivery_errors = false
|
||||
|
||||
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
|
||||
# the I18n.default_locale when a translation cannot be found).
|
||||
config.i18n.fallbacks = true
|
||||
|
||||
# Send deprecation notices to registered listeners.
|
||||
config.active_support.deprecation = :notify
|
||||
|
||||
# Use default logging formatter so that PID and timestamp are not suppressed.
|
||||
config.log_formatter = ::Logger::Formatter.new
|
||||
|
||||
# Use a different logger for distributed setups.
|
||||
# require 'syslog/logger'
|
||||
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
|
||||
|
||||
if ENV["RAILS_LOG_TO_STDOUT"].present?
|
||||
logger = ActiveSupport::Logger.new(STDOUT)
|
||||
logger.formatter = config.log_formatter
|
||||
config.logger = ActiveSupport::TaggedLogging.new(logger)
|
||||
end
|
||||
|
||||
# Do not dump schema after migrations.
|
||||
config.active_record.dump_schema_after_migration = false
|
||||
|
||||
# Inserts middleware to perform automatic connection switching.
|
||||
# The `database_selector` hash is used to pass options to the DatabaseSelector
|
||||
# middleware. The `delay` is used to determine how long to wait after a write
|
||||
# to send a subsequent read to the primary.
|
||||
#
|
||||
# The `database_resolver` class is used by the middleware to determine which
|
||||
# database is appropriate to use based on the time delay.
|
||||
#
|
||||
# The `database_resolver_context` class is used by the middleware to set
|
||||
# timestamps for the last write to the primary. The resolver uses the context
|
||||
# class timestamps to determine how long to wait before reading from the
|
||||
# replica.
|
||||
#
|
||||
# By default Rails will store a last write timestamp in the session. The
|
||||
# DatabaseSelector middleware is designed as such you can define your own
|
||||
# strategy for connection switching and pass that into the middleware through
|
||||
# these configuration options.
|
||||
# config.active_record.database_selector = { delay: 2.seconds }
|
||||
# config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
|
||||
# config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
|
||||
end
|
||||
@@ -26,7 +26,7 @@ Rails.application.configure do
|
||||
config.cache_store = :null_store
|
||||
|
||||
# Raise exceptions instead of rendering exception templates.
|
||||
config.action_dispatch.show_exceptions = false
|
||||
config.action_dispatch.show_exceptions = :none
|
||||
|
||||
# Disable request forgery protection in test environment.
|
||||
config.action_controller.allow_forgery_protection = false
|
||||
@@ -46,4 +46,8 @@ Rails.application.configure do
|
||||
|
||||
# Raises error for missing translations.
|
||||
# config.action_view.raise_on_missing_translations = true
|
||||
|
||||
###
|
||||
|
||||
config.active_support.to_time_preserves_timezone = :zone if Gem::Version.new(Rails.version) >= Gem::Version.new('8.0')
|
||||
end
|
||||
|
||||
@@ -216,6 +216,9 @@ ActiveAdmin.setup do |config|
|
||||
# To load a javascript file:
|
||||
# config.register_javascript 'my_javascript.js'
|
||||
|
||||
# ActiveAdmin 4 with Propshaft loads assets via the application layout
|
||||
# and the manifest.js file, not via register_stylesheet/register_javascript
|
||||
|
||||
# == CSV options
|
||||
#
|
||||
# Set the CSV builder separator
|
||||
|
||||
9
spec/dummy/config/initializers/active_storage.rb
Обычный файл
9
spec/dummy/config/initializers/active_storage.rb
Обычный файл
@@ -0,0 +1,9 @@
|
||||
Rails.application.reloader.to_prepare do
|
||||
ActiveStorage::Attachment.class_eval do
|
||||
class << self
|
||||
def ransackable_attributes(auth_object = nil)
|
||||
%w[blob_id created_at id name record_id record_type]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,3 +1,5 @@
|
||||
Rails.application.routes.draw do
|
||||
ActiveAdmin.routes(self)
|
||||
|
||||
root to: redirect('/admin')
|
||||
end
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
# This migration comes from active_storage (originally 20170806125915)
|
||||
class CreateActiveStorageTables < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
create_table :active_storage_blobs do |t|
|
||||
t.string :key, null: false
|
||||
t.string :filename, null: false
|
||||
t.string :content_type
|
||||
t.text :metadata
|
||||
t.bigint :byte_size, null: false
|
||||
t.string :checksum, null: false
|
||||
t.datetime :created_at, null: false
|
||||
|
||||
t.index [ :key ], unique: true
|
||||
end
|
||||
|
||||
create_table :active_storage_attachments do |t|
|
||||
t.string :name, null: false
|
||||
t.references :record, null: false, polymorphic: true, index: false
|
||||
t.references :blob, null: false
|
||||
|
||||
t.datetime :created_at, null: false
|
||||
|
||||
t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true
|
||||
t.foreign_key :active_storage_blobs, column: :blob_id
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class CreateActiveAdminComments < ActiveRecord::Migration[6.0]
|
||||
def self.up
|
||||
create_table :active_admin_comments do |t|
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
# frozen_string_literal: true
|
||||
# This migration comes from active_storage (originally 20170806125915)
|
||||
|
||||
class CreateActiveStorageTables < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
# Use Active Record's configured type for primary and foreign keys
|
||||
primary_key_type, foreign_key_type = primary_and_foreign_key_types
|
||||
|
||||
create_table :active_storage_blobs, id: primary_key_type do |t|
|
||||
t.string :key, null: false
|
||||
t.string :filename, null: false
|
||||
t.string :content_type
|
||||
t.text :metadata
|
||||
t.string :service_name, null: false
|
||||
t.bigint :byte_size, null: false
|
||||
t.string :checksum
|
||||
|
||||
if connection.supports_datetime_with_precision?
|
||||
t.datetime :created_at, precision: 6, null: false
|
||||
else
|
||||
t.datetime :created_at, null: false
|
||||
end
|
||||
|
||||
t.index [ :key ], unique: true
|
||||
end
|
||||
|
||||
create_table :active_storage_attachments, id: primary_key_type do |t|
|
||||
t.string :name, null: false
|
||||
t.references :record, null: false, polymorphic: true, index: false, type: foreign_key_type
|
||||
t.references :blob, null: false, type: foreign_key_type
|
||||
|
||||
if connection.supports_datetime_with_precision?
|
||||
t.datetime :created_at, precision: 6, null: false
|
||||
else
|
||||
t.datetime :created_at, null: false
|
||||
end
|
||||
|
||||
t.index [ :record_type, :record_id, :name, :blob_id ], name: :index_active_storage_attachments_uniqueness, unique: true
|
||||
t.foreign_key :active_storage_blobs, column: :blob_id
|
||||
end
|
||||
|
||||
create_table :active_storage_variant_records, id: primary_key_type do |t|
|
||||
t.belongs_to :blob, null: false, index: false, type: foreign_key_type
|
||||
t.string :variation_digest, null: false
|
||||
|
||||
t.index [ :blob_id, :variation_digest ], name: :index_active_storage_variant_records_uniqueness, unique: true
|
||||
t.foreign_key :active_storage_blobs, column: :blob_id
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def primary_and_foreign_key_types
|
||||
config = Rails.configuration.generators
|
||||
setting = config.options[config.orm][:primary_key_type]
|
||||
primary_key_type = setting || :primary_key
|
||||
foreign_key_type = setting || :bigint
|
||||
[ primary_key_type, foreign_key_type ]
|
||||
end
|
||||
end
|
||||
@@ -1,6 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class CreateAuthors < ActiveRecord::Migration[5.2]
|
||||
class CreateAuthors < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
create_table :authors do |t|
|
||||
t.string :name
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class CreateProfiles < ActiveRecord::Migration[5.2]
|
||||
class CreateProfiles < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
create_table :profiles do |t|
|
||||
t.text :description
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class CreateTags < ActiveRecord::Migration[5.2]
|
||||
class CreateTags < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
create_table :tags do |t|
|
||||
t.string :name
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class CreatePostTags < ActiveRecord::Migration[5.2]
|
||||
class CreatePostTags < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
create_table :post_tags do |t|
|
||||
t.belongs_to :post, foreign_key: true
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class CreatePosts < ActiveRecord::Migration[5.2]
|
||||
class CreatePosts < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
create_table :posts do |t|
|
||||
t.string :title
|
||||
t.text :summary
|
||||
t.text :description
|
||||
t.belongs_to :author, foreign_key: true
|
||||
t.string :category
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
# of editing this file, please use the migrations feature of Active Record to
|
||||
# incrementally modify your database, and then regenerate this schema definition.
|
||||
#
|
||||
# This file is the source Rails uses to define your schema when running `rails
|
||||
# db:schema:load`. When creating a new database, `rails db:schema:load` tends to
|
||||
# This file is the source Rails uses to define your schema when running `bin/rails
|
||||
# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
|
||||
# be faster and is potentially less error prone than running all of your
|
||||
# migrations from scratch. Old migrations may fail to apply correctly if those
|
||||
# migrations use external dependencies or application code.
|
||||
@@ -11,7 +11,6 @@
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2018_06_07_053739) do
|
||||
|
||||
create_table "active_admin_comments", force: :cascade do |t|
|
||||
t.string "namespace"
|
||||
t.text "body"
|
||||
@@ -19,8 +18,8 @@ ActiveRecord::Schema.define(version: 2018_06_07_053739) do
|
||||
t.integer "resource_id"
|
||||
t.string "author_type"
|
||||
t.integer "author_id"
|
||||
t.datetime "created_at", precision: 6, null: false
|
||||
t.datetime "updated_at", precision: 6, null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["author_type", "author_id"], name: "index_active_admin_comments_on_author_type_and_author_id"
|
||||
t.index ["namespace"], name: "index_active_admin_comments_on_namespace"
|
||||
t.index ["resource_type", "resource_id"], name: "index_active_admin_comments_on_resource_type_and_resource_id"
|
||||
@@ -29,8 +28,8 @@ ActiveRecord::Schema.define(version: 2018_06_07_053739) do
|
||||
create_table "active_storage_attachments", force: :cascade do |t|
|
||||
t.string "name", null: false
|
||||
t.string "record_type", null: false
|
||||
t.integer "record_id", null: false
|
||||
t.integer "blob_id", null: false
|
||||
t.bigint "record_id", null: false
|
||||
t.bigint "blob_id", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
|
||||
t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
|
||||
@@ -41,57 +40,66 @@ ActiveRecord::Schema.define(version: 2018_06_07_053739) do
|
||||
t.string "filename", null: false
|
||||
t.string "content_type"
|
||||
t.text "metadata"
|
||||
t.string "service_name", null: false
|
||||
t.bigint "byte_size", null: false
|
||||
t.string "checksum", null: false
|
||||
t.string "checksum"
|
||||
t.datetime "created_at", null: false
|
||||
t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
|
||||
end
|
||||
|
||||
create_table "active_storage_variant_records", force: :cascade do |t|
|
||||
t.bigint "blob_id", null: false
|
||||
t.string "variation_digest", null: false
|
||||
t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true
|
||||
end
|
||||
|
||||
create_table "authors", force: :cascade do |t|
|
||||
t.string "name"
|
||||
t.integer "age"
|
||||
t.string "email"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.datetime "created_at", precision: nil, null: false
|
||||
t.datetime "updated_at", precision: nil, null: false
|
||||
end
|
||||
|
||||
create_table "post_tags", force: :cascade do |t|
|
||||
t.integer "post_id"
|
||||
t.integer "tag_id"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.datetime "created_at", precision: nil, null: false
|
||||
t.datetime "updated_at", precision: nil, null: false
|
||||
t.index ["post_id"], name: "index_post_tags_on_post_id"
|
||||
t.index ["tag_id"], name: "index_post_tags_on_tag_id"
|
||||
end
|
||||
|
||||
create_table "posts", force: :cascade do |t|
|
||||
t.string "title"
|
||||
t.text "summary"
|
||||
t.text "description"
|
||||
t.integer "author_id"
|
||||
t.string "category"
|
||||
t.datetime "dt"
|
||||
t.datetime "dt", precision: nil
|
||||
t.float "position"
|
||||
t.boolean "published"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.datetime "created_at", precision: nil, null: false
|
||||
t.datetime "updated_at", precision: nil, null: false
|
||||
t.index ["author_id"], name: "index_posts_on_author_id"
|
||||
end
|
||||
|
||||
create_table "profiles", force: :cascade do |t|
|
||||
t.text "description"
|
||||
t.integer "author_id"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.datetime "created_at", precision: nil, null: false
|
||||
t.datetime "updated_at", precision: nil, null: false
|
||||
t.index ["author_id"], name: "index_profiles_on_author_id"
|
||||
end
|
||||
|
||||
create_table "tags", force: :cascade do |t|
|
||||
t.string "name"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.datetime "created_at", precision: nil, null: false
|
||||
t.datetime "updated_at", precision: nil, null: false
|
||||
end
|
||||
|
||||
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
|
||||
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
|
||||
add_foreign_key "post_tags", "posts"
|
||||
add_foreign_key "post_tags", "tags"
|
||||
add_foreign_key "posts", "authors"
|
||||
|
||||
39
spec/dummy/db/seeds.rb
Обычный файл
39
spec/dummy/db/seeds.rb
Обычный файл
@@ -0,0 +1,39 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
(11..16).each do |i|
|
||||
Tag.find_or_create_by!(name: "Tag #{i}")
|
||||
end
|
||||
|
||||
(11..20).each do |i|
|
||||
age = 21 + 3 * (i - 10)
|
||||
attrs = { name: "Author #{i}", age: age, email: "some@email#{i}.com" }
|
||||
Author.find_or_create_by!(name: "Author #{i}") do |author|
|
||||
author.assign_attributes(attrs)
|
||||
author.profile = Profile.new(description: "Profile description for Author #{i}") if (i % 3).zero?
|
||||
end
|
||||
end
|
||||
|
||||
authors = Author.pluck(:id)
|
||||
tags = Tag.where.not(name: 'A test tag').pluck(:id)
|
||||
(11..40).each do |i|
|
||||
attrs = {
|
||||
title: "Post #{i}",
|
||||
author_id: authors.sample,
|
||||
position: rand(100),
|
||||
summary: "<p><em>Summary</em> for post #{i}</p>",
|
||||
description: "<p><strong>Some bold</strong> <em>Some italic</em> <u>Some underline</u> [#{i}]</p>",
|
||||
created_at: Time.now - rand(3600).seconds
|
||||
}
|
||||
attrs[:category] = 'news' if (i % 4).zero?
|
||||
attrs[:dt] = Time.now - rand(30).days if (i % 3).zero?
|
||||
|
||||
Post.find_or_create_by!(title: "Post #{i}") do |post|
|
||||
post.assign_attributes(attrs)
|
||||
post.tags = Tag.where(id: tags.sample(2)) if (i % 2).zero?
|
||||
end
|
||||
end
|
||||
|
||||
Author.find_or_create_by!(name: 'A test author', email: 'aaa@bbb.ccc', age: 30)
|
||||
Tag.find_or_create_by!(name: 'A test tag')
|
||||
|
||||
puts '> Seeds: done.'
|
||||
50
spec/dummy/esbuild.config.js
Обычный файл
50
spec/dummy/esbuild.config.js
Обычный файл
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env node
|
||||
const esbuild = require('esbuild');
|
||||
const path = require('path');
|
||||
const { execSync } = require('node:child_process');
|
||||
|
||||
// For development, use the local gem path
|
||||
const gemPath = path.resolve(__dirname, '../..');
|
||||
|
||||
// Configuration for esbuild with proper module resolution
|
||||
const config = {
|
||||
entryPoints: ['app/javascript/active_admin.js'],
|
||||
bundle: true,
|
||||
sourcemap: true,
|
||||
format: 'iife',
|
||||
outdir: 'app/assets/builds',
|
||||
publicPath: '/assets',
|
||||
loader: {
|
||||
'.js': 'js',
|
||||
},
|
||||
// Define global Quill for the initialization script
|
||||
define: {
|
||||
'global': 'window'
|
||||
},
|
||||
// Use alias for clean imports
|
||||
alias: {
|
||||
'activeadmin/quill_editor': path.join(gemPath, 'vendor/assets/javascripts/activeadmin/quill_editor.js')
|
||||
}
|
||||
};
|
||||
|
||||
// Check if we're in watch mode
|
||||
const watchMode = process.argv.includes('--watch');
|
||||
|
||||
if (watchMode) {
|
||||
// Start the build with watch mode
|
||||
esbuild.context(config).then(ctx => {
|
||||
ctx.watch();
|
||||
console.log('Watching for changes...');
|
||||
}).catch(error => {
|
||||
console.error('Build failed:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
} else {
|
||||
// Single build
|
||||
esbuild.build(config).then(() => {
|
||||
console.log('Build completed');
|
||||
}).catch(error => {
|
||||
console.error('Build failed:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Ссылка в новой задаче
Block a user