@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.
Files changed (116) hide show
  1. package/README.md +76 -0
  2. package/dist/index.esm.js +10248 -0
  3. package/dist/index.esm.js.map +1 -0
  4. package/dist/index.js +7 -0
  5. package/dist/jbrowse-plugin-apollo.cjs.development.js +10298 -0
  6. package/dist/jbrowse-plugin-apollo.cjs.development.js.map +1 -0
  7. package/dist/jbrowse-plugin-apollo.cjs.production.min.js +2 -0
  8. package/dist/jbrowse-plugin-apollo.cjs.production.min.js.map +1 -0
  9. package/dist/jbrowse-plugin-apollo.umd.development.js +46957 -0
  10. package/dist/jbrowse-plugin-apollo.umd.development.js.map +1 -0
  11. package/dist/jbrowse-plugin-apollo.umd.production.min.js +2 -0
  12. package/dist/jbrowse-plugin-apollo.umd.production.min.js.map +1 -0
  13. package/package.json +130 -0
  14. package/src/ApolloInternetAccount/addMenuItems.ts +94 -0
  15. package/src/ApolloInternetAccount/components/AuthTypeSelector.tsx +121 -0
  16. package/src/ApolloInternetAccount/components/LoginButtons.tsx +62 -0
  17. package/src/ApolloInternetAccount/components/LoginIcons.tsx +74 -0
  18. package/src/ApolloInternetAccount/configSchema.ts +26 -0
  19. package/src/ApolloInternetAccount/index.ts +2 -0
  20. package/src/ApolloInternetAccount/model.ts +448 -0
  21. package/src/ApolloJobModel.ts +117 -0
  22. package/src/ApolloSequenceAdapter/ApolloSequenceAdapter.ts +186 -0
  23. package/src/ApolloSequenceAdapter/configSchema.ts +12 -0
  24. package/src/ApolloSequenceAdapter/index.ts +21 -0
  25. package/src/ApolloSixFrameRenderer/ApolloSixFrameRenderer.tsx +12 -0
  26. package/src/ApolloSixFrameRenderer/components/ApolloRendering.tsx +692 -0
  27. package/src/ApolloSixFrameRenderer/configSchema.ts +7 -0
  28. package/src/ApolloSixFrameRenderer/index.ts +3 -0
  29. package/src/ApolloTextSearchAdapter/ApolloTextSearchAdapter.ts +64 -0
  30. package/src/ApolloTextSearchAdapter/configSchema.ts +24 -0
  31. package/src/ApolloTextSearchAdapter/index.ts +18 -0
  32. package/src/BackendDrivers/BackendDriver.ts +31 -0
  33. package/src/BackendDrivers/CollaborationServerDriver.ts +318 -0
  34. package/src/BackendDrivers/DesktopFileDriver.ts +170 -0
  35. package/src/BackendDrivers/InMemoryFileDriver.ts +76 -0
  36. package/src/BackendDrivers/index.ts +4 -0
  37. package/src/ChangeManager.ts +148 -0
  38. package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +248 -0
  39. package/src/LinearApolloDisplay/components/index.ts +1 -0
  40. package/src/LinearApolloDisplay/configSchema.ts +16 -0
  41. package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +422 -0
  42. package/src/LinearApolloDisplay/glyphs/CanonicalGeneGlyph.ts +1191 -0
  43. package/src/LinearApolloDisplay/glyphs/GenericChildGlyph.ts +151 -0
  44. package/src/LinearApolloDisplay/glyphs/Glyph.ts +382 -0
  45. package/src/LinearApolloDisplay/glyphs/ImplicitExonGeneGlyph.ts +697 -0
  46. package/src/LinearApolloDisplay/glyphs/index.ts +4 -0
  47. package/src/LinearApolloDisplay/index.ts +2 -0
  48. package/src/LinearApolloDisplay/stateModel/base.ts +146 -0
  49. package/src/LinearApolloDisplay/stateModel/getGlyph.ts +39 -0
  50. package/src/LinearApolloDisplay/stateModel/glyphs.ts +45 -0
  51. package/src/LinearApolloDisplay/stateModel/index.ts +20 -0
  52. package/src/LinearApolloDisplay/stateModel/layouts.ts +230 -0
  53. package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +513 -0
  54. package/src/LinearApolloDisplay/stateModel/rendering.ts +441 -0
  55. package/src/LinearApolloDisplay/stateModel/trackHeightMixin.ts +43 -0
  56. package/src/LinearApolloDisplay/types.ts +1 -0
  57. package/src/OntologyManager/OntologyStore/__snapshots__/fulltext.test.ts.snap +208 -0
  58. package/src/OntologyManager/OntologyStore/__snapshots__/index.test.ts.snap +18846 -0
  59. package/src/OntologyManager/OntologyStore/fulltext-stopwords.ts +137 -0
  60. package/src/OntologyManager/OntologyStore/fulltext.test.ts +94 -0
  61. package/src/OntologyManager/OntologyStore/fulltext.ts +264 -0
  62. package/src/OntologyManager/OntologyStore/index.test.ts +130 -0
  63. package/src/OntologyManager/OntologyStore/index.ts +526 -0
  64. package/src/OntologyManager/OntologyStore/indexeddb-schema.ts +89 -0
  65. package/src/OntologyManager/OntologyStore/indexeddb-storage.ts +180 -0
  66. package/src/OntologyManager/OntologyStore/obo-graph-json-schema.ts +110 -0
  67. package/src/OntologyManager/OntologyStore/prefixes.ts +35 -0
  68. package/src/OntologyManager/index.ts +173 -0
  69. package/src/SixFrameFeatureDisplay/components/TrackLines.tsx +19 -0
  70. package/src/SixFrameFeatureDisplay/components/index.ts +1 -0
  71. package/src/SixFrameFeatureDisplay/configSchema.ts +21 -0
  72. package/src/SixFrameFeatureDisplay/index.ts +2 -0
  73. package/src/SixFrameFeatureDisplay/stateModel.ts +413 -0
  74. package/src/TabularEditor/HybridGrid/ChangeHandling.ts +88 -0
  75. package/src/TabularEditor/HybridGrid/Feature.tsx +346 -0
  76. package/src/TabularEditor/HybridGrid/FeatureAttributes.tsx +34 -0
  77. package/src/TabularEditor/HybridGrid/Highlight.tsx +40 -0
  78. package/src/TabularEditor/HybridGrid/HybridGrid.tsx +138 -0
  79. package/src/TabularEditor/HybridGrid/NumberCell.tsx +77 -0
  80. package/src/TabularEditor/HybridGrid/ToolBar.tsx +59 -0
  81. package/src/TabularEditor/HybridGrid/featureContextMenuItems.ts +119 -0
  82. package/src/TabularEditor/HybridGrid/index.ts +1 -0
  83. package/src/TabularEditor/TabularEditorPane.tsx +34 -0
  84. package/src/TabularEditor/index.ts +3 -0
  85. package/src/TabularEditor/model.ts +44 -0
  86. package/src/TabularEditor/types.ts +3 -0
  87. package/src/components/AddAssembly.tsx +464 -0
  88. package/src/components/AddChildFeature.tsx +247 -0
  89. package/src/components/AddFeature.tsx +252 -0
  90. package/src/components/CopyFeature.tsx +328 -0
  91. package/src/components/DeleteAssembly.tsx +185 -0
  92. package/src/components/DeleteFeature.tsx +90 -0
  93. package/src/components/Dialog.tsx +47 -0
  94. package/src/components/DownloadGFF3.tsx +213 -0
  95. package/src/components/ImportFeatures.tsx +295 -0
  96. package/src/components/ManageChecks.tsx +280 -0
  97. package/src/components/ManageUsers.tsx +218 -0
  98. package/src/components/ModifyFeatureAttribute.tsx +457 -0
  99. package/src/components/OntologyTermAutocomplete.tsx +240 -0
  100. package/src/components/OntologyTermMultiSelect.tsx +349 -0
  101. package/src/components/OpenLocalFile.tsx +178 -0
  102. package/src/components/ViewChangeLog.tsx +208 -0
  103. package/src/components/ViewCheckResults.tsx +151 -0
  104. package/src/components/index.ts +12 -0
  105. package/src/config.ts +10 -0
  106. package/src/declare.d.ts +3 -0
  107. package/src/extensions/annotationFromPileup.ts +208 -0
  108. package/src/extensions/index.ts +1 -0
  109. package/src/index.ts +394 -0
  110. package/src/makeDisplayComponent.tsx +244 -0
  111. package/src/session/ClientDataStore.ts +282 -0
  112. package/src/session/index.ts +1 -0
  113. package/src/session/session.ts +373 -0
  114. package/src/types.ts +10 -0
  115. package/src/util/index.ts +31 -0
  116. package/src/util/loadAssemblyIntoClient.ts +291 -0
