@performant-software/semantic-components 0.5.7 → 0.5.10
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/build/index.js +1 -1
- package/build/index.js.map +1 -1
- package/package.json +3 -3
- package/src/components/AssociatedDropdown.js +40 -32
- package/src/components/DataTable.js +12 -1
- package/src/components/DataTableColumnSelector.js +2 -1
- package/src/components/ListTable.js +19 -10
- package/types/components/AssociatedDropdown.js.flow +40 -32
- package/types/components/DataTable.js.flow +12 -1
- package/types/components/DataTableColumnSelector.js.flow +2 -1
- package/types/components/ListTable.js.flow +19 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@performant-software/semantic-components",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.10",
|
|
4
4
|
"description": "A package of shared components based on the Semantic UI Framework.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "./build/index.js",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"build": "webpack --mode production && flow-copy-source -v src types"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@performant-software/shared-components": "^0.5.
|
|
15
|
+
"@performant-software/shared-components": "^0.5.10",
|
|
16
16
|
"@react-google-maps/api": "^2.8.1",
|
|
17
17
|
"axios": "^0.26.1",
|
|
18
18
|
"i18next": "^19.4.4",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"react-dom": ">= 16.13.1 < 18.0.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@performant-software/webpack-config": "^0.5.
|
|
35
|
+
"@performant-software/webpack-config": "^0.5.10",
|
|
36
36
|
"flow-copy-source": "^2.0.9",
|
|
37
37
|
"less": "^4.1.2",
|
|
38
38
|
"less-loader": "^11.0.0",
|
|
@@ -63,6 +63,7 @@ class AssociatedDropdown extends Component<Props, State> {
|
|
|
63
63
|
items: [],
|
|
64
64
|
loading: false,
|
|
65
65
|
modalAdd: false,
|
|
66
|
+
modalEdit: false,
|
|
66
67
|
options: [],
|
|
67
68
|
saved: false,
|
|
68
69
|
searchQuery: props.searchQuery || '',
|
|
@@ -208,7 +209,7 @@ class AssociatedDropdown extends Component<Props, State> {
|
|
|
208
209
|
{ this.renderAddButton() }
|
|
209
210
|
{ this.renderClearButton() }
|
|
210
211
|
</Button.Group>
|
|
211
|
-
{ this.
|
|
212
|
+
{ this.renderModal() }
|
|
212
213
|
{ this.state.saved && (
|
|
213
214
|
<Toaster
|
|
214
215
|
onDismiss={() => this.setState({ saved: false })}
|
|
@@ -247,6 +248,27 @@ class AssociatedDropdown extends Component<Props, State> {
|
|
|
247
248
|
);
|
|
248
249
|
}
|
|
249
250
|
|
|
251
|
+
/**
|
|
252
|
+
* Renders the clear button.
|
|
253
|
+
*
|
|
254
|
+
* @returns {*}
|
|
255
|
+
*/
|
|
256
|
+
renderClearButton() {
|
|
257
|
+
if (this.props.required) {
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return (
|
|
262
|
+
<Button
|
|
263
|
+
basic
|
|
264
|
+
content={i18n.t('Common.buttons.clear')}
|
|
265
|
+
icon='times'
|
|
266
|
+
onClick={this.onClear.bind(this)}
|
|
267
|
+
type='button'
|
|
268
|
+
/>
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
|
|
250
272
|
/**
|
|
251
273
|
* Renders the edit button (if applicable).
|
|
252
274
|
*
|
|
@@ -262,7 +284,7 @@ class AssociatedDropdown extends Component<Props, State> {
|
|
|
262
284
|
basic
|
|
263
285
|
content={i18n.t('Common.buttons.edit')}
|
|
264
286
|
icon='pencil'
|
|
265
|
-
onClick={() => this.setState({
|
|
287
|
+
onClick={() => this.setState({ modalEdit: true })}
|
|
266
288
|
type='button'
|
|
267
289
|
/>
|
|
268
290
|
);
|
|
@@ -273,51 +295,37 @@ class AssociatedDropdown extends Component<Props, State> {
|
|
|
273
295
|
*
|
|
274
296
|
* @returns {null|*}
|
|
275
297
|
*/
|
|
276
|
-
|
|
277
|
-
if (!(this.state.modalAdd && this.props.modal)) {
|
|
298
|
+
renderModal() {
|
|
299
|
+
if (!((this.state.modalAdd || this.state.modalEdit) && this.props.modal)) {
|
|
278
300
|
return null;
|
|
279
301
|
}
|
|
280
302
|
|
|
281
|
-
const {
|
|
282
|
-
|
|
283
|
-
|
|
303
|
+
const { component, props, onSave } = this.props.modal;
|
|
304
|
+
|
|
305
|
+
// If we're editing the existing record, pass the ID to the modal in order to retrieve the full record.
|
|
306
|
+
let item;
|
|
307
|
+
|
|
308
|
+
if (this.state.modalEdit) {
|
|
309
|
+
item = {
|
|
310
|
+
id: this.state.value
|
|
311
|
+
};
|
|
312
|
+
}
|
|
284
313
|
|
|
285
314
|
return (
|
|
286
315
|
<EditModal
|
|
287
316
|
component={component}
|
|
288
|
-
item={
|
|
289
|
-
onClose={() => this.setState({ modalAdd: false })}
|
|
290
|
-
onSave={(
|
|
317
|
+
item={item}
|
|
318
|
+
onClose={() => this.setState({ modalAdd: false, modalEdit: false })}
|
|
319
|
+
onSave={(data) => onSave(data)
|
|
291
320
|
.then((record) => {
|
|
292
321
|
this.props.onSelection(record);
|
|
293
|
-
this.setState({ modalAdd: false, saved: true });
|
|
322
|
+
this.setState({ modalAdd: false, modalEdit: false, saved: true });
|
|
294
323
|
})}
|
|
295
324
|
{...props}
|
|
296
325
|
/>
|
|
297
326
|
);
|
|
298
327
|
}
|
|
299
328
|
|
|
300
|
-
/**
|
|
301
|
-
* Renders the clear button.
|
|
302
|
-
*
|
|
303
|
-
* @returns {*}
|
|
304
|
-
*/
|
|
305
|
-
renderClearButton() {
|
|
306
|
-
if (this.props.required) {
|
|
307
|
-
return null;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
return (
|
|
311
|
-
<Button
|
|
312
|
-
basic
|
|
313
|
-
content={i18n.t('Common.buttons.clear')}
|
|
314
|
-
icon='times'
|
|
315
|
-
onClick={this.onClear.bind(this)}
|
|
316
|
-
type='button'
|
|
317
|
-
/>
|
|
318
|
-
);
|
|
319
|
-
}
|
|
320
|
-
|
|
321
329
|
/**
|
|
322
330
|
* Sets the search timer.
|
|
323
331
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
|
|
3
|
-
import { Browser } from '@performant-software/shared-components';
|
|
3
|
+
import { Browser, Object as ObjectUtils } from '@performant-software/shared-components';
|
|
4
4
|
import React, { Component, createRef, type Element } from 'react';
|
|
5
5
|
import {
|
|
6
6
|
Checkbox,
|
|
@@ -122,6 +122,17 @@ class DataTable extends Component<Props, State> {
|
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
/**
|
|
126
|
+
* Reinitialize the column refs if the columns change.
|
|
127
|
+
*
|
|
128
|
+
* @param prevProps
|
|
129
|
+
*/
|
|
130
|
+
componentDidUpdate(prevProps: Props) {
|
|
131
|
+
if (!ObjectUtils.isEqual(prevProps.columns, this.props.columns)) {
|
|
132
|
+
this.initializeColumnRefs();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
125
136
|
/**
|
|
126
137
|
* Removes the mousemove and mouseup event listeners.
|
|
127
138
|
*/
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
|
|
3
|
+
import { Object as ObjectUtils } from '@performant-software/shared-components';
|
|
3
4
|
import React, { Component, type ComponentType, type Element } from 'react';
|
|
4
5
|
import { Checkbox, Dropdown, Icon } from 'semantic-ui-react';
|
|
5
6
|
import _ from 'underscore';
|
|
@@ -49,7 +50,7 @@ const useColumnSelector = (WrappedComponent: ComponentType<any>) => (
|
|
|
49
50
|
* @param prevProps
|
|
50
51
|
*/
|
|
51
52
|
componentDidUpdate(prevProps: Props): * {
|
|
52
|
-
if (prevProps.columns
|
|
53
|
+
if (!ObjectUtils.isEqual(prevProps.columns, this.props.columns)) {
|
|
53
54
|
this.setState({ columns: this.props.columns });
|
|
54
55
|
}
|
|
55
56
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
|
|
3
|
+
import { Hooks, Object as ObjectUtils } from '@performant-software/shared-components';
|
|
3
4
|
import React, { useEffect } from 'react';
|
|
4
5
|
import _ from 'underscore';
|
|
5
6
|
import DataTable from './DataTable';
|
|
@@ -20,6 +21,8 @@ type Props = {
|
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
const ListTable = (props: Props) => {
|
|
24
|
+
const prevColumns = Hooks.usePrevious(props.columns);
|
|
25
|
+
|
|
23
26
|
/**
|
|
24
27
|
* Sorts the list by the selected column, and/or reverse the direction.
|
|
25
28
|
*
|
|
@@ -51,18 +54,24 @@ const ListTable = (props: Props) => {
|
|
|
51
54
|
* sortable column.
|
|
52
55
|
*/
|
|
53
56
|
useEffect(() => {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
if (!ObjectUtils.isEqual(props.columns, prevColumns)) {
|
|
58
|
+
const {
|
|
59
|
+
page,
|
|
60
|
+
defaultSort,
|
|
61
|
+
defaultSortDirection = SORT_ASCENDING
|
|
62
|
+
} = props;
|
|
60
63
|
|
|
61
|
-
if (
|
|
62
|
-
|
|
64
|
+
if (defaultSort) {
|
|
65
|
+
props.onSort(defaultSort, defaultSortDirection, page);
|
|
63
66
|
} else {
|
|
64
|
-
|
|
65
|
-
|
|
67
|
+
const sortableColumn = _.findWhere(props.columns, { sortable: true });
|
|
68
|
+
|
|
69
|
+
if (sortableColumn) {
|
|
70
|
+
onColumnClick(sortableColumn);
|
|
71
|
+
} else {
|
|
72
|
+
// If no columns are sortable, load the data as is
|
|
73
|
+
props.onInit();
|
|
74
|
+
}
|
|
66
75
|
}
|
|
67
76
|
}
|
|
68
77
|
}, [props.columns]);
|
|
@@ -63,6 +63,7 @@ class AssociatedDropdown extends Component<Props, State> {
|
|
|
63
63
|
items: [],
|
|
64
64
|
loading: false,
|
|
65
65
|
modalAdd: false,
|
|
66
|
+
modalEdit: false,
|
|
66
67
|
options: [],
|
|
67
68
|
saved: false,
|
|
68
69
|
searchQuery: props.searchQuery || '',
|
|
@@ -208,7 +209,7 @@ class AssociatedDropdown extends Component<Props, State> {
|
|
|
208
209
|
{ this.renderAddButton() }
|
|
209
210
|
{ this.renderClearButton() }
|
|
210
211
|
</Button.Group>
|
|
211
|
-
{ this.
|
|
212
|
+
{ this.renderModal() }
|
|
212
213
|
{ this.state.saved && (
|
|
213
214
|
<Toaster
|
|
214
215
|
onDismiss={() => this.setState({ saved: false })}
|
|
@@ -247,6 +248,27 @@ class AssociatedDropdown extends Component<Props, State> {
|
|
|
247
248
|
);
|
|
248
249
|
}
|
|
249
250
|
|
|
251
|
+
/**
|
|
252
|
+
* Renders the clear button.
|
|
253
|
+
*
|
|
254
|
+
* @returns {*}
|
|
255
|
+
*/
|
|
256
|
+
renderClearButton() {
|
|
257
|
+
if (this.props.required) {
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return (
|
|
262
|
+
<Button
|
|
263
|
+
basic
|
|
264
|
+
content={i18n.t('Common.buttons.clear')}
|
|
265
|
+
icon='times'
|
|
266
|
+
onClick={this.onClear.bind(this)}
|
|
267
|
+
type='button'
|
|
268
|
+
/>
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
|
|
250
272
|
/**
|
|
251
273
|
* Renders the edit button (if applicable).
|
|
252
274
|
*
|
|
@@ -262,7 +284,7 @@ class AssociatedDropdown extends Component<Props, State> {
|
|
|
262
284
|
basic
|
|
263
285
|
content={i18n.t('Common.buttons.edit')}
|
|
264
286
|
icon='pencil'
|
|
265
|
-
onClick={() => this.setState({
|
|
287
|
+
onClick={() => this.setState({ modalEdit: true })}
|
|
266
288
|
type='button'
|
|
267
289
|
/>
|
|
268
290
|
);
|
|
@@ -273,51 +295,37 @@ class AssociatedDropdown extends Component<Props, State> {
|
|
|
273
295
|
*
|
|
274
296
|
* @returns {null|*}
|
|
275
297
|
*/
|
|
276
|
-
|
|
277
|
-
if (!(this.state.modalAdd && this.props.modal)) {
|
|
298
|
+
renderModal() {
|
|
299
|
+
if (!((this.state.modalAdd || this.state.modalEdit) && this.props.modal)) {
|
|
278
300
|
return null;
|
|
279
301
|
}
|
|
280
302
|
|
|
281
|
-
const {
|
|
282
|
-
|
|
283
|
-
|
|
303
|
+
const { component, props, onSave } = this.props.modal;
|
|
304
|
+
|
|
305
|
+
// If we're editing the existing record, pass the ID to the modal in order to retrieve the full record.
|
|
306
|
+
let item;
|
|
307
|
+
|
|
308
|
+
if (this.state.modalEdit) {
|
|
309
|
+
item = {
|
|
310
|
+
id: this.state.value
|
|
311
|
+
};
|
|
312
|
+
}
|
|
284
313
|
|
|
285
314
|
return (
|
|
286
315
|
<EditModal
|
|
287
316
|
component={component}
|
|
288
|
-
item={
|
|
289
|
-
onClose={() => this.setState({ modalAdd: false })}
|
|
290
|
-
onSave={(
|
|
317
|
+
item={item}
|
|
318
|
+
onClose={() => this.setState({ modalAdd: false, modalEdit: false })}
|
|
319
|
+
onSave={(data) => onSave(data)
|
|
291
320
|
.then((record) => {
|
|
292
321
|
this.props.onSelection(record);
|
|
293
|
-
this.setState({ modalAdd: false, saved: true });
|
|
322
|
+
this.setState({ modalAdd: false, modalEdit: false, saved: true });
|
|
294
323
|
})}
|
|
295
324
|
{...props}
|
|
296
325
|
/>
|
|
297
326
|
);
|
|
298
327
|
}
|
|
299
328
|
|
|
300
|
-
/**
|
|
301
|
-
* Renders the clear button.
|
|
302
|
-
*
|
|
303
|
-
* @returns {*}
|
|
304
|
-
*/
|
|
305
|
-
renderClearButton() {
|
|
306
|
-
if (this.props.required) {
|
|
307
|
-
return null;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
return (
|
|
311
|
-
<Button
|
|
312
|
-
basic
|
|
313
|
-
content={i18n.t('Common.buttons.clear')}
|
|
314
|
-
icon='times'
|
|
315
|
-
onClick={this.onClear.bind(this)}
|
|
316
|
-
type='button'
|
|
317
|
-
/>
|
|
318
|
-
);
|
|
319
|
-
}
|
|
320
|
-
|
|
321
329
|
/**
|
|
322
330
|
* Sets the search timer.
|
|
323
331
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
|
|
3
|
-
import { Browser } from '@performant-software/shared-components';
|
|
3
|
+
import { Browser, Object as ObjectUtils } from '@performant-software/shared-components';
|
|
4
4
|
import React, { Component, createRef, type Element } from 'react';
|
|
5
5
|
import {
|
|
6
6
|
Checkbox,
|
|
@@ -122,6 +122,17 @@ class DataTable extends Component<Props, State> {
|
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
/**
|
|
126
|
+
* Reinitialize the column refs if the columns change.
|
|
127
|
+
*
|
|
128
|
+
* @param prevProps
|
|
129
|
+
*/
|
|
130
|
+
componentDidUpdate(prevProps: Props) {
|
|
131
|
+
if (!ObjectUtils.isEqual(prevProps.columns, this.props.columns)) {
|
|
132
|
+
this.initializeColumnRefs();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
125
136
|
/**
|
|
126
137
|
* Removes the mousemove and mouseup event listeners.
|
|
127
138
|
*/
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
|
|
3
|
+
import { Object as ObjectUtils } from '@performant-software/shared-components';
|
|
3
4
|
import React, { Component, type ComponentType, type Element } from 'react';
|
|
4
5
|
import { Checkbox, Dropdown, Icon } from 'semantic-ui-react';
|
|
5
6
|
import _ from 'underscore';
|
|
@@ -49,7 +50,7 @@ const useColumnSelector = (WrappedComponent: ComponentType<any>) => (
|
|
|
49
50
|
* @param prevProps
|
|
50
51
|
*/
|
|
51
52
|
componentDidUpdate(prevProps: Props): * {
|
|
52
|
-
if (prevProps.columns
|
|
53
|
+
if (!ObjectUtils.isEqual(prevProps.columns, this.props.columns)) {
|
|
53
54
|
this.setState({ columns: this.props.columns });
|
|
54
55
|
}
|
|
55
56
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
|
|
3
|
+
import { Hooks, Object as ObjectUtils } from '@performant-software/shared-components';
|
|
3
4
|
import React, { useEffect } from 'react';
|
|
4
5
|
import _ from 'underscore';
|
|
5
6
|
import DataTable from './DataTable';
|
|
@@ -20,6 +21,8 @@ type Props = {
|
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
const ListTable = (props: Props) => {
|
|
24
|
+
const prevColumns = Hooks.usePrevious(props.columns);
|
|
25
|
+
|
|
23
26
|
/**
|
|
24
27
|
* Sorts the list by the selected column, and/or reverse the direction.
|
|
25
28
|
*
|
|
@@ -51,18 +54,24 @@ const ListTable = (props: Props) => {
|
|
|
51
54
|
* sortable column.
|
|
52
55
|
*/
|
|
53
56
|
useEffect(() => {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
if (!ObjectUtils.isEqual(props.columns, prevColumns)) {
|
|
58
|
+
const {
|
|
59
|
+
page,
|
|
60
|
+
defaultSort,
|
|
61
|
+
defaultSortDirection = SORT_ASCENDING
|
|
62
|
+
} = props;
|
|
60
63
|
|
|
61
|
-
if (
|
|
62
|
-
|
|
64
|
+
if (defaultSort) {
|
|
65
|
+
props.onSort(defaultSort, defaultSortDirection, page);
|
|
63
66
|
} else {
|
|
64
|
-
|
|
65
|
-
|
|
67
|
+
const sortableColumn = _.findWhere(props.columns, { sortable: true });
|
|
68
|
+
|
|
69
|
+
if (sortableColumn) {
|
|
70
|
+
onColumnClick(sortableColumn);
|
|
71
|
+
} else {
|
|
72
|
+
// If no columns are sortable, load the data as is
|
|
73
|
+
props.onInit();
|
|
74
|
+
}
|
|
66
75
|
}
|
|
67
76
|
}
|
|
68
77
|
}, [props.columns]);
|