breezy 0.13.0 → 0.17.1

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 (33) hide show
  1. checksums.yaml +4 -4
  2. data/lib/breezy.rb +3 -3
  3. data/lib/breezy/helpers.rb +523 -0
  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 +12 -5
  7. data/lib/generators/rails/templates/_form.json.props +13 -0
  8. data/lib/generators/rails/templates/controller.rb.tt +0 -28
  9. data/lib/generators/rails/templates/edit.json.props +7 -12
  10. data/lib/generators/rails/templates/index.json.props +1 -2
  11. data/lib/generators/rails/templates/new.json.props +12 -3
  12. data/lib/generators/rails/templates/show.json.props +0 -2
  13. data/lib/generators/rails/templates/web/edit.html.erb +7 -0
  14. data/lib/generators/rails/templates/web/edit.jsx +21 -28
  15. data/lib/generators/rails/templates/web/index.html.erb +7 -0
  16. data/lib/generators/rails/templates/web/index.jsx +10 -7
  17. data/lib/generators/rails/templates/web/new.html.erb +7 -0
  18. data/lib/generators/rails/templates/web/new.jsx +18 -25
  19. data/lib/generators/rails/templates/web/show.html.erb +7 -0
  20. data/lib/generators/rails/templates/web/show.jsx +3 -4
  21. data/lib/install/templates/web/action_creators.js +14 -12
  22. data/lib/install/templates/web/actions.js +4 -1
  23. data/lib/install/templates/web/application.js +173 -47
  24. data/lib/install/templates/web/application.json.props +5 -2
  25. data/lib/install/templates/web/application_visit.js +65 -0
  26. data/lib/install/templates/web/initializer.rb +1 -0
  27. data/lib/install/templates/web/reducer.js +62 -9
  28. data/lib/install/web.rb +10 -28
  29. metadata +16 -13
  30. data/app/views/breezy/response.html.erb +0 -0
  31. data/lib/generators/rails/templates/web/base.jsx +0 -11
  32. data/lib/generators/rails/templates/web/form.jsx +0 -31
  33. data/test/breezy_test.rb +0 -121
@@ -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,9 +29,11 @@ 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)
33
- template 'web/base.jsx', File.join('app/components', 'BaseScreen.jsx')
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
34
37
 
35
38
  %w(index show new edit).each do |view|
36
39
  append_mapping(view)
@@ -48,8 +51,8 @@ module Rails
48
51
  "\nimport #{component_name} from 'views/#{controller_file_path}/#{action}'"
49
52
  end
50
53
 
51
- inject_into_file app_js, after: 'const identifierToComponentMapping = {' do
52
- "\n '#{[controller_file_path, action].join('/')}': #{component_name},"
54
+ inject_into_file app_js, after: 'identifierToComponentMapping = {' do
55
+ "\n '#{[controller_file_path, action].join('/')}': #{component_name},"
53
56
  end
54
57
  end
55
58
 
@@ -69,6 +72,10 @@ module Rails
69
72
  [name, :jsx] * '.'
70
73
  end
71
74
 
75
+ def filename_with_html_extensions(name)
76
+ [name, :html, :erb] * '.'
77
+ end
78
+
72
79
  def attributes_list_with_timestamps
73
80
  attributes_list(attributes_names + %w(created_at updated_at))
74
81
  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
@@ -9,47 +9,19 @@ class <%= controller_class_name %>Controller < ApplicationController
9
9
  # GET <%= route_url %>
10
10
  def index
11
11
  @<%= plural_table_name %> = <%= orm_class.all(class_name) %>
12
- respond_to do |format|
13
- format.html {
14
- @initial_state = render_to_string(formats: [:json], layout: true)
15
- render inline: '', layout: true
16
- }
17
- format.json { render layout: true }
18
- end
19
12
  end
20
13
 
21
14
  # GET <%= route_url %>/1
22
15
  def show
23
- respond_to do |format|
24
- format.html {
25
- @initial_state = render_to_string(formats: [:json], layout: true)
26
- render inline: '', layout: true
27
- }
28
- format.json { render layout: true }
29
- end
30
16
  end
31
17
 
32
18
  # GET <%= route_url %>/new
33
19
  def new
