breezy 0.9.0 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +5 -5
  2. data/lib/breezy.rb +10 -15
  3. data/lib/breezy/helpers.rb +541 -11
  4. data/lib/breezy/redirection.rb +30 -0
  5. data/lib/breezy/xhr_headers.rb +0 -10
  6. data/lib/generators/rails/breezy_generator.rb +13 -4
  7. data/lib/generators/rails/templates/_form.json.props +13 -0
  8. data/lib/generators/rails/templates/controller.rb.tt +0 -3
  9. data/lib/generators/rails/templates/edit.json.props +14 -0
  10. data/lib/generators/rails/templates/index.json.props +13 -0
  11. data/lib/generators/rails/templates/new.json.props +15 -0
  12. data/lib/generators/rails/templates/{show.js.props → show.json.props} +0 -2
  13. data/lib/generators/rails/templates/web/base.jsx +3 -4
  14. data/lib/generators/rails/templates/web/edit.html.erb +11 -0
  15. data/lib/generators/rails/templates/web/edit.jsx +22 -27
  16. data/lib/generators/rails/templates/web/index.html.erb +10 -0
  17. data/lib/generators/rails/templates/web/index.jsx +13 -9
  18. data/lib/generators/rails/templates/web/new.html.erb +11 -0
  19. data/lib/generators/rails/templates/web/new.jsx +19 -24
  20. data/lib/generators/rails/templates/web/show.html.erb +12 -0
  21. data/lib/generators/rails/templates/web/show.jsx +3 -3
  22. data/lib/install/templates/web/action_creators.js +14 -0
  23. data/lib/install/templates/web/actions.js +3 -0
  24. data/lib/install/templates/web/application.js +30 -5
  25. data/lib/install/templates/web/application.json.props +25 -0
  26. data/lib/install/templates/web/initializer.rb +1 -6
  27. data/lib/install/templates/web/reducer.js +28 -0
  28. data/lib/install/web.rb +27 -40
  29. data/lib/tasks/install.rake +11 -7
  30. data/test/helpers_test.rb +23 -0
  31. data/test/render_test.rb +25 -92
  32. data/test/test_helper.rb +2 -2
  33. metadata +32 -30
  34. data/app/views/breezy/response.html.erb +0 -0
  35. data/lib/breezy/configuration.rb +0 -35
  36. data/lib/breezy/render.rb +0 -37
  37. data/lib/generators/rails/templates/edit.js.props +0 -16
  38. data/lib/generators/rails/templates/index.js.props +0 -14
  39. data/lib/generators/rails/templates/new.js.props +0 -4
  40. data/lib/generators/rails/templates/web/form.jsx +0 -31
  41. data/lib/install/templates/web/babelrc +0 -33
  42. data/test/breezy_test.rb +0 -125
  43. data/test/configuration_test.rb +0 -36
@@ -0,0 +1,30 @@
1
+ module Breezy
2
+ module Redirection
3
+ def _compute_redirect_to_location(request, options)
4
+ computed_location = URI.parse(super)
5
+ next_param = Rack::Utils
6
+ .parse_nested_query(computed_location.query)
7
+
8
+ if request.params[:__] == "0"
9
+ computed_location.query = next_param.merge({__: "0"}).to_query
10
+ end
11
+
12
+ computed_location.to_s
13
+ end
14
+
15
+ def redirect_back_with_bzq(opts)
16
+ if request.referrer && params[:bzq]
17
+ referrer_url = URI.parse(request.referrer)
18
+ referrer_url.query = Rack::Utils
19
+ .parse_nested_query(referrer_url.query)
20
+ .merge({bzq: params[:bzq]})
21
+ .to_query
22
+
23
+ redirect_to referrer_url.to_s, opts
24
+ else
25
+ redirect_back(opts)
26
+ end
27
+ end
28
+ end
29
+ end
30
+
@@ -17,17 +17,7 @@ module Breezy
17
17
  end
18
18
  end
19
19
 
20
- if request.xhr? && request.headers["X-BREEZY-REQUEST"]
21
- self.status = 200
22
- response.headers["X-BREEZY-LOCATION"] = url
23
- end
24
-
25
20
  url
