@haniffalab/cherita-react 1.2.0-dev.2025-04-29.181538d6 → 1.2.0-dev.2025-05-16.4367ee63

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 (33) hide show
  1. package/dist/cjs/components/full-page/FullPage.js +19 -26
  2. package/dist/cjs/components/full-page/FullPagePseudospatial.js +20 -26
  3. package/dist/cjs/components/offcanvas/index.js +1 -2
  4. package/dist/cjs/components/scatterplot/Scatterplot.js +8 -2
  5. package/dist/cjs/components/scatterplot/SpatialControls.js +46 -17
  6. package/dist/cjs/components/scatterplot/Toolbox.js +1 -18
  7. package/dist/cjs/components/search-bar/SearchBar.js +152 -57
  8. package/dist/cjs/components/search-bar/SearchInfo.js +175 -0
  9. package/dist/cjs/components/search-bar/SearchResults.js +58 -33
  10. package/dist/cjs/components/var-list/VarItem.js +70 -0
  11. package/dist/cjs/components/var-list/VarList.js +7 -91
  12. package/dist/cjs/components/var-list/VarSet.js +42 -16
  13. package/dist/cjs/utils/Legend.js +14 -8
  14. package/dist/css/cherita.css +60 -10
  15. package/dist/css/cherita.css.map +1 -1
  16. package/dist/esm/components/full-page/FullPage.js +20 -27
  17. package/dist/esm/components/full-page/FullPagePseudospatial.js +21 -27
  18. package/dist/esm/components/offcanvas/index.js +1 -2
  19. package/dist/esm/components/scatterplot/Scatterplot.js +8 -2
  20. package/dist/esm/components/scatterplot/SpatialControls.js +47 -18
  21. package/dist/esm/components/scatterplot/Toolbox.js +1 -18
  22. package/dist/esm/components/search-bar/SearchBar.js +153 -59
  23. package/dist/esm/components/search-bar/SearchInfo.js +165 -0
  24. package/dist/esm/components/search-bar/SearchResults.js +60 -35
  25. package/dist/esm/components/var-list/VarItem.js +70 -2
  26. package/dist/esm/components/var-list/VarList.js +7 -91
  27. package/dist/esm/components/var-list/VarSet.js +44 -18
  28. package/dist/esm/utils/Legend.js +14 -8
  29. package/package.json +2 -2
  30. package/scss/cherita.scss +44 -5
  31. package/scss/components/layouts.scss +20 -13
  32. package/scss/components/lists.scss +11 -0
  33. package/scss/components/plots.scss +3 -5
@@ -1,8 +1,10 @@
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";
@@ -18,13 +20,20 @@ export function SpatialControls(_ref) {
18
20
  selectedFeatureIndexes,
19
21
  resetBounds,
20
22
  increaseZoom,
21
- decreaseZoom
23
+ decreaseZoom,
24
+ setShowObs,
25
+ setShowVars,
26
+ isFullscreen
22
27
  } = _ref;
23
28
  const dataset = useDataset();
24
29
  const dispatch = useDatasetDispatch();
25
30
  const [showControls, setShowControls] = useState(false);
26
31
  const handleCloseControls = () => setShowControls(false);
27
32
  const handleShowControls = () => setShowControls(true);
33
+ const LgBreakpoint = useMediaQuery("(max-width: 991.98px)");
34
+ const XlBreakpoint = useMediaQuery("(max-width: 1199.98px)");
35
+ const showObsBtn = isFullscreen ? LgBreakpoint : true;
36
+ const showVarsBtn = isFullscreen ? XlBreakpoint : true;
28
37
  const onSelect = (eventKey, event) => {
29
38
  switch (eventKey) {
30
39
  case "DrawPolygonMode":
@@ -76,10 +85,37 @@ export function SpatialControls(_ref) {
76
85
  })));
