@apollo-annotation/jbrowse-plugin-apollo 0.3.5 → 0.3.7
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 +6964 -4598
- package/dist/index.esm.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.development.js +6610 -4261
- 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 +11563 -7493
- 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 -4
- package/src/ApolloInternetAccount/addMenuItems.ts +23 -2
- package/src/ApolloInternetAccount/components/AuthTypeSelector.tsx +1 -0
- package/src/ApolloInternetAccount/components/LoginButtons.tsx +1 -1
- package/src/ApolloInternetAccount/components/LoginIcons.tsx +1 -1
- package/src/ApolloInternetAccount/configSchema.ts +1 -1
- package/src/ApolloInternetAccount/model.ts +11 -10
- package/src/ApolloJobModel.ts +1 -1
- package/src/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.ts +8 -6
- package/src/ApolloRefNameAliasAdapter/index.ts +2 -2
- package/src/ApolloSequenceAdapter/ApolloSequenceAdapter.ts +4 -4
- package/src/ApolloSequenceAdapter/index.ts +1 -1
- package/src/ApolloTextSearchAdapter/ApolloTextSearchAdapter.ts +8 -7
- package/src/ApolloTextSearchAdapter/index.ts +1 -1
- package/src/BackendDrivers/BackendDriver.ts +7 -7
- package/src/BackendDrivers/CollaborationServerDriver.ts +14 -10
- package/src/BackendDrivers/DesktopFileDriver.ts +11 -10
- package/src/BackendDrivers/InMemoryFileDriver.ts +10 -6
- package/src/ChangeManager.ts +15 -11
- package/src/FeatureDetailsWidget/ApolloFeatureDetailsWidget.tsx +8 -7
- package/src/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.tsx +35 -14
- package/src/FeatureDetailsWidget/AttributeKey.tsx +50 -0
- package/src/FeatureDetailsWidget/AttributeKeySelector.tsx +104 -0
- package/src/FeatureDetailsWidget/Attributes.tsx +215 -367
- package/src/FeatureDetailsWidget/BasicInformation.tsx +6 -5
- package/src/FeatureDetailsWidget/DefaultAttributeEditor.tsx +104 -0
- package/src/FeatureDetailsWidget/DefaultAttributeViewer.tsx +22 -0
- package/src/FeatureDetailsWidget/FeatureDetailsNavigation.tsx +4 -4
- package/src/FeatureDetailsWidget/NumberTextField.tsx +1 -1
- package/src/FeatureDetailsWidget/Sequence.tsx +2 -2
- package/src/FeatureDetailsWidget/StringTextField.tsx +1 -1
- package/src/FeatureDetailsWidget/TranscriptSequence.tsx +15 -23
- package/src/FeatureDetailsWidget/TranscriptWidgetEditLocation.tsx +950 -196
- package/src/FeatureDetailsWidget/TranscriptWidgetSummary.tsx +8 -4
- package/src/FeatureDetailsWidget/model.ts +8 -3
- package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +7 -7
- package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +59 -72
- package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +253 -60
- package/src/LinearApolloDisplay/glyphs/GenericChildGlyph.ts +52 -6
- package/src/LinearApolloDisplay/glyphs/Glyph.ts +16 -8
- package/src/LinearApolloDisplay/stateModel/base.ts +81 -10
- package/src/LinearApolloDisplay/stateModel/index.ts +4 -3
- package/src/LinearApolloDisplay/stateModel/layouts.ts +8 -39
- package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +63 -46
- package/src/LinearApolloDisplay/stateModel/rendering.ts +60 -31
- package/src/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.tsx +226 -0
- package/src/LinearApolloSixFrameDisplay/components/TrackLines.tsx +32 -0
- package/src/LinearApolloSixFrameDisplay/components/index.ts +2 -0
- package/src/LinearApolloSixFrameDisplay/configSchema.ts +7 -0
- package/src/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.ts +940 -0
- package/src/LinearApolloSixFrameDisplay/glyphs/Glyph.ts +63 -0
- package/src/LinearApolloSixFrameDisplay/glyphs/index.ts +1 -0
- package/src/LinearApolloSixFrameDisplay/index.ts +2 -0
- package/src/LinearApolloSixFrameDisplay/stateModel/base.ts +302 -0
- package/src/LinearApolloSixFrameDisplay/stateModel/index.ts +27 -0
- package/src/LinearApolloSixFrameDisplay/stateModel/layouts.ts +252 -0
- package/src/LinearApolloSixFrameDisplay/stateModel/mouseEvents.ts +368 -0
- package/src/LinearApolloSixFrameDisplay/stateModel/rendering.ts +201 -0
- package/src/LinearApolloSixFrameDisplay/types.ts +1 -0
- package/src/OntologyManager/OntologyStore/fulltext.test.ts +1 -1
- package/src/OntologyManager/OntologyStore/fulltext.ts +8 -3
- package/src/OntologyManager/OntologyStore/index.test.ts +3 -1
- package/src/OntologyManager/OntologyStore/index.ts +19 -14
- package/src/OntologyManager/OntologyStore/indexeddb-schema.ts +6 -5
- package/src/OntologyManager/OntologyStore/indexeddb-storage.ts +11 -5
- package/src/OntologyManager/index.ts +12 -7
- package/src/OntologyManager/util.ts +3 -2
- package/src/TabularEditor/HybridGrid/ChangeHandling.ts +2 -2
- package/src/TabularEditor/HybridGrid/Feature.tsx +13 -7
- package/src/TabularEditor/HybridGrid/FeatureAttributes.tsx +1 -1
- package/src/TabularEditor/HybridGrid/HybridGrid.tsx +3 -2
- package/src/TabularEditor/HybridGrid/ToolBar.tsx +1 -1
- package/src/TabularEditor/HybridGrid/featureContextMenuItems.ts +114 -22
- package/src/TabularEditor/TabularEditorPane.tsx +1 -1
- package/src/TabularEditor/model.ts +2 -2
- package/src/TabularEditor/types.ts +5 -2
- package/src/components/AddAssembly.tsx +182 -179
- package/src/components/AddAssemblyAliases.tsx +114 -0
- package/src/components/AddChildFeature.tsx +8 -10
- package/src/components/AddFeature.tsx +216 -44
- package/src/components/AddRefSeqAliases.tsx +14 -12
- package/src/components/CopyFeature.tsx +10 -11
- package/src/components/CreateApolloAnnotation.tsx +342 -158
- package/src/components/DeleteAssembly.tsx +9 -8
- package/src/components/DeleteFeature.tsx +362 -14
- package/src/components/Dialog.tsx +1 -1
- package/src/components/DownloadGFF3.tsx +31 -11
- package/src/components/FilterFeatures.tsx +6 -4
- package/src/components/FilterTranscripts.tsx +86 -0
- package/src/components/ImportFeatures.tsx +7 -6
- package/src/components/LogOut.tsx +5 -4
- package/src/components/ManageChecks.tsx +9 -8
- package/src/components/ManageUsers.tsx +11 -10
- package/src/components/MergeExons.tsx +193 -0
- package/src/components/MergeTranscripts.tsx +185 -0
- package/src/components/OntologyTermAutocomplete.tsx +5 -5
- package/src/components/OntologyTermMultiSelect.tsx +6 -6
- package/src/components/OpenLocalFile.tsx +4 -3
- package/src/components/SplitExon.tsx +134 -0
- package/src/components/ViewChangeLog.tsx +7 -6
- package/src/components/ViewCheckResults.tsx +8 -7
- package/src/components/index.ts +3 -0
- package/src/config.ts +5 -0
- package/src/extensions/annotationFromJBrowseFeature.test.ts +1 -0
- package/src/extensions/annotationFromJBrowseFeature.ts +13 -10
- package/src/extensions/annotationFromPileup.ts +104 -94
- package/src/index.ts +33 -50
- package/src/makeDisplayComponent.tsx +90 -37
- package/src/session/ClientDataStore.ts +21 -17
- package/src/session/session.ts +46 -39
- package/src/types.ts +4 -4
- package/src/util/annotationFeatureUtils.ts +66 -1
- package/src/util/copyToClipboard.ts +21 -0
- package/src/util/glyphUtils.ts +49 -0
- package/src/util/index.ts +5 -3
- package/src/util/loadAssemblyIntoClient.ts +10 -3
- package/src/util/mouseEventsUtils.ts +113 -0
- package/src/ApolloSixFrameRenderer/ApolloSixFrameRenderer.tsx +0 -13
- package/src/ApolloSixFrameRenderer/components/ApolloRendering.tsx +0 -707
- package/src/ApolloSixFrameRenderer/configSchema.ts +0 -7
- package/src/ApolloSixFrameRenderer/index.ts +0 -3
- package/src/SixFrameFeatureDisplay/components/TrackLines.tsx +0 -19
- package/src/SixFrameFeatureDisplay/components/index.ts +0 -1
- package/src/SixFrameFeatureDisplay/configSchema.ts +0 -21
- package/src/SixFrameFeatureDisplay/index.ts +0 -2
- package/src/SixFrameFeatureDisplay/stateModel.ts +0 -443
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
/* eslint-disable react-hooks/exhaustive-deps */
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-misused-promises */
|
|
3
3
|
/* eslint-disable @typescript-eslint/unbound-method */
|
|
4
|
-
import React, { useEffect, useMemo, useState } from 'react'
|
|
5
4
|
|
|
5
|
+
import { type AnnotationFeatureSnapshot } from '@apollo-annotation/mst'
|
|
6
|
+
import {
|
|
7
|
+
AddFeatureChange,
|
|
8
|
+
LocationEndChange,
|
|
9
|
+
LocationStartChange,
|
|
10
|
+
} from '@apollo-annotation/shared'
|
|
11
|
+
import { type Assembly } from '@jbrowse/core/assemblyManager/assembly'
|
|
12
|
+
import { type AbstractSessionModel } from '@jbrowse/core/util'
|
|
6
13
|
import {
|
|
7
14
|
Box,
|
|
8
15
|
Button,
|
|
@@ -12,19 +19,19 @@ import {
|
|
|
12
19
|
DialogContentText,
|
|
13
20
|
DialogTitle,
|
|
14
21
|
FormControlLabel,
|
|
22
|
+
FormGroup,
|
|
15
23
|
MenuItem,
|
|
16
24
|
Select,
|
|
17
|
-
SelectChangeEvent,
|
|
25
|
+
type SelectChangeEvent,
|
|
18
26
|
Typography,
|
|
19
27
|
} from '@mui/material'
|
|
28
|
+
import ObjectID from 'bson-objectid'
|
|
29
|
+
import { getSnapshot } from 'mobx-state-tree'
|
|
30
|
+
import React, { useEffect, useMemo, useState } from 'react'
|
|
31
|
+
|
|
32
|
+
import { type ApolloSessionModel } from '../session'
|
|
20
33
|
|
|
21
34
|
import { Dialog } from './Dialog'
|
|
22
|
-
import { ApolloSessionModel } from '../session'
|
|
23
|
-
import { AnnotationFeatureSnapshot } from '@apollo-annotation/mst'
|
|
24
|
-
import { getSnapshot } from 'mobx-state-tree'
|
|
25
|
-
import { AddFeatureChange } from '@apollo-annotation/shared'
|
|
26
|
-
import { Assembly } from '@jbrowse/core/assemblyManager/assembly'
|
|
27
|
-
import { AbstractSessionModel } from '@jbrowse/core/util'
|
|
28
35
|
|
|
29
36
|
interface CreateApolloAnnotationProps {
|
|
30
37
|
session: AbstractSessionModel
|
|
@@ -32,6 +39,10 @@ interface CreateApolloAnnotationProps {
|
|
|
32
39
|
annotationFeature: AnnotationFeatureSnapshot
|
|
33
40
|
assembly: Assembly
|
|
34
41
|
refSeqId: string
|
|
42
|
+
region: {
|
|
43
|
+
start: number
|
|
44
|
+
end: number
|
|
45
|
+
}
|
|
35
46
|
}
|
|
36
47
|
|
|
37
48
|
const isGeneOrTranscript = (
|
|
@@ -87,41 +98,59 @@ const isTranscript = (
|
|
|
87
98
|
)
|
|
88
99
|
}
|
|
89
100
|
|
|
90
|
-
|
|
101
|
+
export function getFeatureName(feature: AnnotationFeatureSnapshot) {
|
|
91
102
|
const { attributes } = feature
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
103
|
+
const keys = ['name', 'gff_name', 'transcript_name', 'gene_name']
|
|
104
|
+
for (const key of keys) {
|
|
105
|
+
const value = attributes?.[key]
|
|
106
|
+
if (value?.[0]) {
|
|
107
|
+
return value[0]
|
|
108
|
+
}
|
|
95
109
|
}
|
|
96
|
-
return
|
|
110
|
+
return ''
|
|
97
111
|
}
|
|
98
112
|
|
|
99
|
-
|
|
100
|
-
feature
|
|
101
|
-
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
let attrName = ''
|
|
110
|
-
|
|
111
|
-
if (featureTypeOntology.isTypeOf(feature.type, 'gene')) {
|
|
112
|
-
attrName = 'gene_name'
|
|
113
|
+
export function getGeneNameOrId(feature: AnnotationFeatureSnapshot) {
|
|
114
|
+
const { attributes } = feature
|
|
115
|
+
const keys = ['gene_name', 'gene_id', 'gene_stable_id']
|
|
116
|
+
for (const key of keys) {
|
|
117
|
+
const value = attributes?.[key]
|
|
118
|
+
if (value?.[0]) {
|
|
119
|
+
return value[0]
|
|
120
|
+
}
|
|
113
121
|
}
|
|
122
|
+
return ''
|
|
123
|
+
}
|
|
114
124
|
|
|
115
|
-
|
|
116
|
-
|
|
125
|
+
export function getFeatureId(feature: AnnotationFeatureSnapshot) {
|
|
126
|
+
const { attributes } = feature
|
|
127
|
+
const keys = [
|
|
128
|
+
'id',
|
|
129
|
+
'gff_id',
|
|
130
|
+
'transcript_id',
|
|
131
|
+
'gene_id',
|
|
132
|
+
'gene_stable_id',
|
|
133
|
+
'stable_id',
|
|
134
|
+
]
|
|
135
|
+
for (const key of keys) {
|
|
136
|
+
const value = attributes?.[key]
|
|
137
|
+
if (value?.[0]) {
|
|
138
|
+
return value[0]
|
|
139
|
+
}
|
|
117
140
|
}
|
|
141
|
+
return ''
|
|
142
|
+
}
|
|
118
143
|
|
|
119
|
-
|
|
120
|
-
const name =
|
|
144
|
+
const getFeatureNameOrId = (feature: AnnotationFeatureSnapshot) => {
|
|
145
|
+
const name = getFeatureName(feature)
|
|
146
|
+
const id = getFeatureId(feature)
|
|
121
147
|
if (name) {
|
|
122
|
-
return name
|
|
148
|
+
return `${feature.type} - ${name}`
|
|
123
149
|
}
|
|
124
|
-
|
|
150
|
+
if (id) {
|
|
151
|
+
return `${feature.type} - ${id}`
|
|
152
|
+
}
|
|
153
|
+
return feature.type
|
|
125
154
|
}
|
|
126
155
|
|
|
127
156
|
export function CreateApolloAnnotation({
|
|
@@ -130,44 +159,46 @@ export function CreateApolloAnnotation({
|
|
|
130
159
|
handleClose,
|
|
131
160
|
refSeqId,
|
|
132
161
|
session,
|
|
162
|
+
region,
|
|
133
163
|
}: CreateApolloAnnotationProps) {
|
|
134
164
|
const apolloSessionModel = session as unknown as ApolloSessionModel
|
|
165
|
+
const { featureTypeOntology } =
|
|
166
|
+
apolloSessionModel.apolloDataStore.ontologyManager
|
|
135
167
|
const childIds = useMemo(
|
|
136
168
|
() => Object.keys(annotationFeature.children ?? {}),
|
|
137
169
|
[annotationFeature],
|
|
138
170
|
)
|
|
139
171
|
|
|
140
|
-
const features = useMemo(() => {
|
|
141
|
-
for (const [, asm] of apolloSessionModel.apolloDataStore.assemblies) {
|
|
142
|
-
if (asm._id === assembly.name) {
|
|
143
|
-
for (const [, refSeq] of asm.refSeqs) {
|
|
144
|
-
if (refSeq._id === refSeqId) {
|
|
145
|
-
return refSeq.features
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
return []
|
|
151
|
-
}, [])
|
|
152
|
-
|
|
153
172
|
const [parentFeatureChecked, setParentFeatureChecked] = useState(true)
|
|
154
173
|
const [checkedChildrens, setCheckedChildrens] = useState<string[]>(childIds)
|
|
155
174
|
const [errorMessage, setErrorMessage] = useState('')
|
|
156
175
|
const [destinationFeatures, setDestinationFeatures] = useState<
|
|
157
176
|
AnnotationFeatureSnapshot[]
|
|
158
177
|
>([])
|
|
178
|
+
const [createNewGene, setCreateNewGene] = useState(false)
|
|
159
179
|
const [selectedDestinationFeature, setSelectedDestinationFeature] =
|
|
160
180
|
useState<AnnotationFeatureSnapshot>()
|
|
161
181
|
|
|
162
|
-
const
|
|
182
|
+
const apolloAssembly = apolloSessionModel.apolloDataStore.assemblies.get(
|
|
183
|
+
assembly.name,
|
|
184
|
+
)
|
|
185
|
+
const refSeq = apolloAssembly?.refSeqs.get(refSeqId)
|
|
186
|
+
const features = refSeq?.getFeatures(region.start, region.end)
|
|
187
|
+
|
|
188
|
+
const getDestinationFeatures = () => {
|
|
163
189
|
const filteredFeatures: AnnotationFeatureSnapshot[] = []
|
|
164
190
|
|
|
165
|
-
for (const
|
|
166
|
-
if (f.
|
|
191
|
+
for (const f of features ?? []) {
|
|
192
|
+
if (f.min > region.end || f.max < region.start) {
|
|
167
193
|
continue
|
|
168
194
|
}
|
|
169
|
-
|
|
170
|
-
|
|
195
|
+
|
|
196
|
+
// Destination feature should be of type gene amd should be on the same strand as the source feature
|
|
197
|
+
if (
|
|
198
|
+
featureTypeOntology?.isTypeOf(f.type, 'gene') &&
|
|
199
|
+
f.strand === annotationFeature.strand
|
|
200
|
+
) {
|
|
201
|
+
const featureSnapshot = getSnapshot(f)
|
|
171
202
|
filteredFeatures.push(featureSnapshot)
|
|
172
203
|
}
|
|
173
204
|
}
|
|
@@ -177,34 +208,10 @@ export function CreateApolloAnnotation({
|
|
|
177
208
|
|
|
178
209
|
useEffect(() => {
|
|
179
210
|
setErrorMessage('')
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
annotationFeature.children,
|
|
185
|
-
)
|
|
186
|
-
.filter((child) => isTranscript(child, apolloSessionModel))
|
|
187
|
-
.filter((child) => checkedChildrens.includes(child._id))
|
|
188
|
-
mins = checkedAnnotationFeatureChildren.map((f) => f.min)
|
|
189
|
-
maxes = checkedAnnotationFeatureChildren.map((f) => f.max)
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
const { featureTypeOntology } =
|
|
193
|
-
apolloSessionModel.apolloDataStore.ontologyManager
|
|
194
|
-
if (
|
|
195
|
-
featureTypeOntology &&
|
|
196
|
-
featureTypeOntology.isTypeOf(annotationFeature.type, 'transcript')
|
|
197
|
-
) {
|
|
198
|
-
mins = [annotationFeature.min, ...mins]
|
|
199
|
-
maxes = [annotationFeature.max, ...maxes]
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
const min = Math.min(...mins)
|
|
203
|
-
const max = Math.max(...maxes)
|
|
204
|
-
const filteredFeatures = getFeatures(min, max)
|
|
205
|
-
setDestinationFeatures(filteredFeatures)
|
|
206
|
-
setSelectedDestinationFeature(filteredFeatures[0])
|
|
207
|
-
}, [checkedChildrens, parentFeatureChecked])
|
|
211
|
+
const features = getDestinationFeatures()
|
|
212
|
+
setDestinationFeatures(features)
|
|
213
|
+
setSelectedDestinationFeature(features[0])
|
|
214
|
+
}, [checkedChildrens, parentFeatureChecked, region])
|
|
208
215
|
|
|
209
216
|
const handleParentFeatureCheck = (
|
|
210
217
|
event: React.ChangeEvent<HTMLInputElement>,
|
|
@@ -234,82 +241,236 @@ export function CreateApolloAnnotation({
|
|
|
234
241
|
|
|
235
242
|
const handleCreateApolloAnnotation = async () => {
|
|
236
243
|
if (parentFeatureChecked) {
|
|
237
|
-
|
|
244
|
+
// IF SOURCE FEATURE IS GENE
|
|
238
245
|
if (isGene(annotationFeature, apolloSessionModel)) {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
)
|
|
244
|
-
const childrens: Record<string, AnnotationFeatureSnapshot> = {}
|
|
245
|
-
for (const childId of checkedChildrens) {
|
|
246
|
-
childrens[childId] = annotationFeature.children[childId]
|
|
247
|
-
}
|
|
248
|
-
change = new AddFeatureChange({
|
|
249
|
-
changedIds: [annotationFeature._id],
|
|
250
|
-
typeName: 'AddFeatureChange',
|
|
251
|
-
assembly: assembly.name,
|
|
252
|
-
addedFeature: {
|
|
253
|
-
...annotationFeature,
|
|
254
|
-
children: childrens,
|
|
255
|
-
},
|
|
256
|
-
})
|
|
257
|
-
} else {
|
|
258
|
-
change = new AddFeatureChange({
|
|
259
|
-
changedIds: [annotationFeature._id],
|
|
260
|
-
typeName: 'AddFeatureChange',
|
|
261
|
-
assembly: assembly.name,
|
|
262
|
-
addedFeature: annotationFeature,
|
|
263
|
-
})
|
|
264
|
-
}
|
|
246
|
+
await copyGeneFeature()
|
|
247
|
+
session.notify(
|
|
248
|
+
'Successfully copied selected gene and transcript(s)',
|
|
249
|
+
'success',
|
|
250
|
+
)
|
|
265
251
|
}
|
|
266
|
-
|
|
267
252
|
if (isTranscript(annotationFeature, apolloSessionModel)) {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
253
|
+
// IF THE SOURCE IS TRANSCRIPT AND THE DESTINATION IS SELECTED AND CREATE NEW GENE IS NOT CHECKED
|
|
254
|
+
if (selectedDestinationFeature && !createNewGene) {
|
|
255
|
+
const transcripts: Record<string, AnnotationFeatureSnapshot> = {}
|
|
256
|
+
transcripts[annotationFeature._id] = annotationFeature
|
|
257
|
+
|
|
258
|
+
// If source trancript doesn't overlap with destination gene
|
|
259
|
+
// If not overlapping, then extend the destination gene to include the transcript
|
|
260
|
+
if (
|
|
261
|
+
selectedDestinationFeature.max < annotationFeature.max ||
|
|
262
|
+
selectedDestinationFeature.min > annotationFeature.min
|
|
263
|
+
) {
|
|
264
|
+
const newMin = Math.min(
|
|
265
|
+
selectedDestinationFeature.min,
|
|
266
|
+
annotationFeature.min,
|
|
267
|
+
)
|
|
268
|
+
const newMax = Math.max(
|
|
269
|
+
selectedDestinationFeature.max,
|
|
270
|
+
annotationFeature.max,
|
|
271
|
+
)
|
|
272
|
+
await extendSelectedDestinationFeatureLocation(newMin, newMax)
|
|
273
|
+
await copyTranscriptsToDestinationGene(transcripts)
|
|
274
|
+
} else {
|
|
275
|
+
await copyTranscriptsToDestinationGene(transcripts)
|
|
276
|
+
}
|
|
277
|
+
session.notify(
|
|
278
|
+
'Successfully copied selected transcripts to destination gene',
|
|
279
|
+
'success',
|
|
280
|
+
)
|
|
276
281
|
} else {
|
|
277
|
-
|
|
278
|
-
|
|
282
|
+
// IF THERE IS NO DESTINATION GENE SELECTED AND CREATE NEW GENE IS CHECKED
|
|
283
|
+
const childrens: Record<string, AnnotationFeatureSnapshot> = {}
|
|
284
|
+
childrens[annotationFeature._id] = annotationFeature
|
|
285
|
+
await createNewGeneFeatureWithTranscripts(childrens)
|
|
286
|
+
session.notify(
|
|
287
|
+
'Successfully created a new gene with selected transcripts',
|
|
288
|
+
'success',
|
|
289
|
+
)
|
|
279
290
|
}
|
|
280
291
|
}
|
|
281
|
-
|
|
282
|
-
if (!change) {
|
|
283
|
-
return
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
await apolloSessionModel.apolloDataStore.changeManager.submit(change)
|
|
287
|
-
session.notify('Annotation added successfully', 'success')
|
|
288
|
-
handleClose()
|
|
289
292
|
} else {
|
|
293
|
+
// IF PARENT (GENE) FEATURE IS NOT CHECKED AND WE ARE COPYING CHILDREN (TRANSCRIPTS)
|
|
290
294
|
if (!annotationFeature.children) {
|
|
291
295
|
return
|
|
292
296
|
}
|
|
293
|
-
|
|
294
|
-
|
|
297
|
+
|
|
298
|
+
// IF DESTINATION IS SELECTED AND CREATE NEW GENE IS NOT CHECKED
|
|
299
|
+
if (selectedDestinationFeature && !createNewGene) {
|
|
300
|
+
const childrens: Record<string, AnnotationFeatureSnapshot> = {}
|
|
301
|
+
for (const childId of checkedChildrens) {
|
|
302
|
+
childrens[childId] = annotationFeature.children[childId]
|
|
303
|
+
}
|
|
304
|
+
const min = Math.min(
|
|
305
|
+
...Object.values(childrens).map((child) => child.min),
|
|
306
|
+
)
|
|
307
|
+
const max = Math.max(
|
|
308
|
+
...Object.values(childrens).map((child) => child.max),
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
// If source trancript doesn't overlap with destination gene
|
|
312
|
+
// If not overlapping, then extend the destination gene to include the transcript
|
|
313
|
+
if (
|
|
314
|
+
selectedDestinationFeature.min > min ||
|
|
315
|
+
selectedDestinationFeature.max < max
|
|
316
|
+
) {
|
|
317
|
+
const newMin = Math.min(selectedDestinationFeature.min, min)
|
|
318
|
+
const newMax = Math.max(selectedDestinationFeature.max, max)
|
|
319
|
+
await extendSelectedDestinationFeatureLocation(newMin, newMax)
|
|
320
|
+
await copyTranscriptsToDestinationGene(childrens)
|
|
321
|
+
} else {
|
|
322
|
+
await copyTranscriptsToDestinationGene(childrens)
|
|
323
|
+
}
|
|
324
|
+
session.notify(
|
|
325
|
+
'Successfully copied transcript to destination gene',
|
|
326
|
+
'success',
|
|
327
|
+
)
|
|
328
|
+
} else {
|
|
329
|
+
// IF THERE IS NO DESTINATION GENE SELECTED AND CREATE NEW GENE IS CHECKED
|
|
330
|
+
const childrens: Record<string, AnnotationFeatureSnapshot> = {}
|
|
331
|
+
for (const childId of checkedChildrens) {
|
|
332
|
+
childrens[childId] = annotationFeature.children[childId]
|
|
333
|
+
}
|
|
334
|
+
await createNewGeneFeatureWithTranscripts(childrens)
|
|
335
|
+
session.notify(
|
|
336
|
+
'Successfully created a new gene with selected transcript',
|
|
337
|
+
'success',
|
|
338
|
+
)
|
|
295
339
|
}
|
|
340
|
+
}
|
|
341
|
+
handleClose()
|
|
342
|
+
}
|
|
296
343
|
|
|
344
|
+
// Copies gene feature along with its selected children
|
|
345
|
+
const copyGeneFeature = async () => {
|
|
346
|
+
let change
|
|
347
|
+
if (
|
|
348
|
+
annotationFeature.children &&
|
|
349
|
+
checkedChildrens.length !==
|
|
350
|
+
Object.values(annotationFeature.children).length
|
|
351
|
+
) {
|
|
352
|
+
// IF SOME CHILDREN ARE CHECKED
|
|
353
|
+
const childrens: Record<string, AnnotationFeatureSnapshot> = {}
|
|
297
354
|
for (const childId of checkedChildrens) {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
355
|
+
childrens[childId] = annotationFeature.children[childId]
|
|
356
|
+
}
|
|
357
|
+
change = new AddFeatureChange({
|
|
358
|
+
changedIds: [annotationFeature._id],
|
|
359
|
+
typeName: 'AddFeatureChange',
|
|
360
|
+
assembly: assembly.name,
|
|
361
|
+
addedFeature: {
|
|
362
|
+
...annotationFeature,
|
|
363
|
+
children: childrens,
|
|
364
|
+
},
|
|
365
|
+
})
|
|
366
|
+
} else {
|
|
367
|
+
// IF PARENT AND ALL CHILDREN ARE CHECKED
|
|
368
|
+
change = new AddFeatureChange({
|
|
369
|
+
changedIds: [annotationFeature._id],
|
|
370
|
+
typeName: 'AddFeatureChange',
|
|
371
|
+
assembly: assembly.name,
|
|
372
|
+
addedFeature: annotationFeature,
|
|
373
|
+
})
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
await submitChange(change)
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const copyTranscriptsToDestinationGene = async (
|
|
380
|
+
transcripts: Record<string, AnnotationFeatureSnapshot>,
|
|
381
|
+
) => {
|
|
382
|
+
if (!selectedDestinationFeature) {
|
|
383
|
+
return
|
|
384
|
+
}
|
|
385
|
+
for (const transcriptId of Object.keys(transcripts)) {
|
|
386
|
+
const transcript = transcripts[transcriptId]
|
|
387
|
+
const change = new AddFeatureChange({
|
|
388
|
+
parentFeatureId: selectedDestinationFeature._id,
|
|
389
|
+
changedIds: [selectedDestinationFeature._id],
|
|
390
|
+
typeName: 'AddFeatureChange',
|
|
391
|
+
assembly: assembly.name,
|
|
392
|
+
addedFeature: transcript,
|
|
393
|
+
})
|
|
394
|
+
await submitChange(change)
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const createNewGeneFeatureWithTranscripts = async (
|
|
399
|
+
childrens: Record<string, AnnotationFeatureSnapshot>,
|
|
400
|
+
) => {
|
|
401
|
+
const newGeneId = new ObjectID().toHexString()
|
|
402
|
+
const min = Math.min(...Object.values(childrens).map((child) => child.min))
|
|
403
|
+
const max = Math.max(...Object.values(childrens).map((child) => child.max))
|
|
404
|
+
const change = new AddFeatureChange({
|
|
405
|
+
changedIds: [newGeneId],
|
|
406
|
+
typeName: 'AddFeatureChange',
|
|
407
|
+
assembly: assembly.name,
|
|
408
|
+
addedFeature: {
|
|
409
|
+
_id: newGeneId,
|
|
410
|
+
refSeq: refSeqId,
|
|
411
|
+
min,
|
|
412
|
+
max,
|
|
413
|
+
strand: annotationFeature.strand,
|
|
414
|
+
type: 'gene',
|
|
415
|
+
children: childrens,
|
|
416
|
+
attributes: {
|
|
417
|
+
name: [getGeneNameOrId(annotationFeature)],
|
|
418
|
+
gene_name: [getGeneNameOrId(annotationFeature)],
|
|
419
|
+
},
|
|
420
|
+
},
|
|
421
|
+
})
|
|
422
|
+
await submitChange(change)
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const extendSelectedDestinationFeatureLocation = async (
|
|
426
|
+
newMin: number,
|
|
427
|
+
newMax: number,
|
|
428
|
+
) => {
|
|
429
|
+
if (!selectedDestinationFeature) {
|
|
430
|
+
return
|
|
431
|
+
}
|
|
432
|
+
const changes = []
|
|
433
|
+
if (newMin !== selectedDestinationFeature.min) {
|
|
434
|
+
changes.push(
|
|
435
|
+
new LocationStartChange({
|
|
436
|
+
typeName: 'LocationStartChange',
|
|
301
437
|
changedIds: [selectedDestinationFeature._id],
|
|
302
|
-
|
|
438
|
+
featureId: selectedDestinationFeature._id,
|
|
303
439
|
assembly: assembly.name,
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
440
|
+
oldStart: selectedDestinationFeature.min,
|
|
441
|
+
newStart: newMin,
|
|
442
|
+
}),
|
|
443
|
+
)
|
|
444
|
+
}
|
|
445
|
+
if (newMax !== selectedDestinationFeature.max) {
|
|
446
|
+
changes.push(
|
|
447
|
+
new LocationEndChange({
|
|
448
|
+
typeName: 'LocationEndChange',
|
|
449
|
+
changedIds: [selectedDestinationFeature._id],
|
|
450
|
+
featureId: selectedDestinationFeature._id,
|
|
451
|
+
assembly: assembly.name,
|
|
452
|
+
oldEnd: selectedDestinationFeature.max,
|
|
453
|
+
newEnd: newMax,
|
|
454
|
+
}),
|
|
455
|
+
)
|
|
456
|
+
}
|
|
457
|
+
for (const change of changes) {
|
|
458
|
+
await submitChange(change)
|
|
310
459
|
}
|
|
311
460
|
}
|
|
312
461
|
|
|
462
|
+
const submitChange = async (
|
|
463
|
+
change: AddFeatureChange | LocationStartChange | LocationEndChange,
|
|
464
|
+
) => {
|
|
465
|
+
await apolloSessionModel.apolloDataStore.changeManager.submit(change)
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
const handleCreateNewGeneChange = (
|
|
469
|
+
e: React.ChangeEvent<HTMLInputElement>,
|
|
470
|
+
) => {
|
|
471
|
+
setCreateNewGene(e.target.checked)
|
|
472
|
+
}
|
|
473
|
+
|
|
313
474
|
return (
|
|
314
475
|
<Dialog
|
|
315
476
|
open
|
|
@@ -332,7 +493,7 @@ export function CreateApolloAnnotation({
|
|
|
332
493
|
onChange={handleParentFeatureCheck}
|
|
333
494
|
/>
|
|
334
495
|
}
|
|
335
|
-
label={`${getFeatureNameOrId(annotationFeature
|
|
496
|
+
label={`${getFeatureNameOrId(annotationFeature)} (${annotationFeature.min + 1}..${annotationFeature.max})`}
|
|
336
497
|
/>
|
|
337
498
|
)}
|
|
338
499
|
{annotationFeature.children && (
|
|
@@ -351,7 +512,7 @@ export function CreateApolloAnnotation({
|
|
|
351
512
|
}}
|
|
352
513
|
/>
|
|
353
514
|
}
|
|
354
|
-
label={`${getFeatureNameOrId(child
|
|
515
|
+
label={`${getFeatureNameOrId(child)} (${child.min + 1}..${child.max})`}
|
|
355
516
|
/>
|
|
356
517
|
))}
|
|
357
518
|
</Box>
|
|
@@ -361,26 +522,49 @@ export function CreateApolloAnnotation({
|
|
|
361
522
|
((!parentFeatureChecked && checkedChildrens.length > 0) ||
|
|
362
523
|
(parentFeatureChecked &&
|
|
363
524
|
isTranscript(annotationFeature, apolloSessionModel))) && (
|
|
364
|
-
<
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
>
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
525
|
+
<div
|
|
526
|
+
style={{
|
|
527
|
+
border: '1px solid #ccc',
|
|
528
|
+
marginTop: 20,
|
|
529
|
+
padding: 10,
|
|
530
|
+
borderRadius: 5,
|
|
531
|
+
}}
|
|
532
|
+
>
|
|
533
|
+
<Box sx={{ ml: 3 }}>
|
|
534
|
+
<Typography variant="caption" fontSize={12}>
|
|
535
|
+
Select the destination feature to copy the selected features
|
|
536
|
+
</Typography>
|
|
537
|
+
|
|
538
|
+
<Box sx={{ mt: 1 }}>
|
|
539
|
+
<Select
|
|
540
|
+
labelId="label"
|
|
541
|
+
style={{ width: '100%' }}
|
|
542
|
+
value={selectedDestinationFeature?._id ?? ''}
|
|
543
|
+
onChange={handleDestinationFeatureChange}
|
|
544
|
+
disabled={createNewGene}
|
|
545
|
+
>
|
|
546
|
+
{destinationFeatures.map((f) => (
|
|
547
|
+
<MenuItem key={f._id} value={f._id}>
|
|
548
|
+
{`${getFeatureNameOrId(f)} (${f.min + 1}..${f.max})`}
|
|
549
|
+
</MenuItem>
|
|
550
|
+
))}
|
|
551
|
+
</Select>
|
|
552
|
+
</Box>
|
|
382
553
|
</Box>
|
|
383
|
-
|
|
554
|
+
<Box sx={{ ml: 3 }}>
|
|
555
|
+
<FormGroup>
|
|
556
|
+
<FormControlLabel
|
|
557
|
+
control={
|
|
558
|
+
<Checkbox
|
|
559
|
+
checked={createNewGene}
|
|
560
|
+
onChange={handleCreateNewGeneChange}
|
|
561
|
+
/>
|
|
562
|
+
}
|
|
563
|
+
label="Create new gene"
|
|
564
|
+
/>
|
|
565
|
+
</FormGroup>
|
|
566
|
+
</Box>
|
|
567
|
+
</div>
|
|
384
568
|
)}
|
|
385
569
|
</DialogContent>
|
|
386
570
|
<DialogActions>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/unbound-method */
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-misused-promises */
|
|
3
3
|
import { DeleteAssemblyChange } from '@apollo-annotation/shared'
|
|
4
|
-
import { Assembly } from '@jbrowse/core/assemblyManager/assembly'
|
|
4
|
+
import { type Assembly } from '@jbrowse/core/assemblyManager/assembly'
|
|
5
5
|
import {
|
|
6
6
|
Button,
|
|
7
7
|
Checkbox,
|
|
@@ -12,19 +12,20 @@ import {
|
|
|
12
12
|
FormGroup,
|
|
13
13
|
MenuItem,
|
|
14
14
|
Select,
|
|
15
|
-
SelectChangeEvent,
|
|
15
|
+
type SelectChangeEvent,
|
|
16
16
|
} from '@mui/material'
|
|
17
17
|
import { getRoot } from 'mobx-state-tree'
|
|
18
18
|
import React, { useEffect, useState } from 'react'
|
|
19
19
|
|
|
20
|
-
import { ApolloInternetAccountModel } from '../ApolloInternetAccount/model'
|
|
20
|
+
import { type ApolloInternetAccountModel } from '../ApolloInternetAccount/model'
|
|
21
21
|
import {
|
|
22
|
-
ApolloInternetAccount,
|
|
23
|
-
CollaborationServerDriver,
|
|
22
|
+
type ApolloInternetAccount,
|
|
23
|
+
type CollaborationServerDriver,
|
|
24
24
|
} from '../BackendDrivers'
|
|
25
|
-
import { ChangeManager } from '../ChangeManager'
|
|
26
|
-
import { ApolloSessionModel } from '../session'
|
|
27
|
-
import { ApolloRootModel } from '../types'
|
|
25
|
+
import { type ChangeManager } from '../ChangeManager'
|
|
26
|
+
import { type ApolloSessionModel } from '../session'
|
|
27
|
+
import { type ApolloRootModel } from '../types'
|
|
28
|
+
|
|
28
29
|
import { Dialog } from './Dialog'
|
|
29
30
|
|
|
30
31
|
interface DeleteAssemblyProps {
|