jbrowse-plugin-msaview 3.8.0 → 3.10.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.
Files changed (141) hide show
  1. package/dist/AddHighlightModel/MsaToGenomeHighlight.js +6 -22
  2. package/dist/AddHighlightModel/connectedHighlights.d.ts +9 -0
  3. package/dist/AddHighlightModel/connectedHighlights.js +15 -0
  4. package/dist/AddHighlightModel/connectedHighlights.test.js +36 -0
  5. package/dist/AddHighlightModel/index.js +0 -1
  6. package/dist/BgzipFastaMsaAdapter/BgzipFastaMsaAdapter.d.ts +2 -8
  7. package/dist/BgzipFastaMsaAdapter/configSchema.d.ts +10 -3
  8. package/dist/LaunchMsaView/cleanProteinSequence.test.js +36 -2
  9. package/dist/LaunchMsaView/components/BlastQuery/consts.d.ts +4 -4
  10. package/dist/LaunchMsaView/components/BlastQuery/consts.js +6 -4
  11. package/dist/LaunchMsaView/components/BlastQuery/searchChoiceStorage.d.ts +0 -2
  12. package/dist/LaunchMsaView/components/BlastQuery/searchChoiceStorage.js +2 -2
  13. package/dist/LaunchMsaView/components/OrthologQuery/OrthologSourceSelect.d.ts +0 -1
  14. package/dist/LaunchMsaView/components/OrthologQuery/OrthologSourceSelect.js +1 -1
  15. package/dist/LaunchMsaView/components/OrthologQuery/QuerySpeciesSelect.js +5 -5
  16. package/dist/LaunchMsaView/components/useFeatureSequence.js +3 -6
  17. package/dist/LaunchMsaView/launchTarget.test.js +1 -1
  18. package/dist/LaunchMsaView/util.d.ts +0 -1
  19. package/dist/LaunchMsaView/util.js +1 -1
  20. package/dist/MsaViewPanel/afterCreateAutoruns.d.ts +5 -14
  21. package/dist/MsaViewPanel/afterCreateAutoruns.js +77 -86
  22. package/dist/MsaViewPanel/components/MsaViewPanel.js +1 -1
  23. package/dist/MsaViewPanel/doLaunchBlast.js +42 -16
  24. package/dist/MsaViewPanel/doLaunchBlast.test.js +54 -0
  25. package/dist/MsaViewPanel/doLaunchOrthologs.js +18 -11
  26. package/dist/MsaViewPanel/launchAutoruns.test.js +0 -1
  27. package/dist/MsaViewPanel/model.d.ts +651 -216
  28. package/dist/MsaViewPanel/model.js +39 -10
  29. package/dist/MsaViewPanel/model.test.js +3 -4
  30. package/dist/MsaViewPanel/msaDataStore.d.ts +1 -2
  31. package/dist/MsaViewPanel/msaDataStore.js +11 -26
  32. package/dist/MsaViewPanel/msaDataStore.test.js +10 -2
  33. package/dist/MsaViewPanel/observeProteinHighlights.test.js +1 -0
  34. package/dist/MsaViewPanel/processInit.test.js +1 -7
  35. package/dist/MsaViewPanel/regionSnapshot.test.js +0 -1
  36. package/dist/MsaViewPanel/resolveConnectedTranscript.js +7 -13
  37. package/dist/MsaViewPanel/resolveConnectedTranscript.test.js +2 -3
  38. package/dist/MsaViewPanel/storedData.test.js +238 -145
  39. package/dist/MsaViewPanel/transcriptMap.d.ts +7 -0
  40. package/dist/MsaViewPanel/transcriptMap.js +108 -0
  41. package/dist/MsaViewPanel/transcriptMap.test.d.ts +1 -0
  42. package/dist/MsaViewPanel/transcriptMap.test.js +127 -0
  43. package/dist/index.d.ts +11 -8
  44. package/dist/jbrowse-plugin-msaview.umd.production.min.js +56 -62
  45. package/dist/jbrowse-plugin-msaview.umd.production.min.js.map +4 -4
  46. package/dist/utils/browserAlign.d.ts +5 -3
  47. package/dist/utils/browserAlign.js +29 -23
  48. package/dist/utils/browserAlign.test.js +14 -1
  49. package/dist/utils/ebiBlast.d.ts +0 -8
  50. package/dist/utils/ebiBlast.js +10 -21
  51. package/dist/utils/ebiJobDispatcher.d.ts +9 -9
  52. package/dist/utils/ebiJobDispatcher.js +17 -3
  53. package/dist/utils/eutils.d.ts +0 -2
  54. package/dist/utils/eutils.js +11 -3
  55. package/dist/utils/eutils.test.js +22 -0
  56. package/dist/utils/msa.js +6 -14
  57. package/dist/utils/msaRows.d.ts +0 -8
  58. package/dist/utils/msaRows.js +1 -1
  59. package/dist/utils/ncbiOrthologs.d.ts +7 -5
  60. package/dist/utils/ncbiOrthologs.js +20 -14
  61. package/dist/utils/ncbiOrthologs.test.js +13 -0
  62. package/dist/utils/ncbiTaxonomy.d.ts +2 -2
  63. package/dist/utils/ncbiTaxonomy.js +5 -5
  64. package/dist/utils/pantherOrthologs.d.ts +2 -3
  65. package/dist/utils/pantherOrthologs.js +18 -12
  66. package/dist/utils/phmmer.js +7 -14
  67. package/dist/utils/searchCache.d.ts +18 -0
  68. package/dist/utils/searchCache.js +33 -0
  69. package/dist/utils/searchCache.test.d.ts +1 -0
  70. package/dist/utils/searchCache.test.js +80 -0
  71. package/dist/utils/taxonomyNames.d.ts +1 -1
  72. package/dist/utils/taxonomyNames.js +7 -2
  73. package/dist/utils/taxonomyNamesAbort.test.d.ts +1 -0
  74. package/dist/utils/taxonomyNamesAbort.test.js +36 -0
  75. package/dist/utils/unirefHomologs.d.ts +1 -6
  76. package/dist/utils/unirefHomologs.js +2 -2
  77. package/dist/utils/useFetch.d.ts +1 -1
  78. package/dist/utils/useFetch.js +5 -5
  79. package/dist/utils/useFetchAbort.test.d.ts +1 -0
  80. package/dist/utils/useFetchAbort.test.js +29 -0
  81. package/dist/version.d.ts +1 -1
  82. package/dist/version.js +1 -1
  83. package/package.json +18 -18
  84. package/src/AddHighlightModel/MsaToGenomeHighlight.tsx +10 -23
  85. package/src/AddHighlightModel/connectedHighlights.test.ts +46 -0
  86. package/src/AddHighlightModel/connectedHighlights.ts +35 -0
  87. package/src/AddHighlightModel/index.tsx +0 -1
  88. package/src/LaunchMsaView/cleanProteinSequence.test.ts +37 -2
  89. package/src/LaunchMsaView/components/BlastQuery/consts.ts +6 -4
  90. package/src/LaunchMsaView/components/BlastQuery/searchChoiceStorage.ts +2 -2
  91. package/src/LaunchMsaView/components/OrthologQuery/OrthologSourceSelect.tsx +1 -1
  92. package/src/LaunchMsaView/components/OrthologQuery/QuerySpeciesSelect.tsx +5 -5
  93. package/src/LaunchMsaView/components/useFeatureSequence.ts +3 -6
  94. package/src/LaunchMsaView/launchTarget.test.ts +1 -1
  95. package/src/LaunchMsaView/launchTarget.ts +2 -3
  96. package/src/LaunchMsaView/util.ts +1 -1
  97. package/src/MsaViewPanel/afterCreateAutoruns.ts +90 -87
  98. package/src/MsaViewPanel/components/MsaViewPanel.tsx +1 -1
  99. package/src/MsaViewPanel/doLaunchBlast.test.ts +71 -0
  100. package/src/MsaViewPanel/doLaunchBlast.ts +71 -20
  101. package/src/MsaViewPanel/doLaunchOrthologs.ts +28 -11
  102. package/src/MsaViewPanel/launchAutoruns.test.ts +0 -1
  103. package/src/MsaViewPanel/model.test.ts +3 -4
  104. package/src/MsaViewPanel/model.ts +40 -10
  105. package/src/MsaViewPanel/msaDataStore.test.ts +13 -2
  106. package/src/MsaViewPanel/msaDataStore.ts +11 -25
  107. package/src/MsaViewPanel/observeProteinHighlights.test.ts +1 -0
  108. package/src/MsaViewPanel/processInit.test.ts +1 -8
  109. package/src/MsaViewPanel/regionSnapshot.test.ts +0 -1
  110. package/src/MsaViewPanel/resolveConnectedTranscript.test.ts +2 -3
  111. package/src/MsaViewPanel/resolveConnectedTranscript.ts +7 -17
  112. package/src/MsaViewPanel/storedData.test.ts +273 -158
  113. package/src/MsaViewPanel/transcriptMap.test.ts +160 -0
  114. package/src/MsaViewPanel/transcriptMap.ts +144 -0
  115. package/src/utils/browserAlign.test.ts +17 -0
  116. package/src/utils/browserAlign.ts +39 -25
  117. package/src/utils/ebiBlast.ts +12 -35
  118. package/src/utils/ebiJobDispatcher.ts +26 -7
  119. package/src/utils/eutils.test.ts +25 -0
  120. package/src/utils/eutils.ts +10 -3
  121. package/src/utils/msa.ts +6 -16
  122. package/src/utils/msaRows.ts +1 -1
  123. package/src/utils/ncbiOrthologs.test.ts +16 -0
  124. package/src/utils/ncbiOrthologs.ts +37 -15
  125. package/src/utils/ncbiTaxonomy.ts +8 -2
  126. package/src/utils/pantherOrthologs.ts +28 -12
  127. package/src/utils/phmmer.ts +7 -16
  128. package/src/utils/searchCache.test.ts +98 -0
  129. package/src/utils/searchCache.ts +75 -0
  130. package/src/utils/taxonomyNames.ts +7 -0
  131. package/src/utils/taxonomyNamesAbort.test.ts +46 -0
  132. package/src/utils/unirefHomologs.ts +2 -2
  133. package/src/utils/useFetch.ts +6 -6
  134. package/src/utils/useFetchAbort.test.tsx +33 -0
  135. package/src/version.ts +1 -1
  136. package/dist/LaunchMsaView/components/calculateProteinSequence.d.ts +0 -27
  137. package/dist/LaunchMsaView/components/calculateProteinSequence.js +0 -71
  138. package/dist/LaunchMsaView/components/types.d.ts +0 -9
  139. package/src/LaunchMsaView/components/calculateProteinSequence.ts +0 -113
  140. package/src/LaunchMsaView/components/types.ts +0 -12
  141. /package/dist/{LaunchMsaView/components/types.js → AddHighlightModel/connectedHighlights.test.d.ts} +0 -0
