breezy 0.9.0 → 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4bd43b7f1b0d29427aa03dc2ba8602072a208ae9
4
- data.tar.gz: 8e5b735ee64a73a2ce2e327b4a917cadc79800ef
3
+ metadata.gz: ef5641dfcac8d3779955b4d9d8689e3861b5ddb9
4
+ data.tar.gz: 0bd4e918973827e046047b707b3e050490f35d98
5
5
  SHA512:
6
- metadata.gz: b3712cc47cec6d73de6d61d6f5adc655e28c7e58e7c02795d8e6eef45ddeab6f05dd7eb24b6791259d5e04d2c0e419379ce685a94251cbce2fe1838ecbd4607a
7
- data.tar.gz: adce7cc2ca1af9d817b1d53b0f890507d1208935ea7908dac8134799dbe5ecabbd93edfdb4ffcad4df27ff4087a22606a82757059459336a6ebcec23b672385c
6
+ metadata.gz: 278846c43c35a39e366dabb92e1b62b608349ace0dab982d87542b3a35ea76a6fbbdc6f42b8aa8fcdaebe6aec8024a327282565f6e3bc91bd842ba30e19d6172
7
+ data.tar.gz: 27dfef5d1aa6ab733e40d4cf3ad4ef43cfda050b397741b3cc3198373276b679daf0dca189de979798a0cd81ec2434b7060827081db751a4177736564d897da6
@@ -15,7 +15,7 @@ module Breezy
15
15
  filter = request.params[:_bz]
16
16
 
17
17
  if filter
18
- filter.gsub(/[^\da-zA-Z\=\.]+/, '')
18
+ filter.gsub(/[^\da-zA-Z\_\=\.]+/, '')
19
19
  end
20
20
  end
21
21
  end
@@ -12,5 +12,5 @@ json.attributes_for_form do
12
12
  <%- end -%>
13
13
  end
14
14
 
15
- json.post_path <%= singular_table_name%>_path(@<%=singular_table_name%>)
16
- json.posts_path <%= plural_table_name %>_path
15
+ json.<%= singular_table_name%>_path <%= singular_table_name%>_path(@<%=singular_table_name%>)
16
+ json.<%= plural_table_name %>_path <%= plural_table_name %>_path
@@ -5,10 +5,10 @@ json.<%= plural_table_name %> do
5
5
  <%- attributes_list_with_timestamps.each do |attr| -%>
6
6
  json.<%=attr%> <%= singular_table_name %>.<%=attr%>
7
7
  <%- end -%>
8
- json.edit_post_path edit_<%=singular_table_name%>_path(<%=singular_table_name%>)
9
- json.post_path <%=singular_table_name%>_path(<%=singular_table_name%>)
8
+ json.edit_<%=singular_table_name%>_path edit_<%=singular_table_name%>_path(<%=singular_table_name%>)
9
+ json.<%=singular_table_name%>_path <%=singular_table_name%>_path(<%=singular_table_name%>)
10
10
  end
11
11
  end
12
12
 
13
13
 
14
- json.new_post_path new_<%= singular_table_name %>_path
14
+ json.new_<%= singular_table_name %>_path new_<%= singular_table_name %>_path
@@ -1,12 +1,11 @@
1
1
  import React from 'react'
2
- import {withBrowserBehavior} from '@jho406/breezy'
2
+ import {enhanceVisitWithBrowserBehavior} from '@jho406/breezy'
3
3
 
4
4
  export default class extends React.Component {
5
5
  constructor (props) {
6
6
  super(props)
7
- const {visit, remote} = withBrowserBehavior(props.visit, props.remote)
8
- this.visit = visit.bind(this)
9
- this.remote = remote.bind(this)
7
+ const visit = enhanceVisitWithBrowserBehavior(props.visit)
8
+ this.enhancedVisit = visit.bind(this)
10
9
  }
11
10
  }
12
11
 
@@ -3,19 +3,20 @@ import {mapStateToProps, mapDispatchToProps} from '@jho406/breezy'
3
3
  import {connect} from 'react-redux'
