@teselagen/ui 0.0.9 → 0.0.12

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