jbrowse-plugin-msaview 2.6.6 → 2.6.8

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 (49) hide show
  1. package/dist/BgzipFastaMsaAdapter/BgzipFastaMsaAdapter.js +1 -1
  2. package/dist/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.js +0 -3
  3. package/dist/LaunchMsaView/components/ManualMSALoader/launchView.d.ts +2 -3
  4. package/dist/LaunchMsaView/components/ManualMSALoader/launchView.js +3 -2
  5. package/dist/LaunchMsaView/components/NCBIBlastQuery/CachedBlastResults.js +10 -1
  6. package/dist/LaunchMsaView/components/NCBIBlastQuery/blastLaunchView.d.ts +2 -1
  7. package/dist/LaunchMsaView/components/NCBIBlastQuery/blastLaunchView.js +2 -1
  8. package/dist/LaunchMsaView/components/NCBIBlastQuery/useCachedBlastResults.js +2 -2
  9. package/dist/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.js +1 -2
  10. package/dist/LaunchMsaView/components/PreLoadedMSA/preCalculatedLaunchView.d.ts +2 -3
  11. package/dist/LaunchMsaView/components/PreLoadedMSA/preCalculatedLaunchView.js +3 -2
  12. package/dist/LaunchMsaView/components/calculateProteinSequence.d.ts +1 -2
  13. package/dist/LaunchMsaView/components/calculateProteinSequence.js +4 -2
  14. package/dist/LaunchMsaView/components/useTranscriptSelection.js +14 -11
  15. package/dist/MsaViewPanel/msaDataStore.js +7 -2
  16. package/dist/MsaViewPanel/util.d.ts +0 -11
  17. package/dist/MsaViewPanel/util.js +0 -7
  18. package/dist/jbrowse-plugin-msaview.umd.production.min.js +25 -25
  19. package/dist/jbrowse-plugin-msaview.umd.production.min.js.map +3 -3
  20. package/dist/utils/blastCache.js +13 -5
  21. package/dist/utils/domainCache.js +7 -2
  22. package/dist/utils/fetch.d.ts +0 -2
  23. package/dist/utils/fetch.js +0 -21
  24. package/dist/utils/ncbiDomains.js +10 -3
  25. package/dist/utils/taxonomyNames.js +7 -2
  26. package/dist/version.d.ts +1 -1
  27. package/dist/version.js +1 -1
  28. package/package.json +1 -2
  29. package/src/BgzipFastaMsaAdapter/BgzipFastaMsaAdapter.ts +1 -1
  30. package/src/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.tsx +0 -3
  31. package/src/LaunchMsaView/components/ManualMSALoader/launchView.ts +4 -8
  32. package/src/LaunchMsaView/components/NCBIBlastQuery/CachedBlastResults.tsx +17 -1
  33. package/src/LaunchMsaView/components/NCBIBlastQuery/blastLaunchView.ts +3 -0
  34. package/src/LaunchMsaView/components/NCBIBlastQuery/useCachedBlastResults.ts +2 -1
  35. package/src/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.tsx +1 -2
  36. package/src/LaunchMsaView/components/PreLoadedMSA/preCalculatedLaunchView.ts +4 -4
  37. package/src/LaunchMsaView/components/calculateProteinSequence.ts +4 -3
  38. package/src/LaunchMsaView/components/useTranscriptSelection.ts +16 -16
  39. package/src/MsaViewPanel/msaDataStore.ts +8 -2
  40. package/src/MsaViewPanel/util.ts +0 -24
  41. package/src/utils/blastCache.ts +14 -3
  42. package/src/utils/domainCache.ts +8 -2
  43. package/src/utils/fetch.ts +0 -28
  44. package/src/utils/ncbiDomains.ts +10 -3
  45. package/src/utils/taxonomyNames.ts +8 -2
  46. package/src/version.ts +1 -1
  47. package/dist/LaunchMsaView/components/ManualMSALoader/fetchGeneList.d.ts +0 -1
  48. package/dist/LaunchMsaView/components/ManualMSALoader/fetchGeneList.js +0 -11
  49. package/src/LaunchMsaView/components/ManualMSALoader/fetchGeneList.ts +0 -13
