jbrowse-plugin-protein3d 0.4.4 → 0.4.6
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/dist/AddHighlightModel/ProteinToGenomeHighlightInner.js +1 -1
- package/dist/LaunchProteinView/components/AlphaFoldDBSearch.js +1 -3
- package/dist/LaunchProteinView/components/AlphaFoldDBSearchStatus.js +3 -5
- package/dist/LaunchProteinView/components/FoldseekResultsTable.js +5 -21
- package/dist/LaunchProteinView/components/FoldseekSearch.js +6 -2
- package/dist/LaunchProteinView/components/IdentifierSelector.d.ts +1 -2
- package/dist/LaunchProteinView/components/IdentifierSelector.js +2 -8
- package/dist/LaunchProteinView/components/MSATable.js +3 -3
- package/dist/LaunchProteinView/components/UserProvidedStructure.js +14 -8
- package/dist/LaunchProteinView/components/launchProteinAnnotationView.js +3 -1
- package/dist/LaunchProteinView/hooks/useAlphaFoldDBSearch.d.ts +1 -5
- package/dist/LaunchProteinView/hooks/useAlphaFoldDBSearch.js +11 -22
- package/dist/LaunchProteinView/hooks/useAlphaFoldData.d.ts +1 -6
- package/dist/LaunchProteinView/hooks/useAlphaFoldData.js +7 -23
- package/dist/LaunchProteinView/hooks/useTranscriptSelection.d.ts +2 -1
- package/dist/LaunchProteinView/hooks/useTranscriptSelection.js +14 -15
- package/dist/LaunchProteinView/hooks/useUniProtSearch.d.ts +1 -2
- package/dist/LaunchProteinView/hooks/useUniProtSearch.js +5 -25
- package/dist/LaunchProteinView/services/foldseekApi.d.ts +1 -1
- package/dist/LaunchProteinView/utils/launchViewUtils.js +6 -4
- package/dist/LaunchProteinView/utils/util.js +3 -7
- package/dist/ProteinView/components/AddStructureDialog.js +8 -5
- package/dist/ProteinView/components/HeaderStructureInfo.js +1 -1
- package/dist/ProteinView/components/ProteinFeatureTrack.js +8 -12
- package/dist/ProteinView/components/ProteinViewHeader.js +1 -4
- package/dist/jbrowse-plugin-protein3d.umd.production.min.js +15 -15
- 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 +2 -2
- package/src/AddHighlightModel/ProteinToGenomeHighlightInner.tsx +1 -1
- package/src/LaunchProteinView/components/AlphaFoldDBSearch.tsx +0 -8
- package/src/LaunchProteinView/components/AlphaFoldDBSearchStatus.tsx +6 -4
- package/src/LaunchProteinView/components/FoldseekResultsTable.tsx +7 -24
- package/src/LaunchProteinView/components/FoldseekSearch.tsx +13 -2
- package/src/LaunchProteinView/components/IdentifierSelector.tsx +1 -10
- package/src/LaunchProteinView/components/MSATable.tsx +3 -3
- package/src/LaunchProteinView/components/UserProvidedStructure.tsx +17 -10
- package/src/LaunchProteinView/components/launchProteinAnnotationView.ts +3 -1
- package/src/LaunchProteinView/hooks/useAlphaFoldDBSearch.ts +7 -23
- package/src/LaunchProteinView/hooks/useAlphaFoldData.ts +7 -45
- package/src/LaunchProteinView/hooks/useTranscriptSelection.ts +22 -15
- package/src/LaunchProteinView/hooks/useUniProtSearch.ts +4 -28
- package/src/LaunchProteinView/services/foldseekApi.ts +1 -1
- package/src/LaunchProteinView/services/lookupMethods.ts +9 -4
- package/src/LaunchProteinView/utils/launchViewUtils.ts +6 -4
- package/src/LaunchProteinView/utils/util.ts +5 -7
- package/src/ProteinView/components/AddStructureDialog.tsx +7 -7
- package/src/ProteinView/components/HeaderStructureInfo.tsx +1 -1
- package/src/ProteinView/components/ProteinFeatureTrack.tsx +15 -13
- package/src/ProteinView/components/ProteinViewHeader.tsx +9 -12
- package/src/version.ts +1 -1
- package/dist/LaunchProteinView/components/AlphaFoldEntrySelector.d.ts +0 -12
- package/dist/LaunchProteinView/components/AlphaFoldEntrySelector.js +0 -17
- package/dist/LaunchProteinView/hooks/useAlphaFoldUrl.d.ts +0 -13
- package/dist/LaunchProteinView/hooks/useAlphaFoldUrl.js +0 -17
- package/src/LaunchProteinView/components/AlphaFoldEntrySelector.tsx +0 -47
- package/src/LaunchProteinView/hooks/useAlphaFoldUrl.ts +0 -31
|
@@ -12,6 +12,6 @@ const ProteinToGenomeHighlightInner = observer(function ProteinToGenomeHighlight
|
|
|
12
12
|
const assembly = assemblyName
|
|
13
13
|
? assemblyManager.get(assemblyName)
|
|
14
14
|
: undefined;
|
|
15
|
-
return assembly && assemblyName ? (React.createElement(React.Fragment, null, proteinView?.structures.
|
|
15
|
+
return assembly && assemblyName ? (React.createElement(React.Fragment, null, proteinView?.structures.flatMap((structure, idx) => structure[field].map((r, idx2) => (React.createElement(Highlight, { key: `${r.refName}-${r.start}-${r.end}-${idx}-${idx2}`, start: r.start, end: r.end, refName: r.refName, assemblyName: assemblyName, model: model })))))) : null;
|
|
16
16
|
});
|
|
17
17
|
export default ProteinToGenomeHighlightInner;
|
|
@@ -5,7 +5,6 @@ import { DialogActions, DialogContent, Typography } from '@mui/material';
|
|
|
5
5
|
import { observer } from 'mobx-react';
|
|
6
6
|
import { makeStyles } from 'tss-react/mui';
|
|
7
7
|
import AlphaFoldDBSearchStatus from './AlphaFoldDBSearchStatus';
|
|
8
|
-
import AlphaFoldEntrySelector from './AlphaFoldEntrySelector';
|
|
9
8
|
import IdentifierSelector from './IdentifierSelector';
|
|
10
9
|
import ProteinViewActions from './ProteinViewActions';
|
|
11
10
|
import SequenceSearchStatus from './SequenceSearchStatus';
|
|
@@ -62,8 +61,7 @@ const AlphaFoldDBSearch = observer(function AlphaFoldDBSearch({ feature, model,
|
|
|
62
61
|
"directly and use \"Enter manually\" above, or use \"Search sequence against AlphaFoldDB API\" if available.")),
|
|
63
62
|
state.showStructureSelectors && (React.createElement(React.Fragment, null,
|
|
64
63
|
React.createElement("div", { className: classes.selectorsRow },
|
|
65
|
-
React.createElement(TranscriptSelector, { val: state.userSelection, setVal: state.setUserSelection, structureSequence: state.structureSequence, feature: feature, isoforms: state.transcriptOptions, isoformSequences: state.isoformSequences }),
|
|
66
|
-
state.showAlphaFoldEntrySelector && (React.createElement(AlphaFoldEntrySelector, { predictions: state.predictions, selectedEntryIndex: state.selectedEntryIndex, onSelectionChange: state.setSelectedEntryIndex }))),
|
|
64
|
+
React.createElement(TranscriptSelector, { val: state.userSelection, setVal: state.setUserSelection, structureSequence: state.structureSequence, feature: feature, isoforms: state.transcriptOptions, isoformSequences: state.isoformSequences })),
|
|
67
65
|
state.showSequenceSearchStatus && (React.createElement(SequenceSearchStatus, { isLoading: state.isSequenceSearchLoading, uniprotId: state.uniprotId, url: state.url, hasProteinSequence: !!state.userSelectedProteinSequence, sequenceSearchType: state.sequenceSearchType })),
|
|
68
66
|
state.showAlphaFoldDBSearchStatus && (React.createElement(AlphaFoldDBSearchStatus, { uniprotId: state.uniprotId, selectedTranscript: state.selectedTranscript, structureSequence: state.structureSequence, isoformSequences: state.isoformSequences, url: state.url }))))),
|
|
69
67
|
React.createElement(DialogActions, null,
|
|
@@ -10,15 +10,13 @@ function NotFound({ uniprotId }) {
|
|
|
10
10
|
React.createElement(ExternalLink, { href: `https://alphafold.ebi.ac.uk/search/text/${uniprotId}` }, "(search for results)")));
|
|
11
11
|
}
|
|
12
12
|
export default function AlphaFoldDBSearchStatus({ uniprotId, selectedTranscript, structureSequence, isoformSequences, url, }) {
|
|
13
|
-
const url2 = uniprotId
|
|
14
|
-
? `https://www.uniprot.org/uniprotkb/${uniprotId}/entry`
|
|
15
|
-
: undefined;
|
|
16
13
|
const [showAllProteinSequences, setShowAllProteinSequences] = useState(false);
|
|
17
14
|
return uniprotId ? (React.createElement(React.Fragment, null,
|
|
18
15
|
React.createElement("div", null,
|
|
19
16
|
React.createElement(Typography, null,
|
|
20
|
-
"UniProt link:
|
|
21
|
-
|
|
17
|
+
"UniProt link:",
|
|
18
|
+
' ',
|
|
19
|
+
React.createElement(ExternalLink, { href: `https://www.uniprot.org/uniprotkb/${uniprotId}/entry` }, uniprotId)),
|
|
22
20
|
React.createElement(Typography, null,
|
|
23
21
|
"AlphaFoldDB link: ",
|
|
24
22
|
React.createElement(ExternalLink, { href: url }, url))),
|
|
@@ -22,27 +22,11 @@ const useStyles = makeStyles()({
|
|
|
22
22
|
},
|
|
23
23
|
});
|
|
24
24
|
function flattenResults(results) {
|
|
25
|
-
const hits = []
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
for (const alignmentGroup of dbResult.alignments) {
|
|
31
|
-
if (!alignmentGroup) {
|
|
32
|
-
continue;
|
|
33
|
-
}
|
|
34
|
-
for (const alignment of alignmentGroup) {
|
|
35
|
-
if (!alignment) {
|
|
36
|
-
continue;
|
|
37
|
-
}
|
|
38
|
-
hits.push({
|
|
39
|
-
...alignment,
|
|
40
|
-
db: dbResult.db,
|
|
41
|
-
structureUrl: getStructureUrlFromTarget(alignment.target, dbResult.db),
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
25
|
+
const hits = results.results.flatMap(dbResult => (dbResult.alignments ?? []).flat().map(alignment => ({
|
|
26
|
+
...alignment,
|
|
27
|
+
db: dbResult.db,
|
|
28
|
+
structureUrl: getStructureUrlFromTarget(alignment.target, dbResult.db),
|
|
29
|
+
})));
|
|
46
30
|
hits.sort((a, b) => (a.eval ?? Infinity) - (b.eval ?? Infinity));
|
|
47
31
|
return hits.slice(0, 100);
|
|
48
32
|
}
|
|
@@ -76,8 +76,12 @@ const FoldseekSearch = observer(function FoldseekSearch({ feature, model, handle
|
|
|
76
76
|
statusMessage ? (React.createElement(LoadingEllipses, { variant: "subtitle2", message: statusMessage })) : null,
|
|
77
77
|
results ? (React.createElement(FoldseekResultsTable, { results: results, session: session, view: view, feature: feature, selectedTranscript: selectedTranscript, userProvidedTranscriptSequence: sequence, onClose: handleClose })) : null),
|
|
78
78
|
React.createElement(DialogActions, null,
|
|
79
|
-
React.createElement(Button, { variant: "contained", color: "secondary", onClick:
|
|
80
|
-
|
|
79
|
+
React.createElement(Button, { variant: "contained", color: "secondary", onClick: () => {
|
|
80
|
+
handleClose();
|
|
81
|
+
} }, "Cancel"),
|
|
82
|
+
results ? (React.createElement(Button, { variant: "outlined", onClick: () => {
|
|
83
|
+
reset();
|
|
84
|
+
} }, "New search")) : null,
|
|
81
85
|
!di3Sequence ? (React.createElement(Button, { variant: "contained", color: "primary", disabled: !canPredict, onClick: () => {
|
|
82
86
|
if (sequence.trim()) {
|
|
83
87
|
void predictStructure(sequence.trim());
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
interface IdentifierSelectorProps {
|
|
3
3
|
recognizedIds: string[];
|
|
4
|
-
uniprotId?: string;
|
|
5
4
|
geneName?: string;
|
|
6
5
|
selectedId: string;
|
|
7
6
|
onSelectedIdChange: (id: string) => void;
|
|
8
7
|
}
|
|
9
|
-
export default function IdentifierSelector({ recognizedIds,
|
|
8
|
+
export default function IdentifierSelector({ recognizedIds, geneName, selectedId, onSelectedIdChange, }: IdentifierSelectorProps): React.JSX.Element | null;
|
|
10
9
|
export {};
|
|
@@ -35,26 +35,20 @@ function getIdLabel(id) {
|
|
|
35
35
|
}
|
|
36
36
|
return id;
|
|
37
37
|
}
|
|
38
|
-
export default function IdentifierSelector({ recognizedIds,
|
|
38
|
+
export default function IdentifierSelector({ recognizedIds, geneName, selectedId, onSelectedIdChange, }) {
|
|
39
39
|
const [expanded, setExpanded] = useState(false);
|
|
40
40
|
// Build list of selectable options
|
|
41
41
|
const options = [
|
|
42
42
|
{ value: 'auto', label: 'Auto (try all)' },
|
|
43
43
|
...recognizedIds.map(id => ({ value: id, label: getIdLabel(id) })),
|
|
44
44
|
];
|
|
45
|
-
if (uniprotId) {
|
|
46
|
-
options.push({
|
|
47
|
-
value: `uniprot:${uniprotId}`,
|
|
48
|
-
label: `${uniprotId} (UniProt)`,
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
45
|
if (geneName) {
|
|
52
46
|
options.push({
|
|
53
47
|
value: `gene:${geneName}`,
|
|
54
48
|
label: `${geneName} (gene name)`,
|
|
55
49
|
});
|
|
56
50
|
}
|
|
57
|
-
if (recognizedIds.length === 0 && !
|
|
51
|
+
if (recognizedIds.length === 0 && !geneName) {
|
|
58
52
|
return null;
|
|
59
53
|
}
|
|
60
54
|
if (!expanded) {
|
|
@@ -18,7 +18,7 @@ export default function MSATable({ structureName, structureSequence, isoformSequ
|
|
|
18
18
|
{ ...val, seq: stripStopCodon(val.seq) },
|
|
19
19
|
]));
|
|
20
20
|
const exactMatchIsoformAndStructureSeq = Object.entries(removedStars).find(([_, val]) => structureSequence === val.seq);
|
|
21
|
-
const sname = `${structureName
|
|
21
|
+
const sname = `${structureName} (structure residues)`;
|
|
22
22
|
const maxKeyLen = max([
|
|
23
23
|
sname.length,
|
|
24
24
|
...Object.entries(removedStars).map(([_, val]) => getTranscriptDisplayName(val.feature).length),
|
|
@@ -38,8 +38,8 @@ export default function MSATable({ structureName, structureSequence, isoformSequ
|
|
|
38
38
|
? `${getTranscriptDisplayName(exactMatchIsoformAndStructureSeq[1].feature).padEnd(maxKeyLen)}* ${exactMatchIsoformAndStructureSeq[1].seq}`
|
|
39
39
|
: undefined,
|
|
40
40
|
...Object.entries(removedStars)
|
|
41
|
-
.
|
|
42
|
-
.
|
|
41
|
+
.filter(([k]) => k !== exactMatchIsoformAndStructureSeq?.[0])
|
|
42
|
+
.map(([_, val]) => `${getTranscriptDisplayName(val.feature).padEnd(maxKeyLen)} ${val.seq}`),
|
|
43
43
|
]
|
|
44
44
|
.filter(f => !!f)
|
|
45
45
|
.join('\n'), slotProps: {
|
|
@@ -40,16 +40,18 @@ const UserProvidedStructure = observer(function UserProvidedStructure({ feature,
|
|
|
40
40
|
const [submitError, setSubmitError] = useState();
|
|
41
41
|
const [structureURL, setStructureURL] = useState('');
|
|
42
42
|
const [showAllProteinSequences, setShowAllProteinSequences] = useState(false);
|
|
43
|
+
const activeFile = choice === 'file' ? file : undefined;
|
|
44
|
+
const activeURL = choice === 'file' ? '' : structureURL;
|
|
43
45
|
const options = getTranscriptFeatures(feature);
|
|
44
46
|
const view = getContainingView(model);
|
|
45
47
|
const { isoformSequences, error: isoformError } = useIsoformProteinSequences({
|
|
46
48
|
feature,
|
|
47
49
|
view,
|
|
48
50
|
});
|
|
49
|
-
const { sequences:
|
|
50
|
-
const { sequences:
|
|
51
|
-
const structureName =
|
|
52
|
-
const structureSequences =
|
|
51
|
+
const { sequences: localSequences, error: localFileError } = useLocalStructureFileSequence({ file: activeFile });
|
|
52
|
+
const { sequences: remoteSequences, error: remoteFileError } = useRemoteStructureFileSequence({ url: activeURL });
|
|
53
|
+
const structureName = activeFile?.name ?? activeURL.slice(activeURL.lastIndexOf('/') + 1);
|
|
54
|
+
const structureSequences = activeFile ? localSequences : remoteSequences;
|
|
53
55
|
const structureSequence = structureSequences?.[0];
|
|
54
56
|
const { userSelection, setUserSelection } = useTranscriptSelection({
|
|
55
57
|
options,
|
|
@@ -59,22 +61,26 @@ const UserProvidedStructure = observer(function UserProvidedStructure({ feature,
|
|
|
59
61
|
const selectedTranscript = options.find(val => getId(val) === userSelection);
|
|
60
62
|
const protein = userSelection ? isoformSequences?.[userSelection] : undefined;
|
|
61
63
|
const error = isoformError ?? submitError ?? localFileError ?? remoteFileError;
|
|
62
|
-
const canLaunch = !!(
|
|
64
|
+
const canLaunch = !!(activeURL || activeFile) && !!protein && !!selectedTranscript;
|
|
63
65
|
const sequencesDiffer = !!protein?.seq &&
|
|
64
66
|
!!structureSequence &&
|
|
65
67
|
stripStopCodon(protein.seq) !== structureSequence;
|
|
66
68
|
const handleLaunch = async () => {
|
|
67
|
-
if (!protein || !selectedTranscript
|
|
69
|
+
if (!protein || !selectedTranscript) {
|
|
68
70
|
return;
|
|
69
71
|
}
|
|
70
72
|
try {
|
|
71
|
-
const structureData =
|
|
73
|
+
const structureData = activeFile ? await activeFile.text() : undefined;
|
|
74
|
+
const url = activeURL ? activeURL : undefined;
|
|
75
|
+
if (!url && !structureData) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
72
78
|
launch3DProteinView({
|
|
73
79
|
session,
|
|
74
80
|
view,
|
|
75
81
|
feature,
|
|
76
82
|
selectedTranscript,
|
|
77
|
-
url
|
|
83
|
+
url,
|
|
78
84
|
data: structureData,
|
|
79
85
|
userProvidedTranscriptSequence: protein.seq,
|
|
80
86
|
alignmentAlgorithm,
|
|
@@ -23,7 +23,9 @@ export async function launchProteinAnnotationView({ session, feature, selectedTr
|
|
|
23
23
|
uniprotId,
|
|
24
24
|
getGeneDisplayName(feature),
|
|
25
25
|
getTranscriptDisplayName(selectedTranscript),
|
|
26
|
-
]
|
|
26
|
+
]
|
|
27
|
+
.filter(s => !!s)
|
|
28
|
+
.join(' - '),
|
|
27
29
|
});
|
|
28
30
|
// Register the 1D view for linked highlighting
|
|
29
31
|
if (connectedViewId && selectedTranscript) {
|
|
@@ -15,7 +15,7 @@ export default function useAlphaFoldDBSearch({ feature, view, }: {
|
|
|
15
15
|
sequenceSearchType: SequenceSearchType;
|
|
16
16
|
setSequenceSearchType: import("react").Dispatch<import("react").SetStateAction<SequenceSearchType>>;
|
|
17
17
|
selectedUniprotId: string | undefined;
|
|
18
|
-
setSelectedUniprotId: (
|
|
18
|
+
setSelectedUniprotId: import("react").Dispatch<import("react").SetStateAction<string | undefined>>;
|
|
19
19
|
userSelection: string | undefined;
|
|
20
20
|
setUserSelection: import("react").Dispatch<import("react").SetStateAction<string | undefined>>;
|
|
21
21
|
transcriptOptions: Feature[];
|
|
@@ -29,9 +29,6 @@ export default function useAlphaFoldDBSearch({ feature, view, }: {
|
|
|
29
29
|
seq: string;
|
|
30
30
|
} | undefined;
|
|
31
31
|
uniprotEntries: import("../services/lookupMethods").UniProtEntry[];
|
|
32
|
-
predictions: import("./useAlphaFoldUrl").AlphaFoldPrediction[] | undefined;
|
|
33
|
-
selectedEntryIndex: number;
|
|
34
|
-
setSelectedEntryIndex: import("react").Dispatch<import("react").SetStateAction<number>>;
|
|
35
32
|
recognizedIds: string[];
|
|
36
33
|
geneName: string | undefined;
|
|
37
34
|
featureUniprotId: string | undefined;
|
|
@@ -50,7 +47,6 @@ export default function useAlphaFoldDBSearch({ feature, view, }: {
|
|
|
50
47
|
selectedTableAccession: string | undefined;
|
|
51
48
|
showUniprotResults: boolean;
|
|
52
49
|
showNoResults: boolean;
|
|
53
|
-
showAlphaFoldEntrySelector: boolean;
|
|
54
50
|
showSequenceSearchStatus: boolean;
|
|
55
51
|
showAlphaFoldDBSearchStatus: boolean;
|
|
56
52
|
isLoading: boolean;
|
|
@@ -3,9 +3,10 @@ import useAlphaFoldData from './useAlphaFoldData';
|
|
|
3
3
|
import useAlphaFoldSequenceSearch from './useAlphaFoldSequenceSearch';
|
|
4
4
|
import useDebouncedValue from './useDebouncedValue';
|
|
5
5
|
import useIsoformProteinSequences from './useIsoformProteinSequences';
|
|
6
|
+
import useTranscriptSelection from './useTranscriptSelection';
|
|
6
7
|
import useUniProtSearch from './useUniProtSearch';
|
|
7
8
|
import getSearchDescription from '../utils/getSearchDescription';
|
|
8
|
-
import { extractFeatureIdentifiers, getId, getTranscriptFeatures,
|
|
9
|
+
import { extractFeatureIdentifiers, getId, getTranscriptFeatures, stripStopCodon, } from '../utils/util';
|
|
9
10
|
export default function useAlphaFoldDBSearch({ feature, view, }) {
|
|
10
11
|
const [lookupMode, setLookupMode] = useState('auto');
|
|
11
12
|
const [manualUniprotId, setManualUniprotId] = useState('');
|
|
@@ -13,7 +14,6 @@ export default function useAlphaFoldDBSearch({ feature, view, }) {
|
|
|
13
14
|
const [selectedQueryId, setSelectedQueryId] = useState(geneIds.recognizedIds[0] ?? 'auto');
|
|
14
15
|
const [sequenceSearchType, setSequenceSearchType] = useState('md5');
|
|
15
16
|
const [selectedUniprotId, setSelectedUniprotId] = useState();
|
|
16
|
-
const [userTranscriptId, setUserTranscriptId] = useState();
|
|
17
17
|
const transcriptOptions = getTranscriptFeatures(feature);
|
|
18
18
|
const featureUniprotId = geneIds.uniprotId;
|
|
19
19
|
const effectiveLookupMode = lookupMode === 'auto' && featureUniprotId ? 'feature' : lookupMode;
|
|
@@ -38,18 +38,15 @@ export default function useAlphaFoldDBSearch({ feature, view, }) {
|
|
|
38
38
|
: effectiveLookupMode === 'manual'
|
|
39
39
|
? debouncedManualUniprotId
|
|
40
40
|
: undefined;
|
|
41
|
-
const {
|
|
41
|
+
const { isLoading: isAlphaFoldLoading, error: alphaFoldError, url: alphaFoldUrl, confidenceUrl: alphaFoldConfidenceUrl, structureSequence: alphaFoldStructureSequence, } = useAlphaFoldData({
|
|
42
42
|
uniprotId: isSequenceMode ? undefined : uniprotId,
|
|
43
43
|
});
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
})?.id();
|
|
51
|
-
}
|
|
52
|
-
const effectiveTranscriptId = userTranscriptId ?? autoTranscriptId;
|
|
44
|
+
const { userSelection: effectiveTranscriptId, setUserSelection } = useTranscriptSelection({
|
|
45
|
+
options: transcriptOptions,
|
|
46
|
+
isoformSequences,
|
|
47
|
+
structureSequence: alphaFoldStructureSequence,
|
|
48
|
+
resetKey: uniprotId,
|
|
49
|
+
});
|
|
53
50
|
const selectedTranscript = transcriptOptions.find(f => getId(f) === effectiveTranscriptId);
|
|
54
51
|
const userSelectedProteinSequence = effectiveTranscriptId
|
|
55
52
|
? isoformSequences?.[effectiveTranscriptId]
|
|
@@ -68,10 +65,6 @@ export default function useAlphaFoldDBSearch({ feature, view, }) {
|
|
|
68
65
|
? seqSearchStructureSequence
|
|
69
66
|
: alphaFoldStructureSequence;
|
|
70
67
|
const finalUniprotId = isSequenceMode ? seqSearchUniprotId : uniprotId;
|
|
71
|
-
const setSelectedUniprotIdWithReset = (id) => {
|
|
72
|
-
setSelectedUniprotId(id);
|
|
73
|
-
setUserTranscriptId(undefined);
|
|
74
|
-
};
|
|
75
68
|
const loadingStatuses = [
|
|
76
69
|
isLookupLoading && 'Looking up UniProt ID',
|
|
77
70
|
isIsoformLoading && 'Loading protein sequences from transcript isoforms',
|
|
@@ -96,17 +89,14 @@ export default function useAlphaFoldDBSearch({ feature, view, }) {
|
|
|
96
89
|
sequenceSearchType,
|
|
97
90
|
setSequenceSearchType,
|
|
98
91
|
selectedUniprotId,
|
|
99
|
-
setSelectedUniprotId
|
|
92
|
+
setSelectedUniprotId,
|
|
100
93
|
userSelection: effectiveTranscriptId,
|
|
101
|
-
setUserSelection
|
|
94
|
+
setUserSelection,
|
|
102
95
|
transcriptOptions,
|
|
103
96
|
selectedTranscript,
|
|
104
97
|
isoformSequences,
|
|
105
98
|
userSelectedProteinSequence,
|
|
106
99
|
uniprotEntries,
|
|
107
|
-
predictions,
|
|
108
|
-
selectedEntryIndex,
|
|
109
|
-
setSelectedEntryIndex,
|
|
110
100
|
recognizedIds: geneIds.recognizedIds,
|
|
111
101
|
geneName: geneIds.geneName,
|
|
112
102
|
featureUniprotId,
|
|
@@ -144,7 +134,6 @@ export default function useAlphaFoldDBSearch({ feature, view, }) {
|
|
|
144
134
|
isAutoMode &&
|
|
145
135
|
!isLookupLoading &&
|
|
146
136
|
uniprotEntries.length === 0,
|
|
147
|
-
showAlphaFoldEntrySelector: !!predictions && !isSequenceMode,
|
|
148
137
|
showSequenceSearchStatus: isSequenceMode,
|
|
149
138
|
showAlphaFoldDBSearchStatus: !!finalStructureSequence && !!finalUniprotId && !isSequenceMode,
|
|
150
139
|
isLoading,
|
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
export default function useAlphaFoldData({ uniprotId
|
|
1
|
+
export default function useAlphaFoldData({ uniprotId }: {
|
|
2
2
|
uniprotId?: string;
|
|
3
|
-
useApiSearch?: boolean;
|
|
4
3
|
}): {
|
|
5
|
-
predictions: import("./useAlphaFoldUrl").AlphaFoldPrediction[] | undefined;
|
|
6
4
|
isLoading: boolean;
|
|
7
5
|
error: any;
|
|
8
|
-
selectedEntryIndex: number;
|
|
9
|
-
setSelectedEntryIndex: import("react").Dispatch<import("react").SetStateAction<number>>;
|
|
10
|
-
selectedPrediction: import("./useAlphaFoldUrl").AlphaFoldPrediction | undefined;
|
|
11
6
|
url: string | undefined;
|
|
12
7
|
confidenceUrl: string | undefined;
|
|
13
8
|
structureSequence: string | undefined;
|
|
@@ -1,34 +1,18 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
2
|
-
import useAlphaFoldUrl from './useAlphaFoldUrl';
|
|
3
1
|
import useRemoteStructureFileSequence from './useRemoteStructureFileSequence';
|
|
4
2
|
import { getAlphaFoldConfidenceUrl, getAlphaFoldStructureUrl, } from '../utils/launchViewUtils';
|
|
5
|
-
export default function useAlphaFoldData({ uniprotId
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
? getAlphaFoldStructureUrl(uniprotId)
|
|
9
|
-
: undefined;
|
|
10
|
-
const hardcodedConfidenceUrl = uniprotId
|
|
3
|
+
export default function useAlphaFoldData({ uniprotId }) {
|
|
4
|
+
const url = uniprotId ? getAlphaFoldStructureUrl(uniprotId) : undefined;
|
|
5
|
+
const confidenceUrl = uniprotId
|
|
11
6
|
? getAlphaFoldConfidenceUrl(uniprotId)
|
|
12
7
|
: undefined;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const url = useApiSearch ? selectedPrediction?.cifUrl : hardcodedUrl;
|
|
17
|
-
const confidenceUrl = selectedPrediction?.plddtDocUrl ?? hardcodedConfidenceUrl;
|
|
18
|
-
// Always fetch sequence from structure file
|
|
19
|
-
const { sequences, isLoading: isSequenceLoading, error: sequenceError, } = useRemoteStructureFileSequence({ url });
|
|
20
|
-
const structureSequence = sequences?.[0];
|
|
21
|
-
const isLoading = isApiLoading || isSequenceLoading;
|
|
22
|
-
const error = apiError ?? sequenceError;
|
|
8
|
+
const { sequences, isLoading, error } = useRemoteStructureFileSequence({
|
|
9
|
+
url,
|
|
10
|
+
});
|
|
23
11
|
return {
|
|
24
|
-
predictions,
|
|
25
12
|
isLoading,
|
|
26
13
|
error,
|
|
27
|
-
selectedEntryIndex,
|
|
28
|
-
setSelectedEntryIndex,
|
|
29
|
-
selectedPrediction,
|
|
30
14
|
url,
|
|
31
15
|
confidenceUrl,
|
|
32
|
-
structureSequence,
|
|
16
|
+
structureSequence: sequences?.[0],
|
|
33
17
|
};
|
|
34
18
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { Feature } from '@jbrowse/core/util';
|
|
2
|
-
export default function useTranscriptSelection({ options, isoformSequences, structureSequence, }: {
|
|
2
|
+
export default function useTranscriptSelection({ options, isoformSequences, structureSequence, resetKey, }: {
|
|
3
3
|
options: Feature[];
|
|
4
4
|
isoformSequences?: Record<string, {
|
|
5
5
|
feature: Feature;
|
|
6
6
|
seq: string;
|
|
7
7
|
}>;
|
|
8
8
|
structureSequence?: string;
|
|
9
|
+
resetKey?: string;
|
|
9
10
|
}): {
|
|
10
11
|
userSelection: string | undefined;
|
|
11
12
|
setUserSelection: import("react").Dispatch<import("react").SetStateAction<string | undefined>>;
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import { useMemo, useState } from 'react';
|
|
2
2
|
import { selectBestTranscript } from '../utils/util';
|
|
3
|
-
export default function useTranscriptSelection({ options, isoformSequences, structureSequence, }) {
|
|
3
|
+
export default function useTranscriptSelection({ options, isoformSequences, structureSequence, resetKey, }) {
|
|
4
4
|
const [userSelection, setUserSelection] = useState();
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return { userSelection: effectiveSelection, setUserSelection };
|
|
5
|
+
const [prevResetKey, setPrevResetKey] = useState(resetKey);
|
|
6
|
+
if (resetKey !== prevResetKey) {
|
|
7
|
+
setPrevResetKey(resetKey);
|
|
8
|
+
setUserSelection(undefined);
|
|
9
|
+
}
|
|
10
|
+
const autoSelection = useMemo(() => isoformSequences !== undefined
|
|
11
|
+
? selectBestTranscript({
|
|
12
|
+
options,
|
|
13
|
+
isoformSequences,
|
|
14
|
+
structureSequence,
|
|
15
|
+
})?.id()
|
|
16
|
+
: undefined, [options, structureSequence, isoformSequences]);
|
|
17
|
+
return { userSelection: userSelection ?? autoSelection, setUserSelection };
|
|
19
18
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { UniProtEntry } from '../services/lookupMethods';
|
|
2
|
-
export default function useUniProtSearch({ recognizedIds,
|
|
2
|
+
export default function useUniProtSearch({ recognizedIds, geneId, geneName, selectedQueryId, enabled, }: {
|
|
3
3
|
recognizedIds?: string[];
|
|
4
|
-
uniprotId?: string;
|
|
5
4
|
geneId?: string;
|
|
6
5
|
geneName?: string;
|
|
7
6
|
selectedQueryId?: string;
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import useSWR from 'swr';
|
|
2
2
|
import { searchUniProtEntries } from '../services/lookupMethods';
|
|
3
3
|
import { isRecognizedDatabaseId } from '../utils/util';
|
|
4
|
-
export default function useUniProtSearch({ recognizedIds = [],
|
|
5
|
-
// If selected ID is a UniProt accession (prefixed with uniprot:), return it directly
|
|
6
|
-
const isDirectUniProt = selectedQueryId.startsWith('uniprot:');
|
|
7
|
-
const directUniProtId = isDirectUniProt
|
|
8
|
-
? selectedQueryId.replace('uniprot:', '')
|
|
9
|
-
: undefined;
|
|
4
|
+
export default function useUniProtSearch({ recognizedIds = [], geneId, geneName, selectedQueryId = 'auto', enabled = true, }) {
|
|
10
5
|
// Determine what to search based on selectedQueryId
|
|
11
6
|
let idsToSearch = [];
|
|
12
7
|
let geneNameToSearch;
|
|
@@ -20,16 +15,10 @@ export default function useUniProtSearch({ recognizedIds = [], uniprotId, geneId
|
|
|
20
15
|
else if (isRecognizedDatabaseId(selectedQueryId)) {
|
|
21
16
|
idsToSearch = [selectedQueryId];
|
|
22
17
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
? [
|
|
28
|
-
'uniprotSearch',
|
|
29
|
-
selectedQueryId,
|
|
30
|
-
idsToSearch.join(','),
|
|
31
|
-
geneNameToSearch,
|
|
32
|
-
]
|
|
18
|
+
const hasValidId = idsToSearch.some(id => isRecognizedDatabaseId(id)) ||
|
|
19
|
+
Boolean(geneNameToSearch);
|
|
20
|
+
const { data, error, isLoading } = useSWR(enabled && hasValidId
|
|
21
|
+
? ['uniprotSearch', selectedQueryId, idsToSearch.join(','), geneNameToSearch]
|
|
33
22
|
: null, async () => searchUniProtEntries({
|
|
34
23
|
recognizedIds: idsToSearch,
|
|
35
24
|
geneId,
|
|
@@ -40,15 +29,6 @@ export default function useUniProtSearch({ recognizedIds = [], uniprotId, geneId
|
|
|
40
29
|
revalidateIfStale: false,
|
|
41
30
|
keepPreviousData: true,
|
|
42
31
|
});
|
|
43
|
-
// If direct UniProt accession selected, return it as a synthetic entry
|
|
44
|
-
if (isDirectUniProt && directUniProtId) {
|
|
45
|
-
return {
|
|
46
|
-
entries: [{ accession: directUniProtId, isReviewed: true }],
|
|
47
|
-
isLoading: false,
|
|
48
|
-
error: undefined,
|
|
49
|
-
hasValidId: true,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
32
|
return {
|
|
53
33
|
entries: data ?? [],
|
|
54
34
|
isLoading,
|
|
@@ -55,7 +55,7 @@ export interface FoldseekAlignment {
|
|
|
55
55
|
}
|
|
56
56
|
export interface FoldseekDatabaseResult {
|
|
57
57
|
db: string;
|
|
58
|
-
alignments?:
|
|
58
|
+
alignments?: FoldseekAlignment[][];
|
|
59
59
|
}
|
|
60
60
|
export interface FoldseekResult {
|
|
61
61
|
query: {
|
|
@@ -54,12 +54,13 @@ function formatViewName(prefix, feature, selectedTranscript, uniprotId) {
|
|
|
54
54
|
getGeneDisplayName(feature),
|
|
55
55
|
getTranscriptDisplayName(selectedTranscript),
|
|
56
56
|
]),
|
|
57
|
-
]
|
|
57
|
+
]
|
|
58
|
+
.filter(s => !!s)
|
|
59
|
+
.join(' - ');
|
|
58
60
|
}
|
|
59
61
|
export function launch3DProteinView({ session, view, feature, selectedTranscript, uniprotId, url, data, userProvidedTranscriptSequence, alignmentAlgorithm, displayName, connectedMsaViewId, }) {
|
|
60
|
-
|
|
62
|
+
const snap = {
|
|
61
63
|
type: 'ProteinView',
|
|
62
|
-
isFloating: true,
|
|
63
64
|
alignmentAlgorithm,
|
|
64
65
|
connectedMsaViewId,
|
|
65
66
|
structures: [
|
|
@@ -73,7 +74,8 @@ export function launch3DProteinView({ session, view, feature, selectedTranscript
|
|
|
73
74
|
],
|
|
74
75
|
displayName: displayName ??
|
|
75
76
|
formatViewName('Protein view', feature, selectedTranscript, uniprotId),
|
|
76
|
-
}
|
|
77
|
+
};
|
|
78
|
+
return session.addView('ProteinView', snap);
|
|
77
79
|
}
|
|
78
80
|
export async function launch1DProteinView({ session, view, feature, selectedTranscript, uniprotId, confidenceUrl, }) {
|
|
79
81
|
if (!uniprotId || !isSessionWithAddTracks(session)) {
|
|
@@ -64,13 +64,9 @@ export function isRecognizedDatabaseId(id) {
|
|
|
64
64
|
* Get the database type for a recognized ID (used for UniProt xref queries)
|
|
65
65
|
*/
|
|
66
66
|
export function getDatabaseTypeForId(id) {
|
|
67
|
-
if (ensemblGenePattern.test(id)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (ensemblTranscriptPattern.test(id)) {
|
|
71
|
-
return 'ensembl';
|
|
72
|
-
}
|
|
73
|
-
if (ensemblProteinPattern.test(id)) {
|
|
67
|
+
if (ensemblGenePattern.test(id) ||
|
|
68
|
+
ensemblTranscriptPattern.test(id) ||
|
|
69
|
+
ensemblProteinPattern.test(id)) {
|
|
74
70
|
return 'ensembl';
|
|
75
71
|
}
|
|
76
72
|
if (refSeqTranscriptPattern.test(id) || refSeqProteinPattern.test(id)) {
|
|
@@ -21,19 +21,22 @@ const AddStructureDialog = observer(function AddStructureDialog({ model, }) {
|
|
|
21
21
|
};
|
|
22
22
|
const handleAdd = async () => {
|
|
23
23
|
try {
|
|
24
|
-
let url
|
|
24
|
+
let url;
|
|
25
25
|
let data;
|
|
26
26
|
if (choice === 'pdb' && pdbId) {
|
|
27
27
|
url = getPdbStructureUrl(pdbId);
|
|
28
28
|
}
|
|
29
|
-
if (choice === 'uniprot' && uniprotId) {
|
|
29
|
+
else if (choice === 'uniprot' && uniprotId) {
|
|
30
30
|
url = getAlphaFoldStructureUrl(uniprotId.toUpperCase());
|
|
31
31
|
}
|
|
32
|
-
if (choice === '
|
|
32
|
+
else if (choice === 'url' && structureURL) {
|
|
33
|
+
url = structureURL;
|
|
34
|
+
}
|
|
35
|
+
else if (choice === 'file' && file) {
|
|
33
36
|
data = await file.text();
|
|
34
37
|
}
|
|
35
|
-
if (url || data) {
|
|
36
|
-
await model.addStructureAndSuperpose({ url
|
|
38
|
+
if (url !== undefined || data !== undefined) {
|
|
39
|
+
await model.addStructureAndSuperpose({ url, data });
|
|
37
40
|
handleClose();
|
|
38
41
|
}
|
|
39
42
|
}
|
|
@@ -4,7 +4,7 @@ const HeaderStructureInfo = observer(function HeaderStructureInfo({ model, }) {
|
|
|
4
4
|
const { structures } = model;
|
|
5
5
|
return structures.map((structure, idx) => {
|
|
6
6
|
const { hoverString } = structure;
|
|
7
|
-
return (React.createElement("span", { key:
|
|
7
|
+
return (React.createElement("span", { key: idx },
|
|
8
8
|
hoverString ? `Hover: ${hoverString}` : '',
|
|
9
9
|
"\u00A0"));
|
|
10
10
|
});
|