Bulk add genes (#567)

* bulk add

* cleanup
This commit is contained in:
Colin Megill
2019-01-29 16:26:09 -05:00
committed by GitHub
parent d31c05c970
commit 2df7161cd8
3 changed files with 152 additions and 32 deletions

View File

@@ -13,6 +13,13 @@ A "user" error - eg, bad input
export const postUserErrorToast = message =>
ErrorToastTopCenter.show({ message, intent: Intent.WARNING });
/*
A toast the user must dismiss manually, because they need to act on its information,
ie., 8 bulk add genes out of 40 were bad. Manually see which ones and fix.
*/
export const keepAroundErrorToast = message =>
ErrorToastTopCenter.show({ message, timeout: 0, intent: Intent.WARNING });
/*
a hard network error
*/

View File

@@ -6,12 +6,21 @@ import _ from "lodash";
import fuzzysort from "fuzzysort";
import { connect } from "react-redux";
import { MenuItem, Button } from "@blueprintjs/core";
import {
MenuItem,
Button,
FormGroup,
InputGroup,
ControlGroup
} from "@blueprintjs/core";
import { Suggest } from "@blueprintjs/select";
import HistogramBrush from "../brushableHistogram";
import * as globals from "../../globals";
import actions from "../../actions";
import { postUserErrorToast } from "../framework/toasters";
import {
postUserErrorToast,
keepAroundErrorToast
} from "../framework/toasters";
import ExpressionButtons from "./expressionButtons";
import finiteExtent from "../../util/finiteExtent";
@@ -67,6 +76,14 @@ const filterGenes = (query, genes) => {
};
})
class GeneExpression extends React.Component {
constructor(props) {
super(props);
this.state = {
bulkAdd: "",
tab: "autosuggest"
};
}
handleClick(g) {
const { world, dispatch, userDefinedGenes } = this.props;
const gene = g.target;
@@ -87,6 +104,29 @@ class GeneExpression extends React.Component {
}
}
handleBulkAddClick() {
const { world, dispatch, userDefinedGenes } = this.props;
const { bulkAdd } = this.state;
const genes = _.uniq(bulkAdd.split(", ").map(g => g.trim()));
genes.forEach(gene => {
if (userDefinedGenes.indexOf(gene) !== -1) {
keepAroundErrorToast("That gene already exists");
} else if (!_.find(world.varAnnotations, { name: gene })) {
keepAroundErrorToast(`${gene} doesn't appear to be a valid gene name.`);
} else {
dispatch(actions.requestUserDefinedGene(gene));
dispatch({
type: "user defined gene",
data: gene
});
}
});
this.setState({ bulkAdd: "" });
}
render() {
const {
world,
@@ -95,6 +135,8 @@ class GeneExpression extends React.Component {
differential
} = this.props;
const { tab, bulkAdd } = this.state;
return (
<div>
<div
@@ -111,39 +153,108 @@ class GeneExpression extends React.Component {
Selected Genes
</p>
<div
style={{ padding: globals.leftSidebarSectionPadding }}
className="bp3-control-group"
style={{
padding: globals.leftSidebarSectionPadding
}}
>
<Suggest
disabled={true}
closeOnSelect
openOnKeyDown
resetOnSelect
itemDisabled={userDefinedGenesLoading ? () => true : () => false}
noResults={<MenuItem disabled text="No matching genes." />}
onItemSelect={g => {
/* this happens on 'enter' */
this.handleClick(g);
}}
inputValueRenderer={g => {
return "";
}}
itemListPredicate={filterGenes}
itemRenderer={renderGene.bind(this)}
items={
world && world.varAnnotations
? world.varAnnotations
: [{ name: "No genes", n_counts: "" }]
}
popoverProps={{ minimal: true }}
/>
<Button
className="bp3-button bp3-intent-primary"
loading={userDefinedGenesLoading}
active={tab === "autosuggest"}
style={{ marginRight: 5 }}
minimal
small
onClick={() => {
this.setState({ tab: "autosuggest" });
}}
>
Add
Autosuggest
</Button>
<Button
active={tab === "bulkadd"}
minimal
small
onClick={() => {
this.setState({ tab: "bulkadd" });
}}
>
Bulk add genes
</Button>
</div>
{tab === "autosuggest" ? (
<ControlGroup
style={{
paddingLeft: globals.leftSidebarSectionPadding,
paddingBottom: globals.leftSidebarSectionPadding
}}
>
<Suggest
closeOnSelect
openOnKeyDown
resetOnSelect
itemDisabled={
userDefinedGenesLoading ? () => true : () => false
}
noResults={<MenuItem disabled text="No matching genes." />}
onItemSelect={g => {
/* this happens on 'enter' */
this.handleClick(g);
}}
inputValueRenderer={g => {
return "";
}}
itemListPredicate={filterGenes}
itemRenderer={renderGene.bind(this)}
items={
world && world.varAnnotations
? world.varAnnotations
: [{ name: "No genes" }]
}
popoverProps={{ minimal: true }}
/>
<Button
className="bp3-button bp3-intent-primary"
loading={userDefinedGenesLoading}
>
Add
</Button>
</ControlGroup>
) : null}
{tab === "bulkadd" ? (
<div style={{ paddingLeft: globals.leftSidebarSectionPadding }}>
<form
onSubmit={e => {
e.preventDefault();
this.handleBulkAddClick();
}}
>
<FormGroup
helperText="Add a list of genes (comma delimited)"
labelFor="text-input-bulk-add"
onSubmit={() => {
console.log("heyo");
}}
>
<ControlGroup>
<InputGroup
onChange={e => {
this.setState({ bulkAdd: e.target.value });
}}
id="text-input-bulk-add"
placeholder="Apod, Cd74, ..."
value={bulkAdd}
/>
<Button
intent="primary"
onClick={this.handleBulkAddClick.bind(this)}
loading={userDefinedGenesLoading}
>
Add
</Button>
</ControlGroup>
</FormGroup>
</form>
</div>
) : null}
{world && userDefinedGenes.length > 0
? _.map(userDefinedGenes, (geneName, index) => {
const values = world.varDataCache[geneName];

View File

@@ -1,3 +1,5 @@
import { Colors } from "@blueprintjs/core";
// jshint esversion: 6
/* these will be either (preferably) specified or inferred */
export const categories = [
@@ -44,8 +46,8 @@ export const configDefaults = {
};
/* colors */
export const blue = "#4a90e2";
export const hcaBlue = "#1c7cc7";
export const blue = Colors.BLUE3;
export const linkBlue = Colors.BLUE5;
export const lightestGrey = "rgb(249,249,249)";
export const lighterGrey = "rgb(245,245,245)";
export const lightGrey = "rgb(211,211,211)";