jbrowse-plugin-protein3d 0.8.0 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/dist/AddHighlightModel/GenomeTo1DProteinHoverHighlight.js +2 -11
  2. package/dist/AddHighlightModel/ProteinToGenomeHighlightInner.js +8 -4
  3. package/dist/AddHighlightModel/ProteinToMsaHoverSync.js +6 -2
  4. package/dist/AddHighlightModel/proteinViewLookup.d.ts +37 -0
  5. package/dist/AddHighlightModel/proteinViewLookup.js +23 -0
  6. package/dist/AddHighlightModel/util.d.ts +0 -3
  7. package/dist/AddHighlightModel/util.js +0 -4
  8. package/dist/LaunchProteinView/components/AlphaFoldDBSearch.js +3 -1
  9. package/dist/LaunchProteinView/components/AlphaFoldDBSearchStatus.js +2 -1
  10. package/dist/LaunchProteinView/components/FoldseekActionMenu.js +4 -3
  11. package/dist/LaunchProteinView/components/FoldseekResultsTable.js +1 -1
  12. package/dist/LaunchProteinView/components/FoldseekSearch.js +2 -2
  13. package/dist/LaunchProteinView/components/LaunchProteinViewDialog.js +1 -1
  14. package/dist/LaunchProteinView/components/ProteinViewActions.js +3 -3
  15. package/dist/LaunchProteinView/components/SequenceMismatchNotice.js +2 -3
  16. package/dist/LaunchProteinView/components/StructureSourcePicker.js +1 -1
  17. package/dist/LaunchProteinView/components/UniProtResultsTable.js +2 -1
  18. package/dist/LaunchProteinView/components/UserProvidedStructure.js +4 -2
  19. package/dist/LaunchProteinView/components/proteinAssemblySetup.js +2 -1
  20. package/dist/LaunchProteinView/components/proteinTrackSetup.d.ts +0 -41
  21. package/dist/LaunchProteinView/components/proteinTrackSetup.js +14 -16
  22. package/dist/LaunchProteinView/hooks/useAlphaFoldDBSearch.js +6 -4
  23. package/dist/LaunchProteinView/hooks/useAlphaFoldData.d.ts +1 -1
  24. package/dist/LaunchProteinView/hooks/useAlphaFoldData.js +2 -2
  25. package/dist/LaunchProteinView/hooks/useAlphaFoldSequenceSearch.js +2 -2
  26. package/dist/LaunchProteinView/hooks/useStructureFileSequence.js +4 -13
  27. package/dist/LaunchProteinView/hooks/useTranscriptIsoformSelection.d.ts +3 -2
  28. package/dist/LaunchProteinView/hooks/useTranscriptIsoformSelection.js +7 -4
  29. package/dist/LaunchProteinView/index.js +58 -10
  30. package/dist/LaunchProteinView/services/foldseekApi.d.ts +0 -21
  31. package/dist/LaunchProteinView/services/foldseekApi.js +13 -10
  32. package/dist/LaunchProteinView/utils/caCoordsToPdb.d.ts +10 -2
  33. package/dist/LaunchProteinView/utils/caCoordsToPdb.js +7 -8
  34. package/dist/LaunchProteinView/utils/calculateProteinSequence.d.ts +3 -13
  35. package/dist/LaunchProteinView/utils/calculateProteinSequence.js +25 -16
  36. package/dist/LaunchProteinView/utils/geneticCodes.d.ts +14 -0
  37. package/dist/LaunchProteinView/utils/geneticCodes.js +227 -0
  38. package/dist/LaunchProteinView/utils/launchViewUtils.d.ts +4 -13
  39. package/dist/LaunchProteinView/utils/launchViewUtils.js +4 -6
  40. package/dist/LaunchProteinView/utils/sideBySide.js +25 -4
  41. package/dist/LaunchProteinView/utils/structureUrls.d.ts +30 -1
  42. package/dist/LaunchProteinView/utils/structureUrls.js +63 -1
  43. package/dist/LaunchProteinView/utils/util.d.ts +24 -1
  44. package/dist/LaunchProteinView/utils/util.js +30 -6
  45. package/dist/LaunchProteinViewExtensionPoint/index.js +38 -17
  46. package/dist/LaunchProteinViewExtensionPoint/resolveShortLaunch.d.ts +3 -2
  47. package/dist/LaunchProteinViewExtensionPoint/resolveShortLaunch.js +20 -6
  48. package/dist/ProteinView/addStructureFromData.d.ts +4 -0
  49. package/dist/ProteinView/addStructureFromData.js +5 -1
  50. package/dist/ProteinView/addStructureFromURL.d.ts +3 -0
  51. package/dist/ProteinView/addStructureFromURL.js +4 -1
  52. package/dist/ProteinView/applyLociInteractivity.d.ts +9 -20
  53. package/dist/ProteinView/applyLociInteractivity.js +15 -15
  54. package/dist/ProteinView/chooseMappedEntity.js +20 -10
  55. package/dist/ProteinView/components/AddStructureDialog.js +17 -18
  56. package/dist/ProteinView/components/FeatureBar.js +2 -4
  57. package/dist/ProteinView/components/ManualAlignmentDialog.js +29 -15
  58. package/dist/ProteinView/components/ProteinAlignment.js +58 -18
  59. package/dist/ProteinView/components/ProteinFeatureTrack.js +2 -5
  60. package/dist/ProteinView/components/ProteinView.js +1 -1
  61. package/dist/ProteinView/components/SplitString.d.ts +9 -0
  62. package/dist/ProteinView/components/SplitString.js +22 -3
  63. package/dist/ProteinView/extractStructureSequences.d.ts +38 -4
  64. package/dist/ProteinView/extractStructureSequences.js +39 -0
  65. package/dist/ProteinView/hooks/useProteinFeatureTrackData.d.ts +15 -11
  66. package/dist/ProteinView/hooks/useProteinFeatureTrackData.js +25 -18
  67. package/dist/ProteinView/hooks/useStructureUniProt.d.ts +26 -0
  68. package/dist/ProteinView/hooks/useStructureUniProt.js +47 -0
  69. package/dist/ProteinView/hooks/useUniProtFeatures.js +8 -6
  70. package/dist/ProteinView/loadStructureData.d.ts +16 -1
  71. package/dist/ProteinView/loadStructureData.js +10 -5
  72. package/dist/ProteinView/model.d.ts +29 -26
  73. package/dist/ProteinView/model.js +2 -2
  74. package/dist/ProteinView/pairwiseAlignment.d.ts +10 -0
  75. package/dist/ProteinView/pairwiseAlignment.js +209 -177
  76. package/dist/ProteinView/pdbUniProtMapping.d.ts +43 -0
  77. package/dist/ProteinView/pdbUniProtMapping.js +130 -0
  78. package/dist/ProteinView/proteinViewSpec.d.ts +3 -2
  79. package/dist/ProteinView/residueTracks.d.ts +0 -2
  80. package/dist/ProteinView/residueTracks.js +2 -2
  81. package/dist/ProteinView/structureFormat.d.ts +27 -0
  82. package/dist/ProteinView/structureFormat.js +65 -0
  83. package/dist/ProteinView/structureModel.d.ts +41 -25
  84. package/dist/ProteinView/structureModel.js +114 -100
  85. package/dist/ProteinView/structurePipeline.d.ts +2 -0
  86. package/dist/ProteinView/structurePipeline.js +6 -2
  87. package/dist/ProteinView/subscribeMolstarInteraction.d.ts +9 -7
  88. package/dist/ProteinView/subscribeMolstarInteraction.js +1 -1
  89. package/dist/ProteinView/types.d.ts +7 -1
  90. package/dist/ProteinView/types.js +6 -1
  91. package/dist/ProteinView/useProteinView.js +1 -1
  92. package/dist/ProteinView/util.d.ts +14 -0
  93. package/dist/ProteinView/util.js +17 -0
  94. package/dist/fetchUtils.d.ts +7 -0
  95. package/dist/fetchUtils.js +7 -1
  96. package/dist/jbrowse-plugin-protein3d.umd.production.min.js +17 -16
  97. package/dist/jbrowse-plugin-protein3d.umd.production.min.js.map +4 -4
  98. package/dist/mappings.d.ts +22 -0
  99. package/dist/mappings.js +31 -10
  100. package/dist/{molstar-chunk-Z2FKPQGY.js → molstar-chunk-UJIWPKE3.js} +1 -1
  101. package/dist/{molstar-chunk-Z2FKPQGY.js.map → molstar-chunk-UJIWPKE3.js.map} +1 -1
  102. package/dist/version.d.ts +1 -1
  103. package/dist/version.js +1 -1
  104. package/package.json +17 -14
  105. package/src/AddHighlightModel/GenomeTo1DProteinHoverHighlight.tsx +5 -14
  106. package/src/AddHighlightModel/ProteinToGenomeHighlightInner.tsx +23 -18
  107. package/src/AddHighlightModel/ProteinToMsaHoverSync.tsx +6 -2
  108. package/src/AddHighlightModel/msaHoverSyncGuard.test.ts +4 -8
  109. package/src/AddHighlightModel/proteinViewLookup.test.ts +31 -0
  110. package/src/AddHighlightModel/proteinViewLookup.ts +56 -0
  111. package/src/AddHighlightModel/util.ts +0 -9
  112. package/src/BaseProteinAnnotationAdapter.ts +4 -1
  113. package/src/LaunchProteinView/components/AlphaFoldDBSearch.tsx +3 -1
  114. package/src/LaunchProteinView/components/AlphaFoldDBSearchStatus.tsx +2 -3
  115. package/src/LaunchProteinView/components/FoldseekActionMenu.tsx +7 -5
  116. package/src/LaunchProteinView/components/FoldseekResultsTable.tsx +1 -1
  117. package/src/LaunchProteinView/components/FoldseekSearch.tsx +2 -2
  118. package/src/LaunchProteinView/components/LaunchProteinViewDialog.tsx +1 -0
  119. package/src/LaunchProteinView/components/ProteinViewActions.tsx +19 -3
  120. package/src/LaunchProteinView/components/SequenceMismatchNotice.tsx +1 -2
  121. package/src/LaunchProteinView/components/StructureSourcePicker.tsx +1 -1
  122. package/src/LaunchProteinView/components/UniProtResultsTable.tsx +2 -3
  123. package/src/LaunchProteinView/components/UserProvidedStructure.tsx +4 -2
  124. package/src/LaunchProteinView/components/proteinAssemblySetup.ts +3 -1
  125. package/src/LaunchProteinView/components/proteinTrackSetup.ts +15 -18
  126. package/src/LaunchProteinView/hooks/useAlphaFoldDBSearch.ts +6 -3
  127. package/src/LaunchProteinView/hooks/useAlphaFoldData.ts +2 -2
  128. package/src/LaunchProteinView/hooks/useAlphaFoldSequenceSearch.ts +2 -2
  129. package/src/LaunchProteinView/hooks/useSafeLaunch.ts +4 -1
  130. package/src/LaunchProteinView/hooks/useStructureFileSequence.ts +4 -16
  131. package/src/LaunchProteinView/hooks/useTranscriptIsoformSelection.ts +17 -5
  132. package/src/LaunchProteinView/index.ts +113 -34
  133. package/src/LaunchProteinView/services/foldseekApi.ts +16 -11
  134. package/src/LaunchProteinView/utils/caCoordsToPdb.ts +9 -8
  135. package/src/LaunchProteinView/utils/calculateProteinSequence.ts +42 -22
  136. package/src/LaunchProteinView/utils/geneticCodes.ts +298 -0
  137. package/src/LaunchProteinView/utils/launchViewUtils.ts +6 -26
  138. package/src/LaunchProteinView/utils/pickStructureSequence.test.ts +39 -0
  139. package/src/LaunchProteinView/utils/sideBySide.test.ts +47 -0
  140. package/src/LaunchProteinView/utils/sideBySide.ts +31 -6
  141. package/src/LaunchProteinView/utils/stripStopCodon.test.ts +23 -0
  142. package/src/LaunchProteinView/utils/structureUrls.test.ts +78 -0
  143. package/src/LaunchProteinView/utils/structureUrls.ts +81 -1
  144. package/src/LaunchProteinView/utils/util.ts +37 -7
  145. package/src/LaunchProteinViewExtensionPoint/index.ts +62 -34
  146. package/src/LaunchProteinViewExtensionPoint/resolveShortLaunch.ts +35 -8
  147. package/src/Protein1DViewRegistry/index.test.ts +8 -1
  148. package/src/ProteinView/addStructureFromData.ts +5 -1
  149. package/src/ProteinView/addStructureFromURL.ts +8 -2
  150. package/src/ProteinView/applyLociInteractivity.ts +16 -41
  151. package/src/ProteinView/autoScroll.test.ts +15 -5
  152. package/src/ProteinView/chooseMappedEntity.test.ts +75 -5
  153. package/src/ProteinView/chooseMappedEntity.ts +23 -10
  154. package/src/ProteinView/components/AddStructureDialog.tsx +24 -21
  155. package/src/ProteinView/components/FeatureBar.tsx +2 -4
  156. package/src/ProteinView/components/ManualAlignmentDialog.tsx +31 -14
  157. package/src/ProteinView/components/ProteinAlignment.tsx +105 -44
  158. package/src/ProteinView/components/ProteinFeatureTrack.tsx +2 -4
  159. package/src/ProteinView/components/ProteinView.tsx +4 -0
  160. package/src/ProteinView/components/SplitString.tsx +23 -4
  161. package/src/ProteinView/components/matchRuns.test.ts +26 -0
  162. package/src/ProteinView/extractStructureSequences.test.ts +105 -0
  163. package/src/ProteinView/extractStructureSequences.ts +73 -4
  164. package/src/ProteinView/geneExplorerLinkage.test.ts +8 -2
  165. package/src/ProteinView/hooks/layoutFeature.test.ts +87 -0
  166. package/src/ProteinView/hooks/useProteinFeatureTrackData.ts +38 -22
  167. package/src/ProteinView/hooks/useStructureUniProt.ts +95 -0
  168. package/src/ProteinView/hooks/useUniProtFeatures.ts +9 -6
  169. package/src/ProteinView/labelSeqIdIntegration.test.ts +163 -0
  170. package/src/ProteinView/loadStructureData.ts +28 -6
  171. package/src/ProteinView/model.ts +9 -2
  172. package/src/ProteinView/molstarSelectionQuery.test.ts +147 -0
  173. package/src/ProteinView/pairwiseAlignment.test.ts +28 -0
  174. package/src/ProteinView/pairwiseAlignment.ts +269 -210
  175. package/src/ProteinView/pdbUniProtMapping.test.ts +184 -0
  176. package/src/ProteinView/pdbUniProtMapping.ts +181 -0
  177. package/src/ProteinView/proteinViewSpec.ts +2 -1
  178. package/src/ProteinView/residueTracks.ts +2 -2
  179. package/src/ProteinView/structureFormat.test.ts +81 -0
  180. package/src/ProteinView/structureFormat.ts +83 -0
  181. package/src/ProteinView/structureLoader.test.ts +58 -4
  182. package/src/ProteinView/structureModel.ts +149 -133
  183. package/src/ProteinView/structurePipeline.ts +23 -2
  184. package/src/ProteinView/structureSuperposer.test.ts +3 -1
  185. package/src/ProteinView/subscribeMolstarInteraction.ts +10 -9
  186. package/src/ProteinView/types.ts +7 -2
  187. package/src/ProteinView/useProteinView.ts +1 -1
  188. package/src/ProteinView/util.test.ts +33 -1
  189. package/src/ProteinView/util.ts +21 -0
  190. package/src/UniProtVariationAdapter/parseUniProtVariants.test.ts +1 -4
  191. package/src/fetchUtils.ts +7 -1
  192. package/src/mappings.test.characterization.test.ts +16 -1
  193. package/src/mappings.ts +45 -10
  194. package/src/version.ts +1 -1
