@performant-software/semantic-components 0.5.5 → 0.5.8

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.
Files changed (36) hide show
  1. package/build/index.js +1 -1
  2. package/build/index.js.map +1 -1
  3. package/build/main.css +4 -4
  4. package/build/semantic-ui.css +1 -1
  5. package/package.json +3 -3
  6. package/src/components/DataTable.js +12 -1
  7. package/src/components/DataTableColumnSelector.js +2 -1
  8. package/src/components/ListTable.js +19 -10
  9. package/src/css/theme.config +1 -1
  10. package/src/css/themes/default/elements/step.overrides +2 -2
  11. package/src/index.js +1 -0
  12. package/types/components/AccordionList.js.flow +2 -2
  13. package/types/components/AccordionSelector.js.flow +93 -86
  14. package/types/components/ColorPickerModal.js.flow +36 -31
  15. package/types/components/DataTable.js.flow +12 -1
  16. package/types/components/DataTableColumnSelector.js.flow +12 -0
  17. package/types/components/DataView.js.flow +36 -30
  18. package/types/components/DatabaseView.js.flow +126 -0
  19. package/types/components/DropdownMenu.js.flow +11 -1
  20. package/types/components/FileUploadModal.js.flow +43 -38
  21. package/types/components/FuzzyDate.js.flow +114 -99
  22. package/types/components/ListFilters.js.flow +115 -109
  23. package/types/components/ListTable.js.flow +22 -10
  24. package/types/components/LoginModal.js.flow +72 -65
  25. package/types/components/MenuBar.js.flow +1 -0
  26. package/types/components/PhotoViewer.js.flow +23 -15
  27. package/types/components/ReferenceCodeModal.js.flow +27 -21
  28. package/types/components/ReferenceTableModal.js.flow +61 -55
  29. package/types/components/Selectize.js.flow +50 -45
  30. package/types/components/TabbedModal.js.flow +30 -24
  31. package/types/components/VideoFrameSelector.js.flow +90 -78
  32. package/types/components/VideoPlayer.js.flow +58 -30
  33. package/types/components/ViewXML.js.flow +38 -32
  34. package/types/context/ModalContext.js.flow +5 -0
  35. package/types/index.js.flow +1 -0
  36. package/webpack.config.js +2 -1
