@jbrowse/plugin-linear-genome-view
Version:
JBrowse 2 linear genome view
134 lines (133 loc) • 7.68 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const configuration_1 = require("@jbrowse/core/configuration");
const ui_1 = require("@jbrowse/core/ui");
const Icons_1 = require("@jbrowse/core/ui/Icons");
const util_1 = require("@jbrowse/core/util");
const formatFastaStrings_1 = require("@jbrowse/core/util/formatFastaStrings");
const GetApp_1 = __importDefault(require("@mui/icons-material/GetApp"));
const material_1 = require("@mui/material");
const copy_to_clipboard_1 = __importDefault(require("copy-to-clipboard"));
const file_saver_1 = require("file-saver");
const mobx_react_1 = require("mobx-react");
const mui_1 = require("tss-react/mui");
const useStyles = (0, mui_1.makeStyles)()({
dialogContent: {
width: '80em',
},
textAreaFont: {
fontFamily: 'Courier New',
},
ml: {
marginLeft: 10,
},
});
async function fetchSequence(model, regions) {
const session = (0, util_1.getSession)(model);
const { leftOffset, rightOffset } = model;
if (!leftOffset || !rightOffset) {
throw new Error('no offsets on model to use for range');
}
if (leftOffset.assemblyName !== rightOffset.assemblyName) {
throw new Error('not able to fetch sequences from multiple assemblies');
}
const { rpcManager, assemblyManager } = session;
const assemblyName = leftOffset.assemblyName || rightOffset.assemblyName || '';
const assembly = assemblyManager.get(assemblyName);
if (!assembly) {
throw new Error(`assembly ${assemblyName} not found`);
}
const adapterConfig = (0, configuration_1.getConf)(assembly, ['sequence', 'adapter']);
const sessionId = 'getSequence';
return rpcManager.call(sessionId, 'CoreGetFeatures', {
adapterConfig,
regions,
sessionId,
});
}
const GetSequenceDialog = (0, mobx_react_1.observer)(function ({ model, handleClose, }) {
const { classes } = useStyles();
const [error, setError] = (0, react_1.useState)();
const [sequenceChunks, setSequenceChunks] = (0, react_1.useState)();
const [rev, setReverse] = (0, react_1.useState)(false);
const [copied, setCopied] = (0, react_1.useState)(false);
const [comp, setComplement] = (0, react_1.useState)(false);
const { leftOffset, rightOffset } = model;
const loading = Boolean(sequenceChunks === undefined);
(0, react_1.useEffect)(() => {
const controller = new AbortController();
(async () => {
try {
const selection = model.getSelectedRegions(leftOffset, rightOffset);
if (selection.length === 0) {
throw new Error('Selected region is out of bounds');
}
const chunks = await fetchSequence(model, selection);
setSequenceChunks(chunks);
}
catch (e) {
console.error(e);
setError(e);
}
})();
return () => {
controller.abort();
};
}, [model, leftOffset, rightOffset]);
const sequence = sequenceChunks
? (0, formatFastaStrings_1.formatSeqFasta)(sequenceChunks.map(chunk => {
let chunkSeq = chunk.get('seq');
const chunkRefName = chunk.get('refName');
const chunkStart = chunk.get('start') + 1;
const chunkEnd = chunk.get('end');
const loc = `${chunkRefName}:${chunkStart}-${chunkEnd}`;
if ((chunkSeq === null || chunkSeq === void 0 ? void 0 : chunkSeq.length) !== chunkEnd - chunkStart + 1) {
throw new Error(`${loc} returned ${chunkSeq.length.toLocaleString()} bases, but should have returned ${(chunkEnd - chunkStart).toLocaleString()}`);
}
if (rev) {
chunkSeq = (0, util_1.reverse)(chunkSeq);
}
if (comp) {
chunkSeq = (0, util_1.complement)(chunkSeq);
}
return {
header: loc + (rev ? '-rev' : '') + (comp ? '-comp' : ''),
seq: chunkSeq,
};
}))
: '';
const sequenceTooLarge = sequence ? sequence.length > 1000000 : false;
return ((0, jsx_runtime_1.jsxs)(ui_1.Dialog, { maxWidth: "xl", open: true, onClose: () => {
handleClose();
model.setOffsets();
}, title: "Reference sequence", children: [(0, jsx_runtime_1.jsxs)(material_1.DialogContent, { children: [error ? ((0, jsx_runtime_1.jsx)(material_1.Typography, { color: "error", children: `${error}` })) : loading ? ((0, jsx_runtime_1.jsxs)(material_1.Container, { children: ["Retrieving reference sequence...", (0, jsx_runtime_1.jsx)(material_1.CircularProgress, { className: classes.ml, size: 20, disableShrink: true })] })) : null, (0, jsx_runtime_1.jsx)(material_1.TextField, { "data-testid": "rubberband-sequence", variant: "outlined", multiline: true, minRows: 5, maxRows: 10, disabled: sequenceTooLarge, className: classes.dialogContent, fullWidth: true, value: sequenceTooLarge
? 'Reference sequence too large to display, use the download FASTA button'
: sequence, slotProps: {
input: {
readOnly: true,
classes: {
input: classes.textAreaFont,
},
},
} }), (0, jsx_runtime_1.jsxs)(material_1.FormGroup, { children: [(0, jsx_runtime_1.jsx)(material_1.FormControlLabel, { control: (0, jsx_runtime_1.jsx)(material_1.Checkbox, { value: rev, onChange: event => {
setReverse(event.target.checked);
} }), label: "Reverse sequence" }), (0, jsx_runtime_1.jsx)(material_1.FormControlLabel, { control: (0, jsx_runtime_1.jsx)(material_1.Checkbox, { value: comp, onChange: event => {
setComplement(event.target.checked);
} }), label: "Complement sequence" })] }), (0, jsx_runtime_1.jsx)(material_1.Typography, { style: { margin: 10 }, children: "Note: Check both boxes for the \"reverse complement\"" })] }), (0, jsx_runtime_1.jsxs)(material_1.DialogActions, { children: [(0, jsx_runtime_1.jsx)(material_1.Button, { onClick: () => {
(0, copy_to_clipboard_1.default)(sequence);
setCopied(true);
setTimeout(() => {
setCopied(false);
}, 500);
}, disabled: loading || !!error || sequenceTooLarge, color: "primary", startIcon: (0, jsx_runtime_1.jsx)(Icons_1.ContentCopy, {}), children: copied ? 'Copied' : 'Copy to clipboard' }), (0, jsx_runtime_1.jsx)(material_1.Button, { onClick: () => {
(0, file_saver_1.saveAs)(new Blob([sequence || ''], {
type: 'text/x-fasta;charset=utf-8',
}), 'jbrowse_ref_seq.fa');
}, disabled: loading || !!error, color: "primary", startIcon: (0, jsx_runtime_1.jsx)(GetApp_1.default, {}), children: "Download FASTA" }), (0, jsx_runtime_1.jsx)(material_1.Button, { onClick: handleClose, variant: "contained", children: "Close" })] })] }));
});
exports.default = GetSequenceDialog;