4
4
  import BaseScreen from 'components/BaseScreen'
5
5
  import <%= plural_table_name.camelize %>Form from 'components/<%= plural_table_name.camelize %>Form'
6
+ import * as applicationActionCreators from 'javascript/packs/action_creators'
6
7
 
7
8
  class <%= plural_table_name.camelize %>Edit extends BaseScreen {
8
9
  formRef = React.createRef()
9
10
 
10
11
  handleSubmit = (values, {setSubmitting}) => {
11
- this.props.delInPage({pageKey: this.props.pageKey, keypath: 'errors'})
12
+ this.props.clearFormErrors(this.props.pageKey)
12
13
 
13
14
  const options = {
14
15
  method:'PUT',
15
16
  body: JSON.stringify(values),
16
17
  }
17
18
 
18
- this.visit(this.props.<%= singular_table_name %>, options).then( rsp => {
19
+ this.enhancedVisit(this.props.<%= singular_table_name.camelize(:lower) %>, options).then( rsp => {
19
20
  setSubmitting(false)
20
21
  if (this.props.errors) {
21
22
  this.formRef.current.setErrors(this.props.errors)
@@ -28,11 +29,11 @@ class <%= plural_table_name.camelize %>Edit extends BaseScreen {
28
29
  <div>
29
30
  <<%= plural_table_name.camelize %>Form
30
31
  onSubmit={this.handleSubmit}
31
- initialValues={this.props.attributes_for_form}
32
+ initialValues={this.props.attributesForForm}
32
33
  ref={this.formRef}
33
34
  />
34
- <a onClick={ e => this.visit(this.props.post_path)}>Show</a>
35
- <a onClick={ e => this.visit(this.props.posts_path)}>Back</a>
35
+ <a onClick={ e => this.enhancedVisit(this.props.<%= singular_table_name.camelize(:lower) %>Path)}>Show</a>
36
+ <a onClick={ e => this.enhancedVisit(this.props.<%= plural_table_name.camelize(:lower) %>Path)}>Back</a>
36
37
  </div>
37
38
  )
38
39
  }
@@ -40,7 +41,7 @@ class <%= plural_table_name.camelize %>Edit extends BaseScreen {
40
41
 
41
42
  export default connect(
42
43
  mapStateToProps,
43
- mapDispatchToProps
44
+ {...mapDispatchToProps, ...applicationActionCreators}
44
45
  )(<%= plural_table_name.camelize %>Edit)
45
46
 
46
47
 
@@ -4,7 +4,7 @@ import { Formik, Form, Field } from 'formik';
4
4
  export default React.forwardRef(
5
5
  ({initialValues = {
6
6
  <%- attributes_list.select{|attr| attr != :id }.each do |attr| -%>
7
- <%=attr.to_s%>:'',
7
+ <%=attr.camelize(:lower).to_s%>:'',
8
8
  <%- end -%>
9
9
  }, onSubmit}, ref) => {
10
10
  return (
@@ -17,7 +17,7 @@ export default React.forwardRef(
17
17
  <Form>
18
18
  <%- attributes_list.select{|attr| attr != :id }.each do |attr| -%>
19
19
  <Field type="text" name="<%=attr.to_s%>" />
20
- {errors.<%=attr.to_s%> && touched.<%=attr.to_s%> && errors.<%=attr.to_s%>}
20
+ {errors.<%=attr.camelize(:lower).to_s%> && touched.<%=attr.camelize(:lower).to_s%> && errors.<%=attr.camelize(:lower).to_s%>}
21
21
  <%- end -%>
22
22
 
23
23
  <button type="submit" disabled={isSubmitting}>
@@ -5,19 +5,19 @@ import BaseScreen from 'components/BaseScreen'
5
5
 
6
6
  class <%= plural_table_name.camelize %>Index extends BaseScreen {
7
7
  static defaultProps = {
8
- <%= plural_table_name %>: []
8
+ <%= plural_table_name.camelize(:lower) %>: []
9
9
  }
10
10
 
11
11
  render () {
12
- const <%= singular_table_name %>Items = this.props.<%= plural_table_name %>.map((<%= singular_table_name %>, key) => {
12
+ const <%= singular_table_name.camelize(:lower) %>Items = this.props.<%= plural_table_name.camelize(:lower) %>.map((<%= singular_table_name.camelize(:lower) %>, key) => {
13
13
  return (
14
- <tr key={<%= singular_table_name %>.id}>
14
+ <tr key={<%= singular_table_name.camelize(:lower) %>.id}>
15
15
  <%- attributes_list.select{|attr| attr != :id }.each do |attr| -%>
16
- <td>{<%=singular_table_name%>.<%=attr%>}</td>
16
+ <td>{<%=singular_table_name.camelize(:lower)%>.<%=attr.camelize(:lower)%>}</td>
17
17
  <%- end -%>
18
- <td><a onClick={ e => this.visit(<%=singular_table_name%>.post_path)}>Show</a></td>
19
- <td><a onClick={ e => this.visit(<%=singular_table_name%>.edit_post_path)}>Edit</a></td>
20
- <td><a onClick={ e => this.visit(<%=singular_table_name%>.post_path, {method: 'DELETE'})}>Delete</a></td>
18
+ <td><a onClick={ e => this.enhancedVisit(<%=singular_table_name%>.<%=singular_table_name.camelize(:lower)%>Path)}>Show</a></td>
19
+ <td><a onClick={ e => this.enhancedVisit(<%=singular_table_name%>.edit<%=singular_table_name.camelize%>Path)}>Edit</a></td>
20
+ <td><a onClick={ e => this.enhancedVisit(<%=singular_table_name%>.<%=singular_table_name.camelize(:lower)%>Path, {method: 'DELETE'})}>Delete</a></td>
21
21
  </tr>
22
22
  )
23
23
  })
@@ -43,7 +43,7 @@ class <%= plural_table_name.camelize %>Index extends BaseScreen {
43
43
  </tbody>
44
44
  </table>
45
45
  <br />
46
- <a onClick={ e => this.visit(this.props.new_post_path)}>New <%= singular_table_name.capitalize %></a>
46
+ <a onClick={ e => this.enhancedVisit(this.props.new<%= singular_table_name.camelize %>Path)}>New <%= singular_table_name.capitalize %></a>
47
47
  </div>
48
48
  )
49
49
  }
@@ -3,19 +3,20 @@ import {mapStateToProps, mapDispatchToProps} from '@jho406/breezy'
3
3
  import {connect} from 'react-redux'
4
4
  import BaseScreen from 'components/BaseScreen'
5
5
  import <%= plural_table_name.camelize %>Form from 'components/<%= plural_table_name.camelize %>Form'
6
+ import * as applicationActionCreators from 'javascript/packs/action_creators'
6
7
 
7
8
  class <%= plural_table_name.camelize %>New extends BaseScreen {
8
9
  formRef = React.createRef()
9
10
 
10
11
  handleSubmit = (values, {setSubmitting}) => {
11
- this.props.delInPage({pageKey: this.props.pageKey, keypath: 'errors'})
12
+ this.props.clearFormErrors(this.props.pageKey)
12
13
 
13
14
  const options = {
14
15
  method:'POST',
15
16
  body: JSON.stringify(values),
16
17
  }
17
18
 
18
- this.visit(this.props.<%= plural_table_name %>_path, options).then( rsp => {
19
+ this.enhancedVisit(this.props.<%= plural_table_name.camelize(:lower) %>Path, options).then( rsp => {
19
20
  setSubmitting(false)
20
21
  if (this.props.errors) {
21
22
  this.formRef.current.setErrors(this.props.errors)
@@ -30,7 +31,7 @@ class <%= plural_table_name.camelize %>New extends BaseScreen {
30
31
  onSubmit={this.handleSubmit}
31
32
  ref={this.formRef}
32
33
  />
33
- <a onClick={ e => this.visit(this.props.<%= plural_table_name %>_path)}>Back</a>
34
+ <a onClick={ e => this.enhancedVisit(this.props.<%= plural_table_name.camelize(:lower) %>Path)}>Back</a>
34
35
  </div>
35
36
  )
36
37
  }
@@ -38,6 +39,6 @@ class <%= plural_table_name.camelize %>New extends BaseScreen {
38
39
 
39
40
  export default connect(
40
41
  mapStateToProps,
41
- mapDispatchToProps
42
+ {...mapDispatchToProps, ...applicationActionCreators}
42
43
  )(<%= plural_table_name.camelize %>New)
43
44
 
@@ -11,11 +11,11 @@ class <%= plural_table_name.camelize %>Show extends BaseScreen {
11
11
  <%- attributes_list_with_timestamps.select{|attr| attr != :id }.each do |attr| -%>
12
12
  <p>
13
13
  <strong><%= attr.capitalize %>:</strong>
14
- {this.props.<%=attr%>}
14
+ {this.props.<%=attr.camelize(:lower)%>}
15
15
  </p>
16
16
  <%- end -%>
17
- <a onClick={ e => this.visit(this.props.edit_<%= singular_table_name %>_path)}>Edit</a>
18
- <a onClick={ e => this.visit(this.props.<%= plural_table_name %>_path )}>Back</a>
17
+ <a onClick={ e => this.enhancedVisit(this.props.edit<%= singular_table_name.camelize %>Path)}>Edit</a>
18
+ <a onClick={ e => this.enhancedVisit(this.props.<%= plural_table_name.camelize(:lower) %>Path )}>Back</a>
19
19
  </div>
20
20
  )
21
21
  }
@@ -0,0 +1,12 @@
1
+ import {
2
+ CLEAR_FORM_ERRORS
3
+ } from './actions'
4
+
5
+ export function clearFormErrors(pageKey) {
6
+ return {
7
+ type: CLEAR_FORM_ERRORS,
8
+ payload: {
9
+ pageKey,
10
+ }
11
+ }
12
+ }
@@ -0,0 +1 @@
1
+ export const CLEAR_FORM_ERRORS = 'CLEAR_FORM_ERRORS'
@@ -1,11 +1,14 @@
1
1
  import React from 'react'
2
2
  import {combineReducers, createStore, applyMiddleware, compose} from 'redux'
3
+ import reduceReducers from 'reduce-reducers'
3
4
  import thunk from 'redux-thunk'
4
5
  import { Provider } from 'react-redux'
5
6
  import { render } from 'react-dom'
6
7
  import createHistory from 'history/createBrowserHistory'
7
8
  import Breezy from '@jho406/breezy'
8
9
  import Nav from '@jho406/breezy/dist/NavComponent'
10
+ import applicationReducer from './reducer'
11
+
9
12
 
10
13
  // Mapping between your props template to Component
11
14
  // e.g {'posts/new': PostNew}
@@ -27,9 +30,15 @@ const {reducer, initialState, initialPageKey, connect} = Breezy.start({
27
30
 
28
31
  const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
29
32
 
33
+ const {
34
+ breezy: breezyReducer,
35
+ pages: pagesReducer,
36
+ } = reducer
37
+
30
38
  const store = createStore(
31
39
  combineReducers({
32
- ...reducer,
40
+ breezy: breezyReducer,
41
+ pages: reduceReducers(pagesReducer, applicationReducer),
33
42
  }),
34
43
  initialState,
35
44
  composeEnhancers(applyMiddleware(thunk))
@@ -41,6 +50,7 @@ class App extends React.Component {
41
50
  render() {
42
51
  return <Provider store={store}>
43
52
  <Nav
53
+ store={store}
44
54
  mapping={this.props.mapping}
45
55
  history={history}
46
56
  initialPageKey={initialPageKey}
@@ -18,7 +18,9 @@
18
18
  ["module-resolver", {
19
19
  "root": ["./app"],
20
20
  "alias": {
21
- "views": "./app/views"
21
+ "views": "./app/views",
22
+ "components": "./app/components",
23
+ "javascript": "./app/javascript"
22
24
  }
23
25
  }],
24
26
  "transform-object-rest-spread",
@@ -0,0 +1,19 @@
1
+ import {
2
+ CLEAR_FORM_ERRORS
3
+ } from './actions'
4
+ import produce from "immer"
5
+
6
+ export default function (state = {}, action) {
7
+ switch(action.type) {
8
+ case CLEAR_FORM_ERRORS: {
9
+ const {pageKey} = action.payload
10
+
11
+ return produce(state, draft => {
12
+ const currentPage = draft[pageKey]
13
+ delete currentPage.errors
14
+ })
15
+ }
16
+ default:
17
+ return state
18
+ }
19
+ }
@@ -24,7 +24,7 @@ def add_member_methods
24
24
  inject_into_file "app/models/application_record.rb", after: "class ApplicationRecord < ActiveRecord::Base\n" do
25
25
  <<-RUBY
26
26
  def self.member_at(index)
27
- offset(index).limit(1)
27
+ offset(index).limit(1).first
28
28
  end
29
29
 
30
30
  def self.member_by(attr, value)
@@ -56,7 +56,7 @@ if File.exist?(babelrc)
56
56
  "alias": {
57
57
  "views": "./app/views",
58
58
  "components": "./app/components",
59
- "javascripts": "./app/javascripts"
59
+ "javascript": "./app/javascript"
60
60
  }
61
61
  }])
62
62
 
@@ -75,6 +75,15 @@ end
75
75
  say "Copying application.js file to #{Webpacker.config.source_entry_path}"
76
76
  copy_file "#{__dir__}/templates/web/application.js", "#{Webpacker.config.source_entry_path}/application.js"
77
77
 
78
+ say "Copying reducer.js file to #{Webpacker.config.source_entry_path}"
79
+ copy_file "#{__dir__}/templates/web/reducer.js", "#{Webpacker.config.source_entry_path}/reducer.js"
80
+
81
+ say "Copying action_creators.js file to #{Webpacker.config.source_entry_path}"
82
+ copy_file "#{__dir__}/templates/web/action_creators.js", "#{Webpacker.config.source_entry_path}/action_creators.js"
83
+
84
+ say "Copying actions.js file to #{Webpacker.config.source_entry_path}"
85
+ copy_file "#{__dir__}/templates/web/actions.js", "#{Webpacker.config.source_entry_path}/actions.js"
86
+
78
87
  say "Copying Breezy initializer"
79
88
  copy_file "#{__dir__}/templates/web/initializer.rb", "config/initializers/breezy.rb"
80
89
 
@@ -85,7 +94,7 @@ say "Adding required member methods to ApplicationRecord"
85
94
  add_member_methods
86
95
 
87
96
  say "Installing React, Redux, and Breezy"
88
- run "yarn add babel-plugin-module-resolver babel-preset-react formik history prop-types react-redux redux-thunk redux react react-dom @jho406/breezy --save"
97
+ run "yarn add babel-plugin-module-resolver babel-preset-react formik history prop-types react-redux redux-thunk redux reduce-reducers react react-dom immer @jho406/breezy --save"
89
98
 
90
99
  say "Updating webpack paths to include .jsx file extension"
91
100
  insert_into_file Webpacker.config.config_path, " - .jsx\n", after: /extensions:\n/
@@ -0,0 +1,31 @@
1
+ require 'test_helper'
2
+
3
+ class HelpersTest < ActiveSupport::TestCase
4
+ include Breezy::Helpers
5
+ attr_reader :request
6
+
7
+ class Request
8
+ attr_reader :params
9
+ def initialize(params = {})
10
+ @params = params
11
+ end
12
+ end
13
+
14
+ test 'breezy_filter returns a valid _bz param' do
15
+ @request = Request.new({:_bz => 'foo.bar.baz_baz'})
16
+
17
+ assert_equal breezy_filter, 'foo.bar.baz_baz'
18
+ end
19
+
20
+ test 'breezy_filter removes invalid _bz param chars' do
21
+ @request = Request.new({:_bz => 'foo.bar/?)()-'})
22
+
23
+ assert_equal breezy_filter, 'foo.bar'
24
+ end
25
+
26
+ test 'breezy_filter return nil when no params are present' do
27
+ @request = Request.new({})
28
+
29
+ assert_nil breezy_filter
30
+ end
31
+ end
@@ -108,7 +108,7 @@ class RenderTest < ActionController::TestCase
108
108
  rendered = <<~HTML
109
109
  <html>
110
110
  <head>
111
- <script>(function(){var joints={};var cache={};var defers=[];return ({"data":#{content.to_json},"screen":"#{opts[:screen]}","csrf_token":"secret","assets":["/app.js"],"joints":joints,"defers":defers});})();</script>
111
+ <script>(function(){var fragments={};var lastFragmentName;var lastFragmentPath;var cache={};var defers=[];return ({"data":#{content.to_json},"screen":"#{opts[:screen]}","fragments":fragments,"privateOpts":{"csrfToken":"secret","assets":["/app.js"],"lastFragmentName":lastFragmentName,"lastFragmentPath":lastFragmentPath,"defers":defers}});})();</script>
112
112
  </head>
113
113
  <body></body>
114
114
  </html>
@@ -120,13 +120,13 @@ class RenderTest < ActionController::TestCase
120
120
 
121
121
  def assert_breezy_js(content)
122
122
  assert_response 200
123
- assert_equal '(function(){var joints={};var cache={};var defers=[];return ({"data":' + content.to_json + ',"screen":"render/action","csrf_token":"secret","assets":["/app.js"],"joints":joints,"defers":defers});})()', @response.body
123
+ assert_equal '(function(){var fragments={};var lastFragmentName;var lastFragmentPath;var cache={};var defers=[];return ({"data":' + content.to_json + ',"screen":"render/action","fragments":fragments,"privateOpts":{"csrfToken":"secret","assets":["/app.js"],"lastFragmentName":lastFragmentName,"lastFragmentPath":lastFragmentPath,"defers":defers}});})()', @response.body
124
124
  assert_equal 'text/javascript', @response.content_type
125
125
  end
126
126
 
127
127
  def assert_breezy_replace_js(content)
128
128
  assert_response 200
129
- assert_equal 'Breezy.replace((function(){return ({"data":' + content.to_json + ',"csrf_token":"secret","assets":["/app.js"]});})());', @response.body
129
+ assert_equal 'Breezy.replace((function(){return ({"data":' + content.to_json + ',"csrfToken":"secret","assets":["/app.js"]});})());', @response.body
130
130
  assert_equal 'text/javascript', @response.content_type
131
131
  end
132
132
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: breezy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Johny Ho
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-30 00:00:00.000000000 Z
11
+ date: 2019-01-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - '='
32
32
  - !ruby/object:Gem::Version
33
- version: 0.9.0
33
+ version: 0.10.1
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - '='
39
39
  - !ruby/object:Gem::Version
40
- version: 0.9.0
40
+ version: 0.10.1
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: webpacker
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -177,14 +177,18 @@ files:
177
177
  - lib/generators/rails/templates/web/index.jsx
178
178
  - lib/generators/rails/templates/web/new.jsx
179
179
  - lib/generators/rails/templates/web/show.jsx
180
+ - lib/install/templates/web/action_creators.js
181
+ - lib/install/templates/web/actions.js
180
182
  - lib/install/templates/web/application.js
181
183
  - lib/install/templates/web/babelrc
182
184
  - lib/install/templates/web/initializer.rb
185
+ - lib/install/templates/web/reducer.js
183
186
  - lib/install/web.rb
184
187
  - lib/tasks/install.rake
185
188
  - test/breezy_test.rb
186
189
  - test/configuration_test.rb
187
190
  - test/engine_test.rb
191
+ - test/helpers_test.rb
188
192
  - test/render_test.rb
189
193
  - test/test_helper.rb
190
194
  homepage: https://github.com/jho406/breezy/
@@ -214,6 +218,7 @@ summary: Rails integration for BreezyJS
214
218
  test_files:
215
219
  - test/render_test.rb
216
220
  - test/configuration_test.rb
221
+ - test/helpers_test.rb
217
222
  - test/engine_test.rb
218
223
  - test/test_helper.rb
219
224
  - test/breezy_test.rb