breezy 0.5.5 → 0.5.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/lib/breezy/helpers.rb +1 -1
  3. data/lib/breezy/xhr_headers.rb +9 -0
  4. data/lib/generators/rails/breezy_generator.rb +4 -18
  5. data/lib/generators/rails/scaffold_controller_generator.rb +0 -1
  6. data/lib/generators/rails/templates/edit.js.props +2 -4
  7. data/lib/generators/rails/templates/index.js.props +3 -8
  8. data/lib/generators/rails/templates/new.js.props +1 -3
  9. data/lib/generators/rails/templates/show.js.props +2 -4
  10. data/lib/generators/rails/templates/web/edit.jsx +11 -13
  11. data/lib/generators/rails/templates/web/form.jsx +28 -34
  12. data/lib/generators/rails/templates/web/index.jsx +4 -4
  13. data/lib/generators/rails/templates/web/new.jsx +10 -12
  14. data/lib/generators/rails/templates/web/show.jsx +2 -2
  15. data/lib/install/templates/web/application.js +0 -2
  16. data/lib/install/web.rb +1 -1
  17. metadata +4 -20
  18. data/lib/generators/breezy/view/templates/view.js.breezy +0 -17
  19. data/lib/generators/breezy/view/templates/view.jsx.mobile +0 -21
  20. data/lib/generators/breezy/view/templates/view.jsx.web +0 -24
  21. data/lib/generators/breezy/view/view_generator.rb +0 -68
  22. data/lib/generators/rails/templates/mobile/edit.jsx +0 -76
  23. data/lib/generators/rails/templates/mobile/elements.js +0 -88
  24. data/lib/generators/rails/templates/mobile/form.jsx +0 -34
  25. data/lib/generators/rails/templates/mobile/index.jsx +0 -103
  26. data/lib/generators/rails/templates/mobile/new.jsx +0 -75
  27. data/lib/generators/rails/templates/mobile/show.jsx +0 -32
  28. data/lib/install/mobile.rb +0 -54
  29. data/lib/install/templates/mobile/app.js +0 -77
  30. data/lib/install/templates/mobile/app.json +0 -6
  31. data/lib/install/templates/mobile/babelrc +0 -23
  32. data/lib/install/templates/mobile/package.json +0 -35
  33. data/lib/install/templates/mobile/rn-cli.config.js +0 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dbe2abbdcd65c8ff1a723ff25f966a3911b62d20
4
- data.tar.gz: 99fcaf756ab0ed0b8e99f2eaf2b5ed3ff98862d8
3
+ metadata.gz: 6c761721a71765c3ed4b56408ee45634044b8227
4
+ data.tar.gz: 4c22efd905a87bc5725fde7aa6aa04073ed4d770
5
5
  SHA512:
6
- metadata.gz: 499d93c621ca6e1cbbad91f1fa44ccd0f82b512c2f09e6ff62bfe60995288c96af8c0847c37999c05569635ec5b25b719fe329eed9a469a225c7adbc291f5f9b
7
- data.tar.gz: 5651fca636aacfc7c1f68dc6f3440c0d39069516dd970317f3c58ab63b6081287cd75184029e2eaa64cac7b0373e9027603c8db57793ffd3d5aaed9505ebc0e0
6
+ metadata.gz: a81fa42b4230d6116136d874dd75b347a81b4f84063c20c8aa16c42d153a22db8102a946b7c27a72854b6ac3b3f6b1bbac79e40738609838757ab66b9fb9bd9f
7
+ data.tar.gz: 33cddac08eed8376c3e04ee7c70bcbeeafc108b1bea5674d1ba3bb5734862cf7be8ccc4144f2a83752caeff85ff51806061766180cfa20a22a5cf3f7820a6e26
@@ -22,7 +22,7 @@ module Breezy
22
22
  end
23
23
 
24
24
  def breezy_filter
25
- filter = request.params[:_bz] || (session && session[:breezy_filter])
25
+ filter = request.params[:_bz]
26
26
 
27
27
  if filter
28
28
  filter.gsub(/[^\da-zA-Z\=\.]+/, '')
@@ -19,6 +19,15 @@ module Breezy
19
19
 
20
20
  if request.xhr? && request.headers["X-BREEZY-REQUEST"]
21
21
  self.status = 200
22
+
23
+ if params['_bz'] && !url.include?('_bz')
24
+ parsed_url = URI.parse(url)
25
+ qry_with_bz = URI.decode_www_form(String(parsed_url.query)) << ["_bz", params['_bz']]
26
+ parsed_url.query = URI.encode_www_form(qry_with_bz)
27
+
28
+ url = parsed_url.to_s
29
+ end
30
+
22
31
  response.headers["X-BREEZY-LOCATION"] = url
23
32
  end
24
33
 
@@ -9,7 +9,6 @@ module Rails
9
9
  source_root File.expand_path('../templates', __FILE__)
10
10
 
11
11
  argument :attributes, type: :array, default: [], banner: 'field:type field:type'
12
- class_option :platform, type: :string, default: 'web', enum: ['web', 'mobile']
13
12
 
14
13
  def create_root_folder
15
14
  path = File.join('app/views', controller_file_path)
@@ -26,21 +25,12 @@ module Rails
26
25
  %w(index show new edit).each do |view|
27
26
  @action_name = view
28
27
  filename = filename_with_jsx_extensions(view)
29
- if options[:platform] == 'mobile'
30
- template 'mobile/' + filename, File.join('app/views', controller_file_path, filename)
31
- else
32
- template 'web/' + filename, File.join('app/views', controller_file_path, filename)
33
- end
28
+ template 'web/' + filename, File.join('app/views', controller_file_path, filename)
34
29
  end
35
30
 
36
31
  js_filename = [plural_table_name, 'form.jsx'].map(&:camelcase).join
