jbrowse-plugin-msaview 3.10.0 → 5.0.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/AddHighlightModel/GenomeMouseoverHighlight.js +1 -1
- package/dist/AddHighlightModel/index.js +3 -12
- package/dist/LaunchMsaView/codingFeature.d.ts +0 -12
- package/dist/LaunchMsaView/codingFeature.js +0 -30
- package/dist/LaunchMsaView/codingFeature.test.js +1 -48
- package/dist/LaunchMsaView/components/BlastQuery/BlastAutomaticPanel.js +8 -10
- package/dist/LaunchMsaView/components/BlastQuery/BlastManualPanel.js +9 -11
- package/dist/LaunchMsaView/components/BlastQuery/CachedBlastResults.js +3 -1
- package/dist/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.js +14 -16
- package/dist/LaunchMsaView/components/OrthologQuery/OrthologPanel.js +16 -18
- package/dist/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.js +17 -19
- package/dist/LaunchMsaView/components/fetchSeq.d.ts +1 -1
- package/dist/LaunchMsaView/components/fetchSeq.js +3 -10
- package/dist/LaunchMsaView/components/launchConnectedView.d.ts +2 -2
- package/dist/LaunchMsaView/components/launchConnectedView.js +4 -8
- package/dist/LaunchMsaView/components/useFeatureSequence.d.ts +1 -1
- package/dist/LaunchMsaView/index.js +4 -13
- package/dist/LaunchMsaView/launchTarget.d.ts +7 -30
- package/dist/LaunchMsaView/launchTarget.js +10 -49
- package/dist/LaunchMsaView/launchTarget.test.js +17 -109
- package/dist/LaunchMsaViewExtensionPoint/index.js +3 -3
- package/dist/LaunchMsaViewExtensionPoint/index.test.js +24 -21
- package/dist/MsaViewPanel/index.js +3 -3
- package/dist/MsaViewPanel/isMsaView.d.ts +4 -0
- package/dist/MsaViewPanel/isMsaView.js +3 -0
- package/dist/MsaViewPanel/model.d.ts +8 -11
- package/dist/MsaViewPanel/model.js +3 -13
- package/dist/MsaViewPanel/resolveConnectedTranscript.js +1 -7
- package/dist/chunks/AboutDialog-WT6GXMXU.js +2 -0
- package/dist/chunks/AboutDialog-WT6GXMXU.js.map +7 -0
- package/dist/chunks/AnnotationFileDialog-34R7LFHB.js +2 -0
- package/dist/chunks/AnnotationFileDialog-34R7LFHB.js.map +7 -0
- package/dist/chunks/BgzipFastaMsaAdapter-ZMUARSUQ.js +4 -0
- package/dist/chunks/BgzipFastaMsaAdapter-ZMUARSUQ.js.map +7 -0
- package/dist/chunks/ExportSVGDialog-NMVUHFGY.js +2 -0
- package/dist/chunks/ExportSVGDialog-NMVUHFGY.js.map +7 -0
- package/dist/chunks/FeatureDialog-XNHIA5PS.js +2 -0
- package/dist/chunks/FeatureDialog-XNHIA5PS.js.map +7 -0
- package/dist/chunks/HelpDialog-DF4Y536X.js +2 -0
- package/dist/chunks/HelpDialog-DF4Y536X.js.map +7 -0
- package/dist/chunks/LaunchMsaViewDialog-LMZOJ7T6.js +5 -0
- package/dist/chunks/LaunchMsaViewDialog-LMZOJ7T6.js.map +7 -0
- package/dist/chunks/MetadataDialog-2WT6EX4M.js +2 -0
- package/dist/chunks/MetadataDialog-2WT6EX4M.js.map +7 -0
- package/dist/chunks/MsaViewPanel-YYP4CYYO.js +2 -0
- package/dist/chunks/MsaViewPanel-YYP4CYYO.js.map +7 -0
- package/dist/chunks/TrackInfoDialog-TYCMLUKG.js +2 -0
- package/dist/chunks/TrackInfoDialog-TYCMLUKG.js.map +7 -0
- package/dist/chunks/TreeNodeInfoDialog-BFF6JRCO.js +2 -0
- package/dist/chunks/TreeNodeInfoDialog-BFF6JRCO.js.map +7 -0
- package/dist/chunks/chunk-2IWD4OO4.js +2 -0
- package/dist/chunks/chunk-2IWD4OO4.js.map +7 -0
- package/dist/chunks/chunk-5ORPTTMR.js +2 -0
- package/dist/chunks/chunk-5ORPTTMR.js.map +7 -0
- package/dist/chunks/chunk-6YFCSBEE.js +2 -0
- package/dist/chunks/chunk-6YFCSBEE.js.map +7 -0
- package/dist/chunks/chunk-73KAPCJ2.js +2 -0
- package/dist/chunks/chunk-73KAPCJ2.js.map +7 -0
- package/dist/chunks/chunk-BX4Z274Q.js +2 -0
- package/dist/chunks/chunk-BX4Z274Q.js.map +7 -0
- package/dist/chunks/chunk-CVLB4VFP.js +2 -0
- package/dist/chunks/chunk-CVLB4VFP.js.map +7 -0
- package/dist/chunks/chunk-DNFD5II2.js +2 -0
- package/dist/chunks/chunk-DNFD5II2.js.map +7 -0
- package/dist/chunks/chunk-ENTWPX2K.js +6 -0
- package/dist/chunks/chunk-ENTWPX2K.js.map +7 -0
- package/dist/chunks/chunk-FCNT6B47.js +2 -0
- package/dist/chunks/chunk-FCNT6B47.js.map +7 -0
- package/dist/chunks/chunk-FCWXYIFC.js +2 -0
- package/dist/chunks/chunk-FCWXYIFC.js.map +7 -0
- package/dist/chunks/chunk-FY3BTKY4.js +2 -0
- package/dist/chunks/chunk-FY3BTKY4.js.map +7 -0
- package/dist/chunks/chunk-IBBQUV2I.js +2 -0
- package/dist/chunks/chunk-IBBQUV2I.js.map +7 -0
- package/dist/chunks/chunk-J6KYLXRD.js +2 -0
- package/dist/chunks/chunk-J6KYLXRD.js.map +7 -0
- package/dist/chunks/chunk-MBI4TMKR.js +2 -0
- package/dist/chunks/chunk-MBI4TMKR.js.map +7 -0
- package/dist/chunks/chunk-MHBTV7BZ.js +3 -0
- package/dist/chunks/chunk-MHBTV7BZ.js.map +7 -0
- package/dist/chunks/chunk-NSASZ5FM.js +2 -0
- package/dist/chunks/chunk-NSASZ5FM.js.map +7 -0
- package/dist/chunks/chunk-O7JNDIKD.js +2 -0
- package/dist/chunks/chunk-O7JNDIKD.js.map +7 -0
- package/dist/chunks/chunk-P77DPK6B.js +2 -0
- package/dist/chunks/chunk-P77DPK6B.js.map +7 -0
- package/dist/chunks/chunk-PJZ3XTMG.js +6 -0
- package/dist/chunks/chunk-PJZ3XTMG.js.map +7 -0
- package/dist/chunks/chunk-QAC6JSDZ.js +5 -0
- package/dist/chunks/chunk-QAC6JSDZ.js.map +7 -0
- package/dist/chunks/chunk-QMLPITS4.js +18 -0
- package/dist/chunks/chunk-QMLPITS4.js.map +7 -0
- package/dist/chunks/chunk-RTKNCGDF.js +8 -0
- package/dist/chunks/chunk-RTKNCGDF.js.map +7 -0
- package/dist/chunks/chunk-TITP6LCV.js +2 -0
- package/dist/chunks/chunk-TITP6LCV.js.map +7 -0
- package/dist/chunks/chunk-VOBS7IVV.js +2 -0
- package/dist/chunks/chunk-VOBS7IVV.js.map +7 -0
- package/dist/chunks/chunk-YUKJI2AH.js +2 -0
- package/dist/chunks/chunk-YUKJI2AH.js.map +7 -0
- package/dist/chunks/chunk-ZTQYZDWK.js +2 -0
- package/dist/chunks/chunk-ZTQYZDWK.js.map +7 -0
- package/dist/chunks/dist-2T65ZS4E.js +2 -0
- package/dist/chunks/dist-2T65ZS4E.js.map +7 -0
- package/dist/chunks/dist-UX5CKLQJ.js +2 -0
- package/dist/chunks/dist-UX5CKLQJ.js.map +7 -0
- package/dist/chunks/model-7VBTOIJX.js +12 -0
- package/dist/chunks/model-7VBTOIJX.js.map +7 -0
- package/dist/chunks/renderToSvg-B7RCHRO3.js +2 -0
- package/dist/chunks/renderToSvg-B7RCHRO3.js.map +7 -0
- package/dist/config.json +1 -1
- package/dist/index.js +5 -2
- package/dist/jbrowse-plugin-msaview.esm.js +3 -0
- package/dist/jbrowse-plugin-msaview.esm.js.map +7 -0
- package/dist/utils/launchMsaView.d.ts +1 -1
- package/dist/utils/launchMsaView.js +5 -2
- package/dist/utils/workspaces.js +6 -25
- package/dist/utils/workspaces.test.js +5 -5
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -5
- package/src/AddHighlightModel/GenomeMouseoverHighlight.tsx +1 -1
- package/src/AddHighlightModel/index.tsx +6 -16
- package/src/LaunchMsaView/codingFeature.test.ts +1 -64
- package/src/LaunchMsaView/codingFeature.ts +0 -38
- package/src/LaunchMsaView/components/BlastQuery/BlastAutomaticPanel.tsx +3 -3
- package/src/LaunchMsaView/components/BlastQuery/BlastManualPanel.tsx +3 -3
- package/src/LaunchMsaView/components/BlastQuery/CachedBlastResults.tsx +3 -1
- package/src/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.tsx +3 -3
- package/src/LaunchMsaView/components/OrthologQuery/OrthologPanel.tsx +3 -3
- package/src/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.tsx +3 -3
- package/src/LaunchMsaView/components/fetchSeq.ts +3 -20
- package/src/LaunchMsaView/components/launchConnectedView.ts +5 -8
- package/src/LaunchMsaView/index.ts +8 -13
- package/src/LaunchMsaView/launchTarget.test.ts +20 -133
- package/src/LaunchMsaView/launchTarget.ts +18 -70
- package/src/LaunchMsaViewExtensionPoint/index.test.ts +26 -21
- package/src/LaunchMsaViewExtensionPoint/index.ts +3 -4
- package/src/MsaViewPanel/index.ts +3 -4
- package/src/MsaViewPanel/isMsaView.ts +7 -0
- package/src/MsaViewPanel/model.ts +3 -16
- package/src/MsaViewPanel/resolveConnectedTranscript.ts +1 -7
- package/src/index.ts +5 -2
- package/src/utils/launchMsaView.ts +5 -2
- package/src/utils/useFetch.ts +1 -1
- package/src/utils/workspaces.test.ts +5 -5
- package/src/utils/workspaces.ts +6 -25
- package/src/version.ts +1 -1
- package/dist/jbrowse-plugin-msaview.umd.production.min.js +0 -137
- package/dist/jbrowse-plugin-msaview.umd.production.min.js.map +0 -7
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { getSession } from '@jbrowse/core/util';
|
|
3
3
|
import { observer } from 'mobx-react';
|
|
4
|
-
import { isMsaView } from '../MsaViewPanel/
|
|
4
|
+
import { isMsaView } from '../MsaViewPanel/isMsaView';
|
|
5
5
|
import { hasHoverPosition, useStyles } from './util';
|
|
6
6
|
const GenomeMouseoverHighlight = observer(function ({ model, }) {
|
|
7
7
|
const { hovered, views } = getSession(model);
|
|
@@ -1,19 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { getSession } from '@jbrowse/core/util';
|
|
3
|
-
import { isMsaView } from '../MsaViewPanel/
|
|
3
|
+
import { isMsaView } from '../MsaViewPanel/isMsaView';
|
|
4
4
|
import HighlightComponents from './HighlightComponents';
|
|
5
5
|
export default function AddHighlightComponentsModelF(pluginManager) {
|
|
6
|
-
pluginManager.
|
|
7
|
-
// @ts-expect-error v4 hosts have no contributeToExtensionPoint
|
|
8
|
-
'LinearGenomeView-TracksContainerComponent', (rest, { model }) => {
|
|
6
|
+
pluginManager.contributeToExtensionPoint('LinearGenomeView-TracksContainerComponent', ({ model }) => {
|
|
9
7
|
const { views } = getSession(model);
|
|
10
|
-
|
|
11
|
-
if (!hasMsaView) {
|
|
12
|
-
return rest;
|
|
13
|
-
}
|
|
14
|
-
return [
|
|
15
|
-
...rest,
|
|
16
|
-
React.createElement(HighlightComponents, { key: "highlight_protein_viewer_msaview", model: model }),
|
|
17
|
-
];
|
|
8
|
+
return views.some(v => isMsaView(v) && v.connectedViewId === model.id) ? (React.createElement(HighlightComponents, { key: "highlight_protein_viewer_msaview", model: model })) : undefined;
|
|
18
9
|
});
|
|
19
10
|
}
|
|
@@ -1,14 +1,2 @@
|
|
|
1
1
|
import type { Feature } from '@jbrowse/core/util';
|
|
2
|
-
export declare function isGeneLikeType(type: unknown): boolean;
|
|
3
2
|
export declare function isCodingFeature(feature: Feature): boolean;
|
|
4
|
-
/**
|
|
5
|
-
* Whether the feature is known not to code for anything.
|
|
6
|
-
*
|
|
7
|
-
* Not simply `!isCodingFeature`: a feature that arrived with no subfeatures at
|
|
8
|
-
* all says nothing either way, and a host is free to hand one over that way.
|
|
9
|
-
* Reading that as "no protein here" takes the menu item off a perfectly
|
|
10
|
-
* ordinary gene, silently, which is worse than opening a dialog that then has
|
|
11
|
-
* nothing to translate.
|
|
12
|
-
*/
|
|
13
|
-
export declare function isKnownNonCoding(feature: Feature): boolean;
|
|
14
|
-
export declare function geneLikeRoot(feature: Feature): Feature;
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
// Copied from @jbrowse/core's featureTypes rather than imported: the barrel
|
|
2
|
-
// only exports it from v5, and a bundle resolving it on a v4 host reads
|
|
3
|
-
// undefined.
|
|
4
|
-
const GENE_LIKE_TYPE = /gene(_segment)?$|rna$|transcript/;
|
|
5
|
-
// `unknown` rather than `string | undefined`, because the type comes off a
|
|
6
|
-
// host's hit-test item and nothing here built it.
|
|
7
|
-
export function isGeneLikeType(type) {
|
|
8
|
-
return typeof type === 'string' && GENE_LIKE_TYPE.test(type.toLowerCase());
|
|
9
|
-
}
|
|
10
1
|
function isCDS(feature) {
|
|
11
2
|
return feature.get('type')?.toLowerCase() === 'cds';
|
|
12
3
|
}
|
|
@@ -15,24 +6,3 @@ function isCDS(feature) {
|
|
|
15
6
|
export function isCodingFeature(feature) {
|
|
16
7
|
return isCDS(feature) || !!feature.get('subfeatures')?.some(isCodingFeature);
|
|
17
8
|
}
|
|
18
|
-
/**
|
|
19
|
-
* Whether the feature is known not to code for anything.
|
|
20
|
-
*
|
|
21
|
-
* Not simply `!isCodingFeature`: a feature that arrived with no subfeatures at
|
|
22
|
-
* all says nothing either way, and a host is free to hand one over that way.
|
|
23
|
-
* Reading that as "no protein here" takes the menu item off a perfectly
|
|
24
|
-
* ordinary gene, silently, which is worse than opening a dialog that then has
|
|
25
|
-
* nothing to translate.
|
|
26
|
-
*/
|
|
27
|
-
export function isKnownNonCoding(feature) {
|
|
28
|
-
return !!feature.get('subfeatures')?.length && !isCodingFeature(feature);
|
|
29
|
-
}
|
|
30
|
-
// The outermost gene-like ancestor, so a click on an isoform opens the dialog
|
|
31
|
-
// on the gene with every transcript to choose from, as the canvas host does.
|
|
32
|
-
export function geneLikeRoot(feature) {
|
|
33
|
-
let root = feature;
|
|
34
|
-
for (let parent = root.parent?.(); parent && isGeneLikeType(parent.get('type')); parent = parent.parent?.()) {
|
|
35
|
-
root = parent;
|
|
36
|
-
}
|
|
37
|
-
return root;
|
|
38
|
-
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SimpleFeature } from '@jbrowse/core/util';
|
|
2
2
|
import { describe, expect, it } from 'vitest';
|
|
3
|
-
import {
|
|
3
|
+
import { isCodingFeature } from './codingFeature';
|
|
4
4
|
function feature(type, subfeatures = []) {
|
|
5
5
|
return new SimpleFeature({
|
|
6
6
|
uniqueId: `${type}-${Math.random()}`,
|
|
@@ -11,29 +11,6 @@ function feature(type, subfeatures = []) {
|
|
|
11
11
|
subfeatures: subfeatures.map(s => s.toJSON()),
|
|
12
12
|
});
|
|
13
13
|
}
|
|
14
|
-
describe('isGeneLikeType', () => {
|
|
15
|
-
it('accepts the SO spellings of gene, transcript and RNA', () => {
|
|
16
|
-
for (const t of [
|
|
17
|
-
'gene',
|
|
18
|
-
'mRNA',
|
|
19
|
-
'transcript',
|
|
20
|
-
'ncRNA_gene',
|
|
21
|
-
'protein_coding_gene',
|
|
22
|
-
'V_gene_segment',
|
|
23
|
-
'primary_transcript',
|
|
24
|
-
'pseudogenic_transcript',
|
|
25
|
-
'lnc_RNA',
|
|
26
|
-
]) {
|
|
27
|
-
expect(isGeneLikeType(t)).toBe(true);
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
it('rejects regions, matches and CDS', () => {
|
|
31
|
-
for (const t of ['intergenic_region', 'cDNA_match', 'CDS', 'exon']) {
|
|
32
|
-
expect(isGeneLikeType(t)).toBe(false);
|
|
33
|
-
}
|
|
34
|
-
expect(isGeneLikeType(undefined)).toBe(false);
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
14
|
describe('isCodingFeature', () => {
|
|
38
15
|
it('finds a CDS anywhere below the feature', () => {
|
|
39
16
|
const gene = feature('gene', [
|
|
@@ -49,27 +26,3 @@ describe('isCodingFeature', () => {
|
|
|
49
26
|
expect(isCodingFeature(feature('CDS'))).toBe(true);
|
|
50
27
|
});
|
|
51
28
|
});
|
|
52
|
-
describe('isKnownNonCoding', () => {
|
|
53
|
-
it('is true for a transcript whose subfeatures are all exons', () => {
|
|
54
|
-
expect(isKnownNonCoding(feature('lnc_RNA', [feature('exon'), feature('exon')]))).toBe(true);
|
|
55
|
-
});
|
|
56
|
-
// a host is free to hand over a bare record, and reading that as "no protein
|
|
57
|
-
// here" takes the menu item off an ordinary gene without a word
|
|
58
|
-
it('is false for a feature that arrived with no subfeatures at all', () => {
|
|
59
|
-
expect(isKnownNonCoding(feature('gene'))).toBe(false);
|
|
60
|
-
});
|
|
61
|
-
it('is false when a CDS is somewhere below', () => {
|
|
62
|
-
expect(isKnownNonCoding(feature('gene', [feature('mRNA', [feature('CDS')])]))).toBe(false);
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
describe('geneLikeRoot', () => {
|
|
66
|
-
it('climbs from an isoform to its gene', () => {
|
|
67
|
-
const gene = feature('gene', [feature('mRNA', [feature('CDS')])]);
|
|
68
|
-
const mrna = gene.get('subfeatures')[0];
|
|
69
|
-
expect(geneLikeRoot(mrna)).toBe(gene);
|
|
70
|
-
});
|
|
71
|
-
it('stays put with no gene-like parent', () => {
|
|
72
|
-
const mrna = feature('mRNA', [feature('CDS')]);
|
|
73
|
-
expect(geneLikeRoot(mrna)).toBe(mrna);
|
|
74
|
-
});
|
|
75
|
-
});
|
|
@@ -103,16 +103,14 @@ const BlastAutomaticPanel = observer(function ({ handleClose, feature, model, ch
|
|
|
103
103
|
selectedTranscript: selectedTranscript.toJSON(),
|
|
104
104
|
proteinSequence,
|
|
105
105
|
};
|
|
106
|
-
submit(() => {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
});
|
|
115
|
-
});
|
|
106
|
+
submit(() => launchConnectedView({
|
|
107
|
+
view,
|
|
108
|
+
feature: selectedTranscript,
|
|
109
|
+
placement,
|
|
110
|
+
displayName: getBlastViewTitle(feature, selectedTranscript),
|
|
111
|
+
...builtAlignmentLook,
|
|
112
|
+
blastParams,
|
|
113
|
+
}));
|
|
116
114
|
}
|
|
117
115
|
}, onCancel: handleClose })));
|
|
118
116
|
});
|
|
@@ -85,17 +85,15 @@ const BlastManualPanel = observer(function ({ handleClose, feature, model, child
|
|
|
85
85
|
React.createElement(QueryRowSelector, { ...queryRow })))),
|
|
86
86
|
React.createElement(SubmitCancelActions, { model: model, submitDisabled: !selectedTranscript || !msaText.trim(), onSubmit: placement => {
|
|
87
87
|
if (selectedTranscript) {
|
|
88
|
-
submit(() => {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
});
|
|
98
|
-
});
|
|
88
|
+
submit(() => launchConnectedView({
|
|
89
|
+
view,
|
|
90
|
+
feature: selectedTranscript,
|
|
91
|
+
placement,
|
|
92
|
+
displayName: getGeneDisplayName(selectedTranscript),
|
|
93
|
+
querySeqName: queryRow.querySeqName,
|
|
94
|
+
querySeqOffset: queryRow.querySeqOffset,
|
|
95
|
+
data: { msa: msaText, tree: treeText },
|
|
96
|
+
}));
|
|
99
97
|
}
|
|
100
98
|
}, onCancel: handleClose })));
|
|
101
99
|
});
|
|
@@ -70,8 +70,10 @@ const CachedBlastResults = observer(function ({ model, handleClose, feature, })
|
|
|
70
70
|
displayName: `BLAST - ${getResultDisplayName(cached)}`,
|
|
71
71
|
...builtAlignmentLook,
|
|
72
72
|
data: { msa, tree, treeMetadata },
|
|
73
|
+
}).then(handleClose, (e) => {
|
|
74
|
+
console.error(e);
|
|
75
|
+
setOperationError(e);
|
|
73
76
|
});
|
|
74
|
-
handleClose();
|
|
75
77
|
};
|
|
76
78
|
const displayError = error ?? operationError;
|
|
77
79
|
return displayError ? (React.createElement(ErrorMessage, { error: displayError })) : isLoading ? (React.createElement(Typography, null, "Loading cached results...")) : results.length === 0 ? (React.createElement(Typography, { color: "textSecondary" }, "No cached BLAST results found for this gene. Run a BLAST query to cache results.")) : (React.createElement("div", null,
|
|
@@ -80,22 +80,20 @@ const ManualMSALoader = observer(function PreLoadedMSA2({ model, feature, handle
|
|
|
80
80
|
(inputMethod === 'file' && !msaFileLocation) ||
|
|
81
81
|
(inputMethod === 'text' && !msaText.trim()), onSubmit: placement => {
|
|
82
82
|
if (selectedTranscript) {
|
|
83
|
-
submit(() => {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
});
|
|
98
|
-
});
|
|
83
|
+
submit(() => launchConnectedView({
|
|
84
|
+
view,
|
|
85
|
+
feature: selectedTranscript,
|
|
86
|
+
placement,
|
|
87
|
+
displayName: getGeneDisplayName(selectedTranscript),
|
|
88
|
+
querySeqName: queryRow.querySeqName,
|
|
89
|
+
querySeqOffset: queryRow.querySeqOffset,
|
|
90
|
+
...(inputMethod === 'file'
|
|
91
|
+
? {
|
|
92
|
+
msaFilehandle: msaFileLocation,
|
|
93
|
+
treeFilehandle: treeFileLocation,
|
|
94
|
+
}
|
|
95
|
+
: { data: { msa: msaText, tree: treeText } }),
|
|
96
|
+
}));
|
|
99
97
|
}
|
|
100
98
|
}, onCancel: handleClose })));
|
|
101
99
|
});
|
|
@@ -60,24 +60,22 @@ const OrthologPanel = observer(function ({ handleClose, feature, model, preferre
|
|
|
60
60
|
React.createElement(TranscriptSelector, { feature: feature, ...transcriptSelection })),
|
|
61
61
|
React.createElement(SubmitCancelActions, { model: model, hint: React.createElement(SequenceStatusMessage, { status: sequenceStatus }), submitDisabled: !proteinSequence || !rowCountValid, onSubmit: placement => {
|
|
62
62
|
if (selectedTranscript) {
|
|
63
|
-
submit(() => {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
});
|
|
80
|
-
});
|
|
63
|
+
submit(() => launchConnectedView({
|
|
64
|
+
view,
|
|
65
|
+
feature: selectedTranscript,
|
|
66
|
+
placement,
|
|
67
|
+
displayName: `Orthologs - ${getGeneDisplayName(feature)} - ${getTranscriptDisplayName(selectedTranscript)}`,
|
|
68
|
+
...builtAlignmentLook,
|
|
69
|
+
orthologParams: {
|
|
70
|
+
taxId,
|
|
71
|
+
source,
|
|
72
|
+
maxSpecies: rowCount,
|
|
73
|
+
geneCandidates,
|
|
74
|
+
msaAlgorithm,
|
|
75
|
+
selectedTranscript: selectedTranscript.toJSON(),
|
|
76
|
+
proteinSequence,
|
|
77
|
+
},
|
|
78
|
+
}));
|
|
81
79
|
}
|
|
82
80
|
}, onCancel: handleClose })));
|
|
83
81
|
});
|
|
@@ -82,25 +82,23 @@ const PreLoadedMSA = observer(function ({ model, feature, handleClose, preferred
|
|
|
82
82
|
// dataset that does not cover this gene
|
|
83
83
|
submitDisabled: !selectedTranscript || !msaData?.length || !querySeqName, onSubmit: placement => {
|
|
84
84
|
if (selectedTranscript && msaText) {
|
|
85
|
-
submit(() => {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
});
|
|
103
|
-
});
|
|
85
|
+
submit(() => launchConnectedView({
|
|
86
|
+
view,
|
|
87
|
+
feature: selectedTranscript,
|
|
88
|
+
placement,
|
|
89
|
+
displayName: getGeneDisplayName(selectedTranscript),
|
|
90
|
+
treeAreaWidth: 200,
|
|
91
|
+
treeWidth: 100,
|
|
92
|
+
drawNodeBubbles: false,
|
|
93
|
+
labelsAlignRight: true,
|
|
94
|
+
showBranchLen: false,
|
|
95
|
+
colWidth: 10,
|
|
96
|
+
rowHeight: 12,
|
|
97
|
+
colorSchemeName: 'percent_identity_dynamic',
|
|
98
|
+
querySeqName,
|
|
99
|
+
querySeqOffset: queryRow.querySeqOffset,
|
|
100
|
+
data: { msa: msaText },
|
|
101
|
+
}));
|
|
104
102
|
}
|
|
105
103
|
}, onCancel: handleClose })));
|
|
106
104
|
});
|
|
@@ -5,11 +5,8 @@ export async function fetchSeq({ start, end, refName, session, assemblyName, })
|
|
|
5
5
|
if (!assembly) {
|
|
6
6
|
throw new Error('assembly not found');
|
|
7
7
|
}
|
|
8
|
-
const
|
|
9
|
-
// a named object keeps sessionId, which v4 hosts read from the args
|
|
10
|
-
const args = {
|
|
8
|
+
const feats = await rpcManager.call('getSequence', 'CoreGetFeatures', {
|
|
11
9
|
adapterConfig: getConf(assembly, ['sequence', 'adapter']),
|
|
12
|
-
sessionId,
|
|
13
10
|
regions: [
|
|
14
11
|
{
|
|
15
12
|
start,
|
|
@@ -18,15 +15,11 @@ export async function fetchSeq({ start, end, refName, session, assemblyName, })
|
|
|
18
15
|
assemblyName,
|
|
19
16
|
},
|
|
20
17
|
],
|
|
21
|
-
};
|
|
22
|
-
const feats = await rpcManager.call(sessionId, 'CoreGetFeatures', args);
|
|
18
|
+
});
|
|
23
19
|
return {
|
|
24
20
|
seq: feats[0]?.get('seq') ?? '',
|
|
25
21
|
// travels with the sequence because the caller needs both to translate, and
|
|
26
22
|
// resolving the assembly twice to get them is the shape that lost it
|
|
27
|
-
assemblyGeneticCodeId:
|
|
23
|
+
assemblyGeneticCodeId: assembly.getGeneticCodeId(refName),
|
|
28
24
|
};
|
|
29
25
|
}
|
|
30
|
-
function geneticCodeId(assembly, refName) {
|
|
31
|
-
return assembly.getGeneticCodeId?.(refName);
|
|
32
|
-
}
|
|
@@ -15,9 +15,9 @@ export declare function launchConnectedView({ view, feature, placement, ...snaps
|
|
|
15
15
|
view: LinearGenomeViewModel;
|
|
16
16
|
feature?: Feature;
|
|
17
17
|
placement: MsaViewPlacement;
|
|
18
|
-
} & Record<string, unknown>):
|
|
18
|
+
} & Record<string, unknown>): Promise<import("@jbrowse/core/util").AbstractViewModel>;
|
|
19
19
|
/** runs a panel's launch, closing the dialog on success and keeping the error */
|
|
20
20
|
export declare function useLaunchSubmit(handleClose: () => void): {
|
|
21
21
|
launchError: unknown;
|
|
22
|
-
submit: (launch: () =>
|
|
22
|
+
submit: (launch: () => Promise<unknown>) => void;
|
|
23
23
|
};
|
|
@@ -12,7 +12,7 @@ export const builtAlignmentLook = {
|
|
|
12
12
|
* through `feature` to the transcript whose codons its query row is read by.
|
|
13
13
|
*/
|
|
14
14
|
export function launchConnectedView({ view, feature, placement, ...snapshot }) {
|
|
15
|
-
launchMsaView(getSession(view), {
|
|
15
|
+
return launchMsaView(getSession(view), {
|
|
16
16
|
placement,
|
|
17
17
|
connectedViewId: view.id,
|
|
18
18
|
connectedFeature: feature?.toJSON(),
|
|
@@ -25,15 +25,11 @@ export function useLaunchSubmit(handleClose) {
|
|
|
25
25
|
return {
|
|
26
26
|
launchError,
|
|
27
27
|
submit: (launch) => {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
launch();
|
|
31
|
-
handleClose();
|
|
32
|
-
}
|
|
33
|
-
catch (e) {
|
|
28
|
+
setLaunchError(undefined);
|
|
29
|
+
launch().then(handleClose, (e) => {
|
|
34
30
|
console.error(e);
|
|
35
31
|
setLaunchError(e);
|
|
36
|
-
}
|
|
32
|
+
});
|
|
37
33
|
},
|
|
38
34
|
};
|
|
39
35
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { lazy } from 'react';
|
|
1
2
|
import { getContainingTrack, getSession } from '@jbrowse/core/util';
|
|
2
3
|
import AddIcon from '@mui/icons-material/Add';
|
|
3
4
|
import { isCodingFeature } from './codingFeature';
|
|
4
|
-
import LaunchMsaViewDialog from './components/LaunchMsaViewDialog';
|
|
5
5
|
import { launchTarget } from './launchTarget';
|
|
6
|
+
const LaunchMsaViewDialog = lazy(() => import('./components/LaunchMsaViewDialog'));
|
|
6
7
|
function isDisplay(elt) {
|
|
7
8
|
return elt.name === 'LinearBasicDisplay';
|
|
8
9
|
}
|
|
@@ -23,10 +24,6 @@ function openDialog(self, target) {
|
|
|
23
24
|
{ model: track, handleClose, feature, preferredTranscriptId },
|
|
24
25
|
]);
|
|
25
26
|
};
|
|
26
|
-
if ('feature' in target) {
|
|
27
|
-
open(target.feature);
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
27
|
target
|
|
31
28
|
.fetchFeature()
|
|
32
29
|
.then(feature => {
|
|
@@ -54,14 +51,8 @@ export function extendStateModel(stateModel) {
|
|
|
54
51
|
contextMenuItems() {
|
|
55
52
|
const target = launchTarget(self);
|
|
56
53
|
return [
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
// captured super is invoked detached. It throws, the ErrorBoundary the
|
|
60
|
-
// menu builds inside swallows it, and the user right-clicks a feature
|
|
61
|
-
// and gets no menu at all -- the host's own rows gone too, which is
|
|
62
|
-
// worse than this plugin contributing nothing. jbrowse-components hit
|
|
63
|
-
// exactly this with `this.isGeneLike` and fixed its side in
|
|
64
|
-
// 104bbfc581, but a plugin cannot choose which host build it runs on.
|
|
54
|
+
// a detached call leaves `this` undefined for a host method that
|
|
55
|
+
// reads it, and the throw takes the host's own rows with it
|
|
65
56
|
...superContextMenuItems.call(self),
|
|
66
57
|
...(target
|
|
67
58
|
? [
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { isGeneLikeType } from './codingFeature';
|
|
2
1
|
import type { MenuItem } from '@jbrowse/core/ui';
|
|
3
2
|
import type { Feature } from '@jbrowse/core/util';
|
|
4
3
|
export interface ContextMenuInfo {
|
|
@@ -14,43 +13,21 @@ export interface ContextMenuInfo {
|
|
|
14
13
|
export interface DisplayModel {
|
|
15
14
|
contextMenuItems: () => MenuItem[];
|
|
16
15
|
contextMenuInfo?: ContextMenuInfo;
|
|
17
|
-
fetchFullFeature
|
|
18
|
-
contextMenuFeature?: Feature;
|
|
16
|
+
fetchFullFeature: (featureId: string, displayedRegionIndex: number) => Promise<Feature | undefined>;
|
|
19
17
|
}
|
|
20
18
|
/**
|
|
21
|
-
* What the menu item launches on.
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* answered after the fetch, and the caller answers it there.
|
|
19
|
+
* What the menu item launches on. The hit test carries a type and an id, so
|
|
20
|
+
* whether the feature codes for anything can only be answered after the fetch,
|
|
21
|
+
* and the caller answers it there.
|
|
25
22
|
*/
|
|
26
|
-
interface
|
|
23
|
+
export interface MenuTarget {
|
|
24
|
+
fetchFeature: () => Promise<Feature | undefined>;
|
|
27
25
|
/**
|
|
28
26
|
* The isoform the click actually landed on, when the dialog opens on its
|
|
29
27
|
* gene. Climbing to the gene is what puts every isoform in the picker, and it
|
|
30
28
|
* threw away which one the user pointed at: the picker then opened on the
|
|
31
|
-
* longest transcript
|
|
32
|
-
* ever stated.
|
|
29
|
+
* longest transcript.
|
|
33
30
|
*/
|
|
34
31
|
preferredTranscriptId?: string;
|
|
35
32
|
}
|
|
36
|
-
export type MenuTarget = (ClickedTranscript & {
|
|
37
|
-
feature: Feature;
|
|
38
|
-
}) | (ClickedTranscript & {
|
|
39
|
-
fetchFeature: () => Promise<Feature | undefined>;
|
|
40
|
-
});
|
|
41
|
-
export { isGeneLikeType };
|
|
42
|
-
/**
|
|
43
|
-
* How to get the right-clicked feature, or nothing when there is nothing to
|
|
44
|
-
* launch on. Both host shapes reduce to one target, so the menu item is built
|
|
45
|
-
* and the dialog is opened by one code path — and the same gene test decides
|
|
46
|
-
* both. The strict three-name set the legacy branch used to carry disagreed
|
|
47
|
-
* with the loose one above, so a `lnc_RNA` offered the menu item on a 4.3 host
|
|
48
|
-
* and not on a 3.7 one.
|
|
49
|
-
*
|
|
50
|
-
* Gene-like is not enough on its own: an lncRNA has no protein to align, and
|
|
51
|
-
* accepting it opened a dialog whose Submit never left grey, with nothing
|
|
52
|
-
* saying why. Where the whole feature is in hand the CDS decides here -- but
|
|
53
|
-
* only where there are subfeatures to read it off, since a feature that came
|
|
54
|
-
* with none has not answered the question.
|
|
55
|
-
*/
|
|
56
33
|
export declare function launchTarget(self: DisplayModel): MenuTarget | undefined;
|
|
@@ -1,53 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
// Read off the clicked item rather than off the display
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// `contextMenuItems`, and every host built after it returns `undefined` here --
|
|
7
|
-
// so the gate was never satisfied, `onClick` stayed undefined, and the item
|
|
8
|
-
// silently left the right-click menu on every gene track. Nothing failed loudly:
|
|
9
|
-
// the display still had contextMenuInfo and fetchFullFeature, and the menu still
|
|
10
|
-
// opened with its own items in it.
|
|
11
|
-
//
|
|
12
|
-
// A predicate over the type we were already given cannot go the same way, and it
|
|
13
|
-
// costs one comparison. Deliberately the same loose case-insensitive test the
|
|
14
|
-
// host applies (`isGeneLikeType` in collapseIntronsMenu.ts): real GFFs carry
|
|
15
|
-
// 'mRNA', 'lnc_RNA', 'protein_coding_gene', 'transcript'.
|
|
16
|
-
export { isGeneLikeType };
|
|
17
|
-
/**
|
|
18
|
-
* How to get the right-clicked feature, or nothing when there is nothing to
|
|
19
|
-
* launch on. Both host shapes reduce to one target, so the menu item is built
|
|
20
|
-
* and the dialog is opened by one code path — and the same gene test decides
|
|
21
|
-
* both. The strict three-name set the legacy branch used to carry disagreed
|
|
22
|
-
* with the loose one above, so a `lnc_RNA` offered the menu item on a 4.3 host
|
|
23
|
-
* and not on a 3.7 one.
|
|
24
|
-
*
|
|
25
|
-
* Gene-like is not enough on its own: an lncRNA has no protein to align, and
|
|
26
|
-
* accepting it opened a dialog whose Submit never left grey, with nothing
|
|
27
|
-
* saying why. Where the whole feature is in hand the CDS decides here -- but
|
|
28
|
-
* only where there are subfeatures to read it off, since a feature that came
|
|
29
|
-
* with none has not answered the question.
|
|
30
|
-
*/
|
|
1
|
+
import { isGeneLikeType } from '@jbrowse/core/util';
|
|
2
|
+
// Read off the clicked item rather than off the display: LinearBasicDisplay's
|
|
3
|
+
// `isGeneLike` getter was inlined into its own `contextMenuItems`
|
|
4
|
+
// (jbrowse-components 684142b3), and gating on it silently took the item off
|
|
5
|
+
// every gene track.
|
|
31
6
|
export function launchTarget(self) {
|
|
32
7
|
const info = self.contextMenuInfo;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return isGeneLikeType(info.item.type)
|
|
39
|
-
? {
|
|
40
|
-
fetchFeature: () => fetchFullFeature(info.item.featureId, info.displayedRegionIndex),
|
|
41
|
-
preferredTranscriptId: info.subfeature?.featureId,
|
|
42
|
-
}
|
|
43
|
-
: undefined;
|
|
44
|
-
}
|
|
45
|
-
const legacy = self.contextMenuFeature;
|
|
46
|
-
if (!legacy) {
|
|
47
|
-
return undefined;
|
|
48
|
-
}
|
|
49
|
-
const root = geneLikeRoot(legacy);
|
|
50
|
-
return isGeneLikeType(root.get('type')) && !isKnownNonCoding(root)
|
|
51
|
-
? { feature: root, preferredTranscriptId: legacy.id() }
|
|
8
|
+
return info && isGeneLikeType(info.item.type)
|
|
9
|
+
? {
|
|
10
|
+
fetchFeature: () => self.fetchFullFeature(info.item.featureId, info.displayedRegionIndex),
|
|
11
|
+
preferredTranscriptId: info.subfeature?.featureId,
|
|
12
|
+
}
|
|
52
13
|
: undefined;
|
|
53
14
|
}
|