34
20
  @<%= singular_table_name %> = <%= orm_class.build(class_name) %>
35
- respond_to do |format|
36
- format.html {
37
- @initial_state = render_to_string(formats: [:json], layout: true)
38
- render inline: '', layout: true
39
- }
40
- format.json { render layout: true }
41
- end
42
21
  end
43
22
 
44
23
  # GET <%= route_url %>/1/edit
45
24
  def edit
46
- respond_to do |format|
47
- format.html {
48
- @initial_state = render_to_string(formats: [:json], layout: true)
49
- render inline: '', layout: true
50
- }
51
- format.json { render layout: true }
52
- end
53
25
  end
54
26
 
55
27
  # POST <%= route_url %>
@@ -1,18 +1,13 @@
1
- json.flash flash.to_h
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
+ }
2
6
 
3
- if @<%= singular_table_name %>.errors
4
- json.errors @<%= singular_table_name %>.errors.to_h
7
+ flash.now[:form_error] = content
5
8
  end
6
9
 
7
- <%- attributes_list_with_timestamps.each do |attr| -%>
8
- json.<%=attr%> @<%= singular_table_name %>.<%=attr%>
9
- <%- end -%>
10
-
11
-
12
- json.attributes_for_form do
13
- <%- attributes_list.select{|attr| attr != :id }.each do |attr| -%>
14
- json.<%=attr%> @<%= singular_table_name %>.<%=attr%>
15
- <%- end -%>
10
+ json.form(partial: 'form') do
16
11
  end
17
12
 
18
13
  json.<%= singular_table_name%>_path <%= singular_table_name%>_path(@<%=singular_table_name%>)
@@ -1,5 +1,3 @@
1
- json.flash flash.to_h
2
-
3
1
  json.<%= plural_table_name %> do
4
2
  json.array! @<%= plural_table_name %> do |<%= singular_table_name %>|
5
3
  <%- attributes_list_with_timestamps.each do |attr| -%>
@@ -7,6 +5,7 @@ json.<%= plural_table_name %> do
7
5
  <%- end -%>
8
6
  json.edit_<%=singular_table_name%>_path edit_<%=singular_table_name%>_path(<%=singular_table_name%>)
9
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%>)
10
9
  end
11
10
  end
12
11
 
@@ -1,6 +1,15 @@
1
- json.flash flash.to_h
2
- if @<%= singular_table_name %>.errors
3
- json.errors @<%= singular_table_name %>.errors.to_h
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
4
11
  end
5
12
 
6
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 -%>
@@ -0,0 +1,7 @@
1
+ <%% initial_state = controller.render_to_string(@virtual_path ,formats: [:json], locals: local_assigns, layout: true) %>
2
+
3
+ <script type="text/javascript">
4
+ window.BREEZY_INITIAL_PAGE_STATE=<%%= initial_state.html_safe %>;
5
+ </script>
6
+
7
+ <div id="app"></div>
@@ -1,39 +1,32 @@
1
1
  import React from 'react'
2
2
  import {mapStateToProps, mapDispatchToProps} from '@jho406/breezy'
3
3
  import {connect} from 'react-redux'
4
- import BaseScreen from 'components/BaseScreen'
5
- import <%= plural_table_name.camelize %>Form from 'components/<%= plural_table_name.camelize %>Form'
4
+ import RailsTag from '@jho406/breezy/components/RailsTag'
6
5
  import * as applicationActionCreators from 'javascript/packs/action_creators'
7
6
 
