From 2df7161cd86d63feb83e25f6faa6df06302d9409 Mon Sep 17 00:00:00 2001 From: Colin Megill Date: Tue, 29 Jan 2019 16:26:09 -0500 Subject: [PATCH] Bulk add genes (#567) * bulk add * cleanup --- client/src/components/framework/toasters.js | 7 + client/src/components/geneExpression/index.js | 171 +++++++++++++++--- client/src/globals.js | 6 +- 3 files changed, 152 insertions(+), 32 deletions(-) diff --git a/client/src/components/framework/toasters.js b/client/src/components/framework/toasters.js index 3b0e67f4..46c9d4e8 100644 --- a/client/src/components/framework/toasters.js +++ b/client/src/components/framework/toasters.js @@ -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 */ diff --git a/client/src/components/geneExpression/index.js b/client/src/components/geneExpression/index.js index b17d5d51..8c1f53f7 100644 --- a/client/src/components/geneExpression/index.js +++ b/client/src/components/geneExpression/index.js @@ -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 (
- true : () => false} - noResults={} - 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 }} - /> +
+ + {tab === "autosuggest" ? ( + + true : () => false + } + noResults={} + 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 }} + /> + + + ) : null} + {tab === "bulkadd" ? ( +
+
{ + e.preventDefault(); + this.handleBulkAddClick(); + }} + > + { + console.log("heyo"); + }} + > + + { + this.setState({ bulkAdd: e.target.value }); + }} + id="text-input-bulk-add" + placeholder="Apod, Cd74, ..." + value={bulkAdd} + /> + + + +
+
+ ) : null} {world && userDefinedGenes.length > 0 ? _.map(userDefinedGenes, (geneName, index) => { const values = world.varDataCache[geneName]; diff --git a/client/src/globals.js b/client/src/globals.js index 13f68ed5..3df67411 100644 --- a/client/src/globals.js +++ b/client/src/globals.js @@ -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)";