Merge pull request #9633 from binarygit/add-stimulus-reflex

Add StimulusReflex
This commit is contained in:
Filipe
2022-09-29 17:11:18 +01:00
committed by GitHub
19 changed files with 330 additions and 24 deletions

View File

@@ -97,7 +97,8 @@ gem 'redis', '>= 4.0', require: ['redis', 'redis/connection/hiredis']
gem 'sidekiq'
gem 'sidekiq-scheduler'
gem "cable_ready", "5.0.0.pre3"
gem "cable_ready", "5.0.0.pre9"
gem "stimulus_reflex", "3.5.0.pre9"
gem 'combine_pdf'
gem 'wicked_pdf'

View File

@@ -185,8 +185,13 @@ GEM
bullet (7.0.3)
activesupport (>= 3.0.0)
uniform_notifier (~> 1.11)
cable_ready (5.0.0.pre3)
rails (>= 5.2)
cable_ready (5.0.0.pre9)
actioncable (>= 5.2)
actionpack (>= 5.2)
actionview (>= 5.2)
activerecord (>= 5.2)
activesupport (>= 5.2)
railties (>= 5.2)
thread-local (>= 1.1.0)
cancancan (1.15.0)
capybara (3.37.1)
@@ -627,6 +632,16 @@ GEM
state_machines-activerecord (0.8.0)
activerecord (>= 5.1)
state_machines-activemodel (>= 0.8.0)
stimulus_reflex (3.5.0.pre9)
actioncable (>= 5.2)
actionpack (>= 5.2)
actionview (>= 5.2)
activesupport (>= 5.2)
cable_ready (>= 5.0.0.pre9)
nokogiri
rack
railties (>= 5.2)
redis
stringex (2.8.5)
stripe (7.1.0)
temple (0.8.2)
@@ -708,7 +723,7 @@ DEPENDENCIES
bootsnap
bugsnag
bullet
cable_ready (= 5.0.0.pre3)
cable_ready (= 5.0.0.pre9)
cancancan (~> 1.15.0)
capybara
catalog!
@@ -802,6 +817,7 @@ DEPENDENCIES
spring
spring-commands-rspec
state_machines-activerecord
stimulus_reflex (= 3.5.0.pre9)
stringex (~> 2.8.5)
stripe
test-prof

View File

@@ -0,0 +1,6 @@
# frozen_string_literal: true
module ApplicationCable
class Channel < ActionCable::Channel::Base
end
end

View File

@@ -0,0 +1,24 @@
# frozen_string_literal: true
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :session_id, :current_user
def connect
# initializes Warden after a cold start, in case you're visitor #1
env["warden"].authenticated?
# the problem with only using session is that users often login on multiple devices
self.current_user = env["warden"].user
# the problem with only using user is that sometimes you might want to use SR before you login
self.session_id = request.session.id
# and so, we recommend using both
# this assumes that you want to enable SR for unauthenticated users
reject_unauthorized_connection unless current_user || session_id
# if you want to disable SR for unauthenticated users,
# comment out the line above and uncomment the line below
# reject_unauthorized_connection unless current_user
end
end
end

View File

@@ -0,0 +1,19 @@
# frozen_string_literal: true
class ApplicationReflex < StimulusReflex::Reflex
# Put application-wide Reflex behavior and callbacks in this file.
#
# Learn more at: https://docs.stimulusreflex.com/rtfm/reflex-classes
#
# If your ActionCable connection is: `identified_by :current_user`
# delegate :current_user, to: :connection
#
# If you need to localize your Reflexes, you can set the I18n locale here:
#
# before_reflex do
# I18n.locale = :fr
# end
#
# For code examples, considerations and caveats, see:
# https://docs.stimulusreflex.com/rtfm/patterns#internationalization
end

View File

@@ -33,6 +33,8 @@
= csrf_meta_tags
%meta{name: "turbo-cache-control", content: "no-cache"}
= action_cable_meta_tag
%body{ class: body_classes, "body-scroll": "true", "data-turbo": "false" }
/ [if lte IE 8]
= render partial: "shared/ie_warning"

View File

@@ -1,6 +1,7 @@
%meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}
= csrf_meta_tags
= action_cable_meta_tag
%title
- if content_for? :html_title

View File

@@ -0,0 +1,6 @@
// Action Cable provides the framework to deal with WebSockets in Rails.
// You can generate new channels where WebSocket features live using the `bin/rails generate channel` command.
import { createConsumer } from "@rails/actioncable";
export default createConsumer();

View File

@@ -0,0 +1,5 @@
// Load all the channels within this directory and all subdirectories.
// Channel files must be named *_channel.js.
const channels = require.context(".", true, /_channel\.js$/);
channels.keys().forEach(channels);

View File