@@ -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
- <Modal
366
- as={Form}
367
- centered={false}
368
- className='data-view-modal'
369
- closeIcon
370
- onClose={() => setSelectedRecord(null)}
371
- open
372
- >
373
- <Modal.Header
374
- content={i18n.t('DataView.labels.details')}
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
- { _.map(mergeColumns([selectedRecord]), (column) => (
382
- <Grid.Column
383
- as={Form.Field}
384
- key={column.name}
377
+ <Modal.Header
378
+ content={i18n.t('DataView.labels.details')}
379
+ />
380
+ <Modal.Content>
381
+ <Grid
382
+ columns={3}
383
+ doubling
385
384
  >
386
- <span
387
- className='label'
388
- >
389
- { column.label }
390
- </span>
391
- { resolveValue(selectedRecord, column.name) }
392
- </Grid.Column>
393
- ))}
394
- </Grid>
395
- </Modal.Content>
396
- </Modal>
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}
@@ -13,6 +13,7 @@ import {
13
13
  import _ from 'underscore';
14
14
  import i18n from '../i18n/i18n';
15
15
  import FileUpload from './FileUpload';
16
+ import ModalContext from '../context/ModalContext';
16
17
  import Toaster from './Toaster';
17
18
 
18
19
  type Props = {
@@ -195,44 +196,48 @@ class FileUploadModal extends Component<Props, State> {
195
196
  />
196
197
  )}
197
198
  { this.state.modal && (
198
- <Modal
199
- centered={false}
200
- className='file-upload-modal'
201
- open
202
- >
203
- <Dimmer
204
- active={this.state.saving}
205
- inverted
206
- >
207
- <Loader
208
- content={i18n.t('FileUploadModal.loader')}
209
- />
210
- </Dimmer>
211
- { this.renderErrors() }
212
- <Modal.Header
213
- content={this.props.title || i18n.t('FileUploadModal.title')}
214
- />
215
- <Modal.Content>
216
- <FileUpload
217
- onFilesAdded={this.onAddFiles.bind(this)}
218
- />
219
- { this.renderItems() }
220
- </Modal.Content>
221
- <Modal.Actions>
222
- <Button
223
- content={i18n.t('Common.buttons.save')}
224
- disabled={!(this.state.items && this.state.items.length)}
225
- primary
226
- onClick={this.onSave.bind(this)}
227
- />
228
- <Button
229
- content={i18n.t('Common.buttons.cancel')}
230
- inverted
231
- primary
232
- onClick={this.onClose.bind(this)}
233
- />
234
- </Modal.Actions>
235
- </Modal>
199
+ <ModalContext.Consumer>
200
+ { (mountNode) => (
201
+ <Modal
202
+ centered={false}
203
+ className='file-upload-modal'
204
+ mountNode={mountNode}
205
+ open
206
+ >
207
+ <Dimmer
208
+ active={this.state.saving}
209
+ inverted
210
+ >
211
+ <Loader
212
+ content={i18n.t('FileUploadModal.loader')}
213
+ />
214
+ </Dimmer>
215
+ { this.renderErrors() }
216
+ <Modal.Header
217
+ content={this.props.title || i18n.t('FileUploadModal.title')}
218
+ />
219
+ <Modal.Content>
220
+ <FileUpload
221
+ onFilesAdded={this.onAddFiles.bind(this)}
222
+ />
223
+ { this.renderItems() }
224
+ </Modal.Content>
225
+ <Modal.Actions>
226
+ <Button
227
+ content={i18n.t('Common.buttons.save')}
228
+ disabled={!(this.state.items && this.state.items.length)}
229
+ primary
230
+ onClick={this.onSave.bind(this)}
231
+ />
232
+ <Button
233
+ basic
234
+ content={i18n.t('Common.buttons.cancel')}
235
+ onClick={this.onClose.bind(this)}
236
+ />
237
+ </Modal.Actions>
238
+ </Modal>
239
+ )}
240
+ </ModalContext.Consumer>
236
241
  )}
237
242
  </>
238
243
  );
