breezy 0.9.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ // }