jbrowse-plugin-protein3d 0.0.3 → 0.0.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 (196) hide show
  1. package/dist/AddHighlightModel/GenomeMouseoverHighlight.js +3 -9
  2. package/dist/AddHighlightModel/GenomeMouseoverHighlight.js.map +1 -1
  3. package/dist/AddHighlightModel/HighlightComponents.d.ts +1 -2
  4. package/dist/AddHighlightModel/HighlightComponents.js.map +1 -1
  5. package/dist/AddHighlightModel/ProteinToGenomeClickHighlight.js +4 -3
  6. package/dist/AddHighlightModel/ProteinToGenomeClickHighlight.js.map +1 -1
  7. package/dist/AddHighlightModel/ProteinToGenomeHoverHighlight.d.ts +1 -2
  8. package/dist/AddHighlightModel/ProteinToGenomeHoverHighlight.js +4 -3
  9. package/dist/AddHighlightModel/ProteinToGenomeHoverHighlight.js.map +1 -1
  10. package/dist/AddHighlightModel/util.js +1 -1
  11. package/dist/AddHighlightModel/util.js.map +1 -1
  12. package/dist/AlphaFoldConfidenceAdapter/AlphaFoldConfidenceAdapter.d.ts +16 -0
  13. package/dist/AlphaFoldConfidenceAdapter/AlphaFoldConfidenceAdapter.js +43 -0
  14. package/dist/AlphaFoldConfidenceAdapter/AlphaFoldConfidenceAdapter.js.map +1 -0
  15. package/dist/AlphaFoldConfidenceAdapter/configSchema.d.ts +13 -0
  16. package/dist/AlphaFoldConfidenceAdapter/configSchema.js +16 -0
  17. package/dist/AlphaFoldConfidenceAdapter/configSchema.js.map +1 -0
  18. package/dist/AlphaFoldConfidenceAdapter/index.d.ts +2 -0
  19. package/dist/AlphaFoldConfidenceAdapter/index.js +11 -0
  20. package/dist/AlphaFoldConfidenceAdapter/index.js.map +1 -0
  21. package/dist/AlphaMissensePathogenicityAdapter/AlphaMissensePathogenicityAdapter.d.ts +30 -0
  22. package/dist/AlphaMissensePathogenicityAdapter/AlphaMissensePathogenicityAdapter.js +78 -0
  23. package/dist/AlphaMissensePathogenicityAdapter/AlphaMissensePathogenicityAdapter.js.map +1 -0
  24. package/dist/AlphaMissensePathogenicityAdapter/configSchema.d.ts +13 -0
  25. package/dist/AlphaMissensePathogenicityAdapter/configSchema.js +16 -0
  26. package/dist/AlphaMissensePathogenicityAdapter/configSchema.js.map +1 -0
  27. package/dist/AlphaMissensePathogenicityAdapter/index.d.ts +2 -0
  28. package/dist/AlphaMissensePathogenicityAdapter/index.js +11 -0
  29. package/dist/AlphaMissensePathogenicityAdapter/index.js.map +1 -0
  30. package/dist/LaunchProteinView/components/AlphaFoldDBSearch.js +162 -13
  31. package/dist/LaunchProteinView/components/AlphaFoldDBSearch.js.map +1 -1
  32. package/dist/LaunchProteinView/components/AlphaFoldDBSearchStatus.js +8 -6
  33. package/dist/LaunchProteinView/components/AlphaFoldDBSearchStatus.js.map +1 -1
  34. package/dist/LaunchProteinView/components/HelpButton.js +6 -2
  35. package/dist/LaunchProteinView/components/HelpButton.js.map +1 -1
  36. package/dist/LaunchProteinView/components/HelpDialog.js +3 -1
  37. package/dist/LaunchProteinView/components/HelpDialog.js.map +1 -1
  38. package/dist/LaunchProteinView/components/LaunchProteinViewDialog.js +12 -4
  39. package/dist/LaunchProteinView/components/LaunchProteinViewDialog.js.map +1 -1
  40. package/dist/LaunchProteinView/components/MSATable.js +3 -1
  41. package/dist/LaunchProteinView/components/MSATable.js.map +1 -1
  42. package/dist/LaunchProteinView/components/ManualUniProtIDEntry.d.ts +8 -0
  43. package/dist/LaunchProteinView/components/ManualUniProtIDEntry.js +225 -0
  44. package/dist/LaunchProteinView/components/ManualUniProtIDEntry.js.map +1 -0
  45. package/dist/LaunchProteinView/components/TranscriptSelector.js +3 -1
  46. package/dist/LaunchProteinView/components/TranscriptSelector.js.map +1 -1
  47. package/dist/LaunchProteinView/components/UserProvidedStructure.js +19 -12
  48. package/dist/LaunchProteinView/components/UserProvidedStructure.js.map +1 -1
  49. package/dist/LaunchProteinView/components/calculateProteinSequence.js +5 -3
  50. package/dist/LaunchProteinView/components/calculateProteinSequence.js.map +1 -1
  51. package/dist/LaunchProteinView/components/useLocalStructureFileSequence.d.ts +1 -1
  52. package/dist/LaunchProteinView/components/useLocalStructureFileSequence.js +29 -9
  53. package/dist/LaunchProteinView/components/useLocalStructureFileSequence.js.map +1 -1
  54. package/dist/LaunchProteinView/components/useRemoteStructureFileSequence.d.ts +1 -1
  55. package/dist/LaunchProteinView/components/useRemoteStructureFileSequence.js +25 -8
  56. package/dist/LaunchProteinView/components/useRemoteStructureFileSequence.js.map +1 -1
  57. package/dist/LaunchProteinView/components/util.js +1 -1
  58. package/dist/LaunchProteinView/index.js +7 -3
  59. package/dist/LaunchProteinView/index.js.map +1 -1
  60. package/dist/ProteinView/{loadStructureFromData.d.ts → addStructureFromData.d.ts} +2 -2
  61. package/dist/ProteinView/{loadStructureFromData.js → addStructureFromData.js} +3 -8
  62. package/dist/ProteinView/addStructureFromData.js.map +1 -0
  63. package/dist/ProteinView/{loadStructureFromURL.d.ts → addStructureFromURL.d.ts} +2 -2
  64. package/dist/ProteinView/{loadStructureFromURL.js → addStructureFromURL.js} +11 -9
  65. package/dist/ProteinView/addStructureFromURL.js.map +1 -0
  66. package/dist/ProteinView/clearSelection.js +1 -1
  67. package/dist/ProteinView/clearSelection.js.map +1 -1
  68. package/dist/ProteinView/components/ProteinAlignment.d.ts +2 -2
  69. package/dist/ProteinView/components/ProteinAlignment.js +37 -26
  70. package/dist/ProteinView/components/ProteinAlignment.js.map +1 -1
  71. package/dist/ProteinView/components/ProteinAlignmentHelpButton.d.ts +2 -2
  72. package/dist/ProteinView/components/ProteinAlignmentHelpButton.js +6 -4
  73. package/dist/ProteinView/components/ProteinAlignmentHelpButton.js.map +1 -1
  74. package/dist/ProteinView/components/ProteinAlignmentHelpDialog.js +6 -5
  75. package/dist/ProteinView/components/ProteinAlignmentHelpDialog.js.map +1 -1
  76. package/dist/ProteinView/components/ProteinView.js +18 -60
  77. package/dist/ProteinView/components/ProteinView.js.map +1 -1
  78. package/dist/ProteinView/components/{Header.js → ProteinViewHeader.js} +29 -12
  79. package/dist/ProteinView/components/ProteinViewHeader.js.map +1 -0
  80. package/dist/ProteinView/components/SplitString.d.ts +4 -4
  81. package/dist/ProteinView/components/SplitString.js +3 -3
  82. package/dist/ProteinView/components/SplitString.js.map +1 -1
  83. package/dist/ProteinView/genomeToProtein.d.ts +2 -2
  84. package/dist/ProteinView/genomeToProtein.js +4 -5
  85. package/dist/ProteinView/genomeToProtein.js.map +1 -1
  86. package/dist/ProteinView/highlightResidue.js +2 -2
  87. package/dist/ProteinView/highlightResidue.js.map +1 -1
  88. package/dist/ProteinView/launchRemotePairwiseAlignment.d.ts +2 -5
  89. package/dist/ProteinView/launchRemotePairwiseAlignment.js +7 -3
  90. package/dist/ProteinView/launchRemotePairwiseAlignment.js.map +1 -1
  91. package/dist/ProteinView/model.d.ts +492 -160
  92. package/dist/ProteinView/model.js +62 -246
  93. package/dist/ProteinView/model.js.map +1 -1
  94. package/dist/ProteinView/proteinToGenomeMapping.d.ts +6 -6
  95. package/dist/ProteinView/proteinToGenomeMapping.js +29 -28
  96. package/dist/ProteinView/proteinToGenomeMapping.js.map +1 -1
  97. package/dist/ProteinView/selectResidue.js +1 -1
  98. package/dist/ProteinView/selectResidue.js.map +1 -1
  99. package/dist/ProteinView/structureModel.d.ts +183 -0
  100. package/dist/ProteinView/structureModel.js +407 -0
  101. package/dist/ProteinView/structureModel.js.map +1 -0
  102. package/dist/ProteinView/useProteinView.d.ts +1 -4
  103. package/dist/ProteinView/useProteinView.js +3 -15
  104. package/dist/ProteinView/useProteinView.js.map +1 -1
  105. package/dist/ProteinView/util.d.ts +3 -3
  106. package/dist/ProteinView/util.js +8 -6
  107. package/dist/ProteinView/util.js.map +1 -1
  108. package/dist/UniProtVariationAdapter/UniProtVariationAdapter.d.ts +15 -0
  109. package/dist/UniProtVariationAdapter/UniProtVariationAdapter.js +55 -0
  110. package/dist/UniProtVariationAdapter/UniProtVariationAdapter.js.map +1 -0
  111. package/dist/UniProtVariationAdapter/configSchema.d.ts +17 -0
  112. package/dist/UniProtVariationAdapter/configSchema.js +20 -0
  113. package/dist/UniProtVariationAdapter/configSchema.js.map +1 -0
  114. package/dist/UniProtVariationAdapter/index.d.ts +2 -0
  115. package/dist/UniProtVariationAdapter/index.js +11 -0
  116. package/dist/UniProtVariationAdapter/index.js.map +1 -0
  117. package/dist/genomeToTranscriptMapping.d.ts +2 -2
  118. package/dist/genomeToTranscriptMapping.js +3 -3
  119. package/dist/genomeToTranscriptMapping.js.map +1 -1
  120. package/dist/index.js +6 -0
  121. package/dist/index.js.map +1 -1
  122. package/dist/jbrowse-plugin-protein3d.umd.production.min.js +2506 -1658
  123. package/dist/jbrowse-plugin-protein3d.umd.production.min.js.map +4 -4
  124. package/dist/mappings.d.ts +12 -10
  125. package/dist/mappings.js +7 -7
  126. package/dist/mappings.js.map +1 -1
  127. package/dist/mappings.test.js +7 -5
  128. package/dist/mappings.test.js.map +1 -1
  129. package/dist/test_data/gene.d.ts +577 -64
  130. package/dist/test_data/gene.js +1 -1
  131. package/dist/test_data/gene.js.map +1 -1
  132. package/package.json +20 -19
  133. package/src/AddHighlightModel/GenomeMouseoverHighlight.tsx +4 -17
  134. package/src/AddHighlightModel/HighlightComponents.tsx +1 -3
  135. package/src/AddHighlightModel/ProteinToGenomeClickHighlight.tsx +17 -14
  136. package/src/AddHighlightModel/ProteinToGenomeHoverHighlight.tsx +18 -17
  137. package/src/AddHighlightModel/util.ts +1 -1
  138. package/src/AlphaFoldConfidenceAdapter/AlphaFoldConfidenceAdapter.ts +63 -0
  139. package/src/AlphaFoldConfidenceAdapter/configSchema.ts +21 -0
  140. package/src/AlphaFoldConfidenceAdapter/index.ts +19 -0
  141. package/src/AlphaMissensePathogenicityAdapter/AlphaMissensePathogenicityAdapter.ts +109 -0
  142. package/src/AlphaMissensePathogenicityAdapter/configSchema.ts +21 -0
  143. package/src/AlphaMissensePathogenicityAdapter/index.ts +19 -0
  144. package/src/LaunchProteinView/components/AlphaFoldDBSearch.tsx +173 -12
  145. package/src/LaunchProteinView/components/AlphaFoldDBSearchStatus.tsx +8 -6
  146. package/src/LaunchProteinView/components/HelpButton.tsx +10 -2
  147. package/src/LaunchProteinView/components/HelpDialog.tsx +6 -1
  148. package/src/LaunchProteinView/components/LaunchProteinViewDialog.tsx +20 -4
  149. package/src/LaunchProteinView/components/MSATable.tsx +3 -1
  150. package/src/LaunchProteinView/components/ManualUniProtIDEntry.tsx +332 -0
  151. package/src/LaunchProteinView/components/TranscriptSelector.tsx +9 -7
  152. package/src/LaunchProteinView/components/UserProvidedStructure.tsx +18 -13
  153. package/src/LaunchProteinView/components/calculateProteinSequence.ts +6 -4
  154. package/src/LaunchProteinView/components/useLocalStructureFileSequence.ts +28 -9
  155. package/src/LaunchProteinView/components/useRemoteStructureFileSequence.ts +23 -8
  156. package/src/LaunchProteinView/components/util.ts +1 -1
  157. package/src/LaunchProteinView/index.ts +36 -26
  158. package/src/ProteinView/{loadStructureFromData.ts → addStructureFromData.ts} +2 -8
  159. package/src/ProteinView/{loadStructureFromURL.ts → addStructureFromURL.ts} +11 -11
  160. package/src/ProteinView/clearSelection.ts +1 -1
  161. package/src/ProteinView/components/ProteinAlignment.tsx +51 -35
  162. package/src/ProteinView/components/ProteinAlignmentHelpButton.tsx +4 -4
  163. package/src/ProteinView/components/ProteinAlignmentHelpDialog.tsx +15 -11
  164. package/src/ProteinView/components/ProteinView.tsx +22 -82
  165. package/src/ProteinView/components/{Header.tsx → ProteinViewHeader.tsx} +44 -23
  166. package/src/ProteinView/components/SplitString.tsx +8 -8
  167. package/src/ProteinView/genomeToProtein.ts +5 -9
  168. package/src/ProteinView/highlightResidue.ts +2 -2
  169. package/src/ProteinView/launchRemotePairwiseAlignment.ts +6 -3
  170. package/src/ProteinView/model.ts +75 -287
  171. package/src/ProteinView/proteinToGenomeMapping.ts +40 -38
  172. package/src/ProteinView/selectResidue.ts +1 -1
  173. package/src/ProteinView/structureModel.ts +512 -0
  174. package/src/ProteinView/useProteinView.ts +2 -19
  175. package/src/ProteinView/util.ts +20 -9
  176. package/src/UniProtVariationAdapter/UniProtVariationAdapter.ts +99 -0
  177. package/src/UniProtVariationAdapter/configSchema.ts +25 -0
  178. package/src/UniProtVariationAdapter/index.ts +17 -0
  179. package/src/__snapshots__/mappings.test.ts.snap +224 -224
  180. package/src/genomeToTranscriptMapping.ts +9 -9
  181. package/src/index.ts +6 -0
  182. package/src/mappings.test.ts +7 -5
  183. package/src/mappings.ts +25 -23
  184. package/src/test_data/gene.ts +3 -3
  185. package/dist/ProteinView/components/Header.js.map +0 -1
  186. package/dist/ProteinView/loadStructureFromData.js.map +0 -1
  187. package/dist/ProteinView/loadStructureFromURL.js.map +0 -1
  188. package/dist/ProteinView/useProteinViewClickBehavior.d.ts +0 -8
  189. package/dist/ProteinView/useProteinViewClickBehavior.js +0 -34
  190. package/dist/ProteinView/useProteinViewClickBehavior.js.map +0 -1
  191. package/dist/ProteinView/useProteinViewHoverBehavior.d.ts +0 -6
  192. package/dist/ProteinView/useProteinViewHoverBehavior.js +0 -31
  193. package/dist/ProteinView/useProteinViewHoverBehavior.js.map +0 -1
  194. package/src/ProteinView/useProteinViewClickBehavior.ts +0 -48
  195. package/src/ProteinView/useProteinViewHoverBehavior.ts +0 -44
  196. /package/dist/ProteinView/components/{Header.d.ts → ProteinViewHeader.d.ts} +0 -0