@@ -14,6 +14,7 @@ import {
14
14
  import _ from 'underscore';
15
15
  import i18n from '../i18n/i18n';
16
16
  import DateField from './DateInput';
17
+ import ModalContext from '../context/ModalContext';
17
18
  import './FuzzyDate.css';
18
19
 
19
20
  type DateInput = {
@@ -334,110 +335,119 @@ class FuzzyDate extends Component<Props, State> {
334
335
  onClick={this.onEdit.bind(this)}
335
336
  onChange={this.onClear.bind(this)}
336
337
  />
337
- <Modal
338
- as={Form}
339
- className='fuzzy-date-modal'
340
- open={this.state.modal}
341
- onClose={this.onClose.bind(this)}
342
- >
343
- <Modal.Header
344
- content={this.props.title || i18n.t('FuzzyDate.title')}
345
- />
346
- <Modal.Content>
347
- <Form.Input
348
- className='accuracy-container'
349
- label={i18n.t('FuzzyDate.labels.accuracy')}
338
+ <ModalContext.Consumer>
339
+ { (mountNode) => (
340
+ <Modal
341
+ as={Form}
342
+ className='fuzzy-date-modal'
343
+ mountNode={mountNode}
344
+ open={this.state.modal}
345
+ onClose={this.onClose.bind(this)}
350
346
  >
351
- <Checkbox
352
- checked={this.state.accuracy === ACCURACY_YEAR}
353
- label={i18n.t('FuzzyDate.accuracy.year')}
354
- name='accuracy'
355
- onChange={this.onAccuracyChange.bind(this)}
356
- radio
357
- value={ACCURACY_YEAR}
347
+ <Modal.Header
348
+ content={this.props.title || i18n.t('FuzzyDate.title')}
358
349
  />
359
- <Checkbox
360
- checked={this.state.accuracy === ACCURACY_MONTH}
361
- label={i18n.t('FuzzyDate.accuracy.month')}
362
- name='accuracy'
363
- onChange={this.onAccuracyChange.bind(this)}
364
- radio
365
- value={ACCURACY_MONTH}
366
- />
367
- <Checkbox
368
- checked={this.state.accuracy === ACCURACY_DATE}
369
- label={i18n.t('FuzzyDate.accuracy.date')}
370
- name='accuracy'
371
- onChange={this.onAccuracyChange.bind(this)}
372
- radio
373
- value={ACCURACY_DATE}
374
- />
375
- </Form.Input>
376
- <Form.Group>
377
- { this.renderYear('startDate') }
378
- { this.renderMonth('startDate') }
379
- { this.renderDate('startDate') }
380
- { !this.state.range && (
381
- <div
382
- className='button-container'
350
+ <Modal.Content>
351
+ <Form.Input
352
+ className='accuracy-container'
353
+ label={i18n.t('FuzzyDate.labels.accuracy')}
383
354
  >
384
- <Button
385
- basic
386
- content={i18n.t('FuzzyDate.buttons.addRange')}
387
- icon='plus'
388
- onClick={this.onRangeChange.bind(this)}
355
+ <Checkbox
356
+ checked={this.state.accuracy === ACCURACY_YEAR}
357
+ id='accuracy-year'
358
+ label={i18n.t('FuzzyDate.accuracy.year')}
359
+ name='accuracy'
360
+ onChange={this.onAccuracyChange.bind(this)}
361
+ radio
362
+ value={ACCURACY_YEAR}
389
363
  />
390
- </div>
391
- )}
392
- </Form.Group>
393
- { this.state.range && (
394
- <Form.Group>
395
- { this.renderYear('endDate') }
396
- { this.renderMonth('endDate') }
397
- { this.renderDate('endDate') }
398
- <div
399
- className='button-container'
400
- >
401
- <Button
402
- basic
403
- content={i18n.t('FuzzyDate.buttons.removeRange')}
404
- icon='times'
405
- onClick={this.onRangeChange.bind(this)}
364
+ <Checkbox
365
+ checked={this.state.accuracy === ACCURACY_MONTH}
366
+ id='accuracy-month'
367
+ label={i18n.t('FuzzyDate.accuracy.month')}
368
+ name='accuracy'
369
+ onChange={this.onAccuracyChange.bind(this)}
370
+ radio
371
+ value={ACCURACY_MONTH}
406
372
  />
407
- </div>
408
- </Form.Group>
409
- )}
410
- { this.props.description && (
411
- <Form.Input
412
- label={i18n.t('FuzzyDate.labels.description')}
413
- >
414
- <TextArea
415
- onChange={this.onDescriptionChange.bind(this)}
416
- value={this.state.description}
417
- />
418
- </Form.Input>
419
- )}
420
- </Modal.Content>
421
- <Modal.Actions>
422
- <Button
423
- onClick={this.onSave.bind(this)}
424
- primary
425
- size='medium'
426
- type='submit'
427
- >
428
- { i18n.t('Common.buttons.save') }
429
- </Button>
430
- <Button
431
- inverted
432
- onClick={this.onClose.bind(this)}
433
- primary
434
- size='medium'
435
- type='button'
436
- >
437
- { i18n.t('Common.buttons.cancel') }
438
- </Button>
439
- </Modal.Actions>
440
- </Modal>
373
+ <Checkbox
374
+ checked={this.state.accuracy === ACCURACY_DATE}
375
+ id='accuracy-date'
376
+ label={i18n.t('FuzzyDate.accuracy.date')}
377
+ name='accuracy'
378
+ onChange={this.onAccuracyChange.bind(this)}
379
+ radio
380
+ value={ACCURACY_DATE}
381
+ />
382
+ </Form.Input>
383
+ <Form.Group>
384
+ { this.renderYear('startDate') }
385
+ { this.renderMonth('startDate') }
386
+ { this.renderDate('startDate') }
387
+ { !this.state.range && (
388
+ <div
389
+ className='button-container'
390
+ >
391
+ <Button
392
+ basic
393
+ content={i18n.t('FuzzyDate.buttons.addRange')}
394
+ icon='plus'
395
+ onClick={this.onRangeChange.bind(this)}
396
+ />
397
+ </div>
398
+ )}
399
+ </Form.Group>
400
+ { this.state.range && (
401
+ <Form.Group>
402
+ { this.renderYear('endDate') }
403
+ { this.renderMonth('endDate') }
404
+ { this.renderDate('endDate') }
405
+ <div
406
+ className='button-container'
407
+ >
408
+ <Button
409
+ basic
410
+ content={i18n.t('FuzzyDate.buttons.removeRange')}
411
+ icon='times'
412
+ onClick={this.onRangeChange.bind(this)}
413
+ />
414
+ </div>
415
+ </Form.Group>
416
+ )}
417
+ { this.props.description && (
418
+ <Form.Input
419
+ id='description'
420
+ label={i18n.t('FuzzyDate.labels.description')}
421
+ >
422
+ <TextArea
423
+ id='description'
424
+ onChange={this.onDescriptionChange.bind(this)}
425
+ value={this.state.description}
426
+ />
427
+ </Form.Input>
428
+ )}
429
+ </Modal.Content>
430
+ <Modal.Actions>
431
+ <Button
432
+ onClick={this.onSave.bind(this)}
433
+ primary
434
+ size='medium'
435
+ type='submit'
436
+ >
437
+ { i18n.t('Common.buttons.save') }
438
+ </Button>
439
+ <Button
440
+ basic
441
+ onClick={this.onClose.bind(this)}
442
+ size='medium'
443
+ type='button'
444
+ >
445
+ { i18n.t('Common.buttons.cancel') }
446
+ </Button>
447
+ </Modal.Actions>
448
+ </Modal>
449
+ )}
450
+ </ModalContext.Consumer>
441
451
  </>
442
452
  );
443
453
  }
@@ -459,6 +469,7 @@ class FuzzyDate extends Component<Props, State> {
459
469
 
460
470
  return (
461
471
  <Form.Input
472
+ id='date-dropdown'
462
473
  label={i18n.t('FuzzyDate.labels.date')}
463
474
  >
464
475
  <Dropdown
@@ -486,9 +497,11 @@ class FuzzyDate extends Component<Props, State> {
486
497
 
487
498
  return (
488
499
  <Form.Input
500
+ id='month-dropdown'
489
501
  label={i18n.t('FuzzyDate.labels.month')}
490
502
  >
491
503
  <Dropdown
504
+ id='month-dropdown'
492
505
  onChange={this.onMonthChange.bind(this, property)}
493
506
  options={_.map(this.state.calendar.listMonths(), (m, i) => ({ key: i, value: i, text: m }))}
494
507
  selection
@@ -508,9 +521,11 @@ class FuzzyDate extends Component<Props, State> {
508
521
  renderYear(property: string) {
509
522
  return (
510
523
  <Form.Input
524
+ id='year'
511
525
  label={i18n.t('FuzzyDate.labels.year')}
512
526
  >
513
527
  <Input
528
+ id='year'
514
529
  onChange={this.onYearChange.bind(this, property)}
515
530
  type='number'
516
531
  value={this.state[property].year || ''}