jbrowse-plugin-protein3d 0.10.0 → 0.11.0
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/README.md +12 -2
- package/dist/LaunchProteinView/components/LaunchProteinViewDialog.js +7 -3
- package/dist/LaunchProteinView/components/PdbResultsTable.d.ts +7 -0
- package/dist/LaunchProteinView/components/PdbResultsTable.js +70 -0
- package/dist/LaunchProteinView/components/PdbSearch.d.ts +13 -0
- package/dist/LaunchProteinView/components/PdbSearch.js +92 -0
- package/dist/LaunchProteinView/components/ProteinViewActions.js +1 -0
- package/dist/LaunchProteinView/hooks/useAlphaFoldDBSearch.d.ts +23 -20
- package/dist/LaunchProteinView/hooks/useAlphaFoldDBSearch.js +9 -88
- package/dist/LaunchProteinView/hooks/usePdbBestStructures.d.ts +6 -0
- package/dist/LaunchProteinView/hooks/usePdbBestStructures.js +19 -0
- package/dist/LaunchProteinView/hooks/useUniProtIdLookup.d.ts +39 -0
- package/dist/LaunchProteinView/hooks/useUniProtIdLookup.js +99 -0
- package/dist/LaunchProteinView/services/pdbeBestStructures.d.ts +22 -0
- package/dist/LaunchProteinView/services/pdbeBestStructures.js +66 -0
- package/dist/LaunchProteinView/utils/launchHelpers.d.ts +2 -1
- package/dist/LaunchProteinView/utils/launchHelpers.js +2 -1
- package/dist/LaunchProteinView/utils/structureUrls.d.ts +9 -0
- package/dist/LaunchProteinView/utils/structureUrls.js +19 -0
- package/dist/LaunchProteinViewExtensionPoint/index.js +9 -9
- package/dist/ProteinView/__fixtures__/structureFixtures.d.ts +7 -0
- package/dist/ProteinView/__fixtures__/structureFixtures.js +12 -0
- package/dist/ProteinView/chooseMappedEntity.d.ts +19 -10
- package/dist/ProteinView/chooseMappedEntity.js +38 -14
- package/dist/ProteinView/components/AlignmentRuler.d.ts +5 -4
- package/dist/ProteinView/components/AlignmentRuler.js +7 -6
- package/dist/ProteinView/components/ChainSelect.js +4 -3
- package/dist/ProteinView/components/FeatureBar.js +14 -3
- package/dist/ProteinView/components/HeaderStructureInfo.js +10 -2
- package/dist/ProteinView/components/ProteinAlignment.js +14 -10
- package/dist/ProteinView/components/ProteinAlignmentHelpButton.js +1 -2
- package/dist/ProteinView/components/ProteinAlignmentHelpDialog.js +1 -0
- package/dist/ProteinView/extractStructureSequences.d.ts +51 -0
- package/dist/ProteinView/extractStructureSequences.js +108 -7
- package/dist/ProteinView/model.d.ts +36 -0
- package/dist/ProteinView/model.js +1 -1
- package/dist/ProteinView/proteinViewSpec.d.ts +8 -0
- package/dist/ProteinView/structureModel.d.ts +36 -0
- package/dist/ProteinView/structureModel.js +56 -8
- package/dist/jbrowse-plugin-protein3d.umd.production.min.js +14 -14
- package/dist/jbrowse-plugin-protein3d.umd.production.min.js.map +4 -4
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -2
- package/src/LaunchProteinView/components/LaunchProteinViewDialog.tsx +15 -3
- package/src/LaunchProteinView/components/PdbResultsTable.tsx +117 -0
- package/src/LaunchProteinView/components/PdbSearch.tsx +216 -0
- package/src/LaunchProteinView/components/ProteinViewActions.tsx +1 -0
- package/src/LaunchProteinView/hooks/useAlphaFoldDBSearch.ts +9 -112
- package/src/LaunchProteinView/hooks/usePdbBestStructures.ts +32 -0
- package/src/LaunchProteinView/hooks/useUniProtIdLookup.ts +128 -0
- package/src/LaunchProteinView/services/pdbeBestStructures.test.ts +72 -0
- package/src/LaunchProteinView/services/pdbeBestStructures.ts +87 -0
- package/src/LaunchProteinView/utils/launchHelpers.ts +3 -0
- package/src/LaunchProteinView/utils/structureUrls.test.ts +15 -0
- package/src/LaunchProteinView/utils/structureUrls.ts +26 -0
- package/src/LaunchProteinViewExtensionPoint/index.ts +15 -9
- package/src/ProteinView/__fixtures__/structureFixtures.ts +23 -0
- package/src/ProteinView/chooseMappedEntity.test.ts +63 -0
- package/src/ProteinView/chooseMappedEntity.ts +63 -21
- package/src/ProteinView/components/AlignmentRuler.tsx +11 -5
- package/src/ProteinView/components/ChainSelect.tsx +4 -3
- package/src/ProteinView/components/FeatureBar.tsx +31 -3
- package/src/ProteinView/components/HeaderStructureInfo.tsx +17 -3
- package/src/ProteinView/components/ProteinAlignment.tsx +28 -11
- package/src/ProteinView/components/ProteinAlignmentHelpButton.tsx +0 -3
- package/src/ProteinView/components/ProteinAlignmentHelpDialog.tsx +9 -0
- package/src/ProteinView/components/rulerTicks.test.ts +16 -2
- package/src/ProteinView/extractStructureSequences.test.ts +144 -2
- package/src/ProteinView/extractStructureSequences.ts +144 -7
- package/src/ProteinView/model.ts +1 -1
- package/src/ProteinView/proteinViewSpec.ts +4 -0
- package/src/ProteinView/structureModel.test.ts +104 -0
- package/src/ProteinView/structureModel.ts +67 -6
- package/src/version.ts +1 -1
package/README.md
CHANGED
|
@@ -8,8 +8,9 @@ The major workflow enabled by this is
|
|
|
8
8
|
mouseover between genome and structure
|
|
9
9
|
|
|
10
10
|
It has features to automatically look up a protein structure of interest using
|
|
11
|
-
the UniProt ID mapping API to connect to AlphaFoldDB,
|
|
12
|
-
to
|
|
11
|
+
the UniProt ID mapping API to connect to AlphaFoldDB, lists the experimental PDB
|
|
12
|
+
entries SIFTS maps to that UniProt entry, and can also use Foldseek to look up
|
|
13
|
+
related structures
|
|
13
14
|
|
|
14
15
|
## Coordinate-mapping harness
|
|
15
16
|
|
|
@@ -48,6 +49,15 @@ use it on any species there
|
|
|
48
49
|
|
|
49
50
|
See [DEVELOPERS.md](DEVELOPERS.md)
|
|
50
51
|
|
|
52
|
+
## How it works
|
|
53
|
+
|
|
54
|
+
Notes on the parts that are easy to get subtly wrong, written for someone
|
|
55
|
+
extending the plugin or checking what a number on screen means:
|
|
56
|
+
|
|
57
|
+
- [Residue numbering](docs/residue-numbering.md): how a paper's R248 becomes
|
|
58
|
+
position 154 in the file, `label_seq_id` 155 for Mol\*, and the codon on
|
|
59
|
+
chr17, and how a session spec names a residue the literature's way.
|
|
60
|
+
|
|
51
61
|
## Publishing
|
|
52
62
|
|
|
53
63
|
just push a new tag using e.g.
|
|
@@ -5,6 +5,7 @@ import { Tab, Tabs } from '@mui/material';
|
|
|
5
5
|
import AlphaFoldDBSearch from './AlphaFoldDBSearch';
|
|
6
6
|
import FoldseekSearch from './FoldseekSearch';
|
|
7
7
|
import HelpButton from './HelpButton';
|
|
8
|
+
import PdbSearch from './PdbSearch';
|
|
8
9
|
import TabPanel from './TabPanel';
|
|
9
10
|
import UserProvidedStructure from './UserProvidedStructure';
|
|
10
11
|
import { DEFAULT_ALIGNMENT_ALGORITHM } from '../../ProteinView/types';
|
|
@@ -21,12 +22,15 @@ export default function LaunchProteinViewDialog({ handleClose, feature, model, }
|
|
|
21
22
|
setChoice(val);
|
|
22
23
|
} },
|
|
23
24
|
React.createElement(Tab, { value: 0, label: "AlphaFoldDB search" }),
|
|
24
|
-
React.createElement(Tab, { value: 1, label: "
|
|
25
|
-
React.createElement(Tab, { value: 2, label: "
|
|
25
|
+
React.createElement(Tab, { value: 1, label: "PDB search" }),
|
|
26
|
+
React.createElement(Tab, { value: 2, label: "Foldseek search" }),
|
|
27
|
+
React.createElement(Tab, { value: 3, label: "Open file manually" })),
|
|
26
28
|
React.createElement(TabPanel, { value: choice, index: 0 },
|
|
27
29
|
React.createElement(AlphaFoldDBSearch, { session: session, view: view, feature: feature, handleClose: handleClose, alignmentAlgorithm: alignmentAlgorithm, onAlignmentAlgorithmChange: setAlignmentAlgorithm })),
|
|
28
30
|
React.createElement(TabPanel, { value: choice, index: 1 },
|
|
29
|
-
React.createElement(
|
|
31
|
+
React.createElement(PdbSearch, { session: session, view: view, feature: feature, handleClose: handleClose, alignmentAlgorithm: alignmentAlgorithm, onAlignmentAlgorithmChange: setAlignmentAlgorithm })),
|
|
30
32
|
React.createElement(TabPanel, { value: choice, index: 2 },
|
|
33
|
+
React.createElement(FoldseekSearch, { session: session, view: view, feature: feature, handleClose: handleClose })),
|
|
34
|
+
React.createElement(TabPanel, { value: choice, index: 3 },
|
|
31
35
|
React.createElement(UserProvidedStructure, { session: session, view: view, feature: feature, handleClose: handleClose, alignmentAlgorithm: alignmentAlgorithm, onAlignmentAlgorithmChange: setAlignmentAlgorithm }))));
|
|
32
36
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { PdbStructureEntry } from '../services/pdbeBestStructures';
|
|
3
|
+
export default function PdbResultsTable({ entries, selectedPdbId, onSelect, }: {
|
|
4
|
+
entries: PdbStructureEntry[];
|
|
5
|
+
selectedPdbId?: string;
|
|
6
|
+
onSelect: (pdbId: string) => void;
|
|
7
|
+
}): React.JSX.Element;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Paper, Radio, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Typography, } from '@mui/material';
|
|
3
|
+
import { makeStyles } from 'tss-react/mui';
|
|
4
|
+
import ExternalLink from '../../components/ExternalLink';
|
|
5
|
+
import { rcsbEntryUrl } from '../services/pdbeBestStructures';
|
|
6
|
+
const useStyles = makeStyles()(theme => ({
|
|
7
|
+
tableContainer: {
|
|
8
|
+
maxHeight: 300,
|
|
9
|
+
},
|
|
10
|
+
headerCell: {
|
|
11
|
+
fontWeight: 'bold',
|
|
12
|
+
backgroundColor: theme.palette.mode === 'dark'
|
|
13
|
+
? theme.palette.grey[900]
|
|
14
|
+
: theme.palette.grey[100],
|
|
15
|
+
},
|
|
16
|
+
selectedRow: {
|
|
17
|
+
backgroundColor: theme.palette.action.selected,
|
|
18
|
+
},
|
|
19
|
+
clickableRow: {
|
|
20
|
+
cursor: 'pointer',
|
|
21
|
+
'&:hover': {
|
|
22
|
+
backgroundColor: theme.palette.action.hover,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
}));
|
|
26
|
+
const MAX_ROWS = 100;
|
|
27
|
+
export default function PdbResultsTable({ entries, selectedPdbId, onSelect, }) {
|
|
28
|
+
const { classes } = useStyles();
|
|
29
|
+
const shown = entries.slice(0, MAX_ROWS);
|
|
30
|
+
return (React.createElement(React.Fragment, null,
|
|
31
|
+
React.createElement(Typography, { variant: "body2", color: "textSecondary" },
|
|
32
|
+
entries.length,
|
|
33
|
+
" PDB entries, ranked by PDBe on coverage and resolution",
|
|
34
|
+
entries.length > shown.length
|
|
35
|
+
? ` (showing the first ${MAX_ROWS})`
|
|
36
|
+
: ''),
|
|
37
|
+
React.createElement(TableContainer, { component: Paper, className: classes.tableContainer },
|
|
38
|
+
React.createElement(Table, { size: "small", stickyHeader: true, "data-testid": "pdb-results-table" },
|
|
39
|
+
React.createElement(TableHead, null,
|
|
40
|
+
React.createElement(TableRow, null,
|
|
41
|
+
React.createElement(TableCell, { className: classes.headerCell, padding: "checkbox" }),
|
|
42
|
+
React.createElement(TableCell, { className: classes.headerCell }, "PDB ID"),
|
|
43
|
+
React.createElement(TableCell, { className: classes.headerCell }, "Method"),
|
|
44
|
+
React.createElement(TableCell, { className: classes.headerCell }, "Resolution"),
|
|
45
|
+
React.createElement(TableCell, { className: classes.headerCell }, "UniProt residues"),
|
|
46
|
+
React.createElement(TableCell, { className: classes.headerCell }, "Coverage"),
|
|
47
|
+
React.createElement(TableCell, { className: classes.headerCell }, "Chains"))),
|
|
48
|
+
React.createElement(TableBody, null, shown.map(entry => {
|
|
49
|
+
const selected = entry.pdbId === selectedPdbId;
|
|
50
|
+
return (React.createElement(TableRow, { key: entry.pdbId, className: `${classes.clickableRow} ${selected ? classes.selectedRow : ''}`, onClick: () => {
|
|
51
|
+
onSelect(entry.pdbId);
|
|
52
|
+
} },
|
|
53
|
+
React.createElement(TableCell, { padding: "checkbox" },
|
|
54
|
+
React.createElement(Radio, { checked: selected, size: "small" })),
|
|
55
|
+
React.createElement(TableCell, null,
|
|
56
|
+
React.createElement(ExternalLink, { href: rcsbEntryUrl(entry.pdbId) }, entry.pdbId.toUpperCase())),
|
|
57
|
+
React.createElement(TableCell, null, entry.experimentalMethod),
|
|
58
|
+
React.createElement(TableCell, null, entry.resolution === undefined
|
|
59
|
+
? '-'
|
|
60
|
+
: `${entry.resolution.toFixed(2)} Å`),
|
|
61
|
+
React.createElement(TableCell, null,
|
|
62
|
+
entry.unpStart,
|
|
63
|
+
"-",
|
|
64
|
+
entry.unpEnd),
|
|
65
|
+
React.createElement(TableCell, null,
|
|
66
|
+
(entry.coverage * 100).toFixed(0),
|
|
67
|
+
"%"),
|
|
68
|
+
React.createElement(TableCell, null, entry.chains.join(', '))));
|
|
69
|
+
}))))));
|
|
70
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { AlignmentAlgorithm } from '../../ProteinView/types';
|
|
3
|
+
import type { AbstractSessionModel, Feature } from '@jbrowse/core/util';
|
|
4
|
+
import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view';
|
|
5
|
+
declare const PdbSearch: ({ feature, session, view, handleClose, alignmentAlgorithm, onAlignmentAlgorithmChange, }: {
|
|
6
|
+
feature: Feature;
|
|
7
|
+
session: AbstractSessionModel;
|
|
8
|
+
view: LinearGenomeViewModel;
|
|
9
|
+
handleClose: () => void;
|
|
10
|
+
alignmentAlgorithm: AlignmentAlgorithm;
|
|
11
|
+
onAlignmentAlgorithmChange: (algorithm: AlignmentAlgorithm) => void;
|
|
12
|
+
}) => React.JSX.Element;
|
|
13
|
+
export default PdbSearch;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { ErrorMessage, LoadingEllipses } from '@jbrowse/core/ui';
|
|
3
|
+
import { DialogActions, DialogContent, TextField, Typography, } from '@mui/material';
|
|
4
|
+
import { observer } from 'mobx-react';
|
|
5
|
+
import { makeStyles } from 'tss-react/mui';
|
|
6
|
+
import IdentifierSelector from './IdentifierSelector';
|
|
7
|
+
import PdbResultsTable from './PdbResultsTable';
|
|
8
|
+
import ProteinViewActions from './ProteinViewActions';
|
|
9
|
+
import TranscriptSelector from './TranscriptSelector';
|
|
10
|
+
import UniProtIdInput from './UniProtIdInput';
|
|
11
|
+
import UniProtResultsTable from './UniProtResultsTable';
|
|
12
|
+
import ExternalLink from '../../components/ExternalLink';
|
|
13
|
+
import usePdbBestStructures from '../hooks/usePdbBestStructures';
|
|
14
|
+
import useTranscriptIsoformSelection from '../hooks/useTranscriptIsoformSelection';
|
|
15
|
+
import useUniProtIdLookup from '../hooks/useUniProtIdLookup';
|
|
16
|
+
import { getPdbStructureUrl, uniprotEntryUrl } from '../utils/structureUrls';
|
|
17
|
+
const useStyles = makeStyles()({
|
|
18
|
+
dialogContent: {
|
|
19
|
+
width: '80em',
|
|
20
|
+
'& > *': {
|
|
21
|
+
marginBottom: 20,
|
|
22
|
+
},
|
|
23
|
+
'& > *:last-child': {
|
|
24
|
+
marginBottom: 0,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
endRow: {
|
|
28
|
+
display: 'flex',
|
|
29
|
+
flexDirection: 'row',
|
|
30
|
+
gap: 12,
|
|
31
|
+
alignItems: 'flex-start',
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
// Experimental structures of the gene's protein, found through SIFTS: PDBe
|
|
35
|
+
// lists every entry mapped to the UniProt accession, ranked on coverage and
|
|
36
|
+
// resolution, so a reader who does not know a PDB id can still reach one.
|
|
37
|
+
// A crystal is usually a fragment, often with partners, so the view aligns
|
|
38
|
+
// the transcript to it after launch rather than expecting a sequence match
|
|
39
|
+
// here.
|
|
40
|
+
const PdbSearch = observer(function PdbSearch({ feature, session, view, handleClose, alignmentAlgorithm, onAlignmentAlgorithmChange, }) {
|
|
41
|
+
const { classes } = useStyles();
|
|
42
|
+
const lookup = useUniProtIdLookup({ feature, view });
|
|
43
|
+
const { uniprotId, isAutoMode, isLookupLoading } = lookup;
|
|
44
|
+
const { entries, error: pdbError, isLoading: isPdbLoading, } = usePdbBestStructures(uniprotId);
|
|
45
|
+
const [userPdbId, setUserPdbId] = useState();
|
|
46
|
+
const { transcripts, isoformSequences, isLoading: isIsoformLoading, error: isoformError, selectedTranscriptId, setSelectedTranscriptId, selectedTranscript, selectedIsoform, } = useTranscriptIsoformSelection({ feature, view, resetKey: uniprotId });
|
|
47
|
+
const selectedPdbId = userPdbId && entries?.some(e => e.pdbId === userPdbId)
|
|
48
|
+
? userPdbId
|
|
49
|
+
: entries?.[0]?.pdbId;
|
|
50
|
+
const loadingStatuses = [
|
|
51
|
+
isLookupLoading && 'Looking up UniProt ID',
|
|
52
|
+
isIsoformLoading && 'Loading protein sequences from transcript isoforms',
|
|
53
|
+
isPdbLoading && 'Listing PDB entries from PDBe',
|
|
54
|
+
].filter((s) => !!s);
|
|
55
|
+
const isLoading = loadingStatuses.length > 0;
|
|
56
|
+
const error = isLoading
|
|
57
|
+
? undefined
|
|
58
|
+
: (isoformError ?? lookup.lookupError ?? pdbError);
|
|
59
|
+
return (React.createElement(React.Fragment, null,
|
|
60
|
+
React.createElement(DialogContent, { className: classes.dialogContent },
|
|
61
|
+
error ? React.createElement(ErrorMessage, { error: error }) : null,
|
|
62
|
+
React.createElement(UniProtIdInput, { lookupMode: lookup.lookupMode, onLookupModeChange: lookup.setLookupMode, manualUniprotId: lookup.manualUniprotId, onManualUniprotIdChange: lookup.setManualUniprotId, featureUniprotId: lookup.featureUniprotId, endContent: lookup.showIdentifierSelector ? (React.createElement("div", { className: classes.endRow },
|
|
63
|
+
React.createElement(IdentifierSelector, { recognizedIds: lookup.recognizedIds, geneName: lookup.geneName, selectedId: lookup.selectedQueryId, onSelectedIdChange: lookup.setSelectedQueryId }),
|
|
64
|
+
React.createElement(TextField, { size: "small", label: "Organism (NCBI taxon)", helperText: "Scopes the gene-name search", value: lookup.taxonId, onChange: event => {
|
|
65
|
+
lookup.setTaxonId(event.target.value);
|
|
66
|
+
}, placeholder: String(lookup.effectiveTaxonId), slotProps: { inputLabel: { shrink: true } }, sx: { width: 180 } }))) : null }),
|
|
67
|
+
loadingStatuses.map(status => (React.createElement(LoadingEllipses, { key: status, variant: "subtitle2", message: status }))),
|
|
68
|
+
isAutoMode && lookup.uniprotEntries.length > 0 ? (React.createElement(React.Fragment, null,
|
|
69
|
+
React.createElement(Typography, { variant: "body2", color: "textSecondary" },
|
|
70
|
+
"Searched UniProt by ",
|
|
71
|
+
lookup.searchDescription),
|
|
72
|
+
React.createElement(UniProtResultsTable, { entries: lookup.uniprotEntries, selectedAccession: lookup.selectedTableAccession, onSelect: lookup.setSelectedUniprotId }))) : null,
|
|
73
|
+
isAutoMode &&
|
|
74
|
+
!isLookupLoading &&
|
|
75
|
+
lookup.uniprotEntries.length === 0 ? (React.createElement(Typography, { variant: "body2", color: "textSecondary" },
|
|
76
|
+
"No UniProt entries found for ",
|
|
77
|
+
lookup.searchDescriptionOr,
|
|
78
|
+
". Try a different identifier above, or search",
|
|
79
|
+
' ',
|
|
80
|
+
React.createElement(ExternalLink, { href: "https://www.uniprot.org/" }, "UniProt"),
|
|
81
|
+
' ',
|
|
82
|
+
"directly and use \"Enter manually\".")) : null,
|
|
83
|
+
uniprotId && entries && !isPdbLoading ? (entries.length > 0 ? (React.createElement(PdbResultsTable, { entries: entries, selectedPdbId: selectedPdbId, onSelect: setUserPdbId })) : (React.createElement(Typography, null,
|
|
84
|
+
"PDBe lists no experimental structure for",
|
|
85
|
+
' ',
|
|
86
|
+
React.createElement(ExternalLink, { href: uniprotEntryUrl(uniprotId) }, uniprotId),
|
|
87
|
+
". The AlphaFoldDB tab has a predicted one."))) : null,
|
|
88
|
+
isoformSequences && selectedTranscript ? (React.createElement(TranscriptSelector, { val: selectedTranscriptId, setVal: setSelectedTranscriptId, feature: feature, isoforms: transcripts, isoformSequences: isoformSequences })) : null),
|
|
89
|
+
React.createElement(DialogActions, null,
|
|
90
|
+
React.createElement(ProteinViewActions, { handleClose: handleClose, uniprotId: uniprotId, userSelectedProteinSequence: selectedIsoform, selectedTranscript: selectedTranscript, url: selectedPdbId ? getPdbStructureUrl(selectedPdbId) : undefined, feature: feature, view: view, session: session, alignmentAlgorithm: alignmentAlgorithm, onAlignmentAlgorithmChange: onAlignmentAlgorithmChange, isLoading: isLoading, error: error }))));
|
|
91
|
+
});
|
|
92
|
+
export default PdbSearch;
|
|
@@ -16,6 +16,7 @@ export default function ProteinViewActions({ handleClose, uniprotId, userSelecte
|
|
|
16
16
|
uniprotId,
|
|
17
17
|
userSelectedProteinSequence,
|
|
18
18
|
selectedTranscript,
|
|
19
|
+
url,
|
|
19
20
|
});
|
|
20
21
|
// Disable launch while loading — SWR's keepPreviousData would otherwise let
|
|
21
22
|
// a user click Launch on stale results (wrong UniProt ID) during a refetch.
|
|
@@ -1,34 +1,18 @@
|
|
|
1
1
|
import type { SequenceSearchType } from './useAlphaFoldSequenceSearch';
|
|
2
|
-
import type { LookupMode } from '../components/UniProtIdInput';
|
|
3
2
|
import type { Feature } from '@jbrowse/core/util';
|
|
4
3
|
import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view';
|
|
5
4
|
export default function useAlphaFoldDBSearch({ feature, view, }: {
|
|
6
5
|
feature: Feature;
|
|
7
6
|
view: LinearGenomeViewModel;
|
|
8
7
|
}): {
|
|
9
|
-
lookupMode: LookupMode;
|
|
10
|
-
setLookupMode: import("react").Dispatch<import("react").SetStateAction<LookupMode>>;
|
|
11
|
-
manualUniprotId: string;
|
|
12
|
-
setManualUniprotId: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
13
|
-
taxonId: string;
|
|
14
|
-
setTaxonId: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
15
|
-
effectiveTaxonId: number;
|
|
16
|
-
selectedQueryId: string;
|
|
17
|
-
setSelectedQueryId: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
18
8
|
sequenceSearchType: SequenceSearchType;
|
|
19
9
|
setSequenceSearchType: import("react").Dispatch<import("react").SetStateAction<SequenceSearchType>>;
|
|
20
|
-
selectedUniprotId: string | undefined;
|
|
21
|
-
setSelectedUniprotId: import("react").Dispatch<import("react").SetStateAction<string | undefined>>;
|
|
22
10
|
userSelection: string | undefined;
|
|
23
11
|
setUserSelection: import("react").Dispatch<import("react").SetStateAction<string | undefined>>;
|
|
24
12
|
transcriptOptions: Feature[];
|
|
25
13
|
selectedTranscript: Feature | undefined;
|
|
26
14
|
isoformSequences: import("../utils/util").IsoformSequences | undefined;
|
|
27
15
|
userSelectedProteinSequence: import("../utils/util").IsoformSequence | undefined;
|
|
28
|
-
uniprotEntries: import("../services/lookupMethods").UniProtEntry[];
|
|
29
|
-
recognizedIds: string[];
|
|
30
|
-
geneName: string | undefined;
|
|
31
|
-
featureUniprotId: string | undefined;
|
|
32
16
|
uniprotId: string | undefined;
|
|
33
17
|
url: string | undefined;
|
|
34
18
|
confidenceUrl: string | undefined;
|
|
@@ -36,15 +20,34 @@ export default function useAlphaFoldDBSearch({ feature, view, }: {
|
|
|
36
20
|
error: any;
|
|
37
21
|
loadingStatuses: string[];
|
|
38
22
|
isSequenceSearchLoading: boolean;
|
|
39
|
-
showIdentifierSelector: boolean;
|
|
40
23
|
showStructureSelectors: boolean;
|
|
41
24
|
sequencesMatch: boolean | undefined;
|
|
42
|
-
searchDescription: string;
|
|
43
|
-
searchDescriptionOr: string;
|
|
44
|
-
selectedTableAccession: string | undefined;
|
|
45
25
|
showUniprotResults: boolean;
|
|
46
26
|
showNoResults: boolean;
|
|
47
27
|
showSequenceSearchStatus: boolean;
|
|
48
28
|
showAlphaFoldDBSearchStatus: boolean;
|
|
49
29
|
isLoading: boolean;
|
|
30
|
+
lookupMode: import("../components/UniProtIdInput").LookupMode;
|
|
31
|
+
setLookupMode: import("react").Dispatch<import("react").SetStateAction<import("../components/UniProtIdInput").LookupMode>>;
|
|
32
|
+
manualUniprotId: string;
|
|
33
|
+
setManualUniprotId: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
34
|
+
taxonId: string;
|
|
35
|
+
setTaxonId: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
36
|
+
effectiveTaxonId: number;
|
|
37
|
+
selectedQueryId: string;
|
|
38
|
+
setSelectedQueryId: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
39
|
+
selectedUniprotId: string | undefined;
|
|
40
|
+
setSelectedUniprotId: import("react").Dispatch<import("react").SetStateAction<string | undefined>>;
|
|
41
|
+
selectedTableAccession: string | undefined;
|
|
42
|
+
uniprotEntries: import("../services/lookupMethods").UniProtEntry[];
|
|
43
|
+
isLookupLoading: boolean;
|
|
44
|
+
lookupError: any;
|
|
45
|
+
featureUniprotId: string | undefined;
|
|
46
|
+
recognizedIds: string[];
|
|
47
|
+
geneName: string | undefined;
|
|
48
|
+
isAutoMode: boolean;
|
|
49
|
+
isSequenceMode: boolean;
|
|
50
|
+
showIdentifierSelector: boolean;
|
|
51
|
+
searchDescription: string;
|
|
52
|
+
searchDescriptionOr: string;
|
|
50
53
|
};
|
|
@@ -1,65 +1,14 @@
|
|
|
1
1
|
import { useState } from 'react';
|
|
2
|
-
import { getConf } from '@jbrowse/core/configuration';
|
|
3
|
-
import { getSession } from '@jbrowse/core/util';
|
|
4
2
|
import useAlphaFoldData from './useAlphaFoldData';
|
|
5
3
|
import useAlphaFoldSequenceSearch from './useAlphaFoldSequenceSearch';
|
|
6
|
-
import useDebouncedValue from './useDebouncedValue';
|
|
7
4
|
import useTranscriptIsoformSelection from './useTranscriptIsoformSelection';
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import { extractFeatureIdentifiers, extractTaxonId, stripStopCodon, } from '../utils/util';
|
|
5
|
+
import useUniProtIdLookup from './useUniProtIdLookup';
|
|
6
|
+
import { stripStopCodon } from '../utils/util';
|
|
11
7
|
export default function useAlphaFoldDBSearch({ feature, view, }) {
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const [taxonIdInput, setTaxonIdInput] = useState('');
|
|
15
|
-
const geneIds = extractFeatureIdentifiers(feature);
|
|
16
|
-
// The gene-name UniProt search is ambiguous across species, so scope it to
|
|
17
|
-
// the assembly's organism. jb2hubs assemblies carry the NCBI taxon in the
|
|
18
|
-
// reference-sequence track metadata (UCSC: metadata.taxId, GenArk:
|
|
19
|
-
// metadata.ucsc.taxId). Falls back to human via searchUniProtEntries when
|
|
20
|
-
// absent; a user override (taxonIdInput) always wins.
|
|
21
|
-
const assemblyName = view.assemblyNames[0];
|
|
22
|
-
const assembly = assemblyName
|
|
23
|
-
? getSession(view).assemblyManager.get(assemblyName)
|
|
24
|
-
: undefined;
|
|
25
|
-
const assemblyTaxonId = assembly
|
|
26
|
-
? extractTaxonId(getConf(assembly, ['sequence', 'metadata']))
|
|
27
|
-
: undefined;
|
|
28
|
-
const overrideTaxon = Number(taxonIdInput.trim());
|
|
29
|
-
const effectiveTaxonId = taxonIdInput.trim() !== '' &&
|
|
30
|
-
Number.isFinite(overrideTaxon) &&
|
|
31
|
-
overrideTaxon > 0
|
|
32
|
-
? overrideTaxon
|
|
33
|
-
: assemblyTaxonId;
|
|
34
|
-
const [selectedQueryId, setSelectedQueryId] = useState('auto');
|
|
8
|
+
const lookup = useUniProtIdLookup({ feature, view });
|
|
9
|
+
const { uniprotId, isSequenceMode, isAutoMode, isLookupLoading } = lookup;
|
|
35
10
|
const [sequenceSearchType, setSequenceSearchType] = useState('md5');
|
|
36
|
-
const
|
|
37
|
-
const featureUniprotId = geneIds.uniprotId;
|
|
38
|
-
const effectiveLookupMode = lookupMode === 'auto' && featureUniprotId ? 'feature' : lookupMode;
|
|
39
|
-
const isSequenceMode = effectiveLookupMode === 'sequence';
|
|
40
|
-
const isAutoMode = effectiveLookupMode === 'auto';
|
|
41
|
-
const { entries: uniprotEntries, isLoading: isLookupLoading, error: lookupError, } = useUniProtSearch({
|
|
42
|
-
recognizedIds: geneIds.recognizedIds,
|
|
43
|
-
geneId: geneIds.geneId,
|
|
44
|
-
geneName: geneIds.geneName,
|
|
45
|
-
organismId: effectiveTaxonId,
|
|
46
|
-
selectedQueryId,
|
|
47
|
-
enabled: isAutoMode,
|
|
48
|
-
});
|
|
49
|
-
// Debounce manual entry so fetches don't fire on every keystroke and
|
|
50
|
-
// pollute the SWR cache with partial-ID 404s.
|
|
51
|
-
const debouncedManualUniprotId = useDebouncedValue(manualUniprotId, 400);
|
|
52
|
-
const autoUniprotId = uniprotEntries[0]?.accession;
|
|
53
|
-
const uniprotId = effectiveLookupMode === 'feature'
|
|
54
|
-
? featureUniprotId
|
|
55
|
-
: isAutoMode
|
|
56
|
-
? (selectedUniprotId ?? autoUniprotId)
|
|
57
|
-
: effectiveLookupMode === 'manual'
|
|
58
|
-
? debouncedManualUniprotId
|
|
59
|
-
: undefined;
|
|
60
|
-
const { isLoading: isAlphaFoldLoading, isValidating: isAlphaFoldValidating, error: alphaFoldError, url: alphaFoldUrl, confidenceUrl: alphaFoldConfidenceUrl, structureSequences: alphaFoldStructureSequences, } = useAlphaFoldData({
|
|
61
|
-
uniprotId: isSequenceMode ? undefined : uniprotId,
|
|
62
|
-
});
|
|
11
|
+
const { isLoading: isAlphaFoldLoading, isValidating: isAlphaFoldValidating, error: alphaFoldError, url: alphaFoldUrl, confidenceUrl: alphaFoldConfidenceUrl, structureSequences: alphaFoldStructureSequences, } = useAlphaFoldData({ uniprotId });
|
|
63
12
|
const { transcripts: transcriptOptions, isoformSequences, structureSequence: alphaFoldStructureSequence, isLoading: isIsoformLoading, error: isoformError, selectedTranscriptId: effectiveTranscriptId, setSelectedTranscriptId: setUserSelection, selectedTranscript, selectedIsoform: userSelectedProteinSequence, } = useTranscriptIsoformSelection({
|
|
64
13
|
feature,
|
|
65
14
|
view,
|
|
@@ -99,33 +48,18 @@ export default function useAlphaFoldDBSearch({ feature, view, }) {
|
|
|
99
48
|
// Only show errors once all loading is done — the synchronous
|
|
100
49
|
// effectiveLookupMode and autoTranscriptId computations prevent the
|
|
101
50
|
// one-frame gaps that previously caused brief error flashes
|
|
102
|
-
const rawError = isoformError ?? lookupError ?? alphaFoldError ?? sequenceSearchError;
|
|
51
|
+
const rawError = isoformError ?? lookup.lookupError ?? alphaFoldError ?? sequenceSearchError;
|
|
103
52
|
const error = isLoading ? undefined : rawError;
|
|
104
53
|
return {
|
|
105
|
-
|
|
106
|
-
setLookupMode,
|
|
107
|
-
manualUniprotId,
|
|
108
|
-
setManualUniprotId,
|
|
109
|
-
taxonId: taxonIdInput,
|
|
110
|
-
setTaxonId: setTaxonIdInput,
|
|
111
|
-
// shown as the field placeholder so the user sees the organism in effect
|
|
112
|
-
effectiveTaxonId: effectiveTaxonId ?? 9606,
|
|
113
|
-
selectedQueryId,
|
|
114
|
-
setSelectedQueryId,
|
|
54
|
+
...lookup,
|
|
115
55
|
sequenceSearchType,
|
|
116
56
|
setSequenceSearchType,
|
|
117
|
-
selectedUniprotId,
|
|
118
|
-
setSelectedUniprotId,
|
|
119
57
|
userSelection: effectiveTranscriptId,
|
|
120
58
|
setUserSelection,
|
|
121
59
|
transcriptOptions,
|
|
122
60
|
selectedTranscript,
|
|
123
61
|
isoformSequences,
|
|
124
62
|
userSelectedProteinSequence,
|
|
125
|
-
uniprotEntries,
|
|
126
|
-
recognizedIds: geneIds.recognizedIds,
|
|
127
|
-
geneName: geneIds.geneName,
|
|
128
|
-
featureUniprotId,
|
|
129
63
|
uniprotId: finalUniprotId,
|
|
130
64
|
url: finalUrl,
|
|
131
65
|
confidenceUrl: finalConfidenceUrl,
|
|
@@ -133,7 +67,6 @@ export default function useAlphaFoldDBSearch({ feature, view, }) {
|
|
|
133
67
|
error,
|
|
134
68
|
loadingStatuses,
|
|
135
69
|
isSequenceSearchLoading,
|
|
136
|
-
showIdentifierSelector: isAutoMode && (geneIds.recognizedIds.length > 0 || !!geneIds.geneName),
|
|
137
70
|
showStructureSelectors: !!isoformSequences &&
|
|
138
71
|
!!selectedTranscript &&
|
|
139
72
|
(isSequenceMode || !!(finalStructureSequence && finalUniprotId)),
|
|
@@ -143,25 +76,13 @@ export default function useAlphaFoldDBSearch({ feature, view, }) {
|
|
|
143
76
|
? stripStopCodon(userSelectedProteinSequence.seq) ===
|
|
144
77
|
finalStructureSequence
|
|
145
78
|
: undefined,
|
|
146
|
-
searchDescription: getSearchDescription({
|
|
147
|
-
selectedQueryId,
|
|
148
|
-
recognizedIds: geneIds.recognizedIds,
|
|
149
|
-
geneName: geneIds.geneName,
|
|
150
|
-
}),
|
|
151
|
-
searchDescriptionOr: getSearchDescription({
|
|
152
|
-
selectedQueryId,
|
|
153
|
-
recognizedIds: geneIds.recognizedIds,
|
|
154
|
-
geneName: geneIds.geneName,
|
|
155
|
-
joinWord: 'or',
|
|
156
|
-
}),
|
|
157
|
-
selectedTableAccession: selectedUniprotId ?? autoUniprotId,
|
|
158
79
|
showUniprotResults: !!isoformSequences &&
|
|
159
80
|
isAutoMode &&
|
|
160
|
-
(uniprotEntries.length > 0 || isLookupLoading),
|
|
81
|
+
(lookup.uniprotEntries.length > 0 || isLookupLoading),
|
|
161
82
|
showNoResults: !!isoformSequences &&
|
|
162
83
|
isAutoMode &&
|
|
163
84
|
!isLookupLoading &&
|
|
164
|
-
uniprotEntries.length === 0,
|
|
85
|
+
lookup.uniprotEntries.length === 0,
|
|
165
86
|
showSequenceSearchStatus: isSequenceMode,
|
|
166
87
|
showAlphaFoldDBSearchStatus: !!finalStructureSequence && !!finalUniprotId && !isSequenceMode,
|
|
167
88
|
isLoading,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import useSWR from 'swr';
|
|
2
|
+
import { STATIC_SWR_OPTIONS } from './swrOptions';
|
|
3
|
+
import { parseBestStructures, pdbeBestStructuresUrl, } from '../services/pdbeBestStructures';
|
|
4
|
+
// PDBe answers 404 for an accession with no experimental structure, which is
|
|
5
|
+
// the ordinary case for most genes rather than a failure.
|
|
6
|
+
async function fetchBestStructures(url) {
|
|
7
|
+
const response = await fetch(url);
|
|
8
|
+
if (response.status === 404) {
|
|
9
|
+
return [];
|
|
10
|
+
}
|
|
11
|
+
if (!response.ok) {
|
|
12
|
+
throw new Error(`HTTP ${response.status} fetching ${url} ${await response.text()}`);
|
|
13
|
+
}
|
|
14
|
+
return parseBestStructures(await response.json());
|
|
15
|
+
}
|
|
16
|
+
export default function usePdbBestStructures(uniprotId) {
|
|
17
|
+
const { data, error, isLoading } = useSWR(uniprotId ? pdbeBestStructuresUrl(uniprotId) : null, fetchBestStructures, STATIC_SWR_OPTIONS);
|
|
18
|
+
return { entries: data, error, isLoading };
|
|
19
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { LookupMode } from '../components/UniProtIdInput';
|
|
2
|
+
import type { Feature } from '@jbrowse/core/util';
|
|
3
|
+
import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view';
|
|
4
|
+
/**
|
|
5
|
+
* Which UniProt entry a feature is, by the dialog's lookup modes: the
|
|
6
|
+
* feature's own attribute, the ID-mapping search over its recognised ids and
|
|
7
|
+
* gene name, a typed accession, or none (sequence mode, where the structure
|
|
8
|
+
* search itself names the entry). Shared by every tab that starts from an
|
|
9
|
+
* accession so they agree on what the gene is.
|
|
10
|
+
*/
|
|
11
|
+
export default function useUniProtIdLookup({ feature, view, }: {
|
|
12
|
+
feature: Feature;
|
|
13
|
+
view: LinearGenomeViewModel;
|
|
14
|
+
}): {
|
|
15
|
+
lookupMode: LookupMode;
|
|
16
|
+
setLookupMode: import("react").Dispatch<import("react").SetStateAction<LookupMode>>;
|
|
17
|
+
manualUniprotId: string;
|
|
18
|
+
setManualUniprotId: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
19
|
+
taxonId: string;
|
|
20
|
+
setTaxonId: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
21
|
+
effectiveTaxonId: number;
|
|
22
|
+
selectedQueryId: string;
|
|
23
|
+
setSelectedQueryId: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
24
|
+
selectedUniprotId: string | undefined;
|
|
25
|
+
setSelectedUniprotId: import("react").Dispatch<import("react").SetStateAction<string | undefined>>;
|
|
26
|
+
selectedTableAccession: string | undefined;
|
|
27
|
+
uniprotEntries: import("../services/lookupMethods").UniProtEntry[];
|
|
28
|
+
isLookupLoading: boolean;
|
|
29
|
+
lookupError: any;
|
|
30
|
+
uniprotId: string | undefined;
|
|
31
|
+
featureUniprotId: string | undefined;
|
|
32
|
+
recognizedIds: string[];
|
|
33
|
+
geneName: string | undefined;
|
|
34
|
+
isAutoMode: boolean;
|
|
35
|
+
isSequenceMode: boolean;
|
|
36
|
+
showIdentifierSelector: boolean;
|
|
37
|
+
searchDescription: string;
|
|
38
|
+
searchDescriptionOr: string;
|
|
39
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { getConf } from '@jbrowse/core/configuration';
|
|
3
|
+
import { getSession } from '@jbrowse/core/util';
|
|
4
|
+
import useDebouncedValue from './useDebouncedValue';
|
|
5
|
+
import useUniProtSearch from './useUniProtSearch';
|
|
6
|
+
import getSearchDescription from '../utils/getSearchDescription';
|
|
7
|
+
import { extractFeatureIdentifiers, extractTaxonId } from '../utils/util';
|
|
8
|
+
/**
|
|
9
|
+
* Which UniProt entry a feature is, by the dialog's lookup modes: the
|
|
10
|
+
* feature's own attribute, the ID-mapping search over its recognised ids and
|
|
11
|
+
* gene name, a typed accession, or none (sequence mode, where the structure
|
|
12
|
+
* search itself names the entry). Shared by every tab that starts from an
|
|
13
|
+
* accession so they agree on what the gene is.
|
|
14
|
+
*/
|
|
15
|
+
export default function useUniProtIdLookup({ feature, view, }) {
|
|
16
|
+
const [lookupMode, setLookupMode] = useState('auto');
|
|
17
|
+
const [manualUniprotId, setManualUniprotId] = useState('');
|
|
18
|
+
const [taxonIdInput, setTaxonIdInput] = useState('');
|
|
19
|
+
const geneIds = extractFeatureIdentifiers(feature);
|
|
20
|
+
// The gene-name UniProt search is ambiguous across species, so scope it to
|
|
21
|
+
// the assembly's organism. jb2hubs assemblies carry the NCBI taxon in the
|
|
22
|
+
// reference-sequence track metadata (UCSC: metadata.taxId, GenArk:
|
|
23
|
+
// metadata.ucsc.taxId). Falls back to human via searchUniProtEntries when
|
|
24
|
+
// absent; a user override (taxonIdInput) always wins.
|
|
25
|
+
const assemblyName = view.assemblyNames[0];
|
|
26
|
+
const assembly = assemblyName
|
|
27
|
+
? getSession(view).assemblyManager.get(assemblyName)
|
|
28
|
+
: undefined;
|
|
29
|
+
const assemblyTaxonId = assembly
|
|
30
|
+
? extractTaxonId(getConf(assembly, ['sequence', 'metadata']))
|
|
31
|
+
: undefined;
|
|
32
|
+
const overrideTaxon = Number(taxonIdInput.trim());
|
|
33
|
+
const effectiveTaxonId = taxonIdInput.trim() !== '' &&
|
|
34
|
+
Number.isFinite(overrideTaxon) &&
|
|
35
|
+
overrideTaxon > 0
|
|
36
|
+
? overrideTaxon
|
|
37
|
+
: assemblyTaxonId;
|
|
38
|
+
const [selectedQueryId, setSelectedQueryId] = useState('auto');
|
|
39
|
+
const [selectedUniprotId, setSelectedUniprotId] = useState();
|
|
40
|
+
const featureUniprotId = geneIds.uniprotId;
|
|
41
|
+
const effectiveLookupMode = lookupMode === 'auto' && featureUniprotId ? 'feature' : lookupMode;
|
|
42
|
+
const isSequenceMode = effectiveLookupMode === 'sequence';
|
|
43
|
+
const isAutoMode = effectiveLookupMode === 'auto';
|
|
44
|
+
const { entries: uniprotEntries, isLoading: isLookupLoading, error: lookupError, } = useUniProtSearch({
|
|
45
|
+
recognizedIds: geneIds.recognizedIds,
|
|
46
|
+
geneId: geneIds.geneId,
|
|
47
|
+
geneName: geneIds.geneName,
|
|
48
|
+
organismId: effectiveTaxonId,
|
|
49
|
+
selectedQueryId,
|
|
50
|
+
enabled: isAutoMode,
|
|
51
|
+
});
|
|
52
|
+
// Debounce manual entry so fetches don't fire on every keystroke and
|
|
53
|
+
// pollute the SWR cache with partial-ID 404s.
|
|
54
|
+
const debouncedManualUniprotId = useDebouncedValue(manualUniprotId, 400);
|
|
55
|
+
const autoUniprotId = uniprotEntries[0]?.accession;
|
|
56
|
+
const uniprotId = effectiveLookupMode === 'feature'
|
|
57
|
+
? featureUniprotId
|
|
58
|
+
: isAutoMode
|
|
59
|
+
? (selectedUniprotId ?? autoUniprotId)
|
|
60
|
+
: effectiveLookupMode === 'manual'
|
|
61
|
+
? debouncedManualUniprotId
|
|
62
|
+
: undefined;
|
|
63
|
+
return {
|
|
64
|
+
lookupMode: effectiveLookupMode,
|
|
65
|
+
setLookupMode,
|
|
66
|
+
manualUniprotId,
|
|
67
|
+
setManualUniprotId,
|
|
68
|
+
taxonId: taxonIdInput,
|
|
69
|
+
setTaxonId: setTaxonIdInput,
|
|
70
|
+
// shown as the field placeholder so the user sees the organism in effect
|
|
71
|
+
effectiveTaxonId: effectiveTaxonId ?? 9606,
|
|
72
|
+
selectedQueryId,
|
|
73
|
+
setSelectedQueryId,
|
|
74
|
+
selectedUniprotId,
|
|
75
|
+
setSelectedUniprotId,
|
|
76
|
+
selectedTableAccession: selectedUniprotId ?? autoUniprotId,
|
|
77
|
+
uniprotEntries,
|
|
78
|
+
isLookupLoading,
|
|
79
|
+
lookupError,
|
|
80
|
+
uniprotId,
|
|
81
|
+
featureUniprotId,
|
|
82
|
+
recognizedIds: geneIds.recognizedIds,
|
|
83
|
+
geneName: geneIds.geneName,
|
|
84
|
+
isAutoMode,
|
|
85
|
+
isSequenceMode,
|
|
86
|
+
showIdentifierSelector: isAutoMode && (geneIds.recognizedIds.length > 0 || !!geneIds.geneName),
|
|
87
|
+
searchDescription: getSearchDescription({
|
|
88
|
+
selectedQueryId,
|
|
89
|
+
recognizedIds: geneIds.recognizedIds,
|
|
90
|
+
geneName: geneIds.geneName,
|
|
91
|
+
}),
|
|
92
|
+
searchDescriptionOr: getSearchDescription({
|
|
93
|
+
selectedQueryId,
|
|
94
|
+
recognizedIds: geneIds.recognizedIds,
|
|
95
|
+
geneName: geneIds.geneName,
|
|
96
|
+
joinWord: 'or',
|
|
97
|
+
}),
|
|
98
|
+
};
|
|
99
|
+
}
|