Today view: auto-scroll during drag and scroll to first unchecked #191
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feature/today-view-ux-improvements"
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?
Summary
Changes
app/javascript/controllers/sortable_controller.js: Addedscroll,scrollSensitivity,scrollSpeed,bubbleScroll,forceFallbackoptions to SortableJS config. AddedscrollToFirstUnchecked()method called on controller connect — finds first.queue-item:not(.is-completed), skips if it's already the first item, scrolls with 300ms delay for smooth UX.Test Plan
Review Checklist
Related Notes
landscaping-assistant— projectPR #191 Review
DOMAIN REVIEW
Tech stack: Rails 7 / Hotwired Stimulus / SortableJS -- front-end JavaScript controller, no back-end changes.
SortableJS scroll options (lines 12-16 of diff)
The five new options (
scroll,scrollSensitivity,scrollSpeed,bubbleScroll,forceFallback) are all valid SortableJS configuration properties.forceFallback: trueis the right call for mobile touch support -- it bypasses the native HTML5 drag-and-drop API, which is unreliable on iOS/Android, and ensures the SortableJS custom drag implementation is used consistently across platforms.scrollSensitivity: 80andscrollSpeed: 10are reasonable defaults.scrollToFirstUnchecked()method (lines 29-36 of diff)The implementation is clean and defensive:
scrollIntoView({ behavior: "smooth", block: "start" })which is well-supported.setTimeoutdelay gives the DOM time to settle after Turbo renders.The CSS selectors
.queue-itemand.is-completedare confirmed present in both_queue_item.html.erb(line 1:class="queue-item <%= 'is-completed' if item.completed? %>") andapplication.css(line 389+). Selector coupling is tight and correct.One observation:
html { scroll-behavior: smooth; }is already set inapplication.css(line 36), so thebehavior: "smooth"inscrollIntoViewis redundant but harmless -- it makes the intent explicit at the call site, which is fine.Accessibility: No accessibility regressions. The change is purely behavioral (auto-scroll), not structural. Users with
prefers-reduced-motionwill still get the scroll behavior since neither the CSSscroll-behavior: smoothnor the JSscrollIntoViewrespects that media query by default. This is a nit, not a blocker, since this is a work-crew internal tool, but noted below.BLOCKERS
None.
This is a 16-line front-end-only UX improvement to an existing Stimulus controller. It adds no new API surface, no new user input handling, no auth changes, and no security-sensitive paths. The "no test coverage" BLOCKER criterion does not apply here because:
scrollToFirstUnchecked()is a DOM manipulation method that would require a JS test runner (which this project does not have -- all specs are RSpec request-level).NITS
prefers-reduced-motionconsideration: Users who setprefers-reduced-motion: reducein their OS will still get smooth-scrolling. Consider wrapping thescrollIntoViewbehavior in a motion check:Non-blocking since this is an internal crew tool, but good practice for accessibility.
Magic number 300: The
setTimeoutdelay of 300ms is a reasonable guess but is not tied to any specific animation or render event. If Turbo Drive timing changes, this could race. A comment like// Wait for Turbo to finish renderingwould make the intent clear. Alternatively, listening forturbo:loadwould be more robust, though likely overkill for this use case.SOP COMPLIANCE
feature/today-view-ux-improvements-- does not follow the{issue-number}-{kebab-case-purpose}convention. Expected something like189-today-view-auto-scrollor189-190-today-view-ux. Non-blocking but noted.Closessyntax.PROCESS OBSERVATIONS
onEnd: this.reorder.bind(this)is untouched, and thereorder()method is unchanged.VERDICT: APPROVED
PR #191 Review (re-review)
DOMAIN REVIEW
Tech stack: Rails 8.1 / Stimulus / SortableJS / importmap / vanilla CSS. No JS test framework in the project (no jest/vitest). Test suite is RSpec request specs + Capybara.
1. SortableJS auto-scroll options (
sortable_controller.js)The five new SortableJS options (
scroll,scrollSensitivity,scrollSpeed,bubbleScroll,forceFallback) are all valid SortableJS configuration properties with reasonable values.forceFallback: trueis the correct approach for consistent mobile touch-drag behavior -- it bypasses native HTML5 drag-and-drop (which is broken on mobile) in favor of SortableJS's own fallback implementation.No issues here.
2.
scrollToFirstUnchecked()method (sortable_controller.js).queue-item:not(.is-completed)matches the partial atapp/views/work_queue_items/_queue_item.html.erbline 1 -- class names confirmed.if (!firstUnchecked || firstUnchecked === this.element.firstElementChild) returncorrectly handles: (a) all items completed (no match), (b) no completed items (first unchecked is already the first child, no scroll needed).prefers-reduced-motioncheck is correctly implemented -- respects user accessibility settings by falling back to"instant"scroll behavior.setTimeoutis a reasonable heuristic to let the page settle. The timer reference is not stored, so it cannot be cancelled ifdisconnect()fires within 300ms. This is a minor leak concern documented below as a nit.3. iOS Safari GPU compositing fix (
application.css)transform: translate3d(0, 0, 0)on the.bottom-navis a well-known technique to promote an element to its own compositing layer, preventing repaints when iOS Safari's address bar animates. The comment explains the intent clearly. No layout side effects expected since the element is alreadyposition: fixed.BLOCKERS
None.
The "no tests" question: this PR adds client-side UX behaviors (scroll-on-load, drag auto-scroll, GPU compositing). The project has no JS test framework -- tests are RSpec request specs. These behaviors are not testable via request specs (they require a real browser). The PR body includes a manual test plan with 8 specific test cases covering all scenarios. Given the project's test infrastructure and the nature of the changes (pure UI/UX, no server-side logic, no new endpoints, no data mutations), the manual test plan is sufficient and this does not constitute a blocker.
NITS
Orphaned timeout on disconnect. If the Stimulus controller disconnects within 300ms of connecting (e.g., Turbo navigation), the
setTimeoutcallback will still fire on a potentially stale DOM reference. Consider storing the timer ID and clearing it indisconnect():Low-risk in practice (the
scrollIntoViewcall on a detached element is a no-op in all browsers), but it is cleaner.will-changevstranslate3d. The modern CSS approach for GPU compositing hints iswill-change: transformrather than thetranslate3d(0,0,0)hack. Both work, butwill-changeis more semantically correct and does not create an invisible transform. Not blocking -- thetranslate3dapproach is battle-tested and the comment explains the intent.SOP COMPLIANCE
feature/today-view-ux-improvements, not189-today-view-ux-improvements. Convention calls for{issue-number}-{kebab-case-purpose}. Noted but not blocking for a re-review.landscaping-assistantproject, closes #189 and #190.PROCESS OBSERVATIONS
VERDICT: APPROVED