@jbrowse/core 2.1.4 → 2.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BaseFeatureWidget/BaseFeatureDetail.d.ts +4 -3
- package/BaseFeatureWidget/BaseFeatureDetail.js +16 -17
- package/BaseFeatureWidget/SequenceBox.d.ts +29 -0
- package/BaseFeatureWidget/SequenceBox.js +61 -0
- package/BaseFeatureWidget/SequenceFeatureDetails.d.ts +2 -8
- package/BaseFeatureWidget/SequenceFeatureDetails.js +123 -135
- package/BaseFeatureWidget/SequenceFeatureSettingsDialog.d.ts +9 -0
- package/BaseFeatureWidget/SequenceFeatureSettingsDialog.js +71 -0
- package/BaseFeatureWidget/SequenceHelpDialog.d.ts +4 -0
- package/BaseFeatureWidget/SequenceHelpDialog.js +51 -0
- package/BaseFeatureWidget/SequencePanel.d.ts +10 -0
- package/BaseFeatureWidget/SequencePanel.js +72 -0
- package/BaseFeatureWidget/index.d.ts +7 -0
- package/BaseFeatureWidget/index.js +21 -5
- package/BaseFeatureWidget/test_data/DLGAP3.d.ts +80 -0
- package/BaseFeatureWidget/test_data/DLGAP3.js +585 -0
- package/BaseFeatureWidget/test_data/NCDN.d.ts +141 -0
- package/BaseFeatureWidget/test_data/NCDN.js +1118 -0
- package/BaseFeatureWidget/types.d.ts +2 -2
- package/BaseFeatureWidget/util.d.ts +13 -2
- package/BaseFeatureWidget/util.js +13 -1
- package/PluginLoader.d.ts +29 -13
- package/PluginLoader.js +47 -77
- package/PluginManager.d.ts +4 -3
- package/PluginManager.js +16 -8
- package/assemblyManager/assembly.d.ts +8 -15
- package/assemblyManager/assembly.js +14 -17
- package/assemblyManager/assemblyManager.d.ts +37 -86
- package/assemblyManager/assemblyManager.js +2 -1
- package/configuration/configurationSlot.js +2 -1
- package/data_adapters/CytobandAdapter.js +1 -1
- package/package.json +3 -3
- package/pluggableElementTypes/ViewType.d.ts +2 -0
- package/pluggableElementTypes/ViewType.js +1 -0
- package/pluggableElementTypes/models/BaseConnectionModelFactory.d.ts +7 -5
- package/pluggableElementTypes/models/BaseConnectionModelFactory.js +3 -2
- package/pluggableElementTypes/models/BaseDisplayModel.d.ts +1 -1
- package/pluggableElementTypes/models/BaseDisplayModel.js +3 -2
- package/pluggableElementTypes/models/BaseTrackModel.d.ts +1 -1
- package/pluggableElementTypes/models/BaseTrackModel.js +1 -1
- package/pluggableElementTypes/models/baseTrackConfig.js +16 -4
- package/rpc/RpcManager.d.ts +1 -1
- package/rpc/RpcManager.js +4 -1
- package/rpc/WebWorkerRpcDriver.d.ts +2 -0
- package/rpc/WebWorkerRpcDriver.js +21 -11
- package/rpc/configSchema.js +4 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/ui/AboutDialog.d.ts +6 -0
- package/ui/AboutDialog.js +42 -20
- package/ui/App.d.ts +1 -1
- package/ui/App.js +49 -42
- package/ui/DrawerWidget.js +11 -6
- package/ui/FatalErrorDialog.d.ts +6 -22
- package/ui/FatalErrorDialog.js +10 -29
- package/ui/theme.d.ts +18 -171
- package/ui/theme.js +17 -20
- package/util/calculateStaticBlocks.js +3 -8
- package/util/index.d.ts +5 -1
- package/util/index.js +34 -11
- package/util/simpleFeature.d.ts +1 -2
- package/util/stats.js +7 -5
- package/util/tracks.d.ts +5 -2
- package/util/tracks.js +15 -5
- package/util/types/index.d.ts +1 -1
- package/util/types/index.js +3 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { IAnyStateTreeNode } from 'mobx-state-tree';
|
|
3
3
|
import { BaseCardProps, BaseProps } from './types';
|
|
4
|
-
import {
|
|
4
|
+
import { SimpleFeatureSerializedNoId } from '../util/simpleFeature';
|
|
5
5
|
export declare const useStyles: (params: void, styleOverrides?: {
|
|
6
6
|
props: {
|
|
7
7
|
classes?: Record<string, string> | undefined;
|
|
@@ -37,6 +37,7 @@ interface AttributeProps {
|
|
|
37
37
|
formatter?: (val: unknown, key: string) => React.ReactNode;
|
|
38
38
|
descriptions?: Record<string, React.ReactNode>;
|
|
39
39
|
prefix?: string[];
|
|
40
|
+
hideUris?: boolean;
|
|
40
41
|
}
|
|
41
42
|
export declare function UriLink({ value, }: {
|
|
42
43
|
value: {
|
|
@@ -54,10 +55,10 @@ export interface BaseInputProps extends BaseCardProps {
|
|
|
54
55
|
}
|
|
55
56
|
export declare const FeatureDetails: (props: {
|
|
56
57
|
model: IAnyStateTreeNode;
|
|
57
|
-
feature:
|
|
58
|
+
feature: SimpleFeatureSerializedNoId;
|
|
58
59
|
depth?: number | undefined;
|
|
59
60
|
omit?: string[] | undefined;
|
|
60
61
|
formatter?: ((val: unknown, key: string) => React.ReactNode) | undefined;
|
|
61
62
|
}) => JSX.Element;
|
|
62
|
-
declare const BaseFeatureDetails: (
|
|
63
|
+
declare const BaseFeatureDetails: ({ model }: BaseInputProps) => JSX.Element | null;
|
|
63
64
|
export default BaseFeatureDetails;
|
|
@@ -37,9 +37,8 @@ const x_data_grid_1 = require("@mui/x-data-grid");
|
|
|
37
37
|
const mobx_react_1 = require("mobx-react");
|
|
38
38
|
const is_object_1 = __importDefault(require("is-object"));
|
|
39
39
|
// locals
|
|
40
|
-
const configuration_1 = require("../configuration");
|
|
41
40
|
const util_1 = require("../util");
|
|
42
|
-
const
|
|
41
|
+
const ui_1 = require("../ui");
|
|
43
42
|
const SequenceFeatureDetails_1 = __importDefault(require("./SequenceFeatureDetails"));
|
|
44
43
|
const util_2 = require("./util");
|
|
45
44
|
const MAX_FIELD_NAME_WIDTH = 170;
|
|
@@ -129,7 +128,7 @@ exports.FieldName = FieldName;
|
|
|
129
128
|
const BasicValue = ({ value }) => {
|
|
130
129
|
const { classes } = (0, exports.useStyles)();
|
|
131
130
|
const isLink = `${value}`.match(/^https?:\/\//);
|
|
132
|
-
return (react_1.default.createElement("div", { className: classes.fieldValue }, react_1.default.isValidElement(value) ? (value) : isLink ? (react_1.default.createElement(
|
|
131
|
+
return (react_1.default.createElement("div", { className: classes.fieldValue }, react_1.default.isValidElement(value) ? (value) : isLink ? (react_1.default.createElement(ui_1.SanitizedHTML, { html: `<a href="${value}">${value}</a>` })) : (react_1.default.createElement(ui_1.SanitizedHTML, { html: (0, is_object_1.default)(value) ? JSON.stringify(value) : String(value) }))));
|
|
133
132
|
};
|
|
134
133
|
exports.BasicValue = BasicValue;
|
|
135
134
|
const SimpleValue = ({ name, value, description, prefix, width, }) => {
|
|
@@ -194,7 +193,7 @@ const BaseCoreDetails = (props) => {
|
|
|
194
193
|
exports.BaseCoreDetails = BaseCoreDetails;
|
|
195
194
|
function UriLink({ value, }) {
|
|
196
195
|
const href = (0, util_1.getUriLink)(value);
|
|
197
|
-
return react_1.default.createElement(
|
|
196
|
+
return react_1.default.createElement(ui_1.SanitizedHTML, { html: `<a href="${href}">${href}</a>` });
|
|
198
197
|
}
|
|
199
198
|
exports.UriLink = UriLink;
|
|
200
199
|
const DataGridDetails = ({ value, prefix, name, }) => {
|
|
@@ -284,7 +283,7 @@ function UriAttribute({ value, prefix, name, }) {
|
|
|
284
283
|
react_1.default.createElement(exports.BasicValue, { value: href })));
|
|
285
284
|
}
|
|
286
285
|
function Attributes(props) {
|
|
287
|
-
const { attributes, omit = [], descriptions, formatter = val => val, prefix = [], } = props;
|
|
286
|
+
const { attributes, omit = [], descriptions, formatter = val => val, hideUris, prefix = [], } = props;
|
|
288
287
|
const omits = [...omit, ...globalOmit];
|
|
289
288
|
const { __jbrowsefmt, ...rest } = attributes;
|
|
290
289
|
const formattedAttributes = { ...rest, ...__jbrowsefmt };
|
|
@@ -299,7 +298,7 @@ function Attributes(props) {
|
|
|
299
298
|
return value.length > 1 && value.every(val => (0, is_object_1.default)(val)) ? (react_1.default.createElement(DataGridDetails, { key: key, name: key, prefix: prefix, value: value })) : (react_1.default.createElement(ArrayValue, { key: key, name: key, value: value, description: description, prefix: prefix }));
|
|
300
299
|
}
|
|
301
300
|
else if ((0, is_object_1.default)(value)) {
|
|
302
|
-
return (0, util_1.isUriLocation)(value) ? (react_1.default.createElement(UriAttribute, { key: key, name: key, prefix: prefix, value: value })) : (react_1.default.createElement(Attributes, { ...props, omit: omits, key: key, attributes: value, descriptions: descriptions, prefix: [...prefix, key] }));
|
|
301
|
+
return (0, util_1.isUriLocation)(value) ? (hideUris ? null : (react_1.default.createElement(UriAttribute, { key: key, name: key, prefix: prefix, value: value }))) : (react_1.default.createElement(Attributes, { ...props, omit: omits, key: key, attributes: value, descriptions: descriptions, prefix: [...prefix, key] }));
|
|
303
302
|
}
|
|
304
303
|
else {
|
|
305
304
|
return (react_1.default.createElement(exports.SimpleValue, { key: key, name: key, value: formatter(value, key), description: description, prefix: prefix, width: Math.min(maxLabelWidth, MAX_FIELD_NAME_WIDTH) }));
|
|
@@ -324,22 +323,25 @@ function generateTitle(name, id, type) {
|
|
|
324
323
|
const FeatureDetails = (props) => {
|
|
325
324
|
const { omit = [], model, feature, depth = 0 } = props;
|
|
326
325
|
const { name = '', id = '', type = '', subfeatures } = feature;
|
|
326
|
+
const { pluginManager } = (0, util_1.getEnv)(model);
|
|
327
327
|
const session = (0, util_1.getSession)(model);
|
|
328
|
-
const
|
|
329
|
-
const sequenceTypes = (0, configuration_1.getConf)(session, ['featureDetails', 'sequenceTypes']) || defaultSeqTypes;
|
|
328
|
+
const ExtraPanel = pluginManager === null || pluginManager === void 0 ? void 0 : pluginManager.evaluateExtensionPoint('Core-extraFeaturePanel', null, { session, feature, model });
|
|
330
329
|
return (react_1.default.createElement(BaseCard, { title: generateTitle(name, id, type) },
|
|
331
330
|
react_1.default.createElement(material_1.Typography, null, "Core details"),
|
|
332
331
|
react_1.default.createElement(CoreDetails, { ...props }),
|
|
333
332
|
react_1.default.createElement(material_1.Divider, null),
|
|
334
333
|
react_1.default.createElement(material_1.Typography, null, "Attributes"),
|
|
335
334
|
react_1.default.createElement(Attributes, { attributes: feature, ...props, omit: [...omit, ...coreDetails] }),
|
|
336
|
-
|
|
337
|
-
react_1.default.createElement(SequenceFeatureDetails_1.default, { ...props }))
|
|
338
|
-
|
|
335
|
+
react_1.default.createElement(react_error_boundary_1.ErrorBoundary, { FallbackComponent: ({ error }) => react_1.default.createElement(ui_1.ErrorMessage, { error: error }) },
|
|
336
|
+
react_1.default.createElement(SequenceFeatureDetails_1.default, { ...props })),
|
|
337
|
+
ExtraPanel ? (react_1.default.createElement(react_1.default.Fragment, null,
|
|
338
|
+
react_1.default.createElement(material_1.Divider, null),
|
|
339
|
+
react_1.default.createElement(BaseCard, { title: ExtraPanel.name },
|
|
340
|
+
react_1.default.createElement(ExtraPanel.Component, { ...props })))) : null,
|
|
341
|
+
(subfeatures === null || subfeatures === void 0 ? void 0 : subfeatures.length) ? (react_1.default.createElement(BaseCard, { title: "Subfeatures", defaultExpanded: depth < 1 }, subfeatures.map(sub => (react_1.default.createElement(exports.FeatureDetails, { key: JSON.stringify(sub), feature: sub, model: model, depth: depth + 1 }))))) : null));
|
|
339
342
|
};
|
|
340
343
|
exports.FeatureDetails = FeatureDetails;
|
|
341
|
-
const BaseFeatureDetails = (0, mobx_react_1.observer)((
|
|
342
|
-
const { model } = props;
|
|
344
|
+
const BaseFeatureDetails = (0, mobx_react_1.observer)(({ model }) => {
|
|
343
345
|
const { featureData } = model;
|
|
344
346
|
if (!featureData) {
|
|
345
347
|
return null;
|
|
@@ -349,9 +351,6 @@ const BaseFeatureDetails = (0, mobx_react_1.observer)((props) => {
|
|
|
349
351
|
// config guide. this replacement happens both here and when snapshotting the
|
|
350
352
|
// featureData
|
|
351
353
|
const feature = JSON.parse(JSON.stringify(featureData, (_, v) => typeof v === 'undefined' ? null : v));
|
|
352
|
-
|
|
353
|
-
return null;
|
|
354
|
-
}
|
|
355
|
-
return react_1.default.createElement(exports.FeatureDetails, { model: model, feature: feature });
|
|
354
|
+
return isEmpty(feature) ? null : (react_1.default.createElement(exports.FeatureDetails, { model: model, feature: feature }));
|
|
356
355
|
});
|
|
357
356
|
exports.default = BaseFeatureDetails;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { Feat } from './util';
|
|
3
|
+
export declare function GeneCDS({ cds, sequence }: {
|
|
4
|
+
cds: Feat[];
|
|
5
|
+
sequence: string;
|
|
6
|
+
}): JSX.Element;
|
|
7
|
+
export declare function GeneProtein({ cds, sequence, codonTable, }: {
|
|
8
|
+
cds: Feat[];
|
|
9
|
+
sequence: string;
|
|
10
|
+
codonTable: {
|
|
11
|
+
[key: string]: string;
|
|
12
|
+
};
|
|
13
|
+
}): JSX.Element;
|
|
14
|
+
export declare function GenecDNA({ utr, cds, exons, sequence, upstream, downstream, includeIntrons, collapseIntron, intronBp, }: {
|
|
15
|
+
utr: Feat[];
|
|
16
|
+
cds: Feat[];
|
|
17
|
+
exons: Feat[];
|
|
18
|
+
sequence: string;
|
|
19
|
+
upstream?: string;
|
|
20
|
+
downstream?: string;
|
|
21
|
+
includeIntrons?: boolean;
|
|
22
|
+
collapseIntron?: boolean;
|
|
23
|
+
intronBp: number;
|
|
24
|
+
}): JSX.Element;
|
|
25
|
+
export declare function Genomic({ sequence, upstream, downstream, }: {
|
|
26
|
+
sequence: string;
|
|
27
|
+
upstream?: string;
|
|
28
|
+
downstream?: string;
|
|
29
|
+
}): JSX.Element;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Genomic = exports.GenecDNA = exports.GeneProtein = exports.GeneCDS = void 0;
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
const util_1 = require("./util");
|
|
9
|
+
// note that these are currently put into the style section instead of being
|
|
10
|
+
// defined in classes to aid copy and paste to an external document e.g. word
|
|
11
|
+
const proteinColor = 'rgb(220,160,220)';
|
|
12
|
+
const intronColor = undefined;
|
|
13
|
+
const cdsColor = 'rgb(220,220,180)';
|
|
14
|
+
const updownstreamColor = 'rgba(250,200,200)';
|
|
15
|
+
const utrColor = 'rgb(200,240,240)';
|
|
16
|
+
const genomeColor = 'rgb(200,280,200)';
|
|
17
|
+
function GeneCDS({ cds, sequence }) {
|
|
18
|
+
return react_1.default.createElement("span", { style: { background: cdsColor } }, (0, util_1.stitch)(cds, sequence));
|
|
19
|
+
}
|
|
20
|
+
exports.GeneCDS = GeneCDS;
|
|
21
|
+
function GeneProtein({ cds, sequence, codonTable, }) {
|
|
22
|
+
const str = (0, util_1.stitch)(cds, sequence);
|
|
23
|
+
let protein = '';
|
|
24
|
+
for (let i = 0; i < str.length; i += 3) {
|
|
25
|
+
// use & symbol for undefined codon, or partial slice
|
|
26
|
+
protein += codonTable[str.slice(i, i + 3)] || '&';
|
|
27
|
+
}
|
|
28
|
+
return react_1.default.createElement("span", { style: { background: proteinColor } }, protein);
|
|
29
|
+
}
|
|
30
|
+
exports.GeneProtein = GeneProtein;
|
|
31
|
+
function GenecDNA({ utr, cds, exons, sequence, upstream, downstream, includeIntrons, collapseIntron, intronBp, }) {
|
|
32
|
+
const chunks = cds.length
|
|
33
|
+
? [...cds, ...utr].sort((a, b) => a.start - b.start)
|
|
34
|
+
: exons;
|
|
35
|
+
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
36
|
+
upstream ? (react_1.default.createElement("span", { style: { background: updownstreamColor } }, upstream)) : null,
|
|
37
|
+
chunks
|
|
38
|
+
.filter(f => f.start !== f.end)
|
|
39
|
+
.map((chunk, index) => {
|
|
40
|
+
var _a;
|
|
41
|
+
const intron = sequence.slice(chunk.end, (_a = chunks[index + 1]) === null || _a === void 0 ? void 0 : _a.start);
|
|
42
|
+
return (react_1.default.createElement(react_1.default.Fragment, { key: JSON.stringify(chunk) },
|
|
43
|
+
react_1.default.createElement("span", { style: {
|
|
44
|
+
background: chunk.type === 'CDS' ? cdsColor : utrColor,
|
|
45
|
+
} }, sequence.slice(chunk.start, chunk.end)),
|
|
46
|
+
includeIntrons && index < chunks.length - 1 ? (react_1.default.createElement("span", { style: { background: intronColor } }, collapseIntron && intron.length > intronBp * 2
|
|
47
|
+
? `${intron.slice(0, intronBp)}...${intron.slice(-intronBp)}`
|
|
48
|
+
: intron)) : null));
|
|
49
|
+
}),
|
|
50
|
+
downstream ? (react_1.default.createElement("span", { style: { background: updownstreamColor } }, downstream)) : null));
|
|
51
|
+
}
|
|
52
|
+
exports.GenecDNA = GenecDNA;
|
|
53
|
+
function Genomic({ sequence, upstream, downstream, }) {
|
|
54
|
+
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
55
|
+
upstream ? (react_1.default.createElement("span", { style: { background: updownstreamColor } }, upstream)) : null,
|
|
56
|
+
react_1.default.createElement("span", { style: {
|
|
57
|
+
background: genomeColor,
|
|
58
|
+
} }, sequence),
|
|
59
|
+
downstream ? (react_1.default.createElement("span", { style: { background: updownstreamColor } }, downstream)) : null));
|
|
60
|
+
}
|
|
61
|
+
exports.Genomic = Genomic;
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
|
|
1
|
+
/// <reference types="react" />
|
|
2
2
|
import { BaseProps } from './types';
|
|
3
|
-
|
|
4
|
-
export declare const SequencePanel: React.ForwardRefExoticComponent<{
|
|
5
|
-
sequence: SeqState;
|
|
6
|
-
feature: ParentFeat;
|
|
7
|
-
mode: string;
|
|
8
|
-
} & React.RefAttributes<HTMLDivElement>>;
|
|
9
|
-
export default function SequenceFeatureDetails({ model, feature }: BaseProps): JSX.Element;
|
|
3
|
+
export default function SequenceFeatureDetails({ model, feature }: BaseProps): JSX.Element | null;
|
|
@@ -26,111 +26,34 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.SequencePanel = void 0;
|
|
30
29
|
const react_1 = __importStar(require("react"));
|
|
31
30
|
const material_1 = require("@mui/material");
|
|
32
31
|
const mui_1 = require("tss-react/mui");
|
|
33
|
-
const react_intersection_observer_1 = require("react-intersection-observer");
|
|
34
32
|
const copy_to_clipboard_1 = __importDefault(require("copy-to-clipboard"));
|
|
33
|
+
// locals
|
|
34
|
+
const SequenceFeatureSettingsDialog_1 = __importDefault(require("./SequenceFeatureSettingsDialog"));
|
|
35
|
+
const SequenceHelpDialog_1 = __importDefault(require("./SequenceHelpDialog"));
|
|
36
|
+
const SequencePanel_1 = __importDefault(require("./SequencePanel"));
|
|
35
37
|
const util_1 = require("../util");
|
|
36
38
|
const configuration_1 = require("../configuration");
|
|
37
|
-
|
|
39
|
+
// icons
|
|
40
|
+
const Settings_1 = __importDefault(require("@mui/icons-material/Settings"));
|
|
41
|
+
const Help_1 = __importDefault(require("@mui/icons-material/Help"));
|
|
38
42
|
const useStyles = (0, mui_1.makeStyles)()(theme => ({
|
|
39
43
|
button: {
|
|
40
44
|
margin: theme.spacing(1),
|
|
41
45
|
},
|
|
46
|
+
formControl: {
|
|
47
|
+
margin: 0,
|
|
48
|
+
},
|
|
49
|
+
container: {
|
|
50
|
+
margin: theme.spacing(1),
|
|
51
|
+
},
|
|
52
|
+
container2: {
|
|
53
|
+
marginTop: theme.spacing(1),
|
|
54
|
+
},
|
|
42
55
|
}));
|
|
43
|
-
|
|
44
|
-
// defined in classes to aid copy and paste to an external document e.g. word
|
|
45
|
-
const proteinColor = 'rgb(220,160,220)';
|
|
46
|
-
const intronColor = undefined;
|
|
47
|
-
const cdsColor = 'rgb(220,220,180)';
|
|
48
|
-
const updownstreamColor = 'rgba(250,200,200)';
|
|
49
|
-
const utrColor = 'rgb(200,240,240)';
|
|
50
|
-
function GeneCDS({ cds, sequence }) {
|
|
51
|
-
return react_1.default.createElement("span", { style: { background: cdsColor } }, (0, util_2.stitch)(cds, sequence));
|
|
52
|
-
}
|
|
53
|
-
function GeneProtein({ cds, sequence, codonTable, }) {
|
|
54
|
-
const str = (0, util_2.stitch)(cds, sequence);
|
|
55
|
-
let protein = '';
|
|
56
|
-
for (let i = 0; i < str.length; i += 3) {
|
|
57
|
-
// use & symbol for undefined codon, or partial slice
|
|
58
|
-
protein += codonTable[str.slice(i, i + 3)] || '&';
|
|
59
|
-
}
|
|
60
|
-
return react_1.default.createElement("span", { style: { background: proteinColor } }, protein);
|
|
61
|
-
}
|
|
62
|
-
function GenecDNA({ utr, cds, exons, sequence, upstream, downstream, includeIntrons, collapseIntron, }) {
|
|
63
|
-
const chunks = cds.length
|
|
64
|
-
? [...cds, ...utr].sort((a, b) => a.start - b.start)
|
|
65
|
-
: exons;
|
|
66
|
-
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
67
|
-
upstream ? (react_1.default.createElement("span", { style: { background: updownstreamColor } }, upstream)) : null,
|
|
68
|
-
chunks
|
|
69
|
-
.filter(f => f.start !== f.end)
|
|
70
|
-
.map((chunk, index) => {
|
|
71
|
-
var _a;
|
|
72
|
-
const intron = sequence.slice(chunk.end, (_a = chunks[index + 1]) === null || _a === void 0 ? void 0 : _a.start);
|
|
73
|
-
return (react_1.default.createElement(react_1.default.Fragment, { key: JSON.stringify(chunk) },
|
|
74
|
-
react_1.default.createElement("span", { style: {
|
|
75
|
-
background: chunk.type === 'CDS' ? cdsColor : utrColor,
|
|
76
|
-
} }, sequence.slice(chunk.start, chunk.end)),
|
|
77
|
-
includeIntrons && index < chunks.length - 1 ? (react_1.default.createElement("span", { style: { background: intronColor } }, collapseIntron && intron.length > 20
|
|
78
|
-
? `${intron.slice(0, 10)}...${intron.slice(-10)}`
|
|
79
|
-
: intron)) : null));
|
|
80
|
-
}),
|
|
81
|
-
downstream ? (react_1.default.createElement("span", { style: { background: updownstreamColor } }, downstream)) : null));
|
|
82
|
-
}
|
|
83
|
-
exports.SequencePanel = react_1.default.forwardRef(({ feature, mode, sequence: { seq: sequence, upstream = '', downstream = '' }, }, ref) => {
|
|
84
|
-
const { subfeatures } = feature;
|
|
85
|
-
const codonTable = (0, util_1.generateCodonTable)(util_1.defaultCodonTable);
|
|
86
|
-
if (!subfeatures) {
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
const children = subfeatures
|
|
90
|
-
.sort((a, b) => a.start - b.start)
|
|
91
|
-
.map(sub => ({
|
|
92
|
-
...sub,
|
|
93
|
-
start: sub.start - feature.start,
|
|
94
|
-
end: sub.end - feature.start,
|
|
95
|
-
}));
|
|
96
|
-
// we filter duplicate entries in cds and exon lists duplicate entries may be
|
|
97
|
-
// rare but was seen in Gencode v36 track NCList, likely a bug on GFF3 or
|
|
98
|
-
// probably worth ignoring here (produces broken protein translations if
|
|
99
|
-
// included)
|
|
100
|
-
//
|
|
101
|
-
// position 1:224,800,006..225,203,064 gene ENSG00000185842.15 first
|
|
102
|
-
// transcript ENST00000445597.6
|
|
103
|
-
//
|
|
104
|
-
// http://localhost:3000/?config=test_data%2Fconfig.json&session=share-FUl7G1isvF&password=HXh5Y
|
|
105
|
-
let cds = (0, util_2.dedupe)(children.filter(sub => sub.type === 'CDS'));
|
|
106
|
-
let utr = (0, util_2.dedupe)(children.filter(sub => sub.type.match(/utr/i)));
|
|
107
|
-
let exons = (0, util_2.dedupe)(children.filter(sub => sub.type === 'exon'));
|
|
108
|
-
if (!utr.length && cds.length && exons.length) {
|
|
109
|
-
utr = (0, util_2.calculateUTRs)(cds, exons);
|
|
110
|
-
}
|
|
111
|
-
if (feature.strand === -1) {
|
|
112
|
-
// doing this in a single assignment is needed because downstream and
|
|
113
|
-
// upstream are swapped so this avoids a temp variable
|
|
114
|
-
;
|
|
115
|
-
[sequence, upstream, downstream] = [
|
|
116
|
-
(0, util_1.revcom)(sequence),
|
|
117
|
-
(0, util_1.revcom)(downstream),
|
|
118
|
-
(0, util_1.revcom)(upstream),
|
|
119
|
-
];
|
|
120
|
-
cds = (0, util_2.revlist)(cds, sequence.length);
|
|
121
|
-
exons = (0, util_2.revlist)(exons, sequence.length);
|
|
122
|
-
utr = (0, util_2.revlist)(utr, sequence.length);
|
|
123
|
-
}
|
|
124
|
-
return (react_1.default.createElement("div", { ref: ref, "data-testid": "sequence_panel" },
|
|
125
|
-
react_1.default.createElement("div", { style: {
|
|
126
|
-
fontFamily: 'monospace',
|
|
127
|
-
wordWrap: 'break-word',
|
|
128
|
-
fontSize: 12,
|
|
129
|
-
maxWidth: 600,
|
|
130
|
-
} },
|
|
131
|
-
`>${feature.name || feature.id || 'unknown'}-${mode}\n`,
|
|
132
|
-
mode === 'cds' ? (react_1.default.createElement(GeneCDS, { cds: cds, sequence: sequence })) : mode === 'cdna' ? (react_1.default.createElement(GenecDNA, { exons: exons, cds: cds, utr: utr, sequence: sequence })) : mode === 'protein' ? (react_1.default.createElement(GeneProtein, { cds: cds, codonTable: codonTable, sequence: sequence })) : mode === 'gene' ? (react_1.default.createElement(GenecDNA, { exons: exons, cds: cds, utr: utr, sequence: sequence, includeIntrons: true })) : mode === 'gene_collapsed_intron' ? (react_1.default.createElement(GenecDNA, { exons: exons, cds: cds, sequence: sequence, utr: utr, includeIntrons: true, collapseIntron: true })) : mode === 'gene_updownstream' ? (react_1.default.createElement(GenecDNA, { exons: exons, cds: cds, sequence: sequence, utr: utr, upstream: upstream, downstream: downstream, includeIntrons: true })) : mode === 'gene_updownstream_collapsed_intron' ? (react_1.default.createElement(GenecDNA, { exons: exons, cds: cds, sequence: sequence, utr: utr, upstream: upstream, downstream: downstream, includeIntrons: true, collapseIntron: true })) : (react_1.default.createElement("div", null, "Unknown type")))));
|
|
133
|
-
});
|
|
56
|
+
const BPLIMIT = 500000;
|
|
134
57
|
// display the stitched-together sequence of a gene's CDS, cDNA, or protein
|
|
135
58
|
// sequence. this is a best effort and weird genomic phenomena could lead these
|
|
136
59
|
// to not be 100% accurate
|
|
@@ -138,18 +61,29 @@ function SequenceFeatureDetails({ model, feature }) {
|
|
|
138
61
|
var _a;
|
|
139
62
|
const { classes } = useStyles();
|
|
140
63
|
const parentFeature = feature;
|
|
141
|
-
const hasCDS = (_a = parentFeature.subfeatures) === null || _a === void 0 ? void 0 : _a.find(sub => sub.type === 'CDS');
|
|
64
|
+
const hasCDS = !!((_a = parentFeature.subfeatures) === null || _a === void 0 ? void 0 : _a.find(sub => sub.type === 'CDS'));
|
|
65
|
+
const isGene = feature.type === 'gene';
|
|
142
66
|
const seqPanelRef = (0, react_1.useRef)(null);
|
|
143
|
-
const
|
|
67
|
+
const [settingsDlgOpen, setSettingsDlgOpen] = (0, react_1.useState)(false);
|
|
68
|
+
const [shown, setShown] = (0, react_1.useState)(false);
|
|
69
|
+
const [helpShown, setHelpShown] = (0, react_1.useState)(false);
|
|
144
70
|
const [sequence, setSequence] = (0, react_1.useState)();
|
|
145
71
|
const [error, setError] = (0, react_1.useState)();
|
|
146
|
-
const [mode, setMode] = (0, react_1.useState)(hasCDS ? 'cds' : 'cdna');
|
|
147
72
|
const [copied, setCopied] = (0, react_1.useState)(false);
|
|
148
73
|
const [copiedHtml, setCopiedHtml] = (0, react_1.useState)(false);
|
|
74
|
+
const [intronBp, setIntronBp] = (0, util_1.useLocalStorage)('intronBp', 10);
|
|
75
|
+
const [upDownBp, setUpDownBp] = (0, util_1.useLocalStorage)('upDownBp', 500);
|
|
76
|
+
const [forceLoad, setForceLoad] = (0, react_1.useState)({
|
|
77
|
+
id: feature.uniqueId,
|
|
78
|
+
force: false,
|
|
79
|
+
});
|
|
80
|
+
(0, react_1.useEffect)(() => {
|
|
81
|
+
setForceLoad({ id: feature.uniqueId, force: false });
|
|
82
|
+
}, [feature]);
|
|
149
83
|
(0, react_1.useEffect)(() => {
|
|
150
84
|
var _a;
|
|
151
85
|
let finished = false;
|
|
152
|
-
if (!model || !
|
|
86
|
+
if (!model || !shown) {
|
|
153
87
|
return () => { };
|
|
154
88
|
}
|
|
155
89
|
const { assemblyManager, rpcManager } = (0, util_1.getSession)(model);
|
|
@@ -172,58 +106,112 @@ function SequenceFeatureDetails({ model, feature }) {
|
|
|
172
106
|
],
|
|
173
107
|
});
|
|
174
108
|
const [feat] = feats;
|
|
175
|
-
|
|
176
|
-
throw new Error(`sequence not found for feature with refName:${refName}`);
|
|
177
|
-
}
|
|
178
|
-
return feat.get('seq');
|
|
109
|
+
return (feat === null || feat === void 0 ? void 0 : feat.get('seq')) || '';
|
|
179
110
|
}
|
|
180
111
|
;
|
|
181
112
|
(async () => {
|
|
182
113
|
try {
|
|
114
|
+
setError(undefined);
|
|
183
115
|
const { start, end, refName } = feature;
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
116
|
+
if (!forceLoad.force && end - start > BPLIMIT) {
|
|
117
|
+
setSequence({
|
|
118
|
+
error: `Genomic sequence larger than ${BPLIMIT}bp, use "force load" button to display`,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
const seq = await fetchSeq(start, end, refName);
|
|
123
|
+
const up = await fetchSeq(Math.max(0, start - upDownBp), start, refName);
|
|
124
|
+
const down = await fetchSeq(end, end + upDownBp, refName);
|
|
125
|
+
if (!finished) {
|
|
126
|
+
setSequence({ seq, upstream: up, downstream: down });
|
|
127
|
+
}
|
|
189
128
|
}
|
|
190
129
|
}
|
|
191
130
|
catch (e) {
|
|
131
|
+
console.error(e);
|
|
192
132
|
setError(e);
|
|
193
133
|
}
|
|
194
134
|
})();
|
|
195
135
|
return () => {
|
|
196
136
|
finished = true;
|
|
197
137
|
};
|
|
198
|
-
}, [feature,
|
|
138
|
+
}, [feature, shown, model, upDownBp, forceLoad]);
|
|
199
139
|
const loading = !sequence;
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
140
|
+
const session = (0, util_1.getSession)(model);
|
|
141
|
+
const defaultSeqTypes = ['mRNA', 'transcript', 'gene'];
|
|
142
|
+
const sequenceTypes = (0, configuration_1.getConf)(session, ['featureDetails', 'sequenceTypes']) || defaultSeqTypes;
|
|
143
|
+
// only attempt fetching gene type sequence on a bare CDS if it has no parent
|
|
144
|
+
const attemptGeneType = feature.type === 'CDS'
|
|
145
|
+
? sequenceTypes.includes('CDS') && !feature.parentId
|
|
146
|
+
: sequenceTypes.includes(feature.type);
|
|
147
|
+
const val = attemptGeneType ? (hasCDS ? 'cds' : 'cdna') : 'genomic';
|
|
148
|
+
// this useEffect is needed to reset the mode/setMode useState because the contents of the select box can completely change depending on whether we click on a gene feature or non-gene feature, so the current value in the select box must change accordingly
|
|
149
|
+
(0, react_1.useEffect)(() => {
|
|
150
|
+
setMode(val);
|
|
151
|
+
}, [attemptGeneType, val]);
|
|
152
|
+
const [mode, setMode] = (0, react_1.useState)(attemptGeneType ? (hasCDS ? 'cds' : 'cdna') : 'genomic');
|
|
153
|
+
const rest = {
|
|
154
|
+
gene: 'Gene w/ introns',
|
|
155
|
+
gene_collapsed_intron: `Gene w/ ${intronBp}bp of intron`,
|
|
156
|
+
gene_updownstream: `Gene w/ ${upDownBp}bp up+down stream`,
|
|
157
|
+
gene_updownstream_collapsed_intron: `Gene w/ ${upDownBp}bp up+down stream w/ ${intronBp}bp intron`,
|
|
158
|
+
cdna: 'cDNA',
|
|
159
|
+
};
|
|
160
|
+
const arg = attemptGeneType
|
|
161
|
+
? hasCDS
|
|
162
|
+
? {
|
|
163
|
+
cds: 'CDS',
|
|
164
|
+
protein: 'Protein',
|
|
165
|
+
...rest,
|
|
166
|
+
}
|
|
167
|
+
: rest
|
|
168
|
+
: {
|
|
169
|
+
genomic: 'Genomic seq',
|
|
170
|
+
genomic_sequence_updown: `Genomic seq w/ ${upDownBp}bp up+down stream`,
|
|
171
|
+
};
|
|
172
|
+
return (isGene && !hasCDS) || !model ? null : (react_1.default.createElement("div", { className: classes.container2 },
|
|
173
|
+
react_1.default.createElement(material_1.Button, { variant: "contained", onClick: () => setShown(!shown) }, shown ? 'Hide feature sequence' : 'Show feature sequence'),
|
|
174
|
+
react_1.default.createElement(material_1.FormControl, { className: classes.formControl },
|
|
175
|
+
react_1.default.createElement(material_1.IconButton, { onClick: () => setHelpShown(true) },
|
|
176
|
+
react_1.default.createElement(Help_1.default, null))),
|
|
177
|
+
react_1.default.createElement("br", null),
|
|
178
|
+
shown ? (react_1.default.createElement("div", { className: classes.container2 },
|
|
179
|
+
react_1.default.createElement(material_1.FormControl, { className: classes.formControl },
|
|
180
|
+
react_1.default.createElement(material_1.Select, { value: mode, onChange: event => setMode(event.target.value) }, Object.entries(arg).map(([key, val]) => (react_1.default.createElement(material_1.MenuItem, { key: key, value: key }, val))))),
|
|
181
|
+
react_1.default.createElement(material_1.FormControl, { className: classes.formControl },
|
|
182
|
+
react_1.default.createElement(material_1.Button, { className: classes.button, variant: "contained", color: "inherit", onClick: () => {
|
|
183
|
+
const ref = seqPanelRef.current;
|
|
184
|
+
if (ref) {
|
|
185
|
+
(0, copy_to_clipboard_1.default)(ref.textContent || '', { format: 'text/plain' });
|
|
186
|
+
setCopied(true);
|
|
187
|
+
setTimeout(() => setCopied(false), 1000);
|
|
188
|
+
}
|
|
189
|
+
} }, copied ? 'Copied to clipboard!' : 'Copy plaintext')),
|
|
190
|
+
react_1.default.createElement(material_1.FormControl, { className: classes.formControl },
|
|
191
|
+
react_1.default.createElement(material_1.Tooltip, { title: "The 'Copy HTML' function retains the colors from the sequence panel but cannot be pasted into some programs like notepad that only expect plain text" },
|
|
192
|
+
react_1.default.createElement(material_1.Button, { className: classes.button, variant: "contained", color: "inherit", onClick: () => {
|
|
193
|
+
const ref = seqPanelRef.current;
|
|
194
|
+
if (ref) {
|
|
195
|
+
(0, copy_to_clipboard_1.default)(ref.innerHTML, { format: 'text/html' });
|
|
196
|
+
setCopiedHtml(true);
|
|
197
|
+
setTimeout(() => setCopiedHtml(false), 1000);
|
|
198
|
+
}
|
|
199
|
+
} }, copiedHtml ? 'Copied to clipboard!' : 'Copy HTML'))),
|
|
200
|
+
react_1.default.createElement(material_1.FormControl, { className: classes.formControl },
|
|
201
|
+
react_1.default.createElement(material_1.IconButton, { onClick: () => setSettingsDlgOpen(true) },
|
|
202
|
+
react_1.default.createElement(Settings_1.default, null))),
|
|
203
|
+
react_1.default.createElement("br", null),
|
|
204
|
+
react_1.default.createElement(react_1.default.Fragment, null, error ? (react_1.default.createElement(material_1.Typography, { color: "error" }, `${error}`)) : loading ? (react_1.default.createElement(material_1.Typography, null, "Loading gene sequence...")) : sequence ? ('error' in sequence ? (react_1.default.createElement(react_1.default.Fragment, null,
|
|
205
|
+
react_1.default.createElement(material_1.Typography, { color: "error" }, sequence.error),
|
|
206
|
+
react_1.default.createElement(material_1.Button, { variant: "contained", color: "inherit", onClick: () => setForceLoad({ ...forceLoad, force: true }) }, "Force load"))) : (react_1.default.createElement(SequencePanel_1.default, { ref: seqPanelRef, feature: parentFeature, mode: mode, sequence: sequence, intronBp: intronBp }))) : (react_1.default.createElement(material_1.Typography, null, "No sequence found"))))) : null,
|
|
207
|
+
settingsDlgOpen ? (react_1.default.createElement(SequenceFeatureSettingsDialog_1.default, { handleClose: arg => {
|
|
208
|
+
if (arg) {
|
|
209
|
+
const { upDownBp, intronBp } = arg;
|
|
210
|
+
setIntronBp(intronBp);
|
|
211
|
+
setUpDownBp(upDownBp);
|
|
216
212
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
const ref = seqPanelRef.current;
|
|
221
|
-
if (ref) {
|
|
222
|
-
(0, copy_to_clipboard_1.default)(ref.innerHTML, { format: 'text/html' });
|
|
223
|
-
setCopiedHtml(true);
|
|
224
|
-
setTimeout(() => setCopiedHtml(false), 1000);
|
|
225
|
-
}
|
|
226
|
-
} }, copiedHtml ? 'Copied to clipboard!' : 'Copy as HTML')),
|
|
227
|
-
react_1.default.createElement("div", { "data-testid": "feature_sequence" }, error ? (react_1.default.createElement(material_1.Typography, { color: "error" }, `${error}`)) : loading ? (react_1.default.createElement("div", null, "Loading gene sequence...")) : sequence ? (react_1.default.createElement(exports.SequencePanel, { ref: seqPanelRef, feature: parentFeature, mode: mode, sequence: sequence })) : (react_1.default.createElement("div", null, "No sequence found")))));
|
|
213
|
+
setSettingsDlgOpen(false);
|
|
214
|
+
}, upDownBp: upDownBp, intronBp: intronBp })) : null,
|
|
215
|
+
helpShown ? react_1.default.createElement(SequenceHelpDialog_1.default, { handleClose: () => setHelpShown(false) }) : null));
|
|
228
216
|
}
|
|
229
217
|
exports.default = SequenceFeatureDetails;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
export default function SequenceFeatureSettingsDialog({ handleClose, intronBp: intronBpArg, upDownBp: upDownBpArg, }: {
|
|
3
|
+
handleClose: (arg?: {
|
|
4
|
+
intronBp: number;
|
|
5
|
+
upDownBp: number;
|
|
6
|
+
}) => void;
|
|
7
|
+
intronBp: number;
|
|
8
|
+
upDownBp: number;
|
|
9
|
+
}): JSX.Element;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
const react_1 = __importStar(require("react"));
|
|
30
|
+
const material_1 = require("@mui/material");
|
|
31
|
+
const mui_1 = require("tss-react/mui");
|
|
32
|
+
// icons
|
|
33
|
+
const Close_1 = __importDefault(require("@mui/icons-material/Close"));
|
|
34
|
+
const useStyles = (0, mui_1.makeStyles)()(theme => ({
|
|
35
|
+
formElt: {
|
|
36
|
+
margin: theme.spacing(3),
|
|
37
|
+
width: 400,
|
|
38
|
+
},
|
|
39
|
+
closeButton: {
|
|
40
|
+
position: 'absolute',
|
|
41
|
+
right: theme.spacing(1),
|
|
42
|
+
top: theme.spacing(1),
|
|
43
|
+
color: theme.palette.grey[500],
|
|
44
|
+
},
|
|
45
|
+
dialogContent: {
|
|
46
|
+
width: '80em',
|
|
47
|
+
},
|
|
48
|
+
}));
|
|
49
|
+
function SequenceFeatureSettingsDialog({ handleClose, intronBp: intronBpArg, upDownBp: upDownBpArg, }) {
|
|
50
|
+
const { classes } = useStyles();
|
|
51
|
+
const [intronBp, setIntronBp] = (0, react_1.useState)(`${intronBpArg}`);
|
|
52
|
+
const [upDownBp, setUpDownBp] = (0, react_1.useState)(`${upDownBpArg}`);
|
|
53
|
+
const intronBpValid = !Number.isNaN(+intronBp);
|
|
54
|
+
const upDownBpValid = !Number.isNaN(+upDownBp);
|
|
55
|
+
return (react_1.default.createElement(material_1.Dialog, { maxWidth: "xl", open: true, onClose: () => handleClose() },
|
|
56
|
+
react_1.default.createElement(material_1.DialogTitle, null,
|
|
57
|
+
"Feature sequence settings",
|
|
58
|
+
handleClose ? (react_1.default.createElement(material_1.IconButton, { className: classes.closeButton, onClick: () => handleClose() },
|
|
59
|
+
react_1.default.createElement(Close_1.default, null))) : null),
|
|
60
|
+
react_1.default.createElement(material_1.Divider, null),
|
|
61
|
+
react_1.default.createElement(material_1.DialogContent, { className: classes.dialogContent },
|
|
62
|
+
react_1.default.createElement(material_1.TextField, { label: "Number of intronic bases around splice site to display", className: classes.formElt, value: intronBp, helperText: !intronBpValid ? 'Not a number' : '', error: !intronBpValid, onChange: event => setIntronBp(event.target.value) }),
|
|
63
|
+
react_1.default.createElement(material_1.TextField, { label: "Number of bases up/down stream of feature to display", className: classes.formElt, value: upDownBp, helperText: !upDownBpValid ? 'Not a number' : '', error: !upDownBpValid, onChange: event => setUpDownBp(event.target.value) })),
|
|
64
|
+
react_1.default.createElement(material_1.DialogActions, null,
|
|
65
|
+
react_1.default.createElement(material_1.Button, { onClick: () => handleClose({
|
|
66
|
+
upDownBp: +upDownBp,
|
|
67
|
+
intronBp: +intronBp,
|
|
68
|
+
}), disabled: !intronBpValid || !upDownBpValid, color: "primary", variant: "contained" }, "Submit"),
|
|
69
|
+
react_1.default.createElement(material_1.Button, { onClick: () => handleClose(), color: "secondary", autoFocus: true, variant: "contained" }, "Cancel"))));
|
|
70
|
+
}
|
|
71
|
+
exports.default = SequenceFeatureSettingsDialog;
|