jbrowse-plugin-msaview 2.2.3 → 2.2.5

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 (162) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/README.md +229 -0
  3. package/dist/AddHighlightModel/GenomeMouseoverHighlight.js +23 -18
  4. package/dist/AddHighlightModel/GenomeMouseoverHighlight.js.map +1 -1
  5. package/dist/AddHighlightModel/MsaToGenomeHighlight.js +23 -13
  6. package/dist/AddHighlightModel/MsaToGenomeHighlight.js.map +1 -1
  7. package/dist/AddHighlightModel/index.js +8 -1
  8. package/dist/AddHighlightModel/index.js.map +1 -1
  9. package/dist/AddHighlightModel/util.d.ts +2 -2
  10. package/dist/BgzipFastaMsaAdapter/configSchema.d.ts +2 -2
  11. package/dist/LaunchMsaView/components/EnsemblGeneTree/EnsemblGeneTree.js +5 -11
  12. package/dist/LaunchMsaView/components/EnsemblGeneTree/EnsemblGeneTree.js.map +1 -1
  13. package/dist/LaunchMsaView/components/EnsemblGeneTree/useGeneTree.js +5 -1
  14. package/dist/LaunchMsaView/components/EnsemblGeneTree/useGeneTree.js.map +1 -1
  15. package/dist/LaunchMsaView/components/LaunchMsaViewDialog.js +16 -16
  16. package/dist/LaunchMsaView/components/LaunchMsaViewDialog.js.map +1 -1
  17. package/dist/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.js +38 -46
  18. package/dist/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.js.map +1 -1
  19. package/dist/LaunchMsaView/components/ManualMSALoader/launchView.d.ts +4 -3
  20. package/dist/LaunchMsaView/components/ManualMSALoader/launchView.js +4 -3
  21. package/dist/LaunchMsaView/components/ManualMSALoader/launchView.js.map +1 -1
  22. package/dist/LaunchMsaView/components/NCBIBlastQuery/CachedBlastResults.d.ts +9 -0
  23. package/dist/LaunchMsaView/components/NCBIBlastQuery/CachedBlastResults.js +76 -0
  24. package/dist/LaunchMsaView/components/NCBIBlastQuery/CachedBlastResults.js.map +1 -0
  25. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastAutomaticPanel.js +35 -13
  26. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastAutomaticPanel.js.map +1 -1
  27. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastManualPanel.js +6 -12
  28. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastManualPanel.js.map +1 -1
  29. package/dist/LaunchMsaView/components/NCBIBlastQuery/blastLaunchView.d.ts +6 -0
  30. package/dist/LaunchMsaView/components/NCBIBlastQuery/blastLaunchView.js +15 -0
  31. package/dist/LaunchMsaView/components/NCBIBlastQuery/blastLaunchView.js.map +1 -1
  32. package/dist/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.js +12 -34
  33. package/dist/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.js.map +1 -1
  34. package/dist/LaunchMsaView/components/PreLoadedMSA/consts.d.ts +1 -0
  35. package/dist/LaunchMsaView/components/PreLoadedMSA/consts.js +1 -0
  36. package/dist/LaunchMsaView/components/PreLoadedMSA/consts.js.map +1 -1
  37. package/dist/LaunchMsaView/components/TabPanel.d.ts +2 -2
  38. package/dist/LaunchMsaView/components/TranscriptSelector.d.ts +2 -2
  39. package/dist/LaunchMsaView/components/TranscriptSelector.js +3 -6
  40. package/dist/LaunchMsaView/components/TranscriptSelector.js.map +1 -1
  41. package/dist/LaunchMsaView/components/useSWRFeatureSequence.js +6 -4
  42. package/dist/LaunchMsaView/components/useSWRFeatureSequence.js.map +1 -1
  43. package/dist/LaunchMsaView/components/useTranscriptSelection.d.ts +16 -0
  44. package/dist/LaunchMsaView/components/useTranscriptSelection.js +31 -0
  45. package/dist/LaunchMsaView/components/useTranscriptSelection.js.map +1 -0
  46. package/dist/LaunchMsaView/components/util.d.ts +3 -1
  47. package/dist/LaunchMsaView/components/util.js +12 -2
  48. package/dist/LaunchMsaView/components/util.js.map +1 -1
  49. package/dist/LaunchMsaView/util.d.ts +2 -0
  50. package/dist/LaunchMsaView/util.js +16 -4
  51. package/dist/LaunchMsaView/util.js.map +1 -1
  52. package/dist/LaunchMsaViewExtensionPoint/index.d.ts +2 -0
  53. package/dist/LaunchMsaViewExtensionPoint/index.js +31 -0
  54. package/dist/LaunchMsaViewExtensionPoint/index.js.map +1 -0
  55. package/dist/MsaViewPanel/components/ConnectStructureDialog.d.ts +7 -0
  56. package/dist/MsaViewPanel/components/ConnectStructureDialog.js +56 -0
  57. package/dist/MsaViewPanel/components/ConnectStructureDialog.js.map +1 -0
  58. package/dist/MsaViewPanel/components/MsaViewPanel.js +4 -2
  59. package/dist/MsaViewPanel/components/MsaViewPanel.js.map +1 -1
  60. package/dist/MsaViewPanel/doLaunchBlast.d.ts +1 -0
  61. package/dist/MsaViewPanel/doLaunchBlast.js +65 -19
  62. package/dist/MsaViewPanel/doLaunchBlast.js.map +1 -1
  63. package/dist/MsaViewPanel/genomeToMSA.d.ts +6 -0
  64. package/dist/MsaViewPanel/genomeToMSA.js +38 -8
  65. package/dist/MsaViewPanel/genomeToMSA.js.map +1 -1
  66. package/dist/MsaViewPanel/genomeToMSA.test.d.ts +1 -0
  67. package/dist/MsaViewPanel/genomeToMSA.test.js +244 -0
  68. package/dist/MsaViewPanel/genomeToMSA.test.js.map +1 -0
  69. package/dist/MsaViewPanel/model.d.ts +719 -226
  70. package/dist/MsaViewPanel/model.js +467 -39
  71. package/dist/MsaViewPanel/model.js.map +1 -1
  72. package/dist/MsaViewPanel/msaCoordToGenomeCoord.d.ts +7 -2
  73. package/dist/MsaViewPanel/msaCoordToGenomeCoord.js +26 -27
  74. package/dist/MsaViewPanel/msaCoordToGenomeCoord.js.map +1 -1
  75. package/dist/MsaViewPanel/msaCoordToGenomeCoord.test.d.ts +1 -0
  76. package/dist/MsaViewPanel/msaCoordToGenomeCoord.test.js +240 -0
  77. package/dist/MsaViewPanel/msaCoordToGenomeCoord.test.js.map +1 -0
  78. package/dist/MsaViewPanel/msaDataStore.d.ts +14 -0
  79. package/dist/MsaViewPanel/msaDataStore.js +197 -0
  80. package/dist/MsaViewPanel/msaDataStore.js.map +1 -0
  81. package/dist/MsaViewPanel/pairwiseAlignment.d.ts +27 -0
  82. package/dist/MsaViewPanel/pairwiseAlignment.js +776 -0
  83. package/dist/MsaViewPanel/pairwiseAlignment.js.map +1 -0
  84. package/dist/MsaViewPanel/pairwiseAlignment.test.d.ts +1 -0
  85. package/dist/MsaViewPanel/pairwiseAlignment.test.js +112 -0
  86. package/dist/MsaViewPanel/pairwiseAlignment.test.js.map +1 -0
  87. package/dist/MsaViewPanel/structureConnection.d.ts +27 -0
  88. package/dist/MsaViewPanel/structureConnection.js +46 -0
  89. package/dist/MsaViewPanel/structureConnection.js.map +1 -0
  90. package/dist/MsaViewPanel/structureConnection.test.d.ts +1 -0
  91. package/dist/MsaViewPanel/structureConnection.test.js +122 -0
  92. package/dist/MsaViewPanel/structureConnection.test.js.map +1 -0
  93. package/dist/MsaViewPanel/types.d.ts +13 -0
  94. package/dist/MsaViewPanel/types.js +2 -0
  95. package/dist/MsaViewPanel/types.js.map +1 -0
  96. package/dist/MsaViewPanel/util.d.ts +7 -0
  97. package/dist/MsaViewPanel/util.js +10 -0
  98. package/dist/MsaViewPanel/util.js.map +1 -1
  99. package/dist/index.d.ts +5 -5
  100. package/dist/index.js +3 -1
  101. package/dist/index.js.map +1 -1
  102. package/dist/jbrowse-plugin-msaview.umd.production.min.js +39 -90
  103. package/dist/jbrowse-plugin-msaview.umd.production.min.js.map +4 -4
  104. package/dist/utils/blastCache.d.ts +34 -0
  105. package/dist/utils/blastCache.js +58 -0
  106. package/dist/utils/blastCache.js.map +1 -0
  107. package/dist/utils/fetch.d.ts +1 -1
  108. package/dist/utils/fetch.js +1 -1
  109. package/dist/utils/fetch.js.map +1 -1
  110. package/dist/utils/ncbiBlast.d.ts +1 -5
  111. package/dist/utils/taxonomyNames.d.ts +5 -0
  112. package/dist/utils/taxonomyNames.js +79 -0
  113. package/dist/utils/taxonomyNames.js.map +1 -0
  114. package/dist/utils/types.d.ts +8 -5
  115. package/package.json +50 -54
  116. package/src/AddHighlightModel/GenomeMouseoverHighlight.tsx +37 -21
  117. package/src/AddHighlightModel/MsaToGenomeHighlight.tsx +38 -17
  118. package/src/AddHighlightModel/index.tsx +9 -4
  119. package/src/LaunchMsaView/components/EnsemblGeneTree/EnsemblGeneTree.tsx +13 -13
  120. package/src/LaunchMsaView/components/EnsemblGeneTree/useGeneTree.ts +6 -0
  121. package/src/LaunchMsaView/components/LaunchMsaViewDialog.tsx +30 -23
  122. package/src/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.tsx +64 -51
  123. package/src/LaunchMsaView/components/ManualMSALoader/launchView.ts +9 -6
  124. package/src/LaunchMsaView/components/NCBIBlastQuery/CachedBlastResults.tsx +146 -0
  125. package/src/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastAutomaticPanel.tsx +53 -22
  126. package/src/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastManualPanel.tsx +8 -13
  127. package/src/LaunchMsaView/components/NCBIBlastQuery/blastLaunchView.ts +25 -0
  128. package/src/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.tsx +27 -47
  129. package/src/LaunchMsaView/components/PreLoadedMSA/consts.ts +1 -0
  130. package/src/LaunchMsaView/components/TabPanel.tsx +2 -2
  131. package/src/LaunchMsaView/components/TranscriptSelector.tsx +13 -20
  132. package/src/LaunchMsaView/components/useSWRFeatureSequence.ts +5 -5
  133. package/src/LaunchMsaView/components/useTranscriptSelection.ts +48 -0
  134. package/src/LaunchMsaView/components/util.ts +17 -2
  135. package/src/LaunchMsaView/index.ts +1 -1
  136. package/src/LaunchMsaView/util.ts +25 -6
  137. package/src/LaunchMsaViewExtensionPoint/index.ts +74 -0
  138. package/src/MsaViewPanel/components/ConnectStructureDialog.tsx +156 -0
  139. package/src/MsaViewPanel/components/MsaViewPanel.tsx +6 -1
  140. package/src/MsaViewPanel/doLaunchBlast.ts +83 -23
  141. package/src/MsaViewPanel/genomeToMSA.test.ts +281 -0
  142. package/src/MsaViewPanel/genomeToMSA.ts +43 -10
  143. package/src/MsaViewPanel/model.ts +590 -43
  144. package/src/MsaViewPanel/msaCoordToGenomeCoord.test.ts +256 -0
  145. package/src/MsaViewPanel/msaCoordToGenomeCoord.ts +43 -29
  146. package/src/MsaViewPanel/msaDataStore.ts +236 -0
  147. package/src/MsaViewPanel/pairwiseAlignment.test.ts +140 -0
  148. package/src/MsaViewPanel/pairwiseAlignment.ts +818 -0
  149. package/src/MsaViewPanel/structureConnection.test.ts +143 -0
  150. package/src/MsaViewPanel/structureConnection.ts +72 -0
  151. package/src/MsaViewPanel/types.ts +14 -0
  152. package/src/MsaViewPanel/util.ts +11 -0
  153. package/src/index.ts +3 -1
  154. package/src/utils/blastCache.ts +114 -0
  155. package/src/utils/fetch.ts +1 -1
  156. package/src/utils/taxonomyNames.ts +111 -0
  157. package/src/utils/types.ts +9 -1
  158. package/dist/LaunchMsaView/components/PreLoadedMSA/findValidTranscriptId.d.ts +0 -5
  159. package/dist/LaunchMsaView/components/PreLoadedMSA/findValidTranscriptId.js +0 -16
  160. package/dist/LaunchMsaView/components/PreLoadedMSA/findValidTranscriptId.js.map +0 -1
  161. package/dist/out.js +0 -55381
  162. package/src/LaunchMsaView/components/PreLoadedMSA/findValidTranscriptId.ts +0 -25
