@kaspernj/api-maker 1.0.377 → 1.0.379
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/base-component.jsx +8 -0
- package/src/bootstrap/attribute-row/index.jsx +6 -2
- package/src/super-admin/index-page.jsx +16 -14
- package/src/super-admin/index.jsx +124 -105
- package/src/super-admin/model-class-table.jsx +42 -43
- package/src/super-admin/show-nav.jsx +27 -26
- package/src/super-admin/show-page/index.jsx +101 -82
- package/src/super-admin/show-reflection-link.jsx +33 -0
package/package.json
CHANGED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import fetchingObject from "fetching-object"
|
|
2
|
+
import {ShapeComponent} from "set-state-compare/src/shape-component"
|
|
3
|
+
|
|
4
|
+
export default class BaseComponent extends ShapeComponent {
|
|
5
|
+
p = fetchingObject(() => this.props)
|
|
6
|
+
s = fetchingObject(() => this.shape || this.state)
|
|
7
|
+
tt = fetchingObject(this)
|
|
8
|
+
}
|
|
@@ -17,14 +17,18 @@ export default memo(shapeComponent(class ApiMakerBootstrapAttributeRow extends S
|
|
|
17
17
|
checkIfAttributeLoaded: PropTypes.bool.isRequired,
|
|
18
18
|
children: PropTypes.node,
|
|
19
19
|
identifier: PropTypes.string,
|
|
20
|
-
label: PropTypes.node,
|
|
20
|
+
label: PropTypes.oneOfType([PropTypes.node, PropTypes.string]),
|
|
21
21
|
model: PropTypes.object,
|
|
22
22
|
value: PropTypes.node
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
setup() {
|
|
26
26
|
this.attribute = useMemo(
|
|
27
|
-
() =>
|
|
27
|
+
() => {
|
|
28
|
+
if (this.props.attribute) {
|
|
29
|
+
return this.props.model?.constructor?.attributes()?.find((attribute) => attribute.name() == inflection.underscore(this.props.attribute))
|
|
30
|
+
}
|
|
31
|
+
},
|
|
28
32
|
[this.props.attribute, this.props.model]
|
|
29
33
|
)
|
|
30
34
|
}
|
|
@@ -1,19 +1,21 @@
|
|
|
1
|
+
import BaseComponent from "../base-component"
|
|
2
|
+
import {memo} from "react"
|
|
1
3
|
import ModelClassTable from "./model-class-table"
|
|
2
4
|
import PropTypes from "prop-types"
|
|
3
|
-
import {
|
|
5
|
+
import {shapeComponent} from "set-state-compare/src/shape-component.js"
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
modelClass={modelClass}
|
|
10
|
-
/>
|
|
11
|
-
</div>
|
|
12
|
-
)
|
|
13
|
-
}
|
|
7
|
+
export default memo(shapeComponent(class ApiMakerSuperAdminIndexPage extends BaseComponent {
|
|
8
|
+
static propTypes = {
|
|
9
|
+
modelClass: PropTypes.func.isRequired
|
|
10
|
+
}
|
|
14
11
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
12
|
+
render() {
|
|
13
|
+
const {modelClass} = this.props
|
|
18
14
|
|
|
19
|
-
|
|
15
|
+
return (
|
|
16
|
+
<div className="super-admin--index-page">
|
|
17
|
+
<ModelClassTable modelClass={modelClass} />
|
|
18
|
+
</div>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
}))
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import BaseComponent from "../base-component"
|
|
1
2
|
import EditPage from "./edit-page"
|
|
2
3
|
import hasEditConfig from "./has-edit-config.js"
|
|
3
4
|
import IndexPage from "./index-page"
|
|
@@ -5,36 +6,52 @@ import Layout from "./layout"
|
|
|
5
6
|
import Link from "../link"
|
|
6
7
|
import {memo, useMemo} from "react"
|
|
7
8
|
import * as modelsModule from "@kaspernj/api-maker/src/models.mjs.erb"
|
|
8
|
-
import {
|
|
9
|
+
import {shapeComponent} from "set-state-compare/src/shape-component.js"
|
|
9
10
|
import ShowPage from "./show-page"
|
|
10
11
|
import ShowReflectionActions from "./show-reflection-actions"
|
|
11
12
|
import ShowReflectionPage from "./show-reflection-page"
|
|
13
|
+
import {useEffect} from "react"
|
|
12
14
|
import useCanCan from "../use-can-can"
|
|
13
15
|
import useCurrentUser from "../use-current-user.mjs"
|
|
14
16
|
import useQueryParams from "on-location-changed/src/use-query-params"
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
let modelClass, pageToShow
|
|
18
|
+
export default memo(shapeComponent(class ApiMakerSuperAdmin extends BaseComponent {
|
|
19
|
+
setup() {
|
|
20
|
+
this.queryParams = useQueryParams()
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
if (this.queryParams.model) {
|
|
23
|
+
this.modelClass = modelsModule[this.queryParams.model]
|
|
24
|
+
} else {
|
|
25
|
+
this.modelClass = null
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
this.modelId = this.queryParams.model_id
|
|
29
|
+
this.modelName = this.modelClass?.modelClassData()?.name
|
|
30
|
+
this.currentUser = useCurrentUser()
|
|
22
31
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const canCan = useCanCan(
|
|
27
|
-
() => {
|
|
28
|
-
const abilities = []
|
|
32
|
+
this.canCan = useCanCan(
|
|
33
|
+
() => {
|
|
34
|
+
const abilities = []
|
|
29
35
|
|
|
30
|
-
|
|
36
|
+
if (this.modelClass) abilities.push([this.modelClass, ["new"]])
|
|
37
|
+
|
|
38
|
+
return abilities
|
|
39
|
+
},
|
|
40
|
+
[this.currentUser?.id(), this.modelClass]
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
this.useStates({
|
|
44
|
+
model: undefined
|
|
45
|
+
})
|
|
46
|
+
useEffect(
|
|
47
|
+
() => { this.loadModel() },
|
|
48
|
+
[this.modelId]
|
|
49
|
+
)
|
|
50
|
+
}
|
|
31
51
|
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
[currentUser?.id(), modelClass]
|
|
35
|
-
)
|
|
52
|
+
loadModel = async () => {
|
|
53
|
+
const {modelClass, modelId, modelName} = this.tt
|
|
36
54
|
|
|
37
|
-
const loadModel = useCallback(async () => {
|
|
38
55
|
if (modelId && modelClass) {
|
|
39
56
|
const abilities = {}
|
|
40
57
|
const abilitiesForModel = ["destroy", "edit"]
|
|
@@ -46,29 +63,96 @@ const ApiMakerSuperAdmin = () => {
|
|
|
46
63
|
.abilities(abilities)
|
|
47
64
|
.first()
|
|
48
65
|
|
|
49
|
-
|
|
66
|
+
this.setState({model})
|
|
50
67
|
} else {
|
|
51
|
-
|
|
68
|
+
this.setState({model: undefined})
|
|
52
69
|
}
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
useEffect(() => { loadModel() }, [modelId])
|
|
56
|
-
|
|
57
|
-
if (queryParams.model && queryParams.model_id && queryParams.model_reflection) {
|
|
58
|
-
pageToShow = "show_reflection"
|
|
59
|
-
} else if (queryParams.model && queryParams.model_id && queryParams.mode == "edit") {
|
|
60
|
-
pageToShow = "edit"
|
|
61
|
-
} else if (queryParams.model && queryParams.model_id) {
|
|
62
|
-
pageToShow = "show"
|
|
63
|
-
} else if (queryParams.model && queryParams.mode == "new") {
|
|
64
|
-
pageToShow = "edit"
|
|
65
|
-
} else if (queryParams.model) {
|
|
66
|
-
pageToShow = "index"
|
|
67
|
-
} else {
|
|
68
|
-
pageToShow = "welcome"
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
|
|
72
|
+
render() {
|
|
73
|
+
const {canCan, modelClass, modelId, modelName, queryParams} = this.tt
|
|
74
|
+
const {model} = this.s
|
|
75
|
+
let pageToShow
|
|
76
|
+
|
|
77
|
+
if (queryParams.model && queryParams.model_id && queryParams.model_reflection) {
|
|
78
|
+
pageToShow = "show_reflection"
|
|
79
|
+
} else if (queryParams.model && queryParams.model_id && queryParams.mode == "edit") {
|
|
80
|
+
pageToShow = "edit"
|
|
81
|
+
} else if (queryParams.model && queryParams.model_id) {
|
|
82
|
+
pageToShow = "show"
|
|
83
|
+
} else if (queryParams.model && queryParams.mode == "new") {
|
|
84
|
+
pageToShow = "edit"
|
|
85
|
+
} else if (queryParams.model) {
|
|
86
|
+
pageToShow = "index"
|
|
87
|
+
} else {
|
|
88
|
+
pageToShow = "welcome"
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const actions = useMemo(
|
|
92
|
+
() => <>
|
|
93
|
+
{modelClass && pageToShow == "index" &&
|
|
94
|
+
<>
|
|
95
|
+
{canCan?.can("new", modelClass) && hasEditConfig(modelClass) &&
|
|
96
|
+
<Link className="create-new-model-link" to={Params.withParams({model: modelName, mode: "new"})}>
|
|
97
|
+
Create new
|
|
98
|
+
</Link>
|
|
99
|
+
}
|
|
100
|
+
</>
|
|
101
|
+
}
|
|
102
|
+
{model && pageToShow == "show" &&
|
|
103
|
+
<>
|
|
104
|
+
{model.can("edit") && hasEditConfig(modelClass) &&
|
|
105
|
+
<Link className="edit-model-link" to={Params.withParams({model: modelName, model_id: modelId, mode: "edit"})}>
|
|
106
|
+
Edit
|
|
107
|
+
</Link>
|
|
108
|
+
}
|
|
109
|
+
{model.can("destroy") &&
|
|
110
|
+
<a className="destroy-model-link" href="#" onClick={this.tt.onDestroyClicked}>
|
|
111
|
+
Delete
|
|
112
|
+
</a>
|
|
113
|
+
}
|
|
114
|
+
</>
|
|
115
|
+
}
|
|
116
|
+
{pageToShow == "show_reflection" &&
|
|
117
|
+
<ShowReflectionActions model={model} modelClass={modelClass} reflectionName={queryParams.model_reflection} />
|
|
118
|
+
}
|
|
119
|
+
</>,
|
|
120
|
+
[canCan, model, modelClass, pageToShow]
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<Layout actions={actions} active={queryParams.model} headerTitle={modelClass?.modelName()?.human({count: 2})}>
|
|
125
|
+
{pageToShow == "index" &&
|
|
126
|
+
<IndexPage
|
|
127
|
+
key={`index-page-${modelName}`}
|
|
128
|
+
modelClass={modelClass}
|
|
129
|
+
/>
|
|
130
|
+
}
|
|
131
|
+
{pageToShow == "show" &&
|
|
132
|
+
<ShowPage
|
|
133
|
+
key={`show-page-${modelName}-${modelId}`}
|
|
134
|
+
modelClass={modelClass}
|
|
135
|
+
modelId={modelId}
|
|
136
|
+
/>
|
|
137
|
+
}
|
|
138
|
+
{pageToShow == "show_reflection" &&
|
|
139
|
+
<ShowReflectionPage
|
|
140
|
+
key={`show-reflection-page-${modelName}-${modelId}`}
|
|
141
|
+
modelClass={modelClass}
|
|
142
|
+
modelId={modelId}
|
|
143
|
+
/>
|
|
144
|
+
}
|
|
145
|
+
{pageToShow == "edit" &&
|
|
146
|
+
<EditPage
|
|
147
|
+
key={`edit-page-${modelName}-${modelId}`}
|
|
148
|
+
modelClass={modelClass}
|
|
149
|
+
/>
|
|
150
|
+
}
|
|
151
|
+
</Layout>
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
onDestroyClicked = async (e) => {
|
|
72
156
|
e.preventDefault()
|
|
73
157
|
|
|
74
158
|
if (!confirm("Are you sure?")) {
|
|
@@ -76,76 +160,11 @@ const ApiMakerSuperAdmin = () => {
|
|
|
76
160
|
}
|
|
77
161
|
|
|
78
162
|
try {
|
|
79
|
-
await model.destroy()
|
|
163
|
+
await this.s.model.destroy()
|
|
80
164
|
|
|
81
165
|
Params.changeParams({mode: undefined, model_id: undefined})
|
|
82
166
|
} catch (error) {
|
|
83
167
|
FlashMessage.errorResponse(error)
|
|
84
168
|
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const actions = useMemo(
|
|
88
|
-
() => <>
|
|
89
|
-
{modelClass && pageToShow == "index" &&
|
|
90
|
-
<>
|
|
91
|
-
{canCan?.can("new", modelClass) && hasEditConfig(modelClass) &&
|
|
92
|
-
<Link className="create-new-model-link" to={Params.withParams({model: modelName, mode: "new"})}>
|
|
93
|
-
Create new
|
|
94
|
-
</Link>
|
|
95
|
-
}
|
|
96
|
-
</>
|
|
97
|
-
}
|
|
98
|
-
{model && pageToShow == "show" &&
|
|
99
|
-
<>
|
|
100
|
-
{model.can("edit") && hasEditConfig(modelClass) &&
|
|
101
|
-
<Link className="edit-model-link" to={Params.withParams({model: modelName, model_id: modelId, mode: "edit"})}>
|
|
102
|
-
Edit
|
|
103
|
-
</Link>
|
|
104
|
-
}
|
|
105
|
-
{model.can("destroy") &&
|
|
106
|
-
<a className="destroy-model-link" href="#" onClick={onDestroyClicked}>
|
|
107
|
-
Delete
|
|
108
|
-
</a>
|
|
109
|
-
}
|
|
110
|
-
</>
|
|
111
|
-
}
|
|
112
|
-
{pageToShow == "show_reflection" &&
|
|
113
|
-
<ShowReflectionActions model={model} modelClass={modelClass} reflectionName={queryParams.model_reflection} />
|
|
114
|
-
}
|
|
115
|
-
</>,
|
|
116
|
-
[canCan, model, modelClass, pageToShow]
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
return (
|
|
120
|
-
<Layout actions={actions} active={queryParams.model} headerTitle={modelClass?.modelName()?.human({count: 2})}>
|
|
121
|
-
{pageToShow == "index" &&
|
|
122
|
-
<IndexPage
|
|
123
|
-
key={`index-page-${modelName}`}
|
|
124
|
-
modelClass={modelClass}
|
|
125
|
-
/>
|
|
126
|
-
}
|
|
127
|
-
{pageToShow == "show" &&
|
|
128
|
-
<ShowPage
|
|
129
|
-
key={`show-page-${modelName}-${modelId}`}
|
|
130
|
-
modelClass={modelClass}
|
|
131
|
-
modelId={modelId}
|
|
132
|
-
/>
|
|
133
|
-
}
|
|
134
|
-
{pageToShow == "show_reflection" &&
|
|
135
|
-
<ShowReflectionPage
|
|
136
|
-
key={`show-reflection-page-${modelName}-${modelId}`}
|
|
137
|
-
modelClass={modelClass}
|
|
138
|
-
modelId={modelId}
|
|
139
|
-
/>
|
|
140
|
-
}
|
|
141
|
-
{pageToShow == "edit" &&
|
|
142
|
-
<EditPage
|
|
143
|
-
key={`edit-page-${modelName}-${modelId}`}
|
|
144
|
-
modelClass={modelClass}
|
|
145
|
-
/>
|
|
146
|
-
}
|
|
147
|
-
</Layout>
|
|
148
|
-
)
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export default memo(ApiMakerSuperAdmin)
|
|
169
|
+
}
|
|
170
|
+
}))
|
|
@@ -1,63 +1,62 @@
|
|
|
1
|
+
import BaseComponent from "../base-component"
|
|
1
2
|
import ConfigReader from "./config-reader.jsx"
|
|
2
3
|
import {digg} from "diggerize"
|
|
3
4
|
import hasEditConfig from "./has-edit-config.js"
|
|
4
5
|
import * as inflection from "inflection"
|
|
5
6
|
import Params from "../params"
|
|
6
7
|
import PropTypes from "prop-types"
|
|
7
|
-
import {memo,
|
|
8
|
+
import {memo, useMemo} from "react"
|
|
9
|
+
import {shapeComponent} from "set-state-compare/src/shape-component.js"
|
|
8
10
|
import Table from "../table/table"
|
|
9
11
|
import useCurrentUser from "../use-current-user"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const
|
|
12
|
+
|
|
13
|
+
export default memo(shapeComponent(class ApiMakerSuperAdminModelClassTable extends BaseComponent {
|
|
14
|
+
static propTypes = {
|
|
15
|
+
modelClass: PropTypes.func.isRequired
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
render() {
|
|
19
|
+
const {modelClass, ...restProps} = this.props
|
|
20
|
+
const currentUser = useCurrentUser()
|
|
21
|
+
const configReader = useMemo(() => ConfigReader.forModel(modelClass), [modelClass])
|
|
22
|
+
const columns = useMemo(() => configReader.tableColumns(), [modelClass])
|
|
23
|
+
const tableConfig = configReader.modelConfig?.table
|
|
24
|
+
const tableProps = {}
|
|
25
|
+
|
|
26
|
+
if (tableConfig?.query) tableProps.collection = tableConfig.query
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<Table
|
|
30
|
+
columns={columns}
|
|
31
|
+
currentUser={currentUser}
|
|
32
|
+
editModelPath={hasEditConfig(modelClass) ? this.tt.editModelPath : undefined}
|
|
33
|
+
modelClass={modelClass}
|
|
34
|
+
viewModelPath={this.tt.viewModelPath}
|
|
35
|
+
workplace
|
|
36
|
+
{...tableProps}
|
|
37
|
+
{...restProps}
|
|
38
|
+
/>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
editModelPath = (args) => {
|
|
43
|
+
const argName = inflection.camelize(digg(this.p.modelClass.modelClassData(), "name"), true)
|
|
22
44
|
const model = digg(args, argName)
|
|
23
45
|
|
|
24
46
|
return Params.withParams({
|
|
25
|
-
model:
|
|
47
|
+
model: this.p.modelClass.modelClassData().name,
|
|
26
48
|
model_id: model.primaryKey(),
|
|
27
49
|
mode: "edit"
|
|
28
50
|
})
|
|
29
|
-
}
|
|
51
|
+
}
|
|
30
52
|
|
|
31
|
-
|
|
32
|
-
const argName = inflection.camelize(digg(
|
|
53
|
+
viewModelPath = (args) => {
|
|
54
|
+
const argName = inflection.camelize(digg(this.p.modelClass.modelClassData(), "name"), true)
|
|
33
55
|
const model = digg(args, argName)
|
|
34
56
|
|
|
35
57
|
return Params.withParams({
|
|
36
|
-
model:
|
|
58
|
+
model: this.p.modelClass.modelClassData().name,
|
|
37
59
|
model_id: model.primaryKey()
|
|
38
60
|
})
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const tableProps = {}
|
|
42
|
-
|
|
43
|
-
if (tableConfig?.query) tableProps.collection = tableConfig.query
|
|
44
|
-
|
|
45
|
-
return (
|
|
46
|
-
<Table
|
|
47
|
-
columns={columns}
|
|
48
|
-
currentUser={currentUser}
|
|
49
|
-
editModelPath={hasEditConfig(modelClass) ? editModelPath : undefined}
|
|
50
|
-
modelClass={modelClass}
|
|
51
|
-
viewModelPath={viewModelPath}
|
|
52
|
-
workplace
|
|
53
|
-
{...tableProps}
|
|
54
|
-
{...restProps}
|
|
55
|
-
/>
|
|
56
|
-
)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
ApiMakerSuperAdminModelClassTable.propTypes = {
|
|
60
|
-
modelClass: PropTypes.func.isRequired
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export default memo(ApiMakerSuperAdminModelClassTable)
|
|
61
|
+
}
|
|
62
|
+
}))
|
|
@@ -1,35 +1,36 @@
|
|
|
1
|
-
import
|
|
1
|
+
import BaseComponent from "../base-component"
|
|
2
2
|
import Link from "../link"
|
|
3
3
|
import PropTypes from "prop-types"
|
|
4
4
|
import PropTypesExact from "prop-types-exact"
|
|
5
|
-
import
|
|
5
|
+
import {memo} from "react"
|
|
6
|
+
import {shapeComponent} from "set-state-compare/src/shape-component.js"
|
|
7
|
+
import ShowReflectionLink from "./show-reflection-link"
|
|
6
8
|
import useQueryParams from "on-location-changed/src/use-query-params"
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
export default memo(shapeComponent(class ApiMakerSuperAdminShowNav extends BaseComponent {
|
|
11
|
+
static propTypes = PropTypesExact({
|
|
12
|
+
model: PropTypes.object.isRequired,
|
|
13
|
+
modelClass: PropTypes.func.isRequired
|
|
14
|
+
})
|
|
11
15
|
|
|
12
|
-
|
|
13
|
-
|
|
16
|
+
render() {
|
|
17
|
+
const {model, modelClass} = this.props
|
|
18
|
+
const queryParams = useQueryParams()
|
|
19
|
+
const reflections = modelClass.reflections()
|
|
20
|
+
|
|
21
|
+
return (
|
|
14
22
|
<div>
|
|
15
|
-
<
|
|
16
|
-
{
|
|
17
|
-
|
|
18
|
-
</div>
|
|
19
|
-
{model && reflections.filter((reflection) => reflection.macro() == "has_many").map((reflection) =>
|
|
20
|
-
<div key={reflection.name()}>
|
|
21
|
-
<Link to={Params.withParams({model: digg(modelClass.modelClassData(), "name"), model_id: model.primaryKey(), model_reflection: reflection.name()})}>
|
|
22
|
-
{modelClass.humanAttributeName(reflection.name())}
|
|
23
|
+
<div>
|
|
24
|
+
<Link to={Params.withParams({model: modelClass.modelClassData().name, model_id: queryParams.model_id})}>
|
|
25
|
+
{I18n.t("js.api_maker.suprt_admin.show_reflection_page.general", {defaultValue: "General"})}
|
|
23
26
|
</Link>
|
|
24
27
|
</div>
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
export default React.memo(ApiMakerSuperAdminShowNav)
|
|
28
|
+
{model && reflections.filter((reflection) => reflection.macro() == "has_many").map((reflection) =>
|
|
29
|
+
<div key={reflection.name()}>
|
|
30
|
+
<ShowReflectionLink model={model} modelClass={modelClass} reflection={reflection} />
|
|
31
|
+
</div>
|
|
32
|
+
)}
|
|
33
|
+
</div>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
}))
|
|
@@ -1,110 +1,129 @@
|
|
|
1
1
|
import AttributeRow from "../../bootstrap/attribute-row"
|
|
2
|
+
import BaseComponent from "../../base-component"
|
|
2
3
|
import BelongsToAttributeRow from "./belongs-to-attribute-row"
|
|
3
4
|
import ConfigReader from "../config-reader.jsx"
|
|
4
5
|
import {digg} from "diggerize"
|
|
5
6
|
import * as inflection from "inflection"
|
|
6
7
|
import PropTypes from "prop-types"
|
|
7
|
-
import {memo} from "react"
|
|
8
|
+
import {memo, useMemo} from "react"
|
|
9
|
+
import {shapeComponent} from "set-state-compare/src/shape-component.js"
|
|
8
10
|
import ShowNav from "../show-nav"
|
|
9
11
|
import useModel from "../../use-model"
|
|
10
12
|
|
|
11
|
-
const AttributePresenter = ({attribute, model, modelArgs}) => {
|
|
12
|
-
const attributeRowProps = {
|
|
13
|
+
const AttributePresenter = memo(({attribute, model, modelArgs}) => {
|
|
14
|
+
const attributeRowProps = {
|
|
15
|
+
model
|
|
16
|
+
}
|
|
13
17
|
|
|
14
18
|
if (typeof attribute == "object") {
|
|
15
|
-
attributeRowProps.attribute = attribute.attribute
|
|
19
|
+
if (attribute.attribute) attributeRowProps.attribute = attribute.attribute
|
|
16
20
|
if (attribute.content) attributeRowProps.children = attribute.content(modelArgs)
|
|
17
|
-
|
|
21
|
+
if (attribute.label) attributeRowProps.label = attribute.label
|
|
22
|
+
} else if (attribute) {
|
|
18
23
|
attributeRowProps.attribute = attribute
|
|
19
24
|
}
|
|
20
25
|
|
|
21
26
|
return (
|
|
22
|
-
<AttributeRow
|
|
27
|
+
<AttributeRow {...attributeRowProps} />
|
|
23
28
|
)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const ApiMakerSuperAdminShowPage = ({modelClass}) => {
|
|
27
|
-
const configReader = ConfigReader.forModel(modelClass)
|
|
28
|
-
const showConfig = configReader.modelConfig?.show
|
|
29
|
-
const attributes = configReader.attributesToShow()
|
|
30
|
-
const extraContent = showConfig?.extraContent
|
|
31
|
-
const modelClassName = modelClass.modelClassData().name
|
|
32
|
-
const primaryKeyName = modelClass.primaryKey()
|
|
33
|
-
const preload = []
|
|
34
|
-
const select = showConfig?.extraSelect || {}
|
|
35
|
-
const modelClassSelect = select[modelClassName] || []
|
|
36
|
-
|
|
37
|
-
if (!(modelClassName in select)) select[modelClassName] = modelClassSelect
|
|
38
|
-
if (!modelClassSelect.includes(primaryKeyName)) modelClassSelect.push(primaryKeyName)
|
|
39
|
-
|
|
40
|
-
// Select all attributes selected by default because they will be shown by default
|
|
41
|
-
for (const attribute of modelClass.attributes()) {
|
|
42
|
-
if (attribute.isSelectedByDefault() && !modelClassSelect.includes(attribute.name())) modelClassSelect.push(attribute.name())
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
for (const reflection of modelClass.reflections()) {
|
|
46
|
-
if (reflection.macro() == "belongs_to") {
|
|
47
|
-
const reflectionModelClass = reflection.modelClass()
|
|
48
|
-
const reflectionModelClassName = reflectionModelClass.modelClassData().name
|
|
49
|
-
const reflectionModelClassAttributes = reflectionModelClass.attributes()
|
|
50
|
-
const nameAttribute = reflectionModelClassAttributes.find((attribute) => attribute.name() == "name")
|
|
51
|
-
|
|
52
|
-
preload.push(inflection.underscore(reflection.name()))
|
|
29
|
+
})
|
|
53
30
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
// The foreign key is needed to look up any belongs-to-relationships
|
|
59
|
-
if (!modelClassSelect.includes(reflection.foreignKey())) modelClassSelect.push(reflection.foreignKey())
|
|
60
|
-
} else if (reflection.macro() == "has_one") {
|
|
61
|
-
const reflectionModelClass = reflection.modelClass()
|
|
62
|
-
const reflectionModelClassName = reflectionModelClass.modelClassData().name
|
|
63
|
-
const reflectionModelClassAttributes = reflectionModelClass.attributes()
|
|
64
|
-
const nameAttribute = reflectionModelClassAttributes.find((attribute) => attribute.name() == "name")
|
|
31
|
+
export default memo(shapeComponent(class ApiMakerSuperAdminShowPage extends BaseComponent {
|
|
32
|
+
static propTypes = {
|
|
33
|
+
modelClass: PropTypes.func.isRequired
|
|
34
|
+
}
|
|
65
35
|
|
|
66
|
-
|
|
36
|
+
setup() {
|
|
37
|
+
const {modelClass} = this.props
|
|
38
|
+
const configReader = useMemo(() => ConfigReader.forModel(modelClass), [modelClass])
|
|
39
|
+
const showConfig = configReader.modelConfig?.show
|
|
67
40
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (nameAttribute && !select[reflectionModelClassName].includes("name")) select[reflectionModelClassName].push("name")
|
|
41
|
+
this.setInstance({configReader, showConfig})
|
|
42
|
+
}
|
|
71
43
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
44
|
+
render() {
|
|
45
|
+
const {modelClass} = this.props
|
|
46
|
+
const {configReader, showConfig} = this.tt
|
|
47
|
+
const attributes = configReader.attributesToShow()
|
|
48
|
+
const extraContent = showConfig?.extraContent
|
|
49
|
+
const modelClassName = modelClass.modelClassData().name
|
|
50
|
+
const primaryKeyName = modelClass.primaryKey()
|
|
51
|
+
const preload = []
|
|
52
|
+
const select = showConfig?.extraSelect || {}
|
|
53
|
+
const modelClassSelect = select[modelClassName] || []
|
|
54
|
+
|
|
55
|
+
if (showConfig?.preload) {
|
|
56
|
+
for (const showConfigPreload of showConfig.preload) {
|
|
57
|
+
preload.push(showConfigPreload)
|
|
75
58
|
}
|
|
76
59
|
}
|
|
77
|
-
}
|
|
78
60
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
preload,
|
|
82
|
-
select
|
|
83
|
-
})
|
|
84
|
-
const camelizedLower = digg(modelClass.modelClassData(), "camelizedLower")
|
|
85
|
-
const model = digg(useModelResult, camelizedLower)
|
|
86
|
-
const modelArgs = {}
|
|
61
|
+
if (!(modelClassName in select)) select[modelClassName] = modelClassSelect
|
|
62
|
+
if (!modelClassSelect.includes(primaryKeyName)) modelClassSelect.push(primaryKeyName)
|
|
87
63
|
|
|
88
|
-
|
|
64
|
+
// Select all attributes selected by default because they will be shown by default
|
|
65
|
+
for (const attribute of modelClass.attributes()) {
|
|
66
|
+
if (attribute.isSelectedByDefault() && !modelClassSelect.includes(attribute.name())) modelClassSelect.push(attribute.name())
|
|
67
|
+
}
|
|
89
68
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
69
|
+
for (const reflection of modelClass.reflections()) {
|
|
70
|
+
if (reflection.macro() == "belongs_to") {
|
|
71
|
+
const reflectionModelClass = reflection.modelClass()
|
|
72
|
+
const reflectionModelClassName = reflectionModelClass.modelClassData().name
|
|
73
|
+
const reflectionModelClassAttributes = reflectionModelClass.attributes()
|
|
74
|
+
const nameAttribute = reflectionModelClassAttributes.find((attribute) => attribute.name() == "name")
|
|
75
|
+
|
|
76
|
+
preload.push(inflection.underscore(reflection.name()))
|
|
77
|
+
|
|
78
|
+
if (!(reflectionModelClassName in select)) select[reflectionModelClassName] = []
|
|
79
|
+
if (!select[reflectionModelClassName].includes("id")) select[reflectionModelClassName].push("id")
|
|
80
|
+
if (nameAttribute && !select[reflectionModelClassName].includes("name")) select[reflectionModelClassName].push("name")
|
|
81
|
+
|
|
82
|
+
// The foreign key is needed to look up any belongs-to-relationships
|
|
83
|
+
if (!modelClassSelect.includes(reflection.foreignKey())) modelClassSelect.push(reflection.foreignKey())
|
|
84
|
+
} else if (reflection.macro() == "has_one") {
|
|
85
|
+
const reflectionModelClass = reflection.modelClass()
|
|
86
|
+
const reflectionModelClassName = reflectionModelClass.modelClassData().name
|
|
87
|
+
const reflectionModelClassAttributes = reflectionModelClass.attributes()
|
|
88
|
+
const nameAttribute = reflectionModelClassAttributes.find((attribute) => attribute.name() == "name")
|
|
89
|
+
|
|
90
|
+
preload.push(inflection.underscore(reflection.name()))
|
|
91
|
+
|
|
92
|
+
if (!(reflectionModelClassName in select)) select[reflectionModelClassName] = []
|
|
93
|
+
if (!select[reflectionModelClassName].includes("id")) select[reflectionModelClassName].push("id")
|
|
94
|
+
if (nameAttribute && !select[reflectionModelClassName].includes("name")) select[reflectionModelClassName].push("name")
|
|
95
|
+
|
|
96
|
+
// The foreign key is needed to look up any has-one-relationships
|
|
97
|
+
if (!modelClassSelect.includes(reflection.foreignKey()) && !select[reflectionModelClassName].includes(reflection.foreignKey()) && !reflection.through()) {
|
|
98
|
+
select[reflectionModelClassName].push(reflection.foreignKey())
|
|
99
|
+
}
|
|
94
100
|
}
|
|
95
|
-
|
|
96
|
-
<AttributePresenter attribute={attribute} key={attribute.attribute || attribute} modelArgs={modelArgs} model={model} />
|
|
97
|
-
)}
|
|
98
|
-
{model && modelClass.reflections().filter((reflection) => reflection.macro() == "belongs_to" || reflection.macro() == "has_one").map((reflection) =>
|
|
99
|
-
<BelongsToAttributeRow key={reflection.name()} model={model} modelClass={modelClass} reflection={reflection} />
|
|
100
|
-
)}
|
|
101
|
-
{model && extraContent && extraContent(modelArgs)}
|
|
102
|
-
</div>
|
|
103
|
-
)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
ApiMakerSuperAdminShowPage.propTypes = {
|
|
107
|
-
modelClass: PropTypes.func.isRequired
|
|
108
|
-
}
|
|
101
|
+
}
|
|
109
102
|
|
|
110
|
-
|
|
103
|
+
const useModelResult = useModel(modelClass, {
|
|
104
|
+
loadByQueryParam: ({queryParams}) => queryParams.model_id,
|
|
105
|
+
preload,
|
|
106
|
+
select
|
|
107
|
+
})
|
|
108
|
+
const camelizedLower = digg(modelClass.modelClassData(), "camelizedLower")
|
|
109
|
+
const model = digg(useModelResult, camelizedLower)
|
|
110
|
+
const modelArgs = {}
|
|
111
|
+
|
|
112
|
+
modelArgs[inflection.camelize(modelClass.modelClassData().name, true)] = model
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
<div className="super-admin--show-page">
|
|
116
|
+
{model &&
|
|
117
|
+
<ShowNav model={model} modelClass={modelClass} />
|
|
118
|
+
}
|
|
119
|
+
{attributes && model && attributes.map((attribute) =>
|
|
120
|
+
<AttributePresenter attribute={attribute} key={attribute.key || attribute.attribute || attribute} modelArgs={modelArgs} model={model} />
|
|
121
|
+
)}
|
|
122
|
+
{model && modelClass.reflections().filter((reflection) => reflection.macro() == "belongs_to" || reflection.macro() == "has_one").map((reflection) =>
|
|
123
|
+
<BelongsToAttributeRow key={reflection.name()} model={model} modelClass={modelClass} reflection={reflection} />
|
|
124
|
+
)}
|
|
125
|
+
{model && extraContent && extraContent(modelArgs)}
|
|
126
|
+
</div>
|
|
127
|
+
)
|
|
128
|
+
}
|
|
129
|
+
}))
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import BaseComponent from "../base-component"
|
|
2
|
+
import {digg} from "diggerize"
|
|
3
|
+
import {shapeComponent} from "set-state-compare/src/shape-component.js"
|
|
4
|
+
import {useMemo} from "react"
|
|
5
|
+
|
|
6
|
+
export default memo(shapeComponent(class ApiMakerSuperAdminShowReflectionLink extends BaseComponent {
|
|
7
|
+
setup() {
|
|
8
|
+
this.useStates({count: undefined})
|
|
9
|
+
|
|
10
|
+
useMemo(() => {
|
|
11
|
+
this.countRelationship()
|
|
12
|
+
}, [])
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
countRelationship = async () => {
|
|
16
|
+
const {model, reflection} = this.p
|
|
17
|
+
const query = model[reflection.name()]()
|
|
18
|
+
const count = await query.ransack().count()
|
|
19
|
+
|
|
20
|
+
this.setState({count})
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
render() {
|
|
24
|
+
const {model, modelClass, reflection} = this.p
|
|
25
|
+
const {count} = this.s
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<Link to={Params.withParams({model: digg(modelClass.modelClassData(), "name"), model_id: model.primaryKey(), model_reflection: reflection.name()})}>
|
|
29
|
+
{modelClass.humanAttributeName(reflection.name())} ({count})
|
|
30
|
+
</Link>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
}))
|