@@ -1,41 +1,25 @@
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/model';
4
+ import { connectedHighlights } from './connectedHighlights';
5
5
  import { hasHoverPosition, useStyles } from './util';
6
6
  const MsaToGenomeHighlight = observer(function MsaToGenomeHighlight2({ model, }) {
7
7
  const { views, hovered } = getSession(model);
8
- const msaView = views
9
- .filter(isMsaView)
10
- .find(v => v.connectedViewId === model.id);
11
- // The persistent click selection always shows. The hover codon is suppressed
12
- // while hovering the LGV — GenomeMouseoverHighlight handles the single-bp
13
- // display in that case, so we don't stack a wider codon band on top of it.
14
- const highlights = [
15
- ...(msaView?.connectedClickHighlights ?? []),
16
- ...(hasHoverPosition(hovered)
17
- ? []
18
- : (msaView?.connectedHoverHighlights ?? [])),
19
- ];
8
+ const highlights = connectedHighlights(views, model.id, hasHoverPosition(hovered));
20
9
  return highlights.length ? (React.createElement(MsaToGenomeHighlightRenderer, { model: model, highlights: highlights })) : null;
21
10
  });
22
- // Inner component: handles the scroll-dependent rendering
23
11
  const MsaToGenomeHighlightRenderer = observer(function ({ model, highlights, }) {
24
12
  const { classes } = useStyles();
25
13
  const { offsetPx } = model;
26
- return (React.createElement(React.Fragment, null, highlights.map((r, idx) => {
27
- // Use the highlight's own refName, which is already in the connected
28
- // view's coordinate space (it comes from the connectedFeature the
29
- // launcher set on this LGV). Do NOT canonicalize: bpToPx matches
30
- // displayed regions by exact refName with no alias resolution, so
31
- // rewriting e.g. "chr17" to the assembly-canonical "17" misses a view
32
- // whose regions are "chr17". (GenomeMouseoverHighlight does the same.)
14
+ return (React.createElement(React.Fragment, null, highlights.map(r => {
15
+ // bpToPx matches refNames exactly, so canonicalizing "chr17" to "17"
16
+ // would miss a view whose regions say "chr17"
33
17
  const s = model.bpToPx({ refName: r.refName, coord: r.start });
34
18
  const e = model.bpToPx({ refName: r.refName, coord: r.end });
35
19
  if (s && e) {
36
20
  const width = Math.max(Math.abs(e.offsetPx - s.offsetPx), 4);
37
21
  const left = Math.min(s.offsetPx, e.offsetPx) - offsetPx;
38
- return (React.createElement("div", { key: `${r.refName}-${r.start}-${r.end}-${idx}`, className: classes.highlight, style: { left, width } }));
22
+ return (React.createElement("div", { key: `${r.refName}-${r.start}-${r.end}`, className: classes.highlight, style: { left, width } }));
39
23
  }
40
24
  return null;
41
25
  })));
@@ -0,0 +1,9 @@
1
+ interface Region {
2
+ refName: string;
3
+ start: number;
4
+ end: number;
5
+ }
6
+ export declare function connectedHighlights(views: readonly {
7
+ type: string;
8
+ }[], genomeViewId: string, genomeHovered: boolean): Region[];
9
+ export {};
@@ -0,0 +1,15 @@
1
+ export function connectedHighlights(views, genomeViewId, genomeHovered) {
2
+ const regions = views
3
+ .filter(isLinkedMsaView)
4
+ .filter(v => v.connectedViewId === genomeViewId)
5
+ .flatMap(v => [
6
+ ...v.connectedClickHighlights,
7
+ ...(genomeHovered ? [] : v.connectedHoverHighlights),
8
+ ]);
9
+ return [
10
+ ...new Map(regions.map(r => [`${r.refName}:${r.start}-${r.end}`, r])).values(),
11
+ ];
12
+ }
13
+ function isLinkedMsaView(view) {
14
+ return view.type === 'MsaView';
15
+ }
@@ -0,0 +1,36 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { connectedHighlights } from './connectedHighlights';
3
+ const region = (start) => ({ refName: 'chr17', start, end: start + 3 });
4
+ function msaView(id, click, hover) {
5
+ return {
6
+ type: 'MsaView',
7
+ connectedViewId: id,
8
+ connectedClickHighlights: [region(click)],
9
+ connectedHoverHighlights: [region(hover)],
10
+ };
11
+ }
12
+ describe('connectedHighlights', () => {
13
+ const views = [
14
+ { type: 'LinearGenomeView' },
15
+ msaView('lgv1', 100, 200),
16
+ msaView('lgv2', 300, 400),
17
+ msaView('lgv1', 500, 600),
18
+ ];
19
+ it('collects every MSA view linked to the genome view', () => {
20
+ expect(connectedHighlights(views, 'lgv1', false).map(r => r.start)).toEqual([100, 200, 500, 600]);
21
+ });
22
+ it('drops hover codons while the genome view is hovered', () => {
23
+ expect(connectedHighlights(views, 'lgv1', true).map(r => r.start)).toEqual([
24
+ 100, 500,
25
+ ]);
26
+ });
27
+ it('draws a codon two views both highlight once', () => {
28
+ const both = [msaView('lgv1', 100, 200), msaView('lgv1', 100, 200)];
29
+ expect(connectedHighlights(both, 'lgv1', false).map(r => r.start)).toEqual([
30
+ 100, 200,
31
+ ]);
32
+ });
33
+ it('returns nothing for an unlinked genome view', () => {
34
+ expect(connectedHighlights(views, 'lgv3', false)).toEqual([]);
35
+ });
36
+ });
@@ -6,7 +6,6 @@ export default function AddHighlightComponentsModelF(pluginManager) {
6
6
  pluginManager.addToExtensionPoint(
7
7
  // @ts-expect-error v4 hosts have no contributeToExtensionPoint
8
8
  'LinearGenomeView-TracksContainerComponent', (rest, { model }) => {
9
- // Quick check: don't add any components if no MSA view exists
10
9
  const { views } = getSession(model);
11
10
  const hasMsaView = views.some(v => isMsaView(v) && v.connectedViewId === model.id);
12
11
  if (!hasMsaView) {
@@ -3,14 +3,8 @@ import type { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAda
3
3
  export default class BgzipFastaMsaAdapter extends BaseAdapter {
4
4
  configureP: Promise<BaseFeatureDataAdapter> | undefined;
5
5
  refNamesP: Promise<string[]> | undefined;
6
- configurePre(): Promise<BaseFeatureDataAdapter<import("@jbrowse/mobx-state-tree").ModelInstanceTypeProps<Record<string, any>> & {
7
- setSubschema(slotName: string, data: Record<string, unknown>): any;
8
- setSlot(slotName: string, value: unknown): void;
9
- } & import("@jbrowse/mobx-state-tree").IStateTreeNode<import("@jbrowse/core/configuration").AnyConfigurationSchemaType>>>;
10
- configure(): Promise<BaseFeatureDataAdapter<import("@jbrowse/mobx-state-tree").ModelInstanceTypeProps<Record<string, any>> & {
11
- setSubschema(slotName: string, data: Record<string, unknown>): any;
12
- setSlot(slotName: string, value: unknown): void;
13
- } & import("@jbrowse/mobx-state-tree").IStateTreeNode<import("@jbrowse/core/configuration").AnyConfigurationSchemaType>>>;
6
+ configurePre(): Promise<BaseFeatureDataAdapter<import("@jbrowse/core/configuration").AnyConfigurationModel>>;
7
+ configure(): Promise<BaseFeatureDataAdapter<import("@jbrowse/core/configuration").AnyConfigurationModel>>;
14
8
  getMSARefs(): Promise<string[]>;
15
9
  getMsaRegex(): RegExp;
16
10
  refNameToMsaId(refName: string): string;
@@ -1,7 +1,14 @@
1
1
  import type PluginManager from '@jbrowse/core/PluginManager';
2
2
  export default function configSchemaF(pluginManager: PluginManager): import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
3
+ msaRegex: {
4
+ type: "string";
5
+ } & {
6
+ defaultValue: string;
7
+ };
8
+ } | {
3
9
  readonly msaRegex: {
4
- readonly type: "string";
5
- readonly defaultValue: "_";
10
+ type: "string";
11
+ } & {
12
+ defaultValue: string;
6
13
  };
7
- }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<import("@jbrowse/core/configuration").AnyConfigurationSchemaType, undefined>>;
14
+ }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<any, undefined, undefined, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>>>;
@@ -1,8 +1,8 @@
1
1
  import { SimpleFeature } from '@jbrowse/core/util';
2
+ import { translateTranscript } from '@jbrowse/core/util/translateTranscript';
2
3
  import { genomeToTranscriptSeqMapping } from 'g2p_mapper';
3
4
  import { describe, expect, test } from 'vitest';
4
5
  import { transcriptPosToVisibleCol } from '../MsaViewPanel/util';
5
- import { getProteinSequenceFromFeature } from './components/calculateProteinSequence';
6
6
  import { findQueryRow } from './detectQueryRow';
7
7
  import { cleanProteinSequence } from './util';
8
8
  describe('cleanProteinSequence', () => {
@@ -22,7 +22,7 @@ describe('a launched query row read through g2p', () => {
22
22
  function rowResidueUnder(genomePos, json) {
23
23
  const seq = json.seq;
24
24
  const feature = new SimpleFeature(json);
25
- const row = cleanProteinSequence(getProteinSequenceFromFeature({ seq, feature }));
25
+ const row = cleanProteinSequence(translateTranscript({ transcript: feature, seq })?.protein ?? '');
26
26
  const { g2p } = genomeToTranscriptSeqMapping(feature.toJSON());
27
27
  const col = transcriptPosToVisibleCol({
28
28
  querySeqName: 'QUERY',
@@ -52,6 +52,40 @@ describe('a launched query row read through g2p', () => {
52
52
  expect(rowResidueUnder(4, json)).toBe('A');
53
53
  expect(rowResidueUnder(10, json)).toBe('K');
54
54
  });
55
+ test('on the reverse strand, across an intron, after a partial first codon', () => {
56
+ // sense G | ATG GCC <intron> TGG AAA TAA, stored as the reverse complement
57
+ const json = {
58
+ uniqueId: 't1',
59
+ refName: 'chr1',
60
+ start: 0,
61
+ end: 24,
62
+ strand: -1,
63
+ type: 'mRNA',
64
+ seq: 'TTATTTCCACTACTTACGGCCATC',
65
+ subfeatures: [
66
+ {
67
+ uniqueId: 'c1',
68
+ refName: 'chr1',
69
+ type: 'CDS',
70
+ start: 17,
71
+ end: 24,
72
+ phase: 1,
73
+ },
74
+ {
75
+ uniqueId: 'c2',
76
+ refName: 'chr1',
77
+ type: 'CDS',
78
+ start: 0,
79
+ end: 9,
80
+ phase: 0,
81
+ },
82
+ ],
83
+ };
84
+ expect(rowResidueUnder(22, json)).toBe('M');
85
+ expect(rowResidueUnder(18, json)).toBe('A');
86
+ expect(rowResidueUnder(7, json)).toBe('W');
87
+ expect(rowResidueUnder(4, json)).toBe('K');
88
+ });
55
89
  test('after an internal stop', () => {
56
90
  // ATG TGA GCC TGG TAA: a selenocysteine GENCODE does not annotate
57
91
  const json = transcript('ATGTGAGCCTGGTAA', { type: 'CDS' });
@@ -13,8 +13,10 @@ export type EbiMsaAlgorithm = (typeof ebiMsaAlgorithms)[number];
13
13
  * page and the rows merged on the query (utils/browserAlign.ts), with the tree
14
14
  * built by react-msaview's neighbour joining. It is the aligner for a launch
15
15
  * that must not depend on EBI, and for one that wants to be quick -- a
16
- * hundred rows take a second or two against a Job Dispatcher queue that has
17
- * been measured at anything from ten seconds to fifteen minutes.
16
+ * hundred 400-residue rows take under a second, and a hundred 1400-residue
17
+ * rows eight, against a Job Dispatcher queue that has been measured at
18
+ * anything from ten seconds to fifteen minutes. Past the per-sequence limit in
19
+ * browserAlign.ts it refuses and names an EBI aligner instead.
18
20
  */
19
21
  export declare const msaAlgorithms: readonly ["clustalo", "muscle", "kalign", "mafft", "browser"];
20
22
  export type MsaAlgorithm = (typeof msaAlgorithms)[number];
@@ -28,7 +30,6 @@ export declare const msaAlgorithmLabels: Record<MsaAlgorithm, string>;
28
30
  */
29
31
  export declare const blastDatabaseOptions: readonly ["uniprotkb_swissprot", "uniprotkb", "pan_proteomes", "uniprotkb_trembl"];
30
32
  export type BlastDatabase = (typeof blastDatabaseOptions)[number];
31
- export declare const defaultBlastDatabase: BlastDatabase;
32
33
  export declare const searchPrograms: readonly ["blastp", "phmmer"];
33
34
  export type SearchProgram = (typeof searchPrograms)[number];
34
35
  export declare const searchProgramLabels: Record<SearchProgram, string>;
@@ -46,7 +47,6 @@ export declare const searchProgramLabels: Record<SearchProgram, string>;
46
47
  */
47
48
  export declare const phmmerDatabaseOptions: readonly ["swissprot", "uniprotkb", "uniprotrefprot", "rp75", "rp55", "rp35", "rp15"];
48
49
  export type PhmmerDatabase = (typeof phmmerDatabaseOptions)[number];
49
- export declare const defaultPhmmerDatabase: PhmmerDatabase;
50
50
  export declare const defaultMaxHits = 100;
51
51
  export declare function snapBlastHitCount(maxHits: number): number;
52
52
  /**
@@ -17,8 +17,10 @@ export const ebiMsaAlgorithms = [
17
17
  * page and the rows merged on the query (utils/browserAlign.ts), with the tree
18
18
  * built by react-msaview's neighbour joining. It is the aligner for a launch
19
19
  * that must not depend on EBI, and for one that wants to be quick -- a
20
- * hundred rows take a second or two against a Job Dispatcher queue that has
21
- * been measured at anything from ten seconds to fifteen minutes.
20
+ * hundred 400-residue rows take under a second, and a hundred 1400-residue
21
+ * rows eight, against a Job Dispatcher queue that has been measured at
22
+ * anything from ten seconds to fifteen minutes. Past the per-sequence limit in
23
+ * browserAlign.ts it refuses and names an EBI aligner instead.
22
24
  */
23
25
  export const msaAlgorithms = [...ebiMsaAlgorithms, 'browser'];
24
26
  export const msaAlgorithmLabels = {
@@ -43,7 +45,7 @@ export const blastDatabaseOptions = [
43
45
  ];
44
46
  // curated, so it returns roughly one good sequence per species rather than the
45
47
  // many near-identical TrEMBL entries an alignment reads poorly
46
- export const defaultBlastDatabase = 'uniprotkb_swissprot';
48
+ const defaultBlastDatabase = 'uniprotkb_swissprot';
47
49
  export const searchPrograms = ['blastp', 'phmmer'];
48
50
  export const searchProgramLabels = {
49
51
  blastp: 'blastp (sequence search)',
@@ -70,7 +72,7 @@ export const phmmerDatabaseOptions = [
70
72
  'rp35',
71
73
  'rp15',
72
74
  ];
73
- export const defaultPhmmerDatabase = 'swissprot';
75
+ const defaultPhmmerDatabase = 'swissprot';
74
76
  /**
75
77
  * The hit counts EBI's ncbiblast accepts for `alignments` and `scores`. A value
76
78
  * off this list is a 400 at submit time, so a request is rounded up to the next
@@ -1,6 +1,4 @@
1
1
  import type { MsaAlgorithm, SearchChoice } from './consts';
2
- export declare const SEARCH_CHOICE_STORAGE_KEY = "msaView-blastSearch";
3
- export declare const MSA_ALGORITHM_STORAGE_KEY = "msaView-msaAlgorithm";
4
2
  export declare function validSearchChoice(stored: unknown): SearchChoice;
5
3
  export declare function validMsaAlgorithm(stored: unknown): MsaAlgorithm;
6
4
  export declare function useStoredSearchChoice(): readonly [SearchChoice, (choice: SearchChoice) => void];
@@ -8,8 +8,8 @@ import { databaseOptionsFor, defaultSearchFor, msaAlgorithms, searchPrograms, }
8
8
  // comes back is checked against the current options before it is used — an
9
9
  // option this plugin has since dropped would otherwise reach EBI and come back
10
10
  // a 400, minutes after the user pressed Submit.
11
- export const SEARCH_CHOICE_STORAGE_KEY = 'msaView-blastSearch';
12
- export const MSA_ALGORITHM_STORAGE_KEY = 'msaView-msaAlgorithm';
11
+ const SEARCH_CHOICE_STORAGE_KEY = 'msaView-blastSearch';
12
+ const MSA_ALGORITHM_STORAGE_KEY = 'msaView-msaAlgorithm';
13
13
  const defaultSearch = defaultSearchFor('blastp');
14
14
  const defaultMsaAlgorithm = 'clustalo';
15
15
  export function validSearchChoice(stored) {
@@ -1,6 +1,5 @@
1
1
  import React from 'react';
2
2
  import type { OrthologSource } from '../../../MsaViewPanel/model';
3
- export declare const orthologSourceLabels: Record<OrthologSource, string>;
4
3
  export declare function validOrthologSource(stored: unknown): OrthologSource;
5
4
  export declare function useStoredOrthologSource(): readonly ["ncbi" | "panther" | "uniref", (source: OrthologSource) => void];
6
5
  export default function OrthologSourceSelect({ value, onChange, className, }: {
@@ -3,7 +3,7 @@ import { MenuItem } from '@mui/material';
3
3
  import TextField2 from '../../../components/TextField2';
4
4
  import { useLocalStorage } from '../../../utils/useLocalStorage';
5
5
  const ORTHOLOG_SOURCE_STORAGE_KEY = 'msaview-ortholog-source';
6
- export const orthologSourceLabels = {
6
+ const orthologSourceLabels = {
7
7
  ncbi: 'NCBI orthologs',
8
8
  panther: 'PANTHER',
9
9
  uniref: 'UniRef cluster',
@@ -3,12 +3,12 @@ import TextField2 from '../../../components/TextField2';
3
3
  import { resolveAssemblySpecies, resolveTaxId, } from '../../../utils/ncbiTaxonomy';
4
4
  import { fetchTaxonomyInfo } from '../../../utils/taxonomyNames';
5
5
  import { useDebounced, useFetch } from '../../../utils/useFetch';
6
- async function describeTaxon(query) {
7
- const taxId = await resolveTaxId(query);
6
+ async function describeTaxon(query, signal) {
7
+ const taxId = await resolveTaxId(query, signal);
8
8
  if (!taxId) {
9
9
  throw new Error(`No NCBI taxon matches "${query}"`);
10
10
  }
11
- const info = (await fetchTaxonomyInfo([taxId])).get(taxId);
11
+ const info = (await fetchTaxonomyInfo([taxId], signal)).get(taxId);
12
12
  const label = [info?.sciname, info?.commonName && `(${info.commonName})`]
13
13
  .filter(Boolean)
14
14
  .join(' ');
@@ -40,14 +40,14 @@ export default function QuerySpeciesSelect({ value, assemblyName, onChange, clas
40
40
  // reported the throttle as "blocked by CORS policy" in the helper text.
41
41
  const { data: fromAssembly } = useFetch(assemblyName && typed === undefined
42
42
  ? [assemblyName, 'assembly-species']
43
- : null, () => resolveAssemblySpecies(assemblyName), {
43
+ : null, signal => resolveAssemblySpecies(assemblyName, signal), {
44
44
  onSuccess: found => {
45
45
  if (found) {
46
46
  onChange(found.taxId);
47
47
  }
48
48
  },
49
49
  });
50
- const { data: fromText, error } = useFetch(debounced?.trim() ? [debounced.trim(), 'taxon'] : null, () => describeTaxon(debounced), {
50
+ const { data: fromText, error } = useFetch(debounced?.trim() ? [debounced.trim(), 'taxon'] : null, signal => describeTaxon(debounced, signal), {
51
51
  onSuccess: ({ taxId }) => {
52
52
  onChange(taxId);
53
53
  },
@@ -1,6 +1,6 @@
1
1
  import { getSession } from '@jbrowse/core/util';
2
+ import { translateTranscript } from '@jbrowse/core/util/translateTranscript';
2
3
  import { useFetch } from '../../utils/useFetch';
3
- import { getProteinSequenceFromFeature } from './calculateProteinSequence';
4
4
  import { fetchSeq } from './fetchSeq';
5
5
  export function useFeatureSequence({ view, feature, }) {
6
6
  const assemblyName = view?.assemblyNames?.[0];
@@ -18,11 +18,8 @@ export function useFeatureSequence({ view, feature, }) {
18
18
  });
19
19
  return {
20
20
  proteinSequence: sequence && feature
21
- ? getProteinSequenceFromFeature({
22
- seq: sequence.seq,
23
- feature,
24
- assemblyGeneticCodeId: sequence.assemblyGeneticCodeId,
25
- })
21
+ ? (translateTranscript({ transcript: feature, ...sequence })?.protein ??
22
+ '')
26
23
  : '',
27
24
  sequence,
28
25
  error,
@@ -52,7 +52,7 @@ describe('launchTarget', () => {
52
52
  test('offers nothing when nothing was clicked', () => {
53
53
  expect(launchTarget({ contextMenuItems: () => [] })).toBeUndefined();
54
54
  });
55
- // v3.7.0 hosts have contextMenuFeature and nothing else; dropping this
55
+ // v4.3.0 and earlier have contextMenuFeature and nothing else; dropping this
56
56
  // fallback once took "Launch MSA view" off every host in the wild.
57
57
  test('falls back to a synchronous contextMenuFeature', () => {
58
58
  const target = launchTarget(legacyHost(feature('mRNA')));
@@ -7,7 +7,6 @@ export declare function getTranscriptLength(feature: Feature): {
7
7
  mod: number;
8
8
  };
9
9
  export declare function getId(val?: Feature): string;
10
- export declare function getMatchableIds(val?: Feature): string[];
11
10
  export declare function featureMatchesId(feature: Feature, id: string): boolean;
12
11
  export declare function getTranscriptDisplayName(val?: Feature): string;
13
12
  export declare function getGeneDisplayName(val?: Feature): string;
@@ -39,7 +39,7 @@ export function getTranscriptLength(feature) {
39
39
  export function getId(val) {
40
40
  return val?.id() ?? '';
41
41
  }
42
- export function getMatchableIds(val) {
42
+ function getMatchableIds(val) {
43
43
  return val
44
44
  ? uniqueDefined([
45
45
  val.id(),
@@ -1,20 +1,11 @@
1
1
  import type { JBrowsePluginMsaViewModel } from './model';
2
2
  export declare function loadStoredData(self: JBrowsePluginMsaViewModel): void;
3
3
  /**
4
- * Keep IndexedDB holding what the view holds. The first run writes a new row and
5
- * records its id in the session snapshot; later runs update that row, because
6
- * the alignment keeps changing after it arrives — react-msaview's
7
- * "calculate neighbor-joining tree" replaces `data.tree` — and a session
8
- * reopened against a stale row restores the wrong picture.
9
- *
10
- * `lastStoredData` is what makes that safe to run on every data change: it is
11
- * the only thing separating "this is new" from "this is what we just wrote", and
12
- * it is recorded whether or not the write succeeded, so a browser refusing
13
- * IndexedDB (private mode) fails once rather than in a loop.
14
- *
15
- * A view whose data comes from a filehandle -- or from the indexed block its
16
- * kept `init` names -- stores nothing at all: the file is the source of truth
17
- * and it is refetched at startup.
4
+ * Keep IndexedDB holding `unsavedDocuments`. A view writes in place only to a
5
+ * row it created (`ownsDataStoreRow`), and never deletes one, since other
6
+ * views may name it: an emptied set drops the id and cleanupOldData ages the
7
+ * row out. `lastStoredData` is recorded even when a write fails, so a browser
8
+ * refusing IndexedDB fails once rather than in a loop.
18
9
  */
19
10
  export declare function storeDataToIndexedDB(self: JBrowsePluginMsaViewModel): void;
20
11
  /**