@performant-software/semantic-components 0.5.5 → 0.5.6
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/build/main.css +4 -4
- package/package.json +3 -3
- package/src/index.js +1 -0
- package/types/components/AccordionList.js.flow +2 -2
- package/types/components/AccordionSelector.js.flow +93 -86
- package/types/components/ColorPickerModal.js.flow +36 -31
- package/types/components/DataTableColumnSelector.js.flow +11 -0
- package/types/components/DataView.js.flow +36 -30
- package/types/components/DatabaseView.js.flow +126 -0
- package/types/components/DropdownMenu.js.flow +11 -1
- package/types/components/FileUploadModal.js.flow +43 -38
- package/types/components/FuzzyDate.js.flow +114 -99
- package/types/components/ListFilters.js.flow +115 -109
- package/types/components/ListTable.js.flow +7 -4
- package/types/components/LoginModal.js.flow +72 -65
- package/types/components/MenuBar.js.flow +1 -0
- package/types/components/PhotoViewer.js.flow +23 -15
- package/types/components/ReferenceCodeModal.js.flow +27 -21
- package/types/components/ReferenceTableModal.js.flow +61 -55
- package/types/components/Selectize.js.flow +50 -45
- package/types/components/TabbedModal.js.flow +30 -24
- package/types/components/VideoFrameSelector.js.flow +90 -78
- package/types/components/VideoPlayer.js.flow +58 -30
- package/types/components/ViewXML.js.flow +38 -32
- package/types/context/ModalContext.js.flow +5 -0
- package/types/index.js.flow +1 -0
package/build/main.css
CHANGED
|
@@ -215,6 +215,10 @@
|
|
|
215
215
|
font-weight: bold;
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
+
.list-table .table-container {
|
|
219
|
+
margin-top: 20px;
|
|
220
|
+
}
|
|
221
|
+
|
|
218
222
|
.date-input.ui.icon.input > i.icon.right {
|
|
219
223
|
cursor: pointer;
|
|
220
224
|
pointer-events: inherit;
|
|
@@ -488,10 +492,6 @@ div.react-calendar {
|
|
|
488
492
|
z-index: 999;
|
|
489
493
|
}
|
|
490
494
|
|
|
491
|
-
.list-table .table-container {
|
|
492
|
-
margin-top: 20px;
|
|
493
|
-
}
|
|
494
|
-
|
|
495
495
|
.login-modal .ui.grid > .column > .row {
|
|
496
496
|
margin: 15px 150px 0px 150px;
|
|
497
497
|
}
|
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.6",
|
|
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.6",
|
|
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.6",
|
|
36
36
|
"flow-copy-source": "^2.0.9",
|
|
37
37
|
"less": "^4.1.2",
|
|
38
38
|
"less-loader": "^11.0.0",
|
package/src/index.js
CHANGED
|
@@ -16,6 +16,7 @@ export { default as ColorPickerModal } from './components/ColorPickerModal';
|
|
|
16
16
|
export { default as useDataList } from './components/DataList';
|
|
17
17
|
export { default as DataTable } from './components/DataTable';
|
|
18
18
|
export { default as DataView } from './components/DataView';
|
|
19
|
+
export { default as DatabaseView } from './components/DatabaseView';
|
|
19
20
|
export { default as DateInput } from './components/DateInput';
|
|
20
21
|
export { default as DatePicker } from './components/DatePicker';
|
|
21
22
|
export { default as DescriptorField } from './components/DescriptorField';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { Object as ObjectUtils, Timer } from '@performant-software/shared-components';
|
|
4
4
|
import React, { Component } from 'react';
|
|
5
5
|
import {
|
|
6
6
|
Button,
|
|
@@ -154,7 +154,7 @@ class AccordionList extends Component<Props, State> {
|
|
|
154
154
|
let copy;
|
|
155
155
|
if (this.props.onCopy) {
|
|
156
156
|
copy = this.props.onCopy(selectedItem);
|
|
157
|
-
if (
|
|
157
|
+
if (ObjectUtils.isPromise(copy)) {
|
|
158
158
|
copy.then((item) => {
|
|
159
159
|
this.setState({ selectedItem: item, modalAdd: true });
|
|
160
160
|
});
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
import _ from 'underscore';
|
|
16
16
|
import i18n from '../i18n/i18n';
|
|
17
17
|
import EditModal from './EditModal';
|
|
18
|
+
import ModalContext from '../context/ModalContext';
|
|
18
19
|
import NestedAccordion from './NestedAccordion';
|
|
19
20
|
import SelectizeHeader from './SelectizeHeader';
|
|
20
21
|
import Toaster from './Toaster';
|
|
@@ -39,7 +40,6 @@ type Props = {
|
|
|
39
40
|
renderItem: (item: any) => string | Element<any>,
|
|
40
41
|
selectedItems?: Array<any>,
|
|
41
42
|
showToggle: (item: any) => boolean,
|
|
42
|
-
t: (key: string) => string,
|
|
43
43
|
title?: string
|
|
44
44
|
};
|
|
45
45
|
|
|
@@ -187,93 +187,100 @@ class AccordionSelector extends Component<Props, State> {
|
|
|
187
187
|
*/
|
|
188
188
|
render() {
|
|
189
189
|
return (
|
|
190
|
-
<
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
columns={2}
|
|
198
|
-
verticalAlign='middle'
|
|
190
|
+
<ModalContext.Consumer>
|
|
191
|
+
{ (mountNode) => (
|
|
192
|
+
<Modal
|
|
193
|
+
className='accordion-selector'
|
|
194
|
+
mountNode={mountNode}
|
|
195
|
+
open={this.props.open}
|
|
196
|
+
size='small'
|
|
199
197
|
>
|
|
200
|
-
<
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
198
|
+
<Modal.Header>
|
|
199
|
+
<Grid
|
|
200
|
+
columns={2}
|
|
201
|
+
verticalAlign='middle'
|
|
202
|
+
>
|
|
203
|
+
<Grid.Column
|
|
204
|
+
textAlign='left'
|
|
205
|
+
width={7}
|
|
206
|
+
>
|
|
207
|
+
<Header
|
|
208
|
+
content={this.props.title
|
|
209
|
+
? this.props.title
|
|
210
|
+
: i18n.t('AccordionSelector.title')}
|
|
211
|
+
/>
|
|
212
|
+
</Grid.Column>
|
|
213
|
+
<Grid.Column
|
|
214
|
+
textAlign='right'
|
|
215
|
+
width={9}
|
|
216
|
+
>
|
|
217
|
+
<Input
|
|
218
|
+
aria-label='Search'
|
|
219
|
+
autoFocus
|
|
220
|
+
icon='search'
|
|
221
|
+
onKeyDown={Timer.clearSearchTimer.bind(this)}
|
|
222
|
+
onKeyUp={Timer.setSearchTimer.bind(this, this.onSearch.bind(this))}
|
|
223
|
+
onChange={this.onSearchChange.bind(this)}
|
|
224
|
+
size='mini'
|
|
225
|
+
type='text'
|
|
226
|
+
value={this.state.searchQuery}
|
|
227
|
+
/>
|
|
228
|
+
{ this.renderAddButton() }
|
|
229
|
+
</Grid.Column>
|
|
230
|
+
</Grid>
|
|
231
|
+
</Modal.Header>
|
|
232
|
+
<Modal.Content>
|
|
233
|
+
<SelectizeHeader
|
|
234
|
+
isSelected={(item) => this.state.selectedItem === item}
|
|
235
|
+
items={this.state.selectedItems}
|
|
236
|
+
onItemClick={this.onItemSelection.bind(this)}
|
|
237
|
+
renderItem={this.props.renderItem.bind(this)}
|
|
207
238
|
/>
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
onKeyUp={Timer.setSearchTimer.bind(this, this.onSearch.bind(this))}
|
|
217
|
-
onChange={this.onSearchChange.bind(this)}
|
|
218
|
-
size='mini'
|
|
219
|
-
type='text'
|
|
220
|
-
value={this.state.searchQuery}
|
|
239
|
+
<NestedAccordion
|
|
240
|
+
getChildItems={this.props.getChildItems.bind(this, this.state.items)}
|
|
241
|
+
onItemClick={this.onItemClick.bind(this)}
|
|
242
|
+
onItemToggle={this.onItemToggle.bind(this)}
|
|
243
|
+
renderItem={this.props.renderItem.bind(this)}
|
|
244
|
+
renderRight={this.renderRight.bind(this)}
|
|
245
|
+
rootItems={this.props.getRootItems(this.state.items)}
|
|
246
|
+
showToggle={this.props.showToggle.bind(this)}
|
|
221
247
|
/>
|
|
222
|
-
{ this.
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
</
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
<Button
|
|
259
|
-
onClick={this.props.onSave.bind(this, this.state.selectedItems)}
|
|
260
|
-
primary
|
|
261
|
-
size='medium'
|
|
262
|
-
type='submit'
|
|
263
|
-
>
|
|
264
|
-
{ this.props.t('Common.buttons.save') }
|
|
265
|
-
</Button>
|
|
266
|
-
<Button
|
|
267
|
-
inverted
|
|
268
|
-
onClick={this.props.onClose.bind(this)}
|
|
269
|
-
primary
|
|
270
|
-
size='medium'
|
|
271
|
-
type='button'
|
|
272
|
-
>
|
|
273
|
-
{ this.props.t('Common.buttons.cancel') }
|
|
274
|
-
</Button>
|
|
275
|
-
</Modal.Actions>
|
|
276
|
-
</Modal>
|
|
248
|
+
{ this.renderAddModal() }
|
|
249
|
+
{ this.state.saved && (
|
|
250
|
+
<Toaster
|
|
251
|
+
onDismiss={() => this.setState({ saved: false })}
|
|
252
|
+
type={Toaster.MessageTypes.positive}
|
|
253
|
+
>
|
|
254
|
+
<Message.Header
|
|
255
|
+
content={i18n.t('Common.messages.save.header')}
|
|
256
|
+
/>
|
|
257
|
+
<Message.Content
|
|
258
|
+
content={i18n.t('Common.messages.save.content')}
|
|
259
|
+
/>
|
|
260
|
+
</Toaster>
|
|
261
|
+
)}
|
|
262
|
+
</Modal.Content>
|
|
263
|
+
<Modal.Actions>
|
|
264
|
+
<Button
|
|
265
|
+
onClick={this.props.onSave.bind(this, this.state.selectedItems)}
|
|
266
|
+
primary
|
|
267
|
+
size='medium'
|
|
268
|
+
type='submit'
|
|
269
|
+
>
|
|
270
|
+
{ i18n.t('Common.buttons.save') }
|
|
271
|
+
</Button>
|
|
272
|
+
<Button
|
|
273
|
+
basic
|
|
274
|
+
onClick={this.props.onClose.bind(this)}
|
|
275
|
+
size='medium'
|
|
276
|
+
type='button'
|
|
277
|
+
>
|
|
278
|
+
{ i18n.t('Common.buttons.cancel') }
|
|
279
|
+
</Button>
|
|
280
|
+
</Modal.Actions>
|
|
281
|
+
</Modal>
|
|
282
|
+
)}
|
|
283
|
+
</ModalContext.Consumer>
|
|
277
284
|
);
|
|
278
285
|
}
|
|
279
286
|
|
|
@@ -291,7 +298,7 @@ class AccordionSelector extends Component<Props, State> {
|
|
|
291
298
|
<Button
|
|
292
299
|
basic
|
|
293
300
|
className='add-button'
|
|
294
|
-
content={
|
|
301
|
+
content={i18n.t('Common.buttons.add')}
|
|
295
302
|
icon='plus'
|
|
296
303
|
onClick={() => this.setState({ modalAdd: true })}
|
|
297
304
|
/>
|
|
@@ -4,6 +4,7 @@ import React, { Component } from 'react';
|
|
|
4
4
|
import { SketchPicker } from 'react-color';
|
|
5
5
|
import { Button, Modal } from 'semantic-ui-react';
|
|
6
6
|
import i18n from '../i18n/i18n';
|
|
7
|
+
import ModalContext from '../context/ModalContext';
|
|
7
8
|
import './ColorPickerModal.css';
|
|
8
9
|
|
|
9
10
|
type Props = {
|
|
@@ -38,38 +39,42 @@ class ColorPickerModal extends Component<Props, State> {
|
|
|
38
39
|
*/
|
|
39
40
|
render() {
|
|
40
41
|
return (
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
color={this.state.selectedColor}
|
|
49
|
-
disableAlpha={false}
|
|
50
|
-
onChangeComplete={(selectedColor) => this.setState({ selectedColor })}
|
|
51
|
-
/>
|
|
52
|
-
</Modal.Content>
|
|
53
|
-
<Modal.Actions>
|
|
54
|
-
<Button
|
|
55
|
-
onClick={this.props.onSave.bind(this, this.state.selectedColor)}
|
|
56
|
-
primary
|
|
57
|
-
size='medium'
|
|
58
|
-
type='submit'
|
|
42
|
+
<ModalContext.Consumer>
|
|
43
|
+
{ (mountNode) => (
|
|
44
|
+
<Modal
|
|
45
|
+
className='color-picker-modal'
|
|
46
|
+
mountNode={mountNode}
|
|
47
|
+
onClose={this.props.onClose.bind(this)}
|
|
48
|
+
open={this.props.open}
|
|
59
49
|
>
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
50
|
+
<Modal.Content>
|
|
51
|
+
<SketchPicker
|
|
52
|
+
color={this.state.selectedColor}
|
|
53
|
+
disableAlpha={false}
|
|
54
|
+
onChangeComplete={(selectedColor) => this.setState({ selectedColor })}
|
|
55
|
+
/>
|
|
56
|
+
</Modal.Content>
|
|
57
|
+
<Modal.Actions>
|
|
58
|
+
<Button
|
|
59
|
+
onClick={this.props.onSave.bind(this, this.state.selectedColor)}
|
|
60
|
+
primary
|
|
61
|
+
size='medium'
|
|
62
|
+
type='submit'
|
|
63
|
+
>
|
|
64
|
+
{ i18n.t('Common.buttons.save') }
|
|
65
|
+
</Button>
|
|
66
|
+
<Button
|
|
67
|
+
basic
|
|
68
|
+
onClick={this.props.onClose.bind(this)}
|
|
69
|
+
size='medium'
|
|
70
|
+
type='button'
|
|
71
|
+
>
|
|
72
|
+
{ i18n.t('Common.buttons.cancel') }
|
|
73
|
+
</Button>
|
|
74
|
+
</Modal.Actions>
|
|
75
|
+
</Modal>
|
|
76
|
+
)}
|
|
77
|
+
</ModalContext.Consumer>
|
|
73
78
|
);
|
|
74
79
|
}
|
|
75
80
|
}
|
|
@@ -43,6 +43,17 @@ const useColumnSelector = (WrappedComponent: ComponentType<any>) => (
|
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Reset the columns on the state when the props change.
|
|
48
|
+
*
|
|
49
|
+
* @param prevProps
|
|
50
|
+
*/
|
|
51
|
+
componentDidUpdate(prevProps: Props): * {
|
|
52
|
+
if (prevProps.columns !== this.props.columns) {
|
|
53
|
+
this.setState({ columns: this.props.columns });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
46
57
|
/**
|
|
47
58
|
* Toggles the hidden property for the passed column.
|
|
48
59
|
*
|
|
@@ -15,6 +15,7 @@ import DropdownButton from './DropdownButton';
|
|
|
15
15
|
import i18n from '../i18n/i18n';
|
|
16
16
|
import MenuBar from './MenuBar';
|
|
17
17
|
import MenuSidebar from './MenuSidebar';
|
|
18
|
+
import ModalContext from '../context/ModalContext';
|
|
18
19
|
import useDataList, { SORT_ASCENDING, SORT_DESCENDING } from './DataList';
|
|
19
20
|
import './DataView.css';
|
|
20
21
|
|
|
@@ -362,38 +363,43 @@ const DataView = (props: Props) => {
|
|
|
362
363
|
)}
|
|
363
364
|
</div>
|
|
364
365
|
{ selectedRecord && (
|
|
365
|
-
<
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
/>
|
|
376
|
-
<Modal.Content>
|
|
377
|
-
<Grid
|
|
378
|
-
columns={3}
|
|
379
|
-
doubling
|
|
366
|
+
<ModalContext.Consumer>
|
|
367
|
+
{ (mountNode) => (
|
|
368
|
+
<Modal
|
|
369
|
+
as={Form}
|
|
370
|
+
centered={false}
|
|
371
|
+
className='data-view-modal'
|
|
372
|
+
closeIcon
|
|
373
|
+
mountNode={mountNode}
|
|
374
|
+
onClose={() => setSelectedRecord(null)}
|
|
375
|
+
open
|
|
380
376
|
>
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
377
|
+
<Modal.Header
|
|
378
|
+
content={i18n.t('DataView.labels.details')}
|
|
379
|
+
/>
|
|
380
|
+
<Modal.Content>
|
|
381
|
+
<Grid
|
|
382
|
+
columns={3}
|
|
383
|
+
doubling
|
|
385
384
|
>
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
385
|
+
{ _.map(mergeColumns([selectedRecord]), (column) => (
|
|
386
|
+
<Grid.Column
|
|
387
|
+
as={Form.Field}
|
|
388
|
+
key={column.name}
|
|
389
|
+
>
|
|
390
|
+
<span
|
|
391
|
+
className='label'
|
|
392
|
+
>
|
|
393
|
+
{ column.label }
|
|
394
|
+
</span>
|
|
395
|
+
{ resolveValue(selectedRecord, column.name) }
|
|
396
|
+
</Grid.Column>
|
|
397
|
+
))}
|
|
398
|
+
</Grid>
|
|
399
|
+
</Modal.Content>
|
|
400
|
+
</Modal>
|
|
401
|
+
)}
|
|
402
|
+
</ModalContext.Consumer>
|
|
397
403
|
)}
|
|
398
404
|
</div>
|
|
399
405
|
);
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import React, {
|
|
4
|
+
useCallback,
|
|
5
|
+
useEffect,
|
|
6
|
+
useMemo,
|
|
7
|
+
useRef,
|
|
8
|
+
useState
|
|
9
|
+
} from 'react';
|
|
10
|
+
import axios from 'axios';
|
|
11
|
+
import _ from 'underscore';
|
|
12
|
+
import ListTable from './ListTable';
|
|
13
|
+
import MenuSidebar from './MenuSidebar';
|
|
14
|
+
|
|
15
|
+
type Props = {
|
|
16
|
+
columnCount?: number,
|
|
17
|
+
title: string,
|
|
18
|
+
url: string
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const DatabaseView = (props: Props) => {
|
|
22
|
+
const [columns, setColumns] = useState([]);
|
|
23
|
+
const [selectedTable, setSelectedTable] = useState();
|
|
24
|
+
const [tables, setTables] = useState([]);
|
|
25
|
+
|
|
26
|
+
const menuRef = useRef();
|
|
27
|
+
|
|
28
|
+
const service = useMemo(() => ({
|
|
29
|
+
getColumns: (params) => axios.get(`${props.url}/api/columns`, { params }),
|
|
30
|
+
getData: (params) => axios.post(`${props.url}/api/search`, params),
|
|
31
|
+
getTables: () => axios.get(`${props.url}/api/tables`)
|
|
32
|
+
}), [props.url]);
|
|
33
|
+
|
|
34
|
+
const resolveValue = useCallback((column, item) => {
|
|
35
|
+
let value = item[column.column_name];
|
|
36
|
+
|
|
37
|
+
const { data_type: dataType } = column;
|
|
38
|
+
|
|
39
|
+
if (value) {
|
|
40
|
+
switch (dataType) {
|
|
41
|
+
case 'timestamp without time zone':
|
|
42
|
+
value = new Date(value).toLocaleDateString();
|
|
43
|
+
break;
|
|
44
|
+
|
|
45
|
+
default:
|
|
46
|
+
// Value is already set
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return value;
|
|
51
|
+
}, []);
|
|
52
|
+
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (service) {
|
|
55
|
+
service
|
|
56
|
+
.getTables()
|
|
57
|
+
.then(({ data }) => {
|
|
58
|
+
setTables(data);
|
|
59
|
+
setSelectedTable(_.first(data));
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}, [service]);
|
|
63
|
+
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (selectedTable) {
|
|
66
|
+
service
|
|
67
|
+
.getColumns({ table_name: selectedTable.table_name })
|
|
68
|
+
.then(({ data }) => setColumns(data));
|
|
69
|
+
}
|
|
70
|
+
}, [selectedTable, service]);
|
|
71
|
+
|
|
72
|
+
const test = useMemo(() => _.map(columns, (column, index) => ({
|
|
73
|
+
name: column.column_name,
|
|
74
|
+
label: column.column_name,
|
|
75
|
+
resolve: resolveValue.bind(this, column),
|
|
76
|
+
sortable: true,
|
|
77
|
+
hidden: index > props.columnCount
|
|
78
|
+
})), [columns, resolveValue, props.columnCount]);
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<div
|
|
82
|
+
className='database-view'
|
|
83
|
+
>
|
|
84
|
+
<MenuSidebar
|
|
85
|
+
contextRef={menuRef}
|
|
86
|
+
header={{
|
|
87
|
+
content: props.title,
|
|
88
|
+
inverted: true
|
|
89
|
+
}}
|
|
90
|
+
inverted
|
|
91
|
+
items={[{
|
|
92
|
+
items: _.map(tables, (table) => ({
|
|
93
|
+
active: selectedTable === table,
|
|
94
|
+
content: table.table_name,
|
|
95
|
+
onClick: () => setSelectedTable(table)
|
|
96
|
+
}))
|
|
97
|
+
}]}
|
|
98
|
+
style={{
|
|
99
|
+
overflow: 'auto',
|
|
100
|
+
width: '250px'
|
|
101
|
+
}}
|
|
102
|
+
/>
|
|
103
|
+
<div
|
|
104
|
+
style={{
|
|
105
|
+
marginLeft: '250px'
|
|
106
|
+
}}
|
|
107
|
+
>
|
|
108
|
+
{ selectedTable && (
|
|
109
|
+
<ListTable
|
|
110
|
+
collectionName='items'
|
|
111
|
+
columns={test}
|
|
112
|
+
onLoad={(params) => service.getData({ ...params, table_name: selectedTable.table_name })}
|
|
113
|
+
perPageOptions={[10, 25, 50, 100]}
|
|
114
|
+
searchable
|
|
115
|
+
/>
|
|
116
|
+
)}
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
DatabaseView.defaultProps = {
|
|
123
|
+
columnCount: Number.MAX_SAFE_INTEGER
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export default DatabaseView;
|
|
@@ -11,7 +11,8 @@ import { Dropdown, Ref } from 'semantic-ui-react';
|
|
|
11
11
|
|
|
12
12
|
type Props = {
|
|
13
13
|
children: Node,
|
|
14
|
-
onClick?: () => void
|
|
14
|
+
onClick?: () => void,
|
|
15
|
+
role?: string
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
const DropdownMenu = (props: Props) => {
|
|
@@ -38,6 +39,15 @@ const DropdownMenu = (props: Props) => {
|
|
|
38
39
|
};
|
|
39
40
|
}, [ref]);
|
|
40
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Sets the "role" aria attribute on the current element if provided.
|
|
44
|
+
*/
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
if (ref.current && props.role) {
|
|
47
|
+
ref.current.setAttribute('role', props.role);
|
|
48
|
+
}
|
|
49
|
+
}, [ref, props.role]);
|
|
50
|
+
|
|
41
51
|
return (
|
|
42
52
|
<Ref
|
|
43
53
|
innerRef={ref}
|