UNPKG

@jbrowse/plugin-linear-genome-view

Version:

JBrowse 2 linear genome view

105 lines (104 loc) 5.72 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useEffect, useState } from 'react'; import { Dialog, ErrorMessage, LoadingEllipses } from '@jbrowse/core/ui'; import { complement, reverse } from '@jbrowse/core/util'; import { formatSeqFasta } from '@jbrowse/core/util/formatFastaStrings'; import ContentCopyIcon from '@mui/icons-material/ContentCopy'; import GetAppIcon from '@mui/icons-material/GetApp'; import { Button, Checkbox, DialogActions, DialogContent, FormControlLabel, FormGroup, TextField, Typography, } from '@mui/material'; import copy from 'copy-to-clipboard'; import { saveAs } from 'file-saver'; import { observer } from 'mobx-react'; import { makeStyles } from 'tss-react/mui'; import { fetchSequence } from './fetchSequence'; const useStyles = makeStyles()({ dialogContent: { width: '80em', }, textAreaFont: { fontFamily: 'Courier New', }, ml: { marginLeft: 10, }, }); const GetSequenceDialog = observer(function ({ model, handleClose, }) { const { classes } = useStyles(); const [error, setError] = useState(); const [sequenceChunks, setSequenceChunks] = useState(); const [rev, setReverse] = useState(false); const [copied, setCopied] = useState(false); const [comp, setComplement] = useState(false); const { leftOffset, rightOffset } = model; const loading = sequenceChunks === undefined; 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'); } setSequenceChunks(await fetchSequence(model, selection)); } catch (e) { console.error(e); setError(e); } })(); return () => { controller.abort(); }; }, [model, leftOffset, rightOffset]); const sequence = sequenceChunks ? 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 = reverse(chunkSeq); } if (comp) { chunkSeq = complement(chunkSeq); } return { header: loc + (rev ? '-rev' : '') + (comp ? '-comp' : ''), seq: chunkSeq, }; })) : ''; const sequenceTooLarge = sequence ? sequence.length > 1000000 : false; return (_jsxs(Dialog, { maxWidth: "xl", open: true, onClose: () => { handleClose(); model.setOffsets(); }, title: "Reference sequence", children: [_jsxs(DialogContent, { children: [error ? (_jsx(ErrorMessage, { error: error })) : loading ? (_jsx(LoadingEllipses, { message: "Retrieving sequences" })) : null, _jsx(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, }, }, } }), _jsxs(FormGroup, { children: [_jsx(FormControlLabel, { control: _jsx(Checkbox, { value: rev, onChange: event => { setReverse(event.target.checked); } }), label: "Reverse sequence" }), _jsx(FormControlLabel, { control: _jsx(Checkbox, { value: comp, onChange: event => { setComplement(event.target.checked); } }), label: "Complement sequence" })] }), _jsx(Typography, { style: { margin: 10 }, children: "Note: Check both boxes for the \"reverse complement\"" })] }), _jsxs(DialogActions, { children: [_jsx(Button, { onClick: () => { copy(sequence); setCopied(true); setTimeout(() => { setCopied(false); }, 500); }, disabled: loading || !!error || sequenceTooLarge, color: "primary", startIcon: _jsx(ContentCopyIcon, {}), children: copied ? 'Copied' : 'Copy to clipboard' }), _jsx(Button, { onClick: () => { saveAs(new Blob([sequence || ''], { type: 'text/x-fasta;charset=utf-8', }), 'jbrowse_ref_seq.fa'); }, disabled: loading || !!error, color: "primary", startIcon: _jsx(GetAppIcon, {}), children: "Download FASTA" }), _jsx(Button, { onClick: handleClose, variant: "contained", children: "Close" })] })] })); }); export default GetSequenceDialog;