jbrowse-plugin-msaview 2.8.1 → 2.9.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/dist/LaunchMsaView/components/{NCBIBlastQuery/NCBIBlastRIDPanel.d.ts → BlastQuery/BlastAutomaticPanel.d.ts} +2 -3
- package/dist/LaunchMsaView/components/{NCBIBlastQuery/NCBIBlastAutomaticPanel.js → BlastQuery/BlastAutomaticPanel.js} +6 -25
- package/dist/LaunchMsaView/components/{NCBIBlastQuery/NCBIBlastManualPanel.d.ts → BlastQuery/BlastManualPanel.d.ts} +2 -3
- package/dist/LaunchMsaView/components/{NCBIBlastQuery/NCBIBlastManualPanel.js → BlastQuery/BlastManualPanel.js} +7 -4
- package/dist/LaunchMsaView/components/{NCBIBlastQuery/NCBIBlastMethodSelector.d.ts → BlastQuery/BlastMethodSelector.d.ts} +2 -2
- package/dist/LaunchMsaView/components/{NCBIBlastQuery/NCBIBlastMethodSelector.js → BlastQuery/BlastMethodSelector.js} +1 -2
- package/dist/LaunchMsaView/components/{NCBIBlastQuery/NCBIBlastPanel.d.ts → BlastQuery/BlastPanel.d.ts} +3 -12
- package/dist/LaunchMsaView/components/{NCBIBlastQuery/NCBIBlastPanel.js → BlastQuery/BlastPanel.js} +14 -16
- package/dist/LaunchMsaView/components/BlastQuery/BlastSettingsDialog.d.ts +8 -0
- package/dist/LaunchMsaView/components/{NCBIBlastQuery/NCBISettingsDialog.js → BlastQuery/BlastSettingsDialog.js} +13 -9
- package/dist/LaunchMsaView/components/{NCBIBlastQuery → BlastQuery}/CachedBlastResults.js +1 -1
- package/dist/LaunchMsaView/components/BlastQuery/consts.d.ts +12 -0
- package/dist/LaunchMsaView/components/BlastQuery/consts.js +17 -0
- package/dist/LaunchMsaView/components/LaunchMsaViewDialog.js +3 -3
- package/dist/LaunchMsaView/components/OrthologQuery/OrthologPanel.js +1 -1
- package/dist/LaunchMsaViewExtensionPoint/index.js +11 -4
- package/dist/MsaViewPanel/components/JobLink.d.ts +5 -0
- package/dist/MsaViewPanel/components/JobLink.js +13 -0
- package/dist/MsaViewPanel/components/LoadingBLAST.d.ts +1 -2
- package/dist/MsaViewPanel/components/LoadingBLAST.js +8 -15
- package/dist/MsaViewPanel/components/MsaViewPanel.js +1 -1
- package/dist/MsaViewPanel/doLaunchBlast.js +11 -19
- package/dist/MsaViewPanel/doLaunchOrthologs.js +44 -21
- package/dist/MsaViewPanel/doLaunchOrthologs.test.d.ts +1 -0
- package/dist/MsaViewPanel/doLaunchOrthologs.test.js +127 -0
- package/dist/MsaViewPanel/model.d.ts +15 -7
- package/dist/jbrowse-plugin-msaview.umd.production.min.js +32 -32
- package/dist/jbrowse-plugin-msaview.umd.production.min.js.map +4 -4
- package/dist/utils/blastCache.d.ts +8 -4
- package/dist/utils/blastCache.js +4 -5
- package/dist/utils/ebiBlast.d.ts +52 -0
- package/dist/utils/ebiBlast.js +63 -0
- package/dist/utils/ebiJobDispatcher.d.ts +33 -0
- package/dist/utils/ebiJobDispatcher.js +55 -0
- package/dist/utils/fetch.js +24 -1
- package/dist/utils/msa.d.ts +1 -1
- package/dist/utils/msa.js +25 -32
- package/dist/utils/types.d.ts +9 -14
- package/dist/utils/useLocalStorage.d.ts +1 -0
- package/dist/utils/useLocalStorage.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/src/LaunchMsaView/components/{NCBIBlastQuery/NCBIBlastAutomaticPanel.tsx → BlastQuery/BlastAutomaticPanel.tsx} +13 -59
- package/src/LaunchMsaView/components/{NCBIBlastQuery/NCBIBlastManualPanel.tsx → BlastQuery/BlastManualPanel.tsx} +7 -6
- package/src/LaunchMsaView/components/{NCBIBlastQuery/NCBIBlastMethodSelector.tsx → BlastQuery/BlastMethodSelector.tsx} +2 -7
- package/src/LaunchMsaView/components/{NCBIBlastQuery/NCBIBlastPanel.tsx → BlastQuery/BlastPanel.tsx} +21 -25
- package/src/LaunchMsaView/components/{NCBIBlastQuery/NCBISettingsDialog.tsx → BlastQuery/BlastSettingsDialog.tsx} +26 -13
- package/src/LaunchMsaView/components/{NCBIBlastQuery → BlastQuery}/CachedBlastResults.tsx +1 -1
- package/src/LaunchMsaView/components/BlastQuery/consts.ts +22 -0
- package/src/LaunchMsaView/components/LaunchMsaViewDialog.tsx +5 -7
- package/src/LaunchMsaView/components/OrthologQuery/OrthologPanel.tsx +2 -2
- package/src/LaunchMsaViewExtensionPoint/index.ts +31 -4
- package/src/MsaViewPanel/components/JobLink.tsx +17 -0
- package/src/MsaViewPanel/components/LoadingBLAST.tsx +10 -41
- package/src/MsaViewPanel/components/MsaViewPanel.tsx +1 -1
- package/src/MsaViewPanel/doLaunchBlast.ts +12 -28
- package/src/MsaViewPanel/doLaunchOrthologs.test.ts +159 -0
- package/src/MsaViewPanel/doLaunchOrthologs.ts +49 -20
- package/src/MsaViewPanel/model.ts +15 -8
- package/src/utils/blastCache.ts +8 -9
- package/src/utils/ebiBlast.ts +114 -0
- package/src/utils/ebiJobDispatcher.ts +91 -0
- package/src/utils/fetch.ts +26 -1
- package/src/utils/msa.ts +26 -47
- package/src/utils/types.ts +8 -13
- package/src/utils/useLocalStorage.ts +1 -1
- package/src/version.ts +1 -1
- package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastAutomaticPanel.d.ts +0 -10
- package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastRIDPanel.js +0 -74
- package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBISettingsDialog.d.ts +0 -5
- package/dist/LaunchMsaView/components/NCBIBlastQuery/consts.d.ts +0 -7
- package/dist/LaunchMsaView/components/NCBIBlastQuery/consts.js +0 -4
- package/dist/MsaViewPanel/components/RIDLink.d.ts +0 -6
- package/dist/MsaViewPanel/components/RIDLink.js +0 -12
- package/dist/utils/ncbiBlast.d.ts +0 -30
- package/dist/utils/ncbiBlast.js +0 -84
- package/src/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastRIDPanel.tsx +0 -137
- package/src/LaunchMsaView/components/NCBIBlastQuery/consts.ts +0 -10
- package/src/MsaViewPanel/components/RIDLink.tsx +0 -19
- package/src/utils/ncbiBlast.ts +0 -143
- /package/dist/LaunchMsaView/components/{NCBIBlastQuery → BlastQuery}/CachedBlastResults.d.ts +0 -0
- /package/dist/LaunchMsaView/components/{NCBIBlastQuery → BlastQuery}/MsaAlgorithmSelect.d.ts +0 -0
- /package/dist/LaunchMsaView/components/{NCBIBlastQuery → BlastQuery}/MsaAlgorithmSelect.js +0 -0
- /package/dist/LaunchMsaView/components/{NCBIBlastQuery → BlastQuery}/blastLaunchView.d.ts +0 -0
- /package/dist/LaunchMsaView/components/{NCBIBlastQuery → BlastQuery}/blastLaunchView.js +0 -0
- /package/dist/LaunchMsaView/components/{NCBIBlastQuery → BlastQuery}/useCachedBlastResults.d.ts +0 -0
- /package/dist/LaunchMsaView/components/{NCBIBlastQuery → BlastQuery}/useCachedBlastResults.js +0 -0
- /package/src/LaunchMsaView/components/{NCBIBlastQuery → BlastQuery}/MsaAlgorithmSelect.tsx +0 -0
- /package/src/LaunchMsaView/components/{NCBIBlastQuery → BlastQuery}/blastLaunchView.ts +0 -0
- /package/src/LaunchMsaView/components/{NCBIBlastQuery → BlastQuery}/useCachedBlastResults.ts +0 -0
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { AbstractTrackModel, Feature } from '@jbrowse/core/util';
|
|
3
|
-
declare const
|
|
3
|
+
declare const BlastAutomaticPanel: ({ handleClose, feature, model, children, }: {
|
|
4
4
|
model: AbstractTrackModel;
|
|
5
5
|
feature: Feature;
|
|
6
|
-
baseUrl: string;
|
|
7
6
|
handleClose: () => void;
|
|
8
7
|
children: React.ReactNode;
|
|
9
8
|
}) => React.JSX.Element;
|
|
10
|
-
export default
|
|
9
|
+
export default BlastAutomaticPanel;
|
|
@@ -6,7 +6,7 @@ import { makeStyles } from 'tss-react/mui';
|
|
|
6
6
|
import CachedBlastResults from './CachedBlastResults';
|
|
7
7
|
import MsaAlgorithmSelect from './MsaAlgorithmSelect';
|
|
8
8
|
import { blastLaunchView } from './blastLaunchView';
|
|
9
|
-
import { blastDatabaseOptions,
|
|
9
|
+
import { blastDatabaseOptions, defaultBlastDatabase } from './consts';
|
|
10
10
|
import { useCachedBlastResults } from './useCachedBlastResults';
|
|
11
11
|
import TextField2 from '../../../components/TextField2';
|
|
12
12
|
import { getBlastViewTitle, getGeneIdentifiers, getLinearGenomeView, } from '../../util';
|
|
@@ -18,13 +18,6 @@ const useStyles = makeStyles()({
|
|
|
18
18
|
selectField: {
|
|
19
19
|
width: 150,
|
|
20
20
|
},
|
|
21
|
-
databaseFieldContainer: {
|
|
22
|
-
display: 'flex',
|
|
23
|
-
},
|
|
24
|
-
clusterSeqMessage: {
|
|
25
|
-
marginLeft: 4,
|
|
26
|
-
alignContent: 'center',
|
|
27
|
-
},
|
|
28
21
|
cachedResultsAccordion: {
|
|
29
22
|
marginTop: 20,
|
|
30
23
|
},
|
|
@@ -32,13 +25,12 @@ const useStyles = makeStyles()({
|
|
|
32
25
|
marginTop: 20,
|
|
33
26
|
},
|
|
34
27
|
});
|
|
35
|
-
const
|
|
28
|
+
const BlastAutomaticPanel = observer(function ({ handleClose, feature, model, children, }) {
|
|
36
29
|
const { classes } = useStyles();
|
|
37
30
|
const view = getLinearGenomeView(model);
|
|
38
31
|
const [launchViewError, setLaunchViewError] = useState();
|
|
39
|
-
const [selectedBlastDatabase, setSelectedBlastDatabase] = useState(
|
|
32
|
+
const [selectedBlastDatabase, setSelectedBlastDatabase] = useState(defaultBlastDatabase);
|
|
40
33
|
const [selectedMsaAlgorithm, setSelectedMsaAlgorithm] = useState('clustalo');
|
|
41
|
-
const [selectedBlastProgram, setSelectedBlastProgram] = useState('quick-blastp');
|
|
42
34
|
const geneIds = useMemo(() => getGeneIdentifiers(feature), [feature]);
|
|
43
35
|
const { results: cachedResults, error: cachedResultsError } = useCachedBlastResults(geneIds);
|
|
44
36
|
const transcriptSelection = useTranscriptSelection({ feature, view });
|
|
@@ -48,20 +40,11 @@ const NCBIBlastAutomaticPanel = observer(function ({ handleClose, feature, model
|
|
|
48
40
|
React.createElement(LaunchPanelContent, { error: e },
|
|
49
41
|
children,
|
|
50
42
|
React.createElement(TextField2, { variant: "outlined", label: "BLAST database", className: classes.selectField, select: true, value: selectedBlastDatabase, onChange: event => {
|
|
51
|
-
|
|
52
|
-
setSelectedBlastDatabase(newDb);
|
|
53
|
-
if (newDb === 'nr_cluster_seq') {
|
|
54
|
-
setSelectedBlastProgram('blastp');
|
|
55
|
-
}
|
|
43
|
+
setSelectedBlastDatabase(event.target.value);
|
|
56
44
|
} }, blastDatabaseOptions.map(val => (React.createElement(MenuItem, { value: val, key: val }, val)))),
|
|
57
45
|
React.createElement(MsaAlgorithmSelect, { className: classes.selectField, value: selectedMsaAlgorithm, onChange: setSelectedMsaAlgorithm }),
|
|
58
|
-
React.createElement("div", { className: classes.databaseFieldContainer },
|
|
59
|
-
React.createElement(TextField2, { variant: "outlined", label: "BLAST program", disabled: selectedBlastDatabase === 'nr_cluster_seq', className: classes.selectField, select: true, value: selectedBlastProgram, onChange: event => {
|
|
60
|
-
setSelectedBlastProgram(event.target.value);
|
|
61
|
-
} }, blastPrograms.map(val => (React.createElement(MenuItem, { value: val, key: val }, val)))),
|
|
62
|
-
selectedBlastDatabase === 'nr_cluster_seq' ? (React.createElement(Typography, { variant: "subtitle2", className: classes.clusterSeqMessage }, "Can only use blastp on nr_cluster_seq")) : null),
|
|
63
46
|
React.createElement(TranscriptSelector, { feature: feature, ...transcriptSelection }),
|
|
64
|
-
React.createElement(Typography, { className: classes.infoText }, "This panel will automatically submit a query to
|
|
47
|
+
React.createElement(Typography, { className: classes.infoText }, "This panel will automatically submit a blastp query to EBI, which searches UniProtKB. Searches usually finish in under a minute, and swissprot returns curated sequences that align more cleanly than the many near-identical entries a TrEMBL search brings back. After completion, all the hits will be run through a multiple sequence alignment. Searching NCBI's nr needs the manual approach: NCBI no longer lets a browser read responses from Blast.cgi."),
|
|
65
48
|
cachedResults.length > 0 ? (React.createElement(Accordion, { className: classes.cachedResultsAccordion },
|
|
66
49
|
React.createElement(AccordionSummary, { expandIcon: React.createElement(ExpandMoreIcon, null) },
|
|
67
50
|
React.createElement(Typography, null, "Previous BLAST Results")),
|
|
@@ -76,8 +59,6 @@ const NCBIBlastAutomaticPanel = observer(function ({ handleClose, feature, model
|
|
|
76
59
|
view,
|
|
77
60
|
newViewTitle: getBlastViewTitle(feature, selectedTranscript),
|
|
78
61
|
blastParams: {
|
|
79
|
-
baseUrl,
|
|
80
|
-
blastProgram: selectedBlastProgram,
|
|
81
62
|
blastDatabase: selectedBlastDatabase,
|
|
82
63
|
msaAlgorithm: selectedMsaAlgorithm,
|
|
83
64
|
selectedTranscript,
|
|
@@ -93,4 +74,4 @@ const NCBIBlastAutomaticPanel = observer(function ({ handleClose, feature, model
|
|
|
93
74
|
}
|
|
94
75
|
}, onCancel: handleClose })));
|
|
95
76
|
});
|
|
96
|
-
export default
|
|
77
|
+
export default BlastAutomaticPanel;
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { AbstractTrackModel, Feature } from '@jbrowse/core/util';
|
|
3
|
-
declare const
|
|
3
|
+
declare const BlastManualPanel: ({ handleClose, feature, model, children, }: {
|
|
4
4
|
children: React.ReactNode;
|
|
5
5
|
model: AbstractTrackModel;
|
|
6
6
|
feature: Feature;
|
|
7
|
-
baseUrl: string;
|
|
8
7
|
handleClose: () => void;
|
|
9
8
|
}) => React.JSX.Element;
|
|
10
|
-
export default
|
|
9
|
+
export default BlastManualPanel;
|
|
@@ -3,6 +3,7 @@ import { shorten2 } from '@jbrowse/core/util';
|
|
|
3
3
|
import { Button, DialogActions, Typography } from '@mui/material';
|
|
4
4
|
import { observer } from 'mobx-react';
|
|
5
5
|
import { makeStyles } from 'tss-react/mui';
|
|
6
|
+
import { BASE_BLAST_URL } from './consts';
|
|
6
7
|
import ExternalLink from '../../../components/ExternalLink';
|
|
7
8
|
import { cleanProteinSequence, getLinearGenomeView } from '../../util';
|
|
8
9
|
import LaunchPanelContent from '../LaunchPanelContent';
|
|
@@ -18,14 +19,16 @@ const useStyles = makeStyles()({
|
|
|
18
19
|
marginTop: 20,
|
|
19
20
|
},
|
|
20
21
|
});
|
|
21
|
-
const
|
|
22
|
+
const BlastManualPanel = observer(function ({ handleClose, feature, model, children, }) {
|
|
22
23
|
const { classes } = useStyles();
|
|
23
24
|
const view = getLinearGenomeView(model);
|
|
24
25
|
const transcriptSelection = useTranscriptSelection({ feature, view });
|
|
25
26
|
const { proteinSequence, error } = transcriptSelection;
|
|
26
27
|
const s2 = cleanProteinSequence(proteinSequence);
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
// a link the user follows to NCBI's own site, not something we fetch — which
|
|
29
|
+
// is exactly why this route still works when the automatic one cannot
|
|
30
|
+
const link = `${BASE_BLAST_URL}?PAGE_TYPE=BlastSearch&PAGE=Proteins&PROGRAM=blastp&QUERY=${s2}`;
|
|
31
|
+
const link2 = `${BASE_BLAST_URL}?PAGE_TYPE=BlastSearch&PAGE=Proteins&PROGRAM=blastp&QUERY=${shorten2(s2, 10)}`;
|
|
29
32
|
return (React.createElement(React.Fragment, null,
|
|
30
33
|
React.createElement(LaunchPanelContent, { error: error },
|
|
31
34
|
children,
|
|
@@ -39,4 +42,4 @@ const NCBIBlastManualPanel = observer(function ({ handleClose, feature, model, c
|
|
|
39
42
|
handleClose();
|
|
40
43
|
} }, "Close"))));
|
|
41
44
|
});
|
|
42
|
-
export default
|
|
45
|
+
export default BlastManualPanel;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type { BlastLookupMethod } from './
|
|
3
|
-
export default function
|
|
2
|
+
import type { BlastLookupMethod } from './BlastPanel';
|
|
3
|
+
export default function BlastMethodSelector({ lookupMethod, setLookupMethod, }: {
|
|
4
4
|
lookupMethod: BlastLookupMethod;
|
|
5
5
|
setLookupMethod: (method: BlastLookupMethod) => void;
|
|
6
6
|
}): React.JSX.Element;
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { FormControl, FormControlLabel, Radio, RadioGroup } from '@mui/material';
|
|
3
|
-
export default function
|
|
3
|
+
export default function BlastMethodSelector({ lookupMethod, setLookupMethod, }) {
|
|
4
4
|
return (React.createElement(FormControl, { component: "fieldset" },
|
|
5
5
|
React.createElement(RadioGroup, { row: true, value: lookupMethod, onChange: event => {
|
|
6
6
|
setLookupMethod(event.target.value);
|
|
7
7
|
} },
|
|
8
8
|
React.createElement(FormControlLabel, { value: "automatic", control: React.createElement(Radio, null), label: "Automatic" }),
|
|
9
|
-
React.createElement(FormControlLabel, { value: "rid", control: React.createElement(Radio, null), label: "Load from RID" }),
|
|
10
9
|
React.createElement(FormControlLabel, { value: "manual", control: React.createElement(Radio, null), label: "Manual" }))));
|
|
11
10
|
}
|
|
@@ -1,30 +1,21 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { AbstractTrackModel, Feature } from '@jbrowse/core/util';
|
|
3
3
|
declare const panelMap: {
|
|
4
|
-
readonly automatic: ({ handleClose, feature, model, children,
|
|
4
|
+
readonly automatic: ({ handleClose, feature, model, children, }: {
|
|
5
5
|
model: AbstractTrackModel;
|
|
6
6
|
feature: Feature;
|
|
7
|
-
baseUrl: string;
|
|
8
7
|
handleClose: () => void;
|
|
9
8
|
children: React.ReactNode;
|
|
10
9
|
}) => React.JSX.Element;
|
|
11
|
-
readonly
|
|
12
|
-
model: AbstractTrackModel;
|
|
13
|
-
feature: Feature;
|
|
14
|
-
baseUrl: string;
|
|
15
|
-
handleClose: () => void;
|
|
16
|
-
children: React.ReactNode;
|
|
17
|
-
}) => React.JSX.Element;
|
|
18
|
-
readonly manual: ({ handleClose, feature, model, children, baseUrl, }: {
|
|
10
|
+
readonly manual: ({ handleClose, feature, model, children, }: {
|
|
19
11
|
children: React.ReactNode;
|
|
20
12
|
model: AbstractTrackModel;
|
|
21
13
|
feature: Feature;
|
|
22
|
-
baseUrl: string;
|
|
23
14
|
handleClose: () => void;
|
|
24
15
|
}) => React.JSX.Element;
|
|
25
16
|
};
|
|
26
17
|
export type BlastLookupMethod = keyof typeof panelMap;
|
|
27
|
-
export default function
|
|
18
|
+
export default function BlastPanel({ handleClose, model, feature, }: {
|
|
28
19
|
handleClose: () => void;
|
|
29
20
|
model: AbstractTrackModel;
|
|
30
21
|
feature: Feature;
|
package/dist/LaunchMsaView/components/{NCBIBlastQuery/NCBIBlastPanel.js → BlastQuery/BlastPanel.js}
RENAMED
|
@@ -2,12 +2,11 @@ import React, { useState } from 'react';
|
|
|
2
2
|
import SettingsIcon from '@mui/icons-material/Settings';
|
|
3
3
|
import { IconButton } from '@mui/material';
|
|
4
4
|
import { makeStyles } from 'tss-react/mui';
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import { BASE_BLAST_URL } from './consts';
|
|
5
|
+
import BlastAutomaticPanel from './BlastAutomaticPanel';
|
|
6
|
+
import BlastManualPanel from './BlastManualPanel';
|
|
7
|
+
import BlastMethodSelector from './BlastMethodSelector';
|
|
8
|
+
import BlastSettingsDialog from './BlastSettingsDialog';
|
|
9
|
+
import { DEFAULT_EBI_EMAIL, EBI_EMAIL_STORAGE_KEY, } from '../../../utils/ebiJobDispatcher';
|
|
11
10
|
import { useLocalStorage } from '../../../utils/useLocalStorage';
|
|
12
11
|
const useStyles = makeStyles()({
|
|
13
12
|
settingsButton: {
|
|
@@ -15,13 +14,12 @@ const useStyles = makeStyles()({
|
|
|
15
14
|
},
|
|
16
15
|
});
|
|
17
16
|
const panelMap = {
|
|
18
|
-
automatic:
|
|
19
|
-
|
|
20
|
-
manual: NCBIBlastManualPanel,
|
|
17
|
+
automatic: BlastAutomaticPanel,
|
|
18
|
+
manual: BlastManualPanel,
|
|
21
19
|
};
|
|
22
|
-
export default function
|
|
20
|
+
export default function BlastPanel({ handleClose, model, feature, }) {
|
|
23
21
|
const [lookupMethod, setLookupMethod] = useState('automatic');
|
|
24
|
-
const [
|
|
22
|
+
const [ebiEmail, setEbiEmail] = useLocalStorage(EBI_EMAIL_STORAGE_KEY, DEFAULT_EBI_EMAIL);
|
|
25
23
|
const [settingsOpen, setSettingsOpen] = useState(false);
|
|
26
24
|
const { classes } = useStyles();
|
|
27
25
|
const Panel = panelMap[lookupMethod];
|
|
@@ -30,11 +28,11 @@ export default function NCBIBlastPanel({ handleClose, model, feature, }) {
|
|
|
30
28
|
setSettingsOpen(true);
|
|
31
29
|
} },
|
|
32
30
|
React.createElement(SettingsIcon, null)),
|
|
33
|
-
React.createElement(Panel, { model: model, feature: feature, handleClose: handleClose
|
|
34
|
-
React.createElement(
|
|
35
|
-
settingsOpen ? (React.createElement(
|
|
36
|
-
if (
|
|
37
|
-
|
|
31
|
+
React.createElement(Panel, { model: model, feature: feature, handleClose: handleClose },
|
|
32
|
+
React.createElement(BlastMethodSelector, { lookupMethod: lookupMethod, setLookupMethod: setLookupMethod })),
|
|
33
|
+
settingsOpen ? (React.createElement(BlastSettingsDialog, { ebiEmail: ebiEmail, handleClose: settings => {
|
|
34
|
+
if (settings) {
|
|
35
|
+
setEbiEmail(settings.ebiEmail);
|
|
38
36
|
}
|
|
39
37
|
setSettingsOpen(false);
|
|
40
38
|
} })) : null));
|
|
@@ -1,32 +1,36 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
|
-
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, } from '@mui/material';
|
|
2
|
+
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Typography, } from '@mui/material';
|
|
3
3
|
import { makeStyles } from 'tss-react/mui';
|
|
4
|
-
import { BASE_BLAST_URL } from './consts';
|
|
5
4
|
import TextField2 from '../../../components/TextField2';
|
|
5
|
+
import { DEFAULT_EBI_EMAIL } from '../../../utils/ebiJobDispatcher';
|
|
6
6
|
const useStyles = makeStyles()({
|
|
7
|
-
|
|
7
|
+
field: {
|
|
8
8
|
minWidth: 300,
|
|
9
9
|
},
|
|
10
|
+
help: {
|
|
11
|
+
marginBottom: 8,
|
|
12
|
+
},
|
|
10
13
|
});
|
|
11
|
-
export default function
|
|
14
|
+
export default function BlastSettingsDialog({ handleClose, ebiEmail, }) {
|
|
12
15
|
const { classes } = useStyles();
|
|
13
|
-
const [
|
|
16
|
+
const [tempEbiEmail, setTempEbiEmail] = useState(ebiEmail);
|
|
14
17
|
return (React.createElement(Dialog, { open: true, maxWidth: "lg", onClose: () => {
|
|
15
18
|
handleClose();
|
|
16
19
|
} },
|
|
17
20
|
React.createElement(DialogTitle, null, "BLAST Settings"),
|
|
18
21
|
React.createElement(DialogContent, null,
|
|
19
|
-
React.createElement(
|
|
20
|
-
|
|
22
|
+
React.createElement(Typography, { variant: "subtitle2", className: classes.help }, "Searches run at EBI, which asks for a contact address on every job so they can reach whoever is generating the load. If your site sends real volume, use your own."),
|
|
23
|
+
React.createElement(TextField2, { autoFocus: true, margin: "dense", label: "EBI contact email", fullWidth: true, variant: "outlined", value: tempEbiEmail, className: classes.field, onChange: e => {
|
|
24
|
+
setTempEbiEmail(e.target.value);
|
|
21
25
|
} }),
|
|
22
26
|
React.createElement(Button, { variant: "contained", onClick: () => {
|
|
23
|
-
|
|
27
|
+
setTempEbiEmail(DEFAULT_EBI_EMAIL);
|
|
24
28
|
} }, "Reset")),
|
|
25
29
|
React.createElement(DialogActions, null,
|
|
26
30
|
React.createElement(Button, { variant: "contained", color: "secondary", onClick: () => {
|
|
27
31
|
handleClose();
|
|
28
32
|
} }, "Cancel"),
|
|
29
33
|
React.createElement(Button, { color: "primary", variant: "contained", onClick: () => {
|
|
30
|
-
handleClose(
|
|
34
|
+
handleClose({ ebiEmail: tempEbiEmail });
|
|
31
35
|
} }, "Save"))));
|
|
32
36
|
}
|
|
@@ -83,6 +83,6 @@ const CachedBlastResults = observer(function ({ model, handleClose, feature, })
|
|
|
83
83
|
React.createElement(ListItemButton, { onClick: () => {
|
|
84
84
|
handleUseCached(result);
|
|
85
85
|
} },
|
|
86
|
-
React.createElement(ListItemText, { primary: `${getResultDisplayName(result)} - ${result.blastDatabase}
|
|
86
|
+
React.createElement(ListItemText, { primary: `${getResultDisplayName(result)} - ${result.blastDatabase}${result.blastProgram ? `/${result.blastProgram}` : ''} (${result.msaAlgorithm})`, secondary: `${new Date(result.timestamp).toLocaleString()} - Seq: ${result.proteinSequence.slice(0, 30)}...` }))))))));
|
|
87
87
|
});
|
|
88
88
|
export default CachedBlastResults;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Only used to build the link-out on the manual panel, which sends the user to
|
|
3
|
+
* NCBI's own site to run BLAST there. Nothing fetches this url: NCBI stopped
|
|
4
|
+
* sending Access-Control-Allow-Origin to third-party origins, so a browser
|
|
5
|
+
* cannot read a response from it at all. See docs/blast.md.
|
|
6
|
+
*/
|
|
7
|
+
export declare const BASE_BLAST_URL = "https://blast.ncbi.nlm.nih.gov/Blast.cgi";
|
|
8
|
+
export declare const msaAlgorithms: readonly ["clustalo", "muscle", "kalign", "mafft"];
|
|
9
|
+
export type MsaAlgorithm = (typeof msaAlgorithms)[number];
|
|
10
|
+
export declare const blastDatabaseOptions: readonly ["uniprotkb_swissprot", "uniprotkb", "uniprotkb_reference_proteomes", "uniprotkb_trembl"];
|
|
11
|
+
export type BlastDatabase = (typeof blastDatabaseOptions)[number];
|
|
12
|
+
export declare const defaultBlastDatabase: BlastDatabase;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Only used to build the link-out on the manual panel, which sends the user to
|
|
3
|
+
* NCBI's own site to run BLAST there. Nothing fetches this url: NCBI stopped
|
|
4
|
+
* sending Access-Control-Allow-Origin to third-party origins, so a browser
|
|
5
|
+
* cannot read a response from it at all. See docs/blast.md.
|
|
6
|
+
*/
|
|
7
|
+
export const BASE_BLAST_URL = 'https://blast.ncbi.nlm.nih.gov/Blast.cgi';
|
|
8
|
+
export const msaAlgorithms = ['clustalo', 'muscle', 'kalign', 'mafft'];
|
|
9
|
+
export const blastDatabaseOptions = [
|
|
10
|
+
'uniprotkb_swissprot',
|
|
11
|
+
'uniprotkb',
|
|
12
|
+
'uniprotkb_reference_proteomes',
|
|
13
|
+
'uniprotkb_trembl',
|
|
14
|
+
];
|
|
15
|
+
// curated, so it returns roughly one good sequence per species rather than the
|
|
16
|
+
// many near-identical TrEMBL entries an alignment reads poorly
|
|
17
|
+
export const defaultBlastDatabase = 'uniprotkb_swissprot';
|
|
@@ -2,8 +2,8 @@ import React, { useState } from 'react';
|
|
|
2
2
|
import { Dialog } from '@jbrowse/core/ui';
|
|
3
3
|
import { getSession } from '@jbrowse/core/util';
|
|
4
4
|
import { Tab, Tabs } from '@mui/material';
|
|
5
|
+
import BlastPanel from './BlastQuery/BlastPanel';
|
|
5
6
|
import ManualMSALoader from './ManualMSALoader/ManualMSALoader';
|
|
6
|
-
import NCBIBlastPanel from './NCBIBlastQuery/NCBIBlastPanel';
|
|
7
7
|
import OrthologPanel from './OrthologQuery/OrthologPanel';
|
|
8
8
|
import PreLoadedMSA from './PreLoadedMSA/PreLoadedMSADataPanel';
|
|
9
9
|
import { readMsaDatasets } from './PreLoadedMSA/types';
|
|
@@ -20,13 +20,13 @@ export default function LaunchMsaViewDialog({ handleClose, feature, model, }) {
|
|
|
20
20
|
setValue(newValue);
|
|
21
21
|
} },
|
|
22
22
|
React.createElement(Tab, { label: "Orthologs (fast)", value: "orthologs" }),
|
|
23
|
-
React.createElement(Tab, { label: "
|
|
23
|
+
React.createElement(Tab, { label: "BLAST query", value: "ncbi_blast" }),
|
|
24
24
|
hasPreloadedDatasets ? (React.createElement(Tab, { label: "Pre-loaded MSA datasets", value: "preloaded_msa" })) : null,
|
|
25
25
|
React.createElement(Tab, { label: "Manual upload", value: "manual_msa" })),
|
|
26
26
|
React.createElement(TabPanel, { value: value, index: "orthologs" },
|
|
27
27
|
React.createElement(OrthologPanel, { handleClose: handleClose, feature: feature, model: model })),
|
|
28
28
|
React.createElement(TabPanel, { value: value, index: "ncbi_blast" },
|
|
29
|
-
React.createElement(
|
|
29
|
+
React.createElement(BlastPanel, { handleClose: handleClose, feature: feature, model: model })),
|
|
30
30
|
hasPreloadedDatasets ? (React.createElement(TabPanel, { value: value, index: "preloaded_msa" },
|
|
31
31
|
React.createElement(PreLoadedMSA, { model: model, feature: feature, handleClose: handleClose }))) : null,
|
|
32
32
|
React.createElement(TabPanel, { value: value, index: "manual_msa" },
|
|
@@ -6,8 +6,8 @@ import { orthologLaunchView } from './orthologLaunchView';
|
|
|
6
6
|
import TextField2 from '../../../components/TextField2';
|
|
7
7
|
import { COMMON_SPECIES } from '../../../utils/ncbiOrthologs';
|
|
8
8
|
import { getGeneDisplayName, getGeneIdentifiers, getLinearGenomeView, getTranscriptDisplayName, } from '../../util';
|
|
9
|
+
import MsaAlgorithmSelect from '../BlastQuery/MsaAlgorithmSelect';
|
|
9
10
|
import LaunchPanelContent from '../LaunchPanelContent';
|
|
10
|
-
import MsaAlgorithmSelect from '../NCBIBlastQuery/MsaAlgorithmSelect';
|
|
11
11
|
import SubmitCancelActions from '../SubmitCancelActions';
|
|
12
12
|
import TranscriptSelector from '../TranscriptSelector';
|
|
13
13
|
import { useTranscriptSelection } from '../useTranscriptSelection';
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
export default function LaunchMsaViewExtensionPointF(pluginManager) {
|
|
2
2
|
pluginManager.addToExtensionPoint('LaunchView-MsaView', (args) => {
|
|
3
3
|
const { session, data, msaFileLocation, msaIndexedLocation, msaName, treeFileLocation, querySeqName, ...rest } = args;
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
// `orthologParams` is a fourth source, and unlike the other three it names
|
|
5
|
+
// no alignment at all — the view builds one from NCBI at launch, which is
|
|
6
|
+
// the dialog's Orthologs tab reached declaratively.
|
|
7
|
+
if (!data &&
|
|
8
|
+
!msaFileLocation &&
|
|
9
|
+
!msaIndexedLocation &&
|
|
10
|
+
!rest.orthologParams) {
|
|
11
|
+
throw new Error('No MSA data, file location or orthologParams provided when launching MSA view');
|
|
6
12
|
}
|
|
7
13
|
// inline data and the tree URL are native react-msaview snapshot props, set
|
|
8
|
-
// directly
|
|
9
|
-
//
|
|
14
|
+
// directly, and so is orthologParams (the model's own autorun picks it up).
|
|
15
|
+
// Only sources needing launch-time resolution go through `init`: msaUrl
|
|
16
|
+
// (AlphaFold sniff) and the name-indexed bgzip block (no native loader).
|
|
10
17
|
session.addView('MsaView', {
|
|
11
18
|
type: 'MsaView',
|
|
12
19
|
...rest,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Typography } from '@mui/material';
|
|
3
|
+
import ExternalLink from '../../components/ExternalLink';
|
|
4
|
+
import { ebiBlastResultUrl } from '../../utils/ebiBlast';
|
|
5
|
+
function JobLink({ jobId }) {
|
|
6
|
+
return (React.createElement(Typography, null,
|
|
7
|
+
"Job ",
|
|
8
|
+
jobId,
|
|
9
|
+
" (",
|
|
10
|
+
React.createElement(ExternalLink, { href: ebiBlastResultUrl(jobId) }, "see status"),
|
|
11
|
+
")"));
|
|
12
|
+
}
|
|
13
|
+
export default JobLink;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { JBrowsePluginMsaViewModel } from '../model';
|
|
3
|
-
declare const LoadingBLAST: ({ model,
|
|
3
|
+
declare const LoadingBLAST: ({ model, }: {
|
|
4
4
|
model: JBrowsePluginMsaViewModel;
|
|
5
|
-
baseUrl: string;
|
|
6
5
|
}) => React.JSX.Element;
|
|
7
6
|
export default LoadingBLAST;
|
|
@@ -3,7 +3,7 @@ import { ErrorMessage, LoadingEllipses } from '@jbrowse/core/ui';
|
|
|
3
3
|
import { Typography } from '@mui/material';
|
|
4
4
|
import { observer } from 'mobx-react';
|
|
5
5
|
import { makeStyles } from 'tss-react/mui';
|
|
6
|
-
import
|
|
6
|
+
import JobLink from './JobLink';
|
|
7
7
|
const useStyles = makeStyles()(theme => ({
|
|
8
8
|
margin: {
|
|
9
9
|
padding: 20,
|
|
@@ -12,22 +12,15 @@ const useStyles = makeStyles()(theme => ({
|
|
|
12
12
|
background: theme.palette.background.paper,
|
|
13
13
|
},
|
|
14
14
|
}));
|
|
15
|
-
function
|
|
16
|
-
return (React.createElement("div", null,
|
|
17
|
-
rid ? React.createElement(RIDLink, { rid: rid, baseUrl: baseUrl }) : null,
|
|
18
|
-
React.createElement(ErrorMessage, { error: error })));
|
|
19
|
-
}
|
|
20
|
-
function RIDProgress({ baseUrl, rid, progress, }) {
|
|
21
|
-
const { classes } = useStyles();
|
|
22
|
-
return (React.createElement("div", { className: classes.loading },
|
|
23
|
-
rid ? React.createElement(RIDLink, { baseUrl: baseUrl, rid: rid }) : null,
|
|
24
|
-
React.createElement(Typography, null, progress)));
|
|
25
|
-
}
|
|
26
|
-
const LoadingBLAST = observer(function LoadingBLAST2({ model, baseUrl, }) {
|
|
15
|
+
const LoadingBLAST = observer(function LoadingBLAST2({ model, }) {
|
|
27
16
|
const { progress, rid, error } = model;
|
|
28
17
|
const { classes } = useStyles();
|
|
29
18
|
return (React.createElement("div", { className: classes.margin },
|
|
30
|
-
React.createElement(LoadingEllipses, { message: "Running
|
|
31
|
-
error ? (React.createElement(
|
|
19
|
+
React.createElement(LoadingEllipses, { message: "Running EBI BLAST", variant: "h5" }),
|
|
20
|
+
error ? (React.createElement("div", null,
|
|
21
|
+
rid ? React.createElement(JobLink, { jobId: rid }) : null,
|
|
22
|
+
React.createElement(ErrorMessage, { error: error }))) : rid ? (React.createElement("div", { className: classes.loading },
|
|
23
|
+
React.createElement(JobLink, { jobId: rid }),
|
|
24
|
+
React.createElement(Typography, null, progress))) : (React.createElement(Typography, null, progress || 'Initializing BLAST query'))));
|
|
32
25
|
});
|
|
33
26
|
export default LoadingBLAST;
|
|
@@ -14,7 +14,7 @@ const MsaViewPanel = observer(function MsaViewPanel2({ model, }) {
|
|
|
14
14
|
const { classes } = useStyles();
|
|
15
15
|
const { blastParams, loadingStoredData } = model;
|
|
16
16
|
return (React.createElement(ErrorBoundary, null,
|
|
17
|
-
React.createElement("div", null, blastParams ? (React.createElement(LoadingBLAST, { model: model
|
|
17
|
+
React.createElement("div", null, blastParams ? (React.createElement(LoadingBLAST, { model: model })) : loadingStoredData ? (React.createElement("div", { className: classes.loadingContainer },
|
|
18
18
|
React.createElement(LoadingEllipses, { message: "Loading MSA data", variant: "h6" }))) : (React.createElement(MSAView, { model: model })))));
|
|
19
19
|
});
|
|
20
20
|
export default MsaViewPanel;
|
|
@@ -1,32 +1,25 @@
|
|
|
1
1
|
import { makeId, strip } from '../LaunchMsaView/components/util';
|
|
2
2
|
import { cleanProteinSequence } from '../LaunchMsaView/util';
|
|
3
3
|
import { saveBlastResult } from '../utils/blastCache';
|
|
4
|
+
import { queryEbiBlast } from '../utils/ebiBlast';
|
|
4
5
|
import { launchMSA } from '../utils/msa';
|
|
5
|
-
import { queryBlast, queryBlastFromRid } from '../utils/ncbiBlast';
|
|
6
6
|
import { fetchTaxonomyInfo } from '../utils/taxonomyNames';
|
|
7
7
|
export async function doLaunchBlast({ self, }) {
|
|
8
|
-
const {
|
|
8
|
+
const { blastDatabase, msaAlgorithm, proteinSequence, selectedTranscript } = self.blastParams;
|
|
9
9
|
const cleanedSeq = cleanProteinSequence(proteinSequence);
|
|
10
10
|
const onProgress = (arg) => {
|
|
11
11
|
self.setProgress(arg);
|
|
12
12
|
};
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
const { hits, rid } = await queryEbiBlast({
|
|
14
|
+
query: cleanedSeq,
|
|
15
|
+
blastDatabase,
|
|
16
|
+
onProgress,
|
|
17
|
+
// publish the job id before the first poll so the view can link out while
|
|
15
18
|
// the job is still running
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
: await queryBlast({
|
|
21
|
-
query: cleanedSeq,
|
|
22
|
-
blastDatabase,
|
|
23
|
-
blastProgram,
|
|
24
|
-
baseUrl,
|
|
25
|
-
onProgress,
|
|
26
|
-
onRid: r => {
|
|
27
|
-
self.setRid(r);
|
|
28
|
-
},
|
|
29
|
-
});
|
|
19
|
+
onRid: r => {
|
|
20
|
+
self.setRid(r);
|
|
21
|
+
},
|
|
22
|
+
});
|
|
30
23
|
self.setProgress('Fetching species taxonomy info...');
|
|
31
24
|
const taxids = hits
|
|
32
25
|
.map(h => h.description[0]?.taxid)
|
|
@@ -53,7 +46,6 @@ export async function doLaunchBlast({ self, }) {
|
|
|
53
46
|
await saveBlastResult({
|
|
54
47
|
proteinSequence: cleanedSeq,
|
|
55
48
|
blastDatabase,
|
|
56
|
-
blastProgram,
|
|
57
49
|
msaAlgorithm,
|
|
58
50
|
msa: result.msa,
|
|
59
51
|
tree: result.tree,
|