@@ -3,7 +3,7 @@ import { SimpleFeature, getSession } from '@jbrowse/core/util';
3
3
  import { observer } from 'mobx-react';
4
4
  import Highlight from './Highlight';
5
5
  import { protein1DViewRegistry } from '../Protein1DViewRegistry';
6
- import { checkHovered } from '../ProteinView/util';
6
+ import { genomeHoverToTranscriptPos } from '../ProteinView/util';
7
7
  import { genomeToTranscriptSeqMapping } from '../mappings';
8
8
  const GenomeTo1DProteinHoverHighlight = observer(function GenomeTo1DProteinHoverHighlight({ model, }) {
9
9
  const session = getSession(model);
@@ -17,17 +17,8 @@ const GenomeTo1DProteinHoverHighlight = observer(function GenomeTo1DProteinHover
17
17
  if (!protein1DInfo) {
18
18
  return null;
19
19
  }
20
- if (!checkHovered(hovered)) {
21
- return null;
22
- }
23
- const { coord, refName } = hovered.hoverPosition;
24
20
  const feature = new SimpleFeature(protein1DInfo.feature);
25
- const mapping = genomeToTranscriptSeqMapping(feature);
26
- const { g2p } = mapping;
27
- // g2p is keyed by genomic position on the transcript's own refName; without
28
- // this gate the same numeric coord on an unrelated chromosome would match a
29
- // key and light a protein residue for a different locus.
30
- const proteinPos = refName === mapping.refName ? g2p[coord - 1] : undefined;
21
+ const proteinPos = genomeHoverToTranscriptPos(hovered, genomeToTranscriptSeqMapping(feature));
31
22
  if (proteinPos === undefined) {
32
23
  return null;
33
24
  }
@@ -2,17 +2,21 @@ import React from 'react';
2
2
  import { getSession } from '@jbrowse/core/util';
3
3
  import { observer } from 'mobx-react';
4
4
  import Highlight from './Highlight';
5
- import { getProteinView } from './util';
5
+ import { getProteinViews, getStructuresConnectedTo } from './proteinViewLookup';
6
6
  const ProteinToGenomeHighlightInner = observer(function ProteinToGenomeHighlightInner({ model, field, }) {
7
7
  const session = getSession(model);
8
8
  const { assemblyManager } = session;
9
- const { assemblyNames } = model;
10
- const proteinView = getProteinView(session);
9
+ const { assemblyNames, id: viewId } = model;
11
10
  const assemblyName = assemblyNames[0];
12
11
  const assembly = assemblyName
13
12
  ? assemblyManager.get(assemblyName)
14
13
  : undefined;
15
- return assembly && assemblyName ? (React.createElement(React.Fragment, null, proteinView?.structures.flatMap((structure, idx) => structure[field].map((r, idx2) => (React.createElement(Highlight, { key: `${r.refName}-${r.start}-${r.end}-${idx}-${idx2}`, model: model, region: {
14
+ // Only structures that declare this genome view as their connection: the
15
+ // regions are transcript coordinates on that view's assembly, so painting
16
+ // them into any other genome view would place a highlight at coordinates
17
+ // that mean nothing there.
18
+ const structures = getStructuresConnectedTo(getProteinViews(session), viewId);
19
+ return assembly && assemblyName ? (React.createElement(React.Fragment, null, structures.flatMap((structure, idx) => structure[field].map((r, idx2) => (React.createElement(Highlight, { key: `${r.refName}-${r.start}-${r.end}-${idx}-${idx2}`, model: model, region: {
16
20
  start: r.start,
17
21
  end: r.end,
18
22
  refName: r.refName,
@@ -4,7 +4,7 @@ import { autorun, untracked } from 'mobx';
4
4
  import { observer } from 'mobx-react';
5
5
  import { findConnectedMsaView } from './findConnectedMsaView';
6
6
  import { findStructureRowName } from './msaRowMatch';
7
- import { getProteinView } from './util';
7
+ import { getProteinView } from './proteinViewLookup';
8
8
  import { stripStopCodon } from '../LaunchProteinView/utils/util';
9
9
  const ProteinToMsaHoverSync = observer(function ProteinToMsaHoverSync({ model, }) {
10
10
  const session = getSession(model);
@@ -27,7 +27,11 @@ const ProteinToMsaHoverSync = observer(function ProteinToMsaHoverSync({ model, }
27
27
  // on every hover, so the per-hover conversions below stay cheap.
28
28
  let structureRowName;
29
29
  disposers.push(autorun(() => {
30
- const seq = proteinView.primaryStructure?.structureSequences?.[0];
30
+ // The *mapped* entity, not entity [0]: hover positions below are in the
31
+ // mapped entity's coordinates (molstar interactions are gated to it), so
32
+ // matching chain A's sequence for a heteromer whose gene is chain C
33
+ // finds no row and silently falls back to a wrong 1:1 mapping.
34
+ const seq = proteinView.primaryStructure?.mappedStructureSeq;
31
35
  structureRowName = findStructureRowName(msaView.rowMap, seq === undefined ? undefined : stripStopCodon(seq));
32
36
  }));
33
37
  if (msaView.setMousePos) {
@@ -0,0 +1,37 @@
1
+ import type { JBrowsePluginProteinStructureModel } from '../ProteinView/model';
2
+ import type { AbstractSessionModel } from '@jbrowse/core/util';
3
+ /**
4
+ * What the highlight/hover bridges need from a ProteinView. Declared
5
+ * structurally (like ParentProteinView in structureModel.ts) because the MST
6
+ * Instance type of `structures` widens to a snapshot union at the array
7
+ * boundary, which would force a cast at every call site.
8
+ */
9
+ export interface HighlightSourceProteinView {
10
+ id: string;
11
+ connectedMsaViewId?: string;
12
+ structures: JBrowsePluginProteinStructureModel[];
13
+ primaryStructure?: JBrowsePluginProteinStructureModel;
14
+ }
15
+ export declare function getProteinViews(session: AbstractSessionModel): HighlightSourceProteinView[];
16
+ /**
17
+ * NOTE: assumes a single ProteinView. Unlike the genome-highlight bridge (which
18
+ * pairs by the declared `connectedViewId`, see getStructuresConnectedTo), a
19
+ * second ProteinView's MSA hover sync is skipped — pairing an MSA to one of
20
+ * several protein views has no reliable rule when the protein view declares
21
+ * neither a connectedMsaViewId nor a connectedViewId.
22
+ */
23
+ export declare function getProteinView(session: AbstractSessionModel): HighlightSourceProteinView | undefined;
24
+ interface ConnectableStructure {
25
+ connectedViewId?: string;
26
+ }
27
+ /**
28
+ * Every structure across all ProteinViews that declares this genome view as its
29
+ * connection. Structures are paired to a genome view explicitly, so a second
30
+ * LinearGenomeView doesn't mirror another view's highlights (the coordinates
31
+ * would be meaningless there, possibly on a different assembly), and a second
32
+ * ProteinView isn't ignored.
33
+ */
34
+ export declare function getStructuresConnectedTo<T extends ConnectableStructure>(proteinViews: {
35
+ structures: T[];
36
+ }[], viewId: string): T[];
37
+ export {};
@@ -0,0 +1,23 @@
1
+ export function getProteinViews(session) {
2
+ return session.views.filter(v => v.type === 'ProteinView');
3
+ }
4
+ /**
5
+ * NOTE: assumes a single ProteinView. Unlike the genome-highlight bridge (which
6
+ * pairs by the declared `connectedViewId`, see getStructuresConnectedTo), a
7
+ * second ProteinView's MSA hover sync is skipped — pairing an MSA to one of
8
+ * several protein views has no reliable rule when the protein view declares
9
+ * neither a connectedMsaViewId nor a connectedViewId.
10
+ */
11
+ export function getProteinView(session) {
12
+ return getProteinViews(session)[0];
13
+ }
14
+ /**
15
+ * Every structure across all ProteinViews that declares this genome view as its
16
+ * connection. Structures are paired to a genome view explicitly, so a second
17
+ * LinearGenomeView doesn't mirror another view's highlights (the coordinates
18
+ * would be meaningless there, possibly on a different assembly), and a second
19
+ * ProteinView isn't ignored.
20
+ */
21
+ export function getStructuresConnectedTo(proteinViews, viewId) {
22
+ return proteinViews.flatMap(view => view.structures.filter(s => s.connectedViewId === viewId));
23
+ }
@@ -1,5 +1,3 @@
1
- import type { JBrowsePluginProteinViewModel } from '../ProteinView/model';
2
- import type { AbstractSessionModel } from '@jbrowse/core/util';
3
1
  import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view';
4
2
  export interface HighlightRegion {
5
3
  refName: string;
@@ -20,4 +18,3 @@ export declare const useStyles: (params: void, muiStyleOverridesParams?: {
20
18
  css: import("tss-react").Css;
21
19
  cx: import("tss-react").Cx;
22
20
  };
23
- export declare function getProteinView(session: AbstractSessionModel): JBrowsePluginProteinViewModel | undefined;
@@ -34,7 +34,3 @@ export const useStyles = makeStyles()({
34
34
  border: '1px solid black',
35
35
  },
36
36
  });
37
- export function getProteinView(session) {
38
- const view = session.views.find(v => v.type === 'ProteinView');
39
- return view;
40
- }
@@ -43,7 +43,9 @@ const AlphaFoldDBSearch = observer(function AlphaFoldDBSearch({ feature, session
43
43
  state.error ? React.createElement(ErrorMessage, { error: state.error }) : null,
44
44
  React.createElement(UniProtIdInput, { lookupMode: state.lookupMode, onLookupModeChange: state.setLookupMode, manualUniprotId: state.manualUniprotId, onManualUniprotIdChange: state.setManualUniprotId, featureUniprotId: state.featureUniprotId, hasProteinSequence: !!state.userSelectedProteinSequence?.seq, sequenceSearchType: state.sequenceSearchType, onSequenceSearchTypeChange: state.setSequenceSearchType, endContent: state.showIdentifierSelector ? (React.createElement("div", { className: classes.endRow },
45
45
  React.createElement(IdentifierSelector, { recognizedIds: state.recognizedIds, geneName: state.geneName, selectedId: state.selectedQueryId, onSelectedIdChange: state.setSelectedQueryId }),
46
- React.createElement(TextField, { size: "small", label: "Organism (NCBI taxon)", helperText: "Scopes the gene-name search", value: state.taxonId, onChange: event => { state.setTaxonId(event.target.value); }, placeholder: String(state.effectiveTaxonId), slotProps: { inputLabel: { shrink: true } }, sx: { width: 180 } }))) : null }),
46
+ React.createElement(TextField, { size: "small", label: "Organism (NCBI taxon)", helperText: "Scopes the gene-name search", value: state.taxonId, onChange: event => {
47
+ state.setTaxonId(event.target.value);
48
+ }, placeholder: String(state.effectiveTaxonId), slotProps: { inputLabel: { shrink: true } }, sx: { width: 180 } }))) : null }),
47
49
  state.loadingStatuses.map(status => (React.createElement(LoadingEllipses, { key: status, variant: "subtitle2", message: status }))),
48
50
  state.showUniprotResults && (React.createElement(React.Fragment, null,
49
51
  React.createElement(Typography, { variant: "body2", color: "textSecondary" },
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  import { Typography } from '@mui/material';
3
3
  import IsoformSequencesToggle from './IsoformSequencesToggle';
4
4
  import ExternalLink from '../../components/ExternalLink';
5
+ import { uniprotEntryUrl } from '../utils/structureUrls';
5
6
  import { getTranscriptDisplayName } from '../utils/util';
6
7
  function NotFound({ uniprotId }) {
7
8
  return (React.createElement(Typography, null,
@@ -15,7 +16,7 @@ export default function AlphaFoldDBSearchStatus({ uniprotId, selectedTranscript,
15
16
  React.createElement(Typography, null,
16
17
  "UniProt link:",
17
18
  ' ',
18
- React.createElement(ExternalLink, { href: `https://www.uniprot.org/uniprotkb/${uniprotId}/entry` }, uniprotId)),
19
+ React.createElement(ExternalLink, { href: uniprotEntryUrl(uniprotId) }, uniprotId)),
19
20
  React.createElement(Typography, null,
20
21
  "AlphaFoldDB link: ",
21
22
  React.createElement(ExternalLink, { href: url }, url))),
@@ -3,7 +3,8 @@ import { ErrorMessage } from '@jbrowse/core/ui';
3
3
  import { Button, Menu, MenuItem } from '@mui/material';
4
4
  import { useSafeLaunch } from '../hooks/useSafeLaunch';
5
5
  import { caCoordsToPdb, hasValidCaCoords } from '../utils/caCoordsToPdb';
6
- import { getConditionalProteinLaunches, getConfidenceUrlFromTarget, getUniprotIdFromAlphaFoldTarget, launch3DProteinView, } from '../utils/launchViewUtils';
6
+ import { getConditionalProteinLaunches, launch3DProteinView, } from '../utils/launchViewUtils';
7
+ import { getConfidenceUrlFromTarget, getUniprotIdFromAlphaFoldTarget, } from '../utils/structureUrls';
7
8
  export default function FoldseekActionMenu({ hit, session, view, feature, selectedTranscript, userProvidedTranscriptSequence, onClose, }) {
8
9
  const [anchorEl, setAnchorEl] = useState(null);
9
10
  const open = Boolean(anchorEl);
@@ -18,7 +19,7 @@ export default function FoldseekActionMenu({ hit, session, view, feature, select
18
19
  const baseParams = { session, view, feature, selectedTranscript, uniprotId };
19
20
  const handleLaunch3D = runLaunch(() => {
20
21
  // Use tCa coordinates to generate PDB data if no URL is available
21
- const pdbData = !hit.structureUrl && hasValidCaCoords(hit.tCa, hit.tSeq)
22
+ const pdbData = !hit.structureUrl && hasValidCaCoords(hit)
22
23
  ? caCoordsToPdb(hit.tCa, hit.tSeq, 'A', hit.target)
23
24
  : undefined;
24
25
  launch3DProteinView({
@@ -32,7 +33,7 @@ export default function FoldseekActionMenu({ hit, session, view, feature, select
32
33
  ...baseParams,
33
34
  confidenceUrl: getConfidenceUrlFromTarget(hit.target),
34
35
  });
35
- const canLoad = !!hit.structureUrl || hasValidCaCoords(hit.tCa, hit.tSeq);
36
+ const canLoad = !!hit.structureUrl || hasValidCaCoords(hit);
36
37
  if (!canLoad) {
37
38
  return React.createElement("span", null, "-");
38
39
  }
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Typography, } from '@mui/material';
3
3
  import { makeStyles } from 'tss-react/mui';
4
4
  import FoldseekActionMenu from './FoldseekActionMenu';
5
- import { getStructureUrlFromTarget } from '../utils/launchViewUtils';
5
+ import { getStructureUrlFromTarget } from '../utils/structureUrls';
6
6
  const useStyles = makeStyles()(theme => ({
7
7
  root: {
8
8
  display: 'flex',
@@ -9,7 +9,7 @@ import TranscriptSelector from './TranscriptSelector';
9
9
  import useFoldseekSearch from '../hooks/useFoldseekSearch';
10
10
  import useTranscriptIsoformSelection from '../hooks/useTranscriptIsoformSelection';
11
11
  import { DEFAULT_DATABASES } from '../services/foldseekApi';
12
- import { stripStopCodon } from '../utils/util';
12
+ import { stripAllStopCodons } from '../utils/util';
13
13
  const useStyles = makeStyles()({
14
14
  dialogContent: {
15
15
  width: '80em',
@@ -33,7 +33,7 @@ const FoldseekSearch = observer(function FoldseekSearch({ feature, session, view
33
33
  const { results, cleanedAaSequence, di3Sequence, isLoading, isPredicting, error, statusMessage, predictStructure, search, reset, } = useFoldseekSearch();
34
34
  const { transcripts, isoformSequences, isLoading: isLoadingIsoforms, error: isoformError, selectedTranscriptId: effectiveSelectedTranscriptId, setSelectedTranscriptId: setUserSelection, selectedTranscript, selectedIsoform: selectedIsoformData, } = useTranscriptIsoformSelection({ feature, view });
35
35
  const cleanedSequence = selectedIsoformData
36
- ? stripStopCodon(selectedIsoformData.seq)
36
+ ? stripAllStopCodons(selectedIsoformData.seq)
37
37
  : '';
38
38
  const sequence = userEditedSequence ?? cleanedSequence;
39
39
  // Any change to the input sequence makes an existing 3Di prediction (and any
@@ -14,7 +14,7 @@ export default function LaunchProteinViewDialog({ handleClose, feature, model, }
14
14
  const [alignmentAlgorithm, setAlignmentAlgorithm] = useLocalStorage('jbrowse-protein3d-alignment-algorithm', DEFAULT_ALIGNMENT_ALGORITHM);
15
15
  const session = getSession(model);
16
16
  const view = getContainingView(model);
17
- return (React.createElement(Dialog, { maxWidth: "xl", title: "Launch protein view", titleNode: React.createElement(React.Fragment, null,
17
+ return (React.createElement(Dialog, { "data-testid": "launch-protein-view-dialog", maxWidth: "xl", title: "Launch protein view", titleNode: React.createElement(React.Fragment, null,
18
18
  "Launch protein view ",
19
19
  React.createElement(HelpButton, null)), open: true, onClose: handleClose },
20
20
  React.createElement(Tabs, { value: choice, onChange: (_, val) => {
@@ -2,7 +2,7 @@ import React, { useState } from 'react';
2
2
  import { ErrorMessage } from '@jbrowse/core/ui';
3
3
  import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
4
4
  import SettingsIcon from '@mui/icons-material/Settings';
5
- import { Button, ButtonGroup, IconButton, Tooltip, Typography } from '@mui/material';
5
+ import { Button, ButtonGroup, IconButton, Tooltip, Typography, } from '@mui/material';
6
6
  import LaunchOptionsDialog from './LaunchOptionsDialog';
7
7
  import LaunchSettingsDialog from './LaunchSettingsDialog';
8
8
  import SequenceMismatchNotice from './SequenceMismatchNotice';
@@ -95,8 +95,8 @@ export default function ProteinViewActions({ handleClose, uniprotId, userSelecte
95
95
  } }, "Cancel"),
96
96
  showMissingReasons ? (React.createElement(Typography, { variant: "body2", color: "error", sx: { mr: 2 } }, missingReasons.join('. '))) : null,
97
97
  React.createElement(ButtonGroup, { variant: "contained", color: "primary", size: "small" },
98
- React.createElement(Button, { disabled: !canLaunch, onClick: handleLaunch3DView }, "Launch"),
99
- React.createElement(Button, { disabled: !canLaunch, onClick: () => {
98
+ React.createElement(Button, { "data-testid": "protein-launch-button", disabled: !canLaunch, onClick: handleLaunch3DView }, "Launch"),
99
+ React.createElement(Button, { "data-testid": "protein-launch-options-button", disabled: !canLaunch, onClick: () => {
100
100
  setDialogOpen(true);
101
101
  }, "aria-label": "More launch options" },
102
102
  React.createElement(ArrowDropDownIcon, null))),
@@ -6,8 +6,7 @@ export default function SequenceMismatchNotice({ alignmentAlgorithm, onAlignment
6
6
  return (React.createElement(Typography, { variant: "body2", sx: { mr: 2, display: 'flex', alignItems: 'center' } },
7
7
  "Transcript and structure sequences differ, will run",
8
8
  ' ',
9
- ALIGNMENT_ALGORITHM_LABELS[alignmentAlgorithm] ?? alignmentAlgorithm,
10
- ' ',
11
- "alignment",
9
+ ALIGNMENT_ALGORITHM_LABELS[alignmentAlgorithm],
10
+ " alignment",
12
11
  React.createElement(AlignmentSettingsButton, { value: alignmentAlgorithm, onChange: onAlignmentAlgorithmChange })));
13
12
  }
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { Button, FormControl, FormControlLabel, Radio, RadioGroup, TextField, Typography, } from '@mui/material';
3
3
  import HelpButton from './HelpButton';
4
- import { getPdbStructureUrl } from '../utils/launchViewUtils';
4
+ import { getPdbStructureUrl } from '../utils/structureUrls';
5
5
  export default function StructureSourcePicker({ choice, setChoice, structureURL, setStructureURL, setFile, pdbId, setPdbId, }) {
6
6
  return (React.createElement("div", { style: { display: 'flex', margin: 30 } },
7
7
  React.createElement(Typography, null,
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  import { Chip, Paper, Radio, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Typography, } from '@mui/material';
3
3
  import { makeStyles } from 'tss-react/mui';
4
4
  import ExternalLink from '../../components/ExternalLink';
5
+ import { uniprotEntryUrl } from '../utils/structureUrls';
5
6
  const useStyles = makeStyles()(theme => ({
6
7
  tableContainer: {
7
8
  maxHeight: 200,
@@ -57,7 +58,7 @@ export default function UniProtResultsTable({ entries, selectedAccession, onSele
57
58
  React.createElement(TableCell, { padding: "checkbox" },
58
59
  React.createElement(Radio, { checked: selectedAccession === entry.accession, size: "small" })),
59
60
  React.createElement(TableCell, null,
60
- React.createElement(ExternalLink, { href: `https://www.uniprot.org/uniprotkb/${entry.accession}` }, entry.accession)),
61
+ React.createElement(ExternalLink, { href: uniprotEntryUrl(entry.accession) }, entry.accession)),
61
62
  React.createElement(TableCell, null, entry.geneName ?? '-'),
62
63
  React.createElement(TableCell, null, entry.organismName ?? '-'),
63
64
  React.createElement(TableCell, null, entry.proteinName
@@ -40,8 +40,10 @@ const UserProvidedStructure = observer(function UserProvidedStructure({ feature,
40
40
  const activeURL = choice === 'file' ? '' : structureURL;
41
41
  const { sequences: structureSequences, error: fileError } = useStructureFileSequence({ file: activeFile, url: activeURL });
42
42
  const structureName = activeFile?.name ?? activeURL.slice(activeURL.lastIndexOf('/') + 1);
43
- const structureSequence = structureSequences?.[0];
44
- const { transcripts: options, isoformSequences, selectedTranscriptId: userSelection, setSelectedTranscriptId: setUserSelection, selectedTranscript, selectedIsoform: protein, error: isoformError, } = useTranscriptIsoformSelection({ feature, view, structureSequence });
43
+ const { transcripts: options, isoformSequences,
44
+ // the chain the isoforms are compared against — not blindly chain 0, which
45
+ // mismatched every heteromer the view itself went on to map correctly
46
+ structureSequence, selectedTranscriptId: userSelection, setSelectedTranscriptId: setUserSelection, selectedTranscript, selectedIsoform: protein, error: isoformError, } = useTranscriptIsoformSelection({ feature, view, structureSequences });
45
47
  const error = isoformError ?? launchError ?? fileError;
46
48
  const canLaunch = !!(activeURL || activeFile) && !!protein && !!selectedTranscript;
47
49
  const sequencesDiffer = !!protein?.seq &&
@@ -1,3 +1,4 @@
1
+ import { uniprotFastaUrl } from '../utils/structureUrls';
1
2
  /**
2
3
  * Sets up a temporary assembly for a protein sequence from UniProt
3
4
  */
@@ -12,7 +13,7 @@ export function setupProteinAssembly(session, uniprotId) {
12
13
  type: 'UnindexedFastaAdapter',
13
14
  rewriteRefNames: "jexl:split(refName,'|')[1]",
14
15
  fastaLocation: {
15
- uri: `https://rest.uniprot.org/uniprotkb/${uniprotId}.fasta`,
16
+ uri: uniprotFastaUrl(uniprotId),
16
17
  },
17
18
  },
18
19
  },
@@ -1,45 +1,4 @@
1
1
  import type { SessionWithAddTracks } from '@jbrowse/core/util';
2
- /**
3
- * Fetches UniProt GFF data and extracts unique feature types
4
- */
5
- export declare function fetchUniProtFeatureTypes(uniprotId: string): Promise<string[]>;
6
- /**
7
- * Adds UniProt feature tracks for each feature type
8
- */
9
- export declare function addUniProtFeatureTracks({ session, uniprotId, featureTypes, }: {
10
- session: SessionWithAddTracks;
11
- uniprotId: string;
12
- featureTypes: string[];
13
- }): void;
14
- /**
15
- * Adds antigen annotation track from EBI
16
- */
17
- export declare function addAntigenTrack({ session, uniprotId, }: {
18
- session: SessionWithAddTracks;
19
- uniprotId: string;
20
- }): void;
21
- /**
22
- * Adds variation track from EBI
23
- */
24
- export declare function addVariationTrack({ session, uniprotId, }: {
25
- session: SessionWithAddTracks;
26
- uniprotId: string;
27
- }): void;
28
- /**
29
- * Adds AlphaFold confidence track
30
- */
31
- export declare function addAlphaFoldConfidenceTrack({ session, uniprotId, confidenceUrl, }: {
32
- session: SessionWithAddTracks;
33
- uniprotId: string;
34
- confidenceUrl: string | undefined;
35
- }): void;
36
- /**
37
- * Adds AlphaMissense pathogenicity scores track
38
- */
39
- export declare function addAlphaMissenseTrack({ session, uniprotId, }: {
40
- session: SessionWithAddTracks;
41
- uniprotId: string;
42
- }): void;
43
2
  /**
44
3
  * Adds all protein annotation tracks for a given UniProt ID
45
4
  */
@@ -1,26 +1,24 @@
1
+ import { myfetch } from '../../fetchUtils';
2
+ import { uniprotGffUrl } from '../utils/structureUrls';
1
3
  /**
2
4
  * Fetches UniProt GFF data and extracts unique feature types
3
5
  */
4
- export async function fetchUniProtFeatureTypes(uniprotId) {
5
- const url = `https://rest.uniprot.org/uniprotkb/${uniprotId}.gff`;
6
- const res = await fetch(url);
7
- if (!res.ok) {
8
- throw new Error(`HTTP ${res.status} fetching ${url}`);
9
- }
10
- const data = await res.text();
6
+ async function fetchUniProtFeatureTypes(uniprotId) {
7
+ const data = await (await myfetch(uniprotGffUrl(uniprotId))).text();
11
8
  return [
12
9
  ...new Set(data
13
10
  .split('\n')
14
11
  .filter(f => !f.startsWith('#'))
15
- .map(f => f.trim())
16
- .filter(f => !!f)
17
- .map(f => f.split('\t')[2])),
12
+ // column 3 is the GFF type; a line without one would otherwise become an
13
+ // `undefined`-named track
14
+ .map(f => f.split('\t')[2]?.trim())
15
+ .filter((f) => !!f)),
18
16
  ];
19
17
  }
20
18
  /**
21
19
  * Adds UniProt feature tracks for each feature type
22
20
  */
23
- export function addUniProtFeatureTracks({ session, uniprotId, featureTypes, }) {
21
+ function addUniProtFeatureTracks({ session, uniprotId, featureTypes, }) {
24
22
  featureTypes.forEach(type => {
25
23
  const trackId = `${uniprotId}-${type}`;
26
24
  session.addTrackConf({
@@ -30,7 +28,7 @@ export function addUniProtFeatureTracks({ session, uniprotId, featureTypes, }) {
30
28
  adapter: {
31
29
  type: 'Gff3Adapter',
32
30
  gffLocation: {
33
- uri: `https://rest.uniprot.org/uniprotkb/${uniprotId}.gff`,
31
+ uri: uniprotGffUrl(uniprotId),
34
32
  },
35
33
  },
36
34
  assemblyNames: [uniprotId],
@@ -47,7 +45,7 @@ export function addUniProtFeatureTracks({ session, uniprotId, featureTypes, }) {
47
45
  /**
48
46
  * Adds antigen annotation track from EBI
49
47
  */
50
- export function addAntigenTrack({ session, uniprotId, }) {
48
+ function addAntigenTrack({ session, uniprotId, }) {
51
49
  session.addTrackConf({
52
50
  type: 'FeatureTrack',
53
51
  trackId: `${uniprotId}-Antigen`,
@@ -64,7 +62,7 @@ export function addAntigenTrack({ session, uniprotId, }) {
64
62
  /**
65
63
  * Adds variation track from EBI
66
64
  */
67
- export function addVariationTrack({ session, uniprotId, }) {
65
+ function addVariationTrack({ session, uniprotId, }) {
68
66
  session.addTrackConf({
69
67
  type: 'FeatureTrack',
70
68
  trackId: `${uniprotId}-Variation`,
@@ -81,7 +79,7 @@ export function addVariationTrack({ session, uniprotId, }) {
81
79
  /**
82
80
  * Adds AlphaFold confidence track
83
81
  */
84
- export function addAlphaFoldConfidenceTrack({ session, uniprotId, confidenceUrl, }) {
82
+ function addAlphaFoldConfidenceTrack({ session, uniprotId, confidenceUrl, }) {
85
83
  if (confidenceUrl) {
86
84
  session.addTrackConf({
87
85
  type: 'QuantitativeTrack',
@@ -100,7 +98,7 @@ export function addAlphaFoldConfidenceTrack({ session, uniprotId, confidenceUrl,
100
98
  /**
101
99
  * Adds AlphaMissense pathogenicity scores track
102
100
  */
103
- export function addAlphaMissenseTrack({ session, uniprotId, }) {
101
+ function addAlphaMissenseTrack({ session, uniprotId, }) {
104
102
  session.addTrackConf({
105
103
  type: 'MultiQuantitativeTrack',
106
104
  trackId: `${uniprotId}-AlphaMissense-scores`,
@@ -26,7 +26,9 @@ export default function useAlphaFoldDBSearch({ feature, view, }) {
26
26
  ? extractTaxonId(getConf(assembly, ['sequence', 'metadata']))
27
27
  : undefined;
28
28
  const overrideTaxon = Number(taxonIdInput.trim());
29
- const effectiveTaxonId = taxonIdInput.trim() !== '' && Number.isFinite(overrideTaxon) && overrideTaxon > 0
29
+ const effectiveTaxonId = taxonIdInput.trim() !== '' &&
30
+ Number.isFinite(overrideTaxon) &&
31
+ overrideTaxon > 0
30
32
  ? overrideTaxon
31
33
  : assemblyTaxonId;
32
34
  const [selectedQueryId, setSelectedQueryId] = useState('auto');
@@ -55,13 +57,13 @@ export default function useAlphaFoldDBSearch({ feature, view, }) {
55
57
  : effectiveLookupMode === 'manual'
56
58
  ? debouncedManualUniprotId
57
59
  : undefined;
58
- const { isLoading: isAlphaFoldLoading, isValidating: isAlphaFoldValidating, error: alphaFoldError, url: alphaFoldUrl, confidenceUrl: alphaFoldConfidenceUrl, structureSequence: alphaFoldStructureSequence, } = useAlphaFoldData({
60
+ const { isLoading: isAlphaFoldLoading, isValidating: isAlphaFoldValidating, error: alphaFoldError, url: alphaFoldUrl, confidenceUrl: alphaFoldConfidenceUrl, structureSequences: alphaFoldStructureSequences, } = useAlphaFoldData({
59
61
  uniprotId: isSequenceMode ? undefined : uniprotId,
60
62
  });
61
- const { transcripts: transcriptOptions, isoformSequences, isLoading: isIsoformLoading, error: isoformError, selectedTranscriptId: effectiveTranscriptId, setSelectedTranscriptId: setUserSelection, selectedTranscript, selectedIsoform: userSelectedProteinSequence, } = useTranscriptIsoformSelection({
63
+ const { transcripts: transcriptOptions, isoformSequences, structureSequence: alphaFoldStructureSequence, isLoading: isIsoformLoading, error: isoformError, selectedTranscriptId: effectiveTranscriptId, setSelectedTranscriptId: setUserSelection, selectedTranscript, selectedIsoform: userSelectedProteinSequence, } = useTranscriptIsoformSelection({
62
64
  feature,
63
65
  view,
64
- structureSequence: alphaFoldStructureSequence,
66
+ structureSequences: alphaFoldStructureSequences,
65
67
  resetKey: uniprotId,
66
68
  });
67
69
  const { uniprotId: seqSearchUniprotId, cifUrl: seqSearchUrl, plddtDocUrl: seqSearchConfidenceUrl, structureSequence: seqSearchStructureSequence, isLoading: isSequenceSearchLoading, isValidating: isSequenceSearchValidating, error: sequenceSearchError, } = useAlphaFoldSequenceSearch({
@@ -6,5 +6,5 @@ export default function useAlphaFoldData({ uniprotId, }: {
6
6
  error: any;
7
7
  url: string | undefined;
8
8
  confidenceUrl: string | undefined;
9
- structureSequence: string | undefined;
9
+ structureSequences: string[] | undefined;
10
10
  };
@@ -1,5 +1,5 @@
1
1
  import useStructureFileSequence from './useStructureFileSequence';
2
- import { getAlphaFoldConfidenceUrl, getAlphaFoldStructureUrl, } from '../utils/launchViewUtils';
2
+ import { getAlphaFoldConfidenceUrl, getAlphaFoldStructureUrl, } from '../utils/structureUrls';
3
3
  export default function useAlphaFoldData({ uniprotId, }) {
4
4
  const url = uniprotId ? getAlphaFoldStructureUrl(uniprotId) : undefined;
5
5
  const confidenceUrl = uniprotId
@@ -12,6 +12,6 @@ export default function useAlphaFoldData({ uniprotId, }) {
12
12
  error,
13
13
  url,
14
14
  confidenceUrl,
15
- structureSequence: sequences?.[0],
15
+ structureSequences: sequences,
16
16
  };
17
17
  }
@@ -3,13 +3,13 @@ import useSWR from 'swr';
3
3
  import { STATIC_SWR_OPTIONS } from './swrOptions';
4
4
  import { jsonfetch } from '../../fetchUtils';
5
5
  import { md5 } from '../utils/md5';
6
- import { stripStopCodon } from '../utils/util';
6
+ import { stripAllStopCodons } from '../utils/util';
7
7
  export default function useAlphaFoldSequenceSearch({ sequence, searchType, enabled = true, }) {
8
8
  const searchValue = useMemo(() => {
9
9
  if (!sequence) {
10
10
  return undefined;
11
11
  }
12
- const cleanSeq = stripStopCodon(sequence.toUpperCase());
12
+ const cleanSeq = stripAllStopCodons(sequence.toUpperCase());
13
13
  return searchType === 'md5' ? md5(cleanSeq) : cleanSeq;
14
14
  }, [sequence, searchType]);
15
15
  const { data, error, isLoading, isValidating } = useSWR(enabled && searchValue
@@ -4,22 +4,13 @@ import { addStructureFromData } from '../../ProteinView/addStructureFromData';
4
4
  import { addStructureFromURL } from '../../ProteinView/addStructureFromURL';
5
5
  import { extractStructureSequences } from '../../ProteinView/extractStructureSequences';
6
6
  import { withTemporaryMolstarPlugin } from '../../ProteinView/withTemporaryMolstarPlugin';
7
- function detectStructureFormat(fileName) {
8
- const dot = fileName.lastIndexOf('.');
9
- const ext = dot >= 0 ? fileName.slice(dot + 1).toLowerCase() : '';
10
- if (ext === 'cif' || ext === 'mmcif' || ext === 'bcif') {
11
- return 'mmcif';
12
- }
13
- return 'pdb';
14
- }
7
+ // Format is detected by addStructureFromData/addStructureFromURL themselves.
8
+ // This hook used to detect it here, for the file branch only, which meant the
9
+ // dialog preview and the view that followed could disagree about the same file.
15
10
  async function fetchSequences({ file, url }) {
16
11
  return withTemporaryMolstarPlugin(async (plugin) => {
17
12
  const { model } = file
18
- ? await addStructureFromData({
19
- data: await file.text(),
20
- plugin,
21
- format: detectStructureFormat(file.name),
22
- })
13
+ ? await addStructureFromData({ data: await file.text(), plugin })
23
14
  : await addStructureFromURL({ url: url, plugin });
24
15
  return extractStructureSequences(model);
25
16
  });
@@ -1,14 +1,15 @@
1
1
  import type { Feature } from '@jbrowse/core/util';
2
- export default function useTranscriptIsoformSelection({ feature, view, structureSequence, resetKey, }: {
2
+ export default function useTranscriptIsoformSelection({ feature, view, structureSequences, resetKey, }: {
3
3
  feature: Feature;
4
4
  view?: {
5
5
  assemblyNames?: string[];
6
6
  };
7
- structureSequence?: string;
7
+ structureSequences?: string[];
8
8
  resetKey?: string;
9
9
  }): {
10
10
  transcripts: Feature[];
11
11
  isoformSequences: import("../utils/util").IsoformSequences | undefined;
12
+ structureSequence: string | undefined;
12
13
  isLoading: boolean;
13
14
  error: any;
14
15
  selectedTranscriptId: string | undefined;
@@ -1,15 +1,17 @@
1
1
  import useIsoformProteinSequences from './useIsoformProteinSequences';
2
2
  import useTranscriptSelection from './useTranscriptSelection';
3
- import { getId, getTranscriptFeatures } from '../utils/util';
3
+ import { getId, getTranscriptFeatures, pickStructureSequence, } from '../utils/util';
4
4
  // Bundles the transcript-isoform wiring shared by all three launch tabs:
5
- // list transcripts, fetch their protein sequences, auto/manually select one,
6
- // and resolve the selection back to its feature + sequence.
7
- export default function useTranscriptIsoformSelection({ feature, view, structureSequence, resetKey, }) {
5
+ // list transcripts, fetch their protein sequences, pick which chain of the
6
+ // structure to compare against, auto/manually select a transcript, and resolve
7
+ // the selection back to its feature + sequence.
8
+ export default function useTranscriptIsoformSelection({ feature, view, structureSequences, resetKey, }) {
8
9
  const transcripts = getTranscriptFeatures(feature);
9
10
  const { isoformSequences, isLoading, error } = useIsoformProteinSequences({
10
11
  feature,
11
12
  view,
12
13
  });
14
+ const structureSequence = pickStructureSequence(structureSequences, isoformSequences);
13
15
  const { userSelection, setUserSelection } = useTranscriptSelection({
14
16
  options: transcripts,
15
17
  isoformSequences,
@@ -23,6 +25,7 @@ export default function useTranscriptIsoformSelection({ feature, view, structure
23
25
  return {
24
26
  transcripts,
25
27
  isoformSequences,
28
+ structureSequence,
26
29
  isLoading,
27
30
  error,
28
31
  selectedTranscriptId: userSelection,