26
21
  end
27
-
28
- private
29
- def set_response_url
30
- response.headers['X-RESPONSE-URL'] = request.fullpath
31
- end
32
22
  end
33
23
  end
@@ -21,6 +21,7 @@ module Rails
21
21
  filename = filename_with_extensions(view)
22
22
  template filename, File.join('app/views', controller_file_path, filename)
23
23
  end
24
+ template '_form.json.props', File.join('app/views', controller_file_path, '_form.json.props')
24
25
 
25
26
  %w(index show new edit).each do |view|
26
27
  @action_name = view
@@ -28,8 +29,12 @@ module Rails
28
29
  template 'web/' + filename, File.join('app/views', controller_file_path, filename)
29
30
  end
30
31
 
31
- js_filename = [plural_table_name, 'form.jsx'].map(&:camelcase).join
32
- template 'web/form.jsx', File.join('app/components', js_filename)
32
+ %w(index show new edit).each do |view|
33
+ @action_name = view
34
+ filename = filename_with_html_extensions(view)
35
+ template 'web/' + filename, File.join('app/views', controller_file_path, filename)
36
+ end
37
+
33
38
  template 'web/base.jsx', File.join('app/components', 'BaseScreen.jsx')
34
39
 
35
40
  %w(index show new edit).each do |view|
@@ -48,7 +53,7 @@ module Rails
48
53
  "\nimport #{component_name} from 'views/#{controller_file_path}/#{action}'"
49
54
  end
50
55
 
51
- inject_into_file app_js, after: 'const screenToComponentMapping = {' do
56
+ inject_into_file app_js, after: 'const identifierToComponentMapping = {' do
52
57
  "\n '#{[controller_file_path, action].join('/')}': #{component_name},"
53
58
  end
54
59
  end
@@ -62,13 +67,17 @@ module Rails
62
67
  end
63
68
 
64
69
  def filename_with_extensions(name)
65
- [name, :js, :props] * '.'
70
+ [name, :json, :props] * '.'
66
71
  end
67
72
 
68
73
  def filename_with_jsx_extensions(name)
69
74
  [name, :jsx] * '.'
70
75
  end
71
76
 
77
+ def filename_with_html_extensions(name)
78
+ [name, :html, :erb] * '.'
79
+ end
80
+
72
81
  def attributes_list_with_timestamps
73
82
  attributes_list(attributes_names + %w(created_at updated_at))
74
83
  end
@@ -0,0 +1,13 @@
1
+ html = form_with(model: @<%= model_resource_name %>, local: true) do |form|
2
+ inner = "".html_safe
3
+
4
+ <%- attributes.each do |attr| -%>
5
+ inner << form.label(:<%= attr.column_name %>)
6
+ inner << form.<%= attr.field_type %>(:<%= attr.column_name %>)
7
+ <%- end -%>
8
+ inner << form.submit
9
+
10
+ inner
11
+ end
12
+
13
+ json.html html
@@ -5,9 +5,6 @@ require_dependency "<%= namespaced_path %>/application_controller"
5
5
  <% module_namespacing do -%>
6
6
  class <%= controller_class_name %>Controller < ApplicationController
7
7
  before_action :set_<%= singular_table_name %>, only: [:show, :edit, :update, :destroy]
8
- # `use_breezy` enables breezy functionality
9
- # on application.html.erb
10
- before_action :use_breezy
11
8
 
12
9
  # GET <%= route_url %>
13
10
  def index