8
- class <%= plural_table_name.camelize %>Edit extends BaseScreen {
9
- formRef = React.createRef()
10
-
11
- handleSubmit = (values, {setSubmitting}) => {
12
- this.props.clearFormErrors(this.props.pageKey)
13
-
14
- const options = {
15
- method:'PUT',
16
- body: JSON.stringify(values),
17
- }
18
-
19
- this.enhancedVisit(this.props.<%= singular_table_name.camelize(:lower) %>Path, options).then( rsp => {
20
- setSubmitting(false)
21
- if (this.props.errors) {
22
- this.formRef.current.setErrors(this.props.errors)
23
- }
24
- })
25
- }
26
-
7
+ class <%= plural_table_name.camelize %>Edit extends React.Component {
27
8
  render () {
9
+ const {
10
+ form,
11
+ flash,
12
+ <%= singular_table_name.camelize(:lower) %>Path,
13
+ <%= plural_table_name.camelize(:lower) %>Path,
14
+ } = this.props
15
+ const error = flash.form_error
16
+
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
+ )
23
+
28
24
  return (
29
25
  <div>
30
- <<%= plural_table_name.camelize %>Form
31
- onSubmit={this.handleSubmit}
32
- initialValues={this.props.attributesForForm}
33
- ref={this.formRef}
34
- />
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>
26
+ {messagesEl}
27
+ <RailsTag {...form} data-bz-visit={true}/>
28
+ <a href={<%= singular_table_name.camelize(:lower) %>Path} data-bz-visit={true}>Show</a>
29
+ <a href={<%= plural_table_name.camelize(:lower) %>Path} data-bz-visit={true}>Back</a>
37
30
  </div>
38
31
  )
39
32
  }
@@ -0,0 +1,7 @@
1
+ <%% initial_state = controller.render_to_string(@virtual_path ,formats: [:json], locals: local_assigns, layout: true) %>
2
+
3
+ <script type="text/javascript">
4
+ window.BREEZY_INITIAL_PAGE_STATE=<%%= initial_state.html_safe %>;
5
+ </script>
6
+
7
+ <div id="app"></div>
@@ -1,30 +1,33 @@
1
1
  import React from 'react'
2
2
  import {mapStateToProps, mapDispatchToProps} from '@jho406/breezy'
3
3
  import { connect } from 'react-redux'
4
- import BaseScreen from 'components/BaseScreen'
5
4
 
6
- class <%= plural_table_name.camelize %>Index extends BaseScreen {
5
+ class <%= plural_table_name.camelize %>Index extends React.Component {
7
6
  static defaultProps = {
8
7
  <%= plural_table_name.camelize(:lower) %>: []
9
8
  }
10
9
 
11
10
  render () {
11
+ const {
12
+ flash,
13
+ new<%= singular_table_name.camelize %>Path,
14
+ } = this.props
12
15
  const <%= singular_table_name.camelize(:lower) %>Items = this.props.<%= plural_table_name.camelize(:lower) %>.map((<%= singular_table_name.camelize(:lower) %>, key) => {
13
16
  return (
14
17
  <tr key={<%= singular_table_name.camelize(:lower) %>.id}>
15
18
  <%- attributes_list.select{|attr| attr != :id }.each do |attr| -%>
16
19
  <td>{<%=singular_table_name.camelize(:lower)%>.<%=attr.camelize(:lower)%>}</td>
17
20
  <%- end -%>
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
+ <td><a href={ <%=singular_table_name%>.<%=singular_table_name.camelize(:lower)%>Path } data-bz-visit={true}>Show</a></td>
22
+ <td><a href={ <%=singular_table_name%>.edit<%=singular_table_name.camelize%>Path } data-bz-visit={true}>Edit</a></td>
23
+ <td><a href={ <%=singular_table_name%>.delete<%=singular_table_name.camelize%>Path }data-bz-visit={true} data-bz-method={"DELETE"}>Delete</a></td>
21
24
  </tr>
22
25
  )
23
26
  })
24
27
 
25
28
  return (
26
29
  <div>
27
- <p id="notice">{this.props.flash && this.props.flash.notice}</p>
30
+ <p id="notice">{flash.notice}</p>
28
31
 
29
32
  <h1><%= plural_table_name.capitalize %></h1>
30
33
 
@@ -43,7 +46,7 @@ class <%= plural_table_name.camelize %>Index extends BaseScreen {
43
46
  </tbody>
44
47
  </table>
45
48
  <br />
46
- <a onClick={ e => this.enhancedVisit(this.props.new<%= singular_table_name.camelize %>Path)}>New <%= singular_table_name.capitalize %></a>
49
+ <a href={new<%= singular_table_name.camelize %>Path} data-bz-visit={true}>New <%= singular_table_name.capitalize %></a>
47
50
  </div>
48
51
  )
49
52
  }
@@ -0,0 +1,7 @@
1
+ <%% initial_state = controller.render_to_string(@virtual_path ,formats: [:json], locals: local_assigns, layout: true) %>
2
+
3
+ <script type="text/javascript">
4
+ window.BREEZY_INITIAL_PAGE_STATE=<%%= initial_state.html_safe %>;
5
+ </script>
6
+
7
+ <div id="app"></div>
@@ -1,37 +1,30 @@
1
1
  import React from 'react'
2
2
  import {mapStateToProps, mapDispatchToProps} from '@jho406/breezy'
3
3
  import {connect} from 'react-redux'
4
- import BaseScreen from 'components/BaseScreen'
5
- import <%= plural_table_name.camelize %>Form from 'components/<%= plural_table_name.camelize %>Form'
4
+ import RailsTag from '@jho406/breezy/components/RailsTag'
6
5
  import * as applicationActionCreators from 'javascript/packs/action_creators'
7
6
 
8
- class <%= plural_table_name.camelize %>New extends BaseScreen {
9
- formRef = React.createRef()
10
-
11
- handleSubmit = (values, {setSubmitting}) => {
12
- this.props.clearFormErrors(this.props.pageKey)
13
-
14
- const options = {
15
- method:'POST',
16
- body: JSON.stringify(values),
17
- }
7
+ class <%= plural_table_name.camelize %>New extends React.Component {
8
+ render () {
9
+ const {
10
+ form,
11
+ flash,
12
+ <%= plural_table_name.camelize(:lower) %>Path,
13
+ } = this.props
14
+ const error = flash.form_error
18
15
 
19
- this.enhancedVisit(this.props.<%= plural_table_name.camelize(:lower) %>Path, options).then( rsp => {
20
- setSubmitting(false)
21
- if (this.props.errors) {
22
- this.formRef.current.setErrors(this.props.errors)
23
- }
24
- })
25
- }
16
+ const messagesEl = error && (
17
+ <div id="error_explanation">
18
+ <h2>{ error.explanation }</h2>
19
+ <ul>{ error.messages.map(({body})=> <li key={body}>{body}</li>) }</ul>
20
+ </div>
21
+ )
26
22
 
27
- render () {
28
23
  return (
29
24
  <div>
30
- <<%= plural_table_name.camelize %>Form
31
- onSubmit={this.handleSubmit}
32
- ref={this.formRef}
33
- />
34
- <a onClick={ e => this.enhancedVisit(this.props.<%= plural_table_name.camelize(:lower) %>Path)}>Back</a>
25
+ {messagesEl}
26
+ <RailsTag {...this.props.form} data-bz-visit={true}/>
27
+ <a href={<%= plural_table_name.camelize(:lower) %>Path} data-bz-visit={true}>Back</a>
35
28
  </div>
36
29
  )
37
30
  }
@@ -0,0 +1,7 @@
1
+ <%% initial_state = controller.render_to_string(@virtual_path ,formats: [:json], locals: local_assigns, layout: true) %>
2
+
3
+ <script type="text/javascript">
4
+ window.BREEZY_INITIAL_PAGE_STATE=<%%= initial_state.html_safe %>;
5
+ </script>
6
+
7
+ <div id="app"></div>
@@ -1,9 +1,8 @@
1
1
  import React from 'react'
2
2
  import {mapStateToProps, mapDispatchToProps} from '@jho406/breezy'
3
3
  import { connect } from 'react-redux'
4
- import BaseScreen from 'components/BaseScreen'
5
4
 
6
- class <%= plural_table_name.camelize %>Show extends BaseScreen {
5
+ class <%= plural_table_name.camelize %>Show extends React.Component {
7
6
  render () {
8
7
  return (
9
8
  <div>
@@ -14,8 +13,8 @@ class <%= plural_table_name.camelize %>Show extends BaseScreen {
14
13
  {this.props.<%=attr.camelize(:lower)%>}
15
14
  </p>
16
15
  <%- end -%>
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>
16
+ <a href={ this.props.edit<%= singular_table_name.camelize %>Path } data-bz-visit={true}>Edit</a>
17
+ <a href={ this.props.<%= plural_table_name.camelize(:lower) %>Path } data-bz-visit={true}>Back</a>
19
18
  </div>
20
19
  )
21
20
  }