@kaspernj/api-maker 1.0.313 → 1.0.315
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.
- package/package.json +1 -1
- package/src/use-can-can.mjs +2 -2
- package/src/use-model.mjs +40 -27
- package/src/with-model.jsx +10 -139
package/package.json
CHANGED
package/src/use-can-can.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import {useCallback, useEffect, useState} from "react"
|
|
|
3
3
|
import useShape from "set-state-compare/src/use-shape.js"
|
|
4
4
|
|
|
5
5
|
const useCanCan = (abilitiesCallback, dependencies) => {
|
|
6
|
-
const
|
|
6
|
+
const s = useShape({abilitiesCallback})
|
|
7
7
|
const [canCan, setCanCan] = useState()
|
|
8
8
|
|
|
9
9
|
useEffect(() => {
|
|
@@ -12,7 +12,7 @@ const useCanCan = (abilitiesCallback, dependencies) => {
|
|
|
12
12
|
|
|
13
13
|
const loadAbilities = useCallback(async () => {
|
|
14
14
|
const canCan = CanCan.current()
|
|
15
|
-
const abilities =
|
|
15
|
+
const abilities = s.p.abilitiesCallback()
|
|
16
16
|
|
|
17
17
|
await canCan.loadAbilities(abilities)
|
|
18
18
|
|
package/src/use-model.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import {useCallback, useEffect, useState} from "react"
|
|
1
2
|
import * as inflection from "inflection"
|
|
2
3
|
import ModelEvents from "./model-events.mjs"
|
|
3
4
|
import useQueryParams from "on-location-changed/src/use-query-params.js"
|
|
4
|
-
import
|
|
5
|
+
import useShape from "set-state-compare/src/use-shape.js"
|
|
5
6
|
|
|
6
7
|
const useModel = (modelClassArg, argsArg = {}) => {
|
|
7
8
|
const queryParams = useQueryParams()
|
|
@@ -13,6 +14,8 @@ const useModel = (modelClassArg, argsArg = {}) => {
|
|
|
13
14
|
args = argsArg
|
|
14
15
|
}
|
|
15
16
|
|
|
17
|
+
const s = useShape(args)
|
|
18
|
+
|
|
16
19
|
if (typeof modelClassArg == "object") {
|
|
17
20
|
modelClass = modelClassArg.callback({queryParams})
|
|
18
21
|
} else {
|
|
@@ -20,18 +23,16 @@ const useModel = (modelClassArg, argsArg = {}) => {
|
|
|
20
23
|
}
|
|
21
24
|
|
|
22
25
|
const paramsVariableName = `${modelClass.modelName().paramKey()}_id`
|
|
26
|
+
let modelId
|
|
23
27
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
|
|
28
|
+
if (args.loadByQueryParam) {
|
|
29
|
+
modelId = args.loadByQueryParam({queryParams})
|
|
30
|
+
} else {
|
|
29
31
|
if (!args.match) throw new Error("Both 'loadByQueryParam' and 'match' wasn't given")
|
|
30
32
|
|
|
31
|
-
|
|
33
|
+
modelId = args.match.params[paramsVariableName] || args.match.params.id
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
const modelId = getModelId()
|
|
35
36
|
const modelVariableName = inflection.camelize(modelClass.modelClassData().name, true)
|
|
36
37
|
const cacheArgs = [modelId]
|
|
37
38
|
const [model, setModel] = useState(undefined)
|
|
@@ -41,48 +42,52 @@ const useModel = (modelClassArg, argsArg = {}) => {
|
|
|
41
42
|
cacheArgs.push(...args.cacheArgs)
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
s.updateMeta({modelId, modelVariableName, queryParams})
|
|
46
|
+
|
|
47
|
+
const loadExistingModel = useCallback(async () => {
|
|
48
|
+
const query = await modelClass.ransack({id_eq: s.m.modelId})
|
|
49
|
+
|
|
50
|
+
if (!modelId) {
|
|
51
|
+
throw new Error(`No model ID was given: ${s.m.modelId} by '${paramsVariableName}' in query params: ${Object.keys(s.props.match.params).join(", ")}`)
|
|
52
|
+
}
|
|
46
53
|
|
|
47
|
-
if (
|
|
48
|
-
if (
|
|
49
|
-
if (
|
|
50
|
-
if (args.select) query.select(args.select)
|
|
54
|
+
if (s.props.abilities) query.abilities(s.p.abilities)
|
|
55
|
+
if (s.props.preload) query.preload(s.p.preload)
|
|
56
|
+
if (s.props.select) query.select(s.p.select)
|
|
51
57
|
|
|
52
58
|
const model = await query.first()
|
|
53
59
|
|
|
54
60
|
setModel(model)
|
|
55
61
|
setNotFound(!model)
|
|
56
|
-
}
|
|
62
|
+
}, [])
|
|
57
63
|
|
|
58
|
-
const loadNewModel = async () => {
|
|
59
|
-
const params = Params.parse()
|
|
64
|
+
const loadNewModel = useCallback(async () => {
|
|
60
65
|
const ModelClass = modelClass
|
|
61
66
|
const paramKey = ModelClass.modelName().paramKey()
|
|
62
|
-
const modelDataFromParams =
|
|
67
|
+
const modelDataFromParams = s.m.queryParams[paramKey] || {}
|
|
63
68
|
|
|
64
69
|
let defaults = {}
|
|
65
70
|
|
|
66
|
-
if (
|
|
67
|
-
defaults = await
|
|
71
|
+
if (s.props.newIfNoId?.defaults) {
|
|
72
|
+
defaults = await s.props.newIfNoId.defaults()
|
|
68
73
|
}
|
|
69
74
|
|
|
70
|
-
const modelData = Object.assign(defaults,
|
|
75
|
+
const modelData = Object.assign(defaults, s.props.newAttributes, modelDataFromParams)
|
|
71
76
|
const model = new ModelClass({
|
|
72
77
|
isNewRecord: true,
|
|
73
78
|
data: {a: modelData}
|
|
74
79
|
})
|
|
75
80
|
|
|
76
81
|
setModel(model)
|
|
77
|
-
}
|
|
82
|
+
}, [])
|
|
78
83
|
|
|
79
|
-
const loadModel = async () => {
|
|
80
|
-
if (
|
|
84
|
+
const loadModel = useCallback(async () => {
|
|
85
|
+
if (s.props.newIfNoId && !s.m.modelId) {
|
|
81
86
|
return await loadNewModel()
|
|
82
|
-
} else if (!
|
|
87
|
+
} else if (!s.props.optional || s.m.modelId) {
|
|
83
88
|
return await loadExistingModel()
|
|
84
89
|
}
|
|
85
|
-
}
|
|
90
|
+
}, [])
|
|
86
91
|
|
|
87
92
|
useEffect(
|
|
88
93
|
() => { loadModel() },
|
|
@@ -115,11 +120,19 @@ const useModel = (modelClassArg, argsArg = {}) => {
|
|
|
115
120
|
}
|
|
116
121
|
}, [args.eventUpdated, model?.id()])
|
|
117
122
|
|
|
123
|
+
const onDestroyed = useCallback(({model}) => {
|
|
124
|
+
const forwardArgs = {model}
|
|
125
|
+
|
|
126
|
+
forwardArgs[s.m.modelVariableName] = model
|
|
127
|
+
|
|
128
|
+
s.p.onDestroyed(forwardArgs)
|
|
129
|
+
}, [])
|
|
130
|
+
|
|
118
131
|
useEffect(() => {
|
|
119
132
|
let connectDestroyed
|
|
120
133
|
|
|
121
134
|
if (model && args.onDestroyed) {
|
|
122
|
-
connectDestroyed = ModelEvents.connectDestroyed(model,
|
|
135
|
+
connectDestroyed = ModelEvents.connectDestroyed(model, onDestroyed)
|
|
123
136
|
}
|
|
124
137
|
|
|
125
138
|
return () => {
|
package/src/with-model.jsx
CHANGED
|
@@ -1,144 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import * as inflection from "inflection"
|
|
4
|
-
import Params from "./params.mjs"
|
|
5
|
-
import PropTypes from "prop-types"
|
|
6
|
-
import React from "react"
|
|
7
|
-
import withQueryParams from "on-location-changed/src/with-query-params"
|
|
1
|
+
import {memo} from "react"
|
|
2
|
+
import useModel from "./use-model.mjs"
|
|
8
3
|
|
|
9
|
-
export default (WrappedComponent,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
4
|
+
export default (WrappedComponent, modelClass, givenArgs) => {
|
|
5
|
+
const ApiMakerWithModel = (props) => {
|
|
6
|
+
const args = Object.assign({match: props.match}, givenArgs)
|
|
7
|
+
const useModelResult = useModel(modelClass, args)
|
|
14
8
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
paramsVariableName = `${this.modelClass.modelName().paramKey()}_id`
|
|
19
|
-
|
|
20
|
-
state = {
|
|
21
|
-
model: undefined,
|
|
22
|
-
modelId: this.getModelId(),
|
|
23
|
-
notFound: undefined
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
resolveArgs() {
|
|
27
|
-
if (typeof argsArg == "function") {
|
|
28
|
-
return argsArg({
|
|
29
|
-
modelClass: this.modelClass
|
|
30
|
-
})
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return argsArg
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
resolveModelClass(modelClassArg) {
|
|
37
|
-
if (typeof modelClassArg == "object") {
|
|
38
|
-
const {queryParams} = digs(this.props, "queryParams")
|
|
39
|
-
|
|
40
|
-
return modelClassArg.callback({queryParams})
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return modelClassArg
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
componentDidMount() {
|
|
47
|
-
this.loadModel()
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
componentDidUpdate() {
|
|
51
|
-
const newModelId = this.getModelId()
|
|
52
|
-
|
|
53
|
-
// The model ID was changed in the URL and a different model should be loaded
|
|
54
|
-
if (newModelId != this.state.modelId) {
|
|
55
|
-
this.setState({model: undefined, modelId: newModelId})
|
|
56
|
-
this.loadExistingModel()
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
loadModel = async () => {
|
|
61
|
-
if (this.args.newIfNoId && !this.getModelId()) {
|
|
62
|
-
return await this.loadNewModel()
|
|
63
|
-
} else if (!this.args.optional || this.getModelId()) {
|
|
64
|
-
return await this.loadExistingModel()
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
getModelId() {
|
|
69
|
-
if (this.args.loadByQueryParam)
|
|
70
|
-
return this.args.loadByQueryParam({props: this.props})
|
|
71
|
-
|
|
72
|
-
return this.props.match.params[this.paramsVariableName] || this.props.match.params.id
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
loadExistingModel = async () => {
|
|
76
|
-
const modelId = this.getModelId()
|
|
77
|
-
const ModelClass = digg(this, "modelClass")
|
|
78
|
-
const query = await ModelClass.ransack({id_eq: modelId})
|
|
79
|
-
|
|
80
|
-
if (!modelId) throw new Error(`No model ID was given: ${modelId} by '${this.paramsVariableName}' in query params: ${Object.keys(this.props.match.params).join(", ")}`)
|
|
81
|
-
if (this.args.abilities) query.abilities(this.args.abilities)
|
|
82
|
-
if (this.args.preload) query.preload(this.args.preload)
|
|
83
|
-
if (this.args.select) query.select(this.args.select)
|
|
84
|
-
|
|
85
|
-
const model = await query.first()
|
|
86
|
-
|
|
87
|
-
this.setState({
|
|
88
|
-
model,
|
|
89
|
-
notFound: !model
|
|
90
|
-
})
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
async loadNewModel() {
|
|
94
|
-
const params = Params.parse()
|
|
95
|
-
const ModelClass = digg(this, "modelClass")
|
|
96
|
-
const paramKey = ModelClass.modelName().paramKey()
|
|
97
|
-
const modelDataFromParams = params[paramKey] || {}
|
|
98
|
-
|
|
99
|
-
let defaults = {}
|
|
100
|
-
|
|
101
|
-
if (this.args.newIfNoId?.defaults) {
|
|
102
|
-
defaults = await this.args.newIfNoId.defaults()
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const modelData = Object.assign(defaults, this.args.newAttributes, modelDataFromParams)
|
|
106
|
-
const model = new ModelClass({
|
|
107
|
-
isNewRecord: true,
|
|
108
|
-
data: {a: modelData}
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
this.setState({model})
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
render() {
|
|
115
|
-
const {onUpdated, reloadModel} = digs(this, "onUpdated", "reloadModel")
|
|
116
|
-
const {model, modelId, notFound} = digs(this.state, "model", "modelId", "notFound")
|
|
117
|
-
const wrappedComponentProps = {}
|
|
118
|
-
|
|
119
|
-
wrappedComponentProps[this.modelVariableName] = model
|
|
120
|
-
wrappedComponentProps[`${this.modelVariableName}Id`] = modelId
|
|
121
|
-
wrappedComponentProps[`${this.modelVariableName}NotFound`] = notFound
|
|
122
|
-
|
|
123
|
-
return (
|
|
124
|
-
<>
|
|
125
|
-
{this.args.events &&
|
|
126
|
-
<EventEmitterListener event="reloadModel" events={this.args.events} onCalled={reloadModel} />
|
|
127
|
-
}
|
|
128
|
-
{model && this.args.eventUpdated &&
|
|
129
|
-
<EventUpdated model={model} onUpdated={onUpdated} />
|
|
130
|
-
}
|
|
131
|
-
{model && this.args.onDestroyed &&
|
|
132
|
-
<EventDestroyed model={model} onDestroyed={this.args.onDestroyed} />
|
|
133
|
-
}
|
|
134
|
-
<WrappedComponent {...wrappedComponentProps} {...this.props} />
|
|
135
|
-
</>
|
|
136
|
-
)
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
reloadModel = () => this.loadModel()
|
|
140
|
-
onUpdated = this.loadExistingModel
|
|
9
|
+
return (
|
|
10
|
+
<WrappedComponent {...useModelResult} {...props} />
|
|
11
|
+
)
|
|
141
12
|
}
|
|
142
13
|
|
|
143
|
-
return
|
|
14
|
+
return memo(ApiMakerWithModel)
|
|
144
15
|
}
|