jbrowse-plugin-msaview 2.7.1 → 2.7.2
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/NCBIBlastPanel.js +1 -1
- package/dist/LaunchMsaView/components/calculateProteinSequence.d.ts +3 -2
- package/dist/LaunchMsaView/components/calculateProteinSequence.js +31 -15
- package/dist/LaunchMsaView/components/geneticCodes.d.ts +15 -0
- package/dist/LaunchMsaView/components/geneticCodes.js +227 -0
- package/dist/LaunchMsaView/components/types.d.ts +1 -0
- package/dist/LaunchMsaView/index.js +32 -26
- package/dist/jbrowse-plugin-msaview.umd.production.min.js +27 -27
- package/dist/jbrowse-plugin-msaview.umd.production.min.js.map +4 -4
- package/dist/utils/useLocalStorage.d.ts +1 -0
- package/dist/utils/useLocalStorage.js +29 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -2
- package/src/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastPanel.tsx +1 -1
- package/src/LaunchMsaView/components/calculateProteinSequence.ts +35 -20
- package/src/LaunchMsaView/components/geneticCodes.ts +298 -0
- package/src/LaunchMsaView/components/types.ts +3 -0
- package/src/LaunchMsaView/index.ts +44 -35
- package/src/utils/useLocalStorage.ts +31 -0
- package/src/version.ts +1 -1
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
|
-
import { useLocalStorage } from '@jbrowse/core/util';
|
|
3
2
|
import SettingsIcon from '@mui/icons-material/Settings';
|
|
4
3
|
import { IconButton } from '@mui/material';
|
|
5
4
|
import { makeStyles } from 'tss-react/mui';
|
|
@@ -9,6 +8,7 @@ import NCBIBlastMethodSelector from './NCBIBlastMethodSelector';
|
|
|
9
8
|
import NCBIBlastRIDPanel from './NCBIBlastRIDPanel';
|
|
10
9
|
import NCBISettingsDialog from './NCBISettingsDialog';
|
|
11
10
|
import { BASE_BLAST_URL } from './consts';
|
|
11
|
+
import { useLocalStorage } from '../../../utils/useLocalStorage';
|
|
12
12
|
const useStyles = makeStyles()({
|
|
13
13
|
settingsButton: {
|
|
14
14
|
float: 'right',
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import type { Feat } from './types';
|
|
2
2
|
import type { Feature } from '@jbrowse/core/util';
|
|
3
|
-
export declare function
|
|
4
|
-
export declare function calculateProteinSequence({ cds, sequence, }: {
|
|
3
|
+
export declare function calculateProteinSequence({ cds, sequence, geneticCodeId, }: {
|
|
5
4
|
cds: Feat[];
|
|
6
5
|
sequence: string;
|
|
6
|
+
geneticCodeId?: number;
|
|
7
7
|
}): string;
|
|
8
8
|
export declare function revlist(list: Feat[], seqlen: number): {
|
|
9
9
|
start: number;
|
|
10
10
|
end: number;
|
|
11
11
|
type?: string;
|
|
12
|
+
phase?: number;
|
|
12
13
|
}[];
|
|
13
14
|
export declare function getProteinSequenceFromFeature({ feature, seq, }: {
|
|
14
15
|
seq: string;
|
|
@@ -1,18 +1,25 @@
|
|
|
1
|
-
import { dedupe,
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
import { dedupe, revcom } from '@jbrowse/core/util';
|
|
2
|
+
import { convertCodingSequenceToPeptides } from '@jbrowse/core/util/convertCodingSequenceToPeptides';
|
|
3
|
+
import { getGeneticCode, parseTranslTable } from './geneticCodes';
|
|
4
|
+
// `@jbrowse/core/util/convertCodingSequenceToPeptides` is a deep path, so unlike
|
|
5
|
+
// the `@jbrowse/core/util` barrel it is absent from ReExports and gets bundled
|
|
6
|
+
// rather than resolved out of the host's JBrowseExports. That is what makes
|
|
7
|
+
// reusing core's translation safe across every host a config names: this module
|
|
8
|
+
// previously built its codon table at module scope from the barrel's
|
|
9
|
+
// `defaultCodonTable`, and a core build that dropped that export turned it into
|
|
10
|
+
// `Object.keys(undefined)` while the UMD was still evaluating -- the plugin
|
|
11
|
+
// global was never assigned and PluginLoader error-paged the whole app.
|
|
12
|
+
export function calculateProteinSequence({ cds, sequence, geneticCodeId, }) {
|
|
13
|
+
// `starts` is deliberately not passed: @jbrowse/core 4.3.0's signature has no
|
|
14
|
+
// such parameter, so alternative initiators (GTG under table 11, ATA under
|
|
15
|
+
// table 2) render as their internal residue rather than M. Core main added it;
|
|
16
|
+
// pass it here when msaview's @jbrowse/core floor reaches that release.
|
|
17
|
+
const { codonTable } = getGeneticCode(geneticCodeId);
|
|
18
|
+
return convertCodingSequenceToPeptides({
|
|
19
|
+
cds,
|
|
20
|
+
sequence,
|
|
21
|
+
codonTable,
|
|
22
|
+
});
|
|
16
23
|
}
|
|
17
24
|
export function revlist(list, seqlen) {
|
|
18
25
|
return list
|
|
@@ -33,8 +40,17 @@ export function getProteinSequenceFromFeature({ feature, seq, }) {
|
|
|
33
40
|
end: sub.end - start,
|
|
34
41
|
}))
|
|
35
42
|
.filter(subfeature => subfeature.type === 'CDS') ?? [], feat => `${feat.start}-${feat.end}`);
|
|
43
|
+
// a mitochondrial gene declares e.g. transl_table=2, so it translates with
|
|
44
|
+
// NCBI table 2 rather than the standard code. GFF3 usually carries the
|
|
45
|
+
// attribute on the CDS rather than the transcript, so check both.
|
|
46
|
+
const cdsSubfeature = feature
|
|
47
|
+
.get('subfeatures')
|
|
48
|
+
?.find((f) => f.get('type')?.toLowerCase() === 'cds');
|
|
49
|
+
const geneticCodeId = parseTranslTable(feature.get('transl_table')) ??
|
|
50
|
+
parseTranslTable(cdsSubfeature?.get('transl_table'));
|
|
36
51
|
return calculateProteinSequence({
|
|
37
52
|
cds: strand === -1 ? revlist(cds, seq.length) : cds,
|
|
38
53
|
sequence: strand === -1 ? revcom(seq) : seq,
|
|
54
|
+
geneticCodeId,
|
|
39
55
|
});
|
|
40
56
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface NcbiGeneticCode {
|
|
2
|
+
id: number;
|
|
3
|
+
name: string;
|
|
4
|
+
ncbieaa: string;
|
|
5
|
+
sncbieaa: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const ncbiGeneticCodes: NcbiGeneticCode[];
|
|
8
|
+
export interface GeneticCode {
|
|
9
|
+
id: number;
|
|
10
|
+
name: string;
|
|
11
|
+
codonTable: Record<string, string>;
|
|
12
|
+
starts: string[];
|
|
13
|
+
}
|
|
14
|
+
export declare function getGeneticCode(id?: number): GeneticCode;
|
|
15
|
+
export declare function parseTranslTable(value: unknown): number | undefined;
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
export const ncbiGeneticCodes = [
|
|
2
|
+
{
|
|
3
|
+
id: 1,
|
|
4
|
+
name: 'Standard',
|
|
5
|
+
ncbieaa: 'FFLLSSSSYY**CC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG',
|
|
6
|
+
sncbieaa: '---M------**--*----M---------------M----------------------------',
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
id: 2,
|
|
10
|
+
name: 'Vertebrate Mitochondrial',
|
|
11
|
+
ncbieaa: 'FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIMMTTTTNNKKSS**VVVVAAAADDEEGGGG',
|
|
12
|
+
sncbieaa: '----------**--------------------MMMM----------**---M------------',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
id: 3,
|
|
16
|
+
name: 'Yeast Mitochondrial',
|
|
17
|
+
ncbieaa: 'FFLLSSSSYY**CCWWTTTTPPPPHHQQRRRRIIMMTTTTNNKKSSRRVVVVAAAADDEEGGGG',
|
|
18
|
+
sncbieaa: '----------**----------------------MM---------------M------------',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: 4,
|
|
22
|
+
name: 'Mold Mitochondrial; Protozoan Mitochondrial; Coelenterate Mitochondrial; Mycoplasma; Spiroplasma',
|
|
23
|
+
ncbieaa: 'FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG',
|
|
24
|
+
sncbieaa: '--MM------**-------M------------MMMM---------------M------------',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: 5,
|
|
28
|
+
name: 'Invertebrate Mitochondrial',
|
|
29
|
+
ncbieaa: 'FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIMMTTTTNNKKSSSSVVVVAAAADDEEGGGG',
|
|
30
|
+
sncbieaa: '---M------**--------------------MMMM---------------M------------',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: 6,
|
|
34
|
+
name: 'Ciliate Nuclear; Dasycladacean Nuclear; Hexamita Nuclear',
|
|
35
|
+
ncbieaa: 'FFLLSSSSYYQQCC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG',
|
|
36
|
+
sncbieaa: '--------------*--------------------M----------------------------',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: 9,
|
|
40
|
+
name: 'Echinoderm Mitochondrial; Flatworm Mitochondrial',
|
|
41
|
+
ncbieaa: 'FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIIMTTTTNNNKSSSSVVVVAAAADDEEGGGG',
|
|
42
|
+
sncbieaa: '----------**-----------------------M---------------M------------',
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: 10,
|
|
46
|
+
name: 'Euplotid Nuclear',
|
|
47
|
+
ncbieaa: 'FFLLSSSSYY**CCCWLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG',
|
|
48
|
+
sncbieaa: '----------**-----------------------M----------------------------',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: 11,
|
|
52
|
+
name: 'Bacterial, Archaeal and Plant Plastid',
|
|
53
|
+
ncbieaa: 'FFLLSSSSYY**CC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG',
|
|
54
|
+
sncbieaa: '---M------**--*----M------------MMMM---------------M------------',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: 12,
|
|
58
|
+
name: 'Alternative Yeast Nuclear',
|
|
59
|
+
ncbieaa: 'FFLLSSSSYY**CC*WLLLSPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG',
|
|
60
|
+
sncbieaa: '----------**--*----M---------------M----------------------------',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
id: 13,
|
|
64
|
+
name: 'Ascidian Mitochondrial',
|
|
65
|
+
ncbieaa: 'FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIMMTTTTNNKKSSGGVVVVAAAADDEEGGGG',
|
|
66
|
+
sncbieaa: '---M------**----------------------MM---------------M------------',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
id: 14,
|
|
70
|
+
name: 'Alternative Flatworm Mitochondrial',
|
|
71
|
+
ncbieaa: 'FFLLSSSSYYY*CCWWLLLLPPPPHHQQRRRRIIIMTTTTNNNKSSSSVVVVAAAADDEEGGGG',
|
|
72
|
+
sncbieaa: '-----------*-----------------------M----------------------------',
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: 15,
|
|
76
|
+
name: 'Blepharisma Macronuclear',
|
|
77
|
+
ncbieaa: 'FFLLSSSSYY*QCC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG',
|
|
78
|
+
sncbieaa: '----------*---*--------------------M----------------------------',
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
id: 16,
|
|
82
|
+
name: 'Chlorophycean Mitochondrial',
|
|
83
|
+
ncbieaa: 'FFLLSSSSYY*LCC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG',
|
|
84
|
+
sncbieaa: '----------*---*--------------------M----------------------------',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
id: 21,
|
|
88
|
+
name: 'Trematode Mitochondrial',
|
|
89
|
+
ncbieaa: 'FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIMMTTTTNNNKSSSSVVVVAAAADDEEGGGG',
|
|
90
|
+
sncbieaa: '----------**-----------------------M---------------M------------',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: 22,
|
|
94
|
+
name: 'Scenedesmus obliquus Mitochondrial',
|
|
95
|
+
ncbieaa: 'FFLLSS*SYY*LCC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG',
|
|
96
|
+
sncbieaa: '------*---*---*--------------------M----------------------------',
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
id: 23,
|
|
100
|
+
name: 'Thraustochytrium Mitochondrial',
|
|
101
|
+
ncbieaa: 'FF*LSSSSYY**CC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG',
|
|
102
|
+
sncbieaa: '--*-------**--*-----------------M--M---------------M------------',
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
id: 24,
|
|
106
|
+
name: 'Rhabdopleuridae Mitochondrial',
|
|
107
|
+
ncbieaa: 'FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSSKVVVVAAAADDEEGGGG',
|
|
108
|
+
sncbieaa: '---M------**-------M---------------M---------------M------------',
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
id: 25,
|
|
112
|
+
name: 'Candidate Division SR1 and Gracilibacteria',
|
|
113
|
+
ncbieaa: 'FFLLSSSSYY**CCGWLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG',
|
|
114
|
+
sncbieaa: '---M------**-----------------------M---------------M------------',
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
id: 26,
|
|
118
|
+
name: 'Pachysolen tannophilus Nuclear',
|
|
119
|
+
ncbieaa: 'FFLLSSSSYY**CC*WLLLAPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG',
|
|
120
|
+
sncbieaa: '----------**--*----M---------------M----------------------------',
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
id: 27,
|
|
124
|
+
name: 'Karyorelict Nuclear',
|
|
125
|
+
ncbieaa: 'FFLLSSSSYYQQCCWWLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG',
|
|
126
|
+
sncbieaa: '--------------*--------------------M----------------------------',
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
id: 28,
|
|
130
|
+
name: 'Condylostoma Nuclear',
|
|
131
|
+
ncbieaa: 'FFLLSSSSYYQQCCWWLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG',
|
|
132
|
+
sncbieaa: '----------**--*--------------------M----------------------------',
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
id: 29,
|
|
136
|
+
name: 'Mesodinium Nuclear',
|
|
137
|
+
ncbieaa: 'FFLLSSSSYYYYCC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG',
|
|
138
|
+
sncbieaa: '--------------*--------------------M----------------------------',
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
id: 30,
|
|
142
|
+
name: 'Peritrich Nuclear',
|
|
143
|
+
ncbieaa: 'FFLLSSSSYYEECC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG',
|
|
144
|
+
sncbieaa: '--------------*--------------------M----------------------------',
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
id: 31,
|
|
148
|
+
name: 'Blastocrithidia Nuclear',
|
|
149
|
+
ncbieaa: 'FFLLSSSSYYEECCWWLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG',
|
|
150
|
+
sncbieaa: '----------**-----------------------M----------------------------',
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
id: 32,
|
|
154
|
+
name: 'Balanophoraceae Plastid',
|
|
155
|
+
ncbieaa: 'FFLLSSSSYY*WCC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG',
|
|
156
|
+
sncbieaa: '---M------*---*----M------------MMMM---------------M------------',
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
id: 33,
|
|
160
|
+
name: 'Cephalodiscidae Mitochondrial',
|
|
161
|
+
ncbieaa: 'FFLLSSSSYYY*CCWWLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSSKVVVVAAAADDEEGGGG',
|
|
162
|
+
sncbieaa: '---M-------*-------M---------------M---------------M------------',
|
|
163
|
+
},
|
|
164
|
+
];
|
|
165
|
+
// The codon order shared by every NCBI table -- the Base1/Base2/Base3 comment
|
|
166
|
+
// rows in gc.prt. codon i = BASE1[i] + BASE2[i] + BASE3[i].
|
|
167
|
+
const BASE1 = 'TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG';
|
|
168
|
+
const BASE2 = 'TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG';
|
|
169
|
+
const BASE3 = 'TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG';
|
|
170
|
+
const CODONS = Array.from({ length: 64 }, (_, i) => BASE1[i] + BASE2[i] + BASE3[i]);
|
|
171
|
+
const ncbiCodeById = new Map(ncbiGeneticCodes.map(t => [t.id, t]));
|
|
172
|
+
// Expand an uppercase codon map so every case combination of a triplet resolves,
|
|
173
|
+
// which is what callers reading raw sequence need.
|
|
174
|
+
function caseExpand(table) {
|
|
175
|
+
const out = {};
|
|
176
|
+
for (const [codon, aa] of Object.entries(table)) {
|
|
177
|
+
const cases = (i) => {
|
|
178
|
+
const n = codon.charAt(i);
|
|
179
|
+
return [n.toUpperCase(), n.toLowerCase()];
|
|
180
|
+
};
|
|
181
|
+
for (const n0 of cases(0)) {
|
|
182
|
+
for (const n1 of cases(1)) {
|
|
183
|
+
for (const n2 of cases(2)) {
|
|
184
|
+
out[n0 + n1 + n2] = aa;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return out;
|
|
190
|
+
}
|
|
191
|
+
function buildGeneticCode(id) {
|
|
192
|
+
const def = ncbiCodeById.get(id);
|
|
193
|
+
if (!def && id !== 1) {
|
|
194
|
+
console.warn(`Unknown genetic code (transl_table=${id}); using standard code`);
|
|
195
|
+
}
|
|
196
|
+
const { id: resolvedId, name, ncbieaa, sncbieaa, } = def ?? ncbiCodeById.get(1);
|
|
197
|
+
const table = {};
|
|
198
|
+
const starts = [];
|
|
199
|
+
for (const [i, codon] of CODONS.entries()) {
|
|
200
|
+
table[codon] = ncbieaa[i];
|
|
201
|
+
if (sncbieaa[i] === 'M') {
|
|
202
|
+
starts.push(codon);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return { id: resolvedId, name, codonTable: caseExpand(table), starts };
|
|
206
|
+
}
|
|
207
|
+
const geneticCodeCache = new Map();
|
|
208
|
+
// Resolves the codon map + start set for an NCBI translation-table id, falling
|
|
209
|
+
// back to the standard code (1) for an unrecognized id. Memoized: there are only
|
|
210
|
+
// ~27 tables and each result is immutable.
|
|
211
|
+
export function getGeneticCode(id = 1) {
|
|
212
|
+
let code = geneticCodeCache.get(id);
|
|
213
|
+
if (!code) {
|
|
214
|
+
code = buildGeneticCode(id);
|
|
215
|
+
geneticCodeCache.set(id, code);
|
|
216
|
+
}
|
|
217
|
+
return code;
|
|
218
|
+
}
|
|
219
|
+
// Parses a GFF/GenBank `transl_table` attribute value into an NCBI table id. The
|
|
220
|
+
// GFF adapter yields a string (or an array if the attribute repeated), so this
|
|
221
|
+
// normalizes both; returns undefined for a missing or non-positive-integer value
|
|
222
|
+
// so callers fall back to their default code.
|
|
223
|
+
export function parseTranslTable(value) {
|
|
224
|
+
const raw = Array.isArray(value) ? value[0] : value;
|
|
225
|
+
const n = Number(raw);
|
|
226
|
+
return Number.isInteger(n) && n > 0 ? n : undefined;
|
|
227
|
+
}
|
|
@@ -4,6 +4,7 @@ import LaunchMsaViewDialog from './components/LaunchMsaViewDialog';
|
|
|
4
4
|
function isDisplay(elt) {
|
|
5
5
|
return elt.name === 'LinearBasicDisplay';
|
|
6
6
|
}
|
|
7
|
+
const GENE_LIKE_TYPES = new Set(['gene', 'mRNA', 'transcript']);
|
|
7
8
|
function extendStateModel(stateModel) {
|
|
8
9
|
return stateModel.views((self) => {
|
|
9
10
|
const superContextMenuItems = self.contextMenuItems;
|
|
@@ -11,35 +12,40 @@ function extendStateModel(stateModel) {
|
|
|
11
12
|
contextMenuItems() {
|
|
12
13
|
const track = getContainingTrack(self);
|
|
13
14
|
const session = getSession(track);
|
|
15
|
+
const launch = (feature) => {
|
|
16
|
+
session.queueDialog(handleClose => [
|
|
17
|
+
LaunchMsaViewDialog,
|
|
18
|
+
{ model: track, handleClose, feature },
|
|
19
|
+
]);
|
|
20
|
+
};
|
|
14
21
|
const info = self.contextMenuInfo;
|
|
15
|
-
const
|
|
22
|
+
const fetchFullFeature = self.fetchFullFeature;
|
|
23
|
+
const legacyFeature = self.contextMenuFeature;
|
|
24
|
+
const onClick = info && fetchFullFeature && self.isGeneLike
|
|
25
|
+
? () => {
|
|
26
|
+
fetchFullFeature(info.item.featureId, info.displayedRegionIndex)
|
|
27
|
+
.then(feature => {
|
|
28
|
+
if (feature) {
|
|
29
|
+
launch(feature);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
session.notify('Could not load feature for MSA view', 'warning');
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
.catch((e) => {
|
|
36
|
+
session.notifyError(`${e}`, e);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
: legacyFeature &&
|
|
40
|
+
GENE_LIKE_TYPES.has(String(legacyFeature.get('type')))
|
|
41
|
+
? () => {
|
|
42
|
+
launch(legacyFeature);
|
|
43
|
+
}
|
|
44
|
+
: undefined;
|
|
16
45
|
return [
|
|
17
46
|
...superContextMenuItems(),
|
|
18
|
-
...(
|
|
19
|
-
? [
|
|
20
|
-
{
|
|
21
|
-
label: 'Launch MSA view',
|
|
22
|
-
icon: AddIcon,
|
|
23
|
-
onClick: () => {
|
|
24
|
-
self
|
|
25
|
-
.fetchFullFeature(info.item.featureId, info.displayedRegionIndex)
|
|
26
|
-
.then(feature => {
|
|
27
|
-
if (feature) {
|
|
28
|
-
session.queueDialog(handleClose => [
|
|
29
|
-
LaunchMsaViewDialog,
|
|
30
|
-
{ model: track, handleClose, feature },
|
|
31
|
-
]);
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
session.notify('Could not load feature for MSA view', 'warning');
|
|
35
|
-
}
|
|
36
|
-
})
|
|
37
|
-
.catch((e) => {
|
|
38
|
-
session.notifyError(`${e}`, e);
|
|
39
|
-
});
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
]
|
|
47
|
+
...(onClick
|
|
48
|
+
? [{ label: 'Launch MSA view', icon: AddIcon, onClick }]
|
|
43
49
|
: []),
|
|
44
50
|
];
|
|
45
51
|
},
|