@jbrowse/plugin-linear-genome-view
Version:
JBrowse 2 linear genome view
224 lines (223 loc) • 7.74 kB
JavaScript
import { readConfObject } from '@jbrowse/core/configuration';
import { assembleLocString, getContainingDisplay, getContainingTrack, getSession, getViewParams, 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 { cast, getParent, isAlive, types } from 'mobx-state-tree';
import ServerSideRenderedBlockContent from '../components/ServerSideRenderedBlockContent';
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,
status: '',
error: undefined,
message: undefined,
maxHeightReached: false,
ReactComponent: ServerSideRenderedBlockContent,
renderProps: undefined,
}))
.actions(self => ({
doReload() {
self.reloadFlag = self.reloadFlag + 1;
},
afterAttach() {
const display = getContainingDisplay(self);
setTimeout(() => {
if (isAlive(self)) {
makeAbortableReaction(self, renderBlockData, renderBlockEffect, {
name: `${display.id}/${assembleLocString(self.region)} rendering`,
delay: display.renderDelay,
fireImmediately: true,
}, this.setLoading, this.setRendered, this.setError);
}
}, display.renderDelay);
},
setStatus(message) {
self.status = message;
},
setLoading(newStopToken) {
if (self.stopToken !== undefined) {
stopStopToken(self.stopToken);
}
self.filled = false;
self.message = undefined;
self.reactElement = undefined;
self.features = undefined;
self.layout = undefined;
self.error = undefined;
self.maxHeightReached = false;
self.renderProps = undefined;
self.stopToken = newStopToken;
},
setMessage(messageText) {
if (self.stopToken !== undefined) {
stopStopToken(self.stopToken);
}
self.filled = false;
self.message = messageText;
self.reactElement = undefined;
self.features = undefined;
self.layout = undefined;
self.error = undefined;
self.maxHeightReached = false;
self.renderProps = undefined;
self.stopToken = undefined;
},
setRendered(props) {
if (!props) {
return;
}
const { reactElement, features, layout, maxHeightReached, renderProps } = props;
self.filled = true;
self.message = undefined;
self.reactElement = reactElement;
self.features = features;
self.layout = layout;
self.error = undefined;
self.maxHeightReached = maxHeightReached;
self.renderProps = renderProps;
self.stopToken = undefined;
},
setError(error) {
console.error(error);
if (self.stopToken !== undefined) {
stopStopToken(self.stopToken);
}
self.filled = false;
self.message = undefined;
self.reactElement = undefined;
self.features = undefined;
self.layout = undefined;
self.maxHeightReached = false;
self.error = error;
self.renderProps = undefined;
self.stopToken = undefined;
if (isRetryException(error)) {
this.reload();
}
},
reload() {
self.stopToken = undefined;
self.filled = false;
self.reactElement = undefined;
self.features = undefined;
self.layout = undefined;
self.error = undefined;
self.message = undefined;
self.maxHeightReached = false;
self.ReactComponent = ServerSideRenderedBlockContent;
self.renderProps = undefined;
getParent(self, 2).reload();
},
beforeDestroy() {
;
(async () => {
try {
if (self.stopToken !== undefined) {
stopStopToken(self.stopToken);
}
const display = getContainingDisplay(self);
const { rpcManager } = getSession(self);
const { rendererType } = display;
const { renderArgs } = renderBlockData(cast(self));
if (renderArgs) {
await rendererType.freeResourcesInClient(rpcManager, JSON.parse(JSON.stringify(renderArgs)));
}
}
catch (e) {
console.error('Error while destroying block', e);
}
})();
},
}));
export default blockState;
export function renderBlockData(self, optDisplay) {
try {
const display = optDisplay || 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 => { var _a; return (_a = assemblyManager.get(name)) === null || _a === void 0 ? void 0 : _a.hasName(regionAsm); })) {
throw new Error(`region assembly (${regionAsm}) does not match track assemblies (${assemblyNames})`);
}
const renderProps = display.renderProps();
const { config } = renderProps;
readConfObject(config);
const sessionId = getRpcSessionId(display);
const layoutId = getContainingTrack(display).id;
const cannotBeRenderedReason = display.regionCannotBeRendered(self.region);
return {
rendererType,
rpcManager,
renderProps,
cannotBeRenderedReason,
displayError: error,
renderArgs: {
statusCallback: (message) => {
if (isAlive(self)) {
self.setStatus(message);
}
},
assemblyName: self.region.assemblyName,
regions: [self.region],
adapterConfig,
rendererType: rendererType.name,
sessionId,
layoutId,
blockKey: self.key,
reloadFlag: self.reloadFlag,
timeout: 1000000,
},
};
}
catch (e) {
return { displayError: e };
}
}
async function renderBlockEffect(props, stopToken, self) {
if (!props) {
return;
}
const { rendererType, renderProps, rpcManager, renderArgs, cannotBeRenderedReason, displayError, } = props;
if (!isAlive(self)) {
return undefined;
}
else if (displayError) {
self.setError(displayError);
return undefined;
}
else if (cannotBeRenderedReason) {
self.setMessage(cannotBeRenderedReason);
return undefined;
}
else if (renderProps.notReady) {
return undefined;
}
else {
const { reactElement, features, layout, maxHeightReached } = await rendererType.renderInClient(rpcManager, {
...renderArgs,
...renderProps,
viewParams: getViewParams(self),
stopToken,
});
return {
reactElement,
features,
layout,
maxHeightReached,
renderProps,
};
}
}