@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.
Files changed (192) hide show
  1. package/dist/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.d.ts +1 -1
  2. package/dist/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.d.ts.map +1 -1
  3. package/dist/BackendDrivers/BackendDriver.d.ts +29 -4
  4. package/dist/BackendDrivers/BackendDriver.d.ts.map +1 -1
  5. package/dist/BackendDrivers/CollaborationServerDriver.d.ts +3 -1
  6. package/dist/BackendDrivers/CollaborationServerDriver.d.ts.map +1 -1
  7. package/dist/BackendDrivers/LocalDriver/LocalDriver.d.ts +22 -0
  8. package/dist/BackendDrivers/LocalDriver/LocalDriver.d.ts.map +1 -0
  9. package/dist/BackendDrivers/LocalDriver/db.d.ts +4 -0
  10. package/dist/BackendDrivers/LocalDriver/db.d.ts.map +1 -0
  11. package/dist/BackendDrivers/index.d.ts +1 -2
  12. package/dist/BackendDrivers/index.d.ts.map +1 -1
  13. package/dist/ChangeManager.d.ts +3 -3
  14. package/dist/ChangeManager.d.ts.map +1 -1
  15. package/dist/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.d.ts +0 -6
  16. package/dist/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.d.ts.map +1 -1
  17. package/dist/FeatureDetailsWidget/TranscriptWidgetEditLocation.d.ts.map +1 -1
  18. package/dist/FeatureDetailsWidget/model.d.ts +0 -2
  19. package/dist/FeatureDetailsWidget/model.d.ts.map +1 -1
  20. package/dist/LinearApolloDisplay/components/CheckResultWarnings.d.ts.map +1 -1
  21. package/dist/LinearApolloDisplay/components/LinearApolloDisplay.d.ts.map +1 -1
  22. package/dist/LinearApolloDisplay/components/OverlayCanvas.d.ts +7 -0
  23. package/dist/LinearApolloDisplay/components/OverlayCanvas.d.ts.map +1 -0
  24. package/dist/LinearApolloDisplay/components/Tooltip.d.ts +10 -0
  25. package/dist/LinearApolloDisplay/components/Tooltip.d.ts.map +1 -0
  26. package/dist/LinearApolloDisplay/glyphs/BoxGlyph.d.ts +0 -1
  27. package/dist/LinearApolloDisplay/glyphs/BoxGlyph.d.ts.map +1 -1
  28. package/dist/LinearApolloDisplay/glyphs/CDSGlyph.d.ts +3 -0
  29. package/dist/LinearApolloDisplay/glyphs/CDSGlyph.d.ts.map +1 -0
  30. package/dist/LinearApolloDisplay/glyphs/ExonGlyph.d.ts +3 -0
  31. package/dist/LinearApolloDisplay/glyphs/ExonGlyph.d.ts.map +1 -0
  32. package/dist/LinearApolloDisplay/glyphs/GeneGlyph.d.ts.map +1 -1
  33. package/dist/LinearApolloDisplay/glyphs/GenericChildGlyph.d.ts.map +1 -1
  34. package/dist/LinearApolloDisplay/glyphs/Glyph.d.ts +26 -20
  35. package/dist/LinearApolloDisplay/glyphs/Glyph.d.ts.map +1 -1
  36. package/dist/LinearApolloDisplay/glyphs/TranscriptGlyph.d.ts +3 -0
  37. package/dist/LinearApolloDisplay/glyphs/TranscriptGlyph.d.ts.map +1 -0
  38. package/dist/LinearApolloDisplay/glyphs/util.d.ts +13 -0
  39. package/dist/LinearApolloDisplay/glyphs/util.d.ts.map +1 -1
  40. package/dist/LinearApolloDisplay/stateModel/base.d.ts +17 -0
  41. package/dist/LinearApolloDisplay/stateModel/base.d.ts.map +1 -1
  42. package/dist/LinearApolloDisplay/stateModel/index.d.ts +35 -17
  43. package/dist/LinearApolloDisplay/stateModel/index.d.ts.map +1 -1
  44. package/dist/LinearApolloDisplay/stateModel/layouts.d.ts +29 -7
  45. package/dist/LinearApolloDisplay/stateModel/layouts.d.ts.map +1 -1
  46. package/dist/LinearApolloDisplay/stateModel/mouseEvents.d.ts +69 -23
  47. package/dist/LinearApolloDisplay/stateModel/mouseEvents.d.ts.map +1 -1
  48. package/dist/LinearApolloDisplay/stateModel/rendering.d.ts +26 -9
  49. package/dist/LinearApolloDisplay/stateModel/rendering.d.ts.map +1 -1
  50. package/dist/LinearApolloReferenceSequenceDisplay/stateModel/base.d.ts +6 -0
  51. package/dist/LinearApolloReferenceSequenceDisplay/stateModel/base.d.ts.map +1 -1
  52. package/dist/LinearApolloReferenceSequenceDisplay/stateModel/index.d.ts +6 -0
  53. package/dist/LinearApolloReferenceSequenceDisplay/stateModel/index.d.ts.map +1 -1
  54. package/dist/LinearApolloReferenceSequenceDisplay/stateModel/rendering.d.ts +6 -0
  55. package/dist/LinearApolloReferenceSequenceDisplay/stateModel/rendering.d.ts.map +1 -1
  56. package/dist/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.d.ts.map +1 -1
  57. package/dist/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.d.ts.map +1 -1
  58. package/dist/LinearApolloSixFrameDisplay/glyphs/Glyph.d.ts +1 -1
  59. package/dist/LinearApolloSixFrameDisplay/glyphs/Glyph.d.ts.map +1 -1
  60. package/dist/LinearApolloSixFrameDisplay/stateModel/layouts.d.ts.map +1 -1
  61. package/dist/LinearApolloSixFrameDisplay/stateModel/rendering.d.ts.map +1 -1
  62. package/dist/OntologyManager/OntologyStore/fulltext.d.ts +1 -1
  63. package/dist/OntologyManager/OntologyStore/fulltext.d.ts.map +1 -1
  64. package/dist/OntologyManager/OntologyStore/index.d.ts +2 -2
  65. package/dist/OntologyManager/OntologyStore/index.d.ts.map +1 -1
  66. package/dist/OntologyManager/OntologyStore/indexeddb-storage.d.ts +1 -1
  67. package/dist/OntologyManager/OntologyStore/indexeddb-storage.d.ts.map +1 -1
  68. package/dist/OntologyManager/OntologyStore/types.d.ts +18 -0
  69. package/dist/OntologyManager/OntologyStore/types.d.ts.map +1 -0
  70. package/dist/TabularEditor/HybridGrid/featureContextMenuItems.d.ts.map +1 -1
  71. package/dist/components/AddChildFeature.d.ts.map +1 -1
  72. package/dist/components/ColorFeature.d.ts +13 -0
  73. package/dist/components/ColorFeature.d.ts.map +1 -0
  74. package/dist/components/CreateApolloAnnotation.d.ts.map +1 -1
  75. package/dist/components/DownloadGFF3.d.ts +4 -1
  76. package/dist/components/DownloadGFF3.d.ts.map +1 -1
  77. package/dist/components/DuplicateTranscript.d.ts.map +1 -1
  78. package/dist/components/ViewChangeLog.d.ts +2 -1
  79. package/dist/components/ViewChangeLog.d.ts.map +1 -1
  80. package/dist/components/ViewCheckResults.d.ts +2 -1
  81. package/dist/components/ViewCheckResults.d.ts.map +1 -1
  82. package/dist/components/index.d.ts +1 -1
  83. package/dist/components/index.d.ts.map +1 -1
  84. package/dist/config.d.ts +4 -0
  85. package/dist/config.d.ts.map +1 -0
  86. package/dist/extensions/annotationFromJBrowseFeature.d.ts.map +1 -1
  87. package/dist/extensions/annotationFromPileup.d.ts.map +1 -1
  88. package/dist/index.d.ts +11 -0
  89. package/dist/index.d.ts.map +1 -0
  90. package/dist/index.esm.js +6325 -5997
  91. package/dist/index.esm.js.map +1 -1
  92. package/dist/jbrowse-plugin-apollo.cjs.development.js +5869 -5541
  93. package/dist/jbrowse-plugin-apollo.cjs.development.js.map +1 -1
  94. package/dist/jbrowse-plugin-apollo.cjs.production.min.js +1 -1
  95. package/dist/jbrowse-plugin-apollo.cjs.production.min.js.map +1 -1
  96. package/dist/jbrowse-plugin-apollo.umd.development.js +16782 -25897
  97. package/dist/jbrowse-plugin-apollo.umd.development.js.map +1 -1
  98. package/dist/jbrowse-plugin-apollo.umd.production.min.js +1 -1
  99. package/dist/jbrowse-plugin-apollo.umd.production.min.js.map +1 -1
  100. package/dist/makeDisplayComponent.d.ts.map +1 -1
  101. package/dist/menus/Icons.d.ts +3 -0
  102. package/dist/menus/Icons.d.ts.map +1 -0
  103. package/dist/menus/topLevelMenu.d.ts.map +1 -1
  104. package/dist/session/changeHandlers.d.ts +9 -0
  105. package/dist/session/changeHandlers.d.ts.map +1 -0
  106. package/dist/util/annotationFeatureUtils.d.ts +2 -1
  107. package/dist/util/annotationFeatureUtils.d.ts.map +1 -1
  108. package/dist/util/glyphUtils.d.ts +3 -3
  109. package/dist/util/glyphUtils.d.ts.map +1 -1
  110. package/dist/util/index.d.ts +0 -1
  111. package/dist/util/index.d.ts.map +1 -1
  112. package/package.json +4 -4
  113. package/src/ApolloInternetAccount/model.ts +68 -4
  114. package/src/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.ts +6 -3
  115. package/src/ApolloTextSearchAdapter/ApolloTextSearchAdapter.ts +1 -1
  116. package/src/BackendDrivers/BackendDriver.ts +36 -3
  117. package/src/BackendDrivers/CollaborationServerDriver.ts +78 -23
  118. package/src/BackendDrivers/LocalDriver/LocalDriver.ts +367 -0
  119. package/src/BackendDrivers/LocalDriver/db.ts +37 -0
  120. package/src/BackendDrivers/index.ts +1 -2
  121. package/src/ChangeManager.ts +27 -25
  122. package/src/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.tsx +1 -1
  123. package/src/FeatureDetailsWidget/TranscriptWidgetEditLocation.tsx +69 -53
  124. package/src/LinearApolloDisplay/components/CheckResultWarnings.tsx +1 -5
  125. package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +95 -115
  126. package/src/LinearApolloDisplay/components/OverlayCanvas.tsx +76 -0
  127. package/src/LinearApolloDisplay/components/Tooltip.tsx +42 -0
  128. package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +60 -302
  129. package/src/LinearApolloDisplay/glyphs/CDSGlyph.ts +145 -0
  130. package/src/LinearApolloDisplay/glyphs/ExonGlyph.ts +212 -0
  131. package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +65 -999
  132. package/src/LinearApolloDisplay/glyphs/GenericChildGlyph.ts +71 -181
  133. package/src/LinearApolloDisplay/glyphs/Glyph.ts +42 -66
  134. package/src/LinearApolloDisplay/glyphs/TranscriptGlyph.ts +291 -0
  135. package/src/LinearApolloDisplay/glyphs/util.ts +87 -0
  136. package/src/LinearApolloDisplay/stateModel/base.ts +83 -0
  137. package/src/LinearApolloDisplay/stateModel/layouts.ts +198 -138
  138. package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +252 -158
  139. package/src/LinearApolloDisplay/stateModel/rendering.ts +103 -21
  140. package/src/LinearApolloReferenceSequenceDisplay/drawSequenceOverlay.ts +3 -3
  141. package/src/LinearApolloReferenceSequenceDisplay/stateModel/base.ts +20 -2
  142. package/src/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.tsx +7 -2
  143. package/src/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.ts +8 -13
  144. package/src/LinearApolloSixFrameDisplay/glyphs/Glyph.ts +1 -1
  145. package/src/LinearApolloSixFrameDisplay/stateModel/layouts.ts +4 -3
  146. package/src/LinearApolloSixFrameDisplay/stateModel/mouseEvents.ts +1 -1
  147. package/src/LinearApolloSixFrameDisplay/stateModel/rendering.ts +2 -1
  148. package/src/OntologyManager/OntologyStore/__snapshots__/index.test.ts.snap +18262 -8519
  149. package/src/OntologyManager/OntologyStore/fulltext.ts +1 -2
  150. package/src/OntologyManager/OntologyStore/index.test.ts +5 -2
  151. package/src/OntologyManager/OntologyStore/index.ts +7 -8
  152. package/src/OntologyManager/OntologyStore/indexeddb-storage.ts +2 -2
  153. package/src/OntologyManager/OntologyStore/types.ts +27 -0
  154. package/src/OntologyManager/index.ts +15 -26
  155. package/src/TabularEditor/HybridGrid/featureContextMenuItems.ts +4 -5
  156. package/src/components/AddChildFeature.tsx +15 -8
  157. package/src/components/ColorFeature.tsx +167 -0
  158. package/src/components/CreateApolloAnnotation.tsx +35 -9
  159. package/src/components/DownloadGFF3.tsx +92 -121
  160. package/src/components/DuplicateTranscript.tsx +10 -0
  161. package/src/components/ViewChangeLog.tsx +123 -83
  162. package/src/components/ViewCheckResults.tsx +15 -73
  163. package/src/components/index.ts +1 -1
  164. package/src/config.ts +37 -19
  165. package/src/extensions/annotationFromJBrowseFeature.test.ts +1 -1
  166. package/src/extensions/annotationFromJBrowseFeature.ts +91 -63
  167. package/src/extensions/annotationFromPileup.ts +40 -40
  168. package/src/index.ts +45 -1
  169. package/src/makeDisplayComponent.tsx +10 -3
  170. package/src/menus/Icons.tsx +49 -0
  171. package/src/menus/topLevelMenu.ts +24 -96
  172. package/src/session/ClientDataStore.ts +16 -17
  173. package/src/session/changeHandlers.ts +261 -0
  174. package/src/session/session.ts +77 -46
  175. package/src/util/annotationFeatureUtils.ts +29 -1
  176. package/src/util/glyphUtils.ts +74 -31
  177. package/src/util/index.ts +0 -1
  178. package/dist/BackendDrivers/DesktopFileDriver.d.ts +0 -160
  179. package/dist/BackendDrivers/DesktopFileDriver.d.ts.map +0 -1
  180. package/dist/BackendDrivers/InMemoryFileDriver.d.ts +0 -162
  181. package/dist/BackendDrivers/InMemoryFileDriver.d.ts.map +0 -1
  182. package/dist/LinearApolloDisplay/glyphs/index.d.ts +0 -4
  183. package/dist/LinearApolloDisplay/glyphs/index.d.ts.map +0 -1
  184. package/dist/components/OpenLocalFile.d.ts +0 -15
  185. package/dist/components/OpenLocalFile.d.ts.map +0 -1
  186. package/dist/util/loadAssemblyIntoClient.d.ts +0 -5
  187. package/dist/util/loadAssemblyIntoClient.d.ts.map +0 -1
  188. package/src/BackendDrivers/DesktopFileDriver.ts +0 -184
  189. package/src/BackendDrivers/InMemoryFileDriver.ts +0 -107
  190. package/src/LinearApolloDisplay/glyphs/index.ts +0 -3
  191. package/src/components/OpenLocalFile.tsx +0 -189
  192. package/src/util/loadAssemblyIntoClient.ts +0 -94
