@teselagen/ui 0.6.6 → 0.7.1

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 (98) hide show
  1. package/DataTable/ColumnFilterMenu.d.ts +2 -1
  2. package/DataTable/Columns.d.ts +51 -0
  3. package/DataTable/DisplayOptions.d.ts +14 -14
  4. package/DataTable/EditabelCell.d.ts +2 -5
  5. package/DataTable/EditableCell.d.ts +7 -0
  6. package/DataTable/FilterAndSortMenu.d.ts +9 -9
  7. package/DataTable/PagingTool.d.ts +25 -2
  8. package/DataTable/RenderCell.d.ts +18 -0
  9. package/DataTable/SearchBar.d.ts +4 -3
  10. package/DataTable/SortableColumns.d.ts +6 -9
  11. package/DataTable/ThComponent.d.ts +9 -0
  12. package/DataTable/index.d.ts +0 -5
  13. package/DataTable/utils/getIdOrCodeOrIndex.d.ts +1 -2
  14. package/DataTable/utils/handleCopyTable.d.ts +1 -0
  15. package/DataTable/utils/index.d.ts +4 -2
  16. package/DataTable/utils/primarySelectedValue.d.ts +1 -0
  17. package/DataTable/utils/queryParams.d.ts +13 -8
  18. package/DataTable/utils/removeCleanRows.d.ts +1 -1
  19. package/DataTable/utils/rowClick.d.ts +24 -3
  20. package/DataTable/utils/useDeepEqualMemo.d.ts +1 -0
  21. package/DataTable/utils/useTableEntities.d.ts +5 -0
  22. package/DataTable/utils/useTableParams.d.ts +49 -0
  23. package/DataTable/utils/withTableParams.d.ts +3 -16
  24. package/DataTable/viewColumn.d.ts +11 -4
  25. package/FormComponents/AbstractField.d.ts +1 -0
  26. package/FormComponents/Uploader.d.ts +34 -1
  27. package/FormComponents/index.d.ts +111 -60
  28. package/MatchHeaders.d.ts +9 -10
  29. package/SimpleStepViz.d.ts +2 -1
  30. package/TgSuggest/index.d.ts +1 -21
  31. package/UploadCsvWizard.d.ts +1 -1
  32. package/index.cjs.js +47861 -49125
  33. package/index.d.ts +6 -3
  34. package/index.es.js +47959 -49223
  35. package/package.json +6 -5
  36. package/src/DataTable/CellDragHandle.js +70 -69
  37. package/src/DataTable/ColumnFilterMenu.js +23 -21
  38. package/src/DataTable/Columns.js +948 -0
  39. package/src/DataTable/Columns.jsx +945 -0
  40. package/src/DataTable/DisplayOptions.js +173 -192
  41. package/src/DataTable/EditabelCell.js +7 -18
  42. package/src/DataTable/EditabelCell.jsx +44 -0
  43. package/src/DataTable/EditableCell.js +44 -0
  44. package/src/DataTable/FilterAndSortMenu.js +215 -234
  45. package/src/DataTable/PagingTool.js +47 -56
  46. package/src/DataTable/RenderCell.js +191 -0
  47. package/src/DataTable/RenderCell.jsx +191 -0
  48. package/src/DataTable/SearchBar.js +12 -5
  49. package/src/DataTable/SortableColumns.js +44 -39
  50. package/src/DataTable/ThComponent.js +44 -0
  51. package/src/DataTable/dataTableEnhancer.js +32 -295
  52. package/src/DataTable/index.js +2945 -3596
  53. package/src/DataTable/utils/getIdOrCodeOrIndex.js +1 -1
  54. package/src/DataTable/utils/handleCopyTable.js +16 -0
  55. package/src/DataTable/utils/index.js +7 -3
  56. package/src/DataTable/utils/primarySelectedValue.js +1 -0
  57. package/src/DataTable/utils/queryParams.js +110 -85
  58. package/src/DataTable/utils/removeCleanRows.js +3 -3
  59. package/src/DataTable/utils/rowClick.js +34 -9
  60. package/src/DataTable/utils/selection.js +1 -1
  61. package/src/DataTable/utils/useDeepEqualMemo.js +10 -0
  62. package/src/DataTable/utils/useTableEntities.js +38 -0
  63. package/src/DataTable/utils/useTableParams.js +362 -0
  64. package/src/DataTable/utils/withTableParams.js +244 -274
  65. package/src/DataTable/validateTableWideErrors.js +1 -1
  66. package/src/DataTable/viewColumn.js +5 -9
  67. package/src/DialogFooter/index.js +3 -3
  68. package/src/FillWindow.js +2 -3
  69. package/src/FormComponents/AbstractField.js +388 -0
  70. package/src/FormComponents/Uploader.js +674 -649
  71. package/src/FormComponents/index.js +505 -654
  72. package/src/FormComponents/tryToMatchSchemas.js +1 -6
  73. package/src/MatchHeaders.js +27 -22
  74. package/src/SimpleStepViz.js +19 -23
  75. package/src/TgSelect/index.js +1 -1
  76. package/src/TgSuggest/index.js +94 -106
  77. package/src/UploadCsvWizard.js +571 -577
  78. package/src/enhancers/withDialog/tg_modalState.js +1 -0
  79. package/src/index.js +10 -4
  80. package/src/showDialogOnDocBody.js +5 -9
  81. package/src/useDialog.js +25 -26
  82. package/src/utils/commandControls.js +2 -2
  83. package/src/utils/handlerHelpers.js +19 -25
  84. package/src/utils/hooks/index.js +1 -0
  85. package/src/utils/hooks/useDeepEqualMemo.js +10 -0
  86. package/src/utils/hooks/useStableReference.js +9 -0
  87. package/src/utils/renderOnDoc.js +8 -5
  88. package/src/utils/tagUtils.js +3 -3
  89. package/src/utils/useTraceUpdate.js +19 -0
  90. package/src/wrapDialog.js +0 -2
  91. package/style.css +251 -251
  92. package/useDialog.d.ts +2 -6
  93. package/utils/hooks/index.d.ts +1 -0
  94. package/utils/hooks/useDeepEqualMemo.d.ts +1 -0
  95. package/utils/hooks/useStableReference.d.ts +1 -0
  96. package/utils/renderOnDoc.d.ts +1 -1
  97. package/utils/tagUtils.d.ts +5 -1
  98. package/utils/useTraceUpdate.d.ts +1 -0
