Skip to content

Commit 8194fd7

Browse files
skip attributes before feature copy
1 parent 1d88113 commit 8194fd7

8 files changed

Lines changed: 179 additions & 62 deletions

File tree

packages/apollo-collaboration-server/src/app.module.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ const validationSchema = Joi.object({
5959
DESCRIPTION: Joi.string(),
6060
FEATURE_TYPE_ONTOLOGY_LOCATION: Joi.string(),
6161
PLUGIN_LOCATION: Joi.string(),
62+
SKIPPED_ATTRIBUTES_ON_COPY: Joi.string().default(''),
6263
INDEXED_IDS: Joi.string().default('gff_id'),
6364
ALLOW_ROOT_USER: Joi.boolean().default(false),
6465
ROOT_USER_PASSWORD: Joi.string(),

packages/apollo-collaboration-server/src/jbrowse/jbrowse.service.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export class JBrowseService {
2626
DESCRIPTION?: string
2727
PLUGIN_LOCATION?: string
2828
FEATURE_TYPE_ONTOLOGY_LOCATION?: string
29+
SKIPPED_ATTRIBUTES_ON_COPY?: string
2930
},
3031
true
3132
>,
@@ -43,6 +44,7 @@ export class JBrowseService {
4344
this.configService.get('FEATURE_TYPE_ONTOLOGY_LOCATION', {
4445
infer: true,
4546
}) ?? 'sequence_ontology.json'
47+
const skippedAttributesOnCopy = this.getSkippedAttributesOnCopy()
4648
const configuration = {
4749
theme: {
4850
palette: {
@@ -69,7 +71,10 @@ export class JBrowseService {
6971
],
7072
},
7173
},
72-
ApolloPlugin: { hasRole: false },
74+
ApolloPlugin: {
75+
hasRole: false,
76+
skippedAttributesOnCopy,
77+
},
7378
}
7479
if (!role) {
7580
return configuration
@@ -79,13 +84,15 @@ export class JBrowseService {
7984
...configuration,
8085
ApolloPlugin: {
8186
hasRole: true,
87+
skippedAttributesOnCopy,
8288
},
8389
}
8490
}
8591
return {
8692
...configuration,
8793
ApolloPlugin: {
8894
hasRole: true,
95+
skippedAttributesOnCopy,
8996
ontologies: [
9097
{
9198
name: 'Sequence Ontology',
@@ -99,6 +106,19 @@ export class JBrowseService {
99106
}
100107
}
101108

109+
getSkippedAttributesOnCopy() {
110+
const skippedAttributes = this.configService.get(
111+
'SKIPPED_ATTRIBUTES_ON_COPY',
112+
{
113+
infer: true,
114+
},
115+
)
116+
return (skippedAttributes ?? '')
117+
.split(',')
118+
.map((attribute) => attribute.trim())
119+
.filter(Boolean)
120+
}
121+
102122
getPlugins() {
103123
const pluginLocation =
104124
this.configService.get('PLUGIN_LOCATION', { infer: true }) ?? 'apollo.js'

packages/jbrowse-plugin-apollo/src/LinearApolloDisplay/glyphs/TranscriptGlyph.ts

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
} from '@jbrowse/core/util'
77
import type { ContentBlock } from '@jbrowse/core/util/blockTypes'
88

9-
import { MergeTranscripts } from '../../components'
9+
import { DuplicateTranscript, MergeTranscripts } from '../../components'
1010
import {
1111
isCDSFeature,
1212
isExonFeature,
@@ -217,29 +217,54 @@ function getContextMenuItems(
217217
},
218218
})
219219
}
220-
menuItems.push({
221-
label: 'Merge transcript',
222-
onClick: () => {
223-
;(session as unknown as AbstractSessionModel).queueDialog(
224-
(doneCallback) => [
225-
MergeTranscripts,
226-
{
227-
session,
228-
handleClose: () => {
229-
doneCallback()
220+
menuItems.push(
221+
{
222+
label: 'Merge transcript',
223+
onClick: () => {
224+
;(session as unknown as AbstractSessionModel).queueDialog(
225+
(doneCallback) => [
226+
MergeTranscripts,
227+
{
228+
session,
229+
handleClose: () => {
230+
doneCallback()
231+
},
232+
changeManager,
233+
sourceFeature: feature,
234+
sourceAssemblyId: currentAssemblyId,
235+
selectedFeature,
236+
setSelectedFeature: (feature?: AnnotationFeature) => {
237+
display.setSelectedFeature(feature)
238+
},
230239
},
231-
changeManager,
232-
sourceFeature: feature,
233-
sourceAssemblyId: currentAssemblyId,
234-
selectedFeature,
235-
setSelectedFeature: (feature?: AnnotationFeature) => {
236-
display.setSelectedFeature(feature)
240+
],
241+
)
242+
},
243+
},
244+
{
245+
label: 'Duplicate feature',
246+
onClick: () => {
247+
;(session as unknown as AbstractSessionModel).queueDialog(
248+
(doneCallback) => [
249+
DuplicateTranscript,
250+
{
251+
session,
252+
handleClose: () => {
253+
doneCallback()
254+
},
255+
changeManager,
256+
sourceFeature: feature,
257+
sourceAssemblyId: currentAssemblyId,
258+
selectedFeature,
259+
setSelectedFeature: (feature?: AnnotationFeature) => {
260+
display.setSelectedFeature(feature)
261+
},
237262
},
238-
},
239-
],
240-
)
263+
],
264+
)
265+
},
241266
},
242-
})
267+
)
243268
return menuItems
244269
}
245270

packages/jbrowse-plugin-apollo/src/components/CreateApolloAnnotation.tsx

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
LocationStartChange,
1010
} from '@apollo-annotation/shared'
1111
import type { Assembly } from '@jbrowse/core/assemblyManager/assembly'
12+
import { readConfObject } from '@jbrowse/core/configuration'
1213
import type { AbstractSessionModel } from '@jbrowse/core/util'
1314
import { getSnapshot } from '@jbrowse/mobx-state-tree'
1415
import {
@@ -30,6 +31,7 @@ import ObjectID from 'bson-objectid'
3031
import React, { useEffect, useMemo, useState } from 'react'
3132

3233
import type { ApolloSessionModel } from '../session'
34+
import { removeSkippedAttributes } from '../util'
3335

3436
import { Dialog } from './Dialog'
3537

@@ -162,6 +164,11 @@ export function CreateApolloAnnotation({
162164
region,
163165
}: CreateApolloAnnotationProps) {
164166
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 ?? [])
165172
const { featureTypeOntology } =
166173
apolloSessionModel.apolloDataStore.ontologyManager
167174
const childIds = useMemo(
@@ -340,23 +347,28 @@ export function CreateApolloAnnotation({
340347

341348
// Copies gene feature along with its selected children
342349
const copyGeneFeature = async () => {
350+
const copiedAnnotationFeature = {
351+
...annotationFeature,
352+
} as AnnotationFeatureSnapshot
353+
removeSkippedAttributes(copiedAnnotationFeature, skippedAttributesOnCopy)
354+
343355
let change
344356
if (
345-
annotationFeature.children &&
357+
copiedAnnotationFeature.children &&
346358
checkedChildrens.length !==
347-
Object.values(annotationFeature.children).length
359+
Object.values(copiedAnnotationFeature.children).length
348360
) {
349361
// IF SOME CHILDREN ARE CHECKED
350362
const childrens: Record<string, AnnotationFeatureSnapshot> = {}
351363
for (const childId of checkedChildrens) {
352-
childrens[childId] = annotationFeature.children[childId]
364+
childrens[childId] = copiedAnnotationFeature.children[childId]
353365
}
354366
change = new AddFeatureChange({
355367
changedIds: [annotationFeature._id],
356368
typeName: 'AddFeatureChange',
357369
assembly: assembly.name,
358370
addedFeature: {
359-
...annotationFeature,
371+
...copiedAnnotationFeature,
360372
children: childrens,
361373
},
362374
})
@@ -366,7 +378,7 @@ export function CreateApolloAnnotation({
366378
changedIds: [annotationFeature._id],
367379
typeName: 'AddFeatureChange',
368380
assembly: assembly.name,
369-
addedFeature: annotationFeature,
381+
addedFeature: copiedAnnotationFeature,
370382
})
371383
}
372384

@@ -380,7 +392,10 @@ export function CreateApolloAnnotation({
380392
return
381393
}
382394
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)
384399
transcript.strand = selectedDestinationFeature.strand
385400

386401
// update strand of transcript children if they exist
@@ -405,9 +420,20 @@ export function CreateApolloAnnotation({
405420
const createNewGeneFeatureWithTranscripts = async (
406421
childrens: Record<string, AnnotationFeatureSnapshot>,
407422
) => {
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+
408430
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+
)
411437
const change = new AddFeatureChange({
412438
changedIds: [newGeneId],
413439
typeName: 'AddFeatureChange',
@@ -419,7 +445,7 @@ export function CreateApolloAnnotation({
419445
max,
420446
strand: annotationFeature.strand,
421447
type: 'gene',
422-
children: childrens,
448+
children: copiedChildrens,
423449
attributes: {
424450
name: [getGeneNameOrId(annotationFeature)],
425451
gene_name: [getGeneNameOrId(annotationFeature)],

packages/jbrowse-plugin-apollo/src/components/DuplicateTranscript.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
AnnotationFeatureSnapshot,
55
} from '@apollo-annotation/mst'
66
import { AddFeatureChange } from '@apollo-annotation/shared'
7+
import { readConfObject } from '@jbrowse/core/configuration'
78
import type { AbstractSessionModel } from '@jbrowse/core/util/types'
89
import { getSnapshot } from '@jbrowse/mobx-state-tree'
910
import {
@@ -17,6 +18,7 @@ import React, { useState } from 'react'
1718

1819
import type { ChangeManager } from '../ChangeManager'
1920
import type { ApolloSessionModel } from '../session'
21+
import { removeSkippedAttributes } from '../util'
2022

2123
import { Dialog } from './Dialog'
2224

@@ -71,6 +73,14 @@ export function DuplicateTranscript({
7173
duplicateTranscript.children = newChildren
7274
}
7375

76+
// skip attributes that are configured (SKIPPED_ATTRIBUTES_ON_COPY env var in backend)
77+
const configuredSkippedAttributes = readConfObject(
78+
session.getPluginConfiguration(),
79+
'skippedAttributesOnCopy',
80+
) as string[] | undefined
81+
const skippedAttributesOnCopy = new Set(configuredSkippedAttributes ?? [])
82+
removeSkippedAttributes(duplicateTranscript, skippedAttributesOnCopy)
83+
7484
const change = new AddFeatureChange({
7585
parentFeatureId: parentGene._id,
7686
changedIds: [parentGene._id],

packages/jbrowse-plugin-apollo/src/config.ts

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,36 +3,42 @@ import { types } from '@jbrowse/mobx-state-tree'
33

44
import { OntologyRecordConfiguration } from './OntologyManager'
55

6-
const ApolloPluginConfigurationSchema = ConfigurationSchema(
7-
'ApolloPlugin',
8-
{
9-
ontologies: types.array(OntologyRecordConfiguration),
10-
featureTypeOntologyName: {
11-
description: 'Name of the feature type ontology',
12-
type: 'string',
13-
defaultValue: 'Sequence Ontology',
14-
},
15-
hasRole: {
16-
description: 'Flag used internally by jbrowse-plugin-apollo',
17-
type: 'boolean',
18-
defaultValue: false,
6+
const ApolloPluginConfigurationSchema: ReturnType<typeof ConfigurationSchema> =
7+
ConfigurationSchema(
8+
'ApolloPlugin',
9+
{
10+
ontologies: types.array(OntologyRecordConfiguration),
11+
featureTypeOntologyName: {
12+
description: 'Name of the feature type ontology',
13+
type: 'string',
14+
defaultValue: 'Sequence Ontology',
15+
},
16+
hasRole: {
17+
description: 'Flag used internally by jbrowse-plugin-apollo',
18+
type: 'boolean',
19+
defaultValue: false,
20+
},
21+
skippedAttributesOnCopy: {
22+
description: 'Feature attribute keys to skip when copying features',
23+
type: 'stringArray',
24+
defaultValue: [],
25+
},
26+
geneBackgroundColor: {
27+
description: 'Color for feature background',
28+
type: 'string',
29+
defaultValue: 'jexl:geneBackgroundColor(featureType)',
30+
contextVariable: ['featureType'],
31+
},
1932
},
20-
geneBackgroundColor: {
21-
description: 'Color for feature background',
22-
type: 'string',
23-
defaultValue: 'jexl:geneBackgroundColor(featureType)',
24-
contextVariable: ['featureType'],
33+
{
34+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
35+
actions: (self: any) => ({
36+
addOntology(ontologySnapshot: { name: string }) {
37+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
38+
self.ontologies.push(ontologySnapshot)
39+
},
40+
}),
2541
},
26-
},
27-
{
28-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
29-
actions: (self: any) => ({
30-
addOntology(ontologySnapshot: { name: string }) {
31-
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
32-
self.ontologies.push(ontologySnapshot)
33-
},
34-
}),
35-
},
36-
)
42+
)
3743

3844
export default ApolloPluginConfigurationSchema

packages/jbrowse-plugin-apollo/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ validationRegistry.registerValidation(new ParentChildValidation())
118118
export default class ApolloPlugin extends Plugin {
119119
name = 'ApolloPlugin'
120120
version = version
121-
configurationSchema = ApolloPluginConfigurationSchema
121+
configurationSchema: ReturnType<typeof ConfigurationSchema> =
122+
ApolloPluginConfigurationSchema
122123

123124
install(pluginManager: PluginManager) {
124125
installApolloSequenceAdapter(pluginManager)

0 commit comments

Comments
 (0)