@jbrowse/plugin-linear-genome-view
Version:
JBrowse 2 linear genome view
105 lines (104 loc) • 5.72 kB
JavaScript
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;