@@ -0,0 +1,14 @@
1
+ if @post.errors.any?
2
+ content = {
3
+ explanation: "#{pluralize(@<%= singular_table_name %>.errors.count, "error")} prohibited this post from being saved:",
4
+ messages: @<%= singular_table_name %>.errors.full_messages.map{|msg| {body: msg}}
5
+ }
6
+
7
+ flash.now[:form_error] = content
8
+ end
9
+
10
+ json.form(partial: 'form') do
11
+ end
12
+
13
+ json.<%= singular_table_name%>_path <%= singular_table_name%>_path(@<%=singular_table_name%>)
14
+ json.<%= plural_table_name %>_path <%= plural_table_name %>_path
@@ -0,0 +1,13 @@
1
+ json.<%= plural_table_name %> do
2
+ json.array! @<%= plural_table_name %> do |<%= singular_table_name %>|
3
+ <%- attributes_list_with_timestamps.each do |attr| -%>
4
+ json.<%=attr%> <%= singular_table_name %>.<%=attr%>
5
+ <%- end -%>
6
+ json.edit_<%=singular_table_name%>_path edit_<%=singular_table_name%>_path(<%=singular_table_name%>)
7
+ json.<%=singular_table_name%>_path <%=singular_table_name%>_path(<%=singular_table_name%>)
8
+ json.delete_<%=singular_table_name%>_path <%=singular_table_name%>_path(<%=singular_table_name%>)
9
+ end
10
+ end
11
+
12
+
13
+ json.new_<%= singular_table_name %>_path new_<%= singular_table_name %>_path
@@ -0,0 +1,15 @@
1
+ if @post.errors.any?
2
+ content = {
3
+ explanation: "#{pluralize(@<%= singular_table_name %>.errors.count, "error")} prohibited this post from being saved:",
4
+ messages: @<%= singular_table_name %>.errors.full_messages.map{|msg| {body: msg}}
5
+ }
6
+
7
+ flash.now[:form_error] = content
8
+ end
9
+
10
+ json.form(partial: 'form') do
11
+ end
12
+
13
+ json.<%= plural_table_name %>_path <%= plural_table_name %>_path
14
+
15
+
@@ -1,5 +1,3 @@
1
- json.flash flash.to_h
2
-
3
1
  <%- attributes_list_with_timestamps.each do |attr|-%>
4
2
  json.<%=attr%> @<%= singular_table_name %>.<%=attr%>
5
3
  <%- end -%>
@@ -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
 
@@ -0,0 +1,11 @@
1
+ <%% initial_state = controller.render_to_string(@virtual_path ,formats: [:json], locals: local_assigns, layout: true) %>
2
+
3
+ <%% content_for :initial_state do %>
4
+ <script type="text/javascript">
5
+ window.BREEZY_INITIAL_PAGE_STATE=<%%= initial_state.html_safe %>;
6
+ </script>
7
+ <%% end %>
8
+
9
+
10
+
11
+
@@ -2,37 +2,32 @@ import React from 'react'
2
2
  import {mapStateToProps, mapDispatchToProps} from '@jho406/breezy'
3
3
  import {connect} from 'react-redux'
4
4
  import BaseScreen from 'components/BaseScreen'
5
- import <%= plural_table_name.camelize %>Form from 'components/<%= plural_table_name.camelize %>Form'
5
+ import RailsTag from '@jho406/breezy/dist/RailsTag'
6
+ import * as applicationActionCreators from 'javascript/packs/action_creators'
6
7
 
