UNPKG

@jbrowse/plugin-linear-genome-view

Version:

JBrowse 2 linear genome view

243 lines (242 loc) 8.42 kB
import { readConfObject } from '@jbrowse/core/configuration'; import { assembleLocString, getContainingDisplay, getSession, makeAbortableReaction, } from '@jbrowse/core/util'; import { stopStopToken } from '@jbrowse/core/util/stopToken'; import { getRpcSessionId, getTrackAssemblyNames, } from '@jbrowse/core/util/tracks'; import { isRetryException } from '@jbrowse/core/util/types'; import { getParent, isAlive, types } from '@jbrowse/mobx-state-tree'; import ServerSideRenderedBlockContent from "../components/ServerSideRenderedBlockContent.js"; const blockState = types .model('BlockState', { key: types.string, region: types.frozen(), reloadFlag: 0, isLeftEndOfDisplayedRegion: false, isRightEndOfDisplayedRegion: false, }) .volatile(() => ({ stopToken: undefined, filled: false, reactElement: undefined, features: undefined, layout: undefined, blockStatusMessage: '', error: undefined, message: undefined, maxHeightReached: false, ReactComponent: ServerSideRenderedBlockContent, renderProps: undefined, renderArgs: undefined, isRenderingPending: true, cachedDisplay: undefined, })) .actions(self => { function stopCurrentToken() { if (self.stopToken !== undefined) { stopStopToken(self.stopToken); self.stopToken = undefined; } } function clearRenderState() { self.filled = false; self.reactElement = undefined; self.features = undefined; self.layout = undefined; self.maxHeightReached = false; self.renderProps = undefined; self.renderArgs = undefined; } return { doReload() { self.reloadFlag = self.reloadFlag + 1; }, setStatusMessage(message) { self.blockStatusMessage = message; }, setLoading(newStopToken) { stopCurrentToken(); self.isRenderingPending = true; self.error = undefined; self.message = undefined; self.stopToken = newStopToken; }, setMessage(messageText) { stopCurrentToken(); self.isRenderingPending = false; self.message = messageText; self.error = undefined; clearRenderState(); }, setRendered(props) { if (!props) { return; } const { reactElement, features, layout, maxHeightReached, renderProps, renderArgs, } = props; self.filled = true; self.isRenderingPending = false; self.message = undefined; self.reactElement = reactElement; self.features = features; self.layout = layout; self.error = undefined; self.maxHeightReached = maxHeightReached; self.renderProps = renderProps; self.renderArgs = renderArgs; self.stopToken = undefined; }, setError(error) { console.error(error); stopCurrentToken(); self.isRenderingPending = false; self.message = undefined; self.error = error; clearRenderState(); if (isRetryException(error)) { this.reload(); } }, reload() { self.stopToken = undefined; self.isRenderingPending = false; self.error = undefined; self.message = undefined; self.ReactComponent = ServerSideRenderedBlockContent; clearRenderState(); getParent(self, 2).reload(); }, setCachedDisplay(display) { self.cachedDisplay = display; }, beforeDestroy() { ; (async () => { try { stopCurrentToken(); if (self.renderArgs && self.cachedDisplay) { const { rpcManager } = getSession(self); const { rendererType } = self.cachedDisplay; await rendererType.freeResourcesInClient(rpcManager, JSON.parse(JSON.stringify(self.renderArgs))); } } catch (e) { console.error('Error while destroying block', e); } })(); }, }; }) .views(self => ({ get statusMessage() { return self.isRenderingPending ? self.blockStatusMessage || self.cachedDisplay?.statusMessage || 'Loading' : undefined; }, get displayHeight() { return self.cachedDisplay?.height; }, })) .actions(self => ({ afterAttach() { const display = self.cachedDisplay || getContainingDisplay(self); setTimeout(() => { if (isAlive(self)) { makeAbortableReaction(self, renderBlockData, renderBlockEffect, { name: `${display.id}/${assembleLocString(self.region)} rendering`, delay: display.renderDelay, fireImmediately: true, }, self.setLoading, self.setRendered, self.setError); } }, display.renderDelay); }, })); export default blockState; export function renderBlockData(self, optDisplay) { try { const display = (optDisplay || self.cachedDisplay || getContainingDisplay(self)); const { assemblyManager, rpcManager } = getSession(display); const { adapterConfig, rendererType, error, parentTrack } = display; const assemblyNames = getTrackAssemblyNames(parentTrack); const regionAsm = self.region.assemblyName; if (!assemblyNames.includes(regionAsm) && !assemblyNames.some(name => assemblyManager.get(name)?.hasName(regionAsm))) { throw new Error(`region assembly (${regionAsm}) does not match track assemblies (${assemblyNames})`); } const renderProps = display.renderProps(); const renderingProps = display.renderingProps?.(); const { config } = renderProps; readConfObject(config); const sessionId = getRpcSessionId(display); const trackInstanceId = parentTrack.id; const cannotBeRenderedReason = display.regionCannotBeRendered(self.region); const assembly = assemblyManager.get(self.region.assemblyName); const seqAdapterRefName = assembly?.getSeqAdapterRefName(self.region.refName); return { rendererType, rpcManager, renderProps, renderingProps, cannotBeRenderedReason, displayError: error, renderArgs: { statusCallback: (message) => { if (isAlive(self)) { self.setStatusMessage(message); } }, assemblyName: self.region.assemblyName, regions: [ { ...self.region, seqAdapterRefName, }, ], adapterConfig, rendererType: rendererType.name, sessionId, trackInstanceId, blockKey: self.key, reloadFlag: self.reloadFlag, timeout: 1_000_000, }, }; } catch (e) { return { displayError: e, }; } } async function renderBlockEffect(props, stopToken, self) { if (!props || !isAlive(self)) { return undefined; } const { rendererType, renderProps, renderingProps, rpcManager, renderArgs, cannotBeRenderedReason, displayError, } = props; if (displayError) { self.setError(displayError); return undefined; } if (cannotBeRenderedReason) { self.setMessage(cannotBeRenderedReason); return undefined; } if (renderProps.notReady || !renderArgs) { return undefined; } const { reactElement, features, layout, maxHeightReached } = await rendererType.renderInClient(rpcManager, { ...renderArgs, ...renderProps, renderingProps, stopToken, }); return { reactElement, features, layout, maxHeightReached, renderProps, renderArgs, }; }