gramene-search 1.6.21 → 1.6.23

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gramene-search",
3
- "version": "1.6.21",
3
+ "version": "1.6.23",
4
4
  "description": "search wrapper for gramene",
5
5
  "source": "src/index.js",
6
6
  "main": "dist/index.js",
@@ -64,7 +64,8 @@ grameneSuggestions.selectGrameneSuggestionsStatus = createSelector(
64
64
  if (!queryString) return '';
65
65
  if (shouldUpdate) return 'update needed';
66
66
  if (isLoading) return 'loading';
67
- if (suggestionsRaw) return suggestionsRaw.data.grouped.category.matches + ' terms';
67
+ if (suggestionsRaw.data) return suggestionsRaw.data.grouped.category.matches + ' terms';
68
+ console.error(suggestionsRaw)
68
69
  return 'error';
69
70
  }
70
71
  );
@@ -9,20 +9,44 @@ const auth = getAuth(firebaseApp);
9
9
  const MAX_GENE_IDS = 1000; // Define the maximum number of gene IDs allowed
10
10
 
11
11
  const GeneListDisplayComponent = props => {
12
- const [savedGeneLists, setSavedGeneLists] = useState([]);
12
+ const [publicGeneLists, setPublicGeneLists] = useState([]);
13
+ const [privateGeneLists, setPrivateGeneLists] = useState([]);
13
14
  const [error, setError] = useState(null);
14
15
  const [user, setUser] = useState({});
15
16
  onAuthStateChanged(auth, (user) => setUser(user));
16
17
 
18
+ const fetchPrivateGeneLists = async () => {
19
+ try {
20
+ const token = await user.getIdToken();
21
+ // Replace this with actual fetch from your backend or storage
22
+ const response = await fetch(`${props.api}/gene_lists?site=${props.site}&isPublic=false`, {
23
+ method: 'GET',
24
+ headers: {
25
+ "Content-Type": "application/json",
26
+ "Authorization": `Bearer ${token}`
27
+ }
28
+ });
29
+ const result = await response.json();
30
+
31
+ if (response.ok) {
32
+ setError(null);
33
+ setPrivateGeneLists(result); // array of saved gene lists
34
+ } else {
35
+ setError('Error fetching gene lists.');
36
+ }
37
+ } catch (err) {
38
+ setError('Failed to fetch private gene lists. Please try again later.');
39
+ }
40
+ };
17
41
  // Fetch saved gene lists from a backend or local storage
18
- const fetchSavedGeneLists = async () => {
42
+ const fetchPublicGeneLists = async () => {
19
43
  try {
20
44
  // Replace this with actual fetch from your backend or storage
21
- const response = await fetch(`${props.api}/gene-lists`);
45
+ const response = await fetch(`${props.api}/gene_lists?site=${props.site}&isPublic=true`);
22
46
  const result = await response.json();
23
47
 
24
48
  if (response.ok) {
25
- setSavedGeneLists(result.savedLists); // Assuming savedLists is an array of saved gene lists
49
+ setPublicGeneLists(result); // array of saved gene lists
26
50
  } else {
27
51
  setError('Error fetching gene lists.');
28
52
  }
@@ -33,8 +57,11 @@ const GeneListDisplayComponent = props => {
33
57
 
34
58
  // Fetch data when the component is mounted
35
59
  useEffect(() => {
36
- fetchSavedGeneLists();
60
+ fetchPublicGeneLists();
37
61
  }, []);
62
+ useEffect(() => {
63
+ fetchPrivateGeneLists();
64
+ }, [user]);
38
65
 
39
66
  return (
40
67
  <div className="gene-list-display-component">
@@ -46,7 +73,35 @@ const GeneListDisplayComponent = props => {
46
73
  </Alert>
47
74
  )}
48
75
 
49
- {savedGeneLists.length > 0 ? (
76
+ {privateGeneLists.length > 0 && (
77
+ <Table striped bordered hover className="mt-4">
78
+ <thead>
79
+ <tr>
80
+ <th>List Name</th>
81
+ <th>Number of Genes</th>
82
+ <th>Actions</th>
83
+ </tr>
84
+ </thead>
85
+ <tbody>
86
+ {privateGeneLists.map((list, index) => (
87
+ <tr key={index}>
88
+ <td>{list.label}</td>
89
+ <td>{list.hash}</td>
90
+ <td>
91
+ <Button variant="info" onClick={() => viewGeneList(list)}>
92
+ View
93
+ </Button>
94
+ <Button variant="danger" onClick={() => deleteGeneList(props.api, list._id)} className="ml-2">
95
+ Delete
96
+ </Button>
97
+ </td>
98
+ </tr>
99
+ ))}
100
+ </tbody>
101
+ </Table>
102
+ )}
103
+
104
+ {publicGeneLists.length > 0 ? (
50
105
  <Table striped bordered hover className="mt-4">
51
106
  <thead>
52
107
  <tr>
@@ -56,15 +111,15 @@ const GeneListDisplayComponent = props => {
56
111
  </tr>
57
112
  </thead>
58
113
  <tbody>
59
- {savedGeneLists.map((list, index) => (
114
+ {publicGeneLists.map((list, index) => (
60
115
  <tr key={index}>
61
- <td>{list.name}</td>
62
- <td>{list.genes.length}</td>
116
+ <td>{list.label}</td>
117
+ <td>{list.hash}</td>
63
118
  <td>
64
119
  <Button variant="info" onClick={() => viewGeneList(list)}>
65
120
  View
66
121
  </Button>
67
- <Button variant="danger" onClick={() => deleteGeneList(props.api, list.id)} className="ml-2">
122
+ <Button variant="danger" onClick={() => deleteGeneList(props.api, list._id)} className="ml-2">
68
123
  Delete
69
124
  </Button>
70
125
  </td>
@@ -90,7 +145,7 @@ const deleteGeneList = async (api,listId) => {
90
145
  if (window.confirm('Are you sure you want to delete this gene list?')) {
91
146
  // Replace with the actual delete request
92
147
  try {
93
- await fetch(`${api}/gene-lists/${listId}`, {
148
+ await fetch(`${api}/gene_lists/${listId}`, {
94
149
  method: 'DELETE',
95
150
  });
96
151
  alert('Gene list deleted!');
@@ -149,7 +204,7 @@ const GeneListComponent = props => {
149
204
  headers: {
150
205
  'Content-Type': 'application/json',
151
206
  },
152
- body: JSON.stringify({ ids: geneArray }),
207
+ body: JSON.stringify(geneArray),
153
208
  });
154
209
 
155
210
  const result = await response.json();
@@ -181,7 +236,7 @@ const GeneListComponent = props => {
181
236
 
182
237
  const token = await user.getIdToken();
183
238
  try {
184
- const response = await fetch(`${props.api}/gene_list?${queryString}`, {
239
+ const response = await fetch(`${props.api}/gene_lists?${queryString}`, {
185
240
  method: 'POST',
186
241
  headers: {
187
242
  "Content-Type": "application/json",
@@ -1,6 +1,6 @@
1
- import React, { useRef, useEffect } from 'react'
1
+ import React, { useRef, useEffect, useState } from 'react'
2
2
  import {connect} from "redux-bundler-react";
3
- import {Tabs, Tab} from 'react-bootstrap';
3
+ import {Tabs, Tab, Form, Row, Col} from 'react-bootstrap';
4
4
  import BAR, {haveBAR} from "gramene-efp-browser";
5
5
 
6
6
  function DynamicIframe(props) {
@@ -61,33 +61,82 @@ function DynamicIframe(props) {
61
61
 
62
62
  const Detail = props => {
63
63
  const gene = props.geneDocs[props.searchResult.id];
64
- let paralogs_url;
65
- let gene_url = `/static/atlasWidget.html?reference=0&genes=${gene.atlas_id || gene._id}`;
64
+ const [atlasExperiment, setAtlasExperiment] = useState(null);
65
+ const [atlasExperimentList, setAtlasExperimentList] = useState([]);
66
+ const [isLocal, setIsLocal] = useState(false);
67
+
68
+ const handleLocalAPIChange = (event) => {
69
+ setIsLocal(event.target.checked);
70
+ };
71
+ useEffect(() => {
72
+ const tid = Math.floor(gene.taxon_id / 1000);
73
+ if (props.expressionStudies[tid]) {
74
+ let eList = props.expressionStudies[tid].filter(e => e.type === "Baseline");
75
+ setAtlasExperimentList(eList);
66
76
 
67
- if (props.paralogExpression && props.paralogExpression[gene._id]) {
68
- let paralogs = props.paralogExpression[gene._id].map(p => p.atlas_id || p.id);
69
- if (paralogs.length > 1) {
70
- paralogs_url= `/static/atlasWidget.html?reference=1&genes=${paralogs.join(' ')}`;
77
+ let refExp = eList.filter(e => e.isRef);
78
+ if (refExp.length === 1) {
79
+ setAtlasExperiment(refExp[0]._id);
80
+ } else {
81
+ // no reference experiment - choose first
82
+ setAtlasExperiment(eList[0]._id);
83
+ }
71
84
  }
85
+ }, [props.expressionStudies]);
86
+
87
+ let paralogs_url;
88
+ let gene_url = `/static/atlasWidget.html?genes=${gene.atlas_id || gene._id}&localAPI=${isLocal}`;
89
+ let paralogs = [];
90
+ if (gene.homology && gene.homology.homologous_genes && gene.homology.homologous_genes.within_species_paralog) {
91
+ paralogs = gene.homology.homologous_genes.within_species_paralog;
72
92
  }
73
- else {
74
- props.doRequestParalogExpression(gene._id)
93
+ if (paralogs.length > 1 && atlasExperiment) {
94
+ paralogs_url= `/static/atlasWidget.html?genes=${paralogs.join(' ')}&experiment=${atlasExperiment}&localAPI=${isLocal}`;
75
95
  }
76
96
  return <Tabs>
77
97
  {paralogs_url &&
78
- <Tab tabClassName="gxa" eventKey="paralogs" title="Reference Study (all paralogs)">
98
+ <Tab tabClassName="gxa" eventKey="paralogs" title={`Paralogs`} key="gxaparalogs">
99
+ <Form>
100
+ <Form.Check
101
+ type="switch"
102
+ id="localAPI"
103
+ label="Local API"
104
+ checked={isLocal}
105
+ onChange={handleLocalAPIChange}
106
+ />
107
+ <Form.Group as={Row} className="mb-3" controlId="formGroupExperiment">
108
+ <Form.Label column sm={1}>Experiment</Form.Label>
109
+ <Col sm={5}>
110
+ <Form.Select defaultValue={atlasExperiment} onChange={(e) => setAtlasExperiment(e.target.value)}>
111
+ {atlasExperimentList.map((experiment, index) => (
112
+ <option key={index} value={experiment._id}>{experiment.name}</option>
113
+ ))}
114
+ </Form.Select>
115
+ </Col>
116
+ </Form.Group>
117
+ </Form>
79
118
  <DynamicIframe url={paralogs_url}/>
80
119
  </Tab>
81
120
  }
82
- <Tab tabClassName="gxa" eventKey="gene" title="All Studies"><DynamicIframe url={gene_url}/></Tab>
121
+ <Tab tabClassName="gxa" eventKey="gene" title="All Studies" key="gxa">
122
+ <Form.Check
123
+ type="switch"
124
+ id="localAPI"
125
+ label="Local API"
126
+ checked={isLocal}
127
+ onChange={handleLocalAPIChange}
128
+ />
129
+ <DynamicIframe url={gene_url}/>
130
+ </Tab>
83
131
  {haveBAR(gene) &&
84
- <Tab tabClassName="eFP" eventKey="eFP" title="eFP Browser"><BAR gene={gene}/></Tab>
132
+ <Tab tabClassName="eFP" eventKey="eFP" title="eFP Browser" key="bar"><BAR gene={gene}/></Tab>
85
133
  }
86
134
  </Tabs>
87
135
  };
88
136
 
89
137
  export default connect(
90
- 'selectParalogExpression',
138
+ // 'selectParalogExpression',
139
+ 'selectExpressionStudies',
91
140
  'doRequestParalogExpression',
92
141
  Detail
93
142
  );
@@ -12,7 +12,8 @@ const ggURL = {
12
12
  IRRI: 'https://gringlobal.irri.org/gringlobal/accessiondetail?id=',
13
13
  ARS: 'https://npgsweb.ars-grin.gov/gringlobal/accessiondetail.aspx?id=',
14
14
  ICRISAT: 'https://genebank.icrisat.org/IND/PassportSummary?ID=',
15
- sorbmutdb: 'https://www.depts.ttu.edu/igcast/sorbmutdb.php'
15
+ sorbmutdb: 'https://www.depts.ttu.edu/igcast/sorbmutdb.php',
16
+ maizeGDB: 'https://wgs.maizegdb.org/'
16
17
  };
17
18
 
18
19
  const rice_studies = {'1': {label: 'Rice 3K', type: 'NAT'}};
@@ -62,6 +63,9 @@ const AccessionLink = ({germplasm, gene_id}) => {
62
63
  </form>
63
64
  );
64
65
  }
66
+ if (germplasm.pop_id === '15' && germplasm.stock_center === 'NOT FOUND') {
67
+ return <a target="_blank" href={ggURL['maizeGDB']}>SNPVersity 2.0</a>
68
+ }
65
69
  return <span>{germplasm.pub_id}</span>
66
70
  }
67
71
  function group_germplasm(gene, germplasmLUT, vep_obj) {
@@ -206,7 +210,6 @@ const GridWithGroups = ({groups,gene_id}) => {
206
210
  }
207
211
  },
208
212
  { field: 'synonym', headerName: 'Synonym', filter:false, sortable:false, flex: 1, cellRenderer: (params) => {
209
- console.log(params.data);
210
213
  if (params.data.accession) {
211
214
  return params.data.accession.germplasm.ens_id
212
215
  }
package/src/demo.js CHANGED
@@ -137,11 +137,11 @@ const panSites = [
137
137
  ensemblURL: 'https://ensembl-dev.sorghumbase.org',
138
138
  ensemblSite: 'https://ensembl-dev.sorghumbase.org',
139
139
  ensemblRest: 'https://data.gramene.org/pansite-ensembl-108',
140
- grameneData: 'https://data.sorghumbase.org/sorghum_v9',
140
+ grameneData: 'https://data.sorghumbase.org/auth_testing',
141
141
  ga: 'G-L5KXDCCZ16',
142
142
  targetTaxonId: 4558003,
143
143
  alertText: 'Click the search icon in the menu bar or type /',
144
- showViews: false,
144
+ showViews: true,
145
145
  details: {
146
146
  sequences: true,
147
147
  VEP: true,
@@ -315,7 +315,7 @@ const SearchViewsCmp = props => (
315
315
  <Status/>
316
316
  <Filters/>
317
317
  {props.configuration.showViews && <Views/>}
318
- {/*<Auth/>*/}
318
+ <Auth/>
319
319
  </div>
320
320
  </div>
321
321
  <div style={{width:"calc(100% - 250px", left:250, position:'relative'}}>
package/src/maize.html CHANGED
@@ -10,6 +10,13 @@
10
10
  <script async src="./static/gramene-dalliance/dalliance-all.js"></script>
11
11
  <script async src="https://plantreactome.gramene.org/DiagramJs/diagram/diagram.nocache.js"></script>
12
12
 
13
+ <link rel="stylesheet" type="text/css"
14
+ href="//www.ebi.ac.uk/gxa/resources/css/alt-customized-bootstrap-3.3.5.css"/>
15
+ <script language="JavaScript" type="text/javascript"
16
+ src="https://www.ebi.ac.uk/gxa/resources/js-bundles/vendorCommons.bundle.js"></script>
17
+ <script language="JavaScript" type="text/javascript"
18
+ src="https://www.ebi.ac.uk/gxa/resources/js-bundles/expressionAtlasHeatmapHighcharts.bundle.js"></script>
19
+
13
20
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no"/>
14
21
  <link rel="stylesheet" type="text/css" href="static/style.css">
15
22
  <!-- Global site tag (gtag.js) - Google Analytics -->
@@ -13,14 +13,15 @@
13
13
  const queryString = location.search;
14
14
  const urlParams = new URLSearchParams(queryString);
15
15
  const genes = urlParams.get('genes');
16
- const experiment = urlParams.get('reference');
16
+ const experiment = urlParams.get('experiment');
17
+ const localAPI = urlParams.get('localAPI');
17
18
  const options = {
18
19
  target: "heatmapContainer",
19
- query: { gene: genes }
20
+ query: { gene: genes },
21
+ disableGoogleAnalytics: true,
22
+ experiment: experiment || false,
23
+ atlasUrl: localAPI ? "https://data.sorghumbase.org/auth_testing/gxa/" : "https://www.ebi.ac.uk/gxa/"
20
24
  };
21
- if (+experiment === 1) {
22
- options["experiment"] = "reference"
23
- }
24
25
  expressionAtlasHeatmapHighcharts.render(options);
25
26
  </script>
26
27
  </body>