@teselagen/ui 0.7.34 → 0.7.36

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 (161) hide show
  1. package/isBeingCalledExcessively.js +2 -0
  2. package/package.json +1 -1
  3. package/style.css +26 -10
  4. package/DataTable/utils/filterLocalEntitiesToHasura.d.ts +0 -5
  5. package/DataTable/utils/initializeHasuraWhereAndFilter.d.ts +0 -2
  6. package/DataTable/utils/tableQueryParamsToHasuraClauses.d.ts +0 -26
  7. package/src/AdvancedOptions.js +0 -33
  8. package/src/AdvancedOptions.spec.js +0 -26
  9. package/src/AssignDefaultsModeContext.js +0 -22
  10. package/src/AsyncValidateFieldSpinner/index.js +0 -12
  11. package/src/BlueprintError/index.js +0 -14
  12. package/src/BounceLoader/index.js +0 -16
  13. package/src/BounceLoader/style.css +0 -45
  14. package/src/CollapsibleCard/index.js +0 -68
  15. package/src/CollapsibleCard/style.css +0 -23
  16. package/src/DNALoader/index.js +0 -20
  17. package/src/DNALoader/style.css +0 -251
  18. package/src/DataTable/CellDragHandle.js +0 -132
  19. package/src/DataTable/ColumnFilterMenu.js +0 -62
  20. package/src/DataTable/Columns.js +0 -979
  21. package/src/DataTable/DisabledLoadingComponent.js +0 -15
  22. package/src/DataTable/DisplayOptions.js +0 -199
  23. package/src/DataTable/DropdownCell.js +0 -61
  24. package/src/DataTable/EditableCell.js +0 -44
  25. package/src/DataTable/FilterAndSortMenu.js +0 -388
  26. package/src/DataTable/PagingTool.js +0 -225
  27. package/src/DataTable/RenderCell.js +0 -191
  28. package/src/DataTable/SearchBar.js +0 -69
  29. package/src/DataTable/SortableColumns.js +0 -100
  30. package/src/DataTable/TableFormTrackerContext.js +0 -10
  31. package/src/DataTable/ThComponent.js +0 -44
  32. package/src/DataTable/dataTableEnhancer.js +0 -41
  33. package/src/DataTable/defaultFormatters.js +0 -32
  34. package/src/DataTable/defaultValidators.js +0 -40
  35. package/src/DataTable/editCellHelper.js +0 -44
  36. package/src/DataTable/getCellVal.js +0 -20
  37. package/src/DataTable/getVals.js +0 -8
  38. package/src/DataTable/index.js +0 -3209
  39. package/src/DataTable/isTruthy.js +0 -12
  40. package/src/DataTable/isValueEmpty.js +0 -3
  41. package/src/DataTable/style.css +0 -608
  42. package/src/DataTable/utils/convertSchema.js +0 -69
  43. package/src/DataTable/utils/filterLocalEntitiesToHasura.js +0 -236
  44. package/src/DataTable/utils/filterLocalEntitiesToHasura.test.js +0 -587
  45. package/src/DataTable/utils/formatPasteData.js +0 -16
  46. package/src/DataTable/utils/getAllRows.js +0 -11
  47. package/src/DataTable/utils/getCellCopyText.js +0 -7
  48. package/src/DataTable/utils/getCellInfo.js +0 -36
  49. package/src/DataTable/utils/getFieldPathToField.js +0 -7
  50. package/src/DataTable/utils/getIdOrCodeOrIndex.js +0 -9
  51. package/src/DataTable/utils/getLastSelectedEntity.js +0 -11
  52. package/src/DataTable/utils/getNewEntToSelect.js +0 -25
  53. package/src/DataTable/utils/getRowCopyText.js +0 -28
  54. package/src/DataTable/utils/getTableConfigFromStorage.js +0 -5
  55. package/src/DataTable/utils/handleCopyColumn.js +0 -21
  56. package/src/DataTable/utils/handleCopyHelper.js +0 -15
  57. package/src/DataTable/utils/handleCopyRows.js +0 -23
  58. package/src/DataTable/utils/handleCopyTable.js +0 -16
  59. package/src/DataTable/utils/index.js +0 -55
  60. package/src/DataTable/utils/initializeHasuraWhereAndFilter.js +0 -26
  61. package/src/DataTable/utils/isBottomRightCornerOfRectangle.js +0 -20
  62. package/src/DataTable/utils/isEntityClean.js +0 -15
  63. package/src/DataTable/utils/primarySelectedValue.js +0 -1
  64. package/src/DataTable/utils/queryParams.js +0 -350
  65. package/src/DataTable/utils/removeCleanRows.js +0 -22
  66. package/src/DataTable/utils/rowClick.js +0 -181
  67. package/src/DataTable/utils/selection.js +0 -8
  68. package/src/DataTable/utils/tableQueryParamsToHasuraClauses.js +0 -253
  69. package/src/DataTable/utils/tableQueryParamsToHasuraClauses.test.js +0 -206
  70. package/src/DataTable/utils/useTableEntities.js +0 -38
  71. package/src/DataTable/utils/utils.js +0 -37
  72. package/src/DataTable/utils/withSelectedEntities.js +0 -65
  73. package/src/DataTable/utils/withTableParams.js +0 -288
  74. package/src/DataTable/validateTableWideErrors.js +0 -160
  75. package/src/DataTable/viewColumn.js +0 -97
  76. package/src/DialogFooter/index.js +0 -86
  77. package/src/DialogFooter/style.css +0 -9
  78. package/src/DropdownButton.js +0 -36
  79. package/src/FillWindow.css +0 -6
  80. package/src/FillWindow.js +0 -69
  81. package/src/FormComponents/FormSeparator.js +0 -9
  82. package/src/FormComponents/LoadingDots.js +0 -14
  83. package/src/FormComponents/Uploader.js +0 -1278
  84. package/src/FormComponents/getNewName.js +0 -31
  85. package/src/FormComponents/index.js +0 -1266
  86. package/src/FormComponents/itemUpload.js +0 -84
  87. package/src/FormComponents/sortify.js +0 -73
  88. package/src/FormComponents/style.css +0 -275
  89. package/src/FormComponents/tryToMatchSchemas.js +0 -264
  90. package/src/FormComponents/utils.js +0 -6
  91. package/src/HotkeysDialog/index.js +0 -79
  92. package/src/HotkeysDialog/style.css +0 -54
  93. package/src/InfoHelper/index.js +0 -78
  94. package/src/InfoHelper/style.css +0 -7
  95. package/src/IntentText/index.js +0 -18
  96. package/src/Loading/index.js +0 -70
  97. package/src/Loading/style.css +0 -4
  98. package/src/MatchHeaders.js +0 -234
  99. package/src/MenuBar/index.js +0 -423
  100. package/src/MenuBar/style.css +0 -45
  101. package/src/PromptUnsavedChanges/index.js +0 -38
  102. package/src/ResizableDraggableDialog/index.js +0 -141
  103. package/src/ResizableDraggableDialog/style.css +0 -42
  104. package/src/ScrollToTop/index.js +0 -72
  105. package/src/SimpleStepViz.js +0 -22
  106. package/src/Tag.js +0 -112
  107. package/src/TagSelect/index.js +0 -69
  108. package/src/TagSelect/style.css +0 -13
  109. package/src/TgHtmlSelect/index.js +0 -20
  110. package/src/TgSelect/index.js +0 -537
  111. package/src/TgSelect/style.css +0 -61
  112. package/src/TgSuggest/index.js +0 -124
  113. package/src/Timeline/TimelineEvent.js +0 -31
  114. package/src/Timeline/index.js +0 -15
  115. package/src/Timeline/style.css +0 -29
  116. package/src/UploadCsvWizard.css +0 -4
  117. package/src/UploadCsvWizard.js +0 -719
  118. package/src/autoTooltip.js +0 -201
  119. package/src/constants.js +0 -1
  120. package/src/customIcons.js +0 -361
  121. package/src/enhancers/withDialog/index.js +0 -196
  122. package/src/enhancers/withDialog/tg_modalState.js +0 -47
  123. package/src/enhancers/withField.js +0 -20
  124. package/src/enhancers/withFields.js +0 -11
  125. package/src/enhancers/withLocalStorage.js +0 -11
  126. package/src/index.js +0 -88
  127. package/src/rerenderOnWindowResize.js +0 -26
  128. package/src/showAppSpinner.js +0 -12
  129. package/src/showConfirmationDialog/index.js +0 -148
  130. package/src/showDialogOnDocBody.js +0 -33
  131. package/src/style.css +0 -265
  132. package/src/throwFormError.js +0 -16
  133. package/src/toastr.js +0 -148
  134. package/src/typeToCommonType.js +0 -6
  135. package/src/useDialog.js +0 -63
  136. package/src/utils/adHoc.js +0 -10
  137. package/src/utils/basicHandleActionsWithFullState.js +0 -14
  138. package/src/utils/browserUtils.js +0 -3
  139. package/src/utils/combineReducersWithFullState.js +0 -14
  140. package/src/utils/commandControls.js +0 -82
  141. package/src/utils/commandUtils.js +0 -112
  142. package/src/utils/determineBlackOrWhiteTextColor.js +0 -4
  143. package/src/utils/getDayjsFormatter.js +0 -35
  144. package/src/utils/getTextFromEl.js +0 -28
  145. package/src/utils/handlerHelpers.js +0 -24
  146. package/src/utils/hooks/index.js +0 -1
  147. package/src/utils/hooks/useDeepEqualMemo.js +0 -15
  148. package/src/utils/hooks/useStableReference.js +0 -9
  149. package/src/utils/hotkeyUtils.js +0 -131
  150. package/src/utils/isBeingCalledExcessively.js +0 -24
  151. package/src/utils/menuUtils.js +0 -433
  152. package/src/utils/popoverOverflowModifiers.js +0 -11
  153. package/src/utils/pureNoFunc.js +0 -31
  154. package/src/utils/renderOnDoc.js +0 -32
  155. package/src/utils/showProgressToast.js +0 -22
  156. package/src/utils/tagUtils.js +0 -45
  157. package/src/utils/tgFormValues.js +0 -35
  158. package/src/utils/useTraceUpdate.js +0 -19
  159. package/src/utils/withSelectTableRecords.js +0 -43
  160. package/src/utils/withStore.js +0 -10
  161. package/src/wrapDialog.js +0 -116
