@apollo-annotation/jbrowse-plugin-apollo 0.1.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/README.md +76 -0
- package/dist/index.esm.js +10248 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +7 -0
- package/dist/jbrowse-plugin-apollo.cjs.development.js +10298 -0
- package/dist/jbrowse-plugin-apollo.cjs.development.js.map +1 -0
- package/dist/jbrowse-plugin-apollo.cjs.production.min.js +2 -0
- package/dist/jbrowse-plugin-apollo.cjs.production.min.js.map +1 -0
- package/dist/jbrowse-plugin-apollo.umd.development.js +46957 -0
- package/dist/jbrowse-plugin-apollo.umd.development.js.map +1 -0
- package/dist/jbrowse-plugin-apollo.umd.production.min.js +2 -0
- package/dist/jbrowse-plugin-apollo.umd.production.min.js.map +1 -0
- package/package.json +130 -0
- package/src/ApolloInternetAccount/addMenuItems.ts +94 -0
- package/src/ApolloInternetAccount/components/AuthTypeSelector.tsx +121 -0
- package/src/ApolloInternetAccount/components/LoginButtons.tsx +62 -0
- package/src/ApolloInternetAccount/components/LoginIcons.tsx +74 -0
- package/src/ApolloInternetAccount/configSchema.ts +26 -0
- package/src/ApolloInternetAccount/index.ts +2 -0
- package/src/ApolloInternetAccount/model.ts +448 -0
- package/src/ApolloJobModel.ts +117 -0
- package/src/ApolloSequenceAdapter/ApolloSequenceAdapter.ts +186 -0
- package/src/ApolloSequenceAdapter/configSchema.ts +12 -0
- package/src/ApolloSequenceAdapter/index.ts +21 -0
- package/src/ApolloSixFrameRenderer/ApolloSixFrameRenderer.tsx +12 -0
- package/src/ApolloSixFrameRenderer/components/ApolloRendering.tsx +692 -0
- package/src/ApolloSixFrameRenderer/configSchema.ts +7 -0
- package/src/ApolloSixFrameRenderer/index.ts +3 -0
- package/src/ApolloTextSearchAdapter/ApolloTextSearchAdapter.ts +64 -0
- package/src/ApolloTextSearchAdapter/configSchema.ts +24 -0
- package/src/ApolloTextSearchAdapter/index.ts +18 -0
- package/src/BackendDrivers/BackendDriver.ts +31 -0
- package/src/BackendDrivers/CollaborationServerDriver.ts +318 -0
- package/src/BackendDrivers/DesktopFileDriver.ts +170 -0
- package/src/BackendDrivers/InMemoryFileDriver.ts +76 -0
- package/src/BackendDrivers/index.ts +4 -0
- package/src/ChangeManager.ts +148 -0
- package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +248 -0
- package/src/LinearApolloDisplay/components/index.ts +1 -0
- package/src/LinearApolloDisplay/configSchema.ts +16 -0
- package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +422 -0
- package/src/LinearApolloDisplay/glyphs/CanonicalGeneGlyph.ts +1191 -0
- package/src/LinearApolloDisplay/glyphs/GenericChildGlyph.ts +151 -0
- package/src/LinearApolloDisplay/glyphs/Glyph.ts +382 -0
- package/src/LinearApolloDisplay/glyphs/ImplicitExonGeneGlyph.ts +697 -0
- package/src/LinearApolloDisplay/glyphs/index.ts +4 -0
- package/src/LinearApolloDisplay/index.ts +2 -0
- package/src/LinearApolloDisplay/stateModel/base.ts +146 -0
- package/src/LinearApolloDisplay/stateModel/getGlyph.ts +39 -0
- package/src/LinearApolloDisplay/stateModel/glyphs.ts +45 -0
- package/src/LinearApolloDisplay/stateModel/index.ts +20 -0
- package/src/LinearApolloDisplay/stateModel/layouts.ts +230 -0
- package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +513 -0
- package/src/LinearApolloDisplay/stateModel/rendering.ts +441 -0
- package/src/LinearApolloDisplay/stateModel/trackHeightMixin.ts +43 -0
- package/src/LinearApolloDisplay/types.ts +1 -0
- package/src/OntologyManager/OntologyStore/__snapshots__/fulltext.test.ts.snap +208 -0
- package/src/OntologyManager/OntologyStore/__snapshots__/index.test.ts.snap +18846 -0
- package/src/OntologyManager/OntologyStore/fulltext-stopwords.ts +137 -0
- package/src/OntologyManager/OntologyStore/fulltext.test.ts +94 -0
- package/src/OntologyManager/OntologyStore/fulltext.ts +264 -0
- package/src/OntologyManager/OntologyStore/index.test.ts +130 -0
- package/src/OntologyManager/OntologyStore/index.ts +526 -0
- package/src/OntologyManager/OntologyStore/indexeddb-schema.ts +89 -0
- package/src/OntologyManager/OntologyStore/indexeddb-storage.ts +180 -0
- package/src/OntologyManager/OntologyStore/obo-graph-json-schema.ts +110 -0
- package/src/OntologyManager/OntologyStore/prefixes.ts +35 -0
- package/src/OntologyManager/index.ts +173 -0
- package/src/SixFrameFeatureDisplay/components/TrackLines.tsx +19 -0
- package/src/SixFrameFeatureDisplay/components/index.ts +1 -0
- package/src/SixFrameFeatureDisplay/configSchema.ts +21 -0
- package/src/SixFrameFeatureDisplay/index.ts +2 -0
- package/src/SixFrameFeatureDisplay/stateModel.ts +413 -0
- package/src/TabularEditor/HybridGrid/ChangeHandling.ts +88 -0
- package/src/TabularEditor/HybridGrid/Feature.tsx +346 -0
- package/src/TabularEditor/HybridGrid/FeatureAttributes.tsx +34 -0
- package/src/TabularEditor/HybridGrid/Highlight.tsx +40 -0
- package/src/TabularEditor/HybridGrid/HybridGrid.tsx +138 -0
- package/src/TabularEditor/HybridGrid/NumberCell.tsx +77 -0
- package/src/TabularEditor/HybridGrid/ToolBar.tsx +59 -0
- package/src/TabularEditor/HybridGrid/featureContextMenuItems.ts +119 -0
- package/src/TabularEditor/HybridGrid/index.ts +1 -0
- package/src/TabularEditor/TabularEditorPane.tsx +34 -0
- package/src/TabularEditor/index.ts +3 -0
- package/src/TabularEditor/model.ts +44 -0
- package/src/TabularEditor/types.ts +3 -0
- package/src/components/AddAssembly.tsx +464 -0
- package/src/components/AddChildFeature.tsx +247 -0
- package/src/components/AddFeature.tsx +252 -0
- package/src/components/CopyFeature.tsx +328 -0
- package/src/components/DeleteAssembly.tsx +185 -0
- package/src/components/DeleteFeature.tsx +90 -0
- package/src/components/Dialog.tsx +47 -0
- package/src/components/DownloadGFF3.tsx +213 -0
- package/src/components/ImportFeatures.tsx +295 -0
- package/src/components/ManageChecks.tsx +280 -0
- package/src/components/ManageUsers.tsx +218 -0
- package/src/components/ModifyFeatureAttribute.tsx +457 -0
- package/src/components/OntologyTermAutocomplete.tsx +240 -0
- package/src/components/OntologyTermMultiSelect.tsx +349 -0
- package/src/components/OpenLocalFile.tsx +178 -0
- package/src/components/ViewChangeLog.tsx +208 -0
- package/src/components/ViewCheckResults.tsx +151 -0
- package/src/components/index.ts +12 -0
- package/src/config.ts +10 -0
- package/src/declare.d.ts +3 -0
- package/src/extensions/annotationFromPileup.ts +208 -0
- package/src/extensions/index.ts +1 -0
- package/src/index.ts +394 -0
- package/src/makeDisplayComponent.tsx +244 -0
- package/src/session/ClientDataStore.ts +282 -0
- package/src/session/index.ts +1 -0
- package/src/session/session.ts +373 -0
- package/src/types.ts +10 -0
- package/src/util/index.ts +31 -0
- package/src/util/loadAssemblyIntoClient.ts +291 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Button,
|
|
3
|
+
DialogActions,
|
|
4
|
+
DialogContent,
|
|
5
|
+
DialogContentText,
|
|
6
|
+
MenuItem,
|
|
7
|
+
Select,
|
|
8
|
+
SelectChangeEvent,
|
|
9
|
+
} from '@mui/material'
|
|
10
|
+
import {
|
|
11
|
+
DataGrid,
|
|
12
|
+
GridColDef,
|
|
13
|
+
GridRowsProp,
|
|
14
|
+
GridToolbar,
|
|
15
|
+
} from '@mui/x-data-grid'
|
|
16
|
+
import { changeRegistry } from 'apollo-common'
|
|
17
|
+
import { getRoot } from 'mobx-state-tree'
|
|
18
|
+
import React, { useEffect, useState } from 'react'
|
|
19
|
+
import { makeStyles } from 'tss-react/mui'
|
|
20
|
+
|
|
21
|
+
import { ApolloInternetAccountModel } from '../ApolloInternetAccount/model'
|
|
22
|
+
import { ApolloSessionModel } from '../session'
|
|
23
|
+
import { ApolloRootModel } from '../types'
|
|
24
|
+
import { createFetchErrorMessage } from '../util'
|
|
25
|
+
import { Dialog } from './Dialog'
|
|
26
|
+
|
|
27
|
+
interface ViewChangeLogProps {
|
|
28
|
+
session: ApolloSessionModel
|
|
29
|
+
handleClose(): void
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface AssemblyDocument {
|
|
33
|
+
_id: string
|
|
34
|
+
name: string
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const useStyles = makeStyles()((theme) => ({
|
|
38
|
+
changeTextarea: {
|
|
39
|
+
fontFamily: 'monospace',
|
|
40
|
+
width: 600,
|
|
41
|
+
resize: 'none',
|
|
42
|
+
border: `1px solid ${theme.palette.divider}`,
|
|
43
|
+
borderRadius: theme.shape.borderRadius,
|
|
44
|
+
},
|
|
45
|
+
}))
|
|
46
|
+
|
|
47
|
+
export function ViewChangeLog({ handleClose, session }: ViewChangeLogProps) {
|
|
48
|
+
const { internetAccounts } = getRoot<ApolloRootModel>(session)
|
|
49
|
+
const apolloInternetAccount = internetAccounts.find(
|
|
50
|
+
(ia) => ia.type === 'ApolloInternetAccount',
|
|
51
|
+
) as ApolloInternetAccountModel | undefined
|
|
52
|
+
if (!apolloInternetAccount) {
|
|
53
|
+
throw new Error('No Apollo internet account found')
|
|
54
|
+
}
|
|
55
|
+
const { baseURL } = apolloInternetAccount
|
|
56
|
+
const { classes } = useStyles()
|
|
57
|
+
const [errorMessage, setErrorMessage] = useState<string>()
|
|
58
|
+
const [assemblyCollection, setAssemblyCollection] = useState<
|
|
59
|
+
AssemblyDocument[]
|
|
60
|
+
>([])
|
|
61
|
+
const [assemblyId, setAssemblyId] = useState<string>('')
|
|
62
|
+
const [displayGridData, setDisplayGridData] = useState<GridRowsProp[]>([])
|
|
63
|
+
|
|
64
|
+
const gridColumns: GridColDef[] = [
|
|
65
|
+
{ field: 'sequence' },
|
|
66
|
+
{
|
|
67
|
+
field: 'typeName',
|
|
68
|
+
headerName: 'Change type',
|
|
69
|
+
width: 200,
|
|
70
|
+
type: 'singleSelect',
|
|
71
|
+
// TODO: Get these from change manager once it's on the session
|
|
72
|
+
valueOptions: [...changeRegistry.changes.keys()],
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
field: 'changes',
|
|
76
|
+
headerName: 'Change JSON',
|
|
77
|
+
width: 600,
|
|
78
|
+
renderCell: ({ value }) => (
|
|
79
|
+
<textarea className={classes.changeTextarea} readOnly>
|
|
80
|
+
{JSON.stringify(value)}
|
|
81
|
+
</textarea>
|
|
82
|
+
),
|
|
83
|
+
valueFormatter: ({ value }) => JSON.stringify(value),
|
|
84
|
+
},
|
|
85
|
+
{ field: 'user', headerName: 'User', width: 140 },
|
|
86
|
+
{
|
|
87
|
+
field: 'createdAt',
|
|
88
|
+
headerName: 'Time',
|
|
89
|
+
width: 160,
|
|
90
|
+
type: 'dateTime',
|
|
91
|
+
valueGetter: ({ value }) => value && new Date(value),
|
|
92
|
+
},
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
async function getAssemblies() {
|
|
97
|
+
const uri = new URL('/assemblies', baseURL).href
|
|
98
|
+
const apolloFetch = apolloInternetAccount?.getFetcher({
|
|
99
|
+
locationType: 'UriLocation',
|
|
100
|
+
uri,
|
|
101
|
+
})
|
|
102
|
+
if (apolloFetch) {
|
|
103
|
+
const response = await apolloFetch(uri, { method: 'GET' })
|
|
104
|
+
if (!response.ok) {
|
|
105
|
+
const newErrorMessage = await createFetchErrorMessage(
|
|
106
|
+
response,
|
|
107
|
+
'Error when retrieving assemblies from server',
|
|
108
|
+
)
|
|
109
|
+
setErrorMessage(newErrorMessage)
|
|
110
|
+
return
|
|
111
|
+
}
|
|
112
|
+
const data = (await response.json()) as AssemblyDocument[]
|
|
113
|
+
setAssemblyCollection(data)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
getAssemblies().catch((error) => setErrorMessage(String(error)))
|
|
117
|
+
}, [apolloInternetAccount, baseURL])
|
|
118
|
+
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
if (!assemblyId && assemblyCollection.length > 0) {
|
|
121
|
+
setAssemblyId(assemblyCollection[0]._id)
|
|
122
|
+
}
|
|
123
|
+
}, [assemblyId, assemblyCollection])
|
|
124
|
+
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
async function getGridData() {
|
|
127
|
+
if (!assemblyId) {
|
|
128
|
+
return
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Get changes
|
|
132
|
+
const url = new URL('changes', baseURL)
|
|
133
|
+
const searchParams = new URLSearchParams({ assembly: assemblyId })
|
|
134
|
+
url.search = searchParams.toString()
|
|
135
|
+
const uri = url.toString()
|
|
136
|
+
const apolloFetch = apolloInternetAccount?.getFetcher({
|
|
137
|
+
locationType: 'UriLocation',
|
|
138
|
+
uri,
|
|
139
|
+
})
|
|
140
|
+
if (apolloFetch) {
|
|
141
|
+
const response = await apolloFetch(uri, {
|
|
142
|
+
headers: new Headers({ 'Content-Type': 'application/json' }),
|
|
143
|
+
})
|
|
144
|
+
if (!response.ok) {
|
|
145
|
+
const newErrorMessage = await createFetchErrorMessage(
|
|
146
|
+
response,
|
|
147
|
+
'Error when retrieving changes',
|
|
148
|
+
)
|
|
149
|
+
setErrorMessage(newErrorMessage)
|
|
150
|
+
return
|
|
151
|
+
}
|
|
152
|
+
const data = await response.json()
|
|
153
|
+
setDisplayGridData(data)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
getGridData().catch((error) => setErrorMessage(String(error)))
|
|
157
|
+
}, [assemblyId, apolloInternetAccount, baseURL])
|
|
158
|
+
|
|
159
|
+
async function handleChangeAssembly(e: SelectChangeEvent<string>) {
|
|
160
|
+
setAssemblyId(e.target.value as string)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<Dialog
|
|
165
|
+
open
|
|
166
|
+
fullScreen
|
|
167
|
+
title="View change log"
|
|
168
|
+
handleClose={handleClose}
|
|
169
|
+
data-testid="view-changelog"
|
|
170
|
+
>
|
|
171
|
+
<Select
|
|
172
|
+
style={{ width: 200, marginLeft: 40 }}
|
|
173
|
+
value={assemblyId}
|
|
174
|
+
onChange={handleChangeAssembly}
|
|
175
|
+
>
|
|
176
|
+
{assemblyCollection.map((option) => (
|
|
177
|
+
<MenuItem key={option._id} value={option._id}>
|
|
178
|
+
{option.name}
|
|
179
|
+
</MenuItem>
|
|
180
|
+
))}
|
|
181
|
+
</Select>
|
|
182
|
+
|
|
183
|
+
<DialogContent>
|
|
184
|
+
<DataGrid
|
|
185
|
+
pagination
|
|
186
|
+
rows={displayGridData}
|
|
187
|
+
columns={gridColumns}
|
|
188
|
+
getRowId={(row) => row._id}
|
|
189
|
+
slots={{ toolbar: GridToolbar }}
|
|
190
|
+
initialState={{
|
|
191
|
+
sorting: { sortModel: [{ field: 'sequence', sort: 'desc' }] },
|
|
192
|
+
columns: { columnVisibilityModel: { sequence: false } },
|
|
193
|
+
}}
|
|
194
|
+
/>
|
|
195
|
+
</DialogContent>
|
|
196
|
+
<DialogActions>
|
|
197
|
+
<Button variant="outlined" type="submit" onClick={handleClose}>
|
|
198
|
+
Close
|
|
199
|
+
</Button>
|
|
200
|
+
</DialogActions>
|
|
201
|
+
{errorMessage ? (
|
|
202
|
+
<DialogContent>
|
|
203
|
+
<DialogContentText color="error">{errorMessage}</DialogContentText>
|
|
204
|
+
</DialogContent>
|
|
205
|
+
) : null}
|
|
206
|
+
</Dialog>
|
|
207
|
+
)
|
|
208
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { Assembly } from '@jbrowse/core/assemblyManager/assembly'
|
|
2
|
+
import {
|
|
3
|
+
Button,
|
|
4
|
+
DialogActions,
|
|
5
|
+
DialogContent,
|
|
6
|
+
DialogContentText,
|
|
7
|
+
MenuItem,
|
|
8
|
+
Select,
|
|
9
|
+
SelectChangeEvent,
|
|
10
|
+
} from '@mui/material'
|
|
11
|
+
import {
|
|
12
|
+
DataGrid,
|
|
13
|
+
GridColDef,
|
|
14
|
+
GridRowsProp,
|
|
15
|
+
GridToolbar,
|
|
16
|
+
} from '@mui/x-data-grid'
|
|
17
|
+
import { getRoot } from 'mobx-state-tree'
|
|
18
|
+
import React, { useEffect, useState } from 'react'
|
|
19
|
+
|
|
20
|
+
import { ApolloInternetAccountModel } from '../ApolloInternetAccount/model'
|
|
21
|
+
import { ApolloSessionModel } from '../session'
|
|
22
|
+
import { ApolloRootModel } from '../types'
|
|
23
|
+
import { createFetchErrorMessage } from '../util'
|
|
24
|
+
import { Dialog } from './Dialog'
|
|
25
|
+
|
|
26
|
+
interface ViewCheckResultsProps {
|
|
27
|
+
session: ApolloSessionModel
|
|
28
|
+
handleClose(): void
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function ViewCheckResults({
|
|
32
|
+
handleClose,
|
|
33
|
+
session,
|
|
34
|
+
}: ViewCheckResultsProps) {
|
|
35
|
+
const { internetAccounts } = getRoot<ApolloRootModel>(session)
|
|
36
|
+
const { collaborationServerDriver } = session.apolloDataStore
|
|
37
|
+
const apolloInternetAccount = internetAccounts.find(
|
|
38
|
+
(ia) => ia.type === 'ApolloInternetAccount',
|
|
39
|
+
) as ApolloInternetAccountModel | undefined
|
|
40
|
+
if (!apolloInternetAccount) {
|
|
41
|
+
throw new Error('No Apollo internet account found')
|
|
42
|
+
}
|
|
43
|
+
const { baseURL } = apolloInternetAccount
|
|
44
|
+
const [errorMessage, setErrorMessage] = useState<string>()
|
|
45
|
+
const [selectedAssembly, setSelectedAssembly] = useState<Assembly>()
|
|
46
|
+
const [displayGridData, setDisplayGridData] = useState<GridRowsProp[]>([])
|
|
47
|
+
|
|
48
|
+
const gridColumns: GridColDef[] = [
|
|
49
|
+
{ field: '_id', headerName: 'id', width: 50 },
|
|
50
|
+
{
|
|
51
|
+
field: 'name',
|
|
52
|
+
headerName: 'Check name',
|
|
53
|
+
width: 200,
|
|
54
|
+
},
|
|
55
|
+
{ field: 'refSeq', headerName: 'Reference sequence ID', width: 200 },
|
|
56
|
+
{ field: 'ids', headerName: 'Feature IDs', width: 200 },
|
|
57
|
+
{ field: 'message', headerName: 'Message', flex: 1 },
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
const assemblies = collaborationServerDriver.getAssemblies()
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
if (!selectedAssembly && assemblies.length > 0) {
|
|
63
|
+
setSelectedAssembly(assemblies[0])
|
|
64
|
+
}
|
|
65
|
+
}, [assemblies, selectedAssembly])
|
|
66
|
+
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
async function getGridData() {
|
|
69
|
+
const assemblyId: string | undefined = selectedAssembly?.name
|
|
70
|
+
if (!assemblyId) {
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
const url = new URL('checks', baseURL)
|
|
74
|
+
const searchParams = new URLSearchParams({ assembly: assemblyId })
|
|
75
|
+
url.search = searchParams.toString()
|
|
76
|
+
const uri = url.toString()
|
|
77
|
+
const apolloFetch = apolloInternetAccount?.getFetcher({
|
|
78
|
+
locationType: 'UriLocation',
|
|
79
|
+
uri,
|
|
80
|
+
})
|
|
81
|
+
if (apolloFetch) {
|
|
82
|
+
const response = await apolloFetch(uri, {
|
|
83
|
+
headers: new Headers({ 'Content-Type': 'application/json' }),
|
|
84
|
+
})
|
|
85
|
+
if (!response.ok) {
|
|
86
|
+
const newErrorMessage = await createFetchErrorMessage(
|
|
87
|
+
response,
|
|
88
|
+
'Error when retrieving checks',
|
|
89
|
+
)
|
|
90
|
+
setErrorMessage(newErrorMessage)
|
|
91
|
+
return
|
|
92
|
+
}
|
|
93
|
+
const data = await response.json()
|
|
94
|
+
setDisplayGridData(data)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
getGridData().catch((error) => setErrorMessage(String(error)))
|
|
98
|
+
}, [selectedAssembly, apolloInternetAccount, baseURL])
|
|
99
|
+
|
|
100
|
+
function handleChangeAssembly(e: SelectChangeEvent<string>) {
|
|
101
|
+
const newAssembly = assemblies.find((asm) => asm.name === e.target.value)
|
|
102
|
+
setSelectedAssembly(newAssembly)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<Dialog
|
|
107
|
+
open
|
|
108
|
+
fullScreen
|
|
109
|
+
title="View check results"
|
|
110
|
+
handleClose={handleClose}
|
|
111
|
+
data-testid="view-check-results"
|
|
112
|
+
>
|
|
113
|
+
<Select
|
|
114
|
+
style={{ width: 200, marginLeft: 40 }}
|
|
115
|
+
value={selectedAssembly?.name ?? ''}
|
|
116
|
+
onChange={handleChangeAssembly}
|
|
117
|
+
disabled={assemblies.length === 0}
|
|
118
|
+
>
|
|
119
|
+
{assemblies.map((option) => (
|
|
120
|
+
<MenuItem key={option.name} value={option.name}>
|
|
121
|
+
{option.displayName ?? option.name}
|
|
122
|
+
</MenuItem>
|
|
123
|
+
))}
|
|
124
|
+
</Select>
|
|
125
|
+
|
|
126
|
+
<DialogContent>
|
|
127
|
+
<DataGrid
|
|
128
|
+
pagination
|
|
129
|
+
rows={displayGridData}
|
|
130
|
+
columns={gridColumns}
|
|
131
|
+
getRowId={(row) => row._id}
|
|
132
|
+
slots={{ toolbar: GridToolbar }}
|
|
133
|
+
initialState={{
|
|
134
|
+
sorting: { sortModel: [{ field: 'name', sort: 'asc' }] },
|
|
135
|
+
columns: { columnVisibilityModel: { name: true } },
|
|
136
|
+
}}
|
|
137
|
+
/>
|
|
138
|
+
</DialogContent>
|
|
139
|
+
<DialogActions>
|
|
140
|
+
<Button variant="outlined" type="submit" onClick={handleClose}>
|
|
141
|
+
Close
|
|
142
|
+
</Button>
|
|
143
|
+
</DialogActions>
|
|
144
|
+
{errorMessage ? (
|
|
145
|
+
<DialogContent>
|
|
146
|
+
<DialogContentText color="error">{errorMessage}</DialogContentText>
|
|
147
|
+
</DialogContent>
|
|
148
|
+
) : null}
|
|
149
|
+
</Dialog>
|
|
150
|
+
)
|
|
151
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from './AddAssembly'
|
|
2
|
+
export * from './AddChildFeature'
|
|
3
|
+
export * from './CopyFeature'
|
|
4
|
+
export * from './DeleteAssembly'
|
|
5
|
+
export * from './DeleteFeature'
|
|
6
|
+
export * from './DownloadGFF3'
|
|
7
|
+
export * from './ImportFeatures'
|
|
8
|
+
export * from './ManageChecks'
|
|
9
|
+
export * from './ManageUsers'
|
|
10
|
+
export * from './ModifyFeatureAttribute'
|
|
11
|
+
export * from './OpenLocalFile'
|
|
12
|
+
export * from './ViewChangeLog'
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ConfigurationSchema } from '@jbrowse/core/configuration'
|
|
2
|
+
import { types } from 'mobx-state-tree'
|
|
3
|
+
|
|
4
|
+
import { OntologyRecordConfiguration } from './OntologyManager'
|
|
5
|
+
|
|
6
|
+
const ApolloPluginConfigurationSchema = ConfigurationSchema('ApolloPlugin', {
|
|
7
|
+
ontologies: types.array(OntologyRecordConfiguration),
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
export default ApolloPluginConfigurationSchema
|
package/src/declare.d.ts
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { Assembly } from '@jbrowse/core/assemblyManager/assembly'
|
|
2
|
+
import { DisplayType } from '@jbrowse/core/pluggableElementTypes'
|
|
3
|
+
import PluggableElementBase from '@jbrowse/core/pluggableElementTypes/PluggableElementBase'
|
|
4
|
+
import { getContainingView, getSession } from '@jbrowse/core/util'
|
|
5
|
+
import { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
|
|
6
|
+
import AddIcon from '@mui/icons-material/Add'
|
|
7
|
+
import { AnnotationFeatureSnapshot } from 'apollo-mst'
|
|
8
|
+
import { AddFeatureChange } from 'apollo-shared'
|
|
9
|
+
import ObjectID from 'bson-objectid'
|
|
10
|
+
|
|
11
|
+
import { ApolloSessionModel } from '../session'
|
|
12
|
+
|
|
13
|
+
function parseCigar(cigar: string): [string | undefined, number][] {
|
|
14
|
+
return (cigar.toUpperCase().match(/\d+\D/g) ?? []).map((op) => {
|
|
15
|
+
return [(op.match(/\D/) ?? [])[0], Number.parseInt(op, 10)]
|
|
16
|
+
})
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function annotationFromPileup(pluggableElement: PluggableElementBase) {
|
|
20
|
+
if (pluggableElement.name !== 'LinearPileupDisplay') {
|
|
21
|
+
return pluggableElement
|
|
22
|
+
}
|
|
23
|
+
const { stateModel } = pluggableElement as DisplayType
|
|
24
|
+
const newStateModel = stateModel
|
|
25
|
+
.views((self) => ({
|
|
26
|
+
getFirstRegion() {
|
|
27
|
+
const lgv = getContainingView(self) as unknown as LinearGenomeViewModel
|
|
28
|
+
return lgv.dynamicBlocks.contentBlocks[0]
|
|
29
|
+
},
|
|
30
|
+
getAssembly() {
|
|
31
|
+
const firstRegion = self.getFirstRegion()
|
|
32
|
+
const session = getSession(self)
|
|
33
|
+
const { assemblyManager } = session
|
|
34
|
+
const { assemblyName } = firstRegion
|
|
35
|
+
const assembly = assemblyManager.get(assemblyName)
|
|
36
|
+
if (!assembly) {
|
|
37
|
+
throw new Error(`Could not find assembly named ${assemblyName}`)
|
|
38
|
+
}
|
|
39
|
+
return assembly
|
|
40
|
+
},
|
|
41
|
+
getRefSeqId(assembly: Assembly) {
|
|
42
|
+
const firstRegion = self.getFirstRegion()
|
|
43
|
+
const { refName } = firstRegion
|
|
44
|
+
const { refNameAliases } = assembly
|
|
45
|
+
if (!refNameAliases) {
|
|
46
|
+
throw new Error(`Could not find aliases for ${assembly.name}`)
|
|
47
|
+
}
|
|
48
|
+
const newRefNames = [...Object.entries(refNameAliases)]
|
|
49
|
+
.filter(([id, refName]) => id !== refName)
|
|
50
|
+
.map(([id, refName]) => ({
|
|
51
|
+
_id: id,
|
|
52
|
+
name: refName ?? '',
|
|
53
|
+
}))
|
|
54
|
+
const refSeqId = newRefNames.find((item) => item.name === refName)?._id
|
|
55
|
+
if (!refSeqId) {
|
|
56
|
+
throw new Error(`Could not find refSeqId named ${refName}`)
|
|
57
|
+
}
|
|
58
|
+
return refSeqId
|
|
59
|
+
},
|
|
60
|
+
createFeature() {
|
|
61
|
+
const feature = self.contextMenuFeature
|
|
62
|
+
const assembly = self.getAssembly()
|
|
63
|
+
const refSeqId = self.getRefSeqId(assembly)
|
|
64
|
+
const cigarData: string = feature.get('CIGAR')
|
|
65
|
+
const ops = parseCigar(cigarData)
|
|
66
|
+
let currOffset = 0
|
|
67
|
+
const start: number = feature.get('start')
|
|
68
|
+
let openStart: number | undefined
|
|
69
|
+
const exons: {
|
|
70
|
+
start: number
|
|
71
|
+
end: number
|
|
72
|
+
}[] = []
|
|
73
|
+
for (const [op, len] of ops) {
|
|
74
|
+
// open or continue open
|
|
75
|
+
if (op === 'M' || op === '=') {
|
|
76
|
+
// if it was closed, then open with start, strand, type
|
|
77
|
+
if (openStart === undefined) {
|
|
78
|
+
// add subfeature
|
|
79
|
+
openStart = currOffset + start
|
|
80
|
+
}
|
|
81
|
+
} else if (op === 'N' && openStart !== undefined) {
|
|
82
|
+
// if it was open, then close and add the subfeature
|
|
83
|
+
exons.push({
|
|
84
|
+
start: openStart,
|
|
85
|
+
end: currOffset + openStart,
|
|
86
|
+
})
|
|
87
|
+
openStart = undefined
|
|
88
|
+
}
|
|
89
|
+
if (op !== 'I') {
|
|
90
|
+
// we ignore insertions when calculating potential exon length
|
|
91
|
+
currOffset += len
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// if we are still open, then close with the final length and add subfeature
|
|
95
|
+
if (openStart !== undefined) {
|
|
96
|
+
exons.push({
|
|
97
|
+
start: openStart,
|
|
98
|
+
end: currOffset + start,
|
|
99
|
+
})
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const newFeature: AnnotationFeatureSnapshot = {
|
|
103
|
+
_id: ObjectID().toHexString(),
|
|
104
|
+
gffId: '',
|
|
105
|
+
refSeq: refSeqId,
|
|
106
|
+
start: feature.get('start'),
|
|
107
|
+
end: feature.get('end'),
|
|
108
|
+
type: 'mRNA',
|
|
109
|
+
strand: feature.get('strand'),
|
|
110
|
+
}
|
|
111
|
+
if (exons.length === 0) {
|
|
112
|
+
return newFeature
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const children: Record<string, AnnotationFeatureSnapshot> = {}
|
|
116
|
+
newFeature.children = children
|
|
117
|
+
const [firstExon] = exons
|
|
118
|
+
const cdsFeature: AnnotationFeatureSnapshot = {
|
|
119
|
+
_id: ObjectID().toHexString(),
|
|
120
|
+
gffId: '',
|
|
121
|
+
refSeq: refSeqId,
|
|
122
|
+
start: firstExon.start,
|
|
123
|
+
end: firstExon.end,
|
|
124
|
+
type: 'CDS',
|
|
125
|
+
strand: feature.get('strand'),
|
|
126
|
+
phase: 0,
|
|
127
|
+
}
|
|
128
|
+
newFeature.children[cdsFeature._id] = cdsFeature
|
|
129
|
+
if (exons.length === 1) {
|
|
130
|
+
const exon: AnnotationFeatureSnapshot = {
|
|
131
|
+
_id: ObjectID().toHexString(),
|
|
132
|
+
gffId: '',
|
|
133
|
+
refSeq: refSeqId,
|
|
134
|
+
start: firstExon.start,
|
|
135
|
+
end: firstExon.end,
|
|
136
|
+
type: 'exon',
|
|
137
|
+
strand: feature.get('strand'),
|
|
138
|
+
}
|
|
139
|
+
newFeature.children[exon._id] = exon
|
|
140
|
+
return newFeature
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const discontinuousLocations: {
|
|
144
|
+
start: number
|
|
145
|
+
end: number
|
|
146
|
+
phase: 0 | 1 | 2
|
|
147
|
+
}[] = []
|
|
148
|
+
let phase: 0 | 1 | 2 = 0
|
|
149
|
+
for (const exon of exons) {
|
|
150
|
+
cdsFeature.start = Math.min(cdsFeature.start, exon.start)
|
|
151
|
+
cdsFeature.end = Math.max(cdsFeature.end, exon.end)
|
|
152
|
+
const { end, start } = exon
|
|
153
|
+
discontinuousLocations?.push({ start, end, phase })
|
|
154
|
+
const localPhase = (end - start) % 3
|
|
155
|
+
phase = ((phase + localPhase) % 3) as 0 | 1 | 2
|
|
156
|
+
const newExon: AnnotationFeatureSnapshot = {
|
|
157
|
+
_id: ObjectID().toHexString(),
|
|
158
|
+
gffId: '',
|
|
159
|
+
refSeq: refSeqId,
|
|
160
|
+
start,
|
|
161
|
+
end,
|
|
162
|
+
type: 'exon',
|
|
163
|
+
strand: feature.get('strand'),
|
|
164
|
+
}
|
|
165
|
+
newFeature.children[newExon._id] = newExon
|
|
166
|
+
}
|
|
167
|
+
cdsFeature.discontinuousLocations = discontinuousLocations
|
|
168
|
+
return newFeature
|
|
169
|
+
},
|
|
170
|
+
async onPileupFeatureContext() {
|
|
171
|
+
const newFeature = self.createFeature()
|
|
172
|
+
const assembly = self.getAssembly()
|
|
173
|
+
const assemblyId = assembly.name
|
|
174
|
+
const change = new AddFeatureChange({
|
|
175
|
+
changedIds: [newFeature._id],
|
|
176
|
+
typeName: 'AddFeatureChange',
|
|
177
|
+
assembly: assemblyId,
|
|
178
|
+
addedFeature: newFeature,
|
|
179
|
+
})
|
|
180
|
+
const session = getSession(self)
|
|
181
|
+
await (
|
|
182
|
+
session as unknown as ApolloSessionModel
|
|
183
|
+
).apolloDataStore.changeManager.submit?.(change)
|
|
184
|
+
session.notify('Annotation added successfully', 'success')
|
|
185
|
+
},
|
|
186
|
+
}))
|
|
187
|
+
.views((self) => {
|
|
188
|
+
const superContextMenuItems = self.contextMenuItems
|
|
189
|
+
return {
|
|
190
|
+
contextMenuItems() {
|
|
191
|
+
const feature = self.contextMenuFeature
|
|
192
|
+
if (!feature) {
|
|
193
|
+
return superContextMenuItems()
|
|
194
|
+
}
|
|
195
|
+
return [
|
|
196
|
+
...superContextMenuItems(),
|
|
197
|
+
{
|
|
198
|
+
label: 'Create Apollo annotation',
|
|
199
|
+
icon: AddIcon,
|
|
200
|
+
onClick: self.onPileupFeatureContext,
|
|
201
|
+
},
|
|
202
|
+
]
|
|
203
|
+
},
|
|
204
|
+
}
|
|
205
|
+
})
|
|
206
|
+
;(pluggableElement as DisplayType).stateModel = newStateModel
|
|
207
|
+
return pluggableElement
|
|
208
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './annotationFromPileup'
|