77
86
  return /*#__PURE__*/React.createElement("div", {
78
87
  className: "cherita-spatial-controls"
79
- }, /*#__PURE__*/React.createElement(ButtonGroup, {
88
+ }, (showObsBtn || showVarsBtn) && /*#__PURE__*/React.createElement(ButtonGroup, {
80
89
  vertical: true,
81
90
  className: "w-100 mb-1"
91
+ }, showObsBtn && /*#__PURE__*/React.createElement(OverlayTrigger, {
92
+ placement: "right",
93
+ overlay: /*#__PURE__*/React.createElement(Tooltip, {
94
+ id: "tooltip-obs"
95
+ }, "Browse categories")
82
96
  }, /*#__PURE__*/React.createElement(Button, {
97
+ onClick: () => setShowObs(true)
98
+ }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
99
+ icon: faList
100
+ }))), showVarsBtn && /*#__PURE__*/React.createElement(OverlayTrigger, {
101
+ placement: "right",
102
+ overlay: /*#__PURE__*/React.createElement(Tooltip, {
103
+ id: "tooltip-vars"
104
+ }, "Search features")
105
+ }, /*#__PURE__*/React.createElement(Button, {
106
+ onClick: () => setShowVars(true)
107
+ }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
108
+ icon: faSearch
109
+ })))), /*#__PURE__*/React.createElement(ButtonGroup, {
110
+ vertical: true,
111
+ className: "w-100"
112
+ }, /*#__PURE__*/React.createElement(Button, {
113
+ onClick: () => setMode(() => ViewMode),
114
+ title: "Set dragging mode",
115
+ active: mode === ViewMode
116
+ }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
117
+ icon: faHand
118
+ })), /*#__PURE__*/React.createElement(Button, {
83
119
  onClick: increaseZoom,
84
120
  title: "Increase zoom"
85
121
  }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
@@ -89,24 +125,13 @@ export function SpatialControls(_ref) {
89
125
  title: "Decrease zoom"
90
126
  }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
91
127
  icon: faMinus
92
- })), /*#__PURE__*/React.createElement(Button, {
128
+ })), /*#__PURE__*/React.createElement("div", {
129
+ className: "border-bottom"
130
+ }), " ", /*#__PURE__*/React.createElement(Button, {
93
131
  onClick: resetBounds,
94
132
  title: "Reset zoom and center"
95
133
  }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
96
134
  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
135
  })), /*#__PURE__*/React.createElement(Dropdown, {
111
136
  as: ButtonGroup,
112
137
  className: "caret-off",
@@ -132,7 +157,11 @@ export function SpatialControls(_ref) {
132
157
  }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
133
158
  icon: faTrash,
134
159
  className: "nav-icon"
135
- }), "Delete polygons"))), !!features?.features?.length && polygonControls), /*#__PURE__*/React.createElement(OffcanvasControls, {
160
+ }), "Delete polygons"))), !!features?.features?.length && polygonControls, /*#__PURE__*/React.createElement(Button, {
161
+ onClick: handleShowControls
162
+ }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
163
+ icon: faSliders
164
+ }))), /*#__PURE__*/React.createElement(OffcanvasControls, {
136
165
  show: showControls,
137
166
  handleClose: handleCloseControls,
138
167
  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,15 @@
1
- import React, { useEffect, useRef, useState } from "react";
1
+ import React, { useState } from "react";
2
+ import CloseIcon from "@mui/icons-material/Close";
2
3
  import SearchIcon from "@mui/icons-material/Search";
3
- import _ from "lodash";
4
- import { Dropdown, Form, FormGroup, InputGroup } from "react-bootstrap";
4
+ import { Button, Form, FormGroup, InputGroup, Modal } from "react-bootstrap";
5
+ import Col from "react-bootstrap/Col";
6
+ import Container from "react-bootstrap/Container";
7
+ import Nav from "react-bootstrap/Nav";
8
+ import Row from "react-bootstrap/Row";
9
+ import Tab from "react-bootstrap/Tab";
10
+ import { DiseaseInfo, VarInfo } from "./SearchInfo";
5
11
  import { DiseasesSearchResults, VarSearchResults } from "./SearchResults";
12
+ import { COLOR_ENCODINGS } from "../../constants/constants";
6
13
  function onVarSelect(dispatch, item) {
7
14
  dispatch({
8
15
  type: "select.var",
@@ -14,77 +21,164 @@ function onVarSelect(dispatch, item) {
14
21
  });
15
22
  dispatch({
16
23
  type: "set.colorEncoding",
17
- value: "var"
24
+ value: COLOR_ENCODINGS.VAR
18
25
  });
19
26
  }
20
- export function SearchBar(_ref) {
27
+ function addVarSet(dispatch, _ref) {
21
28
  let {
22
- searchVar = true,
23
- searchDiseases = false,
24
- handleSelect = onVarSelect
29
+ name,
30
+ vars
25
31
  } = _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);
32
+ dispatch({
33
+ type: "add.varSet",
34
+ varSet: {
35
+ name: name,
36
+ vars: vars,
37
+ isSet: true
33
38
  }
34
- }, [text]);
35
-
36
- //@TODO: Abstract styles
37
- return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Form, {
39
+ });
40
+ }
41
+ const FEATURE_TYPE = {
42
+ VAR: "var",
43
+ DISEASE: "disease"
44
+ };
45
+ export function SearchModal(_ref2) {
46
+ let {
47
+ show,
48
+ handleClose,
49
+ text,
50
+ setText,
51
+ displayText,
52
+ handleSelect = onVarSelect,
53
+ searchVar,
54
+ searchDiseases
55
+ } = _ref2;
56
+ const [tab, setTab] = useState("var");
57
+ const [selectedResult, setSelectedResult] = useState({
58
+ var: null,
59
+ disease: null
60
+ });
61
+ const [varResultsLength, setVarResultsLength] = useState(null);
62
+ const [diseaseResultsLength, setDiseaseResultsLength] = useState(null);
63
+ return /*#__PURE__*/React.createElement(Modal, {
64
+ show: show,
65
+ onHide: handleClose,
66
+ size: "xl"
67
+ }, /*#__PURE__*/React.createElement(Modal.Header, {
68
+ className: "bg-primary"
69
+ }, /*#__PURE__*/React.createElement(Container, {
70
+ className: "gx-0"
71
+ }, /*#__PURE__*/React.createElement(Row, null, /*#__PURE__*/React.createElement(Col, {
72
+ xs: 12
73
+ }, /*#__PURE__*/React.createElement(Form, {
38
74
  onSubmit: e => {
39
75
  e.preventDefault();
40
76
  }
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
- },
77
+ }, /*#__PURE__*/React.createElement(FormGroup, null, /*#__PURE__*/React.createElement("div", {
78
+ className: "d-flex align-items-center"
79
+ }, /*#__PURE__*/React.createElement(InputGroup, null, /*#__PURE__*/React.createElement(InputGroup.Text, null, /*#__PURE__*/React.createElement(SearchIcon, null)), /*#__PURE__*/React.createElement(Form.Control, {
80
+ autoFocus: true,
51
81
  type: "text",
52
82
  placeholder: "Search " + displayText,
53
83
  value: text,
54
84
  onChange: e => {
55
85
  setText(e.target.value);
56
- },
57
- style: {
58
- paddingLeft: "2.5rem",
59
- borderRadius: "5px"
86
+ setSelectedResult({
87
+ var: null,
88
+ disease: null
89
+ });
90
+ setVarResultsLength(null);
91
+ setDiseaseResultsLength(null);
60
92
  }
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 => {
93
+ }), /*#__PURE__*/React.createElement(Button, {
94
+ variant: "light",
95
+ onClick: handleClose
96
+ }, /*#__PURE__*/React.createElement(CloseIcon, null)))))))))), /*#__PURE__*/React.createElement(Modal.Body, {
97
+ className: "p-0"
98
+ }, /*#__PURE__*/React.createElement(Container, null, /*#__PURE__*/React.createElement(Row, null, /*#__PURE__*/React.createElement(Col, {
99
+ xs: 12,
100
+ md: 8
101
+ }, /*#__PURE__*/React.createElement(Tab.Container, {
102
+ activeKey: tab,
103
+ onSelect: k => setTab(k)
104
+ }, /*#__PURE__*/React.createElement(Row, {
105
+ className: "w-100"
106
+ }, /*#__PURE__*/React.createElement(Col, {
107
+ sm: 3,
108
+ className: "py-3 border-end"
109
+ }, /*#__PURE__*/React.createElement(Nav, {
110
+ variant: "pills",
111
+ className: "flex-column"
112
+ }, searchVar && /*#__PURE__*/React.createElement(Nav.Item, null, /*#__PURE__*/React.createElement(Nav.Link, {
113
+ eventKey: FEATURE_TYPE.VAR
114
+ }, "Genes", " ", !!varResultsLength && `(${varResultsLength})`)), searchDiseases && /*#__PURE__*/React.createElement(Nav.Item, null, /*#__PURE__*/React.createElement(Nav.Link, {
115
+ eventKey: FEATURE_TYPE.DISEASE
116
+ }, "Diseases", " ", !!diseaseResultsLength && `(${diseaseResultsLength})`)))), /*#__PURE__*/React.createElement(Col, {
117
+ sm: 9,
118
+ className: "py-3"
119
+ }, /*#__PURE__*/React.createElement(Tab.Content, null, searchVar && /*#__PURE__*/React.createElement(Tab.Pane, {
120
+ eventKey: FEATURE_TYPE.VAR
121
+ }, /*#__PURE__*/React.createElement(VarSearchResults, {
122
+ text: text,
123
+ handleSelect: handleSelect,
124
+ selectedResult: selectedResult.var,
125
+ setSelectedResult: item => setSelectedResult(prev => {
126
+ return {
127
+ ...prev,
128
+ var: item
129
+ };
130
+ }),
131
+ setResultsLength: setVarResultsLength
132
+ })), searchDiseases && /*#__PURE__*/React.createElement(Tab.Pane, {
133
+ eventKey: FEATURE_TYPE.DISEASE
134
+ }, /*#__PURE__*/React.createElement(DiseasesSearchResults, {
135
+ text: text,
136
+ selectedResult: selectedResult.disease,
137
+ setSelectedResult: item => setSelectedResult(prev => {
138
+ return {
139
+ ...prev,
140
+ disease: item
141
+ };
142
+ }),
143
+ setResultsLength: setDiseaseResultsLength
144
+ }))))))), /*#__PURE__*/React.createElement(Col, {
145
+ xs: 12,
146
+ md: 4,
147
+ className: "bg-light p-3 search-modal-info"
148
+ }, selectedResult[tab] ? tab === FEATURE_TYPE.DISEASE ? /*#__PURE__*/React.createElement(DiseaseInfo, {
149
+ disease: selectedResult.disease,
150
+ handleSelect: handleSelect,
151
+ addVarSet: addVarSet
152
+ }) : /*#__PURE__*/React.createElement(VarInfo, {
153
+ varItem: selectedResult.var
154
+ }) : /*#__PURE__*/React.createElement("div", {
155
+ className: "text-muted"
156
+ }, "No result selected"))))));
157
+ }
158
+ export function SearchBar(_ref3) {
159
+ let {
160
+ searchVar = true,
161
+ searchDiseases = false
162
+ } = _ref3;
163
+ const [text, setText] = useState("");
164
+ const displayText = [...(searchVar ? ["features"] : []), ...(searchDiseases ? ["diseases"] : [])].join(" and ");
165
+ const [showModal, setShowModal] = useState(false);
166
+ return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Form, {
167
+ onSubmit: e => {
73
168
  e.preventDefault();
74
- },
75
- onSelect: () => {
76
- inputRef.current.blur();
77
- }
78
- }, /*#__PURE__*/React.createElement(Dropdown.Menu, {
79
- style: {
80
- width: "90%"
81
169
  }
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, {
170
+ }, /*#__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, {
171
+ onClick: () => setShowModal(true),
172
+ type: "text",
173
+ placeholder: "Search " + displayText,
174
+ defaultValue: text
175
+ })))), /*#__PURE__*/React.createElement(SearchModal, {
176
+ show: showModal,
87
177
  text: text,
88
- setShowSuggestions: setShowSuggestions
89
- }))))));
178
+ setText: setText,
179
+ displayText: displayText,
180
+ searchVar: searchVar,
181
+ searchDiseases: searchDiseases,
182
+ handleClose: () => setShowModal(false)
183
+ }));
90
184
  }
