@kaspernj/api-maker 1.0.414 → 1.0.415
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/table/filters/attribute-element.jsx +16 -14
- package/src/table/filters/filter-form.jsx +163 -62
- package/src/table/filters/filter.jsx +3 -4
- package/src/table/filters/reflection-element.jsx +17 -17
- package/src/table/filters/save-search-modal.jsx +11 -12
- package/src/table/filters/scope-element.jsx +11 -9
package/package.json
CHANGED
|
@@ -1,37 +1,39 @@
|
|
|
1
|
-
import Attribute from "../../base-model/attribute"
|
|
2
1
|
import BaseComponent from "../../base-component"
|
|
3
|
-
import {digg
|
|
4
|
-
import * as inflection from "inflection"
|
|
2
|
+
import {digg} from "diggerize"
|
|
5
3
|
import PropTypes from "prop-types"
|
|
6
4
|
import PropTypesExact from "prop-types-exact"
|
|
7
5
|
import {memo} from "react"
|
|
6
|
+
import {Pressable, Text} from "react-native"
|
|
8
7
|
import {shapeComponent} from "set-state-compare/src/shape-component"
|
|
9
8
|
|
|
10
9
|
export default memo(shapeComponent(class AttributeElement extends BaseComponent {
|
|
11
10
|
static propTypes = PropTypesExact({
|
|
12
11
|
active: PropTypes.bool.isRequired,
|
|
13
|
-
attribute: PropTypes.
|
|
14
|
-
|
|
12
|
+
attribute: PropTypes.object.isRequired,
|
|
13
|
+
modelClassName: PropTypes.string.isRequired,
|
|
15
14
|
fikter: PropTypes.object,
|
|
16
15
|
onClick: PropTypes.func.isRequired
|
|
17
16
|
})
|
|
18
17
|
|
|
19
18
|
render() {
|
|
20
|
-
const {active, attribute,
|
|
19
|
+
const {active, attribute, modelClassName} = this.p
|
|
21
20
|
const style = {}
|
|
22
21
|
|
|
23
22
|
if (active) style.fontWeight = "bold"
|
|
24
23
|
|
|
25
24
|
return (
|
|
26
|
-
<
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
<Pressable
|
|
26
|
+
dataSet={{
|
|
27
|
+
class: "attribute-element",
|
|
28
|
+
attributeName: digg(attribute, "attributeName"),
|
|
29
|
+
modelClass: modelClassName
|
|
30
|
+
}}
|
|
31
|
+
onPress={this.tt.onAttributeClicked}
|
|
32
32
|
>
|
|
33
|
-
{
|
|
34
|
-
|
|
33
|
+
<Text style={style}>
|
|
34
|
+
{digg(attribute, "humanName")}
|
|
35
|
+
</Text>
|
|
36
|
+
</Pressable>
|
|
35
37
|
)
|
|
36
38
|
}
|
|
37
39
|
|
|
@@ -2,10 +2,12 @@ import AttributeElement from "./attribute-element"
|
|
|
2
2
|
import BaseComponent from "../../base-component"
|
|
3
3
|
import {digg, digs} from "diggerize"
|
|
4
4
|
import * as inflection from "inflection"
|
|
5
|
+
import {Form} from "../../form"
|
|
5
6
|
import Input from "../../inputs/input"
|
|
6
7
|
import PropTypes from "prop-types"
|
|
7
8
|
import PropTypesExact from "prop-types-exact"
|
|
8
9
|
import {memo, useMemo, useRef} from "react"
|
|
10
|
+
import {ActivityIndicator, Text, View} from "react-native"
|
|
9
11
|
import ReflectionElement from "./reflection-element"
|
|
10
12
|
import ScopeElement from "./scope-element"
|
|
11
13
|
import Select from "../../inputs/select"
|
|
@@ -22,41 +24,127 @@ export default memo(shapeComponent(class ApiMakerTableFiltersFilterForm extends
|
|
|
22
24
|
|
|
23
25
|
setup() {
|
|
24
26
|
this.useStates({
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
associations: null,
|
|
28
|
+
attribute: undefined,
|
|
29
|
+
actualCurrentModelClass: () => ({modelClass: this.p.modelClass}),
|
|
30
|
+
loading: 0,
|
|
31
|
+
modelClassName: digg(this.p.modelClass.modelClassData(), "className"),
|
|
32
|
+
path: [],
|
|
29
33
|
predicate: undefined,
|
|
30
34
|
predicates: undefined,
|
|
35
|
+
ransackableAttributes: undefined,
|
|
36
|
+
ransackableScopes: undefined,
|
|
31
37
|
scope: this.props.filter.sc,
|
|
32
38
|
value: this.props.filter.v
|
|
33
39
|
})
|
|
34
|
-
|
|
40
|
+
|
|
41
|
+
this.setInstance({valueInputRef: useRef()})
|
|
35
42
|
|
|
36
43
|
useMemo(() => {
|
|
37
44
|
this.loadRansackPredicates()
|
|
45
|
+
|
|
46
|
+
if (this.props.filter.v) {
|
|
47
|
+
this.loadInitialValuesWithLoadingIndicator()
|
|
48
|
+
}
|
|
38
49
|
}, [])
|
|
50
|
+
|
|
51
|
+
useMemo(() => {
|
|
52
|
+
this.loadAssociations()
|
|
53
|
+
}, [this.s.modelClassName])
|
|
39
54
|
}
|
|
40
55
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
56
|
+
currentModelClass = () => digg(this.s.actualCurrentModelClass, "modelClass")
|
|
57
|
+
|
|
58
|
+
parseAssociationData(result) {
|
|
59
|
+
const associations = result.associations.map(({human_name, model_class_name, reflection_name, resource}) => ({
|
|
60
|
+
humanName: human_name,
|
|
61
|
+
modelClassName: model_class_name,
|
|
62
|
+
reflectionName: inflection.camelize(reflection_name, true),
|
|
63
|
+
resource
|
|
64
|
+
}))
|
|
65
|
+
const ransackableAttributes = digg(result, "ransackable_attributes").map(({attribute_name: attributeName, human_name: humanName}) => ({
|
|
66
|
+
attributeName, humanName
|
|
67
|
+
}))
|
|
68
|
+
const ransackableScopes = digg(result, "ransackable_scopes")
|
|
69
|
+
|
|
70
|
+
return {associations, ransackableAttributes, ransackableScopes}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async loadAssociations() {
|
|
74
|
+
this.increaseLoading()
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const result = await Services.current().sendRequest("Models::Associations", {model_class_name: this.s.modelClassName})
|
|
78
|
+
const {associations, ransackableAttributes, ransackableScopes} = this.parseAssociationData(result)
|
|
45
79
|
|
|
46
|
-
|
|
47
|
-
|
|
80
|
+
this.setState({associations, ransackableAttributes, ransackableScopes})
|
|
81
|
+
} finally {
|
|
82
|
+
this.decreaseLoading()
|
|
48
83
|
}
|
|
84
|
+
}
|
|
49
85
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
86
|
+
decreaseLoading = () => this.setState((prevState) => ({loading: prevState.loading - 1}))
|
|
87
|
+
increaseLoading = () => this.setState((prevState) => ({loading: prevState.loading + 1}))
|
|
88
|
+
|
|
89
|
+
async loadInitialValuesWithLoadingIndicator() {
|
|
90
|
+
try {
|
|
91
|
+
this.increaseLoading()
|
|
92
|
+
await this.loadInitialValues()
|
|
93
|
+
} finally {
|
|
94
|
+
this.decreaseLoading()
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async loadInitialValues() {
|
|
99
|
+
let result = await Services.current().sendRequest("Models::Associations", {model_class_name: this.s.modelClassName})
|
|
100
|
+
let data = this.parseAssociationData(result)
|
|
101
|
+
let modelClassName
|
|
102
|
+
const path = []
|
|
103
|
+
|
|
104
|
+
for (const pathPart of this.props.filter.p) {
|
|
105
|
+
const reflection = data.associations.find((association) => digg(association, "reflectionName") == inflection.camelize(pathPart, true))
|
|
106
|
+
|
|
107
|
+
if (!reflection) throw new Error(`Couldn't find association by that name ${this.s.modelClassName}#${pathPart}`)
|
|
108
|
+
|
|
109
|
+
modelClassName = digg(reflection, "modelClassName")
|
|
110
|
+
|
|
111
|
+
result = await Services.current().sendRequest("Models::Associations", {model_class_name: modelClassName})
|
|
112
|
+
data = this.parseAssociationData(result)
|
|
113
|
+
|
|
114
|
+
path.push(reflection)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const {ransackableAttributes} = data
|
|
118
|
+
const attribute = this.p.filter.a
|
|
119
|
+
const ransackableAttribute = ransackableAttributes.find((ransackableAttribute) => digg(ransackableAttribute, "attributeName") == attribute)
|
|
120
|
+
|
|
121
|
+
this.setState({attribute: ransackableAttribute, modelClassName, path})
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async loadRansackPredicates() {
|
|
125
|
+
this.increaseLoading()
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
const response = await Services.current().sendRequest("Ransack::Predicates")
|
|
129
|
+
const predicates = digg(response, "predicates")
|
|
130
|
+
let currentPredicate
|
|
131
|
+
|
|
132
|
+
if (this.props.filter.pre) {
|
|
133
|
+
currentPredicate = predicates.find((predicate) => predicate.name == this.props.filter.pre)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
this.setState({
|
|
137
|
+
predicate: currentPredicate,
|
|
138
|
+
predicates
|
|
139
|
+
})
|
|
140
|
+
} finally {
|
|
141
|
+
this.decreaseLoading()
|
|
142
|
+
}
|
|
54
143
|
}
|
|
55
144
|
|
|
56
145
|
render() {
|
|
57
146
|
const {valueInputRef} = digs(this, "valueInputRef")
|
|
58
|
-
const
|
|
59
|
-
const {attribute, predicate, predicates, scope, value} = this.s
|
|
147
|
+
const {attribute, path, predicate, predicates, scope, value} = this.s
|
|
60
148
|
let submitEnabled = false
|
|
61
149
|
|
|
62
150
|
if (attribute && predicate) {
|
|
@@ -66,51 +154,53 @@ export default memo(shapeComponent(class ApiMakerTableFiltersFilterForm extends
|
|
|
66
154
|
}
|
|
67
155
|
|
|
68
156
|
return (
|
|
69
|
-
<
|
|
70
|
-
<
|
|
71
|
-
<
|
|
72
|
-
{
|
|
73
|
-
<
|
|
157
|
+
<View dataSet={{class: "api-maker--table--filters--filter-form"}} style={{minWidth: 50, minHeight: 50}}>
|
|
158
|
+
<Form onSubmit={this.tt.onSubmit}>
|
|
159
|
+
<View style={{flexDirection: "row"}}>
|
|
160
|
+
{path.map(({humanName, reflectionName}, pathPartIndex) =>
|
|
161
|
+
<View key={`${pathPartIndex}-${reflectionName}`} style={{flexDirection: "row"}}>
|
|
74
162
|
{pathPartIndex > 0 &&
|
|
75
|
-
<
|
|
163
|
+
<Text style={{marginRight: 5, marginLeft: 5}}>
|
|
76
164
|
-
|
|
77
|
-
</
|
|
165
|
+
</Text>
|
|
78
166
|
}
|
|
79
|
-
|
|
80
|
-
|
|
167
|
+
<Text>
|
|
168
|
+
{humanName}
|
|
169
|
+
</Text>
|
|
170
|
+
</View>
|
|
81
171
|
)}
|
|
82
|
-
</
|
|
83
|
-
<
|
|
84
|
-
<
|
|
85
|
-
{this.
|
|
172
|
+
</View>
|
|
173
|
+
<View style={{flexDirection: "row"}}>
|
|
174
|
+
<View>
|
|
175
|
+
{this.s.associations?.map((reflection) =>
|
|
86
176
|
<ReflectionElement
|
|
87
|
-
|
|
88
|
-
|
|
177
|
+
key={reflection.reflectionName}
|
|
178
|
+
modelClassName={this.s.modelClassName}
|
|
89
179
|
onClick={this.tt.onReflectionClicked}
|
|
90
180
|
reflection={reflection}
|
|
91
181
|
/>
|
|
92
182
|
)}
|
|
93
|
-
</
|
|
94
|
-
<
|
|
95
|
-
{this.
|
|
183
|
+
</View>
|
|
184
|
+
<View>
|
|
185
|
+
{this.s.ransackableAttributes?.map((attribute) =>
|
|
96
186
|
<AttributeElement
|
|
97
|
-
active={attribute.
|
|
187
|
+
active={attribute.attributeName == this.s.attribute?.attributeName}
|
|
98
188
|
attribute={attribute}
|
|
99
|
-
|
|
100
|
-
|
|
189
|
+
key={attribute.attributeName}
|
|
190
|
+
modelClassName={this.s.modelClassName}
|
|
101
191
|
onClick={this.tt.onAttributeClicked}
|
|
102
192
|
/>
|
|
103
193
|
)}
|
|
104
|
-
{
|
|
194
|
+
{this.s.ransackableScopes?.map((scope) =>
|
|
105
195
|
<ScopeElement
|
|
106
|
-
active={scope
|
|
107
|
-
key={scope
|
|
196
|
+
active={scope == this.s.scope}
|
|
197
|
+
key={scope}
|
|
108
198
|
scope={scope}
|
|
109
199
|
onScopeClicked={this.tt.onScopeClicked}
|
|
110
200
|
/>
|
|
111
201
|
)}
|
|
112
|
-
</
|
|
113
|
-
<
|
|
202
|
+
</View>
|
|
203
|
+
<View>
|
|
114
204
|
{predicates && !this.state.scope &&
|
|
115
205
|
<Select
|
|
116
206
|
className="predicate-select"
|
|
@@ -120,25 +210,36 @@ export default memo(shapeComponent(class ApiMakerTableFiltersFilterForm extends
|
|
|
120
210
|
options={predicates.map((predicate) => digg(predicate, "name"))}
|
|
121
211
|
/>
|
|
122
212
|
}
|
|
123
|
-
</
|
|
124
|
-
<
|
|
213
|
+
</View>
|
|
214
|
+
<View>
|
|
125
215
|
{((attribute && predicate) || scope) &&
|
|
126
216
|
<Input className="value-input" defaultValue={value} inputRef={valueInputRef} />
|
|
127
217
|
}
|
|
128
|
-
</
|
|
129
|
-
</
|
|
130
|
-
<
|
|
218
|
+
</View>
|
|
219
|
+
</View>
|
|
220
|
+
<View>
|
|
131
221
|
<button className="apply-filter-button" disabled={!submitEnabled}>
|
|
132
222
|
{I18n.t("js.api_maker.table.filters.relationship_select.apply", {defaultValue: "Apply"})}
|
|
133
223
|
</button>
|
|
134
|
-
</
|
|
135
|
-
</
|
|
136
|
-
|
|
224
|
+
</View>
|
|
225
|
+
</Form>
|
|
226
|
+
{this.s.loading > 0 &&
|
|
227
|
+
<View
|
|
228
|
+
style={{
|
|
229
|
+
alignItems: "center",
|
|
230
|
+
justifyContent: "center",
|
|
231
|
+
position: "absolute",
|
|
232
|
+
width: "100%",
|
|
233
|
+
height: "100%"
|
|
234
|
+
}}
|
|
235
|
+
>
|
|
236
|
+
<ActivityIndicator size="large" />
|
|
237
|
+
</View>
|
|
238
|
+
}
|
|
239
|
+
</View>
|
|
137
240
|
)
|
|
138
241
|
}
|
|
139
242
|
|
|
140
|
-
currentModelClass = () => this.currentModelClassFromPath(this.s.path)
|
|
141
|
-
|
|
142
243
|
currentModelClassFromPath(path) {
|
|
143
244
|
const {modelClass} = this.p
|
|
144
245
|
let currentModelClass = modelClass
|
|
@@ -195,21 +296,22 @@ export default memo(shapeComponent(class ApiMakerTableFiltersFilterForm extends
|
|
|
195
296
|
|
|
196
297
|
onPredicateChanged = (e) => {
|
|
197
298
|
const chosenPredicateName = digg(e, "target", "value")
|
|
198
|
-
const predicate = this.
|
|
299
|
+
const predicate = this.s.predicates.find((predicate) => predicate.name == chosenPredicateName)
|
|
199
300
|
|
|
200
301
|
this.setState({predicate})
|
|
201
302
|
}
|
|
202
303
|
|
|
203
304
|
onReflectionClicked = ({reflection}) => {
|
|
204
|
-
const newPath = this.
|
|
305
|
+
const newPath = this.s.path.concat([reflection])
|
|
205
306
|
|
|
206
307
|
this.setState({
|
|
308
|
+
associations: null,
|
|
207
309
|
attribute: undefined,
|
|
310
|
+
actualCurrentModelClass: {modelClass: digg(reflection, "resource")},
|
|
311
|
+
modelClassName: digg(reflection, "modelClassName"),
|
|
208
312
|
path: newPath,
|
|
209
313
|
predicate: undefined
|
|
210
314
|
})
|
|
211
|
-
|
|
212
|
-
this.props.onPathChanged
|
|
213
315
|
}
|
|
214
316
|
|
|
215
317
|
onScopeClicked = ({scope}) => {
|
|
@@ -219,21 +321,20 @@ export default memo(shapeComponent(class ApiMakerTableFiltersFilterForm extends
|
|
|
219
321
|
})
|
|
220
322
|
}
|
|
221
323
|
|
|
222
|
-
onSubmit = (
|
|
223
|
-
e.preventDefault()
|
|
224
|
-
|
|
324
|
+
onSubmit = () => {
|
|
225
325
|
const {filter, querySearchName} = this.p
|
|
226
326
|
const {attribute, path, predicate, scope} = this.s
|
|
227
327
|
const {filterIndex} = digs(filter, "filterIndex")
|
|
228
328
|
const searchParams = Params.parse()[querySearchName] || {}
|
|
229
329
|
const value = digg(this.tt.valueInputRef, "current", "value")
|
|
330
|
+
const p = path.map((reflection) => inflection.underscore(reflection.reflectionName))
|
|
230
331
|
const newSearchParams = {
|
|
231
|
-
p
|
|
332
|
+
p,
|
|
232
333
|
v: value
|
|
233
334
|
}
|
|
234
335
|
|
|
235
336
|
if (attribute) {
|
|
236
|
-
newSearchParams.a = attribute
|
|
337
|
+
newSearchParams.a = digg(attribute, "attributeName")
|
|
237
338
|
newSearchParams.pre = digg(predicate, "name")
|
|
238
339
|
} else if (scope) {
|
|
239
340
|
newSearchParams.sc = inflection.underscore(scope.name())
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {Pressable, Text, View} from "react-native"
|
|
2
2
|
import BaseComponent from "../../base-component"
|
|
3
|
+
import FontAwesomeIcon from "react-native-vector-icons/FontAwesome"
|
|
3
4
|
import PropTypes from "prop-types"
|
|
4
5
|
import PropTypesExact from "prop-types-exact"
|
|
5
6
|
import {memo} from "react"
|
|
@@ -27,7 +28,7 @@ export default memo(shapeComponent(class ApiMakerTableFilter extends BaseCompone
|
|
|
27
28
|
const {a, pre, sc} = this.props
|
|
28
29
|
|
|
29
30
|
return (
|
|
30
|
-
<View style={{
|
|
31
|
+
<View style={{alignItems: "center", flexDirection: "row", backgroundColor: "grey", paddingVertical: 10, paddingHorizontal: 6}}>
|
|
31
32
|
<Pressable dataSet={{class: "filter-label"}} onPress={this.tt.onFilterPressed}>
|
|
32
33
|
<Text>
|
|
33
34
|
{p.length > 0 &&
|
|
@@ -37,9 +38,7 @@ export default memo(shapeComponent(class ApiMakerTableFilter extends BaseCompone
|
|
|
37
38
|
</Text>
|
|
38
39
|
</Pressable>
|
|
39
40
|
<Pressable dataSet={{class: "remove-filter-button"}} onPress={this.tt.onRemoveFilterPressed} style={{marginLeft: 6}}>
|
|
40
|
-
<
|
|
41
|
-
✖
|
|
42
|
-
</Text>
|
|
41
|
+
<FontAwesomeIcon name="remove" />
|
|
43
42
|
</Pressable>
|
|
44
43
|
</View>
|
|
45
44
|
)
|
|
@@ -1,36 +1,36 @@
|
|
|
1
1
|
import BaseComponent from "../../base-component"
|
|
2
|
-
import {digg, digs} from "diggerize"
|
|
3
2
|
import PropTypes from "prop-types"
|
|
4
3
|
import PropTypesExact from "prop-types-exact"
|
|
5
4
|
import {memo} from "react"
|
|
6
|
-
import
|
|
5
|
+
import {Pressable, Text} from "react-native"
|
|
7
6
|
import {shapeComponent} from "set-state-compare/src/shape-component"
|
|
8
7
|
|
|
9
8
|
export default memo(shapeComponent(class ReflectionElement extends BaseComponent {
|
|
10
9
|
static propTypes = PropTypesExact({
|
|
11
|
-
|
|
10
|
+
modelClassName: PropTypes.string.isRequired,
|
|
12
11
|
onClick: PropTypes.func.isRequired,
|
|
13
|
-
reflection: PropTypes.
|
|
12
|
+
reflection: PropTypes.object.isRequired
|
|
14
13
|
})
|
|
15
14
|
|
|
16
15
|
render() {
|
|
17
|
-
const {
|
|
16
|
+
const {modelClassName, reflection} = this.p
|
|
17
|
+
const {humanName, reflectionName} = reflection
|
|
18
18
|
|
|
19
19
|
return (
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
<Pressable
|
|
21
|
+
dataSet={{
|
|
22
|
+
class: "reflection-element",
|
|
23
|
+
modelClass: modelClassName,
|
|
24
|
+
reflectionName
|
|
25
|
+
}}
|
|
26
|
+
onPress={this.tt.onReflectionClicked}
|
|
25
27
|
>
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
<Text>
|
|
29
|
+
{humanName}
|
|
30
|
+
</Text>
|
|
31
|
+
</Pressable>
|
|
28
32
|
)
|
|
29
33
|
}
|
|
30
34
|
|
|
31
|
-
onReflectionClicked = (
|
|
32
|
-
e.preventDefault()
|
|
33
|
-
|
|
34
|
-
this.p.onClick({reflection: digg(this, "props", "reflection")})
|
|
35
|
-
}
|
|
35
|
+
onReflectionClicked = () => this.p.onClick({reflection: this.p.reflection})
|
|
36
36
|
}))
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import apiMakerConfig from "@kaspernj/api-maker/src/config.mjs"
|
|
2
2
|
import BaseComponent from "../../base-component"
|
|
3
3
|
import Checkbox from "../../bootstrap/checkbox"
|
|
4
|
-
import {digg
|
|
4
|
+
import {digg} from "diggerize"
|
|
5
|
+
import {Form} from "../../form"
|
|
5
6
|
import Input from "../../bootstrap/input"
|
|
6
7
|
import {shapeComponent} from "set-state-compare/src/shape-component.js"
|
|
7
8
|
import {memo} from "react"
|
|
@@ -12,6 +13,7 @@ export default memo(shapeComponent(class ApiMakerTableFiltersSaveSearchModal ext
|
|
|
12
13
|
const {t} = useI18n({namespace: "js.api_maker.table.filters.save_search_modal"})
|
|
13
14
|
|
|
14
15
|
this.t = t
|
|
16
|
+
this.useStates({form: null})
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
render() {
|
|
@@ -20,7 +22,7 @@ export default memo(shapeComponent(class ApiMakerTableFiltersSaveSearchModal ext
|
|
|
20
22
|
|
|
21
23
|
return (
|
|
22
24
|
<Modal onRequestClose={onRequestClose} {...restProps}>
|
|
23
|
-
<
|
|
25
|
+
<Form onSubmit={this.tt.onSaveSearchSubmit} setForm={this.setStates.form}>
|
|
24
26
|
<Input
|
|
25
27
|
defaultValue={search.name()}
|
|
26
28
|
id="table_search_name"
|
|
@@ -36,27 +38,24 @@ export default memo(shapeComponent(class ApiMakerTableFiltersSaveSearchModal ext
|
|
|
36
38
|
<button className="save-search-submit-button">
|
|
37
39
|
{this.t(".save_search", {defaultValue: "Save search"})}
|
|
38
40
|
</button>
|
|
39
|
-
</
|
|
41
|
+
</Form>
|
|
40
42
|
</Modal>
|
|
41
43
|
)
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
onSaveSearchSubmit = async (
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const form = digg(e, "target")
|
|
48
|
-
const formData = new FormData(form)
|
|
46
|
+
onSaveSearchSubmit = async () => {
|
|
47
|
+
const formData = this.s.form.asObject()
|
|
49
48
|
const {currentFilters, currentUser, onRequestClose, search} = this.p
|
|
50
49
|
|
|
51
50
|
if (search.isNewRecord()) {
|
|
52
|
-
formData.
|
|
51
|
+
formData.table_search.query_params = JSON.stringify(currentFilters())
|
|
53
52
|
}
|
|
54
53
|
|
|
55
|
-
formData.
|
|
56
|
-
formData.
|
|
54
|
+
formData.table_search.user_type = digg(currentUser.modelClassData(), "className")
|
|
55
|
+
formData.table_search.user_id = currentUser.id()
|
|
57
56
|
|
|
58
57
|
try {
|
|
59
|
-
await search.saveRaw(formData
|
|
58
|
+
await search.saveRaw(formData)
|
|
60
59
|
onRequestClose()
|
|
61
60
|
} catch (error) {
|
|
62
61
|
FlashMessage.errorResponse(error)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import BaseComponent from "../../base-component"
|
|
2
|
-
import {digg} from "diggerize"
|
|
3
2
|
import PropTypes from "prop-types"
|
|
4
3
|
import {memo} from "react"
|
|
4
|
+
import {Pressable, Text} from "react-native"
|
|
5
5
|
import {shapeComponent} from "set-state-compare/src/shape-component"
|
|
6
6
|
|
|
7
7
|
export default memo(shapeComponent(class ScopeElement extends BaseComponent {
|
|
@@ -12,7 +12,7 @@ export default memo(shapeComponent(class ScopeElement extends BaseComponent {
|
|
|
12
12
|
static propTypes = {
|
|
13
13
|
active: PropTypes.bool.isRequired,
|
|
14
14
|
onScopeClicked: PropTypes.func.isRequired,
|
|
15
|
-
scope: PropTypes.
|
|
15
|
+
scope: PropTypes.string.isRequired
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
render() {
|
|
@@ -22,14 +22,16 @@ export default memo(shapeComponent(class ScopeElement extends BaseComponent {
|
|
|
22
22
|
if (active) style.fontWeight = "bold"
|
|
23
23
|
|
|
24
24
|
return (
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
key={scope
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
<Pressable
|
|
26
|
+
dataSet={{class: "scope-element"}}
|
|
27
|
+
key={scope}
|
|
28
|
+
onPress={this.tt.onScopeClicked}
|
|
29
|
+
|
|
30
30
|
>
|
|
31
|
-
{
|
|
32
|
-
|
|
31
|
+
<Text style={style}>
|
|
32
|
+
{scope}
|
|
33
|
+
</Text>
|
|
34
|
+
</Pressable>
|
|
33
35
|
)
|
|
34
36
|
}
|
|
35
37
|
|