7
8
  class <%= plural_table_name.camelize %>Edit extends BaseScreen {
8
- formRef = React.createRef()
9
-
10
- handleSubmit = (values, {setSubmitting}) => {
11
- this.props.delInPage({pageKey: this.props.pageKey, keypath: 'errors'})
12
-
13
- const options = {
14
- method:'PUT',
15
- body: JSON.stringify(values),
16
- }
17
-
18
- this.visit(this.props.<%= singular_table_name %>, options).then( rsp => {
19
- setSubmitting(false)
20
- if (this.props.errors) {
21
- this.formRef.current.setErrors(this.props.errors)
22
- }
23
- })
24
- }
25
-
26
9
  render () {
10
+ const {
11
+ form,
12
+ flash,
13
+ <%= singular_table_name.camelize(:lower) %>Path,
14
+ <%= plural_table_name.camelize(:lower) %>Path,
15
+ } = this.props
16
+ const error = flash.form_error
17
+
18
+ const messagesEl = error && (
19
+ <div id="error_explanation">
20
+ <h2>{ error.explanation }</h2>
21
+ <ul>{ error.messages.map(({body})=> <li key={body}>{body}</li>) }</ul>
22
+ </div>
23
+ )
24
+
27
25
  return (
28
26
  <div>
29
- <<%= plural_table_name.camelize %>Form
30
- onSubmit={this.handleSubmit}
31
- initialValues={this.props.attributes_for_form}
32
- ref={this.formRef}
33
- />
34
- <a onClick={ e => this.visit(this.props.post_path)}>Show</a>
35
- <a onClick={ e => this.visit(this.props.posts_path)}>Back</a>
27
+ {messagesEl}
28
+ <RailsTag {...form} data-bz-visit={true}/>
29
+ <a href={<%= singular_table_name.camelize(:lower) %>Path} data-bz-visit={true}>Show</a>
30
+ <a href={<%= plural_table_name.camelize(:lower) %>Path} data-bz-visit={true}>Back</a>
36
31
  </div>
37
32
  )
38
33
  }
@@ -40,7 +35,7 @@ class <%= plural_table_name.camelize %>Edit extends BaseScreen {
40
35
 
41
36
  export default connect(
42
37
  mapStateToProps,
43
- mapDispatchToProps
38
+ {...mapDispatchToProps, ...applicationActionCreators}
44
39
  )(<%= plural_table_name.camelize %>Edit)
45
40
 
46
41
 
@@ -0,0 +1,10 @@
1
+ <%% initial_state = controller.render_to_string(@virtual_path ,formats: [:json], locals: local_assigns, layout: true) %>
2
+
3
+ <%% content_for :initial_state do %>
4
+ <script type="text/javascript">
5
+ window.BREEZY_INITIAL_PAGE_STATE=<%%= initial_state.html_safe %>;
6
+ </script>
7
+ <%% end %>
8
+
9
+
10
+
@@ -5,26 +5,30 @@ 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 {
13
+ flash,
14
+ new<%= singular_table_name.camelize %>Path,
15
+ } = this.props
16
+ const <%= singular_table_name.camelize(:lower) %>Items = this.props.<%= plural_table_name.camelize(:lower) %>.map((<%= singular_table_name.camelize(:lower) %>, key) => {
13
17
  return (
14
- <tr key={<%= singular_table_name %>.id}>
18
+ <tr key={<%= singular_table_name.camelize(:lower) %>.id}>
15
19
  <%- attributes_list.select{|attr| attr != :id }.each do |attr| -%>
16
- <td>{<%=singular_table_name%>.<%=attr%>}</td>
20
+ <td>{<%=singular_table_name.camelize(:lower)%>.<%=attr.camelize(:lower)%>}</td>
17
21
  <%- 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>
22
+ <td><a href={ <%=singular_table_name%>.<%=singular_table_name.camelize(:lower)%>Path } data-bz-visit={true}>Show</a></td>
23
+ <td><a href={ <%=singular_table_name%>.edit<%=singular_table_name.camelize%>Path } data-bz-visit={true}>Edit</a></td>
24
+ <td><a href={ <%=singular_table_name%>.delete<%=singular_table_name.camelize%>Path }data-bz-visit={true} data-bz-method={"DELETE"}>Delete</a></td>
21
25
  </tr>
22
26
  )
23
27
  })
24
28
 
25
29
  return (
26
30
  <div>
27
- <p id="notice">{this.props.flash && this.props.flash.notice}</p>
31
+ <p id="notice">{flash.notice}</p>
28
32
 
29
33
  <h1><%= plural_table_name.capitalize %></h1>
30
34
 
@@ -43,7 +47,7 @@ class <%= plural_table_name.camelize %>Index extends BaseScreen {
43
47
  </tbody>
44
48
  </table>
45
49
  <br />
46
- <a onClick={ e => this.visit(this.props.new_post_path)}>New <%= singular_table_name.capitalize %></a>
50
+ <a href={new<%= singular_table_name.camelize %>Path} data-bz-visit={true}>New <%= singular_table_name.capitalize %></a>
47
51
  </div>
48
52
  )
49
53
  }
@@ -0,0 +1,11 @@
1
+ <%% initial_state = controller.render_to_string(@virtual_path ,formats: [:json], locals: local_assigns, layout: true) %>
2
+
3
+ <%% content_for :initial_state do %>
4
+ <script type="text/javascript">
5
+ window.BREEZY_INITIAL_PAGE_STATE=<%%= initial_state.html_safe %>;
6
+ </script>
7
+ <%% end %>
8
+
9
+
10
+
11
+
@@ -2,35 +2,30 @@ import React from 'react'
2
2
  import {mapStateToProps, mapDispatchToProps} from '@jho406/breezy'
3
3
  import {connect} from 'react-redux'
4
4
  import BaseScreen from 'components/BaseScreen'
5
- import <%= plural_table_name.camelize %>Form from 'components/<%= plural_table_name.camelize %>Form'
5
+ import RailsTag from '@jho406/breezy/dist/RailsTag'
6
+ import * as applicationActionCreators from 'javascript/packs/action_creators'
6
7
 
7
8
  class <%= plural_table_name.camelize %>New extends BaseScreen {
8
- formRef = React.createRef()
9
-
10
- handleSubmit = (values, {setSubmitting}) => {
11
- this.props.delInPage({pageKey: this.props.pageKey, keypath: 'errors'})
12
-
13
- const options = {
14
- method:'POST',
15
- body: JSON.stringify(values),
16
- }
9
+ render () {
10
+ const {
11
+ form,
12
+ flash,
13
+ <%= plural_table_name.camelize(:lower) %>Path,
14
+ } = this.props
15
+ const error = flash.form_error
17
16
 
18
- this.visit(this.props.<%= plural_table_name %>_path, options).then( rsp => {
19
- setSubmitting(false)
20
- if (this.props.errors) {
21
- this.formRef.current.setErrors(this.props.errors)
22
- }
23
- })
24
- }
17
+ const messagesEl = error && (
18
+ <div id="error_explanation">
19
+ <h2>{ error.explanation }</h2>
20
+ <ul>{ error.messages.map(({body})=> <li key={body}>{body}</li>) }</ul>
21
+ </div>
22
+ )
25
23
 
26
- render () {
27
24
  return (
28
25
  <div>
29
- <<%= plural_table_name.camelize %>Form
30
- onSubmit={this.handleSubmit}
31
- ref={this.formRef}
32
- />
33
- <a onClick={ e => this.visit(this.props.<%= plural_table_name %>_path)}>Back</a>
26
+ {messagesEl}
27
+ <RailsTag {...this.props.form} data-bz-visit={true}/>
28
+ <a href={<%= plural_table_name.camelize(:lower) %>Path} data-bz-visit={true}>Back</a>
34
29
  </div>
35
30
  )
36
31
  }
@@ -38,6 +33,6 @@ class <%= plural_table_name.camelize %>New extends BaseScreen {
38
33
 
39
34
  export default connect(
40
35
  mapStateToProps,
41
- mapDispatchToProps
36
+ {...mapDispatchToProps, ...applicationActionCreators}
42
37
  )(<%= plural_table_name.camelize %>New)
43
38
 
@@ -0,0 +1,12 @@
1
+ <%% initial_state = controller.render_to_string(@virtual_path ,formats: [:json], locals: local_assigns, layout: true) %>
2
+
3
+ <%% content_for :initial_state do %>
4
+ <script type="text/javascript">
5
+ window.BREEZY_INITIAL_PAGE_STATE=<%%= initial_state.html_safe %>;
6
+ </script>
7
+ <%% end %>
8
+
9
+
10
+
11
+
12
+
@@ -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 href={ this.props.edit<%= singular_table_name.camelize %>Path } data-bz-visit={true}>Edit</a>
18
+ <a href={ this.props.<%= plural_table_name.camelize(:lower) %>Path } data-bz-visit={true}>Back</a>
19
19
  </div>
20
20
  )
21
21
  }
@@ -0,0 +1,14 @@
1
+ // Example:
2
+ //
3
+ // import {
4
+ // CLEAR_FORM_ERRORS
5
+ // } from './actions'
6
+ //
7
+ // export function clearFormErrors(pageKey) {
8
+ // return {
9
+ // type: CLEAR_FORM_ERRORS,
10
+ // payload: {
11
+ // pageKey,
12
+ // }
13
+ // }
14
+ // }