diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d6809cae..4e323710 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -115,7 +115,7 @@ jobs: run: bin/rails db:test:prepare spec - name: Keep screenshots from failed system tests - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 if: failure() with: name: screenshots diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 74d820c5..982eae35 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -22,10 +22,10 @@ jobs: uses: actions/checkout@v6 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v4 - name: Setup SSH - uses: webfactory/ssh-agent@v0.9.1 + uses: webfactory/ssh-agent@v0.10.0 with: ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} diff --git a/Gemfile b/Gemfile index 68494bae..d3f81e7a 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,7 @@ source "https://rubygems.org" # Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main" -gem "rails", "~> 8.1.1" +gem "rails", "~> 8.1.3" # The modern asset pipeline for Rails [https://github.com/rails/propshaft] gem "propshaft" # Use sqlite3 as the database for Active Record @@ -40,7 +40,7 @@ gem "thruster", require: false gem "vite_rails", "~> 3.0" # The Rails adapter for Inertia.js [https://inertia-rails.dev] -gem "inertia_rails", "~> 3.6" +gem "inertia_rails", "~> 3.19" # An authentication system generator for Rails applications # we leave gem here to watch for security updates diff --git a/Gemfile.lock b/Gemfile.lock index 01a7d9ff..012657c0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,31 +1,31 @@ GEM remote: https://rubygems.org/ specs: - action_text-trix (2.1.16) + action_text-trix (2.1.18) railties - actioncable (8.1.2) - actionpack (= 8.1.2) - activesupport (= 8.1.2) + actioncable (8.1.3) + actionpack (= 8.1.3) + activesupport (= 8.1.3) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (8.1.2) - actionpack (= 8.1.2) - activejob (= 8.1.2) - activerecord (= 8.1.2) - activestorage (= 8.1.2) - activesupport (= 8.1.2) + actionmailbox (8.1.3) + actionpack (= 8.1.3) + activejob (= 8.1.3) + activerecord (= 8.1.3) + activestorage (= 8.1.3) + activesupport (= 8.1.3) mail (>= 2.8.0) - actionmailer (8.1.2) - actionpack (= 8.1.2) - actionview (= 8.1.2) - activejob (= 8.1.2) - activesupport (= 8.1.2) + actionmailer (8.1.3) + actionpack (= 8.1.3) + actionview (= 8.1.3) + activejob (= 8.1.3) + activesupport (= 8.1.3) mail (>= 2.8.0) rails-dom-testing (~> 2.2) - actionpack (8.1.2) - actionview (= 8.1.2) - activesupport (= 8.1.2) + actionpack (8.1.3) + actionview (= 8.1.3) + activesupport (= 8.1.3) nokogiri (>= 1.8.5) rack (>= 2.2.4) rack-session (>= 1.0.1) @@ -33,36 +33,36 @@ GEM rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) useragent (~> 0.16) - actiontext (8.1.2) + actiontext (8.1.3) action_text-trix (~> 2.1.15) - actionpack (= 8.1.2) - activerecord (= 8.1.2) - activestorage (= 8.1.2) - activesupport (= 8.1.2) + actionpack (= 8.1.3) + activerecord (= 8.1.3) + activestorage (= 8.1.3) + activesupport (= 8.1.3) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (8.1.2) - activesupport (= 8.1.2) + actionview (8.1.3) + activesupport (= 8.1.3) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - activejob (8.1.2) - activesupport (= 8.1.2) + activejob (8.1.3) + activesupport (= 8.1.3) globalid (>= 0.3.6) - activemodel (8.1.2) - activesupport (= 8.1.2) - activerecord (8.1.2) - activemodel (= 8.1.2) - activesupport (= 8.1.2) + activemodel (8.1.3) + activesupport (= 8.1.3) + activerecord (8.1.3) + activemodel (= 8.1.3) + activesupport (= 8.1.3) timeout (>= 0.4.0) - activestorage (8.1.2) - actionpack (= 8.1.2) - activejob (= 8.1.2) - activerecord (= 8.1.2) - activesupport (= 8.1.2) + activestorage (8.1.3) + actionpack (= 8.1.3) + activejob (= 8.1.3) + activerecord (= 8.1.3) + activesupport (= 8.1.3) marcel (~> 1.0) - activesupport (8.1.2) + activesupport (8.1.3) base64 bigdecimal concurrent-ruby (~> 1.0, >= 1.3.1) @@ -80,13 +80,13 @@ GEM ast (2.4.3) authentication-zero (4.0.3) base64 (0.3.0) - bcrypt (3.1.21) + bcrypt (3.1.22) bcrypt_pbkdf (1.1.2) bigdecimal (4.0.1) bindex (0.8.1) bootsnap (1.23.0) msgpack (~> 1.2) - brakeman (8.0.2) + brakeman (8.0.4) racc builder (3.3.0) bundler-audit (0.9.3) @@ -101,10 +101,9 @@ GEM rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) - capybara-lockstep (2.3.0) - activesupport (>= 4.2) + capybara-lockstep (2.3.1) + activesupport (>= 7.0) capybara (>= 3.0) - ruby2_keywords childprocess (5.1.0) logger (~> 1.5) concurrent-ruby (1.3.6) @@ -119,7 +118,7 @@ GEM drb (2.2.3) dry-cli (1.4.1) ed25519 (1.4.0) - erb (6.0.1) + erb (6.0.2) erubi (1.13.1) et-orbi (1.4.0) tzinfo @@ -135,7 +134,7 @@ GEM activesupport (>= 6.1) i18n (1.14.8) concurrent-ruby (~> 1.0) - inertia_rails (3.17.0) + inertia_rails (3.19.0) railties (>= 6) io-console (0.8.2) irb (1.17.0) @@ -149,8 +148,8 @@ GEM js-routes (2.3.6) railties (>= 5) sorbet-runtime - json (2.18.1) - kamal (2.10.1) + json (2.19.2) + kamal (2.11.0) activesupport (>= 7.0) base64 (~> 0.2) bcrypt_pbkdf (~> 1.0) @@ -170,7 +169,7 @@ GEM launchy (>= 2.2, < 4) lint_roller (1.1.0) logger (1.7.0) - loofah (2.25.0) + loofah (2.25.1) crass (~> 1.0.2) nokogiri (>= 1.12.0) mail (2.9.0) @@ -182,7 +181,8 @@ GEM marcel (1.1.0) matrix (0.4.3) mini_mime (1.1.5) - minitest (6.0.1) + minitest (6.0.2) + drb (~> 2.0) prism (~> 1.5) msgpack (1.8.0) mutex_m (0.3.0) @@ -199,21 +199,21 @@ GEM net-ssh (>= 5.0.0, < 8.0.0) net-smtp (0.5.1) net-protocol - net-ssh (7.3.0) + net-ssh (7.3.2) nio4r (2.7.5) - nokogiri (1.19.0-aarch64-linux-gnu) + nokogiri (1.19.2-aarch64-linux-gnu) racc (~> 1.4) - nokogiri (1.19.0-aarch64-linux-musl) + nokogiri (1.19.2-aarch64-linux-musl) racc (~> 1.4) - nokogiri (1.19.0-arm-linux-gnu) + nokogiri (1.19.2-arm-linux-gnu) racc (~> 1.4) - nokogiri (1.19.0-arm-linux-musl) + nokogiri (1.19.2-arm-linux-musl) racc (~> 1.4) - nokogiri (1.19.0-arm64-darwin) + nokogiri (1.19.2-arm64-darwin) racc (~> 1.4) - nokogiri (1.19.0-x86_64-linux-gnu) + nokogiri (1.19.2-x86_64-linux-gnu) racc (~> 1.4) - nokogiri (1.19.0-x86_64-linux-musl) + nokogiri (1.19.2-x86_64-linux-musl) racc (~> 1.4) ostruct (0.6.3) parallel (1.27.0) @@ -236,7 +236,7 @@ GEM nio4r (~> 2.0) raabro (1.4.0) racc (1.8.1) - rack (3.2.4) + rack (3.2.5) rack-proxy (0.7.7) rack rack-session (2.1.1) @@ -246,30 +246,30 @@ GEM rack (>= 1.3) rackup (2.3.1) rack (>= 3) - rails (8.1.2) - actioncable (= 8.1.2) - actionmailbox (= 8.1.2) - actionmailer (= 8.1.2) - actionpack (= 8.1.2) - actiontext (= 8.1.2) - actionview (= 8.1.2) - activejob (= 8.1.2) - activemodel (= 8.1.2) - activerecord (= 8.1.2) - activestorage (= 8.1.2) - activesupport (= 8.1.2) + rails (8.1.3) + actioncable (= 8.1.3) + actionmailbox (= 8.1.3) + actionmailer (= 8.1.3) + actionpack (= 8.1.3) + actiontext (= 8.1.3) + actionview (= 8.1.3) + activejob (= 8.1.3) + activemodel (= 8.1.3) + activerecord (= 8.1.3) + activestorage (= 8.1.3) + activesupport (= 8.1.3) bundler (>= 1.15.0) - railties (= 8.1.2) + railties (= 8.1.3) rails-dom-testing (2.3.0) activesupport (>= 5.0.0) minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.6.2) - loofah (~> 2.21) + rails-html-sanitizer (1.7.0) + loofah (~> 2.25) nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) - railties (8.1.2) - actionpack (= 8.1.2) - activesupport (= 8.1.2) + railties (8.1.3) + actionpack (= 8.1.3) + activesupport (= 8.1.3) irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) @@ -291,17 +291,17 @@ GEM rspec-expectations (3.13.5) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) - rspec-mocks (3.13.7) + rspec-mocks (3.13.8) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) - rspec-rails (8.0.2) + rspec-rails (8.0.4) actionpack (>= 7.2) activesupport (>= 7.2) railties (>= 7.2) - rspec-core (~> 3.13) - rspec-expectations (~> 3.13) - rspec-mocks (~> 3.13) - rspec-support (~> 3.13) + rspec-core (>= 3.13.0, < 5.0.0) + rspec-expectations (>= 3.13.0, < 5.0.0) + rspec-mocks (>= 3.13.0, < 5.0.0) + rspec-support (>= 3.13.0, < 5.0.0) rspec-support (3.13.7) rubocop (1.84.2) json (~> 2.3) @@ -332,10 +332,9 @@ GEM rubocop-performance (>= 1.24) rubocop-rails (>= 2.30) ruby-progressbar (1.13.0) - ruby2_keywords (0.0.5) rubyzip (3.2.2) securerandom (0.4.1) - selenium-webdriver (4.40.0) + selenium-webdriver (4.41.0) base64 (~> 0.2) logger (~> 1.4) rexml (~> 3.2, >= 3.2.5) @@ -350,7 +349,7 @@ GEM activejob (>= 7.2) activerecord (>= 7.2) railties (>= 7.2) - solid_queue (1.3.1) + solid_queue (1.4.0) activejob (>= 7.1) activerecord (>= 7.1) concurrent-ruby (>= 1.3.1) @@ -358,13 +357,13 @@ GEM railties (>= 7.1) thor (>= 1.3.1) sorbet-runtime (0.6.12940) - sqlite3 (2.9.0-aarch64-linux-gnu) - sqlite3 (2.9.0-aarch64-linux-musl) - sqlite3 (2.9.0-arm-linux-gnu) - sqlite3 (2.9.0-arm-linux-musl) - sqlite3 (2.9.0-arm64-darwin) - sqlite3 (2.9.0-x86_64-linux-gnu) - sqlite3 (2.9.0-x86_64-linux-musl) + sqlite3 (2.9.2-aarch64-linux-gnu) + sqlite3 (2.9.2-aarch64-linux-musl) + sqlite3 (2.9.2-arm-linux-gnu) + sqlite3 (2.9.2-arm-linux-musl) + sqlite3 (2.9.2-arm64-darwin) + sqlite3 (2.9.2-x86_64-linux-gnu) + sqlite3 (2.9.2-x86_64-linux-musl) sshkit (1.25.0) base64 logger @@ -374,11 +373,11 @@ GEM ostruct stringio (3.2.0) thor (1.5.0) - thruster (0.1.18) - thruster (0.1.18-aarch64-linux) - thruster (0.1.18-arm64-darwin) - thruster (0.1.18-x86_64-linux) - timeout (0.6.0) + thruster (0.1.19) + thruster (0.1.19-aarch64-linux) + thruster (0.1.19-arm64-darwin) + thruster (0.1.19-x86_64-linux) + timeout (0.6.1) tsort (0.2.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) @@ -396,11 +395,10 @@ GEM mutex_m rack-proxy (~> 0.6, >= 0.6.1) zeitwerk (~> 2.2) - web-console (4.2.1) - actionview (>= 6.0.0) - activemodel (>= 6.0.0) + web-console (4.3.0) + actionview (>= 8.0.0) bindex (>= 0.4.0) - railties (>= 6.0.0) + railties (>= 8.0.0) websocket (1.2.11) websocket-driver (0.8.0) base64 @@ -408,7 +406,7 @@ GEM websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.7.4) + zeitwerk (2.7.5) PLATFORMS aarch64-linux @@ -431,14 +429,14 @@ DEPENDENCIES capybara-lockstep debug factory_bot_rails - inertia_rails (~> 3.6) + inertia_rails (~> 3.19) jbuilder js-routes kamal letter_opener propshaft puma (>= 5.0) - rails (~> 8.1.1) + rails (~> 8.1.3) rspec-rails (~> 8.0) rubocop-rails-omakase selenium-webdriver diff --git a/app/frontend/components/delete-user.tsx b/app/frontend/components/delete-user.tsx index fd08bb0f..230f1e0b 100644 --- a/app/frontend/components/delete-user.tsx +++ b/app/frontend/components/delete-user.tsx @@ -2,7 +2,6 @@ import { Form } from "@inertiajs/react" import { useRef } from "react" import HeadingSmall from "@/components/heading-small" -import InputError from "@/components/input-error" import { Button } from "@/components/ui/button" import { Dialog, @@ -13,8 +12,8 @@ import { DialogTitle, DialogTrigger, } from "@/components/ui/dialog" +import { Field, FieldError, FieldLabel } from "@/components/ui/field" import { Input } from "@/components/ui/input" -import { Label } from "@/components/ui/label" import { usersPath } from "@/routes" export default function DeleteUser() { @@ -59,10 +58,13 @@ export default function DeleteUser() { > {({ resetAndClearErrors, processing, errors }) => ( <> -
- + - -
+ ({ + message, + }))} + /> + diff --git a/app/frontend/components/ui/field.tsx b/app/frontend/components/ui/field.tsx new file mode 100644 index 00000000..4727412f --- /dev/null +++ b/app/frontend/components/ui/field.tsx @@ -0,0 +1,246 @@ +import { type VariantProps, cva } from "class-variance-authority" +import { useMemo } from "react" + +import { Label } from "@/components/ui/label" +import { Separator } from "@/components/ui/separator" +import { cn } from "@/lib/utils" + +function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) { + return ( +
[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3", + className, + )} + {...props} + /> + ) +} + +function FieldLegend({ + className, + variant = "legend", + ...props +}: React.ComponentProps<"legend"> & { variant?: "legend" | "label" }) { + return ( + + ) +} + +function FieldGroup({ className, ...props }: React.ComponentProps<"div">) { + return ( +
[data-slot=field-group]]:gap-4", + className, + )} + {...props} + /> + ) +} + +const fieldVariants = cva( + "group/field flex w-full gap-3 data-[invalid=true]:text-destructive", + { + variants: { + orientation: { + vertical: ["flex-col [&>*]:w-full [&>.sr-only]:w-auto"], + horizontal: [ + "flex-row items-center", + "[&>[data-slot=field-label]]:flex-auto", + "has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px", + ], + responsive: [ + "flex-col @md/field-group:flex-row @md/field-group:items-center [&>*]:w-full @md/field-group:[&>*]:w-auto [&>.sr-only]:w-auto", + "@md/field-group:[&>[data-slot=field-label]]:flex-auto", + "@md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px", + ], + }, + }, + defaultVariants: { + orientation: "vertical", + }, + }, +) + +function Field({ + className, + orientation = "vertical", + ...props +}: React.ComponentProps<"div"> & VariantProps) { + return ( +
+ ) +} + +function FieldContent({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function FieldLabel({ + className, + ...props +}: React.ComponentProps) { + return ( +