@kaspernj/api-maker 1.0.246 → 1.0.248

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.246",
19
+ "version": "1.0.248",
20
20
  "type": "module",
21
21
  "description": "",
22
22
  "main": "index.js",
@@ -6,6 +6,7 @@ import Deserializer from "./deserializer.mjs"
6
6
  import {dig, digg} from "diggerize"
7
7
  import FormDataObjectizer from "form-data-objectizer"
8
8
  import Serializer from "./serializer.mjs"
9
+ import SessionStatusUpdater from "./session-status-updater.mjs"
9
10
  import ValidationError from "./validation-error.mjs"
10
11
  import {ValidationErrors} from "./validation-errors.mjs"
11
12
 
@@ -89,6 +90,27 @@ export default class ApiMakerCommandsPool {
89
90
  return Object.keys(this.pool)
90
91
  }
91
92
 
93
+ async sendRequest ({commandSubmitData, url}) {
94
+ let response
95
+
96
+ for (let i = 0; i < 3; i++) {
97
+ if (commandSubmitData.getFilesCount() > 0) {
98
+ response = await Api.requestLocal({path: url, method: "POST", rawData: commandSubmitData.getFormData()})
99
+ } else {
100
+ response = await Api.requestLocal({path: url, method: "POST", data: commandSubmitData.getJsonData()})
101
+ }
102
+
103
+ if (response.success === false && response.type == "invalid_authenticity_token") {
104
+ console.error("invalid_authenticity_token - try again")
105
+ await SessionStatusUpdater.current().updateSessionStatus()
106
+ continue;
107
+ }
108
+
109
+ console.error(`Request succeeded after ${i} tries`)
110
+ return response
111
+ }
112
+ }
113
+
92
114
  async flush () {
93
115
  if (this.commandsCount() == 0) {
94
116
  return
@@ -111,14 +133,7 @@ export default class ApiMakerCommandsPool {
111
133
 
112
134
  const commandSubmitData = new CommandSubmitData(submitData)
113
135
  const url = "/api_maker/commands"
114
-
115
- let response
116
-
117
- if (commandSubmitData.getFilesCount() > 0) {
118
- response = await Api.requestLocal({path: url, method: "POST", rawData: commandSubmitData.getFormData()})
119
- } else {
120
- response = await Api.requestLocal({path: url, method: "POST", data: commandSubmitData.getJsonData()})
121
- }
136
+ const response = await this.sendRequest({commandSubmitData, url})
122
137
 
123
138
  for (const commandId in response.responses) {
124
139
  const commandResponse = response.responses[commandId]
@@ -1,6 +1,6 @@
1
- import BaseError from "./base-error.mjs"
1
+ import CustomError from "./custom-error.mjs"
2
2
 
3
- class DestroyError extends BaseError {}
3
+ class DestroyError extends CustomError {}
4
4
 
5
5
  DestroyError.apiMakerType = "DestroyError"
6
6
 
package/src/logger.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  const shared = {}
2
2
 
3
3
  export default class ApiMakerLogger {
4
- static current () {
4
+ static current() {
5
5
  if (!shared.apiMakerLogger) {
6
6
  shared.apiMakerLogger = new ApiMakerLogger()
7
7
  // shared.apiMakerLogger.setDebug(true)
@@ -10,16 +10,20 @@ export default class ApiMakerLogger {
10
10
  return shared.apiMakerLogger
11
11
  }
12
12
 
13
- static log (message) {
13
+ static log(message) {
14
14
  ApiMakerLogger.current().log(message)
15
15
  }
16
16
 
17
- log (message) {
17
+ log(message) {
18
18
  if (this.debug)
19
19
  console.log("ApiMaker", message)
20
20
  }
21
21
 
22
- setDebug (value) {
22
+ getDebug() {
23
+ return this.debug
24
+ }
25
+
26
+ setDebug(value) {
23
27
  this.debug = value
24
28
  }
25
29
  }
@@ -1,5 +1,6 @@
1
1
  import Devise from "./devise.mjs"
2
2
  import inflection from "inflection"
3
+ import Logger from "./logger.mjs"
3
4
  import wakeEvent from "wake-event"
4
5
 
5
6
  export default class ApiMakerSessionStatusUpdater {
@@ -11,7 +12,6 @@ export default class ApiMakerSessionStatusUpdater {
11
12
  }
12
13
 
13
14
  constructor (args = {}) {
14
- this.debugging = args.debug || false
15
15
  this.events = {}
16
16
  this.timeout = args.timeout || 600000
17
17
 
@@ -28,8 +28,7 @@ export default class ApiMakerSessionStatusUpdater {
28
28
  }
29
29
 
30
30
  debug (message) {
31
- if (this.debugging)
32
- console.log(`ApiMakerSessionStatusUpdater: ${message}`)
31
+ Logger.log(`API maker / SessionStatusUpdater: ${message}`)
33
32
  }
34
33
 
35
34
  async sessionStatus () {
@@ -1,4 +1,5 @@
1
1
  import * as stackTraceParser from "stacktrace-parser"
2
+ import Logger from "./logger.mjs"
2
3
  import {SourceMapConsumer} from "source-map"
3
4
  import uniqunize from "uniqunize"
4
5
 
@@ -11,14 +12,13 @@ if (SourceMapConsumer.initialize) {
11
12
 
12
13
  export default class SourceMapsLoader {
13
14
  constructor () {
14
- this.debugging = false
15
15
  this.isLoadingSourceMaps = false
16
16
  this.sourceMaps = []
17
17
  this.srcLoaded = {}
18
18
  }
19
19
 
20
20
  debug(messageCallback) {
21
- if (this.debugging) console.log(`API maker / Source maps loader:`, messageCallback.call())
21
+ if (Logger.current().getDebug()) Logger.log(`API maker / SourceMapsLoader: ${messageCallback.call()}`)
22
22
  }
23
23
 
24
24
  loadSourceMapsForScriptTags (callback) {
@@ -3,10 +3,10 @@ import BelongsToAttributeRow from "./belongs-to-attribute-row"
3
3
  import ConfigReader from "../config-reader"
4
4
  import {digg, digs} from "diggerize"
5
5
  import inflection from "inflection"
6
- import modelLoadWrapper from "../../model-load-wrapper"
7
6
  import PropTypes from "prop-types"
8
7
  import React from "react"
9
8
  import ShowNav from "../show-nav"
9
+ import withModel from "../../with-model"
10
10
 
11
11
  class ApiMakerSuperAdminShowPage extends React.PureComponent {
12
12
  static propTypes = {
@@ -58,7 +58,7 @@ const modelClassResolver = {callback: ({queryParams}) => {
58
58
  return modelClass
59
59
  }}
60
60
 
61
- export default modelLoadWrapper(
61
+ export default withModel(
62
62
  ApiMakerSuperAdminShowPage,
63
63
  modelClassResolver,
64
64
  ({modelClass}) => {
@@ -1,9 +1,9 @@
1
1
  import {digg, digs} from "diggerize"
2
- import modelLoadWrapper from "../model-load-wrapper"
3
2
  import PropTypes from "prop-types"
4
3
  import React from "react"
5
4
  import ModelClassTable from "./model-class-table"
6
5
  import ShowNav from "./show-nav"
6
+ import withModel from "../with-model"
7
7
 
8
8
  class ApiMakerSuperAdminShowReflectionPage extends React.PureComponent {
9
9
  static propTypes = {
@@ -55,7 +55,7 @@ const modelClassResolver = {callback: ({queryParams}) => {
55
55
  return modelClass
56
56
  }}
57
57
 
58
- export default modelLoadWrapper(
58
+ export default withModel(
59
59
  ApiMakerSuperAdminShowReflectionPage,
60
60
  modelClassResolver,
61
61
  {
@@ -206,17 +206,9 @@ class ApiMakerTable extends React.PureComponent {
206
206
  const {abilities, modelClass} = this.props
207
207
  const ownAbilities = []
208
208
 
209
- if (this.props.destroyEnabled) {
210
- ownAbilities.push("destroy")
211
- }
212
-
213
- if (this.props.editModelPath) {
214
- ownAbilities.push("edit")
215
- }
216
-
217
- if (this.props.viewModelPath) {
218
- ownAbilities.push("show")
219
- }
209
+ if (this.props.destroyEnabled) ownAbilities.push("destroy")
210
+ if (this.props.editModelPath) ownAbilities.push("edit")
211
+ if (this.props.viewModelPath) ownAbilities.push("show")
220
212
 
221
213
  if (ownAbilities.length > 0) {
222
214
  const modelClassName = digg(modelClass.modelClassData(), "name")
@@ -0,0 +1,259 @@
1
+ import {debounce} from "debounce"
2
+ import {digg, digs} from "diggerize"
3
+ import EventCreated from "./event-created"
4
+ import EventDestroyed from "./event-destroyed"
5
+ import EventUpdated from "./event-updated"
6
+ import React from "react"
7
+ import Shape from "set-state-compare/src/shape"
8
+ import withQueryParams from "on-location-changed/src/with-query-params"
9
+
10
+ export default (WrappedComponent, withCollectionArgs) => withQueryParams(class ApiMakerWithCollection extends React.PureComponent {
11
+ constructor (props) {
12
+ super(props)
13
+
14
+ let queryName = withCollectionArgs.queryName
15
+
16
+ if (!queryName) queryName = digg(withCollectionArgs.modelClass.modelClassData(), "collectionKey")
17
+
18
+ this.shape = new Shape(this, {
19
+ models: undefined,
20
+ overallCount: undefined,
21
+ query: undefined,
22
+ queryName,
23
+ queryPerKey: `${queryName}_per`,
24
+ queryQName: `${queryName}_q`,
25
+ querySName: `${queryName}_s`,
26
+ queryPageName: `${queryName}_page`,
27
+ qParams: undefined,
28
+ result: undefined,
29
+ searchParams: undefined,
30
+ showNoRecordsAvailableContent: false,
31
+ showNoRecordsFoundContent: false
32
+ })
33
+ }
34
+
35
+ componentDidMount () {
36
+ this.loadQParams()
37
+ this.loadModels()
38
+
39
+ const {noRecordsAvailableContent} = digs(withCollectionArgs)
40
+
41
+ if (noRecordsAvailableContent) this.loadOverallCount()
42
+ }
43
+
44
+ componentDidUpdate(prevProps) {
45
+ const {queryPageName, queryPerKey, queryQName, querySName} = digs(this.shape, "queryPageName", "queryPerKey", "queryQName", "querySName")
46
+ let changed = false
47
+
48
+ // Only load models again if certain things in the URL changes
49
+ if (prevProps.queryParams[queryQName] != this.props.queryParams[queryQName]) {
50
+ changed = true
51
+ } else if (prevProps.queryParams[queryPageName] != this.props.queryParams[queryPageName]) {
52
+ changed = true
53
+ } else if (prevProps.queryParams[queryPerKey] != this.props.queryParams[queryPerKey]) {
54
+ changed = true
55
+ } else if (prevProps.queryParams[querySName] != this.props.queryParams[querySName]) {
56
+ changed = true
57
+ }
58
+
59
+ if (changed) {
60
+ this.loadQParams()
61
+ this.loadModels()
62
+ }
63
+ }
64
+
65
+ async loadOverallCount () {
66
+ const baseQuery = withCollectionArgs.collection || withCollectionArgs.modelClass.all()
67
+ const overallCount = await baseQuery.count()
68
+
69
+ this.shape.set({
70
+ overallCount,
71
+ showNoRecordsAvailableContent: this.showNoRecordsAvailableContent({overallCount}),
72
+ showNoRecordsFoundContent: this.showNoRecordsFoundContent({overallCount})
73
+ })
74
+ }
75
+
76
+ hasQParams() {
77
+ const {queryParams} = digs(this.props, "queryParams")
78
+ const {queryQName} = digs(this.shape, "queryQName")
79
+
80
+ if (queryQName in queryParams) return true
81
+
82
+ return false
83
+ }
84
+
85
+ qParams() {
86
+ const {queryParams} = digs(this.props, "queryParams")
87
+ const {queryQName} = digs(this.shape, "queryQName")
88
+
89
+ if (this.hasQParams()) return JSON.parse(digg(queryParams, queryQName))
90
+
91
+ return {}
92
+ }
93
+
94
+ loadQParams () {
95
+ const {queryParams} = digs(this.props, "queryParams")
96
+ const {querySName} = digs(this.shape, "querySName")
97
+ const qParams = this.hasQParams() ? this.qParams() : Object.assign({}, withCollectionArgs.defaultParams)
98
+ const searchParams = []
99
+
100
+ if (queryParams[querySName]) {
101
+ for (const rawSearchParam of queryParams[querySName]) {
102
+ const parsedSearchParam = JSON.parse(rawSearchParam)
103
+
104
+ searchParams.push(parsedSearchParam)
105
+ }
106
+ }
107
+
108
+ this.shape.set({qParams, searchParams})
109
+ }
110
+
111
+ loadModels = async () => {
112
+ const {queryParams} = digs(this.props, "queryParams")
113
+ const {abilities, collection, groupBy, modelClass, onModelsLoaded, preloads, select, selectColumns} = withCollectionArgs
114
+ const {
115
+ qParams,
116
+ queryPageName,
117
+ queryPerKey,
118
+ queryQName,
119
+ searchParams
120
+ } = digs(
121
+ this.shape,
122
+ "qParams",
123
+ "queryPageName",
124
+ "queryPerKey",
125
+ "queryQName",
126
+ "searchParams"
127
+ )
128
+ const page = queryParams[queryPageName] || 1
129
+ let per = queryParams[queryPerKey] || 30
130
+
131
+ if (per == "all") {
132
+ per = 999_999_999
133
+ } else {
134
+ per = Number(per)
135
+ }
136
+
137
+ let query = collection?.clone() || modelClass.ransack()
138
+
139
+ if (groupBy) query = query.groupBy(...groupBy)
140
+
141
+ query = query
142
+ .ransack(qParams)
143
+ .search(searchParams)
144
+ .searchKey(queryQName)
145
+ .page(page)
146
+ .pageKey(queryPageName)
147
+ .per(per)
148
+ .perKey(queryPerKey)
149
+ .preload(preloads)
150
+ .select(select)
151
+
152
+ if (abilities) query = query.abilities(abilities)
153
+ if (selectColumns) query = query.selectColumns(selectColumns)
154
+
155
+ const result = await query.result()
156
+ const models = result.models()
157
+
158
+ if (onModelsLoaded) {
159
+ onModelsLoaded({
160
+ models,
161
+ qParams,
162
+ query,
163
+ result
164
+ })
165
+ }
166
+
167
+ this.shape.set({
168
+ query,
169
+ result,
170
+ models: result.models(),
171
+ showNoRecordsAvailableContent: this.showNoRecordsAvailableContent({models}),
172
+ showNoRecordsFoundContent: this.showNoRecordsFoundContent({models})
173
+ })
174
+ }
175
+
176
+ loadModelsDebounce = debounce(digg(this, "loadModels"))
177
+ onModelCreated = digg(this, "loadModels")
178
+
179
+ onModelDestroyed = ({destroyedModel}) => {
180
+ const {models} = digs(this.shape, "models")
181
+
182
+ this.shape.set({
183
+ models: models.filter((model) => model.id() != destroyedModel.id())
184
+ })
185
+ }
186
+
187
+ onModelUpdated = ({model: updatedModel}) => {
188
+ const {models} = digs(this.shape, "models")
189
+ const foundModel = models.find((model) => model.id() == updatedModel.id())
190
+
191
+ if (foundModel) this.loadModelsDebounce()
192
+ }
193
+
194
+ showNoRecordsAvailableContent (args) {
195
+ const {noRecordsAvailableContent} = withCollectionArgs
196
+ let models, overallCount
197
+
198
+ if (args.models !== undefined) {
199
+ models = args.models
200
+ } else if (this.shape.models !== undefined) {
201
+ models = this.shape.models
202
+ }
203
+
204
+ if (args.overallCount !== undefined) {
205
+ overallCount = args.overallCount
206
+ } else if (this.shape.overallCount !== undefined) {
207
+ overallCount = this.shape.overallCount
208
+ }
209
+
210
+ if (models === undefined || overallCount === undefined || noRecordsAvailableContent === undefined) return false
211
+ if (models.length === 0 && overallCount === 0 && noRecordsAvailableContent) return true
212
+ }
213
+
214
+ showNoRecordsFoundContent (args) {
215
+ const {noRecordsAvailableContent, noRecordsFoundContent} = withCollectionArgs
216
+ let models, overallCount
217
+
218
+ if (args.models !== undefined) {
219
+ models = args.models
220
+ } else if (this.shape.models !== undefined) {
221
+ models = this.shape.models
222
+ }
223
+
224
+ if (args.overallCount !== undefined) {
225
+ overallCount = args.overallCount
226
+ } else if (this.shape.overallCount !== undefined) {
227
+ overallCount = this.shape.overallCount
228
+ }
229
+
230
+ if (models === undefined || noRecordsFoundContent === undefined) return false
231
+
232
+ // Dont show noRecordsAvailableContent together with noRecordsAvailableContent
233
+ if (models.length === 0 && overallCount === 0 && noRecordsAvailableContent) return false
234
+ if (models.length === 0 && noRecordsFoundContent) return true
235
+ }
236
+
237
+ render() {
238
+ const {modelClass} = digs(withCollectionArgs, "modelClass")
239
+ const {onModelCreated, onModelDestroyed, onModelUpdated} = digs(this, "onModelCreated", "onModelDestroyed", "onModelUpdated")
240
+ const {models} = digs(this.shape, "models")
241
+ const modelsArgName = inflection.camelize(digg(withCollectionArgs.modelClass.modelClassData(), "pluralName"), true)
242
+ const forwardArgs = {}
243
+
244
+ forwardArgs[modelsArgName] = models
245
+
246
+ return (
247
+ <>
248
+ <EventCreated modelClass={modelClass} onCreated={onModelCreated} />
249
+ {models && models.map((model) =>
250
+ <React.Fragment key={model.id()}>
251
+ <EventDestroyed model={model} onDestroyed={onModelDestroyed} />
252
+ <EventUpdated model={model} onUpdated={onModelUpdated} />
253
+ </React.Fragment>
254
+ )}
255
+ <WrappedComponent {...forwardArgs} {...this.props} />
256
+ </>
257
+ )
258
+ }
259
+ })
@@ -6,7 +6,7 @@ import React from "react"
6
6
  import withQueryParams from "on-location-changed/src/with-query-params"
7
7
 
8
8
  export default (WrappedComponent, modelClassArg, argsArg = {}) => {
9
- class ModelLoadWrapper extends React.PureComponent {
9
+ class ApiMakerWithModel extends React.PureComponent {
10
10
  static propTypes = {
11
11
  queryParams: PropTypes.object
12
12
  }
@@ -135,5 +135,5 @@ export default (WrappedComponent, modelClassArg, argsArg = {}) => {
135
135
  onUpdated = this.loadExistingModel
136
136
  }
137
137
 
138
- return withQueryParams(ModelLoadWrapper)
138
+ return withQueryParams(ApiMakerWithModel)
139
139
  }