@@ -0,0 +1,4 @@
1
+ export * from './BackendDriver'
2
+ export * from './CollaborationServerDriver'
3
+ export * from './InMemoryFileDriver'
4
+ export * from './DesktopFileDriver'
@@ -0,0 +1,148 @@
1
+ import { getSession } from '@jbrowse/core/util'
2
+ import {
3
+ Change,
4
+ ClientDataStore,
5
+ isAssemblySpecificChange,
6
+ } from 'apollo-common'
7
+ import { ValidationResultSet, validationRegistry } from 'apollo-shared'
8
+ import { IAnyStateTreeNode } from 'mobx-state-tree'
9
+
10
+ import { ApolloSessionModel } from './session'
11
+
12
+ export interface SubmitOpts {
13
+ /** defaults to true */
14
+ submitToBackend?: boolean
15
+ /** defaults to true */
16
+ addToRecents?: boolean
17
+ /** defaults to undefined */
18
+ internetAccountId?: string
19
+ /** defaults to false */
20
+ updateJobsManager?: boolean
21
+ }
22
+
23
+ export class ChangeManager {
24
+ constructor(private dataStore: ClientDataStore & IAnyStateTreeNode) {}
25
+
26
+ recentChanges: Change[] = []
27
+
28
+ async submit(change: Change, opts: SubmitOpts = {}) {
29
+ const {
30
+ addToRecents = true,
31
+ submitToBackend = true,
32
+ updateJobsManager = false,
33
+ } = opts
34
+ // pre-validate
35
+ const session = getSession(this.dataStore)
36
+ const controller = new AbortController()
37
+
38
+ const { jobsManager } = getSession(
39
+ this.dataStore,
40
+ ) as unknown as ApolloSessionModel
41
+
42
+ const job = {
43
+ name: `${change.typeName}`,
44
+ statusMessage: 'Pre-validating',
45
+ progressPct: 0,
46
+ cancelCallback: () => {
47
+ controller.abort()
48
+ },
49
+ }
50
+
51
+ if (updateJobsManager) {
52
+ jobsManager.runJob(job)
53
+ }
54
+
55
+ const result = await validationRegistry.frontendPreValidate(change)
56
+ if (!result.ok) {
57
+ const msg = `Pre-validation failed: "${result.resultsMessages}"`
58
+ if (updateJobsManager) {
59
+ jobsManager.abortJob(job.name, msg)
60
+ }
61
+ session.notify(msg, 'error')
62
+ return
63
+ }
64
+
65
+ try {
66
+ // submit to client data store
67
+ await change.execute(this.dataStore)
68
+ } catch (error) {
69
+ if (updateJobsManager) {
70
+ jobsManager.abortJob(job.name, String(error))
71
+ }
72
+ console.error(error)
73
+ session.notify(String(error), 'error')
74
+ return
75
+ }
76
+
77
+ // post-validate
78
+ const results2 = await validationRegistry.frontendPostValidate(
79
+ change,
80
+ this.dataStore,
81
+ )
82
+ if (!results2.ok) {
83
+ // notify of invalid change and revert
84
+ await this.revert(change)
85
+ }
86
+
87
+ if (submitToBackend) {
88
+ if (updateJobsManager) {
89
+ jobsManager.update(job.name, 'Submitting to driver')
90
+ }
91
+ // submit to driver
92
+ const { collaborationServerDriver, getBackendDriver } = this.dataStore
93
+ const backendDriver = isAssemblySpecificChange(change)
94
+ ? getBackendDriver(change.assembly)
95
+ : collaborationServerDriver
96
+ let backendResult: ValidationResultSet
97
+ try {
98
+ backendResult = await backendDriver.submitChange(change, opts)
99
+ } catch (error) {
100
+ if (updateJobsManager) {
101
+ jobsManager.abortJob(job.name, String(error))
102
+ }
103
+ console.error(error)
104
+ session.notify(String(error), 'error')
105
+ await this.revert(change, false)
106
+ return
107
+ }
108
+ if (!backendResult.ok) {
109
+ const msg = `Post-validation failed: "${result.resultsMessages}"`
110
+ if (updateJobsManager) {
111
+ jobsManager.abortJob(job.name, msg)
112
+ }
113
+ session.notify(msg, 'error')
114
+ await this.revert(change, false)
115
+ return
116
+ }
117
+ if (change.notification) {
118
+ session.notify(change.notification, 'success')
119
+ }
120
+ }
121
+ if (addToRecents) {
122
+ // Push the change into array
123
+ this.recentChanges.push(change)
124
+ }
125
+
126
+ if (updateJobsManager) {
127
+ jobsManager.done(job)
128
+ }
129
+ }
130
+
131
+ async revert(change: Change, submitToBackend = true) {
132
+ const inverseChange = change.getInverse()
133
+ return this.submit(inverseChange, { submitToBackend, addToRecents: false })
134
+ }
135
+
136
+ /**
137
+ * Undo the last change
138
+ */
139
+ async revertLastChange() {
140
+ const lastChange = this.recentChanges.pop()
141
+ if (!lastChange) {
142
+ const session = getSession(this.dataStore)
143
+ session.notify('No changes to undo!', 'warning')
144
+ return
145
+ }
146
+ return this.revert(lastChange)
147
+ }
148
+ }
@@ -0,0 +1,248 @@
1
+ import { Menu, MenuItem } from '@jbrowse/core/ui'
2
+ import {
3
+ AbstractSessionModel,
4
+ doesIntersect2,
5
+ getContainingView,
6
+ } from '@jbrowse/core/util'
7
+ import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
8
+ import ErrorIcon from '@mui/icons-material/Error'
9
+ import { Alert, Avatar, Tooltip, useTheme } from '@mui/material'
10
+ import { observer } from 'mobx-react'
11
+ import React, { useEffect, useState } from 'react'
12
+ import { makeStyles } from 'tss-react/mui'
13
+
14
+ import { LinearApolloDisplay as LinearApolloDisplayI } from '../stateModel'
15
+
16
+ interface LinearApolloDisplayProps {
17
+ model: LinearApolloDisplayI
18
+ }
19
+ export type Coord = [number, number]
20
+
21
+ const useStyles = makeStyles()((theme) => ({
22
+ canvasContainer: {
23
+ position: 'relative',
24
+ left: 0,
25
+ },
26
+ canvas: {
27
+ position: 'absolute',
28
+ left: 0,
29
+ },
30
+ ellipses: {
31
+ textOverflow: 'ellipsis',
32
+ overflow: 'hidden',
33
+ },
34
+ avatar: {
35
+ position: 'absolute',
36
+ color: theme.palette.warning.light,
37
+ backgroundColor: theme.palette.warning.contrastText,
38
+ },
39
+ }))
40
+
41
+ export const LinearApolloDisplay = observer(function LinearApolloDisplay(
42
+ props: LinearApolloDisplayProps,
43
+ ) {
44
+ const theme = useTheme()
45
+ const { model } = props
46
+ const {
47
+ apolloRowHeight,
48
+ contextMenuItems: getContextMenuItems,
49
+ cursor,
50
+ featuresHeight,
51
+ isShown,
52
+ onMouseDown,
53
+ onMouseLeave,
54
+ onMouseMove,
55
+ onMouseUp,
56
+ regionCannotBeRendered,
57
+ session,
58
+ setCanvas,
59
+ setCollaboratorCanvas,
60
+ setOverlayCanvas,
61
+ setSeqTrackCanvas,
62
+ setSeqTrackOverlayCanvas,
63
+ setTheme,
64
+ tabularEditor,
65
+ } = model
66
+ const { classes } = useStyles()
67
+ const lgv = getContainingView(model) as unknown as LinearGenomeViewModel
68
+
69
+ useEffect(() => setTheme(theme), [theme, setTheme])
70
+ const [contextCoord, setContextCoord] = useState<Coord>()
71
+ const [contextMenuItems, setContextMenuItems] = useState<MenuItem[]>([])
72
+ const message = regionCannotBeRendered()
73
+ if (!isShown) {
74
+ return null
75
+ }
76
+ const { assemblyManager } = session as unknown as AbstractSessionModel
77
+ return (
78
+ <>
79
+ {lgv.bpPerPx <= 3 ? (
80
+ <div
81
+ className={classes.canvasContainer}
82
+ style={{
83
+ width: lgv.dynamicBlocks.totalWidthPx,
84
+ height: lgv.bpPerPx <= 1 ? 125 : 95,
85
+ }}
86
+ >
87
+ <canvas
88
+ ref={async (node: HTMLCanvasElement) => {
89
+ await Promise.resolve()
90
+ setSeqTrackCanvas(node)
91
+ }}
92
+ width={lgv.dynamicBlocks.totalWidthPx}
93
+ height={lgv.bpPerPx <= 1 ? 125 : 95}
94
+ className={classes.canvas}
95
+ data-testid="seqTrackCanvas"
96
+ />
97
+ <canvas
98
+ ref={async (node: HTMLCanvasElement) => {
99
+ await Promise.resolve()
100
+ setSeqTrackOverlayCanvas(node)
101
+ }}
102
+ width={lgv.dynamicBlocks.totalWidthPx}
103
+ height={lgv.bpPerPx <= 1 ? 125 : 95}
104
+ className={classes.canvas}
105
+ data-testid="seqTrackOverlayCanvas"
106
+ />
107
+ </div>
108
+ ) : null}
109
+ <div
110
+ className={classes.canvasContainer}
111
+ style={{
112
+ width: lgv.dynamicBlocks.totalWidthPx,
113
+ height: featuresHeight,
114
+ }}
115
+ onContextMenu={(event) => {
116
+ event.preventDefault()
117
+ if (contextMenuItems.length > 0) {
118
+ // There's already a context menu open, so close it
119
+ setContextMenuItems([])
120
+ } else {
121
+ const coord: [number, number] = [event.clientX, event.clientY]
122
+ setContextCoord(coord)
123
+ setContextMenuItems(getContextMenuItems(coord))
124
+ }
125
+ }}
126
+ >
127
+ {message ? (
128
+ <Alert severity="warning" classes={{ message: classes.ellipses }}>
129
+ <Tooltip title={message}>
130
+ <div>{message}</div>
131
+ </Tooltip>
132
+ </Alert>
133
+ ) : (
134
+ // Promise.resolve() in these 3 callbacks is to avoid infinite rendering loop
135
+ // https://github.com/mobxjs/mobx/issues/3728#issuecomment-1715400931
136
+ <>
137
+ <canvas
138
+ ref={async (node: HTMLCanvasElement) => {
139
+ await Promise.resolve()
140
+ setCollaboratorCanvas(node)
141
+ }}
142
+ width={lgv.dynamicBlocks.totalWidthPx}
143
+ height={featuresHeight}
144
+ className={classes.canvas}
145
+ data-testid="collaboratorCanvas"
146
+ />
147
+ <canvas
148
+ ref={async (node: HTMLCanvasElement) => {
149
+ await Promise.resolve()
150
+ setCanvas(node)
151
+ }}
152
+ width={lgv.dynamicBlocks.totalWidthPx}
153
+ height={featuresHeight}
154
+ className={classes.canvas}
155
+ data-testid="canvas"
156
+ />
157
+ <canvas
158
+ ref={async (node: HTMLCanvasElement) => {
159
+ await Promise.resolve()
160
+ setOverlayCanvas(node)
161
+ }}
162
+ width={lgv.dynamicBlocks.totalWidthPx}
163
+ height={featuresHeight}
164
+ onMouseMove={onMouseMove}
165
+ onMouseLeave={onMouseLeave}
166
+ onMouseDown={onMouseDown}
167
+ onMouseUp={onMouseUp}
168
+ onClick={() => {
169
+ tabularEditor.showPane()
170
+ }}
171
+ className={classes.canvas}
172
+ style={{ cursor: cursor ?? 'default' }}
173
+ data-testid="overlayCanvas"
174
+ />
175
+ {lgv.displayedRegions.flatMap((region, idx) => {
176
+ const assembly = assemblyManager.get(region.assemblyName)
177
+ return [...session.apolloDataStore.checkResults.values()]
178
+ .filter(
179
+ (checkResult) =>
180
+ assembly?.isValidRefName(checkResult.refSeq) &&
181
+ assembly?.getCanonicalRefName(checkResult.refSeq) ===
182
+ region.refName &&
183
+ doesIntersect2(
184
+ region.start,
185
+ region.end,
186
+ checkResult.start,
187
+ checkResult.end,
188
+ ),
189
+ )
190
+ .map((checkResult) => {
191
+ const left =
192
+ (lgv.bpToPx({
193
+ refName: region.refName,
194
+ coord: checkResult.start,
195
+ regionNumber: idx,
196
+ })?.offsetPx ?? 0) - lgv.offsetPx
197
+ const [feature] = checkResult.ids
198
+ if (!feature) {
199
+ return null
200
+ }
201
+ const { topLevelFeature } = feature
202
+ const row = parent
203
+ ? model.getFeatureLayoutPosition(topLevelFeature)
204
+ ?.layoutRow ?? 0
205
+ : 0
206
+ const top = row * apolloRowHeight
207
+ const height = apolloRowHeight
208
+ return (
209
+ <Tooltip key={checkResult._id} title={checkResult.message}>
210
+ <Avatar
211
+ className={classes.avatar}
212
+ style={{ top, left, height, width: height }}
213
+ >
214
+ <ErrorIcon />
215
+ </Avatar>
216
+ </Tooltip>
217
+ )
218
+ })
219
+ })}
220
+ <Menu
221
+ open={contextMenuItems.length > 0}
222
+ onMenuItemClick={(_, callback) => {
223
+ callback()
224
+ setContextMenuItems([])
225
+ }}
226
+ onClose={() => {
227
+ setContextMenuItems([])
228
+ }}
229
+ TransitionProps={{
230
+ onExit: () => {
231
+ setContextMenuItems([])
232
+ },
233
+ }}
234
+ anchorReference="anchorPosition"
235
+ anchorPosition={
236
+ contextCoord
237
+ ? { top: contextCoord[1], left: contextCoord[0] }
238
+ : undefined
239
+ }
240
+ style={{ zIndex: theme.zIndex.tooltip }}
241
+ menuItems={contextMenuItems}
242
+ />
243
+ </>
244
+ )}
245
+ </div>
246
+ </>
247
+ )
248
+ })
@@ -0,0 +1 @@
1
+ export * from './LinearApolloDisplay'
@@ -0,0 +1,16 @@
1
+ import { ConfigurationSchema } from '@jbrowse/core/configuration'
2
+ import PluginManager from '@jbrowse/core/PluginManager'
3
+ import type LinearGenomeViewPlugin from '@jbrowse/plugin-linear-genome-view'
4
+
5
+ export function configSchemaFactory(pluginManager: PluginManager) {
6
+ const LGVPlugin = pluginManager.getPlugin(
7
+ 'LinearGenomeViewPlugin',
8
+ ) as LinearGenomeViewPlugin
9
+ const { baseLinearDisplayConfigSchema } = LGVPlugin.exports
10
+
11
+ return ConfigurationSchema(
12
+ 'LinearApolloDisplay',
13
+ { height: { type: 'number', defaultValue: 500 } },
14
+ { baseConfiguration: baseLinearDisplayConfigSchema, explicitlyTyped: true },
15
+ )
16
+ }