@haniffalab/cherita-react 1.2.0 → 1.3.0-dev.2025-05-28.9afc380f

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 (91) hide show
  1. package/dist/cjs/components/controls/Controls.js +60 -0
  2. package/dist/cjs/components/dotplot/Dotplot.js +47 -38
  3. package/dist/cjs/components/dotplot/DotplotControls.js +77 -114
  4. package/dist/cjs/components/full-page/FullPage.js +29 -33
  5. package/dist/cjs/components/full-page/FullPagePseudospatial.js +30 -33
  6. package/dist/cjs/components/heatmap/Heatmap.js +33 -22
  7. package/dist/cjs/components/heatmap/HeatmapControls.js +2 -19
  8. package/dist/cjs/components/matrixplot/Matrixplot.js +35 -24
  9. package/dist/cjs/components/matrixplot/MatrixplotControls.js +4 -34
  10. package/dist/cjs/components/obs-list/ObsItem.js +63 -51
  11. package/dist/cjs/components/obs-list/ObsList.js +53 -48
  12. package/dist/cjs/components/obsm-list/ObsmList.js +17 -12
  13. package/dist/cjs/components/offcanvas/index.js +14 -11
  14. package/dist/cjs/components/pseudospatial/Pseudospatial.js +78 -68
  15. package/dist/cjs/components/pseudospatial/PseudospatialToolbar.js +27 -21
  16. package/dist/cjs/components/scatterplot/Scatterplot.js +82 -76
  17. package/dist/cjs/components/scatterplot/ScatterplotControls.js +18 -31
  18. package/dist/cjs/components/scatterplot/SpatialControls.js +53 -23
  19. package/dist/cjs/components/scatterplot/Toolbox.js +1 -18
  20. package/dist/cjs/components/search-bar/SearchBar.js +156 -59
  21. package/dist/cjs/components/search-bar/SearchInfo.js +182 -0
  22. package/dist/cjs/components/search-bar/SearchResults.js +90 -60
  23. package/dist/cjs/components/var-list/VarItem.js +52 -75
  24. package/dist/cjs/components/var-list/VarList.js +47 -172
  25. package/dist/cjs/components/var-list/VarListToolbar.js +7 -8
  26. package/dist/cjs/components/var-list/VarSet.js +66 -57
  27. package/dist/cjs/components/violin/Violin.js +54 -43
  28. package/dist/cjs/components/violin/ViolinControls.js +4 -20
  29. package/dist/cjs/context/DatasetContext.js +26 -513
  30. package/dist/cjs/context/FilterContext.js +9 -8
  31. package/dist/cjs/context/SettingsContext.js +539 -0
  32. package/dist/cjs/context/ZarrDataContext.js +1 -2
  33. package/dist/cjs/helpers/color-helper.js +8 -8
  34. package/dist/cjs/helpers/zarr-helper.js +19 -16
  35. package/dist/cjs/utils/Filter.js +25 -21
  36. package/dist/cjs/utils/Histogram.js +4 -3
  37. package/dist/cjs/utils/ImageViewer.js +1 -2
  38. package/dist/cjs/utils/Legend.js +18 -12
  39. package/dist/cjs/utils/LoadingIndicators.js +1 -1
  40. package/dist/cjs/utils/VirtualizedList.js +16 -13
  41. package/dist/cjs/utils/errors.js +20 -22
  42. package/dist/cjs/utils/requests.js +13 -10
  43. package/dist/cjs/utils/zarrData.js +31 -50
  44. package/dist/css/cherita.css +84 -24
  45. package/dist/css/cherita.css.map +1 -1
  46. package/dist/esm/components/controls/Controls.js +51 -0
  47. package/dist/esm/components/dotplot/Dotplot.js +47 -37
  48. package/dist/esm/components/dotplot/DotplotControls.js +77 -112
  49. package/dist/esm/components/full-page/FullPage.js +29 -32
  50. package/dist/esm/components/full-page/FullPagePseudospatial.js +30 -32
  51. package/dist/esm/components/heatmap/Heatmap.js +32 -20
  52. package/dist/esm/components/heatmap/HeatmapControls.js +3 -20
  53. package/dist/esm/components/matrixplot/Matrixplot.js +34 -22
  54. package/dist/esm/components/matrixplot/MatrixplotControls.js +5 -35
  55. package/dist/esm/components/obs-list/ObsItem.js +63 -49
  56. package/dist/esm/components/obs-list/ObsList.js +53 -47
  57. package/dist/esm/components/obsm-list/ObsmList.js +17 -11
  58. package/dist/esm/components/offcanvas/index.js +14 -11
  59. package/dist/esm/components/pseudospatial/Pseudospatial.js +77 -66
  60. package/dist/esm/components/pseudospatial/PseudospatialToolbar.js +27 -20
  61. package/dist/esm/components/scatterplot/Scatterplot.js +81 -74
  62. package/dist/esm/components/scatterplot/ScatterplotControls.js +18 -29
  63. package/dist/esm/components/scatterplot/SpatialControls.js +54 -23
  64. package/dist/esm/components/scatterplot/Toolbox.js +1 -18
  65. package/dist/esm/components/search-bar/SearchBar.js +156 -59
  66. package/dist/esm/components/search-bar/SearchInfo.js +173 -0
  67. package/dist/esm/components/search-bar/SearchResults.js +91 -60
  68. package/dist/esm/components/var-list/VarItem.js +53 -76
  69. package/dist/esm/components/var-list/VarList.js +47 -171
  70. package/dist/esm/components/var-list/VarListToolbar.js +6 -6
  71. package/dist/esm/components/var-list/VarSet.js +67 -57
  72. package/dist/esm/components/violin/Violin.js +53 -41
  73. package/dist/esm/components/violin/ViolinControls.js +5 -21
  74. package/dist/esm/context/DatasetContext.js +25 -510
  75. package/dist/esm/context/FilterContext.js +8 -6
  76. package/dist/esm/context/SettingsContext.js +528 -0
  77. package/dist/esm/helpers/color-helper.js +8 -8
  78. package/dist/esm/helpers/zarr-helper.js +19 -16
  79. package/dist/esm/utils/Filter.js +25 -21
  80. package/dist/esm/utils/Histogram.js +4 -3
  81. package/dist/esm/utils/Legend.js +17 -10
  82. package/dist/esm/utils/LoadingIndicators.js +1 -1
  83. package/dist/esm/utils/VirtualizedList.js +15 -11
  84. package/dist/esm/utils/errors.js +20 -22
  85. package/dist/esm/utils/requests.js +13 -10
  86. package/dist/esm/utils/zarrData.js +33 -51
  87. package/package.json +6 -3
  88. package/scss/cherita.scss +50 -9
  89. package/scss/components/layouts.scss +24 -13
  90. package/scss/components/lists.scss +10 -0
  91. package/scss/components/plots.scss +3 -5
