@kaspernj/api-maker 1.0.214 → 1.0.217
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 +5 -4
- package/src/base-model.mjs +1 -1
- package/src/bootstrap/attribute-row/basic-style.scss +9 -0
- package/src/bootstrap/attribute-row/index.jsx +84 -0
- package/src/bootstrap/attribute-rows.jsx +27 -0
- package/src/bootstrap/card.jsx +135 -0
- package/src/bootstrap/checkbox.jsx +79 -0
- package/src/bootstrap/checkboxes.jsx +122 -0
- package/src/bootstrap/index.js +0 -0
- package/src/bootstrap/input.jsx +160 -0
- package/src/bootstrap/invalid-feedback.jsx +31 -0
- package/src/bootstrap/live-table/model-row.jsx +150 -0
- package/src/bootstrap/live-table.jsx +399 -0
- package/src/bootstrap/paginate.jsx +153 -0
- package/src/bootstrap/radio-buttons.jsx +87 -0
- package/src/bootstrap/select.jsx +110 -0
- package/src/bootstrap/sort-link.jsx +102 -0
- package/src/collection-loader.jsx +7 -8
- package/src/inputs/auto-submit.mjs +37 -0
- package/src/inputs/checkbox.jsx +97 -0
- package/src/inputs/checkboxes.jsx +113 -0
- package/src/inputs/id-for-component.mjs +15 -0
- package/src/inputs/input-wrapper.jsx +170 -0
- package/src/inputs/input.jsx +235 -0
- package/src/inputs/money.jsx +177 -0
- package/src/inputs/name-for-component.mjs +15 -0
- package/src/inputs/select.jsx +87 -0
- package/src/model-class-require.mjs +1 -1
- package/src/model-name.mjs +1 -1
- package/src/super-admin/index.jsx +11 -0
- package/src/super-admin/layout/header/index.jsx +60 -0
- package/src/super-admin/layout/header/style.scss +124 -0
- package/src/super-admin/layout/index.jsx +156 -0
- package/src/super-admin/layout/menu/index.jsx +116 -0
- package/src/super-admin/layout/menu/menu-content.jsx +106 -0
- package/src/super-admin/layout/menu/menu-item/index.jsx +27 -0
- package/src/super-admin/layout/menu/menu-item/style.scss +30 -0
- package/src/super-admin/layout/menu/style.scss +103 -0
- package/src/super-admin/layout/style.scss +25 -0
- package/src/table/column-identifier.mjs +23 -0
- package/src/table/column-visible.mjs +7 -0
- package/src/table/model-row.jsx +182 -0
- package/src/table/select-calculator.mjs +48 -0
- package/src/table/style.scss +72 -0
- package/src/table/table-settings.js +175 -0
- package/src/table/table.jsx +498 -0
- package/src/table/variables.scss +11 -0
- package/src/table/with-breakpoint.jsx +48 -0
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
import "./style"
|
|
2
|
+
import Card from "../bootstrap/card"
|
|
3
|
+
import classNames from "classnames"
|
|
4
|
+
import Collection from "../collection"
|
|
5
|
+
import CollectionLoader from "../collection-loader"
|
|
6
|
+
import columnVisible from "./column-visible.mjs"
|
|
7
|
+
import {debounce} from "debounce"
|
|
8
|
+
import {digg, digs} from "diggerize"
|
|
9
|
+
import inflection from "inflection"
|
|
10
|
+
import instanceOfClassName from "../instance-of-class-name"
|
|
11
|
+
import modelClassRequire from "../model-class-require.mjs"
|
|
12
|
+
import ModelRow from "./model-row"
|
|
13
|
+
import Paginate from "../bootstrap/paginate"
|
|
14
|
+
import Params from "../params"
|
|
15
|
+
import PropTypes from "prop-types"
|
|
16
|
+
import React from "react"
|
|
17
|
+
import selectCalculator from "./select-calculator"
|
|
18
|
+
import Shape from "set-state-compare/src/shape"
|
|
19
|
+
import SortLink from "../bootstrap/sort-link"
|
|
20
|
+
import TableSettings from "./table-settings"
|
|
21
|
+
import uniqunize from "uniqunize"
|
|
22
|
+
import withBreakpoint from "./with-breakpoint"
|
|
23
|
+
|
|
24
|
+
class ApiMakerTable extends React.PureComponent {
|
|
25
|
+
static defaultProps = {
|
|
26
|
+
card: true,
|
|
27
|
+
destroyEnabled: true,
|
|
28
|
+
filterCard: true,
|
|
29
|
+
filterSubmitButton: true,
|
|
30
|
+
noRecordsAvailableContent: undefined,
|
|
31
|
+
noRecordsFoundContent: undefined,
|
|
32
|
+
preloads: [],
|
|
33
|
+
select: {}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
static propTypes = {
|
|
37
|
+
abilities: PropTypes.object,
|
|
38
|
+
actionsContent: PropTypes.func,
|
|
39
|
+
appHistory: PropTypes.object,
|
|
40
|
+
card: PropTypes.bool.isRequired,
|
|
41
|
+
className: PropTypes.string,
|
|
42
|
+
collection: PropTypes.oneOfType([
|
|
43
|
+
instanceOfClassName("ApiMakerCollection"),
|
|
44
|
+
PropTypes.instanceOf(Collection)
|
|
45
|
+
]),
|
|
46
|
+
columns: PropTypes.oneOfType([PropTypes.array, PropTypes.func]),
|
|
47
|
+
columnsContent: PropTypes.func,
|
|
48
|
+
controls: PropTypes.func,
|
|
49
|
+
currentUser: PropTypes.object,
|
|
50
|
+
defaultDateFormatName: PropTypes.string,
|
|
51
|
+
defaultDateTimeFormatName: PropTypes.string,
|
|
52
|
+
defaultParams: PropTypes.object,
|
|
53
|
+
destroyEnabled: PropTypes.bool.isRequired,
|
|
54
|
+
destroyMessage: PropTypes.string,
|
|
55
|
+
editModelPath: PropTypes.func,
|
|
56
|
+
filterCard: PropTypes.bool.isRequired,
|
|
57
|
+
filterContent: PropTypes.func,
|
|
58
|
+
filterSubmitLabel: PropTypes.node,
|
|
59
|
+
groupBy: PropTypes.array,
|
|
60
|
+
header: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
|
|
61
|
+
identifier: PropTypes.string,
|
|
62
|
+
modelClass: PropTypes.func.isRequired,
|
|
63
|
+
noRecordsAvailableContent: PropTypes.func,
|
|
64
|
+
noRecordsFoundContent: PropTypes.func,
|
|
65
|
+
onModelsLoaded: PropTypes.func,
|
|
66
|
+
paginateContent: PropTypes.func,
|
|
67
|
+
paginationComponent: PropTypes.func,
|
|
68
|
+
preloads: PropTypes.array.isRequired,
|
|
69
|
+
queryName: PropTypes.string,
|
|
70
|
+
select: PropTypes.object,
|
|
71
|
+
selectColumns: PropTypes.object,
|
|
72
|
+
viewModelPath: PropTypes.func
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
filterFormRef = React.createRef()
|
|
76
|
+
|
|
77
|
+
constructor (props) {
|
|
78
|
+
super(props)
|
|
79
|
+
|
|
80
|
+
const collectionKey = digg(props.modelClass.modelClassData(), "collectionKey")
|
|
81
|
+
let queryName = props.queryName
|
|
82
|
+
|
|
83
|
+
if (!queryName) queryName = collectionKey
|
|
84
|
+
|
|
85
|
+
const columnsAsArray = this.columnsAsArray()
|
|
86
|
+
|
|
87
|
+
this.shape = new Shape(this, {
|
|
88
|
+
columns: columnsAsArray,
|
|
89
|
+
identifier: this.props.identifier || `${collectionKey}-default`,
|
|
90
|
+
models: undefined,
|
|
91
|
+
overallCount: undefined,
|
|
92
|
+
preload: undefined,
|
|
93
|
+
preparedColumns: undefined,
|
|
94
|
+
query: undefined,
|
|
95
|
+
queryName,
|
|
96
|
+
queryQName: `${queryName}_q`,
|
|
97
|
+
queryPageName: `${queryName}_page`,
|
|
98
|
+
qParams: undefined,
|
|
99
|
+
result: undefined,
|
|
100
|
+
showNoRecordsAvailableContent: false,
|
|
101
|
+
showNoRecordsFoundContent: false
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
this.loadTableSetting()
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async loadTableSetting() {
|
|
108
|
+
this.tableSettings = new TableSettings({table: this})
|
|
109
|
+
|
|
110
|
+
const tableSetting = await this.tableSettings.loadExistingOrCreateTableSettings()
|
|
111
|
+
const {columns, preload} = this.tableSettings.preparedColumns(tableSetting)
|
|
112
|
+
|
|
113
|
+
this.shape.set({
|
|
114
|
+
preparedColumns: columns,
|
|
115
|
+
preload: this.mergedPreloads(preload)
|
|
116
|
+
})
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
columnsAsArray = () => {
|
|
120
|
+
if (typeof this.props.columns == "function") return this.props.columns()
|
|
121
|
+
|
|
122
|
+
return this.props.columns
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
mergedPreloads(preload) {
|
|
126
|
+
const {preloads} = this.props
|
|
127
|
+
let mergedPreloads = []
|
|
128
|
+
|
|
129
|
+
if (preloads) mergedPreloads = mergedPreloads.concat(preloads)
|
|
130
|
+
if (preload) mergedPreloads = mergedPreloads.concat(preload)
|
|
131
|
+
|
|
132
|
+
return uniqunize(mergedPreloads)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
render () {
|
|
136
|
+
const {modelClass, noRecordsAvailableContent, noRecordsFoundContent} = digs(this.props, "modelClass", "noRecordsAvailableContent", "noRecordsFoundContent")
|
|
137
|
+
const {collection, defaultParams, select, selectColumns} = this.props
|
|
138
|
+
const {
|
|
139
|
+
overallCount,
|
|
140
|
+
preload,
|
|
141
|
+
qParams,
|
|
142
|
+
query,
|
|
143
|
+
result,
|
|
144
|
+
models,
|
|
145
|
+
showNoRecordsAvailableContent,
|
|
146
|
+
showNoRecordsFoundContent
|
|
147
|
+
} = digs(
|
|
148
|
+
this.shape,
|
|
149
|
+
"overallCount",
|
|
150
|
+
"preload",
|
|
151
|
+
"qParams",
|
|
152
|
+
"query",
|
|
153
|
+
"result",
|
|
154
|
+
"models",
|
|
155
|
+
"showNoRecordsAvailableContent",
|
|
156
|
+
"showNoRecordsFoundContent"
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
return (
|
|
160
|
+
<div className={this.className()}>
|
|
161
|
+
{preload !== undefined &&
|
|
162
|
+
<CollectionLoader
|
|
163
|
+
abilities={this.abilitiesToLoad()}
|
|
164
|
+
defaultParams={defaultParams}
|
|
165
|
+
collection={collection}
|
|
166
|
+
component={this}
|
|
167
|
+
modelClass={modelClass}
|
|
168
|
+
noRecordsAvailableContent={noRecordsAvailableContent}
|
|
169
|
+
noRecordsFoundContent={noRecordsFoundContent}
|
|
170
|
+
preloads={preload}
|
|
171
|
+
select={selectCalculator({table: this})}
|
|
172
|
+
selectColumns={selectColumns}
|
|
173
|
+
/>
|
|
174
|
+
}
|
|
175
|
+
{showNoRecordsAvailableContent &&
|
|
176
|
+
<div className="live-table--no-records-available-content">
|
|
177
|
+
{noRecordsAvailableContent({models, qParams, overallCount})}
|
|
178
|
+
</div>
|
|
179
|
+
}
|
|
180
|
+
{showNoRecordsFoundContent &&
|
|
181
|
+
<div className="live-table--no-records-found-content">
|
|
182
|
+
{noRecordsFoundContent({models, qParams, overallCount})}
|
|
183
|
+
</div>
|
|
184
|
+
}
|
|
185
|
+
{qParams && query && result && models && !showNoRecordsAvailableContent && !showNoRecordsFoundContent &&
|
|
186
|
+
this.cardOrTable()
|
|
187
|
+
}
|
|
188
|
+
</div>
|
|
189
|
+
)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
abilitiesToLoad () {
|
|
193
|
+
const abilitiesToLoad = {}
|
|
194
|
+
const {abilities, modelClass} = this.props
|
|
195
|
+
const ownAbilities = []
|
|
196
|
+
|
|
197
|
+
if (this.props.destroyEnabled) {
|
|
198
|
+
ownAbilities.push("destroy")
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (this.props.editModelPath) {
|
|
202
|
+
ownAbilities.push("edit")
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (this.props.viewModelPath) {
|
|
206
|
+
ownAbilities.push("show")
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (ownAbilities.length > 0) {
|
|
210
|
+
const modelClassName = digg(modelClass.modelClassData(), "name")
|
|
211
|
+
|
|
212
|
+
abilitiesToLoad[modelClassName] = ownAbilities
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (abilities) {
|
|
216
|
+
for (const modelName in abilities) {
|
|
217
|
+
if (!(modelName in abilitiesToLoad)) {
|
|
218
|
+
abilitiesToLoad[modelName] = []
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
for (const ability of abilities[modelName]) {
|
|
222
|
+
abilitiesToLoad[modelName].push(ability)
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return abilitiesToLoad
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
cardOrTable () {
|
|
231
|
+
const {
|
|
232
|
+
abilities,
|
|
233
|
+
actionsContent,
|
|
234
|
+
appHistory,
|
|
235
|
+
breakPoint,
|
|
236
|
+
card,
|
|
237
|
+
className,
|
|
238
|
+
collection,
|
|
239
|
+
columns,
|
|
240
|
+
columnsContent,
|
|
241
|
+
controls,
|
|
242
|
+
currentUser,
|
|
243
|
+
defaultDateFormatName,
|
|
244
|
+
defaultDateTimeFormatName,
|
|
245
|
+
defaultParams,
|
|
246
|
+
destroyEnabled,
|
|
247
|
+
destroyMessage,
|
|
248
|
+
editModelPath,
|
|
249
|
+
filterCard,
|
|
250
|
+
filterContent,
|
|
251
|
+
filterSubmitButton,
|
|
252
|
+
filterSubmitLabel,
|
|
253
|
+
groupBy,
|
|
254
|
+
header,
|
|
255
|
+
identifier,
|
|
256
|
+
modelClass,
|
|
257
|
+
noRecordsAvailableContent,
|
|
258
|
+
noRecordsFoundContent,
|
|
259
|
+
onModelsLoaded,
|
|
260
|
+
paginateContent,
|
|
261
|
+
paginationComponent,
|
|
262
|
+
preloads,
|
|
263
|
+
queryName,
|
|
264
|
+
select,
|
|
265
|
+
selectColumns,
|
|
266
|
+
viewModelPath,
|
|
267
|
+
...restProps
|
|
268
|
+
} = this.props
|
|
269
|
+
const {models, qParams, query, result} = digs(this.shape, "models", "qParams", "query", "result")
|
|
270
|
+
|
|
271
|
+
let controlsContent, headerContent, PaginationComponent
|
|
272
|
+
|
|
273
|
+
if (controls) {
|
|
274
|
+
controlsContent = controls({models, qParams, query, result})
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (typeof header == "function") {
|
|
278
|
+
headerContent = header({models, qParams, query, result})
|
|
279
|
+
} else if (header) {
|
|
280
|
+
headerContent = header
|
|
281
|
+
} else {
|
|
282
|
+
headerContent = modelClass.modelName().human({count: 2})
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (!paginateContent) {
|
|
286
|
+
if (paginationComponent) {
|
|
287
|
+
PaginationComponent = paginationComponent
|
|
288
|
+
} else {
|
|
289
|
+
PaginationComponent = Paginate
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const TableComponent = this.responsiveComponent("table")
|
|
294
|
+
|
|
295
|
+
return (
|
|
296
|
+
<>
|
|
297
|
+
{filterContent && filterCard &&
|
|
298
|
+
<Card className="live-table--filter-card mb-4">
|
|
299
|
+
{this.filterForm()}
|
|
300
|
+
</Card>
|
|
301
|
+
}
|
|
302
|
+
{filterContent && !filterCard &&
|
|
303
|
+
this.filterForm()
|
|
304
|
+
}
|
|
305
|
+
{card &&
|
|
306
|
+
<Card className={classNames("mb-4", className)} controls={controlsContent} header={headerContent} table={!this.isSmallScreen()} {...restProps}>
|
|
307
|
+
{this.tableContent()}
|
|
308
|
+
</Card>
|
|
309
|
+
}
|
|
310
|
+
{!card &&
|
|
311
|
+
<TableComponent className={className} {...restProps}>
|
|
312
|
+
{this.tableContent()}
|
|
313
|
+
</TableComponent>
|
|
314
|
+
}
|
|
315
|
+
{result && PaginationComponent &&
|
|
316
|
+
<PaginationComponent result={result} />
|
|
317
|
+
}
|
|
318
|
+
{result && paginateContent &&
|
|
319
|
+
paginateContent({result})
|
|
320
|
+
}
|
|
321
|
+
</>
|
|
322
|
+
)
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
filterForm = () => {
|
|
326
|
+
const {filterFormRef, submitFilter, submitFilterDebounce} = digs(this, "filterFormRef", "submitFilter", "submitFilterDebounce")
|
|
327
|
+
const {filterContent, filterSubmitButton} = digs(this.props, "filterContent", "filterSubmitButton")
|
|
328
|
+
const {filterSubmitLabel} = this.props
|
|
329
|
+
const {qParams} = digs(this.shape, "qParams")
|
|
330
|
+
|
|
331
|
+
return (
|
|
332
|
+
<form className="live-table--filter-form" onSubmit={this.onFilterFormSubmit} ref={filterFormRef}>
|
|
333
|
+
{filterContent({
|
|
334
|
+
onFilterChanged: submitFilter,
|
|
335
|
+
onFilterChangedWithDelay: submitFilterDebounce,
|
|
336
|
+
qParams
|
|
337
|
+
})}
|
|
338
|
+
{filterSubmitButton &&
|
|
339
|
+
<input
|
|
340
|
+
className="btn btn-primary live-table--submit-filter-button"
|
|
341
|
+
type="submit"
|
|
342
|
+
value={filterSubmitLabel || I18n.t("js.api_maker_bootstrap.live_table.filter")}
|
|
343
|
+
/>
|
|
344
|
+
}
|
|
345
|
+
</form>
|
|
346
|
+
)
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
tableContent () {
|
|
350
|
+
const {breakPoint} = digs(this.props, "breakPoint")
|
|
351
|
+
const {models, preparedColumns} = digs(this.shape, "models", "preparedColumns")
|
|
352
|
+
const ColumnInHeadComponent = this.columnInHeadComponent()
|
|
353
|
+
const RowComponent = this.rowComponent()
|
|
354
|
+
|
|
355
|
+
let BodyComponent, HeadComponent
|
|
356
|
+
|
|
357
|
+
if (this.isSmallScreen()) {
|
|
358
|
+
BodyComponent = "div"
|
|
359
|
+
HeadComponent = "div"
|
|
360
|
+
} else {
|
|
361
|
+
BodyComponent = "tbody"
|
|
362
|
+
HeadComponent = "thead"
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return (
|
|
366
|
+
<>
|
|
367
|
+
<HeadComponent>
|
|
368
|
+
<RowComponent className="live-table-header-row">
|
|
369
|
+
{this.headersContentFromColumns()}
|
|
370
|
+
<ColumnInHeadComponent />
|
|
371
|
+
</RowComponent>
|
|
372
|
+
</HeadComponent>
|
|
373
|
+
<BodyComponent>
|
|
374
|
+
{models.map((model) =>
|
|
375
|
+
<ModelRow
|
|
376
|
+
breakPoint={breakPoint}
|
|
377
|
+
columnComponent={this.columnComponent()}
|
|
378
|
+
key={model.id()}
|
|
379
|
+
liveTable={this}
|
|
380
|
+
model={model}
|
|
381
|
+
preparedColumns={preparedColumns}
|
|
382
|
+
rowComponent={this.rowComponent()}
|
|
383
|
+
/>
|
|
384
|
+
)}
|
|
385
|
+
</BodyComponent>
|
|
386
|
+
</>
|
|
387
|
+
)
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
className () {
|
|
391
|
+
const classNames = ["component-api-maker-live-table"]
|
|
392
|
+
|
|
393
|
+
if (this.props.className)
|
|
394
|
+
classNames.push(this.props.className)
|
|
395
|
+
|
|
396
|
+
return classNames.join(" ")
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
columnProps(column) {
|
|
400
|
+
const props = {}
|
|
401
|
+
|
|
402
|
+
if (column.textCenter) props["data-text-align"] = "center"
|
|
403
|
+
if (column.textRight) props["data-text-align"] = "right"
|
|
404
|
+
|
|
405
|
+
return props
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
isSmallScreen() {
|
|
409
|
+
if (this.props.breakPoint == "xs" || this.props.breakPoint == "sm") return true
|
|
410
|
+
|
|
411
|
+
return false
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
columnComponent = () => this.responsiveComponent("td")
|
|
415
|
+
columnInHeadComponent = () => this.responsiveComponent("th")
|
|
416
|
+
responsiveComponent = (largeComponent) => this.isSmallScreen() ? "div" : largeComponent
|
|
417
|
+
rowComponent = () => this.responsiveComponent("tr")
|
|
418
|
+
|
|
419
|
+
headersContentFromColumns () {
|
|
420
|
+
const {preparedColumns, query} = digs(this.shape, "preparedColumns", "query")
|
|
421
|
+
const ColumnInHeadComponent = this.columnInHeadComponent()
|
|
422
|
+
|
|
423
|
+
return preparedColumns?.map(({column, tableSettingColumn}) => columnVisible(column, tableSettingColumn) &&
|
|
424
|
+
<ColumnInHeadComponent
|
|
425
|
+
className={classNames(...this.headerClassNameForColumn(column))}
|
|
426
|
+
data-identifier={tableSettingColumn.identifier()}
|
|
427
|
+
key={tableSettingColumn.identifier()}
|
|
428
|
+
{...this.columnProps(column)}
|
|
429
|
+
>
|
|
430
|
+
{tableSettingColumn.hasSortKey() && query &&
|
|
431
|
+
<SortLink attribute={tableSettingColumn.sortKey()} query={query} title={this.headerLabelForColumn(column)} />
|
|
432
|
+
}
|
|
433
|
+
{(!tableSettingColumn.hasSortKey() || !query) &&
|
|
434
|
+
this.headerLabelForColumn(column)
|
|
435
|
+
}
|
|
436
|
+
</ColumnInHeadComponent>
|
|
437
|
+
)
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
headerClassNameForColumn (column) {
|
|
441
|
+
const classNames = ["live-table-header"]
|
|
442
|
+
|
|
443
|
+
if (column.commonProps && column.commonProps.className) classNames.push(column.commonProps.className)
|
|
444
|
+
if (column.headerProps && column.headerProps.className) classNames.push(column.headerProps.className)
|
|
445
|
+
|
|
446
|
+
return classNames
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
headerLabelForColumn (column) {
|
|
450
|
+
const {modelClass} = digs(this.props, "modelClass")
|
|
451
|
+
|
|
452
|
+
if ("label" in column) {
|
|
453
|
+
if (typeof column.label == "function") {
|
|
454
|
+
return column.label()
|
|
455
|
+
} else {
|
|
456
|
+
return column.label
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
let currentModelClass = modelClass
|
|
461
|
+
|
|
462
|
+
// Calculate current model class through path
|
|
463
|
+
if (column.path) {
|
|
464
|
+
for (const pathPart of column.path) {
|
|
465
|
+
const relationships = digg(currentModelClass.modelClassData(), "relationships")
|
|
466
|
+
const relationship = relationships.find((relationshipInArray) => relationshipInArray.name == inflection.underscore(pathPart))
|
|
467
|
+
|
|
468
|
+
currentModelClass = modelClassRequire(digg(relationship, "className"))
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
if (column.attribute) return currentModelClass.humanAttributeName(column.attribute)
|
|
473
|
+
|
|
474
|
+
throw new Error("No 'label' or 'attribute' was given")
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
onFilterFormSubmit = (e) => {
|
|
478
|
+
e.preventDefault()
|
|
479
|
+
this.submitFilter()
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
submitFilter = () => {
|
|
483
|
+
const {filterFormRef} = digs(this, "filterFormRef")
|
|
484
|
+
const filterForm = digg(filterFormRef, "current")
|
|
485
|
+
const {appHistory} = this.props
|
|
486
|
+
const qParams = Params.serializeForm(filterForm)
|
|
487
|
+
const {queryQName} = this.shape
|
|
488
|
+
const changeParamsParams = {}
|
|
489
|
+
|
|
490
|
+
changeParamsParams[queryQName] = qParams
|
|
491
|
+
|
|
492
|
+
Params.changeParams(changeParamsParams, {appHistory})
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
submitFilterDebounce = debounce(digg(this, "submitFilter"))
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
export default withBreakpoint(ApiMakerTable)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import apiMakerConfig from "@kaspernj/api-maker/src/config.mjs"
|
|
2
|
+
import React from "react"
|
|
3
|
+
|
|
4
|
+
export default (WrappedComponent) => class WithBreakPoint extends React.Component {
|
|
5
|
+
state = {
|
|
6
|
+
breakPoint: this.calculateBreakPoint()
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
calculateBreakPoint() {
|
|
10
|
+
const windowWidth = window.innerWidth
|
|
11
|
+
|
|
12
|
+
for (const breakPointData of apiMakerConfig.getBreakPoints()) {
|
|
13
|
+
const breakPoint = breakPointData[0]
|
|
14
|
+
const width = breakPointData[1]
|
|
15
|
+
|
|
16
|
+
if (windowWidth >= width) return breakPoint
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
throw new Error(`Couldn't not find breakPoint from window width: ${windowWidth}`)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
constructor(props) {
|
|
23
|
+
super(props)
|
|
24
|
+
this.onCalled = this.onCalled.bind(this)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
componentDidMount () {
|
|
28
|
+
window.addEventListener("resize", this.onCalled)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
componentWillUnmount () {
|
|
32
|
+
window.removeEventListener("resize", this.onCalled)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
render() {
|
|
36
|
+
return (
|
|
37
|
+
<WrappedComponent breakPoint={this.state.breakPoint} {...this.props} />
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
onCalled = () => {
|
|
42
|
+
const breakPoint = this.calculateBreakPoint()
|
|
43
|
+
|
|
44
|
+
if (breakPoint != this.state.breakPoint) {
|
|
45
|
+
this.setState({breakPoint})
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|