@kaspernj/api-maker 1.0.417 → 1.0.419

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.417",
3
+ "version": "1.0.419",
4
4
  "type": "module",
5
5
  "description": "",
6
6
  "main": "index.js",
@@ -6,6 +6,7 @@ import PropTypes from "prop-types"
6
6
  import {memo, useMemo} from "react"
7
7
  import {shapeComponent, ShapeComponent} from "set-state-compare/src/shape-component.js"
8
8
  import strftime from "strftime"
9
+ import useI18n from "i18n-on-steroids/src/use-i18n.mjs"
9
10
 
10
11
  export default memo(shapeComponent(class ApiMakerBootstrapAttributeRow extends ShapeComponent {
11
12
  static defaultProps = {
@@ -23,6 +24,9 @@ export default memo(shapeComponent(class ApiMakerBootstrapAttributeRow extends S
23
24
  }
24
25
 
25
26
  setup() {
27
+ const {t} = useI18n({namespace: "js.api_maker.attribute_row"})
28
+
29
+ this.t = t
26
30
  this.attribute = useMemo(
27
31
  () => {
28
32
  if (this.props.attribute) {
@@ -88,9 +92,9 @@ export default memo(shapeComponent(class ApiMakerBootstrapAttributeRow extends S
88
92
  } else if (value instanceof Date) {
89
93
  return strftime("%Y-%m-%d %H:%M", value)
90
94
  } else if (typeof value === "boolean") {
91
- if (value) return I18n.t("js.shared.yes", {defaultValue: "Yes"})
95
+ if (value) return this.t("js.shared.yes", {defaultValue: "Yes"})
92
96
 
93
- return I18n.t("js.shared.no", {defaultValue: "No"})
97
+ return this.t("js.shared.no", {defaultValue: "No"})
94
98
  } else if (MoneyFormatter.isMoney(value)) {
95
99
  return MoneyFormatter.format(value)
96
100
  } else {
@@ -37,6 +37,15 @@ export default memo(shapeComponent(class ApiMakerTableHeaderColumn extends BaseC
37
37
  const {defaultParams} = table.props
38
38
  const {styleForHeader, styleForHeaderText} = table.tt
39
39
  const {query} = digs(table.collection, "query")
40
+ const columnProps = table.columnProps(column)
41
+ const {style, ...restColumnProps} = columnProps
42
+ const actualStyle = Object.assign(
43
+ {
44
+ cursor: resizing ? "col-resize" : undefined,
45
+ width
46
+ },
47
+ style
48
+ )
40
49
 
41
50
  return (
42
51
  <Header
@@ -45,11 +54,8 @@ export default memo(shapeComponent(class ApiMakerTableHeaderColumn extends BaseC
45
54
  identifier: tableSettingColumn.identifier()
46
55
  }}
47
56
  onLayout={this.tt.onLayout}
48
- style={styleForHeader({style: {
49
- cursor: resizing ? "col-resize" : undefined,
50
- width: `${width}%`
51
- }})}
52
- {...table.columnProps(column)}
57
+ style={styleForHeader({style: actualStyle})}
58
+ {...restColumnProps}
53
59
  >
54
60
  <View style={{display: "flex", flexDirection: "row", alignItems: "center"}}>
55
61
  {tableSettingColumn.hasSortKey() && query &&
@@ -0,0 +1,64 @@
1
+ import {Text, View} from "react-native"
2
+ import BaseComponent from "../base-component"
3
+ import classNames from "classnames"
4
+ import Column from "./components/column"
5
+ import ColumnContent from "./column-content"
6
+ import columnIdentifier from "./column-identifier.mjs"
7
+ import PropTypes from "prop-types"
8
+ import propTypesExact from "prop-types-exact"
9
+ import {memo} from "react"
10
+ import {shapeComponent} from "set-state-compare/src/shape-component"
11
+
12
+ export default memo(shapeComponent(class ApiMakerTableModelColumn extends BaseComponent {
13
+ static propTypes = propTypesExact({
14
+ column: PropTypes.object.isRequired,
15
+ columnIndex: PropTypes.number.isRequired,
16
+ even: PropTypes.bool.isRequired,
17
+ isSmallScreen: PropTypes.bool.isRequired,
18
+ model: PropTypes.object.isRequired,
19
+ table: PropTypes.object.isRequired,
20
+ tableSettingColumn: PropTypes.object.isRequired,
21
+ width: PropTypes.number.isRequired
22
+ })
23
+
24
+ render() {
25
+ const {column, columnIndex, even, isSmallScreen, model, table, width} = this.props
26
+ const columnProps = table.columnProps(column)
27
+ const {style, ...restColumnProps} = columnProps
28
+ const actualStyle = Object.assign(
29
+ table.styleForColumn({column, columnIndex, even, style: {width}}),
30
+ style
31
+ )
32
+
33
+ return (
34
+ <Column
35
+ dataSet={{
36
+ class: classNames(this.columnClassNamesForColumn(column)),
37
+ identifier: columnIdentifier(column)
38
+ }}
39
+ style={actualStyle}
40
+ {...restColumnProps}
41
+ >
42
+ {isSmallScreen &&
43
+ <View dataSet={{class: "table--column-label"}}>
44
+ <Text>
45
+ {table.headerLabelForColumn(column)}
46
+ </Text>
47
+ </View>
48
+ }
49
+ <View dataSet={{class: "table--column-value"}}>
50
+ {new ColumnContent({column, model, table}).content()}
51
+ </View>
52
+ </Column>
53
+ )
54
+ }
55
+
56
+ columnClassNamesForColumn(column) {
57
+ const classNames = ["table--column"]
58
+
59
+ if (column.commonProps && column.commonProps.className) classNames.push(column.commonProps.className)
60
+ if (column.columnProps && column.columnProps.className) classNames.push(column.columnProps.className)
61
+
62
+ return classNames
63
+ }
64
+ }))
@@ -1,14 +1,13 @@
1
- import {Pressable, Text, View} from "react-native"
1
+ import {Pressable} from "react-native"
2
2
  import BaseComponent from "../base-component"
3
- import classNames from "classnames"
4
3
  import Column from "./components/column"
5
- import ColumnContent from "./column-content"
6
4
  import columnIdentifier from "./column-identifier.mjs"
7
5
  import columnVisible from "./column-visible.mjs"
8
6
  import FontAwesomeIcon from "react-native-vector-icons/FontAwesome"
9
7
  import * as inflection from "inflection"
10
8
  import modelCallbackArgs from "./model-callback-args.mjs"
11
9
  import Link from "../link"
10
+ import ModelColumn from "./model-column"
12
11
  import PropTypes from "prop-types"
13
12
  import propTypesExact from "prop-types-exact"
14
13
  import Row from "./components/row"
@@ -86,39 +85,21 @@ export default memo(shapeComponent(class ApiMakerBootStrapLiveTableModelRow exte
86
85
  )
87
86
  }
88
87
 
89
- columnClassNamesForColumn(column) {
90
- const classNames = ["table--column"]
91
-
92
- if (column.commonProps && column.commonProps.className) classNames.push(column.commonProps.className)
93
- if (column.columnProps && column.columnProps.className) classNames.push(column.columnProps.className)
94
-
95
- return classNames
96
- }
97
-
98
88
  columnsContentFromColumns(model, even) {
99
89
  const {isSmallScreen, table, preparedColumns} = this.p
100
90
 
101
91
  return preparedColumns?.map(({column, tableSettingColumn, width}, columnIndex) => columnVisible(column, tableSettingColumn) &&
102
- <Column
103
- dataSet={{
104
- class: classNames(this.columnClassNamesForColumn(column)),
105
- identifier: columnIdentifier(column)
106
- }}
92
+ <ModelColumn
93
+ column={column}
94
+ columnIndex={columnIndex}
95
+ even={even}
96
+ isSmallScreen={isSmallScreen}
107
97
  key={columnIdentifier(column)}
108
- style={table.styleForColumn({column, columnIndex, even, style: {width: `${width}%`}})}
109
- {...table.columnProps(column)}
110
- >
111
- {isSmallScreen &&
112
- <View dataSet={{class: "table--column-label"}}>
113
- <Text>
114
- {table.headerLabelForColumn(column)}
115
- </Text>
116
- </View>
117
- }
118
- <View dataSet={{class: "table--column-value"}}>
119
- {new ColumnContent({column, model, table}).content()}
120
- </View>
121
- </Column>
98
+ model={model}
99
+ table={table}
100
+ tableSettingColumn={tableSettingColumn}
101
+ width={width}
102
+ />
122
103
  )
123
104
  }
124
105
 
@@ -4,7 +4,7 @@ import PropTypes from "prop-types"
4
4
  import propTypesExact from "prop-types-exact"
5
5
  import {memo, useEffect, useRef} from "react"
6
6
  import {shapeComponent} from "set-state-compare/src/shape-component.js"
7
- import {View} from "react-native"
7
+ import {Text, View} from "react-native"
8
8
 
9
9
  export default memo(shapeComponent(class ColumnRow extends BaseComponent {
10
10
  static propTypes = propTypesExact({
@@ -43,7 +43,9 @@ export default memo(shapeComponent(class ColumnRow extends BaseComponent {
43
43
  type="checkbox"
44
44
  {...checkboxProps}
45
45
  />
46
- {table.headerLabelForColumn(column)}
46
+ <Text>
47
+ {table.headerLabelForColumn(column)}
48
+ </Text>
47
49
  </label>
48
50
  </View>
49
51
  )
@@ -16,10 +16,6 @@ export default memo(shapeComponent(class ApiMakerTableSettings extends BaseCompo
16
16
 
17
17
  setup() {
18
18
  this.rootRef = useRef()
19
-
20
- this.useStates({
21
- fixedTableLayout: this.tableSetting().fixedTableLayout()
22
- })
23
19
  }
24
20
 
25
21
  tableSetting = () => this.p.table.s.tableSetting
@@ -1,6 +1,5 @@
1
- import "./style"
2
1
  import {digg, digs} from "diggerize"
3
- import {Pressable, View} from "react-native"
2
+ import {Pressable, StyleSheet, Text, View} from "react-native"
4
3
  import BaseComponent from "../base-component"
5
4
  import Card from "../bootstrap/card"
6
5
  import classNames from "classnames"
@@ -28,15 +27,25 @@ import TableSettings from "./table-settings"
28
27
  import uniqunize from "uniqunize"
29
28
  import useBreakpoint from "../use-breakpoint"
30
29
  import useCollection from "../use-collection"
30
+ import useI18n from "i18n-on-steroids/src/use-i18n.mjs"
31
+ import useModelEvent from "../use-model-event.js"
31
32
  import useQueryParams from "on-location-changed/src/use-query-params.js"
32
33
  import Widths from "./widths"
33
34
 
34
35
  const paginationOptions = [30, 60, 90, ["All", "all"]]
35
36
  const WorkerPluginsCheckAllCheckbox = React.lazy(() => import("./worker-plugins-check-all-checkbox"))
37
+ const styleSheet = StyleSheet.create({
38
+ flatList: {
39
+ border: "1px solid #dbdbdb",
40
+ borderRadius: 5,
41
+ overflowX: "auto"
42
+ }
43
+ })
36
44
 
37
45
  export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
38
46
  static defaultProps = {
39
47
  card: true,
48
+ currentUser: null,
40
49
  destroyEnabled: true,
41
50
  filterCard: true,
42
51
  filterSubmitButton: true,
@@ -85,14 +94,18 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
85
94
  workplace: PropTypes.bool.isRequired
86
95
  }
87
96
 
97
+ tableSetting = null
98
+
88
99
  setup() {
100
+ const {t} = useI18n({namespace: "js.api_maker.table"})
89
101
  const {breakpoint} = useBreakpoint()
90
102
  const queryParams = useQueryParams()
91
103
 
92
104
  this.setInstance({
93
105
  breakpoint,
94
106
  filterFormRef: useRef(),
95
- isSmallScreen: breakpoint == "xs" || breakpoint == "sm"
107
+ isSmallScreen: breakpoint == "xs" || breakpoint == "sm",
108
+ t
96
109
  })
97
110
 
98
111
  const collectionKey = digg(this.p.modelClass.modelClassData(), "collectionKey")
@@ -106,7 +119,7 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
106
119
  this.useStates({
107
120
  columns: columnsAsArray,
108
121
  currentWorkplace: undefined,
109
- flatListWidth: undefined,
122
+ currentWorkplaceCount: null,
110
123
  identifier: () => this.props.identifier || `${collectionKey}-default`,
111
124
  lastUpdate: () => new Date(),
112
125
  preload: undefined,
@@ -119,17 +132,28 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
119
132
  showFilters: () => Boolean(queryParams[querySName]),
120
133
  showSettings: false,
121
134
  tableSetting: undefined,
135
+ tableSettingLoaded: false,
122
136
  tableSettingFullCacheKey: undefined,
137
+ width: undefined,
123
138
  widths: null
124
139
  })
125
140
 
126
141
  useMemo(() => {
127
- this.loadTableSetting()
128
-
129
142
  if (this.props.workplace) {
130
- this.loadCurrentWorkplace()
143
+ this.loadCurrentWorkplace().then(() => {
144
+ this.loadCurrentWorkplaceCount()
145
+ })
146
+ }
147
+ }, [this.p.currentUser?.id()])
148
+
149
+ useMemo(() => {
150
+ if (!this.tt.tableSetting && this.s.width) {
151
+ this.loadTableSetting()
131
152
  }
132
- }, [])
153
+ }, [this.p.currentUser?.id(), this.s.width])
154
+
155
+ useModelEvent(this.s.currentWorkplace, "workplace_links_created", this.tt.onLinksCreated)
156
+ useModelEvent(this.s.currentWorkplace, "workplace_links_destroyed", this.tt.onLinksDestroyed)
133
157
 
134
158
  let collectionReady = true
135
159
  let select
@@ -169,18 +193,31 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
169
193
  this.setState({currentWorkplace})
170
194
  }
171
195
 
196
+ async loadCurrentWorkplaceCount() {
197
+ const WorkplaceLink = modelClassRequire("WorkplaceLink")
198
+ const currentWorkplaceCount = await WorkplaceLink
199
+ .ransack({
200
+ resource_type_eq: this.p.modelClass.modelClassData().name,
201
+ workplace_id_eq: this.s.currentWorkplace.id()
202
+ })
203
+ .count()
204
+
205
+ this.setState({currentWorkplaceCount})
206
+ }
207
+
172
208
  async loadTableSetting() {
173
209
  this.tableSettings = new TableSettings({table: this})
174
210
 
175
211
  const tableSetting = await this.tableSettings.loadExistingOrCreateTableSettings()
176
212
  const {columns, preload} = this.tableSettings.preparedColumns(tableSetting)
177
- const {flatListWidth} = this.s
178
- const widths = new Widths({columns, flatListWidth, table: this})
213
+ const {width} = this.s
214
+ const widths = new Widths({columns, table: this, width})
179
215
 
180
216
  this.setState({
181
217
  preparedColumns: columns,
182
218
  preload: this.mergedPreloads(preload),
183
219
  tableSetting,
220
+ tableSettingLoaded: true,
184
221
  tableSettingFullCacheKey: tableSetting.fullCacheKey(),
185
222
  widths
186
223
  })
@@ -237,7 +274,7 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
237
274
  }
238
275
 
239
276
  return (
240
- <div className={this.className()} style={this.props.styles?.container}>
277
+ <View dataSet={{class: this.className()}} onLayout={this.tt.onContainerLayout} style={this.props.styles?.container}>
241
278
  {showNoRecordsAvailableContent &&
242
279
  <div className="live-table--no-records-available-content">
243
280
  {noRecordsAvailableContent({models, qParams, overallCount})}
@@ -254,7 +291,7 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
254
291
  {qParams && query && result && models && !showNoRecordsAvailableContent && !showNoRecordsFoundContent &&
255
292
  this.cardOrTable()
256
293
  }
257
- </div>
294
+ </View>
258
295
  )
259
296
  }
260
297
 
@@ -354,10 +391,9 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
354
391
  extraData={this.s.lastUpdate}
355
392
  keyExtractor={this.tt.keyExtrator}
356
393
  ListHeaderComponent={this.tt.listHeaderComponent}
357
- onLayout={this.tt.onFlatListLayout}
358
394
  renderItem={this.tt.renderItem}
359
395
  showsHorizontalScrollIndicator
360
- style={{border: "1px solid #dbdbdb", borderRadius: 5, overflowX: "auto"}}
396
+ style={styleSheet.flatList}
361
397
  {...restProps}
362
398
  />
363
399
  )
@@ -394,12 +430,36 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
394
430
  )
395
431
  }
396
432
 
397
- onFlatListLayout = (e) => {
433
+ onContainerLayout = (e) => {
398
434
  const {width} = e.nativeEvent.layout
399
435
  const {widths} = this.s
400
436
 
401
- this.setState({flatListWidth: width})
402
- widths.flatListWidth = width
437
+ this.setState({width})
438
+ if (widths) widths.tableWidth = width
439
+ }
440
+
441
+ onLinksCreated = ({args}) => {
442
+ const modelClassName = this.p.modelClass.modelClassData().name
443
+
444
+ if (args.created[modelClassName]) {
445
+ const amountCreated = args.created[modelClassName].length
446
+
447
+ this.setState((prevState) => ({
448
+ currentWorkplaceCount: prevState.currentWorkplaceCount + amountCreated
449
+ }))
450
+ }
451
+ }
452
+
453
+ onLinksDestroyed = ({args}) => {
454
+ const modelClassName = this.p.modelClass.modelClassData().name
455
+
456
+ if (args.destroyed[modelClassName]) {
457
+ const amountDestroyed = args.destroyed[modelClassName].length
458
+
459
+ this.setState((prevState) => ({
460
+ currentWorkplaceCount: prevState.currentWorkplaceCount - amountDestroyed
461
+ }))
462
+ }
403
463
  }
404
464
 
405
465
  keyExtrator = (model) => model.id()
@@ -425,7 +485,7 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
425
485
  className="btn btn-primary live-table--submit-filter-button"
426
486
  type="submit"
427
487
  style={{marginTop: "8px"}}
428
- value={filterSubmitLabel || I18n.t("js.api_maker_bootstrap.live_table.filter")}
488
+ value={filterSubmitLabel || this.t(".filter", {defaultValue: "Filter"})}
429
489
  />
430
490
  }
431
491
  </form>
@@ -449,16 +509,14 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
449
509
  }
450
510
 
451
511
  listHeaderComponent = () => {
452
- const {workplace} = this.p
453
- const {currentWorkplace} = this.s
454
512
  const {query} = digs(this.collection, "query")
455
513
 
456
514
  return (
457
515
  <Row dataSet={{class: "live-table-header-row"}} style={this.styleForRow()}>
458
- {workplace && currentWorkplace &&
516
+ {this.p.workplace && this.s.currentWorkplace &&
459
517
  <Header style={this.styleForHeader({style: {width: 41}})}>
460
518
  <WorkerPluginsCheckAllCheckbox
461
- currentWorkplace={currentWorkplace}
519
+ currentWorkplace={this.s.currentWorkplace}
462
520
  query={query}
463
521
  style={{marginHorizontal: "auto"}}
464
522
  />
@@ -473,6 +531,16 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
473
531
  renderItem = ({index, item: model}) => {
474
532
  const {preparedColumns, tableSettingFullCacheKey} = this.s
475
533
 
534
+ if (!this.s.tableSettingLoaded) {
535
+ return (
536
+ <View>
537
+ <Text>
538
+ Loading...
539
+ </Text>
540
+ </View>
541
+ )
542
+ }
543
+
476
544
  return (
477
545
  <ModelRow
478
546
  cacheKey={model.cacheKey()}
@@ -492,7 +560,8 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
492
560
  const defaultStyle = {
493
561
  justifyContent: "center",
494
562
  padding: 8,
495
- backgroundColor: even ? "#f5f5f5" : undefined
563
+ backgroundColor: even ? "#f5f5f5" : undefined,
564
+ overflow: "hidden"
496
565
  }
497
566
 
498
567
  if (type == "actions") {
@@ -576,24 +645,31 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
576
645
  const totalCount = result.totalCount()
577
646
  const perPage = result.perPage()
578
647
  const to = Math.min(currentPage * perPage, totalCount)
579
- const defaultValue = "Showing %{from} to %{to} out of %{total_count} total"
648
+ const defaultValue = "Showing %{from} to %{to} out of %{total_count} total."
580
649
  let from = ((currentPage - 1) * perPage) + 1
581
650
 
582
651
  if (to === 0) from = 0
583
652
 
584
653
  return (
585
- <View style={{flexDirection: "row", justifyContent: "space-between", marginTop: "10px"}}>
586
- <div className="showing-counts">
587
- {I18n.t("js.api_maker.table.showing_from_to_out_of_total", {defaultValue, from, to, total_count: totalCount})}
588
- </div>
589
- <div>
654
+ <View style={{flexDirection: "row", justifyContent: "space-between", marginTop: 10}}>
655
+ <View dataSet={{class: "showing-counts"}} style={{flexDirection: "row"}}>
656
+ <Text>
657
+ {this.t(".showing_from_to_out_of_total", {defaultValue, from, to, total_count: totalCount})}
658
+ </Text>
659
+ {this.p.workplace && this.s.currentWorkplaceCount !== null &&
660
+ <Text style={{marginLeft: 3}}>
661
+ {this.t(".x_selected", {defaultValue: "%{selected} selected.", selected: this.s.currentWorkplaceCount})}
662
+ </Text>
663
+ }
664
+ </View>
665
+ <View>
590
666
  <Select
591
667
  className="per-page-select"
592
668
  defaultValue={perPage}
593
669
  onChange={this.tt.onPerPageChanged}
594
670
  options={paginationOptions}
595
671
  />
596
- </div>
672
+ </View>
597
673
  </View>
598
674
  )
599
675
  }
@@ -611,8 +687,15 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
611
687
  columnProps(column) {
612
688
  const props = {}
613
689
 
614
- if (column.textCenter) props["data-text-align"] = "center"
615
- if (column.textRight) props["data-text-align"] = "right"
690
+ if (column.textCenter) {
691
+ props.style ||= {}
692
+ props.style.textAlign = "center"
693
+ }
694
+
695
+ if (column.textRight) {
696
+ props.style ||= {}
697
+ props.style.textAlign = "right"
698
+ }
616
699
 
617
700
  return props
618
701
  }
@@ -639,7 +722,7 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
639
722
  />
640
723
  )
641
724
 
642
- headerClassNameForColumn (column) {
725
+ headerClassNameForColumn(column) {
643
726
  const classNames = ["live-table-header"]
644
727
 
645
728
  if (column.commonProps && column.commonProps.className) classNames.push(column.commonProps.className)
@@ -648,7 +731,7 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
648
731
  return classNames
649
732
  }
650
733
 
651
- headerLabelForColumn (column) {
734
+ headerLabelForColumn(column) {
652
735
  const {modelClass} = this.p
653
736
 
654
737
  if ("label" in column) {
@@ -1,28 +1,28 @@
1
1
  import {digg} from "diggerize"
2
2
 
3
3
  export default class TableWidths {
4
- constructor({columns, flatListWidth, table}) {
4
+ constructor({columns, table, width}) {
5
5
  this.columns = columns
6
- this.flatListWidth = flatListWidth
6
+ this.tableWidth = width
7
7
  this.table = table
8
8
  this.setWidths()
9
9
  }
10
10
 
11
11
  setWidths() {
12
- let widthLeft = 100.0
13
-
14
12
  this.columnsWidths = {}
15
13
 
14
+ let widthLeft = this.tableWidth
16
15
  const updateData = []
17
16
 
18
17
  // Set widths that are defined
19
18
  for (const columnIndex in this.columns) {
20
- const column = this.columns[columnIndex].tableSettingColumn
19
+ const column = this.columns[columnIndex]
20
+ const tableSettingColumn = column.tableSettingColumn
21
21
 
22
- if (column.hasWidth()) {
23
- this.columns[columnIndex].width = column.width()
22
+ if (tableSettingColumn.hasWidth()) {
23
+ column.width = tableSettingColumn.width()
24
24
 
25
- widthLeft -= column.width()
25
+ widthLeft -= tableSettingColumn.width()
26
26
  }
27
27
  }
28
28
 
@@ -36,21 +36,26 @@ export default class TableWidths {
36
36
 
37
37
  // Set widths of columns without
38
38
  for (const columnIndex in this.columns) {
39
- const column = this.columns[columnIndex].tableSettingColumn
39
+ const column = this.columns[columnIndex]
40
+ const tableSettingColumn = column.tableSettingColumn
41
+
42
+ if (!tableSettingColumn.hasWidth()) {
43
+ let newWidth = widthLeft / amountOfColumns
40
44
 
41
- if (!column.hasWidth()) {
42
- const newWidth = widthLeft / amountOfColumns
45
+ if (newWidth < 200) newWidth = 200
43
46
 
44
- this.columns[columnIndex].width = newWidth
47
+ column.width = newWidth
45
48
 
46
49
  updateData << {
47
- id: column.id(),
50
+ id: tableSettingColumn.id(),
48
51
  width: newWidth
49
52
  }
50
53
  }
51
54
  }
52
55
 
53
- // FIXME: Should update the columns on the backend if anything changed
56
+ if (updateData.length > 0) {
57
+ // FIXME: Should update the columns on the backend if anything changed
58
+ }
54
59
  }
55
60
 
56
61
  getWidthOfColumn(identifier) {
@@ -66,12 +71,8 @@ export default class TableWidths {
66
71
 
67
72
  if (!column) throw new Error(`No such column: ${identifier}`)
68
73
 
69
- const widthPercent = (width / this.flatListWidth) * 100
70
-
71
- column.width = widthPercent
74
+ column.width = width
72
75
 
73
76
  this.table.setState({lastUpdate: new Date()})
74
-
75
- // FIXME: Should reduce / enlarge sibling columns to keep a 100% fit
76
77
  }
77
78
  }
@@ -1,15 +1,16 @@
1
+ import BaseComponent from "../base-component"
1
2
  import classNames from "classnames"
2
3
  import {digg} from "diggerize"
3
- import EventConnection from "../event-connection"
4
4
  import modelClassRequire from "../model-class-require.mjs"
5
5
  import PropTypes from "prop-types"
6
6
  import PropTypesExact from "prop-types-exact"
7
7
  import {memo, useMemo} from "react"
8
- import {shapeComponent, ShapeComponent} from "set-state-compare/src/shape-component"
8
+ import {shapeComponent} from "set-state-compare/src/shape-component"
9
+ import useModelEvent from "../use-model-event.js"
9
10
 
10
11
  const Workplace = modelClassRequire("Workplace")
11
12
 
12
- export default memo(shapeComponent(class ApiMakerTableWorkerPluginsCheckbox extends ShapeComponent {
13
+ export default memo(shapeComponent(class ApiMakerTableWorkerPluginsCheckbox extends BaseComponent {
13
14
  static propTypes = PropTypesExact({
14
15
  currentWorkplace: PropTypes.object,
15
16
  model: PropTypes.object.isRequired,
@@ -25,6 +26,9 @@ export default memo(shapeComponent(class ApiMakerTableWorkerPluginsCheckbox exte
25
26
  useMemo(() => {
26
27
  this.loadCurrentLink()
27
28
  }, [])
29
+
30
+ useModelEvent(this.p.currentWorkplace, "workplace_links_created", this.tt.onLinksCreated)
31
+ useModelEvent(this.p.currentWorkplace, "workplace_links_destroyed", this.tt.onLinksDestroyed)
28
32
  }
29
33
 
30
34
  async loadCurrentLink() {
@@ -39,7 +43,7 @@ export default memo(shapeComponent(class ApiMakerTableWorkerPluginsCheckbox exte
39
43
  }
40
44
 
41
45
  render() {
42
- const {className, currentWorkplace, model, style} = this.props
46
+ const {className, model, style} = this.props
43
47
  const {checked, linkLoaded} = this.state
44
48
 
45
49
  if (!linkLoaded) {
@@ -47,23 +51,15 @@ export default memo(shapeComponent(class ApiMakerTableWorkerPluginsCheckbox exte
47
51
  }
48
52
 
49
53
  return (
50
- <>
51
- {currentWorkplace &&
52
- <>
53
- <EventConnection event="workplace_links_created" model={currentWorkplace} onCall={this.onLinksCreated} />
54
- <EventConnection event="workplace_links_destroyed" model={currentWorkplace} onCall={this.onLinksDestroyed} />
55
- </>
56
- }
57
- <input
58
- checked={checked}
59
- className={classNames("api-maker--table--worker-plugins-checkbox", className)}
60
- data-checked={checked}
61
- data-model-id={model.id()}
62
- onChange={this.tt.onCheckedChanged}
63
- style={style}
64
- type="checkbox"
65
- />
66
- </>
54
+ <input
55
+ checked={checked}
56
+ className={classNames("api-maker--table--worker-plugins-checkbox", className)}
57
+ data-checked={checked}
58
+ data-model-id={model.id()}
59
+ onChange={this.tt.onCheckedChanged}
60
+ style={style}
61
+ type="checkbox"
62
+ />
67
63
  )
68
64
  }
69
65
 
@@ -0,0 +1,60 @@
1
+ import {useCallback, useLayoutEffect, useMemo} from "react"
2
+ import debounceFunction from "debounce"
3
+ import ModelEvents from "./model-events.mjs"
4
+ import useShape from "set-state-compare/src/use-shape.js"
5
+
6
+ const apiMakerUseModelEvent = (model, event, onCallback, props) => {
7
+ const {active = true, debounce, onConnected, ...restProps} = props || {}
8
+
9
+ if (Object.keys(restProps).length > 0) {
10
+ throw new Error(`Unknown props given to apiMakerUseModelEvent: ${Object.keys(restProps).join(", ")}`)
11
+ }
12
+
13
+ const s = useShape({active, debounce, model, onCallback})
14
+
15
+ const debounceCallback = useMemo(() => {
16
+ if (typeof debounce == "number") {
17
+ return debounceFunction(s.p.onCallback, debounce)
18
+ } else {
19
+ return debounceFunction(s.p.onCallback)
20
+ }
21
+ }, [debounce])
22
+
23
+ s.updateMeta({debounceCallback})
24
+
25
+ const onCallbackCallback = useCallback((...args) => {
26
+ if (!s.p.active) {
27
+ return
28
+ }
29
+
30
+ if (s.p.debounce) {
31
+ s.m.debounceCallback(...args)
32
+ } else {
33
+ s.p.onCallback(...args)
34
+ }
35
+ }, [])
36
+
37
+ useLayoutEffect(() => {
38
+ let connectEvent, onConnectedListener
39
+
40
+ if (model) {
41
+ connectEvent = ModelEvents.connect(model, event, onCallbackCallback)
42
+
43
+ if (onConnected) {
44
+ onConnectedListener = connectEvent.events.addListener("connected", onConnected)
45
+ }
46
+ }
47
+
48
+ return () => {
49
+ if (onConnectedListener) {
50
+ connectEvent.events.removeListener("connected", onConnected)
51
+ }
52
+
53
+ if (connectEvent) {
54
+ connectEvent.unsubscribe()
55
+ }
56
+ }
57
+ }, [model?.id()])
58
+ }
59
+
60
+ export default apiMakerUseModelEvent
@@ -1,76 +0,0 @@
1
- @import "./variables";
2
-
3
- .api-maker--table {
4
- &[data-fixed-table-layout="true"] {
5
- table {
6
- table-layout: fixed;
7
- }
8
- }
9
-
10
- .live-table-header {
11
- text-align: left;
12
- }
13
-
14
- @media (max-width: $sm-to) {
15
- .live-table-column {
16
- display: flex;
17
- justify-content: space-between;
18
-
19
- .live-table-column-value {
20
- text-align: right;
21
- }
22
- }
23
-
24
- .live-table-header-row {
25
- margin-bottom: 15px;
26
- }
27
-
28
- .live-table-row {
29
- + .live-table-row {
30
- margin-top: 15px;
31
- }
32
- }
33
- }
34
-
35
- @media (min-width: $md-from) {
36
- .actions-column {
37
- display: flex;
38
- align-items: center;
39
- justify-content: end;
40
- }
41
-
42
- .live-table-header:not(:first-child),
43
- .live-table-column:not(:first-child) {
44
- padding-left: 10px;
45
- }
46
-
47
- .live-table-header:not(:last-child),
48
- .live-table-column:not(:last-child) {
49
- padding-right: 10px;
50
- }
51
-
52
- .live-table-column {
53
- &[data-text-align="center"] {
54
- .live-table-column-value {
55
- text-align: center;
56
- }
57
- }
58
-
59
- &[data-text-align="right"] {
60
- .live-table-column-value {
61
- text-align: right;
62
- }
63
- }
64
- }
65
-
66
- .live-table-header {
67
- &[data-text-align="center"] {
68
- text-align: center;
69
- }
70
-
71
- &[data-text-align="right"] {
72
- text-align: right;
73
- }
74
- }
75
- }
76
- }