@@ -44,7 +44,7 @@ export default class BgzipFastaMsaAdapter extends BaseAdapter {
44
44
  }
45
45
  async getMSA(id) {
46
46
  const adapter = await this.configure();
47
- const refNames = await adapter.getRefNames();
47
+ const refNames = await this.getMSARefs();
48
48
  const rows = refNames.filter(refName => this.refNameToMsaId(refName) === id);
49
49
  return firstValueFrom(adapter
50
50
  .getFeaturesInMultipleRegions(rows.map(refName => ({
@@ -1,6 +1,5 @@
1
1
  import React, { useState } from 'react';
2
2
  import { FileSelector } from '@jbrowse/core/ui';
3
- import { getSession } from '@jbrowse/core/util';
4
3
  import { Alert, FormControl, FormControlLabel, Radio, RadioGroup, } from '@mui/material';
5
4
  import { observer } from 'mobx-react';
6
5
  import { makeStyles } from 'tss-react/mui';
@@ -32,7 +31,6 @@ const useStyles = makeStyles()({
32
31
  },
33
32
  });
34
33
  const ManualMSALoader = observer(function PreLoadedMSA2({ model, feature, handleClose, }) {
35
- const session = getSession(model);
36
34
  const view = getLinearGenomeView(model);
37
35
  const { classes } = useStyles();
38
36
  const [launchViewError, setLaunchViewError] = useState();
@@ -74,7 +72,6 @@ const ManualMSALoader = observer(function PreLoadedMSA2({ model, feature, handle
74
72
  if (selectedTranscript) {
75
73
  setLaunchViewError(undefined);
76
74
  launchView({
77
- session,
78
75
  newViewTitle: getGeneDisplayName(selectedTranscript),
79
76
  view,
80
77
  feature: selectedTranscript,
@@ -1,7 +1,6 @@
1
- import type { AbstractSessionModel, Feature, FileLocation } from '@jbrowse/core/util';
1
+ import type { Feature, FileLocation } from '@jbrowse/core/util';
2
2
  import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view';
3
- export declare function launchView({ session, newViewTitle, view, feature, msaFilehandle, treeFilehandle, querySeqName, data, }: {
4
- session: AbstractSessionModel;
3
+ export declare function launchView({ newViewTitle, view, feature, msaFilehandle, treeFilehandle, querySeqName, data, }: {
5
4
  newViewTitle: string;
6
5
  view: LinearGenomeViewModel;
7
6
  feature: Feature;
@@ -1,5 +1,6 @@
1
- export function launchView({ session, newViewTitle, view, feature, msaFilehandle, treeFilehandle, querySeqName, data, }) {
2
- session.addView('MsaView', {
1
+ import { getSession } from '@jbrowse/core/util';
2
+ export function launchView({ newViewTitle, view, feature, msaFilehandle, treeFilehandle, querySeqName, data, }) {
3
+ getSession(view).addView('MsaView', {
3
4
  type: 'MsaView',
4
5
  displayName: newViewTitle,
5
6
  connectedViewId: view.id,
@@ -6,7 +6,7 @@ import { observer } from 'mobx-react';
6
6
  import { makeStyles } from 'tss-react/mui';
7
7
  import { blastLaunchViewFromCache } from './blastLaunchView';
8
8
  import { useCachedBlastResults } from './useCachedBlastResults';
9
- import { getGeneIdentifiers, getLinearGenomeView } from '../../util';
9
+ import { featureMatchesId, getGeneIdentifiers, getLinearGenomeView, getSortedTranscriptFeatures, } from '../../util';
10
10
  const useStyles = makeStyles()({
11
11
  header: {
12
12
  display: 'flex',
@@ -37,10 +37,19 @@ const CachedBlastResults = observer(function ({ model, handleClose, feature, })
37
37
  const geneIds = useMemo(() => getGeneIdentifiers(feature), [feature]);
38
38
  const { results, error, isLoading, handleDelete, handleClearAll } = useCachedBlastResults(geneIds);
39
39
  const handleUseCached = (cached) => {
40
+ // reconnect the cached MSA to the genome: the cached query row is named
41
+ // 'QUERY' (react-msaview's default querySeqName) and corresponds to the
42
+ // transcript stored as transcriptId. Resolving it here restores the
43
+ // MSA<->genome navigation and hover-sync a fresh BLAST gets.
44
+ const { transcriptId } = cached;
45
+ const transcript = transcriptId
46
+ ? getSortedTranscriptFeatures(feature).find(t => featureMatchesId(t, transcriptId))
47
+ : undefined;
40
48
  blastLaunchViewFromCache({
41
49
  view,
42
50
  cached,
43
51
  newViewTitle: `BLAST - ${getResultDisplayName(cached)}`,
52
+ connectedFeature: transcript?.toJSON(),
44
53
  });
45
54
  handleClose();
46
55
  };
@@ -8,8 +8,9 @@ export declare function blastLaunchView({ newViewTitle, view, feature, blastPara
8
8
  feature: Feature;
9
9
  blastParams: BlastParams;
10
10
  }): void;
11
- export declare function blastLaunchViewFromCache({ newViewTitle, view, cached, }: {
11
+ export declare function blastLaunchViewFromCache({ newViewTitle, view, cached, connectedFeature, }: {
12
12
  newViewTitle: string;
13
13
  view: LinearGenomeViewModel;
14
14
  cached: CachedBlastResult;
15
+ connectedFeature?: ReturnType<Feature['toJSON']>;
15
16
  }): void;
@@ -11,11 +11,12 @@ export function blastLaunchView({ newViewTitle, view, feature, blastParams, }) {
11
11
  blastParams,
12
12
  });
13
13
  }
14
- export function blastLaunchViewFromCache({ newViewTitle, view, cached, }) {
14
+ export function blastLaunchViewFromCache({ newViewTitle, view, cached, connectedFeature, }) {
15
15
  getSession(view).addView('MsaView', {
16
16
  type: 'MsaView',
17
17
  displayName: newViewTitle,
18
18
  connectedViewId: view.id,
19
+ connectedFeature,
19
20
  drawNodeBubbles: true,
20
21
  colWidth: 10,
21
22
  rowHeight: 12,
@@ -2,7 +2,7 @@ import useSWR from 'swr';
2
2
  import { clearAllCachedResults, deleteCachedResult, getAllCachedResults, } from '../../../utils/blastCache';
3
3
  import { staticSwrConfig } from '../../../utils/swrConfig';
4
4
  export function useCachedBlastResults(geneIds) {
5
- const { data: results, error, mutate, } = useSWR(`cached-blast-${geneIds.join(',')}`, async () => {
5
+ const { data: results, error, isLoading, mutate, } = useSWR(`cached-blast-${geneIds.join(',')}`, async () => {
6
6
  const cached = await getAllCachedResults();
7
7
  return cached.filter(r => r.geneId && geneIds.includes(r.geneId));
8
8
  }, staticSwrConfig);
@@ -17,7 +17,7 @@ export function useCachedBlastResults(geneIds) {
17
17
  return {
18
18
  results: results ?? [],
19
19
  error,
20
- isLoading: !results && !error,
20
+ isLoading,
21
21
  handleDelete,
22
22
  handleClearAll,
23
23
  };
@@ -38,7 +38,7 @@ const PreLoadedMSA = observer(function ({ model, feature, handleClose, }) {
38
38
  });
39
39
  const { selectedId, selectedTranscript } = transcriptSelection;
40
40
  const { data: msaData, isLoading: msaDataLoading, error: msaDataFetchError, } = useSWR(selectedId && selectedDataset && msaList
41
- ? `${selectedDataset.datasetId}-${selectedId}-${msaList.length}-msa`
41
+ ? `${selectedDataset.datasetId}-${selectedId}-msa`
42
42
  : null, () => fetchMSA({
43
43
  msaId: selectedId,
44
44
  config: selectedDataset.adapter,
@@ -64,7 +64,6 @@ const PreLoadedMSA = observer(function ({ model, feature, handleClose, }) {
64
64
  if (selectedTranscript && msaData) {
65
65
  const querySeqName = `${selectedId}_${assemblyNames[0]}`;
66
66
  preCalculatedLaunchView({
67
- session,
68
67
  newViewTitle: getGeneDisplayName(selectedTranscript),
69
68
  view,
70
69
  querySeqName,
@@ -1,10 +1,9 @@
1
- import type { AbstractSessionModel, Feature } from '@jbrowse/core/util';
1
+ import type { Feature } from '@jbrowse/core/util';
2
2
  import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view';
3
- export declare function preCalculatedLaunchView({ session, newViewTitle, view, feature, data, querySeqName, }: {
3
+ export declare function preCalculatedLaunchView({ newViewTitle, view, feature, data, querySeqName, }: {
4
4
  data: {
5
5
  msa: string;
6
6
  };
7
- session: AbstractSessionModel;
8
7
  newViewTitle: string;
9
8
  view: LinearGenomeViewModel;
10
9
  feature: Feature;
@@ -1,5 +1,6 @@
1
- export function preCalculatedLaunchView({ session, newViewTitle, view, feature, data, querySeqName, }) {
2
- session.addView('MsaView', {
1
+ import { getSession } from '@jbrowse/core/util';
2
+ export function preCalculatedLaunchView({ newViewTitle, view, feature, data, querySeqName, }) {
3
+ getSession(view).addView('MsaView', {
3
4
  type: 'MsaView',
4
5
  displayName: newViewTitle,
5
6
  treeAreaWidth: 200,
@@ -1,10 +1,9 @@
1
1
  import type { Feat } from './types';
2
2
  import type { Feature } from '@jbrowse/core/util';
3
3
  export declare function stitch(subfeats: Feat[], sequence: string): string;
4
- export declare function calculateProteinSequence({ cds, sequence, codonTable, }: {
4
+ export declare function calculateProteinSequence({ cds, sequence, }: {
5
5
  cds: Feat[];
6
6
  sequence: string;
7
- codonTable: Record<string, string>;
8
7
  }): string;
9
8
  export declare function revlist(list: Feat[], seqlen: number): {
10
9
  start: number;
@@ -1,8 +1,11 @@
1
1
  import { dedupe, defaultCodonTable, generateCodonTable, revcom, } from '@jbrowse/core/util';
2
+ // pure constant: the standard codon table never varies, so build it once rather
3
+ // than on every translation (which runs on every panel re-render)
4
+ const codonTable = generateCodonTable(defaultCodonTable);
2
5
  export function stitch(subfeats, sequence) {
3
6
  return subfeats.map(sub => sequence.slice(sub.start, sub.end)).join('');
4
7
  }
5
- export function calculateProteinSequence({ cds, sequence, codonTable, }) {
8
+ export function calculateProteinSequence({ cds, sequence, }) {
6
9
  const str = stitch(cds, sequence);
7
10
  let protein = '';
8
11
  for (let i = 0; i < str.length; i += 3) {
@@ -33,6 +36,5 @@ export function getProteinSequenceFromFeature({ feature, seq, }) {
33
36
  return calculateProteinSequence({
34
37
  cds: strand === -1 ? revlist(cds, seq.length) : cds,
35
38
  sequence: strand === -1 ? revcom(seq) : seq,
36
- codonTable: generateCodonTable(defaultCodonTable),
37
39
  });
38
40
  }
@@ -1,22 +1,25 @@
1
1
  import { useMemo, useState } from 'react';
2
2
  import { featureMatchesId, getId, getSortedTranscriptFeatures } from '../util';
3
3
  import { useFeatureSequence } from './useFeatureSequence';
4
- function findValidSelection(currentId, options, validIds) {
5
- if (validIds && validIds.length > 0) {
6
- const currentFeature = options.find(opt => getId(opt) === currentId);
7
- const currentIsValid = currentFeature &&
8
- validIds.some(id => featureMatchesId(currentFeature, id));
9
- if (currentFeature && !currentIsValid) {
10
- const validOption = options.find(opt => validIds.some(id => featureMatchesId(opt, id)));
11
- return validOption ? getId(validOption) : undefined;
12
- }
4
+ // Keep the current selection if it's valid for the given validIds, otherwise
5
+ // fall back to the first valid option (or the current id if none qualify). With
6
+ // no validIds constraint the current selection always stands.
7
+ function pickSelectedId(currentId, options, validIds) {
8
+ if (!validIds?.length) {
9
+ return currentId;
13
10
  }
14
- return undefined;
11
+ const isValid = (opt) => validIds.some(id => featureMatchesId(opt, id));
12
+ const current = options.find(opt => getId(opt) === currentId);
13
+ if (current && isValid(current)) {
14
+ return currentId;
15
+ }
16
+ const firstValid = options.find(isValid);
17
+ return firstValid ? getId(firstValid) : currentId;
15
18
  }
16
19
  export function useTranscriptSelection({ feature, view, validIds, }) {
17
20
  const options = useMemo(() => getSortedTranscriptFeatures(feature), [feature]);
18
21
  const [selectedId, setSelectedId] = useState(() => getId(options[0]));
19
- const validatedSelectedId = findValidSelection(selectedId, options, validIds) ?? selectedId;
22
+ const validatedSelectedId = pickSelectedId(selectedId, options, validIds);
20
23
  const selectedTranscript = options.find(val => getId(val) === validatedSelectedId);
21
24
  const { proteinSequence, error } = useFeatureSequence({
22
25
  view,
@@ -2,15 +2,20 @@ import { openDB } from 'idb';
2
2
  const DB_NAME = 'jbrowse-msaview-data';
3
3
  const DB_VERSION = 1;
4
4
  const STORE_NAME = 'msa-data';
5
- async function getDB() {
6
- return openDB(DB_NAME, DB_VERSION, {
5
+ let dbPromise;
6
+ function getDB() {
7
+ dbPromise ??= openDB(DB_NAME, DB_VERSION, {
7
8
  upgrade(db) {
8
9
  if (!db.objectStoreNames.contains(STORE_NAME)) {
9
10
  const store = db.createObjectStore(STORE_NAME, { keyPath: 'id' });
10
11
  store.createIndex('timestamp', 'timestamp', { unique: false });
11
12
  }
12
13
  },
14
+ }).catch((e) => {
15
+ dbPromise = undefined;
16
+ throw e;
13
17
  });
18
+ return dbPromise;
14
19
  }
15
20
  export function generateDataStoreId() {
16
21
  return `msa-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
@@ -4,16 +4,6 @@ export declare function hasHoverPosition(hovered: unknown): hovered is {
4
4
  refName: string;
5
5
  };
6
6
  };
7
- interface AssemblyManagerLike {
8
- get: (name: string) => {
9
- getCanonicalRefName: (r: string) => string | undefined;
10
- } | undefined;
11
- }
12
- export declare function getCanonicalRefName({ assemblyManager, assemblyNames, refName, }: {
13
- assemblyManager: AssemblyManagerLike;
14
- assemblyNames: string[] | undefined;
15
- refName: string;
16
- }): string;
17
7
  /**
18
8
  * Extracts UniProt ID from an AlphaFold URL
19
9
  * Examples:
@@ -21,4 +11,3 @@ export declare function getCanonicalRefName({ assemblyManager, assemblyNames, re
21
11
  * - https://alphafold.ebi.ac.uk/files/msa/AF-P12345-F1-msa_v6.a3m -> P12345
22
12
  */
23
13
  export declare function getUniprotIdFromAlphaFoldUrl(url: string): string | undefined;
24
- export {};
@@ -4,13 +4,6 @@ export function hasHoverPosition(hovered) {
4
4
  'hoverPosition' in hovered &&
5
5
  !!hovered.hoverPosition);
6
6
  }
7
- export function getCanonicalRefName({ assemblyManager, assemblyNames, refName, }) {
8
- const assemblyName = assemblyNames?.[0];
9
- if (assemblyName) {
10
- return (assemblyManager.get(assemblyName)?.getCanonicalRefName(refName) ?? refName);
11
- }
12
- return refName;
13
- }
14
7
  /**
15
8
  * Extracts UniProt ID from an AlphaFold URL
16
9
  * Examples: