From 4fafeee4a96aa1b992f720211ae02979b51258ca Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Wed, 2 Jul 2025 11:47:29 -0400 Subject: [PATCH 01/22] Drop the password column from the users table. --- db/migrate/20250702154620_remove_password_from_users.rb | 5 +++++ db/schema.rb | 2 +- db/schema_cache.yml | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20250702154620_remove_password_from_users.rb diff --git a/db/migrate/20250702154620_remove_password_from_users.rb b/db/migrate/20250702154620_remove_password_from_users.rb new file mode 100644 index 000000000..75173ad1a --- /dev/null +++ b/db/migrate/20250702154620_remove_password_from_users.rb @@ -0,0 +1,5 @@ +class RemovePasswordFromUsers < ActiveRecord::Migration[8.1] + def change + remove_column :users, :password, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 3c4b155e6..a3660591f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.1].define(version: 2025_06_25_111932) do +ActiveRecord::Schema[8.1].define(version: 2025_07_02_154620) do create_table "accesses", force: :cascade do |t| t.datetime "accessed_at" t.integer "collection_id", null: false diff --git a/db/schema_cache.yml b/db/schema_cache.yml index 8aab5a0d5..d3db9362c 100644 --- a/db/schema_cache.yml +++ b/db/schema_cache.yml @@ -2391,4 +2391,4 @@ indexes: comment: valid: true workflows: [] -version: 20250625111932 +version: 20250702154620 From da69bd168940cd41e1b2d861eb8ffdb34784a1f3 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Wed, 2 Jul 2025 11:59:21 -0400 Subject: [PATCH 02/22] Remove local authentication code --- app/controllers/concerns/authentication.rb | 6 +----- app/controllers/signup/base_controller.rb | 5 ----- app/models/account/signal_account.rb | 6 ++---- app/models/user/signal_user.rb | 4 +--- config/initializers/signal_id.rb | 7 ------- 5 files changed, 4 insertions(+), 24 deletions(-) diff --git a/app/controllers/concerns/authentication.rb b/app/controllers/concerns/authentication.rb index dc3ee7bb7..39a6d293e 100644 --- a/app/controllers/concerns/authentication.rb +++ b/app/controllers/concerns/authentication.rb @@ -48,11 +48,7 @@ module Authentication def request_authentication session[:return_to_after_authenticating] = request.url - if Rails.application.config.x.local_authentication - redirect_to new_session_path - else - redirect_to Launchpad.login_url(account: Current.account), allow_other_host: true - end + redirect_to Launchpad.login_url(account: Current.account), allow_other_host: true end def after_authentication_url diff --git a/app/controllers/signup/base_controller.rb b/app/controllers/signup/base_controller.rb index 40ae83e92..088937b04 100644 --- a/app/controllers/signup/base_controller.rb +++ b/app/controllers/signup/base_controller.rb @@ -1,6 +1,5 @@ class Signup::BaseController < ApplicationController require_untenanted_access - before_action :redirect_if_local_auth # TODO: Remove this auth before launch. http_basic_authenticate_with( @@ -34,8 +33,4 @@ class Signup::BaseController < ApplicationController redirect_to account.signal_account.owner.remote_login_url(proceed_to: root_path), allow_other_host: true end - - def redirect_if_local_auth - render plain: "Unauthorized", status: :unauthorized if Rails.application.config.x.local_authentication - end end diff --git a/app/models/account/signal_account.rb b/app/models/account/signal_account.rb index 610a4ed9c..861626909 100644 --- a/app/models/account/signal_account.rb +++ b/app/models/account/signal_account.rb @@ -2,10 +2,8 @@ module Account::SignalAccount extend ActiveSupport::Concern included do - unless Rails.application.config.x.local_authentication - # TODO: remove the "optional: true" once we've populated the accounts properly - belongs_to :signal_account, class_name: "SignalId::Account", primary_key: :queenbee_id, foreign_key: :queenbee_id, optional: true - end + # TODO: remove the "optional: true" once we've populated the accounts properly + belongs_to :signal_account, class_name: "SignalId::Account", primary_key: :queenbee_id, foreign_key: :queenbee_id, optional: true end class_methods do diff --git a/app/models/user/signal_user.rb b/app/models/user/signal_user.rb index 924cfe87d..16bee49bc 100644 --- a/app/models/user/signal_user.rb +++ b/app/models/user/signal_user.rb @@ -2,8 +2,6 @@ module User::SignalUser extend ActiveSupport::Concern included do - unless Rails.application.config.x.local_authentication - belongs_to :signal_user, dependent: :destroy, class_name: "SignalId::User", optional: true - end + belongs_to :signal_user, dependent: :destroy, class_name: "SignalId::User", optional: true end end diff --git a/config/initializers/signal_id.rb b/config/initializers/signal_id.rb index afb6ff60c..b356ef881 100644 --- a/config/initializers/signal_id.rb +++ b/config/initializers/signal_id.rb @@ -1,18 +1,11 @@ require "signal_id" -Rails.application.config.x.local_authentication = ENV["LOCAL_AUTHENTICATION"].present? - ENV["SIGNAL_ID_SECRET"] = Rails.application.credentials.signal_id_secret Rails.application.config.to_prepare do SignalId.product = "fizzy" db_config = SignalId::Database.default_configuration - if Rails.application.config.x.local_authentication - db_config.each do |name, config| - config["connect_timeout"] = 1 - end - end SignalId::Database.load_configuration db_config SignalId::Database.enable_rw_splitting! From c8be7418c1077d5c888ae5910fa468408e253488 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Wed, 2 Jul 2025 12:01:49 -0400 Subject: [PATCH 03/22] Account.signal_account is no longer optional --- app/models/account/signal_account.rb | 3 +-- .../20250702160230_add_not_null_to_accounts_queenbee_id.rb | 5 +++++ db/schema.rb | 4 ++-- db/schema_cache.yml | 4 ++-- 4 files changed, 10 insertions(+), 6 deletions(-) create mode 100644 db/migrate/20250702160230_add_not_null_to_accounts_queenbee_id.rb diff --git a/app/models/account/signal_account.rb b/app/models/account/signal_account.rb index 861626909..a01af7ad2 100644 --- a/app/models/account/signal_account.rb +++ b/app/models/account/signal_account.rb @@ -2,8 +2,7 @@ module Account::SignalAccount extend ActiveSupport::Concern included do - # TODO: remove the "optional: true" once we've populated the accounts properly - belongs_to :signal_account, class_name: "SignalId::Account", primary_key: :queenbee_id, foreign_key: :queenbee_id, optional: true + belongs_to :signal_account, class_name: "SignalId::Account", primary_key: :queenbee_id, foreign_key: :queenbee_id end class_methods do diff --git a/db/migrate/20250702160230_add_not_null_to_accounts_queenbee_id.rb b/db/migrate/20250702160230_add_not_null_to_accounts_queenbee_id.rb new file mode 100644 index 000000000..9698302bf --- /dev/null +++ b/db/migrate/20250702160230_add_not_null_to_accounts_queenbee_id.rb @@ -0,0 +1,5 @@ +class AddNotNullToAccountsQueenbeeId < ActiveRecord::Migration[8.1] + def change + change_column_null :accounts, :queenbee_id, false + end +end diff --git a/db/schema.rb b/db/schema.rb index a3660591f..4ab5a7e92 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.1].define(version: 2025_07_02_154620) do +ActiveRecord::Schema[8.1].define(version: 2025_07_02_160230) do create_table "accesses", force: :cascade do |t| t.datetime "accessed_at" t.integer "collection_id", null: false @@ -28,7 +28,7 @@ ActiveRecord::Schema[8.1].define(version: 2025_07_02_154620) do t.datetime "created_at", null: false t.string "join_code" t.string "name", null: false - t.integer "queenbee_id" + t.integer "queenbee_id", null: false t.datetime "updated_at", null: false t.index ["queenbee_id"], name: "index_accounts_on_queenbee_id", unique: true end diff --git a/db/schema_cache.yml b/db/schema_cache.yml index d3db9362c..701462046 100644 --- a/db/schema_cache.yml +++ b/db/schema_cache.yml @@ -128,7 +128,7 @@ columns: name: queenbee_id cast_type: *3 sql_type_metadata: *4 - 'null': true + 'null': false default: default_function: collation: @@ -2391,4 +2391,4 @@ indexes: comment: valid: true workflows: [] -version: 20250702154620 +version: 20250702160230 From 79eada3e8d6eed86128618c7bdf2bd69cd073724 Mon Sep 17 00:00:00 2001 From: Jason Zimdars Date: Wed, 2 Jul 2025 13:56:50 -0500 Subject: [PATCH 04/22] Screen reader: De-duplicate links for each person in account settings --- app/views/accounts/_user.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/accounts/_user.html.erb b/app/views/accounts/_user.html.erb index cdf3c9beb..f176236c3 100644 --- a/app/views/accounts/_user.html.erb +++ b/app/views/accounts/_user.html.erb @@ -1,5 +1,5 @@
  • - <%= avatar_tag user %> + <%= avatar_tag user, hidden_for_screen_reader: true %> <%= link_to user.name, user, class: "txt-ink btn btn--plain" %> From 5262e2812f97594650fb826e01653b308e734a03 Mon Sep 17 00:00:00 2001 From: Jason Zimdars Date: Wed, 2 Jul 2025 13:58:50 -0500 Subject: [PATCH 05/22] Style --- app/views/commands/_form.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/commands/_form.html.erb b/app/views/commands/_form.html.erb index afd59d6a0..1a2c31f72 100644 --- a/app/views/commands/_form.html.erb +++ b/app/views/commands/_form.html.erb @@ -20,5 +20,5 @@ placeholder: platform.desktop? ? "Press #{ hotkey_label(["ctrl", "K"]) } to search or type commands…" : "Search or type commands…", spellcheck: "false" %> - <%= hidden_field_tag "confirmed", nil, data: { terminal_target: "confirmation" } %> + <%= hidden_field_tag "confirmed", nil, data: { terminal_target: "confirmation" } %> <% end %> From 08043a7c5ecb5eb8fbb378ba5185d81e8da48351 Mon Sep 17 00:00:00 2001 From: Jason Zimdars Date: Wed, 2 Jul 2025 14:01:10 -0500 Subject: [PATCH 06/22] Correct label for field --- app/views/commands/_form.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/commands/_form.html.erb b/app/views/commands/_form.html.erb index 1a2c31f72..eab9ca8f9 100644 --- a/app/views/commands/_form.html.erb +++ b/app/views/commands/_form.html.erb @@ -6,7 +6,7 @@ terminal_target: "form", action: "turbo:submit-start->terminal#commandSubmitted turbo:submit-end->terminal#focus keydown.meta+k@document->terminal#focus:prevent keydown.ctrl+k@document->terminal#focus:prevent keydown.enter->terminal#executeCommand keydown.esc->terminal#hideMenus turbo:submit-end->terminal#handleCommandResponse" } do %> - + <%= text_field_tag "command", nil, autocomplete: "off", From fa1c5f72792f1284e87dc100b96302d8cef43977 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Wed, 2 Jul 2025 14:33:33 -0400 Subject: [PATCH 07/22] Remove session controller actions other than delete and do some general cleanup around sessions controllers and the sign_in_as test helper --- .../sessions/launchpad_controller.rb | 11 ++----- app/controllers/sessions_controller.rb | 24 +-------------- app/views/sessions/launchpad/show.html.erb | 4 ++- app/views/sessions/new.html.erb | 30 ------------------- app/views/users/new.html.erb | 2 +- config/routes.rb | 4 +-- .../sessions/launchpad_controller_test.rb | 11 +++---- test/controllers/sessions_controller_test.rb | 30 +------------------ test/test_helpers/session_test_helper.rb | 2 +- 9 files changed, 18 insertions(+), 100 deletions(-) delete mode 100644 app/views/sessions/new.html.erb diff --git a/app/controllers/sessions/launchpad_controller.rb b/app/controllers/sessions/launchpad_controller.rb index 0e2ad16a7..8a9a082dd 100644 --- a/app/controllers/sessions/launchpad_controller.rb +++ b/app/controllers/sessions/launchpad_controller.rb @@ -1,8 +1,7 @@ class Sessions::LaunchpadController < ApplicationController require_unauthenticated_access - before_action :store_sig, only: :show - before_action :restore_and_clear_sig, only: :update + before_action :require_sig def show end @@ -17,11 +16,7 @@ class Sessions::LaunchpadController < ApplicationController end private - def store_sig - cookies[:_fizzy_launchpad_sig] = params.expect(:sig) - end - - def restore_and_clear_sig - @sig = cookies.delete :_fizzy_launchpad_sig + def require_sig + @sig = params.expect(:sig) end end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 428c5a7f4..fa7d98974 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -1,28 +1,6 @@ class SessionsController < ApplicationController - require_unauthenticated_access only: %i[ new create ] - rate_limit to: 10, within: 3.minutes, only: :create, with: -> { redirect_to new_session_path, alert: "Try again later." } - - before_action :require_first_run_completion - - def new - end - - def create - if user = User.active.authenticate_by(params.permit(:email_address, :password)) - start_new_session_for user - redirect_to after_authentication_url - else - redirect_to new_session_path, alert: "Try another email address or password." - end - end - def destroy terminate_session - redirect_to new_session_path + redirect_to Launchpad.login_url, allow_other_host: true end - - private - def require_first_run_completion - redirect_to first_run_path if Account.none? - end end diff --git a/app/views/sessions/launchpad/show.html.erb b/app/views/sessions/launchpad/show.html.erb index 897e39922..c9acf341d 100644 --- a/app/views/sessions/launchpad/show.html.erb +++ b/app/views/sessions/launchpad/show.html.erb @@ -1 +1,3 @@ -<%= auto_submit_form_with method: :put %> +<%= auto_submit_form_with(method: :put) do |form| %> + <%= form.hidden_field(:sig, value: @sig) %> +<% end %> diff --git a/app/views/sessions/new.html.erb b/app/views/sessions/new.html.erb deleted file mode 100644 index d806a904f..000000000 --- a/app/views/sessions/new.html.erb +++ /dev/null @@ -1,30 +0,0 @@ -<% @page_title = "Sign in" %> - -
    " style="--panel-size: 55ch;"> -

    Fizzy

    - - <%= form_with url: session_path, class: "flex flex-column gap txt-large" do |form| %> -
    - -
    - -
    - -
    - - - <% end %> -
    - -<% content_for :footer do %> -
    Fizzy™ version 0
    -<% end %> diff --git a/app/views/users/new.html.erb b/app/views/users/new.html.erb index 847782db8..2111155d6 100644 --- a/app/views/users/new.html.erb +++ b/app/views/users/new.html.erb @@ -2,7 +2,7 @@ <% content_for :header do %> diff --git a/config/routes.rb b/config/routes.rb index df5d8ad7c..27fdf59a6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -84,11 +84,11 @@ Rails.application.routes.draw do get "join/:join_code", to: "users#new", as: :join post "join/:join_code", to: "users#create" - resource :session do + resource :session, only: :destroy do scope module: "sessions" do resources :transfers, only: %i[ show update ] + resource :launchpad, only: %i[ show update ], controller: "launchpad" end - resource :launchpad, only: %i[ show update ], controller: "sessions/launchpad" end namespace :signup do diff --git a/test/controllers/sessions/launchpad_controller_test.rb b/test/controllers/sessions/launchpad_controller_test.rb index 2ab50b2a0..c67ac8ee2 100644 --- a/test/controllers/sessions/launchpad_controller_test.rb +++ b/test/controllers/sessions/launchpad_controller_test.rb @@ -6,14 +6,16 @@ class Sessions::LaunchpadControllerTest < ActionDispatch::IntegrationTest assert_response :success - assert_equal cookies[:_fizzy_launchpad_sig], "test-sig" + assert_select "form input#sig" do |node| + assert_equal node.length, 1 + assert_equal node.first["value"], "test-sig" + end end test "create establishes a session when the sig is valid" do user = users(:david) - cookies[:_fizzy_launchpad_sig] = user.signal_user.perishable_signature - put session_launchpad_path + put session_launchpad_path(params: { sig: user.signal_user.perishable_signature }) assert_redirected_to root_url assert parsed_cookies.signed[:session_token] @@ -21,9 +23,8 @@ class Sessions::LaunchpadControllerTest < ActionDispatch::IntegrationTest test "returns 401 when the sig is invalid" do user = users(:david) - cookies[:sig] = "not-valid" - put session_launchpad_path + put session_launchpad_path(params: { sig: "invalid" }) assert_response :unauthorized end diff --git a/test/controllers/sessions_controller_test.rb b/test/controllers/sessions_controller_test.rb index 1cf460c6c..35a6b0385 100644 --- a/test/controllers/sessions_controller_test.rb +++ b/test/controllers/sessions_controller_test.rb @@ -1,38 +1,10 @@ require "test_helper" class SessionsControllerTest < ActionDispatch::IntegrationTest - ALLOWED_BROWSER = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15" - DISALLOWED_BROWSER = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/114.0" - - test "new" do - get new_session_path - assert_response :success - end - - test "new enforces browser compatibility" do - get new_session_path, env: { "HTTP_USER_AGENT" => DISALLOWED_BROWSER } - assert_select "svg", message: /Your browser is not supported/ - - get new_session_path, env: { "HTTP_USER_AGENT" => ALLOWED_BROWSER } - assert_select "svg", text: /Your browser is not supported/, count: 0 - end - - test "create with valid credentials" do - post session_path, params: { email_address: "david@37signals.com", password: "secret123456" } - assert_redirected_to root_path - assert cookies[:session_token].present? - end - - test "create with invalid credentials" do - post session_path, params: { email_address: "david@37signals.com", password: "wrong" } - assert_redirected_to new_session_path - assert_not cookies[:session_token].present? - end - test "destroy" do sign_in_as :kevin delete session_path - assert_redirected_to new_session_path + assert_redirected_to Launchpad.login_url assert_not cookies[:session_token].present? end end diff --git a/test/test_helpers/session_test_helper.rb b/test/test_helpers/session_test_helper.rb index 5e4f7eaf0..f4bb6aa45 100644 --- a/test/test_helpers/session_test_helper.rb +++ b/test/test_helpers/session_test_helper.rb @@ -6,7 +6,7 @@ module SessionTestHelper def sign_in_as(user) cookies[:session_token] = nil user = users(user) unless user.is_a? User - post session_path, params: { email_address: user.email_address, password: "secret123456" } + put session_launchpad_path, params: { sig: user.signal_user.perishable_signature } assert cookies[:session_token].present? end From 7f1b384425e3c28d9af68926b3357f1e0c9ec0a6 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Wed, 2 Jul 2025 15:15:05 -0400 Subject: [PATCH 08/22] Remove the invitation codes for now until I circle back for https://3.basecamp.com/2914079/buckets/37331921/todos/8746162337 --- app/views/accounts/settings/_users.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/accounts/settings/_users.html.erb b/app/views/accounts/settings/_users.html.erb index 550715545..7ffd3c5a5 100644 --- a/app/views/accounts/settings/_users.html.erb +++ b/app/views/accounts/settings/_users.html.erb @@ -1,6 +1,6 @@
    People on the account - <%= render "accounts/invite" %> + <%#= render "accounts/invite" # Scheduled work in https://3.basecamp.com/2914079/buckets/37331921/todos/8746162337 %>
    From 91aa8be4fcc4b374ef97717a98c00ad9bfd5b34a Mon Sep 17 00:00:00 2001 From: Jason Zimdars Date: Wed, 2 Jul 2025 14:22:16 -0500 Subject: [PATCH 09/22] Screen reader: Use heading for comments navigation --- app/assets/stylesheets/comments.css | 10 ++++++++-- app/views/cards/comments/_comment.html.erb | 16 +++++++++------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/app/assets/stylesheets/comments.css b/app/assets/stylesheets/comments.css index bba7f8a34..a8b8da16b 100644 --- a/app/assets/stylesheets/comments.css +++ b/app/assets/stylesheets/comments.css @@ -37,8 +37,14 @@ } .comment__author { - .comment--system & strong { - display: none; + .comment--system & { + h3 { + margin-inline: auto; + } + + strong { + display: none; + } } .btn { diff --git a/app/views/cards/comments/_comment.html.erb b/app/views/cards/comments/_comment.html.erb index 8a66b2fcd..daa3eda11 100644 --- a/app/views/cards/comments/_comment.html.erb +++ b/app/views/cards/comments/_comment.html.erb @@ -8,14 +8,16 @@
    - - <%= link_to comment.creator.name, comment.creator, class: "txt-ink btn btn--plain fill-transparent", data: { turbo_frame: "_top" } %> - +

    + + <%= link_to comment.creator.name, comment.creator, class: "txt-ink btn btn--plain fill-transparent", data: { turbo_frame: "_top" } %> + - <%= link_to comment, class: "txt-undecorated txt-ink translucent txt-normal txt-capitalize flex-item-justify-start" do %> - <%= local_datetime_tag comment.created_at, style: :agoorweekday %>, - <%= local_datetime_tag comment.created_at, style: :time %> - <% end %> + <%= link_to comment, class: "txt-undecorated txt-ink translucent txt-normal txt-capitalize" do %> + <%= local_datetime_tag comment.created_at, style: :agoorweekday %>, + <%= local_datetime_tag comment.created_at, style: :time %> + <% end %> +

    <%= link_to edit_card_comment_path(comment.card, comment), class: "comment__edit btn btn--circle borderless fill-transparent translucent" do %> From 4537037a4c7a7f77d049cb7a4fc7cf7e7ad895f2 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Wed, 2 Jul 2025 15:23:59 -0400 Subject: [PATCH 10/22] squash! Remove session controller actions other than delete --- app/views/users/show.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb index d7825ad91..50e905996 100644 --- a/app/views/users/show.html.erb +++ b/app/views/users/show.html.erb @@ -43,7 +43,7 @@
    - <%= button_to session_path, method: :delete, class: "btn center txt-medium" do %> + <%= button_to session_path, method: :delete, class: "btn center txt-medium", data: { turbo: false } do %> <%= icon_tag "logout" %> Sign out <% end %> From 985337a91ca39cdbbee267116bffbfd2b27b7eda Mon Sep 17 00:00:00 2001 From: Jason Zimdars Date: Wed, 2 Jul 2025 14:29:15 -0500 Subject: [PATCH 11/22] Esc should not propagate when closing dialogs --- app/views/cards/comments/reactions/_quick_reaction.html.erb | 2 +- app/views/cards/container/_closure.html.erb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/cards/comments/reactions/_quick_reaction.html.erb b/app/views/cards/comments/reactions/_quick_reaction.html.erb index b93931813..d316e8ef7 100644 --- a/app/views/cards/comments/reactions/_quick_reaction.html.erb +++ b/app/views/cards/comments/reactions/_quick_reaction.html.erb @@ -1,4 +1,4 @@ -
    +
    <%= yield %> diff --git a/app/views/cards/container/_closure.html.erb b/app/views/cards/container/_closure.html.erb index d8df5173f..7d5914a9a 100644 --- a/app/views/cards/container/_closure.html.erb +++ b/app/views/cards/container/_closure.html.erb @@ -7,7 +7,7 @@ <% end %>
    <% else %> -
    +
    Close as <%= icon_tag "caret-down" %> From db99e5928c360c728cbebcbc42cd2154166ad972 Mon Sep 17 00:00:00 2001 From: Jason Zimdars Date: Wed, 2 Jul 2025 14:38:29 -0500 Subject: [PATCH 12/22] Make collection title `h1` for screen reader navigation --- app/views/cards/index.html.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/cards/index.html.erb b/app/views/cards/index.html.erb index 33a2d752e..c6c100811 100644 --- a/app/views/cards/index.html.erb +++ b/app/views/cards/index.html.erb @@ -7,9 +7,9 @@ <% end %>
    - +

    <%= filter_title @filter %> - +

    <%= render "filters/settings", filter: @filter %>
    From 70d6a7190fa24d5cb00dbc24b4439aa1d838ea4b Mon Sep 17 00:00:00 2001 From: Jason Zimdars Date: Wed, 2 Jul 2025 14:42:53 -0500 Subject: [PATCH 13/22] Use `h3` for individual cards in collection view --- app/views/cards/display/_preview.html.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/cards/display/_preview.html.erb b/app/views/cards/display/_preview.html.erb index b622bae69..ded2d8e14 100644 --- a/app/views/cards/display/_preview.html.erb +++ b/app/views/cards/display/_preview.html.erb @@ -16,9 +16,9 @@
    -

    +

    <%= card.title %> -

    + <%= link_to collection_card_path(card.collection, card), draggable: false, class: "card__link", title: card_title_tag(card), data: { action: "dialog#close", turbo_frame: "_top" } do %> <%= card.title %> From c19e5a6253d61fe82e17ebd624829811d4ab66dc Mon Sep 17 00:00:00 2001 From: Jason Zimdars Date: Wed, 2 Jul 2025 14:46:43 -0500 Subject: [PATCH 14/22] Use headings for screen reader navigation --- app/views/events/event/_layout.html.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/events/event/_layout.html.erb b/app/views/events/event/_layout.html.erb index e31fd9749..46d6e3a9f 100644 --- a/app/views/events/event/_layout.html.erb +++ b/app/views/events/event/_layout.html.erb @@ -6,12 +6,12 @@ related_element_group_value: card.id, action: "mouseover->related-element#highlight mouseout->related-element#unhighlight" } do %>
    -
    +

    <%= card.id %> <%= event.collection.name %> -

    + <% if event_column(event) == 2 %> From 46093caeb803c9959684b84bf9fa5ddb99961b61 Mon Sep 17 00:00:00 2001 From: Jason Zimdars Date: Wed, 2 Jul 2025 14:52:10 -0500 Subject: [PATCH 15/22] There aren't any `li` children so just use `div` --- app/helpers/events_helper.rb | 2 +- test/controllers/events_controller_test.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index 6b4ffd47d..51e69e94b 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -37,7 +37,7 @@ module EventsHelper def event_cluster_tag(hour, col, &) row = 25 - hour - tag.ul class: "events__time-block", style: "grid-area: #{row}/#{col}", & + tag.div class: "events__time-block", style: "grid-area: #{row}/#{col}", & end def event_next_page_link(next_day) diff --git a/test/controllers/events_controller_test.rb b/test/controllers/events_controller_test.rb index d89d953f4..c89c06540 100644 --- a/test/controllers/events_controller_test.rb +++ b/test/controllers/events_controller_test.rb @@ -11,7 +11,7 @@ class EventsControllerTest < ActionDispatch::IntegrationTest test "index" do get events_path - assert_select "ul.events__time-block[style='grid-area: 17/2']" do + assert_select "div.events__time-block[style='grid-area: 17/2']" do assert_select "strong", text: "David assigned JZ to Layout is broken" end end @@ -21,7 +21,7 @@ class EventsControllerTest < ActionDispatch::IntegrationTest get events_path - assert_select "ul.events__time-block[style='grid-area: 22/2']" do + assert_select "div.events__time-block[style='grid-area: 22/2']" do assert_select "strong", text: "David assigned JZ to Layout is broken" end end From 6504813b4a90c27236670917b6e566457fb03848 Mon Sep 17 00:00:00 2001 From: Jason Zimdars Date: Wed, 2 Jul 2025 14:53:47 -0500 Subject: [PATCH 16/22] Point skip links to correct anchor, don't navigate with turbo --- app/views/layouts/application.html.erb | 2 +- app/views/layouts/public.html.erb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 03b4727c2..3c3ab9238 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -4,7 +4,7 @@ diff --git a/app/views/layouts/public.html.erb b/app/views/layouts/public.html.erb index 37c066687..4f754a9d1 100644 --- a/app/views/layouts/public.html.erb +++ b/app/views/layouts/public.html.erb @@ -4,7 +4,7 @@ From 10893b8fa2ff80fb23ed95df64e7805b01d949ff Mon Sep 17 00:00:00 2001 From: Jason Zimdars Date: Wed, 2 Jul 2025 15:02:37 -0500 Subject: [PATCH 17/22] Don't hide the input so it's accessible to screen readers --- app/assets/stylesheets/inputs.css | 8 ++++---- app/views/cards/container/_image.html.erb | 5 ++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/app/assets/stylesheets/inputs.css b/app/assets/stylesheets/inputs.css index 3acda5855..ed4a51072 100644 --- a/app/assets/stylesheets/inputs.css +++ b/app/assets/stylesheets/inputs.css @@ -37,7 +37,6 @@ } .input--file { - border: 0; cursor: pointer; display: grid; inline-size: auto; @@ -52,6 +51,7 @@ } input[type="file"] { + --hover-size: 0; --input-border-color: transparent; --input-border-radius: 8px; @@ -69,9 +69,9 @@ &:focus, &:focus-visible { - --input-border-color: var(--color-selected-dark); - --input-border-radius: 8px; - --input-border-size: 0.15rem; + .input--file:has(&) { + outline: 0.15rem solid var(--color-selected-dark); + } } } diff --git a/app/views/cards/container/_image.html.erb b/app/views/cards/container/_image.html.erb index c1617792e..773f7f949 100644 --- a/app/views/cards/container/_image.html.erb +++ b/app/views/cards/container/_image.html.erb @@ -5,13 +5,12 @@ <% end %> <% elsif !card.closed? %> <%= form_with model: card, url: collection_card_path(card.collection, card), data: { controller: "form" } do |form| %> -
    <% end %> <% end %> From 86e6309735e6e09b396328e28fbe89a1470c0a1d Mon Sep 17 00:00:00 2001 From: Jason Zimdars Date: Wed, 2 Jul 2025 15:57:30 -0500 Subject: [PATCH 20/22] Hide dialog targets from screen readers when closed --- app/javascript/controllers/dialog_controller.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/javascript/controllers/dialog_controller.js b/app/javascript/controllers/dialog_controller.js index fd4d122e0..123c2384e 100644 --- a/app/javascript/controllers/dialog_controller.js +++ b/app/javascript/controllers/dialog_controller.js @@ -6,6 +6,10 @@ export default class extends Controller { modal: { type: Boolean, default: false } } + connect() { + this.dialogTarget.setAttribute('aria-hidden', 'true') + } + open() { const modal = this.modalValue @@ -14,6 +18,7 @@ export default class extends Controller { } else { this.dialogTarget.show() } + this.dialogTarget.setAttribute('aria-hidden', 'false') } toggle() { @@ -26,6 +31,7 @@ export default class extends Controller { close() { this.dialogTarget.close() + this.dialogTarget.setAttribute('aria-hidden', 'true') this.dialogTarget.blur() } From 41e40b5444813844961432548917738c99096cd5 Mon Sep 17 00:00:00 2001 From: Jason Zimdars Date: Wed, 2 Jul 2025 15:57:39 -0500 Subject: [PATCH 21/22] Indicate opens menu --- app/views/my/pins/_tray.html.erb | 2 +- app/views/notifications/_tray.html.erb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/my/pins/_tray.html.erb b/app/views/my/pins/_tray.html.erb index 615b61e96..bafafc01c 100644 --- a/app/views/my/pins/_tray.html.erb +++ b/app/views/my/pins/_tray.html.erb @@ -12,7 +12,7 @@
    - diff --git a/app/views/notifications/_tray.html.erb b/app/views/notifications/_tray.html.erb index 0b6d7f0ef..671da7f72 100644 --- a/app/views/notifications/_tray.html.erb +++ b/app/views/notifications/_tray.html.erb @@ -34,7 +34,7 @@ <% end %>
    - From f623f6fea8bebc7305b85305d039b70fbec6efac Mon Sep 17 00:00:00 2001 From: Jason Zimdars Date: Wed, 2 Jul 2025 16:06:22 -0500 Subject: [PATCH 22/22] Fix that stage should be visible above card background --- app/assets/stylesheets/card-columns.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/card-columns.css b/app/assets/stylesheets/card-columns.css index bdbad0bcc..23d974b48 100644 --- a/app/assets/stylesheets/card-columns.css +++ b/app/assets/stylesheets/card-columns.css @@ -85,7 +85,7 @@ .card__background { .card:has(& img:not([src=""])) { - .card__body, + .card__content, .card__meta, .workflow-stage:not(.workflow-stage--current) { opacity: 0;