@apollo-annotation/jbrowse-plugin-apollo 0.1.21 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.esm.js +431 -570
- package/dist/index.esm.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.development.js +439 -578
- package/dist/jbrowse-plugin-apollo.cjs.development.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.production.min.js +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.production.min.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.umd.development.js +11064 -1091
- package/dist/jbrowse-plugin-apollo.umd.development.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.umd.production.min.js +1 -1
- package/dist/jbrowse-plugin-apollo.umd.production.min.js.map +1 -1
- package/package.json +4 -5
- package/src/ApolloInternetAccount/components/AuthTypeSelector.tsx +4 -2
- package/src/ApolloInternetAccount/configSchema.ts +1 -1
- package/src/ApolloInternetAccount/model.ts +5 -10
- package/src/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.ts +1 -1
- package/src/ApolloSixFrameRenderer/components/ApolloRendering.tsx +4 -5
- package/src/BackendDrivers/DesktopFileDriver.ts +3 -2
- package/src/FeatureDetailsWidget/Attributes.tsx +1 -6
- package/src/FeatureDetailsWidget/NumberTextField.tsx +1 -0
- package/src/FeatureDetailsWidget/StringTextField.tsx +1 -0
- package/src/FeatureDetailsWidget/TranscriptBasic.tsx +131 -382
- package/src/FeatureDetailsWidget/TranscriptSequence.tsx +209 -284
- package/src/FeatureDetailsWidget/model.ts +4 -4
- package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +1 -0
- package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +25 -3
- package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +95 -32
- package/src/LinearApolloDisplay/stateModel/base.ts +5 -3
- package/src/LinearApolloDisplay/stateModel/index.ts +1 -1
- package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +1 -1
- package/src/LinearApolloDisplay/stateModel/rendering.ts +1 -1
- package/src/OntologyManager/OntologyStore/fulltext.ts +5 -2
- package/src/OntologyManager/OntologyStore/index.ts +25 -22
- package/src/OntologyManager/OntologyStore/indexeddb-storage.ts +8 -3
- package/src/OntologyManager/index.ts +31 -8
- package/src/SixFrameFeatureDisplay/stateModel.ts +1 -1
- package/src/TabularEditor/HybridGrid/HybridGrid.tsx +1 -0
- package/src/TabularEditor/HybridGrid/NumberCell.tsx +1 -0
- package/src/TabularEditor/model.ts +1 -1
- package/src/components/AddChildFeature.tsx +1 -0
- package/src/components/AddFeature.tsx +1 -1
- package/src/components/AddRefSeqAliases.tsx +1 -0
- package/src/components/CopyFeature.tsx +1 -0
- package/src/components/DeleteAssembly.tsx +1 -0
- package/src/components/DeleteFeature.tsx +1 -0
- package/src/components/LogOut.tsx +2 -1
- package/src/components/ManageChecks.tsx +1 -1
- package/src/components/ManageUsers.tsx +2 -1
- package/src/components/OntologyTermAutocomplete.tsx +7 -9
- package/src/components/OntologyTermMultiSelect.tsx +2 -1
- package/src/components/OpenLocalFile.tsx +3 -1
- package/src/components/ViewChangeLog.tsx +1 -0
- package/src/components/ViewCheckResults.tsx +1 -0
- package/src/config.ts +5 -0
- package/src/extensions/annotationFromPileup.ts +1 -1
- package/src/makeDisplayComponent.tsx +28 -7
- package/src/session/ClientDataStore.ts +1 -1
- package/src/session/session.ts +2 -1
|
@@ -3,71 +3,23 @@ import {
|
|
|
3
3
|
LocationEndChange,
|
|
4
4
|
LocationStartChange,
|
|
5
5
|
} from '@apollo-annotation/shared'
|
|
6
|
-
import { AbstractSessionModel, revcom } from '@jbrowse/core/util'
|
|
7
|
-
import {
|
|
6
|
+
import { AbstractSessionModel, getFrame, revcom } from '@jbrowse/core/util'
|
|
7
|
+
import {
|
|
8
|
+
Paper,
|
|
9
|
+
Typography,
|
|
10
|
+
Table,
|
|
11
|
+
TableBody,
|
|
12
|
+
TableCell,
|
|
13
|
+
TableContainer,
|
|
14
|
+
TableRow,
|
|
15
|
+
useTheme,
|
|
16
|
+
} from '@mui/material'
|
|
8
17
|
import { observer } from 'mobx-react'
|
|
9
18
|
import React from 'react'
|
|
10
19
|
|
|
11
20
|
import { ApolloSessionModel } from '../session'
|
|
12
|
-
import { CDSInfo } from './TranscriptSequence'
|
|
13
21
|
import { NumberTextField } from './NumberTextField'
|
|
14
22
|
|
|
15
|
-
interface ExonInfo {
|
|
16
|
-
min: number
|
|
17
|
-
max: number
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Get single feature by featureId
|
|
22
|
-
* @param feature -
|
|
23
|
-
* @param featureId -
|
|
24
|
-
* @returns
|
|
25
|
-
*/
|
|
26
|
-
function getFeatureFromId(
|
|
27
|
-
feature: AnnotationFeature,
|
|
28
|
-
featureId: string,
|
|
29
|
-
): AnnotationFeature | undefined {
|
|
30
|
-
if (feature._id === featureId) {
|
|
31
|
-
return feature
|
|
32
|
-
}
|
|
33
|
-
// Check if there is also childFeatures in parent feature and it's not empty
|
|
34
|
-
// Let's get featureId from recursive method
|
|
35
|
-
if (!feature.children) {
|
|
36
|
-
return
|
|
37
|
-
}
|
|
38
|
-
for (const [, childFeature] of feature.children) {
|
|
39
|
-
const subFeature = getFeatureFromId(childFeature, featureId)
|
|
40
|
-
if (subFeature) {
|
|
41
|
-
return subFeature
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
return
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function findExonInRange(
|
|
48
|
-
exons: ExonInfo[],
|
|
49
|
-
pairStart: number,
|
|
50
|
-
pairEnd: number,
|
|
51
|
-
): ExonInfo | null {
|
|
52
|
-
for (const exon of exons) {
|
|
53
|
-
if (Number(exon.min) <= pairStart && Number(exon.max) >= pairEnd) {
|
|
54
|
-
return exon
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
return null
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function removeMatchingExon(
|
|
61
|
-
exons: ExonInfo[],
|
|
62
|
-
matchStart: number,
|
|
63
|
-
matchEnd: number,
|
|
64
|
-
): ExonInfo[] {
|
|
65
|
-
// Filter the array to remove elements matching the specified start and end
|
|
66
|
-
return exons.filter(
|
|
67
|
-
(exon) => !(exon.min === matchStart && exon.max === matchEnd),
|
|
68
|
-
)
|
|
69
|
-
}
|
|
70
|
-
|
|
71
23
|
export const TranscriptBasicInformation = observer(
|
|
72
24
|
function TranscriptBasicInformation({
|
|
73
25
|
assembly,
|
|
@@ -84,362 +36,159 @@ export const TranscriptBasicInformation = observer(
|
|
|
84
36
|
const currentAssembly = session.apolloDataStore.assemblies.get(assembly)
|
|
85
37
|
const refData = currentAssembly?.getByRefName(refName)
|
|
86
38
|
const { changeManager } = session.apolloDataStore
|
|
39
|
+
const theme = useTheme()
|
|
87
40
|
|
|
88
|
-
function
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
41
|
+
function handleLocationChange(
|
|
42
|
+
oldLocation: number,
|
|
43
|
+
newLocation: number,
|
|
44
|
+
feature: AnnotationFeature,
|
|
45
|
+
isMin: boolean,
|
|
92
46
|
) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if (newStart < feature.min) {
|
|
96
|
-
notify('Feature start cannot be less than parent starts', 'error')
|
|
97
|
-
return
|
|
98
|
-
}
|
|
99
|
-
const subFeature = getFeatureFromId(feature, featureId)
|
|
100
|
-
if (!subFeature?.children) {
|
|
101
|
-
return
|
|
47
|
+
if (!feature.children) {
|
|
48
|
+
throw new Error('Transcript should have child features')
|
|
102
49
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (
|
|
106
|
-
(child[1].type === 'CDS' || child[1].type === 'exon') &&
|
|
107
|
-
child[1].min === oldStart
|
|
108
|
-
) {
|
|
50
|
+
for (const [, child] of feature.children) {
|
|
51
|
+
if (isMin && oldLocation - 1 === child.min) {
|
|
109
52
|
const change = new LocationStartChange({
|
|
110
53
|
typeName: 'LocationStartChange',
|
|
111
|
-
changedIds: [child
|
|
112
|
-
featureId,
|
|
113
|
-
oldStart,
|
|
114
|
-
newStart,
|
|
54
|
+
changedIds: [child._id],
|
|
55
|
+
featureId: feature._id,
|
|
56
|
+
oldStart: oldLocation - 1,
|
|
57
|
+
newStart: newLocation - 1,
|
|
115
58
|
assembly,
|
|
116
59
|
})
|
|
117
60
|
changeManager.submit(change).catch(() => {
|
|
118
61
|
notify('Error updating feature start position', 'error')
|
|
119
62
|
})
|
|
63
|
+
return
|
|
120
64
|
}
|
|
121
|
-
|
|
122
|
-
return
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function handleEndChange(
|
|
126
|
-
newEnd: number,
|
|
127
|
-
featureId: string,
|
|
128
|
-
oldEnd: number,
|
|
129
|
-
) {
|
|
130
|
-
const subFeature = getFeatureFromId(feature, featureId)
|
|
131
|
-
if (newEnd > feature.max) {
|
|
132
|
-
notify('Feature start cannot be greater than parent end', 'error')
|
|
133
|
-
return
|
|
134
|
-
}
|
|
135
|
-
if (!subFeature?.children) {
|
|
136
|
-
return
|
|
137
|
-
}
|
|
138
|
-
// Let's check CDS start and end values. And possibly update those too
|
|
139
|
-
for (const child of subFeature.children) {
|
|
140
|
-
if (
|
|
141
|
-
(child[1].type === 'CDS' || child[1].type === 'exon') &&
|
|
142
|
-
child[1].max === oldEnd
|
|
143
|
-
) {
|
|
65
|
+
if (!isMin && newLocation === child.max) {
|
|
144
66
|
const change = new LocationEndChange({
|
|
145
67
|
typeName: 'LocationEndChange',
|
|
146
|
-
changedIds: [child
|
|
147
|
-
featureId,
|
|
148
|
-
oldEnd,
|
|
149
|
-
newEnd,
|
|
68
|
+
changedIds: [child._id],
|
|
69
|
+
featureId: feature._id,
|
|
70
|
+
oldEnd: child.max,
|
|
71
|
+
newEnd: newLocation,
|
|
150
72
|
assembly,
|
|
151
73
|
})
|
|
152
74
|
changeManager.submit(change).catch(() => {
|
|
153
|
-
notify('Error updating feature
|
|
75
|
+
notify('Error updating feature start position', 'error')
|
|
154
76
|
})
|
|
77
|
+
return
|
|
155
78
|
}
|
|
156
79
|
}
|
|
157
|
-
return
|
|
158
80
|
}
|
|
159
81
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
const traverse = (currentFeature: AnnotationFeature) => {
|
|
163
|
-
if (currentFeature.type === 'exon') {
|
|
164
|
-
exonsArray.push({
|
|
165
|
-
min: currentFeature.min + 1,
|
|
166
|
-
max: currentFeature.max,
|
|
167
|
-
})
|
|
168
|
-
}
|
|
169
|
-
if (currentFeature.children) {
|
|
170
|
-
for (const child of currentFeature.children) {
|
|
171
|
-
traverse(child[1])
|
|
172
|
-
}
|
|
173
|
-
}
|
|
82
|
+
if (!refData) {
|
|
83
|
+
return null
|
|
174
84
|
}
|
|
175
|
-
traverse(featureNew)
|
|
176
|
-
|
|
177
|
-
const CDSresult: CDSInfo[] = []
|
|
178
|
-
const CDSData = featureNew.cdsLocations
|
|
179
|
-
if (refData) {
|
|
180
|
-
for (const CDSDatum of CDSData) {
|
|
181
|
-
for (const dataPoint of CDSDatum) {
|
|
182
|
-
let startSeq = refData.getSequence(
|
|
183
|
-
Number(dataPoint.min) - 2,
|
|
184
|
-
Number(dataPoint.min),
|
|
185
|
-
)
|
|
186
|
-
let endSeq = refData.getSequence(
|
|
187
|
-
Number(dataPoint.max),
|
|
188
|
-
Number(dataPoint.max) + 2,
|
|
189
|
-
)
|
|
190
|
-
|
|
191
|
-
if (featureNew.strand === -1 && startSeq && endSeq) {
|
|
192
|
-
startSeq = revcom(startSeq)
|
|
193
|
-
endSeq = revcom(endSeq)
|
|
194
|
-
}
|
|
195
|
-
const oneCDS: CDSInfo = {
|
|
196
|
-
id: featureNew._id,
|
|
197
|
-
type: 'CDS',
|
|
198
|
-
strand: Number(featureNew.strand),
|
|
199
|
-
min: dataPoint.min + 1,
|
|
200
|
-
max: dataPoint.max,
|
|
201
|
-
oldMin: dataPoint.min + 1,
|
|
202
|
-
oldMax: dataPoint.max,
|
|
203
|
-
startSeq,
|
|
204
|
-
endSeq,
|
|
205
|
-
}
|
|
206
|
-
// CDSresult.push(oneCDS)
|
|
207
|
-
// Check if there is already an object with the same start and end
|
|
208
|
-
const exists = CDSresult.some(
|
|
209
|
-
(obj) =>
|
|
210
|
-
obj.min === oneCDS.min &&
|
|
211
|
-
obj.max === oneCDS.max &&
|
|
212
|
-
obj.type === oneCDS.type,
|
|
213
|
-
)
|
|
214
85
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
CDSresult.push(oneCDS)
|
|
240
|
-
} else {
|
|
241
|
-
const oneCDS: CDSInfo = {
|
|
242
|
-
id: feature._id,
|
|
243
|
-
type: 'three_prime_UTR',
|
|
244
|
-
strand: Number(feature.strand),
|
|
245
|
-
min: dataPoint.min + 1,
|
|
246
|
-
max: foundExon.min + 1,
|
|
247
|
-
oldMin: dataPoint.min + 1,
|
|
248
|
-
oldMax: foundExon.min + 1,
|
|
249
|
-
startSeq: '',
|
|
250
|
-
endSeq: '',
|
|
251
|
-
}
|
|
252
|
-
CDSresult.push(oneCDS)
|
|
86
|
+
const { strand, transcriptParts } = feature
|
|
87
|
+
const [firstLocation] = transcriptParts
|
|
88
|
+
|
|
89
|
+
const locationData = firstLocation
|
|
90
|
+
.map((loc, idx) => {
|
|
91
|
+
const { max, min, type } = loc
|
|
92
|
+
let label: string = type
|
|
93
|
+
if (label === 'threePrimeUTR') {
|
|
94
|
+
label = '3` UTR'
|
|
95
|
+
} else if (label === 'fivePrimeUTR') {
|
|
96
|
+
label = '5` UTR'
|
|
97
|
+
}
|
|
98
|
+
let fivePrimeSpliceSite
|
|
99
|
+
let threePrimeSpliceSite
|
|
100
|
+
let frameColor
|
|
101
|
+
if (type === 'CDS') {
|
|
102
|
+
const { phase } = loc
|
|
103
|
+
const frame = getFrame(min, max, strand ?? 1, phase)
|
|
104
|
+
frameColor = theme.palette.framesCDS.at(frame)?.main
|
|
105
|
+
const previousLoc = firstLocation.at(idx - 1)
|
|
106
|
+
const nextLoc = firstLocation.at(idx + 1)
|
|
107
|
+
if (strand === 1) {
|
|
108
|
+
if (previousLoc?.type === 'intron') {
|
|
109
|
+
fivePrimeSpliceSite = refData.getSequence(min - 2, min)
|
|
253
110
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
)
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
if (
|
|
262
|
-
|
|
263
|
-
id: feature._id,
|
|
264
|
-
type: 'three_prime_UTR',
|
|
265
|
-
strand: Number(feature.strand),
|
|
266
|
-
min: dataPoint.max + 1,
|
|
267
|
-
max: foundExon.max,
|
|
268
|
-
oldMin: dataPoint.max + 1,
|
|
269
|
-
oldMax: foundExon.max,
|
|
270
|
-
startSeq: '',
|
|
271
|
-
endSeq: '',
|
|
272
|
-
}
|
|
273
|
-
CDSresult.push(oneCDS)
|
|
274
|
-
} else {
|
|
275
|
-
const oneCDS: CDSInfo = {
|
|
276
|
-
id: feature._id,
|
|
277
|
-
type: 'five_prime_UTR',
|
|
278
|
-
strand: Number(feature.strand),
|
|
279
|
-
min: dataPoint.min + 1,
|
|
280
|
-
max: foundExon.max,
|
|
281
|
-
oldMin: dataPoint.min + 1,
|
|
282
|
-
oldMax: foundExon.max,
|
|
283
|
-
startSeq: '',
|
|
284
|
-
endSeq: '',
|
|
285
|
-
}
|
|
286
|
-
CDSresult.push(oneCDS)
|
|
111
|
+
if (nextLoc?.type === 'intron') {
|
|
112
|
+
threePrimeSpliceSite = refData.getSequence(max, max + 2)
|
|
113
|
+
}
|
|
114
|
+
} else {
|
|
115
|
+
if (previousLoc?.type === 'intron') {
|
|
116
|
+
fivePrimeSpliceSite = revcom(refData.getSequence(max, max + 2))
|
|
117
|
+
}
|
|
118
|
+
if (nextLoc?.type === 'intron') {
|
|
119
|
+
threePrimeSpliceSite = revcom(refData.getSequence(min - 2, min))
|
|
287
120
|
}
|
|
288
|
-
exonsArray = removeMatchingExon(
|
|
289
|
-
exonsArray,
|
|
290
|
-
foundExon.min,
|
|
291
|
-
foundExon.max,
|
|
292
|
-
)
|
|
293
|
-
}
|
|
294
|
-
if (
|
|
295
|
-
dataPoint.min + 1 === foundExon?.min &&
|
|
296
|
-
dataPoint.max === foundExon.max
|
|
297
|
-
) {
|
|
298
|
-
exonsArray = removeMatchingExon(
|
|
299
|
-
exonsArray,
|
|
300
|
-
foundExon.min,
|
|
301
|
-
foundExon.max,
|
|
302
|
-
)
|
|
303
121
|
}
|
|
304
122
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
if (featureNew.strand === 1) {
|
|
313
|
-
const oneCDS: CDSInfo = {
|
|
314
|
-
id: featureNew._id,
|
|
315
|
-
type: 'five_prime_UTR',
|
|
316
|
-
strand: Number(featureNew.strand),
|
|
317
|
-
min: element.min + 1,
|
|
318
|
-
max: element.max,
|
|
319
|
-
oldMin: element.min + 1,
|
|
320
|
-
oldMax: element.max,
|
|
321
|
-
startSeq: '',
|
|
322
|
-
endSeq: '',
|
|
323
|
-
}
|
|
324
|
-
CDSresult.push(oneCDS)
|
|
325
|
-
} else {
|
|
326
|
-
const oneCDS: CDSInfo = {
|
|
327
|
-
id: featureNew._id,
|
|
328
|
-
type: 'three_prime_UTR',
|
|
329
|
-
strand: Number(featureNew.strand),
|
|
330
|
-
min: element.min + 1,
|
|
331
|
-
max: element.max + 1,
|
|
332
|
-
oldMin: element.min + 1,
|
|
333
|
-
oldMax: element.max + 1,
|
|
334
|
-
startSeq: '',
|
|
335
|
-
endSeq: '',
|
|
336
|
-
}
|
|
337
|
-
CDSresult.push(oneCDS)
|
|
123
|
+
return {
|
|
124
|
+
min,
|
|
125
|
+
max,
|
|
126
|
+
label,
|
|
127
|
+
fivePrimeSpliceSite,
|
|
128
|
+
threePrimeSpliceSite,
|
|
129
|
+
frameColor,
|
|
338
130
|
}
|
|
339
|
-
exonsArray = removeMatchingExon(exonsArray, element.min, element.max)
|
|
340
131
|
})
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
CDSresult.sort((a, b) => {
|
|
344
|
-
// Primary sorting by 'start' property
|
|
345
|
-
const startDifference = Number(a.min) - Number(b.min)
|
|
346
|
-
if (startDifference !== 0) {
|
|
347
|
-
return startDifference
|
|
348
|
-
}
|
|
349
|
-
return Number(a.max) - Number(b.max)
|
|
350
|
-
})
|
|
351
|
-
if (CDSresult.length > 0) {
|
|
352
|
-
CDSresult[0].startSeq = ''
|
|
353
|
-
|
|
354
|
-
// eslint-disable-next-line unicorn/prefer-at
|
|
355
|
-
CDSresult[CDSresult.length - 1].endSeq = ''
|
|
356
|
-
|
|
357
|
-
// Loop through the array and clear "startSeq" or "endSeq" based on the conditions
|
|
358
|
-
for (let i = 0; i < CDSresult.length; i++) {
|
|
359
|
-
if (i > 0 && CDSresult[i].min === CDSresult[i - 1].max) {
|
|
360
|
-
// Clear "startSeq" if the current item's "start" is equal to the previous item's "end"
|
|
361
|
-
CDSresult[i].startSeq = ''
|
|
362
|
-
}
|
|
363
|
-
if (
|
|
364
|
-
i < CDSresult.length - 1 &&
|
|
365
|
-
CDSresult[i].max === CDSresult[i + 1].min
|
|
366
|
-
) {
|
|
367
|
-
// Clear "endSeq" if the next item's "start" is equal to the current item's "end"
|
|
368
|
-
CDSresult[i].endSeq = ''
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
const transcriptItems = CDSresult
|
|
132
|
+
.filter((loc) => loc.label !== 'intron')
|
|
374
133
|
|
|
375
134
|
return (
|
|
376
135
|
<>
|
|
377
|
-
<Typography
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
>
|
|
381
|
-
CDS and UTRs
|
|
136
|
+
<Typography variant="h5">Structure</Typography>
|
|
137
|
+
<Typography variant="h6">
|
|
138
|
+
{strand === 1 ? 'Forward' : 'Reverse'} strand
|
|
382
139
|
</Typography>
|
|
383
|
-
<
|
|
384
|
-
|
|
385
|
-
<
|
|
386
|
-
|
|
387
|
-
{
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
}}
|
|
436
|
-
/>
|
|
437
|
-
<span style={{ marginLeft: '8px', fontWeight: 'bold' }}>
|
|
438
|
-
{item.endSeq}
|
|
439
|
-
</span>
|
|
440
|
-
</div>
|
|
441
|
-
))}
|
|
442
|
-
</div>
|
|
140
|
+
<TableContainer component={Paper}>
|
|
141
|
+
<Table size="small">
|
|
142
|
+
<TableBody>
|
|
143
|
+
{locationData.map((loc) => (
|
|
144
|
+
<TableRow key={`${loc.label}:${loc.min}-${loc.max}`}>
|
|
145
|
+
<TableCell
|
|
146
|
+
component="th"
|
|
147
|
+
scope="row"
|
|
148
|
+
style={{ background: loc.frameColor }}
|
|
149
|
+
>
|
|
150
|
+
{loc.label}
|
|
151
|
+
</TableCell>
|
|
152
|
+
<TableCell>{loc.fivePrimeSpliceSite ?? ''}</TableCell>
|
|
153
|
+
<TableCell padding="none">
|
|
154
|
+
<NumberTextField
|
|
155
|
+
margin="dense"
|
|
156
|
+
variant="outlined"
|
|
157
|
+
value={strand === 1 ? loc.min + 1 : loc.max}
|
|
158
|
+
onChangeCommitted={(newLocation: number) => {
|
|
159
|
+
handleLocationChange(
|
|
160
|
+
strand === 1 ? loc.min + 1 : loc.max,
|
|
161
|
+
newLocation,
|
|
162
|
+
feature,
|
|
163
|
+
strand === 1,
|
|
164
|
+
)
|
|
165
|
+
}}
|
|
166
|
+
/>
|
|
167
|
+
{/* {strand === 1 ? loc.min : loc.max} */}
|
|
168
|
+
</TableCell>
|
|
169
|
+
<TableCell padding="none">
|
|
170
|
+
<NumberTextField
|
|
171
|
+
margin="dense"
|
|
172
|
+
// disabled={item.type !== 'CDS'}
|
|
173
|
+
variant="outlined"
|
|
174
|
+
value={strand === 1 ? loc.max : loc.min + 1}
|
|
175
|
+
onChangeCommitted={(newLocation: number) => {
|
|
176
|
+
handleLocationChange(
|
|
177
|
+
strand === 1 ? loc.max : loc.min + 1,
|
|
178
|
+
newLocation,
|
|
179
|
+
feature,
|
|
180
|
+
strand !== 1,
|
|
181
|
+
)
|
|
182
|
+
}}
|
|
183
|
+
/>
|
|
184
|
+
{/* {strand === 1 ? loc.max : loc.min} */}
|
|
185
|
+
</TableCell>
|
|
186
|
+
<TableCell>{loc.threePrimeSpliceSite ?? ''}</TableCell>
|
|
187
|
+
</TableRow>
|
|
188
|
+
))}
|
|
189
|
+
</TableBody>
|
|
190
|
+
</Table>
|
|
191
|
+
</TableContainer>
|
|
443
192
|
</>
|
|
444
193
|
)
|
|
445
194
|
},
|