@@ -1,5 +1,5 @@
1
- import React from "react";
2
- import { map, isEmpty, noop } from "lodash-es";
1
+ import React, { useState } from "react";
2
+ import { map, isEmpty, noop, startCase } from "lodash-es";
3
3
  import {
4
4
  Button,
5
5
  Checkbox,
@@ -10,209 +10,190 @@ import {
10
10
  Popover,
11
11
  Switch
12
12
  } from "@blueprintjs/core";
13
+ import { getCCDisplayName } from "./utils/queryParams";
13
14
 
14
- export default class DisplayOptions extends React.Component {
15
- state = {
16
- isOpen: false,
17
- searchTerms: {}
18
- };
19
-
20
- openPopover = () => {
21
- this.setState({
22
- isOpen: true
23
- });
24
- };
15
+ const DisplayOptions = ({
16
+ compact,
17
+ extraCompact,
18
+ disabled,
19
+ hideDisplayOptionsIcon,
20
+ resetDefaultVisibility = noop,
21
+ updateColumnVisibility = noop,
22
+ updateTableDisplayDensity,
23
+ showForcedHiddenColumns,
24
+ setShowForcedHidden,
25
+ hasOptionForForcedHidden,
26
+ schema
27
+ }) => {
28
+ const [isOpen, setIsOpen] = useState(false);
29
+ const [searchTerms, setSearchTerms] = useState({});
25
30
 
26
- closePopover = () => {
27
- this.setState({
28
- isOpen: false
29
- });
30
- };
31
-
32
- changeTableDensity = e => {
33
- const { updateTableDisplayDensity = noop } = this.props;
31
+ const changeTableDensity = e => {
34
32
  updateTableDisplayDensity(e.target.value);
35
- this.closePopover();
33
+ setIsOpen(false);
36
34
  };
37
35
 
38
- toggleForcedHidden = e => this.props.setShowForcedHidden(e.target.checked);
36
+ const toggleForcedHidden = e => setShowForcedHidden(e.target.checked);
37
+
38
+ if (hideDisplayOptionsIcon) {
39
+ return null; //don't show antyhing!
40
+ }
41
+ const { fields } = schema;
42
+ const fieldGroups = {};
43
+ const mainFields = [];
39
44
 
40
- render() {
41
- const { isOpen, searchTerms } = this.state;
42
- const {
43
- schema,
44
- updateColumnVisibility = noop,
45
- resetDefaultVisibility = noop,
46
- compact,
47
- extraCompact,
48
- disabled,
49
- hasOptionForForcedHidden,
50
- showForcedHiddenColumns,
51
- hideDisplayOptionsIcon
52
- } = this.props;
53
- if (hideDisplayOptionsIcon) {
54
- return null; //don't show antyhing!
55
- }
56
- const { fields } = schema;
57
- const fieldGroups = {};
58
- const mainFields = [];
45
+ fields.forEach(field => {
46
+ if (field.hideInMenu) return;
47
+ if (!field.fieldGroup) return mainFields.push(field);
48
+ if (!fieldGroups[field.fieldGroup]) fieldGroups[field.fieldGroup] = [];
49
+ fieldGroups[field.fieldGroup].push(field);
50
+ });
59
51
 
60
- fields.forEach(field => {
61
- if (field.hideInMenu) return;
62
- if (!field.fieldGroup) return mainFields.push(field);
63
- if (!fieldGroups[field.fieldGroup]) fieldGroups[field.fieldGroup] = [];
64
- fieldGroups[field.fieldGroup].push(field);
65
- });
52
+ let numVisible = 0;
66
53
 
67
- let numVisible = 0;
54
+ const getFieldCheckbox = (field, i) => {
55
+ const { displayName, isHidden, isForcedHidden, path } = field;
56
+ if (isForcedHidden) return;
57
+ if (!isHidden) numVisible++;
58
+ return (
59
+ <Checkbox
60
+ name={`${path}-${i}`}
61
+ key={path || i}
62
+ onChange={() => {
63
+ if (numVisible <= 1 && !isHidden) {
64
+ return window.toastr.warning(
65
+ "We have to display at least one column :)"
66
+ );
67
+ }
68
+ updateColumnVisibility({ shouldShow: isHidden, path });
69
+ }}
70
+ checked={!isHidden}
71
+ label={displayName}
72
+ />
73
+ );
74
+ };
68
75
 
69
- const getFieldCheckbox = (field, i) => {
70
- const { displayName, isHidden, isForcedHidden, path } = field;
71
- if (isForcedHidden) return;
72
- if (!isHidden) numVisible++;
76
+ let fieldGroupMenu;
77
+ if (!isEmpty(fieldGroups)) {
78
+ fieldGroupMenu = map(fieldGroups, (groupFields, groupName) => {
79
+ const searchTerm = searchTerms[groupName] || "";
80
+ const anyVisible = groupFields.some(
81
+ field => !field.isHidden && !field.isForcedHidden
82
+ );
83
+ const anyNotForcedHidden = groupFields.some(
84
+ field => !field.isForcedHidden
85
+ );
86
+ if (!anyNotForcedHidden) return;
73
87
  return (
74
- <Checkbox
75
- key={path || i}
76
- onChange={() => {
77
- if (numVisible <= 1 && !isHidden) {
78
- return window.toastr.warning(
79
- "We have to display at least one column :)"
80
- );
81
- }
82
- updateColumnVisibility({ shouldShow: isHidden, path });
83
- }}
84
- checked={!isHidden}
85
- label={displayName}
86
- />
88
+ <MenuItem key={groupName} text={groupName}>
89
+ <InputGroup
90
+ leftIcon="search"
91
+ value={searchTerm}
92
+ onChange={e => {
93
+ setSearchTerms(prev => ({
94
+ ...prev,
95
+ [groupName]: e.target.value
96
+ }));
97
+ }}
98
+ />
99
+ <Button
100
+ className={Classes.MINIMAL}
101
+ text={(anyVisible ? "Hide" : "Show") + " All"}
102
+ style={{ margin: "10px 0" }}
103
+ onClick={() => {
104
+ updateColumnVisibility({
105
+ shouldShow: !anyVisible,
106
+ paths: groupFields.map(field => field.path)
107
+ });
108
+ }}
109
+ />
110
+ {groupFields
111
+ .filter(
112
+ field =>
113
+ startCase(getCCDisplayName(field)) // We have to use startCase with the camelCase here because the displayName is not always a string
114
+ .toLowerCase()
115
+ .indexOf(searchTerm.toLowerCase()) > -1
116
+ )
117
+ .map(getFieldCheckbox)}
118
+ </MenuItem>
87
119
  );
88
- };
89
-
90
- let fieldGroupMenu;
91
- if (!isEmpty(fieldGroups)) {
92
- fieldGroupMenu = map(fieldGroups, (groupFields, groupName) => {
93
- const searchTerm = searchTerms[groupName] || "";
94
- const anyVisible = groupFields.some(
95
- field => !field.isHidden && !field.isForcedHidden
96
- );
97
- const anyNotForcedHidden = groupFields.some(
98
- field => !field.isForcedHidden
99
- );
100
- if (!anyNotForcedHidden) return;
101
- return (
102
- <MenuItem key={groupName} text={groupName}>
103
- <InputGroup
104
- leftIcon="search"
105
- value={searchTerm}
106
- onChange={e => {
107
- this.setState({
108
- searchTerms: {
109
- ...searchTerms,
110
- [groupName]: e.target.value
111
- }
112
- });
113
- }}
114
- />
115
- <Button
116
- className={Classes.MINIMAL}
117
- text={(anyVisible ? "Hide" : "Show") + " All"}
118
- style={{ margin: "10px 0" }}
119
- onClick={() => {
120
- updateColumnVisibility({
121
- shouldShow: !anyVisible,
122
- paths: groupFields.map(field => field.path)
123
- });
124
- }}
125
- />
126
- {groupFields
127
- .filter(
128
- field =>
129
- field.displayName
130
- .toLowerCase()
131
- .indexOf(searchTerm.toLowerCase()) > -1
132
- )
133
- .map(getFieldCheckbox)}
134
- </MenuItem>
135
- );
136
- });
137
- }
120
+ });
121
+ }
138
122
 
139
- return (
140
- <Popover
141
- isOpen={isOpen}
142
- onClose={this.closePopover}
143
- content={
144
- <Menu>
145
- <div style={{ padding: 10, paddingLeft: 20, paddingRight: 20 }}>
146
- <h5 style={{ marginBottom: 10 }}>Display Density:</h5>
147
- <div className={Classes.SELECT + " tg-table-display-density"}>
148
- <select
149
- onChange={this.changeTableDensity}
150
- value={
151
- extraCompact
152
- ? "extraCompact"
153
- : compact
154
- ? "compact"
155
- : "normal"
156
- }
157
- >
158
- <option className={Classes.POPOVER_DISMISS} value="normal">
159
- Comfortable
160
- </option>
161
- {/* tnr: as you can see we're calling what was "compact" Normal now in response to https://github.com/TeselaGen/lims/issues/4713 */}
162
- <option className={Classes.POPOVER_DISMISS} value="compact">
163
- Normal
164
- </option>
165
- <option
166
- className={Classes.POPOVER_DISMISS}
167
- value="extraCompact"
168
- >
169
- Compact
170
- </option>
171
- </select>
172
- </div>
173
- <h5 style={{ marginBottom: 10, marginTop: 10 }}>
174
- Displayed Columns:
175
- </h5>
176
- <div style={{ maxHeight: 260, overflowY: "auto", padding: 2 }}>
177
- {mainFields.map(getFieldCheckbox)}
178
- </div>
179
- <div>{fieldGroupMenu}</div>
180
- {hasOptionForForcedHidden && (
181
- <div style={{ marginTop: 15 }}>
182
- <Switch
183
- label="Show Empty Columns"
184
- checked={showForcedHiddenColumns}
185
- onChange={this.toggleForcedHidden}
186
- />
187
- </div>
188
- )}
189
- <div
190
- style={{
191
- width: "100%",
192
- display: "flex",
193
- justifyContent: "flex-end"
194
- }}
123
+ return (
124
+ <Popover
125
+ isOpen={isOpen}
126
+ onClose={() => setIsOpen(false)}
127
+ content={
128
+ <Menu>
129
+ <div style={{ padding: 10, paddingLeft: 20, paddingRight: 20 }}>
130
+ <h5 style={{ marginBottom: 10 }}>Display Density:</h5>
131
+ <div className={Classes.SELECT + " tg-table-display-density"}>
132
+ <select
133
+ onChange={changeTableDensity}
134
+ value={
135
+ extraCompact ? "extraCompact" : compact ? "compact" : "normal"
136
+ }
195
137
  >
196
- <Button
197
- onClick={resetDefaultVisibility}
198
- title="Display Options"
199
- minimal
138
+ <option className={Classes.POPOVER_DISMISS} value="normal">
139
+ Comfortable
140
+ </option>
141
+ {/* tnr: as you can see we're calling what was "compact" Normal now in response to https://github.com/TeselaGen/lims/issues/4713 */}
142
+ <option className={Classes.POPOVER_DISMISS} value="compact">
143
+ Normal
144
+ </option>
145
+ <option
146
+ className={Classes.POPOVER_DISMISS}
147
+ value="extraCompact"
200
148
  >
201
- Reset
202
- </Button>
149
+ Compact
150
+ </option>
151
+ </select>
152
+ </div>
153
+ <h5 style={{ marginBottom: 10, marginTop: 10 }}>
154
+ Displayed Columns:
155
+ </h5>
156
+ <div style={{ maxHeight: 260, overflowY: "auto", padding: 2 }}>
157
+ {mainFields.map(getFieldCheckbox)}
158
+ </div>
159
+ <div>{fieldGroupMenu}</div>
160
+ {hasOptionForForcedHidden && (
161
+ <div style={{ marginTop: 15 }}>
162
+ <Switch
163
+ label="Show Empty Columns"
164
+ checked={showForcedHiddenColumns}
165
+ onChange={toggleForcedHidden}
166
+ />
203
167
  </div>
168
+ )}
169
+ <div
170
+ style={{
171
+ width: "100%",
172
+ display: "flex",
173
+ justifyContent: "flex-end"
174
+ }}
175
+ >
176
+ <Button
177
+ onClick={resetDefaultVisibility}
178
+ title="Display Options"
179
+ minimal
180
+ >
181
+ Reset
182
+ </Button>
204
183
  </div>
205
- </Menu>
206
- }
207
- >
208
- <Button
209
- className="tg-table-display-options"
210
- onClick={this.openPopover}
211
- disabled={disabled}
212
- minimal
213
- icon="cog"
214
- />
215
- </Popover>
216
- );
217
- }
218
- }
184
+ </div>
185
+ </Menu>
186
+ }
187
+ >
188
+ <Button
189
+ className="tg-table-display-options"
190
+ onClick={() => setIsOpen(true)}
191
+ disabled={disabled}
192
+ minimal
193
+ icon="cog"
194
+ />
195
+ </Popover>
196
+ );
197
+ };
198
+
199
+ export default DisplayOptions;
@@ -1,30 +1,20 @@
1
- import React, { useEffect, useRef, useState } from "react";
1
+ import React, { useEffect, useRef } from "react";
2
2
 
3
3
  export const EditableCell = ({
4
+ value,
5
+ setValue,
4
6
  cancelEdit,
5
7
  dataTest,
6
8
  finishEdit,
7
- initialValue,
8
- isEditableCellInitialValue,
9
- isNumeric,
10
- shouldSelectAll,
11
- stopSelectAll
9
+ isNumeric
12
10
  }) => {
13
- const [value, setValue] = useState(initialValue);
14
11
  const inputRef = useRef(null);
15
12
 
16
13
  useEffect(() => {
17
14
  if (inputRef.current) {
18
15
  inputRef.current.focus();
19
- if (isEditableCellInitialValue && !isNumeric) {
20
- inputRef.current.selectionStart = inputRef.current.value.length;
21
- inputRef.current.selectionEnd = inputRef.current.value.length;
22
- } else if (shouldSelectAll) {
23
- inputRef.current.select();
24
- stopSelectAll();
25
- }
26
16
  }
27
- }, [isEditableCellInitialValue, isNumeric, shouldSelectAll, stopSelectAll]);
17
+ }, [isNumeric]);
28
18
 
29
19
  return (
30
20
  <input
@@ -38,11 +28,10 @@ export const EditableCell = ({
38
28
  {...dataTest}
39
29
  autoFocus
40
30
  onKeyDown={e => {
31
+ e.stopPropagation();
41
32
  if (e.key === "Enter") {
42
- finishEdit(value);
43
- e.stopPropagation();
33
+ e.target.blur();
44
34
  } else if (e.key === "Escape") {
45
- e.stopPropagation();
46
35
  cancelEdit();
47
36
  }
48
37
  }}
@@ -0,0 +1,44 @@
1
+ import React, { useEffect, useRef, useState } from "react";
2
+
3
+ export const EditableCell = ({
4
+ cancelEdit,
5
+ dataTest,
6
+ finishEdit,
7
+ isNumeric,
8
+ initialValue
9
+ }) => {
10
+ const [value, setValue] = useState(initialValue);
11
+ const inputRef = useRef(null);
12
+
13
+ useEffect(() => {
14
+ if (inputRef.current) {
15
+ inputRef.current.focus();
16
+ }
17
+ }, [isNumeric]);
18
+
19
+ return (
20
+ <input
21
+ style={{
22
+ border: 0,
23
+ width: "95%",
24
+ fontSize: 12,
25
+ background: "none"
26
+ }}
27
+ ref={inputRef}
28
+ {...dataTest}
29
+ autoFocus
30
+ onKeyDown={e => {
31
+ e.stopPropagation();
32
+ if (e.key === "Enter") {
33
+ e.target.blur();
34
+ } else if (e.key === "Escape") {
35
+ cancelEdit();
36
+ }
37
+ }}
38
+ onBlur={() => finishEdit(value)}
39
+ onChange={e => setValue(e.target.value)}
40
+ type={isNumeric ? "number" : undefined}
41
+ value={value}
42
+ />
43
+ );
44
+ };
@@ -0,0 +1,44 @@
1
+ import React, { useEffect, useRef, useState } from "react";
2
+
3
+ export const EditableCell = ({
4
+ cancelEdit,
5
+ dataTest,
6
+ finishEdit,
7
+ isNumeric,
8
+ initialValue
9
+ }) => {
10
+ const [value, setValue] = useState(initialValue);
11
+ const inputRef = useRef(null);
12
+
13
+ useEffect(() => {
14
+ if (inputRef.current) {
15
+ inputRef.current.focus();
16
+ }
17
+ }, [isNumeric]);
18
+
19
+ return (
20
+ <input
21
+ style={{
22
+ border: 0,
23
+ width: "95%",
24
+ fontSize: 12,
25
+ background: "none"
26
+ }}
27
+ ref={inputRef}
28
+ {...dataTest}
29
+ autoFocus
30
+ onKeyDown={e => {
31
+ e.stopPropagation();
32
+ if (e.key === "Enter") {
33
+ e.target.blur();
34
+ } else if (e.key === "Escape") {
35
+ cancelEdit();
36
+ }
37
+ }}
38
+ onBlur={() => finishEdit(value)}
39
+ onChange={e => setValue(e.target.value)}
40
+ type={isNumeric ? "number" : undefined}
41
+ value={value}
42
+ />
43
+ );
44
+ };