@apollo-annotation/jbrowse-plugin-apollo 0.3.6 → 0.3.8
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 +4603 -2045
- package/dist/index.esm.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.development.js +4611 -2039
- 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 +9387 -4016
- 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 +15 -15
- package/src/ApolloInternetAccount/model.ts +48 -13
- package/src/BackendDrivers/CollaborationServerDriver.ts +23 -2
- package/src/ChangeManager.ts +42 -18
- package/src/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.tsx +64 -5
- package/src/FeatureDetailsWidget/Attributes.tsx +8 -3
- package/src/FeatureDetailsWidget/TranscriptSequence.tsx +70 -81
- package/src/FeatureDetailsWidget/TranscriptWidgetEditLocation.tsx +946 -190
- package/src/FeatureDetailsWidget/TranscriptWidgetSummary.tsx +4 -0
- package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +61 -73
- package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +55 -211
- package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +562 -108
- package/src/LinearApolloDisplay/glyphs/GenericChildGlyph.ts +78 -14
- package/src/LinearApolloDisplay/glyphs/Glyph.ts +15 -9
- package/src/LinearApolloDisplay/stateModel/base.ts +63 -43
- package/src/LinearApolloDisplay/stateModel/layouts.ts +3 -2
- package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +79 -292
- package/src/LinearApolloDisplay/stateModel/rendering.ts +45 -344
- package/src/LinearApolloReferenceSequenceDisplay/components/LinearApolloReferenceSequenceDisplay.tsx +87 -0
- package/src/LinearApolloReferenceSequenceDisplay/components/index.ts +1 -0
- package/src/LinearApolloReferenceSequenceDisplay/configSchema.ts +7 -0
- package/src/LinearApolloReferenceSequenceDisplay/index.ts +3 -0
- package/src/LinearApolloReferenceSequenceDisplay/stateModel/base.ts +227 -0
- package/src/LinearApolloReferenceSequenceDisplay/stateModel/index.ts +25 -0
- package/src/LinearApolloReferenceSequenceDisplay/stateModel/rendering.ts +481 -0
- package/src/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.tsx +102 -40
- package/src/LinearApolloSixFrameDisplay/components/TrackLines.tsx +12 -20
- package/src/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.ts +382 -243
- package/src/LinearApolloSixFrameDisplay/glyphs/Glyph.ts +12 -8
- package/src/LinearApolloSixFrameDisplay/stateModel/base.ts +83 -4
- package/src/LinearApolloSixFrameDisplay/stateModel/layouts.ts +23 -11
- package/src/LinearApolloSixFrameDisplay/stateModel/mouseEvents.ts +118 -123
- package/src/LinearApolloSixFrameDisplay/stateModel/rendering.ts +53 -63
- package/src/OntologyManager/index.ts +4 -1
- package/src/TabularEditor/HybridGrid/Feature.tsx +20 -14
- package/src/TabularEditor/HybridGrid/HybridGrid.tsx +7 -5
- package/src/TabularEditor/HybridGrid/featureContextMenuItems.ts +108 -16
- package/src/components/AddAssembly.tsx +1 -1
- package/src/components/AddAssemblyAliases.tsx +114 -0
- package/src/components/AddChildFeature.tsx +7 -7
- package/src/components/AddFeature.tsx +20 -15
- package/src/components/AddRefSeqAliases.tsx +9 -9
- package/src/components/CopyFeature.tsx +4 -4
- package/src/components/CreateApolloAnnotation.tsx +335 -151
- package/src/components/DeleteAssembly.tsx +1 -1
- package/src/components/DeleteFeature.tsx +358 -11
- package/src/components/DownloadGFF3.tsx +20 -1
- package/src/components/EditZoomThresholdDialog.tsx +69 -0
- package/src/components/FilterFeatures.tsx +7 -7
- package/src/components/FilterTranscripts.tsx +86 -0
- package/src/components/ImportFeatures.tsx +1 -1
- package/src/components/ManageChecks.tsx +1 -1
- package/src/components/MergeExons.tsx +193 -0
- package/src/components/MergeTranscripts.tsx +182 -0
- package/src/components/OntologyTermMultiSelect.tsx +11 -11
- package/src/components/OpenLocalFile.tsx +11 -7
- package/src/components/SplitExon.tsx +134 -0
- package/src/components/ViewCheckResults.tsx +1 -1
- package/src/components/index.ts +4 -0
- package/src/config.ts +11 -0
- package/src/extensions/annotationFromJBrowseFeature.ts +2 -0
- package/src/extensions/annotationFromPileup.ts +99 -89
- package/src/index.ts +42 -105
- package/src/makeDisplayComponent.tsx +0 -1
- package/src/menus/index.ts +1 -0
- package/src/{ApolloInternetAccount/addMenuItems.ts → menus/topLevelMenu.ts} +60 -33
- package/src/menus/topLevelMenuAdmin.ts +154 -0
- package/src/session/session.ts +163 -104
- package/src/util/annotationFeatureUtils.ts +59 -0
- package/src/util/copyToClipboard.ts +21 -0
- package/src/util/displayUtils.ts +149 -0
- package/src/util/glyphUtils.ts +201 -0
- package/src/util/index.ts +2 -0
- package/src/util/mouseEventsUtils.ts +145 -0
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
import type PluginManager from '@jbrowse/core/PluginManager'
|
|
3
3
|
import { type AnyConfigurationSchemaType } from '@jbrowse/core/configuration/configurationSchema'
|
|
4
4
|
import { doesIntersect2 } from '@jbrowse/core/util'
|
|
5
|
-
import { type Theme } from '@mui/material'
|
|
5
|
+
import { type Theme, createTheme } from '@mui/material'
|
|
6
6
|
import { autorun } from 'mobx'
|
|
7
|
-
import { type Instance, addDisposer } from 'mobx-state-tree'
|
|
7
|
+
import { type Instance, addDisposer, types } from 'mobx-state-tree'
|
|
8
8
|
|
|
9
9
|
import { type ApolloSessionModel } from '../../session'
|
|
10
10
|
|
|
11
11
|
import { layoutsModelFactory } from './layouts'
|
|
12
12
|
|
|
13
|
-
export function
|
|
13
|
+
export function renderingModelFactory(
|
|
14
14
|
pluginManager: PluginManager,
|
|
15
15
|
configSchema: AnyConfigurationSchemaType,
|
|
16
16
|
) {
|
|
@@ -23,23 +23,24 @@ export function renderingModelIntermediateFactory(
|
|
|
23
23
|
'LinearApolloSixFrameDisplayRendering',
|
|
24
24
|
)
|
|
25
25
|
.props({
|
|
26
|
-
sequenceRowHeight: 15,
|
|
27
26
|
apolloRowHeight: 20,
|
|
28
27
|
detailsMinHeight: 200,
|
|
29
28
|
detailsHeight: 200,
|
|
30
|
-
lastRowTooltipBufferHeight:
|
|
29
|
+
lastRowTooltipBufferHeight: 120,
|
|
31
30
|
isShown: true,
|
|
31
|
+
filteredTranscripts: types.array(types.string),
|
|
32
32
|
})
|
|
33
33
|
.volatile(() => ({
|
|
34
34
|
canvas: null as HTMLCanvasElement | null,
|
|
35
35
|
overlayCanvas: null as HTMLCanvasElement | null,
|
|
36
36
|
collaboratorCanvas: null as HTMLCanvasElement | null,
|
|
37
|
-
theme:
|
|
37
|
+
theme: createTheme(),
|
|
38
38
|
}))
|
|
39
39
|
.views((self) => ({
|
|
40
40
|
get featuresHeight() {
|
|
41
|
+
const featureLabelSpacer = self.showFeatureLabels ? 2 : 1
|
|
41
42
|
return (
|
|
42
|
-
(self.highestRow + 1) * self.apolloRowHeight +
|
|
43
|
+
featureLabelSpacer * ((self.highestRow + 1) * self.apolloRowHeight) +
|
|
43
44
|
self.lastRowTooltipBufferHeight
|
|
44
45
|
)
|
|
45
46
|
},
|
|
@@ -68,6 +69,8 @@ export function renderingModelIntermediateFactory(
|
|
|
68
69
|
setTheme(theme: Theme) {
|
|
69
70
|
self.theme = theme
|
|
70
71
|
},
|
|
72
|
+
}))
|
|
73
|
+
.actions((self) => ({
|
|
71
74
|
afterAttach() {
|
|
72
75
|
addDisposer(
|
|
73
76
|
self,
|
|
@@ -128,69 +131,56 @@ export function renderingModelIntermediateFactory(
|
|
|
128
131
|
{ name: 'LinearApolloSixFrameDisplayRenderCollaborators' },
|
|
129
132
|
),
|
|
130
133
|
)
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
renderingModelIntermediateFactory(pluginManager, configSchema)
|
|
141
|
-
|
|
142
|
-
return LinearApolloSixFrameDisplayRendering.actions((self) => ({
|
|
143
|
-
afterAttach() {
|
|
144
|
-
addDisposer(
|
|
145
|
-
self,
|
|
146
|
-
autorun(
|
|
147
|
-
() => {
|
|
148
|
-
const { canvas, featureLayouts, featuresHeight, lgv } = self
|
|
149
|
-
if (!lgv.initialized || self.regionCannotBeRendered()) {
|
|
150
|
-
return
|
|
151
|
-
}
|
|
152
|
-
const { displayedRegions, dynamicBlocks } = lgv
|
|
134
|
+
addDisposer(
|
|
135
|
+
self,
|
|
136
|
+
autorun(
|
|
137
|
+
() => {
|
|
138
|
+
const { canvas, featureLayouts, featuresHeight, lgv } = self
|
|
139
|
+
if (!lgv.initialized || self.regionCannotBeRendered()) {
|
|
140
|
+
return
|
|
141
|
+
}
|
|
142
|
+
const { displayedRegions, dynamicBlocks } = lgv
|
|
153
143
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
144
|
+
const ctx = canvas?.getContext('2d')
|
|
145
|
+
if (!ctx) {
|
|
146
|
+
return
|
|
147
|
+
}
|
|
148
|
+
ctx.clearRect(0, 0, dynamicBlocks.totalWidthPx, featuresHeight)
|
|
149
|
+
for (const [idx, featureLayout] of featureLayouts.entries()) {
|
|
150
|
+
const displayedRegion = displayedRegions[idx]
|
|
151
|
+
for (const [row, featureLayoutRow] of featureLayout.entries()) {
|
|
152
|
+
for (const { feature } of featureLayoutRow) {
|
|
153
|
+
if (!feature.looksLikeGene) {
|
|
154
|
+
continue
|
|
155
|
+
}
|
|
156
|
+
if (
|
|
157
|
+
!doesIntersect2(
|
|
158
|
+
displayedRegion.start,
|
|
159
|
+
displayedRegion.end,
|
|
160
|
+
feature.min,
|
|
161
|
+
feature.max,
|
|
162
|
+
)
|
|
163
|
+
) {
|
|
164
|
+
continue
|
|
165
|
+
}
|
|
166
|
+
const { topLevelFeature } = feature
|
|
167
|
+
const glyph = self.getGlyph(topLevelFeature)
|
|
168
|
+
if (glyph !== undefined) {
|
|
169
|
+
glyph.draw(ctx, topLevelFeature, row, self, idx)
|
|
170
|
+
}
|
|
180
171
|
}
|
|
181
172
|
}
|
|
182
173
|
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
)
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
}))
|
|
174
|
+
},
|
|
175
|
+
{ name: 'LinearApolloSixFrameDisplayRenderFeatures' },
|
|
176
|
+
),
|
|
177
|
+
)
|
|
178
|
+
},
|
|
179
|
+
}))
|
|
190
180
|
}
|
|
191
181
|
|
|
192
182
|
export type LinearApolloSixFrameDisplayRenderingModel = ReturnType<
|
|
193
|
-
typeof
|
|
183
|
+
typeof renderingModelFactory
|
|
194
184
|
>
|
|
195
185
|
// eslint disable because of
|
|
196
186
|
// https://mobx-state-tree.js.org/tips/typescript#using-a-mst-type-at-design-time
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
flow,
|
|
16
16
|
getRoot,
|
|
17
17
|
getSnapshot,
|
|
18
|
+
isAlive,
|
|
18
19
|
types,
|
|
19
20
|
} from 'mobx-state-tree'
|
|
20
21
|
|
|
@@ -79,7 +80,9 @@ export const OntologyRecordType = types
|
|
|
79
80
|
const equivalents: string[] = terms
|
|
80
81
|
.map((term) => term.lbl)
|
|
81
82
|
.filter((term) => term != undefined)
|
|
82
|
-
self
|
|
83
|
+
if (isAlive(self)) {
|
|
84
|
+
self.setEquivalentTypes(type, equivalents)
|
|
85
|
+
}
|
|
83
86
|
}),
|
|
84
87
|
}))
|
|
85
88
|
.actions((self) => ({
|
|
@@ -10,6 +10,7 @@ import { makeStyles } from 'tss-react/mui'
|
|
|
10
10
|
import { isOntologyClass } from '../../OntologyManager'
|
|
11
11
|
import type OntologyStore from '../../OntologyManager/OntologyStore'
|
|
12
12
|
import { OntologyTermAutocomplete } from '../../components/OntologyTermAutocomplete'
|
|
13
|
+
import { navToFeatureCenter } from '../../util'
|
|
13
14
|
import { type DisplayStateModel } from '../types'
|
|
14
15
|
|
|
15
16
|
import {
|
|
@@ -68,6 +69,8 @@ function makeContextMenuItems(
|
|
|
68
69
|
selectedFeature,
|
|
69
70
|
session,
|
|
70
71
|
setSelectedFeature,
|
|
72
|
+
filteredTranscripts,
|
|
73
|
+
updateFilteredTranscripts,
|
|
71
74
|
} = display
|
|
72
75
|
return featureContextMenuItems(
|
|
73
76
|
feature,
|
|
@@ -77,15 +80,18 @@ function makeContextMenuItems(
|
|
|
77
80
|
setSelectedFeature,
|
|
78
81
|
session,
|
|
79
82
|
changeManager,
|
|
83
|
+
filteredTranscripts,
|
|
84
|
+
updateFilteredTranscripts,
|
|
80
85
|
)
|
|
81
86
|
}
|
|
82
87
|
|
|
83
|
-
function
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
88
|
+
function navigateHere(
|
|
89
|
+
displayState: DisplayStateModel,
|
|
90
|
+
feature: AnnotationFeature,
|
|
91
|
+
) {
|
|
92
|
+
displayState.lgv.navTo(
|
|
93
|
+
navToFeatureCenter(feature, 0.1, displayState.lgv.totalBp),
|
|
94
|
+
)
|
|
89
95
|
}
|
|
90
96
|
|
|
91
97
|
export const Feature = observer(function Feature({
|
|
@@ -107,8 +113,8 @@ export const Feature = observer(function Feature({
|
|
|
107
113
|
}) {
|
|
108
114
|
const { classes } = useStyles()
|
|
109
115
|
const {
|
|
110
|
-
apolloHover,
|
|
111
116
|
changeManager,
|
|
117
|
+
hoveredFeature,
|
|
112
118
|
selectedFeature,
|
|
113
119
|
session,
|
|
114
120
|
tabularEditor: tabularEditorState,
|
|
@@ -130,12 +136,7 @@ export const Feature = observer(function Feature({
|
|
|
130
136
|
<>
|
|
131
137
|
<tr
|
|
132
138
|
onMouseEnter={(_e) => {
|
|
133
|
-
displayState.
|
|
134
|
-
feature,
|
|
135
|
-
topLevelFeature: getTopLevelFeature(feature),
|
|
136
|
-
// @ts-expect-error TODO fix in future when moving hover logic to session.
|
|
137
|
-
glyph: displayState.getGlyph(getTopLevelFeature(feature)),
|
|
138
|
-
})
|
|
139
|
+
displayState.setHoveredFeature({ feature, bp: min })
|
|
139
140
|
}}
|
|
140
141
|
className={
|
|
141
142
|
classes.feature +
|
|
@@ -149,6 +150,10 @@ export const Feature = observer(function Feature({
|
|
|
149
150
|
e.stopPropagation()
|
|
150
151
|
displayState.setSelectedFeature(feature)
|
|
151
152
|
}}
|
|
153
|
+
onDoubleClick={() => {
|
|
154
|
+
displayState.setSelectedFeature(feature)
|
|
155
|
+
navigateHere(displayState, feature)
|
|
156
|
+
}}
|
|
152
157
|
onContextMenu={(e) => {
|
|
153
158
|
e.preventDefault()
|
|
154
159
|
setContextMenu({
|
|
@@ -254,7 +259,8 @@ export const Feature = observer(function Feature({
|
|
|
254
259
|
return text.includes(filterText)
|
|
255
260
|
})
|
|
256
261
|
.map(([featureId, childFeature]) => {
|
|
257
|
-
const childHovered =
|
|
262
|
+
const childHovered =
|
|
263
|
+
hoveredFeature?.feature._id === childFeature._id
|
|
258
264
|
const childSelected = selectedFeature?._id === childFeature._id
|
|
259
265
|
return (
|
|
260
266
|
<Feature
|
|
@@ -37,7 +37,7 @@ const HybridGrid = observer(function HybridGrid({
|
|
|
37
37
|
}: {
|
|
38
38
|
model: DisplayStateModel
|
|
39
39
|
}) {
|
|
40
|
-
const {
|
|
40
|
+
const { hoveredFeature, seenFeatures, selectedFeature, tabularEditor } = model
|
|
41
41
|
const theme = useTheme()
|
|
42
42
|
const { classes } = useStyles()
|
|
43
43
|
const scrollContainerRef = useRef<HTMLDivElement>(null)
|
|
@@ -96,7 +96,7 @@ const HybridGrid = observer(function HybridGrid({
|
|
|
96
96
|
})
|
|
97
97
|
.map(([featureId, feature]) => {
|
|
98
98
|
const isSelected = selectedFeature?._id === featureId
|
|
99
|
-
const isHovered =
|
|
99
|
+
const isHovered = hoveredFeature?.feature._id === featureId
|
|
100
100
|
return (
|
|
101
101
|
<Feature
|
|
102
102
|
key={featureId}
|
|
@@ -121,9 +121,11 @@ const HybridGrid = observer(function HybridGrid({
|
|
|
121
121
|
onClose={() => {
|
|
122
122
|
setContextMenu(null)
|
|
123
123
|
}}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
124
|
+
slotProps={{
|
|
125
|
+
transition: {
|
|
126
|
+
onExit: () => {
|
|
127
|
+
setContextMenu(null)
|
|
128
|
+
},
|
|
127
129
|
},
|
|
128
130
|
}}
|
|
129
131
|
style={{ zIndex: theme.zIndex.tooltip }}
|
|
@@ -7,7 +7,14 @@ import {
|
|
|
7
7
|
} from '@jbrowse/core/util'
|
|
8
8
|
|
|
9
9
|
import { type ChangeManager } from '../../ChangeManager'
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
AddChildFeature,
|
|
12
|
+
CopyFeature,
|
|
13
|
+
DeleteFeature,
|
|
14
|
+
MergeExons,
|
|
15
|
+
MergeTranscripts,
|
|
16
|
+
SplitExon,
|
|
17
|
+
} from '../../components'
|
|
11
18
|
import { type ApolloSessionModel } from '../../session'
|
|
12
19
|
import { getApolloInternetAccount } from '../../util'
|
|
13
20
|
|
|
@@ -19,6 +26,8 @@ export function featureContextMenuItems(
|
|
|
19
26
|
setSelectedFeature: (f: AnnotationFeature | undefined) => void,
|
|
20
27
|
session: ApolloSessionModel,
|
|
21
28
|
changeManager: ChangeManager,
|
|
29
|
+
filteredTranscripts: string[],
|
|
30
|
+
updateFilteredTranscripts: (forms: string[]) => void,
|
|
22
31
|
) {
|
|
23
32
|
const internetAccount = getApolloInternetAccount(session)
|
|
24
33
|
const role = internetAccount ? internetAccount.role : 'admin'
|
|
@@ -26,6 +35,7 @@ export function featureContextMenuItems(
|
|
|
26
35
|
const readOnly = !(role && ['admin', 'user'].includes(role))
|
|
27
36
|
const menuItems: MenuItem[] = []
|
|
28
37
|
if (feature) {
|
|
38
|
+
const featureID = feature.attributes.get('gff_id')?.toString()
|
|
29
39
|
const sourceAssemblyId = getAssemblyId(region.assemblyName)
|
|
30
40
|
const currentAssemblyId = getAssemblyId(region.assemblyName)
|
|
31
41
|
menuItems.push(
|
|
@@ -111,6 +121,72 @@ export function featureContextMenuItems(
|
|
|
111
121
|
)
|
|
112
122
|
},
|
|
113
123
|
},
|
|
124
|
+
{
|
|
125
|
+
label: 'Merge transcripts',
|
|
126
|
+
disabled: !admin,
|
|
127
|
+
onClick: () => {
|
|
128
|
+
;(session as unknown as AbstractSessionModel).queueDialog(
|
|
129
|
+
(doneCallback) => [
|
|
130
|
+
MergeTranscripts,
|
|
131
|
+
{
|
|
132
|
+
session,
|
|
133
|
+
handleClose: () => {
|
|
134
|
+
doneCallback()
|
|
135
|
+
},
|
|
136
|
+
changeManager,
|
|
137
|
+
sourceFeature: feature,
|
|
138
|
+
sourceAssemblyId: currentAssemblyId,
|
|
139
|
+
selectedFeature,
|
|
140
|
+
setSelectedFeature,
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
)
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
label: 'Merge exons',
|
|
148
|
+
disabled: !admin,
|
|
149
|
+
onClick: () => {
|
|
150
|
+
;(session as unknown as AbstractSessionModel).queueDialog(
|
|
151
|
+
(doneCallback) => [
|
|
152
|
+
MergeExons,
|
|
153
|
+
{
|
|
154
|
+
session,
|
|
155
|
+
handleClose: () => {
|
|
156
|
+
doneCallback()
|
|
157
|
+
},
|
|
158
|
+
changeManager,
|
|
159
|
+
sourceFeature: feature,
|
|
160
|
+
sourceAssemblyId: currentAssemblyId,
|
|
161
|
+
selectedFeature,
|
|
162
|
+
setSelectedFeature,
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
)
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
label: 'Split exon',
|
|
170
|
+
disabled: !admin,
|
|
171
|
+
onClick: () => {
|
|
172
|
+
;(session as unknown as AbstractSessionModel).queueDialog(
|
|
173
|
+
(doneCallback) => [
|
|
174
|
+
SplitExon,
|
|
175
|
+
{
|
|
176
|
+
session,
|
|
177
|
+
handleClose: () => {
|
|
178
|
+
doneCallback()
|
|
179
|
+
},
|
|
180
|
+
changeManager,
|
|
181
|
+
sourceFeature: feature,
|
|
182
|
+
sourceAssemblyId: currentAssemblyId,
|
|
183
|
+
selectedFeature,
|
|
184
|
+
setSelectedFeature,
|
|
185
|
+
},
|
|
186
|
+
],
|
|
187
|
+
)
|
|
188
|
+
},
|
|
189
|
+
},
|
|
114
190
|
)
|
|
115
191
|
const { featureTypeOntology } = session.apolloDataStore.ontologyManager
|
|
116
192
|
if (!featureTypeOntology) {
|
|
@@ -121,22 +197,38 @@ export function featureContextMenuItems(
|
|
|
121
197
|
featureTypeOntology.isTypeOf(feature.type, 'pseudogenic_transcript')) &&
|
|
122
198
|
isSessionModelWithWidgets(session)
|
|
123
199
|
) {
|
|
124
|
-
menuItems.push(
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
200
|
+
menuItems.push(
|
|
201
|
+
{
|
|
202
|
+
label: 'Edit transcript details',
|
|
203
|
+
onClick: () => {
|
|
204
|
+
const apolloTranscriptWidget = session.addWidget(
|
|
205
|
+
'ApolloTranscriptDetails',
|
|
206
|
+
'apolloTranscriptDetails',
|
|
207
|
+
{
|
|
208
|
+
feature,
|
|
209
|
+
assembly: currentAssemblyId,
|
|
210
|
+
changeManager,
|
|
211
|
+
refName: region.refName,
|
|
212
|
+
},
|
|
213
|
+
)
|
|
214
|
+
session.showWidget(apolloTranscriptWidget)
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
label: 'Visible',
|
|
219
|
+
type: 'checkbox',
|
|
220
|
+
checked:
|
|
221
|
+
featureID && filteredTranscripts.includes(featureID) ? false : true,
|
|
222
|
+
onClick: () => {
|
|
223
|
+
if (featureID) {
|
|
224
|
+
const newForms = filteredTranscripts.includes(featureID)
|
|
225
|
+
? filteredTranscripts.filter((form) => form !== featureID)
|
|
226
|
+
: [...filteredTranscripts, featureID]
|
|
227
|
+
updateFilteredTranscripts(newForms)
|
|
228
|
+
}
|
|
229
|
+
},
|
|
138
230
|
},
|
|
139
|
-
|
|
231
|
+
)
|
|
140
232
|
}
|
|
141
233
|
}
|
|
142
234
|
return menuItems
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { AddAssemblyAliasesChange } from '@apollo-annotation/shared'
|
|
2
|
+
import { Box, DialogContent, DialogContentText } from '@mui/material'
|
|
3
|
+
import { DataGrid, type GridColDef, type GridRowModel } from '@mui/x-data-grid'
|
|
4
|
+
import React from 'react'
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
type ApolloInternetAccount,
|
|
8
|
+
type CollaborationServerDriver,
|
|
9
|
+
} from '../BackendDrivers'
|
|
10
|
+
import { type ChangeManager } from '../ChangeManager'
|
|
11
|
+
import { type ApolloSessionModel } from '../session'
|
|
12
|
+
|
|
13
|
+
import { Dialog } from './Dialog'
|
|
14
|
+
|
|
15
|
+
interface AddAssemblyAliasProps {
|
|
16
|
+
session: ApolloSessionModel
|
|
17
|
+
handleClose: () => void
|
|
18
|
+
changeManager: ChangeManager
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const columns: GridColDef[] = [
|
|
22
|
+
{
|
|
23
|
+
field: 'name',
|
|
24
|
+
headerName: 'Assembly Name',
|
|
25
|
+
width: 150,
|
|
26
|
+
editable: false,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
field: 'aliases',
|
|
30
|
+
headerName: 'Aliases',
|
|
31
|
+
width: 300,
|
|
32
|
+
editable: true,
|
|
33
|
+
},
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
interface AssemblyAlias {
|
|
37
|
+
id: string
|
|
38
|
+
name: string
|
|
39
|
+
aliases: string
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function AddAssemblyAliases({
|
|
43
|
+
changeManager,
|
|
44
|
+
handleClose,
|
|
45
|
+
session,
|
|
46
|
+
}: AddAssemblyAliasProps) {
|
|
47
|
+
const { apolloDataStore } = session
|
|
48
|
+
const { collaborationServerDriver } = apolloDataStore as {
|
|
49
|
+
collaborationServerDriver: CollaborationServerDriver
|
|
50
|
+
getInternetAccount(
|
|
51
|
+
assemblyName?: string,
|
|
52
|
+
internetAccountId?: string,
|
|
53
|
+
): ApolloInternetAccount
|
|
54
|
+
}
|
|
55
|
+
const assemblies = collaborationServerDriver.getAssemblies()
|
|
56
|
+
|
|
57
|
+
const rows: AssemblyAlias[] = assemblies.map((assembly) => {
|
|
58
|
+
return {
|
|
59
|
+
id: assembly.name,
|
|
60
|
+
name: assembly.displayName,
|
|
61
|
+
aliases: assembly.aliases.join(', '),
|
|
62
|
+
} as AssemblyAlias
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
const [errorMessage, setErrorMessage] = React.useState('')
|
|
66
|
+
|
|
67
|
+
const processRowUpdate = (newRow: GridRowModel, _oldRow: GridRowModel) => {
|
|
68
|
+
const change = new AddAssemblyAliasesChange({
|
|
69
|
+
typeName: 'AddAssemblyAliasesChange',
|
|
70
|
+
assembly: newRow.id as string,
|
|
71
|
+
aliases: (newRow.aliases as string).split(','),
|
|
72
|
+
})
|
|
73
|
+
void changeManager.submit(change).catch(() => {
|
|
74
|
+
setErrorMessage('Error submitting change')
|
|
75
|
+
})
|
|
76
|
+
handleClose()
|
|
77
|
+
return newRow
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<Dialog
|
|
82
|
+
open
|
|
83
|
+
title="Add assembly aliases"
|
|
84
|
+
handleClose={handleClose}
|
|
85
|
+
maxWidth={'sm'}
|
|
86
|
+
data-testid="add-assembly-alias"
|
|
87
|
+
fullWidth
|
|
88
|
+
>
|
|
89
|
+
<DialogContent style={{ display: 'flex', flexDirection: 'column' }}>
|
|
90
|
+
<Box sx={{ height: 400, width: '100%' }}>
|
|
91
|
+
<DataGrid
|
|
92
|
+
rows={rows}
|
|
93
|
+
columns={columns}
|
|
94
|
+
initialState={{
|
|
95
|
+
pagination: {
|
|
96
|
+
paginationModel: {
|
|
97
|
+
pageSize: 5,
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
}}
|
|
101
|
+
pageSizeOptions={[5]}
|
|
102
|
+
processRowUpdate={processRowUpdate}
|
|
103
|
+
disableRowSelectionOnClick
|
|
104
|
+
/>
|
|
105
|
+
</Box>
|
|
106
|
+
</DialogContent>
|
|
107
|
+
{errorMessage ? (
|
|
108
|
+
<DialogContent>
|
|
109
|
+
<DialogContentText color="error">{errorMessage}</DialogContentText>
|
|
110
|
+
</DialogContent>
|
|
111
|
+
) : null}
|
|
112
|
+
</Dialog>
|
|
113
|
+
)
|
|
114
|
+
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/unbound-method */
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
import { type AnnotationFeature } from '@apollo-annotation/mst'
|
|
4
4
|
import { AddFeatureChange } from '@apollo-annotation/shared'
|
|
5
|
-
import { type AbstractSessionModel } from '@jbrowse/core/util'
|
|
6
5
|
import {
|
|
7
6
|
Button,
|
|
8
7
|
DialogActions,
|
|
@@ -37,7 +36,6 @@ export function AddChildFeature({
|
|
|
37
36
|
sourceAssemblyId,
|
|
38
37
|
sourceFeature,
|
|
39
38
|
}: AddChildFeatureProps) {
|
|
40
|
-
const { notify } = session as unknown as AbstractSessionModel
|
|
41
39
|
const [end, setEnd] = useState(String(sourceFeature.max))
|
|
42
40
|
const [start, setStart] = useState(String(sourceFeature.min + 1))
|
|
43
41
|
const [type, setType] = useState('')
|
|
@@ -63,15 +61,16 @@ export function AddChildFeature({
|
|
|
63
61
|
return terms
|
|
64
62
|
}
|
|
65
63
|
|
|
66
|
-
|
|
64
|
+
function onSubmit(event: React.FormEvent<HTMLFormElement>) {
|
|
67
65
|
event.preventDefault()
|
|
68
66
|
setErrorMessage('')
|
|
67
|
+
const _id = new ObjectID().toHexString()
|
|
69
68
|
const change = new AddFeatureChange({
|
|
70
69
|
changedIds: [sourceFeature._id],
|
|
71
70
|
typeName: 'AddFeatureChange',
|
|
72
71
|
assembly: sourceAssemblyId,
|
|
73
72
|
addedFeature: {
|
|
74
|
-
_id
|
|
73
|
+
_id,
|
|
75
74
|
refSeq: sourceFeature.refSeq,
|
|
76
75
|
min: Number(start) - 1,
|
|
77
76
|
max: Number(end),
|
|
@@ -79,8 +78,9 @@ export function AddChildFeature({
|
|
|
79
78
|
},
|
|
80
79
|
parentFeatureId: sourceFeature._id,
|
|
81
80
|
})
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
void changeManager.submit(change).then(() => {
|
|
82
|
+
session.apolloSetSelectedFeature(_id)
|
|
83
|
+
})
|
|
84
84
|
handleClose()
|
|
85
85
|
event.preventDefault()
|
|
86
86
|
}
|