superglue 0.54.0 → 1.0.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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +32 -0
  3. data/lib/generators/superglue/install/install_generator.rb +119 -0
  4. data/lib/{install/templates/web → generators/superglue/install/templates}/application.json.props +2 -2
  5. data/lib/generators/superglue/install/templates/js/application.jsx +35 -0
  6. data/lib/generators/superglue/install/templates/js/application_visit.js +113 -0
  7. data/lib/generators/superglue/install/templates/js/components.js +2 -0
  8. data/lib/generators/superglue/install/templates/js/flash.js +44 -0
  9. data/lib/generators/superglue/install/templates/js/inputs.jsx +370 -0
  10. data/lib/generators/superglue/install/templates/js/jsconfig.json +9 -0
  11. data/lib/generators/superglue/install/templates/js/layout.jsx +16 -0
  12. data/lib/generators/superglue/install/templates/js/page_to_page_mapping.js +35 -0
  13. data/lib/generators/superglue/install/templates/js/store.js +30 -0
  14. data/lib/{install/templates/web/application.js → generators/superglue/install/templates/ts/application.tsx} +10 -16
  15. data/lib/generators/superglue/install/templates/ts/application_visit.ts +122 -0
  16. data/lib/generators/superglue/install/templates/ts/components.ts +2 -0
  17. data/lib/generators/superglue/install/templates/ts/flash.ts +46 -0
  18. data/lib/generators/superglue/install/templates/ts/inputs.tsx +554 -0
  19. data/lib/generators/superglue/install/templates/ts/layout.tsx +16 -0
  20. data/lib/generators/superglue/install/templates/ts/page_to_page_mapping.ts +34 -0
  21. data/lib/generators/superglue/install/templates/ts/store.ts +34 -0
  22. data/lib/generators/superglue/install/templates/ts/tsconfig.json +27 -0
  23. data/lib/generators/superglue/scaffold/scaffold_generator.rb +16 -0
  24. data/lib/generators/superglue/scaffold_controller/scaffold_controller_generator.rb +61 -0
  25. data/lib/generators/superglue/view_collection/templates/js/edit.jsx +40 -0
  26. data/lib/generators/superglue/view_collection/templates/js/index.jsx +62 -0
  27. data/lib/generators/superglue/view_collection/templates/js/new.jsx +38 -0
  28. data/lib/generators/superglue/view_collection/templates/js/show.jsx +26 -0
  29. data/lib/generators/superglue/view_collection/templates/props/edit.json.props +9 -0
  30. data/lib/generators/superglue/view_collection/templates/props/index.json.props +14 -0
  31. data/lib/generators/superglue/view_collection/templates/props/new.json.props +10 -0
  32. data/lib/generators/superglue/view_collection/templates/props/show.json.props +6 -0
  33. data/lib/generators/superglue/view_collection/templates/ts/edit.tsx +54 -0
  34. data/lib/generators/superglue/view_collection/templates/ts/index.tsx +77 -0
  35. data/lib/generators/superglue/view_collection/templates/ts/new.tsx +50 -0
  36. data/lib/generators/superglue/view_collection/templates/ts/show.tsx +37 -0
  37. data/lib/generators/superglue/view_collection/view_collection_generator.rb +180 -0
  38. data/lib/superglue/helpers.rb +1 -1
  39. data/lib/superglue.rb +2 -1
  40. metadata +62 -41
  41. data/lib/generators/rails/scaffold_controller_generator.rb +0 -12
  42. data/lib/generators/rails/superglue_generator.rb +0 -98
  43. data/lib/generators/rails/templates/controller.rb.tt +0 -68
  44. data/lib/generators/rails/templates/edit.json.props +0 -12
  45. data/lib/generators/rails/templates/index.json.props +0 -14
  46. data/lib/generators/rails/templates/new.json.props +0 -13
  47. data/lib/generators/rails/templates/show.json.props +0 -6
  48. data/lib/generators/rails/templates/web/edit.js +0 -35
  49. data/lib/generators/rails/templates/web/index.js +0 -56
  50. data/lib/generators/rails/templates/web/new.js +0 -33
  51. data/lib/generators/rails/templates/web/show.js +0 -28
  52. data/lib/install/templates/web/actions.js +0 -6
  53. data/lib/install/templates/web/application_visit.js +0 -65
  54. data/lib/install/templates/web/flash.js +0 -19
  55. data/lib/install/templates/web/page_to_page_mapping.js +0 -12
  56. data/lib/install/templates/web/pages.js +0 -15
  57. data/lib/install/templates/web/store.js +0 -32
  58. data/lib/install/web.rb +0 -55
  59. data/lib/tasks/install.rake +0 -9
  60. /data/lib/{install/templates/web → generators/superglue/install/templates}/initializer.rb +0 -0
  61. /data/lib/generators/{rails/templates/web → superglue/view_collection/templates/erb}/edit.html.erb +0 -0
  62. /data/lib/generators/{rails/templates/web → superglue/view_collection/templates/erb}/index.html.erb +0 -0
  63. /data/lib/generators/{rails/templates/web → superglue/view_collection/templates/erb}/new.html.erb +0 -0
  64. /data/lib/generators/{rails/templates/web → superglue/view_collection/templates/erb}/show.html.erb +0 -0
  65. /data/lib/generators/{rails/templates → superglue/view_collection/templates/props}/_form.json.props +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0a7defe951c632a4f1f2493ad92f3ca691124986e4d6c94d718791489e1cf1ad