@@ -5,11 +5,10 @@
5
5
  import { checkAbortSignal } from '@jbrowse/core/util/aborting'
6
6
  import jsonpath from 'jsonpath'
7
7
 
8
- import type { TextIndexFieldDefinition } from '..'
9
-
10
8
  import { stopwords } from './fulltext-stopwords'
11
9
  import type { OntologyDBNode } from './indexeddb-schema'
12
10
  import { applyPrefixes } from './prefixes'
11
+ import type { TextIndexFieldDefinition } from './types'
13
12
 
14
13
  // eslint-disable-next-line import/no-duplicates
15
14
  import type OntologyStore from '.'
@@ -5,7 +5,7 @@ import { fileURLToPath } from 'node:url'
5
5
 
6
6
  import { beforeAll, describe, expect, it, jest } from '@jest/globals'
7
7
 
8
- import { type OntologyClass, isOntologyClass } from '..'
8
+ import { type OntologyClass, isOntologyClass } from './types'
9
9
 
10
10
  import OntologyStore from '.'
11
11
 
@@ -40,7 +40,10 @@ jest.mock('jsonpath', () => {
40
40
  let so: OntologyStore
41
41
 
42
42
  beforeAll(async () => {
43
- const localPath = path.resolve(__dirname, '../../../test_data/so-v3.1.json')
43
+ const localPath = path.resolve(
44
+ __dirname,
45
+ '../../../test_data/so-2024-11-18.json',
46
+ )
44
47
  so = new OntologyStore(
45
48
  'Sequence Ontology',
46
49
  'automated testing',
@@ -15,14 +15,6 @@ import {
15
15
  deleteDB,
16
16
  } from 'idb/with-async-ittr'
17
17
 
18
- import {
19
- type OntologyClass,
20
- type OntologyProperty,
21
- type OntologyTerm,
22
- isOntologyClass,
23
- isOntologyProperty,
24
- } from '..'
25
-
26
18
  import { textSearch } from './fulltext'
27
19
  import {
28
20
  type OntologyDB,
@@ -35,6 +27,13 @@ import {
35
27
  loadOboGraphJson,
36
28
  openDatabase,
37
29
  } from './indexeddb-storage'
30
+ import {
31
+ type OntologyClass,
32
+ type OntologyProperty,
33
+ type OntologyTerm,
34
+ isOntologyClass,
35
+ isOntologyProperty,
36
+ } from './types'
38
37
 
39
38
  export type SourceLocation = UriLocation | LocalPathLocation | BlobLocation
40
39
 
@@ -8,8 +8,6 @@ import {
8
8
  openDB,
9
9
  } from 'idb/with-async-ittr'
10
10
 
11
- import { defaultTextIndexFields } from '..'
12
-
13
11
  import { PREFIXED_ID_PATH, getWords } from './fulltext'
14
12
  import {
15
13
  type OntologyDB,
@@ -17,6 +15,7 @@ import {
17
15
  isOntologyDBNode,
18
16
  } from './indexeddb-schema'
19
17
  import type { GraphDocument } from './obo-graph-json-schema'
18
+ import { defaultTextIndexFields } from './types'
20
19
 
21
20
  import type OntologyStore from '.'
22
21
 
@@ -172,6 +171,7 @@ export async function loadOboGraphJson(this: OntologyStore, db: Database) {
172
171
  const tx2 = db.transaction('meta', 'readwrite')
173
172
  // eslint-disable-next-line @typescript-eslint/unbound-method
174
173
  const { update, ...otherOptions } = this.options
174
+ await tx2.objectStore('meta').delete('meta')
175
175
  await tx2.objectStore('meta').add(
176
176
  {
177
177
  ontologyRecord: {
@@ -0,0 +1,27 @@
1
+ import type { OntologyDBNode } from './indexeddb-schema'
2
+
3
+ export type OntologyTerm = OntologyDBNode
4
+
5
+ export type OntologyClass = OntologyTerm & { type: 'CLASS' }
6
+ export function isOntologyClass(term: OntologyTerm): term is OntologyClass {
7
+ return term.type === 'CLASS'
8
+ }
9
+
10
+ export type OntologyProperty = OntologyTerm & { type: 'PROPERTY' }
11
+ export function isOntologyProperty(
12
+ term: OntologyTerm,
13
+ ): term is OntologyProperty {
14
+ return term.type === 'PROPERTY'
15
+ }
16
+
17
+ export interface TextIndexFieldDefinition {
18
+ /** name to display in the UI for text taken from this field or fields */
19
+ displayName: string
20
+ /** JSONPath of the field(s) */
21
+ jsonPath: string
22
+ }
23
+ export const defaultTextIndexFields: TextIndexFieldDefinition[] = [
24
+ { displayName: 'Label', jsonPath: '$.lbl' },
25
+ { displayName: 'Synonym', jsonPath: '$.meta.synonyms[*].val' },
26
+ { displayName: 'Definition', jsonPath: '$.meta.definition.val' },
27
+ ]
@@ -23,8 +23,11 @@ import type ApolloPluginConfigurationSchema from '../config'
23
23
  import type { ApolloRootModel } from '../types'
24
24
 
25
25
  import OntologyStore, { type OntologyStoreOptions } from './OntologyStore'
26
- import type { OntologyDBNode } from './OntologyStore/indexeddb-schema'
27
26
  import { applyPrefixes, expandPrefixes } from './OntologyStore/prefixes'
27
+ import {
28
+ type OntologyTerm,
29
+ defaultTextIndexFields,
30
+ } from './OntologyStore/types'
28
31
 
29
32
  export { isDeprecated } from './OntologyStore/indexeddb-schema'
30
33
 
@@ -200,17 +203,17 @@ export const OntologyManagerType = types
200
203
 
201
204
  export default OntologyManagerType
202
205
 
203
- export interface TextIndexFieldDefinition {
204
- /** name to display in the UI for text taken from this field or fields */
205
- displayName: string
206
- /** JSONPath of the field(s) */
207
- jsonPath: string
208
- }
209
- export const defaultTextIndexFields: TextIndexFieldDefinition[] = [
210
- { displayName: 'Label', jsonPath: '$.lbl' },
211
- { displayName: 'Synonym', jsonPath: '$.meta.synonyms[*].val' },
212
- { displayName: 'Definition', jsonPath: '$.meta.definition.val' },
213
- ]
206
+ export type {
207
+ OntologyClass,
208
+ OntologyProperty,
209
+ OntologyTerm,
210
+ TextIndexFieldDefinition,
211
+ } from './OntologyStore/types'
212
+ export {
213
+ defaultTextIndexFields,
214
+ isOntologyClass,
215
+ isOntologyProperty,
216
+ } from './OntologyStore/types'
214
217
 
215
218
  export const OntologyRecordConfiguration = ConfigurationSchema(
216
219
  'OntologyRecord',
@@ -248,17 +251,3 @@ export const OntologyRecordConfiguration = ConfigurationSchema(
248
251
  export interface OntologyManager extends Instance<typeof OntologyManagerType> {}
249
252
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
250
253
  export interface OntologyRecord extends Instance<typeof OntologyRecordType> {}
251
-
252
- export type OntologyTerm = OntologyDBNode
253
-
254
- export type OntologyClass = OntologyTerm & { type: 'CLASS' }
255
- export function isOntologyClass(term: OntologyTerm): term is OntologyClass {
256
- return term.type === 'CLASS'
257
- }
258
-
259
- export type OntologyProperty = OntologyTerm & { type: 'PROPERTY' }
260
- export function isOntologyProperty(
261
- term: OntologyTerm,
262
- ): term is OntologyProperty {
263
- return term.type === 'PROPERTY'
264
- }
@@ -32,7 +32,6 @@ export function featureContextMenuItems(
32
32
  ) {
33
33
  const internetAccount = getApolloInternetAccount(session)
34
34
  const role = internetAccount ? internetAccount.role : 'admin'
35
- const admin = role === 'admin'
36
35
  const readOnly = !(role && ['admin', 'user'].includes(role))
37
36
  const menuItems: MenuItem[] = []
38
37
  if (feature) {
@@ -102,7 +101,7 @@ export function featureContextMenuItems(
102
101
  },
103
102
  {
104
103
  label: 'Delete feature',
105
- disabled: !admin,
104
+ disabled: readOnly,
106
105
  onClick: () => {
107
106
  ;(session as unknown as AbstractSessionModel).queueDialog(
108
107
  (doneCallback) => [
@@ -124,7 +123,7 @@ export function featureContextMenuItems(
124
123
  },
125
124
  {
126
125
  label: 'Merge transcripts',
127
- disabled: !admin,
126
+ disabled: readOnly,
128
127
  onClick: () => {
129
128
  ;(session as unknown as AbstractSessionModel).queueDialog(
130
129
  (doneCallback) => [
@@ -146,7 +145,7 @@ export function featureContextMenuItems(
146
145
  },
147
146
  {
148
147
  label: 'Merge exons',
149
- disabled: !admin,
148
+ disabled: readOnly,
150
149
  onClick: () => {
151
150
  ;(session as unknown as AbstractSessionModel).queueDialog(
152
151
  (doneCallback) => [
@@ -168,7 +167,7 @@ export function featureContextMenuItems(
168
167
  },
169
168
  {
170
169
  label: 'Split exon',
171
- disabled: !admin,
170
+ disabled: readOnly,
172
171
  onClick: () => {
173
172
  ;(session as unknown as AbstractSessionModel).queueDialog(
174
173
  (doneCallback) => [
@@ -1,6 +1,9 @@
1
1
  /* eslint-disable @typescript-eslint/unbound-method */
2
2
 
3
- import type { AnnotationFeature } from '@apollo-annotation/mst'
3
+ import type {
4
+ AnnotationFeature,
5
+ AnnotationFeatureSnapshot,
6
+ } from '@apollo-annotation/mst'
4
7
  import { AddFeatureChange } from '@apollo-annotation/shared'
5
8
  import {
6
9
  Button,
@@ -65,17 +68,21 @@ export function AddChildFeature({
65
68
  event.preventDefault()
66
69
  setErrorMessage('')
67
70
  const _id = new ObjectID().toHexString()
71
+ const addedFeature: AnnotationFeatureSnapshot = {
72
+ _id,
73
+ refSeq: sourceFeature.refSeq,
74
+ min: Number(start) - 1,
75
+ max: Number(end),
76
+ type,
77
+ }
78
+ if (sourceFeature.strand) {
79
+ addedFeature.strand = sourceFeature.strand
80
+ }
68
81
  const change = new AddFeatureChange({
69
82
  changedIds: [sourceFeature._id],
70
83
  typeName: 'AddFeatureChange',
71
84
  assembly: sourceAssemblyId,
72
- addedFeature: {
73
- _id,
74
- refSeq: sourceFeature.refSeq,
75
- min: Number(start) - 1,
76
- max: Number(end),
77
- type,
78
- },
85
+ addedFeature,
79
86
  parentFeatureId: sourceFeature._id,
80
87
  })
81
88
  void changeManager.submit(change).then(() => {
@@ -0,0 +1,167 @@
1
+ /* eslint-disable @typescript-eslint/unbound-method */
2
+
3
+ import type { AnnotationFeature } from '@apollo-annotation/mst'
4
+ import { FeatureAttributeChange } from '@apollo-annotation/shared'
5
+ import { getSnapshot } from '@jbrowse/mobx-state-tree'
6
+ import {
7
+ Button,
8
+ DialogActions,
9
+ DialogContent,
10
+ DialogContentText,
11
+ } from '@mui/material'
12
+ import React, { useState } from 'react'
13
+
14
+ import type { ChangeManager } from '../ChangeManager'
15
+ import type { ApolloSessionModel } from '../session'
16
+
17
+ import { Dialog } from './Dialog'
18
+
19
+ const PRESET_COLORS = [
20
+ '#cc79a7',
21
+ '#d65e00',
22
+ '#e69f00',
23
+ '#f0e442',
24
+ '#56b3e9',
25
+ '#0072b2',
26
+ '#009e73',
27
+ ] as const
28
+
29
+ interface ColorFeatureProps {
30
+ session: ApolloSessionModel
31
+ handleClose(): void
32
+ sourceFeature: AnnotationFeature
33
+ sourceAssemblyId: string
34
+ changeManager: ChangeManager
35
+ }
36
+
37
+ export function ColorFeature({
38
+ changeManager,
39
+ handleClose,
40
+ sourceAssemblyId,
41
+ sourceFeature,
42
+ }: ColorFeatureProps) {
43
+ const existingColor = sourceFeature.attributes.get('apollo_color')?.[0]
44
+ const [color, setColor] = useState<string>(existingColor ?? PRESET_COLORS[0])
45
+
46
+ async function onSubmit(event: React.FormEvent<HTMLFormElement>) {
47
+ event.preventDefault()
48
+ const currentColor = sourceFeature.attributes.get('apollo_color')?.[0]
49
+ if (currentColor === color) {
50
+ handleClose()
51
+ return
52
+ }
53
+ const oldAttributes = getSnapshot(sourceFeature.attributes)
54
+ const newAttributes = { ...oldAttributes, apollo_color: [color] }
55
+ const change = new FeatureAttributeChange({
56
+ changedIds: [sourceFeature._id],
57
+ typeName: 'FeatureAttributeChange',
58
+ assembly: sourceAssemblyId,
59
+ featureId: sourceFeature._id,
60
+ oldAttributes,
61
+ newAttributes,
62
+ })
63
+ await changeManager.submit(change)
64
+ handleClose()
65
+ }
66
+
67
+ async function onRemove() {
68
+ const oldAttributes = getSnapshot(sourceFeature.attributes)
69
+ const { apollo_color: _removed, ...newAttributes } = oldAttributes
70
+ const change = new FeatureAttributeChange({
71
+ changedIds: [sourceFeature._id],
72
+ typeName: 'FeatureAttributeChange',
73
+ assembly: sourceAssemblyId,
74
+ featureId: sourceFeature._id,
75
+ oldAttributes,
76
+ newAttributes,
77
+ })
78
+ await changeManager.submit(change)
79
+ handleClose()
80
+ }
81
+
82
+ return (
83
+ <Dialog
84
+ open
85
+ title="Color feature"
86
+ handleClose={handleClose}
87
+ maxWidth={false}
88
+ data-testid="color-feature"
89
+ >
90
+ <form
91
+ onSubmit={(event) => {
92
+ void onSubmit(event)
93
+ }}
94
+ >
95
+ <DialogContent style={{ display: 'flex', flexDirection: 'column' }}>
96
+ <DialogContentText>
97
+ Choose a color for this feature.
98
+ </DialogContentText>
99
+ <div style={{ display: 'flex', gap: 8, marginTop: 8 }}>
100
+ {PRESET_COLORS.map((preset) => {
101
+ const selected = color.toLowerCase() === preset
102
+ return (
103
+ <button
104
+ key={preset}
105
+ type="button"
106
+ aria-label={preset}
107
+ aria-pressed={selected}
108
+ onClick={() => {
109
+ setColor(preset)
110
+ }}
111
+ style={{
112
+ width: 32,
113
+ height: 32,
114
+ padding: 0,
115
+ borderRadius: 4,
116
+ border: '1px solid rgba(0, 0, 0, 0.3)',
117
+ outline: selected ? '2px solid currentColor' : 'none',
118
+ outlineOffset: 2,
119
+ backgroundColor: preset,
120
+ cursor: 'pointer',
121
+ }}
122
+ />
123
+ )
124
+ })}
125
+ </div>
126
+ <div
127
+ style={{
128
+ display: 'flex',
129
+ alignItems: 'center',
130
+ gap: 8,
131
+ marginTop: 16,
132
+ }}
133
+ >
134
+ <label htmlFor="color-feature-custom">Custom:</label>
135
+ <input
136
+ id="color-feature-custom"
137
+ type="color"
138
+ value={color}
139
+ onChange={(event) => {
140
+ setColor(event.target.value)
141
+ }}
142
+ />
143
+ </div>
144
+ </DialogContent>
145
+ <DialogActions>
146
+ <Button variant="contained" type="submit">
147
+ Submit
148
+ </Button>
149
+ <Button
150
+ variant="outlined"
151
+ color="error"
152
+ type="button"
153
+ disabled={existingColor === undefined}
154
+ onClick={() => {
155
+ void onRemove()
156
+ }}
157
+ >
158
+ Remove color
159
+ </Button>
160
+ <Button variant="outlined" type="button" onClick={handleClose}>
161
+ Cancel
162
+ </Button>
163
+ </DialogActions>
164
+ </form>
165
+ </Dialog>
166
+ )
167
+ }
@@ -9,6 +9,7 @@ import {
9
9
  LocationStartChange,
10
10
  } from '@apollo-annotation/shared'
11
11
  import type { Assembly } from '@jbrowse/core/assemblyManager/assembly'
12
+ import { readConfObject } from '@jbrowse/core/configuration'
12
13
  import type { AbstractSessionModel } from '@jbrowse/core/util'
13
14
  import { getSnapshot } from '@jbrowse/mobx-state-tree'
14
15
  import {
@@ -30,6 +31,7 @@ import ObjectID from 'bson-objectid'
30
31
  import React, { useEffect, useMemo, useState } from 'react'
31
32
 
32
33
  import type { ApolloSessionModel } from '../session'
34
+ import { removeSkippedAttributes } from '../util'
33
35
 
34
36
  import { Dialog } from './Dialog'
35
37
 
@@ -162,6 +164,11 @@ export function CreateApolloAnnotation({
162
164
  region,
163
165
  }: CreateApolloAnnotationProps) {
164
166
  const apolloSessionModel = session as unknown as ApolloSessionModel
167
+ const configuredSkippedAttributes = readConfObject(
168
+ apolloSessionModel.getPluginConfiguration(),
169
+ 'skippedAttributesOnCopy',
170
+ ) as string[] | undefined
171
+ const skippedAttributesOnCopy = new Set(configuredSkippedAttributes ?? [])
165
172
  const { featureTypeOntology } =
166
173
  apolloSessionModel.apolloDataStore.ontologyManager
167
174
  const childIds = useMemo(
@@ -340,23 +347,28 @@ export function CreateApolloAnnotation({
340
347
 
341
348
  // Copies gene feature along with its selected children
342
349
  const copyGeneFeature = async () => {
350
+ const copiedAnnotationFeature = {
351
+ ...annotationFeature,
352
+ } as AnnotationFeatureSnapshot
353
+ removeSkippedAttributes(copiedAnnotationFeature, skippedAttributesOnCopy)
354
+
343
355
  let change
344
356
  if (
345
- annotationFeature.children &&
357
+ copiedAnnotationFeature.children &&
346
358
  checkedChildrens.length !==
347
- Object.values(annotationFeature.children).length
359
+ Object.values(copiedAnnotationFeature.children).length
348
360
  ) {
349
361
  // IF SOME CHILDREN ARE CHECKED
350
362
  const childrens: Record<string, AnnotationFeatureSnapshot> = {}
351
363
  for (const childId of checkedChildrens) {
352
- childrens[childId] = annotationFeature.children[childId]
364
+ childrens[childId] = copiedAnnotationFeature.children[childId]
353
365
  }
354
366
  change = new AddFeatureChange({
355
367
  changedIds: [annotationFeature._id],
356
368
  typeName: 'AddFeatureChange',
357
369
  assembly: assembly.name,
358
370
  addedFeature: {
359
- ...annotationFeature,
371
+ ...copiedAnnotationFeature,
360
372
  children: childrens,
361
373
  },
362
374
  })
@@ -366,7 +378,7 @@ export function CreateApolloAnnotation({
366
378
  changedIds: [annotationFeature._id],
367
379
  typeName: 'AddFeatureChange',
368
380
  assembly: assembly.name,
369
- addedFeature: annotationFeature,
381
+ addedFeature: copiedAnnotationFeature,
370
382
  })
371
383
  }
372
384
 
@@ -380,7 +392,10 @@ export function CreateApolloAnnotation({
380
392
  return
381
393
  }
382
394
  for (const transcriptId of Object.keys(transcripts)) {
383
- const transcript = transcripts[transcriptId]
395
+ const transcript = {
396
+ ...transcripts[transcriptId],
397
+ } as AnnotationFeatureSnapshot
398
+ removeSkippedAttributes(transcript, skippedAttributesOnCopy)
384
399
  transcript.strand = selectedDestinationFeature.strand
385
400
 
386
401
  // update strand of transcript children if they exist
@@ -405,9 +420,20 @@ export function CreateApolloAnnotation({
405
420
  const createNewGeneFeatureWithTranscripts = async (
406
421
  childrens: Record<string, AnnotationFeatureSnapshot>,
407
422
  ) => {
423
+ const copiedChildrens: Record<string, AnnotationFeatureSnapshot> = {}
424
+ for (const [childId, child] of Object.entries(childrens)) {
425
+ const copiedChild = { ...child } as AnnotationFeatureSnapshot
426
+ removeSkippedAttributes(copiedChild, skippedAttributesOnCopy)
427
+ copiedChildrens[childId] = copiedChild
428
+ }
429
+
408
430
  const newGeneId = new ObjectID().toHexString()
409
- const min = Math.min(...Object.values(childrens).map((child) => child.min))
410
- const max = Math.max(...Object.values(childrens).map((child) => child.max))
431
+ const min = Math.min(
432
+ ...Object.values(copiedChildrens).map((child) => child.min),
433
+ )
434
+ const max = Math.max(
435
+ ...Object.values(copiedChildrens).map((child) => child.max),
436
+ )
411
437
  const change = new AddFeatureChange({
412
438
  changedIds: [newGeneId],
413
439
  typeName: 'AddFeatureChange',
@@ -419,7 +445,7 @@ export function CreateApolloAnnotation({
419
445
  max,
420
446
  strand: annotationFeature.strand,
421
447
  type: 'gene',
422
- children: childrens,
448
+ children: copiedChildrens,
423
449
  attributes: {
424
450
  name: [getGeneNameOrId(annotationFeature)],
425
451
  gene_name: [getGeneNameOrId(annotationFeature)],