@@ -0,0 +1,34 @@
1
+ export interface CachedBlastResult {
2
+ id: string;
3
+ proteinSequence: string;
4
+ blastDatabase: string;
5
+ blastProgram: string;
6
+ msaAlgorithm: string;
7
+ msa: string;
8
+ tree: string;
9
+ treeMetadata: string;
10
+ rid: string;
11
+ timestamp: number;
12
+ geneId?: string;
13
+ transcriptId?: string;
14
+ }
15
+ export declare function getCachedBlastResult({ proteinSequence, blastDatabase, blastProgram, }: {
16
+ proteinSequence: string;
17
+ blastDatabase: string;
18
+ blastProgram: string;
19
+ }): Promise<any>;
20
+ export declare function saveBlastResult({ proteinSequence, blastDatabase, blastProgram, msaAlgorithm, msa, tree, treeMetadata, rid, geneId, transcriptId, }: {
21
+ proteinSequence: string;
22
+ blastDatabase: string;
23
+ blastProgram: string;
24
+ msaAlgorithm: string;
25
+ msa: string;
26
+ tree: string;
27
+ treeMetadata: string;
28
+ rid: string;
29
+ geneId?: string;
30
+ transcriptId?: string;
31
+ }): Promise<CachedBlastResult>;
32
+ export declare function getAllCachedResults(): Promise<any[]>;
33
+ export declare function deleteCachedResult(id: string): Promise<void>;
34
+ export declare function clearAllCachedResults(): Promise<void>;
@@ -0,0 +1,58 @@
1
+ import { openDB } from 'idb';
2
+ const DB_NAME = 'jbrowse-msaview-blast-cache';
3
+ const STORE_NAME = 'blast-results';
4
+ const DB_VERSION = 2;
5
+ async function getDB() {
6
+ return openDB(DB_NAME, DB_VERSION, {
7
+ upgrade(db, oldVersion) {
8
+ if (oldVersion < 2 && db.objectStoreNames.contains(STORE_NAME)) {
9
+ db.deleteObjectStore(STORE_NAME);
10
+ }
11
+ if (!db.objectStoreNames.contains(STORE_NAME)) {
12
+ db.createObjectStore(STORE_NAME, { keyPath: 'id' });
13
+ }
14
+ },
15
+ });
16
+ }
17
+ function createCacheKey(proteinSequence, blastDatabase, blastProgram) {
18
+ return `${blastDatabase}:${blastProgram}:${proteinSequence.slice(0, 100)}`;
19
+ }
20
+ export async function getCachedBlastResult({ proteinSequence, blastDatabase, blastProgram, }) {
21
+ const db = await getDB();
22
+ const id = createCacheKey(proteinSequence, blastDatabase, blastProgram);
23
+ return db.get(STORE_NAME, id);
24
+ }
25
+ export async function saveBlastResult({ proteinSequence, blastDatabase, blastProgram, msaAlgorithm, msa, tree, treeMetadata, rid, geneId, transcriptId, }) {
26
+ const db = await getDB();
27
+ const id = createCacheKey(proteinSequence, blastDatabase, blastProgram);
28
+ const entry = {
29
+ id,
30
+ proteinSequence,
31
+ blastDatabase,
32
+ blastProgram,
33
+ msaAlgorithm,
34
+ msa,
35
+ tree,
36
+ treeMetadata,
37
+ rid,
38
+ timestamp: Date.now(),
39
+ geneId,
40
+ transcriptId,
41
+ };
42
+ await db.put(STORE_NAME, entry);
43
+ return entry;
44
+ }
45
+ export async function getAllCachedResults() {
46
+ const db = await getDB();
47
+ const results = await db.getAll(STORE_NAME);
48
+ return results.toSorted((a, b) => b.timestamp - a.timestamp);
49
+ }
50
+ export async function deleteCachedResult(id) {
51
+ const db = await getDB();
52
+ await db.delete(STORE_NAME, id);
53
+ }
54
+ export async function clearAllCachedResults() {
55
+ const db = await getDB();
56
+ await db.clear(STORE_NAME);
57
+ }
58
+ //# sourceMappingURL=blastCache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blastCache.js","sourceRoot":"","sources":["../../src/utils/blastCache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAA;AAE5B,MAAM,OAAO,GAAG,6BAA6B,CAAA;AAC7C,MAAM,UAAU,GAAG,eAAe,CAAA;AAClC,MAAM,UAAU,GAAG,CAAC,CAAA;AAiBpB,KAAK,UAAU,KAAK;IAClB,OAAO,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE;QACjC,OAAO,CAAC,EAAE,EAAE,UAAU;YACpB,IAAI,UAAU,GAAG,CAAC,IAAI,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC/D,EAAE,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAA;YAClC,CAAC;YACD,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC9C,EAAE,CAAC,iBAAiB,CAAC,UAAU,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;YACrD,CAAC;QACH,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,cAAc,CACrB,eAAuB,EACvB,aAAqB,EACrB,YAAoB;IAEpB,OAAO,GAAG,aAAa,IAAI,YAAY,IAAI,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAA;AAC5E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,EACzC,eAAe,EACf,aAAa,EACb,YAAY,GAKb;IACC,MAAM,EAAE,GAAG,MAAM,KAAK,EAAE,CAAA;IACxB,MAAM,EAAE,GAAG,cAAc,CAAC,eAAe,EAAE,aAAa,EAAE,YAAY,CAAC,CAAA;IACvE,OAAO,EAAE,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,CAAC,CAAA;AAC/B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,EACpC,eAAe,EACf,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,GAAG,EACH,IAAI,EACJ,YAAY,EACZ,GAAG,EACH,MAAM,EACN,YAAY,GAYb;IACC,MAAM,EAAE,GAAG,MAAM,KAAK,EAAE,CAAA;IACxB,MAAM,EAAE,GAAG,cAAc,CAAC,eAAe,EAAE,aAAa,EAAE,YAAY,CAAC,CAAA;IACvE,MAAM,KAAK,GAAsB;QAC/B,EAAE;QACF,eAAe;QACf,aAAa;QACb,YAAY;QACZ,YAAY;QACZ,GAAG;QACH,IAAI;QACJ,YAAY;QACZ,GAAG;QACH,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;QACrB,MAAM;QACN,YAAY;KACb,CAAA;IACD,MAAM,EAAE,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,CAAA;IAC/B,OAAO,KAAK,CAAA;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,MAAM,EAAE,GAAG,MAAM,KAAK,EAAE,CAAA;IACxB,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;IAC3C,OAAO,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC,CAAA;AAC9D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,EAAU;IACjD,MAAM,EAAE,GAAG,MAAM,KAAK,EAAE,CAAA;IACxB,MAAM,EAAE,CAAC,MAAM,CAAC,UAAU,EAAE,EAAE,CAAC,CAAA;AACjC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,MAAM,EAAE,GAAG,MAAM,KAAK,EAAE,CAAA;IACxB,MAAM,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;AAC5B,CAAC"}
@@ -3,4 +3,4 @@ export declare function textfetch(url: string, args?: RequestInit): Promise<stri
3
3
  export declare function jsonfetch<T>(url: string, args?: RequestInit): Promise<T>;