4
- data.tar.gz: 2be2e0b8422d9f9c8c2c6f0a7e2fb2ec3cf77cd1facb1e50f0a36034236274fe
3
+ metadata.gz: 8e9624774c0133d0a9d8aac0d8b5d47bbb95862eea0bb1a26ffe3ce373c5e922
4
+ data.tar.gz: 8c69fd808df13768c9036981ca27d2a0b24eb9ce8ab8d890c88b666cc9bd5798
5
5
  SHA512:
6
- metadata.gz: 35131fe314207a550d8921b1f93b37fcac0ada8534940ace2711d2465f741c6151d05f7fd190f72594d36877f265d3a72ba0540cc71d5757075959c5240ff374
7
- data.tar.gz: c207f98aae2d03e1ce5f44fe46194c363762fde5e7113eea1907cc05727d94c5236a6e51633489f7d4b98665a3674d76a9bc594cb30e3e7eb12b4c1cef738c70
6
+ metadata.gz: 17522e020054291483b60953d3fa31e60d6b95de4316ce7469ed71e7f397fa15b07533051b4a4266d5263313a947e7b3eb82621d1d0f8dd45088b9db77295cdf
7
+ data.tar.gz: 97e27d5f9330ac515cd1636af3c9974584476a324d142573176187dd3cf18a7e6db696cec11ba473f8b5f7fc3d8849fa9fbc49d14f359ef9373d5ec75b763d56
data/README.md ADDED
@@ -0,0 +1,32 @@
1
+ <div align="center" style="padding: 30px 0px 20px 0px;">
2
+ <img src="https://thoughtbot.github.io/superglue/images/superglue.svg" data-origin="images/superglue.svg" alt="Logo" width=250>
3
+ </div>
4
+
5
+ # Superglue Rails
6
+ Use classic Rails to build rich React Redux applications with **NO APIs** and
7
+ **NO client-side routing**.
8
+
9
+ This is the officially supported Rails adapter to [Superglue]. This gem will
10
+ add install and scaffold generators to your rails project.
11
+
12
+ To get started, visit the [documentation] and add this to your Gemfile
13
+
14
+ [documentation]: https://thoughtbot.github.io/superglue/
15
+
16
+ ```
17
+ gem 'superglue'
18
+ ```
19
+
20
+ Then run `bundle`
21
+
22
+ [![Test superglue_rails](https://github.com/thoughtbot/superglue_rails/actions/workflows/build_rails.yml/badge.svg)](https://github.com/thoughtbot/superglue_rails/actions/workflows/build_rails.yml)
23
+
24
+ ## Documentation
25
+
26
+ Documentation is hosted on [Github pages](https://thoughtbot.github.io/superglue).
27
+
28
+ ## Contributing
29
+
30
+ Thank you, [contributors]!
31
+
32
+ [contributors]: https://github.com/thoughtbot/superglue_rails/graphs/contributors
@@ -0,0 +1,119 @@
1
+ require "rails/generators/named_base"
2
+ require "rails/generators/resource_helpers"
3
+
4
+ module Superglue
5
+ module Generators
6
+ class InstallGenerator < Rails::Generators::Base
7
+ source_root File.expand_path("../templates", __FILE__)
8
+
9
+ class_option :typescript,
10
+ type: :boolean,
11
+ required: false,
12
+ default: false,
13
+ desc: "Use typescript"
14
+
15
+ def create_files
16
+ remove_file "#{app_js_path}/application.js"
17
+
18
+ use_typescript = options["typescript"]
19
+ if use_typescript
20
+ copy_ts_files
21
+ else
22
+ copy_js_files
23
+ end
24
+
25
+ say "Copying Superglue initializer"
26
+ copy_file "#{__dir__}/templates/initializer.rb", "config/initializers/superglue.rb"
27
+
28
+ say "Copying application.json.props"
29
+ copy_file "#{__dir__}/templates/application.json.props", "app/views/layouts/application.json.props"
30
+
31
+ say "Adding required member methods to ApplicationRecord"
32
+ add_member_methods
33
+
34
+ say "Installing Superglue and friends"
35
+ run "yarn add react react-dom @reduxjs/toolkit react-redux @thoughtbot/superglue"
36
+
37
+ if use_typescript
38
+ run "yarn add -D @types/react-dom @types/react @types/node @thoughtbot/candy_wrapper"
39
+ end
40
+
41
+ say "Superglue is Installed! 🎉", :green
42
+ end
43
+
44
+ private
45
+
46
+ def copy_ts_files
47
+ say "Copying application.tsx file to #{app_js_path}"
48
+ copy_file "#{__dir__}/templates/ts/application.tsx", "#{app_js_path}/application.tsx"
49
+
50
+ say "Copying page_to_page_mapping.ts file to #{app_js_path}"
51
+ copy_file "#{__dir__}/templates/ts/page_to_page_mapping.ts", "#{app_js_path}/page_to_page_mapping.ts"
52
+
53
+ say "Copying flash.ts file to #{app_js_path}"
54
+ copy_file "#{__dir__}/templates/ts/flash.ts", "#{app_js_path}/slices/flash.ts"
55
+
56
+ say "Copying store.ts file to #{app_js_path}"
57
+ copy_file "#{__dir__}/templates/ts/store.ts", "#{app_js_path}/store.ts"
58
+
59
+ say "Copying application_visit.ts file to #{app_js_path}"
60
+ copy_file "#{__dir__}/templates/ts/application_visit.ts", "#{app_js_path}/application_visit.ts"
61
+
62
+ say "Copying components to #{app_js_path}"
63
+ copy_file "#{__dir__}/templates/ts/inputs.tsx", "#{app_js_path}/components/Inputs.tsx"
64
+ copy_file "#{__dir__}/templates/ts/layout.tsx", "#{app_js_path}/components/Layout.tsx"
65
+ copy_file "#{__dir__}/templates/ts/components.ts", "#{app_js_path}/components/index.ts"
66
+
67
+ say "Copying tsconfig.json file to #{app_js_path}"
68
+ copy_file "#{__dir__}/templates/ts/tsconfig.json", "tsconfig.json"
69
+ end
70
+
71
+ def copy_js_files
72
+ say "Copying application.js file to #{app_js_path}"
73
+ copy_file "#{__dir__}/templates/js/application.jsx", "#{app_js_path}/application.jsx"
74
+
75
+ say "Copying page_to_page_mapping.js file to #{app_js_path}"
76
+ copy_file "#{__dir__}/templates/js/page_to_page_mapping.js", "#{app_js_path}/page_to_page_mapping.js"
77
+
78
+ say "Copying flash.js file to #{app_js_path}"
79
+ copy_file "#{__dir__}/templates/js/flash.js", "#{app_js_path}/slices/flash.js"
80
+
81
+ say "Copying store.js file to #{app_js_path}"
82
+ copy_file "#{__dir__}/templates/js/store.js", "#{app_js_path}/store.js"
83
+
84
+ say "Copying application_visit.js file to #{app_js_path}"
85
+ copy_file "#{__dir__}/templates/js/application_visit.js", "#{app_js_path}/application_visit.js"
86
+
87
+ say "Copying components to #{app_js_path}"
88
+ copy_file "#{__dir__}/templates/js/inputs.jsx", "#{app_js_path}/components/Inputs.jsx"
89
+ copy_file "#{__dir__}/templates/js/layout.jsx", "#{app_js_path}/components/Layout.jsx"
90
+ copy_file "#{__dir__}/templates/js/components.js", "#{app_js_path}/components/index.js"
91
+
92
+ say "Copying jsconfig.json file to #{app_js_path}"
93
+ copy_file "#{__dir__}/templates/js/jsconfig.json", "jsconfig.json"
94
+ end
95
+
96
+ def add_member_methods
97
+ inject_into_file "app/models/application_record.rb", after: "class ApplicationRecord < ActiveRecord::Base\n" do
98
+ <<-RUBY
99
+ # This enables digging by index when used with props_template
100
+ # see https://thoughtbot.github.io/superglue/digging/#index-based-selection
101
+ def self.member_at(index)
102
+ offset(index).limit(1).first
103
+ end
104
+
105
+ # This enables digging by attribute when used with props_template
106
+ # see https://thoughtbot.github.io/superglue/digging/#attribute-based-selection
107
+ def self.member_by(attr, value)
108
+ find_by(Hash[attr, value])
109
+ end
110
+ RUBY
111
+ end
112
+ end
113
+
114
+ def app_js_path
115
+ "app/javascript/"
116
+ end
117
+ end
118
+ end
119
+ end
@@ -1,6 +1,6 @@
1
- path = request.format.json? ? param_to_search_path(params[:props_at]) : nil
1
+ path = request.format.json? ? param_to_dig_path(params[:props_at]) : nil
2
2
 
3
- json.data(search: path) do
3
+ json.data(dig: path) do
4
4
  yield json
5
5
  end
6
6
 
@@ -0,0 +1,35 @@
1
+ import React from "react"
2
+ import { createRoot } from "react-dom/client"
3
+ import { Application } from "@thoughtbot/superglue"
4
+ import { buildVisitAndRemote } from "./application_visit"
5
+ import { pageIdentifierToPageComponent } from "./page_to_page_mapping"
6
+ import { store } from "./store"
7
+
8
+ if (typeof window !== "undefined") {
9
+ document.addEventListener("DOMContentLoaded", function() {
10
+ const appEl = document.getElementById("app")
11
+ const location = window.location
12
+
13
+ if (appEl) {
14
+ const root = createRoot(appEl)
15
+ root.render(
16
+ <Application
17
+ // The base url prefixed to all calls made by the `visit`
18
+ // and `remote` thunks.
19
+ baseUrl={location.origin}
20
+ // The global var SUPERGLUE_INITIAL_PAGE_STATE is set by your erb
21
+ // template, e.g., index.html.erb
22
+ initialPage={window.SUPERGLUE_INITIAL_PAGE_STATE}
23
+ // The initial path of the page, e.g., /foobar
24
+ path={location.pathname + location.search + location.hash}
25
+ // Callback used to setup visit and remote
26
+ buildVisitAndRemote={buildVisitAndRemote}
27
+ // Callback used to setup the store
28
+ store={store}
29
+ // Mapping between the page identifier to page component
30
+ mapping={pageIdentifierToPageComponent}
31
+ />
32
+ )
33
+ }
34
+ })
35
+ }
@@ -0,0 +1,113 @@
1
+ import { visit, remote } from "@thoughtbot/superglue/action_creators"
2
+
3
+ /**
4
+ * This function returns a wrapped visit and remote that will be used by UJS,
5
+ * the Navigation component, and passed to your page components through the
6
+ * NavigationContext.
7
+ *
8
+ * You can customize both functions to your liking. For example, for a progress
9
+ * bar. This file also adds support for data-sg-remote.
10
+ */
11
+ export const buildVisitAndRemote = (ref, store) => {
12
+ const appRemote = (path, { dataset, ...options }) => {
13
+ /**
14
+ * You can make use of `dataset` to add custom UJS options.
15
+ * If you are implementing a progress bar, you can selectively
16
+ * hide it for some links. For example:
17
+ *
18
+ * ```
19
+ * <a href="/posts?props_at=data.header" data-sg-remote data-sg-hide-progress>
20
+ * Click me
21
+ * </a>
22
+ * ```
23
+ *
24
+ * This would be available as `sgHideProgress` on the dataset
25
+ */
26
+ return store.dispatch(remote(path, options))
27
+ }
28
+
29
+ const appVisit = (path, { dataset, ...options } = {}) => {
30
+ /**
31
+ * Do something before we make a request.
32
+ * e.g, show a [progress bar](https://thoughtbot.github.io/superglue/recipes/progress-bar/).
33
+ *
34
+ * Hint: you can access the current pageKey
35
+ * via `store.getState().superglue.currentPageKey`
36
+ */
37
+ return store
38
+ .dispatch(visit(path, options))
39
+ .then(meta => {
40
+ /**
41
+ * The assets fingerprints changed, instead of transitioning
42
+ * just go to the URL directly to retrieve new assets
43
+ */
44
+ if (meta.needsRefresh) {
45
+ window.location.href = meta.pageKey
46
+ return meta
47
+ }
48
+
49
+ /**
50
+ * Your first expanded UJS option, `data-sg-replace`
51
+ *
52
+ * This option overrides the `navigationAction` to allow a link click or
53
+ * a form submission to replace history instead of the usual push.
54
+ */
55
+ const navigatonAction = !!dataset?.sgReplace
56
+ ? "replace"
57
+ : meta.navigationAction
58
+ ref.current?.navigateTo(meta.pageKey, {
59
+ action: navigatonAction
60
+ })
61
+
62
+ /**
63
+ * Return the meta object, it's used for scroll restoration when
64
+ * handling the back button. You can skip returning, but Superglue
65
+ * will warn you about scroll restoration.
66
+ */
67
+ return meta
68
+ })
69
+ .finally(() => {
70
+ /**
71
+ * Do something after a request.
72
+ *
73
+ * This is where you hide a progress bar.
74
+ */
75
+ })
76
+ .catch(err => {
77
+ const response = err.response
78
+
79
+ if (!response) {
80
+ /**
81
+ * This is for errors that are NOT from a HTTP request.
82
+ *
83
+ * Tooling like Sentry can capture console errors. If not, feel
84
+ * free to customize to send the error to your telemetry tool of choice.
85
+ */
86
+ console.error(err)
87
+ return
88
+ }
89
+
90
+ if (response.ok) {
91
+ /**
92
+ * This is for errors that are from a HTTP request.
93
+ *
94
+ * If the response is OK, it must be an HTML body, we'll
95
+ * go to that locaton directly.
96
+ */
97
+ window.location = response.url
98
+ } else {
99
+ if (response.status >= 400 && response.status < 500) {
100
+ window.location.href = "/400.html"
101
+ return
102
+ }
103
+
104
+ if (response.status >= 500) {
105
+ window.location.href = "/500.html"
106
+ return
107
+ }
108
+ }
109
+ })
110
+ }
111
+
112
+ return { visit: appVisit, remote: appRemote }
113
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./Layout"
2
+ export * from "./Inputs"
@@ -0,0 +1,44 @@
1
+ import { createSlice } from "@reduxjs/toolkit"
2
+ import { saveResponse, beforeVisit } from "@thoughtbot/superglue"
3
+
4
+ const initialState = {}
5
+
6
+ export const flashSlice = createSlice({
7
+ name: "flash",
8
+ initialState: initialState,
9
+ reducers: {
10
+ clearFlash(state, { payload }) {
11
+ const key = payload
12
+ if (!key) {
13
+ return {}
14
+ }
15
+
16
+ delete state[key]
17
+
18
+ return {
19
+ ...state
20
+ }
21
+ },
22
+ flash(state, { payload }) {
23
+ return {
24
+ ...state,
25
+ ...payload
26
+ }
27
+ }
28
+ },
29
+ extraReducers: builder => {
30
+ builder.addCase(beforeVisit, (_state, _action) => {
31
+ return {}
32
+ })
33
+ builder.addCase(saveResponse, (state, action) => {
34
+ const { page } = action.payload
35
+
36
+ return {
37
+ ...state,
38
+ ...page.slices.flash
39
+ }
40
+ })
41
+ }
42
+ })
43
+
44
+ export const { clearFlash, flash } = flashSlice.actions