@kaspernj/api-maker 1.0.317 → 1.0.319

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
@@ -16,7 +16,7 @@
16
16
  ]
17
17
  },
18
18
  "name": "@kaspernj/api-maker",
19
- "version": "1.0.317",
19
+ "version": "1.0.319",
20
20
  "type": "module",
21
21
  "description": "",
22
22
  "main": "index.js",
package/src/can-can.mjs CHANGED
@@ -81,6 +81,9 @@ export default class ApiMakerCanCan {
81
81
  for (const abilityData of abilities) {
82
82
  const subject = abilityData[0]
83
83
 
84
+ if (!subject) throw new Error(`Invalid subject given in abilities: ${subject} - ${JSON.stringify(abilities)}`)
85
+ if (!Array.isArray(abilityData[1])) throw new Error(`Expected an array of abilities but got: ${typeof abilityData[1]}: ${abilityData[1]}`)
86
+
84
87
  for (const ability of abilityData[1]) {
85
88
  const promise = this.loadAbility(ability, subject)
86
89
 
@@ -119,7 +122,7 @@ export default class ApiMakerCanCan {
119
122
  clearTimeout(this.queueAbilitiesRequestTimeout)
120
123
  }
121
124
 
122
- this.queueAbilitiesRequestTimeout = setTimeout(() => this.sendAbilitiesRequest(), 0)
125
+ this.queueAbilitiesRequestTimeout = setTimeout(this.sendAbilitiesRequest, 0)
123
126
  }
124
127
 
125
128
  async resetAbilities () {
@@ -129,7 +132,7 @@ export default class ApiMakerCanCan {
129
132
  this.events.emit("onResetAbilities")
130
133
  }
131
134
 
132
- async sendAbilitiesRequest () {
135
+ sendAbilitiesRequest = async () => {
133
136
  const abilitiesToLoad = this.abilitiesToLoad
134
137
  const abilitiesToLoadData = this.abilitiesToLoadData
135
138
 
@@ -8,7 +8,7 @@ import useCurrentUser from "../use-current-user"
8
8
  import useModel from "../use-model"
9
9
  import useQueryParams from "on-location-changed/src/use-query-params"
10
10
 
11
- const EditAttributeInput = ({attributeName, id, inputs, label, model, name}) => {
11
+ const EditAttributeInput = memo(({attributeName, id, inputs, label, model, name}) => {
12
12
  if (!(attributeName in model)) {
13
13
  throw new Error(`${attributeName} isn't set on the resource ${model.modelClassData().name}`)
14
14
  }
@@ -42,9 +42,9 @@ const EditAttributeInput = ({attributeName, id, inputs, label, model, name}) =>
42
42
  </View>
43
43
  </View>
44
44
  )
45
- }
45
+ })
46
46
 
47
- const EditAttributeContent = ({attribute, id, inputs, model, name}) => {
47
+ const EditAttributeContent = memo(({attribute, id, inputs, model, name}) => {
48
48
  if (!(attribute.attribute in model)) {
49
49
  throw new Error(`${attribute.attribute} isn't set on the resource ${model.modelClassData().name}`)
50
50
  }
@@ -70,9 +70,9 @@ const EditAttributeContent = ({attribute, id, inputs, model, name}) => {
70
70
  })
71
71
 
72
72
  return attribute.content(contentArgs())
73
- }
73
+ })
74
74
 
75
- const EditAttribute = ({attribute, inputs, model, modelClass}) => {
75
+ const EditAttribute = memo(({attribute, inputs, model, modelClass}) => {
76
76
  const availableLocales = Locales.availableLocales()
77
77
  const camelizedLower = digg(modelClass.modelClassData(), "camelizedLower")
78
78
 
@@ -81,7 +81,7 @@ const EditAttribute = ({attribute, inputs, model, modelClass}) => {
81
81
  {attribute.content &&
82
82
  <EditAttributeContent
83
83
  attribute={attribute}
84
- id={`${camelizedLower}_${inflection.underscore(attribute.attribute)}`}
84
+ id={`${inflection.underscore(camelizedLower)}_${inflection.underscore(attribute.attribute)}`}
85
85
  inputs={inputs}
86
86
  model={model}
87
87
  name={inflection.underscore(attribute.attribute)}
@@ -90,7 +90,7 @@ const EditAttribute = ({attribute, inputs, model, modelClass}) => {
90
90
  {!attribute.content && attribute.translated && availableLocales.map((locale) =>
91
91
  <EditAttributeInput
92
92
  attributeName={`${attribute.attribute}${inflection.camelize(locale)}`}
93
- id={`${camelizedLower}_${inflection.underscore(attribute.attribute)}_${locale}`}
93
+ id={`${inflection.underscore(camelizedLower)}_${inflection.underscore(attribute.attribute)}_${locale}`}
94
94
  inputs={inputs}
95
95
  label={`${modelClass.humanAttributeName(attribute.attribute)} (${locale})`}
96
96
  model={model}
@@ -101,7 +101,7 @@ const EditAttribute = ({attribute, inputs, model, modelClass}) => {
101
101
  {!attribute.content && !attribute.translated &&
102
102
  <EditAttributeInput
103
103
  attributeName={attribute.attribute}
104
- id={`${camelizedLower}_${inflection.underscore(attribute.attribute)}`}
104
+ id={`${inflection.underscore(camelizedLower)}_${inflection.underscore(attribute.attribute)}`}
105
105
  inputs={inputs}
106
106
  label={modelClass.humanAttributeName(attribute.attribute)}
107
107
  model={model}
@@ -110,7 +110,7 @@ const EditAttribute = ({attribute, inputs, model, modelClass}) => {
110
110
  }
111
111
  </>
112
112
  )
113
- }
113
+ })
114
114
 
115
115
  const EditPage = ({modelClass}) => {
116
116
  const availableLocales = Locales.availableLocales()
@@ -128,6 +128,10 @@ const EditPage = ({modelClass}) => {
128
128
 
129
129
  selectedAttributes[modelClassName] = selectedModelAttributes
130
130
 
131
+ if (!attributes) {
132
+ throw new Error(`No 'attributes' given from edit config for ${modelClass.modelClassData().name}`)
133
+ }
134
+
131
135
  for (const attribute of attributes) {
132
136
  if (attribute.translated) {
133
137
  for (const locale of availableLocales) {
@@ -8,6 +8,7 @@ import {useCallback, useEffect, useState} from "react"
8
8
  import ShowPage from "./show-page"
9
9
  import ShowReflectionActions from "./show-reflection-actions"
10
10
  import ShowReflectionPage from "./show-reflection-page"
11
+ import useCanCan from "../use-can-can"
11
12
  import useQueryParams from "on-location-changed/src/use-query-params"
12
13
 
13
14
  const ApiMakerSuperAdmin = () => {
@@ -19,6 +20,13 @@ const ApiMakerSuperAdmin = () => {
19
20
  const modelId = queryParams.model_id
20
21
  const modelName = modelClass?.modelClassData()?.name
21
22
  const [model, setModel] = useState()
23
+ const canCan = useCanCan(() => {
24
+ const abilities = []
25
+
26
+ if (modelClass) abilities.push([modelClass, ["new"]])
27
+
28
+ return abilities
29
+ })
22
30
 
23
31
  const loadModel = useCallback(async () => {
24
32
  if (modelId && modelClass) {
@@ -73,9 +81,13 @@ const ApiMakerSuperAdmin = () => {
73
81
  const actions = useMemo(
74
82
  () => <>
75
83
  {modelClass && pageToShow == "index" &&
76
- <Link className="create-new-model-link" to={Params.withParams({model: modelName, mode: "new"})}>
77
- Create new
78
- </Link>
84
+ <>
85
+ {canCan?.can("new", modelClass) &&
86
+ <Link className="create-new-model-link" to={Params.withParams({model: modelName, mode: "new"})}>
87
+ Create new
88
+ </Link>
89
+ }
90
+ </>
79
91
  }
80
92
  {model && pageToShow == "show" &&
81
93
  <>
@@ -95,7 +107,7 @@ const ApiMakerSuperAdmin = () => {
95
107
  <ShowReflectionActions model={model} modelClass={modelClass} reflectionName={queryParams.model_reflection} />
96
108
  }
97
109
  </>,
98
- [model, modelClass, pageToShow]
110
+ [canCan, model, modelClass, pageToShow]
99
111
  )
100
112
 
101
113
  return (
@@ -6,7 +6,7 @@ import Header from "./header"
6
6
  import Menu from "./menu"
7
7
  import PropTypes from "prop-types"
8
8
  import PropTypesExact from "prop-types-exact"
9
- import {memo, useCallback, useEffect, useState} from "react"
9
+ import {memo, useCallback, useEffect} from "react"
10
10
  import useCurrentUser from "../../use-current-user"
11
11
  import useShape from "set-state-compare/src/use-shape.js"
12
12
 
@@ -29,7 +29,7 @@ const ApiMakerSuperAdminLayout = ({
29
29
  useEffect(() => {
30
30
  CommandsPool.current().globalRequestData.layout = "admin"
31
31
  CommandsPool.current().globalRequestData.locale = I18n.locale
32
- }, [])
32
+ }, [I18n.locale])
33
33
 
34
34
  const headTitle = headTitle || headerTitle
35
35
 
@@ -63,7 +63,6 @@ const ComponentsAdminLayoutMenu = ({active, noAccess, triggered}) => {
63
63
 
64
64
  ComponentsAdminLayoutMenu.propTypes = PropTypesExact({
65
65
  active: PropTypes.string,
66
- currentUser: PropTypes.instanceOf(User),
67
66
  noAccess: PropTypes.bool.isRequired,
68
67
  onRequestMenuClose: PropTypes.func.isRequired,
69
68
  triggered: PropTypes.bool.isRequired
@@ -1,4 +1,3 @@
1
- import CanCan from "../../../can-can"
2
1
  import {digg} from "diggerize"
3
2
  import {memo, useMemo} from "react"
4
3
  import MenuItem from "./menu-item"
@@ -6,20 +5,13 @@ import models from "../../models"
6
5
  import Params from "../../../params"
7
6
  import PropTypes from "prop-types"
8
7
  import PropTypesExact from "prop-types-exact"
9
- import withCanCan from "@kaspernj/api-maker/src/with-can-can"
8
+ import useCanCan from "../../../use-can-can"
10
9
 
11
- const abilities = []
12
-
13
- for (const model of models) {
14
- abilities.push(
15
- [model, ["index"]]
16
- )
17
- }
18
-
19
- const ComponentsAdminLayoutMenuContent = ({active, canCan}) => {
10
+ const ComponentsAdminLayoutMenuContent = ({active}) => {
11
+ const canCan = useCanCan(() => models.map((model) => [model, ["index"]]))
20
12
  const sortedModels = useMemo(
21
13
  () => models.sort((a, b) => a.modelName().human({count: 2}).toLowerCase().localeCompare(b.modelName().human({count: 2}).toLowerCase())),
22
- []
14
+ [I18n.locale]
23
15
  )
24
16
 
25
17
  return (
@@ -39,8 +31,7 @@ const ComponentsAdminLayoutMenuContent = ({active, canCan}) => {
39
31
  }
40
32
 
41
33
  ComponentsAdminLayoutMenuContent.propTypes = PropTypesExact({
42
- active: PropTypes.string,
43
- canCan: PropTypes.instanceOf(CanCan)
34
+ active: PropTypes.string
44
35
  })
45
36
 
46
- export default withCanCan(memo(ComponentsAdminLayoutMenuContent), abilities)
37
+ export default memo(ComponentsAdminLayoutMenuContent)
@@ -6,6 +6,7 @@ const SuperAdminShowReflectionActions = ({model, modelClass, reflectionName}) =>
6
6
  const modelClassName = digg(reflection, "reflectionData", "className")
7
7
  const modelData = {}
8
8
  const dataParamName = inflection.singularize(reflection.reflectionData.collectionName)
9
+ const canCan = useCanCan(() => [[reflection.modelClass(), ["new"]]])
9
10
 
10
11
  modelData[reflection.foreignKey()] = model?.id()
11
12
 
@@ -17,9 +18,13 @@ const SuperAdminShowReflectionActions = ({model, modelClass, reflectionName}) =>
17
18
  linkParams[dataParamName] = modelData
18
19
 
19
20
  return (
20
- <Link className="create-new-model-link" to={Params.withParams(linkParams)}>
21
- Create new
22
- </Link>
21
+ <>
22
+ {canCan?.can("new", reflection.modelClass()) &&
23
+ <Link className="create-new-model-link" to={Params.withParams(linkParams)}>
24
+ Create new
25
+ </Link>
26
+ }
27
+ </>
23
28
  )
24
29
  }
25
30
 
@@ -1,14 +1,16 @@
1
1
  import CanCan from "./can-can.mjs"
2
2
  import {useCallback, useEffect, useState} from "react"
3
+ import useCurrentUser from "./use-current-user.mjs"
3
4
  import useShape from "set-state-compare/src/use-shape.js"
4
5
 
5
6
  const useCanCan = (abilitiesCallback, dependencies) => {
7
+ const currentUser = useCurrentUser()
6
8
  const s = useShape({abilitiesCallback})
7
9
  const [canCan, setCanCan] = useState()
8
10
 
9
- useEffect(() => {
10
- loadAbilities()
11
- }, dependencies)
11
+ if (!dependencies) {
12
+ dependencies = [currentUser?.id()]
13
+ }
12
14
 
13
15
  const loadAbilities = useCallback(async () => {
14
16
  const canCan = CanCan.current()
@@ -24,6 +26,10 @@ const useCanCan = (abilitiesCallback, dependencies) => {
24
26
  loadAbilities()
25
27
  }, [])
26
28
 
29
+ useEffect(() => {
30
+ loadAbilities()
31
+ }, dependencies)
32
+
27
33
  useEffect(() => {
28
34
  CanCan.current().events.addListener("onResetAbilities", onResetAbilities)
29
35