@@ -0,0 +1,65 @@
import { Controller } from "@hotwired/stimulus";
import StimulusReflex from "stimulus_reflex";
/* This is your ApplicationController.
* All StimulusReflex controllers should inherit from this class.
*
* Example:
*
* import ApplicationController from './application_controller'
*
* export default class extends ApplicationController { ... }
*
* Learn more at: https://docs.stimulusreflex.com
*/
export default class extends Controller {
connect() {
StimulusReflex.register(this);
}
/* Application-wide lifecycle methods
*
* Use these methods to handle lifecycle concerns for the entire application.
* Using the lifecycle is optional, so feel free to delete these stubs if you don't need them.
*
* Arguments:
*
* element - the element that triggered the reflex
* may be different than the Stimulus controller's this.element
*
* reflex - the name of the reflex e.g. "Example#demo"
*
* error/noop - the error message (for reflexError), otherwise null
*
* reflexId - a UUID4 or developer-provided unique identifier for each Reflex
*/
beforeReflex(element, reflex, noop, reflexId) {
// document.body.classList.add('wait')
}
reflexSuccess(element, reflex, noop, reflexId) {
// show success message
}
reflexError(element, reflex, error, reflexId) {
// show error message
}
reflexForbidden(element, reflex, noop, reflexId) {
// Reflex action did not have permission to run
// window.location = '/'
}
reflexHalted(element, reflex, noop, reflexId) {
// handle aborted Reflex action
}
afterReflex(element, reflex, noop, reflexId) {
// document.body.classList.remove('wait')
}
finalizeReflex(element, reflex, noop, reflexId) {
// all operations have completed, animation etc is now safe
}
}

View File

@@ -1,18 +1,73 @@
// This is what a basic Stimulus Controller looks like. To apply it to an element you can do:
// div{"data-controller": "example"}
// or:
// div{data: {controller: "example"}}
import ApplicationController from "./application_controller";
import { Controller } from "stimulus";
/* This is the custom StimulusReflex controller for the Example Reflex.
* Learn more at: https://docs.stimulusreflex.com
*/
export default class extends ApplicationController {
/*
* Regular Stimulus lifecycle methods
* Learn more at: https://stimulusjs.org/reference/lifecycle-callbacks
*
* If you intend to use this controller as a regular stimulus controller as well,
* make sure any Stimulus lifecycle methods overridden in ApplicationController call super.
*
* Important:
* By default, StimulusReflex overrides the -connect- method so make sure you
* call super if you intend to do anything else when this controller connects.
*/
export default class extends Controller {
// connect() is a built-in lifecycle callback for Stimulus Controllers. It fires when the
// element is loaded on the page, and that also *includes* when some HTML is asynchronously
// injected into the DOM. This means initialization is not tied to the page load event, but
// will also happen dynamically if and when new DOM elements are added or removed.
connect() {
console.log("We're connected!");
super.connect();
// add your code here, if applicable
}
}
// For more info take a look at https://stimulus.hotwired.dev/handbook/introduction
/* Reflex specific lifecycle methods.
*
* For every method defined in your Reflex class, a matching set of lifecycle methods become available
* in this javascript controller. These are optional, so feel free to delete these stubs if you don't
* need them.
*
* Important:
* Make sure to add data-controller="example" to your markup alongside
* data-reflex="Example#dance" for the lifecycle methods to fire properly.
*
* Example:
*
* <a href="#" data-reflex="click->Example#dance" data-controller="example">Dance!</a>
*
* Arguments:
*
* element - the element that triggered the reflex
* may be different than the Stimulus controller's this.element
*
* reflex - the name of the reflex e.g. "Example#dance"
*
* error/noop - the error message (for reflexError), otherwise null
*
* reflexId - a UUID4 or developer-provided unique identifier for each Reflex
*/
// Assuming you create a "Example#dance" action in your Reflex class
// you'll be able to use the following lifecycle methods:
// beforeDance(element, reflex, noop, reflexId) {
// element.innerText = 'Putting dance shoes on...'
// }
// danceSuccess(element, reflex, noop, reflexId) {
// element.innerText = '\nDanced like no one was watching! Was someone watching?'
// }
// danceError(element, reflex, error, reflexId) {
// console.error('danceError', error);
// element.innerText = "\nCouldn\'t dance!"
// }
// afterDance(element, reflex, noop, reflexId) {
// element.innerText = '\nWhatever that was, it\'s over now.'
// }
// finalizeDance(element, reflex, noop, reflexId) {
// element.innerText = '\nNow, the cleanup can begin!'
// }
}

View File