4
4
  export declare function timeout(time: number): Promise<unknown>;
5
5
  export declare function fetchWithLocalStorageCache<T>(key: string, fetchFn: () => Promise<T>): Promise<T>;
6
- export declare function unzipfetch(url: string, arg?: RequestInit): Promise<string>;
6
+ export declare function unzipfetch(url: string, arg?: RequestInit): Promise<any>;
@@ -1,4 +1,4 @@
1
- import { ungzip } from 'pako';
1
+ import { ungzip } from 'pako-esm2';
2
2
  export async function handleFetch(url, args) {
3
3
  const response = await fetch(url, args);
4
4
  if (!response.ok) {
@@ -1 +1 @@
1
- {"version":3,"file":"fetch.js","sourceRoot":"","sources":["../../src/utils/fetch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAE7B,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAW,EAAE,IAAkB;IAC/D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IAEvC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CACb,QAAQ,QAAQ,CAAC,MAAM,aAAa,GAAG,IAAI,MAAM,QAAQ,CAAC,IAAI,EAAE,EAAE,CACnE,CAAA;IACH,CAAC;IAED,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAW,EAAE,IAAkB;IAC7D,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IAC7C,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAA;AACxB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAI,GAAW,EAAE,IAAkB;IAChE,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IAC7C,OAAO,QAAQ,CAAC,IAAI,EAAgB,CAAA;AACtC,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,IAAY;IAClC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAA;AAClD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,GAAW,EACX,OAAyB;IAEzB,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAE5C,IAAI,UAAU,EAAE,CAAC;QACf,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAM,CAAA;QACpC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,iCAAiC,GAAG,GAAG,EAAE,KAAK,CAAC,CAAA;YAC7D,gDAAgD;YAChD,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;QAC9B,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,OAAO,EAAE,CAAA;IAC5B,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;IAC/C,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAW,EAAE,GAAiB;IAC7D,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;IACvC,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,WAAW,EAAE,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAA;AAC1D,CAAC"}
1
+ {"version":3,"file":"fetch.js","sourceRoot":"","sources":["../../src/utils/fetch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AAElC,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAW,EAAE,IAAkB;IAC/D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IAEvC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CACb,QAAQ,QAAQ,CAAC,MAAM,aAAa,GAAG,IAAI,MAAM,QAAQ,CAAC,IAAI,EAAE,EAAE,CACnE,CAAA;IACH,CAAC;IAED,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAW,EAAE,IAAkB;IAC7D,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IAC7C,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAA;AACxB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAI,GAAW,EAAE,IAAkB;IAChE,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IAC7C,OAAO,QAAQ,CAAC,IAAI,EAAgB,CAAA;AACtC,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,IAAY;IAClC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAA;AAClD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,GAAW,EACX,OAAyB;IAEzB,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAE5C,IAAI,UAAU,EAAE,CAAC;QACf,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAM,CAAA;QACpC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,iCAAiC,GAAG,GAAG,EAAE,KAAK,CAAC,CAAA;YAC7D,gDAAgD;YAChD,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;QAC9B,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,OAAO,EAAE,CAAA;IAC5B,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;IAC/C,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAW,EAAE,GAAiB;IAC7D,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;IACvC,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,WAAW,EAAE,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAA;AAC1D,CAAC"}
@@ -8,11 +8,7 @@ export declare function queryBlast({ query, blastDatabase, blastProgram, baseUrl
8
8
  }): Promise<{
9
9
  rid: string;
10
10
  hits: {
11
- description: {
12
- accession: string;
13
- id: string;
14
- sciname: string;
15
- }[];
11
+ description: import("./types").BlastHitDescription[];
16
12
  hsps: {
17
13
  hseq: string;
18
14
  }[];
@@ -0,0 +1,5 @@
1
+ export interface TaxonomyInfo {
2
+ sciname: string;
3
+ commonName?: string;
4
+ }
5
+ export declare function fetchTaxonomyInfo(taxids: number[]): Promise<Map<number, TaxonomyInfo>>;
@@ -0,0 +1,79 @@
1
+ import { openDB } from 'idb';
2
+ const DB_NAME = 'jbrowse-msaview-taxonomy-cache';
3
+ const STORE_NAME = 'common-names';
4
+ const DB_VERSION = 1;
5
+ async function getDB() {
6
+ return openDB(DB_NAME, DB_VERSION, {
7
+ upgrade(db) {
8
+ if (!db.objectStoreNames.contains(STORE_NAME)) {
9
+ db.createObjectStore(STORE_NAME, { keyPath: 'taxid' });
10
+ }
11
+ },
12
+ });
13
+ }
14
+ async function getCachedCommonName(taxid) {
15
+ const db = await getDB();
16
+ return db.get(STORE_NAME, taxid);
17
+ }
18
+ async function saveTaxonomyCache(entries) {
19
+ const db = await getDB();
20
+ const tx = db.transaction(STORE_NAME, 'readwrite');
21
+ for (const entry of entries) {
22
+ await tx.store.put(entry);
23
+ }
24
+ await tx.done;
25
+ }
26
+ export async function fetchTaxonomyInfo(taxids) {
27
+ const result = new Map();
28
+ const uncachedTaxids = [];
29
+ for (const taxid of taxids) {
30
+ const cached = await getCachedCommonName(taxid);
31
+ if (cached) {
32
+ result.set(taxid, {
33
+ sciname: cached.sciname,
34
+ commonName: cached.commonName,
35
+ });
36
+ }
37
+ else {
38
+ uncachedTaxids.push(taxid);
39
+ }
40
+ }
41
+ if (uncachedTaxids.length === 0) {
42
+ return result;
43
+ }
44
+ const batchSize = 100;
45
+ const toCache = [];
46
+ for (let i = 0; i < uncachedTaxids.length; i += batchSize) {
47
+ const batch = uncachedTaxids.slice(i, i + batchSize);
48
+ const idsParam = batch.join(',');
49
+ try {
50
+ const response = await fetch(`https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=taxonomy&id=${idsParam}&retmode=xml`);
51
+ const text = await response.text();
52
+ for (const taxid of batch) {
53
+ const taxonRegex = new RegExp(`<Taxon>.*?<TaxId>${taxid}</TaxId>.*?</Taxon>`, 's');
54
+ const taxonMatch = taxonRegex.exec(text);
55
+ if (taxonMatch) {
56
+ const taxonXml = taxonMatch[0];
57
+ const genbankCommon = /<GenbankCommonName>(.*?)<\/GenbankCommonName>/.exec(taxonXml);
58
+ const commonName = /<CommonName>(.*?)<\/CommonName>/.exec(taxonXml);
59
+ const sciName = /<ScientificName>(.*?)<\/ScientificName>/.exec(taxonXml);
60
+ const name = genbankCommon?.[1] ?? commonName?.[1];
61
+ const sci = sciName?.[1] ?? '';
62
+ result.set(taxid, { sciname: sci, commonName: name });
63
+ toCache.push({ taxid, sciname: sci, commonName: name });
64
+ }
65
+ else {
66
+ toCache.push({ taxid, sciname: '', commonName: undefined });
67
+ }
68
+ }
69
+ }
70
+ catch (error) {
71
+ console.error('Failed to fetch taxonomy data:', error);
72
+ }
73
+ }
74
+ if (toCache.length > 0) {
75
+ await saveTaxonomyCache(toCache);
76
+ }
77
+ return result;
78
+ }
79
+ //# sourceMappingURL=taxonomyNames.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"taxonomyNames.js","sourceRoot":"","sources":["../../src/utils/taxonomyNames.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,17 @@
1
+ export interface BlastHitDescription {
2
+ accession: string;
3
+ id: string;
4
+ sciname: string;
5
+ taxid?: number;
6
+ title?: string;
7
+ }
1
8
  export interface BlastResults {
2
9
  BlastOutput2: {
3
10
  report: {
4
11
  results: {
5
12
  search: {
6
13
  hits: {
7
- description: {
8
- accession: string;
9
- id: string;
10
- sciname: string;
11
- }[];
14
+ description: BlastHitDescription[];
12
15
  hsps: {
13
16
  hseq: string;
14
17
  }[];
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.2.3",
2
+ "version": "2.2.5",
3
3
  "license": "MIT",
4
4
  "name": "jbrowse-plugin-msaview",
5
5
  "keywords": [
@@ -11,69 +11,65 @@
11
11
  "dist",
12
12
  "src"
13
13
  ],
14
- "config": {
15
- "port": 9000,
16
- "browse": {
17
- "port": 8999
18
- },
19
- "jbrowse": {
20
- "plugin": {
21
- "name": "MsaView"
22
- }
23
- }
24
- },
25
14
  "scripts": {
26
15
  "clean": "rimraf dist",
27
- "start": "node esbuild-watch.mjs",
16
+ "start": "node esbuild.mjs --watch",
28
17
  "format": "prettier --write .",
29
18
  "build": "tsc && NODE_ENV=production node esbuild.mjs && cp distconfig.json dist/config.json",
30
- "prebuild": "npm run clean",
19
+ "prebuild": "yarn clean",
31
20
  "lint": "eslint --report-unused-disable-directives --max-warnings 0",
32
- "prepack": "npm run build",
21
+ "pretest": "rm -rf .test-jbrowse && npx @jbrowse/cli create .test-jbrowse --nightly",
22
+ "test": "vitest run",
23
+ "test:watch": "vitest",
24
+ "test:setup": "node scripts/test-versions.mjs setup",
25
+ "test:setup:version": "node scripts/test-versions.mjs setup",
26
+ "test:versions": "node scripts/test-versions.mjs run",
27
+ "test:version": "node scripts/test-versions.mjs run",
28
+ "prepack": "yarn build",
33
29
  "postversion": "git push --follow-tags"
34
30
  },
35
- "jbrowse-plugin": {
36
- "name": "MsaView"
37
- },
38
31
  "dependencies": {
39
- "@emotion/styled": "^11.14.0",
40
- "g2p_mapper": "^1.0.4",
41
- "pako": "^2.1.0",
42
- "react-msaview": "^4.4.1",
43
- "swr": "^2.3.3"
32
+ "@emotion/styled": "^11.14.1",
33
+ "g2p_mapper": "^2.0.0",
34
+ "idb": "^8.0.3",
35
+ "pako-esm2": "^2.0.0",
36
+ "react-msaview": "^5.0.6",
37
+ "swr": "^2.3.8"
44
38
  },
45
39
  "devDependencies": {
46
- "@emotion/react": "^11.10.4",
40
+ "@emotion/react": "^11.14.0",
41
+ "@eslint/js": "^9.39.2",
47
42
  "@fal-works/esbuild-plugin-global-externals": "^2.1.2",
48
- "@jbrowse/core": "^3.0.1",
49
- "@jbrowse/plugin-linear-genome-view": "^3.0.1",
50
- "@mui/icons-material": "^7.1.0",
51
- "@mui/material": "^7.1.0",
52
- "@mui/system": "^7.1.0",
53
- "@mui/x-data-grid": "^8.2.0",
54
- "@types/node": "^24.1.0",
55
- "@types/pako": "^2.0.1",
56
- "@types/react": "^19.1.6",
57
- "@typescript-eslint/eslint-plugin": "^8.0.1",
58
- "@typescript-eslint/parser": "^8.0.1",
59
- "esbuild": "^0.25.5",
60
- "eslint": "^9.28.0",
61
- "eslint-plugin-import": "^2.31.0",
62
- "eslint-plugin-react": "^7.20.3",
63
- "eslint-plugin-react-hooks": "^7.0.0",
64
- "eslint-plugin-react-refresh": "^0.4.9",
65
- "eslint-plugin-unicorn": "^61.0.2",
66
- "mobx": "^6.10.2",
67
- "mobx-react": "^9.0.1",
68
- "mobx-state-tree": "^5.3.0",
69
- "prettier": "^3.0.3",
70
- "pretty-bytes": "^7.0.0",
71
- "react": "^19.0.0",
72
- "react-dom": "^19.0.0",
73
- "rimraf": "^6.0.0",
74
- "rxjs": "^7.8.1",
75
- "tss-react": "^4.9.2",
76
- "typescript": "^5.2.2",
77
- "typescript-eslint": "^8.1.0"
43
+ "@jbrowse/core": "^4.1.1",
44
+ "@jbrowse/mobx-state-tree": "^5.4.2",
45
+ "@jbrowse/plugin-linear-genome-view": "^4.1.1",
46
+ "@mui/icons-material": "^7.3.7",
47
+ "@mui/material": "^7.3.7",
48
+ "@mui/system": "^7.3.7",
49
+ "@mui/x-data-grid": "^8.24.0",
50
+ "@types/node": "^25.0.10",
51
+ "@types/pako": "^2.0.4",
52
+ "@types/react": "^19.2.7",
53
+ "esbuild": "^0.27.2",
54
+ "eslint": "^9.39.2",
55
+ "eslint-plugin-import": "^2.32.0",
56
+ "eslint-plugin-react": "^7.37.5",
57
+ "eslint-plugin-react-hooks": "^7.0.1",
58
+ "eslint-plugin-react-refresh": "^0.4.26",
59
+ "eslint-plugin-unicorn": "^62.0.0",
60
+ "mobx": "^6.15.0",
61
+ "mobx-react": "^9.2.1",
62
+ "prettier": "^3.7.4",
63
+ "pretty-bytes": "^7.1.0",
64
+ "puppeteer": "^24.34.0",
65
+ "react": "^19.2.3",
66
+ "react-dom": "^19.2.3",
67
+ "rimraf": "^6.1.2",
68
+ "rxjs": "^7.8.2",
69
+ "serve": "^14.2.5",
70
+ "tss-react": "^4.9.20",
71
+ "typescript": "^5.9.3",
72
+ "typescript-eslint": "^8.52.0",
73
+ "vitest": "^4.0.16"
78
74
  }
79
75
  }
@@ -12,35 +12,51 @@ const GenomeMouseoverHighlight = observer(function ({
12
12
  }: {
13
13
  model: LinearGenomeViewModel
14
14
  }) {
15
- const { hovered } = getSession(model)
16
- return hovered &&
17
- typeof hovered === 'object' &&
18
- 'hoverPosition' in hovered ? (
19
- <GenomeMouseoverHighlightPostNullCheck model={model} />
20
- ) : null
15
+ const session = getSession(model)
16
+ const { hovered, views } = session
17
+
18
+ // Early return if no MSA view exists
19
+ const hasMsaView = views.some(s => s.type === 'MsaView')
20
+ if (!hasMsaView) {
21
+ return null
22
+ }
23
+
24
+ // Early return if no hover position
25
+ if (
26
+ !hovered ||
27
+ typeof hovered !== 'object' ||
28
+ !('hoverPosition' in hovered)
29
+ ) {
30
+ return null
31
+ }
32
+
33
+ return <GenomeMouseoverHighlightRenderer model={model} hovered={hovered} />
21
34
  })
22
35
 
23
- const GenomeMouseoverHighlightPostNullCheck = observer(function ({
36
+ const GenomeMouseoverHighlightRenderer = observer(function ({
24
37
  model,
38
+ hovered,
25
39
  }: {
26
40
  model: LinearGenomeViewModel
41
+
42
+ hovered: any
27
43
  }) {
28
44
  const { classes } = useStyles()
29
- const session = getSession(model)
30
- if (session.views.some(s => s.type === 'MsaView')) {
31
- const { hovered } = session
32
- const { offsetPx } = model
33
- // @ts-expect-error
34
- const { coord, refName } = hovered.hoverPosition
35
-
36
- const s = model.bpToPx({ refName, coord: coord - 1 })
37
- const e = model.bpToPx({ refName, coord: coord })
38
- if (s && e) {
39
- const width = Math.max(Math.abs(e.offsetPx - s.offsetPx), 4)
40
- const left = Math.min(s.offsetPx, e.offsetPx) - offsetPx
41
- return <div className={classes.highlight} style={{ left, width }} />
42
- }
45
+ const { offsetPx } = model
46
+ const { coord, refName } = hovered.hoverPosition as {
47
+ coord: number
48
+ refName: string
49
+ }
50
+
51
+ const s = model.bpToPx({ refName, coord: coord - 1 })
52
+ const e = model.bpToPx({ refName, coord: coord })
53
+
54
+ if (s && e) {
55
+ const width = Math.max(Math.abs(e.offsetPx - s.offsetPx), 4)
56
+ const left = Math.min(s.offsetPx, e.offsetPx) - offsetPx
57
+ return <div className={classes.highlight} style={{ left, width }} />
43
58
  }
59
+
44
60
  return null
45
61
  })
46
62
 
@@ -1,53 +1,74 @@
1
1
  import React from 'react'
2
2
 
3
- import { Assembly } from '@jbrowse/core/assemblyManager/assembly'
4
3
  import { getSession } from '@jbrowse/core/util'
5
4
  import { observer } from 'mobx-react'
6
5
 
7
6
  import { useStyles } from './util'
8
- import { JBrowsePluginMsaViewModel } from '../MsaViewPanel/model'
9
7
 
8
+ import type { JBrowsePluginMsaViewModel } from '../MsaViewPanel/model'
10
9
  import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
11
10
 
12
11
  type LGV = LinearGenomeViewModel
13
12
 
14
- function getCanonicalName(assembly: Assembly, s: string) {
15
- return assembly.getCanonicalRefName(s) ?? s
16
- }
17
-
13
+ // Outer component: only re-renders when MSA view or highlights change
18
14
  const MsaToGenomeHighlight = observer(function MsaToGenomeHighlight2({
19
15
  model,
20
16
  }: {
21
17
  model: LGV
22
18
  }) {
23
- const { classes } = useStyles()
24
- const { assemblyManager, views } = getSession(model)
25
- const p = views.find(f => f.type === 'MsaView') as
19
+ const { views } = getSession(model)
20
+ const msaView = views.find(f => f.type === 'MsaView') as
26
21
  | JBrowsePluginMsaViewModel
27
22
  | undefined
23
+
24
+ const highlights = msaView?.connectedHighlights
25
+
26
+ // Early return if no highlights - avoid all other work
27
+ if (!highlights || highlights.length === 0) {
28
+ return null
29
+ }
30
+
31
+ return <MsaToGenomeHighlightRenderer model={model} highlights={highlights} />
32
+ })
33
+
34
+ // Inner component: handles the scroll-dependent rendering
35
+ const MsaToGenomeHighlightRenderer = observer(function ({
36
+ model,
37
+ highlights,
38
+ }: {
39
+ model: LGV
40
+ highlights: { refName: string; start: number; end: number }[]
41
+ }) {
42
+ const { classes } = useStyles()
43
+ const { assemblyManager } = getSession(model)
28
44
  const assembly = assemblyManager.get(model.assemblyNames[0]!)
29
- return assembly ? (
45
+ const { offsetPx } = model
46
+
47
+ if (!assembly) {
48
+ return null
49
+ }
50
+
51
+ return (
30
52
  <>
31
- {p?.connectedHighlights.map((r, idx) => {
32
- const refName = getCanonicalName(assembly, r.refName)
53
+ {highlights.map((r, idx) => {
54
+ const refName = assembly.getCanonicalRefName(r.refName) ?? r.refName
33
55
  const s = model.bpToPx({ refName, coord: r.start })
34
56
  const e = model.bpToPx({ refName, coord: r.end })
35
57
  if (s && e) {
36
58
  const width = Math.max(Math.abs(e.offsetPx - s.offsetPx), 4)
37
- const left = Math.min(s.offsetPx, e.offsetPx) - model.offsetPx
59
+ const left = Math.min(s.offsetPx, e.offsetPx) - offsetPx
38
60
  return (
39
61
  <div
40
- key={`${JSON.stringify(r)}-${idx}`}
62
+ key={`${r.refName}-${r.start}-${r.end}-${idx}`}
41
63
  className={classes.highlight}
42
64
  style={{ left, width }}
43
65
  />
44
66
  )
45
- } else {
46
- return null
47
67
  }
68
+ return null
48
69
  })}
49
70
  </>
50
- ) : null
71
+ )
51
72
  })
52
73
 
53
74
  export default MsaToGenomeHighlight
@@ -1,6 +1,7 @@
1
1
  import React from 'react'
2
2
 
3
3
  import PluginManager from '@jbrowse/core/PluginManager'
4
+ import { getSession } from '@jbrowse/core/util'
4
5
 
5
6
  import HighlightComponents from './HighlightComponents'
6
7
 
@@ -12,10 +13,14 @@ export default function AddHighlightComponentsModelF(
12
13
  pluginManager.addToExtensionPoint(
13
14
  'LinearGenomeView-TracksContainerComponent',
14
15
  // @ts-expect-error
15
- (
16
- rest: React.ReactNode[] = [],
17
- { model }: { model: LinearGenomeViewModel },
18
- ) => {
16
+ (rest: React.ReactNode[], { model }: { model: LinearGenomeViewModel }) => {
17
+ // Quick check: don't add any components if no MSA view exists
18
+ const { views } = getSession(model)
19
+ const hasMsaView = views.some(v => v.type === 'MsaView')
20
+ if (!hasMsaView) {
21
+ return rest
22
+ }
23
+
19
24
  return [
20
25
  ...rest,
21
26
  <HighlightComponents
@@ -13,9 +13,9 @@ import { makeStyles } from 'tss-react/mui'
13
13
 
14
14
  import { ensemblGeneTreeLaunchView } from './ensemblGeneTreeLaunchView'
15
15
  import { useGeneTree } from './useGeneTree'
16
- import { getGeneDisplayName, getId, getTranscriptFeatures } from '../../util'
16
+ import { getGeneDisplayName } from '../../util'
17
17
  import TranscriptSelector from '../TranscriptSelector'
18
- import { useFeatureSequence } from '../useFeatureSequence'
18
+ import { useTranscriptSelection } from '../useTranscriptSelection'
19
19
 
20
20
  import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
21
21
 
@@ -41,15 +41,15 @@ const EnsemblGeneTree = observer(function ({
41
41
  const view = getContainingView(model) as LinearGenomeViewModel
42
42
  const { classes } = useStyles()
43
43
  const [launchViewError, setLaunchViewError] = useState<unknown>()
44
- const options = getTranscriptFeatures(feature)
45
- const [userSelection, setUserSelection] = useState(getId(options[0]))
46
- const { treeData, isTreeLoading, treeError } = useGeneTree(userSelection)
47
- const selectedTranscript = options.find(val => getId(val) === userSelection)!
48
-
49
- const { proteinSequence, error: featureSequenceError } = useFeatureSequence({
50
- view,
51
- feature: selectedTranscript,
52
- })
44
+ const {
45
+ options,
46
+ selectedId,
47
+ setSelectedId,
48
+ selectedTranscript,
49
+ proteinSequence,
50
+ error: featureSequenceError,
51
+ } = useTranscriptSelection({ feature, view })
52
+ const { treeData, isTreeLoading, treeError } = useGeneTree(selectedId)
53
53
 
54
54
  const loadingMessage = isTreeLoading
55
55
  ? 'Loading tree data from Ensembl GeneTree'
@@ -76,8 +76,8 @@ const EnsemblGeneTree = observer(function ({
76
76
  <TranscriptSelector
77
77
  feature={feature}
78
78
  options={options}
79
- selectedTranscriptId={userSelection}
80
- onTranscriptChange={setUserSelection}
79
+ selectedTranscript={selectedTranscript}
80
+ onTranscriptChange={setSelectedId}
81
81
  proteinSequence={proteinSequence}
82
82
  />
83
83
  </DialogContent>
@@ -1,10 +1,16 @@
1
1
  import useSWR from 'swr'
2
+
2
3
  import { geneTreeFetcher } from './ensemblGeneTreeUtils'
3
4
 
4
5
  export function useGeneTree(geneId: string) {
5
6
  const { data, error, isLoading } = useSWR(
6
7
  () => (geneId ? ['geneTree', geneId] : null),
7
8
  ([, geneId]) => geneTreeFetcher(geneId),
9
+ {
10
+ revalidateOnFocus: false,
11
+ revalidateOnReconnect: false,
12
+ revalidateIfStale: false,
13
+ },
8
14
  )
9
15
 
10
16
  return { treeData: data, isTreeLoading: isLoading, treeError: error }