api_maker 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +476 -0
- data/Rakefile +27 -0
- data/app/channels/api_maker/subscriptions_channel.rb +80 -0
- data/app/controllers/api_maker/base_controller.rb +32 -0
- data/app/controllers/api_maker/commands_controller.rb +26 -0
- data/app/controllers/api_maker/devise_controller.rb +60 -0
- data/app/controllers/api_maker/session_statuses_controller.rb +33 -0
- data/app/services/api_maker/application_service.rb +7 -0
- data/app/services/api_maker/collection_command_service.rb +24 -0
- data/app/services/api_maker/command_response.rb +67 -0
- data/app/services/api_maker/command_service.rb +31 -0
- data/app/services/api_maker/create_command.rb +62 -0
- data/app/services/api_maker/create_command_service.rb +18 -0
- data/app/services/api_maker/destroy_command.rb +39 -0
- data/app/services/api_maker/destroy_command_service.rb +22 -0
- data/app/services/api_maker/generate_react_native_api_service.rb +61 -0
- data/app/services/api_maker/index_command.rb +96 -0
- data/app/services/api_maker/index_command_service.rb +22 -0
- data/app/services/api_maker/js_method_namer_service.rb +11 -0
- data/app/services/api_maker/member_command_service.rb +25 -0
- data/app/services/api_maker/model_content_generator_service.rb +108 -0
- data/app/services/api_maker/models_finder_service.rb +22 -0
- data/app/services/api_maker/models_generator_service.rb +104 -0
- data/app/services/api_maker/update_command.rb +43 -0
- data/app/services/api_maker/update_command_service.rb +21 -0
- data/app/services/api_maker/valid_command.rb +35 -0
- data/app/services/api_maker/valid_command_service.rb +21 -0
- data/app/views/api_maker/_data.html.erb +15 -0
- data/config/rails_best_practices.yml +55 -0
- data/config/routes.rb +7 -0
- data/lib/api_maker.rb +36 -0
- data/lib/api_maker/ability.rb +39 -0
- data/lib/api_maker/ability_loader.rb +21 -0
- data/lib/api_maker/action_controller_base_extensions.rb +5 -0
- data/lib/api_maker/base_command.rb +81 -0
- data/lib/api_maker/base_resource.rb +78 -0
- data/lib/api_maker/collection_serializer.rb +69 -0
- data/lib/api_maker/command_spec_helper.rb +57 -0
- data/lib/api_maker/configuration.rb +34 -0
- data/lib/api_maker/engine.rb +5 -0
- data/lib/api_maker/individual_command.rb +37 -0
- data/lib/api_maker/javascript/api.js +92 -0
- data/lib/api_maker/javascript/base-model.js +543 -0
- data/lib/api_maker/javascript/bootstrap/attribute-row.jsx +16 -0
- data/lib/api_maker/javascript/bootstrap/attribute-rows.jsx +47 -0
- data/lib/api_maker/javascript/bootstrap/card.jsx +79 -0
- data/lib/api_maker/javascript/bootstrap/checkbox.jsx +127 -0
- data/lib/api_maker/javascript/bootstrap/checkboxes.jsx +105 -0
- data/lib/api_maker/javascript/bootstrap/live-table.jsx +168 -0
- data/lib/api_maker/javascript/bootstrap/money-input.jsx +136 -0
- data/lib/api_maker/javascript/bootstrap/radio-buttons.jsx +80 -0
- data/lib/api_maker/javascript/bootstrap/select.jsx +168 -0
- data/lib/api_maker/javascript/bootstrap/string-input.jsx +203 -0
- data/lib/api_maker/javascript/cable-connection-pool.js +169 -0
- data/lib/api_maker/javascript/cable-subscription-pool.js +111 -0
- data/lib/api_maker/javascript/cable-subscription.js +33 -0
- data/lib/api_maker/javascript/collection.js +186 -0
- data/lib/api_maker/javascript/commands-pool.js +123 -0
- data/lib/api_maker/javascript/custom-error.js +14 -0
- data/lib/api_maker/javascript/deserializer.js +35 -0
- data/lib/api_maker/javascript/devise.js.erb +113 -0
- data/lib/api_maker/javascript/error-logger.js +119 -0
- data/lib/api_maker/javascript/event-connection.jsx +24 -0
- data/lib/api_maker/javascript/event-created.jsx +26 -0
- data/lib/api_maker/javascript/event-destroyed.jsx +26 -0
- data/lib/api_maker/javascript/event-emitter-listener.jsx +32 -0
- data/lib/api_maker/javascript/event-listener.jsx +41 -0
- data/lib/api_maker/javascript/event-updated.jsx +26 -0
- data/lib/api_maker/javascript/form-data-to-object.js +70 -0
- data/lib/api_maker/javascript/included.js +39 -0
- data/lib/api_maker/javascript/key-value-store.js +47 -0
- data/lib/api_maker/javascript/logger.js +23 -0
- data/lib/api_maker/javascript/model-name.js +21 -0
- data/lib/api_maker/javascript/model-template.js.erb +110 -0
- data/lib/api_maker/javascript/models-response-reader.js +43 -0
- data/lib/api_maker/javascript/paginate.jsx +128 -0
- data/lib/api_maker/javascript/params.js +68 -0
- data/lib/api_maker/javascript/resource-route.jsx +75 -0
- data/lib/api_maker/javascript/resource-routes.jsx +36 -0
- data/lib/api_maker/javascript/result.js +25 -0
- data/lib/api_maker/javascript/session-status-updater.js +113 -0
- data/lib/api_maker/javascript/sort-link.jsx +88 -0
- data/lib/api_maker/javascript/updated-attribute.jsx +60 -0
- data/lib/api_maker/loader.rb +14 -0
- data/lib/api_maker/memory_storage.rb +65 -0
- data/lib/api_maker/model_extensions.rb +96 -0
- data/lib/api_maker/permitted_params_argument.rb +12 -0
- data/lib/api_maker/preloader.rb +91 -0
- data/lib/api_maker/preloader_belongs_to.rb +58 -0
- data/lib/api_maker/preloader_has_many.rb +69 -0
- data/lib/api_maker/preloader_has_one.rb +70 -0
- data/lib/api_maker/preloader_through.rb +101 -0
- data/lib/api_maker/railtie.rb +14 -0
- data/lib/api_maker/relationship_includer.rb +42 -0
- data/lib/api_maker/resource_routing.rb +8 -0
- data/lib/api_maker/result_parser.rb +50 -0
- data/lib/api_maker/serializer.rb +86 -0
- data/lib/api_maker/spec_helper.rb +100 -0
- data/lib/api_maker/version.rb +3 -0
- data/lib/tasks/api_maker_tasks.rake +5 -0
- metadata +581 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
import React from "react"
|
2
|
+
|
3
|
+
export default class BootstrapAttributeRow extends React.Component {
|
4
|
+
render() {
|
5
|
+
return (
|
6
|
+
<tr>
|
7
|
+
<th>
|
8
|
+
{this.props.label}
|
9
|
+
</th>
|
10
|
+
<td>
|
11
|
+
{this.props.value || this.props.children}
|
12
|
+
</td>
|
13
|
+
</tr>
|
14
|
+
)
|
15
|
+
}
|
16
|
+
}
|
@@ -0,0 +1,47 @@
|
|
1
|
+
import AttributeRow from "./attribute-row"
|
2
|
+
import PropTypes from "prop-types"
|
3
|
+
import React from "react"
|
4
|
+
|
5
|
+
export default class BootstrapAttributeRows extends React.Component {
|
6
|
+
static propTypes = {
|
7
|
+
attributes: PropTypes.array.isRequired,
|
8
|
+
model: PropTypes.object.isRequired
|
9
|
+
}
|
10
|
+
|
11
|
+
constructor(props) {
|
12
|
+
super(props)
|
13
|
+
this.state = {
|
14
|
+
classObject: props.model.modelClass()
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
render() {
|
19
|
+
return this.props.attributes.map((attribute) =>
|
20
|
+
<AttributeRow key={`attribute-${attribute}`} label={this.state.classObject.humanAttributeName(attribute)}>
|
21
|
+
{this.valueContent(attribute)}
|
22
|
+
</AttributeRow>
|
23
|
+
)
|
24
|
+
}
|
25
|
+
|
26
|
+
value(attribute) {
|
27
|
+
if (!(attribute in this.props.model))
|
28
|
+
throw new Error(`Attribute not found: ${this.props.model.modelClassData().name}#${attribute}`)
|
29
|
+
|
30
|
+
return this.props.model[attribute]()
|
31
|
+
}
|
32
|
+
|
33
|
+
valueContent(attribute) {
|
34
|
+
var value = this.value(attribute)
|
35
|
+
|
36
|
+
if (value instanceof Date) {
|
37
|
+
return I18n.strftime(value, "%Y-%m-%d %H:%M")
|
38
|
+
} else if (typeof value === "boolean") {
|
39
|
+
if (value)
|
40
|
+
return I18n.t("js.shared.yes")
|
41
|
+
|
42
|
+
return I18n.t("js.shared.no")
|
43
|
+
} else {
|
44
|
+
return this.value(attribute)
|
45
|
+
}
|
46
|
+
}
|
47
|
+
}
|
@@ -0,0 +1,79 @@
|
|
1
|
+
import PropTypes from "prop-types"
|
2
|
+
import PropTypesExact from "prop-types-exact"
|
3
|
+
import React from "react"
|
4
|
+
|
5
|
+
export default class Card extends React.Component {
|
6
|
+
static defaultProps = {
|
7
|
+
responsiveTable: true
|
8
|
+
}
|
9
|
+
static propTypes = PropTypesExact({
|
10
|
+
className: PropTypes.string,
|
11
|
+
children: PropTypes.node,
|
12
|
+
controls: PropTypes.node,
|
13
|
+
header: PropTypes.string,
|
14
|
+
onClick: PropTypes.func,
|
15
|
+
striped: PropTypes.bool,
|
16
|
+
style: PropTypes.object,
|
17
|
+
responsiveTable: PropTypes.bool,
|
18
|
+
table: PropTypes.bool
|
19
|
+
})
|
20
|
+
|
21
|
+
render() {
|
22
|
+
var { children, controls, header, onClick, style, table } = this.props
|
23
|
+
|
24
|
+
return (
|
25
|
+
<div className={this.classNames()} onClick={onClick} ref="card" style={style}>
|
26
|
+
{(controls || header) &&
|
27
|
+
<div className="card-header">
|
28
|
+
{header}
|
29
|
+
{controls &&
|
30
|
+
<div className="float-right">
|
31
|
+
{controls}
|
32
|
+
</div>
|
33
|
+
}
|
34
|
+
</div>
|
35
|
+
}
|
36
|
+
<div className={this.bodyClassNames()}>
|
37
|
+
{table &&
|
38
|
+
<table className={this.tableClassNames()}>
|
39
|
+
{children}
|
40
|
+
</table>
|
41
|
+
}
|
42
|
+
{!table && children}
|
43
|
+
</div>
|
44
|
+
</div>
|
45
|
+
)
|
46
|
+
}
|
47
|
+
|
48
|
+
classNames() {
|
49
|
+
var classNames = ["component-bootstrap-card", "card", "card-default"]
|
50
|
+
|
51
|
+
if (this.props.className)
|
52
|
+
classNames.push(this.props.className)
|
53
|
+
|
54
|
+
return classNames.join(" ")
|
55
|
+
}
|
56
|
+
|
57
|
+
bodyClassNames() {
|
58
|
+
var classNames = ["card-body"]
|
59
|
+
|
60
|
+
if (this.props.table) {
|
61
|
+
if (this.props.responsiveTable){
|
62
|
+
classNames.push("table-responsive")
|
63
|
+
}
|
64
|
+
|
65
|
+
classNames.push("p-0")
|
66
|
+
}
|
67
|
+
|
68
|
+
return classNames.join(" ")
|
69
|
+
}
|
70
|
+
|
71
|
+
tableClassNames() {
|
72
|
+
var classNames = ["table", "table-hover", "mb-0", "w-100"]
|
73
|
+
|
74
|
+
if (this.props.striped)
|
75
|
+
classNames.push("table-striped")
|
76
|
+
|
77
|
+
return classNames.join(" ")
|
78
|
+
}
|
79
|
+
}
|
@@ -0,0 +1,127 @@
|
|
1
|
+
import PropTypes from "prop-types"
|
2
|
+
import PropTypesExact from "prop-types-exact"
|
3
|
+
import React from "react"
|
4
|
+
|
5
|
+
const inflection = require("inflection")
|
6
|
+
|
7
|
+
export default class BootstrapCheckbox extends React.Component {
|
8
|
+
static propTypes = PropTypesExact({
|
9
|
+
attribute: PropTypes.string,
|
10
|
+
className: PropTypes.string,
|
11
|
+
"data-action": PropTypes.string,
|
12
|
+
"data-target": PropTypes.string,
|
13
|
+
defaultChecked: PropTypes.bool,
|
14
|
+
defaultValue: PropTypes.node,
|
15
|
+
hint: PropTypes.node,
|
16
|
+
id: PropTypes.string,
|
17
|
+
label: PropTypes.node,
|
18
|
+
labelClassName: PropTypes.string,
|
19
|
+
model: PropTypes.object,
|
20
|
+
name: PropTypes.string,
|
21
|
+
onChange: PropTypes.func,
|
22
|
+
wrapperClassName: PropTypes.string
|
23
|
+
})
|
24
|
+
|
25
|
+
render() {
|
26
|
+
let id = this.inputId()
|
27
|
+
|
28
|
+
return (
|
29
|
+
<div className={this.wrapperClassName()}>
|
30
|
+
<div className="form-check">
|
31
|
+
<input defaultValue="0" name={this.inputName()} type="hidden" type="hidden" />
|
32
|
+
<input
|
33
|
+
data-target={this.props["data-target"]}
|
34
|
+
defaultChecked={this.inputDefaultChecked()}
|
35
|
+
className={this.className()}
|
36
|
+
data-action={this.props["data-action"]}
|
37
|
+
defaultValue="1"
|
38
|
+
id={id}
|
39
|
+
name={this.inputName()}
|
40
|
+
onChange={this.props.onChange}
|
41
|
+
ref="input"
|
42
|
+
type="checkbox"
|
43
|
+
/>
|
44
|
+
|
45
|
+
{this.label() &&
|
46
|
+
<label className={this.labelClassName()} htmlFor={id}>
|
47
|
+
{this.label()}
|
48
|
+
</label>
|
49
|
+
}
|
50
|
+
</div>
|
51
|
+
{this.props.hint &&
|
52
|
+
<p className="text-muted">
|
53
|
+
{this.props.hint}
|
54
|
+
</p>
|
55
|
+
}
|
56
|
+
</div>
|
57
|
+
)
|
58
|
+
}
|
59
|
+
|
60
|
+
className() {
|
61
|
+
var classNames = ["form-check-input"]
|
62
|
+
|
63
|
+
if (this.props.className)
|
64
|
+
classNames.push(this.props.className)
|
65
|
+
|
66
|
+
return classNames.join(" ")
|
67
|
+
}
|
68
|
+
|
69
|
+
generatedId() {
|
70
|
+
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15)
|
71
|
+
}
|
72
|
+
|
73
|
+
inputDefaultChecked() {
|
74
|
+
if ("defaultChecked" in this.props) {
|
75
|
+
return this.props.defaultChecked
|
76
|
+
} else if (this.props.model) {
|
77
|
+
if (!this.props.model[this.props.attribute])
|
78
|
+
throw new Error(`No such attribute: ${this.props.attribute}`)
|
79
|
+
|
80
|
+
return this.props.model[this.props.attribute]()
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
inputId() {
|
85
|
+
if (this.props.id) {
|
86
|
+
return this.props.id
|
87
|
+
} else if (this.props.model) {
|
88
|
+
return `${this.props.model.modelClassData().paramKey}_${inflection.underscore(this.props.attribute)}`
|
89
|
+
} else {
|
90
|
+
return this.generatedId()
|
91
|
+
}
|
92
|
+
}
|
93
|
+
|
94
|
+
inputName() {
|
95
|
+
if (this.props.name) {
|
96
|
+
return this.props.name
|
97
|
+
} else if (this.props.model) {
|
98
|
+
return `${this.props.model.modelClassData().paramKey}[${inflection.underscore(this.props.attribute)}]`
|
99
|
+
}
|
100
|
+
}
|
101
|
+
|
102
|
+
wrapperClassName() {
|
103
|
+
let classNames = ["component-bootstrap-checkbox"]
|
104
|
+
|
105
|
+
if (this.props.wrapperClassName)
|
106
|
+
classNames.push(this.props.wrapperClassName)
|
107
|
+
|
108
|
+
return classNames.join(" ")
|
109
|
+
}
|
110
|
+
|
111
|
+
label() {
|
112
|
+
if (this.props.label) {
|
113
|
+
return this.props.label
|
114
|
+
} else if (this.props.model) {
|
115
|
+
return this.props.model.modelClass().humanAttributeName(this.props.attribute)
|
116
|
+
}
|
117
|
+
}
|
118
|
+
|
119
|
+
labelClassName() {
|
120
|
+
let classNames = ["form-check-label"]
|
121
|
+
|
122
|
+
if (this.props.labelClassName)
|
123
|
+
classNames.push(this.props.labelClassName)
|
124
|
+
|
125
|
+
return classNames.join(" ")
|
126
|
+
}
|
127
|
+
}
|
@@ -0,0 +1,105 @@
|
|
1
|
+
import PropTypes from "prop-types"
|
2
|
+
import PropTypesExact from "prop-types-exact"
|
3
|
+
import React from "react"
|
4
|
+
|
5
|
+
const inflection = require("inflection")
|
6
|
+
|
7
|
+
export default class BootstrapCheckboxes extends React.Component {
|
8
|
+
static propTypes = PropTypesExact({
|
9
|
+
attribute: PropTypes.string,
|
10
|
+
defaultValue: PropTypes.array,
|
11
|
+
label: PropTypes.string,
|
12
|
+
labelClassName: PropTypes.string,
|
13
|
+
model: PropTypes.object,
|
14
|
+
name: PropTypes.string,
|
15
|
+
options: PropTypes.array.isRequired
|
16
|
+
})
|
17
|
+
|
18
|
+
render() {
|
19
|
+
return (
|
20
|
+
<div className="component-bootstrap-checkboxes form-group">
|
21
|
+
<label className={this.labelClassName()}>
|
22
|
+
{this.label()}
|
23
|
+
</label>
|
24
|
+
|
25
|
+
<input name={this.inputName()} type="hidden" value="" />
|
26
|
+
{this.props.options.map((option, index) => this.optionElement(option, index))}
|
27
|
+
</div>
|
28
|
+
)
|
29
|
+
}
|
30
|
+
|
31
|
+
inputDefaultValue() {
|
32
|
+
if (this.props.defaultValue) {
|
33
|
+
return this.props.defaultValue
|
34
|
+
} else if (this.props.model) {
|
35
|
+
if (!this.props.model[this.props.attribute])
|
36
|
+
throw `No such attribute: ${this.props.attribute}`
|
37
|
+
|
38
|
+
return this.props.model[this.props.attribute]()
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
inputName() {
|
43
|
+
if (this.props.name) {
|
44
|
+
return `${this.props.name}[]`
|
45
|
+
} else if (this.props.model) {
|
46
|
+
return `${this.props.model.modelClassData().paramKey}[${inflection.underscore(this.props.attribute)}]`
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
isDefaultSelected(option) {
|
51
|
+
let defaultValue = this.inputDefaultValue()
|
52
|
+
|
53
|
+
if (!defaultValue)
|
54
|
+
return false
|
55
|
+
|
56
|
+
if (defaultValue.constructor === Array) {
|
57
|
+
return defaultValue.includes(option)
|
58
|
+
} else {
|
59
|
+
return defaultValue == option
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
label() {
|
64
|
+
if (this.props.label === false) {
|
65
|
+
return null
|
66
|
+
} else if (this.props.label) {
|
67
|
+
return this.props.label
|
68
|
+
} else if (this.props.model) {
|
69
|
+
return this.props.model.modelClass().humanAttributeName(this.props.attribute)
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
labelClassName() {
|
74
|
+
let classNames = []
|
75
|
+
|
76
|
+
if (this.props.labelClassName)
|
77
|
+
classNames.push(this.props.labelClassName)
|
78
|
+
|
79
|
+
return classNames.join(" ")
|
80
|
+
}
|
81
|
+
|
82
|
+
generatedId() {
|
83
|
+
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15)
|
84
|
+
}
|
85
|
+
|
86
|
+
optionElement(option) {
|
87
|
+
var id = this.generatedId()
|
88
|
+
|
89
|
+
return (
|
90
|
+
<div className="checkboxes-option" key={`option-${option[1]}`}>
|
91
|
+
<input
|
92
|
+
data-option-value={option[1]}
|
93
|
+
defaultChecked={this.isDefaultSelected(option[1])}
|
94
|
+
id={id}
|
95
|
+
name={this.inputName()}
|
96
|
+
type="checkbox"
|
97
|
+
value={option[1]} />
|
98
|
+
|
99
|
+
<label className="ml-1" htmlFor={id}>
|
100
|
+
{option[0]}
|
101
|
+
</label>
|
102
|
+
</div>
|
103
|
+
)
|
104
|
+
}
|
105
|
+
}
|
@@ -0,0 +1,168 @@
|
|
1
|
+
import Collection from "api-maker/collection"
|
2
|
+
import EventCreated from "api-maker/event-created"
|
3
|
+
import EventDestroyed from "api-maker/event-destroyed"
|
4
|
+
import Paginate from "api-maker/paginate"
|
5
|
+
import Params from "api-maker/params"
|
6
|
+
|
7
|
+
const inflection = require("inflection")
|
8
|
+
|
9
|
+
export default class LiveTable extends React.Component {
|
10
|
+
static defaultProps = {
|
11
|
+
preloads: [],
|
12
|
+
select: {}
|
13
|
+
}
|
14
|
+
|
15
|
+
static propTypes = PropTypesExact({
|
16
|
+
className: PropTypes.string,
|
17
|
+
collection: PropTypes.instanceOf(Collection),
|
18
|
+
columnsContent: PropTypes.func.isRequired,
|
19
|
+
defaultParams: PropTypes.object,
|
20
|
+
destroyMessage: PropTypes.string,
|
21
|
+
filterContent: PropTypes.func,
|
22
|
+
filterSubmitLabel: PropTypes.node,
|
23
|
+
headersContent: PropTypes.func.isRequired,
|
24
|
+
modelClass: PropTypes.func.isRequired,
|
25
|
+
preloads: PropTypes.array.isRequired,
|
26
|
+
queryName: PropTypes.string.isRequired,
|
27
|
+
select: PropTypes.object
|
28
|
+
})
|
29
|
+
|
30
|
+
constructor(props) {
|
31
|
+
super(props)
|
32
|
+
this.state = {
|
33
|
+
currentHref: location.href,
|
34
|
+
queryQName: `${this.props.queryName}_q`,
|
35
|
+
queryPageName: `${this.props.queryName}_page`
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
componentDidMount() {
|
40
|
+
this.loadQParams().then(() => this.loadModels())
|
41
|
+
}
|
42
|
+
|
43
|
+
componentDidUpdate() {
|
44
|
+
if (this.state.currentHref != location.href) {
|
45
|
+
var { queryQName } = this.state
|
46
|
+
var params = Params.parse()
|
47
|
+
var qParams = params[queryQName] || {}
|
48
|
+
Params.setCachedParams(queryQName, qParams)
|
49
|
+
this.setState({currentHref: location.href, qParams}, () => this.loadModels())
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
async loadQParams() {
|
54
|
+
var { queryQName } = this.state
|
55
|
+
var qParams = await Params.getCachedParams(queryQName, {default: this.props.defaultParams || {}})
|
56
|
+
return this.setState({qParams})
|
57
|
+
}
|
58
|
+
|
59
|
+
async loadModels() {
|
60
|
+
var params = Params.parse()
|
61
|
+
var { modelClass, preloads, select } = this.props
|
62
|
+
var { qParams, queryPageName, queryQName } = this.state
|
63
|
+
var query
|
64
|
+
|
65
|
+
if (this.props.collection) {
|
66
|
+
query = this.props.collection
|
67
|
+
} else {
|
68
|
+
query = modelClass
|
69
|
+
}
|
70
|
+
|
71
|
+
query = query
|
72
|
+
.ransack(qParams)
|
73
|
+
.searchKey(queryQName)
|
74
|
+
.page(params[queryPageName])
|
75
|
+
.pageKey(queryPageName)
|
76
|
+
.preload(preloads)
|
77
|
+
.select(select)
|
78
|
+
|
79
|
+
var result = await query.result()
|
80
|
+
|
81
|
+
this.setState({query, result, models: result.models()})
|
82
|
+
}
|
83
|
+
|
84
|
+
render() {
|
85
|
+
var { qParams, query, result, models } = this.state
|
86
|
+
|
87
|
+
return (
|
88
|
+
<div className={this.className()}>
|
89
|
+
{qParams && query && result && models && this.content()}
|
90
|
+
</div>
|
91
|
+
)
|
92
|
+
}
|
93
|
+
|
94
|
+
content() {
|
95
|
+
var { filterContent, filterSubmitLabel, modelClass } = this.props
|
96
|
+
var { qParams, query, result, models } = this.state
|
97
|
+
|
98
|
+
return (
|
99
|
+
<div className="content-container">
|
100
|
+
<EventCreated modelClass={modelClass} onCreated={() => this.onModelCreated()} />
|
101
|
+
|
102
|
+
{filterContent &&
|
103
|
+
<Card className="mb-4">
|
104
|
+
<form onSubmit={(e) => this.onFilterFormSubmit(e)} ref="filterForm">
|
105
|
+
{filterContent({qParams})}
|
106
|
+
<input className="btn btn-primary" label={filterSubmitLabel} type="submit" />
|
107
|
+
</form>
|
108
|
+
</Card>
|
109
|
+
}
|
110
|
+
|
111
|
+
{models.map(model =>
|
112
|
+
<EventDestroyed key={`event-destroyed-${model.cacheKey()}`} model={model} onDestroyed={(args) => this.onModelDestroyed(args)} />
|
113
|
+
)}
|
114
|
+
|
115
|
+
<Card className="mb-4" striped table>
|
116
|
+
<thead>
|
117
|
+
<tr>
|
118
|
+
{this.props.headersContent({query})}
|
119
|
+
</tr>
|
120
|
+
</thead>
|
121
|
+
<tbody>
|
122
|
+
{models.map(model =>
|
123
|
+
<tr className={`${inflection.singularize(modelClass.modelClassData().collectionName)}-row`} data-model-id={model.id()} key={model.cacheKey()}>
|
124
|
+
{this.props.columnsContent({model})}
|
125
|
+
</tr>
|
126
|
+
)}
|
127
|
+
</tbody>
|
128
|
+
</Card>
|
129
|
+
|
130
|
+
<Paginate result={result} />
|
131
|
+
</div>
|
132
|
+
)
|
133
|
+
}
|
134
|
+
|
135
|
+
className() {
|
136
|
+
var classNames = ["component-api-maker-live-table"]
|
137
|
+
|
138
|
+
if (this.props.className)
|
139
|
+
classNames.push(this.props.className)
|
140
|
+
|
141
|
+
return classNames.join(" ")
|
142
|
+
}
|
143
|
+
|
144
|
+
onFilterFormSubmit(e) {
|
145
|
+
e.preventDefault()
|
146
|
+
|
147
|
+
var qParams = Params.serializeForm(this.refs.filterForm)
|
148
|
+
var { queryQName } = this.state
|
149
|
+
|
150
|
+
var changeParamsParams = {}
|
151
|
+
changeParamsParams[queryQName] = qParams
|
152
|
+
|
153
|
+
Params.changeParams(changeParamsParams)
|
154
|
+
Params.setCachedParams(queryQName, qParams)
|
155
|
+
|
156
|
+
this.setState({currentHref: location.href, qParams}, () => this.loadModels())
|
157
|
+
}
|
158
|
+
|
159
|
+
onModelCreated() {
|
160
|
+
this.loadModels()
|
161
|
+
}
|
162
|
+
|
163
|
+
onModelDestroyed(args) {
|
164
|
+
this.setState({
|
165
|
+
models: this.state.models.filter(model => model.id() != args.model.id())
|
166
|
+
})
|
167
|
+
}
|
168
|
+
}
|