@@ -4,3 +4,12 @@ import { definitionsFromContext } from "stimulus/webpack-helpers";
const application = Application.start();
const context = require.context("controllers", true, /.js$/);
application.load(definitionsFromContext(context));
import StimulusReflex from "stimulus_reflex";
import consumer from "../channels/consumer";
import controller from "../controllers/application_controller";
application.consumer = consumer;
StimulusReflex.initialize(application, { controller, isolate: true });
StimulusReflex.debug = process.env.RAILS_ENV === "development";
CableReady.initialize({ consumer });

View File

@@ -22,3 +22,12 @@ mrujs.start({
require.context("../fonts", true);
const images = require.context("../images", true);
const imagePath = (name) => images(name, true);
import StimulusReflex from "stimulus_reflex";
import consumer from "../channels/consumer";
import controller from "../controllers/application_controller";
application.consumer = consumer;
StimulusReflex.initialize(application, { controller, isolate: true });
StimulusReflex.debug = process.env.RAILS_ENV === "development";
CableReady.initialize({ consumer });

19
config/cable.yml Normal file
View File

@@ -0,0 +1,19 @@
development:
adapter: redis
url: <%= ENV.fetch("OFN_REDIS_URL", "redis://localhost:6379/1") %>
channel_prefix: your_application_development
production:
adapter: redis
url: <%= ENV.fetch("OFN_REDIS_URL", "redis://localhost:6380/0") %>
channel_prefix: your_application_production
staging:
adapter: redis
url: <%= ENV.fetch("OFN_REDIS_URL", "redis://localhost:6380/0") %>
channel_prefix: your_application_staging
test:
adapter: redis
url: <%= ENV.fetch("OFN_REDIS_URL", "redis://localhost:6379/1") %>
channel_prefix: your_application_test

View File

@@ -10,6 +10,10 @@ Openfoodnetwork::Application.configure do
# since you don't have to restart the web server when you make code changes.
config.cache_classes = !!ENV["PROFILE"]
config.action_controller.default_url_options = {host: "localhost", port: 3000}
config.session_store :cache_store, key: "_sessions_development", compress: true, pool_size: 5, expire_after: 1.year
# :file_store is used by default when no cache store is specifically configured.
if !!ENV["PROFILE"] || !!ENV["DEV_CACHING"]
config.cache_store = :redis_cache_store, {

View File

@@ -0,0 +1,18 @@
# frozen_string_literal: true
CableReady.configure do |config|
# Enable/disable exiting / warning when the sanity checks fail options:
# `:exit` or `:warn` or `:ignore`
# config.on_failed_sanity_checks = :exit
# Enable/disable exiting / warning when there's a new CableReady release
# `:exit` or `:warn` or `:ignore`
# config.on_new_version_available = :ignore
# Define your own custom operations
# https://cableready.stimulusreflex.com/customization#custom-operations
# config.add_operation_name :jazz_hands
end

View File

@@ -0,0 +1,32 @@
# frozen_string_literal: true
StimulusReflex.configure do |config|
config.on_failed_sanity_checks = :warn
# Enable/disable exiting / warning when the sanity checks fail options:
# `:exit` or `:warn` or `:ignore`
# config.on_failed_sanity_checks = :exit
# Override the parent class that the StimulusReflex ActionCable channel inherits from
# config.parent_channel = "ApplicationCable::Channel"
# Customize server-side Reflex logging format, with optional colorization:
# Available tokens: session_id, session_id_full, reflex_info, operation, reflex_id, reflex_id_full, mode, selector, operation_counter, connection_id, connection_id_full, timestamp
# Available colors: red, green, yellow, blue, magenta, cyan, white
# You can also use attributes from your ActionCable Connection's identifiers that resolve to valid ActiveRecord models
# eg. if your connection is `identified_by :current_user` and your User model has an email attribute, you can access r.email (it will display `-` if the user isn't logged in)
# Learn more at: https://docs.stimulusreflex.com/troubleshooting#stimulusreflex-logging
# config.logging = proc { "[#{session_id}] #{operation_counter.magenta} #{reflex_info.green} -> #{selector.cyan} via #{mode} Morph (#{operation.yellow})" }
# Optimized for speed, StimulusReflex doesn't enable Rack middleware by default.
# If you are using Page Morphs and your app uses Rack middleware to rewrite part of the request path, you must enable those middleware modules in StimulusReflex.
#
# Learn more about registering Rack middleware in Rails here: https://guides.rubyonrails.org/rails_on_rack.html#configuring-middleware-stack
# config.middleware.use FirstRackMiddleware
# config.middleware.use SecondRackMiddleware
end

View File

@@ -40,7 +40,8 @@
"@hotwired/turbo": "^7.1.0",
"@rails/webpacker": "5.4.3",
"babel-loader": "^8.2.3",
"cable_ready": "5.0.0-pre3",
"cable_ready": "5.0.0-pre9",
"stimulus_reflex": "3.5.0-pre9",
"flatpickr": "^4.6.9",
"foundation-sites": "^5.5.2",
"jquery-ui": "1.13.0",

View File

@@ -1726,9 +1726,9 @@
resolved "https://registry.yarnpkg.com/@hotwired/stimulus-webpack-helpers/-/stimulus-webpack-helpers-1.0.1.tgz#4cd74487adeca576c9865ac2b9fe5cb20cef16dd"
integrity sha512-wa/zupVG0eWxRYJjC1IiPBdt3Lruv0RqGN+/DTMmUWUyMAEB27KXmVY6a8YpUVTM7QwVuaLNGW4EqDgrS2upXQ==
"@hotwired/stimulus@^3.1.0":
"@hotwired/stimulus@>= 3.0", "@hotwired/stimulus@^3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@hotwired/stimulus/-/stimulus-3.1.0.tgz#20215251e5afe6e0a3787285181ba1bfc9097df0"
resolved "https://registry.npmjs.org/@hotwired/stimulus/-/stimulus-3.1.0.tgz#20215251e5afe6e0a3787285181ba1bfc9097df0"
integrity sha512-iDMHUhiEJ1xFeicyHcZQQgBzhtk5mPR0QZO3L6wtqzMsJEk2TKECuCQTGKjm+KJTHVY0dKq1dOOAWvODjpd2Mg==
"@hotwired/turbo@^7.1.0":
@@ -2133,6 +2133,11 @@
resolved "https://registry.yarnpkg.com/@orchidjs/sifter/-/sifter-0.9.2.tgz#86c84589fe42c46bb1f5ec1ab8f747a4c928a83b"
integrity sha512-8eR1aNWPhDt+cqOevGUajriiZbMzs6nGGdErUjSr99vMAxwMBRztnJu72OT8M7emyHTVjBB8BPjj4rJIoXQgKA==
"@rails/actioncable@>= 6.0":
version "7.0.3"
resolved "https://registry.npmjs.org/@rails/actioncable/-/actioncable-7.0.3.tgz#71f08e958883af64f6a20489318b5e95d2c6dc5b"
integrity sha512-Iefl21FZD+ck1di6xSHMYzSzRiNJTHV4NrAzCfDfqc/wPz4xncrP8f2/fJ+2jzwKIaDn76UVMsALh7R5OzsF8Q==
"@rails/webpacker@5.4.3":
version "5.4.3"
resolved "https://registry.yarnpkg.com/@rails/webpacker/-/webpacker-5.4.3.tgz#cfe2d8faffe7db5001bad50a1534408b4f2efb2f"
@@ -4211,10 +4216,10 @@ bytes@3.1.0:
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
cable_ready@5.0.0-pre3:
version "5.0.0-pre3"
resolved "https://registry.yarnpkg.com/cable_ready/-/cable_ready-5.0.0-pre3.tgz#d36bb9648aead748dfdf0f46dfb489799733f330"
integrity sha512-jFjTJ/K/AiVIgjKr63qXGzp9xZOt2/2UyjVpkMkSzFyDHlYILOwnK4WofGwBKS6tXwDZMfohbIzW/p+LKbrlgA==
cable_ready@5.0.0-pre9, "cable_ready@>= 5.0.0-pre9":
version "5.0.0-pre9"
resolved "https://registry.npmjs.org/cable_ready/-/cable_ready-5.0.0-pre9.tgz#9c082b796f7b7add7965ce637a8d8717726be5ab"
integrity sha512-m7XggG+LRPFLsbH78G603F3AAYpkv+VfGCouN6RrP20Mgz9H0+xr7v2DN2F1CeJBBAliYPKcAt/48uTGjSrBaA==
dependencies:
morphdom "^2.6.1"
@@ -12676,6 +12681,15 @@ stimulus@^3.0.1:
"@hotwired/stimulus" "^3.1.0"
"@hotwired/stimulus-webpack-helpers" "^1.0.0"
stimulus_reflex@3.5.0-pre9:
version "3.5.0-pre9"
resolved "https://registry.npmjs.org/stimulus_reflex/-/stimulus_reflex-3.5.0-pre9.tgz#e99eaf11e9e7476df10cd8f5c557d368f54446b3"
integrity sha512-ZhGUuJaKaWhHU5eGnZQ3pgnv0/pJ4dtNABDtMZRAHNm3ngsHY5dpR/H801a1ozD6J5rpadONvhhBcPjPY/x6NQ==
dependencies:
"@hotwired/stimulus" ">= 3.0"
"@rails/actioncable" ">= 6.0"
cable_ready ">= 5.0.0-pre9"
store2@^2.12.0:
version "2.12.0"
resolved "https://registry.yarnpkg.com/store2/-/store2-2.12.0.tgz#e1f1b7e1a59b6083b2596a8d067f6ee88fd4d3cf"