@apollo-annotation/jbrowse-plugin-apollo 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ApolloInternetAccount/components/AuthTypeSelector.d.ts +8 -2
- package/dist/ApolloInternetAccount/components/AuthTypeSelector.d.ts.map +1 -1
- package/dist/ApolloInternetAccount/components/LoginButtons.d.ts +8 -3
- package/dist/ApolloInternetAccount/components/LoginButtons.d.ts.map +1 -1
- package/dist/ApolloInternetAccount/configSchema.d.ts +44 -0
- package/dist/ApolloInternetAccount/configSchema.d.ts.map +1 -0
- package/dist/ApolloInternetAccount/model.d.ts +174 -0
- package/dist/ApolloInternetAccount/model.d.ts.map +1 -0
- package/dist/ApolloJobModel.d.ts.map +1 -1
- package/dist/ApolloRefNameAliasAdapter/configSchema.d.ts +8 -0
- package/dist/ApolloRefNameAliasAdapter/configSchema.d.ts.map +1 -0
- package/dist/ApolloSequenceAdapter/configSchema.d.ts +8 -0
- package/dist/ApolloSequenceAdapter/configSchema.d.ts.map +1 -0
- package/dist/ApolloTextSearchAdapter/configSchema.d.ts +20 -0
- package/dist/ApolloTextSearchAdapter/configSchema.d.ts.map +1 -0
- package/dist/BackendDrivers/CollaborationServerDriver.d.ts +1 -1
- package/dist/BackendDrivers/CollaborationServerDriver.d.ts.map +1 -1
- package/dist/BackendDrivers/LocalDriver/LocalDriver.d.ts.map +1 -1
- package/dist/FeatureDetailsWidget/ApolloFeatureDetailsWidget.d.ts.map +1 -1
- package/dist/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.d.ts.map +1 -1
- package/dist/FeatureDetailsWidget/Attributes.d.ts.map +1 -1
- package/dist/FeatureDetailsWidget/DefaultAttributeEditor.d.ts.map +1 -1
- package/dist/FeatureDetailsWidget/DefaultAttributeViewer.d.ts.map +1 -1
- package/dist/FeatureDetailsWidget/NumberTextField.d.ts.map +1 -1
- package/dist/FeatureDetailsWidget/StringTextField.d.ts.map +1 -1
- package/dist/FeatureDetailsWidget/TranscriptSequence.d.ts.map +1 -1
- package/dist/FeatureDetailsWidget/TranscriptWidgetEditLocation.d.ts.map +1 -1
- package/dist/FeatureDetailsWidget/Translation.d.ts +14 -0
- package/dist/FeatureDetailsWidget/Translation.d.ts.map +1 -0
- package/dist/LinearApolloDisplay/components/CheckResultWarnings.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/configSchema.d.ts +2 -0
- package/dist/LinearApolloDisplay/configSchema.d.ts.map +1 -0
- package/dist/LinearApolloDisplay/glyphs/ExonGlyph.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/glyphs/GeneGlyph.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/glyphs/TranscriptGlyph.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/stateModel/base.d.ts +1 -18
- package/dist/LinearApolloDisplay/stateModel/base.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/stateModel/index.d.ts +1 -17
- package/dist/LinearApolloDisplay/stateModel/index.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/stateModel/layouts.d.ts +2 -19
- package/dist/LinearApolloDisplay/stateModel/layouts.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/stateModel/mouseEvents.d.ts +2 -34
- package/dist/LinearApolloDisplay/stateModel/mouseEvents.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/stateModel/rendering.d.ts +2 -19
- package/dist/LinearApolloDisplay/stateModel/rendering.d.ts.map +1 -1
- package/dist/LinearApolloReferenceSequenceDisplay/configSchema.d.ts +2 -0
- package/dist/LinearApolloReferenceSequenceDisplay/configSchema.d.ts.map +1 -0
- package/dist/LinearApolloReferenceSequenceDisplay/stateModel/base.d.ts +1 -1
- package/dist/LinearApolloReferenceSequenceDisplay/stateModel/base.d.ts.map +1 -1
- package/dist/LinearApolloReferenceSequenceDisplay/stateModel/index.d.ts +1 -1
- package/dist/LinearApolloReferenceSequenceDisplay/stateModel/rendering.d.ts +1 -1
- package/dist/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.d.ts.map +1 -1
- package/dist/LinearApolloSixFrameDisplay/configSchema.d.ts +2 -0
- package/dist/LinearApolloSixFrameDisplay/configSchema.d.ts.map +1 -0
- package/dist/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.d.ts.map +1 -1
- package/dist/LinearApolloSixFrameDisplay/stateModel/base.d.ts +1 -1
- package/dist/LinearApolloSixFrameDisplay/stateModel/base.d.ts.map +1 -1
- package/dist/LinearApolloSixFrameDisplay/stateModel/index.d.ts +1 -1
- package/dist/LinearApolloSixFrameDisplay/stateModel/index.d.ts.map +1 -1
- package/dist/LinearApolloSixFrameDisplay/stateModel/layouts.d.ts +2 -3
- package/dist/LinearApolloSixFrameDisplay/stateModel/layouts.d.ts.map +1 -1
- package/dist/LinearApolloSixFrameDisplay/stateModel/mouseEvents.d.ts +2 -2
- package/dist/LinearApolloSixFrameDisplay/stateModel/mouseEvents.d.ts.map +1 -1
- package/dist/LinearApolloSixFrameDisplay/stateModel/rendering.d.ts +2 -3
- package/dist/LinearApolloSixFrameDisplay/stateModel/rendering.d.ts.map +1 -1
- package/dist/OntologyManager/OntologyStore/fulltext.d.ts.map +1 -1
- package/dist/OntologyManager/index.d.ts +734 -0
- package/dist/OntologyManager/index.d.ts.map +1 -0
- package/dist/TabularEditor/HybridGrid/NumberCell.d.ts.map +1 -1
- package/dist/components/AddCodingSequence.d.ts +14 -0
- package/dist/components/AddCodingSequence.d.ts.map +1 -0
- package/dist/components/AddRefSeqAliases.d.ts.map +1 -1
- package/dist/components/CopyFeature.d.ts.map +1 -1
- package/dist/components/CreateApolloAnnotation.d.ts.map +1 -1
- package/dist/components/DeleteFeature.d.ts.map +1 -1
- package/dist/components/DownloadGFF3.d.ts.map +1 -1
- package/dist/components/DuplicateFeatureDialog.d.ts +12 -0
- package/dist/components/DuplicateFeatureDialog.d.ts.map +1 -0
- package/dist/components/ImportAnnotations.d.ts +9 -0
- package/dist/components/ImportAnnotations.d.ts.map +1 -0
- package/dist/components/ManageUsers.d.ts.map +1 -1
- package/dist/components/OntologyTermMultiSelect.d.ts.map +1 -1
- package/dist/components/ViewChangeLog.d.ts.map +1 -1
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/extensions/annotationFromPileup.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +830 -434
- package/dist/index.esm.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.development.js +825 -429
- 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 +863 -468
- 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/session/ClientDataStore.d.ts +2194 -0
- package/dist/session/ClientDataStore.d.ts.map +1 -0
- package/dist/session/handleApolloFeaturesUrlParam.d.ts +8 -0
- package/dist/session/handleApolloFeaturesUrlParam.d.ts.map +1 -0
- package/dist/session/session.d.ts +6788 -0
- package/dist/session/session.d.ts.map +1 -0
- package/dist/util/displayUtils.d.ts +36 -0
- package/dist/util/displayUtils.d.ts.map +1 -0
- package/dist/util/sequenceUtils.d.ts +2 -0
- package/dist/util/sequenceUtils.d.ts.map +1 -0
- package/package.json +14 -14
- package/src/ApolloInternetAccount/components/AuthTypeSelector.tsx +73 -38
- package/src/ApolloInternetAccount/components/LoginButtons.tsx +31 -10
- package/src/ApolloInternetAccount/model.ts +8 -5
- package/src/ApolloJobModel.ts +3 -8
- package/src/ApolloTextSearchAdapter/ApolloTextSearchAdapter.ts +1 -1
- package/src/BackendDrivers/CollaborationServerDriver.ts +7 -11
- package/src/BackendDrivers/LocalDriver/LocalDriver.ts +13 -4
- package/src/FeatureDetailsWidget/ApolloFeatureDetailsWidget.tsx +1 -0
- package/src/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.tsx +4 -2
- package/src/FeatureDetailsWidget/Attributes.tsx +1 -0
- package/src/FeatureDetailsWidget/DefaultAttributeEditor.tsx +1 -0
- package/src/FeatureDetailsWidget/DefaultAttributeViewer.tsx +1 -0
- package/src/FeatureDetailsWidget/NumberTextField.tsx +1 -0
- package/src/FeatureDetailsWidget/StringTextField.tsx +1 -0
- package/src/FeatureDetailsWidget/TranscriptSequence.tsx +2 -1
- package/src/FeatureDetailsWidget/TranscriptWidgetEditLocation.tsx +17 -354
- package/src/FeatureDetailsWidget/Translation.tsx +358 -0
- package/src/LinearApolloDisplay/components/CheckResultWarnings.tsx +4 -1
- package/src/LinearApolloDisplay/glyphs/ExonGlyph.ts +2 -5
- package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +4 -6
- package/src/LinearApolloDisplay/glyphs/TranscriptGlyph.ts +39 -6
- package/src/LinearApolloDisplay/stateModel/base.ts +47 -23
- package/src/LinearApolloDisplay/stateModel/layouts.ts +7 -5
- package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +4 -1
- package/src/LinearApolloDisplay/stateModel/rendering.ts +1 -5
- package/src/LinearApolloReferenceSequenceDisplay/stateModel/base.ts +10 -10
- package/src/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.tsx +5 -3
- package/src/LinearApolloSixFrameDisplay/components/TrackLines.tsx +1 -1
- package/src/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.ts +2 -3
- package/src/LinearApolloSixFrameDisplay/stateModel/base.ts +12 -20
- package/src/LinearApolloSixFrameDisplay/stateModel/layouts.ts +10 -6
- package/src/LinearApolloSixFrameDisplay/stateModel/mouseEvents.ts +38 -45
- package/src/LinearApolloSixFrameDisplay/stateModel/rendering.ts +1 -4
- package/src/OntologyManager/OntologyStore/fulltext.ts +0 -2
- package/src/OntologyManager/OntologyStore/index.ts +1 -1
- package/src/TabularEditor/HybridGrid/ChangeHandling.ts +2 -2
- package/src/TabularEditor/HybridGrid/NumberCell.tsx +2 -1
- package/src/components/AddAssemblyAliases.tsx +1 -1
- package/src/components/AddCodingSequence.tsx +255 -0
- package/src/components/AddFeature.tsx +1 -1
- package/src/components/AddRefSeqAliases.tsx +3 -2
- package/src/components/CopyFeature.tsx +9 -7
- package/src/components/CreateApolloAnnotation.tsx +28 -23
- package/src/components/DeleteAssembly.tsx +2 -2
- package/src/components/DeleteFeature.tsx +1 -4
- package/src/components/DownloadGFF3.tsx +4 -3
- package/src/components/DuplicateFeatureDialog.tsx +154 -0
- package/src/components/DuplicateTranscript.tsx +1 -1
- package/src/components/FilterTranscripts.tsx +1 -1
- package/src/components/ImportAnnotations.tsx +108 -0
- package/src/components/ManageUsers.tsx +1 -2
- package/src/components/OntologyTermAutocomplete.tsx +1 -3
- package/src/components/OntologyTermMultiSelect.tsx +3 -1
- package/src/components/ViewChangeLog.tsx +2 -1
- package/src/components/index.ts +2 -0
- package/src/extensions/annotationFromPileup.ts +34 -26
- package/src/index.ts +9 -8
- package/src/session/ClientDataStore.ts +16 -21
- package/src/session/handleApolloFeaturesUrlParam.ts +122 -0
- package/src/session/session.ts +49 -9
- package/src/util/annotationFeatureUtils.ts +1 -1
- package/src/util/displayUtils.ts +1 -1
- package/src/util/glyphUtils.ts +3 -3
- package/src/util/sequenceUtils.ts +29 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/unbound-method */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-misused-promises */
|
|
3
|
+
import {
|
|
4
|
+
AddFeatureChange,
|
|
5
|
+
gff3ToAnnotationFeature,
|
|
6
|
+
} from '@apollo-annotation/shared'
|
|
7
|
+
import { GFFTransformer } from '@gmod/gff'
|
|
8
|
+
import {
|
|
9
|
+
Button,
|
|
10
|
+
DialogActions,
|
|
11
|
+
DialogContent,
|
|
12
|
+
DialogContentText,
|
|
13
|
+
LinearProgress,
|
|
14
|
+
} from '@mui/material'
|
|
15
|
+
import React, { useState } from 'react'
|
|
16
|
+
|
|
17
|
+
import type { ChangeManager } from '../ChangeManager'
|
|
18
|
+
import type { ApolloSessionModel } from '../session'
|
|
19
|
+
|
|
20
|
+
import { Dialog } from './Dialog'
|
|
21
|
+
|
|
22
|
+
interface ImportAnnotationsProps {
|
|
23
|
+
session: ApolloSessionModel
|
|
24
|
+
handleClose(): void
|
|
25
|
+
assemblyName: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function ImportAnnotations({
|
|
29
|
+
assemblyName,
|
|
30
|
+
handleClose,
|
|
31
|
+
session,
|
|
32
|
+
}: ImportAnnotationsProps) {
|
|
33
|
+
const { changeManager } = session.apolloDataStore as {
|
|
34
|
+
changeManager: ChangeManager
|
|
35
|
+
}
|
|
36
|
+
const [file, setFile] = useState<File>()
|
|
37
|
+
const [errorMessage, setErrorMessage] = useState('')
|
|
38
|
+
const [loading, setLoading] = useState(false)
|
|
39
|
+
|
|
40
|
+
function handleChangeFile(e: React.ChangeEvent<HTMLInputElement>) {
|
|
41
|
+
if (e.target.files) {
|
|
42
|
+
setFile(e.target.files[0])
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function onSubmit(event: React.FormEvent<HTMLFormElement>) {
|
|
47
|
+
event.preventDefault()
|
|
48
|
+
if (!file) {
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
setLoading(true)
|
|
52
|
+
setErrorMessage('')
|
|
53
|
+
try {
|
|
54
|
+
const stream = file
|
|
55
|
+
.stream()
|
|
56
|
+
.pipeThrough(
|
|
57
|
+
new TransformStream(new GFFTransformer({ parseSequences: false })),
|
|
58
|
+
)
|
|
59
|
+
for await (const value of stream) {
|
|
60
|
+
const annotationFeature = gff3ToAnnotationFeature(value)
|
|
61
|
+
const change = new AddFeatureChange({
|
|
62
|
+
changedIds: [annotationFeature._id],
|
|
63
|
+
typeName: 'AddFeatureChange',
|
|
64
|
+
assembly: assemblyName,
|
|
65
|
+
addedFeature: annotationFeature,
|
|
66
|
+
})
|
|
67
|
+
await changeManager.submit(change)
|
|
68
|
+
}
|
|
69
|
+
handleClose()
|
|
70
|
+
} catch (error) {
|
|
71
|
+
setErrorMessage(String(error))
|
|
72
|
+
} finally {
|
|
73
|
+
setLoading(false)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<Dialog open title="Import annotations" handleClose={handleClose}>
|
|
79
|
+
{loading ? <LinearProgress /> : null}
|
|
80
|
+
<form onSubmit={onSubmit}>
|
|
81
|
+
<DialogContent>
|
|
82
|
+
<DialogContentText>
|
|
83
|
+
Import annotations from a GFF3 file into the current Apollo track.
|
|
84
|
+
Features are parsed and stored locally in the browser, so importing
|
|
85
|
+
very large GFF3 files is not recommended.
|
|
86
|
+
</DialogContentText>
|
|
87
|
+
<input
|
|
88
|
+
type="file"
|
|
89
|
+
accept=".gff,.gff3"
|
|
90
|
+
onChange={handleChangeFile}
|
|
91
|
+
disabled={loading}
|
|
92
|
+
/>
|
|
93
|
+
{errorMessage ? (
|
|
94
|
+
<DialogContentText color="error">{errorMessage}</DialogContentText>
|
|
95
|
+
) : null}
|
|
96
|
+
</DialogContent>
|
|
97
|
+
<DialogActions>
|
|
98
|
+
<Button variant="contained" type="submit" disabled={!file || loading}>
|
|
99
|
+
Import
|
|
100
|
+
</Button>
|
|
101
|
+
<Button variant="outlined" onClick={handleClose}>
|
|
102
|
+
Cancel
|
|
103
|
+
</Button>
|
|
104
|
+
</DialogActions>
|
|
105
|
+
</form>
|
|
106
|
+
</Dialog>
|
|
107
|
+
)
|
|
108
|
+
}
|
|
@@ -25,7 +25,6 @@ import {
|
|
|
25
25
|
type GridRowId,
|
|
26
26
|
type GridRowModel,
|
|
27
27
|
type GridRowParams,
|
|
28
|
-
GridToolbar,
|
|
29
28
|
} from '@mui/x-data-grid'
|
|
30
29
|
import React, { useEffect, useState } from 'react'
|
|
31
30
|
|
|
@@ -215,7 +214,7 @@ export function ManageUsers({
|
|
|
215
214
|
rows={users}
|
|
216
215
|
columns={gridColumns}
|
|
217
216
|
getRowId={(row) => row._id}
|
|
218
|
-
|
|
217
|
+
showToolbar
|
|
219
218
|
getRowHeight={() => 'auto'}
|
|
220
219
|
isCellEditable={(params: GridCellParams) =>
|
|
221
220
|
!isCurrentUser(params.id)
|
|
@@ -235,8 +235,6 @@ async function getValidTerms(
|
|
|
235
235
|
}
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
-
|
|
239
|
-
result = await ontologyStore.getAllTerms()
|
|
240
|
-
}
|
|
238
|
+
result ??= await ontologyStore.getAllTerms()
|
|
241
239
|
return filterTerms ? result.filter((element) => filterTerms(element)) : result
|
|
242
240
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable @eslint-react/set-state-in-effect */
|
|
1
2
|
/* eslint-disable @typescript-eslint/unbound-method */
|
|
2
3
|
/* eslint-disable @typescript-eslint/use-unknown-in-catch-callback-variable */
|
|
3
4
|
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
|
|
@@ -78,7 +79,7 @@ function TermTagWithTooltip({
|
|
|
78
79
|
.objectStore('nodes')
|
|
79
80
|
.get(termUrl)
|
|
80
81
|
|
|
81
|
-
if (term
|
|
82
|
+
if (term?.lbl && !signal.aborted) {
|
|
82
83
|
setDescription(term.lbl || 'no label')
|
|
83
84
|
}
|
|
84
85
|
}
|
|
@@ -304,6 +305,7 @@ function HighlightedText(props: { str: string; search: string }) {
|
|
|
304
305
|
<>
|
|
305
306
|
{parts.map((part, index) => (
|
|
306
307
|
<Typography
|
|
308
|
+
// eslint-disable-next-line @eslint-react/no-array-index-key
|
|
307
309
|
key={index}
|
|
308
310
|
component="span"
|
|
309
311
|
sx={{ fontWeight: part.highlight ? 'bold' : 'regular' }}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
5
5
|
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
|
6
6
|
import { changeRegistry } from '@apollo-annotation/common'
|
|
7
|
+
import type { Assembly } from '@jbrowse/core/assemblyManager/assembly'
|
|
7
8
|
import type { AbstractSessionModel } from '@jbrowse/core/util'
|
|
8
9
|
import { makeStyles } from '@jbrowse/core/util/tss-react'
|
|
9
10
|
import {
|
|
@@ -102,7 +103,7 @@ export function ViewChangeLog({
|
|
|
102
103
|
|
|
103
104
|
const { apolloDataStore } = session
|
|
104
105
|
const { assemblyManager } = session as unknown as AbstractSessionModel
|
|
105
|
-
const assembly = assemblyManager.get(assemblyId)
|
|
106
|
+
const assembly = assemblyManager.get(assemblyId) as Assembly | undefined
|
|
106
107
|
const assemblyName = assembly?.displayName ?? assemblyId
|
|
107
108
|
|
|
108
109
|
const gridColumns: GridColDef[] = [
|
package/src/components/index.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
export * from './AddAssembly'
|
|
2
2
|
export * from './AddAssemblyAliases'
|
|
3
3
|
export * from './AddChildFeature'
|
|
4
|
+
export * from './AddCodingSequence'
|
|
4
5
|
export * from './AddFeature'
|
|
5
6
|
export * from './ColorFeature'
|
|
6
7
|
export * from './CopyFeature'
|
|
7
8
|
export * from './DeleteAssembly'
|
|
8
9
|
export * from './DeleteFeature'
|
|
9
10
|
export * from './DownloadGFF3'
|
|
11
|
+
export * from './ImportAnnotations'
|
|
10
12
|
export * from './ImportFeatures'
|
|
11
13
|
export * from './LogOut'
|
|
12
14
|
export * from './ManageChecks'
|
|
@@ -8,11 +8,7 @@ import type {
|
|
|
8
8
|
DisplayType,
|
|
9
9
|
PluggableElementType,
|
|
10
10
|
} from '@jbrowse/core/pluggableElementTypes'
|
|
11
|
-
import {
|
|
12
|
-
type AbstractSessionModel,
|
|
13
|
-
getContainingView,
|
|
14
|
-
getSession,
|
|
15
|
-
} from '@jbrowse/core/util'
|
|
11
|
+
import { getContainingView, getSession } from '@jbrowse/core/util'
|
|
16
12
|
import type { Feature } from '@jbrowse/core/util/simpleFeature'
|
|
17
13
|
import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
|
|
18
14
|
import ObjectID from 'bson-objectid'
|
|
@@ -59,9 +55,25 @@ export function annotationFromPileup(pluggableElement: PluggableElementType) {
|
|
|
59
55
|
getAnnotationFeature(jbrowseFeature: Feature, refSeqId: string) {
|
|
60
56
|
const start: number = jbrowseFeature.get('start')
|
|
61
57
|
const end: number = jbrowseFeature.get('end')
|
|
62
|
-
const strand = jbrowseFeature.get('strand') as 1 | -1 | undefined
|
|
63
58
|
const name = jbrowseFeature.get('name') as string | undefined
|
|
64
59
|
|
|
60
|
+
let strand: 1 | -1 | undefined
|
|
61
|
+
const tags = jbrowseFeature.get('tags') as Record<
|
|
62
|
+
string,
|
|
63
|
+
string | number | undefined
|
|
64
|
+
>
|
|
65
|
+
const { ts, TS, XS } = tags
|
|
66
|
+
for (const tag of [ts, TS, XS]) {
|
|
67
|
+
if (!strand && tag) {
|
|
68
|
+
if ([1, '1', '+'].includes(tag)) {
|
|
69
|
+
strand = 1
|
|
70
|
+
} else if ([-1, '-1', '-'].includes(tag)) {
|
|
71
|
+
strand = -1
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
strand ??= jbrowseFeature.get('strand') as 1 | -1 | undefined
|
|
76
|
+
|
|
65
77
|
const cigarData = jbrowseFeature.get('CIGAR') as string
|
|
66
78
|
const ops = parseCigar(cigarData)
|
|
67
79
|
let position = start
|
|
@@ -81,9 +93,7 @@ export function annotationFromPileup(pluggableElement: PluggableElementType) {
|
|
|
81
93
|
case 'M':
|
|
82
94
|
case '=':
|
|
83
95
|
case 'X': {
|
|
84
|
-
|
|
85
|
-
currentExonStart = position
|
|
86
|
-
}
|
|
96
|
+
currentExonStart ??= position
|
|
87
97
|
position += len
|
|
88
98
|
break
|
|
89
99
|
}
|
|
@@ -190,24 +200,22 @@ export function annotationFromPileup(pluggableElement: PluggableElementType) {
|
|
|
190
200
|
}
|
|
191
201
|
refSeqId = backendRefSeqId
|
|
192
202
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
doneCallback()
|
|
200
|
-
},
|
|
201
|
-
annotationFeature: self.getAnnotationFeature(
|
|
202
|
-
jbrowseFeature,
|
|
203
|
-
refSeqId,
|
|
204
|
-
),
|
|
205
|
-
assembly,
|
|
206
|
-
refSeqId,
|
|
207
|
-
region,
|
|
203
|
+
session.queueDialog((doneCallback) => [
|
|
204
|
+
CreateApolloAnnotation,
|
|
205
|
+
{
|
|
206
|
+
session,
|
|
207
|
+
handleClose: () => {
|
|
208
|
+
doneCallback()
|
|
208
209
|
},
|
|
209
|
-
|
|
210
|
-
|
|
210
|
+
annotationFeature: self.getAnnotationFeature(
|
|
211
|
+
jbrowseFeature,
|
|
212
|
+
refSeqId,
|
|
213
|
+
),
|
|
214
|
+
assembly,
|
|
215
|
+
refSeqId,
|
|
216
|
+
region,
|
|
217
|
+
},
|
|
218
|
+
])
|
|
211
219
|
},
|
|
212
220
|
},
|
|
213
221
|
]
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/unbound-method */
|
|
2
|
-
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
|
|
3
2
|
/* eslint-disable @typescript-eslint/no-misused-promises */
|
|
4
3
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
5
4
|
import { changeRegistry, checkRegistry } from '@apollo-annotation/common'
|
|
@@ -78,8 +77,10 @@ import { addTopLevelMenus } from './menus'
|
|
|
78
77
|
import { type ApolloSessionModel, extendSession } from './session'
|
|
79
78
|
|
|
80
79
|
interface RpcHandle {
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
client: {
|
|
81
|
+
on?(event: string, listener: (event: MessageEvent) => void): void
|
|
82
|
+
}
|
|
83
|
+
worker: Worker
|
|
83
84
|
}
|
|
84
85
|
|
|
85
86
|
interface ApolloMessageData {
|
|
@@ -356,10 +357,10 @@ export default class ApolloPlugin extends Plugin {
|
|
|
356
357
|
pluginManager.addToExtensionPoint(
|
|
357
358
|
'Core-extendWorker',
|
|
358
359
|
(handle: RpcHandle) => {
|
|
359
|
-
if (!('on' in handle && handle.on)) {
|
|
360
|
+
if (!('on' in handle.client && handle.client.on)) {
|
|
360
361
|
return handle
|
|
361
362
|
}
|
|
362
|
-
handle.on('apollo', async (event: MessageEvent) => {
|
|
363
|
+
handle.client.on('apollo', async (event: MessageEvent) => {
|
|
363
364
|
if (!isApolloMessageData(event)) {
|
|
364
365
|
return
|
|
365
366
|
}
|
|
@@ -382,7 +383,7 @@ export default class ApolloPlugin extends Plugin {
|
|
|
382
383
|
}
|
|
383
384
|
const { seq: sequence } =
|
|
384
385
|
await backendDriver.getSequence(region)
|
|
385
|
-
handle.
|
|
386
|
+
handle.worker.postMessage({
|
|
386
387
|
apollo,
|
|
387
388
|
messageId,
|
|
388
389
|
sequence,
|
|
@@ -404,7 +405,7 @@ export default class ApolloPlugin extends Plugin {
|
|
|
404
405
|
break
|
|
405
406
|
}
|
|
406
407
|
const regions = await backendDriver.getRegions(assembly)
|
|
407
|
-
handle.
|
|
408
|
+
handle.worker.postMessage({
|
|
408
409
|
apollo,
|
|
409
410
|
messageId,
|
|
410
411
|
regions,
|
|
@@ -427,7 +428,7 @@ export default class ApolloPlugin extends Plugin {
|
|
|
427
428
|
}
|
|
428
429
|
const refNameAliases =
|
|
429
430
|
await backendDriver.getRefNameAliases(assembly)
|
|
430
|
-
handle.
|
|
431
|
+
handle.worker.postMessage({
|
|
431
432
|
apollo,
|
|
432
433
|
messageId,
|
|
433
434
|
refNameAliases,
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
CheckResult,
|
|
13
13
|
type CheckResultSnapshot,
|
|
14
14
|
} from '@apollo-annotation/mst'
|
|
15
|
+
import type { Assembly } from '@jbrowse/core/assemblyManager/assembly'
|
|
15
16
|
import {
|
|
16
17
|
type AnyConfigurationModel,
|
|
17
18
|
getConf,
|
|
@@ -106,7 +107,9 @@ export function clientDataStoreFactory(
|
|
|
106
107
|
let ref = apolloAssembly.refSeqs.get(feature.refSeq)
|
|
107
108
|
if (!ref) {
|
|
108
109
|
// maybe it's a valid refName that we haven't loaded yet
|
|
109
|
-
const assembly = assemblyManager.get(assemblyId)
|
|
110
|
+
const assembly = assemblyManager.get(assemblyId) as
|
|
111
|
+
| Assembly
|
|
112
|
+
| undefined
|
|
110
113
|
if (!assembly) {
|
|
111
114
|
throw new Error(
|
|
112
115
|
`Could not find assembly "${assemblyId}" to add feature "${feature._id}"`,
|
|
@@ -291,19 +294,17 @@ export function clientDataStoreFactory(
|
|
|
291
294
|
continue
|
|
292
295
|
}
|
|
293
296
|
const { assemblyName, refName } = region
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
}
|
|
297
|
+
const assembly =
|
|
298
|
+
self.assemblies.get(assemblyName) ??
|
|
299
|
+
self.assemblies.put({ _id: assemblyName, refSeqs: {} })
|
|
298
300
|
const [firstFeature] = features
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
301
|
+
const ref =
|
|
302
|
+
assembly.refSeqs.get(firstFeature.refSeq) ??
|
|
303
|
+
assembly.refSeqs.put({
|
|
302
304
|
_id: firstFeature.refSeq,
|
|
303
305
|
name: refName,
|
|
304
306
|
features: {},
|
|
305
307
|
})
|
|
306
|
-
}
|
|
307
308
|
for (const feature of features) {
|
|
308
309
|
if (!ref.features.has(feature._id)) {
|
|
309
310
|
ref.features.put(feature)
|
|
@@ -320,18 +321,12 @@ export function clientDataStoreFactory(
|
|
|
320
321
|
}
|
|
321
322
|
const { refSeq, seq } = yield backendDriver.getSequence(region)
|
|
322
323
|
const { assemblyName, end, refName, start } = region
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
ref = assembly.refSeqs.put({
|
|
330
|
-
_id: refSeq,
|
|
331
|
-
name: refName,
|
|
332
|
-
sequence: [],
|
|
333
|
-
})
|
|
334
|
-
}
|
|
324
|
+
const assembly =
|
|
325
|
+
self.assemblies.get(assemblyName) ??
|
|
326
|
+
self.assemblies.put({ _id: assemblyName, refSeqs: {} })
|
|
327
|
+
const ref =
|
|
328
|
+
assembly.refSeqs.get(refSeq) ??
|
|
329
|
+
assembly.refSeqs.put({ _id: refSeq, name: refName, sequence: [] })
|
|
335
330
|
ref.addSequence({ start, stop: end, sequence: seq })
|
|
336
331
|
}
|
|
337
332
|
}),
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type { AnnotationFeatureSnapshot } from '@apollo-annotation/mst'
|
|
2
|
+
import { AddFeatureChange } from '@apollo-annotation/shared'
|
|
3
|
+
import type { AbstractSessionModel } from '@jbrowse/core/util'
|
|
4
|
+
import type { Assembly } from '@jbrowse/core/assemblyManager/assembly'
|
|
5
|
+
import equal from 'fast-deep-equal/es6'
|
|
6
|
+
|
|
7
|
+
import { LocalDriver } from '../BackendDrivers'
|
|
8
|
+
import { openDb } from '../BackendDrivers/LocalDriver/db'
|
|
9
|
+
import { DuplicateFeatureDialog } from '../components/DuplicateFeatureDialog'
|
|
10
|
+
|
|
11
|
+
import type { ClientDataStoreModel } from './ClientDataStore'
|
|
12
|
+
|
|
13
|
+
export function toUrlSafeBase64(base64: string) {
|
|
14
|
+
return base64
|
|
15
|
+
.replaceAll('+', '-') // Replace + with -
|
|
16
|
+
.replaceAll('/', '_') // Replace / with _
|
|
17
|
+
.replace(/=+$/, '') // Remove padding characters
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function fromUrlSafeBase64(urlSafeBase64: string) {
|
|
21
|
+
let base64 = urlSafeBase64.replaceAll('-', '+').replaceAll('_', '/')
|
|
22
|
+
const pad = base64.length % 4
|
|
23
|
+
if (pad) {
|
|
24
|
+
base64 += '='.repeat(4 - pad)
|
|
25
|
+
}
|
|
26
|
+
return base64
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function compress(data: unknown) {
|
|
30
|
+
const json = JSON.stringify(data)
|
|
31
|
+
const bytes = new TextEncoder().encode(json)
|
|
32
|
+
const stream = new Blob([bytes]).stream()
|
|
33
|
+
const compressionStream = new CompressionStream('gzip')
|
|
34
|
+
const compressedStream = stream.pipeThrough(compressionStream)
|
|
35
|
+
const response = new Response(compressedStream)
|
|
36
|
+
const compressed = await response.arrayBuffer()
|
|
37
|
+
// eslint-disable-next-line unicorn/prefer-code-point
|
|
38
|
+
return btoa(String.fromCharCode(...new Uint8Array(compressed)))
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Base64 decode + decompress
|
|
42
|
+
export async function decompress(encoded: string): Promise<unknown> {
|
|
43
|
+
const binaryString = atob(encoded)
|
|
44
|
+
// eslint-disable-next-line unicorn/prefer-code-point
|
|
45
|
+
const bytes = Uint8Array.from(binaryString, (char) => char.charCodeAt(0))
|
|
46
|
+
const stream = new Blob([bytes]).stream()
|
|
47
|
+
const decompressionStream = new DecompressionStream('gzip')
|
|
48
|
+
const decompressedStream = stream.pipeThrough(decompressionStream)
|
|
49
|
+
const response = new Response(decompressedStream)
|
|
50
|
+
const decompressed = await response.arrayBuffer()
|
|
51
|
+
return JSON.parse(new TextDecoder().decode(decompressed))
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function handleApolloFeaturesUrlParam(
|
|
55
|
+
encodedFeatures: string,
|
|
56
|
+
apolloDataStore: ClientDataStoreModel,
|
|
57
|
+
assemblyManager: AbstractSessionModel['assemblyManager'],
|
|
58
|
+
session: AbstractSessionModel,
|
|
59
|
+
): Promise<void> {
|
|
60
|
+
const base64 = fromUrlSafeBase64(encodedFeatures)
|
|
61
|
+
const decompressed = await decompress(base64)
|
|
62
|
+
const featuresData = decompressed as Record<
|
|
63
|
+
string,
|
|
64
|
+
AnnotationFeatureSnapshot[]
|
|
65
|
+
>
|
|
66
|
+
for (const [assemblyName, featureSnapshots] of Object.entries(featuresData)) {
|
|
67
|
+
const backendDriver = apolloDataStore.getBackendDriver(assemblyName)
|
|
68
|
+
if (!(backendDriver instanceof LocalDriver)) {
|
|
69
|
+
continue
|
|
70
|
+
}
|
|
71
|
+
const assembly = (await assemblyManager.waitForAssembly(assemblyName)) as
|
|
72
|
+
| Assembly
|
|
73
|
+
| undefined
|
|
74
|
+
if (!assembly) {
|
|
75
|
+
throw new Error(`Assembly not found: "${assemblyName}"`)
|
|
76
|
+
}
|
|
77
|
+
const { regions } = assembly
|
|
78
|
+
if (!regions) {
|
|
79
|
+
throw new Error(`Assembly not found: "${assemblyName}"`)
|
|
80
|
+
}
|
|
81
|
+
const refNames = regions.map((r) => r.refName)
|
|
82
|
+
const db = await openDb(assemblyName, refNames)
|
|
83
|
+
for (const featureSnapshot of featureSnapshots) {
|
|
84
|
+
const storeName = `features-${featureSnapshot.refSeq}`
|
|
85
|
+
const existing = (await db.get(storeName, featureSnapshot._id)) as
|
|
86
|
+
| AnnotationFeatureSnapshot
|
|
87
|
+
| undefined
|
|
88
|
+
if (existing === undefined) {
|
|
89
|
+
const change = new AddFeatureChange({
|
|
90
|
+
typeName: 'AddFeatureChange',
|
|
91
|
+
assembly: assemblyName,
|
|
92
|
+
changedIds: [featureSnapshot._id],
|
|
93
|
+
addedFeature: featureSnapshot,
|
|
94
|
+
})
|
|
95
|
+
await apolloDataStore.changeManager.submit(change)
|
|
96
|
+
} else {
|
|
97
|
+
// get rid of undefined values in JSON
|
|
98
|
+
// eslint-disable-next-line unicorn/prefer-structured-clone
|
|
99
|
+
const existingFeature = JSON.parse(
|
|
100
|
+
JSON.stringify(existing),
|
|
101
|
+
) as AnnotationFeatureSnapshot
|
|
102
|
+
if (!equal(featureSnapshot, existingFeature)) {
|
|
103
|
+
await new Promise<void>((resolve) => {
|
|
104
|
+
session.queueDialog((doneCallback) => [
|
|
105
|
+
DuplicateFeatureDialog,
|
|
106
|
+
{
|
|
107
|
+
featureSnapshot,
|
|
108
|
+
existingFeature,
|
|
109
|
+
assemblyName,
|
|
110
|
+
changeManager: apolloDataStore.changeManager,
|
|
111
|
+
handleClose: () => {
|
|
112
|
+
doneCallback()
|
|
113
|
+
resolve()
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
])
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
package/src/session/session.ts
CHANGED
|
@@ -18,9 +18,11 @@ import {
|
|
|
18
18
|
readConfObject,
|
|
19
19
|
} from '@jbrowse/core/configuration'
|
|
20
20
|
import type { BaseTrackConfig } from '@jbrowse/core/pluggableElementTypes'
|
|
21
|
-
import
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
import {
|
|
22
|
+
isElectron,
|
|
23
|
+
type AbstractSessionModel,
|
|
24
|
+
type SessionWithAddTracks,
|
|
25
|
+
type SessionWithDrawerWidgets,
|
|
24
26
|
} from '@jbrowse/core/util'
|
|
25
27
|
import {
|
|
26
28
|
type Instance,
|
|
@@ -45,6 +47,7 @@ import {
|
|
|
45
47
|
type ClientDataStoreModel,
|
|
46
48
|
clientDataStoreFactory,
|
|
47
49
|
} from './ClientDataStore'
|
|
50
|
+
import { handleApolloFeaturesUrlParam } from './handleApolloFeaturesUrlParam'
|
|
48
51
|
|
|
49
52
|
export interface ApolloSession extends AbstractSessionModel {
|
|
50
53
|
apolloDataStore: ClientDataStoreModel
|
|
@@ -169,10 +172,7 @@ export function extendSession(
|
|
|
169
172
|
for (const block of dynamicBlocks.contentBlocks) {
|
|
170
173
|
const { assemblyName, end, refName, start } = block
|
|
171
174
|
const assembly = self.apolloDataStore.assemblies.get(assemblyName)
|
|
172
|
-
if (
|
|
173
|
-
assembly &&
|
|
174
|
-
assembly.backendDriverType === 'CollaborationServerDriver'
|
|
175
|
-
) {
|
|
175
|
+
if (assembly?.backendDriverType === 'CollaborationServerDriver') {
|
|
176
176
|
locations.push({ assemblyName, refName, start, end })
|
|
177
177
|
}
|
|
178
178
|
}
|
|
@@ -245,8 +245,8 @@ export function extendSession(
|
|
|
245
245
|
const assembly =
|
|
246
246
|
self.apolloDataStore.assemblies.get(assemblyName)
|
|
247
247
|
if (
|
|
248
|
-
assembly
|
|
249
|
-
|
|
248
|
+
assembly?.backendDriverType ===
|
|
249
|
+
'CollaborationServerDriver'
|
|
250
250
|
) {
|
|
251
251
|
locations.push({ assemblyName, refName, start, end })
|
|
252
252
|
}
|
|
@@ -409,6 +409,46 @@ export function extendSession(
|
|
|
409
409
|
)
|
|
410
410
|
},
|
|
411
411
|
}))
|
|
412
|
+
.actions((self) => ({
|
|
413
|
+
async afterCreate() {
|
|
414
|
+
if (isElectron) {
|
|
415
|
+
return
|
|
416
|
+
}
|
|
417
|
+
const url = new URL(globalThis.location.href)
|
|
418
|
+
const apolloFeatures = url.searchParams.get('apolloFeatures')
|
|
419
|
+
if (!apolloFeatures) {
|
|
420
|
+
return
|
|
421
|
+
}
|
|
422
|
+
const { assemblyManager } = self as unknown as AbstractSessionModel
|
|
423
|
+
await handleApolloFeaturesUrlParam(
|
|
424
|
+
apolloFeatures,
|
|
425
|
+
self.apolloDataStore,
|
|
426
|
+
assemblyManager,
|
|
427
|
+
self as unknown as AbstractSessionModel,
|
|
428
|
+
)
|
|
429
|
+
await new Promise((resolve) => setTimeout(resolve, 2000))
|
|
430
|
+
const updatedURL = new URL(globalThis.location.href)
|
|
431
|
+
updatedURL.searchParams.delete('apolloFeatures')
|
|
432
|
+
globalThis.history.replaceState(null, '', updatedURL.toString())
|
|
433
|
+
},
|
|
434
|
+
afterAttach() {
|
|
435
|
+
addDisposer(
|
|
436
|
+
self,
|
|
437
|
+
autorun((reaction) => {
|
|
438
|
+
const { focusedViewId, activeWidgets } =
|
|
439
|
+
self as unknown as SessionWithDrawerWidgets
|
|
440
|
+
if (!(focusedViewId && activeWidgets)) {
|
|
441
|
+
return
|
|
442
|
+
}
|
|
443
|
+
const trackSelector = activeWidgets.get('hierarchicalTrackSelector')
|
|
444
|
+
// @ts-expect-error Don't have type for track selector
|
|
445
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
446
|
+
trackSelector?.setView(focusedViewId)
|
|
447
|
+
reaction.dispose()
|
|
448
|
+
}),
|
|
449
|
+
)
|
|
450
|
+
},
|
|
451
|
+
}))
|
|
412
452
|
|
|
413
453
|
.views((self) => {
|
|
414
454
|
const superTrackActions = (self as unknown as AbstractSessionModel)
|
|
@@ -131,7 +131,7 @@ export function removeSkippedAttributes(
|
|
|
131
131
|
if (feature.children) {
|
|
132
132
|
const newChildren: Record<string, AnnotationFeatureSnapshot> = {}
|
|
133
133
|
for (const [childId, child] of Object.entries(feature.children)) {
|
|
134
|
-
const newChild = { ...child }
|
|
134
|
+
const newChild = { ...child }
|
|
135
135
|
removeSkippedAttributes(newChild, skippedAttributes)
|
|
136
136
|
newChildren[childId] = newChild
|
|
137
137
|
}
|
package/src/util/displayUtils.ts
CHANGED
|
@@ -171,7 +171,7 @@ export function colorCode(letter: string, theme: Theme) {
|
|
|
171
171
|
letterUpper === 'G' ||
|
|
172
172
|
letterUpper === 'T'
|
|
173
173
|
) {
|
|
174
|
-
return theme.palette.bases[letterUpper].main
|
|
174
|
+
return theme.palette.bases[letterUpper].main
|
|
175
175
|
}
|
|
176
176
|
return 'lightgray'
|
|
177
177
|
}
|
package/src/util/glyphUtils.ts
CHANGED
|
@@ -275,7 +275,7 @@ export function isSelectedFeature(
|
|
|
275
275
|
feature: AnnotationFeature,
|
|
276
276
|
selectedFeature: AnnotationFeature | undefined,
|
|
277
277
|
) {
|
|
278
|
-
return
|
|
278
|
+
return feature._id === selectedFeature?._id
|
|
279
279
|
}
|
|
280
280
|
|
|
281
281
|
function makeFeatureLabel(feature: AnnotationFeature) {
|
|
@@ -314,8 +314,8 @@ export function getContextMenuItemsForFeature(
|
|
|
314
314
|
const role = internetAccount ? internetAccount.role : 'admin'
|
|
315
315
|
const readOnly = !(role && ['admin', 'user'].includes(role))
|
|
316
316
|
const [region] = regions
|
|
317
|
-
const sourceAssemblyId = display.getAssemblyId(region.assemblyName)
|
|
318
|
-
const currentAssemblyId = display.getAssemblyId(region.assemblyName)
|
|
317
|
+
const sourceAssemblyId = display.getAssemblyId(region.assemblyName) as string
|
|
318
|
+
const currentAssemblyId = display.getAssemblyId(region.assemblyName) as string
|
|
319
319
|
menuItems.push(
|
|
320
320
|
{
|
|
321
321
|
label: makeFeatureLabel(sourceFeature),
|