superglue 0.50.0.beta1 → 0.50.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/generators/rails/templates/edit.json.props +2 -4
- data/lib/generators/rails/templates/new.json.props +2 -4
- data/lib/generators/rails/templates/web/edit.js +2 -5
- data/lib/generators/rails/templates/web/index.js +4 -4
- data/lib/generators/rails/templates/web/new.js +2 -5
- data/lib/generators/rails/templates/web/show.js +3 -3
- data/lib/install/templates/web/actions.js +6 -3
- data/lib/install/templates/web/application.js +9 -30
- data/lib/install/templates/web/application.json.props +4 -1
- data/lib/install/templates/web/flash.js +19 -0
- data/lib/install/templates/web/pages.js +15 -0
- data/lib/install/templates/web/store.js +32 -0
- data/lib/install/web.rb +9 -6
- data/lib/tasks/install.rake +1 -11
- metadata +11 -24
- data/lib/install/templates/web/action_creators.js +0 -14
- data/lib/install/templates/web/reducer.js +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0586b4b5e16fbae55b29d0b9b56fb421fec1f5e0841bea7cb8ed2ee661ad6642'
|
4
|
+
data.tar.gz: 01fe043eadc91fb4efe74b96e4e1ce35d01bcb895514d701b6a924ce8c7ed994
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dab5eef3eff758a64408a2d239e47d0107b60952cb4eb0dfec97a241f39eeeea644ff67741022550d6ca2847a5773098c72379c2b48a2fafb86f0f0ba6d46980
|
7
|
+
data.tar.gz: 10340fee27529540353885d343bd5202a35db8bbd5a403156b53c38e960e1b299dd34d5b8955e831cf0791f0f3ebed35908d3189a828fed3605e51eb4be640c8
|
@@ -1,10 +1,8 @@
|
|
1
1
|
if @post.errors.any?
|
2
|
-
|
2
|
+
json.errors({
|
3
3
|
explanation: "#{pluralize(@<%= singular_table_name %>.errors.count, "error")} prohibited this post from being saved:",
|
4
4
|
messages: @<%= singular_table_name %>.errors.full_messages.map{|msg| {body: msg}}
|
5
|
-
}
|
6
|
-
|
7
|
-
flash.now[:form_error] = content
|
5
|
+
})
|
8
6
|
end
|
9
7
|
|
10
8
|
json.form(partial: 'form') do
|
@@ -1,10 +1,8 @@
|
|
1
1
|
if @post.errors.any?
|
2
|
-
|
2
|
+
json.errors({
|
3
3
|
explanation: "#{pluralize(@<%= singular_table_name %>.errors.count, "error")} prohibited this post from being saved:",
|
4
4
|
messages: @<%= singular_table_name %>.errors.full_messages.map{|msg| {body: msg}}
|
5
|
-
}
|
6
|
-
|
7
|
-
flash.now[:form_error] = content
|
5
|
+
})
|
8
6
|
end
|
9
7
|
|
10
8
|
json.form(partial: 'form') do
|
@@ -1,17 +1,14 @@
|
|
1
1
|
import React from 'react'
|
2
|
-
// import
|
3
|
-
// import {useDispatch} from 'react-redux'
|
2
|
+
// import { useSelector } from 'react-redux'
|
4
3
|
|
5
4
|
export default function <%= plural_table_name.camelize %>Edit ({
|
6
5
|
// visit,
|
7
6
|
// remote,
|
8
7
|
form,
|
9
|
-
|
8
|
+
error,
|
10
9
|
<%= singular_table_name.camelize(:lower) %>Path,
|
11
10
|
<%= plural_table_name.camelize(:lower) %>Path,
|
12
11
|
}) {
|
13
|
-
const error = flash.form_error
|
14
|
-
|
15
12
|
const messagesEl = error && (
|
16
13
|
<div id="error_explanation">
|
17
14
|
<h2>{ error.explanation }</h2>
|
@@ -1,14 +1,14 @@
|
|
1
1
|
import React from 'react'
|
2
|
-
|
3
|
-
// import {useDispatch} from 'react-redux'
|
2
|
+
import { useSelector } from 'react-redux'
|
4
3
|
|
5
4
|
export default function <%= plural_table_name.camelize %>Index({
|
6
5
|
// visit,
|
7
6
|
// remote,
|
8
|
-
flash,
|
9
7
|
new<%= singular_table_name.camelize %>Path,
|
10
8
|
<%= plural_table_name.camelize(:lower) %> = [],
|
11
9
|
}) {
|
10
|
+
const flash = useSelector((state) => state.flash)
|
11
|
+
|
12
12
|
const <%= singular_table_name.camelize(:lower) %>Items = <%= plural_table_name.camelize(:lower) %>.map((<%= singular_table_name.camelize(:lower) %>, key) => {
|
13
13
|
const deleteForm = <%=singular_table_name.camelize(:lower)%>.deleteForm;
|
14
14
|
|
@@ -31,7 +31,7 @@ export default function <%= plural_table_name.camelize %>Index({
|
|
31
31
|
|
32
32
|
return (
|
33
33
|
<div>
|
34
|
-
<p id="notice">{flash.notice}</p>
|
34
|
+
<p id="notice">{flash && flash.notice}</p>
|
35
35
|
|
36
36
|
<h1><%= plural_table_name.capitalize %></h1>
|
37
37
|
|
@@ -1,16 +1,13 @@
|
|
1
1
|
import React from 'react'
|
2
|
-
// import
|
3
|
-
// import { useDispatch } from 'react-redux'
|
2
|
+
// import { useSelector } from 'react-redux'
|
4
3
|
|
5
4
|
export default function <%= plural_table_name.camelize %>New({
|
6
5
|
// visit,
|
7
6
|
// remote
|
8
7
|
form,
|
9
|
-
|
8
|
+
error,
|
10
9
|
<%= plural_table_name.camelize(:lower) %>Path,
|
11
10
|
}) {
|
12
|
-
const error = flash.form_error
|
13
|
-
|
14
11
|
const messagesEl = error && (
|
15
12
|
<div id="error_explanation">
|
16
13
|
<h2>{ error.explanation }</h2>
|
@@ -1,17 +1,17 @@
|
|
1
1
|
import React from 'react'
|
2
|
-
|
3
|
-
// import {useDispatch} from 'react-redux'
|
2
|
+
import { useSelector } from 'react-redux'
|
4
3
|
|
5
4
|
export default function <%= plural_table_name.camelize %>Show({
|
6
5
|
// visit,
|
7
6
|
// remote,
|
8
|
-
flash,
|
9
7
|
<%- attributes_list_with_timestamps.select{|attr| attr != :id }.each do |attr| -%>
|
10
8
|
<%=attr.camelize(:lower)%>,
|
11
9
|
<%- end -%>
|
12
10
|
edit<%= singular_table_name.camelize %>Path,
|
13
11
|
<%= plural_table_name.camelize(:lower) %>Path
|
14
12
|
}) {
|
13
|
+
const flash = useSelector((state) => state.flash)
|
14
|
+
|
15
15
|
return (
|
16
16
|
<div>
|
17
17
|
<p id="notice">{flash && flash.notice}</p>
|
@@ -1,3 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
import { createAction } from '@reduxjs/toolkit'
|
2
|
+
import { SAVE_RESPONSE, BEFORE_VISIT, UPDATE_FRAGMENTS } from '@thoughtbot/superglue'
|
3
|
+
|
4
|
+
export const saveResponse = createAction(SAVE_RESPONSE)
|
5
|
+
export const beforeVisit = createAction(BEFORE_VISIT)
|
6
|
+
export const updateFragments = createAction(UPDATE_FRAGMENTS)
|
@@ -1,13 +1,11 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { combineReducers, createStore, applyMiddleware, compose } from 'redux';
|
3
|
-
import reduceReducers from 'reduce-reducers';
|
4
2
|
import thunk from 'redux-thunk';
|
5
3
|
import { Provider } from 'react-redux';
|
6
|
-
import {
|
7
|
-
import { ApplicationBase
|
8
|
-
import { applicationRootReducer, applicationPagesReducer } from './reducer';
|
4
|
+
import { createRoot } from 'react-dom/client';
|
5
|
+
import { ApplicationBase } from '@thoughtbot/superglue';
|
9
6
|
import { buildVisitAndRemote } from './application_visit';
|
10
7
|
import { pageIdentifierToPageComponent } from './page_to_page_mapping';
|
8
|
+
import { buildStore } from './store'
|
11
9
|
|
12
10
|
class Application extends ApplicationBase {
|
13
11
|
mapping() {
|
@@ -18,27 +16,8 @@ class Application extends ApplicationBase {
|
|
18
16
|
return buildVisitAndRemote(navRef, store);
|
19
17
|
}
|
20
18
|
|
21
|
-
buildStore(initialState, { superglue
|
22
|
-
|
23
|
-
// See `./reducer.js` for an explaination of the two included reducers
|
24
|
-
const composeEnhancers =
|
25
|
-
(this.hasWindow && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) ||
|
26
|
-
compose;
|
27
|
-
const reducer = reduceReducers(
|
28
|
-
combineReducers({
|
29
|
-
superglue: superglueReducer,
|
30
|
-
pages: reduceReducers(pagesReducer, applicationPagesReducer),
|
31
|
-
}),
|
32
|
-
applicationRootReducer
|
33
|
-
);
|
34
|
-
|
35
|
-
const store = createStore(
|
36
|
-
reducer,
|
37
|
-
initialState,
|
38
|
-
composeEnhancers(applyMiddleware(thunk, fragmentMiddleware))
|
39
|
-
);
|
40
|
-
|
41
|
-
return store;
|
19
|
+
buildStore(initialState, { superglue, pages}) {
|
20
|
+
return buildStore(initialState, superglue, pages);
|
42
21
|
}
|
43
22
|
}
|
44
23
|
|
@@ -48,7 +27,8 @@ if (typeof window !== "undefined") {
|
|
48
27
|
const location = window.location;
|
49
28
|
|
50
29
|
if (appEl) {
|
51
|
-
|
30
|
+
const root = createRoot(appEl);
|
31
|
+
root.render(
|
52
32
|
<Application
|
53
33
|
appEl={appEl}
|
54
34
|
// The base url prefixed to all calls made by the `visit`
|
@@ -59,11 +39,10 @@ if (typeof window !== "undefined") {
|
|
59
39
|
initialPage={window.SUPERGLUE_INITIAL_PAGE_STATE}
|
60
40
|
// The initial path of the page, e.g., /foobar
|
61
41
|
path={location.pathname + location.search + location.hash}
|
62
|
-
|
63
|
-
/>,
|
64
|
-
appEl
|
42
|
+
/>
|
65
43
|
);
|
66
44
|
}
|
67
45
|
});
|
68
46
|
}
|
69
47
|
|
48
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import { createSlice } from '@reduxjs/toolkit'
|
2
|
+
import { saveResponse, beforeVisit } from '../actions'
|
3
|
+
|
4
|
+
export const flashSlice = createSlice({
|
5
|
+
name: 'flash',
|
6
|
+
initialState: {},
|
7
|
+
extraReducers: (builder) => {
|
8
|
+
builder.addCase(beforeVisit, (state, action) => {
|
9
|
+
return {}
|
10
|
+
})
|
11
|
+
builder.addCase(saveResponse, (state, action) => {
|
12
|
+
const { page } = action.payload;
|
13
|
+
|
14
|
+
return {
|
15
|
+
...state, ...page.slices.flash
|
16
|
+
}
|
17
|
+
})
|
18
|
+
}
|
19
|
+
})
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import { createSlice } from '@reduxjs/toolkit'
|
2
|
+
import { saveResponse, beforeVisit } from '../actions'
|
3
|
+
|
4
|
+
export const pagesSlice = createSlice({
|
5
|
+
name: 'pages',
|
6
|
+
// extraReducers: (builder) => {
|
7
|
+
// builder.addCase(beforeVisit, (state, action) => {
|
8
|
+
// const {currentPageKey} = action.payload
|
9
|
+
//
|
10
|
+
// const currentPage = draft[currentPageKey]
|
11
|
+
// delete currentPage.error
|
12
|
+
// })
|
13
|
+
// }
|
14
|
+
})
|
15
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import { configureStore } from '@reduxjs/toolkit'
|
2
|
+
import { pagesSlice } from "./slices/pages"
|
3
|
+
import { flashSlice } from "./slices/flash"
|
4
|
+
import {
|
5
|
+
BEFORE_VISIT,
|
6
|
+
BEFORE_FETCH,
|
7
|
+
BEFORE_REMOTE,
|
8
|
+
fragmentMiddleware
|
9
|
+
} from '@thoughtbot/superglue'
|
10
|
+
|
11
|
+
export const buildStore = (initialState, superglueReducer, supergluePagesReducer) => {
|
12
|
+
|
13
|
+
return configureStore({
|
14
|
+
preloadedState: initialState,
|
15
|
+
devTools: process.env.NODE_ENV !== 'production',
|
16
|
+
middleware: (getDefaultMiddleware) =>
|
17
|
+
getDefaultMiddleware({
|
18
|
+
serializableCheck: {
|
19
|
+
ignoredActions: [BEFORE_VISIT, BEFORE_FETCH, BEFORE_REMOTE],
|
20
|
+
},
|
21
|
+
}).concat(fragmentMiddleware),
|
22
|
+
reducer: {
|
23
|
+
superglue: superglueReducer,
|
24
|
+
pages: (state, action) => {
|
25
|
+
const nextState = supergluePagesReducer(state, action)
|
26
|
+
return pagesSlice.reducer(nextState, action)
|
27
|
+
},
|
28
|
+
flash: flashSlice.reducer
|
29
|
+
},
|
30
|
+
});
|
31
|
+
};
|
32
|
+
|
data/lib/install/web.rb
CHANGED
@@ -22,11 +22,14 @@ copy_file "#{__dir__}/templates/web/application.js", "#{app_js_path}/application
|
|
22
22
|
say "Copying page_to_page_mapping.js file to #{app_js_path}"
|
23
23
|
copy_file "#{__dir__}/templates/web/page_to_page_mapping.js", "#{app_js_path}/page_to_page_mapping.js"
|
24
24
|
|
25
|
-
say "Copying
|
26
|
-
copy_file "#{__dir__}/templates/web/
|
25
|
+
say "Copying flash.js file to #{app_js_path}"
|
26
|
+
copy_file "#{__dir__}/templates/web/flash.js", "#{app_js_path}/slices/flash.js"
|
27
27
|
|
28
|
-
say "Copying
|
29
|
-
copy_file "#{__dir__}/templates/web/
|
28
|
+
say "Copying pages.js file to #{app_js_path}"
|
29
|
+
copy_file "#{__dir__}/templates/web/pages.js", "#{app_js_path}/slices/pages.js"
|
30
|
+
|
31
|
+
say "Copying store.js file to #{app_js_path}"
|
32
|
+
copy_file "#{__dir__}/templates/web/store.js", "#{app_js_path}/store.js"
|
30
33
|
|
31
34
|
say "Copying actions.js file to #{app_js_path}"
|
32
35
|
copy_file "#{__dir__}/templates/web/actions.js", "#{app_js_path}/actions.js"
|
@@ -46,7 +49,7 @@ add_member_methods
|
|
46
49
|
say "Installing FormProps"
|
47
50
|
run "bundle add form_props"
|
48
51
|
|
49
|
-
say "Installing
|
50
|
-
run "yarn add history react
|
52
|
+
say "Installing Superglue and friends"
|
53
|
+
run "yarn add history react react-dom @reduxjs/toolkit react-redux @thoughtbot/superglue --save"
|
51
54
|
|
52
55
|
say "Superglue is Installed! 🎉", :green
|
data/lib/tasks/install.rake
CHANGED
@@ -1,17 +1,7 @@
|
|
1
1
|
namespace :superglue do
|
2
|
-
desc "Verifies if any version of react is in package.json"
|
3
|
-
task :verify_react do
|
4
|
-
package_json = JSON.parse(File.read(Rails.root.join("package.json")))
|
5
|
-
|
6
|
-
if package_json["dependencies"]["react"].nil?
|
7
|
-
warn "React not installed. Did you install React? https://github.com/rails/webpacker#react"
|
8
|
-
warn "Exiting!" && exit!
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
2
|
namespace :install do
|
13
3
|
desc "Install everything needed for superglue web"
|
14
|
-
task "web"
|
4
|
+
task "web" do
|
15
5
|
template = File.expand_path("../install/web.rb", __dir__)
|
16
6
|
exec "#{RbConfig.ruby} ./bin/rails app:template LOCATION=#{template}"
|
17
7
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: superglue
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.50.0
|
4
|
+
version: 0.50.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Johny Ho
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-08
|
11
|
+
date: 2023-10-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionpack
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 7.0.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 7.0.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: props_template
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,14 +58,14 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '7.0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '7.0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rake
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,20 +80,6 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '12.0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: byebug
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - "~>"
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '9.0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - "~>"
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '9.0'
|
97
83
|
- !ruby/object:Gem::Dependency
|
98
84
|
name: sqlite3
|
99
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -172,14 +158,15 @@ files:
|
|
172
158
|
- lib/generators/rails/templates/web/new.js
|
173
159
|
- lib/generators/rails/templates/web/show.html.erb
|
174
160
|
- lib/generators/rails/templates/web/show.js
|
175
|
-
- lib/install/templates/web/action_creators.js
|
176
161
|
- lib/install/templates/web/actions.js
|
177
162
|
- lib/install/templates/web/application.js
|
178
163
|
- lib/install/templates/web/application.json.props
|
179
164
|
- lib/install/templates/web/application_visit.js
|
165
|
+
- lib/install/templates/web/flash.js
|
180
166
|
- lib/install/templates/web/initializer.rb
|
181
167
|
- lib/install/templates/web/page_to_page_mapping.js
|
182
|
-
- lib/install/templates/web/
|
168
|
+
- lib/install/templates/web/pages.js
|
169
|
+
- lib/install/templates/web/store.js
|
183
170
|
- lib/install/web.rb
|
184
171
|
- lib/superglue.rb
|
185
172
|
- lib/superglue/helpers.rb
|
@@ -200,9 +187,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
200
187
|
version: '0'
|
201
188
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
202
189
|
requirements:
|
203
|
-
- - "
|
190
|
+
- - ">="
|
204
191
|
- !ruby/object:Gem::Version
|
205
|
-
version:
|
192
|
+
version: '0'
|
206
193
|
requirements: []
|
207
194
|
rubygems_version: 3.4.6
|
208
195
|
signing_key:
|
@@ -1,44 +0,0 @@
|
|
1
|
-
// Example:
|
2
|
-
//
|
3
|
-
// import {
|
4
|
-
// CLEAR_FORM_ERRORS
|
5
|
-
// } from './actions'
|
6
|
-
// import produce from "immer"
|
7
|
-
//
|
8
|
-
// export const applicationPagesReducer = (state = {}, action) => {
|
9
|
-
// switch(action.type) {
|
10
|
-
// case CLEAR_FORM_ERRORS: {
|
11
|
-
// const {pageKey} = action.payload
|
12
|
-
//
|
13
|
-
// return produce(state, draft => {
|
14
|
-
// const currentPage = draft[pageKey]
|
15
|
-
// delete currentPage.errors
|
16
|
-
// })
|
17
|
-
// }
|
18
|
-
// default:
|
19
|
-
// return state
|
20
|
-
// }
|
21
|
-
// }
|
22
|
-
|
23
|
-
|
24
|
-
// The applicationPageReducer is for cross page reducers
|
25
|
-
// Its common to add to this. You'll typically have to pass a pageKey to the
|
26
|
-
// action payload to distinguish the current page
|
27
|
-
//
|
28
|
-
// The pageKey is passed through the props in your component. Access it like
|
29
|
-
// this: `this.props.pageKey` then dispatch it in an action
|
30
|
-
export const applicationPagesReducer = (state = {}, action) => {
|
31
|
-
switch(action.type) {
|
32
|
-
default:
|
33
|
-
return state
|
34
|
-
}
|
35
|
-
}
|
36
|
-
|
37
|
-
// The applicationRootReducer is for app wide reducers
|
38
|
-
// Its rare to be adding to this.
|
39
|
-
export const applicationRootReducer = (state = {}, action) => {
|
40
|
-
switch(action.type) {
|
41
|
-
default:
|
42
|
-
return state
|
43
|
-
}
|
44
|
-
}
|