@@ -0,0 +1,165 @@
1
+ import React, { useState, useEffect } from "react";
2
+ import { faPlus } from "@fortawesome/free-solid-svg-icons";
3
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
4
+ import _ from "lodash";
5
+ import { Button, ListGroup } from "react-bootstrap";
6
+ import { VAR_SORT } from "../../constants/constants";
7
+ import { useDataset, useDatasetDispatch } from "../../context/DatasetContext";
8
+ import { useFetch } from "../../utils/requests";
9
+ import { VarDiseaseInfo } from "../var-list/VarItem";
10
+ export function VarInfo(_ref) {
11
+ let {
12
+ varItem
13
+ } = _ref;
14
+ const ENDPOINT = "disease/gene";
15
+ const dataset = useDataset();
16
+ const [params, setParams] = useState({
17
+ geneName: varItem.name,
18
+ diseaseDatasets: dataset.diseaseDatasets
19
+ });
20
+ useEffect(() => {
21
+ setParams(p => {
22
+ return {
23
+ ...p,
24
+ geneName: varItem.name
25
+ };
26
+ });
27
+ }, [varItem.name]);
28
+ const {
29
+ fetchedData,
30
+ isPending,
31
+ serverError
32
+ } = useFetch(ENDPOINT, params, {
33
+ refetchOnMount: false,
34
+ enabled: !!dataset.diseaseDatasets.length
35
+ });
36
+ const hasDiseaseInfo = !isPending && !serverError && !!fetchedData?.length;
37
+ 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, {
38
+ data: fetchedData
39
+ })));
40
+ }
41
+ const useVarMean = function (varKeys) {
42
+ let enabled = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
43
+ const ENDPOINT = "matrix/mean";
44
+ const dataset = useDataset();
45
+ const [params, setParams] = useState({
46
+ url: dataset.url,
47
+ varKeys: _.map(varKeys, v => v.isSet ? {
48
+ name: v.name,
49
+ indices: v.vars.map(v => v.index)
50
+ } : v.index),
51
+ // obsIndices:
52
+ varNamesCol: dataset.varNamesCol
53
+ });
54
+ useEffect(() => {
55
+ setParams(p => {
56
+ return {
57
+ ...p,
58
+ varKeys: _.map(varKeys, v => v.isSet ? {
59
+ name: v.name,
60
+ indices: v.vars.map(v => v.index)
61
+ } : v.index)
62
+ };
63
+ });
64
+ }, [varKeys]);
65
+ return useFetch(ENDPOINT, params, {
66
+ enabled: enabled,
67
+ refetchOnMount: false
68
+ });
69
+ };
70
+
71
+ // ensure nulls are lowest values
72
+ const sortMeans = (i, means) => {
73
+ return means[i.name] || _.min(_.values(means)) - 1;
74
+ };
75
+ export function DiseaseInfo(_ref2) {
76
+ let {
77
+ disease,
78
+ handleSelect,
79
+ addVarSet
80
+ } = _ref2;
81
+ const ENDPOINT = "disease/genes";
82
+ const dataset = useDataset();
83
+ const dispatch = useDatasetDispatch();
84
+ const [diseaseVars, setDiseaseVars] = useState([]);
85
+ const [sortedDiseaseVars, setSortedDiseaseVars] = useState([]);
86
+ const [params, setParams] = useState({
87
+ url: dataset.url,
88
+ col: dataset.varNamesCol,
89
+ diseaseDatasets: dataset.diseaseDatasets,
90
+ diseaseId: disease.id
91
+ });
92
+ useEffect(() => {
93
+ setParams(p => {
94
+ return {
95
+ ...p,
96
+ diseaseId: disease.id
97
+ };
98
+ });
99
+ }, [disease]);
100
+ const diseaseData = useFetch(ENDPOINT, params, {
101
+ enabled: !!params.diseaseId,
102
+ refetchOnMount: true
103
+ });
104
+ useEffect(() => {
105
+ if (!diseaseData.isPending && !diseaseData.serverError) {
106
+ setDiseaseVars(diseaseData.fetchedData);
107
+ }
108
+ }, [diseaseData.fetchedData, diseaseData.isPending, diseaseData.serverError]);
109
+ const varMeans = useVarMean(diseaseVars, !!diseaseVars?.length && dataset.varSort.disease.sort === VAR_SORT.MATRIX);
110
+ useEffect(() => {
111
+ if (dataset.varSort.disease.sort === VAR_SORT.MATRIX) {
112
+ if (!varMeans.isPending && !varMeans.serverError) {
113
+ setSortedDiseaseVars(_.orderBy(diseaseVars, o => {
114
+ return sortMeans(o, varMeans.fetchedData);
115
+ }, dataset.varSort.disease.sortOrder));
116
+ }
117
+ } else if (dataset.varSort.disease.sort === VAR_SORT.NAME) {
118
+ setSortedDiseaseVars(_.orderBy(diseaseVars, "name", dataset.varSort.disease.sortOrder));
119
+ } else {
120
+ setSortedDiseaseVars(diseaseVars);
121
+ }
122
+ }, [dataset.varSort.disease.sort, dataset.varSort.disease.sortOrder, diseaseVars, varMeans.fetchedData, varMeans.isPending, varMeans.serverError]);
123
+ const diseaseVarList = _.map(sortedDiseaseVars, v => {
124
+ return /*#__PURE__*/React.createElement(ListGroup.Item, {
125
+ key: v.gene_id
126
+ }, /*#__PURE__*/React.createElement("div", {
127
+ className: "d-flex justify-content-between align-items-center w-100"
128
+ }, v.name, /*#__PURE__*/React.createElement("div", {
129
+ className: "d-flex align-items-center gap-1"
130
+ }, /*#__PURE__*/React.createElement(Button, {
131
+ type: "button",
132
+ className: "m-0 p-0 px-1",
133
+ variant: "outline-secondary",
134
+ title: "Add to list",
135
+ onClick: () => {
136
+ handleSelect(dispatch, v);
137
+ }
138
+ }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
139
+ icon: faPlus
140
+ })))));
141
+ });
142
+ const isPending = diseaseData.isPending || varMeans.isPending && dataset.varSort.disease.sort === VAR_SORT.MATRIX;
143
+ 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", {
144
+ className: "d-flex justify-content-end mb-2"
145
+ }, /*#__PURE__*/React.createElement(Button, {
146
+ size: "sm",
147
+ title: "Add all as a set",
148
+ onClick: () => {
149
+ addVarSet(dispatch, {
150
+ name: disease.disease_name,
151
+ vars: _.map(diseaseVars, v => {
152
+ return {
153
+ index: v.index,
154
+ name: v.name,
155
+ matrix_index: v.matrix_index
156
+ };
157
+ })
158
+ });
159
+ }
160
+ }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
161
+ icon: faPlus
162
+ }), " Add all as a set")), /*#__PURE__*/React.createElement(ListGroup, {
163
+ className: "overflow-scroll"
164
+ }, diseaseVarList)));
165
+ }