jbrowse-plugin-msaview 2.4.4 → 2.5.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 (180) hide show
  1. package/dist/AddHighlightModel/GenomeMouseoverHighlight.js +2 -2
  2. package/dist/AddHighlightModel/HighlightComponents.js +0 -1
  3. package/dist/AddHighlightModel/MsaToGenomeHighlight.js +5 -3
  4. package/dist/AddHighlightModel/index.js +2 -2
  5. package/dist/AddHighlightModel/util.d.ts +1 -6
  6. package/dist/AddHighlightModel/util.js +1 -7
  7. package/dist/BgzipFastaMsaAdapter/BgzipFastaMsaAdapter.js +0 -1
  8. package/dist/BgzipFastaMsaAdapter/configSchema.js +0 -1
  9. package/dist/BgzipFastaMsaAdapter/index.js +0 -1
  10. package/dist/LaunchMsaView/components/LaunchMsaViewDialog.js +0 -1
  11. package/dist/LaunchMsaView/components/LaunchPanelContent.js +0 -1
  12. package/dist/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.js +0 -1
  13. package/dist/LaunchMsaView/components/ManualMSALoader/fetchGeneList.js +0 -1
  14. package/dist/LaunchMsaView/components/ManualMSALoader/launchView.js +0 -1
  15. package/dist/LaunchMsaView/components/NCBIBlastQuery/CachedBlastResults.js +0 -1
  16. package/dist/LaunchMsaView/components/NCBIBlastQuery/MsaAlgorithmSelect.js +0 -1
  17. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastAutomaticPanel.js +0 -1
  18. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastManualPanel.js +0 -1
  19. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastMethodSelector.js +0 -1
  20. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastPanel.js +0 -1
  21. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastRIDPanel.js +0 -1
  22. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBISettingsDialog.js +0 -1
  23. package/dist/LaunchMsaView/components/NCBIBlastQuery/blastLaunchView.js +0 -1
  24. package/dist/LaunchMsaView/components/NCBIBlastQuery/consts.js +0 -1
  25. package/dist/LaunchMsaView/components/NCBIBlastQuery/useCachedBlastResults.js +0 -1
  26. package/dist/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.js +0 -1
  27. package/dist/LaunchMsaView/components/PreLoadedMSA/fetchMSAData.js +0 -1
  28. package/dist/LaunchMsaView/components/PreLoadedMSA/preCalculatedLaunchView.js +0 -1
  29. package/dist/LaunchMsaView/components/PreLoadedMSA/types.js +0 -1
  30. package/dist/LaunchMsaView/components/SubmitCancelActions.js +0 -1
  31. package/dist/LaunchMsaView/components/TabPanel.js +1 -2
  32. package/dist/LaunchMsaView/components/TranscriptSelector.js +0 -1
  33. package/dist/LaunchMsaView/components/calculateProteinSequence.js +0 -1
  34. package/dist/LaunchMsaView/components/fetchSeq.js +0 -1
  35. package/dist/LaunchMsaView/components/types.js +0 -1
  36. package/dist/LaunchMsaView/components/useFeatureSequence.js +0 -1
  37. package/dist/LaunchMsaView/components/useSWRFeatureSequence.js +0 -1
  38. package/dist/LaunchMsaView/components/useTranscriptSelection.js +0 -1
  39. package/dist/LaunchMsaView/components/util.js +0 -1
  40. package/dist/LaunchMsaView/index.js +0 -1
  41. package/dist/LaunchMsaView/util.js +1 -2
  42. package/dist/LaunchMsaViewExtensionPoint/index.js +0 -1
  43. package/dist/MsaViewPanel/afterCreateAutoruns.d.ts +8 -1
  44. package/dist/MsaViewPanel/afterCreateAutoruns.js +25 -21
  45. package/dist/MsaViewPanel/blosum62.js +0 -1
  46. package/dist/MsaViewPanel/components/ConnectStructureDialog.js +0 -1
  47. package/dist/MsaViewPanel/components/ErrorBoundary.d.ts +1 -1
  48. package/dist/MsaViewPanel/components/ErrorBoundary.js +0 -1
  49. package/dist/MsaViewPanel/components/LoadingBLAST.js +0 -1
  50. package/dist/MsaViewPanel/components/MsaViewPanel.js +0 -1
  51. package/dist/MsaViewPanel/components/RIDLink.js +0 -1
  52. package/dist/MsaViewPanel/doLaunchBlast.js +0 -1
  53. package/dist/MsaViewPanel/genomeToMSA.d.ts +0 -6
  54. package/dist/MsaViewPanel/genomeToMSA.js +8 -30
  55. package/dist/MsaViewPanel/genomeToMSA.test.js +0 -1
  56. package/dist/MsaViewPanel/index.js +0 -1
  57. package/dist/MsaViewPanel/model.d.ts +143 -514
  58. package/dist/MsaViewPanel/model.js +18 -61
  59. package/dist/MsaViewPanel/msaCoordToGenomeCoord.js +5 -22
  60. package/dist/MsaViewPanel/msaCoordToGenomeCoord.test.js +0 -1
  61. package/dist/MsaViewPanel/msaDataStore.js +0 -1
  62. package/dist/MsaViewPanel/pairwiseAlignment.js +2 -10
  63. package/dist/MsaViewPanel/pairwiseAlignment.test.js +0 -1
  64. package/dist/MsaViewPanel/structureConnection.d.ts +0 -6
  65. package/dist/MsaViewPanel/structureConnection.js +0 -17
  66. package/dist/MsaViewPanel/structureConnection.test.js +1 -52
  67. package/dist/MsaViewPanel/syncGenomeHoverToMsaColumn.test.d.ts +1 -0
  68. package/dist/MsaViewPanel/syncGenomeHoverToMsaColumn.test.js +92 -0
  69. package/dist/MsaViewPanel/types.js +0 -1
  70. package/dist/MsaViewPanel/util.d.ts +1 -3
  71. package/dist/MsaViewPanel/util.js +1 -3
  72. package/dist/components/ExternalLink.js +0 -1
  73. package/dist/components/ReadOnlyTextField2.js +0 -1
  74. package/dist/components/TextField2.js +0 -1
  75. package/dist/index.js +0 -1
  76. package/dist/jbrowse-plugin-msaview.umd.production.min.js +40 -40
  77. package/dist/jbrowse-plugin-msaview.umd.production.min.js.map +4 -4
  78. package/dist/utils/blastCache.js +2 -5
  79. package/dist/utils/fetch.js +0 -1
  80. package/dist/utils/msa.js +9 -9
  81. package/dist/utils/ncbiBlast.js +5 -6
  82. package/dist/utils/swrConfig.js +0 -1
  83. package/dist/utils/taxonomyNames.js +0 -1
  84. package/dist/utils/types.js +0 -1
  85. package/dist/version.d.ts +1 -1
  86. package/dist/version.js +1 -2
  87. package/package.json +11 -11
  88. package/src/AddHighlightModel/GenomeMouseoverHighlight.tsx +4 -1
  89. package/src/AddHighlightModel/MsaToGenomeHighlight.tsx +5 -8
  90. package/src/AddHighlightModel/index.tsx +4 -1
  91. package/src/AddHighlightModel/util.ts +1 -10
  92. package/src/LaunchMsaView/components/TabPanel.tsx +1 -1
  93. package/src/LaunchMsaView/util.ts +1 -3
  94. package/src/MsaViewPanel/afterCreateAutoruns.ts +24 -21
  95. package/src/MsaViewPanel/genomeToMSA.ts +10 -29
  96. package/src/MsaViewPanel/model.ts +21 -66
  97. package/src/MsaViewPanel/msaCoordToGenomeCoord.ts +5 -21
  98. package/src/MsaViewPanel/pairwiseAlignment.ts +2 -7
  99. package/src/MsaViewPanel/structureConnection.test.ts +1 -61
  100. package/src/MsaViewPanel/structureConnection.ts +0 -22
  101. package/src/MsaViewPanel/syncGenomeHoverToMsaColumn.test.ts +112 -0
  102. package/src/MsaViewPanel/util.ts +3 -7
  103. package/src/utils/blastCache.ts +2 -4
  104. package/src/utils/msa.ts +10 -8
  105. package/src/utils/ncbiBlast.ts +5 -6
  106. package/src/version.ts +1 -1
  107. package/dist/AddHighlightModel/GenomeMouseoverHighlight.js.map +0 -1
  108. package/dist/AddHighlightModel/HighlightComponents.js.map +0 -1
  109. package/dist/AddHighlightModel/MsaToGenomeHighlight.js.map +0 -1
  110. package/dist/AddHighlightModel/index.js.map +0 -1
  111. package/dist/AddHighlightModel/util.js.map +0 -1
  112. package/dist/BgzipFastaMsaAdapter/BgzipFastaMsaAdapter.js.map +0 -1
  113. package/dist/BgzipFastaMsaAdapter/configSchema.js.map +0 -1
  114. package/dist/BgzipFastaMsaAdapter/index.js.map +0 -1
  115. package/dist/LaunchMsaView/components/LaunchMsaViewDialog.js.map +0 -1
  116. package/dist/LaunchMsaView/components/LaunchPanelContent.js.map +0 -1
  117. package/dist/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.js.map +0 -1
  118. package/dist/LaunchMsaView/components/ManualMSALoader/fetchGeneList.js.map +0 -1
  119. package/dist/LaunchMsaView/components/ManualMSALoader/launchView.js.map +0 -1
  120. package/dist/LaunchMsaView/components/NCBIBlastQuery/CachedBlastResults.js.map +0 -1
  121. package/dist/LaunchMsaView/components/NCBIBlastQuery/MsaAlgorithmSelect.js.map +0 -1
  122. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastAutomaticPanel.js.map +0 -1
  123. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastManualPanel.js.map +0 -1
  124. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastMethodSelector.js.map +0 -1
  125. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastPanel.js.map +0 -1
  126. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastRIDPanel.js.map +0 -1
  127. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBISettingsDialog.js.map +0 -1
  128. package/dist/LaunchMsaView/components/NCBIBlastQuery/blastLaunchView.js.map +0 -1
  129. package/dist/LaunchMsaView/components/NCBIBlastQuery/consts.js.map +0 -1
  130. package/dist/LaunchMsaView/components/NCBIBlastQuery/useCachedBlastResults.js.map +0 -1
  131. package/dist/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.js.map +0 -1
  132. package/dist/LaunchMsaView/components/PreLoadedMSA/fetchMSAData.js.map +0 -1
  133. package/dist/LaunchMsaView/components/PreLoadedMSA/preCalculatedLaunchView.js.map +0 -1
  134. package/dist/LaunchMsaView/components/PreLoadedMSA/types.js.map +0 -1
  135. package/dist/LaunchMsaView/components/SubmitCancelActions.js.map +0 -1
  136. package/dist/LaunchMsaView/components/TabPanel.js.map +0 -1
  137. package/dist/LaunchMsaView/components/TranscriptSelector.js.map +0 -1
  138. package/dist/LaunchMsaView/components/calculateProteinSequence.js.map +0 -1
  139. package/dist/LaunchMsaView/components/fetchSeq.js.map +0 -1
  140. package/dist/LaunchMsaView/components/types.js.map +0 -1
  141. package/dist/LaunchMsaView/components/useFeatureSequence.js.map +0 -1
  142. package/dist/LaunchMsaView/components/useSWRFeatureSequence.js.map +0 -1
  143. package/dist/LaunchMsaView/components/useTranscriptSelection.js.map +0 -1
  144. package/dist/LaunchMsaView/components/util.js.map +0 -1
  145. package/dist/LaunchMsaView/index.js.map +0 -1
  146. package/dist/LaunchMsaView/util.js.map +0 -1
  147. package/dist/LaunchMsaViewExtensionPoint/index.js.map +0 -1
  148. package/dist/MsaViewPanel/afterCreateAutoruns.js.map +0 -1
  149. package/dist/MsaViewPanel/blosum62.js.map +0 -1
  150. package/dist/MsaViewPanel/components/ConnectStructureDialog.js.map +0 -1
  151. package/dist/MsaViewPanel/components/ErrorBoundary.js.map +0 -1
  152. package/dist/MsaViewPanel/components/LoadingBLAST.js.map +0 -1
  153. package/dist/MsaViewPanel/components/MsaViewPanel.js.map +0 -1
  154. package/dist/MsaViewPanel/components/RIDLink.js.map +0 -1
  155. package/dist/MsaViewPanel/doLaunchBlast.js.map +0 -1
  156. package/dist/MsaViewPanel/genomeToMSA.js.map +0 -1
  157. package/dist/MsaViewPanel/genomeToMSA.test.js.map +0 -1
  158. package/dist/MsaViewPanel/index.js.map +0 -1
  159. package/dist/MsaViewPanel/model.js.map +0 -1
  160. package/dist/MsaViewPanel/msaCoordToGenomeCoord.js.map +0 -1
  161. package/dist/MsaViewPanel/msaCoordToGenomeCoord.test.js.map +0 -1
  162. package/dist/MsaViewPanel/msaDataStore.js.map +0 -1
  163. package/dist/MsaViewPanel/pairwiseAlignment.js.map +0 -1
  164. package/dist/MsaViewPanel/pairwiseAlignment.test.js.map +0 -1
  165. package/dist/MsaViewPanel/structureConnection.js.map +0 -1
  166. package/dist/MsaViewPanel/structureConnection.test.js.map +0 -1
  167. package/dist/MsaViewPanel/types.js.map +0 -1
  168. package/dist/MsaViewPanel/util.js.map +0 -1
  169. package/dist/components/ExternalLink.js.map +0 -1
  170. package/dist/components/ReadOnlyTextField2.js.map +0 -1
  171. package/dist/components/TextField2.js.map +0 -1
  172. package/dist/index.js.map +0 -1
  173. package/dist/utils/blastCache.js.map +0 -1
  174. package/dist/utils/fetch.js.map +0 -1
  175. package/dist/utils/msa.js.map +0 -1
  176. package/dist/utils/ncbiBlast.js.map +0 -1
  177. package/dist/utils/swrConfig.js.map +0 -1
  178. package/dist/utils/taxonomyNames.js.map +0 -1
  179. package/dist/utils/types.js.map +0 -1
  180. package/dist/version.js.map +0 -1