@@ -1,15 +1,19 @@
1
1
  import React, { useState } from "react";
2
- import { faCrosshairs, faDrawPolygon, faHand, faMinus, faPen, faPlus, faSliders, faTrash } from "@fortawesome/free-solid-svg-icons";
2
+ import { faCrosshairs, faDrawPolygon, faHand, faList, faMinus, faPen, faPlus, faSearch, faSliders, faTrash } from "@fortawesome/free-solid-svg-icons";
3
3
  import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
4
4
  import { JoinInner } from "@mui/icons-material";
5
+ import useMediaQuery from "@mui/material/useMediaQuery";
5
6
  import { DrawLineStringMode, DrawPolygonByDraggingMode, DrawPolygonMode, DrawRectangleMode, ModifyMode, ViewMode } from "@nebula.gl/edit-modes";
7
+ import { OverlayTrigger, Tooltip } from "react-bootstrap";
6
8
  import Button from "react-bootstrap/Button";
7
9
  import ButtonGroup from "react-bootstrap/ButtonGroup";
8
10
  import Dropdown from "react-bootstrap/Dropdown";
9
- import { useDataset, useDatasetDispatch } from "../../context/DatasetContext";
11
+ import { useDataset } from "../../context/DatasetContext";
10
12
  import { OffcanvasControls } from "../offcanvas";
11
13
  import { ScatterplotControls } from "./ScatterplotControls";
