@apollo-annotation/jbrowse-plugin-apollo 0.3.12 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.d.ts +1 -1
- package/dist/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.d.ts.map +1 -1
- package/dist/BackendDrivers/BackendDriver.d.ts +29 -4
- package/dist/BackendDrivers/BackendDriver.d.ts.map +1 -1
- package/dist/BackendDrivers/CollaborationServerDriver.d.ts +3 -1
- package/dist/BackendDrivers/CollaborationServerDriver.d.ts.map +1 -1
- package/dist/BackendDrivers/LocalDriver/LocalDriver.d.ts +22 -0
- package/dist/BackendDrivers/LocalDriver/LocalDriver.d.ts.map +1 -0
- package/dist/BackendDrivers/LocalDriver/db.d.ts +4 -0
- package/dist/BackendDrivers/LocalDriver/db.d.ts.map +1 -0
- package/dist/BackendDrivers/index.d.ts +1 -2
- package/dist/BackendDrivers/index.d.ts.map +1 -1
- package/dist/ChangeManager.d.ts +3 -3
- package/dist/ChangeManager.d.ts.map +1 -1
- package/dist/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.d.ts +0 -6
- package/dist/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.d.ts.map +1 -1
- package/dist/FeatureDetailsWidget/TranscriptWidgetEditLocation.d.ts.map +1 -1
- package/dist/FeatureDetailsWidget/model.d.ts +0 -2
- package/dist/FeatureDetailsWidget/model.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/components/CheckResultWarnings.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/components/LinearApolloDisplay.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/components/OverlayCanvas.d.ts +7 -0
- package/dist/LinearApolloDisplay/components/OverlayCanvas.d.ts.map +1 -0
- package/dist/LinearApolloDisplay/components/Tooltip.d.ts +10 -0
- package/dist/LinearApolloDisplay/components/Tooltip.d.ts.map +1 -0
- package/dist/LinearApolloDisplay/glyphs/BoxGlyph.d.ts +0 -1
- package/dist/LinearApolloDisplay/glyphs/BoxGlyph.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/glyphs/CDSGlyph.d.ts +3 -0
- package/dist/LinearApolloDisplay/glyphs/CDSGlyph.d.ts.map +1 -0
- package/dist/LinearApolloDisplay/glyphs/ExonGlyph.d.ts +3 -0
- package/dist/LinearApolloDisplay/glyphs/ExonGlyph.d.ts.map +1 -0
- package/dist/LinearApolloDisplay/glyphs/GeneGlyph.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/glyphs/GenericChildGlyph.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/glyphs/Glyph.d.ts +26 -20
- package/dist/LinearApolloDisplay/glyphs/Glyph.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/glyphs/TranscriptGlyph.d.ts +3 -0
- package/dist/LinearApolloDisplay/glyphs/TranscriptGlyph.d.ts.map +1 -0
- package/dist/LinearApolloDisplay/glyphs/util.d.ts +13 -0
- package/dist/LinearApolloDisplay/glyphs/util.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/stateModel/base.d.ts +17 -0
- package/dist/LinearApolloDisplay/stateModel/base.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/stateModel/index.d.ts +35 -17
- package/dist/LinearApolloDisplay/stateModel/index.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/stateModel/layouts.d.ts +29 -7
- package/dist/LinearApolloDisplay/stateModel/layouts.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/stateModel/mouseEvents.d.ts +69 -23
- package/dist/LinearApolloDisplay/stateModel/mouseEvents.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/stateModel/rendering.d.ts +26 -9
- package/dist/LinearApolloDisplay/stateModel/rendering.d.ts.map +1 -1
- package/dist/LinearApolloReferenceSequenceDisplay/stateModel/base.d.ts +6 -0
- package/dist/LinearApolloReferenceSequenceDisplay/stateModel/base.d.ts.map +1 -1
- package/dist/LinearApolloReferenceSequenceDisplay/stateModel/index.d.ts +6 -0
- package/dist/LinearApolloReferenceSequenceDisplay/stateModel/index.d.ts.map +1 -1
- package/dist/LinearApolloReferenceSequenceDisplay/stateModel/rendering.d.ts +6 -0
- package/dist/LinearApolloReferenceSequenceDisplay/stateModel/rendering.d.ts.map +1 -1
- package/dist/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.d.ts.map +1 -1
- package/dist/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.d.ts.map +1 -1
- package/dist/LinearApolloSixFrameDisplay/glyphs/Glyph.d.ts +1 -1
- package/dist/LinearApolloSixFrameDisplay/glyphs/Glyph.d.ts.map +1 -1
- package/dist/LinearApolloSixFrameDisplay/stateModel/layouts.d.ts.map +1 -1
- package/dist/LinearApolloSixFrameDisplay/stateModel/rendering.d.ts.map +1 -1
- package/dist/OntologyManager/OntologyStore/fulltext.d.ts +1 -1
- package/dist/OntologyManager/OntologyStore/fulltext.d.ts.map +1 -1
- package/dist/OntologyManager/OntologyStore/index.d.ts +2 -2
- package/dist/OntologyManager/OntologyStore/index.d.ts.map +1 -1
- package/dist/OntologyManager/OntologyStore/indexeddb-storage.d.ts +1 -1
- package/dist/OntologyManager/OntologyStore/indexeddb-storage.d.ts.map +1 -1
- package/dist/OntologyManager/OntologyStore/types.d.ts +18 -0
- package/dist/OntologyManager/OntologyStore/types.d.ts.map +1 -0
- package/dist/TabularEditor/HybridGrid/featureContextMenuItems.d.ts.map +1 -1
- package/dist/components/AddChildFeature.d.ts.map +1 -1
- package/dist/components/ColorFeature.d.ts +13 -0
- package/dist/components/ColorFeature.d.ts.map +1 -0
- package/dist/components/CreateApolloAnnotation.d.ts.map +1 -1
- package/dist/components/DownloadGFF3.d.ts +4 -1
- package/dist/components/DownloadGFF3.d.ts.map +1 -1
- package/dist/components/DuplicateTranscript.d.ts.map +1 -1
- package/dist/components/ViewChangeLog.d.ts +2 -1
- package/dist/components/ViewChangeLog.d.ts.map +1 -1
- package/dist/components/ViewCheckResults.d.ts +2 -1
- package/dist/components/ViewCheckResults.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/extensions/annotationFromJBrowseFeature.d.ts.map +1 -1
- package/dist/extensions/annotationFromPileup.d.ts.map +1 -1
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.js +6325 -5997
- package/dist/index.esm.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.development.js +5869 -5541
- 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 +16782 -25897
- 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/dist/makeDisplayComponent.d.ts.map +1 -1
- package/dist/menus/Icons.d.ts +3 -0
- package/dist/menus/Icons.d.ts.map +1 -0
- package/dist/menus/topLevelMenu.d.ts.map +1 -1
- package/dist/session/changeHandlers.d.ts +9 -0
- package/dist/session/changeHandlers.d.ts.map +1 -0
- package/dist/util/annotationFeatureUtils.d.ts +2 -1
- package/dist/util/annotationFeatureUtils.d.ts.map +1 -1
- package/dist/util/glyphUtils.d.ts +3 -3
- package/dist/util/glyphUtils.d.ts.map +1 -1
- package/dist/util/index.d.ts +0 -1
- package/dist/util/index.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/ApolloInternetAccount/model.ts +68 -4
- package/src/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.ts +6 -3
- package/src/ApolloTextSearchAdapter/ApolloTextSearchAdapter.ts +1 -1
- package/src/BackendDrivers/BackendDriver.ts +36 -3
- package/src/BackendDrivers/CollaborationServerDriver.ts +78 -23
- package/src/BackendDrivers/LocalDriver/LocalDriver.ts +367 -0
- package/src/BackendDrivers/LocalDriver/db.ts +37 -0
- package/src/BackendDrivers/index.ts +1 -2
- package/src/ChangeManager.ts +27 -25
- package/src/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.tsx +1 -1
- package/src/FeatureDetailsWidget/TranscriptWidgetEditLocation.tsx +69 -53
- package/src/LinearApolloDisplay/components/CheckResultWarnings.tsx +1 -5
- package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +95 -115
- package/src/LinearApolloDisplay/components/OverlayCanvas.tsx +76 -0
- package/src/LinearApolloDisplay/components/Tooltip.tsx +42 -0
- package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +60 -302
- package/src/LinearApolloDisplay/glyphs/CDSGlyph.ts +145 -0
- package/src/LinearApolloDisplay/glyphs/ExonGlyph.ts +212 -0
- package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +65 -999
- package/src/LinearApolloDisplay/glyphs/GenericChildGlyph.ts +71 -181
- package/src/LinearApolloDisplay/glyphs/Glyph.ts +42 -66
- package/src/LinearApolloDisplay/glyphs/TranscriptGlyph.ts +291 -0
- package/src/LinearApolloDisplay/glyphs/util.ts +87 -0
- package/src/LinearApolloDisplay/stateModel/base.ts +83 -0
- package/src/LinearApolloDisplay/stateModel/layouts.ts +198 -138
- package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +252 -158
- package/src/LinearApolloDisplay/stateModel/rendering.ts +103 -21
- package/src/LinearApolloReferenceSequenceDisplay/drawSequenceOverlay.ts +3 -3
- package/src/LinearApolloReferenceSequenceDisplay/stateModel/base.ts +20 -2
- package/src/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.tsx +7 -2
- package/src/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.ts +8 -13
- package/src/LinearApolloSixFrameDisplay/glyphs/Glyph.ts +1 -1
- package/src/LinearApolloSixFrameDisplay/stateModel/layouts.ts +4 -3
- package/src/LinearApolloSixFrameDisplay/stateModel/mouseEvents.ts +1 -1
- package/src/LinearApolloSixFrameDisplay/stateModel/rendering.ts +2 -1
- package/src/OntologyManager/OntologyStore/__snapshots__/index.test.ts.snap +18262 -8519
- package/src/OntologyManager/OntologyStore/fulltext.ts +1 -2
- package/src/OntologyManager/OntologyStore/index.test.ts +5 -2
- package/src/OntologyManager/OntologyStore/index.ts +7 -8
- package/src/OntologyManager/OntologyStore/indexeddb-storage.ts +2 -2
- package/src/OntologyManager/OntologyStore/types.ts +27 -0
- package/src/OntologyManager/index.ts +15 -26
- package/src/TabularEditor/HybridGrid/featureContextMenuItems.ts +4 -5
- package/src/components/AddChildFeature.tsx +15 -8
- package/src/components/ColorFeature.tsx +167 -0
- package/src/components/CreateApolloAnnotation.tsx +35 -9
- package/src/components/DownloadGFF3.tsx +92 -121
- package/src/components/DuplicateTranscript.tsx +10 -0
- package/src/components/ViewChangeLog.tsx +123 -83
- package/src/components/ViewCheckResults.tsx +15 -73
- package/src/components/index.ts +1 -1
- package/src/config.ts +37 -19
- package/src/extensions/annotationFromJBrowseFeature.test.ts +1 -1
- package/src/extensions/annotationFromJBrowseFeature.ts +91 -63
- package/src/extensions/annotationFromPileup.ts +40 -40
- package/src/index.ts +45 -1
- package/src/makeDisplayComponent.tsx +10 -3
- package/src/menus/Icons.tsx +49 -0
- package/src/menus/topLevelMenu.ts +24 -96
- package/src/session/ClientDataStore.ts +16 -17
- package/src/session/changeHandlers.ts +261 -0
- package/src/session/session.ts +77 -46
- package/src/util/annotationFeatureUtils.ts +29 -1
- package/src/util/glyphUtils.ts +74 -31
- package/src/util/index.ts +0 -1
- package/dist/BackendDrivers/DesktopFileDriver.d.ts +0 -160
- package/dist/BackendDrivers/DesktopFileDriver.d.ts.map +0 -1
- package/dist/BackendDrivers/InMemoryFileDriver.d.ts +0 -162
- package/dist/BackendDrivers/InMemoryFileDriver.d.ts.map +0 -1
- package/dist/LinearApolloDisplay/glyphs/index.d.ts +0 -4
- package/dist/LinearApolloDisplay/glyphs/index.d.ts.map +0 -1
- package/dist/components/OpenLocalFile.d.ts +0 -15
- package/dist/components/OpenLocalFile.d.ts.map +0 -1
- package/dist/util/loadAssemblyIntoClient.d.ts +0 -5
- package/dist/util/loadAssemblyIntoClient.d.ts.map +0 -1
- package/src/BackendDrivers/DesktopFileDriver.ts +0 -184
- package/src/BackendDrivers/InMemoryFileDriver.ts +0 -107
- package/src/LinearApolloDisplay/glyphs/index.ts +0 -3
- package/src/components/OpenLocalFile.tsx +0 -189
- package/src/util/loadAssemblyIntoClient.ts +0 -94
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
+
/* eslint-disable @typescript-eslint/require-await */
|
|
3
|
+
import {
|
|
4
|
+
type Change,
|
|
5
|
+
type SerializedChange,
|
|
6
|
+
checkRegistry,
|
|
7
|
+
isFeatureChange,
|
|
8
|
+
} from '@apollo-annotation/common'
|
|
9
|
+
import type {
|
|
10
|
+
AnnotationFeature,
|
|
11
|
+
AnnotationFeatureSnapshot,
|
|
12
|
+
CheckResultSnapshot,
|
|
13
|
+
} from '@apollo-annotation/mst'
|
|
14
|
+
import {
|
|
15
|
+
ValidationResultSet,
|
|
16
|
+
isDeleteFeatureChange,
|
|
17
|
+
} from '@apollo-annotation/shared'
|
|
18
|
+
import type { Assembly } from '@jbrowse/core/assemblyManager/assembly'
|
|
19
|
+
import type {
|
|
20
|
+
BaseRefNameAliasAdapter,
|
|
21
|
+
BaseSequenceAdapter,
|
|
22
|
+
} from '@jbrowse/core/data_adapters/BaseAdapter'
|
|
23
|
+
import {
|
|
24
|
+
type AbstractRootModel,
|
|
25
|
+
type Region,
|
|
26
|
+
getEnv,
|
|
27
|
+
getSession,
|
|
28
|
+
} from '@jbrowse/core/util'
|
|
29
|
+
import { getSnapshot } from '@jbrowse/mobx-state-tree'
|
|
30
|
+
|
|
31
|
+
import type { SubmitOpts } from '../../ChangeManager'
|
|
32
|
+
import {
|
|
33
|
+
BackendDriver,
|
|
34
|
+
type ChangeDocument,
|
|
35
|
+
type GetChangesOpts,
|
|
36
|
+
type GetChangesResult,
|
|
37
|
+
type RefNameAliases,
|
|
38
|
+
} from '../BackendDriver'
|
|
39
|
+
|
|
40
|
+
import { type FeatureDatabase, openDb } from './db'
|
|
41
|
+
|
|
42
|
+
export class LocalDriver extends BackendDriver {
|
|
43
|
+
async getFeatures(
|
|
44
|
+
region: Region,
|
|
45
|
+
): Promise<[AnnotationFeatureSnapshot[], CheckResultSnapshot[]]> {
|
|
46
|
+
const { assemblyName, end, refName, start } = region
|
|
47
|
+
const regions = await this.getRegions(assemblyName)
|
|
48
|
+
const refNames = regions.map((r) => r.refName)
|
|
49
|
+
const db = await openDb(assemblyName, refNames)
|
|
50
|
+
const featureStoreName = `features-${refName}`
|
|
51
|
+
const checkStoreName = `checkresults-${refName}`
|
|
52
|
+
const features: AnnotationFeatureSnapshot[] = []
|
|
53
|
+
const checkResults: CheckResultSnapshot[] = []
|
|
54
|
+
const tx = db.transaction([featureStoreName, checkStoreName])
|
|
55
|
+
for await (const cursor of tx
|
|
56
|
+
.objectStore(featureStoreName)
|
|
57
|
+
.index('min')
|
|
58
|
+
.iterate(IDBKeyRange.upperBound(end, true))) {
|
|
59
|
+
if ((cursor.value as { max: number }).max > start) {
|
|
60
|
+
features.push(cursor.value as AnnotationFeatureSnapshot)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
for await (const cursor of tx
|
|
64
|
+
.objectStore(checkStoreName)
|
|
65
|
+
.index('min')
|
|
66
|
+
.iterate(IDBKeyRange.upperBound(end, true))) {
|
|
67
|
+
if ((cursor.value as { end: number }).end > start) {
|
|
68
|
+
checkResults.push(cursor.value as CheckResultSnapshot)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return [features, checkResults]
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async getSequence(region: Region): Promise<{ seq: string; refSeq: string }> {
|
|
75
|
+
const session = getSession(this.clientStore)
|
|
76
|
+
const { assemblyManager } = session
|
|
77
|
+
const assembly = await assemblyManager.waitForAssembly(region.assemblyName)
|
|
78
|
+
if (!assembly) {
|
|
79
|
+
throw new Error(`Assembly not found: "${region.assemblyName}"`)
|
|
80
|
+
}
|
|
81
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
82
|
+
const { configuration } = assembly
|
|
83
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
|
84
|
+
const { adapter: adapterConf } = configuration.sequence
|
|
85
|
+
const { pluginManager } = getEnv(this.clientStore)
|
|
86
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
|
|
87
|
+
const type = pluginManager.getAdapterType(adapterConf.type)
|
|
88
|
+
if (!type) {
|
|
89
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
90
|
+
throw new Error(`No adapter found for "${adapterConf.type}"`)
|
|
91
|
+
}
|
|
92
|
+
const CLASS = await type.getAdapterClass()
|
|
93
|
+
const adapter = new CLASS(
|
|
94
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
95
|
+
adapterConf,
|
|
96
|
+
undefined,
|
|
97
|
+
pluginManager,
|
|
98
|
+
) as BaseSequenceAdapter
|
|
99
|
+
const seq = await adapter.getSequence(region)
|
|
100
|
+
if (!seq) {
|
|
101
|
+
throw new Error(`Sequence not found: ${JSON.stringify(region)}`)
|
|
102
|
+
}
|
|
103
|
+
return { seq, refSeq: region.refName }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async getRegions(assemblyName: string): Promise<Region[]> {
|
|
107
|
+
const session = getSession(this.clientStore)
|
|
108
|
+
const { assemblyManager } = session
|
|
109
|
+
const assembly = await assemblyManager.waitForAssembly(assemblyName)
|
|
110
|
+
if (!assembly) {
|
|
111
|
+
throw new Error(`Assembly not found: "${assemblyName}"`)
|
|
112
|
+
}
|
|
113
|
+
const { regions } = assembly
|
|
114
|
+
if (!regions) {
|
|
115
|
+
throw new Error(`Assembly not found: "${assemblyName}"`)
|
|
116
|
+
}
|
|
117
|
+
return regions
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
getAssemblies(internetAccountConfigId?: string): Assembly[] {
|
|
121
|
+
return []
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async getRefNameAliases(assemblyName: string): Promise<RefNameAliases[]> {
|
|
125
|
+
const session = getSession(this.clientStore)
|
|
126
|
+
const { assemblyManager } = session
|
|
127
|
+
const assembly = await assemblyManager.waitForAssembly(assemblyName)
|
|
128
|
+
if (!assembly) {
|
|
129
|
+
throw new Error(`Assembly not found: "${assemblyName}"`)
|
|
130
|
+
}
|
|
131
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
132
|
+
const { configuration } = assembly
|
|
133
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
134
|
+
const { refNameAliases } = configuration
|
|
135
|
+
if (!refNameAliases) {
|
|
136
|
+
return []
|
|
137
|
+
}
|
|
138
|
+
const { pluginManager } = getEnv(this.clientStore)
|
|
139
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
|
|
140
|
+
const type = pluginManager.getAdapterType(refNameAliases.adapter.type)
|
|
141
|
+
if (!type) {
|
|
142
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
143
|
+
throw new Error(`No adapter found for "${refNameAliases.adapter.type}"`)
|
|
144
|
+
}
|
|
145
|
+
const CLASS = await type.getAdapterClass()
|
|
146
|
+
const adapter = new CLASS(
|
|
147
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
|
|
148
|
+
refNameAliases.adapter,
|
|
149
|
+
undefined,
|
|
150
|
+
pluginManager,
|
|
151
|
+
) as BaseRefNameAliasAdapter
|
|
152
|
+
return adapter.getRefNameAliases({})
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async submitChange(
|
|
156
|
+
change: Change,
|
|
157
|
+
opts: SubmitOpts,
|
|
158
|
+
): Promise<ValidationResultSet> {
|
|
159
|
+
if (!isFeatureChange(change)) {
|
|
160
|
+
return new ValidationResultSet()
|
|
161
|
+
}
|
|
162
|
+
const { assembly, changedIds } = change
|
|
163
|
+
const regions = await this.getRegions(assembly)
|
|
164
|
+
const refNames = regions.map((r) => r.refName)
|
|
165
|
+
const db = await openDb(assembly, refNames)
|
|
166
|
+
const topLevelFeatures = new Set<AnnotationFeature>()
|
|
167
|
+
const deletedFeatureIds: { refSeq: string; featureId: string }[] = []
|
|
168
|
+
const neededRefNames = new Set<string>()
|
|
169
|
+
if (isDeleteFeatureChange(change)) {
|
|
170
|
+
for (const c of change.changes) {
|
|
171
|
+
if (c.parentFeatureId) {
|
|
172
|
+
const feature = this.clientStore.getFeature(c.parentFeatureId)
|
|
173
|
+
if (feature) {
|
|
174
|
+
topLevelFeatures.add(feature.topLevelFeature)
|
|
175
|
+
neededRefNames.add(feature.topLevelFeature.refSeq)
|
|
176
|
+
}
|
|
177
|
+
} else {
|
|
178
|
+
const { refSeq, _id } = c.deletedFeature
|
|
179
|
+
deletedFeatureIds.push({ refSeq, featureId: _id })
|
|
180
|
+
neededRefNames.add(refSeq)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
} else {
|
|
184
|
+
for (const changedId of changedIds) {
|
|
185
|
+
const feature = this.clientStore.getFeature(changedId)
|
|
186
|
+
if (feature) {
|
|
187
|
+
topLevelFeatures.add(feature.topLevelFeature)
|
|
188
|
+
neededRefNames.add(feature.refSeq)
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const storeNames = [...neededRefNames].flatMap((r) => [
|
|
193
|
+
`features-${r}`,
|
|
194
|
+
`checkresults-${r}`,
|
|
195
|
+
])
|
|
196
|
+
storeNames.push('changes')
|
|
197
|
+
const tx = db.transaction(storeNames, 'readwrite')
|
|
198
|
+
for (const { refSeq, featureId } of deletedFeatureIds) {
|
|
199
|
+
void tx.objectStore(`features-${refSeq}`).delete(featureId)
|
|
200
|
+
}
|
|
201
|
+
for (const feature of topLevelFeatures) {
|
|
202
|
+
const snapshot = getSnapshot<AnnotationFeatureSnapshot>(feature)
|
|
203
|
+
void tx
|
|
204
|
+
.objectStore(`features-${feature.refSeq}`)
|
|
205
|
+
.put(snapshot, feature._id)
|
|
206
|
+
}
|
|
207
|
+
// Delete old check results for deleted features
|
|
208
|
+
for (const { featureId, refSeq } of deletedFeatureIds) {
|
|
209
|
+
const checkStore = tx.objectStore(`checkresults-${refSeq}`)
|
|
210
|
+
for await (const cursor of checkStore
|
|
211
|
+
.index('featureId')
|
|
212
|
+
.iterate(featureId)) {
|
|
213
|
+
this.clientStore.deleteCheckResult(
|
|
214
|
+
(cursor.value as CheckResultSnapshot)._id,
|
|
215
|
+
)
|
|
216
|
+
void cursor.delete()
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// Delete old check results for modified features
|
|
220
|
+
for (const feature of topLevelFeatures) {
|
|
221
|
+
const checkStore = tx.objectStore(`checkresults-${feature.refSeq}`)
|
|
222
|
+
for await (const cursor of checkStore
|
|
223
|
+
.index('featureId')
|
|
224
|
+
.iterate(feature._id)) {
|
|
225
|
+
this.clientStore.deleteCheckResult(
|
|
226
|
+
(cursor.value as CheckResultSnapshot)._id,
|
|
227
|
+
)
|
|
228
|
+
void cursor.delete()
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
void tx
|
|
232
|
+
.objectStore('changes')
|
|
233
|
+
.put({ ...change.toJSON(), createdAt: new Date() })
|
|
234
|
+
await tx.done
|
|
235
|
+
|
|
236
|
+
// Run checks on modified features. Collect all results first since checks
|
|
237
|
+
// are async (need sequence data) and would cause the transaction to auto-commit.
|
|
238
|
+
if (topLevelFeatures.size > 0) {
|
|
239
|
+
const checks = [...checkRegistry.getChecks().values()]
|
|
240
|
+
const allResults: {
|
|
241
|
+
refSeq: string
|
|
242
|
+
result: CheckResultSnapshot
|
|
243
|
+
topLevelFeatureId: string
|
|
244
|
+
}[] = []
|
|
245
|
+
for (const feature of topLevelFeatures) {
|
|
246
|
+
const snapshot = getSnapshot<AnnotationFeatureSnapshot>(feature)
|
|
247
|
+
const getSequence = async (start: number, end: number) => {
|
|
248
|
+
const result = await this.getSequence({
|
|
249
|
+
assemblyName: assembly,
|
|
250
|
+
refName: feature.refSeq,
|
|
251
|
+
start,
|
|
252
|
+
end,
|
|
253
|
+
})
|
|
254
|
+
return result.seq
|
|
255
|
+
}
|
|
256
|
+
for (const check of checks) {
|
|
257
|
+
const results = await check.checkFeature(snapshot, getSequence)
|
|
258
|
+
for (const result of results) {
|
|
259
|
+
allResults.push({
|
|
260
|
+
refSeq: feature.refSeq,
|
|
261
|
+
result,
|
|
262
|
+
topLevelFeatureId: feature._id,
|
|
263
|
+
})
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (allResults.length > 0) {
|
|
268
|
+
const checkStoreNames = refNames.map((r) => `checkresults-${r}`)
|
|
269
|
+
const checkTx = db.transaction(checkStoreNames, 'readwrite')
|
|
270
|
+
for (const { refSeq, result, topLevelFeatureId } of allResults) {
|
|
271
|
+
void checkTx
|
|
272
|
+
.objectStore(`checkresults-${refSeq}`)
|
|
273
|
+
.put({ ...result, featureId: topLevelFeatureId })
|
|
274
|
+
}
|
|
275
|
+
await checkTx.done
|
|
276
|
+
// Add new check results to client store
|
|
277
|
+
for (const { result } of allResults) {
|
|
278
|
+
this.clientStore.addCheckResult(result)
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return new ValidationResultSet()
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
async searchFeatures(
|
|
287
|
+
term: string,
|
|
288
|
+
assemblies: string[],
|
|
289
|
+
): Promise<AnnotationFeatureSnapshot[]> {
|
|
290
|
+
return []
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
async getCheckResults(assemblyName: string): Promise<CheckResultSnapshot[]> {
|
|
294
|
+
const regions = await this.getRegions(assemblyName)
|
|
295
|
+
const refNames = regions.map((r) => r.refName)
|
|
296
|
+
const db = await openDb(assemblyName, refNames)
|
|
297
|
+
const checkResults: CheckResultSnapshot[] = []
|
|
298
|
+
const storeNames = refNames.map((r) => `checkresults-${r}`)
|
|
299
|
+
const tx = db.transaction(storeNames)
|
|
300
|
+
for (const storeName of storeNames) {
|
|
301
|
+
for await (const cursor of tx.objectStore(storeName).iterate()) {
|
|
302
|
+
checkResults.push(cursor.value as CheckResultSnapshot)
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return checkResults
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
async getChanges(
|
|
309
|
+
assemblyName: string,
|
|
310
|
+
opts: GetChangesOpts = {},
|
|
311
|
+
): Promise<GetChangesResult> {
|
|
312
|
+
const regions = await this.getRegions(assemblyName)
|
|
313
|
+
const refNames = regions.map((r) => r.refName)
|
|
314
|
+
const db = await openDb(assemblyName, refNames)
|
|
315
|
+
let changes: ChangeDocument[] = []
|
|
316
|
+
for await (const cursor of db.transaction('changes').store.iterate()) {
|
|
317
|
+
changes.push({
|
|
318
|
+
sequence: cursor.key,
|
|
319
|
+
...(cursor.value as SerializedChange & { createdAt: string }),
|
|
320
|
+
})
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const { filters } = opts
|
|
324
|
+
if (filters?.user) {
|
|
325
|
+
const re = new RegExp(filters.user, 'i')
|
|
326
|
+
changes = changes.filter((c) => c.user !== undefined && re.test(c.user))
|
|
327
|
+
}
|
|
328
|
+
if (filters?.typeName) {
|
|
329
|
+
changes = changes.filter((c) => c.typeName === filters.typeName)
|
|
330
|
+
}
|
|
331
|
+
if (filters?.startTime) {
|
|
332
|
+
const start = new Date(filters.startTime).getTime()
|
|
333
|
+
changes = changes.filter((c) => new Date(c.createdAt).getTime() >= start)
|
|
334
|
+
}
|
|
335
|
+
if (filters?.endTime) {
|
|
336
|
+
const end = new Date(filters.endTime).getTime()
|
|
337
|
+
changes = changes.filter((c) => new Date(c.createdAt).getTime() <= end)
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const totalCount = changes.length
|
|
341
|
+
|
|
342
|
+
const sortField = opts.sortField ?? 'sequence'
|
|
343
|
+
const sortOrder = opts.sortOrder ?? 'desc'
|
|
344
|
+
const direction = sortOrder === 'asc' ? 1 : -1
|
|
345
|
+
changes.sort((a, b) => {
|
|
346
|
+
const aVal = a[sortField as keyof ChangeDocument]
|
|
347
|
+
const bVal = b[sortField as keyof ChangeDocument]
|
|
348
|
+
if (aVal === bVal) {
|
|
349
|
+
return 0
|
|
350
|
+
}
|
|
351
|
+
if (aVal === undefined) {
|
|
352
|
+
return 1
|
|
353
|
+
}
|
|
354
|
+
if (bVal === undefined) {
|
|
355
|
+
return -1
|
|
356
|
+
}
|
|
357
|
+
return aVal < bVal ? -direction : direction
|
|
358
|
+
})
|
|
359
|
+
|
|
360
|
+
if (opts.page !== undefined && opts.pageSize !== undefined) {
|
|
361
|
+
const start = opts.page * opts.pageSize
|
|
362
|
+
changes = changes.slice(start, start + opts.pageSize)
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return { changes, totalCount }
|
|
366
|
+
}
|
|
367
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type IDBPDatabase, openDB } from 'idb/with-async-ittr'
|
|
2
|
+
|
|
3
|
+
export type FeatureDatabase = IDBPDatabase
|
|
4
|
+
|
|
5
|
+
export async function openDb(
|
|
6
|
+
assemblyName: string,
|
|
7
|
+
refNames: string[],
|
|
8
|
+
): Promise<FeatureDatabase> {
|
|
9
|
+
const dbName = `Apollo-${assemblyName}`
|
|
10
|
+
return openDB(dbName, 1, {
|
|
11
|
+
upgrade(db) {
|
|
12
|
+
const changesStoreName = 'changes'
|
|
13
|
+
if (!db.objectStoreNames.contains(changesStoreName)) {
|
|
14
|
+
db.createObjectStore(changesStoreName, { autoIncrement: true })
|
|
15
|
+
}
|
|
16
|
+
for (const refName of refNames) {
|
|
17
|
+
const storeName = `features-${refName}`
|
|
18
|
+
if (!db.objectStoreNames.contains(storeName)) {
|
|
19
|
+
const store = db.createObjectStore(storeName)
|
|
20
|
+
store.createIndex('min', 'min', { unique: false })
|
|
21
|
+
store.createIndex('max', 'max', { unique: false })
|
|
22
|
+
}
|
|
23
|
+
const checkStoreName = `checkresults-${refName}`
|
|
24
|
+
if (!db.objectStoreNames.contains(checkStoreName)) {
|
|
25
|
+
const store = db.createObjectStore(checkStoreName, {
|
|
26
|
+
keyPath: '_id',
|
|
27
|
+
})
|
|
28
|
+
store.createIndex('min', 'start', { unique: false })
|
|
29
|
+
store.createIndex('max', 'end', { unique: false })
|
|
30
|
+
store.createIndex('featureId', 'featureId', {
|
|
31
|
+
unique: false,
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
})
|
|
37
|
+
}
|
package/src/ChangeManager.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
2
|
-
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
|
3
|
-
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
4
1
|
import {
|
|
5
2
|
type Change,
|
|
6
|
-
type ClientDataStore,
|
|
7
3
|
isAssemblySpecificChange,
|
|
8
4
|
} from '@apollo-annotation/common'
|
|
9
5
|
import {
|
|
@@ -11,9 +7,10 @@ import {
|
|
|
11
7
|
validationRegistry,
|
|
12
8
|
} from '@apollo-annotation/shared'
|
|
13
9
|
import { getSession } from '@jbrowse/core/util'
|
|
14
|
-
import type { IAnyStateTreeNode } from '@jbrowse/mobx-state-tree'
|
|
15
10
|
|
|
16
11
|
import type { ApolloSessionModel } from './session'
|
|
12
|
+
import type { ClientDataStoreModel } from './session/ClientDataStore'
|
|
13
|
+
import { changeHandlers, isLocalChange } from './session/changeHandlers'
|
|
17
14
|
|
|
18
15
|
export interface SubmitOpts {
|
|
19
16
|
/** defaults to true */
|
|
@@ -27,7 +24,7 @@ export interface SubmitOpts {
|
|
|
27
24
|
}
|
|
28
25
|
|
|
29
26
|
export class ChangeManager {
|
|
30
|
-
constructor(private dataStore:
|
|
27
|
+
constructor(private dataStore: ClientDataStoreModel) {}
|
|
31
28
|
|
|
32
29
|
recentChanges: Change[] = []
|
|
33
30
|
undoneChanges: Change[] = []
|
|
@@ -90,27 +87,31 @@ export class ChangeManager {
|
|
|
90
87
|
return
|
|
91
88
|
}
|
|
92
89
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
90
|
+
const changeName = change.typeName
|
|
91
|
+
const handler = isLocalChange(changeName)
|
|
92
|
+
? changeHandlers[changeName]
|
|
93
|
+
: undefined
|
|
94
|
+
if (handler) {
|
|
95
|
+
try {
|
|
96
|
+
// submit to client data store
|
|
97
|
+
// @ts-expect-error change not narrowing
|
|
98
|
+
await handler(this.dataStore, change)
|
|
99
|
+
} catch (error) {
|
|
100
|
+
if (updateJobsManager) {
|
|
101
|
+
jobsManager.abortJob(job.name, String(error))
|
|
102
|
+
}
|
|
103
|
+
console.error(error)
|
|
104
|
+
session.notify(
|
|
105
|
+
`Error encountered in client: ${String(error)}. Data may be out of sync, please refresh the page`,
|
|
106
|
+
'error',
|
|
107
|
+
)
|
|
108
|
+
setChangeInProgress(false)
|
|
109
|
+
return
|
|
99
110
|
}
|
|
100
|
-
console.error(error)
|
|
101
|
-
session.notify(
|
|
102
|
-
`Error encountered in client: ${String(error)}. Data may be out of sync, please refresh the page`,
|
|
103
|
-
'error',
|
|
104
|
-
)
|
|
105
|
-
setChangeInProgress(false)
|
|
106
|
-
return
|
|
107
111
|
}
|
|
108
112
|
|
|
109
113
|
// post-validate
|
|
110
|
-
const results2 = await validationRegistry.frontendPostValidate(
|
|
111
|
-
change,
|
|
112
|
-
this.dataStore,
|
|
113
|
-
)
|
|
114
|
+
const results2 = await validationRegistry.frontendPostValidate(change)
|
|
114
115
|
if (!results2.ok) {
|
|
115
116
|
// notify of invalid change and revert
|
|
116
117
|
await this.undo(change)
|
|
@@ -121,6 +122,7 @@ export class ChangeManager {
|
|
|
121
122
|
jobsManager.update(job.name, 'Submitting to driver')
|
|
122
123
|
}
|
|
123
124
|
// submit to driver
|
|
125
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
124
126
|
const { collaborationServerDriver, getBackendDriver } = this.dataStore
|
|
125
127
|
const backendDriver = isAssemblySpecificChange(change)
|
|
126
128
|
? // for assembly-specific change, fall back in case it's an
|
|
@@ -136,8 +138,8 @@ export class ChangeManager {
|
|
|
136
138
|
}
|
|
137
139
|
console.error(error)
|
|
138
140
|
session.notify(String(error), 'error')
|
|
139
|
-
await this.undo(change, false)
|
|
140
141
|
setChangeInProgress(false)
|
|
142
|
+
await this.undo(change, false)
|
|
141
143
|
return
|
|
142
144
|
}
|
|
143
145
|
if (!backendResult.ok) {
|
|
@@ -146,8 +148,8 @@ export class ChangeManager {
|
|
|
146
148
|
jobsManager.abortJob(job.name, msg)
|
|
147
149
|
}
|
|
148
150
|
session.notify(msg, 'error')
|
|
149
|
-
await this.undo(change, false)
|
|
150
151
|
setChangeInProgress(false)
|
|
152
|
+
await this.undo(change, false)
|
|
151
153
|
return
|
|
152
154
|
}
|
|
153
155
|
if (change.notification) {
|
|
@@ -40,7 +40,7 @@ const useStyles = makeStyles()((theme) => ({
|
|
|
40
40
|
},
|
|
41
41
|
}))
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
const StyledAccordionSummary = styled(AccordionSummary)(() => ({
|
|
44
44
|
minHeight: 30,
|
|
45
45
|
maxHeight: 30,
|
|
46
46
|
'&.Mui-expanded': {
|
|
@@ -22,6 +22,7 @@ import RemoveIcon from '@mui/icons-material/Remove'
|
|
|
22
22
|
import {
|
|
23
23
|
Accordion,
|
|
24
24
|
AccordionDetails,
|
|
25
|
+
AccordionSummary,
|
|
25
26
|
Grid,
|
|
26
27
|
Tooltip,
|
|
27
28
|
Typography,
|
|
@@ -33,7 +34,6 @@ import type { OntologyRecord } from '../OntologyManager'
|
|
|
33
34
|
import type { ApolloSessionModel } from '../session'
|
|
34
35
|
import { copyToClipboard } from '../util/copyToClipboard'
|
|
35
36
|
|
|
36
|
-
import { StyledAccordionSummary } from './ApolloTranscriptDetailsWidget'
|
|
37
37
|
import { NumberTextField } from './NumberTextField'
|
|
38
38
|
|
|
39
39
|
const StyledTextField = styled(NumberTextField)(() => ({
|
|
@@ -64,6 +64,15 @@ const SequenceContainer = styled('div')({
|
|
|
64
64
|
},
|
|
65
65
|
})
|
|
66
66
|
|
|
67
|
+
const StyledAccordionSummary = styled(AccordionSummary)(() => ({
|
|
68
|
+
minHeight: 30,
|
|
69
|
+
maxHeight: 30,
|
|
70
|
+
'&.Mui-expanded': {
|
|
71
|
+
minHeight: 30,
|
|
72
|
+
maxHeight: 30,
|
|
73
|
+
},
|
|
74
|
+
}))
|
|
75
|
+
|
|
67
76
|
const Strand = (props: { strand: 1 | -1 | undefined }) => {
|
|
68
77
|
const { strand } = props
|
|
69
78
|
|
|
@@ -951,61 +960,11 @@ export const TranscriptWidgetEditLocation = observer(
|
|
|
951
960
|
<div>
|
|
952
961
|
{cdsPresent && (
|
|
953
962
|
<div>
|
|
954
|
-
<Accordion>
|
|
955
|
-
<StyledAccordionSummary
|
|
956
|
-
expandIcon={<ExpandMoreIcon style={{ color: 'white' }} />}
|
|
957
|
-
aria-controls="panel1-content"
|
|
958
|
-
id="panel1-header"
|
|
959
|
-
>
|
|
960
|
-
<Typography component="span" fontWeight={'bold'}>
|
|
961
|
-
Translation
|
|
962
|
-
</Typography>
|
|
963
|
-
</StyledAccordionSummary>
|
|
964
|
-
<AccordionDetails>
|
|
965
|
-
<SequenceContainer>
|
|
966
|
-
<Typography
|
|
967
|
-
component={'span'}
|
|
968
|
-
ref={seqRef}
|
|
969
|
-
style={{ maxHeight: 120, overflowY: 'scroll' }}
|
|
970
|
-
>
|
|
971
|
-
{getTranslationSequence()}
|
|
972
|
-
</Typography>
|
|
973
|
-
</SequenceContainer>
|
|
974
|
-
<div
|
|
975
|
-
style={{
|
|
976
|
-
marginTop: 10,
|
|
977
|
-
display: 'flex',
|
|
978
|
-
flexDirection: 'row',
|
|
979
|
-
alignItems: 'center',
|
|
980
|
-
gap: 10,
|
|
981
|
-
}}
|
|
982
|
-
>
|
|
983
|
-
<Tooltip title="Copy">
|
|
984
|
-
<button
|
|
985
|
-
onClick={onCopyClick}
|
|
986
|
-
style={{ border: 'none', background: 'none', padding: 0 }}
|
|
987
|
-
disabled={changeInProgress}
|
|
988
|
-
>
|
|
989
|
-
<ContentCopyIcon style={{ fontSize: 15 }} />
|
|
990
|
-
</button>
|
|
991
|
-
</Tooltip>
|
|
992
|
-
<Tooltip title="Trim">
|
|
993
|
-
<button
|
|
994
|
-
onClick={trimTranslationSequence}
|
|
995
|
-
style={{ border: 'none', background: 'none', padding: 0 }}
|
|
996
|
-
disabled={changeInProgress}
|
|
997
|
-
>
|
|
998
|
-
<ContentCutIcon style={{ fontSize: 15 }} />
|
|
999
|
-
</button>
|
|
1000
|
-
</Tooltip>
|
|
1001
|
-
</div>
|
|
1002
|
-
</AccordionDetails>
|
|
1003
|
-
</Accordion>
|
|
1004
963
|
<Grid
|
|
1005
964
|
container
|
|
1006
965
|
justifyContent="center"
|
|
1007
966
|
alignItems="center"
|
|
1008
|
-
style={{ textAlign: 'center'
|
|
967
|
+
style={{ textAlign: 'center' }}
|
|
1009
968
|
>
|
|
1010
969
|
<Grid size={1} />
|
|
1011
970
|
{strand === 1 ? (
|
|
@@ -1089,7 +1048,10 @@ export const TranscriptWidgetEditLocation = observer(
|
|
|
1089
1048
|
</Grid>
|
|
1090
1049
|
</div>
|
|
1091
1050
|
)}
|
|
1092
|
-
<div style={{ marginTop: 5 }}>
|
|
1051
|
+
<div style={{ marginTop: 5, marginBottom: 10 }}>
|
|
1052
|
+
<div style={{ textAlign: 'center' }}>
|
|
1053
|
+
<Typography>Exons</Typography>
|
|
1054
|
+
</div>
|
|
1093
1055
|
{transcriptExonParts.map((loc, index) => {
|
|
1094
1056
|
return (
|
|
1095
1057
|
<div key={index}>
|
|
@@ -1203,6 +1165,60 @@ export const TranscriptWidgetEditLocation = observer(
|
|
|
1203
1165
|
)
|
|
1204
1166
|
})}
|
|
1205
1167
|
</div>
|
|
1168
|
+
{cdsPresent && (
|
|
1169
|
+
<div>
|
|
1170
|
+
<Accordion>
|
|
1171
|
+
<StyledAccordionSummary
|
|
1172
|
+
expandIcon={<ExpandMoreIcon style={{ color: 'white' }} />}
|
|
1173
|
+
aria-controls="panel1-content"
|
|
1174
|
+
id="panel1-header"
|
|
1175
|
+
>
|
|
1176
|
+
<Typography component="span" fontWeight={'bold'}>
|
|
1177
|
+
Translation
|
|
1178
|
+
</Typography>
|
|
1179
|
+
</StyledAccordionSummary>
|
|
1180
|
+
<AccordionDetails>
|
|
1181
|
+
<SequenceContainer>
|
|
1182
|
+
<Typography
|
|
1183
|
+
component={'span'}
|
|
1184
|
+
ref={seqRef}
|
|
1185
|
+
style={{ maxHeight: 120, overflowY: 'scroll' }}
|
|
1186
|
+
>
|
|
1187
|
+
{getTranslationSequence()}
|
|
1188
|
+
</Typography>
|
|
1189
|
+
</SequenceContainer>
|
|
1190
|
+
<div
|
|
1191
|
+
style={{
|
|
1192
|
+
marginTop: 10,
|
|
1193
|
+
display: 'flex',
|
|
1194
|
+
flexDirection: 'row',
|
|
1195
|
+
alignItems: 'center',
|
|
1196
|
+
gap: 10,
|
|
1197
|
+
}}
|
|
1198
|
+
>
|
|
1199
|
+
<Tooltip title="Copy">
|
|
1200
|
+
<button
|
|
1201
|
+
onClick={onCopyClick}
|
|
1202
|
+
style={{ border: 'none', background: 'none', padding: 0 }}
|
|
1203
|
+
disabled={changeInProgress}
|
|
1204
|
+
>
|
|
1205
|
+
<ContentCopyIcon style={{ fontSize: 15 }} />
|
|
1206
|
+
</button>
|
|
1207
|
+
</Tooltip>
|
|
1208
|
+
<Tooltip title="Trim">
|
|
1209
|
+
<button
|
|
1210
|
+
onClick={trimTranslationSequence}
|
|
1211
|
+
style={{ border: 'none', background: 'none', padding: 0 }}
|
|
1212
|
+
disabled={changeInProgress}
|
|
1213
|
+
>
|
|
1214
|
+
<ContentCutIcon style={{ fontSize: 15 }} />
|
|
1215
|
+
</button>
|
|
1216
|
+
</Tooltip>
|
|
1217
|
+
</div>
|
|
1218
|
+
</AccordionDetails>
|
|
1219
|
+
</Accordion>
|
|
1220
|
+
</div>
|
|
1221
|
+
)}
|
|
1206
1222
|
</div>
|
|
1207
1223
|
)
|
|
1208
1224
|
},
|