@teselagen/ui 0.0.11 → 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 (125) 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.mjs +0 -109378
  124. package/index.umd.js +0 -109381
  125. package/style.css +0 -10421
@@ -0,0 +1,402 @@
1
+ import React from "react";
2
+ import { lifecycle, compose, branch } from "recompose";
3
+ import { withRouter, Link } from "react-router-dom";
4
+ import {
5
+ MenuItem,
6
+ MenuDivider,
7
+ Tooltip,
8
+ KeyCombo,
9
+ ContextMenu,
10
+ Menu,
11
+ Classes,
12
+ Icon
13
+ } from "@blueprintjs/core";
14
+ import { startCase, omit, isNumber, flatMap, isArray, isString, noop } from "lodash";
15
+ import fuzzysearch from "fuzzysearch";
16
+
17
+
18
+ // https://github.com/palantir/blueprint/issues/2820
19
+ function MenuItemLink({ text, onClick, icon, navTo }) {
20
+ const handleLinkClick = e => {
21
+ e.target.closest(`.${Classes.POPOVER_DISMISS}`).click();
22
+ };
23
+
24
+ return (
25
+ <li className={Classes.POPOVER_DISMISS} onClick={onClick}>
26
+ <Link onClick={handleLinkClick} to={navTo} className="bp3-menu-item">
27
+ {icon && <Icon icon={icon} />}
28
+ <div className="bp3-text-overflow-ellipsis bp3-fill">{text}</div>
29
+ </Link>
30
+ </li>
31
+ );
32
+ }
33
+
34
+ // Enhanced MenuItem that supports history-based navigation when passed a
35
+ // `navTo` prop
36
+ export const EnhancedMenuItem = compose(
37
+ lifecycle({
38
+ componentDidMount: function() {
39
+ const { didMount = noop, className } = this.props;
40
+ didMount({ className });
41
+ },
42
+ componentWillUnmount: function() {
43
+ const { willUnmount = noop, className } = this.props;
44
+ willUnmount({ className });
45
+ }
46
+ }),
47
+ branch(({ navTo }) => navTo, withRouter)
48
+ )(function({ navTo, context, staticContext, didMount, willUnmount, ...props }) {
49
+ let MenuItemComp = MenuItem;
50
+ if (navTo) {
51
+ MenuItemComp = MenuItemLink;
52
+ }
53
+
54
+ return (
55
+ <MenuItemComp
56
+ popoverProps={{
57
+ autoFocus: false
58
+ }}
59
+ {...(navTo && { navTo })}
60
+ {...props}
61
+ onClick={
62
+ props.onClick
63
+ ? (...args) => {
64
+ return props.onClick(...args, context);
65
+ }
66
+ : undefined
67
+ }
68
+ />
69
+ );
70
+ });
71
+
72
+ // First Non-Undefined
73
+ function fnu(...args) {
74
+ return args.find(v => v !== undefined);
75
+ }
76
+
77
+ // Sets a tick icon if items has a `checked` prop
78
+ export const tickMenuEnhancer = def => {
79
+ const out = { ...def };
80
+ if (out.checked !== undefined) {
81
+ out.icon = out.checked ? "small-tick" : "blank";
82
+ }
83
+ return out;
84
+ };
85
+
86
+ // Derives various menu item props based on command objects matched via the `cmd`
87
+ // prop. Derived props include `text`, `icon`, `hotkey`, `onClick` and `disabled`.
88
+ export const commandMenuEnhancer = (commands, config = {}) => (
89
+ def,
90
+ context
91
+ ) => {
92
+ const cmdId = typeof def === "string" ? def : def.cmd;
93
+ let item = typeof def === "string" ? { cmd: def } : { ...def };
94
+
95
+ const useTicks = fnu(item.useTicks, config.useTicks);
96
+ delete item.useTicks;
97
+
98
+ if (cmdId && commands[cmdId] && def.divider === undefined) {
99
+ const command = commands[cmdId];
100
+
101
+ const { isActive, isDisabled, isHidden } = command;
102
+ const toggles = isActive !== undefined;
103
+
104
+ item.hidden = fnu(item.hidden, isHidden);
105
+ item.disabled = fnu(item.disabled, isDisabled);
106
+
107
+ item.key = item.key || cmdId;
108
+ item.submenu = item.submenu || command.submenu;
109
+ item.component = item.component || command.component;
110
+
111
+ if (toggles) {
112
+ if (useTicks) {
113
+ item.text = item.text || command.shortName || command.name;
114
+ item.checked = item.checked || isActive;
115
+ } else {
116
+ item.text =
117
+ item.text ||
118
+ (isActive ? command.name : command.inactiveName || command.name);
119
+ item.icon =
120
+ item.icon ||
121
+ (isActive ? command.icon : command.inactiveIcon || command.icon);
122
+ }
123
+ } else {
124
+ item.text = item.text || command.name;
125
+ item.icon = item.icon || command.icon;
126
+ }
127
+
128
+ item.hotkey = item.hotkey || command.hotkey;
129
+ if (!item.onClick) {
130
+ item.onClick = event =>
131
+ command.execute({
132
+ event,
133
+ context,
134
+ menuItem: item,
135
+ viaMenu: true
136
+ });
137
+ }
138
+ } else if (cmdId && !commands[cmdId]) {
139
+ item.text = item.text || startCase(cmdId);
140
+ item.disabled = true;
141
+ }
142
+
143
+ if (config.omitIcons) {
144
+ item.icon = undefined;
145
+ }
146
+
147
+ if (config.forceIconAlignment !== false) {
148
+ item.icon = item.icon || "blank";
149
+ }
150
+
151
+ if (useTicks) {
152
+ item = tickMenuEnhancer(item);
153
+ }
154
+
155
+ return item;
156
+ };
157
+
158
+ const ident = x => x;
159
+
160
+ const dividerShorthandEnhancer = def =>
161
+ typeof def === "string" && def.startsWith("--")
162
+ ? { divider: def.substr(2) }
163
+ : def;
164
+
165
+ // filter out unwanted attributes here! we won't want these to show up on the dom element or react will give nasty warnings
166
+ const unwantedAttrs = [
167
+ "isSimpleText",
168
+ "justText",
169
+ "submenu",
170
+ "component",
171
+ "hotkey",
172
+ "changingProps",
173
+ "showInSearchMenu",
174
+ "hideFromMenuSearch"
175
+ ];
176
+
177
+ /** A menu item component that adds many features over the standard MenuItem,
178
+ * and allows for dynamic menu structures that are computed efficiently (only
179
+ * visible sections are computed and rendered).
180
+ * TODO: document and add examples
181
+ */
182
+ export const DynamicMenuItem = ({
183
+ def,
184
+ enhancers = [ident],
185
+ context,
186
+ doNotEnhanceTopLevelItem
187
+ }) => {
188
+ // If passed an element instead of a menu item definition, return it.
189
+ // This allows mixing menu item elements and menu item defs, and makes it
190
+ // safe to call menu creation utils with their own output.
191
+ if (React.isValidElement(def)) return def;
192
+
193
+ const item = [
194
+ dividerShorthandEnhancer,
195
+ ...(doNotEnhanceTopLevelItem ? [ident] : enhancers)
196
+ ].reduce((v, f) => f(v, context), def);
197
+ let out;
198
+
199
+ if (item.divider !== undefined) {
200
+ out = <MenuDivider {...(item.divider ? { title: item.divider } : {})} />;
201
+ } else {
202
+ const ItemComponent = item.component || EnhancedMenuItem;
203
+ out = (
204
+ <ItemComponent
205
+ // filter out unwanted attributes here!
206
+ {...omit(item, unwantedAttrs)}
207
+ context={context}
208
+ icon={item.icon || item.iconName}
209
+ labelElement={item.hotkey && <KeyCombo minimal combo={item.hotkey} />}
210
+ text={item.text}
211
+ >
212
+ {item.submenu
213
+ ? item.submenu
214
+ .filter(ident)
215
+ .map((def, index) => (
216
+ <DynamicMenuItem {...{ def, enhancers, context }} key={index} />
217
+ ))
218
+ : undefined}
219
+ </ItemComponent>
220
+ );
221
+ }
222
+ // if (item.disabled && item.disabledTooltip) {
223
+ // item.tooltip = def.disabledTooltip
224
+ // }
225
+ if (item.disabled && typeof item.disabled === "string") {
226
+ item.tooltip = item.disabled;
227
+ }
228
+
229
+ if (item.tooltip) {
230
+ out = <Tooltip content={item.tooltip}>{out}</Tooltip>;
231
+ }
232
+
233
+ return item.hidden ? null : out;
234
+ };
235
+
236
+ // Map the passed item definition(s) to DynamicMenuItem elements
237
+ export const createDynamicMenu = (menuDef, enhancers, context) => {
238
+ if (menuDef instanceof Array) {
239
+ return menuDef.map((def, index) => (
240
+ <DynamicMenuItem {...{ def, enhancers, context }} key={index} />
241
+ ));
242
+ } else {
243
+ return <DynamicMenuItem {...{ def: menuDef, enhancers, context }} />;
244
+ }
245
+ };
246
+
247
+ // Create a "bar" menu, keeping the top level array unchanged, and only
248
+ // map their submenus to DynamicMenuItem elements
249
+ export const createDynamicBarMenu = (topMenuDef, enhancers, context) => {
250
+ return topMenuDef.map(topLevelItem => {
251
+ const def = { ...topLevelItem };
252
+ if (def.submenu) {
253
+ def.submenu = def.submenu.map((subdef, index) => (
254
+ <DynamicMenuItem def={subdef} {...{ enhancers, context }} key={index} />
255
+ ));
256
+ }
257
+ return def;
258
+ });
259
+ };
260
+
261
+ // Shorthand for command-based menus
262
+ export const createCommandMenu = (menuDef, commands, config, context) => {
263
+ return createDynamicMenu(
264
+ menuDef,
265
+ [commandMenuEnhancer(commands, config)],
266
+ context
267
+ );
268
+ };
269
+
270
+ // Shorthand for command-based bar menus
271
+ export const createCommandBarMenu = (menuDef, commands, config, context) => {
272
+ return createDynamicBarMenu(
273
+ menuDef,
274
+ [commandMenuEnhancer(commands, config)],
275
+ context
276
+ );
277
+ };
278
+
279
+ export function showCommandContextMenu(
280
+ menuDef,
281
+ commands,
282
+ config,
283
+ event,
284
+ onClose,
285
+ context
286
+ ) {
287
+ return showContextMenu(
288
+ menuDef,
289
+ [commandMenuEnhancer(commands, config)],
290
+ event,
291
+ onClose,
292
+ context
293
+ );
294
+ }
295
+
296
+ /**
297
+ * TODO: update documentation. This is now an alias of createDynamicMenu
298
+ *
299
+ * Creates the contents of a Blueprint menu based on a given menu structure.
300
+ *
301
+ * The input can be an array of item objects, where each may contain:
302
+ * text: text to show
303
+ * key: React key to use (optional)
304
+ * divider: indicates it's a divider instead of an item. Use an empty string
305
+ * for a normal divider, or some label text for a labeled one
306
+ * icon: name of icon to show (optional)
307
+ * label: right-aligned label, used mostly for shortcuts (optional)
308
+ * hotkey: right-aligned label formatted with <KeyCombo> (optional)
309
+ * tooltip: tooltip text to use (optional)
310
+ * submenu: nested menu structure describing submenu (i.e. array of item objects),
311
+ * or array of MenuItem elements
312
+ * onClick: click handler
313
+ * navTo: a url to navigate to (assumes react-router)
314
+ * href: a url to link to
315
+ * target: link target
316
+ *
317
+ * Since this function is recursive (to handle nested submenus), and React
318
+ * elements passed as input are returned unchanged, it is possible to freely mix
319
+ * item objects and MenuItem elements. That also makes it safe to call the function
320
+ * with its own output.
321
+ *
322
+ * A customize function may also be provided, and allows customization or
323
+ * replacement of the created MenuItems, allowing for custom props or behavior.
324
+ * That function receives the original created element and the item object, and
325
+ * must return an element.
326
+ *
327
+ * Usage example:
328
+ *
329
+ * const menu = createMenu([
330
+ * { text: 'Item One', icon: 'add', onClick: () => console.info('Clicked 1') },
331
+ * { text: 'Item One', onClick: () => console.info('Clicked 2') },
332
+ * { divider: '' },
333
+ * { text: 'Item Three', icon: 'numerical', onClick: () => console.info('Clicked 3') },
334
+ * { divider: '' },
335
+ * { text: 'Submenus', submenu: [
336
+ * { text: 'Sub One' },
337
+ * { text: 'Sub Two' },
338
+ * ]},
339
+ * ]);
340
+ *
341
+ */
342
+ export const createMenu = createDynamicMenu;
343
+
344
+ export function showContextMenu(
345
+ menuDef,
346
+ enhancers,
347
+ event,
348
+ onClose,
349
+ context,
350
+ menuComp = Menu
351
+ ) {
352
+ menuDef = filterMenuForCorrectness(menuDef);
353
+ if (!menuDef) return;
354
+
355
+ const MenuComponent = menuComp;
356
+ event.persist && event.persist();
357
+ // Render a context menu at the passed event's position
358
+ ContextMenu.show(
359
+ <MenuComponent>
360
+ {createDynamicMenu(menuDef, enhancers, context)}
361
+ </MenuComponent>,
362
+ { left: event.clientX, top: event.clientY },
363
+ onClose
364
+ );
365
+ event.stopPropagation && event.stopPropagation();
366
+ event.preventDefault && event.preventDefault();
367
+ }
368
+
369
+ function filterMenuForCorrectness(menuDef) {
370
+ return menuDef && menuDef.length && menuDef.filter(ident);
371
+ }
372
+
373
+ export function getStringFromReactComponent(comp) {
374
+ if (!comp) return "";
375
+ if (isString(comp) || isNumber(comp)) return comp;
376
+ if (comp.props?.text) {
377
+ return getStringFromReactComponent(comp.props.text);
378
+ }
379
+ const { children } = comp.props || {};
380
+ if (!children) return "";
381
+ if (isArray(children))
382
+ return flatMap(children, getStringFromReactComponent).join("");
383
+ if (isString(children)) return children;
384
+
385
+ if (children.props) {
386
+ return getStringFromReactComponent(children.props);
387
+ }
388
+ }
389
+ export function doesSearchValMatchText(searchVal, justText) {
390
+ return fuzzysearch(
391
+ searchVal ? searchVal.toLowerCase() : "",
392
+ justText ? justText.toLowerCase() : ""
393
+ );
394
+ }
395
+
396
+ export const MenuItemWithTooltip = ({ tooltip, ...rest }) => {
397
+ let out = <MenuItem {...rest}></MenuItem>;
398
+ if (tooltip) {
399
+ out = <Tooltip content={tooltip}>{out}</Tooltip>;
400
+ }
401
+ return out;
402
+ };
@@ -0,0 +1,11 @@
1
+ // will help tooltip to not get smushed
2
+ const popoverOverflowModifiers = {
3
+ preventOverflow: { enabled: false },
4
+ hide: {
5
+ enabled: false
6
+ },
7
+ flip: {
8
+ boundariesElement: "viewport"
9
+ }
10
+ };
11
+ export default popoverOverflowModifiers;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * This HOC compares props to create a pure component that will only update
3
+ * when props are not deep equal. It will compare the string values of functions
4
+ */
5
+ import { shouldUpdate } from "recompose";
6
+ import { isEqualWith, isFunction } from "lodash";
7
+
8
+ /**
9
+ * tgreen: This is an awful function which we should come up with a better solution for
10
+ * @param {*} o1
11
+ * @param {*} o2
12
+ */
13
+ const isEq = (o1, o2) => {
14
+ const isEq = isEqualWith(o1, o2, function(val1, val2) {
15
+ if (isFunction(val1) && isFunction(val2)) {
16
+ return val1 === val2 || val1.toString() === val2.toString();
17
+ }
18
+ // tgreen: we were seeing an issue where the isEq would infinite loop on react children
19
+ // components. We decided to just ignore them (assume they are equal)
20
+ if (val1 && val1.constructor && val1.constructor.name === "FiberNode")
21
+ return true;
22
+ });
23
+ return isEq;
24
+ };
25
+
26
+ const pure = BaseComponent => {
27
+ const hoc = shouldUpdate((props, nextProps) => !isEq(props, nextProps));
28
+ return hoc(BaseComponent);
29
+ };
30
+
31
+ export default pure;
@@ -0,0 +1,29 @@
1
+ import ReactDOM from 'react-dom'
2
+
3
+ export function renderOnDoc(fn) {
4
+ const elemDiv = document.createElement("div");
5
+ elemDiv.style.cssText =
6
+ "position:absolute;width:100%;height:100%;top:0px;opacity:0.3;z-index:0;";
7
+ document.body.appendChild(elemDiv);
8
+ const handleClose = () => {
9
+ setTimeout(() => {
10
+ ReactDOM.unmountComponentAtNode(elemDiv);
11
+ document.body.removeChild(elemDiv);
12
+ });
13
+ };
14
+ return ReactDOM.render(fn(handleClose), elemDiv);
15
+ }
16
+ export function renderOnDocSimple(el) {
17
+ const elemDiv = document.createElement("div");
18
+ elemDiv.style.cssText =
19
+ "position:absolute;width:100%;height:100%;top:0px;opacity:1;z-index:10000;";
20
+ document.body.appendChild(elemDiv);
21
+ const handleClose = () => {
22
+ setTimeout(() => {
23
+ ReactDOM.unmountComponentAtNode(elemDiv);
24
+ document.body.removeChild(elemDiv);
25
+ });
26
+ };
27
+ ReactDOM.render(el, elemDiv);
28
+ return handleClose
29
+ }
@@ -0,0 +1,22 @@
1
+ /* Copyright (C) 2018 TeselaGen Biotechnology, Inc. */
2
+ import React from "react";
3
+ import { ProgressBar } from "@blueprintjs/core";
4
+
5
+ export default (message, value, key, opts) => {
6
+ return window.toastr.default(
7
+ <div>
8
+ <div style={{ marginBottom: 10 }}>{message}</div>
9
+ <ProgressBar
10
+ intent={value >= 1 ? "success" : "primary"}
11
+ animate={value < 1 || !value}
12
+ stripes={value < 1 || !value}
13
+ value={value}
14
+ />
15
+ </div>,
16
+ {
17
+ timeout: value >= 1 ? 3000 : 100000,
18
+ key,
19
+ ...opts
20
+ }
21
+ );
22
+ };
@@ -0,0 +1,45 @@
1
+ import { flatMap, keyBy } from "lodash";
2
+ import determineBlackOrWhiteTextColor from "./determineBlackOrWhiteTextColor";
3
+
4
+ export function getTagsAndTagOptions(allTags) {
5
+ return flatMap(allTags, tag => {
6
+ if (tag.tagOptions && tag.tagOptions.length) {
7
+ return tag.tagOptions.map(tagO => {
8
+ const fullname = `${tag.name}: ${tagO.name}`;
9
+ const value = `${tag.id}:${tagO.id}`;
10
+ return {
11
+ ...tagO,
12
+ label: fullname,
13
+ value,
14
+ id: tagO.id
15
+ };
16
+ });
17
+ }
18
+ return {
19
+ ...tag,
20
+ label: tag.name,
21
+ value: tag.id
22
+ };
23
+ });
24
+ }
25
+
26
+ export function getKeyedTagsAndTagOptions(tags) {
27
+ return keyBy(getTagsAndTagOptions(tags), "value");
28
+ }
29
+
30
+ export function getTagColorStyle(color) {
31
+ return color
32
+ ? {
33
+ style: {
34
+ backgroundColor: color,
35
+ color: determineBlackOrWhiteTextColor(color)
36
+ }
37
+ }
38
+ : {};
39
+ }
40
+ export function getTagProps(vals) {
41
+ return {
42
+ ...getTagColorStyle(vals.color),
43
+ children: vals.label || vals.name
44
+ };
45
+ }
@@ -0,0 +1,32 @@
1
+ import React, { useMemo } from "react";
2
+ import { connect } from "react-redux";
3
+ import { FormName, formValueSelector } from "redux-form";
4
+
5
+ const tgFormValues = (...fieldNames) => Component => props => {
6
+ return (
7
+ <FormName>
8
+ {formName => {
9
+ const name = formName.form;
10
+ const Wrapped = useMemo(() => {
11
+ const selector = formValueSelector(name || "");
12
+ const wrapper = connect(state => {
13
+ const vals = {};
14
+ fieldNames.forEach(name => {
15
+ vals[name] = selector(state, name);
16
+ });
17
+ return vals;
18
+ });
19
+ return wrapper(Component);
20
+ }, [name]);
21
+ return <Wrapped {...props} />;
22
+ }}
23
+ </FormName>
24
+ );
25
+ };
26
+ export default tgFormValues;
27
+
28
+ export const tgFormValueSelector = (formName, ...fields) => {
29
+ return connect(state => {
30
+ return formValueSelector(formName)(state, ...fields);
31
+ });
32
+ };
@@ -0,0 +1,38 @@
1
+ /* Copyright (C) 2018 TeselaGen Biotechnology, Inc. */
2
+ import { compose, withHandlers } from "recompose";
3
+ import { connect } from "react-redux";
4
+ import { change, initialize } from "redux-form";
5
+
6
+ export default function(_tableFormName, propName = "selectTableRecords") {
7
+ return compose(
8
+ connect(null, {
9
+ changeFormValue: change,
10
+ initializeForm: initialize
11
+ }),
12
+ withHandlers({
13
+ [propName]: props => (_records = []) => {
14
+ let tableFormName = _tableFormName;
15
+ if (typeof _tableFormName === "function") {
16
+ tableFormName = _tableFormName(props);
17
+ }
18
+ // initialize if needed so that the values will stay
19
+ props.initializeForm(tableFormName, {}, true, {
20
+ keepDirty: true,
21
+ updateUnregisteredFields: true,
22
+ keepValues: true
23
+ });
24
+ const selectedEntityIdMap = {};
25
+ let records = _records;
26
+ if (_records && !Array.isArray(_records)) records = [records];
27
+ records.forEach(record => {
28
+ selectedEntityIdMap[record.id] = { entity: record };
29
+ });
30
+ props.changeFormValue(
31
+ tableFormName,
32
+ "reduxFormSelectedEntityIdMap",
33
+ selectedEntityIdMap
34
+ );
35
+ }
36
+ })
37
+ );
38
+ }
@@ -0,0 +1,10 @@
1
+ import { useStore } from "react-redux";
2
+ import React from "react";
3
+
4
+ const withStore = Component => {
5
+ return props => {
6
+ const store = useStore();
7
+ return <Component {...props} store={store} />;
8
+ };
9
+ };
10
+ export default withStore;