37
- if options[:platform] == 'mobile'
38
- template 'mobile/form.jsx', File.join('app/components', js_filename)
39
- template 'mobile/elements.js', File.join('app/components', 'elements.js')
40
- else
41
- template 'web/form.jsx', File.join('app/components', js_filename)
42
- template 'web/base.jsx', File.join('app/components', 'BaseScreen.jsx')
43
- end
32
+ template 'web/form.jsx', File.join('app/components', js_filename)
33
+ template 'web/base.jsx', File.join('app/components', 'BaseScreen.jsx')
44
34
 
45
35
  %w(index show new edit).each do |view|
46
36
  append_mapping(view)
@@ -50,11 +40,7 @@ module Rails
50
40
 
51
41
  protected
52
42
  def append_mapping(action)
53
- if options[:platform] == 'mobile'
54
- app_js = 'App.js'
55
- else
56
- app_js = 'app/javascript/packs/application.js'
57
- end
43
+ app_js = 'app/javascript/packs/application.js'
58
44
 
59
45
  base_parts = class_path + [file_name]
60
46
  destination = File.join("views", base_parts)
@@ -5,7 +5,6 @@ module Rails
5
5
  module Generators
6
6
  class ScaffoldControllerGenerator
7
7
  source_paths << File.expand_path('../templates', __FILE__)
8
- class_option :platform, type: :string, desc:'Indicates to generate React web or native components', default: 'web', enum: ['web', 'mobile']
9
8
 
10
9
  hook_for :breezy, type: :boolean, default: true
11
10
  end
@@ -12,7 +12,5 @@ json.attributes_for_form do
12
12
  <%- end -%>
13
13
  end
14
14
 
15
- json.meta do
16
- json.show_path <%=singular_table_name%>_path(@<%=singular_table_name%>)
17
- json.index_path <%= plural_table_name %>_path
18
- end
15
+ json.post_path <%= singular_table_name%>_path(@<%=singular_table_name%>)
16
+ json.posts_path <%= plural_table_name %>_path
@@ -3,11 +3,8 @@ json.<%= plural_table_name %> do
3
3
  <%- attributes_list_with_timestamps.each do |attr| -%>
4
4
  json.<%=attr%> <%= singular_table_name %>.<%=attr%>
5
5
  <%- end -%>
6
- json.meta do
7
- json.edit_path edit_<%=singular_table_name%>_path(<%=singular_table_name%>)
8
- json.show_path <%=singular_table_name%>_path(<%=singular_table_name%>)
9
- json.delete_path <%=singular_table_name%>_path(<%=singular_table_name%>)
10
- end
6
+ json.edit_post_path edit_<%=singular_table_name%>_path(<%=singular_table_name%>)
7
+ json.post_path <%=singular_table_name%>_path(<%=singular_table_name%>)
11
8
  end
12
9
  end
13
10
 
@@ -15,6 +12,4 @@ if notice
15
12
  json.notice notice
16
13
  end
17
14
 
18
- json.meta do
19
- json.new_path new_<%= singular_table_name %>_path
20
- end
15
+ json.new_post_path new_<%= singular_table_name %>_path
@@ -2,6 +2,4 @@ if @<%= singular_table_name %>.errors.any?
2
2
  json.errors @<%= singular_table_name %>.errors.to_h
3
3
  end
4
4
 
5
- json.meta do
6
- json.index_path <%= plural_table_name %>_path
7
- end
5
+ json.<%= plural_table_name %>_path <%= plural_table_name %>_path
@@ -6,7 +6,5 @@ if notice
6
6
  json.notice notice
7
7
  end
8
8
 
9
- json.meta do
10
- json.index_path <%= plural_table_name %>_path
11
- json.edit_path edit_<%= singular_table_name %>_path(@<%= singular_table_name %>)
12
- end
9
+ json.<%= plural_table_name %>_path <%= plural_table_name %>_path
10
+ json.edit_<%= singular_table_name %>_path edit_<%= singular_table_name %>_path(@<%= singular_table_name %>)
@@ -1,26 +1,24 @@
1
1
  import React from 'react'
2
2
  import {mapStateToProps, mapDispatchToProps} from '@jho406/breezy'
3
- import {delInPage} from '@jho406/breezy/dist/action_creators'
4
3
  import {connect} from 'react-redux'
5
4
  import BaseScreen from 'components/BaseScreen'
6
- import {SubmissionError} from 'redux-form'
7
5
  import <%= plural_table_name.camelize %>Form from 'components/<%= plural_table_name.camelize %>Form'
8
6
 