@@ -1,15 +0,0 @@
1
- import React from "react";
2
- import { ReactTableDefaults } from "@teselagen/react-table";
3
- const { LoadingComponent } = ReactTableDefaults;
4
-
5
- function DisabledLoadingComponent({ disabled, loading, loadingText }) {
6
- return (
7
- <LoadingComponent
8
- className={disabled ? "disabled" : ""}
9
- loading={loading}
10
- loadingText={disabled ? "" : loadingText}
11
- />
12
- );
13
- }
14
-
15
- export default DisabledLoadingComponent;
@@ -1,199 +0,0 @@
1
- import React, { useState } from "react";
2
- import { map, isEmpty, noop, startCase } from "lodash-es";
3
- import {
4
- Button,
5
- Checkbox,
6
- Menu,
7
- MenuItem,
8
- Classes,
9
- InputGroup,
10
- Popover,
11
- Switch
12
- } from "@blueprintjs/core";
13
- import { getCCDisplayName } from "./utils/tableQueryParamsToHasuraClauses";
14
-
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({});
30
-
31
- const changeTableDensity = e => {
32
- updateTableDisplayDensity(e.target.value);
33
- setIsOpen(false);
34
- };
35
-
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 = [];
44
-
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
- });
51
-
52
- let numVisible = 0;
53
-
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
- };
75
-
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;
87
- return (
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>
119
- );
120
- });
121
- }
122
-
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
- }
137
- >
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"
148
- >
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
- />
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>
183
- </div>
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,61 +0,0 @@
1
- import React, { useState } from "react";
2
- import classNames from "classnames";
3
- import TgSelect from "../TgSelect";
4
-
5
- export const DropdownCell = ({
6
- options,
7
- isMulti,
8
- initialValue,
9
- finishEdit,
10
- cancelEdit,
11
- dataTest
12
- }) => {
13
- const [v, setV] = useState(
14
- isMulti
15
- ? initialValue.split(",").map(v => ({ value: v, label: v }))
16
- : initialValue
17
- );
18
- return (
19
- <div
20
- className={classNames("tg-dropdown-cell-edit-container", {
21
- "tg-dropdown-cell-edit-container-multi": isMulti
22
- })}
23
- >
24
- <TgSelect
25
- small
26
- multi={isMulti}
27
- autoOpen
28
- value={v}
29
- onChange={val => {
30
- if (isMulti) {
31
- setV(val);
32
- return;
33
- }
34
- finishEdit(val ? val.value : null);
35
- }}
36
- {...dataTest}
37
- popoverProps={{
38
- onClose: e => {
39
- if (isMulti) {
40
- if (e && e.key === "Escape") {
41
- cancelEdit();
42
- } else {
43
- finishEdit(
44
- v && v.map
45
- ? v
46
- .map(v => v.value)
47
- .filter(v => v)
48
- .join(",")
49
- : v
50
- );
51
- }
52
- } else {
53
- cancelEdit();
54
- }
55
- }
56
- }}
57
- options={options.map(value => ({ label: value, value }))}
58
- />
59
- </div>
60
- );
61
- };
@@ -1,44 +0,0 @@
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
- };
@@ -1,388 +0,0 @@
1
- import React, { useState } from "react";
2
- import { DateInput, DateRangeInput } from "@blueprintjs/datetime";
3
- import { camelCase, startCase } from "lodash-es";
4
- import classNames from "classnames";
5
- import {
6
- Menu,
7
- Intent,
8
- MenuDivider,
9
- InputGroup,
10
- Classes,
11
- NumericInput,
12
- MenuItem
13
- } from "@blueprintjs/core";
14
- import dayjs from "dayjs";
15
-
16
- import getDayjsFormatter from "../utils/getDayjsFormatter";
17
- import { onEnterHelper } from "../utils/handlerHelpers";
18
- import DialogFooter from "../DialogFooter";
19
- import TgSelect from "../TgSelect";
20
- import "@teselagen/react-table/react-table.css";
21
- import "./style.css";
22
- import "../toastr";
23
-
24
- const filterTypesDictionary = {
25
- none: "",
26
- startsWith: "text",
27
- endsWith: "text",
28
- contains: "text",
29
- notContains: "text",
30
- isExactly: "text",
31
- isEmpty: "text",
32
- notEmpty: "text",
33
- inList: "list",
34
- notInList: "list",
35
- true: "boolean",
36
- false: "boolean",
37
- dateIs: "date",
38
- notBetween: "dateRange",
39
- isBetween: "dateRange",
40
- isBefore: "date",
41
- isAfter: "date",
42
- greaterThan: "number",
43
- lessThan: "number",
44
- inRange: "numberRange",
45
- outsideRange: "numberRange",
46
- equalTo: "number",
47
- regex: "text"
48
- };
49
-
50
- const isInvalidFilterValue = value => {
51
- if (Array.isArray(value) && value.length) {
52
- return value.some(item => isInvalidFilterValue(item));
53
- }
54
- return value === "" || value === undefined || value.length === 0;
55
- };
56
-
57
- const FilterAndSortMenu = ({
58
- dataType,
59
- togglePopover,
60
- filterOn,
61
- addFilters,
62
- removeSingleFilter,
63
- currentFilter
64
- }) => {
65
- const [selectedFilter, setSelectedFilter] = useState(
66
- currentFilter?.selectedFilter ?? camelCase(getFilterMenuItems(dataType)[0])
67
- );
68
- const [filterValue, setFilterValue] = useState(
69
- currentFilter?.filterValue ?? ""
70
- );
71
-
72
- const handleFilterChange = selectedFilter => {
73
- if (
74
- filterValue &&
75
- !Array.isArray(filterValue) &&
76
- filterTypesDictionary[selectedFilter] === "list"
77
- ) {
78
- setFilterValue(filterValue?.split(" ") || []);
79
- } else if (
80
- filterTypesDictionary[selectedFilter] === "text" &&
81
- Array.isArray(filterValue)
82
- ) {
83
- setFilterValue(filterValue.join(" "));
84
- }
85
- setSelectedFilter(camelCase(selectedFilter));
86
- };
87
-
88
- const handleFilterValueChange = filterValue => setFilterValue(filterValue);
89
-
90
- const handleFilterSubmit = () => {
91
- const ccSelectedFilter = camelCase(selectedFilter);
92
- let filterValToUse = filterValue;
93
- if (ccSelectedFilter === "true" || ccSelectedFilter === "false") {
94
- //manually set the filterValue because none is set when type=boolean
95
- filterValToUse = ccSelectedFilter;
96
- } else if (ccSelectedFilter === "notEmpty") {
97
- // manually set filter value (nothing is selected by user)
98
- filterValToUse = true;
99
- } else if (ccSelectedFilter === "isEmpty") {
100
- // manually set filter value (nothing is selected by user)
101
- filterValToUse = false;
102
- } else if (
103
- ccSelectedFilter === "inList" ||
104
- ccSelectedFilter === "notInList"
105
- ) {
106
- if (dataType === "number") {
107
- filterValToUse =
108
- filterValue &&
109
- filterValue.map(val => parseFloat(val.replaceAll(",", "")));
110
- }
111
- }
112
-
113
- if (isInvalidFilterValue(filterValToUse)) {
114
- togglePopover();
115
- return removeSingleFilter(filterOn);
116
- }
117
- addFilters([
118
- {
119
- filterOn,
120
- selectedFilter: ccSelectedFilter,
121
- filterValue: filterValToUse
122
- }
123
- ]);
124
- togglePopover();
125
- };
126
-
127
- const filterMenuItems = getFilterMenuItems(dataType);
128
- const ccSelectedFilter = camelCase(selectedFilter);
129
- const requiresValue = ccSelectedFilter && ccSelectedFilter !== "none";
130
-
131
- return (
132
- <Menu className="data-table-header-menu">
133
- <div className="custom-menu-item">
134
- <div className={classNames(Classes.SELECT, Classes.FILL)}>
135
- <select
136
- onChange={function (e) {
137
- const ccSelectedFilter = camelCase(e.target.value);
138
- handleFilterChange(ccSelectedFilter);
139
- }}
140
- value={ccSelectedFilter}
141
- >
142
- {filterMenuItems.map(function (menuItem, index) {
143
- return (
144
- <option key={index} value={camelCase(menuItem)}>
145
- {menuItem}
146
- </option>
147
- );
148
- })}
149
- </select>
150
- </div>
151
- </div>
152
- <div className="custom-menu-item">
153
- <FilterInput
154
- dataType={dataType}
155
- requiresValue={requiresValue}
156
- handleFilterSubmit={handleFilterSubmit}
157
- filterValue={filterValue}
158
- handleFilterValueChange={handleFilterValueChange}
159
- filterSubType={camelCase(selectedFilter)}
160
- filterType={filterTypesDictionary[camelCase(selectedFilter)]}
161
- />
162
- </div>
163
- <MenuDivider />
164
- <DialogFooter
165
- secondaryClassName={Classes.POPOVER_DISMISS}
166
- onClick={() => {
167
- handleFilterSubmit();
168
- }}
169
- intent={Intent.SUCCESS}
170
- text="Filter"
171
- secondaryText="Clear"
172
- secondaryIntent={Intent.DANGER}
173
- secondaryAction={() => {
174
- if (currentFilter) removeSingleFilter(currentFilter.filterOn);
175
- }}
176
- />
177
- </Menu>
178
- );
179
- };
180
-
181
- export default FilterAndSortMenu;
182
-
183
- const dateMinMaxHelpers = {
184
- minDate: dayjs().subtract(25, "years").toDate(),
185
- maxDate: dayjs().add(25, "years").toDate()
186
- };
187
-
188
- const renderCreateNewOption = (query, active, handleClick) => (
189
- <MenuItem
190
- icon="add"
191
- text={query}
192
- active={active}
193
- onClick={handleClick}
194
- shouldDismissPopover={false}
195
- />
196
- );
197
-
198
- const FilterInput = ({
199
- handleFilterValueChange,
200
- handleFilterSubmit,
201
- filterValue,
202
- filterSubType,
203
- filterType
204
- }) => {
205
- //Options: Text, Single number (before, after, equals), 2 numbers (range),
206
- //Single Date (before, after, on), 2 dates (range)
207
- let inputGroup = <div />;
208
- switch (filterType) {
209
- case "text":
210
- inputGroup =
211
- filterSubType === "notEmpty" || filterSubType === "isEmpty" ? (
212
- <div />
213
- ) : (
214
- <div className="custom-menu-item">
215
- <InputGroup
216
- placeholder="Value"
217
- onChange={function (e) {
218
- handleFilterValueChange(e.target.value);
219
- }}
220
- autoFocus
221
- {...onEnterHelper(handleFilterSubmit)}
222
- value={filterValue}
223
- />
224
- </div>
225
- );
226
- break;
227
- case "list":
228
- inputGroup = (
229
- <div className="custom-menu-item">
230
- <TgSelect
231
- placeholder="Add item"
232
- renderCreateNewOption={renderCreateNewOption}
233
- noResults={null}
234
- multi={true}
235
- creatable={true}
236
- value={(filterValue || []).map(val => ({
237
- label: val,
238
- value: val
239
- }))}
240
- onChange={selectedOptions => {
241
- selectedOptions.some(opt => opt.value === "")
242
- ? handleFilterSubmit()
243
- : handleFilterValueChange(
244
- selectedOptions.map(opt => opt.value)
245
- );
246
- }}
247
- options={[]}
248
- />
249
- </div>
250
- );
251
- break;
252
- case "number":
253
- inputGroup = (
254
- <div className="custom-menu-item">
255
- <NumericInput
256
- placeholder="Value"
257
- onValueChange={function (numVal) {
258
- handleFilterValueChange(isNaN(numVal) ? 0 : numVal);
259
- }}
260
- autoFocus
261
- {...onEnterHelper(handleFilterSubmit)}
262
- value={filterValue}
263
- />
264
- </div>
265
- );
266
- break;
267
- case "numberRange":
268
- inputGroup = (
269
- <div className="custom-menu-item">
270
- <NumericInput
271
- placeholder="Low"
272
- onValueChange={function (numVal) {
273
- handleFilterValueChange([
274
- isNaN(numVal) ? 0 : numVal,
275
- filterValue[1]
276
- ]);
277
- }}
278
- {...onEnterHelper(handleFilterSubmit)}
279
- value={filterValue && filterValue[0]}
280
- />
281
- <NumericInput
282
- placeholder="High"
283
- onValueChange={function (numVal) {
284
- handleFilterValueChange([
285
- filterValue[0],
286
- isNaN(numVal) ? 0 : numVal
287
- ]);
288
- }}
289
- {...onEnterHelper(handleFilterSubmit)}
290
- value={filterValue && filterValue[1]}
291
- />
292
- </div>
293
- );
294
- break;
295
- case "date":
296
- inputGroup = (
297
- <div className="custom-menu-item">
298
- <DateInput
299
- value={filterValue ? dayjs(filterValue).toDate() : undefined}
300
- {...getDayjsFormatter("L")}
301
- {...dateMinMaxHelpers}
302
- onChange={selectedDates => {
303
- handleFilterValueChange(selectedDates);
304
- }}
305
- />
306
- </div>
307
- );
308
- break;
309
- case "dateRange":
310
- // eslint-disable-next-line no-case-declarations
311
- let filterValueToUse;
312
- if (Array.isArray(filterValue)) {
313
- filterValueToUse = filterValue;
314
- } else {
315
- filterValueToUse =
316
- filterValue && filterValue.split && filterValue.split(";");
317
- }
318
- inputGroup = (
319
- <div className="custom-menu-item">
320
- <DateRangeInput
321
- value={
322
- filterValueToUse && filterValueToUse[0] && filterValueToUse[1]
323
- ? [new Date(filterValueToUse[0]), new Date(filterValueToUse[1])]
324
- : undefined
325
- }
326
- popoverProps={{
327
- captureDismiss: true
328
- }}
329
- formatDate={date => (date == null ? "" : date.toLocaleDateString())}
330
- parseDate={str => new Date(Date.parse(str))}
331
- placeholder="JS Date"
332
- {...dateMinMaxHelpers}
333
- onChange={selectedDates => {
334
- if (selectedDates[0] && selectedDates[1]) {
335
- handleFilterValueChange(selectedDates);
336
- }
337
- }}
338
- />
339
- </div>
340
- );
341
- break;
342
- default:
343
- // to do
344
- }
345
- return inputGroup;
346
- };
347
-
348
- function getFilterMenuItems(dataType) {
349
- let filterMenuItems = [];
350
- if (dataType === "string") {
351
- filterMenuItems = [
352
- "contains",
353
- "notContains",
354
- "startsWith",
355
- "endsWith",
356
- "isExactly",
357
- "regex",
358
- "inList",
359
- "notInList",
360
- "isEmpty",
361
- "notEmpty"
362
- ];
363
- } else if (dataType === "lookup") {
364
- filterMenuItems = [
365
- "contains",
366
- "notContains",
367
- "startsWith",
368
- "endsWith",
369
- "isExactly",
370
- "regex"
371
- ];
372
- } else if (dataType === "boolean") {
373
- filterMenuItems = ["true", "false"];
374
- } else if (dataType === "number" || dataType === "integer") {
375
- filterMenuItems = [
376
- "greaterThan",
377
- "lessThan",
378
- "inRange",
379
- "outsideRange",
380
- "equalTo",
381
- "inList",
382
- "notInList"
383
- ];
384
- } else if (dataType === "timestamp") {
385
- filterMenuItems = ["isBetween", "notBetween", "isBefore", "isAfter"];
386
- }
387
- return filterMenuItems.map(item => startCase(item));
388
- }