@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaspernj/api-maker",
3
- "version": "1.0.377",
3
+ "version": "1.0.379",
4
4
  "type": "module",
5
5
  "description": "",
6
6
  "main": "index.js",
@@ -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
- () => this.props.model?.constructor?.attributes()?.find((attribute) => attribute.name() == inflection.underscore(this.props.attribute)),
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 {memo} from "react"
5
+ import {shapeComponent} from "set-state-compare/src/shape-component.js"
4
6
 
5
- const ApiMakerSuperAdminIndexPage = ({modelClass}) => {
6
- return (
7
- <div className="super-admin--index-page">
8
- <ModelClassTable
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
- ApiMakerSuperAdminIndexPage.propTypes = {
16
- modelClass: PropTypes.func.isRequired
17
- }
12
+ render() {
13
+ const {modelClass} = this.props
18
14
 
19
- export default memo(ApiMakerSuperAdminIndexPage)
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 {useCallback, useEffect, useState} from "react"
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
- const ApiMakerSuperAdmin = () => {
17
- const currentUser = useCurrentUser()
18
- const queryParams = useQueryParams()
19
- let modelClass, pageToShow
18
+ export default memo(shapeComponent(class ApiMakerSuperAdmin extends BaseComponent {
19
+ setup() {
20
+ this.queryParams = useQueryParams()
20
21
 
21
- if (queryParams.model) modelClass = modelsModule[queryParams.model]
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
- const modelId = queryParams.model_id
24
- const modelName = modelClass?.modelClassData()?.name
25
- const [model, setModel] = useState()
26
- const canCan = useCanCan(
27
- () => {
28
- const abilities = []
32
+ this.canCan = useCanCan(
33
+ () => {
34
+ const abilities = []
29
35
 
30
- if (modelClass) abilities.push([modelClass, ["new"]])
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
- return abilities
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
- setModel(model)
66
+ this.setState({model})
50
67
  } else {
51
- setModel(undefined)
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
- const onDestroyClicked = useCallback(async (e) => {
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
- }, [model])
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, useCallback, useMemo} from "react"
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
- import useShape from "set-state-compare/src/use-shape.js"
11
-
12
- const ApiMakerSuperAdminModelClassTable = (props) => {
13
- const s = useShape(props)
14
- const {modelClass, ...restProps} = props
15
- const currentUser = useCurrentUser()
16
- const configReader = useMemo(() => ConfigReader.forModel(modelClass), [modelClass])
17
- const columns = useMemo(() => configReader.tableColumns(), [modelClass])
18
- const tableConfig = configReader.modelConfig?.table
19
-
20
- const editModelPath = useCallback((args) => {
21
- const argName = inflection.camelize(digg(s.p.modelClass.modelClassData(), "name"), true)
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: s.p.modelClass.modelClassData().name,
47
+ model: this.p.modelClass.modelClassData().name,
26
48
  model_id: model.primaryKey(),
27
49
  mode: "edit"
28
50
  })
29
- }, [])
51
+ }
30
52
 
31
- const viewModelPath = useCallback((args) => {
32
- const argName = inflection.camelize(digg(s.p.modelClass.modelClassData(), "name"), true)
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: s.p.modelClass.modelClassData().name,
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 {digg} from "diggerize"
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 React from "react"
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
- const ApiMakerSuperAdminShowNav = ({model, modelClass}) => {
9
- const queryParams = useQueryParams()
10
- const reflections = modelClass.reflections()
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
- return (
13
- <div>
16
+ render() {
17
+ const {model, modelClass} = this.props
18
+ const queryParams = useQueryParams()
19
+ const reflections = modelClass.reflections()
20
+
21
+ return (
14
22
  <div>
15
- <Link to={Params.withParams({model: modelClass.modelClassData().name, model_id: queryParams.model_id})}>
16
- {I18n.t("js.api_maker.suprt_admin.show_reflection_page.general", {defaultValue: "General"})}
17
- </Link>
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
- </div>
27
- )
28
- }
29
-
30
- ApiMakerSuperAdminShowNav.propTypes = PropTypesExact({
31
- model: PropTypes.object.isRequired,
32
- modelClass: PropTypes.func.isRequired
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
- } else {
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 model={model} {...attributeRowProps} />
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
- if (!(reflectionModelClassName in select)) select[reflectionModelClassName] = []
55
- if (!select[reflectionModelClassName].includes("id")) select[reflectionModelClassName].push("id")
56
- if (nameAttribute && !select[reflectionModelClassName].includes("name")) select[reflectionModelClassName].push("name")
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
- preload.push(inflection.underscore(reflection.name()))
36
+ setup() {
37
+ const {modelClass} = this.props
38
+ const configReader = useMemo(() => ConfigReader.forModel(modelClass), [modelClass])
39
+ const showConfig = configReader.modelConfig?.show
67
40
 
68
- if (!(reflectionModelClassName in select)) select[reflectionModelClassName] = []
69
- if (!select[reflectionModelClassName].includes("id")) select[reflectionModelClassName].push("id")
70
- if (nameAttribute && !select[reflectionModelClassName].includes("name")) select[reflectionModelClassName].push("name")
41
+ this.setInstance({configReader, showConfig})
42
+ }
71
43
 
72
- // The foreign key is needed to look up any has-one-relationships
73
- if (!modelClassSelect.includes(reflection.foreignKey()) && !select[reflectionModelClassName].includes(reflection.foreignKey()) && !reflection.through()) {
74
- select[reflectionModelClassName].push(reflection.foreignKey())
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
- const useModelResult = useModel(modelClass, {
80
- loadByQueryParam: ({queryParams}) => queryParams.model_id,
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
- modelArgs[inflection.camelize(modelClass.modelClassData().name, true)] = model
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
- return (
91
- <div className="super-admin--show-page">
92
- {model &&
93
- <ShowNav model={model} modelClass={modelClass} />
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
- {attributes && model && attributes.map((attribute) =>
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
- export default memo(ApiMakerSuperAdminShowPage)
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
+ }))