Fix quick-add form reset on duplicate queue submission #80
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "50-fix-quick-add-reset"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #50
Summary
redirect_to, causing Turbo to reload the entire page — resetting the property picker input and losing stateturbo_stream(status 422) so the Stimulus controller's existingturbo:submit-endhandler can roll back the optimistic UI in-place#flash-messagescontainer to layout and fixed positioning CSS for overlay toastsChanges
app/controllers/work_queue_items_controller.rb— failure branch now responds with turbo_stream + flash partial instead of redirectapp/views/shared/_flash.html.erb— new shared flash partialapp/javascript/controllers/auto_dismiss_controller.js— removes flash after 3sapp/views/layouts/application.html.erb— added#flash-messagescontainerapp/assets/stylesheets/application.css— fixed-position flash containerspec/requests/work_queue_items_spec.rb— 2 new specs (turbo_stream error response, no duplicate creation)Test Plan
Review Checklist
turbo:submit-endhandler rolls back optimistic UI on 422Related Notes
turbo:submit-endfailure handling (lines 55-61) but it couldn't fire properly because the redirect replaced the DOMPR #80 Review
DOMAIN REVIEW
Tech stack: Ruby on Rails 8 / Hotwire (Turbo Streams + Stimulus) / importmap / RSpec
Controller (
work_queue_items_controller.rb)redirect_tofailure path with arespond_toblock that rendersturbo_streamwith status:unprocessable_entity(422). This is the canonical Hotwire pattern for form validation failures -- the 422 status lets the Stimulusturbo:submit-endhandler inproperty_picker_controller.js(line 56) detect!e.detail.successand roll back the optimistic UI.format.html { redirect_to ... }) is preserved for non-Turbo clients. Good.@item.errors.full_messages.first || "Already in queue.") is correct. The model validatesproperty_iduniqueness scoped towork_date, so the validation message will populate properly. The fallback string handles edge cases.Flash partial (
shared/_flash.html.erb)<%= message %>which auto-escapes HTML in ERB. No XSS risk.data-controller="auto-dismiss"wiring is correct -- the controller file follows the Stimulus naming convention (auto_dismiss_controller.jsmaps toauto-dismiss).Stimulus controller (
auto_dismiss_controller.js)eagerLoadControllersFrom+pin_all_fromin the importmap. No manual registration needed.setTimeout(() => this.element.remove(), 3000)is clean. The element is removed from the DOM entirely, which is appropriate for a toast.Layout (
application.html.erb)<div id="flash-messages"></div>placed correctly at the top of<body>, before<main>. The Turbo Streamappendaction targets this container by ID.CSS
z-index: 1000is appropriate for overlay toasts. Uses theme tokens (--spacing-xs,--spacing-md,--radius,--color-danger,--color-danger-light) -- no magic numbers. Good.Tests (
spec/requests/work_queue_items_spec.rb)format.htmlfallback path.BLOCKERS
None.
NITS
Timer cleanup on disconnect (
auto_dismiss_controller.js): If the element is removed from the DOM before the 3s timeout fires (e.g., user navigates away via Turbo Drive), thesetTimeoutcallback will callremove()on a detached element. This is harmless (no error thrown), but for hygiene, consider storing the timer ID and clearing it in adisconnect()callback:Non-blocking -- the current code works fine.
Flash partial is hardcoded to
flash-alert: The partial always renders with classflash-alert. If this partial is reused for success messages in the future, it would need atypelocal. Fine for now since the only caller is the error path, but worth noting if you plan to reuseshared/flashelsewhere.No ARIA role on flash toast: The flash container could benefit from
role="alert"orrole="status"for screen reader announcements. e.g.,<div class="flash flash-alert" role="alert" ...>. Non-blocking, but would improve accessibility.SOP COMPLIANCE
50-fix-quick-add-resetfollows{issue-number}-{kebab-case-purpose}PROCESS OBSERVATIONS
VERDICT: APPROVED