@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.
Files changed (142) hide show
  1. package/DataTable/utils/queryParams.d.ts +3 -8
  2. package/DataTable/utils/tableQueryParamsToHasuraClauses.d.ts +12 -0
  3. package/index.cjs.js +161 -27
  4. package/index.es.js +161 -27
  5. package/package.json +1 -1
  6. package/src/AdvancedOptions.spec.js +26 -0
  7. package/src/AsyncValidateFieldSpinner/index.js +12 -0
  8. package/src/BlueprintError/index.js +14 -0
  9. package/src/BounceLoader/index.js +16 -0
  10. package/src/BounceLoader/style.css +45 -0
  11. package/src/CollapsibleCard/index.js +68 -0
  12. package/src/CollapsibleCard/style.css +23 -0
  13. package/src/DNALoader/index.js +20 -0
  14. package/src/DNALoader/style.css +251 -0
  15. package/src/{Columns.js → DataTable/Columns.js} +1 -1
  16. package/src/{DisplayOptions.js → DataTable/DisplayOptions.js} +1 -1
  17. package/src/DataTable/index.js +3209 -0
  18. package/src/DataTable/style.css +608 -0
  19. package/src/{filterLocalEntitiesToHasura.js → DataTable/utils/filterLocalEntitiesToHasura.js} +6 -0
  20. package/src/DataTable/utils/filterLocalEntitiesToHasura.test.js +538 -0
  21. package/src/DataTable/utils/index.js +55 -0
  22. package/src/{initializeHasuraWhereAndFilter.js → DataTable/utils/initializeHasuraWhereAndFilter.js} +0 -1
  23. package/src/{queryParams.js → DataTable/utils/queryParams.js} +32 -21
  24. package/src/DataTable/utils/tableQueryParamsToHasuraClauses.js +250 -0
  25. package/src/DataTable/utils/tableQueryParamsToHasuraClauses.test.js +206 -0
  26. package/src/{withTableParams.js → DataTable/utils/withTableParams.js} +2 -2
  27. package/src/DialogFooter/index.js +86 -0
  28. package/src/DialogFooter/style.css +9 -0
  29. package/src/FormComponents/index.js +1266 -0
  30. package/src/FormComponents/style.css +275 -0
  31. package/src/FormComponents/utils.js +6 -0
  32. package/src/HotkeysDialog/index.js +79 -0
  33. package/src/HotkeysDialog/style.css +54 -0
  34. package/src/InfoHelper/index.js +78 -0
  35. package/src/InfoHelper/style.css +7 -0
  36. package/src/IntentText/index.js +18 -0
  37. package/src/Loading/index.js +70 -0
  38. package/src/Loading/style.css +4 -0
  39. package/src/MenuBar/index.js +423 -0
  40. package/src/MenuBar/style.css +45 -0
  41. package/src/PromptUnsavedChanges/index.js +38 -0
  42. package/src/ResizableDraggableDialog/index.js +141 -0
  43. package/src/ResizableDraggableDialog/style.css +42 -0
  44. package/src/ScrollToTop/index.js +72 -0
  45. package/src/TagSelect/index.js +69 -0
  46. package/src/TagSelect/style.css +13 -0
  47. package/src/TgHtmlSelect/index.js +20 -0
  48. package/src/TgSelect/index.js +537 -0
  49. package/src/TgSelect/style.css +61 -0
  50. package/src/TgSuggest/index.js +124 -0
  51. package/src/Timeline/index.js +15 -0
  52. package/src/Timeline/style.css +29 -0
  53. package/src/enhancers/withDialog/index.js +196 -0
  54. package/src/index.js +88 -1
  55. package/src/showConfirmationDialog/index.js +148 -0
  56. package/src/style.css +261 -9
  57. package/src/utils/hooks/index.js +1 -0
  58. package/DataTable/utils/simplifyHasuraWhere.d.ts +0 -1
  59. package/src/simplifyHasuraWhere.js +0 -80
  60. package/src/tableQueryParamsToHasuraClauses.js +0 -113
  61. /package/src/{CellDragHandle.js → DataTable/CellDragHandle.js} +0 -0
  62. /package/src/{ColumnFilterMenu.js → DataTable/ColumnFilterMenu.js} +0 -0
  63. /package/src/{DisabledLoadingComponent.js → DataTable/DisabledLoadingComponent.js} +0 -0
  64. /package/src/{DropdownCell.js → DataTable/DropdownCell.js} +0 -0
  65. /package/src/{EditableCell.js → DataTable/EditableCell.js} +0 -0
  66. /package/src/{FilterAndSortMenu.js → DataTable/FilterAndSortMenu.js} +0 -0
  67. /package/src/{PagingTool.js → DataTable/PagingTool.js} +0 -0
  68. /package/src/{RenderCell.js → DataTable/RenderCell.js} +0 -0
  69. /package/src/{SearchBar.js → DataTable/SearchBar.js} +0 -0
  70. /package/src/{SortableColumns.js → DataTable/SortableColumns.js} +0 -0
  71. /package/src/{TableFormTrackerContext.js → DataTable/TableFormTrackerContext.js} +0 -0
  72. /package/src/{ThComponent.js → DataTable/ThComponent.js} +0 -0
  73. /package/src/{dataTableEnhancer.js → DataTable/dataTableEnhancer.js} +0 -0
  74. /package/src/{defaultFormatters.js → DataTable/defaultFormatters.js} +0 -0
  75. /package/src/{defaultValidators.js → DataTable/defaultValidators.js} +0 -0
  76. /package/src/{editCellHelper.js → DataTable/editCellHelper.js} +0 -0
  77. /package/src/{getCellVal.js → DataTable/getCellVal.js} +0 -0
  78. /package/src/{getVals.js → DataTable/getVals.js} +0 -0
  79. /package/src/{isTruthy.js → DataTable/isTruthy.js} +0 -0
  80. /package/src/{isValueEmpty.js → DataTable/isValueEmpty.js} +0 -0
  81. /package/src/{convertSchema.js → DataTable/utils/convertSchema.js} +0 -0
  82. /package/src/{formatPasteData.js → DataTable/utils/formatPasteData.js} +0 -0
  83. /package/src/{getAllRows.js → DataTable/utils/getAllRows.js} +0 -0
  84. /package/src/{getCellCopyText.js → DataTable/utils/getCellCopyText.js} +0 -0
  85. /package/src/{getCellInfo.js → DataTable/utils/getCellInfo.js} +0 -0
  86. /package/src/{getFieldPathToField.js → DataTable/utils/getFieldPathToField.js} +0 -0
  87. /package/src/{getIdOrCodeOrIndex.js → DataTable/utils/getIdOrCodeOrIndex.js} +0 -0
  88. /package/src/{getLastSelectedEntity.js → DataTable/utils/getLastSelectedEntity.js} +0 -0
  89. /package/src/{getNewEntToSelect.js → DataTable/utils/getNewEntToSelect.js} +0 -0
  90. /package/src/{getRowCopyText.js → DataTable/utils/getRowCopyText.js} +0 -0
  91. /package/src/{getTableConfigFromStorage.js → DataTable/utils/getTableConfigFromStorage.js} +0 -0
  92. /package/src/{handleCopyColumn.js → DataTable/utils/handleCopyColumn.js} +0 -0
  93. /package/src/{handleCopyHelper.js → DataTable/utils/handleCopyHelper.js} +0 -0
  94. /package/src/{handleCopyRows.js → DataTable/utils/handleCopyRows.js} +0 -0
  95. /package/src/{handleCopyTable.js → DataTable/utils/handleCopyTable.js} +0 -0
  96. /package/src/{isBottomRightCornerOfRectangle.js → DataTable/utils/isBottomRightCornerOfRectangle.js} +0 -0
  97. /package/src/{isEntityClean.js → DataTable/utils/isEntityClean.js} +0 -0
  98. /package/src/{primarySelectedValue.js → DataTable/utils/primarySelectedValue.js} +0 -0
  99. /package/src/{removeCleanRows.js → DataTable/utils/removeCleanRows.js} +0 -0
  100. /package/src/{rowClick.js → DataTable/utils/rowClick.js} +0 -0
  101. /package/src/{selection.js → DataTable/utils/selection.js} +0 -0
  102. /package/src/{useTableEntities.js → DataTable/utils/useTableEntities.js} +0 -0
  103. /package/src/{utils.js → DataTable/utils/utils.js} +0 -0
  104. /package/src/{withSelectedEntities.js → DataTable/utils/withSelectedEntities.js} +0 -0
  105. /package/src/{validateTableWideErrors.js → DataTable/validateTableWideErrors.js} +0 -0
  106. /package/src/{viewColumn.js → DataTable/viewColumn.js} +0 -0
  107. /package/src/{FormSeparator.js → FormComponents/FormSeparator.js} +0 -0
  108. /package/src/{LoadingDots.js → FormComponents/LoadingDots.js} +0 -0
  109. /package/src/{Uploader.js → FormComponents/Uploader.js} +0 -0
  110. /package/src/{getNewName.js → FormComponents/getNewName.js} +0 -0
  111. /package/src/{itemUpload.js → FormComponents/itemUpload.js} +0 -0
  112. /package/src/{sortify.js → FormComponents/sortify.js} +0 -0
  113. /package/src/{tryToMatchSchemas.js → FormComponents/tryToMatchSchemas.js} +0 -0
  114. /package/src/{TimelineEvent.js → Timeline/TimelineEvent.js} +0 -0
  115. /package/src/{tg_modalState.js → enhancers/withDialog/tg_modalState.js} +0 -0
  116. /package/src/{withField.js → enhancers/withField.js} +0 -0
  117. /package/src/{withFields.js → enhancers/withFields.js} +0 -0
  118. /package/src/{withLocalStorage.js → enhancers/withLocalStorage.js} +0 -0
  119. /package/src/{adHoc.js → utils/adHoc.js} +0 -0
  120. /package/src/{basicHandleActionsWithFullState.js → utils/basicHandleActionsWithFullState.js} +0 -0
  121. /package/src/{browserUtils.js → utils/browserUtils.js} +0 -0
  122. /package/src/{combineReducersWithFullState.js → utils/combineReducersWithFullState.js} +0 -0
  123. /package/src/{commandControls.js → utils/commandControls.js} +0 -0
  124. /package/src/{commandUtils.js → utils/commandUtils.js} +0 -0
  125. /package/src/{determineBlackOrWhiteTextColor.js → utils/determineBlackOrWhiteTextColor.js} +0 -0
  126. /package/src/{getDayjsFormatter.js → utils/getDayjsFormatter.js} +0 -0
  127. /package/src/{getTextFromEl.js → utils/getTextFromEl.js} +0 -0
  128. /package/src/{handlerHelpers.js → utils/handlerHelpers.js} +0 -0
  129. /package/src/{useDeepEqualMemo.js → utils/hooks/useDeepEqualMemo.js} +0 -0
  130. /package/src/{useStableReference.js → utils/hooks/useStableReference.js} +0 -0
  131. /package/src/{hotkeyUtils.js → utils/hotkeyUtils.js} +0 -0
  132. /package/src/{isBeingCalledExcessively.js → utils/isBeingCalledExcessively.js} +0 -0
  133. /package/src/{menuUtils.js → utils/menuUtils.js} +0 -0
  134. /package/src/{popoverOverflowModifiers.js → utils/popoverOverflowModifiers.js} +0 -0
  135. /package/src/{pureNoFunc.js → utils/pureNoFunc.js} +0 -0
  136. /package/src/{renderOnDoc.js → utils/renderOnDoc.js} +0 -0
  137. /package/src/{showProgressToast.js → utils/showProgressToast.js} +0 -0
  138. /package/src/{tagUtils.js → utils/tagUtils.js} +0 -0
  139. /package/src/{tgFormValues.js → utils/tgFormValues.js} +0 -0
  140. /package/src/{useTraceUpdate.js → utils/useTraceUpdate.js} +0 -0
  141. /package/src/{withSelectTableRecords.js → utils/withSelectTableRecords.js} +0 -0
  142. /package/src/{withStore.js → utils/withStore.js} +0 -0
