diff --git a/.github/workflows/a11y.yml b/.github/workflows/a11y.yml
index 33bc9d11..6ffa33e7 100644
--- a/.github/workflows/a11y.yml
+++ b/.github/workflows/a11y.yml
@@ -34,8 +34,17 @@ jobs:
with:
ruby-version: .tool-versions
bundler-cache: true
+ - name: Set up Node
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+ cache: npm
+ - name: Install npm packages
+ run: npm ci --omit=dev
- name: Set up Database
run: bundle exec rails db:setup
+ - name: Build CSS
+ run: bundle exec rails dartsass:build
- name: Create separate Chrome data directories
run: |
mkdir -p /tmp/chrome-data-rspec
diff --git a/.github/workflows/cucumber.yml b/.github/workflows/cucumber.yml
index 6e511402..368a7e04 100644
--- a/.github/workflows/cucumber.yml
+++ b/.github/workflows/cucumber.yml
@@ -37,12 +37,21 @@ jobs:
with:
ruby-version: .tool-versions
bundler-cache: true
+ - name: Set up Node
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+ cache: npm
+ - name: Install npm packages
+ run: npm ci --omit=dev
- name: Install Chrome and ChromeDriver
uses: browser-actions/setup-chrome@v1
with:
chrome-version: stable
- name: Setup Database
run: bundle exec rails db:setup
+ - name: Build CSS
+ run: bundle exec rails dartsass:build
- name: Create Chrome data directory
run: mkdir -p /tmp/chrome-data-cucumber
- name: Run non-JavaScript Cucumber tests
diff --git a/.github/workflows/rspec.yml b/.github/workflows/rspec.yml
index 78438670..6b333e9f 100644
--- a/.github/workflows/rspec.yml
+++ b/.github/workflows/rspec.yml
@@ -37,9 +37,18 @@ jobs:
with:
ruby-version: .tool-versions
bundler-cache: true
+ - name: Set up Node
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+ cache: npm
+ - name: Install npm packages
+ run: npm ci --omit=dev
- name: Setup Database
run: |
bundle exec rails db:test:prepare
+ - name: Build CSS
+ run: bundle exec rails dartsass:build
- name: Create Chrome data directory
run: mkdir -p /tmp/chrome-data-rspec
- name: Run RSpec Tests
diff --git a/.gitignore b/.gitignore
index b8b4a5cd..6567000b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -66,6 +66,10 @@ node_modules/
/public/packs-test
/public/assets
+# Dart Sass build output (app/assets/builds/application.css)
+/app/assets/builds/*
+!/app/assets/builds/.keep
+
# Ignore yarn files
/yarn-error.log
yarn-debug.log*
diff --git a/Dockerfile b/Dockerfile
index 7f3d9f5a..5e32a426 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -17,9 +17,12 @@ ENV RAILS_ENV="production" \
# Throw-away build stage to reduce size of final image
FROM base as build
-# Install packages needed to build gems
+# Install packages needed to build gems. nodejs/npm are here for the DataTables
+# stylesheets only: application.scss @imports them out of node_modules, so they
+# have to be installed before assets:precompile. This is a build-stage-only
+# dependency -- the runtime image below carries no Node.
RUN apt-get update -qq && \
- apt-get install --no-install-recommends -y build-essential git libvips pkg-config
+ apt-get install --no-install-recommends -y build-essential git libvips pkg-config nodejs npm
# Install application gems
COPY Gemfile Gemfile.lock ./
@@ -30,6 +33,12 @@ RUN bundle install && \
# Copy application code
COPY . .
+# Install the npm packages that supply the DataTables stylesheets. --omit=dev
+# skips the documentation tooling the image does not need. This runs after
+# COPY so that npm ci (which wipes node_modules first) also clears out any
+# node_modules that came along in the build context.
+RUN npm ci --omit=dev
+
# Precompile bootsnap code for faster boot times
RUN bundle exec bootsnap precompile app/ lib/
diff --git a/Gemfile b/Gemfile
index 325e916b..d439468b 100644
--- a/Gemfile
+++ b/Gemfile
@@ -81,8 +81,9 @@ gem 'hypershield'
gem 'good_job', '~> 4.19'
#### Frontend related tools
-# The original asset pipeline for Rails [https://github.com/rails/sprockets-rails]
-gem 'sprockets-rails'
+# Rails 8's default asset pipeline: digests and serves what's on disk, and does
+# no compiling of its own [https://github.com/rails/propshaft]
+gem 'propshaft'
# Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails]
gem 'importmap-rails'
@@ -91,10 +92,15 @@ gem 'importmap-rails'
gem 'turbo-rails'
gem 'bootstrap', '~> 5.3.8'
-# dependency for bootstrap # 03-10-2025 this is deprecated but still works
-gem 'sassc-rails', '~> 2.1'
-# alternative to sassc-rails, this is recommended but bootstrap 5.3.3 is still using "deprecated" @import statements which this gem doesn't like
-# gem 'dartsass-sprockets'
+# Compiles app/assets/stylesheets/application.scss to app/assets/builds with
+# Dart Sass (the only Sass implementation still maintained), which Propshaft
+# then digests and serves. Replaces sassc-rails, deprecated along with its
+# LibSass backend.
+#
+# Bootstrap 5.3 still uses `@import`, which Dart Sass deprecated; those warnings
+# are silenced in config/initializers/dartsass.rb. Bootstrap 6 moves to `@use`,
+# at which point the silencing can go away.
+gem 'dartsass-rails', '~> 0.5'
# Font Awesome for icons
gem 'font-awesome-sass'
diff --git a/Gemfile.lock b/Gemfile.lock
index 65744166..42cd43b2 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -85,14 +85,10 @@ GEM
uri (>= 0.13.1)
addressable (2.9.0)
public_suffix (>= 2.0.2, < 8.0)
- annotaterb (4.24.0)
+ annotaterb (4.23.0)
activerecord (>= 6.0.0)
activesupport (>= 6.0.0)
- anonymous_loader (0.1.3)
- version_gem (~> 1.1, >= 1.1.14)
ast (2.4.3)
- auth-sanitizer (0.2.3)
- version_gem (~> 1.1, >= 1.1.14)
axe-core-api (4.12.0)
dumb_delegator
axe-core-cucumber (4.12.0)
@@ -139,7 +135,7 @@ GEM
bigdecimal
rexml
crass (1.0.7)
- csv (3.3.6)
+ csv (3.3.5)
cucumber (11.1.1)
base64 (~> 0.2)
builder (~> 3.2)
@@ -169,6 +165,9 @@ GEM
cucumber (>= 7, < 12)
railties (>= 6.1, < 9)
cucumber-tag-expressions (8.1.0)
+ dartsass-rails (0.5.1)
+ railties (>= 6.0.0)
+ sass-embedded (~> 1.63)
database_cleaner-active_record (2.2.2)
activerecord (>= 5.a)
database_cleaner-core (~> 2.0)
@@ -185,9 +184,9 @@ GEM
railties (>= 6.1)
drb (2.2.3)
dumb_delegator (1.1.0)
- erb (6.0.7)
+ erb (6.0.6)
erubi (1.13.1)
- et-orbi (1.4.1)
+ et-orbi (1.4.0)
tzinfo
factory_bot (6.5.6)
activesupport (>= 6.1.0)
@@ -227,7 +226,28 @@ GEM
fugit (>= 1.11.0)
railties (>= 6.1.0)
thor (>= 1.0.0)
- guard (2.20.2)
+ google-protobuf (4.35.1)
+ bigdecimal
+ rake (~> 13.3)
+ google-protobuf (4.35.1-aarch64-linux-gnu)
+ bigdecimal
+ rake (~> 13.3)
+ google-protobuf (4.35.1-arm64-darwin)
+ bigdecimal
+ rake (~> 13.3)
+ google-protobuf (4.35.1-x86-linux-gnu)
+ bigdecimal
+ rake (~> 13.3)
+ google-protobuf (4.35.1-x86-mingw32)
+ bigdecimal
+ rake (~> 13.3)
+ google-protobuf (4.35.1-x86_64-darwin)
+ bigdecimal
+ rake (~> 13.3)
+ google-protobuf (4.35.1-x86_64-linux-gnu)
+ bigdecimal
+ rake (~> 13.3)
+ guard (2.20.1)
formatador (>= 0.2.4)
listen (>= 2.7, < 4.0)
logger (~> 1.6)
@@ -246,7 +266,7 @@ GEM
hashdiff (1.2.1)
hashie (5.1.0)
logger
- http-cookie (1.1.6)
+ http-cookie (1.1.0)
domain_name (~> 0.5)
httparty (0.24.2)
csv
@@ -269,7 +289,7 @@ GEM
jbuilder (2.15.1)
actionview (>= 7.0.0)
activesupport (>= 7.0.0)
- json (2.21.2)
+ json (2.21.1)
json_schemer (2.5.0)
bigdecimal
hana (~> 1.3)
@@ -315,7 +335,7 @@ GEM
net-smtp
marcel (1.2.1)
matrix (0.4.3)
- mcp (0.25.0)
+ mcp (0.22.0)
json_schemer (>= 2.4)
memoist3 (1.0.0)
method_source (1.1.0)
@@ -324,9 +344,9 @@ GEM
minitest (6.0.6)
drb (~> 2.0)
prism (~> 1.5)
- msgpack (1.8.4)
+ msgpack (1.8.3)
multi_test (1.1.0)
- multi_xml (0.9.1)
+ multi_xml (0.8.1)
bigdecimal (>= 3.1, < 5)
nenv (0.3.0)
net-http (0.9.1)
@@ -357,16 +377,14 @@ GEM
notiffany (0.1.3)
nenv (~> 0.1)
shellany (~> 0.0)
- oauth2 (2.0.25)
- anonymous_loader (~> 0.1, >= 0.1.3)
- auth-sanitizer (~> 0.2, >= 0.2.3)
+ oauth2 (2.0.18)
faraday (>= 0.17.3, < 4.0)
jwt (>= 1.0, < 4.0)
logger (~> 1.2)
multi_xml (~> 0.5)
rack (>= 1.2, < 4)
- snaky_hash (~> 2.0, >= 2.0.7)
- version_gem (~> 1.1, >= 1.1.14)
+ snaky_hash (~> 2.0, >= 2.0.3)
+ version_gem (~> 1.1, >= 1.1.9)
omniauth (2.1.4)
hashie (>= 3.4.6)
logger
@@ -383,7 +401,7 @@ GEM
omniauth (~> 2.0)
ostruct (0.6.3)
parallel (2.1.0)
- parser (3.3.12.0)
+ parser (3.3.11.1)
ast (~> 2.4.1)
racc
pg (1.6.3)
@@ -396,6 +414,10 @@ GEM
prettyprint
prettyprint (0.2.0)
prism (1.9.0)
+ propshaft (1.3.2)
+ actionpack (>= 7.0.0)
+ activesupport (>= 7.0.0)
+ rack
pry (0.16.0)
coderay (~> 1.1)
method_source (~> 1.0)
@@ -459,7 +481,7 @@ GEM
rb-fsevent (0.11.2)
rb-inotify (0.11.1)
ffi (~> 1.0)
- rbs (4.1.2)
+ rbs (4.1.0)
logger
prism (>= 1.6.0)
tsort
@@ -532,14 +554,21 @@ GEM
ruby-progressbar (1.13.0)
rubyzip (3.4.1)
safely_block (1.0.0)
+ sass-embedded (1.102.0)
+ google-protobuf (~> 4.31)
+ rake (>= 13)
+ sass-embedded (1.102.0-aarch64-linux-gnu)
+ google-protobuf (~> 4.31)
+ sass-embedded (1.102.0-arm-linux-gnueabihf)
+ google-protobuf (~> 4.31)
+ sass-embedded (1.102.0-arm64-darwin)
+ google-protobuf (~> 4.31)
+ sass-embedded (1.102.0-x86_64-darwin)
+ google-protobuf (~> 4.31)
+ sass-embedded (1.102.0-x86_64-linux-gnu)
+ google-protobuf (~> 4.31)
sassc (2.4.0)
ffi (~> 1.9)
- sassc-rails (2.1.2)
- railties (>= 4.0.0)
- sassc (>= 2.0)
- sprockets (> 3.0)
- sprockets-rails
- tilt
securerandom (0.4.1)
selenium-webdriver (4.46.0)
base64 (~> 0.2)
@@ -559,17 +588,9 @@ GEM
activesupport (>= 7.2)
simplecov (1.0.3)
simpleidn (0.2.3)
- snaky_hash (2.0.7)
+ snaky_hash (2.0.3)
hashie (>= 0.1.0, < 6)
- version_gem (~> 1.1, >= 1.1.14)
- sprockets (4.2.2)
- concurrent-ruby (~> 1.0)
- logger
- rack (>= 2.2.4, < 4)
- sprockets-rails (3.5.2)
- actionpack (>= 6.1)
- activesupport (>= 6.1)
- sprockets (>= 3.0.0)
+ version_gem (>= 1.1.8, < 3)
stimulus-rails (1.3.4)
railties (>= 6.0.0)
strong_migrations (2.8.0)
@@ -582,7 +603,6 @@ GEM
memoist3 (~> 1.0.0)
win32ole
thor (1.5.0)
- tilt (2.7.0)
timecop (0.9.11)
timeout (0.6.1)
tsort (0.2.0)
@@ -591,14 +611,14 @@ GEM
railties (>= 7.1.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
- tzinfo-data (1.2026.3)
+ tzinfo-data (1.2026.1)
tzinfo (>= 1.0.0)
unicode-display_width (3.2.0)
unicode-emoji (~> 4.1)
unicode-emoji (4.2.0)
uri (1.1.1)
useragent (0.16.11)
- version_gem (1.1.15)
+ version_gem (1.1.9)
web-console (4.3.0)
actionview (>= 8.0.0)
bindex (>= 0.4.0)
@@ -615,7 +635,7 @@ GEM
win32ole (1.9.3)
xpath (3.2.0)
nokogiri (~> 1.8)
- zeitwerk (2.8.3)
+ zeitwerk (2.8.2)
PLATFORMS
aarch64-linux
@@ -638,6 +658,7 @@ DEPENDENCIES
capybara-screenshot
codeclimate-test-reporter
cucumber-rails
+ dartsass-rails (~> 0.5)
database_cleaner-active_record
debug
dotenv-rails
@@ -662,6 +683,7 @@ DEPENDENCIES
omniauth-rails_csrf_protection
ostruct
pg
+ propshaft
puma (>= 6.0)
rack_session_access
rails (~> 8.1.3)
@@ -672,13 +694,11 @@ DEPENDENCIES
rubocop-performance
rubocop-rails-omakase
rubocop-rspec
- sassc-rails (~> 2.1)
selenium-webdriver
sentry-rails
sentry-ruby
shoulda-matchers (~> 8.0)
simplecov (~> 1.0.3)
- sprockets-rails
stimulus-rails
strong_migrations
timecop
diff --git a/Procfile.dev b/Procfile.dev
index 9c5377e0..4f961872 100644
--- a/Procfile.dev
+++ b/Procfile.dev
@@ -1 +1,2 @@
web: bundle exec rails s -p ${PORT:-3000}
+css: bundle exec rails dartsass:watch
diff --git a/app/assets/builds/.keep b/app/assets/builds/.keep
new file mode 100644
index 00000000..e69de29b
diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js
deleted file mode 100644
index ad05f0d7..00000000
--- a/app/assets/config/manifest.js
+++ /dev/null
@@ -1,9 +0,0 @@
-//= link_tree ../images
-// Only the manifest stylesheet is compiled standalone. Do NOT link the whole
-// directory: Sprockets would also compile the _*.scss partials on their own,
-// where the variables from application.scss are not defined.
-//= link application.css
-//= link_tree ../../javascript .js
-//= link_tree ../../../vendor/javascript .js
-
-//= link stimulus-loading.js
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index fd5316d0..ffceaace 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -8,6 +8,11 @@
// Do NOT use Sprockets require directives (require_tree, require_self)
// in this file — they bypass SCSS compilation and break variable sharing.
+// Dart Sass deprecated the global color functions; `color.mix` is the
+// replacement for `mix`. @use has to precede every rule except variable
+// declarations, so it stays at the top even though the @imports are below.
+@use "sass:color";
+
/**
* UC Berkeley color palette based on the official brand guidelines:
* https://brand.berkeley.edu/colors/
@@ -91,13 +96,41 @@ $code-color-dark: #ea868f;
// invisible on the dark track. Use a solid white knob instead.
$form-switch-color-dark: $white;
+// Bootstrap inlines a handful of icons (accordion chevron, switch knob, select
+// caret) as SVG data URIs, colored by variables that are computed with mix().
+// Dart Sass keeps the fractional channels mix() produces, so those colors
+// serialize as `rgb(50%, 57.45%, 73.14%)` where LibSass emitted a hex triplet
+// — which drops a bare `%` into a URI, and `%` alone is not a valid escape
+// sequence. Browsers pass it through, but escaping `%` first (the list is
+// applied in order) keeps the emitted data URIs well-formed.
+$escaped-characters: (
+ ("%", "%25"),
+ ("<", "%3c"),
+ (">", "%3e"),
+ ("#", "%23"),
+ ("(", "%28"),
+ (")", "%29"),
+);
+
+// font-awesome-sass emits `font-path(...)` when Sprockets' Sass helpers are
+// available and falls back to `#{$fa-font-path}/#{$file}` otherwise. Dart Sass
+// runs as a plain CLI here, so the fallback is what we get — point it at the
+// logical path of the gem's webfonts (its assets/fonts directory is on the
+// Propshaft load path) and let Propshaft rewrite the url() to a digested one.
+$fa-font-path: "font-awesome";
+
@import "bootstrap";
+
+// DataTables' Bootstrap 5 theme, imported straight out of node_modules (see
+// config/initializers/dartsass.rb for the load path). It overrides Bootstrap's
+// own table styles, so it has to come after Bootstrap and before our overrides
+// in custom_bootstrap.
+@import "dataTables.bootstrap5";
+@import "responsive.bootstrap5";
+
@import "custom_bootstrap";
@import "font-awesome";
-// NOTE: DataTables CSS is intentionally not imported here. See the comment in
-// app/views/layouts/application.html.erb for why it is served from public/.
-
@each $name, $value in $colors {
.bg-#{$name} {
background-color: $value;
@@ -112,14 +145,14 @@ $form-switch-color-dark: $white;
.table-#{$name} {
--bs-table-bg: #{$value};
--bs-table-color: #{color-contrast($value)};
- --bs-table-border-color: #{mix(black, $value, 15%)};
+ --bs-table-border-color: #{color.mix(black, $value, 15%)};
&,
> th,
> td {
--bs-table-bg: #{$value};
--bs-table-color: #{color-contrast($value)};
- --bs-table-border-color: #{mix(black, $value, 15%)};
+ --bs-table-border-color: #{color.mix(black, $value, 15%)};
}
}
@@ -131,7 +164,7 @@ $form-switch-color-dark: $white;
> tr > td {
--bs-table-bg: #{$value};
--bs-table-color: #{color-contrast($value)};
- --bs-table-border-color: #{mix(black, $value, 15%)};
+ --bs-table-border-color: #{color.mix(black, $value, 15%)};
}
}
}
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index 7824c9ed..c5b63edb 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -8,18 +8,6 @@
<%= csp_meta_tag %>
<%= stylesheet_link_tag "application" %>
- <%# DataTables CSS is served straight from public/ rather than through the
- asset pipeline, on purpose. Importing it from application.scss does NOT
- work: Sass treats `@import "foo.css"` as a passthrough and emits a literal
- `@import url(datatables/...css)` into the compiled stylesheet, pointing at
- a path that is never precompiled -- so it 404s in production, where
- config.assets.compile is false. Dropping the .css extension so Sass inlines
- it instead fails to compile under sassc-rails. Keep these as plain
- tags until the app moves off sassc-rails. Versions must be kept in sync
- with the datatables.net-bs5 / datatables.net-responsive-bs5 pins in
- config/importmap.rb. %>
-
-
<%= javascript_importmap_tags %>
<%= render "layouts/components/color_mode_critical" %>
diff --git a/bin/setup b/bin/setup
index 5e00489e..817e65bf 100755
--- a/bin/setup
+++ b/bin/setup
@@ -17,6 +17,10 @@ FileUtils.chdir APP_ROOT do
system! "gem install bundler --conservative"
system("bundle check") || system!("bundle install")
+ # application.scss @imports the DataTables stylesheets out of node_modules,
+ # so the CSS will not compile without these.
+ system! "npm install"
+
# puts "\n== Copying sample files =="
# unless File.exist?("config/database.yml")
# FileUtils.cp "config/database.yml.sample", "config/database.yml"
@@ -25,6 +29,12 @@ FileUtils.chdir APP_ROOT do
puts "\n== Preparing database =="
system! "bin/rails db:prepare"
+ # application.css is a build artifact now, so a fresh checkout has none and
+ # the first page render would raise Propshaft::MissingAssetError. `make dev`
+ # keeps it up to date after this via the css process in Procfile.dev.
+ puts "\n== Building CSS =="
+ system! "bin/rails dartsass:build"
+
puts "\n== Removing old logs and tempfiles =="
system! "bin/rails log:clear tmp:clear"
diff --git a/config/environments/development.rb b/config/environments/development.rb
index 1db08070..cd591f66 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -68,14 +68,7 @@
# Highlight code that enqueued background job in logs.
config.active_job.verbose_enqueue_logs = true
- # Suppress logger output for asset requests.
- config.assets.quiet = false
- config.assets.debug = true
- # TODO: WARNING -- As of April 2026 / Rails 7.2 / sprockets + importmaps
- # This must be set to true or JS does not seem to load in development.
- config.assets.digest = true
config.cache_classes = false
- config.assets.compile = true
# Raises error for missing translations.
# config.i18n.raise_on_missing_translations = true
diff --git a/config/environments/production.rb b/config/environments/production.rb
index 50628b54..b8cc70ff 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -23,12 +23,6 @@
# Disable serving static files from `public/`, relying on NGINX/Apache to do so instead.
# config.public_file_server.enabled = false
- # Compress CSS using a preprocessor.
- # config.assets.css_compressor = :sass
-
- # Do not fall back 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.asset_host = "http://assets.example.com"
diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb
index be3a10c5..f47ac388 100644
--- a/config/initializers/assets.rb
+++ b/config/initializers/assets.rb
@@ -1,14 +1,12 @@
# Be sure to restart your server when you modify this file.
-# Version of your assets, change this if you want to expire all your assets.
-Rails.application.config.assets.version = "1.0"
-
-# Add additional assets to the asset load path.
-# Rails.application.config.assets.paths << Emoji.images_path
-
-Rails.application.config.assets.precompile += %w(bootstrap.min.js popper.js)
-
-# Precompile additional assets.
-# application.js, application.css, and all non-JS/CSS in the app/assets
-# folder are already added.
-# Rails.application.config.assets.precompile += %w( admin.js admin.css )
+# Propshaft serves everything it finds on the load path and digests it by
+# content, so there is no precompile list to maintain — that was a Sprockets
+# concept, as was the manifest.js this app used to carry.
+#
+# Rails adds every app/assets/* subdirectory to the load path automatically, so
+# app/assets/builds (where Dart Sass writes application.css) needs no config.
+
+# The Sass sources are inputs to the build, not assets to serve; excluding them
+# keeps unbuilt .scss out of public/assets.
+Rails.application.config.assets.excluded_paths << Rails.root.join('app/assets/stylesheets')
diff --git a/config/initializers/dartsass.rb b/config/initializers/dartsass.rb
new file mode 100644
index 00000000..b25306b5
--- /dev/null
+++ b/config/initializers/dartsass.rb
@@ -0,0 +1,48 @@
+# Be sure to restart your server when you modify this file.
+
+# dartsass-rails shells out to the Dart Sass CLI, so its configuration is a
+# list of command-line flags rather than a Ruby options hash.
+#
+# --quiet-deps drops deprecations raised inside gem-provided stylesheets
+# (Bootstrap, Font Awesome); we can't fix those, and Bootstrap 5.3 alone emits
+# thousands of lines of them per build. --silence-deprecation=import covers the
+# `@import` lines in application.scss itself, which --quiet-deps does not reach.
+#
+# Drop the silencing once Bootstrap 6 ships and the `@import`s can become
+# `@use`.
+Rails.application.config.dartsass.build_options += [
+ '--quiet-deps',
+ '--silence-deprecation=import'
+]
+
+# The gem's default is --style=compressed --no-source-map for every
+# environment. Sprockets only compressed outside development, so keep the
+# built CSS readable and mapped back to the .scss sources while developing.
+if Rails.env.development?
+ Rails.application.config.dartsass.build_options -= [ '--style=compressed', '--no-source-map' ]
+ Rails.application.config.dartsass.build_options += [ '--style=expanded', '--embed-sources' ]
+end
+
+# DataTables ships its Bootstrap 5 theme as plain CSS on npm, so application.scss
+# imports it out of node_modules. Nothing puts those directories on the Sass
+# load path for us.
+Rails.application.config.dartsass.build_options += [
+ '--load-path', Rails.root.join('node_modules/datatables.net-bs5/css').to_s,
+ '--load-path', Rails.root.join('node_modules/datatables.net-responsive-bs5/css').to_s
+]
+
+# The bootstrap and font-awesome-sass gems put their Sass sources on the asset
+# load path so application.scss can @import them. Propshaft has one load path
+# and serves everything on it, so leaving them there digests ~110 .scss
+# partials into public/assets. dartsass-rails builds its --load-path list from
+# config.assets.paths, so hand Dart Sass the directories directly and then take
+# them off Propshaft's path. (font-awesome-sass' assets/fonts directory has to
+# stay — that one holds the webfonts the built CSS points at.)
+sass_gem_paths = %w[bootstrap font-awesome-sass].filter_map do |name|
+ spec = Gem.loaded_specs[name]
+ File.join(spec.gem_dir, 'assets', 'stylesheets') if spec
+end
+
+Rails.application.config.dartsass.build_options +=
+ sass_gem_paths.flat_map { |path| [ '--load-path', path ] }
+Rails.application.config.assets.excluded_paths += sass_gem_paths
diff --git a/package-lock.json b/package-lock.json
index b0f6fa6d..f9161050 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,10 +8,12 @@
"name": "flextensions",
"version": "1.0.0",
"license": "BSD-2-Clause",
+ "dependencies": {
+ "datatables.net-bs5": "2.3.1",
+ "datatables.net-responsive-bs5": "3.0.4"
+ },
"devDependencies": {
"@redocly/cli": "^2.40.0",
- "datatables.net": "^2.2.2",
- "datatables.net-bs5": "^2.2.2",
"swagger-cli": "^4.0.4"
}
},
@@ -310,21 +312,42 @@
"dev": true
},
"node_modules/datatables.net": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/datatables.net/-/datatables.net-2.2.2.tgz",
- "integrity": "sha512-gfODIKE3gpgbVeZy2QGj2Dq9roO6hy00S+k1knklrqlMyAMrh1wt0Q6ryBUM7gU96U77ysbq8dYhxFdmcC/oPQ==",
- "dev": true,
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/datatables.net/-/datatables.net-2.3.1.tgz",
+ "integrity": "sha512-pRXZuk3oR7P5kTl/CRvopcTihlvmZiY+xSBjbNI6e8MjYtgZQodWEqLUUOrIZeLH8CfxapPR/Bmb0NKAvILP5g==",
+ "license": "MIT",
"dependencies": {
"jquery": ">=1.7"
}
},
"node_modules/datatables.net-bs5": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/datatables.net-bs5/-/datatables.net-bs5-2.2.2.tgz",
- "integrity": "sha512-0mAbpUf0EpnIEc0RlN6vSrSk9y/+NuReiwDpjHYY3RfzdvH6Lt0+7Q9OU5RIbYxaFxES/z60thxdrw7IUFnBhw==",
- "dev": true,
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/datatables.net-bs5/-/datatables.net-bs5-2.3.1.tgz",
+ "integrity": "sha512-bUwsW7cIR8EDyiedQv6OKGF5ouxkFjaODmtEd7NRtpoZixAZDScmIrxe9cddjS0EybpC2gYslKs+o03E8tkCEA==",
+ "license": "MIT",
+ "dependencies": {
+ "datatables.net": "2.3.1",
+ "jquery": ">=1.7"
+ }
+ },
+ "node_modules/datatables.net-responsive": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/datatables.net-responsive/-/datatables.net-responsive-3.0.4.tgz",
+ "integrity": "sha512-d1JKaWPRp81xydZrTDqrzGTloXthDtyvwbqiSKYUhDBKWTL4wN5IW5WYr4OBPwu21Ctpi/QgOl7mt9MfyF8KxA==",
+ "license": "MIT",
+ "dependencies": {
+ "datatables.net": "^2",
+ "jquery": ">=1.7"
+ }
+ },
+ "node_modules/datatables.net-responsive-bs5": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/datatables.net-responsive-bs5/-/datatables.net-responsive-bs5-3.0.4.tgz",
+ "integrity": "sha512-/RufNJAFFmXkhfyBmXKfLlpopoKNkeDytMHHbsiBkoTRllJik9rtOON5NuMJOCL8sjwM2c+rUo/rzuXNk/70Qw==",
+ "license": "MIT",
"dependencies": {
- "datatables.net": "2.2.2",
+ "datatables.net-bs5": "^2",
+ "datatables.net-responsive": "3.0.4",
"jquery": ">=1.7"
}
},
@@ -419,10 +442,10 @@
}
},
"node_modules/jquery": {
- "version": "3.7.1",
- "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
- "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==",
- "dev": true
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jquery/-/jquery-4.0.0.tgz",
+ "integrity": "sha512-TXCHVR3Lb6TZdtw1l3RTLf8RBWVGexdxL6AC8/e0xZKEpBflBsjh9/8LXw+dkNFuOyW9B7iB3O1sP7hS0Kiacg==",
+ "license": "MIT"
},
"node_modules/js-yaml": {
"version": "4.3.1",
@@ -838,21 +861,38 @@
"dev": true
},
"datatables.net": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/datatables.net/-/datatables.net-2.2.2.tgz",
- "integrity": "sha512-gfODIKE3gpgbVeZy2QGj2Dq9roO6hy00S+k1knklrqlMyAMrh1wt0Q6ryBUM7gU96U77ysbq8dYhxFdmcC/oPQ==",
- "dev": true,
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/datatables.net/-/datatables.net-2.3.1.tgz",
+ "integrity": "sha512-pRXZuk3oR7P5kTl/CRvopcTihlvmZiY+xSBjbNI6e8MjYtgZQodWEqLUUOrIZeLH8CfxapPR/Bmb0NKAvILP5g==",
"requires": {
"jquery": ">=1.7"
}
},
"datatables.net-bs5": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/datatables.net-bs5/-/datatables.net-bs5-2.2.2.tgz",
- "integrity": "sha512-0mAbpUf0EpnIEc0RlN6vSrSk9y/+NuReiwDpjHYY3RfzdvH6Lt0+7Q9OU5RIbYxaFxES/z60thxdrw7IUFnBhw==",
- "dev": true,
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/datatables.net-bs5/-/datatables.net-bs5-2.3.1.tgz",
+ "integrity": "sha512-bUwsW7cIR8EDyiedQv6OKGF5ouxkFjaODmtEd7NRtpoZixAZDScmIrxe9cddjS0EybpC2gYslKs+o03E8tkCEA==",
"requires": {
- "datatables.net": "2.2.2",
+ "datatables.net": "2.3.1",
+ "jquery": ">=1.7"
+ }
+ },
+ "datatables.net-responsive": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/datatables.net-responsive/-/datatables.net-responsive-3.0.4.tgz",
+ "integrity": "sha512-d1JKaWPRp81xydZrTDqrzGTloXthDtyvwbqiSKYUhDBKWTL4wN5IW5WYr4OBPwu21Ctpi/QgOl7mt9MfyF8KxA==",
+ "requires": {
+ "datatables.net": "^2",
+ "jquery": ">=1.7"
+ }
+ },
+ "datatables.net-responsive-bs5": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/datatables.net-responsive-bs5/-/datatables.net-responsive-bs5-3.0.4.tgz",
+ "integrity": "sha512-/RufNJAFFmXkhfyBmXKfLlpopoKNkeDytMHHbsiBkoTRllJik9rtOON5NuMJOCL8sjwM2c+rUo/rzuXNk/70Qw==",
+ "requires": {
+ "datatables.net-bs5": "^2",
+ "datatables.net-responsive": "3.0.4",
"jquery": ">=1.7"
}
},
@@ -915,10 +955,9 @@
"dev": true
},
"jquery": {
- "version": "3.7.1",
- "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
- "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==",
- "dev": true
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jquery/-/jquery-4.0.0.tgz",
+ "integrity": "sha512-TXCHVR3Lb6TZdtw1l3RTLf8RBWVGexdxL6AC8/e0xZKEpBflBsjh9/8LXw+dkNFuOyW9B7iB3O1sP7hS0Kiacg=="
},
"js-yaml": {
"version": "4.3.1",
diff --git a/package.json b/package.json
index 47633087..deac1a64 100644
--- a/package.json
+++ b/package.json
@@ -11,11 +11,12 @@
},
"author": "CS169l flextensions development team",
"license": "BSD-2-Clause",
-
+ "dependencies": {
+ "datatables.net-bs5": "2.3.1",
+ "datatables.net-responsive-bs5": "3.0.4"
+ },
"devDependencies": {
"@redocly/cli": "^2.40.0",
- "swagger-cli": "^4.0.4",
- "datatables.net": "^2.2.2",
- "datatables.net-bs5": "^2.2.2"
+ "swagger-cli": "^4.0.4"
}
}
diff --git a/public/datatables/dataTables.bootstrap5.css b/public/datatables/dataTables.bootstrap5.css
deleted file mode 100644
index ed11e6ea..00000000
--- a/public/datatables/dataTables.bootstrap5.css
+++ /dev/null
@@ -1,569 +0,0 @@
-:root {
- --dt-row-selected: 13, 110, 253;
- --dt-row-selected-text: 255, 255, 255;
- --dt-row-selected-link: 9, 10, 11;
- --dt-row-stripe: 0, 0, 0;
- --dt-row-hover: 0, 0, 0;
- --dt-column-ordering: 0, 0, 0;
- --dt-html-background: white;
-}
-:root.dark {
- --dt-html-background: rgb(33, 37, 41);
-}
-
-table.dataTable td.dt-control {
- text-align: center;
- cursor: pointer;
-}
-table.dataTable td.dt-control:before {
- display: inline-block;
- box-sizing: border-box;
- content: "";
- border-top: 5px solid transparent;
- border-left: 10px solid rgba(0, 0, 0, 0.5);
- border-bottom: 5px solid transparent;
- border-right: 0px solid transparent;
-}
-table.dataTable tr.dt-hasChild td.dt-control:before {
- border-top: 10px solid rgba(0, 0, 0, 0.5);
- border-left: 5px solid transparent;
- border-bottom: 0px solid transparent;
- border-right: 5px solid transparent;
-}
-table.dataTable tfoot:empty {
- display: none;
-}
-
-html.dark table.dataTable td.dt-control:before,
-:root[data-bs-theme=dark] table.dataTable td.dt-control:before,
-:root[data-theme=dark] table.dataTable td.dt-control:before {
- border-left-color: rgba(255, 255, 255, 0.5);
-}
-html.dark table.dataTable tr.dt-hasChild td.dt-control:before,
-:root[data-bs-theme=dark] table.dataTable tr.dt-hasChild td.dt-control:before,
-:root[data-theme=dark] table.dataTable tr.dt-hasChild td.dt-control:before {
- border-top-color: rgba(255, 255, 255, 0.5);
- border-left-color: transparent;
-}
-
-div.dt-scroll {
- width: 100%;
-}
-
-div.dt-scroll-body thead tr,
-div.dt-scroll-body tfoot tr {
- height: 0;
-}
-div.dt-scroll-body thead tr th, div.dt-scroll-body thead tr td,
-div.dt-scroll-body tfoot tr th,
-div.dt-scroll-body tfoot tr td {
- height: 0 !important;
- padding-top: 0px !important;
- padding-bottom: 0px !important;
- border-top-width: 0px !important;
- border-bottom-width: 0px !important;
-}
-div.dt-scroll-body thead tr th div.dt-scroll-sizing, div.dt-scroll-body thead tr td div.dt-scroll-sizing,
-div.dt-scroll-body tfoot tr th div.dt-scroll-sizing,
-div.dt-scroll-body tfoot tr td div.dt-scroll-sizing {
- height: 0 !important;
- overflow: hidden !important;
-}
-
-table.dataTable thead > tr > th:active,
-table.dataTable thead > tr > td:active {
- outline: none;
-}
-table.dataTable thead > tr > th.dt-orderable-asc span.dt-column-order:before, table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order:before,
-table.dataTable thead > tr > td.dt-orderable-asc span.dt-column-order:before,
-table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order:before {
- position: absolute;
- display: block;
- bottom: 50%;
- content: "\25B2";
- content: "\25B2"/"";
-}
-table.dataTable thead > tr > th.dt-orderable-desc span.dt-column-order:after, table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order:after,
-table.dataTable thead > tr > td.dt-orderable-desc span.dt-column-order:after,
-table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order:after {
- position: absolute;
- display: block;
- top: 50%;
- content: "\25BC";
- content: "\25BC"/"";
-}
-table.dataTable thead > tr > th.dt-orderable-asc span.dt-column-order, table.dataTable thead > tr > th.dt-orderable-desc span.dt-column-order, table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order, table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order,
-table.dataTable thead > tr > td.dt-orderable-asc span.dt-column-order,
-table.dataTable thead > tr > td.dt-orderable-desc span.dt-column-order,
-table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order,
-table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order {
- position: relative;
- width: 12px;
- height: 20px;
-}
-table.dataTable thead > tr > th.dt-orderable-asc span.dt-column-order:before, table.dataTable thead > tr > th.dt-orderable-asc span.dt-column-order:after, table.dataTable thead > tr > th.dt-orderable-desc span.dt-column-order:before, table.dataTable thead > tr > th.dt-orderable-desc span.dt-column-order:after, table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order:before, table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order:after, table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order:before, table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order:after,
-table.dataTable thead > tr > td.dt-orderable-asc span.dt-column-order:before,
-table.dataTable thead > tr > td.dt-orderable-asc span.dt-column-order:after,
-table.dataTable thead > tr > td.dt-orderable-desc span.dt-column-order:before,
-table.dataTable thead > tr > td.dt-orderable-desc span.dt-column-order:after,
-table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order:before,
-table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order:after,
-table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order:before,
-table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order:after {
- left: 0;
- opacity: 0.125;
- line-height: 9px;
- font-size: 0.8em;
-}
-table.dataTable thead > tr > th.dt-orderable-asc, table.dataTable thead > tr > th.dt-orderable-desc,
-table.dataTable thead > tr > td.dt-orderable-asc,
-table.dataTable thead > tr > td.dt-orderable-desc {
- cursor: pointer;
-}
-table.dataTable thead > tr > th.dt-orderable-asc:hover, table.dataTable thead > tr > th.dt-orderable-desc:hover,
-table.dataTable thead > tr > td.dt-orderable-asc:hover,
-table.dataTable thead > tr > td.dt-orderable-desc:hover {
- outline: 2px solid rgba(0, 0, 0, 0.05);
- outline-offset: -2px;
-}
-table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order:before, table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order:after,
-table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order:before,
-table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order:after {
- opacity: 0.6;
-}
-table.dataTable thead > tr > th.sorting_desc_disabled span.dt-column-order:after, table.dataTable thead > tr > th.sorting_asc_disabled span.dt-column-order:before,
-table.dataTable thead > tr > td.sorting_desc_disabled span.dt-column-order:after,
-table.dataTable thead > tr > td.sorting_asc_disabled span.dt-column-order:before {
- display: none;
-}
-table.dataTable thead > tr > th:active,
-table.dataTable thead > tr > td:active {
- outline: none;
-}
-
-table.dataTable thead > tr > th div.dt-column-header,
-table.dataTable thead > tr > th div.dt-column-footer,
-table.dataTable thead > tr > td div.dt-column-header,
-table.dataTable thead > tr > td div.dt-column-footer,
-table.dataTable tfoot > tr > th div.dt-column-header,
-table.dataTable tfoot > tr > th div.dt-column-footer,
-table.dataTable tfoot > tr > td div.dt-column-header,
-table.dataTable tfoot > tr > td div.dt-column-footer {
- display: flex;
- justify-content: space-between;
- align-items: center;
- gap: 4px;
-}
-table.dataTable thead > tr > th div.dt-column-header span.dt-column-title,
-table.dataTable thead > tr > th div.dt-column-footer span.dt-column-title,
-table.dataTable thead > tr > td div.dt-column-header span.dt-column-title,
-table.dataTable thead > tr > td div.dt-column-footer span.dt-column-title,
-table.dataTable tfoot > tr > th div.dt-column-header span.dt-column-title,
-table.dataTable tfoot > tr > th div.dt-column-footer span.dt-column-title,
-table.dataTable tfoot > tr > td div.dt-column-header span.dt-column-title,
-table.dataTable tfoot > tr > td div.dt-column-footer span.dt-column-title {
- flex-grow: 1;
-}
-table.dataTable thead > tr > th div.dt-column-header span.dt-column-title:empty,
-table.dataTable thead > tr > th div.dt-column-footer span.dt-column-title:empty,
-table.dataTable thead > tr > td div.dt-column-header span.dt-column-title:empty,
-table.dataTable thead > tr > td div.dt-column-footer span.dt-column-title:empty,
-table.dataTable tfoot > tr > th div.dt-column-header span.dt-column-title:empty,
-table.dataTable tfoot > tr > th div.dt-column-footer span.dt-column-title:empty,
-table.dataTable tfoot > tr > td div.dt-column-header span.dt-column-title:empty,
-table.dataTable tfoot > tr > td div.dt-column-footer span.dt-column-title:empty {
- display: none;
-}
-
-div.dt-scroll-body > table.dataTable > thead > tr > th,
-div.dt-scroll-body > table.dataTable > thead > tr > td {
- overflow: hidden;
-}
-
-:root.dark table.dataTable thead > tr > th.dt-orderable-asc:hover, :root.dark table.dataTable thead > tr > th.dt-orderable-desc:hover,
-:root.dark table.dataTable thead > tr > td.dt-orderable-asc:hover,
-:root.dark table.dataTable thead > tr > td.dt-orderable-desc:hover,
-:root[data-bs-theme=dark] table.dataTable thead > tr > th.dt-orderable-asc:hover,
-:root[data-bs-theme=dark] table.dataTable thead > tr > th.dt-orderable-desc:hover,
-:root[data-bs-theme=dark] table.dataTable thead > tr > td.dt-orderable-asc:hover,
-:root[data-bs-theme=dark] table.dataTable thead > tr > td.dt-orderable-desc:hover {
- outline: 2px solid rgba(255, 255, 255, 0.05);
-}
-
-div.dt-processing {
- position: absolute;
- top: 50%;
- left: 50%;
- width: 200px;
- margin-left: -100px;
- margin-top: -22px;
- text-align: center;
- padding: 2px;
- z-index: 10;
-}
-div.dt-processing > div:last-child {
- position: relative;
- width: 80px;
- height: 15px;
- margin: 1em auto;
-}
-div.dt-processing > div:last-child > div {
- position: absolute;
- top: 0;
- width: 13px;
- height: 13px;
- border-radius: 50%;
- background: rgb(13, 110, 253);
- background: rgb(var(--dt-row-selected));
- animation-timing-function: cubic-bezier(0, 1, 1, 0);
-}
-div.dt-processing > div:last-child > div:nth-child(1) {
- left: 8px;
- animation: datatables-loader-1 0.6s infinite;
-}
-div.dt-processing > div:last-child > div:nth-child(2) {
- left: 8px;
- animation: datatables-loader-2 0.6s infinite;
-}
-div.dt-processing > div:last-child > div:nth-child(3) {
- left: 32px;
- animation: datatables-loader-2 0.6s infinite;
-}
-div.dt-processing > div:last-child > div:nth-child(4) {
- left: 56px;
- animation: datatables-loader-3 0.6s infinite;
-}
-
-@keyframes datatables-loader-1 {
- 0% {
- transform: scale(0);
- }
- 100% {
- transform: scale(1);
- }
-}
-@keyframes datatables-loader-3 {
- 0% {
- transform: scale(1);
- }
- 100% {
- transform: scale(0);
- }
-}
-@keyframes datatables-loader-2 {
- 0% {
- transform: translate(0, 0);
- }
- 100% {
- transform: translate(24px, 0);
- }
-}
-table.dataTable.nowrap th, table.dataTable.nowrap td {
- white-space: nowrap;
-}
-table.dataTable th,
-table.dataTable td {
- box-sizing: border-box;
-}
-table.dataTable th.dt-type-numeric, table.dataTable th.dt-type-date,
-table.dataTable td.dt-type-numeric,
-table.dataTable td.dt-type-date {
- text-align: right;
-}
-table.dataTable th.dt-type-numeric div.dt-column-header,
-table.dataTable th.dt-type-numeric div.dt-column-footer, table.dataTable th.dt-type-date div.dt-column-header,
-table.dataTable th.dt-type-date div.dt-column-footer,
-table.dataTable td.dt-type-numeric div.dt-column-header,
-table.dataTable td.dt-type-numeric div.dt-column-footer,
-table.dataTable td.dt-type-date div.dt-column-header,
-table.dataTable td.dt-type-date div.dt-column-footer {
- flex-direction: row-reverse;
-}
-table.dataTable th.dt-left,
-table.dataTable td.dt-left {
- text-align: left;
-}
-table.dataTable th.dt-center,
-table.dataTable td.dt-center {
- text-align: center;
-}
-table.dataTable th.dt-right,
-table.dataTable td.dt-right {
- text-align: right;
-}
-table.dataTable th.dt-right div.dt-column-header,
-table.dataTable th.dt-right div.dt-column-footer,
-table.dataTable td.dt-right div.dt-column-header,
-table.dataTable td.dt-right div.dt-column-footer {
- flex-direction: row-reverse;
-}
-table.dataTable th.dt-justify,
-table.dataTable td.dt-justify {
- text-align: justify;
-}
-table.dataTable th.dt-nowrap,
-table.dataTable td.dt-nowrap {
- white-space: nowrap;
-}
-table.dataTable th.dt-empty,
-table.dataTable td.dt-empty {
- text-align: center;
- vertical-align: top;
-}
-table.dataTable thead th,
-table.dataTable thead td,
-table.dataTable tfoot th,
-table.dataTable tfoot td {
- text-align: left;
-}
-table.dataTable thead th.dt-head-left,
-table.dataTable thead td.dt-head-left,
-table.dataTable tfoot th.dt-head-left,
-table.dataTable tfoot td.dt-head-left {
- text-align: left;
-}
-table.dataTable thead th.dt-head-center,
-table.dataTable thead td.dt-head-center,
-table.dataTable tfoot th.dt-head-center,
-table.dataTable tfoot td.dt-head-center {
- text-align: center;
-}
-table.dataTable thead th.dt-head-right,
-table.dataTable thead td.dt-head-right,
-table.dataTable tfoot th.dt-head-right,
-table.dataTable tfoot td.dt-head-right {
- text-align: right;
-}
-table.dataTable thead th.dt-head-right div.dt-column-header,
-table.dataTable thead th.dt-head-right div.dt-column-footer,
-table.dataTable thead td.dt-head-right div.dt-column-header,
-table.dataTable thead td.dt-head-right div.dt-column-footer,
-table.dataTable tfoot th.dt-head-right div.dt-column-header,
-table.dataTable tfoot th.dt-head-right div.dt-column-footer,
-table.dataTable tfoot td.dt-head-right div.dt-column-header,
-table.dataTable tfoot td.dt-head-right div.dt-column-footer {
- flex-direction: row-reverse;
-}
-table.dataTable thead th.dt-head-justify,
-table.dataTable thead td.dt-head-justify,
-table.dataTable tfoot th.dt-head-justify,
-table.dataTable tfoot td.dt-head-justify {
- text-align: justify;
-}
-table.dataTable thead th.dt-head-nowrap,
-table.dataTable thead td.dt-head-nowrap,
-table.dataTable tfoot th.dt-head-nowrap,
-table.dataTable tfoot td.dt-head-nowrap {
- white-space: nowrap;
-}
-table.dataTable tbody th.dt-body-left,
-table.dataTable tbody td.dt-body-left {
- text-align: left;
-}
-table.dataTable tbody th.dt-body-center,
-table.dataTable tbody td.dt-body-center {
- text-align: center;
-}
-table.dataTable tbody th.dt-body-right,
-table.dataTable tbody td.dt-body-right {
- text-align: right;
-}
-table.dataTable tbody th.dt-body-justify,
-table.dataTable tbody td.dt-body-justify {
- text-align: justify;
-}
-table.dataTable tbody th.dt-body-nowrap,
-table.dataTable tbody td.dt-body-nowrap {
- white-space: nowrap;
-}
-
-/*! Bootstrap 5 integration for DataTables
- *
- * ©2020 SpryMedia Ltd, all rights reserved.
- * License: MIT datatables.net/license/mit
- */
-table.table.dataTable {
- clear: both;
- margin-bottom: 0;
- max-width: none;
- border-spacing: 0;
-}
-table.table.dataTable.table-striped > tbody > tr:nth-of-type(2n+1) > * {
- box-shadow: none;
-}
-table.table.dataTable > :not(caption) > * > * {
- background-color: var(--bs-table-bg);
-}
-table.table.dataTable > tbody > tr {
- background-color: transparent;
-}
-table.table.dataTable > tbody > tr.selected > * {
- box-shadow: inset 0 0 0 9999px rgb(13, 110, 253);
- box-shadow: inset 0 0 0 9999px rgb(var(--dt-row-selected));
- color: rgb(255, 255, 255);
- color: rgb(var(--dt-row-selected-text));
-}
-table.table.dataTable > tbody > tr.selected a {
- color: rgb(9, 10, 11);
- color: rgb(var(--dt-row-selected-link));
-}
-table.table.dataTable.table-striped > tbody > tr:nth-of-type(2n+1) > * {
- box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-stripe), 0.05);
-}
-table.table.dataTable.table-striped > tbody > tr:nth-of-type(2n+1).selected > * {
- box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.95);
- box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.95);
-}
-table.table.dataTable.table-hover > tbody > tr:hover > * {
- box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.075);
-}
-table.table.dataTable.table-hover > tbody > tr.selected:hover > * {
- box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.975);
- box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.975);
-}
-
-div.dt-container div.dt-layout-start > *:not(:last-child) {
- margin-right: 1em;
-}
-div.dt-container div.dt-layout-end > *:not(:first-child) {
- margin-left: 1em;
-}
-div.dt-container div.dt-layout-full {
- width: 100%;
-}
-div.dt-container div.dt-layout-full > *:only-child {
- margin-left: auto;
- margin-right: auto;
-}
-div.dt-container div.dt-layout-table > div {
- display: block !important;
-}
-
-@media screen and (max-width: 767px) {
- div.dt-container div.dt-layout-start > *:not(:last-child) {
- margin-right: 0;
- }
- div.dt-container div.dt-layout-end > *:not(:first-child) {
- margin-left: 0;
- }
-}
-div.dt-container {
- position: relative;
-}
-div.dt-container div.dt-length label {
- font-weight: normal;
- text-align: left;
- white-space: nowrap;
-}
-div.dt-container div.dt-length select {
- width: auto;
- display: inline-block;
- margin-right: 0.5em;
-}
-div.dt-container div.dt-search {
- text-align: right;
-}
-div.dt-container div.dt-search label {
- font-weight: normal;
- white-space: nowrap;
- text-align: left;
-}
-div.dt-container div.dt-search input {
- margin-left: 0.5em;
- display: inline-block;
- width: auto;
-}
-div.dt-container div.dt-paging {
- margin: 0;
-}
-div.dt-container div.dt-paging ul.pagination {
- margin: 2px 0;
- flex-wrap: wrap;
-}
-div.dt-container div.dt-row {
- position: relative;
-}
-
-div.dt-scroll-head table.dataTable {
- margin-bottom: 0 !important;
-}
-
-div.dt-scroll-body {
- border-bottom-color: var(--bs-border-color);
- border-bottom-width: var(--bs-border-width);
- border-bottom-style: solid;
-}
-div.dt-scroll-body > table {
- border-top: none;
- margin-top: 0 !important;
- margin-bottom: 0 !important;
-}
-div.dt-scroll-body > table > tbody > tr:first-child {
- border-top-width: 0;
-}
-div.dt-scroll-body > table > thead > tr {
- border-width: 0 !important;
-}
-div.dt-scroll-body > table > tbody > tr:last-child > * {
- border-bottom: none;
-}
-
-div.dt-scroll-foot > .dt-scroll-footInner {
- box-sizing: content-box;
-}
-div.dt-scroll-foot > .dt-scroll-footInner > table {
- margin-top: 0 !important;
- border-top: none;
-}
-div.dt-scroll-foot > .dt-scroll-footInner > table > tfoot > tr:first-child {
- border-top-width: 0 !important;
-}
-
-@media screen and (max-width: 767px) {
- div.dt-container div.dt-length,
- div.dt-container div.dt-search,
- div.dt-container div.dt-info,
- div.dt-container div.dt-paging {
- text-align: center;
- }
- div.dt-container .row {
- --bs-gutter-y: 0.5rem;
- }
- div.dt-container div.dt-paging ul.pagination {
- justify-content: center !important;
- }
-}
-table.dataTable.table-sm > thead > tr th.dt-orderable-asc, table.dataTable.table-sm > thead > tr th.dt-orderable-desc, table.dataTable.table-sm > thead > tr th.dt-ordering-asc, table.dataTable.table-sm > thead > tr th.dt-ordering-desc,
-table.dataTable.table-sm > thead > tr td.dt-orderable-asc,
-table.dataTable.table-sm > thead > tr td.dt-orderable-desc,
-table.dataTable.table-sm > thead > tr td.dt-ordering-asc,
-table.dataTable.table-sm > thead > tr td.dt-ordering-desc {
- padding-right: 20px;
-}
-table.dataTable.table-sm > thead > tr th.dt-orderable-asc span.dt-column-order, table.dataTable.table-sm > thead > tr th.dt-orderable-desc span.dt-column-order, table.dataTable.table-sm > thead > tr th.dt-ordering-asc span.dt-column-order, table.dataTable.table-sm > thead > tr th.dt-ordering-desc span.dt-column-order,
-table.dataTable.table-sm > thead > tr td.dt-orderable-asc span.dt-column-order,
-table.dataTable.table-sm > thead > tr td.dt-orderable-desc span.dt-column-order,
-table.dataTable.table-sm > thead > tr td.dt-ordering-asc span.dt-column-order,
-table.dataTable.table-sm > thead > tr td.dt-ordering-desc span.dt-column-order {
- right: 5px;
-}
-
-div.dt-scroll-head table.table-bordered {
- border-bottom-width: 0;
-}
-
-div.table-responsive > div.dt-container > div.row {
- margin: 0;
-}
-div.table-responsive > div.dt-container > div.row > div[class^=col-]:first-child {
- padding-left: 0;
-}
-div.table-responsive > div.dt-container > div.row > div[class^=col-]:last-child {
- padding-right: 0;
-}
-
-:root[data-bs-theme=dark] {
- --dt-row-hover: 255, 255, 255;
- --dt-row-stripe: 255, 255, 255;
- --dt-column-ordering: 255, 255, 255;
-}
diff --git a/public/datatables/responsive.bootstrap5.css b/public/datatables/responsive.bootstrap5.css
deleted file mode 100644
index ce6fcb54..00000000
--- a/public/datatables/responsive.bootstrap5.css
+++ /dev/null
@@ -1,203 +0,0 @@
-table.dataTable.dtr-inline.collapsed > tbody > tr > td.child,
-table.dataTable.dtr-inline.collapsed > tbody > tr > th.child,
-table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty {
- cursor: default !important;
-}
-table.dataTable.dtr-inline.collapsed > tbody > tr > td.child:before,
-table.dataTable.dtr-inline.collapsed > tbody > tr > th.child:before,
-table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty:before {
- display: none !important;
-}
-table.dataTable.dtr-inline.collapsed > tbody > tr > td.dtr-control,
-table.dataTable.dtr-inline.collapsed > tbody > tr > th.dtr-control {
- cursor: pointer;
-}
-table.dataTable.dtr-inline.collapsed > tbody > tr > td.dtr-control:before,
-table.dataTable.dtr-inline.collapsed > tbody > tr > th.dtr-control:before {
- margin-right: 0.5em;
- display: inline-block;
- box-sizing: border-box;
- content: "";
- border-top: 5px solid transparent;
- border-left: 10px solid rgba(0, 0, 0, 0.5);
- border-bottom: 5px solid transparent;
- border-right: 0px solid transparent;
-}
-table.dataTable.dtr-inline.collapsed > tbody > tr > td.dtr-control.arrow-right::before,
-table.dataTable.dtr-inline.collapsed > tbody > tr > th.dtr-control.arrow-right::before {
- border-top: 5px solid transparent;
- border-left: 0px solid transparent;
- border-bottom: 5px solid transparent;
- border-right: 10px solid rgba(0, 0, 0, 0.5);
-}
-table.dataTable.dtr-inline.collapsed > tbody > tr.dtr-expanded > td.dtr-control:before,
-table.dataTable.dtr-inline.collapsed > tbody > tr.dtr-expanded > th.dtr-control:before {
- border-top: 10px solid rgba(0, 0, 0, 0.5);
- border-left: 5px solid transparent;
- border-bottom: 0px solid transparent;
- border-right: 5px solid transparent;
-}
-table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td.dtr-control,
-table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th.dtr-control {
- padding-left: 0.333em;
-}
-table.dataTable.dtr-column > tbody > tr > td.dtr-control,
-table.dataTable.dtr-column > tbody > tr > th.dtr-control,
-table.dataTable.dtr-column > tbody > tr > td.control,
-table.dataTable.dtr-column > tbody > tr > th.control {
- cursor: pointer;
-}
-table.dataTable.dtr-column > tbody > tr > td.dtr-control:before,
-table.dataTable.dtr-column > tbody > tr > th.dtr-control:before,
-table.dataTable.dtr-column > tbody > tr > td.control:before,
-table.dataTable.dtr-column > tbody > tr > th.control:before {
- display: inline-block;
- box-sizing: border-box;
- content: "";
- border-top: 5px solid transparent;
- border-left: 10px solid rgba(0, 0, 0, 0.5);
- border-bottom: 5px solid transparent;
- border-right: 0px solid transparent;
-}
-table.dataTable.dtr-column > tbody > tr > td.dtr-control.arrow-right::before,
-table.dataTable.dtr-column > tbody > tr > th.dtr-control.arrow-right::before,
-table.dataTable.dtr-column > tbody > tr > td.control.arrow-right::before,
-table.dataTable.dtr-column > tbody > tr > th.control.arrow-right::before {
- border-top: 5px solid transparent;
- border-left: 0px solid transparent;
- border-bottom: 5px solid transparent;
- border-right: 10px solid rgba(0, 0, 0, 0.5);
-}
-table.dataTable.dtr-column > tbody > tr.dtr-expanded td.dtr-control:before,
-table.dataTable.dtr-column > tbody > tr.dtr-expanded th.dtr-control:before,
-table.dataTable.dtr-column > tbody > tr.dtr-expanded td.control:before,
-table.dataTable.dtr-column > tbody > tr.dtr-expanded th.control:before {
- border-top: 10px solid rgba(0, 0, 0, 0.5);
- border-left: 5px solid transparent;
- border-bottom: 0px solid transparent;
- border-right: 5px solid transparent;
-}
-table.dataTable > tbody > tr.child {
- padding: 0.5em 1em;
-}
-table.dataTable > tbody > tr.child:hover {
- background: transparent !important;
-}
-table.dataTable > tbody > tr.child ul.dtr-details {
- display: inline-block;
- list-style-type: none;
- margin: 0;
- padding: 0;
-}
-table.dataTable > tbody > tr.child ul.dtr-details > li {
- border-bottom: 1px solid #efefef;
- padding: 0.5em 0;
-}
-table.dataTable > tbody > tr.child ul.dtr-details > li:first-child {
- padding-top: 0;
-}
-table.dataTable > tbody > tr.child ul.dtr-details > li:last-child {
- padding-bottom: 0;
- border-bottom: none;
-}
-table.dataTable > tbody > tr.child span.dtr-title {
- display: inline-block;
- min-width: 75px;
- font-weight: bold;
-}
-
-div.dtr-modal {
- position: fixed;
- box-sizing: border-box;
- top: 0;
- left: 0;
- height: 100%;
- width: 100%;
- z-index: 100;
- padding: 10em 1em;
-}
-div.dtr-modal div.dtr-modal-display {
- position: absolute;
- top: 0;
- left: 0;
- bottom: 0;
- right: 0;
- width: 50%;
- height: fit-content;
- max-height: 75%;
- overflow: auto;
- margin: auto;
- z-index: 102;
- overflow: auto;
- background-color: #f5f5f7;
- border: 1px solid black;
- border-radius: 0.5em;
- box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6);
-}
-div.dtr-modal div.dtr-modal-content {
- position: relative;
- padding: 2.5em;
-}
-div.dtr-modal div.dtr-modal-content h2 {
- margin-top: 0;
-}
-div.dtr-modal div.dtr-modal-close {
- position: absolute;
- top: 6px;
- right: 6px;
- width: 22px;
- height: 22px;
- text-align: center;
- border-radius: 3px;
- cursor: pointer;
- z-index: 12;
-}
-div.dtr-modal div.dtr-modal-background {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- z-index: 101;
- background: rgba(0, 0, 0, 0.6);
-}
-
-@media screen and (max-width: 767px) {
- div.dtr-modal div.dtr-modal-display {
- width: 95%;
- }
-}
-html.dark table.dataTable > tbody > tr > td.dtr-control:before,
-html[data-bs-theme=dark] table.dataTable > tbody > tr > td.dtr-control:before {
- border-left-color: rgba(255, 255, 255, 0.5) !important;
-}
-html.dark table.dataTable > tbody > tr > td.dtr-control.arrow-right::before,
-html[data-bs-theme=dark] table.dataTable > tbody > tr > td.dtr-control.arrow-right::before {
- border-right-color: rgba(255, 255, 255, 0.5) !important;
-}
-html.dark table.dataTable > tbody > tr.dtr-expanded > td.dtr-control:before,
-html.dark table.dataTable > tbody > tr.dtr-expanded > th.dtr-control:before,
-html[data-bs-theme=dark] table.dataTable > tbody > tr.dtr-expanded > td.dtr-control:before,
-html[data-bs-theme=dark] table.dataTable > tbody > tr.dtr-expanded > th.dtr-control:before {
- border-top-color: rgba(255, 255, 255, 0.5) !important;
- border-left-color: transparent !important;
- border-right-color: transparent !important;
-}
-html.dark table.dataTable > tbody > tr.child ul.dtr-details > li,
-html[data-bs-theme=dark] table.dataTable > tbody > tr.child ul.dtr-details > li {
- border-bottom-color: rgb(64, 67, 70);
-}
-html.dark div.dtr-modal div.dtr-modal-display,
-html[data-bs-theme=dark] div.dtr-modal div.dtr-modal-display {
- background-color: rgb(33, 37, 41);
- border: 1px solid rgba(255, 255, 255, 0.15);
-}
-
-div.dtr-bs-modal table.table tr:first-child td {
- border-top: none;
-}
-
-table.dataTable.table-bordered th.dtr-control.dtr-hidden + *,
-table.dataTable.table-bordered td.dtr-control.dtr-hidden + * {
- border-left-width: 1px;
-}