@teselagen/ui 0.7.33-beta.3 → 0.7.33-beta.5
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/DataTable/utils/queryParams.d.ts +3 -8
- package/DataTable/utils/tableQueryParamsToHasuraClauses.d.ts +12 -0
- package/index.cjs.js +161 -27
- package/index.es.js +161 -27
- package/package.json +1 -1
- package/src/AdvancedOptions.spec.js +26 -0
- package/src/AsyncValidateFieldSpinner/index.js +12 -0
- package/src/BlueprintError/index.js +14 -0
- package/src/BounceLoader/index.js +16 -0
- package/src/BounceLoader/style.css +45 -0
- package/src/CollapsibleCard/index.js +68 -0
- package/src/CollapsibleCard/style.css +23 -0
- package/src/DNALoader/index.js +20 -0
- package/src/DNALoader/style.css +251 -0
- package/src/{Columns.js → DataTable/Columns.js} +1 -1
- package/src/{DisplayOptions.js → DataTable/DisplayOptions.js} +1 -1
- package/src/DataTable/index.js +3209 -0
- package/src/DataTable/style.css +608 -0
- package/src/{filterLocalEntitiesToHasura.js → DataTable/utils/filterLocalEntitiesToHasura.js} +6 -0
- package/src/DataTable/utils/filterLocalEntitiesToHasura.test.js +538 -0
- package/src/DataTable/utils/index.js +55 -0
- package/src/{initializeHasuraWhereAndFilter.js → DataTable/utils/initializeHasuraWhereAndFilter.js} +0 -1
- package/src/{queryParams.js → DataTable/utils/queryParams.js} +32 -21
- package/src/DataTable/utils/tableQueryParamsToHasuraClauses.js +250 -0
- package/src/DataTable/utils/tableQueryParamsToHasuraClauses.test.js +206 -0
- package/src/{withTableParams.js → DataTable/utils/withTableParams.js} +2 -2
- package/src/DialogFooter/index.js +86 -0
- package/src/DialogFooter/style.css +9 -0
- package/src/FormComponents/index.js +1266 -0
- package/src/FormComponents/style.css +275 -0
- package/src/FormComponents/utils.js +6 -0
- package/src/HotkeysDialog/index.js +79 -0
- package/src/HotkeysDialog/style.css +54 -0
- package/src/InfoHelper/index.js +78 -0
- package/src/InfoHelper/style.css +7 -0
- package/src/IntentText/index.js +18 -0
- package/src/Loading/index.js +70 -0
- package/src/Loading/style.css +4 -0
- package/src/MenuBar/index.js +423 -0
- package/src/MenuBar/style.css +45 -0
- package/src/PromptUnsavedChanges/index.js +38 -0
- package/src/ResizableDraggableDialog/index.js +141 -0
- package/src/ResizableDraggableDialog/style.css +42 -0
- package/src/ScrollToTop/index.js +72 -0
- package/src/TagSelect/index.js +69 -0
- package/src/TagSelect/style.css +13 -0
- package/src/TgHtmlSelect/index.js +20 -0
- package/src/TgSelect/index.js +537 -0
- package/src/TgSelect/style.css +61 -0
- package/src/TgSuggest/index.js +124 -0
- package/src/Timeline/index.js +15 -0
- package/src/Timeline/style.css +29 -0
- package/src/enhancers/withDialog/index.js +196 -0
- package/src/index.js +88 -1
- package/src/showConfirmationDialog/index.js +148 -0
- package/src/style.css +261 -9
- package/src/utils/hooks/index.js +1 -0
- package/DataTable/utils/simplifyHasuraWhere.d.ts +0 -1
- package/src/simplifyHasuraWhere.js +0 -80
- package/src/tableQueryParamsToHasuraClauses.js +0 -113
- /package/src/{CellDragHandle.js → DataTable/CellDragHandle.js} +0 -0
- /package/src/{ColumnFilterMenu.js → DataTable/ColumnFilterMenu.js} +0 -0
- /package/src/{DisabledLoadingComponent.js → DataTable/DisabledLoadingComponent.js} +0 -0
- /package/src/{DropdownCell.js → DataTable/DropdownCell.js} +0 -0
- /package/src/{EditableCell.js → DataTable/EditableCell.js} +0 -0
- /package/src/{FilterAndSortMenu.js → DataTable/FilterAndSortMenu.js} +0 -0
- /package/src/{PagingTool.js → DataTable/PagingTool.js} +0 -0
- /package/src/{RenderCell.js → DataTable/RenderCell.js} +0 -0
- /package/src/{SearchBar.js → DataTable/SearchBar.js} +0 -0
- /package/src/{SortableColumns.js → DataTable/SortableColumns.js} +0 -0
- /package/src/{TableFormTrackerContext.js → DataTable/TableFormTrackerContext.js} +0 -0
- /package/src/{ThComponent.js → DataTable/ThComponent.js} +0 -0
- /package/src/{dataTableEnhancer.js → DataTable/dataTableEnhancer.js} +0 -0
- /package/src/{defaultFormatters.js → DataTable/defaultFormatters.js} +0 -0
- /package/src/{defaultValidators.js → DataTable/defaultValidators.js} +0 -0
- /package/src/{editCellHelper.js → DataTable/editCellHelper.js} +0 -0
- /package/src/{getCellVal.js → DataTable/getCellVal.js} +0 -0
- /package/src/{getVals.js → DataTable/getVals.js} +0 -0
- /package/src/{isTruthy.js → DataTable/isTruthy.js} +0 -0
- /package/src/{isValueEmpty.js → DataTable/isValueEmpty.js} +0 -0
- /package/src/{convertSchema.js → DataTable/utils/convertSchema.js} +0 -0
- /package/src/{formatPasteData.js → DataTable/utils/formatPasteData.js} +0 -0
- /package/src/{getAllRows.js → DataTable/utils/getAllRows.js} +0 -0
- /package/src/{getCellCopyText.js → DataTable/utils/getCellCopyText.js} +0 -0
- /package/src/{getCellInfo.js → DataTable/utils/getCellInfo.js} +0 -0
- /package/src/{getFieldPathToField.js → DataTable/utils/getFieldPathToField.js} +0 -0
- /package/src/{getIdOrCodeOrIndex.js → DataTable/utils/getIdOrCodeOrIndex.js} +0 -0
- /package/src/{getLastSelectedEntity.js → DataTable/utils/getLastSelectedEntity.js} +0 -0
- /package/src/{getNewEntToSelect.js → DataTable/utils/getNewEntToSelect.js} +0 -0
- /package/src/{getRowCopyText.js → DataTable/utils/getRowCopyText.js} +0 -0
- /package/src/{getTableConfigFromStorage.js → DataTable/utils/getTableConfigFromStorage.js} +0 -0
- /package/src/{handleCopyColumn.js → DataTable/utils/handleCopyColumn.js} +0 -0
- /package/src/{handleCopyHelper.js → DataTable/utils/handleCopyHelper.js} +0 -0
- /package/src/{handleCopyRows.js → DataTable/utils/handleCopyRows.js} +0 -0
- /package/src/{handleCopyTable.js → DataTable/utils/handleCopyTable.js} +0 -0
- /package/src/{isBottomRightCornerOfRectangle.js → DataTable/utils/isBottomRightCornerOfRectangle.js} +0 -0
- /package/src/{isEntityClean.js → DataTable/utils/isEntityClean.js} +0 -0
- /package/src/{primarySelectedValue.js → DataTable/utils/primarySelectedValue.js} +0 -0
- /package/src/{removeCleanRows.js → DataTable/utils/removeCleanRows.js} +0 -0
- /package/src/{rowClick.js → DataTable/utils/rowClick.js} +0 -0
- /package/src/{selection.js → DataTable/utils/selection.js} +0 -0
- /package/src/{useTableEntities.js → DataTable/utils/useTableEntities.js} +0 -0
- /package/src/{utils.js → DataTable/utils/utils.js} +0 -0
- /package/src/{withSelectedEntities.js → DataTable/utils/withSelectedEntities.js} +0 -0
- /package/src/{validateTableWideErrors.js → DataTable/validateTableWideErrors.js} +0 -0
- /package/src/{viewColumn.js → DataTable/viewColumn.js} +0 -0
- /package/src/{FormSeparator.js → FormComponents/FormSeparator.js} +0 -0
- /package/src/{LoadingDots.js → FormComponents/LoadingDots.js} +0 -0
- /package/src/{Uploader.js → FormComponents/Uploader.js} +0 -0
- /package/src/{getNewName.js → FormComponents/getNewName.js} +0 -0
- /package/src/{itemUpload.js → FormComponents/itemUpload.js} +0 -0
- /package/src/{sortify.js → FormComponents/sortify.js} +0 -0
- /package/src/{tryToMatchSchemas.js → FormComponents/tryToMatchSchemas.js} +0 -0
- /package/src/{TimelineEvent.js → Timeline/TimelineEvent.js} +0 -0
- /package/src/{tg_modalState.js → enhancers/withDialog/tg_modalState.js} +0 -0
- /package/src/{withField.js → enhancers/withField.js} +0 -0
- /package/src/{withFields.js → enhancers/withFields.js} +0 -0
- /package/src/{withLocalStorage.js → enhancers/withLocalStorage.js} +0 -0
- /package/src/{adHoc.js → utils/adHoc.js} +0 -0
- /package/src/{basicHandleActionsWithFullState.js → utils/basicHandleActionsWithFullState.js} +0 -0
- /package/src/{browserUtils.js → utils/browserUtils.js} +0 -0
- /package/src/{combineReducersWithFullState.js → utils/combineReducersWithFullState.js} +0 -0
- /package/src/{commandControls.js → utils/commandControls.js} +0 -0
- /package/src/{commandUtils.js → utils/commandUtils.js} +0 -0
- /package/src/{determineBlackOrWhiteTextColor.js → utils/determineBlackOrWhiteTextColor.js} +0 -0
- /package/src/{getDayjsFormatter.js → utils/getDayjsFormatter.js} +0 -0
- /package/src/{getTextFromEl.js → utils/getTextFromEl.js} +0 -0
- /package/src/{handlerHelpers.js → utils/handlerHelpers.js} +0 -0
- /package/src/{useDeepEqualMemo.js → utils/hooks/useDeepEqualMemo.js} +0 -0
- /package/src/{useStableReference.js → utils/hooks/useStableReference.js} +0 -0
- /package/src/{hotkeyUtils.js → utils/hotkeyUtils.js} +0 -0
- /package/src/{isBeingCalledExcessively.js → utils/isBeingCalledExcessively.js} +0 -0
- /package/src/{menuUtils.js → utils/menuUtils.js} +0 -0
- /package/src/{popoverOverflowModifiers.js → utils/popoverOverflowModifiers.js} +0 -0
- /package/src/{pureNoFunc.js → utils/pureNoFunc.js} +0 -0
- /package/src/{renderOnDoc.js → utils/renderOnDoc.js} +0 -0
- /package/src/{showProgressToast.js → utils/showProgressToast.js} +0 -0
- /package/src/{tagUtils.js → utils/tagUtils.js} +0 -0
- /package/src/{tgFormValues.js → utils/tgFormValues.js} +0 -0
- /package/src/{useTraceUpdate.js → utils/useTraceUpdate.js} +0 -0
- /package/src/{withSelectTableRecords.js → utils/withSelectTableRecords.js} +0 -0
- /package/src/{withStore.js → utils/withStore.js} +0 -0
|
@@ -0,0 +1,1266 @@
|
|
|
1
|
+
import classNames from "classnames";
|
|
2
|
+
import { SketchPicker } from "react-color";
|
|
3
|
+
import { isNumber, noop, kebabCase, isPlainObject, isEqual } from "lodash-es";
|
|
4
|
+
import mathExpressionEvaluator from "math-expression-evaluator";
|
|
5
|
+
import React, {
|
|
6
|
+
useCallback,
|
|
7
|
+
useContext,
|
|
8
|
+
useEffect,
|
|
9
|
+
useMemo,
|
|
10
|
+
useState
|
|
11
|
+
} from "react";
|
|
12
|
+
import { Field, change } from "redux-form";
|
|
13
|
+
import "./style.css";
|
|
14
|
+
import {
|
|
15
|
+
InputGroup,
|
|
16
|
+
NumericInput,
|
|
17
|
+
Intent,
|
|
18
|
+
RadioGroup,
|
|
19
|
+
Checkbox,
|
|
20
|
+
EditableText,
|
|
21
|
+
Tooltip,
|
|
22
|
+
Position,
|
|
23
|
+
Switch,
|
|
24
|
+
Classes,
|
|
25
|
+
FormGroup,
|
|
26
|
+
Button,
|
|
27
|
+
TextArea,
|
|
28
|
+
Popover
|
|
29
|
+
} from "@blueprintjs/core";
|
|
30
|
+
import { DateInput, DateRangeInput } from "@blueprintjs/datetime";
|
|
31
|
+
import useDeepCompareEffect from "use-deep-compare-effect";
|
|
32
|
+
import { difference } from "lodash-es";
|
|
33
|
+
import { set } from "lodash-es";
|
|
34
|
+
import TgSelect from "../TgSelect";
|
|
35
|
+
import TgSuggest from "../TgSuggest";
|
|
36
|
+
import InfoHelper from "../InfoHelper";
|
|
37
|
+
import getDayjsFormatter from "../utils/getDayjsFormatter";
|
|
38
|
+
import AsyncValidateFieldSpinner from "../AsyncValidateFieldSpinner";
|
|
39
|
+
import {
|
|
40
|
+
AssignDefaultsModeContext,
|
|
41
|
+
WorkflowDefaultParamsContext,
|
|
42
|
+
workflowDefaultParamsObj
|
|
43
|
+
} from "../AssignDefaultsModeContext";
|
|
44
|
+
import popoverOverflowModifiers from "../utils/popoverOverflowModifiers";
|
|
45
|
+
import Uploader from "./Uploader";
|
|
46
|
+
import sortify from "./sortify";
|
|
47
|
+
import { fieldRequired } from "./utils";
|
|
48
|
+
import { useDispatch } from "react-redux";
|
|
49
|
+
import { useStableReference } from "../utils/hooks/useStableReference";
|
|
50
|
+
|
|
51
|
+
export { fieldRequired };
|
|
52
|
+
|
|
53
|
+
function getIntent({
|
|
54
|
+
showErrorIfUntouched,
|
|
55
|
+
meta: { touched, error, warning }
|
|
56
|
+
}) {
|
|
57
|
+
const hasError = (touched || showErrorIfUntouched) && error;
|
|
58
|
+
const hasWarning = (touched || showErrorIfUntouched) && warning;
|
|
59
|
+
if (hasError) {
|
|
60
|
+
return Intent.DANGER;
|
|
61
|
+
} else if (hasWarning) {
|
|
62
|
+
return Intent.WARNING;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function getIntentClass({
|
|
67
|
+
showErrorIfUntouched,
|
|
68
|
+
meta: { touched, error, warning }
|
|
69
|
+
}) {
|
|
70
|
+
const intent = getIntent({
|
|
71
|
+
showErrorIfUntouched,
|
|
72
|
+
meta: { touched, error, warning }
|
|
73
|
+
});
|
|
74
|
+
if (intent === Intent.DANGER) {
|
|
75
|
+
return Classes.INTENT_DANGER;
|
|
76
|
+
} else if (intent === Intent.WARNING) {
|
|
77
|
+
return Classes.INTENT_WARNING;
|
|
78
|
+
} else {
|
|
79
|
+
return "";
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function removeUnwantedProps(props) {
|
|
84
|
+
const cleanedProps = { ...props };
|
|
85
|
+
delete cleanedProps.className;
|
|
86
|
+
delete cleanedProps.units;
|
|
87
|
+
delete cleanedProps.inlineLabel;
|
|
88
|
+
delete cleanedProps.isLabelTooltip;
|
|
89
|
+
delete cleanedProps.showErrorIfUntouched;
|
|
90
|
+
delete cleanedProps.onChange;
|
|
91
|
+
delete cleanedProps.containerStyle;
|
|
92
|
+
delete cleanedProps.onFieldSubmit;
|
|
93
|
+
delete cleanedProps.onBlur;
|
|
94
|
+
delete cleanedProps.intent;
|
|
95
|
+
delete cleanedProps.intentClass;
|
|
96
|
+
delete cleanedProps.meta;
|
|
97
|
+
delete cleanedProps.defaultValue;
|
|
98
|
+
delete cleanedProps.enableReinitialize;
|
|
99
|
+
delete cleanedProps.tabIndex;
|
|
100
|
+
delete cleanedProps.secondaryLabel;
|
|
101
|
+
delete cleanedProps.tooltipError;
|
|
102
|
+
delete cleanedProps.tooltipInfo;
|
|
103
|
+
delete cleanedProps.tooltipProps;
|
|
104
|
+
// delete cleanedProps.asyncValidate;
|
|
105
|
+
// delete cleanedProps.asyncValidating;
|
|
106
|
+
// delete cleanedProps.validateOnChange;
|
|
107
|
+
delete cleanedProps.hasCustomError;
|
|
108
|
+
if (cleanedProps.inputClassName) {
|
|
109
|
+
cleanedProps.className = cleanedProps.inputClassName;
|
|
110
|
+
delete cleanedProps.inputClassName;
|
|
111
|
+
}
|
|
112
|
+
return cleanedProps;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const LabelWithTooltipInfo = ({ label, tooltipInfo, labelStyle }) =>
|
|
116
|
+
tooltipInfo ? (
|
|
117
|
+
<div style={{ display: "flex", alignItems: "center", ...labelStyle }}>
|
|
118
|
+
{label}{" "}
|
|
119
|
+
<InfoHelper
|
|
120
|
+
style={{ marginLeft: "5px", marginTop: "-6px" }}
|
|
121
|
+
size={12}
|
|
122
|
+
content={tooltipInfo}
|
|
123
|
+
/>
|
|
124
|
+
</div>
|
|
125
|
+
) : (
|
|
126
|
+
label || null
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
const AbstractInput = ({
|
|
130
|
+
assignDefaultButton,
|
|
131
|
+
asyncValidating,
|
|
132
|
+
className,
|
|
133
|
+
children,
|
|
134
|
+
containerStyle,
|
|
135
|
+
defaultValue,
|
|
136
|
+
disabled,
|
|
137
|
+
fileLimit,
|
|
138
|
+
inlineLabel,
|
|
139
|
+
input: { name },
|
|
140
|
+
intent,
|
|
141
|
+
isLabelTooltip,
|
|
142
|
+
isLoadingDefaultValue,
|
|
143
|
+
isRequired,
|
|
144
|
+
label,
|
|
145
|
+
labelStyle,
|
|
146
|
+
leftEl,
|
|
147
|
+
meta: { form, touched, error, warning, initial },
|
|
148
|
+
noFillField,
|
|
149
|
+
noMarginBottom,
|
|
150
|
+
noOuterLabel,
|
|
151
|
+
onDefaultValChanged: _onDefaultValChanged,
|
|
152
|
+
onFieldSubmit: _onFieldSubmit,
|
|
153
|
+
rightEl,
|
|
154
|
+
secondaryLabel,
|
|
155
|
+
setAssignDefaultsMode,
|
|
156
|
+
showErrorIfUntouched,
|
|
157
|
+
showGenerateDefaultDot,
|
|
158
|
+
startAssigningDefault,
|
|
159
|
+
tooltipError,
|
|
160
|
+
tooltipInfo,
|
|
161
|
+
tooltipProps
|
|
162
|
+
}) => {
|
|
163
|
+
const dispatch = useDispatch();
|
|
164
|
+
const onDefaultValChanged = useStableReference(_onDefaultValChanged);
|
|
165
|
+
const onFieldSubmit = useStableReference(_onFieldSubmit);
|
|
166
|
+
const doesNotHaveInitialValue = !initial;
|
|
167
|
+
// This only takes care that the default Value is changed when it is changed in the parent component
|
|
168
|
+
useEffect(() => {
|
|
169
|
+
//if the input already has an initial value being passed to it, we don't want to override it with the default value
|
|
170
|
+
if (defaultValue !== undefined && doesNotHaveInitialValue) {
|
|
171
|
+
dispatch(change(form, name, defaultValue));
|
|
172
|
+
onDefaultValChanged.current &&
|
|
173
|
+
onDefaultValChanged.current(defaultValue, name, form);
|
|
174
|
+
onFieldSubmit.current && onFieldSubmit.current(defaultValue);
|
|
175
|
+
}
|
|
176
|
+
}, [
|
|
177
|
+
defaultValue,
|
|
178
|
+
dispatch,
|
|
179
|
+
form,
|
|
180
|
+
name,
|
|
181
|
+
onDefaultValChanged,
|
|
182
|
+
onFieldSubmit,
|
|
183
|
+
doesNotHaveInitialValue
|
|
184
|
+
]);
|
|
185
|
+
|
|
186
|
+
// if our custom field level validation is happening then we don't want to show the error visually
|
|
187
|
+
const showError =
|
|
188
|
+
(touched || showErrorIfUntouched) && error && !asyncValidating;
|
|
189
|
+
const showWarning = (touched || showErrorIfUntouched) && warning;
|
|
190
|
+
let componentToWrap =
|
|
191
|
+
isLabelTooltip || tooltipError ? (
|
|
192
|
+
<Tooltip
|
|
193
|
+
disabled={isLabelTooltip ? false : !showError}
|
|
194
|
+
intent={isLabelTooltip ? "none" : error ? "danger" : "warning"}
|
|
195
|
+
content={isLabelTooltip ? label : error || warning}
|
|
196
|
+
position={Position.TOP}
|
|
197
|
+
modifiers={popoverOverflowModifiers}
|
|
198
|
+
{...tooltipProps}
|
|
199
|
+
>
|
|
200
|
+
{children}
|
|
201
|
+
</Tooltip>
|
|
202
|
+
) : (
|
|
203
|
+
children
|
|
204
|
+
);
|
|
205
|
+
const testClassName = "tg-test-" + kebabCase(name);
|
|
206
|
+
if (noFillField) {
|
|
207
|
+
componentToWrap = <div className="tg-no-fill-field">{componentToWrap}</div>;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
let helperText;
|
|
211
|
+
if (!tooltipError) {
|
|
212
|
+
if (showError) {
|
|
213
|
+
helperText = error;
|
|
214
|
+
} else if (showWarning) {
|
|
215
|
+
helperText = warning;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// if in a cypress test show message so that inputs will not be interactable
|
|
220
|
+
if (window.Cypress && isLoadingDefaultValue) {
|
|
221
|
+
return "Loading default value...";
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
let labelInfo = secondaryLabel;
|
|
225
|
+
|
|
226
|
+
const hasOuterLabel = !noOuterLabel && !isLabelTooltip;
|
|
227
|
+
function getFileLimitInfo() {
|
|
228
|
+
if (!fileLimit) return "";
|
|
229
|
+
return `max ${fileLimit} file${fileLimit === 1 ? "" : "s"}`;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (isRequired && hasOuterLabel && label && !labelInfo) {
|
|
233
|
+
labelInfo = `(required${fileLimit ? `, ${getFileLimitInfo()}` : ""})`;
|
|
234
|
+
} else if (!labelInfo && fileLimit) {
|
|
235
|
+
labelInfo = `(${getFileLimitInfo()})`;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return (
|
|
239
|
+
<FormGroup
|
|
240
|
+
className={classNames(className, testClassName, {
|
|
241
|
+
"tg-flex-form-content": leftEl || rightEl,
|
|
242
|
+
"tg-tooltipError": tooltipError,
|
|
243
|
+
"tg-has-error": showError && error
|
|
244
|
+
})}
|
|
245
|
+
disabled={disabled}
|
|
246
|
+
helperText={helperText}
|
|
247
|
+
intent={intent}
|
|
248
|
+
label={
|
|
249
|
+
hasOuterLabel && (
|
|
250
|
+
<LabelWithTooltipInfo
|
|
251
|
+
labelStyle={labelStyle}
|
|
252
|
+
label={label}
|
|
253
|
+
tooltipInfo={tooltipInfo}
|
|
254
|
+
/>
|
|
255
|
+
)
|
|
256
|
+
}
|
|
257
|
+
inline={inlineLabel}
|
|
258
|
+
labelInfo={labelInfo}
|
|
259
|
+
style={{
|
|
260
|
+
...(noMarginBottom && { marginBottom: 0 }),
|
|
261
|
+
...containerStyle
|
|
262
|
+
}}
|
|
263
|
+
>
|
|
264
|
+
{showGenerateDefaultDot && (
|
|
265
|
+
<div style={{ zIndex: 10, position: "relative", height: 0, width: 0 }}>
|
|
266
|
+
<div style={{ position: "absolute", left: "0px", top: "0px" }}>
|
|
267
|
+
<Tooltip
|
|
268
|
+
modifiers={popoverOverflowModifiers}
|
|
269
|
+
content="Allows a Default to be Set. Click to Enter Set Default Mode (or press Shift+D when outside the input field)"
|
|
270
|
+
>
|
|
271
|
+
<div
|
|
272
|
+
onClick={() => {
|
|
273
|
+
setAssignDefaultsMode(true);
|
|
274
|
+
startAssigningDefault();
|
|
275
|
+
}}
|
|
276
|
+
className="generateDefaultDot"
|
|
277
|
+
/>
|
|
278
|
+
</Tooltip>
|
|
279
|
+
</div>
|
|
280
|
+
</div>
|
|
281
|
+
)}
|
|
282
|
+
{assignDefaultButton}
|
|
283
|
+
{leftEl} {componentToWrap} {rightEl}
|
|
284
|
+
</FormGroup>
|
|
285
|
+
);
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
export const renderBlueprintDateInput = ({
|
|
289
|
+
input,
|
|
290
|
+
intent,
|
|
291
|
+
onFieldSubmit,
|
|
292
|
+
inputProps,
|
|
293
|
+
...rest
|
|
294
|
+
}) => (
|
|
295
|
+
<DateInput
|
|
296
|
+
{...getDayjsFormatter("L")}
|
|
297
|
+
{...removeUnwantedProps(rest)}
|
|
298
|
+
intent={intent}
|
|
299
|
+
inputProps={inputProps}
|
|
300
|
+
{...input}
|
|
301
|
+
value={input.value ? new Date(input.value) : undefined}
|
|
302
|
+
onChange={function (selectedDate) {
|
|
303
|
+
input.onChange(selectedDate);
|
|
304
|
+
onFieldSubmit(selectedDate);
|
|
305
|
+
}}
|
|
306
|
+
/>
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
export const renderBlueprintDateRangeInput = ({
|
|
310
|
+
input,
|
|
311
|
+
intent,
|
|
312
|
+
onFieldSubmit,
|
|
313
|
+
inputProps,
|
|
314
|
+
...rest
|
|
315
|
+
}) => (
|
|
316
|
+
<DateRangeInput
|
|
317
|
+
{...getDayjsFormatter("L")}
|
|
318
|
+
{...removeUnwantedProps(rest)}
|
|
319
|
+
intent={intent}
|
|
320
|
+
inputProps={inputProps}
|
|
321
|
+
{...input}
|
|
322
|
+
value={
|
|
323
|
+
input.value
|
|
324
|
+
? [new Date(input.value[0]), new Date(input.value[1])]
|
|
325
|
+
: undefined
|
|
326
|
+
}
|
|
327
|
+
onChange={function (selectedDate) {
|
|
328
|
+
input.onChange(selectedDate);
|
|
329
|
+
onFieldSubmit(selectedDate);
|
|
330
|
+
}}
|
|
331
|
+
/>
|
|
332
|
+
);
|
|
333
|
+
|
|
334
|
+
export const RenderBlueprintInput = ({
|
|
335
|
+
input,
|
|
336
|
+
// meta = {},
|
|
337
|
+
intent,
|
|
338
|
+
onFieldSubmit,
|
|
339
|
+
onKeyDown = noop,
|
|
340
|
+
asyncValidating,
|
|
341
|
+
rightElement,
|
|
342
|
+
clickToEdit,
|
|
343
|
+
...rest
|
|
344
|
+
}) => {
|
|
345
|
+
const [isOpen, setOpen] = useState(false);
|
|
346
|
+
const [value, setVal] = useState(null);
|
|
347
|
+
const toSpread = {};
|
|
348
|
+
if (clickToEdit) {
|
|
349
|
+
const isDisabled = clickToEdit && !isOpen;
|
|
350
|
+
toSpread.disabled = rest.disabled || isDisabled;
|
|
351
|
+
}
|
|
352
|
+
const stopEdit = () => {
|
|
353
|
+
setOpen(false);
|
|
354
|
+
setVal(null);
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
const inner =
|
|
358
|
+
clickToEdit && !isOpen ? (
|
|
359
|
+
<div>{input.value}</div>
|
|
360
|
+
) : (
|
|
361
|
+
<InputGroup
|
|
362
|
+
rightElement={
|
|
363
|
+
asyncValidating ? (
|
|
364
|
+
<AsyncValidateFieldSpinner validating />
|
|
365
|
+
) : (
|
|
366
|
+
rightElement
|
|
367
|
+
)
|
|
368
|
+
}
|
|
369
|
+
{...removeUnwantedProps(rest)}
|
|
370
|
+
intent={intent}
|
|
371
|
+
{...input}
|
|
372
|
+
{...toSpread}
|
|
373
|
+
{...(clickToEdit
|
|
374
|
+
? {
|
|
375
|
+
disabled: rest.disabled,
|
|
376
|
+
onChange: e => {
|
|
377
|
+
setVal(e.target.value);
|
|
378
|
+
},
|
|
379
|
+
...(value === null ? {} : { value }),
|
|
380
|
+
onKeyDown: (...args) => {
|
|
381
|
+
onKeyDown(...args);
|
|
382
|
+
const e = args[0];
|
|
383
|
+
if (e.key === "Enter") {
|
|
384
|
+
input.onChange(value === null ? input.value : value);
|
|
385
|
+
onFieldSubmit(e.target.value, { enter: true }, e);
|
|
386
|
+
stopEdit();
|
|
387
|
+
}
|
|
388
|
+
return true;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
: {
|
|
392
|
+
onKeyDown: function (...args) {
|
|
393
|
+
onKeyDown(...args);
|
|
394
|
+
const e = args[0];
|
|
395
|
+
if (e.key === "Enter") {
|
|
396
|
+
onFieldSubmit(e.target.value, { enter: true }, e);
|
|
397
|
+
}
|
|
398
|
+
},
|
|
399
|
+
onBlur: function (e, val) {
|
|
400
|
+
if (rest.readOnly) return;
|
|
401
|
+
input.onBlur(e, val);
|
|
402
|
+
onFieldSubmit(
|
|
403
|
+
e.target ? e.target.value : val,
|
|
404
|
+
{ blur: true },
|
|
405
|
+
e
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
})}
|
|
409
|
+
/>
|
|
410
|
+
);
|
|
411
|
+
if (clickToEdit)
|
|
412
|
+
return (
|
|
413
|
+
<div style={{ display: "flex" }}>
|
|
414
|
+
{inner}
|
|
415
|
+
{clickToEdit &&
|
|
416
|
+
(isOpen ? (
|
|
417
|
+
<>
|
|
418
|
+
<Button icon="small-cross" onClick={stopEdit} intent="danger" />
|
|
419
|
+
<Button
|
|
420
|
+
icon="small-tick"
|
|
421
|
+
onClick={() => {
|
|
422
|
+
input.onChange(value === null ? input.value : value);
|
|
423
|
+
onFieldSubmit(value === null ? input.value : value, {
|
|
424
|
+
cmdEnter: true
|
|
425
|
+
});
|
|
426
|
+
stopEdit();
|
|
427
|
+
}}
|
|
428
|
+
intent="success"
|
|
429
|
+
/>{" "}
|
|
430
|
+
</>
|
|
431
|
+
) : (
|
|
432
|
+
<Button
|
|
433
|
+
minimal
|
|
434
|
+
onClick={() => {
|
|
435
|
+
setOpen(true);
|
|
436
|
+
}}
|
|
437
|
+
icon="edit"
|
|
438
|
+
/>
|
|
439
|
+
))}
|
|
440
|
+
</div>
|
|
441
|
+
);
|
|
442
|
+
return inner;
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
export const renderBlueprintCheckbox = ({
|
|
446
|
+
input,
|
|
447
|
+
label,
|
|
448
|
+
tooltipInfo,
|
|
449
|
+
beforeOnChange,
|
|
450
|
+
onFieldSubmit,
|
|
451
|
+
...rest
|
|
452
|
+
}) => (
|
|
453
|
+
<Checkbox
|
|
454
|
+
{...removeUnwantedProps(rest)}
|
|
455
|
+
{...input}
|
|
456
|
+
checked={input.value}
|
|
457
|
+
label={<LabelWithTooltipInfo label={label} tooltipInfo={tooltipInfo} />}
|
|
458
|
+
onChange={getCheckboxOrSwitchOnChange({
|
|
459
|
+
beforeOnChange,
|
|
460
|
+
input,
|
|
461
|
+
onFieldSubmit
|
|
462
|
+
})}
|
|
463
|
+
/>
|
|
464
|
+
);
|
|
465
|
+
|
|
466
|
+
const getCheckboxOrSwitchOnChange = ({
|
|
467
|
+
beforeOnChange,
|
|
468
|
+
input,
|
|
469
|
+
onFieldSubmit
|
|
470
|
+
}) =>
|
|
471
|
+
async function (e, val) {
|
|
472
|
+
const v = e.target ? e.target.checked : val;
|
|
473
|
+
if (beforeOnChange) {
|
|
474
|
+
const { stopEarly } = (await beforeOnChange(v, e)) || {};
|
|
475
|
+
if (stopEarly) return;
|
|
476
|
+
set(e, "target.checked", v);
|
|
477
|
+
}
|
|
478
|
+
input.onChange(e, val);
|
|
479
|
+
onFieldSubmit(v);
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
export const renderBlueprintSwitch = ({
|
|
483
|
+
input,
|
|
484
|
+
label,
|
|
485
|
+
tooltipInfo,
|
|
486
|
+
onFieldSubmit,
|
|
487
|
+
beforeOnChange,
|
|
488
|
+
...rest
|
|
489
|
+
}) => (
|
|
490
|
+
<Switch
|
|
491
|
+
{...removeUnwantedProps(rest)}
|
|
492
|
+
{...input}
|
|
493
|
+
checked={input.value}
|
|
494
|
+
label={<LabelWithTooltipInfo label={label} tooltipInfo={tooltipInfo} />}
|
|
495
|
+
onChange={getCheckboxOrSwitchOnChange({
|
|
496
|
+
beforeOnChange,
|
|
497
|
+
input,
|
|
498
|
+
onFieldSubmit
|
|
499
|
+
})}
|
|
500
|
+
/>
|
|
501
|
+
);
|
|
502
|
+
|
|
503
|
+
export const renderFileUpload = ({ input, onFieldSubmit, ...rest }) => (
|
|
504
|
+
<Uploader
|
|
505
|
+
fileList={input.value}
|
|
506
|
+
onFieldSubmit={onFieldSubmit}
|
|
507
|
+
{...rest}
|
|
508
|
+
name={input.name}
|
|
509
|
+
onChange={input.onChange}
|
|
510
|
+
/>
|
|
511
|
+
);
|
|
512
|
+
|
|
513
|
+
export const RenderBlueprintTextarea = ({
|
|
514
|
+
input,
|
|
515
|
+
onFieldSubmit,
|
|
516
|
+
onKeyDown,
|
|
517
|
+
intentClass,
|
|
518
|
+
inputClassName,
|
|
519
|
+
clickToEdit,
|
|
520
|
+
disabled,
|
|
521
|
+
...rest
|
|
522
|
+
}) => {
|
|
523
|
+
const [value, setValue] = useState(null);
|
|
524
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
525
|
+
|
|
526
|
+
const stopEdit = () => {
|
|
527
|
+
setIsOpen(false);
|
|
528
|
+
setValue(null);
|
|
529
|
+
};
|
|
530
|
+
|
|
531
|
+
const handleValSubmit = () => {
|
|
532
|
+
input.onChange(value === null ? input.value : value);
|
|
533
|
+
onFieldSubmit(value === null ? input.value : value, {
|
|
534
|
+
cmdEnter: true
|
|
535
|
+
});
|
|
536
|
+
stopEdit();
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
const handleOnKeyDown = (...args) => {
|
|
540
|
+
const e = args[0];
|
|
541
|
+
(onKeyDown || noop)(...args);
|
|
542
|
+
if (e.keyCode === 13 && (e.metaKey || e.ctrlKey)) {
|
|
543
|
+
onFieldSubmit(e.target.value, { cmdEnter: true }, e);
|
|
544
|
+
input.onChange(e);
|
|
545
|
+
stopEdit();
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
|
|
549
|
+
if (clickToEdit) {
|
|
550
|
+
const isDisabled = clickToEdit && !isOpen;
|
|
551
|
+
return (
|
|
552
|
+
<>
|
|
553
|
+
<TextArea
|
|
554
|
+
{...removeUnwantedProps(rest)}
|
|
555
|
+
disabled={rest.disabled || isDisabled}
|
|
556
|
+
className={classNames(
|
|
557
|
+
intentClass,
|
|
558
|
+
inputClassName,
|
|
559
|
+
Classes.INPUT,
|
|
560
|
+
Classes.FILL
|
|
561
|
+
)}
|
|
562
|
+
value={value === null ? input.value : value}
|
|
563
|
+
onChange={e => setValue(e.target.value)}
|
|
564
|
+
onKeyDown={handleOnKeyDown}
|
|
565
|
+
/>
|
|
566
|
+
{clickToEdit &&
|
|
567
|
+
!disabled &&
|
|
568
|
+
(isOpen ? (
|
|
569
|
+
//show okay/cancel buttons
|
|
570
|
+
<div>
|
|
571
|
+
<Button onClick={stopEdit} intent="danger">
|
|
572
|
+
Cancel
|
|
573
|
+
</Button>
|
|
574
|
+
<Button onClick={handleValSubmit} intent="success">
|
|
575
|
+
Ok
|
|
576
|
+
</Button>
|
|
577
|
+
</div>
|
|
578
|
+
) : (
|
|
579
|
+
//show click to edit button
|
|
580
|
+
<Button onClick={() => setIsOpen(true)}>Edit</Button>
|
|
581
|
+
))}
|
|
582
|
+
</>
|
|
583
|
+
);
|
|
584
|
+
} else {
|
|
585
|
+
return (
|
|
586
|
+
<TextArea
|
|
587
|
+
{...removeUnwantedProps(rest)}
|
|
588
|
+
disabled={disabled}
|
|
589
|
+
className={classNames(
|
|
590
|
+
intentClass,
|
|
591
|
+
inputClassName,
|
|
592
|
+
Classes.INPUT,
|
|
593
|
+
Classes.FILL
|
|
594
|
+
)}
|
|
595
|
+
{...input}
|
|
596
|
+
onBlur={function (e, val) {
|
|
597
|
+
if (rest.readOnly) return;
|
|
598
|
+
input.onBlur(e, val);
|
|
599
|
+
onFieldSubmit(e.target ? e.target.value : val, { blur: true }, e);
|
|
600
|
+
}}
|
|
601
|
+
onKeyDown={(...args) => {
|
|
602
|
+
const e = args[0];
|
|
603
|
+
(onKeyDown || noop)(...args);
|
|
604
|
+
if (e.keyCode === 13 && (e.metaKey || e.ctrlKey)) {
|
|
605
|
+
onFieldSubmit(e.target.value, { cmdEnter: true }, e);
|
|
606
|
+
}
|
|
607
|
+
}}
|
|
608
|
+
/>
|
|
609
|
+
);
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
|
|
613
|
+
export const renderBlueprintEditableText = props => {
|
|
614
|
+
const { input, onFieldSubmit, ...rest } = props;
|
|
615
|
+
return (
|
|
616
|
+
<EditableText
|
|
617
|
+
{...removeUnwantedProps(rest)}
|
|
618
|
+
{...input}
|
|
619
|
+
onConfirm={function (value) {
|
|
620
|
+
input.onBlur && input.onBlur(value);
|
|
621
|
+
onFieldSubmit(value, { input, meta: rest.meta });
|
|
622
|
+
}}
|
|
623
|
+
/>
|
|
624
|
+
);
|
|
625
|
+
};
|
|
626
|
+
|
|
627
|
+
export const renderReactSelect = props => {
|
|
628
|
+
// spreading input not working, grab the values needed instead
|
|
629
|
+
const {
|
|
630
|
+
async,
|
|
631
|
+
input: { value, onChange },
|
|
632
|
+
hideValue,
|
|
633
|
+
intent,
|
|
634
|
+
options,
|
|
635
|
+
onFieldSubmit,
|
|
636
|
+
beforeOnChange,
|
|
637
|
+
...rest
|
|
638
|
+
} = props;
|
|
639
|
+
|
|
640
|
+
const optionsPassed = options;
|
|
641
|
+
|
|
642
|
+
const optsToUse = getOptions(optionsPassed);
|
|
643
|
+
let valueToUse;
|
|
644
|
+
|
|
645
|
+
if (!Array.isArray(value) && typeof value === "object") {
|
|
646
|
+
if (value.userCreated) {
|
|
647
|
+
valueToUse = {
|
|
648
|
+
label: value.value,
|
|
649
|
+
value
|
|
650
|
+
};
|
|
651
|
+
} else {
|
|
652
|
+
valueToUse = optsToUse.find(obj => {
|
|
653
|
+
return isEqual(obj.value, value);
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
} else if (Array.isArray(value)) {
|
|
657
|
+
valueToUse = value.map(val => {
|
|
658
|
+
if (val?.userCreated) {
|
|
659
|
+
return {
|
|
660
|
+
label: val.value,
|
|
661
|
+
value: val
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
if (optsToUse) {
|
|
665
|
+
return optsToUse.find(obj => {
|
|
666
|
+
return isEqual(obj.value, val);
|
|
667
|
+
});
|
|
668
|
+
} else {
|
|
669
|
+
return val;
|
|
670
|
+
}
|
|
671
|
+
});
|
|
672
|
+
} else {
|
|
673
|
+
valueToUse = value;
|
|
674
|
+
}
|
|
675
|
+
const propsToUse = {
|
|
676
|
+
...removeUnwantedProps(rest),
|
|
677
|
+
intent,
|
|
678
|
+
options: optsToUse,
|
|
679
|
+
value: valueToUse,
|
|
680
|
+
// closeOnSelect: !rest.multi,
|
|
681
|
+
async onChange(valOrVals, ...rest2) {
|
|
682
|
+
let valToPass;
|
|
683
|
+
if (Array.isArray(valOrVals)) {
|
|
684
|
+
valToPass = valOrVals.map(function (val) {
|
|
685
|
+
if (val?.userCreated) {
|
|
686
|
+
return val;
|
|
687
|
+
}
|
|
688
|
+
return val?.value;
|
|
689
|
+
});
|
|
690
|
+
} else if (valOrVals) {
|
|
691
|
+
if (valOrVals.userCreated) {
|
|
692
|
+
valToPass = valOrVals;
|
|
693
|
+
} else {
|
|
694
|
+
valToPass = valOrVals.value;
|
|
695
|
+
}
|
|
696
|
+
} else {
|
|
697
|
+
valToPass = "";
|
|
698
|
+
}
|
|
699
|
+
if (props.cancelSubmit && props.cancelSubmit(valToPass)) {
|
|
700
|
+
//allow the user to cancel the submit
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
if (beforeOnChange) {
|
|
704
|
+
const { stopEarly } = (await beforeOnChange(valToPass, ...rest2)) || {};
|
|
705
|
+
if (stopEarly) return;
|
|
706
|
+
}
|
|
707
|
+
onChange(valToPass, ...rest2);
|
|
708
|
+
if (!rest.submitOnBlur) onFieldSubmit(valToPass);
|
|
709
|
+
},
|
|
710
|
+
onBlur() {
|
|
711
|
+
const valToPass = Array.isArray(valueToUse)
|
|
712
|
+
? valueToUse
|
|
713
|
+
.filter(val => !!val)
|
|
714
|
+
.map(function (val) {
|
|
715
|
+
return val.value;
|
|
716
|
+
})
|
|
717
|
+
: valueToUse;
|
|
718
|
+
if (props.cancelSubmit && props.cancelSubmit(valToPass)) {
|
|
719
|
+
return; //allow the user to cancel the submit
|
|
720
|
+
}
|
|
721
|
+
if (rest.submitOnBlur) {
|
|
722
|
+
onFieldSubmit(valToPass);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
};
|
|
726
|
+
return <TgSelect {...propsToUse} />;
|
|
727
|
+
};
|
|
728
|
+
|
|
729
|
+
export const renderSuggest_old = props => {
|
|
730
|
+
return renderReactSelect({ ...props, asSuggest: true });
|
|
731
|
+
};
|
|
732
|
+
|
|
733
|
+
export const renderSuggest = ({
|
|
734
|
+
async,
|
|
735
|
+
input: { value, onChange },
|
|
736
|
+
hideValue,
|
|
737
|
+
intent,
|
|
738
|
+
options,
|
|
739
|
+
onFieldSubmit,
|
|
740
|
+
...rest
|
|
741
|
+
}) => {
|
|
742
|
+
const propsToUse = {
|
|
743
|
+
...removeUnwantedProps(rest),
|
|
744
|
+
intent,
|
|
745
|
+
options,
|
|
746
|
+
value,
|
|
747
|
+
onChange(val) {
|
|
748
|
+
onChange(val);
|
|
749
|
+
if (!rest.submitOnBlur) onFieldSubmit(val);
|
|
750
|
+
},
|
|
751
|
+
onBlur() {
|
|
752
|
+
if (rest.submitOnBlur) {
|
|
753
|
+
onFieldSubmit(value);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
};
|
|
757
|
+
return <TgSuggest {...propsToUse} />;
|
|
758
|
+
};
|
|
759
|
+
|
|
760
|
+
export const BPSelect = ({ value, onChange, ...rest }) => {
|
|
761
|
+
return renderSelect({ ...rest, input: { onChange, value } });
|
|
762
|
+
};
|
|
763
|
+
|
|
764
|
+
export const renderSelect = ({
|
|
765
|
+
input: { value, onChange },
|
|
766
|
+
hideValue,
|
|
767
|
+
className,
|
|
768
|
+
placeholder,
|
|
769
|
+
onFieldSubmit,
|
|
770
|
+
options,
|
|
771
|
+
hidePlaceHolder,
|
|
772
|
+
minimal,
|
|
773
|
+
disabled,
|
|
774
|
+
...rest
|
|
775
|
+
}) => {
|
|
776
|
+
return (
|
|
777
|
+
<div
|
|
778
|
+
className={
|
|
779
|
+
`${minimal && Classes.MINIMAL} ` +
|
|
780
|
+
classNames(Classes.SELECT, Classes.FILL, className)
|
|
781
|
+
}
|
|
782
|
+
>
|
|
783
|
+
<select
|
|
784
|
+
{...removeUnwantedProps(rest)}
|
|
785
|
+
className={`${disabled && Classes.DISABLED} `}
|
|
786
|
+
value={
|
|
787
|
+
placeholder && value === ""
|
|
788
|
+
? "__placeholder__"
|
|
789
|
+
: typeof value !== "string"
|
|
790
|
+
? sortify(value) //deterministically sort and stringify the object/number coming in because select fields only support string values
|
|
791
|
+
: value
|
|
792
|
+
}
|
|
793
|
+
disabled={disabled}
|
|
794
|
+
{...(hideValue ? { value: "" } : {})}
|
|
795
|
+
onChange={function (e) {
|
|
796
|
+
let val = e.target.value;
|
|
797
|
+
try {
|
|
798
|
+
const maybeNewValue = JSON.parse(e.target.value); //try to json parse the string coming in
|
|
799
|
+
const hasMatchInOriginalOptions = options.find(
|
|
800
|
+
opt => opt === maybeNewValue || opt.value === maybeNewValue
|
|
801
|
+
);
|
|
802
|
+
if (hasMatchInOriginalOptions || isPlainObject(maybeNewValue)) {
|
|
803
|
+
val = maybeNewValue;
|
|
804
|
+
}
|
|
805
|
+
} catch (e) {
|
|
806
|
+
//empty
|
|
807
|
+
}
|
|
808
|
+
onChange(val);
|
|
809
|
+
onFieldSubmit && onFieldSubmit(val);
|
|
810
|
+
}}
|
|
811
|
+
>
|
|
812
|
+
{placeholder && (
|
|
813
|
+
<option value="__placeholder__" disabled hidden={hidePlaceHolder}>
|
|
814
|
+
{placeholder}
|
|
815
|
+
</option>
|
|
816
|
+
)}
|
|
817
|
+
{options.map(function (opt, index) {
|
|
818
|
+
let label, value;
|
|
819
|
+
if (typeof opt === "string") {
|
|
820
|
+
//support passing opts like: ['asdf','awfw']
|
|
821
|
+
label = opt;
|
|
822
|
+
value = opt;
|
|
823
|
+
} else if (isNumber(opt)) {
|
|
824
|
+
//support passing opts like: [1,2,3,4]
|
|
825
|
+
label = opt.toString();
|
|
826
|
+
value = opt;
|
|
827
|
+
} else if (Array.isArray(opt)) {
|
|
828
|
+
throw new Error(
|
|
829
|
+
"the option coming in should be an object, not an array!"
|
|
830
|
+
);
|
|
831
|
+
} else {
|
|
832
|
+
//support passing opts the normal way [{label: 'opt1', value: 'hey'}]
|
|
833
|
+
label = opt.label;
|
|
834
|
+
value = opt.value;
|
|
835
|
+
}
|
|
836
|
+
return (
|
|
837
|
+
<option
|
|
838
|
+
key={index}
|
|
839
|
+
value={
|
|
840
|
+
typeof value !== "string"
|
|
841
|
+
? sortify(value) //deterministically sort and stringify the object/number coming in because select fields only support string values
|
|
842
|
+
: value
|
|
843
|
+
}
|
|
844
|
+
>
|
|
845
|
+
{label}
|
|
846
|
+
</option>
|
|
847
|
+
);
|
|
848
|
+
})}
|
|
849
|
+
</select>
|
|
850
|
+
</div>
|
|
851
|
+
);
|
|
852
|
+
};
|
|
853
|
+
|
|
854
|
+
export const renderBlueprintNumericInput = ({
|
|
855
|
+
input,
|
|
856
|
+
hideValue,
|
|
857
|
+
intent,
|
|
858
|
+
inputClassName,
|
|
859
|
+
onFieldSubmit,
|
|
860
|
+
onAnyNumberChange,
|
|
861
|
+
...rest
|
|
862
|
+
}) => {
|
|
863
|
+
function handleBlurOrButtonClick(stringVal) {
|
|
864
|
+
if (rest.readOnly) return;
|
|
865
|
+
try {
|
|
866
|
+
const num = mathExpressionEvaluator.eval(stringVal);
|
|
867
|
+
input.onBlur(num);
|
|
868
|
+
onFieldSubmit(num);
|
|
869
|
+
} catch (e) {
|
|
870
|
+
console.error(
|
|
871
|
+
"TRC: Error occurring when setting evaluated numeric input field:",
|
|
872
|
+
e
|
|
873
|
+
);
|
|
874
|
+
input.onBlur("");
|
|
875
|
+
onFieldSubmit("");
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
return (
|
|
879
|
+
<NumericInput
|
|
880
|
+
value={input.value}
|
|
881
|
+
intent={intent}
|
|
882
|
+
{...removeUnwantedProps(rest)}
|
|
883
|
+
{...(hideValue ? { value: "" } : {})}
|
|
884
|
+
className={classNames(Classes.FILL, inputClassName)}
|
|
885
|
+
onValueChange={(numericVal, stringVal) => {
|
|
886
|
+
// needed for redux form to change value
|
|
887
|
+
input.onChange(stringVal);
|
|
888
|
+
//tnr: use this handler if you want to listen to all value changes!
|
|
889
|
+
onAnyNumberChange && onAnyNumberChange(numericVal);
|
|
890
|
+
}}
|
|
891
|
+
onButtonClick={function (numericVal, stringVal) {
|
|
892
|
+
handleBlurOrButtonClick(stringVal);
|
|
893
|
+
}}
|
|
894
|
+
onBlur={function (e) {
|
|
895
|
+
handleBlurOrButtonClick(e.target.value);
|
|
896
|
+
}}
|
|
897
|
+
/>
|
|
898
|
+
);
|
|
899
|
+
};
|
|
900
|
+
|
|
901
|
+
export const renderBlueprintRadioGroup = ({
|
|
902
|
+
input,
|
|
903
|
+
options,
|
|
904
|
+
onFieldSubmit,
|
|
905
|
+
...rest
|
|
906
|
+
}) => {
|
|
907
|
+
const optionsToUse = getOptions(options);
|
|
908
|
+
if (
|
|
909
|
+
options.some(opt => {
|
|
910
|
+
if (opt.value === "true") {
|
|
911
|
+
return true;
|
|
912
|
+
}
|
|
913
|
+
return false;
|
|
914
|
+
})
|
|
915
|
+
) {
|
|
916
|
+
throw new Error(
|
|
917
|
+
'RadioGroup values cannot be strings of "true" or "false", they must be actual booleans'
|
|
918
|
+
);
|
|
919
|
+
}
|
|
920
|
+
return (
|
|
921
|
+
<RadioGroup
|
|
922
|
+
{...input}
|
|
923
|
+
{...removeUnwantedProps(rest)}
|
|
924
|
+
selectedValue={input.value}
|
|
925
|
+
label={undefined} //removing label from radio group because our label already handles it
|
|
926
|
+
onChange={function (e) {
|
|
927
|
+
let val = e.target.value;
|
|
928
|
+
if (val === "true") {
|
|
929
|
+
val = true;
|
|
930
|
+
}
|
|
931
|
+
if (val === "false") {
|
|
932
|
+
val = false;
|
|
933
|
+
}
|
|
934
|
+
if (val === "") {
|
|
935
|
+
val = false;
|
|
936
|
+
}
|
|
937
|
+
input.onChange(val);
|
|
938
|
+
onFieldSubmit(val);
|
|
939
|
+
}}
|
|
940
|
+
options={optionsToUse}
|
|
941
|
+
/>
|
|
942
|
+
);
|
|
943
|
+
};
|
|
944
|
+
|
|
945
|
+
export const RenderReactColorPicker = ({ input, onFieldSubmit, ...rest }) => (
|
|
946
|
+
<Popover
|
|
947
|
+
position="bottom-right"
|
|
948
|
+
minimal
|
|
949
|
+
modifiers={popoverOverflowModifiers}
|
|
950
|
+
content={
|
|
951
|
+
<SketchPicker
|
|
952
|
+
className="tg-color-picker-selector"
|
|
953
|
+
color={input.value}
|
|
954
|
+
onChangeComplete={color => {
|
|
955
|
+
input.onChange(color.hex);
|
|
956
|
+
onFieldSubmit(color.hex);
|
|
957
|
+
}}
|
|
958
|
+
{...removeUnwantedProps(rest)}
|
|
959
|
+
/>
|
|
960
|
+
}
|
|
961
|
+
>
|
|
962
|
+
<div
|
|
963
|
+
style={{
|
|
964
|
+
padding: "7px",
|
|
965
|
+
margin: "1px",
|
|
966
|
+
background: "#fff",
|
|
967
|
+
borderRadius: "1px",
|
|
968
|
+
boxShadow: "0 0 0 1px rgba(0,0,0,.1)",
|
|
969
|
+
display: "inline-block",
|
|
970
|
+
cursor: "pointer"
|
|
971
|
+
}}
|
|
972
|
+
>
|
|
973
|
+
<div
|
|
974
|
+
className="tg-color-picker-selected-color"
|
|
975
|
+
style={{
|
|
976
|
+
width: "36px",
|
|
977
|
+
height: "14px",
|
|
978
|
+
borderRadius: "2px",
|
|
979
|
+
background: `${input.value}`
|
|
980
|
+
}}
|
|
981
|
+
/>
|
|
982
|
+
</div>
|
|
983
|
+
</Popover>
|
|
984
|
+
);
|
|
985
|
+
|
|
986
|
+
export function generateField(component, opts) {
|
|
987
|
+
const compWithDefaultVal = withAbstractWrapper(component, opts);
|
|
988
|
+
return ({ name, isRequired, onFieldSubmit = noop, ...rest }) => {
|
|
989
|
+
const props = {
|
|
990
|
+
onFieldSubmit,
|
|
991
|
+
name,
|
|
992
|
+
component: compWithDefaultVal,
|
|
993
|
+
...(isRequired && { validate: fieldRequired }),
|
|
994
|
+
isRequired,
|
|
995
|
+
...rest
|
|
996
|
+
};
|
|
997
|
+
|
|
998
|
+
return <Field {...props} />;
|
|
999
|
+
};
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
export const withAbstractWrapper = (ComponentToWrap, opts = {}) => {
|
|
1003
|
+
return props => {
|
|
1004
|
+
const {
|
|
1005
|
+
massageDefaultIdValue,
|
|
1006
|
+
generateDefaultValue,
|
|
1007
|
+
defaultValueByIdOverride,
|
|
1008
|
+
defaultValue: defaultValueFromProps,
|
|
1009
|
+
isRequired,
|
|
1010
|
+
...rest
|
|
1011
|
+
} = props;
|
|
1012
|
+
|
|
1013
|
+
const {
|
|
1014
|
+
showErrorIfUntouched: _showErrorIfUntouched,
|
|
1015
|
+
meta: { touched, error, warning }
|
|
1016
|
+
} = props;
|
|
1017
|
+
const showErrorIfUntouched =
|
|
1018
|
+
opts.showErrorIfUntouched || _showErrorIfUntouched;
|
|
1019
|
+
//get is assign defaults mode
|
|
1020
|
+
//if assign default value mode then add on to the component
|
|
1021
|
+
const [defaultValCount, setDefaultValCount] = useState(0);
|
|
1022
|
+
const [defaultValueFromBackend, setDefault] = useState();
|
|
1023
|
+
const [allowUserOverride, setUserOverride] = useState(true);
|
|
1024
|
+
const [isLoadingDefaultValue, setLoadingDefaultValue] = useState(false);
|
|
1025
|
+
const { inAssignDefaultsMode, setAssignDefaultsMode } = useContext(
|
|
1026
|
+
AssignDefaultsModeContext
|
|
1027
|
+
);
|
|
1028
|
+
// tnr: we might want to grab this context object off the window in the future and have it live in lims by default
|
|
1029
|
+
// there is no reason for those vals to live in TRC. Example code below:
|
|
1030
|
+
// const workflowParams = useContext(window.__tgDefaultValParamsContext || defaultNullContext);
|
|
1031
|
+
const workflowParams = useContext(WorkflowDefaultParamsContext);
|
|
1032
|
+
|
|
1033
|
+
const caresAboutToolContext = generateDefaultValue?.params?.toolName;
|
|
1034
|
+
|
|
1035
|
+
const customParamsToUse = useMemo(
|
|
1036
|
+
() => ({
|
|
1037
|
+
...(caresAboutToolContext
|
|
1038
|
+
? { ...workflowDefaultParamsObj, ...workflowParams }
|
|
1039
|
+
: {}),
|
|
1040
|
+
...(generateDefaultValue ? generateDefaultValue.customParams : {})
|
|
1041
|
+
}),
|
|
1042
|
+
[caresAboutToolContext, generateDefaultValue, workflowParams]
|
|
1043
|
+
);
|
|
1044
|
+
|
|
1045
|
+
const triggerGetDefault = useCallback(async () => {
|
|
1046
|
+
if (!defaultValueByIdOverride) {
|
|
1047
|
+
//if defaultValueByIdOverride is passed, we can skip over getting the value from the backend straight to massaging the default value
|
|
1048
|
+
if (!window.__triggerGetDefaultValueRequest) return;
|
|
1049
|
+
if (!generateDefaultValue) return;
|
|
1050
|
+
setLoadingDefaultValue(true);
|
|
1051
|
+
//custom params should match params keys. if not throw an error
|
|
1052
|
+
const doParamsMatch = isEqual(
|
|
1053
|
+
Object.keys({
|
|
1054
|
+
...(caresAboutToolContext ? workflowDefaultParamsObj : {}), //we don't want to compare these keys so we just spread them here
|
|
1055
|
+
...(generateDefaultValue.params || {})
|
|
1056
|
+
}).sort(),
|
|
1057
|
+
Object.keys(customParamsToUse).sort()
|
|
1058
|
+
);
|
|
1059
|
+
if (!doParamsMatch) {
|
|
1060
|
+
console.warn(
|
|
1061
|
+
`Issue with generateDefaultValue. customParams don't match params`
|
|
1062
|
+
);
|
|
1063
|
+
console.warn(
|
|
1064
|
+
`generateDefaultValue.params:`,
|
|
1065
|
+
generateDefaultValue.params
|
|
1066
|
+
);
|
|
1067
|
+
console.warn(`generateDefaultValue.customParams:`, customParamsToUse);
|
|
1068
|
+
throw new Error(
|
|
1069
|
+
`Issue with generateDefaultValue code=${
|
|
1070
|
+
generateDefaultValue.code
|
|
1071
|
+
}: Difference detected with: ${difference(
|
|
1072
|
+
Object.keys(generateDefaultValue.params || {}),
|
|
1073
|
+
Object.keys(customParamsToUse || {})
|
|
1074
|
+
).join(
|
|
1075
|
+
", "
|
|
1076
|
+
)}. customParams passed into the field should match params (as defined in defaultValueConstants.js). See console for more details.`
|
|
1077
|
+
);
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
try {
|
|
1082
|
+
let { defaultValue, allowUserOverride } = defaultValueByIdOverride
|
|
1083
|
+
? { defaultValue: defaultValueByIdOverride }
|
|
1084
|
+
: await window.__triggerGetDefaultValueRequest(
|
|
1085
|
+
generateDefaultValue.code,
|
|
1086
|
+
customParamsToUse
|
|
1087
|
+
);
|
|
1088
|
+
if (massageDefaultIdValue) {
|
|
1089
|
+
const massagedRes = await massageDefaultIdValue({
|
|
1090
|
+
defaultValueById: defaultValue
|
|
1091
|
+
});
|
|
1092
|
+
if (massagedRes.defaultValue) {
|
|
1093
|
+
defaultValue = massagedRes.defaultValue;
|
|
1094
|
+
}
|
|
1095
|
+
if (massagedRes.preventUserOverrideFromBeingDisabled) {
|
|
1096
|
+
allowUserOverride = true;
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
if (
|
|
1100
|
+
ComponentToWrap === renderBlueprintCheckbox ||
|
|
1101
|
+
ComponentToWrap === renderBlueprintSwitch
|
|
1102
|
+
) {
|
|
1103
|
+
setDefault(defaultValue === "true");
|
|
1104
|
+
} else {
|
|
1105
|
+
if (typeof defaultValue === "string") {
|
|
1106
|
+
// remove double spaces and leading/trailing
|
|
1107
|
+
defaultValue = defaultValue.replace(/\s+/g, " ").trim();
|
|
1108
|
+
}
|
|
1109
|
+
setDefault(defaultValue);
|
|
1110
|
+
}
|
|
1111
|
+
setUserOverride(allowUserOverride);
|
|
1112
|
+
setDefaultValCount(defaultValCount + 1);
|
|
1113
|
+
} catch (error) {
|
|
1114
|
+
console.error(`error aswf298f:`, error);
|
|
1115
|
+
}
|
|
1116
|
+
if (window.Cypress && window.Cypress.addFakeDefaultValueWait) {
|
|
1117
|
+
await fakeWait();
|
|
1118
|
+
}
|
|
1119
|
+
setLoadingDefaultValue(false);
|
|
1120
|
+
}, [
|
|
1121
|
+
caresAboutToolContext,
|
|
1122
|
+
customParamsToUse,
|
|
1123
|
+
defaultValCount,
|
|
1124
|
+
defaultValueByIdOverride,
|
|
1125
|
+
generateDefaultValue,
|
|
1126
|
+
massageDefaultIdValue
|
|
1127
|
+
]);
|
|
1128
|
+
|
|
1129
|
+
// if generateDefaultValue, hit the backend for that value
|
|
1130
|
+
useDeepCompareEffect(() => {
|
|
1131
|
+
// if the input already has a value we don't want to override with the default value request
|
|
1132
|
+
if (rest.input.value) return;
|
|
1133
|
+
triggerGetDefault();
|
|
1134
|
+
}, [generateDefaultValue || {}]);
|
|
1135
|
+
|
|
1136
|
+
// const asyncValidating = props.asyncValidating;
|
|
1137
|
+
const defaultProps = useMemo(
|
|
1138
|
+
() => ({
|
|
1139
|
+
...rest,
|
|
1140
|
+
defaultValue: defaultValueFromBackend || defaultValueFromProps,
|
|
1141
|
+
disabled: props.disabled || allowUserOverride === false,
|
|
1142
|
+
readOnly: props.readOnly || isLoadingDefaultValue,
|
|
1143
|
+
intent: getIntent({
|
|
1144
|
+
showErrorIfUntouched,
|
|
1145
|
+
meta: { touched, error, warning }
|
|
1146
|
+
}),
|
|
1147
|
+
intentClass: getIntentClass({
|
|
1148
|
+
showErrorIfUntouched,
|
|
1149
|
+
meta: { touched, error, warning }
|
|
1150
|
+
})
|
|
1151
|
+
}),
|
|
1152
|
+
[
|
|
1153
|
+
allowUserOverride,
|
|
1154
|
+
defaultValueFromBackend,
|
|
1155
|
+
defaultValueFromProps,
|
|
1156
|
+
error,
|
|
1157
|
+
isLoadingDefaultValue,
|
|
1158
|
+
props.disabled,
|
|
1159
|
+
props.readOnly,
|
|
1160
|
+
rest,
|
|
1161
|
+
showErrorIfUntouched,
|
|
1162
|
+
touched,
|
|
1163
|
+
warning
|
|
1164
|
+
]
|
|
1165
|
+
);
|
|
1166
|
+
|
|
1167
|
+
// don't show intent while async validating
|
|
1168
|
+
// if (asyncValidating) {
|
|
1169
|
+
// delete defaultProps.intent;
|
|
1170
|
+
// delete defaultProps.intentClass;
|
|
1171
|
+
// }
|
|
1172
|
+
|
|
1173
|
+
const startAssigningDefault = useCallback(
|
|
1174
|
+
() =>
|
|
1175
|
+
window.__showAssignDefaultValueModal &&
|
|
1176
|
+
window.__showAssignDefaultValueModal({
|
|
1177
|
+
...props,
|
|
1178
|
+
generateDefaultValue: {
|
|
1179
|
+
...props.generateDefaultValue,
|
|
1180
|
+
customParams: customParamsToUse
|
|
1181
|
+
},
|
|
1182
|
+
onFinish: () => {
|
|
1183
|
+
triggerGetDefault();
|
|
1184
|
+
}
|
|
1185
|
+
}),
|
|
1186
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1187
|
+
[customParamsToUse, triggerGetDefault]
|
|
1188
|
+
);
|
|
1189
|
+
|
|
1190
|
+
return (
|
|
1191
|
+
<AbstractInput
|
|
1192
|
+
{...opts}
|
|
1193
|
+
defaultValCount={defaultValCount}
|
|
1194
|
+
isRequired={isRequired}
|
|
1195
|
+
{...defaultProps}
|
|
1196
|
+
isLoadingDefaultValue={isLoadingDefaultValue}
|
|
1197
|
+
showGenerateDefaultDot={
|
|
1198
|
+
!inAssignDefaultsMode &&
|
|
1199
|
+
window.__showGenerateDefaultDot?.() &&
|
|
1200
|
+
!!generateDefaultValue
|
|
1201
|
+
}
|
|
1202
|
+
setAssignDefaultsMode={setAssignDefaultsMode}
|
|
1203
|
+
startAssigningDefault={startAssigningDefault}
|
|
1204
|
+
assignDefaultButton={
|
|
1205
|
+
inAssignDefaultsMode &&
|
|
1206
|
+
generateDefaultValue && (
|
|
1207
|
+
<Button
|
|
1208
|
+
onClick={startAssigningDefault}
|
|
1209
|
+
small
|
|
1210
|
+
style={{ background: "yellow", color: "black" }}
|
|
1211
|
+
>
|
|
1212
|
+
Assign Default
|
|
1213
|
+
</Button>
|
|
1214
|
+
)
|
|
1215
|
+
}
|
|
1216
|
+
>
|
|
1217
|
+
<ComponentToWrap {...defaultProps} />
|
|
1218
|
+
</AbstractInput>
|
|
1219
|
+
);
|
|
1220
|
+
};
|
|
1221
|
+
};
|
|
1222
|
+
|
|
1223
|
+
export const InputField = generateField(RenderBlueprintInput);
|
|
1224
|
+
export const FileUploadField = generateField(renderFileUpload);
|
|
1225
|
+
export const DateInputField = generateField(renderBlueprintDateInput);
|
|
1226
|
+
export const DateRangeInputField = generateField(renderBlueprintDateRangeInput);
|
|
1227
|
+
export const CheckboxField = generateField(renderBlueprintCheckbox, {
|
|
1228
|
+
noOuterLabel: true,
|
|
1229
|
+
noFillField: true
|
|
1230
|
+
});
|
|
1231
|
+
export const SwitchField = generateField(renderBlueprintSwitch, {
|
|
1232
|
+
noOuterLabel: true,
|
|
1233
|
+
noFillField: true
|
|
1234
|
+
});
|
|
1235
|
+
export const TextareaField = generateField(RenderBlueprintTextarea);
|
|
1236
|
+
export const SuggestField = generateField(renderSuggest);
|
|
1237
|
+
export const EditableTextField = generateField(renderBlueprintEditableText);
|
|
1238
|
+
export const NumericInputField = generateField(renderBlueprintNumericInput);
|
|
1239
|
+
export const RadioGroupField = generateField(renderBlueprintRadioGroup, {
|
|
1240
|
+
noFillField: true
|
|
1241
|
+
});
|
|
1242
|
+
export const ReactSelectField = generateField(renderReactSelect);
|
|
1243
|
+
export const SelectField = generateField(renderSelect);
|
|
1244
|
+
export const ReactColorField = generateField(RenderReactColorPicker);
|
|
1245
|
+
|
|
1246
|
+
function getOptions(options) {
|
|
1247
|
+
return (
|
|
1248
|
+
options &&
|
|
1249
|
+
options.map(function (opt) {
|
|
1250
|
+
if (typeof opt === "string") {
|
|
1251
|
+
return { label: opt, value: opt };
|
|
1252
|
+
} else if (isNumber(opt)) return { label: opt.toString(), value: opt };
|
|
1253
|
+
return opt;
|
|
1254
|
+
})
|
|
1255
|
+
);
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
function fakeWait() {
|
|
1259
|
+
const fakeWaitNum = isNumber(window.Cypress.addFakeDefaultValueWait)
|
|
1260
|
+
? window.Cypress.addFakeDefaultValueWait
|
|
1261
|
+
: 3000;
|
|
1262
|
+
|
|
1263
|
+
return new Promise(resolve => {
|
|
1264
|
+
setTimeout(() => resolve(), fakeWaitNum);
|
|
1265
|
+
});
|
|
1266
|
+
}
|