@@ -15,10 +15,8 @@ async function getDB() {
15
15
  });
16
16
  }
17
17
  function createCacheKey(proteinSequence, blastDatabase, blastProgram, transcriptId) {
18
- if (transcriptId) {
19
- return `${blastDatabase}:${blastProgram}:${transcriptId}:${proteinSequence}`;
20
- }
21
- return `${blastDatabase}:${blastProgram}:${proteinSequence}`;
18
+ const idPart = transcriptId ? `:${transcriptId}` : '';
19
+ return `${blastDatabase}:${blastProgram}${idPart}:${proteinSequence}`;
22
20
  }
23
21
  export async function saveBlastResult({ proteinSequence, blastDatabase, blastProgram, msaAlgorithm, msa, tree, treeMetadata, rid, geneId, transcriptId, transcriptName, geneName, }) {
24
22
  const db = await getDB();
@@ -55,4 +53,3 @@ export async function clearAllCachedResults() {
55
53
  const db = await getDB();
56
54
  await db.clear(STORE_NAME);
57
55
  }
58
- //# sourceMappingURL=blastCache.js.map
@@ -37,4 +37,3 @@ export async function unzipfetch(url, arg) {
37
37
  const res = await handleFetch(url, arg);
38
38
  return ungzip(await res.arrayBuffer(), { to: 'string' });
39
39
  }
40
- //# sourceMappingURL=fetch.js.map
package/dist/utils/msa.js CHANGED
@@ -1,23 +1,24 @@
1
1
  import { textfetch, timeout } from './fetch';
2
2
  const base = `https://www.ebi.ac.uk/Tools/services/rest`;
3
+ const email = 'colin.diesh@gmail.com';
3
4
  const algorithms = {
4
5
  clustalo: {
5
- params: { email: 'colin.diesh@gmail.com' },
6
+ params: { email },
6
7
  msaResult: 'aln-clustal_num',
7
8
  treeResult: 'phylotree',
8
9
  },
9
10
  muscle: {
10
- params: { email: 'colin.diesh@gmail.com', format: 'clw', tree: 'tree1' },
11
+ params: { email, format: 'clw', tree: 'tree1' },
11
12
  msaResult: 'fa',
12
13
  treeResult: 'phylotree',
13
14
  },
14
15
  kalign: {
15
- params: { email: 'colin.diesh@gmail.com', stype: 'protein' },
16
+ params: { email, stype: 'protein' },
16
17
  msaResult: 'fa',
17
18
  treeResult: 'phylotree',
18
19
  },
19
20
  mafft: {
20
- params: { email: 'colin.diesh@gmail.com', stype: 'protein' },
21
+ params: { email, stype: 'protein' },
21
22
  msaResult: 'fa',
22
23
  treeResult: 'phylotree',
23
24
  },
@@ -25,10 +26,6 @@ const algorithms = {
25
26
  async function wait({ onProgress, jobId, algorithm, }) {
26
27
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
27
28
  while (true) {
28
- for (let i = 0; i < 10; i++) {
29
- await timeout(1000);
30
- onProgress(`Re-checking MSA status in... ${10 - i}`);
31
- }
32
29
  const result = await textfetch(`${base}/${algorithm}/status/${jobId}`);
33
30
  if (result === 'FINISHED') {
34
31
  break;
@@ -36,6 +33,10 @@ async function wait({ onProgress, jobId, algorithm, }) {
36
33
  else if (result.includes('FAILURE')) {
37
34
  throw new Error(`Failed to run: jobId ${jobId}`);
38
35
  }
36
+ for (let i = 0; i < 10; i++) {
37
+ onProgress(`Re-checking MSA status in... ${10 - i}`);
38
+ await timeout(1000);
39
+ }
39
40
  }
40
41
  }
41
42
  export async function launchMSA({ algorithm, sequence, onProgress, }) {
@@ -51,4 +52,3 @@ export async function launchMSA({ algorithm, sequence, onProgress, }) {
51
52
  tree: await textfetch(`${base}/${algorithm}/result/${jobId}/${config.treeResult}`),
52
53
  };
53
54
  }
54
- //# sourceMappingURL=msa.js.map
@@ -58,16 +58,16 @@ async function initialQuery({ query, blastProgram, blastDatabase, baseUrl, }) {
58
58
  async function waitForRid({ rid, onProgress, baseUrl, }) {
59
59
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
60
60
  while (true) {
61
- const iter = 20;
62
- for (let i = 0; i < iter; i++) {
63
- await timeout(1000);
64
- onProgress(`Re-checking BLAST status in... ${iter - i}`);
65
- }
66
61
  const res = await textfetch(`${baseUrl}?CMD=Get&FORMAT_OBJECT=SearchInfo&RID=${rid}`);
67
62
  const statusMatch = /\s+Status=(\S+)/m.exec(res);
68
63
  const status = statusMatch?.[1];
69
64
  const hasHits = /\s+ThereAreHits=yes/m.test(res);
70
65
  if (status === 'WAITING') {
66
+ const iter = 20;
67
+ for (let i = 0; i < iter; i++) {
68
+ onProgress(`Re-checking BLAST status in... ${iter - i}`);
69
+ await timeout(1000);
70
+ }
71
71
  continue;
72
72
  }
73
73
  if (status === 'FAILED') {
@@ -84,4 +84,3 @@ async function waitForRid({ rid, onProgress, baseUrl, }) {
84
84
  throw new Error(`BLAST ${rid} returned unexpected status: ${status ?? 'unknown'}`);
85
85
  }
86
86
  }
87
- //# sourceMappingURL=ncbiBlast.js.map
@@ -6,4 +6,3 @@ export const staticSwrConfig = {
6
6
  refreshWhenOffline: false,
7
7
  shouldRetryOnError: false,
8
8
  };
9
- //# sourceMappingURL=swrConfig.js.map
@@ -112,4 +112,3 @@ export async function fetchTaxonomyInfo(taxids) {
112
112
  }
113
113
  return result;
114
114
  }
115
- //# sourceMappingURL=taxonomyNames.js.map
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=types.js.map
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "2.4.4";
1
+ export declare const version = "2.5.0";
package/dist/version.js CHANGED
@@ -1,2 +1 @@
1
- export const version = '2.4.4';
2
- //# sourceMappingURL=version.js.map
1
+ export const version = '2.5.0';
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.4.4",
2
+ "version": "2.5.0",
3
3
  "license": "MIT",
4
4
  "name": "jbrowse-plugin-msaview",
5
5
  "repository": {
@@ -20,35 +20,35 @@
20
20
  "g2p_mapper": "^2.1.5",
21
21
  "idb": "^8.0.3",
22
22
  "pako-esm2": "^2.0.2",
23
- "react-msaview": "^5.0.16",
23
+ "react-msaview": "^5.1.1",
24
24
  "swr": "^2.4.1"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@emotion/react": "^11.14.0",
28
28
  "@eslint/js": "^10.0.1",
29
29
  "@fal-works/esbuild-plugin-global-externals": "^2.1.2",
30
- "@jbrowse/core": "^4.2.1",
31
- "@jbrowse/mobx-state-tree": "^5.6.0",
32
- "@jbrowse/plugin-linear-genome-view": "^4.2.1",
30
+ "@jbrowse/core": "^4.3.0",
31
+ "@jbrowse/mobx-state-tree": "^5.10.2",
32
+ "@jbrowse/plugin-linear-genome-view": "^4.3.0",
33
33
  "@mui/icons-material": "^7.3.11",
34
34
  "@mui/material": "^7.3.11",
35
35
  "@mui/system": "^7.3.11",
36
36
  "@mui/x-data-grid": "^8.28.7",
37
37
  "@types/node": "^25.9.1",
38
38
  "@types/react": "^19.2.15",
39
- "@typescript-eslint/eslint-plugin": "^8.59.4",
40
- "@typescript-eslint/parser": "^8.59.4",
39
+ "@typescript-eslint/eslint-plugin": "^8.60.0",
40
+ "@typescript-eslint/parser": "^8.60.0",
41
41
  "esbuild": "^0.28.0",
42
42
  "eslint": "^10.4.0",
43
43
  "eslint-plugin-import-x": "^4.16.2",
44
44
  "eslint-plugin-react": "^7.37.5",
45
45
  "eslint-plugin-react-hooks": "^7.1.1",
46
46
  "eslint-plugin-unicorn": "^64.0.0",
47
- "mobx": "^6.15.3",
48
- "mobx-react": "^9.2.1",
47
+ "mobx": "^6.15.4",
48
+ "mobx-react": "^9.2.2",
49
49
  "prettier": "^3.8.3",
50
50
  "pretty-bytes": "^7.1.0",
51
- "puppeteer": "^24.43.1",
51
+ "puppeteer": "^25.1.0",
52
52
  "react": "^19.2.6",
53
53
  "react-dom": "^19.2.6",
54
54
  "rimraf": "^6.1.3",
@@ -56,7 +56,7 @@
56
56
  "serve": "^14.2.6",
57
57
  "tss-react": "^4.9.21",
58
58
  "typescript": "^6.0.3",
59
- "typescript-eslint": "^8.59.4",
59
+ "typescript-eslint": "^8.60.0",
60
60
  "vitest": "^4.1.7"
61
61
  },
62
62
  "scripts": {
@@ -4,6 +4,7 @@ import { getSession } from '@jbrowse/core/util'
4
4
  import { observer } from 'mobx-react'
5
5
 
6
6
  import { hasHoverPosition, useStyles } from './util'
7
+ import { isMsaView } from '../MsaViewPanel/model'
7
8
 
8
9
  import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
9
10
 
@@ -13,7 +14,9 @@ const GenomeMouseoverHighlight = observer(function ({
13
14
  model: LinearGenomeViewModel
14
15
  }) {
15
16
  const { hovered, views } = getSession(model)
16
- const hasMsaView = views.some(s => s.type === 'MsaView')
17
+ const hasMsaView = views.some(
18
+ s => isMsaView(s) && s.connectedViewId === model.id,
19
+ )
17
20
  return hasMsaView && hasHoverPosition(hovered) ? (
18
21
  <GenomeMouseoverHighlightRenderer model={model} hovered={hovered} />
19
22
  ) : null
@@ -4,9 +4,9 @@ import { getSession } from '@jbrowse/core/util'
4
4
  import { observer } from 'mobx-react'
5
5
 
6
6
  import { hasHoverPosition, useStyles } from './util'
7
+ import { isMsaView } from '../MsaViewPanel/model'
7
8
  import { getCanonicalRefName } from '../MsaViewPanel/util'
8
9
 
9
- import type { JBrowsePluginMsaViewModel } from '../MsaViewPanel/model'
10
10
  import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
11
11
 
12
12
  type LGV = LinearGenomeViewModel
@@ -17,18 +17,15 @@ const MsaToGenomeHighlight = observer(function MsaToGenomeHighlight2({
17
17
  model: LGV
18
18
  }) {
19
19
  const { views, hovered } = getSession(model)
20
- const msaView = views.find(f => f.type === 'MsaView') as
21
- | JBrowsePluginMsaViewModel
22
- | undefined
20
+ const msaView = views
21
+ .filter(isMsaView)
22
+ .find(v => v.connectedViewId === model.id)
23
23
  const highlights = msaView?.connectedHighlights
24
24
 
25
25
  // Suppress codon highlight while hovering the LGV — GenomeMouseoverHighlight
26
26
  // handles the single-bp display in that case
27
27
  return !hasHoverPosition(hovered) && highlights?.length ? (
28
- <MsaToGenomeHighlightRenderer
29
- model={model}
30
- highlights={Array.from(highlights)}
31
- />
28
+ <MsaToGenomeHighlightRenderer model={model} highlights={highlights} />
32
29
  ) : null
33
30
  })
34
31
 
@@ -3,6 +3,7 @@ import React from 'react'
3
3
  import { getSession } from '@jbrowse/core/util'
4
4
 
5
5
  import HighlightComponents from './HighlightComponents'
6
+ import { isMsaView } from '../MsaViewPanel/model'
6
7
 
7
8
  import type PluginManager from '@jbrowse/core/PluginManager'
8
9
  import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
@@ -16,7 +17,9 @@ export default function AddHighlightComponentsModelF(
16
17
  (rest: React.ReactNode[], { model }: { model: LinearGenomeViewModel }) => {
17
18
  // Quick check: don't add any components if no MSA view exists
18
19
  const { views } = getSession(model)
19
- const hasMsaView = views.some(v => v.type === 'MsaView')
20
+ const hasMsaView = views.some(
21
+ v => isMsaView(v) && v.connectedViewId === model.id,
22
+ )
20
23
  if (!hasMsaView) {
21
24
  return rest
22
25
  }
@@ -1,15 +1,6 @@
1
1
  import { makeStyles } from 'tss-react/mui'
2
2
 
3
- export function hasHoverPosition(
4
- hovered: unknown,
5
- ): hovered is { hoverPosition: { coord: number; refName: string } } {
6
- return (
7
- !!hovered &&
8
- typeof hovered === 'object' &&
9
- 'hoverPosition' in hovered &&
10
- !!hovered.hoverPosition
11
- )
12
- }
3
+ export { hasHoverPosition } from '../MsaViewPanel/util'
13
4
 
14
5
  export const useStyles = makeStyles()({
15
6
  highlight: {
@@ -13,7 +13,7 @@ export default function TabPanel({
13
13
  }) {
14
14
  return (
15
15
  <div role="tabpanel" hidden={value !== index} {...other}>
16
- {value === index ? <div>{children}</div> : null}
16
+ {value === index ? children : null}
17
17
  </div>
18
18
  )
19
19
  }
@@ -40,9 +40,7 @@ export function getTranscriptLength(feature: Feature) {
40
40
  const cdsLen = sum(
41
41
  feature
42
42
  .get('subfeatures')
43
- ?.filter(
44
- f => (f.get('type') as string | undefined)?.toLowerCase() === 'cds',
45
- )
43
+ ?.filter(f => f.get('type') === 'CDS')
46
44
  .map(s => s.get('end') - s.get('start')) ?? [],
47
45
  )
48
46
  return {
@@ -1,7 +1,7 @@
1
1
  import { getSession } from '@jbrowse/core/util'
2
2
 
3
3
  import { doLaunchBlast } from './doLaunchBlast'
4
- import { msaCoordToGenomeCoord } from './msaCoordToGenomeCoord'
4
+ import { genomeToMSA } from './genomeToMSA'
5
5
  import {
6
6
  cleanupOldData,
7
7
  generateDataStoreId,
@@ -19,8 +19,7 @@ import type { JBrowsePluginMsaViewModel } from './model'
19
19
  export function loadStoredData(self: JBrowsePluginMsaViewModel) {
20
20
  const { dataStoreId, rows } = self
21
21
  if (dataStoreId && rows.length === 0) {
22
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
23
- ;(async () => {
22
+ void (async () => {
24
23
  try {
25
24
  self.setLoadingStoredData(true)
26
25
  const storedData = await retrieveMsaData(dataStoreId)
@@ -56,8 +55,7 @@ export function storeDataToIndexedDB(self: JBrowsePluginMsaViewModel) {
56
55
  // data observables change while the write is pending) don't kick off a
57
56
  // duplicate write and leave an orphan IndexedDB entry
58
57
  self.setIsStoringData(true)
59
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
60
- ;(async () => {
58
+ void (async () => {
61
59
  try {
62
60
  const newId = generateDataStoreId()
63
61
  const success = await storeMsaData(newId, {
@@ -80,8 +78,7 @@ export function storeDataToIndexedDB(self: JBrowsePluginMsaViewModel) {
80
78
 
81
79
  export function launchBlastIfNeeded(self: JBrowsePluginMsaViewModel) {
82
80
  if (self.blastParams) {
83
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
84
- ;(async () => {
81
+ void (async () => {
85
82
  try {
86
83
  self.setProgress('Submitting query')
87
84
  self.setError(undefined)
@@ -101,8 +98,7 @@ export function launchBlastIfNeeded(self: JBrowsePluginMsaViewModel) {
101
98
  export function processInit(self: JBrowsePluginMsaViewModel) {
102
99
  const { init } = self
103
100
  if (init) {
104
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
105
- ;(async () => {
101
+ void (async () => {
106
102
  try {
107
103
  self.setError(undefined)
108
104
  const { msaData, msaUrl, treeData, treeUrl, querySeqName } = init
@@ -150,18 +146,25 @@ export function processInit(self: JBrowsePluginMsaViewModel) {
150
146
  }
151
147
  }
152
148
 
153
- export function updateGenomeHighlights(self: JBrowsePluginMsaViewModel) {
154
- const { mouseCol, mouseClickCol } = self
155
- const r1 =
156
- mouseCol === undefined
157
- ? undefined
158
- : msaCoordToGenomeCoord({ model: self, coord: mouseCol })
159
- const r2 =
160
- mouseClickCol === undefined
161
- ? undefined
162
- : msaCoordToGenomeCoord({ model: self, coord: mouseClickCol })
163
-
164
- self.setConnectedHighlights([r1, r2].filter(f => !!f))
149
+ /**
150
+ * Mirror the connected genome view's hover position onto the MSA's hovered
151
+ * column. Returns the autorun body so it can keep a flag tracking whether the
152
+ * MSA's mouseCol was set by this sync: that way an unrelated session hover
153
+ * change clears the column only when the genome put it there, never wiping a
154
+ * column the user is hovering directly in the MSA.
155
+ */
156
+ export function syncGenomeHoverToMsaColumn(self: JBrowsePluginMsaViewModel) {
157
+ let genomeDrivenCol = false
158
+ return () => {
159
+ const col = genomeToMSA({ model: self })
160
+ if (col !== undefined) {
161
+ self.setMousePos(col)
162
+ genomeDrivenCol = true
163
+ } else if (genomeDrivenCol) {
164
+ self.setMousePos(undefined)
165
+ genomeDrivenCol = false
166
+ }
167
+ }
165
168
  }
166
169
 
167
170
  export function highlightConnectedStructures(self: JBrowsePluginMsaViewModel) {
@@ -1,53 +1,34 @@
1
1
  import { getSession } from '@jbrowse/core/util'
2
2
 
3
- import { checkHovered } from './util'
3
+ import { hasHoverPosition } from './util'
4
4
 
5
5
  import type { JBrowsePluginMsaViewModel } from './model'
6
6
 
7
- /**
8
- * Convert a genome coordinate from session.hovered to a visible MSA column.
9
- *
10
- * @param model - The MSA view model
11
- * @returns The visible column index, or undefined if no mapping exists
12
- */
13
7
  export function genomeToMSA({ model }: { model: JBrowsePluginMsaViewModel }) {
14
8
  const { hovered } = getSession(model)
15
9
  const { querySeqName, transcriptToMsaMap, connectedView, mafRegion } = model
16
10
 
17
- if (!connectedView?.initialized || !checkHovered(hovered)) {
11
+ if (!connectedView?.initialized || !hasHoverPosition(hovered)) {
18
12
  return undefined
19
13
  }
20
14
 
21
15
  const { coord: hoverCoord, refName } = hovered.hoverPosition
22
16
 
23
- // Handle MAF region mapping
24
17
  if (mafRegion) {
25
- // Check if the hover is on the same refName as the MAF region
26
- if (refName !== mafRegion.refName) {
18
+ if (
19
+ refName !== mafRegion.refName ||
20
+ !connectedView.assemblyNames.includes(mafRegion.assemblyName) ||
21
+ hoverCoord < mafRegion.start ||
22
+ hoverCoord >= mafRegion.end
23
+ ) {
27
24
  return undefined
28
25
  }
29
- // Check if we're on the same assembly (if assembly info is available)
30
- const viewAssemblies = connectedView.assemblyNames
31
- if (!viewAssemblies.includes(mafRegion.assemblyName)) {
32
- return undefined
33
- }
34
- // Check if the hover coordinate is within the MAF region
35
- if (hoverCoord < mafRegion.start || hoverCoord >= mafRegion.end) {
36
- return undefined
37
- }
38
- // Calculate the ungapped position relative to the region start
39
- const ungappedPos = hoverCoord - mafRegion.start
40
- // Convert to visible column using the query sequence
41
- return model.seqPosToVisibleCol(querySeqName, ungappedPos)
26
+ return model.seqPosToVisibleCol(querySeqName, hoverCoord - mafRegion.start)
42
27
  }
43
28
 
44
- // Handle transcript mapping (original behavior)
45
29
  if (transcriptToMsaMap) {
46
- const { g2p } = transcriptToMsaMap
47
- // g2p maps genome coordinate to sequence position (0-based)
48
- const seqPos = g2p[hoverCoord]
30
+ const seqPos = transcriptToMsaMap.g2p[hoverCoord]
49
31
  if (seqPos !== undefined) {
50
- // Convert sequence position to visible column
51
32
  return model.seqPosToVisibleCol(querySeqName, seqPos)
52
33
  }
53
34
  }
@@ -2,7 +2,7 @@ import { lazy } from 'react'
2
2
 
3
3
  import { BaseViewModel } from '@jbrowse/core/pluggableElementTypes'
4
4
  import { getSession } from '@jbrowse/core/util'
5
- import { addDisposer, cast, types } from '@jbrowse/mobx-state-tree'
5
+ import { addDisposer, types } from '@jbrowse/mobx-state-tree'
6
6
  import { genomeToTranscriptSeqMapping } from 'g2p_mapper'
7
7
  import { autorun } from 'mobx'
8
8
  import { MSAModelF } from 'react-msaview'
@@ -16,15 +16,11 @@ import {
16
16
  processInit,
17
17
  runCleanup,
18
18
  storeDataToIndexedDB,
19
- updateGenomeHighlights,
19
+ syncGenomeHoverToMsaColumn,
20
20
  } from './afterCreateAutoruns'
21
- import { genomeToMSA } from './genomeToMSA'
22
21
  import { msaCoordToGenomeCoord } from './msaCoordToGenomeCoord'
23
22
  import { buildAlignmentMaps, runPairwiseAlignment } from './pairwiseAlignment'
24
- import {
25
- getProteinViews,
26
- ungappedToGappedPosition,
27
- } from './structureConnection'
23
+ import { getProteinViews } from './structureConnection'
28
24
  import { getCanonicalRefName } from './util'
29
25
 
30
26
  import type { ProteinView, StructureConnection } from './structureConnection'
@@ -84,13 +80,6 @@ export default function stateModelFactory() {
84
80
  /**
85
81
  * #property
86
82
  */
87
- connectedHighlights: types.array(
88
- types.model({
89
- refName: types.string,
90
- start: types.number,
91
- end: types.number,
92
- }),
93
- ),
94
83
  /**
95
84
  * #property
96
85
  */
@@ -220,37 +209,16 @@ export default function stateModelFactory() {
220
209
  /**
221
210
  * #getter
222
211
  */
223
- get structureHoverCol(): number | undefined {
224
- for (const conn of self.connectedProteinViews) {
225
- const structure = conn.proteinView.structures[conn.structureIdx]
226
- const structurePos = structure?.hoverPosition?.structureSeqPos
227
- if (structurePos !== undefined) {
228
- const msaUngapped = conn.structureToMsa[structurePos]
229
- if (msaUngapped !== undefined) {
230
- const seq = self.getSequenceByRowName(conn.msaRowName)
231
- if (seq) {
232
- const globalCol = ungappedToGappedPosition(seq, msaUngapped)
233
- if (globalCol !== undefined) {
234
- return self.globalColToVisibleCol(globalCol)
235
- }
236
- }
237
- }
238
- }
239
- }
240
- return undefined
241
- },
242
- }))
243
-
244
- .views(self => ({
245
- /**
246
- * #getter
247
- */
248
- get mouseCol2(): number | undefined {
249
- const structureCol = self.structureHoverCol
250
- if (structureCol !== undefined) {
251
- return structureCol
252
- }
253
- return genomeToMSA({ model: self as JBrowsePluginMsaViewModel })
212
+ get connectedHighlights(): IRegion[] {
213
+ const { mouseCol, mouseClickCol } = self
214
+ return [
215
+ mouseCol === undefined
216
+ ? undefined
217
+ : msaCoordToGenomeCoord({ model: self, coord: mouseCol }),
218
+ mouseClickCol === undefined
219
+ ? undefined
220
+ : msaCoordToGenomeCoord({ model: self, coord: mouseClickCol }),
221
+ ].filter((r): r is IRegion => r !== undefined)
254
222
  },
255
223
  }))
256
224
 
@@ -279,24 +247,6 @@ export default function stateModelFactory() {
279
247
  setRid(arg: string) {
280
248
  self.rid = arg
281
249
  },
282
- /**
283
- * #action
284
- */
285
- setConnectedHighlights(r: IRegion[]) {
286
- self.connectedHighlights = cast(r)
287
- },
288
- /**
289
- * #action
290
- */
291
- addToConnectedHighlights(r: IRegion) {
292
- self.connectedHighlights.push(r)
293
- },
294
- /**
295
- * #action
296
- */
297
- clearConnectedHighlights() {
298
- self.connectedHighlights = cast([])
299
- },
300
250
  /**
301
251
  * #action
302
252
  */
@@ -406,14 +356,13 @@ export default function stateModelFactory() {
406
356
  ungappedMsaSequence,
407
357
  structureSequence,
408
358
  )
409
- const { seq1ToSeq2, seq2ToSeq1 } = buildAlignmentMaps(alignment)
359
+ const { seq1ToSeq2 } = buildAlignmentMaps(alignment)
410
360
 
411
361
  const connection: StructureConnection = {
412
362
  proteinViewId,
413
363
  structureIdx,
414
364
  msaRowName: rowName,
415
365
  msaToStructure: Object.fromEntries(seq1ToSeq2),
416
- structureToMsa: Object.fromEntries(seq2ToSeq1),
417
366
  }
418
367
 
419
368
  self.connectedStructures.push(connection)
@@ -504,7 +453,6 @@ export default function stateModelFactory() {
504
453
  storeDataToIndexedDB,
505
454
  launchBlastIfNeeded,
506
455
  processInit,
507
- updateGenomeHighlights,
508
456
  highlightConnectedStructures,
509
457
  autoConnectStructures,
510
458
  observeProteinHighlights,
@@ -516,6 +464,7 @@ export default function stateModelFactory() {
516
464
  }),
517
465
  )
518
466
  }
467
+ addDisposer(self, autorun(syncGenomeHoverToMsaColumn(self)))
519
468
  },
520
469
  }))
521
470
  }
@@ -526,3 +475,9 @@ export type JBrowsePluginMsaViewStateModel = ReturnType<
526
475
  export type JBrowsePluginMsaViewModel = Instance<JBrowsePluginMsaViewStateModel>
527
476
 
528
477
  export { type MafRegion, type MsaViewInitState } from './types'
478
+
479
+ export function isMsaView(view: {
480
+ type: string
481
+ }): view is JBrowsePluginMsaViewModel {
482
+ return view.type === 'MsaView'
483
+ }
@@ -21,45 +21,29 @@ export function msaCoordToGenomeCoord({
21
21
  }) {
22
22
  const { querySeqName, transcriptToMsaMap, mafRegion } = model
23
23
 
24
- // Get the query sequence
25
- const queryRow = model.rows.find(f => f[0] === querySeqName)
26
- const querySeq = queryRow?.[1]
24
+ const querySeq = model.rows.find(f => f[0] === querySeqName)?.[1]
27
25
  if (!querySeq) {
28
26
  return undefined
29
27
  }
30
28
 
31
- // Convert gapped MSA column to ungapped sequence coordinate
32
- // Returns undefined if the position is a gap
33
29
  const ungappedPos = gappedToUngappedPosition(querySeq, mouseCol)
34
30
  if (ungappedPos === undefined) {
35
31
  return undefined
36
32
  }
37
33
 
38
- // Handle MAF region mapping
39
34
  if (mafRegion) {
40
35
  const genomePos = mafRegion.start + ungappedPos
41
- // Check if position is within the region
42
- if (genomePos >= mafRegion.end) {
43
- return undefined
44
- }
45
- return {
46
- refName: mafRegion.refName,
47
- start: genomePos,
48
- end: genomePos + 1,
49
- }
36
+ return genomePos < mafRegion.end
37
+ ? { refName: mafRegion.refName, start: genomePos, end: genomePos + 1 }
38
+ : undefined
50
39
  }
51
40
 
52
- // Handle transcript mapping (original behavior)
53
41
  if (transcriptToMsaMap) {
54
42
  const { refName, p2g } = transcriptToMsaMap
55
43
  const s = p2g[ungappedPos]
56
44
  const e = p2g[ungappedPos + 1]
57
45
  return s !== undefined && e !== undefined
58
- ? {
59
- refName,
60
- start: Math.min(s, e),
61
- end: Math.max(s, e),
62
- }
46
+ ? { refName, start: Math.min(s, e), end: Math.max(s, e) }
63
47
  : undefined
64
48
  }
65
49