@@ -0,0 +1,423 @@
1
+ import React from "react";
2
+ import {
3
+ pickBy,
4
+ isNumber,
5
+ startsWith,
6
+ flatMap,
7
+ take,
8
+ flatten,
9
+ noop
10
+ } from "lodash-es";
11
+ import { Suggest } from "@blueprintjs/select";
12
+ import "./style.css";
13
+ import { Popover, Position, Menu, Button } from "@blueprintjs/core";
14
+ import { some } from "lodash-es";
15
+ import {
16
+ createDynamicMenu,
17
+ DynamicMenuItem,
18
+ getStringFromReactComponent,
19
+ doesSearchValMatchText
20
+ } from "../utils/menuUtils";
21
+ import { comboToLabel, withHotkeys } from "../utils/hotkeyUtils";
22
+
23
+ class MenuBar extends React.Component {
24
+ constructor(props) {
25
+ super(props);
26
+ const combo =
27
+ (this.props && this.props.menuSearchHotkey) || menuSearchHotkey;
28
+ this.hotkeyEnabler = withHotkeys({
29
+ searchHotkey: {
30
+ allowInInput: true,
31
+ global: true,
32
+ combo,
33
+ label: "Search the menu",
34
+ preventDefault: true,
35
+ stopPropagation: true,
36
+ onKeyDown: this.toggleFocusSearchMenu
37
+ }
38
+ });
39
+ }
40
+ static defaultProps = {
41
+ className: "",
42
+ style: {}
43
+ };
44
+
45
+ state = {
46
+ isOpen: false,
47
+ openIndex: null,
48
+ helpItemQueryStringTracker: "" //we use this to track the search value and to not do all the item rendering logic until someone is actually searching
49
+ };
50
+
51
+ handleInteraction = index => newOpenState => {
52
+ if (!newOpenState && index !== this.state.openIndex) {
53
+ return; //return early because the "close" is being fired by another popover
54
+ }
55
+ this.setState({
56
+ isOpen: newOpenState,
57
+ openIndex: newOpenState ? index : null
58
+ });
59
+ };
60
+ handleMouseOver = index => () => {
61
+ const { isOpen } = this.state;
62
+ if (isOpen) {
63
+ this.setState({
64
+ openIndex: index
65
+ });
66
+ }
67
+ };
68
+
69
+ getAllMenuItems = () => {
70
+ const { menu, enhancers, context } = this.props;
71
+ return getAllMenuTextsAndHandlers(menu, enhancers, context);
72
+ };
73
+ addHelpItemIfNecessary = (menu, i) => {
74
+ return menu.map((item, innerIndex) => {
75
+ const { isMenuSearch, inputProps, ...rest } = item;
76
+ if (isMenuSearch) {
77
+ const isTopLevelSearch = !isNumber(i);
78
+ this.isTopLevelSearch = isTopLevelSearch;
79
+ this.menuSearchIndex = isTopLevelSearch ? innerIndex : i;
80
+
81
+ return {
82
+ shouldDismissPopover: false,
83
+ text: (
84
+ <Suggest
85
+ closeOnSelect={false}
86
+ items={
87
+ this.state.helpItemQueryStringTracker
88
+ ? this.getAllMenuItems()
89
+ : []
90
+ }
91
+ itemListPredicate={filterMenuItems}
92
+ itemDisabled={i => i.disabled}
93
+ popoverProps={{
94
+ minimal: true,
95
+ popoverClassName: "tg-menu-search-suggestions"
96
+ }}
97
+ onQueryChange={val => {
98
+ this.setState({ helpItemQueryStringTracker: val });
99
+ }}
100
+ className="tg-menu-bar-help-search"
101
+ resetOnSelect={false}
102
+ resetOnClose={true}
103
+ inputProps={{
104
+ inputRef: n => {
105
+ if (n) {
106
+ this.searchInput = n;
107
+ n.setAttribute &&
108
+ n.setAttribute(
109
+ "size",
110
+ n.getAttribute("placeholder").length
111
+ );
112
+ }
113
+ },
114
+ autoFocus: !isTopLevelSearch,
115
+ placeholder: `Search the menus (${comboToLabel(
116
+ this.props.menuSearchHotkey || menuSearchHotkey,
117
+ false
118
+ ).replace(/\s/g, "")})`,
119
+ ...inputProps
120
+ }}
121
+ initialContent={null}
122
+ onItemSelect={this.handleItemClickOrSelect()}
123
+ inputValueRenderer={i => i.text}
124
+ noResults={<div>No Results...</div>}
125
+ itemRenderer={this.helpItemRenderer}
126
+ {...rest}
127
+ />
128
+ )
129
+ };
130
+ } else {
131
+ return item;
132
+ }
133
+ });
134
+ };
135
+
136
+ helpItemRenderer = (i, b) => {
137
+ // if (i.submenu.length === 3) debugger;
138
+ return (
139
+ <DynamicMenuItem
140
+ key={b.index}
141
+ {...{
142
+ doNotEnhanceTopLevelItem: true,
143
+ enhancers: this.props.enhancers,
144
+ def: {
145
+ ...i,
146
+ text: i.isSimpleText ? i.justText || i.text : i.text,
147
+ label: i.path.length && (
148
+ <span style={{ fontSize: 8 }}>
149
+ {flatMap(i.path, (el, i2) => {
150
+ if (i2 === 0) return el;
151
+ return [" > ", el];
152
+ })}
153
+ </span>
154
+ ),
155
+ onClick: this.handleItemClickOrSelect(i),
156
+ active: b.modifiers.active
157
+ // shouldDismissPopover: true,
158
+ }
159
+ }}
160
+ />
161
+ );
162
+ };
163
+ // itemRenderer = (i, b) => {
164
+ // return (
165
+ // <MenuItem
166
+ // key={b.index}
167
+ // {...{
168
+ // // ...i,
169
+ // icon: i.icon,
170
+ // text: i.isSimpleText ? i.justText || i.text : i.text,
171
+ // label: i.path.length && (
172
+ // <span style={{ fontSize: 8 }}>
173
+ // {flatMap(i.path, (el, i2) => {
174
+ // if (i2 === 0) return el;
175
+ // return [" > ", el];
176
+ // })}
177
+ // </span>
178
+ // ),
179
+ // onClick: this.handleItemClickOrSelect(i),
180
+ // active: b.modifiers.active
181
+ // // shouldDismissPopover: true,
182
+ // }}
183
+ // />
184
+ // );
185
+ // };
186
+
187
+ handleItemClickOrSelect = __i => _i => {
188
+ const i = __i || _i;
189
+ if (!i.onClick) return;
190
+ !i.disabled && i.onClick();
191
+ if (i.shouldDismissPopover !== false) {
192
+ this.setState({ isOpen: false });
193
+ } else {
194
+ if (_i && _i.stopPropagation) {
195
+ _i.stopPropagation();
196
+ _i.preventDefault();
197
+ }
198
+ }
199
+ };
200
+ toggleFocusSearchMenu = () => {
201
+ if (!isNumber(this.menuSearchIndex)) return;
202
+ //toggle off
203
+ if (this.searchInput && document.activeElement === this.searchInput) {
204
+ this.searchInput.blur();
205
+ this.setState({
206
+ isOpen: false,
207
+ openIndex: this.menuSearchIndex
208
+ });
209
+ } else {
210
+ //toggle on
211
+ if (this.isTopLevelSearch) {
212
+ this.searchInput && this.searchInput.focus();
213
+ } else {
214
+ this.setState({
215
+ isOpen: true,
216
+ openIndex: this.menuSearchIndex
217
+ });
218
+ }
219
+ }
220
+ };
221
+
222
+ render() {
223
+ const { className, style, menu, enhancers, extraContent } = this.props;
224
+ const { isOpen, openIndex } = this.state;
225
+ return (
226
+ <div className={"tg-menu-bar " + className} style={style}>
227
+ <this.hotkeyEnabler></this.hotkeyEnabler>
228
+ {menu.map((topLevelItem, i) => {
229
+ const dataKeys = pickBy(topLevelItem, function (value, key) {
230
+ return startsWith(key, "data-");
231
+ });
232
+
233
+ // Support enhancers for top level items too
234
+ topLevelItem = enhancers.reduce((v, f) => f(v), topLevelItem);
235
+
236
+ if (topLevelItem.hidden) {
237
+ return null;
238
+ }
239
+
240
+ const button = (
241
+ <Button
242
+ {...dataKeys} //spread all data-* attributes
243
+ key={i}
244
+ elementRef={n => {
245
+ if (!n) return;
246
+ this.n = n;
247
+ }}
248
+ minimal
249
+ className="tg-menu-bar-item"
250
+ onClick={topLevelItem.onClick}
251
+ disabled={topLevelItem.disabled}
252
+ onMouseOver={
253
+ topLevelItem.submenu ? this.handleMouseOver(i) : noop
254
+ }
255
+ >
256
+ {topLevelItem.text}
257
+ </Button>
258
+ );
259
+ const vh = Math.max(
260
+ document.documentElement.clientHeight || 0,
261
+ window.innerHeight || 0
262
+ );
263
+ const maxHeight =
264
+ vh - ((this.n && this.n.getBoundingClientRect().y + 70) || 70);
265
+
266
+ return !topLevelItem.submenu ? (
267
+ button
268
+ ) : (
269
+ <Popover
270
+ autoFocus={false}
271
+ key={i}
272
+ minimal
273
+ canEscapeKeyClose
274
+ onClosed={() => {
275
+ this.setState({ helpItemQueryStringTracker: "" });
276
+ this.props.onMenuClose && this.props.onMenuClose();
277
+ }}
278
+ portalClassName="tg-menu-bar-popover"
279
+ position={Position.BOTTOM_LEFT}
280
+ isOpen={isOpen && i === openIndex}
281
+ onInteraction={this.handleInteraction(i)}
282
+ content={
283
+ <Menu
284
+ style={
285
+ some(topLevelItem.submenu, n => n.isMenuSearch) //tnrbp4upgrade - I added this logic to prevent the Search Suggest component popover from covering the suggest. Remove this once we're on bp4 (shouldn't be necessary according to https://github.com/palantir/blueprint/issues/4552)
286
+ ? {}
287
+ : { maxHeight, overflow: "auto" }
288
+ }
289
+ >
290
+ {createDynamicMenu(
291
+ this.addHelpItemIfNecessary(topLevelItem.submenu, i),
292
+ enhancers
293
+ )}
294
+ </Menu>
295
+ }
296
+ transitionDuration={0}
297
+ style={{
298
+ transition: "none"
299
+ }}
300
+ inline
301
+ >
302
+ {button}
303
+ </Popover>
304
+ );
305
+ })}
306
+ {extraContent}
307
+ </div>
308
+ );
309
+ }
310
+ }
311
+
312
+ const isDivider = item => item.divider !== undefined;
313
+
314
+ function getAllMenuTextsAndHandlers(menu, enhancers, context, path = []) {
315
+ if (!menu) return [];
316
+ return flatMap(menu, item => {
317
+ const enhancedItem = [...enhancers].reduce((v, f) => f(v, context), item);
318
+ if (isDivider(enhancedItem)) {
319
+ return [];
320
+ }
321
+ if (enhancedItem && enhancedItem.hidden) return [];
322
+ return [
323
+ {
324
+ ...enhancedItem,
325
+ path
326
+ },
327
+ ...getAllMenuTextsAndHandlers(enhancedItem.submenu, enhancers, context, [
328
+ ...path,
329
+ enhancedItem.text
330
+ ])
331
+ ];
332
+ });
333
+ }
334
+
335
+ const filterMenuItems = (searchVal, items) => {
336
+ const newItems = flatMap(items, item => {
337
+ const {
338
+ text,
339
+ onClick,
340
+ hidden,
341
+ hideFromMenuSearch,
342
+ hiddenButSearchableText,
343
+ showInSearchMenu,
344
+ component
345
+ } = item;
346
+
347
+ if (
348
+ !showInSearchMenu &&
349
+ !component &&
350
+ (!text || !onClick || !searchVal || hideFromMenuSearch || hidden)
351
+ ) {
352
+ return [];
353
+ }
354
+ //fix this to use some smart regex
355
+ let justText = text;
356
+ let isSimpleText = true;
357
+ if (!text.toLowerCase) {
358
+ if (text.props) {
359
+ isSimpleText = false;
360
+ justText = getStringFromReactComponent(text);
361
+ } else {
362
+ return [];
363
+ }
364
+ }
365
+
366
+ if (
367
+ doesSearchValMatchText(
368
+ searchVal,
369
+ hiddenButSearchableText
370
+ ? `${justText} ${hiddenButSearchableText}`
371
+ : justText
372
+ )
373
+ ) {
374
+ return {
375
+ ...item,
376
+ justText,
377
+ isSimpleText
378
+ };
379
+ } else {
380
+ return [];
381
+ }
382
+ }).sort((a, b) => a.justText.length - b.justText.length);
383
+
384
+ return take(newItems, 10).map(i => ({
385
+ ...i,
386
+ justText: highlight(searchVal, i.justText)
387
+ }));
388
+ };
389
+
390
+ const menuSearchHotkey = "meta+/";
391
+
392
+ function highlight(query, text, opts) {
393
+ opts = opts || { tag: <strong /> };
394
+
395
+ if (query.length === 0) {
396
+ return text;
397
+ }
398
+
399
+ const offset = text.toLowerCase().indexOf(query[0].toLowerCase());
400
+ if (offset === -1) return text;
401
+
402
+ let last = 0;
403
+ for (let i = 1; i < query.length; i++) {
404
+ if (text[offset + i] !== query[i]) {
405
+ break;
406
+ }
407
+
408
+ last = i;
409
+ }
410
+
411
+ const before = text.slice(0, offset);
412
+ const match = <strong>{text.slice(offset, offset + last + 1)}</strong>;
413
+
414
+ const after = highlight(
415
+ query.slice(last + 1),
416
+ text.slice(offset + last + 1),
417
+ opts
418
+ );
419
+
420
+ return flatten([before, match, after]);
421
+ }
422
+
423
+ export default MenuBar;
@@ -0,0 +1,45 @@
1
+ .tg-menu-bar {
2
+ /* background: white; */
3
+ color: inherit;
4
+ text-decoration: none;
5
+ z-index: 19;
6
+ display: flex;
7
+ justify-content: flex-start;
8
+ align-items: center;
9
+ height: 34px;
10
+ width: 100%;
11
+ padding-left: 15px;
12
+ }
13
+
14
+ .tg-menu-bar-item {
15
+ margin: 2px;
16
+ }
17
+
18
+ .tg-menu-bar .bp3-popover {
19
+ margin-top: -1px !important;
20
+ }
21
+
22
+ .tg-menu-bar-popover .bp3-popover .bp3-popover-arrow {
23
+ display: none;
24
+ }
25
+
26
+ /* removing the display inline styling because they broke menu positioning: https://github.com/TeselaGen/lims/issues/2563 */
27
+ /* .tg-menu-bar-popover .bp3-popover-wrapper {
28
+ display: inline;
29
+ }
30
+ .tg-menu-search-suggestions .bp3-popover-wrapper {
31
+ display: inline;
32
+ } */
33
+ /* add a fix here that applies the above logic to only the first child of the menu */
34
+ .tg-menu-search-suggestions .bp3-menu > .bp3-popover-wrapper {
35
+ display: inline;
36
+ }
37
+
38
+ li.bp3-menu-divider + li.bp3-menu-divider,
39
+ li.bp3-menu-divider:first-child,
40
+ li.bp3-menu-divider:last-child {
41
+ display: none;
42
+ }
43
+ .tg_search_highlight {
44
+ font-weight: bold;
45
+ }
@@ -0,0 +1,38 @@
1
+ /* Copyright (C) 2018 TeselaGen Biotechnology, Inc. */
2
+
3
+ import React, { useEffect } from "react";
4
+ import { Prompt } from "react-router-dom";
5
+
6
+ export const defaultMessagge =
7
+ "Are you sure you want to leave? There are unsaved changes.";
8
+
9
+ const warnBeforeLeave = e => {
10
+ // if we are in a cypress test run then we don't want to block navigation
11
+ if (window.Cypress) {
12
+ return null;
13
+ }
14
+
15
+ // Maintains older browser compatibility. In newer versions a generic string is returned
16
+ (e || window.event).returnValue = defaultMessagge; //Gecko + IE
17
+ return defaultMessagge; //Webkit, Safari, Chrome
18
+ };
19
+
20
+ export function PromptUnsavedChanges({
21
+ message = defaultMessagge,
22
+ when = false
23
+ }) {
24
+ useEffect(() => {
25
+ if (when) {
26
+ window.addEventListener("beforeunload", warnBeforeLeave);
27
+ }
28
+ return () => window.removeEventListener("beforeunload", warnBeforeLeave);
29
+ });
30
+
31
+ if (window.Cypress) {
32
+ return null;
33
+ }
34
+
35
+ return <Prompt when={when} message={message} />;
36
+ }
37
+
38
+ export default PromptUnsavedChanges;
@@ -0,0 +1,141 @@
1
+ import React from "react";
2
+ import { Dialog, Classes } from "@blueprintjs/core";
3
+ import { Rnd } from "react-rnd";
4
+ import { debounce } from "lodash-es";
5
+ import "./style.css";
6
+
7
+ const defaultDialogWidth = 400;
8
+ const defaultDialogHeight = 100;
9
+ export default class ResizableDraggableDialog extends React.Component {
10
+ componentDidMount() {
11
+ window.addEventListener("resize", this.onWindowResize);
12
+ this.setDefaults();
13
+ setTimeout(() => {
14
+ this.setDefaults();
15
+ try {
16
+ const el = this.containerEl.querySelector(".bp3-dialog-body");
17
+ this.resizeObs = new ResizeObserver(
18
+ debounce(() => {
19
+ this.setDefaults({ doNotSetXOrWidth: true });
20
+ })
21
+ );
22
+ this.resizeObs.observe(el);
23
+ } catch (e) {
24
+ console.warn(
25
+ `1214124599 Error setting up resize observer on dialog :`,
26
+ e
27
+ );
28
+ }
29
+ }, 0);
30
+ }
31
+ state = {
32
+ x: 0,
33
+ y: 0,
34
+ width: defaultDialogWidth,
35
+ height: defaultDialogHeight
36
+ };
37
+
38
+ setDefaults = ({ doNotSetXOrWidth } = {}) => {
39
+ const { width, height } = this.props;
40
+ const { windowWidth, windowHeight } = this.getWindowWidthAndHeight();
41
+
42
+ let heightToUse;
43
+ if (height) {
44
+ heightToUse = height;
45
+ } else {
46
+ heightToUse = (document.querySelector(".bp3-dialog-body") || {})
47
+ .scrollHeight;
48
+ if (heightToUse) {
49
+ heightToUse = heightToUse + 60;
50
+ } else {
51
+ heightToUse = defaultDialogHeight;
52
+ }
53
+ }
54
+ let widthToUse;
55
+ if (width) {
56
+ widthToUse = width;
57
+ } else {
58
+ widthToUse = defaultDialogWidth;
59
+ }
60
+
61
+ this.setState({
62
+ ...(doNotSetXOrWidth
63
+ ? {}
64
+ : {
65
+ x: Math.round(Math.max((windowWidth - widthToUse) / 2, 0)),
66
+ width: Math.min(widthToUse, windowWidth)
67
+ }),
68
+ y: Math.round(Math.max((windowHeight - heightToUse) / 2, 0)),
69
+ height: Math.min(Math.max(defaultDialogHeight, heightToUse), windowHeight)
70
+ });
71
+ };
72
+ onWindowResize = () => {
73
+ this.setDefaults();
74
+ };
75
+ componentWillUnmount() {
76
+ this.resizeObs && this.resizeObs.disconnect();
77
+ window.removeEventListener("resize", this.onWindowResize);
78
+ }
79
+
80
+ getWindowWidthAndHeight = () => {
81
+ const w = window,
82
+ d = document,
83
+ e = d.documentElement,
84
+ g = d.getElementsByTagName("body")[0],
85
+ windowWidth = w.innerWidth || e.clientWidth || g.clientWidth,
86
+ windowHeight = w.innerHeight || e.clientHeight || g.clientHeight;
87
+ return {
88
+ windowWidth,
89
+ windowHeight: windowHeight - 20 //add a small correction here
90
+ };
91
+ };
92
+
93
+ render() {
94
+ const { width, height, RndProps, ...rest } = this.props;
95
+ const { windowWidth, windowHeight } = this.getWindowWidthAndHeight();
96
+ return (
97
+ <div
98
+ ref={el => {
99
+ if (el) this.containerEl = el;
100
+ }}
101
+ className="tg-bp3-dialog-resizable-draggable"
102
+ style={{ top: 0, left: 0, position: "fixed" }}
103
+ >
104
+ <Rnd
105
+ cancel=".bp3-dialog-close-button"
106
+ enableResizing={{
107
+ bottomLeft: true,
108
+ bottomRight: true,
109
+ topLeft: true,
110
+ topRight: true
111
+ }}
112
+ maxHeight={windowHeight}
113
+ maxWidth={windowWidth}
114
+ bounds="window"
115
+ size={{ width: this.state.width, height: this.state.height }}
116
+ position={{ x: this.state.x, y: this.state.y }}
117
+ onDragStop={(e, d) => {
118
+ this.setState({ x: d.x, y: d.y });
119
+ }}
120
+ onResizeStop={(e, direction, ref, delta, position) => {
121
+ this.setState({
122
+ width: ref.style.width,
123
+ height: ref.style.height,
124
+ ...position
125
+ });
126
+ }}
127
+ dragHandleClassName={Classes.DIALOG_HEADER}
128
+ {...RndProps}
129
+ >
130
+ <Dialog
131
+ enforceFocus={false}
132
+ hasBackdrop={false}
133
+ usePortal={false}
134
+ canEscapeKeyClose={true}
135
+ {...rest}
136
+ />
137
+ </Rnd>
138
+ </div>
139
+ );
140
+ }
141
+ }
@@ -0,0 +1,42 @@
1
+ .tg-bp3-dialog-resizable-draggable {
2
+ z-index: 40000; /* necessary for open-vector-editor */
3
+ }
4
+ .tg-bp3-dialog-resizable-draggable
5
+ .bp3-overlay.bp3-overlay-scroll-container.bp3-overlay-inline {
6
+ position: static;
7
+ height: 100%;
8
+ width: 100%;
9
+ }
10
+
11
+ .tg-bp3-dialog-resizable-draggable .bp3-overlay-inline .bp3-overlay-content,
12
+ .tg-bp3-dialog-resizable-draggable
13
+ .bp3-overlay-scroll-container
14
+ .bp3-overlay-content {
15
+ position: static;
16
+ width: 100%;
17
+ height: 100%;
18
+ }
19
+ .tg-bp3-dialog-resizable-draggable .bp3-dialog-container .bp3-dialog {
20
+ position: absolute;
21
+ top: 0;
22
+ width: 100%;
23
+ /* height: 100%; */
24
+ max-height: 100%;
25
+ /* height: -webkit-fill-available; */
26
+ margin: 0 !important;
27
+ }
28
+ .tg-bp3-dialog-resizable-draggable .bp3-dialog-header {
29
+ cursor: move;
30
+ }
31
+ .tg-bp3-dialog-resizable-draggable .bp3-dialog-body {
32
+ height: 100%;
33
+ width: 100%;
34
+ width: stretch;
35
+ overflow: auto;
36
+ margin: 0px;
37
+ padding: 20px;
38
+ padding-bottom: 0px;
39
+ }
40
+ .tg-bp3-dialog-resizable-draggable .bp3-overlay-backdrop {
41
+ display: none;
42
+ }