@@ -0,0 +1,332 @@
1
+ import React, { useEffect, useState } from 'react'
2
+ import { observer } from 'mobx-react'
3
+ import {
4
+ Button,
5
+ DialogActions,
6
+ DialogContent,
7
+ TextField,
8
+ Typography,
9
+ } from '@mui/material'
10
+ import { makeStyles } from 'tss-react/mui'
11
+ import {
12
+ AbstractTrackModel,
13
+ Feature,
14
+ getContainingView,
15
+ getSession,
16
+ isSessionWithAddTracks,
17
+ } from '@jbrowse/core/util'
18
+ import { ErrorMessage, LoadingEllipses } from '@jbrowse/core/ui'
19
+ import { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
20
+
21
+ // locals
22
+ import {
23
+ getId,
24
+ getGeneDisplayName,
25
+ getTranscriptDisplayName,
26
+ getTranscriptFeatures,
27
+ } from './util'
28
+
29
+ // components
30
+ import TranscriptSelector from './TranscriptSelector'
31
+ import AlphaFoldDBSearchStatus from './AlphaFoldDBSearchStatus'
32
+
33
+ // hooks
34
+ import useRemoteStructureFileSequence from './useRemoteStructureFileSequence'
35
+ import useIsoformProteinSequences from './useIsoformProteinSequences'
36
+
37
+ const useStyles = makeStyles()(theme => ({
38
+ dialogContent: {
39
+ marginTop: theme.spacing(6),
40
+ width: '80em',
41
+ },
42
+ }))
43
+
44
+ const ManualUniProtIDEntry = observer(function ({
45
+ feature,
46
+ model,
47
+ handleClose,
48
+ }: {
49
+ feature: Feature
50
+ model: AbstractTrackModel
51
+ handleClose: () => void
52
+ }) {
53
+ const { classes } = useStyles()
54
+ const session = getSession(model)
55
+
56
+ // check if we are looking at a 'two-level' or 'three-level' feature by
57
+ // finding exon/CDS subfeatures. we want to select from transcript names
58
+ const options = getTranscriptFeatures(feature)
59
+ const [userSelection, setUserSelection] = useState<string>()
60
+ const view = getContainingView(model) as LinearGenomeViewModel
61
+ const selectedTranscript = options.find(val => getId(val) === userSelection)
62
+ const {
63
+ isoformSequences,
64
+ isLoading: isIsoformProteinSequencesLoading,
65
+ error: isoformProteinSequencesError,
66
+ } = useIsoformProteinSequences({
67
+ feature,
68
+ view,
69
+ })
70
+ const userSelectedProteinSequence = isoformSequences?.[userSelection ?? '']
71
+ const [uniprotId, setUniprotId] = useState('')
72
+ const url = uniprotId
73
+ ? `https://alphafold.ebi.ac.uk/files/AF-${uniprotId}-F1-model_v4.cif`
74
+ : undefined
75
+ const {
76
+ sequences: structureSequences,
77
+ isLoading: isRemoteStructureSequenceLoading,
78
+ error: remoteStructureSequenceError,
79
+ } = useRemoteStructureFileSequence({ url })
80
+ const e = isoformProteinSequencesError || remoteStructureSequenceError
81
+
82
+ const structureSequence = structureSequences?.[0]
83
+ useEffect(() => {
84
+ if (isoformSequences !== undefined) {
85
+ const ret =
86
+ options.find(
87
+ f =>
88
+ isoformSequences[f.id()]?.seq.replaceAll('*', '') ==
89
+ structureSequence,
90
+ ) ?? options.find(f => !!isoformSequences[f.id()])
91
+ setUserSelection(ret?.id())
92
+ }
93
+ }, [options, structureSequence, isoformSequences])
94
+
95
+ return (
96
+ <>
97
+ <DialogContent className={classes.dialogContent}>
98
+ {e ? <ErrorMessage error={e} /> : null}
99
+ <Typography>Manually enter a UniProt ID</Typography>
100
+ {isRemoteStructureSequenceLoading ? (
101
+ <LoadingEllipses
102
+ variant="h6"
103
+ message="Loading sequence from remote structure file"
104
+ />
105
+ ) : null}
106
+
107
+ <TextField
108
+ label="UniProt ID"
109
+ value={uniprotId}
110
+ onChange={event => {
111
+ setUniprotId(event.target.value)
112
+ }}
113
+ />
114
+ {isIsoformProteinSequencesLoading ? (
115
+ <LoadingEllipses
116
+ variant="h6"
117
+ message="Loading protein sequences from transcript isoforms"
118
+ />
119
+ ) : null}
120
+ {isoformSequences && structureSequence && selectedTranscript ? (
121
+ <>
122
+ <TranscriptSelector
123
+ val={userSelection ?? ''}
124
+ setVal={setUserSelection}
125
+ structureSequence={structureSequence}
126
+ feature={feature}
127
+ isoforms={options}
128
+ isoformSequences={isoformSequences}
129
+ />
130
+ <AlphaFoldDBSearchStatus
131
+ uniprotId={uniprotId}
132
+ selectedTranscript={selectedTranscript}
133
+ structureSequence={structureSequence}
134
+ isoformSequences={isoformSequences}
135
+ />
136
+ </>
137
+ ) : null}
138
+ </DialogContent>
139
+ <DialogActions>
140
+ <Button
141
+ variant="contained"
142
+ color="secondary"
143
+ onClick={() => {
144
+ handleClose()
145
+ }}
146
+ >
147
+ Cancel
148
+ </Button>
149
+ <Button
150
+ variant="contained"
151
+ color="primary"
152
+ disabled={
153
+ !uniprotId || !userSelectedProteinSequence || !selectedTranscript
154
+ }
155
+ onClick={() => {
156
+ session.addView('ProteinView', {
157
+ type: 'ProteinView',
158
+ isFloating: true,
159
+ structures: [
160
+ {
161
+ url,
162
+ userProvidedTranscriptSequence:
163
+ userSelectedProteinSequence?.seq,
164
+ feature: selectedTranscript?.toJSON(),
165
+ connectedViewId: view.id,
166
+ },
167
+ ],
168
+ displayName: [
169
+ 'Protein view',
170
+ uniprotId,
171
+ getGeneDisplayName(feature),
172
+ getTranscriptDisplayName(selectedTranscript),
173
+ ].join(' - '),
174
+ })
175
+ handleClose()
176
+ }}
177
+ >
178
+ Launch 3-D protein structure view
179
+ </Button>
180
+ <Button
181
+ variant="contained"
182
+ disabled={
183
+ !uniprotId || !userSelectedProteinSequence || !selectedTranscript
184
+ }
185
+ onClick={() => {
186
+ if (uniprotId && isSessionWithAddTracks(session)) {
187
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
188
+ ;(async () => {
189
+ try {
190
+ session.addTemporaryAssembly?.({
191
+ name: uniprotId,
192
+ sequence: {
193
+ type: 'ReferenceSequenceTrack',
194
+ trackId: `${uniprotId}-ReferenceSequenceTrack`,
195
+ sequenceType: 'pep',
196
+ adapter: {
197
+ type: 'UnindexedFastaAdapter',
198
+ rewriteRefNames: "jexl:split(refName,'|')[1]",
199
+ fastaLocation: {
200
+ uri: `https://rest.uniprot.org/uniprotkb/${uniprotId}.fasta`,
201
+ },
202
+ },
203
+ },
204
+ })
205
+ const url = `https://rest.uniprot.org/uniprotkb/${uniprotId}.gff`
206
+ const res = await fetch(url)
207
+ if (!res.ok) {
208
+ throw new Error(`HTTP ${res.status} fetching ${url}`)
209
+ }
210
+ const data = await res.text()
211
+
212
+ const types = [
213
+ ...new Set(
214
+ data
215
+ .split('\n')
216
+ .filter(f => !f.startsWith('#'))
217
+ .map(f => f.trim())
218
+ .filter(f => !!f)
219
+ .map(f => f.split('\t')[2]),
220
+ ),
221
+ ]
222
+ types.forEach(type => {
223
+ const s = `${uniprotId}-${type}`
224
+ session.addTrackConf({
225
+ type: 'FeatureTrack',
226
+ trackId: s,
227
+ name: type,
228
+ adapter: {
229
+ type: 'Gff3Adapter',
230
+ gffLocation: {
231
+ uri: `https://rest.uniprot.org/uniprotkb/${uniprotId}.gff`,
232
+ },
233
+ },
234
+ assemblyNames: [uniprotId],
235
+ displays: [
236
+ {
237
+ displayId: `${type}-LinearBasicDisplay`,
238
+ type: 'LinearBasicDisplay',
239
+ jexlFilters: [`get(feature,'type')=='${type}'`],
240
+ },
241
+ ],
242
+ })
243
+ })
244
+ session.addTrackConf({
245
+ type: 'FeatureTrack',
246
+ trackId: 'Antigen',
247
+ name: 'Antigen',
248
+ adapter: {
249
+ type: 'Gff3Adapter',
250
+ gffLocation: {
251
+ uri: `https://www.ebi.ac.uk/proteins/api/antigen/${uniprotId}?format=gff`,
252
+ },
253
+ },
254
+ assemblyNames: [uniprotId],
255
+ })
256
+ session.addTrackConf({
257
+ type: 'FeatureTrack',
258
+ trackId: 'Variation',
259
+ name: 'Variation',
260
+ adapter: {
261
+ type: 'UniProtVariationAdapter',
262
+ location: {
263
+ uri: `https://www.ebi.ac.uk/proteins/api/variation/${uniprotId}.json`,
264
+ },
265
+ },
266
+ assemblyNames: [uniprotId],
267
+ })
268
+ session.addTrackConf({
269
+ type: 'QuantitativeTrack',
270
+ trackId: 'AlphaFold confidence',
271
+ name: 'AlphaFold confidence',
272
+ adapter: {
273
+ type: 'AlphaFoldConfidenceAdapter',
274
+ location: {
275
+ uri: `https://alphafold.ebi.ac.uk/files/AF-${uniprotId}-F1-confidence_v4.json`,
276
+ },
277
+ },
278
+ assemblyNames: [uniprotId],
279
+ })
280
+ session.addTrackConf({
281
+ type: 'MultiQuantitativeTrack',
282
+ trackId: 'AlphaMissense scores',
283
+ name: 'AlphaMissense scores',
284
+ assemblyNames: [uniprotId],
285
+ adapter: {
286
+ type: 'AlphaMissensePathogenicityAdapter',
287
+ location: {
288
+ uri: `https://alphafold.ebi.ac.uk/files/AF-${uniprotId}-F1-aa-substitutions.csv`,
289
+ },
290
+ },
291
+ displays: [
292
+ {
293
+ type: 'MultiLinearWiggleDisplay',
294
+ displayId:
295
+ 'AlphaMissense scores-MultiLinearWiggleDisplay',
296
+ defaultRendering: 'multirowdensity',
297
+ renderers: {
298
+ MultiDensityRenderer: {
299
+ type: 'MultiDensityRenderer',
300
+ bicolorPivotValue: 0.5,
301
+ },
302
+ },
303
+ },
304
+ ],
305
+ })
306
+ const view = session.addView('LinearGenomeView', {
307
+ type: 'LinearGenomeView',
308
+ displayName: [
309
+ 'Protein view',
310
+ uniprotId,
311
+ getGeneDisplayName(feature),
312
+ getTranscriptDisplayName(selectedTranscript),
313
+ ].join(' - '),
314
+ }) as LinearGenomeViewModel
315
+ await view.navToLocString(uniprotId, uniprotId)
316
+ } catch (e) {
317
+ console.error(e)
318
+ session.notifyError(`${e}`, e)
319
+ }
320
+ })()
321
+ }
322
+ handleClose()
323
+ }}
324
+ >
325
+ Launch linear protein annotation view
326
+ </Button>
327
+ </DialogActions>
328
+ </>
329
+ )
330
+ })
331
+
332
+ export default ManualUniProtIDEntry
@@ -31,7 +31,9 @@ export default function TranscriptSelector({
31
31
  return (
32
32
  <TextField2
33
33
  value={val}
34
- onChange={event => setVal(event.target.value)}
34
+ onChange={event => {
35
+ setVal(event.target.value)
36
+ }}
35
37
  label="Choose transcript isoform"
36
38
  select
37
39
  >
@@ -39,13 +41,13 @@ export default function TranscriptSelector({
39
41
  .filter(f => !!isoformSequences[f.id()])
40
42
  .filter(
41
43
  f =>
42
- isoformSequences[f.id()].seq.replaceAll('*', '') ===
44
+ isoformSequences[f.id()]!.seq.replaceAll('*', '') ===
43
45
  structureSequence,
44
46
  )
45
47
  .map(f => (
46
48
  <MenuItem value={f.id()} key={f.id()}>
47
49
  {getGeneDisplayName(feature)} - {getTranscriptDisplayName(f)} (
48
- {isoformSequences[f.id()].seq.length}aa) (matches structure
50
+ {isoformSequences[f.id()]!.seq.length}aa) (matches structure
49
51
  residues)
50
52
  </MenuItem>
51
53
  ))}
@@ -53,18 +55,18 @@ export default function TranscriptSelector({
53
55
  .filter(f => !!isoformSequences[f.id()])
54
56
  .filter(
55
57
  f =>
56
- isoformSequences[f.id()].seq.replaceAll('*', '') !==
58
+ isoformSequences[f.id()]!.seq.replaceAll('*', '') !==
57
59
  structureSequence,
58
60
  )
59
61
  .sort(
60
62
  (a, b) =>
61
- isoformSequences[b.id()].seq.length -
62
- isoformSequences[a.id()].seq.length,
63
+ isoformSequences[b.id()]!.seq.length -
64
+ isoformSequences[a.id()]!.seq.length,
63
65
  )
64
66
  .map(f => (
65
67
  <MenuItem value={f.id()} key={f.id()}>
66
68
  {getGeneDisplayName(feature)} - {getTranscriptDisplayName(f)} (
67
- {isoformSequences[f.id()].seq.length}aa)
69
+ {isoformSequences[f.id()]!.seq.length}aa)
68
70
  </MenuItem>
69
71
  ))}
70
72
  {isoforms
@@ -96,16 +96,15 @@ const UserProvidedStructure = observer(function ({
96
96
  view,
97
97
  })
98
98
  const protein = isoformSequences?.[userSelection ?? '']
99
- const { seq: structureSequence1, error: error3 } =
99
+ const { sequences: structureSequences1, error: error3 } =
100
100
  useLocalStructureFileSequence({ file })
101
101
 
102
- const { seq: structureSequence2, error: error4 } =
102
+ const { sequences: structureSequences2, error: error4 } =
103
103
  useRemoteStructureFileSequence({ url: structureURL })
104
104
  const structureName =
105
- file?.name ??
106
- structureURL.slice(structureURL.lastIndexOf('/') + 1) ??
107
- 'structureSequence'
108
- const structureSequence = structureSequence1 ?? structureSequence2
105
+ file?.name ?? structureURL.slice(structureURL.lastIndexOf('/') + 1)
106
+ const structureSequences = structureSequences1 ?? structureSequences2
107
+ const structureSequence = structureSequences?.[0]
109
108
 
110
109
  useEffect(() => {
111
110
  if (isoformSequences !== undefined) {
@@ -134,7 +133,9 @@ const UserProvidedStructure = observer(function ({
134
133
  <FormControl component="fieldset">
135
134
  <RadioGroup
136
135
  value={choice}
137
- onChange={event => setChoice(event.target.value)}
136
+ onChange={event => {
137
+ setChoice(event.target.value)
138
+ }}
138
139
  >
139
140
  <FormControlLabel value="url" control={<Radio />} label="URL" />
140
141
  <FormControlLabel value="file" control={<Radio />} label="File" />
@@ -153,7 +154,9 @@ const UserProvidedStructure = observer(function ({
153
154
  <TextField
154
155
  label="URL"
155
156
  value={structureURL}
156
- onChange={event => setStructureURL(event.target.value)}
157
+ onChange={event => {
158
+ setStructureURL(event.target.value)
159
+ }}
157
160
  />
158
161
  </div>
159
162
  ) : null}
@@ -168,7 +171,7 @@ const UserProvidedStructure = observer(function ({
168
171
  type="file"
169
172
  hidden
170
173
  onChange={({ target }) => {
171
- const file = target?.files?.[0]
174
+ const file = target.files?.[0]
172
175
  if (file) {
173
176
  setFile(file)
174
177
  }
@@ -205,9 +208,9 @@ const UserProvidedStructure = observer(function ({
205
208
  <Button
206
209
  variant="contained"
207
210
  color="primary"
208
- onClick={() =>
211
+ onClick={() => {
209
212
  setShowAllProteinSequences(!showAllProteinSequences)
210
- }
213
+ }}
211
214
  >
212
215
  {showAllProteinSequences
213
216
  ? 'Hide all isoform protein sequences'
@@ -233,7 +236,9 @@ const UserProvidedStructure = observer(function ({
233
236
  <Button
234
237
  variant="contained"
235
238
  color="secondary"
236
- onClick={() => handleClose()}
239
+ onClick={() => {
240
+ handleClose()
241
+ }}
237
242
  >
238
243
  Cancel
239
244
  </Button>
@@ -262,7 +267,7 @@ const UserProvidedStructure = observer(function ({
262
267
  })()
263
268
  }}
264
269
  >
265
- Submit
270
+ Launch 3-D protein structure view
266
271
  </Button>
267
272
  </DialogActions>
268
273
  </>
@@ -30,7 +30,7 @@ export function calculateProteinSequence({
30
30
  let protein = ''
31
31
  for (let i = 0; i < str.length; i += 3) {
32
32
  // use & symbol for undefined codon, or partial slice
33
- protein += codonTable[str.slice(i, i + 3)] || '&'
33
+ protein += codonTable[str.slice(i, i + 3)] ?? '&'
34
34
  }
35
35
  return protein
36
36
  }
@@ -53,7 +53,7 @@ function getItemId(feat: Feat) {
53
53
  // filters if successive elements share same start/end
54
54
  export function dedupe(list: Feat[]) {
55
55
  return list.filter(
56
- (item, pos, ary) => !pos || getItemId(item) !== getItemId(ary[pos - 1]),
56
+ (item, pos, ary) => !pos || getItemId(item) !== getItemId(ary[pos - 1]!),
57
57
  )
58
58
  }
59
59
 
@@ -102,8 +102,10 @@ export async function fetchProteinSeq({
102
102
  const refName = feature.get('refName')
103
103
  const session = getSession(view)
104
104
  const { assemblyManager, rpcManager } = session
105
- const [assemblyName] = view?.assemblyNames ?? []
106
- const assembly = await assemblyManager.waitForAssembly(assemblyName)
105
+ const assemblyName = view?.assemblyNames?.[0]
106
+ const assembly = assemblyName
107
+ ? await assemblyManager.waitForAssembly(assemblyName)
108
+ : undefined
107
109
  if (!assembly) {
108
110
  throw new Error('assembly not found')
109
111
  }
@@ -1,7 +1,7 @@
1
1
  import { useEffect, useState } from 'react'
2
2
  import { createPluginUI } from 'molstar/lib/mol-plugin-ui'
3
3
  import { renderReact18 } from 'molstar/lib/mol-plugin-ui/react18'
4
- import { loadStructureFromData } from '../../ProteinView/loadStructureFromData'
4
+ import { addStructureFromData } from '../../ProteinView/addStructureFromData'
5
5
 
6
6
  async function structureFileSequenceFetcher(
7
7
  file: File,
@@ -12,11 +12,26 @@ async function structureFileSequenceFetcher(
12
12
  target: ret,
13
13
  render: renderReact18,
14
14
  })
15
- const data = await file.text()
16
- const { seq } = await loadStructureFromData({ data, plugin: p, format })
17
- p.unmount()
18
- ret.remove()
19
- return seq
15
+
16
+ try {
17
+ const { model } = await addStructureFromData({
18
+ data: await file.text(),
19
+ plugin: p,
20
+ format,
21
+ })
22
+ return model.obj?.data.sequence.sequences.map(s => {
23
+ let seq = ''
24
+ const arr = s.sequence.label.toArray()
25
+ // eslint-disable-next-line unicorn/no-for-loop,@typescript-eslint/prefer-for-of
26
+ for (let i = 0; i < arr.length; i++) {
27
+ seq += arr[i]!
28
+ }
29
+ return seq
30
+ })
31
+ } finally {
32
+ p.unmount()
33
+ ret.remove()
34
+ }
20
35
  }
21
36
 
22
37
  export default function useLocalStructureFileSequence({
@@ -26,7 +41,7 @@ export default function useLocalStructureFileSequence({
26
41
  }) {
27
42
  const [error, setError] = useState<unknown>()
28
43
  const [isLoading, setLoading] = useState(false)
29
- const [seq, setSeq] = useState<string>()
44
+ const [sequences, setSequences] = useState<string[]>()
30
45
  useEffect(() => {
31
46
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
32
47
  ;(async () => {
@@ -39,7 +54,11 @@ export default function useLocalStructureFileSequence({
39
54
  file,
40
55
  (ext === 'cif' ? 'mmcif' : ext) as 'pdb' | 'mmcif',
41
56
  )
42
- setSeq(seq)
57
+ if (seq) {
58
+ setSequences(seq)
59
+ } else {
60
+ throw new Error('no sequences detected in file')
61
+ }
43
62
  }
44
63
  } catch (e) {
45
64
  console.error(e)
@@ -49,5 +68,5 @@ export default function useLocalStructureFileSequence({
49
68
  }
50
69
  })()
51
70
  }, [file])
52
- return { error, isLoading, seq }
71
+ return { error, isLoading, sequences }
53
72
  }
@@ -1,7 +1,7 @@
1
1
  import { useEffect, useState } from 'react'
2
2
  import { createPluginUI } from 'molstar/lib/mol-plugin-ui'
3
3
  import { renderReact18 } from 'molstar/lib/mol-plugin-ui/react18'
4
- import { loadStructureFromURL } from '../../ProteinView/loadStructureFromURL'
4
+ import { addStructureFromURL } from '../../ProteinView/addStructureFromURL'
5
5
 
6
6
  async function structureFileSequenceFetcher(url: string) {
7
7
  const ret = document.createElement('div')
@@ -9,10 +9,21 @@ async function structureFileSequenceFetcher(url: string) {
9
9
  target: ret,
10
10
  render: renderReact18,
11
11
  })
12
- const { seq } = await loadStructureFromURL({ url, plugin: p })
13
- p.unmount()
14
- ret.remove()
15
- return seq
12
+ try {
13
+ const { model } = await addStructureFromURL({ url, plugin: p })
14
+ return model.obj?.data.sequence.sequences.map(s => {
15
+ let seq = ''
16
+ const arr = s.sequence.label.toArray()
17
+ // eslint-disable-next-line unicorn/no-for-loop,@typescript-eslint/prefer-for-of
18
+ for (let i = 0; i < arr.length; i++) {
19
+ seq += arr[i]!
20
+ }
21
+ return seq
22
+ })
23
+ } finally {
24
+ p.unmount()
25
+ ret.remove()
26
+ }
16
27
  }
17
28
 
18
29
  export default function useRemoteStructureFileSequence({
@@ -22,7 +33,7 @@ export default function useRemoteStructureFileSequence({
22
33
  }) {
23
34
  const [error, setError] = useState<unknown>()
24
35
  const [isLoading, setLoading] = useState(false)
25
- const [seq, setSeq] = useState<string>()
36
+ const [sequences, setSequences] = useState<string[]>()
26
37
  useEffect(() => {
27
38
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
28
39
  ;(async () => {
@@ -30,7 +41,11 @@ export default function useRemoteStructureFileSequence({
30
41
  if (url) {
31
42
  setLoading(true)
32
43
  const seq = await structureFileSequenceFetcher(url)
33
- setSeq(seq)
44
+ if (seq) {
45
+ setSequences(seq)
46
+ } else {
47
+ throw new Error('no sequences detected in file')
48
+ }
34
49
  }
35
50
  } catch (e) {
36
51
  console.error(e)
@@ -40,5 +55,5 @@ export default function useRemoteStructureFileSequence({
40
55
  }
41
56
  })()
42
57
  }, [url])
43
- return { error, isLoading, seq }
58
+ return { error, isLoading, sequences }
44
59
  }
@@ -12,7 +12,7 @@ export function getTranscriptFeatures(feature: Feature) {
12
12
  }
13
13
 
14
14
  export function stripTrailingVersion(s?: string) {
15
- return s?.replace(/\.[^/.]+$/, '')
15
+ return s?.replace(/\.[^./]+$/, '')
16
16
  }
17
17
 
18
18
  export function z(n: number) {