14
+ import { useSettings, useSettingsDispatch } from "../../context/SettingsContext";
12
15
  export function SpatialControls(_ref) {
16
+ var _features$features;
13
17
  let {
14
18
  mode,
15
19
  setMode,
@@ -18,13 +22,20 @@ export function SpatialControls(_ref) {
18
22
  selectedFeatureIndexes,
19
23
  resetBounds,
20
24
  increaseZoom,
21
- decreaseZoom
25
+ decreaseZoom,
26
+ setShowObs,
27
+ setShowVars,
28
+ isFullscreen
22
29
  } = _ref;
23
- const dataset = useDataset();
24
- const dispatch = useDatasetDispatch();
30
+ const settings = useSettings();
31
+ const dispatch = useSettingsDispatch();
25
32
  const [showControls, setShowControls] = useState(false);
26
33
  const handleCloseControls = () => setShowControls(false);
27
34
  const handleShowControls = () => setShowControls(true);
35
+ const LgBreakpoint = useMediaQuery("(max-width: 991.98px)");
36
+ const XlBreakpoint = useMediaQuery("(max-width: 1199.98px)");
37
+ const showObsBtn = isFullscreen ? LgBreakpoint : true;
38
+ const showVarsBtn = isFullscreen ? XlBreakpoint : true;
28
39
  const onSelect = (eventKey, event) => {
29
40
  switch (eventKey) {
30
41
  case "DrawPolygonMode":
@@ -53,7 +64,7 @@ export function SpatialControls(_ref) {
53
64
  });
54
65
  };
55
66
  const polygonControls = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Button, {
56
- active: dataset.sliceBy.polygons,
67
+ active: settings.sliceBy.polygons,
57
68
  title: "Filter data with polygons",
58
69
  onClick: () => {
59
70
  setMode(() => ViewMode);
@@ -76,10 +87,37 @@ export function SpatialControls(_ref) {
76
87
  })));
77
88
  return /*#__PURE__*/React.createElement("div", {
78
89
  className: "cherita-spatial-controls"
79
- }, /*#__PURE__*/React.createElement(ButtonGroup, {
90
+ }, (showObsBtn || showVarsBtn) && /*#__PURE__*/React.createElement(ButtonGroup, {
80
91
  vertical: true,
81
92
  className: "w-100 mb-1"
93
+ }, showObsBtn && /*#__PURE__*/React.createElement(OverlayTrigger, {
94
+ placement: "right",
95
+ overlay: /*#__PURE__*/React.createElement(Tooltip, {
96
+ id: "tooltip-obs"
97
+ }, "Browse categories")
82
98
  }, /*#__PURE__*/React.createElement(Button, {
99
+ onClick: () => setShowObs(true)
100
+ }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
101
+ icon: faList
102
+ }))), showVarsBtn && /*#__PURE__*/React.createElement(OverlayTrigger, {
103
+ placement: "right",
104
+ overlay: /*#__PURE__*/React.createElement(Tooltip, {
105
+ id: "tooltip-vars"
106
+ }, "Search features")
107
+ }, /*#__PURE__*/React.createElement(Button, {
108
+ onClick: () => setShowVars(true)
109
+ }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
110
+ icon: faSearch
111
+ })))), /*#__PURE__*/React.createElement(ButtonGroup, {
112
+ vertical: true,
113
+ className: "w-100"
114
+ }, /*#__PURE__*/React.createElement(Button, {
115
+ onClick: () => setMode(() => ViewMode),
116
+ title: "Set dragging mode",
117
+ active: mode === ViewMode
118
+ }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
119
+ icon: faHand
120
+ })), /*#__PURE__*/React.createElement(Button, {
83
121
  onClick: increaseZoom,
84
122
  title: "Increase zoom"
85
123
  }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
@@ -89,24 +127,13 @@ export function SpatialControls(_ref) {
89
127
  title: "Decrease zoom"
90
128
  }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
91
129
  icon: faMinus
92
- })), /*#__PURE__*/React.createElement(Button, {
130
+ })), /*#__PURE__*/React.createElement("div", {
131
+ className: "border-bottom"
132
+ }), " ", /*#__PURE__*/React.createElement(Button, {
93
133
  onClick: resetBounds,
94
134
  title: "Reset zoom and center"
95
135
  }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
96
136
  icon: faCrosshairs
97
- })), /*#__PURE__*/React.createElement(Button, {
98
- onClick: handleShowControls
99
- }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
100
- icon: faSliders
101
- }))), /*#__PURE__*/React.createElement(ButtonGroup, {
102
- vertical: true,
103
- className: "w-100"
104
- }, /*#__PURE__*/React.createElement(Button, {
105
- onClick: () => setMode(() => ViewMode),
106
- title: "Set dragging mode",
107
- active: mode === ViewMode
108
- }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
109
- icon: faHand
110
137
  })), /*#__PURE__*/React.createElement(Dropdown, {
111
138
  as: ButtonGroup,
112
139
  className: "caret-off",
@@ -114,7 +141,7 @@ export function SpatialControls(_ref) {
114
141
  onSelect: onSelect
115
142
  }, /*#__PURE__*/React.createElement(Dropdown.Toggle, {
116
143
  id: "dropdown-autoclose-outside",
117
- className: `caret-off ${mode === DrawPolygonByDraggingMode || mode === ModifyMode ? "active" : ""}`
144
+ className: "caret-off ".concat(mode === DrawPolygonByDraggingMode || mode === ModifyMode ? "active" : "")
118
145
  }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
119
146
  icon: faDrawPolygon
120
147
  })), /*#__PURE__*/React.createElement(Dropdown.Menu, null, /*#__PURE__*/React.createElement(Dropdown.Header, null, "Polygon tools"), /*#__PURE__*/React.createElement(Dropdown.Item, {
@@ -132,7 +159,11 @@ export function SpatialControls(_ref) {
132
159
  }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
133
160
  icon: faTrash,
134
161
  className: "nav-icon"
135
- }), "Delete polygons"))), !!features?.features?.length && polygonControls), /*#__PURE__*/React.createElement(OffcanvasControls, {
162
+ }), "Delete polygons"))), !!(features !== null && features !== void 0 && (_features$features = features.features) !== null && _features$features !== void 0 && _features$features.length) && polygonControls, /*#__PURE__*/React.createElement(Button, {
163
+ onClick: handleShowControls
164
+ }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
165
+ icon: faSliders
166
+ }))), /*#__PURE__*/React.createElement(OffcanvasControls, {
136
167
  show: showControls,
137
168
  handleClose: handleCloseControls,
138
169
  Controls: ScatterplotControls
@@ -1,6 +1,4 @@
1
1
  import React from "react";
2
- import { faDroplet } from "@fortawesome/free-solid-svg-icons";
3
- import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
4
2
  import { Button, ButtonGroup, OverlayTrigger, Tooltip } from "react-bootstrap";
5
3
  import { formatNumerical } from "../../utils/string";
6
4
  import { ObsmKeysList } from "../obsm-list/ObsmList";
@@ -12,22 +10,7 @@ export function Toolbox(_ref) {
12
10
  } = _ref;
13
11
  return /*#__PURE__*/React.createElement("div", {
14
12
  className: "cherita-toolbox"
15
- }, /*#__PURE__*/React.createElement(ButtonGroup, null, /*#__PURE__*/React.createElement(ObsmKeysList, null), mode && /*#__PURE__*/React.createElement(OverlayTrigger, {
16
- placement: "top",
17
- overlay: /*#__PURE__*/React.createElement(Tooltip, {
18
- id: "tooltip-dropped-mode"
19
- }, "The color scale is currently set to ", mode)
20
- }, /*#__PURE__*/React.createElement(Button, {
21
- size: "sm",
22
- variant: "primary",
23
- style: {
24
- cursor: "default"
25
- },
26
- "aria-disabled": "true"
27
- }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
28
- icon: faDroplet,
29
- className: "me-1"
30
- }), " ", mode)), (mode || !isNaN(obsLength)) && (mode !== null && !isNaN(slicedLength) && slicedLength !== obsLength ? /*#__PURE__*/React.createElement(OverlayTrigger, {
13
+ }, /*#__PURE__*/React.createElement(ButtonGroup, null, /*#__PURE__*/React.createElement(ObsmKeysList, null), (mode || !isNaN(obsLength)) && (mode !== null && !isNaN(slicedLength) && slicedLength !== obsLength ? /*#__PURE__*/React.createElement(OverlayTrigger, {
31
14
  placement: "top",
32
15
  overlay: /*#__PURE__*/React.createElement(Tooltip, {
33
16
  id: "tooltip-dropped-mode"
@@ -1,8 +1,20 @@
1
- import React, { useEffect, useRef, useState } from "react";
1
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
2
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
3
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
4
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
5
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
6
+ import React, { useState } from "react";
7
+ import CloseIcon from "@mui/icons-material/Close";
2
8
  import SearchIcon from "@mui/icons-material/Search";
3
- import _ from "lodash";
4
- import { Dropdown, Form, FormGroup, InputGroup } from "react-bootstrap";
9
+ import { Button, Form, FormGroup, InputGroup, Modal } from "react-bootstrap";
10
+ import Col from "react-bootstrap/Col";
11
+ import Container from "react-bootstrap/Container";
12
+ import Nav from "react-bootstrap/Nav";
13
+ import Row from "react-bootstrap/Row";
14
+ import Tab from "react-bootstrap/Tab";
15
+ import { DiseaseInfo, VarInfo } from "./SearchInfo";
5
16
  import { DiseasesSearchResults, VarSearchResults } from "./SearchResults";
17
+ import { COLOR_ENCODINGS } from "../../constants/constants";
6
18
  function onVarSelect(dispatch, item) {
7
19
  dispatch({
8
20
  type: "select.var",
@@ -14,77 +26,162 @@ function onVarSelect(dispatch, item) {
14
26
  });
15
27
  dispatch({
16
28
  type: "set.colorEncoding",
17
- value: "var"
29
+ value: COLOR_ENCODINGS.VAR
18
30
  });
19
31
  }
20
- export function SearchBar(_ref) {
32
+ function addVarSet(dispatch, _ref) {
21
33
  let {
22
- searchVar = true,
23
- searchDiseases = false,
24
- handleSelect = onVarSelect
34
+ name,
35
+ vars
25
36
  } = _ref;
26
- const [showSuggestions, setShowSuggestions] = useState(false);
27
- const [text, setText] = useState("");
28
- const inputRef = useRef(null);
29
- const displayText = [...(searchVar ? ["features"] : []), ...(searchDiseases ? ["diseases"] : [])].join(" and ");
30
- useEffect(() => {
31
- if (text.length > 0) {
32
- setShowSuggestions(true);
37
+ dispatch({
38
+ type: "add.var",
39
+ var: {
40
+ name: name,
41
+ vars: vars,
42
+ isSet: true
33
43
  }
34
- }, [text]);
35
-
36
- //@TODO: Abstract styles
37
- return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Form, {
44
+ });
45
+ }
46
+ const FEATURE_TYPE = {
47
+ VAR: "var",
48
+ DISEASE: "disease"
49
+ };
50
+ export function SearchModal(_ref2) {
51
+ let {
52
+ show,
53
+ handleClose,
54
+ text,
55
+ setText,
56
+ displayText,
57
+ handleSelect = onVarSelect,
58
+ searchVar,
59
+ searchDiseases
60
+ } = _ref2;
61
+ const [tab, setTab] = useState("var");
62
+ const [selectedResult, setSelectedResult] = useState({
63
+ var: null,
64
+ disease: null
65
+ });
66
+ const [varResultsLength, setVarResultsLength] = useState(null);
67
+ const [diseaseResultsLength, setDiseaseResultsLength] = useState(null);
68
+ return /*#__PURE__*/React.createElement(Modal, {
69
+ show: show,
70
+ onHide: handleClose,
71
+ size: "xl"
72
+ }, /*#__PURE__*/React.createElement(Modal.Header, {
73
+ className: "bg-primary"
74
+ }, /*#__PURE__*/React.createElement(Container, {
75
+ className: "gx-0"
76
+ }, /*#__PURE__*/React.createElement(Row, null, /*#__PURE__*/React.createElement(Col, {
77
+ xs: 12
78
+ }, /*#__PURE__*/React.createElement(Form, {
38
79
  onSubmit: e => {
39
80
  e.preventDefault();
40
81
  }
41
- }, /*#__PURE__*/React.createElement(FormGroup, null, /*#__PURE__*/React.createElement(InputGroup, null, /*#__PURE__*/React.createElement(Form.Control, {
42
- ref: inputRef,
43
- onFocus: () => {
44
- setShowSuggestions(text.length > 0);
45
- },
46
- onBlur: () => {
47
- _.delay(() => {
48
- setShowSuggestions(false);
49
- }, 150);
50
- },
82
+ }, /*#__PURE__*/React.createElement(FormGroup, null, /*#__PURE__*/React.createElement("div", {
83
+ className: "d-flex align-items-center"
84
+ }, /*#__PURE__*/React.createElement(InputGroup, null, /*#__PURE__*/React.createElement(InputGroup.Text, null, /*#__PURE__*/React.createElement(SearchIcon, null)), /*#__PURE__*/React.createElement(Form.Control, {
85
+ autoFocus: true,
51
86
  type: "text",
52
87
  placeholder: "Search " + displayText,
53
88
  value: text,
54
89
  onChange: e => {
55
90
  setText(e.target.value);
56
- },
57
- style: {
58
- paddingLeft: "2.5rem",
59
- borderRadius: "5px"
91
+ setSelectedResult({
92
+ var: null,
93
+ disease: null
94
+ });
95
+ setVarResultsLength(null);
96
+ setDiseaseResultsLength(null);
60
97
  }
61
- }), /*#__PURE__*/React.createElement("div", {
62
- style: {
63
- position: "absolute",
64
- left: "10px",
65
- top: "50%",
66
- transform: "translateY(-50%)",
67
- pointerEvents: "none",
68
- zIndex: 10
69
- }
70
- }, /*#__PURE__*/React.createElement(SearchIcon, null))), /*#__PURE__*/React.createElement(Dropdown, {
71
- show: showSuggestions,
72
- onMouseDown: e => {
98
+ }), /*#__PURE__*/React.createElement(Button, {
99
+ variant: "light",
100
+ onClick: handleClose
101
+ }, /*#__PURE__*/React.createElement(CloseIcon, null)))))))))), /*#__PURE__*/React.createElement(Modal.Body, {
102
+ className: "p-0"
103
+ }, /*#__PURE__*/React.createElement(Container, null, /*#__PURE__*/React.createElement(Row, null, /*#__PURE__*/React.createElement(Col, {
104
+ xs: 12,
105
+ md: 8
106
+ }, /*#__PURE__*/React.createElement(Tab.Container, {
107
+ activeKey: tab,
108
+ onSelect: k => setTab(k)
109
+ }, /*#__PURE__*/React.createElement(Row, {
110
+ className: "w-100"
111
+ }, /*#__PURE__*/React.createElement(Col, {
112
+ sm: 3,
113
+ className: "py-3 border-end"
114
+ }, /*#__PURE__*/React.createElement(Nav, {
115
+ variant: "pills",
116
+ className: "flex-column"
117
+ }, searchVar && /*#__PURE__*/React.createElement(Nav.Item, null, /*#__PURE__*/React.createElement(Nav.Link, {
118
+ eventKey: FEATURE_TYPE.VAR
119
+ }, "Genes", " ", !!varResultsLength && "(".concat(varResultsLength, ")"))), searchDiseases && /*#__PURE__*/React.createElement(Nav.Item, null, /*#__PURE__*/React.createElement(Nav.Link, {
120
+ eventKey: FEATURE_TYPE.DISEASE
121
+ }, "Diseases", " ", !!diseaseResultsLength && "(".concat(diseaseResultsLength, ")"))))), /*#__PURE__*/React.createElement(Col, {
122
+ sm: 9,
123
+ className: "py-3"
124
+ }, /*#__PURE__*/React.createElement(Tab.Content, null, searchVar && /*#__PURE__*/React.createElement(Tab.Pane, {
125
+ eventKey: FEATURE_TYPE.VAR
126
+ }, /*#__PURE__*/React.createElement(VarSearchResults, {
127
+ text: text,
128
+ handleSelect: handleSelect,
129
+ selectedResult: selectedResult.var,
130
+ setSelectedResult: item => setSelectedResult(prev => {
131
+ return _objectSpread(_objectSpread({}, prev), {}, {
132
+ var: item
133
+ });
134
+ }),
135
+ setResultsLength: setVarResultsLength
136
+ })), searchDiseases && /*#__PURE__*/React.createElement(Tab.Pane, {
137
+ eventKey: FEATURE_TYPE.DISEASE
138
+ }, /*#__PURE__*/React.createElement(DiseasesSearchResults, {
139
+ text: text,
140
+ selectedResult: selectedResult.disease,
141
+ setSelectedResult: item => setSelectedResult(prev => {
142
+ return _objectSpread(_objectSpread({}, prev), {}, {
143
+ disease: item
144
+ });
145
+ }),
146
+ setResultsLength: setDiseaseResultsLength
147
+ }))))))), /*#__PURE__*/React.createElement(Col, {
148
+ xs: 12,
149
+ md: 4,
150
+ className: "bg-light p-3 search-modal-info"
151
+ }, selectedResult[tab] ? tab === FEATURE_TYPE.DISEASE ? /*#__PURE__*/React.createElement(DiseaseInfo, {
152
+ disease: selectedResult.disease,
153
+ handleSelect: handleSelect,
154
+ addVarSet: addVarSet
155
+ }) : /*#__PURE__*/React.createElement(VarInfo, {
156
+ varItem: selectedResult.var
157
+ }) : /*#__PURE__*/React.createElement("div", {
158
+ className: "text-muted"
159
+ }, "No result selected"))))));
160
+ }
161
+ export function SearchBar(_ref3) {
162
+ let {
163
+ searchVar = true,
164
+ searchDiseases = false
165
+ } = _ref3;
166
+ const [text, setText] = useState("");
167
+ const displayText = [...(searchVar ? ["features"] : []), ...(searchDiseases ? ["diseases"] : [])].join(" and ");
168
+ const [showModal, setShowModal] = useState(false);
169
+ return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Form, {
170
+ onSubmit: e => {
73
171
  e.preventDefault();
74
- },
75
- onSelect: () => {
76
- inputRef.current.blur();
77
- }
78
- }, /*#__PURE__*/React.createElement(Dropdown.Menu, {
79
- style: {
80
- width: "90%"
81
172
  }
82
- }, searchVar && /*#__PURE__*/React.createElement(VarSearchResults, {
83
- text: text,
84
- setShowSuggestions: setShowSuggestions,
85
- handleSelect: handleSelect
86
- }), searchVar && searchDiseases && /*#__PURE__*/React.createElement(Dropdown.Divider, null), searchDiseases && /*#__PURE__*/React.createElement(DiseasesSearchResults, {
173
+ }, /*#__PURE__*/React.createElement(FormGroup, null, /*#__PURE__*/React.createElement(InputGroup, null, /*#__PURE__*/React.createElement(InputGroup.Text, null, /*#__PURE__*/React.createElement(SearchIcon, null)), /*#__PURE__*/React.createElement(Form.Control, {
174
+ onClick: () => setShowModal(true),
175
+ type: "text",
176
+ placeholder: "Search " + displayText,
177
+ defaultValue: text
178
+ })))), /*#__PURE__*/React.createElement(SearchModal, {
179
+ show: showModal,
87
180
  text: text,
88
- setShowSuggestions: setShowSuggestions
89
- }))))));
181
+ setText: setText,
182
+ displayText: displayText,
183
+ searchVar: searchVar,
184
+ searchDiseases: searchDiseases,
185
+ handleClose: () => setShowModal(false)
186
+ }));
90
187
  }
@@ -0,0 +1,173 @@
1
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
2
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
3
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
4
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
5
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
6
+ import React, { useState, useEffect } from "react";
7
+ import { faPlus } from "@fortawesome/free-solid-svg-icons";
8
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
9
+ import _ from "lodash";
10
+ import { Button, ListGroup } from "react-bootstrap";
11
+ import { VAR_SORT } from "../../constants/constants";
12
+ import { useDataset } from "../../context/DatasetContext";
13
+ import { useSettings, useSettingsDispatch } from "../../context/SettingsContext";
14
+ import { useFetch } from "../../utils/requests";
15
+ import { VarDiseaseInfo } from "../var-list/VarItem";
16
+ export function VarInfo(_ref) {
17
+ let {
18
+ varItem
19
+ } = _ref;
20
+ const ENDPOINT = "disease/gene";
21
+ const dataset = useDataset();
22
+ const [params, setParams] = useState({
23
+ geneName: varItem.name,
24
+ diseaseDatasets: dataset.diseaseDatasets
25
+ });
26
+ useEffect(() => {
27
+ setParams(p => {
28
+ return _objectSpread(_objectSpread({}, p), {}, {
29
+ geneName: varItem.name
30
+ });
31
+ });
32
+ }, [varItem.name]);
33
+ const {
34
+ fetchedData,
35
+ isPending,
36
+ serverError
37
+ } = useFetch(ENDPOINT, params, {
38
+ refetchOnMount: false,
39
+ enabled: !!dataset.diseaseDatasets.length
40
+ });
41
+ const hasDiseaseInfo = !isPending && !serverError && !!(fetchedData !== null && fetchedData !== void 0 && fetchedData.length);
42
+ return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("h5", null, varItem.name), !!dataset.diseaseDatasets.length && isPending && /*#__PURE__*/React.createElement("p", null, "Loading..."), hasDiseaseInfo && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("h6", null, "Associated diseases"), /*#__PURE__*/React.createElement(VarDiseaseInfo, {
43
+ data: fetchedData
44
+ })));
45
+ }
46
+ const useVarMean = function (varKeys) {
47
+ let enabled = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
48
+ const ENDPOINT = "matrix/mean";
49
+ const dataset = useDataset();
50
+ const [params, setParams] = useState({
51
+ url: dataset.url,
52
+ varKeys: _.map(varKeys, v => v.isSet ? {
53
+ name: v.name,
54
+ indices: v.vars.map(v => v.index)
55
+ } : v.index),
56
+ // obsIndices:
57
+ varNamesCol: dataset.varNamesCol
58
+ });
59
+ useEffect(() => {
60
+ setParams(p => {
61
+ return _objectSpread(_objectSpread({}, p), {}, {
62
+ varKeys: _.map(varKeys, v => v.isSet ? {
63
+ name: v.name,
64
+ indices: v.vars.map(v => v.index)
65
+ } : v.index)
66
+ });
67
+ });
68
+ }, [varKeys]);
69
+ return useFetch(ENDPOINT, params, {
70
+ enabled: enabled,
71
+ refetchOnMount: false
72
+ });
73
+ };
74
+
75
+ // ensure nulls are lowest values
76
+ const sortMeans = (i, means) => {
77
+ return means[i.name] || _.min(_.values(means)) - 1;
78
+ };
79
+ export function DiseaseInfo(_ref2) {
80
+ let {
81
+ disease,
82
+ handleSelect,
83
+ addVarSet
84
+ } = _ref2;
85
+ const ENDPOINT = "disease/genes";
86
+ const dataset = useDataset();
87
+ const settings = useSettings();
88
+ const dispatch = useSettingsDispatch();
89
+ const [diseaseVars, setDiseaseVars] = useState([]);
90
+ const [sortedDiseaseVars, setSortedDiseaseVars] = useState([]);
91
+ const [params, setParams] = useState({
92
+ url: dataset.url,
93
+ col: dataset.varNamesCol,
94
+ diseaseDatasets: dataset.diseaseDatasets,
95
+ diseaseId: disease.id
96
+ });
97
+ useEffect(() => {
98
+ setParams(p => {
99
+ return _objectSpread(_objectSpread({}, p), {}, {
100
+ diseaseId: disease.id
101
+ });
102
+ });
103
+ }, [disease]);
104
+ const diseaseData = useFetch(ENDPOINT, params, {
105
+ enabled: !!params.diseaseId,
106
+ refetchOnMount: true
107
+ });
108
+ useEffect(() => {
109
+ if (!diseaseData.isPending && !diseaseData.serverError) {
110
+ setDiseaseVars(diseaseData.fetchedData);
111
+ }
112
+ }, [diseaseData.fetchedData, diseaseData.isPending, diseaseData.serverError]);
113
+ const varMeans = useVarMean(diseaseVars, !!(diseaseVars !== null && diseaseVars !== void 0 && diseaseVars.length) && settings.varSort.disease.sort === VAR_SORT.MATRIX);
114
+ useEffect(() => {
115
+ if (settings.varSort.disease.sort === VAR_SORT.MATRIX) {
116
+ if (!varMeans.isPending && !varMeans.serverError) {
117
+ setSortedDiseaseVars(_.orderBy(diseaseVars, o => {
118
+ return sortMeans(o, varMeans.fetchedData);
119
+ }, settings.varSort.disease.sortOrder));
120
+ }
121
+ } else if (settings.varSort.disease.sort === VAR_SORT.NAME) {
122
+ setSortedDiseaseVars(_.orderBy(diseaseVars, "name", settings.varSort.disease.sortOrder));
123
+ } else {
124
+ setSortedDiseaseVars(diseaseVars);
125
+ }
126
+ }, [settings.varSort.disease.sort, settings.varSort.disease.sortOrder, diseaseVars, varMeans.fetchedData, varMeans.isPending, varMeans.serverError]);
127
+ const diseaseVarList = _.map(sortedDiseaseVars, v => {
128
+ return /*#__PURE__*/React.createElement(ListGroup.Item, {
129
+ key: v.gene_id
130
+ }, /*#__PURE__*/React.createElement("div", {
131
+ className: "d-flex justify-content-between align-items-center w-100"
132
+ }, v.name, /*#__PURE__*/React.createElement("div", {
133
+ className: "d-flex align-items-center gap-1"
134
+ }, /*#__PURE__*/React.createElement(Button, {
135
+ type: "button",
136
+ className: "m-0 p-0 px-1",
137
+ variant: "outline-secondary",
138
+ title: "Add to list",
139
+ onClick: () => {
140
+ handleSelect(dispatch, {
141
+ name: v.name,
142
+ index: v.index,
143
+ matrix_index: v.matrix_index
144
+ });
145
+ }
146
+ }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
147
+ icon: faPlus
148
+ })))));
149
+ });
150
+ const isPending = diseaseData.isPending || varMeans.isPending && settings.varSort.disease.sort === VAR_SORT.MATRIX;
151
+ return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("h5", null, disease.disease_name), /*#__PURE__*/React.createElement("h6", null, "Implicated genes"), isPending ? /*#__PURE__*/React.createElement("p", null, "Loading...") : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
152
+ className: "d-flex justify-content-end mb-2"
153
+ }, /*#__PURE__*/React.createElement(Button, {
154
+ size: "sm",
155
+ title: "Add all as a set",
156
+ onClick: () => {
157
+ addVarSet(dispatch, {
158
+ name: disease.disease_name,
159
+ vars: _.map(diseaseVars, v => {
160
+ return {
161
+ index: v.index,
162
+ name: v.name,
163
+ matrix_index: v.matrix_index
164
+ };
165
+ })
166
+ });
167
+ }
168
+ }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
169
+ icon: faPlus
170
+ }), " Add all as a set")), /*#__PURE__*/React.createElement(ListGroup, {
171
+ className: "overflow-scroll"
172
+ }, diseaseVarList)));
173
+ }