9
7
  class <%= plural_table_name.camelize %>Edit extends BaseScreen {
10
- handleSubmit = (body) => {
8
+ formRef = React.createRef()
9
+
10
+ handleSubmit = (values, {setSubmitting}) => {
11
11
  this.props.delInPage({pageKey: this.props.pageKey, keypath: 'errors'})
12
12
 
13
13
  const options = {
14
14
  method:'PUT',
15
- body: JSON.stringify(body),
15
+ body: JSON.stringify(values),
16
16
  }
17
- const path = '/<%= plural_table_name %>/' + this.props.id
18
17
 
19
- this.visit(path, options).then( rsp => {
18
+ this.visit(this.props.<%= singular_table_name %>, options).then( rsp => {
19
+ setSubmitting(false)
20
20
  if (this.props.errors) {
21
- throw new SubmissionError({
22
- ...this.props.errors
23
- })
21
+ this.formRef.current.setErrors(this.props.errors)
24
22
  }
25
23
  })
26
24
  }
@@ -29,12 +27,12 @@ class <%= plural_table_name.camelize %>Edit extends BaseScreen {
29
27
  return (
30
28
  <div>
31
29
  <<%= plural_table_name.camelize %>Form
32
- error={this.props.error}
33
30
  onSubmit={this.handleSubmit}
34
31
  initialValues={this.props.attributes_for_form}
32
+ ref={this.formRef}
35
33
  />
36
- <a onClick={ e => this.visit(this.props.meta.show_path)}>Show</a>
37
- <a onClick={ e => this.visit(this.props.meta.index_path)}>Back</a>
34
+ <a onClick={ e => this.visit(this.props.post_path)}>Show</a>
35
+ <a onClick={ e => this.visit(this.props.posts_path)}>Back</a>
38
36
  </div>
39
37
  )
40
38
  }
@@ -42,7 +40,7 @@ class <%= plural_table_name.camelize %>Edit extends BaseScreen {
42
40
 
43
41
  export default connect(
44
42
  mapStateToProps,
45
- {...mapDispatchToProps, delInPage}
43
+ mapDispatchToProps
46
44
  )(<%= plural_table_name.camelize %>Edit)
47
45
 
48
46
 
@@ -1,37 +1,31 @@
1
1
  import React from 'react'
2
- import { Field, reduxForm, stopSubmit, touch} from 'redux-form'
2
+ import { Formik, Form, Field } from 'formik';
3
3
 
4
- const RenderField = ({ input, label, type, meta: { touched, error } }) => (
5
- <div>
6
- <label>{label}</label>
7
- <div>
8
- <input {...input} placeholder={label} type={type} />
9
- {touched && error && <span>{error}</span>}
10
- </div>
11
- </div>
12
- )
13
-
14
- const SimpleForm = props => {
15
- const { error, handleSubmit, initialValue } = props
16
-
17
- return (
18
- <form onSubmit={handleSubmit}>
19
- <%- attributes_list.select{|attr| attr != :id }.each do |attr| -%>
20
- <label><%=attr.to_s.humanize%></label>
21
- <Field
22
- name="<%=attr.to_s.camelize(:lower)%>"
23
- component={RenderField}
24
- type="text"
25
- />
26
- <%- end -%>
27
- <button type="submit">
28
- Submit
29
- </button>
30
- </form>
31
- )
32
- }
33
-
34
- export default reduxForm({
35
- form: '<%=plural_table_name%>_form' // a unique identifier for this form
36
- })(SimpleForm)
4
+ export default React.forwardRef(
5
+ ({initialValues = {
6
+ <%- attributes_list.select{|attr| attr != :id }.each do |attr| -%>
7
+ <%=attr.to_s%>:'',
8
+ <%- end -%>
9
+ }, onSubmit}, ref) => {
10
+ return (
11
+ <Formik
12
+ initialValues={initialValues}
13
+ onSubmit={onSubmit}
14
+ ref={ref}
15
+ >
16
+ {({ errors, touched, isSubmitting }) => (
17
+ <Form>
18
+ <%- attributes_list.select{|attr| attr != :id }.each do |attr| -%>
19
+ <Field type="text" name="<%=attr.to_s%>" />
20
+ {errors.<%=attr.to_s%> && touched.<%=attr.to_s%> && errors.<%=attr.to_s%>}
21
+ <%- end -%>
37
22
 
23
+ <button type="submit" disabled={isSubmitting}>
24
+ Submit
25
+ </button>
26
+ </Form>
27
+ )}
28
+ </Formik>
29
+ )
30
+ }
31
+ )
@@ -15,9 +15,9 @@ class <%= plural_table_name.camelize %>Index extends BaseScreen {
15
15
  <%- attributes_list.select{|attr| attr != :id }.each do |attr| -%>
16
16
  <td>{<%=singular_table_name%>.<%=attr%>}</td>
17
17
  <%- end -%>
18
- <td><a onClick={ e => this.visit(<%=singular_table_name%>.meta.show_path)}>Show</a></td>
19
- <td><a onClick={ e => this.visit(<%=singular_table_name%>.meta.edit_path)}>Edit</a></td>
20
- <td><a onClick={ e => this.visit(<%=singular_table_name%>.meta.delete_path, {method: 'DELETE'})}>Delete</a></td>
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>
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.meta.new_path)}>New <%= singular_table_name.capitalize %></a>
46
+ <a onClick={ e => this.visit(this.props.new_post_path)}>New <%= singular_table_name.capitalize %></a>
47
47
  </div>
48
48
  )
49
49
  }
@@ -1,38 +1,36 @@
1
1
  import React from 'react'
2
2
  import {mapStateToProps, mapDispatchToProps} from '@jho406/breezy'
3
- import {delInPage} from '@jho406/breezy/dist/action_creators'
4
3
  import {connect} from 'react-redux'
5
4
  import BaseScreen from 'components/BaseScreen'
6
- import {SubmissionError} from 'redux-form'
7
5
  import <%= plural_table_name.camelize %>Form from 'components/<%= plural_table_name.camelize %>Form'
8
6
 
9
7
  class <%= plural_table_name.camelize %>New extends BaseScreen {
10
- handleSubmit = (body) => {
8
+ formRef = React.createRef()
9
+
10
+ handleSubmit = (values, {setSubmitting}) => {
11
11
  this.props.delInPage({pageKey: this.props.pageKey, keypath: 'errors'})
12
12
 
13
13
  const options = {
14
14
  method:'POST',
15
- body: JSON.stringify(body),
15
+ body: JSON.stringify(values),
16
16
  }
17
17
 
18
- this.visit('/<%= plural_table_name %>', options).then( rsp => {
18
+ this.visit(this.props.<%= plural_table_name %>_path, options).then( rsp => {
19
+ setSubmitting(false)
19
20
  if (this.props.errors) {
20
- throw new SubmissionError({
21
- ...this.props.errors
22
- })
21
+ this.formRef.current.setErrors(this.props.errors)
23
22
  }
24
23
  })
25
-
26
24
  }
27
25
 
28
26
  render () {
29
27
  return (
30
28
  <div>
31
29
  <<%= plural_table_name.camelize %>Form
32
- error={this.props.error}
33
30
  onSubmit={this.handleSubmit}
31
+ ref={this.formRef}
34
32
  />
35
- <a onClick={ e => this.visit(this.props.meta.index_path)}>Back</a>
33
+ <a onClick={ e => this.visit(this.props.<%= plural_table_name %>_path)}>Back</a>
36
34
  </div>
37
35
  )
38
36
  }
@@ -40,6 +38,6 @@ class <%= plural_table_name.camelize %>New extends BaseScreen {
40
38
 
41
39
  export default connect(
42
40
  mapStateToProps,
43
- {...mapDispatchToProps, delInPage}
41
+ mapDispatchToProps
44
42
  )(<%= plural_table_name.camelize %>New)
45
43
 
@@ -14,8 +14,8 @@ class <%= plural_table_name.camelize %>Show extends BaseScreen {
14
14
  {this.props.<%=attr%>}
15
15
  </p>
16
16
  <%- end -%>
17
- <a onClick={ e => this.visit(this.props.meta.edit_path)}>Edit</a>
18
- <a onClick={ e => this.visit(this.props.meta.index_path)}>Back</a>
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>
19
19
  </div>
20
20
  )
21
21
  }
@@ -4,7 +4,6 @@ import thunk from 'redux-thunk'
4
4
  import { Provider } from 'react-redux'
5
5
  import { render } from 'react-dom'
6
6
  import createHistory from 'history/createBrowserHistory'
7
- import { reducer as formReducer } from 'redux-form'
8
7
  import Breezy from '@jho406/breezy'
9
8
 
10
9
  // This mapping can be auto populate through
@@ -29,7 +28,6 @@ const {reducer, initialState, Nav, connect} = Breezy.start({
29
28
  const store = createStore(
30
29
  combineReducers({
31
30
  ...reducer,
32
- form: formReducer
33
31
  }),
34
32
  initialState,
35
33
  applyMiddleware(thunk)
@@ -85,7 +85,7 @@ say "Adding required member methods to ApplicationRecord"
85
85
  add_member_methods
86
86
 
87
87
  say "Installing React, Redux, and Breezy"
88
- run "yarn add react-redux redux react react-dom babel-preset-react prop-types redux-form @jho406/breezy --save"
88
+ run "yarn add react-redux redux react react-dom babel-preset-react prop-types formik @jho406/breezy --save"
89
89
  run "yarn add babel-plugin-module-resolver --save-dev"
90
90
 
91
91
  say "Updating webpack paths to include .jsx file extension"
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.5.5
4
+ version: 0.5.6
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-09-06 00:00:00.000000000 Z
11
+ date: 2018-10-03 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.5.5
33
+ version: 0.5.6
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.5.5
40
+ version: 0.5.6
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: webpacker
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -164,21 +164,11 @@ files:
164
164
  - lib/breezy/x_domain_blocker.rb
165
165
  - lib/breezy/xhr_headers.rb
166
166
  - lib/breezy/xhr_url_for.rb
167
- - lib/generators/breezy/view/templates/view.js.breezy
168
- - lib/generators/breezy/view/templates/view.jsx.mobile
169
- - lib/generators/breezy/view/templates/view.jsx.web
170
- - lib/generators/breezy/view/view_generator.rb
171
167
  - lib/generators/rails/breezy_generator.rb
172
168
  - lib/generators/rails/scaffold_controller_generator.rb
173
169
  - lib/generators/rails/templates/controller.rb.tt
174
170
  - lib/generators/rails/templates/edit.js.props
175
171
  - lib/generators/rails/templates/index.js.props
176
- - lib/generators/rails/templates/mobile/edit.jsx
177
- - lib/generators/rails/templates/mobile/elements.js
178
- - lib/generators/rails/templates/mobile/form.jsx
179
- - lib/generators/rails/templates/mobile/index.jsx
180
- - lib/generators/rails/templates/mobile/new.jsx
181
- - lib/generators/rails/templates/mobile/show.jsx
182
172
  - lib/generators/rails/templates/new.js.props
183
173
  - lib/generators/rails/templates/show.js.props
184
174
  - lib/generators/rails/templates/web/base.jsx
@@ -187,12 +177,6 @@ files:
187
177
  - lib/generators/rails/templates/web/index.jsx
188
178
  - lib/generators/rails/templates/web/new.jsx
189
179
  - lib/generators/rails/templates/web/show.jsx
190
- - lib/install/mobile.rb
191
- - lib/install/templates/mobile/app.js
192
- - lib/install/templates/mobile/app.json
193
- - lib/install/templates/mobile/babelrc
194
- - lib/install/templates/mobile/package.json
195
- - lib/install/templates/mobile/rn-cli.config.js
196
180
  - lib/install/templates/web/application.js
197
181
  - lib/install/templates/web/babelrc
198
182
  - lib/install/templates/web/initializer.rb
@@ -1,17 +0,0 @@
1
- # Example:
2
- #
3
- # json.notice notice
4
- #
5
- # json.posts do
6
- # json.array! @posts do |post|
7
- # json.id post.id
8
- # json.title post.title
9
- # json.body post.body
10
- #
11
- # json.show_url post_path(post)
12
- # json.edit_url edit_post_path(post)
13
- # json.delete_url post_path(post)
14
- # end
15
- # end
16
- #
17
- json.greetings 'Change me'
@@ -1,21 +0,0 @@
1
- import React from 'react'
2
- import {mapStateToProps, mapDispatchToProps} from '@jho406/breezy'
3
- import { connect } from 'react-redux'
4
- import {View, Text} from 'react-native'
5
-
6
- class <%= @js_filename %> extends React.Component {
7
- render () {
8
- return (
9
- <View>
10
- <Text>
11
- {this.props.greetings}
12
- </Text>
13
- </View>
14
- )
15
- }
16
- }
17
-
18
- export default connect(
19
- mapStateToProps,
20
- mapDispatchToProps
21
- )(<%= @js_filename %>)
@@ -1,24 +0,0 @@
1
- import React from 'react'
2
- import {mapStateToProps, mapDispatchToProps, withBrowserBehavior} from '@jho406/breezy'
3
- import { connect } from 'react-redux'
4
-
5
- class <%= @js_filename %> extends React.Component {
6
- constructor (props) {
7
- super(props)
8
- const {visit, remote} = withBrowserBehavior(props.visit, props.remote)
9
- this.visit = visit.bind(this)
10
- this.remote = remote.bind(this)
11
- }
12
-
13
- render () {
14
- return (
15
- <div> {this.props.greetings}
16
- </div>
17
- )
18
- }
19
- }
20
-
21
- export default connect(
22
- mapStateToProps,
23
- mapDispatchToProps
24
- )(<%= @js_filename %>)
@@ -1,68 +0,0 @@
1
- module Breezy
2
- module Generators
3
- class ViewGenerator < ::Rails::Generators::NamedBase
4
- desc <<-DESC
5
- Description:
6
- Creates a content view and jsx view.
7
- DESC
8
- class_option :target,
9
- aliases: '-t',
10
- type: :string,
11
- default: 'web',
12
- desc: 'Specify target platform',
13
- enum: ['web', 'mobile']
14
-
15
- argument :actions, type: :array, default: [], banner: "action action"
16
-
17
- def self.source_root
18
- @source_root ||= File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
19
- end
20
-
21
- def copy_view_files
22
- base_parts = class_path + [file_name]
23
- destination = File.join("app/views", base_parts)
24
-
25
-
26
- actions.each do |action|
27
- @action = action
28
- @js_filename = (base_parts + [action]).map(&:camelcase).join
29
- @content_path = File.join(destination, "#{@action}.js.props")
30
-
31
- if options[:target] == 'mobile'
32
- @view_ext = 'jsx.mobile'
33
- else
34
- @view_ext = 'jsx.web' #todo fix me
35
- end
36
-
37
- @view_path = File.join(destination, "#{@action}.jsx")
38
-
39
- template "view.#{@view_ext}", @view_path
40
- template 'view.js.breezy', @content_path
41
- end
42
- end
43
-
44
- def append_mapping
45
- if options[:platform] == 'mobile'
46
- app_js = 'App.js'
47
- else
48
- app_js = 'app/javascript/packs/application.js'
49
- end
50
-
51
- base_parts = class_path + [file_name]
52
- destination = File.join("views", base_parts)
53
-
54
- actions.each do |action|
55
- @js_filename = (base_parts + [action]).map(&:camelcase).join
56
-
57
- inject_into_file app_js, after: "from '@jho406/breezy'" do
58
- "\nimport #{@js_filename} from '#{destination}/#{action}'"
59
- end
60
-
61
- inject_into_file app_js, after: 'const mapping = {' do
62
- "\n #{@js_filename},"
63
- end
64
- end
65
- end
66
- end
67
- end
68
- end
@@ -1,76 +0,0 @@
1
- import React from 'react'
2
- import {submit} from 'redux-form'
3
- import {Header} from 'react-native-elements'
4
- import {SubmissionError} from 'redux-form'
5
- import {View} from 'react-native'
6
- import {connect} from 'react-redux'
7
- import {delInPage} from '@jho406/breezy/dist/action_creators'
8
- import {mapStateToProps, mapDispatchToProps} from '@jho406/breezy'
9
- import <%= plural_table_name.camelize %>Form from 'components/<%= plural_table_name.camelize %>Form'
10
- import {Container, BarSaveAndGoBack, BarCancel} from 'components/elements'
11
-
12
- class <%= plural_table_name.camelize %>Edit extends React.Component {
13
- constructor (props) {
14
- super(props)
15
- this.submit = this.submit.bind(this)
16
- this.remoteSubmit = this.remoteSubmit.bind(this)
17
- }
18
-
19
- submit (body) {
20
- const options = {
21
- method: 'PATCH',
22
- body: JSON.stringify(body),
23
- contentType: 'application/json'
24
- }
25
-
26
- this.props.delInPage({pageKey: this.props.pageKey, keypath: 'errors'})
27
- return this.props.visit('/<%= plural_table_name %>/' + this.props.id, options).then((rsp) => {
28
- if (this.props.errors) {
29
- throw new SubmissionError({
30
- ...this.props.errors
31
- })
32
- }
33
- if (rsp.canNavigate) {
34
- return this.props.navigation.goBack()
35
- } else {
36
- // There can only ve one visit at a time, if `canNavigate`
37
- // is false, then this request is being ignored for a more
38
- // recent visit. Do Nothing.
39
- return
40
- }
41
-
42
- }).catch((err) => {
43
- if (err instanceof SubmissionError) {
44
- throw err
45
- } else {
46
- //handle other errors here
47
- }
48
- })
49
- }
50
-
51
- remoteSubmit () {
52
- this.props.remoteSubmit('<%=plural_table_name%>_form')
53
- }
54
-
55
- render () {
56
- const headerOptions = {
57
- leftComponent: (<BarSaveAndGoBack onPress={this.remoteSubmit} />),
58
- rightComponent: (<BarCancel onPress={e => this.props.navigation.goBack()} />)
59
- }
60
- return (
61
- <View>
62
- <Header {...headerOptions}/>
63
- <Container>
64
- <<%= plural_table_name.camelize %>Form error={this.props.error} onSubmit={this.submit} initialValues={this.props.attributes_for_form}/>
65
- </Container>
66
- </View>
67
- )
68
- }
69
- }
70
-
71
- export default connect(
72
- mapStateToProps,
73
- {...mapDispatchToProps, remoteSubmit: submit, delInPage}
74
- )(<%= plural_table_name.camelize %>Edit)
75
-
76
-
@@ -1,88 +0,0 @@
1
- import React from 'react'
2
- import {View, Text, ScrollView, TouchableOpacity, Alert} from 'react-native'
3
- import {Header, Card, ListItem, Icon, Button} from 'react-native-elements'
4
-
5
- export function Container(props) {
6
- return <ScrollView contentContainerStyle={{paddingBottom: 100, flexDirection: 'column'}}>
7
- {props.children}
8
- </ScrollView>
9
- }
10
-
11
- export function BarSaveAndGoBack({onPress}) {
12
- return (
13
- <TouchableOpacity onPress={onPress} style={{flex: 1, flexDirection: 'row', alignItems: 'flex-end'}}>
14
- <Icon
15
- name='chevron-left'
16
- color='#fff'
17
- size={18}
18
- underlayColor='rgba(0, 0, 0, 0)'
19
- />
20
- <Text style={{color: '#fff'}}>SAVE AND GO BACK</Text>
21
- </TouchableOpacity>
22
- )
23
- }
24
-
25
- export function BarGoBack({onPress}) {
26
- return (
27
- <TouchableOpacity onPress={onPress} style={{flex: 1, flexDirection: 'row', alignItems: 'flex-end'}}>
28
- <Icon
29
- name='chevron-left'
30
- color='#fff'
31
- size={18}
32
- underlayColor='rgba(0, 0, 0, 0)'
33
- />
34
- <Text style={{color: '#fff'}}>BACK</Text>
35
- </TouchableOpacity>
36
- )
37
- }
38
-
39
- export function BarCancel({onPress}) {
40
- return (
41
- <TouchableOpacity onPress={onPress} style={{flex: 1, flexDirection: 'row', alignItems: 'flex-end'}}>
42
- <Text style={{color: '#fff'}}>CANCEL</Text>
43
- </TouchableOpacity>
44
- )
45
- }
46
-
47
- export function BarNew ({onPress}) {
48
- return (
49
- <TouchableOpacity
50
- onPress={onPress}
51
- style={{flex: 1, flexDirection: 'row', alignItems: 'flex-end'}}>
52
- <Icon
53
- name='note-add'
54
- color='#fff'
55
- size={18}
56
- underlayColor='rgba(0, 0, 0, 0)'
57
- />
58
- <Text style={{color: '#fff'}}>NEW</Text>
59
- </TouchableOpacity>
60
- )
61
- }
62
-
63
- export function IconDelete({onPress}) {
64
- return <Icon
65
- raised
66
- name='close'
67
- color='#f50'
68
- size={13}
69
- onPress={onPress}/>
70
- }
71
- export function IconEdit({onPress}) {
72
- return <Icon
73
- raised
74
- name='mode-edit'
75
- color='#f50'
76
- size={13}
77
- onPress={onPress}/>
78
-
79
- }
80
- export function IconShow({onPress}) {
81
- return <Icon
82
- raised
83
- name='more-horiz'
84
- color='#f50'
85
- size={13}
86
- onPress={onPress}/>
87
- }
88
-
@@ -1,34 +0,0 @@
1
- import React from 'react'
2
- import { Field, reduxForm, stopSubmit, touch} from 'redux-form'
3
- import {View, Text} from 'react-native'
4
- import { FormLabel, FormInput, FormValidationMessage } from 'react-native-elements'
5
-
6
- const RenderField = ({ input, label, type, meta: { touched, error } }) => {
7
- return (
8
- <View>
9
- <FormLabel><Text>{label}</Text></FormLabel>
10
- <FormInput onChangeText={input.onChange} value={input.value} placeholder={`Please enter ${label}`}/>
11
- {touched && error && <FormValidationMessage><Text>{error}</Text></FormValidationMessage>}
12
- </View>
13
- )
14
- }
15
- const SimpleForm = props => {
16
- const { error, handleSubmit, initialValue } = props
17
-
18
- return (
19
- <View><% attributes_list.select{|attr| attr != :id }.each do |attr| %>
20
- <Field
21
- name="<%=attr.to_s.camelize(:lower)%>"
22
- label="<%=attr.to_s.humanize%>"
23
- component={RenderField}
24
- type="text"
25
- />
26
- <%end%></View>
27
- )
28
- }
29
-
30
- export default reduxForm({
31
- form: '<%=plural_table_name%>_form' // a unique identifier for this form
32
- })(SimpleForm)
33
-
34
-
@@ -1,103 +0,0 @@
1
- import React from 'react'
2
- import {mapDispatchToProps, mapStateToProps} from '@jho406/breezy'
3
- import {connect} from 'react-redux'
4
- import {View, Text, TouchableOpacity, Alert} from 'react-native'
5
- import {Header, Card} from 'react-native-elements'
6
- import DropdownAlert from 'react-native-dropdownalert';
7
- import {Container, IconDelete, IconEdit, IconShow, BarNew} from 'components/elements'
8
-
9
- class <%= plural_table_name.camelize %>Index extends React.Component {
10
- static defaultProps = {
11
- <%= plural_table_name %>: []
12
- }
13
-
14
- constructor (props) {
15
- super(props)
16
- this.handleClick = this.handleClick.bind(this)
17
- this.handleDeleteClick = this.handleDeleteClick.bind(this)
18
- }
19
-
20
- handleDeleteClick(path) {
21
- const method = 'DELETE'
22
-
23
- Alert.alert(
24
- 'Wait!',
25
- 'Are you sure you want to delete this <%=singular_table_name%>?',
26
- [
27
- {
28
- text: 'Delete',
29
- onPress: e => {this.props.visit(path, {method})},
30
- style: 'destructive'
31
- },
32
- { text: 'Cancel', style: 'cancel' },
33
- ],
34
- { cancelable: false }
35
- )
36
- }
37
-
38
- handleClick(path, method='GET') {
39
- const nav = this.props.navigation
40
- this.props.visit(path, {method}).then((rsp)=>{
41
- if (rsp.canNavigate) {
42
- return nav.navigate(rsp.screen, {pageKey: rsp.pageKey})
43
- } else {
44
- // There can only be one visit at a time, if `canNavigate`
45
- // is false, then this request is being ignored for a more
46
- // recent visit. Do Nothing.
47
- return
48
- }
49
- })
50
- }
51
-
52
- showNotice (message) {
53
- if (message) {
54
- setImmediate(() => {
55
- this.dropdown.alertWithType('success', 'Success', message);
56
- })
57
-
58
- return <DropdownAlert ref={ref => this.dropdown = ref} translucent={true}/>
59
- } else {
60
- return null
61
- }
62
- }
63
-
64
- render () {
65
- const headerOptions = {
66
- centerComponent: { text: 'POSTS', style: { color: '#fff' } },
67
- rightComponent: (<BarNew
68
- onPress={e => this.handleClick('/<%=plural_table_name%>/new')}
69
- />)
70
- }
71
-
72
- return (
73
- <View>
74
- <Header {...headerOptions}/>
75
- <Container>
76
- {this.props.<%=plural_table_name%>.map((<%=singular_table_name%>) => {
77
- const {show_path, edit_path, delete_path} = <%=singular_table_name%>.meta
78
- return (
79
- <Card key={<%=singular_table_name%>.id}>
80
- <TouchableOpacity>
81
- <% attributes_list.select{|attr| attr != :id }.each do |attr| %><Text style={{marginBottom: 10}}>{<%=singular_table_name%>.<%=attr%>}</Text>
82
- <% end %>
83
- </TouchableOpacity>
84
- <View style={{flex: 1, justifyContent: 'flex-end', flexDirection: 'row'}}>
85
- <IconDelete onPress={e => this.handleDeleteClick(delete_path)}/>
86
- <IconEdit onPress={e => this.handleClick(edit_path)}/>
87
- <IconShow onPress={e => this.handleClick(show_path)}/>
88
- </View>
89
- </Card>
90
- )
91
- })}
92
- </Container>
93
- {this.showNotice(this.props.notice)}
94
- </View>
95
- )
96
- }
97
- }
98
-
99
- export default connect(
100
- mapStateToProps,
101
- mapDispatchToProps
102
- )(<%= plural_table_name.camelize %>Index)
103
-
@@ -1,75 +0,0 @@
1
- import React from 'react'
2
- import {submit} from 'redux-form'
3
- import {Header} from 'react-native-elements'
4
- import {SubmissionError} from 'redux-form'
5
- import {View} from 'react-native'
6
- import {connect} from 'react-redux'
7
- import {delInPage} from '@jho406/breezy/dist/action_creators'
8
- import {mapStateToProps, mapDispatchToProps} from '@jho406/breezy'
9
- import <%= plural_table_name.camelize %>Form from 'components/<%= plural_table_name.camelize %>Form'
10
- import {Container, BarSaveAndGoBack, BarCancel} from 'components/elements'
11
-
12
- class <%= plural_table_name.camelize %>New extends React.Component {
13
- constructor (props) {
14
- super(props)
15
- this.submit = this.submit.bind(this)
16
- this.remoteSubmit = this.remoteSubmit.bind(this)
17
- }
18
-
19
- submit (body) {
20
- const options = {
21
- method: 'POST',
22
- body: JSON.stringify(body),
23
- contentType: 'application/json'
24
- }
25
-
26
- this.props.delInPage({pageKey: this.props.pageKey, keypath: 'errors'})
27
- return this.props.visit('/<%= plural_table_name %>', options).then((rsp) => {
28
- if (this.props.errors) {
29
- throw new SubmissionError({
30
- ...this.props.errors
31
- })
32
- }
33
- if (rsp.canNavigate) {
34
- return this.props.navigation.goBack()
35
- } else {
36
- // There can only ve one visit at a time, if `canNavigate`
37
- // is false, then this request is being ignored for a more
38
- // recent visit. Do Nothing.
39
- return
40
- }
41
- }).catch((err) => {
42
- if (err instanceof SubmissionError) {
43
- throw err
44
- } else {
45
- //handle other errors here
46
- }
47
- })
48
- }
49
-
50
- remoteSubmit () {
51
- this.props.remoteSubmit('<%=plural_table_name%>_form')
52
- }
53
-
54
- render () {
55
- const headerOptions = {
56
- leftComponent: (<BarSaveAndGoBack onPress={this.remoteSubmit} />),
57
- rightComponent: (<BarCancel onPress={e => this.props.navigation.goBack()} />)
58
- }
59
-
60
- return (
61
- <View>
62
- <Header {...headerOptions}/>
63
- <Container>
64
- <<%= plural_table_name.camelize %>Form error={this.props.error} onSubmit={this.submit}/>
65
- </Container>
66
- </View>
67
- )
68
- }
69
- }
70
-
71
- export default connect(
72
- mapStateToProps,
73
- {...mapDispatchToProps, remoteSubmit: submit, delInPage}
74
- )(<%= plural_table_name.camelize %>New)
75
-
@@ -1,32 +0,0 @@
1
- import React from 'react'
2
- import {mapStateToProps, mapDispatchToProps} from '@jho406/breezy'
3
- import {connect} from 'react-redux'
4
- import {Text, View} from 'react-native'
5
- import {Header, Card} from 'react-native-elements'
6
- import {Container, BarGoBack} from 'components/elements'
7
-
8
- class <%= plural_table_name.camelize %>Show extends React.Component {
9
- render() {
10
- const headerOptions = {
11
- leftComponent: (<BarGoBack onPress={ e => this.props.navigation.goBack()} />)
12
- }
13
-
14
- return (
15
- <View>
16
- <Header {...headerOptions}/>
17
- <Container>
18
- <Card><% attributes_list_with_timestamps.select{|attr| attr != :id }.each do |attr| %>
19
- <Text style={{fontWeight: 'bold'}}><%=attr%></Text>
20
- <Text>{this.props.<%=attr%>}</Text><% end %>
21
- </Card>
22
- </Container>
23
- </View>
24
- )
25
- }
26
- }
27
-
28
- export default connect(
29
- mapStateToProps,
30
- mapDispatchToProps
31
- )(<%= plural_table_name.camelize %>Show)
32
-
@@ -1,54 +0,0 @@
1
- babelrc = Rails.root.join(".babelrc")
2
-
3
- if File.exist?(babelrc)
4
- react_babelrc = JSON.parse(File.read(babelrc))
5
- react_babelrc["presets"] ||= []
6
- react_babelrc["plugins"] ||= []
7
-
8
- if !react_babelrc["presets"].include?("react")
9
- react_babelrc["presets"].push("react")
10
- say "Copying react preset to your .babelrc file"
11
-
12
- File.open(babelrc, "w") do |f|
13
- f.puts JSON.pretty_generate(react_babelrc)
14
- end
15
- end
16
-
17
- if !react_babelrc["plugins"].any?{|plugin| Array(plugin).include?("module-resolver")}
18
- react_babelrc["plugins"].push(["module-resolver", {
19
- "root": ["./app"],
20
- "alias": {
21
- "views": "./app/views",
22
- "components": "./app/components",
23
- "javascripts": "./app/javascripts"
24
- }
25
- }])
26
-
27
- say "Copying module-resolver preset to your .babelrc file"
28
-
29
- File.open(babelrc, "w") do |f|
30
- f.puts JSON.pretty_generate(react_babelrc)
31
- end
32
- end
33
-
34
- else
35
- say "Copying .babelrc to app root"
36
- copy_file "#{__dir__}/templates/mobile/babelrc", Rails.root.join(".babelrc")
37
- end
38
-
39
- say "Copying application.js file to app root"
40
- copy_file "#{__dir__}/templates/mobile/app.js", Rails.root.join("App.js")
41
-
42
- say "Copying rn-cli.config.js file to app root"
43
- copy_file "#{__dir__}/templates/mobile/rn-cli.config.js", Rails.root.join("rn-cli.config.js")
44
-
45
- say "Copying app.json expo file to app root"
46
- copy_file "#{__dir__}/templates/mobile/app.json", Rails.root.join("app.json")
47
-
48
- say "Copying package.json expo file to app root"
49
- copy_file "#{__dir__}/templates/mobile/package.json", Rails.root.join("package.json")
50
-
51
- say "Installing all breezy dependencies"
52
- run "yarn"
53
-
54
- say "Rails Breezy and ReactNative! 🎉", :green
@@ -1,77 +0,0 @@
1
- import React from 'react'
2
- import {combineReducers, createStore, applyMiddleware} from 'redux'
3
- import thunk from 'redux-thunk'
4
- import { Provider } from 'react-redux'
5
- import Breezy from '@jho406/breezy'
6
- import {visit} from '@jho406/breezy/dist/action_creators'
7
- import { StackNavigator } from 'react-navigation'
8
- import { reducer as formReducer } from 'redux-form'
9
-
10
- //Change the below when you have your first screen
11
- const baseUrl = 'http://localhost:3000'
12
- const initialPath = '/example'
13
- const initialPage = {
14
- data: {},
15
- screen: 'ExampleScreen'
16
- }
17
-
18
- // Remove me when you have your first screen
19
- import {View, Text} from 'react-native'
20
- class ExampleScreen extends React.Component {
21
- render() {
22
- return (
23
- <View style={{paddingTop: 50}}>
24
- <Text>Looks like you're up and running!</Text>
25
- <Text>Next create your rails routes and controllers as usual</Text>
26
- <Text>Then run the view generators `rails g breezy:view Post index -t mobile`</Text>
27
- <Text>When ready, remove this ExampleScreen from App.js</Text>
28
- </View>
29
- )
30
- }
31
- }
32
-
33
- // This mapping can be auto populate through
34
- // Breezy generators, for example:
35
- // Run `rails g breezy:view Post index --mobile`
36
- const mapping = {
37
- ExampleScreen, //Remove me when you have your first screen
38
- }
39
-
40
- const navMapping = Object.entries(mapping).reduce((memo, [key, value])=> {
41
- return {[key]: {screen: value}, ...memo}
42
- }, {})
43
-
44
- const {reducer, initialState, connect} = Breezy.start({
45
- initialPage,
46
- baseUrl
47
- })
48
-
49
- const store = createStore(
50
- combineReducers({
51
- ...reducer,
52
- form: formReducer
53
- }),
54
- initialState,
55
- applyMiddleware(thunk)
56
- )
57
-
58
- connect(store)
59
- store.dispatch({type: 'BREEZY_SET_BASE_URL', baseUrl})
60
-
61
- // Uncomment below if you need to fetch on the initial screen
62
- // store.dispatch(visit(initialPath))
63
- window.store = store
64
- const Nav = StackNavigator(navMapping, {
65
- initialRouteName: initialPage.screen,
66
- initialRouteParams: {pageKey: initialPath},
67
- headerMode: 'none',
68
- })
69
-
70
- export default class extends React.Component {
71
- render() {
72
- return <Provider store={store}>
73
- <Nav pageKey={initialPath}/>
74
- </Provider>
75
- }
76
- }
77
-
@@ -1,6 +0,0 @@
1
- {
2
- "expo": {
3
- "sdkVersion": "22.0.0"
4
- }
5
- }
6
-
@@ -1,23 +0,0 @@
1
- {
2
- "presets": ["babel-preset-expo"],
3
- "env": {
4
- "development": {
5
- "plugins": ["transform-react-jsx-source"]
6
- }
7
- },
8
- "plugins": [
9
- [
10
- "module-resolver",
11
- {
12
- "root": [
13
- "./app"
14
- ],
15
- "alias": {
16
- "views": "./app/views",
17
- "components": "./app/components",
18
- "javascripts": "./app/javascripts"
19
- }
20
- }
21
- ]
22
- ]
23
- }
@@ -1,35 +0,0 @@
1
- {
2
- "name": "myapp",
3
- "version": "0.1.0",
4
- "private": true,
5
- "devDependencies": {
6
- "jest-expo": "^22.0.0",
7
- "react-native-scripts": "1.7.0",
8
- "react-test-renderer": "16.0.0-beta.5"
9
- },
10
- "main": "./node_modules/react-native-scripts/build/bin/crna-entry.js",
11
- "scripts": {
12
- "start": "react-native-scripts start",
13
- "eject": "react-native-scripts eject",
14
- "android": "react-native-scripts android",
15
- "ios": "react-native-scripts ios",
16
- "test": "node node_modules/jest/bin/jest.js --watch"
17
- },
18
- "jest": {
19
- "preset": "jest-expo"
20
- },
21
- "dependencies": {
22
- "@jho406/breezy": "0.3.2",
23
- "expo": "^22.0.2",
24
- "react": "16.0.0-beta.5",
25
- "react-native": "^0.49.5",
26
- "react-native-dropdownalert": "3.1.2",
27
- "react-native-elements": "^0.19.0",
28
- "react-navigation": "^1.0.0-beta.19",
29
- "react-redux": "^5.0.6",
30
- "redux": "^3.7.2",
31
- "redux-form": "^7.2.0",
32
- "redux-thunk": "^2.2.0"
33
- }
34
- }
35
-
@@ -1,4 +0,0 @@
1
- module.exports = {
2
- getSourceExts: () => [ 'jsx' ],
3
- }
4
-