Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Squash updates
Browse files Browse the repository at this point in the history
Remove clone. It seems to be unneeded, even though it will mutate the original object, this doesn't seem like it should matter

Another optimization to the track selector

Use structuredClone

Misc lint fixes

Misc
cmdcolin committed Aug 12, 2024
1 parent 615b1e3 commit 7964199
Showing 30 changed files with 364 additions and 268 deletions.
8 changes: 7 additions & 1 deletion packages/app-core/src/JBrowseConfig/index.ts
Original file line number Diff line number Diff line change
@@ -36,9 +36,11 @@ import { types } from 'mobx-state-tree'
export function JBrowseConfigF({
pluginManager,
assemblyConfigSchema,
adminMode,
}: {
pluginManager: PluginManager
assemblyConfigSchema: AnyConfigurationSchemaType
adminMode: boolean
}) {
return types.model('JBrowseConfig', {
configuration: ConfigurationSchema('Root', {
@@ -121,7 +123,11 @@ export function JBrowseConfigF({
* track configuration is an array of track config schemas. multiple
* instances of a track can exist that use the same configuration
*/
tracks: types.array(pluginManager.pluggableConfigSchemaType('track')),
tracks:
// @ts-expect-error
adminMode || globalThis.disableFrozenTracks
? types.array(pluginManager.pluggableConfigSchemaType('track'))
: types.frozen([] as { trackId: string; [key: string]: unknown }[]),
/**
* #slot
* configuration for internet accounts, see InternetAccounts
23 changes: 17 additions & 6 deletions packages/app-core/src/JBrowseModel/index.ts
Original file line number Diff line number Diff line change
@@ -24,13 +24,15 @@ import { JBrowseConfigF } from '../JBrowseConfig'
*/
export function JBrowseModelF({
adminMode,
pluginManager,
assemblyConfigSchema,
}: {
adminMode: boolean
pluginManager: PluginManager
assemblyConfigSchema: BaseAssemblyConfigSchema
}) {
return JBrowseConfigF({ pluginManager, assemblyConfigSchema })
return JBrowseConfigF({ pluginManager, assemblyConfigSchema, adminMode })
.views(self => ({
/**
* #getter
@@ -81,13 +83,17 @@ export function JBrowseModelF({
/**
* #action
*/
addTrackConf(trackConf: AnyConfigurationModel) {
addTrackConf(trackConf: { trackId: string; type: string }) {
const { type } = trackConf
if (!type) {
throw new Error(`unknown track type ${type}`)
}
const length = self.tracks.push(trackConf)
return self.tracks[length - 1]
if (adminMode) {
self.tracks.push(trackConf)
} else {
self.tracks = [...self.tracks, trackConf]
}
return self.tracks.at(-1)
},
/**
* #action
@@ -111,8 +117,13 @@ export function JBrowseModelF({
* #action
*/
deleteTrackConf(trackConf: AnyConfigurationModel) {
const elt = self.tracks.find(t => t.trackId === trackConf.trackId)
return self.tracks.remove(elt)
if (adminMode) {
const elt = self.tracks.find(t => t.trackId === trackConf.trackId)
// @ts-expect-error
return self.tracks.remove(elt)
} else {
return self.tracks.filter(f => f.trackId !== trackConf.trackId)
}
},
/**
* #action
50 changes: 50 additions & 0 deletions packages/core/configuration/configurationSchema.ts
Original file line number Diff line number Diff line change
@@ -6,13 +6,17 @@ import {
getSnapshot,
IAnyType,
SnapshotOut,
getEnv,
getRoot,
resolveIdentifier,
} from 'mobx-state-tree'

import { ElementId } from '../util/types/mst'

import ConfigSlot, { ConfigSlotDefinition } from './configurationSlot'
import { isConfigurationSchemaType } from './util'
import { AnyConfigurationSchemaType } from './types'
import { getContainingTrack, getSession } from '../util'

export type {
AnyConfigurationSchemaType,
@@ -276,9 +280,55 @@ export function ConfigurationSchema<
return schemaType
}

export function TrackConfigurationReference(schemaType: IAnyType) {
const trackRef = types.reference(schemaType, {
get(id, parent) {
let ret = getSession(parent).tracksById[id]
if (!ret) {
// @ts-expect-error
ret = resolveIdentifier(schemaType, getRoot(parent), id)
}
if (!ret) {
throw new Error(`${id} not found`)
}
return isStateTreeNode(ret) ? ret : schemaType.create(ret, getEnv(parent))
},
set(value) {
return value.trackId
},
})
return types.union(trackRef, schemaType)
}

export function DisplayConfigurationReference(schemaType: IAnyType) {
const displayRef = types.reference(schemaType, {
get(id, parent) {
const track = getContainingTrack(parent)
let ret = track.configuration.displays.find(u => u.displayId === id)
if (!ret) {
// @ts-expect-error
ret = resolveIdentifier(schemaType, getRoot(parent), id)
}
if (!ret) {
throw new Error(`${id} not found`)
}
return ret
},
set(value) {
return value.displayId
},
})
return types.union(displayRef, schemaType)
}

export function ConfigurationReference<
SCHEMATYPE extends AnyConfigurationSchemaType,
>(schemaType: SCHEMATYPE) {
if (schemaType.name.endsWith('TrackConfigurationSchema')) {
return TrackConfigurationReference(schemaType)
} else if (schemaType.name.endsWith('DisplayConfigurationSchema')) {
return DisplayConfigurationReference(schemaType)
}
// we cast this to SCHEMATYPE, because the reference *should* behave just
// like the object it points to. It won't be undefined (this is a
// `reference`, not a `safeReference`)
103 changes: 102 additions & 1 deletion packages/core/util/tracks.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import { getParent, isRoot, IAnyStateTreeNode } from 'mobx-state-tree'
import {
getParent,
getRoot,
isRoot,
resolveIdentifier,
types,
IAnyStateTreeNode,
Instance,
IAnyType,
} from 'mobx-state-tree'
import { getSession, objectHash, getEnv } from './index'
import { PreFileLocation, FileLocation } from './types'
import { readConfObject, AnyConfigurationModel } from '../configuration'
@@ -268,3 +277,95 @@ export function getTrackName(
}
return trackName
}

type MSTArray<T extends IAnyType> = Instance<ReturnType<typeof types.array<T>>>

interface MinimalTrack extends IAnyType {
configuration: { trackId: string }
}

interface GenericView {
type: string
tracks: MSTArray<MinimalTrack>
}

export function showTrackGeneric(
self: GenericView,
trackId: string,
initialSnapshot = {},
displayInitialSnapshot = {},
) {
const { pluginManager } = getEnv(self)
const session = getSession(self)
let conf = session.tracks.find(t => t.trackId === trackId)
if (!conf) {
const schema = pluginManager.pluggableConfigSchemaType('track')
conf = resolveIdentifier(schema, getRoot(self), trackId)
}
if (!conf) {
throw new Error(`Could not resolve identifier "${trackId}"`)
}
const trackType = pluginManager.getTrackType(conf.type)
if (!trackType) {
throw new Error(`Unknown track type ${conf.type}`)
}
const viewType = pluginManager.getViewType(self.type)!
const supportedDisplays = new Set(viewType.displayTypes.map(d => d.name))

const { displays = [] } = conf
const displayTypes = new Set()

displays.forEach((d: any) => d && displayTypes.add(d.type))
trackType.displayTypes.forEach(displayType => {
if (!displayTypes.has(displayType.name)) {
displays.push({
displayId: `${trackId}-${displayType.name}`,
type: displayType.name,
})
}
})

const displayConf = displays?.find((d: AnyConfigurationModel) =>
supportedDisplays.has(d.type),
)
if (!displayConf) {
throw new Error(
`Could not find a compatible display for view type ${self.type}`,
)
}

const found = self.tracks.find(t => t.configuration.trackId === trackId)
if (!found) {
const track = trackType.stateModel.create({
...initialSnapshot,
type: conf.type,
configuration: conf,
displays: [
{
type: displayConf.type,
configuration: displayConf,
...displayInitialSnapshot,
},
],
})
self.tracks.push(track)
return track
}
return found
}

export function hideTrackGeneric(self: GenericView, trackId: string) {
const t = self.tracks.find(t => t.configuration.trackId === trackId)
if (t) {
self.tracks.remove(t)
return 1
}
return 0
}

export function toggleTrackGeneric(self: GenericView, trackId: string) {
const hiddenCount = hideTrackGeneric(self, trackId)
if (!hiddenCount) {
showTrackGeneric(self, trackId)
}
}
5 changes: 4 additions & 1 deletion packages/core/util/types/index.ts
Original file line number Diff line number Diff line change
@@ -81,6 +81,7 @@ export type DialogComponentType =

/** minimum interface that all session state models must implement */
export interface AbstractSessionModel extends AbstractViewContainer {
tracksById: Record<string, AnyConfigurationModel>
jbrowse: IAnyStateTreeNode
drawerPosition?: string
configuration: AnyConfigurationModel
@@ -295,9 +296,11 @@ export function isViewModel(thing: unknown): thing is AbstractViewModel {
)
}

type Display = { displayId: string } & AnyConfigurationModel

export interface AbstractTrackModel {
displays: AbstractDisplayModel[]
configuration: AnyConfigurationModel
configuration: AnyConfigurationModel & { displays: Display[] }
}

export function isTrackModel(thing: unknown): thing is AbstractTrackModel {
7 changes: 7 additions & 0 deletions packages/product-core/src/Session/Tracks.ts
Original file line number Diff line number Diff line change
@@ -28,6 +28,13 @@ export function TracksManagerSessionMixin(pluginManager: PluginManager) {
get tracks(): AnyConfigurationModel[] {
return self.jbrowse.tracks
},

/**
* #getter
*/
get tracksById(): Record<string, AnyConfigurationModel> {
return Object.fromEntries(this.tracks.map(t => [t.trackId, t]))
},
}))
.actions(self => ({
/**
14 changes: 10 additions & 4 deletions packages/product-core/src/ui/AboutDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,36 @@
import React from 'react'
import { AnyConfigurationModel } from '@jbrowse/core/configuration'
import Dialog from '@jbrowse/core/ui/Dialog'
import { getSession, getEnv } from '@jbrowse/core/util'
import { getEnv, AbstractSessionModel } from '@jbrowse/core/util'
import { getTrackName } from '@jbrowse/core/util/tracks'

// locals
import AboutContents from './AboutDialogContents'

export function AboutDialog({
config,
session,
handleClose,
}: {
config: AnyConfigurationModel
session: AbstractSessionModel
handleClose: () => void
}) {
const session = getSession(config)
const trackName = getTrackName(config, session)
const { pluginManager } = getEnv(session)

const AboutComponent = pluginManager.evaluateExtensionPoint(
'Core-replaceAbout',
AboutContents,
{ session, config },
) as React.FC<any>
) as React.FC<{
config: AnyConfigurationModel
session: AbstractSessionModel
}>

return (
<Dialog open onClose={handleClose} title={trackName} maxWidth="xl">
<AboutComponent config={config} />
<AboutComponent config={config} session={session} />
</Dialog>
)
}
11 changes: 7 additions & 4 deletions packages/product-core/src/ui/AboutDialogContents.tsx
Original file line number Diff line number Diff line change
@@ -9,13 +9,14 @@ import {
readConfObject,
AnyConfigurationModel,
} from '@jbrowse/core/configuration'
import { getSession, getEnv } from '@jbrowse/core/util'
import { getEnv, AbstractSessionModel } from '@jbrowse/core/util'
import {
BaseCard,
Attributes,
} from '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail'
import FileInfoPanel from './FileInfoPanel'
import RefNameInfoDialog from './RefNameInfoDialog'
import { isStateTreeNode } from 'mobx-state-tree'

const useStyles = makeStyles()({
content: {
@@ -39,12 +40,13 @@ function removeAttr(obj: Record<string, unknown>, attr: string) {

const AboutDialogContents = observer(function ({
config,
session,
}: {
config: AnyConfigurationModel
session: AbstractSessionModel
}) {
const [copied, setCopied] = useState(false)
const conf = readConfObject(config)
const session = getSession(config)
const conf = isStateTreeNode(config) ? readConfObject(config) : config
const { classes } = useStyles()
const [showRefNames, setShowRefNames] = useState(false)

@@ -112,9 +114,10 @@ const AboutDialogContents = observer(function ({
<ExtraPanel.Component config={config} />
</BaseCard>
) : null}
<FileInfoPanel config={config} />
<FileInfoPanel config={config} session={session} />
{showRefNames ? (
<RefNameInfoDialog
session={session}
config={config}
onClose={() => {
setShowRefNames(false)
Loading

0 comments on commit 7964199

Please sign in to comment.