.vbw-planning/milestones/07-rails-audit-and-refactoring/05-view-layer-extraction/03-PLAN.md
Simplify the dropdown controller by removing the fragile stimulus-use async loading path (V6), improve dropdown state isolation (V7), and clean up global window namespace pollution (V13). This improves JavaScript maintainability and prevents memory leaks in SPA-like Turbo Drive navigation.
app/assets/javascripts/source_monitor/controllers/dropdown_controller.js (110 lines) -- fragile async loading with stimulus-use fallback (V6), shared state between instances (V7)app/assets/javascripts/source_monitor/controllers/notification_controller.js (63 lines) -- registers on window.SourceMonitorControllers (V13)app/assets/javascripts/source_monitor/application.js -- exports window.SourceMonitorStimulus (V13)app/views/source_monitor/sources/_row.html.erb -- dropdown for row actions (lines 109-141)app/views/source_monitor/sources/_health_status_badge.html.erb -- dropdown for health menu (lines 8-37)Rewrite app/assets/javascripts/source_monitor/controllers/dropdown_controller.js:
loadTransitions() async method entirelytransitionModuleValue, hiddenClassValue value definitions (keep hiddenClassValue as simple string default "hidden")transitionEnabled, toggleTransition, leave state trackinglogFallback(), _fallbackLogged flagtoggle() toggles this.menuTarget.classList.toggle(this.hiddenClassValue), hide(event) adds hidden class if click is outside controller elementhide(event) must check !this.element.contains(event.target) to scope to own controller instance (V7 fix)connect() and disconnect() manage click-outside listener on document (not window) for proper cleanupModify app/assets/javascripts/source_monitor/controllers/notification_controller.js:
window.SourceMonitorControllers = window.SourceMonitorControllers || {} and window.SourceMonitorControllers.notification = thisdispatch events pattern:
notification:show custom event on this.elementthis.dispatch("show", { detail: { message: "..." } }) patternwindow.SourceMonitorControllers -- if so, update those referencesModify app/assets/javascripts/source_monitor/application.js:
window.SourceMonitorStimulus = application with environment checkif (process.env.NODE_ENV !== "production") or simply remove it (the Stimulus application is accessible via Application.start() return value if needed for debugging)window.Turbo.StreamActions.redirect as-is (standard Turbo extension pattern, acceptable)Modify app/views/source_monitor/sources/_row.html.erb:
click@window->dropdown#hide to click@document->dropdown#hide (if keeping declarative) OR rely on the new connect() listener in the controllerdata-testid="source-actions-<%= dom_id(source) %>" to each dropdown container for testingModify app/views/source_monitor/sources/_health_status_badge.html.erb:
data-testidyarn build -- succeeds with no ESLint errorsapp/assets/builds/source_monitor/application.js is updatedbin/rails test -- full suite passes (no system test regressions)window.SourceMonitorControllers references: grep -r "SourceMonitorControllers" app/assets/grep -r "stimulus-use\|useTransition\|transitionModule" app/assets/