@apollo-annotation/jbrowse-plugin-apollo 0.3.8 → 0.3.9
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/index.esm.js +10932 -10932
- package/dist/index.esm.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.development.js +10845 -10846
- 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 +18619 -21342
- 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/package.json +7 -7
- package/src/ApolloInternetAccount/model.ts +81 -63
- package/src/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.ts +4 -4
- package/src/ApolloSequenceAdapter/ApolloSequenceAdapter.ts +9 -7
- package/src/BackendDrivers/CollaborationServerDriver.ts +49 -18
- package/src/BackendDrivers/DesktopFileDriver.ts +2 -2
- package/src/ChangeManager.ts +3 -1
- package/src/FeatureDetailsWidget/BasicInformation.tsx +6 -4
- package/src/FeatureDetailsWidget/NumberTextField.tsx +5 -2
- package/src/FeatureDetailsWidget/TranscriptWidgetEditLocation.tsx +39 -203
- package/src/LinearApolloDisplay/components/CheckResultWarnings.tsx +92 -0
- package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +6 -102
- package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +31 -230
- package/src/LinearApolloDisplay/glyphs/util.ts +19 -0
- package/src/LinearApolloReferenceSequenceDisplay/drawSequenceOverlay.ts +181 -0
- package/src/LinearApolloReferenceSequenceDisplay/drawSequenceTrack.ts +218 -0
- package/src/LinearApolloReferenceSequenceDisplay/stateModel/rendering.ts +62 -386
- package/src/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.tsx +6 -0
- package/src/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.ts +122 -70
- package/src/components/AddAssembly.tsx +33 -37
- package/src/components/AddFeature.tsx +21 -18
- package/src/components/AddRefSeqAliases.tsx +56 -42
- package/src/components/CopyFeature.tsx +1 -1
- package/src/components/CreateApolloAnnotation.tsx +22 -10
- package/src/components/DeleteAssembly.tsx +2 -9
- package/src/components/DownloadGFF3.tsx +2 -2
- package/src/components/ManageChecks.tsx +2 -9
- package/src/components/ManageUsers.tsx +23 -22
- package/src/components/OntologyTermAutocomplete.tsx +1 -8
- package/src/components/ViewChangeLog.tsx +25 -50
- package/src/components/ViewCheckResults.tsx +1 -7
- package/src/config.ts +3 -3
- package/src/index.ts +17 -16
- package/src/makeDisplayComponent.tsx +9 -13
- package/src/session/ClientDataStore.ts +32 -14
- package/src/session/session.ts +19 -27
- package/src/util/glyphUtils.ts +178 -1
- package/src/util/loadAssemblyIntoClient.ts +3 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apollo-annotation/jbrowse-plugin-apollo",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.9",
|
|
4
4
|
"description": "Apollo plugin for JBrowse 2",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jbrowse",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"start:watch": "JB_NPM=false NODE_ENV=development rollup --config --watch",
|
|
28
28
|
"start:server": "serve --no-request-logging --cors --listen 9000 --no-port-switching .",
|
|
29
29
|
"build": "yarn build:shared && yarn clean && rollup --config",
|
|
30
|
-
"browse": "serve --no-request-logging --listen 8999 --no-port-switching .jbrowse",
|
|
30
|
+
"browse": "serve --no-request-logging --listen 8999 --no-port-switching --symlinks .jbrowse",
|
|
31
31
|
"test": "jest",
|
|
32
32
|
"test:ci": "jest --coverage",
|
|
33
33
|
"start:collab-cypress": "yarn workspace @apollo-annotation/collaboration-server run cypress:start",
|
|
@@ -48,12 +48,12 @@
|
|
|
48
48
|
}
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@apollo-annotation/common": "^0.3.
|
|
52
|
-
"@apollo-annotation/mst": "^0.3.
|
|
53
|
-
"@apollo-annotation/shared": "^0.3.
|
|
51
|
+
"@apollo-annotation/common": "^0.3.9",
|
|
52
|
+
"@apollo-annotation/mst": "^0.3.9",
|
|
53
|
+
"@apollo-annotation/shared": "^0.3.9",
|
|
54
54
|
"@emotion/react": "^11.10.6",
|
|
55
55
|
"@emotion/styled": "^11.10.6",
|
|
56
|
-
"@gmod/gff": "
|
|
56
|
+
"@gmod/gff": "^2.0.0",
|
|
57
57
|
"@jbrowse/plugin-authentication": "^3.6.5",
|
|
58
58
|
"@jbrowse/plugin-linear-genome-view": "^3.6.5",
|
|
59
59
|
"@mui/icons-material": "^6.5.0",
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
"@mui/x-data-grid": "^8.0.0",
|
|
80
80
|
"@types/autosuggest-highlight": "^3",
|
|
81
81
|
"@types/file-saver": "^2",
|
|
82
|
-
"@types/node": "^
|
|
82
|
+
"@types/node": "^20.19.15",
|
|
83
83
|
"@types/prop-types": "^15",
|
|
84
84
|
"@types/react": "^18.3.4",
|
|
85
85
|
"@types/react-dom": "^18",
|
|
@@ -64,32 +64,20 @@ const stateModelFactory = (configSchema: ApolloInternetAccountConfigModel) => {
|
|
|
64
64
|
controller: new AbortController(),
|
|
65
65
|
}))
|
|
66
66
|
|
|
67
|
-
.actions((self) => {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
'You have registered as a user but have not been given access. Ask your administrator to enable access for your account.',
|
|
82
|
-
'warning',
|
|
83
|
-
)
|
|
84
|
-
// notify
|
|
85
|
-
roleNotificationSent = true
|
|
86
|
-
}
|
|
87
|
-
if (self.role !== role) {
|
|
88
|
-
self.role = role
|
|
89
|
-
}
|
|
90
|
-
},
|
|
91
|
-
}
|
|
92
|
-
})
|
|
67
|
+
.actions((self) => ({
|
|
68
|
+
setRole() {
|
|
69
|
+
const token = self.retrieveToken()
|
|
70
|
+
if (!token) {
|
|
71
|
+
self.role = undefined
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
const dec = getDecodedToken(token)
|
|
75
|
+
const { role } = dec
|
|
76
|
+
if (self.role !== role) {
|
|
77
|
+
self.role = role
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
}))
|
|
93
81
|
.actions((self) => {
|
|
94
82
|
let listener: (event: MessageEvent) => void
|
|
95
83
|
return {
|
|
@@ -380,7 +368,7 @@ const stateModelFactory = (configSchema: ApolloInternetAccountConfigModel) => {
|
|
|
380
368
|
}))
|
|
381
369
|
.actions((self) => {
|
|
382
370
|
async function postUserLocation(userLoc: UserLocation[]) {
|
|
383
|
-
if (!isAlive(self)) {
|
|
371
|
+
if (!isAlive(self) || self.role === 'none') {
|
|
384
372
|
return
|
|
385
373
|
}
|
|
386
374
|
const { baseURL, controller } = self
|
|
@@ -418,45 +406,73 @@ const stateModelFactory = (configSchema: ApolloInternetAccountConfigModel) => {
|
|
|
418
406
|
}
|
|
419
407
|
return { postUserLocation: debouncePostUserLocation(postUserLocation) }
|
|
420
408
|
})
|
|
421
|
-
.
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
// Get and set server last change sequence into session storage
|
|
430
|
-
yield self.updateLastChangeSequenceNumber()
|
|
431
|
-
// Open socket listeners
|
|
432
|
-
self.addSocketListeners()
|
|
433
|
-
// request user locations
|
|
434
|
-
const { baseURL } = self
|
|
435
|
-
const uri = new URL('users/locations', baseURL).href
|
|
436
|
-
const apolloFetch = self.getFetcher({
|
|
437
|
-
locationType: 'UriLocation',
|
|
438
|
-
uri,
|
|
439
|
-
})
|
|
440
|
-
yield apolloFetch(uri, {
|
|
441
|
-
method: 'GET',
|
|
442
|
-
signal: self.controller.signal,
|
|
443
|
-
})
|
|
444
|
-
window.addEventListener('beforeunload', () => {
|
|
409
|
+
.volatile(() => ({ roleNotificationSent: false }))
|
|
410
|
+
.actions((self) => {
|
|
411
|
+
function beforeUnloadListener() {
|
|
412
|
+
self.postUserLocation([])
|
|
413
|
+
}
|
|
414
|
+
function visibilityChangeListener() {
|
|
415
|
+
// fires when user switches tabs, apps, goes to homescreen, etc.
|
|
416
|
+
if (document.visibilityState === 'hidden') {
|
|
445
417
|
self.postUserLocation([])
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
418
|
+
}
|
|
419
|
+
// fires when app transitions from prerender, user returns to the app / tab.
|
|
420
|
+
if (document.visibilityState === 'visible') {
|
|
421
|
+
const { session } = getRoot<ApolloRootModel>(self)
|
|
422
|
+
session.broadcastLocations()
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return {
|
|
426
|
+
initialize: flow(function* initialize(role: Role) {
|
|
427
|
+
if (role === 'none') {
|
|
428
|
+
if (!self.roleNotificationSent) {
|
|
429
|
+
const { session } = getRoot<ApolloRootModel>(self)
|
|
430
|
+
;(session as unknown as AbstractSessionModel).notify(
|
|
431
|
+
'You have registered as an Apollo user but have not been given access. Ask your administrator to enable access for your account.',
|
|
432
|
+
'warning',
|
|
433
|
+
)
|
|
434
|
+
self.roleNotificationSent = true
|
|
435
|
+
}
|
|
436
|
+
return
|
|
451
437
|
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
438
|
+
if (role === 'admin') {
|
|
439
|
+
const rootModel = getRoot(self)
|
|
440
|
+
if (isAbstractMenuManager(rootModel)) {
|
|
441
|
+
addTopLevelAdminMenus(rootModel)
|
|
442
|
+
}
|
|
456
443
|
}
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
444
|
+
// Get and set server last change sequence into session storage
|
|
445
|
+
yield self.updateLastChangeSequenceNumber()
|
|
446
|
+
// Open socket listeners
|
|
447
|
+
self.addSocketListeners()
|
|
448
|
+
// request user locations
|
|
449
|
+
const { baseURL } = self
|
|
450
|
+
const uri = new URL('users/locations', baseURL).href
|
|
451
|
+
const apolloFetch = self.getFetcher({
|
|
452
|
+
locationType: 'UriLocation',
|
|
453
|
+
uri,
|
|
454
|
+
})
|
|
455
|
+
yield apolloFetch(uri, {
|
|
456
|
+
method: 'GET',
|
|
457
|
+
signal: self.controller.signal,
|
|
458
|
+
})
|
|
459
|
+
window.addEventListener('beforeunload', beforeUnloadListener)
|
|
460
|
+
document.addEventListener(
|
|
461
|
+
'visibilitychange',
|
|
462
|
+
visibilityChangeListener,
|
|
463
|
+
)
|
|
464
|
+
}),
|
|
465
|
+
removeBeforeUnloadListener() {
|
|
466
|
+
window.removeEventListener('beforeunload', beforeUnloadListener)
|
|
467
|
+
},
|
|
468
|
+
removeVisibilityChangeListener() {
|
|
469
|
+
document.removeEventListener(
|
|
470
|
+
'visibilitychange',
|
|
471
|
+
visibilityChangeListener,
|
|
472
|
+
)
|
|
473
|
+
},
|
|
474
|
+
}
|
|
475
|
+
})
|
|
460
476
|
.actions((self) => ({
|
|
461
477
|
afterAttach() {
|
|
462
478
|
self.setRole()
|
|
@@ -481,6 +497,8 @@ const stateModelFactory = (configSchema: ApolloInternetAccountConfigModel) => {
|
|
|
481
497
|
)
|
|
482
498
|
},
|
|
483
499
|
beforeDestroy() {
|
|
500
|
+
self.removeBeforeUnloadListener()
|
|
501
|
+
self.removeVisibilityChangeListener()
|
|
484
502
|
self.controller.abort('internet account beforeDestroy')
|
|
485
503
|
self.socket.close()
|
|
486
504
|
},
|
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
import type RpcServer from 'librpc-web-mod/dist/server'
|
|
7
7
|
import { nanoid } from 'nanoid'
|
|
8
8
|
|
|
9
|
-
import { type BackendDriver } from '../BackendDrivers'
|
|
10
9
|
import { type ApolloSessionModel } from '../session'
|
|
11
10
|
|
|
12
11
|
import { type RefNameAliases } from './../BackendDrivers/BackendDriver'
|
|
@@ -50,9 +49,10 @@ export default class RefNameAliasAdapter
|
|
|
50
49
|
if (!dataStore) {
|
|
51
50
|
throw new Error('No Apollo data store found')
|
|
52
51
|
}
|
|
53
|
-
const backendDriver = dataStore.getBackendDriver(
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
const backendDriver = dataStore.getBackendDriver(assemblyId)
|
|
53
|
+
if (!backendDriver) {
|
|
54
|
+
throw new Error('No backend driver found')
|
|
55
|
+
}
|
|
56
56
|
const refNameAliases = await backendDriver.getRefNameAliases(assemblyId)
|
|
57
57
|
return refNameAliases
|
|
58
58
|
}
|
|
@@ -10,7 +10,6 @@ import SimpleFeature, { type Feature } from '@jbrowse/core/util/simpleFeature'
|
|
|
10
10
|
import { type NoAssemblyRegion, type Region } from '@jbrowse/core/util/types'
|
|
11
11
|
import { nanoid } from 'nanoid'
|
|
12
12
|
|
|
13
|
-
import { type BackendDriver } from '../BackendDrivers'
|
|
14
13
|
import { type ApolloSessionModel } from '../session'
|
|
15
14
|
|
|
16
15
|
// declare global {
|
|
@@ -62,9 +61,10 @@ export class ApolloSequenceAdapter extends BaseSequenceAdapter {
|
|
|
62
61
|
if (!dataStore) {
|
|
63
62
|
throw new Error('No Apollo data store found')
|
|
64
63
|
}
|
|
65
|
-
const backendDriver = dataStore.getBackendDriver(
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
const backendDriver = dataStore.getBackendDriver(assemblyId)
|
|
65
|
+
if (!backendDriver) {
|
|
66
|
+
throw new Error('No backend driver found')
|
|
67
|
+
}
|
|
68
68
|
const regions = await backendDriver.getRegions(assemblyId)
|
|
69
69
|
this.regions = regions
|
|
70
70
|
return regions
|
|
@@ -124,9 +124,11 @@ export class ApolloSequenceAdapter extends BaseSequenceAdapter {
|
|
|
124
124
|
observer.error('No Apollo data store found')
|
|
125
125
|
return
|
|
126
126
|
}
|
|
127
|
-
const backendDriver = dataStore.getBackendDriver(
|
|
128
|
-
|
|
129
|
-
|
|
127
|
+
const backendDriver = dataStore.getBackendDriver(assemblyId)
|
|
128
|
+
if (!backendDriver) {
|
|
129
|
+
observer.error('No backend driver found')
|
|
130
|
+
return
|
|
131
|
+
}
|
|
130
132
|
const regions = await backendDriver.getRegions(
|
|
131
133
|
regionWithAssemblyName.assemblyName,
|
|
132
134
|
)
|
|
@@ -38,6 +38,14 @@ export interface ApolloRefSeqResponse {
|
|
|
38
38
|
assembly: string
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
interface RefSeq {
|
|
42
|
+
refName: string
|
|
43
|
+
id: string
|
|
44
|
+
aliases: string[]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
type RefSeqMap = Map<string, RefSeq>
|
|
48
|
+
|
|
41
49
|
export interface ApolloInternetAccount extends BaseInternetAccountModel {
|
|
42
50
|
baseURL: string
|
|
43
51
|
socket: Socket
|
|
@@ -48,6 +56,8 @@ export interface ApolloInternetAccount extends BaseInternetAccountModel {
|
|
|
48
56
|
export class CollaborationServerDriver extends BackendDriver {
|
|
49
57
|
private inFlight = new Map<string, Promise<string>>()
|
|
50
58
|
|
|
59
|
+
private refSeqMaps = new Map<string, RefSeqMap>()
|
|
60
|
+
|
|
51
61
|
private async fetch(
|
|
52
62
|
internetAccount: ApolloInternetAccount,
|
|
53
63
|
info: RequestInfo,
|
|
@@ -97,13 +107,12 @@ export class CollaborationServerDriver extends BackendDriver {
|
|
|
97
107
|
if (!assembly) {
|
|
98
108
|
throw new Error(`Could not find assembly with name "${assemblyName}"`)
|
|
99
109
|
}
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const refSeq = ids[refName]
|
|
104
|
-
if (!refSeq) {
|
|
110
|
+
const refSeqMap = await this.getRefSeqMapping(assemblyName)
|
|
111
|
+
const refSeqEntry = refSeqMap.get(refName)
|
|
112
|
+
if (!refSeqEntry) {
|
|
105
113
|
throw new Error(`Could not find refSeq "${refName}"`)
|
|
106
114
|
}
|
|
115
|
+
const refSeq = refSeqEntry.id
|
|
107
116
|
const internetAccount = this.clientStore.getInternetAccount(
|
|
108
117
|
assemblyName,
|
|
109
118
|
) as ApolloInternetAccount
|
|
@@ -192,13 +201,12 @@ export class CollaborationServerDriver extends BackendDriver {
|
|
|
192
201
|
if (!assembly) {
|
|
193
202
|
throw new Error(`Could not find assembly with name "${assemblyName}"`)
|
|
194
203
|
}
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const refSeq = ids[refName]
|
|
199
|
-
if (!refSeq) {
|
|
204
|
+
const refSeqMap = await this.getRefSeqMapping(assemblyName)
|
|
205
|
+
const refSeqEntry = refSeqMap.get(refName)
|
|
206
|
+
if (!refSeqEntry) {
|
|
200
207
|
throw new Error(`Could not find refSeq "${refName}"`)
|
|
201
208
|
}
|
|
209
|
+
const refSeq = refSeqEntry.id
|
|
202
210
|
if (inFlightPromise) {
|
|
203
211
|
const seq = await inFlightPromise
|
|
204
212
|
return { seq, refSeq }
|
|
@@ -269,7 +277,11 @@ export class CollaborationServerDriver extends BackendDriver {
|
|
|
269
277
|
return seq
|
|
270
278
|
}
|
|
271
279
|
|
|
272
|
-
async
|
|
280
|
+
async getRefSeqMapping(assemblyName: string): Promise<RefSeqMap> {
|
|
281
|
+
const cachedRefSeqMap = this.refSeqMaps.get(assemblyName)
|
|
282
|
+
if (cachedRefSeqMap) {
|
|
283
|
+
return cachedRefSeqMap
|
|
284
|
+
}
|
|
273
285
|
const { assemblyManager } = getSession(this.clientStore)
|
|
274
286
|
const assembly = assemblyManager.get(assemblyName)
|
|
275
287
|
if (!assembly) {
|
|
@@ -299,13 +311,32 @@ export class CollaborationServerDriver extends BackendDriver {
|
|
|
299
311
|
)
|
|
300
312
|
}
|
|
301
313
|
const refSeqs = (await response.json()) as ApolloRefSeqResponse[]
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
314
|
+
const refSeqMap = new Map<string, RefSeq>(
|
|
315
|
+
refSeqs.map((refSeq) => [
|
|
316
|
+
refSeq.name,
|
|
317
|
+
{ refName: refSeq.name, id: refSeq._id, aliases: refSeq.aliases },
|
|
318
|
+
]),
|
|
319
|
+
)
|
|
320
|
+
this.refSeqMaps.set(assemblyName, refSeqMap)
|
|
321
|
+
return refSeqMap
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
async getRefNameAliases(assemblyName: string): Promise<RefNameAliases[]> {
|
|
325
|
+
const refSeqMap = await this.getRefSeqMapping(assemblyName)
|
|
326
|
+
return [...refSeqMap.values()].map((refSeq) => ({
|
|
327
|
+
refName: refSeq.refName,
|
|
328
|
+
aliases: [...new Set([refSeq.id, ...refSeq.aliases])],
|
|
329
|
+
uniqueId: `alias-${refSeq.id}`,
|
|
330
|
+
}))
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
async getRefSeqId(assemblyName: string, refName: string) {
|
|
334
|
+
const refSeqMap = await this.getRefSeqMapping(assemblyName)
|
|
335
|
+
if (!refSeqMap) {
|
|
336
|
+
return
|
|
337
|
+
}
|
|
338
|
+
const refSeq = refSeqMap.get(refName)
|
|
339
|
+
return refSeq?.id
|
|
309
340
|
}
|
|
310
341
|
|
|
311
342
|
async getRegions(assemblyName: string): Promise<Region[]> {
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
annotationFeatureToGFF3,
|
|
14
14
|
splitStringIntoChunks,
|
|
15
15
|
} from '@apollo-annotation/shared'
|
|
16
|
-
import
|
|
16
|
+
import { type GFF3Item, formatSync } from '@gmod/gff'
|
|
17
17
|
import { getConf } from '@jbrowse/core/configuration'
|
|
18
18
|
import { type Region, getSession } from '@jbrowse/core/util'
|
|
19
19
|
import { getSnapshot } from 'mobx-state-tree'
|
|
@@ -165,7 +165,7 @@ export class DesktopFileDriver extends BackendDriver {
|
|
|
165
165
|
})
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
-
const gff3Contents =
|
|
168
|
+
const gff3Contents = formatSync(gff3Items)
|
|
169
169
|
|
|
170
170
|
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/consistent-type-imports
|
|
171
171
|
const fs = require('node:fs') as typeof import('fs')
|
package/src/ChangeManager.ts
CHANGED
|
@@ -106,7 +106,9 @@ export class ChangeManager {
|
|
|
106
106
|
// submit to driver
|
|
107
107
|
const { collaborationServerDriver, getBackendDriver } = this.dataStore
|
|
108
108
|
const backendDriver = isAssemblySpecificChange(change)
|
|
109
|
-
?
|
|
109
|
+
? // for assembly-specific change, fall back in case it's an
|
|
110
|
+
// add-assembly change, since that won't exist in the driver yet
|
|
111
|
+
getBackendDriver(change.assembly) ?? collaborationServerDriver
|
|
110
112
|
: collaborationServerDriver
|
|
111
113
|
let backendResult: ValidationResultSet
|
|
112
114
|
try {
|
|
@@ -66,7 +66,7 @@ export const BasicInformation = observer(function BasicInformation({
|
|
|
66
66
|
return changeManager.submit(change)
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
function handleStartChange(newStart: number) {
|
|
69
|
+
function handleStartChange(newStart: number): boolean {
|
|
70
70
|
newStart--
|
|
71
71
|
const change = new LocationStartChange({
|
|
72
72
|
typeName: 'LocationStartChange',
|
|
@@ -76,10 +76,11 @@ export const BasicInformation = observer(function BasicInformation({
|
|
|
76
76
|
newStart,
|
|
77
77
|
assembly,
|
|
78
78
|
})
|
|
79
|
-
|
|
79
|
+
void changeManager.submit(change)
|
|
80
|
+
return true
|
|
80
81
|
}
|
|
81
82
|
|
|
82
|
-
function handleEndChange(newEnd: number) {
|
|
83
|
+
function handleEndChange(newEnd: number): boolean {
|
|
83
84
|
const change = new LocationEndChange({
|
|
84
85
|
typeName: 'LocationEndChange',
|
|
85
86
|
changedIds: [_id],
|
|
@@ -88,7 +89,8 @@ export const BasicInformation = observer(function BasicInformation({
|
|
|
88
89
|
newEnd,
|
|
89
90
|
assembly,
|
|
90
91
|
})
|
|
91
|
-
|
|
92
|
+
void changeManager.submit(change)
|
|
93
|
+
return true
|
|
92
94
|
}
|
|
93
95
|
|
|
94
96
|
async function fetchValidTerms(
|
|
@@ -15,7 +15,7 @@ interface NumberTextFieldProps
|
|
|
15
15
|
| 'error'
|
|
16
16
|
| 'helperText'
|
|
17
17
|
> {
|
|
18
|
-
onChangeCommitted(newValue: number):
|
|
18
|
+
onChangeCommitted(newValue: number): boolean
|
|
19
19
|
value: unknown
|
|
20
20
|
}
|
|
21
21
|
|
|
@@ -65,7 +65,10 @@ export const NumberTextField = observer(function NumberTextField({
|
|
|
65
65
|
if (Number.isNaN(valueAsNumber)) {
|
|
66
66
|
setValue(String(initialValue))
|
|
67
67
|
} else {
|
|
68
|
-
onChangeCommitted(valueAsNumber)
|
|
68
|
+
const success = onChangeCommitted(valueAsNumber)
|
|
69
|
+
if (!success) {
|
|
70
|
+
setValue(String(initialValue))
|
|
71
|
+
}
|
|
69
72
|
}
|
|
70
73
|
}
|
|
71
74
|
}}
|